Index: oldkernel/linux/MAINTAINERS
diff -u linux/MAINTAINERS:1.1.1.1 linux/MAINTAINERS:1.2
--- linux/MAINTAINERS:1.1.1.1	Wed May 31 12:33:48 2000
+++ linux/MAINTAINERS	Fri Jul  7 15:36:41 2000
@@ -304,6 +304,13 @@
 L:	linux-eata@i-connect.net, linux-scsi@vger.rutgers.edu
 S:	Maintained
 
+EMU10K1 SOUND DRIVER
+P:	Rui Sousa	
+M:	rsousa@grad.physics.sunysb.edu	
+L:	emu10k1-devel@opensource.creative.com
+W:	http://opensource.creative.com/
+S:	Maintained
+
 ETHEREXPRESS-16 NETWORK DRIVER
 P:	Philip Blundell
 M:	Philip.Blundell@pobox.com
Index: oldkernel/linux/Makefile
diff -u linux/Makefile:1.3 linux/Makefile:1.4
--- linux/Makefile:1.3	Thu Jun  1 17:59:28 2000
+++ linux/Makefile	Fri Jul  7 15:36:41 2000
@@ -1,7 +1,7 @@
 VERSION = 2
 PATCHLEVEL = 2
 SUBLEVEL = 14
-EXTRAVERSION = -5.0.14
+EXTRAVERSION = -12.ext3.14smp
 
 ARCH := $(shell uname -m | sed -e s/i.86/i386/ -e s/sun4u/sparc64/ -e s/arm.*/arm/ -e s/sa110/arm/)
 
Index: oldkernel/linux/3w-xxxx/driver/Makefile
diff -u /dev/null linux/3w-xxxx/driver/Makefile:1.1
--- /dev/null	Mon Jul 31 21:15:04 2000
+++ linux/3w-xxxx/driver/Makefile	Fri Jul  7 16:34:57 2000
@@ -0,0 +1,13 @@
+CC = /usr/bin/gcc
+
+CFLAGS = -c -D__KERNEL__=1 -DMODULE -Wall -Wstrict-prototypes -I. -O2 -fomit-frame-pointer
+
+OBJS = 3w-xxxx
+
+3w-xxxx.o:3w-xxxx.c 3w-xxxx.h
+	$(CC) $(CFLAGS) -o 3w-xxxx.o 3w-xxxx.c
+
+all: $(OBJS)
+
+clean:
+	rm -rf 3w-xxxx.o *~
Index: oldkernel/linux/Documentation/Changes
diff -u linux/Documentation/Changes:1.1.1.1 linux/Documentation/Changes:1.2
--- linux/Documentation/Changes:1.1.1.1	Wed May 31 12:33:53 2000
+++ linux/Documentation/Changes	Fri Jul  7 15:36:41 2000
@@ -651,9 +651,9 @@
 ftp://ftp.mathematik.th-darmstadt.de/pub/linux/okir/dontuse/nfs-server-2.2beta40.tar.gz
 ftp://linux.nrao.edu/mirrors/fb0429.mathematik.th-darmstadt.de/pub/linux/okir/dontuse/nfs-server-2.2beta40.tar.gz
 
-The kernel-level 1.4.7 release:
-ftp://ftp.varesearch.com/pub/support/hjl/knfsd/knfsd-1.4.7.tar.gz
-ftp://ftp.kernel.org/pub/linux/devel/gcc/knfsd-1.4.7.tar.gz
+
+The kernel-level nfs-utils-0.1.6 release:
+ftp://nfs.sourceforge.net/pub/nfs/nfs-utils-0.1.6.tar.gz
 
 Net-tools
 =========
Index: oldkernel/linux/Documentation/Configure.help
diff -u linux/Documentation/Configure.help:1.10 linux/Documentation/Configure.help:1.11
--- linux/Documentation/Configure.help:1.10	Thu Jun  1 17:28:49 2000
+++ linux/Documentation/Configure.help	Fri Jul  7 15:36:41 2000
@@ -704,6 +704,16 @@
   say M here and read Documentation/modules.txt.  The module will be
   called DAC960.o. 
 
+3ware Storage Controller support
+CONFIG_BLK_DEV_3WARE
+  This driver adds support for 3ware Storage Controller. See
+  readme.3ware for further information about this driver.
+
+  If you want to compile the 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.  The module will be
+  called 3w-xxxx.o.
+
 Parallel port IDE device support
 CONFIG_PARIDE
   There are many external CD-ROM and disk devices that connect through
@@ -1698,14 +1708,6 @@
   is required to make use of the new PIII 128bit XMM registers.  It is safe
   to leave this enabled all the time.
 
-Enable CPU Specific (MMX/MMX2) Optimizations
-CONFIG_X86_CPU_OPTIMIZATIONS
-  This enables use of the MMX registers and 128bit MMX2 registers on CPUs
-  that can support the new instructions (Pentium/AMD K6 or newer).  In
-  order to support the Pentium III 128 bit XMM registers you must enable
-  both this and PII/PIII Extended Fast FPU save support.  It is safe to
-  leave this enabled all the time.
-
 VGA text console
 CONFIG_VGA_CONSOLE
   Saying Y here will allow you to use Linux in text mode through a
@@ -4213,8 +4215,8 @@
 
 synchronous data transfers frequency
 CONFIG_SCSI_NCR53C8XX_SYNC
-  The SCSI Parallel Interface-2 Standard defines 4 classes of transfer
-  rates: FAST-5, FAST-10, FAST-20 and FAST-40. The numbers are
+  The SCSI Parallel Interface-2 Standard defines 5 classes of transfer
+  rates: FAST-5, FAST-10, FAST-20, FAST-40 and FAST-80. The numbers are
   respectively the maximum data transfer rates in mega-transfers per
   second for each class. For example, a FAST-20 Wide 16 device is able
   to transfer data at 20 million 16 bit packets per second for a total
@@ -4222,9 +4224,9 @@
 
   You may specify 0 if you want to only use asynchronous data
   transfers. This is the safest and slowest option. Otherwise, specify
-  a value between 5 and 40, depending on the capability of your SCSI
+  a value between 5 and 80, depending on the capability of your SCSI
   controller. The higher the number, the faster the data transfer.
-  Note that 40 should normally be ok since the driver decreases the
+  Note that 80 should normally be ok since the driver decreases the
   value automatically according to the controller's capabilities.
 
   Your answer to this question is ignored for controllers with NVRAM,
@@ -4235,7 +4237,7 @@
   second).
 
   The normal answer therefore is not to go with the default but to
-  select the maximum value 40 allowing the driver to use the maximum
+  select the maximum value 80 allowing the driver to use the maximum
   value supported by each controller. If this causes problems with
   your SCSI devices, you should come back and decrease the value.
 
@@ -4253,6 +4255,36 @@
   The normal answer therefore is N; try Y only if you encounter SCSI
   related problems.
 
+perform integrity check
+CONFIG_SCSI_NCR53C8XX_INTEGRITY_CHECK
+  If you say Y here, the driver will verify the transmission
+  characteristics of the SCSI bus using the basic and enhanced
+  tests defined by the T10/98-235 and 99-242r2 specifications. 
+  The basic test compares the response to Inquiry commands at 
+  asynchronous, narrow and the maximum settings.  The enhanced
+  test utilizes devices internal buffer to perform a series of
+  write, read and compare tests using high-stress test patterns.
+  Errors in the compare will result in a reduced transmission rate.
+  Ultra 3 support requires this option to be enabled. This option
+  requires the incomplete driver option to be enabled as well.
+
+  Note: Devices that are not fully SCSI compliant may behave badly with 
+  the enhanced test.  If this happens, disable the integrity check
+  using the command line option  bushck:4  and send an email
+  with details to pam.delaney@lsil.com.
+ 
+enable immediate arbitration
+CONFIG_SCSI_NCR53C8XX_IARB
+  This option is only supported by the SYM53C8XX driver.
+  SYMBIOS 53C8XX chips are able to arbitrate for the SCSI BUS as soon
+  as they have detected an expected disconnection (BUS FREE PHASE).
+  Enabling this option makes the SCSI initiator (adapter) very unfair
+  with regards to SCSI BUS arbitration. If you think that this feature
+  can improve your application or are interested in evaluating it,
+  please read first the README.ncr53c8xx file.
+
+  The normal answer for this option is N.
+
 not allow targets to disconnect
 CONFIG_SCSI_NCR53C8XX_NO_DISCONNECT
   This option is only provided for safety if you suspect some SCSI
@@ -4286,7 +4318,8 @@
 CONFIG_SCSI_NCR53C8XX_MAX_TAGS
   This option allows you to specify the maximum number of commands
   that can be queued to any device, when tagged command queuing is
-  possible. The default value is 32. Minimum is 2, maximum is 64.
+  possible. The default value is 32. Minimum is 2, maximum is 64 for
+  the generic NCR53C8XX driver and 255 for the SYM53C8XX driver.
   Modern hard disks are able to support 64 tags and even more, but 
   do not seem to be faster when more than 32 tags are being used.
   
@@ -7544,31 +7577,33 @@
 
 NFS server support
 CONFIG_NFSD
-  If you want your Linux box to act as a NFS *server*, so that other
+  If you want your Linux box to act as an NFS *server*, so that other
   computers on your local network which support NFS can access certain
   directories on your box transparently, you have two options: you can
   use the self-contained user space program nfsd, in which case you
-  should say N here, or you can say Y and use this new experimental
-  kernel based NFS server. The advantage of the kernel based solution
-  is that it is faster; it might not be completely stable yet, though.
+  should say N here, or you can say Y and use the kernel based NFS
+  server. The kernel based solution is faster and is now the recommended
+  solution: no further development is occurring on the userspace server and
+  support of it may be discontinued in future.
 
   In either case, you will need support software; the respective
   locations are given in the file Documentation/Changes in the NFS
   section.
 
-  Please read the NFS-HOWTO, available via FTP (user: anonymous) from
-  ftp://metalab.unc.edu/pub/Linux/docs/HOWTO.
+  Please read the NFS-HOWTO, available from
+  http://www.linuxdoc.org/HOWTO/NFS-HOWTO.html .
+
 
   The NFS server 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 nfsd.o. If you want to compile it as a module,
   say M here and read Documentation/modules.txt. If unsure, say N.
 
-Emulate Sun NFS daemon
-CONFIG_NFSD_SUN
-  If you would like for the server to allow clients to access
-  directories that are mount points on the local filesystem (this is
-  how nfsd behaves on Sun systems), say yes here. If unsure, say N.
+Provide NFSv3 server support (EXPERIMENTAL)
+CONFIG_NFSD_V3
+  If you would like to include the NFSv3 server was well as the NFSv2
+  server, say Y here.  File locking, via the NLMv4 protocol, is now
+  supported. If unsure, say N.
 
 OS/2 HPFS filesystem support (read only)
 CONFIG_HPFS_FS
@@ -10191,6 +10226,11 @@
   be able to use its on-board audio.  Read Documentation/sound/visws
   for more info on this driver's capabilities.
 
+Creative EMU10K1 based PCI sound cards
+CONFIG_SOUND_EMU10K1
+  Say Y or M if you have a PCI sound card using the EMU10K1
+  chipset, such as the Creative SBLive! or SB PCI512.
+
 Ensoniq ES1370 based PCI sound cards
 CONFIG_SOUND_ES1370
   Say Y or M if you have a PCI sound card utilizing the Ensoniq
@@ -10267,11 +10307,6 @@
   Say Y or M if you have a sound system driven by ESS's Maestro line
   of PCI sound chips.  These include the Maestro 1, Maestro 2, and
   Maestro 2E.  See Documentation/sound/Maestro for more details.
-
-EMU10K1 derived boards
-CONFIG_SOUND_EMU10k1
-  Say Y or M if you have a Creative SBLive! sound card, as this
-  is the only card currently supported by this driver.
 
 Are you using a crosscompiler
 CONFIG_CROSSCOMPILE
Index: oldkernel/linux/Documentation/README.DAC960
diff -u linux/Documentation/README.DAC960:1.2 linux/Documentation/README.DAC960:1.3
--- linux/Documentation/README.DAC960:1.2	Wed May 31 14:57:57 2000
+++ linux/Documentation/README.DAC960	Fri Jul  7 15:36:41 2000
@@ -1,11 +1,11 @@
-	   Mylex DAC960/DAC1100 PCI RAID Controller Driver for Linux
+   Linux Driver for Mylex DAC960/AcceleRAID/eXtremeRAID PCI RAID Controllers
 
-			Version 2.2.5 for Linux 2.2.14
-			Version 2.0.5 for Linux 2.0.38
+			Version 2.2.6 for Linux 2.2.15
+			Version 2.4.6 for Linux 2.4.0
 
 			      PRODUCTION RELEASE
 
-				23 January 2000
+				  31 May 2000
 
 			       Leonard N. Zubkoff
 			       Dandelion Digital
@@ -18,30 +18,35 @@
 
 Mylex, Inc. designs and manufactures a variety of high performance PCI RAID
 controllers.  Mylex Corporation is located at 34551 Ardenwood Blvd., Fremont,
-California 94555, USA and can be reached at 510/796-6100 or on the World Wide
-Web at http://www.mylex.com.  Mylex RAID Technical Support can be reached by
-electronic mail at support@mylex.com (for eXtremeRAID 1100 and older DAC960
-models) or techsup@mylex.com (for AcceleRAID models), by voice at 510/608-2400,
-or by FAX at 510/745-7715.  Contact information for offices in Europe and Japan
-is available on the Web site.
+California 94555, USA and can be reached at 510.796.6100 or on the World Wide
+Web at http://www.mylex.com.  Mylex Technical Support can be reached by
+electronic mail at support@mylex.com, by voice at 510.608.2400, or by FAX at
+510.745.7715.  Contact information for offices in Europe and Japan is available
+on their Web site.
 
 The latest information on Linux support for DAC960 PCI RAID Controllers, as
 well as the most recent release of this driver, will always be available from
 my Linux Home Page at URL "http://www.dandelion.com/Linux/".  The Linux DAC960
-driver supports all current DAC960 PCI family controllers including the
-AcceleRAID models, as well as the eXtremeRAID 1100; see below for a complete
-list.  For simplicity, in most places this documentation refers to DAC960
-generically rather than explicitly listing all the models.
-
-Bug reports should be sent via electronic mail to "lnz@dandelion.com".  Please
-include with the bug report the complete configuration messages reported by the
-driver at startup, along with any subsequent system messages relevant to the
-controller's operation, and a detailed description of your system's hardware
-configuration.
-
-Please consult the DAC960 RAID controller documentation for detailed
-information regarding installation and configuration of the controllers.  This
-document primarily provides information specific to the Linux DAC960 support.
+driver supports all current Mylex PCI RAID controllers including the new
+eXtremeRAID 2000/3000 and AcceleRAID 352/170 models which have an entirely new
+firmware interface from the older eXtremeRAID 1100, AcceleRAID 150/200/250, and
+DAC960PJ/PG/PU/PD/PL.  See below for a complete controller list as well as
+minimum firmware version requirements.  For simplicity, in most places this
+documentation refers to DAC960 generically rather than explicitly listing all
+the supported models.
+
+Driver bug reports should be sent via electronic mail to "lnz@dandelion.com".
+Please include with the bug report the complete configuration messages reported
+by the driver at startup, along with any subsequent system messages relevant to
+the controller's operation, and a detailed description of your system's
+hardware configuration.  Driver bugs are actually quite rare; if you encounter
+problems with disks being marked offline, for example, please contact Mylex
+Technical Support as the problem is related to the hardware configuration
+rather than the Linux driver.
+
+Please consult the RAID controller documentation for detailed information
+regarding installation and configuration of the controllers.  This document
+primarily provides information specific to the Linux support.
 
 
 				DRIVER FEATURES
@@ -60,16 +65,18 @@
 from Linux while the system is operational.
 
 The DAC960 driver is architected to support up to 8 controllers per system.
-Each DAC960 controller can support up to 15 disk drives per channel, for a
-maximum of 45 drives on a three channel controller.  The drives installed on a
-controller are divided into one or more "Drive Groups", and then each Drive
-Group is subdivided further into 1 to 32 "Logical Drives".  Each Logical Drive
-has a specific RAID Level and caching policy associated with it, and it appears
-to Linux as a single block device.  Logical Drives are further subdivided into
-up to 7 partitions through the normal Linux and PC disk partitioning schemes.
-Logical Drives are also known as "System Drives", and Drive Groups are also
-called "Packs".  Both terms are in use in the Mylex documentation; I have
-chosen to standardize on the more generic "Logical Drive" and "Drive Group".
+Each DAC960 parallel SCSI controller can support up to 15 disk drives per
+channel, for a maximum of 60 drives on a four channel controller; the fibre
+channel eXtremeRAID 3000 controller supports up to 125 disk drives per loop for
+a total of 250 drives.  The drives installed on a controller are divided into
+one or more "Drive Groups", and then each Drive Group is subdivided further
+into 1 to 32 "Logical Drives".  Each Logical Drive has a specific RAID Level
+and caching policy associated with it, and it appears to Linux as a single
+block device.  Logical Drives are further subdivided into up to 7 partitions
+through the normal Linux and PC disk partitioning schemes.  Logical Drives are
+also known as "System Drives", and Drive Groups are also called "Packs".  Both
+terms are in use in the Mylex documentation; I have chosen to standardize on
+the more generic "Logical Drive" and "Drive Group".
 
 DAC960 RAID disk devices are named in the style of the Device File System
 (DEVFS).  The device corresponding to Logical Drive D on Controller C is
@@ -82,19 +89,41 @@
 Drive and 3 bits for the partition.
 
 
-		 SUPPORTED DAC960/DAC1100 PCI RAID CONTROLLERS
+	  SUPPORTED DAC960/AcceleRAID/eXtremeRAID PCI RAID CONTROLLERS
 
-The following list comprises the supported DAC960 and DAC1100 PCI RAID
-Controllers as of the date of this document.  It is recommended that anyone
-purchasing a Mylex PCI RAID Controller not in the following table contact the
-author beforehand to verify that it is or will be supported.  The eXtremeRAID
-2000, eXtremeRAID 3000, and AcceleRAID 352 have an entirely new firmware
-interface and are not yet supported by this driver.
+The following list comprises the supported DAC960, AcceleRAID, and eXtremeRAID
+PCI RAID Controllers as of the date of this document.  It is recommended that
+anyone purchasing a Mylex PCI RAID Controller not in the following table
+contact the author beforehand to verify that it is or will be supported.
+
+eXtremeRAID 3000
+	    1 Wide Ultra-2/LVD SCSI channel
+	    2 External Fibre FC-AL channels
+	    233MHz StrongARM SA 110 Processor
+	    64 Bit 33MHz PCI (backward compatible with 32 Bit PCI slots)
+	    32MB/64MB ECC SDRAM Memory
+
+eXtremeRAID 2000
+	    4 Wide Ultra-160 LVD SCSI channels
+	    233MHz StrongARM SA 110 Processor
+	    64 Bit 33MHz PCI (backward compatible with 32 Bit PCI slots)
+	    32MB/64MB ECC SDRAM Memory
 
+AcceleRAID 352
+	    2 Wide Ultra-160 LVD SCSI channels
+	    100MHz Intel i960RN RISC Processor
+	    64 Bit 33MHz PCI (backward compatible with 32 Bit PCI slots)
+	    32MB/64MB ECC SDRAM Memory
+
+AcceleRAID 170
+	    1 Wide Ultra-160 LVD SCSI channel
+	    100MHz Intel i960RM RISC Processor
+	    16MB/32MB/64MB ECC SDRAM Memory
+
 eXtremeRAID 1100 (DAC1164P)
 	    3 Wide Ultra-2/LVD SCSI channels
 	    233MHz StrongARM SA 110 Processor
-	    64 Bit PCI (backward compatible with 32 Bit PCI slots)
+	    64 Bit 33MHz PCI (backward compatible with 32 Bit PCI slots)
 	    16MB/32MB/64MB Parity SDRAM Memory with Battery Backup
 
 AcceleRAID 250 (DAC960PTL1)
@@ -135,6 +164,9 @@
 	    Intel i960 RISC Processor
 	    2MB/4MB/8MB/16MB/32MB DRAM Memory
 
+For the eXtremeRAID 2000/3000 and AcceleRAID 352/170, firmware version 6.00-01
+or above is required.
+
 For the eXtremeRAID 1100, firmware version 5.06-0-52 or above is required.
 
 For the AcceleRAID 250, 200, and 150, firmware version 4.06-0-57 or above is
@@ -165,16 +197,16 @@
 
 			      DRIVER INSTALLATION
 
-This distribution was prepared for Linux kernel version 2.2.14 or 2.0.38.
+This distribution was prepared for Linux kernel version 2.2.15 or 2.4.0.
 
 To install the DAC960 RAID driver, you may use the following commands,
 replacing "/usr/src" with wherever you keep your Linux kernel source tree:
 
   cd /usr/src
-  tar -xvzf DAC960-2.2.5.tar.gz (or DAC960-2.0.5.tar.gz)
+  tar -xvzf DAC960-2.2.6.tar.gz (or DAC960-2.4.6.tar.gz)
   mv README.DAC960 linux/Documentation
   mv DAC960.[ch] linux/drivers/block
-  patch -p0 < DAC960.patch (driver 2.0.5 only)
+  patch -p0 < DAC960.patch
   cd linux
   make config
   make depend
Index: oldkernel/linux/Documentation/README.ext3
diff -u /dev/null linux/Documentation/README.ext3:1.1
--- /dev/null	Mon Jul 31 21:15:04 2000
+++ linux/Documentation/README.ext3	Fri Jul  7 16:18:17 2000
@@ -0,0 +1,321 @@
+Journaling for ext2fs, alpha release 0.0.2d
+
+Released 22 March, 2000
+Stephen Tweedie <sct@redhat.com>
+
+
+*** Nobody accepts any responsibility if the use of this code damages
+*** your filesystem, corrupts data, creates a black hole or turns you
+*** into a sperm whale.  If I had a lawyer he'd probably have told me to
+*** say this.  You have been warned.
+
+
+Changes in this release
+-----------------------
+
+in 0.0.2d:
+
+Port forward to 2.2.15pre15
+
+Fixed a missing lock_journal in journal_forget() (this could potentially
+confuse the transaction engine when doing deletes under heavy memory
+pressure).
+
+Merged in a small directory IO error handling fix from ext2
+
+Included Andrea Arcangeli's elevator IO scheduling changes.  This should
+improve the performance of ext3 on non-SCSI devices substantially.
+
+
+in 0.0.2c:
+
+Lots of fixes to the way we set the filesystem's NEEDS_RECOVERY flag.
+It should basically get this right now.  This flag is the thing that
+prevents you from accidentally running e2fsck on a filesystem which
+still needs kernel attention after a crash or unclean shutdown.
+
+Fixed releasing of the journal inode when unmounting a readonly ext3
+filesystem.
+
+
+in 0.0.2b:
+
+Fixed a lockup when the VFS is trying to reclaim dirty inodes
+
+
+in 0.0.2a:
+
+Fixed a nasty bug in truncate.  If truncate overflowed the
+transaction, the transaction state machine could get seriously
+confused.
+
+0.0.2:
+
+Bug fixes.  Lots of bug fixes.  Buckets of them.
+
+It works on >1K blocksize filesystems.  It recovers reliably.  It
+survives log wraps properly during recovery.  mknod() works properly: it
+will no longer turn /dev into a socket if used on your root filesystem.  
+
+This one survives under load quite happily.  A 50-client dbench run
+completes reliably.
+
+So basically, this is the first usable ext3 release.
+
+Note that there are two major places where the implementation is not
+complete: clean handling of all errors (in particular out-of-memory and
+IO errors), and performance (there is still a lot of debugging code in
+place, and all data is journaled as part of the testing cycle).  But it
+is usable: I've been running it on all of my laptop's filesystems for
+over a week now.
+
+
+Future Milestones
+-----------------
+
+0.0.3 to deal gracefully with memory or disk failures.
+0.0.4 to deal with metadata-only journaling
+0.0.5 to disable the extra debugging code and add performance tuning
+0.1 to be released once all of that is solid.
+
+
+Introduction
+------------
+
+What is journaling?
+
+    * It means you don't have to fsck after a crash.  Basically.
+
+What works?
+
+    * Journaling to a journal file on the journaled filesystem
+
+    * Automatic recover when the filesystem is remounted
+
+    * All VFS operations (including quota) should be journaled
+
+    * Add data updates are also journaled
+
+
+What is left to be done?
+
+    * Journaling of metadata only.  Currently everything is journaled,
+      incuding data, resulting in a performance drop as all data gets
+      written twice.
+
+      Journaling of metadata only is supported but is not enabled.  It
+      turns out to involve several extra complications in the journaling
+      buffer state, so I'm testing the simpler case first to get that
+      reliable on its own.
+
+    * Journaling to an off-filesystem device, eg. NVRam
+
+    * Automatic reclamation of unlink but still-referenced files on
+      reboot
+
+    * Error recovery.  You will see that the source is marked quite
+      carefully where there are potential IO or memory allocation errors
+      which can disrupt things, but the code to respond to that (either
+      to remount the fs readonly or to abort and panic) remains to be
+      added. 
+
+    * Decent documentation!
+
+    * A few internal cleanups: migrating the extra buffer_head fields to
+      a separate jfs_buffer_info field in particular.
+
+    * e2fsprogs tools.  e2fsck needs to know about the journal (but see
+      below). 
+
+How to apply
+------------
+
+This README should have come with two diffs for kernel version
+linux-2.2.15pre15:
+
+  -rw-rw-r-- 1 sct sct 218556 Mar 23 18:19 linux-2.2.15pre15.kdb.diff
+  -rw-rw-r-- 1 sct sct 369304 Mar 23 18:25 linux-2.2.15pre15.ext3.diff
+
+and for the "2.2.14-5" kernel distributed with Red Hat 6.2:
+
+  -rw-rw-r-- 1 sct sct 369443 Mar 29 20:12 linux-2.2.14-5.ext3.diff
+  -rw-rw-r-- 1 sct sct 218645 Mar 29 20:06 linux-2.2.14-5.kdb.diff
+
+as well as an incremental diff to take ext3-0.0.2c up to 0.0.2d if you 
+would rather continue running ext3 on an existing (Red Hat 6.1 or 
+linux-2.2.13) kernel:
+
+  -rw-rw-r-- 1 sct sct  18512 Mar 22 15:38 0.0.2c-to-0.0.2d.diff
+
+The first diff of each set is copy of SGI's kdb kernel debugger patches.
+Apply this first if you want kdb.  The second patch is the ext3
+filesystem.  If you apply this without the kdb diff, you will get a
+couple of rejects (the ext3 diff includes a kdb module for interrogating
+jfs data structures) --- ignore those.
+
+If you can't apply kernel patches, stop reading this now.  Right now!
+
+Now, configure the kernel, saying YES to "Enable Second extended fs
+development code" (I *assume* you want it!), and build it.
+
+
+What next?
+----------
+
+Now, you want to make a journaled filesystem (recommended) or journal an
+existing one (for the exceptionally stupid/brave).  Great.  Go right
+ahead, make a new ext2 filesystem if you need to, and mount the
+filesystem you want to journal.  (Except see below for special
+instructions for the root filesystem).
+
+Be aware that the jfs patch does _not_ change the ext2 code.  Rather, it
+makes a copy of ext2 called ext3, and all the fancy footwork takes place
+in that.  You don't have to run ext3 on all your valuable filesystems:
+just use it on the throwaway ones.
+
+Now, create a journal file.  I don't know how big it should be yet: the
+rules of thumb have yet to be established!  However, try (say) 2MB for a
+small filesystem on a 486; maybe up to 30MB on a big 18G 10krpm Cheetah.
+Or whatever you want.  You need at least 1024 blocks for the journal, so
+on a filesystem with a blocksize of 4k the minimum journal is 4MB.
+
+You'll need to make sure that the file is preallocated, so use something
+like:
+
+	dd if=/dev/zero of=/mnt/sparefs/journal.dat bs=1k count=10000
+
+assuming you want a 10MB journal on a 1k ext2 filesystem mounted on
+/mnt/sparefs.  You need to find the journal inode's inode number, too:
+
+	ls -i /mnt/sparefs/journal.dat
+
+For a newly created filesystem, this will probably show
+
+        12 journal.dat
+
+OK, 12 is the expected number for a clean fs.  You might want to do a
+"chmod 400 journal.dat" right now to make sure that nobody will be
+able to poke around in the journal once it is running (don't worry,
+ext3 will be able to write to the journal even if you specify a
+read-only access mode for the file).
+
+Now, umount as ext2.  Take a deep breath.  Now mount as ext3, giving it
+the inode number of the file to be created as a journal:
+
+	mount -t ext3 /dev/sdb2 /mnt/sparefs -o journal=12
+
+Bingo.  That's it.  Enjoy!
+
+Note: The "-o journal=<nnn>" bit is only necessary when creating a new
+journal the first time you mount a filesystem as ext3.  Do _not_ add
+it to /etc/fstab: it will do no good at all there.
+
+Warning: the journaling will get _seriously_ confused if you try to 
+delete the journal file.  Future versions of ext3 will protect this 
+automatically, but for now you probably want to make it into an
+immutable file to guard it:
+
+	chattr +i /mnt/sparefs/journal.dat
+
+Setting the immutable bit will not prevent the filesystem from writing
+to the journal internally, but it will stop any other processes from
+modifying or removing the journal.
+
+
+Creating a journal on your root filesystem
+------------------------------------------
+
+How do you add the "-o journal=<nnn>" to the mount options for the
+root filesystem?  Obviously, / gets mounted for you by the kernel, so
+you can't add it on the mount command.  However, the ext3 comes with a
+new kernel boot option, "rootflags=", which lets you specify any
+options you want to be used when / is mounted.
+
+To create the journal on your root filesystem, then, you want to boot
+once with the rootflags option.  When creating the journal, it is also
+important to mount the root in read-write mode.  So, the kernel
+command line options you want to add will look like this:
+
+	rw rootflags=journal=12
+
+if your journal.dat is inode number 12.  If you are using LILO as your
+boot loader, you can either specify these options at the boot prompt,
+or you can force LILO to add new temporary kernel options just for the
+next boot only: if the LILO kernel image is called "ext3", then you
+can run
+
+	/sbin/lilo -R ext3 rw rootflags=journal=12
+
+and reboot to get the kernel to build your journal on the root
+filesystem.
+
+
+How to fsck
+-----------
+
+Right now, e2fsck will reject an uncleanly unmounted ext3 partition.
+However, if you umount an ext3 filesystem cleanly, you can fsck it using
+a version of fsck which understands the journal flags: you'll want
+e2fsprogs-1.17 or later, which you can get from the ext2 web pages at
+
+	http://web.mit.edu/tytso/www/linux/ext2.html
+	
+You can now run e2fsck quite happily on the filesystem, *as long as the
+filesystem was unmounted cleanly*.  If it wasn't, then you'll need to
+get the kernel code to recover the journal from the disk by mounting the
+filesystem (even a readonly mount will cause a journal recovery to
+happen) and umounting it again (or, for the root filesystem, remounting
+it readonly with "mount -o remount,ro /").
+
+However, the whole point is that you don't HAVE to run e2fsck after a
+crash, right?
+
+
+
+How to move back from ext3 to ext2
+----------------------------------
+
+It's quite easy.  If you unmount an ext3 filesystem cleanly, then you
+can remount it as ext2 without any other commands.  If you crash and are
+left with an unclean ext3 filesystem, on the other hand, the filesystem
+will prevent you from mounting it as ext2: it is not safe to mount it
+until you have recovered the journal, and the only way to do that for
+now is to mount it as ext3.
+
+However, if for any reason you do have an ext3 filesystem which you want
+to convert permanently back to ext2, whether it was cleanly unmounted or
+not, you can use "debugfs" from e2fsprogs-1.17 or later to do it.
+First, run debugfs and open the filesystem (the -w flag means open for
+write, and the -f flag forces it to open the filesystem even if there
+are unknown journal flags set):
+
+    [root@sarek /root]# debugfs
+    debugfs 1.18, 11-Nov-1999 for EXT2 FS 0.5b, 95/08/09
+    debugfs:  open -f -w /dev/sdb1 
+
+Now, use "features" to see which feature bits are set on the filesystem:
+
+    debugfs:  features
+    Filesystem features: has_journal filetype sparse_super
+
+We want to clear the journal bits, then we can quit:
+
+    debugfs:  features -has_journal -needs_recovery
+    Filesystem features: filetype sparse_super
+    debugfs:  quit
+    [root@sarek /root]# debugfs
+
+That's it!
+
+
+Known Bugs
+----------
+
+Lots of stuff is missing, in particular the ext3-aware fsck tools with
+built-in filesystem recovery. All of the other bugs are currently
+unknown.  Good luck finding them.
+
+
+
+Enjoy.
+--Stephen.
Index: oldkernel/linux/Documentation/readme.3ware
diff -u /dev/null linux/Documentation/readme.3ware:1.1
--- /dev/null	Mon Jul 31 21:15:04 2000
+++ linux/Documentation/readme.3ware	Fri Jul  7 16:18:17 2000
@@ -0,0 +1,270 @@
+Linux Installation Instructions (Beta release)
+
+The following instructions describe how to install Red Hat Linux 6.1 so 
+that you can boot your system off a disk or disk array installed on the 
+3ware controller. 
+
+If you are installing the controller on a system that already has linux 
+installed on a unit connected to the system, follow the instructions in 
+Appendix A: Installing the controller on systems that boot from another 
+device. 
+
+If you are installing the controller using a kit downloaded from the 
+3ware website, your must first create a 3ware linux software diskette 
+using the instructions in Appendix B: Creating a 3ware linux software 
+diskette from a www.3ware.com download kit. 
+
+Materials required:
+·	3ware Software Installation diskette (contains driver, 3DM utility, 
+	and driver source code)
+·	Red Hat 6.1 boot diskette
+·	Red Hat 6.1 Linux Installation CD-ROM
+
+Set the boot order using the BIOS Setup utility 
+1.	Using your system’s BIOS Setup utility, set your floppy drive (i.e. 
+removable device) as first device in the boot order since you will be using 
+floppy diskette to install linux.
+
+2.	Since you will be booting off of the 3ware controller once the linux 
+installation is complete, make the controller the second device in the boot 
+order in preparation for future booting. If you have other bootable devices 
+installed in your system, it is particularly important that the controller 
+precedes them in the boot order.
+
+Note: There have been test systems where an IDE drive connected to the 
+motherboard interfered with using the 3ware controller as a boot device. 
+Disconnecting the IDE drive when installing linux will eliminate this problem. 
+After linux is installed, the drive can be reconnected. We are investigating 
+a better solution.
+ 
+Create disk arrays using the BIOS utility
+1.	During the boot phase, wait until you see a message similar to the 
+following appear:
+
+3ware Storage Controller BIOS 1.02
+
+Port 0 Maxtor DiamondMax Plus 6800 20.5 GB 
+Port 1 Maxtor DiamondMax Plus 6800 20.5 GB
+Port 2 Maxtor DiamondMax Plus 6800 20.5 GB
+Port 3 Maxtor DiamondMax Plus 6800 20.5 GB
+
+*** Press <Alt-3> to access 3ware Configuration Screen ***
+
+2.	As soon as it appears, press ALT-3 to bring up the 3ware Disk Array 
+Configuration utility.
+
+3.	Use the Disk Array Configuration utility to create disk arrays as 
+needed. For detailed instructions, see the Using the 3ware Disk Array 
+Configuration Utility section of the 3ware Storage Controller User Guide. 
+You may use either a disk array or independent (individual) disk as your boot 
+device.
+
+Boot the system with both the Linux diskette and CD
+
+1.	Insert Linux Boot Disk into the floppy drive, and insert the Red Hat 
+Linux Installation CD into the CD-ROM.
+
+2.	Restart your computer.
+
+3.	When the Welcome to Red Hat 6.1 screen appears, type expert at the 
+boot prompt.
+
+	boot: expert
+
+Install the driver 
+1.	After loading a number of files, you will be asked to Insert your driver 
+disk. Remove the boot diskette from the floppy, insert the 3ware linux driver 
+diskette, and press OK.
+
+2.	Select the proper language and keyboard types for your locality.
+
+3.	If asked for what type of media, select Local CD-ROM since you are 
+installing from CD-ROM.
+4.	When asked if you would like to specify a special device driver, select 
+Add Device, and press Return.
+5.	When asked what kind of device you would like to add, select SCSI.
+6.	Scroll down the list and select the 3ware Storage Controller.
+7.	The system will inform you that it has found a 3ware Storage Controller.
+8.	Installing the driver will conclude with a message: I have found the 
+following devices in your system and should list the 3ware Storage Controller. 
+Unless you have other third party devices to install in your system, select Done.
+ 
+Complete the normal linux installation
+
+Continue with the Red Hat Linux 6.1 installation. Refer to the Red Hat 
+documentation for questions or problems.
+Install the 3DM disk management utility
+
+The 3DM utility allows you to view status and version information about your 
+3ware storage controller.  When a window is left open with 3DM running, it 
+can also alert you when a disk array needs maintenance by beeping and displaying 
+alert messages.
+
+1.	Insert the 3ware Software Installation diskette for Linux into the floppy 
+drive.
+
+2.	 Mount the floppy drive:
+
+mount -t msdos /dev/fd0 /mnt/floppy
+
+3.	Copy the 3DM executable file into a directory on your system, such as /usr/local/bin.
+
+cp /mnt/floppy/3dm /usr/local/bin
+
+4.	Unmount the floppy drive.
+
+umount /mnt/floppy
+
+5.	Ensure that 3DM has executable permissions.  If not, change the permissions with
+
+chmod u+x /usr/local/bin/3dm
+
+6.	Login as root on the system console and run 3DM from a terminal window:
+
+/usr/local/bin/3dm
+
+7.	To run 3DM in quiet mode where it does not beep on disk failure:
+
+/usr/local/bin/3dm -q
+
+8.	To capture output in a log file.
+
+/usr/local/bin/3dm > logfile
+
+
+If you have any questions, please feel free to visit our website at www.3ware.com 
+or call us at 877-88-3ware (877-883-9273) or direct at (650) 614 - 3439. 
+
+
+Appendix A
+
+Installing the controller on systems that boot from another device.
+Materials required:
+·	3ware software diskette (contains 3ware driver and 3DM management utility)
+
+Create disk arrays using the BIOS utility
+1.	During the boot phase, wait until you see a message similar to the 
+following appear:
+
+3ware Storage Controller BIOS 1.02
+
+Port 0 Maxtor DiamondMax Plus 6800 20.5 GB 
+Port 1 Maxtor DiamondMax Plus 6800 20.5 GB
+Port 2 Maxtor DiamondMax Plus 6800 20.5 GB
+Port 3 Maxtor DiamondMax Plus 6800 20.5 GB
+
+*** Press <Alt-3> to access 3ware Configuration Screen ***
+
+2.	As soon as it appears, press ALT-3 to bring up the 3ware Disk Array 
+Configuration utility (Figure 3).
+
+3.	Use the Disk Array Configuration utility to create disk arrays as 
+needed. For detailed instructions, see the Using the 3ware Disk Array 
+Configuration Utility section of the 3ware Storage Controller User Guide. 
+You may use either a disk array or independent (individual) disk as your 
+boot device. Install the driver.
+
+Case 1: Your system runs Red Hat 6.1 (Kernel 2.2.12-20)
+
+1.	Mount the floppy drive and copy the driver file into a working directory.
+
+mount -t msdos /dev/fd0 /mnt/floppy
+cp /mnt/floppy/3w-xxxx.o /lib/modules/2.2.12-20/scsi
+/sbin/insmod /lib/modules/2.2.12-20/scsi/3w-xxxx.o
+
+ 
+Case 2: Your system runs Red Hat 6.1 (Kernel 2.2.12-20) and is an SMP system (multi-processor)
+
+1.	Mount the floppy drive and copy the driver file into a working directory.
+
+mount -t msdos /dev/fd0 /mnt/floppy
+cp /mnt/floppy/3w-xxxx.smp /lib/modules/2.2.12-20/scsi/3w-xxxx.o
+/sbin/insmod /lib/modules/2.2.12-20/scsi/3w-xxxx.o
+
+ 
+Case 3: Your system runs a version that is NOT Red Hat 6.1 (Kernel 2.2.12-20)
+
+1.	Mount the floppy drive and copy the driver source file into a working 
+directory, compile and load it.
+
+cd workingdir
+mount -t msdos /dev/fd0 /mnt/floppy
+cp /mnt/floppy/3w-xxxx.tgz .
+tar zxf 3w-xxxx.tgz
+cd driver
+make
+/sbin/insmod 3w-xxxx.o
+
+Note:  If you are using an SMP linux system, modify the Makefile to include 
+the flag -D_SMP_
+
+Install the 3DM disk management utility
+
+The 3DM utility allows you to view status and version information about your 
+3ware storage controller.  When a window is left open with 3DM running, it can 
+also alert you when a disk array needs maintenance by beeping and displaying 
+alert messages.
+
+1.	Insert the 3ware Software Installation diskette for Linux into the 
+floppy drive.
+
+2.	 Mount the floppy drive:
+
+mount -t msdos /dev/fd0 /mnt/floppy
+
+3.	Copy the 3DM executable file into a directory on your system, such as /usr/local/bin.
+
+cp /mnt/floppy/3dm /usr/local/bin
+
+4.	Unmount the floppy drive.
+
+umount /mnt/floppy
+
+5.	Ensure that 3DM has executable permissions.  If not, change the 
+permissions with
+
+chmod u+x /usr/local/bin/3dm
+
+6.	Login as root on the system console and run 3DM from a terminal window:
+
+/usr/local/bin/3dm
+
+7.	To run 3DM in quiet mode where it does not beep on disk failure:
+
+/usr/local/bin/3dm -q
+
+8.	To capture output in a log file.
+
+/usr/local/bin/3dm > logfile
+
+ 
+
+Appendix B
+Creating a 3ware software diskette for linux from a www.3ware.com download kit
+
+From www.3ware.com, download the linux software kit. 
+
+If the file was downloaded onto a linux system, insert a blank floppy diskette 
+and issue the following commands:
+
+unzip filename.zip
+cd driver
+mkfs -t msdos /dev/fd0
+mount -t msdos /dev/fd0 /mnt/floppy
+cp * /mnt/floppy
+ummount /mnt/floppy
+
+Where filename is the base name of the file downloaded (e.g. linux_driver.zip)
+
+If the file was downloaded onto a Windows system insert a blank floppy diskette 
+and issue the following commands:
+
+pkunzip -d filename.zip (or use WinZip)
+cd driver
+format a:
+copy * a:
+
+Where filename is the base name of the file downloaded (e.g. linux_driver.zip)
+
+
+
Index: oldkernel/linux/arch/alpha/config.in
diff -u linux/arch/alpha/config.in:1.1.1.1 linux/arch/alpha/config.in:1.2
--- linux/arch/alpha/config.in:1.1.1.1	Wed May 31 12:33:53 2000
+++ linux/arch/alpha/config.in	Fri Jul  7 15:36:41 2000
@@ -157,7 +157,7 @@
 	-o "$CONFIG_ALPHA_NORITAKE" = "y" -o "$CONFIG_ALPHA_PC164" = "y" \
 	-o "$CONFIG_ALPHA_LX164" = "y" -o "$CONFIG_ALPHA_SX164" = "y" \
 	-o "$CONFIG_ALPHA_DP264" = "y" -o "$CONFIG_ALPHA_RAWHIDE" = "y" \
-	-o "$CONFIG_ALPHA_EIGER" = "y" ]
+	-o "$CONFIG_ALPHA_EIGER" = "y" -o "$CONFIG_ALPHA_NAUTILUS" = "y" ]
 then
   bool 'Use SRM as bootloader' CONFIG_ALPHA_SRM
   if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
Index: oldkernel/linux/arch/alpha/kernel/alpha_ksyms.c
diff -u linux/arch/alpha/kernel/alpha_ksyms.c:1.1.1.1 linux/arch/alpha/kernel/alpha_ksyms.c:1.2
--- linux/arch/alpha/kernel/alpha_ksyms.c:1.1.1.1	Wed May 31 12:33:53 2000
+++ linux/arch/alpha/kernel/alpha_ksyms.c	Fri Jul  7 15:36:41 2000
@@ -54,6 +54,7 @@
 EXPORT_SYMBOL(disable_irq_nosync);
 EXPORT_SYMBOL(screen_info);
 EXPORT_SYMBOL(perf_irq);
+EXPORT_SYMBOL(init_mm);
 
 /* platform dependent support */
 EXPORT_SYMBOL(_inb);
@@ -160,6 +161,7 @@
 EXPORT_SYMBOL(flush_tlb_mm);
 EXPORT_SYMBOL(flush_tlb_page);
 EXPORT_SYMBOL(flush_tlb_range);
+EXPORT_SYMBOL(smp_imb);
 EXPORT_SYMBOL(cpu_data);
 EXPORT_SYMBOL(cpu_number_map);
 EXPORT_SYMBOL(global_bh_lock);
Index: oldkernel/linux/arch/alpha/kernel/smp.c
diff -u linux/arch/alpha/kernel/smp.c:1.1.1.1 linux/arch/alpha/kernel/smp.c:1.2
--- linux/arch/alpha/kernel/smp.c:1.1.1.1	Wed May 31 12:33:53 2000
+++ linux/arch/alpha/kernel/smp.c	Fri Jul  7 15:36:41 2000
@@ -839,6 +839,22 @@
 }
 
 static void
+ipi_imb(void *ignored)
+{
+	imb();
+}
+
+void
+smp_imb(void)
+{
+	/* Must wait other processors to flush their icache before continue. */
+	if (smp_call_function(ipi_imb, NULL, 1, 1))
+		printk(KERN_CRIT "smp_imb: timed out\n");
+
+	imb();
+}
+
+static void
 ipi_flush_tlb_all(void *ignored)
 {
 	tbia();
Index: oldkernel/linux/arch/alpha/kernel/sys_nautilus.c
diff -u linux/arch/alpha/kernel/sys_nautilus.c:1.2 linux/arch/alpha/kernel/sys_nautilus.c:1.3
--- linux/arch/alpha/kernel/sys_nautilus.c:1.2	Thu Jun  1 15:17:55 2000
+++ linux/arch/alpha/kernel/sys_nautilus.c	Fri Jul  7 15:36:41 2000
@@ -69,6 +69,11 @@
 {
 	STANDARD_INIT_IRQ_PROLOG;
 
+	if (alpha_using_srm) {
+		alpha_mv.device_interrupt = srm_device_interrupt;
+		alpha_mv.kill_arch = generic_kill_arch;
+	}
+
 	enable_irq(2);			/* enable cascade */
 	disable_irq(8);
 }
@@ -111,7 +116,7 @@
 	case LINUX_REBOOT_CMD_RESTART:
 		{
 			int v;
-			irongate_hose_write_config_byte(0, 0x07<<3, 0x43, &v, 0);
+			irongate_hose_read_config_byte(0, 0x07<<3, 0x43, &v, 0);
 			irongate_hose_write_config_byte(0, 0x07<<3, 0x43, v | 0x80, 0);
 			outb(1, 0x92);
 			outb(0, 0x92);
Index: oldkernel/linux/arch/i386/config.in
diff -u linux/arch/i386/config.in:1.4 linux/arch/i386/config.in:1.5
--- linux/arch/i386/config.in:1.4	Thu Jun  1 17:06:03 2000
+++ linux/arch/i386/config.in	Fri Jul  7 15:36:41 2000
@@ -33,10 +33,9 @@
 fi
 if [ "$CONFIG_M686FX" = "y" -o "$CONFIG_M686" = "y" ]; then
   define_bool CONFIG_X86_GOOD_APIC y
-  bool 'Disable the PII/PIII Serial Number at bootup' CONFIG_X86_PN_OFF
-  bool 'Enable PII/PIII Extended/Fast FPU save and restore support' CONFIG_X86_FX
-  bool 'Enable CPU Specific (MMX/MMX2) Optimization Functions' CONFIG_X86_CPU_OPTIMIZATIONS
 fi
+bool 'Disable the PII/PIII Serial Number at bootup' CONFIG_X86_PN_OFF
+bool 'Enable PII/PIII Extended/Fast FPU save and restore support' CONFIG_X86_FX
 bool 'Math emulation' CONFIG_MATH_EMULATION
 bool 'MTRR (Memory Type Range Register) support' CONFIG_MTRR
 bool 'Symmetric multi-processing support' CONFIG_SMP
Index: oldkernel/linux/arch/i386/defconfig
diff -u linux/arch/i386/defconfig:1.3 linux/arch/i386/defconfig:1.4
--- linux/arch/i386/defconfig:1.3	Thu Jun  1 15:05:19 2000
+++ linux/arch/i386/defconfig	Fri Jul  7 15:36:41 2000
@@ -5,41 +5,36 @@
 #
 # Code maturity level options
 #
-# CONFIG_EXPERIMENTAL is not set
+CONFIG_EXPERIMENTAL=y
 
 #
 # Processor type and features
 #
-# CONFIG_M386 is not set
+CONFIG_M386=y
 # CONFIG_M486 is not set
 # CONFIG_M586 is not set
 # CONFIG_M586TSC is not set
-CONFIG_M686=y
-CONFIG_X86_WP_WORKS_OK=y
-CONFIG_X86_INVLPG=y
-CONFIG_X86_BSWAP=y
-CONFIG_X86_POPAD_OK=y
-CONFIG_X86_TSC=y
-CONFIG_X86_GOOD_APIC=y
+# CONFIG_M686 is not set
 CONFIG_X86_PN_OFF=y
 CONFIG_X86_FX=y
-CONFIG_X86_CPU_OPTIMIZATIONS=y
-# CONFIG_MATH_EMULATION is not set
-# CONFIG_MTRR is not set
-CONFIG_SMP=y
+# CONFIG_X86_CPU_OPTIMIZATIONS is not set
 CONFIG_1GB=y
 # CONFIG_2GB is not set
+CONFIG_MATH_EMULATION=y
+CONFIG_MTRR=y
+CONFIG_SMP=y
 
 #
 # Loadable module support
 #
 CONFIG_MODULES=y
-# CONFIG_MODVERSIONS is not set
-# CONFIG_KMOD is not set
+CONFIG_MODVERSIONS=y
+CONFIG_KMOD=y
 
 #
 # General setup
 #
+CONFIG_BIGMEM=y
 CONFIG_NET=y
 CONFIG_PCI=y
 # CONFIG_PCI_GOBIOS is not set
@@ -48,24 +43,38 @@
 CONFIG_PCI_BIOS=y
 CONFIG_PCI_DIRECT=y
 CONFIG_PCI_QUIRKS=y
+# CONFIG_PCI_OPTIMIZE is not set
 CONFIG_PCI_OLD_PROC=y
 # CONFIG_MCA is not set
 # CONFIG_VISWS is not set
 CONFIG_X86_IO_APIC=y
 CONFIG_X86_LOCAL_APIC=y
 CONFIG_SYSVIPC=y
-# CONFIG_BSD_PROCESS_ACCT is not set
+CONFIG_BSD_PROCESS_ACCT=y
 CONFIG_SYSCTL=y
-CONFIG_BINFMT_AOUT=y
+CONFIG_BINFMT_AOUT=m
 CONFIG_BINFMT_ELF=y
-CONFIG_BINFMT_MISC=y
-# CONFIG_PARPORT is not set
-# CONFIG_APM is not set
+CONFIG_BINFMT_MISC=m
+CONFIG_BINFMT_JAVA=m
+CONFIG_PARPORT=m
+CONFIG_PARPORT_PC=m
+# CONFIG_PARPORT_OTHER is not set
+CONFIG_APM=y
+# CONFIG_APM_IGNORE_USER_SUSPEND is not set
+# CONFIG_APM_DO_ENABLE is not set
+# CONFIG_APM_CPU_IDLE is not set
+# CONFIG_APM_DISPLAY_BLANK is not set
+CONFIG_APM_POWER_OFF=y
+# CONFIG_APM_IGNORE_MULTIPLE_SUSPEND is not set
+# CONFIG_APM_IGNORE_SUSPEND_BOUNCE is not set
+CONFIG_APM_RTC_IS_GMT=y
+# CONFIG_APM_ALLOW_INTS is not set
 
 #
 # Plug and Play support
 #
-# CONFIG_PNP is not set
+CONFIG_PNP=y
+CONFIG_PNP_PARPORT=m
 
 #
 # Block devices
@@ -78,70 +87,157 @@
 #
 # CONFIG_BLK_DEV_HD_IDE is not set
 CONFIG_BLK_DEV_IDEDISK=y
-CONFIG_BLK_DEV_IDECD=y
-# CONFIG_BLK_DEV_IDETAPE is not set
-# CONFIG_BLK_DEV_IDEFLOPPY is not set
-# CONFIG_BLK_DEV_IDESCSI is not set
-CONFIG_BLK_DEV_CMD640=y
-# CONFIG_BLK_DEV_CMD640_ENHANCED is not set
-CONFIG_BLK_DEV_RZ1000=y
+CONFIG_BLK_DEV_IDECD=m
+CONFIG_BLK_DEV_IDETAPE=m
+CONFIG_BLK_DEV_IDEFLOPPY=m
+CONFIG_BLK_DEV_IDESCSI=m
+# CONFIG_BLK_DEV_CMD640 is not set
+# CONFIG_BLK_DEV_RZ1000 is not set
 CONFIG_BLK_DEV_IDEPCI=y
 CONFIG_BLK_DEV_IDEDMA=y
 # CONFIG_BLK_DEV_OFFBOARD is not set
 CONFIG_IDEDMA_AUTO=y
+# CONFIG_BLK_DEV_OPTI621 is not set
+# CONFIG_BLK_DEV_TRM290 is not set
+# CONFIG_BLK_DEV_NS87415 is not set
+# CONFIG_BLK_DEV_VIA82C586 is not set
+# CONFIG_BLK_DEV_CMD646 is not set
 # CONFIG_IDE_CHIPSETS is not set
 
 #
 # Additional Block Devices
 #
-# CONFIG_BLK_DEV_LOOP is not set
-# CONFIG_BLK_DEV_NBD is not set
-CONFIG_BLK_DEV_MD=y
+CONFIG_BLK_DEV_LOOP=m
+CONFIG_BLK_DEV_NBD=m
+# CONFIG_BLK_DEV_MD is not set
 CONFIG_AUTODETECT_RAID=y
-CONFIG_MD_TRANSLUCENT=y
-CONFIG_MD_LINEAR=y
-CONFIG_MD_STRIPED=y
-CONFIG_MD_MIRRORING=y
-CONFIG_MD_RAID5=y
-CONFIG_MD_BOOT=y
-CONFIG_BLK_DEV_HSM=y
-# CONFIG_BLK_DEV_RAM is not set
-# CONFIG_BLK_DEV_XD is not set
-CONFIG_PARIDE_PARPORT=y
-# CONFIG_PARIDE is not set
+CONFIG_MD_LINEAR=m
+CONFIG_MD_STRIPED=m
+CONFIG_MD_MIRRORING=m
+CONFIG_MD_RAID5=m
+# CONFIG_MD_TRANSLUCENT is not set
+# CONFIG_MD_HSM is not set
+CONFIG_BLK_DEV_RAM=y
+CONFIG_BLK_DEV_INITRD=y
+CONFIG_BLK_DEV_XD=m
+CONFIG_BLK_DEV_DAC960=y
+CONFIG_BLK_DEV_3WARE=y
+CONFIG_PARIDE_PARPORT=m
+CONFIG_PARIDE=m
+
+#
+# Parallel IDE high-level drivers
+#
+CONFIG_PARIDE_PD=m
+CONFIG_PARIDE_PCD=m
+CONFIG_PARIDE_PF=m
+CONFIG_PARIDE_PT=m
+CONFIG_PARIDE_PG=m
+
+#
+# Parallel IDE protocol modules
+#
+CONFIG_PARIDE_ATEN=m
+CONFIG_PARIDE_BPCK=m
+CONFIG_PARIDE_COMM=m
+CONFIG_PARIDE_DSTR=m
+CONFIG_PARIDE_FIT2=m
+CONFIG_PARIDE_FIT3=m
+CONFIG_PARIDE_EPAT=m
+CONFIG_PARIDE_EPIA=m
+CONFIG_PARIDE_FRIQ=m
+CONFIG_PARIDE_FRPW=m
+CONFIG_PARIDE_KBIC=m
+CONFIG_PARIDE_KTTI=m
+CONFIG_PARIDE_ON20=m
+CONFIG_PARIDE_ON26=m
+CONFIG_BLK_CPQ_DA=m
 # CONFIG_BLK_DEV_HD is not set
 
 #
 # Networking options
 #
 CONFIG_PACKET=y
-# CONFIG_NETLINK is not set
-# CONFIG_FIREWALL is not set
-# CONFIG_FILTER is not set
+CONFIG_NETLINK=y
+CONFIG_RTNETLINK=y
+CONFIG_NETLINK_DEV=y
+CONFIG_FIREWALL=y
+CONFIG_FILTER=y
 CONFIG_UNIX=y
 CONFIG_INET=y
-# CONFIG_IP_MULTICAST is not set
+CONFIG_IP_MULTICAST=y
 # CONFIG_IP_ADVANCED_ROUTER is not set
 # CONFIG_IP_PNP is not set
+CONFIG_IP_FIREWALL=y
+CONFIG_IP_FIREWALL_NETLINK=y
+CONFIG_NETLINK_DEV=y
+CONFIG_IP_TRANSPARENT_PROXY=y
+CONFIG_IP_MASQUERADE=y
+
+#
+# Protocol-specific masquerading support will be built as modules.
+#
+# CONFIG_IP_MASQUERADE_UDP_LOOSE is not set
+CONFIG_IP_MASQUERADE_ICMP=y
+
+#
+# Protocol-specific masquerading support will be built as modules.
+#
+CONFIG_IP_MASQUERADE_MOD=y
+CONFIG_IP_MASQUERADE_IPAUTOFW=m
+CONFIG_IP_MASQUERADE_IPPORTFW=m
+CONFIG_IP_MASQUERADE_MFW=m
+CONFIG_IP_MASQUERADE_VS=y
+CONFIG_IP_MASQUERADE_VS_TAB_BITS=12
+CONFIG_IP_MASQUERADE_VS_RR=m
+CONFIG_IP_MASQUERADE_VS_WRR=m
+CONFIG_IP_MASQUERADE_VS_LC=m
+CONFIG_IP_MASQUERADE_VS_WLC=m
 # CONFIG_IP_ROUTER is not set
-# CONFIG_NET_IPIP is not set
-# CONFIG_NET_IPGRE is not set
-# CONFIG_IP_ALIAS is not set
-# CONFIG_SYN_COOKIES is not set
+CONFIG_NET_IPIP=m
+CONFIG_NET_IPGRE=m
+CONFIG_NET_IPGRE_BROADCAST=y
+# CONFIG_IP_MROUTE is not set
+CONFIG_IP_ALIAS=y
+# CONFIG_ARPD is not set
+CONFIG_SYN_COOKIES=y
 
 #
 # (it is safe to leave these untouched)
 #
-# CONFIG_INET_RARP is not set
+CONFIG_INET_RARP=m
 CONFIG_SKB_LARGE=y
+# CONFIG_IPV6 is not set
 
 #
 #  
 #
-# CONFIG_IPX is not set
-# CONFIG_ATALK is not set
+CONFIG_IPX=m
+# CONFIG_IPX_INTERN is not set
+# CONFIG_SPX is not set
+CONFIG_ATALK=m
+# CONFIG_X25 is not set
+# CONFIG_LAPB is not set
+# CONFIG_BRIDGE is not set
+# CONFIG_LLC is not set
+# CONFIG_ECONET is not set
+CONFIG_WAN_ROUTER=m
+# CONFIG_NET_FASTROUTE is not set
+# CONFIG_NET_HW_FLOWCONTROL is not set
+# CONFIG_CPU_IS_SLOW is not set
+
+#
+# QoS and/or fair queueing
+#
+# CONFIG_NET_SCHED is not set
 
 #
+# Telephony Support
+#
+CONFIG_PHONE=m
+CONFIG_PHONE_IXJ=m
+
+#
 # SCSI support
 #
 CONFIG_SCSI=y
@@ -150,102 +246,241 @@
 # SCSI support type (disk, tape, CD-ROM)
 #
 CONFIG_BLK_DEV_SD=y
-# CONFIG_CHR_DEV_ST is not set
-# CONFIG_BLK_DEV_SR is not set
-# CONFIG_CHR_DEV_SG is not set
+CONFIG_CHR_DEV_ST=y
+CONFIG_BLK_DEV_SR=y
+CONFIG_BLK_DEV_SR_VENDOR=y
+CONFIG_CHR_DEV_SG=m
 
 #
 # Some SCSI devices (e.g. CD jukebox) support multiple LUNs
 #
-CONFIG_SCSI_MULTI_LUN=y
+# CONFIG_SCSI_MULTI_LUN is not set
 CONFIG_SCSI_CONSTANTS=y
-# CONFIG_SCSI_LOGGING is not set
+CONFIG_SCSI_LOGGING=y
 
 #
 # SCSI low-level drivers
 #
-# CONFIG_SCSI_7000FASST is not set
-# CONFIG_SCSI_ACARD is not set
-# CONFIG_SCSI_AHA152X is not set
-# CONFIG_SCSI_AHA1542 is not set
-# CONFIG_SCSI_AHA1740 is not set
-# CONFIG_SCSI_AIC7XXX is not set
-# CONFIG_SCSI_ADVANSYS is not set
-# CONFIG_SCSI_IN2000 is not set
-# CONFIG_SCSI_AM53C974 is not set
-# CONFIG_SCSI_MEGARAID is not set
-# CONFIG_SCSI_BUSLOGIC is not set
-# CONFIG_SCSI_DTC3280 is not set
-# CONFIG_SCSI_EATA is not set
+CONFIG_SCSI_7000FASST=m
+CONFIG_SCSI_ACARD=m
+CONFIG_SCSI_AHA152X=m
+CONFIG_SCSI_AHA1542=m
+CONFIG_SCSI_AHA1740=m
+CONFIG_SCSI_AIC7XXX=y
+CONFIG_AIC7XXX_TCQ_ON_BY_DEFAULT=y
+CONFIG_AIC7XXX_CMDS_PER_DEVICE=8
+CONFIG_AIC7XXX_PROC_STATS=y
+CONFIG_AIC7XXX_RESET_DELAY=5
+CONFIG_SCSI_IPS=m
+CONFIG_SCSI_ADVANSYS=m
+CONFIG_SCSI_IN2000=m
+CONFIG_SCSI_AM53C974=m
+CONFIG_SCSI_MEGARAID=m
+CONFIG_SCSI_BUSLOGIC=m
+# CONFIG_SCSI_OMIT_FLASHPOINT is not set
+CONFIG_SCSI_DTC3280=m
+CONFIG_SCSI_EATA=y
+CONFIG_SCSI_EATA_TAGGED_QUEUE=y
+# CONFIG_SCSI_EATA_LINKED_COMMANDS is not set
+CONFIG_SCSI_EATA_MAX_TAGS=16
 # CONFIG_SCSI_EATA_DMA is not set
-# CONFIG_SCSI_EATA_PIO is not set
-# CONFIG_SCSI_FUTURE_DOMAIN is not set
-# CONFIG_SCSI_GDTH is not set
-# CONFIG_SCSI_GENERIC_NCR5380 is not set
-# CONFIG_SCSI_INITIO is not set
-# CONFIG_SCSI_INIA100 is not set
-# CONFIG_SCSI_NCR53C406A is not set
-# CONFIG_SCSI_SYM53C416 is not set
-# CONFIG_SCSI_NCR53C7xx is not set
-# CONFIG_SCSI_NCR53C8XX is not set
+CONFIG_SCSI_EATA_PIO=m
+CONFIG_SCSI_FUTURE_DOMAIN=m
+CONFIG_SCSI_GDTH=y
+CONFIG_SCSI_GENERIC_NCR5380=m
+# CONFIG_SCSI_GENERIC_NCR53C400 is not set
+CONFIG_SCSI_G_NCR5380_PORT=y
+# CONFIG_SCSI_G_NCR5380_MEM is not set
+CONFIG_SCSI_INITIO=m
+CONFIG_SCSI_INIA100=m
+CONFIG_SCSI_PPA=m
+CONFIG_SCSI_IMM=m
+# CONFIG_SCSI_IZIP_EPP16 is not set
+# CONFIG_SCSI_IZIP_SLOW_CTR is not set
+CONFIG_SCSI_NCR53C406A=m
+CONFIG_SCSI_SYM53C416=m
+CONFIG_SCSI_SIM710=m
+CONFIG_SCSI_SIM710=m
+CONFIG_SCSI_NCR53C7xx=m
+CONFIG_SCSI_SIM710=m
+# CONFIG_SCSI_NCR53C7xx_sync is not set
+CONFIG_SCSI_SIM710=m
+CONFIG_SCSI_NCR53C7xx_FAST=y
+CONFIG_SCSI_SIM710=m
+CONFIG_SCSI_NCR53C7xx_DISCONNECT=y
+CONFIG_SCSI_NCR53C8XX=y
 CONFIG_SCSI_SYM53C8XX=y
-CONFIG_SCSI_NCR53C8XX_DEFAULT_TAGS=4
+CONFIG_SCSI_NCR53C8XX_DEFAULT_TAGS=8
 CONFIG_SCSI_NCR53C8XX_MAX_TAGS=32
-CONFIG_SCSI_NCR53C8XX_SYNC=20
-# CONFIG_SCSI_NCR53C8XX_PROFILE is not set
+CONFIG_SCSI_NCR53C8XX_SYNC=80
+CONFIG_SCSI_NCR53C8XX_PROFILE=y
 # CONFIG_SCSI_NCR53C8XX_IOMAPPED is not set
-# CONFIG_SCSI_NCR53C8XX_PQS_PDS is not set
-# CONFIG_SCSI_PAS16 is not set
-# CONFIG_SCSI_PCI2000 is not set
-# CONFIG_SCSI_PCI2220I is not set
-# CONFIG_SCSI_PSI240I is not set
-# CONFIG_SCSI_QLOGIC_FAS is not set
-# CONFIG_SCSI_QLOGIC_ISP is not set
-# CONFIG_SCSI_QLOGIC_FC is not set
-# CONFIG_SCSI_SEAGATE is not set
-# CONFIG_SCSI_DC390T is not set
-# CONFIG_SCSI_T128 is not set
-# CONFIG_SCSI_U14_34F is not set
-# CONFIG_SCSI_ULTRASTOR is not set
+CONFIG_SCSI_NCR53C8XX_SYMBIOS_COMPAT=y
+CONFIG_SCSI_NCR53C8XX_PQS_PDS=y 
+# CONFIG_SCSI_NCR53C8XX_IARB is not set 
+CONFIG_SCSI_NCR53C8XX_INTEGRITY_CHECK=y
+CONFIG_SCSI_PAS16=m
+CONFIG_SCSI_PCI2000=m
+CONFIG_SCSI_PCI2220I=m
+CONFIG_SCSI_PSI240I=m
+CONFIG_SCSI_QLOGIC_FAS=m
+CONFIG_SCSI_QLOGIC_ISP=m
+CONFIG_SCSI_QLOGIC_FC=m
+CONFIG_SCSI_SEAGATE=m
+CONFIG_SCSI_DC390T=m
+# CONFIG_SCSI_DC390T_NOGENSUPP is not set
+CONFIG_SCSI_T128=m
+CONFIG_SCSI_U14_34F=m
+# CONFIG_SCSI_U14_34F_LINKED_COMMANDS is not set
+CONFIG_SCSI_U14_34F_MAX_TAGS=8
+CONFIG_SCSI_ULTRASTOR=m
+CONFIG_SCSI_DEBUG=m
 
 #
 # Network device support
 #
 CONFIG_NETDEVICES=y
+
+#
+# ARCnet devices
+#
 # CONFIG_ARCNET is not set
 CONFIG_DUMMY=m
-# CONFIG_EQUALIZER is not set
+CONFIG_BONDING=m
+CONFIG_EQUALIZER=m
+CONFIG_ETHERTAP=m
+CONFIG_NET_SB1000=m
+
+#
+# Ethernet (10 or 100Mbit)
+#
 CONFIG_NET_ETHERNET=y
-# CONFIG_NET_VENDOR_3COM is not set
-# CONFIG_LANCE is not set
-# CONFIG_NET_VENDOR_SMC is not set
-# CONFIG_NET_VENDOR_RACAL is not set
-# CONFIG_NET_ISA is not set
+CONFIG_NET_VENDOR_3COM=y
+CONFIG_EL1=m
+CONFIG_EL2=m
+CONFIG_ELPLUS=m
+CONFIG_EL16=m
+CONFIG_EL3=m
+CONFIG_3C515=m
+CONFIG_BC90X=m
+CONFIG_VORTEX=m
+CONFIG_LANCE=m
+CONFIG_NET_VENDOR_SMC=y
+CONFIG_WD80x3=m
+CONFIG_ULTRA=m
+CONFIG_ULTRA32=m
+CONFIG_SMC9194=m
+CONFIG_NET_VENDOR_RACAL=y
+CONFIG_NI5010=m
+CONFIG_NI52=m
+CONFIG_NI65=m
+CONFIG_RTL8139=m
+CONFIG_NET_ISA=y
+CONFIG_AT1700=m
+CONFIG_E2100=m
+CONFIG_DEPCA=m
+CONFIG_EWRK3=m
+CONFIG_EEXPRESS=m
+CONFIG_EEXPRESS_PRO=m
+CONFIG_FMV18X=m
+CONFIG_HPLAN_PLUS=m
+CONFIG_HPLAN=m
+CONFIG_HP100=m
+CONFIG_ETH16I=m
+CONFIG_NE2000=m
+# CONFIG_SEEQ8005 is not set
+CONFIG_SK_G16=y
 CONFIG_NET_EISA=y
-# CONFIG_PCNET32 is not set
-# CONFIG_APRICOT is not set
-# CONFIG_CS89x0 is not set
-# CONFIG_DE4X5 is not set
-# CONFIG_DEC_ELCP is not set
-# CONFIG_DGRS is not set
+CONFIG_PCNET32=m
+CONFIG_AC3200=m
+CONFIG_APRICOT=m
+CONFIG_CS89x0=m
+CONFIG_DM9102=m
+CONFIG_DE4X5=m
+CONFIG_DEC_ELCP=y
+# CONFIG_DEC_ELCP_OLD is not set
+CONFIG_DGRS=m
 CONFIG_EEXPRESS_PRO100=y
-# CONFIG_NE2K_PCI is not set
-# CONFIG_TLAN is not set
-# CONFIG_VIA_RHINE is not set
-# CONFIG_NET_POCKET is not set
-# CONFIG_FDDI is not set
-# CONFIG_DLCI is not set
-# CONFIG_PPP is not set
-# CONFIG_SLIP is not set
-# CONFIG_NET_RADIO is not set
-# CONFIG_TR is not set
-# CONFIG_HOSTESS_SV11 is not set
-# CONFIG_COSA is not set
-# CONFIG_SEALEVEL_4021 is not set
-# CONFIG_RCPCI is not set
-# CONFIG_WAN_DRIVERS is not set
-# CONFIG_LAPBETHER is not set
-# CONFIG_X25_ASY is not set
+CONFIG_LNE390=m
+CONFIG_NE3210=m
+CONFIG_NE2K_PCI=m
+CONFIG_TLAN=m
+CONFIG_VIA_RHINE=m
+CONFIG_SIS900=m
+CONFIG_ES3210=m
+CONFIG_EPIC100=m
+# CONFIG_ZNET is not set
+CONFIG_NET_POCKET=y
+CONFIG_ATP=y
+CONFIG_DE600=m
+CONFIG_DE620=m
+
+#
+# Ethernet (1000 Mbit)
+#
+CONFIG_ACENIC=m
+CONFIG_HAMACHI=m
+CONFIG_YELLOWFIN=m
+CONFIG_SK98LIN=m
+CONFIG_FDDI=y
+# CONFIG_DEFXX is not set
+# CONFIG_HIPPI is not set
+
+#
+# Appletalk devices
+#
+CONFIG_LTPC=m
+CONFIG_COPS=m
+CONFIG_COPS_DAYNA=y
+CONFIG_COPS_TANGENT=y
+CONFIG_IPDDP=m
+CONFIG_IPDDP_ENCAP=y
+CONFIG_IPDDP_DECAP=y
+CONFIG_PLIP=m
+CONFIG_PPP=m
+
+#
+# CCP compressors for PPP are only built as modules.
+#
+CONFIG_SLIP=m
+CONFIG_SLIP_COMPRESSED=y
+CONFIG_SLIP_SMART=y
+CONFIG_SLIP_MODE_SLIP6=y
+CONFIG_NET_RADIO=y
+CONFIG_STRIP=m
+CONFIG_WAVELAN=m
+CONFIG_ARLAN=m
+
+#
+# Token ring devices
+#
+CONFIG_TR=y
+CONFIG_IBMTR=m
+CONFIG_IBMOL=m
+CONFIG_SKTR=m
+CONFIG_NET_FC=y
+CONFIG_IPHASE5526=m
+CONFIG_RCPCI=m
+CONFIG_SHAPER=m
+
+#
+# Wan interfaces
+#
+CONFIG_HOSTESS_SV11=m
+CONFIG_COSA=m
+CONFIG_SEALEVEL_4021=m
+# CONFIG_COMX is not set
+CONFIG_DLCI=m
+CONFIG_DLCI_COUNT=24
+CONFIG_DLCI_MAX=8
+CONFIG_SDLA=m
+CONFIG_WAN_DRIVERS=y
+CONFIG_VENDOR_SANGOMA=m
+CONFIG_WANPIPE_CARDS=4
+# CONFIG_WANPIPE_FR is not set
+CONFIG_WANPIPE_PPP=y
+CONFIG_WANPIPE_CHDLC=y
+CONFIG_SBNI=m
 
 #
 # Amateur Radio support
@@ -254,18 +489,133 @@
 
 #
 # IrDA subsystem support
+#
+CONFIG_IRDA=m
+
+#
+# IrDA protocols
+#
+CONFIG_IRLAN=m
+CONFIG_IRCOMM=m
+CONFIG_IRLPT=m
+CONFIG_IRLPT_CLIENT=m
+CONFIG_IRLPT_SERVER=m
+CONFIG_IRDA_OPTIONS=y
+
+#
+#    IrDA options
+#
+CONFIG_IRDA_CACHE_LAST_LSAP=y
+CONFIG_IRDA_FAST_RR=y
+# CONFIG_IRDA_DEBUG is not set
+CONFIG_IRDA_COMPRESSION=y
+
+#
+#    IrDA compressors
+#
+CONFIG_IRDA_DEFLATE=m
+
+#
+# Infrared-port device drivers
+#
+
+#
+# SIR device drivers
 #
-# CONFIG_IRDA is not set
+CONFIG_IRTTY_SIR=m
+CONFIG_IRPORT_SIR=m
 
 #
+# FIR device drivers
+#
+CONFIG_NSC_FIR=m
+CONFIG_WINBOND_FIR=m
+CONFIG_SHARP_FIR=m
+CONFIG_TOSHIBA_FIR=m
+CONFIG_SMC_IRCC_FIR=m
+
+#
+# Dongle support
+#
+CONFIG_DONGLE=y
+CONFIG_ESI_DONGLE=m
+CONFIG_ACTISYS_DONGLE=m
+CONFIG_TEKRAM_DONGLE=m
+CONFIG_GIRBIL_DONGLE=m
+CONFIG_LITELINK_DONGLE=m
+
+#
 # ISDN subsystem
 #
-# CONFIG_ISDN is not set
+CONFIG_ISDN=m
+CONFIG_ISDN_PPP=y
+CONFIG_ISDN_PPP_VJ=y
+CONFIG_ISDN_MPP=y
+CONFIG_ISDN_AUDIO=y
+# CONFIG_ISDN_TTY_FAX is not set
+# CONFIG_ISDN_DIVERSION is not set
+CONFIG_ISDN_DRV_ICN=m
+CONFIG_ISDN_DRV_LOOP=m
+CONFIG_ISDN_DRV_PCBIT=m
+CONFIG_ISDN_DRV_HISAX=m
+CONFIG_HISAX_EURO=y
+CONFIG_DE_AOC=y
+# CONFIG_HISAX_NO_SENDCOMPLETE is not set
+# CONFIG_HISAX_NO_LLC is not set
+CONFIG_HISAX_1TR6=y
+CONFIG_HISAX_16_0=y
+CONFIG_HISAX_16_3=y
+CONFIG_HISAX_TELESPCI=y
+CONFIG_HISAX_S0BOX=y
+CONFIG_HISAX_AVM_A1=y
+CONFIG_HISAX_FRITZPCI=y
+CONFIG_HISAX_AVM_A1_PCMCIA=y
+CONFIG_HISAX_ELSA=y
+CONFIG_HISAX_IX1MICROR2=y
+CONFIG_HISAX_DIEHLDIVA=y
+CONFIG_HISAX_ASUSCOM=y
+CONFIG_HISAX_TELEINT=y
+CONFIG_HISAX_HFCS=y
+CONFIG_HISAX_SEDLBAUER=y
+CONFIG_HISAX_SPORTSTER=y
+CONFIG_HISAX_MIC=y
+CONFIG_HISAX_NETJET=y
+CONFIG_HISAX_NICCY=y
+CONFIG_HISAX_ISURF=y
+CONFIG_HISAX_HSTSAPHIR=y
+CONFIG_HISAX_BKM_A4T=y
+CONFIG_HISAX_SCT_QUADRO=y
+CONFIG_HISAX_GAZEL=y
+CONFIG_HISAX_HFC_PCI=y
+CONFIG_HISAX_W6692=y
+# CONFIG_ISDN_DRV_SC is not set
+# CONFIG_ISDN_DRV_ACT2000 is not set
+# CONFIG_ISDN_DRV_EICON is not set
+CONFIG_ISDN_DRV_AVMB1=m
+CONFIG_ISDN_DRV_AVMB1_B1ISA=y
+CONFIG_ISDN_DRV_AVMB1_B1PCI=y
+CONFIG_ISDN_DRV_AVMB1_T1ISA=y
+# CONFIG_ISDN_DRV_AVMB1_B1PCMCIA is not set
+CONFIG_ISDN_DRV_AVMB1_T1PCI=y
+CONFIG_ISDN_DRV_AVMB1_VERBOSE_REASON=y
 
 #
 # Old CD-ROM drivers (not SCSI, not IDE)
 #
-# CONFIG_CD_NO_IDESCSI is not set
+CONFIG_CD_NO_IDESCSI=y
+CONFIG_AZTCD=m
+CONFIG_GSCD=m
+CONFIG_SBPCD=m
+CONFIG_MCD=m
+CONFIG_MCD_IRQ=11
+CONFIG_MCD_BASE=300
+CONFIG_MCDX=m
+CONFIG_OPTCD=m
+CONFIG_CM206=m
+CONFIG_SJCD=m
+CONFIG_ISP16_CDI=m
+CONFIG_CDU31A=m
+CONFIG_CDU535=m
 
 #
 # Character devices
@@ -273,98 +623,402 @@
 CONFIG_VT=y
 CONFIG_VT_CONSOLE=y
 CONFIG_SERIAL=y
-# CONFIG_SERIAL_CONSOLE is not set
-# CONFIG_SERIAL_EXTENDED is not set
-# CONFIG_SERIAL_NONSTANDARD is not set
+CONFIG_SERIAL_CONSOLE=y
+CONFIG_SERIAL_EXTENDED=y
+CONFIG_SERIAL_MANY_PORTS=y
+CONFIG_SERIAL_SHARE_IRQ=y
+# CONFIG_SERIAL_DETECT_IRQ is not set
+CONFIG_SERIAL_MULTIPORT=y
+# CONFIG_HUB6 is not set
+CONFIG_SERIAL_NONSTANDARD=y
+CONFIG_COMPUTONE=m
+CONFIG_ROCKETPORT=m
+CONFIG_CYCLADES=m
+# CONFIG_CYZ_INTR is not set
+CONFIG_DIGIEPCA=m
+CONFIG_ESPSERIAL=m
+CONFIG_MOXA_INTELLIO=m
+CONFIG_MOXA_SMARTIO=m
+CONFIG_ISI=m
+CONFIG_RISCOM8=m
+CONFIG_SPECIALIX=m
+CONFIG_SPECIALIX_RTSCTS=y
+CONFIG_SX=m
+CONFIG_STALDRV=y
+CONFIG_STALLION=m
+CONFIG_ISTALLION=m
+CONFIG_SYNCLINK=m
+CONFIG_N_HDLC=m
 CONFIG_UNIX98_PTYS=y
 CONFIG_UNIX98_PTY_COUNT=256
+CONFIG_PRINTER=m
+CONFIG_PRINTER_READBACK=y
 CONFIG_MOUSE=y
 
 #
 # Mice
 #
-# CONFIG_ATIXL_BUSMOUSE is not set
-# CONFIG_BUSMOUSE is not set
-# CONFIG_MS_BUSMOUSE is not set
+CONFIG_ATIXL_BUSMOUSE=m
+CONFIG_BUSMOUSE=m
+CONFIG_MS_BUSMOUSE=m
 CONFIG_PSMOUSE=y
-CONFIG_82C710_MOUSE=y
-# CONFIG_PC110_PAD is not set
+CONFIG_82C710_MOUSE=m
+CONFIG_PC110_PAD=m
+
+#
+# Joysticks
+#
+CONFIG_JOYSTICK=m
+CONFIG_JOY_ANALOG=m
+CONFIG_JOY_ASSASSIN=m
+CONFIG_JOY_GRAVIS=m
+CONFIG_JOY_LOGITECH=m
+CONFIG_JOY_SIDEWINDER=m
+CONFIG_JOY_THRUSTMASTER=m
+CONFIG_JOY_CREATIVE=m
+CONFIG_JOY_LIGHTNING=m
+CONFIG_JOY_PCI=m
+CONFIG_JOY_MAGELLAN=m
+CONFIG_JOY_SPACEORB=m
+CONFIG_JOY_SPACEBALL=m
+CONFIG_JOY_WARRIOR=m
+CONFIG_JOY_CONSOLE=m
+CONFIG_JOY_DB9=m
+CONFIG_JOY_TURBOGRAFX=m
 # CONFIG_QIC02_TAPE is not set
-# CONFIG_WATCHDOG is not set
-# CONFIG_NVRAM is not set
-# CONFIG_RTC is not set
+CONFIG_IPMI_KCS=m
+CONFIG_WATCHDOG=y
 
 #
-# Video For Linux
+# Watchdog Cards
 #
-# CONFIG_VIDEO_DEV is not set
+CONFIG_IPMI_KCS=m
+# CONFIG_WATCHDOG_NOWAYOUT is not set
+CONFIG_WDT=m
+CONFIG_WDT_501=y
+CONFIG_WDT_501_FAN=y
+CONFIG_SOFT_WATCHDOG=m
+CONFIG_PCWATCHDOG=m
+CONFIG_ACQUIRE_WDT=m
+# CONFIG_MIXCOMWD is not set
+CONFIG_NVRAM=m
+CONFIG_RTC=y
+
+#
+# I2C support
+#
+CONFIG_I2C=m
+CONFIG_I2C_ALGOBIT=m
+CONFIG_I2C_PHILIPSPAR=m
+CONFIG_I2C_ELV=m
+CONFIG_I2C_VELLEMAN=m
+CONFIG_I2C_ALGOPCF=m
+CONFIG_I2C_ELEKTOR=m
+CONFIG_I2C_MAINBOARD=m
+CONFIG_I2C_ALI15X3=m
+CONFIG_I2C_HYDRA=m
+CONFIG_I2C_PIIX4=m
+CONFIG_I2C_VIA=m
+CONFIG_I2C_ISA=m
+CONFIG_I2C_CHARDEV=m
+
+#
+# Hardware sensors support
+#
+CONFIG_SENSORS=m
+CONFIG_SENSORS_ADM1021=m
+CONFIG_SENSORS_ADM9240=m
+CONFIG_SENSORS_GL518SM=m
+CONFIG_SENSORS_LM75=m
+CONFIG_SENSORS_LM78=m
+CONFIG_SENSORS_LM80=m
+CONFIG_SENSORS_SIS5595=m
+CONFIG_SENSORS_W83781D=m
+CONFIG_SENSORS_OTHER=m
+CONFIG_SENSORS_EEPROM=m
+CONFIG_SENSORS_LTC1710=m
+
+#
+# AGP support
+#
+CONFIG_AGP=m
+CONFIG_AGP_INTEL=y
+CONFIG_AGP_I810=y
+CONFIG_AGP_VIA=y
+CONFIG_AGP_AMD=y
+CONFIG_AGP_SIS=y
+CONFIG_AGP_ALI=y
 
 #
-# Joystick support
+# Video For Linux
 #
-# CONFIG_JOYSTICK is not set
-# CONFIG_DTLK is not set
+CONFIG_VIDEO_DEV=m
+CONFIG_RADIO_RTRACK=m
+CONFIG_RADIO_RTRACK2=m
+CONFIG_RADIO_AZTECH=m
+CONFIG_RADIO_CADET=m
+CONFIG_RADIO_MIROPCM20=m
+CONFIG_RADIO_GEMTEK=m
+CONFIG_RADIO_TRUST=m
+CONFIG_VIDEO_BT848=m
+CONFIG_VIDEO_BWQCAM=m
+CONFIG_VIDEO_CQCAM=m
+CONFIG_VIDEO_PMS=m
+CONFIG_VIDEO_SAA5249=m
+CONFIG_RADIO_SF16FMI=m
+CONFIG_RADIO_TYPHOON=m
+CONFIG_RADIO_TYPHOON_PROC_FS=y
+CONFIG_RADIO_ZOLTRIX=m
+CONFIG_VIDEO_ZORAN=m
+CONFIG_VIDEO_BUZ=m
+CONFIG_DTLK=m
 
 #
 # Ftape, the floppy tape device driver
 #
-# CONFIG_FTAPE is not set
+CONFIG_FTAPE=m
+CONFIG_ZFTAPE=m
+CONFIG_ZFT_DFLT_BLK_SZ=10240
 
 #
+# The compressor will be built as a module only!
+#
+CONFIG_ZFT_COMPRESSOR=m
+CONFIG_FT_NR_BUFFERS=3
+CONFIG_FT_PROC_FS=y
+CONFIG_FT_NORMAL_DEBUG=y
+# CONFIG_FT_FULL_DEBUG is not set
+# CONFIG_FT_NO_TRACE is not set
+# CONFIG_FT_NO_TRACE_AT_ALL is not set
+
+#
+# Hardware configuration
+#
+CONFIG_FT_STD_FDC=y
+# CONFIG_FT_MACH2 is not set
+# CONFIG_FT_PROBE_FC10 is not set
+# CONFIG_FT_ALT_FDC is not set
+CONFIG_FT_FDC_THR=8
+CONFIG_FT_FDC_MAX_RATE=2000
+
+#
+# ONLY for DEC Alpha architectures
+#
+CONFIG_FT_ALPHA_CLOCK=0
+
+#
 # Filesystems
 #
-# CONFIG_QUOTA is not set
-CONFIG_AUTOFS_FS=y
-# CONFIG_AFFS_FS is not set
-# CONFIG_HFS_FS is not set
-# CONFIG_FAT_FS is not set
-# CONFIG_MSDOS_FS is not set
-# CONFIG_UMSDOS_FS is not set
-# CONFIG_VFAT_FS is not set
+CONFIG_QUOTA=y
+CONFIG_AUTOFS_FS=m
+CONFIG_ADFS_FS=m
+CONFIG_AFFS_FS=m
+CONFIG_HFS_FS=m
+CONFIG_FAT_FS=y
+CONFIG_MSDOS_FS=m
+CONFIG_UMSDOS_FS=m
+CONFIG_VFAT_FS=y
 CONFIG_ISO9660_FS=y
-# CONFIG_JOLIET is not set
-# CONFIG_MINIX_FS is not set
-# CONFIG_NTFS_FS is not set
-# CONFIG_HPFS_FS is not set
+CONFIG_JOLIET=y
+CONFIG_MINIX_FS=m
+CONFIG_NTFS_FS=m
+CONFIG_NTFS_RW=y
+CONFIG_HPFS_FS=m
 CONFIG_PROC_FS=y
 CONFIG_DEVPTS_FS=y
-# CONFIG_ROMFS_FS is not set
+CONFIG_QNX4FS_FS=m
+# CONFIG_QNX4FS_RW is not set
+CONFIG_ROMFS_FS=m
 CONFIG_EXT2_FS=y
-# CONFIG_SYSV_FS is not set
-# CONFIG_UFS_FS is not set
+CONFIG_EXT3_FS=y 
+CONFIG_EXT3_FS_JFS_CHECK=y
+CONFIG_SYSV_FS=m
+CONFIG_UFS_FS=m
+# CONFIG_UFS_FS_WRITE is not set
+CONFIG_EFS_FS=m
+CONFIG_SGI_PARTITION=y
 
 #
 # Network File Systems
 #
-# CONFIG_CODA_FS is not set
-CONFIG_NFS_FS=y
-# CONFIG_NFSD_SUN is not set
-CONFIG_SUNRPC=y
-CONFIG_LOCKD=y
-# CONFIG_SMB_FS is not set
-# CONFIG_NCP_FS is not set
+CONFIG_CODA_FS=m
+CONFIG_NFS_FS=m
+CONFIG_NFSD=m
+CONFIG_NFSD_SUN=y
+CONFIG_SUNRPC=m
+CONFIG_LOCKD=m
+CONFIG_NFSD_V3=y 
+CONFIG_NFS_V3=y
+CONFIG_SMB_FS=m
+CONFIG_NCP_FS=m
+CONFIG_NCPFS_PACKET_SIGNING=y
+CONFIG_NCPFS_IOCTL_LOCKING=y
+CONFIG_NCPFS_STRONG=y
+CONFIG_NCPFS_NFS_NS=y
+CONFIG_NCPFS_OS2_NS=y
+CONFIG_NCPFS_SMALLDOS=y
+CONFIG_NCPFS_MOUNT_SUBDIR=y
+CONFIG_NCPFS_NLS=y
+CONFIG_NCPFS_EXTRAS=y
 
 #
 # Partition Types
 #
-# CONFIG_BSD_DISKLABEL is not set
-# CONFIG_MAC_PARTITION is not set
-# CONFIG_SMD_DISKLABEL is not set
-# CONFIG_SOLARIS_X86_PARTITION is not set
-# CONFIG_NLS is not set
+CONFIG_BSD_DISKLABEL=y
+CONFIG_MAC_PARTITION=y
+CONFIG_SMD_DISKLABEL=y
+CONFIG_SOLARIS_X86_PARTITION=y
+CONFIG_UNIXWARE_DISKLABEL=y
+CONFIG_NLS=y
+
+#
+# Native Language Support
+#
+CONFIG_NLS_CODEPAGE_437=m
+CONFIG_NLS_CODEPAGE_737=m
+CONFIG_NLS_CODEPAGE_775=m
+CONFIG_NLS_CODEPAGE_850=m
+CONFIG_NLS_CODEPAGE_852=m
+CONFIG_NLS_CODEPAGE_855=m
+CONFIG_NLS_CODEPAGE_857=m
+CONFIG_NLS_CODEPAGE_860=m
+CONFIG_NLS_CODEPAGE_861=m
+CONFIG_NLS_CODEPAGE_862=m
+CONFIG_NLS_CODEPAGE_863=m
+CONFIG_NLS_CODEPAGE_864=m
+CONFIG_NLS_CODEPAGE_865=m
+CONFIG_NLS_CODEPAGE_866=m
+CONFIG_NLS_CODEPAGE_869=m
+CONFIG_NLS_CODEPAGE_874=m
+CONFIG_NLS_ISO8859_1=m
+CONFIG_NLS_ISO8859_2=m
+CONFIG_NLS_ISO8859_3=m
+CONFIG_NLS_ISO8859_4=m
+CONFIG_NLS_ISO8859_5=m
+CONFIG_NLS_ISO8859_6=m
+CONFIG_NLS_ISO8859_7=m
+CONFIG_NLS_ISO8859_8=m
+CONFIG_NLS_ISO8859_9=m
+CONFIG_NLS_ISO8859_14=m
+CONFIG_NLS_ISO8859_15=m
+CONFIG_NLS_KOI8_R=m
 
 #
 # Console drivers
 #
 CONFIG_VGA_CONSOLE=y
-# CONFIG_VIDEO_SELECT is not set
+CONFIG_VIDEO_SELECT=y
+CONFIG_MDA_CONSOLE=m
+# CONFIG_FB is not set
+CONFIG_DUMMY_CONSOLE=y
+CONFIG_FB_PM2=m
+CONFIG_FB_VESA=y
+# CONFIG_FB_VGA16 is not set
+CONFIG_VIDEO_SELECT=y
+CONFIG_FB_MATROX=m
+CONFIG_FB_MATROX_MILLENIUM=y
+CONFIG_FB_MATROX_MYSTIQUE=y
+CONFIG_FB_MATROX_G100=y
+CONFIG_FB_MATROX_MULTIHEAD=y
+CONFIG_FB_ATY=m
+# CONFIG_FB_VIRTUAL is not set
+# CONFIG_FBCON_ADVANCED is not set
+CONFIG_FBCON_CFB8=y
+CONFIG_FBCON_CFB16=y
+CONFIG_FBCON_CFB24=y
+CONFIG_FBCON_CFB32=y
+# CONFIG_FBCON_FONTWIDTH8_ONLY is not set
+# CONFIG_FBCON_FONTS is not set
+CONFIG_FONT_8x8=y
+CONFIG_FONT_8x16=y
 
 #
 # Sound
+#
+CONFIG_SOUND=m
+CONFIG_SOUND_CMPCI=m
+CONFIG_SOUND_CMPCI_FM=y
+CONFIG_SOUND_CMPCI_MIDI=y
+CONFIG_SOUND_ES1370=m
+CONFIG_SOUND_ES1371=m
+CONFIG_SOUND_MAESTRO=m
+CONFIG_SOUND_EMU10K1=m
+CONFIG_SOUND_ESSSOLO1=m
+CONFIG_SOUND_SONICVIBES=m
+CONFIG_SOUND_MSNDCLAS=m
+# CONFIG_MSNDCLAS_HAVE_BOOT is not set
+CONFIG_MSNDCLAS_INIT_FILE="/etc/sound/msndinit.bin"
+CONFIG_MSNDCLAS_PERM_FILE="/etc/sound/msndperm.bin"
+CONFIG_SOUND_MSNDPIN=m
+# CONFIG_MSNDPIN_HAVE_BOOT is not set
+CONFIG_MSNDPIN_INIT_FILE="/etc/sound/pndspini.bin"
+CONFIG_MSNDPIN_PERM_FILE="/etc/sound/pndsperm.bin"
+CONFIG_SOUND_OSS=m
+CONFIG_SOUND_PAS=m
+CONFIG_SOUND_SB=m
+CONFIG_SOUND_GUS=m
+CONFIG_GUS16=y
+CONFIG_GUSMAX=y
+CONFIG_SOUND_MPU401=m
+CONFIG_SOUND_PSS=m
+# CONFIG_PSS_MIXER is not set
+CONFIG_SOUND_MSS=m
+CONFIG_SOUND_SSCAPE=m
+CONFIG_SOUND_TRIX=m
+CONFIG_SOUND_VIA82CXXX=m
+CONFIG_SOUND_MAD16=m
+CONFIG_MAD16_OLDCARD=y
+CONFIG_SOUND_WAVEFRONT=m
+CONFIG_SOUND_CS4232=m
+CONFIG_SOUND_OPL3SA2=m
+CONFIG_SOUND_MAUI=m
+CONFIG_SOUND_SGALAXY=m
+CONFIG_SOUND_AD1816=m
+CONFIG_SOUND_OPL3SA1=m
+CONFIG_SOUND_SOFTOSS=m
+CONFIG_SOUND_YM3812=m
+CONFIG_SOUND_VMIDI=m
+CONFIG_SOUND_UART6850=m
+CONFIG_SOUND_NM256=m
+
+#
+# Additional low level sound drivers
+#
+CONFIG_LOWLEVEL_SOUND=y
+CONFIG_ACI_MIXER=m
+CONFIG_VIDEO_MSP3400=m
+CONFIG_AWE32_SYNTH=m
+CONFIG_AEDSP16=m
+CONFIG_AEDSP16_BASE=220
+CONFIG_MPU_BASE=330
+
+#
+# SC-6600 Audio Cards have no jumper switches at all
+#
+CONFIG_SC6600=y
+
+#
+# SC-6600 specific configuration
+#
+CONFIG_SC6600_JOY=y
+CONFIG_SC6600_CDROM=4
+CONFIG_SC6600_CDROMBASE=0
+CONFIG_AEDSP16_SBPRO=y
+
+#
+# Audio Excel DSP 16 [Sound Blaster Pro]
+#
+CONFIG_AEDSP16_BASE=220
+CONFIG_AEDSP16_SB_IRQ=5
+CONFIG_AEDSP16_SB_DMA=0
+CONFIG_AEDSP16_MPU401=y
+
+#
+# Audio Excel DSP 16 [MPU-401]
 #
-# CONFIG_SOUND is not set
+CONFIG_AEDSP16_MPU_IRQ=5
 
 #
 # Kernel hacking
 #
-# CONFIG_MAGIC_SYSRQ is not set
+CONFIG_MAGIC_SYSRQ=y
Index: oldkernel/linux/arch/i386/kdb/modules/kdbm_jfs.c
diff -u /dev/null linux/arch/i386/kdb/modules/kdbm_jfs.c:1.1
--- /dev/null	Mon Jul 31 21:15:04 2000
+++ linux/arch/i386/kdb/modules/kdbm_jfs.c	Fri Jul  7 16:34:57 2000
@@ -0,0 +1,308 @@
+#include <linux/kdb.h>
+#include <linux/module.h>
+#include <linux/sched.h>
+#include <linux/fs.h>
+#include <linux/jfs.h>
+
+#define FETCH(dest, source) \
+do {							\
+	int i;						\
+	unsigned char *p = (unsigned char *)(dest);	\
+							\
+	for (i=0; i<sizeof(*(dest)); i++)		\
+		*p++ = kdbgetword((source)+i, 1);	\
+} while (0)
+
+const char *bh_listnames[] = {
+	"BUF_CLEAN",
+	"BUF_LOCKED",
+	"BUF_DIRTY",
+	"BUF_JOURNAL"
+};
+
+const char *jfs_listnames[] = {
+	"BJ_None",
+	"BJ_Data",
+	"BJ_Metadata",
+	"BJ_Forget",
+	"BJ_IO",
+	"BJ_Shadow",
+	"BJ_LogCtl",
+	"BJ_Reserved"
+};
+
+const char *statenames[] = {
+	"T_RUNNING",
+	"T_LOCKED",
+	"T_RUNDOWN",
+	"T_FLUSH",
+	"T_COMMIT",
+	"T_FINISH"
+};
+
+const char *bh_statenames = "UDLRPTJ";
+int bh_states[] = {0,1,2,3,6,7,8,-1};
+
+const char *bh_listname(int list)
+{
+	if (list >= NR_LIST)
+		return "*INVALID*";
+	return bh_listnames[list];
+}
+
+const char *jfs_listname(int list)
+{
+	if (list >= BJ_Types)
+		return "*INVALID*";
+	return jfs_listnames[list];
+}
+
+const char *transaction_state(int state)
+{
+	static char statenum[16];
+	if (state > T_FINISHED) {
+		sprintf(statenum, "[%d]", state);
+		return statenum;
+	}
+	return statenames[state];
+}
+
+const char *bh_state(int state)
+{
+	char *result="       ";
+	int i = 0;
+	do {
+		if (state & (1<<bh_states[i]))
+			result[i] = bh_statenames[i];
+		else
+			result[i] = '.';
+		i++;
+	} while (bh_states[i] >= 0);
+	return result;
+}
+
+
+int
+kdbm_bh(int argc, const char **argv, const char **envp, struct pt_regs *regs)
+{
+	struct buffer_head bh;
+	unsigned long addr;
+	long	offset=0;
+	int nextarg;
+	int diag;
+
+	if (argc != 1)
+		return KDB_ARGCOUNT;
+
+	nextarg = 1;
+	diag = kdbgetaddrarg(argc, argv, &nextarg, &addr, &offset, NULL, regs);
+	if (diag)
+		return diag;
+
+	addr += offset;
+
+	FETCH(&bh, addr);
+
+	kdb_printf("struct buffer_head 0x%lx for %d bytes\n", addr, sizeof(bh));
+	kdb_printf("  dev   = %-11s          blk   = 0x%08lx   size  = 0x%04lx\n",
+	       kdevname(bh.b_dev), bh.b_blocknr, bh.b_size);
+	kdb_printf("  data  = %p\n", bh.b_data);
+	kdb_printf("  list  = %-3d (%-11s)    state = %7s       count = %-5d\n",
+	       bh.b_list, bh_listname(bh.b_list),
+	       bh_state(bh.b_state),
+	       bh.b_count);
+	kdb_printf("  jlist = %-3d (%-11s)    transaction      = %p\n",
+	       bh.b_jlist, jfs_listname(bh.b_jlist), bh.b_transaction);
+	kdb_printf("  frozen data    = %p    cp_transaction   = %p\n",
+	       bh.b_frozen_data, bh.b_cp_transaction);
+	kdb_printf("  committed data = %p    next_transaction = %p\n",
+	       bh.b_committed_data, bh.b_next_transaction);
+	return 0;
+}
+
+int
+kdbm_bhi(int argc, const char **argv, const char **envp, struct pt_regs *regs)
+{
+	show_buffers();
+	return 0;
+}
+
+
+static void show_journal(journal_t *journal, unsigned long where)
+{
+	kdb_printf("journal at %08lx for %d bytes:\n", where, sizeof(*journal));
+
+	kdb_printf(" State: ");
+	if (journal->j_flags & JFS_UNMOUNT)
+		kdb_printf("Unmount ");
+	if (journal->j_flags & JFS_SYNC)
+		kdb_printf("Sync ");
+	if (journal->j_locked)
+		kdb_printf("Locked ");
+	kdb_printf("\n");
+
+	kdb_printf(" Log head: %ld  Tail: %ld  Free: %ld     "
+	       "Valid: %ld to %ld (+%d)\n",
+	       journal->j_head, journal->j_tail, journal->j_free,
+	       journal->j_first, journal->j_last, journal->j_maxlen);
+
+	kdb_printf(" Transactions IDs:\n");
+	kdb_printf("  Oldest:     %-8ld          Next:       %-8ld\n",
+		   journal->j_tail_sequence,
+		   journal->j_transaction_sequence);
+	kdb_printf("    Committed:  %-8ld          Req commit: %-8ld\n",
+		   journal->j_commit_sequence,
+		   journal->j_commit_request);
+	kdb_printf("\n");
+}
+
+static void show_transaction_brief(transaction_t *transaction,
+				   unsigned long where,
+				   const char *kind)
+{
+	kdb_printf("%s%s at %08lx for %d bytes:\n",
+	       kind ? kind : "", kind ? " transaction" : "Transaction",
+	       where, sizeof(*transaction));
+
+	kdb_printf(" ID: %-5ld   State: %9s   "
+	       "Buffers: %-5d Log at: %-5ld\n",
+	       transaction->t_tid, transaction_state(transaction->t_state),
+	       transaction->t_nr_buffers, transaction->t_log_start);
+	kdb_printf(" Updates: %-5d   Credits: %-5d\n",
+	       transaction->t_updates, transaction->t_outstanding_credits);
+}
+
+static void show_transaction_list(unsigned long where, const char *kind,
+				  unsigned long offset)
+{
+	unsigned long bp, first, count=0;
+
+	if (!where)
+		return;
+
+	first = where;
+	
+	do {
+		FETCH(&bp, where+offset);
+		where = bp;
+		count++;
+	} while (bp != first);
+
+	kdb_printf (" %9s list: %5ld buffers\n", kind, count);
+}
+
+#define SHOW_BUFS(bh, kind, field) \
+do {								    \
+	unsigned long offset, bp;				    \
+	bp = (unsigned long) (bh);				    \
+	offset = ((char *) &((struct buffer_head *)(bp))->field) -  \
+		 ((char *) (bp));				    \
+	show_transaction_list((bp), kind, offset);		    \
+} while (0)
+
+static void show_transaction_full(transaction_t *transaction,
+				  unsigned long where,
+				  const char *kind)
+{
+	show_transaction_brief(transaction, where, kind);
+
+	SHOW_BUFS(transaction->t_datalist,        "Data",      b_tnext);
+	SHOW_BUFS(transaction->t_buffers,         "Metadata",  b_tnext);
+	SHOW_BUFS(transaction->t_forget,          "Forget",    b_tnext);
+	SHOW_BUFS(transaction->t_checkpoint_list, "Checkpoint",b_cpnext);
+	SHOW_BUFS(transaction->t_iobuf_list,      "Iobuf",     b_tnext);
+	SHOW_BUFS(transaction->t_shadow_list,     "Shadow",    b_tnext);
+	SHOW_BUFS(transaction->t_log_list,        "Log",       b_tnext);
+}
+
+int
+kdbm_jfs(int argc, const char **argv, const char **envp, struct pt_regs *regs)
+{
+	journal_t journal;
+	transaction_t transaction;
+	unsigned long jaddr, taddr;
+
+	long	offset=0;
+	int nextarg;
+	int diag;
+
+	if (argc != 1)
+		return KDB_ARGCOUNT;
+
+	nextarg = 1;
+	diag = kdbgetaddrarg(argc, argv, &nextarg, &jaddr, &offset, NULL,regs);
+	if (diag)
+		return diag;
+
+	jaddr += offset;
+
+	FETCH(&journal, jaddr);
+	show_journal(&journal, jaddr);
+
+	taddr = (unsigned long) journal.j_running_transaction;
+	if (taddr) {
+		FETCH(&transaction, taddr);
+		show_transaction_brief(&transaction, taddr, "Running");
+	}
+
+	taddr = (unsigned long) journal.j_committing_transaction;
+	if (taddr) {
+		FETCH(&transaction, taddr);
+		show_transaction_brief(&transaction, taddr, "Committing");
+	}
+
+	taddr = (unsigned long) journal.j_checkpoint_transactions;
+	if (taddr) do {
+		FETCH(&transaction, taddr);
+		show_transaction_brief(&transaction, taddr, "Checkpointed");
+		taddr = (unsigned long) transaction.t_cpnext;
+	} while (taddr != (unsigned long) journal.j_checkpoint_transactions);
+
+	return 0;
+}
+
+int
+kdbm_tr(int argc, const char **argv, const char **envp, struct pt_regs *regs)
+{
+	transaction_t transaction;
+	unsigned long taddr;
+
+	long	offset=0;
+	int nextarg;
+	int diag;
+
+	if (argc != 1)
+		return KDB_ARGCOUNT;
+
+	nextarg = 1;
+	diag = kdbgetaddrarg(argc, argv, &nextarg, &taddr, &offset, NULL,regs);
+	if (diag)
+		return diag;
+
+	taddr += offset;
+
+	FETCH(&transaction, taddr);
+	show_transaction_full(&transaction, taddr, NULL);
+
+	return 0;
+}
+
+int
+init_module(void)
+{
+	kdb_register("bh",  kdbm_bh,  "<vaddr>", "Display buffer_head", 0);
+	kdb_register("bhi", kdbm_bhi, "", "Summarise buffer_head info", 0);
+	kdb_register("jfs", kdbm_jfs, "<vaddr>", "Display journal_t", 0);
+	kdb_register("tr",  kdbm_tr,  "<vaddr>", "Display transaction_t", 0);
+
+	return 0;
+}
+
+void
+cleanup_module(void)
+{
+	kdb_unregister("bh");
+	kdb_unregister("bhi");
+	kdb_unregister("jfs");
+	kdb_unregister("tr");
+}
Index: oldkernel/linux/arch/i386/kernel/bios32.c
diff -u linux/arch/i386/kernel/bios32.c:1.2 linux/arch/i386/kernel/bios32.c:1.3
--- linux/arch/i386/kernel/bios32.c:1.2	Thu Jun  1 14:11:18 2000
+++ linux/arch/i386/kernel/bios32.c	Fri Jul  7 15:36:41 2000
@@ -1,7 +1,7 @@
 /*
  * bios32.c - Low-Level PCI Access
  *
- * $Id: bios32.c,v 1.1.1.1 2000/05/31 19:33:53 ccr Exp $
+ * $Id: bios32.c,v 1.48 1998/09/26 08:06:55 mj Exp $
  *
  * Copyright 1993, 1994 Drew Eckhardt
  *      Visionary Computing
Index: oldkernel/linux/arch/i386/kernel/entry.S
diff -u linux/arch/i386/kernel/entry.S:1.2 linux/arch/i386/kernel/entry.S:1.3
--- linux/arch/i386/kernel/entry.S:1.2	Thu Jun  1 15:03:08 2000
+++ linux/arch/i386/kernel/entry.S	Fri Jul  7 15:36:41 2000
@@ -562,21 +562,13 @@
 	.long SYMBOL_NAME(sys_ni_syscall)		/* streams1 */
 	.long SYMBOL_NAME(sys_ni_syscall)		/* streams2 */
 	.long SYMBOL_NAME(sys_vfork)            /* 190 */
-	.long SYMBOL_NAME(sys_ni_syscall)
-	.long SYMBOL_NAME(sys_mmap2)
-	.long SYMBOL_NAME(sys_truncate64)
-	.long SYMBOL_NAME(sys_ftruncate64)
-	.long SYMBOL_NAME(sys_stat64)		/* 195 */
-	.long SYMBOL_NAME(sys_lstat64)
-	.long SYMBOL_NAME(sys_fstat64)
 
-
 	/*
 	 * NOTE!! This doesn't have to be exact - we just have
 	 * to make sure we have _enough_ of the "sys_ni_syscall"
 	 * entries. Don't panic if you notice that this hasn't
 	 * been shrunk every time we add a new system call.
 	 */
-	.rept NR_syscalls-197
+	.rept NR_syscalls-190
 		.long SYMBOL_NAME(sys_ni_syscall)
 	.endr
Index: oldkernel/linux/arch/i386/kernel/i386_ksyms.c
diff -u linux/arch/i386/kernel/i386_ksyms.c:1.2 linux/arch/i386/kernel/i386_ksyms.c:1.3
--- linux/arch/i386/kernel/i386_ksyms.c:1.2	Thu Jun  1 15:05:19 2000
+++ linux/arch/i386/kernel/i386_ksyms.c	Fri Jul  7 15:36:41 2000
@@ -119,13 +119,3 @@
 #ifdef CONFIG_VT
 EXPORT_SYMBOL(screen_info);
 #endif
-
-#ifdef CONFIG_X86_CPU_OPTIMIZATIONS
-EXPORT_SYMBOL(best_memcpy);
-EXPORT_SYMBOL(best_memset);
-EXPORT_SYMBOL(best_copy_to_user);
-EXPORT_SYMBOL(best_copy_from_user);
-EXPORT_SYMBOL(__best_copy_to_user);
-EXPORT_SYMBOL(__best_copy_from_user);
-#endif
-
Index: oldkernel/linux/arch/i386/kernel/mtrr.c
diff -u linux/arch/i386/kernel/mtrr.c:1.1.1.1 linux/arch/i386/kernel/mtrr.c:1.2
--- linux/arch/i386/kernel/mtrr.c:1.1.1.1	Wed May 31 12:33:53 2000
+++ linux/arch/i386/kernel/mtrr.c	Fri Jul  7 15:36:41 2000
@@ -139,41 +139,41 @@
 	       Changed locking to spin with reschedule.
 	       Made use of new <smp_call_function>.
   v1.28
-    19990201   Zoltan Boszormenyi <zboszor@mol.hu>
+    19990201   Zoltán Böszörményi <zboszor@mail.externet.hu>
 	       Extended the driver to be able to use Cyrix style ARRs.
     19990204   Richard Gooch <rgooch@atnf.csiro.au>
 	       Restructured Cyrix support.
   v1.29
-    19990204   Zoltan Boszormenyi <zboszor@mol.hu>
+    19990204   Zoltán Böszörményi <zboszor@mail.externet.hu>
 	       Refined ARR support: enable MAPEN in set_mtrr_prepare()
 	       and disable MAPEN in set_mtrr_done().
     19990205   Richard Gooch <rgooch@atnf.csiro.au>
 	       Minor cleanups.
   v1.30
-    19990208   Zoltan Boszormenyi <zboszor@mol.hu>
+    19990208   Zoltán Böszörményi <zboszor@mail.externet.hu>
                Protect plain 6x86s (and other processors without the
                Page Global Enable feature) against accessing CR4 in
                set_mtrr_prepare() and set_mtrr_done().
     19990210   Richard Gooch <rgooch@atnf.csiro.au>
 	       Turned <set_mtrr_up> and <get_mtrr> into function pointers.
   v1.31
-    19990212   Zoltan Boszormenyi <zboszor@mol.hu>
+    19990212   Zoltán Böszörményi <zboszor@mail.externet.hu>
                Major rewrite of cyrix_arr_init(): do not touch ARRs,
                leave them as the BIOS have set them up.
                Enable usage of all 8 ARRs.
                Avoid multiplications by 3 everywhere and other
                code clean ups/speed ups.
-    19990213   Zoltan Boszormenyi <zboszor@mol.hu>
+    19990213   Zoltán Böszörményi <zboszor@mail.externet.hu>
                Set up other Cyrix processors identical to the boot cpu.
                Since Cyrix don't support Intel APIC, this is l'art pour l'art.
                Weigh ARRs by size:
                If size <= 32M is given, set up ARR# we were given.
                If size >  32M is given, set up ARR7 only if it is free,
                fail otherwise.
-    19990214   Zoltan Boszormenyi <zboszor@mol.hu>
+    19990214   Zoltán Böszörményi <zboszor@mail.externet.hu>
                Also check for size >= 256K if we are to set up ARR7,
                mtrr_add() returns the value it gets from set_mtrr()
-    19990218   Zoltan Boszormenyi <zboszor@mol.hu>
+    19990218   Zoltán Böszörményi <zboszor@mail.externet.hu>
                Remove Cyrix "coma bug" workaround from here.
                Moved to linux/arch/i386/kernel/setup.c and
                linux/include/asm-i386/bugs.h
@@ -187,7 +187,7 @@
     19990305   Richard Gooch <rgooch@atnf.csiro.au>
 	       Temporarily disable AMD support now MTRR capability flag is set.
   v1.32
-    19990308   Zoltan Boszormenyi <zboszor@mol.hu>
+    19990308   Zoltán Böszörményi <zboszor@mail.externet.hu>
 	       Adjust my changes (19990212-19990218) to Richard Gooch's
 	       latest changes. (19990228-19990305)
   v1.33
@@ -197,7 +197,7 @@
 	       Support K6-II/III based on Alan Cox's <alan@redhat.com> patches.
   v1.34
     19990511   Bart Hartgers <bart@etpmod.phys.tue.nl>
-	       Support Centaur C6 MCR's.
+	       Support Centaur C6 MCRs.
     19990512   Richard Gooch <rgooch@atnf.csiro.au>
 	       Minor cleanups.
   v1.35
@@ -210,6 +210,9 @@
     19990819   Alan Cox <alan@redhat.com>
     	       Tested Zoltan's changes on a pre production Athlon - 100%
     	       success. Fixed one fall through check to be Intel only.
+    19991116   Bart Hartgers <bart@etpmod.phys.tue.nl>
+               Changed Centaur/IDT WinChip support to include WinChip 2.
+               (WC 2 kindly provided by IDT).
 */
 
 #include <linux/types.h>
@@ -464,9 +467,9 @@
 static void intel_get_mtrr (unsigned int reg, unsigned long *base,
 			    unsigned long *size, mtrr_type *type)
 {
-    unsigned long dummy, mask_lo, base_lo;
+    unsigned long mask_lo, mask_hi, base_lo, base_hi;
 
-    rdmsr (MTRRphysMask_MSR(reg), mask_lo, dummy);
+    rdmsr (MTRRphysMask_MSR(reg), mask_lo, mask_hi);
     if ((mask_lo & 0x800) == 0) {
 	/* Invalid (i.e. free) range. */
 	*base = 0;
@@ -475,20 +478,17 @@
 	return;
     }
 
-    rdmsr(MTRRphysBase_MSR(reg), base_lo, dummy);
+    rdmsr(MTRRphysBase_MSR(reg), base_lo, base_hi);
 
-    /* We ignore the extra address bits (32-35). If someone wants to
-       run x86 Linux on a machine with >4GB memory, this will be the
-       least of their problems. */
+    /* Work out the shifted address mask. */
+    mask_lo = 0xff000000 | mask_hi << (32 - PAGE_SHIFT)
+		| mask_lo >> PAGE_SHIFT;
 
-    /* Clean up mask_lo so it gives the real address mask. */
-    mask_lo = (mask_lo & 0xfffff000UL);
     /* This works correctly if size is a power of two, i.e. a
        contiguous range. */
-    *size = ~(mask_lo - 1);
-
-    *base = (base_lo & 0xfffff000UL);
-    *type = (base_lo & 0xff);
+    *size = -mask_lo;
+    *base = base_hi << (32 - PAGE_SHIFT) | base_lo >> PAGE_SHIFT;
+    *type = base_lo & 0xff;
 }   /*  End Function intel_get_mtrr  */
 
 static void cyrix_get_arr (unsigned int reg, unsigned long *base,
@@ -513,13 +513,13 @@
     /* Enable interrupts if it was enabled previously */
     __restore_flags (flags);
     shift = ((unsigned char *) base)[1] & 0x0f;
-    *base &= 0xfffff000UL;
+    *base >>= PAGE_SHIFT;
 
     /* Power of two, at least 4K on ARR0-ARR6, 256K on ARR7
      * Note: shift==0xf means 4G, this is unsupported.
      */
     if (shift)
-      *size = (reg < 7 ? 0x800UL : 0x20000UL) << shift;
+      *size = (reg < 7 ? 0x1UL : 0x40UL) << (shift - 1);
     else
       *size = 0;
 
@@ -552,7 +552,7 @@
     /*  Upper dword is region 1, lower is region 0  */
     if (reg == 1) low = high;
     /*  The base masks off on the right alignment  */
-    *base = low & 0xFFFE0000;
+    *base = (low & 0xFFFE0000) >> PAGE_SHIFT;
     *type = 0;
     if (low & 1) *type = MTRR_TYPE_UNCACHABLE;
     if (low & 2) *type = MTRR_TYPE_WRCOMB;
@@ -577,22 +577,35 @@
      *	*128K	...
      */
     low = (~low) & 0x1FFFC;
-    *size = (low + 4) << 15;
+    *size = (low + 4) << (15 - PAGE_SHIFT);
     return;
 }   /*  End Function amd_get_mtrr  */
 
-static struct
+static struct CENTAUR_MCR_CTX
 {
-    unsigned long high;
-    unsigned long low;
-} centaur_mcr[8];
+   unsigned type_bits[MTRR_NUM_TYPES];
+   struct {
+      u32 low;
+      u32 high;
+   } mcr[8];
+} *centaur_ctx=NULL;
 
 static void centaur_get_mcr (unsigned int reg, unsigned long *base,
 			     unsigned long *size, mtrr_type *type)
 {
-    *base = centaur_mcr[reg].high & 0xfffff000;
-    *size = (~(centaur_mcr[reg].low & 0xfffff000))+1;
-    *type = MTRR_TYPE_WRCOMB;	/*  If it is there, it is write-combining  */
+    unsigned i;
+    u32 tb;
+    tb = centaur_ctx->mcr[reg].low & 0xfff;
+    *base = centaur_ctx->mcr[reg].high >> PAGE_SHIFT;
+    *size = -(centaur_ctx->mcr[reg].low & 0xfffff000) >> PAGE_SHIFT;
+    if (*size) {
+        for( i=0; i<MTRR_NUM_TYPES; ++i)
+	    if (centaur_ctx->type_bits[i]==tb) {
+	        *type = (mtrr_type) i;
+	        return;
+	    }
+        *size = 0;
+    }
 }   /*  End Function centaur_get_mcr  */
 
 static void (*get_mtrr) (unsigned int reg, unsigned long *base,
@@ -621,8 +634,10 @@
     }
     else
     {
-	wrmsr (MTRRphysBase_MSR (reg), base | type, 0);
-	wrmsr (MTRRphysMask_MSR (reg), ~(size - 1) | 0x800, 0);
+	wrmsr (MTRRphysBase_MSR (reg), base << PAGE_SHIFT | type,
+	       (base & 0xf00000) >> (32 - PAGE_SHIFT));
+	wrmsr (MTRRphysMask_MSR (reg), -size << PAGE_SHIFT | 0x800,
+	       (-size & 0xf00000) >> (32 - PAGE_SHIFT));
     }
     if (do_safe) set_mtrr_done (&ctxt);
 }   /*  End Function intel_set_mtrr_up  */
@@ -636,7 +651,9 @@
     arr = CX86_ARR_BASE + (reg << 1) + reg; /* avoid multiplication by 3 */
 
     /* count down from 32M (ARR0-ARR6) or from 2G (ARR7) */
-    size >>= (reg < 7 ? 12 : 18);
+    if (reg >= 7)
+	size >>= 6;
+
     size &= 0x7fff; /* make sure arr_size <= 14 */
     for(arr_size = 0; size; arr_size++, size >>= 1);
 
@@ -657,6 +674,7 @@
     }
 
     if (do_safe) set_mtrr_prepare (&ctxt);
+    base <<= PAGE_SHIFT;
     setCx86(arr,    ((unsigned char *) &base)[3]);
     setCx86(arr+1,  ((unsigned char *) &base)[2]);
     setCx86(arr+2, (((unsigned char *) &base)[1]) | arr_size);
@@ -676,34 +694,36 @@
     [RETURNS] Nothing.
 */
 {
-    u32 low, high;
+    u32 regs[2];
     struct set_mtrr_context ctxt;
 
     if (do_safe) set_mtrr_prepare (&ctxt);
     /*
      *	Low is MTRR0 , High MTRR 1
      */
-    rdmsr (0xC0000085, low, high);
+    rdmsr (0xC0000085, regs[0], regs[1]);
     /*
      *	Blank to disable
      */
     if (size == 0)
-	*(reg ? &high : &low) = 0;
+	regs[reg] = 0;
     else
-	/* Set the register to the base (already shifted for us), the
-	   type (off by one) and an inverted bitmask of the size
-	   The size is the only odd bit. We are fed say 512K
-	   We invert this and we get 111 1111 1111 1011 but
-	   if you subtract one and invert you get the desired
-	   111 1111 1111 1100 mask
-	   */
-	*(reg ? &high : &low)=(((~(size-1))>>15)&0x0001FFFC)|base|(type+1);
+	/* Set the register to the base, the type (off by one) and an
+	   inverted bitmask of the size The size is the only odd
+	   bit. We are fed say 512K We invert this and we get 111 1111
+	   1111 1011 but if you subtract one and invert you get the
+	   desired 111 1111 1111 1100 mask
+
+	   But ~(x - 1) == ~x + 1 == -x. Two's complement rocks!  */
+	regs[reg] = (-size>>(15-PAGE_SHIFT) & 0x0001FFFC)
+	    			| (base<<PAGE_SHIFT) | (type+1);
+
     /*
      *	The writeback rule is quite specific. See the manual. Its
      *	disable local interrupts, write back the cache, set the mtrr
      */
     __asm__ __volatile__ ("wbinvd" : : : "memory");
-    wrmsr (0xC0000085, low, high);
+    wrmsr (0xC0000085, regs[0], regs[1]);
     if (do_safe) set_mtrr_done (&ctxt);
 }   /*  End Function amd_set_mtrr_up  */
 
@@ -716,6 +736,7 @@
     unsigned long low, high;
 
     if (do_safe) set_mtrr_prepare( &ctxt );
+   
     if (size == 0)
     {
         /*  Disable  */
@@ -723,13 +744,14 @@
     }
     else
     {
-        high = base & 0xfffff000; /* base works on 4K pages... */
-        low = ((~(size-1))&0xfffff000);
-        low |= 0x1f;		  /* only support write-combining... */
+        high = base << PAGE_SHIFT;
+        low = -size << PAGE_SHIFT | centaur_ctx->type_bits[type];
     }
-    centaur_mcr[reg].high = high;
-    centaur_mcr[reg].low = low;
+    centaur_ctx->mcr[reg].high = high;
+    centaur_ctx->mcr[reg].low = low;
+   
     wrmsr (0x110 + reg, low, high);
+   
     if (do_safe) set_mtrr_done( &ctxt );
 }   /*  End Function centaur_set_mtrr_up  */
 
@@ -1023,7 +1045,7 @@
     for (i = 0; i < max; ++i)
     {
 	(*get_mtrr) (i, &lbase, &lsize, &ltype);
-	if (lsize < 1) return i;
+	if (lsize == 0) return i;
     }
     return -ENOSPC;
 }   /*  End Function generic_get_free_region  */
@@ -1040,7 +1062,7 @@
     unsigned long lbase, lsize;
 
     /* If we are to set up a region >32M then look at ARR7 immediately */
-    if (size > 0x2000000UL) {
+    if (size > 0x2000UL) {
 	cyrix_get_arr (7, &lbase, &lsize, &ltype);
 	if (lsize < 1) return 7;
     /* else try ARR0-ARR6 first */
@@ -1048,11 +1070,11 @@
 	for (i = 0; i < 7; i++)
 	{
 	    cyrix_get_arr (i, &lbase, &lsize, &ltype);
-	    if (lsize < 1) return i;
+	    if (lsize == 0) return i;
 	}
 	/* ARR0-ARR6 isn't free, try ARR7 but its size must be at least 256K */
 	cyrix_get_arr (i, &lbase, &lsize, &ltype);
-	if ((lsize < 1) && (size >= 0x40000)) return i;
+	if ((lsize == 0) && (size >= 0x40)) return i;
     }
     return -ENOSPC;
 }   /*  End Function cyrix_get_free_region  */
@@ -1078,6 +1100,12 @@
     unsigned long lbase, lsize, last;
 
     if ( !(boot_cpu_data.x86_capability & X86_FEATURE_MTRR) ) return -ENODEV;
+    if (type >= MTRR_NUM_TYPES)
+    {
+	printk ("mtrr: type: %u illegal\n", type);
+	return -EINVAL;
+    }
+   
     switch (boot_cpu_data.x86_vendor)
     {
       case X86_VENDOR_AMD:
@@ -1105,7 +1133,7 @@
 	/*  Fall through  */
       case X86_VENDOR_CYRIX:
       case X86_VENDOR_CENTAUR:
-	if ( (base & 0xfff) || (size & 0xfff) )
+	if ( (base & (PAGE_SIZE - 1)) || (size & (PAGE_SIZE - 1)) )
 	{
 	    printk ("mtrr: size and base must be multiples of 4 kiB\n");
 	    printk ("mtrr: size: %lx  base: %lx\n", size, base);
@@ -1113,13 +1141,12 @@
 	}
         if (boot_cpu_data.x86_vendor == X86_VENDOR_CENTAUR)
 	{
-	    if (type != MTRR_TYPE_WRCOMB)
-	    {
-		printk ("mtrr: only write-combining is supported\n");
+	    if (centaur_ctx->type_bits[type]==0) {
+		printk ("mtrr: type not supported\n");
 		return -EINVAL;
 	    }
 	}
-	else if (base + size < 0x100000)
+	else if (base + size < 0x100000) /* Not Centaur */
 	{
 	    printk ("mtrr: cannot set region below 1 MiB (0x%lx,0x%lx)\n",
 		    base, size);
@@ -1141,11 +1168,12 @@
 	return -EINVAL;
 	/*break;*/
     }
-    if (type >= MTRR_NUM_TYPES)
-    {
-	printk ("mtrr: type: %u illegal\n", type);
-	return -EINVAL;
-    }
+
+    /* For all CPU types, the checks above should have ensured that
+       base and size are page aligned */
+    base >>= PAGE_SHIFT;
+    size >>= PAGE_SHIFT;
+
     /*  If the type is WC, check that this processor supports it  */
     if ( (type == MTRR_TYPE_WRCOMB) && !have_wrcomb () )
     {
@@ -1165,16 +1193,18 @@
 	if ( (base < lbase) || (base + size > lbase + lsize) )
 	{
 	    spin_unlock (&main_lock);
-	    printk ("mtrr: 0x%lx,0x%lx overlaps existing 0x%lx,0x%lx\n",
+	    printk ("mtrr: 0x%lx000,0x%lx000 overlaps existing"
+		    " 0x%lx000,0x%lx000\n",
 		    base, size, lbase, lsize);
 	    return -EINVAL;
 	}
 	/*  New region is enclosed by an existing region  */
 	if (ltype != type)
 	{
-	    if (type == MTRR_TYPE_UNCACHABLE) continue;
+	    if ((boot_cpu_data.x86_vendor != X86_VENDOR_CENTAUR) && 
+	        (type == MTRR_TYPE_UNCACHABLE)) continue;
 	    spin_unlock (&main_lock);
-	    printk ( "mtrr: type mismatch for %lx,%lx old: %s new: %s\n",
+	    printk ( "mtrr: type mismatch for %lx000,%lx000 old: %s new: %s\n",
 		     base, size, attrib_to_str (ltype), attrib_to_str (type) );
 	    return -EINVAL;
 	}
@@ -1214,6 +1244,7 @@
     unsigned long lbase, lsize;
 
     if ( !(boot_cpu_data.x86_capability & X86_FEATURE_MTRR) ) return -ENODEV;
+
     max = get_num_var_ranges ();
     spin_lock_reschedule (&main_lock);
     if (reg < 0)
@@ -1222,7 +1253,8 @@
 	for (i = 0; i < max; ++i)
 	{
 	    (*get_mtrr) (i, &lbase, &lsize, &ltype);
-	    if ( (lbase == base) && (lsize == size) )
+	    if (lbase < 0x100000 && lbase << PAGE_SHIFT == base
+		&& lsize < 0x100000 && lsize << PAGE_SHIFT == size)
 	    {
 		reg = i;
 		break;
@@ -1231,7 +1263,7 @@
 	if (reg < 0)
 	{
 	    spin_unlock (&main_lock);
-	    printk ("mtrr: no MTRR for %lx,%lx found\n", base, size);
+	    printk ("mtrr: no MTRR for %lx000,%lx000 found\n", base, size);
 	    return -EINVAL;
 	}
     }
@@ -1412,7 +1444,16 @@
 	    return -EFAULT;
 	if ( gentry.regnum >= get_num_var_ranges () ) return -EINVAL;
 	(*get_mtrr) (gentry.regnum, &gentry.base, &gentry.size, &type);
-	gentry.type = type;
+
+	/* Hide entries that go above 4GB */
+	if (gentry.base + gentry.size > 0x100000 || gentry.size == 0x100000)
+	    gentry.base = gentry.size = gentry.type = 0;
+	else {
+	    gentry.base <<= PAGE_SHIFT;
+	    gentry.size <<= PAGE_SHIFT;
+	    gentry.type = type;
+	}
+	
 	if ( copy_to_user ( (void *) arg, &gentry, sizeof gentry) )
 	     return -EFAULT;
 	break;
@@ -1504,24 +1545,24 @@
     for (i = 0; i < max; i++)
     {
 	(*get_mtrr) (i, &base, &size, &type);
-	if (size < 1) usage_table[i] = 0;
+	if (size == 0) usage_table[i] = 0;
 	else
 	{
-	    if (size < 0x100000)
+	    if (size < 0x100000 >> PAGE_SHIFT)
 	    {
-		/* 1MB */
-		factor = 'k';
-		size >>= 10;
+		/* less than 1MB */
+		factor = 'K';
+		size <<= PAGE_SHIFT - 10;
 	    }
 	    else
 	    {
 		factor = 'M';
-		size >>= 20;
+		size >>= 20 - PAGE_SHIFT;
 	    }
 	    sprintf
 		(ascii_buffer + ascii_buf_bytes,
-		 "reg%02i: base=0x%08lx (%4liMB), size=%4li%cB: %s, count=%d\n",
-		 i, base, base>>20, size, factor,
+		 "reg%02i: base=0x%05lx000 (%4liMB), size=%4li%cB: %s, count=%d\n",
+		 i, base, base >> (20 - PAGE_SHIFT), size, factor,
 		 attrib_to_str (type), usage_table[i]);
 	    ascii_buf_bytes += strlen (ascii_buffer + ascii_buf_bytes);
 	}
@@ -1652,7 +1693,51 @@
 {
     unsigned i;
     struct set_mtrr_context ctxt;
-
+    u32 low,high;
+    u32 mcr_ctrl_value;
+    unsigned mcr_type;
+    /* Deduce the MCR traits type for this processor.
+     * The documentation of the WinChip 2 suggests that we can read the
+     * MCR_CTRL register for all WinChips, but this hangs on my C6.
+     * -> Work around this.
+     */
+    if ((boot_cpu_data.x86 == 5) && (boot_cpu_data.x86_model == 4)) {
+	/* C6 */
+	mcr_type = 0;
+    } else {
+	rdmsr (0x120, low, high );
+	mcr_type = (low>>17)&0x7;
+    }
+    centaur_ctx = kmalloc( sizeof( struct CENTAUR_MCR_CTX ), GFP_KERNEL );
+    if (centaur_ctx == NULL) {
+        printk("mtrr: Could not allocate memory. Disabling MTRR.\n");
+        boot_cpu_data.x86_capability &= ~X86_FEATURE_MTRR;
+        return;
+    }
+    for( i=0; i<MTRR_NUM_TYPES; ++i) {
+        centaur_ctx->type_bits[i] = 0;
+    }
+    switch( mcr_type ) {
+      case 0:
+        centaur_ctx->type_bits[ MTRR_TYPE_WRCOMB ] = 0x0f;
+        centaur_ctx->type_bits[ MTRR_TYPE_WRBACK ] = 0x1f;
+        mcr_ctrl_value = 0x01f0001f;
+        break;
+      case 1:
+        centaur_ctx->type_bits[ MTRR_TYPE_UNCACHABLE ] = 0x02;
+        centaur_ctx->type_bits[ MTRR_TYPE_WRCOMB ]     = 0x13;
+        centaur_ctx->type_bits[ MTRR_TYPE_WRTHROUGH ]  = 0x11;
+        centaur_ctx->type_bits[ MTRR_TYPE_WRBACK ]     = 0x19;
+        mcr_ctrl_value = 0x01f2005f;
+        break;
+      default:
+        kfree( centaur_ctx );
+        centaur_ctx = NULL;
+        printk ("mtrr: Centaur MCR traits version %u not supported. "
+		"Disabling MTRR.\n", mcr_type);
+	boot_cpu_data.x86_capability &= ~X86_FEATURE_MTRR;
+        return;
+    }
     set_mtrr_prepare (&ctxt);
     /* Unfortunately, MCR's are read-only, so there is no way to
      * find out what the bios might have done.
@@ -1661,14 +1746,16 @@
      * This way we are sure that the centaur_mcr array contains the actual
      * values. The disadvantage is that any BIOS tweaks are thus undone.
      */
+    /* switch off MCR's first */
+    wrmsr (0x120, 0, 0 );
     for (i = 0; i < 8; ++i)
     {
-        centaur_mcr[i].high = 0;
-	centaur_mcr[i].low = 0;
+        centaur_ctx->mcr[i].high = 0;
+	centaur_ctx->mcr[i].low = 0;
 	wrmsr (0x110 + i , 0, 0);
     }
     /*  Throw the main write-combining switch...  */
-    wrmsr (0x120, 0x01f0001f, 0);
+    wrmsr (0x120, mcr_ctrl_value, 0);
     set_mtrr_done (&ctxt);
 }   /*  End Function centaur_mcr_init  */
 
Index: oldkernel/linux/arch/i386/kernel/setup.c
diff -u linux/arch/i386/kernel/setup.c:1.5 linux/arch/i386/kernel/setup.c:1.6
--- linux/arch/i386/kernel/setup.c:1.5	Thu Jun  1 17:04:06 2000
+++ linux/arch/i386/kernel/setup.c	Fri Jul  7 15:36:41 2000
@@ -427,7 +427,7 @@
 		i386_endbase += PAGE_OFFSET;
 	}
 
-#define VMALLOC_RESERVE	(64 << 20)	/* 64MB for vmalloc */
+#define VMALLOC_RESERVE	(128 << 20)	/* 64MB for vmalloc */
 #define MAXMEM	((unsigned long)(-PAGE_OFFSET-VMALLOC_RESERVE))
 
 #ifdef CONFIG_BIGMEM
@@ -835,8 +835,8 @@
 	{ X86_VENDOR_INTEL,	6,
 	  { "Pentium Pro A-step", "Pentium Pro", NULL, "Pentium II (Klamath)", 
 	    NULL, "Pentium II (Deschutes)", "Mobile Pentium II", 
-	    "Pentium III (Katmai)", "Pentium III (Coppermine)", NULL, NULL, 
-	    NULL, NULL, NULL, NULL, NULL }},
+	    "Pentium III (Katmai)", "Pentium III (Coppermine)", NULL,
+            "Pentium III (Cascades)", NULL, NULL, NULL, NULL, NULL }},
 	{ X86_VENDOR_AMD,	4,
 	  { NULL, NULL, NULL, "486 DX/2", NULL, NULL, NULL, "486 DX/2-WB",
 	    "486 DX/4", "486 DX/4-WB", NULL, NULL, NULL, NULL, "Am5x86-WT",
@@ -898,24 +898,26 @@
 				c->x86_cache_size = 0;
 				break;
 
-			case 0x41:
+			case 0x41: /* 4-way 128 */
 				c->x86_cache_size = 128;
 				break;
 
-			case 0x42:
-			case 0x82: /*Detect 256-Kbyte cache on Coppermine*/ 
+			case 0x42: /* 4-way 256 */
+			case 0x82: /* 8-way 256 */ 
 				c->x86_cache_size = 256;
 				break;
 
-			case 0x43:
+			case 0x43: /* 4-way 512*/
 				c->x86_cache_size = 512;
 				break;
 
-			case 0x44:
+			case 0x44: /* 4-way 1024 */
+			case 0x84: /* 8-way 1024 */
 				c->x86_cache_size = 1024;
 				break;
 
-			case 0x45:
+			case 0x45: /* 4-way 2048 */
+			case 0x85: /* 8-way 2048 */
 				c->x86_cache_size = 2048;
 				break;
 
Index: oldkernel/linux/arch/i386/kernel/signal.c
diff -u linux/arch/i386/kernel/signal.c:1.3 linux/arch/i386/kernel/signal.c:1.4
--- linux/arch/i386/kernel/signal.c:1.3	Thu Jun  1 17:04:57 2000
+++ linux/arch/i386/kernel/signal.c	Fri Jul  7 15:36:41 2000
@@ -154,11 +154,21 @@
 
 static inline int restore_i387_hard(struct _fpstate *buf)
 {
+	int err = 0;
 	struct task_struct *tsk = current;
-	clear_fpu(tsk);
 
-	return i387_user_to_hard(&tsk->tss.i387.hard,
-				 (struct user_i387_struct *)buf);
+	/* make sure the base fpu info is in the task struct */
+	err = i387_user_to_hard(&tsk->tss.i387.hard,
+				(struct user_i387_struct *)buf);
+	if (err) {
+		/*
+		 * Oops, we didn't get a valid FPU image back, wipe out
+		 * our current FPU context to force an finit at the next
+		 * DNA
+		 */
+		tsk->used_math = 0;
+	}
+	return err;
 }
 
 static inline int restore_i387(struct _fpstate *buf)
@@ -172,7 +182,6 @@
 	else
 		err = restore_i387_soft(&current->tss.i387.soft, buf);
 #endif
-	current->used_math = 1;
 	return err;
 }
 
@@ -315,7 +324,7 @@
 	unlazy_fpu(tsk);
 	err = i387_hard_to_user((struct user_i387_struct *)buf,
 			&tsk->tss.i387.hard);
-	i387_get_swd(status, tsk->tss.i387.hard);
+	i387_get_swd(tsk->tss.i387.hard, status);
 	err |= put_user(status, &buf->status);
 	if (err)
 		return -1;
@@ -326,11 +335,6 @@
 {
 	if (!current->used_math)
 		return 0;
-
-	/* This will cause a "finit" to be triggered by the next
-	   attempted FPU operation by the 'current' process.
-	   */
-	current->used_math = 0;
 
 #ifndef CONFIG_MATH_EMULATION
 	return save_i387_hard(buf);
Index: oldkernel/linux/arch/i386/kernel/sys_i386.c
diff -u linux/arch/i386/kernel/sys_i386.c:1.2 linux/arch/i386/kernel/sys_i386.c:1.3
--- linux/arch/i386/kernel/sys_i386.c:1.2	Thu Jun  1 15:03:08 2000
+++ linux/arch/i386/kernel/sys_i386.c	Fri Jul  7 15:36:41 2000
@@ -41,43 +41,6 @@
 	return error;
 }
 
-/* common code for old and new mmaps */
-static inline long do_mmap2(
-	unsigned long addr, unsigned long len,
-	unsigned long prot, unsigned long flags,
-	unsigned long fd, unsigned long pgoff)
-{
-	int error = -EBADF;
-	struct file * file = NULL;
-
-	flags &= ~(MAP_EXECUTABLE | MAP_DENYWRITE);
-	if (!(flags & MAP_ANONYMOUS)) {
-		file = fget(fd);
-		if (!file)
-			goto out;
-	}
-
-	down(&current->mm->mmap_sem);
-	lock_kernel();
-
-	error = do_mmap_pgoff(file, addr, len, prot, flags, pgoff);
-
-	unlock_kernel();
-	up(&current->mm->mmap_sem);
-
-	if (file)
-		fput(file);
-out:
-	return error;
-}
-
-asmlinkage long sys_mmap2(unsigned long addr, unsigned long len,
-	unsigned long prot, unsigned long flags,
-	unsigned long fd, unsigned long pgoff)
-{
-	return do_mmap2(addr, len, prot, flags, fd, pgoff);
-}
-
 /*
  * Perform the select(nd, in, out, ex, tv) and mmap() system
  * calls. Linux/i386 didn't use to be able to handle more than
@@ -96,19 +59,30 @@
 
 asmlinkage int old_mmap(struct mmap_arg_struct *arg)
 {
+	int error = -EFAULT;
+	struct file * file = NULL;
 	struct mmap_arg_struct a;
-	int err = -EFAULT;
 
 	if (copy_from_user(&a, arg, sizeof(a)))
-		goto out;
+		return -EFAULT;
 
-	err = -EINVAL;
-	if (a.offset & ~PAGE_MASK)
-		goto out;
+	down(&current->mm->mmap_sem);
+	lock_kernel();
+	if (!(a.flags & MAP_ANONYMOUS)) {
+		error = -EBADF;
+		file = fget(a.fd);
+		if (!file)
+			goto out;
+	}
+	a.flags &= ~(MAP_EXECUTABLE | MAP_DENYWRITE);
 
-	err = do_mmap2(a.addr, a.len, a.prot, a.flags, a.fd, a.offset >> PAGE_SHIFT);
+	error = do_mmap(file, a.addr, a.len, a.prot, a.flags, a.offset);
+	if (file)
+		fput(file);
 out:
-	return err;
+	unlock_kernel();
+	up(&current->mm->mmap_sem);
+	return error;
 }
 
 extern asmlinkage int sys_select(int, fd_set *, fd_set *, fd_set *, struct timeval *);
Index: oldkernel/linux/arch/i386/kernel/traps.c
diff -u linux/arch/i386/kernel/traps.c:1.3 linux/arch/i386/kernel/traps.c:1.4
--- linux/arch/i386/kernel/traps.c:1.3	Thu Jun  1 17:01:59 2000
+++ linux/arch/i386/kernel/traps.c	Fri Jul  7 15:36:41 2000
@@ -20,6 +20,7 @@
 #include <linux/smp_lock.h>
 #include <linux/init.h>
 #include <linux/delay.h>
+#include <asm/i387.h>
 
 #ifdef CONFIG_MCA
 #include <linux/mca.h>
@@ -33,7 +34,6 @@
 #include <asm/atomic.h>
 #include <asm/debugreg.h>
 #include <asm/desc.h>
-#include <asm/i387.h>
 
 #include <asm/smp.h>
 
@@ -536,9 +536,7 @@
 	 * (this will also clear the error)
 	 */
 	task = current;
-	i387_save_hard(task->tss.i387);
-	task->flags &= ~PF_USEDFPU;
-	stts();
+	save_fpu(task);
 	task->tss.trap_no = 16;
 	task->tss.error_code = 0;
 	force_sig(SIGFPE, task);
@@ -569,44 +567,18 @@
 asmlinkage void math_state_restore(struct pt_regs regs)
 {
 	__asm__ __volatile__("clts");		/* Allow maths ops (or we recurse) */
-	/*
-	 * If we have either of the kernel FPU use states set in the
-	 * fpustate variable, then this will be a kernel math trap.
-	 * Otherwise, this is userspace trying to use the FPU.
-	 */
-	if(current->tss.x86_fpustate & X86_FPUSTATE_KERN_ANY) {
-		load_default_mxcsr(); /* we don't ever mess with this in
-					 kernel space, so just make sure
-					 we have a reasonable one so we
-					 don't start taking unmasked
-					 exceptions by accident */
-		if(current->tss.mmx_reg_space != NULL)
-			__asm__("movq 0x00(%0), %%mm0\n\t"
-				"movq 0x08(%0), %%mm1\n\t"
-				"movq 0x10(%0), %%mm2\n\t"
-				"movq 0x18(%0), %%mm3\n\t"
-				:: "r" (current->tss.mmx_reg_space));
-		if(current->tss.kni_reg_space != NULL)
-			__asm__("movups 0x00(%0), %%xmm0\n\t"
-				"movups 0x10(%0), %%xmm1\n\t"
-				"movups 0x20(%0), %%xmm2\n\t"
-				"movups 0x30(%0), %%xmm3\n\t"
-				:: "r" (current->tss.kni_reg_space));
-	} else if(current->tss.x86_fpustate & X86_FPUSTATE_USER_SAVED) {
-		i387_restore_hard(current->tss.i387);
-		current->tss.x86_fpustate = 0;
-	} else if(current->used_math) {
+	if(current->used_math)
 		i387_restore_hard(current->tss.i387);
-		current->flags|=PF_USEDFPU;	/* make switch_to() work */
-	} else {
+	else
+	{
 		/*
 		 *	Our first FPU usage, clean the chip.
 		 */
 		__asm__("fninit");
 		load_default_mxcsr();
 		current->used_math = 1;
-		current->flags|=PF_USEDFPU;	/* make switch_to() work */
 	}
+	current->flags|=PF_USEDFPU;		/* So we fnsave on switch_to() */
 }
 
 #ifndef CONFIG_MATH_EMULATION
Index: oldkernel/linux/arch/i386/lib/Makefile
diff -u linux/arch/i386/lib/Makefile:1.2 linux/arch/i386/lib/Makefile:1.3
--- linux/arch/i386/lib/Makefile:1.2	Thu Jun  1 15:05:19 2000
+++ linux/arch/i386/lib/Makefile	Fri Jul  7 15:36:42 2000
@@ -9,8 +9,4 @@
 L_OBJS  = checksum.o old-checksum.o semaphore.o delay.o \
 	usercopy.o getuser.o putuser.o
 
-ifeq ($(CONFIG_X86_CPU_OPTIMIZATIONS),y)
-	L_OBJS += best_function.o simd.o
-endif
-
 include $(TOPDIR)/Rules.make
Index: oldkernel/linux/arch/i386/mm/init.c
diff -u linux/arch/i386/mm/init.c:1.4 linux/arch/i386/mm/init.c:1.5
--- linux/arch/i386/mm/init.c:1.4	Thu Jun  1 17:04:06 2000
+++ linux/arch/i386/mm/init.c	Fri Jul  7 15:36:42 2000
@@ -35,6 +35,40 @@
 extern void show_net_buffers(void);
 extern unsigned long init_smp_mappings(unsigned long);
 
+#ifdef CONFIG_BLK_DEV_INITRD
+
+extern unsigned long initrd_end,initrd_start;
+
+static void __init relocate_initrd(unsigned long mem_start,unsigned long mem_end)
+{
+        unsigned long initrd_size = initrd_end - initrd_start;
+        unsigned long dest;
+
+        if(!initrd_start || initrd_start >= initrd_end)
+                return;
+        if(mem_start > initrd_start) {
+                printk(KERN_CRIT "initrd already destroyed by paging_init!\n");
+                return;
+        }
+
+        dest = ((mem_end - initrd_size) & PAGE_MASK);
+        printk(KERN_WARNING "relocating initrd image:\n");
+        printk(KERN_WARNING "    initrd_start:0x%08lx    initrd_end:0x%08lx\n",
+                initrd_start, initrd_end);
+        printk(KERN_WARNING "    mem_start:0x%08lx    mem_end:0x%08lx\n",
+                mem_start, mem_end);
+        printk(KERN_WARNING "    initrd_size:0x%08lx     dest:0x%08lx\n",
+                initrd_size, dest);
+
+        if((initrd_end < dest) &&
+           (initrd_start > mem_start)) {
+                __memcpy((void *)dest,(void *)initrd_start,initrd_size);
+                initrd_start = dest;
+                initrd_end = initrd_start + initrd_size;
+        }
+}
+#endif
+
 void __bad_pte_kernel(pmd_t *pmd)
 {
 	printk("Bad pmd in pte_alloc: %08lx\n", pmd_val(*pmd));
@@ -327,8 +361,11 @@
 #ifndef CONFIG_BIGMEM
 	return free_area_init(start_mem, end_mem);
 #else
-	kmap_init(); /* run after fixmap_init */
-	return free_area_init(start_mem, bigmem_end + PAGE_OFFSET);
+#ifdef CONFIG_BLK_DEV_INITRD
+	relocate_initrd(start_mem,end_mem);
+#endif
+	kmap_init();
+	return(free_area_init(start_mem,bigmem_end + PAGE_OFFSET));
 #endif
 }
 
Index: oldkernel/linux/arch/mips/baget/vacserial.c
diff -u linux/arch/mips/baget/vacserial.c:1.1.1.1 linux/arch/mips/baget/vacserial.c:1.2
--- linux/arch/mips/baget/vacserial.c:1.1.1.1	Wed May 31 12:33:53 2000
+++ linux/arch/mips/baget/vacserial.c	Fri Jul  7 15:36:42 2000
@@ -2162,7 +2162,7 @@
 done:
 	if (off >= len+begin)
 		return 0;
-	*start = page + (begin-off);
+	*start = page + (off-begin);
 	return ((count < begin+len-off) ? count : begin+len-off);
 }
 
Index: oldkernel/linux/arch/ppc/8xx_io/uart.c
diff -u linux/arch/ppc/8xx_io/uart.c:1.1.1.1 linux/arch/ppc/8xx_io/uart.c:1.2
--- linux/arch/ppc/8xx_io/uart.c:1.1.1.1	Wed May 31 12:33:53 2000
+++ linux/arch/ppc/8xx_io/uart.c	Fri Jul  7 15:36:42 2000
@@ -2050,7 +2050,7 @@
 done:
 	if (off >= len+begin)
 		return 0;
-	*start = page + (begin-off);
+	*start = page + (off-begin);
 	return ((count < begin+len-off) ? count : begin+len-off);
 }
 
Index: oldkernel/linux/arch/sparc/config.in
diff -u linux/arch/sparc/config.in:1.3 linux/arch/sparc/config.in:1.4
--- linux/arch/sparc/config.in:1.3	Thu Jun  1 15:44:43 2000
+++ linux/arch/sparc/config.in	Fri Jul  7 15:36:42 2000
@@ -85,10 +85,13 @@
 
 bool 'Multiple devices driver support' CONFIG_BLK_DEV_MD
 if [ "$CONFIG_BLK_DEV_MD" = "y" ]; then
+  bool 'Autodetect RAID partitions' CONFIG_AUTODETECT_RAID
   tristate '   Linear (append) mode' CONFIG_MD_LINEAR
   tristate '   RAID-0 (striping) mode' CONFIG_MD_STRIPED
   tristate '   RAID-1 (mirroring) mode' CONFIG_MD_MIRRORING
   tristate '   RAID-4/RAID-5 mode' CONFIG_MD_RAID5
+  tristate '   Translucent mode' CONFIG_MD_TRANSLUCENT
+  tristate '   Hierarchical Storage Management support' CONFIG_MD_HSM
 fi
 
 tristate 'RAM disk support' CONFIG_BLK_DEV_RAM
Index: oldkernel/linux/arch/sparc/defconfig
diff -u linux/arch/sparc/defconfig:1.3 linux/arch/sparc/defconfig:1.4
--- linux/arch/sparc/defconfig:1.3	Thu Jun  1 15:44:43 2000
+++ linux/arch/sparc/defconfig	Fri Jul  7 15:36:42 2000
@@ -88,10 +88,13 @@
 #
 CONFIG_BLK_DEV_FD=y
 CONFIG_BLK_DEV_MD=y
+CONFIG_AUTODETECT_RAID=y
 CONFIG_MD_LINEAR=m
 CONFIG_MD_STRIPED=m
 CONFIG_MD_MIRRORING=m
 CONFIG_MD_RAID5=m
+# CONFIG_MD_TRANSLUCENT is not set
+# CONFIG_MD_HSM is not set
 CONFIG_BLK_DEV_RAM=y
 CONFIG_BLK_DEV_INITRD=y
 CONFIG_BLK_DEV_LOOP=m
Index: oldkernel/linux/arch/sparc/kernel/sys_sparc.c
diff -u linux/arch/sparc/kernel/sys_sparc.c:1.2 linux/arch/sparc/kernel/sys_sparc.c:1.3
--- linux/arch/sparc/kernel/sys_sparc.c:1.2	Thu Jun  1 15:03:08 2000
+++ linux/arch/sparc/kernel/sys_sparc.c	Fri Jul  7 15:36:42 2000
@@ -176,9 +176,9 @@
 }
 
 /* Linux version of mmap */
-asmlinkage unsigned long do_mmap2(unsigned long addr, unsigned long len,
+asmlinkage unsigned long sys_mmap(unsigned long addr, unsigned long len,
 	unsigned long prot, unsigned long flags, unsigned long fd,
-	unsigned long pgoff)
+	unsigned long off)
 {
 	struct file * file = NULL;
 	unsigned long retval = -EBADF;
@@ -211,7 +211,7 @@
 		goto out_putf;
 
 	flags &= ~(MAP_EXECUTABLE | MAP_DENYWRITE);
-	retval = do_mmap_pgoff(file, addr, len, prot, flags, pgoff);
+	retval = do_mmap(file, addr, len, prot, flags, off);
 
 out_putf:
 	if (file)
@@ -222,22 +222,6 @@
 	return retval;
 }
 
-asmlinkage unsigned long sys_mmap2(unsigned long addr, unsigned long len,
-	unsigned long prot, unsigned long flags, unsigned long fd,
-	unsigned long pgoff)
-{
-	/* Make sure the shift for mmap2 is constant (12), no matter what PAGE_SIZE
-	   we have. */
-	return do_mmap2(addr, len, prot, flags, fd, pgoff >> (PAGE_SHIFT - 12));
-}
-
-asmlinkage unsigned long sys_mmap(unsigned long addr, unsigned long len,
-	unsigned long prot, unsigned long flags, unsigned long fd,
-	unsigned long off)
-{
-	return do_mmap2(addr, len, prot, flags, fd, off >> PAGE_SHIFT);
-}
-
 /* we come to here via sys_nis_syscall so it can setup the regs argument */
 asmlinkage unsigned long
 c_sys_nis_syscall (struct pt_regs *regs)
@@ -251,6 +235,13 @@
 	show_regs (regs);
 #endif
 	unlock_kernel();
+	return -ENOSYS;
+}
+
+/* We don't want to warn about LFS syscalls which are defined in our headers */
+asmlinkage unsigned long
+sys_lfs_syscall (void)
+{
 	return -ENOSYS;
 }
 
Index: oldkernel/linux/arch/sparc/kernel/systbls.S
diff -u linux/arch/sparc/kernel/systbls.S:1.2 linux/arch/sparc/kernel/systbls.S:1.3
--- linux/arch/sparc/kernel/systbls.S:1.2	Thu Jun  1 15:03:08 2000
+++ linux/arch/sparc/kernel/systbls.S	Fri Jul  7 15:36:42 2000
@@ -1,4 +1,4 @@
-/* $Id: systbls.S,v 1.88 1999/12/21 14:09:06 jj Exp $
+/* $Id: systbls.S,v 1.83.2.1 1999/09/22 11:37:27 jj Exp $
  * systbls.S: System call entry point tables for OS compatibility.
  *            The native Linux system call table lives here also.
  *
@@ -29,12 +29,12 @@
 /*40*/	.long sys_newlstat, sys_dup, sys_pipe, sys_times, sys_nis_syscall
 /*45*/	.long sys_umount, sys_setgid, sys_getgid, sys_signal, sys_geteuid
 /*50*/	.long sys_getegid, sys_acct, sys_nis_syscall, sys_nis_syscall, sys_ioctl
-/*55*/	.long sys_reboot, sys_mmap2, sys_symlink, sys_readlink, sys_execve
-/*60*/	.long sys_umask, sys_chroot, sys_newfstat, sys_fstat64, sys_getpagesize
+/*55*/	.long sys_reboot, sys_lfs_syscall, sys_symlink, sys_readlink, sys_execve
+/*60*/	.long sys_umask, sys_chroot, sys_newfstat, sys_lfs_syscall, sys_getpagesize
 /*65*/	.long sys_msync, sys_vfork, sys_pread, sys_pwrite, sys_nis_syscall
 /*70*/	.long sys_nis_syscall, sys_mmap, sys_nis_syscall, sys_munmap, sys_mprotect
-/*75*/	.long sys_nis_syscall, sys_vhangup, sys_truncate64, sys_nis_syscall, sys_getgroups
-/*80*/	.long sys_setgroups, sys_getpgrp, sys_nis_syscall, sys_setitimer, sys_ftruncate64
+/*75*/	.long sys_nis_syscall, sys_vhangup, sys_lfs_syscall, sys_nis_syscall, sys_getgroups
+/*80*/	.long sys_setgroups, sys_getpgrp, sys_nis_syscall, sys_setitimer, sys_lfs_syscall
 /*85*/	.long sys_swapon, sys_getitimer, sys_nis_syscall, sys_sethostname, sys_nis_syscall
 /*90*/	.long sys_dup2, sys_nis_syscall, sys_fcntl, sys_select, sys_nis_syscall
 /*95*/	.long sys_fsync, sys_setpriority, sys_nis_syscall, sys_nis_syscall, sys_nis_syscall
@@ -44,8 +44,8 @@
 /*115*/	.long sys_nis_syscall, sys_gettimeofday, sys_getrusage, sys_nis_syscall, sys_getcwd
 /*120*/	.long sys_readv, sys_writev, sys_settimeofday, sys_fchown, sys_fchmod
 /*125*/	.long sys_nis_syscall, sys_setreuid, sys_setregid, sys_rename, sys_truncate
-/*130*/	.long sys_ftruncate, sys_flock, sys_lstat64, sys_nis_syscall, sys_nis_syscall
-/*135*/	.long sys_nis_syscall, sys_mkdir, sys_rmdir, sys_utimes, sys_stat64
+/*130*/	.long sys_ftruncate, sys_flock, sys_lfs_syscall, sys_nis_syscall, sys_nis_syscall
+/*135*/	.long sys_nis_syscall, sys_mkdir, sys_rmdir, sys_utimes, sys_lfs_syscall
 /*140*/	.long sys_nis_syscall, sys_nis_syscall, sys_nis_syscall, sys_nis_syscall, sys_getrlimit
 /*145*/	.long sys_setrlimit, sys_nis_syscall, sys_prctl, sys_pciconfig_read, sys_pciconfig_write
 /*150*/	.long sys_nis_syscall, sys_nis_syscall, sys_nis_syscall, sys_poll, sys_nis_syscall
Index: oldkernel/linux/arch/sparc/lib/muldi3.S
diff -u linux/arch/sparc/lib/muldi3.S:1.1 linux/arch/sparc/lib/muldi3.S:1.2
--- linux/arch/sparc/lib/muldi3.S:1.1	Thu Jun  1 15:12:09 2000
+++ linux/arch/sparc/lib/muldi3.S	Fri Jul  7 15:36:42 2000
@@ -1,4 +1,4 @@
-/* $Id: muldi3.S,v 1.1 2000/06/01 22:12:09 ccr Exp $
+/* $Id: muldi3.S,v 1.2 2000/07/07 22:36:42 sflory Exp $
  * muldi3.S:   GCC emits these for certain drivers playing
  *	       with long longs.
  *
Index: oldkernel/linux/arch/sparc/mm/srmmu.c
diff -u linux/arch/sparc/mm/srmmu.c:1.2 linux/arch/sparc/mm/srmmu.c:1.3
--- linux/arch/sparc/mm/srmmu.c:1.2	Thu Jun  1 15:44:43 2000
+++ linux/arch/sparc/mm/srmmu.c	Fri Jul  7 15:36:42 2000
@@ -2424,7 +2424,15 @@
 	BTFIXUPSET_CALL(set_pte, srmmu_set_pte_nocache_swift, BTFIXUPCALL_NORM);
 	BTFIXUPSET_CALL(init_new_context, swift_init_new_context, BTFIXUPCALL_NORM);
 
+#if 1
+	/* If granular flushes are ever cured and reenabled in
+	 * swift.S, revert this setting back to non-global iommu
+	 * cache flushes. -DaveM
+	 */
+	flush_page_for_dma_global = 1;
+#else
 	flush_page_for_dma_global = 0;
+#endif
 
 	/* Are you now convinced that the Swift is one of the
 	 * biggest VLSI abortions of all time?  Bravo Fujitsu!
Index: oldkernel/linux/arch/sparc/mm/swift.S
diff -u linux/arch/sparc/mm/swift.S:1.1.1.1 linux/arch/sparc/mm/swift.S:1.2
--- linux/arch/sparc/mm/swift.S:1.1.1.1	Wed May 31 12:33:53 2000
+++ linux/arch/sparc/mm/swift.S	Fri Jul  7 15:36:42 2000
@@ -41,10 +41,10 @@
 swift_flush_page_to_ram:
 	sethi	%hi(0x2000), %o0
 1:	subcc	%o0, 0x10, %o0
-	sta	%g0, [%o0] ASI_M_TXTC_TAG
+	add	%o0, %o0, %o1
 	sta	%g0, [%o0] ASI_M_DATAC_TAG
 	bne	1b
-	 nop
+	 sta	%g0, [%o1] ASI_M_TXTC_TAG
 	retl
 	 nop
 #else
Index: oldkernel/linux/arch/sparc64/config.in
diff -u linux/arch/sparc64/config.in:1.5 linux/arch/sparc64/config.in:1.6
--- linux/arch/sparc64/config.in:1.5	Thu Jun  1 16:59:06 2000
+++ linux/arch/sparc64/config.in	Fri Jul  7 15:36:42 2000
@@ -97,10 +97,13 @@
 
 bool 'Multiple devices driver support' CONFIG_BLK_DEV_MD
 if [ "$CONFIG_BLK_DEV_MD" = "y" ]; then
+  bool 'Autodetect RAID partitions' CONFIG_AUTODETECT_RAID
   tristate '   Linear (append) mode' CONFIG_MD_LINEAR
   tristate '   RAID-0 (striping) mode' CONFIG_MD_STRIPED
   tristate '   RAID-1 (mirroring) mode' CONFIG_MD_MIRRORING
   tristate '   RAID-4/RAID-5 mode' CONFIG_MD_RAID5
+  tristate '   Translucent mode' CONFIG_MD_TRANSLUCENT
+  tristate '   Hierarchical Storage Management support' CONFIG_MD_HSM
 fi
 
 tristate 'RAM disk support' CONFIG_BLK_DEV_RAM
Index: oldkernel/linux/arch/sparc64/defconfig
diff -u linux/arch/sparc64/defconfig:1.5 linux/arch/sparc64/defconfig:1.6
--- linux/arch/sparc64/defconfig:1.5	Thu Jun  1 16:59:06 2000
+++ linux/arch/sparc64/defconfig	Fri Jul  7 15:36:42 2000
@@ -107,10 +107,13 @@
 #
 CONFIG_BLK_DEV_FD=y
 CONFIG_BLK_DEV_MD=y
+CONFIG_AUTODETECT_RAID=y
 CONFIG_MD_LINEAR=m
 CONFIG_MD_STRIPED=m
 CONFIG_MD_MIRRORING=m
 CONFIG_MD_RAID5=m
+# CONFIG_MD_TRANSLUCENT is not set
+# CONFIG_MD_HSM is not set
 CONFIG_BLK_DEV_RAM=y
 CONFIG_BLK_DEV_INITRD=y
 CONFIG_BLK_DEV_LOOP=m
Index: oldkernel/linux/arch/sparc64/kernel/entry.S
diff -u linux/arch/sparc64/kernel/entry.S:1.1.1.1 linux/arch/sparc64/kernel/entry.S:1.2
--- linux/arch/sparc64/kernel/entry.S:1.1.1.1	Wed May 31 12:33:53 2000
+++ linux/arch/sparc64/kernel/entry.S	Fri Jul  7 15:36:42 2000
@@ -945,7 +945,17 @@
 		 nop
 		ldx		[%g6 + AOFF_task_tss + AOFF_thread_pcr_reg], %o7
 		wr		%g0, %o7, %pcr
-		wr		%g0, %g0, %pic
+
+		/* Blackbird errata workaround.  See commentary in
+		 * smp.c:smp_percpu_timer_interrupt() for more
+		 * information.
+		 */
+		ba,pt		%xcc, 99f
+		 nop
+		.align		64
+99:		wr		%g0, %g0, %pic
+		rd		%pic, %g0
+
 1:		b,pt		%xcc, ret_sys_call
 		 ldx		[%sp + STACK_BIAS + REGWIN_SZ + PT_V9_I0], %o0
 sparc_exit:	rdpr		%otherwin, %g1
Index: oldkernel/linux/arch/sparc64/kernel/head.S
diff -u linux/arch/sparc64/kernel/head.S:1.1.1.1 linux/arch/sparc64/kernel/head.S:1.2
--- linux/arch/sparc64/kernel/head.S:1.1.1.1	Wed May 31 12:33:53 2000
+++ linux/arch/sparc64/kernel/head.S	Fri Jul  7 15:36:42 2000
@@ -262,7 +262,16 @@
 
 	/* Setup "Linux Current Register", thanks Sun 8-) */
 	wr	%g0, 0x1, %pcr
-	wr	%g6, 0x0, %pic
+
+	/* Blackbird errata workaround.  See commentary in
+	 * smp.c:smp_percpu_timer_interrupt() for more
+	 * information.
+	 */
+	ba,pt	%xcc, 99f
+	 nop
+	.align	64
+99:	wr	%g6, %g0, %pic
+	rd	%pic, %g0
 #endif
 
 	mov	1, %g5
Index: oldkernel/linux/arch/sparc64/kernel/irq.c
diff -u linux/arch/sparc64/kernel/irq.c:1.1.1.1 linux/arch/sparc64/kernel/irq.c:1.2
--- linux/arch/sparc64/kernel/irq.c:1.1.1.1	Wed May 31 12:33:53 2000
+++ linux/arch/sparc64/kernel/irq.c	Fri Jul  7 15:36:42 2000
@@ -1230,7 +1230,7 @@
 void init_timers(void (*cfunc)(int, void *, struct pt_regs *),
 		 unsigned long *clock)
 {
-	unsigned long flags;
+	unsigned long pstate;
 	extern unsigned long timer_tick_offset;
 	int node, err;
 #ifdef __SMP__
@@ -1253,31 +1253,57 @@
 		prom_halt();
 	}
 
-	save_and_cli(flags);
+	/* Guarentee that the following sequences execute
+	 * uninterrupted.
+	 */
+	__asm__ __volatile__("rdpr	%%pstate, %0\n\t"
+			     "wrpr	%0, %1, %%pstate"
+			     : "=r" (pstate)
+			     : "i" (PSTATE_IE));
 
 	/* Set things up so user can access tick register for profiling
-	 * purposes.
+	 * purposes.  Also workaround BB_ERRATA_1 by doing a dummy
+	 * read back of %tick after writing it.
 	 */
 	__asm__ __volatile__("
 		sethi	%%hi(0x80000000), %%g1
-		sllx	%%g1, 32, %%g1
-		rd	%%tick, %%g2
+		ba,pt	%%xcc, 1f
+		 sllx	%%g1, 32, %%g1
+		.align	64
+	1:	rd	%%tick, %%g2
 		add	%%g2, 6, %%g2
 		andn	%%g2, %%g1, %%g2
 		wrpr	%%g2, 0, %%tick
-"	: /* no outputs */
+		rdpr	%%tick, %%g0"
+	: /* no outputs */
 	: /* no inputs */
 	: "g1", "g2");
 
+	/* Workaround for Spitfire Errata (#54 I think??), I discovered
+	 * this via Sun BugID 4008234, mentioned in Solaris-2.5.1 patch
+	 * number 103640.
+	 *
+	 * On Blackbird writes to %tick_cmpr can fail, the
+	 * workaround seems to be to execute the wr instruction
+	 * at the start of an I-cache line, and perform a dummy
+	 * read back from %tick_cmpr right after writing to it. -DaveM
+	 */
 	__asm__ __volatile__("
 		rd	%%tick, %%g1
-		add	%%g1, %0, %%g1
-		wr	%%g1, 0x0, %%tick_cmpr"
+		ba,pt	%%xcc, 1f
+		 add	%%g1, %0, %%g1
+		.align	64
+	1:	wr	%%g1, 0x0, %%tick_cmpr
+		rd	%%tick_cmpr, %%g0"
 	: /* no outputs */
 	: "r" (timer_tick_offset)
 	: "g1");
+
+	/* Restore PSTATE_IE. */
+	__asm__ __volatile__("wrpr	%0, 0x0, %%pstate"
+			     : /* no outputs */
+			     : "r" (pstate));
 
-	restore_flags(flags);
 	sti();
 }
 
Index: oldkernel/linux/arch/sparc64/kernel/ptrace.c
diff -u linux/arch/sparc64/kernel/ptrace.c:1.1.1.1 linux/arch/sparc64/kernel/ptrace.c:1.2
--- linux/arch/sparc64/kernel/ptrace.c:1.1.1.1	Wed May 31 12:33:53 2000
+++ linux/arch/sparc64/kernel/ptrace.c	Fri Jul  7 15:36:42 2000
@@ -120,16 +120,14 @@
 
 static __inline__ void write_user_long(unsigned long kvaddr, unsigned long val)
 {
-	__asm__ __volatile__("stxa %0, [%1] %2"
-			     : /* no outputs */
-			     : "r" (val), "r" (__pa(kvaddr)), "i" (ASI_PHYS_USE_EC));
+	*(unsigned long *)kvaddr = val;
+	flush_dcache_page(kvaddr & PAGE_MASK);
 }
 
 static __inline__ void write_user_int(unsigned long kvaddr, unsigned int val)
 {
-	__asm__ __volatile__("stwa %0, [%1] %2"
-			     : /* no outputs */
-			     : "r" (val), "r" (__pa(kvaddr)), "i" (ASI_PHYS_USE_EC));
+	*(unsigned int *)kvaddr = val;
+	flush_dcache_page(kvaddr & PAGE_MASK);
 }
 
 static inline unsigned long get_long(struct task_struct * tsk,
@@ -164,11 +162,6 @@
 
 		pgaddr = page + (addr & ~PAGE_MASK);
 		write_user_long(pgaddr, data);
-
-		__asm__ __volatile__("
-		membar	#StoreStore
-		flush	%0
-"		: : "r" (pgaddr & ~7) : "memory");
 	}
 /* we're bypassing pagetables, so we have to set the dirty bit ourselves */
 /* this should also re-instate whatever read-only mode there was before */
@@ -209,11 +202,6 @@
 
 		pgaddr = page + (addr & ~PAGE_MASK);
 		write_user_int(pgaddr, data);
-
-		__asm__ __volatile__("
-		membar	#StoreStore
-		flush	%0
-"		: : "r" (pgaddr & ~7) : "memory");
 	}
 /* we're bypassing pagetables, so we have to set the dirty bit ourselves */
 /* this should also re-instate whatever read-only mode there was before */
Index: oldkernel/linux/arch/sparc64/kernel/setup.c
diff -u linux/arch/sparc64/kernel/setup.c:1.1.1.1 linux/arch/sparc64/kernel/setup.c:1.2
--- linux/arch/sparc64/kernel/setup.c:1.1.1.1	Wed May 31 12:33:53 2000
+++ linux/arch/sparc64/kernel/setup.c	Fri Jul  7 15:36:42 2000
@@ -160,9 +160,17 @@
 		}
 
 		if ((va >= KERNBASE) && (va < (KERNBASE + (4 * 1024 * 1024)))) {
+			/* Spitfire Errata #32 workaround */
+			__asm__ __volatile__("stxa	%0, [%1] %2\n\t"
+					     "flush	%%g6"
+					     : /* No outputs */
+					     : "r" (0),
+					     "r" (PRIMARY_CONTEXT), "i" (ASI_DMMU));
+
 			/*
 			 * Locked down tlb entry 63.
 			 */
+
 			tte = spitfire_get_dtlb_data(63);
 			res = PROM_TRUE;
 			goto done;
Index: oldkernel/linux/arch/sparc64/kernel/smp.c
diff -u linux/arch/sparc64/kernel/smp.c:1.1.1.1 linux/arch/sparc64/kernel/smp.c:1.2
--- linux/arch/sparc64/kernel/smp.c:1.1.1.1	Wed May 31 12:33:53 2000
+++ linux/arch/sparc64/kernel/smp.c	Fri Jul  7 15:36:42 2000
@@ -119,6 +119,7 @@
 __initfunc(void smp_callin(void))
 {
 	int cpuid = hard_smp_processor_id();
+	unsigned long pstate;
 
 	inherit_locked_prom_mappings(0);
 
@@ -127,18 +128,37 @@
 
 	cpu_probe();
 
-	/* Master did this already, now is the time for us to do it. */
+	/* Guarentee that the following sequences execute
+	 * uninterrupted.
+	 */
+	__asm__ __volatile__("rdpr	%%pstate, %0\n\t"
+			     "wrpr	%0, %1, %%pstate"
+			     : "=r" (pstate)
+			     : "i" (PSTATE_IE));
+
+	/* Set things up so user can access tick register for profiling
+	 * purposes.  Also workaround BB_ERRATA_1 by doing a dummy
+	 * read back of %tick after writing it.
+	 */
 	__asm__ __volatile__("
 	sethi	%%hi(0x80000000), %%g1
-	sllx	%%g1, 32, %%g1
-	rd	%%tick, %%g2
+	ba,pt	%%xcc, 1f
+	 sllx	%%g1, 32, %%g1
+	.align	64
+1:	rd	%%tick, %%g2
 	add	%%g2, 6, %%g2
 	andn	%%g2, %%g1, %%g2
 	wrpr	%%g2, 0, %%tick
-"	: /* no outputs */
+	rdpr	%%tick, %%g0"
+	: /* no outputs */
 	: /* no inputs */
 	: "g1", "g2");
 
+	/* Restore PSTATE_IE. */
+	__asm__ __volatile__("wrpr	%0, 0x0, %%pstate"
+			     : /* no outputs */
+			     : "r" (pstate));
+
 	smp_setup_percpu_timer();
 
 	__sti();
@@ -280,6 +300,13 @@
 	       smp_processor_id(), data0, data1, data2, target);
 #endif
 again:
+	/* Ok, this is the real Spitfire Errata #54.
+	 * One must read back from a UDB internal register
+	 * after writes to the UDB interrupt dispatch, but
+	 * before the membar Sync for that write.
+	 * So we use the high UDB control register (ASI 0x7f,
+	 * ADDR 0x20) for the dummy read. -DaveM
+	 */
 	__asm__ __volatile__("
 	wrpr	%0, %1, %%pstate
 	wr	%%g0, %2, %%asi
@@ -288,10 +315,14 @@
 	stxa	%5, [0x60] %%asi
 	membar	#Sync
 	stxa	%%g0, [%6] %%asi
+	membar	#Sync
+	mov	0x20, %%g1
+	ldxa	[%%g1] 0x7f, %%g0
 	membar	#Sync"
 	: /* No outputs */
 	: "r" (pstate), "i" (PSTATE_IE), "i" (ASI_UDB_INTR_W),
-	  "r" (data0), "r" (data1), "r" (data2), "r" (target));
+	  "r" (data0), "r" (data1), "r" (data2), "r" (target)
+	: "g1");
 
 	/* NOTE: PSTATE_IE is still clear. */
 	stuck = 100000;
@@ -589,7 +620,7 @@
 
 void smp_percpu_timer_interrupt(struct pt_regs *regs)
 {
-	unsigned long compare, tick;
+	unsigned long compare, tick, pstate;
 	int cpu = smp_processor_id();
 	int user = user_mode(regs);
 
@@ -655,27 +686,87 @@
 			prof_counter(cpu) = prof_multiplier(cpu);
 		}
 
+		/* Guarentee that the following sequences execute
+		 * uninterrupted.
+		 */
+		__asm__ __volatile__("rdpr	%%pstate, %0\n\t"
+				     "wrpr	%0, %1, %%pstate"
+				     : "=r" (pstate)
+				     : "i" (PSTATE_IE));
+
+		/* Workaround for Spitfire Errata (#54 I think??), I discovered
+		 * this via Sun BugID 4008234, mentioned in Solaris-2.5.1 patch
+		 * number 103640.
+		 *
+		 * On Blackbird writes to %tick_cmpr can fail, the
+		 * workaround seems to be to execute the wr instruction
+		 * at the start of an I-cache line, and perform a dummy
+		 * read back from %tick_cmpr right after writing to it. -DaveM
+		 *
+		 * Just to be anal we add a workaround for Spitfire
+		 * Errata 50 by preventing pipeline bypasses on the
+		 * final read of the %tick register into a compare
+		 * instruction.  The Errata 50 description states
+		 * that %tick is not prone to this bug, but I am not
+		 * taking any chances.
+		 */
 		__asm__ __volatile__("rd	%%tick_cmpr, %0\n\t"
-				     "add	%0, %2, %0\n\t"
-				     "wr	%0, 0x0, %%tick_cmpr\n\t"
-				     "rd	%%tick, %1"
+				     "ba,pt	%%xcc, 1f\n\t"
+				     " add	%0, %2, %0\n\t"
+				     ".align	64\n"
+				  "1: wr	%0, 0x0, %%tick_cmpr\n\t"
+				     "rd	%%tick_cmpr, %%g0\n\t"
+				     "rd	%%tick, %1\n\t"
+				     "mov	%1, %1"
 				     : "=&r" (compare), "=r" (tick)
 				     : "r" (current_tick_offset));
+
+		/* Restore PSTATE_IE. */
+		__asm__ __volatile__("wrpr	%0, 0x0, %%pstate"
+				     : /* no outputs */
+				     : "r" (pstate));
 	} while (tick >= compare);
 }
 
 __initfunc(static void smp_setup_percpu_timer(void))
 {
 	int cpu = smp_processor_id();
+	unsigned long pstate;
 
 	prof_counter(cpu) = prof_multiplier(cpu) = 1;
+
+	/* Guarentee that the following sequences execute
+	 * uninterrupted.
+	 */
+	__asm__ __volatile__("rdpr	%%pstate, %0\n\t"
+			     "wrpr	%0, %1, %%pstate"
+			     : "=r" (pstate)
+			     : "i" (PSTATE_IE));
+
+	/* Workaround for Spitfire Errata (#54 I think??), I discovered
+	 * this via Sun BugID 4008234, mentioned in Solaris-2.5.1 patch
+	 * number 103640.
+	 *
+	 * On Blackbird writes to %tick_cmpr can fail, the
+	 * workaround seems to be to execute the wr instruction
+	 * at the start of an I-cache line, and perform a dummy
+	 * read back from %tick_cmpr right after writing to it. -DaveM
+	 */
+	__asm__ __volatile__("
+		rd	%%tick, %%g1
+		ba,pt	%%xcc, 1f
+		 add	%%g1, %0, %%g1
+		.align	64
+	1:	wr	%%g1, 0x0, %%tick_cmpr
+		rd	%%tick_cmpr, %%g0"
+	: /* no outputs */
+	: "r" (current_tick_offset)
+	: "g1");
 
-	__asm__ __volatile__("rd	%%tick, %%g1\n\t"
-			     "add	%%g1, %0, %%g1\n\t"
-			     "wr	%%g1, 0x0, %%tick_cmpr"
+	/* Restore PSTATE_IE. */
+	__asm__ __volatile__("wrpr	%0, 0x0, %%pstate"
 			     : /* no outputs */
-			     : "r" (current_tick_offset)
-			     : "g1");
+			     : "r" (pstate));
 }
 
 __initfunc(void smp_tick_init(void))
Index: oldkernel/linux/arch/sparc64/kernel/sparc64_ksyms.c
diff -u linux/arch/sparc64/kernel/sparc64_ksyms.c:1.3 linux/arch/sparc64/kernel/sparc64_ksyms.c:1.4
--- linux/arch/sparc64/kernel/sparc64_ksyms.c:1.3	Thu Jun  1 15:03:08 2000
+++ linux/arch/sparc64/kernel/sparc64_ksyms.c	Fri Jul  7 15:36:42 2000
@@ -82,7 +82,6 @@
 extern int sys32_ioctl(unsigned int fd, unsigned int cmd, u32 arg);
 extern int (*handle_mathemu)(struct pt_regs *, struct fpustate *);
 extern void VISenter(void);
-extern long sparc32_open(const char * filename, int flags, int mode);
                 
 extern void bcopy (const char *, char *, int);
 extern int __ashrdi3(int, int);
@@ -164,6 +163,8 @@
 
 EXPORT_SYMBOL_PRIVATE(flushw_user);
 
+EXPORT_SYMBOL(flush_dcache_page);
+
 EXPORT_SYMBOL(mstk48t02_regs);
 EXPORT_SYMBOL(request_fast_irq);
 EXPORT_SYMBOL(sparc_alloc_io);
@@ -267,7 +268,6 @@
 EXPORT_SYMBOL(prom_cpu_nodes);
 EXPORT_SYMBOL(sys_ioctl);
 EXPORT_SYMBOL(sys32_ioctl);
-EXPORT_SYMBOL(sparc32_open);
 EXPORT_SYMBOL(move_addr_to_kernel);
 EXPORT_SYMBOL(move_addr_to_user);
 #endif
Index: oldkernel/linux/arch/sparc64/kernel/sys32.S
diff -u linux/arch/sparc64/kernel/sys32.S:1.3 linux/arch/sparc64/kernel/sys32.S:1.4
--- linux/arch/sparc64/kernel/sys32.S:1.3	Thu Jun  1 15:44:43 2000
+++ linux/arch/sparc64/kernel/sys32.S	Fri Jul  7 15:36:42 2000
@@ -1,4 +1,4 @@
-/* $Id: sys32.S,v 1.9 1999/12/21 14:09:18 jj Exp $
+/* $Id: sys32.S,v 1.8.2.1 2000/01/24 11:36:55 jj Exp $
  * sys32.S: I-cache tricks for 32-bit compatability layer simple
  *          conversions.
  *
@@ -60,12 +60,3 @@
 	sethi		%hi(sys_bdflush), %g1
 	jmpl		%g1 + %lo(sys_bdflush), %g0
 	 sra		%o1, 0, %o1
-
-	.align		32
-	.globl		sys32_mmap2
-sys32_mmap2:
-	srl		%o4, 0, %o4
-	sethi		%hi(sys_mmap), %g1
-	srl		%o5, 0, %o5
-	jmpl		%g1 + %lo(sys_mmap), %g0
-	 sllx		%o5, 12, %o5
Index: oldkernel/linux/arch/sparc64/kernel/sys_sparc.c
diff -u linux/arch/sparc64/kernel/sys_sparc.c:1.1.1.1 linux/arch/sparc64/kernel/sys_sparc.c:1.2
--- linux/arch/sparc64/kernel/sys_sparc.c:1.1.1.1	Wed May 31 12:33:53 2000
+++ linux/arch/sparc64/kernel/sys_sparc.c	Fri Jul  7 15:36:42 2000
@@ -214,6 +214,13 @@
 	return -ENOSYS;
 }
 
+/* We don't want to warn about LFS syscalls which are defined in our headers */
+asmlinkage unsigned long
+sys_lfs_syscall (void)
+{
+	return -ENOSYS;
+}
+
 /* #define DEBUG_SPARC_BREAKPOINT */
 
 asmlinkage void
Index: oldkernel/linux/arch/sparc64/kernel/sys_sparc32.c
diff -u linux/arch/sparc64/kernel/sys_sparc32.c:1.3 linux/arch/sparc64/kernel/sys_sparc32.c:1.4
--- linux/arch/sparc64/kernel/sys_sparc32.c:1.3	Thu Jun  1 15:44:43 2000
+++ linux/arch/sparc64/kernel/sys_sparc32.c	Fri Jul  7 15:36:42 2000
@@ -579,30 +579,6 @@
 	return err;
 }
 
-static inline int get_flock64(struct flock *kfl, struct flock32_64 *ufl)
-{
-	int err;
-	
-	err = get_user(kfl->l_type, &ufl->l_type);
-	err |= __get_user(kfl->l_whence, &ufl->l_whence);
-	err |= __get_user(kfl->l_start, &ufl->l_start);
-	err |= __get_user(kfl->l_len, &ufl->l_len);
-	err |= __get_user(kfl->l_pid, &ufl->l_pid);
-	return err;
-}
-
-static inline int put_flock64(struct flock *kfl, struct flock32_64 *ufl)
-{
-	int err;
-	
-	err = __put_user(kfl->l_type, &ufl->l_type);
-	err |= __put_user(kfl->l_whence, &ufl->l_whence);
-	err |= __put_user(kfl->l_start, &ufl->l_start);
-	err |= __put_user(kfl->l_len, &ufl->l_len);
-	err |= __put_user(kfl->l_pid, &ufl->l_pid);
-	return err;
-}
-
 extern asmlinkage long sys_fcntl(unsigned int fd, unsigned int cmd, unsigned long arg);
 
 asmlinkage long sys32_fcntl(unsigned int fd, unsigned int cmd, unsigned long arg)
@@ -621,31 +597,10 @@
 			old_fs = get_fs(); set_fs (KERNEL_DS);
 			ret = sys_fcntl(fd, cmd, (unsigned long)&f);
 			set_fs (old_fs);
-			if (f.l_start >= 0x7fffffffUL ||
-			    f.l_len >= 0x7fffffffUL ||
-			    f.l_start + f.l_len >= 0x7fffffffUL)
-				return -EOVERFLOW;
 			if(put_flock(&f, (struct flock32 *)arg))
 				return -EFAULT;
 			return ret;
 		}
-	case F_GETLK64:
-	case F_SETLK64:
-	case F_SETLKW64:
-		{
-			struct flock f;
-			mm_segment_t old_fs;
-			long ret;
-			
-			if(get_flock64(&f, (struct flock32_64 *)arg))
-				return -EFAULT;
-			old_fs = get_fs(); set_fs (KERNEL_DS);
-			ret = sys_fcntl(fd, cmd + F_GETLK - F_GETLK64, (unsigned long)&f);
-			set_fs (old_fs);
-			if(put_flock64(&f, (struct flock32_64 *)arg))
-				return -EFAULT;
-			return ret;
-		}
 	default:
 		return sys_fcntl(fd, cmd, (unsigned long)arg);
 	}
@@ -762,25 +717,6 @@
 	return ret;
 }
 
-extern asmlinkage long sys_truncate(const char * path, unsigned long length);
-extern asmlinkage long sys_ftruncate(unsigned int fd, unsigned long length);
-
-asmlinkage int sys32_truncate64(const char * path, unsigned long high, unsigned long low)
-{
-	if ((int)high < 0)
-		return -EINVAL;
-	else
-		return sys_truncate(path, (high << 32) | low);
-}
-
-asmlinkage int sys32_ftruncate64(unsigned int fd, unsigned long high, unsigned long low)
-{
-	if ((int)high < 0)
-		return -EINVAL;
-	else
-		return sys_ftruncate(fd, (high << 32) | low);
-}
-
 extern asmlinkage int sys_utime(char * filename, struct utimbuf * times);
 
 struct utimbuf32 {
@@ -3752,6 +3688,10 @@
 	case NFSCTL_GETFH:
 		err = nfs_getfh32_trans(karg, arg32);
 		break;
+	case NFSCTL_LOCKD:
+		/* No arguments, no translations... */
+		err = 0;
+		break;
 	default:
 		err = -EINVAL;
 		break;
@@ -4078,37 +4018,4 @@
 		ret = -EFAULT;
 
 	return ret;
-}
-
-/* This is just a version for 32-bit applications which does
- * not force O_LARGEFILE on.
- */
-
-asmlinkage long sparc32_open(const char * filename, int flags, int mode)
-{
-	char * tmp;
-	int fd, error;
-
-	tmp = getname(filename);
-	fd = PTR_ERR(tmp);
-	if (!IS_ERR(tmp)) {
-		lock_kernel();
-		fd = get_unused_fd();
-		if (fd >= 0) {
-			struct file * f = filp_open(tmp, flags, mode);
-			error = PTR_ERR(f);
-			if (IS_ERR(f))
-				goto out_error;
-			fd_install(fd, f);
-		}
-out:
-		unlock_kernel();
-		putname(tmp);
-	}
-	return fd;
-
-out_error:
-	put_unused_fd(fd);
-	fd = error;
-	goto out;
 }
Index: oldkernel/linux/arch/sparc64/kernel/sys_sunos32.c
diff -u linux/arch/sparc64/kernel/sys_sunos32.c:1.3 linux/arch/sparc64/kernel/sys_sunos32.c:1.4
--- linux/arch/sparc64/kernel/sys_sunos32.c:1.3	Thu Jun  1 15:44:43 2000
+++ linux/arch/sparc64/kernel/sys_sunos32.c	Fri Jul  7 15:36:42 2000
@@ -1296,15 +1296,13 @@
 	return rval;
 }
 
-extern asmlinkage long sparc32_open(const char * filename, int flags, int mode);
-
 asmlinkage int sunos_open(u32 filename, int flags, int mode)
 {
 	int ret;
 
 	lock_kernel();
 	current->personality |= PER_BSD;
-	ret = sparc32_open ((char *)A(filename), flags, mode);
+	ret = sys_open ((char *)A(filename), flags, mode);
 	unlock_kernel();
 	return ret;
 }
Index: oldkernel/linux/arch/sparc64/kernel/systbls.S
diff -u linux/arch/sparc64/kernel/systbls.S:1.3 linux/arch/sparc64/kernel/systbls.S:1.4
--- linux/arch/sparc64/kernel/systbls.S:1.3	Thu Jun  1 15:44:43 2000
+++ linux/arch/sparc64/kernel/systbls.S	Fri Jul  7 15:36:42 2000
@@ -1,4 +1,4 @@
-/* $Id: systbls.S,v 1.62 2000/01/04 23:54:43 davem Exp $
+/* $Id: systbls.S,v 1.53.2.3 2000/01/24 22:14:40 davem Exp $
  * systbls.S: System call entry point tables for OS compatibility.
  *            The native Linux system call table lives here also.
  *
@@ -20,9 +20,9 @@
 	.globl sys_call_table32
 sys_call_table32:
 /*0*/	.word sys_nis_syscall, sparc_exit, sys_fork, sys_read, sys_write
-/*5*/	.word sparc32_open, sys_close, sys32_wait4, sys_creat, sys_link
-/*10*/  .word sys_unlink, sunos_execv, sys_chdir, sys32_chown, sys32_mknod
-/*15*/	.word sys32_chmod, sys32_lchown, sparc_brk, sys_perfctr, sys32_lseek
+/*5*/	.word sys_open, sys_close, sys32_wait4, sys_creat, sys_link
+/*10*/  .word sys_unlink, sunos_execv, sys_chdir, sys32_chown16, sys32_mknod
+/*15*/	.word sys32_chmod, sys32_lchown16, sparc_brk, sys_perfctr, sys32_lseek
 /*20*/	.word sys_getpid, sys_capget, sys_capset, sys_setuid, sys_getuid
 /*25*/	.word sys_time, sys_ptrace, sys_alarm, sys32_sigaltstack, sys32_pause
 /*30*/	.word sys32_utime, sys_nis_syscall, sys_nis_syscall, sys_access, sys_nice
@@ -30,12 +30,12 @@
 /*40*/	.word sys32_newlstat, sys_dup, sys_pipe, sys32_times, sys_nis_syscall
 	.word sys_umount, sys_setgid, sys_getgid, sys_signal, sys_geteuid
 /*50*/	.word sys_getegid, sys_acct, sys_nis_syscall, sys_nis_syscall, sys32_ioctl
-	.word sys_reboot, sys32_mmap2, sys_symlink, sys_readlink, sys32_execve
-/*60*/	.word sys_umask, sys_chroot, sys32_newfstat, sys_fstat64, sys_getpagesize
+	.word sys_reboot, sys_lfs_syscall, sys_symlink, sys_readlink, sys32_execve
+/*60*/	.word sys_umask, sys_chroot, sys32_newfstat, sys_lfs_syscall, sys_getpagesize
 	.word sys_msync, sys_vfork, sys32_pread, sys32_pwrite, sys_nis_syscall
 /*70*/	.word sys_nis_syscall, sys32_mmap, sys_nis_syscall, sys_munmap, sys_mprotect
-	.word sys_nis_syscall, sys_vhangup, sys32_truncate64, sys_nis_syscall, sys32_getgroups
-/*80*/	.word sys32_setgroups, sys_getpgrp, sys_nis_syscall, sys32_setitimer, sys32_ftruncate64
+	.word sys_nis_syscall, sys_vhangup, sys_lfs_syscall, sys_nis_syscall, sys32_getgroups
+/*80*/	.word sys32_setgroups, sys_getpgrp, sys_nis_syscall, sys32_setitimer, sys_lfs_syscall
 	.word sys_swapon, sys32_getitimer, sys_nis_syscall, sys_sethostname, sys_nis_syscall
 /*90*/	.word sys_dup2, sys_nis_syscall, sys32_fcntl, sys32_select, sys_nis_syscall
 	.word sys_fsync, sys_setpriority, sys_nis_syscall, sys_nis_syscall, sys_nis_syscall
@@ -45,8 +45,8 @@
 	.word sys_nis_syscall, sys32_gettimeofday, sys32_getrusage, sys_nis_syscall, sys_getcwd
 /*120*/	.word sys32_readv, sys32_writev, sys32_settimeofday, sys32_fchown16, sys_fchmod
 	.word sys_nis_syscall, sys32_setreuid, sys32_setregid, sys_rename, sys_truncate
-/*130*/	.word sys_ftruncate, sys_flock, sys_lstat64, sys_nis_syscall, sys_nis_syscall
-	.word sys_nis_syscall, sys_mkdir, sys_rmdir, sys32_utimes, sys_stat64
+/*130*/	.word sys_ftruncate, sys_flock, sys_lfs_syscall, sys_nis_syscall, sys_nis_syscall
+	.word sys_nis_syscall, sys_mkdir, sys_rmdir, sys32_utimes, sys_lfs_syscall
 /*140*/	.word sys_nis_syscall, sys_nis_syscall, sys_nis_syscall, sys_nis_syscall, sys32_getrlimit
 	.word sys32_setrlimit, sys_nis_syscall, sys32_prctl, sys32_pciconfig_read, sys32_pciconfig_write
 /*150*/	.word sys_nis_syscall, sys_nis_syscall, sys_nis_syscall, sys_poll, sys_nis_syscall
@@ -114,15 +114,15 @@
 	.word sys_quotactl, sys_nis_syscall, sys_mount, sys_ustat, sys_nis_syscall
 /*170*/	.word sys_nis_syscall, sys_nis_syscall, sys_nis_syscall, sys_nis_syscall, sys_getdents
 	.word sys_setsid, sys_fchdir, sys_nis_syscall, sys_nis_syscall, sys_nis_syscall
-/*180*/	.word sys_nis_syscall, sys_nis_syscall, sys_nis_syscall, sys_nis_syscall, sys_query_module
+/*180*/	.word sys_nis_syscall, sys_nis_syscall, sys_nis_syscall, sys_sigpending, sys_query_module
 	.word sys_setpgid, sys_nis_syscall, sys_nis_syscall, sys_nis_syscall, sys_newuname
 /*190*/	.word sys_init_module, sys_personality, sys_nis_syscall, sys_nis_syscall, sys_nis_syscall
-	.word sys_nis_syscall, sys_nis_syscall, sys_getppid, sys_nis_syscall, sys_sgetmask
-/*200*/	.word sys_ssetmask, sys_nis_syscall, sys_newlstat, sys_uselib, sys_nis_syscall
+	.word sys_nis_syscall, sys_nis_syscall, sys_getppid, sys_sigaction, sys_sgetmask
+/*200*/	.word sys_ssetmask, sys_sigsuspend, sys_newlstat, sys_uselib, sys_nis_syscall
 	.word sys_nis_syscall, sys_socketcall, sys_syslog, sys_nis_syscall, sys_nis_syscall
 /*210*/	.word sys_idle, sys_nis_syscall, sys_waitpid, sys_swapoff, sys_sysinfo
-	.word sys_ipc, sys_nis_syscall, sys_clone, sys_nis_syscall, sys_adjtimex
-/*220*/	.word sys_nis_syscall, sys_create_module, sys_delete_module, sys_get_kernel_syms, sys_getpgid
+	.word sys_ipc, sys_sigreturn, sys_clone, sys_nis_syscall, sys_adjtimex
+/*220*/	.word sys_sigprocmask, sys_create_module, sys_delete_module, sys_get_kernel_syms, sys_getpgid
 	.word sys_bdflush, sys_sysfs, sys_nis_syscall, sys_setfsuid, sys_setfsgid
 /*230*/	.word sys_select, sys_time, sys_nis_syscall, sys_stime, sys_nis_syscall
 	.word sys_nis_syscall, sys_llseek, sys_mlock, sys_munlock, sys_mlockall
Index: oldkernel/linux/arch/sparc64/kernel/time.c
diff -u linux/arch/sparc64/kernel/time.c:1.1.1.1 linux/arch/sparc64/kernel/time.c:1.2
--- linux/arch/sparc64/kernel/time.c:1.1.1.1	Wed May 31 12:33:53 2000
+++ linux/arch/sparc64/kernel/time.c	Fri Jul  7 15:36:42 2000
@@ -1,4 +1,4 @@
-/* $Id: time.c,v 1.20.2.1 1999/10/09 06:03:23 davem Exp $
+/* $Id: time.c,v 1.20.2.2 2000/03/02 02:03:31 davem Exp $
  * time.c: UltraSparc timer and TOD clock support.
  *
  * Copyright (C) 1997 David S. Miller (davem@caip.rutgers.edu)
@@ -69,20 +69,53 @@
 
 static void timer_interrupt(int irq, void *dev_id, struct pt_regs * regs)
 {
-	unsigned long ticks;
+	unsigned long ticks, pstate;
 
 	write_lock(&xtime_lock);
 
 	do {
 		do_timer(regs);
 
+		/* Guarentee that the following sequences execute
+		 * uninterrupted.
+		 */
+		__asm__ __volatile__("rdpr	%%pstate, %0\n\t"
+				     "wrpr	%0, %1, %%pstate"
+				     : "=r" (pstate)
+				     : "i" (PSTATE_IE));
+
+		/* Workaround for Spitfire Errata (#54 I think??), I discovered
+		 * this via Sun BugID 4008234, mentioned in Solaris-2.5.1 patch
+		 * number 103640.
+		 *
+		 * On Blackbird writes to %tick_cmpr can fail, the
+		 * workaround seems to be to execute the wr instruction
+		 * at the start of an I-cache line, and perform a dummy
+		 * read back from %tick_cmpr right after writing to it. -DaveM
+		 *
+		 * Just to be anal we add a workaround for Spitfire
+		 * Errata 50 by preventing pipeline bypasses on the
+		 * final read of the %tick register into a compare
+		 * instruction.  The Errata 50 description states
+		 * that %tick is not prone to this bug, but I am not
+		 * taking any chances.
+		 */
 		__asm__ __volatile__("
 			rd	%%tick_cmpr, %0
-			add	%0, %2, %0
-			wr	%0, 0, %%tick_cmpr
-			rd	%%tick, %1"
+			ba,pt	%%xcc, 1f
+			 add	%0, %2, %0
+			.align	64
+		     1: wr	%0, 0, %%tick_cmpr
+		        rd	%%tick_cmpr, %%g0
+			rd	%%tick, %1
+			mov	%1, %1"
 			: "=&r" (timer_tick_compare), "=r" (ticks)
 			: "r" (timer_tick_offset));
+
+		/* Restore PSTATE_IE. */
+		__asm__ __volatile__("wrpr	%0, 0x0, %%pstate"
+				     : /* no outputs */
+				     : "r" (pstate));
 	} while (ticks >= timer_tick_compare);
 
 	timer_check_rtc();
Index: oldkernel/linux/arch/sparc64/kernel/unaligned.c
diff -u linux/arch/sparc64/kernel/unaligned.c:1.1.1.1 linux/arch/sparc64/kernel/unaligned.c:1.2
--- linux/arch/sparc64/kernel/unaligned.c:1.1.1.1	Wed May 31 12:33:53 2000
+++ linux/arch/sparc64/kernel/unaligned.c	Fri Jul  7 15:36:42 2000
@@ -587,9 +587,19 @@
 	                        
 	maybe_flush_windows(0, 0, rd, from_kernel);
 	reg = fetch_reg_addr(rd, regs);
-	if ((insn & 0x780000) == 0x180000)
-		reg[1] = 0;
-	reg[0] = 0;
+	if (from_kernel || rd < 16) {
+		reg[0] = 0;
+		if ((insn & 0x780000) == 0x180000)
+			reg[1] = 0;
+	} else if (current->tss.flags & SPARC_FLAG_32BIT) {
+		put_user(0, (int *)reg);
+		if ((insn & 0x780000) == 0x180000)
+			put_user(0, ((int *)reg) + 1);
+	} else {
+		put_user(0, reg);
+		if ((insn & 0x780000) == 0x180000)
+			put_user(0, reg + 1);
+	}
 	advance(regs);
 }
 
Index: oldkernel/linux/arch/sparc64/lib/blockops.S
diff -u linux/arch/sparc64/lib/blockops.S:1.1.1.1 linux/arch/sparc64/lib/blockops.S:1.2
--- linux/arch/sparc64/lib/blockops.S:1.1.1.1	Wed May 31 12:33:53 2000
+++ linux/arch/sparc64/lib/blockops.S	Fri Jul  7 15:36:42 2000
@@ -46,13 +46,37 @@
 	sethi		%hi(TLBTEMP_ENT1), %o3
 	rdpr		%pstate, %g3
 	wrpr		%g3, PSTATE_IE, %pstate
+
+	/* Spitfire Errata #32 workaround */
+	mov		0x8, %o4
+	stxa		%g0, [%o4] ASI_DMMU
+	flush		%g6
+
 	ldxa		[%o3] ASI_DTLB_TAG_READ, %o4
+
+	/* Spitfire Errata #32 workaround */
+	mov		0x8, %o5
+	stxa		%g0, [%o5] ASI_DMMU
+	flush		%g6
+
 	ldxa		[%o3] ASI_DTLB_DATA_ACCESS, %o5
 	stxa		%o0, [%o2] ASI_DMMU
 	stxa		%g1, [%o3] ASI_DTLB_DATA_ACCESS
 	membar		#Sync
 	add		%o3, (TLBTEMP_ENTSZ), %o3
+
+	/* Spitfire Errata #32 workaround */
+	mov		0x8, %g5
+	stxa		%g0, [%g5] ASI_DMMU
+	flush		%g6
+
 	ldxa		[%o3] ASI_DTLB_TAG_READ, %g5
+
+	/* Spitfire Errata #32 workaround */
+	mov		0x8, %g7
+	stxa		%g0, [%g7] ASI_DMMU
+	flush		%g6
+
 	ldxa		[%o3] ASI_DTLB_DATA_ACCESS, %g7
 	stxa		%o1, [%o2] ASI_DMMU
 	stxa		%g2, [%o3] ASI_DTLB_DATA_ACCESS
@@ -120,7 +144,19 @@
 	sethi		%hi(TLBTEMP_ENT2), %o3
 	rdpr		%pstate, %g3
 	wrpr		%g3, PSTATE_IE, %pstate
+
+	/* Spitfire Errata #32 workaround */
+	mov		0x8, %g5
+	stxa		%g0, [%g5] ASI_DMMU
+	flush		%g6
+
 	ldxa		[%o3] ASI_DTLB_TAG_READ, %g5
+
+	/* Spitfire Errata #32 workaround */
+	mov		0x8, %g7
+	stxa		%g0, [%g7] ASI_DMMU
+	flush		%g6
+
 	ldxa		[%o3] ASI_DTLB_DATA_ACCESS, %g7
 	stxa		%o0, [%o2] ASI_DMMU
 	stxa		%g1, [%o3] ASI_DTLB_DATA_ACCESS
Index: oldkernel/linux/arch/sparc64/mm/init.c
diff -u linux/arch/sparc64/mm/init.c:1.1.1.1 linux/arch/sparc64/mm/init.c:1.2
--- linux/arch/sparc64/mm/init.c:1.1.1.1	Wed May 31 12:33:53 2000
+++ linux/arch/sparc64/mm/init.c	Fri Jul  7 15:36:42 2000
@@ -709,6 +709,14 @@
 
 	/* Now fixup OBP's idea about where we really are mapped. */
 	prom_printf("Remapping the kernel... ");
+
+	/* Spitfire Errata #32 workaround */
+	__asm__ __volatile__("stxa	%0, [%1] %2\n\t"
+			     "flush	%%g6"
+			     : /* No outputs */
+			     : "r" (0),
+			     "r" (PRIMARY_CONTEXT), "i" (ASI_DMMU));
+
 	phys_page = spitfire_get_dtlb_data(63) & _PAGE_PADDR;
 	phys_page += ((unsigned long)&prom_boot_page -
 		      (unsigned long)&empty_zero_page);
@@ -731,11 +739,27 @@
 		: "memory");
 
 	tte_vaddr = (unsigned long) &empty_zero_page;
+
+	/* Spitfire Errata #32 workaround */
+	__asm__ __volatile__("stxa	%0, [%1] %2\n\t"
+			     "flush	%%g6"
+			     : /* No outputs */
+			     : "r" (0),
+			     "r" (PRIMARY_CONTEXT), "i" (ASI_DMMU));
+
 	kern_locked_tte_data = tte_data = spitfire_get_dtlb_data(63);
 
 	remap_func = (void *)  ((unsigned long) &prom_remap -
 				(unsigned long) &prom_boot_page);
 
+
+	/* Spitfire Errata #32 workaround */
+	__asm__ __volatile__("stxa	%0, [%1] %2\n\t"
+			     "flush	%%g6"
+			     : /* No outputs */
+			     : "r" (0),
+			     "r" (PRIMARY_CONTEXT), "i" (ASI_DMMU));
+
 	remap_func(spitfire_get_dtlb_data(63) & _PAGE_PADDR,
 		   (unsigned long) &empty_zero_page,
 		   prom_get_mmu_ihandle());
@@ -798,8 +822,16 @@
 
 	/* Only DTLB must be checked for VPTE entries. */
 	for(i = 0; i < 63; i++) {
-		unsigned long tag = spitfire_get_dtlb_tag(i);
+		unsigned long tag;
+
+		/* Spitfire Errata #32 workaround */
+		__asm__ __volatile__("stxa	%0, [%1] %2\n\t"
+				     "flush	%%g6"
+				     : /* No outputs */
+				     : "r" (0),
+				     "r" (PRIMARY_CONTEXT), "i" (ASI_DMMU));
 
+		tag = spitfire_get_dtlb_tag(i);
 		if(((tag & ~(PAGE_MASK)) == 0) &&
 		   ((tag &  (PAGE_MASK)) >= prom_reserved_base)) {
 			__asm__ __volatile__("stxa %%g0, [%0] %1"
@@ -912,10 +944,26 @@
 	for(i = 0; i < 63; i++) {
 		unsigned long data;
 
+
+		/* Spitfire Errata #32 workaround */
+		__asm__ __volatile__("stxa	%0, [%1] %2\n\t"
+				     "flush	%%g6"
+				     : /* No outputs */
+				     : "r" (0),
+				     "r" (PRIMARY_CONTEXT), "i" (ASI_DMMU));
+
 		data = spitfire_get_dtlb_data(i);
 		if((data & (_PAGE_L|_PAGE_VALID)) == (_PAGE_L|_PAGE_VALID)) {
-			unsigned long tag = spitfire_get_dtlb_tag(i);
+			unsigned long tag;
 
+			/* Spitfire Errata #32 workaround */
+			__asm__ __volatile__("stxa	%0, [%1] %2\n\t"
+					     "flush	%%g6"
+					     : /* No outputs */
+					     : "r" (0),
+					     "r" (PRIMARY_CONTEXT), "i" (ASI_DMMU));
+
+			tag = spitfire_get_dtlb_tag(i);
 			if(save_p) {
 				prom_dtlb[dtlb_seen].tlb_ent = i;
 				prom_dtlb[dtlb_seen].tlb_tag = tag;
@@ -935,10 +983,25 @@
 	for(i = 0; i < 63; i++) {
 		unsigned long data;
 
+		/* Spitfire Errata #32 workaround */
+		__asm__ __volatile__("stxa	%0, [%1] %2\n\t"
+				     "flush	%%g6"
+				     : /* No outputs */
+				     : "r" (0),
+				     "r" (PRIMARY_CONTEXT), "i" (ASI_DMMU));
+
 		data = spitfire_get_itlb_data(i);
 		if((data & (_PAGE_L|_PAGE_VALID)) == (_PAGE_L|_PAGE_VALID)) {
-			unsigned long tag = spitfire_get_itlb_tag(i);
+			unsigned long tag;
 
+			/* Spitfire Errata #32 workaround */
+			__asm__ __volatile__("stxa	%0, [%1] %2\n\t"
+					     "flush	%%g6"
+					     : /* No outputs */
+					     : "r" (0),
+					     "r" (PRIMARY_CONTEXT), "i" (ASI_DMMU));
+
+			tag = spitfire_get_itlb_tag(i);
 			if(save_p) {
 				prom_itlb[itlb_seen].tlb_ent = i;
 				prom_itlb[itlb_seen].tlb_tag = tag;
@@ -989,13 +1052,11 @@
 
 void __flush_dcache_range(unsigned long start, unsigned long end)
 {
-	unsigned long va;
-	int n = 0;
-
-	for (va = start; va < end; va += 32) {
-		spitfire_put_dcache_tag(va & 0x3fe0, 0x0);
-		if (++n >= 512)
-			break;
+	start &= PAGE_MASK;
+	end = PAGE_ALIGN(end);
+	while (start < end) {
+		flush_dcache_page(start);
+		start += PAGE_SIZE;
 	}
 }
 
@@ -1020,6 +1081,13 @@
 			     : "=r" (pstate)
 			     : "i" (PSTATE_IE));
 	for(i = 0; i < 64; i++) {
+		/* Spitfire Errata #32 workaround */
+		__asm__ __volatile__("stxa	%0, [%1] %2\n\t"
+				     "flush	%%g6"
+				     : /* No outputs */
+				     : "r" (0),
+				     "r" (PRIMARY_CONTEXT), "i" (ASI_DMMU));
+
 		if(!(spitfire_get_dtlb_data(i) & _PAGE_L)) {
 			__asm__ __volatile__("stxa %%g0, [%0] %1"
 					     : /* no outputs */
@@ -1028,6 +1096,14 @@
 			spitfire_put_dtlb_data(i, 0x0UL);
 			membar("#Sync");
 		}
+
+		/* Spitfire Errata #32 workaround */
+		__asm__ __volatile__("stxa	%0, [%1] %2\n\t"
+				     "flush	%%g6"
+				     : /* No outputs */
+				     : "r" (0),
+				     "r" (PRIMARY_CONTEXT), "i" (ASI_DMMU));
+
 		if(!(spitfire_get_itlb_data(i) & _PAGE_L)) {
 			__asm__ __volatile__("stxa %%g0, [%0] %1"
 					     : /* no outputs */
Index: oldkernel/linux/arch/sparc64/mm/ultra.S
diff -u linux/arch/sparc64/mm/ultra.S:1.1.1.1 linux/arch/sparc64/mm/ultra.S:1.2
--- linux/arch/sparc64/mm/ultra.S:1.1.1.1	Wed May 31 12:33:53 2000
+++ linux/arch/sparc64/mm/ultra.S	Fri Jul  7 15:36:42 2000
@@ -35,7 +35,7 @@
 __flush_tlb_range: /* %o0=(ctx&0x3ff), %o1=start&PAGE_MASK, %o2=SECONDARY_CONTEXT,
 		    * %o3=end&PAGE_MASK, %o4=PAGE_SIZE, %o5=(end - start)
 		    */
-#define TLB_MAGIC	206 /* Students, do you know how I calculated this?  -DaveM */
+#define TLB_MAGIC	207 /* Students, do you know how I calculated this?  -DaveM */
 /*IC3*/	cmp		%o5, %o4
 	be,pt		%xcc, __flush_tlb_page
 	 srlx		%o5, 13, %g5
@@ -58,6 +58,12 @@
 	wrpr		%g1, PSTATE_IE, %pstate
 	mov		TLB_TAG_ACCESS, %g3
 	mov		(62 << 3), %g2
+
+	/* Spitfire Errata #32 workaround. */
+	mov		0x8, %o4
+	stxa		%g0, [%o4] ASI_DMMU
+	flush		%g6
+
 1:	ldxa		[%g2] ASI_ITLB_TAG_READ, %o4
 	and		%o4, 0x3ff, %o5
 	cmp		%o5, %o0
@@ -83,12 +89,27 @@
 	 wrpr		%g1, 0x0, %pstate
 4:	stxa		%g0, [%g3] ASI_IMMU
 	stxa		%g0, [%g2] ASI_ITLB_DATA_ACCESS
+	flush		%g6
+
+	/* Spitfire Errata #32 workaround. */
+	mov		0x8, %o4
+	stxa		%g0, [%o4] ASI_DMMU
+	flush		%g6
+
 	ba,pt		%xcc, 2b
-	 flush		%g6
+	 nop
+
 5:	stxa		%g0, [%g3] ASI_DMMU
 /*IC9*/	stxa		%g0, [%g2] ASI_DTLB_DATA_ACCESS
+	flush		%g6
+
+	/* Spitfire Errata #32 workaround. */
+	mov		0x8, %o4
+	stxa		%g0, [%o4] ASI_DMMU
+	flush		%g6
+
 	ba,pt		%xcc, 3b
-	 flush		%g6
+	 nop
 
 	.align		32
 __flush_tlb_mm_slow:
@@ -167,6 +188,29 @@
 	ba,pt		%xcc, 3b
 	 flush		%g6
 
+	.align		64
+	.globl		flush_dcache_page
+flush_dcache_page:
+	sub		%o0, %g4, %o0
+	clr		%o1
+	srlx		%o0, 11, %o0
+	sethi		%hi(1 << 14), %o2
+1:	ldxa		[%o1] ASI_DCACHE_TAG, %o3
+	andn		%o3, 0x3, %o3
+	cmp		%o0, %o3
+	bne,pt		%xcc, 2f
+	 nop
+	stxa		%g0, [%o1] ASI_DCACHE_TAG
+2:	add		%o1, (1 << 5), %o1
+	cmp		%o1, %o2
+	bne,pt		%xcc, 1b
+	 nop
+	/* The I-cache does not snoop local stores so we
+	 * better flush that too.
+	 */
+	ba,pt		%xcc, flush_icache_page
+	 sllx		%o0, 11, %o0
+
 #ifdef __SMP__
 	/* These are all called by the slaves of a cross call, at
 	 * trap level 1, with interrupts fully disabled.
@@ -292,28 +336,51 @@
 	 clr		%l6
 99:	retry
 
+	.data
+
+errata32_hwbug:
+	.xword	0
+
+	.text
+
 	/* These two are not performance critical... */
 	.globl		xcall_flush_tlb_all
 xcall_flush_tlb_all:
+
+	/* Spitfire Errata #32 workaround. */
+	sethi		%hi(errata32_hwbug), %g4
+	stx		%g0, [%g4 + %lo(errata32_hwbug)]
+
 	clr		%g2
 	clr		%g3
 1:	ldxa		[%g3] ASI_DTLB_DATA_ACCESS, %g4
 	and		%g4, _PAGE_L, %g5
 	brnz,pn		%g5, 2f
 	 mov		TLB_TAG_ACCESS, %g7
+
 	stxa		%g0, [%g7] ASI_DMMU
 	membar		#Sync
-
 	stxa		%g0, [%g3] ASI_DTLB_DATA_ACCESS
 	membar		#Sync
+
+	/* Spitfire Errata #32 workaround. */
+	sethi		%hi(errata32_hwbug), %g4
+	stx		%g0, [%g4 + %lo(errata32_hwbug)]
+
 2:	ldxa		[%g3] ASI_ITLB_DATA_ACCESS, %g4
 	and		%g4, _PAGE_L, %g5
 	brnz,pn		%g5, 2f
 	 mov		TLB_TAG_ACCESS, %g7
+
 	stxa		%g0, [%g7] ASI_IMMU
 	membar		#Sync
-
 	stxa		%g0, [%g3] ASI_ITLB_DATA_ACCESS
+	membar		#Sync
+
+	/* Spitfire Errata #32 workaround. */
+	sethi		%hi(errata32_hwbug), %g4
+	stx		%g0, [%g4 + %lo(errata32_hwbug)]
+
 2:	add		%g2, 1, %g2
 	cmp		%g2, 63
 	ble,pt		%icc, 1b
Index: oldkernel/linux/arch/sparc64/solaris/fs.c
diff -u linux/arch/sparc64/solaris/fs.c:1.2 linux/arch/sparc64/solaris/fs.c:1.3
--- linux/arch/sparc64/solaris/fs.c:1.2	Thu Jun  1 15:03:08 2000
+++ linux/arch/sparc64/solaris/fs.c	Fri Jul  7 15:36:42 2000
@@ -572,20 +572,20 @@
 	return error;
 }
 
-extern asmlinkage long sparc32_open(const char * filename, int flags, int mode);
-
 asmlinkage int solaris_open(u32 filename, int flags, u32 mode)
 {
+	int (*sys_open)(const char *,int,int) = 
+		(int (*)(const char *,int,int))SYS(open);
 	int fl = flags & 0xf;
 
-	if (flags & 0x2000) fl |= O_LARGEFILE;
+/*	if (flags & 0x2000) - allow LFS			*/
 	if (flags & 0x8050) fl |= O_SYNC;
 	if (flags & 0x80) fl |= O_NONBLOCK;
 	if (flags & 0x100) fl |= O_CREAT;
 	if (flags & 0x200) fl |= O_TRUNC;
 	if (flags & 0x400) fl |= O_EXCL;
 	if (flags & 0x800) fl |= O_NOCTTY;
-	return sparc32_open((const char *)A(filename), fl, mode);
+	return sys_open((const char *)A(filename), fl, mode);
 }
 
 #define SOL_F_SETLK	6
Index: oldkernel/linux/configs/kernel-2.2.14-i386-BOOT.config
diff -u linux/configs/kernel-2.2.14-i386-BOOT.config:1.5 linux/configs/kernel-2.2.14-i386-BOOT.config:1.6
--- linux/configs/kernel-2.2.14-i386-BOOT.config:1.5	Thu Jun  1 13:01:16 2000
+++ linux/configs/kernel-2.2.14-i386-BOOT.config	Fri Jul  7 15:36:42 2000
@@ -1,5 +1,5 @@
 #
-# Automatically generated by make menuconfig: don't edit
+# Automatically generated make config: don't edit
 #
 
 #
@@ -15,15 +15,14 @@
 # CONFIG_M586 is not set
 # CONFIG_M586TSC is not set
 # CONFIG_M686 is not set
-# CONFIG_M686FX is not set
-# CONFIG_X86_PN_OFF is not set
-# CONFIG_X86_FX is not set
+CONFIG_X86_PN_OFF=y
+CONFIG_X86_FX=y
 # CONFIG_X86_CPU_OPTIMIZATIONS is not set
+CONFIG_1GB=y
+# CONFIG_2GB is not set
 CONFIG_MATH_EMULATION=y
 # CONFIG_MTRR is not set
 # CONFIG_SMP is not set
-CONFIG_1GB=y
-# CONFIG_2GB is not set
 
 #
 # Loadable module support
@@ -48,7 +47,7 @@
 CONFIG_PCI_OLD_PROC=y
 # CONFIG_MCA is not set
 # CONFIG_VISWS is not set
-# CONFIG_SYSVIPC is not set
+CONFIG_SYSVIPC=y
 # CONFIG_BSD_PROCESS_ACCT is not set
 CONFIG_SYSCTL=y
 # CONFIG_BINFMT_AOUT is not set
@@ -71,6 +70,10 @@
 #
 CONFIG_BLK_DEV_FD=y
 CONFIG_BLK_DEV_IDE=y
+
+#
+# Please see Documentation/ide.txt for help/info on IDE drives
+#
 # CONFIG_BLK_DEV_HD_IDE is not set
 CONFIG_BLK_DEV_IDEDISK=y
 CONFIG_BLK_DEV_IDECD=y
@@ -90,6 +93,10 @@
 # CONFIG_BLK_DEV_VIA82C586 is not set
 # CONFIG_BLK_DEV_CMD646 is not set
 # CONFIG_IDE_CHIPSETS is not set
+
+#
+# Additional Block Devices
+#
 CONFIG_BLK_DEV_LOOP=y
 # CONFIG_BLK_DEV_NBD is not set
 # CONFIG_BLK_DEV_MD is not set
@@ -104,13 +111,22 @@
 CONFIG_BLK_DEV_INITRD=y
 # CONFIG_BLK_DEV_XD is not set
 CONFIG_BLK_DEV_DAC960=m
+CONFIG_BLK_DEV_3WARE=m
 CONFIG_PARIDE_PARPORT=m
 CONFIG_PARIDE=m
+
+#
+# Parallel IDE high-level drivers
+#
 CONFIG_PARIDE_PD=m
 CONFIG_PARIDE_PCD=m
 # CONFIG_PARIDE_PF is not set
 # CONFIG_PARIDE_PT is not set
 # CONFIG_PARIDE_PG is not set
+
+#
+# Parallel IDE protocol modules
+#
 CONFIG_PARIDE_ATEN=m
 CONFIG_PARIDE_BPCK=m
 CONFIG_PARIDE_COMM=m
@@ -145,9 +161,17 @@
 # CONFIG_NET_IPGRE is not set
 # CONFIG_IP_ALIAS is not set
 CONFIG_SYN_COOKIES=y
+
+#
+# (it is safe to leave these untouched)
+#
 # CONFIG_INET_RARP is not set
 # CONFIG_SKB_LARGE is not set
 # CONFIG_IPV6 is not set
+
+#
+#  
+#
 # CONFIG_IPX is not set
 # CONFIG_ATALK is not set
 # CONFIG_X25 is not set
@@ -175,11 +199,19 @@
 # SCSI support
 #
 CONFIG_SCSI=y
+
+#
+# SCSI support type (disk, tape, CD-ROM)
+#
 CONFIG_BLK_DEV_SD=y
 CONFIG_CHR_DEV_ST=m
 CONFIG_BLK_DEV_SR=y
 CONFIG_BLK_DEV_SR_VENDOR=y
 CONFIG_CHR_DEV_SG=m
+
+#
+# Some SCSI devices (e.g. CD jukebox) support multiple LUNs
+#
 # CONFIG_SCSI_MULTI_LUN is not set
 CONFIG_SCSI_CONSTANTS=y
 CONFIG_SCSI_LOGGING=y
@@ -193,7 +225,7 @@
 CONFIG_SCSI_AHA1542=m
 CONFIG_SCSI_AHA1740=m
 CONFIG_SCSI_AIC7XXX=m
-# CONFIG_AIC7XXX_TCQ_ON_BY_DEFAULT is not set
+CONFIG_AIC7XXX_TCQ_ON_BY_DEFAULT=y
 CONFIG_AIC7XXX_CMDS_PER_DEVICE=8
 CONFIG_AIC7XXX_PROC_STATS=y
 CONFIG_AIC7XXX_RESET_DELAY=5
@@ -238,11 +270,13 @@
 CONFIG_SCSI_SYM53C8XX=m
 CONFIG_SCSI_NCR53C8XX_DEFAULT_TAGS=8
 CONFIG_SCSI_NCR53C8XX_MAX_TAGS=32
-CONFIG_SCSI_NCR53C8XX_SYNC=40
+CONFIG_SCSI_NCR53C8XX_SYNC=80
 CONFIG_SCSI_NCR53C8XX_PROFILE=y
 # CONFIG_SCSI_NCR53C8XX_IOMAPPED is not set
 CONFIG_SCSI_NCR53C8XX_SYMBIOS_COMPAT=y
-CONFIG_SCSI_NCR53C8XX_PQS_PDS=y
+CONFIG_SCSI_NCR53C8XX_PQS_PDS=y 
+# CONFIG_SCSI_NCR53C8XX_IARB is not set 
+CONFIG_SCSI_NCR53C8XX_INTEGRITY_CHECK=y
 CONFIG_SCSI_PAS16=m
 CONFIG_SCSI_PCI2000=m
 CONFIG_SCSI_PCI2220I=m
@@ -444,6 +478,15 @@
 # CONFIG_WATCHDOG is not set
 # CONFIG_NVRAM is not set
 # CONFIG_RTC is not set
+
+#
+# I2C support
+#
+# CONFIG_I2C is not set
+
+#
+# AGP support
+#
 CONFIG_AGP=y
 CONFIG_AGP_INTEL=y
 CONFIG_AGP_I810=y
@@ -485,6 +528,8 @@
 # CONFIG_QNX4FS_FS is not set
 CONFIG_ROMFS_FS=m
 CONFIG_EXT2_FS=y
+CONFIG_EXT3_FS=m 
+CONFIG_EXT3_FS_JFS_CHECK=y
 CONFIG_SYSV_FS=m
 CONFIG_UFS_FS=m
 # CONFIG_UFS_FS_WRITE is not set
@@ -498,6 +543,8 @@
 # CONFIG_NFSD is not set
 CONFIG_SUNRPC=m
 CONFIG_LOCKD=m
+CONFIG_NFSD_V3=y 
+CONFIG_NFS_V3=y
 CONFIG_SMB_FS=m
 # CONFIG_NCP_FS is not set
 
Index: oldkernel/linux/configs/kernel-2.2.14-i386-smp.config
diff -u linux/configs/kernel-2.2.14-i386-smp.config:1.5 linux/configs/kernel-2.2.14-i386-smp.config:1.6
--- linux/configs/kernel-2.2.14-i386-smp.config:1.5	Thu Jun  1 13:01:16 2000
+++ linux/configs/kernel-2.2.14-i386-smp.config	Fri Jul  7 15:36:42 2000
@@ -1,5 +1,5 @@
 #
-# Automatically generated by make menuconfig: don't edit
+# Automatically generated make config: don't edit
 #
 
 #
@@ -15,15 +15,14 @@
 # CONFIG_M586 is not set
 # CONFIG_M586TSC is not set
 # CONFIG_M686 is not set
-# CONFIG_M686FX is not set
-# CONFIG_X86_PN_OFF is not set
-# CONFIG_X86_FX is not set
+CONFIG_X86_PN_OFF=y
+CONFIG_X86_FX=y
 # CONFIG_X86_CPU_OPTIMIZATIONS is not set
+CONFIG_1GB=y
+# CONFIG_2GB is not set
 CONFIG_MATH_EMULATION=y
 CONFIG_MTRR=y
 CONFIG_SMP=y
-CONFIG_1GB=y
-# CONFIG_2GB is not set
 
 #
 # Loadable module support
@@ -82,6 +81,10 @@
 #
 CONFIG_BLK_DEV_FD=y
 CONFIG_BLK_DEV_IDE=y
+
+#
+# Please see Documentation/ide.txt for help/info on IDE drives
+#
 # CONFIG_BLK_DEV_HD_IDE is not set
 CONFIG_BLK_DEV_IDEDISK=y
 CONFIG_BLK_DEV_IDECD=m
@@ -100,6 +103,10 @@
 # CONFIG_BLK_DEV_VIA82C586 is not set
 # CONFIG_BLK_DEV_CMD646 is not set
 # CONFIG_IDE_CHIPSETS is not set
+
+#
+# Additional Block Devices
+#
 CONFIG_BLK_DEV_LOOP=m
 CONFIG_BLK_DEV_NBD=m
 # CONFIG_BLK_DEV_MD is not set
@@ -114,13 +121,22 @@
 CONFIG_BLK_DEV_INITRD=y
 CONFIG_BLK_DEV_XD=m
 CONFIG_BLK_DEV_DAC960=y
+CONFIG_BLK_DEV_3WARE=y
 CONFIG_PARIDE_PARPORT=m
 CONFIG_PARIDE=m
+
+#
+# Parallel IDE high-level drivers
+#
 CONFIG_PARIDE_PD=m
 CONFIG_PARIDE_PCD=m
 CONFIG_PARIDE_PF=m
 CONFIG_PARIDE_PT=m
 CONFIG_PARIDE_PG=m
+
+#
+# Parallel IDE protocol modules
+#
 CONFIG_PARIDE_ATEN=m
 CONFIG_PARIDE_BPCK=m
 CONFIG_PARIDE_COMM=m
@@ -157,7 +173,16 @@
 CONFIG_NETLINK_DEV=y
 CONFIG_IP_TRANSPARENT_PROXY=y
 CONFIG_IP_MASQUERADE=y
+
+#
+# Protocol-specific masquerading support will be built as modules.
+#
+# CONFIG_IP_MASQUERADE_UDP_LOOSE is not set
 CONFIG_IP_MASQUERADE_ICMP=y
+
+#
+# Protocol-specific masquerading support will be built as modules.
+#
 CONFIG_IP_MASQUERADE_MOD=y
 CONFIG_IP_MASQUERADE_IPAUTOFW=m
 CONFIG_IP_MASQUERADE_IPPORTFW=m
@@ -176,9 +201,17 @@
 CONFIG_IP_ALIAS=y
 # CONFIG_ARPD is not set
 CONFIG_SYN_COOKIES=y
+
+#
+# (it is safe to leave these untouched)
+#
 CONFIG_INET_RARP=m
 CONFIG_SKB_LARGE=y
 # CONFIG_IPV6 is not set
+
+#
+#  
+#
 CONFIG_IPX=m
 # CONFIG_IPX_INTERN is not set
 # CONFIG_SPX is not set
@@ -208,11 +241,19 @@
 # SCSI support
 #
 CONFIG_SCSI=y
+
+#
+# SCSI support type (disk, tape, CD-ROM)
+#
 CONFIG_BLK_DEV_SD=y
 CONFIG_CHR_DEV_ST=y
 CONFIG_BLK_DEV_SR=y
 CONFIG_BLK_DEV_SR_VENDOR=y
 CONFIG_CHR_DEV_SG=m
+
+#
+# Some SCSI devices (e.g. CD jukebox) support multiple LUNs
+#
 # CONFIG_SCSI_MULTI_LUN is not set
 CONFIG_SCSI_CONSTANTS=y
 CONFIG_SCSI_LOGGING=y
@@ -226,7 +267,7 @@
 CONFIG_SCSI_AHA1542=m
 CONFIG_SCSI_AHA1740=m
 CONFIG_SCSI_AIC7XXX=y
-# CONFIG_AIC7XXX_TCQ_ON_BY_DEFAULT is not set
+CONFIG_AIC7XXX_TCQ_ON_BY_DEFAULT=y
 CONFIG_AIC7XXX_CMDS_PER_DEVICE=8
 CONFIG_AIC7XXX_PROC_STATS=y
 CONFIG_AIC7XXX_RESET_DELAY=5
@@ -271,11 +312,13 @@
 CONFIG_SCSI_SYM53C8XX=y
 CONFIG_SCSI_NCR53C8XX_DEFAULT_TAGS=8
 CONFIG_SCSI_NCR53C8XX_MAX_TAGS=32
-CONFIG_SCSI_NCR53C8XX_SYNC=40
+CONFIG_SCSI_NCR53C8XX_SYNC=80
 CONFIG_SCSI_NCR53C8XX_PROFILE=y
 # CONFIG_SCSI_NCR53C8XX_IOMAPPED is not set
 CONFIG_SCSI_NCR53C8XX_SYMBIOS_COMPAT=y
-CONFIG_SCSI_NCR53C8XX_PQS_PDS=y
+CONFIG_SCSI_NCR53C8XX_PQS_PDS=y 
+# CONFIG_SCSI_NCR53C8XX_IARB is not set 
+CONFIG_SCSI_NCR53C8XX_INTEGRITY_CHECK=y
 CONFIG_SCSI_PAS16=m
 CONFIG_SCSI_PCI2000=m
 CONFIG_SCSI_PCI2220I=m
@@ -395,6 +438,10 @@
 CONFIG_IPDDP_DECAP=y
 CONFIG_PLIP=m
 CONFIG_PPP=m
+
+#
+# CCP compressors for PPP are only built as modules.
+#
 CONFIG_SLIP=m
 CONFIG_SLIP_COMPRESSED=y
 CONFIG_SLIP_SMART=y
@@ -444,28 +491,52 @@
 # IrDA subsystem support
 #
 CONFIG_IRDA=m
+
+#
+# IrDA protocols
+#
 CONFIG_IRLAN=m
 CONFIG_IRCOMM=m
 CONFIG_IRLPT=m
 CONFIG_IRLPT_CLIENT=m
 CONFIG_IRLPT_SERVER=m
 CONFIG_IRDA_OPTIONS=y
+
+#
+#    IrDA options
+#
 CONFIG_IRDA_CACHE_LAST_LSAP=y
 CONFIG_IRDA_FAST_RR=y
 # CONFIG_IRDA_DEBUG is not set
 CONFIG_IRDA_COMPRESSION=y
+
+#
+#    IrDA compressors
+#
 CONFIG_IRDA_DEFLATE=m
 
 #
 # Infrared-port device drivers
 #
+
+#
+# SIR device drivers
+#
 CONFIG_IRTTY_SIR=m
 CONFIG_IRPORT_SIR=m
+
+#
+# FIR device drivers
+#
 CONFIG_NSC_FIR=m
 CONFIG_WINBOND_FIR=m
 CONFIG_SHARP_FIR=m
 CONFIG_TOSHIBA_FIR=m
 CONFIG_SMC_IRCC_FIR=m
+
+#
+# Dongle support
+#
 CONFIG_DONGLE=y
 CONFIG_ESI_DONGLE=m
 CONFIG_ACTISYS_DONGLE=m
@@ -632,6 +703,44 @@
 # CONFIG_MIXCOMWD is not set
 CONFIG_NVRAM=m
 CONFIG_RTC=y
+
+#
+# I2C support
+#
+CONFIG_I2C=m
+CONFIG_I2C_ALGOBIT=m
+CONFIG_I2C_PHILIPSPAR=m
+CONFIG_I2C_ELV=m
+CONFIG_I2C_VELLEMAN=m
+CONFIG_I2C_ALGOPCF=m
+CONFIG_I2C_ELEKTOR=m
+CONFIG_I2C_MAINBOARD=m
+CONFIG_I2C_ALI15X3=m
+CONFIG_I2C_HYDRA=m
+CONFIG_I2C_PIIX4=m
+CONFIG_I2C_VIA=m
+CONFIG_I2C_ISA=m
+CONFIG_I2C_CHARDEV=m
+
+#
+# Hardware sensors support
+#
+CONFIG_SENSORS=m
+CONFIG_SENSORS_ADM1021=m
+CONFIG_SENSORS_ADM9240=m
+CONFIG_SENSORS_GL518SM=m
+CONFIG_SENSORS_LM75=m
+CONFIG_SENSORS_LM78=m
+CONFIG_SENSORS_LM80=m
+CONFIG_SENSORS_SIS5595=m
+CONFIG_SENSORS_W83781D=m
+CONFIG_SENSORS_OTHER=m
+CONFIG_SENSORS_EEPROM=m
+CONFIG_SENSORS_LTC1710=m
+
+#
+# AGP support
+#
 CONFIG_AGP=m
 CONFIG_AGP_INTEL=y
 CONFIG_AGP_I810=y
@@ -670,6 +779,10 @@
 CONFIG_FTAPE=m
 CONFIG_ZFTAPE=m
 CONFIG_ZFT_DFLT_BLK_SZ=10240
+
+#
+# The compressor will be built as a module only!
+#
 CONFIG_ZFT_COMPRESSOR=m
 CONFIG_FT_NR_BUFFERS=3
 CONFIG_FT_PROC_FS=y
@@ -677,12 +790,20 @@
 # CONFIG_FT_FULL_DEBUG is not set
 # CONFIG_FT_NO_TRACE is not set
 # CONFIG_FT_NO_TRACE_AT_ALL is not set
+
+#
+# Hardware configuration
+#
 CONFIG_FT_STD_FDC=y
 # CONFIG_FT_MACH2 is not set
 # CONFIG_FT_PROBE_FC10 is not set
 # CONFIG_FT_ALT_FDC is not set
 CONFIG_FT_FDC_THR=8
 CONFIG_FT_FDC_MAX_RATE=2000
+
+#
+# ONLY for DEC Alpha architectures
+#
 CONFIG_FT_ALPHA_CLOCK=0
 
 #
@@ -709,6 +830,8 @@
 # CONFIG_QNX4FS_RW is not set
 CONFIG_ROMFS_FS=m
 CONFIG_EXT2_FS=y
+CONFIG_EXT3_FS=y 
+CONFIG_EXT3_FS_JFS_CHECK=y
 CONFIG_SYSV_FS=m
 CONFIG_UFS_FS=m
 # CONFIG_UFS_FS_WRITE is not set
@@ -724,6 +847,8 @@
 CONFIG_NFSD_SUN=y
 CONFIG_SUNRPC=m
 CONFIG_LOCKD=m
+CONFIG_NFSD_V3=y 
+CONFIG_NFS_V3=y
 CONFIG_SMB_FS=m
 CONFIG_NCP_FS=m
 CONFIG_NCPFS_PACKET_SIGNING=y
@@ -866,15 +991,31 @@
 CONFIG_AEDSP16=m
 CONFIG_AEDSP16_BASE=220
 CONFIG_MPU_BASE=330
+
+#
+# SC-6600 Audio Cards have no jumper switches at all
+#
 CONFIG_SC6600=y
+
+#
+# SC-6600 specific configuration
+#
 CONFIG_SC6600_JOY=y
 CONFIG_SC6600_CDROM=4
 CONFIG_SC6600_CDROMBASE=0
 CONFIG_AEDSP16_SBPRO=y
+
+#
+# Audio Excel DSP 16 [Sound Blaster Pro]
+#
 CONFIG_AEDSP16_BASE=220
 CONFIG_AEDSP16_SB_IRQ=5
 CONFIG_AEDSP16_SB_DMA=0
 CONFIG_AEDSP16_MPU401=y
+
+#
+# Audio Excel DSP 16 [MPU-401]
+#
 CONFIG_AEDSP16_MPU_IRQ=5
 
 #
Index: oldkernel/linux/configs/kernel-2.2.14-i386.config
diff -u linux/configs/kernel-2.2.14-i386.config:1.5 linux/configs/kernel-2.2.14-i386.config:1.6
--- linux/configs/kernel-2.2.14-i386.config:1.5	Thu Jun  1 13:01:16 2000
+++ linux/configs/kernel-2.2.14-i386.config	Fri Jul  7 15:36:42 2000
@@ -1,5 +1,5 @@
 #
-# Automatically generated by make menuconfig: don't edit
+# Automatically generated make config: don't edit
 #
 
 #
@@ -15,15 +15,14 @@
 # CONFIG_M586 is not set
 # CONFIG_M586TSC is not set
 # CONFIG_M686 is not set
-# CONFIG_M686FX is not set
-# CONFIG_X86_PN_OFF is not set
-# CONFIG_X86_FX is not set
+CONFIG_X86_PN_OFF=y
+CONFIG_X86_FX=y
 # CONFIG_X86_CPU_OPTIMIZATIONS is not set
+CONFIG_1GB=y
+# CONFIG_2GB is not set
 CONFIG_MATH_EMULATION=y
 CONFIG_MTRR=y
 # CONFIG_SMP is not set
-CONFIG_1GB=y
-# CONFIG_2GB is not set
 
 #
 # Loadable module support
@@ -80,6 +79,10 @@
 #
 CONFIG_BLK_DEV_FD=y
 CONFIG_BLK_DEV_IDE=y
+
+#
+# Please see Documentation/ide.txt for help/info on IDE drives
+#
 # CONFIG_BLK_DEV_HD_IDE is not set
 CONFIG_BLK_DEV_IDEDISK=y
 CONFIG_BLK_DEV_IDECD=m
@@ -98,6 +101,10 @@
 # CONFIG_BLK_DEV_VIA82C586 is not set
 # CONFIG_BLK_DEV_CMD646 is not set
 # CONFIG_IDE_CHIPSETS is not set
+
+#
+# Additional Block Devices
+#
 CONFIG_BLK_DEV_LOOP=m
 CONFIG_BLK_DEV_NBD=m
 # CONFIG_BLK_DEV_MD is not set
@@ -112,13 +119,22 @@
 CONFIG_BLK_DEV_INITRD=y
 CONFIG_BLK_DEV_XD=m
 CONFIG_BLK_DEV_DAC960=y
+CONFIG_BLK_DEV_3WARE=y
 CONFIG_PARIDE_PARPORT=m
 CONFIG_PARIDE=m
+
+#
+# Parallel IDE high-level drivers
+#
 CONFIG_PARIDE_PD=m
 CONFIG_PARIDE_PCD=m
 CONFIG_PARIDE_PF=m
 CONFIG_PARIDE_PT=m
 CONFIG_PARIDE_PG=m
+
+#
+# Parallel IDE protocol modules
+#
 CONFIG_PARIDE_ATEN=m
 CONFIG_PARIDE_BPCK=m
 CONFIG_PARIDE_COMM=m
@@ -155,7 +171,16 @@
 CONFIG_NETLINK_DEV=y
 CONFIG_IP_TRANSPARENT_PROXY=y
 CONFIG_IP_MASQUERADE=y
+
+#
+# Protocol-specific masquerading support will be built as modules.
+#
+# CONFIG_IP_MASQUERADE_UDP_LOOSE is not set
 CONFIG_IP_MASQUERADE_ICMP=y
+
+#
+# Protocol-specific masquerading support will be built as modules.
+#
 CONFIG_IP_MASQUERADE_MOD=y
 CONFIG_IP_MASQUERADE_IPAUTOFW=m
 CONFIG_IP_MASQUERADE_IPPORTFW=m
@@ -174,9 +199,17 @@
 CONFIG_IP_ALIAS=y
 # CONFIG_ARPD is not set
 CONFIG_SYN_COOKIES=y
+
+#
+# (it is safe to leave these untouched)
+#
 CONFIG_INET_RARP=m
 CONFIG_SKB_LARGE=y
 # CONFIG_IPV6 is not set
+
+#
+#  
+#
 CONFIG_IPX=m
 # CONFIG_IPX_INTERN is not set
 # CONFIG_SPX is not set
@@ -206,11 +239,19 @@
 # SCSI support
 #
 CONFIG_SCSI=y
+
+#
+# SCSI support type (disk, tape, CD-ROM)
+#
 CONFIG_BLK_DEV_SD=y
 CONFIG_CHR_DEV_ST=y
 CONFIG_BLK_DEV_SR=y
 CONFIG_BLK_DEV_SR_VENDOR=y
 CONFIG_CHR_DEV_SG=m
+
+#
+# Some SCSI devices (e.g. CD jukebox) support multiple LUNs
+#
 # CONFIG_SCSI_MULTI_LUN is not set
 CONFIG_SCSI_CONSTANTS=y
 CONFIG_SCSI_LOGGING=y
@@ -224,7 +265,7 @@
 CONFIG_SCSI_AHA1542=m
 CONFIG_SCSI_AHA1740=m
 CONFIG_SCSI_AIC7XXX=y
-# CONFIG_AIC7XXX_TCQ_ON_BY_DEFAULT is not set
+CONFIG_AIC7XXX_TCQ_ON_BY_DEFAULT=y
 CONFIG_AIC7XXX_CMDS_PER_DEVICE=8
 CONFIG_AIC7XXX_PROC_STATS=y
 CONFIG_AIC7XXX_RESET_DELAY=5
@@ -269,11 +310,13 @@
 CONFIG_SCSI_SYM53C8XX=y
 CONFIG_SCSI_NCR53C8XX_DEFAULT_TAGS=8
 CONFIG_SCSI_NCR53C8XX_MAX_TAGS=32
-CONFIG_SCSI_NCR53C8XX_SYNC=40
+CONFIG_SCSI_NCR53C8XX_SYNC=80
 CONFIG_SCSI_NCR53C8XX_PROFILE=y
 # CONFIG_SCSI_NCR53C8XX_IOMAPPED is not set
 CONFIG_SCSI_NCR53C8XX_SYMBIOS_COMPAT=y
-CONFIG_SCSI_NCR53C8XX_PQS_PDS=y
+CONFIG_SCSI_NCR53C8XX_PQS_PDS=y 
+# CONFIG_SCSI_NCR53C8XX_IARB is not set 
+CONFIG_SCSI_NCR53C8XX_INTEGRITY_CHECK=y
 CONFIG_SCSI_PAS16=m
 CONFIG_SCSI_PCI2000=m
 CONFIG_SCSI_PCI2220I=m
@@ -393,6 +436,10 @@
 CONFIG_IPDDP_DECAP=y
 CONFIG_PLIP=m
 CONFIG_PPP=m
+
+#
+# CCP compressors for PPP are only built as modules.
+#
 CONFIG_SLIP=m
 CONFIG_SLIP_COMPRESSED=y
 CONFIG_SLIP_SMART=y
@@ -442,28 +489,52 @@
 # IrDA subsystem support
 #
 CONFIG_IRDA=m
+
+#
+# IrDA protocols
+#
 CONFIG_IRLAN=m
 CONFIG_IRCOMM=m
 CONFIG_IRLPT=m
 CONFIG_IRLPT_CLIENT=m
 CONFIG_IRLPT_SERVER=m
 CONFIG_IRDA_OPTIONS=y
+
+#
+#    IrDA options
+#
 CONFIG_IRDA_CACHE_LAST_LSAP=y
 CONFIG_IRDA_FAST_RR=y
 # CONFIG_IRDA_DEBUG is not set
 CONFIG_IRDA_COMPRESSION=y
+
+#
+#    IrDA compressors
+#
 CONFIG_IRDA_DEFLATE=m
 
 #
 # Infrared-port device drivers
 #
+
+#
+# SIR device drivers
+#
 CONFIG_IRTTY_SIR=m
 CONFIG_IRPORT_SIR=m
+
+#
+# FIR device drivers
+#
 CONFIG_NSC_FIR=m
 CONFIG_WINBOND_FIR=m
 CONFIG_SHARP_FIR=m
 CONFIG_TOSHIBA_FIR=m
 CONFIG_SMC_IRCC_FIR=m
+
+#
+# Dongle support
+#
 CONFIG_DONGLE=y
 CONFIG_ESI_DONGLE=m
 CONFIG_ACTISYS_DONGLE=m
@@ -630,6 +701,44 @@
 # CONFIG_MIXCOMWD is not set
 CONFIG_NVRAM=m
 CONFIG_RTC=y
+
+#
+# I2C support
+#
+CONFIG_I2C=m
+CONFIG_I2C_ALGOBIT=m
+CONFIG_I2C_PHILIPSPAR=m
+CONFIG_I2C_ELV=m
+CONFIG_I2C_VELLEMAN=m
+CONFIG_I2C_ALGOPCF=m
+CONFIG_I2C_ELEKTOR=m
+CONFIG_I2C_MAINBOARD=m
+CONFIG_I2C_ALI15X3=m
+CONFIG_I2C_HYDRA=m
+CONFIG_I2C_PIIX4=m
+CONFIG_I2C_VIA=m
+CONFIG_I2C_ISA=m
+CONFIG_I2C_CHARDEV=m
+
+#
+# Hardware sensors support
+#
+CONFIG_SENSORS=m
+CONFIG_SENSORS_ADM1021=m
+CONFIG_SENSORS_ADM9240=m
+CONFIG_SENSORS_GL518SM=m
+CONFIG_SENSORS_LM75=m
+CONFIG_SENSORS_LM78=m
+CONFIG_SENSORS_LM80=m
+CONFIG_SENSORS_SIS5595=m
+CONFIG_SENSORS_W83781D=m
+CONFIG_SENSORS_OTHER=m
+CONFIG_SENSORS_EEPROM=m
+CONFIG_SENSORS_LTC1710=m
+
+#
+# AGP support
+#
 CONFIG_AGP=m
 CONFIG_AGP_INTEL=y
 CONFIG_AGP_I810=y
@@ -668,6 +777,10 @@
 CONFIG_FTAPE=m
 CONFIG_ZFTAPE=m
 CONFIG_ZFT_DFLT_BLK_SZ=10240
+
+#
+# The compressor will be built as a module only!
+#
 CONFIG_ZFT_COMPRESSOR=m
 CONFIG_FT_NR_BUFFERS=3
 CONFIG_FT_PROC_FS=y
@@ -675,12 +788,20 @@
 # CONFIG_FT_FULL_DEBUG is not set
 # CONFIG_FT_NO_TRACE is not set
 # CONFIG_FT_NO_TRACE_AT_ALL is not set
+
+#
+# Hardware configuration
+#
 CONFIG_FT_STD_FDC=y
 # CONFIG_FT_MACH2 is not set
 # CONFIG_FT_PROBE_FC10 is not set
 # CONFIG_FT_ALT_FDC is not set
 CONFIG_FT_FDC_THR=8
 CONFIG_FT_FDC_MAX_RATE=2000
+
+#
+# ONLY for DEC Alpha architectures
+#
 CONFIG_FT_ALPHA_CLOCK=0
 
 #
@@ -707,6 +828,8 @@
 # CONFIG_QNX4FS_RW is not set
 CONFIG_ROMFS_FS=m
 CONFIG_EXT2_FS=y
+CONFIG_EXT3_FS=y 
+CONFIG_EXT3_FS_JFS_CHECK=y
 CONFIG_SYSV_FS=m
 CONFIG_UFS_FS=m
 # CONFIG_UFS_FS_WRITE is not set
@@ -722,6 +845,8 @@
 CONFIG_NFSD_SUN=y
 CONFIG_SUNRPC=m
 CONFIG_LOCKD=m
+CONFIG_NFSD_V3=y 
+CONFIG_NFS_V3=y
 CONFIG_SMB_FS=m
 CONFIG_NCP_FS=m
 CONFIG_NCPFS_PACKET_SIGNING=y
@@ -864,15 +989,31 @@
 CONFIG_AEDSP16=m
 CONFIG_AEDSP16_BASE=220
 CONFIG_MPU_BASE=330
+
+#
+# SC-6600 Audio Cards have no jumper switches at all
+#
 CONFIG_SC6600=y
+
+#
+# SC-6600 specific configuration
+#
 CONFIG_SC6600_JOY=y
 CONFIG_SC6600_CDROM=4
 CONFIG_SC6600_CDROMBASE=0
 CONFIG_AEDSP16_SBPRO=y
+
+#
+# Audio Excel DSP 16 [Sound Blaster Pro]
+#
 CONFIG_AEDSP16_BASE=220
 CONFIG_AEDSP16_SB_IRQ=5
 CONFIG_AEDSP16_SB_DMA=0
 CONFIG_AEDSP16_MPU401=y
+
+#
+# Audio Excel DSP 16 [MPU-401]
+#
 CONFIG_AEDSP16_MPU_IRQ=5
 
 #
Index: oldkernel/linux/configs/kernel-2.2.14-i586-smp.config
diff -u linux/configs/kernel-2.2.14-i586-smp.config:1.6 linux/configs/kernel-2.2.14-i586-smp.config:1.7
--- linux/configs/kernel-2.2.14-i586-smp.config:1.6	Thu Jun  1 13:01:16 2000
+++ linux/configs/kernel-2.2.14-i586-smp.config	Fri Jul  7 15:36:42 2000
@@ -1,5 +1,5 @@
 #
-# Automatically generated by make menuconfig: don't edit
+# Automatically generated make config: don't edit
 #
 
 #
@@ -15,19 +15,18 @@
 CONFIG_M586=y
 # CONFIG_M586TSC is not set
 # CONFIG_M686 is not set
-# CONFIG_M686FX is not set
 CONFIG_X86_WP_WORKS_OK=y
 CONFIG_X86_INVLPG=y
 CONFIG_X86_BSWAP=y
 CONFIG_X86_POPAD_OK=y
 CONFIG_X86_PN_OFF=y
-# CONFIG_X86_FX is not set
+CONFIG_X86_FX=y
 # CONFIG_X86_CPU_OPTIMIZATIONS is not set
+CONFIG_1GB=y
+# CONFIG_2GB is not set
 # CONFIG_MATH_EMULATION is not set
 CONFIG_MTRR=y
 CONFIG_SMP=y
-CONFIG_1GB=y
-# CONFIG_2GB is not set
 
 #
 # Loadable module support
@@ -77,6 +76,10 @@
 #
 CONFIG_BLK_DEV_FD=y
 CONFIG_BLK_DEV_IDE=y
+
+#
+# Please see Documentation/ide.txt for help/info on IDE drives
+#
 # CONFIG_BLK_DEV_HD_IDE is not set
 CONFIG_BLK_DEV_IDEDISK=y
 CONFIG_BLK_DEV_IDECD=m
@@ -95,6 +98,10 @@
 # CONFIG_BLK_DEV_VIA82C586 is not set
 # CONFIG_BLK_DEV_CMD646 is not set
 # CONFIG_IDE_CHIPSETS is not set
+
+#
+# Additional Block Devices
+#
 CONFIG_BLK_DEV_LOOP=m
 CONFIG_BLK_DEV_NBD=m
 # CONFIG_BLK_DEV_MD is not set
@@ -109,13 +116,22 @@
 CONFIG_BLK_DEV_INITRD=y
 CONFIG_BLK_DEV_XD=m
 CONFIG_BLK_DEV_DAC960=y
+CONFIG_BLK_DEV_3WARE=y
 CONFIG_PARIDE_PARPORT=m
 CONFIG_PARIDE=m
+
+#
+# Parallel IDE high-level drivers
+#
 CONFIG_PARIDE_PD=m
 CONFIG_PARIDE_PCD=m
 CONFIG_PARIDE_PF=m
 CONFIG_PARIDE_PT=m
 CONFIG_PARIDE_PG=m
+
+#
+# Parallel IDE protocol modules
+#
 CONFIG_PARIDE_ATEN=m
 CONFIG_PARIDE_BPCK=m
 CONFIG_PARIDE_COMM=m
@@ -152,7 +168,16 @@
 CONFIG_NETLINK_DEV=y
 CONFIG_IP_TRANSPARENT_PROXY=y
 CONFIG_IP_MASQUERADE=y
+
+#
+# Protocol-specific masquerading support will be built as modules.
+#
+# CONFIG_IP_MASQUERADE_UDP_LOOSE is not set
 CONFIG_IP_MASQUERADE_ICMP=y
+
+#
+# Protocol-specific masquerading support will be built as modules.
+#
 CONFIG_IP_MASQUERADE_MOD=y
 CONFIG_IP_MASQUERADE_IPAUTOFW=m
 CONFIG_IP_MASQUERADE_IPPORTFW=m
@@ -171,9 +196,17 @@
 CONFIG_IP_ALIAS=y
 # CONFIG_ARPD is not set
 CONFIG_SYN_COOKIES=y
+
+#
+# (it is safe to leave these untouched)
+#
 CONFIG_INET_RARP=m
 CONFIG_SKB_LARGE=y
 # CONFIG_IPV6 is not set
+
+#
+#  
+#
 CONFIG_IPX=m
 # CONFIG_IPX_INTERN is not set
 # CONFIG_SPX is not set
@@ -203,11 +236,19 @@
 # SCSI support
 #
 CONFIG_SCSI=y
+
+#
+# SCSI support type (disk, tape, CD-ROM)
+#
 CONFIG_BLK_DEV_SD=y
 CONFIG_CHR_DEV_ST=y
 CONFIG_BLK_DEV_SR=y
 CONFIG_BLK_DEV_SR_VENDOR=y
 CONFIG_CHR_DEV_SG=m
+
+#
+# Some SCSI devices (e.g. CD jukebox) support multiple LUNs
+#
 # CONFIG_SCSI_MULTI_LUN is not set
 CONFIG_SCSI_CONSTANTS=y
 CONFIG_SCSI_LOGGING=y
@@ -221,7 +262,7 @@
 CONFIG_SCSI_AHA1542=m
 CONFIG_SCSI_AHA1740=m
 CONFIG_SCSI_AIC7XXX=y
-# CONFIG_AIC7XXX_TCQ_ON_BY_DEFAULT is not set
+CONFIG_AIC7XXX_TCQ_ON_BY_DEFAULT=y
 CONFIG_AIC7XXX_CMDS_PER_DEVICE=8
 CONFIG_AIC7XXX_PROC_STATS=y
 CONFIG_AIC7XXX_RESET_DELAY=5
@@ -266,11 +307,13 @@
 CONFIG_SCSI_SYM53C8XX=y
 CONFIG_SCSI_NCR53C8XX_DEFAULT_TAGS=8
 CONFIG_SCSI_NCR53C8XX_MAX_TAGS=32
-CONFIG_SCSI_NCR53C8XX_SYNC=40
+CONFIG_SCSI_NCR53C8XX_SYNC=80
 CONFIG_SCSI_NCR53C8XX_PROFILE=y
 # CONFIG_SCSI_NCR53C8XX_IOMAPPED is not set
 CONFIG_SCSI_NCR53C8XX_SYMBIOS_COMPAT=y
-CONFIG_SCSI_NCR53C8XX_PQS_PDS=y
+CONFIG_SCSI_NCR53C8XX_PQS_PDS=y 
+# CONFIG_SCSI_NCR53C8XX_IARB is not set 
+CONFIG_SCSI_NCR53C8XX_INTEGRITY_CHECK=y
 CONFIG_SCSI_PAS16=m
 CONFIG_SCSI_PCI2000=m
 CONFIG_SCSI_PCI2220I=m
@@ -390,6 +433,10 @@
 CONFIG_IPDDP_DECAP=y
 CONFIG_PLIP=m
 CONFIG_PPP=m
+
+#
+# CCP compressors for PPP are only built as modules.
+#
 CONFIG_SLIP=m
 CONFIG_SLIP_COMPRESSED=y
 CONFIG_SLIP_SMART=y
@@ -439,28 +486,52 @@
 # IrDA subsystem support
 #
 CONFIG_IRDA=m
+
+#
+# IrDA protocols
+#
 CONFIG_IRLAN=m
 CONFIG_IRCOMM=m
 CONFIG_IRLPT=m
 CONFIG_IRLPT_CLIENT=m
 CONFIG_IRLPT_SERVER=m
 CONFIG_IRDA_OPTIONS=y
+
+#
+#    IrDA options
+#
 CONFIG_IRDA_CACHE_LAST_LSAP=y
 CONFIG_IRDA_FAST_RR=y
 # CONFIG_IRDA_DEBUG is not set
 CONFIG_IRDA_COMPRESSION=y
+
+#
+#    IrDA compressors
+#
 CONFIG_IRDA_DEFLATE=m
 
 #
 # Infrared-port device drivers
 #
+
+#
+# SIR device drivers
+#
 CONFIG_IRTTY_SIR=m
 CONFIG_IRPORT_SIR=m
+
+#
+# FIR device drivers
+#
 CONFIG_NSC_FIR=m
 CONFIG_WINBOND_FIR=m
 CONFIG_SHARP_FIR=m
 CONFIG_TOSHIBA_FIR=m
 CONFIG_SMC_IRCC_FIR=m
+
+#
+# Dongle support
+#
 CONFIG_DONGLE=y
 CONFIG_ESI_DONGLE=m
 CONFIG_ACTISYS_DONGLE=m
@@ -627,6 +698,44 @@
 # CONFIG_MIXCOMWD is not set
 CONFIG_NVRAM=m
 CONFIG_RTC=y
+
+#
+# I2C support
+#
+CONFIG_I2C=m
+CONFIG_I2C_ALGOBIT=m
+CONFIG_I2C_PHILIPSPAR=m
+CONFIG_I2C_ELV=m
+CONFIG_I2C_VELLEMAN=m
+CONFIG_I2C_ALGOPCF=m
+CONFIG_I2C_ELEKTOR=m
+CONFIG_I2C_MAINBOARD=m
+CONFIG_I2C_ALI15X3=m
+CONFIG_I2C_HYDRA=m
+CONFIG_I2C_PIIX4=m
+CONFIG_I2C_VIA=m
+CONFIG_I2C_ISA=m
+CONFIG_I2C_CHARDEV=m
+
+#
+# Hardware sensors support
+#
+CONFIG_SENSORS=m
+CONFIG_SENSORS_ADM1021=m
+CONFIG_SENSORS_ADM9240=m
+CONFIG_SENSORS_GL518SM=m
+CONFIG_SENSORS_LM75=m
+CONFIG_SENSORS_LM78=m
+CONFIG_SENSORS_LM80=m
+CONFIG_SENSORS_SIS5595=m
+CONFIG_SENSORS_W83781D=m
+CONFIG_SENSORS_OTHER=m
+CONFIG_SENSORS_EEPROM=m
+CONFIG_SENSORS_LTC1710=m
+
+#
+# AGP support
+#
 CONFIG_AGP=m
 CONFIG_AGP_INTEL=y
 CONFIG_AGP_I810=y
@@ -665,6 +774,10 @@
 CONFIG_FTAPE=m
 CONFIG_ZFTAPE=m
 CONFIG_ZFT_DFLT_BLK_SZ=10240
+
+#
+# The compressor will be built as a module only!
+#
 CONFIG_ZFT_COMPRESSOR=m
 CONFIG_FT_NR_BUFFERS=3
 CONFIG_FT_PROC_FS=y
@@ -672,12 +785,20 @@
 # CONFIG_FT_FULL_DEBUG is not set
 # CONFIG_FT_NO_TRACE is not set
 # CONFIG_FT_NO_TRACE_AT_ALL is not set
+
+#
+# Hardware configuration
+#
 CONFIG_FT_STD_FDC=y
 # CONFIG_FT_MACH2 is not set
 # CONFIG_FT_PROBE_FC10 is not set
 # CONFIG_FT_ALT_FDC is not set
 CONFIG_FT_FDC_THR=8
 CONFIG_FT_FDC_MAX_RATE=2000
+
+#
+# ONLY for DEC Alpha architectures
+#
 CONFIG_FT_ALPHA_CLOCK=0
 
 #
@@ -704,6 +825,8 @@
 # CONFIG_QNX4FS_RW is not set
 CONFIG_ROMFS_FS=m
 CONFIG_EXT2_FS=y
+CONFIG_EXT3_FS=y 
+CONFIG_EXT3_FS_JFS_CHECK=y
 CONFIG_SYSV_FS=m
 CONFIG_UFS_FS=m
 # CONFIG_UFS_FS_WRITE is not set
@@ -719,6 +842,8 @@
 CONFIG_NFSD_SUN=y
 CONFIG_SUNRPC=m
 CONFIG_LOCKD=m
+CONFIG_NFSD_V3=y 
+CONFIG_NFS_V3=y
 CONFIG_SMB_FS=m
 CONFIG_NCP_FS=m
 CONFIG_NCPFS_PACKET_SIGNING=y
@@ -861,15 +986,31 @@
 CONFIG_AEDSP16=m
 CONFIG_AEDSP16_BASE=220
 CONFIG_MPU_BASE=330
+
+#
+# SC-6600 Audio Cards have no jumper switches at all
+#
 CONFIG_SC6600=y
+
+#
+# SC-6600 specific configuration
+#
 CONFIG_SC6600_JOY=y
 CONFIG_SC6600_CDROM=4
 CONFIG_SC6600_CDROMBASE=0
 CONFIG_AEDSP16_SBPRO=y
+
+#
+# Audio Excel DSP 16 [Sound Blaster Pro]
+#
 CONFIG_AEDSP16_BASE=220
 CONFIG_AEDSP16_SB_IRQ=5
 CONFIG_AEDSP16_SB_DMA=0
 CONFIG_AEDSP16_MPU401=y
+
+#
+# Audio Excel DSP 16 [MPU-401]
+#
 CONFIG_AEDSP16_MPU_IRQ=5
 
 #
Index: oldkernel/linux/configs/kernel-2.2.14-i586.config
diff -u linux/configs/kernel-2.2.14-i586.config:1.6 linux/configs/kernel-2.2.14-i586.config:1.7
--- linux/configs/kernel-2.2.14-i586.config:1.6	Thu Jun  1 13:01:16 2000
+++ linux/configs/kernel-2.2.14-i586.config	Fri Jul  7 15:36:42 2000
@@ -1,5 +1,5 @@
 #
-# Automatically generated by make menuconfig: don't edit
+# Automatically generated make config: don't edit
 #
 
 #
@@ -15,19 +15,18 @@
 CONFIG_M586=y
 # CONFIG_M586TSC is not set
 # CONFIG_M686 is not set
-# CONFIG_M686FX is not set
 CONFIG_X86_WP_WORKS_OK=y
 CONFIG_X86_INVLPG=y
 CONFIG_X86_BSWAP=y
 CONFIG_X86_POPAD_OK=y
 CONFIG_X86_PN_OFF=y
-# CONFIG_X86_FX is not set
+CONFIG_X86_FX=y
 # CONFIG_X86_CPU_OPTIMIZATIONS is not set
+CONFIG_1GB=y
+# CONFIG_2GB is not set
 # CONFIG_MATH_EMULATION is not set
 CONFIG_MTRR=y
 # CONFIG_SMP is not set
-CONFIG_1GB=y
-# CONFIG_2GB is not set
 
 #
 # Loadable module support
@@ -84,6 +83,10 @@
 #
 CONFIG_BLK_DEV_FD=y
 CONFIG_BLK_DEV_IDE=y
+
+#
+# Please see Documentation/ide.txt for help/info on IDE drives
+#
 # CONFIG_BLK_DEV_HD_IDE is not set
 CONFIG_BLK_DEV_IDEDISK=y
 CONFIG_BLK_DEV_IDECD=m
@@ -102,6 +105,10 @@
 # CONFIG_BLK_DEV_VIA82C586 is not set
 # CONFIG_BLK_DEV_CMD646 is not set
 # CONFIG_IDE_CHIPSETS is not set
+
+#
+# Additional Block Devices
+#
 CONFIG_BLK_DEV_LOOP=m
 CONFIG_BLK_DEV_NBD=m
 # CONFIG_BLK_DEV_MD is not set
@@ -116,13 +123,22 @@
 CONFIG_BLK_DEV_INITRD=y
 CONFIG_BLK_DEV_XD=m
 CONFIG_BLK_DEV_DAC960=y
+CONFIG_BLK_DEV_3WARE=y
 CONFIG_PARIDE_PARPORT=m
 CONFIG_PARIDE=m
+
+#
+# Parallel IDE high-level drivers
+#
 CONFIG_PARIDE_PD=m
 CONFIG_PARIDE_PCD=m
 CONFIG_PARIDE_PF=m
 CONFIG_PARIDE_PT=m
 CONFIG_PARIDE_PG=m
+
+#
+# Parallel IDE protocol modules
+#
 CONFIG_PARIDE_ATEN=m
 CONFIG_PARIDE_BPCK=m
 CONFIG_PARIDE_COMM=m
@@ -159,7 +175,16 @@
 CONFIG_NETLINK_DEV=y
 CONFIG_IP_TRANSPARENT_PROXY=y
 CONFIG_IP_MASQUERADE=y
+
+#
+# Protocol-specific masquerading support will be built as modules.
+#
+# CONFIG_IP_MASQUERADE_UDP_LOOSE is not set
 CONFIG_IP_MASQUERADE_ICMP=y
+
+#
+# Protocol-specific masquerading support will be built as modules.
+#
 CONFIG_IP_MASQUERADE_MOD=y
 CONFIG_IP_MASQUERADE_IPAUTOFW=m
 CONFIG_IP_MASQUERADE_IPPORTFW=m
@@ -178,9 +203,17 @@
 CONFIG_IP_ALIAS=y
 # CONFIG_ARPD is not set
 CONFIG_SYN_COOKIES=y
+
+#
+# (it is safe to leave these untouched)
+#
 CONFIG_INET_RARP=m
 CONFIG_SKB_LARGE=y
 # CONFIG_IPV6 is not set
+
+#
+#  
+#
 CONFIG_IPX=m
 # CONFIG_IPX_INTERN is not set
 # CONFIG_SPX is not set
@@ -210,11 +243,19 @@
 # SCSI support
 #
 CONFIG_SCSI=y
+
+#
+# SCSI support type (disk, tape, CD-ROM)
+#
 CONFIG_BLK_DEV_SD=y
 CONFIG_CHR_DEV_ST=y
 CONFIG_BLK_DEV_SR=y
 CONFIG_BLK_DEV_SR_VENDOR=y
 CONFIG_CHR_DEV_SG=m
+
+#
+# Some SCSI devices (e.g. CD jukebox) support multiple LUNs
+#
 # CONFIG_SCSI_MULTI_LUN is not set
 CONFIG_SCSI_CONSTANTS=y
 CONFIG_SCSI_LOGGING=y
@@ -228,7 +269,7 @@
 CONFIG_SCSI_AHA1542=m
 CONFIG_SCSI_AHA1740=m
 CONFIG_SCSI_AIC7XXX=y
-# CONFIG_AIC7XXX_TCQ_ON_BY_DEFAULT is not set
+CONFIG_AIC7XXX_TCQ_ON_BY_DEFAULT=y
 CONFIG_AIC7XXX_CMDS_PER_DEVICE=8
 CONFIG_AIC7XXX_PROC_STATS=y
 CONFIG_AIC7XXX_RESET_DELAY=5
@@ -273,11 +314,13 @@
 CONFIG_SCSI_SYM53C8XX=y
 CONFIG_SCSI_NCR53C8XX_DEFAULT_TAGS=8
 CONFIG_SCSI_NCR53C8XX_MAX_TAGS=32
-CONFIG_SCSI_NCR53C8XX_SYNC=40
+CONFIG_SCSI_NCR53C8XX_SYNC=80
 CONFIG_SCSI_NCR53C8XX_PROFILE=y
 # CONFIG_SCSI_NCR53C8XX_IOMAPPED is not set
 CONFIG_SCSI_NCR53C8XX_SYMBIOS_COMPAT=y
-CONFIG_SCSI_NCR53C8XX_PQS_PDS=y
+CONFIG_SCSI_NCR53C8XX_PQS_PDS=y 
+# CONFIG_SCSI_NCR53C8XX_IARB is not set 
+CONFIG_SCSI_NCR53C8XX_INTEGRITY_CHECK=y
 CONFIG_SCSI_PAS16=m
 CONFIG_SCSI_PCI2000=m
 CONFIG_SCSI_PCI2220I=m
@@ -397,6 +440,10 @@
 CONFIG_IPDDP_DECAP=y
 CONFIG_PLIP=m
 CONFIG_PPP=m
+
+#
+# CCP compressors for PPP are only built as modules.
+#
 CONFIG_SLIP=m
 CONFIG_SLIP_COMPRESSED=y
 CONFIG_SLIP_SMART=y
@@ -446,28 +493,52 @@
 # IrDA subsystem support
 #
 CONFIG_IRDA=m
+
+#
+# IrDA protocols
+#
 CONFIG_IRLAN=m
 CONFIG_IRCOMM=m
 CONFIG_IRLPT=m
 CONFIG_IRLPT_CLIENT=m
 CONFIG_IRLPT_SERVER=m
 CONFIG_IRDA_OPTIONS=y
+
+#
+#    IrDA options
+#
 CONFIG_IRDA_CACHE_LAST_LSAP=y
 CONFIG_IRDA_FAST_RR=y
 # CONFIG_IRDA_DEBUG is not set
 CONFIG_IRDA_COMPRESSION=y
+
+#
+#    IrDA compressors
+#
 CONFIG_IRDA_DEFLATE=m
 
 #
 # Infrared-port device drivers
 #
+
+#
+# SIR device drivers
+#
 CONFIG_IRTTY_SIR=m
 CONFIG_IRPORT_SIR=m
+
+#
+# FIR device drivers
+#
 CONFIG_NSC_FIR=m
 CONFIG_WINBOND_FIR=m
 CONFIG_SHARP_FIR=m
 CONFIG_TOSHIBA_FIR=m
 CONFIG_SMC_IRCC_FIR=m
+
+#
+# Dongle support
+#
 CONFIG_DONGLE=y
 CONFIG_ESI_DONGLE=m
 CONFIG_ACTISYS_DONGLE=m
@@ -634,6 +705,44 @@
 # CONFIG_MIXCOMWD is not set
 CONFIG_NVRAM=m
 CONFIG_RTC=y
+
+#
+# I2C support
+#
+CONFIG_I2C=m
+CONFIG_I2C_ALGOBIT=m
+CONFIG_I2C_PHILIPSPAR=m
+CONFIG_I2C_ELV=m
+CONFIG_I2C_VELLEMAN=m
+CONFIG_I2C_ALGOPCF=m
+CONFIG_I2C_ELEKTOR=m
+CONFIG_I2C_MAINBOARD=m
+CONFIG_I2C_ALI15X3=m
+CONFIG_I2C_HYDRA=m
+CONFIG_I2C_PIIX4=m
+CONFIG_I2C_VIA=m
+CONFIG_I2C_ISA=m
+CONFIG_I2C_CHARDEV=m
+
+#
+# Hardware sensors support
+#
+CONFIG_SENSORS=m
+CONFIG_SENSORS_ADM1021=m
+CONFIG_SENSORS_ADM9240=m
+CONFIG_SENSORS_GL518SM=m
+CONFIG_SENSORS_LM75=m
+CONFIG_SENSORS_LM78=m
+CONFIG_SENSORS_LM80=m
+CONFIG_SENSORS_SIS5595=m
+CONFIG_SENSORS_W83781D=m
+CONFIG_SENSORS_OTHER=m
+CONFIG_SENSORS_EEPROM=m
+CONFIG_SENSORS_LTC1710=m
+
+#
+# AGP support
+#
 CONFIG_AGP=m
 CONFIG_AGP_INTEL=y
 CONFIG_AGP_I810=y
@@ -672,6 +781,10 @@
 CONFIG_FTAPE=m
 CONFIG_ZFTAPE=m
 CONFIG_ZFT_DFLT_BLK_SZ=10240
+
+#
+# The compressor will be built as a module only!
+#
 CONFIG_ZFT_COMPRESSOR=m
 CONFIG_FT_NR_BUFFERS=3
 CONFIG_FT_PROC_FS=y
@@ -679,12 +792,20 @@
 # CONFIG_FT_FULL_DEBUG is not set
 # CONFIG_FT_NO_TRACE is not set
 # CONFIG_FT_NO_TRACE_AT_ALL is not set
+
+#
+# Hardware configuration
+#
 CONFIG_FT_STD_FDC=y
 # CONFIG_FT_MACH2 is not set
 # CONFIG_FT_PROBE_FC10 is not set
 # CONFIG_FT_ALT_FDC is not set
 CONFIG_FT_FDC_THR=8
 CONFIG_FT_FDC_MAX_RATE=2000
+
+#
+# ONLY for DEC Alpha architectures
+#
 CONFIG_FT_ALPHA_CLOCK=0
 
 #
@@ -711,6 +832,8 @@
 # CONFIG_QNX4FS_RW is not set
 CONFIG_ROMFS_FS=m
 CONFIG_EXT2_FS=y
+CONFIG_EXT3_FS=y 
+CONFIG_EXT3_FS_JFS_CHECK=y
 CONFIG_SYSV_FS=m
 CONFIG_UFS_FS=m
 # CONFIG_UFS_FS_WRITE is not set
@@ -726,6 +849,8 @@
 CONFIG_NFSD_SUN=y
 CONFIG_SUNRPC=m
 CONFIG_LOCKD=m
+CONFIG_NFSD_V3=y 
+CONFIG_NFS_V3=y
 CONFIG_SMB_FS=m
 CONFIG_NCP_FS=m
 CONFIG_NCPFS_PACKET_SIGNING=y
@@ -868,15 +993,31 @@
 CONFIG_AEDSP16=m
 CONFIG_AEDSP16_BASE=220
 CONFIG_MPU_BASE=330
+
+#
+# SC-6600 Audio Cards have no jumper switches at all
+#
 CONFIG_SC6600=y
+
+#
+# SC-6600 specific configuration
+#
 CONFIG_SC6600_JOY=y
 CONFIG_SC6600_CDROM=4
 CONFIG_SC6600_CDROMBASE=0
 CONFIG_AEDSP16_SBPRO=y
+
+#
+# Audio Excel DSP 16 [Sound Blaster Pro]
+#
 CONFIG_AEDSP16_BASE=220
 CONFIG_AEDSP16_SB_IRQ=5
 CONFIG_AEDSP16_SB_DMA=0
 CONFIG_AEDSP16_MPU401=y
+
+#
+# Audio Excel DSP 16 [MPU-401]
+#
 CONFIG_AEDSP16_MPU_IRQ=5
 
 #
Index: oldkernel/linux/configs/kernel-2.2.14-i686-smp.config
diff -u linux/configs/kernel-2.2.14-i686-smp.config:1.7 linux/configs/kernel-2.2.14-i686-smp.config:1.8
--- linux/configs/kernel-2.2.14-i686-smp.config:1.7	Thu Jun  1 13:01:16 2000
+++ linux/configs/kernel-2.2.14-i686-smp.config	Fri Jul  7 15:36:42 2000
@@ -1,5 +1,5 @@
 #
-# Automatically generated by make menuconfig: don't edit
+# Automatically generated make config: don't edit
 #
 
 #
@@ -14,8 +14,7 @@
 # CONFIG_M486 is not set
 # CONFIG_M586 is not set
 # CONFIG_M586TSC is not set
-# CONFIG_M686 is not set
-CONFIG_M686FX=y
+CONFIG_M686=y
 CONFIG_X86_WP_WORKS_OK=y
 CONFIG_X86_INVLPG=y
 CONFIG_X86_BSWAP=y
@@ -25,11 +24,11 @@
 CONFIG_X86_PN_OFF=y
 CONFIG_X86_FX=y
 # CONFIG_X86_CPU_OPTIMIZATIONS is not set
+CONFIG_1GB=y
+# CONFIG_2GB is not set
 # CONFIG_MATH_EMULATION is not set
 CONFIG_MTRR=y
 CONFIG_SMP=y
-CONFIG_1GB=y
-# CONFIG_2GB is not set
 
 #
 # Loadable module support
@@ -79,6 +78,10 @@
 #
 CONFIG_BLK_DEV_FD=y
 CONFIG_BLK_DEV_IDE=y
+
+#
+# Please see Documentation/ide.txt for help/info on IDE drives
+#
 # CONFIG_BLK_DEV_HD_IDE is not set
 CONFIG_BLK_DEV_IDEDISK=y
 CONFIG_BLK_DEV_IDECD=m
@@ -97,27 +100,41 @@
 # CONFIG_BLK_DEV_VIA82C586 is not set
 # CONFIG_BLK_DEV_CMD646 is not set
 # CONFIG_IDE_CHIPSETS is not set
+
+#
+# Additional Block Devices
+#
 CONFIG_BLK_DEV_LOOP=m
 CONFIG_BLK_DEV_NBD=m
-# CONFIG_BLK_DEV_MD is not set
+CONFIG_BLK_DEV_MD=y 
 CONFIG_AUTODETECT_RAID=y
-CONFIG_MD_LINEAR=m
-CONFIG_MD_STRIPED=m
-CONFIG_MD_MIRRORING=m
-CONFIG_MD_RAID5=m
+CONFIG_MD_LINEAR=y
+CONFIG_MD_STRIPED=y
+CONFIG_MD_MIRRORING=y
+CONFIG_MD_RAID5=y
 # CONFIG_MD_TRANSLUCENT is not set
 # CONFIG_MD_HSM is not set
+CONFIG_MD_BOOT=y
 CONFIG_BLK_DEV_RAM=y
 CONFIG_BLK_DEV_INITRD=y
 CONFIG_BLK_DEV_XD=m
 CONFIG_BLK_DEV_DAC960=y
+CONFIG_BLK_DEV_3WARE=y
 CONFIG_PARIDE_PARPORT=m
 CONFIG_PARIDE=m
+
+#
+# Parallel IDE high-level drivers
+#
 CONFIG_PARIDE_PD=m
 CONFIG_PARIDE_PCD=m
 CONFIG_PARIDE_PF=m
 CONFIG_PARIDE_PT=m
 CONFIG_PARIDE_PG=m
+
+#
+# Parallel IDE protocol modules
+#
 CONFIG_PARIDE_ATEN=m
 CONFIG_PARIDE_BPCK=m
 CONFIG_PARIDE_COMM=m
@@ -154,7 +171,16 @@
 CONFIG_NETLINK_DEV=y
 CONFIG_IP_TRANSPARENT_PROXY=y
 CONFIG_IP_MASQUERADE=y
+
+#
+# Protocol-specific masquerading support will be built as modules.
+#
+# CONFIG_IP_MASQUERADE_UDP_LOOSE is not set
 CONFIG_IP_MASQUERADE_ICMP=y
+
+#
+# Protocol-specific masquerading support will be built as modules.
+#
 CONFIG_IP_MASQUERADE_MOD=y
 CONFIG_IP_MASQUERADE_IPAUTOFW=m
 CONFIG_IP_MASQUERADE_IPPORTFW=m
@@ -173,9 +199,17 @@
 CONFIG_IP_ALIAS=y
 # CONFIG_ARPD is not set
 CONFIG_SYN_COOKIES=y
+
+#
+# (it is safe to leave these untouched)
+#
 CONFIG_INET_RARP=m
 CONFIG_SKB_LARGE=y
 # CONFIG_IPV6 is not set
+
+#
+#  
+#
 CONFIG_IPX=m
 # CONFIG_IPX_INTERN is not set
 # CONFIG_SPX is not set
@@ -205,11 +239,19 @@
 # SCSI support
 #
 CONFIG_SCSI=y
+
+#
+# SCSI support type (disk, tape, CD-ROM)
+#
 CONFIG_BLK_DEV_SD=y
 CONFIG_CHR_DEV_ST=y
 CONFIG_BLK_DEV_SR=y
 CONFIG_BLK_DEV_SR_VENDOR=y
 CONFIG_CHR_DEV_SG=m
+
+#
+# Some SCSI devices (e.g. CD jukebox) support multiple LUNs
+#
 # CONFIG_SCSI_MULTI_LUN is not set
 CONFIG_SCSI_CONSTANTS=y
 CONFIG_SCSI_LOGGING=y
@@ -223,7 +265,7 @@
 CONFIG_SCSI_AHA1542=m
 CONFIG_SCSI_AHA1740=m
 CONFIG_SCSI_AIC7XXX=y
-# CONFIG_AIC7XXX_TCQ_ON_BY_DEFAULT is not set
+CONFIG_AIC7XXX_TCQ_ON_BY_DEFAULT=y
 CONFIG_AIC7XXX_CMDS_PER_DEVICE=8
 CONFIG_AIC7XXX_PROC_STATS=y
 CONFIG_AIC7XXX_RESET_DELAY=5
@@ -268,11 +310,13 @@
 CONFIG_SCSI_SYM53C8XX=y
 CONFIG_SCSI_NCR53C8XX_DEFAULT_TAGS=8
 CONFIG_SCSI_NCR53C8XX_MAX_TAGS=32
-CONFIG_SCSI_NCR53C8XX_SYNC=40
+CONFIG_SCSI_NCR53C8XX_SYNC=80
 CONFIG_SCSI_NCR53C8XX_PROFILE=y
 # CONFIG_SCSI_NCR53C8XX_IOMAPPED is not set
 CONFIG_SCSI_NCR53C8XX_SYMBIOS_COMPAT=y
-CONFIG_SCSI_NCR53C8XX_PQS_PDS=y
+CONFIG_SCSI_NCR53C8XX_PQS_PDS=y 
+# CONFIG_SCSI_NCR53C8XX_IARB is not set 
+CONFIG_SCSI_NCR53C8XX_INTEGRITY_CHECK=y
 CONFIG_SCSI_PAS16=m
 CONFIG_SCSI_PCI2000=m
 CONFIG_SCSI_PCI2220I=m
@@ -392,6 +436,10 @@
 CONFIG_IPDDP_DECAP=y
 CONFIG_PLIP=m
 CONFIG_PPP=m
+
+#
+# CCP compressors for PPP are only built as modules.
+#
 CONFIG_SLIP=m
 CONFIG_SLIP_COMPRESSED=y
 CONFIG_SLIP_SMART=y
@@ -441,28 +489,52 @@
 # IrDA subsystem support
 #
 CONFIG_IRDA=m
+
+#
+# IrDA protocols
+#
 CONFIG_IRLAN=m
 CONFIG_IRCOMM=m
 CONFIG_IRLPT=m
 CONFIG_IRLPT_CLIENT=m
 CONFIG_IRLPT_SERVER=m
 CONFIG_IRDA_OPTIONS=y
+
+#
+#    IrDA options
+#
 CONFIG_IRDA_CACHE_LAST_LSAP=y
 CONFIG_IRDA_FAST_RR=y
 # CONFIG_IRDA_DEBUG is not set
 CONFIG_IRDA_COMPRESSION=y
+
+#
+#    IrDA compressors
+#
 CONFIG_IRDA_DEFLATE=m
 
 #
 # Infrared-port device drivers
 #
+
+#
+# SIR device drivers
+#
 CONFIG_IRTTY_SIR=m
 CONFIG_IRPORT_SIR=m
+
+#
+# FIR device drivers
+#
 CONFIG_NSC_FIR=m
 CONFIG_WINBOND_FIR=m
 CONFIG_SHARP_FIR=m
 CONFIG_TOSHIBA_FIR=m
 CONFIG_SMC_IRCC_FIR=m
+
+#
+# Dongle support
+#
 CONFIG_DONGLE=y
 CONFIG_ESI_DONGLE=m
 CONFIG_ACTISYS_DONGLE=m
@@ -629,6 +701,44 @@
 # CONFIG_MIXCOMWD is not set
 CONFIG_NVRAM=m
 CONFIG_RTC=y
+
+#
+# I2C support
+#
+CONFIG_I2C=m
+CONFIG_I2C_ALGOBIT=m
+CONFIG_I2C_PHILIPSPAR=m
+CONFIG_I2C_ELV=m
+CONFIG_I2C_VELLEMAN=m
+CONFIG_I2C_ALGOPCF=m
+CONFIG_I2C_ELEKTOR=m
+CONFIG_I2C_MAINBOARD=m
+CONFIG_I2C_ALI15X3=m
+CONFIG_I2C_HYDRA=m
+CONFIG_I2C_PIIX4=m
+CONFIG_I2C_VIA=m
+CONFIG_I2C_ISA=m
+CONFIG_I2C_CHARDEV=m
+
+#
+# Hardware sensors support
+#
+CONFIG_SENSORS=m
+CONFIG_SENSORS_ADM1021=m
+CONFIG_SENSORS_ADM9240=m
+CONFIG_SENSORS_GL518SM=m
+CONFIG_SENSORS_LM75=m
+CONFIG_SENSORS_LM78=m
+CONFIG_SENSORS_LM80=m
+CONFIG_SENSORS_SIS5595=m
+CONFIG_SENSORS_W83781D=m
+CONFIG_SENSORS_OTHER=m
+CONFIG_SENSORS_EEPROM=m
+CONFIG_SENSORS_LTC1710=m
+
+#
+# AGP support
+#
 CONFIG_AGP=m
 CONFIG_AGP_INTEL=y
 CONFIG_AGP_I810=y
@@ -667,6 +777,10 @@
 CONFIG_FTAPE=m
 CONFIG_ZFTAPE=m
 CONFIG_ZFT_DFLT_BLK_SZ=10240
+
+#
+# The compressor will be built as a module only!
+#
 CONFIG_ZFT_COMPRESSOR=m
 CONFIG_FT_NR_BUFFERS=3
 CONFIG_FT_PROC_FS=y
@@ -674,12 +788,20 @@
 # CONFIG_FT_FULL_DEBUG is not set
 # CONFIG_FT_NO_TRACE is not set
 # CONFIG_FT_NO_TRACE_AT_ALL is not set
+
+#
+# Hardware configuration
+#
 CONFIG_FT_STD_FDC=y
 # CONFIG_FT_MACH2 is not set
 # CONFIG_FT_PROBE_FC10 is not set
 # CONFIG_FT_ALT_FDC is not set
 CONFIG_FT_FDC_THR=8
 CONFIG_FT_FDC_MAX_RATE=2000
+
+#
+# ONLY for DEC Alpha architectures
+#
 CONFIG_FT_ALPHA_CLOCK=0
 
 #
@@ -706,6 +828,8 @@
 # CONFIG_QNX4FS_RW is not set
 CONFIG_ROMFS_FS=m
 CONFIG_EXT2_FS=y
+CONFIG_EXT3_FS=y 
+CONFIG_EXT3_FS_JFS_CHECK=y
 CONFIG_SYSV_FS=m
 CONFIG_UFS_FS=m
 # CONFIG_UFS_FS_WRITE is not set
@@ -721,6 +845,8 @@
 CONFIG_NFSD_SUN=y
 CONFIG_SUNRPC=m
 CONFIG_LOCKD=m
+CONFIG_NFSD_V3=y 
+CONFIG_NFS_V3=y
 CONFIG_SMB_FS=m
 CONFIG_NCP_FS=m
 CONFIG_NCPFS_PACKET_SIGNING=y
@@ -863,15 +989,31 @@
 CONFIG_AEDSP16=m
 CONFIG_AEDSP16_BASE=220
 CONFIG_MPU_BASE=330
+
+#
+# SC-6600 Audio Cards have no jumper switches at all
+#
 CONFIG_SC6600=y
+
+#
+# SC-6600 specific configuration
+#
 CONFIG_SC6600_JOY=y
 CONFIG_SC6600_CDROM=4
 CONFIG_SC6600_CDROMBASE=0
 CONFIG_AEDSP16_SBPRO=y
+
+#
+# Audio Excel DSP 16 [Sound Blaster Pro]
+#
 CONFIG_AEDSP16_BASE=220
 CONFIG_AEDSP16_SB_IRQ=5
 CONFIG_AEDSP16_SB_DMA=0
 CONFIG_AEDSP16_MPU401=y
+
+#
+# Audio Excel DSP 16 [MPU-401]
+#
 CONFIG_AEDSP16_MPU_IRQ=5
 
 #
Index: oldkernel/linux/configs/kernel-2.2.14-i686.config
diff -u linux/configs/kernel-2.2.14-i686.config:1.7 linux/configs/kernel-2.2.14-i686.config:1.8
--- linux/configs/kernel-2.2.14-i686.config:1.7	Thu Jun  1 13:01:16 2000
+++ linux/configs/kernel-2.2.14-i686.config	Fri Jul  7 15:36:42 2000
@@ -1,5 +1,5 @@
 #
-# Automatically generated by make menuconfig: don't edit
+# Automatically generated make config: don't edit
 #
 
 #
@@ -14,8 +14,7 @@
 # CONFIG_M486 is not set
 # CONFIG_M586 is not set
 # CONFIG_M586TSC is not set
-# CONFIG_M686 is not set
-CONFIG_M686FX=y
+CONFIG_M686=y
 CONFIG_X86_WP_WORKS_OK=y
 CONFIG_X86_INVLPG=y
 CONFIG_X86_BSWAP=y
@@ -25,11 +24,11 @@
 CONFIG_X86_PN_OFF=y
 CONFIG_X86_FX=y
 # CONFIG_X86_CPU_OPTIMIZATIONS is not set
+CONFIG_1GB=y
+# CONFIG_2GB is not set
 # CONFIG_MATH_EMULATION is not set
 CONFIG_MTRR=y
 # CONFIG_SMP is not set
-CONFIG_1GB=y
-# CONFIG_2GB is not set
 
 #
 # Loadable module support
@@ -86,6 +85,10 @@
 #
 CONFIG_BLK_DEV_FD=y
 CONFIG_BLK_DEV_IDE=y
+
+#
+# Please see Documentation/ide.txt for help/info on IDE drives
+#
 # CONFIG_BLK_DEV_HD_IDE is not set
 CONFIG_BLK_DEV_IDEDISK=y
 CONFIG_BLK_DEV_IDECD=m
@@ -104,27 +107,41 @@
 # CONFIG_BLK_DEV_VIA82C586 is not set
 # CONFIG_BLK_DEV_CMD646 is not set
 # CONFIG_IDE_CHIPSETS is not set
+
+#
+# Additional Block Devices
+#
 CONFIG_BLK_DEV_LOOP=m
 CONFIG_BLK_DEV_NBD=m
-# CONFIG_BLK_DEV_MD is not set
+CONFIG_BLK_DEV_MD=y
 CONFIG_AUTODETECT_RAID=y
-CONFIG_MD_LINEAR=m
-CONFIG_MD_STRIPED=m
-CONFIG_MD_MIRRORING=m
-CONFIG_MD_RAID5=m
+CONFIG_MD_LINEAR=y
+CONFIG_MD_STRIPED=y
+CONFIG_MD_MIRRORING=y
+CONFIG_MD_RAID5=y
 # CONFIG_MD_TRANSLUCENT is not set
 # CONFIG_MD_HSM is not set
+CONFIG_MD_BOOT=y
 CONFIG_BLK_DEV_RAM=y
 CONFIG_BLK_DEV_INITRD=y
 CONFIG_BLK_DEV_XD=m
 CONFIG_BLK_DEV_DAC960=y
+CONFIG_BLK_DEV_3WARE=y
 CONFIG_PARIDE_PARPORT=m
 CONFIG_PARIDE=m
+
+#
+# Parallel IDE high-level drivers
+#
 CONFIG_PARIDE_PD=m
 CONFIG_PARIDE_PCD=m
 CONFIG_PARIDE_PF=m
 CONFIG_PARIDE_PT=m
 CONFIG_PARIDE_PG=m
+
+#
+# Parallel IDE protocol modules
+#
 CONFIG_PARIDE_ATEN=m
 CONFIG_PARIDE_BPCK=m
 CONFIG_PARIDE_COMM=m
@@ -161,7 +178,16 @@
 CONFIG_NETLINK_DEV=y
 CONFIG_IP_TRANSPARENT_PROXY=y
 CONFIG_IP_MASQUERADE=y
+
+#
+# Protocol-specific masquerading support will be built as modules.
+#
+# CONFIG_IP_MASQUERADE_UDP_LOOSE is not set
 CONFIG_IP_MASQUERADE_ICMP=y
+
+#
+# Protocol-specific masquerading support will be built as modules.
+#
 CONFIG_IP_MASQUERADE_MOD=y
 CONFIG_IP_MASQUERADE_IPAUTOFW=m
 CONFIG_IP_MASQUERADE_IPPORTFW=m
@@ -180,9 +206,17 @@
 CONFIG_IP_ALIAS=y
 # CONFIG_ARPD is not set
 CONFIG_SYN_COOKIES=y
+
+#
+# (it is safe to leave these untouched)
+#
 CONFIG_INET_RARP=m
 CONFIG_SKB_LARGE=y
 # CONFIG_IPV6 is not set
+
+#
+#  
+#
 CONFIG_IPX=m
 # CONFIG_IPX_INTERN is not set
 # CONFIG_SPX is not set
@@ -212,11 +246,19 @@
 # SCSI support
 #
 CONFIG_SCSI=y
+
+#
+# SCSI support type (disk, tape, CD-ROM)
+#
 CONFIG_BLK_DEV_SD=y
 CONFIG_CHR_DEV_ST=y
 CONFIG_BLK_DEV_SR=y
 CONFIG_BLK_DEV_SR_VENDOR=y
 CONFIG_CHR_DEV_SG=m
+
+#
+# Some SCSI devices (e.g. CD jukebox) support multiple LUNs
+#
 # CONFIG_SCSI_MULTI_LUN is not set
 CONFIG_SCSI_CONSTANTS=y
 CONFIG_SCSI_LOGGING=y
@@ -230,7 +272,7 @@
 CONFIG_SCSI_AHA1542=m
 CONFIG_SCSI_AHA1740=m
 CONFIG_SCSI_AIC7XXX=y
-# CONFIG_AIC7XXX_TCQ_ON_BY_DEFAULT is not set
+CONFIG_AIC7XXX_TCQ_ON_BY_DEFAULT=y
 CONFIG_AIC7XXX_CMDS_PER_DEVICE=8
 CONFIG_AIC7XXX_PROC_STATS=y
 CONFIG_AIC7XXX_RESET_DELAY=5
@@ -275,11 +317,13 @@
 CONFIG_SCSI_SYM53C8XX=y
 CONFIG_SCSI_NCR53C8XX_DEFAULT_TAGS=8
 CONFIG_SCSI_NCR53C8XX_MAX_TAGS=32
-CONFIG_SCSI_NCR53C8XX_SYNC=40
+CONFIG_SCSI_NCR53C8XX_SYNC=80
 CONFIG_SCSI_NCR53C8XX_PROFILE=y
 # CONFIG_SCSI_NCR53C8XX_IOMAPPED is not set
 CONFIG_SCSI_NCR53C8XX_SYMBIOS_COMPAT=y
-CONFIG_SCSI_NCR53C8XX_PQS_PDS=y
+CONFIG_SCSI_NCR53C8XX_PQS_PDS=y 
+# CONFIG_SCSI_NCR53C8XX_IARB is not set 
+CONFIG_SCSI_NCR53C8XX_INTEGRITY_CHECK=y
 CONFIG_SCSI_PAS16=m
 CONFIG_SCSI_PCI2000=m
 CONFIG_SCSI_PCI2220I=m
@@ -399,6 +443,10 @@
 CONFIG_IPDDP_DECAP=y
 CONFIG_PLIP=m
 CONFIG_PPP=m
+
+#
+# CCP compressors for PPP are only built as modules.
+#
 CONFIG_SLIP=m
 CONFIG_SLIP_COMPRESSED=y
 CONFIG_SLIP_SMART=y
@@ -448,28 +496,52 @@
 # IrDA subsystem support
 #
 CONFIG_IRDA=m
+
+#
+# IrDA protocols
+#
 CONFIG_IRLAN=m
 CONFIG_IRCOMM=m
 CONFIG_IRLPT=m
 CONFIG_IRLPT_CLIENT=m
 CONFIG_IRLPT_SERVER=m
 CONFIG_IRDA_OPTIONS=y
+
+#
+#    IrDA options
+#
 CONFIG_IRDA_CACHE_LAST_LSAP=y
 CONFIG_IRDA_FAST_RR=y
 # CONFIG_IRDA_DEBUG is not set
 CONFIG_IRDA_COMPRESSION=y
+
+#
+#    IrDA compressors
+#
 CONFIG_IRDA_DEFLATE=m
 
 #
 # Infrared-port device drivers
 #
+
+#
+# SIR device drivers
+#
 CONFIG_IRTTY_SIR=m
 CONFIG_IRPORT_SIR=m
+
+#
+# FIR device drivers
+#
 CONFIG_NSC_FIR=m
 CONFIG_WINBOND_FIR=m
 CONFIG_SHARP_FIR=m
 CONFIG_TOSHIBA_FIR=m
 CONFIG_SMC_IRCC_FIR=m
+
+#
+# Dongle support
+#
 CONFIG_DONGLE=y
 CONFIG_ESI_DONGLE=m
 CONFIG_ACTISYS_DONGLE=m
@@ -636,6 +708,44 @@
 # CONFIG_MIXCOMWD is not set
 CONFIG_NVRAM=m
 CONFIG_RTC=y
+
+#
+# I2C support
+#
+CONFIG_I2C=m
+CONFIG_I2C_ALGOBIT=m
+CONFIG_I2C_PHILIPSPAR=m
+CONFIG_I2C_ELV=m
+CONFIG_I2C_VELLEMAN=m
+CONFIG_I2C_ALGOPCF=m
+CONFIG_I2C_ELEKTOR=m
+CONFIG_I2C_MAINBOARD=m
+CONFIG_I2C_ALI15X3=m
+CONFIG_I2C_HYDRA=m
+CONFIG_I2C_PIIX4=m
+CONFIG_I2C_VIA=m
+CONFIG_I2C_ISA=m
+CONFIG_I2C_CHARDEV=m
+
+#
+# Hardware sensors support
+#
+CONFIG_SENSORS=m
+CONFIG_SENSORS_ADM1021=m
+CONFIG_SENSORS_ADM9240=m
+CONFIG_SENSORS_GL518SM=m
+CONFIG_SENSORS_LM75=m
+CONFIG_SENSORS_LM78=m
+CONFIG_SENSORS_LM80=m
+CONFIG_SENSORS_SIS5595=m
+CONFIG_SENSORS_W83781D=m
+CONFIG_SENSORS_OTHER=m
+CONFIG_SENSORS_EEPROM=m
+CONFIG_SENSORS_LTC1710=m
+
+#
+# AGP support
+#
 CONFIG_AGP=m
 CONFIG_AGP_INTEL=y
 CONFIG_AGP_I810=y
@@ -674,6 +784,10 @@
 CONFIG_FTAPE=m
 CONFIG_ZFTAPE=m
 CONFIG_ZFT_DFLT_BLK_SZ=10240
+
+#
+# The compressor will be built as a module only!
+#
 CONFIG_ZFT_COMPRESSOR=m
 CONFIG_FT_NR_BUFFERS=3
 CONFIG_FT_PROC_FS=y
@@ -681,12 +795,20 @@
 # CONFIG_FT_FULL_DEBUG is not set
 # CONFIG_FT_NO_TRACE is not set
 # CONFIG_FT_NO_TRACE_AT_ALL is not set
+
+#
+# Hardware configuration
+#
 CONFIG_FT_STD_FDC=y
 # CONFIG_FT_MACH2 is not set
 # CONFIG_FT_PROBE_FC10 is not set
 # CONFIG_FT_ALT_FDC is not set
 CONFIG_FT_FDC_THR=8
 CONFIG_FT_FDC_MAX_RATE=2000
+
+#
+# ONLY for DEC Alpha architectures
+#
 CONFIG_FT_ALPHA_CLOCK=0
 
 #
@@ -713,6 +835,8 @@
 # CONFIG_QNX4FS_RW is not set
 CONFIG_ROMFS_FS=m
 CONFIG_EXT2_FS=y
+CONFIG_EXT3_FS=y 
+CONFIG_EXT3_FS_JFS_CHECK=y
 CONFIG_SYSV_FS=m
 CONFIG_UFS_FS=m
 # CONFIG_UFS_FS_WRITE is not set
@@ -728,6 +852,8 @@
 CONFIG_NFSD_SUN=y
 CONFIG_SUNRPC=m
 CONFIG_LOCKD=m
+CONFIG_NFSD_V3=y 
+CONFIG_NFS_V3=y
 CONFIG_SMB_FS=m
 CONFIG_NCP_FS=m
 CONFIG_NCPFS_PACKET_SIGNING=y
@@ -870,15 +996,31 @@
 CONFIG_AEDSP16=m
 CONFIG_AEDSP16_BASE=220
 CONFIG_MPU_BASE=330
+
+#
+# SC-6600 Audio Cards have no jumper switches at all
+#
 CONFIG_SC6600=y
+
+#
+# SC-6600 specific configuration
+#
 CONFIG_SC6600_JOY=y
 CONFIG_SC6600_CDROM=4
 CONFIG_SC6600_CDROMBASE=0
 CONFIG_AEDSP16_SBPRO=y
+
+#
+# Audio Excel DSP 16 [Sound Blaster Pro]
+#
 CONFIG_AEDSP16_BASE=220
 CONFIG_AEDSP16_SB_IRQ=5
 CONFIG_AEDSP16_SB_DMA=0
 CONFIG_AEDSP16_MPU401=y
+
+#
+# Audio Excel DSP 16 [MPU-401]
+#
 CONFIG_AEDSP16_MPU_IRQ=5
 
 #
Index: oldkernel/linux/drivers/block/3w-xxxx.c
diff -u /dev/null linux/drivers/block/3w-xxxx.c:1.1
--- /dev/null	Mon Jul 31 21:15:04 2000
+++ linux/drivers/block/3w-xxxx.c	Fri Jul  7 16:18:17 2000
@@ -0,0 +1,2387 @@
+/* 
+   3w-xxxx.c -- 3ware Storage Controller device driver for Linux.
+
+   Written By: Adam Radford <linux@3ware.com>
+   Copyright (C) 1999 3ware Inc.
+
+   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; version 2 of the License.
+
+   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.                              
+
+   NO WARRANTY                                                               
+   THE PROGRAM IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OR        
+   CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED INCLUDING, WITHOUT      
+   LIMITATION, ANY WARRANTIES OR CONDITIONS OF TITLE, NON-INFRINGEMENT,      
+   MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. Each Recipient is    
+   solely responsible for determining the appropriateness of using and       
+   distributing the Program and assumes all risks associated with its        
+   exercise of rights under this Agreement, including but not limited to     
+   the risks and costs of program errors, damage to or loss of data,         
+   programs or equipment, and unavailability or interruption of operations.  
+
+   DISCLAIMER OF LIABILITY                                                   
+   NEITHER RECIPIENT NOR ANY CONTRIBUTORS SHALL HAVE ANY LIABILITY FOR ANY   
+   DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL        
+   DAMAGES (INCLUDING WITHOUT LIMITATION LOST PROFITS), HOWEVER CAUSED AND   
+   ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR     
+   TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE    
+   USE OR DISTRIBUTION OF THE PROGRAM OR THE EXERCISE OF ANY RIGHTS GRANTED  
+   HEREUNDER, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGES             
+
+   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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA 
+
+   Bugs/Comments/Suggestions should be mailed to:                            
+   linux@3ware.com
+
+   For more information, goto:
+   http://www.3ware.com
+*/
+
+#include <linux/config.h>
+#include <linux/version.h>
+
+#ifdef MODULE
+#include <linux/modversions.h>
+#include <linux/module.h>
+char kernel_version[] = UTS_RELEASE;
+MODULE_AUTHOR ("3ware Inc.");
+MODULE_DESCRIPTION ("3ware Storage Controller Linux Driver");
+#endif
+
+#include <linux/kernel.h>
+#include <linux/pci.h>
+#include <linux/time.h>
+#include <linux/proc_fs.h>
+#include <linux/sched.h>
+#include <linux/ioport.h>
+#include <linux/blk.h>
+#include <linux/hdreg.h>
+#include <linux/string.h>
+#include <linux/delay.h>
+#include <linux/smp.h>
+#include <asm/errno.h>
+#include <asm/io.h>
+#include <asm/irq.h>
+#include <asm/uaccess.h>
+#include <asm/spinlock.h>
+
+#include "../scsi/sd.h"
+#include "../scsi/scsi.h"
+#include "../scsi/hosts.h"
+
+#include "3w-xxxx.h"
+
+struct proc_dir_entry tw_scsi_proc_entry = 
+/* We will eventually need to be added to proc_fs.h */
+{
+#if !defined(PROC_SCSI_3W_XXXX)
+  PROC_SCSI_IDESCSI,
+#else
+  PROC_SCSI_3W_XXXX,
+#endif
+  7, "3w-xxxx", 
+  S_IFDIR | S_IRUGO | S_IXUGO, 2
+};
+
+/* Globals */
+char *tw_driver_version="1.0.000";
+TW_Device_Extension *tw_device_extension_list[TW_MAX_SLOT];
+int tw_device_extension_count = 0;
+
+/* Functions */
+
+/* This function will complete an aen request from the isr */
+int tw_aen_complete(TW_Device_Extension *tw_dev, int request_id) 
+{
+  TW_Param *param;
+  unsigned short aen, aen_code;
+
+  if (tw_dev->alignment_virtual_address[request_id] == NULL) {
+    printk(KERN_WARNING "3w-xxxx: tw_aen_complete(): Bad alignment "
+	   "virtual address.\n");
+    return 1;
+  }
+  param = (TW_Param *)tw_dev->alignment_virtual_address[request_id];
+  aen = *(unsigned short *)(param->data);
+  aen_code = (aen & 0x0ff);
+  dprintk(KERN_NOTICE "3w-xxxx: tw_aen_complete(): Queue'd code 0x%x\n", 
+	  aen_code);
+  /* Now queue the code */
+  tw_dev->aen_queue[tw_dev->aen_tail] = aen_code;
+  if (tw_dev->aen_tail == TW_Q_LENGTH - 1)
+    tw_dev->aen_tail = TW_Q_START;
+  else
+    tw_dev->aen_tail = tw_dev->aen_tail + 1;
+  if (tw_dev->aen_head == tw_dev->aen_tail) {
+    if (tw_dev->aen_head == TW_Q_LENGTH - 1)
+      tw_dev->aen_head = TW_Q_START;
+    else
+      tw_dev->aen_head = tw_dev->aen_head + 1;
+  }
+  tw_dev->state[request_id] = TW_S_COMPLETED;
+  tw_state_request_finish(tw_dev, request_id);
+
+  return 0;
+} /* End tw_aen_complete() */
+
+/* This function will drain the aen queue after a soft reset */
+int tw_aen_drain_queue(TW_Device_Extension *tw_dev)
+{
+  TW_Command *command_packet;
+  TW_Param *param;
+  int tries = 0;
+  int request_id = 0;
+  u32 command_que_value = 0, command_que_addr;
+  u32 status_reg_value = 0, status_reg_addr;
+  u32 param_value;
+  TW_Response_Queue response_queue;
+  u32 response_que_addr;
+  unsigned short aen;
+  unsigned short aen_code;
+  int finished = 0;
+  int first_reset = 0;
+  int queue = 0;
+  int imax, i;
+  int found = 0;
+
+  dprintk(KERN_NOTICE "3w-xxxx: tw_aen_drain_queue()\n");
+
+  command_que_addr = tw_dev->registers.command_que_addr;
+  status_reg_addr = tw_dev->registers.status_reg_addr;
+  response_que_addr = tw_dev->registers.response_que_addr;
+
+  if (tw_poll_status(tw_dev, TW_STATUS_ATTENTION_INTERRUPT, 15)) {
+    printk(KERN_WARNING "3w-xxxx: tw_aen_drain_queue(): No attention "
+	   "interrupt for card %d\n", tw_dev->host->host_no);
+    return 1;
+  }
+
+  /* Initialize command packet */
+  if (tw_dev->command_packet_virtual_address[request_id] == NULL) {
+    printk(KERN_WARNING "3w-xxxx: tw_aen_drain_queue(): Bad command packet "
+	   "virtual address.\n");
+    return 1;
+  }
+  command_packet = 
+    (TW_Command *)tw_dev->command_packet_virtual_address[request_id];
+  memset(command_packet, 0, sizeof(TW_Sector));
+  command_packet->byte0.opcode = TW_OP_GET_PARAM;
+  command_packet->byte0.sgl_offset = 2;
+  command_packet->size = 4;
+  command_packet->request_id = request_id;
+  command_packet->byte3.unit = 0;
+  command_packet->byte3.host_id = 0;
+  command_packet->status = 0;
+  command_packet->flags = 0;
+  command_packet->byte6.parameter_count = 1;
+  command_que_value = tw_dev->command_packet_physical_address[request_id];
+  if (command_que_value == 0) {
+    printk(KERN_WARNING "3w-xxxx: tw_aen_drain_queue(): Bad command packet "
+	   "physical address.\n");
+    return 1;
+  }
+
+  /* Now setup the param */
+  if (tw_dev->alignment_virtual_address[request_id] == NULL) {
+    printk(KERN_WARNING "3w-xxxx: tw_aen_drain_queue(): Bad alignment "
+	   "virtual address.\n");
+    return 1;
+  }
+  param = (TW_Param *)tw_dev->alignment_virtual_address[request_id];
+  memset(param, 0, sizeof(TW_Sector));
+  param->table_id = 0x401; /* AEN table */
+  param->parameter_id = 2; /* Unit code */
+  param->parameter_size_bytes = 2;
+  param_value = tw_dev->alignment_physical_address[request_id];
+  if (param_value == 0) {
+    printk(KERN_WARNING "3w-xxxx: tw_aen_drain_queue(): Bad alignment "
+	   "physical address.\n");
+    return 1;
+  }
+  command_packet->byte8.param.sgl[0].address = param_value;
+  command_packet->byte8.param.sgl[0].length = sizeof(TW_Sector);
+
+  imax = TW_POLL_MAX_RETRIES;
+
+  /* Now drain the controller's aen queue */
+  do {
+    /* Post command packet */
+    outl(command_que_value, command_que_addr);
+    
+    /* Now poll for completion */
+    for (i=0;i<imax;i++) {
+      mdelay(10);
+      status_reg_value = inl(status_reg_addr);
+      if (tw_check_bits(status_reg_value)) {
+	printk(KERN_WARNING "3w-xxxx: tw_aen_drain_queue(): Unexpected "
+	       "bits.\n");
+	return 1;
+      }
+      if ((status_reg_value & TW_STATUS_RESPONSE_QUEUE_EMPTY) == 0) {
+	response_queue.value = inl(response_que_addr);
+	request_id = (unsigned char)response_queue.u.response_id;
+    
+	if (request_id != 0) {
+	  /* Unexpected request id */
+	  printk(KERN_WARNING "3w-xxxx: tw_aen_drain_queue(): Unexpected "
+		 "request id.\n");
+	  return 1;
+	}
+	
+	if (command_packet->status != 0) {
+	  if (command_packet->flags != TW_AEN_TABLE_UNDEFINED) {
+	    /* Bad response */
+	    printk(KERN_WARNING "3w-xxxx: tw_aen_drain_queue(): Bad "
+		   "response, flags = 0x%x.\n", command_packet->flags);
+	    return 1;
+	  } else {
+	    /* We know this is a 3w-1x00, and doesn't support aen's */
+	    return 0;
+	  }
+	}
+
+	/* Now check the aen */
+	aen = *(unsigned short *)(param->data);
+	aen_code = (aen & 0x0ff);
+	queue = 0;
+	switch (aen_code) {
+	case TW_AEN_QUEUE_EMPTY:
+	  dprintk(KERN_NOTICE "3w-xxxx: tw_aen_drain_queue(): Found "
+		  "TW_AEN_QUEUE_EMPTY.\n");
+	  if (first_reset != 1)
+	    continue;
+	  else
+	    finished = 1;
+	  break;
+	case TW_AEN_SOFT_RESET:
+	  dprintk(KERN_NOTICE "3w-xxxx: tw_aen_drain_queue(): Found "
+		  "TW_AEN_SOFT_RESET.\n");
+	  if (first_reset == 0) 
+	    first_reset = 1;
+	  else
+	    queue = 1;
+	  break;
+	case TW_AEN_DEGRADED_MIRROR:
+	  dprintk(KERN_NOTICE "3w-xxxx: tw_aen_drain_queue(): Found "
+		  "TW_AEN_DEGRADED_MIRROR.\n");
+	  queue = 1;
+	  break;
+	case TW_AEN_CONTROLLER_ERROR:
+	  dprintk(KERN_NOTICE "3w-xxxx: tw_aen_drain_queue(): Found "
+		  "TW_AEN_CONTROLLER_ERROR.\n");
+	  queue = 1;
+	  break;
+	case TW_AEN_REBUILD_FAIL:
+	  dprintk(KERN_NOTICE "3w-xxxx: tw_aen_drain_queue(): Found "
+		  "TW_AEN_REBUILD_FAIL.\n");
+	  queue = 1;
+	  break;
+	case TW_AEN_REBUILD_DONE:
+	  dprintk(KERN_NOTICE "3w-xxxx: tw_aen_drain_queue(): Found "
+		  "TW_AEN_REBUILD_DONE.\n");
+	  queue = 1;
+	  break;
+	case TW_AEN_QUEUE_FULL:
+	  dprintk(KERN_NOTICE "3w-xxxx: tw_aen_drain_queue(): Found "
+		  "TW_AEN_QUEUE_FULL.\n");
+	  queue = 1;
+	  break;
+	default:
+	  dprintk(KERN_WARNING "3w-xxxx: tw_aen_drain_queue(): Unknown AEN "
+		  "code 0x%x.\n", aen_code);
+	  queue = 1;
+	}
+
+	/* Now put the aen on the aen_queue */
+	if (queue == 1) {
+	  tw_dev->aen_queue[tw_dev->aen_tail] = aen_code;
+	  if (tw_dev->aen_tail == TW_Q_LENGTH - 1)
+	    tw_dev->aen_tail = TW_Q_START;
+	  else
+	    tw_dev->aen_tail = tw_dev->aen_tail + 1;
+	  if (tw_dev->aen_head == tw_dev->aen_tail) {
+	    if (tw_dev->aen_head == TW_Q_LENGTH - 1)
+	      tw_dev->aen_head = TW_Q_START;
+	    else
+	      tw_dev->aen_head = tw_dev->aen_head + 1;
+	  }
+	}
+	found = 1;
+	break;
+      }
+    }
+    if (found == 0) {
+      printk(KERN_WARNING "3w-xxxx: tw_aen_drain_queue(): Response never "
+	     "received.\n");
+      return 1;
+    }
+    tries++;
+  } while ((tries < TW_MAX_AEN_TRIES) && (finished == 0));
+
+  if (tries >=TW_MAX_AEN_TRIES) {
+    printk(KERN_WARNING "3w-xxxx: tw_aen_drain_queue(): Aen queue error.\n");
+    return 1;
+  }
+
+  return 0;
+} /* End tw_aen_drain_queue() */
+
+/* This function will read the aen queue from the isr */
+int tw_aen_read_queue(TW_Device_Extension *tw_dev, int request_id) 
+{
+  TW_Command *command_packet;
+  TW_Param *param;
+  u32 command_que_value = 0, command_que_addr;
+  u32 status_reg_value = 0, status_reg_addr;
+  u32 param_value = 0;
+
+  dprintk(KERN_NOTICE "3w-xxxx: tw_aen_read_queue()\n");
+  command_que_addr = tw_dev->registers.command_que_addr;
+  status_reg_addr = tw_dev->registers.status_reg_addr;
+
+  status_reg_value = inl(status_reg_addr);
+  if (tw_check_bits(status_reg_value)) {
+    printk(KERN_WARNING "3w-xxxx: tw_aen_read_queue(): Unexpected bits.\n");
+    return 1;
+  }
+  if (tw_dev->command_packet_virtual_address[request_id] == NULL) {
+    printk(KERN_WARNING "3w-xxxx: tw_aen_read_queue(): Bad command packet "
+	   "virtual address.\n");
+    return 1;
+  }
+  command_packet = 
+    (TW_Command *)tw_dev->command_packet_virtual_address[request_id];
+  memset(command_packet, 0, sizeof(TW_Sector));
+  command_packet->byte0.opcode = TW_OP_GET_PARAM;
+  command_packet->byte0.sgl_offset = 2;
+  command_packet->size = 4;
+  command_packet->request_id = request_id;
+  command_packet->byte3.unit = 0;
+  command_packet->byte3.host_id = 0;
+  command_packet->status = 0;
+  command_packet->flags = 0;
+  command_packet->byte6.parameter_count = 1;
+  command_que_value = tw_dev->command_packet_physical_address[request_id];
+  if (command_que_value == 0) {
+    printk(KERN_WARNING "3w-xxxx: tw_aen_read_queue(): Bad command packet "
+	   "physical address.\n");
+    return 1;
+  }
+  /* Now setup the param */
+  if (tw_dev->alignment_virtual_address[request_id] == NULL) {
+    printk(KERN_WARNING "3w-xxxx: tw_aen_read_queue(): Bad alignment "
+	   "virtual address.\n");
+    return 1;
+  }
+  param = (TW_Param *)tw_dev->alignment_virtual_address[request_id];
+  memset(param, 0, sizeof(TW_Sector));
+  param->table_id = 0x401; /* AEN table */
+  param->parameter_id = 2; /* Unit code */
+  param->parameter_size_bytes = 2;
+  param_value = tw_dev->alignment_physical_address[request_id];
+  if (param_value == 0) {
+    printk(KERN_WARNING "3w-xxxx: tw_aen_read_queue(): Bad alignment "
+	   "physical address.\n");
+    return 1;
+  }
+  command_packet->byte8.param.sgl[0].address = param_value;
+  command_packet->byte8.param.sgl[0].length = sizeof(TW_Sector);
+
+  /* Now post the command packet */
+  if ((status_reg_value & TW_STATUS_COMMAND_QUEUE_FULL) == 0) {
+    dprintk(KERN_WARNING "3w-xxxx: tw_aen_read_queue(): Post succeeded.\n");
+    tw_dev->srb[request_id] = 0; /* Flag internal command */
+    tw_dev->state[request_id] = TW_S_POSTED;
+    outl(command_que_value, command_que_addr);
+  }
+  else {
+    printk(KERN_WARNING "3w-xxxx: tw_aen_read_queue(): Post failed, will "
+	   "retry.\n");
+    return 1;
+  }
+
+  return 0;
+} /* End tw_aen_read_queue() */
+
+/* This function will allocate memory and check if it is 16 d-word aligned */
+int tw_allocate_memory(TW_Device_Extension *tw_dev, int request_id, 
+		       int size, int which)
+{
+  u32 *virt_addr;
+
+  dprintk(KERN_NOTICE "3w-xxxx: tw_allocate_memory()\n");
+
+  if (which == 0) {
+    /* Allocate command packet memory */
+    virt_addr = kmalloc(size, GFP_ATOMIC);
+    if (virt_addr == NULL) {
+      printk(KERN_WARNING "3w-xxxx: tw_allocate_memory(): kmalloc() "
+	     "failed.\n");
+      return 1;
+    }
+    if ((u32)virt_addr % TW_ALIGNMENT) {
+      printk(KERN_WARNING "3w-xxxx: tw_allocate_memory(): Found unaligned "
+	     "address.\n");
+      return 1;
+    }
+    tw_dev->command_packet_virtual_address[request_id] = virt_addr;
+    tw_dev->command_packet_physical_address[request_id] = 
+      virt_to_bus(virt_addr);
+  } else {
+    /* Allocate generic buffer */
+    virt_addr = kmalloc(size, GFP_ATOMIC);
+    if (virt_addr == NULL) {
+      printk(KERN_WARNING "3w-xxxx: tw_allocate_memory(): kmalloc() "
+	     "failed.\n");
+      return 1;
+    }
+    if ((u32)virt_addr % TW_ALIGNMENT) {
+      printk(KERN_WARNING "3w-xxxx: tw_allocate_memory(): Found unaligned "
+	     "address.\n");
+      return 1;
+    }
+    tw_dev->alignment_virtual_address[request_id] = virt_addr;
+    tw_dev->alignment_physical_address[request_id] = virt_to_bus(virt_addr);
+  }
+  return 0;
+} /* End tw_allocate_memory() */
+
+/* This function will check the status register for unexpected bits */
+int tw_check_bits(u32 status_reg_value)
+{
+  if ((status_reg_value & TW_STATUS_EXPECTED_BITS) != 
+      TW_STATUS_EXPECTED_BITS) {  
+    printk(KERN_WARNING "3w-xxxx: tw_check_bits(): No expected bits (0x%x).\n",
+	   status_reg_value);
+    return 1;
+  }
+  if ((status_reg_value & TW_STATUS_UNEXPECTED_BITS) != 0) {
+    printk(KERN_WARNING "3w-xxxx: tw_check_bits(): Found unexpected "
+	   "bits (0x%x).\n",
+	   status_reg_value);
+    return 1;
+  }
+  return 0;
+} /* End tw_check_bits() */
+
+/* This function will report controller error status */
+int tw_check_errors(TW_Device_Extension *tw_dev) 
+{
+  u32 status_reg_addr, status_reg_value;
+  
+  status_reg_addr = tw_dev->registers.status_reg_addr;
+  status_reg_value = inl(status_reg_addr);
+
+  if (TW_STATUS_ERRORS(status_reg_value) || 
+      tw_check_bits(status_reg_value))
+    return 1;
+  return 0;
+} /* End tw_check_errors() */
+
+/* This function will clear the attention interrupt */
+void tw_clear_attention_interrupt(TW_Device_Extension *tw_dev)
+{
+  u32 control_reg_addr, control_reg_value;
+  
+  control_reg_addr = tw_dev->registers.control_reg_addr;
+  control_reg_value = TW_CONTROL_CLEAR_ATTENTION_INTERRUPT;
+  outl(control_reg_value, control_reg_addr);
+} /* End tw_clear_attention_interrupt() */
+
+/* This function will clear the host interrupt */
+void tw_clear_host_interrupt(TW_Device_Extension *tw_dev)
+{
+  u32 control_reg_addr, control_reg_value;
+
+  control_reg_addr = tw_dev->registers.control_reg_addr;
+  control_reg_value = TW_CONTROL_CLEAR_HOST_INTERRUPT;
+  outl(control_reg_value, control_reg_addr);
+} /* End tw_clear_host_interrupt() */
+
+/* This function is called by tw_scsi_proc_info */
+static int tw_copy_info(TW_Info *info, char *fmt, ...) 
+{
+  va_list args;
+  char buf[81];
+  int len;
+  
+  va_start(args, fmt);
+  len = vsprintf(buf, fmt, args);
+  va_end(args);
+  tw_copy_mem_info(info, buf, len);
+  return len;
+} /* End tw_copy_info() */
+
+/* This function is called by tw_scsi_proc_info */
+static void tw_copy_mem_info(TW_Info *info, char *data, int len)
+{
+  if (info->position + len > info->length)
+    len = info->length - info->position;
+
+  if (info->position + len < info->offset) {
+    info->position += len;
+    return;
+  }
+  if (info->position < info->offset) {
+    data += (info->offset - info->position);
+    len  -= (info->offset - info->position);
+  }
+  if (len > 0) {
+    memcpy(info->buffer + info->position, data, len);
+    info->position += len;
+  }
+} /* End tw_copy_mem_info() */
+
+/* This function will disable interrupts on the controller */  
+void tw_disable_interrupts(TW_Device_Extension *tw_dev) 
+{
+  u32 control_reg_value, control_reg_addr;
+
+  control_reg_addr = tw_dev->registers.control_reg_addr;
+  control_reg_value = TW_CONTROL_DISABLE_INTERRUPTS;
+  outl(control_reg_value, control_reg_addr);
+} /* End tw_disable_interrupts() */
+
+/* This function will empty the response que */
+int tw_empty_response_que(TW_Device_Extension *tw_dev) 
+{
+  u32 status_reg_addr, status_reg_value;
+  u32 response_que_addr, response_que_value;
+
+  status_reg_addr = tw_dev->registers.status_reg_addr;
+  response_que_addr = tw_dev->registers.response_que_addr;
+  
+  status_reg_value = inl(status_reg_addr);
+
+  if (tw_check_bits(status_reg_value)) {
+    printk(KERN_WARNING "3w-xxxx: tw_empty_response_queue(): "
+	   "Unexpected bits 1.\n");
+    return 1;
+  }
+  
+  while ((status_reg_value & TW_STATUS_RESPONSE_QUEUE_EMPTY) == 0) {
+    response_que_value = inl(response_que_addr);
+    status_reg_value = inl(status_reg_addr);
+    if (tw_check_bits(status_reg_value)) {
+      printk(KERN_WARNING "3w-xxxx: tw_empty_response_queue(): "
+	     "Unexpected bits 2.\n");
+      return 1;
+    }
+  }
+  return 0;
+} /* End tw_empty_response_que() */
+
+/* This function will enable interrupts on the controller */
+void tw_enable_interrupts(TW_Device_Extension *tw_dev)
+{
+  u32 control_reg_value, control_reg_addr;
+
+  control_reg_addr = tw_dev->registers.control_reg_addr;
+  control_reg_value = (TW_CONTROL_CLEAR_ATTENTION_INTERRUPT |
+		       TW_CONTROL_UNMASK_RESPONSE_INTERRUPT |
+		       TW_CONTROL_ENABLE_INTERRUPTS);
+  outl(control_reg_value, control_reg_addr);
+} /* End tw_enable_interrupts() */
+
+/* This function will find and initialize all cards */
+int tw_findcards(Scsi_Host_Template *tw_host) 
+{
+  int numcards = 0, tries = 0, error = 0;
+  struct Scsi_Host *host;
+  TW_Device_Extension *tw_dev;
+  TW_Device_Extension *tw_dev2;
+  struct pci_dev *tw_pci_dev = pci_devices;
+  u32 status_reg_value;
+
+  dprintk(KERN_NOTICE "3w-xxxx: tw_findcards()\n");
+  while ((tw_pci_dev = pci_find_device(TW_VENDOR_ID, TW_DEVICE_ID, 
+				       tw_pci_dev))) {
+    /* Prepare temporary device extension */
+    tw_dev=(TW_Device_Extension *)kmalloc(sizeof(TW_Device_Extension), 
+					  GFP_ATOMIC);
+    if (tw_dev == NULL) {
+      printk(KERN_WARNING "3w-xxxx: tw_findcards(): kmalloc() failed for "
+	     "card %d.\n", numcards);
+      continue;
+    }
+    memset(tw_dev, 0, sizeof(TW_Device_Extension));
+
+    error = tw_initialize_device_extension(tw_dev);
+    if (error) {
+      printk(KERN_WARNING "3w-xxxx: tw_findcards(): Couldn't initialize "
+	     "device extension for card %d.\n", numcards);
+      tw_free_device_extension(tw_dev);
+      kfree(tw_dev);
+      continue;
+    }
+
+    /* Calculate the cards register addresses */
+    tw_dev->registers.base_addr = tw_pci_dev->base_address[0];
+    tw_dev->registers.control_reg_addr = 
+      (tw_pci_dev->base_address[0] & ~15);
+    tw_dev->registers.status_reg_addr = 
+      ((tw_pci_dev->base_address[0] & ~15) + 0x4);
+    tw_dev->registers.command_que_addr = 
+      ((tw_pci_dev->base_address[0] & ~15) + 0x8);
+    tw_dev->registers.response_que_addr = 
+      ((tw_pci_dev->base_address[0] & ~15) + 0xC);
+
+    /* Save pci_dev struct to device extension */
+    tw_dev->tw_pci_dev = tw_pci_dev;
+
+    /* Poll status register for 60 secs for 'Controller Ready' flag */
+    if (tw_poll_status(tw_dev, TW_STATUS_MICROCONTROLLER_READY, 60)) {
+      printk(KERN_WARNING "3w-xxxx: tw_findcards(): Microcontroller not "
+	     "ready for card %d.\n", numcards);
+      tw_free_device_extension(tw_dev);
+      kfree(tw_dev);
+      continue;
+    }
+
+    /* Disable interrupts on the card */
+    tw_disable_interrupts(tw_dev);
+
+    while (tries < TW_MAX_RESET_TRIES) {
+      /* Do soft reset */
+      tw_soft_reset(tw_dev);
+
+      error = tw_aen_drain_queue(tw_dev);
+      if (error) {
+	printk(KERN_WARNING "3w-xxxx: tw_findcards(): No attention "
+	       "interrupt for card %d.\n", numcards);
+	tries++;
+	continue;
+      }
+
+      /* Check for controller errors */
+      if (tw_check_errors(tw_dev)) {
+	printk(KERN_WARNING "3w-xxxx: tw_findcards(): Controller errors "
+	       "found, soft resetting card %d.\n", numcards);
+	tries++;
+	continue;
+      }
+
+      /* Empty the response queue */
+      error = tw_empty_response_que(tw_dev);
+      if (error) {
+	printk(KERN_WARNING "3w-xxxx: tw_findcards(): Couldn't empty "
+	       "response queue for card %d.\n", numcards);
+	tries++;
+	continue;
+      }
+
+      /* Now the controller is in a good state */
+      break;
+    }
+
+    if (tries >= TW_MAX_RESET_TRIES) {
+      printk(KERN_WARNING "3w-xxxx: tw_findcards(): Controller error or "
+	     "no attention interrupt: giving up for card %d.\n", numcards);
+      tw_free_device_extension(tw_dev);
+      kfree(tw_dev);
+      continue;
+    }
+
+    /* Make sure that io region isn't already taken */
+    if (check_region((tw_dev->tw_pci_dev->base_address[0] & ~15), 
+		     TW_IO_ADDRESS_RANGE)) {
+      printk(KERN_WARNING "3w-xxxx: tw_findcards(): Couldn't get io range "
+	     "0x%lx-0x%lx for card %d.\n", 
+	     (tw_dev->tw_pci_dev->base_address[0] & ~15), 
+	     (tw_dev->tw_pci_dev->base_address[0] & ~15) + 
+	     TW_IO_ADDRESS_RANGE, numcards);
+      tw_free_device_extension(tw_dev);
+      kfree(tw_dev);
+      continue;
+    }
+    
+    /* Reserve the io address space */
+    request_region((tw_dev->tw_pci_dev->base_address[0] & ~15), 
+		   TW_IO_ADDRESS_RANGE, TW_DEVICE_NAME);
+
+    error = tw_initialize_units(tw_dev);
+    if (error) {
+      printk(KERN_WARNING "3w-xxxx: tw_findcards(): Couldn't initialize "
+	     "units for card %d.\n", numcards);
+      release_region((tw_dev->tw_pci_dev->base_address[0] & ~15),
+		     TW_IO_ADDRESS_RANGE);
+      tw_free_device_extension(tw_dev);
+      kfree(tw_dev);
+      continue;
+    }
+
+    error = tw_initconnection(tw_dev);
+    if (error) {
+      printk(KERN_WARNING "3w-xxxx: tw_findcards(): Couldn't initconnection "
+	     "for card %d.\n", numcards);
+      release_region((tw_dev->tw_pci_dev->base_address[0] & ~15),
+		     TW_IO_ADDRESS_RANGE);
+      tw_free_device_extension(tw_dev);
+      kfree(tw_dev);
+      continue;
+    }
+
+    /* Calculate max cmds per lun */
+    if (tw_dev->num_units > 0)
+      tw_host->cmd_per_lun = (TW_Q_LENGTH-2)/tw_dev->num_units;
+
+    /* Register the card with the kernel SCSI layer */
+    host = scsi_register(tw_host, sizeof(TW_Device_Extension));
+
+    status_reg_value = inl(tw_dev->registers.status_reg_addr);
+
+    dprintk(KERN_NOTICE "scsi%d : Found a 3ware Storage Controller at "
+	    "0x%x, IRQ: %d P-chip: %d.%d\n", host->host_no, 
+	    (u32)(tw_pci_dev->base_address[0] & ~15), tw_pci_dev->irq, 
+	    (status_reg_value & TW_STATUS_MAJOR_VERSION_MASK) >> 28, 
+	    (status_reg_value & TW_STATUS_MINOR_VERSION_MASK) >> 24);
+
+    if (host->hostdata) {
+      tw_dev2 = (TW_Device_Extension *)host->hostdata;
+      memcpy(tw_dev2, tw_dev, sizeof(TW_Device_Extension));
+      tw_device_extension_list[tw_device_extension_count] = tw_dev2;
+      numcards++;
+      tw_device_extension_count = numcards;
+      tw_dev2->host = host;
+    } else { 
+      printk(KERN_WARNING "3w-xxxx: tw_findcards(): Bad scsi host data for "
+	     "card %d.\n", numcards-1);
+      scsi_unregister(host);
+      release_region((tw_dev->tw_pci_dev->base_address[0] & ~15),
+		     TW_IO_ADDRESS_RANGE);
+      tw_free_device_extension(tw_dev);
+      kfree(tw_dev);
+      continue;
+    }
+    
+    /* Re-enable interrupts on the card */
+    tw_enable_interrupts(tw_dev2);
+
+    /* Now setup the interrupt handler */
+    error = tw_setup_irq(tw_dev2);
+    if (error) {
+      printk(KERN_WARNING "3w-xxxx: tw_findcards(): Error requesting irq "
+	     "for card %d.\n", numcards-1);
+      scsi_unregister(host);
+      release_region((tw_dev->tw_pci_dev->base_address[0] & ~15),
+		     TW_IO_ADDRESS_RANGE);
+      tw_free_device_extension(tw_dev);
+      kfree(tw_dev);
+      numcards--;
+      continue;
+    }
+
+    /* Free the temporary device extension */
+    if (tw_dev)
+      kfree(tw_dev);
+  }
+
+  if (numcards == 0) 
+    printk(KERN_WARNING "3w-xxxx: tw_findcards(): No cards found.\n");
+
+  return numcards;
+} /* End tw_findcards() */
+
+/* This function will free up device extension resources */
+void tw_free_device_extension(TW_Device_Extension *tw_dev)
+{
+  int i, imax;
+  imax = TW_Q_LENGTH;
+
+  dprintk(KERN_NOTICE "3w-xxxx: tw_free_device_extension()\n");
+  /* Free command packet and generic buffer memory */
+  for (i=0;i<imax;i++) {
+    if (tw_dev->command_packet_virtual_address[i]) 
+      kfree(tw_dev->command_packet_virtual_address[i]);
+    if (tw_dev->alignment_virtual_address[i])
+      kfree(tw_dev->alignment_virtual_address[i]);
+  }
+} /* End tw_free_device_extension() */
+
+/* This function will send an initconnection command to controller */
+int tw_initconnection(TW_Device_Extension *tw_dev) 
+{
+  u32 command_que_addr, command_que_value;
+  u32 status_reg_addr, status_reg_value;
+  u32 response_que_addr;
+  TW_Command  *command_packet;
+  TW_Response_Queue response_queue;
+  int request_id = 0;
+  int i = 0;
+  int imax = 0;
+
+  dprintk(KERN_NOTICE "3w-xxxx: tw_initconnection()\n");
+  command_que_addr = tw_dev->registers.command_que_addr;
+  status_reg_addr = tw_dev->registers.status_reg_addr;
+  response_que_addr = tw_dev->registers.response_que_addr;
+
+  /* Initialize InitConnection command packet */
+  if (tw_dev->command_packet_virtual_address[request_id] == NULL) {
+    printk(KERN_WARNING "3w-xxxx: tw_initconnection(): "
+	   "Bad command packet virtual address.\n");
+    return 1;
+  }
+
+  command_packet = 
+    (TW_Command *)tw_dev->command_packet_virtual_address[request_id];
+  memset(command_packet, 0, sizeof(TW_Sector));
+  command_packet->byte0.opcode = TW_OP_INIT_CONNECTION;
+  command_packet->byte0.sgl_offset = 0x0;
+  command_packet->size = TW_INIT_COMMAND_PACKET_SIZE;
+  command_packet->request_id = request_id;
+  command_packet->byte3.unit = 0x0;
+  command_packet->byte3.host_id = 0x0;
+  command_packet->status = 0x0;
+  command_packet->flags = 0x0;
+  command_packet->byte6.message_credits = TW_INIT_MESSAGE_CREDITS; 
+  command_packet->byte8.init_connection.response_queue_pointer = 0x0;
+  command_que_value = tw_dev->command_packet_physical_address[request_id];
+
+  if (command_que_value == 0) {
+    printk(KERN_WARNING "3w-xxxx: tw_initconnection(): "
+	   "Bad command packet physical address.\n");
+    return 1;
+  }
+  
+  /* Send command packet to the board */
+  outl(command_que_value, command_que_addr);
+    
+  /* Poll for completion */
+  imax = TW_POLL_MAX_RETRIES;
+  for (i=0;i<imax;i++) {
+    mdelay(10);
+    status_reg_value = inl(status_reg_addr);
+    if (tw_check_bits(status_reg_value)) {
+      printk(KERN_WARNING "3w-xxxx: tw_initconnection(): Unexpected bits.\n");
+      return 1;
+    }
+    if ((status_reg_value & TW_STATUS_RESPONSE_QUEUE_EMPTY) == 0) {
+      response_queue.value = inl(response_que_addr);
+      request_id = (unsigned char)response_queue.u.response_id;
+      if (request_id != 0) {
+	/* unexpected request id */
+	printk(KERN_WARNING "3w-xxxx: tw_initconnection(): Unexpected "
+	       "request id.\n");
+	return 1;
+      }
+      if (command_packet->status != 0) {
+	/* bad response */
+	printk(KERN_WARNING "3w-xxxx: tw_initconnection(): Bad response, "
+	       "flags = 0x%x.\n", command_packet->flags);
+	return 1;
+      }
+      break; /* Response was okay, so we exit */
+    }
+  }
+  return 0;
+} /* End tw_initconnection() */
+
+/* This function will initialize the fields of a device extension */
+int tw_initialize_device_extension(TW_Device_Extension *tw_dev)
+{
+  int i, imax;
+
+  dprintk(KERN_NOTICE "3w-xxxx: tw_initialize_device_extension()\n");
+  imax = TW_Q_LENGTH;
+
+  for (i=0; i<imax; i++) {
+    /* Initialize command packet buffers */
+    tw_allocate_memory(tw_dev, i, sizeof(TW_Sector), 0);
+    if (tw_dev->command_packet_virtual_address[i] == NULL) {
+      printk(KERN_WARNING "3w-xxxx: tw_initialize_device_extension(): "
+	     "Bad command packet virtual address.\n");
+      return 1;
+    }
+    memset(tw_dev->command_packet_virtual_address[i], 0, sizeof(TW_Sector));
+    
+    /* Initialize generic buffer */
+    tw_allocate_memory(tw_dev, i, sizeof(TW_Sector), 1);
+    if (tw_dev->alignment_virtual_address[i] == NULL) {
+      printk(KERN_WARNING "3w-xxxx: tw_initialize_device_extension(): "
+	     "Bad alignment virtual address.\n");
+      return 1;
+    }
+    memset(tw_dev->alignment_virtual_address[i], 0, sizeof(TW_Sector));
+
+    tw_dev->free_queue[i] = i;
+    tw_dev->state[i] = TW_S_INITIAL;
+    tw_dev->ioctl_size[i] = 0;
+    tw_dev->aen_queue[i] = 0;
+  }
+
+  for (i=0;i<TW_MAX_UNITS;i++)
+    tw_dev->is_unit_present[i] = 0;
+
+  tw_dev->num_units = 0;
+  tw_dev->num_aborts = 0;
+  tw_dev->num_resets = 0;
+  tw_dev->free_head = TW_Q_START;
+  tw_dev->free_tail = TW_Q_LENGTH - 1;
+  tw_dev->posted_request_count = 0;
+  tw_dev->max_posted_request_count = 0;
+  tw_dev->max_sgl_entries = 0;
+  tw_dev->sgl_entries = 0;
+  tw_dev->host = NULL;
+  tw_dev->pending_head = TW_Q_START;
+  tw_dev->pending_tail = TW_Q_START;
+  tw_dev->aen_head = 0;
+  tw_dev->aen_tail = 0;
+  tw_dev->sector_count = 0;
+  tw_dev->max_sector_count = 0;
+  spin_lock_init(&tw_dev->tw_lock);
+
+  return 0;
+} /* End tw_initialize_device_extension() */
+
+/* This function will get unit info from the controller */
+int tw_initialize_units(TW_Device_Extension *tw_dev) 
+{
+  int found = 0;
+  unsigned char request_id = 0;
+  TW_Command *command_packet;
+  TW_Param *param;
+  int i, imax, num_units = 0;
+  u32 status_reg_addr, status_reg_value;
+  u32 command_que_addr, command_que_value;
+  u32 response_que_addr;
+  TW_Response_Queue response_queue;
+  u32 param_value;
+  unsigned char *is_unit_present;
+
+  dprintk(KERN_NOTICE "3w-xxxx: tw_initialize_units()\n");
+
+  status_reg_addr = tw_dev->registers.status_reg_addr;
+  command_que_addr = tw_dev->registers.command_que_addr;
+  response_que_addr = tw_dev->registers.response_que_addr;
+  
+  /* Setup the command packet */
+  command_packet = 
+    (TW_Command *)tw_dev->command_packet_virtual_address[request_id];
+  if (command_packet == NULL) {
+    printk(KERN_WARNING "3w-xxxx: tw_initialize_units(): "
+	   "Bad command packet virtual address.\n");
+    return 1;
+  }
+  memset(command_packet, 0, sizeof(TW_Sector));
+  command_packet->byte0.opcode      = TW_OP_GET_PARAM;
+  command_packet->byte0.sgl_offset  = 2;
+  command_packet->size              = 4;
+  command_packet->request_id        = request_id;
+  command_packet->byte3.unit        = 0;
+  command_packet->byte3.host_id     = 0;
+  command_packet->status            = 0;
+  command_packet->flags             = 0;
+  command_packet->byte6.block_count = 1;
+
+  /* Now setup the param */
+  if (tw_dev->alignment_virtual_address[request_id] == NULL) {
+    printk(KERN_WARNING "3w-xxxx: tw_initialize_units(): Bad alignment "
+	   "virtual address.\n");
+    return 1;
+  }
+  param = (TW_Param *)tw_dev->alignment_virtual_address[request_id];
+  memset(param, 0, sizeof(TW_Sector));
+  param->table_id = 3;       /* unit summary table */
+  param->parameter_id = 3;   /* unitstatus parameter */
+  param->parameter_size_bytes = TW_MAX_UNITS;
+  param_value = tw_dev->alignment_physical_address[request_id];
+  if (param_value == 0) {
+    printk(KERN_WARNING "3w-xxxx: tw_initialize_units(): Bad alignment "
+	   "physical address.\n");
+    return 1;
+  }
+
+  command_packet->byte8.param.sgl[0].address = param_value;
+  command_packet->byte8.param.sgl[0].length = sizeof(TW_Sector);
+
+  /* Post the command packet to the board */
+  command_que_value = tw_dev->command_packet_physical_address[request_id];
+  if (command_que_value == 0) {
+    printk(KERN_WARNING "3w-xxxx: tw_initialize_units(): "
+	   "Bad command packet physical address.\n");
+    return 1;
+  }
+  outl(command_que_value, command_que_addr);
+
+  /* Poll for completion */
+  imax = TW_POLL_MAX_RETRIES;
+  for(i=0; i<imax; i++) {
+    mdelay(10);
+    status_reg_value = inl(status_reg_addr);
+    if (tw_check_bits(status_reg_value)) {
+      printk(KERN_WARNING "3w-xxxx: tw_initialize_units(): Unexpected "
+	     "bits.\n");
+      return 1;
+    }
+    if ((status_reg_value & TW_STATUS_RESPONSE_QUEUE_EMPTY) == 0) {
+      response_queue.value = inl(response_que_addr);
+      request_id = (unsigned char)response_queue.u.response_id;
+      if (request_id != 0) {
+	/* unexpected request id */
+	printk(KERN_WARNING "3w-xxxx: tw_initialize_units(): Unexpected "
+	       "request id.\n");
+	return 1;
+      }
+      if (command_packet->status != 0) {
+	/* bad response */
+	printk(KERN_WARNING "3w-xxxx: tw_initialize_units(): Bad response,"
+	       " flags = 0x%x.\n", command_packet->flags);
+	return 1;
+      }
+      found = 1;
+      break;
+    }
+  }
+  if (found == 0) {
+    /* response never received */
+    printk(KERN_WARNING "3w-xxxx: tw_initialize_units(): No response.\n");
+    return 1;
+  }
+
+  param = (TW_Param *)tw_dev->alignment_virtual_address[request_id];
+  is_unit_present = (unsigned char *)&(param->data[0]);
+  
+  /* Show all units present */
+  imax = TW_MAX_UNITS;
+  for(i=0; i<imax; i++) {
+    if (is_unit_present[i] == 0) 
+      tw_dev->is_unit_present[i] = FALSE;
+    else {
+      dprintk(KERN_NOTICE "3w-xxxx: tw_initialize_units(): Unit %d "
+	      "found.\n", i);
+      tw_dev->is_unit_present[i] = TRUE;
+      num_units++;
+    }
+  }
+  tw_dev->num_units = num_units;
+
+  if (num_units == 0) {
+    printk(KERN_NOTICE "3w-xxxx: tw_initialize_units(): No units found.\n");
+    return 1;
+  }
+  
+  return 0;
+} /* End tw_initialize_units() */
+
+/* This function is the interrupt service routine */
+static void tw_interrupt(int irq, void *dev_instance, struct pt_regs *regs) 
+{
+  int request_id;
+  u32 status_reg_addr, status_reg_value;
+  u32 response_que_addr;
+  TW_Device_Extension *tw_dev = (TW_Device_Extension *)dev_instance;
+  TW_Response_Queue response_que;
+  int error = 0;
+  int do_response_interrupt=0;
+  int do_attention_interrupt=0;
+  int do_host_interrupt=0;
+  int do_command_interrupt=0;
+  int flags = 0;
+  int flags2 = 0;
+  TW_Command *command_packet;
+
+  spin_lock_irqsave(&io_request_lock, flags);
+
+  if (tw_dev->tw_pci_dev->irq == irq) {
+    spin_lock_irqsave(&tw_dev->tw_lock, flags2);
+    dprintk(KERN_NOTICE "3w-xxxx: tw_interrupt()\n");
+
+    /* Read the registers */
+    status_reg_addr = tw_dev->registers.status_reg_addr;
+    response_que_addr = tw_dev->registers.response_que_addr;
+    status_reg_value = inl(status_reg_addr);
+
+    /* Check which interrupt */
+    if (status_reg_value & TW_STATUS_HOST_INTERRUPT)
+      do_host_interrupt=1;
+    if (status_reg_value & TW_STATUS_ATTENTION_INTERRUPT)
+      do_attention_interrupt=1;
+    if (status_reg_value & TW_STATUS_COMMAND_INTERRUPT)
+      do_command_interrupt=1;
+    if (status_reg_value & TW_STATUS_RESPONSE_INTERRUPT)
+      do_response_interrupt=1;
+
+    /* Handle host interrupt */
+    if (do_host_interrupt) {
+      dprintk(KERN_NOTICE "3w-xxxx: tw_interrupt(): Received host "
+	      "interrupt.\n");
+      tw_clear_host_interrupt(tw_dev);
+    }
+
+    /* Handle attention interrupt */
+    if (do_attention_interrupt) {
+      dprintk(KERN_NOTICE "3w-xxxx: tw_interrupt(): Received attention "
+	      "interrupt.\n");
+      tw_state_request_start(tw_dev, &request_id);
+      error = tw_aen_read_queue(tw_dev, request_id);
+      if (error) {
+	printk(KERN_WARNING "3w-xxxx: tw_interrupt(): Error reading aen "
+	       "queue.\n");
+	tw_dev->state[request_id] = TW_S_COMPLETED;
+	tw_state_request_finish(tw_dev, request_id);
+      } else {
+	dprintk(KERN_WARNING "3w-xxxx: tw_interrupt(): Clearing attention "
+		"interrupt.\n");
+	tw_clear_attention_interrupt(tw_dev);
+      }
+    }
+
+    /* Handle command interrupt */
+    if (do_command_interrupt) {
+      /* Drain as many pending commands as we can */
+      while (tw_dev->pending_request_count > 0) {
+	request_id = tw_dev->pending_queue[tw_dev->pending_head];
+	if (tw_dev->state[request_id] != TW_S_PENDING) {
+	  printk(KERN_WARNING "3w-xxxx: tw_interrupt(): Found request id "
+		 "that wasn't pending.\n");
+	  break;
+	}
+	if (tw_post_command_packet(tw_dev, request_id)==0) {
+	  if (tw_dev->pending_head == TW_Q_LENGTH-1)
+	    tw_dev->pending_head = TW_Q_START;
+	  else
+	    tw_dev->pending_head = tw_dev->pending_head + 1;
+	  tw_dev->pending_request_count--;
+	} else 
+	  break;
+      }
+      /* If there are no more pending requests, we mask command interrupt */
+      if (tw_dev->pending_request_count == 0) 
+	tw_mask_command_interrupt(tw_dev);
+    }
+
+    /* Handle response interrupt */
+    if (do_response_interrupt) {
+      /* Drain the response queue from the board */
+      while ((status_reg_value & TW_STATUS_RESPONSE_QUEUE_EMPTY) == 0) {
+	response_que.value = inl(response_que_addr);
+	request_id = response_que.u.response_id;
+	command_packet = 
+	  (TW_Command *)tw_dev->command_packet_virtual_address[request_id];
+	if (command_packet->status != 0) {
+	  printk(KERN_WARNING "3w-xxxx: tw_interrupt(): Bad response, "
+		 "flags = 0x%x.\n", command_packet->flags);
+	}
+	if (tw_dev->state[request_id] != TW_S_POSTED) {
+	  printk(KERN_WARNING "3w-xxxx: tw_interrupt(): Received a request "
+		 "id (%d) (opcode = 0x%x) that wasn't posted.\n",
+		 request_id, command_packet->byte0.opcode);
+	}
+	error = 0;
+	dprintk(KERN_NOTICE "3w-xxxx: tw_interrupt(): Response queue "
+		"request id: %d.\n", request_id);
+	/* Check for internal command */
+	if (tw_dev->srb[request_id] == 0) {
+	  dprintk(KERN_WARNING "3w-xxxx: tw_interrupt(): Found internally "
+		  "posted command.\n");
+	  error = tw_aen_complete(tw_dev, request_id);
+	  if (error) 
+	    printk(KERN_WARNING "3w-xxxx: tw_interrupt(): Error completing "
+		   "aen.\n");
+	  status_reg_value = inl(status_reg_addr);
+	  if (tw_check_bits(status_reg_value))
+	    printk(KERN_WARNING "3w-xxxx: tw_interrupt(): Unexpected bits.\n");
+	} else {
+	  switch (tw_dev->srb[request_id]->cmnd[0]) {
+	  case READ_10:
+	    dprintk(KERN_NOTICE "3w-xxxx: tw_interrupt(): caught READ_10\n");
+	  case READ_6:
+	    dprintk(KERN_NOTICE "3w-xxxx: tw_interrupt(): caught READ_6\n");
+	    break;
+	  case WRITE_10:
+	    dprintk(KERN_NOTICE "3w-xxxx: tw_interrupt(): caught WRITE_10\n");
+	  case WRITE_6:
+	    dprintk(KERN_NOTICE "3w-xxxx: tw_interrupt(): caught WRITE_6\n");
+	    break;
+	  case INQUIRY:
+	    dprintk(KERN_NOTICE "3w-xxxx: tw_interrupt(): caught INQUIRY\n");
+	    error = tw_scsiop_inquiry_complete(tw_dev, request_id);
+	    break;
+	  case READ_CAPACITY:
+	    dprintk(KERN_NOTICE "3w-xxxx: tw_interrupt(): caught "
+		    "READ_CAPACITY\n");
+	    error = tw_scsiop_read_capacity_complete(tw_dev, request_id);
+	    break;
+	  case TW_IOCTL:
+	    dprintk(KERN_NOTICE "3w-xxxx: tw_interrupt(): caught TW_IOCTL\n");
+	    error = tw_ioctl_complete(tw_dev, request_id);
+	    break;
+	  default:
+	    printk(KERN_WARNING "3w-xxxx: tw_interrupt(): Unknown scsi "
+		   "opcode: 0x%x.\n", tw_dev->srb[request_id]->cmnd[0]);
+	    tw_dev->srb[request_id]->result = (DID_BAD_TARGET << 16);
+	    tw_dev->srb[request_id]->scsi_done(tw_dev->srb[request_id]);
+	  }
+	  if (error) {
+	    /* Tell scsi layer there was an error */
+	    printk(KERN_WARNING "3w-xxxx: tw_interrupt(): Scsi Error.\n");
+	    tw_dev->srb[request_id]->result = (DID_ERROR << 16);
+	  } else {
+	    /* Tell scsi layer command was a success */
+	    tw_dev->srb[request_id]->result = (DID_OK << 16);
+	  }
+	  tw_dev->state[request_id] = TW_S_COMPLETED;
+	  tw_state_request_finish(tw_dev, request_id);
+	  tw_dev->posted_request_count--;
+	  tw_dev->srb[request_id]->scsi_done(tw_dev->srb[request_id]);
+	  status_reg_value = inl(status_reg_addr);
+	  if (tw_check_bits(status_reg_value))
+	    printk(KERN_WARNING "3w-xxxx: tw_interrupt(): Unexpected bits.\n");
+	}
+      }
+    }
+    spin_unlock_irqrestore(&tw_dev->tw_lock, flags2);
+  }
+  spin_unlock_irqrestore(&io_request_lock, flags);
+}  /* End tw_interrupt() */
+
+/* This function handles ioctls from userspace to the driver */
+int tw_ioctl(TW_Device_Extension *tw_dev, int request_id)
+{
+  unsigned char opcode;
+  int bufflen;
+  TW_Param *param;
+  TW_Command *command_packet;
+  u32 param_value;
+  TW_Ioctl *ioctl = NULL;
+  int tw_aen_code;
+
+  ioctl = (TW_Ioctl *)tw_dev->srb[request_id]->request_buffer;
+  if (ioctl == NULL) {
+    printk(KERN_WARNING "3w-xxxx: tw_ioctl(): Request buffer NULL.\n");
+    tw_dev->state[request_id] = TW_S_COMPLETED;
+    tw_state_request_finish(tw_dev, request_id);
+    tw_dev->srb[request_id]->result = (DID_OK << 16);
+    tw_dev->srb[request_id]->scsi_done(tw_dev->srb[request_id]);
+    return 0;
+  }
+  bufflen = tw_dev->srb[request_id]->request_bufflen;
+
+  /* Initialize command packet */
+  command_packet = 
+    (TW_Command *)tw_dev->command_packet_virtual_address[request_id];
+  if (command_packet == NULL) {
+    printk(KERN_WARNING "3w-xxxx: twioctl(): Bad command packet "
+	   "virtual address.\n");
+    tw_dev->state[request_id] = TW_S_COMPLETED;
+    tw_state_request_finish(tw_dev, request_id);
+    tw_dev->srb[request_id]->result = (DID_OK << 16);
+    tw_dev->srb[request_id]->scsi_done(tw_dev->srb[request_id]);
+    return 0;
+  }
+  memset(command_packet, 0, sizeof(TW_Sector));
+
+  /* Initialize param */
+  if (tw_dev->alignment_virtual_address[request_id] == NULL) {
+    printk(KERN_WARNING "3w-xxxx: tw_ioctl(): Bad alignment "
+	   "virtual address.\n");
+    tw_dev->state[request_id] = TW_S_COMPLETED;
+    tw_state_request_finish(tw_dev, request_id);
+    tw_dev->srb[request_id]->result = (DID_OK << 16);
+    tw_dev->srb[request_id]->scsi_done(tw_dev->srb[request_id]);
+    return 0;
+  }
+  param = (TW_Param *)tw_dev->alignment_virtual_address[request_id];
+  memset(param, 0, sizeof(TW_Sector));
+
+  dprintk(KERN_NOTICE "opcode = %d table_id = %d parameter_id = %d "
+	  "parameter_size_bytes = %d\n", ioctl->opcode, ioctl->table_id,
+	  ioctl->parameter_id, ioctl->parameter_size_bytes);
+  opcode = ioctl->opcode;
+
+  switch (opcode) {
+  case TW_OP_NOP:
+    dprintk(KERN_NOTICE "3w-xxxx: tw_ioctl(): caught TW_OP_NOP.\n");
+    command_packet->byte0.opcode = TW_OP_NOP;
+    break;
+  case TW_OP_GET_PARAM:
+    dprintk(KERN_NOTICE "3w-xxxx: tw_ioctl(): caught TW_OP_GET_PARAM.\n");
+    command_packet->byte0.opcode = TW_OP_GET_PARAM;
+    param->table_id = ioctl->table_id;
+    param->parameter_id = ioctl->parameter_id;
+    param->parameter_size_bytes = ioctl->parameter_size_bytes;
+    tw_dev->ioctl_size[request_id] = ioctl->parameter_size_bytes;
+    dprintk(KERN_NOTICE 
+	    "table_id = %d parameter_id = %d parameter_size_bytes %d\n", 
+	    param->table_id, param->parameter_id, param->parameter_size_bytes);
+    break;
+  case TW_OP_SET_PARAM:
+    dprintk(KERN_NOTICE "3w-xxxx: tw_ioctl(): caught TW_OP_SET_PARAM: "
+	    "table_id = %d, parameter_id = %d, parameter_size_bytes = %d.\n",
+	    ioctl->table_id, ioctl->parameter_id, ioctl->parameter_size_bytes);
+    command_packet->byte0.opcode = TW_OP_SET_PARAM;
+    param->table_id = ioctl->table_id;
+    param->parameter_id = ioctl->parameter_id;
+    param->parameter_size_bytes = ioctl->parameter_size_bytes;
+    memcpy(param->data, ioctl->data, ioctl->parameter_size_bytes);
+    break;
+  case TW_OP_AEN_LISTEN:
+    dprintk(KERN_NOTICE "3w-xxxx: tw_ioctl(): caught TW_OP_AEN_LISTEN.\n");
+    if (tw_dev->aen_head == tw_dev->aen_tail) {
+      /* aen queue empty */
+      dprintk(KERN_NOTICE "3w-xxxx: tw_ioctl(): Aen queue empty.\n");
+      tw_aen_code = TW_AEN_QUEUE_EMPTY;
+      memcpy(tw_dev->srb[request_id]->request_buffer,
+	     &tw_aen_code, ioctl->parameter_size_bytes);
+    } else {
+      /* Copy aen queue entry to request buffer */
+      dprintk(KERN_NOTICE "3w-xxxx: tw_ioctl(): Returning aen 0x%x\n", 
+	      tw_dev->aen_queue[tw_dev->aen_head]);
+      tw_aen_code = tw_dev->aen_queue[tw_dev->aen_head];
+      memcpy(tw_dev->srb[request_id]->request_buffer, 
+	     &tw_aen_code, ioctl->parameter_size_bytes);
+      if (tw_dev->aen_head == TW_Q_LENGTH - 1)
+	tw_dev->aen_head = TW_Q_START;
+      else
+	tw_dev->aen_head = tw_dev->aen_head + 1;
+    }
+    tw_dev->state[request_id] = TW_S_COMPLETED;
+    tw_state_request_finish(tw_dev, request_id);
+    tw_dev->srb[request_id]->result = (DID_OK << 16);
+    tw_dev->srb[request_id]->scsi_done(tw_dev->srb[request_id]);
+    return 0;
+  default:
+    printk(KERN_WARNING "3w-xxxx: Unknown ioctl 0x%x.\n", opcode);
+    tw_dev->state[request_id] = TW_S_COMPLETED;
+    tw_state_request_finish(tw_dev, request_id);
+    tw_dev->srb[request_id]->result = (DID_OK << 16);
+    tw_dev->srb[request_id]->scsi_done(tw_dev->srb[request_id]);
+    return 0;
+  }
+
+  param_value = tw_dev->alignment_physical_address[request_id];
+  if (param_value == 0) {
+    printk(KERN_WARNING "3w-xxxx: tw_ioctl(): Bad alignment physical "
+	   "address.\n");
+    tw_dev->state[request_id] = TW_S_COMPLETED;
+    tw_state_request_finish(tw_dev, request_id);
+    tw_dev->srb[request_id]->result = (DID_OK << 16);
+    tw_dev->srb[request_id]->scsi_done(tw_dev->srb[request_id]);
+  }
+
+  command_packet->byte8.param.sgl[0].address = param_value;
+  command_packet->byte8.param.sgl[0].length = sizeof(TW_Sector);
+
+  command_packet->byte0.sgl_offset = 2;
+  command_packet->size = 4;
+  command_packet->request_id = request_id;
+  command_packet->byte3.unit = 0;
+  command_packet->byte3.host_id = 0;
+  command_packet->status = 0;
+  command_packet->flags = 0;
+  command_packet->byte6.parameter_count = 1;
+
+  /* Now try to post the command to the board */
+  tw_post_command_packet(tw_dev, request_id);
+
+  return 0;
+} /* End tw_ioctl() */
+
+/* This function is called by the isr to complete ioctl requests */
+int tw_ioctl_complete(TW_Device_Extension *tw_dev, int request_id)
+{
+  unsigned char *param_data;
+  unsigned char *buff;
+  TW_Param *param;
+
+  dprintk(KERN_NOTICE "3w-xxxx: tw_ioctl_complete()\n");
+  buff = tw_dev->srb[request_id]->request_buffer;
+  if (buff == NULL) {
+    printk(KERN_WARNING "3w-xxxx: tw_ioctl_complete(): "
+	   "Request buffer NULL.\n");
+    return 1;
+  }
+  dprintk(KERN_NOTICE "3w-xxxx: tw_ioctl_complete(): Request_bufflen = %d\n",
+	  tw_dev->srb[request_id]->request_bufflen);
+  memset(buff, 0, tw_dev->srb[request_id]->request_bufflen);
+  param = (TW_Param *)tw_dev->alignment_virtual_address[request_id];
+  if (param == NULL) {
+    printk(KERN_WARNING "3w-xxxx: tw_scsiop_read_capacity_complete(): "
+	   "Bad alignment virtual address.\n");
+    return 1;
+  }
+  param_data = &(param->data[0]);
+
+  memcpy(buff, param_data, tw_dev->ioctl_size[request_id]);
+
+  return 0;
+} /* End tw_ioctl_complete() */
+
+/* This function will mask the command interrupt */
+void tw_mask_command_interrupt(TW_Device_Extension *tw_dev)
+{
+  u32 control_reg_addr, control_reg_value;
+  
+  control_reg_addr = tw_dev->registers.control_reg_addr;
+  control_reg_value = TW_CONTROL_MASK_COMMAND_INTERRUPT;
+  outl(control_reg_value, control_reg_addr);
+} /* End tw_mask_command_interrupt() */
+
+/* This function will poll the status register for a flag */
+int tw_poll_status(TW_Device_Extension *tw_dev, u32 flag, int seconds)
+{
+  u32 status_reg_addr, status_reg_value;
+  struct timeval before, timeout;
+
+  status_reg_addr = tw_dev->registers.status_reg_addr;
+  do_gettimeofday(&before);
+  status_reg_value = inl(status_reg_addr);
+
+  while ((status_reg_value & flag) != flag) {
+    status_reg_value = inl(status_reg_addr);
+    do_gettimeofday(&timeout);
+    if (before.tv_sec + seconds < timeout.tv_sec) { 
+      printk(KERN_WARNING "3w-xxxx: tw_poll_status(): Flag 0x%x not found.\n",
+	     flag);
+      return 1;
+    }
+    mdelay(1);
+  }
+  return 0;
+} /* End tw_poll_status() */
+
+/* This function will attempt to post a command packet to the board */
+int tw_post_command_packet(TW_Device_Extension *tw_dev, int request_id)
+{
+  u32 status_reg_addr, status_reg_value;
+  u32 command_que_addr, command_que_value;
+
+  dprintk(KERN_NOTICE "3w-xxxx: tw_post_command_packet()\n");
+  command_que_addr = tw_dev->registers.command_que_addr;
+  command_que_value = tw_dev->command_packet_physical_address[request_id];
+  status_reg_addr = tw_dev->registers.status_reg_addr;
+  status_reg_value = inl(status_reg_addr);
+
+  if (tw_check_bits(status_reg_value)) 
+    printk(KERN_WARNING "3w-xxxx: tw_post_command_packet(): Unexpected "
+	   "bits.\n");
+
+  if ((status_reg_value & TW_STATUS_COMMAND_QUEUE_FULL) == 0) {
+    /* We successfully posted the command packet */
+    outl(command_que_value, command_que_addr);
+    tw_dev->state[request_id] = TW_S_POSTED;
+    tw_dev->posted_request_count++;
+    if (tw_dev->posted_request_count > tw_dev->max_posted_request_count)
+      tw_dev->max_posted_request_count = tw_dev->posted_request_count;
+  } else {
+    /* Couldn't post the command packet, so we do it in the isr */
+    if (tw_dev->state[request_id] != TW_S_PENDING) {
+      tw_dev->state[request_id] = TW_S_PENDING;
+      tw_dev->pending_request_count++;
+      if (tw_dev->pending_request_count > tw_dev->max_pending_request_count)
+	tw_dev->max_pending_request_count = tw_dev->pending_request_count;
+      tw_dev->pending_queue[tw_dev->pending_tail] = request_id;
+      if (tw_dev->pending_tail == TW_Q_LENGTH-1)
+	tw_dev->pending_tail = TW_Q_START;
+      else
+	tw_dev->pending_tail = tw_dev->pending_tail + 1;
+    } 
+    tw_unmask_command_interrupt(tw_dev);
+    return 1;
+  }
+  return 0;
+} /* End tw_post_command_packet() */
+
+/* This function will reset a device extension */
+int tw_reset_device_extension(TW_Device_Extension *tw_dev) 
+{
+  int imax = 0;
+  int i = 0;
+  Scsi_Cmnd *srb;
+
+  dprintk(KERN_NOTICE "3w-xxxx: tw_reset_device_extension()\n");
+  imax = TW_Q_LENGTH;
+
+  if (tw_reset_sequence(tw_dev)) {
+    printk(KERN_WARNING "3w-xxxx: tw_reset_device_extension(): Reset "
+	   "sequence failed for card %d.\n", tw_dev->host->host_no);
+    return 1;
+  }
+
+  /* Abort all requests that are in progress */
+  for (i=0;i<imax;i++) {
+    if ((tw_dev->state[i] != TW_S_FINISHED) && 
+	(tw_dev->state[i] != TW_S_INITIAL) &&
+	(tw_dev->state[i] != TW_S_COMPLETED)) {
+      srb = tw_dev->srb[i];
+      srb->result = (DID_RESET << 16);
+      tw_dev->srb[i]->scsi_done(tw_dev->srb[i]);
+    }
+  }
+
+  /* Reset queues and counts */
+  for (i=0;i<imax;i++) {
+    tw_dev->free_queue[i] = i;
+    tw_dev->state[i] = TW_S_INITIAL;
+  }
+  tw_dev->free_head = TW_Q_START;
+  tw_dev->free_tail = TW_Q_LENGTH - 1;
+  tw_dev->posted_request_count = 0;
+  tw_dev->pending_request_count = 0;
+  tw_dev->pending_head = TW_Q_START;
+  tw_dev->pending_tail = TW_Q_START;
+
+  return 0;
+} /* End tw_reset_device_extension() */
+
+/* This function will reset a controller */
+int tw_reset_sequence(TW_Device_Extension *tw_dev) 
+{
+  int error = 0;
+  int tries = 0;
+
+  /* Disable interrupts */
+  tw_disable_interrupts(tw_dev);
+
+  /* Reset the board */
+  while (tries < TW_MAX_RESET_TRIES) {
+    tw_soft_reset(tw_dev);
+
+    error = tw_aen_drain_queue(tw_dev);
+    if (error) {
+      printk(KERN_WARNING "3w-xxxx: tw_reset_sequence(): No attention "
+	     "interrupt for card %d.\n", tw_dev->host->host_no);
+      tries++;
+      continue;
+    }
+
+    /* Check for controller errors */
+    if (tw_check_errors(tw_dev)) {
+      printk(KERN_WARNING "3w-xxxx: tw_reset_sequence(): Controller "
+	     "errors found, soft resetting card %d.\n", tw_dev->host->host_no);
+      tries++;
+      continue;
+    }
+
+    /* Empty the response queue again */
+    error = tw_empty_response_que(tw_dev);
+    if (error) {
+      printk(KERN_WARNING "3w-xxxx: tw_reset_sequence(): Couldn't empty "
+	     "response queue for card %d.\n", tw_dev->host->host_no);
+      tries++;
+      continue;
+    }
+
+    /* Now the controller is in a good state */
+    break;
+  }
+
+  if (tries >= TW_MAX_RESET_TRIES) {
+    printk(KERN_WARNING "3w-xxxx: tw_reset_sequence(): Controller error or no "
+	   "attention interrupt: giving up for card %d.\n", 
+	   tw_dev->host->host_no);
+    return 1;
+  }
+
+  error = tw_initconnection(tw_dev);
+  if (error) {
+    printk(KERN_WARNING "3w-xxxx: tw_reset_sequence(): Couldn't "
+	   "initconnection for card %d.\n", tw_dev->host->host_no);
+    return 1;
+  }
+
+  /* Re-enable interrupts */
+  tw_enable_interrupts(tw_dev);
+
+  return 0;
+} /* End tw_reset_sequence() */
+
+/* This funciton returns unit geometry in cylinders/heads/sectors */
+int tw_scsi_biosparam(Disk *disk, kdev_t dev, int geom[]) 
+{
+  int heads, sectors, cylinders;
+  TW_Device_Extension *tw_dev;
+  
+  dprintk(KERN_NOTICE "3w-xxxx: tw_scsi_biosparam()\n");
+  tw_dev = (TW_Device_Extension *)disk->device->host->hostdata;
+
+  heads = 64;
+  sectors = 32;
+  cylinders = disk->capacity / (heads * sectors);
+
+  if (disk->capacity >= 0x200000) {
+    heads = 255;
+    sectors = 63;
+    cylinders = disk->capacity / (heads * sectors);
+  }
+
+  dprintk(KERN_NOTICE "3w-xxxx: tw_scsi_biosparam(): heads = %d, "
+	  "sectors = %d, cylinders = %d\n", heads, sectors, cylinders);
+  geom[0] = heads;       
+  geom[1] = sectors;
+  geom[2] = cylinders;
+
+  return 0;
+} /* End tw_scsi_biosparam() */
+
+/* This function will find and initialize any cards */
+int tw_scsi_detect(Scsi_Host_Template *tw_host)
+{
+  dprintk(KERN_NOTICE "3w-xxxx: tw_scsi_detect()\n");
+
+  /* Check if the kernel has PCI interface compiled in */
+  if (!pci_present()) {
+    printk(KERN_WARNING "3w-xxxx: tw_scsi_detect(): No pci interface "
+	   "present.\n");
+    return 0;
+  }
+
+  return(tw_findcards(tw_host));
+} /* End tw_scsi_detect() */
+
+/* This is the new scsi eh abort function */
+int tw_scsi_eh_abort(Scsi_Cmnd *SCpnt) 
+{
+  TW_Device_Extension *tw_dev=NULL;
+  int i = 0;
+
+  dprintk(KERN_NOTICE "3w-xxxx: tw_scsi_eh_abort()\n");
+
+  if (!SCpnt) {
+    printk(KERN_WARNING "3w-xxxx: tw_scsi_eh_abort(): Invalid Scsi_Cmnd.\n");
+    return (FAILED);
+  }
+
+  tw_dev = (TW_Device_Extension *)SCpnt->host->hostdata;
+  if (tw_dev == NULL) {
+    printk(KERN_WARNING "3w-xxxx: tw_scsi_eh_abort(): Invalid device "
+	   "extension.\n");
+    return (FAILED);
+  }
+
+  spin_lock(&tw_dev->tw_lock);
+  tw_dev->num_aborts++;
+
+  /* If the command hasn't been posted yet, we can do the abort */
+  for (i=0;i<TW_Q_LENGTH;i++) {
+    if (tw_dev->srb[i] == SCpnt) {
+      if (tw_dev->state[i] == TW_S_STARTED) {
+	printk(KERN_WARNING "3w-xxxx: tw_scsi_eh_abort(): Abort succeeded for"
+	       " started Scsi_Cmnd 0x%x\n", (u32)tw_dev->srb[i]);
+	tw_dev->state[i] = TW_S_COMPLETED;
+	tw_state_request_finish(tw_dev, i);
+	spin_unlock(&tw_dev->tw_lock);
+	return (SUCCESS);
+      }
+      if (tw_dev->state[i] == TW_S_PENDING) {
+	printk(KERN_WARNING "3w-xxxx: tw_scsi_eh_abort(): Abort succeeded for"
+	       " pending Scsi_Cmnd 0x%x\n", (u32)tw_dev->srb[i]);
+	if (tw_dev->pending_head == TW_Q_LENGTH-1)
+	  tw_dev->pending_head = TW_Q_START;
+	else
+	  tw_dev->pending_head = tw_dev->pending_head + 1;
+	tw_dev->pending_request_count--;
+	tw_dev->state[i] = TW_S_COMPLETED;
+	tw_state_request_finish(tw_dev, i);
+	spin_unlock(&tw_dev->tw_lock);
+	return (SUCCESS);
+      }
+    }
+  }
+
+  /* If the command has already been posted, we have to reset the card */
+  printk(KERN_WARNING "3w-xxxx: tw_scsi_eh_abort(): Abort failed for "
+	 "unknown Scsi_Cmnd 0x%x, resetting card %d.\n", (u32)SCpnt, 
+	 tw_dev->host->host_no);
+
+  if (tw_reset_device_extension(tw_dev)) {
+    printk(KERN_WARNING "3w-xxxx: tw_scsi_eh_abort(): Reset failed for "
+	   "card %d.\n", tw_dev->host->host_no);
+    spin_unlock(&tw_dev->tw_lock);
+    return (FAILED);
+  }
+  spin_unlock(&tw_dev->tw_lock);
+
+  return (SUCCESS);
+} /* End tw_scsi_eh_abort() */
+
+/* This is the new scsi eh reset function */
+int tw_scsi_eh_reset(Scsi_Cmnd *SCpnt) 
+{
+  TW_Device_Extension *tw_dev=NULL;
+  int flags = 0;
+
+  dprintk(KERN_NOTICE "3w-xxxx: tw_scsi_eh_reset()\n");
+
+  if (!SCpnt) {
+    printk(KERN_WARNING "3w-xxxx: tw_scsi_eh_reset(): Invalid Scsi_Cmnd.\n");
+    return (FAILED);
+  }
+
+  tw_dev = (TW_Device_Extension *)SCpnt->host->hostdata;
+  if (tw_dev == NULL) {
+    printk(KERN_WARNING "3w-xxxx: tw_scsi_eh_reset(): Invalid device "
+	   "extension.\n");
+    return (FAILED);
+  }
+
+  spin_lock_irqsave(&tw_dev->tw_lock, flags);
+  tw_dev->num_resets++;
+
+  /* Now reset the card and some of the device extension data */
+  if (tw_reset_device_extension(tw_dev)) {
+    printk(KERN_WARNING "3w-xxxx: tw_scsi_eh_reset(): Reset failed for "
+	   "card %d.\n", tw_dev->host->host_no);
+    spin_unlock_irqrestore(&tw_dev->tw_lock, flags);
+    return (FAILED);
+  }
+  printk(KERN_WARNING "3w-xxxx: tw_scsi_eh_reset(): Reset succeeded for "
+	 "card %d.\n", tw_dev->host->host_no);
+  spin_unlock_irqrestore(&tw_dev->tw_lock, flags);
+
+  return (SUCCESS);
+} /* End tw_scsi_eh_reset() */
+
+/* This function handles input and output from /proc/scsi/3w-xxxx/x */
+int tw_scsi_proc_info(char *buffer, char **start, off_t offset, int length, 
+		      int hostno, int inout) 
+{
+  TW_Device_Extension *tw_dev = NULL;
+  TW_Info info;
+  int i;
+  int j;
+
+  dprintk(KERN_NOTICE "3w-xxxx: tw_scsi_proc_info()\n");
+
+  /* Find the correct device extension */
+  for (i=0;i<tw_device_extension_count;i++) 
+    if (tw_device_extension_list[i]->host->host_no == hostno) 
+      tw_dev = tw_device_extension_list[i];
+  if (tw_dev == NULL) {
+    printk(KERN_WARNING "3w-xxxx: tw_scsi_proc_info(): Couldn't locate "
+	   "device extension.\n");
+    return (-EINVAL);
+  }
+
+  info.buffer = buffer;
+  info.length = length;
+  info.offset = offset;
+  info.position = 0;
+  
+  if (inout) {
+    /* Write */
+    if (strncmp(buffer, "debug", 5) == 0) {
+      printk(KERN_INFO "3w-xxxx: Posted commands:\n");
+      for (j=0;j<TW_Q_LENGTH;j++) {
+	if (tw_dev->state[j] == TW_S_POSTED) {
+	  TW_Command *command=
+	    (TW_Command *)tw_dev->command_packet_virtual_address[j];
+	  printk(KERN_INFO "3w-xxxx: Request_id: %d\n", j);
+	  printk(KERN_INFO "Opcode: 0x%x\n", command->byte0.opcode);
+	  printk(KERN_INFO "Block_count: 0x%x\n", 
+		 command->byte6.block_count);
+	  printk(KERN_INFO "LBA: 0x%x\n", (u32)command->byte8.io.lba);
+	  printk(KERN_INFO "Physical command packet addr: 0x%x\n",
+		 tw_dev->command_packet_physical_address[j]);
+	  printk(KERN_INFO "Scsi_Cmnd: 0x%x\n", (u32)tw_dev->srb[j]);
+	}
+      }
+      printk(KERN_INFO "3w-xxxx: Free_head: %3d\n", tw_dev->free_head);
+      printk(KERN_INFO "3w-xxxx: Free_tail: %3d\n", tw_dev->free_tail);
+    } 
+    return length;
+  } else {
+    /* Read */
+    if (start) 
+      *start = buffer;
+    tw_copy_info(&info, "scsi%d: 3ware Storage Controller\n", hostno);
+    tw_copy_info(&info, "Driver version: %s\n",
+		 tw_driver_version);
+    tw_copy_info(&info, "Current commands posted:       %3d\n", 
+		 tw_dev->posted_request_count);
+    tw_copy_info(&info, "Max commands posted:           %3d\n", 
+		 tw_dev->max_posted_request_count);
+    tw_copy_info(&info, "Current pending commands:      %3d\n",
+		 tw_dev->pending_request_count);
+    tw_copy_info(&info, "Max pending commands:          %3d\n", 
+		 tw_dev->max_pending_request_count);
+    tw_copy_info(&info, "Last sgl length:               %3d\n",
+		 tw_dev->sgl_entries);
+    tw_copy_info(&info, "Max sgl length:                %3d\n", 
+		 tw_dev->max_sgl_entries);
+    tw_copy_info(&info, "Last sector count:             %3d\n",
+		 tw_dev->sector_count);
+    tw_copy_info(&info, "Max sector count:              %3d\n",
+		 tw_dev->max_sector_count);
+    tw_copy_info(&info, "Resets:                        %3d\n",
+		 tw_dev->num_resets);
+    tw_copy_info(&info, "Aborts:                        %3d\n", 
+		 tw_dev->num_aborts);
+  }
+  if (info.position > info.offset)
+    return (info.position - info.offset);
+  else 
+    return 0;
+} /* End tw_scsi_proc_info() */
+
+/* This is the main scsi queue function to handle scsi opcodes */
+int tw_scsi_queue(Scsi_Cmnd *SCpnt, void (*done)(Scsi_Cmnd *)) 
+{
+  unsigned char *command = SCpnt->cmnd;
+  int request_id = 0;
+  int error = 0;
+  int flags = 0;
+  TW_Device_Extension *tw_dev = (TW_Device_Extension *)SCpnt->host->hostdata;
+
+  spin_lock_irqsave(&tw_dev->tw_lock, flags);
+  dprintk(KERN_NOTICE "3w-xxxx: tw_scsi_queue()\n");
+
+  /* Skip scsi command if it isn't for us */
+  if ((tw_dev->is_unit_present[SCpnt->target] == FALSE) || (SCpnt->lun != 0)) {
+    SCpnt->result = (DID_BAD_TARGET << 16);
+    done(SCpnt);
+    spin_unlock_irqrestore(&tw_dev->tw_lock, flags);
+    return 0;
+  }
+  if (done == NULL) {
+    printk(KERN_WARNING "3w-xxxx: tw_scsi_queue(): Invalid done function.\n");
+    SCpnt->result = (DID_ERROR << 16);
+    done(SCpnt);
+    spin_unlock_irqrestore(&tw_dev->tw_lock, flags);
+    return 0;
+  }
+  if (tw_dev == NULL) {
+    printk(KERN_WARNING "3w-xxxx: tw_scsi_queue(): Invalid device "
+	   "extension.\n");
+    SCpnt->result = (DID_ERROR << 16);
+    done(SCpnt);
+    spin_unlock_irqrestore(&tw_dev->tw_lock, flags);
+    return 0;
+  }
+  
+  /* Save done function into Scsi_Cmnd struct */
+  SCpnt->scsi_done = done;
+     
+  /* Queue the command and get a request id */
+  tw_state_request_start(tw_dev, &request_id);
+
+  /* Save the scsi command for use by the ISR */
+  tw_dev->srb[request_id] = SCpnt;
+
+  switch (*command) {
+  case READ_10:
+    dprintk(KERN_NOTICE "3w-xxxx: tw_scsi_queue(): caught READ_10.\n");
+  case READ_6:
+    dprintk(KERN_NOTICE "3w-xxxx: tw_scsi_queue(): caught READ_6.\n");
+  case WRITE_10:
+    dprintk(KERN_NOTICE "3w-xxxx: tw_scsi_queue(): caught WRITE_10.\n");
+  case WRITE_6:
+    dprintk(KERN_NOTICE "3w-xxxx: tw_scsi_queue(): caught WRITE_6.\n");
+    error = tw_scsiop_read_write(tw_dev, request_id);
+    break;
+  case TEST_UNIT_READY:
+    dprintk(KERN_NOTICE "3w-xxxx: tw_scsi_queue(): caught TEST_UNIT_READY.\n");
+    error = tw_scsiop_test_unit_ready(tw_dev, request_id);
+    break;
+  case INQUIRY:
+    dprintk(KERN_NOTICE "3w-xxxx: tw_scsi_queue(): caught INQUIRY.\n");
+    error = tw_scsiop_inquiry(tw_dev, request_id);
+    break;
+  case READ_CAPACITY:
+    dprintk(KERN_NOTICE "3w-xxxx: tw_scsi_queue(): caught READ_CAPACITY.\n");
+    error = tw_scsiop_read_capacity(tw_dev, request_id);
+    break;
+  case TW_IOCTL:
+    dprintk(KERN_NOTICE "3w-xxxx: tw_scsi_queue(): caught TW_SCSI_IOCTL.\n");
+    error = tw_ioctl(tw_dev, request_id);
+    break;
+  default:
+    printk(KERN_NOTICE "3w-xxxx: tw_scsi_queue(): Unknown scsi opcode: "
+	   "0x%x\n", *command);
+    tw_dev->state[request_id] = TW_S_COMPLETED;
+    tw_state_request_finish(tw_dev, request_id);
+    SCpnt->result = (DID_BAD_TARGET << 16);
+    done(SCpnt);
+  }
+  if (error) {
+    tw_dev->state[request_id] = TW_S_COMPLETED;
+    tw_state_request_finish(tw_dev, request_id);
+    SCpnt->result = (DID_ERROR << 16);
+    done(SCpnt);
+  }
+  spin_unlock_irqrestore(&tw_dev->tw_lock, flags);
+
+  return 0;
+} /* End tw_scsi_queue() */
+
+/* This function will release the resources on an rmmod call */
+int tw_scsi_release(struct Scsi_Host *tw_host) 
+{
+  TW_Device_Extension *tw_dev;
+  tw_dev = (TW_Device_Extension *)tw_host->hostdata;
+
+  dprintk(KERN_NOTICE "3w-xxxx: tw_scsi_release()\n");
+
+  /* Free up the IO region */
+  release_region((tw_dev->tw_pci_dev->base_address[0] & ~15), 
+		 TW_IO_ADDRESS_RANGE);
+
+  /* Free up the IRQ */
+  free_irq(tw_dev->tw_pci_dev->irq, tw_dev);
+
+  /* Free up device extension resources */
+  tw_free_device_extension(tw_dev);
+
+  /* Tell kernel scsi-layer we are gone */
+  scsi_unregister(tw_host);
+
+  return 0;
+} /* End tw_scsi_release() */
+
+/* This function handles scsi inquiry commands */
+int tw_scsiop_inquiry(TW_Device_Extension *tw_dev, int request_id)
+{
+  TW_Param *param;
+  TW_Command *command_packet;
+  u32 command_que_value, command_que_addr;
+  u32 param_value;
+
+  dprintk(KERN_NOTICE "3w-xxxx: tw_scsiop_inquiry()\n");
+
+  /* Initialize command packet */
+  command_que_addr = tw_dev->registers.command_que_addr;
+  command_packet = 
+    (TW_Command *)tw_dev->command_packet_virtual_address[request_id];
+  if (command_packet == NULL) {
+    printk(KERN_WARNING "3w-xxxx: tw_scsiop_inquiry(): Bad command packet "
+	   "virtual address.\n");
+    return 1;
+  }
+  memset(command_packet, 0, sizeof(TW_Sector));
+  command_packet->byte0.opcode = TW_OP_GET_PARAM;
+  command_packet->byte0.sgl_offset = 2;
+  command_packet->size = 4;
+  command_packet->request_id = request_id;
+  command_packet->byte3.unit = 0;
+  command_packet->byte3.host_id = 0;
+  command_packet->status = 0;
+  command_packet->flags = 0;
+  command_packet->byte6.parameter_count = 1;
+
+  /* Now setup the param */
+  if (tw_dev->alignment_virtual_address[request_id] == NULL) {
+    printk(KERN_WARNING "3w-xxxx: tw_scsiop_inquiry(): Bad alignment "
+	   "virtual address.\n");
+    return 1;
+  }
+  param = (TW_Param *)tw_dev->alignment_virtual_address[request_id];
+  memset(param, 0, sizeof(TW_Sector));
+  param->table_id = 3;     /* unit summary table */
+  param->parameter_id = 3; /* unitsstatus parameter */
+  param->parameter_size_bytes = TW_MAX_UNITS;
+  param_value = tw_dev->alignment_physical_address[request_id];
+  if (param_value == 0) {
+    printk(KERN_WARNING "3w-xxxx: tw_scsiop_inquiry(): Bad alignment "
+	   "physical address.\n");
+    return 1;
+  }
+
+  command_packet->byte8.param.sgl[0].address = param_value;
+  command_packet->byte8.param.sgl[0].length = sizeof(TW_Sector);
+  command_que_value = tw_dev->command_packet_physical_address[request_id];
+  if (command_que_value == 0) {
+    printk(KERN_WARNING "3w-xxxx: tw_scsiop_inquiry(): Bad command packet "
+	   "physical address.\n");
+    return 1;
+  }
+
+  /* Now try to post the command packet */
+  tw_post_command_packet(tw_dev, request_id);
+
+  return 0;
+} /* End tw_scsiop_inquiry() */
+
+/* This function is called by the isr to complete an inquiry command */
+int tw_scsiop_inquiry_complete(TW_Device_Extension *tw_dev, int request_id)
+{
+  unsigned char *is_unit_present;
+  unsigned char *request_buffer;
+  int i;
+  TW_Param *param;
+
+  dprintk(KERN_NOTICE "3w-xxxx: tw_scsiop_inquiry_complete()\n");
+
+  /* Fill request buffer */
+  if (tw_dev->srb[request_id]->request_buffer == NULL) {
+    printk(KERN_WARNING "3w-xxxx: tw_scsiop_inquiry_complete(): Request "
+	   "buffer NULL.\n");
+    return 1;
+  }
+  request_buffer = tw_dev->srb[request_id]->request_buffer;
+  memset(request_buffer, 0, tw_dev->srb[request_id]->request_bufflen);
+  request_buffer[0] = TYPE_DISK;                   /* Peripheral device type */
+  request_buffer[1] = 0;                           /* Device type modifier */
+  request_buffer[2] = 0;                           /* No ansi/iso compliance */
+  request_buffer[4] = 31;                          /* Additional length */
+  memcpy(&request_buffer[8], "3ware   ", 8);       /* Vendor ID */
+  memcpy(&request_buffer[16], "3w-xxxx         ", 16); /* Product ID */
+  memcpy(&request_buffer[32], tw_driver_version, 3);
+
+  param = (TW_Param *)tw_dev->alignment_virtual_address[request_id];
+  if (param == NULL) {
+    printk(KERN_WARNING "3w-xxxx: tw_scsiop_inquiry_complete(): "
+	   "Bad alignment virtual address.\n");
+    return 1;
+  }
+  is_unit_present = &(param->data[0]);
+
+  for (i=0 ; i<TW_MAX_UNITS; i++) {
+    if (is_unit_present[i] == 0)
+      tw_dev->is_unit_present[i] = FALSE;
+    else {
+      tw_dev->is_unit_present[i] = TRUE;
+      dprintk(KERN_NOTICE "3w-xxxx: tw_scsiop_inquiry_complete: Unit "
+	      "%d found.\n", i);
+    }
+  }
+
+  return 0;
+} /* End tw_scsiop_inquiry_complete() */
+
+/* This function handles scsi read_capacity commands */
+int tw_scsiop_read_capacity(TW_Device_Extension *tw_dev, int request_id) 
+{
+  TW_Param *param;
+  TW_Command *command_packet;
+  u32 command_que_addr, command_que_value;
+  u32 param_value;
+
+  dprintk(KERN_NOTICE "3w-xxxx: tw_scsiop_read_capacity()\n");
+
+  /* Initialize command packet */
+  command_que_addr = tw_dev->registers.command_que_addr;
+  command_packet = 
+    (TW_Command *)tw_dev->command_packet_virtual_address[request_id];
+  if (command_packet == NULL) {
+    dprintk(KERN_NOTICE "3w-xxxx: tw_scsiop_read_capacity(): Bad command "
+	    "packet virtual address.\n");
+    return 1;
+  }
+  memset(command_packet, 0, sizeof(TW_Sector));
+  command_packet->byte0.opcode = TW_OP_GET_PARAM;
+  command_packet->byte0.sgl_offset = 2;
+  command_packet->size = 4;
+  command_packet->request_id = request_id;
+  command_packet->byte3.unit = tw_dev->srb[request_id]->target;
+  command_packet->byte3.host_id = 0;
+  command_packet->status = 0;
+  command_packet->flags = 0;
+  command_packet->byte6.block_count = 1;
+
+  /* Now setup the param */
+  if (tw_dev->alignment_virtual_address[request_id] == NULL) {
+    dprintk(KERN_NOTICE "3w-xxxx: tw_scsiop_read_capacity(): "
+	    "Bad alignment virtual address.\n");
+    return 1;
+  }
+  param = (TW_Param *)tw_dev->alignment_virtual_address[request_id];
+  memset(param, 0, sizeof(TW_Sector));
+  param->table_id = TW_UNIT_INFORMATION_TABLE_BASE + 
+    tw_dev->srb[request_id]->target;
+  param->parameter_id = 4;  /* unitcapacity parameter */
+  param->parameter_size_bytes = 4;
+  param_value = tw_dev->alignment_physical_address[request_id];
+  if (param_value == 0) {
+    dprintk(KERN_NOTICE "3w-xxxx: tw_scsiop_read_capacity(): Bad alignment "
+	    "physical address.\n");
+    return 1;
+  }
+  
+  command_packet->byte8.param.sgl[0].address = param_value;
+  command_packet->byte8.param.sgl[0].length = sizeof(TW_Sector);
+  command_que_value = tw_dev->command_packet_physical_address[request_id];
+  if (command_que_value == 0) {
+    dprintk(KERN_NOTICE "3w-xxxx: tw_scsiop_read_capacity(): "
+	    "Bad command packet physical address.\n");
+    return 1;
+  }
+
+  /* Now try to post the command to the board */
+  tw_post_command_packet(tw_dev, request_id);
+  
+  return 0;
+} /* End tw_scsiop_read_capacity() */
+
+/* This function is called by the isr to complete a readcapacity command */
+int tw_scsiop_read_capacity_complete(TW_Device_Extension *tw_dev, 
+				     int request_id)
+{
+  unsigned char *param_data;
+  u32 capacity;
+  char *buff;
+  TW_Param *param;
+
+  dprintk(KERN_NOTICE "3w-xxxx: tw_scsiop_read_capacity_complete()\n");
+
+  buff = tw_dev->srb[request_id]->request_buffer;
+  if (buff == NULL) {
+    printk(KERN_WARNING "3w-xxxx: tw_scsiop_read_capacity_complete(): "
+	   "Request buffer NULL.\n");
+    return 1;
+  }
+  memset(buff, 0, tw_dev->srb[request_id]->request_bufflen);
+  param = (TW_Param *)tw_dev->alignment_virtual_address[request_id];
+  if (param == NULL) {
+    printk(KERN_WARNING "3w-xxxx: tw_scsiop_read_capacity_complete(): "
+	   "Bad alignment virtual address.\n");
+    return 1;
+  }
+  param_data = &(param->data[0]);
+
+  capacity = (param_data[3] << 24) | (param_data[2] << 16) | 
+    (param_data[1] << 8) | param_data[0];
+
+  dprintk(KERN_NOTICE "3w-xxxx: tw_scsiop_read_capacity_complete(): "
+	  "Capacity = 0x%x.\n", capacity);
+
+  /* Number of LBA's */
+  buff[0] = (capacity >> 24);
+  buff[1] = (capacity >> 16) & 0xff;
+  buff[2] = (capacity >> 8) & 0xff;
+  buff[3] = capacity & 0xff;
+
+  /* Block size in bytes (512) */
+  buff[4] = (TW_BLOCK_SIZE >> 24);
+  buff[5] = (TW_BLOCK_SIZE >> 16) & 0xff;
+  buff[6] = (TW_BLOCK_SIZE >> 8) & 0xff;
+  buff[7] = TW_BLOCK_SIZE & 0xff;
+
+  return 0;
+} /* End tw_scsiop_read_capacity_complete() */
+
+/* This function handles scsi read or write commands */
+int tw_scsiop_read_write(TW_Device_Extension *tw_dev, int request_id) 
+{
+  TW_Command *command_packet;
+  u32 command_que_addr, command_que_value = 0;
+  u32 lba = 0x0, num_sectors = 0x0;
+  int i;
+  Scsi_Cmnd *srb;
+  struct scatterlist *sglist;
+
+  dprintk(KERN_NOTICE "3w-xxxx: tw_scsiop_read_write()\n");
+
+  if (tw_dev->srb[request_id]->request_buffer == NULL) {
+    printk(KERN_WARNING "3w-xxxx: tw_scsiop_read_write(): Request buffer "
+	   "NULL.\n");
+    return 1;
+  }
+  sglist = (struct scatterlist *)tw_dev->srb[request_id]->request_buffer;
+  srb = tw_dev->srb[request_id];
+
+  /* Initialize command packet */
+  command_que_addr = tw_dev->registers.command_que_addr;
+  command_packet = 
+    (TW_Command *)tw_dev->command_packet_virtual_address[request_id];
+  if (command_packet == NULL) {
+    dprintk(KERN_NOTICE "3w-xxxx: tw_scsiop_read_write(): Bad command "
+	    "packet virtual address.\n");
+    return 1;
+  }
+
+  if (srb->cmnd[0] == READ_6 || srb->cmnd[0] == READ_10) 
+    command_packet->byte0.opcode = TW_OP_READ;
+  else
+    command_packet->byte0.opcode = TW_OP_WRITE;
+
+  command_packet->byte0.sgl_offset = 3;
+  command_packet->size = 5;
+  command_packet->request_id = request_id;
+  command_packet->byte3.unit = srb->target;
+  command_packet->byte3.host_id = 0;
+  command_packet->status = 0;
+  command_packet->flags = 0;
+
+  if ((srb->cmnd[0] == WRITE_6) || (srb->cmnd[0] == WRITE_10)) {
+    if ((srb->cmnd[1] & 0x8) || (srb->cmnd[1] & 0x10)) 
+      command_packet->flags = 1;
+  }
+
+  if (srb->cmnd[0] == READ_6 || srb->cmnd[0] == WRITE_6) {
+    lba = ((u32)srb->cmnd[1] << 16) | ((u32)srb->cmnd[2] << 8) | 
+      (u32)srb->cmnd[3];
+    num_sectors = (u32)srb->cmnd[4];
+  } else {
+    lba = ((u32)srb->cmnd[2] << 24) | ((u32)srb->cmnd[3] << 16) | 
+      ((u32)srb->cmnd[4] << 8) | (u32)srb->cmnd[5];
+    num_sectors = (u32)srb->cmnd[8] | ((u32)srb->cmnd[7] << 8);
+  }
+  
+  /* Update sector statistic */
+  tw_dev->sector_count = num_sectors;
+  if (tw_dev->sector_count > tw_dev->max_sector_count)
+    tw_dev->max_sector_count = tw_dev->sector_count;
+  
+  dprintk(KERN_NOTICE "3w-xxxx: tw_scsiop_read_write(): lba = 0x%x "
+	  "num_sectors = 0x%x\n", lba, num_sectors);
+  command_packet->byte8.io.lba = lba;
+  command_packet->byte6.block_count = num_sectors;
+
+  /* Do this if there are no sg list entries */
+  if (tw_dev->srb[request_id]->use_sg == 0) {    
+    dprintk(KERN_NOTICE "3w-xxxx: tw_scsiop_read_write(): SG = 0\n");
+    command_packet->byte8.io.sgl[0].address = 
+      virt_to_bus(tw_dev->srb[request_id]->request_buffer);
+    command_packet->byte8.io.sgl[0].length =
+      tw_dev->srb[request_id]->request_bufflen;
+  }
+
+  /* Do this if we have multiple sg list entries */
+  if (tw_dev->srb[request_id]->use_sg > 0) {
+    for (i=0;i<tw_dev->srb[request_id]->use_sg; i++) {
+      command_packet->byte8.io.sgl[i].address = virt_to_bus(sglist[i].address);
+      command_packet->byte8.io.sgl[i].length = sglist[i].length;
+      command_packet->size+=2;
+    }
+    if (tw_dev->srb[request_id]->use_sg > 1)
+      command_packet->size-=2;
+  }
+
+  /* Update SG statistics */
+  tw_dev->sgl_entries = tw_dev->srb[request_id]->use_sg;
+  if (tw_dev->sgl_entries > tw_dev->max_sgl_entries)
+    tw_dev->max_sgl_entries = tw_dev->sgl_entries;
+
+  command_que_value = tw_dev->command_packet_physical_address[request_id];
+  if (command_que_value == 0) {
+    dprintk(KERN_WARNING "3w-xxxx: tw_scsiop_read_write(): Bad command "
+	    "packet physical address.\n");
+    return 1;
+  }
+      
+  /* Now try to post the command to the board */
+  tw_post_command_packet(tw_dev, request_id);
+
+  return 0;
+} /* End tw_scsiop_read_write() */
+
+/* This function will handle test unit ready scsi command */
+int tw_scsiop_test_unit_ready(TW_Device_Extension *tw_dev, int request_id)
+{
+  dprintk(KERN_NOTICE "3w-xxxx: tw_scsiop_test_unit_ready()\n");
+
+  /* Tell the scsi layer were done */
+  tw_dev->state[request_id] = TW_S_COMPLETED;
+  tw_state_request_finish(tw_dev, request_id);
+  tw_dev->srb[request_id]->result = (DID_OK << 16);
+  tw_dev->srb[request_id]->scsi_done(tw_dev->srb[request_id]);
+
+  return 0;
+} /* End tw_scsiop_test_unit_ready() */
+
+/* This function will setup the interrupt handler */
+int tw_setup_irq(TW_Device_Extension *tw_dev)
+{
+  char *device = TW_DEVICE_NAME;
+  int error;
+
+  dprintk(KERN_NOTICE "3w-xxxx: tw_setup_irq()\n");
+  error = request_irq(tw_dev->tw_pci_dev->irq, tw_interrupt, 
+		      SA_SHIRQ, device, tw_dev);
+  if (error < 0) {
+    printk(KERN_WARNING "3w-xxxx: tw_setup_irq(): Error requesting IRQ: %d "
+	   "for card %d.\n", tw_dev->tw_pci_dev->irq, tw_dev->host->host_no);
+    return 1;
+  }
+  return 0;
+} /* End tw_setup_irq() */
+
+/* This function will soft reset the controller */
+void tw_soft_reset(TW_Device_Extension *tw_dev) 
+{
+  u32 control_reg_addr, control_reg_value;
+
+  control_reg_addr = tw_dev->registers.control_reg_addr;
+  control_reg_value = ( TW_CONTROL_ISSUE_SOFT_RESET |
+			TW_CONTROL_CLEAR_HOST_INTERRUPT |
+			TW_CONTROL_CLEAR_ATTENTION_INTERRUPT |
+			TW_CONTROL_MASK_COMMAND_INTERRUPT |
+			TW_CONTROL_MASK_RESPONSE_INTERRUPT |
+			TW_CONTROL_CLEAR_ERROR_STATUS | 
+			TW_CONTROL_DISABLE_INTERRUPTS);
+  outl(control_reg_value, control_reg_addr);
+} /* End tw_soft_reset() */
+
+/* This function will free a request_id */
+int tw_state_request_finish(TW_Device_Extension *tw_dev, 
+			    int request_id)
+{
+  dprintk(KERN_NOTICE "3w-xxxx: tw_state_request_finish()\n");
+  
+  do {    
+    if (tw_dev->free_tail == TW_Q_LENGTH-1)
+      tw_dev->free_tail = TW_Q_START;
+    else
+      tw_dev->free_tail = tw_dev->free_tail + 1;
+  } 
+  while ((tw_dev->state[tw_dev->free_queue[tw_dev->free_tail]] != 
+	  TW_S_COMPLETED));
+
+  tw_dev->free_queue[tw_dev->free_tail] = request_id;
+
+  tw_dev->state[request_id] = TW_S_FINISHED;
+  dprintk(KERN_NOTICE "3w-xxxx: tw_state_request_finish(): Freeing "
+	  "request_id %d\n", request_id);
+
+  return 0;
+} /* End tw_state_request_finish() */
+
+/* This function will assign an available request_id */
+int tw_state_request_start(TW_Device_Extension *tw_dev, int *request_id)
+{
+  int id = 0;
+
+  dprintk(KERN_NOTICE "3w-xxxx: tw_state_request_start()\n");
+
+  /* Obtain next free request_id */
+  do {
+    if (tw_dev->free_head == TW_Q_LENGTH - 1)
+      tw_dev->free_head = TW_Q_START;
+    else
+      tw_dev->free_head = tw_dev->free_head + 1;
+  }
+  while ((tw_dev->state[tw_dev->free_queue[tw_dev->free_head]] == 
+	  TW_S_STARTED) ||
+	 (tw_dev->state[tw_dev->free_queue[tw_dev->free_head]] == 
+	  TW_S_POSTED) ||
+	 (tw_dev->state[tw_dev->free_queue[tw_dev->free_head]] == 
+	  TW_S_PENDING) ||
+	 (tw_dev->state[tw_dev->free_queue[tw_dev->free_head]] == 
+	  TW_S_COMPLETED));
+
+  id = tw_dev->free_queue[tw_dev->free_head];
+
+  if (tw_dev->free_head == TW_Q_LENGTH - 1)
+    tw_dev->free_head = TW_Q_START;
+  else
+    tw_dev->free_head = tw_dev->free_head + 1;
+
+  dprintk(KERN_NOTICE "3w-xxxx: tw_state_request_start(): id = %d.\n", id);
+  *request_id = id;
+  tw_dev->state[id] = TW_S_STARTED;
+
+  return 0;
+} /* End tw_state_request_start() */
+
+/* This function will unmask the command interrupt on the controller */
+void tw_unmask_command_interrupt(TW_Device_Extension *tw_dev)
+{
+  u32 control_reg_addr, control_reg_value;
+
+  control_reg_addr = tw_dev->registers.control_reg_addr;
+  control_reg_value = TW_CONTROL_UNMASK_COMMAND_INTERRUPT;
+  outl(control_reg_value, control_reg_addr);
+} /* End tw_unmask_command_interrupt() */
+
+/* Now get things going */
+#ifdef MODULE
+Scsi_Host_Template driver_template = TWXXXX;
+#include "../scsi/scsi_module.c"
+#endif
Index: oldkernel/linux/drivers/block/3w-xxxx.h
diff -u /dev/null linux/drivers/block/3w-xxxx.h:1.1
--- /dev/null	Mon Jul 31 21:15:04 2000
+++ linux/drivers/block/3w-xxxx.h	Fri Jul  7 16:18:17 2000
@@ -0,0 +1,374 @@
+/* 
+   3w-xxxx.h -- 3ware Storage Controller device driver for Linux.
+   
+   Written By: Adam Radford <linux@3ware.com>
+   Copyright (C) 1999 3ware Inc.
+
+   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; version 2 of the License.
+
+   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.                              
+
+   NO WARRANTY                                                               
+   THE PROGRAM IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OR        
+   CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED INCLUDING, WITHOUT      
+   LIMITATION, ANY WARRANTIES OR CONDITIONS OF TITLE, NON-INFRINGEMENT,      
+   MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. Each Recipient is    
+   solely responsible for determining the appropriateness of using and       
+   distributing the Program and assumes all risks associated with its        
+   exercise of rights under this Agreement, including but not limited to     
+   the risks and costs of program errors, damage to or loss of data,         
+   programs or equipment, and unavailability or interruption of operations.  
+
+   DISCLAIMER OF LIABILITY                                                   
+   NEITHER RECIPIENT NOR ANY CONTRIBUTORS SHALL HAVE ANY LIABILITY FOR ANY   
+   DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL        
+   DAMAGES (INCLUDING WITHOUT LIMITATION LOST PROFITS), HOWEVER CAUSED AND   
+   ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR     
+   TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE    
+   USE OR DISTRIBUTION OF THE PROGRAM OR THE EXERCISE OF ANY RIGHTS GRANTED  
+   HEREUNDER, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGES             
+
+   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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA 
+
+   Bugs/Comments/Suggestions should be mailed to:                            
+   linux@3ware.com
+   
+   For more information, goto:
+   http://www.3ware.com
+*/
+
+/* Control register bit definitions */
+#define TW_CONTROL_CLEAR_HOST_INTERRUPT	       0x00080000
+#define TW_CONTROL_CLEAR_ATTENTION_INTERRUPT   0x00040000
+#define TW_CONTROL_MASK_COMMAND_INTERRUPT      0x00020000
+#define TW_CONTROL_MASK_RESPONSE_INTERRUPT     0x00010000
+#define TW_CONTROL_UNMASK_COMMAND_INTERRUPT    0x00008000
+#define TW_CONTROL_UNMASK_RESPONSE_INTERRUPT   0x00004000
+#define TW_CONTROL_CLEAR_ERROR_STATUS	       0x00000200
+#define TW_CONTROL_ISSUE_SOFT_RESET	       0x00000100
+#define TW_CONTROL_ENABLE_INTERRUPTS	       0x00000080
+#define TW_CONTROL_DISABLE_INTERRUPTS	       0x00000040
+#define TW_CONTROL_ISSUE_HOST_INTERRUPT	       0x00000020
+
+/* Status register bit definitions */
+#define TW_STATUS_MAJOR_VERSION_MASK	       0xF0000000
+#define TW_STATUS_MINOR_VERSION_MASK	       0x0F000000
+#define TW_STATUS_PCI_PARITY_ERROR	       0x00800000
+#define TW_STATUS_QUEUE_ERROR		       0x00400000
+#define TW_STATUS_MICROCONTROLLER_ERROR	       0x00200000
+#define TW_STATUS_PCI_ABORT		       0x00100000
+#define TW_STATUS_HOST_INTERRUPT	       0x00080000
+#define TW_STATUS_ATTENTION_INTERRUPT	       0x00040000
+#define TW_STATUS_COMMAND_INTERRUPT	       0x00020000
+#define TW_STATUS_RESPONSE_INTERRUPT	       0x00010000
+#define TW_STATUS_COMMAND_QUEUE_FULL	       0x00008000
+#define TW_STATUS_RESPONSE_QUEUE_EMPTY	       0x00004000
+#define TW_STATUS_MICROCONTROLLER_READY	       0x00002000
+#define TW_STATUS_COMMAND_QUEUE_EMPTY	       0x00001000
+#define TW_STATUS_ALL_INTERRUPTS	       0x000F0000
+#define TW_STATUS_CLEARABLE_BITS	       0x00D00000
+#define TW_STATUS_EXPECTED_BITS		       0x00002000
+#define TW_STATUS_UNEXPECTED_BITS	       0x00F80000
+
+/* RESPONSE QUEUE BIT DEFINITIONS */
+#define TW_RESPONSE_ID_MASK		       0x00000FF0
+
+/* PCI related defines */
+#define TW_IO_ADDRESS_RANGE		       0xD
+#define TW_DEVICE_NAME			       "3ware Storage Controller"
+#define TW_VENDOR_ID (0x13C1)	/* 3ware */
+#define TW_DEVICE_ID (0x1000)	/* Storage Controller */
+
+/* Command packet opcodes */
+#define TW_OP_NOP	      0x0
+#define TW_OP_INIT_CONNECTION 0x1
+#define TW_OP_READ	      0x2
+#define TW_OP_WRITE	      0x3
+#define TW_OP_VERIFY	      0x4
+#define TW_OP_GET_PARAM	      0x12
+#define TW_OP_SET_PARAM	      0x13
+#define TW_OP_SECTOR_INFO     0x1a
+#define TW_OP_AEN_LISTEN      0x1c
+
+/* Asynchronous Event Notification (AEN) Codes */
+#define TW_AEN_QUEUE_EMPTY       0x0000
+#define TW_AEN_SOFT_RESET        0x0001
+#define TW_AEN_DEGRADED_MIRROR   0x0002
+#define TW_AEN_CONTROLLER_ERROR  0x0003
+#define TW_AEN_REBUILD_FAIL      0x0004
+#define TW_AEN_REBUILD_DONE      0x0005
+#define TW_AEN_QUEUE_FULL        0x00ff
+#define TW_AEN_TABLE_UNDEFINED   0x15
+
+/* Misc defines */
+#define TW_ALIGNMENT			      0x200 /* 16 D-WORDS */
+#define TW_MAX_UNITS			      16
+#define TW_COMMAND_ALIGNMENT_MASK	      0x1ff
+#define TW_INIT_MESSAGE_CREDITS		      0x100
+#define TW_INIT_COMMAND_PACKET_SIZE	      0x3
+#define TW_POLL_MAX_RETRIES        	      10000
+#define TW_MAX_SGL_LENGTH		      62
+#define TW_Q_LENGTH			      256
+#define TW_Q_START			      0
+#define TW_MAX_SLOT			      32
+#define TW_MAX_PCI_BUSES		      255
+#define TW_MAX_RESET_TRIES		      3
+#define TW_UNIT_INFORMATION_TABLE_BASE	      0x300
+#define TW_MAX_CMDS_PER_LUN		      (TW_Q_LENGTH-2)/TW_MAX_UNITS
+#define TW_BLOCK_SIZE			      0x200 /* 512-byte blocks */
+#define TW_IOCTL                              0x80
+#define TW_MAX_AEN_TRIES                      100
+
+#ifndef MAJOR_NR 
+#define MAJOR_NR			      8 /* SCSI */
+#endif
+
+/* Macros */
+#define TW_STATUS_ERRORS(x) \
+(((x & TW_STATUS_PCI_ABORT) || \
+(x & TW_STATUS_PCI_PARITY_ERROR) || \
+(x & TW_STATUS_QUEUE_ERROR) || \
+(x & TW_STATUS_MICROCONTROLLER_ERROR)) && \
+(x & TW_STATUS_MICROCONTROLLER_READY))
+
+#ifdef TW_DEBUG
+#define dprintk(msg...) printk(msg)
+#else
+#define dprintk(msg...) do { } while(0);
+#endif
+
+extern struct proc_dir_entry tw_scsi_proc_entry;
+
+/* Scatter Gather List Entry */
+typedef struct TAG_TW_SG_Entry
+{
+  unsigned long address;
+  unsigned long length;
+} TW_SG_Entry;
+
+typedef unsigned char TW_Sector[512];
+
+/* Command Packet */
+typedef struct TW_Command 
+{
+  /* First DWORD */
+  struct {
+    unsigned char opcode:5;
+    unsigned char sgl_offset:3;
+  } byte0;
+  unsigned char size;
+  unsigned char request_id;
+  struct {
+    unsigned char unit:4;
+    unsigned char host_id:4;
+  } byte3;
+  /* Second DWORD */
+  unsigned char status;
+  unsigned char flags;
+  union {
+    unsigned short block_count;
+    unsigned short parameter_count;
+    unsigned short message_credits;
+  } byte6;
+  union {
+    struct {
+      unsigned long lba;
+      TW_SG_Entry sgl[TW_MAX_SGL_LENGTH];
+      unsigned long padding;  /* pad to 512 bytes */
+    } io;
+    struct {
+      TW_SG_Entry sgl[TW_MAX_SGL_LENGTH];
+      unsigned long padding[2];
+    } param;
+    struct {
+      unsigned long response_queue_pointer;
+      unsigned long padding[125];
+    } init_connection;
+    struct {
+      char version[504];
+    } ioctl_miniport_version;
+  } byte8;
+} TW_Command;
+
+typedef struct TAG_TW_Ioctl
+{
+  int buffer;
+  unsigned char opcode;
+  unsigned short table_id;
+  unsigned char parameter_id;
+  unsigned char parameter_size_bytes;
+  unsigned char data[1];
+} TW_Ioctl;
+
+/* GetParam descriptor */
+typedef struct 
+{
+  unsigned short  table_id;
+  unsigned char	  parameter_id;
+  unsigned char	  parameter_size_bytes;
+  unsigned char	  data[1];
+} TW_Param, *PTW_Param;
+
+/* Response queue */
+typedef union TAG_TW_Response_Queue
+{
+  struct 
+  {
+    u32 undefined_1: 4;
+    u32 response_id: 8;
+    u32 undefined_2: 20;
+  } u;
+  u32 value;
+} TW_Response_Queue;
+
+typedef struct TAG_TW_Registers 
+{
+  u32 base_addr;
+  u32 control_reg_addr;
+  u32 status_reg_addr;
+  u32 command_que_addr;
+  u32 response_que_addr;
+} TW_Registers;
+
+typedef struct TAG_TW_Info
+{
+  char *buffer;
+  int length;
+  int offset;
+  int position;
+} TW_Info;
+
+typedef enum TAG_TW_Cmd_State 
+{
+  TW_S_INITIAL,		  /* Initial state */
+  TW_S_STARTED,		  /* Id in use */
+  TW_S_POSTED,		  /* Posted to the controller */
+  TW_S_PENDING,		  /* Waiting to be posted in isr */
+  TW_S_COMPLETED,	  /* Completed by isr */
+  TW_S_FINISHED,	  /* I/O completely done */
+} TW_Cmd_State;
+
+typedef struct TAG_TW_Device_Extension
+{
+  TW_Registers registers;
+  u32 *alignment_virtual_address[TW_Q_LENGTH];
+  u32 alignment_physical_address[TW_Q_LENGTH];
+  int is_unit_present[TW_MAX_UNITS];
+  int num_units;
+  u32  *command_packet_virtual_address[TW_Q_LENGTH];
+  u32 command_packet_physical_address[TW_Q_LENGTH];
+  struct pci_dev *tw_pci_dev;
+  Scsi_Cmnd *srb[TW_Q_LENGTH];
+  unsigned char free_queue[TW_Q_LENGTH];
+  unsigned char free_head;
+  unsigned char free_tail;
+  unsigned char pending_queue[TW_Q_LENGTH];
+  unsigned char pending_head;
+  unsigned char pending_tail;
+  TW_Cmd_State state[TW_Q_LENGTH];
+  u32 posted_request_count;
+  u32 max_posted_request_count;
+  u32 request_count_marked_pending;
+  u32 pending_request_count;
+  u32 max_pending_request_count;
+  u32 max_sgl_entries;
+  u32 sgl_entries;
+  u32 num_aborts;
+  u32 num_resets;
+  u32 sector_count;
+  u32 max_sector_count;
+  struct Scsi_Host *host;
+  spinlock_t tw_lock;
+  unsigned char ioctl_size[TW_Q_LENGTH];
+  unsigned short aen_queue[TW_Q_LENGTH];
+  unsigned char aen_head;
+  unsigned char aen_tail;
+} TW_Device_Extension;
+
+/* Function prototypes */
+int tw_aen_complete(TW_Device_Extension *tw_dev, int request_id);
+int tw_aen_drain_queue(TW_Device_Extension *tw_dev);
+int tw_aen_read_queue(TW_Device_Extension *tw_dev, int request_id);
+int tw_allocate_memory(TW_Device_Extension *tw_dev, int request_id, 
+		       int size, int which);
+int tw_check_bits(u32 status_reg_value);
+int tw_check_errors(TW_Device_Extension *tw_dev);
+void tw_clear_attention_interrupt(TW_Device_Extension *tw_dev);
+void tw_clear_host_interrupt(TW_Device_Extension *tw_dev);
+static int tw_copy_info(TW_Info *info, char *fmt, ...);
+static void tw_copy_mem_info(TW_Info *info, char *data, int len);
+void tw_disable_interrupts(TW_Device_Extension *tw_dev);
+int tw_empty_response_que(TW_Device_Extension *tw_dev);
+void tw_enable_interrupts(TW_Device_Extension *tw_dev);
+int tw_findcards(Scsi_Host_Template *tw_host);
+void tw_free_device_extension(TW_Device_Extension *tw_dev);
+int tw_initconnection(TW_Device_Extension *tw_dev);
+int tw_initialize_device_extension(TW_Device_Extension *tw_dev);
+int tw_initialize_units(TW_Device_Extension *tw_dev);
+static void tw_interrupt(int irq, void *dev_instance, struct pt_regs *regs);
+int tw_ioctl(TW_Device_Extension *tw_dev, int request_id);
+int tw_ioctl_complete(TW_Device_Extension *tw_dev, int request_id);
+void tw_mask_command_interrupt(TW_Device_Extension *tw_dev);
+int tw_poll_status(TW_Device_Extension *tw_dev, u32 flag, int seconds);
+int tw_post_command_packet(TW_Device_Extension *tw_dev, int request_id);
+int tw_reset_device_extension(TW_Device_Extension *tw_dev);
+int tw_reset_sequence(TW_Device_Extension *tw_dev);
+int tw_scsi_biosparam(Disk *disk, kdev_t dev, int geom[]);
+int tw_scsi_detect(Scsi_Host_Template *tw_host);
+int tw_scsi_eh_abort(Scsi_Cmnd *SCpnt);
+int tw_scsi_eh_reset(Scsi_Cmnd *SCpnt);
+int tw_scsi_proc_info(char *buffer, char **start, off_t offset, int length,
+		      int inode, int inout);
+int tw_scsi_queue(Scsi_Cmnd *cmd, void (*done) (Scsi_Cmnd *));
+int tw_scsi_release(struct Scsi_Host *tw_host);
+int tw_scsiop_inquiry(TW_Device_Extension *tw_dev, int request_id);
+int tw_scsiop_inquiry_complete(TW_Device_Extension *tw_dev, int request_id);
+int tw_scsiop_read_capacity(TW_Device_Extension *tw_dev, int request_id);
+int tw_scsiop_read_capacity_complete(TW_Device_Extension *tw_dev, 
+				     int request_id);
+int tw_scsiop_read_write(TW_Device_Extension *tw_dev, int request_id);
+int tw_scsiop_test_unit_ready(TW_Device_Extension *tw_dev, int request_id);
+int tw_setup_irq(TW_Device_Extension *tw_dev);
+void tw_soft_reset(TW_Device_Extension *tw_dev);
+int tw_state_request_finish(TW_Device_Extension *tw_dev,int request_id);
+int tw_state_request_start(TW_Device_Extension *tw_dev, int *request_id);
+void tw_unmask_command_interrupt(TW_Device_Extension *tw_dev);
+
+/* Scsi_Host_Template Initializer */
+#define TWXXXX {			     \
+    next : NULL,			     \
+    module : NULL,			     \
+    proc_dir : &tw_scsi_proc_entry,	     \
+    proc_info : tw_scsi_proc_info,	     \
+    name : "3ware Storage Controller",	     \
+    detect : tw_scsi_detect,		     \
+    release : tw_scsi_release,		     \
+    info : NULL,			     \
+    ioctl : NULL,                            \
+    command : NULL,			     \
+    queuecommand : tw_scsi_queue,	     \
+    eh_strategy_handler : NULL,		     \
+    eh_abort_handler : tw_scsi_eh_abort,     \
+    eh_device_reset_handler : NULL,	     \
+    eh_bus_reset_handler : NULL,	     \
+    eh_host_reset_handler : tw_scsi_eh_reset,\
+    abort : NULL,		             \
+    reset : NULL,		             \
+    slave_attach : NULL,		     \
+    bios_param : tw_scsi_biosparam,	     \
+    can_queue : TW_Q_LENGTH,		     \
+    this_id: -1,			     \
+    sg_tablesize : TW_MAX_SGL_LENGTH,	     \
+    cmd_per_lun: TW_MAX_CMDS_PER_LUN,	     \
+    present : 0,			     \
+    unchecked_isa_dma : 0,		     \
+    use_clustering : ENABLE_CLUSTERING,	     \
+    use_new_eh_code : 1			     \
+ }
Index: oldkernel/linux/drivers/block/Config.in
diff -u linux/drivers/block/Config.in:1.2 linux/drivers/block/Config.in:1.3
--- linux/drivers/block/Config.in:1.2	Thu Jun  1 14:51:28 2000
+++ linux/drivers/block/Config.in	Fri Jul  7 15:36:42 2000
@@ -119,6 +119,7 @@
 tristate 'XT hard disk support' CONFIG_BLK_DEV_XD
 if [ "$CONFIG_PCI" = "y" ]; then
   tristate 'Mylex DAC960/DAC1100 PCI RAID Controller support' CONFIG_BLK_DEV_DAC960
+  tristate '3ware Storage Controller support' CONFIG_BLK_DEV_3WARE
 fi
 
 # PARIDE doesn't need PARPORT, but if PARPORT is configured as a module,
Index: oldkernel/linux/drivers/block/DAC960.c
diff -u linux/drivers/block/DAC960.c:1.2 linux/drivers/block/DAC960.c:1.3
--- linux/drivers/block/DAC960.c:1.2	Wed May 31 14:57:57 2000
+++ linux/drivers/block/DAC960.c	Fri Jul  7 15:36:42 2000
@@ -1,8 +1,8 @@
 /*
 
-  Linux Driver for Mylex DAC960 and DAC1100 PCI RAID Controllers
+  Linux Driver for Mylex DAC960/AcceleRAID/eXtremeRAID PCI RAID Controllers
 
-  Copyright 1998-1999 by Leonard N. Zubkoff <lnz@dandelion.com>
+  Copyright 1998-2000 by Leonard N. Zubkoff <lnz@dandelion.com>
 
   This program is free software; you may redistribute and/or modify it under
   the terms of the GNU General Public License Version 2 as published by the
@@ -19,8 +19,8 @@
 */
 
 
-#define DAC960_DriverVersion			"2.2.5"
-#define DAC960_DriverDate			"23 January 2000"
+#define DAC960_DriverVersion			"2.2.6"
+#define DAC960_DriverDate			"31 May 2000"
 
 
 #include <linux/version.h>
@@ -55,7 +55,7 @@
 
 
 /*
-  DAC960_ActiveControllerCount is the number of Active DAC960 Controllers
+  DAC960_ActiveControllerCount is the number of active DAC960 Controllers
   detected.
 */
 
@@ -130,7 +130,7 @@
 */
 
 static boolean DAC960_Failure(DAC960_Controller_T *Controller,
-			      char *ErrorMessage)
+			      unsigned char *ErrorMessage)
 {
   DAC960_Error("While configuring DAC960 PCI RAID Controller at\n",
 	       Controller);
@@ -150,17 +150,128 @@
 
 
 /*
-  DAC960_ClearCommand clears critical fields of Command.
+  DAC960_CreateAuxiliaryStructures allocates and initializes the auxiliary
+  data structures for Controller.  It returns true on success and false on
+  failure.
 */
 
-static inline void DAC960_ClearCommand(DAC960_Command_T *Command)
+static boolean DAC960_CreateAuxiliaryStructures(DAC960_Controller_T *Controller)
 {
-  DAC960_CommandMailbox_T *CommandMailbox = &Command->CommandMailbox;
-  CommandMailbox->Words[0] = 0;
-  CommandMailbox->Words[1] = 0;
-  CommandMailbox->Words[2] = 0;
-  CommandMailbox->Words[3] = 0;
-  Command->CommandStatus = 0;
+  int CommandAllocationLength, CommandAllocationGroupSize;
+  int CommandsRemaining = 0, CommandIdentifier, CommandGroupByteCount;
+  void *AllocationPointer = NULL;
+  if (Controller->FirmwareType == DAC960_V1_Controller)
+    {
+      CommandAllocationLength = offsetof(DAC960_Command_T, V1.EndMarker);
+      CommandAllocationGroupSize = DAC960_V1_CommandAllocationGroupSize;
+    }
+  else
+    {
+      CommandAllocationLength = offsetof(DAC960_Command_T, V2.EndMarker);
+      CommandAllocationGroupSize = DAC960_V2_CommandAllocationGroupSize;
+    }
+  Controller->CommandAllocationGroupSize = CommandAllocationGroupSize;
+  Controller->FreeCommands = NULL;
+  for (CommandIdentifier = 1;
+       CommandIdentifier <= Controller->DriverQueueDepth;
+       CommandIdentifier++)
+    {
+      DAC960_Command_T *Command;
+      if (--CommandsRemaining <= 0)
+	{
+	  CommandsRemaining =
+	    Controller->DriverQueueDepth - CommandIdentifier + 1;
+	  if (CommandsRemaining > CommandAllocationGroupSize)
+	    CommandsRemaining = CommandAllocationGroupSize;
+	  CommandGroupByteCount =
+	    CommandsRemaining * CommandAllocationLength;
+	  AllocationPointer = kmalloc(CommandGroupByteCount, GFP_ATOMIC);
+	  if (AllocationPointer == NULL)
+	    return DAC960_Failure(Controller, "AUXILIARY STRUCTURE CREATION");
+	  memset(AllocationPointer, 0, CommandGroupByteCount);
+	}
+      Command = (DAC960_Command_T *) AllocationPointer;
+      AllocationPointer += CommandAllocationLength;
+      Command->CommandIdentifier = CommandIdentifier;
+      Command->Controller = Controller;
+      Command->Next = Controller->FreeCommands;
+      Controller->FreeCommands = Command;
+      Controller->Commands[CommandIdentifier-1] = Command;
+    }
+  return true;
+}
+
+
+/*
+  DAC960_DestroyAuxiliaryStructures deallocates the auxiliary data
+  structures for Controller.
+*/
+
+static void DAC960_DestroyAuxiliaryStructures(DAC960_Controller_T *Controller)
+{
+  int i;
+  Controller->FreeCommands = NULL;
+  for (i = 0; i < Controller->DriverQueueDepth; i++)
+    {
+      DAC960_Command_T *Command = Controller->Commands[i];
+      if (Command != NULL &&
+	  (Command->CommandIdentifier
+	   % Controller->CommandAllocationGroupSize) == 1)
+	kfree(Command);
+      Controller->Commands[i] = NULL;
+    }
+  if (Controller->CombinedStatusBuffer != NULL)
+    {
+      kfree(Controller->CombinedStatusBuffer);
+      Controller->CombinedStatusBuffer = NULL;
+      Controller->CurrentStatusBuffer = NULL;
+    }
+  if (Controller->FirmwareType == DAC960_V1_Controller) return;
+  for (i = 0; i < DAC960_MaxLogicalDrives; i++)
+    if (Controller->V2.LogicalDeviceInformation[i] != NULL)
+      {
+	kfree(Controller->V2.LogicalDeviceInformation[i]);
+	Controller->V2.LogicalDeviceInformation[i] = NULL;
+      }
+  for (i = 0; i < DAC960_V2_MaxPhysicalDevices; i++)
+    {
+      if (Controller->V2.PhysicalDeviceInformation[i] != NULL)
+	{
+	  kfree(Controller->V2.PhysicalDeviceInformation[i]);
+	  Controller->V2.PhysicalDeviceInformation[i] = NULL;
+	}
+      if (Controller->V2.InquiryUnitSerialNumber[i] != NULL)
+	{
+	  kfree(Controller->V2.InquiryUnitSerialNumber[i]);
+	  Controller->V2.InquiryUnitSerialNumber[i] = NULL;
+	}
+    }
+}
+
+
+/*
+  DAC960_V1_ClearCommand clears critical fields of Command for DAC960 V1
+  Firmware Controllers.
+*/
+
+static inline void DAC960_V1_ClearCommand(DAC960_Command_T *Command)
+{
+  DAC960_V1_CommandMailbox_T *CommandMailbox = &Command->V1.CommandMailbox;
+  memset(CommandMailbox, 0, sizeof(DAC960_V1_CommandMailbox_T));
+  Command->V1.CommandStatus = 0;
+}
+
+
+/*
+  DAC960_V2_ClearCommand clears critical fields of Command for DAC960 V2
+  Firmware Controllers.
+*/
+
+static inline void DAC960_V2_ClearCommand(DAC960_Command_T *Command)
+{
+  DAC960_V2_CommandMailbox_T *CommandMailbox = &Command->V2.CommandMailbox;
+  memset(CommandMailbox, 0, sizeof(DAC960_V2_CommandMailbox_T));
+  Command->V2.CommandStatus = 0;
 }
 
 
@@ -211,66 +322,181 @@
 
 
 /*
-  DAC960_QueueCommand queues Command.
+  DAC960_BA_QueueCommand queues Command for DAC960 BA Series Controllers.
 */
 
-static void DAC960_QueueCommand(DAC960_Command_T *Command)
+static void DAC960_BA_QueueCommand(DAC960_Command_T *Command)
 {
   DAC960_Controller_T *Controller = Command->Controller;
   void *ControllerBaseAddress = Controller->BaseAddress;
-  DAC960_CommandMailbox_T *CommandMailbox = &Command->CommandMailbox;
-  DAC960_CommandMailbox_T *NextCommandMailbox;
-  CommandMailbox->Common.CommandIdentifier = Command - Controller->Commands;
-  switch (Controller->ControllerType)
-    {
-    case DAC960_V5_Controller:
-      NextCommandMailbox = Controller->NextCommandMailbox;
-      DAC960_V5_WriteCommandMailbox(NextCommandMailbox, CommandMailbox);
-      if (Controller->PreviousCommandMailbox1->Words[0] == 0 ||
-	  Controller->PreviousCommandMailbox2->Words[0] == 0)
-	{
-	  if (Controller->DualModeMemoryMailboxInterface)
-	    DAC960_V5_MemoryMailboxNewCommand(ControllerBaseAddress);
-	  else DAC960_V5_HardwareMailboxNewCommand(ControllerBaseAddress);
-	}
-      Controller->PreviousCommandMailbox2 = Controller->PreviousCommandMailbox1;
-      Controller->PreviousCommandMailbox1 = NextCommandMailbox;
-      if (++NextCommandMailbox > Controller->LastCommandMailbox)
-	NextCommandMailbox = Controller->FirstCommandMailbox;
-      Controller->NextCommandMailbox = NextCommandMailbox;
-      break;
-    case DAC960_V4_Controller:
-      NextCommandMailbox = Controller->NextCommandMailbox;
-      DAC960_V4_WriteCommandMailbox(NextCommandMailbox, CommandMailbox);
-      if (Controller->PreviousCommandMailbox1->Words[0] == 0 ||
-	  Controller->PreviousCommandMailbox2->Words[0] == 0)
-	{
-	  if (Controller->DualModeMemoryMailboxInterface)
-	    DAC960_V4_MemoryMailboxNewCommand(ControllerBaseAddress);
-	  else DAC960_V4_HardwareMailboxNewCommand(ControllerBaseAddress);
-	}
-      Controller->PreviousCommandMailbox2 = Controller->PreviousCommandMailbox1;
-      Controller->PreviousCommandMailbox1 = NextCommandMailbox;
-      if (++NextCommandMailbox > Controller->LastCommandMailbox)
-	NextCommandMailbox = Controller->FirstCommandMailbox;
-      Controller->NextCommandMailbox = NextCommandMailbox;
-      break;
-    case DAC960_V3_Controller:
-      while (DAC960_V3_MailboxFullP(ControllerBaseAddress))
-	udelay(1);
-      DAC960_V3_WriteCommandMailbox(ControllerBaseAddress, CommandMailbox);
-      DAC960_V3_NewCommand(ControllerBaseAddress);
-      break;
-    }
+  DAC960_V2_CommandMailbox_T *CommandMailbox = &Command->V2.CommandMailbox;
+  DAC960_V2_CommandMailbox_T *NextCommandMailbox =
+    Controller->V2.NextCommandMailbox;
+  CommandMailbox->Common.CommandIdentifier = Command->CommandIdentifier;
+  DAC960_BA_WriteCommandMailbox(NextCommandMailbox, CommandMailbox);
+  if (Controller->V2.PreviousCommandMailbox1->Words[0] == 0 ||
+      Controller->V2.PreviousCommandMailbox2->Words[0] == 0)
+    DAC960_BA_MemoryMailboxNewCommand(ControllerBaseAddress);
+  Controller->V2.PreviousCommandMailbox2 =
+    Controller->V2.PreviousCommandMailbox1;
+  Controller->V2.PreviousCommandMailbox1 = NextCommandMailbox;
+  if (++NextCommandMailbox > Controller->V2.LastCommandMailbox)
+    NextCommandMailbox = Controller->V2.FirstCommandMailbox;
+  Controller->V2.NextCommandMailbox = NextCommandMailbox;
 }
 
 
 /*
-  DAC960_ExecuteCommand executes Command and waits for completion.  It
-  returns true on success and false on failure.
+  DAC960_LP_QueueCommand queues Command for DAC960 LP Series Controllers.
+*/
+
+static void DAC960_LP_QueueCommand(DAC960_Command_T *Command)
+{
+  DAC960_Controller_T *Controller = Command->Controller;
+  void *ControllerBaseAddress = Controller->BaseAddress;
+  DAC960_V2_CommandMailbox_T *CommandMailbox = &Command->V2.CommandMailbox;
+  DAC960_V2_CommandMailbox_T *NextCommandMailbox =
+    Controller->V2.NextCommandMailbox;
+  CommandMailbox->Common.CommandIdentifier = Command->CommandIdentifier;
+  DAC960_LP_WriteCommandMailbox(NextCommandMailbox, CommandMailbox);
+  if (Controller->V2.PreviousCommandMailbox1->Words[0] == 0 ||
+      Controller->V2.PreviousCommandMailbox2->Words[0] == 0)
+    DAC960_LP_MemoryMailboxNewCommand(ControllerBaseAddress);
+  Controller->V2.PreviousCommandMailbox2 =
+    Controller->V2.PreviousCommandMailbox1;
+  Controller->V2.PreviousCommandMailbox1 = NextCommandMailbox;
+  if (++NextCommandMailbox > Controller->V2.LastCommandMailbox)
+    NextCommandMailbox = Controller->V2.FirstCommandMailbox;
+  Controller->V2.NextCommandMailbox = NextCommandMailbox;
+}
+
+
+/*
+  DAC960_LA_QueueCommandDualMode queues Command for DAC960 LA Series
+  Controllers with Dual Mode Firmware.
+*/
+
+static void DAC960_LA_QueueCommandDualMode(DAC960_Command_T *Command)
+{
+  DAC960_Controller_T *Controller = Command->Controller;
+  void *ControllerBaseAddress = Controller->BaseAddress;
+  DAC960_V1_CommandMailbox_T *CommandMailbox = &Command->V1.CommandMailbox;
+  DAC960_V1_CommandMailbox_T *NextCommandMailbox =
+    Controller->V1.NextCommandMailbox;
+  CommandMailbox->Common.CommandIdentifier = Command->CommandIdentifier;
+  DAC960_LA_WriteCommandMailbox(NextCommandMailbox, CommandMailbox);
+  if (Controller->V1.PreviousCommandMailbox1->Words[0] == 0 ||
+      Controller->V1.PreviousCommandMailbox2->Words[0] == 0)
+    DAC960_LA_MemoryMailboxNewCommand(ControllerBaseAddress);
+  Controller->V1.PreviousCommandMailbox2 =
+    Controller->V1.PreviousCommandMailbox1;
+  Controller->V1.PreviousCommandMailbox1 = NextCommandMailbox;
+  if (++NextCommandMailbox > Controller->V1.LastCommandMailbox)
+    NextCommandMailbox = Controller->V1.FirstCommandMailbox;
+  Controller->V1.NextCommandMailbox = NextCommandMailbox;
+}
+
+
+/*
+  DAC960_LA_QueueCommandSingleMode queues Command for DAC960 LA Series
+  Controllers with Single Mode Firmware.
+*/
+
+static void DAC960_LA_QueueCommandSingleMode(DAC960_Command_T *Command)
+{
+  DAC960_Controller_T *Controller = Command->Controller;
+  void *ControllerBaseAddress = Controller->BaseAddress;
+  DAC960_V1_CommandMailbox_T *CommandMailbox = &Command->V1.CommandMailbox;
+  DAC960_V1_CommandMailbox_T *NextCommandMailbox =
+    Controller->V1.NextCommandMailbox;
+  CommandMailbox->Common.CommandIdentifier = Command->CommandIdentifier;
+  DAC960_LA_WriteCommandMailbox(NextCommandMailbox, CommandMailbox);
+  if (Controller->V1.PreviousCommandMailbox1->Words[0] == 0 ||
+      Controller->V1.PreviousCommandMailbox2->Words[0] == 0)
+    DAC960_LA_HardwareMailboxNewCommand(ControllerBaseAddress);
+  Controller->V1.PreviousCommandMailbox2 =
+    Controller->V1.PreviousCommandMailbox1;
+  Controller->V1.PreviousCommandMailbox1 = NextCommandMailbox;
+  if (++NextCommandMailbox > Controller->V1.LastCommandMailbox)
+    NextCommandMailbox = Controller->V1.FirstCommandMailbox;
+  Controller->V1.NextCommandMailbox = NextCommandMailbox;
+}
+
+
+/*
+  DAC960_PG_QueueCommandDualMode queues Command for DAC960 PG Series
+  Controllers with Dual Mode Firmware.
+*/
+
+static void DAC960_PG_QueueCommandDualMode(DAC960_Command_T *Command)
+{
+  DAC960_Controller_T *Controller = Command->Controller;
+  void *ControllerBaseAddress = Controller->BaseAddress;
+  DAC960_V1_CommandMailbox_T *CommandMailbox = &Command->V1.CommandMailbox;
+  DAC960_V1_CommandMailbox_T *NextCommandMailbox =
+    Controller->V1.NextCommandMailbox;
+  CommandMailbox->Common.CommandIdentifier = Command->CommandIdentifier;
+  DAC960_PG_WriteCommandMailbox(NextCommandMailbox, CommandMailbox);
+  if (Controller->V1.PreviousCommandMailbox1->Words[0] == 0 ||
+      Controller->V1.PreviousCommandMailbox2->Words[0] == 0)
+    DAC960_PG_MemoryMailboxNewCommand(ControllerBaseAddress);
+  Controller->V1.PreviousCommandMailbox2 =
+    Controller->V1.PreviousCommandMailbox1;
+  Controller->V1.PreviousCommandMailbox1 = NextCommandMailbox;
+  if (++NextCommandMailbox > Controller->V1.LastCommandMailbox)
+    NextCommandMailbox = Controller->V1.FirstCommandMailbox;
+  Controller->V1.NextCommandMailbox = NextCommandMailbox;
+}
+
+
+/*
+  DAC960_PG_QueueCommandSingleMode queues Command for DAC960 PG Series
+  Controllers with Single Mode Firmware.
+*/
+
+static void DAC960_PG_QueueCommandSingleMode(DAC960_Command_T *Command)
+{
+  DAC960_Controller_T *Controller = Command->Controller;
+  void *ControllerBaseAddress = Controller->BaseAddress;
+  DAC960_V1_CommandMailbox_T *CommandMailbox = &Command->V1.CommandMailbox;
+  DAC960_V1_CommandMailbox_T *NextCommandMailbox =
+    Controller->V1.NextCommandMailbox;
+  CommandMailbox->Common.CommandIdentifier = Command->CommandIdentifier;
+  DAC960_PG_WriteCommandMailbox(NextCommandMailbox, CommandMailbox);
+  if (Controller->V1.PreviousCommandMailbox1->Words[0] == 0 ||
+      Controller->V1.PreviousCommandMailbox2->Words[0] == 0)
+    DAC960_PG_HardwareMailboxNewCommand(ControllerBaseAddress);
+  Controller->V1.PreviousCommandMailbox2 =
+    Controller->V1.PreviousCommandMailbox1;
+  Controller->V1.PreviousCommandMailbox1 = NextCommandMailbox;
+  if (++NextCommandMailbox > Controller->V1.LastCommandMailbox)
+    NextCommandMailbox = Controller->V1.FirstCommandMailbox;
+  Controller->V1.NextCommandMailbox = NextCommandMailbox;
+}
+
+
+/*
+  DAC960_PD_QueueCommand queues Command for DAC960 PD Series Controllers.
+*/
+
+static void DAC960_PD_QueueCommand(DAC960_Command_T *Command)
+{
+  DAC960_Controller_T *Controller = Command->Controller;
+  void *ControllerBaseAddress = Controller->BaseAddress;
+  DAC960_V1_CommandMailbox_T *CommandMailbox = &Command->V1.CommandMailbox;
+  CommandMailbox->Common.CommandIdentifier = Command->CommandIdentifier;
+  while (DAC960_PD_MailboxFullP(ControllerBaseAddress))
+    udelay(1);
+  DAC960_PD_WriteCommandMailbox(ControllerBaseAddress, CommandMailbox);
+  DAC960_PD_NewCommand(ControllerBaseAddress);
+}
+
+
+/*
+  DAC960_ExecuteCommand executes Command and waits for completion.
 */
 
-static boolean DAC960_ExecuteCommand(DAC960_Command_T *Command)
+static void DAC960_ExecuteCommand(DAC960_Command_T *Command)
 {
   DAC960_Controller_T *Controller = Command->Controller;
   Semaphore_T Semaphore = MUTEX_LOCKED;
@@ -279,227 +505,386 @@
   DAC960_AcquireControllerLock(Controller, &ProcessorFlags);
   DAC960_QueueCommand(Command);
   DAC960_ReleaseControllerLock(Controller, &ProcessorFlags);
-  if (!in_interrupt())
-    down(&Semaphore);
-  return Command->CommandStatus == DAC960_NormalCompletion;
+  if (in_interrupt()) return;
+  down(&Semaphore);
 }
 
 
 /*
-  DAC960_ExecuteType3 executes a DAC960 Type 3 Command and waits for
-  completion.  It returns true on success and false on failure.
+  DAC960_V1_ExecuteType3 executes a DAC960 V1 Firmware Controller Type 3
+  Command and waits for completion.  It returns true on success and false
+  on failure.
 */
 
-static boolean DAC960_ExecuteType3(DAC960_Controller_T *Controller,
-				   DAC960_CommandOpcode_T CommandOpcode,
-				   void *DataPointer)
+static boolean DAC960_V1_ExecuteType3(DAC960_Controller_T *Controller,
+				      DAC960_V1_CommandOpcode_T CommandOpcode,
+				      void *DataPointer)
 {
   DAC960_Command_T *Command = DAC960_AllocateCommand(Controller);
-  DAC960_CommandMailbox_T *CommandMailbox = &Command->CommandMailbox;
-  boolean Result;
-  DAC960_ClearCommand(Command);
+  DAC960_V1_CommandMailbox_T *CommandMailbox = &Command->V1.CommandMailbox;
+  DAC960_V1_CommandStatus_T CommandStatus;
+  DAC960_V1_ClearCommand(Command);
   Command->CommandType = DAC960_ImmediateCommand;
   CommandMailbox->Type3.CommandOpcode = CommandOpcode;
   CommandMailbox->Type3.BusAddress = Virtual_to_Bus(DataPointer);
-  Result = DAC960_ExecuteCommand(Command);
+  DAC960_ExecuteCommand(Command);
+  CommandStatus = Command->V1.CommandStatus;
   DAC960_DeallocateCommand(Command);
-  return Result;
+  return (CommandStatus == DAC960_V1_NormalCompletion);
 }
 
 
 /*
-  DAC960_ExecuteType3D executes a DAC960 Type 3D Command and waits for
-  completion.  It returns true on success and false on failure.
+  DAC960_V1_ExecuteType3D executes a DAC960 V1 Firmware Controller Type 3D
+  Command and waits for completion.  It returns true on success and false
+  on failure.
 */
 
-static boolean DAC960_ExecuteType3D(DAC960_Controller_T *Controller,
-				    DAC960_CommandOpcode_T CommandOpcode,
-				    unsigned char Channel,
-				    unsigned char TargetID,
-				    void *DataPointer)
+static boolean DAC960_V1_ExecuteType3D(DAC960_Controller_T *Controller,
+				       DAC960_V1_CommandOpcode_T CommandOpcode,
+				       unsigned char Channel,
+				       unsigned char TargetID,
+				       void *DataPointer)
 {
   DAC960_Command_T *Command = DAC960_AllocateCommand(Controller);
-  DAC960_CommandMailbox_T *CommandMailbox = &Command->CommandMailbox;
-  boolean Result;
-  DAC960_ClearCommand(Command);
+  DAC960_V1_CommandMailbox_T *CommandMailbox = &Command->V1.CommandMailbox;
+  DAC960_V1_CommandStatus_T CommandStatus;
+  DAC960_V1_ClearCommand(Command);
   Command->CommandType = DAC960_ImmediateCommand;
   CommandMailbox->Type3D.CommandOpcode = CommandOpcode;
   CommandMailbox->Type3D.Channel = Channel;
   CommandMailbox->Type3D.TargetID = TargetID;
   CommandMailbox->Type3D.BusAddress = Virtual_to_Bus(DataPointer);
-  Result = DAC960_ExecuteCommand(Command);
+  DAC960_ExecuteCommand(Command);
+  CommandStatus = Command->V1.CommandStatus;
   DAC960_DeallocateCommand(Command);
-  return Result;
+  return (CommandStatus == DAC960_V1_NormalCompletion);
 }
 
 
 /*
-  DAC960_ReportErrorStatus reports Controller BIOS Messages passed through
-  the Error Status Register when the driver performs the BIOS handshaking.
-  It returns true for fatal errors and false otherwise.
+  DAC960_V2_GeneralInfo executes a DAC960 V2 Firmware General Information
+  Reading IOCTL Command and waits for completion.  It returns true on success
+  and false on failure.
 */
 
-static boolean DAC960_ReportErrorStatus(DAC960_Controller_T *Controller,
-					unsigned char ErrorStatus,
-					unsigned char Parameter0,
-					unsigned char Parameter1)
+static boolean DAC960_V2_GeneralInfo(DAC960_Controller_T *Controller,
+				     DAC960_V2_IOCTL_Opcode_T IOCTL_Opcode,
+				     void *DataPointer,
+				     unsigned int DataByteCount)
 {
-  switch (ErrorStatus)
-    {
-    case 0x00:
-      DAC960_Notice("Physical Drive %d:%d Not Responding\n",
-		    Controller, Parameter1, Parameter0);
-      break;
-    case 0x08:
-      if (Controller->DriveSpinUpMessageDisplayed) break;
-      DAC960_Notice("Spinning Up Drives\n", Controller);
-      Controller->DriveSpinUpMessageDisplayed = true;
-      break;
-    case 0x30:
-      DAC960_Notice("Configuration Checksum Error\n", Controller);
-      break;
-    case 0x60:
-      DAC960_Notice("Mirror Race Recovery Failed\n", Controller);
-      break;
-    case 0x70:
-      DAC960_Notice("Mirror Race Recovery In Progress\n", Controller);
-      break;
-    case 0x90:
-      DAC960_Notice("Physical Drive %d:%d COD Mismatch\n",
-		    Controller, Parameter1, Parameter0);
-      break;
-    case 0xA0:
-      DAC960_Notice("Logical Drive Installation Aborted\n", Controller);
-      break;
-    case 0xB0:
-      DAC960_Notice("Mirror Race On A Critical Logical Drive\n", Controller);
-      break;
-    case 0xD0:
-      DAC960_Notice("New Controller Configuration Found\n", Controller);
-      break;
-    case 0xF0:
-      DAC960_Error("Fatal Memory Parity Error for Controller at\n", Controller);
-      return true;
-    default:
-      DAC960_Error("Unknown Initialization Error %02X for Controller at\n",
-		   Controller, ErrorStatus);
-      return true;
-    }
-  return false;
+  DAC960_Command_T *Command = DAC960_AllocateCommand(Controller);
+  DAC960_V2_CommandMailbox_T *CommandMailbox = &Command->V2.CommandMailbox;
+  DAC960_V2_CommandStatus_T CommandStatus;
+  DAC960_V2_ClearCommand(Command);
+  Command->CommandType = DAC960_ImmediateCommand;
+  CommandMailbox->Common.CommandOpcode = DAC960_V2_IOCTL;
+  CommandMailbox->Common.CommandControlBits
+			.DataTransferControllerToHost = true;
+  CommandMailbox->Common.CommandControlBits
+			.NoAutoRequestSense = true;
+  CommandMailbox->Common.DataTransferSize = DataByteCount;
+  CommandMailbox->Common.IOCTL_Opcode = IOCTL_Opcode;
+  CommandMailbox->Common.DataTransferMemoryAddress
+			.ScatterGatherSegments[0]
+			.SegmentDataPointer =
+    Virtual_to_Bus(DataPointer);
+  CommandMailbox->Common.DataTransferMemoryAddress
+			.ScatterGatherSegments[0]
+			.SegmentByteCount =
+    CommandMailbox->Common.DataTransferSize;
+  DAC960_ExecuteCommand(Command);
+  CommandStatus = Command->V2.CommandStatus;
+  DAC960_DeallocateCommand(Command);
+  return (CommandStatus == DAC960_V2_NormalCompletion);
 }
 
 
 /*
-  DAC960_EnableMemoryMailboxInterface enables the Memory Mailbox Interface.
+  DAC960_V2_ControllerInfo executes a DAC960 V2 Firmware Controller
+  Information Reading IOCTL Command and waits for completion.  It returns
+  true on success and false on failure.
 */
 
-static boolean DAC960_EnableMemoryMailboxInterface(DAC960_Controller_T
-						   *Controller)
+static boolean DAC960_V2_ControllerInfo(DAC960_Controller_T *Controller,
+					DAC960_V2_IOCTL_Opcode_T IOCTL_Opcode,
+					void *DataPointer,
+					unsigned int DataByteCount)
+{
+  DAC960_Command_T *Command = DAC960_AllocateCommand(Controller);
+  DAC960_V2_CommandMailbox_T *CommandMailbox = &Command->V2.CommandMailbox;
+  DAC960_V2_CommandStatus_T CommandStatus;
+  DAC960_V2_ClearCommand(Command);
+  Command->CommandType = DAC960_ImmediateCommand;
+  CommandMailbox->ControllerInfo.CommandOpcode = DAC960_V2_IOCTL;
+  CommandMailbox->ControllerInfo.CommandControlBits
+				.DataTransferControllerToHost = true;
+  CommandMailbox->ControllerInfo.CommandControlBits
+				.NoAutoRequestSense = true;
+  CommandMailbox->ControllerInfo.DataTransferSize = DataByteCount;
+  CommandMailbox->ControllerInfo.ControllerNumber = 0;
+  CommandMailbox->ControllerInfo.IOCTL_Opcode = IOCTL_Opcode;
+  CommandMailbox->ControllerInfo.DataTransferMemoryAddress
+				.ScatterGatherSegments[0]
+				.SegmentDataPointer =
+    Virtual_to_Bus(DataPointer);
+  CommandMailbox->ControllerInfo.DataTransferMemoryAddress
+				.ScatterGatherSegments[0]
+				.SegmentByteCount =
+    CommandMailbox->ControllerInfo.DataTransferSize;
+  DAC960_ExecuteCommand(Command);
+  CommandStatus = Command->V2.CommandStatus;
+  DAC960_DeallocateCommand(Command);
+  return (CommandStatus == DAC960_V2_NormalCompletion);
+}
+
+
+/*
+  DAC960_V2_LogicalDeviceInfo executes a DAC960 V2 Firmware Controller Logical
+  Device Information Reading IOCTL Command and waits for completion.  It
+  returns true on success and false on failure.
+*/
+
+static boolean DAC960_V2_LogicalDeviceInfo(DAC960_Controller_T *Controller,
+					   DAC960_V2_IOCTL_Opcode_T
+					     IOCTL_Opcode,
+					   unsigned short
+					     LogicalDeviceNumber,
+					   void *DataPointer,
+					   unsigned int DataByteCount)
+{
+  DAC960_Command_T *Command = DAC960_AllocateCommand(Controller);
+  DAC960_V2_CommandMailbox_T *CommandMailbox = &Command->V2.CommandMailbox;
+  DAC960_V2_CommandStatus_T CommandStatus;
+  DAC960_V2_ClearCommand(Command);
+  Command->CommandType = DAC960_ImmediateCommand;
+  CommandMailbox->LogicalDeviceInfo.CommandOpcode = DAC960_V2_IOCTL;
+  CommandMailbox->LogicalDeviceInfo.CommandControlBits
+				   .DataTransferControllerToHost = true;
+  CommandMailbox->LogicalDeviceInfo.CommandControlBits
+				   .NoAutoRequestSense = true;
+  CommandMailbox->LogicalDeviceInfo.DataTransferSize = DataByteCount;
+  CommandMailbox->LogicalDeviceInfo.LogicalDevice.LogicalDeviceNumber =
+    LogicalDeviceNumber;
+  CommandMailbox->LogicalDeviceInfo.IOCTL_Opcode = IOCTL_Opcode;
+  CommandMailbox->LogicalDeviceInfo.DataTransferMemoryAddress
+				   .ScatterGatherSegments[0]
+				   .SegmentDataPointer =
+    Virtual_to_Bus(DataPointer);
+  CommandMailbox->LogicalDeviceInfo.DataTransferMemoryAddress
+				   .ScatterGatherSegments[0]
+				   .SegmentByteCount =
+    CommandMailbox->LogicalDeviceInfo.DataTransferSize;
+  DAC960_ExecuteCommand(Command);
+  CommandStatus = Command->V2.CommandStatus;
+  DAC960_DeallocateCommand(Command);
+  return (CommandStatus == DAC960_V2_NormalCompletion);
+}
+
+
+/*
+  DAC960_V2_PhysicalDeviceInfo executes a DAC960 V2 Firmware Controller Physical
+  Device Information Reading IOCTL Command and waits for completion.  It
+  returns true on success and false on failure.
+*/
+
+static boolean DAC960_V2_PhysicalDeviceInfo(DAC960_Controller_T *Controller,
+					    DAC960_V2_IOCTL_Opcode_T
+					      IOCTL_Opcode,
+					    unsigned char Channel,
+					    unsigned char TargetID,
+					    unsigned char LogicalUnit,
+					    void *DataPointer,
+					    unsigned int DataByteCount)
+{
+  DAC960_Command_T *Command = DAC960_AllocateCommand(Controller);
+  DAC960_V2_CommandMailbox_T *CommandMailbox = &Command->V2.CommandMailbox;
+  DAC960_V2_CommandStatus_T CommandStatus;
+  DAC960_V2_ClearCommand(Command);
+  Command->CommandType = DAC960_ImmediateCommand;
+  CommandMailbox->PhysicalDeviceInfo.CommandOpcode = DAC960_V2_IOCTL;
+  CommandMailbox->PhysicalDeviceInfo.CommandControlBits
+				    .DataTransferControllerToHost = true;
+  CommandMailbox->PhysicalDeviceInfo.CommandControlBits
+				    .NoAutoRequestSense = true;
+  CommandMailbox->PhysicalDeviceInfo.DataTransferSize = DataByteCount;
+  CommandMailbox->PhysicalDeviceInfo.PhysicalDevice.LogicalUnit = LogicalUnit;
+  CommandMailbox->PhysicalDeviceInfo.PhysicalDevice.TargetID = TargetID;
+  CommandMailbox->PhysicalDeviceInfo.PhysicalDevice.Channel = Channel;
+  CommandMailbox->PhysicalDeviceInfo.IOCTL_Opcode = IOCTL_Opcode;
+  CommandMailbox->PhysicalDeviceInfo.DataTransferMemoryAddress
+				    .ScatterGatherSegments[0]
+				    .SegmentDataPointer =
+    Virtual_to_Bus(DataPointer);
+  CommandMailbox->PhysicalDeviceInfo.DataTransferMemoryAddress
+				    .ScatterGatherSegments[0]
+				    .SegmentByteCount =
+    CommandMailbox->PhysicalDeviceInfo.DataTransferSize;
+  DAC960_ExecuteCommand(Command);
+  CommandStatus = Command->V2.CommandStatus;
+  DAC960_DeallocateCommand(Command);
+  return (CommandStatus == DAC960_V2_NormalCompletion);
+}
+
+
+/*
+  DAC960_V2_DeviceOperation executes a DAC960 V2 Firmware Controller Device
+  Operation IOCTL Command and waits for completion.  It returns true on
+  success and false on failure.
+*/
+
+static boolean DAC960_V2_DeviceOperation(DAC960_Controller_T *Controller,
+					 DAC960_V2_IOCTL_Opcode_T IOCTL_Opcode,
+					 DAC960_V2_OperationDevice_T
+					   OperationDevice)
+{
+  DAC960_Command_T *Command = DAC960_AllocateCommand(Controller);
+  DAC960_V2_CommandMailbox_T *CommandMailbox = &Command->V2.CommandMailbox;
+  DAC960_V2_CommandStatus_T CommandStatus;
+  DAC960_V2_ClearCommand(Command);
+  Command->CommandType = DAC960_ImmediateCommand;
+  CommandMailbox->DeviceOperation.CommandOpcode = DAC960_V2_IOCTL;
+  CommandMailbox->DeviceOperation.CommandControlBits
+				 .DataTransferControllerToHost = true;
+  CommandMailbox->DeviceOperation.CommandControlBits
+    				 .NoAutoRequestSense = true;
+  CommandMailbox->DeviceOperation.IOCTL_Opcode = IOCTL_Opcode;
+  CommandMailbox->DeviceOperation.OperationDevice = OperationDevice;
+  DAC960_ExecuteCommand(Command);
+  CommandStatus = Command->V2.CommandStatus;
+  DAC960_DeallocateCommand(Command);
+  return (CommandStatus == DAC960_V2_NormalCompletion);
+}
+
+
+/*
+  DAC960_V1_EnableMemoryMailboxInterface enables the Memory Mailbox Interface
+  for DAC960 V1 Firmware Controllers.
+*/
+
+static boolean DAC960_V1_EnableMemoryMailboxInterface(DAC960_Controller_T
+						      *Controller)
 {
   void *ControllerBaseAddress = Controller->BaseAddress;
-  DAC960_CommandMailbox_T *CommandMailboxesMemory;
-  DAC960_StatusMailbox_T *StatusMailboxesMemory;
-  DAC960_CommandMailbox_T CommandMailbox;
-  DAC960_CommandStatus_T CommandStatus;
+  DAC960_V1_CommandMailbox_T *CommandMailboxesMemory;
+  DAC960_V1_StatusMailbox_T *StatusMailboxesMemory;
+  DAC960_V1_CommandMailbox_T CommandMailbox;
+  DAC960_V1_CommandStatus_T CommandStatus;
+  unsigned long MemoryMailboxPagesAddress;
+  unsigned long MemoryMailboxPagesOrder;
+  unsigned long MemoryMailboxPagesSize;
   void *SavedMemoryMailboxesAddress = NULL;
   short NextCommandMailboxIndex = 0;
   short NextStatusMailboxIndex = 0;
   int TimeoutCounter = 1000000, i;
-  if (Controller->ControllerType == DAC960_V5_Controller)
-    DAC960_V5_RestoreMemoryMailboxInfo(Controller,
+  MemoryMailboxPagesOrder = 0;
+  MemoryMailboxPagesSize =
+    DAC960_V1_CommandMailboxCount * sizeof(DAC960_V1_CommandMailbox_T) +
+    DAC960_V1_StatusMailboxCount * sizeof(DAC960_V1_StatusMailbox_T);
+  while (MemoryMailboxPagesSize > PAGE_SIZE << MemoryMailboxPagesOrder)
+    MemoryMailboxPagesOrder++;
+  if (Controller->HardwareType == DAC960_LA_Controller)
+    DAC960_LA_RestoreMemoryMailboxInfo(Controller,
 				       &SavedMemoryMailboxesAddress,
 				       &NextCommandMailboxIndex,
 				       &NextStatusMailboxIndex);
-  else DAC960_V4_RestoreMemoryMailboxInfo(Controller,
+  else DAC960_PG_RestoreMemoryMailboxInfo(Controller,
 					  &SavedMemoryMailboxesAddress,
 					  &NextCommandMailboxIndex,
 					  &NextStatusMailboxIndex);
   if (SavedMemoryMailboxesAddress == NULL)
-    CommandMailboxesMemory =
-      (DAC960_CommandMailbox_T *) __get_free_pages(GFP_KERNEL, 1);
+    {
+      MemoryMailboxPagesAddress =
+	__get_free_pages(GFP_KERNEL, MemoryMailboxPagesOrder);
+      Controller->MemoryMailboxPagesAddress = MemoryMailboxPagesAddress;
+      CommandMailboxesMemory =
+	(DAC960_V1_CommandMailbox_T *) MemoryMailboxPagesAddress;
+    }
   else CommandMailboxesMemory = SavedMemoryMailboxesAddress;
-  memset(CommandMailboxesMemory, 0, PAGE_SIZE << 1);
-  Controller->FirstCommandMailbox = CommandMailboxesMemory;
-  CommandMailboxesMemory += DAC960_CommandMailboxCount - 1;
-  Controller->LastCommandMailbox = CommandMailboxesMemory;
-  Controller->NextCommandMailbox =
-    &Controller->FirstCommandMailbox[NextCommandMailboxIndex];
+  if (CommandMailboxesMemory == NULL) return false;
+  Controller->MemoryMailboxPagesOrder = MemoryMailboxPagesOrder;
+  memset(CommandMailboxesMemory, 0, MemoryMailboxPagesSize);
+  Controller->V1.FirstCommandMailbox = CommandMailboxesMemory;
+  CommandMailboxesMemory += DAC960_V1_CommandMailboxCount - 1;
+  Controller->V1.LastCommandMailbox = CommandMailboxesMemory;
+  Controller->V1.NextCommandMailbox =
+    &Controller->V1.FirstCommandMailbox[NextCommandMailboxIndex];
   if (--NextCommandMailboxIndex < 0)
-    NextCommandMailboxIndex = DAC960_CommandMailboxCount - 1;
-  Controller->PreviousCommandMailbox1 =
-    &Controller->FirstCommandMailbox[NextCommandMailboxIndex];
+    NextCommandMailboxIndex = DAC960_V1_CommandMailboxCount - 1;
+  Controller->V1.PreviousCommandMailbox1 =
+    &Controller->V1.FirstCommandMailbox[NextCommandMailboxIndex];
   if (--NextCommandMailboxIndex < 0)
-    NextCommandMailboxIndex = DAC960_CommandMailboxCount - 1;
-  Controller->PreviousCommandMailbox2 =
-    &Controller->FirstCommandMailbox[NextCommandMailboxIndex];
+    NextCommandMailboxIndex = DAC960_V1_CommandMailboxCount - 1;
+  Controller->V1.PreviousCommandMailbox2 =
+    &Controller->V1.FirstCommandMailbox[NextCommandMailboxIndex];
   StatusMailboxesMemory =
-    (DAC960_StatusMailbox_T *) (CommandMailboxesMemory + 1);
-  Controller->FirstStatusMailbox = StatusMailboxesMemory;
-  StatusMailboxesMemory += DAC960_StatusMailboxCount - 1;
-  Controller->LastStatusMailbox = StatusMailboxesMemory;
-  Controller->NextStatusMailbox =
-    &Controller->FirstStatusMailbox[NextStatusMailboxIndex];
+    (DAC960_V1_StatusMailbox_T *) (CommandMailboxesMemory + 1);
+  Controller->V1.FirstStatusMailbox = StatusMailboxesMemory;
+  StatusMailboxesMemory += DAC960_V1_StatusMailboxCount - 1;
+  Controller->V1.LastStatusMailbox = StatusMailboxesMemory;
+  Controller->V1.NextStatusMailbox =
+    &Controller->V1.FirstStatusMailbox[NextStatusMailboxIndex];
   if (SavedMemoryMailboxesAddress != NULL) return true;
   /* Enable the Memory Mailbox Interface. */
-  Controller->DualModeMemoryMailboxInterface = true;
+  Controller->V1.DualModeMemoryMailboxInterface = true;
   CommandMailbox.TypeX.CommandOpcode = 0x2B;
   CommandMailbox.TypeX.CommandIdentifier = 0;
   CommandMailbox.TypeX.CommandOpcode2 = 0x14;
   CommandMailbox.TypeX.CommandMailboxesBusAddress =
-    Virtual_to_Bus(Controller->FirstCommandMailbox);
+    Virtual_to_Bus(Controller->V1.FirstCommandMailbox);
   CommandMailbox.TypeX.StatusMailboxesBusAddress =
-    Virtual_to_Bus(Controller->FirstStatusMailbox);
+    Virtual_to_Bus(Controller->V1.FirstStatusMailbox);
   for (i = 0; i < 2; i++)
-    switch (Controller->ControllerType)
+    switch (Controller->HardwareType)
       {
-      case DAC960_V5_Controller:
+      case DAC960_LA_Controller:
 	while (--TimeoutCounter >= 0)
 	  {
-	    if (!DAC960_V5_HardwareMailboxFullP(ControllerBaseAddress))
+	    if (!DAC960_LA_HardwareMailboxFullP(ControllerBaseAddress))
 	      break;
 	    udelay(10);
 	  }
 	if (TimeoutCounter < 0) return false;
-	DAC960_V5_WriteHardwareMailbox(ControllerBaseAddress, &CommandMailbox);
-	DAC960_V5_HardwareMailboxNewCommand(ControllerBaseAddress);
+	DAC960_LA_WriteHardwareMailbox(ControllerBaseAddress, &CommandMailbox);
+	DAC960_LA_HardwareMailboxNewCommand(ControllerBaseAddress);
 	while (--TimeoutCounter >= 0)
 	  {
-	    if (DAC960_V5_HardwareMailboxStatusAvailableP(
+	    if (DAC960_LA_HardwareMailboxStatusAvailableP(
 		  ControllerBaseAddress))
 	      break;
 	    udelay(10);
 	  }
 	if (TimeoutCounter < 0) return false;
-	CommandStatus = DAC960_V5_ReadStatusRegister(ControllerBaseAddress);
-	DAC960_V5_AcknowledgeHardwareMailboxInterrupt(ControllerBaseAddress);
-	DAC960_V5_AcknowledgeHardwareMailboxStatus(ControllerBaseAddress);
-	if (CommandStatus == DAC960_NormalCompletion) return true;
-	Controller->DualModeMemoryMailboxInterface = false;
+	CommandStatus = DAC960_LA_ReadStatusRegister(ControllerBaseAddress);
+	DAC960_LA_AcknowledgeHardwareMailboxInterrupt(ControllerBaseAddress);
+	DAC960_LA_AcknowledgeHardwareMailboxStatus(ControllerBaseAddress);
+	if (CommandStatus == DAC960_V1_NormalCompletion) return true;
+	Controller->V1.DualModeMemoryMailboxInterface = false;
 	CommandMailbox.TypeX.CommandOpcode2 = 0x10;
 	break;
-      case DAC960_V4_Controller:
+      case DAC960_PG_Controller:
 	while (--TimeoutCounter >= 0)
 	  {
-	    if (!DAC960_V4_HardwareMailboxFullP(ControllerBaseAddress))
+	    if (!DAC960_PG_HardwareMailboxFullP(ControllerBaseAddress))
 	      break;
 	    udelay(10);
 	  }
 	if (TimeoutCounter < 0) return false;
-	DAC960_V4_WriteHardwareMailbox(ControllerBaseAddress, &CommandMailbox);
-	DAC960_V4_HardwareMailboxNewCommand(ControllerBaseAddress);
+	DAC960_PG_WriteHardwareMailbox(ControllerBaseAddress, &CommandMailbox);
+	DAC960_PG_HardwareMailboxNewCommand(ControllerBaseAddress);
 	while (--TimeoutCounter >= 0)
 	  {
-	    if (DAC960_V4_HardwareMailboxStatusAvailableP(
+	    if (DAC960_PG_HardwareMailboxStatusAvailableP(
 		  ControllerBaseAddress))
 	      break;
 	    udelay(10);
 	  }
 	if (TimeoutCounter < 0) return false;
-	CommandStatus = DAC960_V4_ReadStatusRegister(ControllerBaseAddress);
-	DAC960_V4_AcknowledgeHardwareMailboxInterrupt(ControllerBaseAddress);
-	DAC960_V4_AcknowledgeHardwareMailboxStatus(ControllerBaseAddress);
-	if (CommandStatus == DAC960_NormalCompletion) return true;
-	Controller->DualModeMemoryMailboxInterface = false;
+	CommandStatus = DAC960_PG_ReadStatusRegister(ControllerBaseAddress);
+	DAC960_PG_AcknowledgeHardwareMailboxInterrupt(ControllerBaseAddress);
+	DAC960_PG_AcknowledgeHardwareMailboxStatus(ControllerBaseAddress);
+	if (CommandStatus == DAC960_V1_NormalCompletion) return true;
+	Controller->V1.DualModeMemoryMailboxInterface = false;
 	CommandMailbox.TypeX.CommandOpcode2 = 0x10;
 	break;
       default:
@@ -510,283 +895,165 @@
 
 
 /*
-  DAC960_DetectControllers detects DAC960 PCI RAID Controllers by interrogating
-  the PCI Configuration Space for Controller Type.
+  DAC960_V2_EnableMemoryMailboxInterface enables the Memory Mailbox Interface
+  for DAC960 V2 Firmware Controllers.
 */
 
-static void DAC960_DetectControllers(DAC960_ControllerType_T ControllerType)
+static boolean DAC960_V2_EnableMemoryMailboxInterface(DAC960_Controller_T
+						      *Controller)
 {
-  unsigned short VendorID = 0, DeviceID = 0;
-  unsigned int MemoryWindowSize = 0;
-  PCI_Device_T *PCI_Device = NULL;
-  switch (ControllerType)
+  void *ControllerBaseAddress = Controller->BaseAddress;
+  DAC960_V2_CommandMailbox_T *CommandMailboxesMemory;
+  DAC960_V2_StatusMailbox_T *StatusMailboxesMemory;
+  DAC960_V2_CommandMailbox_T CommandMailbox;
+  DAC960_V2_CommandStatus_T CommandStatus = 0;
+  unsigned long MemoryMailboxPagesAddress;
+  unsigned long MemoryMailboxPagesOrder;
+  unsigned long MemoryMailboxPagesSize;
+  MemoryMailboxPagesOrder = 0;
+  MemoryMailboxPagesSize =
+    DAC960_V2_CommandMailboxCount * sizeof(DAC960_V2_CommandMailbox_T) +
+    DAC960_V2_StatusMailboxCount * sizeof(DAC960_V2_StatusMailbox_T) +
+    sizeof(DAC960_V2_HealthStatusBuffer_T);
+  while (MemoryMailboxPagesSize > PAGE_SIZE << MemoryMailboxPagesOrder)
+    MemoryMailboxPagesOrder++;
+  MemoryMailboxPagesAddress =
+    __get_free_pages(GFP_KERNEL, MemoryMailboxPagesOrder);
+  Controller->MemoryMailboxPagesAddress = MemoryMailboxPagesAddress;
+  CommandMailboxesMemory =
+    (DAC960_V2_CommandMailbox_T *) MemoryMailboxPagesAddress;
+  if (CommandMailboxesMemory == NULL) return false;
+  Controller->MemoryMailboxPagesOrder = MemoryMailboxPagesOrder;
+  memset(CommandMailboxesMemory, 0, MemoryMailboxPagesSize);
+  Controller->V2.FirstCommandMailbox = CommandMailboxesMemory;
+  CommandMailboxesMemory += DAC960_V2_CommandMailboxCount - 1;
+  Controller->V2.LastCommandMailbox = CommandMailboxesMemory;
+  Controller->V2.NextCommandMailbox = Controller->V2.FirstCommandMailbox;
+  Controller->V2.PreviousCommandMailbox1 = Controller->V2.LastCommandMailbox;
+  Controller->V2.PreviousCommandMailbox2 =
+    Controller->V2.LastCommandMailbox - 1;
+  StatusMailboxesMemory =
+    (DAC960_V2_StatusMailbox_T *) (CommandMailboxesMemory + 1);
+  Controller->V2.FirstStatusMailbox = StatusMailboxesMemory;
+  StatusMailboxesMemory += DAC960_V2_StatusMailboxCount - 1;
+  Controller->V2.LastStatusMailbox = StatusMailboxesMemory;
+  Controller->V2.NextStatusMailbox = Controller->V2.FirstStatusMailbox;
+  Controller->V2.HealthStatusBuffer =
+    (DAC960_V2_HealthStatusBuffer_T *) (StatusMailboxesMemory + 1);
+  /* Enable the Memory Mailbox Interface. */
+  memset(&CommandMailbox, 0, sizeof(DAC960_V2_CommandMailbox_T));
+  CommandMailbox.SetMemoryMailbox.CommandIdentifier = 1;
+  CommandMailbox.SetMemoryMailbox.CommandOpcode = DAC960_V2_IOCTL;
+  CommandMailbox.SetMemoryMailbox.CommandControlBits.NoAutoRequestSense = true;
+  CommandMailbox.SetMemoryMailbox.FirstCommandMailboxSizeKB =
+    (DAC960_V2_CommandMailboxCount * sizeof(DAC960_V2_CommandMailbox_T)) >> 10;
+  CommandMailbox.SetMemoryMailbox.FirstStatusMailboxSizeKB =
+    (DAC960_V2_StatusMailboxCount * sizeof(DAC960_V2_StatusMailbox_T)) >> 10;
+  CommandMailbox.SetMemoryMailbox.SecondCommandMailboxSizeKB = 0;
+  CommandMailbox.SetMemoryMailbox.SecondStatusMailboxSizeKB = 0;
+  CommandMailbox.SetMemoryMailbox.RequestSenseSize = 0;
+  CommandMailbox.SetMemoryMailbox.IOCTL_Opcode = DAC960_V2_SetMemoryMailbox;
+  CommandMailbox.SetMemoryMailbox.HealthStatusBufferSizeKB = 1;
+  CommandMailbox.SetMemoryMailbox.HealthStatusBufferBusAddress =
+    Virtual_to_Bus(Controller->V2.HealthStatusBuffer);
+  CommandMailbox.SetMemoryMailbox.FirstCommandMailboxBusAddress =
+    Virtual_to_Bus(Controller->V2.FirstCommandMailbox);
+  CommandMailbox.SetMemoryMailbox.FirstStatusMailboxBusAddress =
+    Virtual_to_Bus(Controller->V2.FirstStatusMailbox);
+  switch (Controller->HardwareType)
     {
-    case DAC960_V5_Controller:
-      VendorID = PCI_VENDOR_ID_DEC;
-      DeviceID = PCI_DEVICE_ID_DEC_21285;
-      MemoryWindowSize = DAC960_V5_RegisterWindowSize;
+    case DAC960_BA_Controller:
+      while (DAC960_BA_HardwareMailboxFullP(ControllerBaseAddress))
+	udelay(1);
+      DAC960_BA_WriteHardwareMailbox(ControllerBaseAddress, &CommandMailbox);
+      DAC960_BA_HardwareMailboxNewCommand(ControllerBaseAddress);
+      while (!DAC960_BA_HardwareMailboxStatusAvailableP(ControllerBaseAddress))
+	udelay(1);
+      CommandStatus = DAC960_BA_ReadCommandStatus(ControllerBaseAddress);
+      DAC960_BA_AcknowledgeHardwareMailboxInterrupt(ControllerBaseAddress);
+      DAC960_BA_AcknowledgeHardwareMailboxStatus(ControllerBaseAddress);
       break;
-    case DAC960_V4_Controller:
-      VendorID = PCI_VENDOR_ID_MYLEX;
-      DeviceID = PCI_DEVICE_ID_MYLEX_DAC960P_V4;
-      MemoryWindowSize = DAC960_V4_RegisterWindowSize;
+    case DAC960_LP_Controller:
+      while (DAC960_LP_HardwareMailboxFullP(ControllerBaseAddress))
+	udelay(1);
+      DAC960_LP_WriteHardwareMailbox(ControllerBaseAddress, &CommandMailbox);
+      DAC960_LP_HardwareMailboxNewCommand(ControllerBaseAddress);
+      while (!DAC960_LP_HardwareMailboxStatusAvailableP(ControllerBaseAddress))
+	udelay(1);
+      CommandStatus = DAC960_LP_ReadCommandStatus(ControllerBaseAddress);
+      DAC960_LP_AcknowledgeHardwareMailboxInterrupt(ControllerBaseAddress);
+      DAC960_LP_AcknowledgeHardwareMailboxStatus(ControllerBaseAddress);
       break;
-    case DAC960_V3_Controller:
-      VendorID = PCI_VENDOR_ID_MYLEX;
-      DeviceID = PCI_DEVICE_ID_MYLEX_DAC960P_V3;
-      MemoryWindowSize = DAC960_V3_RegisterWindowSize;
+    default:
       break;
     }
-  while ((PCI_Device = pci_find_device(VendorID, DeviceID, PCI_Device)) != NULL)
+  return (CommandStatus == DAC960_V2_NormalCompletion);
+}
+
+
+/*
+  DAC960_V1_ReadControllerConfiguration reads the Configuration Information
+  from DAC960 V1 Firmware Controllers and initializes the Controller structure.
+*/
+
+static boolean DAC960_V1_ReadControllerConfiguration(DAC960_Controller_T
+						     *Controller)
+{
+  DAC960_V1_Enquiry2_T Enquiry2;
+  DAC960_V1_Config2_T Config2;
+  int LogicalDriveNumber, Channel, TargetID;
+  if (!DAC960_V1_ExecuteType3(Controller, DAC960_V1_Enquiry,
+			      &Controller->V1.Enquiry))
+    return DAC960_Failure(Controller, "ENQUIRY");
+  if (!DAC960_V1_ExecuteType3(Controller, DAC960_V1_Enquiry2, &Enquiry2))
+    return DAC960_Failure(Controller, "ENQUIRY2");
+  if (!DAC960_V1_ExecuteType3(Controller, DAC960_V1_ReadConfig2, &Config2))
+    return DAC960_Failure(Controller, "READ CONFIG2");
+  if (!DAC960_V1_ExecuteType3(Controller, DAC960_V1_GetLogicalDriveInformation,
+			      &Controller->V1.LogicalDriveInformation))
+    return DAC960_Failure(Controller, "GET LOGICAL DRIVE INFORMATION");
+  for (Channel = 0; Channel < Enquiry2.ActualChannels; Channel++)
+    for (TargetID = 0; TargetID < Enquiry2.MaxTargets; TargetID++)
+      if (!DAC960_V1_ExecuteType3D(Controller, DAC960_V1_GetDeviceState,
+				   Channel, TargetID,
+				   &Controller->V1.DeviceState
+						   [Channel][TargetID]))
+	return DAC960_Failure(Controller, "GET DEVICE STATE");
+  /*
+    Initialize the Controller Model Name and Full Model Name fields.
+  */
+  switch (Enquiry2.HardwareID.SubModel)
     {
-      DAC960_Controller_T *Controller = (DAC960_Controller_T *)
-	kmalloc(sizeof(DAC960_Controller_T), GFP_ATOMIC);
-      DAC960_IO_Address_T IO_Address = 0;
-      DAC960_PCI_Address_T PCI_Address = 0;
-      unsigned char Bus = PCI_Device->bus->number;
-      unsigned char DeviceFunction = PCI_Device->devfn;
-      unsigned char Device = DeviceFunction >> 3;
-      unsigned char Function = DeviceFunction & 0x7;
-      unsigned char ErrorStatus, Parameter0, Parameter1;
-      unsigned int IRQ_Channel = PCI_Device->irq;
-      unsigned long BaseAddress0 = PCI_Device->base_address[0];
-      unsigned long BaseAddress1 = PCI_Device->base_address[1];
-      unsigned short SubsystemVendorID, SubsystemDeviceID;
-      int CommandIdentifier;
-      void *BaseAddress;
-      pci_read_config_word(PCI_Device, PCI_SUBSYSTEM_VENDOR_ID,
-			   &SubsystemVendorID);
-      pci_read_config_word(PCI_Device, PCI_SUBSYSTEM_ID,
-			   &SubsystemDeviceID);
-      switch (ControllerType)
-	{
-	case DAC960_V5_Controller:
-	  if (!(SubsystemVendorID == PCI_VENDOR_ID_MYLEX &&
-		SubsystemDeviceID == PCI_DEVICE_ID_MYLEX_DAC960P_V5))
-	    goto Ignore;
-	  PCI_Address = BaseAddress0 & PCI_BASE_ADDRESS_MEM_MASK;
-	  break;
-	case DAC960_V4_Controller:
-	  PCI_Address = BaseAddress0 & PCI_BASE_ADDRESS_MEM_MASK;
-	  break;
-	case DAC960_V3_Controller:
-	  IO_Address = BaseAddress0 & PCI_BASE_ADDRESS_IO_MASK;
-	  PCI_Address = BaseAddress1 & PCI_BASE_ADDRESS_MEM_MASK;
-	  break;
-	}
-      if (DAC960_ControllerCount == DAC960_MaxControllers)
-	{
-	  DAC960_Error("More than %d DAC960 Controllers detected - "
-		       "ignoring from Controller at\n",
-		       NULL, DAC960_MaxControllers);
-	  goto Ignore;
-	}
-      if (Controller == NULL)
-	{
-	  DAC960_Error("Unable to allocate Controller structure for "
-		       "Controller at\n", NULL);
-	  goto Ignore;
-	}
-      memset(Controller, 0, sizeof(DAC960_Controller_T));
-      Controller->ControllerNumber = DAC960_ControllerCount;
-      DAC960_Controllers[DAC960_ControllerCount++] = Controller;
-      DAC960_AnnounceDriver(Controller);
-      Controller->ControllerType = ControllerType;
-      Controller->IO_Address = IO_Address;
-      Controller->PCI_Address = PCI_Address;
-      Controller->Bus = Bus;
-      Controller->Device = Device;
-      Controller->Function = Function;
-      sprintf(Controller->ControllerName, "c%d", Controller->ControllerNumber);
-      /*
-	Map the Controller Register Window.
-      */
-      if (MemoryWindowSize < PAGE_SIZE)
-	MemoryWindowSize = PAGE_SIZE;
-      Controller->MemoryMappedAddress =
-	ioremap_nocache(PCI_Address & PAGE_MASK, MemoryWindowSize);
-      Controller->BaseAddress =
-	Controller->MemoryMappedAddress + (PCI_Address & ~PAGE_MASK);
-      if (Controller->MemoryMappedAddress == NULL)
-	{
-	  DAC960_Error("Unable to map Controller Register Window for "
-		       "Controller at\n", Controller);
-	  goto Failure;
-	}
-      BaseAddress = Controller->BaseAddress;
-      switch (ControllerType)
-	{
-	case DAC960_V5_Controller:
-	  DAC960_V5_DisableInterrupts(BaseAddress);
-	  DAC960_V5_AcknowledgeHardwareMailboxStatus(BaseAddress);
-	  udelay(1000);
-	  while (DAC960_V5_InitializationInProgressP(BaseAddress))
-	    {
-	      if (DAC960_V5_ReadErrorStatus(BaseAddress, &ErrorStatus,
-					    &Parameter0, &Parameter1) &&
-		  DAC960_ReportErrorStatus(Controller, ErrorStatus,
-					   Parameter0, Parameter1))
-		goto Failure;
-	      udelay(10);
-	    }
-	  if (!DAC960_EnableMemoryMailboxInterface(Controller))
-	    {
-	      DAC960_Error("Unable to Enable Memory Mailbox Interface "
-			   "for Controller at\n", Controller);
-	      goto Failure;
-	    }
-	  DAC960_V5_EnableInterrupts(BaseAddress);
-	  break;
-	case DAC960_V4_Controller:
-	  DAC960_V4_DisableInterrupts(BaseAddress);
-	  DAC960_V4_AcknowledgeHardwareMailboxStatus(BaseAddress);
-	  udelay(1000);
-	  while (DAC960_V4_InitializationInProgressP(BaseAddress))
-	    {
-	      if (DAC960_V4_ReadErrorStatus(BaseAddress, &ErrorStatus,
-					    &Parameter0, &Parameter1) &&
-		  DAC960_ReportErrorStatus(Controller, ErrorStatus,
-					   Parameter0, Parameter1))
-		goto Failure;
-	      udelay(10);
-	    }
-	  if (!DAC960_EnableMemoryMailboxInterface(Controller))
-	    {
-	      DAC960_Error("Unable to Enable Memory Mailbox Interface "
-			   "for Controller at\n", Controller);
-	      goto Failure;
-	    }
-	  DAC960_V4_EnableInterrupts(BaseAddress);
-	  break;
-	case DAC960_V3_Controller:
-	  request_region(Controller->IO_Address, 0x80,
-			 Controller->FullModelName);
-	  DAC960_V3_DisableInterrupts(BaseAddress);
-	  DAC960_V3_AcknowledgeStatus(BaseAddress);
-	  udelay(1000);
-	  while (DAC960_V3_InitializationInProgressP(BaseAddress))
-	    {
-	      if (DAC960_V3_ReadErrorStatus(BaseAddress, &ErrorStatus,
-					    &Parameter0, &Parameter1) &&
-		  DAC960_ReportErrorStatus(Controller, ErrorStatus,
-					   Parameter0, Parameter1))
-		goto Failure;
-	      udelay(10);
-	    }
-	  DAC960_V3_EnableInterrupts(BaseAddress);
-	  break;
-	}
-      /*
-	Acquire shared access to the IRQ Channel.
-      */
-      if (IRQ_Channel == 0)
-	{
-	  DAC960_Error("IRQ Channel %d illegal for Controller at\n",
-		       Controller, IRQ_Channel);
-	  goto Failure;
-	}
-      strcpy(Controller->FullModelName, "DAC960");
-      if (request_irq(IRQ_Channel, DAC960_InterruptHandler,
-		      SA_SHIRQ, Controller->FullModelName, Controller) < 0)
-	{
-	  DAC960_Error("Unable to acquire IRQ Channel %d for Controller at\n",
-		       Controller, IRQ_Channel);
-	  goto Failure;
-	}
-      Controller->IRQ_Channel = IRQ_Channel;
-      DAC960_ActiveControllerCount++;
-      for (CommandIdentifier = 0;
-	   CommandIdentifier < DAC960_MaxChannels;
-	   CommandIdentifier++)
-	{
-	  Controller->Commands[CommandIdentifier].Controller = Controller;
-	  Controller->Commands[CommandIdentifier].Next =
-	    Controller->FreeCommands;
-	  Controller->FreeCommands = &Controller->Commands[CommandIdentifier];
-	}
-      continue;
-    Failure:
-      if (IO_Address == 0)
-	DAC960_Error("PCI Bus %d Device %d Function %d I/O Address N/A "
-		     "PCI Address 0x%X\n", Controller,
-		     Bus, Device, Function, PCI_Address);
-      else DAC960_Error("PCI Bus %d Device %d Function %d I/O Address "
-			"0x%X PCI Address 0x%X\n", Controller,
-			Bus, Device, Function, IO_Address, PCI_Address);
-      if (Controller == NULL) break;
-      if (Controller->MemoryMappedAddress != NULL)
-	iounmap(Controller->MemoryMappedAddress);
-      DAC960_Controllers[Controller->ControllerNumber] = NULL;
-      if (Controller->IRQ_Channel > 0)
-	free_irq(IRQ_Channel, Controller);
-    Ignore:
-      kfree(Controller);
-    }
-}
-
-
-/*
-  DAC960_ReadControllerConfiguration reads the Configuration Information
-  from Controller and initializes the Controller structure.
-*/
-
-static boolean DAC960_ReadControllerConfiguration(DAC960_Controller_T
-						  *Controller)
-{
-  DAC960_Enquiry2_T Enquiry2;
-  DAC960_Config2_T Config2;
-  int LogicalDriveNumber, Channel, TargetID;
-  if (!DAC960_ExecuteType3(Controller, DAC960_Enquiry,
-			   &Controller->Enquiry[0]))
-    return DAC960_Failure(Controller, "ENQUIRY");
-  if (!DAC960_ExecuteType3(Controller, DAC960_Enquiry2, &Enquiry2))
-    return DAC960_Failure(Controller, "ENQUIRY2");
-  if (!DAC960_ExecuteType3(Controller, DAC960_ReadConfig2, &Config2))
-    return DAC960_Failure(Controller, "READ CONFIG2");
-  if (!DAC960_ExecuteType3(Controller, DAC960_GetLogicalDriveInformation,
-			   &Controller->LogicalDriveInformation[0]))
-    return DAC960_Failure(Controller, "GET LOGICAL DRIVE INFORMATION");
-  for (Channel = 0; Channel < Enquiry2.ActualChannels; Channel++)
-    for (TargetID = 0; TargetID < DAC960_MaxTargets; TargetID++)
-      if (!DAC960_ExecuteType3D(Controller, DAC960_GetDeviceState,
-				Channel, TargetID,
-				&Controller->DeviceState[0][Channel][TargetID]))
-	return DAC960_Failure(Controller, "GET DEVICE STATE");
-  /*
-    Initialize the Controller Model Name and Full Model Name fields.
-  */
-  switch (Enquiry2.HardwareID.SubModel)
-    {
-    case DAC960_P_PD_PU:
-      if (Enquiry2.SCSICapability.BusSpeed == DAC960_Ultra)
+    case DAC960_V1_P_PD_PU:
+      if (Enquiry2.SCSICapability.BusSpeed == DAC960_V1_Ultra)
 	strcpy(Controller->ModelName, "DAC960PU");
       else strcpy(Controller->ModelName, "DAC960PD");
       break;
-    case DAC960_PL:
+    case DAC960_V1_PL:
       strcpy(Controller->ModelName, "DAC960PL");
       break;
-    case DAC960_PG:
+    case DAC960_V1_PG:
       strcpy(Controller->ModelName, "DAC960PG");
       break;
-    case DAC960_PJ:
+    case DAC960_V1_PJ:
       strcpy(Controller->ModelName, "DAC960PJ");
       break;
-    case DAC960_PR:
+    case DAC960_V1_PR:
       strcpy(Controller->ModelName, "DAC960PR");
       break;
-    case DAC960_PT:
+    case DAC960_V1_PT:
       strcpy(Controller->ModelName, "DAC960PT");
       break;
-    case DAC960_PTL0:
+    case DAC960_V1_PTL0:
       strcpy(Controller->ModelName, "DAC960PTL0");
       break;
-    case DAC960_PRL:
+    case DAC960_V1_PRL:
       strcpy(Controller->ModelName, "DAC960PRL");
       break;
-    case DAC960_PTL1:
+    case DAC960_V1_PTL1:
       strcpy(Controller->ModelName, "DAC960PTL1");
       break;
-    case DAC1164_P:
+    case DAC960_V1_1164P:
       strcpy(Controller->ModelName, "DAC1164P");
       break;
     default:
@@ -818,61 +1085,197 @@
       return false;
     }
   /*
-    Initialize the Controller Channels, Memory Size, and SAF-TE Enclosure
-    Management Enabled fields.
+    Initialize the Controller Channels, Targets, Memory Size, and SAF-TE
+    Enclosure Management Enabled fields.
   */
   Controller->Channels = Enquiry2.ActualChannels;
+  Controller->Targets = Enquiry2.MaxTargets;
   Controller->MemorySize = Enquiry2.MemorySize >> 20;
-  Controller->SAFTE_EnclosureManagementEnabled =
-    Enquiry2.FaultManagementType == DAC960_SAFTE;
+  Controller->V1.SAFTE_EnclosureManagementEnabled =
+    (Enquiry2.FaultManagementType == DAC960_V1_SAFTE);
   /*
     Initialize the Controller Queue Depth, Driver Queue Depth, Logical Drive
-    Count, Maximum Blocks per Command, and Maximum Scatter/Gather Segments.
-    The Driver Queue Depth must be at most one less than the Controller Queue
-    Depth to allow for an automatic drive rebuild operation.
+    Count, Maximum Blocks per Command, Controller Scatter/Gather Limit, and
+    Driver Scatter/Gather Limit.  The Driver Queue Depth must be at most one
+    less than the Controller Queue Depth to allow for an automatic drive
+    rebuild operation.
   */
-  Controller->ControllerQueueDepth = Controller->Enquiry[0].MaxCommands;
+  Controller->ControllerQueueDepth = Controller->V1.Enquiry.MaxCommands;
   Controller->DriverQueueDepth = Controller->ControllerQueueDepth - 1;
-  Controller->LogicalDriveCount = Controller->Enquiry[0].NumberOfLogicalDrives;
+  if (Controller->DriverQueueDepth > DAC960_MaxDriverQueueDepth)
+    Controller->DriverQueueDepth = DAC960_MaxDriverQueueDepth;
+  Controller->LogicalDriveCount =
+    Controller->V1.Enquiry.NumberOfLogicalDrives;
   Controller->MaxBlocksPerCommand = Enquiry2.MaxBlocksPerCommand;
-  Controller->MaxScatterGatherSegments = Enquiry2.MaxScatterGatherEntries;
+  Controller->ControllerScatterGatherLimit = Enquiry2.MaxScatterGatherEntries;
+  Controller->DriverScatterGatherLimit =
+    Controller->ControllerScatterGatherLimit;
+  if (Controller->DriverScatterGatherLimit > DAC960_V1_ScatterGatherLimit)
+    Controller->DriverScatterGatherLimit = DAC960_V1_ScatterGatherLimit;
   /*
     Initialize the Stripe Size, Segment Size, and Geometry Translation.
   */
-  Controller->StripeSize = Config2.BlocksPerStripe * Config2.BlockFactor
-			   >> (10 - DAC960_BlockSizeBits);
-  Controller->SegmentSize = Config2.BlocksPerCacheLine * Config2.BlockFactor
-			    >> (10 - DAC960_BlockSizeBits);
+  Controller->V1.StripeSize = Config2.BlocksPerStripe * Config2.BlockFactor
+			      >> (10 - DAC960_BlockSizeBits);
+  Controller->V1.SegmentSize = Config2.BlocksPerCacheLine * Config2.BlockFactor
+			       >> (10 - DAC960_BlockSizeBits);
   switch (Config2.DriveGeometry)
     {
-    case DAC960_Geometry_128_32:
-      Controller->GeometryTranslationHeads = 128;
-      Controller->GeometryTranslationSectors = 32;
-      break;
-    case DAC960_Geometry_255_63:
-      Controller->GeometryTranslationHeads = 255;
-      Controller->GeometryTranslationSectors = 63;
+    case DAC960_V1_Geometry_128_32:
+      Controller->V1.GeometryTranslationHeads = 128;
+      Controller->V1.GeometryTranslationSectors = 32;
+      break;
+    case DAC960_V1_Geometry_255_63:
+      Controller->V1.GeometryTranslationHeads = 255;
+      Controller->V1.GeometryTranslationSectors = 63;
       break;
     default:
       return DAC960_Failure(Controller, "CONFIG2 DRIVE GEOMETRY");
     }
   /*
-    Initialize the Logical Drive Initial State.
+    Initialize the Logical Drive Initially Accessible flag.
   */
   for (LogicalDriveNumber = 0;
        LogicalDriveNumber < Controller->LogicalDriveCount;
        LogicalDriveNumber++)
-    Controller->LogicalDriveInitialState[LogicalDriveNumber] =
-      Controller->LogicalDriveInformation[0]
-		  [LogicalDriveNumber].LogicalDriveState;
-  Controller->LastRebuildStatus = DAC960_NoRebuildOrCheckInProgress;
+    if (Controller->V1.LogicalDriveInformation
+		       [LogicalDriveNumber].LogicalDriveState !=
+	DAC960_V1_LogicalDrive_Offline)
+      Controller->LogicalDriveInitiallyAccessible[LogicalDriveNumber] = true;
+  Controller->V1.LastRebuildStatus = DAC960_V1_NoRebuildOrCheckInProgress;
   return true;
 }
 
 
 /*
-  DAC960_ReportControllerConfiguration reports the Configuration Information of
-  Controller.
+  DAC960_V2_ReadControllerConfiguration reads the Configuration Information
+  from DAC960 V2 Firmware Controllers and initializes the Controller structure.
+*/
+
+static boolean DAC960_V2_ReadControllerConfiguration(DAC960_Controller_T
+						     *Controller)
+{
+  DAC960_V2_ControllerInfo_T *ControllerInfo =
+    &Controller->V2.ControllerInformation;
+  unsigned short LogicalDeviceNumber = 0;
+  int ModelNameLength;
+  if (!DAC960_V2_ControllerInfo(Controller, DAC960_V2_GetControllerInfo,
+				ControllerInfo,
+				sizeof(DAC960_V2_ControllerInfo_T)))
+    return DAC960_Failure(Controller, "GET CONTROLLER INFO");
+  if (!DAC960_V2_GeneralInfo(Controller, DAC960_V2_GetHealthStatus,
+			     Controller->V2.HealthStatusBuffer,
+			     sizeof(DAC960_V2_HealthStatusBuffer_T)))
+    return DAC960_Failure(Controller, "GET HEALTH STATUS");
+  /*
+    Initialize the Controller Model Name and Full Model Name fields.
+  */
+  ModelNameLength = sizeof(ControllerInfo->ControllerName);
+  if (ModelNameLength > sizeof(Controller->ModelName)-1)
+    ModelNameLength = sizeof(Controller->ModelName)-1;
+  memcpy(Controller->ModelName, ControllerInfo->ControllerName,
+	 ModelNameLength);
+  ModelNameLength--;
+  while (Controller->ModelName[ModelNameLength] == ' ' ||
+	 Controller->ModelName[ModelNameLength] == '\0')
+    ModelNameLength--;
+  Controller->ModelName[++ModelNameLength] = '\0';
+  strcpy(Controller->FullModelName, "Mylex ");
+  strcat(Controller->FullModelName, Controller->ModelName);
+  /*
+    Initialize the Controller Firmware Version field.
+  */
+  sprintf(Controller->FirmwareVersion, "%d.%02d-%02d",
+	  ControllerInfo->FirmwareMajorVersion,
+	  ControllerInfo->FirmwareMinorVersion,
+	  ControllerInfo->FirmwareTurnNumber);
+  if (ControllerInfo->FirmwareMajorVersion == 6 &&
+      ControllerInfo->FirmwareMinorVersion == 0 &&
+      ControllerInfo->FirmwareTurnNumber < 1)
+    {
+      DAC960_Info("FIRMWARE VERSION %s DOES NOT PROVIDE THE CONTROLLER\n",
+		  Controller, Controller->FirmwareVersion);
+      DAC960_Info("STATUS MONITORING FUNCTIONALITY NEEDED BY THIS DRIVER.\n",
+		  Controller);
+      DAC960_Info("PLEASE UPGRADE TO VERSION 6.00-01 OR ABOVE.\n",
+		  Controller);
+    }
+  /*
+    Initialize the Controller Channels, Targets, and Memory Size.
+  */
+  Controller->Channels = ControllerInfo->NumberOfPhysicalChannelsPresent;
+  Controller->Targets =
+    ControllerInfo->MaximumTargetsPerChannel
+		    [ControllerInfo->NumberOfPhysicalChannelsPresent-1];
+  Controller->MemorySize = ControllerInfo->MemorySizeMB;
+  /*
+    Initialize the Controller Queue Depth, Driver Queue Depth, Logical Drive
+    Count, Maximum Blocks per Command, Controller Scatter/Gather Limit, and
+    Driver Scatter/Gather Limit.  The Driver Queue Depth must be at most one
+    less than the Controller Queue Depth to allow for an automatic drive
+    rebuild operation.
+  */
+  Controller->ControllerQueueDepth = ControllerInfo->MaximumParallelCommands;
+  Controller->DriverQueueDepth = Controller->ControllerQueueDepth - 1;
+  if (Controller->DriverQueueDepth > DAC960_MaxDriverQueueDepth)
+    Controller->DriverQueueDepth = DAC960_MaxDriverQueueDepth;
+  Controller->LogicalDriveCount = ControllerInfo->LogicalDevicesPresent;
+  Controller->MaxBlocksPerCommand =
+    ControllerInfo->MaximumDataTransferSizeInBlocks;
+  Controller->ControllerScatterGatherLimit =
+    ControllerInfo->MaximumScatterGatherEntries;
+  Controller->DriverScatterGatherLimit =
+    Controller->ControllerScatterGatherLimit;
+  if (Controller->DriverScatterGatherLimit > DAC960_V2_ScatterGatherLimit)
+    Controller->DriverScatterGatherLimit = DAC960_V2_ScatterGatherLimit;
+  /*
+    Initialize the Logical Device Information.
+  */
+  while (true)
+    {
+      DAC960_V2_LogicalDeviceInfo_T *NewLogicalDeviceInfo =
+	&Controller->V2.NewLogicalDeviceInformation;
+      DAC960_V2_LogicalDeviceInfo_T *LogicalDeviceInfo;
+      DAC960_V2_PhysicalDevice_T PhysicalDevice;
+      if (!DAC960_V2_LogicalDeviceInfo(Controller,
+				       DAC960_V2_GetLogicalDeviceInfoValid,
+				       LogicalDeviceNumber,
+				       NewLogicalDeviceInfo,
+				       sizeof(DAC960_V2_LogicalDeviceInfo_T)))
+	break;
+      LogicalDeviceNumber = NewLogicalDeviceInfo->LogicalDeviceNumber;
+      if (LogicalDeviceNumber > DAC960_MaxLogicalDrives)
+	panic("DAC960: Logical Drive Number %d not supported\n",
+		       LogicalDeviceNumber);
+      if (NewLogicalDeviceInfo->DeviceBlockSizeInBytes != DAC960_BlockSize)
+	panic("DAC960: Logical Drive Block Size %d not supported\n",
+	      NewLogicalDeviceInfo->DeviceBlockSizeInBytes);
+      PhysicalDevice.Controller = 0;
+      PhysicalDevice.Channel = NewLogicalDeviceInfo->Channel;
+      PhysicalDevice.TargetID = NewLogicalDeviceInfo->TargetID;
+      PhysicalDevice.LogicalUnit = NewLogicalDeviceInfo->LogicalUnit;
+      Controller->V2.LogicalDriveToVirtualDevice[LogicalDeviceNumber] =
+	PhysicalDevice;
+      if (NewLogicalDeviceInfo->LogicalDeviceState !=
+	  DAC960_V2_LogicalDevice_Offline)
+	Controller->LogicalDriveInitiallyAccessible[LogicalDeviceNumber] = true;
+      LogicalDeviceInfo = (DAC960_V2_LogicalDeviceInfo_T *)
+	kmalloc(sizeof(DAC960_V2_LogicalDeviceInfo_T), GFP_ATOMIC);
+      if (LogicalDeviceInfo == NULL)
+	return DAC960_Failure(Controller, "LOGICAL DEVICE ALLOCATION");
+      Controller->V2.LogicalDeviceInformation[LogicalDeviceNumber] =
+	LogicalDeviceInfo;
+      memcpy(LogicalDeviceInfo, NewLogicalDeviceInfo,
+	     sizeof(DAC960_V2_LogicalDeviceInfo_T));
+      LogicalDeviceNumber++;
+    }
+  return true;
+}
+
+
+/*
+  DAC960_ReportControllerConfiguration reports the Configuration Information
+  for Controller.
 */
 
 static boolean DAC960_ReportControllerConfiguration(DAC960_Controller_T
@@ -898,54 +1301,60 @@
 	      Controller, Controller->ControllerQueueDepth,
 	      Controller->MaxBlocksPerCommand);
   DAC960_Info("  Driver Queue Depth: %d, "
-	      "Maximum Scatter/Gather Segments: %d\n",
+	      "Scatter/Gather Limit: %d of %d Segments\n",
 	      Controller, Controller->DriverQueueDepth,
-	      Controller->MaxScatterGatherSegments);
-  DAC960_Info("  Stripe Size: %dKB, Segment Size: %dKB, "
-	      "BIOS Geometry: %d/%d\n", Controller,
-	      Controller->StripeSize,
-	      Controller->SegmentSize,
-	      Controller->GeometryTranslationHeads,
-	      Controller->GeometryTranslationSectors);
-  if (Controller->SAFTE_EnclosureManagementEnabled)
-    DAC960_Info("  SAF-TE Enclosure Management Enabled\n", Controller);
+	      Controller->DriverScatterGatherLimit,
+	      Controller->ControllerScatterGatherLimit);
+  if (Controller->FirmwareType == DAC960_V1_Controller)
+    {
+      DAC960_Info("  Stripe Size: %dKB, Segment Size: %dKB, "
+		  "BIOS Geometry: %d/%d\n", Controller,
+		  Controller->V1.StripeSize,
+		  Controller->V1.SegmentSize,
+		  Controller->V1.GeometryTranslationHeads,
+		  Controller->V1.GeometryTranslationSectors);
+      if (Controller->V1.SAFTE_EnclosureManagementEnabled)
+	DAC960_Info("  SAF-TE Enclosure Management Enabled\n", Controller);
+    }
   return true;
 }
 
 
 /*
-  DAC960_ReadDeviceConfiguration reads the Device Configuration Information by
-  requesting the SCSI Inquiry and SCSI Inquiry Unit Serial Number information
-  for each device connected to Controller.
+  DAC960_V1_ReadDeviceConfiguration reads the Device Configuration Information
+  for DAC960 V1 Firmware Controllers by requesting the SCSI Inquiry and SCSI
+  Inquiry Unit Serial Number information for each device connected to
+  Controller.
 */
 
-static boolean DAC960_ReadDeviceConfiguration(DAC960_Controller_T *Controller)
+static boolean DAC960_V1_ReadDeviceConfiguration(DAC960_Controller_T
+						 *Controller)
 {
-  DAC960_DCDB_T DCDBs[DAC960_MaxChannels], *DCDB;
-  Semaphore_T Semaphores[DAC960_MaxChannels], *Semaphore;
+  DAC960_V1_DCDB_T DCDBs[DAC960_V1_MaxChannels], *DCDB;
+  Semaphore_T Semaphores[DAC960_V1_MaxChannels], *Semaphore;
   unsigned long ProcessorFlags;
   int Channel, TargetID;
-  for (TargetID = 0; TargetID < DAC960_MaxTargets; TargetID++)
+  for (TargetID = 0; TargetID < Controller->Targets; TargetID++)
     {
       for (Channel = 0; Channel < Controller->Channels; Channel++)
 	{
-	  DAC960_Command_T *Command = &Controller->Commands[Channel];
+	  DAC960_Command_T *Command = Controller->Commands[Channel];
 	  DAC960_SCSI_Inquiry_T *InquiryStandardData =
-	    &Controller->InquiryStandardData[Channel][TargetID];
+	    &Controller->V1.InquiryStandardData[Channel][TargetID];
 	  InquiryStandardData->PeripheralDeviceType = 0x1F;
 	  Semaphore = &Semaphores[Channel];
 	  *Semaphore = MUTEX_LOCKED;
 	  DCDB = &DCDBs[Channel];
-	  DAC960_ClearCommand(Command);
+	  DAC960_V1_ClearCommand(Command);
 	  Command->CommandType = DAC960_ImmediateCommand;
 	  Command->Semaphore = Semaphore;
-	  Command->CommandMailbox.Type3.CommandOpcode = DAC960_DCDB;
-	  Command->CommandMailbox.Type3.BusAddress = Virtual_to_Bus(DCDB);
+	  Command->V1.CommandMailbox.Type3.CommandOpcode = DAC960_V1_DCDB;
+	  Command->V1.CommandMailbox.Type3.BusAddress = Virtual_to_Bus(DCDB);
 	  DCDB->Channel = Channel;
 	  DCDB->TargetID = TargetID;
-	  DCDB->Direction = DAC960_DCDB_DataTransferDeviceToSystem;
+	  DCDB->Direction = DAC960_V1_DCDB_DataTransferDeviceToSystem;
 	  DCDB->EarlyStatus = false;
-	  DCDB->Timeout = DAC960_DCDB_Timeout_10_seconds;
+	  DCDB->Timeout = DAC960_V1_DCDB_Timeout_10_seconds;
 	  DCDB->NoAutomaticRequestSense = false;
 	  DCDB->DisconnectPermitted = true;
 	  DCDB->TransferLength = sizeof(DAC960_SCSI_Inquiry_T);
@@ -965,13 +1374,14 @@
 	}
       for (Channel = 0; Channel < Controller->Channels; Channel++)
 	{
-	  DAC960_Command_T *Command = &Controller->Commands[Channel];
+	  DAC960_Command_T *Command = Controller->Commands[Channel];
 	  DAC960_SCSI_Inquiry_UnitSerialNumber_T *InquiryUnitSerialNumber =
-	    &Controller->InquiryUnitSerialNumber[Channel][TargetID];
+	    &Controller->V1.InquiryUnitSerialNumber[Channel][TargetID];
 	  InquiryUnitSerialNumber->PeripheralDeviceType = 0x1F;
 	  Semaphore = &Semaphores[Channel];
 	  down(Semaphore);
-	  if (Command->CommandStatus != DAC960_NormalCompletion) continue;
+	  if (Command->V1.CommandStatus != DAC960_V1_NormalCompletion)
+	    continue;
 	  Command->Semaphore = Semaphore;
 	  DCDB = &DCDBs[Channel];
 	  DCDB->TransferLength = sizeof(DAC960_SCSI_Inquiry_UnitSerialNumber_T);
@@ -988,108 +1398,216 @@
 	  DAC960_ReleaseControllerLock(Controller, &ProcessorFlags);
 	  down(Semaphore);
 	}
+    }
+  return true;
+}
+
+
+/*
+  DAC960_V2_ReadDeviceConfiguration reads the Device Configuration Information
+  for DAC960 V2 Firmware Controllers by requesting the Physical Device
+  Information and SCSI Inquiry Unit Serial Number information for each
+  device connected to Controller.
+*/
+
+static boolean DAC960_V2_ReadDeviceConfiguration(DAC960_Controller_T
+						 *Controller)
+{
+  unsigned char Channel = 0, TargetID = 0, LogicalUnit = 0;
+  unsigned short PhysicalDeviceIndex = 0;
+  while (true)
+    {
+      DAC960_V2_PhysicalDeviceInfo_T *NewPhysicalDeviceInfo =
+	&Controller->V2.NewPhysicalDeviceInformation;
+      DAC960_V2_PhysicalDeviceInfo_T *PhysicalDeviceInfo;
+      DAC960_SCSI_Inquiry_UnitSerialNumber_T *InquiryUnitSerialNumber;
+      DAC960_Command_T *Command;
+      DAC960_V2_CommandMailbox_T *CommandMailbox;
+      if (!DAC960_V2_PhysicalDeviceInfo(Controller,
+					DAC960_V2_GetPhysicalDeviceInfoValid,
+					Channel,
+					TargetID,
+					LogicalUnit,
+					NewPhysicalDeviceInfo,
+					sizeof(DAC960_V2_PhysicalDeviceInfo_T)))
+	  break;
+      Channel = NewPhysicalDeviceInfo->Channel;
+      TargetID = NewPhysicalDeviceInfo->TargetID;
+      LogicalUnit = NewPhysicalDeviceInfo->LogicalUnit;
+      PhysicalDeviceInfo = (DAC960_V2_PhysicalDeviceInfo_T *)
+	kmalloc(sizeof(DAC960_V2_PhysicalDeviceInfo_T), GFP_ATOMIC);
+      if (PhysicalDeviceInfo == NULL)
+	return DAC960_Failure(Controller, "PHYSICAL DEVICE ALLOCATION");
+      Controller->V2.PhysicalDeviceInformation[PhysicalDeviceIndex] =
+	PhysicalDeviceInfo;
+      memcpy(PhysicalDeviceInfo, NewPhysicalDeviceInfo,
+	     sizeof(DAC960_V2_PhysicalDeviceInfo_T));
+      InquiryUnitSerialNumber = (DAC960_SCSI_Inquiry_UnitSerialNumber_T *)
+	kmalloc(sizeof(DAC960_SCSI_Inquiry_UnitSerialNumber_T), GFP_ATOMIC);
+      if (InquiryUnitSerialNumber == NULL)
+	return DAC960_Failure(Controller, "SERIAL NUMBER ALLOCATION");
+      Controller->V2.InquiryUnitSerialNumber[PhysicalDeviceIndex] =
+	InquiryUnitSerialNumber;
+      memset(InquiryUnitSerialNumber, 0,
+	     sizeof(DAC960_SCSI_Inquiry_UnitSerialNumber_T));
+      InquiryUnitSerialNumber->PeripheralDeviceType = 0x1F;
+      Command = DAC960_AllocateCommand(Controller);
+      CommandMailbox = &Command->V2.CommandMailbox;
+      DAC960_V2_ClearCommand(Command);
+      Command->CommandType = DAC960_ImmediateCommand;
+      CommandMailbox->SCSI_10.CommandOpcode = DAC960_V2_SCSI_10_Passthru;
+      CommandMailbox->SCSI_10.CommandControlBits
+			     .DataTransferControllerToHost = true;
+      CommandMailbox->SCSI_10.CommandControlBits
+			     .NoAutoRequestSense = true;
+      CommandMailbox->SCSI_10.DataTransferSize =
+	sizeof(DAC960_SCSI_Inquiry_UnitSerialNumber_T);
+      CommandMailbox->SCSI_10.PhysicalDevice.LogicalUnit = LogicalUnit;
+      CommandMailbox->SCSI_10.PhysicalDevice.TargetID = TargetID;
+      CommandMailbox->SCSI_10.PhysicalDevice.Channel = Channel;
+      CommandMailbox->SCSI_10.CDBLength = 6;
+      CommandMailbox->SCSI_10.SCSI_CDB[0] = 0x12; /* INQUIRY */
+      CommandMailbox->SCSI_10.SCSI_CDB[1] = 1; /* EVPD = 1 */
+      CommandMailbox->SCSI_10.SCSI_CDB[2] = 0x80; /* Page Code */
+      CommandMailbox->SCSI_10.SCSI_CDB[3] = 0; /* Reserved */
+      CommandMailbox->SCSI_10.SCSI_CDB[4] =
+	sizeof(DAC960_SCSI_Inquiry_UnitSerialNumber_T);
+      CommandMailbox->SCSI_10.SCSI_CDB[5] = 0; /* Control */
+      CommandMailbox->SCSI_10.DataTransferMemoryAddress
+			     .ScatterGatherSegments[0]
+			     .SegmentDataPointer =
+	Virtual_to_Bus(InquiryUnitSerialNumber);
+      CommandMailbox->SCSI_10.DataTransferMemoryAddress
+			     .ScatterGatherSegments[0]
+			     .SegmentByteCount =
+	CommandMailbox->SCSI_10.DataTransferSize;
+      DAC960_ExecuteCommand(Command);
+      DAC960_DeallocateCommand(Command);
+      PhysicalDeviceIndex++;
+      LogicalUnit++;
+    }
+  return true;
+}
+
+
+/*
+  DAC960_SanitizeInquiryData sanitizes the Vendor, Model, Revision, and
+  Product Serial Number fields of the Inquiry Standard Data and Inquiry
+  Unit Serial Number structures.
+*/
+
+static void DAC960_SanitizeInquiryData(DAC960_SCSI_Inquiry_T
+					 *InquiryStandardData,
+				       DAC960_SCSI_Inquiry_UnitSerialNumber_T
+					 *InquiryUnitSerialNumber,
+				       unsigned char *Vendor,
+				       unsigned char *Model,
+				       unsigned char *Revision,
+				       unsigned char *SerialNumber)
+{
+  int SerialNumberLength, i;
+  if (InquiryStandardData->PeripheralDeviceType == 0x1F) return;
+  for (i = 0; i < sizeof(InquiryStandardData->VendorIdentification); i++)
+    {
+      unsigned char VendorCharacter =
+	InquiryStandardData->VendorIdentification[i];
+      Vendor[i] = (VendorCharacter >= ' ' && VendorCharacter <= '~'
+		   ? VendorCharacter : ' ');
+    }
+  Vendor[sizeof(InquiryStandardData->VendorIdentification)] = '\0';
+  for (i = 0; i < sizeof(InquiryStandardData->ProductIdentification); i++)
+    {
+      unsigned char ModelCharacter =
+	InquiryStandardData->ProductIdentification[i];
+      Model[i] = (ModelCharacter >= ' ' && ModelCharacter <= '~'
+		  ? ModelCharacter : ' ');
     }
-  return true; 
+  Model[sizeof(InquiryStandardData->ProductIdentification)] = '\0';
+  for (i = 0; i < sizeof(InquiryStandardData->ProductRevisionLevel); i++)
+    {
+      unsigned char RevisionCharacter =
+	InquiryStandardData->ProductRevisionLevel[i];
+      Revision[i] = (RevisionCharacter >= ' ' && RevisionCharacter <= '~'
+		     ? RevisionCharacter : ' ');
+    }
+  Revision[sizeof(InquiryStandardData->ProductRevisionLevel)] = '\0';
+  if (InquiryUnitSerialNumber->PeripheralDeviceType == 0x1F) return;
+  SerialNumberLength = InquiryUnitSerialNumber->PageLength;
+  if (SerialNumberLength >
+      sizeof(InquiryUnitSerialNumber->ProductSerialNumber))
+    SerialNumberLength = sizeof(InquiryUnitSerialNumber->ProductSerialNumber);
+  for (i = 0; i < SerialNumberLength; i++)
+    {
+      unsigned char SerialNumberCharacter =
+	InquiryUnitSerialNumber->ProductSerialNumber[i];
+      SerialNumber[i] =
+	(SerialNumberCharacter >= ' ' && SerialNumberCharacter <= '~'
+	 ? SerialNumberCharacter : ' ');
+    }
+  SerialNumber[SerialNumberLength] = '\0';
 }
 
 
 /*
-  DAC960_ReportDeviceConfiguration reports the Device Configuration Information
-  of Controller.
+  DAC960_V1_ReportDeviceConfiguration reports the Device Configuration
+  Information for DAC960 V1 Firmware Controllers.
 */
 
-static boolean DAC960_ReportDeviceConfiguration(DAC960_Controller_T *Controller)
+static boolean DAC960_V1_ReportDeviceConfiguration(DAC960_Controller_T
+						   *Controller)
 {
   int LogicalDriveNumber, Channel, TargetID;
   DAC960_Info("  Physical Devices:\n", Controller);
   for (Channel = 0; Channel < Controller->Channels; Channel++)
-    for (TargetID = 0; TargetID < DAC960_MaxTargets; TargetID++)
+    for (TargetID = 0; TargetID < Controller->Targets; TargetID++)
       {
 	DAC960_SCSI_Inquiry_T *InquiryStandardData =
-	  &Controller->InquiryStandardData[Channel][TargetID];
+	  &Controller->V1.InquiryStandardData[Channel][TargetID];
 	DAC960_SCSI_Inquiry_UnitSerialNumber_T *InquiryUnitSerialNumber =
-	  &Controller->InquiryUnitSerialNumber[Channel][TargetID];
-	DAC960_DeviceState_T *DeviceState =
-	  &Controller->DeviceState[Controller->DeviceStateIndex]
-				  [Channel][TargetID];
-	DAC960_ErrorTable_T *ErrorTable =
-	  &Controller->ErrorTable[Controller->ErrorTableIndex];
-	DAC960_ErrorTableEntry_T *ErrorEntry =
-	  &ErrorTable->ErrorTableEntries[Channel][TargetID];
+	  &Controller->V1.InquiryUnitSerialNumber[Channel][TargetID];
+	DAC960_V1_DeviceState_T *DeviceState =
+	  &Controller->V1.DeviceState[Channel][TargetID];
+	DAC960_V1_ErrorTableEntry_T *ErrorEntry =
+	  &Controller->V1.ErrorTable.ErrorTableEntries[Channel][TargetID];
 	char Vendor[1+sizeof(InquiryStandardData->VendorIdentification)];
 	char Model[1+sizeof(InquiryStandardData->ProductIdentification)];
 	char Revision[1+sizeof(InquiryStandardData->ProductRevisionLevel)];
 	char SerialNumber[1+sizeof(InquiryUnitSerialNumber
 				   ->ProductSerialNumber)];
-	int i;
 	if (InquiryStandardData->PeripheralDeviceType == 0x1F) continue;
-	for (i = 0; i < sizeof(Vendor)-1; i++)
-	  {
-	    unsigned char VendorCharacter =
-	      InquiryStandardData->VendorIdentification[i];
-	    Vendor[i] = (VendorCharacter >= ' ' && VendorCharacter <= '~'
-			 ? VendorCharacter : ' ');
-	  }
-	Vendor[sizeof(Vendor)-1] = '\0';
-	for (i = 0; i < sizeof(Model)-1; i++)
-	  {
-	    unsigned char ModelCharacter =
-	      InquiryStandardData->ProductIdentification[i];
-	    Model[i] = (ModelCharacter >= ' ' && ModelCharacter <= '~'
-			? ModelCharacter : ' ');
-	  }
-	Model[sizeof(Model)-1] = '\0';
-	for (i = 0; i < sizeof(Revision)-1; i++)
-	  {
-	    unsigned char RevisionCharacter =
-	      InquiryStandardData->ProductRevisionLevel[i];
-	    Revision[i] = (RevisionCharacter >= ' ' && RevisionCharacter <= '~'
-			   ? RevisionCharacter : ' ');
-	  }
-	Revision[sizeof(Revision)-1] = '\0';
+	DAC960_SanitizeInquiryData(InquiryStandardData, InquiryUnitSerialNumber,
+				   Vendor, Model, Revision, SerialNumber);
 	DAC960_Info("    %d:%d%s Vendor: %s  Model: %s  Revision: %s\n",
 		    Controller, Channel, TargetID, (TargetID < 10 ? " " : ""),
 		    Vendor, Model, Revision);
 	if (InquiryUnitSerialNumber->PeripheralDeviceType != 0x1F)
-	  {
-	    int SerialNumberLength = InquiryUnitSerialNumber->PageLength;
-	    if (SerialNumberLength >
-		sizeof(InquiryUnitSerialNumber->ProductSerialNumber))
-	      SerialNumberLength =
-		sizeof(InquiryUnitSerialNumber->ProductSerialNumber);
-	    for (i = 0; i < SerialNumberLength; i++)
-	      {
-		unsigned char SerialNumberCharacter =
-		  InquiryUnitSerialNumber->ProductSerialNumber[i];
-		SerialNumber[i] =
-		  (SerialNumberCharacter >= ' ' && SerialNumberCharacter <= '~'
-		   ? SerialNumberCharacter : ' ');
-	      }
-	    SerialNumber[SerialNumberLength] = '\0';
-	    DAC960_Info("         Serial Number: %s\n",
-			Controller, SerialNumber);
-	  }
-	if (DeviceState->Present && DeviceState->DeviceType == DAC960_DiskType)
+	  DAC960_Info("         Serial Number: %s\n", Controller, SerialNumber);
+	if (DeviceState->Present &&
+	    DeviceState->DeviceType == DAC960_V1_DiskType)
 	  {
-	    if (Controller->DeviceResetCount[Channel][TargetID] > 0)
+	    if (Controller->V1.DeviceResetCount[Channel][TargetID] > 0)
 	      DAC960_Info("         Disk Status: %s, %d blocks, %d resets\n",
 			  Controller,
-			  (DeviceState->DeviceState == DAC960_Device_Dead
+			  (DeviceState->DeviceState == DAC960_V1_Device_Dead
 			   ? "Dead"
-			   : DeviceState->DeviceState == DAC960_Device_WriteOnly
-			   ? "Write-Only"
-			   : DeviceState->DeviceState == DAC960_Device_Online
-			   ? "Online" : "Standby"),
+			   : DeviceState->DeviceState
+			     == DAC960_V1_Device_WriteOnly
+			     ? "Write-Only"
+			     : DeviceState->DeviceState
+			       == DAC960_V1_Device_Online
+			       ? "Online" : "Standby"),
 			  DeviceState->DiskSize,
-			  Controller->DeviceResetCount[Channel][TargetID]);
+			  Controller->V1.DeviceResetCount[Channel][TargetID]);
 	    else
 	      DAC960_Info("         Disk Status: %s, %d blocks\n", Controller,
-			  (DeviceState->DeviceState == DAC960_Device_Dead
+			  (DeviceState->DeviceState == DAC960_V1_Device_Dead
 			   ? "Dead"
-			   : DeviceState->DeviceState == DAC960_Device_WriteOnly
-			   ? "Write-Only"
-			   : DeviceState->DeviceState == DAC960_Device_Online
-			   ? "Online" : "Standby"),
+			   : DeviceState->DeviceState
+			     == DAC960_V1_Device_WriteOnly
+			     ? "Write-Only"
+			     : DeviceState->DeviceState
+			       == DAC960_V1_Device_Online
+			       ? "Online" : "Standby"),
 			  DeviceState->DiskSize);
 	  }
 	if (ErrorEntry->ParityErrorCount > 0 ||
@@ -1108,17 +1626,16 @@
        LogicalDriveNumber < Controller->LogicalDriveCount;
        LogicalDriveNumber++)
     {
-      DAC960_LogicalDriveInformation_T *LogicalDriveInformation =
-	&Controller->LogicalDriveInformation
-	   [Controller->LogicalDriveInformationIndex][LogicalDriveNumber];
+      DAC960_V1_LogicalDriveInformation_T *LogicalDriveInformation =
+	&Controller->V1.LogicalDriveInformation[LogicalDriveNumber];
       DAC960_Info("    /dev/rd/c%dd%d: RAID-%d, %s, %d blocks, %s\n",
 		  Controller, Controller->ControllerNumber, LogicalDriveNumber,
 		  LogicalDriveInformation->RAIDLevel,
-		  (LogicalDriveInformation->LogicalDriveState ==
-		     DAC960_LogicalDrive_Online
+		  (LogicalDriveInformation->LogicalDriveState
+		   == DAC960_V1_LogicalDrive_Online
 		   ? "Online"
-		   : LogicalDriveInformation->LogicalDriveState ==
-		     DAC960_LogicalDrive_Critical
+		   : LogicalDriveInformation->LogicalDriveState
+		     == DAC960_V1_LogicalDrive_Critical
 		     ? "Critical" : "Offline"),
 		  LogicalDriveInformation->LogicalDriveSize,
 		  (LogicalDriveInformation->WriteBack
@@ -1129,6 +1646,179 @@
 
 
 /*
+  DAC960_V2_ReportDeviceConfiguration reports the Device Configuration
+  Information for DAC960 V2 Firmware Controllers.
+*/
+
+static boolean DAC960_V2_ReportDeviceConfiguration(DAC960_Controller_T
+						   *Controller)
+{
+  int PhysicalDeviceIndex, LogicalDriveNumber;
+  DAC960_Info("  Physical Devices:\n", Controller);
+  for (PhysicalDeviceIndex = 0;
+       PhysicalDeviceIndex < DAC960_V2_MaxPhysicalDevices;
+       PhysicalDeviceIndex++)
+    {
+      DAC960_V2_PhysicalDeviceInfo_T *PhysicalDeviceInfo =
+	Controller->V2.PhysicalDeviceInformation[PhysicalDeviceIndex];
+      DAC960_SCSI_Inquiry_T *InquiryStandardData =
+	(DAC960_SCSI_Inquiry_T *) &PhysicalDeviceInfo->SCSI_InquiryData;
+      DAC960_SCSI_Inquiry_UnitSerialNumber_T *InquiryUnitSerialNumber =
+	Controller->V2.InquiryUnitSerialNumber[PhysicalDeviceIndex];
+      char Vendor[1+sizeof(InquiryStandardData->VendorIdentification)];
+      char Model[1+sizeof(InquiryStandardData->ProductIdentification)];
+      char Revision[1+sizeof(InquiryStandardData->ProductRevisionLevel)];
+      char SerialNumber[1+sizeof(InquiryUnitSerialNumber->ProductSerialNumber)];
+      if (PhysicalDeviceInfo == NULL) break;
+      DAC960_SanitizeInquiryData(InquiryStandardData, InquiryUnitSerialNumber,
+				 Vendor, Model, Revision, SerialNumber);
+      DAC960_Info("    %d:%d%s Vendor: %s  Model: %s  Revision: %s\n",
+		  Controller,
+		  PhysicalDeviceInfo->Channel,
+		  PhysicalDeviceInfo->TargetID,
+		  (PhysicalDeviceInfo->TargetID < 10 ? " " : ""),
+		  Vendor, Model, Revision);
+      if (PhysicalDeviceInfo->NegotiatedSynchronousMegaTransfers == 0)
+	DAC960_Info("         %sAsynchronous\n", Controller,
+		    (PhysicalDeviceInfo->NegotiatedDataWidthBits == 16
+		     ? "Wide " :""));
+      else
+	DAC960_Info("         %sSynchronous at %d MB/sec\n", Controller,
+		    (PhysicalDeviceInfo->NegotiatedDataWidthBits == 16
+		     ? "Wide " :""),
+		    (PhysicalDeviceInfo->NegotiatedSynchronousMegaTransfers
+		     * (PhysicalDeviceInfo->NegotiatedDataWidthBits == 16
+			? 2 : 1)));
+      if (InquiryUnitSerialNumber->PeripheralDeviceType != 0x1F)
+	DAC960_Info("         Serial Number: %s\n", Controller, SerialNumber);
+      if (PhysicalDeviceInfo->PhysicalDeviceState ==
+	  DAC960_V2_Device_Unconfigured)
+	continue;
+      DAC960_Info("         Disk Status: %s, %d blocks\n", Controller,
+		  (PhysicalDeviceInfo->PhysicalDeviceState
+		   == DAC960_V2_Device_Online
+		   ? "Online"
+		   : PhysicalDeviceInfo->PhysicalDeviceState
+		     == DAC960_V2_Device_WriteOnly
+		     ? "Write-Only"
+		     : PhysicalDeviceInfo->PhysicalDeviceState
+		       == DAC960_V2_Device_Dead
+		       ? "Dead" : "Standby"),
+		  PhysicalDeviceInfo
+		  ->ConfigurableDeviceSizeIn512ByteBlocksOrMB);
+      if (PhysicalDeviceInfo->ParityErrors == 0 &&
+	  PhysicalDeviceInfo->SoftErrors == 0 &&
+	  PhysicalDeviceInfo->HardErrors == 0 &&
+	  PhysicalDeviceInfo->MiscellaneousErrors == 0 &&
+	  PhysicalDeviceInfo->CommandTimeouts == 0 &&
+	  PhysicalDeviceInfo->Retries == 0 &&
+	  PhysicalDeviceInfo->Aborts == 0 &&
+	  PhysicalDeviceInfo->PredictedFailuresDetected == 0)
+	continue;
+      DAC960_Info("         Errors - Parity: %d, Soft: %d, "
+		  "Hard: %d, Misc: %d\n", Controller,
+		  PhysicalDeviceInfo->ParityErrors,
+		  PhysicalDeviceInfo->SoftErrors,
+		  PhysicalDeviceInfo->HardErrors,
+		  PhysicalDeviceInfo->MiscellaneousErrors);
+      DAC960_Info("                  Timeouts: %d, Retries: %d, "
+		  "Aborts: %d, Predicted: %d\n", Controller,
+		  PhysicalDeviceInfo->CommandTimeouts,
+		  PhysicalDeviceInfo->Retries,
+		  PhysicalDeviceInfo->Aborts,
+		  PhysicalDeviceInfo->PredictedFailuresDetected);
+    }
+  DAC960_Info("  Logical Drives:\n", Controller);
+  for (LogicalDriveNumber = 0;
+       LogicalDriveNumber < DAC960_MaxLogicalDrives;
+       LogicalDriveNumber++)
+    {
+      DAC960_V2_LogicalDeviceInfo_T *LogicalDeviceInfo =
+	Controller->V2.LogicalDeviceInformation[LogicalDriveNumber];
+      unsigned char *ReadCacheStatus[] = { "Read Cache Disabled",
+					   "Read Cache Enabled",
+					   "Read Ahead Enabled",
+					   "Intelligent Read Ahead Enabled",
+					   "-", "-", "-", "-" };
+      unsigned char *WriteCacheStatus[] = { "Write Cache Disabled",
+					    "Logical Device Read Only",
+					    "Write Cache Enabled",
+					    "Intelligent Write Cache Enabled",
+					    "-", "-", "-", "-" };
+      unsigned char *GeometryTranslation;
+      if (LogicalDeviceInfo == NULL) continue;
+      switch(LogicalDeviceInfo->DriveGeometry)
+	{
+	case DAC960_V2_Geometry_128_32:
+	  GeometryTranslation = "128/32";
+	  break;
+	case DAC960_V2_Geometry_255_63:
+	  GeometryTranslation = "255/63";
+	  break;
+	default:
+	  GeometryTranslation = "Invalid";
+	  DAC960_Error("Illegal Logical Device Geometry %d\n",
+		       Controller, LogicalDeviceInfo->DriveGeometry);
+	  break;
+	}
+      DAC960_Info("    /dev/rd/c%dd%d: RAID-%d, %s, %d blocks\n",
+		  Controller, Controller->ControllerNumber, LogicalDriveNumber,
+		  LogicalDeviceInfo->RAIDLevel,
+		  (LogicalDeviceInfo->LogicalDeviceState
+		   == DAC960_V2_LogicalDevice_Online
+		   ? "Online"
+		   : LogicalDeviceInfo->LogicalDeviceState
+		     == DAC960_V2_LogicalDevice_Critical
+		     ? "Critical" : "Offline"),
+		  LogicalDeviceInfo->ConfigurableDeviceSizeIn512ByteBlocksOrMB);
+      DAC960_Info("                  Logical Device %s, BIOS Geometry: %s\n",
+		  Controller,
+		  (LogicalDeviceInfo->LogicalDeviceControl
+				     .LogicalDeviceInitialized
+		   ? "Initialized" : "Uninitialized"),
+		  GeometryTranslation);
+      if (LogicalDeviceInfo->StripeSize == 0)
+	{
+	  if (LogicalDeviceInfo->CacheLineSize == 0)
+	    DAC960_Info("                  Stripe Size: N/A, "
+			"Segment Size: N/A\n", Controller);
+	  else
+	    DAC960_Info("                  Stripe Size: N/A, "
+			"Segment Size: %dKB\n", Controller,
+			1 << (LogicalDeviceInfo->CacheLineSize - 2));
+	}
+      else
+	{
+	  if (LogicalDeviceInfo->CacheLineSize == 0)
+	    DAC960_Info("                  Stripe Size: %dKB, "
+			"Segment Size: N/A\n", Controller,
+			1 << (LogicalDeviceInfo->StripeSize - 2));
+	  else
+	    DAC960_Info("                  Stripe Size: %dKB, "
+			"Segment Size: %dKB\n", Controller,
+			1 << (LogicalDeviceInfo->StripeSize - 2),
+			1 << (LogicalDeviceInfo->CacheLineSize - 2));
+	}
+      DAC960_Info("                  %s, %s\n", Controller,
+		  ReadCacheStatus[
+		    LogicalDeviceInfo->LogicalDeviceControl.ReadCache],
+		  WriteCacheStatus[
+		    LogicalDeviceInfo->LogicalDeviceControl.WriteCache]);
+      if (LogicalDeviceInfo->SoftErrors > 0 ||
+	  LogicalDeviceInfo->CommandsFailed > 0 ||
+	  LogicalDeviceInfo->DeferredWriteErrors)
+	DAC960_Info("                  Errors - Soft: %d, Failed: %d, "
+		    "Deferred Write: %d\n", Controller,
+		    LogicalDeviceInfo->SoftErrors,
+		    LogicalDeviceInfo->CommandsFailed,
+		    LogicalDeviceInfo->DeferredWriteErrors);
+
+    }
+  return true;
+}
+
+
+/*
   DAC960_RegisterBlockDevice registers the Block Device structures
   associated with Controller.
 */
@@ -1167,7 +1857,7 @@
       Controller->MaxSectorsPerRequest[MinorNumber] =
 	Controller->MaxBlocksPerCommand;
       Controller->MaxSegmentsPerRequest[MinorNumber] =
-	Controller->MaxScatterGatherSegments;
+	Controller->DriverScatterGatherLimit;
     }
   Controller->GenericDiskInfo.part = Controller->DiskPartitions;
   Controller->GenericDiskInfo.sizes = Controller->PartitionSizes;
@@ -1250,37 +1940,485 @@
 
 
 /*
-  DAC960_InitializeController initializes Controller.
+  DAC960_GenericDiskInit is the Generic Disk Information Initialization
+  Function for the DAC960 Driver.
 */
 
-static void DAC960_InitializeController(DAC960_Controller_T *Controller)
+static void DAC960_InitializeGenericDiskInfo(GenericDiskInfo_T *GenericDiskInfo)
 {
-  if (DAC960_ReadControllerConfiguration(Controller) &&
-      DAC960_ReportControllerConfiguration(Controller) &&
-      DAC960_ReadDeviceConfiguration(Controller) &&
-      DAC960_ReportDeviceConfiguration(Controller) &&
-      DAC960_RegisterBlockDevice(Controller))
-    {
-      /*
-	Initialize the Command structures.
-      */
-      DAC960_Command_T *Commands = Controller->Commands;
-      int CommandIdentifier;
-      Controller->FreeCommands = NULL;
-      for (CommandIdentifier = 0;
-	   CommandIdentifier < Controller->DriverQueueDepth;
-	   CommandIdentifier++)
-	{
-	  Commands[CommandIdentifier].Controller = Controller;
-	  Commands[CommandIdentifier].Next = Controller->FreeCommands;
-	  Controller->FreeCommands = &Commands[CommandIdentifier];
-	}
-      /*
-	Initialize the Monitoring Timer.
-      */
-      init_timer(&Controller->MonitoringTimer);
-      Controller->MonitoringTimer.expires =
-	jiffies + DAC960_MonitoringTimerInterval;
+  DAC960_Controller_T *Controller =
+    (DAC960_Controller_T *) GenericDiskInfo->real_devices;
+  int LogicalDriveNumber;
+  if (Controller->FirmwareType == DAC960_V1_Controller)
+    for (LogicalDriveNumber = 0;
+	 LogicalDriveNumber < Controller->LogicalDriveCount;
+	 LogicalDriveNumber++)
+      GenericDiskInfo->part[DAC960_MinorNumber(LogicalDriveNumber, 0)]
+		      .nr_sects =
+	Controller->V1.LogicalDriveInformation
+		       [LogicalDriveNumber].LogicalDriveSize;
+  else
+    for (LogicalDriveNumber = 0;
+	 LogicalDriveNumber < DAC960_MaxLogicalDrives;
+	 LogicalDriveNumber++)
+      {
+	DAC960_V2_LogicalDeviceInfo_T *LogicalDeviceInfo =
+	  Controller->V2.LogicalDeviceInformation[LogicalDriveNumber];
+	if (LogicalDeviceInfo != NULL)
+	  GenericDiskInfo->part[DAC960_MinorNumber(LogicalDriveNumber, 0)]
+			  .nr_sects =
+	    LogicalDeviceInfo->ConfigurableDeviceSizeIn512ByteBlocksOrMB;
+      }
+}
+
+
+/*
+  DAC960_ReportErrorStatus reports Controller BIOS Messages passed through
+  the Error Status Register when the driver performs the BIOS handshaking.
+  It returns true for fatal errors and false otherwise.
+*/
+
+static boolean DAC960_ReportErrorStatus(DAC960_Controller_T *Controller,
+					unsigned char ErrorStatus,
+					unsigned char Parameter0,
+					unsigned char Parameter1)
+{
+  switch (ErrorStatus)
+    {
+    case 0x00:
+      DAC960_Notice("Physical Device %d:%d Not Responding\n",
+		    Controller, Parameter1, Parameter0);
+      break;
+    case 0x08:
+      if (Controller->DriveSpinUpMessageDisplayed) break;
+      DAC960_Notice("Spinning Up Drives\n", Controller);
+      Controller->DriveSpinUpMessageDisplayed = true;
+      break;
+    case 0x30:
+      DAC960_Notice("Configuration Checksum Error\n", Controller);
+      break;
+    case 0x60:
+      DAC960_Notice("Mirror Race Recovery Failed\n", Controller);
+      break;
+    case 0x70:
+      DAC960_Notice("Mirror Race Recovery In Progress\n", Controller);
+      break;
+    case 0x90:
+      DAC960_Notice("Physical Device %d:%d COD Mismatch\n",
+		    Controller, Parameter1, Parameter0);
+      break;
+    case 0xA0:
+      DAC960_Notice("Logical Drive Installation Aborted\n", Controller);
+      break;
+    case 0xB0:
+      DAC960_Notice("Mirror Race On A Critical Logical Drive\n", Controller);
+      break;
+    case 0xD0:
+      DAC960_Notice("New Controller Configuration Found\n", Controller);
+      break;
+    case 0xF0:
+      DAC960_Error("Fatal Memory Parity Error for Controller at\n", Controller);
+      return true;
+    default:
+      DAC960_Error("Unknown Initialization Error %02X for Controller at\n",
+		   Controller, ErrorStatus);
+      return true;
+    }
+  return false;
+}
+
+
+/*
+  DAC960_DetectControllers detects Mylex DAC960/AcceleRAID/eXtremeRAID
+  PCI RAID Controllers by interrogating the PCI Configuration Space for
+  Controller Type.
+*/
+
+static void DAC960_DetectControllers(DAC960_HardwareType_T HardwareType)
+{
+  void (*InterruptHandler)(int, void *, Registers_T *) = NULL;
+  DAC960_FirmwareType_T FirmwareType = 0;
+  unsigned short VendorID = 0, DeviceID = 0;
+  unsigned int MemoryWindowSize = 0;
+  PCI_Device_T *PCI_Device = NULL;
+  switch (HardwareType)
+    {
+    case DAC960_BA_Controller:
+      VendorID = PCI_VENDOR_ID_MYLEX;
+      DeviceID = PCI_DEVICE_ID_MYLEX_DAC960_BA;
+      FirmwareType = DAC960_V2_Controller;
+      InterruptHandler = DAC960_BA_InterruptHandler;
+      MemoryWindowSize = DAC960_BA_RegisterWindowSize;
+      break;
+    case DAC960_LP_Controller:
+      VendorID = PCI_VENDOR_ID_MYLEX;
+      DeviceID = PCI_DEVICE_ID_MYLEX_DAC960_LP;
+      FirmwareType = DAC960_LP_Controller;
+      InterruptHandler = DAC960_LP_InterruptHandler;
+      MemoryWindowSize = DAC960_LP_RegisterWindowSize;
+      break;
+    case DAC960_LA_Controller:
+      VendorID = PCI_VENDOR_ID_DEC;
+      DeviceID = PCI_DEVICE_ID_DEC_21285;
+      FirmwareType = DAC960_V1_Controller;
+      InterruptHandler = DAC960_LA_InterruptHandler;
+      MemoryWindowSize = DAC960_LA_RegisterWindowSize;
+      break;
+    case DAC960_PG_Controller:
+      VendorID = PCI_VENDOR_ID_MYLEX;
+      DeviceID = PCI_DEVICE_ID_MYLEX_DAC960_PG;
+      FirmwareType = DAC960_V1_Controller;
+      InterruptHandler = DAC960_PG_InterruptHandler;
+      MemoryWindowSize = DAC960_PG_RegisterWindowSize;
+      break;
+    case DAC960_PD_Controller:
+      VendorID = PCI_VENDOR_ID_MYLEX;
+      DeviceID = PCI_DEVICE_ID_MYLEX_DAC960_PD;
+      FirmwareType = DAC960_V1_Controller;
+      InterruptHandler = DAC960_PD_InterruptHandler;
+      MemoryWindowSize = DAC960_PD_RegisterWindowSize;
+      break;
+    }
+  while ((PCI_Device = pci_find_device(VendorID, DeviceID, PCI_Device)) != NULL)
+    {
+      DAC960_Controller_T *Controller = NULL;
+      DAC960_IO_Address_T IO_Address = 0;
+      DAC960_PCI_Address_T PCI_Address = 0;
+      unsigned char Bus = PCI_Device->bus->number;
+      unsigned char DeviceFunction = PCI_Device->devfn;
+      unsigned char Device = DeviceFunction >> 3;
+      unsigned char Function = DeviceFunction & 0x7;
+      unsigned char ErrorStatus, Parameter0, Parameter1;
+      unsigned int IRQ_Channel = PCI_Device->irq;
+      unsigned long BaseAddress0 = PCI_Device->base_address[0];
+      unsigned long BaseAddress1 = PCI_Device->base_address[1];
+      unsigned short SubsystemVendorID, SubsystemDeviceID;
+      void *BaseAddress;
+      pci_read_config_word(PCI_Device, PCI_SUBSYSTEM_VENDOR_ID,
+			   &SubsystemVendorID);
+      pci_read_config_word(PCI_Device, PCI_SUBSYSTEM_ID,
+			   &SubsystemDeviceID);
+      switch (HardwareType)
+	{
+	case DAC960_BA_Controller:
+	  PCI_Address = BaseAddress0 & PCI_BASE_ADDRESS_MEM_MASK;
+	  break;
+	case DAC960_LP_Controller:
+	  PCI_Address = BaseAddress0 & PCI_BASE_ADDRESS_MEM_MASK;
+	  break;
+	case DAC960_LA_Controller:
+	  if (!(SubsystemVendorID == PCI_VENDOR_ID_MYLEX &&
+		SubsystemDeviceID == PCI_DEVICE_ID_MYLEX_DAC960_LA))
+	    continue;
+	  PCI_Address = BaseAddress0 & PCI_BASE_ADDRESS_MEM_MASK;
+	  break;
+	case DAC960_PG_Controller:
+	  PCI_Address = BaseAddress0 & PCI_BASE_ADDRESS_MEM_MASK;
+	  break;
+	case DAC960_PD_Controller:
+	  IO_Address = BaseAddress0 & PCI_BASE_ADDRESS_IO_MASK;
+	  PCI_Address = BaseAddress1 & PCI_BASE_ADDRESS_MEM_MASK;
+	  break;
+	}
+      if (DAC960_ControllerCount == DAC960_MaxControllers)
+	{
+	  DAC960_Error("More than %d DAC960 Controllers detected - "
+		       "ignoring from Controller at\n",
+		       NULL, DAC960_MaxControllers);
+	  goto Failure;
+	}
+      Controller = (DAC960_Controller_T *)
+	kmalloc(sizeof(DAC960_Controller_T), GFP_ATOMIC);
+      if (Controller == NULL)
+	{
+	  DAC960_Error("Unable to allocate Controller structure for "
+		       "Controller at\n", NULL);
+	  goto Failure;
+	}
+      memset(Controller, 0, sizeof(DAC960_Controller_T));
+      Controller->ControllerNumber = DAC960_ControllerCount;
+      DAC960_Controllers[DAC960_ControllerCount++] = Controller;
+      DAC960_AnnounceDriver(Controller);
+      Controller->FirmwareType = FirmwareType;
+      Controller->HardwareType = HardwareType;
+      Controller->IO_Address = IO_Address;
+      Controller->PCI_Address = PCI_Address;
+      Controller->Bus = Bus;
+      Controller->Device = Device;
+      Controller->Function = Function;
+      sprintf(Controller->ControllerName, "c%d", Controller->ControllerNumber);
+      /*
+	Map the Controller Register Window.
+      */
+      if (MemoryWindowSize < PAGE_SIZE)
+	MemoryWindowSize = PAGE_SIZE;
+      Controller->MemoryMappedAddress =
+	ioremap_nocache(PCI_Address & PAGE_MASK, MemoryWindowSize);
+      Controller->BaseAddress =
+	Controller->MemoryMappedAddress + (PCI_Address & ~PAGE_MASK);
+      if (Controller->MemoryMappedAddress == NULL)
+	{
+	  DAC960_Error("Unable to map Controller Register Window for "
+		       "Controller at\n", Controller);
+	  goto Failure;
+	}
+      BaseAddress = Controller->BaseAddress;
+      switch (HardwareType)
+	{
+	case DAC960_BA_Controller:
+	  DAC960_BA_DisableInterrupts(Controller->BaseAddress);
+	  DAC960_BA_AcknowledgeHardwareMailboxStatus(BaseAddress);
+	  udelay(1000);
+	  while (DAC960_BA_InitializationInProgressP(BaseAddress))
+	    {
+	      if (DAC960_BA_ReadErrorStatus(BaseAddress, &ErrorStatus,
+					    &Parameter0, &Parameter1) &&
+		  DAC960_ReportErrorStatus(Controller, ErrorStatus,
+					   Parameter0, Parameter1))
+		goto Failure;
+	      udelay(10);
+	    }
+	  if (!DAC960_V2_EnableMemoryMailboxInterface(Controller))
+	    {
+	      DAC960_Error("Unable to Enable Memory Mailbox Interface "
+			   "for Controller at\n", Controller);
+	      goto Failure;
+	    }
+	  DAC960_BA_EnableInterrupts(Controller->BaseAddress);
+	  Controller->QueueCommand = DAC960_BA_QueueCommand;
+	  Controller->ReadControllerConfiguration =
+	    DAC960_V2_ReadControllerConfiguration;
+	  Controller->ReadDeviceConfiguration =
+	    DAC960_V2_ReadDeviceConfiguration;
+	  Controller->ReportDeviceConfiguration =
+	    DAC960_V2_ReportDeviceConfiguration;
+	  Controller->QueueReadWriteCommand =
+	    DAC960_V2_QueueReadWriteCommand;
+	  break;
+	case DAC960_LP_Controller:
+	  DAC960_LP_DisableInterrupts(Controller->BaseAddress);
+	  DAC960_LP_AcknowledgeHardwareMailboxStatus(BaseAddress);
+	  udelay(1000);
+	  while (DAC960_LP_InitializationInProgressP(BaseAddress))
+	    {
+	      if (DAC960_LP_ReadErrorStatus(BaseAddress, &ErrorStatus,
+					    &Parameter0, &Parameter1) &&
+		  DAC960_ReportErrorStatus(Controller, ErrorStatus,
+					   Parameter0, Parameter1))
+		goto Failure;
+	      udelay(10);
+	    }
+	  if (!DAC960_V2_EnableMemoryMailboxInterface(Controller))
+	    {
+	      DAC960_Error("Unable to Enable Memory Mailbox Interface "
+			   "for Controller at\n", Controller);
+	      goto Failure;
+	    }
+	  DAC960_LP_EnableInterrupts(Controller->BaseAddress);
+	  Controller->QueueCommand = DAC960_LP_QueueCommand;
+	  Controller->ReadControllerConfiguration =
+	    DAC960_V2_ReadControllerConfiguration;
+	  Controller->ReadDeviceConfiguration =
+	    DAC960_V2_ReadDeviceConfiguration;
+	  Controller->ReportDeviceConfiguration =
+	    DAC960_V2_ReportDeviceConfiguration;
+	  Controller->QueueReadWriteCommand =
+	    DAC960_V2_QueueReadWriteCommand;
+	  break;
+	case DAC960_LA_Controller:
+	  DAC960_LA_DisableInterrupts(Controller->BaseAddress);
+	  DAC960_LA_AcknowledgeHardwareMailboxStatus(BaseAddress);
+	  udelay(1000);
+	  while (DAC960_LA_InitializationInProgressP(BaseAddress))
+	    {
+	      if (DAC960_LA_ReadErrorStatus(BaseAddress, &ErrorStatus,
+					    &Parameter0, &Parameter1) &&
+		  DAC960_ReportErrorStatus(Controller, ErrorStatus,
+					   Parameter0, Parameter1))
+		goto Failure;
+	      udelay(10);
+	    }
+	  if (!DAC960_V1_EnableMemoryMailboxInterface(Controller))
+	    {
+	      DAC960_Error("Unable to Enable Memory Mailbox Interface "
+			   "for Controller at\n", Controller);
+	      goto Failure;
+	    }
+	  DAC960_LA_EnableInterrupts(Controller->BaseAddress);
+	  if (Controller->V1.DualModeMemoryMailboxInterface)
+	    Controller->QueueCommand = DAC960_LA_QueueCommandDualMode;
+	  else Controller->QueueCommand = DAC960_LA_QueueCommandSingleMode;
+	  Controller->ReadControllerConfiguration =
+	    DAC960_V1_ReadControllerConfiguration;
+	  Controller->ReadDeviceConfiguration =
+	    DAC960_V1_ReadDeviceConfiguration;
+	  Controller->ReportDeviceConfiguration =
+	    DAC960_V1_ReportDeviceConfiguration;
+	  Controller->QueueReadWriteCommand =
+	    DAC960_V1_QueueReadWriteCommand;
+	  break;
+	case DAC960_PG_Controller:
+	  DAC960_PG_DisableInterrupts(Controller->BaseAddress);
+	  DAC960_PG_AcknowledgeHardwareMailboxStatus(BaseAddress);
+	  udelay(1000);
+	  while (DAC960_PG_InitializationInProgressP(BaseAddress))
+	    {
+	      if (DAC960_PG_ReadErrorStatus(BaseAddress, &ErrorStatus,
+					    &Parameter0, &Parameter1) &&
+		  DAC960_ReportErrorStatus(Controller, ErrorStatus,
+					   Parameter0, Parameter1))
+		goto Failure;
+	      udelay(10);
+	    }
+	  if (!DAC960_V1_EnableMemoryMailboxInterface(Controller))
+	    {
+	      DAC960_Error("Unable to Enable Memory Mailbox Interface "
+			   "for Controller at\n", Controller);
+	      goto Failure;
+	    }
+	  DAC960_PG_EnableInterrupts(Controller->BaseAddress);
+	  if (Controller->V1.DualModeMemoryMailboxInterface)
+	    Controller->QueueCommand = DAC960_PG_QueueCommandDualMode;
+	  else Controller->QueueCommand = DAC960_PG_QueueCommandSingleMode;
+	  Controller->ReadControllerConfiguration =
+	    DAC960_V1_ReadControllerConfiguration;
+	  Controller->ReadDeviceConfiguration =
+	    DAC960_V1_ReadDeviceConfiguration;
+	  Controller->ReportDeviceConfiguration =
+	    DAC960_V1_ReportDeviceConfiguration;
+	  Controller->QueueReadWriteCommand =
+	    DAC960_V1_QueueReadWriteCommand;
+	  break;
+	case DAC960_PD_Controller:
+	  request_region(Controller->IO_Address, 0x80,
+			 Controller->FullModelName);
+	  DAC960_PD_DisableInterrupts(BaseAddress);
+	  DAC960_PD_AcknowledgeStatus(BaseAddress);
+	  udelay(1000);
+	  while (DAC960_PD_InitializationInProgressP(BaseAddress))
+	    {
+	      if (DAC960_PD_ReadErrorStatus(BaseAddress, &ErrorStatus,
+					    &Parameter0, &Parameter1) &&
+		  DAC960_ReportErrorStatus(Controller, ErrorStatus,
+					   Parameter0, Parameter1))
+		goto Failure;
+	      udelay(10);
+	    }
+	  DAC960_PD_EnableInterrupts(Controller->BaseAddress);
+	  Controller->QueueCommand = DAC960_PD_QueueCommand;
+	  Controller->ReadControllerConfiguration =
+	    DAC960_V1_ReadControllerConfiguration;
+	  Controller->ReadDeviceConfiguration =
+	    DAC960_V1_ReadDeviceConfiguration;
+	  Controller->ReportDeviceConfiguration =
+	    DAC960_V1_ReportDeviceConfiguration;
+	  Controller->QueueReadWriteCommand =
+	    DAC960_V1_QueueReadWriteCommand;
+	  break;
+	}
+      /*
+	Acquire shared access to the IRQ Channel.
+      */
+      if (IRQ_Channel == 0)
+	{
+	  DAC960_Error("IRQ Channel %d illegal for Controller at\n",
+		       Controller, IRQ_Channel);
+	  goto Failure;
+	}
+      strcpy(Controller->FullModelName, "DAC960");
+      if (request_irq(IRQ_Channel, InterruptHandler, SA_SHIRQ,
+		      Controller->FullModelName, Controller) < 0)
+	{
+	  DAC960_Error("Unable to acquire IRQ Channel %d for Controller at\n",
+		       Controller, IRQ_Channel);
+	  goto Failure;
+	}
+      Controller->IRQ_Channel = IRQ_Channel;
+      DAC960_ActiveControllerCount++;
+      Controller->InitialCommand.CommandIdentifier = 1;
+      Controller->InitialCommand.Controller = Controller;
+      Controller->Commands[0] = &Controller->InitialCommand;
+      Controller->FreeCommands = &Controller->InitialCommand;
+      Controller->ControllerDetectionSuccessful = true;
+      continue;
+    Failure:
+      if (IO_Address == 0)
+	DAC960_Error("PCI Bus %d Device %d Function %d I/O Address N/A "
+		     "PCI Address 0x%X\n", Controller,
+		     Bus, Device, Function, PCI_Address);
+      else DAC960_Error("PCI Bus %d Device %d Function %d I/O Address "
+			"0x%X PCI Address 0x%X\n", Controller,
+			Bus, Device, Function, IO_Address, PCI_Address);
+      if (Controller == NULL) break;
+      if (Controller->MemoryMappedAddress != NULL)
+	iounmap(Controller->MemoryMappedAddress);
+      if (Controller->IRQ_Channel > 0)
+	free_irq(IRQ_Channel, Controller);
+    }
+}
+
+
+/*
+  DAC960_SortControllers sorts the Controllers by PCI Bus and Device Number.
+*/
+
+static void DAC960_SortControllers(void)
+{
+  int ControllerNumber, LastInterchange, Bound, j;
+  LastInterchange = DAC960_ControllerCount-1;
+  while (LastInterchange > 0)
+    {
+      Bound = LastInterchange;
+      LastInterchange = 0;
+      for (j = 0; j < Bound; j++)
+	{
+	  DAC960_Controller_T *Controller1 = DAC960_Controllers[j];
+	  DAC960_Controller_T *Controller2 = DAC960_Controllers[j+1];
+	  if (Controller1->Bus > Controller2->Bus ||
+	      (Controller1->Bus == Controller2->Bus &&
+	       (Controller1->Device > Controller2->Device)))
+	    {
+	      Controller2->ControllerNumber = j;
+	      DAC960_Controllers[j] = Controller2;
+	      Controller1->ControllerNumber = j+1;
+	      DAC960_Controllers[j+1] = Controller1;
+	      LastInterchange = j;
+	    }
+	}
+    }
+  for (ControllerNumber = 0;
+       ControllerNumber < DAC960_ControllerCount;
+       ControllerNumber++)
+    {
+      DAC960_Controller_T *Controller = DAC960_Controllers[ControllerNumber];
+      if (!Controller->ControllerDetectionSuccessful)
+	{
+	  DAC960_Controllers[ControllerNumber] = NULL;
+	  kfree(Controller);
+	}
+    }
+}
+
+
+/*
+  DAC960_InitializeController initializes Controller.
+*/
+
+static void DAC960_InitializeController(DAC960_Controller_T *Controller)
+{
+  if (DAC960_ReadControllerConfiguration(Controller) &&
+      DAC960_ReportControllerConfiguration(Controller) &&
+      DAC960_CreateAuxiliaryStructures(Controller) &&
+      DAC960_ReadDeviceConfiguration(Controller) &&
+      DAC960_ReportDeviceConfiguration(Controller) &&
+      DAC960_RegisterBlockDevice(Controller))
+    {
+      /*
+	Initialize the Monitoring Timer.
+      */
+      init_timer(&Controller->MonitoringTimer);
+      Controller->MonitoringTimer.expires =
+	jiffies + DAC960_MonitoringTimerInterval;
       Controller->MonitoringTimer.data = (unsigned long) Controller;
       Controller->MonitoringTimer.function = DAC960_MonitoringTimerFunction;
       add_timer(&Controller->MonitoringTimer);
@@ -1299,28 +2437,46 @@
   if (Controller->ControllerInitialized)
     {
       del_timer(&Controller->MonitoringTimer);
-      DAC960_Notice("Flushing Cache...", Controller);
-      DAC960_ExecuteType3(Controller, DAC960_Flush, NULL);
-      DAC960_Notice("done\n", Controller);
-      switch (Controller->ControllerType)
-	{
-	case DAC960_V5_Controller:
-	  if (!Controller->DualModeMemoryMailboxInterface)
-	    DAC960_V5_SaveMemoryMailboxInfo(Controller);
-	  break;
-	case DAC960_V4_Controller:
-	  if (!Controller->DualModeMemoryMailboxInterface)
-	    DAC960_V4_SaveMemoryMailboxInfo(Controller);
-	  break;
-	case DAC960_V3_Controller:
-	  break;
+      if (Controller->FirmwareType == DAC960_V1_Controller)
+	{
+	  DAC960_Notice("Flushing Cache...", Controller);
+	  DAC960_V1_ExecuteType3(Controller, DAC960_V1_Flush, NULL);
+	  DAC960_Notice("done\n", Controller);
+	  switch (Controller->HardwareType)
+	    {
+	    case DAC960_LA_Controller:
+	      if (Controller->V1.DualModeMemoryMailboxInterface)
+		free_pages(Controller->MemoryMailboxPagesAddress,
+			   Controller->MemoryMailboxPagesOrder);
+	      else DAC960_LA_SaveMemoryMailboxInfo(Controller);
+	      break;
+	    case DAC960_PG_Controller:
+	      if (Controller->V1.DualModeMemoryMailboxInterface)
+		free_pages(Controller->MemoryMailboxPagesAddress,
+			   Controller->MemoryMailboxPagesOrder);
+	      else DAC960_PG_SaveMemoryMailboxInfo(Controller);
+	      break;
+	    case DAC960_PD_Controller:
+	      release_region(Controller->IO_Address, 0x80);
+	      break;
+	    default:
+	      break;
+	    }
 	}
+      else
+	{
+	  DAC960_Notice("Flushing Cache...", Controller);
+	  DAC960_V2_DeviceOperation(Controller, DAC960_V2_PauseDevice,
+				    DAC960_V2_RAID_Controller);
+	  DAC960_Notice("done\n", Controller);
+	  free_pages(Controller->MemoryMailboxPagesAddress,
+		     Controller->MemoryMailboxPagesOrder);
+	}
     }
   free_irq(Controller->IRQ_Channel, Controller);
   iounmap(Controller->MemoryMappedAddress);
-  if (Controller->IO_Address > 0)
-    release_region(Controller->IO_Address, 0x80);
   DAC960_UnregisterBlockDevice(Controller);
+  DAC960_DestroyAuxiliaryStructures(Controller);
   DAC960_Controllers[Controller->ControllerNumber] = NULL;
   kfree(Controller);
 }
@@ -1333,9 +2489,12 @@
 void DAC960_Initialize(void)
 {
   int ControllerNumber;
-  DAC960_DetectControllers(DAC960_V5_Controller);
-  DAC960_DetectControllers(DAC960_V4_Controller);
-  DAC960_DetectControllers(DAC960_V3_Controller);
+  DAC960_DetectControllers(DAC960_BA_Controller);
+  DAC960_DetectControllers(DAC960_LP_Controller);
+  DAC960_DetectControllers(DAC960_LA_Controller);
+  DAC960_DetectControllers(DAC960_PG_Controller);
+  DAC960_DetectControllers(DAC960_PD_Controller);
+  DAC960_SortControllers();
   if (DAC960_ActiveControllerCount == 0) return;
   for (ControllerNumber = 0;
        ControllerNumber < DAC960_ControllerCount;
@@ -1371,68 +2530,38 @@
 
 
 /*
-  DAC960_ProcessRequest attempts to remove one I/O Request from Controller's
-  I/O Request Queue and queues it to the Controller.  WaitForCommand is true if
-  this function should wait for a Command to become available if necessary.
-  This function returns true if an I/O Request was queued and false otherwise.
+  DAC960_V1_QueueReadWriteCommand prepares and queues a Read/Write Command for
+  DAC960 V1 Firmware Controllers.
 */
 
-static boolean DAC960_ProcessRequest(DAC960_Controller_T *Controller,
-				     boolean WaitForCommand)
+static void DAC960_V1_QueueReadWriteCommand(DAC960_Command_T *Command)
 {
-  IO_Request_T **RequestQueuePointer =
-    &blk_dev[DAC960_MAJOR + Controller->ControllerNumber].current_request;
-  IO_Request_T *Request;
-  DAC960_Command_T *Command;
-  char *RequestBuffer;
-  while (true)
-    {
-      Request = *RequestQueuePointer;
-      if (Request == NULL || Request->rq_status == RQ_INACTIVE) return false;
-      Command = DAC960_AllocateCommand(Controller);
-      if (Command != NULL) break;
-      if (!WaitForCommand) return false;
-      DAC960_WaitForCommand(Controller);
-    }
-  DAC960_ClearCommand(Command);
-  if (Request->cmd == READ)
-    Command->CommandType = DAC960_ReadCommand;
-  else Command->CommandType = DAC960_WriteCommand;
-  Command->Semaphore = Request->sem;
-  Command->LogicalDriveNumber = DAC960_LogicalDriveNumber(Request->rq_dev);
-  Command->BlockNumber =
-    Request->sector
-    + Controller->GenericDiskInfo.part[MINOR(Request->rq_dev)].start_sect;
-  Command->BlockCount = Request->nr_sectors;
-  Command->SegmentCount = Request->nr_segments;
-  Command->BufferHeader = Request->bh;
-  RequestBuffer = Request->buffer;
-  Request->rq_status = RQ_INACTIVE;
-  *RequestQueuePointer = Request->next;
-  wake_up(&wait_for_request);
+  DAC960_Controller_T *Controller = Command->Controller;
+  DAC960_V1_CommandMailbox_T *CommandMailbox = &Command->V1.CommandMailbox;
+  DAC960_V1_ClearCommand(Command);
   if (Command->SegmentCount == 1)
     {
-      DAC960_CommandMailbox_T *CommandMailbox = &Command->CommandMailbox;
       if (Command->CommandType == DAC960_ReadCommand)
-	CommandMailbox->Type5.CommandOpcode = DAC960_Read;
-      else CommandMailbox->Type5.CommandOpcode = DAC960_Write;
+	CommandMailbox->Type5.CommandOpcode = DAC960_V1_Read;
+      else CommandMailbox->Type5.CommandOpcode = DAC960_V1_Write;
       CommandMailbox->Type5.LD.TransferLength = Command->BlockCount;
       CommandMailbox->Type5.LD.LogicalDriveNumber = Command->LogicalDriveNumber;
       CommandMailbox->Type5.LogicalBlockAddress = Command->BlockNumber;
-      CommandMailbox->Type5.BusAddress = Virtual_to_Bus(RequestBuffer);
+      CommandMailbox->Type5.BusAddress = Virtual_to_Bus(Command->RequestBuffer);
     }
   else
     {
-      DAC960_CommandMailbox_T *CommandMailbox = &Command->CommandMailbox;
-      DAC960_ScatterGatherSegment_T
-	*ScatterGatherList = Command->ScatterGatherList;
+      DAC960_V1_ScatterGatherSegment_T
+	*ScatterGatherList = Command->V1.ScatterGatherList;
       BufferHeader_T *BufferHeader = Command->BufferHeader;
       char *LastDataEndPointer = NULL;
       int SegmentNumber = 0;
       if (Command->CommandType == DAC960_ReadCommand)
-	CommandMailbox->Type5.CommandOpcode = DAC960_ReadWithOldScatterGather;
+	CommandMailbox->Type5.CommandOpcode =
+	  DAC960_V1_ReadWithOldScatterGather;
       else
-	CommandMailbox->Type5.CommandOpcode = DAC960_WriteWithOldScatterGather;
+	CommandMailbox->Type5.CommandOpcode =
+	  DAC960_V1_WriteWithOldScatterGather;
       CommandMailbox->Type5.LD.TransferLength = Command->BlockCount;
       CommandMailbox->Type5.LD.LogicalDriveNumber = Command->LogicalDriveNumber;
       CommandMailbox->Type5.LogicalBlockAddress = Command->BlockNumber;
@@ -1453,7 +2582,7 @@
 	      ScatterGatherList[SegmentNumber].SegmentByteCount =
 		BufferHeader->b_size;
 	      LastDataEndPointer = BufferHeader->b_data + BufferHeader->b_size;
-	      if (SegmentNumber++ > Controller->MaxScatterGatherSegments)
+	      if (SegmentNumber++ > Controller->DriverScatterGatherLimit)
 		panic("DAC960: Scatter/Gather Segment Overflow\n");
 	    }
 	  BufferHeader = BufferHeader->b_reqnext;
@@ -1462,6 +2591,138 @@
 	panic("DAC960: SegmentNumber != SegmentCount\n");
     }
   DAC960_QueueCommand(Command);
+}
+
+
+/*
+  DAC960_V2_QueueReadWriteCommand prepares and queues a Read/Write Command for
+  DAC960 V2 Firmware Controllers.
+*/
+
+static void DAC960_V2_QueueReadWriteCommand(DAC960_Command_T *Command)
+{
+  DAC960_Controller_T *Controller = Command->Controller;
+  DAC960_V2_CommandMailbox_T *CommandMailbox = &Command->V2.CommandMailbox;
+  DAC960_V2_ClearCommand(Command);
+  CommandMailbox->SCSI_10.CommandOpcode = DAC960_V2_SCSI_10;
+  CommandMailbox->SCSI_10.CommandControlBits.DataTransferControllerToHost =
+    (Command->CommandType == DAC960_ReadCommand);
+  CommandMailbox->SCSI_10.DataTransferSize =
+    Command->BlockCount << DAC960_BlockSizeBits;
+  CommandMailbox->SCSI_10.RequestSenseBusAddress =
+    Virtual_to_Bus(&Command->V2.RequestSense);
+  CommandMailbox->SCSI_10.PhysicalDevice =
+    Controller->V2.LogicalDriveToVirtualDevice[Command->LogicalDriveNumber];
+  CommandMailbox->SCSI_10.RequestSenseSize =
+    sizeof(DAC960_SCSI_RequestSense_T);
+  CommandMailbox->SCSI_10.CDBLength = 10;
+  CommandMailbox->SCSI_10.SCSI_CDB[0] =
+    (Command->CommandType == DAC960_ReadCommand ? 0x28 : 0x2A);
+  CommandMailbox->SCSI_10.SCSI_CDB[2] = Command->BlockNumber >> 24;
+  CommandMailbox->SCSI_10.SCSI_CDB[3] = Command->BlockNumber >> 16;
+  CommandMailbox->SCSI_10.SCSI_CDB[4] = Command->BlockNumber >> 8;
+  CommandMailbox->SCSI_10.SCSI_CDB[5] = Command->BlockNumber;
+  CommandMailbox->SCSI_10.SCSI_CDB[7] = Command->BlockCount >> 8;
+  CommandMailbox->SCSI_10.SCSI_CDB[8] = Command->BlockCount;
+  if (Command->SegmentCount == 1)
+    {
+      CommandMailbox->SCSI_10.DataTransferMemoryAddress
+			     .ScatterGatherSegments[0]
+			     .SegmentDataPointer =
+	Virtual_to_Bus(Command->RequestBuffer);
+      CommandMailbox->SCSI_10.DataTransferMemoryAddress
+			     .ScatterGatherSegments[0]
+			     .SegmentByteCount =
+	CommandMailbox->SCSI_10.DataTransferSize;
+    }
+  else
+    {
+      DAC960_V2_ScatterGatherSegment_T
+	*ScatterGatherList = Command->V2.ScatterGatherList;
+      BufferHeader_T *BufferHeader = Command->BufferHeader;
+      char *LastDataEndPointer = NULL;
+      int SegmentNumber = 0;
+      if (Command->SegmentCount > 2)
+	{
+	  CommandMailbox->SCSI_10.CommandControlBits
+			 .AdditionalScatterGatherListMemory = true;
+	  CommandMailbox->SCSI_10.DataTransferMemoryAddress
+			 .ExtendedScatterGather.ScatterGatherList0Length =
+	    Command->SegmentCount;
+	  CommandMailbox->SCSI_10.DataTransferMemoryAddress
+			 .ExtendedScatterGather.ScatterGatherList0Address =
+	    Virtual_to_Bus(ScatterGatherList);
+	}
+      else
+	ScatterGatherList =
+	  CommandMailbox->SCSI_10.DataTransferMemoryAddress
+				 .ScatterGatherSegments;
+      while (BufferHeader != NULL)
+	{
+	  if (BufferHeader->b_data == LastDataEndPointer)
+	    {
+	      ScatterGatherList[SegmentNumber-1].SegmentByteCount +=
+		BufferHeader->b_size;
+	      LastDataEndPointer += BufferHeader->b_size;
+	    }
+	  else
+	    {
+	      ScatterGatherList[SegmentNumber].SegmentDataPointer =
+		Virtual_to_Bus(BufferHeader->b_data);
+	      ScatterGatherList[SegmentNumber].SegmentByteCount =
+		BufferHeader->b_size;
+	      LastDataEndPointer = BufferHeader->b_data + BufferHeader->b_size;
+	      if (SegmentNumber++ > Controller->DriverScatterGatherLimit)
+		panic("DAC960: Scatter/Gather Segment Overflow\n");
+	    }
+	  BufferHeader = BufferHeader->b_reqnext;
+	}
+      if (SegmentNumber != Command->SegmentCount)
+	panic("DAC960: SegmentNumber != SegmentCount\n");
+    }
+  DAC960_QueueCommand(Command);
+}
+
+
+/*
+  DAC960_ProcessRequest attempts to remove one I/O Request from Controller's
+  I/O Request Queue and queues it to the Controller.  WaitForCommand is true if
+  this function should wait for a Command to become available if necessary.
+  This function returns true if an I/O Request was queued and false otherwise.
+*/
+
+static boolean DAC960_ProcessRequest(DAC960_Controller_T *Controller,
+				     boolean WaitForCommand)
+{
+  IO_Request_T **RequestQueuePointer =
+    &blk_dev[DAC960_MAJOR + Controller->ControllerNumber].current_request;
+  IO_Request_T *Request;
+  DAC960_Command_T *Command;
+  while (true)
+    {
+      Request = *RequestQueuePointer;
+      if (Request == NULL || Request->rq_status == RQ_INACTIVE) return false;
+      Command = DAC960_AllocateCommand(Controller);
+      if (Command != NULL) break;
+      if (!WaitForCommand) return false;
+      DAC960_WaitForCommand(Controller);
+    }
+  if (Request->cmd == READ)
+    Command->CommandType = DAC960_ReadCommand;
+  else Command->CommandType = DAC960_WriteCommand;
+  Command->Semaphore = Request->sem;
+  Command->LogicalDriveNumber = DAC960_LogicalDriveNumber(Request->rq_dev);
+  Command->BlockNumber =
+    Request->sector
+    + Controller->GenericDiskInfo.part[MINOR(Request->rq_dev)].start_sect;
+  Command->BlockCount = Request->nr_sectors;
+  Command->SegmentCount = Request->nr_segments;
+  Command->BufferHeader = Request->bh;
+  Command->RequestBuffer = Request->buffer;
+  Request->rq_status = RQ_INACTIVE;
+  *RequestQueuePointer = Request->next;
+  DAC960_QueueReadWriteCommand(Command);
+  wake_up(&wait_for_request);
   return true;
 }
 
@@ -1662,15 +2923,27 @@
 }
 
 
+/*
+  DAC960_ProcessCompletedBuffer performs completion processing for an
+  individual Buffer.
+*/
+
+static inline void DAC960_ProcessCompletedBuffer(BufferHeader_T *BufferHeader,
+						 boolean SuccessfulIO)
+{
+  BufferHeader->b_end_io(BufferHeader, SuccessfulIO);
+}
+
+
 /*
-  DAC960_ReadWriteError prints an appropriate error message for Command when
-  an error occurs on a Read or Write operation.
+  DAC960_V1_ReadWriteError prints an appropriate error message for Command
+  when an error occurs on a Read or Write operation.
 */
 
-static void DAC960_ReadWriteError(DAC960_Command_T *Command)
+static void DAC960_V1_ReadWriteError(DAC960_Command_T *Command)
 {
   DAC960_Controller_T *Controller = Command->Controller;
-  char *CommandName = "UNKNOWN";
+  unsigned char *CommandName = "UNKNOWN";
   switch (Command->CommandType)
     {
     case DAC960_ReadCommand:
@@ -1686,26 +2959,26 @@
     case DAC960_QueuedCommand:
       break;
     }
-  switch (Command->CommandStatus)
+  switch (Command->V1.CommandStatus)
     {
-    case DAC960_IrrecoverableDataError:
+    case DAC960_V1_IrrecoverableDataError:
       DAC960_Error("Irrecoverable Data Error on %s:\n",
 		   Controller, CommandName);
       break;
-    case DAC960_LogicalDriveNonexistentOrOffline:
+    case DAC960_V1_LogicalDriveNonexistentOrOffline:
       DAC960_Error("Logical Drive Nonexistent or Offline on %s:\n",
 		   Controller, CommandName);
       break;
-    case DAC960_AccessBeyondEndOfLogicalDrive:
+    case DAC960_V1_AccessBeyondEndOfLogicalDrive:
       DAC960_Error("Attempt to Access Beyond End of Logical Drive "
 		   "on %s:\n", Controller, CommandName);
       break;
-    case DAC960_BadDataEncountered:
+    case DAC960_V1_BadDataEncountered:
       DAC960_Error("Bad Data Encountered on %s:\n", Controller, CommandName);
       break;
     default:
       DAC960_Error("Unexpected Error Status %04X on %s:\n",
-		   Controller, Command->CommandStatus, CommandName);
+		   Controller, Command->V1.CommandStatus, CommandName);
       break;
     }
   DAC960_Error("  /dev/rd/c%dd%d:   absolute blocks %d..%d\n",
@@ -1723,33 +2996,22 @@
 
 
 /*
-  DAC960_ProcessCompletedBuffer performs completion processing for an
-  individual Buffer.
-*/
-
-static inline void DAC960_ProcessCompletedBuffer(BufferHeader_T *BufferHeader,
-						 boolean SuccessfulIO)
-{
-  BufferHeader->b_end_io(BufferHeader, SuccessfulIO);
-}
-
-
-/*
-  DAC960_ProcessCompletedCommand performs completion processing for Command.
+  DAC960_V1_ProcessCompletedCommand performs completion processing for Command
+  for DAC960 V1 Firmware Controllers.
 */
 
-static void DAC960_ProcessCompletedCommand(DAC960_Command_T *Command)
+static void DAC960_V1_ProcessCompletedCommand(DAC960_Command_T *Command)
 {
   DAC960_Controller_T *Controller = Command->Controller;
   DAC960_CommandType_T CommandType = Command->CommandType;
-  DAC960_CommandOpcode_T CommandOpcode =
-    Command->CommandMailbox.Common.CommandOpcode;
-  DAC960_CommandStatus_T CommandStatus = Command->CommandStatus;
+  DAC960_V1_CommandOpcode_T CommandOpcode =
+    Command->V1.CommandMailbox.Common.CommandOpcode;
+  DAC960_V1_CommandStatus_T CommandStatus = Command->V1.CommandStatus;
   BufferHeader_T *BufferHeader = Command->BufferHeader;
   if (CommandType == DAC960_ReadCommand ||
       CommandType == DAC960_WriteCommand)
     {
-      if (CommandStatus == DAC960_NormalCompletion)
+      if (CommandStatus == DAC960_V1_NormalCompletion)
 	{
 	  /*
 	    Perform completion processing for all buffers in this I/O Request.
@@ -1771,21 +3033,22 @@
 	    }
 	  add_blkdev_randomness(DAC960_MAJOR + Controller->ControllerNumber);
 	}
-      else if ((CommandStatus == DAC960_IrrecoverableDataError ||
-		CommandStatus == DAC960_BadDataEncountered) &&
+      else if ((CommandStatus == DAC960_V1_IrrecoverableDataError ||
+		CommandStatus == DAC960_V1_BadDataEncountered) &&
 	       BufferHeader != NULL &&
 	       BufferHeader->b_reqnext != NULL)
 	{
-	  DAC960_CommandMailbox_T *CommandMailbox = &Command->CommandMailbox;
+	  DAC960_V1_CommandMailbox_T *CommandMailbox =
+	    &Command->V1.CommandMailbox;
 	  if (CommandType == DAC960_ReadCommand)
 	    {
 	      Command->CommandType = DAC960_ReadRetryCommand;
-	      CommandMailbox->Type5.CommandOpcode = DAC960_Read;
+	      CommandMailbox->Type5.CommandOpcode = DAC960_V1_Read;
 	    }
 	  else
 	    {
 	      Command->CommandType = DAC960_WriteRetryCommand;
-	      CommandMailbox->Type5.CommandOpcode = DAC960_Write;
+	      CommandMailbox->Type5.CommandOpcode = DAC960_V1_Write;
 	    }
 	  Command->BlockCount = BufferHeader->b_size >> DAC960_BlockSizeBits;
 	  CommandMailbox->Type5.LD.TransferLength = Command->BlockCount;
@@ -1796,8 +3059,8 @@
 	}
       else
 	{
-	  if (CommandStatus != DAC960_LogicalDriveNonexistentOrOffline)
-	    DAC960_ReadWriteError(Command);
+	  if (CommandStatus != DAC960_V1_LogicalDriveNonexistentOrOffline)
+	    DAC960_V1_ReadWriteError(Command);
 	  /*
 	    Perform completion processing for all buffers in this I/O Request.
 	  */
@@ -1826,17 +3089,18 @@
       /*
 	Perform completion processing for this single buffer.
       */
-      if (CommandStatus == DAC960_NormalCompletion)
+      if (CommandStatus == DAC960_V1_NormalCompletion)
 	DAC960_ProcessCompletedBuffer(BufferHeader, true);
       else
 	{
-	  if (CommandStatus != DAC960_LogicalDriveNonexistentOrOffline)
-	    DAC960_ReadWriteError(Command);
+	  if (CommandStatus != DAC960_V1_LogicalDriveNonexistentOrOffline)
+	    DAC960_V1_ReadWriteError(Command);
 	  DAC960_ProcessCompletedBuffer(BufferHeader, false);
 	}
       if (NextBufferHeader != NULL)
 	{
-	  DAC960_CommandMailbox_T *CommandMailbox = &Command->CommandMailbox;
+	  DAC960_V1_CommandMailbox_T *CommandMailbox =
+	    &Command->V1.CommandMailbox;
 	  Command->BlockNumber +=
 	    BufferHeader->b_size >> DAC960_BlockSizeBits;
 	  Command->BlockCount =
@@ -1851,30 +3115,43 @@
 	}
     }
   else if (CommandType == DAC960_MonitoringCommand ||
-	   CommandOpcode == DAC960_Enquiry ||
-	   CommandOpcode == DAC960_GetRebuildProgress)
+	   CommandOpcode == DAC960_V1_Enquiry ||
+	   CommandOpcode == DAC960_V1_GetRebuildProgress)
     {
       if (CommandType != DAC960_MonitoringCommand)
 	{
-	  if (CommandOpcode == DAC960_Enquiry)
-	    memcpy(&Controller->Enquiry[Controller->EnquiryIndex ^ 1],
-		   Bus_to_Virtual(Command->CommandMailbox.Type3.BusAddress),
-		   sizeof(DAC960_Enquiry_T));
-	  else if (CommandOpcode == DAC960_GetRebuildProgress)
-	    memcpy(&Controller->RebuildProgress,
-		   Bus_to_Virtual(Command->CommandMailbox.Type3.BusAddress),
-		   sizeof(DAC960_RebuildProgress_T));
-	}
-      if (CommandOpcode == DAC960_Enquiry)
-	{
-	  DAC960_Enquiry_T *OldEnquiry =
-	    &Controller->Enquiry[Controller->EnquiryIndex];
-	  DAC960_Enquiry_T *NewEnquiry =
-	    &Controller->Enquiry[Controller->EnquiryIndex ^= 1];
+	  if (CommandOpcode == DAC960_V1_Enquiry)
+	    memcpy(&Controller->V1.NewEnquiry,
+		   Bus_to_Virtual(Command->V1.CommandMailbox.Type3.BusAddress),
+		   sizeof(DAC960_V1_Enquiry_T));
+	  else if (CommandOpcode == DAC960_V1_GetRebuildProgress)
+	    memcpy(&Controller->V1.RebuildProgress,
+		   Bus_to_Virtual(Command->V1.CommandMailbox.Type3.BusAddress),
+		   sizeof(DAC960_V1_RebuildProgress_T));
+	}
+      if (CommandOpcode == DAC960_V1_Enquiry &&
+	  Controller->ControllerInitialized)
+	{
+	  DAC960_V1_Enquiry_T *OldEnquiry = &Controller->V1.Enquiry;
+	  DAC960_V1_Enquiry_T *NewEnquiry = &Controller->V1.NewEnquiry;
 	  unsigned int OldCriticalLogicalDriveCount =
 	    OldEnquiry->CriticalLogicalDriveCount;
 	  unsigned int NewCriticalLogicalDriveCount =
 	    NewEnquiry->CriticalLogicalDriveCount;
+	  if (NewEnquiry->NumberOfLogicalDrives > Controller->LogicalDriveCount)
+	    {
+	      int LogicalDriveNumber = Controller->LogicalDriveCount;
+	      while (LogicalDriveNumber < NewEnquiry->NumberOfLogicalDrives)
+		{
+		  DAC960_Critical("Logical Drive %d (/dev/rd/c%dd%d) "
+				  "Now Exists\n", Controller,
+				  LogicalDriveNumber,
+				  Controller->ControllerNumber,
+				  LogicalDriveNumber);
+		  LogicalDriveNumber++;
+		}
+	      Controller->LogicalDriveCount = LogicalDriveNumber;
+	    }
 	  if (NewEnquiry->StatusFlags.DeferredWriteError !=
 	      OldEnquiry->StatusFlags.DeferredWriteError)
 	    DAC960_Critical("Deferred Write Error Flag is now %s\n", Controller,
@@ -1894,72 +3171,86 @@
 	      (jiffies - Controller->SecondaryMonitoringTime
 	       >= DAC960_SecondaryMonitoringInterval))
 	    {
-	      Controller->NeedLogicalDriveInformation = true;
-	      Controller->NewEventLogSequenceNumber =
+	      Controller->V1.NeedLogicalDriveInformation = true;
+	      Controller->V1.NewEventLogSequenceNumber =
 		NewEnquiry->EventLogSequenceNumber;
-	      Controller->NeedErrorTableInformation = true;
-	      Controller->NeedDeviceStateInformation = true;
-	      Controller->DeviceStateChannel = 0;
-	      Controller->DeviceStateTargetID = -1;
+	      Controller->V1.NeedErrorTableInformation = true;
+	      Controller->V1.NeedDeviceStateInformation = true;
+	      Controller->V1.DeviceStateChannel = 0;
+	      Controller->V1.DeviceStateTargetID = -1;
 	      Controller->SecondaryMonitoringTime = jiffies;
+	    }
+	  if (NewEnquiry->RebuildFlag == DAC960_V1_StandbyRebuildInProgress ||
+	      NewEnquiry->RebuildFlag
+	      == DAC960_V1_BackgroundRebuildInProgress ||
+	      OldEnquiry->RebuildFlag == DAC960_V1_StandbyRebuildInProgress ||
+	      OldEnquiry->RebuildFlag == DAC960_V1_BackgroundRebuildInProgress)
+	    {
+	      Controller->V1.NeedRebuildProgress = true;
+	      Controller->V1.RebuildProgressFirst =
+		(NewEnquiry->CriticalLogicalDriveCount <
+		 OldEnquiry->CriticalLogicalDriveCount);
 	    }
-	  if (NewEnquiry->RebuildFlag == DAC960_StandbyRebuildInProgress ||
-	      NewEnquiry->RebuildFlag == DAC960_BackgroundRebuildInProgress ||
-	      OldEnquiry->RebuildFlag == DAC960_StandbyRebuildInProgress ||
-	      OldEnquiry->RebuildFlag == DAC960_BackgroundRebuildInProgress)
-	    Controller->NeedRebuildProgress = true;
-	  if (OldEnquiry->RebuildFlag == DAC960_BackgroundCheckInProgress)
+	  if (OldEnquiry->RebuildFlag == DAC960_V1_BackgroundCheckInProgress)
 	    switch (NewEnquiry->RebuildFlag)
 	      {
-	      case DAC960_NoStandbyRebuildOrCheckInProgress:
+	      case DAC960_V1_NoStandbyRebuildOrCheckInProgress:
 		DAC960_Progress("Consistency Check Completed Successfully\n",
 				Controller);
 		break;
-	      case DAC960_StandbyRebuildInProgress:
-	      case DAC960_BackgroundRebuildInProgress:
+	      case DAC960_V1_StandbyRebuildInProgress:
+	      case DAC960_V1_BackgroundRebuildInProgress:
 		break;
-	      case DAC960_BackgroundCheckInProgress:
-		Controller->NeedConsistencyCheckProgress = true;
+	      case DAC960_V1_BackgroundCheckInProgress:
+		Controller->V1.NeedConsistencyCheckProgress = true;
 		break;
-	      case DAC960_StandbyRebuildCompletedWithError:
+	      case DAC960_V1_StandbyRebuildCompletedWithError:
 		DAC960_Progress("Consistency Check Completed with Error\n",
 				Controller);
 		break;
-	      case DAC960_BackgroundRebuildOrCheckFailed_DriveFailed:
+	      case DAC960_V1_BackgroundRebuildOrCheckFailed_DriveFailed:
 		DAC960_Progress("Consistency Check Failed - "
-				"Physical Drive Failed\n", Controller);
+				"Physical Device Failed\n", Controller);
 		break;
-	      case DAC960_BackgroundRebuildOrCheckFailed_LogicalDriveFailed:
+	      case DAC960_V1_BackgroundRebuildOrCheckFailed_LogicalDriveFailed:
 		DAC960_Progress("Consistency Check Failed - "
 				"Logical Drive Failed\n", Controller);
 		break;
-	      case DAC960_BackgroundRebuildOrCheckFailed_OtherCauses:
+	      case DAC960_V1_BackgroundRebuildOrCheckFailed_OtherCauses:
 		DAC960_Progress("Consistency Check Failed - Other Causes\n",
 				Controller);
 		break;
-	      case DAC960_BackgroundRebuildOrCheckSuccessfullyTerminated:
+	      case DAC960_V1_BackgroundRebuildOrCheckSuccessfullyTerminated:
 		DAC960_Progress("Consistency Check Successfully Terminated\n",
 				Controller);
 		break;
 	      }
-	  else if (NewEnquiry->RebuildFlag == DAC960_BackgroundCheckInProgress)
-	    Controller->NeedConsistencyCheckProgress = true;
+	  else if (NewEnquiry->RebuildFlag
+		   == DAC960_V1_BackgroundCheckInProgress)
+	    Controller->V1.NeedConsistencyCheckProgress = true;
+	  Controller->MonitoringAlertMode =
+	    (NewEnquiry->CriticalLogicalDriveCount > 0 ||
+	     NewEnquiry->OfflineLogicalDriveCount > 0 ||
+	     NewEnquiry->DeadDriveCount > 0);
 	  if (CommandType != DAC960_MonitoringCommand &&
-	      Controller->RebuildFlagPending)
+	      Controller->V1.RebuildFlagPending)
 	    {
-	      DAC960_Enquiry_T *Enquiry = (DAC960_Enquiry_T *)
-		Bus_to_Virtual(Command->CommandMailbox.Type3.BusAddress);
-	      Enquiry->RebuildFlag = Controller->PendingRebuildFlag;
-	      Controller->RebuildFlagPending = false;
+	      DAC960_V1_Enquiry_T *Enquiry = (DAC960_V1_Enquiry_T *)
+		Bus_to_Virtual(Command->V1.CommandMailbox.Type3.BusAddress);
+	      Enquiry->RebuildFlag = Controller->V1.PendingRebuildFlag;
+	      Controller->V1.RebuildFlagPending = false;
 	    }
 	  else if (CommandType == DAC960_MonitoringCommand &&
-		   NewEnquiry->RebuildFlag > DAC960_BackgroundCheckInProgress)
+		   NewEnquiry->RebuildFlag >
+		   DAC960_V1_BackgroundCheckInProgress)
 	    {
-	      Controller->PendingRebuildFlag = NewEnquiry->RebuildFlag;
-	      Controller->RebuildFlagPending = true;
+	      Controller->V1.PendingRebuildFlag = NewEnquiry->RebuildFlag;
+	      Controller->V1.RebuildFlagPending = true;
 	    }
+	  memcpy(&Controller->V1.Enquiry, &Controller->V1.NewEnquiry,
+		 sizeof(DAC960_V1_Enquiry_T));
 	}
-      else if (CommandOpcode == DAC960_PerformEventLogOperation)
+      else if (CommandOpcode == DAC960_V1_PerformEventLogOperation)
 	{
 	  static char
 	    *DAC960_EventMessages[] =
@@ -1976,37 +3267,39 @@
 		 "killed because of selection timeout",
 		 "killed due to SCSI phase sequence error",
 		 "killed due to unknown status" };
-	  DAC960_EventLogEntry_T *EventLogEntry = &Controller->EventLogEntry;
+	  DAC960_V1_EventLogEntry_T *EventLogEntry =
+	    &Controller->V1.EventLogEntry;
 	  if (EventLogEntry->SequenceNumber ==
-	      Controller->OldEventLogSequenceNumber)
+	      Controller->V1.OldEventLogSequenceNumber)
 	    {
 	      unsigned char SenseKey = EventLogEntry->SenseKey;
 	      unsigned char AdditionalSenseCode =
 		EventLogEntry->AdditionalSenseCode;
 	      unsigned char AdditionalSenseCodeQualifier =
 		EventLogEntry->AdditionalSenseCodeQualifier;
-	      if (SenseKey == 9 &&
+	      if (SenseKey == DAC960_SenseKey_VendorSpecific &&
 		  AdditionalSenseCode == 0x80 &&
 		  AdditionalSenseCodeQualifier <
 		  sizeof(DAC960_EventMessages) / sizeof(char *))
-		DAC960_Critical("Physical Drive %d:%d %s\n", Controller,
+		DAC960_Critical("Physical Device %d:%d %s\n", Controller,
 				EventLogEntry->Channel,
 				EventLogEntry->TargetID,
 				DAC960_EventMessages[
 				  AdditionalSenseCodeQualifier]);
-	      else if (SenseKey == 6 && AdditionalSenseCode == 0x29)
+	      else if (SenseKey == DAC960_SenseKey_UnitAttention &&
+		       AdditionalSenseCode == 0x29)
 		{
 		  if (Controller->MonitoringTimerCount > 0)
-		    Controller->DeviceResetCount[EventLogEntry->Channel]
-						[EventLogEntry->TargetID]++;
+		    Controller->V1.DeviceResetCount[EventLogEntry->Channel]
+						   [EventLogEntry->TargetID]++;
 		}
-	      else if (!(SenseKey == 0 ||
-			 (SenseKey == 2 &&
+	      else if (!(SenseKey == DAC960_SenseKey_NoSense ||
+			 (SenseKey == DAC960_SenseKey_NotReady &&
 			  AdditionalSenseCode == 0x04 &&
 			  (AdditionalSenseCodeQualifier == 0x01 ||
 			   AdditionalSenseCodeQualifier == 0x02))))
 		{
-		  DAC960_Critical("Physical Drive %d:%d Error Log: "
+		  DAC960_Critical("Physical Device %d:%d Error Log: "
 				  "Sense Key = %d, ASC = %02X, ASCQ = %02X\n",
 				  Controller,
 				  EventLogEntry->Channel,
@@ -2014,7 +3307,7 @@
 				  SenseKey,
 				  AdditionalSenseCode,
 				  AdditionalSenseCodeQualifier);
-		  DAC960_Critical("Physical Drive %d:%d Error Log: "
+		  DAC960_Critical("Physical Device %d:%d Error Log: "
 				  "Information = %02X%02X%02X%02X "
 				  "%02X%02X%02X%02X\n",
 				  Controller,
@@ -2030,21 +3323,19 @@
 				  EventLogEntry->CommandSpecificInformation[3]);
 		}
 	    }
-	  Controller->OldEventLogSequenceNumber++;
+	  Controller->V1.OldEventLogSequenceNumber++;
 	}
-      else if (CommandOpcode == DAC960_GetErrorTable)
+      else if (CommandOpcode == DAC960_V1_GetErrorTable)
 	{
-	  DAC960_ErrorTable_T *OldErrorTable =
-	    &Controller->ErrorTable[Controller->ErrorTableIndex];
-	  DAC960_ErrorTable_T *NewErrorTable =
-	    &Controller->ErrorTable[Controller->ErrorTableIndex ^= 1];
+	  DAC960_V1_ErrorTable_T *OldErrorTable = &Controller->V1.ErrorTable;
+	  DAC960_V1_ErrorTable_T *NewErrorTable = &Controller->V1.NewErrorTable;
 	  int Channel, TargetID;
 	  for (Channel = 0; Channel < Controller->Channels; Channel++)
-	    for (TargetID = 0; TargetID < DAC960_MaxTargets; TargetID++)
+	    for (TargetID = 0; TargetID < Controller->Targets; TargetID++)
 	      {
-		DAC960_ErrorTableEntry_T *NewErrorEntry =
+		DAC960_V1_ErrorTableEntry_T *NewErrorEntry =
 		  &NewErrorTable->ErrorTableEntries[Channel][TargetID];
-		DAC960_ErrorTableEntry_T *OldErrorEntry =
+		DAC960_V1_ErrorTableEntry_T *OldErrorEntry =
 		  &OldErrorTable->ErrorTableEntries[Channel][TargetID];
 		if ((NewErrorEntry->ParityErrorCount !=
 		     OldErrorEntry->ParityErrorCount) ||
@@ -2054,7 +3345,7 @@
 		     OldErrorEntry->HardErrorCount) ||
 		    (NewErrorEntry->MiscErrorCount !=
 		     OldErrorEntry->MiscErrorCount))
-		  DAC960_Critical("Physical Drive %d:%d Errors: "
+		  DAC960_Critical("Physical Device %d:%d Errors: "
 				  "Parity = %d, Soft = %d, "
 				  "Hard = %d, Misc = %d\n",
 				  Controller, Channel, TargetID,
@@ -2063,51 +3354,49 @@
 				  NewErrorEntry->HardErrorCount,
 				  NewErrorEntry->MiscErrorCount);
 	      }
+	  memcpy(&Controller->V1.ErrorTable, &Controller->V1.NewErrorTable,
+		 sizeof(DAC960_V1_ErrorTable_T));
 	}
-      else if (CommandOpcode == DAC960_GetDeviceState)
+      else if (CommandOpcode == DAC960_V1_GetDeviceState)
 	{
-	  DAC960_DeviceState_T *OldDeviceState =
-	    &Controller->DeviceState[Controller->DeviceStateIndex]
-				    [Controller->DeviceStateChannel]
-				    [Controller->DeviceStateTargetID];
-	  DAC960_DeviceState_T *NewDeviceState =
-	    &Controller->DeviceState[Controller->DeviceStateIndex ^ 1]
-				    [Controller->DeviceStateChannel]
-				    [Controller->DeviceStateTargetID];
+	  DAC960_V1_DeviceState_T *OldDeviceState =
+	    &Controller->V1.DeviceState[Controller->V1.DeviceStateChannel]
+				       [Controller->V1.DeviceStateTargetID];
+	  DAC960_V1_DeviceState_T *NewDeviceState =
+	    &Controller->V1.NewDeviceState;
 	  if (NewDeviceState->DeviceState != OldDeviceState->DeviceState)
-	    DAC960_Critical("Physical Drive %d:%d is now %s\n", Controller,
-			    Controller->DeviceStateChannel,
-			    Controller->DeviceStateTargetID,
-			    (NewDeviceState->DeviceState == DAC960_Device_Dead
+	    DAC960_Critical("Physical Device %d:%d is now %s\n", Controller,
+			    Controller->V1.DeviceStateChannel,
+			    Controller->V1.DeviceStateTargetID,
+			    (NewDeviceState->DeviceState
+			     == DAC960_V1_Device_Dead
 			     ? "DEAD"
 			     : NewDeviceState->DeviceState
-			       == DAC960_Device_WriteOnly
+			       == DAC960_V1_Device_WriteOnly
 			       ? "WRITE-ONLY"
 			       : NewDeviceState->DeviceState
-				 == DAC960_Device_Online
+				 == DAC960_V1_Device_Online
 				 ? "ONLINE" : "STANDBY"));
-	  if (OldDeviceState->DeviceState == DAC960_Device_Dead &&
-	      NewDeviceState->DeviceState != DAC960_Device_Dead)
+	  if (OldDeviceState->DeviceState == DAC960_V1_Device_Dead &&
+	      NewDeviceState->DeviceState != DAC960_V1_Device_Dead)
 	    {
-	      Controller->NeedDeviceInquiryInformation = true;
-	      Controller->NeedDeviceSerialNumberInformation = true;
+	      Controller->V1.NeedDeviceInquiryInformation = true;
+	      Controller->V1.NeedDeviceSerialNumberInformation = true;
 	    }
+	  memcpy(OldDeviceState, NewDeviceState,
+		 sizeof(DAC960_V1_DeviceState_T));
 	}
-      else if (CommandOpcode == DAC960_GetLogicalDriveInformation)
+      else if (CommandOpcode == DAC960_V1_GetLogicalDriveInformation)
 	{
 	  int LogicalDriveNumber;
 	  for (LogicalDriveNumber = 0;
 	       LogicalDriveNumber < Controller->LogicalDriveCount;
 	       LogicalDriveNumber++)
 	    {
-	      DAC960_LogicalDriveInformation_T *OldLogicalDriveInformation =
-		&Controller->LogicalDriveInformation
-			     [Controller->LogicalDriveInformationIndex]
-			     [LogicalDriveNumber];
-	      DAC960_LogicalDriveInformation_T *NewLogicalDriveInformation =
-		&Controller->LogicalDriveInformation
-			     [Controller->LogicalDriveInformationIndex ^ 1]
-			     [LogicalDriveNumber];
+	      DAC960_V1_LogicalDriveInformation_T *OldLogicalDriveInformation =
+		&Controller->V1.LogicalDriveInformation[LogicalDriveNumber];
+	      DAC960_V1_LogicalDriveInformation_T *NewLogicalDriveInformation =
+		&Controller->V1.NewLogicalDriveInformation[LogicalDriveNumber];
 	      if (NewLogicalDriveInformation->LogicalDriveState !=
 		  OldLogicalDriveInformation->LogicalDriveState)
 		DAC960_Critical("Logical Drive %d (/dev/rd/c%dd%d) "
@@ -2116,11 +3405,11 @@
 				Controller->ControllerNumber,
 				LogicalDriveNumber,
 				(NewLogicalDriveInformation->LogicalDriveState
-				 == DAC960_LogicalDrive_Online
+				 == DAC960_V1_LogicalDrive_Online
 				 ? "ONLINE"
 				 : NewLogicalDriveInformation->LogicalDriveState
-				 == DAC960_LogicalDrive_Critical
-				 ? "CRITICAL" : "OFFLINE"));
+				   == DAC960_V1_LogicalDrive_Critical
+				   ? "CRITICAL" : "OFFLINE"));
 	      if (NewLogicalDriveInformation->WriteBack !=
 		  OldLogicalDriveInformation->WriteBack)
 		DAC960_Critical("Logical Drive %d (/dev/rd/c%dd%d) "
@@ -2131,22 +3420,24 @@
 				(NewLogicalDriveInformation->WriteBack
 				 ? "WRITE BACK" : "WRITE THRU"));
 	    }
-	  Controller->LogicalDriveInformationIndex ^= 1;
+	  memcpy(&Controller->V1.LogicalDriveInformation,
+		 &Controller->V1.NewLogicalDriveInformation,
+		 sizeof(DAC960_V1_LogicalDriveInformationArray_T));
 	}
-      else if (CommandOpcode == DAC960_GetRebuildProgress)
+      else if (CommandOpcode == DAC960_V1_GetRebuildProgress)
 	{
 	  unsigned int LogicalDriveNumber =
-	    Controller->RebuildProgress.LogicalDriveNumber;
+	    Controller->V1.RebuildProgress.LogicalDriveNumber;
 	  unsigned int LogicalDriveSize =
-	    Controller->RebuildProgress.LogicalDriveSize;
+	    Controller->V1.RebuildProgress.LogicalDriveSize;
 	  unsigned int BlocksCompleted =
-	    LogicalDriveSize - Controller->RebuildProgress.RemainingBlocks;
-	  if (CommandStatus == DAC960_NoRebuildOrCheckInProgress &&
-	      Controller->LastRebuildStatus == DAC960_NormalCompletion)
-	    CommandStatus = DAC960_RebuildSuccessful;
+	    LogicalDriveSize - Controller->V1.RebuildProgress.RemainingBlocks;
+	  if (CommandStatus == DAC960_V1_NoRebuildOrCheckInProgress &&
+	      Controller->V1.LastRebuildStatus == DAC960_V1_NormalCompletion)
+	    CommandStatus = DAC960_V1_RebuildSuccessful;
 	  switch (CommandStatus)
 	    {
-	    case DAC960_NormalCompletion:
+	    case DAC960_V1_NormalCompletion:
 	      Controller->EphemeralProgressMessage = true;
 	      DAC960_Progress("Rebuild in Progress: "
 			      "Logical Drive %d (/dev/rd/c%dd%d) "
@@ -2158,244 +3449,1061 @@
 			      / (LogicalDriveSize >> 7));
 	      Controller->EphemeralProgressMessage = false;
 	      break;
-	    case DAC960_RebuildFailed_LogicalDriveFailure:
+	    case DAC960_V1_RebuildFailed_LogicalDriveFailure:
 	      DAC960_Progress("Rebuild Failed due to "
 			      "Logical Drive Failure\n", Controller);
 	      break;
-	    case DAC960_RebuildFailed_BadBlocksOnOther:
+	    case DAC960_V1_RebuildFailed_BadBlocksOnOther:
 	      DAC960_Progress("Rebuild Failed due to "
 			      "Bad Blocks on Other Drives\n", Controller);
 	      break;
-	    case DAC960_RebuildFailed_NewDriveFailed:
+	    case DAC960_V1_RebuildFailed_NewDriveFailed:
 	      DAC960_Progress("Rebuild Failed due to "
 			      "Failure of Drive Being Rebuilt\n", Controller);
 	      break;
-	    case DAC960_NoRebuildOrCheckInProgress:
+	    case DAC960_V1_NoRebuildOrCheckInProgress:
 	      break;
-	    case DAC960_RebuildSuccessful:
+	    case DAC960_V1_RebuildSuccessful:
 	      DAC960_Progress("Rebuild Completed Successfully\n", Controller);
 	      break;
-	    case DAC960_RebuildSuccessfullyTerminated:
+	    case DAC960_V1_RebuildSuccessfullyTerminated:
 	      DAC960_Progress("Rebuild Successfully Terminated\n", Controller);
 	      break;
 	    }
-	  Controller->LastRebuildStatus = CommandStatus;
+	  Controller->V1.LastRebuildStatus = CommandStatus;
 	  if (CommandType != DAC960_MonitoringCommand &&
-	      Controller->RebuildStatusPending)
+	      Controller->V1.RebuildStatusPending)
+	    {
+	      Command->V1.CommandStatus = Controller->V1.PendingRebuildStatus;
+	      Controller->V1.RebuildStatusPending = false;
+	    }
+	  else if (CommandType == DAC960_MonitoringCommand &&
+		   CommandStatus != DAC960_V1_NormalCompletion &&
+		   CommandStatus != DAC960_V1_NoRebuildOrCheckInProgress)
+	    {
+	      Controller->V1.PendingRebuildStatus = CommandStatus;
+	      Controller->V1.RebuildStatusPending = true;
+	    }
+	}
+      else if (CommandOpcode == DAC960_V1_RebuildStat)
+	{
+	  unsigned int LogicalDriveNumber =
+	    Controller->V1.RebuildProgress.LogicalDriveNumber;
+	  unsigned int LogicalDriveSize =
+	    Controller->V1.RebuildProgress.LogicalDriveSize;
+	  unsigned int BlocksCompleted =
+	    LogicalDriveSize - Controller->V1.RebuildProgress.RemainingBlocks;
+	  if (CommandStatus == DAC960_V1_NormalCompletion)
+	    {
+	      Controller->EphemeralProgressMessage = true;
+	      DAC960_Progress("Consistency Check in Progress: "
+			      "Logical Drive %d (/dev/rd/c%dd%d) "
+			      "%d%% completed\n",
+			      Controller, LogicalDriveNumber,
+			      Controller->ControllerNumber,
+			      LogicalDriveNumber,
+			      (100 * (BlocksCompleted >> 7))
+			      / (LogicalDriveSize >> 7));
+	      Controller->EphemeralProgressMessage = false;
+	    }
+	}
+    }
+  if (CommandType == DAC960_MonitoringCommand)
+    {
+      if (Controller->V1.NewEventLogSequenceNumber
+	  - Controller->V1.OldEventLogSequenceNumber > 0)
+	{
+	  Command->V1.CommandMailbox.Type3E.CommandOpcode =
+	    DAC960_V1_PerformEventLogOperation;
+	  Command->V1.CommandMailbox.Type3E.OperationType =
+	    DAC960_V1_GetEventLogEntry;
+	  Command->V1.CommandMailbox.Type3E.OperationQualifier = 1;
+	  Command->V1.CommandMailbox.Type3E.SequenceNumber =
+	    Controller->V1.OldEventLogSequenceNumber;
+	  Command->V1.CommandMailbox.Type3E.BusAddress =
+	    Virtual_to_Bus(&Controller->V1.EventLogEntry);
+	  DAC960_QueueCommand(Command);
+	  return;
+	}
+      if (Controller->V1.NeedErrorTableInformation)
+	{
+	  Controller->V1.NeedErrorTableInformation = false;
+	  Command->V1.CommandMailbox.Type3.CommandOpcode =
+	    DAC960_V1_GetErrorTable;
+	  Command->V1.CommandMailbox.Type3.BusAddress =
+	    Virtual_to_Bus(&Controller->V1.NewErrorTable);
+	  DAC960_QueueCommand(Command);
+	  return;
+	}
+      if (Controller->V1.NeedRebuildProgress &&
+	  Controller->V1.RebuildProgressFirst)
+	{
+	  Controller->V1.NeedRebuildProgress = false;
+	  Command->V1.CommandMailbox.Type3.CommandOpcode =
+	    DAC960_V1_GetRebuildProgress;
+	  Command->V1.CommandMailbox.Type3.BusAddress =
+	    Virtual_to_Bus(&Controller->V1.RebuildProgress);
+	  DAC960_QueueCommand(Command);
+	  return;
+	}
+      if (Controller->V1.NeedDeviceStateInformation)
+	{
+	  if (Controller->V1.NeedDeviceInquiryInformation)
+	    {
+	      DAC960_V1_DCDB_T *DCDB = &Controller->V1.MonitoringDCDB;
+	      DAC960_SCSI_Inquiry_T *InquiryStandardData =
+		&Controller->V1.InquiryStandardData
+				[Controller->V1.DeviceStateChannel]
+				[Controller->V1.DeviceStateTargetID];
+	      InquiryStandardData->PeripheralDeviceType = 0x1F;
+	      Command->V1.CommandMailbox.Type3.CommandOpcode = DAC960_V1_DCDB;
+	      Command->V1.CommandMailbox.Type3.BusAddress =
+		Virtual_to_Bus(DCDB);
+	      DCDB->Channel = Controller->V1.DeviceStateChannel;
+	      DCDB->TargetID = Controller->V1.DeviceStateTargetID;
+	      DCDB->Direction = DAC960_V1_DCDB_DataTransferDeviceToSystem;
+	      DCDB->EarlyStatus = false;
+	      DCDB->Timeout = DAC960_V1_DCDB_Timeout_10_seconds;
+	      DCDB->NoAutomaticRequestSense = false;
+	      DCDB->DisconnectPermitted = true;
+	      DCDB->TransferLength = sizeof(DAC960_SCSI_Inquiry_T);
+	      DCDB->BusAddress = Virtual_to_Bus(InquiryStandardData);
+	      DCDB->CDBLength = 6;
+	      DCDB->TransferLengthHigh4 = 0;
+	      DCDB->SenseLength = sizeof(DCDB->SenseData);
+	      DCDB->CDB[0] = 0x12; /* INQUIRY */
+	      DCDB->CDB[1] = 0; /* EVPD = 0 */
+	      DCDB->CDB[2] = 0; /* Page Code */
+	      DCDB->CDB[3] = 0; /* Reserved */
+	      DCDB->CDB[4] = sizeof(DAC960_SCSI_Inquiry_T);
+	      DCDB->CDB[5] = 0; /* Control */
+	      DAC960_QueueCommand(Command);
+	      Controller->V1.NeedDeviceInquiryInformation = false;
+	      return;
+	    }
+	  if (Controller->V1.NeedDeviceSerialNumberInformation)
+	    {
+	      DAC960_V1_DCDB_T *DCDB = &Controller->V1.MonitoringDCDB;
+	      DAC960_SCSI_Inquiry_UnitSerialNumber_T *InquiryUnitSerialNumber =
+		&Controller->V1.InquiryUnitSerialNumber
+				[Controller->V1.DeviceStateChannel]
+				[Controller->V1.DeviceStateTargetID];
+	      InquiryUnitSerialNumber->PeripheralDeviceType = 0x1F;
+	      Command->V1.CommandMailbox.Type3.CommandOpcode = DAC960_V1_DCDB;
+	      Command->V1.CommandMailbox.Type3.BusAddress =
+		Virtual_to_Bus(DCDB);
+	      DCDB->Channel = Controller->V1.DeviceStateChannel;
+	      DCDB->TargetID = Controller->V1.DeviceStateTargetID;
+	      DCDB->Direction = DAC960_V1_DCDB_DataTransferDeviceToSystem;
+	      DCDB->EarlyStatus = false;
+	      DCDB->Timeout = DAC960_V1_DCDB_Timeout_10_seconds;
+	      DCDB->NoAutomaticRequestSense = false;
+	      DCDB->DisconnectPermitted = true;
+	      DCDB->TransferLength =
+		sizeof(DAC960_SCSI_Inquiry_UnitSerialNumber_T);
+	      DCDB->BusAddress = Virtual_to_Bus(InquiryUnitSerialNumber);
+	      DCDB->CDBLength = 6;
+	      DCDB->TransferLengthHigh4 = 0;
+	      DCDB->SenseLength = sizeof(DCDB->SenseData);
+	      DCDB->CDB[0] = 0x12; /* INQUIRY */
+	      DCDB->CDB[1] = 1; /* EVPD = 1 */
+	      DCDB->CDB[2] = 0x80; /* Page Code */
+	      DCDB->CDB[3] = 0; /* Reserved */
+	      DCDB->CDB[4] = sizeof(DAC960_SCSI_Inquiry_UnitSerialNumber_T);
+	      DCDB->CDB[5] = 0; /* Control */
+	      DAC960_QueueCommand(Command);
+	      Controller->V1.NeedDeviceSerialNumberInformation = false;
+	      return;
+	    }
+	  if (++Controller->V1.DeviceStateTargetID == Controller->Targets)
+	    {
+	      Controller->V1.DeviceStateChannel++;
+	      Controller->V1.DeviceStateTargetID = 0;
+	    }
+	  while (Controller->V1.DeviceStateChannel < Controller->Channels)
+	    {
+	      DAC960_V1_DeviceState_T *OldDeviceState =
+		&Controller->V1.DeviceState[Controller->V1.DeviceStateChannel]
+					   [Controller->V1.DeviceStateTargetID];
+	      if (OldDeviceState->Present &&
+		  OldDeviceState->DeviceType == DAC960_V1_DiskType)
+		{
+		  Command->V1.CommandMailbox.Type3D.CommandOpcode =
+		    DAC960_V1_GetDeviceState;
+		  Command->V1.CommandMailbox.Type3D.Channel =
+		    Controller->V1.DeviceStateChannel;
+		  Command->V1.CommandMailbox.Type3D.TargetID =
+		    Controller->V1.DeviceStateTargetID;
+		  Command->V1.CommandMailbox.Type3D.BusAddress =
+		    Virtual_to_Bus(&Controller->V1.NewDeviceState);
+		  DAC960_QueueCommand(Command);
+		  return;
+		}
+	      if (++Controller->V1.DeviceStateTargetID == Controller->Targets)
+		{
+		  Controller->V1.DeviceStateChannel++;
+		  Controller->V1.DeviceStateTargetID = 0;
+		}
+	    }
+	  Controller->V1.NeedDeviceStateInformation = false;
+	}
+      if (Controller->V1.NeedLogicalDriveInformation)
+	{
+	  Controller->V1.NeedLogicalDriveInformation = false;
+	  Command->V1.CommandMailbox.Type3.CommandOpcode =
+	    DAC960_V1_GetLogicalDriveInformation;
+	  Command->V1.CommandMailbox.Type3.BusAddress =
+	    Virtual_to_Bus(&Controller->V1.NewLogicalDriveInformation);
+	  DAC960_QueueCommand(Command);
+	  return;
+	}
+      if (Controller->V1.NeedRebuildProgress)
+	{
+	  Controller->V1.NeedRebuildProgress = false;
+	  Command->V1.CommandMailbox.Type3.CommandOpcode =
+	    DAC960_V1_GetRebuildProgress;
+	  Command->V1.CommandMailbox.Type3.BusAddress =
+	    Virtual_to_Bus(&Controller->V1.RebuildProgress);
+	  DAC960_QueueCommand(Command);
+	  return;
+	}
+      if (Controller->V1.NeedConsistencyCheckProgress)
+	{
+	  Controller->V1.NeedConsistencyCheckProgress = false;
+	  Command->V1.CommandMailbox.Type3.CommandOpcode =
+	    DAC960_V1_RebuildStat;
+	  Command->V1.CommandMailbox.Type3.BusAddress =
+	    Virtual_to_Bus(&Controller->V1.RebuildProgress);
+	  DAC960_QueueCommand(Command);
+	  return;
+	}
+      Controller->MonitoringTimerCount++;
+      Controller->MonitoringTimer.expires =
+	jiffies + DAC960_MonitoringTimerInterval;
+      add_timer(&Controller->MonitoringTimer);
+    }
+  if (CommandType == DAC960_ImmediateCommand)
+    {
+      up(Command->Semaphore);
+      Command->Semaphore = NULL;
+      return;
+    }
+  if (CommandType == DAC960_QueuedCommand)
+    {
+      DAC960_V1_KernelCommand_T *KernelCommand = Command->V1.KernelCommand;
+      KernelCommand->CommandStatus = Command->V1.CommandStatus;
+      Command->V1.KernelCommand = NULL;
+      if (CommandOpcode == DAC960_V1_DCDB)
+	Controller->V1.DirectCommandActive[KernelCommand->DCDB->Channel]
+					  [KernelCommand->DCDB->TargetID] =
+	  false;
+      DAC960_DeallocateCommand(Command);
+      KernelCommand->CompletionFunction(KernelCommand);
+      return;
+    }
+  /*
+    Queue a Status Monitoring Command to the Controller using the just
+    completed Command if one was deferred previously due to lack of a
+    free Command when the Monitoring Timer Function was called.
+  */
+  if (Controller->MonitoringCommandDeferred)
+    {
+      Controller->MonitoringCommandDeferred = false;
+      DAC960_V1_QueueMonitoringCommand(Command);
+      return;
+    }
+  /*
+    Deallocate the Command.
+  */
+  DAC960_DeallocateCommand(Command);
+  /*
+    Wake up any processes waiting on a free Command.
+  */
+  wake_up(&Controller->CommandWaitQueue);
+}
+
+
+/*
+  DAC960_V2_ReadWriteError prints an appropriate error message for Command
+  when an error occurs on a Read or Write operation.
+*/
+
+static void DAC960_V2_ReadWriteError(DAC960_Command_T *Command)
+{
+  DAC960_Controller_T *Controller = Command->Controller;
+  unsigned char *SenseErrors[] = { "NO SENSE", "RECOVERED ERROR",
+				   "NOT READY", "MEDIUM ERROR",
+				   "HARDWARE ERROR", "ILLEGAL REQUEST",
+				   "UNIT ATTENTION", "DATA PROTECT",
+				   "BLANK CHECK", "VENDOR-SPECIFIC",
+				   "COPY ABORTED", "ABORTED COMMAND",
+				   "EQUAL", "VOLUME OVERFLOW",
+				   "MISCOMPARE", "RESERVED" };
+  unsigned char *CommandName = "UNKNOWN";
+  switch (Command->CommandType)
+    {
+    case DAC960_ReadCommand:
+    case DAC960_ReadRetryCommand:
+      CommandName = "READ";
+      break;
+    case DAC960_WriteCommand:
+    case DAC960_WriteRetryCommand:
+      CommandName = "WRITE";
+      break;
+    case DAC960_MonitoringCommand:
+    case DAC960_ImmediateCommand:
+    case DAC960_QueuedCommand:
+      break;
+    }
+  DAC960_Error("Error Condition %s on %s:\n", Controller,
+	       SenseErrors[Command->V2.RequestSense.SenseKey], CommandName);
+  DAC960_Error("  /dev/rd/c%dd%d:   absolute blocks %d..%d\n",
+	       Controller, Controller->ControllerNumber,
+	       Command->LogicalDriveNumber, Command->BlockNumber,
+	       Command->BlockNumber + Command->BlockCount - 1);
+  if (DAC960_PartitionNumber(Command->BufferHeader->b_rdev) > 0)
+    DAC960_Error("  /dev/rd/c%dd%dp%d: relative blocks %d..%d\n",
+		 Controller, Controller->ControllerNumber,
+		 Command->LogicalDriveNumber,
+		 DAC960_PartitionNumber(Command->BufferHeader->b_rdev),
+		 Command->BufferHeader->b_rsector,
+		 Command->BufferHeader->b_rsector + Command->BlockCount - 1);
+}
+
+
+/*
+  DAC960_V2_ReportEvent prints an appropriate message when a Controller Event
+  occurs.
+*/
+
+static void DAC960_V2_ReportEvent(DAC960_Controller_T *Controller,
+				  DAC960_V2_Event_T *Event)
+{
+  DAC960_SCSI_RequestSense_T *RequestSense =
+    (DAC960_SCSI_RequestSense_T *) &Event->RequestSenseData;
+  unsigned char MessageBuffer[DAC960_LineBufferSize];
+  static struct { int EventCode; unsigned char *EventMessage; } EventList[] =
+    { /* Physical Device Events (0x0000 - 0x007F) */
+      { 0x0001, "P Online" },
+      { 0x0002, "P Standby" },
+      { 0x0005, "P Automatic Rebuild Started" },
+      { 0x0006, "P Manual Rebuild Started" },
+      { 0x0007, "P Rebuild Completed" },
+      { 0x0008, "P Rebuild Cancelled" },
+      { 0x0009, "P Rebuild Failed for Unknown Reasons" },
+      { 0x000A, "P Rebuild Failed due to New Physical Device" },
+      { 0x000B, "P Rebuild Failed due to Logical Drive Failure" },
+      { 0x000C, "S Offline" },
+      { 0x000D, "P Found" },
+      { 0x000E, "P Gone" },
+      { 0x000F, "P Unconfigured" },
+      { 0x0010, "P Expand Capacity Started" },
+      { 0x0011, "P Expand Capacity Completed" },
+      { 0x0012, "P Expand Capacity Failed" },
+      { 0x0016, "P Parity Error" },
+      { 0x0017, "P Soft Error" },
+      { 0x0018, "P Miscellaneous Error" },
+      { 0x0019, "P Reset" },
+      { 0x001A, "P Active Spare Found" },
+      { 0x001B, "P Warm Spare Found" },
+      { 0x001C, "S Sense Data Received" },
+      { 0x001D, "P Initialization Started" },
+      { 0x001E, "P Initialization Completed" },
+      { 0x001F, "P Initialization Failed" },
+      { 0x0020, "P Initialization Cancelled" },
+      { 0x0021, "P Failed because Write Recovery Failed" },
+      { 0x0022, "P Failed because SCSI Bus Reset Failed" },
+      { 0x0023, "P Failed because of Double Check Condition" },
+      { 0x0024, "P Failed because Device Cannot Be Accessed" },
+      { 0x0025, "P Failed because of Gross Error on SCSI Processor" },
+      { 0x0026, "P Failed because of Bad Tag from Device" },
+      { 0x0027, "P Failed because of Command Timeout" },
+      { 0x0028, "P Failed because of System Reset" },
+      { 0x0029, "P Failed because of Busy Status or Parity Error" },
+      { 0x002A, "P Failed because Host Set Device to Failed State" },
+      { 0x002B, "P Failed because of Selection Timeout" },
+      { 0x002C, "P Failed because of SCSI Bus Phase Error" },
+      { 0x002D, "P Failed because Device Returned Unknown Status" },
+      { 0x002E, "P Failed because Device Not Ready" },
+      { 0x002F, "P Failed because Device Not Found at Startup" },
+      { 0x0030, "P Failed because COD Write Operation Failed" },
+      { 0x0031, "P Failed because BDT Write Operation Failed" },
+      { 0x0039, "P Missing at Startup" },
+      { 0x003A, "P Start Rebuild Failed due to Physical Drive Too Small" },
+      /* Logical Device Events (0x0080 - 0x00FF) */
+      { 0x0080, "M Consistency Check Started" },
+      { 0x0081, "M Consistency Check Completed" },
+      { 0x0082, "M Consistency Check Cancelled" },
+      { 0x0083, "M Consistency Check Completed With Errors" },
+      { 0x0084, "M Consistency Check Failed due to Logical Drive Failure" },
+      { 0x0085, "M Consistency Check Failed due to Physical Device Failure" },
+      { 0x0086, "L Offline" },
+      { 0x0087, "L Critical" },
+      { 0x0088, "L Online" },
+      { 0x0089, "M Automatic Rebuild Started" },
+      { 0x008A, "M Manual Rebuild Started" },
+      { 0x008B, "M Rebuild Completed" },
+      { 0x008C, "M Rebuild Cancelled" },
+      { 0x008D, "M Rebuild Failed for Unknown Reasons" },
+      { 0x008E, "M Rebuild Failed due to New Physical Device" },
+      { 0x008F, "M Rebuild Failed due to Logical Drive Failure" },
+      { 0x0090, "L Initialization Started" },
+      { 0x0091, "L Initialization Completed" },
+      { 0x0092, "L Initialization Cancelled" },
+      { 0x0093, "L Initialization Failed" },
+      { 0x0094, "L Found" },
+      { 0x0095, "L Gone" },
+      { 0x0096, "L Expand Capacity Started" },
+      { 0x0097, "L Expand Capacity Completed" },
+      { 0x0098, "L Expand Capacity Failed" },
+      { 0x0099, "L Bad Block Found" },
+      { 0x009A, "L Size Changed" },
+      { 0x009B, "L Type Changed" },
+      { 0x009C, "L Bad Data Block Found" },
+      { 0x009E, "L Read of Data Block in BDT" },
+      { 0x009F, "L Write Back Data for Disk Block Lost" },
+      /* Fault Management Events (0x0100 - 0x017F) */
+      { 0x0140, "E Fan %d Failed" },
+      { 0x0141, "E Fan %d OK" },
+      { 0x0142, "E Fan %d Not Present" },
+      { 0x0143, "E Power Supply %d Failed" },
+      { 0x0144, "E Power Supply %d OK" },
+      { 0x0145, "E Power Supply %d Not Present" },
+      { 0x0146, "E Temperature Sensor %d Failed" },
+      { 0x0147, "E Temperature Sensor %d Critical" },
+      { 0x0148, "E Temperature Sensor %d OK" },
+      { 0x0149, "E Temperature Sensor %d Not Present" },
+      { 0x014A, "E Unit %d Access Critical" },
+      { 0x014B, "E Unit %d Access OK" },
+      { 0x014C, "E Unit %d Access Offline" },
+      /* Controller Events (0x0180 - 0x01FF) */
+      { 0x0181, "C Cache Write Back Error" },
+      { 0x0188, "C Battery Backup Unit Found" },
+      { 0x0189, "C Battery Backup Unit Charge Level Low" },
+      { 0x018A, "C Battery Backup Unit Charge Level OK" },
+      { 0x0193, "C Installation Aborted" },
+      { 0x0195, "C Mirror Race Recovery In Progress" },
+      { 0x0196, "C Mirror Race on Critical Drive" },
+      { 0x019E, "C Memory Soft ECC Error" },
+      { 0x019F, "C Memory Hard ECC Error" },
+      { 0x01A2, "C Battery Backup Unit Failed" },
+      { 0, "" } };
+  int EventListIndex = 0, EventCode;
+  unsigned char EventType, *EventMessage;
+  while (true)
+    {
+      EventCode = EventList[EventListIndex].EventCode;
+      if (EventCode == Event->EventCode || EventCode == 0) break;
+      EventListIndex++;
+    }
+  EventType = EventList[EventListIndex].EventMessage[0];
+  EventMessage = &EventList[EventListIndex].EventMessage[2];
+  if (EventCode == 0)
+    {
+      DAC960_Critical("Unknown Controller Event Code %04X\n",
+		      Controller, Event->EventCode);
+      return;
+    }
+  switch (EventType)
+    {
+    case 'P':
+      DAC960_Critical("Physical Device %d:%d %s\n", Controller,
+		      Event->Channel, Event->TargetID, EventMessage);
+      break;
+    case 'L':
+      DAC960_Critical("Logical Drive %d (/dev/rd/c%dd%d) %s\n", Controller,
+		      Event->LogicalUnit, Controller->ControllerNumber,
+		      Event->LogicalUnit, EventMessage);
+      break;
+    case 'M':
+      DAC960_Progress("Logical Drive %d (/dev/rd/c%dd%d) %s\n", Controller,
+		      Event->LogicalUnit, Controller->ControllerNumber,
+		      Event->LogicalUnit, EventMessage);
+      break;
+    case 'S':
+      if (RequestSense->SenseKey == DAC960_SenseKey_NoSense ||
+	  (RequestSense->SenseKey == DAC960_SenseKey_NotReady &&
+	   RequestSense->AdditionalSenseCode == 0x04 &&
+	   (RequestSense->AdditionalSenseCodeQualifier == 0x01 ||
+	    RequestSense->AdditionalSenseCodeQualifier == 0x02)))
+	break;
+      DAC960_Critical("Physical Device %d:%d %s\n", Controller,
+		      Event->Channel, Event->TargetID, EventMessage);
+      DAC960_Critical("Physical Device %d:%d Request Sense: "
+		      "Sense Key = %d, ASC = %02X, ASCQ = %02X\n",
+		      Controller,
+		      Event->Channel,
+		      Event->TargetID,
+		      RequestSense->SenseKey,
+		      RequestSense->AdditionalSenseCode,
+		      RequestSense->AdditionalSenseCodeQualifier);
+      DAC960_Critical("Physical Device %d:%d Request Sense: "
+		      "Information = %02X%02X%02X%02X "
+		      "%02X%02X%02X%02X\n",
+		      Controller,
+		      Event->Channel,
+		      Event->TargetID,
+		      RequestSense->Information[0],
+		      RequestSense->Information[1],
+		      RequestSense->Information[2],
+		      RequestSense->Information[3],
+		      RequestSense->CommandSpecificInformation[0],
+		      RequestSense->CommandSpecificInformation[1],
+		      RequestSense->CommandSpecificInformation[2],
+		      RequestSense->CommandSpecificInformation[3]);
+      break;
+    case 'E':
+      sprintf(MessageBuffer, EventMessage, Event->LogicalUnit);
+      DAC960_Critical("Enclosure %d %s\n", Controller,
+		      Event->TargetID, MessageBuffer);
+      break;
+    case 'C':
+      DAC960_Critical("Controller %s\n", Controller, EventMessage);
+      break;
+    default:
+      DAC960_Critical("Unknown Controller Event Code %04X\n",
+		      Controller, Event->EventCode);
+      break;
+    }
+}
+
+
+/*
+  DAC960_V2_ReportProgress prints an appropriate progress message for
+  Logical Device Long Operations.
+*/
+
+static void DAC960_V2_ReportProgress(DAC960_Controller_T *Controller,
+				     unsigned char *MessageString,
+				     unsigned int LogicalDeviceNumber,
+				     unsigned long BlocksCompleted,
+				     unsigned long LogicalDeviceSize)
+{
+  Controller->EphemeralProgressMessage = true;
+  DAC960_Progress("%s in Progress: Logical Drive %d (/dev/rd/c%dd%d) "
+		  "%d%% completed\n", Controller,
+		  MessageString,
+		  LogicalDeviceNumber,
+		  Controller->ControllerNumber,
+		  LogicalDeviceNumber,
+		  (100 * (BlocksCompleted >> 7)) / (LogicalDeviceSize >> 7));
+  Controller->EphemeralProgressMessage = false;
+}
+
+
+/*
+  DAC960_V2_ProcessCompletedCommand performs completion processing for Command
+  for DAC960 V2 Firmware Controllers.
+*/
+
+static void DAC960_V2_ProcessCompletedCommand(DAC960_Command_T *Command)
+{
+  DAC960_Controller_T *Controller = Command->Controller;
+  DAC960_CommandType_T CommandType = Command->CommandType;
+  DAC960_V2_CommandMailbox_T *CommandMailbox = &Command->V2.CommandMailbox;
+  DAC960_V2_IOCTL_Opcode_T CommandOpcode = CommandMailbox->Common.IOCTL_Opcode;
+  DAC960_V2_CommandStatus_T CommandStatus = Command->V2.CommandStatus;
+  BufferHeader_T *BufferHeader = Command->BufferHeader;
+  if (CommandType == DAC960_ReadCommand ||
+      CommandType == DAC960_WriteCommand)
+    {
+      if (CommandStatus == DAC960_V2_NormalCompletion)
+	{
+	  /*
+	    Perform completion processing for all buffers in this I/O Request.
+	  */
+	  while (BufferHeader != NULL)
 	    {
-	      Command->CommandStatus = Controller->PendingRebuildStatus;
-	      Controller->RebuildStatusPending = false;
+	      BufferHeader_T *NextBufferHeader = BufferHeader->b_reqnext;
+	      BufferHeader->b_reqnext = NULL;
+	      DAC960_ProcessCompletedBuffer(BufferHeader, true);
+	      BufferHeader = NextBufferHeader;
 	    }
-	  else if (CommandType == DAC960_MonitoringCommand &&
-		   CommandStatus != DAC960_NormalCompletion &&
-		   CommandStatus != DAC960_NoRebuildOrCheckInProgress)
+	  /*
+	    Wake up requestor for swap file paging requests.
+	  */
+	  if (Command->Semaphore != NULL)
 	    {
-	      Controller->PendingRebuildStatus = CommandStatus;
-	      Controller->RebuildStatusPending = true;
+	      up(Command->Semaphore);
+	      Command->Semaphore = NULL;
 	    }
+	  add_blkdev_randomness(DAC960_MAJOR + Controller->ControllerNumber);
 	}
-      else if (CommandOpcode == DAC960_RebuildStat)
+      else if (Command->V2.RequestSense.SenseKey
+	       == DAC960_SenseKey_MediumError &&
+	       BufferHeader != NULL &&
+	       BufferHeader->b_reqnext != NULL)
 	{
-	  unsigned int LogicalDriveNumber =
-	    Controller->RebuildProgress.LogicalDriveNumber;
-	  unsigned int LogicalDriveSize =
-	    Controller->RebuildProgress.LogicalDriveSize;
-	  unsigned int BlocksCompleted =
-	    LogicalDriveSize - Controller->RebuildProgress.RemainingBlocks;
-	  if (CommandStatus == DAC960_NormalCompletion)
+	  if (CommandType == DAC960_ReadCommand)
+	    Command->CommandType = DAC960_ReadRetryCommand;
+	  else Command->CommandType = DAC960_WriteRetryCommand;
+	  Command->BlockCount = BufferHeader->b_size >> DAC960_BlockSizeBits;
+	  CommandMailbox->SCSI_10.CommandControlBits
+				 .AdditionalScatterGatherListMemory = false;
+	  CommandMailbox->SCSI_10.DataTransferSize =
+	    Command->BlockCount << DAC960_BlockSizeBits;
+	  CommandMailbox->SCSI_10.DataTransferMemoryAddress
+				 .ScatterGatherSegments[0].SegmentDataPointer =
+	    Virtual_to_Bus(BufferHeader->b_data);
+	  CommandMailbox->SCSI_10.DataTransferMemoryAddress
+				 .ScatterGatherSegments[0].SegmentByteCount =
+	    CommandMailbox->SCSI_10.DataTransferSize;
+	  CommandMailbox->SCSI_10.SCSI_CDB[7] = Command->BlockCount >> 8;
+	  CommandMailbox->SCSI_10.SCSI_CDB[8] = Command->BlockCount;
+	  DAC960_QueueCommand(Command);
+	  return;
+	}
+      else
+	{
+	  if (Command->V2.RequestSense.SenseKey != DAC960_SenseKey_NotReady)
+	    DAC960_V2_ReadWriteError(Command);
+	  /*
+	    Perform completion processing for all buffers in this I/O Request.
+	  */
+	  while (BufferHeader != NULL)
 	    {
-	      Controller->EphemeralProgressMessage = true;
-	      DAC960_Progress("Consistency Check in Progress: "
-			      "Logical Drive %d (/dev/rd/c%dd%d) "
-			      "%d%% completed\n",
-			      Controller, LogicalDriveNumber,
-			      Controller->ControllerNumber,
-			      LogicalDriveNumber,
-			      (100 * (BlocksCompleted >> 7))
-			      / (LogicalDriveSize >> 7));
-	      Controller->EphemeralProgressMessage = false;
+	      BufferHeader_T *NextBufferHeader = BufferHeader->b_reqnext;
+	      BufferHeader->b_reqnext = NULL;
+	      DAC960_ProcessCompletedBuffer(BufferHeader, false);
+	      BufferHeader = NextBufferHeader;
+	    }
+	  /*
+	    Wake up requestor for swap file paging requests.
+	  */
+	  if (Command->Semaphore != NULL)
+	    {
+	      up(Command->Semaphore);
+	      Command->Semaphore = NULL;
 	    }
 	}
     }
-  if (CommandType == DAC960_MonitoringCommand)
+  else if (CommandType == DAC960_ReadRetryCommand ||
+	   CommandType == DAC960_WriteRetryCommand)
     {
-      if (Controller->NewEventLogSequenceNumber
-	  - Controller->OldEventLogSequenceNumber > 0)
+      BufferHeader_T *NextBufferHeader = BufferHeader->b_reqnext;
+      BufferHeader->b_reqnext = NULL;
+      /*
+	Perform completion processing for this single buffer.
+      */
+      if (CommandStatus == DAC960_V2_NormalCompletion)
+	DAC960_ProcessCompletedBuffer(BufferHeader, true);
+      else
 	{
-	  Command->CommandMailbox.Type3E.CommandOpcode =
-	    DAC960_PerformEventLogOperation;
-	  Command->CommandMailbox.Type3E.OperationType =
-	    DAC960_GetEventLogEntry;
-	  Command->CommandMailbox.Type3E.OperationQualifier = 1;
-	  Command->CommandMailbox.Type3E.SequenceNumber =
-	    Controller->OldEventLogSequenceNumber;
-	  Command->CommandMailbox.Type3E.BusAddress =
-	    Virtual_to_Bus(&Controller->EventLogEntry);
-	  DAC960_QueueCommand(Command);
-	  return;
+	  if (Command->V2.RequestSense.SenseKey != DAC960_SenseKey_NotReady)
+	    DAC960_V2_ReadWriteError(Command);
+	  DAC960_ProcessCompletedBuffer(BufferHeader, false);
 	}
-      if (Controller->NeedErrorTableInformation)
+      if (NextBufferHeader != NULL)
 	{
-	  Controller->NeedErrorTableInformation = false;
-	  Command->CommandMailbox.Type3.CommandOpcode = DAC960_GetErrorTable;
-	  Command->CommandMailbox.Type3.BusAddress =
-	    Virtual_to_Bus(
-	      &Controller->ErrorTable[Controller->ErrorTableIndex ^ 1]);
-	  DAC960_QueueCommand(Command);
-	  return;
-	}
-      if (Controller->NeedRebuildProgress && 
-	  Controller->Enquiry[Controller->EnquiryIndex]
-		      .CriticalLogicalDriveCount <
-	  Controller->Enquiry[Controller->EnquiryIndex ^ 1]
-		      .CriticalLogicalDriveCount)
-	{
-	  Controller->NeedRebuildProgress = false;
-	  Command->CommandMailbox.Type3.CommandOpcode =
-	    DAC960_GetRebuildProgress;
-	  Command->CommandMailbox.Type3.BusAddress =
-	    Virtual_to_Bus(&Controller->RebuildProgress);
+	  Command->BlockNumber +=
+	    BufferHeader->b_size >> DAC960_BlockSizeBits;
+	  Command->BlockCount =
+	    NextBufferHeader->b_size >> DAC960_BlockSizeBits;
+	  Command->BufferHeader = NextBufferHeader;
+	  CommandMailbox->SCSI_10.DataTransferSize =
+	    Command->BlockCount << DAC960_BlockSizeBits;
+	  CommandMailbox->SCSI_10.DataTransferMemoryAddress
+				 .ScatterGatherSegments[0]
+				 .SegmentDataPointer =
+	    Virtual_to_Bus(NextBufferHeader->b_data);
+	  CommandMailbox->SCSI_10.DataTransferMemoryAddress
+				 .ScatterGatherSegments[0]
+				 .SegmentByteCount =
+	    CommandMailbox->SCSI_10.DataTransferSize;
+	  CommandMailbox->SCSI_10.SCSI_CDB[2] = Command->BlockNumber >> 24;
+	  CommandMailbox->SCSI_10.SCSI_CDB[3] = Command->BlockNumber >> 16;
+	  CommandMailbox->SCSI_10.SCSI_CDB[4] = Command->BlockNumber >> 8;
+	  CommandMailbox->SCSI_10.SCSI_CDB[5] = Command->BlockNumber;
+	  CommandMailbox->SCSI_10.SCSI_CDB[7] = Command->BlockCount >> 8;
+	  CommandMailbox->SCSI_10.SCSI_CDB[8] = Command->BlockCount;
 	  DAC960_QueueCommand(Command);
 	  return;
 	}
-      if (Controller->NeedDeviceStateInformation)
+    }
+  else if (CommandType == DAC960_MonitoringCommand)
+    {
+      if (CommandOpcode == DAC960_V2_GetControllerInfo)
 	{
-	  if (Controller->NeedDeviceInquiryInformation)
+	  DAC960_V2_ControllerInfo_T *NewControllerInfo =
+	    &Controller->V2.NewControllerInformation;
+	  DAC960_V2_ControllerInfo_T *ControllerInfo =
+	    &Controller->V2.ControllerInformation;
+	  Controller->LogicalDriveCount =
+	    NewControllerInfo->LogicalDevicesPresent;
+	  Controller->V2.NeedLogicalDeviceInformation = true;
+	  Controller->V2.NewLogicalDeviceInformation.LogicalDeviceNumber = 0;
+	  Controller->V2.NeedPhysicalDeviceInformation = true;
+	  Controller->V2.PhysicalDeviceIndex = 0;
+	  Controller->V2.NewPhysicalDeviceInformation.Channel = 0;
+	  Controller->V2.NewPhysicalDeviceInformation.TargetID = 0;
+	  Controller->V2.NewPhysicalDeviceInformation.LogicalUnit = 0;
+	  Controller->MonitoringAlertMode =
+	    (NewControllerInfo->LogicalDevicesCritical > 0 ||
+	     NewControllerInfo->LogicalDevicesOffline > 0 ||
+	     NewControllerInfo->PhysicalDisksCritical > 0 ||
+	     NewControllerInfo->PhysicalDisksOffline > 0);
+	  memcpy(ControllerInfo, NewControllerInfo,
+		 sizeof(DAC960_V2_ControllerInfo_T));
+	}
+      else if (CommandOpcode == DAC960_V2_GetEvent)
+	{
+	  if (CommandStatus == DAC960_V2_NormalCompletion)
+	    DAC960_V2_ReportEvent(Controller, &Controller->V2.Event);
+	  Controller->V2.NextEventSequenceNumber++;
+	}
+      else if (CommandOpcode == DAC960_V2_GetPhysicalDeviceInfoValid &&
+	       CommandStatus == DAC960_V2_NormalCompletion)
+	{
+	  DAC960_V2_PhysicalDeviceInfo_T *NewPhysicalDeviceInfo =
+	    &Controller->V2.NewPhysicalDeviceInformation;
+	  unsigned int PhysicalDeviceIndex = Controller->V2.PhysicalDeviceIndex;
+	  DAC960_V2_PhysicalDeviceInfo_T *PhysicalDeviceInfo =
+	    Controller->V2.PhysicalDeviceInformation[PhysicalDeviceIndex];
+	  DAC960_SCSI_Inquiry_UnitSerialNumber_T *InquiryUnitSerialNumber;
+	  if (PhysicalDeviceInfo == NULL ||
+	      (NewPhysicalDeviceInfo->Channel !=
+	       PhysicalDeviceInfo->Channel) ||
+	      (NewPhysicalDeviceInfo->TargetID !=
+	       PhysicalDeviceInfo->TargetID) ||
+	      (NewPhysicalDeviceInfo->LogicalUnit !=
+	       PhysicalDeviceInfo->LogicalUnit))
 	    {
-	      DAC960_DCDB_T *DCDB = &Controller->MonitoringDCDB;
-	      DAC960_SCSI_Inquiry_T *InquiryStandardData =
-		&Controller->InquiryStandardData
-			       [Controller->DeviceStateChannel]
-			       [Controller->DeviceStateTargetID];
-	      InquiryStandardData->PeripheralDeviceType = 0x1F;
-	      Command->CommandMailbox.Type3.CommandOpcode = DAC960_DCDB;
-	      Command->CommandMailbox.Type3.BusAddress = Virtual_to_Bus(DCDB);
-	      DCDB->Channel = Controller->DeviceStateChannel;
-	      DCDB->TargetID = Controller->DeviceStateTargetID;
-	      DCDB->Direction = DAC960_DCDB_DataTransferDeviceToSystem;
-	      DCDB->EarlyStatus = false;
-	      DCDB->Timeout = DAC960_DCDB_Timeout_10_seconds;
-	      DCDB->NoAutomaticRequestSense = false;
-	      DCDB->DisconnectPermitted = true;
-	      DCDB->TransferLength = sizeof(DAC960_SCSI_Inquiry_T);
-	      DCDB->BusAddress = Virtual_to_Bus(InquiryStandardData);
-	      DCDB->CDBLength = 6;
-	      DCDB->TransferLengthHigh4 = 0;
-	      DCDB->SenseLength = sizeof(DCDB->SenseData);
-	      DCDB->CDB[0] = 0x12; /* INQUIRY */
-	      DCDB->CDB[1] = 0; /* EVPD = 0 */
-	      DCDB->CDB[2] = 0; /* Page Code */
-	      DCDB->CDB[3] = 0; /* Reserved */
-	      DCDB->CDB[4] = sizeof(DAC960_SCSI_Inquiry_T);
-	      DCDB->CDB[5] = 0; /* Control */
-	      DAC960_QueueCommand(Command);
-	      Controller->NeedDeviceInquiryInformation = false;
-	      return;
+	      unsigned int DeviceIndex;
+	      PhysicalDeviceInfo = (DAC960_V2_PhysicalDeviceInfo_T *)
+		kmalloc(sizeof(DAC960_V2_PhysicalDeviceInfo_T), GFP_ATOMIC);
+	      InquiryUnitSerialNumber =
+		(DAC960_SCSI_Inquiry_UnitSerialNumber_T *)
+		  kmalloc(sizeof(DAC960_SCSI_Inquiry_UnitSerialNumber_T),
+			  GFP_ATOMIC);
+	      if (InquiryUnitSerialNumber == NULL)
+		{
+		  kfree(PhysicalDeviceInfo);
+		  PhysicalDeviceInfo = NULL;
+		}
+	      DAC960_Critical("Physical Device %d:%d Now Exists%s\n",
+			      Controller,
+			      NewPhysicalDeviceInfo->Channel,
+			      NewPhysicalDeviceInfo->TargetID,
+			      (PhysicalDeviceInfo != NULL
+			       ? "" : " - Allocation Failed"));
+	      if (PhysicalDeviceInfo != NULL)
+		{
+		  for (DeviceIndex = PhysicalDeviceIndex;
+		       DeviceIndex < DAC960_V2_MaxPhysicalDevices - 1;
+		       DeviceIndex++)
+		    {
+		      Controller->V2.PhysicalDeviceInformation[DeviceIndex+1] =
+			Controller->V2.PhysicalDeviceInformation[DeviceIndex];
+		      Controller->V2.InquiryUnitSerialNumber[DeviceIndex+1] =
+			Controller->V2.InquiryUnitSerialNumber[DeviceIndex];
+		      Controller->V2.PhysicalDeviceInformation
+				     [PhysicalDeviceIndex] =
+			PhysicalDeviceInfo;
+		      Controller->V2.InquiryUnitSerialNumber
+				     [PhysicalDeviceIndex] =
+			InquiryUnitSerialNumber;
+		    }
+		  memset(PhysicalDeviceInfo, 0,
+			 sizeof(DAC960_V2_PhysicalDeviceInfo_T));
+		  PhysicalDeviceInfo->PhysicalDeviceState =
+		    DAC960_V2_Device_InvalidState;
+		  memset(InquiryUnitSerialNumber, 0,
+			 sizeof(DAC960_SCSI_Inquiry_UnitSerialNumber_T));
+		  InquiryUnitSerialNumber->PeripheralDeviceType = 0x1F;
+		  Controller->V2.NeedDeviceSerialNumberInformation = true;
+		}
 	    }
-	  if (Controller->NeedDeviceSerialNumberInformation)
+	  if (PhysicalDeviceInfo != NULL)
 	    {
-	      DAC960_DCDB_T *DCDB = &Controller->MonitoringDCDB;
-	      DAC960_SCSI_Inquiry_UnitSerialNumber_T *InquiryUnitSerialNumber =
-		&Controller->InquiryUnitSerialNumber
-			       [Controller->DeviceStateChannel]
-			       [Controller->DeviceStateTargetID];
-	      InquiryUnitSerialNumber->PeripheralDeviceType = 0x1F;
-	      Command->CommandMailbox.Type3.CommandOpcode = DAC960_DCDB;
-	      Command->CommandMailbox.Type3.BusAddress = Virtual_to_Bus(DCDB);
-	      DCDB->Channel = Controller->DeviceStateChannel;
-	      DCDB->TargetID = Controller->DeviceStateTargetID;
-	      DCDB->Direction = DAC960_DCDB_DataTransferDeviceToSystem;
-	      DCDB->EarlyStatus = false;
-	      DCDB->Timeout = DAC960_DCDB_Timeout_10_seconds;
-	      DCDB->NoAutomaticRequestSense = false;
-	      DCDB->DisconnectPermitted = true;
-	      DCDB->TransferLength =
-		sizeof(DAC960_SCSI_Inquiry_UnitSerialNumber_T);
-	      DCDB->BusAddress = Virtual_to_Bus(InquiryUnitSerialNumber);
-	      DCDB->CDBLength = 6;
-	      DCDB->TransferLengthHigh4 = 0;
-	      DCDB->SenseLength = sizeof(DCDB->SenseData);
-	      DCDB->CDB[0] = 0x12; /* INQUIRY */
-	      DCDB->CDB[1] = 1; /* EVPD = 1 */
-	      DCDB->CDB[2] = 0x80; /* Page Code */
-	      DCDB->CDB[3] = 0; /* Reserved */
-	      DCDB->CDB[4] = sizeof(DAC960_SCSI_Inquiry_UnitSerialNumber_T);
-	      DCDB->CDB[5] = 0; /* Control */
-	      DAC960_QueueCommand(Command);
-	      Controller->NeedDeviceSerialNumberInformation = false;
-	      return;
+	      if (NewPhysicalDeviceInfo->PhysicalDeviceState !=
+		  PhysicalDeviceInfo->PhysicalDeviceState)
+		DAC960_Critical("Physical Device %d:%d is now %s\n", Controller,
+				NewPhysicalDeviceInfo->Channel,
+				NewPhysicalDeviceInfo->TargetID,
+				(NewPhysicalDeviceInfo->PhysicalDeviceState
+				 == DAC960_V2_Device_Unconfigured
+				 ? "UNCONFIGURED"
+				 : NewPhysicalDeviceInfo->PhysicalDeviceState
+				   == DAC960_V2_Device_Online
+				   ? "ONLINE"
+				   : NewPhysicalDeviceInfo->PhysicalDeviceState
+				     == DAC960_V2_Device_WriteOnly
+				     ? "WRITE-ONLY"
+				     : NewPhysicalDeviceInfo
+				       ->PhysicalDeviceState
+				       == DAC960_V2_Device_Dead
+				       ? "DEAD" : "STANDBY"));
+	      if ((NewPhysicalDeviceInfo->ParityErrors !=
+		   PhysicalDeviceInfo->ParityErrors) ||
+		  (NewPhysicalDeviceInfo->SoftErrors !=
+		   PhysicalDeviceInfo->SoftErrors) ||
+		  (NewPhysicalDeviceInfo->HardErrors !=
+		   PhysicalDeviceInfo->HardErrors) ||
+		  (NewPhysicalDeviceInfo->MiscellaneousErrors !=
+		   PhysicalDeviceInfo->MiscellaneousErrors) ||
+		  (NewPhysicalDeviceInfo->CommandTimeouts !=
+		   PhysicalDeviceInfo->CommandTimeouts) ||
+		  (NewPhysicalDeviceInfo->Retries !=
+		   PhysicalDeviceInfo->Retries) ||
+		  (NewPhysicalDeviceInfo->Aborts !=
+		   PhysicalDeviceInfo->Aborts) ||
+		  (NewPhysicalDeviceInfo->PredictedFailuresDetected !=
+		   PhysicalDeviceInfo->PredictedFailuresDetected))
+		{
+		  DAC960_Critical("Physical Device %d:%d Errors: "
+				  "Parity = %d, Soft = %d, "
+				  "Hard = %d, Misc = %d\n",
+				  Controller,
+				  NewPhysicalDeviceInfo->Channel,
+				  NewPhysicalDeviceInfo->TargetID,
+				  NewPhysicalDeviceInfo->ParityErrors,
+				  NewPhysicalDeviceInfo->SoftErrors,
+				  NewPhysicalDeviceInfo->HardErrors,
+				  NewPhysicalDeviceInfo->MiscellaneousErrors);
+		  DAC960_Critical("Physical Device %d:%d Errors: "
+				  "Timeouts = %d, Retries = %d, "
+				  "Aborts = %d, Predicted = %d\n",
+				  Controller,
+				  NewPhysicalDeviceInfo->Channel,
+				  NewPhysicalDeviceInfo->TargetID,
+				  NewPhysicalDeviceInfo->CommandTimeouts,
+				  NewPhysicalDeviceInfo->Retries,
+				  NewPhysicalDeviceInfo->Aborts,
+				  NewPhysicalDeviceInfo
+				  ->PredictedFailuresDetected);
+		}
+	      if (PhysicalDeviceInfo->PhysicalDeviceState
+		  == DAC960_V2_Device_Dead &&
+		  NewPhysicalDeviceInfo->PhysicalDeviceState
+		  != DAC960_V2_Device_Dead)
+		Controller->V2.NeedDeviceSerialNumberInformation = true;
+	      memcpy(PhysicalDeviceInfo, NewPhysicalDeviceInfo,
+		     sizeof(DAC960_V2_PhysicalDeviceInfo_T));
 	    }
-	  if (++Controller->DeviceStateTargetID == DAC960_MaxTargets)
+	  NewPhysicalDeviceInfo->LogicalUnit++;
+	  Controller->V2.PhysicalDeviceIndex++;
+	}
+      else if (CommandOpcode == DAC960_V2_GetPhysicalDeviceInfoValid)
+	Controller->V2.NeedPhysicalDeviceInformation = false;
+      else if (CommandOpcode == DAC960_V2_GetLogicalDeviceInfoValid &&
+	       CommandStatus == DAC960_V2_NormalCompletion)
+	{
+	  DAC960_V2_LogicalDeviceInfo_T *NewLogicalDeviceInfo =
+	    &Controller->V2.NewLogicalDeviceInformation;
+	  unsigned short LogicalDeviceNumber =
+	    NewLogicalDeviceInfo->LogicalDeviceNumber;
+	  DAC960_V2_LogicalDeviceInfo_T *LogicalDeviceInfo =
+	    Controller->V2.LogicalDeviceInformation[LogicalDeviceNumber];
+	  if (LogicalDeviceInfo == NULL)
 	    {
-	      Controller->DeviceStateChannel++;
-	      Controller->DeviceStateTargetID = 0;
+	      DAC960_V2_PhysicalDevice_T PhysicalDevice;
+	      PhysicalDevice.Controller = 0;
+	      PhysicalDevice.Channel = NewLogicalDeviceInfo->Channel;
+	      PhysicalDevice.TargetID = NewLogicalDeviceInfo->TargetID;
+	      PhysicalDevice.LogicalUnit = NewLogicalDeviceInfo->LogicalUnit;
+	      Controller->V2.LogicalDriveToVirtualDevice[LogicalDeviceNumber] =
+		PhysicalDevice;
+	      LogicalDeviceInfo = (DAC960_V2_LogicalDeviceInfo_T *)
+		kmalloc(sizeof(DAC960_V2_LogicalDeviceInfo_T), GFP_ATOMIC);
+	      Controller->V2.LogicalDeviceInformation[LogicalDeviceNumber] =
+		LogicalDeviceInfo;
+	      DAC960_Critical("Logical Drive %d (/dev/rd/c%dd%d) "
+			      "Now Exists%s\n", Controller,
+			      LogicalDeviceNumber,
+			      Controller->ControllerNumber,
+			      LogicalDeviceNumber,
+			      (LogicalDeviceInfo != NULL
+			       ? "" : " - Allocation Failed"));
+	      if (LogicalDeviceInfo != NULL)
+		memset(LogicalDeviceInfo, 0,
+		       sizeof(DAC960_V2_LogicalDeviceInfo_T));
 	    }
-	  while (Controller->DeviceStateChannel < Controller->Channels)
+	  if (LogicalDeviceInfo != NULL)
 	    {
-	      DAC960_DeviceState_T *OldDeviceState =
-		&Controller->DeviceState[Controller->DeviceStateIndex]
-					[Controller->DeviceStateChannel]
-					[Controller->DeviceStateTargetID];
-	      if (OldDeviceState->Present &&
-		  OldDeviceState->DeviceType == DAC960_DiskType)
-		{
-		  Command->CommandMailbox.Type3D.CommandOpcode =
-		    DAC960_GetDeviceState;
-		  Command->CommandMailbox.Type3D.Channel =
-		    Controller->DeviceStateChannel;
-		  Command->CommandMailbox.Type3D.TargetID =
-		    Controller->DeviceStateTargetID;
-		  Command->CommandMailbox.Type3D.BusAddress =
-		    Virtual_to_Bus(&Controller->DeviceState
-				      [Controller->DeviceStateIndex ^ 1]
-				      [Controller->DeviceStateChannel]
-				      [Controller->DeviceStateTargetID]);
-		  DAC960_QueueCommand(Command);
-		  return;
-		}
-	      if (++Controller->DeviceStateTargetID == DAC960_MaxTargets)
-		{
-		  Controller->DeviceStateChannel++;
-		  Controller->DeviceStateTargetID = 0;
-		}
+	      unsigned long LogicalDeviceSize =
+		NewLogicalDeviceInfo->ConfigurableDeviceSizeIn512ByteBlocksOrMB;
+	      if (NewLogicalDeviceInfo->LogicalDeviceState !=
+		  LogicalDeviceInfo->LogicalDeviceState)
+		DAC960_Critical("Logical Drive %d (/dev/rd/c%dd%d) "
+				"is now %s\n", Controller,
+				LogicalDeviceNumber,
+				Controller->ControllerNumber,
+				LogicalDeviceNumber,
+				(NewLogicalDeviceInfo->LogicalDeviceState
+				 == DAC960_V2_LogicalDevice_Online
+				 ? "ONLINE"
+				 : NewLogicalDeviceInfo->LogicalDeviceState
+				   == DAC960_V2_LogicalDevice_Critical
+				   ? "CRITICAL" : "OFFLINE"));
+	      if ((NewLogicalDeviceInfo->SoftErrors !=
+		   LogicalDeviceInfo->SoftErrors) ||
+		  (NewLogicalDeviceInfo->CommandsFailed !=
+		   LogicalDeviceInfo->CommandsFailed) ||
+		  (NewLogicalDeviceInfo->DeferredWriteErrors !=
+		   LogicalDeviceInfo->DeferredWriteErrors))
+		DAC960_Critical("Logical Drive %d (/dev/rd/c%dd%d) Errors: "
+				"Soft = %d, Failed = %d, Deferred Write = %d\n",
+				Controller, LogicalDeviceNumber,
+				Controller->ControllerNumber,
+				LogicalDeviceNumber,
+				NewLogicalDeviceInfo->SoftErrors,
+				NewLogicalDeviceInfo->CommandsFailed,
+				NewLogicalDeviceInfo->DeferredWriteErrors);
+	      if (NewLogicalDeviceInfo->ConsistencyCheckInProgress)
+		DAC960_V2_ReportProgress(Controller,
+					 "Consistency Check",
+					 LogicalDeviceNumber,
+					 NewLogicalDeviceInfo
+					 ->ConsistencyCheckBlockNumber,
+					 LogicalDeviceSize);
+	      else if (NewLogicalDeviceInfo->RebuildInProgress)
+		DAC960_V2_ReportProgress(Controller,
+					 "Rebuild",
+					 LogicalDeviceNumber,
+					 NewLogicalDeviceInfo
+					 ->RebuildBlockNumber,
+					 LogicalDeviceSize);
+	      else if (NewLogicalDeviceInfo->BackgroundInitializationInProgress)
+		DAC960_V2_ReportProgress(Controller,
+					 "BackgroundInitialization",
+					 LogicalDeviceNumber,
+					 NewLogicalDeviceInfo
+					 ->BackgroundInitializationBlockNumber,
+					 LogicalDeviceSize);
+	      else if (NewLogicalDeviceInfo->ForegroundInitializationInProgress)
+		DAC960_V2_ReportProgress(Controller,
+					 "Foreground Initialization",
+					 LogicalDeviceNumber,
+					 NewLogicalDeviceInfo
+					 ->ForegroundInitializationBlockNumber,
+					 LogicalDeviceSize);
+	      else if (NewLogicalDeviceInfo->DataMigrationInProgress)
+		DAC960_V2_ReportProgress(Controller,
+					 "Data Migration",
+					 LogicalDeviceNumber,
+					 NewLogicalDeviceInfo
+					 ->DataMigrationBlockNumber,
+					 LogicalDeviceSize);
+	      else if (NewLogicalDeviceInfo->PatrolOperationInProgress)
+		DAC960_V2_ReportProgress(Controller,
+					 "Patrol Operation",
+					 LogicalDeviceNumber,
+					 NewLogicalDeviceInfo
+					 ->PatrolOperationBlockNumber,
+					 LogicalDeviceSize);
+	      memcpy(LogicalDeviceInfo, NewLogicalDeviceInfo,
+		     sizeof(DAC960_V2_LogicalDeviceInfo_T));
 	    }
-	  Controller->NeedDeviceStateInformation = false;
-	  Controller->DeviceStateIndex ^= 1;
+	  NewLogicalDeviceInfo->LogicalDeviceNumber++;
 	}
-      if (Controller->NeedLogicalDriveInformation)
-	{
-	  Controller->NeedLogicalDriveInformation = false;
-	  Command->CommandMailbox.Type3.CommandOpcode =
-	    DAC960_GetLogicalDriveInformation;
-	  Command->CommandMailbox.Type3.BusAddress =
-	    Virtual_to_Bus(
-	      &Controller->LogicalDriveInformation
-			   [Controller->LogicalDriveInformationIndex ^ 1]);
+      else if (CommandOpcode == DAC960_V2_GetLogicalDeviceInfoValid)
+	Controller->V2.NeedLogicalDeviceInformation = false;
+      if (Controller->V2.HealthStatusBuffer->NextEventSequenceNumber
+	  - Controller->V2.NextEventSequenceNumber > 0)
+	{
+	  CommandMailbox->GetEvent.CommandOpcode = DAC960_V2_IOCTL;
+	  CommandMailbox->GetEvent.DataTransferSize = sizeof(DAC960_V2_Event_T);
+	  CommandMailbox->GetEvent.EventSequenceNumberHigh16 =
+	    Controller->V2.NextEventSequenceNumber >> 16;
+	  CommandMailbox->GetEvent.ControllerNumber = 0;
+	  CommandMailbox->GetEvent.IOCTL_Opcode =
+	    DAC960_V2_GetEvent;
+	  CommandMailbox->GetEvent.EventSequenceNumberLow16 =
+	    Controller->V2.NextEventSequenceNumber & 0xFFFF;
+	  CommandMailbox->GetEvent.DataTransferMemoryAddress
+				  .ScatterGatherSegments[0]
+				  .SegmentDataPointer =
+	    Virtual_to_Bus(&Controller->V2.Event);
+	  CommandMailbox->GetEvent.DataTransferMemoryAddress
+				  .ScatterGatherSegments[0]
+				  .SegmentByteCount =
+	    CommandMailbox->GetEvent.DataTransferSize;
 	  DAC960_QueueCommand(Command);
 	  return;
 	}
-      if (Controller->NeedRebuildProgress)
+      if (Controller->V2.NeedPhysicalDeviceInformation)
 	{
-	  Controller->NeedRebuildProgress = false;
-	  Command->CommandMailbox.Type3.CommandOpcode =
-	    DAC960_GetRebuildProgress;
-	  Command->CommandMailbox.Type3.BusAddress =
-	    Virtual_to_Bus(&Controller->RebuildProgress);
+	  if (Controller->V2.NeedDeviceSerialNumberInformation)
+	    {
+	      DAC960_SCSI_Inquiry_UnitSerialNumber_T *InquiryUnitSerialNumber =
+		Controller->V2.InquiryUnitSerialNumber
+			       [Controller->V2.PhysicalDeviceIndex - 1];
+	      InquiryUnitSerialNumber->PeripheralDeviceType = 0x1F;
+	      CommandMailbox->SCSI_10.CommandOpcode =
+		DAC960_V2_SCSI_10_Passthru;
+	      CommandMailbox->SCSI_10.DataTransferSize =
+		sizeof(DAC960_SCSI_Inquiry_UnitSerialNumber_T);
+	      CommandMailbox->SCSI_10.PhysicalDevice.LogicalUnit =
+		Controller->V2.NewPhysicalDeviceInformation.LogicalUnit - 1;
+	      CommandMailbox->SCSI_10.PhysicalDevice.TargetID =
+		Controller->V2.NewPhysicalDeviceInformation.TargetID;
+	      CommandMailbox->SCSI_10.PhysicalDevice.Channel =
+		Controller->V2.NewPhysicalDeviceInformation.Channel;
+	      CommandMailbox->SCSI_10.CDBLength = 6;
+	      CommandMailbox->SCSI_10.SCSI_CDB[0] = 0x12; /* INQUIRY */
+	      CommandMailbox->SCSI_10.SCSI_CDB[1] = 1; /* EVPD = 1 */
+	      CommandMailbox->SCSI_10.SCSI_CDB[2] = 0x80; /* Page Code */
+	      CommandMailbox->SCSI_10.SCSI_CDB[3] = 0; /* Reserved */
+	      CommandMailbox->SCSI_10.SCSI_CDB[4] =
+		sizeof(DAC960_SCSI_Inquiry_UnitSerialNumber_T);
+	      CommandMailbox->SCSI_10.SCSI_CDB[5] = 0; /* Control */
+	      CommandMailbox->SCSI_10.DataTransferMemoryAddress
+				     .ScatterGatherSegments[0]
+				     .SegmentDataPointer =
+		Virtual_to_Bus(InquiryUnitSerialNumber);
+	      CommandMailbox->SCSI_10.DataTransferMemoryAddress
+				     .ScatterGatherSegments[0]
+				     .SegmentByteCount =
+		CommandMailbox->SCSI_10.DataTransferSize;
+	      DAC960_QueueCommand(Command);
+	      Controller->V2.NeedDeviceSerialNumberInformation = false;
+	      return;
+	    }
+	  CommandMailbox->PhysicalDeviceInfo.CommandOpcode = DAC960_V2_IOCTL;
+	  CommandMailbox->PhysicalDeviceInfo.DataTransferSize =
+	    sizeof(DAC960_V2_PhysicalDeviceInfo_T);
+	  CommandMailbox->PhysicalDeviceInfo.PhysicalDevice.LogicalUnit =
+	    Controller->V2.NewPhysicalDeviceInformation.LogicalUnit;
+	  CommandMailbox->PhysicalDeviceInfo.PhysicalDevice.TargetID =
+	    Controller->V2.NewPhysicalDeviceInformation.TargetID;
+	  CommandMailbox->PhysicalDeviceInfo.PhysicalDevice.Channel =
+	    Controller->V2.NewPhysicalDeviceInformation.Channel;
+	  CommandMailbox->PhysicalDeviceInfo.IOCTL_Opcode =
+	    DAC960_V2_GetPhysicalDeviceInfoValid;
+	  CommandMailbox->PhysicalDeviceInfo.DataTransferMemoryAddress
+					    .ScatterGatherSegments[0]
+					    .SegmentDataPointer =
+	    Virtual_to_Bus(&Controller->V2.NewPhysicalDeviceInformation);
+	  CommandMailbox->PhysicalDeviceInfo.DataTransferMemoryAddress
+					    .ScatterGatherSegments[0]
+					    .SegmentByteCount =
+	    CommandMailbox->PhysicalDeviceInfo.DataTransferSize;
 	  DAC960_QueueCommand(Command);
 	  return;
 	}
-      if (Controller->NeedConsistencyCheckProgress)
+      if (Controller->V2.NeedLogicalDeviceInformation)
 	{
-	  Controller->NeedConsistencyCheckProgress = false;
-	  Command->CommandMailbox.Type3.CommandOpcode = DAC960_RebuildStat;
-	  Command->CommandMailbox.Type3.BusAddress =
-	    Virtual_to_Bus(&Controller->RebuildProgress);
+	  CommandMailbox->LogicalDeviceInfo.CommandOpcode = DAC960_V2_IOCTL;
+	  CommandMailbox->LogicalDeviceInfo.DataTransferSize =
+	    sizeof(DAC960_V2_LogicalDeviceInfo_T);
+	  CommandMailbox->LogicalDeviceInfo.LogicalDevice.LogicalDeviceNumber =
+	    Controller->V2.NewLogicalDeviceInformation.LogicalDeviceNumber;
+	  CommandMailbox->LogicalDeviceInfo.IOCTL_Opcode =
+	    DAC960_V2_GetLogicalDeviceInfoValid;
+	  CommandMailbox->LogicalDeviceInfo.DataTransferMemoryAddress
+					   .ScatterGatherSegments[0]
+					   .SegmentDataPointer =
+	    Virtual_to_Bus(&Controller->V2.NewLogicalDeviceInformation);
+	  CommandMailbox->LogicalDeviceInfo.DataTransferMemoryAddress
+					   .ScatterGatherSegments[0]
+					   .SegmentByteCount =
+	    CommandMailbox->LogicalDeviceInfo.DataTransferSize;
 	  DAC960_QueueCommand(Command);
 	  return;
 	}
       Controller->MonitoringTimerCount++;
       Controller->MonitoringTimer.expires =
-	jiffies + DAC960_MonitoringTimerInterval;
+	jiffies + DAC960_HealthStatusMonitoringInterval;
       add_timer(&Controller->MonitoringTimer);
     }
   if (CommandType == DAC960_ImmediateCommand)
@@ -2406,12 +4514,11 @@
     }
   if (CommandType == DAC960_QueuedCommand)
     {
-      DAC960_KernelCommand_T *KernelCommand = Command->KernelCommand;
-      KernelCommand->CommandStatus = Command->CommandStatus;
-      Command->KernelCommand = NULL;
-      if (CommandOpcode == DAC960_DCDB)
-	Controller->DirectCommandActive[KernelCommand->DCDB->Channel]
-				       [KernelCommand->DCDB->TargetID] = false;
+      DAC960_V2_KernelCommand_T *KernelCommand = Command->V2.KernelCommand;
+      KernelCommand->CommandStatus = CommandStatus;
+      KernelCommand->RequestSenseLength = Command->V2.RequestSenseLength;
+      KernelCommand->DataTransferLength = Command->V2.DataTransferResidue;
+      Command->V2.KernelCommand = NULL;
       DAC960_DeallocateCommand(Command);
       KernelCommand->CompletionFunction(KernelCommand);
       return;
@@ -2424,7 +4531,7 @@
   if (Controller->MonitoringCommandDeferred)
     {
       Controller->MonitoringCommandDeferred = false;
-      DAC960_QueueMonitoringCommand(Command);
+      DAC960_V2_QueueMonitoringCommand(Command);
       return;
     }
   /*
@@ -2438,17 +4545,209 @@
 }
 
 
+/*
+  DAC960_BA_InterruptHandler handles hardware interrupts from DAC960 BA Series
+  Controllers.
+*/
+
+static void DAC960_BA_InterruptHandler(int IRQ_Channel,
+				       void *DeviceIdentifier,
+				       Registers_T *InterruptRegisters)
+{
+  DAC960_Controller_T *Controller = (DAC960_Controller_T *) DeviceIdentifier;
+  void *ControllerBaseAddress = Controller->BaseAddress;
+  DAC960_V2_StatusMailbox_T *NextStatusMailbox;
+  ProcessorFlags_T ProcessorFlags;
+  /*
+    Acquire exclusive access to Controller.
+  */
+  DAC960_AcquireControllerLockIH(Controller, &ProcessorFlags);
+  /*
+    Process Hardware Interrupts for Controller.
+  */
+  DAC960_BA_AcknowledgeInterrupt(ControllerBaseAddress);
+  NextStatusMailbox = Controller->V2.NextStatusMailbox;
+  while (NextStatusMailbox->Fields.CommandIdentifier > 0)
+    {
+      DAC960_V2_CommandIdentifier_T CommandIdentifier =
+	NextStatusMailbox->Fields.CommandIdentifier;
+      DAC960_Command_T *Command = Controller->Commands[CommandIdentifier-1];
+      Command->V2.CommandStatus = NextStatusMailbox->Fields.CommandStatus;
+      Command->V2.RequestSenseLength =
+	NextStatusMailbox->Fields.RequestSenseLength;
+      Command->V2.DataTransferResidue =
+	NextStatusMailbox->Fields.DataTransferResidue;
+      NextStatusMailbox->Words[0] = 0;
+      if (++NextStatusMailbox > Controller->V2.LastStatusMailbox)
+	NextStatusMailbox = Controller->V2.FirstStatusMailbox;
+      DAC960_V2_ProcessCompletedCommand(Command);
+    }
+  Controller->V2.NextStatusMailbox = NextStatusMailbox;
+  /*
+    Attempt to remove additional I/O Requests from the Controller's
+    I/O Request Queue and queue them to the Controller.
+  */
+  while (DAC960_ProcessRequest(Controller, false)) ;
+  /*
+    Release exclusive access to Controller.
+  */
+  DAC960_ReleaseControllerLockIH(Controller, &ProcessorFlags);
+}
+
+
+/*
+  DAC960_LP_InterruptHandler handles hardware interrupts from DAC960 LP Series
+  Controllers.
+*/
+
+static void DAC960_LP_InterruptHandler(int IRQ_Channel,
+				       void *DeviceIdentifier,
+				       Registers_T *InterruptRegisters)
+{
+  DAC960_Controller_T *Controller = (DAC960_Controller_T *) DeviceIdentifier;
+  void *ControllerBaseAddress = Controller->BaseAddress;
+  DAC960_V2_StatusMailbox_T *NextStatusMailbox;
+  ProcessorFlags_T ProcessorFlags;
+  /*
+    Acquire exclusive access to Controller.
+  */
+  DAC960_AcquireControllerLockIH(Controller, &ProcessorFlags);
+  /*
+    Process Hardware Interrupts for Controller.
+  */
+  DAC960_LP_AcknowledgeInterrupt(ControllerBaseAddress);
+  NextStatusMailbox = Controller->V2.NextStatusMailbox;
+  while (NextStatusMailbox->Fields.CommandIdentifier > 0)
+    {
+      DAC960_V2_CommandIdentifier_T CommandIdentifier =
+	NextStatusMailbox->Fields.CommandIdentifier;
+      DAC960_Command_T *Command = Controller->Commands[CommandIdentifier-1];
+      Command->V2.CommandStatus = NextStatusMailbox->Fields.CommandStatus;
+      Command->V2.RequestSenseLength =
+	NextStatusMailbox->Fields.RequestSenseLength;
+      Command->V2.DataTransferResidue =
+	NextStatusMailbox->Fields.DataTransferResidue;
+      NextStatusMailbox->Words[0] = 0;
+      if (++NextStatusMailbox > Controller->V2.LastStatusMailbox)
+	NextStatusMailbox = Controller->V2.FirstStatusMailbox;
+      DAC960_V2_ProcessCompletedCommand(Command);
+    }
+  Controller->V2.NextStatusMailbox = NextStatusMailbox;
+  /*
+    Attempt to remove additional I/O Requests from the Controller's
+    I/O Request Queue and queue them to the Controller.
+  */
+  while (DAC960_ProcessRequest(Controller, false)) ;
+  /*
+    Release exclusive access to Controller.
+  */
+  DAC960_ReleaseControllerLockIH(Controller, &ProcessorFlags);
+}
+
+
+/*
+  DAC960_LA_InterruptHandler handles hardware interrupts from DAC960 LA Series
+  Controllers.
+*/
+
+static void DAC960_LA_InterruptHandler(int IRQ_Channel,
+				       void *DeviceIdentifier,
+				       Registers_T *InterruptRegisters)
+{
+  DAC960_Controller_T *Controller = (DAC960_Controller_T *) DeviceIdentifier;
+  void *ControllerBaseAddress = Controller->BaseAddress;
+  DAC960_V1_StatusMailbox_T *NextStatusMailbox;
+  ProcessorFlags_T ProcessorFlags;
+  /*
+    Acquire exclusive access to Controller.
+  */
+  DAC960_AcquireControllerLockIH(Controller, &ProcessorFlags);
+  /*
+    Process Hardware Interrupts for Controller.
+  */
+  DAC960_LA_AcknowledgeInterrupt(ControllerBaseAddress);
+  NextStatusMailbox = Controller->V1.NextStatusMailbox;
+  while (NextStatusMailbox->Fields.Valid)
+    {
+      DAC960_V1_CommandIdentifier_T CommandIdentifier =
+	NextStatusMailbox->Fields.CommandIdentifier;
+      DAC960_Command_T *Command = Controller->Commands[CommandIdentifier-1];
+      Command->V1.CommandStatus = NextStatusMailbox->Fields.CommandStatus;
+      NextStatusMailbox->Word = 0;
+      if (++NextStatusMailbox > Controller->V1.LastStatusMailbox)
+	NextStatusMailbox = Controller->V1.FirstStatusMailbox;
+      DAC960_V1_ProcessCompletedCommand(Command);
+    }
+  Controller->V1.NextStatusMailbox = NextStatusMailbox;
+  /*
+    Attempt to remove additional I/O Requests from the Controller's
+    I/O Request Queue and queue them to the Controller.
+  */
+  while (DAC960_ProcessRequest(Controller, false)) ;
+  /*
+    Release exclusive access to Controller.
+  */
+  DAC960_ReleaseControllerLockIH(Controller, &ProcessorFlags);
+}
+
+
+/*
+  DAC960_PG_InterruptHandler handles hardware interrupts from DAC960 PG Series
+  Controllers.
+*/
+
+static void DAC960_PG_InterruptHandler(int IRQ_Channel,
+				       void *DeviceIdentifier,
+				       Registers_T *InterruptRegisters)
+{
+  DAC960_Controller_T *Controller = (DAC960_Controller_T *) DeviceIdentifier;
+  void *ControllerBaseAddress = Controller->BaseAddress;
+  DAC960_V1_StatusMailbox_T *NextStatusMailbox;
+  ProcessorFlags_T ProcessorFlags;
+  /*
+    Acquire exclusive access to Controller.
+  */
+  DAC960_AcquireControllerLockIH(Controller, &ProcessorFlags);
+  /*
+    Process Hardware Interrupts for Controller.
+  */
+  DAC960_PG_AcknowledgeInterrupt(ControllerBaseAddress);
+  NextStatusMailbox = Controller->V1.NextStatusMailbox;
+  while (NextStatusMailbox->Fields.Valid)
+    {
+      DAC960_V1_CommandIdentifier_T CommandIdentifier =
+	NextStatusMailbox->Fields.CommandIdentifier;
+      DAC960_Command_T *Command = Controller->Commands[CommandIdentifier-1];
+      Command->V1.CommandStatus = NextStatusMailbox->Fields.CommandStatus;
+      NextStatusMailbox->Word = 0;
+      if (++NextStatusMailbox > Controller->V1.LastStatusMailbox)
+	NextStatusMailbox = Controller->V1.FirstStatusMailbox;
+      DAC960_V1_ProcessCompletedCommand(Command);
+    }
+  Controller->V1.NextStatusMailbox = NextStatusMailbox;
+  /*
+    Attempt to remove additional I/O Requests from the Controller's
+    I/O Request Queue and queue them to the Controller.
+  */
+  while (DAC960_ProcessRequest(Controller, false)) ;
+  /*
+    Release exclusive access to Controller.
+  */
+  DAC960_ReleaseControllerLockIH(Controller, &ProcessorFlags);
+}
+
+
 /*
-  DAC960_InterruptHandler handles hardware interrupts from DAC960 Controllers.
+  DAC960_PD_InterruptHandler handles hardware interrupts from DAC960 PD Series
+  Controllers.
 */
 
-static void DAC960_InterruptHandler(int IRQ_Channel,
-				    void *DeviceIdentifier,
-				    Registers_T *InterruptRegisters)
+static void DAC960_PD_InterruptHandler(int IRQ_Channel,
+				       void *DeviceIdentifier,
+				       Registers_T *InterruptRegisters)
 {
   DAC960_Controller_T *Controller = (DAC960_Controller_T *) DeviceIdentifier;
   void *ControllerBaseAddress = Controller->BaseAddress;
-  DAC960_StatusMailbox_T *NextStatusMailbox;
   ProcessorFlags_T ProcessorFlags;
   /*
     Acquire exclusive access to Controller.
@@ -2457,53 +4756,16 @@
   /*
     Process Hardware Interrupts for Controller.
   */
-  switch (Controller->ControllerType)
+  while (DAC960_PD_StatusAvailableP(ControllerBaseAddress))
     {
-    case DAC960_V5_Controller:
-      DAC960_V5_AcknowledgeInterrupt(ControllerBaseAddress);
-      NextStatusMailbox = Controller->NextStatusMailbox;
-      while (NextStatusMailbox->Fields.Valid)
-	{
-	  DAC960_CommandIdentifier_T CommandIdentifier =
-	    NextStatusMailbox->Fields.CommandIdentifier;
-	  DAC960_Command_T *Command = &Controller->Commands[CommandIdentifier];
-	  Command->CommandStatus = NextStatusMailbox->Fields.CommandStatus;
-	  NextStatusMailbox->Word = 0;
-	  if (++NextStatusMailbox > Controller->LastStatusMailbox)
-	    NextStatusMailbox = Controller->FirstStatusMailbox;
-	  DAC960_ProcessCompletedCommand(Command);
-	}
-      Controller->NextStatusMailbox = NextStatusMailbox;
-      break;
-    case DAC960_V4_Controller:
-      DAC960_V4_AcknowledgeInterrupt(ControllerBaseAddress);
-      NextStatusMailbox = Controller->NextStatusMailbox;
-      while (NextStatusMailbox->Fields.Valid)
-	{
-	  DAC960_CommandIdentifier_T CommandIdentifier =
-	    NextStatusMailbox->Fields.CommandIdentifier;
-	  DAC960_Command_T *Command = &Controller->Commands[CommandIdentifier];
-	  Command->CommandStatus = NextStatusMailbox->Fields.CommandStatus;
-	  NextStatusMailbox->Word = 0;
-	  if (++NextStatusMailbox > Controller->LastStatusMailbox)
-	    NextStatusMailbox = Controller->FirstStatusMailbox;
-	  DAC960_ProcessCompletedCommand(Command);
-	}
-      Controller->NextStatusMailbox = NextStatusMailbox;
-      break;
-    case DAC960_V3_Controller:
-      while (DAC960_V3_StatusAvailableP(ControllerBaseAddress))
-	{
-	  DAC960_CommandIdentifier_T CommandIdentifier =
-	    DAC960_V3_ReadStatusCommandIdentifier(ControllerBaseAddress);
-	  DAC960_Command_T *Command = &Controller->Commands[CommandIdentifier];
-	  Command->CommandStatus =
-	    DAC960_V3_ReadStatusRegister(ControllerBaseAddress);
-	  DAC960_V3_AcknowledgeInterrupt(ControllerBaseAddress);
-	  DAC960_V3_AcknowledgeStatus(ControllerBaseAddress);
-	  DAC960_ProcessCompletedCommand(Command);
-	}
-      break;
+      DAC960_V1_CommandIdentifier_T CommandIdentifier =
+	DAC960_PD_ReadStatusCommandIdentifier(ControllerBaseAddress);
+      DAC960_Command_T *Command = Controller->Commands[CommandIdentifier-1];
+      Command->V1.CommandStatus =
+	DAC960_PD_ReadStatusRegister(ControllerBaseAddress);
+      DAC960_PD_AcknowledgeInterrupt(ControllerBaseAddress);
+      DAC960_PD_AcknowledgeStatus(ControllerBaseAddress);
+      DAC960_V1_ProcessCompletedCommand(Command);
     }
   /*
     Attempt to remove additional I/O Requests from the Controller's
@@ -2517,19 +4779,51 @@
 }
 
 
+/*
+  DAC960_V1_QueueMonitoringCommand queues a Monitoring Command to DAC960 V1
+  Firmware Controllers.
+*/
+
+static void DAC960_V1_QueueMonitoringCommand(DAC960_Command_T *Command)
+{
+  DAC960_Controller_T *Controller = Command->Controller;
+  DAC960_V1_CommandMailbox_T *CommandMailbox = &Command->V1.CommandMailbox;
+  DAC960_V1_ClearCommand(Command);
+  Command->CommandType = DAC960_MonitoringCommand;
+  CommandMailbox->Type3.CommandOpcode = DAC960_V1_Enquiry;
+  CommandMailbox->Type3.BusAddress = Virtual_to_Bus(&Controller->V1.NewEnquiry);
+  DAC960_QueueCommand(Command);
+}
+
+
 /*
-  DAC960_QueueMonitoringCommand queues a Monitoring Command to Controller.
+  DAC960_V2_QueueMonitoringCommand queues a Monitoring Command to DAC960 V2
+  Firmware Controllers.
 */
 
-static void DAC960_QueueMonitoringCommand(DAC960_Command_T *Command)
+static void DAC960_V2_QueueMonitoringCommand(DAC960_Command_T *Command)
 {
   DAC960_Controller_T *Controller = Command->Controller;
-  DAC960_CommandMailbox_T *CommandMailbox = &Command->CommandMailbox;
-  DAC960_ClearCommand(Command);
+  DAC960_V2_CommandMailbox_T *CommandMailbox = &Command->V2.CommandMailbox;
+  DAC960_V2_ClearCommand(Command);
   Command->CommandType = DAC960_MonitoringCommand;
-  CommandMailbox->Type3.CommandOpcode = DAC960_Enquiry;
-  CommandMailbox->Type3.BusAddress =
-    Virtual_to_Bus(&Controller->Enquiry[Controller->EnquiryIndex ^ 1]);
+  CommandMailbox->ControllerInfo.CommandOpcode = DAC960_V2_IOCTL;
+  CommandMailbox->ControllerInfo.CommandControlBits
+				.DataTransferControllerToHost = true;
+  CommandMailbox->ControllerInfo.CommandControlBits
+				.NoAutoRequestSense = true;
+  CommandMailbox->ControllerInfo.DataTransferSize =
+    sizeof(DAC960_V2_ControllerInfo_T);
+  CommandMailbox->ControllerInfo.ControllerNumber = 0;
+  CommandMailbox->ControllerInfo.IOCTL_Opcode = DAC960_V2_GetControllerInfo;
+  CommandMailbox->ControllerInfo.DataTransferMemoryAddress
+				.ScatterGatherSegments[0]
+				.SegmentDataPointer =
+    Virtual_to_Bus(&Controller->V2.NewControllerInformation);
+  CommandMailbox->ControllerInfo.DataTransferMemoryAddress
+				.ScatterGatherSegments[0]
+				.SegmentByteCount =
+    CommandMailbox->ControllerInfo.DataTransferSize;
   DAC960_QueueCommand(Command);
 }
 
@@ -2544,21 +4838,69 @@
   DAC960_Controller_T *Controller = (DAC960_Controller_T *) TimerData;
   DAC960_Command_T *Command;
   ProcessorFlags_T ProcessorFlags;
-  /*
-    Acquire exclusive access to Controller.
-  */
-  DAC960_AcquireControllerLock(Controller, &ProcessorFlags);
-  /*
-    Queue a Status Monitoring Command to Controller.
-  */
-  Command = DAC960_AllocateCommand(Controller);
-  if (Command != NULL)
-    DAC960_QueueMonitoringCommand(Command);
-  else Controller->MonitoringCommandDeferred = true;
-  /*
-    Release exclusive access to Controller.
-  */
-  DAC960_ReleaseControllerLock(Controller, &ProcessorFlags);
+  if (Controller->FirmwareType == DAC960_V1_Controller)
+    {
+      /*
+	Acquire exclusive access to Controller.
+      */
+      DAC960_AcquireControllerLock(Controller, &ProcessorFlags);
+      /*
+	Queue a Status Monitoring Command to Controller.
+      */
+      Command = DAC960_AllocateCommand(Controller);
+      if (Command != NULL)
+	DAC960_V1_QueueMonitoringCommand(Command);
+      else Controller->MonitoringCommandDeferred = true;
+      /*
+	Release exclusive access to Controller.
+      */
+      DAC960_ReleaseControllerLock(Controller, &ProcessorFlags);
+    }
+  else
+    {
+      DAC960_V2_ControllerInfo_T *ControllerInfo =
+	&Controller->V2.ControllerInformation;
+      unsigned int StatusChangeCounter =
+	Controller->V2.HealthStatusBuffer->StatusChangeCounter;
+      if (StatusChangeCounter == Controller->V2.StatusChangeCounter &&
+	  Controller->V2.HealthStatusBuffer->NextEventSequenceNumber
+	  == Controller->V2.NextEventSequenceNumber &&
+	  (ControllerInfo->BackgroundInitializationsActive +
+	   ControllerInfo->LogicalDeviceInitializationsActive +
+	   ControllerInfo->PhysicalDeviceInitializationsActive +
+	   ControllerInfo->ConsistencyChecksActive +
+	   ControllerInfo->RebuildsActive +
+	   ControllerInfo->OnlineExpansionsActive == 0 ||
+	   jiffies - Controller->PrimaryMonitoringTime
+	   < DAC960_MonitoringTimerInterval))
+	{
+	  Controller->MonitoringTimer.expires =
+	    jiffies + DAC960_HealthStatusMonitoringInterval;
+	  add_timer(&Controller->MonitoringTimer);
+	  return;
+	}
+      Controller->V2.StatusChangeCounter = StatusChangeCounter;
+      Controller->PrimaryMonitoringTime = jiffies;
+      /*
+	Acquire exclusive access to Controller.
+      */
+      DAC960_AcquireControllerLock(Controller, &ProcessorFlags);
+      /*
+	Queue a Status Monitoring Command to Controller.
+      */
+      Command = DAC960_AllocateCommand(Controller);
+      if (Command != NULL)
+	DAC960_V2_QueueMonitoringCommand(Command);
+      else Controller->MonitoringCommandDeferred = true;
+      /*
+	Release exclusive access to Controller.
+      */
+      DAC960_ReleaseControllerLock(Controller, &ProcessorFlags);
+      /*
+	Wake up any processes waiting on a Health Status Buffer change.
+      */
+      wake_up(&Controller->HealthStatusWaitQueue);
+    }
 }
 
 
@@ -2577,19 +4919,28 @@
   if (ControllerNumber < 0 || ControllerNumber > DAC960_ControllerCount - 1)
     return -ENXIO;
   Controller = DAC960_Controllers[ControllerNumber];
-  if (Controller == NULL ||
-      LogicalDriveNumber > Controller->LogicalDriveCount - 1)
-    return -ENXIO;
-  if (Controller->LogicalDriveInformation
-		  [Controller->LogicalDriveInformationIndex]
-		  [LogicalDriveNumber].LogicalDriveState
-      == DAC960_LogicalDrive_Offline)
-    return -ENXIO;
-  if (Controller->LogicalDriveInitialState[LogicalDriveNumber]
-      == DAC960_LogicalDrive_Offline)
+  if (Controller == NULL) return -ENXIO;
+  if (Controller->FirmwareType == DAC960_V1_Controller)
+    {
+      if (LogicalDriveNumber > Controller->LogicalDriveCount - 1)
+	return -ENXIO;
+      if (Controller->V1.LogicalDriveInformation
+			 [LogicalDriveNumber].LogicalDriveState
+	  == DAC960_V1_LogicalDrive_Offline)
+	return -ENXIO;
+    }
+  else
+    {
+      DAC960_V2_LogicalDeviceInfo_T *LogicalDeviceInfo =
+	Controller->V2.LogicalDeviceInformation[LogicalDriveNumber];
+      if (LogicalDeviceInfo == NULL ||
+	  LogicalDeviceInfo->LogicalDeviceState
+	  == DAC960_V2_LogicalDevice_Offline)
+	return -ENXIO;
+    }
+  if (!Controller->LogicalDriveInitiallyAccessible[LogicalDriveNumber])
     {
-      Controller->LogicalDriveInitialState[LogicalDriveNumber] =
-	DAC960_LogicalDrive_Online;
+      Controller->LogicalDriveInitiallyAccessible[LogicalDriveNumber] = true;
       DAC960_InitializeGenericDiskInfo(&Controller->GenericDiskInfo);
       resetup_one_dev(&Controller->GenericDiskInfo, LogicalDriveNumber);
     }
@@ -2650,25 +5001,51 @@
   if (ControllerNumber < 0 || ControllerNumber > DAC960_ControllerCount - 1)
     return -ENXIO;
   Controller = DAC960_Controllers[ControllerNumber];
-  if (Controller == NULL ||
-      LogicalDriveNumber > Controller->LogicalDriveCount - 1)
-    return -ENXIO;
+  if (Controller == NULL) return -ENXIO;
   switch (Request)
     {
     case HDIO_GETGEO:
       /* Get BIOS Disk Geometry. */
       UserGeometry = (DiskGeometry_T *) Argument;
       if (UserGeometry == NULL) return -EINVAL;
-      Geometry.heads = Controller->GeometryTranslationHeads;
-      Geometry.sectors = Controller->GeometryTranslationSectors;
-      Geometry.cylinders =
-	Controller->LogicalDriveInformation
-		    [Controller->LogicalDriveInformationIndex]
-		    [LogicalDriveNumber].LogicalDriveSize
-	/ (Controller->GeometryTranslationHeads *
-	   Controller->GeometryTranslationSectors);
-      Geometry.start = Controller->GenericDiskInfo.part[MINOR(Inode->i_rdev)]
-						  .start_sect;
+      if (Controller->FirmwareType == DAC960_V1_Controller)
+	{
+	  if (LogicalDriveNumber > Controller->LogicalDriveCount - 1)
+	    return -ENXIO;
+	  Geometry.heads = Controller->V1.GeometryTranslationHeads;
+	  Geometry.sectors = Controller->V1.GeometryTranslationSectors;
+	  Geometry.cylinders =
+	    Controller->V1.LogicalDriveInformation[LogicalDriveNumber]
+						  .LogicalDriveSize
+	    / (Geometry.heads * Geometry.sectors);
+	}
+      else
+	{
+	  DAC960_V2_LogicalDeviceInfo_T *LogicalDeviceInfo =
+	    Controller->V2.LogicalDeviceInformation[LogicalDriveNumber];
+	  if (LogicalDeviceInfo == NULL)
+	    return -EINVAL;
+	  switch(LogicalDeviceInfo->DriveGeometry)
+	    {
+	    case DAC960_V2_Geometry_128_32:
+	      Geometry.heads = 128;
+	      Geometry.sectors = 32;
+	      break;
+	    case DAC960_V2_Geometry_255_63:
+	      Geometry.heads = 255;
+	      Geometry.sectors = 63;
+	      break;
+	    default:
+	      DAC960_Error("Illegal Logical Device Geometry %d\n",
+			   Controller, LogicalDeviceInfo->DriveGeometry);
+	      return -EINVAL;
+	    }
+	  Geometry.cylinders =
+	    LogicalDeviceInfo->ConfigurableDeviceSizeIn512ByteBlocksOrMB
+	    / (Geometry.heads * Geometry.sectors);
+	}
+      Geometry.start =
+	Controller->GenericDiskInfo.part[MINOR(Inode->i_rdev)].start_sect;
       return copy_to_user(UserGeometry, &Geometry, sizeof(DiskGeometry_T));
     case BLKGETSIZE:
       /* Get Device Size. */
@@ -2764,59 +5141,63 @@
 	    ControllerNumber > DAC960_ControllerCount - 1)
 	  return -ENXIO;
 	Controller = DAC960_Controllers[ControllerNumber];
-	if (Controller == NULL)
-	  return -ENXIO;
+	if (Controller == NULL) return -ENXIO;
 	memset(&ControllerInfo, 0, sizeof(DAC960_ControllerInfo_T));
 	ControllerInfo.ControllerNumber = ControllerNumber;
+	ControllerInfo.FirmwareType = Controller->FirmwareType;
+	ControllerInfo.Channels = Controller->Channels;
+	ControllerInfo.Targets = Controller->Targets;
 	ControllerInfo.PCI_Bus = Controller->Bus;
 	ControllerInfo.PCI_Device = Controller->Device;
 	ControllerInfo.PCI_Function = Controller->Function;
 	ControllerInfo.IRQ_Channel = Controller->IRQ_Channel;
-	ControllerInfo.Channels = Controller->Channels;
 	ControllerInfo.PCI_Address = Controller->PCI_Address;
 	strcpy(ControllerInfo.ModelName, Controller->ModelName);
 	strcpy(ControllerInfo.FirmwareVersion, Controller->FirmwareVersion);
 	return copy_to_user(UserSpaceControllerInfo, &ControllerInfo,
 			    sizeof(DAC960_ControllerInfo_T));
       }
-    case DAC960_IOCTL_EXECUTE_COMMAND:
+    case DAC960_IOCTL_V1_EXECUTE_COMMAND:
       {
-	DAC960_UserCommand_T *UserSpaceUserCommand =
-	  (DAC960_UserCommand_T *) Argument;
-	DAC960_UserCommand_T UserCommand;
+	DAC960_V1_UserCommand_T *UserSpaceUserCommand =
+	  (DAC960_V1_UserCommand_T *) Argument;
+	DAC960_V1_UserCommand_T UserCommand;
 	DAC960_Controller_T *Controller;
 	DAC960_Command_T *Command = NULL;
-	DAC960_CommandOpcode_T CommandOpcode;
-	DAC960_CommandStatus_T CommandStatus;
-	DAC960_DCDB_T DCDB;
+	DAC960_V1_CommandOpcode_T CommandOpcode;
+	DAC960_V1_CommandStatus_T CommandStatus;
+	DAC960_V1_DCDB_T DCDB;
 	ProcessorFlags_T ProcessorFlags;
 	int ControllerNumber, DataTransferLength;
 	unsigned char *DataTransferBuffer = NULL;
 	if (UserSpaceUserCommand == NULL) return -EINVAL;
 	ErrorCode = copy_from_user(&UserCommand, UserSpaceUserCommand,
-				   sizeof(DAC960_UserCommand_T));
-	if (ErrorCode != 0) goto Failure;
+				   sizeof(DAC960_V1_UserCommand_T));
+	if (ErrorCode != 0) goto Failure1;
 	ControllerNumber = UserCommand.ControllerNumber;
 	if (ControllerNumber < 0 ||
 	    ControllerNumber > DAC960_ControllerCount - 1)
 	  return -ENXIO;
 	Controller = DAC960_Controllers[ControllerNumber];
-	if (Controller == NULL)
-	  return -ENXIO;
+	if (Controller == NULL) return -ENXIO;
+	if (Controller->FirmwareType != DAC960_V1_Controller) return -EINVAL;
 	CommandOpcode = UserCommand.CommandMailbox.Common.CommandOpcode;
 	DataTransferLength = UserCommand.DataTransferLength;
 	if (CommandOpcode & 0x80) return -EINVAL;
-	if (CommandOpcode == DAC960_DCDB)
+	if (CommandOpcode == DAC960_V1_DCDB)
 	  {
 	    ErrorCode =
-	      copy_from_user(&DCDB, UserCommand.DCDB, sizeof(DAC960_DCDB_T));
-	    if (ErrorCode != 0) goto Failure;
+	      copy_from_user(&DCDB, UserCommand.DCDB, sizeof(DAC960_V1_DCDB_T));
+	    if (ErrorCode != 0) goto Failure1;
 	    if (!((DataTransferLength == 0 &&
-		   DCDB.Direction == DAC960_DCDB_NoDataTransfer) ||
+		   DCDB.Direction
+		   == DAC960_V1_DCDB_NoDataTransfer) ||
 		  (DataTransferLength > 0 &&
-		   DCDB.Direction == DAC960_DCDB_DataTransferDeviceToSystem) ||
+		   DCDB.Direction
+		   == DAC960_V1_DCDB_DataTransferDeviceToSystem) ||
 		  (DataTransferLength < 0 &&
-		   DCDB.Direction == DAC960_DCDB_DataTransferSystemToDevice)))
+		   DCDB.Direction
+		   == DAC960_V1_DCDB_DataTransferSystemToDevice)))
 	      return -EINVAL;
 	    if (((DCDB.TransferLengthHigh4 << 16) | DCDB.TransferLength)
 		!= abs(DataTransferLength))
@@ -2835,23 +5216,24 @@
 	    ErrorCode = copy_from_user(DataTransferBuffer,
 				       UserCommand.DataTransferBuffer,
 				       -DataTransferLength);
-	    if (ErrorCode != 0) goto Failure;
+	    if (ErrorCode != 0) goto Failure1;
 	  }
-	if (CommandOpcode == DAC960_DCDB)
+	if (CommandOpcode == DAC960_V1_DCDB)
 	  {
 	    DAC960_AcquireControllerLock(Controller, &ProcessorFlags);
-	    while (Controller->DirectCommandActive[DCDB.Channel]
-						  [DCDB.TargetID] ||
+	    while (Controller->V1.DirectCommandActive[DCDB.Channel]
+						     [DCDB.TargetID] ||
 		   (Command = DAC960_AllocateCommand(Controller)) == NULL)
 	      DAC960_WaitForCommand(Controller);
-	    Controller->DirectCommandActive[DCDB.Channel]
-					   [DCDB.TargetID] = true;
+	    Controller->V1.DirectCommandActive[DCDB.Channel]
+					      [DCDB.TargetID] = true;
 	    DAC960_ReleaseControllerLock(Controller, &ProcessorFlags);
-	    DAC960_ClearCommand(Command);
+	    DAC960_V1_ClearCommand(Command);
 	    Command->CommandType = DAC960_ImmediateCommand;
-	    memcpy(&Command->CommandMailbox, &UserCommand.CommandMailbox,
-		   sizeof(DAC960_CommandMailbox_T));
-	    Command->CommandMailbox.Type3.BusAddress = Virtual_to_Bus(&DCDB);
+	    memcpy(&Command->V1.CommandMailbox, &UserCommand.CommandMailbox,
+		   sizeof(DAC960_V1_CommandMailbox_T));
+	    Command->V1.CommandMailbox.Type3.BusAddress =
+	      Virtual_to_Bus(&DCDB);
 	    DCDB.BusAddress = Virtual_to_Bus(DataTransferBuffer);
 	  }
 	else
@@ -2860,38 +5242,213 @@
 	    while ((Command = DAC960_AllocateCommand(Controller)) == NULL)
 	      DAC960_WaitForCommand(Controller);
 	    DAC960_ReleaseControllerLock(Controller, &ProcessorFlags);
-	    DAC960_ClearCommand(Command);
+	    DAC960_V1_ClearCommand(Command);
 	    Command->CommandType = DAC960_ImmediateCommand;
-	    memcpy(&Command->CommandMailbox, &UserCommand.CommandMailbox,
-		   sizeof(DAC960_CommandMailbox_T));
+	    memcpy(&Command->V1.CommandMailbox, &UserCommand.CommandMailbox,
+		   sizeof(DAC960_V1_CommandMailbox_T));
 	    if (DataTransferBuffer != NULL)
-	      Command->CommandMailbox.Type3.BusAddress =
+	      Command->V1.CommandMailbox.Type3.BusAddress =
 		Virtual_to_Bus(DataTransferBuffer);
 	  }
 	DAC960_ExecuteCommand(Command);
-	CommandStatus = Command->CommandStatus;
+	CommandStatus = Command->V1.CommandStatus;
 	DAC960_AcquireControllerLock(Controller, &ProcessorFlags);
 	DAC960_DeallocateCommand(Command);
 	DAC960_ReleaseControllerLock(Controller, &ProcessorFlags);
-	if (CommandStatus == DAC960_NormalCompletion &&
+	if (CommandStatus == DAC960_V1_NormalCompletion &&
 	    DataTransferLength > 0)
 	  {
 	    ErrorCode = copy_to_user(UserCommand.DataTransferBuffer,
 				     DataTransferBuffer, DataTransferLength);
-	    if (ErrorCode != 0) goto Failure;
+	    if (ErrorCode != 0) goto Failure1;
 	  }
-	if (CommandOpcode == DAC960_DCDB)
+	if (CommandOpcode == DAC960_V1_DCDB)
 	  {
-	    Controller->DirectCommandActive[DCDB.Channel]
-					   [DCDB.TargetID] = false;
+	    Controller->V1.DirectCommandActive[DCDB.Channel]
+					      [DCDB.TargetID] = false;
 	    ErrorCode =
-	      copy_to_user(UserCommand.DCDB, &DCDB, sizeof(DAC960_DCDB_T));
-	    if (ErrorCode != 0) goto Failure;
+	      copy_to_user(UserCommand.DCDB, &DCDB, sizeof(DAC960_V1_DCDB_T));
+	    if (ErrorCode != 0) goto Failure1;
+	  }
+	ErrorCode = CommandStatus;
+      Failure1:
+	if (DataTransferBuffer != NULL)
+	  kfree(DataTransferBuffer);
+	return ErrorCode;
+      }
+    case DAC960_IOCTL_V2_EXECUTE_COMMAND:
+      {
+	DAC960_V2_UserCommand_T *UserSpaceUserCommand =
+	  (DAC960_V2_UserCommand_T *) Argument;
+	DAC960_V2_UserCommand_T UserCommand;
+	DAC960_Controller_T *Controller;
+	DAC960_Command_T *Command = NULL;
+	DAC960_V2_CommandMailbox_T *CommandMailbox;
+	DAC960_V2_CommandStatus_T CommandStatus;
+	ProcessorFlags_T ProcessorFlags;
+	int ControllerNumber, DataTransferLength;
+	int DataTransferResidue, RequestSenseLength;
+	unsigned char *DataTransferBuffer = NULL;
+	unsigned char *RequestSenseBuffer = NULL;
+	if (UserSpaceUserCommand == NULL) return -EINVAL;
+	ErrorCode = copy_from_user(&UserCommand, UserSpaceUserCommand,
+				   sizeof(DAC960_V2_UserCommand_T));
+	if (ErrorCode != 0) goto Failure2;
+	ControllerNumber = UserCommand.ControllerNumber;
+	if (ControllerNumber < 0 ||
+	    ControllerNumber > DAC960_ControllerCount - 1)
+	  return -ENXIO;
+	Controller = DAC960_Controllers[ControllerNumber];
+	if (Controller == NULL) return -ENXIO;
+	if (Controller->FirmwareType != DAC960_V2_Controller) return -EINVAL;
+	DataTransferLength = UserCommand.DataTransferLength;
+	if (DataTransferLength > 0)
+	  {
+	    DataTransferBuffer = kmalloc(DataTransferLength, GFP_KERNEL);
+	    if (DataTransferBuffer == NULL) return -ENOMEM;
+	    memset(DataTransferBuffer, 0, DataTransferLength);
+	  }
+	else if (DataTransferLength < 0)
+	  {
+	    DataTransferBuffer = kmalloc(-DataTransferLength, GFP_KERNEL);
+	    if (DataTransferBuffer == NULL) return -ENOMEM;
+	    ErrorCode = copy_from_user(DataTransferBuffer,
+				       UserCommand.DataTransferBuffer,
+				       -DataTransferLength);
+	    if (ErrorCode != 0) goto Failure2;
 	  }
+	RequestSenseLength = UserCommand.RequestSenseLength;
+	if (RequestSenseLength > 0)
+	  {
+	    RequestSenseBuffer = kmalloc(RequestSenseLength, GFP_KERNEL);
+	    if (RequestSenseBuffer == NULL)
+	      {
+		ErrorCode = -ENOMEM;
+		goto Failure2;
+	      }
+	    memset(RequestSenseBuffer, 0, RequestSenseLength);
+	  }
+	DAC960_AcquireControllerLock(Controller, &ProcessorFlags);
+	while ((Command = DAC960_AllocateCommand(Controller)) == NULL)
+	  DAC960_WaitForCommand(Controller);
+	DAC960_ReleaseControllerLock(Controller, &ProcessorFlags);
+	DAC960_V2_ClearCommand(Command);
+	Command->CommandType = DAC960_ImmediateCommand;
+	CommandMailbox = &Command->V2.CommandMailbox;
+	memcpy(CommandMailbox, &UserCommand.CommandMailbox,
+	       sizeof(DAC960_V2_CommandMailbox_T));
+	CommandMailbox->Common.CommandControlBits
+			      .AdditionalScatterGatherListMemory = false;
+	CommandMailbox->Common.CommandControlBits
+			      .NoAutoRequestSense = true;
+	CommandMailbox->Common.DataTransferSize = 0;
+	CommandMailbox->Common.DataTransferPageNumber = 0;
+	memset(&CommandMailbox->Common.DataTransferMemoryAddress, 0,
+	       sizeof(DAC960_V2_DataTransferMemoryAddress_T));
+	if (DataTransferLength != 0)
+	  {
+	    if (DataTransferLength > 0)
+	      {
+		CommandMailbox->Common.CommandControlBits
+				      .DataTransferControllerToHost = true;
+		CommandMailbox->Common.DataTransferSize = DataTransferLength;
+	      }
+	    else
+	      {
+		CommandMailbox->Common.CommandControlBits
+				      .DataTransferControllerToHost = false;
+		CommandMailbox->Common.DataTransferSize = -DataTransferLength;
+	      }
+	    CommandMailbox->Common.DataTransferMemoryAddress
+				  .ScatterGatherSegments[0]
+				  .SegmentDataPointer =
+	      Virtual_to_Bus(DataTransferBuffer);
+	    CommandMailbox->Common.DataTransferMemoryAddress
+				  .ScatterGatherSegments[0]
+				  .SegmentByteCount =
+	      CommandMailbox->Common.DataTransferSize;
+	  }
+	if (RequestSenseLength > 0)
+	  {
+	    CommandMailbox->Common.CommandControlBits
+				  .NoAutoRequestSense = false;
+	    CommandMailbox->Common.RequestSenseSize = RequestSenseLength;
+	    CommandMailbox->Common.RequestSenseBusAddress =
+	      Virtual_to_Bus(RequestSenseBuffer);
+	  }
+	DAC960_ExecuteCommand(Command);
+	CommandStatus = Command->V2.CommandStatus;
+	RequestSenseLength = Command->V2.RequestSenseLength;
+	DataTransferResidue = Command->V2.DataTransferResidue;
+	DAC960_AcquireControllerLock(Controller, &ProcessorFlags);
+	DAC960_DeallocateCommand(Command);
+	DAC960_ReleaseControllerLock(Controller, &ProcessorFlags);
+	if (RequestSenseLength > UserCommand.RequestSenseLength)
+	  RequestSenseLength = UserCommand.RequestSenseLength;
+	ErrorCode = copy_to_user(&UserSpaceUserCommand->DataTransferLength,
+				 &DataTransferResidue,
+				 sizeof(DataTransferResidue));
+	if (ErrorCode != 0) goto Failure2;
+	ErrorCode = copy_to_user(&UserSpaceUserCommand->RequestSenseLength,
+				 &RequestSenseLength,
+				 sizeof(RequestSenseLength));
+	if (ErrorCode != 0) goto Failure2;
+	if (CommandStatus == DAC960_V2_NormalCompletion &&
+	    DataTransferLength > 0)
+	  {
+	    ErrorCode = copy_to_user(UserCommand.DataTransferBuffer,
+				     DataTransferBuffer, DataTransferLength);
+	    if (ErrorCode != 0) goto Failure2;
+	  }
+	if (RequestSenseLength > 0)
+	  {
+	    ErrorCode = copy_to_user(UserCommand.RequestSenseBuffer,
+				     RequestSenseBuffer, RequestSenseLength);
+	    if (ErrorCode != 0) goto Failure2;
+	  }
 	ErrorCode = CommandStatus;
-      Failure:
+      Failure2:
 	if (DataTransferBuffer != NULL)
 	  kfree(DataTransferBuffer);
+	if (RequestSenseBuffer != NULL)
+	  kfree(RequestSenseBuffer);
+	return ErrorCode;
+      }
+    case DAC960_IOCTL_V2_GET_HEALTH_STATUS:
+      {
+	DAC960_V2_GetHealthStatus_T *UserSpaceGetHealthStatus =
+	  (DAC960_V2_GetHealthStatus_T *) Argument;
+	DAC960_V2_GetHealthStatus_T GetHealthStatus;
+	DAC960_V2_HealthStatusBuffer_T HealthStatusBuffer;
+	DAC960_Controller_T *Controller;
+	int ControllerNumber;
+	if (UserSpaceGetHealthStatus == NULL) return -EINVAL;
+	ErrorCode = copy_from_user(&GetHealthStatus, UserSpaceGetHealthStatus,
+				   sizeof(DAC960_V2_GetHealthStatus_T));
+	if (ErrorCode != 0) return ErrorCode;
+	ControllerNumber = GetHealthStatus.ControllerNumber;
+	if (ControllerNumber < 0 ||
+	    ControllerNumber > DAC960_ControllerCount - 1)
+	  return -ENXIO;
+	Controller = DAC960_Controllers[ControllerNumber];
+	if (Controller == NULL) return -ENXIO;
+	if (Controller->FirmwareType != DAC960_V2_Controller) return -EINVAL;
+	ErrorCode = copy_from_user(&HealthStatusBuffer,
+				   GetHealthStatus.HealthStatusBuffer,
+				   sizeof(DAC960_V2_HealthStatusBuffer_T));
+	if (ErrorCode != 0) return ErrorCode;
+	while (Controller->V2.HealthStatusBuffer->StatusChangeCounter
+	       == HealthStatusBuffer.StatusChangeCounter &&
+	       Controller->V2.HealthStatusBuffer->NextEventSequenceNumber
+	       == HealthStatusBuffer.NextEventSequenceNumber)
+	  {
+	    interruptible_sleep_on_timeout(&Controller->HealthStatusWaitQueue,
+					   DAC960_MonitoringTimerInterval);
+	    if (signal_pending(current)) return -EINTR;
+	  }
+	ErrorCode = copy_to_user(GetHealthStatus.HealthStatusBuffer,
+				 Controller->V2.HealthStatusBuffer,
+				 sizeof(DAC960_V2_HealthStatusBuffer_T));
 	return ErrorCode;
       }
     }
@@ -2921,28 +5478,29 @@
 	    ControllerNumber > DAC960_ControllerCount - 1)
 	  return -ENXIO;
 	Controller = DAC960_Controllers[ControllerNumber];
-	if (Controller == NULL)
-	  return -ENXIO;
+	if (Controller == NULL) return -ENXIO;
 	memset(ControllerInfo, 0, sizeof(DAC960_ControllerInfo_T));
 	ControllerInfo->ControllerNumber = ControllerNumber;
+	ControllerInfo->FirmwareType = Controller->FirmwareType;
+	ControllerInfo->Channels = Controller->Channels;
+	ControllerInfo->Targets = Controller->Targets;
 	ControllerInfo->PCI_Bus = Controller->Bus;
 	ControllerInfo->PCI_Device = Controller->Device;
 	ControllerInfo->PCI_Function = Controller->Function;
 	ControllerInfo->IRQ_Channel = Controller->IRQ_Channel;
-	ControllerInfo->Channels = Controller->Channels;
 	ControllerInfo->PCI_Address = Controller->PCI_Address;
 	strcpy(ControllerInfo->ModelName, Controller->ModelName);
 	strcpy(ControllerInfo->FirmwareVersion, Controller->FirmwareVersion);
 	return 0;
       }
-    case DAC960_IOCTL_EXECUTE_COMMAND:
+    case DAC960_IOCTL_V1_EXECUTE_COMMAND:
       {
-	DAC960_KernelCommand_T *KernelCommand =
-	  (DAC960_KernelCommand_T *) Argument;
+	DAC960_V1_KernelCommand_T *KernelCommand =
+	  (DAC960_V1_KernelCommand_T *) Argument;
 	DAC960_Controller_T *Controller;
 	DAC960_Command_T *Command = NULL;
-	DAC960_CommandOpcode_T CommandOpcode;
-	DAC960_DCDB_T *DCDB = NULL;
+	DAC960_V1_CommandOpcode_T CommandOpcode;
+	DAC960_V1_DCDB_T *DCDB = NULL;
 	ProcessorFlags_T ProcessorFlags;
 	int ControllerNumber, DataTransferLength;
 	unsigned char *DataTransferBuffer = NULL;
@@ -2952,21 +5510,23 @@
 	    ControllerNumber > DAC960_ControllerCount - 1)
 	  return -ENXIO;
 	Controller = DAC960_Controllers[ControllerNumber];
-	if (Controller == NULL)
-	  return -ENXIO;
+	if (Controller == NULL) return -ENXIO;
+	if (Controller->FirmwareType != DAC960_V1_Controller) return -EINVAL;
 	CommandOpcode = KernelCommand->CommandMailbox.Common.CommandOpcode;
 	DataTransferLength = KernelCommand->DataTransferLength;
 	DataTransferBuffer = KernelCommand->DataTransferBuffer;
 	if (CommandOpcode & 0x80) return -EINVAL;
-	if (CommandOpcode == DAC960_DCDB)
+	if (CommandOpcode == DAC960_V1_DCDB)
 	  {
 	    DCDB = KernelCommand->DCDB;
 	    if (!((DataTransferLength == 0 &&
-		   DCDB->Direction == DAC960_DCDB_NoDataTransfer) ||
+		   DCDB->Direction == DAC960_V1_DCDB_NoDataTransfer) ||
 		  (DataTransferLength > 0 &&
-		   DCDB->Direction == DAC960_DCDB_DataTransferDeviceToSystem) ||
+		   DCDB->Direction
+		   == DAC960_V1_DCDB_DataTransferDeviceToSystem) ||
 		  (DataTransferLength < 0 &&
-		   DCDB->Direction == DAC960_DCDB_DataTransferSystemToDevice)))
+		   DCDB->Direction
+		   == DAC960_V1_DCDB_DataTransferSystemToDevice)))
 	      return -EINVAL;
 	    if (((DCDB->TransferLengthHigh4 << 16) | DCDB->TransferLength)
 		!= abs(DataTransferLength))
@@ -2976,25 +5536,26 @@
 	  return -EINVAL;
 	if (DataTransferLength > 0)
 	  memset(DataTransferBuffer, 0, DataTransferLength);
-	if (CommandOpcode == DAC960_DCDB)
+	if (CommandOpcode == DAC960_V1_DCDB)
 	  {
 	    DAC960_AcquireControllerLock(Controller, &ProcessorFlags);
-	    if (!Controller->DirectCommandActive[DCDB->Channel]
-						[DCDB->TargetID])
+	    if (!Controller->V1.DirectCommandActive[DCDB->Channel]
+						   [DCDB->TargetID])
 	      Command = DAC960_AllocateCommand(Controller);
 	    if (Command == NULL)
 	      {
 		DAC960_ReleaseControllerLock(Controller, &ProcessorFlags);
 		return -EBUSY;
 	      }
-	    else Controller->DirectCommandActive[DCDB->Channel]
-						[DCDB->TargetID] = true;
-	    DAC960_ClearCommand(Command);
+	    else Controller->V1.DirectCommandActive[DCDB->Channel]
+						   [DCDB->TargetID] = true;
+	    DAC960_V1_ClearCommand(Command);
 	    Command->CommandType = DAC960_QueuedCommand;
-	    memcpy(&Command->CommandMailbox, &KernelCommand->CommandMailbox,
-		   sizeof(DAC960_CommandMailbox_T));
-	    Command->CommandMailbox.Type3.BusAddress = Virtual_to_Bus(DCDB);
-	    Command->KernelCommand = KernelCommand;
+	    memcpy(&Command->V1.CommandMailbox, &KernelCommand->CommandMailbox,
+		   sizeof(DAC960_V1_CommandMailbox_T));
+	    Command->V1.CommandMailbox.Type3.BusAddress =
+	      Virtual_to_Bus(DCDB);
+	    Command->V1.KernelCommand = KernelCommand;
 	    DCDB->BusAddress = Virtual_to_Bus(DataTransferBuffer);
 	    DAC960_QueueCommand(Command);
 	    DAC960_ReleaseControllerLock(Controller, &ProcessorFlags);
@@ -3008,42 +5569,153 @@
 		DAC960_ReleaseControllerLock(Controller, &ProcessorFlags);
 		return -EBUSY;
 	      }
-	    DAC960_ClearCommand(Command);
+	    DAC960_V1_ClearCommand(Command);
 	    Command->CommandType = DAC960_QueuedCommand;
-	    memcpy(&Command->CommandMailbox, &KernelCommand->CommandMailbox,
-		   sizeof(DAC960_CommandMailbox_T));
+	    memcpy(&Command->V1.CommandMailbox, &KernelCommand->CommandMailbox,
+		   sizeof(DAC960_V1_CommandMailbox_T));
 	    if (DataTransferBuffer != NULL)
-	      Command->CommandMailbox.Type3.BusAddress =
+	      Command->V1.CommandMailbox.Type3.BusAddress =
 		Virtual_to_Bus(DataTransferBuffer);
-	    Command->KernelCommand = KernelCommand;
+	    Command->V1.KernelCommand = KernelCommand;
 	    DAC960_QueueCommand(Command);
 	    DAC960_ReleaseControllerLock(Controller, &ProcessorFlags);
 	  }
 	return 0;
       }
+    case DAC960_IOCTL_V2_EXECUTE_COMMAND:
+      {
+	DAC960_V2_KernelCommand_T *KernelCommand =
+	  (DAC960_V2_KernelCommand_T *) Argument;
+	DAC960_Controller_T *Controller;
+	DAC960_Command_T *Command = NULL;
+	DAC960_V2_CommandMailbox_T *CommandMailbox;
+	ProcessorFlags_T ProcessorFlags;
+	int ControllerNumber, DataTransferLength, RequestSenseLength;
+	unsigned char *DataTransferBuffer = NULL;
+	unsigned char *RequestSenseBuffer = NULL;
+	if (KernelCommand == NULL) return -EINVAL;
+	ControllerNumber = KernelCommand->ControllerNumber;
+	if (ControllerNumber < 0 ||
+	    ControllerNumber > DAC960_ControllerCount - 1)
+	  return -ENXIO;
+	Controller = DAC960_Controllers[ControllerNumber];
+	if (Controller == NULL) return -ENXIO;
+	if (Controller->FirmwareType != DAC960_V2_Controller) return -EINVAL;
+	DataTransferLength = KernelCommand->DataTransferLength;
+	RequestSenseLength = KernelCommand->RequestSenseLength;
+	DataTransferBuffer = KernelCommand->DataTransferBuffer;
+	RequestSenseBuffer = KernelCommand->RequestSenseBuffer;
+	if (DataTransferLength != 0 && DataTransferBuffer == NULL)
+	  return -EINVAL;
+	if (RequestSenseLength < 0)
+	  return -EINVAL;
+	if (RequestSenseLength > 0 && RequestSenseBuffer == NULL)
+	  return -EINVAL;
+	if (DataTransferLength > 0)
+	  memset(DataTransferBuffer, 0, DataTransferLength);
+	if (RequestSenseLength > 0)
+	  memset(RequestSenseBuffer, 0, RequestSenseLength);
+	DAC960_AcquireControllerLock(Controller, &ProcessorFlags);
+	Command = DAC960_AllocateCommand(Controller);
+	if (Command == NULL)
+	  {
+	    DAC960_ReleaseControllerLock(Controller, &ProcessorFlags);
+	    return -EBUSY;
+	  }
+	DAC960_V2_ClearCommand(Command);
+	Command->CommandType = DAC960_QueuedCommand;
+	CommandMailbox = &Command->V2.CommandMailbox;
+	memcpy(CommandMailbox, &KernelCommand->CommandMailbox,
+	       sizeof(DAC960_V2_CommandMailbox_T));
+	CommandMailbox->Common.CommandControlBits
+			      .AdditionalScatterGatherListMemory = false;
+	CommandMailbox->Common.CommandControlBits
+			      .NoAutoRequestSense = true;
+	CommandMailbox->Common.DataTransferSize = 0;
+	CommandMailbox->Common.DataTransferPageNumber = 0;
+	memset(&CommandMailbox->Common.DataTransferMemoryAddress, 0,
+	       sizeof(DAC960_V2_DataTransferMemoryAddress_T));
+	if (DataTransferLength != 0)
+	  {
+	    if (DataTransferLength > 0)
+	      {
+		CommandMailbox->Common.CommandControlBits
+				      .DataTransferControllerToHost = true;
+		CommandMailbox->Common.DataTransferSize = DataTransferLength;
+	      }
+	    else
+	      {
+		CommandMailbox->Common.CommandControlBits
+				      .DataTransferControllerToHost = false;
+		CommandMailbox->Common.DataTransferSize = -DataTransferLength;
+	      }
+	    CommandMailbox->Common.DataTransferMemoryAddress
+				  .ScatterGatherSegments[0]
+				  .SegmentDataPointer =
+	      Virtual_to_Bus(DataTransferBuffer);
+	    CommandMailbox->Common.DataTransferMemoryAddress
+				  .ScatterGatherSegments[0]
+				  .SegmentByteCount =
+	      CommandMailbox->Common.DataTransferSize;
+	  }
+	if (RequestSenseLength > 0)
+	  {
+	    CommandMailbox->Common.CommandControlBits
+				  .NoAutoRequestSense = false;
+	    CommandMailbox->Common.RequestSenseBusAddress =
+	      Virtual_to_Bus(RequestSenseBuffer);
+	  }
+	Command->V2.KernelCommand = KernelCommand;
+	DAC960_QueueCommand(Command);
+	DAC960_ReleaseControllerLock(Controller, &ProcessorFlags);
+	return 0;
+      }
     }
   return -EINVAL;
 }
 
 
 /*
-  DAC960_GenericDiskInit is the Generic Disk Information Initialization
-  Function for the DAC960 Driver.
-*/
-
-static void DAC960_InitializeGenericDiskInfo(GenericDiskInfo_T *GenericDiskInfo)
-{
-  DAC960_Controller_T *Controller =
-    (DAC960_Controller_T *) GenericDiskInfo->real_devices;
-  DAC960_LogicalDriveInformation_T *LogicalDriveInformation =
-    Controller->LogicalDriveInformation
-		[Controller->LogicalDriveInformationIndex];
-  int LogicalDriveNumber;
-  for (LogicalDriveNumber = 0;
-       LogicalDriveNumber < Controller->LogicalDriveCount;
-       LogicalDriveNumber++)
-    GenericDiskInfo->part[DAC960_MinorNumber(LogicalDriveNumber, 0)].nr_sects =
-      LogicalDriveInformation[LogicalDriveNumber].LogicalDriveSize;
+  DAC960_CheckStatusBuffer verifies that there is room to hold ByteCount
+  additional bytes in the Combined Status Buffer and grows the buffer if
+  necessary.  It returns true if there is enough room and false otherwise.
+*/
+
+static boolean DAC960_CheckStatusBuffer(DAC960_Controller_T *Controller,
+					unsigned int ByteCount)
+{
+  unsigned char *NewStatusBuffer;
+  if (Controller->InitialStatusLength + 1 +
+      Controller->CurrentStatusLength + ByteCount + 1 <=
+      Controller->CombinedStatusBufferLength)
+    return true;
+  if (Controller->CombinedStatusBufferLength == 0)
+    {
+      unsigned int NewStatusBufferLength = DAC960_InitialStatusBufferSize;
+      while (NewStatusBufferLength < ByteCount)
+	NewStatusBufferLength *= 2;
+      Controller->CombinedStatusBuffer =
+	(unsigned char *) kmalloc(NewStatusBufferLength, GFP_ATOMIC);
+      if (Controller->CombinedStatusBuffer == NULL) return false;
+      Controller->CombinedStatusBufferLength = NewStatusBufferLength;
+      return true;
+    }
+  NewStatusBuffer = (unsigned char *)
+    kmalloc(2 * Controller->CombinedStatusBufferLength, GFP_ATOMIC);
+  if (NewStatusBuffer == NULL)
+    {
+      DAC960_Warning("Unable to expand Combined Status Buffer - Truncating\n",
+		     Controller);
+      return false;
+    }
+  memcpy(NewStatusBuffer, Controller->CombinedStatusBuffer,
+	 Controller->CombinedStatusBufferLength);
+  kfree(Controller->CombinedStatusBuffer);
+  Controller->CombinedStatusBuffer = NewStatusBuffer;
+  Controller->CombinedStatusBufferLength *= 2;
+  Controller->CurrentStatusBuffer =
+    &NewStatusBuffer[Controller->InitialStatusLength + 1];
+  return true;
 }
 
 
@@ -3052,11 +5724,11 @@
 */
 
 static void DAC960_Message(DAC960_MessageLevel_T MessageLevel,
-			   char *Format,
+			   unsigned char *Format,
 			   DAC960_Controller_T *Controller,
 			   ...)
 {
-  static char Buffer[DAC960_LineBufferSize];
+  static unsigned char Buffer[DAC960_LineBufferSize];
   static boolean BeginningOfLine = true;
   va_list Arguments;
   int Length = 0;
@@ -3071,9 +5743,16 @@
     {
       if (!Controller->ControllerInitialized)
 	{
-	  strcpy(&Controller->InitialStatusBuffer[
-		    Controller->InitialStatusLength], Buffer);
-	  Controller->InitialStatusLength += Length;
+	  if (DAC960_CheckStatusBuffer(Controller, Length))
+	    {
+	      strcpy(&Controller->CombinedStatusBuffer
+				  [Controller->InitialStatusLength],
+		     Buffer);
+	      Controller->InitialStatusLength += Length;
+	      Controller->CurrentStatusBuffer =
+		&Controller->CombinedStatusBuffer
+			     [Controller->InitialStatusLength + 1];
+	    }
 	  if (MessageLevel == DAC960_AnnounceLevel)
 	    {
 	      static int AnnouncementLines = 0;
@@ -3093,7 +5772,7 @@
 	      else printk("%s", Buffer);
 	    }
 	}
-      else
+      else if (DAC960_CheckStatusBuffer(Controller, Length))
 	{
 	  strcpy(&Controller->CurrentStatusBuffer[
 		    Controller->CurrentStatusLength], Buffer);
@@ -3102,8 +5781,8 @@
     }
   else if (MessageLevel == DAC960_ProgressLevel)
     {
-      strcpy(Controller->RebuildProgressBuffer, Buffer);
-      Controller->RebuildProgressLength = Length;
+      strcpy(Controller->ProgressBuffer, Buffer);
+      Controller->ProgressBufferLength = Length;
       if (Controller->EphemeralProgressMessage)
 	{
 	  if (jiffies - Controller->LastProgressReportTime
@@ -3138,15 +5817,15 @@
 
 
 /*
-  DAC960_ParsePhysicalDrive parses spaces followed by a Physical Drive
+  DAC960_ParsePhysicalDevice parses spaces followed by a Physical Device
   Channel:TargetID specification from a User Command string.  It updates
-  Channel and TargetID and returns true on success and returns false otherwise.
+  Channel and TargetID and returns true on success and false on failure.
 */
 
-static boolean DAC960_ParsePhysicalDrive(DAC960_Controller_T *Controller,
-					 char *UserCommandString,
-					 unsigned char *Channel,
-					 unsigned char *TargetID)
+static boolean DAC960_ParsePhysicalDevice(DAC960_Controller_T *Controller,
+					  char *UserCommandString,
+					  unsigned char *Channel,
+					  unsigned char *TargetID)
 {
   char *NewUserCommandString = UserCommandString;
   unsigned long XChannel, XTargetID;
@@ -3162,7 +5841,7 @@
   XTargetID = simple_strtoul(UserCommandString, &NewUserCommandString, 10);
   if (NewUserCommandString == UserCommandString ||
       *NewUserCommandString != '\0' ||
-      XTargetID >= DAC960_MaxTargets)
+      XTargetID >= Controller->Targets)
     return false;
   *Channel = XChannel;
   *TargetID = XTargetID;
@@ -3173,7 +5852,7 @@
 /*
   DAC960_ParseLogicalDrive parses spaces followed by a Logical Drive Number
   specification from a User Command string.  It updates LogicalDriveNumber and
-  returns true on success and returns false otherwise.
+  returns true on success and false on failure.
 */
 
 static boolean DAC960_ParseLogicalDrive(DAC960_Controller_T *Controller,
@@ -3189,7 +5868,7 @@
     simple_strtoul(UserCommandString, &NewUserCommandString, 10);
   if (NewUserCommandString == UserCommandString ||
       *NewUserCommandString != '\0' ||
-      XLogicalDriveNumber >= Controller->LogicalDriveCount)
+      XLogicalDriveNumber > DAC960_MaxLogicalDrives - 1)
     return false;
   *LogicalDriveNumber = XLogicalDriveNumber;
   return true;
@@ -3197,68 +5876,71 @@
 
 
 /*
-  DAC960_SetDeviceState sets the Device State for a Physical Drive.
+  DAC960_V1_SetDeviceState sets the Device State for a Physical Device for
+  DAC960 V1 Firmware Controllers.
 */
 
-static void DAC960_SetDeviceState(DAC960_Controller_T *Controller,
-				  DAC960_Command_T *Command,
-				  unsigned char Channel,
-				  unsigned char TargetID,
-				  DAC960_PhysicalDeviceState_T DeviceState,
-				  const char *DeviceStateString)
+static void DAC960_V1_SetDeviceState(DAC960_Controller_T *Controller,
+				     DAC960_Command_T *Command,
+				     unsigned char Channel,
+				     unsigned char TargetID,
+				     DAC960_V1_PhysicalDeviceState_T
+				       DeviceState,
+				     const unsigned char *DeviceStateString)
 {
-  DAC960_CommandMailbox_T *CommandMailbox = &Command->CommandMailbox;
-  CommandMailbox->Type3D.CommandOpcode = DAC960_StartDevice;
+  DAC960_V1_CommandMailbox_T *CommandMailbox = &Command->V1.CommandMailbox;
+  CommandMailbox->Type3D.CommandOpcode = DAC960_V1_StartDevice;
   CommandMailbox->Type3D.Channel = Channel;
   CommandMailbox->Type3D.TargetID = TargetID;
   CommandMailbox->Type3D.DeviceState = DeviceState;
   CommandMailbox->Type3D.Modifier = 0;
   DAC960_ExecuteCommand(Command);
-  switch (Command->CommandStatus)
+  switch (Command->V1.CommandStatus)
     {
-    case DAC960_NormalCompletion:
-      DAC960_UserCritical("%s of Physical Drive %d:%d Succeeded\n", Controller,
+    case DAC960_V1_NormalCompletion:
+      DAC960_UserCritical("%s of Physical Device %d:%d Succeeded\n", Controller,
 			  DeviceStateString, Channel, TargetID);
       break;
-    case DAC960_UnableToStartDevice:
-      DAC960_UserCritical("%s of Physical Drive %d:%d Failed - "
+    case DAC960_V1_UnableToStartDevice:
+      DAC960_UserCritical("%s of Physical Device %d:%d Failed - "
 			  "Unable to Start Device\n", Controller,
 			  DeviceStateString, Channel, TargetID);
       break;
-    case DAC960_NoDeviceAtAddress:
-      DAC960_UserCritical("%s of Physical Drive %d:%d Failed - "
+    case DAC960_V1_NoDeviceAtAddress:
+      DAC960_UserCritical("%s of Physical Device %d:%d Failed - "
 			  "No Device at Address\n", Controller,
 			  DeviceStateString, Channel, TargetID);
       break;
-    case DAC960_InvalidChannelOrTargetOrModifier:
-      DAC960_UserCritical("%s of Physical Drive %d:%d Failed - "
+    case DAC960_V1_InvalidChannelOrTargetOrModifier:
+      DAC960_UserCritical("%s of Physical Device %d:%d Failed - "
 			  "Invalid Channel or Target or Modifier\n",
 			  Controller, DeviceStateString, Channel, TargetID);
       break;
-    case DAC960_ChannelBusy:
-      DAC960_UserCritical("%s of Physical Drive %d:%d Failed - "
+    case DAC960_V1_ChannelBusy:
+      DAC960_UserCritical("%s of Physical Device %d:%d Failed - "
 			  "Channel Busy\n", Controller,
 			  DeviceStateString, Channel, TargetID);
       break;
     default:
-      DAC960_UserCritical("%s of Physical Drive %d:%d Failed - "
+      DAC960_UserCritical("%s of Physical Device %d:%d Failed - "
 			  "Unexpected Status %04X\n", Controller,
 			  DeviceStateString, Channel, TargetID,
-			  Command->CommandStatus);
+			  Command->V1.CommandStatus);
       break;
     }
 }
 
 
 /*
-  DAC960_ExecuteUserCommand executes a User Command.
+  DAC960_V1_ExecuteUserCommand executes a User Command for DAC960 V1 Firmware
+  Controllers.
 */
 
-static boolean DAC960_ExecuteUserCommand(DAC960_Controller_T *Controller,
-					 char *UserCommand)
+static boolean DAC960_V1_ExecuteUserCommand(DAC960_Controller_T *Controller,
+					    unsigned char *UserCommand)
 {
   DAC960_Command_T *Command;
-  DAC960_CommandMailbox_T *CommandMailbox;
+  DAC960_V1_CommandMailbox_T *CommandMailbox;
   ProcessorFlags_T ProcessorFlags;
   unsigned char Channel, TargetID, LogicalDriveNumber;
   DAC960_AcquireControllerLock(Controller, &ProcessorFlags);
@@ -3266,100 +5948,98 @@
     DAC960_WaitForCommand(Controller);
   DAC960_ReleaseControllerLock(Controller, &ProcessorFlags);
   Controller->UserStatusLength = 0;
-  DAC960_ClearCommand(Command);
+  DAC960_V1_ClearCommand(Command);
   Command->CommandType = DAC960_ImmediateCommand;
-  CommandMailbox = &Command->CommandMailbox;
+  CommandMailbox = &Command->V1.CommandMailbox;
   if (strcmp(UserCommand, "flush-cache") == 0)
     {
-      CommandMailbox->Type3.CommandOpcode = DAC960_Flush;
+      CommandMailbox->Type3.CommandOpcode = DAC960_V1_Flush;
       DAC960_ExecuteCommand(Command);
       DAC960_UserCritical("Cache Flush Completed\n", Controller);
     }
   else if (strncmp(UserCommand, "kill", 4) == 0 &&
-	   DAC960_ParsePhysicalDrive(Controller, &UserCommand[4],
-				     &Channel, &TargetID))
+	   DAC960_ParsePhysicalDevice(Controller, &UserCommand[4],
+				      &Channel, &TargetID))
     {
-      DAC960_DeviceState_T *DeviceState =
-	&Controller->DeviceState[Controller->DeviceStateIndex]
-				[Channel][TargetID];
+      DAC960_V1_DeviceState_T *DeviceState =
+	&Controller->V1.DeviceState[Channel][TargetID];
       if (DeviceState->Present &&
-	  DeviceState->DeviceType == DAC960_DiskType &&
-	  DeviceState->DeviceState != DAC960_Device_Dead)
-	DAC960_SetDeviceState(Controller, Command, Channel, TargetID,
-			      DAC960_Device_Dead, "Kill");
-      else DAC960_UserCritical("Kill of Physical Drive %d:%d Illegal\n",
+	  DeviceState->DeviceType == DAC960_V1_DiskType &&
+	  DeviceState->DeviceState != DAC960_V1_Device_Dead)
+	DAC960_V1_SetDeviceState(Controller, Command, Channel, TargetID,
+				 DAC960_V1_Device_Dead, "Kill");
+      else DAC960_UserCritical("Kill of Physical Device %d:%d Illegal\n",
 			       Controller, Channel, TargetID);
     }
   else if (strncmp(UserCommand, "make-online", 11) == 0 &&
-	   DAC960_ParsePhysicalDrive(Controller, &UserCommand[11],
-				     &Channel, &TargetID))
+	   DAC960_ParsePhysicalDevice(Controller, &UserCommand[11],
+				      &Channel, &TargetID))
     {
-      DAC960_DeviceState_T *DeviceState =
-	&Controller->DeviceState[Controller->DeviceStateIndex]
-				[Channel][TargetID];
+      DAC960_V1_DeviceState_T *DeviceState =
+	&Controller->V1.DeviceState[Channel][TargetID];
       if (DeviceState->Present &&
-	  DeviceState->DeviceType == DAC960_DiskType &&
-	  DeviceState->DeviceState == DAC960_Device_Dead)
-	DAC960_SetDeviceState(Controller, Command, Channel, TargetID,
-			      DAC960_Device_Online, "Make Online");
-      else DAC960_UserCritical("Make Online of Physical Drive %d:%d Illegal\n",
+	  DeviceState->DeviceType == DAC960_V1_DiskType &&
+	  DeviceState->DeviceState == DAC960_V1_Device_Dead)
+	DAC960_V1_SetDeviceState(Controller, Command, Channel, TargetID,
+				 DAC960_V1_Device_Online, "Make Online");
+      else DAC960_UserCritical("Make Online of Physical Device %d:%d Illegal\n",
 			       Controller, Channel, TargetID);
 
     }
   else if (strncmp(UserCommand, "make-standby", 12) == 0 &&
-	   DAC960_ParsePhysicalDrive(Controller, &UserCommand[12],
-				     &Channel, &TargetID))
+	   DAC960_ParsePhysicalDevice(Controller, &UserCommand[12],
+				      &Channel, &TargetID))
     {
-      DAC960_DeviceState_T *DeviceState =
-	&Controller->DeviceState[Controller->DeviceStateIndex]
-				[Channel][TargetID];
+      DAC960_V1_DeviceState_T *DeviceState =
+	&Controller->V1.DeviceState[Channel][TargetID];
       if (DeviceState->Present &&
-	  DeviceState->DeviceType == DAC960_DiskType &&
-	  DeviceState->DeviceState == DAC960_Device_Dead)
-	DAC960_SetDeviceState(Controller, Command, Channel, TargetID,
-			      DAC960_Device_Standby, "Make Standby");
-      else DAC960_UserCritical("Make Standby of Physical Drive %d:%d Illegal\n",
+	  DeviceState->DeviceType == DAC960_V1_DiskType &&
+	  DeviceState->DeviceState == DAC960_V1_Device_Dead)
+	DAC960_V1_SetDeviceState(Controller, Command, Channel, TargetID,
+				 DAC960_V1_Device_Standby, "Make Standby");
+      else DAC960_UserCritical("Make Standby of Physical "
+			       "Device %d:%d Illegal\n",
 			       Controller, Channel, TargetID);
     }
   else if (strncmp(UserCommand, "rebuild", 7) == 0 &&
-	   DAC960_ParsePhysicalDrive(Controller, &UserCommand[7],
-				     &Channel, &TargetID))
+	   DAC960_ParsePhysicalDevice(Controller, &UserCommand[7],
+				      &Channel, &TargetID))
     {
-      CommandMailbox->Type3D.CommandOpcode = DAC960_RebuildAsync;
+      CommandMailbox->Type3D.CommandOpcode = DAC960_V1_RebuildAsync;
       CommandMailbox->Type3D.Channel = Channel;
       CommandMailbox->Type3D.TargetID = TargetID;
       DAC960_ExecuteCommand(Command);
-      switch (Command->CommandStatus)
+      switch (Command->V1.CommandStatus)
 	{
-	case DAC960_NormalCompletion:
-	  DAC960_UserCritical("Rebuild of Physical Drive %d:%d Initiated\n",
+	case DAC960_V1_NormalCompletion:
+	  DAC960_UserCritical("Rebuild of Physical Device %d:%d Initiated\n",
 			      Controller, Channel, TargetID);
 	  break;
-	case DAC960_AttemptToRebuildOnlineDrive:
-	  DAC960_UserCritical("Rebuild of Physical Drive %d:%d Failed - "
+	case DAC960_V1_AttemptToRebuildOnlineDrive:
+	  DAC960_UserCritical("Rebuild of Physical Device %d:%d Failed - "
 			      "Attempt to Rebuild Online or "
 			      "Unresponsive Drive\n",
 			      Controller, Channel, TargetID);
 	  break;
-	case DAC960_NewDiskFailedDuringRebuild:
-	  DAC960_UserCritical("Rebuild of Physical Drive %d:%d Failed - "
+	case DAC960_V1_NewDiskFailedDuringRebuild:
+	  DAC960_UserCritical("Rebuild of Physical Device %d:%d Failed - "
 			      "New Disk Failed During Rebuild\n",
 			      Controller, Channel, TargetID);
 	  break;
-	case DAC960_InvalidDeviceAddress:
-	  DAC960_UserCritical("Rebuild of Physical Drive %d:%d Failed - "
+	case DAC960_V1_InvalidDeviceAddress:
+	  DAC960_UserCritical("Rebuild of Physical Device %d:%d Failed - "
 			      "Invalid Device Address\n",
 			      Controller, Channel, TargetID);
 	  break;
-	case DAC960_RebuildOrCheckAlreadyInProgress:
-	  DAC960_UserCritical("Rebuild of Physical Drive %d:%d Failed - "
+	case DAC960_V1_RebuildOrCheckAlreadyInProgress:
+	  DAC960_UserCritical("Rebuild of Physical Device %d:%d Failed - "
 			      "Rebuild or Consistency Check Already "
 			      "in Progress\n", Controller, Channel, TargetID);
 	  break;
 	default:
-	  DAC960_UserCritical("Rebuild of Physical Drive %d:%d Failed - "
+	  DAC960_UserCritical("Rebuild of Physical Device %d:%d Failed - "
 			      "Unexpected Status %04X\n", Controller,
-			      Channel, TargetID, Command->CommandStatus);
+			      Channel, TargetID, Command->V1.CommandStatus);
 	  break;
 	}
     }
@@ -3367,28 +6047,28 @@
 	   DAC960_ParseLogicalDrive(Controller, &UserCommand[17],
 				    &LogicalDriveNumber))
     {
-      CommandMailbox->Type3C.CommandOpcode = DAC960_CheckConsistencyAsync;
+      CommandMailbox->Type3C.CommandOpcode = DAC960_V1_CheckConsistencyAsync;
       CommandMailbox->Type3C.LogicalDriveNumber = LogicalDriveNumber;
       CommandMailbox->Type3C.AutoRestore = true;
       DAC960_ExecuteCommand(Command);
-      switch (Command->CommandStatus)
+      switch (Command->V1.CommandStatus)
 	{
-	case DAC960_NormalCompletion:
+	case DAC960_V1_NormalCompletion:
 	  DAC960_UserCritical("Consistency Check of Logical Drive %d "
 			      "(/dev/rd/c%dd%d) Initiated\n",
 			      Controller, LogicalDriveNumber,
 			      Controller->ControllerNumber,
 			      LogicalDriveNumber);
 	  break;
-	case DAC960_DependentDiskIsDead:
+	case DAC960_V1_DependentDiskIsDead:
 	  DAC960_UserCritical("Consistency Check of Logical Drive %d "
 			      "(/dev/rd/c%dd%d) Failed - "
-			      "Dependent Physical Drive is DEAD\n",
+			      "Dependent Physical Device is DEAD\n",
 			      Controller, LogicalDriveNumber,
 			      Controller->ControllerNumber,
 			      LogicalDriveNumber);
 	  break;
-	case DAC960_InvalidOrNonredundantLogicalDrive:
+	case DAC960_V1_InvalidOrNonredundantLogicalDrive:
 	  DAC960_UserCritical("Consistency Check of Logical Drive %d "
 			      "(/dev/rd/c%dd%d) Failed - "
 			      "Invalid or Nonredundant Logical Drive\n",
@@ -3396,7 +6076,7 @@
 			      Controller->ControllerNumber,
 			      LogicalDriveNumber);
 	  break;
-	case DAC960_RebuildOrCheckAlreadyInProgress:
+	case DAC960_V1_RebuildOrCheckAlreadyInProgress:
 	  DAC960_UserCritical("Consistency Check of Logical Drive %d "
 			      "(/dev/rd/c%dd%d) Failed - Rebuild or "
 			      "Consistency Check Already in Progress\n",
@@ -3410,7 +6090,7 @@
 			      "Unexpected Status %04X\n",
 			      Controller, LogicalDriveNumber,
 			      Controller->ControllerNumber,
-			      LogicalDriveNumber, Command->CommandStatus);
+			      LogicalDriveNumber, Command->V1.CommandStatus);
 	  break;
 	}
     }
@@ -3418,14 +6098,14 @@
 	   strcmp(UserCommand, "cancel-consistency-check") == 0)
     {
       unsigned char OldRebuildRateConstant;
-      CommandMailbox->Type3R.CommandOpcode = DAC960_RebuildControl;
+      CommandMailbox->Type3R.CommandOpcode = DAC960_V1_RebuildControl;
       CommandMailbox->Type3R.RebuildRateConstant = 0xFF;
       CommandMailbox->Type3R.BusAddress =
 	Virtual_to_Bus(&OldRebuildRateConstant);
       DAC960_ExecuteCommand(Command);
-      switch (Command->CommandStatus)
+      switch (Command->V1.CommandStatus)
 	{
-	case DAC960_NormalCompletion:
+	case DAC960_V1_NormalCompletion:
 	  DAC960_UserCritical("Rebuild or Consistency Check Cancelled\n",
 			      Controller);
 	  break;
@@ -3433,7 +6113,7 @@
 	  DAC960_UserCritical("Cancellation of Rebuild or "
 			      "Consistency Check Failed - "
 			      "Unexpected Status %04X\n",
-			      Controller, Command->CommandStatus);
+			      Controller, Command->V1.CommandStatus);
 	  break;
 	}
     }
@@ -3447,25 +6127,235 @@
 
 
 /*
+  DAC960_V2_TranslatePhysicalDevice translates a Physical Device Channel and
+  TargetID into a Logical Device.  It returns true on success and false
+  on failure.
+*/
+
+static boolean DAC960_V2_TranslatePhysicalDevice(DAC960_Command_T *Command,
+						 unsigned char Channel,
+						 unsigned char TargetID,
+						 unsigned short
+						   *LogicalDeviceNumber)
+{
+  DAC960_V2_CommandMailbox_T SavedCommandMailbox, *CommandMailbox;
+  DAC960_V2_PhysicalToLogicalDevice_T PhysicalToLogicalDevice;
+  CommandMailbox = &Command->V2.CommandMailbox;
+  memcpy(&SavedCommandMailbox, CommandMailbox,
+	 sizeof(DAC960_V2_CommandMailbox_T));
+  CommandMailbox->PhysicalDeviceInfo.CommandOpcode = DAC960_V2_IOCTL;
+  CommandMailbox->PhysicalDeviceInfo.CommandControlBits
+				    .DataTransferControllerToHost = true;
+  CommandMailbox->PhysicalDeviceInfo.CommandControlBits
+				    .NoAutoRequestSense = true;
+  CommandMailbox->PhysicalDeviceInfo.DataTransferSize =
+    sizeof(DAC960_V2_PhysicalToLogicalDevice_T);
+  CommandMailbox->PhysicalDeviceInfo.PhysicalDevice.TargetID = TargetID;
+  CommandMailbox->PhysicalDeviceInfo.PhysicalDevice.Channel = Channel;
+  CommandMailbox->PhysicalDeviceInfo.IOCTL_Opcode =
+    DAC960_V2_TranslatePhysicalToLogicalDevice;
+  CommandMailbox->Common.DataTransferMemoryAddress
+			.ScatterGatherSegments[0]
+			.SegmentDataPointer =
+    Virtual_to_Bus(&PhysicalToLogicalDevice);
+  CommandMailbox->Common.DataTransferMemoryAddress
+			.ScatterGatherSegments[0]
+			.SegmentByteCount =
+    CommandMailbox->Common.DataTransferSize;
+  DAC960_ExecuteCommand(Command);
+  memcpy(CommandMailbox, &SavedCommandMailbox,
+	 sizeof(DAC960_V2_CommandMailbox_T));
+  *LogicalDeviceNumber = PhysicalToLogicalDevice.LogicalDeviceNumber;
+  return (Command->V2.CommandStatus == DAC960_V2_NormalCompletion);
+}
+
+
+/*
+  DAC960_V2_ExecuteUserCommand executes a User Command for DAC960 V2 Firmware
+  Controllers.
+*/
+
+static boolean DAC960_V2_ExecuteUserCommand(DAC960_Controller_T *Controller,
+					    unsigned char *UserCommand)
+{
+  DAC960_Command_T *Command;
+  DAC960_V2_CommandMailbox_T *CommandMailbox;
+  ProcessorFlags_T ProcessorFlags;
+  unsigned char Channel, TargetID, LogicalDriveNumber;
+  unsigned short LogicalDeviceNumber;
+  DAC960_AcquireControllerLock(Controller, &ProcessorFlags);
+  while ((Command = DAC960_AllocateCommand(Controller)) == NULL)
+    DAC960_WaitForCommand(Controller);
+  DAC960_ReleaseControllerLock(Controller, &ProcessorFlags);
+  Controller->UserStatusLength = 0;
+  DAC960_V2_ClearCommand(Command);
+  Command->CommandType = DAC960_ImmediateCommand;
+  CommandMailbox = &Command->V2.CommandMailbox;
+  CommandMailbox->Common.CommandOpcode = DAC960_V2_IOCTL;
+  CommandMailbox->Common.CommandControlBits.DataTransferControllerToHost = true;
+  CommandMailbox->Common.CommandControlBits.NoAutoRequestSense = true;
+  if (strcmp(UserCommand, "flush-cache") == 0)
+    {
+      CommandMailbox->DeviceOperation.IOCTL_Opcode = DAC960_V2_PauseDevice;
+      CommandMailbox->DeviceOperation.OperationDevice =
+	DAC960_V2_RAID_Controller;
+      DAC960_ExecuteCommand(Command);
+      DAC960_UserCritical("Cache Flush Completed\n", Controller);
+    }
+  else if (strncmp(UserCommand, "kill", 4) == 0 &&
+	   DAC960_ParsePhysicalDevice(Controller, &UserCommand[4],
+				      &Channel, &TargetID) &&
+	   DAC960_V2_TranslatePhysicalDevice(Command, Channel, TargetID,
+					     &LogicalDeviceNumber))
+    {
+      CommandMailbox->SetDeviceState.LogicalDevice.LogicalDeviceNumber =
+	LogicalDeviceNumber;
+      CommandMailbox->SetDeviceState.IOCTL_Opcode =
+	DAC960_V2_SetDeviceState;
+      CommandMailbox->SetDeviceState.DeviceState.PhysicalDeviceState =
+	DAC960_V2_Device_Dead;
+      DAC960_ExecuteCommand(Command);
+      DAC960_UserCritical("Kill of Physical Device %d:%d %s\n",
+			  Controller, Channel, TargetID,
+			  (Command->V2.CommandStatus
+			   == DAC960_V2_NormalCompletion
+			   ? "Succeeded" : "Failed"));
+    }
+  else if (strncmp(UserCommand, "make-online", 11) == 0 &&
+	   DAC960_ParsePhysicalDevice(Controller, &UserCommand[11],
+				      &Channel, &TargetID) &&
+	   DAC960_V2_TranslatePhysicalDevice(Command, Channel, TargetID,
+					     &LogicalDeviceNumber))
+    {
+      CommandMailbox->SetDeviceState.LogicalDevice.LogicalDeviceNumber =
+	LogicalDeviceNumber;
+      CommandMailbox->SetDeviceState.IOCTL_Opcode =
+	DAC960_V2_SetDeviceState;
+      CommandMailbox->SetDeviceState.DeviceState.PhysicalDeviceState =
+	DAC960_V2_Device_Online;
+      DAC960_ExecuteCommand(Command);
+      DAC960_UserCritical("Make Online of Physical Device %d:%d %s\n",
+			  Controller, Channel, TargetID,
+			  (Command->V2.CommandStatus
+			   == DAC960_V2_NormalCompletion
+			   ? "Succeeded" : "Failed"));
+    }
+  else if (strncmp(UserCommand, "make-standby", 12) == 0 &&
+	   DAC960_ParsePhysicalDevice(Controller, &UserCommand[12],
+				      &Channel, &TargetID) &&
+	   DAC960_V2_TranslatePhysicalDevice(Command, Channel, TargetID,
+					     &LogicalDeviceNumber))
+    {
+      CommandMailbox->SetDeviceState.LogicalDevice.LogicalDeviceNumber =
+	LogicalDeviceNumber;
+      CommandMailbox->SetDeviceState.IOCTL_Opcode =
+	DAC960_V2_SetDeviceState;
+      CommandMailbox->SetDeviceState.DeviceState.PhysicalDeviceState =
+	DAC960_V2_Device_Standby;
+      DAC960_ExecuteCommand(Command);
+      DAC960_UserCritical("Make Standby of Physical Device %d:%d %s\n",
+			  Controller, Channel, TargetID,
+			  (Command->V2.CommandStatus
+			   == DAC960_V2_NormalCompletion
+			   ? "Succeeded" : "Failed"));
+    }
+  else if (strncmp(UserCommand, "rebuild", 7) == 0 &&
+	   DAC960_ParsePhysicalDevice(Controller, &UserCommand[7],
+				      &Channel, &TargetID) &&
+	   DAC960_V2_TranslatePhysicalDevice(Command, Channel, TargetID,
+					     &LogicalDeviceNumber))
+    {
+      CommandMailbox->LogicalDeviceInfo.LogicalDevice.LogicalDeviceNumber =
+	LogicalDeviceNumber;
+      CommandMailbox->LogicalDeviceInfo.IOCTL_Opcode =
+	DAC960_V2_RebuildDeviceStart;
+      DAC960_ExecuteCommand(Command);
+      DAC960_UserCritical("Rebuild of Physical Device %d:%d %s\n",
+			  Controller, Channel, TargetID,
+			  (Command->V2.CommandStatus
+			   == DAC960_V2_NormalCompletion
+			   ? "Initiated" : "Not Initiated"));
+    }
+  else if (strncmp(UserCommand, "cancel-rebuild", 14) == 0 &&
+	   DAC960_ParsePhysicalDevice(Controller, &UserCommand[14],
+				      &Channel, &TargetID) &&
+	   DAC960_V2_TranslatePhysicalDevice(Command, Channel, TargetID,
+					     &LogicalDeviceNumber))
+    {
+      CommandMailbox->LogicalDeviceInfo.LogicalDevice.LogicalDeviceNumber =
+	LogicalDeviceNumber;
+      CommandMailbox->LogicalDeviceInfo.IOCTL_Opcode =
+	DAC960_V2_RebuildDeviceStop;
+      DAC960_ExecuteCommand(Command);
+      DAC960_UserCritical("Rebuild of Physical Device %d:%d %s\n",
+			  Controller, Channel, TargetID,
+			  (Command->V2.CommandStatus
+			   == DAC960_V2_NormalCompletion
+			   ? "Cancelled" : "Not Cancelled"));
+    }
+  else if (strncmp(UserCommand, "check-consistency", 17) == 0 &&
+	   DAC960_ParseLogicalDrive(Controller, &UserCommand[17],
+				    &LogicalDriveNumber))
+    {
+      CommandMailbox->ConsistencyCheck.LogicalDevice.LogicalDeviceNumber =
+	LogicalDriveNumber;
+      CommandMailbox->ConsistencyCheck.IOCTL_Opcode =
+	DAC960_V2_ConsistencyCheckStart;
+      CommandMailbox->ConsistencyCheck.RestoreConsistency = true;
+      CommandMailbox->ConsistencyCheck.InitializedAreaOnly = false;
+      DAC960_ExecuteCommand(Command);
+      DAC960_UserCritical("Consistency Check of Logical Drive %d "
+			  "(/dev/rd/c%dd%d) %s\n",
+			  Controller, LogicalDriveNumber,
+			  Controller->ControllerNumber,
+			  LogicalDriveNumber,
+			  (Command->V2.CommandStatus
+			   == DAC960_V2_NormalCompletion
+			   ? "Initiated" : "Not Initiated"));
+    }
+  else if (strncmp(UserCommand, "cancel-consistency-check", 24) == 0 &&
+	   DAC960_ParseLogicalDrive(Controller, &UserCommand[24],
+				    &LogicalDriveNumber))
+    {
+      CommandMailbox->ConsistencyCheck.LogicalDevice.LogicalDeviceNumber =
+	LogicalDriveNumber;
+      CommandMailbox->ConsistencyCheck.IOCTL_Opcode =
+	DAC960_V2_ConsistencyCheckStop;
+      DAC960_ExecuteCommand(Command);
+      DAC960_UserCritical("Consistency Check of Logical Drive %d "
+			  "(/dev/rd/c%dd%d) %s\n",
+			  Controller, LogicalDriveNumber,
+			  Controller->ControllerNumber,
+			  LogicalDriveNumber,
+			  (Command->V2.CommandStatus
+			   == DAC960_V2_NormalCompletion
+			   ? "Cancelled" : "Not Cancelled"));
+    }
+  else DAC960_UserCritical("Illegal User Command: '%s'\n",
+			   Controller, UserCommand);
+  DAC960_AcquireControllerLock(Controller, &ProcessorFlags);
+  DAC960_DeallocateCommand(Command);
+  DAC960_ReleaseControllerLock(Controller, &ProcessorFlags);
+  return true;
+}
+
+
+/*
   DAC960_ProcReadStatus implements reading /proc/rd/status.
 */
 
 static int DAC960_ProcReadStatus(char *Page, char **Start, off_t Offset,
 				 int Count, int *EOF, void *Data)
 {
-  char *StatusMessage = "OK\n";
+  unsigned char *StatusMessage = "OK\n";
   int ControllerNumber, BytesAvailable;
   for (ControllerNumber = 0;
        ControllerNumber < DAC960_ControllerCount;
        ControllerNumber++)
     {
       DAC960_Controller_T *Controller = DAC960_Controllers[ControllerNumber];
-      DAC960_Enquiry_T *Enquiry;
       if (Controller == NULL) continue;
-      Enquiry = &Controller->Enquiry[Controller->EnquiryIndex];
-      if (Enquiry->CriticalLogicalDriveCount > 0 ||
-	  Enquiry->OfflineLogicalDriveCount > 0 ||
-	  Enquiry->DeadDriveCount > 0)
+      if (Controller->MonitoringAlertMode)
 	{
 	  StatusMessage = "ALERT\n";
 	  break;
@@ -3500,7 +6390,7 @@
     }
   if (Count <= 0) return 0;
   *Start = Page;
-  memcpy(Page, &Controller->InitialStatusBuffer[Offset], Count);
+  memcpy(Page, &Controller->CombinedStatusBuffer[Offset], Count);
   return Count;
 }
 
@@ -3513,6 +6403,9 @@
 					int Count, int *EOF, void *Data)
 {
   DAC960_Controller_T *Controller = (DAC960_Controller_T *) Data;
+  unsigned char *StatusMessage =
+    "No Rebuild or Consistency Check in Progress\n";
+  int ProgressMessageLength = strlen(StatusMessage);
   int BytesAvailable;
   if (jiffies != Controller->LastCurrentStatusTime)
     {
@@ -3520,22 +6413,20 @@
       DAC960_AnnounceDriver(Controller);
       DAC960_ReportControllerConfiguration(Controller);
       DAC960_ReportDeviceConfiguration(Controller);
-      Controller->CurrentStatusBuffer[Controller->CurrentStatusLength++] = ' ';
-      Controller->CurrentStatusBuffer[Controller->CurrentStatusLength++] = ' ';
-      if (Controller->RebuildProgressLength > 0)
-	{
-	  strcpy(&Controller->CurrentStatusBuffer
-			      [Controller->CurrentStatusLength],
-		 Controller->RebuildProgressBuffer);
-	  Controller->CurrentStatusLength += Controller->RebuildProgressLength;
-	}
-      else
-	{
-	  char *StatusMessage = "No Rebuild or Consistency Check in Progress\n";
-	  strcpy(&Controller->CurrentStatusBuffer
-			      [Controller->CurrentStatusLength],
-		 StatusMessage);
-	  Controller->CurrentStatusLength += strlen(StatusMessage);
+      if (Controller->ProgressBufferLength > 0)
+	ProgressMessageLength = Controller->ProgressBufferLength;
+      if (DAC960_CheckStatusBuffer(Controller, 2 + ProgressMessageLength))
+	{
+	  unsigned char *CurrentStatusBuffer = Controller->CurrentStatusBuffer;
+	  CurrentStatusBuffer[Controller->CurrentStatusLength++] = ' ';
+	  CurrentStatusBuffer[Controller->CurrentStatusLength++] = ' ';
+	  if (Controller->ProgressBufferLength > 0)
+	    strcpy(&CurrentStatusBuffer[Controller->CurrentStatusLength],
+		   Controller->ProgressBuffer);
+	  else
+	    strcpy(&CurrentStatusBuffer[Controller->CurrentStatusLength],
+		   StatusMessage);
+	  Controller->CurrentStatusLength += ProgressMessageLength;
 	}
       Controller->LastCurrentStatusTime = jiffies;
     }
@@ -3581,7 +6472,7 @@
 				       unsigned long Count, void *Data)
 {
   DAC960_Controller_T *Controller = (DAC960_Controller_T *) Data;
-  char CommandBuffer[80];
+  unsigned char CommandBuffer[80];
   int Length;
   if (Count > sizeof(CommandBuffer)-1) return -EINVAL;
   copy_from_user(CommandBuffer, Buffer, Count);
@@ -3589,8 +6480,12 @@
   Length = strlen(CommandBuffer);
   if (CommandBuffer[Length-1] == '\n')
     CommandBuffer[--Length] = '\0';
-  return (DAC960_ExecuteUserCommand(Controller, CommandBuffer)
-	  ? Count : -EBUSY);
+  if (Controller->FirmwareType == DAC960_V1_Controller)
+    return (DAC960_V1_ExecuteUserCommand(Controller, CommandBuffer)
+	    ? Count : -EBUSY);
+  else
+    return (DAC960_V2_ExecuteUserCommand(Controller, CommandBuffer)
+	    ? Count : -EBUSY);
 }
 
 
Index: oldkernel/linux/drivers/block/DAC960.h
diff -u linux/drivers/block/DAC960.h:1.2 linux/drivers/block/DAC960.h:1.3
--- linux/drivers/block/DAC960.h:1.2	Wed May 31 14:57:57 2000
+++ linux/drivers/block/DAC960.h	Fri Jul  7 15:36:42 2000
@@ -1,8 +1,8 @@
 /*
 
-  Linux Driver for Mylex DAC960 and DAC1100 PCI RAID Controllers
+  Linux Driver for Mylex DAC960/AcceleRAID/eXtremeRAID PCI RAID Controllers
 
-  Copyright 1998-1999 by Leonard N. Zubkoff <lnz@dandelion.com>
+  Copyright 1998-2000 by Leonard N. Zubkoff <lnz@dandelion.com>
 
   This program is free software; you may redistribute and/or modify it under
   the terms of the GNU General Public License Version 2 as published by the
@@ -27,27 +27,41 @@
 
 
 /*
-  Define the maximum number of Controller Channels supported by this driver.
+  Define the maximum number of Controller Channels supported by DAC960
+  V1 and V2 Firmware Controllers.
 */
 
-#define DAC960_MaxChannels			3
+#define DAC960_V1_MaxChannels			3
+#define DAC960_V2_MaxChannels			4
 
 
 /*
-  Define the maximum number of Targets per Channel supported by this driver.
+  Define the maximum number of Targets per Channel supported by DAC960
+  V1 and V2 Firmware Controllers.
 */
 
-#define DAC960_MaxTargets			16
+#define DAC960_V1_MaxTargets			16
+#define DAC960_V2_MaxTargets			128
 
 
 /*
-  Define the maximum number of Logical Drives supported by any DAC960 model.
+  Define the maximum number of Logical Drives supported by DAC960
+  V1 and V2 Firmware Controllers.
 */
 
 #define DAC960_MaxLogicalDrives			32
 
 
 /*
+  Define the maximum number of Physical Devices supported by DAC960
+  V1 and V2 Firmware Controllers.
+*/
+
+#define DAC960_V1_MaxPhysicalDevices		45
+#define DAC960_V2_MaxPhysicalDevices		272
+
+
+/*
   Define a Boolean data type.
 */
 
@@ -71,150 +85,265 @@
 /*
   Define a 32 bit Bus Address data type.
 */
+
+typedef unsigned int DAC960_BusAddress32_T;
+
+
+/*
+  Define a 64 bit Bus Address data type.
+*/
 
-typedef unsigned int DAC960_BusAddress_T;
+typedef unsigned long long DAC960_BusAddress64_T;
 
 
 /*
   Define a 32 bit Byte Count data type.
 */
+
+typedef unsigned int DAC960_ByteCount32_T;
+
+
+/*
+  Define a 64 bit Byte Count data type.
+*/
+
+typedef unsigned long long DAC960_ByteCount64_T;
+
+
+/*
+  Define the SCSI INQUIRY Standard Data structure.
+*/
+
+typedef struct DAC960_SCSI_Inquiry
+{
+  unsigned char PeripheralDeviceType:5;			/* Byte 0 Bits 0-4 */
+  unsigned char PeripheralQualifier:3;			/* Byte 0 Bits 5-7 */
+  unsigned char DeviceTypeModifier:7;			/* Byte 1 Bits 0-6 */
+  boolean RMB:1;					/* Byte 1 Bit 7 */
+  unsigned char ANSI_ApprovedVersion:3;			/* Byte 2 Bits 0-2 */
+  unsigned char ECMA_Version:3;				/* Byte 2 Bits 3-5 */
+  unsigned char ISO_Version:2;				/* Byte 2 Bits 6-7 */
+  unsigned char ResponseDataFormat:4;			/* Byte 3 Bits 0-3 */
+  unsigned char :2;					/* Byte 3 Bits 4-5 */
+  boolean TrmIOP:1;					/* Byte 3 Bit 6 */
+  boolean AENC:1;					/* Byte 3 Bit 7 */
+  unsigned char AdditionalLength;			/* Byte 4 */
+  unsigned char :8;					/* Byte 5 */
+  unsigned char :8;					/* Byte 6 */
+  boolean SftRe:1;					/* Byte 7 Bit 0 */
+  boolean CmdQue:1;					/* Byte 7 Bit 1 */
+  boolean :1;						/* Byte 7 Bit 2 */
+  boolean Linked:1;					/* Byte 7 Bit 3 */
+  boolean Sync:1;					/* Byte 7 Bit 4 */
+  boolean WBus16:1;					/* Byte 7 Bit 5 */
+  boolean WBus32:1;					/* Byte 7 Bit 6 */
+  boolean RelAdr:1;					/* Byte 7 Bit 7 */
+  unsigned char VendorIdentification[8];		/* Bytes 8-15 */
+  unsigned char ProductIdentification[16];		/* Bytes 16-31 */
+  unsigned char ProductRevisionLevel[4];		/* Bytes 32-35 */
+}
+DAC960_SCSI_Inquiry_T;
+
+
+/*
+  Define the SCSI INQUIRY Unit Serial Number structure.
+*/
+
+typedef struct DAC960_SCSI_Inquiry_UnitSerialNumber
+{
+  unsigned char PeripheralDeviceType:5;			/* Byte 0 Bits 0-4 */
+  unsigned char PeripheralQualifier:3;			/* Byte 0 Bits 5-7 */
+  unsigned char PageCode;				/* Byte 1 */
+  unsigned char :8;					/* Byte 2 */
+  unsigned char PageLength;				/* Byte 3 */
+  unsigned char ProductSerialNumber[28];		/* Bytes 4-31 */
+}
+DAC960_SCSI_Inquiry_UnitSerialNumber_T;
+
+
+/*
+  Define the SCSI REQUEST SENSE Sense Key type.
+*/
+
+typedef enum
+{
+  DAC960_SenseKey_NoSense =			0x0,
+  DAC960_SenseKey_RecoveredError =		0x1,
+  DAC960_SenseKey_NotReady =			0x2,
+  DAC960_SenseKey_MediumError =			0x3,
+  DAC960_SenseKey_HardwareError =		0x4,
+  DAC960_SenseKey_IllegalRequest =		0x5,
+  DAC960_SenseKey_UnitAttention =		0x6,
+  DAC960_SenseKey_DataProtect =			0x7,
+  DAC960_SenseKey_BlankCheck =			0x8,
+  DAC960_SenseKey_VendorSpecific =		0x9,
+  DAC960_SenseKey_CopyAborted =			0xA,
+  DAC960_SenseKey_AbortedCommand =		0xB,
+  DAC960_SenseKey_Equal =			0xC,
+  DAC960_SenseKey_VolumeOverflow =		0xD,
+  DAC960_SenseKey_Miscompare =			0xE,
+  DAC960_SenseKey_Reserved =			0xF
+}
+__attribute__ ((packed))
+DAC960_SCSI_RequestSenseKey_T;
+
+
+/*
+  Define the SCSI REQUEST SENSE structure.
+*/
 
-typedef unsigned int DAC960_ByteCount_T;
+typedef struct DAC960_SCSI_RequestSense
+{
+  unsigned char ErrorCode:7;				/* Byte 0 Bits 0-6 */
+  boolean Valid:1;					/* Byte 0 Bit 7 */
+  unsigned char SegmentNumber;				/* Byte 1 */
+  DAC960_SCSI_RequestSenseKey_T SenseKey:4;		/* Byte 2 Bits 0-3 */
+  unsigned char :1;					/* Byte 2 Bit 4 */
+  boolean ILI:1;					/* Byte 2 Bit 5 */
+  boolean EOM:1;					/* Byte 2 Bit 6 */
+  boolean Filemark:1;					/* Byte 2 Bit 7 */
+  unsigned char Information[4];				/* Bytes 3-6 */
+  unsigned char AdditionalSenseLength;			/* Byte 7 */
+  unsigned char CommandSpecificInformation[4];		/* Bytes 8-11 */
+  unsigned char AdditionalSenseCode;			/* Byte 12 */
+  unsigned char AdditionalSenseCodeQualifier;		/* Byte 13 */
+}
+DAC960_SCSI_RequestSense_T;
 
 
 /*
-  Define the DAC960 Command Opcodes.
+  Define the DAC960 V1 Firmware Command Opcodes.
 */
 
 typedef enum
 {
   /* I/O Commands */
-  DAC960_ReadExtended =				0x33,
-  DAC960_WriteExtended =			0x34,
-  DAC960_ReadAheadExtended =			0x35,
-  DAC960_ReadExtendedWithScatterGather =	0xB3,
-  DAC960_WriteExtendedWithScatterGather =	0xB4,
-  DAC960_Read =					0x36,
-  DAC960_ReadWithOldScatterGather =		0xB6,
-  DAC960_Write =				0x37,
-  DAC960_WriteWithOldScatterGather =		0xB7,
-  DAC960_DCDB =					0x04,
-  DAC960_DCDBWithScatterGather =		0x84,
-  DAC960_Flush =				0x0A,
+  DAC960_V1_ReadExtended =			0x33,
+  DAC960_V1_WriteExtended =			0x34,
+  DAC960_V1_ReadAheadExtended =			0x35,
+  DAC960_V1_ReadExtendedWithScatterGather =	0xB3,
+  DAC960_V1_WriteExtendedWithScatterGather =	0xB4,
+  DAC960_V1_Read =				0x36,
+  DAC960_V1_ReadWithOldScatterGather =		0xB6,
+  DAC960_V1_Write =				0x37,
+  DAC960_V1_WriteWithOldScatterGather =		0xB7,
+  DAC960_V1_DCDB =				0x04,
+  DAC960_V1_DCDBWithScatterGather =		0x84,
+  DAC960_V1_Flush =				0x0A,
   /* Controller Status Related Commands */
-  DAC960_Enquiry =				0x53,
-  DAC960_Enquiry2 =				0x1C,
-  DAC960_GetLogicalDriveElement =		0x55,
-  DAC960_GetLogicalDriveInformation =		0x19,
-  DAC960_IOPortRead =				0x39,
-  DAC960_IOPortWrite =				0x3A,
-  DAC960_GetSDStats =				0x3E,
-  DAC960_GetPDStats =				0x3F,
-  DAC960_PerformEventLogOperation =		0x72,
+  DAC960_V1_Enquiry =				0x53,
+  DAC960_V1_Enquiry2 =				0x1C,
+  DAC960_V1_GetLogicalDriveElement =		0x55,
+  DAC960_V1_GetLogicalDriveInformation =	0x19,
+  DAC960_V1_IOPortRead =			0x39,
+  DAC960_V1_IOPortWrite =			0x3A,
+  DAC960_V1_GetSDStats =			0x3E,
+  DAC960_V1_GetPDStats =			0x3F,
+  DAC960_V1_PerformEventLogOperation =		0x72,
   /* Device Related Commands */
-  DAC960_StartDevice =				0x10,
-  DAC960_GetDeviceState =			0x50,
-  DAC960_StopChannel =				0x13,
-  DAC960_StartChannel =				0x12,
-  DAC960_ResetChannel =				0x1A,
+  DAC960_V1_StartDevice =			0x10,
+  DAC960_V1_GetDeviceState =			0x50,
+  DAC960_V1_StopChannel =			0x13,
+  DAC960_V1_StartChannel =			0x12,
+  DAC960_V1_ResetChannel =			0x1A,
   /* Commands Associated with Data Consistency and Errors */
-  DAC960_Rebuild =				0x09,
-  DAC960_RebuildAsync =				0x16,
-  DAC960_CheckConsistency =			0x0F,
-  DAC960_CheckConsistencyAsync =		0x1E,
-  DAC960_RebuildStat =				0x0C,
-  DAC960_GetRebuildProgress =			0x27,
-  DAC960_RebuildControl =			0x1F,
-  DAC960_ReadBadBlockTable =			0x0B,
-  DAC960_ReadBadDataTable =			0x25,
-  DAC960_ClearBadDataTable =			0x26,
-  DAC960_GetErrorTable =			0x17,
-  DAC960_AddCapacityAsync =			0x2A,
+  DAC960_V1_Rebuild =				0x09,
+  DAC960_V1_RebuildAsync =			0x16,
+  DAC960_V1_CheckConsistency =			0x0F,
+  DAC960_V1_CheckConsistencyAsync =		0x1E,
+  DAC960_V1_RebuildStat =			0x0C,
+  DAC960_V1_GetRebuildProgress =		0x27,
+  DAC960_V1_RebuildControl =			0x1F,
+  DAC960_V1_ReadBadBlockTable =			0x0B,
+  DAC960_V1_ReadBadDataTable =			0x25,
+  DAC960_V1_ClearBadDataTable =			0x26,
+  DAC960_V1_GetErrorTable =			0x17,
+  DAC960_V1_AddCapacityAsync =			0x2A,
   /* Configuration Related Commands */
-  DAC960_ReadConfig2 =				0x3D,
-  DAC960_WriteConfig2 =				0x3C,
-  DAC960_ReadConfigurationOnDisk =		0x4A,
-  DAC960_WriteConfigurationOnDisk =		0x4B,
-  DAC960_ReadConfiguration =			0x4E,
-  DAC960_ReadBackupConfiguration =		0x4D,
-  DAC960_WriteConfiguration =			0x4F,
-  DAC960_AddConfiguration =			0x4C,
-  DAC960_ReadConfigurationLabel =		0x48,
-  DAC960_WriteConfigurationLabel =		0x49,
+  DAC960_V1_ReadConfig2 =			0x3D,
+  DAC960_V1_WriteConfig2 =			0x3C,
+  DAC960_V1_ReadConfigurationOnDisk =		0x4A,
+  DAC960_V1_WriteConfigurationOnDisk =		0x4B,
+  DAC960_V1_ReadConfiguration =			0x4E,
+  DAC960_V1_ReadBackupConfiguration =		0x4D,
+  DAC960_V1_WriteConfiguration =		0x4F,
+  DAC960_V1_AddConfiguration =			0x4C,
+  DAC960_V1_ReadConfigurationLabel =		0x48,
+  DAC960_V1_WriteConfigurationLabel =		0x49,
   /* Firmware Upgrade Related Commands */
-  DAC960_LoadImage =				0x20,
-  DAC960_StoreImage =				0x21,
-  DAC960_ProgramImage =				0x22,
+  DAC960_V1_LoadImage =				0x20,
+  DAC960_V1_StoreImage =			0x21,
+  DAC960_V1_ProgramImage =			0x22,
   /* Diagnostic Commands */
-  DAC960_SetDiagnosticMode =			0x31,
-  DAC960_RunDiagnostic =			0x32,
+  DAC960_V1_SetDiagnosticMode =			0x31,
+  DAC960_V1_RunDiagnostic =			0x32,
   /* Subsystem Service Commands */
-  DAC960_GetSubsystemData =			0x70,
-  DAC960_SetSubsystemParameters =		0x71
+  DAC960_V1_GetSubsystemData =			0x70,
+  DAC960_V1_SetSubsystemParameters =		0x71
 }
 __attribute__ ((packed))
-DAC960_CommandOpcode_T;
+DAC960_V1_CommandOpcode_T;
 
 
 /*
-  Define the DAC960 Command Identifier type.
+  Define the DAC960 V1 Firmware Command Identifier type.
 */
 
-typedef unsigned char DAC960_CommandIdentifier_T;
+typedef unsigned char DAC960_V1_CommandIdentifier_T;
 
 
 /*
-  Define the DAC960 Command Status Codes.
+  Define the DAC960 V1 Firmware Command Status Codes.
 */
 
-#define DAC960_NormalCompletion			0x0000	/* Common */
-#define DAC960_CheckConditionReceived		0x0002	/* Common */
-#define DAC960_NoDeviceAtAddress		0x0102	/* Common */
-#define DAC960_InvalidDeviceAddress		0x0105	/* Common */
-#define DAC960_InvalidParameter			0x0105	/* Common */
-#define DAC960_IrrecoverableDataError		0x0001	/* I/O */
-#define DAC960_LogicalDriveNonexistentOrOffline	0x0002	/* I/O */
-#define DAC960_AccessBeyondEndOfLogicalDrive	0x0105	/* I/O */
-#define DAC960_BadDataEncountered		0x010C	/* I/O */
-#define DAC960_DeviceBusy			0x0008	/* DCDB */
-#define DAC960_DeviceNonresponsive		0x000E	/* DCDB */
-#define DAC960_CommandTerminatedAbnormally	0x000F	/* DCDB */
-#define DAC960_UnableToStartDevice		0x0002	/* Device */
-#define DAC960_InvalidChannelOrTargetOrModifier	0x0105	/* Device */
-#define DAC960_ChannelBusy			0x0106	/* Device */
-#define DAC960_ChannelNotStopped		0x0002	/* Device */
-#define DAC960_AttemptToRebuildOnlineDrive	0x0002	/* Consistency */
-#define DAC960_RebuildBadBlocksEncountered	0x0003	/* Consistency */
-#define DAC960_NewDiskFailedDuringRebuild	0x0004	/* Consistency */
-#define DAC960_RebuildOrCheckAlreadyInProgress	0x0106	/* Consistency */
-#define DAC960_DependentDiskIsDead		0x0002	/* Consistency */
-#define DAC960_InconsistentBlocksFound		0x0003	/* Consistency */
-#define DAC960_InvalidOrNonredundantLogicalDrive 0x0105	/* Consistency */
-#define DAC960_NoRebuildOrCheckInProgress	0x0105	/* Consistency */
-#define DAC960_RebuildInProgress_DataValid	0x0000	/* Consistency */
-#define DAC960_RebuildFailed_LogicalDriveFailure 0x0002	/* Consistency */
-#define DAC960_RebuildFailed_BadBlocksOnOther	0x0003	/* Consistency */
-#define DAC960_RebuildFailed_NewDriveFailed	0x0004	/* Consistency */
-#define DAC960_RebuildSuccessful		0x0100	/* Consistency */
-#define DAC960_RebuildSuccessfullyTerminated	0x0107	/* Consistency */
-#define DAC960_AddCapacityInProgress		0x0004	/* Consistency */
-#define DAC960_AddCapacityFailedOrSuspended	0x00F4	/* Consistency */
-#define DAC960_Config2ChecksumError		0x0002	/* Configuration */
-#define DAC960_ConfigurationSuspended		0x0106	/* Configuration */
-#define DAC960_FailedToConfigureNVRAM		0x0105	/* Configuration */
-#define DAC960_ConfigurationNotSavedStateChange	0x0106	/* Configuration */
-#define DAC960_SubsystemNotInstalled		0x0001	/* Subsystem */
-#define DAC960_SubsystemFailed			0x0002	/* Subsystem */
-#define DAC960_SubsystemBusy			0x0106	/* Subsystem */
+#define DAC960_V1_NormalCompletion		0x0000	/* Common */
+#define DAC960_V1_CheckConditionReceived	0x0002	/* Common */
+#define DAC960_V1_NoDeviceAtAddress		0x0102	/* Common */
+#define DAC960_V1_InvalidDeviceAddress		0x0105	/* Common */
+#define DAC960_V1_InvalidParameter		0x0105	/* Common */
+#define DAC960_V1_IrrecoverableDataError	0x0001	/* I/O */
+#define DAC960_V1_LogicalDriveNonexistentOrOffline 0x0002 /* I/O */
+#define DAC960_V1_AccessBeyondEndOfLogicalDrive	0x0105	/* I/O */
+#define DAC960_V1_BadDataEncountered		0x010C	/* I/O */
+#define DAC960_V1_DeviceBusy			0x0008	/* DCDB */
+#define DAC960_V1_DeviceNonresponsive		0x000E	/* DCDB */
+#define DAC960_V1_CommandTerminatedAbnormally	0x000F	/* DCDB */
+#define DAC960_V1_UnableToStartDevice		0x0002	/* Device */
+#define DAC960_V1_InvalidChannelOrTargetOrModifier 0x0105 /* Device */
+#define DAC960_V1_ChannelBusy			0x0106	/* Device */
+#define DAC960_V1_ChannelNotStopped		0x0002	/* Device */
+#define DAC960_V1_AttemptToRebuildOnlineDrive	0x0002	/* Consistency */
+#define DAC960_V1_RebuildBadBlocksEncountered	0x0003	/* Consistency */
+#define DAC960_V1_NewDiskFailedDuringRebuild	0x0004	/* Consistency */
+#define DAC960_V1_RebuildOrCheckAlreadyInProgress 0x0106 /* Consistency */
+#define DAC960_V1_DependentDiskIsDead		0x0002	/* Consistency */
+#define DAC960_V1_InconsistentBlocksFound	0x0003	/* Consistency */
+#define DAC960_V1_InvalidOrNonredundantLogicalDrive 0x0105 /* Consistency */
+#define DAC960_V1_NoRebuildOrCheckInProgress	0x0105	/* Consistency */
+#define DAC960_V1_RebuildInProgress_DataValid	0x0000	/* Consistency */
+#define DAC960_V1_RebuildFailed_LogicalDriveFailure 0x0002 /* Consistency */
+#define DAC960_V1_RebuildFailed_BadBlocksOnOther 0x0003	/* Consistency */
+#define DAC960_V1_RebuildFailed_NewDriveFailed	0x0004	/* Consistency */
+#define DAC960_V1_RebuildSuccessful		0x0100	/* Consistency */
+#define DAC960_V1_RebuildSuccessfullyTerminated	0x0107	/* Consistency */
+#define DAC960_V1_AddCapacityInProgress		0x0004	/* Consistency */
+#define DAC960_V1_AddCapacityFailedOrSuspended	0x00F4	/* Consistency */
+#define DAC960_V1_Config2ChecksumError		0x0002	/* Configuration */
+#define DAC960_V1_ConfigurationSuspended	0x0106	/* Configuration */
+#define DAC960_V1_FailedToConfigureNVRAM	0x0105	/* Configuration */
+#define DAC960_V1_ConfigurationNotSavedStateChange 0x0106 /* Configuration */
+#define DAC960_V1_SubsystemNotInstalled		0x0001	/* Subsystem */
+#define DAC960_V1_SubsystemFailed		0x0002	/* Subsystem */
+#define DAC960_V1_SubsystemBusy			0x0106	/* Subsystem */
 
-typedef unsigned short DAC960_CommandStatus_T;
+typedef unsigned short DAC960_V1_CommandStatus_T;
 
 
 /*
-  Define the Enquiry reply structure.
+  Define the DAC960 V1 Firmware Enquiry Command reply structure.
 */
 
-typedef struct DAC960_Enquiry
+typedef struct DAC960_V1_Enquiry
 {
   unsigned char NumberOfLogicalDrives;			/* Byte 0 */
   unsigned int :24;					/* Bytes 1-3 */
@@ -229,15 +358,15 @@
   unsigned char MinorFirmwareVersion;			/* Byte 136 */
   unsigned char MajorFirmwareVersion;			/* Byte 137 */
   enum {
-    DAC960_NoStandbyRebuildOrCheckInProgress =			0x00,
-    DAC960_StandbyRebuildInProgress =				0x01,
-    DAC960_BackgroundRebuildInProgress =			0x02,
-    DAC960_BackgroundCheckInProgress =				0x03,
-    DAC960_StandbyRebuildCompletedWithError =			0xFF,
-    DAC960_BackgroundRebuildOrCheckFailed_DriveFailed =		0xF0,
-    DAC960_BackgroundRebuildOrCheckFailed_LogicalDriveFailed =	0xF1,
-    DAC960_BackgroundRebuildOrCheckFailed_OtherCauses =		0xF2,
-    DAC960_BackgroundRebuildOrCheckSuccessfullyTerminated =	0xF3
+    DAC960_V1_NoStandbyRebuildOrCheckInProgress =		    0x00,
+    DAC960_V1_StandbyRebuildInProgress =			    0x01,
+    DAC960_V1_BackgroundRebuildInProgress =			    0x02,
+    DAC960_V1_BackgroundCheckInProgress =			    0x03,
+    DAC960_V1_StandbyRebuildCompletedWithError =		    0xFF,
+    DAC960_V1_BackgroundRebuildOrCheckFailed_DriveFailed =	    0xF0,
+    DAC960_V1_BackgroundRebuildOrCheckFailed_LogicalDriveFailed =   0xF1,
+    DAC960_V1_BackgroundRebuildOrCheckFailed_OtherCauses =	    0xF2,
+    DAC960_V1_BackgroundRebuildOrCheckSuccessfullyTerminated =	    0xF3
   } __attribute__ ((packed)) RebuildFlag;		/* Byte 138 */
   unsigned char MaxCommands;				/* Byte 139 */
   unsigned char OfflineLogicalDriveCount;		/* Byte 140 */
@@ -261,40 +390,40 @@
   unsigned char Reserved[62];				/* Bytes 195-255 */
 }
 __attribute__ ((packed))
-DAC960_Enquiry_T;
+DAC960_V1_Enquiry_T;
 
 
 /*
-  Define the Enquiry2 reply structure.
+  Define the DAC960 V1 Firmware Enquiry2 Command reply structure.
 */
 
-typedef struct DAC960_Enquiry2
+typedef struct DAC960_V1_Enquiry2
 {
   struct {
     enum {
-      DAC960_P_PD_PU =				0x01,
-      DAC960_PL =				0x02,
-      DAC960_PG =				0x10,
-      DAC960_PJ =				0x11,
-      DAC960_PR =				0x12,
-      DAC960_PT =				0x13,
-      DAC960_PTL0 =				0x14,
-      DAC960_PRL =				0x15,
-      DAC960_PTL1 =				0x16,
-      DAC1164_P =				0x20
+      DAC960_V1_P_PD_PU =			0x01,
+      DAC960_V1_PL =				0x02,
+      DAC960_V1_PG =				0x10,
+      DAC960_V1_PJ =				0x11,
+      DAC960_V1_PR =				0x12,
+      DAC960_V1_PT =				0x13,
+      DAC960_V1_PTL0 =				0x14,
+      DAC960_V1_PRL =				0x15,
+      DAC960_V1_PTL1 =				0x16,
+      DAC960_V1_1164P =				0x20
     } __attribute__ ((packed)) SubModel;		/* Byte 0 */
     unsigned char ActualChannels;			/* Byte 1 */
     enum {
-      DAC960_FiveChannelBoard =			0x01,
-      DAC960_ThreeChannelBoard =		0x02,
-      DAC960_TwoChannelBoard =			0x03,
-      DAC960_ThreeChannelASIC_DAC =		0x04
+      DAC960_V1_FiveChannelBoard =		0x01,
+      DAC960_V1_ThreeChannelBoard =		0x02,
+      DAC960_V1_TwoChannelBoard =		0x03,
+      DAC960_V1_ThreeChannelASIC_DAC =		0x04
     } __attribute__ ((packed)) Model;			/* Byte 2 */
     enum {
-      DAC960_EISA_Controller =			0x01,
-      DAC960_MicroChannel_Controller =		0x02,
-      DAC960_PCI_Controller =			0x03,
-      DAC960_SCSItoSCSI_Controller =		0x08
+      DAC960_V1_EISA_Controller =		0x01,
+      DAC960_V1_MicroChannel_Controller =	0x02,
+      DAC960_V1_PCI_Controller =		0x03,
+      DAC960_V1_SCSItoSCSI_Controller =		0x08
     } __attribute__ ((packed)) ProductFamily;		/* Byte 3 */
   } HardwareID;						/* Bytes 0-3 */
   /* MajorVersion.MinorVersion-FirmwareType-TurnID */
@@ -321,14 +450,14 @@
   unsigned int NonVolatileMemorySize;			/* Bytes 36-39 */
   struct {
     enum {
-      DAC960_DRAM =				0x00,
-      DAC960_EDO =				0x01,
-      DAC960_SDRAM =				0x02
+      DAC960_V1_DRAM =				0x0,
+      DAC960_V1_EDO =				0x1,
+      DAC960_V1_SDRAM =				0x2
     } __attribute__ ((packed)) RamType:3;		/* Byte 40 Bits 0-2 */
     enum {
-      DAC960_None =				0x00,
-      DAC960_Parity =				0x01,
-      DAC960_ECC =				0x02
+      DAC960_V1_None =				0x0,
+      DAC960_V1_Parity =			0x1,
+      DAC960_V1_ECC =				0x2
     } __attribute__ ((packed)) ErrorCorrection:3;	/* Byte 40 Bits 3-5 */
     boolean FastPageMode:1;				/* Byte 40 Bit 6 */
     boolean LowPowerMemory:1;				/* Byte 40 Bit 7 */
@@ -367,14 +496,14 @@
   unsigned short CacheLineSize;				/* Bytes 104-105 */
   struct {
     enum {
-      DAC960_Narrow_8bit =			0x00,
-      DAC960_Wide_16bit =			0x01,
-      DAC960_Wide_32bit =			0x02
+      DAC960_V1_Narrow_8bit =			0x0,
+      DAC960_V1_Wide_16bit =			0x1,
+      DAC960_V1_Wide_32bit =			0x2
     } __attribute__ ((packed)) BusWidth:2;		/* Byte 106 Bits 0-1 */
     enum {
-      DAC960_Fast =				0x00,
-      DAC960_Ultra =				0x01,
-      DAC960_Ultra2 =				0x02
+      DAC960_V1_Fast =				0x0,
+      DAC960_V1_Ultra =				0x1,
+      DAC960_V1_Ultra2 =			0x2
     } __attribute__ ((packed)) BusSpeed:2;		/* Byte 106 Bits 2-3 */
     boolean Differential:1;				/* Byte 106 Bit 4 */
     unsigned char :3;					/* Byte 106 Bits 5-7 */
@@ -383,12 +512,12 @@
   unsigned int :32;					/* Bytes 108-111 */
   unsigned short FirmwareBuildNumber;			/* Bytes 112-113 */
   enum {
-    DAC960_AEMI =				0x01,
-    DAC960_OEM1 =				0x02,
-    DAC960_OEM2 =				0x04,
-    DAC960_OEM3 =				0x08,
-    DAC960_Conner =				0x10,
-    DAC960_SAFTE =				0x20
+    DAC960_V1_AEMI =				0x01,
+    DAC960_V1_OEM1 =				0x02,
+    DAC960_V1_OEM2 =				0x04,
+    DAC960_V1_OEM3 =				0x08,
+    DAC960_V1_Conner =				0x10,
+    DAC960_V1_SAFTE =				0x20
   } __attribute__ ((packed)) FaultManagementType;	/* Byte 114 */
   unsigned char :8;					/* Byte 115 */
   struct {
@@ -399,55 +528,64 @@
   unsigned int :32;					/* Bytes 120-123 */
   unsigned int :32;					/* Bytes 124-127 */
 }
-DAC960_Enquiry2_T;
+DAC960_V1_Enquiry2_T;
 
 
 /*
-  Define the Logical Drive State type.
+  Define the DAC960 V1 Firmware Logical Drive State type.
 */
 
 typedef enum
 {
-    DAC960_LogicalDrive_Online =		0x03,
-    DAC960_LogicalDrive_Critical =		0x04,
-    DAC960_LogicalDrive_Offline =		0xFF
+  DAC960_V1_LogicalDrive_Online =		0x03,
+  DAC960_V1_LogicalDrive_Critical =		0x04,
+  DAC960_V1_LogicalDrive_Offline =		0xFF
 }
 __attribute__ ((packed))
-DAC960_LogicalDriveState_T;
+DAC960_V1_LogicalDriveState_T;
 
 
 /*
-  Define the Get Logical Drive Information reply structure.
+  Define the DAC960 V1 Firmware Logical Drive Information structure.
 */
 
-typedef struct DAC960_LogicalDriveInformation
+typedef struct DAC960_V1_LogicalDriveInformation
 {
   unsigned int LogicalDriveSize;			/* Bytes 0-3 */
-  DAC960_LogicalDriveState_T LogicalDriveState;		/* Byte 4 */
+  DAC960_V1_LogicalDriveState_T LogicalDriveState;	/* Byte 4 */
   unsigned char RAIDLevel:7;				/* Byte 5 Bits 0-6 */
   boolean WriteBack:1;					/* Byte 5 Bit 7 */
-  unsigned int :16;					/* Bytes 6-7 */
+  unsigned short :16;					/* Bytes 6-7 */
 }
-DAC960_LogicalDriveInformation_T;
+DAC960_V1_LogicalDriveInformation_T;
+
 
+/*
+  Define the DAC960 V1 Firmware Get Logical Drive Information Command
+  reply structure.
+*/
+
+typedef DAC960_V1_LogicalDriveInformation_T
+	DAC960_V1_LogicalDriveInformationArray_T[DAC960_MaxLogicalDrives];
+
 
 /*
-  Define the Perform Event Log Operation Types.
+  Define the DAC960 V1 Firmware Perform Event Log Operation Types.
 */
 
 typedef enum
 {
-  DAC960_GetEventLogEntry =			0x00
+  DAC960_V1_GetEventLogEntry =			0x00
 }
 __attribute__ ((packed))
-DAC960_PerformEventLogOpType_T;
+DAC960_V1_PerformEventLogOpType_T;
 
 
 /*
-  Define the Get Event Log Entry reply structure.
+  Define the DAC960 V1 Firmware Get Event Log Entry Command reply structure.
 */
 
-typedef struct DAC960_EventLogEntry
+typedef struct DAC960_V1_EventLogEntry
 {
   unsigned char MessageType;				/* Byte 0 */
   unsigned char MessageLength;				/* Byte 1 */
@@ -459,7 +597,7 @@
   unsigned char ErrorCode:7;				/* Byte 6 Bits 0-6 */
   boolean Valid:1;					/* Byte 6 Bit 7 */
   unsigned char SegmentNumber;				/* Byte 7 */
-  unsigned char SenseKey:4;				/* Byte 8 Bits 0-3 */
+  DAC960_SCSI_RequestSenseKey_T SenseKey:4;		/* Byte 8 Bits 0-3 */
   unsigned char :1;					/* Byte 8 Bit 4 */
   boolean ILI:1;					/* Byte 8 Bit 5 */
   boolean EOM:1;					/* Byte 8 Bit 6 */
@@ -471,37 +609,37 @@
   unsigned char AdditionalSenseCodeQualifier;		/* Byte 19 */
   unsigned char Dummy[12];				/* Bytes 20-31 */
 }
-DAC960_EventLogEntry_T;
+DAC960_V1_EventLogEntry_T;
 
 
 /*
-  Define the Physical Device State type.
+  Define the DAC960 V1 Firmware Physical Device State type.
 */
 
 typedef enum
 {
-    DAC960_Device_Dead =			0x00,
-    DAC960_Device_WriteOnly =			0x02,
-    DAC960_Device_Online =			0x03,
-    DAC960_Device_Standby =			0x10
+    DAC960_V1_Device_Dead =			0x00,
+    DAC960_V1_Device_WriteOnly =		0x02,
+    DAC960_V1_Device_Online =			0x03,
+    DAC960_V1_Device_Standby =			0x10
 }
 __attribute__ ((packed))
-DAC960_PhysicalDeviceState_T;
+DAC960_V1_PhysicalDeviceState_T;
 
 
 /*
-  Define the Get Device State reply structure.
+  Define the DAC960 V1 Firmware Get Device State Command reply structure.
 */
 
-typedef struct DAC960_DeviceState
+typedef struct DAC960_V1_DeviceState
 {
   boolean Present:1;					/* Byte 0 Bit 0 */
   unsigned char :7;					/* Byte 0 Bits 1-7 */
   enum {
-    DAC960_OtherType =				0x00,
-    DAC960_DiskType =				0x01,
-    DAC960_SequentialType =			0x02,
-    DAC960_CDROM_or_WORM_Type =			0x03
+    DAC960_V1_OtherType =			0x0,
+    DAC960_V1_DiskType =			0x1,
+    DAC960_V1_SequentialType =			0x2,
+    DAC960_V1_CDROM_or_WORM_Type =		0x3
     } __attribute__ ((packed)) DeviceType:2;		/* Byte 1 Bits 0-1 */
   boolean :1;						/* Byte 1 Bit 2 */
   boolean Fast20:1;					/* Byte 1 Bit 3 */
@@ -509,60 +647,60 @@
   boolean Fast:1;					/* Byte 1 Bit 5 */
   boolean Wide:1;					/* Byte 1 Bit 6 */
   boolean TaggedQueuingSupported:1;			/* Byte 1 Bit 7 */
-  DAC960_PhysicalDeviceState_T DeviceState;		/* Byte 2 */
+  DAC960_V1_PhysicalDeviceState_T DeviceState;		/* Byte 2 */
   unsigned char :8;					/* Byte 3 */
   unsigned char SynchronousMultiplier;			/* Byte 4 */
   unsigned char SynchronousOffset:5;			/* Byte 5 Bits 0-4 */
   unsigned char :3;					/* Byte 5 Bits 5-7 */
   unsigned int DiskSize __attribute__ ((packed));	/* Bytes 6-9 */
 }
-DAC960_DeviceState_T;
+DAC960_V1_DeviceState_T;
 
 
 /*
-  Define the Get Rebuild Progress reply structure.
+  Define the DAC960 V1 Firmware Get Rebuild Progress Command reply structure.
 */
 
-typedef struct DAC960_RebuildProgress
+typedef struct DAC960_V1_RebuildProgress
 {
   unsigned int LogicalDriveNumber;			/* Bytes 0-3 */
   unsigned int LogicalDriveSize;			/* Bytes 4-7 */
   unsigned int RemainingBlocks;				/* Bytes 8-11 */
 }
-DAC960_RebuildProgress_T;
+DAC960_V1_RebuildProgress_T;
 
 
 /*
-  Define the Error Table Entry and Get Error Table reply structure.
+  Define the DAC960 V1 Firmware Error Table Entry structure.
 */
 
-typedef struct DAC960_ErrorTableEntry
+typedef struct DAC960_V1_ErrorTableEntry
 {
   unsigned char ParityErrorCount;			/* Byte 0 */
   unsigned char SoftErrorCount;				/* Byte 1 */
   unsigned char HardErrorCount;				/* Byte 2 */
   unsigned char MiscErrorCount;				/* Byte 3 */
 }
-DAC960_ErrorTableEntry_T;
+DAC960_V1_ErrorTableEntry_T;
 
 
 /*
-  Define the Get Error Table reply structure.
+  Define the DAC960 V1 Firmware Get Error Table Command reply structure.
 */
 
-typedef struct DAC960_ErrorTable
+typedef struct DAC960_V1_ErrorTable
 {
-  DAC960_ErrorTableEntry_T
-    ErrorTableEntries[DAC960_MaxChannels][DAC960_MaxTargets];
+  DAC960_V1_ErrorTableEntry_T
+    ErrorTableEntries[DAC960_V1_MaxChannels][DAC960_V1_MaxTargets];
 }
-DAC960_ErrorTable_T;
+DAC960_V1_ErrorTable_T;
 
 
 /*
-  Define the Config2 reply structure.
+  Define the DAC960 V1 Firmware Read Config2 Command reply structure.
 */
 
-typedef struct DAC960_Config2
+typedef struct DAC960_V1_Config2
 {
   unsigned char :1;					/* Byte 0 Bit 0 */
   boolean ActiveNegationEnabled:1;			/* Byte 0 Bit 1 */
@@ -576,12 +714,12 @@
   boolean AEMI_OFM:1;					/* Byte 1 Bit 6 */
   unsigned char :1;					/* Byte 1 Bit 7 */
   enum {
-    DAC960_OEMID_Mylex =			0x00,
-    DAC960_OEMID_IBM =				0x08,
-    DAC960_OEMID_HP =				0x0A,
-    DAC960_OEMID_DEC =				0x0C,
-    DAC960_OEMID_Siemens =			0x10,
-    DAC960_OEMID_Intel =			0x12
+    DAC960_V1_OEMID_Mylex =			0x00,
+    DAC960_V1_OEMID_IBM =			0x08,
+    DAC960_V1_OEMID_HP =			0x0A,
+    DAC960_V1_OEMID_DEC =			0x0C,
+    DAC960_V1_OEMID_Siemens =			0x10,
+    DAC960_V1_OEMID_Intel =			0x12
   } __attribute__ ((packed)) OEMID;			/* Byte 2 */
   unsigned char OEMModelNumber;				/* Byte 3 */
   unsigned char PhysicalSector;				/* Byte 4 */
@@ -600,21 +738,21 @@
   unsigned char BlocksPerStripe;			/* Byte 11 */
   struct {
     enum {
-      DAC960_Async =				0x00,
-      DAC960_Sync_8MHz =			0x01,
-      DAC960_Sync_5MHz =			0x02,
-      DAC960_Sync_10or20MHz =			0x03	/* Bits 0-1 */
+      DAC960_V1_Async =				0x0,
+      DAC960_V1_Sync_8MHz =			0x1,
+      DAC960_V1_Sync_5MHz =			0x2,
+      DAC960_V1_Sync_10or20MHz =		0x3	/* Byte 11 Bits 0-1 */
     } __attribute__ ((packed)) Speed:2;
-    boolean Force8Bit:1;				/* Bit 2 */
-    boolean DisableFast20:1;				/* Bit 3 */
-    unsigned char :3;					/* Bits 4-6 */
-    boolean EnableTaggedQueuing:1;			/* Bit 7 */
+    boolean Force8Bit:1;				/* Byte 11 Bit 2 */
+    boolean DisableFast20:1;				/* Byte 11 Bit 3 */
+    unsigned char :3;					/* Byte 11 Bits 4-6 */
+    boolean EnableTaggedQueuing:1;			/* Byte 11 Bit 7 */
   } __attribute__ ((packed)) ChannelParameters[6];	/* Bytes 12-17 */
   unsigned char SCSIInitiatorID;			/* Byte 18 */
   unsigned char :8;					/* Byte 19 */
   enum {
-    DAC960_StartupMode_ControllerSpinUp =	0x00,
-    DAC960_StartupMode_PowerOnSpinUp =		0x01
+    DAC960_V1_StartupMode_ControllerSpinUp =	0x00,
+    DAC960_V1_StartupMode_PowerOnSpinUp =	0x01
   } __attribute__ ((packed)) StartupMode;		/* Byte 20 */
   unsigned char SimultaneousDeviceSpinUpCount;		/* Byte 21 */
   unsigned char SecondsDelayBetweenSpinUps;		/* Byte 22 */
@@ -623,44 +761,44 @@
   boolean CDROMBootEnabled:1;				/* Byte 52 Bit 1 */
   unsigned char :3;					/* Byte 52 Bits 2-4 */
   enum {
-    DAC960_Geometry_128_32 =			0x00,
-    DAC960_Geometry_255_63 =			0x01,
-    DAC960_Geometry_Reserved1 =			0x02,
-    DAC960_Geometry_Reserved2 =			0x03
+    DAC960_V1_Geometry_128_32 =			0x0,
+    DAC960_V1_Geometry_255_63 =			0x1,
+    DAC960_V1_Geometry_Reserved1 =		0x2,
+    DAC960_V1_Geometry_Reserved2 =		0x3
   } __attribute__ ((packed)) DriveGeometry:2;		/* Byte 52 Bits 5-6 */
   unsigned char :1;					/* Byte 52 Bit 7 */
   unsigned char Reserved2[9];				/* Bytes 53-61 */
   unsigned short Checksum;				/* Bytes 62-63 */
 }
-DAC960_Config2_T;
+DAC960_V1_Config2_T;
 
 
 /*
-  Define the DCDB request structure.
+  Define the DAC960 V1 Firmware DCDB request structure.
 */
 
-typedef struct DAC960_DCDB
+typedef struct DAC960_V1_DCDB
 {
   unsigned char TargetID:4;				 /* Byte 0 Bits 0-3 */
   unsigned char Channel:4;				 /* Byte 0 Bits 4-7 */
   enum {
-    DAC960_DCDB_NoDataTransfer = 0,
-    DAC960_DCDB_DataTransferDeviceToSystem = 1,
-    DAC960_DCDB_DataTransferSystemToDevice = 2,
-    DAC960_DCDB_IllegalDataTransfer = 3
+    DAC960_V1_DCDB_NoDataTransfer =		0,
+    DAC960_V1_DCDB_DataTransferDeviceToSystem = 1,
+    DAC960_V1_DCDB_DataTransferSystemToDevice = 2,
+    DAC960_V1_DCDB_IllegalDataTransfer =	3
   } __attribute__ ((packed)) Direction:2;		 /* Byte 1 Bits 0-1 */
   boolean EarlyStatus:1;				 /* Byte 1 Bit 2 */
   unsigned char :1;					 /* Byte 1 Bit 3 */
   enum {
-    DAC960_DCDB_Timeout_24_hours = 0,
-    DAC960_DCDB_Timeout_10_seconds = 1,
-    DAC960_DCDB_Timeout_60_seconds = 2,
-    DAC960_DCDB_Timeout_10_minutes = 3
+    DAC960_V1_DCDB_Timeout_24_hours =		0,
+    DAC960_V1_DCDB_Timeout_10_seconds =		1,
+    DAC960_V1_DCDB_Timeout_60_seconds =		2,
+    DAC960_V1_DCDB_Timeout_10_minutes =		3
   } __attribute__ ((packed)) Timeout:2;			 /* Byte 1 Bits 4-5 */
   boolean NoAutomaticRequestSense:1;			 /* Byte 1 Bit 6 */
   boolean DisconnectPermitted:1;			 /* Byte 1 Bit 7 */
   unsigned short TransferLength;			 /* Bytes 2-3 */
-  DAC960_BusAddress_T BusAddress;			 /* Bytes 4-7 */
+  DAC960_BusAddress32_T BusAddress;			 /* Bytes 4-7 */
   unsigned char CDBLength:4;				 /* Byte 8 Bits 0-3 */
   unsigned char TransferLengthHigh4:4;			 /* Byte 8 Bits 4-7 */
   unsigned char SenseLength;				 /* Byte 9 */
@@ -668,388 +806,1289 @@
   unsigned char SenseData[64];				 /* Bytes 22-85 */
   unsigned char Status;					 /* Byte 86 */
   unsigned char :8;					 /* Byte 87 */
-}
-DAC960_DCDB_T;
-
-
-/*
-  Define the SCSI INQUIRY Standard Data reply structure.
-*/
-
-typedef struct DAC960_SCSI_Inquiry
-{
-  unsigned char PeripheralDeviceType:5;			/* Byte 0 Bits 0-4 */
-  unsigned char PeripheralQualifier:3;			/* Byte 0 Bits 5-7 */
-  unsigned char DeviceTypeModifier:7;			/* Byte 1 Bits 0-6 */
-  boolean RMB:1;					/* Byte 1 Bit 7 */
-  unsigned char ANSI_ApprovedVersion:3;			/* Byte 2 Bits 0-2 */
-  unsigned char ECMA_Version:3;				/* Byte 2 Bits 3-5 */
-  unsigned char ISO_Version:2;				/* Byte 2 Bits 6-7 */
-  unsigned char ResponseDataFormat:4;			/* Byte 3 Bits 0-3 */
-  unsigned char :2;					/* Byte 3 Bits 4-5 */
-  boolean TrmIOP:1;					/* Byte 3 Bit 6 */
-  boolean AENC:1;					/* Byte 3 Bit 7 */
-  unsigned char AdditionalLength;			/* Byte 4 */
-  unsigned char :8;					/* Byte 5 */
-  unsigned char :8;					/* Byte 6 */
-  boolean SftRe:1;					/* Byte 7 Bit 0 */
-  boolean CmdQue:1;					/* Byte 7 Bit 1 */
-  boolean :1;						/* Byte 7 Bit 2 */
-  boolean Linked:1;					/* Byte 7 Bit 3 */
-  boolean Sync:1;					/* Byte 7 Bit 4 */
-  boolean WBus16:1;					/* Byte 7 Bit 5 */
-  boolean WBus32:1;					/* Byte 7 Bit 6 */
-  boolean RelAdr:1;					/* Byte 7 Bit 7 */
-  unsigned char VendorIdentification[8];		/* Bytes 8-15 */
-  unsigned char ProductIdentification[16];		/* Bytes 16-31 */
-  unsigned char ProductRevisionLevel[4];		/* Bytes 32-35 */
-}
-DAC960_SCSI_Inquiry_T;
-
-
-/*
-  Define the SCSI INQUIRY Unit Serial Number reply structure.
-*/
-
-typedef struct DAC960_SCSI_Inquiry_UnitSerialNumber
-{
-  unsigned char PeripheralDeviceType:5;			/* Byte 0 Bits 0-4 */
-  unsigned char PeripheralQualifier:3;			/* Byte 0 Bits 5-7 */
-  unsigned char PageCode;				/* Byte 1 */
-  unsigned char :8;					/* Byte 2 */
-  unsigned char PageLength;				/* Byte 3 */
-  unsigned char ProductSerialNumber[28];		/* Bytes 4 - 31 */
 }
-DAC960_SCSI_Inquiry_UnitSerialNumber_T;
+DAC960_V1_DCDB_T;
 
 
 /*
-  Define the Scatter/Gather List Type 1 32 Bit Address 32 Bit Byte Count
-  structure.
+  Define the DAC960 V1 Firmware Scatter/Gather List Type 1 32 Bit Address
+  32 Bit Byte Count structure.
 */
 
-typedef struct DAC960_ScatterGatherSegment
+typedef struct DAC960_V1_ScatterGatherSegment
 {
-  DAC960_BusAddress_T SegmentDataPointer;		/* Bytes 0-3 */
-  DAC960_ByteCount_T SegmentByteCount;			/* Bytes 4-7 */
+  DAC960_BusAddress32_T SegmentDataPointer;		/* Bytes 0-3 */
+  DAC960_ByteCount32_T SegmentByteCount;		/* Bytes 4-7 */
 }
-DAC960_ScatterGatherSegment_T;
+DAC960_V1_ScatterGatherSegment_T;
 
 
 /*
-  Define the 13 Byte DAC960 Command Mailbox structure.  Bytes 13-15 are
-  not used.  The Command Mailbox structure is padded to 16 bytes for
+  Define the 13 Byte DAC960 V1 Firmware Command Mailbox structure.  Bytes 13-15
+  are not used.  The Command Mailbox structure is padded to 16 bytes for
   efficient access.
 */
 
-typedef union DAC960_CommandMailbox
+typedef union DAC960_V1_CommandMailbox
 {
   unsigned int Words[4];				/* Words 0-3 */
   unsigned char Bytes[16];				/* Bytes 0-15 */
   struct {
-    DAC960_CommandOpcode_T CommandOpcode;		/* Byte 0 */
-    DAC960_CommandIdentifier_T CommandIdentifier;	/* Byte 1 */
+    DAC960_V1_CommandOpcode_T CommandOpcode;		/* Byte 0 */
+    DAC960_V1_CommandIdentifier_T CommandIdentifier;	/* Byte 1 */
     unsigned char Dummy[14];				/* Bytes 2-15 */
   } __attribute__ ((packed)) Common;
   struct {
-    DAC960_CommandOpcode_T CommandOpcode;		/* Byte 0 */
-    DAC960_CommandIdentifier_T CommandIdentifier;	/* Byte 1 */
+    DAC960_V1_CommandOpcode_T CommandOpcode;		/* Byte 0 */
+    DAC960_V1_CommandIdentifier_T CommandIdentifier;	/* Byte 1 */
     unsigned char Dummy1[6];				/* Bytes 2-7 */
-    DAC960_BusAddress_T BusAddress;			/* Bytes 8-11 */
+    DAC960_BusAddress32_T BusAddress;			/* Bytes 8-11 */
     unsigned char Dummy2[4];				/* Bytes 12-15 */
   } __attribute__ ((packed)) Type3;
   struct {
-    DAC960_CommandOpcode_T CommandOpcode;		/* Byte 0 */
-    DAC960_CommandIdentifier_T CommandIdentifier;	/* Byte 1 */
+    DAC960_V1_CommandOpcode_T CommandOpcode;		/* Byte 0 */
+    DAC960_V1_CommandIdentifier_T CommandIdentifier;	/* Byte 1 */
     unsigned char Dummy1[5];				/* Bytes 2-6 */
     unsigned char LogicalDriveNumber:6;			/* Byte 7 Bits 0-6 */
     boolean AutoRestore:1;				/* Byte 7 Bit 7 */
     unsigned char Dummy2[8];				/* Bytes 8-15 */
   } __attribute__ ((packed)) Type3C;
   struct {
-    DAC960_CommandOpcode_T CommandOpcode;		/* Byte 0 */
-    DAC960_CommandIdentifier_T CommandIdentifier;	/* Byte 1 */
+    DAC960_V1_CommandOpcode_T CommandOpcode;		/* Byte 0 */
+    DAC960_V1_CommandIdentifier_T CommandIdentifier;	/* Byte 1 */
     unsigned char Channel;				/* Byte 2 */
     unsigned char TargetID;				/* Byte 3 */
-    DAC960_PhysicalDeviceState_T DeviceState:5;		/* Byte 4 Bits 0-4 */
+    DAC960_V1_PhysicalDeviceState_T DeviceState:5;	/* Byte 4 Bits 0-4 */
     unsigned char Modifier:3;				/* Byte 4 Bits 5-7 */
     unsigned char Dummy1[3];				/* Bytes 5-7 */
-    DAC960_BusAddress_T BusAddress;			/* Bytes 8-11 */
+    DAC960_BusAddress32_T BusAddress;			/* Bytes 8-11 */
     unsigned char Dummy2[4];				/* Bytes 12-15 */
   } __attribute__ ((packed)) Type3D;
   struct {
-    DAC960_CommandOpcode_T CommandOpcode;		/* Byte 0 */
-    DAC960_CommandIdentifier_T CommandIdentifier;	/* Byte 1 */
-    DAC960_PerformEventLogOpType_T OperationType;	/* Byte 2 */
+    DAC960_V1_CommandOpcode_T CommandOpcode;		/* Byte 0 */
+    DAC960_V1_CommandIdentifier_T CommandIdentifier;	/* Byte 1 */
+    DAC960_V1_PerformEventLogOpType_T OperationType;	/* Byte 2 */
     unsigned char OperationQualifier;			/* Byte 3 */
     unsigned short SequenceNumber;			/* Bytes 4-5 */
     unsigned char Dummy1[2];				/* Bytes 6-7 */
-    DAC960_BusAddress_T BusAddress;			/* Bytes 8-11 */
+    DAC960_BusAddress32_T BusAddress;			/* Bytes 8-11 */
     unsigned char Dummy2[4];				/* Bytes 12-15 */
   } __attribute__ ((packed)) Type3E;
   struct {
-    DAC960_CommandOpcode_T CommandOpcode;		/* Byte 0 */
-    DAC960_CommandIdentifier_T CommandIdentifier;	/* Byte 1 */
+    DAC960_V1_CommandOpcode_T CommandOpcode;		/* Byte 0 */
+    DAC960_V1_CommandIdentifier_T CommandIdentifier;	/* Byte 1 */
     unsigned char Dummy1[2];				/* Bytes 2-3 */
     unsigned char RebuildRateConstant;			/* Byte 4 */
     unsigned char Dummy2[3];				/* Bytes 5-7 */
-    DAC960_BusAddress_T BusAddress;			/* Bytes 8-11 */
+    DAC960_BusAddress32_T BusAddress;			/* Bytes 8-11 */
     unsigned char Dummy3[4];				/* Bytes 12-15 */
   } __attribute__ ((packed)) Type3R;
   struct {
-    DAC960_CommandOpcode_T CommandOpcode;		/* Byte 0 */
-    DAC960_CommandIdentifier_T CommandIdentifier;	/* Byte 1 */
+    DAC960_V1_CommandOpcode_T CommandOpcode;		/* Byte 0 */
+    DAC960_V1_CommandIdentifier_T CommandIdentifier;	/* Byte 1 */
     unsigned short TransferLength;			/* Bytes 2-3 */
     unsigned int LogicalBlockAddress;			/* Bytes 4-7 */
-    DAC960_BusAddress_T BusAddress;			/* Bytes 8-11 */
+    DAC960_BusAddress32_T BusAddress;			/* Bytes 8-11 */
     unsigned char LogicalDriveNumber;			/* Byte 12 */
     unsigned char Dummy[3];				/* Bytes 13-15 */
   } __attribute__ ((packed)) Type4;
   struct {
-    DAC960_CommandOpcode_T CommandOpcode;		/* Byte 0 */
-    DAC960_CommandIdentifier_T CommandIdentifier;	/* Byte 1 */
+    DAC960_V1_CommandOpcode_T CommandOpcode;		/* Byte 0 */
+    DAC960_V1_CommandIdentifier_T CommandIdentifier;	/* Byte 1 */
     struct {
       unsigned short TransferLength:11;			/* Bytes 2-3 */
       unsigned char LogicalDriveNumber:5;		/* Byte 3 Bits 3-7 */
     } __attribute__ ((packed)) LD;
     unsigned int LogicalBlockAddress;			/* Bytes 4-7 */
-    DAC960_BusAddress_T BusAddress;			/* Bytes 8-11 */
+    DAC960_BusAddress32_T BusAddress;			/* Bytes 8-11 */
     unsigned char ScatterGatherCount:6;			/* Byte 12 Bits 0-5 */
     enum {
-      DAC960_ScatterGather_32BitAddress_32BitByteCount =	0x0,
-      DAC960_ScatterGather_32BitAddress_16BitByteCount =	0x1,
-      DAC960_ScatterGather_32BitByteCount_32BitAddress =	0x2,
-      DAC960_ScatterGather_16BitByteCount_32BitAddress =	0x3
+      DAC960_V1_ScatterGather_32BitAddress_32BitByteCount = 0x0,
+      DAC960_V1_ScatterGather_32BitAddress_16BitByteCount = 0x1,
+      DAC960_V1_ScatterGather_32BitByteCount_32BitAddress = 0x2,
+      DAC960_V1_ScatterGather_16BitByteCount_32BitAddress = 0x3
     } __attribute__ ((packed)) ScatterGatherType:2;	/* Byte 12 Bits 6-7 */
     unsigned char Dummy[3];				/* Bytes 13-15 */
   } __attribute__ ((packed)) Type5;
   struct {
-    DAC960_CommandOpcode_T CommandOpcode;		/* Byte 0 */
-    DAC960_CommandIdentifier_T CommandIdentifier;	/* Byte 1 */
+    DAC960_V1_CommandOpcode_T CommandOpcode;		/* Byte 0 */
+    DAC960_V1_CommandIdentifier_T CommandIdentifier;	/* Byte 1 */
     unsigned char CommandOpcode2;			/* Byte 2 */
     unsigned char :8;					/* Byte 3 */
-    DAC960_BusAddress_T CommandMailboxesBusAddress;	/* Bytes 4-7 */
-    DAC960_BusAddress_T StatusMailboxesBusAddress;	/* Bytes 8-11 */
+    DAC960_BusAddress32_T CommandMailboxesBusAddress;	/* Bytes 4-7 */
+    DAC960_BusAddress32_T StatusMailboxesBusAddress;	/* Bytes 8-11 */
     unsigned char Dummy[4];				/* Bytes 12-15 */
   } __attribute__ ((packed)) TypeX;
 }
-DAC960_CommandMailbox_T;
+DAC960_V1_CommandMailbox_T;
 
 
 /*
-  Define the DAC960 Driver IOCTL requests.
+  Define the DAC960 V2 Firmware Command Opcodes.
 */
 
-#define DAC960_IOCTL_GET_CONTROLLER_COUNT	0xDAC001
-#define DAC960_IOCTL_GET_CONTROLLER_INFO	0xDAC002
-#define DAC960_IOCTL_EXECUTE_COMMAND		0xDAC003
+typedef enum
+{
+  DAC960_V2_MemCopy =				0x01,
+  DAC960_V2_SCSI_10_Passthru =			0x02,
+  DAC960_V2_SCSI_255_Passthru =			0x03,
+  DAC960_V2_SCSI_10 =				0x04,
+  DAC960_V2_SCSI_256 =				0x05,
+  DAC960_V2_IOCTL =				0x20
+}
+__attribute__ ((packed))
+DAC960_V2_CommandOpcode_T;
 
 
 /*
-  Define the DAC960_IOCTL_GET_CONTROLLER_INFO reply structure.
+  Define the DAC960 V2 Firmware IOCTL Opcodes.
 */
 
-typedef struct DAC960_ControllerInfo
+typedef enum
 {
-  unsigned char ControllerNumber;
-  unsigned char PCI_Bus;
-  unsigned char PCI_Device;
-  unsigned char PCI_Function;
-  unsigned char IRQ_Channel;
-  unsigned char Channels;
-  DAC960_PCI_Address_T PCI_Address;
-  unsigned char ModelName[16];
-  unsigned char FirmwareVersion[16];
+  DAC960_V2_GetControllerInfo =			0x01,
+  DAC960_V2_GetLogicalDeviceInfoValid =		0x03,
+  DAC960_V2_GetPhysicalDeviceInfoValid =	0x05,
+  DAC960_V2_GetHealthStatus =			0x11,
+  DAC960_V2_GetEvent =				0x15,
+  DAC960_V2_SetDeviceState =			0x82,
+  DAC960_V2_RebuildDeviceStart =		0x88,
+  DAC960_V2_RebuildDeviceStop =			0x89,
+  DAC960_V2_ConsistencyCheckStart =		0x8C,
+  DAC960_V2_ConsistencyCheckStop =		0x8D,
+  DAC960_V2_SetMemoryMailbox =			0x8E,
+  DAC960_V2_PauseDevice =			0x92,
+  DAC960_V2_TranslatePhysicalToLogicalDevice =	0xC5
 }
-DAC960_ControllerInfo_T;
+__attribute__ ((packed))
+DAC960_V2_IOCTL_Opcode_T;
 
 
 /*
-  Define the User Mode DAC960_IOCTL_EXECUTE_COMMAND request structure.
+  Define the DAC960 V2 Firmware Command Identifier type.
 */
 
-typedef struct DAC960_UserCommand
-{
-  unsigned char ControllerNumber;
-  DAC960_CommandMailbox_T CommandMailbox;
-  int DataTransferLength;
-  void *DataTransferBuffer;
-  DAC960_DCDB_T *DCDB;
-}
-DAC960_UserCommand_T;
+typedef unsigned short DAC960_V2_CommandIdentifier_T;
 
 
 /*
-  Define the Kernel Mode DAC960_IOCTL_EXECUTE_COMMAND request structure.
+  Define the DAC960 V2 Firmware Command Status Codes.
 */
 
-typedef struct DAC960_KernelCommand
-{
-  unsigned char ControllerNumber;
-  DAC960_CommandMailbox_T CommandMailbox;
-  int DataTransferLength;
-  void *DataTransferBuffer;
-  DAC960_DCDB_T *DCDB;
-  DAC960_CommandStatus_T CommandStatus;
-  void (*CompletionFunction)(struct DAC960_KernelCommand *);
-  void *CompletionData;
-}
-DAC960_KernelCommand_T;
+#define DAC960_V2_NormalCompletion		0x00
+#define DAC960_V2_AbormalCompletion		0x02
+#define DAC960_V2_DeviceNonresponsive		0x0E
 
+typedef unsigned char DAC960_V2_CommandStatus_T;
 
+
 /*
-  Import the Kernel Mode IOCTL interface.
+  Define the DAC960 V2 Firmware Memory Type structure.
 */
 
-extern int DAC960_KernelIOCTL(unsigned int Request, void *Argument);
+typedef struct DAC960_V2_MemoryType
+{
+  enum {
+    DAC960_V2_MemoryType_Reserved =		0x00,
+    DAC960_V2_MemoryType_DRAM =			0x01,
+    DAC960_V2_MemoryType_EDRAM =		0x02,
+    DAC960_V2_MemoryType_EDO =			0x03,
+    DAC960_V2_MemoryType_SDRAM =		0x04
+  } __attribute__ ((packed)) MemoryType:5;		/* Byte 0 Bits 0-4 */
+  boolean :1;						/* Byte 0 Bit 5 */
+  boolean MemoryParity:1;				/* Byte 0 Bit 6 */
+  boolean MemoryECC:1;					/* Byte 0 Bit 7 */
+}
+DAC960_V2_MemoryType_T;
 
 
 /*
-  Virtual_to_Bus maps from Kernel Virtual Addresses to PCI Bus Addresses.
+  Define the DAC960 V2 Firmware Processor Type structure.
 */
 
-static inline DAC960_BusAddress_T Virtual_to_Bus(void *VirtualAddress)
+typedef enum
 {
-  return (DAC960_BusAddress_T) virt_to_bus(VirtualAddress);
+  DAC960_V2_ProcessorType_i960CA =		0x01,
+  DAC960_V2_ProcessorType_i960RD =		0x02,
+  DAC960_V2_ProcessorType_i960RN =		0x03,
+  DAC960_V2_ProcessorType_i960RP =		0x04,
+  DAC960_V2_ProcessorType_NorthBay =		0x05,
+  DAC960_V2_ProcessorType_StrongArm =		0x06,
+  DAC960_V2_ProcessorType_i960RM =		0x07
 }
+__attribute__ ((packed))
+DAC960_V2_ProcessorType_T;
 
 
 /*
-  Bus_to_Virtual maps from PCI Bus Addresses to Kernel Virtual Addresses.
+  Define the DAC960 V2 Firmware Get Controller Info reply structure.
 */
 
-static inline void *Bus_to_Virtual(DAC960_BusAddress_T BusAddress)
+typedef struct DAC960_V2_ControllerInfo
 {
-  return (void *) bus_to_virt(BusAddress);
+  unsigned char :8;					/* Byte 0 */
+  enum {
+    DAC960_V2_SCSI_Bus =			0x00,
+    DAC960_V2_Fibre_Bus =			0x01,
+    DAC960_V2_PCI_Bus =				0x03
+  } __attribute__ ((packed)) BusInterfaceType;		/* Byte 1 */
+  enum {
+    DAC960_V2_DAC960E =				0x01,
+    DAC960_V2_DAC960M =				0x08,
+    DAC960_V2_DAC960PD =			0x10,
+    DAC960_V2_DAC960PL =			0x11,
+    DAC960_V2_DAC960PU =			0x12,
+    DAC960_V2_DAC960PE =			0x13,
+    DAC960_V2_DAC960PG =			0x14,
+    DAC960_V2_DAC960PJ =			0x15,
+    DAC960_V2_DAC960PTL0 =			0x16,
+    DAC960_V2_DAC960PR =			0x17,
+    DAC960_V2_DAC960PRL =			0x18,
+    DAC960_V2_DAC960PT =			0x19,
+    DAC960_V2_DAC1164P =			0x1A,
+    DAC960_V2_DAC960PTL1 =			0x1B,
+    DAC960_V2_EXR2000P =			0x1C,
+    DAC960_V2_EXR3000P =			0x1D,
+    DAC960_V2_AcceleRAID352 =			0x1E,
+    DAC960_V2_AcceleRAID351 =			0x1F,
+    DAC960_V2_DAC960S =				0x60,
+    DAC960_V2_DAC960SU =			0x61,
+    DAC960_V2_DAC960SX =			0x62,
+    DAC960_V2_DAC960SF =			0x63,
+    DAC960_V2_DAC960SS =			0x64,
+    DAC960_V2_DAC960FL =			0x65,
+    DAC960_V2_DAC960LL =			0x66,
+    DAC960_V2_DAC960FF =			0x67,
+    DAC960_V2_DAC960HP =			0x68,
+    DAC960_V2_RAIDBRICK =			0x69,
+    DAC960_V2_METEOR_FL =			0x6A,
+    DAC960_V2_METEOR_FF =			0x6B
+  } __attribute__ ((packed)) ControllerType;		/* Byte 2 */
+  unsigned char :8;					/* Byte 3 */
+  unsigned short BusInterfaceSpeedMHz;			/* Bytes 4-5 */
+  unsigned char BusWidthBits;				/* Byte 6 */
+  unsigned char Reserved1[9];				/* Bytes 7-15 */
+  unsigned char BusInterfaceName[16];			/* Bytes 16-31 */
+  unsigned char ControllerName[16];			/* Bytes 32-47 */
+  unsigned char Reserved2[16];				/* Bytes 48-63 */
+  /* Firmware Release Information */
+  unsigned char FirmwareMajorVersion;			/* Byte 64 */
+  unsigned char FirmwareMinorVersion;			/* Byte 65 */
+  unsigned char FirmwareTurnNumber;			/* Byte 66 */
+  unsigned char FirmwareBuildNumber;			/* Byte 67 */
+  unsigned char FirmwareReleaseDay;			/* Byte 68 */
+  unsigned char FirmwareReleaseMonth;			/* Byte 69 */
+  unsigned char FirmwareReleaseYearHigh2Digits;		/* Byte 70 */
+  unsigned char FirmwareReleaseYearLow2Digits;		/* Byte 71 */
+  /* Hardware Release Information */
+  unsigned char HardwareRevision;			/* Byte 72 */
+  unsigned int :24;					/* Bytes 73-75 */
+  unsigned char HardwareReleaseDay;			/* Byte 76 */
+  unsigned char HardwareReleaseMonth;			/* Byte 77 */
+  unsigned char HardwareReleaseYearHigh2Digits;		/* Byte 78 */
+  unsigned char HardwareReleaseYearLow2Digits;		/* Byte 79 */
+  /* Hardware Manufacturing Information */
+  unsigned char ManufacturingBatchNumber;		/* Byte 80 */
+  unsigned char :8;					/* Byte 81 */
+  unsigned char ManufacturingPlantNumber;		/* Byte 82 */
+  unsigned char :8;					/* Byte 83 */
+  unsigned char HardwareManufacturingDay;		/* Byte 84 */
+  unsigned char HardwareManufacturingMonth;		/* Byte 85 */
+  unsigned char HardwareManufacturingYearHigh2Digits;	/* Byte 86 */
+  unsigned char HardwareManufacturingYearLow2Digits;	/* Byte 87 */
+  unsigned char MaximumNumberOfPDDperXLDD;		/* Byte 88 */
+  unsigned char MaximumNumberOfILDDperXLDD;		/* Byte 89 */
+  unsigned short NonvolatileMemorySizeKB;		/* Bytes 90-91 */
+  unsigned char MaximumNumberOfXLDD;			/* Byte 92 */
+  unsigned int :24;					/* Bytes 93-95 */
+  /* Unique Information per Controller */
+  unsigned char ControllerSerialNumber[16];		/* Bytes 96-111 */
+  unsigned char Reserved3[16];				/* Bytes 112-127 */
+  /* Vendor Information */
+  unsigned int :24;					/* Bytes 128-130 */
+  unsigned char OEM_Information;			/* Byte 131 */
+  unsigned char VendorName[16];				/* Bytes 132-147 */
+  /* Other Physical/Controller/Operation Information */
+  boolean BBU_Present:1;				/* Byte 148 Bit 0 */
+  boolean ActiveActiveClusteringMode:1;			/* Byte 148 Bit 1 */
+  unsigned char :6;					/* Byte 148 Bits 2-7 */
+  unsigned char :8;					/* Byte 149 */
+  unsigned short :16;					/* Bytes 150-151 */
+  /* Physical Device Scan Information */
+  boolean PhysicalScanActive:1;				/* Byte 152 Bit 0 */
+  unsigned char :7;					/* Byte 152 Bits 1-7 */
+  unsigned char PhysicalDeviceChannelNumber;		/* Byte 153 */
+  unsigned char PhysicalDeviceTargetID;			/* Byte 154 */
+  unsigned char PhysicalDeviceLogicalUnit;		/* Byte 155 */
+  /* Maximum Command Data Transfer Sizes */
+  unsigned short MaximumDataTransferSizeInBlocks;	/* Bytes 156-157 */
+  unsigned short MaximumScatterGatherEntries;		/* Bytes 158-159 */
+  /* Logical/Physical Device Counts */
+  unsigned short LogicalDevicesPresent;			/* Bytes 160-161 */
+  unsigned short LogicalDevicesCritical;		/* Bytes 162-163 */
+  unsigned short LogicalDevicesOffline;			/* Bytes 164-165 */
+  unsigned short PhysicalDevicesPresent;		/* Bytes 166-167 */
+  unsigned short PhysicalDisksPresent;			/* Bytes 168-169 */
+  unsigned short PhysicalDisksCritical;			/* Bytes 170-171 */
+  unsigned short PhysicalDisksOffline;			/* Bytes 172-173 */
+  unsigned short MaximumParallelCommands;		/* Bytes 174-175 */
+  /* Channel and Target ID Information */
+  unsigned char NumberOfPhysicalChannelsPresent;	/* Byte 176 */
+  unsigned char NumberOfVirtualChannelsPresent;		/* Byte 177 */
+  unsigned char NumberOfPhysicalChannelsPossible;	/* Byte 178 */
+  unsigned char NumberOfVirtualChannelsPossible;	/* Byte 179 */
+  unsigned char MaximumTargetsPerChannel[16];		/* Bytes 180-195 */
+  unsigned char Reserved4[12];				/* Bytes 196-207 */
+  /* Memory/Cache Information */
+  unsigned short MemorySizeMB;				/* Bytes 208-209 */
+  unsigned short CacheSizeMB;				/* Bytes 210-211 */
+  unsigned int ValidCacheSizeInBytes;			/* Bytes 212-215 */
+  unsigned int DirtyCacheSizeInBytes;			/* Bytes 216-219 */
+  unsigned short MemorySpeedMHz;			/* Bytes 220-221 */
+  unsigned char MemoryDataWidthBits;			/* Byte 222 */
+  DAC960_V2_MemoryType_T MemoryType;			/* Byte 223 */
+  unsigned char CacheMemoryTypeName[16];		/* Bytes 224-239 */
+  /* Execution Memory Information */
+  unsigned short ExecutionMemorySizeMB;			/* Bytes 240-241 */
+  unsigned short ExecutionL2CacheSizeMB;		/* Bytes 242-243 */
+  unsigned char Reserved5[8];				/* Bytes 244-251 */
+  unsigned short ExecutionMemorySpeedMHz;		/* Bytes 252-253 */
+  unsigned char ExecutionMemoryDataWidthBits;		/* Byte 254 */
+  DAC960_V2_MemoryType_T ExecutionMemoryType;		/* Byte 255 */
+  unsigned char ExecutionMemoryTypeName[16];		/* Bytes 256-271 */
+  /* First CPU Type Information */
+  unsigned short FirstProcessorSpeedMHz;		/* Bytes 272-273 */
+  DAC960_V2_ProcessorType_T FirstProcessorType;		/* Byte 274 */
+  unsigned char FirstProcessorCount;			/* Byte 275 */
+  unsigned char Reserved6[12];				/* Bytes 276-287 */
+  unsigned char FirstProcessorName[16];			/* Bytes 288-303 */
+  /* Second CPU Type Information */
+  unsigned short SecondProcessorSpeedMHz;		/* Bytes 304-305 */
+  DAC960_V2_ProcessorType_T SecondProcessorType;	/* Byte 306 */
+  unsigned char SecondProcessorCount;			/* Byte 307 */
+  unsigned char Reserved7[12];				/* Bytes 308-319 */
+  unsigned char SecondProcessorName[16];		/* Bytes 320-335 */
+  /* Debugging/Profiling/Command Time Tracing Information */
+  unsigned short CurrentProfilingDataPageNumber;	/* Bytes 336-337 */
+  unsigned short ProgramsAwaitingProfilingData;		/* Bytes 338-339 */
+  unsigned short CurrentCommandTimeTraceDataPageNumber;	/* Bytes 340-341 */
+  unsigned short ProgramsAwaitingCommandTimeTraceData;	/* Bytes 342-343 */
+  unsigned char Reserved8[8];				/* Bytes 344-351 */
+  /* Error Counters on Physical Devices */
+  unsigned short PhysicalDeviceBusResets;		/* Bytes 352-353 */
+  unsigned short PhysicalDeviceParityErrors;		/* Bytes 355-355 */
+  unsigned short PhysicalDeviceSoftErrors;		/* Bytes 356-357 */
+  unsigned short PhysicalDeviceCommandsFailed;		/* Bytes 358-359 */
+  unsigned short PhysicalDeviceMiscellaneousErrors;	/* Bytes 360-361 */
+  unsigned short PhysicalDeviceCommandTimeouts;		/* Bytes 362-363 */
+  unsigned short PhysicalDeviceSelectionTimeouts;	/* Bytes 364-365 */
+  unsigned short PhysicalDeviceRetriesDone;		/* Bytes 366-367 */
+  unsigned short PhysicalDeviceAbortsDone;		/* Bytes 368-369 */
+  unsigned short PhysicalDeviceHostCommandAbortsDone;	/* Bytes 370-371 */
+  unsigned short PhysicalDevicePredictedFailuresDetected; /* Bytes 372-373 */
+  unsigned short PhysicalDeviceHostCommandsFailed;	/* Bytes 374-375 */
+  unsigned char Reserved9[8];				/* Bytes 376-383 */
+  /* Error Counters on Logical Devices */
+  unsigned short LogicalDeviceSoftErrors;		/* Bytes 384-385 */
+  unsigned short LogicalDeviceCommandsFailed;		/* Bytes 386-387 */
+  unsigned short LogicalDeviceHostCommandAbortsDone;	/* Bytes 388-389 */
+  unsigned short :16;					/* Bytes 390-391 */
+  unsigned short ControllerMemoryErrors;		/* Bytes 392-393 */
+  unsigned short ControllerHostCommandAbortsDone;	/* Bytes 394-395 */
+  unsigned int :32;					/* Bytes 396-399 */
+  /* Long Duration Activity Information */
+  unsigned short BackgroundInitializationsActive;	/* Bytes 400-401 */
+  unsigned short LogicalDeviceInitializationsActive;	/* Bytes 402-403 */
+  unsigned short PhysicalDeviceInitializationsActive;	/* Bytes 404-405 */
+  unsigned short ConsistencyChecksActive;		/* Bytes 406-407 */
+  unsigned short RebuildsActive;			/* Bytes 408-409 */
+  unsigned short OnlineExpansionsActive;		/* Bytes 410-411 */
+  unsigned short PatrolActivitiesActive;		/* Bytes 412-413 */
+  unsigned char LongOperationStatus;			/* Byte 414 */
+  unsigned char :8;					/* Byte 415 */
+  /* Flash ROM Information */
+  unsigned char FlashType;				/* Byte 416 */
+  unsigned char :8;					/* Byte 417 */
+  unsigned short FlashSizeMB;				/* Bytes 418-419 */
+  unsigned int FlashLimit;				/* Bytes 420-423 */
+  unsigned int FlashCount;				/* Bytes 424-427 */
+  unsigned int :32;					/* Bytes 428-431 */
+  unsigned char FlashTypeName[16];			/* Bytes 432-447 */
+  /* Firmware Run Time Information */
+  unsigned char RebuildRate;				/* Byte 448 */
+  unsigned char BackgroundInitializationRate;		/* Byte 449 */
+  unsigned char ForegroundInitializationRate;		/* Byte 450 */
+  unsigned char ConsistencyCheckRate;			/* Byte 451 */
+  unsigned int :32;					/* Bytes 452-455 */
+  unsigned int MaximumDP;				/* Bytes 456-459 */
+  unsigned int FreeDP;					/* Bytes 460-463 */
+  unsigned int MaximumIOP;				/* Bytes 464-467 */
+  unsigned int FreeIOP;					/* Bytes 468-471 */
+  unsigned short MaximumCombLengthInBlocks;		/* Bytes 472-473 */
+  unsigned short NumberOfConfigurationGroups;		/* Bytes 474-475 */
+  boolean InstallationAbortStatus:1;			/* Byte 476 Bit 0 */
+  boolean MaintenanceModeStatus:1;			/* Byte 476 Bit 1 */
+  unsigned int :6;					/* Byte 476 Bits 2-7 */
+  unsigned int :24;					/* Bytes 477-479 */
+  unsigned char Reserved10[32];				/* Bytes 480-511 */
+  unsigned char Reserved11[512];			/* Bytes 512-1023 */
 }
+DAC960_V2_ControllerInfo_T;
 
 
 /*
-  DAC960_DriverVersion protects the private portion of this file.
+  Define the DAC960 V2 Firmware Logical Device State type.
 */
 
-#ifdef DAC960_DriverVersion
+typedef enum
+{
+  DAC960_V2_LogicalDevice_Online =		0x01,
+  DAC960_V2_LogicalDevice_Offline =		0x08,
+  DAC960_V2_LogicalDevice_Critical =		0x09
+}
+__attribute__ ((packed))
+DAC960_V2_LogicalDeviceState_T;
 
 
 /*
-  Define the maximum Driver Queue Depth and Controller Queue Depth supported
-  by any DAC960 model.
+  Define the DAC960 V2 Firmware Get Logical Device Info reply structure.
 */
 
-#define DAC960_MaxDriverQueueDepth		127
-#define DAC960_MaxControllerQueueDepth		128
+typedef struct DAC960_V2_LogicalDeviceInfo
+{
+  unsigned char :8;					/* Byte 0 */
+  unsigned char Channel;				/* Byte 1 */
+  unsigned char TargetID;				/* Byte 2 */
+  unsigned char LogicalUnit;				/* Byte 3 */
+  DAC960_V2_LogicalDeviceState_T LogicalDeviceState;	/* Byte 4 */
+  unsigned char RAIDLevel;				/* Byte 5 */
+  unsigned char StripeSize;				/* Byte 6 */
+  unsigned char CacheLineSize;				/* Byte 7 */
+  struct {
+    enum {
+      DAC960_V2_ReadCacheDisabled =		0x0,
+      DAC960_V2_ReadCacheEnabled =		0x1,
+      DAC960_V2_ReadAheadEnabled =		0x2,
+      DAC960_V2_IntelligentReadAheadEnabled =	0x3
+    } __attribute__ ((packed)) ReadCache:3;		/* Byte 8 Bits 0-2 */
+    enum {
+      DAC960_V2_WriteCacheDisabled =		0x0,
+      DAC960_V2_LogicalDeviceReadOnly =		0x1,
+      DAC960_V2_WriteCacheEnabled =		0x2,
+      DAC960_V2_IntelligentWriteCacheEnabled =	0x3
+    } __attribute__ ((packed)) WriteCache:3;		/* Byte 8 Bits 3-5 */
+    boolean :1;						/* Byte 8 Bit 6 */
+    boolean LogicalDeviceInitialized:1;			/* Byte 8 Bit 7 */
+  } LogicalDeviceControl;				/* Byte 8 */
+  /* Logical Device Operations Status */
+  boolean ConsistencyCheckInProgress:1;			/* Byte 9 Bit 0 */
+  boolean RebuildInProgress:1;				/* Byte 9 Bit 1 */
+  boolean BackgroundInitializationInProgress:1;		/* Byte 9 Bit 2 */
+  boolean ForegroundInitializationInProgress:1;		/* Byte 9 Bit 3 */
+  boolean DataMigrationInProgress:1;			/* Byte 9 Bit 4 */
+  boolean PatrolOperationInProgress:1;			/* Byte 9 Bit 5 */
+  unsigned char :2;					/* Byte 9 Bits 6-7 */
+  unsigned char RAID5WriteUpdate;			/* Byte 10 */
+  unsigned char RAID5Algorithm;				/* Byte 11 */
+  unsigned short LogicalDeviceNumber;			/* Bytes 12-13 */
+  /* BIOS Info */
+  boolean BIOSDisabled:1;				/* Byte 14 Bit 0 */
+  boolean CDROMBootEnabled:1;				/* Byte 14 Bit 1 */
+  boolean DriveCoercionEnabled:1;			/* Byte 14 Bit 2 */
+  boolean WriteSameDisabled:1;				/* Byte 14 Bit 3 */
+  boolean HBA_ModeEnabled:1;				/* Byte 14 Bit 4 */
+  enum {
+    DAC960_V2_Geometry_128_32 =			0x0,
+    DAC960_V2_Geometry_255_63 =			0x1,
+    DAC960_V2_Geometry_Reserved1 =		0x2,
+    DAC960_V2_Geometry_Reserved2 =		0x3
+  } __attribute__ ((packed)) DriveGeometry:2;		/* Byte 14 Bits 5-6 */
+  unsigned char :1;					/* Byte 14 Bit 7 */
+  unsigned char :8;					/* Byte 15 */
+  /* Error Counters */
+  unsigned short SoftErrors;				/* Bytes 16-17 */
+  unsigned short CommandsFailed;			/* Bytes 18-19 */
+  unsigned short HostCommandAbortsDone;			/* Bytes 20-21 */
+  unsigned short DeferredWriteErrors;			/* Bytes 22-23 */
+  unsigned int :32;					/* Bytes 24-27 */
+  unsigned int :32;					/* Bytes 28-31 */
+  /* Device Size Information */
+  unsigned short :16;					/* Bytes 32-33 */
+  unsigned short DeviceBlockSizeInBytes;		/* Bytes 34-35 */
+  unsigned int OriginalDeviceSizeIn512ByteBlocksOrMB;	/* Bytes 36-39 */
+  unsigned int ConfigurableDeviceSizeIn512ByteBlocksOrMB; /* Bytes 40-43 */
+  unsigned int :32;					/* Bytes 44-47 */
+  unsigned char LogicalDeviceName[32];			/* Bytes 48-79 */
+  unsigned char SCSI_InquiryData[36];			/* Bytes 80-115 */
+  unsigned char Reserved1[12];				/* Bytes 116-127 */
+  DAC960_ByteCount64_T LastReadBlockNumber;		/* Bytes 128-135 */
+  DAC960_ByteCount64_T LastWrittenBlockNumber;		/* Bytes 136-143 */
+  DAC960_ByteCount64_T ConsistencyCheckBlockNumber;	/* Bytes 144-151 */
+  DAC960_ByteCount64_T RebuildBlockNumber;		/* Bytes 152-159 */
+  DAC960_ByteCount64_T BackgroundInitializationBlockNumber; /* Bytes 160-167 */
+  DAC960_ByteCount64_T ForegroundInitializationBlockNumber; /* Bytes 168-175 */
+  DAC960_ByteCount64_T DataMigrationBlockNumber;	/* Bytes 176-183 */
+  DAC960_ByteCount64_T PatrolOperationBlockNumber;	/* Bytes 184-191 */
+  unsigned char Reserved2[64];				/* Bytes 192-255 */
+}
+DAC960_V2_LogicalDeviceInfo_T;
 
 
 /*
-  Define the maximum number of Scatter/Gather Segments supported by any
-  DAC960 model.
+  Define the DAC960 V2 Firmware Physical Device State type.
 */
 
-#define DAC960_MaxScatterGatherSegments		33
+typedef enum
+{
+    DAC960_V2_Device_Unconfigured =		0x00,
+    DAC960_V2_Device_Online =			0x01,
+    DAC960_V2_Device_WriteOnly =		0x03,
+    DAC960_V2_Device_Dead =			0x08,
+    DAC960_V2_Device_Standby =			0x21,
+    DAC960_V2_Device_InvalidState =		0xFF
+}
+__attribute__ ((packed))
+DAC960_V2_PhysicalDeviceState_T;
 
 
 /*
-  Define the number of Command Mailboxes and Status Mailboxes used by the
-  Memory Mailbox Interface.
+  Define the DAC960 V2 Firmware Get Physical Device Info reply structure.
 */
 
-#define DAC960_CommandMailboxCount		256
-#define DAC960_StatusMailboxCount		1024
+typedef struct DAC960_V2_PhysicalDeviceInfo
+{
+  unsigned char :8;					/* Byte 0 */
+  unsigned char Channel;				/* Byte 1 */
+  unsigned char TargetID;				/* Byte 2 */
+  unsigned char LogicalUnit;				/* Byte 3 */
+  /* Configuration Status Bits */
+  boolean PhysicalDeviceFaultTolerant:1;		/* Byte 4 Bit 0 */
+  boolean :1;						/* Byte 4 Bit 1 */
+  boolean PhysicalDeviceLocalToController:1;		/* Byte 4 Bit 2 */
+  unsigned char :5;					/* Byte 4 Bits 3-7 */
+  /* Multiple Host/Controller Status Bits */
+  boolean RemoteHostSystemDead:1;			/* Byte 5 Bit 0 */
+  boolean RemoteControllerDead:1;			/* Byte 5 Bit 1 */
+  unsigned char :6;					/* Byte 5 Bits 2-7 */
+  DAC960_V2_PhysicalDeviceState_T PhysicalDeviceState;	/* Byte 6 */
+  unsigned char NegotiatedDataWidthBits;		/* Byte 7 */
+  unsigned short NegotiatedSynchronousMegaTransfers;	/* Bytes 8-9 */
+  /* Multiported Physical Device Information */
+  unsigned char NumberOfPortConnections;		/* Byte 10 */
+  unsigned char DriveAccessibilityBitmap;		/* Byte 11 */
+  unsigned int :32;					/* Bytes 12-15 */
+  unsigned char NetworkAddress[16];			/* Bytes 16-31 */
+  unsigned short MaximumTags;				/* Bytes 32-33 */
+  /* Physical Device Operations Status */
+  boolean ConsistencyCheckInProgress:1;			/* Byte 34 Bit 0 */
+  boolean RebuildInProgress:1;				/* Byte 34 Bit 1 */
+  boolean MakingDataConsistentInProgress:1;		/* Byte 34 Bit 2 */
+  boolean PhysicalDeviceInitializationInProgress:1;	/* Byte 34 Bit 3 */
+  boolean DataMigrationInProgress:1;			/* Byte 34 Bit 4 */
+  boolean PatrolOperationInProgress:1;			/* Byte 34 Bit 5 */
+  unsigned char :2;					/* Byte 34 Bits 6-7 */
+  unsigned char LongOperationStatus;			/* Byte 35 */
+  unsigned char ParityErrors;				/* Byte 36 */
+  unsigned char SoftErrors;				/* Byte 37 */
+  unsigned char HardErrors;				/* Byte 38 */
+  unsigned char MiscellaneousErrors;			/* Byte 39 */
+  unsigned char CommandTimeouts;			/* Byte 40 */
+  unsigned char Retries;				/* Byte 41 */
+  unsigned char Aborts;					/* Byte 42 */
+  unsigned char PredictedFailuresDetected;		/* Byte 43 */
+  unsigned int :32;					/* Bytes 44-47 */
+  unsigned short :16;					/* Bytes 48-49 */
+  unsigned short DeviceBlockSizeInBytes;		/* Bytes 50-51 */
+  unsigned int OriginalDeviceSizeIn512ByteBlocksOrMB;	/* Bytes 52-55 */
+  unsigned int ConfigurableDeviceSizeIn512ByteBlocksOrMB; /* Bytes 56-59 */
+  unsigned int :32;					/* Bytes 60-63 */
+  unsigned char PhysicalDeviceName[16];			/* Bytes 64-79 */
+  unsigned char Reserved1[16];				/* Bytes 80-95 */
+  unsigned char Reserved2[32];				/* Bytes 96-127 */
+  unsigned char SCSI_InquiryData[36];			/* Bytes 128-163 */
+  unsigned char Reserved3[12];				/* Bytes 164-175 */
+  unsigned char Reserved4[16];				/* Bytes 176-191 */
+  DAC960_ByteCount64_T LastReadBlockNumber;		/* Bytes 192-199 */
+  DAC960_ByteCount64_T LastWrittenBlockNumber;		/* Bytes 200-207 */
+  DAC960_ByteCount64_T ConsistencyCheckBlockNumber;	/* Bytes 208-215 */
+  DAC960_ByteCount64_T RebuildBlockNumber;		/* Bytes 216-223 */
+  DAC960_ByteCount64_T MakingDataConsistentBlockNumber;	/* Bytes 224-231 */
+  DAC960_ByteCount64_T DeviceInitializationBlockNumber; /* Bytes 232-239 */
+  DAC960_ByteCount64_T DataMigrationBlockNumber;	/* Bytes 240-247 */
+  DAC960_ByteCount64_T PatrolOperationBlockNumber;	/* Bytes 248-255 */
+  unsigned char Reserved5[256];				/* Bytes 256-511 */
+}
+DAC960_V2_PhysicalDeviceInfo_T;
+
+
+/*
+  Define the DAC960 V2 Firmware Health Status Buffer structure.
+*/
+
+typedef struct DAC960_V2_HealthStatusBuffer
+{
+  unsigned int MicrosecondsFromControllerStartTime;	/* Bytes 0-3 */
+  unsigned int MillisecondsFromControllerStartTime;	/* Bytes 4-7 */
+  unsigned int SecondsFrom1January1970;			/* Bytes 8-11 */
+  unsigned int :32;					/* Bytes 12-15 */
+  unsigned int StatusChangeCounter;			/* Bytes 16-19 */
+  unsigned int :32;					/* Bytes 20-23 */
+  unsigned int DebugOutputMessageBufferIndex;		/* Bytes 24-27 */
+  unsigned int CodedMessageBufferIndex;			/* Bytes 28-31 */
+  unsigned int CurrentTimeTracePageNumber;		/* Bytes 32-35 */
+  unsigned int CurrentProfilerPageNumber;		/* Bytes 36-39 */
+  unsigned int NextEventSequenceNumber;			/* Bytes 40-43 */
+  unsigned int :32;					/* Bytes 44-47 */
+  unsigned char Reserved1[16];				/* Bytes 48-63 */
+  unsigned char Reserved2[64];				/* Bytes 64-127 */
+}
+DAC960_V2_HealthStatusBuffer_T;
 
 
 /*
-  Define the DAC960 Controller Monitoring Timer Interval.
+  Define the DAC960 V2 Firmware Get Event reply structure.
 */
 
-#define DAC960_MonitoringTimerInterval		(10 * HZ)
+typedef struct DAC960_V2_Event
+{
+  unsigned int EventSequenceNumber;			/* Bytes 0-3 */
+  unsigned int EventTime;				/* Bytes 4-7 */
+  unsigned int EventCode;				/* Bytes 8-11 */
+  unsigned char :8;					/* Byte 12 */
+  unsigned char Channel;				/* Byte 13 */
+  unsigned char TargetID;				/* Byte 14 */
+  unsigned char LogicalUnit;				/* Byte 15 */
+  unsigned int :32;					/* Bytes 16-19 */
+  unsigned int EventSpecificParameter;			/* Bytes 20-23 */
+  unsigned char RequestSenseData[40];			/* Bytes 24-63 */
+}
+DAC960_V2_Event_T;
 
 
 /*
-  Define the DAC960 Controller Secondary Monitoring Interval.
+  Define the DAC960 V2 Firmware Command Control Bits structure.
 */
 
-#define DAC960_SecondaryMonitoringInterval	(60 * HZ)
+typedef struct DAC960_V2_CommandControlBits
+{
+  boolean ForceUnitAccess:1;				/* Byte 0 Bit 0 */
+  boolean DisablePageOut:1;				/* Byte 0 Bit 1 */
+  boolean :1;						/* Byte 0 Bit 2 */
+  boolean AdditionalScatterGatherListMemory:1;		/* Byte 0 Bit 3 */
+  boolean DataTransferControllerToHost:1;		/* Byte 0 Bit 4 */
+  boolean :1;						/* Byte 0 Bit 5 */
+  boolean NoAutoRequestSense:1;				/* Byte 0 Bit 6 */
+  boolean DisconnectProhibited:1;			/* Byte 0 Bit 7 */
+}
+DAC960_V2_CommandControlBits_T;
 
 
 /*
-  Define the DAC960 Controller Progress Reporting Interval.
+  Define the DAC960 V2 Firmware Command Timeout structure.
 */
 
-#define DAC960_ProgressReportingInterval	(60 * HZ)
+typedef struct DAC960_V2_CommandTimeout
+{
+  unsigned char TimeoutValue:6;				/* Byte 0 Bits 0-5 */
+  enum {
+    DAC960_V2_TimeoutScale_Seconds =		0,
+    DAC960_V2_TimeoutScale_Minutes =		1,
+    DAC960_V2_TimeoutScale_Hours =		2,
+    DAC960_V2_TimeoutScale_Reserved =		3
+  } __attribute__ ((packed)) TimeoutScale:2;		/* Byte 0 Bits 6-7 */
+}
+DAC960_V2_CommandTimeout_T;
 
 
 /*
-  Define the maximum number of Partitions allowed for each Logical Drive.
+  Define the DAC960 V2 Firmware Physical Device structure.
 */
 
-#define DAC960_MaxPartitions			8
-#define DAC960_MaxPartitionsBits		3
+typedef struct DAC960_V2_PhysicalDevice
+{
+  unsigned char LogicalUnit;				/* Byte 0 */
+  unsigned char TargetID;				/* Byte 1 */
+  unsigned char Channel:3;				/* Byte 2 Bits 0-2 */
+  unsigned char Controller:5;				/* Byte 2 Bits 3-7 */
+}
+__attribute__ ((packed))
+DAC960_V2_PhysicalDevice_T;
 
 
 /*
-  Define macros to extract the Controller Number, Logical Drive Number, and
-  Partition Number from a Kernel Device, and to construct a Major Number, Minor
-  Number, and Kernel Device from the Controller Number, Logical Drive Number,
-  and Partition Number.  There is one Major Number assigned to each Controller.
-  The associated Minor Number is divided into the Logical Drive Number and
-  Partition Number.
+  Define the DAC960 V2 Firmware Logical Device structure.
 */
 
-#define DAC960_ControllerNumber(Device) \
-  (MAJOR(Device) - DAC960_MAJOR)
+typedef struct DAC960_V2_LogicalDevice
+{
+  unsigned short LogicalDeviceNumber;			/* Bytes 0-1 */
+  unsigned char :3;					/* Byte 2 Bits 0-2 */
+  unsigned char Controller:5;				/* Byte 2 Bits 3-7 */
+}
+__attribute__ ((packed))
+DAC960_V2_LogicalDevice_T;
 
-#define DAC960_LogicalDriveNumber(Device) \
-  (MINOR(Device) >> DAC960_MaxPartitionsBits)
 
-#define DAC960_PartitionNumber(Device) \
-  (MINOR(Device) & (DAC960_MaxPartitions - 1))
+/*
+  Define the DAC960 V2 Firmware Operation Device type.
+*/
 
-#define DAC960_MajorNumber(ControllerNumber) \
-  (DAC960_MAJOR + (ControllerNumber))
+typedef enum
+{
+  DAC960_V2_Physical_Device =			0x00,
+  DAC960_V2_RAID_Device =			0x01,
+  DAC960_V2_Physical_Channel =			0x02,
+  DAC960_V2_RAID_Channel =			0x03,
+  DAC960_V2_Physical_Controller =		0x04,
+  DAC960_V2_RAID_Controller =			0x05,
+  DAC960_V2_Configuration_Group =		0x10
+}
+__attribute__ ((packed))
+DAC960_V2_OperationDevice_T;
 
-#define DAC960_MinorNumber(LogicalDriveNumber, PartitionNumber) \
-   (((LogicalDriveNumber) << DAC960_MaxPartitionsBits) | (PartitionNumber))
 
-#define DAC960_MinorCount			(DAC960_MaxLogicalDrives \
-						 * DAC960_MaxPartitions)
+/*
+  Define the DAC960 V2 Firmware Translate Physical To Logical Device structure.
+*/
 
-#define DAC960_KernelDevice(ControllerNumber,				       \
-			    LogicalDriveNumber,				       \
-			    PartitionNumber)				       \
-   MKDEV(DAC960_MajorNumber(ControllerNumber),				       \
-	 DAC960_MinorNumber(LogicalDriveNumber, PartitionNumber))
+typedef struct DAC960_V2_PhysicalToLogicalDevice
+{
+  unsigned short LogicalDeviceNumber;			/* Bytes 0-1 */
+  unsigned short :16;					/* Bytes 2-3 */
+  unsigned char PreviousBootController;			/* Byte 4 */
+  unsigned char PreviousBootChannel;			/* Byte 5 */
+  unsigned char PreviousBootTargetID;			/* Byte 6 */
+  unsigned char PreviousBootLogicalUnit;		/* Byte 7 */
+}
+DAC960_V2_PhysicalToLogicalDevice_T;
+
 
 
 /*
-  Define the DAC960 Controller fixed Block Size and Block Size Bits.
+  Define the DAC960 V2 Firmware Scatter/Gather List Entry structure.
 */
 
-#define DAC960_BlockSize			512
+typedef struct DAC960_V2_ScatterGatherSegment
+{
+  DAC960_BusAddress64_T SegmentDataPointer;		/* Bytes 0-7 */
+  DAC960_ByteCount64_T SegmentByteCount;		/* Bytes 8-15 */
+}
+DAC960_V2_ScatterGatherSegment_T;
+
+
+/*
+  Define the DAC960 V2 Firmware Data Transfer Memory Address structure.
+*/
+
+typedef union DAC960_V2_DataTransferMemoryAddress
+{
+  DAC960_V2_ScatterGatherSegment_T ScatterGatherSegments[2]; /* Bytes 0-31 */
+  struct {
+    unsigned short ScatterGatherList0Length;		/* Bytes 0-1 */
+    unsigned short ScatterGatherList1Length;		/* Bytes 2-3 */
+    unsigned short ScatterGatherList2Length;		/* Bytes 4-5 */
+    unsigned short :16;					/* Bytes 6-7 */
+    DAC960_BusAddress64_T ScatterGatherList0Address;	/* Bytes 8-15 */
+    DAC960_BusAddress64_T ScatterGatherList1Address;	/* Bytes 16-23 */
+    DAC960_BusAddress64_T ScatterGatherList2Address;	/* Bytes 24-31 */
+  } ExtendedScatterGather;
+}
+DAC960_V2_DataTransferMemoryAddress_T;
+
+
+/*
+  Define the 64 Byte DAC960 V2 Firmware Command Mailbox structure.
+*/
+
+typedef union DAC960_V2_CommandMailbox
+{
+  unsigned int Words[16];				/* Words 0-15 */
+  struct {
+    DAC960_V2_CommandIdentifier_T CommandIdentifier;	/* Bytes 0-1 */
+    DAC960_V2_CommandOpcode_T CommandOpcode;		/* Byte 2 */
+    DAC960_V2_CommandControlBits_T CommandControlBits;	/* Byte 3 */
+    DAC960_ByteCount32_T DataTransferSize:24;		/* Bytes 4-6 */
+    unsigned char DataTransferPageNumber;		/* Byte 7 */
+    DAC960_BusAddress64_T RequestSenseBusAddress;	/* Bytes 8-15 */
+    unsigned int :24;					/* Bytes 16-18 */
+    DAC960_V2_CommandTimeout_T CommandTimeout;		/* Byte 19 */
+    unsigned char RequestSenseSize;			/* Byte 20 */
+    unsigned char IOCTL_Opcode;				/* Byte 21 */
+    unsigned char Reserved[10];				/* Bytes 22-31 */
+    DAC960_V2_DataTransferMemoryAddress_T
+      DataTransferMemoryAddress;			/* Bytes 32-63 */
+  } Common;
+  struct {
+    DAC960_V2_CommandIdentifier_T CommandIdentifier;	/* Bytes 0-1 */
+    DAC960_V2_CommandOpcode_T CommandOpcode;		/* Byte 2 */
+    DAC960_V2_CommandControlBits_T CommandControlBits;	/* Byte 3 */
+    DAC960_ByteCount32_T DataTransferSize:24;		/* Bytes 4-6 */
+    unsigned char DataTransferPageNumber;		/* Byte 7 */
+    DAC960_BusAddress64_T RequestSenseBusAddress;	/* Bytes 8-15 */
+    DAC960_V2_PhysicalDevice_T PhysicalDevice;		/* Bytes 16-18 */
+    DAC960_V2_CommandTimeout_T CommandTimeout;		/* Byte 19 */
+    unsigned char RequestSenseSize;			/* Byte 20 */
+    unsigned char CDBLength;				/* Byte 21 */
+    unsigned char SCSI_CDB[10];				/* Bytes 22-31 */
+    DAC960_V2_DataTransferMemoryAddress_T
+      DataTransferMemoryAddress;			/* Bytes 32-63 */
+  } SCSI_10;
+  struct {
+    DAC960_V2_CommandIdentifier_T CommandIdentifier;	/* Bytes 0-1 */
+    DAC960_V2_CommandOpcode_T CommandOpcode;		/* Byte 2 */
+    DAC960_V2_CommandControlBits_T CommandControlBits;	/* Byte 3 */
+    DAC960_ByteCount32_T DataTransferSize:24;		/* Bytes 4-6 */
+    unsigned char DataTransferPageNumber;		/* Byte 7 */
+    DAC960_BusAddress64_T RequestSenseBusAddress;	/* Bytes 8-15 */
+    DAC960_V2_PhysicalDevice_T PhysicalDevice;		/* Bytes 16-18 */
+    DAC960_V2_CommandTimeout_T CommandTimeout;		/* Byte 19 */
+    unsigned char RequestSenseSize;			/* Byte 20 */
+    unsigned char CDBLength;				/* Byte 21 */
+    unsigned short :16;					/* Bytes 22-23 */
+    DAC960_BusAddress64_T SCSI_CDB_BusAddress;		/* Bytes 24-31 */
+    DAC960_V2_DataTransferMemoryAddress_T
+      DataTransferMemoryAddress;			/* Bytes 32-63 */
+  } SCSI_255;
+  struct {
+    DAC960_V2_CommandIdentifier_T CommandIdentifier;	/* Bytes 0-1 */
+    DAC960_V2_CommandOpcode_T CommandOpcode;		/* Byte 2 */
+    DAC960_V2_CommandControlBits_T CommandControlBits;	/* Byte 3 */
+    DAC960_ByteCount32_T DataTransferSize:24;		/* Bytes 4-6 */
+    unsigned char DataTransferPageNumber;		/* Byte 7 */
+    DAC960_BusAddress64_T RequestSenseBusAddress;	/* Bytes 8-15 */
+    unsigned short :16;					/* Bytes 16-17 */
+    unsigned char ControllerNumber;			/* Byte 18 */
+    DAC960_V2_CommandTimeout_T CommandTimeout;		/* Byte 19 */
+    unsigned char RequestSenseSize;			/* Byte 20 */
+    unsigned char IOCTL_Opcode;				/* Byte 21 */
+    unsigned char Reserved[10];				/* Bytes 22-31 */
+    DAC960_V2_DataTransferMemoryAddress_T
+      DataTransferMemoryAddress;			/* Bytes 32-63 */
+  } ControllerInfo;
+  struct {
+    DAC960_V2_CommandIdentifier_T CommandIdentifier;	/* Bytes 0-1 */
+    DAC960_V2_CommandOpcode_T CommandOpcode;		/* Byte 2 */
+    DAC960_V2_CommandControlBits_T CommandControlBits;	/* Byte 3 */
+    DAC960_ByteCount32_T DataTransferSize:24;		/* Bytes 4-6 */
+    unsigned char DataTransferPageNumber;		/* Byte 7 */
+    DAC960_BusAddress64_T RequestSenseBusAddress;	/* Bytes 8-15 */
+    DAC960_V2_LogicalDevice_T LogicalDevice;		/* Bytes 16-18 */
+    DAC960_V2_CommandTimeout_T CommandTimeout;		/* Byte 19 */
+    unsigned char RequestSenseSize;			/* Byte 20 */
+    unsigned char IOCTL_Opcode;				/* Byte 21 */
+    unsigned char Reserved[10];				/* Bytes 22-31 */
+    DAC960_V2_DataTransferMemoryAddress_T
+      DataTransferMemoryAddress;			/* Bytes 32-63 */
+  } LogicalDeviceInfo;
+  struct {
+    DAC960_V2_CommandIdentifier_T CommandIdentifier;	/* Bytes 0-1 */
+    DAC960_V2_CommandOpcode_T CommandOpcode;		/* Byte 2 */
+    DAC960_V2_CommandControlBits_T CommandControlBits;	/* Byte 3 */
+    DAC960_ByteCount32_T DataTransferSize:24;		/* Bytes 4-6 */
+    unsigned char DataTransferPageNumber;		/* Byte 7 */
+    DAC960_BusAddress64_T RequestSenseBusAddress;	/* Bytes 8-15 */
+    DAC960_V2_PhysicalDevice_T PhysicalDevice;		/* Bytes 16-18 */
+    DAC960_V2_CommandTimeout_T CommandTimeout;		/* Byte 19 */
+    unsigned char RequestSenseSize;			/* Byte 20 */
+    unsigned char IOCTL_Opcode;				/* Byte 21 */
+    unsigned char Reserved[10];				/* Bytes 22-31 */
+    DAC960_V2_DataTransferMemoryAddress_T
+      DataTransferMemoryAddress;			/* Bytes 32-63 */
+  } PhysicalDeviceInfo;
+  struct {
+    DAC960_V2_CommandIdentifier_T CommandIdentifier;	/* Bytes 0-1 */
+    DAC960_V2_CommandOpcode_T CommandOpcode;		/* Byte 2 */
+    DAC960_V2_CommandControlBits_T CommandControlBits;	/* Byte 3 */
+    DAC960_ByteCount32_T DataTransferSize:24;		/* Bytes 4-6 */
+    unsigned char DataTransferPageNumber;		/* Byte 7 */
+    DAC960_BusAddress64_T RequestSenseBusAddress;	/* Bytes 8-15 */
+    unsigned short EventSequenceNumberHigh16;		/* Bytes 16-17 */
+    unsigned char ControllerNumber;			/* Byte 18 */
+    DAC960_V2_CommandTimeout_T CommandTimeout;		/* Byte 19 */
+    unsigned char RequestSenseSize;			/* Byte 20 */
+    unsigned char IOCTL_Opcode;				/* Byte 21 */
+    unsigned short EventSequenceNumberLow16;		/* Bytes 22-23 */
+    unsigned char Reserved[8];				/* Bytes 24-31 */
+    DAC960_V2_DataTransferMemoryAddress_T
+      DataTransferMemoryAddress;			/* Bytes 32-63 */
+  } GetEvent;
+  struct {
+    DAC960_V2_CommandIdentifier_T CommandIdentifier;	/* Bytes 0-1 */
+    DAC960_V2_CommandOpcode_T CommandOpcode;		/* Byte 2 */
+    DAC960_V2_CommandControlBits_T CommandControlBits;	/* Byte 3 */
+    DAC960_ByteCount32_T DataTransferSize:24;		/* Bytes 4-6 */
+    unsigned char DataTransferPageNumber;		/* Byte 7 */
+    DAC960_BusAddress64_T RequestSenseBusAddress;	/* Bytes 8-15 */
+    DAC960_V2_LogicalDevice_T LogicalDevice;		/* Bytes 16-18 */
+    DAC960_V2_CommandTimeout_T CommandTimeout;		/* Byte 19 */
+    unsigned char RequestSenseSize;			/* Byte 20 */
+    unsigned char IOCTL_Opcode;				/* Byte 21 */
+    union {
+      DAC960_V2_LogicalDeviceState_T LogicalDeviceState;
+      DAC960_V2_PhysicalDeviceState_T PhysicalDeviceState;
+    } DeviceState;					/* Byte 22 */
+    unsigned char Reserved[9];				/* Bytes 23-31 */
+    DAC960_V2_DataTransferMemoryAddress_T
+      DataTransferMemoryAddress;			/* Bytes 32-63 */
+  } SetDeviceState;
+  struct {
+    DAC960_V2_CommandIdentifier_T CommandIdentifier;	/* Bytes 0-1 */
+    DAC960_V2_CommandOpcode_T CommandOpcode;		/* Byte 2 */
+    DAC960_V2_CommandControlBits_T CommandControlBits;	/* Byte 3 */
+    DAC960_ByteCount32_T DataTransferSize:24;		/* Bytes 4-6 */
+    unsigned char DataTransferPageNumber;		/* Byte 7 */
+    DAC960_BusAddress64_T RequestSenseBusAddress;	/* Bytes 8-15 */
+    DAC960_V2_LogicalDevice_T LogicalDevice;		/* Bytes 16-18 */
+    DAC960_V2_CommandTimeout_T CommandTimeout;		/* Byte 19 */
+    unsigned char RequestSenseSize;			/* Byte 20 */
+    unsigned char IOCTL_Opcode;				/* Byte 21 */
+    boolean RestoreConsistency:1;			/* Byte 22 Bit 0 */
+    boolean InitializedAreaOnly:1;			/* Byte 22 Bit 1 */
+    unsigned char :6;					/* Byte 22 Bits 2-7 */
+    unsigned char Reserved[9];				/* Bytes 23-31 */
+    DAC960_V2_DataTransferMemoryAddress_T
+      DataTransferMemoryAddress;			/* Bytes 32-63 */
+  } ConsistencyCheck;
+  struct {
+    DAC960_V2_CommandIdentifier_T CommandIdentifier;	/* Bytes 0-1 */
+    DAC960_V2_CommandOpcode_T CommandOpcode;		/* Byte 2 */
+    DAC960_V2_CommandControlBits_T CommandControlBits;	/* Byte 3 */
+    unsigned char FirstCommandMailboxSizeKB;		/* Byte 4 */
+    unsigned char FirstStatusMailboxSizeKB;		/* Byte 5 */
+    unsigned char SecondCommandMailboxSizeKB;		/* Byte 6 */
+    unsigned char SecondStatusMailboxSizeKB;		/* Byte 7 */
+    DAC960_BusAddress64_T RequestSenseBusAddress;	/* Bytes 8-15 */
+    unsigned int :24;					/* Bytes 16-18 */
+    DAC960_V2_CommandTimeout_T CommandTimeout;		/* Byte 19 */
+    unsigned char RequestSenseSize;			/* Byte 20 */
+    unsigned char IOCTL_Opcode;				/* Byte 21 */
+    unsigned char HealthStatusBufferSizeKB;		/* Byte 22 */
+    unsigned char :8;					/* Byte 23 */
+    DAC960_BusAddress64_T HealthStatusBufferBusAddress; /* Bytes 24-31 */
+    DAC960_BusAddress64_T FirstCommandMailboxBusAddress; /* Bytes 32-39 */
+    DAC960_BusAddress64_T FirstStatusMailboxBusAddress; /* Bytes 40-47 */
+    DAC960_BusAddress64_T SecondCommandMailboxBusAddress; /* Bytes 48-55 */
+    DAC960_BusAddress64_T SecondStatusMailboxBusAddress; /* Bytes 56-63 */
+  } SetMemoryMailbox;
+  struct {
+    DAC960_V2_CommandIdentifier_T CommandIdentifier;	/* Bytes 0-1 */
+    DAC960_V2_CommandOpcode_T CommandOpcode;		/* Byte 2 */
+    DAC960_V2_CommandControlBits_T CommandControlBits;	/* Byte 3 */
+    DAC960_ByteCount32_T DataTransferSize:24;		/* Bytes 4-6 */
+    unsigned char DataTransferPageNumber;		/* Byte 7 */
+    DAC960_BusAddress64_T RequestSenseBusAddress;	/* Bytes 8-15 */
+    DAC960_V2_PhysicalDevice_T PhysicalDevice;		/* Bytes 16-18 */
+    DAC960_V2_CommandTimeout_T CommandTimeout;		/* Byte 19 */
+    unsigned char RequestSenseSize;			/* Byte 20 */
+    unsigned char IOCTL_Opcode;				/* Byte 21 */
+    DAC960_V2_OperationDevice_T OperationDevice;	/* Byte 22 */
+    unsigned char Reserved[9];				/* Bytes 23-31 */
+    DAC960_V2_DataTransferMemoryAddress_T
+      DataTransferMemoryAddress;			/* Bytes 32-63 */
+  } DeviceOperation;
+}
+__attribute__ ((packed))
+DAC960_V2_CommandMailbox_T;
+
+
+/*
+  Define the DAC960 Driver IOCTL requests.
+*/
+
+#define DAC960_IOCTL_GET_CONTROLLER_COUNT	0xDAC001
+#define DAC960_IOCTL_GET_CONTROLLER_INFO	0xDAC002
+#define DAC960_IOCTL_V1_EXECUTE_COMMAND		0xDAC003
+#define DAC960_IOCTL_V2_EXECUTE_COMMAND		0xDAC004
+#define DAC960_IOCTL_V2_GET_HEALTH_STATUS	0xDAC005
+
+
+/*
+  Define the DAC960_IOCTL_GET_CONTROLLER_INFO reply structure.
+*/
+
+typedef struct DAC960_ControllerInfo
+{
+  unsigned char ControllerNumber;
+  unsigned char FirmwareType;
+  unsigned char Channels;
+  unsigned char Targets;
+  unsigned char PCI_Bus;
+  unsigned char PCI_Device;
+  unsigned char PCI_Function;
+  unsigned char IRQ_Channel;
+  DAC960_PCI_Address_T PCI_Address;
+  unsigned char ModelName[20];
+  unsigned char FirmwareVersion[12];
+}
+DAC960_ControllerInfo_T;
+
+
+/*
+  Define the User Mode DAC960_IOCTL_V1_EXECUTE_COMMAND request structure.
+*/
+
+typedef struct DAC960_V1_UserCommand
+{
+  unsigned char ControllerNumber;
+  DAC960_V1_CommandMailbox_T CommandMailbox;
+  int DataTransferLength;
+  void *DataTransferBuffer;
+  DAC960_V1_DCDB_T *DCDB;
+}
+DAC960_V1_UserCommand_T;
+
+
+/*
+  Define the Kernel Mode DAC960_IOCTL_V1_EXECUTE_COMMAND request structure.
+*/
+
+typedef struct DAC960_V1_KernelCommand
+{
+  unsigned char ControllerNumber;
+  DAC960_V1_CommandMailbox_T CommandMailbox;
+  int DataTransferLength;
+  void *DataTransferBuffer;
+  DAC960_V1_DCDB_T *DCDB;
+  DAC960_V1_CommandStatus_T CommandStatus;
+  void (*CompletionFunction)(struct DAC960_V1_KernelCommand *);
+  void *CompletionData;
+}
+DAC960_V1_KernelCommand_T;
+
+
+/*
+  Define the User Mode DAC960_IOCTL_V2_EXECUTE_COMMAND request structure.
+*/
+
+typedef struct DAC960_V2_UserCommand
+{
+  unsigned char ControllerNumber;
+  DAC960_V2_CommandMailbox_T CommandMailbox;
+  int DataTransferLength;
+  int RequestSenseLength;
+  void *DataTransferBuffer;
+  void *RequestSenseBuffer;
+}
+DAC960_V2_UserCommand_T;
+
+
+/*
+  Define the Kernel Mode DAC960_IOCTL_V2_EXECUTE_COMMAND request structure.
+*/
+
+typedef struct DAC960_V2_KernelCommand
+{
+  unsigned char ControllerNumber;
+  DAC960_V2_CommandMailbox_T CommandMailbox;
+  int DataTransferLength;
+  int RequestSenseLength;
+  void *DataTransferBuffer;
+  void *RequestSenseBuffer;
+  DAC960_V2_CommandStatus_T CommandStatus;
+  void (*CompletionFunction)(struct DAC960_V2_KernelCommand *);
+  void *CompletionData;
+}
+DAC960_V2_KernelCommand_T;
+
+
+/*
+  Define the User Mode DAC960_IOCTL_V2_GET_HEALTH_STATUS request structure.
+*/
+
+typedef struct DAC960_V2_GetHealthStatus
+{
+  unsigned char ControllerNumber;
+  DAC960_V2_HealthStatusBuffer_T *HealthStatusBuffer;
+}
+DAC960_V2_GetHealthStatus_T;
+
+
+/*
+  Import the Kernel Mode IOCTL interface.
+*/
+
+extern int DAC960_KernelIOCTL(unsigned int Request, void *Argument);
+
+
+/*
+  Virtual_to_Bus maps from Kernel Virtual Addresses to PCI Bus Addresses.
+*/
+
+static inline DAC960_BusAddress32_T Virtual_to_Bus(void *VirtualAddress)
+{
+  return (DAC960_BusAddress32_T) virt_to_bus(VirtualAddress);
+}
+
+
+/*
+  Bus_to_Virtual maps from PCI Bus Addresses to Kernel Virtual Addresses.
+*/
+
+static inline void *Bus_to_Virtual(DAC960_BusAddress32_T BusAddress)
+{
+  return (void *) bus_to_virt(BusAddress);
+}
+
+
+/*
+  DAC960_DriverVersion protects the private portion of this file.
+*/
+
+#ifdef DAC960_DriverVersion
+
+
+/*
+  Define the maximum Driver Queue Depth and Controller Queue Depth supported
+  by DAC960 V1 and V2 Firmware Controllers.
+*/
+
+#define DAC960_MaxDriverQueueDepth		511
+#define DAC960_MaxControllerQueueDepth		512
+
+
+/*
+  Define the maximum number of Scatter/Gather Segments supported for any
+  DAC960 V1 and V2 Firmware controller.
+*/
+
+#define DAC960_V1_ScatterGatherLimit		33
+#define DAC960_V2_ScatterGatherLimit		128
+
+
+/*
+  Define the number of Command Mailboxes and Status Mailboxes used by the
+  DAC960 V1 and V2 Firmware Memory Mailbox Interface.
+*/
+
+#define DAC960_V1_CommandMailboxCount		256
+#define DAC960_V1_StatusMailboxCount		1024
+#define DAC960_V2_CommandMailboxCount		512
+#define DAC960_V2_StatusMailboxCount		512
+
+
+/*
+  Define the DAC960 Controller Monitoring Timer Interval.
+*/
+
+#define DAC960_MonitoringTimerInterval		(10 * HZ)
+
+
+/*
+  Define the DAC960 Controller Secondary Monitoring Interval.
+*/
+
+#define DAC960_SecondaryMonitoringInterval	(60 * HZ)
+
+
+/*
+  Define the DAC960 Controller Health Status Monitoring Interval.
+*/
+
+#define DAC960_HealthStatusMonitoringInterval	(1 * HZ)
+
+
+/*
+  Define the DAC960 Controller Progress Reporting Interval.
+*/
+
+#define DAC960_ProgressReportingInterval	(60 * HZ)
+
+
+/*
+  Define the maximum number of Partitions allowed for each Logical Drive.
+*/
+
+#define DAC960_MaxPartitions			8
+#define DAC960_MaxPartitionsBits		3
+
+
+/*
+  Define macros to extract the Controller Number, Logical Drive Number, and
+  Partition Number from a Kernel Device, and to construct a Major Number, Minor
+  Number, and Kernel Device from the Controller Number, Logical Drive Number,
+  and Partition Number.  There is one Major Number assigned to each Controller.
+  The associated Minor Number is divided into the Logical Drive Number and
+  Partition Number.
+*/
+
+#define DAC960_ControllerNumber(Device) \
+  (MAJOR(Device) - DAC960_MAJOR)
+
+#define DAC960_LogicalDriveNumber(Device) \
+  (MINOR(Device) >> DAC960_MaxPartitionsBits)
+
+#define DAC960_PartitionNumber(Device) \
+  (MINOR(Device) & (DAC960_MaxPartitions - 1))
+
+#define DAC960_MajorNumber(ControllerNumber) \
+  (DAC960_MAJOR + (ControllerNumber))
+
+#define DAC960_MinorNumber(LogicalDriveNumber, PartitionNumber) \
+   (((LogicalDriveNumber) << DAC960_MaxPartitionsBits) | (PartitionNumber))
+
+#define DAC960_MinorCount			(DAC960_MaxLogicalDrives \
+						 * DAC960_MaxPartitions)
+
+#define DAC960_KernelDevice(ControllerNumber,				       \
+			    LogicalDriveNumber,				       \
+			    PartitionNumber)				       \
+   MKDEV(DAC960_MajorNumber(ControllerNumber),				       \
+	 DAC960_MinorNumber(LogicalDriveNumber, PartitionNumber))
+
+
+/*
+  Define the DAC960 Controller fixed Block Size and Block Size Bits.
+*/
+
+#define DAC960_BlockSize			512
 #define DAC960_BlockSizeBits			9
 
 
+/*
+  Define the number of Command structures that should be allocated as a
+  group to optimize kernel memory allocation.
+*/
+
+#define DAC960_V1_CommandAllocationGroupSize	11
+#define DAC960_V2_CommandAllocationGroupSize	29
+
+
 /*
-  Define the Controller Line Buffer, Status Buffer, Rebuild Progress,
-  and User Message Sizes.
+  Define the Controller Line Buffer, Progress Buffer, User Message, and
+  Initial Status Buffer sizes.
 */
 
 #define DAC960_LineBufferSize			100
-#define DAC960_StatusBufferSize			16384
-#define DAC960_RebuildProgressSize		200
+#define DAC960_ProgressBufferSize		200
 #define DAC960_UserMessageSize			200
+#define DAC960_InitialStatusBufferSize		(8192-32)
+
+
+/*
+  Define the DAC960 Controller Firmware Types.
+*/
+
+typedef enum
+{
+  DAC960_V1_Controller =			1,
+  DAC960_V2_Controller =			2
+}
+DAC960_FirmwareType_T;
 
 
 /*
-  Define the types of DAC960 Controllers that are supported.
+  Define the DAC960 Controller Hardware Types.
 */
 
 typedef enum
 {
-  DAC960_V5_Controller =			1,	/* DAC1164P */
-  DAC960_V4_Controller =			2,	/* DAC960PTL/PJ/PG */
-  DAC960_V3_Controller =			3	/* DAC960PU/PD/PL */
+  DAC960_BA_Controller =			1,	/* eXtremeRAID 2000 */
+  DAC960_LP_Controller =			2,	/* AcceleRAID 352 */
+  DAC960_LA_Controller =			3,	/* DAC1164P */
+  DAC960_PG_Controller =			4,	/* DAC960PTL/PJ/PG */
+  DAC960_PD_Controller =			5	/* DAC960PU/PD/PL */
 }
-DAC960_ControllerType_T;
+DAC960_HardwareType_T;
 
 
 /*
@@ -1130,286 +2169,1000 @@
 typedef struct wait_queue WaitQueue_T;
 
 
+/*
+  Define the DAC960 V1 Firmware Controller Status Mailbox structure.
+*/
+
+typedef union DAC960_V1_StatusMailbox
+{
+  unsigned int Word;					/* Word 0 */
+  struct {
+    DAC960_V1_CommandIdentifier_T CommandIdentifier;	/* Byte 0 */
+    unsigned char :7;					/* Byte 1 Bits 0-6 */
+    boolean Valid:1;					/* Byte 1 Bit 7 */
+    DAC960_V1_CommandStatus_T CommandStatus;		/* Bytes 2-3 */
+  } Fields;
+}
+DAC960_V1_StatusMailbox_T;
+
+
+/*
+  Define the DAC960 V2 Firmware Controller Status Mailbox structure.
+*/
+
+typedef union DAC960_V2_StatusMailbox
+{
+  unsigned int Words[2];				/* Words 0-1 */
+  struct {
+    DAC960_V2_CommandIdentifier_T CommandIdentifier;	/* Bytes 0-1 */
+    DAC960_V2_CommandStatus_T CommandStatus;		/* Byte 2 */
+    unsigned char RequestSenseLength;			/* Byte 3 */
+    int DataTransferResidue;				/* Bytes 4-7 */
+  } Fields;
+}
+DAC960_V2_StatusMailbox_T;
+
+
+/*
+  Define the DAC960 Driver Command Types.
+*/
+
+typedef enum
+{
+  DAC960_ReadCommand =				1,
+  DAC960_WriteCommand =				2,
+  DAC960_ReadRetryCommand =			3,
+  DAC960_WriteRetryCommand =			4,
+  DAC960_MonitoringCommand =			5,
+  DAC960_ImmediateCommand =			6,
+  DAC960_QueuedCommand =			7
+}
+DAC960_CommandType_T;
+
+
+/*
+  Define the DAC960 Driver Command structure.
+*/
+
+typedef struct DAC960_Command
+{
+  int CommandIdentifier;
+  DAC960_CommandType_T CommandType;
+  struct DAC960_Controller *Controller;
+  struct DAC960_Command *Next;
+  Semaphore_T *Semaphore;
+  unsigned int LogicalDriveNumber;
+  unsigned int BlockNumber;
+  unsigned int BlockCount;
+  unsigned int SegmentCount;
+  BufferHeader_T *BufferHeader;
+  void *RequestBuffer;
+  union {
+    struct {
+      DAC960_V1_CommandMailbox_T CommandMailbox;
+      DAC960_V1_KernelCommand_T *KernelCommand;
+      DAC960_V1_CommandStatus_T CommandStatus;
+      DAC960_V1_ScatterGatherSegment_T
+	ScatterGatherList[DAC960_V1_ScatterGatherLimit]
+	__attribute__ ((aligned (sizeof(DAC960_V1_ScatterGatherSegment_T))));
+      unsigned int EndMarker[0];
+    } V1;
+    struct {
+      DAC960_V2_CommandMailbox_T CommandMailbox;
+      DAC960_V2_KernelCommand_T *KernelCommand;
+      DAC960_V2_CommandStatus_T CommandStatus;
+      unsigned char RequestSenseLength;
+      int DataTransferResidue;
+      DAC960_V2_ScatterGatherSegment_T
+	ScatterGatherList[DAC960_V2_ScatterGatherLimit]
+	__attribute__ ((aligned (sizeof(DAC960_V2_ScatterGatherSegment_T))));
+      DAC960_SCSI_RequestSense_T RequestSense
+	__attribute__ ((aligned (sizeof(int))));
+      unsigned int EndMarker[0];
+    } V2;
+  } FW;
+}
+DAC960_Command_T;
+
+
+/*
+  Define the DAC960 Driver Controller structure.
+*/
+
+typedef struct DAC960_Controller
+{
+  void *BaseAddress;
+  void *MemoryMappedAddress;
+  DAC960_FirmwareType_T FirmwareType;
+  DAC960_HardwareType_T HardwareType;
+  DAC960_IO_Address_T IO_Address;
+  DAC960_PCI_Address_T PCI_Address;
+  unsigned char ControllerNumber;
+  unsigned char ControllerName[4];
+  unsigned char ModelName[20];
+  unsigned char FullModelName[28];
+  unsigned char FirmwareVersion[12];
+  unsigned char Bus;
+  unsigned char Device;
+  unsigned char Function;
+  unsigned char IRQ_Channel;
+  unsigned char Channels;
+  unsigned char Targets;
+  unsigned char MemorySize;
+  unsigned char LogicalDriveCount;
+  unsigned short CommandAllocationGroupSize;
+  unsigned short ControllerQueueDepth;
+  unsigned short DriverQueueDepth;
+  unsigned short MaxBlocksPerCommand;
+  unsigned short ControllerScatterGatherLimit;
+  unsigned short DriverScatterGatherLimit;
+  unsigned int ControllerUsageCount;
+  unsigned int CombinedStatusBufferLength;
+  unsigned int InitialStatusLength;
+  unsigned int CurrentStatusLength;
+  unsigned int ProgressBufferLength;
+  unsigned int UserStatusLength;
+  unsigned long MemoryMailboxPagesAddress;
+  unsigned long MemoryMailboxPagesOrder;
+  unsigned long MonitoringTimerCount;
+  unsigned long PrimaryMonitoringTime;
+  unsigned long SecondaryMonitoringTime;
+  unsigned long LastProgressReportTime;
+  unsigned long LastCurrentStatusTime;
+  boolean ControllerDetectionSuccessful;
+  boolean ControllerInitialized;
+  boolean MonitoringCommandDeferred;
+  boolean EphemeralProgressMessage;
+  boolean DriveSpinUpMessageDisplayed;
+  boolean MonitoringAlertMode;
+  Timer_T MonitoringTimer;
+  GenericDiskInfo_T GenericDiskInfo;
+  DAC960_Command_T *FreeCommands;
+  unsigned char *CombinedStatusBuffer;
+  unsigned char *CurrentStatusBuffer;
+  PROC_DirectoryEntry_T ControllerProcEntry;
+  PROC_DirectoryEntry_T InitialStatusProcEntry;
+  PROC_DirectoryEntry_T CurrentStatusProcEntry;
+  PROC_DirectoryEntry_T UserCommandProcEntry;
+  WaitQueue_T *CommandWaitQueue;
+  WaitQueue_T *HealthStatusWaitQueue;
+  DAC960_Command_T InitialCommand;
+  DAC960_Command_T *Commands[DAC960_MaxDriverQueueDepth];
+  unsigned int LogicalDriveUsageCount[DAC960_MaxLogicalDrives];
+  boolean LogicalDriveInitiallyAccessible[DAC960_MaxLogicalDrives];
+  void (*QueueCommand)(DAC960_Command_T *Command);
+  boolean (*ReadControllerConfiguration)(struct DAC960_Controller *);
+  boolean (*ReadDeviceConfiguration)(struct DAC960_Controller *);
+  boolean (*ReportDeviceConfiguration)(struct DAC960_Controller *);
+  void (*QueueReadWriteCommand)(DAC960_Command_T *Command);
+  union {
+    struct {
+      unsigned char GeometryTranslationHeads;
+      unsigned char GeometryTranslationSectors;
+      unsigned char PendingRebuildFlag;
+      unsigned short StripeSize;
+      unsigned short SegmentSize;
+      unsigned short NewEventLogSequenceNumber;
+      unsigned short OldEventLogSequenceNumber;
+      unsigned short DeviceStateChannel;
+      unsigned short DeviceStateTargetID;
+      boolean DualModeMemoryMailboxInterface;
+      boolean SAFTE_EnclosureManagementEnabled;
+      boolean NeedLogicalDriveInformation;
+      boolean NeedErrorTableInformation;
+      boolean NeedDeviceStateInformation;
+      boolean NeedDeviceInquiryInformation;
+      boolean NeedDeviceSerialNumberInformation;
+      boolean NeedRebuildProgress;
+      boolean NeedConsistencyCheckProgress;
+      boolean RebuildProgressFirst;
+      boolean RebuildFlagPending;
+      boolean RebuildStatusPending;
+      DAC960_V1_CommandMailbox_T *FirstCommandMailbox;
+      DAC960_V1_CommandMailbox_T *LastCommandMailbox;
+      DAC960_V1_CommandMailbox_T *NextCommandMailbox;
+      DAC960_V1_CommandMailbox_T *PreviousCommandMailbox1;
+      DAC960_V1_CommandMailbox_T *PreviousCommandMailbox2;
+      DAC960_V1_StatusMailbox_T *FirstStatusMailbox;
+      DAC960_V1_StatusMailbox_T *LastStatusMailbox;
+      DAC960_V1_StatusMailbox_T *NextStatusMailbox;
+      DAC960_V1_DCDB_T MonitoringDCDB;
+      DAC960_V1_Enquiry_T Enquiry;
+      DAC960_V1_Enquiry_T NewEnquiry;
+      DAC960_V1_ErrorTable_T ErrorTable;
+      DAC960_V1_ErrorTable_T NewErrorTable;
+      DAC960_V1_EventLogEntry_T EventLogEntry;
+      DAC960_V1_RebuildProgress_T RebuildProgress;
+      DAC960_V1_CommandStatus_T LastRebuildStatus;
+      DAC960_V1_CommandStatus_T PendingRebuildStatus;
+      DAC960_V1_LogicalDriveInformationArray_T LogicalDriveInformation;
+      DAC960_V1_LogicalDriveInformationArray_T NewLogicalDriveInformation;
+      DAC960_V1_DeviceState_T
+	DeviceState[DAC960_V1_MaxChannels][DAC960_V1_MaxTargets];
+      DAC960_V1_DeviceState_T NewDeviceState;
+      DAC960_SCSI_Inquiry_T
+	InquiryStandardData[DAC960_V1_MaxChannels][DAC960_V1_MaxTargets];
+      DAC960_SCSI_Inquiry_UnitSerialNumber_T
+	InquiryUnitSerialNumber[DAC960_V1_MaxChannels][DAC960_V1_MaxTargets];
+      int DeviceResetCount[DAC960_V1_MaxChannels][DAC960_V1_MaxTargets];
+      boolean DirectCommandActive[DAC960_V1_MaxChannels][DAC960_V1_MaxTargets];
+    } V1;
+    struct {
+      unsigned int StatusChangeCounter;
+      unsigned int NextEventSequenceNumber;
+      unsigned int PhysicalDeviceIndex;
+      boolean NeedLogicalDeviceInformation;
+      boolean NeedPhysicalDeviceInformation;
+      boolean NeedDeviceSerialNumberInformation;
+      DAC960_V2_CommandMailbox_T *FirstCommandMailbox;
+      DAC960_V2_CommandMailbox_T *LastCommandMailbox;
+      DAC960_V2_CommandMailbox_T *NextCommandMailbox;
+      DAC960_V2_CommandMailbox_T *PreviousCommandMailbox1;
+      DAC960_V2_CommandMailbox_T *PreviousCommandMailbox2;
+      DAC960_V2_StatusMailbox_T *FirstStatusMailbox;
+      DAC960_V2_StatusMailbox_T *LastStatusMailbox;
+      DAC960_V2_StatusMailbox_T *NextStatusMailbox;
+      DAC960_V2_HealthStatusBuffer_T *HealthStatusBuffer;
+      DAC960_V2_ControllerInfo_T ControllerInformation;
+      DAC960_V2_ControllerInfo_T NewControllerInformation;
+      DAC960_V2_LogicalDeviceInfo_T
+	*LogicalDeviceInformation[DAC960_MaxLogicalDrives];
+      DAC960_V2_LogicalDeviceInfo_T NewLogicalDeviceInformation;
+      DAC960_V2_PhysicalDeviceInfo_T
+	*PhysicalDeviceInformation[DAC960_V2_MaxPhysicalDevices];
+      DAC960_V2_PhysicalDeviceInfo_T NewPhysicalDeviceInformation;
+      DAC960_SCSI_Inquiry_UnitSerialNumber_T
+	*InquiryUnitSerialNumber[DAC960_V2_MaxPhysicalDevices];
+      DAC960_V2_PhysicalDevice_T
+	LogicalDriveToVirtualDevice[DAC960_MaxLogicalDrives];
+      DAC960_V2_Event_T Event;
+    } V2;
+  } FW;
+  DiskPartition_T DiskPartitions[DAC960_MinorCount];
+  int PartitionSizes[DAC960_MinorCount];
+  int BlockSizes[DAC960_MinorCount];
+  int MaxSectorsPerRequest[DAC960_MinorCount];
+  int MaxSegmentsPerRequest[DAC960_MinorCount];
+  unsigned char ProgressBuffer[DAC960_ProgressBufferSize];
+  unsigned char UserStatusBuffer[DAC960_UserMessageSize];
+}
+DAC960_Controller_T;
+
+
+/*
+  Simplify access to Firmware Version Dependent Data Structure Components
+  and Functions.
+*/
+
+#define V1				FW.V1
+#define V2				FW.V2
+#define DAC960_QueueCommand(Command) \
+  (Controller->QueueCommand)(Command)
+#define DAC960_ReadControllerConfiguration(Controller) \
+  (Controller->ReadControllerConfiguration)(Controller)
+#define DAC960_ReadDeviceConfiguration(Controller) \
+  (Controller->ReadDeviceConfiguration)(Controller)
+#define DAC960_ReportDeviceConfiguration(Controller) \
+  (Controller->ReportDeviceConfiguration)(Controller)
+#define DAC960_QueueReadWriteCommand(Command) \
+  (Controller->QueueReadWriteCommand)(Command)
+
+
+/*
+  DAC960_AcquireControllerLock acquires exclusive access to Controller.
+*/
+
+static inline
+void DAC960_AcquireControllerLock(DAC960_Controller_T *Controller,
+				  ProcessorFlags_T *ProcessorFlags)
+{
+  spin_lock_irqsave(&io_request_lock, *ProcessorFlags);
+}
+
+
+/*
+  DAC960_ReleaseControllerLock releases exclusive access to Controller.
+*/
+
+static inline
+void DAC960_ReleaseControllerLock(DAC960_Controller_T *Controller,
+				  ProcessorFlags_T *ProcessorFlags)
+{
+  spin_unlock_irqrestore(&io_request_lock, *ProcessorFlags);
+}
+
+
+/*
+  DAC960_AcquireControllerLockRF acquires exclusive access to Controller,
+  but is only called from the request function with the io_request_lock held.
+*/
+
+static inline
+void DAC960_AcquireControllerLockRF(DAC960_Controller_T *Controller,
+				    ProcessorFlags_T *ProcessorFlags)
+{
+}
+
+
+/*
+  DAC960_ReleaseControllerLockRF releases exclusive access to Controller,
+  but is only called from the request function with the io_request_lock held.
+*/
+
+static inline
+void DAC960_ReleaseControllerLockRF(DAC960_Controller_T *Controller,
+				    ProcessorFlags_T *ProcessorFlags)
+{
+}
+
+
+/*
+  DAC960_AcquireControllerLockIH acquires exclusive access to Controller,
+  but is only called from the interrupt handler.
+*/
+
+static inline
+void DAC960_AcquireControllerLockIH(DAC960_Controller_T *Controller,
+				    ProcessorFlags_T *ProcessorFlags)
+{
+  spin_lock_irqsave(&io_request_lock, *ProcessorFlags);
+}
+
+
+/*
+  DAC960_ReleaseControllerLockIH releases exclusive access to Controller,
+  but is only called from the interrupt handler.
+*/
+
+static inline
+void DAC960_ReleaseControllerLockIH(DAC960_Controller_T *Controller,
+				    ProcessorFlags_T *ProcessorFlags)
+{
+  spin_unlock_irqrestore(&io_request_lock, *ProcessorFlags);
+}
+
+
+/*
+  Define the DAC960 BA Series Controller Interface Register Offsets.
+*/
+
+#define DAC960_BA_RegisterWindowSize		0x80
+
+typedef enum
+{
+  DAC960_BA_InboundDoorBellRegisterOffset =	0x60,
+  DAC960_BA_OutboundDoorBellRegisterOffset =	0x61,
+  DAC960_BA_InterruptStatusRegisterOffset =	0x30,
+  DAC960_BA_InterruptMaskRegisterOffset =	0x34,
+  DAC960_BA_CommandMailboxBusAddressOffset =	0x50,
+  DAC960_BA_CommandStatusOffset =		0x58,
+  DAC960_BA_ErrorStatusRegisterOffset =		0x63
+}
+DAC960_BA_RegisterOffsets_T;
+
+
+/*
+  Define the structure of the DAC960 BA Series Inbound Door Bell Register.
+*/
+
+typedef union DAC960_BA_InboundDoorBellRegister
+{
+  unsigned char All;
+  struct {
+    boolean HardwareMailboxNewCommand:1;		/* Bit 0 */
+    boolean AcknowledgeHardwareMailboxStatus:1;		/* Bit 1 */
+    boolean GenerateInterrupt:1;			/* Bit 2 */
+    boolean ControllerReset:1;				/* Bit 3 */
+    boolean MemoryMailboxNewCommand:1;			/* Bit 4 */
+    unsigned char :3;					/* Bits 5-7 */
+  } Write;
+  struct {
+    boolean HardwareMailboxEmpty:1;			/* Bit 0 */
+    boolean InitializationNotInProgress:1;		/* Bit 1 */
+    unsigned char :6;					/* Bits 2-7 */
+  } Read;
+}
+DAC960_BA_InboundDoorBellRegister_T;
+
+
+/*
+  Define the structure of the DAC960 BA Series Outbound Door Bell Register.
+*/
+
+typedef union DAC960_BA_OutboundDoorBellRegister
+{
+  unsigned char All;
+  struct {
+    boolean AcknowledgeHardwareMailboxInterrupt:1;	/* Bit 0 */
+    boolean AcknowledgeMemoryMailboxInterrupt:1;	/* Bit 1 */
+    unsigned char :6;					/* Bits 2-7 */
+  } Write;
+  struct {
+    boolean HardwareMailboxStatusAvailable:1;		/* Bit 0 */
+    boolean MemoryMailboxStatusAvailable:1;		/* Bit 1 */
+    unsigned char :6;					/* Bits 2-7 */
+  } Read;
+}
+DAC960_BA_OutboundDoorBellRegister_T;
+
+
+/*
+  Define the structure of the DAC960 BA Series Interrupt Mask Register.
+*/
+
+typedef union DAC960_BA_InterruptMaskRegister
+{
+  unsigned char All;
+  struct {
+    unsigned int :2;					/* Bits 0-1 */
+    boolean DisableInterrupts:1;			/* Bit 2 */
+    boolean DisableInterruptsI2O:1;			/* Bit 3 */
+    unsigned int :4;					/* Bits 4-7 */
+  } Bits;
+}
+DAC960_BA_InterruptMaskRegister_T;
+
+
+/*
+  Define the structure of the DAC960 BA Series Error Status Register.
+*/
+
+typedef union DAC960_BA_ErrorStatusRegister
+{
+  unsigned char All;
+  struct {
+    unsigned int :2;					/* Bits 0-1 */
+    boolean ErrorStatusPending:1;			/* Bit 2 */
+    unsigned int :5;					/* Bits 3-7 */
+  } Bits;
+}
+DAC960_BA_ErrorStatusRegister_T;
+
+
+/*
+  Define inline functions to provide an abstraction for reading and writing the
+  DAC960 BA Series Controller Interface Registers.
+*/
+
+static inline
+void DAC960_BA_HardwareMailboxNewCommand(void *ControllerBaseAddress)
+{
+  DAC960_BA_InboundDoorBellRegister_T InboundDoorBellRegister;
+  InboundDoorBellRegister.All = 0;
+  InboundDoorBellRegister.Write.HardwareMailboxNewCommand = true;
+  writeb(InboundDoorBellRegister.All,
+	 ControllerBaseAddress + DAC960_BA_InboundDoorBellRegisterOffset);
+}
+
+static inline
+void DAC960_BA_AcknowledgeHardwareMailboxStatus(void *ControllerBaseAddress)
+{
+  DAC960_BA_InboundDoorBellRegister_T InboundDoorBellRegister;
+  InboundDoorBellRegister.All = 0;
+  InboundDoorBellRegister.Write.AcknowledgeHardwareMailboxStatus = true;
+  writeb(InboundDoorBellRegister.All,
+	 ControllerBaseAddress + DAC960_BA_InboundDoorBellRegisterOffset);
+}
+
+static inline
+void DAC960_BA_GenerateInterrupt(void *ControllerBaseAddress)
+{
+  DAC960_BA_InboundDoorBellRegister_T InboundDoorBellRegister;
+  InboundDoorBellRegister.All = 0;
+  InboundDoorBellRegister.Write.GenerateInterrupt = true;
+  writeb(InboundDoorBellRegister.All,
+	 ControllerBaseAddress + DAC960_BA_InboundDoorBellRegisterOffset);
+}
+
+static inline
+void DAC960_BA_ControllerReset(void *ControllerBaseAddress)
+{
+  DAC960_BA_InboundDoorBellRegister_T InboundDoorBellRegister;
+  InboundDoorBellRegister.All = 0;
+  InboundDoorBellRegister.Write.ControllerReset = true;
+  writeb(InboundDoorBellRegister.All,
+	 ControllerBaseAddress + DAC960_BA_InboundDoorBellRegisterOffset);
+}
+
+static inline
+void DAC960_BA_MemoryMailboxNewCommand(void *ControllerBaseAddress)
+{
+  DAC960_BA_InboundDoorBellRegister_T InboundDoorBellRegister;
+  InboundDoorBellRegister.All = 0;
+  InboundDoorBellRegister.Write.MemoryMailboxNewCommand = true;
+  writeb(InboundDoorBellRegister.All,
+	 ControllerBaseAddress + DAC960_BA_InboundDoorBellRegisterOffset);
+}
+
+static inline
+boolean DAC960_BA_HardwareMailboxFullP(void *ControllerBaseAddress)
+{
+  DAC960_BA_InboundDoorBellRegister_T InboundDoorBellRegister;
+  InboundDoorBellRegister.All =
+    readb(ControllerBaseAddress + DAC960_BA_InboundDoorBellRegisterOffset);
+  return !InboundDoorBellRegister.Read.HardwareMailboxEmpty;
+}
+
+static inline
+boolean DAC960_BA_InitializationInProgressP(void *ControllerBaseAddress)
+{
+  DAC960_BA_InboundDoorBellRegister_T InboundDoorBellRegister;
+  InboundDoorBellRegister.All =
+    readb(ControllerBaseAddress + DAC960_BA_InboundDoorBellRegisterOffset);
+  return !InboundDoorBellRegister.Read.InitializationNotInProgress;
+}
+
+static inline
+void DAC960_BA_AcknowledgeHardwareMailboxInterrupt(void *ControllerBaseAddress)
+{
+  DAC960_BA_OutboundDoorBellRegister_T OutboundDoorBellRegister;
+  OutboundDoorBellRegister.All = 0;
+  OutboundDoorBellRegister.Write.AcknowledgeHardwareMailboxInterrupt = true;
+  writeb(OutboundDoorBellRegister.All,
+	 ControllerBaseAddress + DAC960_BA_OutboundDoorBellRegisterOffset);
+}
+
+static inline
+void DAC960_BA_AcknowledgeMemoryMailboxInterrupt(void *ControllerBaseAddress)
+{
+  DAC960_BA_OutboundDoorBellRegister_T OutboundDoorBellRegister;
+  OutboundDoorBellRegister.All = 0;
+  OutboundDoorBellRegister.Write.AcknowledgeMemoryMailboxInterrupt = true;
+  writeb(OutboundDoorBellRegister.All,
+	 ControllerBaseAddress + DAC960_BA_OutboundDoorBellRegisterOffset);
+}
+
+static inline
+void DAC960_BA_AcknowledgeInterrupt(void *ControllerBaseAddress)
+{
+  DAC960_BA_OutboundDoorBellRegister_T OutboundDoorBellRegister;
+  OutboundDoorBellRegister.All = 0;
+  OutboundDoorBellRegister.Write.AcknowledgeHardwareMailboxInterrupt = true;
+  OutboundDoorBellRegister.Write.AcknowledgeMemoryMailboxInterrupt = true;
+  writeb(OutboundDoorBellRegister.All,
+	 ControllerBaseAddress + DAC960_BA_OutboundDoorBellRegisterOffset);
+}
+
+static inline
+boolean DAC960_BA_HardwareMailboxStatusAvailableP(void *ControllerBaseAddress)
+{
+  DAC960_BA_OutboundDoorBellRegister_T OutboundDoorBellRegister;
+  OutboundDoorBellRegister.All =
+    readb(ControllerBaseAddress + DAC960_BA_OutboundDoorBellRegisterOffset);
+  return OutboundDoorBellRegister.Read.HardwareMailboxStatusAvailable;
+}
+
+static inline
+boolean DAC960_BA_MemoryMailboxStatusAvailableP(void *ControllerBaseAddress)
+{
+  DAC960_BA_OutboundDoorBellRegister_T OutboundDoorBellRegister;
+  OutboundDoorBellRegister.All =
+    readb(ControllerBaseAddress + DAC960_BA_OutboundDoorBellRegisterOffset);
+  return OutboundDoorBellRegister.Read.MemoryMailboxStatusAvailable;
+}
+
+static inline
+void DAC960_BA_EnableInterrupts(void *ControllerBaseAddress)
+{
+  DAC960_BA_InterruptMaskRegister_T InterruptMaskRegister;
+  InterruptMaskRegister.All = 0xFF;
+  InterruptMaskRegister.Bits.DisableInterrupts = false;
+  InterruptMaskRegister.Bits.DisableInterruptsI2O = true;
+  writeb(InterruptMaskRegister.All,
+	 ControllerBaseAddress + DAC960_BA_InterruptMaskRegisterOffset);
+}
+
+static inline
+void DAC960_BA_DisableInterrupts(void *ControllerBaseAddress)
+{
+  DAC960_BA_InterruptMaskRegister_T InterruptMaskRegister;
+  InterruptMaskRegister.All = 0xFF;
+  InterruptMaskRegister.Bits.DisableInterrupts = true;
+  InterruptMaskRegister.Bits.DisableInterruptsI2O = true;
+  writeb(InterruptMaskRegister.All,
+	 ControllerBaseAddress + DAC960_BA_InterruptMaskRegisterOffset);
+}
+
+static inline
+boolean DAC960_BA_InterruptsEnabledP(void *ControllerBaseAddress)
+{
+  DAC960_BA_InterruptMaskRegister_T InterruptMaskRegister;
+  InterruptMaskRegister.All =
+    readb(ControllerBaseAddress + DAC960_BA_InterruptMaskRegisterOffset);
+  return !InterruptMaskRegister.Bits.DisableInterrupts;
+}
+
+static inline
+void DAC960_BA_WriteCommandMailbox(DAC960_V2_CommandMailbox_T
+				     *MemoryCommandMailbox,
+				   DAC960_V2_CommandMailbox_T
+				     *CommandMailbox)
+{
+  memcpy(&MemoryCommandMailbox->Words[1], &CommandMailbox->Words[1],
+	 sizeof(DAC960_V2_CommandMailbox_T) - sizeof(unsigned int));
+  wmb();
+  MemoryCommandMailbox->Words[0] = CommandMailbox->Words[0];
+  mb();
+}
+
+static inline
+void DAC960_BA_WriteHardwareMailbox(void *ControllerBaseAddress,
+				    DAC960_V2_CommandMailbox_T *CommandMailbox)
+{
+  writel(Virtual_to_Bus(CommandMailbox),
+	 ControllerBaseAddress + DAC960_BA_CommandMailboxBusAddressOffset);
+}
+
+static inline DAC960_V2_CommandIdentifier_T
+DAC960_BA_ReadCommandIdentifier(void *ControllerBaseAddress)
+{
+  return readw(ControllerBaseAddress + DAC960_BA_CommandStatusOffset);
+}
+
+static inline DAC960_V2_CommandStatus_T
+DAC960_BA_ReadCommandStatus(void *ControllerBaseAddress)
+{
+  return readw(ControllerBaseAddress + DAC960_BA_CommandStatusOffset + 2);
+}
+
+static inline boolean
+DAC960_BA_ReadErrorStatus(void *ControllerBaseAddress,
+			  unsigned char *ErrorStatus,
+			  unsigned char *Parameter0,
+			  unsigned char *Parameter1)
+{
+  DAC960_BA_ErrorStatusRegister_T ErrorStatusRegister;
+  ErrorStatusRegister.All =
+    readb(ControllerBaseAddress + DAC960_BA_ErrorStatusRegisterOffset);
+  if (!ErrorStatusRegister.Bits.ErrorStatusPending) return false;
+  ErrorStatusRegister.Bits.ErrorStatusPending = false;
+  *ErrorStatus = ErrorStatusRegister.All;
+  *Parameter0 =
+    readb(ControllerBaseAddress + DAC960_BA_CommandMailboxBusAddressOffset + 0);
+  *Parameter1 =
+    readb(ControllerBaseAddress + DAC960_BA_CommandMailboxBusAddressOffset + 1);
+  writeb(0xFF, ControllerBaseAddress + DAC960_BA_ErrorStatusRegisterOffset);
+  return true;
+}
+
+
 /*
-  Define the DAC960 Controller Status Mailbox structure.
+  Define the DAC960 LP Series Controller Interface Register Offsets.
 */
 
-typedef union DAC960_StatusMailbox
+#define DAC960_LP_RegisterWindowSize		0x80
+
+typedef enum
 {
-  unsigned int Word;					/* Bytes 0-3 */
-  struct {
-    DAC960_CommandIdentifier_T CommandIdentifier;	/* Byte 0 */
-    unsigned char :7;					/* Byte 1 Bits 0-6 */
-    boolean Valid:1;					/* Byte 1 Bit 7 */
-    DAC960_CommandStatus_T CommandStatus;		/* Bytes 2-3 */
-  } Fields;
+  DAC960_LP_InboundDoorBellRegisterOffset =	0x20,
+  DAC960_LP_OutboundDoorBellRegisterOffset =	0x2C,
+  DAC960_LP_InterruptStatusRegisterOffset =	0x30,
+  DAC960_LP_InterruptMaskRegisterOffset =	0x34,
+  DAC960_LP_CommandMailboxBusAddressOffset =	0x10,
+  DAC960_LP_CommandStatusOffset =		0x18,
+  DAC960_LP_ErrorStatusRegisterOffset =		0x2E
 }
-DAC960_StatusMailbox_T;
+DAC960_LP_RegisterOffsets_T;
 
 
 /*
-  Define the DAC960 Driver Command Types.
+  Define the structure of the DAC960 LP Series Inbound Door Bell Register.
 */
 
-typedef enum
+typedef union DAC960_LP_InboundDoorBellRegister
 {
-  DAC960_ReadCommand =				1,
-  DAC960_WriteCommand =				2,
-  DAC960_ReadRetryCommand =			3,
-  DAC960_WriteRetryCommand =			4,
-  DAC960_MonitoringCommand =			5,
-  DAC960_ImmediateCommand =			6,
-  DAC960_QueuedCommand =			7
+  unsigned char All;
+  struct {
+    boolean HardwareMailboxNewCommand:1;		/* Bit 0 */
+    boolean AcknowledgeHardwareMailboxStatus:1;		/* Bit 1 */
+    boolean GenerateInterrupt:1;			/* Bit 2 */
+    boolean ControllerReset:1;				/* Bit 3 */
+    boolean MemoryMailboxNewCommand:1;			/* Bit 4 */
+    unsigned char :3;					/* Bits 5-7 */
+  } Write;
+  struct {
+    boolean HardwareMailboxFull:1;			/* Bit 0 */
+    boolean InitializationInProgress:1;			/* Bit 1 */
+    unsigned char :6;					/* Bits 2-7 */
+  } Read;
 }
-DAC960_CommandType_T;
+DAC960_LP_InboundDoorBellRegister_T;
 
 
 /*
-  Define the DAC960 Driver Command structure.
+  Define the structure of the DAC960 LP Series Outbound Door Bell Register.
 */
 
-typedef struct DAC960_Command
+typedef union DAC960_LP_OutboundDoorBellRegister
 {
-  DAC960_CommandType_T CommandType;
-  DAC960_CommandMailbox_T CommandMailbox;
-  DAC960_CommandStatus_T CommandStatus;
-  struct DAC960_Controller *Controller;
-  struct DAC960_Command *Next;
-  Semaphore_T *Semaphore;
-  unsigned int LogicalDriveNumber;
-  unsigned int BlockNumber;
-  unsigned int BlockCount;
-  unsigned int SegmentCount;
-  BufferHeader_T *BufferHeader;
-  DAC960_KernelCommand_T *KernelCommand;
-  DAC960_ScatterGatherSegment_T
-    ScatterGatherList[DAC960_MaxScatterGatherSegments];
+  unsigned char All;
+  struct {
+    boolean AcknowledgeHardwareMailboxInterrupt:1;	/* Bit 0 */
+    boolean AcknowledgeMemoryMailboxInterrupt:1;	/* Bit 1 */
+    unsigned char :6;					/* Bits 2-7 */
+  } Write;
+  struct {
+    boolean HardwareMailboxStatusAvailable:1;		/* Bit 0 */
+    boolean MemoryMailboxStatusAvailable:1;		/* Bit 1 */
+    unsigned char :6;					/* Bits 2-7 */
+  } Read;
 }
-DAC960_Command_T;
+DAC960_LP_OutboundDoorBellRegister_T;
 
 
 /*
-  Define the DAC960 Driver Controller structure.
+  Define the structure of the DAC960 LP Series Interrupt Mask Register.
 */
 
-typedef struct DAC960_Controller
+typedef union DAC960_LP_InterruptMaskRegister
 {
-  void *BaseAddress;
-  void *MemoryMappedAddress;
-  DAC960_ControllerType_T ControllerType;
-  DAC960_IO_Address_T IO_Address;
-  DAC960_PCI_Address_T PCI_Address;
-  unsigned char ControllerNumber;
-  unsigned char ControllerName[4];
-  unsigned char ModelName[12];
-  unsigned char FullModelName[18];
-  unsigned char FirmwareVersion[14];
-  unsigned char Bus;
-  unsigned char Device;
-  unsigned char Function;
-  unsigned char IRQ_Channel;
-  unsigned char Channels;
-  unsigned char MemorySize;
-  unsigned char LogicalDriveCount;
-  unsigned char GeometryTranslationHeads;
-  unsigned char GeometryTranslationSectors;
-  unsigned char PendingRebuildFlag;
-  unsigned short ControllerQueueDepth;
-  unsigned short DriverQueueDepth;
-  unsigned short MaxBlocksPerCommand;
-  unsigned short MaxScatterGatherSegments;
-  unsigned short StripeSize;
-  unsigned short SegmentSize;
-  unsigned short NewEventLogSequenceNumber;
-  unsigned short OldEventLogSequenceNumber;
-  unsigned short InitialStatusLength;
-  unsigned short CurrentStatusLength;
-  unsigned short UserStatusLength;
-  unsigned short RebuildProgressLength;
-  unsigned int ControllerUsageCount;
-  unsigned int EnquiryIndex;
-  unsigned int LogicalDriveInformationIndex;
-  unsigned int ErrorTableIndex;
-  unsigned int DeviceStateIndex;
-  unsigned int DeviceStateChannel;
-  unsigned int DeviceStateTargetID;
-  unsigned long MonitoringTimerCount;
-  unsigned long SecondaryMonitoringTime;
-  unsigned long LastProgressReportTime;
-  unsigned long LastCurrentStatusTime;
-  boolean DualModeMemoryMailboxInterface;
-  boolean SAFTE_EnclosureManagementEnabled;
-  boolean ControllerInitialized;
-  boolean MonitoringCommandDeferred;
-  boolean NeedLogicalDriveInformation;
-  boolean NeedErrorTableInformation;
-  boolean NeedDeviceStateInformation;
-  boolean NeedDeviceInquiryInformation;
-  boolean NeedDeviceSerialNumberInformation;
-  boolean NeedRebuildProgress;
-  boolean NeedConsistencyCheckProgress;
-  boolean EphemeralProgressMessage;
-  boolean RebuildFlagPending;
-  boolean RebuildStatusPending;
-  boolean DriveSpinUpMessageDisplayed;
-  Timer_T MonitoringTimer;
-  GenericDiskInfo_T GenericDiskInfo;
-  DAC960_Command_T *FreeCommands;
-  DAC960_CommandMailbox_T *FirstCommandMailbox;
-  DAC960_CommandMailbox_T *LastCommandMailbox;
-  DAC960_CommandMailbox_T *NextCommandMailbox;
-  DAC960_CommandMailbox_T *PreviousCommandMailbox1;
-  DAC960_CommandMailbox_T *PreviousCommandMailbox2;
-  DAC960_StatusMailbox_T *FirstStatusMailbox;
-  DAC960_StatusMailbox_T *LastStatusMailbox;
-  DAC960_StatusMailbox_T *NextStatusMailbox;
-  PROC_DirectoryEntry_T ControllerProcEntry;
-  PROC_DirectoryEntry_T InitialStatusProcEntry;
-  PROC_DirectoryEntry_T CurrentStatusProcEntry;
-  PROC_DirectoryEntry_T UserCommandProcEntry;
-  WaitQueue_T *CommandWaitQueue;
-  DAC960_DCDB_T MonitoringDCDB;
-  DAC960_Enquiry_T Enquiry[2];
-  DAC960_ErrorTable_T ErrorTable[2];
-  DAC960_EventLogEntry_T EventLogEntry;
-  DAC960_RebuildProgress_T RebuildProgress;
-  DAC960_CommandStatus_T LastRebuildStatus;
-  DAC960_CommandStatus_T PendingRebuildStatus;
-  DAC960_LogicalDriveInformation_T
-    LogicalDriveInformation[2][DAC960_MaxLogicalDrives];
-  DAC960_LogicalDriveState_T LogicalDriveInitialState[DAC960_MaxLogicalDrives];
-  DAC960_DeviceState_T DeviceState[2][DAC960_MaxChannels][DAC960_MaxTargets];
-  DAC960_Command_T Commands[DAC960_MaxDriverQueueDepth];
-  DAC960_SCSI_Inquiry_T
-    InquiryStandardData[DAC960_MaxChannels][DAC960_MaxTargets];
-  DAC960_SCSI_Inquiry_UnitSerialNumber_T
-    InquiryUnitSerialNumber[DAC960_MaxChannels][DAC960_MaxTargets];
-  DiskPartition_T DiskPartitions[DAC960_MinorCount];
-  int LogicalDriveUsageCount[DAC960_MaxLogicalDrives];
-  int PartitionSizes[DAC960_MinorCount];
-  int BlockSizes[DAC960_MinorCount];
-  int MaxSectorsPerRequest[DAC960_MinorCount];
-  int MaxSegmentsPerRequest[DAC960_MinorCount];
-  int DeviceResetCount[DAC960_MaxChannels][DAC960_MaxTargets];
-  boolean DirectCommandActive[DAC960_MaxChannels][DAC960_MaxTargets];
-  char InitialStatusBuffer[DAC960_StatusBufferSize];
-  char CurrentStatusBuffer[DAC960_StatusBufferSize];
-  char UserStatusBuffer[DAC960_UserMessageSize];
-  char RebuildProgressBuffer[DAC960_RebuildProgressSize];
+  unsigned char All;
+  struct {
+    unsigned int :2;					/* Bits 0-1 */
+    boolean DisableInterrupts:1;			/* Bit 2 */
+    unsigned int :5;					/* Bits 3-7 */
+  } Bits;
 }
-DAC960_Controller_T;
+DAC960_LP_InterruptMaskRegister_T;
 
 
 /*
-  DAC960_AcquireControllerLock acquires exclusive access to Controller.
+  Define the structure of the DAC960 LP Series Error Status Register.
 */
 
-static inline
-void DAC960_AcquireControllerLock(DAC960_Controller_T *Controller,
-				  ProcessorFlags_T *ProcessorFlags)
+typedef union DAC960_LP_ErrorStatusRegister
 {
-  spin_lock_irqsave(&io_request_lock, *ProcessorFlags);
+  unsigned char All;
+  struct {
+    unsigned int :2;					/* Bits 0-1 */
+    boolean ErrorStatusPending:1;			/* Bit 2 */
+    unsigned int :5;					/* Bits 3-7 */
+  } Bits;
 }
+DAC960_LP_ErrorStatusRegister_T;
 
 
 /*
-  DAC960_ReleaseControllerLock releases exclusive access to Controller.
+  Define inline functions to provide an abstraction for reading and writing the
+  DAC960 LP Series Controller Interface Registers.
 */
 
 static inline
-void DAC960_ReleaseControllerLock(DAC960_Controller_T *Controller,
-				  ProcessorFlags_T *ProcessorFlags)
+void DAC960_LP_HardwareMailboxNewCommand(void *ControllerBaseAddress)
 {
-  spin_unlock_irqrestore(&io_request_lock, *ProcessorFlags);
+  DAC960_LP_InboundDoorBellRegister_T InboundDoorBellRegister;
+  InboundDoorBellRegister.All = 0;
+  InboundDoorBellRegister.Write.HardwareMailboxNewCommand = true;
+  writeb(InboundDoorBellRegister.All,
+	 ControllerBaseAddress + DAC960_LP_InboundDoorBellRegisterOffset);
 }
 
+static inline
+void DAC960_LP_AcknowledgeHardwareMailboxStatus(void *ControllerBaseAddress)
+{
+  DAC960_LP_InboundDoorBellRegister_T InboundDoorBellRegister;
+  InboundDoorBellRegister.All = 0;
+  InboundDoorBellRegister.Write.AcknowledgeHardwareMailboxStatus = true;
+  writeb(InboundDoorBellRegister.All,
+	 ControllerBaseAddress + DAC960_LP_InboundDoorBellRegisterOffset);
+}
 
-/*
-  DAC960_AcquireControllerLockRF acquires exclusive access to Controller,
-  but is only called from the request function with the io_request_lock held.
-*/
+static inline
+void DAC960_LP_GenerateInterrupt(void *ControllerBaseAddress)
+{
+  DAC960_LP_InboundDoorBellRegister_T InboundDoorBellRegister;
+  InboundDoorBellRegister.All = 0;
+  InboundDoorBellRegister.Write.GenerateInterrupt = true;
+  writeb(InboundDoorBellRegister.All,
+	 ControllerBaseAddress + DAC960_LP_InboundDoorBellRegisterOffset);
+}
 
 static inline
-void DAC960_AcquireControllerLockRF(DAC960_Controller_T *Controller,
-				    ProcessorFlags_T *ProcessorFlags)
+void DAC960_LP_ControllerReset(void *ControllerBaseAddress)
 {
+  DAC960_LP_InboundDoorBellRegister_T InboundDoorBellRegister;
+  InboundDoorBellRegister.All = 0;
+  InboundDoorBellRegister.Write.ControllerReset = true;
+  writeb(InboundDoorBellRegister.All,
+	 ControllerBaseAddress + DAC960_LP_InboundDoorBellRegisterOffset);
 }
 
+static inline
+void DAC960_LP_MemoryMailboxNewCommand(void *ControllerBaseAddress)
+{
+  DAC960_LP_InboundDoorBellRegister_T InboundDoorBellRegister;
+  InboundDoorBellRegister.All = 0;
+  InboundDoorBellRegister.Write.MemoryMailboxNewCommand = true;
+  writeb(InboundDoorBellRegister.All,
+	 ControllerBaseAddress + DAC960_LP_InboundDoorBellRegisterOffset);
+}
 
-/*
-  DAC960_ReleaseControllerLockRF releases exclusive access to Controller,
-  but is only called from the request function with the io_request_lock held.
-*/
+static inline
+boolean DAC960_LP_HardwareMailboxFullP(void *ControllerBaseAddress)
+{
+  DAC960_LP_InboundDoorBellRegister_T InboundDoorBellRegister;
+  InboundDoorBellRegister.All =
+    readb(ControllerBaseAddress + DAC960_LP_InboundDoorBellRegisterOffset);
+  return InboundDoorBellRegister.Read.HardwareMailboxFull;
+}
 
 static inline
-void DAC960_ReleaseControllerLockRF(DAC960_Controller_T *Controller,
-				    ProcessorFlags_T *ProcessorFlags)
+boolean DAC960_LP_InitializationInProgressP(void *ControllerBaseAddress)
 {
+  DAC960_LP_InboundDoorBellRegister_T InboundDoorBellRegister;
+  InboundDoorBellRegister.All =
+    readb(ControllerBaseAddress + DAC960_LP_InboundDoorBellRegisterOffset);
+  return InboundDoorBellRegister.Read.InitializationInProgress;
 }
 
+static inline
+void DAC960_LP_AcknowledgeHardwareMailboxInterrupt(void *ControllerBaseAddress)
+{
+  DAC960_LP_OutboundDoorBellRegister_T OutboundDoorBellRegister;
+  OutboundDoorBellRegister.All = 0;
+  OutboundDoorBellRegister.Write.AcknowledgeHardwareMailboxInterrupt = true;
+  writeb(OutboundDoorBellRegister.All,
+	 ControllerBaseAddress + DAC960_LP_OutboundDoorBellRegisterOffset);
+}
 
-/*
-  DAC960_AcquireControllerLockIH acquires exclusive access to Controller,
-  but is only called from the interrupt handler.
-*/
+static inline
+void DAC960_LP_AcknowledgeMemoryMailboxInterrupt(void *ControllerBaseAddress)
+{
+  DAC960_LP_OutboundDoorBellRegister_T OutboundDoorBellRegister;
+  OutboundDoorBellRegister.All = 0;
+  OutboundDoorBellRegister.Write.AcknowledgeMemoryMailboxInterrupt = true;
+  writeb(OutboundDoorBellRegister.All,
+	 ControllerBaseAddress + DAC960_LP_OutboundDoorBellRegisterOffset);
+}
 
 static inline
-void DAC960_AcquireControllerLockIH(DAC960_Controller_T *Controller,
-				    ProcessorFlags_T *ProcessorFlags)
+void DAC960_LP_AcknowledgeInterrupt(void *ControllerBaseAddress)
 {
-  spin_lock_irqsave(&io_request_lock, *ProcessorFlags);
+  DAC960_LP_OutboundDoorBellRegister_T OutboundDoorBellRegister;
+  OutboundDoorBellRegister.All = 0;
+  OutboundDoorBellRegister.Write.AcknowledgeHardwareMailboxInterrupt = true;
+  OutboundDoorBellRegister.Write.AcknowledgeMemoryMailboxInterrupt = true;
+  writeb(OutboundDoorBellRegister.All,
+	 ControllerBaseAddress + DAC960_LP_OutboundDoorBellRegisterOffset);
 }
 
+static inline
+boolean DAC960_LP_HardwareMailboxStatusAvailableP(void *ControllerBaseAddress)
+{
+  DAC960_LP_OutboundDoorBellRegister_T OutboundDoorBellRegister;
+  OutboundDoorBellRegister.All =
+    readb(ControllerBaseAddress + DAC960_LP_OutboundDoorBellRegisterOffset);
+  return OutboundDoorBellRegister.Read.HardwareMailboxStatusAvailable;
+}
 
-/*
-  DAC960_ReleaseControllerLockIH releases exclusive access to Controller,
-  but is only called from the interrupt handler.
-*/
+static inline
+boolean DAC960_LP_MemoryMailboxStatusAvailableP(void *ControllerBaseAddress)
+{
+  DAC960_LP_OutboundDoorBellRegister_T OutboundDoorBellRegister;
+  OutboundDoorBellRegister.All =
+    readb(ControllerBaseAddress + DAC960_LP_OutboundDoorBellRegisterOffset);
+  return OutboundDoorBellRegister.Read.MemoryMailboxStatusAvailable;
+}
 
 static inline
-void DAC960_ReleaseControllerLockIH(DAC960_Controller_T *Controller,
-				    ProcessorFlags_T *ProcessorFlags)
+void DAC960_LP_EnableInterrupts(void *ControllerBaseAddress)
 {
-  spin_unlock_irqrestore(&io_request_lock, *ProcessorFlags);
+  DAC960_LP_InterruptMaskRegister_T InterruptMaskRegister;
+  InterruptMaskRegister.All = 0xFF;
+  InterruptMaskRegister.Bits.DisableInterrupts = false;
+  writeb(InterruptMaskRegister.All,
+	 ControllerBaseAddress + DAC960_LP_InterruptMaskRegisterOffset);
+}
+
+static inline
+void DAC960_LP_DisableInterrupts(void *ControllerBaseAddress)
+{
+  DAC960_LP_InterruptMaskRegister_T InterruptMaskRegister;
+  InterruptMaskRegister.All = 0xFF;
+  InterruptMaskRegister.Bits.DisableInterrupts = true;
+  writeb(InterruptMaskRegister.All,
+	 ControllerBaseAddress + DAC960_LP_InterruptMaskRegisterOffset);
+}
+
+static inline
+boolean DAC960_LP_InterruptsEnabledP(void *ControllerBaseAddress)
+{
+  DAC960_LP_InterruptMaskRegister_T InterruptMaskRegister;
+  InterruptMaskRegister.All =
+    readb(ControllerBaseAddress + DAC960_LP_InterruptMaskRegisterOffset);
+  return !InterruptMaskRegister.Bits.DisableInterrupts;
+}
+
+static inline
+void DAC960_LP_WriteCommandMailbox(DAC960_V2_CommandMailbox_T
+				     *MemoryCommandMailbox,
+				   DAC960_V2_CommandMailbox_T
+				     *CommandMailbox)
+{
+  memcpy(&MemoryCommandMailbox->Words[1], &CommandMailbox->Words[1],
+	 sizeof(DAC960_V2_CommandMailbox_T) - sizeof(unsigned int));
+  wmb();
+  MemoryCommandMailbox->Words[0] = CommandMailbox->Words[0];
+  mb();
+}
+
+static inline
+void DAC960_LP_WriteHardwareMailbox(void *ControllerBaseAddress,
+				    DAC960_V2_CommandMailbox_T *CommandMailbox)
+{
+  writel(Virtual_to_Bus(CommandMailbox),
+	 ControllerBaseAddress + DAC960_LP_CommandMailboxBusAddressOffset);
+}
+
+static inline DAC960_V2_CommandIdentifier_T
+DAC960_LP_ReadCommandIdentifier(void *ControllerBaseAddress)
+{
+  return readw(ControllerBaseAddress + DAC960_LP_CommandStatusOffset);
+}
+
+static inline DAC960_V2_CommandStatus_T
+DAC960_LP_ReadCommandStatus(void *ControllerBaseAddress)
+{
+  return readw(ControllerBaseAddress + DAC960_LP_CommandStatusOffset + 2);
+}
+
+static inline boolean
+DAC960_LP_ReadErrorStatus(void *ControllerBaseAddress,
+			  unsigned char *ErrorStatus,
+			  unsigned char *Parameter0,
+			  unsigned char *Parameter1)
+{
+  DAC960_LP_ErrorStatusRegister_T ErrorStatusRegister;
+  ErrorStatusRegister.All =
+    readb(ControllerBaseAddress + DAC960_LP_ErrorStatusRegisterOffset);
+  if (!ErrorStatusRegister.Bits.ErrorStatusPending) return false;
+  ErrorStatusRegister.Bits.ErrorStatusPending = false;
+  *ErrorStatus = ErrorStatusRegister.All;
+  *Parameter0 =
+    readb(ControllerBaseAddress + DAC960_LP_CommandMailboxBusAddressOffset + 0);
+  *Parameter1 =
+    readb(ControllerBaseAddress + DAC960_LP_CommandMailboxBusAddressOffset + 1);
+  writeb(0xFF, ControllerBaseAddress + DAC960_LP_ErrorStatusRegisterOffset);
+  return true;
 }
 
 
 /*
-  Define the DAC960 V5 Controller Interface Register Offsets.
+  Define the DAC960 LA Series Controller Interface Register Offsets.
 */
 
-#define DAC960_V5_RegisterWindowSize		0x80
+#define DAC960_LA_RegisterWindowSize		0x80
 
 typedef enum
 {
-  DAC960_V5_InboundDoorBellRegisterOffset =	0x60,
-  DAC960_V5_OutboundDoorBellRegisterOffset =	0x61,
-  DAC960_V5_InterruptMaskRegisterOffset =	0x34,
-  DAC960_V5_CommandOpcodeRegisterOffset =	0x50,
-  DAC960_V5_CommandIdentifierRegisterOffset =	0x51,
-  DAC960_V5_MailboxRegister2Offset =		0x52,
-  DAC960_V5_MailboxRegister3Offset =		0x53,
-  DAC960_V5_MailboxRegister4Offset =		0x54,
-  DAC960_V5_MailboxRegister5Offset =		0x55,
-  DAC960_V5_MailboxRegister6Offset =		0x56,
-  DAC960_V5_MailboxRegister7Offset =		0x57,
-  DAC960_V5_MailboxRegister8Offset =		0x58,
-  DAC960_V5_MailboxRegister9Offset =		0x59,
-  DAC960_V5_MailboxRegister10Offset =		0x5A,
-  DAC960_V5_MailboxRegister11Offset =		0x5B,
-  DAC960_V5_MailboxRegister12Offset =		0x5C,
-  DAC960_V5_StatusCommandIdentifierRegOffset =	0x5D,
-  DAC960_V5_StatusRegisterOffset =		0x5E,
-  DAC960_V5_ErrorStatusRegisterOffset =		0x63
+  DAC960_LA_InboundDoorBellRegisterOffset =	0x60,
+  DAC960_LA_OutboundDoorBellRegisterOffset =	0x61,
+  DAC960_LA_InterruptMaskRegisterOffset =	0x34,
+  DAC960_LA_CommandOpcodeRegisterOffset =	0x50,
+  DAC960_LA_CommandIdentifierRegisterOffset =	0x51,
+  DAC960_LA_MailboxRegister2Offset =		0x52,
+  DAC960_LA_MailboxRegister3Offset =		0x53,
+  DAC960_LA_MailboxRegister4Offset =		0x54,
+  DAC960_LA_MailboxRegister5Offset =		0x55,
+  DAC960_LA_MailboxRegister6Offset =		0x56,
+  DAC960_LA_MailboxRegister7Offset =		0x57,
+  DAC960_LA_MailboxRegister8Offset =		0x58,
+  DAC960_LA_MailboxRegister9Offset =		0x59,
+  DAC960_LA_MailboxRegister10Offset =		0x5A,
+  DAC960_LA_MailboxRegister11Offset =		0x5B,
+  DAC960_LA_MailboxRegister12Offset =		0x5C,
+  DAC960_LA_StatusCommandIdentifierRegOffset =	0x5D,
+  DAC960_LA_StatusRegisterOffset =		0x5E,
+  DAC960_LA_ErrorStatusRegisterOffset =		0x63
 }
-DAC960_V5_RegisterOffsets_T;
+DAC960_LA_RegisterOffsets_T;
 
 
 /*
-  Define the structure of the DAC960 V5 Inbound Door Bell Register.
+  Define the structure of the DAC960 LA Series Inbound Door Bell Register.
 */
 
-typedef union DAC960_V5_InboundDoorBellRegister
+typedef union DAC960_LA_InboundDoorBellRegister
 {
   unsigned char All;
   struct {
@@ -1426,14 +3179,14 @@
     unsigned char :6;					/* Bits 2-7 */
   } Read;
 }
-DAC960_V5_InboundDoorBellRegister_T;
+DAC960_LA_InboundDoorBellRegister_T;
 
 
 /*
-  Define the structure of the DAC960 V5 Outbound Door Bell Register.
+  Define the structure of the DAC960 LA Series Outbound Door Bell Register.
 */
 
-typedef union DAC960_V5_OutboundDoorBellRegister
+typedef union DAC960_LA_OutboundDoorBellRegister
 {
   unsigned char All;
   struct {
@@ -1447,14 +3200,14 @@
     unsigned char :6;					/* Bits 2-7 */
   } Read;
 }
-DAC960_V5_OutboundDoorBellRegister_T;
+DAC960_LA_OutboundDoorBellRegister_T;
 
 
 /*
-  Define the structure of the DAC960 V5 Interrupt Mask Register.
+  Define the structure of the DAC960 LA Series Interrupt Mask Register.
 */
 
-typedef union DAC960_V5_InterruptMaskRegister
+typedef union DAC960_LA_InterruptMaskRegister
 {
   unsigned char All;
   struct {
@@ -1463,14 +3216,14 @@
     unsigned char :5;					/* Bits 3-7 */
   } Bits;
 }
-DAC960_V5_InterruptMaskRegister_T;
+DAC960_LA_InterruptMaskRegister_T;
 
 
 /*
-  Define the structure of the DAC960 V5 Error Status Register.
+  Define the structure of the DAC960 LA Series Error Status Register.
 */
 
-typedef union DAC960_V5_ErrorStatusRegister
+typedef union DAC960_LA_ErrorStatusRegister
 {
   unsigned char All;
   struct {
@@ -1479,288 +3232,290 @@
     unsigned int :5;					/* Bits 3-7 */
   } Bits;
 }
-DAC960_V5_ErrorStatusRegister_T;
+DAC960_LA_ErrorStatusRegister_T;
 
 
 /*
   Define inline functions to provide an abstraction for reading and writing the
-  DAC960 V5 Controller Interface Registers.
+  DAC960 LA Series Controller Interface Registers.
 */
 
 static inline
-void DAC960_V5_HardwareMailboxNewCommand(void *ControllerBaseAddress)
+void DAC960_LA_HardwareMailboxNewCommand(void *ControllerBaseAddress)
 {
-  DAC960_V5_InboundDoorBellRegister_T InboundDoorBellRegister;
+  DAC960_LA_InboundDoorBellRegister_T InboundDoorBellRegister;
   InboundDoorBellRegister.All = 0;
   InboundDoorBellRegister.Write.HardwareMailboxNewCommand = true;
   writeb(InboundDoorBellRegister.All,
-	 ControllerBaseAddress + DAC960_V5_InboundDoorBellRegisterOffset);
+	 ControllerBaseAddress + DAC960_LA_InboundDoorBellRegisterOffset);
 }
 
 static inline
-void DAC960_V5_AcknowledgeHardwareMailboxStatus(void *ControllerBaseAddress)
+void DAC960_LA_AcknowledgeHardwareMailboxStatus(void *ControllerBaseAddress)
 {
-  DAC960_V5_InboundDoorBellRegister_T InboundDoorBellRegister;
+  DAC960_LA_InboundDoorBellRegister_T InboundDoorBellRegister;
   InboundDoorBellRegister.All = 0;
   InboundDoorBellRegister.Write.AcknowledgeHardwareMailboxStatus = true;
   writeb(InboundDoorBellRegister.All,
-	 ControllerBaseAddress + DAC960_V5_InboundDoorBellRegisterOffset);
+	 ControllerBaseAddress + DAC960_LA_InboundDoorBellRegisterOffset);
 }
 
 static inline
-void DAC960_V5_GenerateInterrupt(void *ControllerBaseAddress)
+void DAC960_LA_GenerateInterrupt(void *ControllerBaseAddress)
 {
-  DAC960_V5_InboundDoorBellRegister_T InboundDoorBellRegister;
+  DAC960_LA_InboundDoorBellRegister_T InboundDoorBellRegister;
   InboundDoorBellRegister.All = 0;
   InboundDoorBellRegister.Write.GenerateInterrupt = true;
   writeb(InboundDoorBellRegister.All,
-	 ControllerBaseAddress + DAC960_V5_InboundDoorBellRegisterOffset);
+	 ControllerBaseAddress + DAC960_LA_InboundDoorBellRegisterOffset);
 }
 
 static inline
-void DAC960_V5_ControllerReset(void *ControllerBaseAddress)
+void DAC960_LA_ControllerReset(void *ControllerBaseAddress)
 {
-  DAC960_V5_InboundDoorBellRegister_T InboundDoorBellRegister;
+  DAC960_LA_InboundDoorBellRegister_T InboundDoorBellRegister;
   InboundDoorBellRegister.All = 0;
   InboundDoorBellRegister.Write.ControllerReset = true;
   writeb(InboundDoorBellRegister.All,
-	 ControllerBaseAddress + DAC960_V5_InboundDoorBellRegisterOffset);
+	 ControllerBaseAddress + DAC960_LA_InboundDoorBellRegisterOffset);
 }
 
 static inline
-void DAC960_V5_MemoryMailboxNewCommand(void *ControllerBaseAddress)
+void DAC960_LA_MemoryMailboxNewCommand(void *ControllerBaseAddress)
 {
-  DAC960_V5_InboundDoorBellRegister_T InboundDoorBellRegister;
+  DAC960_LA_InboundDoorBellRegister_T InboundDoorBellRegister;
   InboundDoorBellRegister.All = 0;
   InboundDoorBellRegister.Write.MemoryMailboxNewCommand = true;
   writeb(InboundDoorBellRegister.All,
-	 ControllerBaseAddress + DAC960_V5_InboundDoorBellRegisterOffset);
+	 ControllerBaseAddress + DAC960_LA_InboundDoorBellRegisterOffset);
 }
 
 static inline
-boolean DAC960_V5_HardwareMailboxFullP(void *ControllerBaseAddress)
+boolean DAC960_LA_HardwareMailboxFullP(void *ControllerBaseAddress)
 {
-  DAC960_V5_InboundDoorBellRegister_T InboundDoorBellRegister;
+  DAC960_LA_InboundDoorBellRegister_T InboundDoorBellRegister;
   InboundDoorBellRegister.All =
-    readb(ControllerBaseAddress + DAC960_V5_InboundDoorBellRegisterOffset);
+    readb(ControllerBaseAddress + DAC960_LA_InboundDoorBellRegisterOffset);
   return !InboundDoorBellRegister.Read.HardwareMailboxEmpty;
 }
 
 static inline
-boolean DAC960_V5_InitializationInProgressP(void *ControllerBaseAddress)
+boolean DAC960_LA_InitializationInProgressP(void *ControllerBaseAddress)
 {
-  DAC960_V5_InboundDoorBellRegister_T InboundDoorBellRegister;
+  DAC960_LA_InboundDoorBellRegister_T InboundDoorBellRegister;
   InboundDoorBellRegister.All =
-    readb(ControllerBaseAddress + DAC960_V5_InboundDoorBellRegisterOffset);
+    readb(ControllerBaseAddress + DAC960_LA_InboundDoorBellRegisterOffset);
   return !InboundDoorBellRegister.Read.InitializationNotInProgress;
 }
 
 static inline
-void DAC960_V5_AcknowledgeHardwareMailboxInterrupt(void *ControllerBaseAddress)
+void DAC960_LA_AcknowledgeHardwareMailboxInterrupt(void *ControllerBaseAddress)
 {
-  DAC960_V5_OutboundDoorBellRegister_T OutboundDoorBellRegister;
+  DAC960_LA_OutboundDoorBellRegister_T OutboundDoorBellRegister;
   OutboundDoorBellRegister.All = 0;
   OutboundDoorBellRegister.Write.AcknowledgeHardwareMailboxInterrupt = true;
   writeb(OutboundDoorBellRegister.All,
-	 ControllerBaseAddress + DAC960_V5_OutboundDoorBellRegisterOffset);
+	 ControllerBaseAddress + DAC960_LA_OutboundDoorBellRegisterOffset);
 }
 
 static inline
-void DAC960_V5_AcknowledgeMemoryMailboxInterrupt(void *ControllerBaseAddress)
+void DAC960_LA_AcknowledgeMemoryMailboxInterrupt(void *ControllerBaseAddress)
 {
-  DAC960_V5_OutboundDoorBellRegister_T OutboundDoorBellRegister;
+  DAC960_LA_OutboundDoorBellRegister_T OutboundDoorBellRegister;
   OutboundDoorBellRegister.All = 0;
   OutboundDoorBellRegister.Write.AcknowledgeMemoryMailboxInterrupt = true;
   writeb(OutboundDoorBellRegister.All,
-	 ControllerBaseAddress + DAC960_V5_OutboundDoorBellRegisterOffset);
+	 ControllerBaseAddress + DAC960_LA_OutboundDoorBellRegisterOffset);
 }
 
 static inline
-void DAC960_V5_AcknowledgeInterrupt(void *ControllerBaseAddress)
+void DAC960_LA_AcknowledgeInterrupt(void *ControllerBaseAddress)
 {
-  DAC960_V5_OutboundDoorBellRegister_T OutboundDoorBellRegister;
+  DAC960_LA_OutboundDoorBellRegister_T OutboundDoorBellRegister;
   OutboundDoorBellRegister.All = 0;
   OutboundDoorBellRegister.Write.AcknowledgeHardwareMailboxInterrupt = true;
   OutboundDoorBellRegister.Write.AcknowledgeMemoryMailboxInterrupt = true;
   writeb(OutboundDoorBellRegister.All,
-	 ControllerBaseAddress + DAC960_V5_OutboundDoorBellRegisterOffset);
+	 ControllerBaseAddress + DAC960_LA_OutboundDoorBellRegisterOffset);
 }
 
 static inline
-boolean DAC960_V5_HardwareMailboxStatusAvailableP(void *ControllerBaseAddress)
+boolean DAC960_LA_HardwareMailboxStatusAvailableP(void *ControllerBaseAddress)
 {
-  DAC960_V5_OutboundDoorBellRegister_T OutboundDoorBellRegister;
+  DAC960_LA_OutboundDoorBellRegister_T OutboundDoorBellRegister;
   OutboundDoorBellRegister.All =
-    readb(ControllerBaseAddress + DAC960_V5_OutboundDoorBellRegisterOffset);
+    readb(ControllerBaseAddress + DAC960_LA_OutboundDoorBellRegisterOffset);
   return OutboundDoorBellRegister.Read.HardwareMailboxStatusAvailable;
 }
 
 static inline
-boolean DAC960_V5_MemoryMailboxStatusAvailableP(void *ControllerBaseAddress)
+boolean DAC960_LA_MemoryMailboxStatusAvailableP(void *ControllerBaseAddress)
 {
-  DAC960_V5_OutboundDoorBellRegister_T OutboundDoorBellRegister;
+  DAC960_LA_OutboundDoorBellRegister_T OutboundDoorBellRegister;
   OutboundDoorBellRegister.All =
-    readb(ControllerBaseAddress + DAC960_V5_OutboundDoorBellRegisterOffset);
+    readb(ControllerBaseAddress + DAC960_LA_OutboundDoorBellRegisterOffset);
   return OutboundDoorBellRegister.Read.MemoryMailboxStatusAvailable;
 }
 
 static inline
-void DAC960_V5_EnableInterrupts(void *ControllerBaseAddress)
+void DAC960_LA_EnableInterrupts(void *ControllerBaseAddress)
 {
-  DAC960_V5_InterruptMaskRegister_T InterruptMaskRegister;
+  DAC960_LA_InterruptMaskRegister_T InterruptMaskRegister;
   InterruptMaskRegister.All = 0xFF;
   InterruptMaskRegister.Bits.DisableInterrupts = false;
   writeb(InterruptMaskRegister.All,
-	 ControllerBaseAddress + DAC960_V5_InterruptMaskRegisterOffset);
+	 ControllerBaseAddress + DAC960_LA_InterruptMaskRegisterOffset);
 }
 
 static inline
-void DAC960_V5_DisableInterrupts(void *ControllerBaseAddress)
+void DAC960_LA_DisableInterrupts(void *ControllerBaseAddress)
 {
-  DAC960_V5_InterruptMaskRegister_T InterruptMaskRegister;
+  DAC960_LA_InterruptMaskRegister_T InterruptMaskRegister;
   InterruptMaskRegister.All = 0xFF;
   InterruptMaskRegister.Bits.DisableInterrupts = true;
   writeb(InterruptMaskRegister.All,
-	 ControllerBaseAddress + DAC960_V5_InterruptMaskRegisterOffset);
+	 ControllerBaseAddress + DAC960_LA_InterruptMaskRegisterOffset);
 }
 
 static inline
-boolean DAC960_V5_InterruptsEnabledP(void *ControllerBaseAddress)
+boolean DAC960_LA_InterruptsEnabledP(void *ControllerBaseAddress)
 {
-  DAC960_V5_InterruptMaskRegister_T InterruptMaskRegister;
+  DAC960_LA_InterruptMaskRegister_T InterruptMaskRegister;
   InterruptMaskRegister.All =
-    readb(ControllerBaseAddress + DAC960_V5_InterruptMaskRegisterOffset);
+    readb(ControllerBaseAddress + DAC960_LA_InterruptMaskRegisterOffset);
   return !InterruptMaskRegister.Bits.DisableInterrupts;
 }
 
 static inline
-void DAC960_V5_WriteCommandMailbox(DAC960_CommandMailbox_T *NextCommandMailbox,
-				   DAC960_CommandMailbox_T *CommandMailbox)
-{
-  NextCommandMailbox->Words[1] = CommandMailbox->Words[1];
-  NextCommandMailbox->Words[2] = CommandMailbox->Words[2];
-  NextCommandMailbox->Words[3] = CommandMailbox->Words[3];
+void DAC960_LA_WriteCommandMailbox(DAC960_V1_CommandMailbox_T
+				     *MemoryCommandMailbox,
+				   DAC960_V1_CommandMailbox_T
+				     *CommandMailbox)
+{
+  MemoryCommandMailbox->Words[1] = CommandMailbox->Words[1];
+  MemoryCommandMailbox->Words[2] = CommandMailbox->Words[2];
+  MemoryCommandMailbox->Words[3] = CommandMailbox->Words[3];
   wmb();
-  NextCommandMailbox->Words[0] = CommandMailbox->Words[0];
+  MemoryCommandMailbox->Words[0] = CommandMailbox->Words[0];
   mb();
 }
 
 static inline
-void DAC960_V5_WriteHardwareMailbox(void *ControllerBaseAddress,
-				    DAC960_CommandMailbox_T *CommandMailbox)
+void DAC960_LA_WriteHardwareMailbox(void *ControllerBaseAddress,
+				    DAC960_V1_CommandMailbox_T *CommandMailbox)
 {
   writel(CommandMailbox->Words[0],
-	 ControllerBaseAddress + DAC960_V5_CommandOpcodeRegisterOffset);
+	 ControllerBaseAddress + DAC960_LA_CommandOpcodeRegisterOffset);
   writel(CommandMailbox->Words[1],
-	 ControllerBaseAddress + DAC960_V5_MailboxRegister4Offset);
+	 ControllerBaseAddress + DAC960_LA_MailboxRegister4Offset);
   writel(CommandMailbox->Words[2],
-	 ControllerBaseAddress + DAC960_V5_MailboxRegister8Offset);
+	 ControllerBaseAddress + DAC960_LA_MailboxRegister8Offset);
   writeb(CommandMailbox->Bytes[12],
-	 ControllerBaseAddress + DAC960_V5_MailboxRegister12Offset);
+	 ControllerBaseAddress + DAC960_LA_MailboxRegister12Offset);
 }
 
-static inline DAC960_CommandIdentifier_T
-DAC960_V5_ReadStatusCommandIdentifier(void *ControllerBaseAddress)
+static inline DAC960_V1_CommandIdentifier_T
+DAC960_LA_ReadStatusCommandIdentifier(void *ControllerBaseAddress)
 {
   return readb(ControllerBaseAddress
-	       + DAC960_V5_StatusCommandIdentifierRegOffset);
+	       + DAC960_LA_StatusCommandIdentifierRegOffset);
 }
 
-static inline DAC960_CommandStatus_T
-DAC960_V5_ReadStatusRegister(void *ControllerBaseAddress)
+static inline DAC960_V1_CommandStatus_T
+DAC960_LA_ReadStatusRegister(void *ControllerBaseAddress)
 {
-  return readw(ControllerBaseAddress + DAC960_V5_StatusRegisterOffset);
+  return readw(ControllerBaseAddress + DAC960_LA_StatusRegisterOffset);
 }
 
 static inline boolean
-DAC960_V5_ReadErrorStatus(void *ControllerBaseAddress,
+DAC960_LA_ReadErrorStatus(void *ControllerBaseAddress,
 			  unsigned char *ErrorStatus,
 			  unsigned char *Parameter0,
 			  unsigned char *Parameter1)
 {
-  DAC960_V5_ErrorStatusRegister_T ErrorStatusRegister;
+  DAC960_LA_ErrorStatusRegister_T ErrorStatusRegister;
   ErrorStatusRegister.All =
-    readb(ControllerBaseAddress + DAC960_V5_ErrorStatusRegisterOffset);
+    readb(ControllerBaseAddress + DAC960_LA_ErrorStatusRegisterOffset);
   if (!ErrorStatusRegister.Bits.ErrorStatusPending) return false;
   ErrorStatusRegister.Bits.ErrorStatusPending = false;
   *ErrorStatus = ErrorStatusRegister.All;
   *Parameter0 =
-    readb(ControllerBaseAddress + DAC960_V5_CommandOpcodeRegisterOffset);
+    readb(ControllerBaseAddress + DAC960_LA_CommandOpcodeRegisterOffset);
   *Parameter1 =
-    readb(ControllerBaseAddress + DAC960_V5_CommandIdentifierRegisterOffset);
-  writeb(0xFF, ControllerBaseAddress + DAC960_V5_ErrorStatusRegisterOffset);
+    readb(ControllerBaseAddress + DAC960_LA_CommandIdentifierRegisterOffset);
+  writeb(0xFF, ControllerBaseAddress + DAC960_LA_ErrorStatusRegisterOffset);
   return true;
 }
 
 static inline
-void DAC960_V5_SaveMemoryMailboxInfo(DAC960_Controller_T *Controller)
+void DAC960_LA_SaveMemoryMailboxInfo(DAC960_Controller_T *Controller)
 {
   void *ControllerBaseAddress = Controller->BaseAddress;
   writel(0x743C485E,
-	 ControllerBaseAddress + DAC960_V5_CommandOpcodeRegisterOffset);
-  writel((unsigned long) Controller->FirstCommandMailbox,
-	 ControllerBaseAddress + DAC960_V5_MailboxRegister4Offset);
-  writew(Controller->NextCommandMailbox - Controller->FirstCommandMailbox,
-	 ControllerBaseAddress + DAC960_V5_MailboxRegister8Offset);
-  writew(Controller->NextStatusMailbox - Controller->FirstStatusMailbox,
-	 ControllerBaseAddress + DAC960_V5_MailboxRegister10Offset);
+	 ControllerBaseAddress + DAC960_LA_CommandOpcodeRegisterOffset);
+  writel((unsigned long) Controller->V1.FirstCommandMailbox,
+	 ControllerBaseAddress + DAC960_LA_MailboxRegister4Offset);
+  writew(Controller->V1.NextCommandMailbox - Controller->V1.FirstCommandMailbox,
+	 ControllerBaseAddress + DAC960_LA_MailboxRegister8Offset);
+  writew(Controller->V1.NextStatusMailbox - Controller->V1.FirstStatusMailbox,
+	 ControllerBaseAddress + DAC960_LA_MailboxRegister10Offset);
 }
 
 static inline
-void DAC960_V5_RestoreMemoryMailboxInfo(DAC960_Controller_T *Controller,
+void DAC960_LA_RestoreMemoryMailboxInfo(DAC960_Controller_T *Controller,
 					void **MemoryMailboxAddress,
 					short *NextCommandMailboxIndex,
 					short *NextStatusMailboxIndex)
 {
   void *ControllerBaseAddress = Controller->BaseAddress;
   if (readl(ControllerBaseAddress
-	    + DAC960_V5_CommandOpcodeRegisterOffset) != 0x743C485E)
+	    + DAC960_LA_CommandOpcodeRegisterOffset) != 0x743C485E)
     return;
   *MemoryMailboxAddress =
-    (void *) readl(ControllerBaseAddress + DAC960_V5_MailboxRegister4Offset);
+    (void *) readl(ControllerBaseAddress + DAC960_LA_MailboxRegister4Offset);
   *NextCommandMailboxIndex =
-    readw(ControllerBaseAddress + DAC960_V5_MailboxRegister8Offset);
+    readw(ControllerBaseAddress + DAC960_LA_MailboxRegister8Offset);
   *NextStatusMailboxIndex =
-    readw(ControllerBaseAddress + DAC960_V5_MailboxRegister10Offset);
+    readw(ControllerBaseAddress + DAC960_LA_MailboxRegister10Offset);
 }
 
 
 /*
-  Define the DAC960 V4 Controller Interface Register Offsets.
+  Define the DAC960 PG Series Controller Interface Register Offsets.
 */
 
-#define DAC960_V4_RegisterWindowSize		0x2000
+#define DAC960_PG_RegisterWindowSize		0x2000
 
 typedef enum
 {
-  DAC960_V4_InboundDoorBellRegisterOffset =	0x0020,
-  DAC960_V4_OutboundDoorBellRegisterOffset =	0x002C,
-  DAC960_V4_InterruptMaskRegisterOffset =	0x0034,
-  DAC960_V4_CommandOpcodeRegisterOffset =	0x1000,
-  DAC960_V4_CommandIdentifierRegisterOffset =	0x1001,
-  DAC960_V4_MailboxRegister2Offset =		0x1002,
-  DAC960_V4_MailboxRegister3Offset =		0x1003,
-  DAC960_V4_MailboxRegister4Offset =		0x1004,
-  DAC960_V4_MailboxRegister5Offset =		0x1005,
-  DAC960_V4_MailboxRegister6Offset =		0x1006,
-  DAC960_V4_MailboxRegister7Offset =		0x1007,
-  DAC960_V4_MailboxRegister8Offset =		0x1008,
-  DAC960_V4_MailboxRegister9Offset =		0x1009,
-  DAC960_V4_MailboxRegister10Offset =		0x100A,
-  DAC960_V4_MailboxRegister11Offset =		0x100B,
-  DAC960_V4_MailboxRegister12Offset =		0x100C,
-  DAC960_V4_StatusCommandIdentifierRegOffset =	0x1018,
-  DAC960_V4_StatusRegisterOffset =		0x101A,
-  DAC960_V4_ErrorStatusRegisterOffset =		0x103F
+  DAC960_PG_InboundDoorBellRegisterOffset =	0x0020,
+  DAC960_PG_OutboundDoorBellRegisterOffset =	0x002C,
+  DAC960_PG_InterruptMaskRegisterOffset =	0x0034,
+  DAC960_PG_CommandOpcodeRegisterOffset =	0x1000,
+  DAC960_PG_CommandIdentifierRegisterOffset =	0x1001,
+  DAC960_PG_MailboxRegister2Offset =		0x1002,
+  DAC960_PG_MailboxRegister3Offset =		0x1003,
+  DAC960_PG_MailboxRegister4Offset =		0x1004,
+  DAC960_PG_MailboxRegister5Offset =		0x1005,
+  DAC960_PG_MailboxRegister6Offset =		0x1006,
+  DAC960_PG_MailboxRegister7Offset =		0x1007,
+  DAC960_PG_MailboxRegister8Offset =		0x1008,
+  DAC960_PG_MailboxRegister9Offset =		0x1009,
+  DAC960_PG_MailboxRegister10Offset =		0x100A,
+  DAC960_PG_MailboxRegister11Offset =		0x100B,
+  DAC960_PG_MailboxRegister12Offset =		0x100C,
+  DAC960_PG_StatusCommandIdentifierRegOffset =	0x1018,
+  DAC960_PG_StatusRegisterOffset =		0x101A,
+  DAC960_PG_ErrorStatusRegisterOffset =		0x103F
 }
-DAC960_V4_RegisterOffsets_T;
+DAC960_PG_RegisterOffsets_T;
 
 
 /*
-  Define the structure of the DAC960 V4 Inbound Door Bell Register.
+  Define the structure of the DAC960 PG Series Inbound Door Bell Register.
 */
 
-typedef union DAC960_V4_InboundDoorBellRegister
+typedef union DAC960_PG_InboundDoorBellRegister
 {
   unsigned int All;
   struct {
@@ -1777,14 +3532,14 @@
     unsigned int :30;					/* Bits 2-31 */
   } Read;
 }
-DAC960_V4_InboundDoorBellRegister_T;
+DAC960_PG_InboundDoorBellRegister_T;
 
 
 /*
-  Define the structure of the DAC960 V4 Outbound Door Bell Register.
+  Define the structure of the DAC960 PG Series Outbound Door Bell Register.
 */
 
-typedef union DAC960_V4_OutboundDoorBellRegister
+typedef union DAC960_PG_OutboundDoorBellRegister
 {
   unsigned int All;
   struct {
@@ -1798,14 +3553,14 @@
     unsigned int :30;					/* Bits 2-31 */
   } Read;
 }
-DAC960_V4_OutboundDoorBellRegister_T;
+DAC960_PG_OutboundDoorBellRegister_T;
 
 
 /*
-  Define the structure of the DAC960 V4 Interrupt Mask Register.
+  Define the structure of the DAC960 PG Series Interrupt Mask Register.
 */
 
-typedef union DAC960_V4_InterruptMaskRegister
+typedef union DAC960_PG_InterruptMaskRegister
 {
   unsigned int All;
   struct {
@@ -1815,14 +3570,14 @@
     unsigned int Reserved0:24;				/* Bits 8-31 */
   } Bits;
 }
-DAC960_V4_InterruptMaskRegister_T;
+DAC960_PG_InterruptMaskRegister_T;
 
 
 /*
-  Define the structure of the DAC960 V4 Error Status Register.
+  Define the structure of the DAC960 PG Series Error Status Register.
 */
 
-typedef union DAC960_V4_ErrorStatusRegister
+typedef union DAC960_PG_ErrorStatusRegister
 {
   unsigned char All;
   struct {
@@ -1831,292 +3586,294 @@
     unsigned int :5;					/* Bits 3-7 */
   } Bits;
 }
-DAC960_V4_ErrorStatusRegister_T;
+DAC960_PG_ErrorStatusRegister_T;
 
 
 /*
   Define inline functions to provide an abstraction for reading and writing the
-  DAC960 V4 Controller Interface Registers.
+  DAC960 PG Series Controller Interface Registers.
 */
 
 static inline
-void DAC960_V4_HardwareMailboxNewCommand(void *ControllerBaseAddress)
+void DAC960_PG_HardwareMailboxNewCommand(void *ControllerBaseAddress)
 {
-  DAC960_V4_InboundDoorBellRegister_T InboundDoorBellRegister;
+  DAC960_PG_InboundDoorBellRegister_T InboundDoorBellRegister;
   InboundDoorBellRegister.All = 0;
   InboundDoorBellRegister.Write.HardwareMailboxNewCommand = true;
   writel(InboundDoorBellRegister.All,
-	 ControllerBaseAddress + DAC960_V4_InboundDoorBellRegisterOffset);
+	 ControllerBaseAddress + DAC960_PG_InboundDoorBellRegisterOffset);
 }
 
 static inline
-void DAC960_V4_AcknowledgeHardwareMailboxStatus(void *ControllerBaseAddress)
+void DAC960_PG_AcknowledgeHardwareMailboxStatus(void *ControllerBaseAddress)
 {
-  DAC960_V4_InboundDoorBellRegister_T InboundDoorBellRegister;
+  DAC960_PG_InboundDoorBellRegister_T InboundDoorBellRegister;
   InboundDoorBellRegister.All = 0;
   InboundDoorBellRegister.Write.AcknowledgeHardwareMailboxStatus = true;
   writel(InboundDoorBellRegister.All,
-	 ControllerBaseAddress + DAC960_V4_InboundDoorBellRegisterOffset);
+	 ControllerBaseAddress + DAC960_PG_InboundDoorBellRegisterOffset);
 }
 
 static inline
-void DAC960_V4_GenerateInterrupt(void *ControllerBaseAddress)
+void DAC960_PG_GenerateInterrupt(void *ControllerBaseAddress)
 {
-  DAC960_V4_InboundDoorBellRegister_T InboundDoorBellRegister;
+  DAC960_PG_InboundDoorBellRegister_T InboundDoorBellRegister;
   InboundDoorBellRegister.All = 0;
   InboundDoorBellRegister.Write.GenerateInterrupt = true;
   writel(InboundDoorBellRegister.All,
-	 ControllerBaseAddress + DAC960_V4_InboundDoorBellRegisterOffset);
+	 ControllerBaseAddress + DAC960_PG_InboundDoorBellRegisterOffset);
 }
 
 static inline
-void DAC960_V4_ControllerReset(void *ControllerBaseAddress)
+void DAC960_PG_ControllerReset(void *ControllerBaseAddress)
 {
-  DAC960_V4_InboundDoorBellRegister_T InboundDoorBellRegister;
+  DAC960_PG_InboundDoorBellRegister_T InboundDoorBellRegister;
   InboundDoorBellRegister.All = 0;
   InboundDoorBellRegister.Write.ControllerReset = true;
   writel(InboundDoorBellRegister.All,
-	 ControllerBaseAddress + DAC960_V4_InboundDoorBellRegisterOffset);
+	 ControllerBaseAddress + DAC960_PG_InboundDoorBellRegisterOffset);
 }
 
 static inline
-void DAC960_V4_MemoryMailboxNewCommand(void *ControllerBaseAddress)
+void DAC960_PG_MemoryMailboxNewCommand(void *ControllerBaseAddress)
 {
-  DAC960_V4_InboundDoorBellRegister_T InboundDoorBellRegister;
+  DAC960_PG_InboundDoorBellRegister_T InboundDoorBellRegister;
   InboundDoorBellRegister.All = 0;
   InboundDoorBellRegister.Write.MemoryMailboxNewCommand = true;
   writel(InboundDoorBellRegister.All,
-	 ControllerBaseAddress + DAC960_V4_InboundDoorBellRegisterOffset);
+	 ControllerBaseAddress + DAC960_PG_InboundDoorBellRegisterOffset);
 }
 
 static inline
-boolean DAC960_V4_HardwareMailboxFullP(void *ControllerBaseAddress)
+boolean DAC960_PG_HardwareMailboxFullP(void *ControllerBaseAddress)
 {
-  DAC960_V4_InboundDoorBellRegister_T InboundDoorBellRegister;
+  DAC960_PG_InboundDoorBellRegister_T InboundDoorBellRegister;
   InboundDoorBellRegister.All =
-    readl(ControllerBaseAddress + DAC960_V4_InboundDoorBellRegisterOffset);
+    readl(ControllerBaseAddress + DAC960_PG_InboundDoorBellRegisterOffset);
   return InboundDoorBellRegister.Read.HardwareMailboxFull;
 }
 
 static inline
-boolean DAC960_V4_InitializationInProgressP(void *ControllerBaseAddress)
+boolean DAC960_PG_InitializationInProgressP(void *ControllerBaseAddress)
 {
-  DAC960_V4_InboundDoorBellRegister_T InboundDoorBellRegister;
+  DAC960_PG_InboundDoorBellRegister_T InboundDoorBellRegister;
   InboundDoorBellRegister.All =
-    readl(ControllerBaseAddress + DAC960_V4_InboundDoorBellRegisterOffset);
+    readl(ControllerBaseAddress + DAC960_PG_InboundDoorBellRegisterOffset);
   return InboundDoorBellRegister.Read.InitializationInProgress;
 }
 
 static inline
-void DAC960_V4_AcknowledgeHardwareMailboxInterrupt(void *ControllerBaseAddress)
+void DAC960_PG_AcknowledgeHardwareMailboxInterrupt(void *ControllerBaseAddress)
 {
-  DAC960_V4_OutboundDoorBellRegister_T OutboundDoorBellRegister;
+  DAC960_PG_OutboundDoorBellRegister_T OutboundDoorBellRegister;
   OutboundDoorBellRegister.All = 0;
   OutboundDoorBellRegister.Write.AcknowledgeHardwareMailboxInterrupt = true;
   writel(OutboundDoorBellRegister.All,
-	 ControllerBaseAddress + DAC960_V4_OutboundDoorBellRegisterOffset);
+	 ControllerBaseAddress + DAC960_PG_OutboundDoorBellRegisterOffset);
 }
 
 static inline
-void DAC960_V4_AcknowledgeMemoryMailboxInterrupt(void *ControllerBaseAddress)
+void DAC960_PG_AcknowledgeMemoryMailboxInterrupt(void *ControllerBaseAddress)
 {
-  DAC960_V4_OutboundDoorBellRegister_T OutboundDoorBellRegister;
+  DAC960_PG_OutboundDoorBellRegister_T OutboundDoorBellRegister;
   OutboundDoorBellRegister.All = 0;
   OutboundDoorBellRegister.Write.AcknowledgeMemoryMailboxInterrupt = true;
   writel(OutboundDoorBellRegister.All,
-	 ControllerBaseAddress + DAC960_V4_OutboundDoorBellRegisterOffset);
+	 ControllerBaseAddress + DAC960_PG_OutboundDoorBellRegisterOffset);
 }
 
 static inline
-void DAC960_V4_AcknowledgeInterrupt(void *ControllerBaseAddress)
+void DAC960_PG_AcknowledgeInterrupt(void *ControllerBaseAddress)
 {
-  DAC960_V4_OutboundDoorBellRegister_T OutboundDoorBellRegister;
+  DAC960_PG_OutboundDoorBellRegister_T OutboundDoorBellRegister;
   OutboundDoorBellRegister.All = 0;
   OutboundDoorBellRegister.Write.AcknowledgeHardwareMailboxInterrupt = true;
   OutboundDoorBellRegister.Write.AcknowledgeMemoryMailboxInterrupt = true;
   writel(OutboundDoorBellRegister.All,
-	 ControllerBaseAddress + DAC960_V4_OutboundDoorBellRegisterOffset);
+	 ControllerBaseAddress + DAC960_PG_OutboundDoorBellRegisterOffset);
 }
 
 static inline
-boolean DAC960_V4_HardwareMailboxStatusAvailableP(void *ControllerBaseAddress)
+boolean DAC960_PG_HardwareMailboxStatusAvailableP(void *ControllerBaseAddress)
 {
-  DAC960_V4_OutboundDoorBellRegister_T OutboundDoorBellRegister;
+  DAC960_PG_OutboundDoorBellRegister_T OutboundDoorBellRegister;
   OutboundDoorBellRegister.All =
-    readl(ControllerBaseAddress + DAC960_V4_OutboundDoorBellRegisterOffset);
+    readl(ControllerBaseAddress + DAC960_PG_OutboundDoorBellRegisterOffset);
   return OutboundDoorBellRegister.Read.HardwareMailboxStatusAvailable;
 }
 
 static inline
-boolean DAC960_V4_MemoryMailboxStatusAvailableP(void *ControllerBaseAddress)
+boolean DAC960_PG_MemoryMailboxStatusAvailableP(void *ControllerBaseAddress)
 {
-  DAC960_V4_OutboundDoorBellRegister_T OutboundDoorBellRegister;
+  DAC960_PG_OutboundDoorBellRegister_T OutboundDoorBellRegister;
   OutboundDoorBellRegister.All =
-    readl(ControllerBaseAddress + DAC960_V4_OutboundDoorBellRegisterOffset);
+    readl(ControllerBaseAddress + DAC960_PG_OutboundDoorBellRegisterOffset);
   return OutboundDoorBellRegister.Read.MemoryMailboxStatusAvailable;
 }
 
 static inline
-void DAC960_V4_EnableInterrupts(void *ControllerBaseAddress)
+void DAC960_PG_EnableInterrupts(void *ControllerBaseAddress)
 {
-  DAC960_V4_InterruptMaskRegister_T InterruptMaskRegister;
+  DAC960_PG_InterruptMaskRegister_T InterruptMaskRegister;
   InterruptMaskRegister.All = 0;
   InterruptMaskRegister.Bits.MessageUnitInterruptMask1 = 0x3;
   InterruptMaskRegister.Bits.DisableInterrupts = false;
   InterruptMaskRegister.Bits.MessageUnitInterruptMask2 = 0x1F;
   writel(InterruptMaskRegister.All,
-	 ControllerBaseAddress + DAC960_V4_InterruptMaskRegisterOffset);
+	 ControllerBaseAddress + DAC960_PG_InterruptMaskRegisterOffset);
 }
 
 static inline
-void DAC960_V4_DisableInterrupts(void *ControllerBaseAddress)
+void DAC960_PG_DisableInterrupts(void *ControllerBaseAddress)
 {
-  DAC960_V4_InterruptMaskRegister_T InterruptMaskRegister;
+  DAC960_PG_InterruptMaskRegister_T InterruptMaskRegister;
   InterruptMaskRegister.All = 0;
   InterruptMaskRegister.Bits.MessageUnitInterruptMask1 = 0x3;
   InterruptMaskRegister.Bits.DisableInterrupts = true;
   InterruptMaskRegister.Bits.MessageUnitInterruptMask2 = 0x1F;
   writel(InterruptMaskRegister.All,
-	 ControllerBaseAddress + DAC960_V4_InterruptMaskRegisterOffset);
+	 ControllerBaseAddress + DAC960_PG_InterruptMaskRegisterOffset);
 }
 
 static inline
-boolean DAC960_V4_InterruptsEnabledP(void *ControllerBaseAddress)
+boolean DAC960_PG_InterruptsEnabledP(void *ControllerBaseAddress)
 {
-  DAC960_V4_InterruptMaskRegister_T InterruptMaskRegister;
+  DAC960_PG_InterruptMaskRegister_T InterruptMaskRegister;
   InterruptMaskRegister.All =
-    readl(ControllerBaseAddress + DAC960_V4_InterruptMaskRegisterOffset);
+    readl(ControllerBaseAddress + DAC960_PG_InterruptMaskRegisterOffset);
   return !InterruptMaskRegister.Bits.DisableInterrupts;
 }
 
 static inline
-void DAC960_V4_WriteCommandMailbox(DAC960_CommandMailbox_T *NextCommandMailbox,
-				   DAC960_CommandMailbox_T *CommandMailbox)
-{
-  NextCommandMailbox->Words[1] = CommandMailbox->Words[1];
-  NextCommandMailbox->Words[2] = CommandMailbox->Words[2];
-  NextCommandMailbox->Words[3] = CommandMailbox->Words[3];
+void DAC960_PG_WriteCommandMailbox(DAC960_V1_CommandMailbox_T
+				     *MemoryCommandMailbox,
+				   DAC960_V1_CommandMailbox_T
+				     *CommandMailbox)
+{
+  MemoryCommandMailbox->Words[1] = CommandMailbox->Words[1];
+  MemoryCommandMailbox->Words[2] = CommandMailbox->Words[2];
+  MemoryCommandMailbox->Words[3] = CommandMailbox->Words[3];
   wmb();
-  NextCommandMailbox->Words[0] = CommandMailbox->Words[0];
+  MemoryCommandMailbox->Words[0] = CommandMailbox->Words[0];
   mb();
 }
 
 static inline
-void DAC960_V4_WriteHardwareMailbox(void *ControllerBaseAddress,
-				    DAC960_CommandMailbox_T *CommandMailbox)
+void DAC960_PG_WriteHardwareMailbox(void *ControllerBaseAddress,
+				    DAC960_V1_CommandMailbox_T *CommandMailbox)
 {
   writel(CommandMailbox->Words[0],
-	 ControllerBaseAddress + DAC960_V4_CommandOpcodeRegisterOffset);
+	 ControllerBaseAddress + DAC960_PG_CommandOpcodeRegisterOffset);
   writel(CommandMailbox->Words[1],
-	 ControllerBaseAddress + DAC960_V4_MailboxRegister4Offset);
+	 ControllerBaseAddress + DAC960_PG_MailboxRegister4Offset);
   writel(CommandMailbox->Words[2],
-	 ControllerBaseAddress + DAC960_V4_MailboxRegister8Offset);
+	 ControllerBaseAddress + DAC960_PG_MailboxRegister8Offset);
   writeb(CommandMailbox->Bytes[12],
-	 ControllerBaseAddress + DAC960_V4_MailboxRegister12Offset);
+	 ControllerBaseAddress + DAC960_PG_MailboxRegister12Offset);
 }
 
-static inline DAC960_CommandIdentifier_T
-DAC960_V4_ReadStatusCommandIdentifier(void *ControllerBaseAddress)
+static inline DAC960_V1_CommandIdentifier_T
+DAC960_PG_ReadStatusCommandIdentifier(void *ControllerBaseAddress)
 {
   return readb(ControllerBaseAddress
-	       + DAC960_V4_StatusCommandIdentifierRegOffset);
+	       + DAC960_PG_StatusCommandIdentifierRegOffset);
 }
 
-static inline DAC960_CommandStatus_T
-DAC960_V4_ReadStatusRegister(void *ControllerBaseAddress)
+static inline DAC960_V1_CommandStatus_T
+DAC960_PG_ReadStatusRegister(void *ControllerBaseAddress)
 {
-  return readw(ControllerBaseAddress + DAC960_V4_StatusRegisterOffset);
+  return readw(ControllerBaseAddress + DAC960_PG_StatusRegisterOffset);
 }
 
 static inline boolean
-DAC960_V4_ReadErrorStatus(void *ControllerBaseAddress,
+DAC960_PG_ReadErrorStatus(void *ControllerBaseAddress,
 			  unsigned char *ErrorStatus,
 			  unsigned char *Parameter0,
 			  unsigned char *Parameter1)
 {
-  DAC960_V4_ErrorStatusRegister_T ErrorStatusRegister;
+  DAC960_PG_ErrorStatusRegister_T ErrorStatusRegister;
   ErrorStatusRegister.All =
-    readb(ControllerBaseAddress + DAC960_V4_ErrorStatusRegisterOffset);
+    readb(ControllerBaseAddress + DAC960_PG_ErrorStatusRegisterOffset);
   if (!ErrorStatusRegister.Bits.ErrorStatusPending) return false;
   ErrorStatusRegister.Bits.ErrorStatusPending = false;
   *ErrorStatus = ErrorStatusRegister.All;
   *Parameter0 =
-    readb(ControllerBaseAddress + DAC960_V4_CommandOpcodeRegisterOffset);
+    readb(ControllerBaseAddress + DAC960_PG_CommandOpcodeRegisterOffset);
   *Parameter1 =
-    readb(ControllerBaseAddress + DAC960_V4_CommandIdentifierRegisterOffset);
-  writeb(0, ControllerBaseAddress + DAC960_V4_ErrorStatusRegisterOffset);
+    readb(ControllerBaseAddress + DAC960_PG_CommandIdentifierRegisterOffset);
+  writeb(0, ControllerBaseAddress + DAC960_PG_ErrorStatusRegisterOffset);
   return true;
 }
 
 static inline
-void DAC960_V4_SaveMemoryMailboxInfo(DAC960_Controller_T *Controller)
+void DAC960_PG_SaveMemoryMailboxInfo(DAC960_Controller_T *Controller)
 {
   void *ControllerBaseAddress = Controller->BaseAddress;
   writel(0x743C485E,
-	 ControllerBaseAddress + DAC960_V4_CommandOpcodeRegisterOffset);
-  writel((unsigned long) Controller->FirstCommandMailbox,
-	 ControllerBaseAddress + DAC960_V4_MailboxRegister4Offset);
-  writew(Controller->NextCommandMailbox - Controller->FirstCommandMailbox,
-	 ControllerBaseAddress + DAC960_V4_MailboxRegister8Offset);
-  writew(Controller->NextStatusMailbox - Controller->FirstStatusMailbox,
-	 ControllerBaseAddress + DAC960_V4_MailboxRegister10Offset);
+	 ControllerBaseAddress + DAC960_PG_CommandOpcodeRegisterOffset);
+  writel((unsigned long) Controller->V1.FirstCommandMailbox,
+	 ControllerBaseAddress + DAC960_PG_MailboxRegister4Offset);
+  writew(Controller->V1.NextCommandMailbox - Controller->V1.FirstCommandMailbox,
+	 ControllerBaseAddress + DAC960_PG_MailboxRegister8Offset);
+  writew(Controller->V1.NextStatusMailbox - Controller->V1.FirstStatusMailbox,
+	 ControllerBaseAddress + DAC960_PG_MailboxRegister10Offset);
 }
 
 static inline
-void DAC960_V4_RestoreMemoryMailboxInfo(DAC960_Controller_T *Controller,
+void DAC960_PG_RestoreMemoryMailboxInfo(DAC960_Controller_T *Controller,
 					void **MemoryMailboxAddress,
 					short *NextCommandMailboxIndex,
 					short *NextStatusMailboxIndex)
 {
   void *ControllerBaseAddress = Controller->BaseAddress;
   if (readl(ControllerBaseAddress
-	    + DAC960_V4_CommandOpcodeRegisterOffset) != 0x743C485E)
+	    + DAC960_PG_CommandOpcodeRegisterOffset) != 0x743C485E)
     return;
   *MemoryMailboxAddress =
-    (void *) readl(ControllerBaseAddress + DAC960_V4_MailboxRegister4Offset);
+    (void *) readl(ControllerBaseAddress + DAC960_PG_MailboxRegister4Offset);
   *NextCommandMailboxIndex =
-    readw(ControllerBaseAddress + DAC960_V4_MailboxRegister8Offset);
+    readw(ControllerBaseAddress + DAC960_PG_MailboxRegister8Offset);
   *NextStatusMailboxIndex =
-    readw(ControllerBaseAddress + DAC960_V4_MailboxRegister10Offset);
+    readw(ControllerBaseAddress + DAC960_PG_MailboxRegister10Offset);
 }
 
 
 /*
-  Define the DAC960 V3 Controller Interface Register Offsets.
+  Define the DAC960 PD Series Controller Interface Register Offsets.
 */
 
-#define DAC960_V3_RegisterWindowSize		0x80
+#define DAC960_PD_RegisterWindowSize		0x80
 
 typedef enum
 {
-  DAC960_V3_CommandOpcodeRegisterOffset =	0x00,
-  DAC960_V3_CommandIdentifierRegisterOffset =	0x01,
-  DAC960_V3_MailboxRegister2Offset =		0x02,
-  DAC960_V3_MailboxRegister3Offset =		0x03,
-  DAC960_V3_MailboxRegister4Offset =		0x04,
-  DAC960_V3_MailboxRegister5Offset =		0x05,
-  DAC960_V3_MailboxRegister6Offset =		0x06,
-  DAC960_V3_MailboxRegister7Offset =		0x07,
-  DAC960_V3_MailboxRegister8Offset =		0x08,
-  DAC960_V3_MailboxRegister9Offset =		0x09,
-  DAC960_V3_MailboxRegister10Offset =		0x0A,
-  DAC960_V3_MailboxRegister11Offset =		0x0B,
-  DAC960_V3_MailboxRegister12Offset =		0x0C,
-  DAC960_V3_StatusCommandIdentifierRegOffset =	0x0D,
-  DAC960_V3_StatusRegisterOffset =		0x0E,
-  DAC960_V3_ErrorStatusRegisterOffset =		0x3F,
-  DAC960_V3_InboundDoorBellRegisterOffset =	0x40,
-  DAC960_V3_OutboundDoorBellRegisterOffset =	0x41,
-  DAC960_V3_InterruptEnableRegisterOffset =	0x43
+  DAC960_PD_CommandOpcodeRegisterOffset =	0x00,
+  DAC960_PD_CommandIdentifierRegisterOffset =	0x01,
+  DAC960_PD_MailboxRegister2Offset =		0x02,
+  DAC960_PD_MailboxRegister3Offset =		0x03,
+  DAC960_PD_MailboxRegister4Offset =		0x04,
+  DAC960_PD_MailboxRegister5Offset =		0x05,
+  DAC960_PD_MailboxRegister6Offset =		0x06,
+  DAC960_PD_MailboxRegister7Offset =		0x07,
+  DAC960_PD_MailboxRegister8Offset =		0x08,
+  DAC960_PD_MailboxRegister9Offset =		0x09,
+  DAC960_PD_MailboxRegister10Offset =		0x0A,
+  DAC960_PD_MailboxRegister11Offset =		0x0B,
+  DAC960_PD_MailboxRegister12Offset =		0x0C,
+  DAC960_PD_StatusCommandIdentifierRegOffset =	0x0D,
+  DAC960_PD_StatusRegisterOffset =		0x0E,
+  DAC960_PD_ErrorStatusRegisterOffset =		0x3F,
+  DAC960_PD_InboundDoorBellRegisterOffset =	0x40,
+  DAC960_PD_OutboundDoorBellRegisterOffset =	0x41,
+  DAC960_PD_InterruptEnableRegisterOffset =	0x43
 }
-DAC960_V3_RegisterOffsets_T;
+DAC960_PD_RegisterOffsets_T;
 
 
 /*
-  Define the structure of the DAC960 V3 Inbound Door Bell Register.
+  Define the structure of the DAC960 PD Series Inbound Door Bell Register.
 */
 
-typedef union DAC960_V3_InboundDoorBellRegister
+typedef union DAC960_PD_InboundDoorBellRegister
 {
   unsigned char All;
   struct {
@@ -2132,14 +3889,14 @@
     unsigned char :6;					/* Bits 2-7 */
   } Read;
 }
-DAC960_V3_InboundDoorBellRegister_T;
+DAC960_PD_InboundDoorBellRegister_T;
 
 
 /*
-  Define the structure of the DAC960 V3 Outbound Door Bell Register.
+  Define the structure of the DAC960 PD Series Outbound Door Bell Register.
 */
 
-typedef union DAC960_V3_OutboundDoorBellRegister
+typedef union DAC960_PD_OutboundDoorBellRegister
 {
   unsigned char All;
   struct {
@@ -2151,14 +3908,14 @@
     unsigned char :7;					/* Bits 1-7 */
   } Read;
 }
-DAC960_V3_OutboundDoorBellRegister_T;
+DAC960_PD_OutboundDoorBellRegister_T;
 
 
 /*
-  Define the structure of the DAC960 V3 Interrupt Enable Register.
+  Define the structure of the DAC960 PD Series Interrupt Enable Register.
 */
 
-typedef union DAC960_V3_InterruptEnableRegister
+typedef union DAC960_PD_InterruptEnableRegister
 {
   unsigned char All;
   struct {
@@ -2166,14 +3923,14 @@
     unsigned char :7;					/* Bits 1-7 */
   } Bits;
 }
-DAC960_V3_InterruptEnableRegister_T;
+DAC960_PD_InterruptEnableRegister_T;
 
 
 /*
-  Define the structure of the DAC960 V3 Error Status Register.
+  Define the structure of the DAC960 PD Series Error Status Register.
 */
 
-typedef union DAC960_V3_ErrorStatusRegister
+typedef union DAC960_PD_ErrorStatusRegister
 {
   unsigned char All;
   struct {
@@ -2182,187 +3939,176 @@
     unsigned int :5;					/* Bits 3-7 */
   } Bits;
 }
-DAC960_V3_ErrorStatusRegister_T;
+DAC960_PD_ErrorStatusRegister_T;
 
 
 /*
   Define inline functions to provide an abstraction for reading and writing the
-  DAC960 V3 Controller Interface Registers.
+  DAC960 PD Series Controller Interface Registers.
 */
 
 static inline
-void DAC960_V3_NewCommand(void *ControllerBaseAddress)
+void DAC960_PD_NewCommand(void *ControllerBaseAddress)
 {
-  DAC960_V3_InboundDoorBellRegister_T InboundDoorBellRegister;
+  DAC960_PD_InboundDoorBellRegister_T InboundDoorBellRegister;
   InboundDoorBellRegister.All = 0;
   InboundDoorBellRegister.Write.NewCommand = true;
   writeb(InboundDoorBellRegister.All,
-	 ControllerBaseAddress + DAC960_V3_InboundDoorBellRegisterOffset);
+	 ControllerBaseAddress + DAC960_PD_InboundDoorBellRegisterOffset);
 }
 
 static inline
-void DAC960_V3_AcknowledgeStatus(void *ControllerBaseAddress)
+void DAC960_PD_AcknowledgeStatus(void *ControllerBaseAddress)
 {
-  DAC960_V3_InboundDoorBellRegister_T InboundDoorBellRegister;
+  DAC960_PD_InboundDoorBellRegister_T InboundDoorBellRegister;
   InboundDoorBellRegister.All = 0;
   InboundDoorBellRegister.Write.AcknowledgeStatus = true;
   writeb(InboundDoorBellRegister.All,
-	 ControllerBaseAddress + DAC960_V3_InboundDoorBellRegisterOffset);
+	 ControllerBaseAddress + DAC960_PD_InboundDoorBellRegisterOffset);
 }
 
 static inline
-void DAC960_V3_GenerateInterrupt(void *ControllerBaseAddress)
+void DAC960_PD_GenerateInterrupt(void *ControllerBaseAddress)
 {
-  DAC960_V3_InboundDoorBellRegister_T InboundDoorBellRegister;
+  DAC960_PD_InboundDoorBellRegister_T InboundDoorBellRegister;
   InboundDoorBellRegister.All = 0;
   InboundDoorBellRegister.Write.GenerateInterrupt = true;
   writeb(InboundDoorBellRegister.All,
-	 ControllerBaseAddress + DAC960_V3_InboundDoorBellRegisterOffset);
+	 ControllerBaseAddress + DAC960_PD_InboundDoorBellRegisterOffset);
 }
 
 static inline
-void DAC960_V3_ControllerReset(void *ControllerBaseAddress)
+void DAC960_PD_ControllerReset(void *ControllerBaseAddress)
 {
-  DAC960_V3_InboundDoorBellRegister_T InboundDoorBellRegister;
+  DAC960_PD_InboundDoorBellRegister_T InboundDoorBellRegister;
   InboundDoorBellRegister.All = 0;
   InboundDoorBellRegister.Write.ControllerReset = true;
   writeb(InboundDoorBellRegister.All,
-	 ControllerBaseAddress + DAC960_V3_InboundDoorBellRegisterOffset);
+	 ControllerBaseAddress + DAC960_PD_InboundDoorBellRegisterOffset);
 }
 
 static inline
-boolean DAC960_V3_MailboxFullP(void *ControllerBaseAddress)
+boolean DAC960_PD_MailboxFullP(void *ControllerBaseAddress)
 {
-  DAC960_V3_InboundDoorBellRegister_T InboundDoorBellRegister;
+  DAC960_PD_InboundDoorBellRegister_T InboundDoorBellRegister;
   InboundDoorBellRegister.All =
-    readb(ControllerBaseAddress + DAC960_V3_InboundDoorBellRegisterOffset);
+    readb(ControllerBaseAddress + DAC960_PD_InboundDoorBellRegisterOffset);
   return InboundDoorBellRegister.Read.MailboxFull;
 }
 
 static inline
-boolean DAC960_V3_InitializationInProgressP(void *ControllerBaseAddress)
+boolean DAC960_PD_InitializationInProgressP(void *ControllerBaseAddress)
 {
-  DAC960_V3_InboundDoorBellRegister_T InboundDoorBellRegister;
+  DAC960_PD_InboundDoorBellRegister_T InboundDoorBellRegister;
   InboundDoorBellRegister.All =
-    readb(ControllerBaseAddress + DAC960_V3_InboundDoorBellRegisterOffset);
+    readb(ControllerBaseAddress + DAC960_PD_InboundDoorBellRegisterOffset);
   return InboundDoorBellRegister.Read.InitializationInProgress;
 }
 
 static inline
-void DAC960_V3_AcknowledgeInterrupt(void *ControllerBaseAddress)
+void DAC960_PD_AcknowledgeInterrupt(void *ControllerBaseAddress)
 {
-  DAC960_V3_OutboundDoorBellRegister_T OutboundDoorBellRegister;
+  DAC960_PD_OutboundDoorBellRegister_T OutboundDoorBellRegister;
   OutboundDoorBellRegister.All = 0;
   OutboundDoorBellRegister.Write.AcknowledgeInterrupt = true;
   writeb(OutboundDoorBellRegister.All,
-	 ControllerBaseAddress + DAC960_V3_OutboundDoorBellRegisterOffset);
+	 ControllerBaseAddress + DAC960_PD_OutboundDoorBellRegisterOffset);
 }
 
 static inline
-boolean DAC960_V3_StatusAvailableP(void *ControllerBaseAddress)
+boolean DAC960_PD_StatusAvailableP(void *ControllerBaseAddress)
 {
-  DAC960_V3_OutboundDoorBellRegister_T OutboundDoorBellRegister;
+  DAC960_PD_OutboundDoorBellRegister_T OutboundDoorBellRegister;
   OutboundDoorBellRegister.All =
-    readb(ControllerBaseAddress + DAC960_V3_OutboundDoorBellRegisterOffset);
+    readb(ControllerBaseAddress + DAC960_PD_OutboundDoorBellRegisterOffset);
   return OutboundDoorBellRegister.Read.StatusAvailable;
 }
 
 static inline
-void DAC960_V3_EnableInterrupts(void *ControllerBaseAddress)
+void DAC960_PD_EnableInterrupts(void *ControllerBaseAddress)
 {
-  DAC960_V3_InterruptEnableRegister_T InterruptEnableRegister;
+  DAC960_PD_InterruptEnableRegister_T InterruptEnableRegister;
   InterruptEnableRegister.All = 0;
   InterruptEnableRegister.Bits.EnableInterrupts = true;
   writeb(InterruptEnableRegister.All,
-	 ControllerBaseAddress + DAC960_V3_InterruptEnableRegisterOffset);
+	 ControllerBaseAddress + DAC960_PD_InterruptEnableRegisterOffset);
 }
 
 static inline
-void DAC960_V3_DisableInterrupts(void *ControllerBaseAddress)
+void DAC960_PD_DisableInterrupts(void *ControllerBaseAddress)
 {
-  DAC960_V3_InterruptEnableRegister_T InterruptEnableRegister;
+  DAC960_PD_InterruptEnableRegister_T InterruptEnableRegister;
   InterruptEnableRegister.All = 0;
   InterruptEnableRegister.Bits.EnableInterrupts = false;
   writeb(InterruptEnableRegister.All,
-	 ControllerBaseAddress + DAC960_V3_InterruptEnableRegisterOffset);
+	 ControllerBaseAddress + DAC960_PD_InterruptEnableRegisterOffset);
 }
 
 static inline
-boolean DAC960_V3_InterruptsEnabledP(void *ControllerBaseAddress)
+boolean DAC960_PD_InterruptsEnabledP(void *ControllerBaseAddress)
 {
-  DAC960_V3_InterruptEnableRegister_T InterruptEnableRegister;
+  DAC960_PD_InterruptEnableRegister_T InterruptEnableRegister;
   InterruptEnableRegister.All =
-    readb(ControllerBaseAddress + DAC960_V3_InterruptEnableRegisterOffset);
+    readb(ControllerBaseAddress + DAC960_PD_InterruptEnableRegisterOffset);
   return InterruptEnableRegister.Bits.EnableInterrupts;
 }
 
 static inline
-void DAC960_V3_WriteCommandMailbox(void *ControllerBaseAddress,
-				   DAC960_CommandMailbox_T *CommandMailbox)
+void DAC960_PD_WriteCommandMailbox(void *ControllerBaseAddress,
+				   DAC960_V1_CommandMailbox_T *CommandMailbox)
 {
   writel(CommandMailbox->Words[0],
-	 ControllerBaseAddress + DAC960_V3_CommandOpcodeRegisterOffset);
+	 ControllerBaseAddress + DAC960_PD_CommandOpcodeRegisterOffset);
   writel(CommandMailbox->Words[1],
-	 ControllerBaseAddress + DAC960_V3_MailboxRegister4Offset);
+	 ControllerBaseAddress + DAC960_PD_MailboxRegister4Offset);
   writel(CommandMailbox->Words[2],
-	 ControllerBaseAddress + DAC960_V3_MailboxRegister8Offset);
+	 ControllerBaseAddress + DAC960_PD_MailboxRegister8Offset);
   writeb(CommandMailbox->Bytes[12],
-	 ControllerBaseAddress + DAC960_V3_MailboxRegister12Offset);
+	 ControllerBaseAddress + DAC960_PD_MailboxRegister12Offset);
 }
 
-static inline DAC960_CommandIdentifier_T
-DAC960_V3_ReadStatusCommandIdentifier(void *ControllerBaseAddress)
+static inline DAC960_V1_CommandIdentifier_T
+DAC960_PD_ReadStatusCommandIdentifier(void *ControllerBaseAddress)
 {
   return readb(ControllerBaseAddress
-	       + DAC960_V3_StatusCommandIdentifierRegOffset);
+	       + DAC960_PD_StatusCommandIdentifierRegOffset);
 }
 
-static inline DAC960_CommandStatus_T
-DAC960_V3_ReadStatusRegister(void *ControllerBaseAddress)
+static inline DAC960_V1_CommandStatus_T
+DAC960_PD_ReadStatusRegister(void *ControllerBaseAddress)
 {
-  return readw(ControllerBaseAddress + DAC960_V3_StatusRegisterOffset);
+  return readw(ControllerBaseAddress + DAC960_PD_StatusRegisterOffset);
 }
 
 static inline boolean
-DAC960_V3_ReadErrorStatus(void *ControllerBaseAddress,
+DAC960_PD_ReadErrorStatus(void *ControllerBaseAddress,
 			  unsigned char *ErrorStatus,
 			  unsigned char *Parameter0,
 			  unsigned char *Parameter1)
 {
-  DAC960_V3_ErrorStatusRegister_T ErrorStatusRegister;
+  DAC960_PD_ErrorStatusRegister_T ErrorStatusRegister;
   ErrorStatusRegister.All =
-    readb(ControllerBaseAddress + DAC960_V3_ErrorStatusRegisterOffset);
+    readb(ControllerBaseAddress + DAC960_PD_ErrorStatusRegisterOffset);
   if (!ErrorStatusRegister.Bits.ErrorStatusPending) return false;
   ErrorStatusRegister.Bits.ErrorStatusPending = false;
   *ErrorStatus = ErrorStatusRegister.All;
   *Parameter0 =
-    readb(ControllerBaseAddress + DAC960_V3_CommandOpcodeRegisterOffset);
+    readb(ControllerBaseAddress + DAC960_PD_CommandOpcodeRegisterOffset);
   *Parameter1 =
-    readb(ControllerBaseAddress + DAC960_V3_CommandIdentifierRegisterOffset);
-  writeb(0, ControllerBaseAddress + DAC960_V3_ErrorStatusRegisterOffset);
+    readb(ControllerBaseAddress + DAC960_PD_CommandIdentifierRegisterOffset);
+  writeb(0, ControllerBaseAddress + DAC960_PD_ErrorStatusRegisterOffset);
   return true;
 }
 
 
 /*
-  Define compatibility macros between Linux 2.0 and Linux 2.1.
-*/
-
-#if LINUX_VERSION_CODE < 0x20100
-
-#define MODULE_PARM(Variable, Type)
-#define ioremap_nocache(Offset, Size)	vremap(Offset, Size)
-#define iounmap(Address)		vfree(Address)
-
-#endif
-
-
-/*
   Define prototypes for the forward referenced DAC960 Driver Internal Functions.
 */
 
 static void DAC960_FinalizeController(DAC960_Controller_T *);
 static int DAC960_Finalize(NotifierBlock_T *, unsigned long, void *);
+static void DAC960_V1_QueueReadWriteCommand(DAC960_Command_T *);
+static void DAC960_V2_QueueReadWriteCommand(DAC960_Command_T *);
 static void DAC960_RequestFunction0(void);
 static void DAC960_RequestFunction1(void);
 static void DAC960_RequestFunction2(void);
@@ -2371,15 +4117,20 @@
 static void DAC960_RequestFunction5(void);
 static void DAC960_RequestFunction6(void);
 static void DAC960_RequestFunction7(void);
-static void DAC960_InterruptHandler(int, void *, Registers_T *);
-static void DAC960_QueueMonitoringCommand(DAC960_Command_T *);
+static void DAC960_BA_InterruptHandler(int, void *, Registers_T *);
+static void DAC960_LP_InterruptHandler(int, void *, Registers_T *);
+static void DAC960_LA_InterruptHandler(int, void *, Registers_T *);
+static void DAC960_PG_InterruptHandler(int, void *, Registers_T *);
+static void DAC960_PD_InterruptHandler(int, void *, Registers_T *);
+static void DAC960_V1_QueueMonitoringCommand(DAC960_Command_T *);
+static void DAC960_V2_QueueMonitoringCommand(DAC960_Command_T *);
 static void DAC960_MonitoringTimerFunction(unsigned long);
 static int DAC960_Open(Inode_T *, File_T *);
 static int DAC960_Release(Inode_T *, File_T *);
 static int DAC960_IOCTL(Inode_T *, File_T *, unsigned int, unsigned long);
 static int DAC960_UserIOCTL(Inode_T *, File_T *, unsigned int, unsigned long);
 static void DAC960_InitializeGenericDiskInfo(GenericDiskInfo_T *);
-static void DAC960_Message(DAC960_MessageLevel_T, char *,
+static void DAC960_Message(DAC960_MessageLevel_T, unsigned char *,
 			   DAC960_Controller_T *, ...);
 static void DAC960_CreateProcEntries(void);
 static void DAC960_DestroyProcEntries(void);
Index: oldkernel/linux/drivers/block/Makefile
diff -u linux/drivers/block/Makefile:1.2 linux/drivers/block/Makefile:1.3
--- linux/drivers/block/Makefile:1.2	Thu Jun  1 14:51:28 2000
+++ linux/drivers/block/Makefile	Fri Jul  7 15:36:42 2000
@@ -322,6 +322,14 @@
   endif
 endif
 
+ifeq ($(CONFIG_BLK_DEV_3WARE), y)
+  LX_OBJS += 3w-xxxx.o
+else
+  ifeq ($(CONFIG_BLK_DEV_3WARE), m)
+    MX_OBJS += 3w-xxxx.o
+  endif
+endif
+
 include $(TOPDIR)/Rules.make
 
 ide-mod.o: ide.o $(IDE_OBJS)
Index: oldkernel/linux/drivers/block/ide.c
diff -u linux/drivers/block/ide.c:1.1.1.1 linux/drivers/block/ide.c:1.2
--- linux/drivers/block/ide.c:1.1.1.1	Wed May 31 12:33:50 2000
+++ linux/drivers/block/ide.c	Fri Jul  7 15:36:42 2000
@@ -2285,6 +2285,10 @@
 			drive->nice1 = (arg >> IDE_NICE_1) & 1;
 			return 0;
 
+		case BLKELVGET:
+		case BLKELVSET:
+ 			return blkelv_ioctl(inode->i_rdev, cmd, arg);
+
 		RO_IOCTLS(inode->i_rdev, arg);
 
 		default:
Index: oldkernel/linux/drivers/block/ll_rw_blk.c
diff -u linux/drivers/block/ll_rw_blk.c:1.3 linux/drivers/block/ll_rw_blk.c:1.4
--- linux/drivers/block/ll_rw_blk.c:1.3	Thu Jun  1 17:02:44 2000
+++ linux/drivers/block/ll_rw_blk.c	Fri Jul  7 15:36:42 2000
@@ -3,6 +3,7 @@
  *
  * Copyright (C) 1991, 1992 Linus Torvalds
  * Copyright (C) 1994,      Karl Keyte: Added support for disk statistics
+ * Elevator latency, (C) 2000  Andrea Arcangeli <andrea@suse.de> SuSE
  */
 
 /*
@@ -20,6 +21,7 @@
 
 #include <asm/system.h>
 #include <asm/io.h>
+#include <asm/uaccess.h>
 #include <linux/blk.h>
 #include <linux/raid/md.h>
 
@@ -148,6 +150,17 @@
 	return &blk_dev[major].current_request;
 }
 
+static inline int get_request_latency(elevator_t * elevator, int rw)
+{
+	int latency;
+
+	latency = elevator->read_latency;
+	if (rw != READ)
+		latency = elevator->write_latency;
+
+	return latency;
+}
+
 /*
  * remove the plug and let it rip..
  */
@@ -328,6 +341,196 @@
 	}
 }
 
+static int blkelvget_ioctl(elevator_t * elevator, blkelv_ioctl_arg_t * arg)
+{
+	int ret;
+	blkelv_ioctl_arg_t output;
+
+	output.queue_ID			= elevator;
+	output.read_latency		= elevator->read_latency;
+	output.write_latency		= elevator->write_latency;
+	output.max_bomb_segments	= elevator->max_bomb_segments;
+
+	ret = -EFAULT;
+	if (copy_to_user(arg, &output, sizeof(blkelv_ioctl_arg_t)))
+		goto out;
+	ret = 0;
+ out:
+	return ret;
+}
+
+static int blkelvset_ioctl(elevator_t * elevator, const blkelv_ioctl_arg_t * arg)
+{
+	blkelv_ioctl_arg_t input;
+	int ret;
+
+	ret = -EFAULT;
+	if (copy_from_user(&input, arg, sizeof(blkelv_ioctl_arg_t)))
+		goto out;
+
+	ret = -EINVAL;
+	if (input.read_latency < 0)
+		goto out;
+	if (input.write_latency < 0)
+		goto out;
+	if (input.max_bomb_segments <= 0)
+		goto out;
+
+	elevator->read_latency		= input.read_latency;
+	elevator->write_latency		= input.write_latency;
+	elevator->max_bomb_segments	= input.max_bomb_segments;
+
+	ret = 0;
+ out:
+	return ret;
+}
+
+int blkelv_ioctl(kdev_t dev, unsigned long cmd, unsigned long arg)
+{
+	elevator_t * elevator = &blk_dev[MAJOR(dev)].elevator;
+	blkelv_ioctl_arg_t * __arg = (blkelv_ioctl_arg_t *) arg;
+
+	switch (cmd) {
+	case BLKELVGET:
+		return blkelvget_ioctl(elevator, __arg);
+	case BLKELVSET:
+		return blkelvset_ioctl(elevator, __arg);
+	}
+}
+
+static inline int seek_to_not_starving_chunk(struct request ** req, int * lat)
+{
+	struct request * tmp = *req;
+	int found = 0, pos = 0;
+	int last_pos = 0, __lat = *lat;
+
+	do {
+		if (tmp->elevator_latency <= 0)
+		{
+			*req = tmp;
+			found = 1;
+			last_pos = pos;
+			if (last_pos >= __lat)
+				break;
+		}
+		pos += tmp->nr_segments;
+	} while ((tmp = tmp->next));
+	*lat -= last_pos;
+
+	return found;
+}
+
+#define CASE_COALESCE_BUT_FIRST_REQUEST_MAYBE_BUSY	\
+	     case IDE0_MAJOR:	/* same as HD_MAJOR */	\
+	     case IDE1_MAJOR:				\
+	     case FLOPPY_MAJOR:				\
+	     case IDE2_MAJOR:				\
+	     case IDE3_MAJOR:				\
+	     case IDE4_MAJOR:				\
+	     case IDE5_MAJOR:				\
+	     case ACSI_MAJOR:				\
+	     case MFM_ACORN_MAJOR:			\
+             case MDISK_MAJOR:				\
+             case DASD_MAJOR:
+#define CASE_COALESCE_ALSO_FIRST_REQUEST	\
+	     case SCSI_DISK0_MAJOR:		\
+	     case SCSI_DISK1_MAJOR:		\
+	     case SCSI_DISK2_MAJOR:		\
+	     case SCSI_DISK3_MAJOR:		\
+	     case SCSI_DISK4_MAJOR:		\
+	     case SCSI_DISK5_MAJOR:		\
+	     case SCSI_DISK6_MAJOR:		\
+	     case SCSI_DISK7_MAJOR:		\
+	     case SCSI_CDROM_MAJOR:		\
+	     case DAC960_MAJOR+0:		\
+	     case DAC960_MAJOR+1:		\
+	     case DAC960_MAJOR+2:		\
+	     case DAC960_MAJOR+3:		\
+	     case DAC960_MAJOR+4:		\
+	     case DAC960_MAJOR+5:		\
+	     case DAC960_MAJOR+6:		\
+	     case DAC960_MAJOR+7:		\
+	     case COMPAQ_SMART2_MAJOR+0:	\
+	     case COMPAQ_SMART2_MAJOR+1:	\
+	     case COMPAQ_SMART2_MAJOR+2:	\
+	     case COMPAQ_SMART2_MAJOR+3:	\
+	     case COMPAQ_SMART2_MAJOR+4:	\
+	     case COMPAQ_SMART2_MAJOR+5:	\
+	     case COMPAQ_SMART2_MAJOR+6:	\
+	     case COMPAQ_SMART2_MAJOR+7:
+
+#define elevator_starve_rest_of_queue(req)			\
+do {								\
+	struct request * tmp = (req);				\
+	for ((tmp) = (tmp)->next; (tmp); (tmp) = (tmp)->next)	\
+		(tmp)->elevator_latency--;			\
+} while (0)
+
+static inline void elevator_queue(struct request * req,
+				  struct request * tmp,
+				  int latency,
+				  struct blk_dev_struct * dev,
+				  struct request ** queue_head)
+{
+	struct request * __tmp;
+	int starving, __latency;
+
+	starving = seek_to_not_starving_chunk(&tmp, &latency);
+	__tmp = tmp;
+	__latency = latency;
+
+	for (;; tmp = tmp->next)
+	{
+		if ((latency -= tmp->nr_segments) <= 0)
+		{
+			tmp = __tmp;
+			latency = __latency - tmp->nr_segments;
+
+			if (starving)
+				break;
+
+			switch (MAJOR(req->rq_dev))
+			{
+			CASE_COALESCE_BUT_FIRST_REQUEST_MAYBE_BUSY
+				if (tmp == dev->current_request)
+			default:
+					goto link;
+			CASE_COALESCE_ALSO_FIRST_REQUEST
+			}
+
+			latency += tmp->nr_segments;
+			req->next = tmp;
+			*queue_head = req;
+			goto after_link;
+		}
+
+		if (!tmp->next)
+			break;
+
+		{
+			const int after_current = IN_ORDER(tmp,req);
+			const int before_next = IN_ORDER(req,tmp->next);
+
+			if (!IN_ORDER(tmp,tmp->next)) {
+				if (after_current || before_next)
+					break;
+			} else {
+				if (after_current && before_next)
+					break;
+			}
+		}
+	}
+
+ link:
+	req->next = tmp->next;
+	tmp->next = req;
+
+ after_link:
+	req->elevator_latency = latency;
+
+	elevator_starve_rest_of_queue(req);
+}
+
 /*
  * add-request adds a request to the linked list.
  * It disables interrupts (aquires the request spinlock) so that it can muck
@@ -346,6 +549,7 @@
 	short		 disk_index;
 	unsigned long flags;
 	int queue_new_request = 0;
+	int latency;
 
 	switch (major) {
 		case DAC960_MAJOR+0:
@@ -370,7 +574,7 @@
 			break;
 	}
 
-	req->next = NULL;
+	latency = get_request_latency(&dev->elevator, req->cmd);
 
 	/*
 	 * We use the goto to reduce locking complexity
@@ -381,28 +585,17 @@
 	if (req->bh)
 		mark_buffer_clean(req->bh);
 	if (!(tmp = *current_request)) {
+		req->next = NULL;
+		req->elevator_latency = latency;
 		*current_request = req;
 		if (dev->current_request != &dev->plug)
 			queue_new_request = 1;
 		goto out;
-	}
-	for ( ; tmp->next ; tmp = tmp->next) {
-		const int after_current = IN_ORDER(tmp,req);
-		const int before_next = IN_ORDER(req,tmp->next);
-
-		if (!IN_ORDER(tmp,tmp->next)) {
-			if (after_current || before_next)
-				break;
-		} else {
-			if (after_current && before_next)
-				break;
-		}
 	}
-	req->next = tmp->next;
-	tmp->next = req;
+	elevator_queue(req, tmp, latency, dev, current_request);
 
 /* for SCSI devices, call request_fn unconditionally */
-	if (scsi_blk_major(major) ||
+	if ((0 && scsi_blk_major(major)) ||
             (major >= DAC960_MAJOR+0 && major <= DAC960_MAJOR+7) ||
             (major >= COMPAQ_SMART2_MAJOR+0 &&
              major <= COMPAQ_SMART2_MAJOR+7))
@@ -436,6 +629,8 @@
 		total_segments--;
 	if (total_segments > max_segments)
 		return;
+	if (next->elevator_latency < req->elevator_latency)
+		req->elevator_latency = next->elevator_latency;
 	req->bhtail->b_reqnext = next->bh;
 	req->bhtail = next->bhtail;
 	req->nr_sectors += next->nr_sectors;
@@ -445,12 +640,28 @@
 	wake_up (&wait_for_request);
 }
 
+#define read_pendings(req)			\
+({						\
+	int __ret = 0;				\
+	struct request * tmp = (req);		\
+	do {					\
+		if (tmp->cmd == READ)		\
+		{				\
+			__ret = 1;		\
+			break;			\
+		}				\
+		tmp = tmp->next;		\
+	} while (tmp);				\
+	__ret;					\
+})
+
 void make_request(kdev_t dev, int rw, struct buffer_head * bh)
 {
 	unsigned int sector, count;
-	struct request * req;
+	struct request * req, * prev;
 	int rw_ahead, max_req, max_sectors, max_segments;
 	unsigned long flags;
+	int latency, starving;
 	int major, minor;
 
 	major = MAJOR (dev);
@@ -535,6 +746,8 @@
 	max_sectors = get_max_sectors(bh->b_rdev);
 	max_segments = get_max_segments(bh->b_rdev);
 
+	latency = get_request_latency(&blk_dev[major].elevator, rw);
+
 	/*
 	 * Now we acquire the request spinlock, we have to be mega careful
 	 * not to schedule or do something nonatomic
@@ -547,17 +760,7 @@
 		    major != DDV_MAJOR && major != NBD_MAJOR)
 			plug_device(blk_dev + major); /* is atomic */
 	} else switch (major) {
-	     case IDE0_MAJOR:	/* same as HD_MAJOR */
-	     case IDE1_MAJOR:
-	     case FLOPPY_MAJOR:
-	     case IDE2_MAJOR:
-	     case IDE3_MAJOR:
-	     case IDE4_MAJOR:
-	     case IDE5_MAJOR:
-	     case ACSI_MAJOR:
-	     case MFM_ACORN_MAJOR:
-             case MDISK_MAJOR:
-             case DASD_MAJOR:
+	     CASE_COALESCE_BUT_FIRST_REQUEST_MAYBE_BUSY
 		/*
 		 * The scsi disk and cdrom drivers completely remove the request
 		 * from the queue when they start processing an entry.  For this
@@ -568,37 +771,20 @@
 		 * entry may be busy being processed and we thus can't change it.
 		 */
 		if (req == blk_dev[major].current_request)
-	        	req = req->next;
-		if (!req)
-			break;
+		{
+	        	if (!(req = req->next))
+				break;
+			latency -= req->nr_segments;
+		}
 		/* fall through */
+	     CASE_COALESCE_ALSO_FIRST_REQUEST
 
-	     case SCSI_DISK0_MAJOR:
-	     case SCSI_DISK1_MAJOR:
-	     case SCSI_DISK2_MAJOR:
-	     case SCSI_DISK3_MAJOR:
-	     case SCSI_DISK4_MAJOR:
-	     case SCSI_DISK5_MAJOR:
-	     case SCSI_DISK6_MAJOR:
-	     case SCSI_DISK7_MAJOR:
-	     case SCSI_CDROM_MAJOR:
-	     case DAC960_MAJOR+0:
-	     case DAC960_MAJOR+1:
-	     case DAC960_MAJOR+2:
-	     case DAC960_MAJOR+3:
-	     case DAC960_MAJOR+4:
-	     case DAC960_MAJOR+5:
-	     case DAC960_MAJOR+6:
-	     case DAC960_MAJOR+7:
-	     case COMPAQ_SMART2_MAJOR+0:
-	     case COMPAQ_SMART2_MAJOR+1:
-	     case COMPAQ_SMART2_MAJOR+2:
-	     case COMPAQ_SMART2_MAJOR+3:
-	     case COMPAQ_SMART2_MAJOR+4:
-	     case COMPAQ_SMART2_MAJOR+5:
-	     case COMPAQ_SMART2_MAJOR+6:
-	     case COMPAQ_SMART2_MAJOR+7:
+		/* avoid write-bombs to not hurt iteractiveness of reads */
+		if (rw != READ && read_pendings(req))
+			max_segments = blk_dev[major].elevator.max_bomb_segments;
 
+		starving = seek_to_not_starving_chunk(&req, &latency);
+		prev = NULL;
 		do {
 			if (req->sem)
 				continue;
@@ -610,24 +796,34 @@
 				continue;
 			/* Can we add it to the end of this request? */
 			if (req->sector + req->nr_sectors == sector) {
+				if (latency - req->nr_segments < 0)
+					break;
 				if (req->bhtail->b_data + req->bhtail->b_size
 				    != bh->b_data) {
 					if (req->nr_segments < max_segments)
 						req->nr_segments++;
-					else continue;
+					else break;
 				}
 				req->bhtail->b_reqnext = bh;
 				req->bhtail = bh;
 			    	req->nr_sectors += count;
+
+				/* latency stuff */
+				if ((latency -= req->nr_segments) < req->elevator_latency)
+					req->elevator_latency = latency;
+				elevator_starve_rest_of_queue(req);
+
 				/* Can we now merge this req with the next? */
 				attempt_merge(req, max_sectors, max_segments);
 			/* or to the beginning? */
 			} else if (req->sector - count == sector) {
+				if (!prev && starving)
+					break;
 				if (bh->b_data + bh->b_size
 				    != req->bh->b_data) {
 					if (req->nr_segments < max_segments)
 						req->nr_segments++;
-					else continue;
+					else break;
 				}
 			    	bh->b_reqnext = req->bh;
 			    	req->bh = bh;
@@ -635,6 +831,14 @@
 			    	req->current_nr_sectors = count;
 			    	req->sector = sector;
 			    	req->nr_sectors += count;
+
+				/* latency stuff */
+				if (latency < --req->elevator_latency)
+					req->elevator_latency = latency;
+				elevator_starve_rest_of_queue(req);
+
+				if (prev)
+					attempt_merge(prev, max_sectors, max_segments);
 			} else
 				continue;
 
@@ -642,7 +846,8 @@
 			spin_unlock_irqrestore(&io_request_lock,flags);
 		    	return;
 
-		} while ((req = req->next) != NULL);
+		} while (prev = req,
+			 (latency -= req->nr_segments) >= 0 && (req = req->next) != NULL);
 	}
 
 /* find an unused request. */
@@ -668,7 +873,6 @@
 	req->sem = NULL;
 	req->bh = bh;
 	req->bhtail = bh;
-	req->next = NULL;
 	add_request(major+blk_dev,req);
 	return;
 
@@ -837,12 +1041,12 @@
 		dev->plug_tq.sync    = 0;
 		dev->plug_tq.routine = &unplug_device;
 		dev->plug_tq.data    = dev;
+		dev->elevator = ELEVATOR_DEFAULTS;
 	}
 
 	req = all_requests + NR_REQUEST;
 	while (--req >= all_requests) {
 		req->rq_status = RQ_INACTIVE;
-		req->next = NULL;
 	}
 	memset(ro_bits,0,sizeof(ro_bits));
 	memset(max_readahead, 0, sizeof(max_readahead));
Index: oldkernel/linux/drivers/block/loop.c
diff -u linux/drivers/block/loop.c:1.3 linux/drivers/block/loop.c:1.4
--- linux/drivers/block/loop.c:1.3	Thu Jun  1 15:46:10 2000
+++ linux/drivers/block/loop.c	Fri Jul  7 15:36:42 2000
@@ -143,12 +143,12 @@
 	int	size;
 
 	if (S_ISREG(lo->lo_dentry->d_inode->i_mode))
-		size = (lo->lo_dentry->d_inode->i_size - lo->lo_offset) >> BLOCK_SIZE_BITS;
+		size = (lo->lo_dentry->d_inode->i_size - lo->lo_offset) / BLOCK_SIZE;
 	else {
 		kdev_t lodev = lo->lo_device;
 		if (blk_size[MAJOR(lodev)])
 			size = blk_size[MAJOR(lodev)][MINOR(lodev)] -
-				 (lo->lo_offset >> BLOCK_SIZE_BITS);
+                                lo->lo_offset / BLOCK_SIZE;
 		else
 			size = MAX_DISK_SIZE;
 	}
Index: oldkernel/linux/drivers/block/md.c
diff -u linux/drivers/block/md.c:1.3 linux/drivers/block/md.c:1.4
--- linux/drivers/block/md.c:1.3	Thu Jun  1 17:03:15 2000
+++ linux/drivers/block/md.c	Fri Jul  7 15:36:42 2000
@@ -827,16 +827,16 @@
 	int ret;
 	mdp_super_t *tmp1, *tmp2;
 
-	tmp1 = kmalloc(sizeof(*tmp1),GFP_KERNEL);
-	tmp2 = kmalloc(sizeof(*tmp2),GFP_KERNEL);
+	tmp1 = kmalloc(MD_SB_BYTES,GFP_KERNEL);
+	tmp2 = kmalloc(MD_SB_BYTES,GFP_KERNEL);
 
 	if (!tmp1 || !tmp2) {
 		ret = 0;
 		goto abort;
 	}
 
-	*tmp1 = *sb1;
-	*tmp2 = *sb2;
+	memcpy(tmp1, sb1, MD_SB_BYTES);
+	memcpy(tmp2, sb2, MD_SB_BYTES);
 
 	/*
 	 * nr_disks is not constant
@@ -985,7 +985,7 @@
 		if (rdev->faulty)
 			continue;
 		sb = rdev->sb;
-		*sb = *mddev->sb;
+		memcpy(sb, mddev->sb, MD_SB_BYTES);
 		set_this_disk(mddev, rdev);
 		sb->sb_csum = calc_sb_csum(sb);
 	}
@@ -1249,7 +1249,7 @@
 		printk(OUT_OF_DATE);
 		printk("freshest: %s\n", partition_name(freshest->dev));
 	}
-	memcpy (sb, freshest->sb, sizeof(*sb));
+	memcpy (sb, freshest->sb, MD_SB_BYTES);
 
 	/*
 	 * at this point we have picked the 'best' superblock
Index: oldkernel/linux/drivers/block/xor.c
diff -u linux/drivers/block/xor.c:1.2 linux/drivers/block/xor.c:1.3
--- linux/drivers/block/xor.c:1.2	Thu Jun  1 15:06:21 2000
+++ linux/drivers/block/xor.c	Fri Jul  7 15:36:42 2000
@@ -22,10 +22,6 @@
 #include <asm/asi.h>
 #include <asm/visasm.h>
 #endif
-#ifdef __i386__
-#include <asm/processor.h>
-#include <asm/i387.h>
-#endif
 
 /*
  * we use the 'XOR function template' to register multiple xor
@@ -70,7 +66,7 @@
 
 #ifdef __i386__
 
-#ifdef CONFIG_X86_CPU_OPTIMIZATIONS
+#ifdef CONFIG_X86_XMM
 /*
  * Cache avoiding checksumming functions utilizing KNI instructions
  * Copyright (C) 1999 Zach Brown (with obvious credit due Ingo)
@@ -78,13 +74,21 @@
 
 XORBLOCK_TEMPLATE(pIII_kni)
 {
-	char xmm_space[64];
-	int lines = (bh_ptr[0]->b_size>>8);
-	int recursive = 0;
-	unsigned long flags;
+	char xmm_save[16*4];
+	int cr0;
+        int lines = (bh_ptr[0]->b_size>>8);
+
+	__asm__ __volatile__ ( 
+		"movl %%cr0,%0		;\n\t"
+		"clts			;\n\t"
+		"movups %%xmm0,(%1)	;\n\t"
+		"movups %%xmm1,0x10(%1)	;\n\t"
+		"movups %%xmm2,0x20(%1)	;\n\t"
+		"movups %%xmm3,0x30(%1)	;\n\t"
+		: "=r" (cr0)
+		: "r" (xmm_save) 
+		: "memory" );
 
-	kernel_take_fpu_kni(recursive,&xmm_space[0],NULL,flags);
-
 #define OFFS(x) "8*("#x"*2)"
 #define	PF0(x) \
 	"	prefetcht0  "OFFS(x)"(%1)   ;\n"
@@ -153,7 +157,7 @@
         "       jnz 1b                  ;\n"
 
         		:
-			: "m" (lines),
+			: "r" (lines),
 			  "r" (bh_ptr[0]->b_data),
         		  "r" (bh_ptr[1]->b_data)
 		        : "memory" );
@@ -203,7 +207,7 @@
         "       decl %0                 ;\n"
         "       jnz 1b                  ;\n"
         		:
-			: "m" (lines),
+			: "r" (lines),
 			  "r" (bh_ptr[0]->b_data),
         		  "r" (bh_ptr[1]->b_data),
 			  "r" (bh_ptr[2]->b_data)
@@ -262,7 +266,7 @@
         "       jnz 1b                  ;\n"
 
         		:
-			: "m" (lines),
+			: "r" (lines),
 			  "r" (bh_ptr[0]->b_data),
         		  "r" (bh_ptr[1]->b_data),
 			  "r" (bh_ptr[2]->b_data),
@@ -329,7 +333,7 @@
         "       jnz 1b                  ;\n"
 
         		:
-			: "m" (lines),
+			: "r" (lines),
 			  "r" (bh_ptr[0]->b_data),
         		  "r" (bh_ptr[1]->b_data),
 			  "r" (bh_ptr[2]->b_data),
@@ -339,7 +343,16 @@
 			break;
 	}
 
-	kernel_release_fpu_kni(recursive,&xmm_space[0],flags);
+	__asm__ __volatile__ ( 
+		"sfence			;\n\t"
+		"movups (%1),%%xmm0	;\n\t"
+		"movups 0x10(%1),%%xmm1	;\n\t"
+		"movups 0x20(%1),%%xmm2	;\n\t"
+		"movups 0x30(%1),%%xmm3	;\n\t"
+		"movl 	%0,%%cr0	;\n\t"
+		:
+		: "r" (cr0), "r" (xmm_save)
+		: "memory" );
 }
 
 #undef OFFS
@@ -358,7 +371,7 @@
 #undef XO5
 #undef BLOCK
 
-#endif /* CONFIG_X86_CPU_OPTIMIZATIONS */
+#endif /* CONFIG_X86_XMM */
 
 /*
  * high-speed RAID5 checksumming functions utilizing MMX instructions
@@ -366,12 +379,13 @@
  */
 XORBLOCK_TEMPLATE(pII_mmx)
 {
+	char fpu_save[108];
         int lines = (bh_ptr[0]->b_size>>7);
-	char mmx_space[32];
-	int recursive = 0;
-	unsigned long flags;
+
+	if (!(current->flags & PF_USEDFPU))
+		__asm__ __volatile__ ( " clts;\n");
 
-	kernel_take_fpu_mmx(recursive,&mmx_space[0],NULL,flags);
+	__asm__ __volatile__ ( " fsave %0; fwait\n"::"m"(fpu_save[0]) );
 
 #define LD(x,y) \
         "       movq   8*("#x")(%1), %%mm"#y"   ;\n"
@@ -417,7 +431,7 @@
 		        "       decl %0               ;\n"
 		        "       jnz 1b                ;\n"
 	        	:
-			: "m" (lines),
+			: "r" (lines),
 			  "r" (bh_ptr[0]->b_data),
 			  "r" (bh_ptr[1]->b_data)
 			: "memory");
@@ -457,7 +471,7 @@
 		        "       decl %0               ;\n"
 		        "       jnz 1b                ;\n"
 	        	:
-			: "m" (lines),
+			: "r" (lines),
 			  "r" (bh_ptr[0]->b_data),
 			  "r" (bh_ptr[1]->b_data),
 			  "r" (bh_ptr[2]->b_data)
@@ -503,7 +517,7 @@
 		        "       decl %0               ;\n"
 		        "       jnz 1b                ;\n"
 	        	:
-			: "m" (lines),
+			: "r" (lines),
 			  "r" (bh_ptr[0]->b_data),
 			  "r" (bh_ptr[1]->b_data),
 			  "r" (bh_ptr[2]->b_data),
@@ -555,7 +569,7 @@
 		        "       decl %0               ;\n"
 		        "       jnz 1b                ;\n"
 	        	:
-			: "m" (lines),
+			: "r" (lines),
 			  "r" (bh_ptr[0]->b_data),
 			  "r" (bh_ptr[1]->b_data),
 			  "r" (bh_ptr[2]->b_data),
@@ -565,7 +579,10 @@
 			break;
 	}
 
-	kernel_release_fpu_mmx(recursive,&mmx_space[0],flags);
+	__asm__ __volatile__ ( " frstor %0;\n"::"m"(fpu_save[0]) );
+
+	if (!(current->flags & PF_USEDFPU))
+		stts();
 }
 
 #undef LD
@@ -578,12 +595,13 @@
 
 XORBLOCK_TEMPLATE(p5_mmx)
 {
+	char fpu_save[108];
         int lines = (bh_ptr[0]->b_size>>6);
-	char mmx_space[32];
-	int recursive = 0;
-	unsigned long flags;
+
+	if (!(current->flags & PF_USEDFPU))
+		__asm__ __volatile__ ( " clts;\n");
 
-	kernel_take_fpu_mmx(recursive,&mmx_space[0],NULL,flags);
+	__asm__ __volatile__ ( " fsave %0; fwait\n"::"m"(fpu_save[0]) );
 
 	switch(count) {
 		case 2:
@@ -600,21 +618,21 @@
 			        "       movq 24(%1), %%mm3   ;\n"
 			        "       movq %%mm1,  8(%1)   ;\n"
 			        "       pxor 16(%2), %%mm2   ;\n"
-			        "       movq 32(%1), %%mm0   ;\n"
+			        "       movq 32(%1), %%mm4   ;\n"
 			        "       movq %%mm2, 16(%1)   ;\n"
 			        "       pxor 24(%2), %%mm3   ;\n"
-			        "       movq 40(%1), %%mm1   ;\n"
+			        "       movq 40(%1), %%mm5   ;\n"
 			        "       movq %%mm3, 24(%1)   ;\n"
-			        "       pxor 32(%2), %%mm0   ;\n"
-			        "       movq 48(%1), %%mm2   ;\n"
-			        "       movq %%mm0, 32(%1)   ;\n"
-			        "       pxor 40(%2), %%mm1   ;\n"
-			        "       movq 56(%1), %%mm3   ;\n"
-			        "       movq %%mm1, 40(%1)   ;\n"
-			        "       pxor 48(%2), %%mm2   ;\n"
-			        "       pxor 56(%2), %%mm3   ;\n"
-			        "       movq %%mm2, 48(%1)   ;\n"
-			        "       movq %%mm3, 56(%1)   ;\n"
+			        "       pxor 32(%2), %%mm4   ;\n"
+			        "       movq 48(%1), %%mm6   ;\n"
+			        "       movq %%mm4, 32(%1)   ;\n"
+			        "       pxor 40(%2), %%mm5   ;\n"
+			        "       movq 56(%1), %%mm7   ;\n"
+			        "       movq %%mm5, 40(%1)   ;\n"
+			        "       pxor 48(%2), %%mm6   ;\n"
+			        "       pxor 56(%2), %%mm7   ;\n"
+			        "       movq %%mm6, 48(%1)   ;\n"
+			        "       movq %%mm7, 56(%1)   ;\n"
         
 			        "       addl $64, %1         ;\n"
 			        "       addl $64, %2         ;\n"
@@ -622,7 +640,7 @@
 			        "       jnz 1b               ;\n"
 
 			        : 
-			        : "m" (lines),
+			        : "r" (lines),
 				  "r" (bh_ptr[0]->b_data),
 				  "r" (bh_ptr[1]->b_data)
 			        : "memory" );
@@ -644,26 +662,26 @@
 			        "       pxor 16(%3), %%mm2   ;\n"
 			        "       movq 24(%1), %%mm3   ;\n"
 			        "       movq %%mm1,  8(%1)   ;\n"
-			        "       movq 32(%1), %%mm0   ;\n"
-			        "       movq 40(%1), %%mm1   ;\n"
+			        "       movq 32(%1), %%mm4   ;\n"
+			        "       movq 40(%1), %%mm5   ;\n"
 			        "       pxor 24(%2), %%mm3   ;\n"
 			        "       movq %%mm2, 16(%1)   ;\n"
-			        "       pxor 32(%2), %%mm0   ;\n"
+			        "       pxor 32(%2), %%mm4   ;\n"
 			        "       pxor 24(%3), %%mm3   ;\n"
-			        "       pxor 40(%2), %%mm1   ;\n"
+			        "       pxor 40(%2), %%mm5   ;\n"
 			        "       movq %%mm3, 24(%1)   ;\n"
-			        "       pxor 32(%3), %%mm0   ;\n"
-			        "       pxor 40(%3), %%mm1   ;\n"
-			        "       movq 48(%1), %%mm2   ;\n"
-			        "       movq %%mm0, 32(%1)   ;\n"
-			        "       movq 56(%1), %%mm3   ;\n"
-			        "       pxor 48(%2), %%mm2   ;\n"
-			        "       movq %%mm1, 40(%1)   ;\n"
-			        "       pxor 56(%2), %%mm3   ;\n"
-			        "       pxor 48(%3), %%mm2   ;\n"
-			        "       pxor 56(%3), %%mm3   ;\n"
-			        "       movq %%mm2, 48(%1)   ;\n"
-			        "       movq %%mm3, 56(%1)   ;\n"
+			        "       pxor 32(%3), %%mm4   ;\n"
+			        "       pxor 40(%3), %%mm5   ;\n"
+			        "       movq 48(%1), %%mm6   ;\n"
+			        "       movq %%mm4, 32(%1)   ;\n"
+			        "       movq 56(%1), %%mm7   ;\n"
+			        "       pxor 48(%2), %%mm6   ;\n"
+			        "       movq %%mm5, 40(%1)   ;\n"
+			        "       pxor 56(%2), %%mm7   ;\n"
+			        "       pxor 48(%3), %%mm6   ;\n"
+			        "       pxor 56(%3), %%mm7   ;\n"
+			        "       movq %%mm6, 48(%1)   ;\n"
+			        "       movq %%mm7, 56(%1)   ;\n"
         
 			        "       addl $64, %1         ;\n"
 			        "       addl $64, %2         ;\n"
@@ -672,7 +690,7 @@
 			        "       jnz 1b               ;\n"
 
 			        : 
-			        : "m" (lines),
+			        : "r" (lines),
 				  "r" (bh_ptr[0]->b_data),
 				  "r" (bh_ptr[1]->b_data),
 				  "r" (bh_ptr[2]->b_data)
@@ -696,33 +714,33 @@
 			        "       pxor 16(%3), %%mm2   ;\n"
 			        "       pxor  8(%4), %%mm1   ;\n"
 			        "       movq %%mm0,   (%1)   ;\n"
-			        "       movq 32(%1), %%mm0   ;\n"
+			        "       movq 32(%1), %%mm4   ;\n"
 			        "       pxor 24(%2), %%mm3   ;\n"
 			        "       pxor 16(%4), %%mm2   ;\n"
 			        "       movq %%mm1,  8(%1)   ;\n"
-			        "       movq 40(%1), %%mm1   ;\n"
-			        "       pxor 32(%2), %%mm0   ;\n"
+			        "       movq 40(%1), %%mm5   ;\n"
+			        "       pxor 32(%2), %%mm4   ;\n"
 			        "       pxor 24(%3), %%mm3   ;\n"
 			        "       movq %%mm2, 16(%1)   ;\n"
-			        "       pxor 40(%2), %%mm1   ;\n"
-			        "       pxor 32(%3), %%mm0   ;\n"
+			        "       pxor 40(%2), %%mm5   ;\n"
+			        "       pxor 32(%3), %%mm4   ;\n"
 			        "       pxor 24(%4), %%mm3   ;\n"
 			        "       movq %%mm3, 24(%1)   ;\n"
-			        "       movq 56(%1), %%mm3   ;\n"
-			        "       movq 48(%1), %%mm2   ;\n"
-			        "       pxor 40(%3), %%mm1   ;\n"
-			        "       pxor 32(%4), %%mm0   ;\n"
-			        "       pxor 48(%2), %%mm2   ;\n"
-			        "       movq %%mm0, 32(%1)   ;\n"
-			        "       pxor 56(%2), %%mm3   ;\n"
-			        "       pxor 40(%4), %%mm1   ;\n"
-			        "       pxor 48(%3), %%mm2   ;\n"
-			        "       pxor 56(%3), %%mm3   ;\n"
-			        "       movq %%mm1, 40(%1)   ;\n"
-			        "       pxor 48(%4), %%mm2   ;\n"
-			        "       pxor 56(%4), %%mm3   ;\n"
-			        "       movq %%mm2, 48(%1)   ;\n"
-			        "       movq %%mm3, 56(%1)   ;\n"
+			        "       movq 56(%1), %%mm7   ;\n"
+			        "       movq 48(%1), %%mm6   ;\n"
+			        "       pxor 40(%3), %%mm5   ;\n"
+			        "       pxor 32(%4), %%mm4   ;\n"
+			        "       pxor 48(%2), %%mm6   ;\n"
+			        "       movq %%mm4, 32(%1)   ;\n"
+			        "       pxor 56(%2), %%mm7   ;\n"
+			        "       pxor 40(%4), %%mm5   ;\n"
+			        "       pxor 48(%3), %%mm6   ;\n"
+			        "       pxor 56(%3), %%mm7   ;\n"
+			        "       movq %%mm5, 40(%1)   ;\n"
+			        "       pxor 48(%4), %%mm6   ;\n"
+			        "       pxor 56(%4), %%mm7   ;\n"
+			        "       movq %%mm6, 48(%1)   ;\n"
+			        "       movq %%mm7, 56(%1)   ;\n"
         
 			        "       addl $64, %1         ;\n"
 			        "       addl $64, %2         ;\n"
@@ -732,7 +750,7 @@
 			        "       jnz 1b               ;\n"
 
 			        : 
-			        : "m" (lines),
+			        : "r" (lines),
 				  "r" (bh_ptr[0]->b_data),
 				  "r" (bh_ptr[1]->b_data),
 				  "r" (bh_ptr[2]->b_data),
@@ -764,34 +782,34 @@
 			        "       movq %%mm1,  8(%1)   ;\n"
 			        "       pxor 16(%5), %%mm2   ;\n"
 			        "       pxor 24(%3), %%mm3   ;\n"
-			        "       movq 32(%1), %%mm0   ;\n"
+			        "       movq 32(%1), %%mm4   ;\n"
 			        "       movq %%mm2, 16(%1)   ;\n"
 			        "       pxor 24(%4), %%mm3   ;\n"
-			        "       pxor 32(%2), %%mm0   ;\n"
-			        "       movq 40(%1), %%mm1   ;\n"
+			        "       pxor 32(%2), %%mm4   ;\n"
+			        "       movq 40(%1), %%mm5   ;\n"
 			        "       pxor 24(%5), %%mm3   ;\n"
-			        "       pxor 32(%3), %%mm0   ;\n"
-			        "       pxor 40(%2), %%mm1   ;\n"
+			        "       pxor 32(%3), %%mm4   ;\n"
+			        "       pxor 40(%2), %%mm5   ;\n"
 			        "       movq %%mm3, 24(%1)   ;\n"
-			        "       pxor 32(%4), %%mm0   ;\n"
-			        "       pxor 40(%3), %%mm1   ;\n"
-			        "       movq 48(%1), %%mm2   ;\n"
-			        "       movq 56(%1), %%mm3   ;\n"
-			        "       pxor 32(%5), %%mm0   ;\n"
-			        "       pxor 40(%4), %%mm1   ;\n"
-			        "       pxor 48(%2), %%mm2   ;\n"
-			        "       pxor 56(%2), %%mm3   ;\n"
-			        "       movq %%mm0, 32(%1)   ;\n"
-			        "       pxor 48(%3), %%mm2   ;\n"
-			        "       pxor 56(%3), %%mm3   ;\n"
-			        "       pxor 40(%5), %%mm1   ;\n"
-			        "       pxor 48(%4), %%mm2   ;\n"
-			        "       pxor 56(%4), %%mm3   ;\n"
-			        "       movq %%mm1, 40(%1)   ;\n"
-			        "       pxor 48(%5), %%mm2   ;\n"
-			        "       pxor 56(%5), %%mm3   ;\n"
-			        "       movq %%mm2, 48(%1)   ;\n"
-			        "       movq %%mm3, 56(%1)   ;\n"
+			        "       pxor 32(%4), %%mm4   ;\n"
+			        "       pxor 40(%3), %%mm5   ;\n"
+			        "       movq 48(%1), %%mm6   ;\n"
+			        "       movq 56(%1), %%mm7   ;\n"
+			        "       pxor 32(%5), %%mm4   ;\n"
+			        "       pxor 40(%4), %%mm5   ;\n"
+			        "       pxor 48(%2), %%mm6   ;\n"
+			        "       pxor 56(%2), %%mm7   ;\n"
+			        "       movq %%mm4, 32(%1)   ;\n"
+			        "       pxor 48(%3), %%mm6   ;\n"
+			        "       pxor 56(%3), %%mm7   ;\n"
+			        "       pxor 40(%5), %%mm5   ;\n"
+			        "       pxor 48(%4), %%mm6   ;\n"
+			        "       pxor 56(%4), %%mm7   ;\n"
+			        "       movq %%mm5, 40(%1)   ;\n"
+			        "       pxor 48(%5), %%mm6   ;\n"
+			        "       pxor 56(%5), %%mm7   ;\n"
+			        "       movq %%mm6, 48(%1)   ;\n"
+			        "       movq %%mm7, 56(%1)   ;\n"
         
 			        "       addl $64, %1         ;\n"
 			        "       addl $64, %2         ;\n"
@@ -802,7 +820,7 @@
 			        "       jnz 1b               ;\n"
 
 			        : 
-			        : "m" (lines),
+			        : "r" (lines),
 				  "r" (bh_ptr[0]->b_data),
 				  "r" (bh_ptr[1]->b_data),
 				  "r" (bh_ptr[2]->b_data),
@@ -812,7 +830,10 @@
 			break;
 	}
 
-	kernel_release_fpu_mmx(recursive,&mmx_space[0],flags);
+	__asm__ __volatile__ ( " frstor %0;\n"::"m"(fpu_save[0]) );
+
+	if (!(current->flags & PF_USEDFPU))
+		stts();
 }
 #endif /* __i386__ */
 #endif /* !__sparc_v9__ */
@@ -1790,12 +1811,11 @@
 		if (f->speed > fastest->speed)
 			fastest = f;
 	}
-#ifdef CONFIG_X86_CPU_OPTIMIZATIONS
-	if ( (boot_cpu_data.mmu_cr4_features & X86_CR4_OSFXSR) &&
-	     (boot_cpu_data.x86_capability & X86_FEATURE_XMM) ) {
+#ifdef CONFIG_X86_XMM 
+	if (boot_cpu_data.mmu_cr4_features & X86_CR4_OSXMMEXCPT) {
 		fastest = &t_xor_block_pIII_kni;
 	}
-#endif /* CONFIG_X86_CPU_OPTIMIZATIONS */
+#endif
 	xor_block = fastest->xor_block;
 	printk( "using fastest function: %s (%d.%03d MB/sec)\n", fastest->name,
 		fastest->speed / 1000, fastest->speed % 1000);
@@ -1827,9 +1847,8 @@
 	xor_speed(&t_xor_block_SPARC,&b1,&b2);
 #endif
 
-#ifdef CONFIG_X86_CPU_OPTIMIZATIONS
-	if ( (boot_cpu_data.mmu_cr4_features & X86_CR4_OSFXSR) &&
-	     (boot_cpu_data.x86_capability & X86_FEATURE_XMM) ) {
+#ifdef CONFIG_X86_XMM 
+	if (boot_cpu_data.mmu_cr4_features & X86_CR4_OSXMMEXCPT) {
 		printk(KERN_INFO
 			"raid5: KNI detected, trying cache-avoiding KNI checksum routine\n");
 		/* we force the use of the KNI xor block because it
@@ -1840,7 +1859,7 @@
 		*/
 		xor_speed(&t_xor_block_pIII_kni,&b1,&b2);
 	}
-#endif /* CONFIG_X86_CPU_OPTIMIZATIONS */
+#endif /* CONFIG_X86_XMM */
 
 #ifdef __i386__
 
Index: oldkernel/linux/drivers/char/ip2main.c
diff -u linux/drivers/char/ip2main.c:1.1.1.1 linux/drivers/char/ip2main.c:1.2
--- linux/drivers/char/ip2main.c:1.1.1.1	Wed May 31 12:33:51 2000
+++ linux/drivers/char/ip2main.c	Fri Jul  7 15:36:42 2000
@@ -3174,7 +3174,7 @@
 	if (off >= len+begin)
 		return 0;
 
-	*start = page + (begin-off);
+	*start = page + (off-begin);
 	return ((count < begin+len-off) ? count : begin+len-off);
  }
  
Index: oldkernel/linux/drivers/char/serial.c
diff -u linux/drivers/char/serial.c:1.2 linux/drivers/char/serial.c:1.3
--- linux/drivers/char/serial.c:1.2	Thu Jun  1 15:35:12 2000
+++ linux/drivers/char/serial.c	Fri Jul  7 15:36:43 2000
@@ -2,6 +2,8 @@
  *  linux/drivers/char/serial.c
  *
  *  Copyright (C) 1991, 1992  Linus Torvalds
+ *  Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 
+ * 		1998, 1999  Theodore Ts'o
  *
  *  Extensively rewritten by Theodore Ts'o, 8/16/92 -- 9/14/92.  Now
  *  much more extensible to support other serial cards based on the
@@ -32,11 +34,23 @@
  *  4/98: Added changes to support the ARM architecture proposed by
  * 	  Russell King
  *
+ *  5/99: Updated to include support for the XR16C850 and ST16C654
+ *        uarts.  Stuart MacDonald <stuartm@connecttech.com>
+ *
+ *  8/99: Generalized PCI support added.  Theodore Ts'o
+ * 
+ *  3/00: Rid circular buffer of redundant xmit_cnt.  Fix a
+ *	  few races on freeing buffers too.
+ *	  Alan Modra <alan@linuxcare.com>
+ *
  * This module exports the following rs232 io functions:
  *
  *	int rs_init(void);
  */
 
+static char *serial_version = "4.94";
+static char *serial_revdate = "2000-04-25";
+
 /*
  * Serial driver configuration section.  Here are the various options:
  *
@@ -61,15 +75,16 @@
  * 		Check the magic number for the async_structure where
  * 		ever possible.
  */
+
 #include <linux/config.h>
+#include <linux/version.h>
 
 #undef SERIAL_PARANOIA_CHECK
 #define CONFIG_SERIAL_NOPAUSE_IO
 #define SERIAL_DO_RESTART
 
 #if 0
-/* Normally these defines are controlled by the autoconf.h */
-
+/* These defines are normally controlled by the autoconf.h */
 #define CONFIG_SERIAL_MANY_PORTS
 #define CONFIG_SERIAL_SHARE_IRQ
 #define CONFIG_SERIAL_DETECT_IRQ
@@ -77,6 +92,31 @@
 #define CONFIG_HUB6
 #endif
 
+#ifdef CONFIG_PCI
+#define ENABLE_SERIAL_PCI
+#ifndef CONFIG_SERIAL_SHARE_IRQ
+#define CONFIG_SERIAL_SHARE_IRQ
+#endif
+#ifndef CONFIG_SERIAL_MANY_PORTS
+#define CONFIG_SERIAL_MANY_PORTS
+#endif
+#endif
+
+#if defined(CONFIG_ISAPNP)|| (defined(CONFIG_ISAPNP_MODULE) && defined(MODULE))
+#ifndef ENABLE_SERIAL_PNP
+#define ENABLE_SERIAL_PNP
+#endif
+#endif
+
+/* Set of debugging defines */
+
+#undef SERIAL_DEBUG_INTR
+#undef SERIAL_DEBUG_OPEN
+#undef SERIAL_DEBUG_FLOW
+#undef SERIAL_DEBUG_RS_WAIT_UNTIL_SENT
+#undef SERIAL_DEBUG_PCI
+#undef SERIAL_DEBUG_AUTOCONF
+
 /* Sanity checks */
 
 #ifdef CONFIG_SERIAL_MULTIPORT
@@ -94,33 +134,33 @@
 #endif
 #endif
 
-/* Set of debugging defines */
-
-#undef SERIAL_DEBUG_INTR
-#undef SERIAL_DEBUG_OPEN
-#undef SERIAL_DEBUG_FLOW
-#undef SERIAL_DEBUG_RS_WAIT_UNTIL_SENT
-
 #define RS_STROBE_TIME (10*HZ)
 #define RS_ISR_PASS_LIMIT 256
-
-#define IRQ_T(state) \
- ((state->flags & ASYNC_SHARE_IRQ) ? SA_SHIRQ : SA_INTERRUPT)
 
+#if defined(__i386__) && (defined(CONFIG_M386) || defined(CONFIG_M486))
 #define SERIAL_INLINE
-  
-#if defined(MODULE) && defined(SERIAL_DEBUG_MCOUNT)
-#define DBG_CNT(s) printk("(%s): [%x] refc=%d, serc=%d, ttyc=%d -> %s\n", \
- kdevname(tty->device), (info->flags), serial_refcount,info->count,tty->count,s)
-#else
-#define DBG_CNT(s)
 #endif
-
+  
 /*
  * End of serial driver configuration section.
  */
 
+#ifdef MODVERSIONS
+#include <linux/modversions.h>
+#endif
 #include <linux/module.h>
+
+#include <linux/types.h>
+#ifdef LOCAL_HEADERS
+#include "serial_local.h"
+#else
+#include <linux/serial.h>
+#include <linux/serialP.h>
+#include <linux/serial_reg.h>
+#include <asm/serial.h>
+#define LOCAL_VERSTRING ""
+#endif
+
 #include <linux/errno.h>
 #include <linux/signal.h>
 #include <linux/sched.h>
@@ -128,8 +168,6 @@
 #include <linux/interrupt.h>
 #include <linux/tty.h>
 #include <linux/tty_flip.h>
-#include <linux/serial.h>
-#include <linux/serial_reg.h>
 #include <linux/major.h>
 #include <linux/string.h>
 #include <linux/fcntl.h>
@@ -137,31 +175,64 @@
 #include <linux/ioport.h>
 #include <linux/mm.h>
 #include <linux/malloc.h>
+#if (LINUX_VERSION_CODE >= 131343)
 #include <linux/init.h>
+#endif
+#if (LINUX_VERSION_CODE >= 131336)
+#include <asm/uaccess.h>
+#endif
 #include <linux/delay.h>
 #ifdef CONFIG_SERIAL_CONSOLE
 #include <linux/console.h>
 #endif
+#ifdef ENABLE_SERIAL_PCI
+#include <linux/pci.h>
+#endif
+#ifdef ENABLE_SERIAL_PNP
+#include <linux/isapnp.h>
+#endif
+#ifdef CONFIG_MAGIC_SYSRQ
+#include <linux/sysrq.h>
+#endif
 
+/*
+ * All of the compatibilty code so we can compile serial.c against
+ * older kernels is hidden in serial_compat.h
+ */
+#if defined(LOCAL_HEADERS) || (LINUX_VERSION_CODE < 0x020317) /* 2.3.23 */
+#include "serial_compat.h"
+#endif
+
 #include <asm/system.h>
 #include <asm/io.h>
 #include <asm/irq.h>
-#include <asm/uaccess.h>
 #include <asm/bitops.h>
-#include <asm/serial.h>
+
+#ifdef CONFIG_MAC_SERIAL
+#define SERIAL_DEV_OFFSET	2
+#else
+#define SERIAL_DEV_OFFSET	0
+#endif
 
 #ifdef SERIAL_INLINE
 #define _INLINE_ inline
+#else
+#define _INLINE_
 #endif
-	
+
 static char *serial_name = "Serial driver";
-static char *serial_version = "4.27";
 
 static DECLARE_TASK_QUEUE(tq_serial);
 
 static struct tty_driver serial_driver, callout_driver;
 static int serial_refcount;
 
+/* serial subtype definitions */
+#ifndef SERIAL_TYPE_NORMAL
+#define SERIAL_TYPE_NORMAL	1
+#define SERIAL_TYPE_CALLOUT	2
+#endif
+
 /* number of characters left in xmit buffer before we ask for more */
 #define WAKEUP_CHARS 256
 
@@ -177,10 +248,11 @@
 static int IRQ_timeout[NR_IRQS];
 #ifdef CONFIG_SERIAL_CONSOLE
 static struct console sercons;
+static unsigned long break_pressed; /* break, really ... */
 #endif
 
 static unsigned detect_uart_irq (struct serial_state * state);
-static void autoconfig(struct serial_state * info);
+static void autoconfig(struct serial_state * state);
 static void change_speed(struct async_struct *info, struct termios *old);
 static void rs_wait_until_sent(struct tty_struct *tty, int timeout);
 
@@ -194,26 +266,64 @@
 	{ "16450", 1, 0 }, 
 	{ "16550", 1, 0 }, 
 	{ "16550A", 16, UART_CLEAR_FIFO | UART_USE_FIFO }, 
-	{ "cirrus", 1, 0 }, 
-	{ "ST16650", 1, UART_CLEAR_FIFO | UART_STARTECH }, 
+	{ "cirrus", 1, 0 }, 	/* usurped by cyclades.c */
+	{ "ST16650", 1, UART_CLEAR_FIFO |UART_STARTECH }, 
 	{ "ST16650V2", 32, UART_CLEAR_FIFO | UART_USE_FIFO |
 		  UART_STARTECH }, 
 	{ "TI16750", 64, UART_CLEAR_FIFO | UART_USE_FIFO},
+	{ "Startech", 1, 0},	/* usurped by cyclades.c */
+	{ "16C950/954", 128, UART_CLEAR_FIFO | UART_USE_FIFO},
+	{ "ST16654", 64, UART_CLEAR_FIFO | UART_USE_FIFO |
+		  UART_STARTECH }, 
+	{ "XR16850", 128, UART_CLEAR_FIFO | UART_USE_FIFO |
+		  UART_STARTECH },
 	{ 0, 0}
 };
 
-static struct serial_state rs_table[] = {
+static struct serial_state rs_table[RS_TABLE_SIZE] = {
 	SERIAL_PORT_DFNS	/* Defined in serial.h */
 };
 
 #define NR_PORTS	(sizeof(rs_table)/sizeof(struct serial_state))
 
+#if (defined(ENABLE_SERIAL_PCI) || defined(ENABLE_SERIAL_PNP))
+#define NR_PCI_BOARDS	8
+#ifdef MODULE
+/* We don't unregister PCI boards right now */
+static struct pci_board_inst	serial_pci_board[NR_PCI_BOARDS];
+static int serial_pci_board_idx = 0;
+#endif
+#ifndef IS_PCI_REGION_IOPORT
+#define IS_PCI_REGION_IOPORT(dev, r) (pci_resource_flags((dev), (r)) & \
+				      IORESOURCE_IO)
+#endif
+#ifndef PCI_IRQ_RESOURCE
+#define PCI_IRQ_RESOURCE(dev, r) ((dev)->irq_resource[r].start)
+#endif
+#ifndef pci_get_subvendor
+#define pci_get_subvendor(dev) ((dev)->subsystem_vendor)
+#define pci_get_subdevice(dev)  ((dev)->subsystem_device)
+#endif
+#endif	/* ENABLE_SERIAL_PCI || ENABLE_SERIAL_PNP  */
+
+#ifndef PREPARE_FUNC
+#define PREPARE_FUNC(dev)  (dev->prepare)
+#define ACTIVATE_FUNC(dev)  (dev->activate)
+#define DEACTIVATE_FUNC(dev)  (dev->deactivate)
+#endif
+
+#define HIGH_BITS_OFFSET ((sizeof(long)-sizeof(int))*8)
+
 static struct tty_struct *serial_table[NR_PORTS];
 static struct termios *serial_termios[NR_PORTS];
 static struct termios *serial_termios_locked[NR_PORTS];
 
-#ifndef MIN
-#define MIN(a,b)	((a) < (b) ? (a) : (b))
+
+#if defined(MODULE) && defined(SERIAL_DEBUG_MCOUNT)
+#define DBG_CNT(s) printk("(%s): [%x] refc=%d, serc=%d, ttyc=%d -> %s\n", \
+ kdevname(tty->device), (info->flags), serial_refcount,info->count,tty->count,s)
+#else
+#define DBG_CNT(s)
 #endif
 
 /*
@@ -226,8 +336,13 @@
  * memory if large numbers of serial ports are open.
  */
 static unsigned char *tmp_buf;
+#ifdef DECLARE_MUTEX
+static DECLARE_MUTEX(tmp_buf_sem);
+#else
 static struct semaphore tmp_buf_sem = MUTEX;
+#endif
 
+
 static inline int serial_paranoia_check(struct async_struct *info,
 					kdev_t device, const char *routine)
 {
@@ -249,57 +364,78 @@
 	return 0;
 }
 
-static inline unsigned int serial_in(struct async_struct *info, int offset)
+static _INLINE_ unsigned int serial_in(struct async_struct *info, int offset)
 {
+	switch (info->io_type) {
 #ifdef CONFIG_HUB6
-    if (info->hub6) {
-	outb(info->hub6 - 1 + offset, info->port);
-	return inb(info->port+1);
-    } else
+	case SERIAL_IO_HUB6:
+		outb(info->hub6 - 1 + offset, info->port);
+		return inb(info->port+1);
+#endif
+	case SERIAL_IO_MEM:
+		return readb((unsigned long) info->iomem_base +
+			     (offset<<info->iomem_reg_shift));
+#ifdef CONFIG_SERIAL_GSC
+	case SERIAL_IO_GSC:
+		return gsc_readb(info->iomem_base + offset);
 #endif
-	return inb(info->port + offset);
+	default:
+		return inb(info->port + offset);
+	}
 }
 
-static inline unsigned int serial_inp(struct async_struct *info, int offset)
+static _INLINE_ void serial_out(struct async_struct *info, int offset,
+				int value)
 {
+	switch (info->io_type) {
 #ifdef CONFIG_HUB6
-    if (info->hub6) {
-	outb(info->hub6 - 1 + offset, info->port);
-	return inb_p(info->port+1);
-    } else
+	case SERIAL_IO_HUB6:
+		outb(info->hub6 - 1 + offset, info->port);
+		outb(value, info->port+1);
+		break;
 #endif
-#ifdef CONFIG_SERIAL_NOPAUSE_IO
-	return inb(info->port + offset);
-#else
-	return inb_p(info->port + offset);
+	case SERIAL_IO_MEM:
+		writeb(value, (unsigned long) info->iomem_base +
+			      (offset<<info->iomem_reg_shift));
+		break;
+#ifdef CONFIG_SERIAL_GSC
+	case SERIAL_IO_GSC:
+		gsc_writeb(value, info->iomem_base + offset);
+		break;
 #endif
+	default:
+		outb(value, info->port+offset);
+	}
 }
+
+/*
+ * We used to support using pause I/O for certain machines.  We
+ * haven't supported this for a while, but just in case it's badly
+ * needed for certain old 386 machines, I've left these #define's
+ * in....
+ */
+#define serial_inp(info, offset)		serial_in(info, offset)
+#define serial_outp(info, offset, value)	serial_out(info, offset, value)
 
-static inline void serial_out(struct async_struct *info, int offset, int value)
+
+/*
+ * For the 16C950
+ */
+void serial_icr_write(struct async_struct *info, int offset, int  value)
 {
-#ifdef CONFIG_HUB6
-    if (info->hub6) {
-	outb(info->hub6 - 1 + offset, info->port);
-	outb(value, info->port+1);
-    } else
-#endif
-	outb(value, info->port+offset);
+	serial_out(info, UART_SCR, offset);
+	serial_out(info, UART_ICR, value);
 }
 
-static inline void serial_outp(struct async_struct *info, int offset,
-			       int value)
+unsigned int serial_icr_read(struct async_struct *info, int offset)
 {
-#ifdef CONFIG_HUB6
-    if (info->hub6) {
-	outb(info->hub6 - 1 + offset, info->port);
-	outb_p(value, info->port+1);
-    } else
-#endif
-#ifdef CONFIG_SERIAL_NOPAUSE_IO
-	outb(value, info->port+offset);
-#else
-    	outb_p(value, info->port+offset);
-#endif
+	int	value;
+
+	serial_icr_write(info, UART_ACR, info->ACR | UART_ACR_ICRRD);
+	serial_out(info, UART_SCR, offset);
+	value = serial_in(info, UART_ICR);
+	serial_icr_write(info, UART_ACR, info->ACR);
+	return value;
 }
 
 /*
@@ -323,6 +459,10 @@
 		info->IER &= ~UART_IER_THRI;
 		serial_out(info, UART_IER, info->IER);
 	}
+	if (info->state->type == PORT_16C950) {
+		info->ACR |= UART_ACR_TXDIS;
+		serial_icr_write(info, UART_ACR, info->ACR);
+	}
 	restore_flags(flags);
 }
 
@@ -335,10 +475,16 @@
 		return;
 	
 	save_flags(flags); cli();
-	if (info->xmit_cnt && info->xmit_buf && !(info->IER & UART_IER_THRI)) {
+	if (info->xmit.head != info->xmit.tail
+	    && info->xmit.buf
+	    && !(info->IER & UART_IER_THRI)) {
 		info->IER |= UART_IER_THRI;
 		serial_out(info, UART_IER, info->IER);
 	}
+	if (info->state->type == PORT_16C950) {
+		info->ACR &= ~UART_ACR_TXDIS;
+		serial_icr_write(info, UART_ACR, info->ACR);
+	}
 	restore_flags(flags);
 }
 
@@ -376,7 +522,7 @@
 }
 
 static _INLINE_ void receive_chars(struct async_struct *info,
-				 int *status)
+				 int *status, struct pt_regs * regs)
 {
 	struct tty_struct *tty = info->tty;
 	unsigned char ch;
@@ -387,7 +533,7 @@
 	do {
 		ch = serial_inp(info, UART_RX);
 		if (tty->flip.count >= TTY_FLIPBUF_SIZE)
-			break;
+			goto ignore_char;
 		*tty->flip.char_buf_ptr = ch;
 		icount->rx++;
 		
@@ -426,6 +572,15 @@
 #ifdef SERIAL_DEBUG_INTR
 				printk("handling break....");
 #endif
+#if defined(CONFIG_SERIAL_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ) && !defined(MODULE)
+				if (info->line == sercons.index) {
+					if (!break_pressed) {
+						break_pressed = jiffies;
+						goto ignore_char;
+					}
+					break_pressed = 0;
+				}
+#endif
 				*tty->flip.flag_buf_ptr = TTY_BREAK;
 				if (info->flags & ASYNC_SAK)
 					do_SAK(tty);
@@ -439,27 +594,42 @@
 				 * reported immediately, and doesn't
 				 * affect the current character
 				 */
-				if (tty->flip.count < TTY_FLIPBUF_SIZE) {
-					tty->flip.count++;
-					tty->flip.flag_buf_ptr++;
-					tty->flip.char_buf_ptr++;
-					*tty->flip.flag_buf_ptr = TTY_OVERRUN;
-				}
+				tty->flip.count++;
+				tty->flip.flag_buf_ptr++;
+				tty->flip.char_buf_ptr++;
+				*tty->flip.flag_buf_ptr = TTY_OVERRUN;
+				if (tty->flip.count >= TTY_FLIPBUF_SIZE)
+					goto ignore_char;
 			}
 		}
+#if defined(CONFIG_SERIAL_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ) && !defined(MODULE)
+		if (break_pressed && info->line == sercons.index) {
+			if (ch != 0 &&
+			    time_before(jiffies, break_pressed + HZ*5)) {
+				handle_sysrq(ch, regs, NULL, NULL);
+				break_pressed = 0;
+				goto ignore_char;
+			}
+			break_pressed = 0;
+		}
+#endif
 		tty->flip.flag_buf_ptr++;
 		tty->flip.char_buf_ptr++;
 		tty->flip.count++;
 	ignore_char:
 		*status = serial_inp(info, UART_LSR);
 	} while (*status & UART_LSR_DR);
+#if (LINUX_VERSION_CODE > 131394) /* 2.1.66 */
 	tty_flip_buffer_push(tty);
+#else
+	queue_task_irq_off(&tty->flip.tqueue, &tq_timer);
+#endif	
 }
 
 static _INLINE_ void transmit_chars(struct async_struct *info, int *intr_done)
 {
 	int count;
-	
+
 	if (info->x_char) {
 		serial_outp(info, UART_TX, info->x_char);
 		info->state->icount.tx++;
@@ -468,8 +638,9 @@
 			*intr_done = 0;
 		return;
 	}
-	if ((info->xmit_cnt <= 0) || info->tty->stopped ||
-	    info->tty->hw_stopped) {
+	if (info->xmit.head == info->xmit.tail
+	    || info->tty->stopped
+	    || info->tty->hw_stopped) {
 		info->IER &= ~UART_IER_THRI;
 		serial_out(info, UART_IER, info->IER);
 		return;
@@ -477,14 +648,16 @@
 	
 	count = info->xmit_fifo_size;
 	do {
-		serial_out(info, UART_TX, info->xmit_buf[info->xmit_tail++]);
-		info->xmit_tail = info->xmit_tail & (SERIAL_XMIT_SIZE-1);
+		serial_out(info, UART_TX, info->xmit.buf[info->xmit.tail]);
+		info->xmit.tail = (info->xmit.tail + 1) & (SERIAL_XMIT_SIZE-1);
 		info->state->icount.tx++;
-		if (--info->xmit_cnt <= 0)
+		if (info->xmit.head == info->xmit.tail)
 			break;
 	} while (--count > 0);
 	
-	if (info->xmit_cnt < WAKEUP_CHARS)
+	if (CIRC_CNT(info->xmit.head,
+		     info->xmit.tail,
+		     SERIAL_XMIT_SIZE) < WAKEUP_CHARS)
 		rs_sched_event(info, RS_EVENT_WRITE_WAKEUP);
 
 #ifdef SERIAL_DEBUG_INTR
@@ -493,7 +666,7 @@
 	if (intr_done)
 		*intr_done = 0;
 
-	if (info->xmit_cnt <= 0) {
+	if (info->xmit.head == info->xmit.tail) {
 		info->IER &= ~UART_IER_THRI;
 		serial_out(info, UART_IER, info->IER);
 	}
@@ -585,11 +758,11 @@
 #ifdef SERIAL_DEBUG_INTR
 	printk("rs_interrupt(%d)...", irq);
 #endif
-	
+
 	info = IRQ_ports[irq];
 	if (!info)
 		return;
-	
+
 #ifdef CONFIG_SERIAL_MULTIPORT	
 	multi = &rs_multiport[irq];
 	if (multi->port_monitor)
@@ -612,7 +785,7 @@
 		printk("status = %x...", status);
 #endif
 		if (status & UART_LSR_DR)
-			receive_chars(info, &status);
+			receive_chars(info, &status, regs);
 		check_modem_status(info);
 		if (status & UART_LSR_THRE)
 			transmit_chars(info, 0);
@@ -659,7 +832,7 @@
 #ifdef SERIAL_DEBUG_INTR
 	printk("rs_interrupt_single(%d)...", irq);
 #endif
-	
+
 	info = IRQ_ports[irq];
 	if (!info || !info->tty)
 		return;
@@ -676,7 +849,7 @@
 		printk("status = %x...", status);
 #endif
 		if (status & UART_LSR_DR)
-			receive_chars(info, &status);
+			receive_chars(info, &status, regs);
 		check_modem_status(info);
 		if (status & UART_LSR_THRE)
 			transmit_chars(info, 0);
@@ -714,7 +887,7 @@
 #ifdef SERIAL_DEBUG_INTR
 	printk("rs_interrupt_multi(%d)...", irq);
 #endif
-	
+
 	info = IRQ_ports[irq];
 	if (!info)
 		return;
@@ -739,7 +912,7 @@
 		printk("status = %x...", status);
 #endif
 		if (status & UART_LSR_DR)
-			receive_chars(info, &status);
+			receive_chars(info, &status, regs);
 		check_modem_status(info);
 		if (status & UART_LSR_THRE)
 			transmit_chars(info, 0);
@@ -750,11 +923,16 @@
 			continue;
 
 		info = IRQ_ports[irq];
+		/*
+		 * The user was a bonehead, and misconfigured their
+		 * multiport info.  Rather than lock up the kernel
+		 * in an infinite loop, if we loop too many times,
+		 * print a message and break out of the loop.
+		 */
 		if (pass_counter++ > RS_ISR_PASS_LIMIT) {
-#if 1
-			printk("rs_multi loop break\n");
-#endif
-			break; 	/* Prevent infinite loops */
+			printk("Misconfigured multiport serial info "
+			       "for irq %d.  Breaking out irq loop\n", irq);
+			break; 
 		}
 		if (multi->port_monitor)
 			printk("rs port monitor irq %d: 0x%x, 0x%x\n",
@@ -834,7 +1012,7 @@
 	unsigned long flags;
 
 	if ((jiffies - last_strobe) >= RS_STROBE_TIME) {
-		for (i=1; i < NR_IRQS; i++) {
+		for (i=0; i < NR_IRQS; i++) {
 			info = IRQ_ports[i];
 			if (!info)
 				continue;
@@ -847,7 +1025,7 @@
 					serial_out(info, UART_IER, info->IER);
 					info = info->next_port;
 				} while (info);
-#ifdef CONFIG_SERIAL_MULTIPORT					
+#ifdef CONFIG_SERIAL_MULTIPORT
 				if (rs_multiport[i].port1)
 					rs_interrupt_multi(i, NULL, NULL);
 				else
@@ -921,7 +1099,7 @@
 	unsigned short ICP;
 #endif
 
-	page = get_free_page(GFP_KERNEL);
+	page = get_zeroed_page(GFP_KERNEL);
 	if (!page)
 		return -ENOMEM;
 
@@ -932,16 +1110,16 @@
 		goto errout;
 	}
 
-	if (!state->port || !state->type) {
+	if (!CONFIGURED_SERIAL_PORT(state) || !state->type) {
 		if (info->tty)
 			set_bit(TTY_IO_ERROR, &info->tty->flags);
 		free_page(page);
 		goto errout;
 	}
-	if (info->xmit_buf)
+	if (info->xmit.buf)
 		free_page(page);
 	else
-		info->xmit_buf = (unsigned char *) page;
+		info->xmit.buf = (unsigned char *) page;
 
 #ifdef SERIAL_DEBUG_OPEN
 	printk("starting up ttys%d (irq %d)...", info->line, state->irq);
@@ -951,8 +1129,28 @@
 		/* Wake up UART */
 		serial_outp(info, UART_LCR, 0xBF);
 		serial_outp(info, UART_EFR, UART_EFR_ECB);
+		/*
+		 * Turn off LCR == 0xBF so we actually set the IER
+		 * register on the XR16C850
+		 */
+		serial_outp(info, UART_LCR, 0);
 		serial_outp(info, UART_IER, 0);
+		/*
+		 * Now reset LCR so we can turn off the ECB bit
+		 */
+		serial_outp(info, UART_LCR, 0xBF);
 		serial_outp(info, UART_EFR, 0);
+		/*
+		 * For a XR16C850, we need to set the trigger levels
+		 */
+		if (info->state->type == PORT_16850) {
+			serial_outp(info, UART_FCTR, UART_FCTR_TRGD |
+					UART_FCTR_RX);
+			serial_outp(info, UART_TRG, UART_TRG_96);
+			serial_outp(info, UART_FCTR, UART_FCTR_TRGD |
+					UART_FCTR_TX);
+			serial_outp(info, UART_TRG, UART_TRG_96);
+		}
 		serial_outp(info, UART_LCR, 0);
 	}
 
@@ -961,20 +1159,47 @@
 		serial_outp(info, UART_IER, 0);
 	}
 
+	if (info->state->type == PORT_16C950) {
+		/* Wake up and initialize UART */
+		info->ACR = 0;
+		serial_outp(info, UART_LCR, 0xBF);
+		serial_outp(info, UART_EFR, UART_EFR_ECB);
+		serial_outp(info, UART_IER, 0);
+		serial_outp(info, UART_LCR, 0);
+		serial_icr_write(info, UART_CSR, 0); /* Reset the UART */
+		serial_outp(info, UART_LCR, 0xBF);
+		serial_outp(info, UART_EFR, UART_EFR_ECB);
+		serial_outp(info, UART_LCR, 0);
+	}
+
 	/*
 	 * Clear the FIFO buffers and disable them
 	 * (they will be reenabled in change_speed())
 	 */
-	if (uart_config[state->type].flags & UART_CLEAR_FIFO)
-		serial_outp(info, UART_FCR, (UART_FCR_CLEAR_RCVR |
+	if (uart_config[state->type].flags & UART_CLEAR_FIFO) {
+		serial_outp(info, UART_FCR, UART_FCR_ENABLE_FIFO);
+		serial_outp(info, UART_FCR, (UART_FCR_ENABLE_FIFO |
+					     UART_FCR_CLEAR_RCVR |
 					     UART_FCR_CLEAR_XMIT));
+		serial_outp(info, UART_FCR, 0);
+	}
+
+	/*
+	 * Clear the interrupt registers.
+	 */
+	(void) serial_inp(info, UART_LSR);
+	(void) serial_inp(info, UART_RX);
+	(void) serial_inp(info, UART_IIR);
+	(void) serial_inp(info, UART_MSR);
 
 	/*
 	 * At this point there's no way the LSR could still be 0xFF;
 	 * if it is, then bail out, because there's likely no UART
 	 * here.
 	 */
-	if (serial_inp(info, UART_LSR) == 0xff) {
+	if (!(info->flags & ASYNC_BUGGY_UART) &&
+	    (serial_inp(info, UART_LSR) == 0xff)) {
+		printk("LSR safety check engaged!\n");
 		if (capable(CAP_SYS_ADMIN)) {
 			if (info->tty)
 				set_bit(TTY_IO_ERROR, &info->tty->flags);
@@ -990,7 +1215,7 @@
 			  !IRQ_ports[state->irq]->next_port)) {
 		if (IRQ_ports[state->irq]) {
 #ifdef CONFIG_SERIAL_SHARE_IRQ
-			free_irq(state->irq, NULL);
+			free_irq(state->irq, &IRQ_ports[state->irq]);
 #ifdef CONFIG_SERIAL_MULTIPORT				
 			if (rs_multiport[state->irq].port1)
 				handler = rs_interrupt_multi;
@@ -1004,8 +1229,8 @@
 		} else 
 			handler = rs_interrupt_single;
 
-		retval = request_irq(state->irq, handler, IRQ_T(state),
-				     "serial", NULL);
+		retval = request_irq(state->irq, handler, SA_SHIRQ,
+				     "serial", &IRQ_ports[state->irq]);
 		if (retval) {
 			if (capable(CAP_SYS_ADMIN)) {
 				if (info->tty)
@@ -1028,14 +1253,6 @@
 	figure_IRQ_timeout(state->irq);
 
 	/*
-	 * Clear the interrupt registers.
-	 */
-     /* (void) serial_inp(info, UART_LSR); */   /* (see above) */
-	(void) serial_inp(info, UART_RX);
-	(void) serial_inp(info, UART_IIR);
-	(void) serial_inp(info, UART_MSR);
-
-	/*
 	 * Now, initialize the UART 
 	 */
 	serial_outp(info, UART_LCR, UART_LCR_WLEN8);	/* reset DLAB */
@@ -1053,12 +1270,7 @@
 		if (state->irq != 0)
 			info->MCR |= UART_MCR_OUT2;
 	}
-#if defined(__alpha__) && !defined(CONFIG_PCI)
-	/*
-	 * DEC did something gratutiously wrong....
-	 */
-	info->MCR |= UART_MCR_OUT1 | UART_MCR_OUT2;
-#endif
+	info->MCR |= ALPHA_KLUDGE_MCR; 		/* Don't ask */
 	serial_outp(info, UART_MCR, info->MCR);
 	
 	/*
@@ -1086,7 +1298,7 @@
 
 	if (info->tty)
 		clear_bit(TTY_IO_ERROR, &info->tty->flags);
-	info->xmit_cnt = info->xmit_head = info->xmit_tail = 0;
+	info->xmit.head = info->xmit.tail = 0;
 
 	/*
 	 * Set up serial timers...
@@ -1097,6 +1309,7 @@
 	/*
 	 * Set up the tty->alt_speed kludge
 	 */
+#if (LINUX_VERSION_CODE >= 131394) /* Linux 2.1.66 */
 	if (info->tty) {
 		if ((info->flags & ASYNC_SPD_MASK) == ASYNC_SPD_HI)
 			info->tty->alt_speed = 57600;
@@ -1107,6 +1320,7 @@
 		if ((info->flags & ASYNC_SPD_MASK) == ASYNC_SPD_WARP)
 			info->tty->alt_speed = 460800;
 	}
+#endif
 	
 	/*
 	 * and set the speed of the serial port
@@ -1167,20 +1381,22 @@
 	if (state->irq && (!IRQ_ports[state->irq] ||
 			  !IRQ_ports[state->irq]->next_port)) {
 		if (IRQ_ports[state->irq]) {
-			free_irq(state->irq, NULL);
+			free_irq(state->irq, &IRQ_ports[state->irq]);
 			retval = request_irq(state->irq, rs_interrupt_single,
-					     IRQ_T(state), "serial", NULL);
+					     SA_SHIRQ, "serial",
+					     &IRQ_ports[state->irq]);
 			
 			if (retval)
 				printk("serial shutdown: request_irq: error %d"
 				       "  Couldn't reacquire IRQ.\n", retval);
 		} else
-			free_irq(state->irq, NULL);
+			free_irq(state->irq, &IRQ_ports[state->irq]);
 	}
 
-	if (info->xmit_buf) {
-		free_page((unsigned long) info->xmit_buf);
-		info->xmit_buf = 0;
+	if (info->xmit.buf) {
+		unsigned long pg = (unsigned long) info->xmit.buf;
+		info->xmit.buf = 0;
+		free_page(pg);
 	}
 
 	info->IER = 0;
@@ -1193,12 +1409,7 @@
 	} else
 #endif
 		info->MCR &= ~UART_MCR_OUT2;
-#if defined(__alpha__) && !defined(CONFIG_PCI)
-	/*
-	 * DEC did something gratutiously wrong....
-	 */
-	info->MCR |= UART_MCR_OUT1 | UART_MCR_OUT2;
-#endif
+	info->MCR |= ALPHA_KLUDGE_MCR; 		/* Don't ask */
 	
 	/* disable break condition */
 	serial_out(info, UART_LCR, serial_inp(info, UART_LCR) & ~UART_LCR_SBC);
@@ -1208,8 +1419,11 @@
 	serial_outp(info, UART_MCR, info->MCR);
 
 	/* disable FIFO's */	
-	serial_outp(info, UART_FCR, (UART_FCR_CLEAR_RCVR |
+	serial_outp(info, UART_FCR, (UART_FCR_ENABLE_FIFO |
+				     UART_FCR_CLEAR_RCVR |
 				     UART_FCR_CLEAR_XMIT));
+	serial_outp(info, UART_FCR, 0);
+
 	(void)serial_in(info, UART_RX);    /* read data port to reset things */
 	
 	if (info->tty)
@@ -1230,6 +1444,37 @@
 	restore_flags(flags);
 }
 
+#if (LINUX_VERSION_CODE < 131394) /* Linux 2.1.66 */
+static int baud_table[] = {
+	0, 50, 75, 110, 134, 150, 200, 300,
+	600, 1200, 1800, 2400, 4800, 9600, 19200,
+	38400, 57600, 115200, 230400, 460800, 0 };
+
+static int tty_get_baud_rate(struct tty_struct *tty)
+{
+	struct async_struct * info = (struct async_struct *)tty->driver_data;
+	unsigned int cflag, i;
+
+	cflag = tty->termios->c_cflag;
+
+	i = cflag & CBAUD;
+	if (i & CBAUDEX) {
+		i &= ~CBAUDEX;
+		if (i < 1 || i > 2) 
+			tty->termios->c_cflag &= ~CBAUDEX;
+		else
+			i += 15;
+	}
+	if (i == 15) {
+		if ((info->flags & ASYNC_SPD_MASK) == ASYNC_SPD_HI)
+			i += 1;
+		if ((info->flags & ASYNC_SPD_MASK) == ASYNC_SPD_VHI)
+			i += 2;
+	}
+	return baud_table[i];
+}
+#endif
+
 /*
  * This routine is called to set the UART divisor registers to match
  * the specified baud rate for a serial port.
@@ -1237,7 +1482,6 @@
 static void change_speed(struct async_struct *info,
 			 struct termios *old_termios)
 {
-	unsigned short port;
 	int	quot = 0, baud_base, baud;
 	unsigned cflag, cval, fcr = 0;
 	int	bits;
@@ -1246,7 +1490,7 @@
 	if (!info->tty || !info->tty->termios)
 		return;
 	cflag = info->tty->termios->c_cflag;
-	if (!(port = info->port))
+	if (!CONFIGURED_SERIAL_PORT(info))
 		return;
 
 	/* byte size and parity */
@@ -1278,6 +1522,18 @@
 	if (!baud)
 		baud = 9600;	/* B0 transition handled in rs_set_termios */
 	baud_base = info->state->baud_base;
+	if (info->state->type == PORT_16C950) {
+		if (baud <= baud_base)
+			serial_icr_write(info, UART_TCR, 0);
+		else if (baud <= 2*baud_base) {
+			serial_icr_write(info, UART_TCR, 0x8);
+			baud_base = baud_base * 2;
+		} else if (baud <= 4*baud_base) {
+			serial_icr_write(info, UART_TCR, 0x4);
+			baud_base = baud_base * 4;
+		} else
+			serial_icr_write(info, UART_TCR, 0);
+	}
 	if (baud == 38400 &&
 	    ((info->flags & ASYNC_SPD_MASK) == ASYNC_SPD_CUST))
 		quot = info->state->custom_divisor;
@@ -1309,6 +1565,15 @@
 	/* As a last resort, if the quotient is zero, default to 9600 bps */
 	if (!quot)
 		quot = baud_base / 9600;
+	/*
+	 * Work around a bug in the Oxford Semiconductor 952 rev B
+	 * chip which causes it to seriously miscalculate baud rates
+	 * when DLL is 0.
+	 */
+	if (((quot & 0xFF) == 0) && (info->state->type == PORT_16C950) &&
+	    (info->state->revision == 0x5201))
+		quot++;
+	
 	info->quot = quot;
 	info->timeout = ((info->xmit_fifo_size*HZ*bits*quot) / baud_base);
 	info->timeout += HZ/50;		/* Add .02 seconds of slop */
@@ -1383,11 +1648,12 @@
 	if (info->state->type == PORT_16750)
 		serial_outp(info, UART_FCR, fcr); 	/* set fcr */
 	serial_outp(info, UART_LCR, cval);		/* reset DLAB */
-	if (info->state->type != PORT_16750) {
-		if (fcr & UART_FCR_ENABLE_FIFO) {
-			/* emulated UARTs (Lucent Venus 167x) need two steps */
-			serial_outp(info, UART_FCR, UART_FCR_ENABLE_FIFO);
-		}
+	info->LCR = cval;				/* Save LCR */
+ 	if (info->state->type != PORT_16750) {
+ 		if (fcr & UART_FCR_ENABLE_FIFO) {
+ 			/* emulated UARTs (Lucent Venus 167x) need two steps */
+ 			serial_outp(info, UART_FCR, UART_FCR_ENABLE_FIFO);
+ 		}
 		serial_outp(info, UART_FCR, fcr); 	/* set fcr */
 	}
 	restore_flags(flags);
@@ -1401,18 +1667,19 @@
 	if (serial_paranoia_check(info, tty->device, "rs_put_char"))
 		return;
 
-	if (!tty || !info->xmit_buf)
+	if (!tty || !info->xmit.buf)
 		return;
 
 	save_flags(flags); cli();
-	if (info->xmit_cnt >= SERIAL_XMIT_SIZE - 1) {
+	if (CIRC_SPACE(info->xmit.head,
+		       info->xmit.tail,
+		       SERIAL_XMIT_SIZE) == 0) {
 		restore_flags(flags);
 		return;
 	}
 
-	info->xmit_buf[info->xmit_head++] = ch;
-	info->xmit_head &= SERIAL_XMIT_SIZE-1;
-	info->xmit_cnt++;
+	info->xmit.buf[info->xmit.head] = ch;
+	info->xmit.head = (info->xmit.head + 1) & (SERIAL_XMIT_SIZE-1);
 	restore_flags(flags);
 }
 
@@ -1424,8 +1691,10 @@
 	if (serial_paranoia_check(info, tty->device, "rs_flush_chars"))
 		return;
 
-	if (info->xmit_cnt <= 0 || tty->stopped || tty->hw_stopped ||
-	    !info->xmit_buf)
+	if (info->xmit.head == info->xmit.tail
+	    || tty->stopped
+	    || tty->hw_stopped
+	    || !info->xmit.buf)
 		return;
 
 	save_flags(flags); cli();
@@ -1444,16 +1713,19 @@
 	if (serial_paranoia_check(info, tty->device, "rs_write"))
 		return 0;
 
-	if (!tty || !info->xmit_buf || !tmp_buf)
+	if (!tty || !info->xmit.buf || !tmp_buf)
 		return 0;
 
 	save_flags(flags);
 	if (from_user) {
 		down(&tmp_buf_sem);
 		while (1) {
-			c = MIN(count,
-				MIN(SERIAL_XMIT_SIZE - info->xmit_cnt - 1,
-				    SERIAL_XMIT_SIZE - info->xmit_head));
+			int c1;
+			c = CIRC_SPACE_TO_END(info->xmit.head,
+					      info->xmit.tail,
+					      SERIAL_XMIT_SIZE);
+			if (count < c)
+				c = count;
 			if (c <= 0)
 				break;
 
@@ -1464,12 +1736,14 @@
 				break;
 			}
 			cli();
-			c = MIN(c, MIN(SERIAL_XMIT_SIZE - info->xmit_cnt - 1,
-				       SERIAL_XMIT_SIZE - info->xmit_head));
-			memcpy(info->xmit_buf + info->xmit_head, tmp_buf, c);
-			info->xmit_head = ((info->xmit_head + c) &
+			c1 = CIRC_SPACE_TO_END(info->xmit.head,
+					       info->xmit.tail,
+					       SERIAL_XMIT_SIZE);
+			if (c1 < c)
+				c = c1;
+			memcpy(info->xmit.buf + info->xmit.head, tmp_buf, c);
+			info->xmit.head = ((info->xmit.head + c) &
 					   (SERIAL_XMIT_SIZE-1));
-			info->xmit_cnt += c;
 			restore_flags(flags);
 			buf += c;
 			count -= c;
@@ -1477,27 +1751,29 @@
 		}
 		up(&tmp_buf_sem);
 	} else {
+		cli();
 		while (1) {
-			cli();		
-			c = MIN(count,
-				MIN(SERIAL_XMIT_SIZE - info->xmit_cnt - 1,
-				    SERIAL_XMIT_SIZE - info->xmit_head));
+			c = CIRC_SPACE_TO_END(info->xmit.head,
+					      info->xmit.tail,
+					      SERIAL_XMIT_SIZE);
+			if (count < c)
+				c = count;
 			if (c <= 0) {
-				restore_flags(flags);
 				break;
 			}
-			memcpy(info->xmit_buf + info->xmit_head, buf, c);
-			info->xmit_head = ((info->xmit_head + c) &
+			memcpy(info->xmit.buf + info->xmit.head, buf, c);
+			info->xmit.head = ((info->xmit.head + c) &
 					   (SERIAL_XMIT_SIZE-1));
-			info->xmit_cnt += c;
-			restore_flags(flags);
 			buf += c;
 			count -= c;
 			ret += c;
 		}
+		restore_flags(flags);
 	}
-	if (info->xmit_cnt && !tty->stopped && !tty->hw_stopped &&
-	    !(info->IER & UART_IER_THRI)) {
+	if (info->xmit.head != info->xmit.tail
+	    && !tty->stopped
+	    && !tty->hw_stopped
+	    && !(info->IER & UART_IER_THRI)) {
 		info->IER |= UART_IER_THRI;
 		serial_out(info, UART_IER, info->IER);
 	}
@@ -1507,14 +1783,10 @@
 static int rs_write_room(struct tty_struct *tty)
 {
 	struct async_struct *info = (struct async_struct *)tty->driver_data;
-	int	ret;
-				
+
 	if (serial_paranoia_check(info, tty->device, "rs_write_room"))
 		return 0;
-	ret = SERIAL_XMIT_SIZE - info->xmit_cnt - 1;
-	if (ret < 0)
-		ret = 0;
-	return ret;
+	return CIRC_SPACE(info->xmit.head, info->xmit.tail, SERIAL_XMIT_SIZE);
 }
 
 static int rs_chars_in_buffer(struct tty_struct *tty)
@@ -1523,7 +1795,7 @@
 				
 	if (serial_paranoia_check(info, tty->device, "rs_chars_in_buffer"))
 		return 0;
-	return info->xmit_cnt;
+	return CIRC_CNT(info->xmit.head, info->xmit.tail, SERIAL_XMIT_SIZE);
 }
 
 static void rs_flush_buffer(struct tty_struct *tty)
@@ -1534,7 +1806,7 @@
 	if (serial_paranoia_check(info, tty->device, "rs_flush_buffer"))
 		return;
 	save_flags(flags); cli();
-	info->xmit_cnt = info->xmit_head = info->xmit_tail = 0;
+	info->xmit.head = info->xmit.tail = 0;
 	restore_flags(flags);
 	wake_up_interruptible(&tty->write_wait);
 	if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) &&
@@ -1639,6 +1911,10 @@
 	tmp.type = state->type;
 	tmp.line = state->line;
 	tmp.port = state->port;
+	if (HIGH_BITS_OFFSET)
+		tmp.port_high = state->port >> HIGH_BITS_OFFSET;
+	else
+		tmp.port_high = 0;
 	tmp.irq = state->irq;
 	tmp.flags = state->flags;
 	tmp.xmit_fifo_size = state->xmit_fifo_size;
@@ -1647,6 +1923,7 @@
 	tmp.closing_wait = state->closing_wait;
 	tmp.custom_divisor = state->custom_divisor;
 	tmp.hub6 = state->hub6;
+	tmp.io_type = state->io_type;
 	if (copy_to_user(retinfo,&tmp,sizeof(*retinfo)))
 		return -EFAULT;
 	return 0;
@@ -1659,14 +1936,19 @@
  	struct serial_state old_state, *state;
 	unsigned int		i,change_irq,change_port;
 	int 			retval = 0;
+	unsigned long		new_port;
 
 	if (copy_from_user(&new_serial,new_info,sizeof(new_serial)))
 		return -EFAULT;
 	state = info->state;
 	old_state = *state;
-  
+
+	new_port = new_serial.port;
+	if (HIGH_BITS_OFFSET)
+		new_port += new_serial.port_high << HIGH_BITS_OFFSET;
+
 	change_irq = new_serial.irq != state->irq;
-	change_port = (new_serial.port != state->port) ||
+	change_port = (new_port != ((int) state->port)) ||
 		(new_serial.hub6 != state->hub6);
   
 	if (!capable(CAP_SYS_ADMIN)) {
@@ -1688,7 +1970,7 @@
 
 	new_serial.irq = irq_cannonicalize(new_serial.irq);
 
-	if ((new_serial.irq >= NR_IRQS) || (new_serial.port > 0xffff) ||
+	if ((new_serial.irq >= NR_IRQS) || 
 	    (new_serial.baud_base < 9600)|| (new_serial.type < PORT_UNKNOWN) ||
 	    (new_serial.type > PORT_MAX) || (new_serial.type == PORT_CIRRUS) ||
 	    (new_serial.type == PORT_STARTECH)) {
@@ -1704,7 +1986,7 @@
 	if (new_serial.type) {
 		for (i = 0 ; i < NR_PORTS; i++)
 			if ((state != &rs_table[i]) &&
-			    (rs_table[i].port == new_serial.port) &&
+			    (rs_table[i].port == new_port) &&
 			    rs_table[i].type)
 				return -EADDRINUSE;
 	}
@@ -1723,14 +2005,17 @@
 	info->flags = ((state->flags & ~ASYNC_INTERNAL_FLAGS) |
 		       (info->flags & ASYNC_INTERNAL_FLAGS));
 	state->custom_divisor = new_serial.custom_divisor;
-	state->type = new_serial.type;
 	state->close_delay = new_serial.close_delay * HZ/100;
 	state->closing_wait = new_serial.closing_wait * HZ/100;
+#if (LINUX_VERSION_CODE > 0x20100)
 	info->tty->low_latency = (info->flags & ASYNC_LOW_LATENCY) ? 1 : 0;
+#endif
 	info->xmit_fifo_size = state->xmit_fifo_size =
 		new_serial.xmit_fifo_size;
 
-	release_region(state->port,8);
+	if ((state->type != PORT_UNKNOWN) && state->port)
+		release_region(state->port,8);
+	state->type = new_serial.type;
 	if (change_port || change_irq) {
 		/*
 		 * We need to shutdown the serial port at the old
@@ -1738,10 +2023,14 @@
 		 */
 		shutdown(info);
 		state->irq = new_serial.irq;
-		info->port = state->port = new_serial.port;
+		info->port = state->port = new_port;
 		info->hub6 = state->hub6 = new_serial.hub6;
+		if (info->hub6)
+			info->io_type = state->io_type = SERIAL_IO_HUB6;
+		else if (info->io_type == SERIAL_IO_HUB6)
+			info->io_type = state->io_type = SERIAL_IO_PORT;
 	}
-	if (state->type != PORT_UNKNOWN)
+	if ((state->type != PORT_UNKNOWN) && state->port)
 		request_region(state->port,8,"serial(set)");
 
 	
@@ -1752,6 +2041,7 @@
 		if (((old_state.flags & ASYNC_SPD_MASK) !=
 		     (state->flags & ASYNC_SPD_MASK)) ||
 		    (old_state.custom_divisor != state->custom_divisor)) {
+#if (LINUX_VERSION_CODE >= 131394) /* Linux 2.1.66 */
 			if ((state->flags & ASYNC_SPD_MASK) == ASYNC_SPD_HI)
 				info->tty->alt_speed = 57600;
 			if ((state->flags & ASYNC_SPD_MASK) == ASYNC_SPD_VHI)
@@ -1760,6 +2050,7 @@
 				info->tty->alt_speed = 230400;
 			if ((state->flags & ASYNC_SPD_MASK) == ASYNC_SPD_WARP)
 				info->tty->alt_speed = 460800;
+#endif
 			change_speed(info, 0);
 		}
 	} else
@@ -1788,7 +2079,22 @@
 	status = serial_in(info, UART_LSR);
 	restore_flags(flags);
 	result = ((status & UART_LSR_TEMT) ? TIOCSER_TEMT : 0);
-	return put_user(result,value);
+
+	/*
+	 * If we're about to load something into the transmit
+	 * register, we'll pretend the transmitter isn't empty to
+	 * avoid a race condition (depending on when the transmit
+	 * interrupt happens).
+	 */
+	if (info->x_char || 
+	    ((CIRC_CNT(info->xmit.head, info->xmit.tail,
+		       SERIAL_XMIT_SIZE) > 0) &&
+	     !info->tty->stopped && !info->tty->hw_stopped))
+		result &= TIOCSER_TEMT;
+
+	if (copy_to_user(value, &result, sizeof(int)))
+		return -EFAULT;
+	return 0;
 }
 
 
@@ -1812,19 +2118,21 @@
 		| ((status  & UART_MSR_RI) ? TIOCM_RNG : 0)
 		| ((status  & UART_MSR_DSR) ? TIOCM_DSR : 0)
 		| ((status  & UART_MSR_CTS) ? TIOCM_CTS : 0);
-	return put_user(result,value);
+
+	if (copy_to_user(value, &result, sizeof(int)))
+		return -EFAULT;
+	return 0;
 }
 
 static int set_modem_info(struct async_struct * info, unsigned int cmd,
 			  unsigned int *value)
 {
-	int error;
 	unsigned int arg;
 	unsigned long flags;
+
+	if (copy_from_user(&arg, value, sizeof(int)))
+		return -EFAULT;
 
-	error = get_user(arg, value);
-	if (error)
-		return error;
 	switch (cmd) {
 	case TIOCMBIS: 
 		if (arg & TIOCM_RTS)
@@ -1837,6 +2145,8 @@
 		if (arg & TIOCM_OUT2)
 			info->MCR |= UART_MCR_OUT2;
 #endif
+		if (arg & TIOCM_LOOP)
+			info->MCR |= UART_MCR_LOOP;
 		break;
 	case TIOCMBIC:
 		if (arg & TIOCM_RTS)
@@ -1849,6 +2159,8 @@
 		if (arg & TIOCM_OUT2)
 			info->MCR &= ~UART_MCR_OUT2;
 #endif
+		if (arg & TIOCM_LOOP)
+			info->MCR &= ~UART_MCR_LOOP;
 		break;
 	case TIOCMSET:
 		info->MCR = ((info->MCR & ~(UART_MCR_RTS |
@@ -1856,18 +2168,21 @@
 					    UART_MCR_OUT1 |
 					    UART_MCR_OUT2 |
 #endif
+					    UART_MCR_LOOP |
 					    UART_MCR_DTR))
 			     | ((arg & TIOCM_RTS) ? UART_MCR_RTS : 0)
 #ifdef TIOCM_OUT1
 			     | ((arg & TIOCM_OUT1) ? UART_MCR_OUT1 : 0)
 			     | ((arg & TIOCM_OUT2) ? UART_MCR_OUT2 : 0)
 #endif
+			     | ((arg & TIOCM_LOOP) ? UART_MCR_LOOP : 0)
 			     | ((arg & TIOCM_DTR) ? UART_MCR_DTR : 0));
 		break;
 	default:
 		return -EINVAL;
 	}
 	save_flags(flags); cli();
+	info->MCR |= ALPHA_KLUDGE_MCR; 		/* Don't ask */
 	serial_out(info, UART_MCR, info->MCR);
 	restore_flags(flags);
 	return 0;
@@ -1900,6 +2215,22 @@
 /*
  * rs_break() --- routine which turns the break handling on or off
  */
+#if (LINUX_VERSION_CODE < 131394) /* Linux 2.1.66 */
+static void send_break(	struct async_struct * info, int duration)
+{
+	if (!CONFIGURED_SERIAL_PORT(info))
+		return;
+	current->state = TASK_INTERRUPTIBLE;
+	current->timeout = jiffies + duration;
+	cli();
+	info->LCR |= UART_LCR_SBC;
+	serial_out(info, UART_LCR, info->LCR);
+	schedule();
+	info->LCR &= ~UART_LCR_SBC;
+	serial_out(info, UART_LCR, info->LCR);
+	sti();
+}
+#else
 static void rs_break(struct tty_struct *tty, int break_state)
 {
 	struct async_struct * info = (struct async_struct *)tty->driver_data;
@@ -1908,17 +2239,17 @@
 	if (serial_paranoia_check(info, tty->device, "rs_break"))
 		return;
 
-	if (!info->port)
+	if (!CONFIGURED_SERIAL_PORT(info))
 		return;
 	save_flags(flags); cli();
 	if (break_state == -1)
-		serial_out(info, UART_LCR,
-			   serial_inp(info, UART_LCR) | UART_LCR_SBC);
+		info->LCR |= UART_LCR_SBC;
 	else
-		serial_out(info, UART_LCR,
-			   serial_inp(info, UART_LCR) & ~UART_LCR_SBC);
+		info->LCR &= ~UART_LCR_SBC;
+	serial_out(info, UART_LCR, info->LCR);
 	restore_flags(flags);
 }
+#endif
 
 #ifdef CONFIG_SERIAL_MULTIPORT
 static int get_multiport_struct(struct async_struct * info,
@@ -2017,14 +2348,14 @@
 	
 	if (IRQ_ports[state->irq]->next_port &&
 	    (was_multi != now_multi)) {
-		free_irq(state->irq, NULL);
+		free_irq(state->irq, &IRQ_ports[state->irq]);
 		if (now_multi)
 			handler = rs_interrupt_multi;
 		else
 			handler = rs_interrupt;
 
-		retval = request_irq(state->irq, handler, IRQ_T(state),
-				     "serial", NULL);
+		retval = request_irq(state->irq, handler, SA_SHIRQ,
+				     "serial", &IRQ_ports[state->irq]);
 		if (retval) {
 			printk("Couldn't reallocate serial interrupt "
 			       "driver!!\n");
@@ -2037,11 +2368,13 @@
 static int rs_ioctl(struct tty_struct *tty, struct file * file,
 		    unsigned int cmd, unsigned long arg)
 {
-	int error;
 	struct async_struct * info = (struct async_struct *)tty->driver_data;
 	struct async_icount cprev, cnow;	/* kernel counter temps */
-	struct serial_icounter_struct *p_cuser;	/* user space */
+	struct serial_icounter_struct icount;
 	unsigned long flags;
+#if (LINUX_VERSION_CODE < 131394) /* Linux 2.1.66 */
+	int retval, tmp;
+#endif
 	
 	if (serial_paranoia_check(info, tty->device, "rs_ioctl"))
 		return -ENODEV;
@@ -2054,6 +2387,45 @@
 	}
 	
 	switch (cmd) {
+#if (LINUX_VERSION_CODE < 131394) /* Linux 2.1.66 */
+		case TCSBRK:	/* SVID version: non-zero arg --> no break */
+			retval = tty_check_change(tty);
+			if (retval)
+				return retval;
+			tty_wait_until_sent(tty, 0);
+			if (signal_pending(current))
+				return -EINTR;
+			if (!arg) {
+				send_break(info, HZ/4);	/* 1/4 second */
+				if (signal_pending(current))
+					return -EINTR;
+			}
+			return 0;
+		case TCSBRKP:	/* support for POSIX tcsendbreak() */
+			retval = tty_check_change(tty);
+			if (retval)
+				return retval;
+			tty_wait_until_sent(tty, 0);
+			if (signal_pending(current))
+				return -EINTR;
+			send_break(info, arg ? arg*(HZ/10) : HZ/4);
+			if (signal_pending(current))
+				return -EINTR;
+			return 0;
+		case TIOCGSOFTCAR:
+			tmp = C_CLOCAL(tty) ? 1 : 0;
+			if (copy_to_user((void *)arg, &tmp, sizeof(int)))
+				return -EFAULT;
+			return 0;
+		case TIOCSSOFTCAR:
+			if (copy_from_user(&tmp, (void *)arg, sizeof(int)))
+				return -EFAULT;
+
+			tty->termios->c_cflag =
+				((tty->termios->c_cflag & ~CLOCAL) |
+				 (tmp ? CLOCAL : 0));
+			return 0;
+#endif
 		case TIOCMGET:
 			return get_modem_info(info, (unsigned int *) arg);
 		case TIOCMBIS:
@@ -2129,31 +2501,21 @@
 			save_flags(flags); cli();
 			cnow = info->state->icount;
 			restore_flags(flags);
-			p_cuser = (struct serial_icounter_struct *) arg;
-			error = put_user(cnow.cts, &p_cuser->cts);
-			if (error) return error;
-			error = put_user(cnow.dsr, &p_cuser->dsr);
-			if (error) return error;
-			error = put_user(cnow.rng, &p_cuser->rng);
-			if (error) return error;
-			error = put_user(cnow.dcd, &p_cuser->dcd);
-			if (error) return error;
-			error = put_user(cnow.rx, &p_cuser->rx);
-			if (error) return error;
-			error = put_user(cnow.tx, &p_cuser->tx);
-			if (error) return error;
-			error = put_user(cnow.frame, &p_cuser->frame);
-			if (error) return error;
-			error = put_user(cnow.overrun, &p_cuser->overrun);
-			if (error) return error;
-			error = put_user(cnow.parity, &p_cuser->parity);
-			if (error) return error;
-			error = put_user(cnow.brk, &p_cuser->brk);
-			if (error) return error;
-			error = put_user(cnow.buf_overrun, &p_cuser->buf_overrun);
-			if (error) return error;			
+			icount.cts = cnow.cts;
+			icount.dsr = cnow.dsr;
+			icount.rng = cnow.rng;
+			icount.dcd = cnow.dcd;
+			icount.rx = cnow.rx;
+			icount.tx = cnow.tx;
+			icount.frame = cnow.frame;
+			icount.overrun = cnow.overrun;
+			icount.parity = cnow.parity;
+			icount.brk = cnow.brk;
+			icount.buf_overrun = cnow.buf_overrun;
+			
+			if (copy_to_user((void *)arg, &icount, sizeof(icount)))
+				return -EFAULT;
 			return 0;
-
 		case TIOCSERGWILD:
 		case TIOCSERSWILD:
 			/* "setserial -W" is called in Debian boot */
@@ -2278,6 +2640,7 @@
 		return;
 	}
 	info->flags |= ASYNC_CLOSING;
+	restore_flags(flags);
 	/*
 	 * Save the termios structure, since this port may have
 	 * separate termios for callout and dialin.
@@ -2320,7 +2683,7 @@
 	info->tty = 0;
 	if (info->blocked_open) {
 		if (info->close_delay) {
-			current->state = TASK_INTERRUPTIBLE;
+			set_current_state(TASK_INTERRUPTIBLE);
 			schedule_timeout(info->close_delay);
 		}
 		wake_up_interruptible(&info->open_wait);
@@ -2329,7 +2692,6 @@
 			 ASYNC_CLOSING);
 	wake_up_interruptible(&info->close_wait);
 	MOD_DEC_USE_COUNT;
-	restore_flags(flags);
 }
 
 /*
@@ -2363,8 +2725,8 @@
 	char_time = char_time / 5;
 	if (char_time == 0)
 		char_time = 1;
-	if (timeout)
-	  char_time = MIN(char_time, timeout);
+	if (timeout && timeout < char_time)
+		char_time = timeout;
 	/*
 	 * If the transmitter hasn't cleared in twice the approximate
 	 * amount of time to send the entire FIFO, it probably won't
@@ -2384,15 +2746,14 @@
 #ifdef SERIAL_DEBUG_RS_WAIT_UNTIL_SENT
 		printk("lsr = %d (jiff=%lu)...", lsr, jiffies);
 #endif
-		current->state = TASK_INTERRUPTIBLE;
-		current->counter = 0;	/* make us low-priority */
+		set_current_state(TASK_INTERRUPTIBLE);
 		schedule_timeout(char_time);
 		if (signal_pending(current))
 			break;
 		if (timeout && time_after(jiffies, orig_jiffies + timeout))
 			break;
 	}
-	current->state = TASK_RUNNING;
+	set_current_state(TASK_RUNNING);
 #ifdef SERIAL_DEBUG_RS_WAIT_UNTIL_SENT
 	printk("lsr = %d (jiff=%lu)...done\n", lsr, jiffies);
 #endif
@@ -2412,6 +2773,8 @@
 	state = info->state;
 	
 	rs_flush_buffer(tty);
+	if (info->flags & ASYNC_CLOSING)
+		return;
 	shutdown(info);
 	info->event = 0;
 	state->count = 0;
@@ -2428,7 +2791,7 @@
 static int block_til_ready(struct tty_struct *tty, struct file * filp,
 			   struct async_struct *info)
 {
-	struct wait_queue wait = { current, NULL };
+	DECLARE_WAITQUEUE(wait, current);
 	struct serial_state *state = info->state;
 	int		retval;
 	int		do_clocal = 0, extra_count = 0;
@@ -2517,7 +2880,7 @@
 				   serial_inp(info, UART_MCR) |
 				   (UART_MCR_DTR | UART_MCR_RTS));
 		restore_flags(flags);
-		current->state = TASK_INTERRUPTIBLE;
+		set_current_state(TASK_INTERRUPTIBLE);
 		if (tty_hung_up_p(filp) ||
 		    !(info->flags & ASYNC_INITIALIZED)) {
 #ifdef SERIAL_DO_RESTART
@@ -2545,7 +2908,7 @@
 #endif
 		schedule();
 	}
-	current->state = TASK_RUNNING;
+	set_current_state(TASK_RUNNING);
 	remove_wait_queue(&info->open_wait, &wait);
 	if (extra_count)
 		state->count++;
@@ -2577,9 +2940,15 @@
 		return -ENOMEM;
 	}
 	memset(info, 0, sizeof(struct async_struct));
+	init_waitqueue_head(&info->open_wait);
+	init_waitqueue_head(&info->close_wait);
+	init_waitqueue_head(&info->delta_msr_wait);
 	info->magic = SERIAL_MAGIC;
 	info->port = sstate->port;
 	info->flags = sstate->flags;
+	info->io_type = sstate->io_type;
+	info->iomem_base = sstate->iomem_base;
+	info->iomem_reg_shift = sstate->iomem_reg_shift;
 	info->xmit_fifo_size = sstate->xmit_fifo_size;
 	info->line = line;
 	info->tqueue.routine = do_softint;
@@ -2619,21 +2988,20 @@
 	}
 	tty->driver_data = info;
 	info->tty = tty;
-	if (serial_paranoia_check(info, tty->device, "rs_open")) {
-		/* MOD_DEC_USE_COUNT; "info->tty" will cause this */
+	if (serial_paranoia_check(info, tty->device, "rs_open"))
 		return -ENODEV;
-	}
 
 #ifdef SERIAL_DEBUG_OPEN
 	printk("rs_open %s%d, count = %d\n", tty->driver.name, info->line,
 	       info->state->count);
 #endif
+#if (LINUX_VERSION_CODE > 0x20100)
 	info->tty->low_latency = (info->flags & ASYNC_LOW_LATENCY) ? 1 : 0;
+#endif
 
 	if (!tmp_buf) {
-		page = get_free_page(GFP_KERNEL);
+		page = get_zeroed_page(GFP_KERNEL);
 		if (!page) {
-			/* MOD_DEC_USE_COUNT; "info->tty" will cause this? */
 			return -ENOMEM;
 		}
 		if (tmp_buf)
@@ -2649,7 +3017,6 @@
 	    (info->flags & ASYNC_CLOSING)) {
 		if (info->flags & ASYNC_CLOSING)
 			interruptible_sleep_on(&info->close_wait);
-		/* MOD_DEC_USE_COUNT; "info->tty" will cause this? */
 #ifdef SERIAL_DO_RESTART
 		return ((info->flags & ASYNC_HUP_NOTIFY) ?
 			-EAGAIN : -ERESTARTSYS);
@@ -2663,13 +3030,11 @@
 	 */
 	retval = startup(info);
 	if (retval) {
-		/* MOD_DEC_USE_COUNT; "info->tty" will cause this? */
 		return retval;
 	}
 
 	retval = block_til_ready(tty, filp, info);
 	if (retval) {
-		/* MOD_DEC_USE_COUNT; "info->tty" will cause this? */
 #ifdef SERIAL_DEBUG_OPEN
 		printk("rs_open returning after block_til_ready with %d\n",
 		       retval);
@@ -2712,7 +3077,7 @@
 	int	ret;
 	unsigned long flags;
 
-	ret = sprintf(buf, "%d: uart:%s port:%X irq:%d",
+	ret = sprintf(buf, "%d: uart:%s port:%lX irq:%d",
 		      state->line, uart_config[state->type].name, 
 		      state->port, state->irq);
 
@@ -2735,9 +3100,9 @@
 	}
 	save_flags(flags); cli();
 	status = serial_in(info, UART_MSR);
-	control = info ? info->MCR : serial_in(info, UART_MCR);
+	control = info != &scr_info ? info->MCR : serial_in(info, UART_MCR);
 	restore_flags(flags); 
-	
+
 	stat_buf[0] = 0;
 	stat_buf[1] = 0;
 	if (control & UART_MCR_RTS)
@@ -2786,8 +3151,9 @@
 	int i, len = 0, l;
 	off_t	begin = 0;
 
-	len += sprintf(page, "serinfo:1.0 driver:%s\n", serial_version);
-	for (i = 0; i < NR_PORTS && len < 3900; i++) {
+	len += sprintf(page, "serinfo:1.0 driver:%s%s revision:%s\n",
+		       serial_version, LOCAL_VERSTRING, serial_revdate);
+	for (i = 0; i < NR_PORTS && len < 4000; i++) {
 		l = line_info(page + len, &rs_table[i]);
 		len += l;
 		if (len+begin > off+count)
@@ -2801,7 +3167,7 @@
 done:
 	if (off >= len+begin)
 		return 0;
-	*start = page + (begin-off);
+	*start = page + (off-begin);
 	return ((count < begin+len-off) ? count : begin+len-off);
 }
 
@@ -2818,37 +3184,49 @@
  * number, and identifies which options were configured into this
  * driver.
  */
-static _INLINE_ void show_serial_version(void)
-{
- 	printk(KERN_INFO "%s version %s with", serial_name, serial_version);
+static char serial_options[] __initdata =
 #ifdef CONFIG_HUB6
-	printk(" HUB-6");
+       " HUB-6"
 #define SERIAL_OPT
 #endif
 #ifdef CONFIG_SERIAL_MANY_PORTS
-	printk(" MANY_PORTS");
+       " MANY_PORTS"
 #define SERIAL_OPT
 #endif
 #ifdef CONFIG_SERIAL_MULTIPORT
-	printk(" MULTIPORT");
+       " MULTIPORT"
 #define SERIAL_OPT
 #endif
 #ifdef CONFIG_SERIAL_SHARE_IRQ
-	printk(" SHARE_IRQ");
+       " SHARE_IRQ"
 #define SERIAL_OPT
 #endif
 #ifdef CONFIG_SERIAL_DETECT_IRQ
-	printk(" DETECT_IRQ");
+       " DETECT_IRQ"
+#define SERIAL_OPT
+#endif
+#ifdef ENABLE_SERIAL_PCI
+       " SERIAL_PCI"
+#define SERIAL_OPT
+#endif
+#ifdef ENABLE_SERIAL_PNP
+       " ISAPNP"
 #define SERIAL_OPT
 #endif
 #ifdef SERIAL_OPT
-	printk(" enabled\n");
+       " enabled\n";
 #else
-	printk(" no serial options enabled\n");
+       " no serial options enabled\n";
 #endif
 #undef SERIAL_OPT
-}
 
+static _INLINE_ void show_serial_version(void)
+{
+ 	printk(KERN_INFO "%s version %s%s (%s) with%s", serial_name,
+	       serial_version, LOCAL_VERSTRING, serial_revdate,
+	       serial_options);
+}
+
 /*
  * This routine detect the IRQ of a serial port by clearing OUT2 when
  * no UART interrupt are requested (IER = 0) (*GPL*). This seems to work at
@@ -2875,11 +3253,15 @@
 	}
 #endif
 	scr_info.magic = SERIAL_MAGIC;
+	scr_info.state = state;
 	scr_info.port = state->port;
 	scr_info.flags = state->flags;
 #ifdef CONFIG_HUB6
 	scr_info.hub6 = state->hub6;
 #endif
+	scr_info.io_type = state->io_type;
+	scr_info.iomem_base = state->iomem_base;
+	scr_info.iomem_reg_shift = state->iomem_reg_shift;
 
 	/* forget possible initially masked and pending IRQ */
 	probe_irq_off(probe_irq_on());
@@ -2916,53 +3298,197 @@
 }
 
 /*
+ * This is a quickie test to see how big the FIFO is.
+ * It doesn't work at all the time, more's the pity.
+ */
+static int size_fifo(struct async_struct *info)
+{
+	unsigned char old_fcr, old_mcr, old_dll, old_dlm;
+	int count;
+
+	old_fcr = serial_inp(info, UART_FCR);
+	old_mcr = serial_inp(info, UART_MCR);
+	serial_outp(info, UART_FCR, UART_FCR_ENABLE_FIFO |
+		    UART_FCR_CLEAR_RCVR | UART_FCR_CLEAR_XMIT);
+	serial_outp(info, UART_MCR, UART_MCR_LOOP);
+	serial_outp(info, UART_LCR, UART_LCR_DLAB);
+	old_dll = serial_inp(info, UART_DLL);
+	old_dlm = serial_inp(info, UART_DLM);
+	serial_outp(info, UART_DLL, 0x01);
+	serial_outp(info, UART_DLM, 0x00);
+	serial_outp(info, UART_LCR, 0x03);
+	for (count = 0; count < 256; count++)
+		serial_outp(info, UART_TX, count);
+	mdelay(20);
+	for (count = 0; (serial_inp(info, UART_LSR) & UART_LSR_DR) &&
+	     (count < 256); count++)
+		serial_inp(info, UART_RX);
+	serial_outp(info, UART_FCR, old_fcr);
+	serial_outp(info, UART_MCR, old_mcr);
+	serial_outp(info, UART_LCR, UART_LCR_DLAB);
+	serial_outp(info, UART_DLL, old_dll);
+	serial_outp(info, UART_DLM, old_dlm);
+
+	return count;
+}
+
+/*
+ * This is a helper routine to autodetect StarTech/Exar/Oxsemi UART's.
+ * When this function is called we know it is at least a StarTech
+ * 16650 V2, but it might be one of several StarTech UARTs, or one of
+ * its clones.  (We treat the broken original StarTech 16650 V1 as a
+ * 16550, and why not?  Startech doesn't seem to even acknowledge its
+ * existence.)
+ * 
+ * What evil have men's minds wrought...
+ */
+static void autoconfig_startech_uarts(struct async_struct *info,
+				      struct serial_state *state,
+				      unsigned long flags)
+{
+	unsigned char scratch, scratch2, scratch3;
+
+	/*
+	 * First we check to see if it's an Oxford Semiconductor UART.
+	 *
+	 * If we have to do this here because some non-National
+	 * Semiconductor clone chips lock up if you try writing to the
+	 * LSR register (which serial_icr_read does)
+	 */
+	if (state->type == PORT_16550A) {
+		/*
+		 * EFR [4] must be set else this test fails
+		 *
+		 * This shouldn't be necessary, but Mike Hudson
+		 * (Exoray@isys.ca) claims that it's needed for 952
+		 * dual UART's (which are not recommended for new designs).
+		 */
+		serial_out(info, UART_LCR, 0xBF);
+		serial_out(info, UART_EFR, 0x10);
+		serial_out(info, UART_LCR, 0x00);
+		/* Check for Oxford Semiconductor 16C950 */
+		scratch = serial_icr_read(info, UART_ID1);
+		scratch2 = serial_icr_read(info, UART_ID2);
+		scratch3 = serial_icr_read(info, UART_ID3);
+		
+		if (scratch == 0x16 && scratch2 == 0xC9 &&
+		    (scratch3 == 0x50 || scratch3 == 0x52 ||
+		     scratch3 == 0x54)) {
+			state->type = PORT_16C950;
+			state->revision = serial_icr_read(info, UART_REV) |
+				(scratch3 << 8);
+			return;
+		}
+	}
+	
+	/*
+	 * We check for a XR16C850 by setting DLL and DLM to 0, and
+	 * then reading back DLL and DLM.  If DLM reads back 0x10,
+	 * then the UART is a XR16C850 and the DLL contains the chip
+	 * revision.  If DLM reads back 0x14, then the UART is a
+	 * XR16C854.
+	 * 
+	 */
+	serial_outp(info, UART_LCR, UART_LCR_DLAB);
+	serial_outp(info, UART_DLL, 0);
+	serial_outp(info, UART_DLM, 0);
+	state->revision = serial_inp(info, UART_DLL);
+	scratch = serial_inp(info, UART_DLM);
+	serial_outp(info, UART_LCR, 0);
+	if (scratch == 0x10 || scratch == 0x14) {
+		state->type = PORT_16850;
+		return;
+	}
+
+	/*
+	 * We distinguish between the '654 and the '650 by counting
+	 * how many bytes are in the FIFO.  I'm using this for now,
+	 * since that's the technique that was sent to me in the
+	 * serial driver update, but I'm not convinced this works.
+	 * I've had problems doing this in the past.  -TYT
+	 */
+	if (size_fifo(info) == 64)
+		state->type = PORT_16654;
+	else
+		state->type = PORT_16650V2;
+}
+
+/*
  * This routine is called by rs_init() to initialize a specific serial
  * port.  It determines what type of UART chip this serial port is
  * using: 8250, 16450, 16550, 16550A.  The important question is
- * whether or not this UART is a 16550A, since this will determine
- * whether or not we can use its FIFO features.
+ * whether or not this UART is a 16550A or not, since this will
+ * determine whether or not we can use its FIFO features or not.
  */
 static void autoconfig(struct serial_state * state)
 {
-	unsigned char status1, status2, scratch, scratch2;
+	unsigned char status1, status2, scratch, scratch2, scratch3;
+	unsigned char save_lcr, save_mcr;
 	struct async_struct *info, scr_info;
 	unsigned long flags;
 
 	state->type = PORT_UNKNOWN;
+
+#ifdef SERIAL_DEBUG_AUTOCONF
+	printk("Testing ttyS%d (0x%04lx, 0x%04x)...\n", state->line,
+	       state->port, (unsigned) state->iomem_base);
+#endif
 	
-	if (!state->port)
+	if (!CONFIGURED_SERIAL_PORT(state))
 		return;
 		
 	info = &scr_info;	/* This is just for serial_{in,out} */
 
 	info->magic = SERIAL_MAGIC;
+	info->state = state;
 	info->port = state->port;
 	info->flags = state->flags;
 #ifdef CONFIG_HUB6
 	info->hub6 = state->hub6;
 #endif
+	info->io_type = state->io_type;
+	info->iomem_base = state->iomem_base;
+	info->iomem_reg_shift = state->iomem_reg_shift;
 
 	save_flags(flags); cli();
 	
-	/*
-	 * Do a simple existence test first; if we fail this, there's
-	 * no point trying anything else.
-	 *
-	 * 0x80 is used as a nonsense port to prevent against false
-	 * positives due to ISA bus float.  The assumption is that
-	 * 0x80 is a non-existent port; which should be safe since
-	 * include/asm/io.h also makes this assumption.
-	 */
-	scratch = serial_inp(info, UART_IER);
-	serial_outp(info, UART_IER, 0);
-	outb(0xff, 0x080);
-	scratch2 = serial_inp(info, UART_IER);
-	serial_outp(info, UART_IER, scratch);
-	if (scratch2) {
-		restore_flags(flags);
-		return;		/* We failed; there's nothing here */
+	if (!(state->flags & ASYNC_BUGGY_UART) &&
+	    !state->iomem_base) {
+		/*
+		 * Do a simple existence test first; if we fail this,
+		 * there's no point trying anything else.
+		 * 
+		 * 0x80 is used as a nonsense port to prevent against
+		 * false positives due to ISA bus float.  The
+		 * assumption is that 0x80 is a non-existent port;
+		 * which should be safe since include/asm/io.h also
+		 * makes this assumption.
+		 */
+		scratch = serial_inp(info, UART_IER);
+		serial_outp(info, UART_IER, 0);
+#ifdef __i386__
+		outb(0xff, 0x080);
+#endif
+		scratch2 = serial_inp(info, UART_IER);
+		serial_outp(info, UART_IER, 0x0F);
+#ifdef __i386__
+		outb(0, 0x080);
+#endif
+		scratch3 = serial_inp(info, UART_IER);
+		serial_outp(info, UART_IER, scratch);
+		if (scratch2 || scratch3 != 0x0F) {
+#ifdef SERIAL_DEBUG_AUTOCONF
+			printk("serial: ttyS%d: simple autoconfig failed\n",
+			       state->line);
+#endif
+			restore_flags(flags);
+			return;		/* We failed; there's nothing here */
+		}
 	}
 
+	save_mcr = serial_in(info, UART_MCR);
+	save_lcr = serial_in(info, UART_LCR);
+
 	/* 
 	 * Check to see if a UART is really there.  Certain broken
 	 * internal modems based on the Rockwell chipset fail this
@@ -2973,18 +3499,18 @@
 	 * that conflicts with COM 1-4 --- we hope!
 	 */
 	if (!(state->flags & ASYNC_SKIP_TEST)) {
-		scratch = serial_inp(info, UART_MCR);
-		serial_outp(info, UART_MCR, UART_MCR_LOOP | scratch);
 		serial_outp(info, UART_MCR, UART_MCR_LOOP | 0x0A);
 		status1 = serial_inp(info, UART_MSR) & 0xF0;
-		serial_outp(info, UART_MCR, scratch);
+		serial_outp(info, UART_MCR, save_mcr);
 		if (status1 != 0x90) {
+#ifdef SERIAL_DEBUG_AUTOCONF
+			printk("serial: ttyS%d: no UART loopback failed\n",
+			       state->line);
+#endif
 			restore_flags(flags);
 			return;
 		}
-	} 
-	
-	scratch2 = serial_in(info, UART_LCR);
+	}
 	serial_outp(info, UART_LCR, 0xBF); /* set up for StarTech test */
 	serial_outp(info, UART_EFR, 0);	/* EFR is the same as FCR */
 	serial_outp(info, UART_LCR, 0);
@@ -3006,30 +3532,39 @@
 	}
 	if (state->type == PORT_16550A) {
 		/* Check for Startech UART's */
-		serial_outp(info, UART_LCR, scratch2 | UART_LCR_DLAB);
+		serial_outp(info, UART_LCR, UART_LCR_DLAB);
 		if (serial_in(info, UART_EFR) == 0) {
 			state->type = PORT_16650;
 		} else {
 			serial_outp(info, UART_LCR, 0xBF);
 			if (serial_in(info, UART_EFR) == 0)
-				state->type = PORT_16650V2;
+				autoconfig_startech_uarts(info, state, flags);
 		}
 	}
 	if (state->type == PORT_16550A) {
 		/* Check for TI 16750 */
-		serial_outp(info, UART_LCR, scratch2 | UART_LCR_DLAB);
+		serial_outp(info, UART_LCR, save_lcr | UART_LCR_DLAB);
 		serial_outp(info, UART_FCR,
 			    UART_FCR_ENABLE_FIFO | UART_FCR7_64BYTE);
 		scratch = serial_in(info, UART_IIR) >> 5;
 		if (scratch == 7) {
+			/*
+			 * If this is a 16750, and not a cheap UART
+			 * clone, then it should only go into 64 byte
+			 * mode if the UART_FCR7_64BYTE bit was set
+			 * while UART_LCR_DLAB was latched.
+			 */
+ 			serial_outp(info, UART_FCR, UART_FCR_ENABLE_FIFO);
 			serial_outp(info, UART_LCR, 0);
+			serial_outp(info, UART_FCR,
+				    UART_FCR_ENABLE_FIFO | UART_FCR7_64BYTE);
 			scratch = serial_in(info, UART_IIR) >> 5;
 			if (scratch == 6)
 				state->type = PORT_16750;
 		}
 		serial_outp(info, UART_FCR, UART_FCR_ENABLE_FIFO);
 	}
-	serial_outp(info, UART_LCR, scratch2);
+	serial_outp(info, UART_LCR, save_lcr);
 	if (state->type == PORT_16450) {
 		scratch = serial_in(info, UART_SCR);
 		serial_outp(info, UART_SCR, 0xa5);
@@ -3048,22 +3583,17 @@
 		return;
 	}
 
-	request_region(info->port,8,"serial(auto)");
+	if (info->port)
+		request_region(info->port,8,"serial(auto)");
 
 	/*
 	 * Reset the UART.
-	 */
-#if defined(__alpha__) && !defined(CONFIG_PCI)
-	/*
-	 * I wonder what DEC did to the OUT1 and OUT2 lines?
-	 * clearing them results in endless interrupts.
 	 */
-	serial_outp(info, UART_MCR, 0x0c);
-#else
-	serial_outp(info, UART_MCR, 0x00);
-#endif
-	serial_outp(info, UART_FCR, (UART_FCR_CLEAR_RCVR |
+	serial_outp(info, UART_MCR, save_mcr);
+	serial_outp(info, UART_FCR, (UART_FCR_ENABLE_FIFO |
+				     UART_FCR_CLEAR_RCVR |
 				     UART_FCR_CLEAR_XMIT));
+	serial_outp(info, UART_FCR, 0);
 	(void)serial_in(info, UART_RX);
 	serial_outp(info, UART_IER, 0);
 	
@@ -3073,25 +3603,1009 @@
 int register_serial(struct serial_struct *req);
 void unregister_serial(int line);
 
+#if (LINUX_VERSION_CODE > 0x20100)
 EXPORT_SYMBOL(register_serial);
 EXPORT_SYMBOL(unregister_serial);
+#else
+static struct symbol_table serial_syms = {
+#include <linux/symtab_begin.h>
+	X(register_serial),
+	X(unregister_serial),
+#include <linux/symtab_end.h>
+};
+#endif
+
+
+#if defined(ENABLE_SERIAL_PCI) || defined(ENABLE_SERIAL_PNP) 
+
+static void __init printk_pnp_dev_id(unsigned short vendor,
+				     unsigned short device)
+{
+	printk("%c%c%c%x%x%x%x",
+	       'A' + ((vendor >> 2) & 0x3f) - 1,
+	       'A' + (((vendor & 3) << 3) | ((vendor >> 13) & 7)) - 1,
+	       'A' + ((vendor >> 8) & 0x1f) - 1,
+	       (device >> 4) & 0x0f,
+	       device & 0x0f,
+	       (device >> 12) & 0x0f,
+	       (device >> 8) & 0x0f);
+}
+
+static _INLINE_ int get_pci_port(struct pci_dev *dev,
+				  struct pci_board *board,
+				  struct serial_struct *state,
+				  int idx)
+{
+	unsigned long port;
+	int base_idx;
+	int max_port;
+
+	base_idx = SPCI_FL_GET_BASE(board->flags);
+	if (board->flags & SPCI_FL_BASE_TABLE)
+		base_idx += idx;
+
+	if (board->flags & SPCI_FL_REGION_SZ_CAP) {
+		max_port = pci_resource_len(dev, base_idx) / 8;
+		if (idx >= max_port)
+			return 1;
+	}
+			
+	port = pci_resource_start(dev, base_idx) + board->first_uart_offset;
+
+	if ((board->flags & SPCI_FL_BASE_TABLE) == 0)
+		port += idx * (board->uart_offset ? board->uart_offset : 8);
+
+	if (IS_PCI_REGION_IOPORT(dev, base_idx)) {
+		state->port = port;
+		if (HIGH_BITS_OFFSET)
+			state->port_high = port >> HIGH_BITS_OFFSET;
+		else
+			state->port_high = 0;
+		return 0;
+	}
+	state->io_type = SERIAL_IO_MEM;
+	state->iomem_base = ioremap(port, board->uart_offset);
+	state->iomem_reg_shift = board->reg_shift;
+	state->port = 0;
+	return 0;
+}
+
+static _INLINE_ int get_pci_irq(struct pci_dev *dev,
+				struct pci_board *board,
+				int idx)
+{
+	int base_idx;
+
+	if ((board->flags & SPCI_FL_IRQRESOURCE) == 0)
+		return dev->irq;
+
+	base_idx = SPCI_FL_GET_IRQBASE(board->flags);
+	if (board->flags & SPCI_FL_IRQ_TABLE)
+		base_idx += idx;
+	
+	return PCI_IRQ_RESOURCE(dev, base_idx);
+}
+
+/*
+ * Common enabler code shared by both PCI and ISAPNP probes
+ */
+static void __init start_pci_pnp_board(struct pci_dev *dev,
+				       struct pci_board *board)
+{
+	int k, line;
+	struct serial_struct fake_state;
+	int base_baud;
+
+       if (PREPARE_FUNC(dev) && (PREPARE_FUNC(dev))(dev) < 0) {
+	       printk("SERIAL: PNP device '");
+	       printk_pnp_dev_id(board->vendor, board->device);
+	       printk("' prepare failed\n");
+	       return;
+       }
+
+       if (ACTIVATE_FUNC(dev) && (ACTIVATE_FUNC(dev))(dev) < 0) {
+	       printk("SERIAL: PNP device '");
+	       printk_pnp_dev_id(board->vendor, board->device);
+	       printk("' activate failed\n");
+	       return;
+       }
+
+	/*
+	 * Run the initialization function, if any
+	 */
+	if (board->init_fn && ((board->init_fn)(dev, board, 1) != 0))
+		return;
+
+#ifdef MODULE
+	/*
+	 * Register the serial board in the array if we need to
+	 * shutdown the board on a module unload.
+	 */
+	if (DEACTIVATE_FUNC(dev) || board->init_fn) {
+		if (serial_pci_board_idx >= NR_PCI_BOARDS)
+			return;
+		serial_pci_board[serial_pci_board_idx].board = *board;
+		serial_pci_board[serial_pci_board_idx].dev = dev;
+		serial_pci_board_idx++;
+	}
+#endif
+
+	base_baud = board->base_baud;
+	if (!base_baud)
+		base_baud = BASE_BAUD;
+	memset(&fake_state, 0, sizeof(fake_state));
+
+	for (k=0; k < board->num_ports; k++) {
+		fake_state.irq = get_pci_irq(dev, board, k);
+		if (get_pci_port(dev, board, &fake_state, k))
+			break;
+		fake_state.flags = ASYNC_SKIP_TEST;
+#ifdef SERIAL_DEBUG_PCI
+		printk("Setup PCI/PNP port: port %x, irq %d, type %d\n",
+		       fake_state.port, fake_state.irq, fake_state.io_type);
+#endif
+		line = register_serial(&fake_state);
+		if (line < 0)
+			break;
+		rs_table[line].baud_base = base_baud;
+	}
+}
+#endif	/* ENABLE_SERIAL_PCI || ENABLE_SERIAL_PNP */
+
+#ifdef ENABLE_SERIAL_PCI
+/*
+ * Some PCI serial cards using the PLX 9050 PCI interface chip require
+ * that the card interrupt be explicitly enabled or disabled.  This
+ * seems to be mainly needed on card using the PLX which also use I/O
+ * mapped memory.
+ */
+static int
+#ifndef MODULE
+__init
+#endif
+pci_plx9050_fn(struct pci_dev *dev, struct pci_board *board, int enable)
+{
+	u8 data, *p, irq_config;
+	int pci_config;
+
+	irq_config = 0x41;
+	pci_config = PCI_COMMAND_MEMORY;
+	if (dev->vendor == PCI_VENDOR_ID_PANACOM)
+		irq_config = 0x43;
+	if ((dev->vendor == PCI_VENDOR_ID_PLX) &&
+	    (dev->device == PCI_VENDOR_ID_PLX_ROMULUS)) {
+		/*
+		 * As the megawolf cards have the int pins active
+		 * high, and have 2 UART chips, both ints must be
+		 * enabled on the 9050. Also, the UARTS are set in
+		 * 16450 mode by default, so we have to enable the
+		 * 16C950 'enhanced' mode so that we can use the deep
+		 * FIFOs
+		 */
+		irq_config = 0x5b;
+		pci_config = PCI_COMMAND_MEMORY | PCI_COMMAND_IO;
+	}
+	
+	pci_read_config_byte(dev, PCI_COMMAND, &data);
+
+	if (enable)
+		pci_write_config_byte(dev, PCI_COMMAND,
+				      data | pci_config);
+	
+	/* enable/disable interrupts */
+	p = ioremap(pci_resource_start(dev, 0), 0x80);
+	writel(enable ? irq_config : 0x00, (unsigned long)p + 0x4c);
+	iounmap(p);
+
+	if (!enable)
+		pci_write_config_byte(dev, PCI_COMMAND,
+				      data & ~pci_config);
+	return 0;
+}
+
+
+/*
+ * SIIG serial cards have an PCI interface chip which also controls
+ * the UART clocking frequency. Each UART can be clocked independently
+ * (except cards equiped with 4 UARTs) and initial clocking settings
+ * are stored in the EEPROM chip. It can cause problems because this
+ * version of serial driver doesn't support differently clocked UART's
+ * on single PCI card. To prevent this, initialization functions set
+ * high frequency clocking for all UART's on given card. It is safe (I
+ * hope) because it doesn't touch EEPROM settings to prevent conflicts
+ * with other OSes (like M$ DOS).
+ *
+ *  SIIG support added by Andrey Panin <pazke@mail.tp.ru>, 10/1999
+ * 
+ * There is two family of SIIG serial cards with different PCI
+ * interface chip and different configuration methods:
+ *     - 10x cards have control registers in IO and/or memory space;
+ *     - 20x cards have control registers in standard PCI configuration space.
+ */
+
+#define PCI_DEVICE_ID_SIIG_1S_10x (PCI_DEVICE_ID_SIIG_1S_10x_550 & 0xfffc)
+#define PCI_DEVICE_ID_SIIG_2S_10x (PCI_DEVICE_ID_SIIG_2S_10x_550 & 0xfff8)
+
+static int
+#ifndef MODULE
+__init
+#endif
+pci_siig10x_fn(struct pci_dev *dev, struct pci_board *board, int enable)
+{
+       u16 data, *p;
+
+       if (!enable) return 0;
+
+       p = ioremap(pci_resource_start(dev, 0), 0x80);
+
+       switch (dev->device & 0xfff8) {
+               case PCI_DEVICE_ID_SIIG_1S_10x:         /* 1S */
+                       data = 0xffdf;
+                       break;
+               case PCI_DEVICE_ID_SIIG_2S_10x:         /* 2S, 2S1P */
+                       data = 0xf7ff;
+                       break;
+               default:                                /* 1S1P, 4S */
+                       data = 0xfffb;
+                       break;
+       }
+
+       writew(readw((unsigned long) p + 0x28) & data, (unsigned long) p + 0x28);
+       iounmap(p);
+       return 0;
+}
+
+#define PCI_DEVICE_ID_SIIG_2S_20x (PCI_DEVICE_ID_SIIG_2S_20x_550 & 0xfffc)
+#define PCI_DEVICE_ID_SIIG_2S1P_20x (PCI_DEVICE_ID_SIIG_2S1P_20x_550 & 0xfffc)
+
+static int
+#ifndef MODULE
+__init
+#endif
+pci_siig20x_fn(struct pci_dev *dev, struct pci_board *board, int enable)
+{
+       u8 data;
+
+       if (!enable) return 0;
+
+       /* Change clock frequency for the first UART. */
+       pci_read_config_byte(dev, 0x6f, &data);
+       pci_write_config_byte(dev, 0x6f, data & 0xef);
+
+       /* If this card has 2 UART, we have to do the same with second UART. */
+       if (((dev->device & 0xfffc) == PCI_DEVICE_ID_SIIG_2S_20x) ||
+           ((dev->device & 0xfffc) == PCI_DEVICE_ID_SIIG_2S1P_20x)) {
+               pci_read_config_byte(dev, 0x73, &data);
+               pci_write_config_byte(dev, 0x73, data & 0xef);
+       }
+       return 0;
+}
+
+/* Added for EKF Intel i960 serial boards */
+static int
+#ifndef MODULE
+__init
+#endif
+pci_inteli960ni_fn(struct pci_dev *dev,
+		   struct pci_board *board,
+		   int enable)
+{
+	unsigned long oldval;
+	
+	if (!(board->subdevice & 0x1000))
+		return(-1);
+
+	if (!enable) /* is there something to deinit? */
+		return(0);
+   
+#ifdef SERIAL_DEBUG_PCI
+	printk(KERN_DEBUG " Subsystem ID %lx, at Address: %lx\n",
+	       (unsigned long) board->subdevice, port);
+#endif
+	/* is firmware started? */
+	pci_read_config_dword(dev, 0x44, (void*) &oldval); 
+	if (oldval == 0x00001000L) { /* RESET value */ 
+		printk(KERN_DEBUG "Local i960 firmware missing");
+		return(-1); 
+	}
+	return(0);
+}
+
+
+/*
+ * This is the configuration table for all of the PCI serial boards
+ * which we support.
+ */
+static struct pci_board pci_boards[] __initdata = {
+	/*
+	 * Vendor ID, 	Device ID,
+	 * Subvendor ID,	Subdevice ID,
+	 * PCI Flags, Number of Ports, Base (Maximum) Baud Rate,
+	 * Offset to get to next UART's registers,
+	 * Register shift to use for memory-mapped I/O,
+	 * Initialization function, first UART offset
+	 */
+	{	PCI_VENDOR_ID_V3, PCI_DEVICE_ID_V3_V960,
+		PCI_SUBVENDOR_ID_CONNECT_TECH,
+		PCI_SUBDEVICE_ID_CONNECT_TECH_BH8_232,
+		SPCI_FL_BASE1, 8, 1382400 },
+	{	PCI_VENDOR_ID_V3, PCI_DEVICE_ID_V3_V960,
+		PCI_SUBVENDOR_ID_CONNECT_TECH,
+		PCI_SUBDEVICE_ID_CONNECT_TECH_BH4_232,
+		SPCI_FL_BASE1, 4, 1382400 },
+	{	PCI_VENDOR_ID_V3, PCI_DEVICE_ID_V3_V960,
+		PCI_SUBVENDOR_ID_CONNECT_TECH,
+		PCI_SUBDEVICE_ID_CONNECT_TECH_BH2_232,
+		SPCI_FL_BASE1, 2, 1382400 },
+	{	PCI_VENDOR_ID_V3, PCI_DEVICE_ID_V3_V960V2,
+		PCI_SUBVENDOR_ID_CONNECT_TECH,
+		PCI_SUBDEVICE_ID_CONNECT_TECH_BH8_232,
+		SPCI_FL_BASE1, 8, 1382400 },
+	{	PCI_VENDOR_ID_V3, PCI_DEVICE_ID_V3_V960V2,
+		PCI_SUBVENDOR_ID_CONNECT_TECH,
+		PCI_SUBDEVICE_ID_CONNECT_TECH_BH4_232,
+		SPCI_FL_BASE1, 4, 1382400 },
+	{	PCI_VENDOR_ID_V3, PCI_DEVICE_ID_V3_V960V2,
+		PCI_SUBVENDOR_ID_CONNECT_TECH,
+		PCI_SUBDEVICE_ID_CONNECT_TECH_BH2_232,
+		SPCI_FL_BASE1, 2, 1382400 },
+	{	PCI_VENDOR_ID_V3, PCI_DEVICE_ID_V3_V960,
+		PCI_SUBVENDOR_ID_CONNECT_TECH,
+		PCI_SUBDEVICE_ID_CONNECT_TECH_BH8_485,
+		SPCI_FL_BASE1, 8, 921600 },
+	{	PCI_VENDOR_ID_V3, PCI_DEVICE_ID_V3_V960,
+		PCI_SUBVENDOR_ID_CONNECT_TECH,
+		PCI_SUBDEVICE_ID_CONNECT_TECH_BH8_485_4_4,
+		SPCI_FL_BASE1, 8, 921600 },
+	{	PCI_VENDOR_ID_V3, PCI_DEVICE_ID_V3_V960,
+		PCI_SUBVENDOR_ID_CONNECT_TECH,
+		PCI_SUBDEVICE_ID_CONNECT_TECH_BH4_485,
+		SPCI_FL_BASE1, 4, 921600 },
+	{	PCI_VENDOR_ID_V3, PCI_DEVICE_ID_V3_V960,
+		PCI_SUBVENDOR_ID_CONNECT_TECH,
+		PCI_SUBDEVICE_ID_CONNECT_TECH_BH4_485_2_2,
+		SPCI_FL_BASE1, 4, 921600 },
+	{	PCI_VENDOR_ID_V3, PCI_DEVICE_ID_V3_V960,
+		PCI_SUBVENDOR_ID_CONNECT_TECH,
+		PCI_SUBDEVICE_ID_CONNECT_TECH_BH2_485,
+		SPCI_FL_BASE1, 2, 921600 },
+	{	PCI_VENDOR_ID_V3, PCI_DEVICE_ID_V3_V960V2,
+		PCI_SUBVENDOR_ID_CONNECT_TECH,
+		PCI_SUBDEVICE_ID_CONNECT_TECH_BH8_485,
+		SPCI_FL_BASE1, 8, 921600 },
+	{	PCI_VENDOR_ID_V3, PCI_DEVICE_ID_V3_V960V2,
+		PCI_SUBVENDOR_ID_CONNECT_TECH,
+		PCI_SUBDEVICE_ID_CONNECT_TECH_BH8_485_4_4,
+		SPCI_FL_BASE1, 8, 921600 },
+	{	PCI_VENDOR_ID_V3, PCI_DEVICE_ID_V3_V960V2,
+		PCI_SUBVENDOR_ID_CONNECT_TECH,
+		PCI_SUBDEVICE_ID_CONNECT_TECH_BH4_485,
+		SPCI_FL_BASE1, 4, 921600 },
+	{	PCI_VENDOR_ID_V3, PCI_DEVICE_ID_V3_V960V2,
+		PCI_SUBVENDOR_ID_CONNECT_TECH,
+		PCI_SUBDEVICE_ID_CONNECT_TECH_BH4_485_2_2,
+		SPCI_FL_BASE1, 4, 921600 },
+	{	PCI_VENDOR_ID_V3, PCI_DEVICE_ID_V3_V960V2,
+		PCI_SUBVENDOR_ID_CONNECT_TECH,
+		PCI_SUBDEVICE_ID_CONNECT_TECH_BH2_485,
+		SPCI_FL_BASE1, 2, 921600 },
+	{	PCI_VENDOR_ID_SEALEVEL, PCI_DEVICE_ID_SEALEVEL_U530,
+		PCI_ANY_ID, PCI_ANY_ID,
+		SPCI_FL_BASE2 | SPCI_FL_BASE_TABLE, 1, 115200 },
+	{	PCI_VENDOR_ID_SEALEVEL, PCI_DEVICE_ID_SEALEVEL_UCOMM2,
+		PCI_ANY_ID, PCI_ANY_ID,
+		SPCI_FL_BASE2 | SPCI_FL_BASE_TABLE, 2, 115200 },
+	{	PCI_VENDOR_ID_SEALEVEL, PCI_DEVICE_ID_SEALEVEL_UCOMM422,
+		PCI_ANY_ID, PCI_ANY_ID,
+		SPCI_FL_BASE2 | SPCI_FL_BASE_TABLE, 4, 115200 },
+	{	PCI_VENDOR_ID_SEALEVEL, PCI_DEVICE_ID_SEALEVEL_UCOMM232,
+		PCI_ANY_ID, PCI_ANY_ID,
+		SPCI_FL_BASE2 | SPCI_FL_BASE_TABLE, 2, 115200 },
+	{	PCI_VENDOR_ID_SEALEVEL, PCI_DEVICE_ID_SEALEVEL_COMM4,
+		PCI_ANY_ID, PCI_ANY_ID,
+		SPCI_FL_BASE2 | SPCI_FL_BASE_TABLE, 4, 115200 },
+	{	PCI_VENDOR_ID_SEALEVEL, PCI_DEVICE_ID_SEALEVEL_COMM8,
+		PCI_ANY_ID, PCI_ANY_ID,
+		SPCI_FL_BASE2, 8, 115200 },
+	{	PCI_VENDOR_ID_PLX, PCI_DEVICE_ID_PLX_GTEK_SERIAL2,
+		PCI_ANY_ID, PCI_ANY_ID,
+		SPCI_FL_BASE2 | SPCI_FL_BASE_TABLE, 2, 115200 },
+	{	PCI_VENDOR_ID_PLX, PCI_DEVICE_ID_PLX_SPCOM200,
+		PCI_ANY_ID, PCI_ANY_ID,
+		SPCI_FL_BASE2 | SPCI_FL_BASE_TABLE, 2, 921600 },
+	/* VScom SPCOM800, from sl@s.pl */
+	{	PCI_VENDOR_ID_PLX, PCI_DEVICE_ID_PLX_SPCOM800, 
+		PCI_ANY_ID, PCI_ANY_ID,
+		SPCI_FL_BASE2, 8, 921600 },
+	{	PCI_VENDOR_ID_PLX, PCI_DEVICE_ID_PLX_9050,
+		PCI_SUBVENDOR_ID_KEYSPAN,
+		PCI_SUBDEVICE_ID_KEYSPAN_SX2,
+		SPCI_FL_BASE2, 2, 921600, /* IOMEM */
+		0x400, 7, pci_plx9050_fn },
+	{	PCI_VENDOR_ID_PANACOM, PCI_DEVICE_ID_PANACOM_QUADMODEM,
+		PCI_ANY_ID, PCI_ANY_ID,
+		SPCI_FL_BASE2 | SPCI_FL_BASE_TABLE, 4, 921600,
+		0x400, 7, pci_plx9050_fn },
+	{	PCI_VENDOR_ID_PANACOM, PCI_DEVICE_ID_PANACOM_DUALMODEM,
+		PCI_ANY_ID, PCI_ANY_ID,
+		SPCI_FL_BASE2 | SPCI_FL_BASE_TABLE, 2, 921600,
+		0x400, 7, pci_plx9050_fn },
+	{	PCI_VENDOR_ID_PLX, PCI_DEVICE_ID_PLX_9050,
+		PCI_SUBVENDOR_ID_CHASE_PCIFAST,
+		PCI_SUBDEVICE_ID_CHASE_PCIFAST4,
+		SPCI_FL_BASE2, 4, 460800 },
+	{	PCI_VENDOR_ID_PLX, PCI_DEVICE_ID_PLX_9050,
+		PCI_SUBVENDOR_ID_CHASE_PCIFAST,
+		PCI_SUBDEVICE_ID_CHASE_PCIFAST8,
+		SPCI_FL_BASE2, 8, 460800 },
+	{	PCI_VENDOR_ID_PLX, PCI_DEVICE_ID_PLX_9050,
+		PCI_SUBVENDOR_ID_CHASE_PCIFAST,
+		PCI_SUBDEVICE_ID_CHASE_PCIFAST16,
+		SPCI_FL_BASE2, 16, 460800 },
+	{	PCI_VENDOR_ID_PLX, PCI_DEVICE_ID_PLX_9050,
+		PCI_SUBVENDOR_ID_CHASE_PCIFAST,
+		PCI_SUBDEVICE_ID_CHASE_PCIFAST16FMC,
+		SPCI_FL_BASE2, 16, 460800 },
+	{	PCI_VENDOR_ID_PLX, PCI_DEVICE_ID_PLX_9050,
+		PCI_SUBVENDOR_ID_CHASE_PCIRAS,
+		PCI_SUBDEVICE_ID_CHASE_PCIRAS4,
+		SPCI_FL_BASE2, 4, 460800 },
+	{	PCI_VENDOR_ID_PLX, PCI_DEVICE_ID_PLX_9050,
+		PCI_SUBVENDOR_ID_CHASE_PCIRAS,
+		PCI_SUBDEVICE_ID_CHASE_PCIRAS8,
+		SPCI_FL_BASE2, 8, 460800 },
+	/* Megawolf Romulus PCI Serial Card, from Mike Hudson */
+	/* (Exoray@isys.ca) */
+	{	PCI_VENDOR_ID_PLX, PCI_VENDOR_ID_PLX_ROMULUS,
+		0x10b5, 0x106a,
+		SPCI_FL_BASE2, 4, 921600,
+		0x20, 2, pci_plx9050_fn, 0x03 },
+	{	PCI_VENDOR_ID_QUATECH, PCI_DEVICE_ID_QUATECH_QSC100,
+		PCI_ANY_ID, PCI_ANY_ID,
+		SPCI_FL_BASE1, 4, 115200 },
+	{	PCI_VENDOR_ID_QUATECH, PCI_DEVICE_ID_QUATECH_DSC100,
+		PCI_ANY_ID, PCI_ANY_ID,
+		SPCI_FL_BASE1, 2, 115200 },
+	{	PCI_VENDOR_ID_QUATECH, PCI_DEVICE_ID_QUATECH_ESC100D,
+		PCI_ANY_ID, PCI_ANY_ID,
+		SPCI_FL_BASE1, 8, 115200 },
+	{	PCI_VENDOR_ID_QUATECH, PCI_DEVICE_ID_QUATECH_ESC100M,
+		PCI_ANY_ID, PCI_ANY_ID,
+		SPCI_FL_BASE1, 8, 115200 },
+	{	PCI_VENDOR_ID_SPECIALIX, PCI_DEVICE_ID_OXSEMI_16PCI954,
+		PCI_VENDOR_ID_SPECIALIX, PCI_SUBDEVICE_ID_SPECIALIX_SPEED4,
+		SPCI_FL_BASE0 , 4, 921600 },
+	{	PCI_VENDOR_ID_OXSEMI, PCI_DEVICE_ID_OXSEMI_16PCI954,
+		PCI_ANY_ID, PCI_ANY_ID,
+		SPCI_FL_BASE0 , 4, 115200 },
+	{	PCI_VENDOR_ID_OXSEMI, PCI_DEVICE_ID_OXSEMI_16PCI952,
+		PCI_ANY_ID, PCI_ANY_ID,
+		SPCI_FL_BASE0 , 2, 115200 },
+		/* This board uses the size of PCI Base region 0 to
+		 * signal now many ports are available */
+	{	PCI_VENDOR_ID_OXSEMI, PCI_DEVICE_ID_OXSEMI_16PCI95N,
+		PCI_ANY_ID, PCI_ANY_ID,
+		SPCI_FL_BASE0 | SPCI_FL_REGION_SZ_CAP, 32, 115200 },
+	{	PCI_VENDOR_ID_TIMEDIA, PCI_DEVICE_ID_TIMEDIA_1889,
+		PCI_ANY_ID, PCI_ANY_ID,
+		SPCI_FL_BASE0 , 2, 921600 },
+	{	PCI_VENDOR_ID_LAVA, PCI_DEVICE_ID_LAVA_DSERIAL,
+		PCI_ANY_ID, PCI_ANY_ID,
+		SPCI_FL_BASE0 | SPCI_FL_BASE_TABLE, 2, 115200 },
+	{	PCI_VENDOR_ID_LAVA, PCI_DEVICE_ID_LAVA_QUATRO_A,
+		PCI_ANY_ID, PCI_ANY_ID,
+		SPCI_FL_BASE0 | SPCI_FL_BASE_TABLE, 2, 115200 },
+	{	PCI_VENDOR_ID_LAVA, PCI_DEVICE_ID_LAVA_QUATRO_B,
+		PCI_ANY_ID, PCI_ANY_ID,
+		SPCI_FL_BASE0 | SPCI_FL_BASE_TABLE, 2, 115200 },
+	{	PCI_VENDOR_ID_LAVA, PCI_DEVICE_ID_LAVA_PORT_PLUS,
+		PCI_ANY_ID, PCI_ANY_ID,
+		SPCI_FL_BASE0 | SPCI_FL_BASE_TABLE, 2, 460800 },
+	{	PCI_VENDOR_ID_LAVA, PCI_DEVICE_ID_LAVA_QUAD_A,
+		PCI_ANY_ID, PCI_ANY_ID,
+		SPCI_FL_BASE0 | SPCI_FL_BASE_TABLE, 2, 460800 },
+	{	PCI_VENDOR_ID_LAVA, PCI_DEVICE_ID_LAVA_QUAD_B,
+		PCI_ANY_ID, PCI_ANY_ID,
+		SPCI_FL_BASE0 | SPCI_FL_BASE_TABLE, 2, 460800 },
+	{	PCI_VENDOR_ID_LAVA, PCI_DEVICE_ID_LAVA_SSERIAL,
+		PCI_ANY_ID, PCI_ANY_ID,
+		SPCI_FL_BASE0 | SPCI_FL_BASE_TABLE, 1, 115200 },
+	{	PCI_VENDOR_ID_LAVA, PCI_DEVICE_ID_LAVA_PORT_650,
+		PCI_ANY_ID, PCI_ANY_ID,
+		SPCI_FL_BASE0 | SPCI_FL_BASE_TABLE, 1, 460800 },
+	{	PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_1S_10x_550,
+		PCI_ANY_ID, PCI_ANY_ID,
+		SPCI_FL_BASE2, 1, 460800,
+		0, 0, pci_siig10x_fn },
+	{	PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_1S_10x_650,
+		PCI_ANY_ID, PCI_ANY_ID,
+		SPCI_FL_BASE2, 1, 460800,
+		0, 0, pci_siig10x_fn },
+	{	PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_1S_10x_850,
+		PCI_ANY_ID, PCI_ANY_ID,
+		SPCI_FL_BASE2, 1, 460800,
+		0, 0, pci_siig10x_fn },
+	{	PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_1S1P_10x_550,
+		PCI_ANY_ID, PCI_ANY_ID,
+		SPCI_FL_BASE2, 1, 921600,
+		0, 0, pci_siig10x_fn },
+	{	PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_1S1P_10x_650,
+		PCI_ANY_ID, PCI_ANY_ID,
+		SPCI_FL_BASE2, 1, 921600,
+		0, 0, pci_siig10x_fn },
+	{	PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_1S1P_10x_850,
+		PCI_ANY_ID, PCI_ANY_ID,
+		SPCI_FL_BASE2, 1, 921600,
+		0, 0, pci_siig10x_fn },
+	{	PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_2S_10x_550,
+		PCI_ANY_ID, PCI_ANY_ID,
+		SPCI_FL_BASE2 | SPCI_FL_BASE_TABLE, 2, 921600,
+		0, 0, pci_siig10x_fn },
+	{	PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_2S_10x_650,
+		PCI_ANY_ID, PCI_ANY_ID,
+		SPCI_FL_BASE2 | SPCI_FL_BASE_TABLE, 2, 921600,
+		0, 0, pci_siig10x_fn },
+	{	PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_2S_10x_850,
+		PCI_ANY_ID, PCI_ANY_ID,
+		SPCI_FL_BASE2 | SPCI_FL_BASE_TABLE, 2, 921600,
+		0, 0, pci_siig10x_fn },
+	{	PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_2S1P_10x_550,
+		PCI_ANY_ID, PCI_ANY_ID,
+		SPCI_FL_BASE2 | SPCI_FL_BASE_TABLE, 2, 921600,
+		0, 0, pci_siig10x_fn },
+	{	PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_2S1P_10x_650,
+		PCI_ANY_ID, PCI_ANY_ID,
+		SPCI_FL_BASE2 | SPCI_FL_BASE_TABLE, 2, 921600,
+		0, 0, pci_siig10x_fn },
+	{	PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_2S1P_10x_850,
+		PCI_ANY_ID, PCI_ANY_ID,
+		SPCI_FL_BASE2 | SPCI_FL_BASE_TABLE, 2, 921600,
+		0, 0, pci_siig10x_fn },
+	{	PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_4S_10x_550,
+		PCI_ANY_ID, PCI_ANY_ID,
+		SPCI_FL_BASE2 | SPCI_FL_BASE_TABLE, 4, 921600,
+		0, 0, pci_siig10x_fn },
+	{	PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_4S_10x_650,
+		PCI_ANY_ID, PCI_ANY_ID,
+		SPCI_FL_BASE2 | SPCI_FL_BASE_TABLE, 4, 921600,
+		0, 0, pci_siig10x_fn },
+	{	PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_4S_10x_850,
+		PCI_ANY_ID, PCI_ANY_ID,
+		SPCI_FL_BASE2 | SPCI_FL_BASE_TABLE, 4, 921600,
+		0, 0, pci_siig10x_fn },
+	{	PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_1S_20x_550,
+		PCI_ANY_ID, PCI_ANY_ID,
+		SPCI_FL_BASE0, 1, 921600,
+		0, 0, pci_siig20x_fn },
+	{	PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_1S_20x_650,
+		PCI_ANY_ID, PCI_ANY_ID,
+		SPCI_FL_BASE0, 1, 921600,
+		0, 0, pci_siig20x_fn },
+	{	PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_1S_20x_850,
+		PCI_ANY_ID, PCI_ANY_ID,
+		SPCI_FL_BASE0, 1, 921600,
+		0, 0, pci_siig20x_fn },
+	{	PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_1S1P_20x_550,
+		PCI_ANY_ID, PCI_ANY_ID,
+		SPCI_FL_BASE0, 1, 921600,
+		0, 0, pci_siig20x_fn },
+	{	PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_1S1P_20x_650,
+		PCI_ANY_ID, PCI_ANY_ID,
+		SPCI_FL_BASE0, 1, 921600,
+		0, 0, pci_siig20x_fn },
+	{	PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_1S1P_20x_850,
+		PCI_ANY_ID, PCI_ANY_ID,
+		SPCI_FL_BASE0, 1, 921600,
+		0, 0, pci_siig20x_fn },
+	{	PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_2P1S_20x_550,
+		PCI_ANY_ID, PCI_ANY_ID,
+		SPCI_FL_BASE0, 1, 921600,
+		0, 0, pci_siig20x_fn },
+	{	PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_2P1S_20x_650,
+		PCI_ANY_ID, PCI_ANY_ID,
+		SPCI_FL_BASE0, 1, 921600,
+		0, 0, pci_siig20x_fn },
+	{	PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_2P1S_20x_850,
+		PCI_ANY_ID, PCI_ANY_ID,
+		SPCI_FL_BASE0, 1, 921600,
+		0, 0, pci_siig20x_fn },
+	{	PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_2S_20x_550,
+		PCI_ANY_ID, PCI_ANY_ID,
+		SPCI_FL_BASE0 | SPCI_FL_BASE_TABLE, 2, 921600,
+		0, 0, pci_siig20x_fn },
+	{	PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_2S_20x_650,
+		PCI_ANY_ID, PCI_ANY_ID,
+		SPCI_FL_BASE0 | SPCI_FL_BASE_TABLE, 2, 921600,
+		0, 0, pci_siig20x_fn },
+	{	PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_2S_20x_850,
+		PCI_ANY_ID, PCI_ANY_ID,
+		SPCI_FL_BASE0 | SPCI_FL_BASE_TABLE, 2, 921600,
+		0, 0, pci_siig20x_fn },
+	{	PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_2S1P_20x_550,
+		PCI_ANY_ID, PCI_ANY_ID,
+		SPCI_FL_BASE0 | SPCI_FL_BASE_TABLE, 2, 921600,
+		0, 0, pci_siig20x_fn },
+	{	PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_2S1P_20x_650,
+		PCI_ANY_ID, PCI_ANY_ID,
+		SPCI_FL_BASE0 | SPCI_FL_BASE_TABLE, 2, 921600,
+		0, 0, pci_siig20x_fn },
+	{	PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_2S1P_20x_850,
+		PCI_ANY_ID, PCI_ANY_ID,
+		SPCI_FL_BASE0 | SPCI_FL_BASE_TABLE, 2, 921600,
+		0, 0, pci_siig20x_fn },
+	{	PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_4S_20x_550,
+		PCI_ANY_ID, PCI_ANY_ID,
+		SPCI_FL_BASE0 | SPCI_FL_BASE_TABLE, 4, 921600,
+		0, 0, pci_siig20x_fn },
+	{	PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_4S_20x_650,
+		PCI_ANY_ID, PCI_ANY_ID,
+		SPCI_FL_BASE0 | SPCI_FL_BASE_TABLE, 4, 921600,
+		0, 0, pci_siig20x_fn },
+	{	PCI_VENDOR_ID_SIIG, PCI_DEVICE_ID_SIIG_4S_20x_850,
+		PCI_ANY_ID, PCI_ANY_ID,
+		SPCI_FL_BASE0 | SPCI_FL_BASE_TABLE, 4, 921600,
+		0, 0, pci_siig20x_fn },
+	/* Computone devices submitted by Doug McNash dmcnash@computone.com */
+	{	PCI_VENDOR_ID_COMPUTONE, PCI_DEVICE_ID_COMPUTONE_PG,
+		PCI_SUBVENDOR_ID_COMPUTONE, PCI_SUBDEVICE_ID_COMPUTONE_PG4,
+		SPCI_FL_BASE0, 4, 921600, /* IOMEM */
+		0x40, 2, NULL, 0x200 },
+	{	PCI_VENDOR_ID_COMPUTONE, PCI_DEVICE_ID_COMPUTONE_PG,
+		PCI_SUBVENDOR_ID_COMPUTONE, PCI_SUBDEVICE_ID_COMPUTONE_PG8,
+		SPCI_FL_BASE0, 8, 921600, /* IOMEM */
+		0x40, 2, NULL, 0x200 },
+	{	PCI_VENDOR_ID_COMPUTONE, PCI_DEVICE_ID_COMPUTONE_PG,
+		PCI_SUBVENDOR_ID_COMPUTONE, PCI_SUBDEVICE_ID_COMPUTONE_PG6,
+		SPCI_FL_BASE0, 6, 921600, /* IOMEM */
+		0x40, 2, NULL, 0x200 },
+	/* Digitan DS560-558, from jimd@esoft.com */
+	{	PCI_VENDOR_ID_ATT, PCI_DEVICE_ID_ATT_VENUS_MODEM,
+		PCI_ANY_ID, PCI_ANY_ID,
+		SPCI_FL_BASE1, 1, 115200 },
+	/* 3Com US Robotics 56k Voice Internal PCI model 5610 */
+	{	PCI_VENDOR_ID_USR, 0x1008,
+		PCI_ANY_ID, PCI_ANY_ID,
+		SPCI_FL_BASE0, 1, 115200 },
+	/* Titan Electronic cards */
+	{	PCI_VENDOR_ID_TITAN, PCI_DEVICE_ID_TITAN_100,
+		PCI_ANY_ID, PCI_ANY_ID,
+		SPCI_FL_BASE0, 1, 921600 },
+	{	PCI_VENDOR_ID_TITAN, PCI_DEVICE_ID_TITAN_200,
+		PCI_ANY_ID, PCI_ANY_ID,
+		SPCI_FL_BASE0, 2, 921600 },
+	{	PCI_VENDOR_ID_TITAN, PCI_DEVICE_ID_TITAN_400,
+		PCI_ANY_ID, PCI_ANY_ID,
+		SPCI_FL_BASE0, 4, 921600 },
+	{	PCI_VENDOR_ID_TITAN, PCI_DEVICE_ID_TITAN_800B,
+		PCI_ANY_ID, PCI_ANY_ID,
+		SPCI_FL_BASE0, 4, 921600 },
+	/* EKF addition for i960 Boards form EKF with serial port */
+	{	PCI_VENDOR_ID_INTEL, 0x1960,
+		0xE4BF, PCI_ANY_ID,
+		SPCI_FL_BASE0, 32, 921600, /* max 256 ports */
+		8<<2, 2, pci_inteli960ni_fn, 0x10000},	  
+	/*
+	 * Untested PCI modems, sent in from various folks...
+	 */
+	/* Elsa Model 56K PCI Modem, from Andreas Rath <arh@01019freenet.de> */
+	{	PCI_VENDOR_ID_ROCKWELL, 0x1004,
+		0x1048, 0x1500, 
+		SPCI_FL_BASE1, 1, 115200 },
+#if 0			/* No definition for PCI_DEVICE_ID_NEC_NILE4 */
+	/*
+	 * NEC Vrc-5074 (Nile 4) builtin UART.
+	 */
+	{	PCI_VENDOR_ID_NEC, PCI_DEVICE_ID_NEC_NILE4,
+		PCI_ANY_ID, PCI_ANY_ID,
+		SPCI_FL_BASE0, 1, 520833,
+		64, 3, NULL, 0x300 },
+#endif
+	/* Generic serial board */
+	{	0, 0,
+		0, 0,
+		SPCI_FL_BASE0, 1, 115200 },
+};
+
+/*
+ * Given a complete unknown PCI device, try to use some heuristics to
+ * guess what the configuration might be, based on the pitiful PCI
+ * serial specs.  Returns 0 on success, 1 on failure.
+ */
+static int _INLINE_ serial_pci_guess_board(struct pci_dev *dev,
+					   struct pci_board *board)
+{
+	int	num_iomem = 0, num_port = 0, first_port = -1;
+	int	i;
+	
+	/*
+	 * If it is not a communications device or the programming
+	 * interface is greater than 6, give up.
+	 *
+	 * (Should we try to make guesses for multiport serial devices
+	 * later?) 
+	 */
+	if ((dev->class >> 8) != PCI_CLASS_COMMUNICATION_SERIAL ||
+	    (dev->class & 0xff) > 6)
+		return 1;
+
+	for (i=0; i < 6; i++) {
+		if (IS_PCI_REGION_IOPORT(dev, i)) {
+			num_port = 0;
+			if (first_port == -1)
+				first_port = i;
+		} else {
+			num_iomem++;
+		}
+	}
+
+	/*
+	 * If there is 1 or 0 iomem regions, and exactly one port, use
+	 * it.
+	 */
+	if (num_iomem <= 1 && num_port == 1) {
+		board->flags = first_port;
+		return 0;
+	}
+	return 1;
+}
+
+
+
+/*
+ * Query PCI space for known serial boards
+ * If found, add them to the PCI device space in rs_table[]
+ *
+ * Accept a maximum of eight boards
+ *
+ */
+static void __init probe_serial_pci(void) 
+{
+	struct pci_dev *dev = NULL;
+	struct pci_board *board;
+
+#ifdef SERIAL_DEBUG_PCI
+	printk(KERN_DEBUG "Entered probe_serial_pci()\n");
+#endif
+  
+	if (!pcibios_present()) {
+#ifdef SERIAL_DEBUG_PCI
+		printk(KERN_DEBUG "Leaving probe_serial_pci() (no pcibios)\n");
+#endif
+		return;
+	}
+
+	pci_for_each_dev(dev) {
+		for (board = pci_boards; board->vendor; board++) {
+			if (board->vendor != (unsigned short) PCI_ANY_ID &&
+			    dev->vendor != board->vendor)
+				continue;
+			if (board->device != (unsigned short) PCI_ANY_ID &&
+			    dev->device != board->device)
+				continue;
+			if (board->subvendor != (unsigned short) PCI_ANY_ID &&
+			    pci_get_subvendor(dev) != board->subvendor)
+				continue;
+			if (board->subdevice != (unsigned short) PCI_ANY_ID &&
+			    pci_get_subdevice(dev) != board->subdevice)
+				continue;
+			break;
+		}
+	
+		if (board->vendor == 0 && serial_pci_guess_board(dev, board))
+			continue;
+		
+		start_pci_pnp_board(dev, board);
+	}
+	
+#ifdef SERIAL_DEBUG_PCI
+	printk(KERN_DEBUG "Leaving probe_serial_pci() (probe finished)\n");
+#endif
+	return;
+}
+
+#endif /* ENABLE_SERIAL_PCI */
+
+#ifdef ENABLE_SERIAL_PNP
+
+static struct pci_board pnp_devices[] __initdata = {
+	/* Rockwell 56K ACF II Fax+Data+Voice Modem */
+	{	ISAPNP_VENDOR('A', 'K', 'Y'), ISAPNP_DEVICE(0x1021), 0, 0,
+		SPCI_FL_BASE0 | SPCI_FL_NO_SHIRQ | SPCI_FL_PNPDEFAULT,
+		1, 115200 },
+	/* ASKEY 56K Plug&Play Modem */
+	{	ISAPNP_VENDOR('A', 'S', 'K'), ISAPNP_DEVICE(0x0004), 0, 0,
+		SPCI_FL_BASE0 | SPCI_FL_PNPDEFAULT, 1, 115200 },
+	/* AZT3005 PnP SOUND DEVICE */
+	{	ISAPNP_VENDOR('A', 'Z', 'T'), ISAPNP_DEVICE(0x4001), 0, 0,
+		SPCI_FL_BASE0 | SPCI_FL_PNPDEFAULT, 1, 115200 },
+	/* Best Data Products Inc. Smart One 336F PnP Modem */
+	{	ISAPNP_VENDOR('B', 'D', 'P'), ISAPNP_DEVICE(0x3336), 0, 0,
+		SPCI_FL_BASE0 | SPCI_FL_PNPDEFAULT, 1, 115200 },
+	/* Boca Research 33,600 ACF Modem */
+	{	ISAPNP_VENDOR('B', 'R', 'I'), ISAPNP_DEVICE(0x1400), 0, 0,
+		SPCI_FL_BASE0 | SPCI_FL_PNPDEFAULT, 1, 115200 },
+	/* Davicom 33.6 PNP Modem */
+	{	ISAPNP_VENDOR('D', 'A', 'V'), ISAPNP_DEVICE(0x0336), 0, 0,
+		SPCI_FL_BASE0 | SPCI_FL_PNPDEFAULT, 1, 115200 },
+	/* Creative Modem Blaster Flash56 DI5601-1 */
+	{	ISAPNP_VENDOR('D', 'M', 'B'), ISAPNP_DEVICE(0x1032), 0, 0,
+		SPCI_FL_BASE0 | SPCI_FL_PNPDEFAULT, 1, 115200 },
+	/* Creative Modem Blaster V.90 DI5660 */
+	{	ISAPNP_VENDOR('D', 'M', 'B'), ISAPNP_DEVICE(0x2001), 0, 0,
+		SPCI_FL_BASE0 | SPCI_FL_PNPDEFAULT, 1, 115200 },
+	/* Motorola VoiceSURFR 56K Modem */
+	{	ISAPNP_VENDOR('M', 'O', 'T'), ISAPNP_DEVICE(0x15F0), 0, 0,
+		SPCI_FL_BASE0 | SPCI_FL_PNPDEFAULT, 1, 115200 },
+	/* Pace 56 Voice Internal Plug & Play Modem */
+	{	ISAPNP_VENDOR('P', 'M', 'C'), ISAPNP_DEVICE(0x2430), 0, 0,
+		SPCI_FL_BASE0 | SPCI_FL_PNPDEFAULT, 1, 115200 },
+	/* SupraExpress 28.8 Data/Fax PnP modem */
+	{	ISAPNP_VENDOR('S', 'U', 'P'), ISAPNP_DEVICE(0x1310), 0, 0,
+		SPCI_FL_BASE0 | SPCI_FL_PNPDEFAULT, 1, 115200 },
+	/* US Robotics Sporster 33600 Modem */
+	{	ISAPNP_VENDOR('U', 'S', 'R'), ISAPNP_DEVICE(0x0006), 0, 0,
+		SPCI_FL_BASE0 | SPCI_FL_PNPDEFAULT, 1, 115200 },
+	/* U.S. Robotics 56K FAX INT */
+	{	ISAPNP_VENDOR('U', 'S', 'R'), ISAPNP_DEVICE(0x3031), 0, 0,
+		SPCI_FL_BASE0 | SPCI_FL_PNPDEFAULT, 1, 115200 },
+	/* U.S. Robotics 56k FAX INT */
+	{	ISAPNP_VENDOR('U', 'S', 'R'), ISAPNP_DEVICE(0x3050), 0, 0,
+		SPCI_FL_BASE0 | SPCI_FL_PNPDEFAULT, 1, 115200 },
+	/* Viking 56K FAX INT */
+	{	ISAPNP_VENDOR('R', 'S', 'S'), ISAPNP_DEVICE(0x0262), 0, 0,
+		SPCI_FL_BASE0 | SPCI_FL_PNPDEFAULT, 1, 115200 },
+
+	/* These ID's are taken from M$ documentation */
+	/* Compaq 14400 Modem */
+	{	ISAPNP_VENDOR('P', 'N', 'P'), ISAPNP_DEVICE(0xC000), 0, 0,
+		SPCI_FL_BASE0 | SPCI_FL_PNPDEFAULT, 1, 115200 },
+	/* Compaq 2400/9600 Modem */
+	{	ISAPNP_VENDOR('P', 'N', 'P'), ISAPNP_DEVICE(0xC001), 0, 0,
+		SPCI_FL_BASE0 | SPCI_FL_PNPDEFAULT, 1, 115200 },
+	/* Generic standard PC COM port	 */
+	{	ISAPNP_VENDOR('P', 'N', 'P'), ISAPNP_DEVICE(0x0500), 0, 0,
+		SPCI_FL_BASE0 | SPCI_FL_PNPDEFAULT, 1, 115200 },
+	/* Generic 16550A-compatible COM port */
+	{	ISAPNP_VENDOR('P', 'N', 'P'), ISAPNP_DEVICE(0x0501), 0, 0,
+		SPCI_FL_BASE0 | SPCI_FL_PNPDEFAULT, 1, 115200 },
+	/* Generic ISA PnP serial board */
+	{       0, 0, 0, 0,
+		SPCI_FL_BASE0 | SPCI_FL_NO_SHIRQ | SPCI_FL_PNPDEFAULT,
+		1, 115200 },
+	{	0, }
+};
+
+static void inline avoid_irq_share(struct pci_dev *dev)
+{
+	int i, map = 0x1FF8;
+	struct serial_state *state = rs_table;
+	struct isapnp_irq *irq;
+	struct isapnp_resources *res = dev->sysdata;
+
+	for (i = 0; i < NR_PORTS; i++) {
+		if (state->type != PORT_UNKNOWN)
+			clear_bit(state->irq, &map);
+		state++;
+	}
+
+	for ( ; res; res = res->alt)
+		for(irq = res->irq; irq; irq = irq->next)
+			irq->map = map;
+}
+
+static char *modem_names[] = {
+       "MODEM", "Modem", "modem", "FAX", "Fax", "fax",
+       "56K", "56k", "K56", "33.6", "28.8", "14.4",
+       "33,600", "28,800", "14,400", "33.600", "28.800", "14.400",
+       "33600", "28800", "14400", "V.90", "V.34", "V.32", 0
+};
+
+static int check_name(char *name)
+{
+       char **tmp = modem_names;
+
+       while (*tmp) {
+               if (strstr(name, *tmp))
+                       return 1;
+               tmp++;
+       }
+       return 0;
+}
+
+/*
+ * Given a complete unknown ISA PnP device, try to use some heuristics to
+ * detect modems. Currently use such heuristic set:
+ *     - dev->name or dev->bus->name must contain "modem" substring;
+ *     - device must have only one IO region (8 byte long) with base adress
+ *       0x2e8, 0x3e8, 0x2f8 or 0x3f8.
+ *
+ * Such detection looks very ugly, but can detect at least some of numerous
+ * ISA PnP modems, alternatively we must hardcode all modems in pnp_devices[]
+ * table.
+ */
+static int _INLINE_ serial_pnp_guess_board(struct pci_dev *dev,
+                                          struct pci_board *board)
+{
+       struct isapnp_resources *res = (struct isapnp_resources *)dev->sysdata;
+       struct isapnp_resources *resa;
+
+       if (dev->active)
+               return 1;
+
+       if (!(check_name(dev->name) || check_name(dev->bus->name)))
+               return 1;
+
+       if (res->next)
+               return 1;
+
+       for (resa = res->alt; resa; resa = resa->alt) {
+               struct isapnp_port *port;
+               for (port = res->port; port; port = port->next)
+                       if ((port->size == 8) &&
+                           ((port->min == 0x2f8) ||
+                            (port->min == 0x3f8) ||
+                            (port->min == 0x2e8) ||
+                            (port->min == 0x3e8)))
+                               return 0;
+       }
+
+       return 1;
+}
+
+static void __init probe_serial_pnp(void)
+{
+       struct pci_dev *dev = NULL;
+       struct pci_board *board;
+
+#ifdef SERIAL_DEBUG_PNP
+       printk("Entered probe_serial_pnp()\n");
+#endif
+       if (!isapnp_present()) {
+#ifdef SERIAL_DEBUG_PNP
+               printk("Leaving probe_serial_pnp() (no isapnp)\n");
+#endif
+               return;
+       }
+
+       isapnp_for_each_dev(dev) {
+	       for (board = pnp_devices; board->vendor; board++)
+		       if ((dev->vendor == board->vendor) &&
+			   (dev->device == board->device))
+			       break;
 
+	       if (board->vendor == 0 && serial_pnp_guess_board(dev, board))
+		       continue;
+
+	       if (board->flags & SPCI_FL_NO_SHIRQ)
+		       avoid_irq_share(dev);
+	       start_pci_pnp_board(dev, board);
+       }
+
+#ifdef SERIAL_DEBUG_PNP
+       printk("Leaving probe_serial_pnp() (probe finished)\n");
+#endif
+       return;
+}
+
+#endif /* ENABLE_SERIAL_PNP */
+
 /*
  * The serial driver boot-time initialization code!
  */
-__initfunc(int rs_init(void))
+int __init rs_init(void)
 {
 	int i;
 	struct serial_state * state;
-	extern void atomwide_serial_init (void);
-	extern void dualsp_serial_init (void);
 
-#ifdef CONFIG_ATOMWIDE_SERIAL
-	atomwide_serial_init ();
-#endif
-#ifdef CONFIG_DUALSP_SERIAL
-	dualsp_serial_init ();
+	if (timer_table[RS_TIMER].fn) {
+		printk("RS_TIMER already set, another serial driver "
+		       "already loaded?\n");
+#ifdef MODULE
+		printk("Can't load serial driver module over built-in "
+		       "serial driver\n");
 #endif
+		return -EBUSY;
+	}
 
 	init_bh(SERIAL_BH, do_serial_bh);
 	timer_table[RS_TIMER].fn = rs_timer;
@@ -3123,17 +4637,23 @@
 	
 	memset(&serial_driver, 0, sizeof(struct tty_driver));
 	serial_driver.magic = TTY_DRIVER_MAGIC;
+#if (LINUX_VERSION_CODE > 0x20100)
 	serial_driver.driver_name = "serial";
+#endif
+#if (LINUX_VERSION_CODE > 0x2032D)
+	serial_driver.name = "tts/%d";
+#else
 	serial_driver.name = "ttyS";
+#endif
 	serial_driver.major = TTY_MAJOR;
-	serial_driver.minor_start = 64;
+	serial_driver.minor_start = 64 + SERIAL_DEV_OFFSET;
 	serial_driver.num = NR_PORTS;
 	serial_driver.type = TTY_DRIVER_TYPE_SERIAL;
 	serial_driver.subtype = SERIAL_TYPE_NORMAL;
 	serial_driver.init_termios = tty_std_termios;
 	serial_driver.init_termios.c_cflag =
 		B9600 | CS8 | CREAD | HUPCL | CLOCAL;
-	serial_driver.flags = TTY_DRIVER_REAL_RAW;
+	serial_driver.flags = TTY_DRIVER_REAL_RAW | TTY_DRIVER_NO_DEVFS;
 	serial_driver.refcount = &serial_refcount;
 	serial_driver.table = serial_table;
 	serial_driver.termios = serial_termios;
@@ -3150,25 +4670,35 @@
 	serial_driver.ioctl = rs_ioctl;
 	serial_driver.throttle = rs_throttle;
 	serial_driver.unthrottle = rs_unthrottle;
-	serial_driver.send_xchar = rs_send_xchar;
 	serial_driver.set_termios = rs_set_termios;
 	serial_driver.stop = rs_stop;
 	serial_driver.start = rs_start;
 	serial_driver.hangup = rs_hangup;
+#if (LINUX_VERSION_CODE >= 131394) /* Linux 2.1.66 */
 	serial_driver.break_ctl = rs_break;
+#endif
+#if (LINUX_VERSION_CODE >= 131343)
+	serial_driver.send_xchar = rs_send_xchar;
 	serial_driver.wait_until_sent = rs_wait_until_sent;
 	serial_driver.read_proc = rs_read_proc;
+#endif
 	
 	/*
 	 * The callout device is just like normal device except for
 	 * major number and the subtype code.
 	 */
 	callout_driver = serial_driver;
+#if (LINUX_VERSION_CODE > 0x2032D)
+	callout_driver.name = "cua/%d";
+#else
 	callout_driver.name = "cua";
+#endif
 	callout_driver.major = TTYAUX_MAJOR;
 	callout_driver.subtype = SERIAL_TYPE_CALLOUT;
+#if (LINUX_VERSION_CODE >= 131343)
 	callout_driver.read_proc = 0;
 	callout_driver.proc_entry = 0;
+#endif
 
 	if (tty_register_driver(&serial_driver))
 		panic("Couldn't register serial driver\n");
@@ -3190,15 +4720,13 @@
 		state->icount.frame = state->icount.parity = 0;
 		state->icount.overrun = state->icount.brk = 0;
 		state->irq = irq_cannonicalize(state->irq);
-		if (check_region(state->port,8))
+		if (state->hub6)
+			state->io_type = SERIAL_IO_HUB6;
+		if (state->port && check_region(state->port,8))
 			continue;
 		if (state->flags & ASYNC_BOOT_AUTOCONF)
 			autoconfig(state);
 	}
-	/*
-	 * Detect the IRQ only once every port is initialised,
-	 * because some 16450 do not reset to 0 the MCR register.
-	 */
 	for (i = 0, state = rs_table; i < NR_PORTS; i++,state++) {
 		if (state->type == PORT_UNKNOWN)
 			continue;
@@ -3206,29 +4734,60 @@
 		    && (state->flags & ASYNC_AUTO_IRQ)
 		    && (state->port != 0))
 			state->irq = detect_uart_irq(state);
-		printk(KERN_INFO "ttyS%02d%s at 0x%04x (irq = %d) is a %s\n",
-		       state->line,
+		printk(KERN_INFO "ttyS%02d%s at 0x%04lx (irq = %d) is a %s\n",
+		       state->line + SERIAL_DEV_OFFSET,
 		       (state->flags & ASYNC_FOURPORT) ? " FourPort" : "",
 		       state->port, state->irq,
 		       uart_config[state->type].name);
+		tty_register_devfs(&serial_driver, 0,
+				   serial_driver.minor_start + state->line);
+		tty_register_devfs(&callout_driver, 0,
+				   callout_driver.minor_start + state->line);
 	}
+#ifdef ENABLE_SERIAL_PCI
+	probe_serial_pci();
+#endif
+#ifdef ENABLE_SERIAL_PNP
+       probe_serial_pnp();
+#endif
 	return 0;
 }
 
 /*
- * register_serial and unregister_serial allows for serial ports to be
+ * register_serial and unregister_serial allows for 16x50 serial ports to be
  * configured at run-time, to support PCMCIA modems.
  */
+ 
+/**
+ *	register_serial - configure a 16x50 serial port at runtime
+ *	@req: request structure
+ *
+ *	Configure the serial port specified by the request. If the
+ *	port exists and is in use an error is returned. If the port
+ *	is not currently in the table it is added.
+ *
+ *	The port is then probed and if neccessary the IRQ is autodetected
+ *	If this fails an error is returned.
+ *
+ *	On success the port is ready to use and the line number is returned.
+ */
+ 
 int register_serial(struct serial_struct *req)
 {
 	int i;
 	unsigned long flags;
 	struct serial_state *state;
+	struct async_struct *info;
+	unsigned long port;
 
-	save_flags(flags);
-	cli();
+	port = req->port;
+	if (HIGH_BITS_OFFSET)
+		port += req->port_high << HIGH_BITS_OFFSET;
+
+	save_flags(flags); cli();
 	for (i = 0; i < NR_PORTS; i++) {
-		if (rs_table[i].port == req->port)
+		if ((rs_table[i].port == port) &&
+		    (rs_table[i].iomem_base == req->iomem_base))
 			break;
 	}
 	if (i == NR_PORTS) {
@@ -3244,14 +4803,25 @@
 	state = &rs_table[i];
 	if (rs_table[i].count) {
 		restore_flags(flags);
-		printk("Couldn't configure serial #%d (port=%d,irq=%d): "
-		       "device already open\n", i, req->port, req->irq);
+		printk("Couldn't configure serial #%d (port=%ld,irq=%d): "
+		       "device already open\n", i, port, req->irq);
 		return -1;
 	}
 	state->irq = req->irq;
-	state->port = req->port;
+	state->port = port;
 	state->flags = req->flags;
-
+	state->io_type = req->io_type;
+	state->iomem_base = req->iomem_base;
+	state->iomem_reg_shift = req->iomem_reg_shift;
+	if (req->baud_base)
+		state->baud_base = req->baud_base;
+	if ((info = state->info) != NULL) {
+		info->port = port;
+		info->flags = req->flags;
+		info->io_type = req->io_type;
+		info->iomem_base = req->iomem_base;
+		info->iomem_reg_shift = req->iomem_reg_shift;
+	}
 	autoconfig(state);
 	if (state->type == PORT_UNKNOWN) {
 		restore_flags(flags);
@@ -3260,36 +4830,52 @@
 	}
 	restore_flags(flags);
 
-	if ((state->flags & ASYNC_AUTO_IRQ) && (state->port != 0))
+	if ((state->flags & ASYNC_AUTO_IRQ) && CONFIGURED_SERIAL_PORT(state))
 		state->irq = detect_uart_irq(state);
 
-	printk(KERN_INFO "tty%02d at 0x%04x (irq = %d) is a %s\n",
-	       state->line, state->port, state->irq,
-	       uart_config[state->type].name);
-	return state->line;
+       printk(KERN_INFO "ttyS%02d at %s 0x%04lx (irq = %d) is a %s\n",
+	      state->line + SERIAL_DEV_OFFSET,
+	      state->iomem_base ? "iomem" : "port",
+	      state->iomem_base ? (unsigned long)state->iomem_base :
+	      state->port, state->irq, uart_config[state->type].name);
+	tty_register_devfs(&serial_driver, 0,
+			   serial_driver.minor_start + state->line); 
+	tty_register_devfs(&callout_driver, 0,
+			   callout_driver.minor_start + state->line);
+	return state->line + SERIAL_DEV_OFFSET;
 }
 
+/**
+ *	unregister_serial - deconfigure a 16x50 serial port
+ *	@line: line to deconfigure
+ *
+ *	The port specified is deconfigured and its resources are freed. Any
+ *	user of the port is disconnected as if carrier was dropped. Line is
+ *	the port number returned by register_serial().
+ */
+
 void unregister_serial(int line)
 {
 	unsigned long flags;
 	struct serial_state *state = &rs_table[line];
 
-	save_flags(flags);
-	cli();
+	save_flags(flags); cli();
 	if (state->info && state->info->tty)
 		tty_hangup(state->info->tty);
 	state->type = PORT_UNKNOWN;
 	printk(KERN_INFO "tty%02d unloaded\n", state->line);
+	/* These will be hidden, because they are devices that will no longer
+	 * be available to the system. (ie, PCMCIA modems, once ejected)
+	 */
+	tty_unregister_devfs(&serial_driver,
+			     serial_driver.minor_start + state->line);
+	tty_unregister_devfs(&callout_driver,
+			     callout_driver.minor_start + state->line);
 	restore_flags(flags);
 }
 
 #ifdef MODULE
-int init_module(void)
-{
-	return rs_init();
-}
-
-void cleanup_module(void) 
+void rs_fini(void) 
 {
 	unsigned long flags;
 	int e1, e2;
@@ -3297,8 +4883,7 @@
 	struct async_struct *info;
 
 	/* printk("Unloading %s: version %s\n", serial_name, serial_version); */
-	save_flags(flags);
-	cli();
+	save_flags(flags); cli();
 	timer_active &= ~(1 << RS_TIMER);
 	timer_table[RS_TIMER].fn = NULL;
 	timer_table[RS_TIMER].expires = 0;
@@ -3312,22 +4897,40 @@
 	restore_flags(flags);
 
 	for (i = 0; i < NR_PORTS; i++) {
-		if (rs_table[i].type != PORT_UNKNOWN)
-			release_region(rs_table[i].port, 8);
-		info = rs_table[i].info;
-		if (info) {
+		if ((info = rs_table[i].info)) {
 			rs_table[i].info = NULL;
 			kfree_s(info, sizeof(struct async_struct));
 		}
+		if ((rs_table[i].type != PORT_UNKNOWN) && rs_table[i].port)
+			release_region(rs_table[i].port, 8);
+#if defined(ENABLE_SERIAL_PCI) || defined(ENABLE_SERIAL_PNP)
+		if (rs_table[i].iomem_base)
+			iounmap(rs_table[i].iomem_base);
+#endif
+	}
+#if defined(ENABLE_SERIAL_PCI) || defined(ENABLE_SERIAL_PNP)
+	for (i=0; i < serial_pci_board_idx; i++) {
+		struct pci_board_inst *brd = &serial_pci_board[i];
+		
+		if (brd->board.init_fn)
+			(brd->board.init_fn)(brd->dev, &brd->board, 0);
+
+		if (DEACTIVATE_FUNC(brd->dev))
+			(DEACTIVATE_FUNC(brd->dev))(brd->dev);
 	}
+#endif	
 	if (tmp_buf) {
-		free_page((unsigned long) tmp_buf);
+		unsigned long pg = (unsigned long) tmp_buf;
 		tmp_buf = NULL;
+		free_page(pg);
 	}
 }
 #endif /* MODULE */
 
+module_init(rs_init);
+module_exit(rs_fini);
 
+
 /*
  * ------------------------------------------------------------
  * Serial console driver
@@ -3337,52 +4940,53 @@
 
 #define BOTH_EMPTY (UART_LSR_TEMT | UART_LSR_THRE)
 
+static struct async_struct async_sercons;
+
 /*
  *	Wait for transmitter & holding register to empty
  */
-static inline void wait_for_xmitr(struct serial_state *ser)
+static inline void wait_for_xmitr(struct async_struct *info)
 {
-	int lsr;
 	unsigned int tmout = 1000000;
 
-	do {
-		lsr = inb(ser->port + UART_LSR);
-		if (--tmout == 0) break;
-	} while ((lsr & BOTH_EMPTY) != BOTH_EMPTY);
+	while (--tmout &&
+	       ((serial_in(info, UART_LSR) & BOTH_EMPTY) != BOTH_EMPTY));
 }
 
+
 /*
  *	Print a string to the serial port trying not to disturb
  *	any possible real use of the port...
+ *
+ *	The console_lock must be held when we get here.
  */
 static void serial_console_write(struct console *co, const char *s,
 				unsigned count)
 {
-	struct serial_state *ser;
+	static struct async_struct *info = &async_sercons;
 	int ier;
 	unsigned i;
 
-	ser = rs_table + co->index;
 	/*
 	 *	First save the IER then disable the interrupts
 	 */
-	ier = inb(ser->port + UART_IER);
-	outb(0x00, ser->port + UART_IER);
+	ier = serial_in(info, UART_IER);
+	serial_out(info, UART_IER, 0x00);
 
 	/*
 	 *	Now, do each character
 	 */
 	for (i = 0; i < count; i++, s++) {
-		wait_for_xmitr(ser);
+		wait_for_xmitr(info);
 
 		/*
 		 *	Send the character out.
 		 *	If a LF, also do CR...
 		 */
-		outb(*s, ser->port + UART_TX);
+		serial_out(info, UART_TX, *s);
 		if (*s == 10) {
-			wait_for_xmitr(ser);
-			outb(13, ser->port + UART_TX);
+			wait_for_xmitr(info);
+			serial_out(info, UART_TX, 13);
 		}
 	}
 
@@ -3390,8 +4994,8 @@
 	 *	Finally, Wait for transmitter & holding register to empty
 	 * 	and restore the IER
 	 */
-	wait_for_xmitr(ser);
-	outb(ier, ser->port + UART_IER);
+	wait_for_xmitr(info);
+	serial_out(info, UART_IER, ier);
 }
 
 /*
@@ -3399,30 +5003,26 @@
  */
 static int serial_console_wait_key(struct console *co)
 {
-	struct serial_state *ser;
-	int ier;
-	int lsr;
-	int c;
+	static struct async_struct *info;
+	int ier, c;
 
-	ser = rs_table + co->index;
+	info = &async_sercons;
 
 	/*
 	 *	First save the IER then disable the interrupts so
 	 *	that the real driver for the port does not get the
 	 *	character.
 	 */
-	ier = inb(ser->port + UART_IER);
-	outb(0x00, ser->port + UART_IER);
-
-	do {
-		lsr = inb(ser->port + UART_LSR);
-	} while (!(lsr & UART_LSR_DR));
-	c = inb(ser->port + UART_RX);
+	ier = serial_in(info, UART_IER);
+	serial_out(info, UART_IER, 0x00);
+ 
+	while ((serial_in(info, UART_LSR) & UART_LSR_DR) == 0);
+	c = serial_in(info, UART_RX);
 
 	/*
 	 *	Restore the interrupts
 	 */
-	outb(ier, ser->port + UART_IER);
+	serial_out(info, UART_IER, ier);
 
 	return c;
 }
@@ -3438,9 +5038,10 @@
  *	- initialize the serial port
  *	Return non-zero if we didn't find a serial port.
  */
-__initfunc(static int serial_console_setup(struct console *co, char *options))
+static int __init serial_console_setup(struct console *co, char *options)
 {
-	struct serial_state *ser;
+	static struct async_struct *info;
+	struct serial_state *state;
 	unsigned cval;
 	int	baud = 9600;
 	int	bits = 8;
@@ -3448,6 +5049,9 @@
 	int	cflag = CREAD | HUPCL | CLOCAL;
 	int	quot = 0;
 	char	*s;
+#if defined(CONFIG_KDB)
+	extern int  kdb_port;
+#endif
 
 	if (options) {
 		baud = simple_strtoul(options, NULL, 10);
@@ -3510,8 +5114,19 @@
 	/*
 	 *	Divisor, bytesize and parity
 	 */
-	ser = rs_table + co->index;
-	quot = ser->baud_base / baud;
+	state = rs_table + co->index;
+	info = &async_sercons;
+	info->magic = SERIAL_MAGIC;
+	info->state = state;
+	info->port = state->port;
+	info->flags = state->flags;
+#ifdef CONFIG_HUB6
+	info->hub6 = state->hub6;
+#endif
+	info->io_type = state->io_type;
+	info->iomem_base = state->iomem_base;
+	info->iomem_reg_shift = state->iomem_reg_shift;
+	quot = state->baud_base / baud;
 	cval = cflag & (CSIZE | CSTOPB);
 #if defined(__powerpc__) || defined(__alpha__)
 	cval >>= 8;
@@ -3527,18 +5142,27 @@
 	 *	Disable UART interrupts, set DTR and RTS high
 	 *	and set speed.
 	 */
-	outb(cval | UART_LCR_DLAB, ser->port + UART_LCR);	/* set DLAB */
-	outb(quot & 0xff, ser->port + UART_DLL);	/* LS of divisor */
-	outb(quot >> 8, ser->port + UART_DLM);		/* MS of divisor */
-	outb(cval, ser->port + UART_LCR);		/* reset DLAB */
-	outb(0, ser->port + UART_IER);
-	outb(UART_MCR_DTR | UART_MCR_RTS, ser->port + UART_MCR);
+	serial_out(info, UART_LCR, cval | UART_LCR_DLAB);	/* set DLAB */
+	serial_out(info, UART_DLL, quot & 0xff);	/* LS of divisor */
+	serial_out(info, UART_DLM, quot >> 8);		/* MS of divisor */
+	serial_out(info, UART_LCR, cval);		/* reset DLAB */
+	serial_out(info, UART_IER, 0);
+	serial_out(info, UART_MCR, UART_MCR_DTR | UART_MCR_RTS);
 
 	/*
 	 *	If we read 0xff from the LSR, there is no UART here.
 	 */
-	if (inb(ser->port + UART_LSR) == 0xff)
+	if (serial_in(info, UART_LSR) == 0xff)
 		return -1;
+
+#if defined(CONFIG_KDB)
+	/*
+	 * Remember I/O port for kdb
+	 */
+	if (kdb_port == 0 )
+		kdb_port = ser->port;
+#endif	/* CONFIG_KDB */
+	
 	return 0;
 }
 
@@ -3559,9 +5183,14 @@
 /*
  *	Register console.
  */
-__initfunc (long serial_console_init(long kmem_start, long kmem_end))
+void __init serial_console_init(void)
 {
 	register_console(&sercons);
-	return kmem_start;
 }
 #endif
+
+/*
+  Local variables:
+  compile-command: "gcc -D__KERNEL__ -I../../include -Wall -Wstrict-prototypes -O2 -fomit-frame-pointer -fno-strict-aliasing -D__SMP__ -pipe -fno-strength-reduce -march=i586 -DMODULE -DMODVERSIONS -include ../../include/linux/modversions.h   -DEXPORT_SYMTAB -c serial.c"
+  End:
+*/
Index: oldkernel/linux/drivers/char/serial_compat.h
diff -u /dev/null linux/drivers/char/serial_compat.h:1.1
--- /dev/null	Mon Jul 31 21:15:05 2000
+++ linux/drivers/char/serial_compat.h	Fri Jul  7 16:18:17 2000
@@ -0,0 +1,388 @@
+/*
+ * Nasty compatibility functions that don't need to go into the
+ * mainline kernel.
+ */
+
+#if (LINUX_VERSION_CODE < 131343)  /* 2.1.15 -- XX get correct version */
+#define __init
+#endif
+
+#if (LINUX_VERSION_CODE < 0x20000)
+typedef dev_t kdev_t;
+#endif
+
+#if (LINUX_VERSION_CODE < 0x02017E)
+static signed long schedule_timeout(signed long timeout)
+{
+	unsigned long expire;
+
+	expire = timeout + jiffies;
+
+	current->timeout = jiffies + timeout;
+	schedule();
+
+	timeout = expire - jiffies;
+	return timeout < 0 ? 0 : timeout;
+}
+#endif
+
+#ifndef time_after
+#define time_after(a,b)		((long)(b) - (long)(a) < 0)
+#endif
+
+#if (LINUX_VERSION_CODE < 0x020100)
+static inline int irq_cannonicalize(int irq)
+{
+	return ((irq == 2) ? 9 : irq);
+}
+#endif
+
+#if (LINUX_VERSION_CODE < 131336)
+static int copy_from_user(void *to, const void *from_user, unsigned long len)
+{
+	int	error;
+
+	error = verify_area(VERIFY_READ, from_user, len);
+	if (error)
+		return len;
+	memcpy_fromfs(to, from_user, len);
+	return 0;
+}
+
+static int copy_to_user(void *to_user, const void *from, unsigned long len)
+{
+	int	error;
+	
+	error = verify_area(VERIFY_WRITE, to_user, len);
+	if (error)
+		return len;
+	memcpy_tofs(to_user, from, len);
+	return 0;
+}
+
+static inline int signal_pending(struct task_struct *p)
+{
+	return (p->signal & (~p->blocked != 0));
+}
+
+#endif
+
+#if (LINUX_VERSION_CODE < 131394) /* 2.1.66 */
+#define test_and_clear_bit(x,y)		clear_bit(x,y)
+
+static inline void remove_bh(int nr)
+{
+	bh_base[nr] = NULL;
+	bh_mask &= ~(1 << nr);
+}
+#endif
+
+#ifndef set_current_state
+#define set_current_state(state_value)			\
+	do { current->state = state_value; } while (0)
+#endif
+
+#ifndef DECLARE_WAITQUEUE
+#define DECLARE_WAITQUEUE(wait, current) \
+	struct wait_queue wait = { current, NULL }
+#define init_waitqueue_head(head)	init_waitqueue(head)
+#endif
+
+#ifndef CAP_SYS_ADMIN
+#define capable(x)	(suser())
+#endif
+	
+#if (LINUX_VERSION_CODE < 0x020317) /* 2.3.23 */
+#define get_zeroed_page(x)	get_free_page(x)
+#endif
+
+/* Deal with the interface change in 2.3.23 */
+#if defined(CONFIG_SERIAL_CONSOLE) && (LINUX_VERSION_CODE < 0x020317)
+void __init serial_console_init_real(void);
+long __init serial_console_init(long kmem_start, long kmem_end)
+{
+	serial_console_init_real();
+	return kmem_start;
+}
+
+#define serial_console_init	serial_console_init_real
+
+#endif
+
+#ifndef pci_for_each_dev
+#define pci_for_each_dev(dev) for (dev=pci_devices;dev;dev=dev->next)
+
+/*
+ * New kernels define dev->subsystem_vendor and dev->subsystem device,
+ * which we don't have.  So we have to play some games...
+ */
+	static u16 compat__tmp;
+
+#define pci_get_subvendor(dev) (pci_read_config_word(dev, \
+		PCI_SUBSYSTEM_VENDOR_ID, &compat__tmp), compat__tmp)
+#define pci_get_subdevice(dev) (pci_read_config_word(dev, \
+		PCI_SUBSYSTEM_ID, &compat__tmp), compat__tmp)
+
+#endif
+
+#ifndef PCI_NUM_RESOURCES
+#define IS_PCI_REGION_IOPORT(dev, r) (((dev)->base_address[(r)] & \
+				       PCI_BASE_ADDRESS_SPACE))
+#define pci_resource_start(dev, r) ((dev)->base_address[(r)] & \
+	(IS_PCI_REGION_IOPORT(dev, r) ? PCI_BASE_ADDRESS_IO_MASK : \
+	 PCI_BASE_ADDRESS_MEM_MASK))
+/* Too hard to figure out, so we just return a minimum size. */
+#define pci_resource_len(dev, r) 8
+#endif	
+
+#ifndef DEVICE_COUNT_IRQ
+#define PCI_IRQ_RESOURCE(dev, r) ((dev)->irq)
+
+/*
+ * Old kernels don't have ISAPNP support, so they don't have
+ * dev->prepare and dev->activate.  Compensate.
+ */
+#define PREPARE_FUNC(dev)  ((int (*)(struct pci_dev *)) 0)
+#define ACTIVATE_FUNC(dev)  ((int (*)(struct pci_dev *)) 0)
+#define DEACTIVATE_FUNC(dev)  ((int (*)(struct pci_dev *)) 0)
+
+#endif
+
+#if (LINUX_VERSION_CODE <= 0x2032D)
+static void tty_register_devfs  (struct tty_driver *driver, unsigned int flags,
+				 unsigned int minor)
+{
+	return;
+}
+
+static void tty_unregister_devfs (struct tty_driver *driver, unsigned minor)
+{
+	return;
+}
+#endif
+
+/*
+ * Compatibility with the new module_init() code
+ */
+#ifndef module_init
+#ifdef MODULE
+#define module_init(x)	int init_module(void) { return x(); }
+#define module_exit(x)	void cleanup_module(void) { x(); }
+#else
+#define module_init(x)	/* nothing */
+#define module_exit(x)	/* nothing */
+#endif
+#endif	/* module_init */
+
+
+/* New termbits definitions */
+#ifndef TIOCM_OUT1
+#define TIOCM_OUT1	0x2000
+#define TIOCM_OUT2	0x4000
+#endif
+
+#ifndef TIOCM_LOOP
+#define TIOCM_LOOP	0x8000
+#endif
+
+#ifndef TTY_DRIVER_NO_DEVFS
+#define TTY_DRIVER_NO_DEVFS 0
+#endif
+
+/* Define new-style CPU configs */
+#if (defined(__i386__) && (defined(CPU)))
+#if CPU == 386
+#define CONFIG_M386
+#endif
+#if CPU == 486
+#define CONFIG_M486
+#endif
+#endif
+
+/*
+ * Some PCI identifiers which might not be in pci.h
+ */
+
+#ifndef PCI_VENDOR_ID_V3
+#define PCI_VENDOR_ID_V3		0x11b0
+#define PCI_DEVICE_ID_V3_V960		0x0001
+#define PCI_DEVICE_ID_V3_V350		0x0001
+#define PCI_DEVICE_ID_V3_V960V2		0x0002
+#define PCI_DEVICE_ID_V3_V350V2		0x0002
+#endif
+
+#ifndef PCI_VENDOR_ID_SEALEVEL
+#define PCI_VENDOR_ID_SEALEVEL		0x135e
+#define PCI_DEVICE_ID_SEALEVEL_U530	0x7101
+#define PCI_DEVICE_ID_SEALEVEL_UCOMM2	0x7201
+#define PCI_DEVICE_ID_SEALEVEL_UCOMM422	0x7402
+#define PCI_DEVICE_ID_SEALEVEL_UCOMM232	0x7202
+#define PCI_DEVICE_ID_SEALEVEL_COMM4	0x7401
+#define PCI_DEVICE_ID_SEALEVEL_COMM8	0x7801
+#endif
+	
+#ifndef PCI_SUBVENDOR_ID_CONNECT_TECH
+#define PCI_SUBVENDOR_ID_CONNECT_TECH			0x12c4
+#define PCI_SUBDEVICE_ID_CONNECT_TECH_BH8_232		0x0001
+#define PCI_SUBDEVICE_ID_CONNECT_TECH_BH4_232		0x0002
+#define PCI_SUBDEVICE_ID_CONNECT_TECH_BH2_232		0x0003
+#define PCI_SUBDEVICE_ID_CONNECT_TECH_BH8_485		0x0004
+#define PCI_SUBDEVICE_ID_CONNECT_TECH_BH8_485_4_4	0x0005
+#define PCI_SUBDEVICE_ID_CONNECT_TECH_BH4_485		0x0006
+#define PCI_SUBDEVICE_ID_CONNECT_TECH_BH4_485_2_2	0x0007
+#define PCI_SUBDEVICE_ID_CONNECT_TECH_BH2_485		0x0008
+#endif
+
+#ifndef PCI_SUBVENDOR_ID_KEYSPAN
+#define PCI_SUBVENDOR_ID_KEYSPAN 			0x11a9
+#define PCI_SUBDEVICE_ID_KEYSPAN_SX2			0x5334
+#endif
+
+#ifndef PCI_DEVICE_ID_PLX_GTEK_SERIAL2
+#define PCI_DEVICE_ID_PLX_GTEK_SERIAL2	0xa001
+#endif
+
+#ifndef PCI_DEVICE_ID_PLX_SPCOM200
+#define PCI_DEVICE_ID_PLX_SPCOM200 0x1103
+#endif
+	
+#ifndef PCI_DEVICE_ID_PLX_SPCOM800
+#define PCI_DEVICE_ID_PLX_SPCOM800 0x1076
+#endif
+
+#ifndef PCI_VENDOR_ID_PLX_ROMULUS
+#define PCI_VENDOR_ID_PLX_ROMULUS	0x106a
+#endif	
+
+#ifndef PCI_VENDOR_ID_TITAN
+#define PCI_VENDOR_ID_TITAN		0x14D2
+#define PCI_DEVICE_ID_TITAN_100		0xA001
+#define PCI_DEVICE_ID_TITAN_200		0xA005
+#define PCI_DEVICE_ID_TITAN_400		0xA003
+#define PCI_DEVICE_ID_TITAN_800B	0xA004
+#endif
+
+#ifndef PCI_VENDOR_ID_PANACOM
+#define PCI_VENDOR_ID_PANACOM             0x14d4
+#define PCI_DEVICE_ID_PANACOM_QUADMODEM   0x0400
+#define PCI_DEVICE_ID_PANACOM_DUALMODEM   0x0402
+#endif
+
+#ifndef PCI_SUBVENDOR_ID_CHASE_PCIFAST
+#define PCI_SUBVENDOR_ID_CHASE_PCIFAST		0x12E0
+#define PCI_SUBDEVICE_ID_CHASE_PCIFAST4		0x0031
+#define PCI_SUBDEVICE_ID_CHASE_PCIFAST8		0x0021
+#define PCI_SUBDEVICE_ID_CHASE_PCIFAST16	0x0011
+#define PCI_SUBDEVICE_ID_CHASE_PCIFAST16FMC	0x0041
+#define PCI_SUBVENDOR_ID_CHASE_PCIRAS		0x124D
+#define PCI_SUBDEVICE_ID_CHASE_PCIRAS4		0xF001
+#define PCI_SUBDEVICE_ID_CHASE_PCIRAS8		0xF010
+#endif
+
+#ifndef PCI_VENDOR_ID_QUATECH
+#define PCI_VENDOR_ID_QUATECH		0x135C
+#define PCI_DEVICE_ID_QUATECH_QSC100	0x0010
+#define PCI_DEVICE_ID_QUATECH_DSC100	0x0020
+#define PCI_DEVICE_ID_QUATECH_DSC200	0x0030
+#define PCI_DEVICE_ID_QUATECH_QSC200	0x0040
+#define PCI_DEVICE_ID_QUATECH_ESC100D	0x0050
+#define PCI_DEVICE_ID_QUATECH_ESC100M	0x0060
+#endif
+
+#ifndef PCI_VENDOR_ID_ROCKWELL
+#define PCI_VENDOR_ID_ROCKWELL		0x127A
+#endif
+
+#ifndef PCI_VENDOR_ID_USR
+#define PCI_VENDOR_ID_USR		0x12B9
+#endif
+
+#ifndef PCI_SUBDEVICE_ID_SPECIALIX_SPEED4
+#define PCI_SUBDEVICE_ID_SPECIALIX_SPEED4 0xa004
+#endif
+
+#ifndef PCI_VENDOR_ID_OXSEMI
+#define PCI_VENDOR_ID_OXSEMI            0x1415
+#define PCI_DEVICE_ID_OXSEMI_16PCI954   0x9501
+#endif
+
+#ifndef PCI_DEVICE_ID_OXSEMI_16PCI952
+#define PCI_DEVICE_ID_OXSEMI_16PCI952	0x950A
+#define PCI_DEVICE_ID_OXSEMI_16PCI95N	0x9511
+#endif
+
+#ifndef PCI_VENDOR_ID_LAVA
+#define PCI_VENDOR_ID_LAVA		0x1407
+#endif
+
+#ifndef PCI_DEVICE_ID_LAVA_DSERIAL
+#define PCI_DEVICE_ID_LAVA_DSERIAL	0x0100 /* 2x 16550 */
+#define PCI_DEVICE_ID_LAVA_QUATRO_A	0x0101 /* 2x 16550, half of 4 port */
+#define PCI_DEVICE_ID_LAVA_QUATRO_B	0x0102 /* 2x 16550, half of 4 port */
+#define PCI_DEVICE_ID_LAVA_PORT_PLUS	0x0200 /* 2x 16650 */
+#define PCI_DEVICE_ID_LAVA_QUAD_A	0x0201 /* 2x 16650, half of 4 port */
+#define PCI_DEVICE_ID_LAVA_QUAD_B	0x0202 /* 2x 16650, half of 4 port */
+#define PCI_DEVICE_ID_LAVA_SSERIAL	0x0500 /* 1x 16550 */
+#define PCI_DEVICE_ID_LAVA_PORT_650	0x0600 /* 1x 16650 */
+#endif
+	
+#ifndef PCI_VENDOR_ID_TIMEDIA
+#define PCI_VENDOR_ID_TIMEDIA		0x1409
+#define PCI_DEVICE_ID_TIMEDIA_1889	0x7168
+#endif 
+
+#ifndef PCI_VENDOR_ID_SIIG
+#define PCI_VENDOR_ID_SIIG		0x131f
+#endif
+
+#ifndef PCI_DEVICE_ID_SIIG_1S_10x_550
+#define PCI_DEVICE_ID_SIIG_1S_10x_550  0x1000
+#define PCI_DEVICE_ID_SIIG_1S_10x_650  0x1001
+#define PCI_DEVICE_ID_SIIG_1S_10x_850  0x1002
+#define PCI_DEVICE_ID_SIIG_2S_10x_550  0x1030
+#define PCI_DEVICE_ID_SIIG_2S_10x_650  0x1031
+#define PCI_DEVICE_ID_SIIG_2S_10x_850  0x1032
+#define PCI_DEVICE_ID_SIIG_4S_10x_550  0x1050
+#define PCI_DEVICE_ID_SIIG_4S_10x_650  0x1051
+#define PCI_DEVICE_ID_SIIG_4S_10x_850  0x1052
+#define PCI_DEVICE_ID_SIIG_1S_20x_550  0x2000
+#define PCI_DEVICE_ID_SIIG_1S_20x_650  0x2001
+#define PCI_DEVICE_ID_SIIG_1S_20x_850  0x2002
+#define PCI_DEVICE_ID_SIIG_2S_20x_550  0x2030
+#define PCI_DEVICE_ID_SIIG_2S_20x_650  0x2031
+#define PCI_DEVICE_ID_SIIG_2S_20x_850  0x2032
+#define PCI_DEVICE_ID_SIIG_4S_20x_550  0x2050
+#define PCI_DEVICE_ID_SIIG_4S_20x_650  0x2051
+#define PCI_DEVICE_ID_SIIG_4S_20x_850  0x2052
+#define PCI_DEVICE_ID_SIIG_1S1P_10x_550	0x1010
+#define PCI_DEVICE_ID_SIIG_1S1P_10x_650	0x1011
+#define PCI_DEVICE_ID_SIIG_1S1P_10x_850	0x1012
+#define PCI_DEVICE_ID_SIIG_2S1P_10x_550	0x1034
+#define PCI_DEVICE_ID_SIIG_2S1P_10x_650	0x1035
+#define PCI_DEVICE_ID_SIIG_2S1P_10x_850	0x1036
+#define PCI_DEVICE_ID_SIIG_2P1S_20x_550	0x2040
+#define PCI_DEVICE_ID_SIIG_2P1S_20x_650	0x2041
+#define PCI_DEVICE_ID_SIIG_2P1S_20x_850	0x2042
+#define PCI_DEVICE_ID_SIIG_1S1P_20x_550	0x2010
+#define PCI_DEVICE_ID_SIIG_1S1P_20x_650	0x2011
+#define PCI_DEVICE_ID_SIIG_1S1P_20x_850	0x2012
+#define PCI_DEVICE_ID_SIIG_2S1P_20x_550	0x2060
+#define PCI_DEVICE_ID_SIIG_2S1P_20x_650	0x2061
+#define PCI_DEVICE_ID_SIIG_2S1P_20x_850	0x2062
+#endif
+
+#ifndef PCI_VENDOR_ID_COMPUTONE
+#define PCI_VENDOR_ID_COMPUTONE			0x8e0e
+#endif
+
+#ifndef PCI_DEVICE_ID_COMPUTONE_PG
+#define PCI_DEVICE_ID_COMPUTONE_PG		0x0302
+#define PCI_SUBVENDOR_ID_COMPUTONE		0x8e0e
+#define PCI_SUBDEVICE_ID_COMPUTONE_PG4	0x0001
+#define PCI_SUBDEVICE_ID_COMPUTONE_PG8	0x0002
+#define PCI_SUBDEVICE_ID_COMPUTONE_PG6	0x0003
+#endif
+
+#ifndef PCI_DEVICE_ID_ATT_VENUS_MODEM
+#define PCI_DEVICE_ID_ATT_VENUS_MODEM	0x480
+#endif
Index: oldkernel/linux/drivers/char/synclink.c
diff -u linux/drivers/char/synclink.c:1.1.1.1 linux/drivers/char/synclink.c:1.2
--- linux/drivers/char/synclink.c:1.1.1.1	Wed May 31 12:33:51 2000
+++ linux/drivers/char/synclink.c	Fri Jul  7 15:36:43 2000
@@ -3900,7 +3900,7 @@
 done:
 	if (off >= len+begin)
 		return 0;
-	*start = page + (begin-off);
+	*start = page + (off-begin);
 	return ((count < begin+len-off) ? count : begin+len-off);
 	
 }	/* end of mgsl_read_proc() */
Index: oldkernel/linux/drivers/isdn/avmb1/capi.c
diff -u linux/drivers/isdn/avmb1/capi.c:1.1.1.1 linux/drivers/isdn/avmb1/capi.c:1.2
--- linux/drivers/isdn/avmb1/capi.c:1.1.1.1	Wed May 31 12:33:52 2000
+++ linux/drivers/isdn/avmb1/capi.c	Fri Jul  7 15:36:43 2000
@@ -561,7 +561,7 @@
 		*eof = 1;
 	if (off >= len+begin)
 		return 0;
-	*start = page + (begin-off);
+	*start = page + (off-begin);
 	return ((count < begin+len-off) ? count : begin+len-off);
 }
 
Index: oldkernel/linux/drivers/isdn/avmb1/kcapi.c
diff -u linux/drivers/isdn/avmb1/kcapi.c:1.1.1.1 linux/drivers/isdn/avmb1/kcapi.c:1.2
--- linux/drivers/isdn/avmb1/kcapi.c:1.1.1.1	Wed May 31 12:33:52 2000
+++ linux/drivers/isdn/avmb1/kcapi.c	Fri Jul  7 15:36:43 2000
@@ -250,7 +250,7 @@
 		*eof = 1;
 	if (off >= len+begin)
 		return 0;
-	*start = page + (begin-off);
+	*start = page + (off-begin);
 	return ((count < begin+len-off) ? count : begin+len-off);
 }
 
@@ -289,7 +289,7 @@
 		*eof = 1;
 	if (off >= len+begin)
 		return 0;
-	*start = page + (begin-off);
+	*start = page + (off-begin);
 	return ((count < begin+len-off) ? count : begin+len-off);
 }
 
@@ -321,7 +321,7 @@
 		*eof = 1;
 	if (off >= len+begin)
 		return 0;
-	*start = page + (begin-off);
+	*start = page + (off-begin);
 	return ((count < begin+len-off) ? count : begin+len-off);
 }
 
@@ -350,7 +350,7 @@
 		*eof = 1;
 	if (off >= len+begin)
 		return 0;
-	*start = page + (begin-off);
+	*start = page + (off-begin);
 	return ((count < begin+len-off) ? count : begin+len-off);
 }
 
@@ -387,7 +387,7 @@
 		*eof = 1;
 	if (off >= len+begin)
 		return 0;
-	*start = page + (begin-off);
+	*start = page + (off-begin);
 	return ((count < begin+len-off) ? count : begin+len-off);
 }
 
@@ -424,7 +424,7 @@
 		*eof = 1;
 	if (off >= len+begin)
 		return 0;
-	*start = page + (begin-off);
+	*start = page + (off-begin);
 	return ((count < begin+len-off) ? count : begin+len-off);
 }
 
@@ -461,7 +461,7 @@
 		*eof = 1;
 	if (off >= len+begin)
 		return 0;
-	*start = page + (begin-off);
+	*start = page + (off-begin);
 	return ((count < begin+len-off) ? count : begin+len-off);
 }
 
Index: oldkernel/linux/drivers/net/acenic.c
diff -u linux/drivers/net/acenic.c:1.2 linux/drivers/net/acenic.c:1.3
--- linux/drivers/net/acenic.c:1.2	Thu Jun  1 15:47:21 2000
+++ linux/drivers/net/acenic.c	Fri Jul  7 15:36:43 2000
@@ -29,6 +29,7 @@
  *                                       infrastructure and Sparc support
  *   Pierrick Pinasseau (CERN): For lending me an Ultra 5 to test the
  *                              driver under Linux/Sparc64
+ *   Matt Domsch <Matt_Domsch@dell.com>: Detect 1000baseT cards
  */
 
 #include <linux/config.h>
@@ -70,8 +71,11 @@
 
 #ifndef PCI_VENDOR_ID_ALTEON
 #define PCI_VENDOR_ID_ALTEON		0x12ae	
-#define PCI_DEVICE_ID_ALTEON_ACENIC	0x0001
 #endif
+#ifndef PCI_DEVICE_ID_ALTEON_ACENIC_FIBRE
+#define PCI_DEVICE_ID_ALTEON_ACENIC_FIBRE  0x0001
+#define PCI_DEVICE_ID_ALTEON_ACENIC_COPPER 0x0002
+#endif
 #ifndef PCI_DEVICE_ID_3COM_3C985
 #define PCI_DEVICE_ID_3COM_3C985	0x0001
 #endif
@@ -83,13 +87,13 @@
  * They used the DEC vendor ID by mistake
  */
 #ifndef PCI_DEVICE_ID_FARALLON_PN9000SX
-#define PCI_DEVICE_ID_FARALLON_PN9000SX 0x1a
+#define PCI_DEVICE_ID_FARALLON_PN9000SX	0x1a
 #endif
 #ifndef PCI_VENDOR_ID_SGI
-#define PCI_VENDOR_ID_SGI             0x10a9
+#define PCI_VENDOR_ID_SGI		0x10a9
 #endif
 #ifndef PCI_DEVICE_ID_SGI_ACENIC
-#define PCI_DEVICE_ID_SGI_ACENIC      0x0009
+#define PCI_DEVICE_ID_SGI_ACENIC	0x0009
 #endif
 
 #ifndef wmb
@@ -100,6 +104,17 @@
 #define __exit
 #endif
 
+#ifndef SMP_CACHE_BYTES
+#define SMP_CACHE_BYTES	L1_CACHE_BYTES
+#endif
+
+
+#if (LINUX_VERSION_CODE < 0x02030d)
+#define pci_resource_start(dev, bar)	dev->base_address[bar]
+#elif (LINUX_VERSION_CODE < 0x02032c)
+#define pci_resource_start(dev, bar)	dev->resource[bar].start
+#endif
+
 #if (LINUX_VERSION_CODE < 0x02030e)
 #define net_device device
 #endif
@@ -121,8 +136,8 @@
 	return virt_ptr;
 }
 #define pci_free_consistent(cookie, size, ptr, dma_ptr)	kfree(ptr)
-#define pci_map_single(cookie, address, size)		virt_to_bus(address)
-#define pci_unmap_single(cookie, address, size)
+#define pci_map_single(cookie, address, size, dir)	virt_to_bus(address)
+#define pci_unmap_single(cookie, address, size, dir)
 #endif
 
 #if (LINUX_VERSION_CODE < 0x02032b)
@@ -140,18 +155,22 @@
 	dev->start = 1;
 }
 
-#define ace_mark_net_bh(foo)				mark_bh(foo)
-#define ace_if_busy(dev)	dev->tbusy
-#define ace_if_running(dev)	dev->start
-#define ace_if_down(dev)	{do{dev->start = 0;}while (0);}
+#define ace_mark_net_bh(foo)		mark_bh(foo)
+#define netif_queue_stopped(dev)	dev->tbusy
+#define netif_running(dev)		dev->start
+#define ace_if_down(dev)		{do{dev->start = 0;}while (0);}
 #else
 #define NET_BH			0
 #define ace_mark_net_bh(foo)	{do{} while(0);}
-#define ace_if_busy(dev)	test_bit(LINK_STATE_XOFF, &dev->state)
-#define ace_if_running(dev)	test_bit(LINK_STATE_START, &dev->state)
 #define ace_if_down(dev)	{do{} while(0);}
 #endif
 
+
+#define ACE_MAX_MOD_PARMS	8
+#define BOARD_IDX_STATIC	0
+#define BOARD_IDX_OVERFLOW	-1
+
+
 #include "acenic.h"
 
 /*
@@ -336,30 +355,41 @@
 #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
 /*
  * There seems to be a magic difference in the effect between 995 and 996
  * but little difference between 900 and 995 ... no idea why.
+ *
+ * There is now a default set of tuning parameters which is set, depending
+ * on whether or not the user enables Jumbo frames. It's assumed that if
+ * Jumbo frames are enabled, the user wants optimal tuning for that case.
  */
-#define DEF_TX_COAL		996
+#define DEF_TX_COAL		400 /* 996 */
 #define DEF_TX_MAX_DESC		40
-#define DEF_RX_COAL		1000
+#define DEF_RX_COAL		120 /* 1000 */
 #define DEF_RX_MAX_DESC		25
+#define DEF_TX_RATIO		21 /* 24 */
+
+#define DEF_JUMBO_TX_COAL	20
+#define DEF_JUMBO_TX_MAX_DESC	60
+#define DEF_JUMBO_RX_COAL	30
+#define DEF_JUMBO_RX_MAX_DESC	6
+#define DEF_JUMBO_TX_RATIO	21
+
 #define TX_COAL_INTS_ONLY	0	/* seems not worth it */
 #define DEF_TRACE		0
-#define DEF_STAT		2 * TICKS_PER_SEC
+#define DEF_STAT		(2 * TICKS_PER_SEC)
 
-static int link[8] = {0, };
-static int trace[8] = {0, };
-static int tx_coal_tick[8] = {0, };
-static int rx_coal_tick[8] = {0, };
-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 int link[ACE_MAX_MOD_PARMS] = {0, };
+static int trace[ACE_MAX_MOD_PARMS] = {0, };
+static int tx_coal_tick[ACE_MAX_MOD_PARMS] = {0, };
+static int rx_coal_tick[ACE_MAX_MOD_PARMS] = {0, };
+static int max_tx_desc[ACE_MAX_MOD_PARMS] = {0, };
+static int max_rx_desc[ACE_MAX_MOD_PARMS] = {0, };
+static int tx_ratio[ACE_MAX_MOD_PARMS] = {0, };
+static int dis_pci_mem_inval[ACE_MAX_MOD_PARMS] = {1, 1, 1, 1, 1, 1, 1, 1};
 
 static const char __initdata *version = 
-  "acenic.c: v0.41 02/16/2000  Jes Sorensen, linux-acenic@SunSITE.auc.dk\n"
+  "acenic.c: v0.44 05/11/2000  Jes Sorensen, linux-acenic@SunSITE.auc.dk\n"
   "                            http://home.cern.ch/~jes/gige/acenic.html\n";
 
 static struct net_device *root_dev = NULL;
@@ -394,7 +424,8 @@
 	while ((pdev = pci_find_class(PCI_CLASS_NETWORK_ETHERNET<<8, pdev))) {
 
 		if (!((pdev->vendor == PCI_VENDOR_ID_ALTEON) &&
-		      (pdev->device == PCI_DEVICE_ID_ALTEON_ACENIC)) &&
+		      ((pdev->device == PCI_DEVICE_ID_ALTEON_ACENIC_FIBRE) ||
+		       (pdev->device == PCI_DEVICE_ID_ALTEON_ACENIC_COPPER)) ) &&
 		    !((pdev->vendor == PCI_VENDOR_ID_3COM) &&
 		      (pdev->device == PCI_DEVICE_ID_3COM_3C985)) &&
 		    !((pdev->vendor == PCI_VENDOR_ID_NETGEAR) &&
@@ -469,22 +500,12 @@
 
 		pci_set_master(pdev);
 
-#ifdef __sparc__
-		/* NOTE: Cache line size is in 32-bit word units. */
-		pci_write_config_byte(pdev, PCI_CACHE_LINE_SIZE, 0x10);
-#endif
-
 		/*
 		 * 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
-
+		dev->base_addr = pci_resource_start(pdev, 0);
 		ap->regs = (struct ace_regs *)ioremap(dev->base_addr, 0x4000);
 		if (!ap->regs) {
 			printk(KERN_ERR "%s:  Unable to map I/O register, "
@@ -540,8 +561,7 @@
 		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);
+			ace_init_cleanup(dev);
 			continue;
 		}
 #endif
@@ -550,13 +570,17 @@
 			continue;
 
 #ifdef MODULE
-		if (ace_init(dev, boards_found))
-			continue;
+		if (boards_found >= ACE_MAX_MOD_PARMS)
+			ap->board_idx = BOARD_IDX_OVERFLOW;
+		else
+			ap->board_idx = boards_found;
 #else
-		if (ace_init(dev, -1))
-			continue;
+		ap->board_idx = BOARD_IDX_STATIC;
 #endif
 
+		if (ace_init(dev))
+			continue;
+
 		boards_found++;
 	}
 
@@ -566,20 +590,16 @@
 	 * or more boards. Otherwise, return failure (-ENODEV).
 	 */
 
-#ifdef MODULE
-	return boards_found;
-#else
 	if (boards_found > 0)
 		return 0;
 	else
 		return -ENODEV;
-#endif
 }
 
 
 #ifdef MODULE
 MODULE_AUTHOR("Jes Sorensen <Jes.Sorensen@cern.ch>");
-MODULE_DESCRIPTION("AceNIC/3C985 Gigabit Ethernet driver");
+MODULE_DESCRIPTION("AceNIC/3C985/GA620 Gigabit Ethernet driver");
 MODULE_PARM(link, "1-" __MODULE_STRING(8) "i");
 MODULE_PARM(trace, "1-" __MODULE_STRING(8) "i");
 MODULE_PARM(tx_coal_tick, "1-" __MODULE_STRING(8) "i");
@@ -597,7 +617,7 @@
 
 	while (root_dev) {
 		next = ((struct ace_private *)root_dev->priv)->next;
-		ap = (struct ace_private *)root_dev->priv;
+		ap = root_dev->priv;
 
 		regs = ap->regs;
 
@@ -632,7 +652,8 @@
 				ap->rx_std_ring[i].size = 0;
 				ap->skb->rx_std_skbuff[i].skb = NULL;
 				pci_unmap_single(ap->pdev, mapping,
-						 ACE_STD_BUFSIZE - (2 + 16));
+						 ACE_STD_BUFSIZE - (2 + 16),
+						 PCI_DMA_FROMDEVICE);
 				dev_kfree_skb(skb);
 			}
 		}
@@ -647,7 +668,8 @@
 					ap->rx_mini_ring[i].size = 0;
 					ap->skb->rx_mini_skbuff[i].skb = NULL;
 					pci_unmap_single(ap->pdev, mapping,
-							 ACE_MINI_BUFSIZE - (2 + 16));
+							 ACE_MINI_BUFSIZE - (2 + 16),
+							 PCI_DMA_FROMDEVICE);
 					dev_kfree_skb(skb);
 				}
 			}
@@ -662,43 +684,32 @@
 				ap->rx_jumbo_ring[i].size = 0;
 				ap->skb->rx_jumbo_skbuff[i].skb = NULL;
 				pci_unmap_single(ap->pdev, mapping,
-						 ACE_JUMBO_BUFSIZE - (2 + 16));
+						 ACE_JUMBO_BUFSIZE - (2 + 16),
+						 PCI_DMA_FROMDEVICE);
 				dev_kfree_skb(skb);
 			}
 		}
-
-		ace_free_descriptors(root_dev);
 
-		if (ap->trace_buf)
-			kfree(ap->trace_buf);
-		if (ap->info)
-			pci_free_consistent(ap->pdev, sizeof(struct ace_info),
-					    ap->info, ap->info_dma);
-		if (ap->skb)
-			kfree(ap->skb);
-		if (root_dev->irq)
-			free_irq(root_dev->irq, root_dev);
-		unregister_netdev(root_dev);
-		iounmap(regs);
+		ace_init_cleanup(root_dev);
 		kfree(root_dev);
-
 		root_dev = next;
 	}
 }
+#endif
 
 
 int __init ace_module_init(void)
 {
-	int cards;
+	int status;
 
 	root_dev = NULL;
 
 #ifdef NEW_NETINIT
-	cards = acenic_probe();
+	status = acenic_probe();
 #else
-	cards = acenic_probe(NULL);
+	status = acenic_probe(NULL);
 #endif
-	return cards ? 0 : -ENODEV;
+	return status;
 }
 
 
@@ -713,11 +724,7 @@
 {
 	ace_module_cleanup();
 }
-#endif
-#endif
-
-
-#if (LINUX_VERSION_CODE >= 0x02032a)
+#else
 module_init(ace_module_init);
 module_exit(ace_module_cleanup);
 #endif
@@ -814,10 +821,36 @@
 
 fail:
 	/* Clean up. */
+	ace_init_cleanup(dev);
+	return 1;
+}
+
+
+/*
+ * Generic cleanup handling data allocated during init. Used when the
+ * module is unloaded or if an error occurs during initialization
+ */
+static void ace_init_cleanup(struct net_device *dev)
+{
+	struct ace_private *ap;
+
+	ap = dev->priv;
+
 	ace_free_descriptors(dev);
-	iounmap(ap->regs);
+
+	if (ap->info)
+		pci_free_consistent(ap->pdev, sizeof(struct ace_info),
+				    ap->info, ap->info_dma);
+	if (ap->skb)
+		kfree(ap->skb);
+	if (ap->trace_buf)
+		kfree(ap->trace_buf);
+
+	if (dev->irq)
+		free_irq(dev->irq, dev);
+
 	unregister_netdev(dev);
-	return 1;
+	iounmap(ap->regs);
 }
 
 
@@ -837,19 +870,22 @@
 }
 
 
-static int __init ace_init(struct net_device *dev, int board_idx)
+static int __init ace_init(struct net_device *dev)
 {
 	struct ace_private *ap;
 	struct ace_regs *regs;
 	struct ace_info *info = NULL;
 	unsigned long tmp_ptr, myjif;
 	u32 tig_ver, mac1, mac2, tmp, pci_state;
-	int ecode = 0;
+	int board_idx, ecode = 0;
 	short i;
+	unsigned char cache;
 
 	ap = dev->priv;
 	regs = ap->regs;
 
+	board_idx = ap->board_idx;
+
 	/*
 	 * aman@sgi.com - its useful to do a NIC reset here to
 	 * address the `Firmware not running' problem subsequent
@@ -965,6 +1001,21 @@
 	dev->dev_addr[4] = (mac2 >> 8) & 0xff;
 	dev->dev_addr[5] = mac2 & 0xff;
 
+	/*
+	 * Looks like this is necessary to deal with on all architectures,
+	 * even this %$#%$# N440BX Intel based thing doesn't get it right.
+	 * Ie. having two NICs in the machine, one will have the cache
+	 * line set at boot time, the other will not.
+	 */
+	pci_read_config_byte(ap->pdev, PCI_CACHE_LINE_SIZE, &cache);
+	if ((cache << 2) != SMP_CACHE_BYTES) {
+		printk(KERN_INFO "  PCI cache line size set incorrectly "
+		       "(%i bytes) by BIOS/FW, corring to %i\n",
+		       (cache << 2), SMP_CACHE_BYTES);
+		pci_write_config_byte(ap->pdev, PCI_CACHE_LINE_SIZE,
+				      SMP_CACHE_BYTES >> 2);
+	}
+
 	pci_state = readl(&regs->PciState);
 	printk(KERN_INFO "  PCI bus width: %i bits, speed: %iMHz, "
 	       "latency: %i clks\n",
@@ -988,19 +1039,20 @@
 		/*
 		 * Tuning parameters only supported for 8 cards
 		 */
-		if (board_idx > 7 || dis_pci_mem_inval[board_idx]) {
+		if (board_idx == BOARD_IDX_OVERFLOW ||
+		    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);
+				printk(KERN_INFO "  Disabling PCI memory "
+				       "write and invalidate\n");
 			}
 		} 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) {
+			printk(KERN_INFO "  PCI memory write & invalidate "
+			       "enabled by BIOS, enabling counter measures\n");
+			
+			switch(SMP_CACHE_BYTES) {
 			case 16:
 				tmp |= DMA_WRITE_MAX_16;
 				break;
@@ -1020,8 +1072,37 @@
 			}
 		}
 	}
+
+#ifdef __sparc__
+	/*
+	 * On this platform, we know what the best dma settings
+	 * are.  We use 64-byte maximum bursts, because if we
+	 * burst larger than the cache line size (or even cross
+	 * a 64byte boundry in a single burst) the UltraSparc
+	 * PCI controller will disconnect at 64-byte multiples.
+	 *
+	 * Read-multiple will be properly enabled above, and when
+	 * set will give the PCI controller proper hints about
+	 * prefetching.
+	 */
+	tmp = tmp & ~DMA_READ_WRITE_MASK;
+	tmp |= DMA_READ_MAX_64;
+	tmp |= DMA_WRITE_MAX_64;
+#endif
 	writel(tmp, &regs->PciState);
 
+#if 0
+	/*
+	 * I have received reports from people having problems when this
+	 * bit is enabled.
+	 */
+	if (!(ap->pci_command & PCI_COMMAND_FAST_BACK)) {
+		printk(KERN_INFO "  Enabling PCI Fast Back to Back\n");
+		ap->pci_command |= PCI_COMMAND_FAST_BACK;
+		pci_write_config_word(ap->pdev, PCI_COMMAND, ap->pci_command);
+	}
+#endif
+		
 	/*
 	 * Initialize the generic info block and the command+event rings
 	 * and the control blocks for the transmit and receive rings
@@ -1195,21 +1276,15 @@
 	writel(1, &regs->AssistState);
 
 	writel(DEF_STAT, &regs->TuneStatTicks);
-
-	writel(DEF_TX_COAL, &regs->TuneTxCoalTicks);
-	writel(DEF_TX_MAX_DESC, &regs->TuneMaxTxDesc);
-	writel(DEF_RX_COAL, &regs->TuneRxCoalTicks);
-	writel(DEF_RX_MAX_DESC, &regs->TuneMaxRxDesc);
 	writel(DEF_TRACE, &regs->TuneTrace);
-	writel(DEF_TX_RATIO, &regs->TxBufRat);
 
-	if (board_idx >= 8) {
-		printk(KERN_WARNING "%s: more then 8 NICs detected, "
-		       "ignoring module parameters!\n", dev->name);
-		board_idx = -1;
-	}
+	ace_set_rxtx_parms(dev, 0);
 
-	if (board_idx >= 0) {
+	if (board_idx == BOARD_IDX_OVERFLOW) {
+		printk(KERN_WARNING "%s: more then %i NICs detected, "
+		       "ignoring module parameters!\n",
+		       dev->name, ACE_MAX_MOD_PARMS);
+	} else if (board_idx >= 0) {
 		if (tx_coal_tick[board_idx])
 			writel(tx_coal_tick[board_idx],
 			       &regs->TuneTxCoalTicks);
@@ -1334,8 +1409,6 @@
 			writel(readl(&regs->CpuBCtrl) | CPU_HALT,
 			       &regs->CpuBCtrl);
 		writel(0, &regs->Mb0Lo);
-		free_irq(dev->irq, dev);
-		dev->irq = 0;
 
 		ecode = -EBUSY;
 		goto init_error;
@@ -1358,27 +1431,63 @@
 			       "the RX mini ring\n", dev->name);
 	}
 	return 0;
+
  init_error:
-	iounmap(ap->regs);
-	unregister_netdev(dev);
-	if (ap->skb) {
-		kfree(ap->skb);
-		ap->skb = NULL;
-	}
-	if (ap->info)
-		pci_free_consistent(ap->pdev, sizeof(struct ace_info),
-				    info, ap->info_dma);
+	ace_init_cleanup(dev);
 	return ecode;
 }
 
 
+static void ace_set_rxtx_parms(struct net_device *dev, int jumbo)
+{
+	struct ace_private *ap;
+	struct ace_regs *regs;
+	int board_idx;
+
+	ap = dev->priv;
+	regs = ap->regs;
+
+	board_idx = ap->board_idx;
+
+	if (board_idx >= 0) {
+		if (!jumbo) {
+			if (!tx_coal_tick[board_idx])
+				writel(DEF_TX_COAL, &regs->TuneTxCoalTicks);
+			if (!max_tx_desc[board_idx])
+				writel(DEF_TX_MAX_DESC, &regs->TuneMaxTxDesc);
+			if (!rx_coal_tick[board_idx])
+				writel(DEF_RX_COAL, &regs->TuneRxCoalTicks);
+			if (!max_rx_desc[board_idx])
+				writel(DEF_RX_MAX_DESC, &regs->TuneMaxRxDesc);
+			if (!tx_ratio[board_idx])
+				writel(DEF_TX_RATIO, &regs->TxBufRat);
+		} else {
+			if (!tx_coal_tick[board_idx])
+				writel(DEF_JUMBO_TX_COAL,
+				       &regs->TuneTxCoalTicks);
+			if (!max_tx_desc[board_idx])
+				writel(DEF_JUMBO_TX_MAX_DESC,
+				       &regs->TuneMaxTxDesc);
+			if (!rx_coal_tick[board_idx])
+				writel(DEF_JUMBO_RX_COAL,
+				       &regs->TuneRxCoalTicks);
+			if (!max_rx_desc[board_idx])
+				writel(DEF_JUMBO_RX_MAX_DESC,
+				       &regs->TuneMaxRxDesc);
+			if (!tx_ratio[board_idx])
+				writel(DEF_JUMBO_TX_RATIO, &regs->TxBufRat);
+		}
+	}
+}
+
+
 /*
  * Monitor the card to detect hangs.
  */
 static void ace_timer(unsigned long data)
 {
 	struct net_device *dev = (struct net_device *)data;
-	struct ace_private *ap = (struct ace_private *)dev->priv;
+	struct ace_private *ap = dev->priv;
 	struct ace_regs *regs = ap->regs;
 
 	/*
@@ -1441,7 +1550,7 @@
 {
 #if 0
 	if (!ap->trace_buf)
-		if (!(ap->trace_buf = kmalloc(ACE_TRACE_SIZE, GFP_KERNEL)));
+		if (!(ap->trace_buf = kmalloc(ACE_TRACE_SIZE, GFP_KERNEL)))
 		    return;
 #endif
 }
@@ -1477,7 +1586,8 @@
 		 */
 		skb_reserve(skb, 2 + 16);
 		mapping = pci_map_single(ap->pdev, skb->data,
-					 ACE_STD_BUFSIZE - (2 + 16));
+					 ACE_STD_BUFSIZE - (2 + 16),
+					 PCI_DMA_FROMDEVICE);
 		ap->skb->rx_std_skbuff[idx].skb = skb;
 		ap->skb->rx_std_skbuff[idx].mapping = mapping;
 
@@ -1538,7 +1648,8 @@
 		 */
 		skb_reserve(skb, 2 + 16);
 		mapping = pci_map_single(ap->pdev, skb->data,
-					 ACE_MINI_BUFSIZE - (2 + 16));
+					 ACE_MINI_BUFSIZE - (2 + 16),
+					 PCI_DMA_FROMDEVICE);
 		ap->skb->rx_mini_skbuff[idx].skb = skb;
 		ap->skb->rx_mini_skbuff[idx].mapping = mapping;
 
@@ -1596,7 +1707,8 @@
 		 */
 		skb_reserve(skb, 2 + 16);
 		mapping = pci_map_single(ap->pdev, skb->data,
-					 ACE_JUMBO_BUFSIZE - (2 + 16));
+					 ACE_JUMBO_BUFSIZE - (2 + 16),
+					 PCI_DMA_FROMDEVICE);
 		ap->skb->rx_jumbo_skbuff[idx].skb = skb;
 		ap->skb->rx_jumbo_skbuff[idx].mapping = mapping;
 
@@ -1643,7 +1755,7 @@
 {
 	struct ace_private *ap;
 
-	ap = (struct ace_private *)dev->priv;
+	ap = dev->priv;
 
 	while (evtcsm != evtprd) {
 		switch (ap->evt_ring[evtcsm].evt) {
@@ -1658,16 +1770,23 @@
 		case E_LNK_STATE:
 		{
 			u16 code = ap->evt_ring[evtcsm].code;
-			if (code == E_C_LINK_UP) {
+			switch (code) {
+			case E_C_LINK_UP:
 				printk(KERN_WARNING "%s: Optical link UP\n",
 				       dev->name);
-			}
-			else if (code == E_C_LINK_DOWN)
+				break;
+			case E_C_LINK_DOWN:
 				printk(KERN_WARNING "%s: Optical link DOWN\n",
 				       dev->name);
-			else
+				break;
+			case E_C_LINK_10_100:
+				printk(KERN_WARNING "%s: 10/100BaseT link "
+				       "UP\n", dev->name);
+				break;
+			default:
 				printk(KERN_ERR "%s: Unknown optical link "
 				       "state %02x\n", dev->name, code);
+			}
 			break;
 		}
 		case E_ERROR:
@@ -1721,7 +1840,7 @@
 
 static void ace_rx_int(struct net_device *dev, u32 rxretprd, u32 rxretcsm)
 {
-	struct ace_private *ap = (struct ace_private *)dev->priv;
+	struct ace_private *ap = dev->priv;
 	u32 idx;
 	int mini_count = 0, std_count = 0;
 
@@ -1774,7 +1893,8 @@
 
 		skb = rip->skb;
 		rip->skb = NULL;
-		pci_unmap_single(ap->pdev, rip->mapping, mapsize);
+		pci_unmap_single(ap->pdev, rip->mapping, mapsize,
+				 PCI_DMA_FROMDEVICE);
 		skb_put(skb, retdesc->size);
 #if 0
 		/* unncessary */
@@ -1839,7 +1959,7 @@
 	u32 txcsm, rxretcsm, rxretprd;
 	u32 evtcsm, evtprd;
 
-	ap = (struct ace_private *)dev->priv;
+	ap = dev->priv;
 	regs = ap->regs;
 
 	/*
@@ -1877,11 +1997,16 @@
 			dma_addr_t mapping;
 
 			skb = ap->skb->tx_skbuff[idx].skb;
+			if (skb == NULL) {
+				idx = (idx + 1) % TX_RING_ENTRIES;
+				continue;
+			}
 			mapping = ap->skb->tx_skbuff[idx].mapping;
 
 			ap->stats.tx_packets++;
 			ap->stats.tx_bytes += skb->len;
-			pci_unmap_single(ap->pdev, mapping, skb->len);
+			pci_unmap_single(ap->pdev, mapping, skb->len,
+					 PCI_DMA_TODEVICE);
 			dev_kfree_skb_irq(skb);
 
 			ap->skb->tx_skbuff[idx].skb = NULL;
@@ -1907,7 +2032,7 @@
 		 * Ie. skip the comparison of the tx producer vs. the
 		 * consumer.
 		 */
-		if (ace_if_busy(dev) && xchg(&ap->tx_full, 0)) {
+		if (netif_queue_stopped(dev) && xchg(&ap->tx_full, 0)) {
 			/*
 			 * This does not need to be atomic (and expensive),
 			 * I've seen cases where it would fail otherwise ;-(
@@ -1938,7 +2063,7 @@
 	 * This has to go last in the interrupt handler and run with
 	 * the spin lock released ... what lock?
 	 */
-	if (ace_if_running(dev)) {
+	if (netif_running(dev)) {
 		int cur_size;
 		int run_bh = 0;
 
@@ -2087,7 +2212,7 @@
 	ace_if_down(dev);
 	netif_stop_queue(dev);
 
-	ap = (struct ace_private *)dev->priv;
+	ap = dev->priv;
 	regs = ap->regs;
 
 	del_timer(&ap->timer);
@@ -2122,7 +2247,8 @@
 			writel(0, &ap->tx_ring[i].addr.addrhi);
 			writel(0, &ap->tx_ring[i].addr.addrlo);
 			writel(0, &ap->tx_ring[i].flagsize);
-			pci_unmap_single(ap->pdev, mapping, skb->len);
+			pci_unmap_single(ap->pdev, mapping, skb->len,
+					 PCI_DMA_TODEVICE);
 			dev_kfree_skb(skb);
 			ap->skb->tx_skbuff[i].skb = NULL;
 		}
@@ -2144,7 +2270,7 @@
 
 static int ace_start_xmit(struct sk_buff *skb, struct net_device *dev)
 {
-	struct ace_private *ap = (struct ace_private *)dev->priv;
+	struct ace_private *ap = dev->priv;
 	struct ace_regs *regs = ap->regs;
 	unsigned long addr;
 	u32 idx, flagsize;
@@ -2172,7 +2298,8 @@
 
 	ap->skb->tx_skbuff[idx].skb = skb;
 	ap->skb->tx_skbuff[idx].mapping =
-		pci_map_single(ap->pdev, skb->data, skb->len);
+		pci_map_single(ap->pdev, skb->data, skb->len,
+			       PCI_DMA_TODEVICE);
 	addr = (unsigned long) ap->skb->tx_skbuff[idx].mapping;
 #if (BITS_PER_LONG == 64)
 	writel(addr >> 32, &ap->tx_ring[idx].addr.addrhi);
@@ -2243,12 +2370,13 @@
 			ap->jumbo = 1;
 			if (!test_and_set_bit(0, &ap->jumbo_refill_busy))
 				ace_load_jumbo_rx_ring(ap, RX_JUMBO_SIZE);
-			ap->jumbo = 1;
+			ace_set_rxtx_parms(dev, 1);
 		}
 	} else {
 		netif_stop_queue(dev);
 		while (test_and_set_bit(0, &ap->jumbo_refill_busy));
 		synchronize_irq();
+		ace_set_rxtx_parms(dev, 0);
 		if (ap->jumbo){
 			struct cmd cmd;
 
@@ -2266,7 +2394,7 @@
 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_private *ap = dev->priv;
 	struct ace_regs *regs = ap->regs;
 	struct ethtool_cmd ecmd;
 	u32 link, speed;
@@ -2408,7 +2536,7 @@
 	u16 *da;
 	struct cmd cmd;
 
-	if(ace_if_running(dev))
+	if(netif_running(dev))
 		return -EBUSY;
 
 	memcpy(dev->dev_addr, addr->sa_data,dev->addr_len);
@@ -2566,7 +2694,7 @@
 	struct ace_private *ap;
 	struct ace_regs *regs;
 
-	ap = (struct ace_private *)dev->priv;
+	ap = dev->priv;
 	regs = ap->regs;
 
 	if (!(readl(&regs->CpuCtrl) & CPU_HALTED)) {
Index: oldkernel/linux/drivers/net/acenic.h
diff -u linux/drivers/net/acenic.h:1.2 linux/drivers/net/acenic.h:1.3
--- linux/drivers/net/acenic.h:1.2	Thu Jun  1 15:47:21 2000
+++ linux/drivers/net/acenic.h	Fri Jul  7 15:36:43 2000
@@ -233,6 +233,7 @@
 #define DMA_WRITE_MAX_128	0xa0
 #define DMA_WRITE_MAX_256	0xc0
 #define DMA_WRITE_MAX_1K	0xe0
+#define DMA_READ_WRITE_MASK	0xfc
 #define MEM_READ_MULTIPLE	0x00020000
 #define PCI_66MHZ		0x00080000
 #define PCI_32BIT		0x00100000
@@ -323,7 +324,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_C_LINK_10_100		0x03
 
 #define E_ERROR			0x07
 #define E_C_ERR_INVAL_CMD	0x01
@@ -635,6 +636,7 @@
 	unsigned char		*trace_buf;
 	struct pci_dev		*pdev;
 	struct net_device	*next;
+	int			board_idx;
 	u16			pci_command;
 	u8			pci_latency;
 	char			name[48];
@@ -698,7 +700,7 @@
 /*
  * Prototypes
  */
-static int ace_init(struct net_device *dev, int board_idx);
+static int ace_init(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);
@@ -717,8 +719,10 @@
 #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 void ace_set_rxtx_parms(struct net_device *dev, int jumbo);
 static int ace_allocate_descriptors(struct net_device *dev);
 static void ace_free_descriptors(struct net_device *dev);
+static void ace_init_cleanup(struct net_device *dev);
 static struct net_device_stats *ace_get_stats(struct net_device *dev);
 static int read_eeprom_byte(struct net_device *dev, unsigned long offset);
 
Index: oldkernel/linux/drivers/net/acenic_firmware.h
diff -u linux/drivers/net/acenic_firmware.h:1.2 linux/drivers/net/acenic_firmware.h:1.3
--- linux/drivers/net/acenic_firmware.h:1.2	Thu Jun  1 15:47:21 2000
+++ linux/drivers/net/acenic_firmware.h	Fri Jul  7 15:36:43 2000
@@ -5,17 +5,17 @@
  */
 #define tigonFwReleaseMajor 0xc
 #define tigonFwReleaseMinor 0x4
-#define tigonFwReleaseFix 0x5
+#define tigonFwReleaseFix 0xb
 #define tigonFwStartAddr 0x00004000
 #define tigonFwTextAddr 0x00004000
-#define tigonFwTextLen 0x11190
-#define tigonFwRodataAddr 0x00015190
+#define tigonFwTextLen 0x11140
+#define tigonFwRodataAddr 0x00015140
 #define tigonFwRodataLen 0xac0
-#define tigonFwDataAddr 0x00015c80
+#define tigonFwDataAddr 0x00015c20
 #define tigonFwDataLen 0x170
-#define tigonFwSbssAddr 0x00015df0
-#define tigonFwSbssLen 0x34
-#define tigonFwBssAddr 0x00015e30
+#define tigonFwSbssAddr 0x00015d90
+#define tigonFwSbssLen 0x38
+#define tigonFwBssAddr 0x00015dd0
 #define tigonFwBssLen 0x2080
 u32 tigonFwText[];
 u32 tigonFwData[];
@@ -25,16 +25,16 @@
 u32 tigonFwText[(MAX_TEXT_LEN/4) + 1] __initdata = {
 0x10000003, 
 0x0, 0xd, 0xd, 0x3c1d0001, 
-0x8fbd5cb4, 0x3a0f021, 0x3c100000, 0x26104000, 
+0x8fbd5c54, 0x3a0f021, 0x3c100000, 0x26104000, 
 0xc00100c, 0x0, 0xd, 0x27bdffd8, 
 0x3c1cc000, 0x3c1b0013, 0x377bd800, 0xd021, 
 0x3c170013, 0x36f75418, 0x2e02021, 0x340583e8, 
 0xafbf0024, 0xc002488, 0xafb00020, 0xc0023e8, 
-0x0, 0x3c040001, 0x248451f4, 0x24050001, 
-0x2e03021, 0x3821, 0x3c100001, 0x26107eb0, 
+0x0, 0x3c040001, 0x248451a4, 0x24050001, 
+0x2e03021, 0x3821, 0x3c100001, 0x26107e50, 
 0xafb00010, 0xc002403, 0xafbb0014, 0x3c02000f, 
 0x3442ffff, 0x2021024, 0x362102b, 0x10400009, 
-0x24050003, 0x3c040001, 0x24845200, 0x2003021, 
+0x24050003, 0x3c040001, 0x248451b0, 0x2003021, 
 0x3603821, 0x3c020010, 0xafa20010, 0xc002403, 
 0xafa00014, 0x2021, 0x3405c000, 0x3c010001, 
 0x370821, 0xa02083b0, 0x3c010001, 0x370821, 
@@ -72,7 +72,7 @@
 0x0, 0x8ee20450, 0x8ee30454, 0xaee304fc, 
 0x8ee204fc, 0x2442e000, 0x2c422001, 0x1440000d, 
 0x26e40030, 0x8ee20450, 0x8ee30454, 0x3c040001, 
-0x2484520c, 0x3c050001, 0xafa00010, 0xafa00014, 
+0x248451bc, 0x3c050001, 0xafa00010, 0xafa00014, 
 0x8ee704fc, 0x34a5f000, 0xc002403, 0x603021, 
 0x26e40030, 0xc002488, 0x24050400, 0x27440080, 
 0xc002488, 0x24050080, 0x26e4777c, 0xc002488, 
@@ -82,7 +82,7 @@
 0x3442ca00, 0x2021, 0x24030002, 0xaee30074, 
 0xaee30070, 0xaee2006c, 0x240203e8, 0xaee20104, 
 0x24020001, 0xaee30100, 0xaee2010c, 0x3c030001, 
-0x641821, 0x90635c80, 0x2e41021, 0x24840001, 
+0x641821, 0x90635c20, 0x2e41021, 0x24840001, 
 0xa043009c, 0x2c82000f, 0x1440fff8, 0x0, 
 0x8f820040, 0x2e41821, 0x24840001, 0x21702, 
 0x24420030, 0xa062009c, 0x2e41021, 0xa040009c, 
@@ -128,7 +128,7 @@
 0x8ee24e30, 0x24420001, 0xaee24e30, 0x8ee24e30, 
 0x210c0, 0x24425038, 0x2e22021, 0x24020007, 
 0xac820000, 0x24020001, 0xac820004, 0x54c0000c, 
-0xaee90608, 0x3c040001, 0x24845218, 0xafa00010, 
+0xaee90608, 0x3c040001, 0x248451c8, 0xafa00010, 
 0xafa00014, 0x8ee60608, 0x8f470228, 0x3c050009, 
 0xc002403, 0x34a5f000, 0x8001223, 0x0, 
 0x8f830120, 0x27623800, 0x24660020, 0xc2102b, 
@@ -154,21 +154,21 @@
 0x24420001, 0xaee24e30, 0x8ee24e30, 0x210c0, 
 0x24425038, 0x2e22021, 0x24020012, 0xac820000, 
 0x24020001, 0xac820004, 0x14c0001b, 0x0, 
-0x3c040001, 0x24845220, 0xafa00010, 0xafa00014, 
+0x3c040001, 0x248451d0, 0xafa00010, 0xafa00014, 
 0x8ee60608, 0x8f470228, 0x3c050009, 0xc002403, 
 0x34a5f001, 0x8ee201b0, 0x24420001, 0xaee201b0, 
-0x8001223, 0x8ee201b0, 0x3c040001, 0x2484522c, 
+0x8001223, 0x8ee201b0, 0x3c040001, 0x248451dc, 
 0xafa00014, 0x8ee60608, 0x8f470228, 0x3c050009, 
 0xc002403, 0x34a5f005, 0x8ee201ac, 0x24420001, 
 0xaee201ac, 0x8ee201ac, 0x8ee20160, 0x3c040001, 
-0x24845238, 0x3405f001, 0x24420001, 0xaee20160, 
+0x248451e8, 0x3405f001, 0x24420001, 0xaee20160, 
 0x8ee20160, 0x3021, 0x3821, 0xafa00010, 
 0xc002403, 0xafa00014, 0x8001238, 0x0, 
 0x3c020001, 0x2442f5a8, 0x21100, 0x21182, 
 0x431025, 0x3c010001, 0xac221278, 0x96e2045a, 
 0x30420003, 0x10400025, 0x3c050fff, 0x8ee204c8, 
 0x34a5ffff, 0x34420a00, 0xaee204c8, 0x8ee304c8, 
-0x3c040001, 0x24845244, 0x24020001, 0xa2e204ec, 
+0x3c040001, 0x248451f4, 0x24020001, 0xa2e204ec, 
 0xa2e204ed, 0x3c020002, 0x621825, 0x3c020001, 
 0x2442a390, 0x451024, 0x21082, 0xaee304c8, 
 0x3c030800, 0x431025, 0x3c010001, 0xac221220, 
@@ -211,7 +211,7 @@
 0xaee24e30, 0x8ee24e30, 0x210c0, 0x24425038, 
 0x2e22021, 0x24020007, 0xac820000, 0x24020001, 
 0xac820004, 0x54c0000c, 0xaee90608, 0x3c040001, 
-0x24845218, 0xafa00010, 0xafa00014, 0x8ee60608, 
+0x248451c8, 0xafa00010, 0xafa00014, 0x8ee60608, 
 0x8f470228, 0x3c050009, 0xc002403, 0x34a5f000, 
 0x800136d, 0x0, 0x8f830120, 0x27623800, 
 0x24660020, 0xc2102b, 0x50400001, 0x27663000, 
@@ -236,17 +236,17 @@
 0x1021, 0x8ee24e30, 0x24420001, 0xaee24e30, 
 0x8ee24e30, 0x210c0, 0x24425038, 0x2e22021, 
 0x24020012, 0xac820000, 0x24020001, 0xac820004, 
-0x14c0001b, 0x0, 0x3c040001, 0x24845220, 
+0x14c0001b, 0x0, 0x3c040001, 0x248451d0, 
 0xafa00010, 0xafa00014, 0x8ee60608, 0x8f470228, 
 0x3c050009, 0xc002403, 0x34a5f001, 0x8ee201b0, 
 0x24420001, 0xaee201b0, 0x800136d, 0x8ee201b0, 
-0x3c040001, 0x2484522c, 0xafa00014, 0x8ee60608, 
+0x3c040001, 0x248451dc, 0xafa00014, 0x8ee60608, 
 0x8f470228, 0x3c050009, 0xc002403, 0x34a5f005, 
 0x8ee201ac, 0x24420001, 0xaee201ac, 0x8ee201ac, 
-0x8ee20160, 0x3c040001, 0x24845238, 0x3405f002, 
+0x8ee20160, 0x3c040001, 0x248451e8, 0x3405f002, 
 0x24420001, 0xaee20160, 0x8ee20160, 0x3021, 
 0x3821, 0xafa00010, 0xc002403, 0xafa00014, 
-0x96e6047a, 0x96e7046a, 0x3c040001, 0x24845250, 
+0x96e6047a, 0x96e7046a, 0x3c040001, 0x24845200, 
 0x24050012, 0xafa00010, 0xc002403, 0xafa00014, 
 0xc004500, 0x0, 0xc002318, 0x0, 
 0x3c060001, 0x34c63800, 0xaee00608, 0xaf400228, 
@@ -289,7 +289,7 @@
 0xaee24e30, 0x8ee24e30, 0x210c0, 0x24425038, 
 0x2e22021, 0x24020007, 0xac820000, 0x24020001, 
 0xac820004, 0x54c0000c, 0xaee90608, 0x3c040001, 
-0x24845218, 0xafa00010, 0xafa00014, 0x8ee60608, 
+0x248451c8, 0xafa00010, 0xafa00014, 0x8ee60608, 
 0x8f470228, 0x3c050009, 0xc002403, 0x34a5f000, 
 0x80014a5, 0x0, 0x8f830120, 0x27623800, 
 0x24660020, 0xc2102b, 0x50400001, 0x27663000, 
@@ -314,11 +314,11 @@
 0x1021, 0x8ee24e30, 0x24420001, 0xaee24e30, 
 0x8ee24e30, 0x210c0, 0x24425038, 0x2e22021, 
 0x24020012, 0xac820000, 0x24020001, 0xac820004, 
-0x14c0001b, 0x0, 0x3c040001, 0x24845220, 
+0x14c0001b, 0x0, 0x3c040001, 0x248451d0, 
 0xafa00010, 0xafa00014, 0x8ee60608, 0x8f470228, 
 0x3c050009, 0xc002403, 0x34a5f001, 0x8ee201b0, 
 0x24420001, 0xaee201b0, 0x80014a5, 0x8ee201b0, 
-0x3c040001, 0x2484522c, 0xafa00014, 0x8ee60608, 
+0x3c040001, 0x248451dc, 0xafa00014, 0x8ee60608, 
 0x8f470228, 0x3c050009, 0xc002403, 0x34a5f005, 
 0x8ee201ac, 0x24420001, 0xaee201ac, 0x8ee201ac, 
 0x8ee20154, 0x24420001, 0xaee20154, 0xc0014dc, 
@@ -340,7 +340,7 @@
 0xaee07b8c, 0xaee07b84, 0x3c010001, 0x370821, 
 0xac2083bc, 0x3c010001, 0x370821, 0x3e00008, 
 0xa02083b9, 0x27bdffd8, 0xafbf0024, 0xafb00020, 
-0x8f820054, 0x3c030001, 0x8c635d38, 0x24420067, 
+0x8f820054, 0x3c030001, 0x8c635cd8, 0x24420067, 
 0x1060000d, 0xaf820058, 0x3c020001, 0x571021, 
 0x904283b8, 0x10400005, 0x3c030200, 0x3c010001, 
 0x370821, 0x8001503, 0xa02083b8, 0x8ee20000, 
@@ -358,7 +358,7 @@
 0x0, 0x3c030001, 0x771821, 0x8c6383d4, 
 0x8f8200b4, 0x1462007c, 0x0, 0x3c070001, 
 0xf73821, 0x8ce783d0, 0x8f8200b0, 0x3c040001, 
-0x248452c0, 0xafa00014, 0xafa20010, 0x8f8600b0, 
+0x24845270, 0xafa00014, 0xafa20010, 0x8f8600b0, 
 0x3c050005, 0xc002403, 0x34a50900, 0x8f82011c, 
 0x34420002, 0xaf82011c, 0x8f830104, 0x8f8200b0, 
 0x34420001, 0xaf8200b0, 0xaf830104, 0x8f830120, 
@@ -386,10 +386,10 @@
 0xac820000, 0x24020001, 0xac820004, 0x8f82011c, 
 0x2403fffd, 0x431024, 0xaf82011c, 0x8ee201e4, 
 0x3c070001, 0xf73821, 0x8ce783d0, 0x24420001, 
-0xaee201e4, 0x8ee201e4, 0x3c040001, 0x248452cc, 
+0xaee201e4, 0x8ee201e4, 0x3c040001, 0x2484527c, 
 0x80015bd, 0xafa00010, 0x8f820104, 0x3c010001, 
 0x370821, 0xac2283d0, 0x8f8200b4, 0x3c070001, 
-0xf73821, 0x8ce783d0, 0x3c040001, 0x248452d4, 
+0xf73821, 0x8ce783d0, 0x3c040001, 0x24845284, 
 0x3c010001, 0x370821, 0xac2283d4, 0xafa00010, 
 0xafa00014, 0x8f8600b0, 0x3c050005, 0xc002403, 
 0x34a50900, 0x80015cc, 0x0, 0x8f820104, 
@@ -422,7 +422,7 @@
 0x24420001, 0xaee24e30, 0x8ee24e30, 0x210c0, 
 0x24425038, 0x2e22021, 0x24020012, 0xac820000, 
 0x24020001, 0xac820004, 0x5600000b, 0x24100001, 
-0x8ee204e4, 0x3c040001, 0x248452dc, 0xafa00014, 
+0x8ee204e4, 0x3c040001, 0x2484528c, 0xafa00014, 
 0xafa20010, 0x8ee60608, 0x8f470228, 0x3c050009, 
 0xc002403, 0x34a5f006, 0x16000003, 0x24020001, 
 0x8001650, 0xa2e204f4, 0x8ee20170, 0x24420001, 
@@ -452,7 +452,7 @@
 0x8ee24e30, 0x210c0, 0x24425038, 0x2e22021, 
 0x24020012, 0xac820000, 0x24020001, 0xac820004, 
 0x5600000b, 0x24100001, 0x8ee2724c, 0x3c040001, 
-0x248452e8, 0xafa00014, 0xafa20010, 0x8ee6724c, 
+0x24845298, 0xafa00014, 0xafa20010, 0x8ee6724c, 
 0x8f470280, 0x3c050009, 0xc002403, 0x34a5f008, 
 0x56000001, 0xaee00e1c, 0x8ee20174, 0x24420001, 
 0xaee20174, 0x8ee20174, 0x8ee24e24, 0x10400019, 
@@ -563,11 +563,11 @@
 0x8f820054, 0x1221023, 0x2c420033, 0x1440ffa6, 
 0x0, 0x316300ff, 0x24020001, 0x14620003, 
 0x3c050009, 0x800197c, 0x24100001, 0x3c040001, 
-0x248452f4, 0xafa00010, 0xafa00014, 0x8f860120, 
+0x248452a4, 0xafa00010, 0xafa00014, 0x8f860120, 
 0x8f870124, 0x800187b, 0x34a5f011, 0x3c040001, 
-0x24845300, 0xafa00010, 0xafa00014, 0x8f860120, 
+0x248452b0, 0xafa00010, 0xafa00014, 0x8f860120, 
 0x8f870124, 0x34a5f010, 0xc002403, 0x8021, 
-0x800197c, 0x0, 0x3c040001, 0x2484530c, 
+0x800197c, 0x0, 0x3c040001, 0x248452bc, 
 0xafa00014, 0x8ee60608, 0x8f470228, 0x3c050009, 
 0x8001975, 0x34a5f00f, 0x8ee20608, 0x8f430228, 
 0x24420001, 0x304900ff, 0x512300e2, 0xafa00010, 
@@ -598,7 +598,7 @@
 0x24420001, 0xaee24e30, 0x8ee24e30, 0x210c0, 
 0x24425038, 0x2e22021, 0x24020007, 0xac820000, 
 0x24020001, 0xac820004, 0x5600000c, 0xaee90608, 
-0x3c040001, 0x24845318, 0xafa00010, 0xafa00014, 
+0x3c040001, 0x248452c8, 0xafa00010, 0xafa00014, 
 0x8ee60608, 0x8f470228, 0x3c050009, 0xc002403, 
 0x34a5f000, 0x800197c, 0x0, 0x8f830120, 
 0x27623800, 0x24660020, 0xc2102b, 0x50400001, 
@@ -624,10 +624,10 @@
 0xaee24e30, 0x8ee24e30, 0x210c0, 0x24425038, 
 0x2e22021, 0x24020012, 0xac820000, 0x24020001, 
 0xac820004, 0x5600001d, 0x24100001, 0x3c040001, 
-0x24845320, 0xafa00010, 0xafa00014, 0x8ee60608, 
+0x248452d0, 0xafa00010, 0xafa00014, 0x8ee60608, 
 0x8f470228, 0x3c050009, 0xc002403, 0x34a5f001, 
 0x8ee201b0, 0x24420001, 0xaee201b0, 0x800197c, 
-0x8ee201b0, 0x3c040001, 0x2484532c, 0xafa00014, 
+0x8ee201b0, 0x3c040001, 0x248452dc, 0xafa00014, 
 0x8ee60608, 0x8f470228, 0x3c050009, 0x34a5f005, 
 0xc002403, 0x0, 0x8ee201ac, 0x8021, 
 0x24420001, 0xaee201ac, 0x8ee201ac, 0x1200000c, 
@@ -635,7 +635,7 @@
 0x8f420238, 0x8ee30158, 0x24630001, 0xaee30158, 
 0x8ee30158, 0x800198c, 0xaee27278, 0x24020001, 
 0x3c010001, 0x370821, 0xa02283b0, 0x3c020001, 
-0x8c425d38, 0x10400187, 0x0, 0x8ee27b84, 
+0x8c425cd8, 0x10400187, 0x0, 0x8ee27b84, 
 0x24430001, 0x284200c9, 0x144001a4, 0xaee37b84, 
 0x8ee204d4, 0x30420002, 0x14400119, 0xaee07b84, 
 0x8ee204d4, 0x3c030600, 0x34631000, 0x34420002, 
@@ -699,12 +699,12 @@
 0x56000006, 0x240b0001, 0x8f820054, 0x1221023, 
 0x2c420033, 0x1440ffa6, 0x0, 0x316300ff, 
 0x24020001, 0x10620022, 0x0, 0x3c040001, 
-0x248452f4, 0xafa00010, 0xafa00014, 0x8f860120, 
+0x248452a4, 0xafa00010, 0xafa00014, 0x8f860120, 
 0x8f870124, 0x3c050009, 0xc002403, 0x34a5f011, 
-0x8001aad, 0x0, 0x3c040001, 0x24845300, 
+0x8001aad, 0x0, 0x3c040001, 0x248452b0, 
 0xafa00014, 0x8f860120, 0x8f870124, 0x3c050009, 
 0xc002403, 0x34a5f010, 0x8001aad, 0x0, 
-0x3c040001, 0x2484530c, 0xafa00014, 0x8ee60608, 
+0x3c040001, 0x248452bc, 0xafa00014, 0x8ee60608, 
 0x8f470228, 0x3c050009, 0xc002403, 0x34a5f00f, 
 0x8ee201ac, 0x24420001, 0xaee201ac, 0x8ee201ac, 
 0x8ee2015c, 0x24420001, 0xaee2015c, 0x8ee2015c, 
@@ -741,7 +741,7 @@
 0xaf820044, 0x8f820044, 0x34420040, 0xaf820044, 
 0x8ee27b88, 0x24430001, 0x28421389, 0x14400005, 
 0xaee37b88, 0x8f820044, 0x38420020, 0xaf820044, 
-0xaee07b88, 0xc0045f4, 0x0, 0x8fbf0024, 
+0xaee07b88, 0xc004603, 0x0, 0x8fbf0024, 
 0x8fb00020, 0x3e00008, 0x27bd0028, 0x27bdffb8, 
 0xafbf0044, 0xafb60040, 0xafb5003c, 0xafb40038, 
 0xafb30034, 0xafb20030, 0xafb1002c, 0xafb00028, 
@@ -751,18 +751,18 @@
 0xaee2016c, 0x80022f4, 0x8ee2016c, 0x32c20001, 
 0x10400004, 0x24020001, 0xaf820064, 0x80022f4, 
 0x0, 0x32c20002, 0x1440000c, 0x3c050003, 
-0x3c040001, 0x248453a4, 0x34a50001, 0x2c03021, 
+0x3c040001, 0x24845354, 0x34a50001, 0x2c03021, 
 0x3821, 0xafa00010, 0xc002403, 0xafa00014, 
 0x2402fff8, 0x80022f4, 0xaf820064, 0x8f43022c, 
 0x8f42010c, 0x5062000c, 0xafa00010, 0x8f42022c, 
 0x21080, 0x5a1021, 0x8c420300, 0xafa20020, 
 0x8f42022c, 0x24070001, 0x24420001, 0x3042003f, 
-0x8001b80, 0xaf42022c, 0x3c040001, 0x248453b0, 
+0x8001b80, 0xaf42022c, 0x3c040001, 0x24845360, 
 0xafa00014, 0x8f46022c, 0x8f47010c, 0x3c050003, 
 0xc002403, 0x34a5f01f, 0x3821, 0x14e00003, 
 0x0, 0x80022ed, 0xaf960064, 0x93a20020, 
 0x2443ffff, 0x2c620011, 0x10400658, 0x31080, 
-0x3c010001, 0x220821, 0x8c225468, 0x400008, 
+0x3c010001, 0x220821, 0x8c225418, 0x400008, 
 0x0, 0x8fa20020, 0x30420fff, 0xaee20e0c, 
 0x8f820060, 0x34420200, 0xaf820060, 0x8ee20118, 
 0x24420001, 0xaee20118, 0x80022e8, 0x8ee20118, 
@@ -778,7 +778,7 @@
 0x8f840054, 0x41442, 0x41c82, 0x431021, 
 0x41cc2, 0x431023, 0x41d02, 0x431021, 
 0x41d42, 0x431023, 0x8001bd0, 0xaee20078, 
-0x3c040001, 0x248453bc, 0xafa00014, 0x8fa60020, 
+0x3c040001, 0x2484536c, 0xafa00014, 0x8fa60020, 
 0x3c050003, 0xc002403, 0x34a50004, 0x8ee20110, 
 0x24420001, 0xaee20110, 0x80022e8, 0x8ee20110, 
 0x27440212, 0xc0022fe, 0x24050006, 0x3049001f, 
@@ -794,7 +794,7 @@
 0x2c820080, 0x1440fff8, 0x410c0, 0x4c10010, 
 0x618c0, 0x610c0, 0x571821, 0x8c63737c, 
 0x571021, 0xafa30010, 0x8c427380, 0x3c040001, 
-0x248453c8, 0xafa20014, 0x8f470214, 0x3c050003, 
+0x24845378, 0xafa20014, 0x8f470214, 0x3c050003, 
 0xc002403, 0x34a50013, 0x8001c90, 0x3c020800, 
 0x97440212, 0x771021, 0xa444737e, 0x8f440214, 
 0x771021, 0x2e31821, 0xac447380, 0x34028000, 
@@ -812,7 +812,7 @@
 0x24840001, 0x2c820080, 0x1440fff8, 0x410c0, 
 0x4c10023, 0x618c0, 0x910c0, 0x571821, 
 0x8c63727c, 0x571021, 0xafa30010, 0x8c427280, 
-0x3c040001, 0x248453d4, 0xafa20014, 0x8f470214, 
+0x3c040001, 0x24845384, 0xafa20014, 0x8f470214, 
 0x3c050003, 0xc002403, 0x34a5f017, 0x8001c90, 
 0x3c020800, 0x8f430210, 0xb71021, 0xac43777c, 
 0x8f430214, 0xb71021, 0xac437780, 0x3c020001, 
@@ -887,13 +887,13 @@
 0x2e22021, 0xac8a0000, 0xac8c0004, 0x54e00006, 
 0x240b0001, 0x8f820054, 0x1221023, 0x2c420033, 
 0x1440ffa6, 0x0, 0x316300ff, 0x24020001, 
-0x10620022, 0x0, 0x3c040001, 0x248453e0, 
+0x10620022, 0x0, 0x3c040001, 0x24845390, 
 0xafa00010, 0xafa00014, 0x8f860120, 0x8f870124, 
 0x3c050009, 0xc002403, 0x34a5f011, 0x8001da0, 
-0x0, 0x3c040001, 0x248453ec, 0xafa00014, 
+0x0, 0x3c040001, 0x2484539c, 0xafa00014, 
 0x8f860120, 0x8f870124, 0x3c050009, 0xc002403, 
 0x34a5f010, 0x8001da0, 0x0, 0x3c040001, 
-0x248453f8, 0xafa00014, 0x8ee60608, 0x8f470228, 
+0x248453a8, 0xafa00014, 0x8ee60608, 0x8f470228, 
 0x3c050009, 0xc002403, 0x34a5f00f, 0x8ee201ac, 
 0x24420001, 0xaee201ac, 0x8ee201ac, 0x8ee20124, 
 0x24420001, 0xaee20124, 0x8001f97, 0x8ee20124, 
@@ -908,7 +908,7 @@
 0x1221004, 0x21027, 0x621824, 0xaf830228, 
 0x910c0, 0x2e21821, 0x3402c000, 0x8001e4e, 
 0xa462727c, 0x8f420214, 0xafa20010, 0x910c0, 
-0x571021, 0x8c42727c, 0x3c040001, 0x24845404, 
+0x571021, 0x8c42727c, 0x3c040001, 0x248453b4, 
 0x3c050003, 0xafa20014, 0x8f470210, 0x34a5f01c, 
 0xc002403, 0x1203021, 0x8001e83, 0x3c020800, 
 0xb71021, 0x9443727e, 0x97420212, 0x14620019, 
@@ -936,7 +936,7 @@
 0x910c0, 0x2e41821, 0x3402c000, 0x15000015, 
 0xa462737c, 0x910c0, 0x2e21821, 0x34028000, 
 0x8001e4e, 0xa462727c, 0x571021, 0x8c42727c, 
-0x3c040001, 0x24845410, 0x3c050003, 0xafa20010, 
+0x3c040001, 0x248453c0, 0x3c050003, 0xafa20010, 
 0x710c0, 0x571021, 0x8c42737c, 0x34a5001e, 
 0x1203021, 0xc002403, 0xafa20014, 0x8001e83, 
 0x3c020800, 0x2021, 0x428c0, 0xb71021, 
@@ -1012,12 +1012,12 @@
 0xac8a0000, 0xac8c0004, 0x54e00006, 0x240b0001, 
 0x8f820054, 0x1221023, 0x2c420033, 0x1440ffa6, 
 0x0, 0x316300ff, 0x24020001, 0x10620022, 
-0x0, 0x3c040001, 0x248453e0, 0xafa00010, 
+0x0, 0x3c040001, 0x24845390, 0xafa00010, 
 0xafa00014, 0x8f860120, 0x8f870124, 0x3c050009, 
 0xc002403, 0x34a5f011, 0x8001f93, 0x0, 
-0x3c040001, 0x248453ec, 0xafa00014, 0x8f860120, 
+0x3c040001, 0x2484539c, 0xafa00014, 0x8f860120, 
 0x8f870124, 0x3c050009, 0xc002403, 0x34a5f010, 
-0x8001f93, 0x0, 0x3c040001, 0x248453f8, 
+0x8001f93, 0x0, 0x3c040001, 0x248453a8, 
 0xafa00014, 0x8ee60608, 0x8f470228, 0x3c050009, 
 0xc002403, 0x34a5f00f, 0x8ee201ac, 0x24420001, 
 0xaee201ac, 0x8ee201ac, 0x8ee20128, 0x24420001, 
@@ -1029,7 +1029,7 @@
 0x8f820228, 0xaee204dc, 0x2402ffff, 0xaf820228, 
 0x24020001, 0x8001fbe, 0xa2e204d8, 0x92e204d8, 
 0x5040000c, 0xa2e004d8, 0x8ee204dc, 0xaf820228, 
-0x8001fbe, 0xa2e004d8, 0x3c040001, 0x24845418, 
+0x8001fbe, 0xa2e004d8, 0x3c040001, 0x248453c8, 
 0xafa00014, 0x8fa60020, 0x3c050003, 0xc002403, 
 0x34a5f009, 0x8ee2013c, 0x24420001, 0xaee2013c, 
 0x80022e8, 0x8ee2013c, 0x8fa20020, 0x21200, 
@@ -1040,7 +1040,7 @@
 0x370821, 0xa02283b2, 0x8001fea, 0xaee40108, 
 0x8f820220, 0x3c0308ff, 0x3463fff7, 0x431024, 
 0xaf820220, 0x3c010001, 0x370821, 0xa02083b2, 
-0x8001fea, 0xaee40108, 0x3c040001, 0x24845424, 
+0x8001fea, 0xaee40108, 0x3c040001, 0x248453d4, 
 0xafa00014, 0x8fa60020, 0x3c050003, 0xc002403, 
 0x34a5f00a, 0x8ee2012c, 0x24420001, 0xaee2012c, 
 0x80022e8, 0x8ee2012c, 0x8fa20020, 0x21200, 
@@ -1052,13 +1052,13 @@
 0x571021, 0x904283b2, 0x3c010001, 0x370821, 
 0x1440000e, 0xa02083b3, 0x8f820220, 0x3c0308ff, 
 0x3463fff7, 0x431024, 0x8002018, 0xaf820220, 
-0x3c040001, 0x24845430, 0xafa00014, 0x8fa60020, 
+0x3c040001, 0x248453e0, 0xafa00014, 0x8fa60020, 
 0x3c050003, 0xc002403, 0x34a5f00b, 0x8ee20114, 
 0x24420001, 0xaee20114, 0x80022e8, 0x8ee20114, 
 0x27840208, 0x27450200, 0xc00249a, 0x24060008, 
 0x26e40094, 0x27450200, 0xc00249a, 0x24060008, 
 0x8ee20134, 0x24420001, 0xaee20134, 0x80022e8, 
-0x8ee20134, 0x8f460248, 0x2021, 0xc0050e0, 
+0x8ee20134, 0x8f460248, 0x2021, 0xc005108, 
 0x24050004, 0x8ee20130, 0x24420001, 0xaee20130, 
 0x80022e8, 0x8ee20130, 0x8ef301cc, 0x8ef401d0, 
 0x8ef501d8, 0x8ee20140, 0x26e40030, 0x24420001, 
@@ -1072,7 +1072,7 @@
 0xaee20104, 0xaee40100, 0xaee3010c, 0x8f820220, 
 0x30420008, 0x10400004, 0x0, 0xaee30108, 
 0x8002061, 0x2021, 0xaee40108, 0x2021, 
-0x3c030001, 0x641821, 0x90635c90, 0x2e41021, 
+0x3c030001, 0x641821, 0x90635c30, 0x2e41021, 
 0x24840001, 0xa043009c, 0x2c82000f, 0x1440fff8, 
 0x0, 0x8f820040, 0x2e41821, 0x24840001, 
 0x21702, 0x24420030, 0xa062009c, 0x2e41021, 
@@ -1152,13 +1152,13 @@
 0x2e22021, 0xac8a0000, 0xac8c0004, 0x54e00006, 
 0x240b0001, 0x8f820054, 0x1221023, 0x2c420033, 
 0x1440ffa6, 0x0, 0x316300ff, 0x24020001, 
-0x10620022, 0x0, 0x3c040001, 0x248453e0, 
+0x10620022, 0x0, 0x3c040001, 0x24845390, 
 0xafa00010, 0xafa00014, 0x8f860120, 0x8f870124, 
 0x3c050009, 0xc002403, 0x34a5f011, 0x80021c4, 
-0x0, 0x3c040001, 0x248453ec, 0xafa00014, 
+0x0, 0x3c040001, 0x2484539c, 0xafa00014, 
 0x8f860120, 0x8f870124, 0x3c050009, 0xc002403, 
 0x34a5f010, 0x80021c4, 0x0, 0x3c040001, 
-0x248453f8, 0xafa00014, 0x8ee60608, 0x8f470228, 
+0x248453a8, 0xafa00014, 0x8ee60608, 0x8f470228, 
 0x3c050009, 0xc002403, 0x34a5f00f, 0x8ee201ac, 
 0x24420001, 0xaee201ac, 0x8ee201ac, 0x8ee20120, 
 0x24420001, 0xaee20120, 0x8ee20120, 0x8ee20168, 
@@ -1168,7 +1168,7 @@
 0x8f820220, 0x30420008, 0x14400002, 0x24020001, 
 0x24020002, 0xaee20108, 0x8ee2011c, 0x24420001, 
 0xaee2011c, 0x80022e8, 0x8ee2011c, 0x3c040001, 
-0x2484543c, 0xafa00010, 0xafa00014, 0x8fa60020, 
+0x248453ec, 0xafa00010, 0xafa00014, 0x8fa60020, 
 0x3c050003, 0xc002403, 0x34a5f00f, 0x93a20020, 
 0x3c030700, 0x34631000, 0x431025, 0xafa20018, 
 0x8ee20608, 0x8f430228, 0x24420001, 0x304900ff, 
@@ -1199,7 +1199,7 @@
 0x1021, 0x8ee24e30, 0x24420001, 0xaee24e30, 
 0x8ee24e30, 0x210c0, 0x24425038, 0x2e22021, 
 0x24020007, 0xac820000, 0x24020001, 0xac820004, 
-0x54e0000c, 0xaee90608, 0x3c040001, 0x24845444, 
+0x54e0000c, 0xaee90608, 0x3c040001, 0x248453f4, 
 0xafa00010, 0xafa00014, 0x8ee60608, 0x8f470228, 
 0x3c050009, 0xc002403, 0x34a5f000, 0x80022e0, 
 0x0, 0x8f830120, 0x27623800, 0x24660020, 
@@ -1225,11 +1225,11 @@
 0x8ee24e30, 0x24420001, 0xaee24e30, 0x8ee24e30, 
 0x210c0, 0x24425038, 0x2e22021, 0x24020012, 
 0xac820000, 0x24020001, 0xac820004, 0x14e0001b, 
-0x0, 0x3c040001, 0x2484544c, 0xafa00010, 
+0x0, 0x3c040001, 0x248453fc, 0xafa00010, 
 0xafa00014, 0x8ee60608, 0x8f470228, 0x3c050009, 
 0xc002403, 0x34a5f001, 0x8ee201b0, 0x24420001, 
 0xaee201b0, 0x80022e0, 0x8ee201b0, 0x3c040001, 
-0x24845458, 0xafa00014, 0x8ee60608, 0x8f470228, 
+0x24845408, 0xafa00014, 0x8ee60608, 0x8f470228, 
 0x3c050009, 0xc002403, 0x34a5f005, 0x8ee201ac, 
 0x24420001, 0xaee201ac, 0x8ee201ac, 0x8ee20150, 
 0x24420001, 0xaee20150, 0x8ee20150, 0x8ee20160, 
@@ -1256,7 +1256,7 @@
 0xaf82011c, 0x8fbf0010, 0x3e00008, 0x27bd0018, 
 0x27bdffe0, 0xafbf0018, 0x8f820104, 0xafa20010, 
 0x8f820100, 0x3c050002, 0xafa20014, 0x8f8600b0, 
-0x8f87011c, 0x3c040001, 0x24845510, 0xc002403, 
+0x8f87011c, 0x3c040001, 0x248454c0, 0xc002403, 
 0x34a5f000, 0x8f8300b0, 0x3c027f00, 0x621824, 
 0x3c020400, 0x10620029, 0x43102b, 0x14400008, 
 0x3c022000, 0x3c020100, 0x10620024, 0x3c020200, 
@@ -1273,7 +1273,7 @@
 0x27bd0020, 0x27bdffe0, 0xafbf001c, 0xafb00018, 
 0x8f820120, 0xafa20010, 0x8f820124, 0x3c050001, 
 0xafa20014, 0x8f8600a0, 0x8f87011c, 0x3c040001, 
-0x2484551c, 0xc002403, 0x34a5f000, 0x8f8300a0, 
+0x248454cc, 0xc002403, 0x34a5f000, 0x8f8300a0, 
 0x3c027f00, 0x621824, 0x3c020400, 0x10620053, 
 0x8021, 0x43102b, 0x14400008, 0x3c042000, 
 0x3c020100, 0x1062004d, 0x3c020200, 0x1062003a, 
@@ -1298,43 +1298,43 @@
 0xaee2019c, 0x80023e3, 0x8ee2019c, 0x8f8200a0, 
 0x34420001, 0xaf8200a0, 0x8fbf001c, 0x8fb00018, 
 0x3e00008, 0x27bd0020, 0x0, 0x3c020001, 
-0x8c425cb8, 0x27bdffe8, 0xafbf0014, 0x14400012, 
-0xafb00010, 0x3c100001, 0x26105e30, 0x2002021, 
+0x8c425c58, 0x27bdffe8, 0xafbf0014, 0x14400012, 
+0xafb00010, 0x3c100001, 0x26105dd0, 0x2002021, 
 0xc002488, 0x24052000, 0x26021fe0, 0x3c010001, 
-0xac225df4, 0x3c010001, 0xac225df0, 0xaf420250, 
+0xac225d94, 0x3c010001, 0xac225d90, 0xaf420250, 
 0x24022000, 0xaf500254, 0xaf420258, 0x24020001, 
-0x3c010001, 0xac225cb8, 0x8fbf0014, 0x8fb00010, 
-0x3e00008, 0x27bd0018, 0x3c030001, 0x8c635df4, 
+0x3c010001, 0xac225c58, 0x8fbf0014, 0x8fb00010, 
+0x3e00008, 0x27bd0018, 0x3c030001, 0x8c635d94, 
 0x8c820000, 0x8fa80010, 0x8fa90014, 0xac620000, 
-0x3c020001, 0x8c425df4, 0x8c830004, 0xac430004, 
+0x3c020001, 0x8c425d94, 0x8c830004, 0xac430004, 
 0xac450008, 0x8f840054, 0x2443ffe0, 0xac460010, 
 0xac470014, 0xac480018, 0xac49001c, 0x3c010001, 
-0xac235df4, 0xac44000c, 0x3c020001, 0x24425e30, 
+0xac235d94, 0xac44000c, 0x3c020001, 0x24425dd0, 
 0x62182b, 0x10600005, 0x0, 0x3c020001, 
-0x8c425df0, 0x3c010001, 0xac225df4, 0x3c030001, 
-0x8c635df4, 0x3c020001, 0x8c425ca0, 0xac620000, 
-0x3c030001, 0x8c635df4, 0x3c020001, 0x8c425ca0, 
+0x8c425d90, 0x3c010001, 0xac225d94, 0x3c030001, 
+0x8c635d94, 0x3c020001, 0x8c425c40, 0xac620000, 
+0x3c030001, 0x8c635d94, 0x3c020001, 0x8c425c40, 
 0xac620004, 0x3e00008, 0xaf430250, 0x3c030001, 
-0x8c635df4, 0x3c020001, 0x8c425ca0, 0x27bdffd0, 
+0x8c635d94, 0x3c020001, 0x8c425c40, 0x27bdffd0, 
 0xafb40020, 0x8fb40040, 0xafb00010, 0x808021, 
 0xafb50024, 0x8fb50044, 0x8fa40048, 0xafb10014, 
 0xa08821, 0xafbf0028, 0xafb3001c, 0xafb20018, 
-0xac620000, 0x3c050001, 0x8ca55df4, 0x3c020001, 
-0x8c425ca0, 0xc09021, 0xe09821, 0x10800006, 
+0xac620000, 0x3c050001, 0x8ca55d94, 0x3c020001, 
+0x8c425c40, 0xc09021, 0xe09821, 0x10800006, 
 0xaca20004, 0x24a50008, 0xc002490, 0x24060018, 
 0x800244e, 0x0, 0x24a40008, 0xc002488, 
-0x24050018, 0x3c020001, 0x8c425df4, 0x3c050001, 
-0x24a55e30, 0x2442ffe0, 0x3c010001, 0xac225df4, 
+0x24050018, 0x3c020001, 0x8c425d94, 0x3c050001, 
+0x24a55dd0, 0x2442ffe0, 0x3c010001, 0xac225d94, 
 0x45102b, 0x10400005, 0x0, 0x3c020001, 
-0x8c425df0, 0x3c010001, 0xac225df4, 0x3c030001, 
-0x8c635df4, 0x8e020000, 0xac620000, 0x3c030001, 
-0x8c635df4, 0x8e020004, 0xac620004, 0xac710008, 
-0x8f840054, 0x2462ffe0, 0x3c010001, 0xac225df4, 
+0x8c425d90, 0x3c010001, 0xac225d94, 0x3c030001, 
+0x8c635d94, 0x8e020000, 0xac620000, 0x3c030001, 
+0x8c635d94, 0x8e020004, 0xac620004, 0xac710008, 
+0x8f840054, 0x2462ffe0, 0x3c010001, 0xac225d94, 
 0x45102b, 0xac720010, 0xac730014, 0xac740018, 
 0xac75001c, 0x10400005, 0xac64000c, 0x3c020001, 
-0x8c425df0, 0x3c010001, 0xac225df4, 0x3c030001, 
-0x8c635df4, 0x3c020001, 0x8c425ca0, 0xac620000, 
-0x3c030001, 0x8c635df4, 0x3c020001, 0x8c425ca0, 
+0x8c425d90, 0x3c010001, 0xac225d94, 0x3c030001, 
+0x8c635d94, 0x3c020001, 0x8c425c40, 0xac620000, 
+0x3c030001, 0x8c635d94, 0x3c020001, 0x8c425c40, 
 0xac620004, 0xaf430250, 0x8fbf0028, 0x8fb50024, 
 0x8fb40020, 0x8fb3001c, 0x8fb20018, 0x8fb10014, 
 0x8fb00010, 0x3e00008, 0x27bd0030, 0x10a00005, 
@@ -1380,7 +1380,7 @@
 0x210c0, 0x24424e38, 0x2e22021, 0x24020005, 
 0xac820000, 0x24020001, 0xac820004, 0x1520000a, 
 0x3c040001, 0xafab0010, 0x8ee27264, 0x3c040001, 
-0x24845780, 0x3c050004, 0xafa20014, 0x8ee604e4, 
+0x24845730, 0x3c050004, 0xafa20014, 0x8ee604e4, 
 0x80028be, 0x34a5f114, 0x8ee27264, 0x34843800, 
 0x3641821, 0x24420010, 0x43102b, 0x14400073, 
 0x0, 0x8ee27264, 0x24480010, 0x3641021, 
@@ -1409,7 +1409,7 @@
 0x210c0, 0x24424e38, 0x2e22021, 0x24020005, 
 0xac820000, 0x24020001, 0xac820004, 0x1520000a, 
 0x2508fffc, 0xafab0010, 0x8ee27264, 0x3c040001, 
-0x24845780, 0x3c050004, 0xafa20014, 0x8ee604e4, 
+0x24845730, 0x3c050004, 0xafa20014, 0x8ee604e4, 
 0x80028be, 0x34a5f125, 0x34028100, 0xa5020000, 
 0x9582000e, 0x800261d, 0xa5020002, 0x8f850100, 
 0x27623000, 0x24a60020, 0xc2102b, 0x50400001, 
@@ -1436,7 +1436,7 @@
 0x8ee24e28, 0x210c0, 0x24424e38, 0x2e22021, 
 0x24020005, 0xac820000, 0x24020001, 0xac820004, 
 0x1520000a, 0x34028100, 0xafab0010, 0x8ee27264, 
-0x3c040001, 0x24845780, 0x3c050004, 0xafa20014, 
+0x3c040001, 0x24845730, 0x3c050004, 0xafa20014, 
 0x8ee604e4, 0x80028be, 0x34a5f015, 0x8ee37264, 
 0xa462000c, 0x8ee37264, 0x9582000e, 0xa462000e, 
 0x8002681, 0x24e70004, 0x8f840100, 0x27623000, 
@@ -1462,7 +1462,7 @@
 0x24420001, 0xaee24e28, 0x8ee24e28, 0x210c0, 
 0x24424e38, 0x2e22021, 0x24020005, 0xac820000, 
 0x24020001, 0xac820004, 0x15200009, 0x3c050004, 
-0xafab0010, 0x8ee27264, 0x3c040001, 0x24845780, 
+0xafab0010, 0x8ee27264, 0x3c040001, 0x24845730, 
 0xafa20014, 0x8ee604e4, 0x80028be, 0x34a5f004, 
 0x8ee2725c, 0x30e7ffff, 0x471021, 0xaee2725c, 
 0x8ee204e4, 0x8ee304fc, 0x8ee47258, 0x21100, 
@@ -1482,7 +1482,7 @@
 0x8f8200f0, 0x24090001, 0x8fa30018, 0x8fa4001c, 
 0xac430000, 0xac440004, 0xaf8700f0, 0x15200012, 
 0xd1142, 0x8f8200f0, 0xafa20010, 0x8f8200f4, 
-0x3c040001, 0x2484578c, 0xafa20014, 0x8fa60018, 
+0x3c040001, 0x2484573c, 0xafa20014, 0x8fa60018, 
 0x8fa7001c, 0x3c050004, 0xc002403, 0x34a5f005, 
 0x8ee20088, 0x24420001, 0xaee20088, 0x8ee20088, 
 0x80028d3, 0xaee0725c, 0x30430003, 0x24020002, 
@@ -1524,7 +1524,7 @@
 0xaee24e28, 0x8ee24e28, 0x210c0, 0x24424e38, 
 0x2e22021, 0x24020005, 0xac820000, 0x24020001, 
 0xac820004, 0x1520000a, 0x3c040001, 0xafab0010, 
-0x8ee27264, 0x3c040001, 0x24845780, 0x3c050004, 
+0x8ee27264, 0x3c040001, 0x24845730, 0x3c050004, 
 0xafa20014, 0x8ee604e4, 0x80028be, 0x34a5f014, 
 0x8ee27264, 0x34843800, 0x3641821, 0x24420010, 
 0x43102b, 0x14400073, 0x0, 0x8ee27264, 
@@ -1553,7 +1553,7 @@
 0xaee24e28, 0x8ee24e28, 0x210c0, 0x24424e38, 
 0x2e22021, 0x24020005, 0xac820000, 0x24020001, 
 0xac820004, 0x1520000a, 0x2508fffc, 0xafab0010, 
-0x8ee27264, 0x3c040001, 0x24845780, 0x3c050004, 
+0x8ee27264, 0x3c040001, 0x24845730, 0x3c050004, 
 0xafa20014, 0x8ee604e4, 0x80028be, 0x34a5f015, 
 0x34028100, 0xa5020000, 0x9582000e, 0x800285f, 
 0xa5020002, 0x8f850100, 0x27623000, 0x24a60020, 
@@ -1580,7 +1580,7 @@
 0x24420001, 0xaee24e28, 0x8ee24e28, 0x210c0, 
 0x24424e38, 0x2e22021, 0x24020005, 0xac820000, 
 0x24020001, 0xac820004, 0x1520000a, 0x34028100, 
-0xafab0010, 0x8ee27264, 0x3c040001, 0x24845780, 
+0xafab0010, 0x8ee27264, 0x3c040001, 0x24845730, 
 0x3c050004, 0xafa20014, 0x8ee604e4, 0x80028be, 
 0x34a5f016, 0x8ee37264, 0xa462000c, 0x8ee37264, 
 0x9582000e, 0xa462000e, 0x80028c2, 0x24e70004, 
@@ -1606,7 +1606,7 @@
 0xaee24e28, 0x8ee24e28, 0x210c0, 0x24424e38, 
 0x2e22021, 0x24020005, 0xac820000, 0x24020001, 
 0xac820004, 0x1520000b, 0x3c050004, 0x3c040001, 
-0x24845798, 0xafab0010, 0xafa00014, 0x8ee604e4, 
+0x24845748, 0xafab0010, 0xafa00014, 0x8ee604e4, 
 0x34a5f017, 0xc002403, 0x30e7ffff, 0x80028e1, 
 0x0, 0x8ee27264, 0x3c050001, 0x30e4ffff, 
 0x441021, 0xaee27264, 0x8ee2725c, 0x8ee37264, 
@@ -1672,7 +1672,7 @@
 0x24420001, 0xaee24e28, 0x8ee24e28, 0x210c0, 
 0x24424e38, 0x2e22021, 0x24020005, 0xac820000, 
 0x24020001, 0xac820004, 0x1540000a, 0x24020001, 
-0xafa90010, 0x8ee27264, 0x3c040001, 0x24845780, 
+0xafa90010, 0x8ee27264, 0x3c040001, 0x24845730, 
 0x3c050004, 0xafa20014, 0x8ee604e4, 0x8002a4f, 
 0x34a5f204, 0xa2e204ed, 0x8ee204e8, 0x8ee304fc, 
 0x8ee47258, 0x3c060001, 0x34c63800, 0x3c010001, 
@@ -1706,7 +1706,7 @@
 0xaee24e28, 0x8ee24e28, 0x210c0, 0x24424e38, 
 0x2e22021, 0x24020005, 0xac820000, 0x24020001, 
 0xac820004, 0x1540000c, 0x30e5ffff, 0x3c040001, 
-0x24845798, 0x3c050004, 0xafa90010, 0xafa00014, 
+0x24845748, 0x3c050004, 0xafa90010, 0xafa00014, 
 0x8ee604e4, 0x34a5f237, 0xc002403, 0x30e7ffff, 
 0x8002a72, 0x0, 0x8ee27264, 0x451021, 
 0xaee27264, 0x8ee2726c, 0x8ee37264, 0x3c040001, 
@@ -1730,7 +1730,7 @@
 0x8f830108, 0x21140, 0x621821, 0xaf830108, 
 0xac800000, 0x8cc20018, 0x2443fffe, 0x2c620013, 
 0x104000c1, 0x31080, 0x3c010001, 0x220821, 
-0x8c2257c0, 0x400008, 0x0, 0x8ee204f0, 
+0x8c225770, 0x400008, 0x0, 0x8ee204f0, 
 0x471021, 0xaee204f0, 0x8ee204f0, 0x8f43023c, 
 0x43102b, 0x144000be, 0x0, 0x8ee304e4, 
 0x8ee204f8, 0x506200ba, 0xa2e004f4, 0x8f830120, 
@@ -1757,7 +1757,7 @@
 0xaee24e30, 0x8ee24e30, 0x210c0, 0x24425038, 
 0x2e22021, 0x24020012, 0xac820000, 0x24020001, 
 0xac820004, 0x5600000b, 0x24100001, 0x8ee204e4, 
-0x3c040001, 0x248457a4, 0xafa00014, 0xafa20010, 
+0x3c040001, 0x24845754, 0xafa00014, 0xafa20010, 
 0x8ee60608, 0x8f470228, 0x3c050009, 0xc002403, 
 0x34a5f006, 0x16000003, 0x24020001, 0x8002b71, 
 0xa2e204f4, 0x8ee20170, 0x24420001, 0xaee20170, 
@@ -1778,7 +1778,7 @@
 0x8002b71, 0xaee20000, 0x8ee2014c, 0x3c010001, 
 0x370821, 0xa02083e0, 0x24420001, 0xaee2014c, 
 0x8002b71, 0x8ee2014c, 0x94c7000e, 0x8cc2001c, 
-0x3c040001, 0x248457b0, 0xafa60014, 0xafa20010, 
+0x3c040001, 0x24845760, 0xafa60014, 0xafa20010, 
 0x8cc60018, 0x3c050008, 0xc002403, 0x34a50910, 
 0x8fbf001c, 0x8fb00018, 0x3e00008, 0x27bd0020, 
 0x27bdff98, 0xafbf0060, 0xafbe005c, 0xafb60058, 
@@ -1787,7 +1787,7 @@
 0xafa00024, 0x106203e7, 0xafa0002c, 0x3c1e0001, 
 0x37de3800, 0x3c0bffff, 0x8f930108, 0x8e620018, 
 0x8f830104, 0x2443fffe, 0x2c620014, 0x104003cf, 
-0x31080, 0x3c010001, 0x220821, 0x8c225810, 
+0x31080, 0x3c010001, 0x220821, 0x8c2257c0, 
 0x400008, 0x0, 0x9663000e, 0x8ee2725c, 
 0x8ee404f0, 0x431021, 0xaee2725c, 0x8e63001c, 
 0x96e20458, 0x24840001, 0xaee404f0, 0x24630001, 
@@ -1816,7 +1816,7 @@
 0xaee24e30, 0x8ee24e30, 0x210c0, 0x24425038, 
 0x2e22021, 0x24020012, 0x240c0001, 0xac820000, 
 0xac8c0004, 0x5600000d, 0x24100001, 0x8ee204e4, 
-0x3c040001, 0x248457a4, 0xafa00014, 0xafa20010, 
+0x3c040001, 0x24845754, 0xafa00014, 0xafa20010, 
 0x8ee60608, 0x8f470228, 0x3c050009, 0x34a5f006, 
 0xc002403, 0xafab0038, 0x8fab0038, 0x1200030a, 
 0x240c0001, 0x8002f19, 0x0, 0x966c001c, 
@@ -2010,7 +2010,7 @@
 0x24420001, 0xaee24e30, 0x8ee24e30, 0x210c0, 
 0x24425038, 0x2e22021, 0x24020012, 0x240c0001, 
 0xac820000, 0xac8c0004, 0x5600000d, 0x24100001, 
-0x8ee204e4, 0x3c040001, 0x248457a4, 0xafa00014, 
+0x8ee204e4, 0x3c040001, 0x24845754, 0xafa00014, 
 0xafa20010, 0x8ee60608, 0x8f470228, 0x3c050009, 
 0x34a5f006, 0xc002403, 0xafab0038, 0x8fab0038, 
 0x16000003, 0x240c0001, 0x8002f5c, 0xa2ec04f4, 
@@ -2065,7 +2065,7 @@
 0x8821, 0x8f8200e4, 0x24110001, 0x8c430000, 
 0x8c440004, 0xafa30018, 0xafa4001c, 0x1620000e, 
 0x3c02ffff, 0x8f8200c4, 0xafa20010, 0x8f8200c8, 
-0x3c040001, 0x248458c0, 0xafa20014, 0x8f8600e0, 
+0x3c040001, 0x24845870, 0xafa20014, 0x8f8600e0, 
 0x8f8700e4, 0x3c050006, 0xc002403, 0x34a5f000, 
 0x80034cc, 0x0, 0x8fa3001c, 0x8fb20018, 
 0x3074ffff, 0x2694fffc, 0x621024, 0x10400058, 
@@ -2163,11 +2163,11 @@
 0x862021, 0xaee400c0, 0xaee500c4, 0x8ee20058, 
 0x24420001, 0xaee20058, 0x8ee20058, 0x8ee2007c, 
 0x24420001, 0xaee2007c, 0x8ee2007c, 0x8f8200e0, 
-0xafa20010, 0x8f8200e4, 0x3c040001, 0x248458c8, 
+0xafa20010, 0x8f8200e4, 0x3c040001, 0x24845878, 
 0xafa20014, 0x8fa60018, 0x8fa7001c, 0x3c050006, 
 0xc002403, 0x34a5f003, 0x80034cc, 0x0, 
 0x8ee25240, 0xafa20010, 0x8ee25244, 0x3c040001, 
-0x248458d4, 0xafa20014, 0x8ee60e10, 0x8ee70e18, 
+0x24845884, 0xafa20014, 0x8ee60e10, 0x8ee70e18, 
 0x3c050006, 0xc002403, 0x34a5f002, 0x8ee201c0, 
 0x24420001, 0xaee201c0, 0x8ee20000, 0x8ee301c0, 
 0x2403ffbf, 0x431024, 0x8003470, 0xaee20000, 
@@ -2219,7 +2219,7 @@
 0x50550003, 0x1021, 0x8ee24e30, 0x24420001, 
 0xaee24e30, 0x8ee24e30, 0x210c0, 0x24425038, 
 0x2e22021, 0xac960000, 0xac9e0004, 0x16200018, 
-0x3c050006, 0x8e020018, 0x3c040001, 0x248458e0, 
+0x3c050006, 0x8e020018, 0x3c040001, 0x24845890, 
 0xafa20010, 0x8e020000, 0x8e030004, 0x34a5f009, 
 0x2003021, 0xc002403, 0xafa30014, 0x93a20037, 
 0x10400216, 0x340f8100, 0x8e420004, 0x8e430008, 
@@ -2252,7 +2252,7 @@
 0x210c0, 0x24425038, 0x2e22021, 0xac960000, 
 0xac9e0004, 0x1620000d, 0x0, 0xa60c000a, 
 0xa60a000e, 0x8f820100, 0xafa20010, 0x8f820104, 
-0x3c040001, 0x248458ec, 0x3c050006, 0xafa20014, 
+0x3c040001, 0x2484589c, 0x3c050006, 0xafa20014, 
 0x8ee6724c, 0x800343b, 0x34a5f00b, 0x3c010001, 
 0x370821, 0xa02083c0, 0xadab0000, 0x8ee201d8, 
 0x8ee3724c, 0x2442ffff, 0xaee201d8, 0x8ee201d8, 
@@ -2284,7 +2284,7 @@
 0x1021, 0x8ee24e30, 0x24420001, 0xaee24e30, 
 0x8ee24e30, 0x210c0, 0x24425038, 0x2e22021, 
 0xac8e0000, 0xac9e0004, 0x5620000d, 0x24110001, 
-0x8ee2724c, 0x3c040001, 0x248458f8, 0xafa00014, 
+0x8ee2724c, 0x3c040001, 0x248458a8, 0xafa00014, 
 0xafa20010, 0x8ee6724c, 0x8f470280, 0x3c050009, 
 0x34a5f008, 0xc002403, 0xafae0048, 0x8fae0048, 
 0x56200001, 0xaee00e1c, 0x8ee20188, 0x24420001, 
@@ -2311,7 +2311,7 @@
 0x8ee24e30, 0x24420001, 0xaee24e30, 0x8ee24e30, 
 0x210c0, 0x24425038, 0x2e22021, 0xac8e0000, 
 0xac9e0004, 0x1620000d, 0x0, 0x8ee2724c, 
-0x3c040001, 0x248458f8, 0xafa00014, 0xafa20010, 
+0x3c040001, 0x248458a8, 0xafa00014, 0xafa20010, 
 0x8ee6724c, 0x8f470280, 0x3c050009, 0x34a5f008, 
 0xc002403, 0xafae0048, 0x8fae0048, 0x8ee20174, 
 0x24420001, 0xaee20174, 0x8ee20174, 0x800346e, 
@@ -2341,7 +2341,7 @@
 0x8ee24e30, 0x210c0, 0x24425038, 0x2e22021, 
 0xac960000, 0xac9e0004, 0x1620001d, 0x0, 
 0xa60c000a, 0x8f820100, 0xafa20010, 0x8f820104, 
-0x3c040001, 0x248458ec, 0x3c050006, 0xafa20014, 
+0x3c040001, 0x2484589c, 0x3c050006, 0xafa20014, 
 0x8ee6724c, 0x34a5f00d, 0xc002403, 0x2003821, 
 0x93a20037, 0x10400031, 0x340f8100, 0x8e420004, 
 0x8e430008, 0x8e44000c, 0xa64f000c, 0xae420000, 
@@ -2403,7 +2403,7 @@
 0x10430007, 0x4821, 0x8f8200e4, 0x24090001, 
 0x8c430000, 0x8c440004, 0xafa30018, 0xafa4001c, 
 0x1520000e, 0x3c02ffff, 0x8f8200c4, 0xafa20010, 
-0x8f8200c8, 0x3c040001, 0x248458c0, 0xafa20014, 
+0x8f8200c8, 0x3c040001, 0x24845870, 0xafa20014, 
 0x8f8600e0, 0x8f8700e4, 0x3c050006, 0xc002403, 
 0x34a5f000, 0x8003850, 0x0, 0x8fa3001c, 
 0x8fb20018, 0x3073ffff, 0x2673fffc, 0x621024, 
@@ -2501,15 +2501,15 @@
 0x862021, 0xaee400c0, 0xaee500c4, 0x8ee20058, 
 0x24420001, 0xaee20058, 0x8ee20058, 0x8ee2007c, 
 0x24420001, 0xaee2007c, 0x8ee2007c, 0x8f8200e0, 
-0xafa20010, 0x8f8200e4, 0x3c040001, 0x248458c8, 
+0xafa20010, 0x8f8200e4, 0x3c040001, 0x24845878, 
 0xafa20014, 0x8fa60018, 0x8fa7001c, 0x3c050006, 
 0xc002403, 0x34a5f003, 0x8003850, 0x0, 
 0x8ee25240, 0xafa20010, 0x8ee25244, 0x3c040001, 
-0x248458d4, 0xafa20014, 0x8ee60e10, 0x8ee70e18, 
+0x24845884, 0xafa20014, 0x8ee60e10, 0x8ee70e18, 
 0xc002403, 0x34a5f002, 0x8ee201c0, 0x24420001, 
 0xaee201c0, 0x8ee20000, 0x8ee301c0, 0x2403ffbf, 
 0x431024, 0x80037f8, 0xaee20000, 0x8ee25240, 
-0xafa20010, 0x8ee25244, 0x3c040001, 0x248458d4, 
+0xafa20010, 0x8ee25244, 0x3c040001, 0x24845884, 
 0xafa20014, 0x8ee60e10, 0x8ee70e18, 0x3c050006, 
 0xc002403, 0x34a5f002, 0x8ee201c0, 0x24420001, 
 0xaee201c0, 0x80037f8, 0x8ee201c0, 0x96e20468, 
@@ -2568,7 +2568,7 @@
 0x24420001, 0xaee24e30, 0x8ee24e30, 0x210c0, 
 0x24425038, 0x2e22021, 0x24020007, 0xac820000, 
 0x24020001, 0xac820004, 0x15200018, 0x3c050006, 
-0x8e020018, 0x3c040001, 0x248458e0, 0xafa20010, 
+0x8e020018, 0x3c040001, 0x24845890, 0xafa20010, 
 0x8e020000, 0x8e030004, 0x34a5f009, 0x2003021, 
 0xc002403, 0xafa30014, 0x32c200ff, 0x1040002b, 
 0x34028100, 0x8e430004, 0x8e440008, 0x8e45000c, 
@@ -2628,7 +2628,7 @@
 0x10430007, 0x3821, 0x8f8200e4, 0x24070001, 
 0x8c430000, 0x8c440004, 0xafa30018, 0xafa4001c, 
 0x14e0000e, 0x3c02ffff, 0x8f8200c4, 0xafa20010, 
-0x8f8200c8, 0x3c040001, 0x24845904, 0xafa20014, 
+0x8f8200c8, 0x3c040001, 0x248458b4, 0xafa20014, 
 0x8f8600e0, 0x8f8700e4, 0x3c050006, 0xc002403, 
 0x34a5f200, 0x8003c5b, 0x0, 0x8fa3001c, 
 0x8fb20018, 0x3073ffff, 0x2673fffc, 0x621024, 
@@ -2726,11 +2726,11 @@
 0x862021, 0xaee400c0, 0xaee500c4, 0x8ee20058, 
 0x24420001, 0xaee20058, 0x8ee20058, 0x8ee2007c, 
 0x24420001, 0xaee2007c, 0x8ee2007c, 0x8f8200e0, 
-0xafa20010, 0x8f8200e4, 0x3c040001, 0x24845910, 
+0xafa20010, 0x8f8200e4, 0x3c040001, 0x248458c0, 
 0xafa20014, 0x8fa60018, 0x8fa7001c, 0x3c050006, 
 0xc002403, 0x34a5f203, 0x8003c5b, 0x0, 
 0x8ee25240, 0xafa20010, 0x8ee25244, 0x3c040001, 
-0x2484591c, 0xafa20014, 0x8ee60e10, 0x8ee70e18, 
+0x248458cc, 0xafa20014, 0x8ee60e10, 0x8ee70e18, 
 0x3c050006, 0xc002403, 0x34a5f202, 0x8ee201c0, 
 0x24420001, 0xaee201c0, 0x8003c02, 0x8ee201c0, 
 0x96e20468, 0x53102b, 0x54400001, 0x3c168000, 
@@ -2826,7 +2826,7 @@
 0x1021, 0x8ee24e30, 0x24420001, 0xaee24e30, 
 0x8ee24e30, 0x210c0, 0x24425038, 0x2e22021, 
 0x24020007, 0xac820000, 0x24020001, 0xac820004, 
-0x14e00019, 0x3c050006, 0x3c040001, 0x248458e0, 
+0x14e00019, 0x3c050006, 0x3c040001, 0x24845890, 
 0x8e220018, 0x34a5f209, 0xafa20010, 0x8e220000, 
 0x8e230004, 0x2203021, 0x1603821, 0xc002403, 
 0xafa30014, 0x93a2002f, 0x1040002a, 0x34028100, 
@@ -2890,7 +2890,7 @@
 0x24020001, 0xac620004, 0x1480000e, 0x24030040, 
 0x8ee20e14, 0xafa20010, 0x8ee20e18, 0x3c050007, 
 0xafa20014, 0x8ee60e0c, 0x8ee70e10, 0x3c040001, 
-0x24845924, 0xc002403, 0x34a5f001, 0x8003cdd, 
+0x248458d4, 0xc002403, 0x34a5f001, 0x8003cdd, 
 0x0, 0x8ee20500, 0x24420001, 0x50430003, 
 0x1021, 0x8ee20500, 0x24420001, 0xaee20500, 
 0x8ee20500, 0x21080, 0x571021, 0xac490508, 
@@ -2922,7 +2922,7 @@
 0x24020003, 0xac620000, 0x24020001, 0xac620004, 
 0x1480000e, 0x24030040, 0x8ee2523c, 0xafa20010, 
 0x8ee25244, 0x3c050007, 0xafa20014, 0x8ee65238, 
-0x8ee75240, 0x3c040001, 0x24845930, 0xc002403, 
+0x8ee75240, 0x3c040001, 0x248458e0, 0xc002403, 
 0x34a5f010, 0x8003d5f, 0x0, 0x8ee20500, 
 0x24420001, 0x50430003, 0x1021, 0x8ee20500, 
 0x24420001, 0xaee20500, 0x8ee20500, 0x21080, 
@@ -2942,7 +2942,7 @@
 0x8f830128, 0x21140, 0x621821, 0xaf830128, 
 0xaca00000, 0x8cc20018, 0x2443fffe, 0x2c620012, 
 0x10400008, 0x31080, 0x3c010001, 0x220821, 
-0x8c225940, 0x400008, 0x0, 0x24020001, 
+0x8c2258f0, 0x400008, 0x0, 0x24020001, 
 0xaee24e24, 0x3e00008, 0x0, 0x27bdffc8, 
 0xafbf0030, 0xafb5002c, 0xafb40028, 0xafb30024, 
 0xafb20020, 0xafb1001c, 0xafb00018, 0x8f830128, 
@@ -2951,7 +2951,7 @@
 0x24140040, 0x8f8c0128, 0x8f820128, 0x24420020, 
 0xaf820128, 0x9182001b, 0x8f830128, 0x2443fffe, 
 0x2c620012, 0x1040029c, 0x31080, 0x3c010001, 
-0x220821, 0x8c225998, 0x400008, 0x0, 
+0x220821, 0x8c225948, 0x400008, 0x0, 
 0x8f420218, 0x30420100, 0x10400007, 0x0, 
 0x95830016, 0x95820018, 0x621823, 0x31402, 
 0x431021, 0xa5820016, 0x8d82001c, 0x3c038000, 
@@ -3052,7 +3052,7 @@
 0x24420001, 0xaee24e30, 0x8ee24e30, 0x210c0, 
 0x24425038, 0x2e22021, 0x24020007, 0xac820000, 
 0x24020001, 0xac820004, 0x1600000d, 0x0, 
-0x8f820120, 0x3c040001, 0x24845988, 0xafa00014, 
+0x8f820120, 0x3c040001, 0x24845938, 0xafa00014, 
 0xafa20010, 0x8d86001c, 0x8f870124, 0x3c050008, 
 0xc002403, 0x34a50001, 0x8004057, 0x0, 
 0x8ee2724c, 0x24420001, 0x304207ff, 0x11a00006, 
@@ -3087,7 +3087,7 @@
 0x24420001, 0xaee24e30, 0x8ee24e30, 0x210c0, 
 0x24425038, 0x2e22021, 0x24020001, 0xac950000, 
 0xac820004, 0x5600000b, 0x24100001, 0x8ee2724c, 
-0x3c040001, 0x248458f8, 0xafa00014, 0xafa20010, 
+0x3c040001, 0x248458a8, 0xafa00014, 0xafa20010, 
 0x8ee6724c, 0x8f470280, 0x3c050009, 0xc002403, 
 0x34a5f008, 0x56000001, 0xaee00e1c, 0x8ee20188, 
 0x24420001, 0xaee20188, 0x8004050, 0x8ee20188, 
@@ -3113,7 +3113,7 @@
 0x1021, 0x8ee24e30, 0x24420001, 0xaee24e30, 
 0x8ee24e30, 0x210c0, 0x24425038, 0x2e22021, 
 0x24020001, 0xac950000, 0xac820004, 0x1600000b, 
-0x0, 0x8ee2724c, 0x3c040001, 0x248458f8, 
+0x0, 0x8ee2724c, 0x3c040001, 0x248458a8, 
 0xafa00014, 0xafa20010, 0x8ee6724c, 0x8f470280, 
 0x3c050009, 0xc002403, 0x34a5f008, 0x8ee20174, 
 0x24420001, 0xaee20174, 0x8004057, 0x8ee20174, 
@@ -3125,16 +3125,16 @@
 0xc00249a, 0xafb00010, 0x2021, 0x24100001, 
 0x2402241f, 0xaf900210, 0xaf900200, 0xaf800204, 
 0xaf820214, 0x8f460248, 0x24030004, 0x3c020040, 
-0x3c010001, 0xac235d24, 0x3c010001, 0xac235d28, 
-0x3c010001, 0xac205dfc, 0x3c010001, 0xac225d20, 
-0x3c010001, 0xac235d28, 0xc0050e0, 0x24050004, 
-0xc0047fc, 0x0, 0x8ee20000, 0x3c03feff, 
+0x3c010001, 0xac235cc4, 0x3c010001, 0xac235cc8, 
+0x3c010001, 0xac205d9c, 0x3c010001, 0xac225cc0, 
+0x3c010001, 0xac235cc8, 0xc005108, 0x24050004, 
+0xc004822, 0x0, 0x8ee20000, 0x3c03feff, 
 0x3463fffd, 0x431024, 0xaee20000, 0x3c023c00, 
 0xaf82021c, 0x3c010001, 0x370821, 0xac3083ac, 
 0x8fbf0014, 0x8fb00010, 0x3e00008, 0x27bd0018, 
 0x27bdffe0, 0x3c050008, 0x34a50400, 0xafbf0018, 
 0xafa00010, 0xafa00014, 0x8f860200, 0x3c040001, 
-0x24845a40, 0xc002403, 0x3821, 0x8ee20280, 
+0x248459f0, 0xc002403, 0x3821, 0x8ee20280, 
 0x24420001, 0xaee20280, 0x8ee20280, 0x8f830200, 
 0x3c023f00, 0x621824, 0x8fbf0018, 0x3c020400, 
 0x3e00008, 0x27bd0020, 0x27bdffd8, 0xafbf0020, 
@@ -3146,16 +3146,16 @@
 0xaee20218, 0x8ee20218, 0x80040c6, 0x3c03fdff, 
 0x8ee2021c, 0x24420001, 0xaee2021c, 0x8ee2021c, 
 0x3c03fdff, 0x3463ffff, 0x3c0808ff, 0x3508ffff, 
-0x8ee20000, 0x3c040001, 0x24845a4c, 0x3c050008, 
+0x8ee20000, 0x3c040001, 0x248459fc, 0x3c050008, 
 0x2003021, 0x431024, 0xaee20000, 0x8f820220, 
 0x3821, 0x3c030300, 0x481024, 0x431025, 
 0xaf820220, 0xafa00010, 0xc002403, 0xafa00014, 
 0x8004296, 0x0, 0x2111024, 0x1040001f, 
 0x3c024000, 0x8f830224, 0x24021402, 0x1462000b, 
-0x3c03fdff, 0x3c040001, 0x24845a58, 0x3c050008, 
+0x3c03fdff, 0x3c040001, 0x24845a08, 0x3c050008, 
 0xafa00010, 0xafa00014, 0x8f860224, 0x34a5ffff, 
 0xc002403, 0x3821, 0x3c03fdff, 0x8ee20000, 
-0x3463ffff, 0x2002021, 0x431024, 0xc004e2c, 
+0x3463ffff, 0x2002021, 0x431024, 0xc004e54, 
 0xaee20000, 0x8ee20220, 0x24420001, 0xaee20220, 
 0x8ee20220, 0x8f820220, 0x3c0308ff, 0x3463ffff, 
 0x431024, 0x8004295, 0x511025, 0x2021024, 
@@ -3226,7 +3226,7 @@
 0x431025, 0xaf820220, 0x8f8600e0, 0x8f8400e4, 
 0x10c4002a, 0x0, 0x8ee2007c, 0x24420001, 
 0xaee2007c, 0x8ee2007c, 0x24c2fff8, 0xaf8200e0, 
-0x3c020001, 0x8c427e90, 0x3c030008, 0x8f8600e0, 
+0x3c020001, 0x8c427e30, 0x3c030008, 0x8f8600e0, 
 0x431024, 0x1040001d, 0x0, 0x10c4001b, 
 0x240dfff8, 0x3c0a000a, 0x354af000, 0x3c0c0080, 
 0x24850008, 0x27622800, 0x50a20001, 0x27651800, 
@@ -3262,12 +3262,12 @@
 0x621023, 0x2c420002, 0x1440fffc, 0x0, 
 0x8f820220, 0x3c0308ff, 0x3463fffb, 0x431024, 
 0xaf820220, 0x8fbf0020, 0x8fb1001c, 0x8fb00018, 
-0x3e00008, 0x27bd0028, 0x3c020001, 0x8c425d38, 
+0x3e00008, 0x27bd0028, 0x3c020001, 0x8c425cd8, 
 0x27bdffd8, 0x10400012, 0xafbf0020, 0x3c040001, 
-0x24845a64, 0x3c050008, 0x24020001, 0x3c010001, 
+0x24845a14, 0x3c050008, 0x24020001, 0x3c010001, 
 0x370821, 0xac2283ac, 0xafa00010, 0xafa00014, 
-0x8f860220, 0x34a50498, 0x3c010001, 0xac205d38, 
-0x3c010001, 0xac225d2c, 0xc002403, 0x3821, 
+0x8f860220, 0x34a50498, 0x3c010001, 0xac205cd8, 
+0x3c010001, 0xac225ccc, 0xc002403, 0x3821, 
 0x8f420268, 0x3c037fff, 0x3463ffff, 0x431024, 
 0xaf420268, 0x8ee204d0, 0x8ee404d4, 0x2403fffe, 
 0x431024, 0x30840002, 0x1080011e, 0xaee204d0, 
@@ -3333,24 +3333,24 @@
 0x54a00006, 0x240b0001, 0x8f820054, 0x1221023, 
 0x2c420033, 0x1440ffa6, 0x0, 0x316300ff, 
 0x24020001, 0x54620003, 0xafa00010, 0x80043d6, 
-0x0, 0x3c040001, 0x24845a70, 0xafa00014, 
+0x0, 0x3c040001, 0x24845a20, 0xafa00014, 
 0x8f860120, 0x8f870124, 0x3c050009, 0xc002403, 
 0x34a5f011, 0x80043d6, 0x0, 0x3c040001, 
-0x24845a7c, 0xafa00014, 0x8f860120, 0x8f870124, 
+0x24845a2c, 0xafa00014, 0x8f860120, 0x8f870124, 
 0x3c050009, 0xc002403, 0x34a5f010, 0x80043d6, 
-0x0, 0x3c040001, 0x24845a88, 0xafa00014, 
+0x0, 0x3c040001, 0x24845a38, 0xafa00014, 
 0x8ee60608, 0x8f470228, 0x3c050009, 0xc002403, 
 0x34a5f00f, 0x8ee201ac, 0x24420001, 0xaee201ac, 
 0x8ee201ac, 0x8ee2015c, 0x24420001, 0xaee2015c, 
 0x8ee2015c, 0x8fbf0020, 0x3e00008, 0x27bd0028, 
-0x3c020001, 0x8c425d38, 0x27bdffe0, 0x1440000d, 
-0xafbf0018, 0x3c040001, 0x24845a94, 0x3c050008, 
+0x3c020001, 0x8c425cd8, 0x27bdffe0, 0x1440000d, 
+0xafbf0018, 0x3c040001, 0x24845a44, 0x3c050008, 
 0xafa00010, 0xafa00014, 0x8f860220, 0x34a50499, 
-0x24020001, 0x3c010001, 0xac225d38, 0xc002403, 
+0x24020001, 0x3c010001, 0xac225cd8, 0xc002403, 
 0x3821, 0x8ee204d0, 0x3c030001, 0x771821, 
 0x946383b2, 0x34420001, 0x10600007, 0xaee204d0, 
 0x8f820220, 0x3c0308ff, 0x3463ffff, 0x431024, 
-0x34420008, 0xaf820220, 0x2021, 0xc005276, 
+0x34420008, 0xaf820220, 0x2021, 0xc0052a2, 
 0x24050004, 0xaf420268, 0x8fbf0018, 0x3e00008, 
 0x27bd0020, 0x0, 0x0, 0x0, 
 0x0, 0x0, 0x0, 0x0, 
@@ -3368,7 +3368,7 @@
 0x0, 0x0, 0x0, 0x0, 
 0x0, 0x0, 0x0, 0x0, 
 0x0, 0x0, 0x0, 0x3c120001, 
-0x26521200, 0x3c140001, 0x8e945cb0, 0x3c100001, 
+0x26521200, 0x3c140001, 0x8e945c50, 0x3c100001, 
 0x26101120, 0x3c15c000, 0x36b50060, 0x8e8a0000, 
 0x8eb30000, 0x26a400b, 0x248000a, 0x200f821, 
 0x0, 0xd, 0x0, 0x0, 
@@ -3429,978 +3429,973 @@
 0x1062000c, 0x43102b, 0x14400006, 0x3c026000, 
 0x3c024000, 0x10620008, 0x24020800, 0x8004539, 
 0x0, 0x10620004, 0x24020800, 0x8004539, 
-0x0, 0x24020700, 0x3c010001, 0xac225d3c, 
-0x3e00008, 0x0, 0x27bdffd0, 0xafbf0028, 
-0x8f830054, 0x8f820054, 0x3c010001, 0xac205d24, 
-0x8004544, 0x24630064, 0x8f820054, 0x621023, 
-0x2c420065, 0x1440fffc, 0x0, 0xc004d49, 
-0x0, 0x24040001, 0x2821, 0x27a60020, 
-0x34028000, 0xc004966, 0xa7a20020, 0x8f830054, 
-0x8f820054, 0x8004555, 0x24630064, 0x8f820054, 
-0x621023, 0x2c420065, 0x1440fffc, 0x24040001, 
-0x24050001, 0xc004924, 0x27a60020, 0x8f830054, 
-0x8f820054, 0x8004561, 0x24630064, 0x8f820054, 
-0x621023, 0x2c420065, 0x1440fffc, 0x24040001, 
-0x24050001, 0xc004924, 0x27a60020, 0x8f830054, 
-0x8f820054, 0x800456d, 0x24630064, 0x8f820054, 
-0x621023, 0x2c420065, 0x1440fffc, 0x24040001, 
-0x24050002, 0xc004924, 0x27a60018, 0x8f830054, 
-0x8f820054, 0x8004579, 0x24630064, 0x8f820054, 
-0x621023, 0x2c420065, 0x1440fffc, 0x24040001, 
-0x24050003, 0xc004924, 0x27a6001a, 0x3c040001, 
-0x24845b00, 0x97a60020, 0x97a70018, 0x97a2001a, 
-0x3c05000d, 0x34a50100, 0xafa00014, 0xc002403, 
-0xafa20010, 0x97a20020, 0x10400045, 0x24036040, 
-0x97a2001a, 0x3042fff0, 0x14430009, 0x24020020, 
-0x97a30018, 0x54620008, 0x24027830, 0x24020003, 
-0x3c010001, 0xac225d24, 0x80045a4, 0x24020005, 
-0x97a30018, 0x24027830, 0x1462000e, 0x24030010, 
-0x97a2001a, 0x3042fff0, 0x1443000a, 0x24020003, 
-0x3c010001, 0xac225d24, 0x24020006, 0x3c010001, 
-0xac225e0c, 0x3c010001, 0xac225e18, 0x80045da, 
-0x3c09fff0, 0x3c020001, 0x8c425d24, 0x97a30018, 
-0x34420001, 0x3c010001, 0xac225d24, 0x24020015, 
-0x1462000e, 0x0, 0x97a2001a, 0x3042fff0, 
-0x3843f420, 0x2c630001, 0x3842f430, 0x2c420001, 
-0x621825, 0x10600005, 0x24020003, 0x3c010001, 
-0xac225e18, 0x80045da, 0x3c09fff0, 0x97a30018, 
-0x24027810, 0x1462000a, 0x24020002, 0x97a2001a, 
+0x0, 0x24020700, 0x3c010001, 0xac225cdc, 
+0x3e00008, 0x0, 0x27bdffd8, 0xafbf0024, 
+0xafb00020, 0x8f830054, 0x8f820054, 0x3c010001, 
+0xac205cc4, 0x8004545, 0x24630064, 0x8f820054, 
+0x621023, 0x2c420065, 0x1440fffc, 0x0, 
+0xc004d71, 0x0, 0x24040001, 0x2821, 
+0x27a60018, 0x34028000, 0xc00498e, 0xa7a20018, 
+0x8f830054, 0x8f820054, 0x8004556, 0x24630064, 
+0x8f820054, 0x621023, 0x2c420065, 0x1440fffc, 
+0x24040001, 0x24050001, 0xc00494c, 0x27a60018, 
+0x8f830054, 0x8f820054, 0x8004562, 0x24630064, 
+0x8f820054, 0x621023, 0x2c420065, 0x1440fffc, 
+0x24040001, 0x24050001, 0xc00494c, 0x27a60018, 
+0x8f830054, 0x8f820054, 0x800456e, 0x24630064, 
+0x8f820054, 0x621023, 0x2c420065, 0x1440fffc, 
+0x24040001, 0x3c060001, 0x24c65da0, 0xc00494c, 
+0x24050002, 0x8f830054, 0x8f820054, 0x800457b, 
+0x24630064, 0x8f820054, 0x621023, 0x2c420065, 
+0x1440fffc, 0x24040001, 0x24050003, 0x3c100001, 
+0x26105da2, 0xc00494c, 0x2003021, 0x97a60018, 
+0x3c070001, 0x94e75da0, 0x3c040001, 0x24845ab0, 
+0xafa00014, 0x96020000, 0x3c05000d, 0x34a50100, 
+0xc002403, 0xafa20010, 0x97a20018, 0x1040004c, 
+0x24036040, 0x96020000, 0x3042fff0, 0x1443000a, 
+0x24020020, 0x3c030001, 0x94635da0, 0x54620009, 
+0x24027830, 0x24020003, 0x3c010001, 0xac225cc4, 
+0x80045ac, 0x24020005, 0x3c030001, 0x94635da0, 
+0x24027830, 0x1462000f, 0x24030010, 0x3c020001, 
+0x94425da2, 0x3042fff0, 0x1443000a, 0x24020003, 
+0x3c010001, 0xac225cc4, 0x24020006, 0x3c010001, 
+0xac225db0, 0x3c010001, 0xac225dbc, 0x80045e6, 
+0x3c09fff0, 0x3c020001, 0x8c425cc4, 0x3c030001, 
+0x94635da0, 0x34420001, 0x3c010001, 0xac225cc4, 
+0x24020015, 0x1462000f, 0x0, 0x3c020001, 
+0x94425da2, 0x3042fff0, 0x3843f420, 0x2c630001, 
+0x3842f430, 0x2c420001, 0x621825, 0x10600005, 
+0x24020003, 0x3c010001, 0xac225dbc, 0x80045e6, 
+0x3c09fff0, 0x3c030001, 0x94635da0, 0x24027810, 
+0x1462000b, 0x24020002, 0x3c020001, 0x94425da2, 
 0x3042fff0, 0x14400006, 0x24020002, 0x24020004, 
-0x3c010001, 0xac225e18, 0x80045da, 0x3c09fff0, 
-0x3c010001, 0xac225e18, 0x80045da, 0x3c09fff0, 
-0x3c020001, 0x8c425d24, 0x24030001, 0x3c010001, 
-0xac235e18, 0x34420004, 0x3c010001, 0xac225d24, 
-0x3c09fff0, 0x3529bdc0, 0x8f830054, 0x3c060001, 
-0x8cc65d24, 0x3c070001, 0x8ce75e18, 0x97a80018, 
-0x3c040001, 0x24845b00, 0x24020001, 0x3c010001, 
-0xac225d2c, 0xafa80010, 0x97a2001a, 0x3c05000d, 
-0x34a50100, 0x3c010001, 0xac205d28, 0x691821, 
-0x3c010001, 0xac235e08, 0xc002403, 0xafa20014, 
-0x8fbf0028, 0x3e00008, 0x27bd0030, 0x27bdffe8, 
-0x3c050001, 0x8ca55d28, 0x24060004, 0x24020001, 
-0x14a20014, 0xafbf0010, 0x3c020001, 0x8c427e9c, 
-0x30428000, 0x10400005, 0x3c04000f, 0x3c030001, 
-0x8c635e18, 0x8004608, 0x34844240, 0x3c040004, 
-0x3c030001, 0x8c635e18, 0x348493e0, 0x24020005, 
-0x14620016, 0x0, 0x3c04003d, 0x8004620, 
-0x34840900, 0x3c020001, 0x8c427e98, 0x30428000, 
-0x10400005, 0x3c04001e, 0x3c030001, 0x8c635e18, 
-0x800461b, 0x34848480, 0x3c04000f, 0x3c030001, 
-0x8c635e18, 0x34844240, 0x24020005, 0x14620003, 
-0x0, 0x3c04007a, 0x34841200, 0x3c020001, 
-0x8c425e08, 0x8f830054, 0x441021, 0x431023, 
-0x44102b, 0x14400037, 0x0, 0x3c020001, 
-0x8c425d30, 0x14400033, 0x0, 0x3c010001, 
-0x10c00025, 0xac205d40, 0x3c090001, 0x8d295d24, 
-0x24070001, 0x3c044000, 0x3c080001, 0x25087e9c, 
-0x250afffc, 0x52842, 0x14a00002, 0x24c6ffff, 
-0x24050008, 0xa91024, 0x10400010, 0x0, 
-0x14a70008, 0x0, 0x8d020000, 0x441024, 
-0x1040000a, 0x0, 0x3c010001, 0x800464c, 
-0xac255d40, 0x8d420000, 0x441024, 0x10400003, 
-0x0, 0x3c010001, 0xac275d40, 0x3c020001, 
-0x8c425d40, 0x6182b, 0x2c420001, 0x431024, 
-0x5440ffe5, 0x52842, 0x8f820054, 0x3c030001, 
-0x8c635d40, 0x3c010001, 0xac225e08, 0x1060002a, 
-0x24020001, 0x3c010001, 0xac255d28, 0x3c010001, 
-0xac225d2c, 0x3c020001, 0x8c425d40, 0x10400022, 
-0x0, 0x3c020001, 0x8c425d2c, 0x1040000a, 
-0x24020001, 0x3c010001, 0xac205d2c, 0x3c010001, 
-0x370821, 0xac2283ac, 0x3c010001, 0xac205dac, 
-0x3c010001, 0xac225d64, 0x3c030001, 0x771821, 
-0x8c6383ac, 0x24020008, 0x10620005, 0x24020001, 
-0xc004686, 0x0, 0x8004683, 0x0, 
-0x3c030001, 0x8c635d28, 0x10620007, 0x2402000e, 
-0x3c030001, 0x8c637e30, 0x10620003, 0x0, 
-0xc004e2c, 0x8f840220, 0x8fbf0010, 0x3e00008, 
-0x27bd0018, 0x27bdffe0, 0x3c02fdff, 0xafbf001c, 
-0xafb00018, 0x8ee30000, 0x3c050001, 0x8ca55d28, 
-0x3c040001, 0x8c845d50, 0x3442ffff, 0x621824, 
-0x14a40008, 0xaee30000, 0x3c030001, 0x771821, 
-0x8c6383ac, 0x3c020001, 0x8c425d54, 0x10620008, 
-0x0, 0x3c020001, 0x571021, 0x8c4283ac, 
-0x3c010001, 0xac255d50, 0x3c010001, 0xac225d54, 
-0x3c030001, 0x8c635d28, 0x24020002, 0x10620150, 
-0x2c620003, 0x10400005, 0x24020001, 0x10620008, 
-0x0, 0x80047f5, 0x0, 0x24020004, 
-0x10620098, 0x24020001, 0x80047f6, 0x0, 
-0x3c020001, 0x571021, 0x8c4283ac, 0x2443ffff, 
-0x2c620008, 0x10400141, 0x31080, 0x3c010001, 
-0x220821, 0x8c225b18, 0x400008, 0x0, 
-0x3c030001, 0x8c635e18, 0x24020005, 0x14620014, 
-0x0, 0x3c020001, 0x8c425d34, 0x1040000a, 
-0x24020003, 0xc0047fc, 0x0, 0x24020002, 
+0x3c010001, 0xac225dbc, 0x80045e6, 0x3c09fff0, 
+0x3c010001, 0xac225dbc, 0x80045e6, 0x3c09fff0, 
+0x3c020001, 0x8c425cc4, 0x24030001, 0x3c010001, 
+0xac235dbc, 0x34420004, 0x3c010001, 0xac225cc4, 
+0x3c09fff0, 0x3529bdc0, 0x3c060001, 0x8cc65cc4, 
+0x3c040001, 0x24845ab0, 0x24020001, 0x3c010001, 
+0xac225ccc, 0x8f820054, 0x3c070001, 0x8ce75dbc, 
+0x3c030001, 0x94635da0, 0x3c080001, 0x95085da2, 
+0x3c05000d, 0x34a50100, 0x3c010001, 0xac205cc8, 
+0x491021, 0x3c010001, 0xac225dac, 0xafa30010, 
+0xc002403, 0xafa80014, 0x8fbf0024, 0x8fb00020, 
+0x3e00008, 0x27bd0028, 0x27bdffe8, 0x3c050001, 
+0x8ca55cc8, 0x24060004, 0x24020001, 0x14a20014, 
+0xafbf0010, 0x3c020001, 0x8c427e3c, 0x30428000, 
+0x10400005, 0x3c04000f, 0x3c030001, 0x8c635dbc, 
+0x8004617, 0x34844240, 0x3c040004, 0x3c030001, 
+0x8c635dbc, 0x348493e0, 0x24020005, 0x14620016, 
+0x0, 0x3c04003d, 0x800462f, 0x34840900, 
+0x3c020001, 0x8c427e38, 0x30428000, 0x10400005, 
+0x3c04001e, 0x3c030001, 0x8c635dbc, 0x800462a, 
+0x34848480, 0x3c04000f, 0x3c030001, 0x8c635dbc, 
+0x34844240, 0x24020005, 0x14620003, 0x0, 
+0x3c04007a, 0x34841200, 0x3c020001, 0x8c425dac, 
+0x8f830054, 0x441021, 0x431023, 0x44102b, 
+0x14400037, 0x0, 0x3c020001, 0x8c425cd0, 
+0x14400033, 0x0, 0x3c010001, 0x10c00025, 
+0xac205ce0, 0x3c090001, 0x8d295cc4, 0x24070001, 
+0x3c044000, 0x3c080001, 0x25087e3c, 0x250afffc, 
+0x52842, 0x14a00002, 0x24c6ffff, 0x24050008, 
+0xa91024, 0x10400010, 0x0, 0x14a70008, 
+0x0, 0x8d020000, 0x441024, 0x1040000a, 
+0x0, 0x3c010001, 0x800465b, 0xac255ce0, 
+0x8d420000, 0x441024, 0x10400003, 0x0, 
+0x3c010001, 0xac275ce0, 0x3c020001, 0x8c425ce0, 
+0x6182b, 0x2c420001, 0x431024, 0x5440ffe5, 
+0x52842, 0x8f820054, 0x3c030001, 0x8c635ce0, 
+0x3c010001, 0xac225dac, 0x1060002a, 0x24020001, 
+0x3c010001, 0xac255cc8, 0x3c010001, 0xac225ccc, 
+0x3c020001, 0x8c425ce0, 0x10400022, 0x0, 
+0x3c020001, 0x8c425ccc, 0x1040000a, 0x24020001, 
+0x3c010001, 0xac205ccc, 0x3c010001, 0x370821, 
+0xac2283ac, 0x3c010001, 0xac205d4c, 0x3c010001, 
+0xac225d04, 0x3c030001, 0x771821, 0x8c6383ac, 
+0x24020008, 0x10620005, 0x24020001, 0xc004695, 
+0x0, 0x8004692, 0x0, 0x3c030001, 
+0x8c635cc8, 0x10620007, 0x2402000e, 0x3c030001, 
+0x8c637dd0, 0x10620003, 0x0, 0xc004e54, 
+0x8f840220, 0x8fbf0010, 0x3e00008, 0x27bd0018, 
+0x27bdffe0, 0x3c02fdff, 0xafbf0018, 0x8ee30000, 
+0x3c050001, 0x8ca55cc8, 0x3c040001, 0x8c845cf0, 
+0x3442ffff, 0x621824, 0x14a40008, 0xaee30000, 
+0x3c030001, 0x771821, 0x8c6383ac, 0x3c020001, 
+0x8c425cf4, 0x10620008, 0x0, 0x3c020001, 
+0x571021, 0x8c4283ac, 0x3c010001, 0xac255cf0, 
+0x3c010001, 0xac225cf4, 0x3c030001, 0x8c635cc8, 
+0x24020002, 0x10620169, 0x2c620003, 0x10400005, 
+0x24020001, 0x10620008, 0x0, 0x800481c, 
+0x0, 0x24020004, 0x106200b1, 0x24020001, 
+0x800481d, 0x0, 0x3c020001, 0x571021, 
+0x8c4283ac, 0x2443ffff, 0x2c620008, 0x1040015a, 
+0x31080, 0x3c010001, 0x220821, 0x8c225ac8, 
+0x400008, 0x0, 0x3c030001, 0x8c635dbc, 
+0x24020005, 0x14620014, 0x0, 0x3c020001, 
+0x8c425cd4, 0x1040000a, 0x24020003, 0xc004822, 
+0x0, 0x24020002, 0x3c010001, 0x370821, 
+0xac2283ac, 0x3c010001, 0x80046e0, 0xac205cd4, 
 0x3c010001, 0x370821, 0xac2283ac, 0x3c010001, 
-0x80046d2, 0xac205d34, 0x3c010001, 0x370821, 
-0xac2283ac, 0x3c010001, 0x80047f8, 0xac205cc0, 
-0xc0047fc, 0x0, 0x3c020001, 0x8c425d34, 
-0x3c010001, 0xac205cc0, 0x104000c4, 0x24020002, 
+0x800481f, 0xac205c60, 0xc004822, 0x0, 
+0x3c020001, 0x8c425cd4, 0x3c010001, 0xac205c60, 
+0x104000dd, 0x24020002, 0x3c010001, 0x370821, 
+0xac2283ac, 0x3c010001, 0x800481f, 0xac205cd4, 
+0x3c030001, 0x8c635dbc, 0x24020005, 0x14620003, 
+0x24020001, 0x3c010001, 0xac225d00, 0xc0049cf, 
+0x0, 0x3c030001, 0x8c635d00, 0x800478e, 
+0x24020011, 0x3c050001, 0x8ca55cc8, 0x3c060001, 
+0x8cc67e3c, 0xc005108, 0x2021, 0x24020005, 
+0x3c010001, 0xac205cd4, 0x3c010001, 0x370821, 
+0x800481f, 0xac2283ac, 0x3c040001, 0x24845abc, 
+0x3c05000f, 0x34a50100, 0x3021, 0x3821, 
+0xafa00010, 0xc002403, 0xafa00014, 0x800481f, 
+0x0, 0x8f820220, 0x3c03f700, 0x431025, 
+0x80047b7, 0xaf820220, 0x8f820220, 0x3c030004, 
+0x431024, 0x144000a9, 0x24020007, 0x8f830054, 
+0x3c020001, 0x8c425da4, 0x2463d8f0, 0x431023, 
+0x2c422710, 0x144000f8, 0x24020001, 0x800481d, 
+0x0, 0x3c050001, 0x8ca55cc8, 0xc0052a2, 
+0x2021, 0xc005386, 0x2021, 0x3c030001, 
+0x8c637e34, 0x46100ea, 0x24020001, 0x3c020008, 
+0x621024, 0x10400006, 0x0, 0x8f820214, 
+0x3c03ffff, 0x431024, 0x8004741, 0x3442251f, 
+0x8f820214, 0x3c03ffff, 0x431024, 0x3442241f, 
+0xaf820214, 0x8ee20000, 0x3c030200, 0x431025, 
+0xaee20000, 0x8f820220, 0x2403fffb, 0x431024, 
+0xaf820220, 0x8f820220, 0x34420002, 0xaf820220, 
+0x24020008, 0x3c010001, 0x370821, 0xac2283ac, 
+0x8f820220, 0x3c030004, 0x431024, 0x14400005, 
+0x0, 0x8f820220, 0x3c03f700, 0x431025, 
+0xaf820220, 0x3c030001, 0x8c635dbc, 0x24020005, 
+0x1462000a, 0x0, 0x3c020001, 0x94425da2, 
+0x24429fbc, 0x2c420004, 0x10400004, 0x24040018, 
+0x24050002, 0xc004d93, 0x24060020, 0xc0043dd, 
+0x0, 0x3c010001, 0x800481f, 0xac205d50, 
+0x3c020001, 0x571021, 0x8c4283ac, 0x2443ffff, 
+0x2c620008, 0x104000ac, 0x31080, 0x3c010001, 
+0x220821, 0x8c225ae8, 0x400008, 0x0, 
+0xc00429b, 0x0, 0x3c010001, 0xac205ccc, 
+0xaf800204, 0x3c010001, 0xc004822, 0xac207e20, 
+0x24020001, 0x3c010001, 0xac225ce4, 0x24020002, 
+0x3c010001, 0x370821, 0x800481f, 0xac2283ac, 
+0xc00489f, 0x0, 0x3c030001, 0x8c635ce4, 
+0x24020009, 0x14620090, 0x24020003, 0x3c010001, 
+0x370821, 0x800481f, 0xac2283ac, 0x3c020001, 
+0x8c427e38, 0x30424000, 0x10400005, 0x0, 
+0x8f820044, 0x3c03ffff, 0x800479f, 0x34637fff, 
+0x8f820044, 0x2403ff7f, 0x431024, 0xaf820044, 
+0x8f830054, 0x80047b9, 0x24020004, 0x8f830054, 
+0x3c020001, 0x8c425da4, 0x2463d8f0, 0x431023, 
+0x2c422710, 0x14400074, 0x24020005, 0x3c010001, 
+0x370821, 0x800481f, 0xac2283ac, 0x8f820220, 
+0x3c03f700, 0x431025, 0xaf820220, 0xaf800204, 
+0x3c010001, 0xac207e20, 0x8f830054, 0x24020006, 
 0x3c010001, 0x370821, 0xac2283ac, 0x3c010001, 
-0x80047f8, 0xac205d34, 0x24020001, 0x3c010001, 
-0xc0049a7, 0xac225d60, 0x3c030001, 0x8c635d60, 
-0x8004767, 0x24020011, 0x3c020001, 0x8c425e18, 
-0x24100005, 0x10500007, 0x0, 0x3c050001, 
-0x8ca55d28, 0x3c060001, 0x8cc67e9c, 0xc0050e0, 
-0x2021, 0x3c010001, 0xac205d34, 0x3c010001, 
-0x370821, 0x80047f8, 0xac3083ac, 0x3c040001, 
-0x24845b0c, 0x3c05000f, 0x34a50100, 0x3021, 
-0x3821, 0xafa00010, 0xc002403, 0xafa00014, 
-0x80047f8, 0x0, 0x8f820220, 0x3c03f700, 
-0x431025, 0x8004790, 0xaf820220, 0x8f820220, 
-0x3c030004, 0x431024, 0x14400091, 0x24020007, 
-0x8f830054, 0x3c020001, 0x8c425e00, 0x2463d8f0, 
-0x431023, 0x2c422710, 0x144000e0, 0x24020001, 
-0x80047f6, 0x0, 0x3c050001, 0x8ca55d28, 
-0xc005276, 0x2021, 0xc005397, 0x2021, 
-0x3c030001, 0x8c637e94, 0x46100d2, 0x24020001, 
-0x3c020008, 0x621024, 0x10400006, 0x0, 
-0x8f820214, 0x3c03ffff, 0x431024, 0x8004732, 
-0x3442251f, 0x8f820214, 0x3c03ffff, 0x431024, 
-0x3442241f, 0xaf820214, 0x8ee20000, 0x3c030200, 
-0x431025, 0xaee20000, 0x8f820220, 0x2403fffb, 
-0x431024, 0xaf820220, 0x8f820220, 0x34420002, 
-0xaf820220, 0x24020008, 0x3c010001, 0x370821, 
-0xc0043dd, 0xac2283ac, 0x3c010001, 0x80047f8, 
-0xac205db0, 0x3c020001, 0x571021, 0x8c4283ac, 
-0x2443ffff, 0x2c620008, 0x104000ac, 0x31080, 
-0x3c010001, 0x220821, 0x8c225b38, 0x400008, 
-0x0, 0xc00429b, 0x0, 0x3c010001, 
-0xac205d2c, 0xaf800204, 0x3c010001, 0xc0047fc, 
-0xac207e80, 0x24020001, 0x3c010001, 0xac225d44, 
-0x24020002, 0x3c010001, 0x370821, 0x80047f8, 
-0xac2283ac, 0xc004879, 0x0, 0x3c030001, 
-0x8c635d44, 0x24020009, 0x14620090, 0x24020003, 
-0x3c010001, 0x370821, 0x80047f8, 0xac2283ac, 
-0x3c020001, 0x8c427e98, 0x30424000, 0x10400005, 
-0x0, 0x8f820044, 0x3c03ffff, 0x8004778, 
-0x34637fff, 0x8f820044, 0x2403ff7f, 0x431024, 
-0xaf820044, 0x8f830054, 0x8004792, 0x24020004, 
-0x8f830054, 0x3c020001, 0x8c425e00, 0x2463d8f0, 
-0x431023, 0x2c422710, 0x14400074, 0x24020005, 
-0x3c010001, 0x370821, 0x80047f8, 0xac2283ac, 
+0x800481f, 0xac235da4, 0x8f830054, 0x3c020001, 
+0x8c425da4, 0x2463fff6, 0x431023, 0x2c42000a, 
+0x14400059, 0x0, 0x24020007, 0x3c010001, 
+0x370821, 0x800481f, 0xac2283ac, 0x8f820220, 
+0x3c04f700, 0x441025, 0xaf820220, 0x8f820220, 
+0x3c030300, 0x431024, 0x14400005, 0x1821, 
+0x8f820220, 0x24030001, 0x441025, 0xaf820220, 
+0x10600043, 0x24020001, 0x8f820214, 0x3c03ffff, 
+0x3c040001, 0x8c845d98, 0x431024, 0x3442251f, 
+0xaf820214, 0x24020008, 0x3c010001, 0x370821, 
+0x1080000b, 0xac2283ac, 0x3c020001, 0x8c425d74, 
+0x14400007, 0x24020001, 0x3c010001, 0xac227dd0, 
+0xc004e54, 0x8f840220, 0x800480c, 0x0, 
+0x8f820220, 0x3c030008, 0x431024, 0x14400017, 
+0x2402000e, 0x3c010001, 0xac227dd0, 0x8ee20000, 
+0x2021, 0x3c030200, 0x431025, 0xc005386, 
+0xaee20000, 0x8f820220, 0x2403fffb, 0x431024, 
+0xaf820220, 0x8f820220, 0x34420002, 0xc0043dd, 
+0xaf820220, 0x3c050001, 0x8ca55cc8, 0xc0052a2, 
+0x2021, 0x800481f, 0x0, 0x3c020001, 
+0x8c425d74, 0x10400010, 0x0, 0x3c020001, 
+0x8c425d70, 0x2442ffff, 0x3c010001, 0xac225d70, 
+0x14400009, 0x24020002, 0x3c010001, 0xac205d74, 
+0x3c010001, 0x800481f, 0xac225d70, 0x24020001, 
+0x3c010001, 0xac225ccc, 0x8fbf0018, 0x3e00008, 
+0x27bd0020, 0x8f820200, 0x8f820220, 0x8f820220, 
+0x34420004, 0xaf820220, 0x8f820200, 0x3c060001, 
+0x8cc65cc8, 0x34420004, 0xaf820200, 0x24020002, 
+0x10c2003a, 0x2cc20003, 0x10400005, 0x24020001, 
+0x10c20008, 0x0, 0x8004868, 0x0, 
+0x24020004, 0x10c20013, 0x24020001, 0x8004868, 
+0x0, 0x3c030001, 0x8c635cb8, 0x3c020001, 
+0x8c425cc0, 0x3c040001, 0x8c845cdc, 0x3c050001, 
+0x8ca55cbc, 0xaf860200, 0xaf860220, 0x34630022, 
+0x441025, 0x451025, 0x34420002, 0x8004867, 
+0xaf830200, 0x3c030001, 0x8c635d98, 0xaf820200, 
+0x10600009, 0xaf820220, 0x3c020001, 0x8c425d74, 
+0x14400005, 0x3c033f00, 0x3c020001, 0x8c425cb0, 
+0x800485b, 0x346300e0, 0x3c020001, 0x8c425cb0, 
+0x3c033f00, 0x346300e2, 0x431025, 0xaf820200, 
+0x3c030001, 0x8c635cb4, 0x3c04f700, 0x3c020001, 
+0x8c425cc0, 0x3c050001, 0x8ca55cdc, 0x641825, 
+0x431025, 0x451025, 0xaf820220, 0x3e00008, 
+0x0, 0x8f820220, 0x3c030001, 0x8c635cc8, 
+0x34420004, 0xaf820220, 0x24020001, 0x1062000f, 
+0x0, 0x8f830054, 0x8f820054, 0x24630002, 
+0x621023, 0x2c420003, 0x10400011, 0x0, 
+0x8f820054, 0x621023, 0x2c420003, 0x1040000c, 
+0x0, 0x8004879, 0x0, 0x8f830054, 
+0x8f820054, 0x8004885, 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, 0x8c635ce4, 
+0x3c020001, 0x8c425ce8, 0x50620004, 0x2463ffff, 
+0x3c010001, 0xac235ce8, 0x2463ffff, 0x2c620009, 
+0x1040009d, 0x31080, 0x3c010001, 0x220821, 
+0x8c225b08, 0x400008, 0x0, 0x8f820044, 
+0x34428080, 0xaf820044, 0x8f830054, 0x8004938, 
+0x24020002, 0x8f830054, 0x3c020001, 0x8c425da8, 
+0x2463d8f0, 0x431023, 0x2c422710, 0x1440008a, 
+0x24020003, 0x8004945, 0x0, 0x8f820044, 
+0x3c03ffff, 0x34637fff, 0x431024, 0xaf820044, 
+0x8f830054, 0x8004938, 0x24020004, 0x8f830054, 
+0x3c020001, 0x8c425da8, 0x2463fff6, 0x431023, 
+0x2c42000a, 0x14400078, 0x24020005, 0x8004945, 
+0x0, 0x8f820220, 0x3c03f700, 0x431025, 
+0xaf820220, 0x8f820220, 0x2403fffb, 0x431024, 
+0xaf820220, 0x8f820220, 0x34420002, 0xaf820220, 
+0x3c023f00, 0x344200e0, 0xaf820200, 0x8f820200, 
+0x2403fffd, 0x431024, 0xaf820200, 0x24040001, 
+0x3405ffff, 0xaf840204, 0x8f830054, 0x8f820054, 
+0x80048ec, 0x24630001, 0x8f820054, 0x621023, 
+0x2c420002, 0x1440fffc, 0x0, 0x8f820224, 
+0x42040, 0xa4102b, 0x1040fff2, 0x0, 
 0x8f820220, 0x3c03f700, 0x431025, 0xaf820220, 
-0xaf800204, 0x3c010001, 0xac207e80, 0x8f830054, 
-0x24020006, 0x3c010001, 0x370821, 0xac2283ac, 
-0x3c010001, 0x80047f8, 0xac235e00, 0x8f830054, 
-0x3c020001, 0x8c425e00, 0x2463fff6, 0x431023, 
-0x2c42000a, 0x14400059, 0x0, 0x24020007, 
-0x3c010001, 0x370821, 0x80047f8, 0xac2283ac, 
-0x8f820220, 0x3c04f700, 0x441025, 0xaf820220, 
-0x8f820220, 0x3c030300, 0x431024, 0x14400005, 
-0x1821, 0x8f820220, 0x24030001, 0x441025, 
-0xaf820220, 0x10600043, 0x24020001, 0x8f820214, 
-0x3c03ffff, 0x3c040001, 0x8c845df8, 0x431024, 
-0x3442251f, 0xaf820214, 0x24020008, 0x3c010001, 
-0x370821, 0x1080000b, 0xac2283ac, 0x3c020001, 
-0x8c425dd4, 0x14400007, 0x24020001, 0x3c010001, 
-0xac227e30, 0xc004e2c, 0x8f840220, 0x80047e5, 
-0x0, 0x8f820220, 0x3c030008, 0x431024, 
-0x14400017, 0x2402000e, 0x3c010001, 0xac227e30, 
-0x8ee20000, 0x2021, 0x3c030200, 0x431025, 
-0xc005397, 0xaee20000, 0x8f820220, 0x2403fffb, 
-0x431024, 0xaf820220, 0x8f820220, 0x34420002, 
-0xc0043dd, 0xaf820220, 0x3c050001, 0x8ca55d28, 
-0xc005276, 0x2021, 0x80047f8, 0x0, 
-0x3c020001, 0x8c425dd4, 0x10400010, 0x0, 
-0x3c020001, 0x8c425dd0, 0x2442ffff, 0x3c010001, 
-0xac225dd0, 0x14400009, 0x24020002, 0x3c010001, 
-0xac205dd4, 0x3c010001, 0x80047f8, 0xac225dd0, 
-0x24020001, 0x3c010001, 0xac225d2c, 0x8fbf001c, 
-0x8fb00018, 0x3e00008, 0x27bd0020, 0x8f820200, 
-0x8f820220, 0x8f820220, 0x34420004, 0xaf820220, 
-0x8f820200, 0x3c060001, 0x8cc65d28, 0x34420004, 
-0xaf820200, 0x24020002, 0x10c2003a, 0x2cc20003, 
-0x10400005, 0x24020001, 0x10c20008, 0x0, 
-0x8004842, 0x0, 0x24020004, 0x10c20013, 
-0x24020001, 0x8004842, 0x0, 0x3c030001, 
-0x8c635d18, 0x3c020001, 0x8c425d20, 0x3c040001, 
-0x8c845d3c, 0x3c050001, 0x8ca55d1c, 0xaf860200, 
-0xaf860220, 0x34630022, 0x441025, 0x451025, 
-0x34420002, 0x8004841, 0xaf830200, 0x3c030001, 
-0x8c635df8, 0xaf820200, 0x10600009, 0xaf820220, 
-0x3c020001, 0x8c425dd4, 0x14400005, 0x3c033f00, 
-0x3c020001, 0x8c425d10, 0x8004835, 0x346300e0, 
-0x3c020001, 0x8c425d10, 0x3c033f00, 0x346300e2, 
-0x431025, 0xaf820200, 0x3c030001, 0x8c635d14, 
-0x3c04f700, 0x3c020001, 0x8c425d20, 0x3c050001, 
-0x8ca55d3c, 0x641825, 0x431025, 0x451025, 
-0xaf820220, 0x3e00008, 0x0, 0x8f820220, 
-0x3c030001, 0x8c635d28, 0x34420004, 0xaf820220, 
-0x24020001, 0x1062000f, 0x0, 0x8f830054, 
-0x8f820054, 0x24630002, 0x621023, 0x2c420003, 
-0x10400011, 0x0, 0x8f820054, 0x621023, 
-0x2c420003, 0x1040000c, 0x0, 0x8004853, 
-0x0, 0x8f830054, 0x8f820054, 0x800485f, 
-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, 0x8c635d44, 0x3c020001, 0x8c425d48, 
-0x50620004, 0x2463ffff, 0x3c010001, 0xac235d48, 
-0x2463ffff, 0x2c620009, 0x1040009d, 0x31080, 
-0x3c010001, 0x220821, 0x8c225b58, 0x400008, 
-0x0, 0x8f820044, 0x34428080, 0xaf820044, 
-0x8f830054, 0x8004912, 0x24020002, 0x8f830054, 
-0x3c020001, 0x8c425e04, 0x2463d8f0, 0x431023, 
-0x2c422710, 0x1440008a, 0x24020003, 0x800491f, 
-0x0, 0x8f820044, 0x3c03ffff, 0x34637fff, 
-0x431024, 0xaf820044, 0x8f830054, 0x8004912, 
-0x24020004, 0x8f830054, 0x3c020001, 0x8c425e04, 
-0x2463fff6, 0x431023, 0x2c42000a, 0x14400078, 
-0x24020005, 0x800491f, 0x0, 0x8f820220, 
-0x3c03f700, 0x431025, 0xaf820220, 0x8f820220, 
-0x2403fffb, 0x431024, 0xaf820220, 0x8f820220, 
-0x34420002, 0xaf820220, 0x3c023f00, 0x344200e0, 
-0xaf820200, 0x8f820200, 0x2403fffd, 0x431024, 
-0xaf820200, 0x24040001, 0x3405ffff, 0xaf840204, 
-0x8f830054, 0x8f820054, 0x80048c6, 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, 
-0x24425cd0, 0xac820000, 0xac830004, 0xaf8500f0, 
-0x8f830054, 0x8004912, 0x24020006, 0x8f830054, 
-0x3c020001, 0x8c425e04, 0x2463fff6, 0x431023, 
-0x2c42000a, 0x14400022, 0x24020007, 0x800491f, 
-0x0, 0x8f8200e0, 0xaf8200e4, 0x8f8200e0, 
-0xaf8200e8, 0x8f820220, 0x34420004, 0xaf820220, 
-0x8f820220, 0x2403fff7, 0x431024, 0xaf820220, 
-0x8f820044, 0x34428080, 0xaf820044, 0x8f830054, 
-0x24020008, 0x3c010001, 0xac225d44, 0x3c010001, 
-0x8004921, 0xac235e04, 0x8f830054, 0x3c020001, 
-0x8c425e04, 0x2463d8f0, 0x431023, 0x2c422710, 
-0x14400003, 0x24020009, 0x3c010001, 0xac225d44, 
-0x3e00008, 0x0, 0x0, 0x27bdffd8, 
+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, 0x24425c70, 0xac820000, 
+0xac830004, 0xaf8500f0, 0x8f830054, 0x8004938, 
+0x24020006, 0x8f830054, 0x3c020001, 0x8c425da8, 
+0x2463fff6, 0x431023, 0x2c42000a, 0x14400022, 
+0x24020007, 0x8004945, 0x0, 0x8f8200e0, 
+0xaf8200e4, 0x8f8200e0, 0xaf8200e8, 0x8f820220, 
+0x34420004, 0xaf820220, 0x8f820220, 0x2403fff7, 
+0x431024, 0xaf820220, 0x8f820044, 0x34428080, 
+0xaf820044, 0x8f830054, 0x24020008, 0x3c010001, 
+0xac225ce4, 0x3c010001, 0x8004947, 0xac235da8, 
+0x8f830054, 0x3c020001, 0x8c425da8, 0x2463d8f0, 
+0x431023, 0x2c422710, 0x14400003, 0x24020009, 
+0x3c010001, 0xac225ce4, 0x3e00008, 0x0, 
+0x0, 0x0, 0x0, 0x27bdffd8, 
 0xafb20018, 0x809021, 0xafb3001c, 0xa09821, 
 0xafb10014, 0xc08821, 0xafb00010, 0x8021, 
-0xafbf0020, 0xa6200000, 0xc004d23, 0x24040001, 
+0xafbf0020, 0xa6200000, 0xc004d4b, 0x24040001, 
 0x26100001, 0x2e020020, 0x1440fffb, 0x0, 
-0xc004d23, 0x2021, 0xc004d23, 0x24040001, 
-0xc004d23, 0x24040001, 0xc004d23, 0x2021, 
+0xc004d4b, 0x2021, 0xc004d4b, 0x24040001, 
+0xc004d4b, 0x24040001, 0xc004d4b, 0x2021, 
 0x24100010, 0x2501024, 0x10400002, 0x2021, 
-0x24040001, 0xc004d23, 0x108042, 0x1600fffa, 
+0x24040001, 0xc004d4b, 0x108042, 0x1600fffa, 
 0x2501024, 0x24100010, 0x2701024, 0x10400002, 
-0x2021, 0x24040001, 0xc004d23, 0x108042, 
-0x1600fffa, 0x2701024, 0xc004d49, 0x34108000, 
-0xc004d49, 0x0, 0xc004d03, 0x0, 
+0x2021, 0x24040001, 0xc004d4b, 0x108042, 
+0x1600fffa, 0x2701024, 0xc004d71, 0x34108000, 
+0xc004d71, 0x0, 0xc004d2b, 0x0, 
 0x50400005, 0x108042, 0x96220000, 0x501025, 
 0xa6220000, 0x108042, 0x1600fff7, 0x0, 
-0xc004d49, 0x0, 0x8fbf0020, 0x8fb3001c, 
+0xc004d71, 0x0, 0x8fbf0020, 0x8fb3001c, 
 0x8fb20018, 0x8fb10014, 0x8fb00010, 0x3e00008, 
 0x27bd0028, 0x27bdffd8, 0xafb10014, 0x808821, 
 0xafb20018, 0xa09021, 0xafb3001c, 0xc09821, 
-0xafb00010, 0x8021, 0xafbf0020, 0xc004d23, 
+0xafb00010, 0x8021, 0xafbf0020, 0xc004d4b, 
 0x24040001, 0x26100001, 0x2e020020, 0x1440fffb, 
-0x0, 0xc004d23, 0x2021, 0xc004d23, 
-0x24040001, 0xc004d23, 0x2021, 0xc004d23, 
+0x0, 0xc004d4b, 0x2021, 0xc004d4b, 
+0x24040001, 0xc004d4b, 0x2021, 0xc004d4b, 
 0x24040001, 0x24100010, 0x2301024, 0x10400002, 
-0x2021, 0x24040001, 0xc004d23, 0x108042, 
+0x2021, 0x24040001, 0xc004d4b, 0x108042, 
 0x1600fffa, 0x2301024, 0x24100010, 0x2501024, 
-0x10400002, 0x2021, 0x24040001, 0xc004d23, 
-0x108042, 0x1600fffa, 0x2501024, 0xc004d23, 
-0x24040001, 0xc004d23, 0x2021, 0x34108000, 
+0x10400002, 0x2021, 0x24040001, 0xc004d4b, 
+0x108042, 0x1600fffa, 0x2501024, 0xc004d4b, 
+0x24040001, 0xc004d4b, 0x2021, 0x34108000, 
 0x96620000, 0x501024, 0x10400002, 0x2021, 
-0x24040001, 0xc004d23, 0x108042, 0x1600fff8, 
-0x0, 0xc004d49, 0x0, 0x8fbf0020, 
+0x24040001, 0xc004d4b, 0x108042, 0x1600fff8, 
+0x0, 0xc004d71, 0x0, 0x8fbf0020, 
 0x8fb3001c, 0x8fb20018, 0x8fb10014, 0x8fb00010, 
-0x3e00008, 0x27bd0028, 0x3c030001, 0x8c635d60, 
-0x3c020001, 0x8c425da8, 0x27bdffd8, 0xafbf0020, 
+0x3e00008, 0x27bd0028, 0x3c030001, 0x8c635d00, 
+0x3c020001, 0x8c425d48, 0x27bdffd8, 0xafbf0020, 
 0xafb1001c, 0x10620003, 0xafb00018, 0x3c010001, 
-0xac235da8, 0x2463ffff, 0x2c620013, 0x10400349, 
-0x31080, 0x3c010001, 0x220821, 0x8c225b80, 
-0x400008, 0x0, 0xc004d49, 0x8021, 
-0x34028000, 0xa7a20010, 0x27b10010, 0xc004d23, 
+0xac235d48, 0x2463ffff, 0x2c620013, 0x10400349, 
+0x31080, 0x3c010001, 0x220821, 0x8c225b30, 
+0x400008, 0x0, 0xc004d71, 0x8021, 
+0x34028000, 0xa7a20010, 0x27b10010, 0xc004d4b, 
 0x24040001, 0x26100001, 0x2e020020, 0x1440fffb, 
-0x0, 0xc004d23, 0x2021, 0xc004d23, 
-0x24040001, 0xc004d23, 0x2021, 0xc004d23, 
+0x0, 0xc004d4b, 0x2021, 0xc004d4b, 
+0x24040001, 0xc004d4b, 0x2021, 0xc004d4b, 
 0x24040001, 0x24100010, 0x32020001, 0x10400002, 
-0x2021, 0x24040001, 0xc004d23, 0x108042, 
-0x1600fffa, 0x32020001, 0x24100010, 0xc004d23, 
+0x2021, 0x24040001, 0xc004d4b, 0x108042, 
+0x1600fffa, 0x32020001, 0x24100010, 0xc004d4b, 
 0x2021, 0x108042, 0x1600fffc, 0x0, 
-0xc004d23, 0x24040001, 0xc004d23, 0x2021, 
+0xc004d4b, 0x24040001, 0xc004d4b, 0x2021, 
 0x34108000, 0x96220000, 0x501024, 0x10400002, 
-0x2021, 0x24040001, 0xc004d23, 0x108042, 
-0x1600fff8, 0x0, 0xc004d49, 0x0, 
-0x8004cfc, 0x24020002, 0x27b10010, 0xa7a00010, 
-0x8021, 0xc004d23, 0x24040001, 0x26100001, 
-0x2e020020, 0x1440fffb, 0x0, 0xc004d23, 
-0x2021, 0xc004d23, 0x24040001, 0xc004d23, 
-0x24040001, 0xc004d23, 0x2021, 0x24100010, 
+0x2021, 0x24040001, 0xc004d4b, 0x108042, 
+0x1600fff8, 0x0, 0xc004d71, 0x0, 
+0x8004d24, 0x24020002, 0x27b10010, 0xa7a00010, 
+0x8021, 0xc004d4b, 0x24040001, 0x26100001, 
+0x2e020020, 0x1440fffb, 0x0, 0xc004d4b, 
+0x2021, 0xc004d4b, 0x24040001, 0xc004d4b, 
+0x24040001, 0xc004d4b, 0x2021, 0x24100010, 
 0x32020001, 0x10400002, 0x2021, 0x24040001, 
-0xc004d23, 0x108042, 0x1600fffa, 0x32020001, 
-0x24100010, 0xc004d23, 0x2021, 0x108042, 
-0x1600fffc, 0x0, 0xc004d49, 0x34108000, 
-0xc004d49, 0x0, 0xc004d03, 0x0, 
+0xc004d4b, 0x108042, 0x1600fffa, 0x32020001, 
+0x24100010, 0xc004d4b, 0x2021, 0x108042, 
+0x1600fffc, 0x0, 0xc004d71, 0x34108000, 
+0xc004d71, 0x0, 0xc004d2b, 0x0, 
 0x50400005, 0x108042, 0x96220000, 0x501025, 
 0xa6220000, 0x108042, 0x1600fff7, 0x0, 
-0xc004d49, 0x0, 0x97a20010, 0x30428000, 
-0x144002dc, 0x24020003, 0x8004cfc, 0x0, 
+0xc004d71, 0x0, 0x97a20010, 0x30428000, 
+0x144002dc, 0x24020003, 0x8004d24, 0x0, 
 0x24021200, 0xa7a20010, 0x27b10010, 0x8021, 
-0xc004d23, 0x24040001, 0x26100001, 0x2e020020, 
-0x1440fffb, 0x0, 0xc004d23, 0x2021, 
-0xc004d23, 0x24040001, 0xc004d23, 0x2021, 
-0xc004d23, 0x24040001, 0x24100010, 0x32020001, 
-0x10400002, 0x2021, 0x24040001, 0xc004d23, 
+0xc004d4b, 0x24040001, 0x26100001, 0x2e020020, 
+0x1440fffb, 0x0, 0xc004d4b, 0x2021, 
+0xc004d4b, 0x24040001, 0xc004d4b, 0x2021, 
+0xc004d4b, 0x24040001, 0x24100010, 0x32020001, 
+0x10400002, 0x2021, 0x24040001, 0xc004d4b, 
 0x108042, 0x1600fffa, 0x32020001, 0x24100010, 
-0xc004d23, 0x2021, 0x108042, 0x1600fffc, 
-0x0, 0xc004d23, 0x24040001, 0xc004d23, 
+0xc004d4b, 0x2021, 0x108042, 0x1600fffc, 
+0x0, 0xc004d4b, 0x24040001, 0xc004d4b, 
 0x2021, 0x34108000, 0x96220000, 0x501024, 
-0x10400002, 0x2021, 0x24040001, 0xc004d23, 
-0x108042, 0x1600fff8, 0x0, 0xc004d49, 
-0x0, 0x8f830054, 0x8004cee, 0x24020004, 
-0x8f830054, 0x3c020001, 0x8c425e14, 0x2463ff9c, 
+0x10400002, 0x2021, 0x24040001, 0xc004d4b, 
+0x108042, 0x1600fff8, 0x0, 0xc004d71, 
+0x0, 0x8f830054, 0x8004d16, 0x24020004, 
+0x8f830054, 0x3c020001, 0x8c425db8, 0x2463ff9c, 
 0x431023, 0x2c420064, 0x1440029e, 0x24020002, 
-0x3c030001, 0x8c635e18, 0x10620297, 0x2c620003, 
+0x3c030001, 0x8c635dbc, 0x10620297, 0x2c620003, 
 0x14400296, 0x24020011, 0x24020003, 0x10620005, 
-0x24020004, 0x10620291, 0x2402000f, 0x8004cfc, 
-0x24020011, 0x8004cfc, 0x24020005, 0x24020014, 
-0xa7a20010, 0x27b10010, 0x8021, 0xc004d23, 
+0x24020004, 0x10620291, 0x2402000f, 0x8004d24, 
+0x24020011, 0x8004d24, 0x24020005, 0x24020014, 
+0xa7a20010, 0x27b10010, 0x8021, 0xc004d4b, 
 0x24040001, 0x26100001, 0x2e020020, 0x1440fffb, 
-0x0, 0xc004d23, 0x2021, 0xc004d23, 
-0x24040001, 0xc004d23, 0x2021, 0xc004d23, 
+0x0, 0xc004d4b, 0x2021, 0xc004d4b, 
+0x24040001, 0xc004d4b, 0x2021, 0xc004d4b, 
 0x24040001, 0x24100010, 0x32020001, 0x10400002, 
-0x2021, 0x24040001, 0xc004d23, 0x108042, 
+0x2021, 0x24040001, 0xc004d4b, 0x108042, 
 0x1600fffa, 0x32020001, 0x24100010, 0x32020012, 
-0x10400002, 0x2021, 0x24040001, 0xc004d23, 
-0x108042, 0x1600fffa, 0x32020012, 0xc004d23, 
-0x24040001, 0xc004d23, 0x2021, 0x34108000, 
+0x10400002, 0x2021, 0x24040001, 0xc004d4b, 
+0x108042, 0x1600fffa, 0x32020012, 0xc004d4b, 
+0x24040001, 0xc004d4b, 0x2021, 0x34108000, 
 0x96220000, 0x501024, 0x10400002, 0x2021, 
-0x24040001, 0xc004d23, 0x108042, 0x1600fff8, 
-0x0, 0xc004d49, 0x0, 0x8f830054, 
-0x8004cee, 0x24020006, 0x8f830054, 0x3c020001, 
-0x8c425e14, 0x2463ff9c, 0x431023, 0x2c420064, 
-0x14400250, 0x24020007, 0x8004cfc, 0x0, 
+0x24040001, 0xc004d4b, 0x108042, 0x1600fff8, 
+0x0, 0xc004d71, 0x0, 0x8f830054, 
+0x8004d16, 0x24020006, 0x8f830054, 0x3c020001, 
+0x8c425db8, 0x2463ff9c, 0x431023, 0x2c420064, 
+0x14400250, 0x24020007, 0x8004d24, 0x0, 
 0x24020006, 0xa7a20010, 0x27b10010, 0x8021, 
-0xc004d23, 0x24040001, 0x26100001, 0x2e020020, 
-0x1440fffb, 0x0, 0xc004d23, 0x2021, 
-0xc004d23, 0x24040001, 0xc004d23, 0x2021, 
-0xc004d23, 0x24040001, 0x24100010, 0x32020001, 
-0x10400002, 0x2021, 0x24040001, 0xc004d23, 
+0xc004d4b, 0x24040001, 0x26100001, 0x2e020020, 
+0x1440fffb, 0x0, 0xc004d4b, 0x2021, 
+0xc004d4b, 0x24040001, 0xc004d4b, 0x2021, 
+0xc004d4b, 0x24040001, 0x24100010, 0x32020001, 
+0x10400002, 0x2021, 0x24040001, 0xc004d4b, 
 0x108042, 0x1600fffa, 0x32020001, 0x24100010, 
 0x32020013, 0x10400002, 0x2021, 0x24040001, 
-0xc004d23, 0x108042, 0x1600fffa, 0x32020013, 
-0xc004d23, 0x24040001, 0xc004d23, 0x2021, 
+0xc004d4b, 0x108042, 0x1600fffa, 0x32020013, 
+0xc004d4b, 0x24040001, 0xc004d4b, 0x2021, 
 0x34108000, 0x96220000, 0x501024, 0x10400002, 
-0x2021, 0x24040001, 0xc004d23, 0x108042, 
-0x1600fff8, 0x0, 0xc004d49, 0x0, 
-0x8f830054, 0x8004cee, 0x24020008, 0x8f830054, 
-0x3c020001, 0x8c425e14, 0x2463ff9c, 0x431023, 
-0x2c420064, 0x1440020f, 0x24020009, 0x8004cfc, 
+0x2021, 0x24040001, 0xc004d4b, 0x108042, 
+0x1600fff8, 0x0, 0xc004d71, 0x0, 
+0x8f830054, 0x8004d16, 0x24020008, 0x8f830054, 
+0x3c020001, 0x8c425db8, 0x2463ff9c, 0x431023, 
+0x2c420064, 0x1440020f, 0x24020009, 0x8004d24, 
 0x0, 0x27b10010, 0xa7a00010, 0x8021, 
-0xc004d23, 0x24040001, 0x26100001, 0x2e020020, 
-0x1440fffb, 0x0, 0xc004d23, 0x2021, 
-0xc004d23, 0x24040001, 0xc004d23, 0x24040001, 
-0xc004d23, 0x2021, 0x24100010, 0x32020001, 
-0x10400002, 0x2021, 0x24040001, 0xc004d23, 
+0xc004d4b, 0x24040001, 0x26100001, 0x2e020020, 
+0x1440fffb, 0x0, 0xc004d4b, 0x2021, 
+0xc004d4b, 0x24040001, 0xc004d4b, 0x24040001, 
+0xc004d4b, 0x2021, 0x24100010, 0x32020001, 
+0x10400002, 0x2021, 0x24040001, 0xc004d4b, 
 0x108042, 0x1600fffa, 0x32020001, 0x24100010, 
 0x32020018, 0x10400002, 0x2021, 0x24040001, 
-0xc004d23, 0x108042, 0x1600fffa, 0x32020018, 
-0xc004d49, 0x34108000, 0xc004d49, 0x0, 
-0xc004d03, 0x0, 0x50400005, 0x108042, 
+0xc004d4b, 0x108042, 0x1600fffa, 0x32020018, 
+0xc004d71, 0x34108000, 0xc004d71, 0x0, 
+0xc004d2b, 0x0, 0x50400005, 0x108042, 
 0x96220000, 0x501025, 0xa6220000, 0x108042, 
-0x1600fff7, 0x0, 0xc004d49, 0x8021, 
+0x1600fff7, 0x0, 0xc004d71, 0x8021, 
 0x97a20010, 0x27b10010, 0x34420001, 0xa7a20010, 
-0xc004d23, 0x24040001, 0x26100001, 0x2e020020, 
-0x1440fffb, 0x0, 0xc004d23, 0x2021, 
-0xc004d23, 0x24040001, 0xc004d23, 0x2021, 
-0xc004d23, 0x24040001, 0x24100010, 0x32020001, 
-0x10400002, 0x2021, 0x24040001, 0xc004d23, 
+0xc004d4b, 0x24040001, 0x26100001, 0x2e020020, 
+0x1440fffb, 0x0, 0xc004d4b, 0x2021, 
+0xc004d4b, 0x24040001, 0xc004d4b, 0x2021, 
+0xc004d4b, 0x24040001, 0x24100010, 0x32020001, 
+0x10400002, 0x2021, 0x24040001, 0xc004d4b, 
 0x108042, 0x1600fffa, 0x32020001, 0x24100010, 
 0x32020018, 0x10400002, 0x2021, 0x24040001, 
-0xc004d23, 0x108042, 0x1600fffa, 0x32020018, 
-0xc004d23, 0x24040001, 0xc004d23, 0x2021, 
+0xc004d4b, 0x108042, 0x1600fffa, 0x32020018, 
+0xc004d4b, 0x24040001, 0xc004d4b, 0x2021, 
 0x34108000, 0x96220000, 0x501024, 0x10400002, 
-0x2021, 0x24040001, 0xc004d23, 0x108042, 
-0x1600fff8, 0x0, 0xc004d49, 0x0, 
-0x8f830054, 0x8004cee, 0x2402000a, 0x8f830054, 
-0x3c020001, 0x8c425e14, 0x2463ff9c, 0x431023, 
-0x2c420064, 0x1440019b, 0x2402000b, 0x8004cfc, 
+0x2021, 0x24040001, 0xc004d4b, 0x108042, 
+0x1600fff8, 0x0, 0xc004d71, 0x0, 
+0x8f830054, 0x8004d16, 0x2402000a, 0x8f830054, 
+0x3c020001, 0x8c425db8, 0x2463ff9c, 0x431023, 
+0x2c420064, 0x1440019b, 0x2402000b, 0x8004d24, 
 0x0, 0x27b10010, 0xa7a00010, 0x8021, 
-0xc004d23, 0x24040001, 0x26100001, 0x2e020020, 
-0x1440fffb, 0x0, 0xc004d23, 0x2021, 
-0xc004d23, 0x24040001, 0xc004d23, 0x24040001, 
-0xc004d23, 0x2021, 0x24100010, 0x32020001, 
-0x10400002, 0x2021, 0x24040001, 0xc004d23, 
+0xc004d4b, 0x24040001, 0x26100001, 0x2e020020, 
+0x1440fffb, 0x0, 0xc004d4b, 0x2021, 
+0xc004d4b, 0x24040001, 0xc004d4b, 0x24040001, 
+0xc004d4b, 0x2021, 0x24100010, 0x32020001, 
+0x10400002, 0x2021, 0x24040001, 0xc004d4b, 
 0x108042, 0x1600fffa, 0x32020001, 0x24100010, 
 0x32020017, 0x10400002, 0x2021, 0x24040001, 
-0xc004d23, 0x108042, 0x1600fffa, 0x32020017, 
-0xc004d49, 0x34108000, 0xc004d49, 0x0, 
-0xc004d03, 0x0, 0x50400005, 0x108042, 
+0xc004d4b, 0x108042, 0x1600fffa, 0x32020017, 
+0xc004d71, 0x34108000, 0xc004d71, 0x0, 
+0xc004d2b, 0x0, 0x50400005, 0x108042, 
 0x96220000, 0x501025, 0xa6220000, 0x108042, 
-0x1600fff7, 0x0, 0xc004d49, 0x8021, 
+0x1600fff7, 0x0, 0xc004d71, 0x8021, 
 0x97a20010, 0x27b10010, 0x34420700, 0xa7a20010, 
-0xc004d23, 0x24040001, 0x26100001, 0x2e020020, 
-0x1440fffb, 0x0, 0xc004d23, 0x2021, 
-0xc004d23, 0x24040001, 0xc004d23, 0x2021, 
-0xc004d23, 0x24040001, 0x24100010, 0x32020001, 
-0x10400002, 0x2021, 0x24040001, 0xc004d23, 
+0xc004d4b, 0x24040001, 0x26100001, 0x2e020020, 
+0x1440fffb, 0x0, 0xc004d4b, 0x2021, 
+0xc004d4b, 0x24040001, 0xc004d4b, 0x2021, 
+0xc004d4b, 0x24040001, 0x24100010, 0x32020001, 
+0x10400002, 0x2021, 0x24040001, 0xc004d4b, 
 0x108042, 0x1600fffa, 0x32020001, 0x24100010, 
 0x32020017, 0x10400002, 0x2021, 0x24040001, 
-0xc004d23, 0x108042, 0x1600fffa, 0x32020017, 
-0xc004d23, 0x24040001, 0xc004d23, 0x2021, 
+0xc004d4b, 0x108042, 0x1600fffa, 0x32020017, 
+0xc004d4b, 0x24040001, 0xc004d4b, 0x2021, 
 0x34108000, 0x96220000, 0x501024, 0x10400002, 
-0x2021, 0x24040001, 0xc004d23, 0x108042, 
-0x1600fff8, 0x0, 0xc004d49, 0x0, 
-0x8f830054, 0x8004cee, 0x2402000c, 0x8f830054, 
-0x3c020001, 0x8c425e14, 0x2463ff9c, 0x431023, 
-0x2c420064, 0x14400127, 0x24020012, 0x8004cfc, 
+0x2021, 0x24040001, 0xc004d4b, 0x108042, 
+0x1600fff8, 0x0, 0xc004d71, 0x0, 
+0x8f830054, 0x8004d16, 0x2402000c, 0x8f830054, 
+0x3c020001, 0x8c425db8, 0x2463ff9c, 0x431023, 
+0x2c420064, 0x14400127, 0x24020012, 0x8004d24, 
 0x0, 0x27b10010, 0xa7a00010, 0x8021, 
-0xc004d23, 0x24040001, 0x26100001, 0x2e020020, 
-0x1440fffb, 0x0, 0xc004d23, 0x2021, 
-0xc004d23, 0x24040001, 0xc004d23, 0x24040001, 
-0xc004d23, 0x2021, 0x24100010, 0x32020001, 
-0x10400002, 0x2021, 0x24040001, 0xc004d23, 
+0xc004d4b, 0x24040001, 0x26100001, 0x2e020020, 
+0x1440fffb, 0x0, 0xc004d4b, 0x2021, 
+0xc004d4b, 0x24040001, 0xc004d4b, 0x24040001, 
+0xc004d4b, 0x2021, 0x24100010, 0x32020001, 
+0x10400002, 0x2021, 0x24040001, 0xc004d4b, 
 0x108042, 0x1600fffa, 0x32020001, 0x24100010, 
 0x32020014, 0x10400002, 0x2021, 0x24040001, 
-0xc004d23, 0x108042, 0x1600fffa, 0x32020014, 
-0xc004d49, 0x34108000, 0xc004d49, 0x0, 
-0xc004d03, 0x0, 0x50400005, 0x108042, 
+0xc004d4b, 0x108042, 0x1600fffa, 0x32020014, 
+0xc004d71, 0x34108000, 0xc004d71, 0x0, 
+0xc004d2b, 0x0, 0x50400005, 0x108042, 
 0x96220000, 0x501025, 0xa6220000, 0x108042, 
-0x1600fff7, 0x0, 0xc004d49, 0x8021, 
+0x1600fff7, 0x0, 0xc004d71, 0x8021, 
 0x97a20010, 0x27b10010, 0x34420010, 0xa7a20010, 
-0xc004d23, 0x24040001, 0x26100001, 0x2e020020, 
-0x1440fffb, 0x0, 0xc004d23, 0x2021, 
-0xc004d23, 0x24040001, 0xc004d23, 0x2021, 
-0xc004d23, 0x24040001, 0x24100010, 0x32020001, 
-0x10400002, 0x2021, 0x24040001, 0xc004d23, 
+0xc004d4b, 0x24040001, 0x26100001, 0x2e020020, 
+0x1440fffb, 0x0, 0xc004d4b, 0x2021, 
+0xc004d4b, 0x24040001, 0xc004d4b, 0x2021, 
+0xc004d4b, 0x24040001, 0x24100010, 0x32020001, 
+0x10400002, 0x2021, 0x24040001, 0xc004d4b, 
 0x108042, 0x1600fffa, 0x32020001, 0x24100010, 
 0x32020014, 0x10400002, 0x2021, 0x24040001, 
-0xc004d23, 0x108042, 0x1600fffa, 0x32020014, 
-0xc004d23, 0x24040001, 0xc004d23, 0x2021, 
+0xc004d4b, 0x108042, 0x1600fffa, 0x32020014, 
+0xc004d4b, 0x24040001, 0xc004d4b, 0x2021, 
 0x34108000, 0x96220000, 0x501024, 0x10400002, 
-0x2021, 0x24040001, 0xc004d23, 0x108042, 
-0x1600fff8, 0x0, 0xc004d49, 0x0, 
-0x8f830054, 0x8004cee, 0x24020013, 0x8f830054, 
-0x3c020001, 0x8c425e14, 0x2463ff9c, 0x431023, 
-0x2c420064, 0x144000b3, 0x2402000d, 0x8004cfc, 
+0x2021, 0x24040001, 0xc004d4b, 0x108042, 
+0x1600fff8, 0x0, 0xc004d71, 0x0, 
+0x8f830054, 0x8004d16, 0x24020013, 0x8f830054, 
+0x3c020001, 0x8c425db8, 0x2463ff9c, 0x431023, 
+0x2c420064, 0x144000b3, 0x2402000d, 0x8004d24, 
 0x0, 0x27b10010, 0xa7a00010, 0x8021, 
-0xc004d23, 0x24040001, 0x26100001, 0x2e020020, 
-0x1440fffb, 0x0, 0xc004d23, 0x2021, 
-0xc004d23, 0x24040001, 0xc004d23, 0x24040001, 
-0xc004d23, 0x2021, 0x24100010, 0x32020001, 
-0x10400002, 0x2021, 0x24040001, 0xc004d23, 
+0xc004d4b, 0x24040001, 0x26100001, 0x2e020020, 
+0x1440fffb, 0x0, 0xc004d4b, 0x2021, 
+0xc004d4b, 0x24040001, 0xc004d4b, 0x24040001, 
+0xc004d4b, 0x2021, 0x24100010, 0x32020001, 
+0x10400002, 0x2021, 0x24040001, 0xc004d4b, 
 0x108042, 0x1600fffa, 0x32020001, 0x24100010, 
 0x32020018, 0x10400002, 0x2021, 0x24040001, 
-0xc004d23, 0x108042, 0x1600fffa, 0x32020018, 
-0xc004d49, 0x34108000, 0xc004d49, 0x0, 
-0xc004d03, 0x0, 0x50400005, 0x108042, 
+0xc004d4b, 0x108042, 0x1600fffa, 0x32020018, 
+0xc004d71, 0x34108000, 0xc004d71, 0x0, 
+0xc004d2b, 0x0, 0x50400005, 0x108042, 
 0x96220000, 0x501025, 0xa6220000, 0x108042, 
-0x1600fff7, 0x0, 0xc004d49, 0x8021, 
+0x1600fff7, 0x0, 0xc004d71, 0x8021, 
 0x97a20010, 0x27b10010, 0x3042fffe, 0xa7a20010, 
-0xc004d23, 0x24040001, 0x26100001, 0x2e020020, 
-0x1440fffb, 0x0, 0xc004d23, 0x2021, 
-0xc004d23, 0x24040001, 0xc004d23, 0x2021, 
-0xc004d23, 0x24040001, 0x24100010, 0x32020001, 
-0x10400002, 0x2021, 0x24040001, 0xc004d23, 
+0xc004d4b, 0x24040001, 0x26100001, 0x2e020020, 
+0x1440fffb, 0x0, 0xc004d4b, 0x2021, 
+0xc004d4b, 0x24040001, 0xc004d4b, 0x2021, 
+0xc004d4b, 0x24040001, 0x24100010, 0x32020001, 
+0x10400002, 0x2021, 0x24040001, 0xc004d4b, 
 0x108042, 0x1600fffa, 0x32020001, 0x24100010, 
 0x32020018, 0x10400002, 0x2021, 0x24040001, 
-0xc004d23, 0x108042, 0x1600fffa, 0x32020018, 
-0xc004d23, 0x24040001, 0xc004d23, 0x2021, 
+0xc004d4b, 0x108042, 0x1600fffa, 0x32020018, 
+0xc004d4b, 0x24040001, 0xc004d4b, 0x2021, 
 0x34108000, 0x96220000, 0x501024, 0x10400002, 
-0x2021, 0x24040001, 0xc004d23, 0x108042, 
-0x1600fff8, 0x0, 0xc004d49, 0x0, 
-0x8f830054, 0x8004cee, 0x2402000e, 0x24020840, 
-0xa7a20010, 0x27b10010, 0x8021, 0xc004d23, 
+0x2021, 0x24040001, 0xc004d4b, 0x108042, 
+0x1600fff8, 0x0, 0xc004d71, 0x0, 
+0x8f830054, 0x8004d16, 0x2402000e, 0x24020840, 
+0xa7a20010, 0x27b10010, 0x8021, 0xc004d4b, 
 0x24040001, 0x26100001, 0x2e020020, 0x1440fffb, 
-0x0, 0xc004d23, 0x2021, 0xc004d23, 
-0x24040001, 0xc004d23, 0x2021, 0xc004d23, 
+0x0, 0xc004d4b, 0x2021, 0xc004d4b, 
+0x24040001, 0xc004d4b, 0x2021, 0xc004d4b, 
 0x24040001, 0x24100010, 0x32020001, 0x10400002, 
-0x2021, 0x24040001, 0xc004d23, 0x108042, 
+0x2021, 0x24040001, 0xc004d4b, 0x108042, 
 0x1600fffa, 0x32020001, 0x24100010, 0x32020013, 
-0x10400002, 0x2021, 0x24040001, 0xc004d23, 
-0x108042, 0x1600fffa, 0x32020013, 0xc004d23, 
-0x24040001, 0xc004d23, 0x2021, 0x34108000, 
+0x10400002, 0x2021, 0x24040001, 0xc004d4b, 
+0x108042, 0x1600fffa, 0x32020013, 0xc004d4b, 
+0x24040001, 0xc004d4b, 0x2021, 0x34108000, 
 0x96220000, 0x501024, 0x10400002, 0x2021, 
-0x24040001, 0xc004d23, 0x108042, 0x1600fff8, 
-0x0, 0xc004d49, 0x0, 0x8f830054, 
-0x24020010, 0x3c010001, 0xac225d60, 0x3c010001, 
-0x8004cfe, 0xac235e14, 0x8f830054, 0x3c020001, 
-0x8c425e14, 0x2463ff9c, 0x431023, 0x2c420064, 
+0x24040001, 0xc004d4b, 0x108042, 0x1600fff8, 
+0x0, 0xc004d71, 0x0, 0x8f830054, 
+0x24020010, 0x3c010001, 0xac225d00, 0x3c010001, 
+0x8004d26, 0xac235db8, 0x8f830054, 0x3c020001, 
+0x8c425db8, 0x2463ff9c, 0x431023, 0x2c420064, 
 0x14400004, 0x0, 0x24020011, 0x3c010001, 
-0xac225d60, 0x8fbf0020, 0x8fb1001c, 0x8fb00018, 
+0xac225d00, 0x8fbf0020, 0x8fb1001c, 0x8fb00018, 
 0x3e00008, 0x27bd0028, 0x8f850044, 0x8f820044, 
 0x3c030001, 0x431025, 0x3c030008, 0xaf820044, 
-0x8f840054, 0x8f820054, 0xa32824, 0x8004d0f, 
+0x8f840054, 0x8f820054, 0xa32824, 0x8004d37, 
 0x24840001, 0x8f820054, 0x821023, 0x2c420002, 
 0x1440fffc, 0x0, 0x8f820044, 0x3c03fffe, 
 0x3463ffff, 0x431024, 0xaf820044, 0x8f830054, 
-0x8f820054, 0x8004d1d, 0x24630001, 0x8f820054, 
+0x8f820054, 0x8004d45, 0x24630001, 0x8f820054, 
 0x621023, 0x2c420002, 0x1440fffc, 0x0, 
 0x3e00008, 0xa01021, 0x8f830044, 0x3c02fff0, 
 0x3442ffff, 0x42480, 0x621824, 0x3c020002, 
 0x822025, 0x641825, 0xaf830044, 0x8f820044, 
 0x3c03fffe, 0x3463ffff, 0x431024, 0xaf820044, 
-0x8f830054, 0x8f820054, 0x8004d36, 0x24630001, 
+0x8f830054, 0x8f820054, 0x8004d5e, 0x24630001, 
 0x8f820054, 0x621023, 0x2c420002, 0x1440fffc, 
 0x0, 0x8f820044, 0x3c030001, 0x431025, 
-0xaf820044, 0x8f830054, 0x8f820054, 0x8004d43, 
+0xaf820044, 0x8f830054, 0x8f820054, 0x8004d6b, 
 0x24630001, 0x8f820054, 0x621023, 0x2c420002, 
 0x1440fffc, 0x0, 0x3e00008, 0x0, 
 0x8f820044, 0x3c03fff0, 0x3463ffff, 0x431024, 
 0xaf820044, 0x8f820044, 0x3c030001, 0x431025, 
-0xaf820044, 0x8f830054, 0x8f820054, 0x8004d57, 
+0xaf820044, 0x8f830054, 0x8f820054, 0x8004d7f, 
 0x24630001, 0x8f820054, 0x621023, 0x2c420002, 
 0x1440fffc, 0x0, 0x8f820044, 0x3c03fffe, 
 0x3463ffff, 0x431024, 0xaf820044, 0x8f830054, 
-0x8f820054, 0x8004d65, 0x24630001, 0x8f820054, 
+0x8f820054, 0x8004d8d, 0x24630001, 0x8f820054, 
 0x621023, 0x2c420002, 0x1440fffc, 0x0, 
 0x3e00008, 0x0, 0x27bdffc8, 0xafb30024, 
 0x809821, 0xafb5002c, 0xa0a821, 0xafb20020, 
 0xc09021, 0x32a2ffff, 0xafbf0030, 0xafb40028, 
 0xafb1001c, 0xafb00018, 0x14400034, 0xa7b20010, 
-0x3271ffff, 0x27b20010, 0x8021, 0xc004d23, 
+0x3271ffff, 0x27b20010, 0x8021, 0xc004d4b, 
 0x24040001, 0x26100001, 0x2e020020, 0x1440fffb, 
-0x0, 0xc004d23, 0x2021, 0xc004d23, 
-0x24040001, 0xc004d23, 0x2021, 0xc004d23, 
+0x0, 0xc004d4b, 0x2021, 0xc004d4b, 
+0x24040001, 0xc004d4b, 0x2021, 0xc004d4b, 
 0x24040001, 0x24100010, 0x32020001, 0x10400002, 
-0x2021, 0x24040001, 0xc004d23, 0x108042, 
+0x2021, 0x24040001, 0xc004d4b, 0x108042, 
 0x1600fffa, 0x32020001, 0x24100010, 0x2301024, 
-0x10400002, 0x2021, 0x24040001, 0xc004d23, 
-0x108042, 0x1600fffa, 0x2301024, 0xc004d23, 
-0x24040001, 0xc004d23, 0x2021, 0x34108000, 
+0x10400002, 0x2021, 0x24040001, 0xc004d4b, 
+0x108042, 0x1600fffa, 0x2301024, 0xc004d4b, 
+0x24040001, 0xc004d4b, 0x2021, 0x34108000, 
 0x96420000, 0x501024, 0x10400002, 0x2021, 
-0x24040001, 0xc004d23, 0x108042, 0x12000075, 
-0x0, 0x8004da1, 0x0, 0x3274ffff, 
-0x27b10010, 0xa7a00010, 0x8021, 0xc004d23, 
+0x24040001, 0xc004d4b, 0x108042, 0x12000075, 
+0x0, 0x8004dc9, 0x0, 0x3274ffff, 
+0x27b10010, 0xa7a00010, 0x8021, 0xc004d4b, 
 0x24040001, 0x26100001, 0x2e020020, 0x1440fffb, 
-0x0, 0xc004d23, 0x2021, 0xc004d23, 
-0x24040001, 0xc004d23, 0x24040001, 0xc004d23, 
+0x0, 0xc004d4b, 0x2021, 0xc004d4b, 
+0x24040001, 0xc004d4b, 0x24040001, 0xc004d4b, 
 0x2021, 0x24100010, 0x32020001, 0x10400002, 
-0x2021, 0x24040001, 0xc004d23, 0x108042, 
+0x2021, 0x24040001, 0xc004d4b, 0x108042, 
 0x1600fffa, 0x32020001, 0x24100010, 0x2901024, 
-0x10400002, 0x2021, 0x24040001, 0xc004d23, 
-0x108042, 0x1600fffa, 0x2901024, 0xc004d49, 
-0x34108000, 0xc004d49, 0x0, 0xc004d03, 
+0x10400002, 0x2021, 0x24040001, 0xc004d4b, 
+0x108042, 0x1600fffa, 0x2901024, 0xc004d71, 
+0x34108000, 0xc004d71, 0x0, 0xc004d2b, 
 0x0, 0x50400005, 0x108042, 0x96220000, 
 0x501025, 0xa6220000, 0x108042, 0x1600fff7, 
-0x0, 0xc004d49, 0x0, 0x32a5ffff, 
+0x0, 0xc004d71, 0x0, 0x32a5ffff, 
 0x24020001, 0x54a20004, 0x24020002, 0x97a20010, 
-0x8004dec, 0x521025, 0x14a20006, 0x3271ffff, 
+0x8004e14, 0x521025, 0x14a20006, 0x3271ffff, 
 0x97a20010, 0x121827, 0x431024, 0xa7a20010, 
-0x3271ffff, 0x27b20010, 0x8021, 0xc004d23, 
+0x3271ffff, 0x27b20010, 0x8021, 0xc004d4b, 
 0x24040001, 0x26100001, 0x2e020020, 0x1440fffb, 
-0x0, 0xc004d23, 0x2021, 0xc004d23, 
-0x24040001, 0xc004d23, 0x2021, 0xc004d23, 
+0x0, 0xc004d4b, 0x2021, 0xc004d4b, 
+0x24040001, 0xc004d4b, 0x2021, 0xc004d4b, 
 0x24040001, 0x24100010, 0x32020001, 0x10400002, 
-0x2021, 0x24040001, 0xc004d23, 0x108042, 
+0x2021, 0x24040001, 0xc004d4b, 0x108042, 
 0x1600fffa, 0x32020001, 0x24100010, 0x2301024, 
-0x10400002, 0x2021, 0x24040001, 0xc004d23, 
-0x108042, 0x1600fffa, 0x2301024, 0xc004d23, 
-0x24040001, 0xc004d23, 0x2021, 0x34108000, 
+0x10400002, 0x2021, 0x24040001, 0xc004d4b, 
+0x108042, 0x1600fffa, 0x2301024, 0xc004d4b, 
+0x24040001, 0xc004d4b, 0x2021, 0x34108000, 
 0x96420000, 0x501024, 0x10400002, 0x2021, 
-0x24040001, 0xc004d23, 0x108042, 0x1600fff8, 
-0x0, 0xc004d49, 0x0, 0x8fbf0030, 
+0x24040001, 0xc004d4b, 0x108042, 0x1600fff8, 
+0x0, 0xc004d71, 0x0, 0x8fbf0030, 
 0x8fb5002c, 0x8fb40028, 0x8fb30024, 0x8fb20020, 
 0x8fb1001c, 0x8fb00018, 0x3e00008, 0x27bd0038, 
 0x0, 0x0, 0x0, 0x27bdffe8, 
 0xafbf0010, 0x3c030001, 0x771821, 0x8c6383ac, 
 0x24020008, 0x1462022c, 0x803021, 0x3c020001, 
-0x8c425df8, 0x14400033, 0x0, 0x8f850224, 
+0x8c425d98, 0x14400033, 0x0, 0x8f850224, 
 0x38a30020, 0x2c630001, 0x38a20010, 0x2c420001, 
 0x621825, 0x1460000d, 0x38a30030, 0x2c630001, 
 0x38a20400, 0x2c420001, 0x621825, 0x14600007, 
 0x38a30402, 0x2c630001, 0x38a20404, 0x2c420001, 
 0x621825, 0x10600005, 0x0, 0xc00429b, 
-0x0, 0x8004e65, 0x2402000e, 0xc0043dd, 
-0x0, 0x3c050001, 0x8ca55d28, 0xc005276, 
-0x2021, 0x3c030001, 0x8c635d28, 0x24020004, 
-0x14620005, 0x2403fffb, 0x3c020001, 0x8c425d24, 
-0x8004e61, 0x2403fff7, 0x3c020001, 0x8c425d24, 
-0x431024, 0x3c010001, 0xac225d24, 0x2402000e, 
-0x3c010001, 0xc00429b, 0xac227e30, 0x800505f, 
+0x0, 0x8004e8d, 0x2402000e, 0xc0043dd, 
+0x0, 0x3c050001, 0x8ca55cc8, 0xc0052a2, 
+0x2021, 0x3c030001, 0x8c635cc8, 0x24020004, 
+0x14620005, 0x2403fffb, 0x3c020001, 0x8c425cc4, 
+0x8004e89, 0x2403fff7, 0x3c020001, 0x8c425cc4, 
+0x431024, 0x3c010001, 0xac225cc4, 0x2402000e, 
+0x3c010001, 0xc00429b, 0xac227dd0, 0x8005087, 
 0x0, 0x8f820220, 0x3c030400, 0x431024, 
 0x10400027, 0x2403ffbf, 0x8f850224, 0x3c020001, 
-0x8c427e3c, 0xa32024, 0x431024, 0x1482000c, 
-0x0, 0x3c020001, 0x8c427e40, 0x24420001, 
-0x3c010001, 0xac227e40, 0x2c420002, 0x14400008, 
-0x24020001, 0x3c010001, 0x8004e85, 0xac227e60, 
-0x3c010001, 0xac207e40, 0x3c010001, 0xac207e60, 
-0x3c020001, 0x8c427e60, 0x10400006, 0x30a20040, 
-0x10400004, 0x24020001, 0x3c010001, 0x8004e90, 
-0xac227e64, 0x3c010001, 0xac207e64, 0x3c010001, 
-0xac257e3c, 0x3c010001, 0x8004ea0, 0xac207e70, 
-0x24020001, 0x3c010001, 0xac227e70, 0x3c010001, 
-0xac207e60, 0x3c010001, 0xac207e40, 0x3c010001, 
-0xac207e64, 0x3c010001, 0xac207e3c, 0x3c030001, 
-0x8c637e30, 0x3c020001, 0x8c427e34, 0x10620003, 
-0x3c020200, 0x3c010001, 0xac237e34, 0xc21024, 
+0x8c427ddc, 0xa32024, 0x431024, 0x1482000c, 
+0x0, 0x3c020001, 0x8c427de0, 0x24420001, 
+0x3c010001, 0xac227de0, 0x2c420002, 0x14400008, 
+0x24020001, 0x3c010001, 0x8004ead, 0xac227e00, 
+0x3c010001, 0xac207de0, 0x3c010001, 0xac207e00, 
+0x3c020001, 0x8c427e00, 0x10400006, 0x30a20040, 
+0x10400004, 0x24020001, 0x3c010001, 0x8004eb8, 
+0xac227e04, 0x3c010001, 0xac207e04, 0x3c010001, 
+0xac257ddc, 0x3c010001, 0x8004ec8, 0xac207e10, 
+0x24020001, 0x3c010001, 0xac227e10, 0x3c010001, 
+0xac207e00, 0x3c010001, 0xac207de0, 0x3c010001, 
+0xac207e04, 0x3c010001, 0xac207ddc, 0x3c030001, 
+0x8c637dd0, 0x3c020001, 0x8c427dd4, 0x10620003, 
+0x3c020200, 0x3c010001, 0xac237dd4, 0xc21024, 
 0x10400007, 0x2463ffff, 0x8f820220, 0x24030001, 
-0x3c010001, 0xac235d2c, 0x800505d, 0x3c03f700, 
+0x3c010001, 0xac235ccc, 0x8005085, 0x3c03f700, 
 0x2c62000e, 0x104001a8, 0x31080, 0x3c010001, 
-0x220821, 0x8c225bd0, 0x400008, 0x0, 
-0x3c010001, 0xac207e60, 0x3c010001, 0xac207e40, 
-0x3c010001, 0xac207e3c, 0x3c010001, 0xac207e64, 
-0x3c010001, 0xac207e58, 0x3c010001, 0xac207e50, 
-0xc004844, 0xaf800224, 0x24020002, 0x3c010001, 
-0xac227e30, 0x3c020001, 0x8c427e70, 0x14400056, 
+0x220821, 0x8c225b80, 0x400008, 0x0, 
+0x3c010001, 0xac207e00, 0x3c010001, 0xac207de0, 
+0x3c010001, 0xac207ddc, 0x3c010001, 0xac207e04, 
+0x3c010001, 0xac207df8, 0x3c010001, 0xac207df0, 
+0xc00486a, 0xaf800224, 0x24020002, 0x3c010001, 
+0xac227dd0, 0x3c020001, 0x8c427e10, 0x14400056, 
 0x3c03fdff, 0x8ee20000, 0x3463ffff, 0x431024, 
 0xc00429b, 0xaee20000, 0xaf800204, 0x8f820200, 
 0x2403fffd, 0x431024, 0xaf820200, 0x3c010001, 
-0xac207e80, 0x8f830054, 0x3c020001, 0x8c427e58, 
-0x24040001, 0x3c010001, 0xac247e6c, 0x24420001, 
-0x3c010001, 0xac227e58, 0x2c420004, 0x3c010001, 
-0xac237e54, 0x14400006, 0x24020003, 0x3c010001, 
-0xac245d2c, 0x3c010001, 0x800505b, 0xac207e58, 
-0x3c010001, 0x800505b, 0xac227e30, 0x8f830054, 
-0x3c020001, 0x8c427e54, 0x2463d8f0, 0x431023, 
+0xac207e20, 0x8f830054, 0x3c020001, 0x8c427df8, 
+0x24040001, 0x3c010001, 0xac247e0c, 0x24420001, 
+0x3c010001, 0xac227df8, 0x2c420004, 0x3c010001, 
+0xac237df4, 0x14400006, 0x24020003, 0x3c010001, 
+0xac245ccc, 0x3c010001, 0x8005083, 0xac207df8, 
+0x3c010001, 0x8005083, 0xac227dd0, 0x8f830054, 
+0x3c020001, 0x8c427df4, 0x2463d8f0, 0x431023, 
 0x2c422710, 0x14400003, 0x24020004, 0x3c010001, 
-0xac227e30, 0x3c020001, 0x8c427e70, 0x14400026, 
+0xac227dd0, 0x3c020001, 0x8c427e10, 0x14400026, 
 0x3c03fdff, 0x8ee20000, 0x3463ffff, 0x431024, 
-0x800505b, 0xaee20000, 0x3c040001, 0x8c845dfc, 
-0x3c010001, 0xc005062, 0xac207e48, 0x3c020001, 
-0x8c427e7c, 0xaf820204, 0x3c020001, 0x8c427e70, 
+0x8005083, 0xaee20000, 0x3c040001, 0x8c845d9c, 
+0x3c010001, 0xc00508a, 0xac207de8, 0x3c020001, 
+0x8c427e1c, 0xaf820204, 0x3c020001, 0x8c427e10, 
 0x14400015, 0x3c03fdff, 0x8ee20000, 0x3463ffff, 
 0x431024, 0xaee20000, 0x8f820204, 0x30420030, 
-0x1440013c, 0x24020002, 0x3c030001, 0x8c637e7c, 
-0x24020005, 0x3c010001, 0xac227e30, 0x3c010001, 
-0x800505b, 0xac237e80, 0x3c020001, 0x8c427e70, 
-0x10400010, 0x3c03fdff, 0x3c020001, 0x8c425dcc, 
-0x24420001, 0x3c010001, 0xac225dcc, 0x2c420002, 
-0x14400131, 0x24020001, 0x3c010001, 0xac225dd4, 
-0x3c010001, 0xac205dcc, 0x3c010001, 0x800505b, 
-0xac225d2c, 0x8ee20000, 0x3463ffff, 0x431024, 
-0xaee20000, 0x3c020001, 0x8c427e60, 0x10400122, 
-0x0, 0x3c020001, 0x8c427e3c, 0x1040011e, 
-0x0, 0x3c010001, 0xac227e68, 0x24020003, 
-0x3c010001, 0xac227e40, 0x8004ffc, 0x24020006, 
-0x3c010001, 0xac207e48, 0x8f820204, 0x34420040, 
-0xaf820204, 0x3c020001, 0x8c427e80, 0x24030007, 
-0x3c010001, 0xac237e30, 0x34420040, 0x3c010001, 
-0xac227e80, 0x3c020001, 0x8c427e60, 0x10400005, 
-0x0, 0x3c020001, 0x8c427e3c, 0x104000f9, 
-0x24020002, 0x3c050001, 0x24a57e40, 0x8ca20000, 
+0x1440013c, 0x24020002, 0x3c030001, 0x8c637e1c, 
+0x24020005, 0x3c010001, 0xac227dd0, 0x3c010001, 
+0x8005083, 0xac237e20, 0x3c020001, 0x8c427e10, 
+0x10400010, 0x3c03fdff, 0x3c020001, 0x8c425d6c, 
+0x24420001, 0x3c010001, 0xac225d6c, 0x2c420002, 
+0x14400131, 0x24020001, 0x3c010001, 0xac225d74, 
+0x3c010001, 0xac205d6c, 0x3c010001, 0x8005083, 
+0xac225ccc, 0x8ee20000, 0x3463ffff, 0x431024, 
+0xaee20000, 0x3c020001, 0x8c427e00, 0x10400122, 
+0x0, 0x3c020001, 0x8c427ddc, 0x1040011e, 
+0x0, 0x3c010001, 0xac227e08, 0x24020003, 
+0x3c010001, 0xac227de0, 0x8005024, 0x24020006, 
+0x3c010001, 0xac207de8, 0x8f820204, 0x34420040, 
+0xaf820204, 0x3c020001, 0x8c427e20, 0x24030007, 
+0x3c010001, 0xac237dd0, 0x34420040, 0x3c010001, 
+0xac227e20, 0x3c020001, 0x8c427e00, 0x10400005, 
+0x0, 0x3c020001, 0x8c427ddc, 0x104000f9, 
+0x24020002, 0x3c050001, 0x24a57de0, 0x8ca20000, 
 0x2c424e21, 0x104000f3, 0x24020002, 0x3c020001, 
-0x8c427e64, 0x104000f8, 0x2404ffbf, 0x3c020001, 
-0x8c427e3c, 0x3c030001, 0x8c637e68, 0x441024, 
+0x8c427e04, 0x104000f8, 0x2404ffbf, 0x3c020001, 
+0x8c427ddc, 0x3c030001, 0x8c637e08, 0x441024, 
 0x641824, 0x10430004, 0x24020001, 0x3c010001, 
-0x800505b, 0xac227e30, 0x24020003, 0xaca20000, 
-0x24020008, 0x3c010001, 0xac227e30, 0x3c020001, 
-0x8c427e6c, 0x1040000c, 0x24020001, 0x3c040001, 
-0xc00506f, 0x8c847e3c, 0x3c020001, 0x8c427e88, 
-0x14400005, 0x24020001, 0x3c020001, 0x8c427e84, 
-0x10400006, 0x24020001, 0x3c010001, 0xac225d2c, 
-0x3c010001, 0x800505b, 0xac207e58, 0x3c020001, 
-0x8c427e50, 0x3c030001, 0x8c637e3c, 0x2c420001, 
-0x210c0, 0x30630008, 0x3c010001, 0xac227e50, 
-0x3c010001, 0xac237e4c, 0x8f830054, 0x24020009, 
-0x3c010001, 0xac227e30, 0x3c010001, 0x800505b, 
-0xac237e54, 0x8f830054, 0x3c020001, 0x8c427e54, 
+0x8005083, 0xac227dd0, 0x24020003, 0xaca20000, 
+0x24020008, 0x3c010001, 0xac227dd0, 0x3c020001, 
+0x8c427e0c, 0x1040000c, 0x24020001, 0x3c040001, 
+0xc005097, 0x8c847ddc, 0x3c020001, 0x8c427e28, 
+0x14400005, 0x24020001, 0x3c020001, 0x8c427e24, 
+0x10400006, 0x24020001, 0x3c010001, 0xac225ccc, 
+0x3c010001, 0x8005083, 0xac207df8, 0x3c020001, 
+0x8c427df0, 0x3c030001, 0x8c637ddc, 0x2c420001, 
+0x210c0, 0x30630008, 0x3c010001, 0xac227df0, 
+0x3c010001, 0xac237dec, 0x8f830054, 0x24020009, 
+0x3c010001, 0xac227dd0, 0x3c010001, 0x8005083, 
+0xac237df4, 0x8f830054, 0x3c020001, 0x8c427df4, 
 0x2463d8f0, 0x431023, 0x2c422710, 0x144000a8, 
-0x0, 0x3c020001, 0x8c427e60, 0x10400005, 
-0x0, 0x3c020001, 0x8c427e3c, 0x104000a9, 
-0x24020002, 0x3c030001, 0x24637e40, 0x8c620000, 
+0x0, 0x3c020001, 0x8c427e00, 0x10400005, 
+0x0, 0x3c020001, 0x8c427ddc, 0x104000a9, 
+0x24020002, 0x3c030001, 0x24637de0, 0x8c620000, 
 0x2c424e21, 0x104000a3, 0x24020002, 0x3c020001, 
-0x8c427e6c, 0x1040000e, 0x0, 0x3c020001, 
-0x8c427e3c, 0x3c010001, 0xac207e6c, 0x30420080, 
+0x8c427e0c, 0x1040000e, 0x0, 0x3c020001, 
+0x8c427ddc, 0x3c010001, 0xac207e0c, 0x30420080, 
 0x1040002f, 0x2402000c, 0x8f820204, 0x30420080, 
-0x1440000c, 0x24020003, 0x8004fe9, 0x2402000c, 
-0x3c020001, 0x8c427e3c, 0x30420080, 0x14400005, 
+0x1440000c, 0x24020003, 0x8005011, 0x2402000c, 
+0x3c020001, 0x8c427ddc, 0x30420080, 0x14400005, 
 0x24020003, 0x8f820204, 0x30420080, 0x1040001f, 
 0x24020003, 0xac620000, 0x2402000a, 0x3c010001, 
-0xac227e30, 0x3c040001, 0x24847e78, 0x8c820000, 
-0x3c030001, 0x8c637e50, 0x431025, 0xaf820204, 
-0x8c830000, 0x3c040001, 0x8c847e50, 0x2402000b, 
-0x3c010001, 0xac227e30, 0x641825, 0x3c010001, 
-0xac237e80, 0x3c050001, 0x24a57e40, 0x8ca20000, 
+0xac227dd0, 0x3c040001, 0x24847e18, 0x8c820000, 
+0x3c030001, 0x8c637df0, 0x431025, 0xaf820204, 
+0x8c830000, 0x3c040001, 0x8c847df0, 0x2402000b, 
+0x3c010001, 0xac227dd0, 0x641825, 0x3c010001, 
+0xac237e20, 0x3c050001, 0x24a57de0, 0x8ca20000, 
 0x2c424e21, 0x1040006f, 0x24020002, 0x3c020001, 
-0x8c427e70, 0x10400005, 0x0, 0x2402000c, 
-0x3c010001, 0x800505b, 0xac227e30, 0x3c020001, 
-0x8c427e60, 0x1040006c, 0x0, 0x3c040001, 
-0x8c847e3c, 0x1080005e, 0x30820008, 0x3c030001, 
-0x8c637e4c, 0x10620064, 0x24020003, 0x3c010001, 
-0xac247e68, 0xaca20000, 0x24020006, 0x3c010001, 
-0x800505b, 0xac227e30, 0x8f820200, 0x34420002, 
+0x8c427e10, 0x10400005, 0x0, 0x2402000c, 
+0x3c010001, 0x8005083, 0xac227dd0, 0x3c020001, 
+0x8c427e00, 0x1040006c, 0x0, 0x3c040001, 
+0x8c847ddc, 0x1080005e, 0x30820008, 0x3c030001, 
+0x8c637dec, 0x10620064, 0x24020003, 0x3c010001, 
+0xac247e08, 0xaca20000, 0x24020006, 0x3c010001, 
+0x8005083, 0xac227dd0, 0x8f820200, 0x34420002, 
 0xaf820200, 0x8f830054, 0x2402000d, 0x3c010001, 
-0xac227e30, 0x3c010001, 0xac237e54, 0x8f830054, 
-0x3c020001, 0x8c427e54, 0x2463d8f0, 0x431023, 
+0xac227dd0, 0x3c010001, 0xac237df4, 0x8f830054, 
+0x3c020001, 0x8c427df4, 0x2463d8f0, 0x431023, 
 0x2c422710, 0x1440003a, 0x0, 0x3c020001, 
-0x8c427e70, 0x10400029, 0x2402000e, 0x3c030001, 
-0x8c637e84, 0x3c010001, 0x14600015, 0xac227e30, 
-0xc0043dd, 0x0, 0x3c050001, 0x8ca55d28, 
-0xc005276, 0x2021, 0x3c030001, 0x8c635d28, 
+0x8c427e10, 0x10400029, 0x2402000e, 0x3c030001, 
+0x8c637e24, 0x3c010001, 0x14600015, 0xac227dd0, 
+0xc0043dd, 0x0, 0x3c050001, 0x8ca55cc8, 
+0xc0052a2, 0x2021, 0x3c030001, 0x8c635cc8, 
 0x24020004, 0x14620005, 0x2403fffb, 0x3c020001, 
-0x8c425d24, 0x800502a, 0x2403fff7, 0x3c020001, 
-0x8c425d24, 0x431024, 0x3c010001, 0xac225d24, 
+0x8c425cc4, 0x8005052, 0x2403fff7, 0x3c020001, 
+0x8c425cc4, 0x431024, 0x3c010001, 0xac225cc4, 
 0x8ee20000, 0x3c030200, 0x431025, 0xaee20000, 
-0x8f820224, 0x3c010001, 0xac227e8c, 0x8f820220, 
+0x8f820224, 0x3c010001, 0xac227e2c, 0x8f820220, 
 0x2403fffb, 0x431024, 0xaf820220, 0x8f820220, 
-0x34420002, 0x800505b, 0xaf820220, 0x3c020001, 
-0x8c427e60, 0x10400005, 0x0, 0x3c020001, 
-0x8c427e3c, 0x1040000f, 0x24020002, 0x3c020001, 
-0x8c427e40, 0x2c424e21, 0x1040000a, 0x24020002, 
-0x3c020001, 0x8c427e60, 0x1040000f, 0x0, 
-0x3c020001, 0x8c427e3c, 0x1440000b, 0x0, 
-0x24020002, 0x3c010001, 0x800505b, 0xac227e30, 
-0x3c020001, 0x8c427e60, 0x10400003, 0x0, 
+0x34420002, 0x8005083, 0xaf820220, 0x3c020001, 
+0x8c427e00, 0x10400005, 0x0, 0x3c020001, 
+0x8c427ddc, 0x1040000f, 0x24020002, 0x3c020001, 
+0x8c427de0, 0x2c424e21, 0x1040000a, 0x24020002, 
+0x3c020001, 0x8c427e00, 0x1040000f, 0x0, 
+0x3c020001, 0x8c427ddc, 0x1440000b, 0x0, 
+0x24020002, 0x3c010001, 0x8005083, 0xac227dd0, 
+0x3c020001, 0x8c427e00, 0x10400003, 0x0, 
 0xc00429b, 0x0, 0x8f820220, 0x3c03f700, 
 0x431025, 0xaf820220, 0x8fbf0010, 0x3e00008, 
-0x27bd0018, 0x3c030001, 0x24637e88, 0x8c620000, 
-0x10400005, 0x34422000, 0x3c010001, 0xac227e7c, 
-0x800506d, 0xac600000, 0x3c010001, 0xac247e7c, 
+0x27bd0018, 0x3c030001, 0x24637e28, 0x8c620000, 
+0x10400005, 0x34422000, 0x3c010001, 0xac227e1c, 
+0x8005095, 0xac600000, 0x3c010001, 0xac247e1c, 
 0x3e00008, 0x0, 0x27bdffe0, 0x30820030, 
-0xafbf0018, 0x3c010001, 0xac227e84, 0x14400067, 
+0xafbf0018, 0x3c010001, 0xac227e24, 0x14400067, 
 0x3c02ffff, 0x34421f0e, 0x821024, 0x14400061, 
 0x24020030, 0x30822000, 0x1040005d, 0x30838000, 
 0x31a02, 0x30820001, 0x21200, 0x3c040001, 
-0x8c845dfc, 0x621825, 0x331c2, 0x3c030001, 
-0x24635dd8, 0x30828000, 0x21202, 0x30840001, 
+0x8c845d9c, 0x621825, 0x331c2, 0x3c030001, 
+0x24635d78, 0x30828000, 0x21202, 0x30840001, 
 0x42200, 0x441025, 0x239c2, 0x61080, 
 0x431021, 0x471021, 0x90430000, 0x24020001, 
 0x10620025, 0x0, 0x10600007, 0x24020002, 
 0x10620013, 0x24020003, 0x1062002c, 0x3c05000f, 
-0x80050d1, 0x0, 0x8f820200, 0x2403feff, 
+0x80050f9, 0x0, 0x8f820200, 0x2403feff, 
 0x431024, 0xaf820200, 0x8f820220, 0x3c03fffe, 
 0x3463ffff, 0x431024, 0xaf820220, 0x3c010001, 
-0xac207ea4, 0x3c010001, 0x80050dc, 0xac207eac, 
+0xac207e44, 0x3c010001, 0x8005104, 0xac207e4c, 
 0x8f820200, 0x34420100, 0xaf820200, 0x8f820220, 
 0x3c03fffe, 0x3463ffff, 0x431024, 0xaf820220, 
-0x24020100, 0x3c010001, 0xac227ea4, 0x3c010001, 
-0x80050dc, 0xac207eac, 0x8f820200, 0x2403feff, 
+0x24020100, 0x3c010001, 0xac227e44, 0x3c010001, 
+0x8005104, 0xac207e4c, 0x8f820200, 0x2403feff, 
 0x431024, 0xaf820200, 0x8f820220, 0x3c030001, 
-0x431025, 0xaf820220, 0x3c010001, 0xac207ea4, 
-0x3c010001, 0x80050dc, 0xac237eac, 0x8f820200, 
+0x431025, 0xaf820220, 0x3c010001, 0xac207e44, 
+0x3c010001, 0x8005104, 0xac237e4c, 0x8f820200, 
 0x34420100, 0xaf820200, 0x8f820220, 0x3c030001, 
 0x431025, 0xaf820220, 0x24020100, 0x3c010001, 
-0xac227ea4, 0x3c010001, 0x80050dc, 0xac237eac, 
-0x34a5ffff, 0x3c040001, 0x24845c08, 0xafa30010, 
-0xc002403, 0xafa00014, 0x80050dc, 0x0, 
-0x24020030, 0x3c010001, 0xac227e88, 0x8fbf0018, 
+0xac227e44, 0x3c010001, 0x8005104, 0xac237e4c, 
+0x34a5ffff, 0x3c040001, 0x24845bb8, 0xafa30010, 
+0xc002403, 0xafa00014, 0x8005104, 0x0, 
+0x24020030, 0x3c010001, 0xac227e28, 0x8fbf0018, 
 0x3e00008, 0x27bd0020, 0x0, 0x27bdffc8, 
 0xafb20028, 0x809021, 0xafb3002c, 0xa09821, 
-0xafb00020, 0xc08021, 0x3c040001, 0x24845c20, 
-0x3c050009, 0x3c020001, 0x8c425d28, 0x34a59001, 
+0xafb00020, 0xc08021, 0x3c040001, 0x24845bd0, 
+0x3c050009, 0x3c020001, 0x8c425cc8, 0x34a59001, 
 0x2403021, 0x2603821, 0xafbf0030, 0xafb10024, 
 0xa7a0001a, 0xafb00014, 0xc002403, 0xafa20010, 
-0x24020002, 0x1262007f, 0x2e620003, 0x10400005, 
-0x24020001, 0x1262000a, 0x0, 0x800526f, 
-0x0, 0x24020004, 0x126200f6, 0x24020008, 
-0x126200f5, 0x3c02ffec, 0x800526f, 0x0, 
-0x3c020001, 0x8c425d24, 0x30420002, 0x14400004, 
+0x24020002, 0x12620083, 0x2e620003, 0x10400005, 
+0x24020001, 0x1262000a, 0x0, 0x800529b, 
+0x0, 0x24020004, 0x126200fa, 0x24020008, 
+0x126200f9, 0x3c02ffec, 0x800529b, 0x0, 
+0x3c020001, 0x8c425cc4, 0x30420002, 0x14400004, 
 0x128940, 0x3c02fffb, 0x3442ffff, 0x2028024, 
-0x3c010001, 0x310821, 0xac307e9c, 0x3c024000, 
-0x2021024, 0x1040004a, 0x1023c2, 0x30840030, 
-0x101382, 0x3042001c, 0x3c030001, 0x24635d68, 
+0x3c010001, 0x310821, 0xac307e3c, 0x3c024000, 
+0x2021024, 0x1040004e, 0x1023c2, 0x30840030, 
+0x101382, 0x3042001c, 0x3c030001, 0x24635d08, 
 0x431021, 0x823821, 0x3c020020, 0x2021024, 
 0x10400006, 0x24020100, 0x3c010001, 0x310821, 
-0xac227ea0, 0x8005128, 0x3c020080, 0x3c010001, 
-0x310821, 0xac207ea0, 0x3c020080, 0x2021024, 
+0xac227e40, 0x8005150, 0x3c020080, 0x3c010001, 
+0x310821, 0xac207e40, 0x3c020080, 0x2021024, 
 0x10400006, 0x121940, 0x3c020001, 0x3c010001, 
-0x230821, 0x8005134, 0xac227ea8, 0x121140, 
-0x3c010001, 0x220821, 0xac207ea8, 0x94e30000, 
-0x32024000, 0x10400003, 0xa7a30018, 0x34624000, 
+0x230821, 0x800515c, 0xac227e48, 0x121140, 
+0x3c010001, 0x220821, 0xac207e48, 0x94e40000, 
+0x3c030001, 0x8c635dbc, 0x24020005, 0x10620010, 
+0xa7a40018, 0x32024000, 0x10400002, 0x34824000, 
 0xa7a20018, 0x24040001, 0x94e20002, 0x24050004, 
-0x24e60002, 0x34420001, 0xc004966, 0xa4e20002, 
-0x24040001, 0x2821, 0xc004966, 0x27a60018, 
-0x3c020001, 0x8c425d28, 0x24110001, 0x3c010001, 
-0xac315d34, 0x14530004, 0x32028000, 0xc00429b, 
+0x24e60002, 0x34420001, 0xc00498e, 0xa4e20002, 
+0x24040001, 0x2821, 0xc00498e, 0x27a60018, 
+0x3c020001, 0x8c425cc8, 0x24110001, 0x3c010001, 
+0xac315cd4, 0x14530004, 0x32028000, 0xc00429b, 
 0x0, 0x32028000, 0x1040011f, 0x0, 
-0xc00429b, 0x0, 0x3c030001, 0x8c635e18, 
+0xc00429b, 0x0, 0x3c030001, 0x8c635dbc, 
 0x24020005, 0x10620118, 0x24020002, 0x3c010001, 
-0xac315d2c, 0x3c010001, 0x800526f, 0xac225d28, 
-0x24040001, 0x24050004, 0x27b0001a, 0xc004966, 
-0x2003021, 0x24040001, 0x2821, 0xc004966, 
-0x2003021, 0x3c020001, 0x511021, 0x8c427e94, 
-0x3c040001, 0x8c845d28, 0x3c03bfff, 0x3463ffff, 
-0x3c010001, 0xac335d34, 0x431024, 0x3c010001, 
-0x310821, 0x109300fa, 0xac227e94, 0x800526f, 
+0xac315ccc, 0x3c010001, 0x800529b, 0xac225cc8, 
+0x24040001, 0x24050004, 0x27b0001a, 0xc00498e, 
+0x2003021, 0x24040001, 0x2821, 0xc00498e, 
+0x2003021, 0x3c020001, 0x511021, 0x8c427e34, 
+0x3c040001, 0x8c845cc8, 0x3c03bfff, 0x3463ffff, 
+0x3c010001, 0xac335cd4, 0x431024, 0x3c010001, 
+0x310821, 0x109300fa, 0xac227e34, 0x800529b, 
 0x0, 0x3c022000, 0x2021024, 0x10400005, 
-0x24020001, 0x3c010001, 0xac225df8, 0x8005181, 
-0x128940, 0x3c010001, 0xac205df8, 0x128940, 
-0x3c010001, 0x310821, 0xac307e98, 0x3c024000, 
+0x24020001, 0x3c010001, 0xac225d98, 0x80051ad, 
+0x128940, 0x3c010001, 0xac205d98, 0x128940, 
+0x3c010001, 0x310821, 0xac307e38, 0x3c024000, 
 0x2021024, 0x14400016, 0x0, 0x3c020001, 
-0x8c425df8, 0x10400008, 0x24040004, 0x24050001, 
-0xc004d6b, 0x24062000, 0x24020001, 0x3c010001, 
+0x8c425d98, 0x10400008, 0x24040004, 0x24050001, 
+0xc004d93, 0x24062000, 0x24020001, 0x3c010001, 
 0x370821, 0xac2283ac, 0x3c020001, 0x511021, 
-0x8c427e90, 0x3c03bfff, 0x3463ffff, 0x431024, 
-0x3c010001, 0x310821, 0x800526d, 0xac227e90, 
-0x3c020001, 0x8c425df8, 0x10400028, 0x3c0300a0, 
+0x8c427e30, 0x3c03bfff, 0x3463ffff, 0x431024, 
+0x3c010001, 0x310821, 0x8005299, 0xac227e30, 
+0x3c020001, 0x8c425d98, 0x10400028, 0x3c0300a0, 
 0x2031024, 0x5443000d, 0x3c020020, 0x3c020001, 
-0x8c425dfc, 0x24030100, 0x3c010001, 0x310821, 
-0xac237ea4, 0x3c030001, 0x3c010001, 0x310821, 
-0xac237eac, 0x80051c4, 0x34420400, 0x2021024, 
-0x10400008, 0x24030100, 0x3c020001, 0x8c425dfc, 
-0x3c010001, 0x310821, 0xac237ea4, 0x80051c4, 
+0x8c425d9c, 0x24030100, 0x3c010001, 0x310821, 
+0xac237e44, 0x3c030001, 0x3c010001, 0x310821, 
+0xac237e4c, 0x80051f0, 0x34420400, 0x2021024, 
+0x10400008, 0x24030100, 0x3c020001, 0x8c425d9c, 
+0x3c010001, 0x310821, 0xac237e44, 0x80051f0, 
 0x34420800, 0x3c020080, 0x2021024, 0x1040002e, 
-0x3c030001, 0x3c020001, 0x8c425dfc, 0x3c010001, 
-0x310821, 0xac237eac, 0x34420c00, 0x3c010001, 
-0xac225dfc, 0x80051ec, 0x24040001, 0x3c020020, 
+0x3c030001, 0x3c020001, 0x8c425d9c, 0x3c010001, 
+0x310821, 0xac237e4c, 0x34420c00, 0x3c010001, 
+0xac225d9c, 0x8005218, 0x24040001, 0x3c020020, 
 0x2021024, 0x10400006, 0x24020100, 0x3c010001, 
-0x310821, 0xac227ea4, 0x80051d5, 0x3c020080, 
-0x3c010001, 0x310821, 0xac207ea4, 0x3c020080, 
+0x310821, 0xac227e44, 0x8005201, 0x3c020080, 
+0x3c010001, 0x310821, 0xac207e44, 0x3c020080, 
 0x2021024, 0x10400007, 0x121940, 0x3c020001, 
-0x3c010001, 0x230821, 0xac227eac, 0x80051e3, 
+0x3c010001, 0x230821, 0xac227e4c, 0x800520f, 
 0x24040001, 0x121140, 0x3c010001, 0x220821, 
-0xac207eac, 0x24040001, 0x2821, 0x27b0001e, 
-0xc004924, 0x2003021, 0x24040001, 0x2821, 
-0xc004924, 0x2003021, 0x24040001, 0x24050001, 
-0x27b0001c, 0xc004924, 0x2003021, 0x24040001, 
-0x24050001, 0xc004924, 0x2003021, 0x800526d, 
+0xac207e4c, 0x24040001, 0x2821, 0x27b0001e, 
+0xc00494c, 0x2003021, 0x24040001, 0x2821, 
+0xc00494c, 0x2003021, 0x24040001, 0x24050001, 
+0x27b0001c, 0xc00494c, 0x2003021, 0x24040001, 
+0x24050001, 0xc00494c, 0x2003021, 0x8005299, 
 0x0, 0x3c02ffec, 0x3442ffff, 0x2028024, 
 0x3c020008, 0x2028025, 0x121140, 0x3c010001, 
-0x220821, 0xac307e98, 0x3c022000, 0x2021024, 
-0x10400009, 0x0, 0x3c020001, 0x8c425dd4, 
-0x14400005, 0x24020001, 0x3c010001, 0xac225df8, 
-0x800520e, 0x3c024000, 0x3c010001, 0xac205df8, 
+0x220821, 0xac307e38, 0x3c022000, 0x2021024, 
+0x10400009, 0x0, 0x3c020001, 0x8c425d74, 
+0x14400005, 0x24020001, 0x3c010001, 0xac225d98, 
+0x800523a, 0x3c024000, 0x3c010001, 0xac205d98, 
 0x3c024000, 0x2021024, 0x1440001e, 0x0, 
-0x3c020001, 0x8c425df8, 0x3c010001, 0xac205d40, 
-0x10400007, 0x24022020, 0x3c010001, 0xac225dfc, 
+0x3c020001, 0x8c425d98, 0x3c010001, 0xac205ce0, 
+0x10400007, 0x24022020, 0x3c010001, 0xac225d9c, 
 0x24020001, 0x3c010001, 0x370821, 0xac2283ac, 
 0x3c04bfff, 0x121940, 0x3c020001, 0x431021, 
-0x8c427e90, 0x3c050001, 0x8ca55d28, 0x3484ffff, 
-0x441024, 0x3c010001, 0x230821, 0xac227e90, 
-0x24020001, 0x10a20044, 0x0, 0x800526d, 
-0x0, 0x3c020001, 0x8c425df8, 0x1040001c, 
-0x24022000, 0x3c010001, 0xac225dfc, 0x3c0300a0, 
+0x8c427e30, 0x3c050001, 0x8ca55cc8, 0x3484ffff, 
+0x441024, 0x3c010001, 0x230821, 0xac227e30, 
+0x24020001, 0x10a20044, 0x0, 0x8005299, 
+0x0, 0x3c020001, 0x8c425d98, 0x1040001c, 
+0x24022000, 0x3c010001, 0xac225d9c, 0x3c0300a0, 
 0x2031024, 0x14430005, 0x121140, 0x3402a000, 
-0x3c010001, 0x8005268, 0xac225dfc, 0x3c030001, 
-0x621821, 0x8c637e98, 0x3c020020, 0x621024, 
-0x10400004, 0x24022001, 0x3c010001, 0x8005268, 
-0xac225dfc, 0x3c020080, 0x621024, 0x1040001f, 
-0x3402a001, 0x3c010001, 0x8005268, 0xac225dfc, 
+0x3c010001, 0x8005294, 0xac225d9c, 0x3c030001, 
+0x621821, 0x8c637e38, 0x3c020020, 0x621024, 
+0x10400004, 0x24022001, 0x3c010001, 0x8005294, 
+0xac225d9c, 0x3c020080, 0x621024, 0x1040001f, 
+0x3402a001, 0x3c010001, 0x8005294, 0xac225d9c, 
 0x3c020020, 0x2021024, 0x10400007, 0x121940, 
-0x24020100, 0x3c010001, 0x230821, 0xac227ea4, 
-0x800525c, 0x3c020080, 0x121140, 0x3c010001, 
-0x220821, 0xac207ea4, 0x3c020080, 0x2021024, 
+0x24020100, 0x3c010001, 0x230821, 0xac227e44, 
+0x8005288, 0x3c020080, 0x121140, 0x3c010001, 
+0x220821, 0xac207e44, 0x3c020080, 0x2021024, 
 0x10400006, 0x121940, 0x3c020001, 0x3c010001, 
-0x230821, 0x8005268, 0xac227eac, 0x121140, 
-0x3c010001, 0x220821, 0xac207eac, 0x3c030001, 
-0x8c635d28, 0x24020001, 0x10620003, 0x0, 
+0x230821, 0x8005294, 0xac227e4c, 0x121140, 
+0x3c010001, 0x220821, 0xac207e4c, 0x3c030001, 
+0x8c635cc8, 0x24020001, 0x10620003, 0x0, 
 0xc00429b, 0x0, 0x8fbf0030, 0x8fb3002c, 
 0x8fb20028, 0x8fb10024, 0x8fb00020, 0x3e00008, 
-0x27bd0038, 0x27bdffc0, 0xafb40038, 0x80a021, 
-0xafb20030, 0x9021, 0xafb1002c, 0x8821, 
-0x24020002, 0xafbf003c, 0xafb30034, 0xafb00028, 
-0xa7a00020, 0xa7a00018, 0xa7a0001a, 0xa7a0001c, 
-0x10a20108, 0xa7a0001e, 0x2ca20003, 0x10400005, 
-0x24020001, 0x10a2000a, 0x149940, 0x800538f, 
-0x2201021, 0x24020004, 0x10a200b2, 0x24020008, 
-0x10a200b1, 0x142940, 0x800538f, 0x2201021, 
-0x3c030001, 0x731821, 0x8c637e9c, 0x3c024000, 
-0x621024, 0x14400009, 0x24040001, 0x3c027fff, 
-0x3442ffff, 0x628824, 0x3c010001, 0x330821, 
-0xac317e94, 0x800538f, 0x2201021, 0x2821, 
-0xc004924, 0x27a60018, 0x24040001, 0x2821, 
-0xc004924, 0x27a60018, 0x24040001, 0x24050001, 
-0x27b0001a, 0xc004924, 0x2003021, 0x24040001, 
-0x24050001, 0xc004924, 0x2003021, 0x24040001, 
-0x24050004, 0x27b0001c, 0xc004924, 0x2003021, 
-0x24040001, 0x24050004, 0xc004924, 0x2003021, 
-0x24040001, 0x24050005, 0x27b0001e, 0xc004924, 
-0x2003021, 0x24040001, 0x24050005, 0xc004924, 
-0x2003021, 0x24040001, 0x24050009, 0xc004924, 
-0x2003021, 0x24040001, 0x24050009, 0xc004924, 
-0x2003021, 0x24040001, 0x24050001, 0xc004924, 
-0x27a60018, 0x24040001, 0x24050001, 0xc004924, 
-0x27a60018, 0x97a20018, 0x30420004, 0x10400034, 
-0x3c114000, 0x3c020001, 0x8c425e18, 0x2443ffff, 
-0x2c620006, 0x10400034, 0x31080, 0x3c010001, 
-0x220821, 0x8c225c38, 0x400008, 0x0, 
-0x24040001, 0x24050011, 0x27b00020, 0xc004924, 
-0x2003021, 0x24040001, 0x24050011, 0xc004924, 
-0x2003021, 0x97a40020, 0x30824000, 0x10400002, 
-0x3c030010, 0x3c030008, 0x3c120001, 0x8005306, 
-0x30828000, 0x24040001, 0x24050014, 0x27b00020, 
-0xc004924, 0x2003021, 0x24040001, 0x24050014, 
-0xc004924, 0x2003021, 0x97a40020, 0x30821000, 
-0x10400002, 0x3c030010, 0x3c030008, 0x3c120001, 
-0x30820800, 0x54400001, 0x3c120002, 0x3c028000, 
-0x2221025, 0x2431825, 0x8005313, 0x438825, 
-0x3c110001, 0x2338821, 0x8e317e9c, 0x3c027fff, 
-0x3442ffff, 0x2228824, 0x3c020001, 0x8c425d38, 
-0x1040001c, 0x0, 0x3c020001, 0x8c425df8, 
-0x10400002, 0x3c022000, 0x2228825, 0x141140, 
-0x3c010001, 0x220821, 0x8c227ea0, 0x10400003, 
-0x3c020020, 0x8005327, 0x2228825, 0x3c02ffdf, 
-0x3442ffff, 0x2228824, 0x141140, 0x3c010001, 
-0x220821, 0x8c227ea8, 0x10400003, 0x3c020080, 
-0x8005332, 0x2228825, 0x3c02ff7f, 0x3442ffff, 
-0x2228824, 0x3c040001, 0x24845c2c, 0x3c05000c, 
-0x34a50326, 0x3c070001, 0x8ce75d28, 0x3021, 
-0x141140, 0x3c010001, 0x220821, 0xac317e94, 
-0xafb20010, 0xc002403, 0xafb10014, 0x800538f, 
-0x2201021, 0x142940, 0x3c030001, 0x651821, 
-0x8c637e98, 0x3c024000, 0x621024, 0x14400008, 
-0x3c027fff, 0x3442ffff, 0x628824, 0x3c010001, 
-0x250821, 0xac317e90, 0x800538f, 0x2201021, 
-0x3c020001, 0x8c425d38, 0x10400033, 0x3c11c00c, 
-0x3c020001, 0x8c425dd4, 0x3c04c00c, 0x34842000, 
-0x3c030001, 0x8c635df8, 0x2102b, 0x21023, 
-0x441024, 0x10600003, 0x518825, 0x3c022000, 
-0x2228825, 0x3c020001, 0x451021, 0x8c427ea4, 
-0x10400003, 0x3c020020, 0x800536c, 0x2228825, 
-0x3c02ffdf, 0x3442ffff, 0x2228824, 0x141140, 
-0x3c010001, 0x220821, 0x8c227eac, 0x10400003, 
-0x3c020080, 0x8005377, 0x2228825, 0x3c02ff7f, 
-0x3442ffff, 0x2228824, 0x3c020001, 0x8c425dc0, 
-0x10400002, 0x3c020800, 0x2228825, 0x3c020001, 
-0x8c425dc4, 0x10400002, 0x3c020400, 0x2228825, 
-0x3c020001, 0x8c425dc8, 0x10400006, 0x3c020100, 
-0x800538a, 0x2228825, 0x3c027fff, 0x3442ffff, 
-0x628824, 0x141140, 0x3c010001, 0x220821, 
-0xac317e90, 0x2201021, 0x8fbf003c, 0x8fb40038, 
-0x8fb30034, 0x8fb20030, 0x8fb1002c, 0x8fb00028, 
-0x3e00008, 0x27bd0040, 0x27bdffd8, 0xafb40020, 
-0x80a021, 0xafbf0024, 0xafb3001c, 0xafb20018, 
-0xafb10014, 0xafb00010, 0x8f900200, 0x3c030001, 
-0x8c635d28, 0x8f930220, 0x24020002, 0x10620063, 
-0x2c620003, 0x10400005, 0x24020001, 0x1062000a, 
-0x141940, 0x8005459, 0x0, 0x24020004, 
-0x1062005a, 0x24020008, 0x10620059, 0x149140, 
-0x8005459, 0x0, 0x3c040001, 0x832021, 
-0x8c847e9c, 0x3c110001, 0x2238821, 0x8e317e94, 
-0x3c024000, 0x821024, 0x1040003e, 0x3c020008, 
-0x2221024, 0x10400020, 0x36100002, 0x3c020001, 
-0x431021, 0x8c427ea0, 0x10400005, 0x36100020, 
-0x36100100, 0x3c020020, 0x80053ce, 0x2228825, 
-0x2402feff, 0x2028024, 0x3c02ffdf, 0x3442ffff, 
+0x27bd0038, 0x27bdffd8, 0xafb20020, 0x809021, 
+0xafb1001c, 0x8821, 0x24020002, 0xafbf0024, 
+0xafb00018, 0xa7a00012, 0x10a200d3, 0xa7a00010, 
+0x2ca20003, 0x10400005, 0x24020001, 0x10a2000a, 
+0x128140, 0x8005380, 0x2201021, 0x24020004, 
+0x10a2007d, 0x24020008, 0x10a2007c, 0x122940, 
+0x8005380, 0x2201021, 0x3c030001, 0x701821, 
+0x8c637e3c, 0x3c024000, 0x621024, 0x14400009, 
+0x24040001, 0x3c027fff, 0x3442ffff, 0x628824, 
+0x3c010001, 0x300821, 0xac317e34, 0x8005380, 
+0x2201021, 0x24050001, 0xc00494c, 0x27a60010, 
+0x24040001, 0x24050001, 0xc00494c, 0x27a60010, 
+0x97a20010, 0x30420004, 0x10400034, 0x3c114000, 
+0x3c020001, 0x8c425dbc, 0x2443ffff, 0x2c620006, 
+0x10400034, 0x31080, 0x3c010001, 0x220821, 
+0x8c225be0, 0x400008, 0x0, 0x24040001, 
+0x24050011, 0x27b00012, 0xc00494c, 0x2003021, 
+0x24040001, 0x24050011, 0xc00494c, 0x2003021, 
+0x97a50012, 0x30a24000, 0x10400002, 0x3c040010, 
+0x3c040008, 0x3c030001, 0x8005301, 0x30a28000, 
+0x24040001, 0x24050014, 0x27b00012, 0xc00494c, 
+0x2003021, 0x24040001, 0x24050014, 0xc00494c, 
+0x2003021, 0x97a50012, 0x30a21000, 0x10400002, 
+0x3c040010, 0x3c040008, 0x3c030001, 0x30a20800, 
+0x54400001, 0x3c030002, 0x3c028000, 0x2221025, 
+0x641825, 0x800530e, 0x438825, 0x3c110001, 
+0x2308821, 0x8e317e3c, 0x3c027fff, 0x3442ffff, 
+0x2228824, 0x3c020001, 0x8c425cd8, 0x1040001d, 
+0x121140, 0x3c020001, 0x8c425d98, 0x10400002, 
+0x3c022000, 0x2228825, 0x121140, 0x3c010001, 
+0x220821, 0x8c227e40, 0x10400003, 0x3c020020, 
+0x8005322, 0x2228825, 0x3c02ffdf, 0x3442ffff, 
+0x2228824, 0x121140, 0x3c010001, 0x220821, 
+0x8c227e48, 0x10400003, 0x3c020080, 0x800532d, 
+0x2228825, 0x3c02ff7f, 0x3442ffff, 0x2228824, 
+0x121140, 0x3c010001, 0x220821, 0xac317e34, 
+0x8005380, 0x2201021, 0x122940, 0x3c030001, 
+0x651821, 0x8c637e38, 0x3c024000, 0x621024, 
+0x14400008, 0x3c027fff, 0x3442ffff, 0x628824, 
+0x3c010001, 0x250821, 0xac317e30, 0x8005380, 
+0x2201021, 0x3c020001, 0x8c425cd8, 0x10400033, 
+0x3c11c00c, 0x3c020001, 0x8c425d74, 0x3c04c00c, 
+0x34842000, 0x3c030001, 0x8c635d98, 0x2102b, 
+0x21023, 0x441024, 0x10600003, 0x518825, 
+0x3c022000, 0x2228825, 0x3c020001, 0x451021, 
+0x8c427e44, 0x10400003, 0x3c020020, 0x800535d, 
+0x2228825, 0x3c02ffdf, 0x3442ffff, 0x2228824, 
+0x121140, 0x3c010001, 0x220821, 0x8c227e4c, 
+0x10400003, 0x3c020080, 0x8005368, 0x2228825, 
+0x3c02ff7f, 0x3442ffff, 0x2228824, 0x3c020001, 
+0x8c425d60, 0x10400002, 0x3c020800, 0x2228825, 
+0x3c020001, 0x8c425d64, 0x10400002, 0x3c020400, 
+0x2228825, 0x3c020001, 0x8c425d68, 0x10400006, 
+0x3c020100, 0x800537b, 0x2228825, 0x3c027fff, 
+0x3442ffff, 0x628824, 0x121140, 0x3c010001, 
+0x220821, 0xac317e30, 0x2201021, 0x8fbf0024, 
+0x8fb20020, 0x8fb1001c, 0x8fb00018, 0x3e00008, 
+0x27bd0028, 0x27bdffd8, 0xafb40020, 0x80a021, 
+0xafbf0024, 0xafb3001c, 0xafb20018, 0xafb10014, 
+0xafb00010, 0x8f900200, 0x3c030001, 0x8c635cc8, 
+0x8f930220, 0x24020002, 0x10620063, 0x2c620003, 
+0x10400005, 0x24020001, 0x1062000a, 0x141940, 
+0x8005448, 0x0, 0x24020004, 0x1062005a, 
+0x24020008, 0x10620059, 0x149140, 0x8005448, 
+0x0, 0x3c040001, 0x832021, 0x8c847e3c, 
+0x3c110001, 0x2238821, 0x8e317e34, 0x3c024000, 
+0x821024, 0x1040003e, 0x3c020008, 0x2221024, 
+0x10400020, 0x36100002, 0x3c020001, 0x431021, 
+0x8c427e40, 0x10400005, 0x36100020, 0x36100100, 
+0x3c020020, 0x80053bd, 0x2228825, 0x2402feff, 
+0x2028024, 0x3c02ffdf, 0x3442ffff, 0x2228824, 
+0x141140, 0x3c010001, 0x220821, 0x8c227e48, 
+0x10400005, 0x3c020001, 0x2629825, 0x3c020080, 
+0x80053dc, 0x2228825, 0x3c02fffe, 0x3442ffff, 
+0x2629824, 0x3c02ff7f, 0x3442ffff, 0x80053dc, 
+0x2228824, 0x2402fedf, 0x2028024, 0x3c02fffe, 
+0x3442ffff, 0x2629824, 0x3c02ff5f, 0x3442ffff, 
+0x2228824, 0x3c010001, 0x230821, 0xac207e40, 
+0x3c010001, 0x230821, 0xac207e48, 0xc00486a, 
+0x0, 0xaf900200, 0xaf930220, 0x8f820220, 
+0x2403fffb, 0x431024, 0xaf820220, 0x8f820220, 
+0x34420002, 0xaf820220, 0x80053f3, 0x141140, 
+0x8f820200, 0x2403fffd, 0x431024, 0xc00486a, 
+0xaf820200, 0x3c02bfff, 0x3442ffff, 0xc00429b, 
 0x2228824, 0x141140, 0x3c010001, 0x220821, 
-0x8c227ea8, 0x10400005, 0x3c020001, 0x2629825, 
-0x3c020080, 0x80053ed, 0x2228825, 0x3c02fffe, 
-0x3442ffff, 0x2629824, 0x3c02ff7f, 0x3442ffff, 
-0x80053ed, 0x2228824, 0x2402fedf, 0x2028024, 
-0x3c02fffe, 0x3442ffff, 0x2629824, 0x3c02ff5f, 
-0x3442ffff, 0x2228824, 0x3c010001, 0x230821, 
-0xac207ea0, 0x3c010001, 0x230821, 0xac207ea8, 
-0xc004844, 0x0, 0xaf900200, 0xaf930220, 
+0x8005448, 0xac317e34, 0x149140, 0x3c040001, 
+0x922021, 0x8c847e38, 0x3c110001, 0x2328821, 
+0x8e317e30, 0x3c024000, 0x821024, 0x14400011, 
+0x0, 0x3c020001, 0x8c425d98, 0x14400006, 
+0x3c02bfff, 0x8f820200, 0x34420002, 0xc00486a, 
+0xaf820200, 0x3c02bfff, 0x3442ffff, 0xc00429b, 
+0x2228824, 0x3c010001, 0x320821, 0x8005448, 
+0xac317e30, 0x3c020001, 0x8c425d98, 0x10400005, 
+0x3c020020, 0x3c020001, 0x8c425d74, 0x1040002b, 
+0x3c020020, 0x821024, 0x10400007, 0x36100020, 
+0x24020100, 0x3c010001, 0x320821, 0xac227e44, 
+0x8005428, 0x36100100, 0x3c010001, 0x320821, 
+0xac207e44, 0x2402feff, 0x2028024, 0x3c020080, 
+0x821024, 0x10400007, 0x141940, 0x3c020001, 
+0x3c010001, 0x230821, 0xac227e4c, 0x8005439, 
+0x2629825, 0x141140, 0x3c010001, 0x220821, 
+0xac207e4c, 0x3c02fffe, 0x3442ffff, 0x2629824, 
+0xc00486a, 0x0, 0xaf900200, 0xaf930220, 
 0x8f820220, 0x2403fffb, 0x431024, 0xaf820220, 
-0x8f820220, 0x34420002, 0xaf820220, 0x8005404, 
-0x141140, 0x8f820200, 0x2403fffd, 0x431024, 
-0xc004844, 0xaf820200, 0x3c02bfff, 0x3442ffff, 
-0xc00429b, 0x2228824, 0x141140, 0x3c010001, 
-0x220821, 0x8005459, 0xac317e94, 0x149140, 
-0x3c040001, 0x922021, 0x8c847e98, 0x3c110001, 
-0x2328821, 0x8e317e90, 0x3c024000, 0x821024, 
-0x14400011, 0x0, 0x3c020001, 0x8c425df8, 
-0x14400006, 0x3c02bfff, 0x8f820200, 0x34420002, 
-0xc004844, 0xaf820200, 0x3c02bfff, 0x3442ffff, 
-0xc00429b, 0x2228824, 0x3c010001, 0x320821, 
-0x8005459, 0xac317e90, 0x3c020001, 0x8c425df8, 
-0x10400005, 0x3c020020, 0x3c020001, 0x8c425dd4, 
-0x1040002b, 0x3c020020, 0x821024, 0x10400007, 
-0x36100020, 0x24020100, 0x3c010001, 0x320821, 
-0xac227ea4, 0x8005439, 0x36100100, 0x3c010001, 
-0x320821, 0xac207ea4, 0x2402feff, 0x2028024, 
-0x3c020080, 0x821024, 0x10400007, 0x141940, 
-0x3c020001, 0x3c010001, 0x230821, 0xac227eac, 
-0x800544a, 0x2629825, 0x141140, 0x3c010001, 
-0x220821, 0xac207eac, 0x3c02fffe, 0x3442ffff, 
-0x2629824, 0xc004844, 0x0, 0xaf900200, 
-0xaf930220, 0x8f820220, 0x2403fffb, 0x431024, 
-0xaf820220, 0x8f820220, 0x34420002, 0xaf820220, 
-0x141140, 0x3c010001, 0x220821, 0xac317e90, 
-0x8fbf0024, 0x8fb40020, 0x8fb3001c, 0x8fb20018, 
-0x8fb10014, 0x8fb00010, 0x3e00008, 0x27bd0028, 
-0x0, 0x0, 0x0, 0x0 };
+0x8f820220, 0x34420002, 0xaf820220, 0x141140, 
+0x3c010001, 0x220821, 0xac317e30, 0x8fbf0024, 
+0x8fb40020, 0x8fb3001c, 0x8fb20018, 0x8fb10014, 
+0x8fb00010, 0x3e00008, 0x27bd0028, 0x0 };
 u32 tigonFwRodata[(MAX_RODATA_LEN/4) + 1] __initdata = {
 0x24486561, 0x6465723a, 0x202f7072, 
 0x6f6a6563, 0x74732f72, 0x63732f73, 0x772f6765, 
@@ -4473,10 +4468,10 @@
 0x32203139, 0x39382f30, 0x342f3237, 0x2032323a, 
 0x31333a34, 0x30207368, 0x75616e67, 0x20457870, 
 0x20240000, 0x46575f56, 0x45525349, 0x4f4e3a20, 
-0x23312053, 0x61742044, 0x65632031, 0x31203136, 
-0x3a30333a, 0x31392050, 0x53542031, 0x39393900, 
+0x23312046, 0x72692041, 0x70722037, 0x2031373a, 
+0x35353a34, 0x38205044, 0x54203230, 0x30300000, 
 0x46575f43, 0x4f4d5049, 0x4c455f54, 0x494d453a, 
-0x2031363a, 0x30333a31, 0x39000000, 0x46575f43, 
+0x2031373a, 0x35353a34, 0x38000000, 0x46575f43, 
 0x4f4d5049, 0x4c455f42, 0x593a2064, 0x65767263, 
 0x73000000, 0x46575f43, 0x4f4d5049, 0x4c455f48, 
 0x4f53543a, 0x20636f6d, 0x70757465, 0x0, 
@@ -4554,27 +4549,27 @@
 0x2e322031, 0x3939382f, 0x30342f32, 0x37203232, 
 0x3a31333a, 0x33392073, 0x6875616e, 0x67204578, 
 0x70202400, 0x50726f62, 0x65506879, 0x0, 
-0x6c6e6b41, 0x53535254, 0x0, 0x11af4, 
-0x11b8c, 0x11bac, 0x11bf0, 0x11c1c, 
-0x11c30, 0x11c6c, 0x11fe0, 0x11d48, 
-0x11d88, 0x11db4, 0x11df4, 0x11e24, 
-0x11e60, 0x11e94, 0x11fe0, 0x12228, 
-0x12240, 0x12268, 0x12288, 0x122b0, 
-0x123e0, 0x12408, 0x1245c, 0x12484, 
-0x0, 0x126ec, 0x127bc, 0x12894, 
-0x12964, 0x129c0, 0x12a9c, 0x12ac4, 
-0x12ba0, 0x12bc8, 0x12d70, 0x12d98, 
-0x12f40, 0x13138, 0x133cc, 0x132e0, 
-0x133cc, 0x133f8, 0x12f68, 0x13110, 
-0x0, 0x13ae4, 0x13b28, 0x13bc0, 
-0x13c0c, 0x13c7c, 0x13d14, 0x13d48, 
-0x13dd0, 0x13e68, 0x13f38, 0x13f78, 
-0x13ffc, 0x14020, 0x14154, 0x646f4261, 
+0x6c6e6b41, 0x53535254, 0x0, 0x11b2c, 
+0x11bc4, 0x11bf8, 0x11c2c, 0x11c58, 
+0x11c6c, 0x11ca8, 0x1207c, 0x11de4, 
+0x11e24, 0x11e50, 0x11e90, 0x11ec0, 
+0x11efc, 0x11f30, 0x1207c, 0x122c0, 
+0x122d8, 0x12300, 0x12320, 0x12348, 
+0x12478, 0x124a0, 0x124f4, 0x1251c, 
+0x0, 0x1278c, 0x1285c, 0x12934, 
+0x12a04, 0x12a60, 0x12b3c, 0x12b64, 
+0x12c40, 0x12c68, 0x12e10, 0x12e38, 
+0x12fe0, 0x131d8, 0x1346c, 0x13380, 
+0x1346c, 0x13498, 0x13008, 0x131b0, 
+0x0, 0x13b84, 0x13bc8, 0x13c60, 
+0x13cac, 0x13d1c, 0x13db4, 0x13de8, 
+0x13e70, 0x13f08, 0x13fd8, 0x14018, 
+0x1409c, 0x140c0, 0x141f4, 0x646f4261, 
 0x73655067, 0x0, 0x0, 0x0, 
 0x0, 0x73746d61, 0x634c4e4b, 0x0, 
-0x6765746d, 0x636c6e6b, 0x0, 0x14c4c, 
-0x14c4c, 0x14b94, 0x14bd8, 0x14c4c, 
-0x14c4c, 0x0 };
+0x0, 0x14c38, 0x14c38, 0x14b80, 
+0x14bc4, 0x14c38, 0x14c38, 0x0, 
+0x0, 0x0 };
 u32 tigonFwData[(MAX_DATA_LEN/4) + 1] __initdata = {
 0x416c7465, 
 0x6f6e2041, 0x63654e49, 0x43205600, 0x416c7465, 
@@ -4604,25 +4599,25 @@
 /* Generated by genfw.c */
 #define tigon2FwReleaseMajor 0xc
 #define tigon2FwReleaseMinor 0x4
-#define tigon2FwReleaseFix 0x5
+#define tigon2FwReleaseFix 0xb
 #define tigon2FwStartAddr 0x00004000
 #define tigon2FwTextAddr 0x00004000
-#define tigon2FwTextLen 0x11c50
-#define tigon2FwRodataAddr 0x00015c50
-#define tigon2FwRodataLen 0x10c0
-#define tigon2FwDataAddr 0x00016d40
+#define tigon2FwTextLen 0x11bc0
+#define tigon2FwRodataAddr 0x00015bc0
+#define tigon2FwRodataLen 0x10d0
+#define tigon2FwDataAddr 0x00016cc0
 #define tigon2FwDataLen 0x1c0
-#define tigon2FwSbssAddr 0x00016f00
-#define tigon2FwSbssLen 0xc4
-#define tigon2FwBssAddr 0x00016fd0
+#define tigon2FwSbssAddr 0x00016e80
+#define tigon2FwSbssLen 0xcc
+#define tigon2FwBssAddr 0x00016f50
 #define tigon2FwBssLen 0x20c0
 u32 tigon2FwText[(MAX_TEXT_LEN/4) + 1] __initdata = {
 0x0, 
 0x10000003, 0x0, 0xd, 0xd, 
-0x3c1d0001, 0x8fbd6da0, 0x3a0f021, 0x3c100000, 
+0x3c1d0001, 0x8fbd6d20, 0x3a0f021, 0x3c100000, 
 0x26104000, 0xc0010c0, 0x0, 0xd, 
-0x3c1d0001, 0x8fbd6da4, 0x3a0f021, 0x3c100000, 
-0x26104000, 0xc0017c8, 0x0, 0xd, 
+0x3c1d0001, 0x8fbd6d24, 0x3a0f021, 0x3c100000, 
+0x26104000, 0xc0017e0, 0x0, 0xd, 
 0x0, 0x0, 0x0, 0x0, 
 0x0, 0x0, 0x0, 0x0, 
 0x0, 0x0, 0x0, 0x0, 
@@ -4634,22 +4629,22 @@
 0x0, 0x0, 0x0, 0x0, 
 0x0, 0x0, 0x0, 0x0, 
 0x0, 0x0, 0x0, 0x2000008, 
-0x0, 0x8001717, 0x3c0a0001, 0x8001717, 
-0x3c0a0002, 0x8001717, 0x0, 0x8002c68, 
-0x0, 0x8002c0b, 0x0, 0x8001717, 
-0x3c0a0004, 0x8003272, 0x0, 0x8001a3a, 
-0x0, 0x8003925, 0x0, 0x80038cc, 
-0x0, 0x8001717, 0x3c0a0006, 0x8003993, 
-0x3c0a0007, 0x8001717, 0x3c0a0008, 0x8001717, 
-0x3c0a0009, 0x80039eb, 0x0, 0x8002e62, 
-0x0, 0x8001717, 0x3c0a000b, 0x8001717, 
-0x3c0a000c, 0x8001717, 0x3c0a000d, 0x80028d7, 
-0x0, 0x800286c, 0x0, 0x8001717, 
-0x3c0a000e, 0x8002074, 0x0, 0x800194c, 
-0x0, 0x80019ec, 0x0, 0x8003c7e, 
-0x0, 0x8003c6c, 0x0, 0x8001717, 
-0x0, 0x8001902, 0x0, 0x8001717, 
-0x0, 0x8001717, 0x3c0a0013, 0x8001717, 
+0x0, 0x800172f, 0x3c0a0001, 0x800172f, 
+0x3c0a0002, 0x800172f, 0x0, 0x8002cac, 
+0x0, 0x8002c4f, 0x0, 0x800172f, 
+0x3c0a0004, 0x800328a, 0x0, 0x8001a52, 
+0x0, 0x800394d, 0x0, 0x80038f4, 
+0x0, 0x800172f, 0x3c0a0006, 0x80039bb, 
+0x3c0a0007, 0x800172f, 0x3c0a0008, 0x800172f, 
+0x3c0a0009, 0x8003a13, 0x0, 0x8002ea6, 
+0x0, 0x800172f, 0x3c0a000b, 0x800172f, 
+0x3c0a000c, 0x800172f, 0x3c0a000d, 0x80028fb, 
+0x0, 0x8002890, 0x0, 0x800172f, 
+0x3c0a000e, 0x800208c, 0x0, 0x8001964, 
+0x0, 0x8001a04, 0x0, 0x8003ca6, 
+0x0, 0x8003c94, 0x0, 0x800172f, 
+0x0, 0x800191a, 0x0, 0x800172f, 
+0x0, 0x800172f, 0x3c0a0013, 0x800172f, 
 0x3c0a0014, 0x0, 0x0, 0x0, 
 0x0, 0x0, 0x0, 0x0, 
 0x0, 0x0, 0x0, 0x0, 
@@ -4667,335 +4662,341 @@
 0x0, 0x0, 0x0, 0x0, 
 0x0, 0x0, 0x0, 0x27bdffe0, 
 0x3c1cc000, 0xafbf001c, 0xafb00018, 0x8f820140, 
-0x24030003, 0xaf8300ec, 0x34420004, 0xc002afc, 
-0xaf820140, 0x3c0100c0, 0xc00174b, 0xac203ffc, 
-0x403021, 0x3c020008, 0x3c010001, 0xac266f18, 
-0x50c2000d, 0x24020008, 0x3c100010, 0x10d00009, 
-0x24050100, 0x3c040001, 0x24845d04, 0x3821, 
-0xafa00010, 0xc002b17, 0xafa00014, 0x3c010001, 
-0xac306f18, 0x24020008, 0x3c010001, 0xac226f30, 
-0x2402001f, 0x3c010001, 0xac226f40, 0x24020016, 
-0x3c010001, 0xac226f14, 0x3c05fffe, 0x34a56f08, 
-0x3c020001, 0x8c426f18, 0x3c030002, 0x24639090, 
-0x3c040001, 0x8c846d44, 0x431023, 0x14800002, 
-0x458021, 0x2610fa38, 0x2402f000, 0x2028024, 
-0xc00176d, 0x2002021, 0x2022823, 0x3c040020, 
-0x821823, 0x651823, 0x247bb000, 0x3c03fffe, 
-0x3463bf08, 0x363b821, 0x3c0600bf, 0x34c6f000, 
-0x3c070001, 0x8ce76d40, 0x3c0300bf, 0x3463e000, 
-0x852023, 0x3c010001, 0xac246f24, 0x822023, 
-0x3c010001, 0xac256f0c, 0x52842, 0x3c010001, 
-0xac226f00, 0x27620ffc, 0x3c010001, 0xac226da0, 
-0x27621ffc, 0xdb3023, 0x7b1823, 0x3c010001, 
-0xac246f04, 0x3c010001, 0xac256f28, 0x3c010001, 
-0xac226da4, 0xaf860150, 0x10e00011, 0xaf830250, 
-0x3c1d0001, 0x8fbd6d4c, 0x3a0f021, 0xc001731, 
-0x0, 0x3c020001, 0x8c426d50, 0x3c030001, 
-0x8c636d54, 0x2442fe00, 0x24630200, 0x3c010001, 
-0xac226d50, 0x3c010001, 0x10000004, 0xac236d54, 
-0x3c1d0001, 0x8fbd6da0, 0x3a0f021, 0x3c020001, 
-0x8c426d44, 0x1040000d, 0x26fafa38, 0x3c020001, 
-0x8c426d50, 0x3c030001, 0x8c636d54, 0x3c1a0001, 
-0x8f5a6d54, 0x2442fa38, 0x246305c8, 0x3c010001, 
-0xac226d50, 0x3c010001, 0xac236d54, 0x3c020001, 
-0x8c426d48, 0x14400003, 0x0, 0x3c010001, 
-0xac206d50, 0xc00114c, 0x0, 0x8fbf001c, 
-0x8fb00018, 0x3e00008, 0x27bd0020, 0x3c020001, 
-0x8c426d50, 0x3c030001, 0x8c636d54, 0x27bdffa0, 
-0xafb00040, 0x3c100001, 0x8e106748, 0x3c040001, 
-0x24845d10, 0xafbf0058, 0xafbe0054, 0xafb50050, 
-0xafb3004c, 0xafb20048, 0xafb10044, 0xafa20034, 
-0xafa30030, 0xafa00010, 0xafa00014, 0x8f860040, 
-0x24050200, 0xc002b17, 0x2003821, 0x8f830040, 
-0x3c02f000, 0x621824, 0x3c026000, 0x1062000b, 
-0xa3a0003f, 0x240e0001, 0x3c040001, 0x24845d18, 
-0xa3ae003f, 0xafa00010, 0xafa00014, 0x8f860040, 
-0x24050300, 0xc002b17, 0x2003821, 0x8f820240, 
-0x3c030001, 0x431025, 0xaf820240, 0xaf800048, 
-0x8f820048, 0x14400005, 0x0, 0xaf800048, 
-0x8f820048, 0x10400004, 0x0, 0xaf800048, 
-0x10000003, 0x2e02021, 0xaf80004c, 0x2e02021, 
-0x3c050001, 0xc002b84, 0x34a540f8, 0x3402021, 
-0xc002b84, 0x240505c8, 0x3c020001, 0x8c426f24, 
-0x3c0d0001, 0x8dad6f04, 0x3c030001, 0x8c636f00, 
-0x3c080001, 0x8d086f0c, 0x3c090001, 0x8d296f28, 
-0x3c0a0001, 0x8d4a6f30, 0x3c0b0001, 0x8d6b6f40, 
-0x3c0c0001, 0x8d8c6f14, 0x3c040001, 0x24845d24, 
-0x24050400, 0xaf42013c, 0x8f42013c, 0x24060001, 
-0x24070001, 0xaf400000, 0xaf4d0138, 0xaf430144, 
-0xaf480148, 0xaf49014c, 0xaf4a0150, 0xaf4b0154, 
-0xaf4c0158, 0x2442ff80, 0xaf420140, 0x24020001, 
-0xafa20010, 0xc002b17, 0xafa00014, 0x8f420138, 
-0xafa20010, 0x8f42013c, 0xafa20014, 0x8f460144, 
-0x8f470148, 0x3c040001, 0x24845d30, 0xc002b17, 
-0x24050500, 0xafb70010, 0xafba0014, 0x8f46014c, 
-0x8f470150, 0x3c040001, 0x24845d3c, 0xc002b17, 
-0x24050600, 0x3c020001, 0x8c426f18, 0x3603821, 
-0x3c060002, 0x24c69090, 0x2448ffff, 0x1061824, 
-0xe81024, 0x43102b, 0x10400006, 0x24050900, 
-0x3c040001, 0x24845d48, 0xafa80010, 0xc002b17, 
-0xafa00014, 0x8f82000c, 0xafa20010, 0x8f82003c, 
-0xafa20014, 0x8f860000, 0x8f870004, 0x3c040001, 
-0x24845d54, 0xc002b17, 0x24051000, 0x8c020220, 
-0x8c030224, 0x8c060218, 0x8c07021c, 0x3c040001, 
-0x24845d5c, 0x24051100, 0xafa20010, 0xc002b17, 
-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, 0x8f420014, 0xaf8200b0, 0x8f8200b0, 
-0x30420004, 0x1440fffd, 0x0, 0x8f8200b0, 
-0x3c03ef00, 0x431024, 0x10400021, 0x0, 
-0x8f8200b4, 0xafa20010, 0x8f820090, 0x8f830094, 
-0x3c040001, 0x24845d64, 0xafa30014, 0x8f8600b0, 
-0x8f87009c, 0x3c050001, 0xc002b17, 0x34a5200d, 
-0x3c040001, 0x24845d70, 0x240203ac, 0xafa20010, 
-0xafa00014, 0x8f860144, 0x3c070001, 0x24e75d78, 
-0xc002b17, 0x3405dead, 0x8f82011c, 0x34420002, 
-0xaf82011c, 0x8f820220, 0x34420004, 0xaf820220, 
-0x8f820140, 0x3c030001, 0x431025, 0xaf820140, 
-0x96e20472, 0x96e60452, 0x96e70462, 0xafa20010, 
-0x96e20482, 0x3c040001, 0x24845da4, 0x24051200, 
-0xc002b17, 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, 0x24845db0, 
-0x24051300, 0x2003821, 0xa3ae003f, 0xafa30010, 
-0xc002b17, 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, 0xaf420160, 
-0xaf430164, 0x8ee204a0, 0x8ee304a4, 0xaf420168, 
-0xaf43016c, 0x8ee204a8, 0x8ee304ac, 0xaf420170, 
-0xaf430174, 0x8ee20428, 0x8ee3042c, 0xaf420178, 
-0xaf43017c, 0x8ee20448, 0x8ee3044c, 0xaf420180, 
-0xaf430184, 0x8ee20458, 0x8ee3045c, 0xaf420188, 
-0xaf43018c, 0x8ee20468, 0x8ee3046c, 0xaf420190, 
-0xaf430194, 0x8ee20478, 0x8ee3047c, 0xaf420198, 
-0xaf43019c, 0x8ee20488, 0x8ee3048c, 0xaf4201a0, 
-0xaf4301a4, 0x8ee204b0, 0x8ee304b4, 0x24040080, 
-0xaf4201a8, 0xaf4301ac, 0xc002b84, 0x24050080, 
-0x8c02025c, 0x27440224, 0xaf4201f0, 0x8c020260, 
-0x24050200, 0x24060008, 0xc002b9b, 0xaf4201f8, 
-0x3c043b9a, 0x3484ca00, 0x3821, 0x24020006, 
-0x24030002, 0xaf4201f4, 0x240203e8, 0xaf430204, 
-0xaf430200, 0xaf4401fc, 0xaf420294, 0x24020001, 
-0xaf430290, 0xaf42029c, 0x3c030001, 0x671821, 
-0x90636d58, 0x3471021, 0x24e70001, 0xa043022c, 
-0x2ce2000f, 0x1440fff8, 0x3471821, 0x24e70001, 
-0x3c080001, 0x350840f8, 0x8f820040, 0x3c040001, 
-0x24845dbc, 0x24051400, 0x21702, 0x24420030, 
-0xa062022c, 0x3471021, 0xa040022c, 0x8c070218, 
-0x2c03021, 0x240205c8, 0xafa20010, 0xc002b17, 
-0xafa80014, 0x3c040001, 0x24845dc8, 0x3c050000, 
-0x24a55c20, 0x24060010, 0x27b10030, 0x2203821, 
-0x27b30034, 0xc00178b, 0xafb30010, 0x3c030001, 
-0x8c636d48, 0x1060000a, 0x408021, 0x8fa30030, 
-0x2405ff00, 0x8fa20034, 0x246400ff, 0x852024, 
-0x831823, 0x431023, 0xafa20034, 0xafa40030, 
-0xafb30010, 0x3c040001, 0x24845dd4, 0x3c050000, 
-0x24a54100, 0x24060108, 0xc00178b, 0x2203821, 
-0x409021, 0x32c20003, 0x50400045, 0x2203821, 
-0x8f820050, 0x3c030010, 0x431024, 0x10400016, 
-0x0, 0x8c020218, 0x30420040, 0x1040000f, 
-0x24020001, 0x8f820050, 0x8c030218, 0x240e0001, 
-0x3c040001, 0x24845de0, 0xa3ae003f, 0xafa20010, 
-0xafa30014, 0x8f870040, 0x24051500, 0xc002b17, 
-0x2c03021, 0x10000004, 0x0, 0x3c010001, 
-0x370821, 0xa02240f4, 0x3c040001, 0x24845dec, 
-0x3c050001, 0x24a55bd0, 0x3c060001, 0x24c65c3c, 
-0xc53023, 0x8f420010, 0x27b30030, 0x2603821, 
-0x27b10034, 0x34420a00, 0xaf420010, 0xc00178b, 
-0xafb10010, 0x3c040001, 0x24845e00, 0x3c050001, 
-0x24a5b604, 0x3c060001, 0x24c6b980, 0xc53023, 
-0x2603821, 0xaf420108, 0xc00178b, 0xafb10010, 
-0x3c040001, 0x24845e1c, 0x3c050001, 0x24a5bda0, 
-0x3c060001, 0x24c6c8a0, 0xc53023, 0x2603821, 
-0x3c010001, 0xac226f70, 0xc00178b, 0xafb10010, 
-0x3c040001, 0x24845e34, 0x10000024, 0x24051600, 
-0x3c040001, 0x24845e3c, 0x3c050001, 0x24a5a07c, 
-0x3c060001, 0x24c6a1a8, 0xc53023, 0xc00178b, 
-0xafb30010, 0x3c040001, 0x24845e4c, 0x3c050001, 
-0x24a5b1a0, 0x3c060001, 0x24c6b5fc, 0xc53023, 
-0x2203821, 0xaf420108, 0xc00178b, 0xafb30010, 
-0x3c040001, 0x24845e60, 0x3c050001, 0x24a5b988, 
-0x3c060001, 0x24c6bd98, 0xc53023, 0x2203821, 
-0x3c010001, 0xac226f70, 0xc00178b, 0xafb30010, 
-0x3c040001, 0x24845e74, 0x24051650, 0x2c03021, 
-0x3821, 0x3c010001, 0xac226f74, 0xafa00010, 
-0xc002b17, 0xafa00014, 0x32c20020, 0x10400021, 
-0x27a70030, 0x3c040001, 0x24845e80, 0x3c050001, 
-0x24a5b02c, 0x3c060001, 0x24c6b198, 0xc53023, 
-0x24022000, 0xaf42001c, 0x27a20034, 0xc00178b, 
-0xafa20010, 0x21900, 0x31982, 0x3c040800, 
-0x641825, 0xae430028, 0x24030010, 0xaf43003c, 
-0x96e30450, 0xaf430040, 0x8f430040, 0x3c040001, 
-0x24845e94, 0xafa00014, 0xafa30010, 0x8f47001c, 
-0x24051660, 0x3c010001, 0xac226f6c, 0x10000025, 
-0x32c60020, 0x8ee20448, 0x8ee3044c, 0xaf43001c, 
-0x8f42001c, 0x2442e000, 0x2c422001, 0x1440000a, 
-0x240e0001, 0x3c040001, 0x24845ea0, 0xa3ae003f, 
-0xafa00010, 0xafa00014, 0x8f46001c, 0x24051700, 
-0xc002b17, 0x3821, 0x3c020000, 0x24425c5c, 
-0x21100, 0x21182, 0x3c030800, 0x431025, 
-0xae420028, 0x24020008, 0xaf42003c, 0x96e20450, 
-0xaf420040, 0x8f420040, 0x3c040001, 0x24845eac, 
-0xafa00014, 0xafa20010, 0x8f47001c, 0x24051800, 
-0x32c60020, 0xc002b17, 0x0, 0x3c030001, 
-0x8c636f70, 0x3c050fff, 0x34a5ffff, 0x3c020001, 
-0x8c426f74, 0x3c040800, 0x651824, 0x31882, 
-0x641825, 0x451024, 0x21082, 0x441025, 
-0xae420080, 0x32c20180, 0x10400056, 0xae430020, 
-0x8f82005c, 0x3c030080, 0x431024, 0x1040000d, 
-0x0, 0x8f820050, 0xafa20010, 0x8f82005c, 
-0x240e0001, 0x3c040001, 0x24845eb8, 0xa3ae003f, 
-0xafa20014, 0x8f870040, 0x24051900, 0xc002b17, 
-0x2c03021, 0x8f820050, 0x3c030010, 0x431024, 
+0x24030003, 0xaf8300ec, 0x34420004, 0xc002b20, 
+0xaf820140, 0x3c0100c0, 0xc001763, 0xac203ffc, 
+0x401821, 0x3c020010, 0x3c010001, 0xac236e9c, 
+0x10620011, 0x43102b, 0x14400002, 0x3c020020, 
+0x3c020008, 0x1062000c, 0x24050100, 0x3c060001, 
+0x8cc66e9c, 0x3c040001, 0x24845c74, 0x3821, 
+0xafa00010, 0xc002b3b, 0xafa00014, 0x3c020020, 
+0x3c010001, 0xac226e9c, 0x24020008, 0x3c010001, 
+0xac226eb4, 0x2402001f, 0x3c010001, 0xac226ec4, 
+0x24020016, 0x3c010001, 0xac226e98, 0x3c05fffe, 
+0x34a56f08, 0x3c020001, 0x8c426e9c, 0x3c030002, 
+0x24639010, 0x3c040001, 0x8c846cc4, 0x431023, 
+0x14800002, 0x458021, 0x2610fa38, 0x2402f000, 
+0x2028024, 0xc001785, 0x2002021, 0x2022823, 
+0x3c040020, 0x821823, 0x651823, 0x247bb000, 
+0x3c03fffe, 0x3463bf08, 0x363b821, 0x3c0600bf, 
+0x34c6f000, 0x3c070001, 0x8ce76cc0, 0x3c0300bf, 
+0x3463e000, 0x852023, 0x3c010001, 0xac246ea8, 
+0x822023, 0x3c010001, 0xac256e90, 0x52842, 
+0x3c010001, 0xac226e84, 0x27620ffc, 0x3c010001, 
+0xac226d20, 0x27621ffc, 0xdb3023, 0x7b1823, 
+0x3c010001, 0xac246e88, 0x3c010001, 0xac256eac, 
+0x3c010001, 0xac226d24, 0xaf860150, 0x10e00011, 
+0xaf830250, 0x3c1d0001, 0x8fbd6ccc, 0x3a0f021, 
+0xc001749, 0x0, 0x3c020001, 0x8c426cd0, 
+0x3c030001, 0x8c636cd4, 0x2442fe00, 0x24630200, 
+0x3c010001, 0xac226cd0, 0x3c010001, 0x10000004, 
+0xac236cd4, 0x3c1d0001, 0x8fbd6d20, 0x3a0f021, 
+0x3c020001, 0x8c426cc4, 0x1040000d, 0x26fafa38, 
+0x3c020001, 0x8c426cd0, 0x3c030001, 0x8c636cd4, 
+0x3c1a0001, 0x8f5a6cd4, 0x2442fa38, 0x246305c8, 
+0x3c010001, 0xac226cd0, 0x3c010001, 0xac236cd4, 
+0x3c020001, 0x8c426cc8, 0x14400003, 0x0, 
+0x3c010001, 0xac206cd0, 0xc001151, 0x0, 
+0x8fbf001c, 0x8fb00018, 0x3e00008, 0x27bd0020, 
+0x3c020001, 0x8c426cd0, 0x3c030001, 0x8c636cd4, 
+0x27bdff98, 0xafb00048, 0x3c100001, 0x8e1066b8, 
+0xafb20050, 0x3c120000, 0x26524100, 0xafbf0060, 
+0xafbe005c, 0xafb50058, 0xafb30054, 0xafb1004c, 
+0xafa20034, 0xafa30030, 0xafa00010, 0xafa00014, 
+0x8f860040, 0x3c040001, 0x24845c80, 0x24050200, 
+0x3c010001, 0xac326e80, 0xc002b3b, 0x2003821, 
+0x8f830040, 0x3c02f000, 0x621824, 0x3c026000, 
+0x1062000b, 0xa3a0003f, 0x240e0001, 0x3c040001, 
+0x24845c88, 0xa3ae003f, 0xafa00010, 0xafa00014, 
+0x8f860040, 0x24050300, 0xc002b3b, 0x2003821, 
+0x8f820240, 0x3c030001, 0x431025, 0xaf820240, 
+0xaf800048, 0x8f820048, 0x14400005, 0x0, 
+0xaf800048, 0x8f820048, 0x10400004, 0x0, 
+0xaf800048, 0x10000003, 0x2e02021, 0xaf80004c, 
+0x2e02021, 0x3c050001, 0xc002ba8, 0x34a540f8, 
+0x3402021, 0xc002ba8, 0x240505c8, 0x3c020001, 
+0x8c426ea8, 0x3c0d0001, 0x8dad6e88, 0x3c030001, 
+0x8c636e84, 0x3c080001, 0x8d086e90, 0x3c090001, 
+0x8d296eac, 0x3c0a0001, 0x8d4a6eb4, 0x3c0b0001, 
+0x8d6b6ec4, 0x3c0c0001, 0x8d8c6e98, 0x3c040001, 
+0x24845c94, 0x24050400, 0xaf42013c, 0x8f42013c, 
+0x24060001, 0x24070001, 0xaf400000, 0xaf4d0138, 
+0xaf430144, 0xaf480148, 0xaf49014c, 0xaf4a0150, 
+0xaf4b0154, 0xaf4c0158, 0x2442ff80, 0xaf420140, 
+0x24020001, 0xafa20010, 0xc002b3b, 0xafa00014, 
+0x8f420138, 0xafa20010, 0x8f42013c, 0xafa20014, 
+0x8f460144, 0x8f470148, 0x3c040001, 0x24845ca0, 
+0xc002b3b, 0x24050500, 0xafb70010, 0xafba0014, 
+0x8f46014c, 0x8f470150, 0x3c040001, 0x24845cac, 
+0xc002b3b, 0x24050600, 0x3c020001, 0x8c426e9c, 
+0x3603821, 0x3c060002, 0x24c69010, 0x2448ffff, 
+0x1061824, 0xe81024, 0x43102b, 0x10400006, 
+0x24050900, 0x3c040001, 0x24845cb8, 0xafa80010, 
+0xc002b3b, 0xafa00014, 0x8f82000c, 0xafa20010, 
+0x8f82003c, 0xafa20014, 0x8f860000, 0x8f870004, 
+0x3c040001, 0x24845cc4, 0xc002b3b, 0x24051000, 
+0x8c020220, 0x8c030224, 0x8c060218, 0x8c07021c, 
+0x3c040001, 0x24845ccc, 0x24051100, 0xafa20010, 
+0xc002b3b, 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, 0xaf8000d0, 0xaf8000c0, 
+0x10000002, 0x24630064, 0x8f820054, 0x621023, 
+0x2c420065, 0x1440fffc, 0x0, 0x8c040208, 
+0x8c05020c, 0x26e20028, 0xaee20020, 0x24020490, 
+0xaee20010, 0xaee40008, 0xaee5000c, 0x26e40008, 
+0x8c820000, 0x8c830004, 0xaf820090, 0xaf830094, 
+0x8c820018, 0xaf8200b4, 0x9482000a, 0xaf82009c, 
+0x8f420014, 0xaf8200b0, 0x8f8200b0, 0x30420004, 
+0x1440fffd, 0x0, 0x8f8200b0, 0x3c03ef00, 
+0x431024, 0x10400021, 0x0, 0x8f8200b4, 
+0xafa20010, 0x8f820090, 0x8f830094, 0x3c040001, 
+0x24845cd4, 0xafa30014, 0x8f8600b0, 0x8f87009c, 
+0x3c050001, 0xc002b3b, 0x34a5200d, 0x3c040001, 
+0x24845ce0, 0x240203c0, 0xafa20010, 0xafa00014, 
+0x8f860144, 0x3c070001, 0x24e75ce8, 0xc002b3b, 
+0x3405dead, 0x8f82011c, 0x34420002, 0xaf82011c, 
+0x8f820220, 0x34420004, 0xaf820220, 0x8f820140, 
+0x3c030001, 0x431025, 0xaf820140, 0x96e20472, 
+0x96e60452, 0x96e70462, 0xafa20010, 0x96e20482, 
+0x3c040001, 0x24845d14, 0x24051200, 0xc002b3b, 
+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, 0x24845d20, 0x24051300, 
+0x2003821, 0xa3ae003f, 0xafa30010, 0xc002b3b, 
+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, 0xaf420160, 0xaf430164, 
+0x8ee204a0, 0x8ee304a4, 0xaf420168, 0xaf43016c, 
+0x8ee204a8, 0x8ee304ac, 0xaf420170, 0xaf430174, 
+0x8ee20428, 0x8ee3042c, 0xaf420178, 0xaf43017c, 
+0x8ee20448, 0x8ee3044c, 0xaf420180, 0xaf430184, 
+0x8ee20458, 0x8ee3045c, 0xaf420188, 0xaf43018c, 
+0x8ee20468, 0x8ee3046c, 0xaf420190, 0xaf430194, 
+0x8ee20478, 0x8ee3047c, 0xaf420198, 0xaf43019c, 
+0x8ee20488, 0x8ee3048c, 0xaf4201a0, 0xaf4301a4, 
+0x8ee204b0, 0x8ee304b4, 0x24040080, 0xaf4201a8, 
+0xaf4301ac, 0xc002ba8, 0x24050080, 0x8c02025c, 
+0x27440224, 0xaf4201f0, 0x8c020260, 0x24050200, 
+0x24060008, 0xc002bbf, 0xaf4201f8, 0x3c043b9a, 
+0x3484ca00, 0x3821, 0x24020006, 0x24030002, 
+0xaf4201f4, 0x240203e8, 0xaf430204, 0xaf430200, 
+0xaf4401fc, 0xaf420294, 0x24020001, 0xaf430290, 
+0xaf42029c, 0x3c030001, 0x671821, 0x90636cd8, 
+0x3471021, 0x24e70001, 0xa043022c, 0x2ce2000f, 
+0x1440fff8, 0x3471821, 0x24e70001, 0x3c080001, 
+0x350840f8, 0x8f820040, 0x3c040001, 0x24845d2c, 
+0x24051400, 0x21702, 0x24420030, 0xa062022c, 
+0x3471021, 0xa040022c, 0x8c070218, 0x2c03021, 
+0x240205c8, 0xafa20010, 0xc002b3b, 0xafa80014, 
+0x3c040001, 0x24845d38, 0x3c050000, 0x24a55c80, 
+0x24060010, 0x27b10030, 0x2203821, 0x27b30034, 
+0xc0017a3, 0xafb30010, 0x3c030001, 0x8c636cc8, 
+0x1060000a, 0x408021, 0x8fa30030, 0x2405ff00, 
+0x8fa20034, 0x246400ff, 0x852024, 0x831823, 
+0x431023, 0xafa20034, 0xafa40030, 0x3c040001, 
+0x24845d44, 0x3c050000, 0x24a54100, 0x24060108, 
+0x2203821, 0xc0017a3, 0xafb30010, 0x409021, 
+0x32c20003, 0x3c010001, 0xac326e80, 0x10400045, 
+0x2203821, 0x8f820050, 0x3c030010, 0x431024, 
 0x10400016, 0x0, 0x8c020218, 0x30420040, 
 0x1040000f, 0x24020001, 0x8f820050, 0x8c030218, 
-0x240e0001, 0x3c040001, 0x24845de0, 0xa3ae003f, 
-0xafa20010, 0xafa30014, 0x8f870040, 0x24052000, 
-0xc002b17, 0x2c03021, 0x10000004, 0x0, 
+0x240e0001, 0x3c040001, 0x24845d50, 0xa3ae003f, 
+0xafa20010, 0xafa30014, 0x8f870040, 0x24051500, 
+0xc002b3b, 0x2c03021, 0x10000004, 0x0, 
+0x3c010001, 0x370821, 0xa02240f4, 0x3c040001, 
+0x24845d5c, 0x3c050001, 0x24a55b40, 0x3c060001, 
+0x24c65bac, 0xc53023, 0x8f420010, 0x27b30030, 
+0x2603821, 0x27b10034, 0x34420a00, 0xaf420010, 
+0xc0017a3, 0xafb10010, 0x3c040001, 0x24845d70, 
+0x3c050001, 0x24a5b714, 0x3c060001, 0x24c6ba90, 
+0xc53023, 0x2603821, 0xaf420108, 0xc0017a3, 
+0xafb10010, 0x3c040001, 0x24845d8c, 0x3c050001, 
+0x24a5be58, 0x3c060001, 0x24c6c900, 0xc53023, 
+0x2603821, 0x3c010001, 0xac226ef4, 0xc0017a3, 
+0xafb10010, 0x3c040001, 0x24845da4, 0x10000024, 
+0x24051600, 0x3c040001, 0x24845dac, 0x3c050001, 
+0x24a5a10c, 0x3c060001, 0x24c6a238, 0xc53023, 
+0xc0017a3, 0xafb30010, 0x3c040001, 0x24845dbc, 
+0x3c050001, 0x24a5b2b0, 0x3c060001, 0x24c6b70c, 
+0xc53023, 0x2203821, 0xaf420108, 0xc0017a3, 
+0xafb30010, 0x3c040001, 0x24845dd0, 0x3c050001, 
+0x24a5ba98, 0x3c060001, 0x24c6be50, 0xc53023, 
+0x2203821, 0x3c010001, 0xac226ef4, 0xc0017a3, 
+0xafb30010, 0x3c040001, 0x24845de4, 0x24051650, 
+0x2c03021, 0x3821, 0x3c010001, 0xac226ef8, 
+0xafa00010, 0xc002b3b, 0xafa00014, 0x32c20020, 
+0x10400021, 0x27a70030, 0x3c040001, 0x24845df0, 
+0x3c050001, 0x24a5b13c, 0x3c060001, 0x24c6b2a8, 
+0xc53023, 0x24022000, 0xaf42001c, 0x27a20034, 
+0xc0017a3, 0xafa20010, 0x21900, 0x31982, 
+0x3c040800, 0x641825, 0xae430028, 0x24030010, 
+0xaf43003c, 0x96e30450, 0xaf430040, 0x8f430040, 
+0x3c040001, 0x24845e04, 0xafa00014, 0xafa30010, 
+0x8f47001c, 0x24051660, 0x3c010001, 0xac226ef0, 
+0x10000025, 0x32c60020, 0x8ee20448, 0x8ee3044c, 
+0xaf43001c, 0x8f42001c, 0x2442e000, 0x2c422001, 
+0x1440000a, 0x240e0001, 0x3c040001, 0x24845e10, 
+0xa3ae003f, 0xafa00010, 0xafa00014, 0x8f46001c, 
+0x24051700, 0xc002b3b, 0x3821, 0x3c020000, 
+0x24425cbc, 0x21100, 0x21182, 0x3c030800, 
+0x431025, 0xae420028, 0x24020008, 0xaf42003c, 
+0x96e20450, 0xaf420040, 0x8f420040, 0x3c040001, 
+0x24845e1c, 0xafa00014, 0xafa20010, 0x8f47001c, 
+0x24051800, 0x32c60020, 0xc002b3b, 0x0, 
+0x3c050fff, 0x3c030001, 0x8c636ef4, 0x34a5ffff, 
+0x2403021, 0x3c020001, 0x8c426ef8, 0x3c040800, 
+0x651824, 0x31882, 0x641825, 0x451024, 
+0x21082, 0x441025, 0xacc20080, 0x32c20180, 
+0x10400056, 0xacc30020, 0x8f82005c, 0x3c030080, 
+0x431024, 0x1040000d, 0x0, 0x8f820050, 
+0xafa20010, 0x8f82005c, 0x240e0001, 0x3c040001, 
+0x24845e28, 0xa3ae003f, 0xafa20014, 0x8f870040, 
+0x24051900, 0xc002b3b, 0x2c03021, 0x8f820050, 
+0x3c030010, 0x431024, 0x10400016, 0x0, 
+0x8c020218, 0x30420040, 0x1040000f, 0x24020001, 
+0x8f820050, 0x8c030218, 0x240e0001, 0x3c040001, 
+0x24845d50, 0xa3ae003f, 0xafa20010, 0xafa30014, 
+0x8f870040, 0x24052000, 0xc002b3b, 0x2c03021, 
+0x10000004, 0x0, 0x3c010001, 0x370821, 
+0xa02240f4, 0x3c040001, 0x24845e34, 0x3c050001, 
+0x24a55ac0, 0x3c060001, 0x24c65b38, 0xc53023, 
+0x8f420008, 0x27b30030, 0x2603821, 0x27b10034, 
+0x34420e00, 0xaf420008, 0xc0017a3, 0xafb10010, 
+0x3c040001, 0x24845e4c, 0x3c050001, 0x24a5d8b4, 
+0x3c060001, 0x24c6e3c8, 0xc53023, 0x2603821, 
+0xaf42010c, 0xc0017a3, 0xafb10010, 0x3c040001, 
+0x24845e64, 0x3c050001, 0x24a5e9ac, 0x3c060001, 
+0x24c6f0f0, 0xc53023, 0x2603821, 0x3c010001, 
+0xac226f04, 0xc0017a3, 0xafb10010, 0x3c040001, 
+0x24845e7c, 0x10000027, 0x24052100, 0x3c040001, 
+0x24845e84, 0x3c050001, 0x24a59fc8, 0x3c060001, 
+0x24c6a104, 0xc53023, 0x27b10030, 0x2203821, 
+0x27b30034, 0xc0017a3, 0xafb30010, 0x3c040001, 
+0x24845e94, 0x3c050001, 0x24a5cad4, 0x3c060001, 
+0x24c6d8ac, 0xc53023, 0x2203821, 0xaf42010c, 
+0xc0017a3, 0xafb30010, 0x3c040001, 0x24845ea4, 
+0x3c050001, 0x24a5e84c, 0x3c060001, 0x24c6e9a4, 
+0xc53023, 0x2203821, 0x3c010001, 0xac226f04, 
+0xc0017a3, 0xafb30010, 0x3c040001, 0x24845eb8, 
+0x24052150, 0x2c03021, 0x3821, 0x3c010001, 
+0xac226f10, 0xafa00010, 0xc002b3b, 0xafa00014, 
+0x3c110fff, 0x3c030001, 0x8c636f04, 0x3631ffff, 
+0x2409821, 0x3c020001, 0x8c426f10, 0x3c0e0800, 
+0x711824, 0x31882, 0x6e1825, 0x511024, 
+0x21082, 0x4e1025, 0xae630038, 0xae620078, 
+0x8c020218, 0x30420040, 0x14400004, 0x24020001, 
 0x3c010001, 0x370821, 0xa02240f4, 0x3c040001, 
-0x24845ec4, 0x3c050001, 0x24a55b50, 0x3c060001, 
-0x24c65bc8, 0xc53023, 0x8f420008, 0x27b30030, 
-0x2603821, 0x27b10034, 0x34420e00, 0xaf420008, 
-0xc00178b, 0xafb10010, 0x3c040001, 0x24845edc, 
-0x3c050001, 0x24a5d814, 0x3c060001, 0x24c6e328, 
-0xc53023, 0x2603821, 0xaf42010c, 0xc00178b, 
-0xafb10010, 0x3c040001, 0x24845ef4, 0x3c050001, 
-0x24a5e90c, 0x3c060001, 0x24c6f050, 0xc53023, 
-0x2603821, 0x3c010001, 0xac226f80, 0xc00178b, 
-0xafb10010, 0x3c040001, 0x24845f0c, 0x10000027, 
-0x24052100, 0x3c040001, 0x24845f14, 0x3c050001, 
-0x24a59f38, 0x3c060001, 0x24c6a074, 0xc53023, 
-0x27b10030, 0x2203821, 0x27b30034, 0xc00178b, 
-0xafb30010, 0x3c040001, 0x24845f24, 0x3c050001, 
-0x24a5ca74, 0x3c060001, 0x24c6d80c, 0xc53023, 
-0x2203821, 0xaf42010c, 0xc00178b, 0xafb30010, 
-0x3c040001, 0x24845f34, 0x3c050001, 0x24a5e7ac, 
-0x3c060001, 0x24c6e904, 0xc53023, 0x2203821, 
-0x3c010001, 0xac226f80, 0xc00178b, 0xafb30010, 
-0x3c040001, 0x24845f48, 0x24052150, 0x2c03021, 
-0x3821, 0x3c010001, 0xac226f8c, 0xafa00010, 
-0xc002b17, 0xafa00014, 0x3c030001, 0x8c636f80, 
-0x3c110fff, 0x3631ffff, 0x3c020001, 0x8c426f8c, 
-0x3c1e0800, 0x711824, 0x31882, 0x7e1825, 
-0x511024, 0x21082, 0x5e1025, 0xae430038, 
-0xae420078, 0x8c020218, 0x30420040, 0x14400004, 
-0x24020001, 0x3c010001, 0x370821, 0xa02240f4, 
-0x3c040001, 0x24845f54, 0x3c050001, 0x24a5e330, 
-0x3c060001, 0x24c6e48c, 0xc53023, 0x27b50030, 
-0x2a03821, 0x27b30034, 0xc00178b, 0xafb30010, 
-0x3c010001, 0xac226f78, 0x511024, 0x21082, 
-0x5e1025, 0xae420050, 0x32c22000, 0x10400005, 
-0x2a03821, 0x3c020000, 0x24425c5c, 0x1000000d, 
-0x511024, 0x3c040001, 0x24845f68, 0x3c050001, 
-0x24a5e494, 0x3c060001, 0x24c6e644, 0xc53023, 
-0xc00178b, 0xafb30010, 0x3c010001, 0xac226f90, 
-0x511024, 0x21082, 0x5e1025, 0xae420048, 
-0x32c24000, 0x10400005, 0x27a70030, 0x3c020000, 
-0x24425c5c, 0x1000000e, 0x21100, 0x3c040001, 
-0x24845f80, 0x3c050001, 0x24a5e64c, 0x3c060001, 
-0x24c6e7a4, 0xc53023, 0x27a20034, 0xc00178b, 
-0xafa20010, 0x3c010001, 0xac226f84, 0x21100, 
-0x21182, 0x3c030800, 0x431025, 0xae420060, 
-0x3c040001, 0x24845f98, 0x3c050001, 0x24a581d0, 
-0x3c060001, 0x24c685f0, 0xc53023, 0x27b10030, 
-0x2203821, 0x27b30034, 0xc00178b, 0xafb30010, 
-0x3c1e0fff, 0x37deffff, 0x3c040001, 0x24845fa4, 
-0x3c050000, 0x24a56408, 0x3c060000, 0x24c66528, 
-0xc53023, 0x2203821, 0x3c010001, 0xac226f58, 
-0x5e1024, 0x21082, 0x3c150800, 0x551025, 
-0xae4200b8, 0xc00178b, 0xafb30010, 0x3c040001, 
-0x24845fb0, 0x3c050000, 0x24a56530, 0x3c060000, 
-0x24c667a8, 0xc53023, 0x2203821, 0x3c010001, 
-0xac226f4c, 0x5e1024, 0x21082, 0x551025, 
-0xae4200e8, 0xc00178b, 0xafb30010, 0x3c040001, 
-0x24845fc8, 0x3c050000, 0x24a567b0, 0x3c060000, 
-0x24c668e0, 0xc53023, 0x2203821, 0x3c010001, 
-0xac226f44, 0x5e1024, 0x21082, 0x551025, 
-0xae4200c0, 0xc00178b, 0xafb30010, 0x3c040001, 
-0x24845fe0, 0x3c050001, 0x24a5fa30, 0x3c060001, 
-0x24c6fb08, 0xc53023, 0x2203821, 0x3c010001, 
-0xac226f50, 0x5e1024, 0x21082, 0x551025, 
-0xae4200c8, 0xc00178b, 0xafb30010, 0x3c040001, 
-0x24845fec, 0x3c050001, 0x24a5c8dc, 0x3c060001, 
-0x24c6c9c0, 0xc53023, 0x2203821, 0xaf420110, 
-0xc00178b, 0xafb30010, 0x3c040001, 0x24845ffc, 
-0x3c050001, 0x24a5c8b0, 0x3c060001, 0x24c6c8d4, 
-0xc53023, 0x2203821, 0xaf420124, 0xc00178b, 
-0xafb30010, 0x3c040001, 0x2484600c, 0x3c050001, 
-0x24a55b10, 0x3c060001, 0x24c65b3c, 0xc53023, 
-0x2203821, 0xaf420120, 0xaf420114, 0xc00178b, 
-0xafb30010, 0x3c040001, 0x24846018, 0x3c050001, 
-0x24a5f1f8, 0x3c060001, 0x24c6f614, 0xc53023, 
-0x2203821, 0xaf420118, 0xc00178b, 0xafb30010, 
-0x3c010001, 0xac226f94, 0x5e1024, 0x21082, 
-0x551025, 0xc003f9b, 0xae4200d0, 0xc003c18, 
-0x0, 0xc002784, 0x0, 0xac000228, 
+0x24845ec4, 0x3c050001, 0x24a5e3d0, 0x3c060001, 
+0x24c6e52c, 0xc53023, 0x27be0030, 0x3c03821, 
+0x27b50034, 0xc0017a3, 0xafb50010, 0x3c010001, 
+0xac226efc, 0x511024, 0x21082, 0x3c0e0800, 
+0x4e1025, 0xae620050, 0x32c22000, 0x10400006, 
+0x3c03821, 0x3c020000, 0x24425cbc, 0x2221024, 
+0x1000000f, 0x21082, 0x3c040001, 0x24845ed8, 
+0x3c050001, 0x24a5e534, 0x3c060001, 0x24c6e6e4, 
+0xc53023, 0xc0017a3, 0xafb50010, 0x3c010001, 
+0xac226f14, 0x511024, 0x21082, 0x3c0e0800, 
+0x4e1025, 0xae620048, 0x32c24000, 0x10400005, 
+0x27a70030, 0x3c020000, 0x24425cbc, 0x1000000e, 
+0x21100, 0x3c040001, 0x24845ef0, 0x3c050001, 
+0x24a5e6ec, 0x3c060001, 0x24c6e844, 0xc53023, 
+0x27a20034, 0xc0017a3, 0xafa20010, 0x3c010001, 
+0xac226f08, 0x21100, 0x21182, 0x3c030800, 
+0x431025, 0xae420060, 0x3c040001, 0x24845f08, 
+0x3c050001, 0x24a58230, 0x3c060001, 0x24c68650, 
+0xc53023, 0x27b10030, 0x2203821, 0x27b30034, 
+0xc0017a3, 0xafb30010, 0x3c0e0fff, 0x35ceffff, 
+0x3c040001, 0x24845f14, 0x3c050000, 0x24a56468, 
+0x3c060000, 0x24c66588, 0xc53023, 0x2203821, 
+0x240f021, 0x3c010001, 0xac226edc, 0x4e1024, 
+0x21082, 0x3c150800, 0x551025, 0xafae0044, 
+0xafc200b8, 0xc0017a3, 0xafb30010, 0x3c040001, 
+0x24845f20, 0x3c050000, 0x24a56590, 0x3c060000, 
+0x24c66808, 0x8fae0044, 0xc53023, 0x2203821, 
+0x3c010001, 0xac226ed0, 0x4e1024, 0x21082, 
+0x551025, 0xafc200e8, 0xc0017a3, 0xafb30010, 
+0x3c040001, 0x24845f38, 0x3c050000, 0x24a56810, 
+0x3c060000, 0x24c66940, 0x8fae0044, 0xc53023, 
+0x2203821, 0x3c010001, 0xac226ec8, 0x4e1024, 
+0x21082, 0x551025, 0xafc200c0, 0xc0017a3, 
+0xafb30010, 0x3c040001, 0x24845f50, 0x3c050001, 
+0x24a5fad0, 0x3c060001, 0x24c6fba8, 0x8fae0044, 
+0xc53023, 0x2203821, 0x3c010001, 0xac226ed4, 
+0x4e1024, 0x21082, 0x551025, 0xafc200c8, 
+0xc0017a3, 0xafb30010, 0x3c040001, 0x24845f5c, 
+0x3c050001, 0x24a5c93c, 0x3c060001, 0x24c6ca20, 
+0xc53023, 0x2203821, 0xaf420110, 0xc0017a3, 
+0xafb30010, 0x3c040001, 0x24845f6c, 0x3c050001, 
+0x24a5c910, 0x3c060001, 0x24c6c934, 0xc53023, 
+0x2203821, 0xaf420124, 0xc0017a3, 0xafb30010, 
+0x3c040001, 0x24845f7c, 0x3c050001, 0x24a55a80, 
+0x3c060001, 0x24c65aac, 0xc53023, 0x2203821, 
+0xaf420120, 0xaf420114, 0xc0017a3, 0xafb30010, 
+0x3c040001, 0x24845f88, 0x3c050001, 0x24a5f298, 
+0x3c060001, 0x24c6f6b4, 0xc53023, 0x2203821, 
+0xaf420118, 0xc0017a3, 0xafb30010, 0x8fae0044, 
+0x3c010001, 0xac226f18, 0x4e1024, 0x21082, 
+0x551025, 0xc003fc3, 0xafc200d0, 0xc003c40, 
+0x0, 0xc0027a8, 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, 0x24846028, 0xa3ae003f, 
+0x240e0001, 0x3c040001, 0x24845f98, 0xa3ae003f, 
 0x96e60490, 0x24052170, 0x2c03821, 0xafa00010, 
-0xc002b17, 0xafa00014, 0x8f430138, 0x8f440138, 
+0xc002b3b, 0xafa00014, 0x8f430138, 0x8f440138, 
 0x24020001, 0xa34205c2, 0xaf430094, 0xaf440098, 
 0xafa00010, 0xafa00014, 0x8f460080, 0x8f470084, 
-0x3c040001, 0x24846034, 0xc002b17, 0x24052200, 
-0xc002480, 0x3c110800, 0x3c1433d8, 0x3694cb58, 
-0x3c020800, 0x34420080, 0x3c040001, 0x24846040, 
-0x3c050000, 0x24a55ca0, 0x3c060000, 0x24c65cbc, 
+0x3c040001, 0x24845fa4, 0xc002b3b, 0x24052200, 
+0xc0024a4, 0x3c110800, 0x3c1433d8, 0x3694cb58, 
+0x3c020800, 0x34420080, 0x3c040001, 0x24845fb0, 
+0x3c050000, 0x24a55d00, 0x3c060000, 0x24c65d1c, 
 0xc53023, 0x27a70030, 0xaf820060, 0x2402ffff, 
-0xaf820064, 0x27a20034, 0xc00178b, 0xafa20010, 
-0x3c010001, 0xac226f34, 0x21100, 0x21182, 
-0x511025, 0xc0018e4, 0xae420000, 0x8f820240, 
+0xaf820064, 0x27a20034, 0xc0017a3, 0xafa20010, 
+0x3c010001, 0xac226eb8, 0x21100, 0x21182, 
+0x511025, 0xc0018fc, 0xae420000, 0x8f820240, 
 0x3c030001, 0x431025, 0xaf820240, 0x3c020000, 
 0x24424034, 0xaf820244, 0xaf800240, 0x8f820060, 
 0x511024, 0x14400005, 0x3c030800, 0x8f820060, 
-0x431024, 0x1040fffd, 0x0, 0xc003c25, 
+0x431024, 0x1040fffd, 0x0, 0xc003c4d, 
 0x8821, 0x3c020100, 0xafa20020, 0x8f530018, 
 0x240200ff, 0x56620001, 0x26710001, 0x8c020228, 
 0x1622000e, 0x1330c0, 0x8f42033c, 0x24420001, 
 0xaf42033c, 0x8f42033c, 0x8c020228, 0x3c040001, 
-0x24845cb4, 0x3c050009, 0xafa00014, 0xafa20010, 
+0x24845c24, 0x3c050009, 0xafa00014, 0xafa20010, 
 0x8fa60020, 0x1000003f, 0x34a50100, 0xd71021, 
 0x8fa30020, 0x8fa40024, 0xac4304c0, 0xac4404c4, 
 0xc01821, 0x8f440178, 0x8f45017c, 0x1021, 
@@ -5004,21 +5005,21 @@
 0x24070008, 0xa32821, 0xa3482b, 0x822021, 
 0x100f809, 0x892021, 0x1440000b, 0x24070008, 
 0x8f820120, 0xafa20010, 0x8f820124, 0x3c040001, 
-0x24845cbc, 0x3c050009, 0xafa20014, 0x8fa60020, 
+0x24845c2c, 0x3c050009, 0xafa20014, 0x8fa60020, 
 0x1000001c, 0x34a50200, 0x8f440160, 0x8f450164, 
 0x8f43000c, 0xaf510018, 0x8f860120, 0x24020010, 
 0xafa20010, 0xafb10014, 0xafa30018, 0x8f42010c, 
 0x40f809, 0x24c6001c, 0x14400010, 0x0, 
 0x8f420340, 0x24420001, 0xaf420340, 0x8f420340, 
 0x8f820120, 0xafa20010, 0x8f820124, 0x3c040001, 
-0x24845cc4, 0x3c050009, 0xafa20014, 0x8fa60020, 
-0x34a50300, 0xc002b17, 0x2603821, 0x8f4202e4, 
+0x24845c34, 0x3c050009, 0xafa20014, 0x8fa60020, 
+0x34a50300, 0xc002b3b, 0x2603821, 0x8f4202e4, 
 0x24420001, 0xaf4202e4, 0x8f4202e4, 0x93a2003f, 
 0x10400069, 0x3c020700, 0x34423000, 0xafa20028, 
 0x8f530018, 0x240200ff, 0x12620002, 0x8821, 
 0x26710001, 0x8c020228, 0x1622000e, 0x1330c0, 
 0x8f42033c, 0x24420001, 0xaf42033c, 0x8f42033c, 
-0x8c020228, 0x3c040001, 0x24845cb4, 0x3c050009, 
+0x8c020228, 0x3c040001, 0x24845c24, 0x3c050009, 
 0xafa00014, 0xafa20010, 0x8fa60028, 0x1000003f, 
 0x34a50100, 0xd71021, 0x8fa30028, 0x8fa4002c, 
 0xac4304c0, 0xac4404c4, 0xc01821, 0x8f440178, 
@@ -5027,18 +5028,18 @@
 0xafa80018, 0x8f48010c, 0x24070008, 0xa32821, 
 0xa3482b, 0x822021, 0x100f809, 0x892021, 
 0x1440000b, 0x24070008, 0x8f820120, 0xafa20010, 
-0x8f820124, 0x3c040001, 0x24845cbc, 0x3c050009, 
+0x8f820124, 0x3c040001, 0x24845c2c, 0x3c050009, 
 0xafa20014, 0x8fa60028, 0x1000001c, 0x34a50200, 
 0x8f440160, 0x8f450164, 0x8f43000c, 0xaf510018, 
 0x8f860120, 0x24020010, 0xafa20010, 0xafb10014, 
 0xafa30018, 0x8f42010c, 0x40f809, 0x24c6001c, 
 0x14400010, 0x0, 0x8f420340, 0x24420001, 
 0xaf420340, 0x8f420340, 0x8f820120, 0xafa20010, 
-0x8f820124, 0x3c040001, 0x24845cc4, 0x3c050009, 
-0xafa20014, 0x8fa60028, 0x34a50300, 0xc002b17, 
+0x8f820124, 0x3c040001, 0x24845c34, 0x3c050009, 
+0xafa20014, 0x8fa60028, 0x34a50300, 0xc002b3b, 
 0x2603821, 0x8f4202f0, 0x24420001, 0xaf4202f0, 
-0x8f4202f0, 0x3c040001, 0x24846050, 0xafa00010, 
-0xafa00014, 0x8fa60028, 0x24052300, 0xc002b17, 
+0x8f4202f0, 0x3c040001, 0x24845fc0, 0xafa00010, 
+0xafa00014, 0x8fa60028, 0x24052300, 0xc002b3b, 
 0x3821, 0x10000004, 0x0, 0x8c020264, 
 0x10400005, 0x0, 0x8f8200a0, 0x30420004, 
 0x1440fffa, 0x0, 0x8f820044, 0x34420004, 
@@ -5049,31 +5050,31 @@
 0x431021, 0xaf420090, 0x24020001, 0xaf42008c, 
 0x32c20008, 0x10400006, 0x0, 0x8f820214, 
 0x3c038100, 0x3042ffff, 0x431025, 0xaf820214, 
-0x3c030001, 0x8c636e14, 0x30620002, 0x10400009, 
-0x30620001, 0x3c040001, 0x2484605c, 0x3c050000, 
-0x24a56cf0, 0x3c060000, 0x24c67168, 0x10000012, 
+0x3c030001, 0x8c636d94, 0x30620002, 0x10400009, 
+0x30620001, 0x3c040001, 0x24845fcc, 0x3c050000, 
+0x24a56d50, 0x3c060000, 0x24c671c8, 0x10000012, 
 0xc53023, 0x10400009, 0x0, 0x3c040001, 
-0x2484606c, 0x3c050000, 0x24a57170, 0x3c060000, 
-0x24c67618, 0x10000008, 0xc53023, 0x3c040001, 
-0x2484607c, 0x3c050000, 0x24a568e8, 0x3c060000, 
-0x24c66ce8, 0xc53023, 0x27a70030, 0x27a20034, 
-0xc00178b, 0xafa20010, 0x3c010001, 0xac226f48, 
-0x3c020001, 0x8c426f48, 0x3c030800, 0x21100, 
+0x24845fdc, 0x3c050000, 0x24a571d0, 0x3c060000, 
+0x24c67678, 0x10000008, 0xc53023, 0x3c040001, 
+0x24845fec, 0x3c050000, 0x24a56948, 0x3c060000, 
+0x24c66d48, 0xc53023, 0x27a70030, 0x27a20034, 
+0xc0017a3, 0xafa20010, 0x3c010001, 0xac226ecc, 
+0x3c020001, 0x8c426ecc, 0x3c030800, 0x21100, 
 0x21182, 0x431025, 0xae420040, 0x8f8200a0, 
 0xafa20010, 0x8f8200b0, 0xafa20014, 0x8f86005c, 
-0x8f87011c, 0x3c040001, 0x2484608c, 0x3c010001, 
-0xac366f20, 0x3c010001, 0xac206f10, 0x3c010001, 
-0xac3c6f08, 0x3c010001, 0xac3b6f38, 0x3c010001, 
-0xac376f3c, 0x3c010001, 0xac3a6f1c, 0xc002b17, 
+0x8f87011c, 0x3c040001, 0x24845ffc, 0x3c010001, 
+0xac366ea4, 0x3c010001, 0xac206e94, 0x3c010001, 
+0xac3c6e8c, 0x3c010001, 0xac3b6ebc, 0x3c010001, 
+0xac376ec0, 0x3c010001, 0xac3a6ea0, 0xc002b3b, 
 0x24052400, 0x8f820200, 0xafa20010, 0x8f820220, 
 0xafa20014, 0x8f860044, 0x8f870050, 0x3c040001, 
-0x24846098, 0xc002b17, 0x24052500, 0x8f830060, 
+0x24846008, 0xc002b3b, 0x24052500, 0x8f830060, 
 0x74100b, 0x242000a, 0x200f821, 0x0, 
-0xd, 0x8fbf0058, 0x8fbe0054, 0x8fb50050, 
-0x8fb3004c, 0x8fb20048, 0x8fb10044, 0x8fb00040, 
-0x3e00008, 0x27bd0060, 0x27bdffe0, 0x3c040001, 
-0x248460a4, 0x24052600, 0x3021, 0x3821, 
-0xafbf0018, 0xafa00010, 0xc002b17, 0xafa00014, 
+0xd, 0x8fbf0060, 0x8fbe005c, 0x8fb50058, 
+0x8fb30054, 0x8fb20050, 0x8fb1004c, 0x8fb00048, 
+0x3e00008, 0x27bd0068, 0x27bdffe0, 0x3c040001, 
+0x24846014, 0x24052600, 0x3021, 0x3821, 
+0xafbf0018, 0xafa00010, 0xc002b3b, 0xafa00014, 
 0x8fbf0018, 0x3e00008, 0x27bd0020, 0x3e00008, 
 0x0, 0x3e00008, 0x0, 0x0, 
 0x0, 0x0, 0x0, 0x0, 
@@ -5083,15 +5084,15 @@
 0xafa40018, 0xa22823, 0xa32824, 0x8ca20000, 
 0x1044000a, 0x0, 0xafa50010, 0x8ca20000, 
 0xafa20014, 0x8f860150, 0x8f870250, 0x3c040001, 
-0x248460ac, 0xc002b17, 0x24052700, 0x8fbf0218, 
+0x2484601c, 0xc002b3b, 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, 
-0x248460b8, 0x24052800, 0x2003021, 0x3821, 
-0xafa00010, 0xc002b17, 0xafa00014, 0x2001021, 
+0x24846028, 0x24052800, 0x2003021, 0x3821, 
+0xafa00010, 0xc002b3b, 0xafa00014, 0x2001021, 
 0x8fbf001c, 0x8fb00018, 0x3e00008, 0x27bd0020, 
 0x8c020224, 0x3047003f, 0x10e00010, 0x803021, 
 0x2821, 0x24030020, 0xe31024, 0x10400002, 
@@ -5106,84 +5107,84 @@
 0x8ea20000, 0x2403fffc, 0xc38024, 0x50102b, 
 0x1440001b, 0xe08821, 0x8e330000, 0xafb00010, 
 0x8ea20000, 0xafa20014, 0x8e270000, 0x24053000, 
-0xc002b17, 0x2403021, 0x8e230000, 0x702021, 
+0xc002b3b, 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, 
-0xc002b17, 0x2603021, 0x2601021, 0x8fbf002c, 
+0xc002b3b, 0x2603021, 0x2601021, 0x8fbf002c, 
 0x8fb50028, 0x8fb30024, 0x8fb20020, 0x8fb1001c, 
 0x8fb00018, 0x3e00008, 0x27bd0030, 0x27bdffe8, 
-0x3c1cc000, 0x3c05fffe, 0x3c030001, 0x8c636f00, 
-0x3c040001, 0x8c846f0c, 0x34a5bf08, 0x24021ffc, 
-0x3c010001, 0xac226d50, 0x3c0200c0, 0x3c010001, 
-0xac226d54, 0x3c020020, 0xafbf0010, 0x3c0100c0, 
+0x3c1cc000, 0x3c05fffe, 0x3c030001, 0x8c636e84, 
+0x3c040001, 0x8c846e90, 0x34a5bf08, 0x24021ffc, 
+0x3c010001, 0xac226cd0, 0x3c0200c0, 0x3c010001, 
+0xac226cd4, 0x3c020020, 0xafbf0010, 0x3c0100c0, 
 0xac201ffc, 0x431023, 0x441023, 0x245bb000, 
-0x365b821, 0x3c1d0001, 0x8fbd6d4c, 0x3a0f021, 
+0x365b821, 0x3c1d0001, 0x8fbd6ccc, 0x3a0f021, 
 0x3c0400c0, 0x34840200, 0x3c1a00c0, 0x3c0300c0, 
-0x346307c8, 0x24021dfc, 0x3c010001, 0xac226d50, 
-0x24021834, 0x3c010001, 0xac246d54, 0x3c010001, 
-0xac226d50, 0x3c010001, 0xac236d54, 0xc0017f5, 
+0x346307c8, 0x24021dfc, 0x3c010001, 0xac226cd0, 
+0x24021834, 0x3c010001, 0xac246cd4, 0x3c010001, 
+0xac226cd0, 0x3c010001, 0xac236cd4, 0xc00180d, 
 0x375a0200, 0x8fbf0010, 0x3e00008, 0x27bd0018, 
-0x27bdffc8, 0x3c040001, 0x248460c4, 0x24053200, 
-0x3c020001, 0x8c426d50, 0x3c030001, 0x8c636d54, 
+0x27bdffc8, 0x3c040001, 0x24846034, 0x24053200, 
+0x3c020001, 0x8c426cd0, 0x3c030001, 0x8c636cd4, 
 0x3021, 0x3603821, 0xafbf0030, 0xafb3002c, 
 0xafb20028, 0xafb10024, 0xafb00020, 0xafa2001c, 
-0xafa30018, 0xafb70010, 0xc002b17, 0xafba0014, 
-0xc0018fe, 0x0, 0x8f820240, 0x34420004, 
+0xafa30018, 0xafb70010, 0xc002b3b, 0xafba0014, 
+0xc001916, 0x0, 0x8f820240, 0x34420004, 
 0xaf820240, 0x24020001, 0xaf420000, 0x3c020001, 
 0x571021, 0x904240f4, 0x10400092, 0x2403fffc, 
-0x3c100001, 0x2610abe3, 0x3c120001, 0x2652a7bc, 
+0x3c100001, 0x2610ac73, 0x3c120001, 0x2652a84c, 
 0x2121023, 0x438024, 0x8fa3001c, 0x3c040001, 
-0x248460d0, 0x70102b, 0x1440001a, 0x27b30018, 
+0x24846040, 0x70102b, 0x1440001a, 0x27b30018, 
 0x8fb10018, 0x24053000, 0x2403021, 0xafb00010, 
-0xafa30014, 0xc002b17, 0x2203821, 0x8fa30018, 
+0xafa30014, 0xc002b3b, 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, 
-0xc002b17, 0xa0820000, 0x24070020, 0x8fa3001c, 
-0x3c040001, 0x248460ec, 0x24120020, 0x3c010001, 
-0xac316f2c, 0x2c620020, 0x1440001d, 0x27b10018, 
-0x8fb00018, 0x24053000, 0x3c060001, 0x24c66fd0, 
-0xafa70010, 0xafa30014, 0xc002b17, 0x2003821, 
-0x8fa30018, 0x3c040001, 0x24846fd0, 0x24650020, 
+0xc002b3b, 0xa0820000, 0x24070020, 0x8fa3001c, 
+0x3c040001, 0x2484605c, 0x24120020, 0x3c010001, 
+0xac316eb0, 0x2c620020, 0x1440001d, 0x27b10018, 
+0x8fb00018, 0x24053000, 0x3c060001, 0x24c66f50, 
+0xafa70010, 0xafa30014, 0xc002b3b, 0x2003821, 
+0x8fa30018, 0x3c040001, 0x24846f50, 0x24650020, 
 0x65102b, 0x10400007, 0x0, 0x8c820000, 
 0xac620000, 0x24630004, 0x65102b, 0x1440fffb, 
 0x24840004, 0x8fa2001c, 0x521023, 0xafa2001c, 
 0x8e220000, 0x521021, 0x1000000b, 0xae220000, 
-0x3c100001, 0x26106fd0, 0x24053100, 0xafa70010, 
+0x3c100001, 0x26106f50, 0x24053100, 0xafa70010, 
 0xafa30014, 0x8fa70018, 0x2003021, 0x2402002d, 
-0xc002b17, 0xa0820000, 0x24070020, 0x3c040001, 
-0x24846100, 0x8fa3001c, 0x24120020, 0x3c010001, 
-0xac306f60, 0x2c620020, 0x1440001d, 0x27b10018, 
-0x8fb00018, 0x24053000, 0x3c060001, 0x24c66ff0, 
-0xafa70010, 0xafa30014, 0xc002b17, 0x2003821, 
-0x8fa30018, 0x3c040001, 0x24846ff0, 0x24650020, 
+0xc002b3b, 0xa0820000, 0x24070020, 0x3c040001, 
+0x24846070, 0x8fa3001c, 0x24120020, 0x3c010001, 
+0xac306ee4, 0x2c620020, 0x1440001d, 0x27b10018, 
+0x8fb00018, 0x24053000, 0x3c060001, 0x24c66f70, 
+0xafa70010, 0xafa30014, 0xc002b3b, 0x2003821, 
+0x8fa30018, 0x3c040001, 0x24846f70, 0x24650020, 
 0x65102b, 0x10400007, 0x0, 0x8c820000, 
 0xac620000, 0x24630004, 0x65102b, 0x1440fffb, 
 0x24840004, 0x8fa2001c, 0x521023, 0xafa2001c, 
 0x8e220000, 0x521021, 0x1000000b, 0xae220000, 
-0x3c100001, 0x26106ff0, 0x24053100, 0xafa70010, 
+0x3c100001, 0x26106f70, 0x24053100, 0xafa70010, 
 0xafa30014, 0x8fa70018, 0x2003021, 0x2402002d, 
-0xc002b17, 0xa0820000, 0x3c010001, 0x10000031, 
-0xac306f5c, 0x3c100001, 0x261081bf, 0x3c120001, 
-0x2652803c, 0x2121023, 0x438024, 0x8fa3001c, 
-0x3c040001, 0x24846114, 0x70102b, 0x1440001a, 
+0xc002b3b, 0xa0820000, 0x3c010001, 0x10000031, 
+0xac306ee0, 0x3c100001, 0x2610821f, 0x3c120001, 
+0x2652809c, 0x2121023, 0x438024, 0x8fa3001c, 
+0x3c040001, 0x24846084, 0x70102b, 0x1440001a, 
 0x27b30018, 0x8fb10018, 0x24053000, 0x2403021, 
-0xafb00010, 0xafa30014, 0xc002b17, 0x2203821, 
+0xafb00010, 0xafa30014, 0xc002b3b, 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, 0xc002b17, 0xa0820000, 0x3c010001, 
-0xac316f2c, 0x3c030001, 0x8c636f2c, 0x24020400, 
+0x2402002d, 0xc002b3b, 0xa0820000, 0x3c010001, 
+0xac316eb0, 0x3c030001, 0x8c636eb0, 0x24020400, 
 0x60f809, 0xaf820070, 0x8fbf0030, 0x8fb3002c, 
 0x8fb20028, 0x8fb10024, 0x8fb00020, 0x3e00008, 
 0x27bd0038, 0x0, 0x0, 0x8f820040, 
@@ -5197,21 +5198,21 @@
 0xaf820078, 0x27bdffe8, 0xafbf0010, 0x8f820054, 
 0x244203e8, 0xaf820058, 0x3c020800, 0x2c21024, 
 0x10400004, 0x3c02f7ff, 0x3442ffff, 0x2c2b024, 
-0x36940040, 0x3c020001, 0x8c426e28, 0x10400017, 
-0x3c020200, 0x3c030001, 0x8c636f98, 0x10600016, 
-0x282a025, 0x3c020001, 0x8c426ec4, 0x14400012, 
-0x3c020200, 0x3c020001, 0x8c426e14, 0x30420003, 
+0x36940040, 0x3c020001, 0x8c426da8, 0x10400017, 
+0x3c020200, 0x3c030001, 0x8c636f1c, 0x10600016, 
+0x282a025, 0x3c020001, 0x8c426e44, 0x14400012, 
+0x3c020200, 0x3c020001, 0x8c426d94, 0x30420003, 
 0x1440000d, 0x3c020200, 0x8f830224, 0x3c020002, 
-0x8c42906c, 0x10620008, 0x3c020200, 0xc003d87, 
-0x0, 0x10000004, 0x3c020200, 0xc004161, 
+0x8c428fec, 0x10620008, 0x3c020200, 0xc003daf, 
+0x0, 0x10000004, 0x3c020200, 0xc004196, 
 0x0, 0x3c020200, 0x2c21024, 0x10400003, 
-0x0, 0xc001f33, 0x0, 0x8f4200d8, 
+0x0, 0xc001f4b, 0x0, 0x8f4200d8, 
 0x8f4300dc, 0x24420001, 0xaf4200d8, 0x43102b, 
 0x14400003, 0x0, 0xaf4000d8, 0x36940080, 
 0x8c030238, 0x1060000c, 0x0, 0x8f4201b0, 
 0x244203e8, 0xaf4201b0, 0x43102b, 0x14400006, 
 0x0, 0x934205c5, 0x14400003, 0x0, 
-0xc001d88, 0x0, 0x8fbf0010, 0x3e00008, 
+0xc001da0, 0x0, 0x8fbf0010, 0x3e00008, 
 0x27bd0018, 0x3e00008, 0x0, 0x27bdffd8, 
 0xafbf0020, 0x8f43002c, 0x8f420038, 0x10620059, 
 0x0, 0x3c020001, 0x571021, 0x904240f0, 
@@ -5220,8 +5221,8 @@
 0xafa30014, 0xafa80018, 0x8f42010c, 0x40f809, 
 0x24c6001c, 0x14400011, 0x24020001, 0x3c010001, 
 0x370821, 0xa02240f0, 0x8f820124, 0xafa20010, 
-0x8f820128, 0x3c040001, 0x248461b8, 0xafa20014, 
-0x8f46002c, 0x8f870120, 0x3c050009, 0xc002b17, 
+0x8f820128, 0x3c040001, 0x24846128, 0xafa20014, 
+0x8f46002c, 0x8f870120, 0x3c050009, 0xc002b3b, 
 0x34a50900, 0x1000005c, 0x0, 0x8f420300, 
 0x24420001, 0xaf420300, 0x8f420300, 0x8f42002c, 
 0xa34005c1, 0x10000027, 0xaf420038, 0x8f440170, 
@@ -5230,8 +5231,8 @@
 0x8f42010c, 0x40f809, 0x24c6001c, 0x14400011, 
 0x24020001, 0x3c010001, 0x370821, 0xa02240f1, 
 0x8f820124, 0xafa20010, 0x8f820128, 0x3c040001, 
-0x248461c4, 0xafa20014, 0x8f46002c, 0x8f870120, 
-0x3c050009, 0xc002b17, 0x34a51100, 0x10000036, 
+0x24846134, 0xafa20014, 0x8f46002c, 0x8f870120, 
+0x3c050009, 0xc002b3b, 0x34a51100, 0x10000036, 
 0x0, 0x8f420300, 0x8f43002c, 0x24420001, 
 0xaf420300, 0x8f420300, 0x24020001, 0xa34205c1, 
 0xaf430038, 0x3c010001, 0x370821, 0xa02040f1, 
@@ -5259,8 +5260,8 @@
 0xafa80018, 0x8f42010c, 0x40f809, 0x24c6001c, 
 0x14400011, 0x24020001, 0x3c010001, 0x370821, 
 0xa02240f2, 0x8f820124, 0xafa20010, 0x8f820128, 
-0x3c040001, 0x248461cc, 0xafa20014, 0x8f460044, 
-0x8f870120, 0x3c050009, 0xc002b17, 0x34a51300, 
+0x3c040001, 0x2484613c, 0xafa20014, 0x8f460044, 
+0x8f870120, 0x3c050009, 0xc002b3b, 0x34a51300, 
 0x1000000f, 0x0, 0x8f420304, 0x24420001, 
 0xaf420304, 0x8f420304, 0x8f420044, 0xaf42007c, 
 0x3c010001, 0x370821, 0xa02040f2, 0x10000004, 
@@ -5272,20 +5273,20 @@
 0x431024, 0xaf820060, 0x8f420000, 0x10400003, 
 0x0, 0x10000002, 0xaf80004c, 0xaf800048, 
 0x8fbf0020, 0x3e00008, 0x27bd0028, 0x3e00008, 
-0x0, 0x3c020001, 0x8c426e28, 0x27bdffa8, 
+0x0, 0x3c020001, 0x8c426da8, 0x27bdffa8, 
 0xafbf0050, 0xafbe004c, 0xafb50048, 0xafb30044, 
 0xafb20040, 0xafb1003c, 0xafb00038, 0x104000d5, 
 0x8f900044, 0x8f4200d0, 0x24430001, 0x2842000b, 
 0x144000e4, 0xaf4300d0, 0x8f420004, 0x30420002, 
 0x1440009c, 0xaf4000d0, 0x8f420004, 0x3c030001, 
-0x8c636e18, 0x34420002, 0xaf420004, 0x24020001, 
+0x8c636d98, 0x34420002, 0xaf420004, 0x24020001, 
 0x14620003, 0x3c020600, 0x10000002, 0x34423000, 
 0x34421000, 0xafa20020, 0x8f4a0018, 0xafaa0034, 
 0x27aa0020, 0xafaa002c, 0x8faa0034, 0x240200ff, 
 0x11420002, 0x1821, 0x25430001, 0x8c020228, 
 0x609821, 0x1662000e, 0x3c050009, 0x8f42033c, 
 0x24420001, 0xaf42033c, 0x8f42033c, 0x8c020228, 
-0x8fa70034, 0x3c040001, 0x2484619c, 0xafa00014, 
+0x8fa70034, 0x3c040001, 0x2484610c, 0xafa00014, 
 0xafa20010, 0x8fa60020, 0x10000070, 0x34a50500, 
 0x8faa0034, 0xa38c0, 0xf71021, 0x8fa30020, 
 0x8fa40024, 0xac4304c0, 0xac4404c4, 0x8f830054, 
@@ -5300,7 +5301,7 @@
 0x32a200ff, 0x54400018, 0xaf530018, 0x8f420378, 
 0x24420001, 0xaf420378, 0x8f420378, 0x8f820120, 
 0x8faa002c, 0x8fa70034, 0xafa20010, 0x8f820124, 
-0x3c040001, 0x248461a8, 0xafa20014, 0x8d460000, 
+0x3c040001, 0x24846118, 0xafa20014, 0x8d460000, 
 0x3c050009, 0x10000035, 0x34a50600, 0x8f420308, 
 0x24150001, 0x24420001, 0xaf420308, 0x8f420308, 
 0x1000001e, 0x32a200ff, 0x8f830054, 0x8f820054, 
@@ -5313,8 +5314,8 @@
 0x1440ffee, 0x0, 0x32a200ff, 0x14400011, 
 0x3c050009, 0x8f420378, 0x24420001, 0xaf420378, 
 0x8f420378, 0x8f820120, 0x8faa002c, 0x8fa70034, 
-0xafa20010, 0x8f820124, 0x3c040001, 0x248461b0, 
-0xafa20014, 0x8d460000, 0x34a50700, 0xc002b17, 
+0xafa20010, 0x8f820124, 0x3c040001, 0x24846120, 
+0xafa20014, 0x8d460000, 0x34a50700, 0xc002b3b, 
 0x0, 0x8f4202ec, 0x24420001, 0xaf4202ec, 
 0x8f4202ec, 0x8f420004, 0x30420001, 0x50400029, 
 0x36100040, 0x3c020400, 0x2c21024, 0x10400013, 
@@ -5337,19 +5338,19 @@
 0x8fbf0050, 0x8fbe004c, 0x8fb50048, 0x8fb30044, 
 0x8fb20040, 0x8fb1003c, 0x8fb00038, 0x3e00008, 
 0x27bd0058, 0x3e00008, 0x0, 0x3c020001, 
-0x8c426e28, 0x27bdffb0, 0xafbf0048, 0xafbe0044, 
+0x8c426da8, 0x27bdffb0, 0xafbf0048, 0xafbe0044, 
 0xafb50040, 0xafb3003c, 0xafb20038, 0xafb10034, 
 0x104000c7, 0xafb00030, 0x8f4200d0, 0x24430001, 
 0x2842000b, 0x144000da, 0xaf4300d0, 0x8f420004, 
 0x30420002, 0x14400097, 0xaf4000d0, 0x8f420004, 
-0x3c030001, 0x8c636e18, 0x34420002, 0xaf420004, 
+0x3c030001, 0x8c636d98, 0x34420002, 0xaf420004, 
 0x24020001, 0x14620003, 0x3c020600, 0x10000002, 
 0x34423000, 0x34421000, 0xafa20020, 0x1821, 
 0x8f5e0018, 0x27aa0020, 0x240200ff, 0x13c20002, 
 0xafaa002c, 0x27c30001, 0x8c020228, 0x609021, 
 0x1642000e, 0x1e38c0, 0x8f42033c, 0x24420001, 
 0xaf42033c, 0x8f42033c, 0x8c020228, 0x3c040001, 
-0x2484619c, 0x3c050009, 0xafa00014, 0xafa20010, 
+0x2484610c, 0x3c050009, 0xafa00014, 0xafa20010, 
 0x8fa60020, 0x1000006d, 0x34a50500, 0xf71021, 
 0x8fa30020, 0x8fa40024, 0xac4304c0, 0xac4404c4, 
 0x8f830054, 0x8f820054, 0x247003e8, 0x2021023, 
@@ -5363,7 +5364,7 @@
 0x0, 0x326200ff, 0x54400017, 0xaf520018, 
 0x8f420378, 0x24420001, 0xaf420378, 0x8f420378, 
 0x8f820120, 0x8faa002c, 0xafa20010, 0x8f820124, 
-0x3c040001, 0x248461a8, 0x3c050009, 0xafa20014, 
+0x3c040001, 0x24846118, 0x3c050009, 0xafa20014, 
 0x8d460000, 0x10000035, 0x34a50600, 0x8f420308, 
 0x24130001, 0x24420001, 0xaf420308, 0x8f420308, 
 0x1000001e, 0x326200ff, 0x8f830054, 0x8f820054, 
@@ -5376,43 +5377,43 @@
 0x1440ffee, 0x0, 0x326200ff, 0x14400011, 
 0x0, 0x8f420378, 0x24420001, 0xaf420378, 
 0x8f420378, 0x8f820120, 0x8faa002c, 0xafa20010, 
-0x8f820124, 0x3c040001, 0x248461b0, 0x3c050009, 
-0xafa20014, 0x8d460000, 0x34a50700, 0xc002b17, 
+0x8f820124, 0x3c040001, 0x24846120, 0x3c050009, 
+0xafa20014, 0x8d460000, 0x34a50700, 0xc002b3b, 
 0x3c03821, 0x8f4202ec, 0x24420001, 0xaf4202ec, 
 0x8f4202ec, 0x8f420004, 0x30420001, 0x10400018, 
 0x24040001, 0x8f420250, 0x8f430254, 0x8f4501b4, 
-0x3c010001, 0x14650006, 0xa0246d71, 0x8f420270, 
+0x3c010001, 0x14650006, 0xa0246cf1, 0x8f420270, 
 0x8f430274, 0x8f4401b8, 0x10640021, 0x0, 
-0x8f420250, 0x8f430254, 0x3c040001, 0x90846d70, 
+0x8f420250, 0x8f430254, 0x3c040001, 0x90846cf0, 
 0x8f460270, 0x8f470274, 0x38840001, 0xaf4301b4, 
-0xaf4701b8, 0x3c010001, 0x10000025, 0xa0246d70, 
-0x8f4200d4, 0x3c010001, 0xa0206d70, 0x24430001, 
+0xaf4701b8, 0x3c010001, 0x10000025, 0xa0246cf0, 
+0x8f4200d4, 0x3c010001, 0xa0206cf0, 0x24430001, 
 0x28420033, 0x1440001e, 0xaf4300d4, 0x3c020001, 
-0x90426d71, 0xaf4000d4, 0x10000017, 0x38420001, 
+0x90426cf1, 0xaf4000d4, 0x10000017, 0x38420001, 
 0x8f420004, 0x30420001, 0x10400008, 0x0, 
-0xc00567e, 0x2021, 0x3c010001, 0xa0206d71, 
-0x3c010001, 0x1000000e, 0xa0206d70, 0x8f4200d4, 
-0x3c010001, 0xa0206d70, 0x24430001, 0x284201f5, 
-0x14400007, 0xaf4300d4, 0x3c020001, 0x90426d71, 
-0xaf4000d4, 0x421026, 0x3c010001, 0xa0226d71, 
-0x3c030001, 0x8c636e18, 0x24020002, 0x1462000c, 
-0x3c030002, 0x3c030001, 0x90636d71, 0x24020001, 
-0x5462001f, 0x2021, 0x3c020001, 0x90426d70, 
+0xc00565a, 0x2021, 0x3c010001, 0xa0206cf1, 
+0x3c010001, 0x1000000e, 0xa0206cf0, 0x8f4200d4, 
+0x3c010001, 0xa0206cf0, 0x24430001, 0x284201f5, 
+0x14400007, 0xaf4300d4, 0x3c020001, 0x90426cf1, 
+0xaf4000d4, 0x421026, 0x3c010001, 0xa0226cf1, 
+0x3c030001, 0x8c636d98, 0x24020002, 0x1462000c, 
+0x3c030002, 0x3c030001, 0x90636cf1, 0x24020001, 
+0x5462001f, 0x2021, 0x3c020001, 0x90426cf0, 
 0x1443001b, 0x24040005, 0x10000019, 0x24040006, 
-0x3c020002, 0x8c429074, 0x431024, 0x1040000b, 
-0x24020001, 0x3c030001, 0x90636d71, 0x54620010, 
-0x2021, 0x3c020001, 0x90426d70, 0x1443000c, 
+0x3c020002, 0x8c428ff4, 0x431024, 0x1040000b, 
+0x24020001, 0x3c030001, 0x90636cf1, 0x54620010, 
+0x2021, 0x3c020001, 0x90426cf0, 0x1443000c, 
 0x24040003, 0x1000000a, 0x24040004, 0x3c030001, 
-0x90636d71, 0x14620006, 0x2021, 0x3c020001, 
-0x90426d70, 0x24040001, 0x50440001, 0x24040002, 
-0xc00567e, 0x0, 0x2402ff7f, 0x282a024, 
+0x90636cf1, 0x14620006, 0x2021, 0x3c020001, 
+0x90426cf0, 0x24040001, 0x50440001, 0x24040002, 
+0xc00565a, 0x0, 0x2402ff7f, 0x282a024, 
 0x8fbf0048, 0x8fbe0044, 0x8fb50040, 0x8fb3003c, 
 0x8fb20038, 0x8fb10034, 0x8fb00030, 0x3e00008, 
 0x27bd0050, 0x3e00008, 0x0, 0x3c020001, 
-0x8c426e28, 0x27bdffb0, 0xafbf0048, 0xafbe0044, 
+0x8c426da8, 0x27bdffb0, 0xafbf0048, 0xafbe0044, 
 0xafb50040, 0xafb3003c, 0xafb20038, 0xafb10034, 
 0x104000de, 0xafb00030, 0x8f4200d0, 0x3c040001, 
-0x8c846e18, 0x24430001, 0x2842000b, 0xaf4400e8, 
+0x8c846d98, 0x24430001, 0x2842000b, 0xaf4400e8, 
 0x144000fe, 0xaf4300d0, 0x8f420004, 0x30420002, 
 0x14400095, 0xaf4000d0, 0x8f420004, 0x34420002, 
 0xaf420004, 0x24020001, 0x14820003, 0x3c020600, 
@@ -5421,7 +5422,7 @@
 0x13c20002, 0xafaa002c, 0x27c30001, 0x8c020228, 
 0x609021, 0x1642000e, 0x1e38c0, 0x8f42033c, 
 0x24420001, 0xaf42033c, 0x8f42033c, 0x8c020228, 
-0x3c040001, 0x2484619c, 0x3c050009, 0xafa00014, 
+0x3c040001, 0x2484610c, 0x3c050009, 0xafa00014, 
 0xafa20010, 0x8fa60020, 0x1000006d, 0x34a50500, 
 0xf71021, 0x8fa30020, 0x8fa40024, 0xac4304c0, 
 0xac4404c4, 0x8f830054, 0x8f820054, 0x247003e8, 
@@ -5435,7 +5436,7 @@
 0x1440ffe9, 0x0, 0x326200ff, 0x54400017, 
 0xaf520018, 0x8f420378, 0x24420001, 0xaf420378, 
 0x8f420378, 0x8f820120, 0x8faa002c, 0xafa20010, 
-0x8f820124, 0x3c040001, 0x248461a8, 0x3c050009, 
+0x8f820124, 0x3c040001, 0x24846118, 0x3c050009, 
 0xafa20014, 0x8d460000, 0x10000035, 0x34a50600, 
 0x8f420308, 0x24130001, 0x24420001, 0xaf420308, 
 0x8f420308, 0x1000001e, 0x326200ff, 0x8f830054, 
@@ -5448,9 +5449,9 @@
 0x2c4203e9, 0x1440ffee, 0x0, 0x326200ff, 
 0x14400011, 0x0, 0x8f420378, 0x24420001, 
 0xaf420378, 0x8f420378, 0x8f820120, 0x8faa002c, 
-0xafa20010, 0x8f820124, 0x3c040001, 0x248461b0, 
+0xafa20010, 0x8f820124, 0x3c040001, 0x24846120, 
 0x3c050009, 0xafa20014, 0x8d460000, 0x34a50700, 
-0xc002b17, 0x3c03821, 0x8f4202ec, 0x24420001, 
+0xc002b3b, 0x3c03821, 0x8f4202ec, 0x24420001, 
 0xaf4202ec, 0x8f4202ec, 0x8f420004, 0x30420001, 
 0x10400033, 0x3c020400, 0x2c21024, 0x10400017, 
 0x0, 0x934205c0, 0x8f440250, 0x8f450254, 
@@ -5480,7 +5481,7 @@
 0x8f4300e8, 0x3042007f, 0xa34205c0, 0x24020001, 
 0x14620005, 0x0, 0x934405c0, 0x42102, 
 0x10000003, 0x348400f0, 0x934405c0, 0x3484000f, 
-0xc005664, 0x0, 0x2402ff7f, 0x282a024, 
+0xc005640, 0x0, 0x2402ff7f, 0x282a024, 
 0x8fbf0048, 0x8fbe0044, 0x8fb50040, 0x8fb3003c, 
 0x8fb20038, 0x8fb10034, 0x8fb00030, 0x3e00008, 
 0x27bd0050, 0x3e00008, 0x0, 0x27bdffb0, 
@@ -5533,7 +5534,7 @@
 0xafaa002c, 0x27c30001, 0x8c020228, 0x609021, 
 0x1642000e, 0x1e38c0, 0x8f42033c, 0x24420001, 
 0xaf42033c, 0x8f42033c, 0x8c020228, 0x3c040001, 
-0x2484619c, 0x3c050009, 0xafa00014, 0xafa20010, 
+0x2484610c, 0x3c050009, 0xafa00014, 0xafa20010, 
 0x8fa60020, 0x1000006b, 0x34a50500, 0xf71021, 
 0x8fa30020, 0x8fa40024, 0xac4304c0, 0xac4404c4, 
 0x8f830054, 0x8f820054, 0x247003e8, 0x2021023, 
@@ -5547,7 +5548,7 @@
 0x0, 0x326200ff, 0x54400017, 0xaf520018, 
 0x8f420378, 0x24420001, 0xaf420378, 0x8f420378, 
 0x8f820120, 0x8faa002c, 0xafa20010, 0x8f820124, 
-0x3c040001, 0x248461a8, 0x3c050009, 0xafa20014, 
+0x3c040001, 0x24846118, 0x3c050009, 0xafa20014, 
 0x8d460000, 0x10000033, 0x34a50600, 0x8f420308, 
 0x24130001, 0x24420001, 0xaf420308, 0x8f420308, 
 0x1000001c, 0x326200ff, 0x8f830054, 0x8f820054, 
@@ -5560,13 +5561,13 @@
 0x326200ff, 0x54400012, 0x24020001, 0x8f420378, 
 0x24420001, 0xaf420378, 0x8f420378, 0x8f820120, 
 0x8faa002c, 0xafa20010, 0x8f820124, 0x3c040001, 
-0x248461b0, 0x3c050009, 0xafa20014, 0x8d460000, 
-0x34a50700, 0xc002b17, 0x3c03821, 0x1021, 
+0x24846120, 0x3c050009, 0xafa20014, 0x8d460000, 
+0x34a50700, 0xc002b3b, 0x3c03821, 0x1021, 
 0x1440005b, 0x24020001, 0x10000065, 0x0, 
 0x8f510018, 0x240200ff, 0x12220002, 0x8021, 
 0x26300001, 0x8c020228, 0x1602000e, 0x1130c0, 
 0x8f42033c, 0x24420001, 0xaf42033c, 0x8f42033c, 
-0x8c020228, 0x3c040001, 0x24846184, 0x3c050009, 
+0x8c020228, 0x3c040001, 0x248460f4, 0x3c050009, 
 0xafa00014, 0xafa20010, 0x8fa60020, 0x1000003f, 
 0x34a50100, 0xd71021, 0x8fa30020, 0x8fa40024, 
 0xac4304c0, 0xac4404c4, 0xc01821, 0x8f440178, 
@@ -5575,15 +5576,15 @@
 0xafa80018, 0x8f48010c, 0x24070008, 0xa32821, 
 0xa3482b, 0x822021, 0x100f809, 0x892021, 
 0x1440000b, 0x24070008, 0x8f820120, 0xafa20010, 
-0x8f820124, 0x3c040001, 0x2484618c, 0x3c050009, 
+0x8f820124, 0x3c040001, 0x248460fc, 0x3c050009, 
 0xafa20014, 0x8fa60020, 0x1000001c, 0x34a50200, 
 0x8f440160, 0x8f450164, 0x8f43000c, 0xaf500018, 
 0x8f860120, 0x24020010, 0xafa20010, 0xafb00014, 
 0xafa30018, 0x8f42010c, 0x40f809, 0x24c6001c, 
 0x54400011, 0x24020001, 0x8f420340, 0x24420001, 
 0xaf420340, 0x8f420340, 0x8f820120, 0xafa20010, 
-0x8f820124, 0x3c040001, 0x24846194, 0x3c050009, 
-0xafa20014, 0x8fa60020, 0x34a50300, 0xc002b17, 
+0x8f820124, 0x3c040001, 0x24846104, 0x3c050009, 
+0xafa20014, 0x8fa60020, 0x34a50300, 0xc002b3b, 
 0x2203821, 0x1021, 0x1040000d, 0x24020001, 
 0x8f4202e8, 0xa34005c6, 0xaf4001b0, 0x24420001, 
 0xaf4202e8, 0x8f4202e8, 0x8ee20150, 0x24420001, 
@@ -5603,11 +5604,11 @@
 0x14620005, 0x0, 0x8f430130, 0x8f8200b4, 
 0x10620010, 0x0, 0x8f820104, 0xaf420128, 
 0x8f8200b4, 0x8f430128, 0xaf420130, 0xafa30010, 
-0x8f420130, 0x3c040001, 0x248461d4, 0xafa20014, 
+0x8f420130, 0x3c040001, 0x24846144, 0xafa20014, 
 0x8f86011c, 0x8f8700b0, 0x3c050005, 0x10000031, 
 0x34a50900, 0x8f420128, 0xafa20010, 0x8f420130, 
-0x3c040001, 0x248461e0, 0xafa20014, 0x8f86011c, 
-0x8f8700b0, 0x3c050005, 0xc002b17, 0x34a51000, 
+0x3c040001, 0x24846150, 0xafa20014, 0x8f86011c, 
+0x8f8700b0, 0x3c050005, 0xc002b3b, 0x34a51000, 
 0x8f82011c, 0x34420002, 0xaf82011c, 0x8f830104, 
 0x8f8200b0, 0x34420001, 0xaf8200b0, 0x24020008, 
 0xaf830104, 0xafa20010, 0xafa00014, 0x8f42000c, 
@@ -5615,9 +5616,9 @@
 0x26e60028, 0x40f809, 0x24070400, 0x8f82011c, 
 0x2403fffd, 0x431024, 0xaf82011c, 0x8ee201dc, 
 0x24420001, 0xaee201dc, 0x8ee201dc, 0x8f420128, 
-0xafa20010, 0x8f420130, 0x3c040001, 0x248461ec, 
+0xafa20010, 0x8f420130, 0x3c040001, 0x2484615c, 
 0xafa20014, 0x8f86011c, 0x8f8700b0, 0x3c050005, 
-0x34a51100, 0xc002b17, 0x0, 0x8f8200a0, 
+0x34a51100, 0xc002b3b, 0x0, 0x8f8200a0, 
 0x30420004, 0x10400069, 0x0, 0x8f43012c, 
 0x8f820124, 0x14620005, 0x0, 0x8f430134, 
 0x8f8200a4, 0x10620006, 0x0, 0x8f820124, 
@@ -5630,21 +5631,21 @@
 0x0, 0x8f430134, 0x8f8200a4, 0x10620010, 
 0x0, 0x8f820124, 0xaf42012c, 0x8f8200a4, 
 0x8f43012c, 0xaf420134, 0xafa30010, 0x8f420134, 
-0x3c040001, 0x248461f8, 0xafa20014, 0x8f86011c, 
+0x3c040001, 0x24846168, 0xafa20014, 0x8f86011c, 
 0x8f8700a0, 0x3c050005, 0x10000032, 0x34a51200, 
 0x8f42012c, 0xafa20010, 0x8f420134, 0x3c040001, 
-0x24846204, 0xafa20014, 0x8f86011c, 0x8f8700a0, 
-0x3c050005, 0xc002b17, 0x34a51300, 0x8f82011c, 
+0x24846174, 0xafa20014, 0x8f86011c, 0x8f8700a0, 
+0x3c050005, 0xc002b3b, 0x34a51300, 0x8f82011c, 
 0x34420002, 0xaf82011c, 0x8f830124, 0x8f8200a0, 
 0x34420001, 0xaf8200a0, 0x24020080, 0xaf830124, 
 0xafa20010, 0xafa00014, 0x8f420014, 0x8c040208, 
 0x8c05020c, 0xafa20018, 0x8f420108, 0x3c060001, 
-0x24c66f54, 0x40f809, 0x24070004, 0x8f82011c, 
+0x24c66ed8, 0x40f809, 0x24070004, 0x8f82011c, 
 0x2403fffd, 0x431024, 0xaf82011c, 0x8ee201dc, 
 0x24420001, 0xaee201dc, 0x8ee201dc, 0x8f42012c, 
-0xafa20010, 0x8f420134, 0x3c040001, 0x24846210, 
+0xafa20010, 0x8f420134, 0x3c040001, 0x24846180, 
 0xafa20014, 0x8f86011c, 0x8f8700a0, 0x3c050005, 
-0x34a51400, 0xc002b17, 0x0, 0x8fbf0020, 
+0x34a51400, 0xc002b3b, 0x0, 0x8fbf0020, 
 0x3e00008, 0x27bd0028, 0x3c081000, 0x24070001, 
 0x3c060080, 0x3c050100, 0x8f820070, 0x481024, 
 0x1040fffd, 0x0, 0x8f820054, 0x24420005, 
@@ -5712,8 +5713,8 @@
 0xaf80004c, 0x1000006a, 0xaf800048, 0x30c20001, 
 0x10400004, 0x24020001, 0xaf820064, 0x10000064, 
 0x0, 0x30c20002, 0x1440000b, 0x3c050003, 
-0x3c040001, 0x248462d4, 0x34a50500, 0x3821, 
-0xafa00010, 0xc002b17, 0xafa00014, 0x2402ffc0, 
+0x3c040001, 0x24846244, 0x34a50500, 0x3821, 
+0xafa00010, 0xc002b3b, 0xafa00014, 0x2402ffc0, 
 0x10000057, 0xaf820064, 0x8c05022c, 0x8c02010c, 
 0x10a20048, 0x51080, 0x8c460300, 0x24a20001, 
 0x3045003f, 0x24020003, 0xac05022c, 0x61e02, 
@@ -5732,7 +5733,7 @@
 0xaf800048, 0x8f820048, 0x1040fffd, 0x0, 
 0x8f820060, 0x34420100, 0xaf820060, 0x8f420000, 
 0x10400003, 0x0, 0x10000006, 0xaf80004c, 
-0x10000004, 0xaf800048, 0xc00217e, 0xc02021, 
+0x10000004, 0xaf800048, 0xc002196, 0xc02021, 
 0x402821, 0x8c02010c, 0x14a20002, 0x24020002, 
 0xaf820064, 0x8f820064, 0x30420002, 0x14400004, 
 0x0, 0x8c02010c, 0x14a2ffac, 0x0, 
@@ -5740,196 +5741,199 @@
 0x0, 0x27bdffa0, 0xafb00040, 0x808021, 
 0x101602, 0x2442ffff, 0x304300ff, 0x2c620013, 
 0xafbf0058, 0xafbe0054, 0xafb50050, 0xafb3004c, 
-0xafb20048, 0xafb10044, 0x104001ec, 0xafa50034, 
-0x31080, 0x3c010001, 0x220821, 0x8c226318, 
+0xafb20048, 0xafb10044, 0x104001f3, 0xafa50034, 
+0x31080, 0x3c010001, 0x220821, 0x8c226288, 
 0x400008, 0x0, 0x101302, 0x30440fff, 
-0x24020001, 0x10820005, 0x24020002, 0x1082000a, 
-0x2402fffe, 0x10000021, 0x3c050003, 0x8f430004, 
-0x3c020001, 0x8c426f80, 0xaf440200, 0xaf440204, 
-0x10000007, 0x34630001, 0x8f430004, 0xaf440200, 
-0xaf440204, 0x621824, 0x3c020001, 0x2442c9c8, 
+0x24020001, 0x10820005, 0x24020002, 0x1082000c, 
+0x2402fffe, 0x10000024, 0x3c050003, 0x8f430004, 
+0x3c020001, 0x8c426f04, 0xaf440200, 0xaf440204, 
+0x3c040001, 0x8c846e80, 0x10000009, 0x34630001, 
+0x8f430004, 0xaf440200, 0xaf440204, 0x3c040001, 
+0x8c846e80, 0x621824, 0x3c020001, 0x2442ca28, 
 0x21100, 0x21182, 0xaf430004, 0x3c030800, 
-0x431025, 0x3c010000, 0xac224138, 0x8f840054, 
-0x41442, 0x41c82, 0x431021, 0x41cc2, 
-0x431023, 0x41d02, 0x431021, 0x41d42, 
-0x431023, 0x10000009, 0xaf420208, 0x3c040001, 
-0x248462e0, 0x34a51000, 0x2003021, 0x3821, 
-0xafa00010, 0xc002b17, 0xafa00014, 0x8f4202a0, 
-0x24420001, 0xaf4202a0, 0x1000021b, 0x8f4202a0, 
-0x27b00028, 0x2002021, 0x24050210, 0xc002b9b, 
-0x24060008, 0xc0024f4, 0x2002021, 0x10000212, 
-0x0, 0x8faa0034, 0x27a40028, 0xa1880, 
-0x25420001, 0x3042003f, 0xafa20034, 0x8c650300, 
-0x8faa0034, 0x21080, 0x8c430300, 0x25420001, 
-0x3042003f, 0xafa20034, 0xac02022c, 0xafa50028, 
-0xc0024f4, 0xafa3002c, 0x100001ff, 0x0, 
-0x27b00028, 0x2002021, 0x24050210, 0xc002b9b, 
-0x24060008, 0xc002633, 0x2002021, 0x100001f6, 
-0x0, 0x8faa0034, 0x27a40028, 0xa1880, 
-0x25420001, 0x3042003f, 0xafa20034, 0x8c650300, 
-0x8faa0034, 0x21080, 0x8c430300, 0x25420001, 
-0x3042003f, 0xafa20034, 0xac02022c, 0xafa50028, 
-0xc002633, 0xafa3002c, 0x100001e3, 0x0, 
-0x101302, 0x30430fff, 0x24020001, 0x10620005, 
-0x24020002, 0x1062001e, 0x3c020002, 0x10000033, 
-0x3c050003, 0x3c030002, 0x2c31024, 0x54400037, 
-0x2c3b025, 0x8f820228, 0x3c010001, 0x370821, 
-0xac2238d8, 0x8f82022c, 0x3c010001, 0x370821, 
-0xac2238dc, 0x8f820230, 0x3c010001, 0x370821, 
-0xac2238e0, 0x8f820234, 0x3c010001, 0x370821, 
-0xac2238e4, 0x2402ffff, 0xaf820228, 0xaf82022c, 
-0xaf820230, 0xaf820234, 0x10000020, 0x2c3b025, 
-0x2c21024, 0x10400012, 0x3c02fffd, 0x3c020001, 
-0x571021, 0x8c4238d8, 0xaf820228, 0x3c020001, 
-0x571021, 0x8c4238dc, 0xaf82022c, 0x3c020001, 
-0x571021, 0x8c4238e0, 0xaf820230, 0x3c020001, 
-0x571021, 0x8c4238e4, 0xaf820234, 0x3c02fffd, 
-0x3442ffff, 0x10000009, 0x2c2b024, 0x3c040001, 
-0x248462ec, 0x34a51100, 0x2003021, 0x3821, 
-0xafa00010, 0xc002b17, 0xafa00014, 0x8f4202cc, 
-0x24420001, 0xaf4202cc, 0x1000019b, 0x8f4202cc, 
-0x101302, 0x30450fff, 0x24020001, 0x10a20005, 
-0x24020002, 0x10a2000d, 0x3c0408ff, 0x10000014, 
-0x3c050003, 0x3c0208ff, 0x3442ffff, 0x8f830220, 
-0x3c040004, 0x2c4b025, 0x621824, 0x34630008, 
-0xaf830220, 0x10000012, 0xaf450298, 0x3484fff7, 
-0x3c03fffb, 0x8f820220, 0x3463ffff, 0x2c3b024, 
-0x441024, 0xaf820220, 0x10000009, 0xaf450298, 
-0x3c040001, 0x248462f8, 0x34a51200, 0x2003021, 
-0x3821, 0xafa00010, 0xc002b17, 0xafa00014, 
-0x8f4202bc, 0x24420001, 0xaf4202bc, 0x10000172, 
-0x8f4202bc, 0x27840208, 0x24050200, 0xc002b9b, 
-0x24060008, 0x27440224, 0x24050200, 0xc002b9b, 
-0x24060008, 0x8f4202c4, 0x24420001, 0xaf4202c4, 
-0x10000165, 0x8f4202c4, 0x101302, 0x30430fff, 
-0x24020001, 0x10620011, 0x28620002, 0x50400005, 
-0x24020002, 0x10600007, 0x0, 0x10000017, 
-0x0, 0x1062000f, 0x0, 0x10000013, 
-0x0, 0x8c060248, 0x2021, 0xc005134, 
-0x24050004, 0x10000007, 0x0, 0x8c060248, 
-0x2021, 0xc005134, 0x24050004, 0x10000010, 
-0x0, 0x8c06024c, 0x2021, 0xc005134, 
-0x24050001, 0x1000000a, 0x0, 0x3c040001, 
-0x24846304, 0x3c050003, 0x34a51300, 0x2003021, 
-0x3821, 0xafa00010, 0xc002b17, 0xafa00014, 
-0x8f4202c0, 0x24420001, 0xaf4202c0, 0x10000136, 
-0x8f4202c0, 0xc002407, 0x0, 0x10000132, 
-0x0, 0x24020001, 0xa34205c5, 0x24100100, 
-0x8f4401a8, 0x8f4501ac, 0xafb00010, 0xafa00014, 
-0x8f420014, 0xafa20018, 0x8f420108, 0x26e60028, 
-0x40f809, 0x24070400, 0x1040fff5, 0x0, 
-0x10000121, 0x0, 0x3c02ffff, 0x34427fff, 
-0x2c2b024, 0x1821, 0x3c020900, 0xaf400058, 
-0xaf40005c, 0xaf400060, 0xaf400064, 0xaf400360, 
-0xafa20020, 0x8f5e0018, 0x27aa0020, 0x240200ff, 
-0x13c20002, 0xafaa003c, 0x27c30001, 0x8c020228, 
-0x609021, 0x1642000e, 0x1e38c0, 0x8f42033c, 
-0x24420001, 0xaf42033c, 0x8f42033c, 0x8c020228, 
-0x3c040001, 0x2484629c, 0x3c050009, 0xafa00014, 
-0xafa20010, 0x8fa60020, 0x1000006b, 0x34a50500, 
-0xf71021, 0x8fa30020, 0x8fa40024, 0xac4304c0, 
-0xac4404c4, 0x8f830054, 0x8f820054, 0x247003e8, 
-0x2021023, 0x2c4203e9, 0x1040001b, 0x9821, 
-0xe08821, 0x263504c0, 0x8f440178, 0x8f45017c, 
-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, 0x8f420378, 0x24420001, 0xaf420378, 
-0x8f420378, 0x8f820120, 0x8faa003c, 0xafa20010, 
-0x8f820124, 0x3c040001, 0x248462a8, 0x3c050009, 
-0xafa20014, 0x8d460000, 0x10000033, 0x34a50600, 
-0x8f420308, 0x24130001, 0x24420001, 0xaf420308, 
-0x8f420308, 0x1000001c, 0x326200ff, 0x8f830054, 
-0x8f820054, 0x247003e8, 0x2021023, 0x2c4203e9, 
-0x10400014, 0x9821, 0x24110010, 0x8f42000c, 
-0x8f440160, 0x8f450164, 0x8f860120, 0xafb10010, 
-0xafb20014, 0xafa20018, 0x8f42010c, 0x24070008, 
-0x40f809, 0x24c6001c, 0x1440ffe5, 0x0, 
-0x8f820054, 0x2021023, 0x2c4203e9, 0x1440ffef, 
-0x0, 0x326200ff, 0x14400011, 0x0, 
+0x431025, 0xac820038, 0x8f840054, 0x41442, 
+0x41c82, 0x431021, 0x41cc2, 0x431023, 
+0x41d02, 0x431021, 0x41d42, 0x431023, 
+0x10000009, 0xaf420208, 0x3c040001, 0x24846250, 
+0x34a51000, 0x2003021, 0x3821, 0xafa00010, 
+0xc002b3b, 0xafa00014, 0x8f4202a0, 0x24420001, 
+0xaf4202a0, 0x1000021f, 0x8f4202a0, 0x27b00028, 
+0x2002021, 0x24050210, 0xc002bbf, 0x24060008, 
+0xc002518, 0x2002021, 0x10000216, 0x0, 
+0x8faa0034, 0x27a40028, 0xa1880, 0x25420001, 
+0x3042003f, 0xafa20034, 0x8c650300, 0x8faa0034, 
+0x21080, 0x8c430300, 0x25420001, 0x3042003f, 
+0xafa20034, 0xac02022c, 0xafa50028, 0xc002518, 
+0xafa3002c, 0x10000203, 0x0, 0x27b00028, 
+0x2002021, 0x24050210, 0xc002bbf, 0x24060008, 
+0xc002657, 0x2002021, 0x100001fa, 0x0, 
+0x8faa0034, 0x27a40028, 0xa1880, 0x25420001, 
+0x3042003f, 0xafa20034, 0x8c650300, 0x8faa0034, 
+0x21080, 0x8c430300, 0x25420001, 0x3042003f, 
+0xafa20034, 0xac02022c, 0xafa50028, 0xc002657, 
+0xafa3002c, 0x100001e7, 0x0, 0x101302, 
+0x30430fff, 0x24020001, 0x10620005, 0x24020002, 
+0x1062001e, 0x3c020002, 0x10000033, 0x3c050003, 
+0x3c030002, 0x2c31024, 0x54400037, 0x2c3b025, 
+0x8f820228, 0x3c010001, 0x370821, 0xac2238d8, 
+0x8f82022c, 0x3c010001, 0x370821, 0xac2238dc, 
+0x8f820230, 0x3c010001, 0x370821, 0xac2238e0, 
+0x8f820234, 0x3c010001, 0x370821, 0xac2238e4, 
+0x2402ffff, 0xaf820228, 0xaf82022c, 0xaf820230, 
+0xaf820234, 0x10000020, 0x2c3b025, 0x2c21024, 
+0x10400012, 0x3c02fffd, 0x3c020001, 0x571021, 
+0x8c4238d8, 0xaf820228, 0x3c020001, 0x571021, 
+0x8c4238dc, 0xaf82022c, 0x3c020001, 0x571021, 
+0x8c4238e0, 0xaf820230, 0x3c020001, 0x571021, 
+0x8c4238e4, 0xaf820234, 0x3c02fffd, 0x3442ffff, 
+0x10000009, 0x2c2b024, 0x3c040001, 0x2484625c, 
+0x34a51100, 0x2003021, 0x3821, 0xafa00010, 
+0xc002b3b, 0xafa00014, 0x8f4202cc, 0x24420001, 
+0xaf4202cc, 0x1000019f, 0x8f4202cc, 0x101302, 
+0x30450fff, 0x24020001, 0x10a20005, 0x24020002, 
+0x10a2000d, 0x3c0408ff, 0x10000014, 0x3c050003, 
+0x3c0208ff, 0x3442ffff, 0x8f830220, 0x3c040004, 
+0x2c4b025, 0x621824, 0x34630008, 0xaf830220, 
+0x10000012, 0xaf450298, 0x3484fff7, 0x3c03fffb, 
+0x8f820220, 0x3463ffff, 0x2c3b024, 0x441024, 
+0xaf820220, 0x10000009, 0xaf450298, 0x3c040001, 
+0x24846268, 0x34a51200, 0x2003021, 0x3821, 
+0xafa00010, 0xc002b3b, 0xafa00014, 0x8f4202bc, 
+0x24420001, 0xaf4202bc, 0x10000176, 0x8f4202bc, 
+0x27840208, 0x24050200, 0xc002bbf, 0x24060008, 
+0x27440224, 0x24050200, 0xc002bbf, 0x24060008, 
+0x8f4202c4, 0x24420001, 0xaf4202c4, 0x10000169, 
+0x8f4202c4, 0x101302, 0x30430fff, 0x24020001, 
+0x10620011, 0x28620002, 0x50400005, 0x24020002, 
+0x10600007, 0x0, 0x10000017, 0x0, 
+0x1062000f, 0x0, 0x10000013, 0x0, 
+0x8c060248, 0x2021, 0xc005104, 0x24050004, 
+0x10000007, 0x0, 0x8c060248, 0x2021, 
+0xc005104, 0x24050004, 0x10000010, 0x0, 
+0x8c06024c, 0x2021, 0xc005104, 0x24050001, 
+0x1000000a, 0x0, 0x3c040001, 0x24846274, 
+0x3c050003, 0x34a51300, 0x2003021, 0x3821, 
+0xafa00010, 0xc002b3b, 0xafa00014, 0x8f4202c0, 
+0x24420001, 0xaf4202c0, 0x1000013a, 0x8f4202c0, 
+0xc002426, 0x0, 0x10000136, 0x0, 
+0x24020001, 0xa34205c5, 0x24100100, 0x8f4401a8, 
+0x8f4501ac, 0xafb00010, 0xafa00014, 0x8f420014, 
+0xafa20018, 0x8f420108, 0x26e60028, 0x40f809, 
+0x24070400, 0x1040fff5, 0x0, 0x10000125, 
+0x0, 0x3c03ffff, 0x34637fff, 0x8f420368, 
+0x8f440360, 0x2c3b024, 0x1821, 0xaf400058, 
+0xaf40005c, 0xaf400060, 0xaf400064, 0x441023, 
+0xaf420368, 0x3c020900, 0xaf400360, 0xafa20020, 
+0x8f5e0018, 0x27aa0020, 0x240200ff, 0x13c20002, 
+0xafaa003c, 0x27c30001, 0x8c020228, 0x609021, 
+0x1642000e, 0x1e38c0, 0x8f42033c, 0x24420001, 
+0xaf42033c, 0x8f42033c, 0x8c020228, 0x3c040001, 
+0x2484620c, 0x3c050009, 0xafa00014, 0xafa20010, 
+0x8fa60020, 0x1000006b, 0x34a50500, 0xf71021, 
+0x8fa30020, 0x8fa40024, 0xac4304c0, 0xac4404c4, 
+0x8f830054, 0x8f820054, 0x247003e8, 0x2021023, 
+0x2c4203e9, 0x1040001b, 0x9821, 0xe08821, 
+0x263504c0, 0x8f440178, 0x8f45017c, 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, 
 0x8f420378, 0x24420001, 0xaf420378, 0x8f420378, 
 0x8f820120, 0x8faa003c, 0xafa20010, 0x8f820124, 
-0x3c040001, 0x248462b0, 0x3c050009, 0xafa20014, 
-0x8d460000, 0x34a50700, 0xc002b17, 0x3c03821, 
-0x8f4202b0, 0x24420001, 0xaf4202b0, 0x8f4202b0, 
-0x8f4202f8, 0x24420001, 0xaf4202f8, 0x1000008a, 
-0x8f4202f8, 0x8c02025c, 0x27440224, 0xaf4201f0, 
-0x8c020260, 0x24050200, 0x24060008, 0xc002b9b, 
-0xaf4201f8, 0x8f820220, 0x30420008, 0x14400002, 
-0x24020001, 0x24020002, 0xaf420298, 0x8f4202ac, 
-0x24420001, 0xaf4202ac, 0x10000077, 0x8f4202ac, 
-0x3c0200ff, 0x3442ffff, 0x2021824, 0x32c20180, 
-0x14400006, 0x3402fffb, 0x43102b, 0x14400003, 
-0x0, 0x1000006c, 0xaf4300bc, 0x3c040001, 
-0x24846310, 0x3c050003, 0x34a51500, 0x2003021, 
-0x3821, 0xafa00010, 0xc002b17, 0xafa00014, 
-0x3c020700, 0x34421000, 0x101e02, 0x621825, 
-0xafa30020, 0x8f510018, 0x240200ff, 0x12220002, 
-0x8021, 0x26300001, 0x8c020228, 0x1602000e, 
-0x1130c0, 0x8f42033c, 0x24420001, 0xaf42033c, 
-0x8f42033c, 0x8c020228, 0x3c040001, 0x24846284, 
-0x3c050009, 0xafa00014, 0xafa20010, 0x8fa60020, 
-0x1000003f, 0x34a50100, 0xd71021, 0x8fa30020, 
-0x8fa40024, 0xac4304c0, 0xac4404c4, 0xc01821, 
-0x8f440178, 0x8f45017c, 0x1021, 0x24070004, 
-0xafa70010, 0xafb00014, 0x8f48000c, 0x24c604c0, 
-0x2e63021, 0xafa80018, 0x8f48010c, 0x24070008, 
-0xa32821, 0xa3482b, 0x822021, 0x100f809, 
-0x892021, 0x1440000b, 0x24070008, 0x8f820120, 
-0xafa20010, 0x8f820124, 0x3c040001, 0x2484628c, 
-0x3c050009, 0xafa20014, 0x8fa60020, 0x1000001c, 
-0x34a50200, 0x8f440160, 0x8f450164, 0x8f43000c, 
-0xaf500018, 0x8f860120, 0x24020010, 0xafa20010, 
-0xafb00014, 0xafa30018, 0x8f42010c, 0x40f809, 
-0x24c6001c, 0x14400010, 0x0, 0x8f420340, 
-0x24420001, 0xaf420340, 0x8f420340, 0x8f820120, 
-0xafa20010, 0x8f820124, 0x3c040001, 0x24846294, 
-0x3c050009, 0xafa20014, 0x8fa60020, 0x34a50300, 
-0xc002b17, 0x2203821, 0x8f4202e0, 0x24420001, 
-0xaf4202e0, 0x8f4202e0, 0x8f4202f0, 0x24420001, 
-0xaf4202f0, 0x8f4202f0, 0x8fa20034, 0x8fbf0058, 
-0x8fbe0054, 0x8fb50050, 0x8fb3004c, 0x8fb20048, 
-0x8fb10044, 0x8fb00040, 0x3e00008, 0x27bd0060, 
-0x27bdfff8, 0x2408ffff, 0x10a00014, 0x4821, 
-0x3c0aedb8, 0x354a8320, 0x90870000, 0x24840001, 
-0x3021, 0x1071026, 0x30420001, 0x10400002, 
-0x81842, 0x6a1826, 0x604021, 0x24c60001, 
-0x2cc20008, 0x1440fff7, 0x73842, 0x25290001, 
-0x125102b, 0x1440fff0, 0x0, 0x1001021, 
-0x3e00008, 0x27bd0008, 0x27bdffb8, 0xafbf0040, 
-0xafbe003c, 0xafb50038, 0xafb30034, 0xafb20030, 
-0xafb1002c, 0xafb00028, 0x8f870220, 0xafa7001c, 
-0x8f870200, 0xafa70024, 0x8f820220, 0x3c0308ff, 
-0x3463ffff, 0x431024, 0x34420004, 0xaf820220, 
-0x8f820200, 0x3c03c0ff, 0x3463ffff, 0x431024, 
-0x34420004, 0xaf820200, 0x8f53035c, 0x8f550360, 
-0x8f5e0364, 0x8f470368, 0xafa70014, 0x8f4202d0, 
-0x274401c0, 0x24420001, 0xaf4202d0, 0x8f5002d0, 
-0x8f510204, 0x8f520200, 0xc002b84, 0x24050400, 
-0xaf53035c, 0xaf550360, 0xaf5e0364, 0x8fa70014, 
-0xaf470368, 0xaf5002d0, 0xaf510204, 0xaf520200, 
+0x3c040001, 0x24846218, 0x3c050009, 0xafa20014, 
+0x8d460000, 0x10000033, 0x34a50600, 0x8f420308, 
+0x24130001, 0x24420001, 0xaf420308, 0x8f420308, 
+0x1000001c, 0x326200ff, 0x8f830054, 0x8f820054, 
+0x247003e8, 0x2021023, 0x2c4203e9, 0x10400014, 
+0x9821, 0x24110010, 0x8f42000c, 0x8f440160, 
+0x8f450164, 0x8f860120, 0xafb10010, 0xafb20014, 
+0xafa20018, 0x8f42010c, 0x24070008, 0x40f809, 
+0x24c6001c, 0x1440ffe5, 0x0, 0x8f820054, 
+0x2021023, 0x2c4203e9, 0x1440ffef, 0x0, 
+0x326200ff, 0x14400011, 0x0, 0x8f420378, 
+0x24420001, 0xaf420378, 0x8f420378, 0x8f820120, 
+0x8faa003c, 0xafa20010, 0x8f820124, 0x3c040001, 
+0x24846220, 0x3c050009, 0xafa20014, 0x8d460000, 
+0x34a50700, 0xc002b3b, 0x3c03821, 0x8f4202b0, 
+0x24420001, 0xaf4202b0, 0x8f4202b0, 0x8f4202f8, 
+0x24420001, 0xaf4202f8, 0x1000008a, 0x8f4202f8, 
 0x8c02025c, 0x27440224, 0xaf4201f0, 0x8c020260, 
-0x24050200, 0x24060008, 0xaf4201f8, 0x24020006, 
-0xc002b9b, 0xaf4201f4, 0x3c023b9a, 0x3442ca00, 
-0xaf4201fc, 0x240203e8, 0x24040002, 0x24030001, 
-0xaf420294, 0xaf440290, 0xaf43029c, 0x8f820220, 
-0x30420008, 0x10400004, 0x0, 0xaf430298, 
-0x10000003, 0x3021, 0xaf440298, 0x3021, 
-0x3c030001, 0x661821, 0x90636d80, 0x3461021, 
-0x24c60001, 0xa043022c, 0x2cc2000f, 0x1440fff8, 
-0x3461821, 0x24c60001, 0x8f820040, 0x24040080, 
-0x24050080, 0x21702, 0x24420030, 0xa062022c, 
-0x3461021, 0xc002b84, 0xa040022c, 0x8fa7001c, 
-0x30e20004, 0x14400006, 0x0, 0x8f820220, 
-0x3c0308ff, 0x3463fffb, 0x431024, 0xaf820220, 
-0x8fa70024, 0x30e20004, 0x14400006, 0x0, 
-0x8f820200, 0x3c03c0ff, 0x3463fffb, 0x431024, 
-0xaf820200, 0x8fbf0040, 0x8fbe003c, 0x8fb50038, 
-0x8fb30034, 0x8fb20030, 0x8fb1002c, 0x8fb00028, 
-0x3e00008, 0x27bd0048, 0x0, 0xaf400104, 
+0x24050200, 0x24060008, 0xc002bbf, 0xaf4201f8, 
+0x8f820220, 0x30420008, 0x14400002, 0x24020001, 
+0x24020002, 0xaf420298, 0x8f4202ac, 0x24420001, 
+0xaf4202ac, 0x10000077, 0x8f4202ac, 0x3c0200ff, 
+0x3442ffff, 0x2021824, 0x32c20180, 0x14400006, 
+0x3402fffb, 0x43102b, 0x14400003, 0x0, 
+0x1000006c, 0xaf4300bc, 0x3c040001, 0x24846280, 
+0x3c050003, 0x34a51500, 0x2003021, 0x3821, 
+0xafa00010, 0xc002b3b, 0xafa00014, 0x3c020700, 
+0x34421000, 0x101e02, 0x621825, 0xafa30020, 
+0x8f510018, 0x240200ff, 0x12220002, 0x8021, 
+0x26300001, 0x8c020228, 0x1602000e, 0x1130c0, 
+0x8f42033c, 0x24420001, 0xaf42033c, 0x8f42033c, 
+0x8c020228, 0x3c040001, 0x248461f4, 0x3c050009, 
+0xafa00014, 0xafa20010, 0x8fa60020, 0x1000003f, 
+0x34a50100, 0xd71021, 0x8fa30020, 0x8fa40024, 
+0xac4304c0, 0xac4404c4, 0xc01821, 0x8f440178, 
+0x8f45017c, 0x1021, 0x24070004, 0xafa70010, 
+0xafb00014, 0x8f48000c, 0x24c604c0, 0x2e63021, 
+0xafa80018, 0x8f48010c, 0x24070008, 0xa32821, 
+0xa3482b, 0x822021, 0x100f809, 0x892021, 
+0x1440000b, 0x24070008, 0x8f820120, 0xafa20010, 
+0x8f820124, 0x3c040001, 0x248461fc, 0x3c050009, 
+0xafa20014, 0x8fa60020, 0x1000001c, 0x34a50200, 
+0x8f440160, 0x8f450164, 0x8f43000c, 0xaf500018, 
+0x8f860120, 0x24020010, 0xafa20010, 0xafb00014, 
+0xafa30018, 0x8f42010c, 0x40f809, 0x24c6001c, 
+0x14400010, 0x0, 0x8f420340, 0x24420001, 
+0xaf420340, 0x8f420340, 0x8f820120, 0xafa20010, 
+0x8f820124, 0x3c040001, 0x24846204, 0x3c050009, 
+0xafa20014, 0x8fa60020, 0x34a50300, 0xc002b3b, 
+0x2203821, 0x8f4202e0, 0x24420001, 0xaf4202e0, 
+0x8f4202e0, 0x8f4202f0, 0x24420001, 0xaf4202f0, 
+0x8f4202f0, 0x8fa20034, 0x8fbf0058, 0x8fbe0054, 
+0x8fb50050, 0x8fb3004c, 0x8fb20048, 0x8fb10044, 
+0x8fb00040, 0x3e00008, 0x27bd0060, 0x27bdfff8, 
+0x2408ffff, 0x10a00014, 0x4821, 0x3c0aedb8, 
+0x354a8320, 0x90870000, 0x24840001, 0x3021, 
+0x1071026, 0x30420001, 0x10400002, 0x81842, 
+0x6a1826, 0x604021, 0x24c60001, 0x2cc20008, 
+0x1440fff7, 0x73842, 0x25290001, 0x125102b, 
+0x1440fff0, 0x0, 0x1001021, 0x3e00008, 
+0x27bd0008, 0x27bdffb0, 0xafbf0048, 0xafbe0044, 
+0xafb50040, 0xafb3003c, 0xafb20038, 0xafb10034, 
+0xafb00030, 0x8f870220, 0xafa70024, 0x8f870200, 
+0xafa7002c, 0x8f820220, 0x3c0308ff, 0x3463ffff, 
+0x431024, 0x34420004, 0xaf820220, 0x8f820200, 
+0x3c03c0ff, 0x3463ffff, 0x431024, 0x34420004, 
+0xaf820200, 0x8f530358, 0x8f55035c, 0x8f5e0360, 
+0x8f470364, 0xafa70014, 0x8f470368, 0xafa7001c, 
+0x8f4202d0, 0x274401c0, 0x24420001, 0xaf4202d0, 
+0x8f5002d0, 0x8f510204, 0x8f520200, 0xc002ba8, 
+0x24050400, 0xaf530358, 0xaf55035c, 0xaf5e0360, 
+0x8fa70014, 0xaf470364, 0x8fa7001c, 0xaf470368, 
+0xaf5002d0, 0xaf510204, 0xaf520200, 0x8c02025c, 
+0x27440224, 0xaf4201f0, 0x8c020260, 0x24050200, 
+0x24060008, 0xaf4201f8, 0x24020006, 0xc002bbf, 
+0xaf4201f4, 0x3c023b9a, 0x3442ca00, 0xaf4201fc, 
+0x240203e8, 0x24040002, 0x24030001, 0xaf420294, 
+0xaf440290, 0xaf43029c, 0x8f820220, 0x30420008, 
+0x10400004, 0x0, 0xaf430298, 0x10000003, 
+0x3021, 0xaf440298, 0x3021, 0x3c030001, 
+0x661821, 0x90636d00, 0x3461021, 0x24c60001, 
+0xa043022c, 0x2cc2000f, 0x1440fff8, 0x3461821, 
+0x24c60001, 0x8f820040, 0x24040080, 0x24050080, 
+0x21702, 0x24420030, 0xa062022c, 0x3461021, 
+0xc002ba8, 0xa040022c, 0x8fa70024, 0x30e20004, 
+0x14400006, 0x0, 0x8f820220, 0x3c0308ff, 
+0x3463fffb, 0x431024, 0xaf820220, 0x8fa7002c, 
+0x30e20004, 0x14400006, 0x0, 0x8f820200, 
+0x3c03c0ff, 0x3463fffb, 0x431024, 0xaf820200, 
+0x8fbf0048, 0x8fbe0044, 0x8fb50040, 0x8fb3003c, 
+0x8fb20038, 0x8fb10034, 0x8fb00030, 0x3e00008, 
+0x27bd0050, 0x0, 0x0, 0xaf400104, 
 0x24040001, 0x410c0, 0x2e21821, 0x24820001, 
 0x3c010001, 0x230821, 0xa42234d0, 0x402021, 
 0x2c820080, 0x1440fff8, 0x410c0, 0x24020001, 
@@ -5946,7 +5950,7 @@
 0x2c450001, 0xa01021, 0x14400009, 0x24840008, 
 0x86102b, 0x1440fff0, 0x1021, 0x304200ff, 
 0x14400030, 0x24020001, 0x1000002e, 0x1021, 
-0x1000fffa, 0x24020001, 0x2002021, 0xc0023ed, 
+0x1000fffa, 0x24020001, 0x2002021, 0xc00240c, 
 0x24050006, 0x3042007f, 0x218c0, 0x2e31021, 
 0x3c010001, 0x220821, 0x942230d0, 0x1040fff2, 
 0x2e31021, 0x3c060001, 0xc23021, 0x94c630d0, 
@@ -5961,7 +5965,7 @@
 0x27bd0018, 0x3e00008, 0x0, 0x27bdffb0, 
 0x801021, 0xafb00030, 0x24500002, 0x2002021, 
 0x24050006, 0xafb10034, 0x408821, 0xafbf0048, 
-0xafbe0044, 0xafb50040, 0xafb3003c, 0xc0023ed, 
+0xafbe0044, 0xafb50040, 0xafb3003c, 0xc00240c, 
 0xafb20038, 0x3047007f, 0x710c0, 0x2e21021, 
 0x3c050001, 0xa22821, 0x94a530d0, 0x50a0001c, 
 0xa03021, 0x3c090001, 0x352934d2, 0x96280002, 
@@ -5974,15 +5978,15 @@
 0x10c00014, 0x610c0, 0x571821, 0x3c010001, 
 0x230821, 0x8c2334d0, 0x571021, 0xafa30010, 
 0x3c010001, 0x220821, 0x8c2234d4, 0x3c040001, 
-0x24846424, 0xafa20014, 0x8e260000, 0x8e270004, 
-0x3c050004, 0xc002b17, 0x34a50400, 0x10000063, 
+0x24846394, 0xafa20014, 0x8e260000, 0x8e270004, 
+0x3c050004, 0xc002b3b, 0x34a50400, 0x10000063, 
 0x3c020800, 0x8f450100, 0x10a00006, 0x510c0, 
 0x2e21021, 0x3c010001, 0x220821, 0x942234d0, 
 0xaf420100, 0xa03021, 0x14c00011, 0x628c0, 
 0x710c0, 0x2e21021, 0xafa70010, 0x3c010001, 
-0x220821, 0x942230d0, 0x3c040001, 0x24846430, 
+0x220821, 0x942230d0, 0x3c040001, 0x248463a0, 
 0xafa20014, 0x8e260000, 0x8e270004, 0x3c050004, 
-0xc002b17, 0x34a50500, 0x10000048, 0x3c020800, 
+0xc002b3b, 0x34a50500, 0x10000048, 0x3c020800, 
 0xb71821, 0x3c020001, 0x96040000, 0x344234d2, 
 0x621821, 0xa4640000, 0x8e020002, 0x720c0, 
 0xac620002, 0x2e41021, 0x3c030001, 0x621821, 
@@ -6005,7 +6009,7 @@
 0x240200ff, 0x13c20002, 0xafaa002c, 0x27c30001, 
 0x8c020228, 0x609021, 0x1642000e, 0x1e38c0, 
 0x8f42033c, 0x24420001, 0xaf42033c, 0x8f42033c, 
-0x8c020228, 0x3c040001, 0x248463ec, 0x3c050009, 
+0x8c020228, 0x3c040001, 0x2484635c, 0x3c050009, 
 0xafa00014, 0xafa20010, 0x8fa60020, 0x1000006b, 
 0x34a50500, 0xf71021, 0x8fa30020, 0x8fa40024, 
 0xac4304c0, 0xac4404c4, 0x8f830054, 0x8f820054, 
@@ -6019,7 +6023,7 @@
 0x2c4203e9, 0x1440ffe9, 0x0, 0x326200ff, 
 0x54400017, 0xaf520018, 0x8f420378, 0x24420001, 
 0xaf420378, 0x8f420378, 0x8f820120, 0x8faa002c, 
-0xafa20010, 0x8f820124, 0x3c040001, 0x248463f8, 
+0xafa20010, 0x8f820124, 0x3c040001, 0x24846368, 
 0x3c050009, 0xafa20014, 0x8d460000, 0x10000033, 
 0x34a50600, 0x8f420308, 0x24130001, 0x24420001, 
 0xaf420308, 0x8f420308, 0x1000001c, 0x326200ff, 
@@ -6032,8 +6036,8 @@
 0x1440ffef, 0x0, 0x326200ff, 0x14400011, 
 0x0, 0x8f420378, 0x24420001, 0xaf420378, 
 0x8f420378, 0x8f820120, 0x8faa002c, 0xafa20010, 
-0x8f820124, 0x3c040001, 0x24846400, 0x3c050009, 
-0xafa20014, 0x8d460000, 0x34a50700, 0xc002b17, 
+0x8f820124, 0x3c040001, 0x24846370, 0x3c050009, 
+0xafa20014, 0x8d460000, 0x34a50700, 0xc002b3b, 
 0x3c03821, 0x8f4202b4, 0x24420001, 0xaf4202b4, 
 0x8f4202b4, 0x8f4202f4, 0x24420001, 0xaf4202f4, 
 0x8f4202f4, 0x8fbf0048, 0x8fbe0044, 0x8fb50040, 
@@ -6041,7 +6045,7 @@
 0x3e00008, 0x27bd0050, 0x27bdffa0, 0x801021, 
 0xafb00040, 0x24500002, 0x2002021, 0x24050006, 
 0xafb10044, 0x408821, 0xafbf0058, 0xafbe0054, 
-0xafb50050, 0xafb3004c, 0xc0023ed, 0xafb20048, 
+0xafb50050, 0xafb3004c, 0xc00240c, 0xafb20048, 
 0x3048007f, 0x810c0, 0x2e21021, 0x3c060001, 
 0xc23021, 0x94c630d0, 0x10c0001c, 0x3821, 
 0x3c0a0001, 0x354a34d2, 0x96290002, 0x610c0, 
@@ -6053,8 +6057,8 @@
 0x94c634d0, 0x14c0ffea, 0x610c0, 0x14c00011, 
 0xafa70028, 0x810c0, 0x2e21021, 0xafa80010, 
 0x3c010001, 0x220821, 0x942230d0, 0x3c040001, 
-0x2484643c, 0xafa20014, 0x8e260000, 0x8e270004, 
-0x3c050004, 0xc002b17, 0x34a50900, 0x10000075, 
+0x248463ac, 0xafa20014, 0x8e260000, 0x8e270004, 
+0x3c050004, 0xc002b3b, 0x34a50900, 0x10000075, 
 0x3c020800, 0x10e0000c, 0x610c0, 0x2e21021, 
 0x3c030001, 0x621821, 0x946334d0, 0x710c0, 
 0x2e21021, 0x3c010001, 0x220821, 0xa42334d0, 
@@ -6089,7 +6093,7 @@
 0xafab0034, 0x27c30001, 0x8c020228, 0x609021, 
 0x1642000e, 0x1e38c0, 0x8f42033c, 0x24420001, 
 0xaf42033c, 0x8f42033c, 0x8c020228, 0x3c040001, 
-0x248463ec, 0x3c050009, 0xafa00014, 0xafa20010, 
+0x2484635c, 0x3c050009, 0xafa00014, 0xafa20010, 
 0x8fa60020, 0x1000006b, 0x34a50500, 0xf71021, 
 0x8fa30020, 0x8fa40024, 0xac4304c0, 0xac4404c4, 
 0x8f830054, 0x8f820054, 0x247003e8, 0x2021023, 
@@ -6103,7 +6107,7 @@
 0x0, 0x326200ff, 0x54400017, 0xaf520018, 
 0x8f420378, 0x24420001, 0xaf420378, 0x8f420378, 
 0x8f820120, 0x8fab0034, 0xafa20010, 0x8f820124, 
-0x3c040001, 0x248463f8, 0x3c050009, 0xafa20014, 
+0x3c040001, 0x24846368, 0x3c050009, 0xafa20014, 
 0x8d660000, 0x10000033, 0x34a50600, 0x8f420308, 
 0x24130001, 0x24420001, 0xaf420308, 0x8f420308, 
 0x1000001c, 0x326200ff, 0x8f830054, 0x8f820054, 
@@ -6116,14 +6120,14 @@
 0x326200ff, 0x14400011, 0x0, 0x8f420378, 
 0x24420001, 0xaf420378, 0x8f420378, 0x8f820120, 
 0x8fab0034, 0xafa20010, 0x8f820124, 0x3c040001, 
-0x24846400, 0x3c050009, 0xafa20014, 0x8d660000, 
-0x34a50700, 0xc002b17, 0x3c03821, 0x8f4202b8, 
+0x24846370, 0x3c050009, 0xafa20014, 0x8d660000, 
+0x34a50700, 0xc002b3b, 0x3c03821, 0x8f4202b8, 
 0x24420001, 0xaf4202b8, 0x8f4202b8, 0x8f4202f4, 
 0x24420001, 0xaf4202f4, 0x8f4202f4, 0x8fbf0058, 
 0x8fbe0054, 0x8fb50050, 0x8fb3004c, 0x8fb20048, 
 0x8fb10044, 0x8fb00040, 0x3e00008, 0x27bd0060, 
 0x0, 0x0, 0x0, 0x27bdffe0, 
-0x27644000, 0xafbf0018, 0xc002b84, 0x24051000, 
+0x27644000, 0xafbf0018, 0xc002ba8, 0x24051000, 
 0x3c030001, 0x34632cc0, 0x3c040001, 0x34842ec8, 
 0x24020020, 0xaf82011c, 0x2e31021, 0xaf800100, 
 0xaf800104, 0xaf800108, 0xaf800110, 0xaf800114, 
@@ -6132,15 +6136,15 @@
 0x2e31021, 0xaf4200f0, 0x2e41021, 0xaf4200f4, 
 0x2e41021, 0xaf4200f8, 0x3c020001, 0x571021, 
 0x904240f4, 0x1440001c, 0x3c050001, 0x8f82011c, 
-0x3c040001, 0x24846500, 0x3c050001, 0x34420001, 
+0x3c040001, 0x24846470, 0x3c050001, 0x34420001, 
 0xaf82011c, 0xafa00010, 0xafa00014, 0x8f86011c, 
-0x34a50100, 0xc002b17, 0x3821, 0x8c020218, 
+0x34a50100, 0xc002b3b, 0x3821, 0x8c020218, 
 0x30420040, 0x10400014, 0x0, 0x8f82011c, 
-0x3c040001, 0x2484650c, 0x3c050001, 0x34420004, 
+0x3c040001, 0x2484647c, 0x3c050001, 0x34420004, 
 0xaf82011c, 0xafa00010, 0xafa00014, 0x8f86011c, 
-0x10000007, 0x34a50200, 0x3c040001, 0x24846514, 
+0x10000007, 0x34a50200, 0x3c040001, 0x24846484, 
 0xafa00010, 0xafa00014, 0x8f86011c, 0x34a50300, 
-0xc002b17, 0x3821, 0x8fbf0018, 0x3e00008, 
+0xc002b3b, 0x3821, 0x8fbf0018, 0x3e00008, 
 0x27bd0020, 0x8fa90010, 0x8f83012c, 0x8faa0014, 
 0x8fab0018, 0x1060000a, 0x27624fe0, 0x14620002, 
 0x24680020, 0x27684800, 0x8f820128, 0x11020004, 
@@ -6181,55 +6185,55 @@
 0x2e21021, 0x402021, 0x24020001, 0xaf4400ec, 
 0xac890000, 0xac820004, 0x24020001, 0x3e00008, 
 0x0, 0x3e00008, 0x0, 0x27bdffd8, 
-0x3c040001, 0x2484651c, 0x3c050001, 0xafbf0024, 
+0x3c040001, 0x2484648c, 0x3c050001, 0xafbf0024, 
 0xafb20020, 0xafb1001c, 0xafb00018, 0x8f900104, 
 0x8f9100b0, 0x8f92011c, 0x34a52500, 0x8f820100, 
-0x2403021, 0x2203821, 0xafa20010, 0xc002b17, 
+0x2403021, 0x2203821, 0xafa20010, 0xc002b3b, 
 0xafb00014, 0x8e020008, 0xafa20010, 0x8e02000c, 
-0x3c040001, 0x24846528, 0xafa20014, 0x8e060000, 
-0x8e070004, 0x3c050001, 0xc002b17, 0x34a52510, 
+0x3c040001, 0x24846498, 0xafa20014, 0x8e060000, 
+0x8e070004, 0x3c050001, 0xc002b3b, 0x34a52510, 
 0x8e020018, 0xafa20010, 0x8e02001c, 0x3c040001, 
-0x24846534, 0xafa20014, 0x8e060010, 0x8e070014, 
-0x3c050001, 0xc002b17, 0x34a52520, 0x3c027f00, 
+0x248464a4, 0xafa20014, 0x8e060010, 0x8e070014, 
+0x3c050001, 0xc002b3b, 0x34a52520, 0x3c027f00, 
 0x2221024, 0x3c030800, 0x54430016, 0x3c030200, 
 0x8f82009c, 0x3042ffff, 0x14400012, 0x3c030200, 
-0x3c040001, 0x24846540, 0x3c050002, 0x34a5f030, 
+0x3c040001, 0x248464b0, 0x3c050002, 0x34a5f030, 
 0x3021, 0x3821, 0x36420002, 0xaf82011c, 
 0x36220001, 0xaf8200b0, 0xaf900104, 0xaf92011c, 
-0xafa00010, 0xc002b17, 0xafa00014, 0x10000024, 
+0xafa00010, 0xc002b3b, 0xafa00014, 0x10000024, 
 0x0, 0x2c31024, 0x1040000d, 0x2231024, 
 0x1040000b, 0x36420002, 0xaf82011c, 0x36220001, 
 0xaf8200b0, 0xaf900104, 0xaf92011c, 0x8f420330, 
 0x24420001, 0xaf420330, 0x10000015, 0x8f420330, 
-0x3c040001, 0x24846548, 0x240202a9, 0xafa20010, 
-0xafa00014, 0x8f860144, 0x3c070001, 0x24e76550, 
-0xc002b17, 0x3405dead, 0x8f82011c, 0x34420002, 
+0x3c040001, 0x248464b8, 0x240202a9, 0xafa20010, 
+0xafa00014, 0x8f860144, 0x3c070001, 0x24e764c0, 
+0xc002b3b, 0x3405dead, 0x8f82011c, 0x34420002, 
 0xaf82011c, 0x8f820220, 0x34420004, 0xaf820220, 
 0x8f820140, 0x3c030001, 0x431025, 0xaf820140, 
 0x8fbf0024, 0x8fb20020, 0x8fb1001c, 0x8fb00018, 
 0x3e00008, 0x27bd0028, 0x27bdffd8, 0x3c040001, 
-0x24846578, 0x3c050001, 0xafbf0024, 0xafb20020, 
+0x248464e8, 0x3c050001, 0xafbf0024, 0xafb20020, 
 0xafb1001c, 0xafb00018, 0x8f900124, 0x8f9100a0, 
 0x8f92011c, 0x34a52600, 0x8f820120, 0x2403021, 
-0x2203821, 0xafa20010, 0xc002b17, 0xafb00014, 
+0x2203821, 0xafa20010, 0xc002b3b, 0xafb00014, 
 0x8e020008, 0xafa20010, 0x8e02000c, 0x3c040001, 
-0x24846584, 0xafa20014, 0x8e060000, 0x8e070004, 
-0x3c050001, 0xc002b17, 0x34a52610, 0x8e020018, 
-0xafa20010, 0x8e02001c, 0x3c040001, 0x24846590, 
+0x248464f4, 0xafa20014, 0x8e060000, 0x8e070004, 
+0x3c050001, 0xc002b3b, 0x34a52610, 0x8e020018, 
+0xafa20010, 0x8e02001c, 0x3c040001, 0x24846500, 
 0xafa20014, 0x8e060010, 0x8e070014, 0x3c050001, 
-0xc002b17, 0x34a52620, 0x3c027f00, 0x2221024, 
+0xc002b3b, 0x34a52620, 0x3c027f00, 0x2221024, 
 0x3c030800, 0x54430016, 0x3c030200, 0x8f8200ac, 
 0x3042ffff, 0x14400012, 0x3c030200, 0x3c040001, 
-0x2484659c, 0x3c050001, 0x34a5f030, 0x3021, 
+0x2484650c, 0x3c050001, 0x34a5f030, 0x3021, 
 0x3821, 0x36420002, 0xaf82011c, 0x36220001, 
 0xaf8200a0, 0xaf900124, 0xaf92011c, 0xafa00010, 
-0xc002b17, 0xafa00014, 0x10000024, 0x0, 
+0xc002b3b, 0xafa00014, 0x10000024, 0x0, 
 0x2c31024, 0x1040000d, 0x2231024, 0x1040000b, 
 0x36420002, 0xaf82011c, 0x36220001, 0xaf8200a0, 
 0xaf900124, 0xaf92011c, 0x8f42032c, 0x24420001, 
 0xaf42032c, 0x10000015, 0x8f42032c, 0x3c040001, 
-0x24846548, 0x240202e2, 0xafa20010, 0xafa00014, 
-0x8f860144, 0x3c070001, 0x24e76550, 0xc002b17, 
+0x248464b8, 0x240202e2, 0xafa20010, 0xafa00014, 
+0x8f860144, 0x3c070001, 0x24e764c0, 0xc002b3b, 
 0x3405dead, 0x8f82011c, 0x34420002, 0xaf82011c, 
 0x8f820220, 0x34420004, 0xaf820220, 0x8f820140, 
 0x3c030001, 0x431025, 0xaf820140, 0x8fbf0024, 
@@ -6238,24 +6242,24 @@
 0x2821, 0x6821, 0x4821, 0x7821, 
 0x7021, 0x8f880124, 0x8f870104, 0x1580002e, 
 0x8f8b011c, 0x11a00014, 0x31620800, 0x8f820120, 
-0x10460029, 0x0, 0x3c040001, 0x8c846f60, 
+0x10460029, 0x0, 0x3c040001, 0x8c846ee4, 
 0x8cc20000, 0x8cc30004, 0xac820000, 0xac830004, 
 0x8cc20008, 0xac820008, 0x94c2000e, 0xa482000e, 
 0x8cc20010, 0x240c0001, 0xac820010, 0x8cc20014, 
 0x10000012, 0x24c60020, 0x10400017, 0x0, 
-0x3c040001, 0x8c846f60, 0x8d020000, 0x8d030004, 
+0x3c040001, 0x8c846ee4, 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, 0x8c846f5c, 0x8ca20000, 
+0x31620100, 0x3c040001, 0x8c846ee0, 0x8ca20000, 
 0x8ca30004, 0xac820000, 0xac830004, 0x8ca20008, 
 0xac820008, 0x94a2000e, 0xa482000e, 0x8ca20010, 
 0x240a0001, 0xac820010, 0x8ca20014, 0x10000012, 
 0x24a50020, 0x10400018, 0x31620100, 0x3c040001, 
-0x8c846f5c, 0x8ce20000, 0x8ce30004, 0xac820000, 
+0x8c846ee0, 0x8ce20000, 0x8ce30004, 0xac820000, 
 0xac830004, 0x8ce20008, 0xac820008, 0x94e2000e, 
 0xa482000e, 0x8ce20010, 0x24e50020, 0xac820010, 
 0x8ce20014, 0x240a0001, 0xa01821, 0xac820014, 
@@ -6264,7 +6268,7 @@
 0x11a00009, 0x31a20800, 0x10400004, 0x25020020, 
 0x8f8200a8, 0xa5e20000, 0x25020020, 0xaf820124, 
 0x8f880124, 0x6821, 0x11800011, 0x31621000, 
-0x3c040001, 0x8c846f60, 0x8c820000, 0x8c830004, 
+0x3c040001, 0x8c846ee4, 0x8c820000, 0x8c830004, 
 0xaf820080, 0xaf830084, 0x8c820008, 0xaf8200a4, 
 0x9482000e, 0xaf8200ac, 0x8c820010, 0x6021, 
 0xaf8200a0, 0x8c8d0010, 0x8c8f0014, 0x31621000, 
@@ -6273,7 +6277,7 @@
 0x3c020002, 0x1221024, 0x10400004, 0x24e20020, 
 0x8f8200b4, 0xaf8200d4, 0x24e20020, 0xaf820104, 
 0x8f870104, 0x4821, 0x1140ff70, 0x0, 
-0x3c040001, 0x8c846f5c, 0x8c820000, 0x8c830004, 
+0x3c040001, 0x8c846ee0, 0x8c820000, 0x8c830004, 
 0xaf820090, 0xaf830094, 0x8c820008, 0xaf8200b4, 
 0x9482000e, 0xaf82009c, 0x8c820010, 0x5021, 
 0xaf8200b0, 0x8c890010, 0x1000ff60, 0x8c8e0014, 
@@ -6282,11 +6286,11 @@
 0x7821, 0x7021, 0x8f880124, 0x8f870104, 
 0x3c180100, 0x1580002e, 0x8f89011c, 0x11a00014, 
 0x31220800, 0x8f820120, 0x10460029, 0x0, 
-0x3c040001, 0x8c846f60, 0x8cc20000, 0x8cc30004, 
+0x3c040001, 0x8c846ee4, 0x8cc20000, 0x8cc30004, 
 0xac820000, 0xac830004, 0x8cc20008, 0xac820008, 
 0x94c2000e, 0xa482000e, 0x8cc20010, 0x240c0001, 
 0xac820010, 0x8cc20014, 0x10000012, 0x24c60020, 
-0x10400017, 0x0, 0x3c040001, 0x8c846f60, 
+0x10400017, 0x0, 0x3c040001, 0x8c846ee4, 
 0x8d020000, 0x8d030004, 0xac820000, 0xac830004, 
 0x8d020008, 0xac820008, 0x9502000e, 0xa482000e, 
 0x8d020010, 0x25060020, 0xac820010, 0x8d020014, 
@@ -6294,11 +6298,11 @@
 0x43102b, 0x54400001, 0x27634800, 0x603021, 
 0x1560002f, 0x31220100, 0x11400014, 0x31228000, 
 0x8f820100, 0x1045002a, 0x31220100, 0x3c040001, 
-0x8c846f5c, 0x8ca20000, 0x8ca30004, 0xac820000, 
+0x8c846ee0, 0x8ca20000, 0x8ca30004, 0xac820000, 
 0xac830004, 0x8ca20008, 0xac820008, 0x94a2000e, 
 0xa482000e, 0x8ca20010, 0x240b0001, 0xac820010, 
 0x8ca20014, 0x10000012, 0x24a50020, 0x10400018, 
-0x31220100, 0x3c040001, 0x8c846f5c, 0x8ce20000, 
+0x31220100, 0x3c040001, 0x8c846ee0, 0x8ce20000, 
 0x8ce30004, 0xac820000, 0xac830004, 0x8ce20008, 
 0xac820008, 0x94e2000e, 0xa482000e, 0x8ce20010, 
 0x24e50020, 0xac820010, 0x8ce20014, 0x240b0001, 
@@ -6307,7 +6311,7 @@
 0x5440001d, 0x31221000, 0x11a00009, 0x31a20800, 
 0x10400004, 0x25020020, 0x8f8200a8, 0xa5e20000, 
 0x25020020, 0xaf820124, 0x8f880124, 0x6821, 
-0x11800011, 0x31221000, 0x3c040001, 0x8c846f60, 
+0x11800011, 0x31221000, 0x3c040001, 0x8c846ee4, 
 0x8c820000, 0x8c830004, 0xaf820080, 0xaf830084, 
 0x8c820008, 0xaf8200a4, 0x9482000e, 0xaf8200ac, 
 0x8c820010, 0x6021, 0xaf8200a0, 0x8c8d0010, 
@@ -6316,7 +6320,7 @@
 0x8f8200b8, 0xa5c20000, 0x3c020002, 0x1421024, 
 0x10400004, 0x24e20020, 0x8f8200b4, 0xaf8200d4, 
 0x24e20020, 0xaf820104, 0x8f870104, 0x5021, 
-0x11600010, 0x0, 0x3c040001, 0x8c846f5c, 
+0x11600010, 0x0, 0x3c040001, 0x8c846ee0, 
 0x8c820000, 0x8c830004, 0xaf820090, 0xaf830094, 
 0x8c820008, 0xaf8200b4, 0x9482000e, 0xaf82009c, 
 0x8c820010, 0x5821, 0xaf8200b0, 0x8c8a0010, 
@@ -6345,37 +6349,37 @@
 0x8f420000, 0x10400003, 0x0, 0x1000ff05, 
 0xaf80004c, 0x1000ff03, 0xaf800048, 0x3e00008, 
 0x0, 0x0, 0x0, 0x3c020001, 
-0x8c426da8, 0x27bdffe8, 0xafbf0014, 0x14400012, 
-0xafb00010, 0x3c100001, 0x26107010, 0x2002021, 
-0xc002b84, 0x24052000, 0x26021fe0, 0x3c010001, 
-0xac226f68, 0x3c010001, 0xac226f64, 0xac020250, 
+0x8c426d28, 0x27bdffe8, 0xafbf0014, 0x14400012, 
+0xafb00010, 0x3c100001, 0x26106f90, 0x2002021, 
+0xc002ba8, 0x24052000, 0x26021fe0, 0x3c010001, 
+0xac226eec, 0x3c010001, 0xac226ee8, 0xac020250, 
 0x24022000, 0xac100254, 0xac020258, 0x24020001, 
-0x3c010001, 0xac226da8, 0x8fbf0014, 0x8fb00010, 
-0x3e00008, 0x27bd0018, 0x3c090001, 0x8d296f68, 
+0x3c010001, 0xac226d28, 0x8fbf0014, 0x8fb00010, 
+0x3e00008, 0x27bd0018, 0x3c090001, 0x8d296eec, 
 0x8c820000, 0x8fa30010, 0x8fa80014, 0xad220000, 
 0x8c820004, 0xad250008, 0xad220004, 0x8f820054, 
 0xad260010, 0xad270014, 0xad230018, 0xad28001c, 
-0xad22000c, 0x2529ffe0, 0x3c020001, 0x24427010, 
+0xad22000c, 0x2529ffe0, 0x3c020001, 0x24426f90, 
 0x122102b, 0x10400003, 0x0, 0x3c090001, 
-0x8d296f64, 0x3c020001, 0x8c426d90, 0xad220000, 
-0x3c020001, 0x8c426d90, 0x3c010001, 0xac296f68, 
+0x8d296ee8, 0x3c020001, 0x8c426d10, 0xad220000, 
+0x3c020001, 0x8c426d10, 0x3c010001, 0xac296eec, 
 0xad220004, 0xac090250, 0x3e00008, 0x0, 
-0x27bdffd0, 0xafb00010, 0x3c100001, 0x8e106f68, 
-0x3c020001, 0x8c426d90, 0xafb10014, 0x808821, 
+0x27bdffd0, 0xafb00010, 0x3c100001, 0x8e106eec, 
+0x3c020001, 0x8c426d10, 0xafb10014, 0x808821, 
 0xafbe0024, 0x8fbe0040, 0x8fa40048, 0xafb20018, 
 0xa09021, 0xafbf0028, 0xafb50020, 0xafb3001c, 
-0xae020000, 0x3c020001, 0x8c426d90, 0xc09821, 
+0xae020000, 0x3c020001, 0x8c426d10, 0xc09821, 
 0xe0a821, 0x10800006, 0xae020004, 0x26050008, 
-0xc002b8f, 0x24060018, 0x10000005, 0x2610ffe0, 
-0x26040008, 0xc002b84, 0x24050018, 0x2610ffe0, 
-0x3c030001, 0x24637010, 0x203102b, 0x10400003, 
-0x0, 0x3c100001, 0x8e106f64, 0x8e220000, 
+0xc002bb3, 0x24060018, 0x10000005, 0x2610ffe0, 
+0x26040008, 0xc002ba8, 0x24050018, 0x2610ffe0, 
+0x3c030001, 0x24636f90, 0x203102b, 0x10400003, 
+0x0, 0x3c100001, 0x8e106ee8, 0x8e220000, 
 0xae020000, 0x8e220004, 0xae120008, 0xae020004, 
 0x8f820054, 0xae130010, 0xae150014, 0xae1e0018, 
 0x8fa80044, 0xae08001c, 0xae02000c, 0x2610ffe0, 
 0x203102b, 0x10400003, 0x0, 0x3c100001, 
-0x8e106f64, 0x3c020001, 0x8c426d90, 0xae020000, 
-0x3c020001, 0x8c426d90, 0x3c010001, 0xac306f68, 
+0x8e106ee8, 0x3c020001, 0x8c426d10, 0xae020000, 
+0x3c020001, 0x8c426d10, 0x3c010001, 0xac306eec, 
 0xae020004, 0xac100250, 0x8fbf0028, 0x8fbe0024, 
 0x8fb50020, 0x8fb3001c, 0x8fb20018, 0x8fb10014, 
 0x8fb00010, 0x3e00008, 0x27bd0030, 0x851821, 
@@ -6390,28 +6394,36 @@
 0x3e00008, 0x0, 0x63080, 0x861821, 
 0x83102b, 0x10400006, 0x0, 0xac850000, 
 0x24840004, 0x83102b, 0x5440fffd, 0xac850000, 
-0x3e00008, 0x0, 0x0, 0x3c0208ff, 
-0x3442ffff, 0x3c03c0ff, 0x8f850220, 0x3463ffff, 
-0x8f860200, 0xa21024, 0x34420004, 0xc31824, 
-0x34630004, 0xaf820220, 0xaf830200, 0x8c820214, 
-0xac020084, 0x8c820218, 0xac020088, 0x8c82021c, 
-0xac02008c, 0x8c820220, 0xac020090, 0x8c820224, 
-0xac020094, 0x8c820228, 0xac020098, 0x8c82022c, 
-0xac02009c, 0x8c820230, 0xac0200a0, 0x8c820234, 
-0xac0200a4, 0x8c820238, 0xac0200a8, 0x8c82023c, 
-0xac0200ac, 0x8c820240, 0xac0200b0, 0x8c820244, 
-0xac0200b4, 0x8c820248, 0xac0200b8, 0x8c82024c, 
-0xac0200bc, 0x8c82001c, 0xac020080, 0x8c820018, 
-0xac0200c0, 0x8c820020, 0xac0200cc, 0x8c820024, 
-0xac0200d0, 0x8c8201d0, 0xac0200e0, 0x8c8201d4, 
-0xac0200e4, 0x8c8201d8, 0xac0200e8, 0x8c8201dc, 
-0xac0200ec, 0x8c8201e0, 0xac0200f0, 0x8c820098, 
-0x8c83009c, 0xac0300fc, 0x8c8200a8, 0x8c8300ac, 
-0xac0300f4, 0x8c8200a0, 0x8c8300a4, 0x30a50004, 
-0xac0300f8, 0x14a00007, 0x30c20004, 0x8f820220, 
-0x3c0308ff, 0x3463fffb, 0x431024, 0xaf820220, 
-0x30c20004, 0x14400006, 0x0, 0x8f820200, 
-0x3c03c0ff, 0x3463fffb, 0x431024, 0xaf820200, 
+0x3e00008, 0x0, 0x0, 0x26e50028, 
+0xa03021, 0x274301c0, 0x8f4d0358, 0x8f47035c, 
+0x8f480360, 0x8f490364, 0x8f4a0368, 0x8f4b0204, 
+0x8f4c0200, 0x24640400, 0x64102b, 0x10400008, 
+0x3c0208ff, 0x8cc20000, 0xac620000, 0x24630004, 
+0x64102b, 0x1440fffb, 0x24c60004, 0x3c0208ff, 
+0x3442ffff, 0x3c03c0ff, 0xaf4d0358, 0xaf47035c, 
+0xaf480360, 0xaf490364, 0xaf4a0368, 0xaf4b0204, 
+0xaf4c0200, 0x8f840220, 0x3463ffff, 0x8f860200, 
+0x821024, 0x34420004, 0xc31824, 0x34630004, 
+0xaf820220, 0xaf830200, 0x8ca20214, 0xac020084, 
+0x8ca20218, 0xac020088, 0x8ca2021c, 0xac02008c, 
+0x8ca20220, 0xac020090, 0x8ca20224, 0xac020094, 
+0x8ca20228, 0xac020098, 0x8ca2022c, 0xac02009c, 
+0x8ca20230, 0xac0200a0, 0x8ca20234, 0xac0200a4, 
+0x8ca20238, 0xac0200a8, 0x8ca2023c, 0xac0200ac, 
+0x8ca20240, 0xac0200b0, 0x8ca20244, 0xac0200b4, 
+0x8ca20248, 0xac0200b8, 0x8ca2024c, 0xac0200bc, 
+0x8ca2001c, 0xac020080, 0x8ca20018, 0xac0200c0, 
+0x8ca20020, 0xac0200cc, 0x8ca20024, 0xac0200d0, 
+0x8ca201d0, 0xac0200e0, 0x8ca201d4, 0xac0200e4, 
+0x8ca201d8, 0xac0200e8, 0x8ca201dc, 0xac0200ec, 
+0x8ca201e0, 0xac0200f0, 0x8ca20098, 0x8ca3009c, 
+0xac0300fc, 0x8ca200a8, 0x8ca300ac, 0xac0300f4, 
+0x8ca200a0, 0x8ca300a4, 0x30840004, 0xac0300f8, 
+0x14800007, 0x30c20004, 0x8f820220, 0x3c0308ff, 
+0x3463fffb, 0x431024, 0xaf820220, 0x30c20004, 
+0x14400006, 0x0, 0x8f820200, 0x3c03c0ff, 
+0x3463fffb, 0x431024, 0xaf820200, 0x8f4202dc, 
+0xa34005c5, 0x24420001, 0xaf4202dc, 0x8f4202dc, 
 0x3e00008, 0x0, 0x27bdffd8, 0xafbf0024, 
 0xafb00020, 0x8f430024, 0x8f420020, 0x10620038, 
 0x0, 0x8f430020, 0x8f420024, 0x622023, 
@@ -6443,7 +6455,7 @@
 0x8e040000, 0x8e050004, 0x96120008, 0x8f420090, 
 0x9611000a, 0x3246ffff, 0x46102a, 0x10400017, 
 0x0, 0x8f8200d8, 0x8f430098, 0x431023, 
-0x2442fff8, 0xaf420090, 0x8f420090, 0x2842fff9, 
+0x2442dcbe, 0xaf420090, 0x8f420090, 0x2842dcbf, 
 0x10400005, 0x0, 0x8f420090, 0x8f430144, 
 0x431021, 0xaf420090, 0x8f420090, 0x46102a, 
 0x10400006, 0x0, 0x8f420348, 0x24420001, 
@@ -6513,7 +6525,7 @@
 0x8e040000, 0x8e050004, 0x96110008, 0x8f420090, 
 0x9607000a, 0x3226ffff, 0x46102a, 0x10400017, 
 0x0, 0x8f8200d8, 0x8f430098, 0x431023, 
-0x2442ff80, 0xaf420090, 0x8f420090, 0x2842ff81, 
+0x2442dc46, 0xaf420090, 0x8f420090, 0x2842dc47, 
 0x10400005, 0x0, 0x8f420090, 0x8f430144, 
 0x431021, 0xaf420090, 0x8f420090, 0x46102a, 
 0x10400006, 0x0, 0x8f420348, 0x24420001, 
@@ -6575,15 +6587,15 @@
 0x30a20001, 0x8c82001c, 0x8f430040, 0x8f440034, 
 0x24420001, 0x2463ffff, 0x431024, 0x862021, 
 0xaf42002c, 0x30a20030, 0x14400006, 0xaf440034, 
-0x8f420034, 0x8c03023c, 0x43102b, 0x144000ca, 
+0x8f420034, 0x8c03023c, 0x43102b, 0x144000b4, 
 0x0, 0x32c20010, 0x10400028, 0x24070008, 
 0x8f440170, 0x8f450174, 0x8f43002c, 0x8f48000c, 
 0x8f860120, 0x24020080, 0xafa20010, 0xafa30014, 
 0xafa80018, 0x8f42010c, 0x40f809, 0x24c6001c, 
 0x14400011, 0x24020001, 0x3c010001, 0x370821, 
 0xa02240f1, 0x8f820124, 0xafa20010, 0x8f820128, 
-0x3c040001, 0x24846854, 0xafa20014, 0x8f46002c, 
-0x8f870120, 0x3c050009, 0xc002b17, 0x34a51100, 
+0x3c040001, 0x248467c4, 0xafa20014, 0x8f46002c, 
+0x8f870120, 0x3c050009, 0xc002b3b, 0x34a51100, 
 0x10000036, 0x0, 0x8f420300, 0x8f43002c, 
 0x24420001, 0xaf420300, 0x8f420300, 0x24020001, 
 0xa34205c1, 0x10000026, 0xaf430038, 0x8f440170, 
@@ -6592,13 +6604,13 @@
 0x8f42010c, 0x40f809, 0x24c6001c, 0x14400011, 
 0x24020001, 0x3c010001, 0x370821, 0xa02240f0, 
 0x8f820124, 0xafa20010, 0x8f820128, 0x3c040001, 
-0x24846848, 0xafa20014, 0x8f46002c, 0x8f870120, 
-0x3c050009, 0xc002b17, 0x34a50900, 0x1000000f, 
+0x248467b8, 0xafa20014, 0x8f46002c, 0x8f870120, 
+0x3c050009, 0xc002b3b, 0x34a50900, 0x1000000f, 
 0x0, 0x8f420300, 0x24420001, 0xaf420300, 
 0x8f420300, 0x8f42002c, 0xa34005c1, 0xaf420038, 
 0x3c010001, 0x370821, 0xa02040f1, 0x3c010001, 
 0x370821, 0xa02040f0, 0xaf400034, 0x8f420314, 
-0x24420001, 0xaf420314, 0x1000006f, 0x8f420314, 
+0x24420001, 0xaf420314, 0x10000059, 0x8f420314, 
 0x10400022, 0x30a27000, 0x8c85001c, 0x8f420028, 
 0xa22023, 0x4810003, 0x0, 0x8f420040, 
 0x822021, 0x8f420358, 0x8f430000, 0xaf450028, 
@@ -6606,8 +6618,8 @@
 0x8f82004c, 0x1040fffd, 0x0, 0x10000005, 
 0x0, 0xaf800048, 0x8f820048, 0x1040fffd, 
 0x0, 0x8f820060, 0x34420008, 0xaf820060, 
-0x8f420000, 0x10400003, 0x0, 0x1000004e, 
-0xaf80004c, 0x1000004c, 0xaf800048, 0x1040002f, 
+0x8f420000, 0x10400003, 0x0, 0x10000038, 
+0xaf80004c, 0x10000036, 0xaf800048, 0x1040002f, 
 0x30a21000, 0x1040000c, 0x30a24000, 0x8c83001c, 
 0x8f420050, 0x622023, 0x4820001, 0x24840200, 
 0x8f42035c, 0x441021, 0xaf42035c, 0x8f420368, 
@@ -6618,190 +6630,179 @@
 0x3c020800, 0x8c83001c, 0x8f420060, 0x622023, 
 0x4820001, 0x24840100, 0x8f420360, 0x441021, 
 0xaf420360, 0x8f420368, 0xaf430060, 0x441021, 
-0xaf420368, 0x3c020800, 0x2c21024, 0x5040001e, 
-0x36940040, 0x1000001c, 0x0, 0x30a20100, 
-0x10400019, 0x0, 0x3c020001, 0x8c426d44, 
-0x1040000d, 0x274301c0, 0x24650400, 0x65102b, 
-0x10400007, 0x26e40028, 0x8c820000, 0xac620000, 
-0x24630004, 0x65102b, 0x1440fffb, 0x24840004, 
-0x10000002, 0x274401c0, 0x26e40028, 0xc002bb4, 
-0x0, 0x8f4202dc, 0xa34005c5, 0x24420001, 
-0xaf4202dc, 0x8f4202dc, 0x8fbf0020, 0x3e00008, 
-0x27bd0028, 0x3e00008, 0x0, 0x27bdffa8, 
-0xafbf0050, 0xafbe004c, 0xafb50048, 0xafb30044, 
-0xafb20040, 0xafb1003c, 0xafb00038, 0x8f910108, 
-0x26220020, 0xaf820108, 0x8e320018, 0xa821, 
-0x32420024, 0x104001ba, 0xf021, 0x8e26001c, 
-0x8f43001c, 0x61100, 0x621821, 0x8c70000c, 
-0x9604000c, 0x962d0016, 0x9473000a, 0x2c8305dd, 
-0x38828870, 0x2c420001, 0x621825, 0x10600015, 
-0x2821, 0x32c20040, 0x10400015, 0x24020800, 
-0x96030014, 0x14620012, 0x3402aaaa, 0x9603000e, 
-0x14620007, 0x2021, 0x96030010, 0x24020300, 
-0x14620004, 0x801021, 0x96020012, 0x2c440001, 
-0x801021, 0x54400006, 0x24050016, 0x10000004, 
-0x0, 0x24020800, 0x50820001, 0x2405000e, 
-0x934205c3, 0x14400008, 0x5821, 0x240b0001, 
-0x32620180, 0xaf4500a8, 0xaf5000a0, 0x10400002, 
-0xaf4600a4, 0xa34b05c3, 0x10a00085, 0x2054021, 
-0x91020000, 0x3821, 0x3042000f, 0x25080, 
-0x32c20002, 0x10400012, 0x10a1821, 0x32620002, 
-0x10400010, 0x32c20001, 0x1002021, 0x94820000, 
-0x24840002, 0xe23821, 0x83102b, 0x1440fffb, 
-0x30e2ffff, 0x71c02, 0x623821, 0x71c02, 
-0x30e2ffff, 0x623821, 0x71027, 0xa502000a, 
-0x32c20001, 0x1040006a, 0x32620001, 0x10400068, 
-0x0, 0x8f4200a8, 0x10400065, 0x0, 
-0x8f4200a0, 0x8f4300a8, 0x431021, 0x904c0009, 
-0x318900ff, 0x39230006, 0x3182b, 0x39220011, 
-0x2102b, 0x621824, 0x1060000c, 0x3c050006, 
-0x8f4200a4, 0x3c040001, 0x24846864, 0xafa20010, 
-0x8f4200a0, 0x34a54600, 0x1203821, 0xc002b17, 
-0xafa20014, 0x1000004e, 0x0, 0x32c20004, 
-0x14400013, 0x2821, 0x316200ff, 0x14400004, 
-0x0, 0x95020002, 0x1000000d, 0x4a2823, 
-0x9505000c, 0x9502000e, 0x95030010, 0xa22821, 
-0xa32821, 0x95030012, 0x91040009, 0x95020002, 
-0xa32821, 0xa42821, 0x4a1023, 0xa22821, 
-0x2002021, 0x94820000, 0x24840002, 0xe23821, 
-0x88102b, 0x1440fffb, 0x71c02, 0x30e2ffff, 
+0xaf420368, 0x3c020800, 0x2c21024, 0x50400008, 
+0x36940040, 0x10000006, 0x0, 0x30a20100, 
+0x10400003, 0x0, 0xc002bd8, 0x0, 
+0x8fbf0020, 0x3e00008, 0x27bd0028, 0x3e00008, 
+0x0, 0x27bdffa8, 0xafbf0050, 0xafbe004c, 
+0xafb50048, 0xafb30044, 0xafb20040, 0xafb1003c, 
+0xafb00038, 0x8f910108, 0x26220020, 0xaf820108, 
+0x8e320018, 0xa821, 0x32420024, 0x104001ba, 
+0xf021, 0x8e26001c, 0x8f43001c, 0x61100, 
+0x621821, 0x8c70000c, 0x9604000c, 0x962d0016, 
+0x9473000a, 0x2c8305dd, 0x38828870, 0x2c420001, 
+0x621825, 0x10600015, 0x2821, 0x32c20040, 
+0x10400015, 0x24020800, 0x96030014, 0x14620012, 
+0x3402aaaa, 0x9603000e, 0x14620007, 0x2021, 
+0x96030010, 0x24020300, 0x14620004, 0x801021, 
+0x96020012, 0x2c440001, 0x801021, 0x54400006, 
+0x24050016, 0x10000004, 0x0, 0x24020800, 
+0x50820001, 0x2405000e, 0x934205c3, 0x14400008, 
+0x5821, 0x240b0001, 0x32620180, 0xaf4500a8, 
+0xaf5000a0, 0x10400002, 0xaf4600a4, 0xa34b05c3, 
+0x10a00085, 0x2054021, 0x91020000, 0x3821, 
+0x3042000f, 0x25080, 0x32c20002, 0x10400012, 
+0x10a1821, 0x32620002, 0x10400010, 0x32c20001, 
+0x1002021, 0x94820000, 0x24840002, 0xe23821, 
+0x83102b, 0x1440fffb, 0x30e2ffff, 0x71c02, 
 0x623821, 0x71c02, 0x30e2ffff, 0x623821, 
-0x1a52821, 0x51c02, 0x30a2ffff, 0x622821, 
-0x51c02, 0x30a2ffff, 0x622821, 0xa72823, 
-0x51402, 0xa22821, 0x30a5ffff, 0x50a00001, 
-0x3405ffff, 0x316200ff, 0x14400008, 0x318300ff, 
-0x8f4300a0, 0x8f4200a8, 0x624021, 0x91020000, 
-0x3042000f, 0x25080, 0x318300ff, 0x24020006, 
-0x14620003, 0x10a1021, 0x10000002, 0x24440010, 
-0x24440006, 0x316200ff, 0x14400006, 0x0, 
-0x94820000, 0xa22821, 0x51c02, 0x30a2ffff, 
-0x622821, 0x934205c3, 0x10400003, 0x32620100, 
-0x50400003, 0xa4850000, 0x52827, 0xa4850000, 
-0x9622000e, 0x8f43009c, 0x621821, 0x32a200ff, 
-0x10400007, 0xaf43009c, 0x3c024000, 0x2021025, 
-0xafa20020, 0x8f42009c, 0x10000003, 0x5e1025, 
-0xafb00020, 0x8f42009c, 0xafa20024, 0x32620080, 
-0x10400010, 0x32620100, 0x8f4200b4, 0x24430001, 
-0x210c0, 0x571021, 0xaf4300b4, 0x8fa30020, 
-0x8fa40024, 0x3c010001, 0x220821, 0xac2338e8, 
-0x3c010001, 0x220821, 0xac2438ec, 0x100000a5, 
-0x32c20020, 0x10400064, 0x0, 0x8f4200b4, 
-0x24430001, 0x210c0, 0x571021, 0xaf4300b4, 
-0x8fa30020, 0x8fa40024, 0x3c010001, 0x220821, 
-0xac2338e8, 0x3c010001, 0x220821, 0xac2438ec, 
-0x8f4200b4, 0x10400051, 0x3821, 0x3c090001, 
-0x352938e8, 0x3c08001f, 0x3508ffff, 0x240bffff, 
-0x340affff, 0x710c0, 0x571021, 0x491021, 
-0x8c430000, 0x8c440004, 0xafa30028, 0xafa4002c, 
-0x8f8200fc, 0x8fa30028, 0x8fa4002c, 0xac430000, 
-0xac440004, 0x24420008, 0xaf8200f0, 0x8f42008c, 
-0x2442ffff, 0xaf42008c, 0x97a2002e, 0x8f440270, 
-0x8f450274, 0x401821, 0x1021, 0xa32821, 
-0xa3302b, 0x822021, 0x862021, 0xaf440270, 
-0xaf450274, 0x8fa20028, 0x481024, 0x90430000, 
-0x30630001, 0x1460000b, 0x402021, 0x8f420278, 
-0x8f43027c, 0x24630001, 0x2c640001, 0x441021, 
-0xaf420278, 0xaf43027c, 0x8f420278, 0x1000001a, 
-0x8f43027c, 0x8c820000, 0x144b000e, 0x0, 
-0x94820004, 0x144a000b, 0x0, 0x8f420288, 
-0x8f43028c, 0x24630001, 0x2c640001, 0x441021, 
-0xaf420288, 0xaf43028c, 0x8f420288, 0x1000000a, 
-0x8f43028c, 0x8f420280, 0x8f430284, 0x24630001, 
-0x2c640001, 0x441021, 0xaf420280, 0xaf430284, 
-0x8f420280, 0x8f430284, 0x8f4200b4, 0x24e70001, 
-0xe2102b, 0x1440ffb8, 0x710c0, 0xa34005c3, 
-0x1000003f, 0xaf4000b4, 0x8f8200fc, 0x8fa30020, 
-0x8fa40024, 0xac430000, 0xac440004, 0x24420008, 
-0xaf8200f0, 0x8f42009c, 0x8f46008c, 0x8f440270, 
-0x8f450274, 0x401821, 0x1021, 0x24c6ffff, 
-0xaf46008c, 0xa32821, 0xa3302b, 0x822021, 
-0x862021, 0xaf440270, 0xaf450274, 0x92020000, 
-0x30420001, 0x1440000c, 0x2402ffff, 0x8f420278, 
-0x8f43027c, 0x24630001, 0x2c640001, 0x441021, 
-0xaf420278, 0xaf43027c, 0x8f420278, 0x8f43027c, 
-0x1000001c, 0x32c20020, 0x8e030000, 0x1462000f, 
-0x3402ffff, 0x96030004, 0x1462000c, 0x0, 
-0x8f420288, 0x8f43028c, 0x24630001, 0x2c640001, 
-0x441021, 0xaf420288, 0xaf43028c, 0x8f420288, 
-0x8f43028c, 0x1000000b, 0x32c20020, 0x8f420280, 
+0x71027, 0xa502000a, 0x32c20001, 0x1040006a, 
+0x32620001, 0x10400068, 0x0, 0x8f4200a8, 
+0x10400065, 0x0, 0x8f4200a0, 0x8f4300a8, 
+0x431021, 0x904c0009, 0x318900ff, 0x39230006, 
+0x3182b, 0x39220011, 0x2102b, 0x621824, 
+0x1060000c, 0x3c050006, 0x8f4200a4, 0x3c040001, 
+0x248467d4, 0xafa20010, 0x8f4200a0, 0x34a54600, 
+0x1203821, 0xc002b3b, 0xafa20014, 0x1000004e, 
+0x0, 0x32c20004, 0x14400013, 0x2821, 
+0x316200ff, 0x14400004, 0x0, 0x95020002, 
+0x1000000d, 0x4a2823, 0x9505000c, 0x9502000e, 
+0x95030010, 0xa22821, 0xa32821, 0x95030012, 
+0x91040009, 0x95020002, 0xa32821, 0xa42821, 
+0x4a1023, 0xa22821, 0x2002021, 0x94820000, 
+0x24840002, 0xe23821, 0x88102b, 0x1440fffb, 
+0x71c02, 0x30e2ffff, 0x623821, 0x71c02, 
+0x30e2ffff, 0x623821, 0x1a52821, 0x51c02, 
+0x30a2ffff, 0x622821, 0x51c02, 0x30a2ffff, 
+0x622821, 0xa72823, 0x51402, 0xa22821, 
+0x30a5ffff, 0x50a00001, 0x3405ffff, 0x316200ff, 
+0x14400008, 0x318300ff, 0x8f4300a0, 0x8f4200a8, 
+0x624021, 0x91020000, 0x3042000f, 0x25080, 
+0x318300ff, 0x24020006, 0x14620003, 0x10a1021, 
+0x10000002, 0x24440010, 0x24440006, 0x316200ff, 
+0x14400006, 0x0, 0x94820000, 0xa22821, 
+0x51c02, 0x30a2ffff, 0x622821, 0x934205c3, 
+0x10400003, 0x32620100, 0x50400003, 0xa4850000, 
+0x52827, 0xa4850000, 0x9622000e, 0x8f43009c, 
+0x621821, 0x32a200ff, 0x10400007, 0xaf43009c, 
+0x3c024000, 0x2021025, 0xafa20020, 0x8f42009c, 
+0x10000003, 0x5e1025, 0xafb00020, 0x8f42009c, 
+0xafa20024, 0x32620080, 0x10400010, 0x32620100, 
+0x8f4200b4, 0x24430001, 0x210c0, 0x571021, 
+0xaf4300b4, 0x8fa30020, 0x8fa40024, 0x3c010001, 
+0x220821, 0xac2338e8, 0x3c010001, 0x220821, 
+0xac2438ec, 0x100000a5, 0x32c20020, 0x10400064, 
+0x0, 0x8f4200b4, 0x24430001, 0x210c0, 
+0x571021, 0xaf4300b4, 0x8fa30020, 0x8fa40024, 
+0x3c010001, 0x220821, 0xac2338e8, 0x3c010001, 
+0x220821, 0xac2438ec, 0x8f4200b4, 0x10400051, 
+0x3821, 0x3c090001, 0x352938e8, 0x3c08001f, 
+0x3508ffff, 0x240bffff, 0x340affff, 0x710c0, 
+0x571021, 0x491021, 0x8c430000, 0x8c440004, 
+0xafa30028, 0xafa4002c, 0x8f8200fc, 0x8fa30028, 
+0x8fa4002c, 0xac430000, 0xac440004, 0x24420008, 
+0xaf8200f0, 0x8f42008c, 0x2442ffff, 0xaf42008c, 
+0x97a2002e, 0x8f440270, 0x8f450274, 0x401821, 
+0x1021, 0xa32821, 0xa3302b, 0x822021, 
+0x862021, 0xaf440270, 0xaf450274, 0x8fa20028, 
+0x481024, 0x90430000, 0x30630001, 0x1460000b, 
+0x402021, 0x8f420278, 0x8f43027c, 0x24630001, 
+0x2c640001, 0x441021, 0xaf420278, 0xaf43027c, 
+0x8f420278, 0x1000001a, 0x8f43027c, 0x8c820000, 
+0x144b000e, 0x0, 0x94820004, 0x144a000b, 
+0x0, 0x8f420288, 0x8f43028c, 0x24630001, 
+0x2c640001, 0x441021, 0xaf420288, 0xaf43028c, 
+0x8f420288, 0x1000000a, 0x8f43028c, 0x8f420280, 
 0x8f430284, 0x24630001, 0x2c640001, 0x441021, 
 0xaf420280, 0xaf430284, 0x8f420280, 0x8f430284, 
-0x32c20020, 0x10400005, 0xaf40009c, 0x8f420358, 
+0x8f4200b4, 0x24e70001, 0xe2102b, 0x1440ffb8, 
+0x710c0, 0xa34005c3, 0x1000003f, 0xaf4000b4, 
+0x8f8200fc, 0x8fa30020, 0x8fa40024, 0xac430000, 
+0xac440004, 0x24420008, 0xaf8200f0, 0x8f42009c, 
+0x8f46008c, 0x8f440270, 0x8f450274, 0x401821, 
+0x1021, 0x24c6ffff, 0xaf46008c, 0xa32821, 
+0xa3302b, 0x822021, 0x862021, 0xaf440270, 
+0xaf450274, 0x92020000, 0x30420001, 0x1440000c, 
+0x2402ffff, 0x8f420278, 0x8f43027c, 0x24630001, 
+0x2c640001, 0x441021, 0xaf420278, 0xaf43027c, 
+0x8f420278, 0x8f43027c, 0x1000001c, 0x32c20020, 
+0x8e030000, 0x1462000f, 0x3402ffff, 0x96030004, 
+0x1462000c, 0x0, 0x8f420288, 0x8f43028c, 
+0x24630001, 0x2c640001, 0x441021, 0xaf420288, 
+0xaf43028c, 0x8f420288, 0x8f43028c, 0x1000000b, 
+0x32c20020, 0x8f420280, 0x8f430284, 0x24630001, 
+0x2c640001, 0x441021, 0xaf420280, 0xaf430284, 
+0x8f420280, 0x8f430284, 0x32c20020, 0x10400005, 
+0xaf40009c, 0x8f420358, 0x2442ffff, 0xaf420358, 
+0x8f420358, 0x8e22001c, 0x8f430040, 0x24420001, 
+0x2463ffff, 0x431024, 0xaf42002c, 0x32420060, 
+0x14400008, 0x32c20010, 0x8f420034, 0x24420001, 
+0xaf420034, 0x8c03023c, 0x43102b, 0x14400102, 
+0x32c20010, 0x10400018, 0x24070008, 0x8f440170, 
+0x8f450174, 0x8f43002c, 0x8f48000c, 0x8f860120, 
+0x24020080, 0xafa20010, 0xafa30014, 0xafa80018, 
+0x8f42010c, 0x40f809, 0x24c6001c, 0x10400047, 
+0x24020001, 0x8f420300, 0x8f43002c, 0x24420001, 
+0xaf420300, 0x8f420300, 0x24020001, 0xa34205c1, 
+0x1000007c, 0xaf430038, 0x8f440170, 0x8f450174, 
+0x8f43002c, 0x8f48000c, 0x8f860120, 0x24020020, 
+0xafa20010, 0xafa30014, 0xafa80018, 0x8f42010c, 
+0x40f809, 0x24c6001c, 0x10400057, 0x24020001, 
+0x10000065, 0x0, 0x32420012, 0x10400075, 
+0x32420001, 0x9622000e, 0x8f43009c, 0x621821, 
+0x32c20020, 0x10400005, 0xaf43009c, 0x8f420358, 
 0x2442ffff, 0xaf420358, 0x8f420358, 0x8e22001c, 
 0x8f430040, 0x24420001, 0x2463ffff, 0x431024, 
-0xaf42002c, 0x32420060, 0x14400008, 0x32c20010, 
+0xaf42002c, 0x32420010, 0x14400008, 0x32c20010, 
 0x8f420034, 0x24420001, 0xaf420034, 0x8c03023c, 
-0x43102b, 0x14400118, 0x32c20010, 0x10400018, 
+0x43102b, 0x144000bc, 0x32c20010, 0x10400028, 
 0x24070008, 0x8f440170, 0x8f450174, 0x8f43002c, 
 0x8f48000c, 0x8f860120, 0x24020080, 0xafa20010, 
 0xafa30014, 0xafa80018, 0x8f42010c, 0x40f809, 
-0x24c6001c, 0x10400047, 0x24020001, 0x8f420300, 
+0x24c6001c, 0x14400011, 0x24020001, 0x3c010001, 
+0x370821, 0xa02240f1, 0x8f820124, 0xafa20010, 
+0x8f820128, 0x3c040001, 0x248467c4, 0xafa20014, 
+0x8f46002c, 0x8f870120, 0x3c050009, 0xc002b3b, 
+0x34a51100, 0x10000036, 0x0, 0x8f420300, 
 0x8f43002c, 0x24420001, 0xaf420300, 0x8f420300, 
-0x24020001, 0xa34205c1, 0x1000007c, 0xaf430038, 
+0x24020001, 0xa34205c1, 0x10000026, 0xaf430038, 
 0x8f440170, 0x8f450174, 0x8f43002c, 0x8f48000c, 
 0x8f860120, 0x24020020, 0xafa20010, 0xafa30014, 
 0xafa80018, 0x8f42010c, 0x40f809, 0x24c6001c, 
-0x10400057, 0x24020001, 0x10000065, 0x0, 
-0x32420012, 0x10400075, 0x32420001, 0x9622000e, 
-0x8f43009c, 0x621821, 0x32c20020, 0x10400005, 
-0xaf43009c, 0x8f420358, 0x2442ffff, 0xaf420358, 
-0x8f420358, 0x8e22001c, 0x8f430040, 0x24420001, 
-0x2463ffff, 0x431024, 0xaf42002c, 0x32420010, 
-0x14400008, 0x32c20010, 0x8f420034, 0x24420001, 
-0xaf420034, 0x8c03023c, 0x43102b, 0x144000d2, 
-0x32c20010, 0x10400028, 0x24070008, 0x8f440170, 
-0x8f450174, 0x8f43002c, 0x8f48000c, 0x8f860120, 
-0x24020080, 0xafa20010, 0xafa30014, 0xafa80018, 
-0x8f42010c, 0x40f809, 0x24c6001c, 0x14400011, 
-0x24020001, 0x3c010001, 0x370821, 0xa02240f1, 
-0x8f820124, 0xafa20010, 0x8f820128, 0x3c040001, 
-0x24846854, 0xafa20014, 0x8f46002c, 0x8f870120, 
-0x3c050009, 0xc002b17, 0x34a51100, 0x10000036, 
-0x0, 0x8f420300, 0x8f43002c, 0x24420001, 
-0xaf420300, 0x8f420300, 0x24020001, 0xa34205c1, 
-0x10000026, 0xaf430038, 0x8f440170, 0x8f450174, 
-0x8f43002c, 0x8f48000c, 0x8f860120, 0x24020020, 
-0xafa20010, 0xafa30014, 0xafa80018, 0x8f42010c, 
-0x40f809, 0x24c6001c, 0x14400011, 0x24020001, 
-0x3c010001, 0x370821, 0xa02240f0, 0x8f820124, 
-0xafa20010, 0x8f820128, 0x3c040001, 0x24846848, 
-0xafa20014, 0x8f46002c, 0x8f870120, 0x3c050009, 
-0xc002b17, 0x34a50900, 0x1000000f, 0x0, 
-0x8f420300, 0x24420001, 0xaf420300, 0x8f420300, 
-0x8f42002c, 0xa34005c1, 0xaf420038, 0x3c010001, 
-0x370821, 0xa02040f1, 0x3c010001, 0x370821, 
-0xa02040f0, 0xaf400034, 0x8f420314, 0x24420001, 
-0xaf420314, 0x10000078, 0x8f420314, 0x10400022, 
-0x32427000, 0x8e25001c, 0x8f420028, 0xa22023, 
-0x4810003, 0x0, 0x8f420040, 0x822021, 
-0x8f420358, 0x8f430000, 0xaf450028, 0x441021, 
-0x10600007, 0xaf420358, 0xaf80004c, 0x8f82004c, 
-0x1040fffd, 0x0, 0x10000005, 0x0, 
-0xaf800048, 0x8f820048, 0x1040fffd, 0x0, 
-0x8f820060, 0x34420008, 0xaf820060, 0x8f420000, 
-0x10400003, 0x0, 0x10000057, 0xaf80004c, 
-0x10000055, 0xaf800048, 0x1040002f, 0x32421000, 
-0x1040000c, 0x32424000, 0x8e23001c, 0x8f420050, 
-0x622023, 0x4820001, 0x24840200, 0x8f42035c, 
-0x441021, 0xaf42035c, 0x8f420368, 0x1000001a, 
-0xaf430050, 0x1040000c, 0x32c28000, 0x8e23001c, 
-0x8f420070, 0x622023, 0x4820001, 0x24840400, 
-0x8f420364, 0x441021, 0xaf420364, 0x8f420368, 
-0x1000000d, 0xaf430070, 0x1040000e, 0x3c020800, 
-0x8e23001c, 0x8f420060, 0x622023, 0x4820001, 
-0x24840100, 0x8f420360, 0x441021, 0xaf420360, 
-0x8f420368, 0xaf430060, 0x441021, 0xaf420368, 
-0x3c020800, 0x2c21024, 0x50400027, 0x36940040, 
-0x10000025, 0x0, 0x32420048, 0x10400007, 
-0x24150001, 0x8e22001c, 0x3c03ffff, 0x43f024, 
-0x3042ffff, 0x1000fd75, 0xae22001c, 0x32420100, 
-0x10400019, 0x0, 0x3c020001, 0x8c426d44, 
-0x1040000d, 0x274301c0, 0x24650400, 0x65102b, 
-0x10400007, 0x26e40028, 0x8c820000, 0xac620000, 
-0x24630004, 0x65102b, 0x1440fffb, 0x24840004, 
-0x10000002, 0x274401c0, 0x26e40028, 0xc002bb4, 
-0x0, 0x8f4202dc, 0xa34005c5, 0x24420001, 
-0xaf4202dc, 0x8f4202dc, 0x8fbf0050, 0x8fbe004c, 
+0x14400011, 0x24020001, 0x3c010001, 0x370821, 
+0xa02240f0, 0x8f820124, 0xafa20010, 0x8f820128, 
+0x3c040001, 0x248467b8, 0xafa20014, 0x8f46002c, 
+0x8f870120, 0x3c050009, 0xc002b3b, 0x34a50900, 
+0x1000000f, 0x0, 0x8f420300, 0x24420001, 
+0xaf420300, 0x8f420300, 0x8f42002c, 0xa34005c1, 
+0xaf420038, 0x3c010001, 0x370821, 0xa02040f1, 
+0x3c010001, 0x370821, 0xa02040f0, 0xaf400034, 
+0x8f420314, 0x24420001, 0xaf420314, 0x10000062, 
+0x8f420314, 0x10400022, 0x32427000, 0x8e25001c, 
+0x8f420028, 0xa22023, 0x4810003, 0x0, 
+0x8f420040, 0x822021, 0x8f420358, 0x8f430000, 
+0xaf450028, 0x441021, 0x10600007, 0xaf420358, 
+0xaf80004c, 0x8f82004c, 0x1040fffd, 0x0, 
+0x10000005, 0x0, 0xaf800048, 0x8f820048, 
+0x1040fffd, 0x0, 0x8f820060, 0x34420008, 
+0xaf820060, 0x8f420000, 0x10400003, 0x0, 
+0x10000041, 0xaf80004c, 0x1000003f, 0xaf800048, 
+0x1040002f, 0x32421000, 0x1040000c, 0x32424000, 
+0x8e23001c, 0x8f420050, 0x622023, 0x4820001, 
+0x24840200, 0x8f42035c, 0x441021, 0xaf42035c, 
+0x8f420368, 0x1000001a, 0xaf430050, 0x1040000c, 
+0x32c28000, 0x8e23001c, 0x8f420070, 0x622023, 
+0x4820001, 0x24840400, 0x8f420364, 0x441021, 
+0xaf420364, 0x8f420368, 0x1000000d, 0xaf430070, 
+0x1040000e, 0x3c020800, 0x8e23001c, 0x8f420060, 
+0x622023, 0x4820001, 0x24840100, 0x8f420360, 
+0x441021, 0xaf420360, 0x8f420368, 0xaf430060, 
+0x441021, 0xaf420368, 0x3c020800, 0x2c21024, 
+0x50400011, 0x36940040, 0x1000000f, 0x0, 
+0x32420048, 0x10400007, 0x24150001, 0x8e22001c, 
+0x3c03ffff, 0x43f024, 0x3042ffff, 0x1000fd75, 
+0xae22001c, 0x32420100, 0x10400003, 0x0, 
+0xc002bd8, 0x0, 0x8fbf0050, 0x8fbe004c, 
 0x8fb50048, 0x8fb30044, 0x8fb20040, 0x8fb1003c, 
 0x8fb00038, 0x3e00008, 0x27bd0058, 0x3e00008, 
 0x0, 0x0, 0x0, 0x8f8300e4, 
@@ -6818,7 +6819,7 @@
 0x10400003, 0x0, 0x8f420148, 0x621821, 
 0x94a20006, 0x24420050, 0x62102b, 0x1440000f, 
 0xa01021, 0xafa40010, 0xafa30014, 0x8ca60000, 
-0x8ca70004, 0x3c040001, 0xc002b17, 0x24846924, 
+0x8ca70004, 0x3c040001, 0xc002b3b, 0x24846894, 
 0x8f42020c, 0x24420001, 0xaf42020c, 0x8f42020c, 
 0x1021, 0xaf9000e8, 0xaf9000e4, 0x8fbf001c, 
 0x8fb00018, 0x3e00008, 0x27bd0020, 0x3e00008, 
@@ -6840,15 +6841,15 @@
 0x8f4b00c4, 0xafab0064, 0x8f4a00c0, 0xafaa006c, 
 0x8f4b00cc, 0xafab0074, 0x8f4a00c8, 0x10000129, 
 0xafaa007c, 0x8f420114, 0x40f809, 0x0, 
-0x403021, 0x10c0033f, 0x0, 0x8cc20000, 
+0x403021, 0x10c0034f, 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, 0xc002497, 
+0x95430004, 0x1062000b, 0x0, 0xc0024bb, 
 0x8fa40064, 0x304200ff, 0x14400006, 0x0, 
-0x8f420118, 0x40f809, 0x0, 0x1000031d, 
+0x8f420118, 0x40f809, 0x0, 0x1000032d, 
 0x0, 0x8fa20024, 0x3c03ffbf, 0x3463ffff, 
 0x431024, 0x3c03ffff, 0x431824, 0x14600003, 
 0xafa20024, 0x10000040, 0x1821, 0x3c020080, 
@@ -6871,13 +6872,13 @@
 0x4b102b, 0x10400014, 0x307000ff, 0x8f4201e8, 
 0x24420001, 0xaf4201e8, 0x8f4201e8, 0x8faa007c, 
 0x8f8200e0, 0x354a0100, 0xafaa007c, 0xafa20010, 
-0x8f8200e4, 0x24100001, 0x3c040001, 0x24846930, 
+0x8f8200e4, 0x24100001, 0x3c040001, 0x248468a0, 
 0xafa20014, 0x8fa60020, 0x8fa70024, 0x3c050007, 
-0xc002b17, 0x34a50800, 0x12000010, 0x3c020080, 
+0xc002b3b, 0x34a50800, 0x12000010, 0x3c020080, 
 0x2c21024, 0x1440000e, 0x32c20400, 0x8fab007c, 
 0x3c020080, 0x34420100, 0x1621024, 0x10400005, 
 0x0, 0x8f42020c, 0x24420001, 0xaf42020c, 
-0x8f42020c, 0x100002a0, 0x8fa3006c, 0x32c20400, 
+0x8f42020c, 0x100002b0, 0x8fa3006c, 0x32c20400, 
 0x10400015, 0x34028100, 0x8faa0064, 0x9543000c, 
 0x14620012, 0x3c020100, 0x240b0200, 0xa7ab008e, 
 0x9542000e, 0x8d430008, 0x8d440004, 0x8d450000, 
@@ -6892,66 +6893,66 @@
 0x10400056, 0x32c28000, 0x1040005e, 0x240a0003, 
 0x32c21000, 0x1040005b, 0xafaa005c, 0x10000058, 
 0x240b0004, 0x8f420350, 0x2403ffbf, 0x283a024, 
-0x24420001, 0xaf420350, 0x1000023f, 0x8f420350, 
+0x24420001, 0xaf420350, 0x1000024f, 0x8f420350, 
 0x2c2b025, 0x2402ffbf, 0x282a024, 0x8f830128, 
-0x3c040001, 0x24846960, 0x26620001, 0xafa20014, 
+0x3c040001, 0x248468d0, 0x26620001, 0xafa20014, 
 0xafa30010, 0x8f860120, 0x8f870124, 0x3c050007, 
-0xc002b17, 0x34a52250, 0x1000022f, 0x0, 
+0xc002b3b, 0x34a52250, 0x1000023f, 0x0, 
 0x2c2b025, 0x2402ffbf, 0x282a024, 0x8f830128, 
-0x3c040001, 0x24846960, 0x24020002, 0xafa20014, 
+0x3c040001, 0x248468d0, 0x24020002, 0xafa20014, 
 0xafa30010, 0x8f860120, 0x8f870124, 0x3c050007, 
-0xc002b17, 0x34a52450, 0x1000021f, 0x0, 
-0x8ea20000, 0x8ea30004, 0x3c040001, 0x24846978, 
+0xc002b3b, 0x34a52450, 0x1000022f, 0x0, 
+0x8ea20000, 0x8ea30004, 0x3c040001, 0x248468e8, 
 0xafb00010, 0xafbe0014, 0x8ea70018, 0x34a52800, 
-0xc002b17, 0x603021, 0x10000213, 0x0, 
-0xa6b1000a, 0x8f820124, 0x3c040001, 0x24846980, 
+0xc002b3b, 0x603021, 0x10000223, 0x0, 
+0xa6b1000a, 0x8f820124, 0x3c040001, 0x248468f0, 
 0xafbe0014, 0xafa20010, 0x8f460044, 0x8f870120, 
-0x3c050007, 0xc002b17, 0x34a53000, 0x10000206, 
+0x3c050007, 0xc002b3b, 0x34a53000, 0x10000216, 
 0x0, 0xa6b1000a, 0xa6b2000e, 0x8f820124, 
-0x3c040001, 0x2484698c, 0xafbe0014, 0xafa20010, 
-0x8f460044, 0x8f870120, 0x3c050007, 0xc002b17, 
-0x34a53200, 0x100001f8, 0x0, 0x8f420084, 
+0x3c040001, 0x248468fc, 0xafbe0014, 0xafa20010, 
+0x8f460044, 0x8f870120, 0x3c050007, 0xc002b3b, 
+0x34a53200, 0x10000208, 0x0, 0x8f420084, 
 0x8faa006c, 0x4a102b, 0x14400007, 0x3c020001, 
 0x2c21024, 0x10400004, 0x0, 0x240b0002, 
-0xafab005c, 0x8faa006c, 0x1140020b, 0x27ab0020, 
+0xafab005c, 0x8faa006c, 0x1140021b, 0x27ab0020, 
 0xafab00a4, 0x3c0a001f, 0x354affff, 0xafaa009c, 
-0x8fab005c, 0x240a0001, 0x156a0021, 0x24020002, 
+0x8fab005c, 0x240a0001, 0x556a0021, 0x240a0002, 
 0x8f430054, 0x8f420050, 0x1062000b, 0x274b0054, 
 0x8f5e0054, 0x3403ecc0, 0xafab004c, 0x27c20001, 
 0x304201ff, 0xafa20054, 0x1e1140, 0x431021, 
 0x1000006b, 0x2e2a821, 0x8f420044, 0x8faa006c, 
-0x3c040001, 0x2484693c, 0xafaa0014, 0xafa20010, 
-0x8f460054, 0x8f470050, 0x3c050007, 0xc002b17, 
+0x3c040001, 0x248468ac, 0xafaa0014, 0xafa20010, 
+0x8f460054, 0x8f470050, 0x3c050007, 0xc002b3b, 
 0x34a51300, 0x8f430350, 0x2402ffbf, 0x282a024, 
-0x24630001, 0xaf430350, 0x100001c3, 0x8f420350, 
-0x1562001d, 0x0, 0x8f430074, 0x8f420070, 
-0x1062000a, 0x274a0074, 0x8f5e0074, 0xafaa004c, 
+0x24630001, 0xaf430350, 0x100001d3, 0x8f420350, 
+0x156a001d, 0x0, 0x8f430074, 0x8f420070, 
+0x1062000a, 0x274b0074, 0x8f5e0074, 0xafab004c, 
 0x27c20001, 0x304203ff, 0xafa20054, 0x1e1140, 
 0x24426cc0, 0x1000004a, 0x2e2a821, 0x8f420044, 
-0x8fab006c, 0x3c040001, 0x24846948, 0x3c050007, 
-0xafab0014, 0xafa20010, 0x8f460074, 0x8f470070, 
-0x34a51500, 0x240a0001, 0xc002b17, 0xafaa005c, 
+0x8faa006c, 0x3c040001, 0x248468b8, 0x3c050007, 
+0xafaa0014, 0xafa20010, 0x8f460074, 0x8f470070, 
+0x34a51500, 0x240b0001, 0xc002b3b, 0xafab005c, 
 0x1000ffc3, 0x0, 0x8f430064, 0x8f420060, 
-0x1062001a, 0x274b0064, 0x8f5e0064, 0x8faa005c, 
-0xafab004c, 0x27c20001, 0x304200ff, 0xafa20054, 
-0x24020004, 0x1542000e, 0x1e1140, 0x1e1180, 
+0x1062001a, 0x274a0064, 0x8f5e0064, 0x8fab005c, 
+0xafaa004c, 0x27c20001, 0x304200ff, 0xafa20054, 
+0x24020004, 0x1562000e, 0x1e1140, 0x1e1180, 
 0x24420cc0, 0x2e21021, 0xafa20044, 0x9442002a, 
-0x8fab0044, 0x8faa006c, 0x4a102b, 0x10400024, 
-0x25750020, 0x240b0001, 0x10000021, 0xa3ab0097, 
+0x8faa0044, 0x8fab006c, 0x4b102b, 0x10400024, 
+0x25550020, 0x240a0001, 0x10000021, 0xa3aa0097, 
 0x24424cc0, 0x1000001e, 0x2e2a821, 0x8f420044, 
-0x8faa006c, 0x3c040001, 0x24846954, 0xafaa0014, 
+0x8fab006c, 0x3c040001, 0x248468c4, 0xafab0014, 
 0xafa20010, 0x8f460064, 0x8f470060, 0x3c050007, 
-0xc002b17, 0x34a51800, 0x3c020008, 0x2c21024, 
-0x1440ff34, 0x0, 0x8f420370, 0x240b0001, 
-0xafab005c, 0x24420001, 0xaf420370, 0x1000ff90, 
+0xc002b3b, 0x34a51800, 0x3c020008, 0x2c21024, 
+0x1440ff34, 0x0, 0x8f420370, 0x240a0001, 
+0xafaa005c, 0x24420001, 0xaf420370, 0x1000ff90, 
 0x8f420370, 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, 
+0x8fab0064, 0xaeab0018, 0x93a20097, 0x10400072, 
+0x9821, 0x8faa0044, 0x8fa4006c, 0x8fa300a4, 
+0x25420020, 0xafa20028, 0x25420008, 0xafa20030, 
+0x25420010, 0xafaa002c, 0xafa20034, 0x9542002a, 
+0xa7a20038, 0x95420018, 0xa7a2003a, 0x9542001a, 
+0xa7a2003c, 0x9542001c, 0xa7a2003e, 0x94620018, 
 0x24630002, 0x822023, 0x1880ffde, 0x26730001, 
 0x2e620004, 0x1440fff9, 0x0, 0x8f4200fc, 
 0x26650001, 0xa2102a, 0x1440002b, 0x24030001, 
@@ -6960,20 +6961,20 @@
 0x8f820128, 0x431023, 0x21943, 0x58600001, 
 0x24630040, 0x64102a, 0x54400001, 0x602021, 
 0xaf4400fc, 0x8f4200fc, 0xa2102a, 0x10400011, 
-0x24030001, 0x10000015, 0x306200ff, 0x8faa0064, 
-0x96070018, 0xafaa0010, 0x8e220008, 0x3c040001, 
-0x2484696c, 0x8c430004, 0x8c420000, 0x34a52400, 
-0x2403021, 0xc002b17, 0xafa30014, 0x1000002b, 
+0x24030001, 0x10000015, 0x306200ff, 0x8fab0064, 
+0x96070018, 0xafab0010, 0x8e220008, 0x3c040001, 
+0x248468dc, 0x8c430004, 0x8c420000, 0x34a52400, 
+0x2403021, 0xc002b3b, 0xafa30014, 0x1000002b, 
 0x0, 0x8f420334, 0x1821, 0x24420001, 
 0xaf420334, 0x8f420334, 0x306200ff, 0x5040fedc, 
 0x3c020800, 0x12600021, 0x9021, 0x8fb100a4, 
 0x2208021, 0x8e220008, 0x96070018, 0x8fa60064, 
-0x8c440000, 0x8c450004, 0x240b0001, 0xafab0010, 
+0x8c440000, 0x8c450004, 0x240a0001, 0xafaa0010, 
 0xafbe0014, 0x8f420008, 0xafa20018, 0x8f42010c, 
 0x40f809, 0x0, 0x1040ffd8, 0x3c050007, 
-0x96020018, 0x8faa0064, 0x8fab009c, 0x1425021, 
-0x16a102b, 0x10400004, 0xafaa0064, 0x8f420148, 
-0x1425023, 0xafaa0064, 0x26100002, 0x26520001, 
+0x96020018, 0x8fab0064, 0x8faa009c, 0x1625821, 
+0x14b102b, 0x10400004, 0xafab0064, 0x8f420148, 
+0x1625823, 0xafab0064, 0x26100002, 0x26520001, 
 0x253102b, 0x1440ffe3, 0x26310004, 0x8fb0006c, 
 0x10000036, 0x97b10038, 0x8f4200fc, 0x24050002, 
 0xa2102a, 0x1440001b, 0x24030001, 0x8f83012c, 
@@ -6986,42 +6987,42 @@
 0x8f420334, 0x306200ff, 0x1040fea5, 0x3c020800, 
 0x96b1000a, 0x8fb0006c, 0x3223ffff, 0x70102b, 
 0x54400001, 0x608021, 0x8ea40000, 0x8ea50004, 
-0x240a0001, 0xafaa0010, 0xafbe0014, 0x8f420008, 
+0x240b0001, 0xafab0010, 0xafbe0014, 0x8f420008, 
 0x8fa60064, 0xafa20018, 0x8f42010c, 0x40f809, 
 0x2003821, 0x1040fea2, 0x3c050007, 0x96a3000e, 
-0x97ab008e, 0x11600007, 0x609021, 0x934205c4, 
-0x14400004, 0x0, 0x97aa0086, 0x6b1825, 
-0xa6aa0016, 0x8fab007c, 0x3c02ffff, 0x1621024, 
-0x10400003, 0xb1402, 0x34630400, 0xa6a20014, 
-0x8faa006c, 0x560a0072, 0xa6a3000e, 0x34620004, 
-0xa6a2000e, 0x8fab0074, 0x14b1021, 0xa6a2000a, 
+0x97aa008e, 0x11400007, 0x609021, 0x934205c4, 
+0x14400004, 0x0, 0x97ab0086, 0x6a1825, 
+0xa6ab0016, 0x8faa007c, 0x3c02ffff, 0x1421024, 
+0x10400003, 0xa1402, 0x34630400, 0xa6a20014, 
+0x8fab006c, 0x560b0072, 0xa6a3000e, 0x34620004, 
+0xa6a2000e, 0x8faa0074, 0x16a1021, 0xa6a2000a, 
 0x8f430044, 0x8f4401a0, 0x8f4501a4, 0x34028000, 
 0xafa20010, 0x8f420044, 0x2a03021, 0x24070020, 
 0xafa20014, 0x8f42000c, 0x31940, 0x604821, 
 0xafa20018, 0x8f42010c, 0x4021, 0xa92821, 
 0xa9182b, 0x882021, 0x40f809, 0x832021, 
 0x5040fe7f, 0xa6b2000e, 0x8f420368, 0xafa0006c, 
-0xa34005c4, 0x2442ffff, 0xaf420368, 0x8faa005c, 
-0x240b0001, 0x8f420368, 0x154b0006, 0x24020002, 
+0xa34005c4, 0x2442ffff, 0xaf420368, 0x8fab005c, 
+0x240a0001, 0x8f420368, 0x156a0006, 0x240a0002, 
 0x8f42035c, 0x2442ffff, 0xaf42035c, 0x1000000c, 
-0x8f42035c, 0x15420006, 0x0, 0x8f420364, 
+0x8f42035c, 0x156a0006, 0x0, 0x8f420364, 
 0x2442ffff, 0xaf420364, 0x10000005, 0x8f420364, 
 0x8f420360, 0x2442ffff, 0xaf420360, 0x8f420360, 
 0x8faa0054, 0x8fab004c, 0xad6a0000, 0x8f420044, 
 0x8f440088, 0x8f430078, 0x24420001, 0x441024, 
 0x24630001, 0xaf420044, 0xaf430078, 0x8c020240, 
-0x62182b, 0x14600065, 0x24070008, 0x8f440168, 
+0x62182b, 0x14600075, 0x24070008, 0x8f440168, 
 0x8f45016c, 0x8f430044, 0x8f48000c, 0x8f860120, 
 0x24020040, 0xafa20010, 0xafa30014, 0xafa80018, 
 0x8f42010c, 0x40f809, 0x24c6001c, 0x14400011, 
 0x240b0001, 0x3c010001, 0x370821, 0xa02b40f2, 
 0x8f820124, 0xafa20010, 0x8f820128, 0x3c040001, 
-0x2484691c, 0xafa20014, 0x8f460044, 0x8f870120, 
-0x3c050009, 0xc002b17, 0x34a51300, 0x1000000b, 
+0x2484688c, 0xafa20014, 0x8f460044, 0x8f870120, 
+0x3c050009, 0xc002b3b, 0x34a51300, 0x1000000b, 
 0x0, 0x8f420304, 0x24420001, 0xaf420304, 
 0x8f420304, 0x8f420044, 0xaf42007c, 0x3c010001, 
 0x370821, 0xa02040f2, 0xaf400078, 0x8f420318, 
-0x24420001, 0xaf420318, 0x10000038, 0x8f420318, 
+0x24420001, 0xaf420318, 0x10000048, 0x8f420318, 
 0xa6b0000a, 0x8f430044, 0x8f4401a0, 0x8f4501a4, 
 0x34028000, 0xafa20010, 0x8f420044, 0x2a03021, 
 0x24070020, 0xafa20014, 0x8f42000c, 0x31940, 
@@ -7031,12 +7032,16 @@
 0x8fab006c, 0x8faa0064, 0x1705823, 0xafab006c, 
 0x8fab009c, 0x1505021, 0x16a102b, 0x10400004, 
 0xafaa0064, 0x8f420148, 0x1425023, 0xafaa0064, 
-0x8f420368, 0x2442ffff, 0xaf420368, 0x8f420368, 
-0x8f42035c, 0x2442ffff, 0xaf42035c, 0x8fab0054, 
-0x8faa004c, 0x8f42035c, 0xad4b0000, 0x8f420044, 
+0x8f420368, 0x2442ffff, 0xaf420368, 0x8faa005c, 
+0x240b0001, 0x8f420368, 0x154b0006, 0x240b0002, 
+0x8f42035c, 0x2442ffff, 0xaf42035c, 0x1000000c, 
+0x8f42035c, 0x114b0006, 0x0, 0x8f420360, 
+0x2442ffff, 0xaf420360, 0x10000005, 0x8f420360, 
+0x8f420364, 0x2442ffff, 0xaf420364, 0x8f420364, 
+0x8fab0054, 0x8faa004c, 0xad4b0000, 0x8f420044, 
 0x8f440088, 0x8f430078, 0x24420001, 0x441024, 
 0x24630001, 0xaf420044, 0xaf430078, 0x8faa006c, 
-0x1540fe1b, 0x0, 0x8fab006c, 0x1160001e, 
+0x1540fe0b, 0x0, 0x8fab006c, 0x1160001e, 
 0x0, 0x934205c4, 0x10400009, 0x0, 
 0x8faa0064, 0xaf4a00c4, 0xaf4b00c0, 0x8fab007c, 
 0xaf4b00c8, 0x8faa0074, 0x1000000e, 0xaf4a00cc, 
@@ -7063,7 +7068,7 @@
 0xafa20064, 0x3c020006, 0x2c21024, 0x14400015, 
 0xafac006c, 0x93c20000, 0x30420001, 0x10400011, 
 0x2402ffff, 0x8fc30000, 0x14620004, 0x3402ffff, 
-0x97c30004, 0x1062000b, 0x0, 0xc002497, 
+0x97c30004, 0x1062000b, 0x0, 0xc0024bb, 
 0x3c02021, 0x304200ff, 0x14400006, 0x0, 
 0x8f420118, 0x40f809, 0x0, 0x10000280, 
 0x0, 0x8fa20024, 0x3c03ffbf, 0x3463ffff, 
@@ -7088,9 +7093,9 @@
 0x4b102b, 0x10400015, 0x320200ff, 0x8f4201e8, 
 0x24420001, 0xaf4201e8, 0x8f4201e8, 0x8fac006c, 
 0x8f8200e0, 0x358c0100, 0xafac006c, 0xafa20010, 
-0x8f8200e4, 0x24100001, 0x3c040001, 0x24846930, 
+0x8f8200e4, 0x24100001, 0x3c040001, 0x248468a0, 
 0xafa20014, 0x8fa60020, 0x8fa70024, 0x3c050007, 
-0xc002b17, 0x34a53600, 0x320200ff, 0x10400010, 
+0xc002b3b, 0x34a53600, 0x320200ff, 0x10400010, 
 0x3c020080, 0x2c21024, 0x1440000e, 0x32c20400, 
 0x8fab006c, 0x3c020080, 0x34420100, 0x1621024, 
 0x10400005, 0x0, 0x8f42020c, 0x24420001, 
@@ -7115,8 +7120,8 @@
 0x2c420001, 0x621825, 0x10600004, 0x3c020100, 
 0x94820002, 0x453821, 0x3c020100, 0x2c21024, 
 0x5040000e, 0xafa70064, 0x8fac0064, 0x10ec0008, 
-0x3c050007, 0x3c040001, 0x24846998, 0x8fa60064, 
-0x34a54000, 0xafa00010, 0xc002b17, 0xafa00014, 
+0x3c050007, 0x3c040001, 0x24846908, 0x8fa60064, 
+0x34a54000, 0xafa00010, 0xc002b3b, 0xafa00014, 
 0x8fab0064, 0x256b0004, 0xafab0064, 0x8f420080, 
 0x8fac0064, 0x4c102b, 0x1040002c, 0x32c28000, 
 0x10400034, 0x240b0003, 0x32c21000, 0x10400031, 
@@ -7124,11 +7129,11 @@
 0x2403ffbf, 0x283a024, 0x24420001, 0xaf420350, 
 0x10000173, 0x8f420350, 0x3c020800, 0x2c2b025, 
 0x2402ffbf, 0x282a024, 0x8f830128, 0x3c040001, 
-0x24846960, 0x26620001, 0xafa20014, 0xafa30010, 
-0x8f860120, 0x8f870124, 0x3c050007, 0xc002b17, 
+0x248468d0, 0x26620001, 0xafa20014, 0xafa30010, 
+0x8f860120, 0x8f870124, 0x3c050007, 0xc002b3b, 
 0x34a55300, 0x10000162, 0x0, 0x8ea20000, 
-0x8ea30004, 0x3c040001, 0x24846978, 0xafb00010, 
-0xafb10014, 0x8ea70018, 0x34a55900, 0xc002b17, 
+0x8ea30004, 0x3c040001, 0x248468e8, 0xafb00010, 
+0xafb10014, 0x8ea70018, 0x34a55900, 0xc002b3b, 
 0x603021, 0x10000156, 0x0, 0x8f420084, 
 0x8fab0064, 0x4b102b, 0x14400007, 0x3c020001, 
 0x2c21024, 0x10400004, 0x0, 0x240c0002, 
@@ -7138,17 +7143,17 @@
 0x274b0054, 0x8f510054, 0x3403ecc0, 0xafab004c, 
 0x26220001, 0x304201ff, 0xafa20054, 0x111140, 
 0x431021, 0x1000006b, 0x2e2a821, 0x8f420044, 
-0x8fac0064, 0x3c040001, 0x2484693c, 0xafac0014, 
+0x8fac0064, 0x3c040001, 0x248468ac, 0xafac0014, 
 0xafa20010, 0x8f460054, 0x8f470050, 0x3c050007, 
-0xc002b17, 0x34a54300, 0x8f430350, 0x2402ffbf, 
+0xc002b3b, 0x34a54300, 0x8f430350, 0x2402ffbf, 
 0x282a024, 0x24630001, 0xaf430350, 0x10000124, 
 0x8f420350, 0x156c001d, 0x0, 0x8f430074, 
 0x8f420070, 0x1062000a, 0x274b0074, 0x8f510074, 
 0xafab004c, 0x26220001, 0x304203ff, 0xafa20054, 
 0x111140, 0x24426cc0, 0x1000004a, 0x2e2a821, 
-0x8f420044, 0x8fac0064, 0x3c040001, 0x24846948, 
+0x8f420044, 0x8fac0064, 0x3c040001, 0x248468b8, 
 0x3c050007, 0xafac0014, 0xafa20010, 0x8f460074, 
-0x8f470070, 0x34a54500, 0x240b0001, 0xc002b17, 
+0x8f470070, 0x34a54500, 0x240b0001, 0xc002b3b, 
 0xafab005c, 0x1000ffc3, 0x0, 0x8f430064, 
 0x8f420060, 0x1062001a, 0x274c0064, 0x8f510064, 
 0x8fab005c, 0xafac004c, 0x26220001, 0x304200ff, 
@@ -7157,9 +7162,9 @@
 0x9442002a, 0x8fac0044, 0x8fab0064, 0x4b102b, 
 0x10400024, 0x25950020, 0x240c0001, 0x10000021, 
 0xa3ac0087, 0x24424cc0, 0x1000001e, 0x2e2a821, 
-0x8f420044, 0x8fab0064, 0x3c040001, 0x24846954, 
+0x8f420044, 0x8fab0064, 0x3c040001, 0x248468c4, 
 0xafab0014, 0xafa20010, 0x8f460064, 0x8f470060, 
-0x3c050007, 0xc002b17, 0x34a54800, 0x3c020008, 
+0x3c050007, 0xc002b3b, 0x34a54800, 0x3c020008, 
 0x2c21024, 0x1440ff61, 0x0, 0x8f420370, 
 0x240c0001, 0xafac005c, 0x24420001, 0xaf420370, 
 0x1000ff90, 0x8f420370, 0x27a30036, 0x131040, 
@@ -7180,9 +7185,9 @@
 0x8f4200fc, 0x262102a, 0x10400016, 0x24030001, 
 0x1000001a, 0x306200ff, 0x8fac008c, 0x101040, 
 0x4c1021, 0x94470018, 0x101080, 0x4c1021, 
-0xafbe0010, 0x8c420008, 0x3c040001, 0x2484696c, 
+0xafbe0010, 0x8c420008, 0x3c040001, 0x248468dc, 
 0x3c050007, 0x8c430004, 0x8c420000, 0x34a55500, 
-0x2003021, 0xc002b17, 0xafa30014, 0x10000039, 
+0x2003021, 0xc002b3b, 0xafa30014, 0x10000039, 
 0x0, 0x8f420334, 0x1821, 0x24420001, 
 0xaf420334, 0x8f420334, 0x306200ff, 0x1040ff06, 
 0x8021, 0x8f430008, 0x2402fbff, 0x1260002d, 
@@ -7399,7 +7404,7 @@
 0x822023, 0x94820000, 0x2028021, 0x3c020100, 
 0x2c21024, 0x1040000e, 0x0, 0x8faa002c, 
 0x31420004, 0x1040000a, 0x0, 0x9504000e, 
-0x2642021, 0xc003ec4, 0x2484fffc, 0x3042ffff, 
+0x2642021, 0xc003eec, 0x2484fffc, 0x3042ffff, 
 0x2228821, 0x111c02, 0x3222ffff, 0x628821, 
 0x8faa0024, 0x1518823, 0x111402, 0x2228821, 
 0x2308821, 0x111402, 0x2228821, 0x3231ffff, 
@@ -7412,8 +7417,8 @@
 0xafa80018, 0x8f48010c, 0x1021, 0xa32821, 
 0xa3482b, 0x822021, 0x100f809, 0x892021, 
 0x1440000b, 0x0, 0x8f820128, 0x3c040001, 
-0x248469a4, 0xafbe0014, 0xafa20010, 0x8f860124, 
-0x8f870120, 0x3c050007, 0xc002b17, 0x34a59920, 
+0x24846914, 0xafbe0014, 0xafa20010, 0x8f860124, 
+0x8f870120, 0x3c050007, 0xc002b3b, 0x34a59920, 
 0x8f420368, 0x2442ffff, 0xaf420368, 0x8f420044, 
 0x8f430088, 0x24420001, 0x431024, 0xaf420044, 
 0x8faa0034, 0x8f440368, 0x24020001, 0x15420006, 
@@ -7430,9 +7435,9 @@
 0xafa20010, 0xafa30014, 0xafa80018, 0x8f42010c, 
 0x40f809, 0x24c6001c, 0x14400011, 0x24020001, 
 0x3c010001, 0x370821, 0xa02240f2, 0x8f820124, 
-0xafa20010, 0x8f820128, 0x3c040001, 0x2484691c, 
+0xafa20010, 0x8f820128, 0x3c040001, 0x2484688c, 
 0xafa20014, 0x8f460044, 0x8f870120, 0x3c050009, 
-0xc002b17, 0x34a51300, 0x1000000b, 0x0, 
+0xc002b3b, 0x34a51300, 0x1000000b, 0x0, 
 0x8f420304, 0x24420001, 0xaf420304, 0x8f420304, 
 0x8f420044, 0xaf42007c, 0x3c010001, 0x370821, 
 0xa02040f2, 0xaf400078, 0x8f420318, 0x24420001, 
@@ -7444,32 +7449,32 @@
 0xaf8200c8, 0x8f420138, 0xaf8200d0, 0x8f420138, 
 0xaf8200d4, 0x8f420138, 0x3e00008, 0xaf8200d8, 
 0x27bdffe0, 0x27840208, 0x24050200, 0xafbf0018, 
-0xc002b9b, 0x24060008, 0x8c020204, 0xc003fea, 
-0xaf820210, 0x3c020001, 0x8c426e14, 0x30420002, 
+0xc002bbf, 0x24060008, 0x8c020204, 0xc004012, 
+0xaf820210, 0x3c020001, 0x8c426d94, 0x30420002, 
 0x1040000e, 0x2021, 0x8c060248, 0x24020002, 
-0x3c010001, 0xac226e18, 0xc005134, 0x24050002, 
+0x3c010001, 0xac226d98, 0xc005104, 0x24050002, 
 0x2021, 0x8c060248, 0x24020001, 0x3c010001, 
-0xac226e18, 0x10000011, 0x24050001, 0x8c060248, 
-0x24020004, 0x3c010001, 0xac226e18, 0xc005134, 
-0x24050004, 0x3c020001, 0x8c426e14, 0x30420001, 
-0x10400008, 0x24020001, 0x3c010001, 0xac226e18, 
-0x2021, 0x24050001, 0x3c06601b, 0xc005134, 
-0x0, 0x3c040001, 0x24846a60, 0x8f420150, 
+0xac226d98, 0x10000011, 0x24050001, 0x8c060248, 
+0x24020004, 0x3c010001, 0xac226d98, 0xc005104, 
+0x24050004, 0x3c020001, 0x8c426d94, 0x30420001, 
+0x10400008, 0x24020001, 0x3c010001, 0xac226d98, 
+0x2021, 0x24050001, 0x3c06601b, 0xc005104, 
+0x0, 0x3c040001, 0x248469d0, 0x8f420150, 
 0x8f430154, 0x3c050008, 0x8f460158, 0x21640, 
 0x31940, 0x34630403, 0x431025, 0x633c0, 
 0x461025, 0xaf82021c, 0xafa00010, 0xafa00014, 
-0x8f86021c, 0x34a50200, 0xc002b17, 0x3821, 
-0x3c010001, 0xac206e10, 0x3c010001, 0xac206e28, 
+0x8f86021c, 0x34a50200, 0xc002b3b, 0x3821, 
+0x3c010001, 0xac206d90, 0x3c010001, 0xac206da8, 
 0x8fbf0018, 0x3e00008, 0x27bd0020, 0x27bdffe0, 
 0x3c050008, 0x34a50300, 0xafbf0018, 0xafa00010, 
-0xafa00014, 0x8f860200, 0x3c040001, 0x24846a6c, 
-0xc002b17, 0x3821, 0x8f420410, 0x24420001, 
+0xafa00014, 0x8f860200, 0x3c040001, 0x248469dc, 
+0xc002b3b, 0x3821, 0x8f420410, 0x24420001, 
 0xaf420410, 0x8f420410, 0x8fbf0018, 0x3e00008, 
 0x27bd0020, 0x27bdffd8, 0xafbf0020, 0xafb1001c, 
 0xafb00018, 0x8f4203a4, 0x24420001, 0xaf4203a4, 
 0x8f4203a4, 0x8f900220, 0x8f8200e0, 0xafa20010, 
 0x8f8200e4, 0xafa20014, 0x8f8600c4, 0x8f8700c8, 
-0x3c040001, 0x24846a78, 0xc002b17, 0x2002821, 
+0x3c040001, 0x248469e8, 0xc002b3b, 0x2002821, 
 0x3c044000, 0x2041024, 0x504000b4, 0x3c040100, 
 0x8f4203bc, 0x24420001, 0xaf4203bc, 0x8f4203bc, 
 0x8f8700c4, 0x8f8300c8, 0x8f420148, 0x671823, 
@@ -7518,26 +7523,26 @@
 0xaf4303cc, 0x10000039, 0x8f4203cc, 0x2041024, 
 0x1040000e, 0x3c110200, 0x8f4203a8, 0x24420001, 
 0xaf4203a8, 0x8f4203a8, 0x8f820220, 0x3c0308ff, 
-0x3463ffff, 0x431024, 0x441025, 0xc003d87, 
+0x3463ffff, 0x431024, 0x441025, 0xc003daf, 
 0xaf820220, 0x10000029, 0x0, 0x2111024, 
 0x50400008, 0x3c110400, 0x8f4203ac, 0x24420001, 
-0xaf4203ac, 0xc003d87, 0x8f4203ac, 0x10000019, 
+0xaf4203ac, 0xc003daf, 0x8f4203ac, 0x10000019, 
 0x0, 0x2111024, 0x1040001c, 0x0, 
 0x8f830224, 0x24021402, 0x14620009, 0x3c050008, 
-0x3c040001, 0x24846a84, 0xafa00010, 0xafa00014, 
-0x8f860224, 0x34a50500, 0xc002b17, 0x3821, 
+0x3c040001, 0x248469f4, 0xafa00010, 0xafa00014, 
+0x8f860224, 0x34a50500, 0xc002b3b, 0x3821, 
 0x8f4203b0, 0x24420001, 0xaf4203b0, 0x8f4203b0, 
-0x8f820220, 0x2002021, 0x34420002, 0xc004ecc, 
+0x8f820220, 0x2002021, 0x34420002, 0xc004e9c, 
 0xaf820220, 0x8f820220, 0x3c0308ff, 0x3463ffff, 
 0x431024, 0x511025, 0xaf820220, 0x8fbf0020, 
 0x8fb1001c, 0x8fb00018, 0x3e00008, 0x27bd0028, 
-0x3e00008, 0x0, 0x3c020001, 0x8c426e28, 
+0x3e00008, 0x0, 0x3c020001, 0x8c426da8, 
 0x27bdffb0, 0xafbf0048, 0xafbe0044, 0xafb50040, 
 0xafb3003c, 0xafb20038, 0xafb10034, 0x1040000f, 
-0xafb00030, 0x3c040001, 0x24846a90, 0x3c050008, 
+0xafb00030, 0x3c040001, 0x24846a00, 0x3c050008, 
 0xafa00010, 0xafa00014, 0x8f860220, 0x34a50600, 
-0x24020001, 0x3c010001, 0xac206e28, 0x3c010001, 
-0xac226e1c, 0xc002b17, 0x3821, 0x3c037fff, 
+0x24020001, 0x3c010001, 0xac206da8, 0x3c010001, 
+0xac226d9c, 0xc002b3b, 0x3821, 0x3c037fff, 
 0x8c020268, 0x3463ffff, 0x3c04fdff, 0x431024, 
 0xac020268, 0x8f420004, 0x3484ffff, 0x30420002, 
 0x10400092, 0x284a024, 0x3c040600, 0x34842000, 
@@ -7546,7 +7551,7 @@
 0x240200ff, 0x13c20002, 0xafaa002c, 0x27c50001, 
 0x8c020228, 0xa09021, 0x1642000e, 0x1e38c0, 
 0x8f42033c, 0x24420001, 0xaf42033c, 0x8f42033c, 
-0x8c020228, 0x3c040001, 0x24846a28, 0x3c050009, 
+0x8c020228, 0x3c040001, 0x24846998, 0x3c050009, 
 0xafa00014, 0xafa20010, 0x8fa60020, 0x1000006d, 
 0x34a50500, 0xf71021, 0x8fa30020, 0x8fa40024, 
 0xac4304c0, 0xac4404c4, 0x8f830054, 0x8f820054, 
@@ -7560,7 +7565,7 @@
 0x2c4203e9, 0x1440ffe9, 0x0, 0x326200ff, 
 0x54400017, 0xaf520018, 0x8f420378, 0x24420001, 
 0xaf420378, 0x8f420378, 0x8f820120, 0x8faa002c, 
-0xafa20010, 0x8f820124, 0x3c040001, 0x24846a34, 
+0xafa20010, 0x8f820124, 0x3c040001, 0x248469a4, 
 0x3c050009, 0xafa20014, 0x8d460000, 0x10000035, 
 0x34a50600, 0x8f420308, 0x24130001, 0x24420001, 
 0xaf420308, 0x8f420308, 0x1000001e, 0x326200ff, 
@@ -7574,21 +7579,21 @@
 0x326200ff, 0x14400011, 0x0, 0x8f420378, 
 0x24420001, 0xaf420378, 0x8f420378, 0x8f820120, 
 0x8faa002c, 0xafa20010, 0x8f820124, 0x3c040001, 
-0x24846a3c, 0x3c050009, 0xafa20014, 0x8d460000, 
-0x34a50700, 0xc002b17, 0x3c03821, 0x8f4202ec, 
+0x248469ac, 0x3c050009, 0xafa20014, 0x8d460000, 
+0x34a50700, 0xc002b3b, 0x3c03821, 0x8f4202ec, 
 0x24420001, 0xaf4202ec, 0x8f4202ec, 0x8fbf0048, 
 0x8fbe0044, 0x8fb50040, 0x8fb3003c, 0x8fb20038, 
 0x8fb10034, 0x8fb00030, 0x3e00008, 0x27bd0050, 
-0x3c020001, 0x8c426e28, 0x27bdffe0, 0x1440000d, 
-0xafbf0018, 0x3c040001, 0x24846a9c, 0x3c050008, 
+0x3c020001, 0x8c426da8, 0x27bdffe0, 0x1440000d, 
+0xafbf0018, 0x3c040001, 0x24846a0c, 0x3c050008, 
 0xafa00010, 0xafa00014, 0x8f860220, 0x34a50700, 
-0x24020001, 0x3c010001, 0xac226e28, 0xc002b17, 
+0x24020001, 0x3c010001, 0xac226da8, 0xc002b3b, 
 0x3821, 0x3c020004, 0x2c21024, 0x10400007, 
 0x0, 0x8f820220, 0x3c0308ff, 0x3463ffff, 
 0x431024, 0x34420008, 0xaf820220, 0x3c050001, 
-0x8ca56e18, 0x24020001, 0x14a20007, 0x2021, 
-0xc0052c7, 0x24050001, 0xac02026c, 0x8c03026c, 
-0x10000006, 0x3c020007, 0xc0052c7, 0x2021, 
+0x8ca56d98, 0x24020001, 0x14a20007, 0x2021, 
+0xc00529b, 0x24050001, 0xac02026c, 0x8c03026c, 
+0x10000006, 0x3c020007, 0xc00529b, 0x2021, 
 0xac020268, 0x8c030268, 0x3c020007, 0x621824, 
 0x3c020002, 0x5062000d, 0x3c0205f5, 0x43102b, 
 0x14400006, 0x3c020004, 0x3c020001, 0x10620009, 
@@ -7636,7 +7641,7 @@
 0x90a20000, 0x822021, 0x41c02, 0x3082ffff, 
 0x622021, 0x41c02, 0x3082ffff, 0x622021, 
 0x3e00008, 0x3082ffff, 0x0, 0x8f820220, 
-0x34420002, 0xaf820220, 0x3c020002, 0x8c429078, 
+0x34420002, 0xaf820220, 0x3c020002, 0x8c428ff8, 
 0x30424000, 0x10400054, 0x24040001, 0x8f820200, 
 0x24067fff, 0x8f830200, 0x30450002, 0x2402fffd, 
 0x621824, 0xaf830200, 0xaf840204, 0x8f830054, 
@@ -7683,1091 +7688,1069 @@
 0x43102b, 0x14400006, 0x3c026000, 0x3c024000, 
 0x10620008, 0x24020800, 0x10000008, 0x0, 
 0x10620004, 0x24020800, 0x10000004, 0x0, 
-0x24020700, 0x3c010001, 0xac226e2c, 0x3e00008, 
-0x0, 0x3c020001, 0x8c426e3c, 0x27bdffc8, 
-0xafbf0034, 0xafb20030, 0xafb1002c, 0xafb00028, 
-0x3c010001, 0x10400005, 0xac206e14, 0xc004dd1, 
-0x0, 0x3c010001, 0xac206e3c, 0x8f830054, 
+0x24020700, 0x3c010001, 0xac226dac, 0x3e00008, 
+0x0, 0x3c020001, 0x8c426dbc, 0x27bdffd0, 
+0xafbf002c, 0xafb20028, 0xafb10024, 0xafb00020, 
+0x3c010001, 0x10400005, 0xac206d94, 0xc004d9e, 
+0x0, 0x3c010001, 0xac206dbc, 0x8f830054, 
 0x8f820054, 0x10000002, 0x24630064, 0x8f820054, 
 0x621023, 0x2c420065, 0x1440fffc, 0x0, 
-0xc004dec, 0x0, 0x24040001, 0x2821, 
-0x27a60020, 0x34028000, 0xc00450e, 0xa7a20020, 
+0xc004db9, 0x0, 0x24040001, 0x2821, 
+0x27a60018, 0x34028000, 0xc0045be, 0xa7a20018, 
 0x8f830054, 0x8f820054, 0x10000002, 0x24630064, 
 0x8f820054, 0x621023, 0x2c420065, 0x1440fffc, 
-0x24040001, 0x24050001, 0xc0044cc, 0x27a60020, 
+0x24040001, 0x24050001, 0xc00457c, 0x27a60018, 
 0x8f830054, 0x8f820054, 0x10000002, 0x24630064, 
 0x8f820054, 0x621023, 0x2c420065, 0x1440fffc, 
-0x24040001, 0x24050001, 0xc0044cc, 0x27a60020, 
+0x24040001, 0x24050001, 0xc00457c, 0x27a60018, 
 0x8f830054, 0x8f820054, 0x10000002, 0x24630064, 
 0x8f820054, 0x621023, 0x2c420065, 0x1440fffc, 
-0x24040001, 0x24050002, 0xc0044cc, 0x27a60018, 
-0x8f830054, 0x8f820054, 0x10000002, 0x24630064, 
-0x8f820054, 0x621023, 0x2c420065, 0x1440fffc, 
-0x24040001, 0x24050003, 0xc0044cc, 0x27a6001a, 
-0x3c040001, 0x24846b70, 0x97a60020, 0x97a70018, 
-0x97a2001a, 0x3c05000d, 0x34a50100, 0xafa00014, 
-0xc002b17, 0xafa20010, 0x97a20020, 0x10400046, 
-0x24036040, 0x97a2001a, 0x3042fff0, 0x1443000b, 
-0x24020020, 0x97a30018, 0x1462000a, 0x24027830, 
-0x24020003, 0x3c010001, 0xac226e14, 0x24020005, 
-0x3c010001, 0x10000039, 0xac226fac, 0x97a30018, 
-0x24027830, 0x1462000b, 0x24030010, 0x97a2001a, 
-0x3042fff0, 0x14430007, 0x24020003, 0x3c010001, 
-0xac226e14, 0x24020006, 0x3c010001, 0x1000002b, 
-0xac226fac, 0x3c020001, 0x8c426e14, 0x97a30018, 
-0x34420001, 0x3c010001, 0xac226e14, 0x24020015, 
-0x1462000a, 0x0, 0x97a2001a, 0x3042fff0, 
-0x3843f420, 0x2c630001, 0x3842f430, 0x2c420001, 
-0x621825, 0x14600019, 0x24020003, 0x97a30018, 
-0x24027810, 0x14620015, 0x24020002, 0x97a2001a, 
-0x3042fff0, 0x14400011, 0x24020002, 0x1000000f, 
-0x24020004, 0x3c020001, 0x8c426e14, 0x34420008, 
-0x3c010001, 0xac226e14, 0x1000005e, 0x24020004, 
-0x3c020001, 0x8c426e14, 0x34420004, 0x3c010001, 
-0x100000af, 0xac226e14, 0x24020001, 0x3c010001, 
-0xac226fb8, 0x3c020001, 0x8c426e14, 0x30420002, 
-0x144000b2, 0x3c09fff0, 0x24020e00, 0xaf820238, 
-0x8f840054, 0x8f820054, 0x24030008, 0x3c010001, 
-0xac236e18, 0x10000002, 0x248401f4, 0x8f820054, 
-0x821023, 0x2c4201f5, 0x1440fffc, 0x3c0200c8, 
-0x344201fb, 0xaf820238, 0x8f830054, 0x8f820054, 
-0x10000002, 0x246301f4, 0x8f820054, 0x621023, 
-0x2c4201f5, 0x1440fffc, 0x8021, 0x24120001, 
-0x24110009, 0xc0043d3, 0x0, 0x3c010001, 
-0xac326e34, 0xc004498, 0x0, 0x3c020001, 
-0x8c426e34, 0x1451fffb, 0x3c0200c8, 0x344201f6, 
+0x24040001, 0x3c060001, 0x24c66f24, 0xc00457c, 
+0x24050002, 0x8f830054, 0x8f820054, 0x10000002, 
+0x24630064, 0x8f820054, 0x621023, 0x2c420065, 
+0x1440fffc, 0x24040001, 0x24050003, 0x3c100001, 
+0x26106f26, 0xc00457c, 0x2003021, 0x97a60018, 
+0x3c070001, 0x94e76f24, 0x3c040001, 0x24846ae0, 
+0xafa00014, 0x96020000, 0x3c05000d, 0x34a50100, 
+0xc002b3b, 0xafa20010, 0x97a20018, 0x1040004d, 
+0x24036040, 0x96020000, 0x3042fff0, 0x1443000c, 
+0x24020020, 0x3c030001, 0x94636f24, 0x1462000b, 
+0x24027830, 0x24020003, 0x3c010001, 0xac226d94, 
+0x24020005, 0x3c010001, 0x1000003f, 0xac226f34, 
+0x3c030001, 0x94636f24, 0x24027830, 0x1462000c, 
+0x24030010, 0x3c020001, 0x94426f26, 0x3042fff0, 
+0x14430007, 0x24020003, 0x3c010001, 0xac226d94, 
+0x24020006, 0x3c010001, 0x1000002f, 0xac226f34, 
+0x3c020001, 0x8c426d94, 0x3c030001, 0x94636f24, 
+0x34420001, 0x3c010001, 0xac226d94, 0x24020015, 
+0x1462000b, 0x0, 0x3c020001, 0x94426f26, 
+0x3042fff0, 0x3843f420, 0x2c630001, 0x3842f430, 
+0x2c420001, 0x621825, 0x1460001b, 0x24020003, 
+0x3c030001, 0x94636f24, 0x24027810, 0x14620016, 
+0x24020002, 0x3c020001, 0x94426f26, 0x3042fff0, 
+0x14400011, 0x24020002, 0x1000000f, 0x24020004, 
+0x3c020001, 0x8c426d94, 0x34420008, 0x3c010001, 
+0xac226d94, 0x1000005e, 0x24020004, 0x3c020001, 
+0x8c426d94, 0x34420004, 0x3c010001, 0x100000af, 
+0xac226d94, 0x24020001, 0x3c010001, 0xac226f40, 
+0x3c020001, 0x8c426d94, 0x30420002, 0x144000b2, 
+0x3c09fff0, 0x24020e00, 0xaf820238, 0x8f840054, 
+0x8f820054, 0x24030008, 0x3c010001, 0xac236d98, 
+0x10000002, 0x248401f4, 0x8f820054, 0x821023, 
+0x2c4201f5, 0x1440fffc, 0x3c0200c8, 0x344201fb, 
 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, 
-0x1082ffa0, 0x26100001, 0x2e020014, 0x1440ffcd, 
-0x24020004, 0x3c010001, 0xac226e18, 0x8021, 
-0x24120009, 0x3c11ffff, 0x36313f7f, 0xc0043d3, 
-0x0, 0x24020001, 0x3c010001, 0xac226e34, 
-0xc004498, 0x0, 0x3c020001, 0x8c426e34, 
-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, 
+0x246301f4, 0x8f820054, 0x621023, 0x2c4201f5, 
+0x1440fffc, 0x8021, 0x24120001, 0x24110009, 
+0xc004482, 0x0, 0x3c010001, 0xac326db4, 
+0xc004547, 0x0, 0x3c020001, 0x8c426db4, 
+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, 0x1082ff50, 
-0x26100001, 0x2e020064, 0x1440ffb0, 0x0, 
-0x3c020001, 0x8c426e14, 0x30420004, 0x14400007, 
-0x3c09fff0, 0x8f820044, 0x3c03ffff, 0x34633f7f, 
-0x431024, 0xaf820044, 0x3c09fff0, 0x3529bdc0, 
-0x8f830054, 0x3c060001, 0x8cc66e14, 0x3c070001, 
-0x8ce76fb8, 0x97a80018, 0x3c040001, 0x24846b70, 
-0x24020001, 0x3c010001, 0xac226e1c, 0xafa80010, 
-0x97a2001a, 0x3c05000d, 0x34a50100, 0x3c010001, 
-0xac206e18, 0x691821, 0x3c010001, 0xac236fa8, 
-0xc002b17, 0xafa20014, 0x8fbf0034, 0x8fb20030, 
-0x8fb1002c, 0x8fb00028, 0x3e00008, 0x27bd0038, 
-0x27bdffe8, 0x3c050001, 0x8ca56e18, 0x24060004, 
-0x24020001, 0x14a20014, 0xafbf0010, 0x3c020002, 
-0x8c42907c, 0x30428000, 0x10400005, 0x3c04000f, 
-0x3c030001, 0x8c636fb8, 0x10000005, 0x34844240, 
-0x3c040004, 0x3c030001, 0x8c636fb8, 0x348493e0, 
-0x24020005, 0x14620016, 0x0, 0x3c04003d, 
-0x10000013, 0x34840900, 0x3c020002, 0x8c429078, 
-0x30428000, 0x10400005, 0x3c04001e, 0x3c030001, 
-0x8c636fb8, 0x10000005, 0x34848480, 0x3c04000f, 
-0x3c030001, 0x8c636fb8, 0x34844240, 0x24020005, 
-0x14620003, 0x0, 0x3c04007a, 0x34841200, 
-0x3c020001, 0x8c426fa8, 0x8f830054, 0x441021, 
-0x431023, 0x44102b, 0x1440004b, 0x0, 
-0x3c020001, 0x8c426e20, 0x14400047, 0x0, 
-0x3c010001, 0x10c00025, 0xac206e30, 0x3c090001, 
-0x8d296e14, 0x24070001, 0x3c044000, 0x3c080002, 
-0x2508907c, 0x250afffc, 0x52842, 0x14a00002, 
-0x24c6ffff, 0x24050008, 0xa91024, 0x10400010, 
-0x0, 0x14a70008, 0x0, 0x8d020000, 
-0x441024, 0x1040000a, 0x0, 0x3c010001, 
-0x10000007, 0xac256e30, 0x8d420000, 0x441024, 
-0x10400003, 0x0, 0x3c010001, 0xac276e30, 
-0x3c020001, 0x8c426e30, 0x6182b, 0x2c420001, 
-0x431024, 0x5440ffe5, 0x52842, 0x8f820054, 
-0x3c030001, 0x8c636e30, 0x3c010001, 0xac226fa8, 
-0x1060003a, 0x24020005, 0x3c030001, 0x8c636fb8, 
-0x3c010001, 0xac256e18, 0x14620011, 0x24020001, 
-0x3c020002, 0x8c429078, 0x3c032000, 0x431024, 
-0x14400006, 0x24020001, 0x3c010001, 0xac206f98, 
-0x3c010001, 0xac226e18, 0x24020001, 0x3c010001, 
-0xac226ea4, 0x3c010001, 0xac226e24, 0x24020001, 
-0x3c010001, 0xac226e1c, 0x3c020001, 0x8c426e30, 
-0x1040001e, 0x0, 0x3c020001, 0x8c426e1c, 
-0x10400008, 0x24020001, 0x3c010001, 0xac206e1c, 
-0xaee204b8, 0x3c010001, 0xac206e9c, 0x3c010001, 
-0xac226e54, 0x8ee304b8, 0x24020008, 0x10620005, 
-0x24020001, 0xc004203, 0x0, 0x1000000b, 
-0x0, 0x3c030001, 0x8c636e18, 0x10620007, 
-0x2402000e, 0x3c030002, 0x8c639010, 0x10620003, 
-0x0, 0xc004ecc, 0x8f840220, 0x8fbf0010, 
-0x3e00008, 0x27bd0018, 0x27bdffe0, 0x3c03fdff, 
-0x3c040001, 0x8c846e18, 0x3c020001, 0x8c426e40, 
-0x3463ffff, 0x283a024, 0xafbf001c, 0x14820006, 
-0xafb00018, 0x8ee304b8, 0x3c020001, 0x8c426e44, 
-0x10620006, 0x0, 0x8ee204b8, 0x3c010001, 
-0xac246e40, 0x3c010001, 0xac226e44, 0x3c030001, 
-0x8c636e18, 0x24020002, 0x10620167, 0x2c620003, 
-0x10400005, 0x24020001, 0x1062000a, 0x0, 
-0x100001ab, 0x0, 0x24020004, 0x10620081, 
-0x24020008, 0x106200d5, 0x24020001, 0x100001a4, 
-0x0, 0x8ee204b8, 0x2443ffff, 0x2c620008, 
-0x104001a1, 0x31080, 0x3c010001, 0x220821, 
-0x8c226b88, 0x400008, 0x0, 0x3c030001, 
-0x8c636fb8, 0x24020005, 0x14620010, 0x0, 
-0x3c020001, 0x8c426e24, 0x10400008, 0x24020003, 
-0xc0043d3, 0x0, 0x24020002, 0xaee204b8, 
-0x3c010001, 0x10000002, 0xac206e24, 0xaee204b8, 
-0x3c010001, 0x10000188, 0xac206db0, 0xc0043d3, 
-0x0, 0x3c020001, 0x8c426e24, 0x3c010001, 
-0xac206db0, 0x14400145, 0x24020002, 0x10000163, 
-0x24020007, 0x24020001, 0x3c010001, 0xc00454f, 
-0xac226e50, 0x3c030001, 0x8c636e50, 0x10000144, 
-0x24020011, 0x3c020001, 0x8c426fb8, 0x24100005, 
-0x10500007, 0x0, 0x3c050001, 0x8ca56e18, 
-0x3c060002, 0x8cc6907c, 0xc005134, 0x2021, 
-0x3c010001, 0xac206e24, 0x10000167, 0xaef004b8, 
-0x3c040001, 0x24846b7c, 0x3c05000f, 0x34a50100, 
-0x3021, 0x3821, 0xafa00010, 0xc002b17, 
-0xafa00014, 0x1000015c, 0x0, 0x8f820220, 
-0x3c030004, 0x431024, 0x1440013c, 0x24020007, 
-0x8f830054, 0x3c020001, 0x8c426fa0, 0x2463d8f0, 
-0x431023, 0x2c422710, 0x1440014f, 0x24020001, 
-0x1000014b, 0x0, 0x3c050001, 0x8ca56e18, 
-0xc0052c7, 0x2021, 0xc00553d, 0x2021, 
-0x3c030002, 0x8c639074, 0x4610141, 0x24020001, 
-0x3c020008, 0x621024, 0x10400006, 0x0, 
-0x8f820214, 0x3c03ffff, 0x431024, 0x10000005, 
-0x3442251f, 0x8f820214, 0x3c03ffff, 0x431024, 
-0x3442241f, 0xaf820214, 0x8f820220, 0x3c030200, 
-0x283a025, 0x34420002, 0xaf820220, 0x24020008, 
-0xc003e45, 0xaee204b8, 0x3c010001, 0x1000012a, 
-0xac206ea0, 0x8ee204b8, 0x2443ffff, 0x2c620008, 
-0x10400125, 0x31080, 0x3c010001, 0x220821, 
-0x8c226ba8, 0x400008, 0x0, 0xc004498, 
-0x0, 0x3c030001, 0x8c636e34, 0x100000e8, 
-0x24020009, 0x3c020002, 0x8c429078, 0x30424000, 
-0x10400004, 0x0, 0x8f820044, 0x10000006, 
-0x3442f080, 0x8f820044, 0x3c03ffff, 0x34633f7f, 
-0x431024, 0x3442a080, 0xaf820044, 0x8f830054, 
-0x100000ea, 0x24020004, 0x8f830054, 0x3c020001, 
-0x8c426fa0, 0x2463d8f0, 0x431023, 0x2c422710, 
-0x14400101, 0x24020005, 0x100000d8, 0x0, 
+0xa4102b, 0x1040fff0, 0x34028000, 0x1082ffa0, 
+0x26100001, 0x2e020014, 0x1440ffcd, 0x24020004, 
+0x3c010001, 0xac226d98, 0x8021, 0x24120009, 
+0x3c11ffff, 0x36313f7f, 0xc004482, 0x0, 
+0x24020001, 0x3c010001, 0xac226db4, 0xc004547, 
+0x0, 0x3c020001, 0x8c426db4, 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, 0x1082ff50, 0x26100001, 
+0x2e020064, 0x1440ffb0, 0x0, 0x3c020001, 
+0x8c426d94, 0x30420004, 0x14400007, 0x3c09fff0, 
+0x8f820044, 0x3c03ffff, 0x34633f7f, 0x431024, 
+0xaf820044, 0x3c09fff0, 0x3529bdc0, 0x3c060001, 
+0x8cc66d94, 0x3c040001, 0x24846ae0, 0x24020001, 
+0x3c010001, 0xac226d9c, 0x8f820054, 0x3c070001, 
+0x8ce76f40, 0x3c030001, 0x94636f24, 0x3c080001, 
+0x95086f26, 0x3c05000d, 0x34a50100, 0x3c010001, 
+0xac206d98, 0x491021, 0x3c010001, 0xac226f30, 
+0xafa30010, 0xc002b3b, 0xafa80014, 0x8fbf002c, 
+0x8fb20028, 0x8fb10024, 0x8fb00020, 0x3e00008, 
+0x27bd0030, 0x27bdffe8, 0x3c050001, 0x8ca56d98, 
+0x24060004, 0x24020001, 0x14a20014, 0xafbf0010, 
+0x3c020002, 0x8c428ffc, 0x30428000, 0x10400005, 
+0x3c04000f, 0x3c030001, 0x8c636f40, 0x10000005, 
+0x34844240, 0x3c040004, 0x3c030001, 0x8c636f40, 
+0x348493e0, 0x24020005, 0x14620016, 0x0, 
+0x3c04003d, 0x10000013, 0x34840900, 0x3c020002, 
+0x8c428ff8, 0x30428000, 0x10400005, 0x3c04001e, 
+0x3c030001, 0x8c636f40, 0x10000005, 0x34848480, 
+0x3c04000f, 0x3c030001, 0x8c636f40, 0x34844240, 
+0x24020005, 0x14620003, 0x0, 0x3c04007a, 
+0x34841200, 0x3c020001, 0x8c426f30, 0x8f830054, 
+0x441021, 0x431023, 0x44102b, 0x1440004c, 
+0x0, 0x3c020001, 0x8c426da0, 0x14400048, 
+0x0, 0x3c010001, 0x10c00025, 0xac206db0, 
+0x3c090001, 0x8d296d94, 0x24070001, 0x3c044000, 
+0x3c080002, 0x25088ffc, 0x250afffc, 0x52842, 
+0x14a00002, 0x24c6ffff, 0x24050008, 0xa91024, 
+0x10400010, 0x0, 0x14a70008, 0x0, 
+0x8d020000, 0x441024, 0x1040000a, 0x0, 
+0x3c010001, 0x10000007, 0xac256db0, 0x8d420000, 
+0x441024, 0x10400003, 0x0, 0x3c010001, 
+0xac276db0, 0x3c020001, 0x8c426db0, 0x6182b, 
+0x2c420001, 0x431024, 0x5440ffe5, 0x52842, 
+0x8f820054, 0x3c030001, 0x8c636db0, 0x3c010001, 
+0xac226f30, 0x1060003b, 0x24020005, 0x3c030001, 
+0x8c636f40, 0x3c010001, 0xac256d98, 0x14620012, 
+0x24020001, 0x3c020002, 0x8c428ff8, 0x3c032000, 
+0x34635000, 0x431024, 0x14400006, 0x24020001, 
+0x3c010001, 0xac206f1c, 0x3c010001, 0xac226d98, 
+0x24020001, 0x3c010001, 0xac226e24, 0x3c010001, 
+0xac226da4, 0x24020001, 0x3c010001, 0xac226d9c, 
+0x3c020001, 0x8c426db0, 0x1040001e, 0x0, 
+0x3c020001, 0x8c426d9c, 0x10400008, 0x24020001, 
+0x3c010001, 0xac206d9c, 0xaee204b8, 0x3c010001, 
+0xac206e1c, 0x3c010001, 0xac226dd4, 0x8ee304b8, 
+0x24020008, 0x10620005, 0x24020001, 0xc004239, 
+0x0, 0x1000000b, 0x0, 0x3c030001, 
+0x8c636d98, 0x10620007, 0x2402000e, 0x3c030002, 
+0x8c638f90, 0x10620003, 0x0, 0xc004e9c, 
+0x8f840220, 0x8fbf0010, 0x3e00008, 0x27bd0018, 
+0x27bdffe0, 0x3c03fdff, 0x3c040001, 0x8c846d98, 
+0x3c020001, 0x8c426dc0, 0x3463ffff, 0x283a024, 
+0x14820006, 0xafbf0018, 0x8ee304b8, 0x3c020001, 
+0x8c426dc4, 0x10620006, 0x0, 0x8ee204b8, 
+0x3c010001, 0xac246dc0, 0x3c010001, 0xac226dc4, 
+0x3c030001, 0x8c636d98, 0x24020002, 0x1062019c, 
+0x2c620003, 0x10400005, 0x24020001, 0x1062000a, 
+0x0, 0x10000226, 0x0, 0x24020004, 
+0x106200b6, 0x24020008, 0x1062010a, 0x24020001, 
+0x1000021f, 0x0, 0x8ee204b8, 0x2443ffff, 
+0x2c620008, 0x1040021c, 0x31080, 0x3c010001, 
+0x220821, 0x8c226af8, 0x400008, 0x0, 
+0x3c030001, 0x8c636f40, 0x24020005, 0x14620010, 
+0x0, 0x3c020001, 0x8c426da4, 0x10400008, 
+0x24020003, 0xc004482, 0x0, 0x24020002, 
+0xaee204b8, 0x3c010001, 0x10000002, 0xac206da4, 
+0xaee204b8, 0x3c010001, 0x10000203, 0xac206d30, 
+0xc004482, 0x0, 0x3c020001, 0x8c426da4, 
+0x3c010001, 0xac206d30, 0x1440017a, 0x24020002, 
+0x1000019d, 0x24020007, 0x3c030001, 0x8c636f40, 
+0x24020005, 0x14620003, 0x24020001, 0x3c010001, 
+0xac226dd0, 0xc0045ff, 0x0, 0x3c030001, 
+0x8c636dd0, 0x10000174, 0x24020011, 0x3c050001, 
+0x8ca56d98, 0x3c060002, 0x8cc68ffc, 0xc005104, 
+0x2021, 0x24020005, 0x3c010001, 0xac206da4, 
+0x100001e1, 0xaee204b8, 0x3c040001, 0x24846aec, 
+0x3c05000f, 0x34a50100, 0x3021, 0x3821, 
+0xafa00010, 0xc002b3b, 0xafa00014, 0x100001d6, 
+0x0, 0x8f820220, 0x3c030004, 0x431024, 
+0x14400175, 0x24020007, 0x8f830054, 0x3c020001, 
+0x8c426f28, 0x2463d8f0, 0x431023, 0x2c422710, 
+0x14400003, 0x24020001, 0x3c010001, 0xac226d9c, 
+0x3c020002, 0x8c428ffc, 0x30425000, 0x104001c2, 
+0x0, 0x8f820220, 0x30428000, 0x1040017d, 
+0x0, 0x10000175, 0x0, 0x3c050001, 
+0x8ca56d98, 0xc00529b, 0x2021, 0xc00551b, 
+0x2021, 0x3c030002, 0x8c638ff4, 0x46101b0, 
+0x24020001, 0x3c020008, 0x621024, 0x10400006, 
+0x0, 0x8f820214, 0x3c03ffff, 0x431024, 
+0x10000005, 0x3442251f, 0x8f820214, 0x3c03ffff, 
+0x431024, 0x3442241f, 0xaf820214, 0x8f820220, 
+0x3c030200, 0x34420002, 0xaf820220, 0x24020008, 
+0xaee204b8, 0x8f820220, 0x283a025, 0x3c030004, 
+0x431024, 0x14400016, 0x0, 0x3c020002, 
+0x8c428ffc, 0x30425000, 0x1040000d, 0x0, 
+0x8f820220, 0x30428000, 0x10400006, 0x0, 
+0x8f820220, 0x3c03ffff, 0x34637fff, 0x10000003, 
+0x431024, 0x8f820220, 0x34428000, 0xaf820220, 
 0x8f820220, 0x3c03f700, 0x431025, 0xaf820220, 
-0xaf800204, 0x3c010002, 0x100000d6, 0xac209060, 
-0x8f830054, 0x3c020001, 0x8c426fa0, 0x2463fff6, 
-0x431023, 0x2c42000a, 0x144000ef, 0x24020007, 
-0x100000d2, 0x0, 0xc003f28, 0x0, 
-0x104000e7, 0x24020001, 0x8f820214, 0x3c03ffff, 
-0x3c040001, 0x8c846f98, 0x431024, 0x3442251f, 
-0xaf820214, 0x24020008, 0x10800005, 0xaee204b8, 
-0x3c020001, 0x8c426ec4, 0x10400064, 0x24020001, 
-0x8f820220, 0x3c030008, 0x431024, 0x1040006a, 
-0x3c020200, 0x10000078, 0x0, 0x8ee204b8, 
-0x2443ffff, 0x2c620007, 0x104000cf, 0x31080, 
-0x3c010001, 0x220821, 0x8c226bc8, 0x400008, 
-0x0, 0xc003d87, 0x0, 0x3c010001, 
-0xac206e1c, 0xaf800204, 0x3c010002, 0xc0043d3, 
-0xac209060, 0x24020001, 0x3c010001, 0xac226e34, 
-0x24020002, 0x100000bc, 0xaee204b8, 0xc004498, 
-0x0, 0x3c030001, 0x8c636e34, 0x10000084, 
-0x24020009, 0x3c020002, 0x8c429078, 0x30424000, 
-0x10400003, 0x3c0200c8, 0x10000002, 0x344201f6, 
-0x344201fe, 0xaf820238, 0x8f830054, 0x1000008b, 
-0x24020004, 0x8f830054, 0x3c020001, 0x8c426fa0, 
-0x2463d8f0, 0x431023, 0x2c422710, 0x144000a2, 
-0x24020005, 0x10000079, 0x0, 0x8f820220, 
-0x3c03f700, 0x431025, 0xaf820220, 0xaf800204, 
-0x3c010002, 0x10000077, 0xac209060, 0x8f830054, 
-0x3c020001, 0x8c426fa0, 0x2463fff6, 0x431023, 
-0x2c42000a, 0x14400090, 0x24020007, 0x10000073, 
-0x0, 0xc003f28, 0x0, 0x10400088, 
-0x24020001, 0x8f820214, 0x3c03ffff, 0x3c040001, 
-0x8c846f98, 0x431024, 0x3442251f, 0xaf820214, 
-0x24020008, 0x1080000f, 0xaee204b8, 0x3c020001, 
-0x8c426ec4, 0x1440000b, 0x0, 0x8f820220, 
-0x34420002, 0xaf820220, 0x24020001, 0x3c010002, 
-0xac229010, 0xc004ecc, 0x8f840220, 0x10000016, 
-0x0, 0x8f820220, 0x3c030008, 0x431024, 
-0x14400011, 0x3c020200, 0x282a025, 0x2402000e, 
-0x3c010002, 0xac229010, 0xc00553d, 0x2021, 
-0x8f820220, 0x34420002, 0xc003e45, 0xaf820220, 
-0x3c050001, 0x8ca56e18, 0xc0052c7, 0x2021, 
-0x1000005d, 0x0, 0x3c020001, 0x8c426ec4, 
-0x10400059, 0x0, 0x3c020001, 0x8c426ec0, 
-0x2442ffff, 0x3c010001, 0xac226ec0, 0x14400052, 
-0x24020002, 0x3c010001, 0xac206ec4, 0x3c010001, 
-0x1000004d, 0xac226ec0, 0x8ee204b8, 0x2443ffff, 
-0x2c620007, 0x10400048, 0x31080, 0x3c010001, 
-0x220821, 0x8c226be8, 0x400008, 0x0, 
-0x3c020001, 0x8c426e24, 0x10400024, 0x24020007, 
-0xc0043d3, 0x0, 0x24020002, 0xaee204b8, 
-0x3c010001, 0x10000038, 0xac206e24, 0xc0048b3, 
-0x0, 0x3c030001, 0x8c636e54, 0x24020006, 
-0x14620031, 0x24020003, 0x1000002f, 0xaee204b8, 
-0x3c050001, 0x8ca56e18, 0x3c060002, 0x8cc69078, 
-0xc005134, 0x2021, 0x24020005, 0x10000026, 
-0xaee204b8, 0x8f820220, 0x3c03f700, 0x431025, 
-0xaf820220, 0x8f830054, 0x24020006, 0xaee204b8, 
-0x3c010001, 0x1000001c, 0xac236fa0, 0x1000001a, 
-0xaee204b8, 0x3c050001, 0x8ca56e18, 0xc0052c7, 
-0x2021, 0xc00553d, 0x2021, 0x3c020002, 
-0x8c429070, 0x441000e, 0x24020001, 0x8f820214, 
+0x3c030001, 0x8c636f40, 0x24020005, 0x1462000a, 
+0x0, 0x3c020001, 0x94426f26, 0x24429fbc, 
+0x2c420004, 0x10400004, 0x24040018, 0x24050002, 
+0xc004ddb, 0x24060020, 0xc003e6d, 0x0, 
+0x3c010001, 0x10000170, 0xac206e20, 0x8ee204b8, 
+0x2443ffff, 0x2c620008, 0x1040016b, 0x31080, 
+0x3c010001, 0x220821, 0x8c226b18, 0x400008, 
+0x0, 0xc004547, 0x0, 0x3c030001, 
+0x8c636db4, 0x100000e8, 0x24020009, 0x3c020002, 
+0x8c428ff8, 0x30424000, 0x10400004, 0x0, 
+0x8f820044, 0x10000006, 0x3442f080, 0x8f820044, 
+0x3c03ffff, 0x34633f7f, 0x431024, 0x3442a080, 
+0xaf820044, 0x8f830054, 0x100000ea, 0x24020004, 
+0x8f830054, 0x3c020001, 0x8c426f28, 0x2463d8f0, 
+0x431023, 0x2c422710, 0x14400147, 0x24020005, 
+0x100000d8, 0x0, 0x8f820220, 0x3c03f700, 
+0x431025, 0xaf820220, 0xaf800204, 0x3c010002, 
+0x100000d6, 0xac208fe0, 0x8f830054, 0x3c020001, 
+0x8c426f28, 0x2463fff6, 0x431023, 0x2c42000a, 
+0x14400135, 0x24020007, 0x100000d7, 0x0, 
+0xc003f50, 0x0, 0x1040012d, 0x24020001, 
+0x8f820214, 0x3c03ffff, 0x3c040001, 0x8c846f1c, 
+0x431024, 0x3442251f, 0xaf820214, 0x24020008, 
+0x10800005, 0xaee204b8, 0x3c020001, 0x8c426e44, 
+0x10400064, 0x24020001, 0x8f820220, 0x3c030008, 
+0x431024, 0x1040006a, 0x3c020200, 0x10000078, 
+0x0, 0x8ee204b8, 0x2443ffff, 0x2c620007, 
+0x10400115, 0x31080, 0x3c010001, 0x220821, 
+0x8c226b38, 0x400008, 0x0, 0xc003daf, 
+0x0, 0x3c010001, 0xac206d9c, 0xaf800204, 
+0x3c010002, 0xc004482, 0xac208fe0, 0x24020001, 
+0x3c010001, 0xac226db4, 0x24020002, 0x10000102, 
+0xaee204b8, 0xc004547, 0x0, 0x3c030001, 
+0x8c636db4, 0x10000084, 0x24020009, 0x3c020002, 
+0x8c428ff8, 0x30424000, 0x10400003, 0x3c0200c8, 
+0x10000002, 0x344201f6, 0x344201fe, 0xaf820238, 
+0x8f830054, 0x1000008b, 0x24020004, 0x8f830054, 
+0x3c020001, 0x8c426f28, 0x2463d8f0, 0x431023, 
+0x2c422710, 0x144000e8, 0x24020005, 0x10000079, 
+0x0, 0x8f820220, 0x3c03f700, 0x431025, 
+0xaf820220, 0xaf800204, 0x3c010002, 0x10000077, 
+0xac208fe0, 0x8f830054, 0x3c020001, 0x8c426f28, 
+0x2463fff6, 0x431023, 0x2c42000a, 0x144000d6, 
+0x24020007, 0x10000078, 0x0, 0xc003f50, 
+0x0, 0x104000ce, 0x24020001, 0x8f820214, 
+0x3c03ffff, 0x3c040001, 0x8c846f1c, 0x431024, 
+0x3442251f, 0xaf820214, 0x24020008, 0x1080000f, 
+0xaee204b8, 0x3c020001, 0x8c426e44, 0x1440000b, 
+0x0, 0x8f820220, 0x34420002, 0xaf820220, 
+0x24020001, 0x3c010002, 0xac228f90, 0xc004e9c, 
+0x8f840220, 0x10000016, 0x0, 0x8f820220, 
+0x3c030008, 0x431024, 0x14400011, 0x3c020200, 
+0x282a025, 0x2402000e, 0x3c010002, 0xac228f90, 
+0xc00551b, 0x2021, 0x8f820220, 0x34420002, 
+0xc003e6d, 0xaf820220, 0x3c050001, 0x8ca56d98, 
+0xc00529b, 0x2021, 0x100000a3, 0x0, 
+0x3c020001, 0x8c426e44, 0x1040009f, 0x0, 
+0x3c020001, 0x8c426e40, 0x2442ffff, 0x3c010001, 
+0xac226e40, 0x14400098, 0x24020002, 0x3c010001, 
+0xac206e44, 0x3c010001, 0x10000093, 0xac226e40, 
+0x8ee204b8, 0x2443ffff, 0x2c620007, 0x1040008e, 
+0x31080, 0x3c010001, 0x220821, 0x8c226b58, 
+0x400008, 0x0, 0x3c020001, 0x8c426da4, 
+0x10400018, 0x24020005, 0xc004482, 0x0, 
+0x24020002, 0xaee204b8, 0x3c010001, 0x1000007e, 
+0xac206da4, 0xc004963, 0x0, 0x3c030001, 
+0x8c636dd4, 0x24020006, 0x14620077, 0x24020003, 
+0x10000075, 0xaee204b8, 0x3c050001, 0x8ca56d98, 
+0x3c060002, 0x8cc68ff8, 0xc005104, 0x2021, 
+0x24020005, 0x1000006c, 0xaee204b8, 0x8f820220, 
+0x3c03f700, 0x431025, 0xaf820220, 0x8f830054, 
+0x24020006, 0xaee204b8, 0x3c010001, 0x10000062, 
+0xac236f28, 0x8f820220, 0x3c030004, 0x431024, 
+0x10400003, 0x24020007, 0x1000005b, 0xaee204b8, 
+0x8f830054, 0x3c020001, 0x8c426f28, 0x2463d8f0, 
+0x431023, 0x2c422710, 0x14400003, 0x24020001, 
+0x3c010001, 0xac226d9c, 0x3c020002, 0x8c428ff8, 
+0x30425000, 0x1040004c, 0x0, 0x8f820220, 
+0x30428000, 0x10400007, 0x0, 0x8f820220, 
+0x3c03ffff, 0x34637fff, 0x431024, 0x10000042, 
+0xaf820220, 0x8f820220, 0x34428000, 0x1000003e, 
+0xaf820220, 0x3c050001, 0x8ca56d98, 0xc00529b, 
+0x2021, 0xc00551b, 0x2021, 0x3c020002, 
+0x8c428ff0, 0x4410032, 0x24020001, 0x8f820214, 
 0x3c03ffff, 0x431024, 0x3442251f, 0xaf820214, 
 0x24020008, 0xaee204b8, 0x8f820220, 0x34420002, 
-0xc003e45, 0xaf820220, 0x10000003, 0x0, 
-0x3c010001, 0xac226e1c, 0x8fbf001c, 0x8fb00018, 
-0x3e00008, 0x27bd0020, 0x8f820200, 0x8f820220, 
-0x8f820220, 0x34420004, 0xaf820220, 0x8f820200, 
-0x3c050001, 0x8ca56e18, 0x34420004, 0xaf820200, 
-0x24020002, 0x10a2004b, 0x2ca20003, 0x10400005, 
-0x24020001, 0x10a2000a, 0x0, 0x100000b1, 
-0x0, 0x24020004, 0x10a20072, 0x24020008, 
-0x10a20085, 0x3c02f0ff, 0x100000aa, 0x0, 
+0xaf820220, 0x8f820220, 0x3c030004, 0x431024, 
+0x14400016, 0x0, 0x3c020002, 0x8c428ff8, 
+0x30425000, 0x1040000d, 0x0, 0x8f820220, 
+0x30428000, 0x10400006, 0x0, 0x8f820220, 
+0x3c03ffff, 0x34637fff, 0x10000003, 0x431024, 
+0x8f820220, 0x34428000, 0xaf820220, 0x8f820220, 
+0x3c03f700, 0x431025, 0xaf820220, 0x3c020001, 
+0x94426f26, 0x24429fbc, 0x2c420004, 0x10400004, 
+0x24040018, 0x24050002, 0xc004ddb, 0x24060020, 
+0xc003e6d, 0x0, 0x10000003, 0x0, 
+0x3c010001, 0xac226d9c, 0x8fbf0018, 0x3e00008, 
+0x27bd0020, 0x8f820200, 0x8f820220, 0x8f820220, 
+0x34420004, 0xaf820220, 0x8f820200, 0x3c050001, 
+0x8ca56d98, 0x34420004, 0xaf820200, 0x24020002, 
+0x10a2004b, 0x2ca20003, 0x10400005, 0x24020001, 
+0x10a2000a, 0x0, 0x100000b1, 0x0, 
+0x24020004, 0x10a20072, 0x24020008, 0x10a20085, 
+0x3c02f0ff, 0x100000aa, 0x0, 0x8f830050, 
+0x3c02f0ff, 0x3442ffff, 0x3c040001, 0x8c846f40, 
+0x621824, 0x3c020700, 0x621825, 0x24020e00, 
+0x2484fffb, 0x2c840002, 0xaf830050, 0xaf850200, 
+0xaf850220, 0x14800006, 0xaf820238, 0x8f820044, 
+0x3c03ffff, 0x34633f7f, 0x431024, 0xaf820044, 
+0x3c030001, 0x8c636f40, 0x24020005, 0x14620004, 
+0x0, 0x8f820044, 0x34425000, 0xaf820044, 
+0x3c020001, 0x8c426d88, 0x3c030001, 0x8c636f40, 
+0x34420022, 0x2463fffc, 0x2c630002, 0x1460000c, 
+0xaf820200, 0x3c020001, 0x8c426dac, 0x3c030001, 
+0x8c636d90, 0x3c040001, 0x8c846d8c, 0x34428000, 
+0x621825, 0x641825, 0x1000000a, 0x34620002, 
+0x3c020001, 0x8c426d90, 0x3c030001, 0x8c636dac, 
+0x3c040001, 0x8c846d8c, 0x431025, 0x441025, 
+0x34420002, 0xaf820220, 0x1000002f, 0x24020001, 
+0x24020e01, 0xaf820238, 0x8f830050, 0x3c02f0ff, 
+0x3442ffff, 0x3c040001, 0x8c846f1c, 0x621824, 
+0x3c020d00, 0x621825, 0x24020001, 0xaf830050, 
+0xaf820200, 0xaf820220, 0x10800005, 0x3c033f00, 
+0x3c020001, 0x8c426d80, 0x10000004, 0x34630070, 
+0x3c020001, 0x8c426d80, 0x34630072, 0x431025, 
+0xaf820200, 0x3c030001, 0x8c636d84, 0x3c02f700, 
+0x621825, 0x3c020001, 0x8c426d90, 0x3c040001, 
+0x8c846dac, 0x3c050001, 0x8ca56f40, 0x431025, 
+0x441025, 0xaf820220, 0x24020005, 0x14a20006, 
+0x24020001, 0x8f820044, 0x2403afff, 0x431024, 
+0xaf820044, 0x24020001, 0x1000003d, 0xaf820238, 
 0x8f830050, 0x3c02f0ff, 0x3442ffff, 0x3c040001, 
-0x8c846fb8, 0x621824, 0x3c020700, 0x621825, 
-0x24020e00, 0x2484fffb, 0x2c840002, 0xaf830050, 
-0xaf850200, 0xaf850220, 0x14800006, 0xaf820238, 
-0x8f820044, 0x3c03ffff, 0x34633f7f, 0x431024, 
-0xaf820044, 0x3c030001, 0x8c636fb8, 0x24020005, 
-0x14620004, 0x0, 0x8f820044, 0x34425000, 
-0xaf820044, 0x3c020001, 0x8c426e08, 0x3c030001, 
-0x8c636fb8, 0x34420022, 0x2463fffc, 0x2c630002, 
-0x1460000c, 0xaf820200, 0x3c020001, 0x8c426e2c, 
-0x3c030001, 0x8c636e10, 0x3c040001, 0x8c846e0c, 
-0x34428000, 0x621825, 0x641825, 0x1000000a, 
-0x34620002, 0x3c020001, 0x8c426e10, 0x3c030001, 
-0x8c636e2c, 0x3c040001, 0x8c846e0c, 0x431025, 
-0x441025, 0x34420002, 0xaf820220, 0x1000002f, 
-0x24020001, 0x24020e01, 0xaf820238, 0x8f830050, 
-0x3c02f0ff, 0x3442ffff, 0x3c040001, 0x8c846f98, 
-0x621824, 0x3c020d00, 0x621825, 0x24020001, 
-0xaf830050, 0xaf820200, 0xaf820220, 0x10800005, 
-0x3c033f00, 0x3c020001, 0x8c426e00, 0x10000004, 
-0x34630070, 0x3c020001, 0x8c426e00, 0x34630072, 
-0x431025, 0xaf820200, 0x3c030001, 0x8c636e04, 
-0x3c02f700, 0x621825, 0x3c020001, 0x8c426e10, 
-0x3c040001, 0x8c846e2c, 0x3c050001, 0x8ca56fb8, 
-0x431025, 0x441025, 0xaf820220, 0x24020005, 
-0x14a20006, 0x24020001, 0x8f820044, 0x2403afff, 
-0x431024, 0xaf820044, 0x24020001, 0x1000003d, 
-0xaf820238, 0x8f830050, 0x3c02f0ff, 0x3442ffff, 
-0x3c040001, 0x8c846f98, 0x621824, 0x3c020a00, 
-0x621825, 0x24020001, 0xaf830050, 0xaf820200, 
-0x1080001e, 0xaf820220, 0x3c020001, 0x8c426ec4, 
-0x1440001a, 0x3c033f00, 0x3c020001, 0x8c426e00, 
-0x1000001a, 0x346300e0, 0x8f830050, 0x3c040001, 
-0x8c846f98, 0x3442ffff, 0x621824, 0x1080000f, 
-0xaf830050, 0x3c020001, 0x8c426ec4, 0x1440000b, 
-0x3c043f00, 0x3c030001, 0x8c636e00, 0x348400e0, 
-0x24020001, 0xaf820200, 0xaf820220, 0x641825, 
-0xaf830200, 0x10000008, 0x3c05f700, 0x3c020001, 
-0x8c426e00, 0x3c033f00, 0x346300e2, 0x431025, 
-0xaf820200, 0x3c05f700, 0x34a58000, 0x3c030001, 
-0x8c636e04, 0x3c020001, 0x8c426e10, 0x3c040001, 
-0x8c846e2c, 0x651825, 0x431025, 0x441025, 
-0xaf820220, 0x3e00008, 0x0, 0x3c030001, 
-0x8c636e34, 0x3c020001, 0x8c426e38, 0x10620003, 
-0x24020002, 0x3c010001, 0xac236e38, 0x1062001d, 
-0x2c620003, 0x10400025, 0x24020001, 0x14620023, 
-0x24020004, 0x3c030001, 0x8c636e18, 0x10620006, 
-0x24020008, 0x1462000c, 0x3c0200c8, 0x344201fb, 
-0x10000009, 0xaf820238, 0x24020e01, 0xaf820238, 
-0x8f820044, 0x3c03ffff, 0x34633f7f, 0x431024, 
-0x34420080, 0xaf820044, 0x8f830054, 0x24020002, 
-0x3c010001, 0xac226e34, 0x3c010001, 0x1000000b, 
-0xac236fa4, 0x8f830054, 0x3c020001, 0x8c426fa4, 
-0x2463d8f0, 0x431023, 0x2c422710, 0x14400003, 
-0x24020009, 0x3c010001, 0xac226e34, 0x3e00008, 
+0x8c846f1c, 0x621824, 0x3c020a00, 0x621825, 
+0x24020001, 0xaf830050, 0xaf820200, 0x1080001e, 
+0xaf820220, 0x3c020001, 0x8c426e44, 0x1440001a, 
+0x3c033f00, 0x3c020001, 0x8c426d80, 0x1000001a, 
+0x346300e0, 0x8f830050, 0x3c040001, 0x8c846f1c, 
+0x3442ffff, 0x621824, 0x1080000f, 0xaf830050, 
+0x3c020001, 0x8c426e44, 0x1440000b, 0x3c043f00, 
+0x3c030001, 0x8c636d80, 0x348400e0, 0x24020001, 
+0xaf820200, 0xaf820220, 0x641825, 0xaf830200, 
+0x10000008, 0x3c05f700, 0x3c020001, 0x8c426d80, 
+0x3c033f00, 0x346300e2, 0x431025, 0xaf820200, 
+0x3c05f700, 0x34a58000, 0x3c030001, 0x8c636d84, 
+0x3c020001, 0x8c426d90, 0x3c040001, 0x8c846dac, 
+0x651825, 0x431025, 0x441025, 0xaf820220, 
+0x3e00008, 0x0, 0x3c030001, 0x8c636db4, 
+0x3c020001, 0x8c426db8, 0x10620003, 0x24020002, 
+0x3c010001, 0xac236db8, 0x1062001d, 0x2c620003, 
+0x10400025, 0x24020001, 0x14620023, 0x24020004, 
+0x3c030001, 0x8c636d98, 0x10620006, 0x24020008, 
+0x1462000c, 0x3c0200c8, 0x344201fb, 0x10000009, 
+0xaf820238, 0x24020e01, 0xaf820238, 0x8f820044, 
+0x3c03ffff, 0x34633f7f, 0x431024, 0x34420080, 
+0xaf820044, 0x8f830054, 0x24020002, 0x3c010001, 
+0xac226db4, 0x3c010001, 0x1000000b, 0xac236f2c, 
+0x8f830054, 0x3c020001, 0x8c426f2c, 0x2463d8f0, 
+0x431023, 0x2c422710, 0x14400003, 0x24020009, 
+0x3c010001, 0xac226db4, 0x3e00008, 0x0, 
 0x0, 0x0, 0x0, 0x27bdffd8, 
 0xafb20018, 0x809021, 0xafb3001c, 0xa09821, 
 0xafb10014, 0xc08821, 0xafb00010, 0x8021, 
-0xafbf0020, 0xa6200000, 0xc004dab, 0x24040001, 
+0xafbf0020, 0xa6200000, 0xc004d78, 0x24040001, 
 0x26100001, 0x2e020020, 0x1440fffb, 0x0, 
-0xc004dab, 0x2021, 0xc004dab, 0x24040001, 
-0xc004dab, 0x24040001, 0xc004dab, 0x2021, 
+0xc004d78, 0x2021, 0xc004d78, 0x24040001, 
+0xc004d78, 0x24040001, 0xc004d78, 0x2021, 
 0x24100010, 0x2501024, 0x10400002, 0x2021, 
-0x24040001, 0xc004dab, 0x108042, 0x1600fffa, 
+0x24040001, 0xc004d78, 0x108042, 0x1600fffa, 
 0x2501024, 0x24100010, 0x2701024, 0x10400002, 
-0x2021, 0x24040001, 0xc004dab, 0x108042, 
-0x1600fffa, 0x2701024, 0xc004dec, 0x34108000, 
-0xc004dec, 0x0, 0xc004d8b, 0x0, 
+0x2021, 0x24040001, 0xc004d78, 0x108042, 
+0x1600fffa, 0x2701024, 0xc004db9, 0x34108000, 
+0xc004db9, 0x0, 0xc004d58, 0x0, 
 0x50400005, 0x108042, 0x96220000, 0x501025, 
 0xa6220000, 0x108042, 0x1600fff7, 0x0, 
-0xc004dec, 0x0, 0x8fbf0020, 0x8fb3001c, 
+0xc004db9, 0x0, 0x8fbf0020, 0x8fb3001c, 
 0x8fb20018, 0x8fb10014, 0x8fb00010, 0x3e00008, 
 0x27bd0028, 0x27bdffd8, 0xafb10014, 0x808821, 
 0xafb20018, 0xa09021, 0xafb3001c, 0xc09821, 
-0xafb00010, 0x8021, 0xafbf0020, 0xc004dab, 
+0xafb00010, 0x8021, 0xafbf0020, 0xc004d78, 
 0x24040001, 0x26100001, 0x2e020020, 0x1440fffb, 
-0x0, 0xc004dab, 0x2021, 0xc004dab, 
-0x24040001, 0xc004dab, 0x2021, 0xc004dab, 
+0x0, 0xc004d78, 0x2021, 0xc004d78, 
+0x24040001, 0xc004d78, 0x2021, 0xc004d78, 
 0x24040001, 0x24100010, 0x2301024, 0x10400002, 
-0x2021, 0x24040001, 0xc004dab, 0x108042, 
+0x2021, 0x24040001, 0xc004d78, 0x108042, 
 0x1600fffa, 0x2301024, 0x24100010, 0x2501024, 
-0x10400002, 0x2021, 0x24040001, 0xc004dab, 
-0x108042, 0x1600fffa, 0x2501024, 0xc004dab, 
-0x24040001, 0xc004dab, 0x2021, 0x34108000, 
+0x10400002, 0x2021, 0x24040001, 0xc004d78, 
+0x108042, 0x1600fffa, 0x2501024, 0xc004d78, 
+0x24040001, 0xc004d78, 0x2021, 0x34108000, 
 0x96620000, 0x501024, 0x10400002, 0x2021, 
-0x24040001, 0xc004dab, 0x108042, 0x1600fff8, 
-0x0, 0xc004dec, 0x0, 0x8fbf0020, 
+0x24040001, 0xc004d78, 0x108042, 0x1600fff8, 
+0x0, 0xc004db9, 0x0, 0x8fbf0020, 
 0x8fb3001c, 0x8fb20018, 0x8fb10014, 0x8fb00010, 
-0x3e00008, 0x27bd0028, 0x3c040001, 0x8c846e50, 
-0x3c020001, 0x8c426e98, 0x27bdffd8, 0xafbf0020, 
+0x3e00008, 0x27bd0028, 0x3c040001, 0x8c846dd0, 
+0x3c020001, 0x8c426e18, 0x27bdffd8, 0xafbf0020, 
 0xafb1001c, 0x10820003, 0xafb00018, 0x3c010001, 
-0xac246e98, 0x3c030001, 0x8c636fb8, 0x24020005, 
-0x14620005, 0x2483ffff, 0xc0048b3, 0x0, 
+0xac246e18, 0x3c030001, 0x8c636f40, 0x24020005, 
+0x14620005, 0x2483ffff, 0xc004963, 0x0, 
 0x1000034c, 0x0, 0x2c620013, 0x10400349, 
-0x31080, 0x3c010001, 0x220821, 0x8c226c10, 
-0x400008, 0x0, 0xc004dec, 0x8021, 
-0x34028000, 0xa7a20010, 0x27b10010, 0xc004dab, 
+0x31080, 0x3c010001, 0x220821, 0x8c226b80, 
+0x400008, 0x0, 0xc004db9, 0x8021, 
+0x34028000, 0xa7a20010, 0x27b10010, 0xc004d78, 
 0x24040001, 0x26100001, 0x2e020020, 0x1440fffb, 
-0x0, 0xc004dab, 0x2021, 0xc004dab, 
-0x24040001, 0xc004dab, 0x2021, 0xc004dab, 
+0x0, 0xc004d78, 0x2021, 0xc004d78, 
+0x24040001, 0xc004d78, 0x2021, 0xc004d78, 
 0x24040001, 0x24100010, 0x32020001, 0x10400002, 
-0x2021, 0x24040001, 0xc004dab, 0x108042, 
-0x1600fffa, 0x32020001, 0x24100010, 0xc004dab, 
+0x2021, 0x24040001, 0xc004d78, 0x108042, 
+0x1600fffa, 0x32020001, 0x24100010, 0xc004d78, 
 0x2021, 0x108042, 0x1600fffc, 0x0, 
-0xc004dab, 0x24040001, 0xc004dab, 0x2021, 
+0xc004d78, 0x24040001, 0xc004d78, 0x2021, 
 0x34108000, 0x96220000, 0x501024, 0x10400002, 
-0x2021, 0x24040001, 0xc004dab, 0x108042, 
-0x1600fff8, 0x0, 0xc004dec, 0x0, 
+0x2021, 0x24040001, 0xc004d78, 0x108042, 
+0x1600fff8, 0x0, 0xc004db9, 0x0, 
 0x1000030e, 0x24020002, 0x27b10010, 0xa7a00010, 
-0x8021, 0xc004dab, 0x24040001, 0x26100001, 
-0x2e020020, 0x1440fffb, 0x0, 0xc004dab, 
-0x2021, 0xc004dab, 0x24040001, 0xc004dab, 
-0x24040001, 0xc004dab, 0x2021, 0x24100010, 
+0x8021, 0xc004d78, 0x24040001, 0x26100001, 
+0x2e020020, 0x1440fffb, 0x0, 0xc004d78, 
+0x2021, 0xc004d78, 0x24040001, 0xc004d78, 
+0x24040001, 0xc004d78, 0x2021, 0x24100010, 
 0x32020001, 0x10400002, 0x2021, 0x24040001, 
-0xc004dab, 0x108042, 0x1600fffa, 0x32020001, 
-0x24100010, 0xc004dab, 0x2021, 0x108042, 
-0x1600fffc, 0x0, 0xc004dec, 0x34108000, 
-0xc004dec, 0x0, 0xc004d8b, 0x0, 
+0xc004d78, 0x108042, 0x1600fffa, 0x32020001, 
+0x24100010, 0xc004d78, 0x2021, 0x108042, 
+0x1600fffc, 0x0, 0xc004db9, 0x34108000, 
+0xc004db9, 0x0, 0xc004d58, 0x0, 
 0x50400005, 0x108042, 0x96220000, 0x501025, 
 0xa6220000, 0x108042, 0x1600fff7, 0x0, 
-0xc004dec, 0x0, 0x97a20010, 0x30428000, 
+0xc004db9, 0x0, 0x97a20010, 0x30428000, 
 0x144002dc, 0x24020003, 0x100002d8, 0x0, 
 0x24021200, 0xa7a20010, 0x27b10010, 0x8021, 
-0xc004dab, 0x24040001, 0x26100001, 0x2e020020, 
-0x1440fffb, 0x0, 0xc004dab, 0x2021, 
-0xc004dab, 0x24040001, 0xc004dab, 0x2021, 
-0xc004dab, 0x24040001, 0x24100010, 0x32020001, 
-0x10400002, 0x2021, 0x24040001, 0xc004dab, 
+0xc004d78, 0x24040001, 0x26100001, 0x2e020020, 
+0x1440fffb, 0x0, 0xc004d78, 0x2021, 
+0xc004d78, 0x24040001, 0xc004d78, 0x2021, 
+0xc004d78, 0x24040001, 0x24100010, 0x32020001, 
+0x10400002, 0x2021, 0x24040001, 0xc004d78, 
 0x108042, 0x1600fffa, 0x32020001, 0x24100010, 
-0xc004dab, 0x2021, 0x108042, 0x1600fffc, 
-0x0, 0xc004dab, 0x24040001, 0xc004dab, 
+0xc004d78, 0x2021, 0x108042, 0x1600fffc, 
+0x0, 0xc004d78, 0x24040001, 0xc004d78, 
 0x2021, 0x34108000, 0x96220000, 0x501024, 
-0x10400002, 0x2021, 0x24040001, 0xc004dab, 
-0x108042, 0x1600fff8, 0x0, 0xc004dec, 
+0x10400002, 0x2021, 0x24040001, 0xc004d78, 
+0x108042, 0x1600fff8, 0x0, 0xc004db9, 
 0x0, 0x8f830054, 0x10000296, 0x24020004, 
-0x8f830054, 0x3c020001, 0x8c426fb4, 0x2463ff9c, 
+0x8f830054, 0x3c020001, 0x8c426f3c, 0x2463ff9c, 
 0x431023, 0x2c420064, 0x1440029e, 0x24020002, 
-0x3c030001, 0x8c636fb8, 0x10620297, 0x2c620003, 
+0x3c030001, 0x8c636f40, 0x10620297, 0x2c620003, 
 0x14400296, 0x24020011, 0x24020003, 0x10620005, 
 0x24020004, 0x10620291, 0x2402000f, 0x1000028f, 
 0x24020011, 0x1000028d, 0x24020005, 0x24020014, 
-0xa7a20010, 0x27b10010, 0x8021, 0xc004dab, 
+0xa7a20010, 0x27b10010, 0x8021, 0xc004d78, 
 0x24040001, 0x26100001, 0x2e020020, 0x1440fffb, 
-0x0, 0xc004dab, 0x2021, 0xc004dab, 
-0x24040001, 0xc004dab, 0x2021, 0xc004dab, 
+0x0, 0xc004d78, 0x2021, 0xc004d78, 
+0x24040001, 0xc004d78, 0x2021, 0xc004d78, 
 0x24040001, 0x24100010, 0x32020001, 0x10400002, 
-0x2021, 0x24040001, 0xc004dab, 0x108042, 
+0x2021, 0x24040001, 0xc004d78, 0x108042, 
 0x1600fffa, 0x32020001, 0x24100010, 0x32020012, 
-0x10400002, 0x2021, 0x24040001, 0xc004dab, 
-0x108042, 0x1600fffa, 0x32020012, 0xc004dab, 
-0x24040001, 0xc004dab, 0x2021, 0x34108000, 
+0x10400002, 0x2021, 0x24040001, 0xc004d78, 
+0x108042, 0x1600fffa, 0x32020012, 0xc004d78, 
+0x24040001, 0xc004d78, 0x2021, 0x34108000, 
 0x96220000, 0x501024, 0x10400002, 0x2021, 
-0x24040001, 0xc004dab, 0x108042, 0x1600fff8, 
-0x0, 0xc004dec, 0x0, 0x8f830054, 
+0x24040001, 0xc004d78, 0x108042, 0x1600fff8, 
+0x0, 0xc004db9, 0x0, 0x8f830054, 
 0x10000248, 0x24020006, 0x8f830054, 0x3c020001, 
-0x8c426fb4, 0x2463ff9c, 0x431023, 0x2c420064, 
+0x8c426f3c, 0x2463ff9c, 0x431023, 0x2c420064, 
 0x14400250, 0x24020007, 0x1000024c, 0x0, 
 0x24020006, 0xa7a20010, 0x27b10010, 0x8021, 
-0xc004dab, 0x24040001, 0x26100001, 0x2e020020, 
-0x1440fffb, 0x0, 0xc004dab, 0x2021, 
-0xc004dab, 0x24040001, 0xc004dab, 0x2021, 
-0xc004dab, 0x24040001, 0x24100010, 0x32020001, 
-0x10400002, 0x2021, 0x24040001, 0xc004dab, 
+0xc004d78, 0x24040001, 0x26100001, 0x2e020020, 
+0x1440fffb, 0x0, 0xc004d78, 0x2021, 
+0xc004d78, 0x24040001, 0xc004d78, 0x2021, 
+0xc004d78, 0x24040001, 0x24100010, 0x32020001, 
+0x10400002, 0x2021, 0x24040001, 0xc004d78, 
 0x108042, 0x1600fffa, 0x32020001, 0x24100010, 
 0x32020013, 0x10400002, 0x2021, 0x24040001, 
-0xc004dab, 0x108042, 0x1600fffa, 0x32020013, 
-0xc004dab, 0x24040001, 0xc004dab, 0x2021, 
+0xc004d78, 0x108042, 0x1600fffa, 0x32020013, 
+0xc004d78, 0x24040001, 0xc004d78, 0x2021, 
 0x34108000, 0x96220000, 0x501024, 0x10400002, 
-0x2021, 0x24040001, 0xc004dab, 0x108042, 
-0x1600fff8, 0x0, 0xc004dec, 0x0, 
+0x2021, 0x24040001, 0xc004d78, 0x108042, 
+0x1600fff8, 0x0, 0xc004db9, 0x0, 
 0x8f830054, 0x10000207, 0x24020008, 0x8f830054, 
-0x3c020001, 0x8c426fb4, 0x2463ff9c, 0x431023, 
+0x3c020001, 0x8c426f3c, 0x2463ff9c, 0x431023, 
 0x2c420064, 0x1440020f, 0x24020009, 0x1000020b, 
 0x0, 0x27b10010, 0xa7a00010, 0x8021, 
-0xc004dab, 0x24040001, 0x26100001, 0x2e020020, 
-0x1440fffb, 0x0, 0xc004dab, 0x2021, 
-0xc004dab, 0x24040001, 0xc004dab, 0x24040001, 
-0xc004dab, 0x2021, 0x24100010, 0x32020001, 
-0x10400002, 0x2021, 0x24040001, 0xc004dab, 
+0xc004d78, 0x24040001, 0x26100001, 0x2e020020, 
+0x1440fffb, 0x0, 0xc004d78, 0x2021, 
+0xc004d78, 0x24040001, 0xc004d78, 0x24040001, 
+0xc004d78, 0x2021, 0x24100010, 0x32020001, 
+0x10400002, 0x2021, 0x24040001, 0xc004d78, 
 0x108042, 0x1600fffa, 0x32020001, 0x24100010, 
 0x32020018, 0x10400002, 0x2021, 0x24040001, 
-0xc004dab, 0x108042, 0x1600fffa, 0x32020018, 
-0xc004dec, 0x34108000, 0xc004dec, 0x0, 
-0xc004d8b, 0x0, 0x50400005, 0x108042, 
+0xc004d78, 0x108042, 0x1600fffa, 0x32020018, 
+0xc004db9, 0x34108000, 0xc004db9, 0x0, 
+0xc004d58, 0x0, 0x50400005, 0x108042, 
 0x96220000, 0x501025, 0xa6220000, 0x108042, 
-0x1600fff7, 0x0, 0xc004dec, 0x8021, 
+0x1600fff7, 0x0, 0xc004db9, 0x8021, 
 0x97a20010, 0x27b10010, 0x34420001, 0xa7a20010, 
-0xc004dab, 0x24040001, 0x26100001, 0x2e020020, 
-0x1440fffb, 0x0, 0xc004dab, 0x2021, 
-0xc004dab, 0x24040001, 0xc004dab, 0x2021, 
-0xc004dab, 0x24040001, 0x24100010, 0x32020001, 
-0x10400002, 0x2021, 0x24040001, 0xc004dab, 
+0xc004d78, 0x24040001, 0x26100001, 0x2e020020, 
+0x1440fffb, 0x0, 0xc004d78, 0x2021, 
+0xc004d78, 0x24040001, 0xc004d78, 0x2021, 
+0xc004d78, 0x24040001, 0x24100010, 0x32020001, 
+0x10400002, 0x2021, 0x24040001, 0xc004d78, 
 0x108042, 0x1600fffa, 0x32020001, 0x24100010, 
 0x32020018, 0x10400002, 0x2021, 0x24040001, 
-0xc004dab, 0x108042, 0x1600fffa, 0x32020018, 
-0xc004dab, 0x24040001, 0xc004dab, 0x2021, 
+0xc004d78, 0x108042, 0x1600fffa, 0x32020018, 
+0xc004d78, 0x24040001, 0xc004d78, 0x2021, 
 0x34108000, 0x96220000, 0x501024, 0x10400002, 
-0x2021, 0x24040001, 0xc004dab, 0x108042, 
-0x1600fff8, 0x0, 0xc004dec, 0x0, 
+0x2021, 0x24040001, 0xc004d78, 0x108042, 
+0x1600fff8, 0x0, 0xc004db9, 0x0, 
 0x8f830054, 0x10000193, 0x2402000a, 0x8f830054, 
-0x3c020001, 0x8c426fb4, 0x2463ff9c, 0x431023, 
+0x3c020001, 0x8c426f3c, 0x2463ff9c, 0x431023, 
 0x2c420064, 0x1440019b, 0x2402000b, 0x10000197, 
 0x0, 0x27b10010, 0xa7a00010, 0x8021, 
-0xc004dab, 0x24040001, 0x26100001, 0x2e020020, 
-0x1440fffb, 0x0, 0xc004dab, 0x2021, 
-0xc004dab, 0x24040001, 0xc004dab, 0x24040001, 
-0xc004dab, 0x2021, 0x24100010, 0x32020001, 
-0x10400002, 0x2021, 0x24040001, 0xc004dab, 
+0xc004d78, 0x24040001, 0x26100001, 0x2e020020, 
+0x1440fffb, 0x0, 0xc004d78, 0x2021, 
+0xc004d78, 0x24040001, 0xc004d78, 0x24040001, 
+0xc004d78, 0x2021, 0x24100010, 0x32020001, 
+0x10400002, 0x2021, 0x24040001, 0xc004d78, 
 0x108042, 0x1600fffa, 0x32020001, 0x24100010, 
 0x32020017, 0x10400002, 0x2021, 0x24040001, 
-0xc004dab, 0x108042, 0x1600fffa, 0x32020017, 
-0xc004dec, 0x34108000, 0xc004dec, 0x0, 
-0xc004d8b, 0x0, 0x50400005, 0x108042, 
+0xc004d78, 0x108042, 0x1600fffa, 0x32020017, 
+0xc004db9, 0x34108000, 0xc004db9, 0x0, 
+0xc004d58, 0x0, 0x50400005, 0x108042, 
 0x96220000, 0x501025, 0xa6220000, 0x108042, 
-0x1600fff7, 0x0, 0xc004dec, 0x8021, 
+0x1600fff7, 0x0, 0xc004db9, 0x8021, 
 0x97a20010, 0x27b10010, 0x34420700, 0xa7a20010, 
-0xc004dab, 0x24040001, 0x26100001, 0x2e020020, 
-0x1440fffb, 0x0, 0xc004dab, 0x2021, 
-0xc004dab, 0x24040001, 0xc004dab, 0x2021, 
-0xc004dab, 0x24040001, 0x24100010, 0x32020001, 
-0x10400002, 0x2021, 0x24040001, 0xc004dab, 
+0xc004d78, 0x24040001, 0x26100001, 0x2e020020, 
+0x1440fffb, 0x0, 0xc004d78, 0x2021, 
+0xc004d78, 0x24040001, 0xc004d78, 0x2021, 
+0xc004d78, 0x24040001, 0x24100010, 0x32020001, 
+0x10400002, 0x2021, 0x24040001, 0xc004d78, 
 0x108042, 0x1600fffa, 0x32020001, 0x24100010, 
 0x32020017, 0x10400002, 0x2021, 0x24040001, 
-0xc004dab, 0x108042, 0x1600fffa, 0x32020017, 
-0xc004dab, 0x24040001, 0xc004dab, 0x2021, 
+0xc004d78, 0x108042, 0x1600fffa, 0x32020017, 
+0xc004d78, 0x24040001, 0xc004d78, 0x2021, 
 0x34108000, 0x96220000, 0x501024, 0x10400002, 
-0x2021, 0x24040001, 0xc004dab, 0x108042, 
-0x1600fff8, 0x0, 0xc004dec, 0x0, 
+0x2021, 0x24040001, 0xc004d78, 0x108042, 
+0x1600fff8, 0x0, 0xc004db9, 0x0, 
 0x8f830054, 0x1000011f, 0x2402000c, 0x8f830054, 
-0x3c020001, 0x8c426fb4, 0x2463ff9c, 0x431023, 
+0x3c020001, 0x8c426f3c, 0x2463ff9c, 0x431023, 
 0x2c420064, 0x14400127, 0x24020012, 0x10000123, 
 0x0, 0x27b10010, 0xa7a00010, 0x8021, 
-0xc004dab, 0x24040001, 0x26100001, 0x2e020020, 
-0x1440fffb, 0x0, 0xc004dab, 0x2021, 
-0xc004dab, 0x24040001, 0xc004dab, 0x24040001, 
-0xc004dab, 0x2021, 0x24100010, 0x32020001, 
-0x10400002, 0x2021, 0x24040001, 0xc004dab, 
+0xc004d78, 0x24040001, 0x26100001, 0x2e020020, 
+0x1440fffb, 0x0, 0xc004d78, 0x2021, 
+0xc004d78, 0x24040001, 0xc004d78, 0x24040001, 
+0xc004d78, 0x2021, 0x24100010, 0x32020001, 
+0x10400002, 0x2021, 0x24040001, 0xc004d78, 
 0x108042, 0x1600fffa, 0x32020001, 0x24100010, 
 0x32020014, 0x10400002, 0x2021, 0x24040001, 
-0xc004dab, 0x108042, 0x1600fffa, 0x32020014, 
-0xc004dec, 0x34108000, 0xc004dec, 0x0, 
-0xc004d8b, 0x0, 0x50400005, 0x108042, 
+0xc004d78, 0x108042, 0x1600fffa, 0x32020014, 
+0xc004db9, 0x34108000, 0xc004db9, 0x0, 
+0xc004d58, 0x0, 0x50400005, 0x108042, 
 0x96220000, 0x501025, 0xa6220000, 0x108042, 
-0x1600fff7, 0x0, 0xc004dec, 0x8021, 
+0x1600fff7, 0x0, 0xc004db9, 0x8021, 
 0x97a20010, 0x27b10010, 0x34420010, 0xa7a20010, 
-0xc004dab, 0x24040001, 0x26100001, 0x2e020020, 
-0x1440fffb, 0x0, 0xc004dab, 0x2021, 
-0xc004dab, 0x24040001, 0xc004dab, 0x2021, 
-0xc004dab, 0x24040001, 0x24100010, 0x32020001, 
-0x10400002, 0x2021, 0x24040001, 0xc004dab, 
+0xc004d78, 0x24040001, 0x26100001, 0x2e020020, 
+0x1440fffb, 0x0, 0xc004d78, 0x2021, 
+0xc004d78, 0x24040001, 0xc004d78, 0x2021, 
+0xc004d78, 0x24040001, 0x24100010, 0x32020001, 
+0x10400002, 0x2021, 0x24040001, 0xc004d78, 
 0x108042, 0x1600fffa, 0x32020001, 0x24100010, 
 0x32020014, 0x10400002, 0x2021, 0x24040001, 
-0xc004dab, 0x108042, 0x1600fffa, 0x32020014, 
-0xc004dab, 0x24040001, 0xc004dab, 0x2021, 
+0xc004d78, 0x108042, 0x1600fffa, 0x32020014, 
+0xc004d78, 0x24040001, 0xc004d78, 0x2021, 
 0x34108000, 0x96220000, 0x501024, 0x10400002, 
-0x2021, 0x24040001, 0xc004dab, 0x108042, 
-0x1600fff8, 0x0, 0xc004dec, 0x0, 
+0x2021, 0x24040001, 0xc004d78, 0x108042, 
+0x1600fff8, 0x0, 0xc004db9, 0x0, 
 0x8f830054, 0x100000ab, 0x24020013, 0x8f830054, 
-0x3c020001, 0x8c426fb4, 0x2463ff9c, 0x431023, 
+0x3c020001, 0x8c426f3c, 0x2463ff9c, 0x431023, 
 0x2c420064, 0x144000b3, 0x2402000d, 0x100000af, 
 0x0, 0x27b10010, 0xa7a00010, 0x8021, 
-0xc004dab, 0x24040001, 0x26100001, 0x2e020020, 
-0x1440fffb, 0x0, 0xc004dab, 0x2021, 
-0xc004dab, 0x24040001, 0xc004dab, 0x24040001, 
-0xc004dab, 0x2021, 0x24100010, 0x32020001, 
-0x10400002, 0x2021, 0x24040001, 0xc004dab, 
+0xc004d78, 0x24040001, 0x26100001, 0x2e020020, 
+0x1440fffb, 0x0, 0xc004d78, 0x2021, 
+0xc004d78, 0x24040001, 0xc004d78, 0x24040001, 
+0xc004d78, 0x2021, 0x24100010, 0x32020001, 
+0x10400002, 0x2021, 0x24040001, 0xc004d78, 
 0x108042, 0x1600fffa, 0x32020001, 0x24100010, 
 0x32020018, 0x10400002, 0x2021, 0x24040001, 
-0xc004dab, 0x108042, 0x1600fffa, 0x32020018, 
-0xc004dec, 0x34108000, 0xc004dec, 0x0, 
-0xc004d8b, 0x0, 0x50400005, 0x108042, 
+0xc004d78, 0x108042, 0x1600fffa, 0x32020018, 
+0xc004db9, 0x34108000, 0xc004db9, 0x0, 
+0xc004d58, 0x0, 0x50400005, 0x108042, 
 0x96220000, 0x501025, 0xa6220000, 0x108042, 
-0x1600fff7, 0x0, 0xc004dec, 0x8021, 
+0x1600fff7, 0x0, 0xc004db9, 0x8021, 
 0x97a20010, 0x27b10010, 0x3042fffe, 0xa7a20010, 
-0xc004dab, 0x24040001, 0x26100001, 0x2e020020, 
-0x1440fffb, 0x0, 0xc004dab, 0x2021, 
-0xc004dab, 0x24040001, 0xc004dab, 0x2021, 
-0xc004dab, 0x24040001, 0x24100010, 0x32020001, 
-0x10400002, 0x2021, 0x24040001, 0xc004dab, 
+0xc004d78, 0x24040001, 0x26100001, 0x2e020020, 
+0x1440fffb, 0x0, 0xc004d78, 0x2021, 
+0xc004d78, 0x24040001, 0xc004d78, 0x2021, 
+0xc004d78, 0x24040001, 0x24100010, 0x32020001, 
+0x10400002, 0x2021, 0x24040001, 0xc004d78, 
 0x108042, 0x1600fffa, 0x32020001, 0x24100010, 
 0x32020018, 0x10400002, 0x2021, 0x24040001, 
-0xc004dab, 0x108042, 0x1600fffa, 0x32020018, 
-0xc004dab, 0x24040001, 0xc004dab, 0x2021, 
+0xc004d78, 0x108042, 0x1600fffa, 0x32020018, 
+0xc004d78, 0x24040001, 0xc004d78, 0x2021, 
 0x34108000, 0x96220000, 0x501024, 0x10400002, 
-0x2021, 0x24040001, 0xc004dab, 0x108042, 
-0x1600fff8, 0x0, 0xc004dec, 0x0, 
+0x2021, 0x24040001, 0xc004d78, 0x108042, 
+0x1600fff8, 0x0, 0xc004db9, 0x0, 
 0x8f830054, 0x10000037, 0x2402000e, 0x24020840, 
-0xa7a20010, 0x27b10010, 0x8021, 0xc004dab, 
+0xa7a20010, 0x27b10010, 0x8021, 0xc004d78, 
 0x24040001, 0x26100001, 0x2e020020, 0x1440fffb, 
-0x0, 0xc004dab, 0x2021, 0xc004dab, 
-0x24040001, 0xc004dab, 0x2021, 0xc004dab, 
+0x0, 0xc004d78, 0x2021, 0xc004d78, 
+0x24040001, 0xc004d78, 0x2021, 0xc004d78, 
 0x24040001, 0x24100010, 0x32020001, 0x10400002, 
-0x2021, 0x24040001, 0xc004dab, 0x108042, 
+0x2021, 0x24040001, 0xc004d78, 0x108042, 
 0x1600fffa, 0x32020001, 0x24100010, 0x32020013, 
-0x10400002, 0x2021, 0x24040001, 0xc004dab, 
-0x108042, 0x1600fffa, 0x32020013, 0xc004dab, 
-0x24040001, 0xc004dab, 0x2021, 0x34108000, 
+0x10400002, 0x2021, 0x24040001, 0xc004d78, 
+0x108042, 0x1600fffa, 0x32020013, 0xc004d78, 
+0x24040001, 0xc004d78, 0x2021, 0x34108000, 
 0x96220000, 0x501024, 0x10400002, 0x2021, 
-0x24040001, 0xc004dab, 0x108042, 0x1600fff8, 
-0x0, 0xc004dec, 0x0, 0x8f830054, 
-0x24020010, 0x3c010001, 0xac226e50, 0x3c010001, 
-0x1000000c, 0xac236fb4, 0x8f830054, 0x3c020001, 
-0x8c426fb4, 0x2463ff9c, 0x431023, 0x2c420064, 
+0x24040001, 0xc004d78, 0x108042, 0x1600fff8, 
+0x0, 0xc004db9, 0x0, 0x8f830054, 
+0x24020010, 0x3c010001, 0xac226dd0, 0x3c010001, 
+0x1000000c, 0xac236f3c, 0x8f830054, 0x3c020001, 
+0x8c426f3c, 0x2463ff9c, 0x431023, 0x2c420064, 
 0x14400004, 0x0, 0x24020011, 0x3c010001, 
-0xac226e50, 0x8fbf0020, 0x8fb1001c, 0x8fb00018, 
-0x3e00008, 0x27bd0028, 0x3c030001, 0x8c636e18, 
+0xac226dd0, 0x8fbf0020, 0x8fb1001c, 0x8fb00018, 
+0x3e00008, 0x27bd0028, 0x3c030001, 0x8c636d98, 
 0x27bdffc8, 0x24020002, 0xafbf0034, 0xafb20030, 
 0xafb1002c, 0x14620004, 0xafb00028, 0x3c120002, 
-0x10000003, 0x8e529078, 0x3c120002, 0x8e52907c, 
-0x3c030001, 0x8c636e54, 0x3c020001, 0x8c426e9c, 
-0x50620004, 0x2463ffff, 0x3c010001, 0xac236e9c, 
-0x2463ffff, 0x2c620006, 0x104004b9, 0x31080, 
-0x3c010001, 0x220821, 0x8c226c68, 0x400008, 
-0x0, 0x2021, 0x2821, 0xc004e0e, 
+0x10000003, 0x8e528ff8, 0x3c120002, 0x8e528ffc, 
+0x3c030001, 0x8c636dd4, 0x3c020001, 0x8c426e1c, 
+0x50620004, 0x2463ffff, 0x3c010001, 0xac236e1c, 
+0x2463ffff, 0x2c620006, 0x10400377, 0x31080, 
+0x3c010001, 0x220821, 0x8c226bd8, 0x400008, 
+0x0, 0x2021, 0x2821, 0xc004ddb, 
 0x34068000, 0x24040010, 0x24050002, 0x24060002, 
-0x24020002, 0xc004e0e, 0xa7a20018, 0x24020002, 
-0x3c010001, 0x100004a6, 0xac226e54, 0x27b10018, 
-0xa7a00018, 0x8021, 0xc004dab, 0x24040001, 
+0x24020002, 0xc004ddb, 0xa7a20018, 0x24020002, 
+0x3c010001, 0x10000364, 0xac226dd4, 0x27b10018, 
+0xa7a00018, 0x8021, 0xc004d78, 0x24040001, 
 0x26100001, 0x2e020020, 0x1440fffb, 0x0, 
-0xc004dab, 0x2021, 0xc004dab, 0x24040001, 
-0xc004dab, 0x24040001, 0xc004dab, 0x2021, 
+0xc004d78, 0x2021, 0xc004d78, 0x24040001, 
+0xc004d78, 0x24040001, 0xc004d78, 0x2021, 
 0x24100010, 0x32020001, 0x10400002, 0x2021, 
-0x24040001, 0xc004dab, 0x108042, 0x1600fffa, 
-0x32020001, 0x24100010, 0xc004dab, 0x2021, 
-0x108042, 0x1600fffc, 0x0, 0xc004dec, 
-0x34108000, 0xc004dec, 0x0, 0xc004d8b, 
+0x24040001, 0xc004d78, 0x108042, 0x1600fffa, 
+0x32020001, 0x24100010, 0xc004d78, 0x2021, 
+0x108042, 0x1600fffc, 0x0, 0xc004db9, 
+0x34108000, 0xc004db9, 0x0, 0xc004d58, 
 0x0, 0x50400005, 0x108042, 0x96220000, 
 0x501025, 0xa6220000, 0x108042, 0x1600fff7, 
-0x0, 0xc004dec, 0x0, 0x97a20018, 
+0x0, 0xc004db9, 0x0, 0x97a20018, 
 0x30428000, 0x14400004, 0x24020003, 0x3c010001, 
-0xac226e54, 0x24020003, 0x3c010001, 0x1000046c, 
-0xac226e54, 0x24040010, 0x24050002, 0x24060002, 
-0x24020002, 0xc004e0e, 0xa7a20018, 0x3c030001, 
-0x8c636ea0, 0x24020001, 0x146201e2, 0x0, 
-0x27b10018, 0xa7a00018, 0x8021, 0xc004dab, 
-0x24040001, 0x26100001, 0x2e020020, 0x1440fffb, 
-0x0, 0xc004dab, 0x2021, 0xc004dab, 
-0x24040001, 0xc004dab, 0x24040001, 0xc004dab, 
-0x2021, 0x24100010, 0x32020001, 0x10400002, 
-0x2021, 0x24040001, 0xc004dab, 0x108042, 
-0x1600fffa, 0x32020001, 0x24100010, 0x32020018, 
-0x10400002, 0x2021, 0x24040001, 0xc004dab, 
-0x108042, 0x1600fffa, 0x32020018, 0xc004dec, 
-0x34108000, 0xc004dec, 0x0, 0xc004d8b, 
-0x0, 0x50400005, 0x108042, 0x96220000, 
-0x501025, 0xa6220000, 0x108042, 0x1600fff7, 
-0x0, 0xc004dec, 0x8021, 0x27b10018, 
-0xa7a00018, 0xc004dab, 0x24040001, 0x26100001, 
-0x2e020020, 0x1440fffb, 0x0, 0xc004dab, 
-0x2021, 0xc004dab, 0x24040001, 0xc004dab, 
-0x24040001, 0xc004dab, 0x2021, 0x24100010, 
+0xac226dd4, 0x24020003, 0x3c010001, 0x1000032a, 
+0xac226dd4, 0x24040010, 0x24050002, 0x24060002, 
+0x24020002, 0xc004ddb, 0xa7a20018, 0x3c030001, 
+0x8c636e20, 0x24020001, 0x146201e1, 0x8021, 
+0x27b10018, 0xa7a00018, 0xc004d78, 0x24040001, 
+0x26100001, 0x2e020020, 0x1440fffb, 0x0, 
+0xc004d78, 0x2021, 0xc004d78, 0x24040001, 
+0xc004d78, 0x24040001, 0xc004d78, 0x2021, 
+0x24100010, 0x32020001, 0x10400002, 0x2021, 
+0x24040001, 0xc004d78, 0x108042, 0x1600fffa, 
+0x32020001, 0x24100010, 0x32020018, 0x10400002, 
+0x2021, 0x24040001, 0xc004d78, 0x108042, 
+0x1600fffa, 0x32020018, 0xc004db9, 0x34108000, 
+0xc004db9, 0x0, 0xc004d58, 0x0, 
+0x50400005, 0x108042, 0x96220000, 0x501025, 
+0xa6220000, 0x108042, 0x1600fff7, 0x0, 
+0xc004db9, 0x8021, 0x27b10018, 0xa7a00018, 
+0xc004d78, 0x24040001, 0x26100001, 0x2e020020, 
+0x1440fffb, 0x0, 0xc004d78, 0x2021, 
+0xc004d78, 0x24040001, 0xc004d78, 0x24040001, 
+0xc004d78, 0x2021, 0x24100010, 0x32020001, 
+0x10400002, 0x2021, 0x24040001, 0xc004d78, 
+0x108042, 0x1600fffa, 0x32020001, 0x24100010, 
+0x32020018, 0x10400002, 0x2021, 0x24040001, 
+0xc004d78, 0x108042, 0x1600fffa, 0x32020018, 
+0xc004db9, 0x34108000, 0xc004db9, 0x0, 
+0xc004d58, 0x0, 0x50400005, 0x108042, 
+0x96220000, 0x501025, 0xa6220000, 0x108042, 
+0x1600fff7, 0x0, 0xc004db9, 0x8021, 
+0x24040018, 0x2821, 0xc004ddb, 0x24060404, 
+0xa7a0001a, 0xc004d78, 0x24040001, 0x26100001, 
+0x2e020020, 0x1440fffb, 0x0, 0xc004d78, 
+0x2021, 0xc004d78, 0x24040001, 0xc004d78, 
+0x24040001, 0xc004d78, 0x2021, 0x24100010, 
 0x32020001, 0x10400002, 0x2021, 0x24040001, 
-0xc004dab, 0x108042, 0x1600fffa, 0x32020001, 
+0xc004d78, 0x108042, 0x1600fffa, 0x32020001, 
 0x24100010, 0x32020018, 0x10400002, 0x2021, 
-0x24040001, 0xc004dab, 0x108042, 0x1600fffa, 
-0x32020018, 0xc004dec, 0x34108000, 0xc004dec, 
-0x0, 0xc004d8b, 0x0, 0x50400005, 
-0x108042, 0x96220000, 0x501025, 0xa6220000, 
-0x108042, 0x1600fff7, 0x0, 0xc004dec, 
-0x8021, 0x24040018, 0x2821, 0xc004e0e, 
-0x24060404, 0xa7a0001a, 0xc004dab, 0x24040001, 
+0x24040001, 0xc004d78, 0x108042, 0x1600fffa, 
+0x32020018, 0xc004db9, 0x34108000, 0xc004db9, 
+0x0, 0xc004d58, 0x0, 0x50400005, 
+0x108042, 0x97a2001a, 0x501025, 0xa7a2001a, 
+0x108042, 0x1600fff7, 0x0, 0xc004db9, 
+0x8021, 0xa7a0001a, 0xc004d78, 0x24040001, 
 0x26100001, 0x2e020020, 0x1440fffb, 0x0, 
-0xc004dab, 0x2021, 0xc004dab, 0x24040001, 
-0xc004dab, 0x24040001, 0xc004dab, 0x2021, 
+0xc004d78, 0x2021, 0xc004d78, 0x24040001, 
+0xc004d78, 0x24040001, 0xc004d78, 0x2021, 
 0x24100010, 0x32020001, 0x10400002, 0x2021, 
-0x24040001, 0xc004dab, 0x108042, 0x1600fffa, 
+0x24040001, 0xc004d78, 0x108042, 0x1600fffa, 
 0x32020001, 0x24100010, 0x32020018, 0x10400002, 
-0x2021, 0x24040001, 0xc004dab, 0x108042, 
-0x1600fffa, 0x32020018, 0xc004dec, 0x34108000, 
-0xc004dec, 0x0, 0xc004d8b, 0x0, 
+0x2021, 0x24040001, 0xc004d78, 0x108042, 
+0x1600fffa, 0x32020018, 0xc004db9, 0x34108000, 
+0xc004db9, 0x0, 0xc004d58, 0x0, 
 0x50400005, 0x108042, 0x97a2001a, 0x501025, 
 0xa7a2001a, 0x108042, 0x1600fff7, 0x0, 
-0xc004dec, 0x8021, 0xa7a0001a, 0xc004dab, 
+0xc004db9, 0x8021, 0xa7a0001c, 0xc004d78, 
 0x24040001, 0x26100001, 0x2e020020, 0x1440fffb, 
-0x0, 0xc004dab, 0x2021, 0xc004dab, 
-0x24040001, 0xc004dab, 0x24040001, 0xc004dab, 
-0x2021, 0x24100010, 0x32020001, 0x10400002, 
-0x2021, 0x24040001, 0xc004dab, 0x108042, 
-0x1600fffa, 0x32020001, 0x24100010, 0x32020018, 
-0x10400002, 0x2021, 0x24040001, 0xc004dab, 
-0x108042, 0x1600fffa, 0x32020018, 0xc004dec, 
-0x34108000, 0xc004dec, 0x0, 0xc004d8b, 
-0x0, 0x50400005, 0x108042, 0x97a2001a, 
-0x501025, 0xa7a2001a, 0x108042, 0x1600fff7, 
-0x0, 0xc004dec, 0x8021, 0xa7a0001c, 
-0xc004dab, 0x24040001, 0x26100001, 0x2e020020, 
-0x1440fffb, 0x0, 0xc004dab, 0x2021, 
-0xc004dab, 0x24040001, 0xc004dab, 0x24040001, 
-0xc004dab, 0x2021, 0x24100010, 0xc004dab, 
+0x0, 0xc004d78, 0x2021, 0xc004d78, 
+0x24040001, 0xc004d78, 0x24040001, 0xc004d78, 
+0x2021, 0x24100010, 0xc004d78, 0x2021, 
+0x108042, 0x1600fffc, 0x0, 0x24100010, 
+0x3202001e, 0x10400002, 0x2021, 0x24040001, 
+0xc004d78, 0x108042, 0x1600fffa, 0x3202001e, 
+0xc004db9, 0x34108000, 0xc004db9, 0x0, 
+0xc004d58, 0x0, 0x50400005, 0x108042, 
+0x97a2001c, 0x501025, 0xa7a2001c, 0x108042, 
+0x1600fff7, 0x0, 0xc004db9, 0x8021, 
+0xa7a0001c, 0xc004d78, 0x24040001, 0x26100001, 
+0x2e020020, 0x1440fffb, 0x0, 0xc004d78, 
+0x2021, 0xc004d78, 0x24040001, 0xc004d78, 
+0x24040001, 0xc004d78, 0x2021, 0x24100010, 
+0xc004d78, 0x2021, 0x108042, 0x1600fffc, 
+0x0, 0x24100010, 0x3202001e, 0x10400002, 
+0x2021, 0x24040001, 0xc004d78, 0x108042, 
+0x1600fffa, 0x3202001e, 0xc004db9, 0x34108000, 
+0xc004db9, 0x0, 0xc004d58, 0x0, 
+0x50400005, 0x108042, 0x97a2001c, 0x501025, 
+0xa7a2001c, 0x108042, 0x1600fff7, 0x0, 
+0xc004db9, 0x8021, 0x24020002, 0xa7a2001e, 
+0xc004d78, 0x24040001, 0x26100001, 0x2e020020, 
+0x1440fffb, 0x0, 0xc004d78, 0x2021, 
+0xc004d78, 0x24040001, 0xc004d78, 0x2021, 
+0xc004d78, 0x24040001, 0x24100010, 0xc004d78, 
 0x2021, 0x108042, 0x1600fffc, 0x0, 
 0x24100010, 0x3202001e, 0x10400002, 0x2021, 
-0x24040001, 0xc004dab, 0x108042, 0x1600fffa, 
-0x3202001e, 0xc004dec, 0x34108000, 0xc004dec, 
-0x0, 0xc004d8b, 0x0, 0x50400005, 
-0x108042, 0x97a2001c, 0x501025, 0xa7a2001c, 
-0x108042, 0x1600fff7, 0x0, 0xc004dec, 
-0x8021, 0xa7a0001c, 0xc004dab, 0x24040001, 
+0x24040001, 0xc004d78, 0x108042, 0x1600fffa, 
+0x3202001e, 0xc004d78, 0x24040001, 0xc004d78, 
+0x2021, 0x34108000, 0x97a2001e, 0x501024, 
+0x10400002, 0x2021, 0x24040001, 0xc004d78, 
+0x108042, 0x1600fff8, 0x0, 0xc004db9, 
+0x8021, 0xa7a00020, 0xc004d78, 0x24040001, 
 0x26100001, 0x2e020020, 0x1440fffb, 0x0, 
-0xc004dab, 0x2021, 0xc004dab, 0x24040001, 
-0xc004dab, 0x24040001, 0xc004dab, 0x2021, 
-0x24100010, 0xc004dab, 0x2021, 0x108042, 
+0xc004d78, 0x2021, 0xc004d78, 0x24040001, 
+0xc004d78, 0x24040001, 0xc004d78, 0x2021, 
+0x24100010, 0xc004d78, 0x2021, 0x108042, 
 0x1600fffc, 0x0, 0x24100010, 0x3202001e, 
-0x10400002, 0x2021, 0x24040001, 0xc004dab, 
-0x108042, 0x1600fffa, 0x3202001e, 0xc004dec, 
-0x34108000, 0xc004dec, 0x0, 0xc004d8b, 
-0x0, 0x50400005, 0x108042, 0x97a2001c, 
-0x501025, 0xa7a2001c, 0x108042, 0x1600fff7, 
-0x0, 0xc004dec, 0x8021, 0x24020002, 
-0xa7a2001e, 0xc004dab, 0x24040001, 0x26100001, 
-0x2e020020, 0x1440fffb, 0x0, 0xc004dab, 
-0x2021, 0xc004dab, 0x24040001, 0xc004dab, 
-0x2021, 0xc004dab, 0x24040001, 0x24100010, 
-0xc004dab, 0x2021, 0x108042, 0x1600fffc, 
-0x0, 0x24100010, 0x3202001e, 0x10400002, 
-0x2021, 0x24040001, 0xc004dab, 0x108042, 
-0x1600fffa, 0x3202001e, 0xc004dab, 0x24040001, 
-0xc004dab, 0x2021, 0x34108000, 0x97a2001e, 
-0x501024, 0x10400002, 0x2021, 0x24040001, 
-0xc004dab, 0x108042, 0x1600fff8, 0x0, 
-0xc004dec, 0x8021, 0xa7a00020, 0xc004dab, 
-0x24040001, 0x26100001, 0x2e020020, 0x1440fffb, 
-0x0, 0xc004dab, 0x2021, 0xc004dab, 
-0x24040001, 0xc004dab, 0x24040001, 0xc004dab, 
-0x2021, 0x24100010, 0xc004dab, 0x2021, 
-0x108042, 0x1600fffc, 0x0, 0x24100010, 
-0x3202001e, 0x10400002, 0x2021, 0x24040001, 
-0xc004dab, 0x108042, 0x1600fffa, 0x3202001e, 
-0xc004dec, 0x34108000, 0xc004dec, 0x0, 
-0xc004d8b, 0x0, 0x50400005, 0x108042, 
-0x97a20020, 0x501025, 0xa7a20020, 0x108042, 
-0x1600fff7, 0x0, 0xc004dec, 0x8021, 
-0xa7a00020, 0xc004dab, 0x24040001, 0x26100001, 
-0x2e020020, 0x1440fffb, 0x0, 0xc004dab, 
-0x2021, 0xc004dab, 0x24040001, 0xc004dab, 
-0x24040001, 0xc004dab, 0x2021, 0x24100010, 
-0xc004dab, 0x2021, 0x108042, 0x1600fffc, 
-0x0, 0x24100010, 0x3202001e, 0x10400002, 
-0x2021, 0x24040001, 0xc004dab, 0x108042, 
-0x1600fffa, 0x3202001e, 0xc004dec, 0x34108000, 
-0xc004dec, 0x0, 0xc004d8b, 0x0, 
-0x50400005, 0x108042, 0x97a20020, 0x501025, 
-0xa7a20020, 0x108042, 0x1600fff7, 0x0, 
-0xc004dec, 0x8021, 0xa7a00022, 0xc004dab, 
-0x24040001, 0x26100001, 0x2e020020, 0x1440fffb, 
-0x0, 0xc004dab, 0x2021, 0xc004dab, 
-0x24040001, 0xc004dab, 0x2021, 0xc004dab, 
-0x24040001, 0x24100010, 0xc004dab, 0x2021, 
-0x108042, 0x1600fffc, 0x0, 0x24100010, 
-0xc004dab, 0x2021, 0x108042, 0x1600fffc, 
-0x0, 0xc004dab, 0x24040001, 0xc004dab, 
-0x2021, 0x34108000, 0x97a20022, 0x501024, 
-0x10400002, 0x2021, 0x24040001, 0xc004dab, 
-0x108042, 0x1600fff8, 0x0, 0xc004dec, 
-0x0, 0x24040018, 0x24050002, 0xc004e0e, 
-0x24060004, 0x3c030001, 0x8c636ea4, 0x24020001, 
-0x146200fc, 0x3c024000, 0x3c010001, 0xac206ea4, 
-0x2421024, 0x10400276, 0x3c022000, 0x2421024, 
-0x10400004, 0x0, 0x3c010001, 0x10000003, 
-0xac236f98, 0x3c010001, 0xac206f98, 0x3c030001, 
-0x8c636fac, 0x24020005, 0x146200ea, 0x0, 
-0x3c020001, 0x8c426f98, 0x1040005f, 0x3c020004, 
-0x2421024, 0x10400011, 0xa7a00018, 0x3c020008, 
-0x2421024, 0x10400002, 0x24020200, 0xa7a20018, 
-0x3c020010, 0x2421024, 0x10400004, 0x0, 
-0x97a20018, 0x34420100, 0xa7a20018, 0x97a60018, 
-0x24040009, 0x10000004, 0x2821, 0x24040009, 
-0x2821, 0x3021, 0xc004e0e, 0x0, 
-0x24020001, 0xa7a2001a, 0x3c020008, 0x2421024, 
-0x1040000c, 0x3c020002, 0x2421024, 0x10400002, 
-0x24020101, 0xa7a2001a, 0x3c020001, 0x2421024, 
-0x10400005, 0x3c020010, 0x97a2001a, 0x34420040, 
-0xa7a2001a, 0x3c020010, 0x2421024, 0x1040000e, 
-0x3c020002, 0x2421024, 0x10400005, 0x3c020001, 
-0x97a2001a, 0x34420080, 0xa7a2001a, 0x3c020001, 
-0x2421024, 0x10400005, 0x3c0300a0, 0x97a2001a, 
-0x34420020, 0xa7a2001a, 0x3c0300a0, 0x2431024, 
-0x54430004, 0x3c020020, 0x97a2001a, 0x1000000c, 
-0x34420400, 0x2421024, 0x50400004, 0x3c020080, 
-0x97a2001a, 0x10000006, 0x34420800, 0x2421024, 
-0x10400004, 0x0, 0x97a2001a, 0x34420c00, 
-0xa7a2001a, 0x97a6001a, 0x24040004, 0xc004e0e, 
-0x2821, 0x32424000, 0x10400003, 0xa7a0001c, 
-0x24024000, 0xa7a2001c, 0x97a6001c, 0x2021, 
-0x2821, 0x34c61200, 0xc004e0e, 0xa7a6001c, 
-0x10000088, 0x0, 0x32424000, 0x10400003, 
-0xa7a00018, 0x24024000, 0xa7a20018, 0x3c020010, 
+0x10400002, 0x2021, 0x24040001, 0xc004d78, 
+0x108042, 0x1600fffa, 0x3202001e, 0xc004db9, 
+0x34108000, 0xc004db9, 0x0, 0xc004d58, 
+0x0, 0x50400005, 0x108042, 0x97a20020, 
+0x501025, 0xa7a20020, 0x108042, 0x1600fff7, 
+0x0, 0xc004db9, 0x8021, 0xa7a00020, 
+0xc004d78, 0x24040001, 0x26100001, 0x2e020020, 
+0x1440fffb, 0x0, 0xc004d78, 0x2021, 
+0xc004d78, 0x24040001, 0xc004d78, 0x24040001, 
+0xc004d78, 0x2021, 0x24100010, 0xc004d78, 
+0x2021, 0x108042, 0x1600fffc, 0x0, 
+0x24100010, 0x3202001e, 0x10400002, 0x2021, 
+0x24040001, 0xc004d78, 0x108042, 0x1600fffa, 
+0x3202001e, 0xc004db9, 0x34108000, 0xc004db9, 
+0x0, 0xc004d58, 0x0, 0x50400005, 
+0x108042, 0x97a20020, 0x501025, 0xa7a20020, 
+0x108042, 0x1600fff7, 0x0, 0xc004db9, 
+0x8021, 0xa7a00022, 0xc004d78, 0x24040001, 
+0x26100001, 0x2e020020, 0x1440fffb, 0x0, 
+0xc004d78, 0x2021, 0xc004d78, 0x24040001, 
+0xc004d78, 0x2021, 0xc004d78, 0x24040001, 
+0x24100010, 0xc004d78, 0x2021, 0x108042, 
+0x1600fffc, 0x0, 0x24100010, 0xc004d78, 
+0x2021, 0x108042, 0x1600fffc, 0x0, 
+0xc004d78, 0x24040001, 0xc004d78, 0x2021, 
+0x34108000, 0x97a20022, 0x501024, 0x10400002, 
+0x2021, 0x24040001, 0xc004d78, 0x108042, 
+0x1600fff8, 0x0, 0xc004db9, 0x0, 
+0x24040018, 0x24050002, 0xc004ddb, 0x24060004, 
+0x3c100001, 0x8e106e24, 0x24020001, 0x1602011d, 
+0x0, 0x3c020001, 0x94426f26, 0x3c010001, 
+0xac206e24, 0x24429fbc, 0x2c420004, 0x1040000c, 
+0x24040009, 0x24050001, 0xc004ddb, 0x24060400, 
+0x24040018, 0x24050001, 0xc004ddb, 0x24060020, 
+0x24040018, 0x24050001, 0xc004ddb, 0x24062000, 
+0x3c024000, 0x2421024, 0x10400123, 0x3c022000, 
+0x2421024, 0x10400004, 0x0, 0x3c010001, 
+0x10000003, 0xac306f1c, 0x3c010001, 0xac206f1c, 
+0x3c030001, 0x8c636f34, 0x24020005, 0x146200f9, 
+0x0, 0x3c020001, 0x8c426f1c, 0x10400067, 
+0x3c020004, 0x2421024, 0x10400011, 0xa7a00018, 
+0x3c020008, 0x2421024, 0x10400002, 0x24020200, 
+0xa7a20018, 0x3c020010, 0x2421024, 0x10400004, 
+0x0, 0x97a20018, 0x34420100, 0xa7a20018, 
+0x97a60018, 0x24040009, 0x10000004, 0x2821, 
+0x24040009, 0x2821, 0x3021, 0xc004ddb, 
+0x0, 0x24020001, 0xa7a2001a, 0x3c020008, 
+0x2421024, 0x1040000c, 0x3c020002, 0x2421024, 
+0x10400002, 0x24020101, 0xa7a2001a, 0x3c020001, 
+0x2421024, 0x10400005, 0x3c020010, 0x97a2001a, 
+0x34420040, 0xa7a2001a, 0x3c020010, 0x2421024, 
+0x1040000e, 0x3c020002, 0x2421024, 0x10400005, 
+0x3c020001, 0x97a2001a, 0x34420080, 0xa7a2001a, 
+0x3c020001, 0x2421024, 0x10400005, 0x3c0300a0, 
+0x97a2001a, 0x34420020, 0xa7a2001a, 0x3c0300a0, 
+0x2431024, 0x54430004, 0x3c020020, 0x97a2001a, 
+0x1000000c, 0x34420400, 0x2421024, 0x50400004, 
+0x3c020080, 0x97a2001a, 0x10000006, 0x34420800, 
+0x2421024, 0x10400004, 0x0, 0x97a2001a, 
+0x34420c00, 0xa7a2001a, 0x97a6001a, 0x24040004, 
+0xc004ddb, 0x2821, 0x3c020004, 0x2421024, 
+0x10400004, 0xa7a0001c, 0x32425000, 0x14400004, 
+0x0, 0x32424000, 0x10400005, 0x2021, 
+0xc004cf9, 0x2402021, 0x10000096, 0x0, 
+0x97a6001c, 0x2821, 0x34c61200, 0xc004ddb, 
+0xa7a6001c, 0x1000008f, 0x0, 0x2421024, 
+0x10400004, 0xa7a00018, 0x32425000, 0x14400004, 
+0x0, 0x32424000, 0x10400005, 0x3c020010, 
+0xc004cf9, 0x2402021, 0x10000019, 0xa7a0001a, 
 0x2421024, 0x10400004, 0x0, 0x97a20018, 
 0x10000004, 0xa7a20018, 0x97a20018, 0x34420100, 
 0xa7a20018, 0x3c020001, 0x2421024, 0x10400004, 
 0x0, 0x97a20018, 0x10000004, 0xa7a20018, 
-0x97a20018, 0x34422000, 0xa7a20018, 0x2021, 
-0x97a60018, 0x2821, 0xc004e0e, 0x8021, 
-0xa7a0001a, 0xc004dab, 0x24040001, 0x26100001, 
-0x2e020020, 0x1440fffb, 0x0, 0xc004dab, 
-0x2021, 0xc004dab, 0x24040001, 0xc004dab, 
-0x24040001, 0xc004dab, 0x2021, 0x24100010, 
+0x97a20018, 0x34422000, 0xa7a20018, 0x97a60018, 
+0x2021, 0xc004ddb, 0x2821, 0xa7a0001a, 
+0x8021, 0xc004d78, 0x24040001, 0x26100001, 
+0x2e020020, 0x1440fffb, 0x0, 0xc004d78, 
+0x2021, 0xc004d78, 0x24040001, 0xc004d78, 
+0x24040001, 0xc004d78, 0x2021, 0x24100010, 
 0x32020001, 0x10400002, 0x2021, 0x24040001, 
-0xc004dab, 0x108042, 0x1600fffa, 0x32020001, 
-0x24100010, 0xc004dab, 0x2021, 0x108042, 
-0x1600fffc, 0x0, 0xc004dec, 0x34108000, 
-0xc004dec, 0x0, 0xc004d8b, 0x0, 
+0xc004d78, 0x108042, 0x1600fffa, 0x32020001, 
+0x24100010, 0xc004d78, 0x2021, 0x108042, 
+0x1600fffc, 0x0, 0xc004db9, 0x34108000, 
+0xc004db9, 0x0, 0xc004d58, 0x0, 
 0x50400005, 0x108042, 0x97a2001a, 0x501025, 
 0xa7a2001a, 0x108042, 0x1600fff7, 0x0, 
-0xc004dec, 0x8021, 0xa7a0001a, 0xc004dab, 
+0xc004db9, 0x8021, 0xa7a0001a, 0xc004d78, 
 0x24040001, 0x26100001, 0x2e020020, 0x1440fffb, 
-0x0, 0xc004dab, 0x2021, 0xc004dab, 
-0x24040001, 0xc004dab, 0x24040001, 0xc004dab, 
+0x0, 0xc004d78, 0x2021, 0xc004d78, 
+0x24040001, 0xc004d78, 0x24040001, 0xc004d78, 
 0x2021, 0x24100010, 0x32020001, 0x10400002, 
-0x2021, 0x24040001, 0xc004dab, 0x108042, 
-0x1600fffa, 0x32020001, 0x24100010, 0xc004dab, 
+0x2021, 0x24040001, 0xc004d78, 0x108042, 
+0x1600fffa, 0x32020001, 0x24100010, 0xc004d78, 
 0x2021, 0x108042, 0x1600fffc, 0x0, 
-0xc004dec, 0x34108000, 0xc004dec, 0x0, 
-0xc004d8b, 0x0, 0x50400005, 0x108042, 
+0xc004db9, 0x34108000, 0xc004db9, 0x0, 
+0xc004d58, 0x0, 0x50400005, 0x108042, 
 0x97a2001a, 0x501025, 0xa7a2001a, 0x108042, 
-0x1600fff7, 0x0, 0xc004dec, 0x0, 
-0x3c040001, 0x24846c5c, 0x97a60018, 0x97a7001a, 
-0x3c020001, 0x8c426e18, 0x3c030001, 0x8c636f98, 
-0x3c05000d, 0x34a50205, 0xafa20010, 0xc002b17, 
+0x1600fff7, 0x0, 0xc004db9, 0x0, 
+0x3c040001, 0x24846bcc, 0x97a60018, 0x97a7001a, 
+0x3c020001, 0x8c426d98, 0x3c030001, 0x8c636f1c, 
+0x3c05000d, 0x34a50205, 0xafa20010, 0xc002b3b, 
 0xafa30014, 0x8f830054, 0x24020004, 0x3c010001, 
-0xac226e54, 0x3c010001, 0x10000179, 0xac236fb0, 
-0x8f830054, 0x3c020001, 0x8c426fb0, 0x2463ff9c, 
-0x431023, 0x2c420064, 0x14400009, 0x27b10018, 
-0x8f820220, 0x24030005, 0x3c010001, 0xac236e54, 
-0x3c03f700, 0x431025, 0xaf820220, 0x27b10018, 
-0xa7a00018, 0x8021, 0xc004dab, 0x24040001, 
-0x26100001, 0x2e020020, 0x1440fffb, 0x0, 
-0xc004dab, 0x2021, 0xc004dab, 0x24040001, 
-0xc004dab, 0x24040001, 0xc004dab, 0x2021, 
-0x24100010, 0x32020001, 0x10400002, 0x2021, 
-0x24040001, 0xc004dab, 0x108042, 0x1600fffa, 
-0x32020001, 0x24100010, 0xc004dab, 0x2021, 
-0x108042, 0x1600fffc, 0x0, 0xc004dec, 
-0x34108000, 0xc004dec, 0x0, 0xc004d8b, 
-0x0, 0x50400005, 0x108042, 0x96220000, 
-0x501025, 0xa6220000, 0x108042, 0x1600fff7, 
-0x0, 0xc004dec, 0x8021, 0xa7a0001a, 
-0xc004dab, 0x24040001, 0x26100001, 0x2e020020, 
-0x1440fffb, 0x0, 0xc004dab, 0x2021, 
-0xc004dab, 0x24040001, 0xc004dab, 0x24040001, 
-0xc004dab, 0x2021, 0x24100010, 0x32020001, 
-0x10400002, 0x2021, 0x24040001, 0xc004dab, 
-0x108042, 0x1600fffa, 0x32020001, 0x24100010, 
-0x32020001, 0x10400002, 0x2021, 0x24040001, 
-0xc004dab, 0x108042, 0x1600fffa, 0x32020001, 
-0xc004dec, 0x34108000, 0xc004dec, 0x0, 
-0xc004d8b, 0x0, 0x50400005, 0x108042, 
-0x97a2001a, 0x501025, 0xa7a2001a, 0x108042, 
-0x1600fff7, 0x0, 0xc004dec, 0x8021, 
-0xa7a0001a, 0xc004dab, 0x24040001, 0x26100001, 
-0x2e020020, 0x1440fffb, 0x0, 0xc004dab, 
-0x2021, 0xc004dab, 0x24040001, 0xc004dab, 
-0x24040001, 0xc004dab, 0x2021, 0x24100010, 
-0x32020001, 0x10400002, 0x2021, 0x24040001, 
-0xc004dab, 0x108042, 0x1600fffa, 0x32020001, 
-0x24100010, 0x32020001, 0x10400002, 0x2021, 
-0x24040001, 0xc004dab, 0x108042, 0x1600fffa, 
-0x32020001, 0xc004dec, 0x34108000, 0xc004dec, 
-0x0, 0xc004d8b, 0x0, 0x50400005, 
-0x108042, 0x97a2001a, 0x501025, 0xa7a2001a, 
-0x108042, 0x1600fff7, 0x0, 0xc004dec, 
-0x8021, 0xa7a0001c, 0xc004dab, 0x24040001, 
-0x26100001, 0x2e020020, 0x1440fffb, 0x0, 
-0xc004dab, 0x2021, 0xc004dab, 0x24040001, 
-0xc004dab, 0x24040001, 0xc004dab, 0x2021, 
-0x24100010, 0x32020001, 0x10400002, 0x2021, 
-0x24040001, 0xc004dab, 0x108042, 0x1600fffa, 
-0x32020001, 0x24100010, 0x32020004, 0x10400002, 
-0x2021, 0x24040001, 0xc004dab, 0x108042, 
-0x1600fffa, 0x32020004, 0xc004dec, 0x34108000, 
-0xc004dec, 0x0, 0xc004d8b, 0x0, 
-0x50400005, 0x108042, 0x97a2001c, 0x501025, 
-0xa7a2001c, 0x108042, 0x1600fff7, 0x0, 
-0xc004dec, 0x8021, 0xa7a0001c, 0xc004dab, 
-0x24040001, 0x26100001, 0x2e020020, 0x1440fffb, 
-0x0, 0xc004dab, 0x2021, 0xc004dab, 
-0x24040001, 0xc004dab, 0x24040001, 0xc004dab, 
-0x2021, 0x24100010, 0x32020001, 0x10400002, 
-0x2021, 0x24040001, 0xc004dab, 0x108042, 
-0x1600fffa, 0x32020001, 0x24100010, 0x32020004, 
-0x10400002, 0x2021, 0x24040001, 0xc004dab, 
-0x108042, 0x1600fffa, 0x32020004, 0xc004dec, 
-0x34108000, 0xc004dec, 0x0, 0xc004d8b, 
-0x0, 0x50400005, 0x108042, 0x97a2001c, 
-0x501025, 0xa7a2001c, 0x108042, 0x1600fff7, 
-0x0, 0xc004dec, 0x8021, 0xa7a00020, 
-0xc004dab, 0x24040001, 0x26100001, 0x2e020020, 
-0x1440fffb, 0x0, 0xc004dab, 0x2021, 
-0xc004dab, 0x24040001, 0xc004dab, 0x24040001, 
-0xc004dab, 0x2021, 0x24100010, 0x32020001, 
-0x10400002, 0x2021, 0x24040001, 0xc004dab, 
-0x108042, 0x1600fffa, 0x32020001, 0x24100010, 
-0x32020019, 0x10400002, 0x2021, 0x24040001, 
-0xc004dab, 0x108042, 0x1600fffa, 0x32020019, 
-0xc004dec, 0x34108000, 0xc004dec, 0x0, 
-0xc004d8b, 0x0, 0x50400005, 0x108042, 
-0x97a20020, 0x501025, 0xa7a20020, 0x108042, 
-0x1600fff7, 0x0, 0xc004dec, 0x8021, 
-0xa7a00020, 0xc004dab, 0x24040001, 0x26100001, 
-0x2e020020, 0x1440fffb, 0x0, 0xc004dab, 
-0x2021, 0xc004dab, 0x24040001, 0xc004dab, 
-0x24040001, 0xc004dab, 0x2021, 0x24100010, 
-0x32020001, 0x10400002, 0x2021, 0x24040001, 
-0xc004dab, 0x108042, 0x1600fffa, 0x32020001, 
-0x24100010, 0x32020019, 0x10400002, 0x2021, 
-0x24040001, 0xc004dab, 0x108042, 0x1600fffa, 
-0x32020019, 0xc004dec, 0x34108000, 0xc004dec, 
-0x0, 0xc004d8b, 0x0, 0x50400005, 
-0x108042, 0x97a20020, 0x501025, 0xa7a20020, 
-0x108042, 0x1600fff7, 0x0, 0xc004dec, 
-0x0, 0x97a60018, 0x97a7001a, 0x97a2001c, 
-0x3c040001, 0x24846c5c, 0xafa20010, 0x97a20020, 
-0x3c05000d, 0x34a50204, 0xc002b17, 0xafa20014, 
-0x10000007, 0x0, 0x24020006, 0x3c010001, 
-0xac226e54, 0x24020011, 0x3c010001, 0xac226e50, 
-0x8fbf0034, 0x8fb20030, 0x8fb1002c, 0x8fb00028, 
-0x3e00008, 0x27bd0038, 0x8f850044, 0x8f820044, 
-0x3c030001, 0x431025, 0x3c030008, 0xaf820044, 
-0x8f840054, 0x8f820054, 0xa32824, 0x10000002, 
-0x24840001, 0x8f820054, 0x821023, 0x2c420002, 
-0x1440fffc, 0x0, 0x8f820044, 0x3c03fffe, 
-0x3463ffff, 0x431024, 0xaf820044, 0x8f830054, 
-0x8f820054, 0x10000002, 0x24630001, 0x8f820054, 
-0x621023, 0x2c420002, 0x1440fffc, 0x0, 
-0x3e00008, 0xa01021, 0x8f830044, 0x3c02fff0, 
-0x3442ffff, 0x42480, 0x621824, 0x3c020002, 
-0x822025, 0x641825, 0xaf830044, 0x8f820044, 
+0xac226dd4, 0x3c010001, 0x10000017, 0xac236f38, 
+0x8f830054, 0x3c020001, 0x8c426f38, 0x2463ff9c, 
+0x431023, 0x2c420064, 0x1440000f, 0x0, 
+0x8f820220, 0x24030005, 0x3c010001, 0xac236dd4, 
+0x3c03f700, 0x431025, 0x10000007, 0xaf820220, 
+0x24020006, 0x3c010001, 0xac226dd4, 0x24020011, 
+0x3c010001, 0xac226dd0, 0x8fbf0034, 0x8fb20030, 
+0x8fb1002c, 0x8fb00028, 0x3e00008, 0x27bd0038, 
+0x27bdffd8, 0xafb00018, 0x808021, 0xafb1001c, 
+0x8821, 0x32024000, 0x10400013, 0xafbf0020, 
+0x3c020010, 0x2021024, 0x2c420001, 0x21023, 
+0x30434100, 0x3c020001, 0x2021024, 0x14400006, 
+0x34714000, 0x3c020002, 0x2021024, 0x14400002, 
+0x34716000, 0x34714040, 0x2021, 0x2821, 
+0x10000036, 0x2203021, 0x32021000, 0x10400035, 
+0x2021, 0x2821, 0xc004ddb, 0x24060040, 
+0x24040018, 0x2821, 0xc004ddb, 0x24060c00, 
+0x24040017, 0x2821, 0xc004ddb, 0x24060400, 
+0x24040016, 0x2821, 0xc004ddb, 0x24060006, 
+0x24040017, 0x2821, 0xc004ddb, 0x24062500, 
+0x24040016, 0x2821, 0xc004ddb, 0x24060006, 
+0x24040017, 0x2821, 0xc004ddb, 0x24064600, 
+0x24040016, 0x2821, 0xc004ddb, 0x24060006, 
+0x24040017, 0x2821, 0xc004ddb, 0x24066700, 
+0x24040016, 0x2821, 0xc004ddb, 0x24060006, 
+0x2404001f, 0x2821, 0xc004ddb, 0x24060010, 
+0x24040009, 0x2821, 0xc004ddb, 0x24061500, 
+0x24040009, 0x2821, 0x24061d00, 0xc004ddb, 
+0x0, 0x3c040001, 0x24846bf0, 0x3c05000e, 
+0x34a50100, 0x2003021, 0x2203821, 0xafa00010, 
+0xc002b3b, 0xafa00014, 0x8fbf0020, 0x8fb1001c, 
+0x8fb00018, 0x3e00008, 0x27bd0028, 0x8f850044, 
+0x8f820044, 0x3c030001, 0x431025, 0x3c030008, 
+0xaf820044, 0x8f840054, 0x8f820054, 0xa32824, 
+0x10000002, 0x24840001, 0x8f820054, 0x821023, 
+0x2c420002, 0x1440fffc, 0x0, 0x8f820044, 
 0x3c03fffe, 0x3463ffff, 0x431024, 0xaf820044, 
 0x8f830054, 0x8f820054, 0x10000002, 0x24630001, 
 0x8f820054, 0x621023, 0x2c420002, 0x1440fffc, 
-0x0, 0x8f820044, 0x3c030001, 0x431025, 
+0x0, 0x3e00008, 0xa01021, 0x8f830044, 
+0x3c02fff0, 0x3442ffff, 0x42480, 0x621824, 
+0x3c020002, 0x822025, 0x641825, 0xaf830044, 
+0x8f820044, 0x3c03fffe, 0x3463ffff, 0x431024, 
 0xaf820044, 0x8f830054, 0x8f820054, 0x10000002, 
 0x24630001, 0x8f820054, 0x621023, 0x2c420002, 
-0x1440fffc, 0x0, 0x3e00008, 0x0, 
-0x8f820044, 0x2403ff7f, 0x431024, 0xaf820044, 
-0x8f830054, 0x8f820054, 0x10000002, 0x24630001, 
-0x8f820054, 0x621023, 0x2c420002, 0x1440fffc, 
-0x0, 0x8f820044, 0x34420080, 0xaf820044, 
-0x8f830054, 0x8f820054, 0x10000002, 0x24630001, 
-0x8f820054, 0x621023, 0x2c420002, 0x1440fffc, 
-0x0, 0x3e00008, 0x0, 0x8f820044, 
-0x3c03fff0, 0x3463ffff, 0x431024, 0xaf820044, 
-0x8f820044, 0x3c030001, 0x431025, 0xaf820044, 
-0x8f830054, 0x8f820054, 0x10000002, 0x24630001, 
-0x8f820054, 0x621023, 0x2c420002, 0x1440fffc, 
-0x0, 0x8f820044, 0x3c03fffe, 0x3463ffff, 
-0x431024, 0xaf820044, 0x8f830054, 0x8f820054, 
+0x1440fffc, 0x0, 0x8f820044, 0x3c030001, 
+0x431025, 0xaf820044, 0x8f830054, 0x8f820054, 
 0x10000002, 0x24630001, 0x8f820054, 0x621023, 
 0x2c420002, 0x1440fffc, 0x0, 0x3e00008, 
-0x0, 0x27bdffc8, 0xafb30024, 0x809821, 
-0xafbe002c, 0xa0f021, 0xafb20020, 0xc09021, 
-0x33c2ffff, 0xafbf0030, 0xafb50028, 0xafb1001c, 
-0xafb00018, 0x14400034, 0xa7b20010, 0x3271ffff, 
-0x27b20010, 0x8021, 0xc004dab, 0x24040001, 
-0x26100001, 0x2e020020, 0x1440fffb, 0x0, 
-0xc004dab, 0x2021, 0xc004dab, 0x24040001, 
-0xc004dab, 0x2021, 0xc004dab, 0x24040001, 
-0x24100010, 0x32020001, 0x10400002, 0x2021, 
-0x24040001, 0xc004dab, 0x108042, 0x1600fffa, 
-0x32020001, 0x24100010, 0x2301024, 0x10400002, 
-0x2021, 0x24040001, 0xc004dab, 0x108042, 
-0x1600fffa, 0x2301024, 0xc004dab, 0x24040001, 
-0xc004dab, 0x2021, 0x34108000, 0x96420000, 
-0x501024, 0x10400002, 0x2021, 0x24040001, 
-0xc004dab, 0x108042, 0x12000075, 0x0, 
-0x1000fff6, 0x0, 0x3275ffff, 0x27b10010, 
-0xa7a00010, 0x8021, 0xc004dab, 0x24040001, 
-0x26100001, 0x2e020020, 0x1440fffb, 0x0, 
-0xc004dab, 0x2021, 0xc004dab, 0x24040001, 
-0xc004dab, 0x24040001, 0xc004dab, 0x2021, 
-0x24100010, 0x32020001, 0x10400002, 0x2021, 
-0x24040001, 0xc004dab, 0x108042, 0x1600fffa, 
-0x32020001, 0x24100010, 0x2b01024, 0x10400002, 
-0x2021, 0x24040001, 0xc004dab, 0x108042, 
-0x1600fffa, 0x2b01024, 0xc004dec, 0x34108000, 
-0xc004dec, 0x0, 0xc004d8b, 0x0, 
-0x50400005, 0x108042, 0x96220000, 0x501025, 
-0xa6220000, 0x108042, 0x1600fff7, 0x0, 
-0xc004dec, 0x0, 0x33c5ffff, 0x24020001, 
-0x54a20004, 0x24020002, 0x97a20010, 0x10000006, 
-0x521025, 0x14a20006, 0x3271ffff, 0x97a20010, 
-0x121827, 0x431024, 0xa7a20010, 0x3271ffff, 
-0x27b20010, 0x8021, 0xc004dab, 0x24040001, 
-0x26100001, 0x2e020020, 0x1440fffb, 0x0, 
-0xc004dab, 0x2021, 0xc004dab, 0x24040001, 
-0xc004dab, 0x2021, 0xc004dab, 0x24040001, 
-0x24100010, 0x32020001, 0x10400002, 0x2021, 
-0x24040001, 0xc004dab, 0x108042, 0x1600fffa, 
-0x32020001, 0x24100010, 0x2301024, 0x10400002, 
-0x2021, 0x24040001, 0xc004dab, 0x108042, 
-0x1600fffa, 0x2301024, 0xc004dab, 0x24040001, 
-0xc004dab, 0x2021, 0x34108000, 0x96420000, 
-0x501024, 0x10400002, 0x2021, 0x24040001, 
-0xc004dab, 0x108042, 0x1600fff8, 0x0, 
-0xc004dec, 0x0, 0x8fbf0030, 0x8fbe002c, 
-0x8fb50028, 0x8fb30024, 0x8fb20020, 0x8fb1001c, 
-0x8fb00018, 0x3e00008, 0x27bd0038, 0x27bdffe8, 
+0x0, 0x8f820044, 0x2403ff7f, 0x431024, 
+0xaf820044, 0x8f830054, 0x8f820054, 0x10000002, 
+0x24630001, 0x8f820054, 0x621023, 0x2c420002, 
+0x1440fffc, 0x0, 0x8f820044, 0x34420080, 
+0xaf820044, 0x8f830054, 0x8f820054, 0x10000002, 
+0x24630001, 0x8f820054, 0x621023, 0x2c420002, 
+0x1440fffc, 0x0, 0x3e00008, 0x0, 
+0x8f820044, 0x3c03fff0, 0x3463ffff, 0x431024, 
+0xaf820044, 0x8f820044, 0x3c030001, 0x431025, 
+0xaf820044, 0x8f830054, 0x8f820054, 0x10000002, 
+0x24630001, 0x8f820054, 0x621023, 0x2c420002, 
+0x1440fffc, 0x0, 0x8f820044, 0x3c03fffe, 
+0x3463ffff, 0x431024, 0xaf820044, 0x8f830054, 
+0x8f820054, 0x10000002, 0x24630001, 0x8f820054, 
+0x621023, 0x2c420002, 0x1440fffc, 0x0, 
+0x3e00008, 0x0, 0x27bdffc8, 0xafb30024, 
+0x809821, 0xafbe002c, 0xa0f021, 0xafb20020, 
+0xc09021, 0x33c2ffff, 0xafbf0030, 0xafb50028, 
+0xafb1001c, 0xafb00018, 0x14400034, 0xa7b20010, 
+0x3271ffff, 0x27b20010, 0x8021, 0xc004d78, 
+0x24040001, 0x26100001, 0x2e020020, 0x1440fffb, 
+0x0, 0xc004d78, 0x2021, 0xc004d78, 
+0x24040001, 0xc004d78, 0x2021, 0xc004d78, 
+0x24040001, 0x24100010, 0x32020001, 0x10400002, 
+0x2021, 0x24040001, 0xc004d78, 0x108042, 
+0x1600fffa, 0x32020001, 0x24100010, 0x2301024, 
+0x10400002, 0x2021, 0x24040001, 0xc004d78, 
+0x108042, 0x1600fffa, 0x2301024, 0xc004d78, 
+0x24040001, 0xc004d78, 0x2021, 0x34108000, 
+0x96420000, 0x501024, 0x10400002, 0x2021, 
+0x24040001, 0xc004d78, 0x108042, 0x12000075, 
+0x0, 0x1000fff6, 0x0, 0x3275ffff, 
+0x27b10010, 0xa7a00010, 0x8021, 0xc004d78, 
+0x24040001, 0x26100001, 0x2e020020, 0x1440fffb, 
+0x0, 0xc004d78, 0x2021, 0xc004d78, 
+0x24040001, 0xc004d78, 0x24040001, 0xc004d78, 
+0x2021, 0x24100010, 0x32020001, 0x10400002, 
+0x2021, 0x24040001, 0xc004d78, 0x108042, 
+0x1600fffa, 0x32020001, 0x24100010, 0x2b01024, 
+0x10400002, 0x2021, 0x24040001, 0xc004d78, 
+0x108042, 0x1600fffa, 0x2b01024, 0xc004db9, 
+0x34108000, 0xc004db9, 0x0, 0xc004d58, 
+0x0, 0x50400005, 0x108042, 0x96220000, 
+0x501025, 0xa6220000, 0x108042, 0x1600fff7, 
+0x0, 0xc004db9, 0x0, 0x33c5ffff, 
+0x24020001, 0x54a20004, 0x24020002, 0x97a20010, 
+0x10000006, 0x521025, 0x14a20006, 0x3271ffff, 
+0x97a20010, 0x121827, 0x431024, 0xa7a20010, 
+0x3271ffff, 0x27b20010, 0x8021, 0xc004d78, 
+0x24040001, 0x26100001, 0x2e020020, 0x1440fffb, 
+0x0, 0xc004d78, 0x2021, 0xc004d78, 
+0x24040001, 0xc004d78, 0x2021, 0xc004d78, 
+0x24040001, 0x24100010, 0x32020001, 0x10400002, 
+0x2021, 0x24040001, 0xc004d78, 0x108042, 
+0x1600fffa, 0x32020001, 0x24100010, 0x2301024, 
+0x10400002, 0x2021, 0x24040001, 0xc004d78, 
+0x108042, 0x1600fffa, 0x2301024, 0xc004d78, 
+0x24040001, 0xc004d78, 0x2021, 0x34108000, 
+0x96420000, 0x501024, 0x10400002, 0x2021, 
+0x24040001, 0xc004d78, 0x108042, 0x1600fff8, 
+0x0, 0xc004db9, 0x0, 0x8fbf0030, 
+0x8fbe002c, 0x8fb50028, 0x8fb30024, 0x8fb20020, 
+0x8fb1001c, 0x8fb00018, 0x3e00008, 0x27bd0038, 
+0x0, 0x0, 0x0, 0x27bdffe8, 
 0xafbf0010, 0x8ee304b8, 0x24020008, 0x146201e0, 
-0x0, 0x3c020001, 0x8c426f98, 0x14400005, 
-0x0, 0xc003d87, 0x8f840224, 0x100001d8, 
+0x0, 0x3c020001, 0x8c426f1c, 0x14400005, 
+0x0, 0xc003daf, 0x8f840224, 0x100001d8, 
 0x0, 0x8f820220, 0x3c030008, 0x431024, 
 0x10400026, 0x24020001, 0x8f840224, 0x8f820220, 
 0x3c030400, 0x431024, 0x10400006, 0x0, 
-0x3c010002, 0xac209020, 0x3c010002, 0x1000000b, 
-0xac209040, 0x3c030002, 0x24639020, 0x8c620000, 
+0x3c010002, 0xac208fa0, 0x3c010002, 0x1000000b, 
+0xac208fc0, 0x3c030002, 0x24638fa0, 0x8c620000, 
 0x24420001, 0xac620000, 0x2c420002, 0x14400003, 
-0x24020001, 0x3c010002, 0xac229040, 0x3c020002, 
-0x8c429040, 0x10400006, 0x30820040, 0x10400004, 
-0x24020001, 0x3c010002, 0x10000003, 0xac229044, 
-0x3c010002, 0xac209044, 0x3c010002, 0xac24901c, 
-0x3c010002, 0x1000000b, 0xac209050, 0x3c010002, 
-0xac229050, 0x3c010002, 0xac209040, 0x3c010002, 
-0xac209020, 0x3c010002, 0xac209044, 0x3c010002, 
-0xac20901c, 0x3c030002, 0x8c639010, 0x3c020002, 
-0x8c429014, 0x50620004, 0x2463ffff, 0x3c010002, 
-0xac239014, 0x2463ffff, 0x2c62000e, 0x10400194, 
-0x31080, 0x3c010001, 0x220821, 0x8c226c80, 
+0x24020001, 0x3c010002, 0xac228fc0, 0x3c020002, 
+0x8c428fc0, 0x10400006, 0x30820040, 0x10400004, 
+0x24020001, 0x3c010002, 0x10000003, 0xac228fc4, 
+0x3c010002, 0xac208fc4, 0x3c010002, 0xac248f9c, 
+0x3c010002, 0x1000000b, 0xac208fd0, 0x3c010002, 
+0xac228fd0, 0x3c010002, 0xac208fc0, 0x3c010002, 
+0xac208fa0, 0x3c010002, 0xac208fc4, 0x3c010002, 
+0xac208f9c, 0x3c030002, 0x8c638f90, 0x3c020002, 
+0x8c428f94, 0x50620004, 0x2463ffff, 0x3c010002, 
+0xac238f94, 0x2463ffff, 0x2c62000e, 0x10400194, 
+0x31080, 0x3c010001, 0x220821, 0x8c226c00, 
 0x400008, 0x0, 0x24020002, 0x3c010002, 
-0xac209040, 0x3c010002, 0xac209020, 0x3c010002, 
-0xac20901c, 0x3c010002, 0xac209044, 0x3c010002, 
-0xac209038, 0x3c010002, 0xac209030, 0xaf800224, 
-0x3c010002, 0xac229010, 0x3c020002, 0x8c429050, 
-0x1440004f, 0x3c02fdff, 0x3442ffff, 0xc003d87, 
+0xac208fc0, 0x3c010002, 0xac208fa0, 0x3c010002, 
+0xac208f9c, 0x3c010002, 0xac208fc4, 0x3c010002, 
+0xac208fb8, 0x3c010002, 0xac208fb0, 0xaf800224, 
+0x3c010002, 0xac228f90, 0x3c020002, 0x8c428fd0, 
+0x1440004f, 0x3c02fdff, 0x3442ffff, 0xc003daf, 
 0x282a024, 0xaf800204, 0x8f820200, 0x2403fffd, 
-0x431024, 0xaf820200, 0x3c010002, 0xac209060, 
-0x8f830054, 0x3c020002, 0x8c429038, 0x24040001, 
-0x3c010002, 0xac24904c, 0x24420001, 0x3c010002, 
-0xac229038, 0x2c420004, 0x3c010002, 0xac239034, 
-0x14400006, 0x24020003, 0x3c010001, 0xac246e1c, 
-0x3c010002, 0x1000015e, 0xac209038, 0x3c010002, 
-0x1000015b, 0xac229010, 0x8f830054, 0x3c020002, 
-0x8c429034, 0x2463d8f0, 0x431023, 0x2c422710, 
-0x14400003, 0x24020004, 0x3c010002, 0xac229010, 
-0x3c020002, 0x8c429050, 0x14400021, 0x3c02fdff, 
+0x431024, 0xaf820200, 0x3c010002, 0xac208fe0, 
+0x8f830054, 0x3c020002, 0x8c428fb8, 0x24040001, 
+0x3c010002, 0xac248fcc, 0x24420001, 0x3c010002, 
+0xac228fb8, 0x2c420004, 0x3c010002, 0xac238fb4, 
+0x14400006, 0x24020003, 0x3c010001, 0xac246d9c, 
+0x3c010002, 0x1000015e, 0xac208fb8, 0x3c010002, 
+0x1000015b, 0xac228f90, 0x8f830054, 0x3c020002, 
+0x8c428fb4, 0x2463d8f0, 0x431023, 0x2c422710, 
+0x14400003, 0x24020004, 0x3c010002, 0xac228f90, 
+0x3c020002, 0x8c428fd0, 0x14400021, 0x3c02fdff, 
 0x3442ffff, 0x1000014a, 0x282a024, 0x3c040001, 
-0x8c846f9c, 0x3c010002, 0xc0050b4, 0xac209028, 
-0x3c020002, 0x8c42905c, 0xaf820204, 0x3c020002, 
-0x8c429050, 0x14400012, 0x3c03fdff, 0x8f820204, 
+0x8c846f20, 0x3c010002, 0xc005084, 0xac208fa8, 
+0x3c020002, 0x8c428fdc, 0xaf820204, 0x3c020002, 
+0x8c428fd0, 0x14400012, 0x3c03fdff, 0x8f820204, 
 0x3463ffff, 0x30420030, 0x1440012f, 0x283a024, 
-0x3c030002, 0x8c63905c, 0x24020005, 0x3c010002, 
-0xac229010, 0x3c010002, 0x10000131, 0xac239060, 
-0x3c020002, 0x8c429050, 0x10400010, 0x3c02fdff, 
-0x3c020001, 0x8c426ebc, 0x24420001, 0x3c010001, 
-0xac226ebc, 0x2c420002, 0x14400125, 0x24020001, 
-0x3c010001, 0xac226ec4, 0x3c010001, 0xac206ebc, 
-0x3c010001, 0x1000011e, 0xac226e1c, 0x3c030002, 
-0x8c639040, 0x3442ffff, 0x10600119, 0x282a024, 
-0x3c020002, 0x8c42901c, 0x10400115, 0x0, 
-0x3c010002, 0xac229048, 0x24020003, 0x3c010002, 
-0xac229020, 0x100000b8, 0x24020006, 0x3c010002, 
-0xac209028, 0x8f820204, 0x34420040, 0xaf820204, 
-0x3c020002, 0x8c429060, 0x24030007, 0x3c010002, 
-0xac239010, 0x34420040, 0x3c010002, 0xac229060, 
-0x3c020002, 0x8c429040, 0x10400005, 0x0, 
-0x3c020002, 0x8c42901c, 0x104000f0, 0x24020002, 
-0x3c050002, 0x24a59020, 0x8ca20000, 0x2c424e21, 
-0x104000ea, 0x24020002, 0x3c020002, 0x8c429044, 
-0x104000ef, 0x2404ffbf, 0x3c020002, 0x8c42901c, 
-0x3c030002, 0x8c639048, 0x441024, 0x641824, 
+0x3c030002, 0x8c638fdc, 0x24020005, 0x3c010002, 
+0xac228f90, 0x3c010002, 0x10000131, 0xac238fe0, 
+0x3c020002, 0x8c428fd0, 0x10400010, 0x3c02fdff, 
+0x3c020001, 0x8c426e3c, 0x24420001, 0x3c010001, 
+0xac226e3c, 0x2c420002, 0x14400125, 0x24020001, 
+0x3c010001, 0xac226e44, 0x3c010001, 0xac206e3c, 
+0x3c010001, 0x1000011e, 0xac226d9c, 0x3c030002, 
+0x8c638fc0, 0x3442ffff, 0x10600119, 0x282a024, 
+0x3c020002, 0x8c428f9c, 0x10400115, 0x0, 
+0x3c010002, 0xac228fc8, 0x24020003, 0x3c010002, 
+0xac228fa0, 0x100000b8, 0x24020006, 0x3c010002, 
+0xac208fa8, 0x8f820204, 0x34420040, 0xaf820204, 
+0x3c020002, 0x8c428fe0, 0x24030007, 0x3c010002, 
+0xac238f90, 0x34420040, 0x3c010002, 0xac228fe0, 
+0x3c020002, 0x8c428fc0, 0x10400005, 0x0, 
+0x3c020002, 0x8c428f9c, 0x104000f0, 0x24020002, 
+0x3c050002, 0x24a58fa0, 0x8ca20000, 0x2c424e21, 
+0x104000ea, 0x24020002, 0x3c020002, 0x8c428fc4, 
+0x104000ef, 0x2404ffbf, 0x3c020002, 0x8c428f9c, 
+0x3c030002, 0x8c638fc8, 0x441024, 0x641824, 
 0x10430004, 0x24020001, 0x3c010002, 0x100000e4, 
-0xac229010, 0x24020003, 0xaca20000, 0x24020008, 
-0x3c010002, 0xac229010, 0x3c020002, 0x8c42904c, 
-0x1040000c, 0x24020001, 0x3c040002, 0xc0050c1, 
-0x8c84901c, 0x3c020002, 0x8c429068, 0x14400005, 
-0x24020001, 0x3c020002, 0x8c429064, 0x10400006, 
-0x24020001, 0x3c010001, 0xac226e1c, 0x3c010002, 
-0x100000cb, 0xac209038, 0x3c020002, 0x8c429030, 
-0x3c030002, 0x8c63901c, 0x2c420001, 0x210c0, 
-0x30630008, 0x3c010002, 0xac229030, 0x3c010002, 
-0xac23902c, 0x8f830054, 0x24020009, 0x3c010002, 
-0xac229010, 0x3c010002, 0x100000b9, 0xac239034, 
-0x8f830054, 0x3c020002, 0x8c429034, 0x2463d8f0, 
+0xac228f90, 0x24020003, 0xaca20000, 0x24020008, 
+0x3c010002, 0xac228f90, 0x3c020002, 0x8c428fcc, 
+0x1040000c, 0x24020001, 0x3c040002, 0xc005091, 
+0x8c848f9c, 0x3c020002, 0x8c428fe8, 0x14400005, 
+0x24020001, 0x3c020002, 0x8c428fe4, 0x10400006, 
+0x24020001, 0x3c010001, 0xac226d9c, 0x3c010002, 
+0x100000cb, 0xac208fb8, 0x3c020002, 0x8c428fb0, 
+0x3c030002, 0x8c638f9c, 0x2c420001, 0x210c0, 
+0x30630008, 0x3c010002, 0xac228fb0, 0x3c010002, 
+0xac238fac, 0x8f830054, 0x24020009, 0x3c010002, 
+0xac228f90, 0x3c010002, 0x100000b9, 0xac238fb4, 
+0x8f830054, 0x3c020002, 0x8c428fb4, 0x2463d8f0, 
 0x431023, 0x2c422710, 0x1440009f, 0x0, 
-0x3c020002, 0x8c429040, 0x10400005, 0x0, 
-0x3c020002, 0x8c42901c, 0x104000a0, 0x24020002, 
-0x3c030002, 0x24639020, 0x8c620000, 0x2c424e21, 
-0x1040009a, 0x24020002, 0x3c020002, 0x8c42904c, 
-0x1040000e, 0x0, 0x3c020002, 0x8c42901c, 
-0x3c010002, 0xac20904c, 0x30420080, 0x1040002f, 
+0x3c020002, 0x8c428fc0, 0x10400005, 0x0, 
+0x3c020002, 0x8c428f9c, 0x104000a0, 0x24020002, 
+0x3c030002, 0x24638fa0, 0x8c620000, 0x2c424e21, 
+0x1040009a, 0x24020002, 0x3c020002, 0x8c428fcc, 
+0x1040000e, 0x0, 0x3c020002, 0x8c428f9c, 
+0x3c010002, 0xac208fcc, 0x30420080, 0x1040002f, 
 0x2402000c, 0x8f820204, 0x30420080, 0x1440000c, 
 0x24020003, 0x10000029, 0x2402000c, 0x3c020002, 
-0x8c42901c, 0x30420080, 0x14400005, 0x24020003, 
+0x8c428f9c, 0x30420080, 0x14400005, 0x24020003, 
 0x8f820204, 0x30420080, 0x1040001f, 0x24020003, 
-0xac620000, 0x2402000a, 0x3c010002, 0xac229010, 
-0x3c040002, 0x24849058, 0x8c820000, 0x3c030002, 
-0x8c639030, 0x431025, 0xaf820204, 0x8c830000, 
-0x3c040002, 0x8c849030, 0x2402000b, 0x3c010002, 
-0xac229010, 0x641825, 0x3c010002, 0xac239060, 
-0x3c050002, 0x24a59020, 0x8ca20000, 0x2c424e21, 
-0x10400066, 0x24020002, 0x3c020002, 0x8c429050, 
+0xac620000, 0x2402000a, 0x3c010002, 0xac228f90, 
+0x3c040002, 0x24848fd8, 0x8c820000, 0x3c030002, 
+0x8c638fb0, 0x431025, 0xaf820204, 0x8c830000, 
+0x3c040002, 0x8c848fb0, 0x2402000b, 0x3c010002, 
+0xac228f90, 0x641825, 0x3c010002, 0xac238fe0, 
+0x3c050002, 0x24a58fa0, 0x8ca20000, 0x2c424e21, 
+0x10400066, 0x24020002, 0x3c020002, 0x8c428fd0, 
 0x10400005, 0x0, 0x2402000c, 0x3c010002, 
-0x10000067, 0xac229010, 0x3c020002, 0x8c429040, 
-0x10400063, 0x0, 0x3c040002, 0x8c84901c, 
-0x10800055, 0x30820008, 0x3c030002, 0x8c63902c, 
-0x1062005b, 0x24020003, 0x3c010002, 0xac249048, 
+0x10000067, 0xac228f90, 0x3c020002, 0x8c428fc0, 
+0x10400063, 0x0, 0x3c040002, 0x8c848f9c, 
+0x10800055, 0x30820008, 0x3c030002, 0x8c638fac, 
+0x1062005b, 0x24020003, 0x3c010002, 0xac248fc8, 
 0xaca20000, 0x24020006, 0x3c010002, 0x10000054, 
-0xac229010, 0x8f820200, 0x34420002, 0xaf820200, 
-0x8f830054, 0x2402000d, 0x3c010002, 0xac229010, 
-0x3c010002, 0xac239034, 0x8f830054, 0x3c020002, 
-0x8c429034, 0x2463d8f0, 0x431023, 0x2c422710, 
-0x14400031, 0x0, 0x3c020002, 0x8c429050, 
-0x10400020, 0x2402000e, 0x3c030002, 0x8c639064, 
-0x3c010002, 0x14600015, 0xac229010, 0xc003e45, 
-0x0, 0x3c050001, 0x8ca56e18, 0xc0052c7, 
-0x2021, 0x3c030001, 0x8c636e18, 0x24020004, 
-0x14620005, 0x2403fffb, 0x3c020001, 0x8c426e14, 
-0x10000003, 0x2403fff7, 0x3c020001, 0x8c426e14, 
-0x431024, 0x3c010001, 0xac226e14, 0x8f830224, 
-0x3c020200, 0x3c010002, 0xac23906c, 0x10000020, 
-0x282a025, 0x3c020002, 0x8c429040, 0x10400005, 
-0x0, 0x3c020002, 0x8c42901c, 0x1040000f, 
-0x24020002, 0x3c020002, 0x8c429020, 0x2c424e21, 
-0x1040000a, 0x24020002, 0x3c020002, 0x8c429040, 
-0x1040000f, 0x0, 0x3c020002, 0x8c42901c, 
+0xac228f90, 0x8f820200, 0x34420002, 0xaf820200, 
+0x8f830054, 0x2402000d, 0x3c010002, 0xac228f90, 
+0x3c010002, 0xac238fb4, 0x8f830054, 0x3c020002, 
+0x8c428fb4, 0x2463d8f0, 0x431023, 0x2c422710, 
+0x14400031, 0x0, 0x3c020002, 0x8c428fd0, 
+0x10400020, 0x2402000e, 0x3c030002, 0x8c638fe4, 
+0x3c010002, 0x14600015, 0xac228f90, 0xc003e6d, 
+0x0, 0x3c050001, 0x8ca56d98, 0xc00529b, 
+0x2021, 0x3c030001, 0x8c636d98, 0x24020004, 
+0x14620005, 0x2403fffb, 0x3c020001, 0x8c426d94, 
+0x10000003, 0x2403fff7, 0x3c020001, 0x8c426d94, 
+0x431024, 0x3c010001, 0xac226d94, 0x8f830224, 
+0x3c020200, 0x3c010002, 0xac238fec, 0x10000020, 
+0x282a025, 0x3c020002, 0x8c428fc0, 0x10400005, 
+0x0, 0x3c020002, 0x8c428f9c, 0x1040000f, 
+0x24020002, 0x3c020002, 0x8c428fa0, 0x2c424e21, 
+0x1040000a, 0x24020002, 0x3c020002, 0x8c428fc0, 
+0x1040000f, 0x0, 0x3c020002, 0x8c428f9c, 
 0x1440000b, 0x0, 0x24020002, 0x3c010002, 
-0x10000007, 0xac229010, 0x3c020002, 0x8c429040, 
-0x10400003, 0x0, 0xc003d87, 0x0, 
+0x10000007, 0xac228f90, 0x3c020002, 0x8c428fc0, 
+0x10400003, 0x0, 0xc003daf, 0x0, 
 0x8f820220, 0x3c03f700, 0x431025, 0xaf820220, 
 0x8fbf0010, 0x3e00008, 0x27bd0018, 0x3c030002, 
-0x24639068, 0x8c620000, 0x10400005, 0x34422000, 
-0x3c010002, 0xac22905c, 0x10000003, 0xac600000, 
-0x3c010002, 0xac24905c, 0x3e00008, 0x0, 
+0x24638fe8, 0x8c620000, 0x10400005, 0x34422000, 
+0x3c010002, 0xac228fdc, 0x10000003, 0xac600000, 
+0x3c010002, 0xac248fdc, 0x3e00008, 0x0, 
 0x27bdffe0, 0x30820030, 0xafbf0018, 0x3c010002, 
-0xac229064, 0x14400067, 0x3c02ffff, 0x34421f0e, 
+0xac228fe4, 0x14400067, 0x3c02ffff, 0x34421f0e, 
 0x821024, 0x14400061, 0x24020030, 0x30822000, 
 0x1040005d, 0x30838000, 0x31a02, 0x30820001, 
-0x21200, 0x3c040001, 0x8c846f9c, 0x621825, 
-0x331c2, 0x3c030001, 0x24636ec8, 0x30828000, 
+0x21200, 0x3c040001, 0x8c846f20, 0x621825, 
+0x331c2, 0x3c030001, 0x24636e48, 0x30828000, 
 0x21202, 0x30840001, 0x42200, 0x441025, 
 0x239c2, 0x61080, 0x431021, 0x471021, 
 0x90430000, 0x24020001, 0x10620025, 0x0, 
@@ -8775,354 +8758,357 @@
 0x1062002c, 0x3c05000f, 0x10000037, 0x0, 
 0x8f820200, 0x2403feff, 0x431024, 0xaf820200, 
 0x8f820220, 0x3c03fffe, 0x3463ffff, 0x431024, 
-0xaf820220, 0x3c010002, 0xac209084, 0x3c010002, 
-0x10000034, 0xac20908c, 0x8f820200, 0x34420100, 
+0xaf820220, 0x3c010002, 0xac209004, 0x3c010002, 
+0x10000034, 0xac20900c, 0x8f820200, 0x34420100, 
 0xaf820200, 0x8f820220, 0x3c03fffe, 0x3463ffff, 
 0x431024, 0xaf820220, 0x24020100, 0x3c010002, 
-0xac229084, 0x3c010002, 0x10000026, 0xac20908c, 
+0xac229004, 0x3c010002, 0x10000026, 0xac20900c, 
 0x8f820200, 0x2403feff, 0x431024, 0xaf820200, 
 0x8f820220, 0x3c030001, 0x431025, 0xaf820220, 
-0x3c010002, 0xac209084, 0x3c010002, 0x10000019, 
-0xac23908c, 0x8f820200, 0x34420100, 0xaf820200, 
+0x3c010002, 0xac209004, 0x3c010002, 0x10000019, 
+0xac23900c, 0x8f820200, 0x34420100, 0xaf820200, 
 0x8f820220, 0x3c030001, 0x431025, 0xaf820220, 
-0x24020100, 0x3c010002, 0xac229084, 0x3c010002, 
-0x1000000c, 0xac23908c, 0x34a5ffff, 0x3c040001, 
-0x24846cb8, 0xafa30010, 0xc002b17, 0xafa00014, 
+0x24020100, 0x3c010002, 0xac229004, 0x3c010002, 
+0x1000000c, 0xac23900c, 0x34a5ffff, 0x3c040001, 
+0x24846c38, 0xafa30010, 0xc002b3b, 0xafa00014, 
 0x10000004, 0x0, 0x24020030, 0x3c010002, 
-0xac229068, 0x8fbf0018, 0x3e00008, 0x27bd0020, 
+0xac228fe8, 0x8fbf0018, 0x3e00008, 0x27bd0020, 
 0x0, 0x0, 0x0, 0x27bdffc8, 
 0xafb20028, 0x809021, 0xafb3002c, 0xa09821, 
-0xafb00020, 0xc08021, 0x3c040001, 0x24846cd0, 
-0x3c050009, 0x3c020001, 0x8c426e18, 0x34a59001, 
+0xafb00020, 0xc08021, 0x3c040001, 0x24846c50, 
+0x3c050009, 0x3c020001, 0x8c426d98, 0x34a59001, 
 0x2403021, 0x2603821, 0xafbf0030, 0xafb10024, 
-0xa7a0001a, 0xafb00014, 0xc002b17, 0xafa20010, 
-0x24020002, 0x1262007f, 0x2e620003, 0x10400005, 
-0x24020001, 0x1262000a, 0x0, 0x1000016f, 
-0x0, 0x24020004, 0x126200f4, 0x24020008, 
-0x126200f3, 0x3c02ffec, 0x10000168, 0x0, 
-0x3c020001, 0x8c426e14, 0x30420002, 0x14400004, 
+0xa7a0001a, 0xafb00014, 0xc002b3b, 0xafa20010, 
+0x24020002, 0x12620083, 0x2e620003, 0x10400005, 
+0x24020001, 0x1262000a, 0x0, 0x10000173, 
+0x0, 0x24020004, 0x126200f8, 0x24020008, 
+0x126200f7, 0x3c02ffec, 0x1000016c, 0x0, 
+0x3c020001, 0x8c426d94, 0x30420002, 0x14400004, 
 0x128940, 0x3c02fffb, 0x3442ffff, 0x2028024, 
-0x3c010002, 0x310821, 0xac30907c, 0x3c024000, 
-0x2021024, 0x1040004a, 0x1023c2, 0x30840030, 
-0x101382, 0x3042001c, 0x3c030001, 0x24636e58, 
+0x3c010002, 0x310821, 0xac308ffc, 0x3c024000, 
+0x2021024, 0x1040004e, 0x1023c2, 0x30840030, 
+0x101382, 0x3042001c, 0x3c030001, 0x24636dd8, 
 0x431021, 0x823821, 0x3c020020, 0x2021024, 
 0x10400006, 0x24020100, 0x3c010002, 0x310821, 
-0xac229080, 0x10000005, 0x3c020080, 0x3c010002, 
-0x310821, 0xac209080, 0x3c020080, 0x2021024, 
+0xac229000, 0x10000005, 0x3c020080, 0x3c010002, 
+0x310821, 0xac209000, 0x3c020080, 0x2021024, 
 0x10400006, 0x121940, 0x3c020001, 0x3c010002, 
-0x230821, 0x10000005, 0xac229088, 0x121140, 
-0x3c010002, 0x220821, 0xac209088, 0x94e30000, 
-0x32024000, 0x10400003, 0xa7a30018, 0x34624000, 
+0x230821, 0x10000005, 0xac229008, 0x121140, 
+0x3c010002, 0x220821, 0xac209008, 0x94e40000, 
+0x3c030001, 0x8c636f40, 0x24020005, 0x10620010, 
+0xa7a40018, 0x32024000, 0x10400002, 0x34824000, 
 0xa7a20018, 0x24040001, 0x94e20002, 0x24050004, 
-0x24e60002, 0x34420001, 0xc00450e, 0xa4e20002, 
-0x24040001, 0x2821, 0xc00450e, 0x27a60018, 
-0x3c020001, 0x8c426e18, 0x24110001, 0x3c010001, 
-0xac316e24, 0x14530004, 0x32028000, 0xc003d87, 
+0x24e60002, 0x34420001, 0xc0045be, 0xa4e20002, 
+0x24040001, 0x2821, 0xc0045be, 0x27a60018, 
+0x3c020001, 0x8c426d98, 0x24110001, 0x3c010001, 
+0xac316da4, 0x14530004, 0x32028000, 0xc003daf, 
 0x0, 0x32028000, 0x1040011c, 0x0, 
-0xc003d87, 0x0, 0x3c030001, 0x8c636fb8, 
+0xc003daf, 0x0, 0x3c030001, 0x8c636f40, 
 0x24020005, 0x10620115, 0x24020002, 0x3c010001, 
-0xac316e1c, 0x3c010001, 0x10000110, 0xac226e18, 
-0x24040001, 0x24050004, 0x27b0001a, 0xc00450e, 
-0x2003021, 0x24040001, 0x2821, 0xc00450e, 
-0x2003021, 0x3c020002, 0x511021, 0x8c429074, 
-0x3c040001, 0x8c846e18, 0x3c03bfff, 0x3463ffff, 
-0x3c010001, 0xac336e24, 0x431024, 0x3c010002, 
-0x310821, 0x109300f7, 0xac229074, 0x100000f7, 
+0xac316d9c, 0x3c010001, 0x10000110, 0xac226d98, 
+0x24040001, 0x24050004, 0x27b0001a, 0xc0045be, 
+0x2003021, 0x24040001, 0x2821, 0xc0045be, 
+0x2003021, 0x3c020002, 0x511021, 0x8c428ff4, 
+0x3c040001, 0x8c846d98, 0x3c03bfff, 0x3463ffff, 
+0x3c010001, 0xac336da4, 0x431024, 0x3c010002, 
+0x310821, 0x109300f7, 0xac228ff4, 0x100000f7, 
 0x0, 0x3c022000, 0x2021024, 0x10400005, 
-0x24020001, 0x3c010001, 0xac226f98, 0x10000004, 
-0x128940, 0x3c010001, 0xac206f98, 0x128940, 
-0x3c010002, 0x310821, 0xac309078, 0x3c024000, 
+0x24020001, 0x3c010001, 0xac226f1c, 0x10000004, 
+0x128940, 0x3c010001, 0xac206f1c, 0x128940, 
+0x3c010002, 0x310821, 0xac308ff8, 0x3c024000, 
 0x2021024, 0x14400014, 0x0, 0x3c020001, 
-0x8c426f98, 0x10400006, 0x24040004, 0x24050001, 
-0xc004e0e, 0x24062000, 0x24020001, 0xaee204b8, 
-0x3c020002, 0x511021, 0x8c429070, 0x3c03bfff, 
+0x8c426f1c, 0x10400006, 0x24040004, 0x24050001, 
+0xc004ddb, 0x24062000, 0x24020001, 0xaee204b8, 
+0x3c020002, 0x511021, 0x8c428ff0, 0x3c03bfff, 
 0x3463ffff, 0x431024, 0x3c010002, 0x310821, 
-0x100000d0, 0xac229070, 0x3c020001, 0x8c426f98, 
+0x100000d0, 0xac228ff0, 0x3c020001, 0x8c426f1c, 
 0x10400028, 0x3c0300a0, 0x2031024, 0x5443000d, 
-0x3c020020, 0x3c020001, 0x8c426f9c, 0x24030100, 
-0x3c010002, 0x310821, 0xac239084, 0x3c030001, 
-0x3c010002, 0x310821, 0xac23908c, 0x10000015, 
+0x3c020020, 0x3c020001, 0x8c426f20, 0x24030100, 
+0x3c010002, 0x310821, 0xac239004, 0x3c030001, 
+0x3c010002, 0x310821, 0xac23900c, 0x10000015, 
 0x34420400, 0x2021024, 0x10400008, 0x24030100, 
-0x3c020001, 0x8c426f9c, 0x3c010002, 0x310821, 
-0xac239084, 0x1000000b, 0x34420800, 0x3c020080, 
+0x3c020001, 0x8c426f20, 0x3c010002, 0x310821, 
+0xac239004, 0x1000000b, 0x34420800, 0x3c020080, 
 0x2021024, 0x1040002e, 0x3c030001, 0x3c020001, 
-0x8c426f9c, 0x3c010002, 0x310821, 0xac23908c, 
-0x34420c00, 0x3c010001, 0xac226f9c, 0x10000025, 
+0x8c426f20, 0x3c010002, 0x310821, 0xac23900c, 
+0x34420c00, 0x3c010001, 0xac226f20, 0x10000025, 
 0x24040001, 0x3c020020, 0x2021024, 0x10400006, 
-0x24020100, 0x3c010002, 0x310821, 0xac229084, 
+0x24020100, 0x3c010002, 0x310821, 0xac229004, 
 0x10000005, 0x3c020080, 0x3c010002, 0x310821, 
-0xac209084, 0x3c020080, 0x2021024, 0x10400007, 
+0xac209004, 0x3c020080, 0x2021024, 0x10400007, 
 0x121940, 0x3c020001, 0x3c010002, 0x230821, 
-0xac22908c, 0x10000006, 0x24040001, 0x121140, 
-0x3c010002, 0x220821, 0xac20908c, 0x24040001, 
-0x2821, 0x27b0001e, 0xc0044cc, 0x2003021, 
-0x24040001, 0x2821, 0xc0044cc, 0x2003021, 
-0x24040001, 0x24050001, 0x27b0001c, 0xc0044cc, 
-0x2003021, 0x24040001, 0x24050001, 0xc0044cc, 
+0xac22900c, 0x10000006, 0x24040001, 0x121140, 
+0x3c010002, 0x220821, 0xac20900c, 0x24040001, 
+0x2821, 0x27b0001e, 0xc00457c, 0x2003021, 
+0x24040001, 0x2821, 0xc00457c, 0x2003021, 
+0x24040001, 0x24050001, 0x27b0001c, 0xc00457c, 
+0x2003021, 0x24040001, 0x24050001, 0xc00457c, 
 0x2003021, 0x10000077, 0x0, 0x3c02ffec, 
 0x3442ffff, 0x2028024, 0x3c020008, 0x2028025, 
-0x121140, 0x3c010002, 0x220821, 0xac309078, 
+0x121140, 0x3c010002, 0x220821, 0xac308ff8, 
 0x3c022000, 0x2021024, 0x10400009, 0x0, 
-0x3c020001, 0x8c426ec4, 0x14400005, 0x24020001, 
-0x3c010001, 0xac226f98, 0x10000004, 0x3c024000, 
-0x3c010001, 0xac206f98, 0x3c024000, 0x2021024, 
-0x1440001d, 0x24020e01, 0x3c030001, 0x8c636f98, 
-0xaf820238, 0x3c010001, 0xac206e30, 0x10600005, 
-0x24022020, 0x3c010001, 0xac226f9c, 0x24020001, 
+0x3c020001, 0x8c426e44, 0x14400005, 0x24020001, 
+0x3c010001, 0xac226f1c, 0x10000004, 0x3c024000, 
+0x3c010001, 0xac206f1c, 0x3c024000, 0x2021024, 
+0x1440001d, 0x24020e01, 0x3c030001, 0x8c636f1c, 
+0xaf820238, 0x3c010001, 0xac206db0, 0x10600005, 
+0x24022020, 0x3c010001, 0xac226f20, 0x24020001, 
 0xaee204b8, 0x3c04bfff, 0x121940, 0x3c020002, 
-0x431021, 0x8c429070, 0x3c050001, 0x8ca56e18, 
+0x431021, 0x8c428ff0, 0x3c050001, 0x8ca56d98, 
 0x3484ffff, 0x441024, 0x3c010002, 0x230821, 
-0xac229070, 0x24020001, 0x10a20044, 0x0, 
-0x10000040, 0x0, 0x3c020001, 0x8c426f98, 
-0x1040001c, 0x24022000, 0x3c010001, 0xac226f9c, 
+0xac228ff0, 0x24020001, 0x10a20044, 0x0, 
+0x10000040, 0x0, 0x3c020001, 0x8c426f1c, 
+0x1040001c, 0x24022000, 0x3c010001, 0xac226f20, 
 0x3c0300a0, 0x2031024, 0x14430005, 0x121140, 
-0x3402a000, 0x3c010001, 0x1000002d, 0xac226f9c, 
-0x3c030002, 0x621821, 0x8c639078, 0x3c020020, 
+0x3402a000, 0x3c010001, 0x1000002d, 0xac226f20, 
+0x3c030002, 0x621821, 0x8c638ff8, 0x3c020020, 
 0x621024, 0x10400004, 0x24022001, 0x3c010001, 
-0x10000023, 0xac226f9c, 0x3c020080, 0x621024, 
+0x10000023, 0xac226f20, 0x3c020080, 0x621024, 
 0x1040001f, 0x3402a001, 0x3c010001, 0x1000001c, 
-0xac226f9c, 0x3c020020, 0x2021024, 0x10400007, 
+0xac226f20, 0x3c020020, 0x2021024, 0x10400007, 
 0x121940, 0x24020100, 0x3c010002, 0x230821, 
-0xac229084, 0x10000006, 0x3c020080, 0x121140, 
-0x3c010002, 0x220821, 0xac209084, 0x3c020080, 
+0xac229004, 0x10000006, 0x3c020080, 0x121140, 
+0x3c010002, 0x220821, 0xac209004, 0x3c020080, 
 0x2021024, 0x10400006, 0x121940, 0x3c020001, 
-0x3c010002, 0x230821, 0x10000005, 0xac22908c, 
-0x121140, 0x3c010002, 0x220821, 0xac20908c, 
-0x3c030001, 0x8c636e18, 0x24020001, 0x10620003, 
-0x0, 0xc003d87, 0x0, 0x8fbf0030, 
+0x3c010002, 0x230821, 0x10000005, 0xac22900c, 
+0x121140, 0x3c010002, 0x220821, 0xac20900c, 
+0x3c030001, 0x8c636d98, 0x24020001, 0x10620003, 
+0x0, 0xc003daf, 0x0, 0x8fbf0030, 
 0x8fb3002c, 0x8fb20028, 0x8fb10024, 0x8fb00020, 
-0x3e00008, 0x27bd0038, 0x27bdffb8, 0xafbe003c, 
-0x80f021, 0xafb30034, 0x9821, 0xafb20030, 
-0x9021, 0xafb1002c, 0x8821, 0x24020002, 
-0xafbf0040, 0xafb50038, 0xafb00028, 0xa7a00020, 
-0xa7a00018, 0xa7a0001a, 0xa7a0001c, 0xa7a0001e, 
-0x10a20142, 0xa7a00022, 0x2ca20003, 0x10400005, 
-0x24020001, 0x10a2000a, 0x1ea940, 0x10000253, 
-0x2201021, 0x24020004, 0x10a20203, 0x24020008, 
-0x10a20202, 0x1e2940, 0x1000024c, 0x2201021, 
-0x3c030002, 0x751821, 0x8c63907c, 0x3c024000, 
-0x621024, 0x14400009, 0x24040001, 0x3c027fff, 
-0x3442ffff, 0x628824, 0x3c010002, 0x350821, 
-0xac319074, 0x1000023d, 0x2201021, 0x2821, 
-0xc0044cc, 0x27a60018, 0x24040001, 0x2821, 
-0xc0044cc, 0x27a60018, 0x24040001, 0x24050001, 
-0x27b0001a, 0xc0044cc, 0x2003021, 0x24040001, 
-0x24050001, 0xc0044cc, 0x2003021, 0x24040001, 
-0x24050004, 0x27b0001c, 0xc0044cc, 0x2003021, 
-0x24040001, 0x24050004, 0xc0044cc, 0x2003021, 
-0x24040001, 0x24050005, 0x27b0001e, 0xc0044cc, 
-0x2003021, 0x24040001, 0x24050005, 0xc0044cc, 
-0x2003021, 0x24040001, 0x24050009, 0xc0044cc, 
-0x2003021, 0x24040001, 0x24050009, 0xc0044cc, 
-0x2003021, 0x24040001, 0x24050001, 0xc0044cc, 
-0x27a60018, 0x24040001, 0x24050001, 0xc0044cc, 
-0x27a60018, 0x97a20018, 0x30420004, 0x104000ba, 
-0x3c114000, 0x3c020001, 0x8c426fb8, 0x2443ffff, 
-0x2c620006, 0x104000ba, 0x31080, 0x3c010001, 
-0x220821, 0x8c226ce8, 0x400008, 0x0, 
-0x24040001, 0x24050011, 0x27b00020, 0xc0044cc, 
-0x2003021, 0x24040001, 0x24050011, 0xc0044cc, 
-0x2003021, 0x97a30020, 0x30624000, 0x10400002, 
-0x3c120010, 0x3c120008, 0x3c130001, 0x30628000, 
-0x54400098, 0x3c130002, 0x10000097, 0x3c028000, 
-0x24040001, 0x24050014, 0x27b00020, 0xc0044cc, 
-0x2003021, 0x24040001, 0x24050014, 0xc0044cc, 
-0x2003021, 0x97a30020, 0x30621000, 0x10400002, 
-0x3c120010, 0x3c120008, 0x3c130001, 0x1000ffec, 
-0x30620800, 0x24040001, 0x24050019, 0x27b00022, 
-0xc0044cc, 0x2003021, 0x24040001, 0x24050019, 
-0xc0044cc, 0x2003021, 0x97a20022, 0x30430700, 
-0x24020400, 0x10620027, 0x28620401, 0x1040000e, 
-0x24020200, 0x1062001f, 0x28620201, 0x10400005, 
-0x24020100, 0x5062001e, 0x3c130001, 0x1000001e, 
-0x24040001, 0x24020300, 0x50620019, 0x3c130002, 
-0x10000019, 0x24040001, 0x24020600, 0x1062000d, 
-0x28620601, 0x10400005, 0x24020500, 0x5062000b, 
-0x3c130002, 0x10000010, 0x24040001, 0x24020700, 
-0x1462000d, 0x24040001, 0x3c130004, 0x1000000a, 
-0x3c120008, 0x10000006, 0x3c130004, 0x10000005, 
-0x3c120008, 0x3c130001, 0x10000002, 0x3c120008, 
-0x3c120010, 0x24040001, 0x24050010, 0x27b0001c, 
-0xc0044cc, 0x2003021, 0x24040001, 0x24050010, 
-0xc0044cc, 0x2003021, 0x3c020004, 0x16620010, 
-0x3c020001, 0x8f840054, 0x24030001, 0x24020002, 
-0x3c010001, 0xac236e1c, 0x3c010001, 0xac226e18, 
-0x3c010001, 0xac236e24, 0x3c010001, 0xac236ea4, 
-0x3c010001, 0xac246fa8, 0x10000041, 0x2538825, 
-0x16620035, 0x3c028000, 0x3c020001, 0x8c426ea0, 
-0x1440001e, 0x24040018, 0x2021, 0x2821, 
-0xc004e0e, 0x34068000, 0x8f830054, 0x8f820054, 
-0x2538825, 0x10000002, 0x24630032, 0x8f820054, 
-0x621023, 0x2c420033, 0x1440fffc, 0x0, 
-0x8f830054, 0x24020001, 0x3c010001, 0xac226ea0, 
-0x3c010001, 0xac226e1c, 0x3c010001, 0xac226e18, 
-0x3c010001, 0xac226e24, 0x3c010001, 0xac226ea4, 
-0x3c010001, 0x1000001e, 0xac236fa8, 0x2821, 
-0xc004e0e, 0x24060404, 0x2021, 0x2405001e, 
-0x27a60018, 0x24020002, 0xc00450e, 0xa7a20018, 
-0x2021, 0x2821, 0x27a60018, 0xc00450e, 
-0xa7a00018, 0x24040018, 0x24050002, 0xc004e0e, 
-0x24060004, 0x3c028000, 0x2221025, 0x2721825, 
-0x10000007, 0x438825, 0x3c110002, 0x2358821, 
-0x8e31907c, 0x3c027fff, 0x3442ffff, 0x2228824, 
-0x3c020001, 0x8c426e28, 0x1040001c, 0x0, 
-0x3c020001, 0x8c426f98, 0x10400002, 0x3c022000, 
-0x2228825, 0x1e1140, 0x3c010002, 0x220821, 
-0x8c229080, 0x10400003, 0x3c020020, 0x10000004, 
+0x3e00008, 0x27bd0038, 0x27bdffb0, 0xafb3003c, 
+0x9821, 0xafb50040, 0xa821, 0xafb10034, 
+0x8821, 0x24020002, 0xafbf0048, 0xafbe0044, 
+0xafb20038, 0xafb00030, 0xafa4002c, 0xa7a0001a, 
+0xa7a00018, 0xa7a00020, 0xa7a0001e, 0xa7a00022, 
+0x10a20130, 0xa7a0001c, 0x2ca20003, 0x10400005, 
+0x24020001, 0x10a2000a, 0x3c024000, 0x1000025d, 
+0x2201021, 0x24020004, 0x10a2020a, 0x24020008, 
+0x10a20208, 0x2201021, 0x10000256, 0x0, 
+0x8fa8002c, 0x88140, 0x3c030002, 0x701821, 
+0x8c638ffc, 0x621024, 0x14400009, 0x24040001, 
+0x3c027fff, 0x3442ffff, 0x628824, 0x3c010002, 
+0x300821, 0xac318ff4, 0x10000246, 0x2201021, 
+0x24050001, 0xc00457c, 0x27a60018, 0x24040001, 
+0x24050001, 0xc00457c, 0x27a60018, 0x97a20018, 
+0x30420004, 0x104000d9, 0x3c114000, 0x3c020001, 
+0x8c426f40, 0x2443ffff, 0x2c620006, 0x104000d9, 
+0x31080, 0x3c010001, 0x220821, 0x8c226c68, 
+0x400008, 0x0, 0x24040001, 0x24050011, 
+0x27b0001a, 0xc00457c, 0x2003021, 0x24040001, 
+0x24050011, 0xc00457c, 0x2003021, 0x97a3001a, 
+0x30624000, 0x10400002, 0x3c150010, 0x3c150008, 
+0x30628000, 0x104000aa, 0x3c130001, 0x100000a8, 
+0x3c130002, 0x24040001, 0x24050014, 0x27b0001a, 
+0xc00457c, 0x2003021, 0x24040001, 0x24050014, 
+0xc00457c, 0x2003021, 0x97a3001a, 0x30621000, 
+0x10400002, 0x3c150010, 0x3c150008, 0x30620800, 
+0x10400097, 0x3c130001, 0x10000095, 0x3c130002, 
+0x24040001, 0x24050019, 0x27b0001c, 0xc00457c, 
+0x2003021, 0x24040001, 0x24050019, 0xc00457c, 
+0x2003021, 0x97a2001c, 0x30430700, 0x24020400, 
+0x10620027, 0x28620401, 0x1040000e, 0x24020200, 
+0x1062001f, 0x28620201, 0x10400005, 0x24020100, 
+0x5062001e, 0x3c130001, 0x1000001e, 0x24040001, 
+0x24020300, 0x50620019, 0x3c130002, 0x10000019, 
+0x24040001, 0x24020600, 0x1062000d, 0x28620601, 
+0x10400005, 0x24020500, 0x5062000b, 0x3c130002, 
+0x10000010, 0x24040001, 0x24020700, 0x1462000d, 
+0x24040001, 0x3c130004, 0x1000000a, 0x3c150008, 
+0x10000006, 0x3c130004, 0x10000005, 0x3c150008, 
+0x3c130001, 0x10000002, 0x3c150008, 0x3c150010, 
+0x24040001, 0x24050018, 0x27b0001e, 0xc00457c, 
+0x2003021, 0x24040001, 0x24050018, 0xc00457c, 
+0x2003021, 0x8fa8002c, 0x97a7001e, 0x81140, 
+0x3c060002, 0xc23021, 0x8cc68ff4, 0x97a20022, 
+0x3c100001, 0x26106c5c, 0x2002021, 0xafa20010, 
+0x97a2001c, 0x3c05000c, 0x34a50303, 0xc002b3b, 
+0xafa20014, 0x3c020004, 0x16620010, 0x3c020001, 
+0x8f840054, 0x24030001, 0x24020002, 0x3c010001, 
+0xac236d9c, 0x3c010001, 0xac226d98, 0x3c010001, 
+0xac236da4, 0x3c010001, 0xac236e24, 0x3c010001, 
+0xac246f30, 0x1000004f, 0x2b38825, 0x16620039, 
+0x3c028000, 0x3c020001, 0x8c426e20, 0x1440001e, 
+0x24040018, 0x2021, 0x2821, 0xc004ddb, 
+0x34068000, 0x8f830054, 0x8f820054, 0x2b38825, 
+0x10000002, 0x24630032, 0x8f820054, 0x621023, 
+0x2c420033, 0x1440fffc, 0x0, 0x8f830054, 
+0x24020001, 0x3c010001, 0xac226e20, 0x3c010001, 
+0xac226d9c, 0x3c010001, 0xac226d98, 0x3c010001, 
+0xac226da4, 0x3c010001, 0xac226e24, 0x3c010001, 
+0x1000002c, 0xac236f30, 0x2821, 0xc004ddb, 
+0x24060404, 0x2021, 0x2405001e, 0x27a60018, 
+0x24020002, 0xc0045be, 0xa7a20018, 0x2021, 
+0x2821, 0x27a60018, 0xc0045be, 0xa7a00018, 
+0x24040018, 0x24050002, 0xc004ddb, 0x24060004, 
+0x3c028000, 0x2221025, 0x2b31825, 0x10000015, 
+0x438825, 0x2221025, 0x2751825, 0x438825, 
+0x2002021, 0x97a6001c, 0x3c070001, 0x8ce76d98, 
+0x3c05000c, 0x34a50326, 0xafb30010, 0xc002b3b, 
+0xafb10014, 0x10000007, 0x0, 0x3c110002, 
+0x2308821, 0x8e318ffc, 0x3c027fff, 0x3442ffff, 
+0x2228824, 0x3c020001, 0x8c426da8, 0x1040001e, 
+0x0, 0x3c020001, 0x8c426f1c, 0x10400002, 
+0x3c022000, 0x2228825, 0x8fa8002c, 0x81140, 
+0x3c010002, 0x220821, 0x8c229000, 0x10400003, 
+0x3c020020, 0x10000005, 0x2228825, 0x3c02ffdf, 
+0x3442ffff, 0x2228824, 0x8fa8002c, 0x81140, 
+0x3c010002, 0x220821, 0x8c229008, 0x10400003, 
+0x3c020080, 0x10000004, 0x2228825, 0x3c02ff7f, 
+0x3442ffff, 0x2228824, 0x8fa8002c, 0x81140, 
+0x3c010002, 0x220821, 0xac318ff4, 0x10000135, 
+0x2201021, 0x8fa8002c, 0x8f140, 0x3c030002, 
+0x7e1821, 0x8c638ff8, 0x3c024000, 0x621024, 
+0x14400009, 0x24040001, 0x3c027fff, 0x3442ffff, 
+0x628824, 0x3c010002, 0x3e0821, 0xac318ff0, 
+0x10000124, 0x2201021, 0x2821, 0xc00457c, 
+0x27a60018, 0x24040001, 0x2821, 0xc00457c, 
+0x27a60018, 0x24040001, 0x24050001, 0x27b20020, 
+0xc00457c, 0x2403021, 0x24040001, 0x24050001, 
+0xc00457c, 0x2403021, 0x24040001, 0x24050004, 
+0x27b1001e, 0xc00457c, 0x2203021, 0x24040001, 
+0x24050004, 0xc00457c, 0x2203021, 0x24040001, 
+0x24050005, 0x27b00022, 0xc00457c, 0x2003021, 
+0x24040001, 0x24050005, 0xc00457c, 0x2003021, 
+0x24040001, 0x24050010, 0xc00457c, 0x27a60018, 
+0x24040001, 0x24050010, 0xc00457c, 0x27a60018, 
+0x24040001, 0x2405000a, 0xc00457c, 0x2403021, 
+0x24040001, 0x2405000a, 0xc00457c, 0x2403021, 
+0x24040001, 0x24050018, 0xc00457c, 0x2203021, 
+0x24040001, 0x24050018, 0xc00457c, 0x2203021, 
+0x24040001, 0x24050001, 0xc00457c, 0x27a60018, 
+0x24040001, 0x24050001, 0xc00457c, 0x27a60018, 
+0x97a20018, 0x30420004, 0x10400066, 0x3c114000, 
+0x3c030001, 0x8c636f34, 0x24020005, 0x14620067, 
+0x24040001, 0x24050019, 0x27b0001c, 0xc00457c, 
+0x2003021, 0x24040001, 0x24050019, 0xc00457c, 
+0x2003021, 0x97a2001c, 0x30430700, 0x24020400, 
+0x10620027, 0x28620401, 0x1040000e, 0x24020200, 
+0x1062001f, 0x28620201, 0x10400005, 0x24020100, 
+0x5062001e, 0x3c130001, 0x1000001e, 0x3c020004, 
+0x24020300, 0x50620019, 0x3c130002, 0x10000019, 
+0x3c020004, 0x24020600, 0x1062000d, 0x28620601, 
+0x10400005, 0x24020500, 0x5062000b, 0x3c130002, 
+0x10000010, 0x3c020004, 0x24020700, 0x1462000d, 
+0x3c020004, 0x3c130004, 0x1000000a, 0x3c150008, 
+0x10000006, 0x3c130004, 0x10000005, 0x3c150008, 
+0x3c130001, 0x10000002, 0x3c150008, 0x3c150010, 
+0x3c020004, 0x12620017, 0x3c028000, 0x8f820054, 
+0x24100001, 0x3c010001, 0xac306d9c, 0x3c010001, 
+0xac306d98, 0x3c010001, 0xac306da4, 0x3c010001, 
+0xac306e24, 0x3c010001, 0xac226f30, 0x3c020001, 
+0x16620022, 0x2758825, 0x2021, 0x2821, 
+0xc004ddb, 0x34068000, 0x3c010001, 0x1000001b, 
+0xac306e20, 0x2221025, 0x2b31825, 0x438825, 
+0x97a6001c, 0x3c020001, 0x8c426f1c, 0x3c070001, 
+0x8ce76d98, 0x3c040001, 0x24846c5c, 0xafa20010, 
+0x97a2001e, 0x3c05000c, 0x34a50323, 0x3c010001, 
+0xac206e20, 0xc002b3b, 0xafa20014, 0x10000007, 
+0x0, 0x3c110002, 0x23e8821, 0x8e318ff0, 
+0x3c027fff, 0x3442ffff, 0x2228824, 0x3c020001, 
+0x8c426da8, 0x10400069, 0x0, 0x3c020001, 
+0x8c426f1c, 0x10400002, 0x3c022000, 0x2228825, 
+0x8fa8002c, 0x81140, 0x3c010002, 0x220821, 
+0x8c229004, 0x10400003, 0x3c020020, 0x10000005, 
 0x2228825, 0x3c02ffdf, 0x3442ffff, 0x2228824, 
-0x1e1140, 0x3c010002, 0x220821, 0x8c229088, 
-0x10400003, 0x3c020080, 0x10000004, 0x2228825, 
-0x3c02ff7f, 0x3442ffff, 0x2228824, 0x3c040001, 
-0x24846cdc, 0x3c05000c, 0x97a60022, 0x3c070001, 
-0x8ce76e18, 0x34a50326, 0x1e1140, 0x3c010002, 
-0x220821, 0xac319074, 0xafb30010, 0xc002b17, 
-0xafb10014, 0x10000119, 0x2201021, 0x1ea940, 
-0x3c030002, 0x751821, 0x8c639078, 0x3c024000, 
-0x621024, 0x14400009, 0x24040001, 0x3c027fff, 
-0x3442ffff, 0x628824, 0x3c010002, 0x350821, 
-0xac319070, 0x10000109, 0x2201021, 0x2821, 
-0xc0044cc, 0x27a60018, 0x24040001, 0x2821, 
-0xc0044cc, 0x27a60018, 0x24040001, 0x24050001, 
-0x27b1001a, 0xc0044cc, 0x2203021, 0x24040001, 
-0x24050001, 0xc0044cc, 0x2203021, 0x24040001, 
-0x24050004, 0x27b0001c, 0xc0044cc, 0x2003021, 
-0x24040001, 0x24050004, 0xc0044cc, 0x2003021, 
-0x24040001, 0x24050005, 0x27b0001e, 0xc0044cc, 
-0x2003021, 0x24040001, 0x24050005, 0xc0044cc, 
-0x2003021, 0x24040001, 0x24050010, 0xc0044cc, 
-0x27a60018, 0x24040001, 0x24050010, 0xc0044cc, 
-0x27a60018, 0x24040001, 0x2405000a, 0xc0044cc, 
-0x2203021, 0x24040001, 0x2405000a, 0xc0044cc, 
-0x2203021, 0x24040001, 0x24050001, 0xc0044cc, 
-0x27a60018, 0x24040001, 0x24050001, 0xc0044cc, 
-0x27a60018, 0x97a20018, 0x30420004, 0x10400058, 
-0x3c114000, 0x3c030001, 0x8c636fac, 0x24020005, 
-0x14620059, 0x24040001, 0x24050019, 0x27b00022, 
-0xc0044cc, 0x2003021, 0x24040001, 0x24050019, 
-0xc0044cc, 0x2003021, 0x97a20022, 0x30430700, 
-0x24020400, 0x10620027, 0x28620401, 0x1040000e, 
-0x24020200, 0x1062001f, 0x28620201, 0x10400005, 
-0x24020100, 0x5062001e, 0x3c130001, 0x1000001e, 
-0x3c020004, 0x24020300, 0x50620019, 0x3c130002, 
-0x10000019, 0x3c020004, 0x24020600, 0x1062000d, 
-0x28620601, 0x10400005, 0x24020500, 0x5062000b, 
-0x3c130002, 0x10000010, 0x3c020004, 0x24020700, 
-0x1462000d, 0x3c020004, 0x3c130004, 0x1000000a, 
-0x3c120008, 0x10000006, 0x3c130004, 0x10000005, 
-0x3c120008, 0x3c130001, 0x10000002, 0x3c120008, 
-0x3c120010, 0x3c020004, 0x12620017, 0x3c028000, 
-0x8f820054, 0x24100001, 0x3c010001, 0xac306e1c, 
-0x3c010001, 0xac306e18, 0x3c010001, 0xac306e24, 
-0x3c010001, 0xac306ea4, 0x3c010001, 0xac226fa8, 
-0x3c020001, 0x16620014, 0x2728825, 0x2021, 
-0x2821, 0xc004e0e, 0x34068000, 0x3c010001, 
-0x1000000d, 0xac306ea0, 0x2221025, 0x2531825, 
-0x3c010001, 0xac206ea0, 0x10000007, 0x438825, 
-0x3c110002, 0x2358821, 0x8e319070, 0x3c027fff, 
-0x3442ffff, 0x2228824, 0x3c020001, 0x8c426e28, 
-0x10400066, 0x1e1140, 0x3c020001, 0x8c426f98, 
-0x10400002, 0x3c022000, 0x2228825, 0x1e1140, 
-0x3c010002, 0x220821, 0x8c229084, 0x10400003, 
-0x3c020020, 0x10000004, 0x2228825, 0x3c02ffdf, 
-0x3442ffff, 0x2228824, 0x1e1140, 0x3c010002, 
-0x220821, 0x8c22908c, 0x10400003, 0x3c020080, 
-0x1000004d, 0x2228825, 0x3c02ff7f, 0x3442ffff, 
-0x10000049, 0x2228824, 0x1e2940, 0x3c030002, 
-0x651821, 0x8c639078, 0x3c024000, 0x621024, 
+0x8fa8002c, 0x81140, 0x3c010002, 0x220821, 
+0x8c22900c, 0x10400003, 0x3c020080, 0x1000004f, 
+0x2228825, 0x3c02ff7f, 0x3442ffff, 0x1000004b, 
+0x2228824, 0x8fa8002c, 0x82940, 0x3c030002, 
+0x651821, 0x8c638ff8, 0x3c024000, 0x621024, 
 0x14400008, 0x3c027fff, 0x3442ffff, 0x628824, 
-0x3c010002, 0x250821, 0xac319070, 0x1000003f, 
-0x2201021, 0x3c020001, 0x8c426e28, 0x10400033, 
-0x3c11c00c, 0x3c020001, 0x8c426ec4, 0x3c04c00c, 
-0x34842000, 0x3c030001, 0x8c636f98, 0x2102b, 
+0x3c010002, 0x250821, 0xac318ff0, 0x10000041, 
+0x2201021, 0x3c020001, 0x8c426da8, 0x10400034, 
+0x3c11c00c, 0x3c020001, 0x8c426e44, 0x3c04c00c, 
+0x34842000, 0x3c030001, 0x8c636f1c, 0x2102b, 
 0x21023, 0x441024, 0x10600003, 0x518825, 
 0x3c022000, 0x2228825, 0x3c020002, 0x451021, 
-0x8c429084, 0x10400003, 0x3c020020, 0x10000004, 
+0x8c429004, 0x10400003, 0x3c020020, 0x10000004, 
 0x2228825, 0x3c02ffdf, 0x3442ffff, 0x2228824, 
-0x1e1140, 0x3c010002, 0x220821, 0x8c22908c, 
-0x10400003, 0x3c020080, 0x10000004, 0x2228825, 
-0x3c02ff7f, 0x3442ffff, 0x2228824, 0x3c020001, 
-0x8c426eb0, 0x10400002, 0x3c020800, 0x2228825, 
-0x3c020001, 0x8c426eb4, 0x10400002, 0x3c020400, 
-0x2228825, 0x3c020001, 0x8c426eb8, 0x10400006, 
-0x3c020100, 0x10000004, 0x2228825, 0x3c027fff, 
-0x3442ffff, 0x628824, 0x1e1140, 0x3c010002, 
-0x220821, 0xac319070, 0x2201021, 0x8fbf0040, 
-0x8fbe003c, 0x8fb50038, 0x8fb30034, 0x8fb20030, 
-0x8fb1002c, 0x8fb00028, 0x3e00008, 0x27bd0048, 
-0x27bdffd0, 0xafb20028, 0x809021, 0xafbf002c, 
-0xafb10024, 0xafb00020, 0x8f840200, 0x3c100001, 
-0x8e106e18, 0x8f860220, 0x24020002, 0x1202005c, 
-0x2e020003, 0x10400005, 0x24020001, 0x1202000a, 
-0x121940, 0x1000010c, 0x0, 0x24020004, 
-0x120200bf, 0x24020008, 0x120200be, 0x128940, 
-0x10000105, 0x0, 0x3c050002, 0xa32821, 
-0x8ca5907c, 0x3c100002, 0x2038021, 0x8e109074, 
-0x3c024000, 0xa21024, 0x10400038, 0x3c020008, 
-0x2021024, 0x10400020, 0x34840002, 0x3c020002, 
-0x431021, 0x8c429080, 0x10400005, 0x34840020, 
-0x34840100, 0x3c020020, 0x10000006, 0x2028025, 
-0x2402feff, 0x822024, 0x3c02ffdf, 0x3442ffff, 
-0x2028024, 0x121140, 0x3c010002, 0x220821, 
-0x8c229088, 0x10400005, 0x3c020001, 0xc23025, 
-0x3c020080, 0x10000016, 0x2028025, 0x3c02fffe, 
-0x3442ffff, 0xc23024, 0x3c02ff7f, 0x3442ffff, 
-0x1000000f, 0x2028024, 0x2402fedf, 0x822024, 
-0x3c02fffe, 0x3442ffff, 0xc23024, 0x3c02ff5f, 
-0x3442ffff, 0x2028024, 0x3c010002, 0x230821, 
-0xac209080, 0x3c010002, 0x230821, 0xac209088, 
-0xaf840200, 0xaf860220, 0x8f820220, 0x34420002, 
-0xaf820220, 0x1000000a, 0x121140, 0x3c02bfff, 
-0x3442ffff, 0x8f830200, 0x2028024, 0x2402fffd, 
-0x621824, 0xc003d87, 0xaf830200, 0x121140, 
-0x3c010002, 0x220821, 0x100000b7, 0xac309074, 
-0x3c020001, 0x8c426f98, 0x10400069, 0x24050004, 
-0x24040001, 0xc0044cc, 0x27a60018, 0x24040001, 
-0x24050005, 0xc0044cc, 0x27a6001a, 0x97a30018, 
-0x97a2001a, 0x3c040001, 0x24846ec8, 0x30630c00, 
-0x31a82, 0x30420c00, 0x21282, 0xa7a2001a, 
-0x21080, 0x441021, 0x431021, 0xa7a30018, 
-0x90480000, 0x24020001, 0x3103ffff, 0x10620029, 
-0x28620002, 0x10400005, 0x0, 0x10600009, 
-0x0, 0x1000003d, 0x0, 0x10700013, 
-0x24020003, 0x1062002c, 0x0, 0x10000037, 
-0x0, 0x8f820200, 0x2403feff, 0x431024, 
-0xaf820200, 0x8f820220, 0x3c03fffe, 0x3463ffff, 
-0x431024, 0xaf820220, 0x3c010002, 0xac209084, 
-0x3c010002, 0x10000032, 0xac20908c, 0x8f820200, 
-0x34420100, 0xaf820200, 0x8f820220, 0x3c03fffe, 
-0x3463ffff, 0x431024, 0xaf820220, 0x24020100, 
-0x3c010002, 0xac229084, 0x3c010002, 0x10000024, 
-0xac20908c, 0x8f820200, 0x2403feff, 0x431024, 
-0xaf820200, 0x8f820220, 0x3c030001, 0x431025, 
-0xaf820220, 0x3c010002, 0xac209084, 0x3c010002, 
-0x10000017, 0xac23908c, 0x8f820200, 0x34420100, 
-0xaf820200, 0x8f820220, 0x3c030001, 0x431025, 
-0xaf820220, 0x24020100, 0x3c010002, 0xac229084, 
-0x3c010002, 0x1000000a, 0xac23908c, 0x3c040001, 
-0x24846d00, 0x97a6001a, 0x97a70018, 0x3c050001, 
-0x34a5ffff, 0xafa80010, 0xc002b17, 0xafa00014, 
-0x8f820200, 0x34420002, 0x1000004b, 0xaf820200, 
-0x128940, 0x3c050002, 0xb12821, 0x8ca59078, 
-0x3c100002, 0x2118021, 0x8e109070, 0x3c024000, 
-0xa21024, 0x14400010, 0x0, 0x3c020001, 
-0x8c426f98, 0x14400005, 0x3c02bfff, 0x8f820200, 
-0x34420002, 0xaf820200, 0x3c02bfff, 0x3442ffff, 
-0xc003d87, 0x2028024, 0x3c010002, 0x310821, 
-0x10000031, 0xac309070, 0x3c020001, 0x8c426f98, 
-0x10400005, 0x3c020020, 0x3c020001, 0x8c426ec4, 
-0x10400025, 0x3c020020, 0xa21024, 0x10400007, 
-0x34840020, 0x24020100, 0x3c010002, 0x310821, 
-0xac229084, 0x10000006, 0x34840100, 0x3c010002, 
-0x310821, 0xac209084, 0x2402feff, 0x822024, 
-0x3c020080, 0xa21024, 0x10400007, 0x121940, 
-0x3c020001, 0x3c010002, 0x230821, 0xac22908c, 
-0x10000008, 0xc23025, 0x121140, 0x3c010002, 
-0x220821, 0xac20908c, 0x3c02fffe, 0x3442ffff, 
-0xc23024, 0xaf840200, 0xaf860220, 0x8f820220, 
-0x34420002, 0xaf820220, 0x121140, 0x3c010002, 
-0x220821, 0xac309070, 0x8fbf002c, 0x8fb20028, 
-0x8fb10024, 0x8fb00020, 0x3e00008, 0x27bd0030, 
-0x0, 0x0, 0x0, 0x1821, 
+0x8fa8002c, 0x81140, 0x3c010002, 0x220821, 
+0x8c22900c, 0x10400003, 0x3c020080, 0x10000004, 
+0x2228825, 0x3c02ff7f, 0x3442ffff, 0x2228824, 
+0x3c020001, 0x8c426e30, 0x10400002, 0x3c020800, 
+0x2228825, 0x3c020001, 0x8c426e34, 0x10400002, 
+0x3c020400, 0x2228825, 0x3c020001, 0x8c426e38, 
+0x10400006, 0x3c020100, 0x10000004, 0x2228825, 
+0x3c027fff, 0x3442ffff, 0x628824, 0x8fa8002c, 
+0x81140, 0x3c010002, 0x220821, 0xac318ff0, 
+0x2201021, 0x8fbf0048, 0x8fbe0044, 0x8fb50040, 
+0x8fb3003c, 0x8fb20038, 0x8fb10034, 0x8fb00030, 
+0x3e00008, 0x27bd0050, 0x27bdffd0, 0xafb20028, 
+0x809021, 0xafbf002c, 0xafb10024, 0xafb00020, 
+0x8f840200, 0x3c100001, 0x8e106d98, 0x8f860220, 
+0x24020002, 0x1202005c, 0x2e020003, 0x10400005, 
+0x24020001, 0x1202000a, 0x121940, 0x1000010c, 
+0x0, 0x24020004, 0x120200bf, 0x24020008, 
+0x120200be, 0x128940, 0x10000105, 0x0, 
+0x3c050002, 0xa32821, 0x8ca58ffc, 0x3c100002, 
+0x2038021, 0x8e108ff4, 0x3c024000, 0xa21024, 
+0x10400038, 0x3c020008, 0x2021024, 0x10400020, 
+0x34840002, 0x3c020002, 0x431021, 0x8c429000, 
+0x10400005, 0x34840020, 0x34840100, 0x3c020020, 
+0x10000006, 0x2028025, 0x2402feff, 0x822024, 
+0x3c02ffdf, 0x3442ffff, 0x2028024, 0x121140, 
+0x3c010002, 0x220821, 0x8c229008, 0x10400005, 
+0x3c020001, 0xc23025, 0x3c020080, 0x10000016, 
+0x2028025, 0x3c02fffe, 0x3442ffff, 0xc23024, 
+0x3c02ff7f, 0x3442ffff, 0x1000000f, 0x2028024, 
+0x2402fedf, 0x822024, 0x3c02fffe, 0x3442ffff, 
+0xc23024, 0x3c02ff5f, 0x3442ffff, 0x2028024, 
+0x3c010002, 0x230821, 0xac209000, 0x3c010002, 
+0x230821, 0xac209008, 0xaf840200, 0xaf860220, 
+0x8f820220, 0x34420002, 0xaf820220, 0x1000000a, 
+0x121140, 0x3c02bfff, 0x3442ffff, 0x8f830200, 
+0x2028024, 0x2402fffd, 0x621824, 0xc003daf, 
+0xaf830200, 0x121140, 0x3c010002, 0x220821, 
+0x100000b7, 0xac308ff4, 0x3c020001, 0x8c426f1c, 
+0x10400069, 0x24050004, 0x24040001, 0xc00457c, 
+0x27a60018, 0x24040001, 0x24050005, 0xc00457c, 
+0x27a6001a, 0x97a30018, 0x97a2001a, 0x3c040001, 
+0x24846e48, 0x30630c00, 0x31a82, 0x30420c00, 
+0x21282, 0xa7a2001a, 0x21080, 0x441021, 
+0x431021, 0xa7a30018, 0x90480000, 0x24020001, 
+0x3103ffff, 0x10620029, 0x28620002, 0x10400005, 
+0x0, 0x10600009, 0x0, 0x1000003d, 
+0x0, 0x10700013, 0x24020003, 0x1062002c, 
+0x0, 0x10000037, 0x0, 0x8f820200, 
+0x2403feff, 0x431024, 0xaf820200, 0x8f820220, 
+0x3c03fffe, 0x3463ffff, 0x431024, 0xaf820220, 
+0x3c010002, 0xac209004, 0x3c010002, 0x10000032, 
+0xac20900c, 0x8f820200, 0x34420100, 0xaf820200, 
+0x8f820220, 0x3c03fffe, 0x3463ffff, 0x431024, 
+0xaf820220, 0x24020100, 0x3c010002, 0xac229004, 
+0x3c010002, 0x10000024, 0xac20900c, 0x8f820200, 
+0x2403feff, 0x431024, 0xaf820200, 0x8f820220, 
+0x3c030001, 0x431025, 0xaf820220, 0x3c010002, 
+0xac209004, 0x3c010002, 0x10000017, 0xac23900c, 
+0x8f820200, 0x34420100, 0xaf820200, 0x8f820220, 
+0x3c030001, 0x431025, 0xaf820220, 0x24020100, 
+0x3c010002, 0xac229004, 0x3c010002, 0x1000000a, 
+0xac23900c, 0x3c040001, 0x24846c80, 0x97a6001a, 
+0x97a70018, 0x3c050001, 0x34a5ffff, 0xafa80010, 
+0xc002b3b, 0xafa00014, 0x8f820200, 0x34420002, 
+0x1000004b, 0xaf820200, 0x128940, 0x3c050002, 
+0xb12821, 0x8ca58ff8, 0x3c100002, 0x2118021, 
+0x8e108ff0, 0x3c024000, 0xa21024, 0x14400010, 
+0x0, 0x3c020001, 0x8c426f1c, 0x14400005, 
+0x3c02bfff, 0x8f820200, 0x34420002, 0xaf820200, 
+0x3c02bfff, 0x3442ffff, 0xc003daf, 0x2028024, 
+0x3c010002, 0x310821, 0x10000031, 0xac308ff0, 
+0x3c020001, 0x8c426f1c, 0x10400005, 0x3c020020, 
+0x3c020001, 0x8c426e44, 0x10400025, 0x3c020020, 
+0xa21024, 0x10400007, 0x34840020, 0x24020100, 
+0x3c010002, 0x310821, 0xac229004, 0x10000006, 
+0x34840100, 0x3c010002, 0x310821, 0xac209004, 
+0x2402feff, 0x822024, 0x3c020080, 0xa21024, 
+0x10400007, 0x121940, 0x3c020001, 0x3c010002, 
+0x230821, 0xac22900c, 0x10000008, 0xc23025, 
+0x121140, 0x3c010002, 0x220821, 0xac20900c, 
+0x3c02fffe, 0x3442ffff, 0xc23024, 0xaf840200, 
+0xaf860220, 0x8f820220, 0x34420002, 0xaf820220, 
+0x121140, 0x3c010002, 0x220821, 0xac308ff0, 
+0x8fbf002c, 0x8fb20028, 0x8fb10024, 0x8fb00020, 
+0x3e00008, 0x27bd0030, 0x0, 0x1821, 
 0x308400ff, 0x2405ffdf, 0x2406ffbf, 0x641007, 
 0x30420001, 0x10400004, 0x0, 0x8f820044, 
 0x10000003, 0x34420040, 0x8f820044, 0x461024, 
@@ -9131,7 +9117,7 @@
 0x28620008, 0x5440ffee, 0x641007, 0x3e00008, 
 0x0, 0x2c820008, 0x1040001b, 0x0, 
 0x2405ffdf, 0x2406ffbf, 0x41880, 0x3c020001, 
-0x24426ee0, 0x621821, 0x24640004, 0x90620000, 
+0x24426e60, 0x621821, 0x24640004, 0x90620000, 
 0x10400004, 0x0, 0x8f820044, 0x10000003, 
 0x34420040, 0x8f820044, 0x461024, 0xaf820044, 
 0x8f820044, 0x34420020, 0xaf820044, 0x8f820044, 
@@ -9180,7 +9166,7 @@
 0x74460000, 0x4d516576, 0x505f4600, 0x5173436f, 
 0x6e495f46, 0x0, 0x5173436f, 0x6e734600, 
 0x51725072, 0x6f644600, 0x6261644d, 0x656d537a, 
-0x0, 0x68774677, 0x56657200, 0x62616448, 
+0x0, 0x68775665, 0x72000000, 0x62616448, 
 0x77566572, 0x0, 0x2a2a4441, 0x574e5f41, 
 0x0, 0x74785278, 0x4266537a, 0x0, 
 0x62664174, 0x6e4d726b, 0x0, 0x7265645a, 
@@ -9276,12 +9262,12 @@
 0x0, 0x3f636d64, 0x48737453, 0x0, 
 0x3f636d64, 0x4d634d64, 0x0, 0x3f636d64, 
 0x50726f6d, 0x0, 0x3f636d64, 0x4c696e6b, 
-0x0, 0x3f636d64, 0x45727200, 0x864c, 
-0x8de0, 0x8de0, 0x8d68, 0x8b0c, 
-0x8db4, 0x8de0, 0x8724, 0x8794, 
-0x8924, 0x89fc, 0x89c8, 0x8de0, 
-0x8804, 0x8ab8, 0x8de0, 0x8ac8, 
-0x8748, 0x87b8, 0x0, 0x0, 
+0x0, 0x3f636d64, 0x45727200, 0x86ac, 
+0x8e5c, 0x8e5c, 0x8de4, 0x8b78, 
+0x8e30, 0x8e5c, 0x8790, 0x8800, 
+0x8990, 0x8a68, 0x8a34, 0x8e5c, 
+0x8870, 0x8b24, 0x8e5c, 0x8b34, 
+0x87b4, 0x8824, 0x0, 0x0, 
 0x0, 0x24486561, 0x6465723a, 0x202f7072, 
 0x6f6a6563, 0x74732f72, 0x63732f73, 0x772f6765, 
 0x2f2e2f6e, 0x69632f66, 0x77322f63, 0x6f6d6d6f, 
@@ -9332,10 +9318,10 @@
 0x2e313220, 0x31393939, 0x2f30312f, 0x32302031, 
 0x393a3439, 0x3a353120, 0x73687561, 0x6e672045, 
 0x78702024, 0x0, 0x46575f56, 0x45525349, 
-0x4f4e3a20, 0x23312053, 0x61742044, 0x65632031, 
-0x31203136, 0x3a30353a, 0x30332050, 0x53542031, 
-0x39393900, 0x46575f43, 0x4f4d5049, 0x4c455f54, 
-0x494d453a, 0x2031363a, 0x30353a30, 0x33000000, 
+0x4f4e3a20, 0x23312046, 0x72692041, 0x70722037, 
+0x2031373a, 0x35373a35, 0x32205044, 0x54203230, 
+0x30300000, 0x46575f43, 0x4f4d5049, 0x4c455f54, 
+0x494d453a, 0x2031373a, 0x35373a35, 0x32000000, 
 0x46575f43, 0x4f4d5049, 0x4c455f42, 0x593a2064, 
 0x65767263, 0x73000000, 0x46575f43, 0x4f4d5049, 
 0x4c455f48, 0x4f53543a, 0x20636f6d, 0x70757465, 
@@ -9343,7 +9329,7 @@
 0x4f4d4149, 0x4e3a2065, 0x6e672e61, 0x6374656f, 
 0x6e2e636f, 0x6d000000, 0x46575f43, 0x4f4d5049, 
 0x4c45523a, 0x20676363, 0x20766572, 0x73696f6e, 
-0x20322e37, 0x2e320000, 0x0, 0x12040100, 
+0x20322e37, 0x2e320000, 0x0, 0x12041100, 
 0x0, 0x24486561, 0x6465723a, 0x202f7072, 
 0x6f6a6563, 0x74732f72, 0x63732f73, 0x772f6765, 
 0x2f2e2f6e, 0x69632f66, 0x77322f63, 0x6f6d6d6f, 
@@ -9411,31 +9397,32 @@
 0x6e495f46, 0x0, 0x5173436f, 0x6e734600, 
 0x51725072, 0x6f644600, 0x0, 0x0, 
 0x0, 0x50726f62, 0x65506879, 0x0, 
-0x6c6e6b41, 0x53535254, 0x0, 0x108d0, 
-0x10948, 0x10968, 0x109a4, 0x10ea8, 
-0x109d0, 0x10a0c, 0x10f3c, 0x10c18, 
-0x10ac0, 0x10ad8, 0x10b1c, 0x10b44, 
-0x10b64, 0x10b8c, 0x10f3c, 0x10c18, 
-0x10c50, 0x10c68, 0x10c98, 0x10cc0, 
-0x10ce0, 0x10d08, 0x0, 0x10e34, 
-0x10e60, 0x10e84, 0x10f3c, 0x10ea8, 
-0x109d0, 0x10ed8, 0x0, 0x0, 
-0x0, 0x115ac, 0x1167c, 0x11754, 
-0x11824, 0x11880, 0x1195c, 0x11984, 
-0x11a60, 0x11a88, 0x11c30, 0x11c58, 
-0x11e00, 0x11ff8, 0x1228c, 0x121a0, 
-0x1228c, 0x122b8, 0x11e28, 0x11fd0, 
-0x7273745f, 0x676d6969, 0x0, 0x12348, 
-0x12380, 0x12468, 0x13034, 0x135fc, 
-0x13614, 0x13c7c, 0x13cbc, 0x13d4c, 
-0x13d90, 0x13df4, 0x13e80, 0x13eb4, 
-0x13f3c, 0x13fd4, 0x140a4, 0x140e4, 
-0x14168, 0x1418c, 0x1429c, 0x646f4261, 
+0x6c6e6b41, 0x53535254, 0x0, 0x109a4, 
+0x10a1c, 0x10a50, 0x10a7c, 0x11050, 
+0x10aa8, 0x10b10, 0x111fc, 0x10dc0, 
+0x10c68, 0x10c80, 0x10cc4, 0x10cec, 
+0x10d0c, 0x10d34, 0x111fc, 0x10dc0, 
+0x10df8, 0x10e10, 0x10e40, 0x10e68, 
+0x10e88, 0x10eb0, 0x0, 0x10fdc, 
+0x11008, 0x1102c, 0x111fc, 0x11050, 
+0x11078, 0x11108, 0x0, 0x0, 
+0x0, 0x1186c, 0x1193c, 0x11a14, 
+0x11ae4, 0x11b40, 0x11c1c, 0x11c44, 
+0x11d20, 0x11d48, 0x11ef0, 0x11f18, 
+0x120c0, 0x122b8, 0x1254c, 0x12460, 
+0x1254c, 0x12578, 0x120e8, 0x12290, 
+0x7273745f, 0x676d6969, 0x0, 0x12608, 
+0x12640, 0x12728, 0x13374, 0x133b4, 
+0x133cc, 0x7365746c, 0x6f6f7000, 0x0, 
+0x0, 0x13bbc, 0x13bfc, 0x13c8c, 
+0x13cd0, 0x13d34, 0x13dc0, 0x13df4, 
+0x13e7c, 0x13f14, 0x13fe4, 0x14024, 
+0x140a8, 0x140cc, 0x141dc, 0x646f4261, 
 0x73655067, 0x0, 0x0, 0x0, 
 0x0, 0x73746d61, 0x634c4e4b, 0x0, 
-0x6765746d, 0x636c6e6b, 0x0, 0x14fb4, 
-0x14fb4, 0x14ce4, 0x14d34, 0x14d78, 
-0x14fb4, 0x7365746d, 0x61636163, 0x74000000, 
+0x6765746d, 0x636c6e6b, 0x0, 0x14ed8, 
+0x14ed8, 0x14b8c, 0x14bd8, 0x14c24, 
+0x14ed8, 0x7365746d, 0x61636163, 0x74000000, 
 0x0, 0x0 };
 u32 tigon2FwData[(MAX_DATA_LEN/4) + 1] __initdata = {
 0x1, 
Index: oldkernel/linux/drivers/net/dgrs.c
diff -u linux/drivers/net/dgrs.c:1.1.1.1 linux/drivers/net/dgrs.c:1.2
--- linux/drivers/net/dgrs.c:1.1.1.1	Wed May 31 12:33:50 2000
+++ linux/drivers/net/dgrs.c	Fri Jul  7 15:36:43 2000
@@ -861,6 +861,8 @@
 				return -EFAULT;
 			return (0);
 		case DGRS_SETFILTER:
+			if (!suser())
+				return -EPERM;
 			if (ioc.port > privN->bcomm->bc_nports)
 				return -EINVAL;
 			if (ioc.filter >= NFILTERS)
@@ -1197,8 +1199,11 @@
 
 	priv->intrcnt = 0;
 	for (i = jiffies + 2*HZ + HZ/2; time_after(i, jiffies); )
+	{
+		rmb();		/* gcc 2.95 needs this */
 		if (priv->intrcnt >= 2)
 			break;
+	}
 	if (priv->intrcnt < 2)
 	{
 		printk("%s: Not interrupting on IRQ %d (%d)\n",
Index: oldkernel/linux/drivers/net/eepro100.c
diff -u linux/drivers/net/eepro100.c:1.5 linux/drivers/net/eepro100.c:1.6
--- linux/drivers/net/eepro100.c:1.5	Thu Jun  1 17:15:50 2000
+++ linux/drivers/net/eepro100.c	Fri Jul  7 15:36:43 2000
@@ -24,11 +24,24 @@
 	The driver also contains updates by different kernel developers.
 	This driver clone is maintained by Andrey V. Savochkin <saw@saw.sw.com.sg>.
 	Please use this email address and linux-kernel mailing list for bug reports.
+	
+	Modification history:
+
+	2000 May 9 Dragan Stancevic <visitor@valinux.com> 
+		Added the ability to change the driver debug
+	       	level on the fly.
+	
+	2000 May 4 Dragan Stancevic <visitor@valinux.com> 
+		Added more detailed device recognition.
+	
+	2000 Mar 24  Dragan Stancevic <visitor@valinux.com>
+		Disabled FC and ER, to avoid lockups when when we get FCP interrupts.
+		Dragan Stancevic <visitor@valinux.com> March 24th, 2000.
 */
 
 static const char *version =
 "eepro100.c:v1.09j-t 9/29/99 Donald Becker http://cesdis.gsfc.nasa.gov/linux/drivers/eepro100.html\n"
-"eepro100.c: $Revision: 1.1.2.1 $ 2000/03/02 Modified by Andrey V. Savochkin <saw@saw.sw.com.sg> and others\n";
+"eepro100.c: $Revision: 1.20.2.5 $ 2000/03/28 Modified by Andrey V. Savochkin <saw@saw.sw.com.sg> and others\n";
 
 /* A few user-configurable values that apply to all boards.
    First set is undocumented and spelled per Intel recommendations. */
@@ -103,17 +116,8 @@
 #include <linux/ioport.h>
 #include <linux/malloc.h>
 #include <linux/interrupt.h>
-#ifdef HAS_PCI_NETIF
-#include "pci-netif.h"
-#else
 #include <linux/pci.h>
-#endif
-#include <linux/pci.h>
-#if LINUX_VERSION_CODE >= 0x20312
-#include <linux/spinlock.h>
-#else
 #include <asm/spinlock.h>
-#endif
 
 #include <asm/bitops.h>
 #include <asm/io.h>
@@ -144,21 +148,18 @@
 #define virt_to_le32desc(addr)  cpu_to_le32(virt_to_bus(addr))
 #define le32desc_to_virt(addr)  bus_to_virt(le32_to_cpu(addr))
 
-#if LINUX_VERSION_CODE < 0x020314
 #define net_device              device
 #define pci_base_address(p, n)  (p)->base_address[n]
-#else
-#define pci_base_address(p, n)  (p)->resource[n].start
-#endif
 
 #define dev_free_skb(skb)       dev_kfree_skb(skb);
-#if ! defined(HAS_NETIF_QUEUE)
 #define netif_wake_queue(dev)   do { \
 									clear_bit(0, (void*)&dev->tbusy); \
 									mark_bh(NET_BH); \
 								} while(0)
 #define netif_start_queue(dev)  clear_bit(0, (void*)&dev->tbusy)
 #define netif_stop_queue(dev)   set_bit(0, (void*)&dev->tbusy)
+#ifndef PCI_DEVICE_ID_INTEL_82559ER
+#define PCI_DEVICE_ID_INTEL_82559ER 0x1209
 #endif
 
 /* The total I/O port extent of the board.
@@ -282,7 +283,8 @@
 */
 
 /* This table drives the PCI probe routines. */
-static struct net_device *speedo_found1(int pci_bus, int pci_devfn, long ioaddr, int irq, int chip_idx, int fnd_cnt);
+static struct net_device *speedo_found1(int pci_bus, int pci_devfn,
+		long ioaddr, int irq, int chip_idx, int fnd_cnt, int dev_id, unsigned char rev_id);
 
 #ifdef USE_IO
 #define SPEEDO_IOTYPE   PCI_USES_MASTER|PCI_USES_IO|PCI_ADDR1
@@ -308,7 +310,8 @@
 	const char *name;
 	u16	vendor_id, device_id, device_id_mask, flags;
 	int io_size;
-	struct net_device *(*probe1)(int pci_bus, int pci_devfn, long ioaddr, int irq, int chip_idx, int fnd_cnt);
+	struct net_device *(*probe1)(int pci_bus, int pci_devfn, long ioaddr,
+			int irq, int chip_idx, int fnd_cnt, int dev_id, unsigned char rev_id);
 } static pci_tbl[] = {
 	{ "Intel PCI EtherExpress Pro100",
 	  0x8086, 0x1229, 0xffff, PCI_USES_IO|PCI_USES_MASTER, 32, speedo_found1 },
@@ -316,21 +319,6 @@
 };
 #endif
 
-struct eepro_revision_info {
-	const char *name;
-	unsigned char revision;
-} static eepro_revisions [] = {
-	{ "82557 (A-Step)", 0x1},
-	{ "82557 (B-Step)", 0x2},
-	{ "82557 (C-Step)", 0x3},
-	{ "82558 (A-Step)", 0x4},
-	{ "82558 (B-Step)", 0x5},
-	{ "82559 (A-Step)", 0x6},
-	{ "82559 (B-Step)", 0x7},
-	{ "82559 (C-Step)", 0x8},
-	{ "82559ER (A-Step)", 0x9},
-};
-
 #ifndef USE_IO
 #undef inb
 #undef inw
@@ -350,7 +338,7 @@
    Typically this takes 0 ticks. */
 static inline void wait_for_cmd_done(long cmd_ioaddr)
 {
-	int wait = 100;
+	int wait = 1000;
 	do   ;
 	while(inb(cmd_ioaddr) && --wait >= 0);
 }
@@ -381,7 +369,7 @@
 #if defined(__LITTLE_ENDIAN)
 #define clear_suspend(cmd)  ((__u16 *)&(cmd)->cmd_status)[1] &= ~0x4000
 #elif defined(__BIG_ENDIAN)
-#define clear_suspend(cmd)  ((__u16 *)&(cmd)->cmd_status)[0] &= ~0x4000
+#define clear_suspend(cmd)  ((__u16 *)&(cmd)->cmd_status)[1] &= ~0x0040
 #else
 #error Unsupported byteorder
 #endif
@@ -521,7 +509,7 @@
 const char i82558_config_cmd[22] = {
 	22, 0x08, 0, 1,  0, 0, 0x22, 0x03,  1, /* 1=Use MII  0=Use AUI */
 	0, 0x2E, 0,  0x60, 0x08, 0x88,
-	0x68, 0, 0x40, 0xf2, 0xBD, 		/* 0xBD->0xFD=Force full-duplex */
+	0x68, 0, 0x40, 0xf2, 0x84,		/* Disable FC */
 	0x31, 0x05, };
 
 /* PHY media interface chips. */
@@ -535,6 +523,13 @@
 static const char is_mii[] = { 0, 1, 1, 0, 1, 1, 0, 1 };
 #define EE_READ_CMD		(6)
 
+/* Device specific Revision IDs */
+#define REV_ID_82558_A      0x4
+#define REV_ID_82558_B      0x5
+#define REV_ID_82559_B      0x8
+#define REV_ID_82559_C      0x9  
+
+
 static int do_eeprom_cmd(long ioaddr, int cmd, int cmd_len);
 static int mdio_read(long ioaddr, int phy_id, int location);
 static int mdio_write(long ioaddr, int phy_id, int location, int value);
@@ -576,7 +571,7 @@
 		return cards_found;
 
 	for (; pci_index < 8; pci_index++) {
-		unsigned char pci_bus, pci_device_fn, pci_latency;
+		unsigned char pci_bus, pci_device_fn, pci_latency, rev_id;
 		unsigned long pciaddr;
 		long ioaddr;
 		int irq;
@@ -607,9 +602,22 @@
 				   pciaddr);
 			continue;
 		}
-		if (speedo_debug > 2)
-			printk("Found Intel i82557 PCI Speedo at I/O %#lx, IRQ %d.\n",
-				   ioaddr, irq);
+		/* Read the device revision ID */
+		pcibios_read_config_byte(pci_bus, pci_device_fn,
+								PCI_REVISION_ID, &rev_id);
+				 
+		/* Display device version */
+		if (speedo_debug > 2){
+			printk("Found Intel i");
+			if(rev_id < REV_ID_82558_A)
+				printk("82557");
+			else if(rev_id < REV_ID_82559_B)
+				printk("82558");
+			else if(rev_id >= REV_ID_82559_B)
+				printk("82559");
+			printk(" PCI Speedo at I/O %#lx, IRQ %d, Rev. ID 0x%x.\n",
+					ioaddr, irq, rev_id);
+		} 
 
 		/* Get and check the bus-master and latency values. */
 		pcibios_read_config_word(pci_bus, pci_device_fn,
@@ -632,12 +640,13 @@
 		} else if (speedo_debug > 1)
 			printk("  PCI latency timer (CFLT) is %#x.\n", pci_latency);
 
-		if (speedo_found1(pci_bus, pci_device_fn, ioaddr, irq, 0, cards_found))
+		if (speedo_found1(pci_bus, pci_device_fn, ioaddr, irq, 0, cards_found,
+					PCI_DEVICE_ID_INTEL_82557, rev_id))
 			cards_found++;
 	}
 
 	for (; pci_index < 8; pci_index++) {
-		unsigned char pci_bus, pci_device_fn, pci_latency;
+		unsigned char pci_bus, pci_device_fn, pci_latency, rev_id;
 		long ioaddr;
 		int irq;
 
@@ -655,10 +664,16 @@
 		}
 		/* Remove I/O space marker in bit 0. */
 		ioaddr &= ~3;
+ 
+		/* Read the device revision ID */
+		pcibios_read_config_byte(pci_bus, pci_device_fn,
+								PCI_REVISION_ID, &rev_id);
+
+		/* Display device version */
 		if (speedo_debug > 2)
-		    printk("Found Intel i82559ER PCI Speedo at I/O %#lx, IRQ %d.\n",
-			   ioaddr, irq);
-		
+			printk("Found Intel i82559ER PCI Speedo at I/O %#lx, IRQ %d,"
+					" Rev. ID 0x%x.\n", ioaddr, irq, rev_id);
+				
 		/* Get and check the bus-master and latency values. */
 		pcibios_read_config_word(pci_bus, pci_device_fn,
 					 PCI_COMMAND, &pci_command);
@@ -680,7 +695,8 @@
 		} else if (speedo_debug > 1)
 			printk("  PCI latency timer (CFLT) is %#x.\n", pci_latency);
 		
-		if(speedo_found1(pci_bus, pci_device_fn, ioaddr, irq, 0, cards_found))
+		if(speedo_found1(pci_bus, pci_device_fn, ioaddr, irq, 0, cards_found,
+					PCI_DEVICE_ID_INTEL_82559ER, rev_id))
 			cards_found++;
 	}
 
@@ -689,21 +705,20 @@
 #endif
 
 static struct net_device *speedo_found1(int pci_bus, int pci_devfn, 
-			  long ioaddr, int irq, int chip_idx, int card_idx)
+			  long ioaddr, int irq, int chip_idx, int card_idx, int dev_id, unsigned char rev_id)
 {
 	struct net_device *dev;
 	struct speedo_private *sp;
-	const char *product;
+	char *product;
 	int i, option;
 	u16 eeprom[0x100];
 	int acpi_idle_state = 0;
-	unsigned char revision;
 #ifndef MODULE
 	static int did_version = 0;			/* Already printed version info. */
 	if (speedo_debug > 0  &&  did_version++ == 0)
 		printk(version);
 #endif
-
+	product = kmalloc(33, GFP_KERNEL);
 	dev = init_etherdev(NULL, sizeof(struct speedo_private));
 
 	if (dev->mem_start > 0)
@@ -758,33 +773,51 @@
 	   action. */
 	outl(PortReset, ioaddr + SCBPort);
 
-	if (eeprom[3] & 0x0100)
-		product = "OEM i82557/i82558 10/100 Ethernet";
-	else
-		product = pci_tbl[chip_idx].name;
+	/* Device is an OEM */
+	if (eeprom[3] & 0x0100){
+		if(dev_id == PCI_DEVICE_ID_INTEL_82559ER){
+			sprintf(product, "OEM Ethernet (82559ER)"
+					" Rev:%x", rev_id);
+		} else {
+			char temp[6];
+
+			if(rev_id < REV_ID_82558_A)
+				strcpy(temp,"82557");
+			else if(rev_id < REV_ID_82559_B)
+				strcpy(temp, "82558");
+			else if(rev_id >= REV_ID_82559_B)
+				strcpy(temp, "82559");
+			sprintf(product, "OEM Ethernet (%s)"
+					" Rev:%x", temp, rev_id);
+		}
+
+	/* It's an Intel device */
+	} else {
+		if(dev_id == PCI_DEVICE_ID_INTEL_82559ER){
+			sprintf(product, "Intel EEPro 100 (82559ER)"
+					" Rev:%x", rev_id);
+		} else {
+			char temp[6];
+
+			if(rev_id < REV_ID_82558_A)
+				strcpy(temp,"82557");
+			else if(rev_id < REV_ID_82559_B)
+				strcpy(temp, "82558");
+			else if(rev_id >= REV_ID_82559_B)
+				strcpy(temp, "82559");
+			sprintf(product, "Intel EEPro 100 (%s)"
+					" Rev:%x", temp, rev_id);
+		}
+
+	}
 
-	printk(KERN_INFO "%s: %s at %#3lx, ", dev->name, product, ioaddr);
+	printk(KERN_INFO "%s: PCI %s at %#3lx, ", dev->name,
+			product, ioaddr);
 
 	for (i = 0; i < 5; i++)
 		printk("%2.2X:", dev->dev_addr[i]);
 	printk("%2.2X, IRQ %d.\n", dev->dev_addr[i], irq);
 
-	/* Get the chip revision. */
-	pcibios_read_config_byte(pci_bus, pci_devfn,
-				 PCI_REVISION_ID, &revision);
-	for (i = 0;
-	     i < sizeof (eepro_revisions) / sizeof (eepro_revisions [0]);
-	     i++) {
-		if (eepro_revisions [i].revision == revision)
-			break;
-	}
-	if (i < sizeof (eepro_revisions) / sizeof (eepro_revisions [0]))
-		printk(KERN_INFO "  %s LAN controller\n",
-		       eepro_revisions [i].name);
-	else
-		printk(KERN_INFO "  Pro100 (0x%x) LAN controller\n",
-		       revision);
-
 #if 1 || defined(kernel_bloat)
 	/* OK, this is pure kernel bloat.  I don't like it when other drivers
 	   waste non-pageable kernel space to emit similar messages, but I need
@@ -861,7 +894,7 @@
 #endif
 
 	/* We do a request_region() only to register /proc/ioports info. */
-	request_region(ioaddr, SPEEDO3_TOTAL_SIZE, "Intel Speedo3 Ethernet");
+	request_region(ioaddr, SPEEDO3_TOTAL_SIZE, product);
 
 	dev->base_addr = ioaddr;
 	dev->irq = irq;
@@ -876,6 +909,7 @@
 	sp->next_module = root_speedo_dev;
 	root_speedo_dev = dev;
 
+	sp->product_name = product;
 	sp->pci_bus = pci_bus;
 	sp->pci_devfn = pci_devfn;
 	sp->chip_id = chip_idx;
@@ -1046,7 +1080,7 @@
 		sp->advertising = mdio_read(ioaddr, sp->phy[0] & 0x1f, 4);
 
 	if (speedo_debug > 2) {
-		printk(KERN_DEBUG "%s: Done speedo_open(), status %4.4x.\n",
+		printk(KERN_DEBUG "%s: Done speedo_open(), status %8.8x.\n",
 			   dev->name, inw(ioaddr + SCBStatus));
 	}
 
@@ -1122,7 +1156,9 @@
 	wait_for_cmd_done(ioaddr + SCBCmd);
 	outl(virt_to_bus(&sp->tx_ring[sp->dirty_tx % TX_RING_SIZE]),
 		 ioaddr + SCBPointer);
-	outw(CUStart, ioaddr + SCBCmd);
+	/* We are not ACK-ing FCP and ER in the interrupt handler yet so they should
+	   remain masked --Dragan */
+	outw(CUStart | SCBMaskEarlyRx | SCBMaskFlowCtl, ioaddr + SCBCmd);
 }
 
 /* Media monitoring and control. */
@@ -1221,7 +1257,6 @@
 	int i;
 
 	sp->cur_rx = 0;
-	sp->rx_ring_state = 0;
 
 	for (i = 0; i < RX_RING_SIZE; i++) {
 		struct sk_buff *skb;
@@ -1520,13 +1555,15 @@
 	do {
 		status = inw(ioaddr + SCBStatus);
 		/* Acknowledge all of the current interrupt sources ASAP. */
-		outw(status & 0xfd00, ioaddr + SCBStatus);
+		/* Will change from 0xfc00 to 0xff00 when we start handling
+		   FCP and ER interrupts --Dragan */
+		outw(status & 0xfc00, ioaddr + SCBStatus);
 
 		if (speedo_debug > 4)
 			printk(KERN_DEBUG "%s: interrupt  status=%#4.4x.\n",
 				   dev->name, status);
 
-		if ((status & 0xfd00) == 0)
+		if ((status & 0xfc00) == 0)
 			break;
 
 		/* Always check if all rx buffers are allocated.  --SAW */
@@ -1541,9 +1578,9 @@
 			spin_lock(&sp->lock);
 			if ((status & 0x003c) == 0x0028) {		/* No more Rx buffers. */
 				struct RxFD *rxf;
-				printk(KERN_WARNING "%s: card reports no RX buffers, status=%#4.4x, flow control=%s.\n",
-						dev->name, status,
-						sp->flow_ctrl ? "on" : "off");
+					if (speedo_debug > 2)
+						printk(KERN_WARNING "%s: card reports no RX buffers.\n",
+						dev->name);
 				rxf = sp->rx_ringp[sp->cur_rx % RX_RING_SIZE];
 				if (rxf == NULL) {
 					if (speedo_debug > 2)
@@ -1561,9 +1598,9 @@
 					outb(RxResumeNoResources, ioaddr + SCBCmd);
 			} else if ((status & 0x003c) == 0x0008) { /* No resources. */
 				struct RxFD *rxf;
-				printk(KERN_WARNING "%s: card reports no resources, status=%#4.4x, flow control=%s.\n",
-						dev->name, status,
-						sp->flow_ctrl ? "on" : "off");
+					if (speedo_debug > 1)
+						printk(KERN_WARNING "%s: card reports no resources.\n",
+												dev->name);
 				rxf = sp->rx_ringp[sp->cur_rx % RX_RING_SIZE];
 				if (rxf == NULL) {
 					if (speedo_debug > 2)
@@ -1621,7 +1658,9 @@
 			printk(KERN_ERR "%s: Too much work at interrupt, status=0x%4.4x.\n",
 				   dev->name, status);
 			/* Clear all interrupt sources. */
-			outw(0xfd00, ioaddr + SCBStatus);
+			/* Will change from 0xfc00 to 0xff00 when we start handling
+			   FCP and ER interrupts --Dragan */
+			outl(0xfc00, ioaddr + SCBStatus);
 			break;
 		}
 	} while (1);
@@ -1961,6 +2000,13 @@
 		mdio_write(ioaddr, data[0], data[1], data[2]);
 #endif
 		return 0;
+
+	case SIOCDEVPRIVATE+5:		/* Change the debug level of the driver */
+		speedo_debug = *(int *)rq->ifr_data;
+		printk(KERN_DEBUG "%s: set debug level to [%d].\n",
+			   	dev->name, speedo_debug);
+		return 0;
+		
 	default:
 		return -EOPNOTSUPP;
 	}
@@ -2022,16 +2068,10 @@
 		config_cmd_data[4] = rxdmacount;
 		config_cmd_data[5] = txdmacount + 0x80;
 		config_cmd_data[15] |= (new_rx_mode & 2) ? 1 : 0;
-		if (sp->flow_ctrl) {
-			config_cmd_data[16] = 0x1f;
-			config_cmd_data[17] = 0x01;
-			config_cmd_data[19] = 0xb8;
-		}
-		else {
-			config_cmd_data[16] = 0;
-			config_cmd_data[17] = 0x40;
-			config_cmd_data[19] = 0x84;
-		}
+		/* 0x80 doesn't disable FC 0x84 does.
+		   Disable Flow control since we are not ACK-ing any FC interrupts
+		   for now. --Dragan */
+		config_cmd_data[19] = 0x84;
 		config_cmd_data[19] |= sp->full_duplex ? 0x40 : 0;
 		config_cmd_data[21] = (new_rx_mode & 1) ? 0x0D : 0x05;
 		if (sp->phy[0] & 0x8000) {			/* Use the AUI port instead. */
@@ -2212,6 +2252,7 @@
 		next_dev = sp->next_module;
 		if (sp->priv_addr)
 			kfree(sp->priv_addr);
+		kfree(sp->product_name);		
 		kfree(root_speedo_dev);
 		root_speedo_dev = next_dev;
 	}
Index: oldkernel/linux/drivers/net/plip.c
diff -u linux/drivers/net/plip.c:1.2 linux/drivers/net/plip.c:1.3
--- linux/drivers/net/plip.c:1.2	Thu Jun  1 15:38:25 2000
+++ linux/drivers/net/plip.c	Fri Jul  7 15:36:43 2000
@@ -1198,6 +1198,8 @@
 		pc->nibble  = nl->nibble;
 		break;
 	case PLIP_SET_TIMEOUT:
+		if(!capable(CAP_NET_ADMIN))
+			return -EPERM;
 		nl->trigger = pc->trigger;
 		nl->nibble  = pc->nibble;
 		break;
Index: oldkernel/linux/drivers/net/rcpci45.c
diff -u linux/drivers/net/rcpci45.c:1.1.1.1 linux/drivers/net/rcpci45.c:1.2
--- linux/drivers/net/rcpci45.c:1.1.1.1	Wed May 31 12:33:50 2000
+++ linux/drivers/net/rcpci45.c	Fri Jul  7 15:36:43 2000
@@ -1152,6 +1152,9 @@
     printk("RCioctl: cmd = 0x%x\n", cmd);
 #endif
  
+    if(!capable(CAP_NET_ADMIN))
+    	return -EPERM;
+    	
     switch (cmd)  {
  
     case RCU_PROTOCOL_REV:
@@ -1165,17 +1168,8 @@
 
     case RCU_COMMAND:
     {
-#ifdef LINUX_2_1
         if(copy_from_user(&RCuser, rq->ifr_data, sizeof(RCuser)))
              return -EFAULT;
-#else
-        int error;
-        error=verify_area(VERIFY_WRITE, rq->ifr_data, sizeof(RCuser));
-        if (error)  {
-            return error;
-        }
-        memcpy_fromfs(&RCuser, rq->ifr_data, sizeof(RCuser));
-#endif
         
 #ifdef RCDEBUG
         printk("RCioctl: RCuser_cmd = 0x%x\n", RCuser.cmd);
@@ -1284,11 +1278,8 @@
             RCUD_DEFAULT -> rc = 0x11223344;
             break;
         }
-#ifdef LINUX_2_1
-        copy_to_user(rq->ifr_data, &RCuser, sizeof(RCuser));
-#else
-        memcpy_tofs(rq->ifr_data, &RCuser, sizeof(RCuser));
-#endif
+        if(copy_to_user(rq->ifr_data, &RCuser, sizeof(RCuser)))
+        	return -EFAULT;
         break;
     }   /* RCU_COMMAND */ 
 
Index: oldkernel/linux/drivers/net/sbni.c
diff -u linux/drivers/net/sbni.c:1.1.1.1 linux/drivers/net/sbni.c:1.2
--- linux/drivers/net/sbni.c:1.1.1.1	Wed May 31 12:33:50 2000
+++ linux/drivers/net/sbni.c	Fri Jul  7 15:36:43 2000
@@ -1223,6 +1223,8 @@
 		}
 		case SIOCDEVRESINSTATS:
 		{
+			if(!capable(CAP_NET_ADMIN))
+				return -EPERM;
 			DP( printk("%s: SIOCDEVRESINSTATS\n",dev->name); )
 			lp->in_stats.all_rx_number = 0;
 			lp->in_stats.bad_rx_number = 0;
Index: oldkernel/linux/drivers/net/hamradio/baycom_epp.c
diff -u linux/drivers/net/hamradio/baycom_epp.c:1.1.1.1 linux/drivers/net/hamradio/baycom_epp.c:1.2
--- linux/drivers/net/hamradio/baycom_epp.c:1.1.1.1	Wed May 31 12:33:50 2000
+++ linux/drivers/net/hamradio/baycom_epp.c	Fri Jul  7 15:36:43 2000
@@ -1308,6 +1308,8 @@
 		break;		
 
 	case HDLCDRVCTL_CALIBRATE:
+		if (!suser())
+			return -EACCES;
 		bc->hdlctx.calibrate = hi.data.calibrate * bc->bitrate / 8;
 		return 0;
 
Index: oldkernel/linux/drivers/net/hamradio/hdlcdrv.c
diff -u linux/drivers/net/hamradio/hdlcdrv.c:1.1.1.1 linux/drivers/net/hamradio/hdlcdrv.c:1.2
--- linux/drivers/net/hamradio/hdlcdrv.c:1.1.1.1	Wed May 31 12:33:50 2000
+++ linux/drivers/net/hamradio/hdlcdrv.c	Fri Jul  7 15:36:43 2000
@@ -701,6 +701,8 @@
 		break;		
 
 	case HDLCDRVCTL_CALIBRATE:
+		if(!suser())
+			return -EPERM;
 		s->hdlctx.calibrate = bi.data.calibrate * s->par.bitrate / 16;
 		return 0;
 
Index: oldkernel/linux/drivers/pci/oldproc.c
diff -u linux/drivers/pci/oldproc.c:1.3 linux/drivers/pci/oldproc.c:1.4
--- linux/drivers/pci/oldproc.c:1.3	Thu Jun  1 14:11:18 2000
+++ linux/drivers/pci/oldproc.c	Fri Jul  7 15:36:43 2000
@@ -1,5 +1,5 @@
 /*
- *	$Id: oldproc.c,v 1.2 2000/05/31 21:56:52 ccr Exp $
+ *	$Id: oldproc.c,v 1.24 1998/10/11 15:13:04 mj Exp $
  *
  *	Backward-compatible procfs interface for PCI.
  *
@@ -224,9 +224,11 @@
 	DEVICE( X,		X_AGX016,	"ITT AGX016"),
 	DEVICE( PICOP,		PICOP_PT86C52X,	"PT86C52x Vesuvius"),
 	DEVICE( PICOP,		PICOP_PT80C524,	"PT80C524 Nile"),
-	DEVICE( MYLEX,		MYLEX_DAC960P_V2,"DAC960P V2"),
-	DEVICE( MYLEX,		MYLEX_DAC960P_V3,"DAC960P V3"),
-	DEVICE( MYLEX,		MYLEX_DAC960P_V4,"DAC960P V4"),
+	DEVICE( MYLEX,		MYLEX_DAC960_P, "DAC960 P Series"),
+	DEVICE( MYLEX,		MYLEX_DAC960_PD,"DAC960 PD Series"),
+	DEVICE( MYLEX,		MYLEX_DAC960_PG,"DAC960 PG Series"),
+	DEVICE( MYLEX,		MYLEX_DAC960_LP,"DAC960 LP Series"),
+	DEVICE( MYLEX,		MYLEX_DAC960_BA,"DAC960 BA Series"),
 	DEVICE( APPLE,		APPLE_BANDIT,	"Bandit"),
 	DEVICE( APPLE,		APPLE_GC,	"Grand Central"),
 	DEVICE( APPLE,		APPLE_HYDRA,	"Hydra"),
@@ -518,6 +520,7 @@
 	DEVICE( INTEL,		INTEL_82430,	"82430ZX Aries"),
 	DEVICE( INTEL,		INTEL_82434,	"82434LX Mercury/Neptune"),
 	DEVICE( INTEL,		INTEL_I960,	"i960"),
+	DEVICE( INTEL,		INTEL_I960RN,	"i960 RN"),
 	DEVICE( INTEL,		INTEL_82092AA_0,"82092AA PCMCIA bridge"),
 	DEVICE( INTEL,		INTEL_82092AA_1,"82092AA EIDE"),
 	DEVICE( INTEL,		INTEL_7116,	"SAA7116"),
Index: oldkernel/linux/drivers/pci/pci.c
diff -u linux/drivers/pci/pci.c:1.2 linux/drivers/pci/pci.c:1.3
--- linux/drivers/pci/pci.c:1.2	Thu Jun  1 14:11:18 2000
+++ linux/drivers/pci/pci.c	Fri Jul  7 15:36:43 2000
@@ -1,5 +1,5 @@
 /*
- *	$Id: pci.c,v 1.1.1.1 2000/05/31 19:33:52 ccr Exp $
+ *	$Id: pci.c,v 1.91 1999/01/21 13:34:01 davem Exp $
  *
  *	PCI Bus Services, see include/linux/pci.h for further explanation.
  *
Index: oldkernel/linux/drivers/sbus/char/sab82532.c
diff -u linux/drivers/sbus/char/sab82532.c:1.1.1.1 linux/drivers/sbus/char/sab82532.c:1.2
--- linux/drivers/sbus/char/sab82532.c:1.1.1.1	Wed May 31 12:33:52 2000
+++ linux/drivers/sbus/char/sab82532.c	Fri Jul  7 15:36:43 2000
@@ -2063,7 +2063,7 @@
 done:
 	if (off >= len+begin)
 		return 0;
-	*start = page + (begin-off);
+	*start = page + (off-begin);
 	return ((count < begin+len-off) ? count : begin+len-off);
 }
 
Index: oldkernel/linux/drivers/sbus/char/su.c
diff -u linux/drivers/sbus/char/su.c:1.1.1.1 linux/drivers/sbus/char/su.c:1.2
--- linux/drivers/sbus/char/su.c:1.1.1.1	Wed May 31 12:33:52 2000
+++ linux/drivers/sbus/char/su.c	Fri Jul  7 15:36:43 2000
@@ -2205,7 +2205,7 @@
 done:
 	if (off >= len+begin)
 		return 0;
-	*start = page + (begin-off);
+	*start = page + (off-begin);
 	return ((count < begin+len-off) ? count : begin+len-off);
 }
 
Index: oldkernel/linux/drivers/sbus/char/sunkbd.c
diff -u linux/drivers/sbus/char/sunkbd.c:1.2 linux/drivers/sbus/char/sunkbd.c:1.3
--- linux/drivers/sbus/char/sunkbd.c:1.2	Thu Jun  1 15:08:24 2000
+++ linux/drivers/sbus/char/sunkbd.c	Fri Jul  7 15:36:43 2000
@@ -550,7 +550,7 @@
 
 #ifdef CONFIG_MAGIC_SYSRQ			/* Handle the SysRq hack */
 	if (l1a_state.l1_down) {
-		if (!up_flag)
+		if (!up_flag && sysrq_enabled)
 			handle_sysrq(sun_sysrq_xlate[keycode], pt_regs, kbd, tty);
 		goto out;
 	}
Index: oldkernel/linux/drivers/scsi/ChangeLog.ncr53c8xx
diff -u linux/drivers/scsi/ChangeLog.ncr53c8xx:1.1.1.1 linux/drivers/scsi/ChangeLog.ncr53c8xx:1.2
--- linux/drivers/scsi/ChangeLog.ncr53c8xx:1.1.1.1	Wed May 31 12:33:51 2000
+++ linux/drivers/scsi/ChangeLog.ncr53c8xx	Fri Jul  7 15:36:43 2000
@@ -1,12 +1,34 @@
-Wed Jul 21 1999 23:00 Gerard Roudier (groudier@club-internet.fr)
-	* revision 3.2a-2
-	- merge of driver 3.2a-1 with linux-2.3.11-pre3
+Tue Jan 11 14:00 2000 Pam Delaney (pam.delaney@lsil.com)
+	* revision 3.31
+	- Added support for mounting disks on wide-narrow-wide
+	  scsi configurations. 
 
-Sun May 9  15:00 1999 Gerard Roudier (groudier@club-internet.fr)
-	* revision 3.2a-1
-	- Fix the misdetection of SYM53C875E (was detected as a 876).
-	- Set the actual host ID used for each host in the scsi host data 
-	  structure. The mid-layer SCSI driver needs this information.
+Mon Jan 10 13:30 2000 Pam Delaney (pam.delaney@lsil.com)
+	* revision 3.30
+	- Added capability to use the integrity checking code
+	  in the kernel (optional).
+	- Disabled support for the 53C1010.
+
+Sat Sep 11  18:00 1999 Gerard Roudier (groudier@club-internet.fr)
+	* revision 3.2c
+	- Handle correctly (hopefully) jiffies wrap-around.
+	- Restore the entry used to detect 875 until revision 0xff.
+	  (I removed it inadvertently, it seems :) )
+	- Replace __initfunc() which is deprecated stuff by __init which 
+	  is not yet so. ;-)
+	- Add support of some 'resource handling' for linux-2.3.13.
+	  Basically the BARs have been changed to something more complex 
+	  in the pci_dev structure.
+	- Remove some deprecated code.
+
+Sat May 10  11:00 1999 Gerard Roudier (groudier@club-internet.fr)
+	* revision pre-3.2b-1
+	- Support for the 53C895A by Pamela Delaney <pam.delaney@lsil.com>
+	  The 53C895A contains all of the features of the 896 but has only 
+	  one channel and has a 32 bit PCI bus. It does 64 bit PCI addressing 
+	  using dual cycle PCI data transfers.
+	- Miscellaneous minor fixes.
+	- Some additions to the README.ncr53c8xx file.
 
 Sun Apr 11  10:00 1999 Gerard Roudier (groudier@club-internet.fr)
 	* revision 3.2a
Index: oldkernel/linux/drivers/scsi/ChangeLog.sym53c8xx
diff -u linux/drivers/scsi/ChangeLog.sym53c8xx:1.1.1.1 linux/drivers/scsi/ChangeLog.sym53c8xx:1.2
--- linux/drivers/scsi/ChangeLog.sym53c8xx:1.1.1.1	Wed May 31 12:33:52 2000
+++ linux/drivers/scsi/ChangeLog.sym53c8xx	Fri Jul  7 15:36:43 2000
@@ -1,23 +1,140 @@
-Sat Jul 24  12:00 1999 Gerard Roudier (groudier@club-internet.fr)
-	* version sym53c8xx-1.3g
-	- merge of driver 1.3f with linux-2.2.11-pre3
-	- remove the broken testing of the chip being connected to SCSI 
-	  from the SCSI interrupt handling code.   
+Tue Jan 11 14:00 2000 Pam Delaney (pam.delaney@lsil.com)
+ 	* version sym53c8xx-1.61
+	- Added support for mounting disks on wide-narrow-wide
+	  scsi configurations. 
+	- Modified offset to be a maximum of 31 in ST mode, 
+	  62 in DT mode.
 
-Sun May 9  15:00 1999 Gerard Roudier (groudier@club-internet.fr)
-	* version sym53c8xx-1.3f
+Mon Jan 10 10:00 2000 Pam Delaney (pam.delaney@lsil.com)
+ 	* version sym53c8xx-1.60
+ 	- Added capability to use the integrity checking code
+ 	  in the kernel (optional).
+ 	- Added PPR negotiation.
+ 	- Added support for 53C1010 Ultra 3 part.
+ 
+Sun Oct  3  19:00 1999 Gerard Roudier (groudier@club-internet.fr)
+	* version sym53c8xx-1.5f
+	- Change the way the driver checks the PCI clock frequency, so 
+	  that overclocked PCI BUS up to 48 MHz will not be refused.
+	  The more the BUS is overclocked, the less the driver will 
+	  guarantee that its measure of the SCSI clock is correct.
+	- Backport some minor improvements of SCRIPTS from the sym_hipd 
+	  driver.
+	- Backport the code rewrite of the START QUEUE dequeuing (on 
+	  bad scsi status received) from the sym_hipd driver.
+
+Sat Sep 11  11:00 1999 Gerard Roudier (groudier@club-internet.fr)
+	* version sym53c8xx-1.5e
+	- New linux-2.3.13 __setup scheme support added.
+	- Cleanup of the extended error status handling:
+	  Use 1 bit per error type.
+	- Also save the extended error status prior to auto-sense.
+	- Add the FE_DIFF chip feature bit to indicate support of 
+	  diff probing from GPIO3 (825/825A/876/875).
+	- Remove the quirk handling that has been useless since day one.
+	- Work-around PCI chips being reported twice on some platforms.
+	- Add some redundant PCI reads in order to deal with common 
+	  bridge misbehaviour regarding posted write flushing.
+	- Add some other conditionnal code for people who have to deal 
+	  with really broken bridges (they will have to edit a source 
+	  file to try these options).
+	- Handle correctly (hopefully) jiffies wrap-around.
+	- Restore the entry used to detect 875 until revision 0xff.
+	  (I removed it inadvertently, it seems :) )
+	- Replace __initfunc() which is deprecated stuff by __init which 
+	  is not yet so. ;-)
+	- Rewrite the MESSAGE IN scripts more generic by using a MOVE 
+	  table indirect. Extended messages of any size are accepted now.
+	  (Size is limited to 8 for now, but a constant is just to be 
+	  increased if necessary)
+	- Fix some bug in the fully untested MDP handling:) and share 
+	  some code between MDP handling and residual calculation.
+	- Calculate the data transfer residual as the 2's complement 
+	  integer (A positive value in returned on data overrun, and 
+	  a negative one on underrun).
+	- Add support of some 'resource handling' for linux-2.3.13.
+	  Basically the BARs have been changed to something more complex 
+	  in the pci_dev structure.
+	- Remove some deprecated code.
+
+Sat Jun  5  11:00 1999 Gerard Roudier (groudier@club-internet.fr)
+	* version sym53c8xx-1.5c
+	- Donnot negotiate on auto-sense if we are currently using 8 bit 
+	  async transfer for the target.
+	- Only check for SISL/RAID on i386 platforms.
+	  (A problem has been reported on PPC with that code).
+	- On MSG REJECT for a negotiation, the driver attempted to restart 
+	  the SCRIPT processor when this one was already running.
+
+Sat May 29  12:00 1999 Gerard Roudier (groudier@club-internet.fr)
+	* version sym53c8xx-1.5b
+	- Force negotiation prior auto-sense.
+	  This ensures that the driver will be able to grab the sense data 
+	  from a device that has received a BUS DEVICE RESET message from 
+	  another initiator.
+	- Complete all disconnected CCBs for a logical UNIT if we are told 
+	  about a UNIT ATTENTION for a RESET condition by this target.
+	- Add the control command 'cleardev' that allows to send a ABORT  
+	  message to a logical UNIT (for test purpose).
+
+Tue May 25  23:00 1999 Gerard Roudier (groudier@club-internet.fr)
+	* version sym53c8xx-1.5a
+	- Add support for task abort and bus device reset SCSI message 
+	  and implement proper synchonisation with SCRIPTS to handle 
+          correctly task abortion without races.
+	- Send an ABORT message (if untagged) or ABORT TAG message (if tagged)
+	  when the driver is told to abort a command that is disconnected and 
+	  complete the command with appropriate error.
+	  If the aborted command is not yet started, remove it from the start 
+	  queue and complete it with error.
+	- Add the control command 'resetdev' that allows to send a BUS 
+	  DEVICE RESET message to a target (for test purpose).
+	- Clean-up some unused or useless code.
+
+Fri May 21  23:00 1999 Gerard Roudier (groudier@club-internet.fr)
+	* version sym53c8xx-1.5
+	- Add support for CHMOV with Wide controllers.
+	- Handling of the SWIDE (low byte residue at the end of a CHMOV 
+	  in DATA IN phase with WIDE transfer when the byte count gets odd).
+	- Handling of the IGNORE WIDE RESIDUE message.
+	  Handled from SCRIPTS as possible with some optimizations when both 
+	  a wide device and the controller are odd at the same time (SWIDE 
+	  present and IGNORE WIDE RESIDUE message on the BUS at the same time).
+	- Check against data OVERRUN/UNDERRUN condition at the end of a data 
+	  transfer, whatever a SWIDE is present (OVERRUN in DATA IN phase) 
+	  or the SODL is full (UNDERRUN in DATA out phase).
+	- Handling of the MODIFY DATA POINTER message.
+	  This one cannot be handled from SCRIPTS, but hopefully it will not
+	  happen very often. :)
+	- Large rewrite of the SCSI MESSAGE handling.
+
+Sun May 9  11:00 1999 Gerard Roudier (groudier@club-internet.fr)
+	* version sym53c8xx-1.4
+	- Support for IMMEDIATE ARBITRATION.
+	  See the README file for detailed information about this feature.
+	  Requires both a compile option and a boot option.
+	- Minor SCRIPTS optimization in reselection pattern for LUN 0.
+	- Simpler algorithm to deal with SCSI command starvation.
+	  Just use 2 tag counters in flip/flop and switch to the other 
+	  one every 3 seconds.
+	- Do some work in SCRIPTS after the SELECT instruction and prior 
+	  to testing for a PHASE. SYMBIOS say this feature is working fine. 
+	  (Btw, only problems with Toshiba 3401B had been reported).
+	- Measure the PCI clock speed and donnot attach controllers if 
+	  result is greater than 37 MHz. Since the precision of the 
+	  algorithm (from Stefan Esser) is better than 2%, this should 
+	  be fine.
 	- Fix the misdetection of SYM53C875E (was detected as a 876).
 	- Fix the misdetection of SYM53C810 not A (was detected as a 810A).
+	- Support for up to 256 TAGS per LUN (CMD_PER_LUN).
+	  Currently limited to 255 due to Linux limitation. :)
+	- Support for up to 508 active commands (CAN_QUEUE).
 	- Support for the 53C895A by Pamela Delaney <pam.delaney@lsil.com>
 	  The 53C895A contains all of the features of the 896 but has only 
 	  one channel and has a 32 bit PCI bus. It does 64 bit PCI addressing 
 	  using dual cycle PCI data transfers.
-	- Call request_region() event if MMIO is used and not normal IO.
-	  This allows sym and the ncr driver to be loaded in any order 
-	  without any risk of attaching the same device.
-	- Set the actual host ID used for each host in the scsi host data 
-	  structure. The mid-layer SCSI driver needs this information.
 	- Miscellaneous minor fixes.
+	- Some additions to the README.ncr53c8xx file.
 
 Tue Apr 15  10:00 1999 Gerard Roudier (groudier@club-internet.fr)
 	* version sym53c8xx-1.3e
Index: oldkernel/linux/drivers/scsi/Config.in
diff -u linux/drivers/scsi/Config.in:1.1.1.1 linux/drivers/scsi/Config.in:1.2
--- linux/drivers/scsi/Config.in:1.1.1.1	Wed May 31 12:33:51 2000
+++ linux/drivers/scsi/Config.in	Fri Jul  7 15:36:43 2000
@@ -95,11 +95,13 @@
     bool '  use normal IO' CONFIG_SCSI_NCR53C8XX_IOMAPPED
     if [ "$CONFIG_SCSI_SYM53C8XX" != "n" ]; then
       bool '  include support for the NCR PQS/PDS SCSI card' CONFIG_SCSI_NCR53C8XX_PQS_PDS
+      bool '  enable immediate arbitration' CONFIG_SCSI_NCR53C8XX_IARB
     fi
     if [ "$CONFIG_SCSI_NCR53C8XX_DEFAULT_TAGS" = "0" ]; then
       bool '  not allow targets to disconnect' CONFIG_SCSI_NCR53C8XX_NO_DISCONNECT
     fi
     if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
+      bool '  perform integrity check' CONFIG_SCSI_NCR53C8XX_INTEGRITY_CHECK
       bool '  assume boards are SYMBIOS compatible' CONFIG_SCSI_NCR53C8XX_SYMBIOS_COMPAT
     fi
   fi
Index: oldkernel/linux/drivers/scsi/README.ncr53c8xx
diff -u linux/drivers/scsi/README.ncr53c8xx:1.1.1.1 linux/drivers/scsi/README.ncr53c8xx:1.2
--- linux/drivers/scsi/README.ncr53c8xx:1.1.1.1	Wed May 31 12:33:51 2000
+++ linux/drivers/scsi/README.ncr53c8xx	Fri Jul  7 15:36:43 2000
@@ -1,10 +1,10 @@
-The Linux NCR53C8XX driver README file
+The Linux NCR53C8XX/SYM53C8XX drivers README file
 
 Written by Gerard Roudier <groudier@club-internet.fr>
 21 Rue Carnot
 95170 DEUIL LA BARRE - FRANCE
 
-9 May 1999
+29 May 1999
 ===============================================================================
 
 1.  Introduction
@@ -25,14 +25,39 @@
       8.6  Clear profile counters
       8.7  Set flag (no_disc)
       8.8  Set verbose level
+      8.9  Reset all logical units of a target
+      8.10 Abort all tasks of all logical units of a target
 9.  Configuration parameters
 10. Boot setup commands
       10.1 Syntax
       10.2 Available arguments
+             10.2.1  Master parity checking
+             10.2.2  Scsi parity checking
+             10.2.3  Scsi disconnections
+             10.2.4  Special features
+             10.2.5  Ultra SCSI support
+             10.2.6  Default number of tagged commands
+             10.2.7  Default synchronous period factor
+             10.2.8  Negotiate synchronous with all devices
+             10.2.9  Verbosity level
+             10.2.10 Debug mode
+             10.2.11 Burst max
+             10.2.12 LED support
+             10.2.13 Max wide
+             10.2.14 Differential mode
+             10.2.15 IRQ mode
+             10.2.16 Reverse probe
+             10.2.17 Fix up PCI configuration space
+             10.2.18 Serial NVRAM
+             10.2.19 Check SCSI BUS 
+             10.2.20 Exclude a host from being attached
+             10.2.21 Suggest a default SCSI id for hosts
+             10.2.22 Enable use of IMMEDIATE ARBITRATION
       10.3 Advised boot setup commands
       10.4 PCI configuration fix-up boot option
       10.5 Serial NVRAM support boot option
       10.6 SCSI BUS checking boot option
+      10.7 IMMEDIATE ARBITRATION boot option
 11. Some constants and flags of the ncr53c8xx.h header file
 12. Installation
 13. Architecture dependent features
@@ -43,6 +68,8 @@
       14.4 Possible data corruption during a Memory Write and Invalidate
       14.5 IRQ sharing problems
 15. SCSI problem troubleshooting
+      15.1 Problem tracking
+      15.2 Understanding hardware error reports
 16. Synchonous transfer negotiation tables
       16.1 Synchronous timings for 53C875 and 53C860 Ultra-SCSI controllers
       16.2 Synchronous timings for fast SCSI-2 53C8XX controllers
@@ -69,11 +96,12 @@
 It is now available as a bundle of 2 drivers:
 
 - ncr53c8xx generic driver that supports all the SYM53C8XX family including 
-  the ealiest 810 rev. 1 and the latest 896 2 channels LVD SCSI controller.
+  the ealiest 810 rev. 1, the latest 896 (2 channel LVD SCSI controller) and
+  the new 895A (1 channel LVD SCSI controller).
 - sym53c8xx enhanced driver (a.k.a. 896 drivers) that drops support of oldest 
   chips in order to gain advantage of new features, as LOAD/STORE intructions 
   available since the 810A and hardware phase mismatch available with the 
-  latest 896.
+  896 and the 895A.
 
 You can find technical information about the NCR 8xx family in the
 PCI-HOWTO written by Michael Will and in the SCSI-HOWTO written by
@@ -95,15 +123,17 @@
 These tools are not ALPHA but quite clean and work quite well.
 It is essential you have the 'scsiinfo' package.
 
-This short documentation only describes the features of the NCR53C8XX
-driver, configuration parameters and control commands available
-through the proc SCSI file system read / write operations.
+This short documentation describes the features of the generic and enhanced
+drivers, configuration parameters and control commands available through 
+the proc SCSI file system read / write operations.
 
 This driver has been tested OK with linux/i386, Linux/Alpha and Linux/PPC.
 
 Latest driver version and patches are available at:
 
           ftp://ftp.tux.org/pub/people/gerard-roudier
+or
+          ftp://ftp.symbios.com/mirror/ftp.tux.org/pub/tux/roudier/drivers
 
 I am not a native speaker of English and there are probably lots of
 mistakes in this README file. Any help will be welcome.
@@ -136,6 +166,7 @@
 875        Y         Y      FAST20    40 MB/s        Y             Y
 876        Y         Y      FAST20    40 MB/s        Y             Y
 895        Y         Y      FAST40    80 MB/s        Y             Y
+895A       Y         Y      FAST40    80 MB/s        Y             Y
 896        Y         Y      FAST40    80 MB/s        Y             Y
 
 
@@ -156,21 +187,25 @@
 
 3.1 Optimized SCSI SCRIPTS.
 
-The 810A, 825A, 875, 895 and newest 896 support new SCSI SCRIPTS instructions 
-named LOAD and STORE that allow to move 1 DWORD from/to an IO register to/from 
-memory much faster that the MOVE MEMORY instruction that is supported by the 
-53c7xx and 53c8xx family. The LOAD/STORE instructions support absolute and 
-DSA relative addressing modes. The SCSI SCRIPTS had been entirely rewritten 
-using LOAD/STORE instead of MOVE MEMORY instructions.
+The 810A, 825A, 875, 895, 896 and 895A support new SCSI SCRIPTS instructions 
+named LOAD and STORE that allow to move up to 1 DWORD from/to an IO register 
+to/from memory much faster that the MOVE MEMORY instruction that is supported 
+by the 53c7xx and 53c8xx family.
+The LOAD/STORE instructions support absolute and DSA relative addressing 
+modes.  The SCSI SCRIPTS had been entirely rewritten using LOAD/STORE instead 
+of MOVE MEMORY instructions.
 
 3.2 New features of the SYM53C896 (64 bit PCI dual LVD SCSI controller)
 
-The 896 allows to handle the phase mismatch context saving from SCRIPTS 
-(avoids the phase mismatch interrupt that stops the SCSI processor 
+The 896 and the 895A allows handling of the phase mismatch context from 
+SCRIPTS (avoids the phase mismatch interrupt that stops the SCSI processor 
 until the C code has saved the context of the transfer).
 Implementing this without using LOAD/STORE instructions would be painfull 
-and I did'nt even try it. This chip also supports 64 bit PCI transactions 
-and addressing. The SCRIPTS processor is not true 64 bit, but uses segment 
+and I did'nt even want to try it.
+
+The 896 chip supports 64 bit PCI transactions and addressing, while the 
+895A supports 32 bit PCI transactions and 64 bit addressing.
+The SCRIPTS processor of these chips is not true 64 bit, but uses segment 
 registers for bit 32-63. Another interesting feature is that LOAD/STORE 
 instructions that address the on-chip RAM (8k) remain internal to the chip.
 
@@ -219,9 +254,13 @@
 is currently set to 8 by default.  This value is suitable for most SCSI
 disks.  With large SCSI disks (>= 2GB, cache >= 512KB, average seek time
 <= 10 ms), using a larger value may give better performances.
-The driver supports up to 64 commands per device, but using more than 
-32 is generally not worth it, unless you are using a very large disk 
-or disk array.
+
+The sym53c8xx driver supports up to 255 commands per device, and the 
+generic ncr53c8xx driver supports up to 64, but using more than 32 is 
+generally not worth-while, unless you are using a very large disk or disk 
+array. It is noticeable that most of recent hard disks seem not to accept 
+more than 64 simultaneous commands. So, using more than 64 queued commands 
+is probably just resource wasting.
 
 If your controller does not have NVRAM or if it is managed by the SDMS 
 BIOS/SETUP, you can configure tagged queueing feature and device queue 
@@ -491,6 +530,24 @@
     The driver default verbose level is 1. This command allows to change 
     th driver verbose level after boot-up.
 
+8.9 Reset all logical units of a target
+
+    resetdev <target>
+
+    target:    target number
+    The driver will try to send a BUS DEVICE RESET message to the target.
+    (Only supported by the SYM53C8XX driver and provided for test purpose)
+
+8.10 Abort all tasks of all logical units of a target
+
+    cleardev <target>
+
+    target:    target number
+    The driver will try to send a ABORT message to all the logical units 
+    of the target.
+    (Only supported by the SYM53C8XX driver and provided for test purpose)
+
+
 9. Configuration parameters
 
 If the firmware of all your devices is perfect enough, all the
@@ -566,10 +623,11 @@
 Setup commands can be passed to the driver either at boot time or as a 
 string variable using 'insmod'.
 
-A boot setup command for the ncr53c8xx driver begins with the driver name 
-"ncr53c8xx=". The kernel syntax parser then expects an optionnal list of
-integers separated with comma followed by an optionnal list of  comma- 
-separated strings. Example of boot setup command under lilo prompt:
+A boot setup command for the ncr53c8xx (sym53c8xx) driver begins with the 
+driver name "ncr53c8xx="(sym53c8xx). The kernel syntax parser then expects 
+an optionnal list of integers separated with comma followed by an optional 
+list of  comma-separated strings. Example of boot setup command under lilo 
+prompt:
 
 lilo: linux root=/dev/hda2 ncr53c8xx=tags:4,sync:10,debug:0x200
 
@@ -582,7 +640,7 @@
 The following command will install driver module with the same options as 
 above.
 
-insmod ncr53c8xx.o ncr53c8xx="tags:4 sync:10 debug:0x200"
+    insmod ncr53c8xx.o ncr53c8xx="tags:4 sync:10 debug:0x200"
 
 For the moment, the integer list of arguments is discarded by the driver. 
 It will be used in the future in order to allow a per controller setup.
@@ -590,40 +648,53 @@
 Each string argument must be specified as "keyword:value". Only lower-case 
 characters and digits are allowed.
 
+In a system that contains multiple 53C8xx adapters insmod will install the 
+specified driver on each adapter. To exclude a chip use the 'excl' keyword.
+
+The sequence of commands, 
+
+    insmod sym53c8xx sym53c8xx=excl:0x1400
+    insmod ncr53c8xx
+
+installs the sym53c8xx driver on all adapters except the one at IO port 
+address 0x1400 and then installs the ncr53c8xx driver to the adapter at IO 
+port address 0x1400.
+
+
 10.2 Available arguments
 
-Master parity checking
-      mpar:y     enabled
-      mpar:n     disabled
-
-Scsi parity checking
-      spar:y     enabled
-      spar:n     disabled
-
-Scsi disconnections
-      disc:y     enabled
-      disc:n     disabled
+10.2.1  Master parity checking
+        mpar:y     enabled
+        mpar:n     disabled
+
+10.2.2  Scsi parity checking
+        spar:y     enabled
+        spar:n     disabled
+
+10.2.3  Scsi disconnections
+        disc:y     enabled
+        disc:n     disabled
  
-Special features
+10.2.4  Special features
    Only apply to 810A, 825A, 860, 875 and 895 controllers.
    Have no effect with other ones.
-      specf:y    (or 1) enabled
-      specf:n    (or 0) disabled
-      specf:3           enabled except Memory Write And Invalidate
+        specf:y    (or 1) enabled
+        specf:n    (or 0) disabled
+        specf:3           enabled except Memory Write And Invalidate
    The default driver setup is 'specf:3'. As a consequence, option 'specf:y' 
    must be specified in the boot setup command to enable Memory Write And 
    Invalidate.
 
-Ultra SCSI support
+10.2.5  Ultra SCSI support
    Only apply to 860, 875 and 895 controllers.
    Have no effect with other ones.
-      ultra:2    Ultra2 enabled
-      ultra:1    Ultra enabled
-      ultra:n    disabled
-
-Default number of tagged commands
-      tags:0     (or tags:1 ) tagged command queuing disabled
-      tags:#tags (#tags  > 1) tagged command queuing enabled
+        ultra:2    Ultra2 enabled
+        ultra:1    Ultra enabled
+        ultra:n    disabled
+
+10.2.6  Default number of tagged commands
+        tags:0     (or tags:1 ) tagged command queuing disabled
+        tags:#tags (#tags  > 1) tagged command queuing enabled
   #tags will be truncated to the max queued commands configuration parameter.
   This option also allows to specify a command queue depth for each device 
   that support tagged command queueing.
@@ -635,9 +706,9 @@
       - controller #1 target #1 logical unit #2                -> 32 commands,
       - all other logical units (all targets, all controllers) -> 10 commands.
 
-Default synchronous period factor
-      sync:255     disabled (asynchronous transfer mode)
-      sync:#factor
+10.2.7  Default synchronous period factor
+        sync:255     disabled (asynchronous transfer mode)
+        sync:#factor
   #factor = 10     Ultra-2 SCSI 40 Mega-transfers / second
   #factor = 11     Ultra-2 SCSI 33 Mega-transfers / second
   #factor < 25     Ultra   SCSI 20 Mega-transfers / second
@@ -646,19 +717,19 @@
   In all cases, the driver will use the minimum transfer period supported by 
   controllers according to NCR53C8XX chip type.
 
-Negotiate synchronous with all devices
-  (force sync nego)
-      fsn:y      enabled
-      fsn:n      disabled
-
-Verbosity level
-      verb:0     minimal
-      verb:1     normal
-      verb:2     too much
-
-Debug mode
-      debug:0	 clear debug flags
-      debug:#x   set debug flags
+10.2.8  Negotiate synchronous with all devices
+        (force sync nego)
+        fsn:y      enabled
+        fsn:n      disabled
+
+10.2.9  Verbosity level
+        verb:0     minimal
+        verb:1     normal
+        verb:2     too much
+
+10.2.10 Debug mode
+        debug:0	 clear debug flags
+        debug:#x   set debug flags
   #x is an integer value combining the following power-of-2 values:
   DEBUG_ALLOC       0x1
   DEBUG_PHASE       0x2
@@ -677,10 +748,10 @@
   You can play safely with DEBUG_NEGO. However, some of these flags may 
   generate bunches of syslog messages. 
 
-Burst max
-      burst:0    burst disabled
-      burst:255  get burst length from initial IO register settings.
-      burst:#x   burst enabled (1<<#x burst transfers max)
+10.2.11 Burst max
+        burst:0    burst disabled
+        burst:255  get burst length from initial IO register settings.
+        burst:#x   burst enabled (1<<#x burst transfers max)
   #x is an integer value which is log base 2 of the burst transfers max.
   The NCR53C875 and NCR53C825A support up to 128 burst transfers (#x = 7).
   Other chips only support up to 16 (#x = 4).
@@ -688,42 +759,42 @@
   and revision ids. By default the driver uses the maximum value supported 
   by the chip.
 
-LED support
-     led:1      enable  LED support
-     led:0      disable LED support
+10.2.12 LED support
+        led:1      enable  LED support
+        led:0      disable LED support
   Donnot enable LED support if your scsi board does not use SDMS BIOS.
   (See 'Configuration parameters')
 
-Max wide
-    wide:1      wide scsi enabled
-    wide:0      wide scsi disabled
+10.2.13 Max wide
+        wide:1      wide scsi enabled
+        wide:0      wide scsi disabled
   Some scsi boards use a 875 (ultra wide) and only supply narrow connectors.
   If you have connected a wide device with a 50 pins to 68 pins cable 
   converter, any accepted wide negotiation will break further data transfers.
   In such a case, using "wide:0" in the bootup command will be helpfull. 
 
-Differential mode
-    diff:0	never set up diff mode
-    diff:1	set up diff mode if BIOS set it
-    diff:2	always set up diff mode
-    diff:3	set diff mode if GPIO3 is not set
-
-IRQ mode
-    irqm:0	always open drain
-    irqm:1	same as initial settings (assumed BIOS settings)
-    irqm:2	always totem pole
-    irqm:0x10	driver will not use SA_SHIRQ flag when requesting irq
-    irqm:0x20	driver will not use SA_INTERRUPT flag when requesting irq
+10.2.14 Differential mode
+        diff:0	never set up diff mode
+        diff:1	set up diff mode if BIOS set it
+        diff:2	always set up diff mode
+        diff:3	set diff mode if GPIO3 is not set
+
+10.2.15 IRQ mode
+        irqm:0     always open drain
+        irqm:1     same as initial settings (assumed BIOS settings)
+        irqm:2     always totem pole
+        irqm:0x10  driver will not use SA_SHIRQ flag when requesting irq
+        irqm:0x20  driver will not use SA_INTERRUPT flag when requesting irq
 
     (Bits 0x10 and 0x20 can be combined with hardware irq mode option)
 
-Reverse probe
-    revprob:n   probe chip ids from the PCI configuration in this order:
-                810, 815, 820, 860, 875, 885, 895, 896
-    revprob:y   probe chip ids in the reverse order.
+10.2.16 Reverse probe
+        revprob:n   probe chip ids from the PCI configuration in this order:
+                    810, 815, 820, 860, 875, 885, 895, 896
+        revprob:y   probe chip ids in the reverse order.
 
-Fix up PCI configuration space
-    pcifix:<option bits>
+10.2.17 Fix up PCI configuration space
+        pcifix:<option bits>
 
     Available option bits:
         0x0:   No attempt to fix PCI configuration space registers values.
@@ -733,35 +804,36 @@
 
     Use 'pcifix:7' in order to allow the driver to fix up all PCI features.
 
-Serial NVRAM
-    nvram:n     do not look for serial NVRAM
-    nvram:y     test controllers for onboard serial NVRAM
-    (alternate binary form)
-    mvram=<bits options>
-      0x01   look for NVRAM  (equivalent to nvram=y)
-      0x02   ignore NVRAM "Synchronous negotiation" parameters for all devices
-      0x04   ignore NVRAM "Wide negotiation"  parameter for all devices
-      0x08   ignore NVRAM "Scan at boot time" parameter for all devices
-      0x80   also attach controllers set to OFF in the NVRAM (sym53c8xx only)
+10.2.18 Serial NVRAM
+        nvram:n     do not look for serial NVRAM
+        nvram:y     test controllers for onboard serial NVRAM
+        (alternate binary form)
+        mvram=<bits options>
+        0x01   look for NVRAM  (equivalent to nvram=y)
+        0x02   ignore NVRAM "Synchronous negotiation" parameters for all devices
+        0x04   ignore NVRAM "Wide negotiation"  parameter for all devices
+        0x08   ignore NVRAM "Scan at boot time" parameter for all devices
+        0x80   also attach controllers set to OFF in the NVRAM (sym53c8xx only)
 
-Check SCSI BUS 
-    buschk:<option bits>
+10.2.19 Check SCSI BUS 
+        buschk:<option bits>
 
     Available option bits:
         0x0:   No check.
         0x1:   Check and donnot attach the controller on error.  
         0x2:   Check and just warn on error.
+        0x4:   Disable SCSI bus integrity checking.
 
-Exclude a host from being attached
-    excl=<io_address>
+10.2.20 Exclude a host from being attached
+        excl=<io_address>
 
     Prevent host at a given io address from being attached.
-    For example 'ncr53c8xx=excl:0xb400,excl:0xc000' indicates to the 
+    For example 'ncr53c8xx=excl:0xb400,excl:0xc000' indicate to the 
     ncr53c8xx driver not to attach hosts at address 0xb400 and 0xc000.
 
-Suggest a default SCSI id for hosts
-    hostid:255	no id suggested.
-    hostid:#x   (0 < x < 7) x suggested for hosts SCSI id.
+10.2.21 Suggest a default SCSI id for hosts
+        hostid:255	no id suggested.
+        hostid:#x   (0 < x < 7) x suggested for hosts SCSI id.
 
     If a host SCSI id is available from the NVRAM, the driver will ignore 
     any value suggested as boot option. Otherwise, if a suggested value 
@@ -769,6 +841,16 @@
     try to deduce the value previously set in the hardware and use value 
     7 if the hardware value is zero.
 
+10.2.22 Enable use of IMMEDIATE ARBITRATION
+        (only supported by the sym53c8xx driver. See 10.7 for more details)
+        iarb:0    donnot use this feature.
+        iarb:#x   use this feature according to bit fields as follow:
+
+    bit 0 (1) : enable IARB each time the initiator has been reselected 
+                when it arbitrated for the SCSI BUS.
+    (#x >> 4) : maximum number of successive settings of IARB if the initiator 
+                win arbitration and it has other commands to send to a device.
+
 Boot fail safe
     safe:y	load the following assumed fail safe initial setup
 
@@ -792,6 +874,7 @@
   differential support		from BIOS settings	diff:1
   irq mode			from BIOS settings	irqm:1
   SCSI BUS check		donnot attach on error	buschk:1
+  immediate arbitration		disabled		iarb:0
 
 10.3 Advised boot setup commands
 
@@ -920,6 +1003,45 @@
 On the other hand, either bad cabling, broken devices, not conformant 
 devices, ... may cause a SCSI signal to be wrong when te driver reads it.
 
+10.7 IMMEDIATE ARBITRATION boot option
+
+This option is only supported by the SYM53C8XX driver (not by the NCR53C8XX).
+
+SYMBIOS 53C8XX chips are able to arbitrate for the SCSI BUS as soon as they 
+have detected an expected disconnection (BUS FREE PHASE). For this process 
+to be started, bit 1 of SCNTL1 IO register must be set when the chip is 
+connected to the SCSI BUS.
+
+When this feature has been enabled for the current connection, the chip has 
+every chance to win arbitration if only devices with lower priority are 
+competing for the SCSI BUS. By the way, when the chip is using SCSI id 7, 
+then it will for sure win the next SCSI BUS arbitration.
+
+Since, there is no way to know what devices are trying to arbitrate for the 
+BUS, using this feature can be extremally unfair. So, you are not advised 
+to enable it, or at most enable this feature for the case the chip lost 
+the previous arbitration (boot option 'iarb:1').
+
+This feature has the following advantages:
+
+a) Allow the initiator with ID 7 to win arbitration when it wants so.
+b) Overlap at least 4 micro-seconds of arbitration time with the execution 
+   of SCRIPTS that deal with the end of the current connection and that 
+   starts the next job.
+
+Hmmm... But (a) may just prevent other devices from reselecting the initiator, 
+and delay data transfers or status/completions, and (b) may just waste 
+SCSI BUS bandwidth if the SCRIPTS execution lasts more than 4 micro-seconds.
+
+The use of IARB needs the SCSI_NCR_IARB_SUPPORT option to have been defined 
+at compile time and the 'iarb' boot option to have been set to a non zero 
+value at boot time. It is not that usefull for real work, but can be used 
+to stress SCSI devices or for some applications that can gain advantage of 
+it. By the way, if you experience badnesses like 'unexpected disconnections', 
+'bad reselections', etc... when using IARB on heavy IO load, you should not 
+be surprised, because force-feeding anything and blocking its arse at the 
+same time cannot work for a long time. :-))
+
 
 11. Some constants and flags of the ncr53c8xx.h header file
 
@@ -1133,6 +1255,8 @@
 
 15. SCSI problem troubleshooting
 
+15.1 Problem tracking
+
 Most SCSI problems are due to a non conformant SCSI bus or to buggy
 devices.  If infortunately you have SCSI problems, you can check the
 following things:
@@ -1179,6 +1303,77 @@
 Once you have found the device and the feature that cause problems, just 
 disable that feature for that device.
 
+15.2 Understanding hardware error reports
+
+When the driver detects an unexpected error condition, it may display a 
+message of the following pattern.
+
+sym53c876-0:1: ERROR (0:48) (1-21-65) (f/95) @ (script 7c0:19000000).
+sym53c876-0: script cmd = 19000000
+sym53c876-0: regdump: da 10 80 95 47 0f 01 07 75 01 81 21 80 01 09 00.
+
+Some fields in such a message may help you understand the cause of the 
+problem, as follows:
+
+sym53c876-0:1: ERROR (0:48) (1-21-65) (f/95) @ (script 7c0:19000000).
+............A.........B.C....D.E..F....G.H.......I.....J...K.......
+
+Field A : target number.
+  SCSI ID of the device the controller was talking with at the moment the 
+  error occurs.
+
+Field B : DSTAT io register (DMA STATUS)
+  Bit 0x40 : MDPE Master Data Parity Error
+             Data parity error detected on the PCI BUS.
+  Bit 0x20 : BF   Bus Fault
+             PCI bus fault condition detected
+  Bit 0x01 : IID  Illegal Instruction Detected
+             Set by the chip when it detects an Illegal Instruction format 
+             on some condition that makes an instruction illegal.
+  Bit 0x80 : DFE Dma Fifo Empty
+             Pure status bit that does not indicate an error.
+  If the reported DSTAT value contains a combination of MDPE (0x40), 
+  BF (0x20), then the cause may be likely due to a PCI BUS problem.
+
+Field C : SIST io register (SCSI Interrupt Status)
+  Bit 0x08 : SGE  SCSI GROSS ERROR
+             Indicates that the chip detected a severe error condition 
+             on the SCSI BUS that prevents the SCSI protocol from functionning
+             properly.
+  Bit 0x04 : UDC  Undexpected Disconnection
+             Indicates that the device released the SCSI BUS when the chip 
+             was not expecting this to happen. A device may behave so to 
+             indicate the SCSI initiator that an error condition not reportable              using the SCSI protocol has occured.
+  Bit 0x02 : RST  SCSI BUS Reset
+             Generally SCSI targets donnot reset the SCSI BUS, although any 
+             device on the BUS can reset it at any time.
+  Bit 0x01 : PAR  Parity
+             SCSI parity error detected.
+  On a faulty SCSI BUS, any error condition among SGE (0x08), UDC (0x04) and 
+  PAR (0x01) may be detected by the chip. If your SCSI system sometimes 
+  encounters such error conditions, especially SCSI GROSS ERROR, then a SCSI 
+  BUS problem is likely the cause of these errors.
+
+For fields D,E,F,G and H, you may look into the sym53c8xx_defs.h file 
+that contains some minimal comments on IO register bits.
+Field D : SOCL  Scsi Output Control Latch
+          This register reflects the state of the SCSI control lines the 
+          chip want to drive or compare against.
+Field E : SBCL  Scsi Bus Control Lines
+          Actual value of control lines on the SCSI BUS.
+Field F : SBDL  Scsi Bus Data Lines
+          Actual value of data lines on the SCSI BUS.
+Field G : SXFER  SCSI Transfer
+          Contains the setting of the Synchronous Period for output and 
+          the current Synchronous offset (offset 0 means asynchronous).
+Field H : SCNTL3 Scsi Control Register 3
+          Contains the setting of timing values for both asynchronous and 
+          synchronous data transfers. 
+
+Understanding Fields I, J, K and dumps requires to have good knowledge of 
+SCSI standards, chip cores functionnals and internal driver data structures.
+You are not required to decode and understand them, unless you want to help 
+maintain the driver code.
 
 16. Synchonous transfer negotiation tables
 
Index: oldkernel/linux/drivers/scsi/aic7xxx.c
diff -u linux/drivers/scsi/aic7xxx.c:1.7 linux/drivers/scsi/aic7xxx.c:1.8
--- linux/drivers/scsi/aic7xxx.c:1.7	Thu Jun  1 17:00:05 2000
+++ linux/drivers/scsi/aic7xxx.c	Fri Jul  7 15:36:43 2000
@@ -270,7 +270,7 @@
     0, 0, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL
 };
 
-#define AIC7XXX_C_VERSION  "5.1.27"
+#define AIC7XXX_C_VERSION  "5.1.28"
 
 #define NUMBER(arr)     (sizeof(arr) / sizeof(arr[0]))
 #define MIN(a,b)        (((a) < (b)) ? (a) : (b))
@@ -1471,7 +1471,6 @@
   {
     x = inb(p->base + port);
   }
-  mb();
   return(x);
 #else
   return(inb(p->base + port));
@@ -1485,12 +1484,15 @@
   if(p->maddr)
   {
     writeb(val, p->maddr + port);
+    mb(); /* locked operation in order to force ordering */
+    readb(p->maddr + HCNTRL); /* dummy read to flush the write */
   }
   else
   {
     outb(val, p->base + port);
+    mb(); /* locked operation in order to force ordering */
+    inb(p->base + HCNTRL); /* dummy read to flush the write */
   }
-  mb();
 #else
   outb(val, p->base + port);
 #endif
@@ -1772,7 +1774,6 @@
   struct ins_format1 *fmt1_ins;
   struct ins_format3 *fmt3_ins;
   unsigned char opcode;
-  volatile unsigned char hcntrl;
 
   instr = *(union ins_formats*) &seqprog[instrptr * 4];
 
@@ -1874,13 +1875,9 @@
         }
       }
       aic_outb(p, (instr.integer & 0xff), SEQRAM);
-      hcntrl = aic_inb(p, HCNTRL);
       aic_outb(p, ((instr.integer >> 8) & 0xff), SEQRAM);
-      hcntrl = aic_inb(p, HCNTRL);
       aic_outb(p, ((instr.integer >> 16) & 0xff), SEQRAM);
-      hcntrl = aic_inb(p, HCNTRL);
       aic_outb(p, ((instr.integer >> 24) & 0xff), SEQRAM);
-      hcntrl = aic_inb(p, HCNTRL);
       udelay(10);
       break;
 
@@ -2964,6 +2961,19 @@
         p->needwdtr_copy &= ~(1<<tindex);
         p->needsdtr &= ~(1<<tindex);
         p->needsdtr_copy &= ~(1<<tindex);
+        /*
+         * This is needed to work around a sequencer bug for now.  Regardless
+         * of the controller in use, if we have a Quantum drive, we need to
+         * limit the speed to 80MByte/sec.  As soon as I get a fixed version
+         * of the sequencer, this code will get yanked.
+         */
+        if(!strncmp(buffer + 8, "QUANTUM", 7) &&
+           p->transinfo[tindex].goal_options )
+        {
+          p->transinfo[tindex].goal_period = 
+            MAX(p->transinfo[tindex].goal_period, 10);
+          p->transinfo[tindex].goal_options = 0;
+        }
       }
       /*
        * Get the INQUIRY checksum.  We use this on Ultra 160/m
@@ -4769,11 +4779,6 @@
             case CHECK_CONDITION:
               if ( !(scb->flags & SCB_SENSE) )
               {
-                /*
-                 * XXX - How do we save the residual (if there is one).
-                 */
-                if ( hscb->residual_SG_segment_count != 0 )
-                  aic7xxx_calculate_residual(p, scb);
 
                 /*
                    * Send a sense command to the requesting target.
@@ -6354,10 +6359,6 @@
       cmd->result = (DID_TIME_OUT << 16);
 
       /*
-       * Clear the data bits on the SCSI bus
-       */
-      aic_outb(p, aic_inb(p, SCSIID) & 0x0f, SCSIID);
-      /*
        * Clear out this hardware SCB
        */
       aic_outb(p, 0, SCB_CONTROL);
@@ -6417,11 +6418,14 @@
     if(p->features & AHC_WIDE)
       aic_outb(p, 0, SCSIBUSH);
     aic_outb(p, 0, SCSIBUSL);
-    aic_outb(p, aic_inb(p, SCSIID) & 0x0f, SCSIID);
     /*
-     * Fake PCI read to flush any posted writes prior to our delay loop
+     * Clear the target id bit from the SCSI bus
      */
-    aic_inb(p, HCNTRL);
+    if(p->features & AHC_ULTRA2)
+      aic_outb(p, aic_inb(p, SCSIID_ULTRA2) & 0x0f, SCSIID_ULTRA2);
+    else
+      aic_outb(p, aic_inb(p, SCSIID) & 0x0f, SCSIID);
+
     /*
      * Delay for the selection timeout delay period then stop the selection
      */
@@ -11557,8 +11561,10 @@
              (scb->flags & SCB_WAITINGQ) ? "WAITINGQ" : "Sent" );
     }
   }
-#endif
   sti();
+#else
+  spin_unlock_irq(&io_request_lock);
+#endif
   for(;;) barrier();
 }
 
@@ -12348,6 +12354,7 @@
           0x84, 0x8e, 0x90, 0x95, 0x97, 0x97, 0x9a, 0x9a, 0x9c, 0x9f,
           0xe0, 0xf1, 0xf4, 0xfc} },
   };
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,1,0)
 #ifdef CONFIG_PCI
   static struct register_ranges cards_ns[] = {
     { 0, {0,} }, /* none */
@@ -12369,6 +12376,7 @@
           0xff, 0xff} }
   };
 #endif
+#endif
   chip = p->chip & AHC_CHIPID_MASK;
   /*
    * Let's run through the PCI space first....
@@ -12390,6 +12398,7 @@
       break;
   }
 
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,1,0)
 #ifdef CONFIG_PCI
   {
     unsigned char temp;
@@ -12402,11 +12411,7 @@
           j <= cards_ns[chip].range_val[ i * 2 + 1 ] ;
           j++)
       {
-#if LINUX_VERSION_CODE > KERNEL_VERSION(2,1,92)
-        pci_read_config_byte(p->pdev, j, &temp);
-#else
         pcibios_read_config_byte(p->pci_bus, p->pci_device_fn, j, &temp);
-#endif
         printk("%02x:%02x ", j, temp);
         if(++k == 13)
         {
@@ -12419,6 +12424,7 @@
   if(k != 0)
     printk("\n");
 #endif /* CONFIG_PCI */
+#endif
 
   /*
    * Now the registers on the card....
@@ -12441,6 +12447,7 @@
   }
   if(k != 0)
     printk("\n");
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,1,0)
   if (p->flags & AHC_SEEPROM_FOUND)
   {
     unsigned short *sc1;
@@ -12456,6 +12463,7 @@
         printk("  ");
     }
   }
+#endif
 
   /*
    * If this was an Ultra2 controller, then we just hosed the card in terms
Index: oldkernel/linux/drivers/scsi/aic7xxx_seq.c
diff -u linux/drivers/scsi/aic7xxx_seq.c:1.3 linux/drivers/scsi/aic7xxx_seq.c:1.4
--- linux/drivers/scsi/aic7xxx_seq.c:1.3	Thu Jun  1 15:46:48 2000
+++ linux/drivers/scsi/aic7xxx_seq.c	Fri Jul  7 15:36:43 2000
@@ -8,14 +8,14 @@
 	0x12, 0x6a, 0x00, 0x00,
 	0xff, 0x6a, 0xd6, 0x09,
 	0xff, 0x6a, 0xdc, 0x09,
-	0x00, 0x65, 0x42, 0x59,
+	0x00, 0x65, 0x44, 0x59,
 	0xf7, 0x01, 0x02, 0x08,
 	0xff, 0x4e, 0xc8, 0x08,
 	0xbf, 0x60, 0xc0, 0x08,
-	0x60, 0x0b, 0x86, 0x68,
+	0x60, 0x0b, 0x88, 0x68,
 	0x40, 0x00, 0x0e, 0x68,
 	0x08, 0x1f, 0x3e, 0x10,
-	0x60, 0x0b, 0x86, 0x68,
+	0x60, 0x0b, 0x88, 0x68,
 	0x40, 0x00, 0x0e, 0x68,
 	0x08, 0x1f, 0x3e, 0x10,
 	0xff, 0x3e, 0x4a, 0x60,
@@ -26,12 +26,12 @@
 	0x00, 0x4d, 0x12, 0x70,
 	0x01, 0x4e, 0x9c, 0x18,
 	0xbf, 0x60, 0xc0, 0x08,
-	0x00, 0x6a, 0xbc, 0x5c,
+	0x00, 0x6a, 0xbe, 0x5c,
 	0xff, 0x4e, 0xc8, 0x18,
-	0x02, 0x6a, 0xd2, 0x5b,
+	0x02, 0x6a, 0xd4, 0x5b,
 	0xff, 0x52, 0x20, 0x09,
 	0x0d, 0x6a, 0x6a, 0x00,
-	0x00, 0x52, 0x48, 0x5c,
+	0x00, 0x52, 0x4a, 0x5c,
 	0x03, 0xb0, 0x52, 0x31,
 	0xff, 0xb0, 0x52, 0x09,
 	0xff, 0xb1, 0x54, 0x09,
@@ -52,51 +52,52 @@
 	0xf0, 0xa1, 0xc8, 0x08,
 	0x0f, 0x05, 0x0a, 0x08,
 	0x00, 0x05, 0x0a, 0x00,
+	0xff, 0x6a, 0x0c, 0x08,
 	0x5a, 0x6a, 0x00, 0x04,
 	0x12, 0x65, 0x02, 0x00,
 	0x31, 0x6a, 0xca, 0x00,
-	0x80, 0x37, 0x6e, 0x68,
+	0x80, 0x37, 0x70, 0x68,
 	0xff, 0x65, 0xca, 0x18,
 	0xff, 0x37, 0xdc, 0x08,
 	0xff, 0x6e, 0xc8, 0x08,
-	0x00, 0x6c, 0x76, 0x78,
+	0x00, 0x6c, 0x78, 0x78,
 	0x20, 0x01, 0x02, 0x00,
 	0x4c, 0x37, 0xc8, 0x28,
-	0x08, 0x1f, 0x7e, 0x78,
+	0x08, 0x1f, 0x80, 0x78,
 	0x08, 0x37, 0x6e, 0x00,
 	0x08, 0x64, 0xc8, 0x00,
 	0x70, 0x64, 0xca, 0x18,
 	0xff, 0x6c, 0x0a, 0x08,
 	0x20, 0x64, 0xca, 0x18,
 	0xff, 0x6c, 0x08, 0x0c,
-	0x40, 0x0b, 0x0e, 0x69,
-	0x80, 0x0b, 0x00, 0x79,
+	0x40, 0x0b, 0x10, 0x69,
+	0x80, 0x0b, 0x02, 0x79,
 	0xa4, 0x6a, 0x06, 0x00,
 	0x40, 0x6a, 0x16, 0x00,
-	0x10, 0x03, 0xfc, 0x78,
+	0x10, 0x03, 0xfe, 0x78,
 	0xff, 0x50, 0xc8, 0x08,
 	0x88, 0x6a, 0xcc, 0x00,
-	0x49, 0x6a, 0x38, 0x5c,
+	0x49, 0x6a, 0x3a, 0x5c,
 	0x01, 0x6a, 0x26, 0x01,
 	0xff, 0x6a, 0xca, 0x08,
 	0x08, 0x01, 0x02, 0x00,
-	0x02, 0x0b, 0x9c, 0x78,
+	0x02, 0x0b, 0x9e, 0x78,
 	0xf7, 0x01, 0x02, 0x08,
 	0xff, 0x06, 0xcc, 0x08,
 	0xff, 0x66, 0x32, 0x09,
 	0x01, 0x65, 0xca, 0x18,
-	0x80, 0x66, 0xaa, 0x78,
+	0x80, 0x66, 0xac, 0x78,
 	0xff, 0x66, 0xa2, 0x08,
-	0x10, 0x03, 0x9a, 0x68,
+	0x10, 0x03, 0x9c, 0x68,
 	0xfc, 0x65, 0xc8, 0x18,
-	0x00, 0x65, 0xb2, 0x48,
+	0x00, 0x65, 0xb4, 0x48,
 	0xff, 0x6a, 0x32, 0x01,
 	0x01, 0x64, 0x18, 0x19,
 	0xff, 0x6a, 0x1a, 0x09,
 	0xff, 0x6a, 0x1c, 0x09,
 	0x84, 0x6a, 0x06, 0x00,
 	0x08, 0x01, 0x02, 0x00,
-	0x02, 0x0b, 0xbc, 0x78,
+	0x02, 0x0b, 0xbe, 0x78,
 	0xff, 0x06, 0xc8, 0x08,
 	0xff, 0x64, 0x32, 0x09,
 	0xff, 0x6a, 0xca, 0x08,
@@ -110,33 +111,33 @@
 	0x0b, 0x65, 0xca, 0x18,
 	0xff, 0x65, 0xc8, 0x08,
 	0x00, 0x8c, 0x18, 0x19,
-	0x02, 0x0b, 0xd8, 0x78,
-	0x01, 0x65, 0xde, 0x60,
+	0x02, 0x0b, 0xda, 0x78,
+	0x01, 0x65, 0xe0, 0x60,
 	0xf7, 0x01, 0x02, 0x08,
 	0xff, 0x06, 0x32, 0x09,
 	0xff, 0x65, 0xca, 0x18,
-	0xff, 0x65, 0xd8, 0x68,
+	0xff, 0x65, 0xda, 0x68,
 	0x0a, 0x93, 0x26, 0x01,
-	0x00, 0x65, 0xae, 0x5c,
-	0x40, 0x51, 0xf0, 0x78,
+	0x00, 0x65, 0xb0, 0x5c,
+	0x40, 0x51, 0xf2, 0x78,
 	0xe4, 0x6a, 0x06, 0x00,
 	0x08, 0x01, 0x02, 0x00,
-	0x04, 0x6a, 0x6a, 0x5b,
+	0x04, 0x6a, 0x6c, 0x5b,
 	0x01, 0x50, 0xa0, 0x18,
-	0x00, 0x50, 0xf6, 0xe0,
+	0x00, 0x50, 0xf8, 0xe0,
 	0xff, 0x6a, 0xa0, 0x08,
 	0xff, 0x6a, 0x3a, 0x01,
 	0x02, 0x6a, 0x22, 0x01,
-	0x40, 0x51, 0xfc, 0x68,
+	0x40, 0x51, 0xfe, 0x68,
 	0xff, 0x6a, 0x06, 0x08,
 	0x00, 0x65, 0x0e, 0x40,
 	0x20, 0x6a, 0x16, 0x00,
 	0xf0, 0x19, 0x6e, 0x08,
 	0x08, 0x6a, 0x18, 0x00,
 	0x08, 0x11, 0x22, 0x00,
-	0x08, 0x6a, 0x66, 0x58,
+	0x08, 0x6a, 0x68, 0x58,
 	0x08, 0x6a, 0x68, 0x00,
-	0x00, 0x65, 0x22, 0x41,
+	0x00, 0x65, 0x24, 0x41,
 	0x12, 0x6a, 0x00, 0x00,
 	0x40, 0x6a, 0x16, 0x00,
 	0xff, 0x3e, 0x20, 0x09,
@@ -144,23 +145,23 @@
 	0xff, 0xa1, 0x6e, 0x08,
 	0x08, 0x6a, 0x18, 0x00,
 	0x08, 0x11, 0x22, 0x00,
-	0x08, 0x6a, 0x66, 0x58,
+	0x08, 0x6a, 0x68, 0x58,
 	0x80, 0x6a, 0x68, 0x00,
 	0x80, 0x36, 0x6c, 0x00,
-	0x00, 0x65, 0x1c, 0x5c,
+	0x00, 0x65, 0x1e, 0x5c,
 	0xff, 0x3d, 0xc8, 0x08,
-	0xbf, 0x64, 0x5a, 0x79,
-	0x80, 0x64, 0x22, 0x72,
-	0xa0, 0x64, 0x52, 0x72,
-	0xc0, 0x64, 0x4a, 0x72,
-	0xe0, 0x64, 0x92, 0x72,
+	0xbf, 0x64, 0x5c, 0x79,
+	0x80, 0x64, 0x24, 0x72,
+	0xa0, 0x64, 0x54, 0x72,
+	0xc0, 0x64, 0x4c, 0x72,
+	0xe0, 0x64, 0x94, 0x72,
 	0x01, 0x6a, 0x22, 0x01,
-	0x00, 0x65, 0x22, 0x41,
+	0x00, 0x65, 0x24, 0x41,
 	0xf7, 0x11, 0x22, 0x08,
-	0x00, 0x65, 0x42, 0x59,
+	0x00, 0x65, 0x44, 0x59,
 	0xff, 0x06, 0xd4, 0x08,
 	0xf7, 0x01, 0x02, 0x08,
-	0x09, 0x0c, 0x3c, 0x79,
+	0x09, 0x0c, 0x3e, 0x79,
 	0x08, 0x0c, 0x0e, 0x68,
 	0x01, 0x6a, 0x22, 0x01,
 	0xff, 0x6a, 0x26, 0x09,
@@ -173,25 +174,25 @@
 	0x03, 0xa9, 0x18, 0x31,
 	0x03, 0xa9, 0x10, 0x30,
 	0x08, 0x6a, 0xcc, 0x00,
-	0xa9, 0x6a, 0x32, 0x5c,
-	0x00, 0x65, 0x7a, 0x41,
+	0xa9, 0x6a, 0x34, 0x5c,
+	0x00, 0x65, 0x7c, 0x41,
 	0xa8, 0x6a, 0x6a, 0x00,
 	0x79, 0x6a, 0x6a, 0x00,
-	0x40, 0x3d, 0x62, 0x69,
+	0x40, 0x3d, 0x64, 0x69,
 	0x04, 0x35, 0x6a, 0x00,
-	0x00, 0x65, 0x8c, 0x5b,
+	0x00, 0x65, 0x8e, 0x5b,
 	0x80, 0x6a, 0xd4, 0x01,
-	0x10, 0x36, 0x4e, 0x69,
+	0x10, 0x36, 0x50, 0x69,
 	0x10, 0x36, 0x6c, 0x00,
 	0x07, 0xac, 0x10, 0x31,
 	0x03, 0x8c, 0x10, 0x30,
 	0x05, 0xa3, 0x70, 0x30,
 	0x88, 0x6a, 0xcc, 0x00,
-	0xac, 0x6a, 0x2a, 0x5c,
-	0x00, 0x65, 0x24, 0x5c,
+	0xac, 0x6a, 0x2c, 0x5c,
+	0x00, 0x65, 0x26, 0x5c,
 	0x38, 0x6a, 0xcc, 0x00,
-	0xa3, 0x6a, 0x2e, 0x5c,
-	0xff, 0x38, 0x8a, 0x69,
+	0xa3, 0x6a, 0x30, 0x5c,
+	0xff, 0x38, 0x8c, 0x69,
 	0x80, 0x02, 0x04, 0x00,
 	0xe7, 0x35, 0x6a, 0x08,
 	0x03, 0x69, 0x18, 0x31,
@@ -199,337 +200,337 @@
 	0xff, 0x6a, 0x10, 0x00,
 	0xff, 0x6a, 0x12, 0x00,
 	0xff, 0x6a, 0x14, 0x00,
-	0x01, 0x38, 0x90, 0x61,
+	0x01, 0x38, 0x92, 0x61,
 	0xbf, 0x35, 0x6a, 0x08,
 	0x02, 0x6a, 0xf8, 0x01,
 	0xff, 0x69, 0xca, 0x08,
 	0xff, 0x35, 0x26, 0x09,
-	0x04, 0x0b, 0x94, 0x69,
-	0x04, 0x0b, 0xa0, 0x69,
-	0x10, 0x0c, 0x96, 0x79,
-	0x04, 0x0b, 0xa0, 0x69,
+	0x04, 0x0b, 0x96, 0x69,
+	0x04, 0x0b, 0xa2, 0x69,
+	0x10, 0x0c, 0x98, 0x79,
+	0x04, 0x0b, 0xa2, 0x69,
 	0xff, 0x6a, 0xca, 0x08,
-	0x00, 0x35, 0x74, 0x5b,
-	0x80, 0x02, 0xf4, 0x69,
-	0xff, 0x65, 0xe4, 0x79,
+	0x00, 0x35, 0x76, 0x5b,
+	0x80, 0x02, 0xf6, 0x69,
+	0xff, 0x65, 0xe6, 0x79,
 	0xff, 0x38, 0x70, 0x18,
-	0xff, 0x38, 0xe4, 0x79,
-	0x80, 0xea, 0xc0, 0x61,
+	0xff, 0x38, 0xe6, 0x79,
+	0x80, 0xea, 0xc2, 0x61,
 	0xef, 0x38, 0xc8, 0x18,
 	0x80, 0x6a, 0xc8, 0x00,
-	0x00, 0x65, 0xb2, 0x49,
+	0x00, 0x65, 0xb4, 0x49,
 	0x33, 0x38, 0xc8, 0x28,
 	0xff, 0x64, 0xd0, 0x09,
 	0x04, 0x39, 0xc0, 0x31,
 	0x09, 0x6a, 0xd6, 0x01,
-	0x80, 0xeb, 0xb8, 0x79,
+	0x80, 0xeb, 0xba, 0x79,
 	0xf7, 0xeb, 0xd6, 0x09,
-	0x08, 0xeb, 0xbc, 0x69,
+	0x08, 0xeb, 0xbe, 0x69,
 	0x01, 0x6a, 0xd6, 0x01,
 	0x08, 0xe9, 0x10, 0x31,
 	0x03, 0x8c, 0x10, 0x30,
 	0x88, 0x6a, 0xcc, 0x00,
-	0x39, 0x6a, 0x30, 0x5c,
+	0x39, 0x6a, 0x32, 0x5c,
 	0x08, 0x6a, 0x18, 0x01,
 	0xff, 0x6a, 0x1a, 0x09,
 	0xff, 0x6a, 0x1c, 0x09,
 	0x0d, 0x93, 0x26, 0x01,
-	0x00, 0x65, 0xae, 0x5c,
-	0x88, 0x6a, 0x9e, 0x5c,
-	0x00, 0x65, 0x24, 0x5c,
+	0x00, 0x65, 0xb0, 0x5c,
+	0x88, 0x6a, 0xa0, 0x5c,
+	0x00, 0x65, 0x26, 0x5c,
 	0xff, 0x6a, 0xc8, 0x08,
 	0x08, 0x39, 0x72, 0x18,
 	0x00, 0x3a, 0x74, 0x20,
-	0x01, 0x0c, 0xdc, 0x79,
-	0x10, 0x0c, 0x7a, 0x79,
+	0x01, 0x0c, 0xde, 0x79,
+	0x10, 0x0c, 0x7c, 0x79,
 	0xff, 0x35, 0x26, 0x09,
-	0x04, 0x0b, 0xe2, 0x69,
-	0x00, 0x65, 0xfc, 0x59,
+	0x04, 0x0b, 0xe4, 0x69,
+	0x00, 0x65, 0xfe, 0x59,
 	0x03, 0x08, 0x52, 0x31,
 	0xff, 0x38, 0x50, 0x09,
 	0xff, 0x08, 0x52, 0x09,
 	0xff, 0x09, 0x54, 0x09,
 	0xff, 0x0a, 0x56, 0x09,
 	0xff, 0x38, 0x50, 0x09,
-	0x00, 0x65, 0x22, 0x41,
-	0x00, 0x65, 0xfc, 0x59,
+	0x00, 0x65, 0x24, 0x41,
+	0x00, 0x65, 0xfe, 0x59,
 	0x7f, 0x02, 0x04, 0x08,
 	0xe1, 0x6a, 0x22, 0x01,
-	0x00, 0x65, 0x22, 0x41,
-	0x04, 0x93, 0x12, 0x6a,
+	0x00, 0x65, 0x24, 0x41,
+	0x04, 0x93, 0x14, 0x6a,
 	0xdf, 0x93, 0x26, 0x09,
-	0x20, 0x93, 0x00, 0x6a,
+	0x20, 0x93, 0x02, 0x6a,
 	0x02, 0x93, 0x26, 0x01,
-	0x01, 0x94, 0x02, 0x7a,
-	0x01, 0x94, 0x02, 0x7a,
-	0x01, 0x94, 0x02, 0x7a,
-	0x01, 0x94, 0x02, 0x7a,
-	0x01, 0x94, 0x02, 0x7a,
-	0x01, 0x94, 0x02, 0x7a,
-	0x10, 0x94, 0x10, 0x6a,
+	0x01, 0x94, 0x04, 0x7a,
+	0x01, 0x94, 0x04, 0x7a,
+	0x01, 0x94, 0x04, 0x7a,
+	0x01, 0x94, 0x04, 0x7a,
+	0x01, 0x94, 0x04, 0x7a,
+	0x01, 0x94, 0x04, 0x7a,
+	0x10, 0x94, 0x12, 0x6a,
 	0xf7, 0x93, 0x26, 0x09,
-	0x08, 0x93, 0x14, 0x6a,
+	0x08, 0x93, 0x16, 0x6a,
 	0xdf, 0x93, 0x26, 0x09,
-	0x20, 0x93, 0x18, 0x6a,
+	0x20, 0x93, 0x1a, 0x6a,
 	0x03, 0x08, 0x52, 0x31,
 	0xff, 0x38, 0x50, 0x09,
 	0x12, 0x01, 0x02, 0x00,
 	0xff, 0x6a, 0xd4, 0x0c,
-	0x00, 0x65, 0x8c, 0x5b,
+	0x00, 0x65, 0x8e, 0x5b,
 	0x05, 0xb4, 0x10, 0x31,
 	0x02, 0x6a, 0x1a, 0x31,
 	0x03, 0x8c, 0x10, 0x30,
 	0x88, 0x6a, 0xcc, 0x00,
-	0xb4, 0x6a, 0x2e, 0x5c,
+	0xb4, 0x6a, 0x30, 0x5c,
 	0xff, 0x6a, 0x1a, 0x09,
 	0xff, 0x6a, 0x1c, 0x09,
-	0x00, 0x65, 0x24, 0x5c,
-	0x3d, 0x6a, 0x74, 0x5b,
+	0x00, 0x65, 0x26, 0x5c,
+	0x3d, 0x6a, 0x76, 0x5b,
 	0xac, 0x6a, 0x26, 0x01,
-	0x04, 0x0b, 0x38, 0x6a,
-	0x04, 0x0b, 0x3e, 0x6a,
-	0x10, 0x0c, 0x3a, 0x7a,
+	0x04, 0x0b, 0x3a, 0x6a,
+	0x04, 0x0b, 0x40, 0x6a,
+	0x10, 0x0c, 0x3c, 0x7a,
 	0xf7, 0x93, 0x26, 0x09,
-	0x08, 0x93, 0x40, 0x6a,
+	0x08, 0x93, 0x42, 0x6a,
 	0xdf, 0x93, 0x26, 0x09,
-	0x20, 0x93, 0x44, 0x6a,
+	0x20, 0x93, 0x46, 0x6a,
 	0x12, 0x01, 0x02, 0x00,
-	0x00, 0x65, 0x22, 0x41,
-	0x00, 0x65, 0x8c, 0x5b,
+	0x00, 0x65, 0x24, 0x41,
+	0x00, 0x65, 0x8e, 0x5b,
 	0xff, 0x06, 0x44, 0x09,
-	0x00, 0x65, 0x22, 0x41,
+	0x00, 0x65, 0x24, 0x41,
 	0x10, 0x3d, 0x06, 0x00,
 	0xff, 0x34, 0xca, 0x08,
-	0x80, 0x65, 0x76, 0x62,
+	0x80, 0x65, 0x78, 0x62,
 	0x0f, 0xa1, 0xca, 0x08,
 	0x07, 0xa1, 0xca, 0x08,
 	0x40, 0xa0, 0xc8, 0x08,
 	0x00, 0x65, 0xca, 0x00,
 	0x80, 0x65, 0xca, 0x00,
-	0x80, 0xa0, 0x66, 0x7a,
+	0x80, 0xa0, 0x68, 0x7a,
 	0xff, 0x65, 0x0c, 0x08,
-	0x00, 0x65, 0x78, 0x42,
-	0x20, 0xa0, 0x7e, 0x7a,
+	0x00, 0x65, 0x7a, 0x42,
+	0x20, 0xa0, 0x80, 0x7a,
 	0xff, 0x65, 0x0c, 0x08,
-	0x00, 0x65, 0x1c, 0x5c,
-	0xa0, 0x3d, 0x86, 0x62,
+	0x00, 0x65, 0x1e, 0x5c,
+	0xa0, 0x3d, 0x88, 0x62,
 	0x23, 0xa0, 0x0c, 0x08,
-	0x00, 0x65, 0x1c, 0x5c,
-	0xa0, 0x3d, 0x86, 0x62,
-	0x00, 0xb9, 0x7e, 0x42,
-	0xff, 0x65, 0x7e, 0x62,
+	0x00, 0x65, 0x1e, 0x5c,
+	0xa0, 0x3d, 0x88, 0x62,
+	0x00, 0xb9, 0x80, 0x42,
+	0xff, 0x65, 0x80, 0x62,
 	0xa1, 0x6a, 0x22, 0x01,
 	0xff, 0x6a, 0xd4, 0x08,
-	0x10, 0x51, 0x86, 0x72,
+	0x10, 0x51, 0x88, 0x72,
 	0x40, 0x6a, 0x18, 0x00,
 	0xff, 0x65, 0x0c, 0x08,
-	0x00, 0x65, 0x1c, 0x5c,
-	0xa0, 0x3d, 0x50, 0x72,
+	0x00, 0x65, 0x1e, 0x5c,
+	0xa0, 0x3d, 0x52, 0x72,
 	0x40, 0x6a, 0x18, 0x00,
 	0xff, 0x34, 0xa6, 0x08,
-	0x80, 0x34, 0x8e, 0x62,
+	0x80, 0x34, 0x90, 0x62,
 	0x7f, 0xa0, 0x40, 0x09,
 	0x08, 0x6a, 0x68, 0x00,
-	0x00, 0x65, 0x22, 0x41,
-	0x64, 0x6a, 0x64, 0x5b,
-	0x80, 0x64, 0x04, 0x6b,
-	0x04, 0x64, 0xe6, 0x72,
-	0x02, 0x64, 0xec, 0x72,
-	0x00, 0x6a, 0xae, 0x72,
-	0x03, 0x64, 0x00, 0x73,
-	0x01, 0x64, 0xe2, 0x72,
-	0x07, 0x64, 0x42, 0x73,
-	0x08, 0x64, 0xaa, 0x72,
-	0x23, 0x64, 0x46, 0x73,
+	0x00, 0x65, 0x24, 0x41,
+	0x64, 0x6a, 0x66, 0x5b,
+	0x80, 0x64, 0x06, 0x6b,
+	0x04, 0x64, 0xe8, 0x72,
+	0x02, 0x64, 0xee, 0x72,
+	0x00, 0x6a, 0xb0, 0x72,
+	0x03, 0x64, 0x02, 0x73,
+	0x01, 0x64, 0xe4, 0x72,
+	0x07, 0x64, 0x44, 0x73,
+	0x08, 0x64, 0xac, 0x72,
+	0x23, 0x64, 0x48, 0x73,
 	0x11, 0x6a, 0x22, 0x01,
-	0x07, 0x6a, 0x56, 0x5b,
+	0x07, 0x6a, 0x58, 0x5b,
 	0xff, 0x06, 0xd4, 0x08,
-	0x00, 0x65, 0x22, 0x41,
-	0xff, 0xa8, 0xb2, 0x6a,
-	0xff, 0xa2, 0xca, 0x7a,
+	0x00, 0x65, 0x24, 0x41,
+	0xff, 0xa8, 0xb4, 0x6a,
+	0xff, 0xa2, 0xcc, 0x7a,
 	0x01, 0x6a, 0x6a, 0x00,
-	0x00, 0xb9, 0x48, 0x5c,
-	0xff, 0xa2, 0xca, 0x7a,
+	0x00, 0xb9, 0x4a, 0x5c,
+	0xff, 0xa2, 0xcc, 0x7a,
 	0x71, 0x6a, 0x22, 0x01,
 	0xff, 0x6a, 0xd4, 0x08,
-	0x40, 0x51, 0xca, 0x62,
+	0x40, 0x51, 0xcc, 0x62,
 	0x0d, 0x6a, 0x6a, 0x00,
-	0x00, 0xb9, 0x48, 0x5c,
+	0x00, 0xb9, 0x4a, 0x5c,
 	0xff, 0x3e, 0x74, 0x09,
 	0xff, 0x90, 0x7c, 0x08,
 	0x00, 0x65, 0x50, 0x58,
-	0x00, 0x65, 0x34, 0x41,
-	0x20, 0xa0, 0xd2, 0x6a,
+	0x00, 0x65, 0x36, 0x41,
+	0x20, 0xa0, 0xd4, 0x6a,
 	0xff, 0x37, 0xc8, 0x08,
-	0x00, 0x6a, 0xf2, 0x5b,
-	0xff, 0x6a, 0x08, 0x5c,
+	0x00, 0x6a, 0xf4, 0x5b,
+	0xff, 0x6a, 0x0a, 0x5c,
 	0xff, 0xf8, 0xc8, 0x08,
 	0xff, 0x4f, 0xc8, 0x08,
-	0x01, 0x6a, 0xf2, 0x5b,
-	0x00, 0xb9, 0x08, 0x5c,
+	0x01, 0x6a, 0xf4, 0x5b,
+	0x00, 0xb9, 0x0a, 0x5c,
 	0x01, 0x4f, 0x9e, 0x18,
 	0x02, 0x6a, 0x22, 0x01,
-	0x00, 0x65, 0xb6, 0x5c,
-	0x00, 0x65, 0x34, 0x41,
+	0x00, 0x65, 0xb8, 0x5c,
+	0x00, 0x65, 0x36, 0x41,
 	0x41, 0x6a, 0x22, 0x01,
-	0x00, 0x65, 0x22, 0x41,
+	0x00, 0x65, 0x24, 0x41,
 	0x04, 0xa0, 0x40, 0x01,
-	0x00, 0x65, 0xce, 0x5c,
-	0x00, 0x65, 0x34, 0x41,
-	0x10, 0x36, 0xaa, 0x7a,
+	0x00, 0x65, 0xd0, 0x5c,
+	0x00, 0x65, 0x36, 0x41,
+	0x10, 0x36, 0xac, 0x7a,
 	0x05, 0x38, 0x46, 0x31,
 	0x04, 0x14, 0x58, 0x31,
 	0x03, 0xa9, 0x60, 0x31,
 	0xa3, 0x6a, 0xcc, 0x00,
-	0x38, 0x6a, 0x2e, 0x5c,
+	0x38, 0x6a, 0x30, 0x5c,
 	0xac, 0x6a, 0xcc, 0x00,
-	0x14, 0x6a, 0x30, 0x5c,
-	0xa9, 0x6a, 0x32, 0x5c,
-	0x00, 0x65, 0xaa, 0x42,
+	0x14, 0x6a, 0x32, 0x5c,
+	0xa9, 0x6a, 0x34, 0x5c,
+	0x00, 0x65, 0xac, 0x42,
 	0xef, 0x36, 0x6c, 0x08,
-	0x00, 0x65, 0xaa, 0x42,
+	0x00, 0x65, 0xac, 0x42,
 	0x0f, 0x64, 0xc8, 0x08,
 	0x07, 0x64, 0xc8, 0x08,
 	0x00, 0x37, 0x6e, 0x00,
 	0xff, 0x6a, 0xa4, 0x00,
-	0x00, 0x65, 0xc2, 0x5b,
-	0xff, 0x51, 0x16, 0x73,
-	0x20, 0x36, 0x20, 0x7b,
-	0x00, 0x90, 0xb0, 0x5b,
-	0x00, 0x65, 0x22, 0x43,
+	0x00, 0x65, 0xc4, 0x5b,
+	0xff, 0x51, 0x18, 0x73,
+	0x20, 0x36, 0x22, 0x7b,
+	0x00, 0x90, 0xb2, 0x5b,
+	0x00, 0x65, 0x24, 0x43,
 	0xff, 0x06, 0xd4, 0x08,
-	0x00, 0x65, 0x1c, 0x5c,
-	0xe0, 0x3d, 0x3c, 0x63,
-	0x20, 0x12, 0x3c, 0x63,
-	0x51, 0x6a, 0x5a, 0x5b,
-	0x00, 0x65, 0xaa, 0x5b,
+	0x00, 0x65, 0x1e, 0x5c,
+	0xe0, 0x3d, 0x3e, 0x63,
+	0x20, 0x12, 0x3e, 0x63,
+	0x51, 0x6a, 0x5c, 0x5b,
+	0x00, 0x65, 0xac, 0x5b,
 	0xff, 0x37, 0xc8, 0x08,
-	0x00, 0xa1, 0x34, 0x63,
-	0x04, 0xa0, 0x34, 0x7b,
+	0x00, 0xa1, 0x36, 0x63,
+	0x04, 0xa0, 0x36, 0x7b,
 	0xfb, 0xa0, 0x40, 0x09,
 	0x80, 0x36, 0x6c, 0x00,
-	0x80, 0xa0, 0xaa, 0x7a,
+	0x80, 0xa0, 0xac, 0x7a,
 	0x7f, 0xa0, 0x40, 0x09,
-	0xff, 0x6a, 0x56, 0x5b,
-	0x00, 0x65, 0xaa, 0x42,
-	0x04, 0xa0, 0x3a, 0x7b,
-	0x00, 0x65, 0xce, 0x5c,
-	0x00, 0x65, 0x3c, 0x43,
-	0x00, 0x65, 0xb6, 0x5c,
+	0xff, 0x6a, 0x58, 0x5b,
+	0x00, 0x65, 0xac, 0x42,
+	0x04, 0xa0, 0x3c, 0x7b,
+	0x00, 0x65, 0xd0, 0x5c,
+	0x00, 0x65, 0x3e, 0x43,
+	0x00, 0x65, 0xb8, 0x5c,
 	0x31, 0x6a, 0x22, 0x01,
-	0x0c, 0x6a, 0x56, 0x5b,
-	0x00, 0x65, 0xaa, 0x42,
+	0x0c, 0x6a, 0x58, 0x5b,
+	0x00, 0x65, 0xac, 0x42,
 	0x61, 0x6a, 0x22, 0x01,
-	0x00, 0x65, 0xaa, 0x42,
-	0x51, 0x6a, 0x5a, 0x5b,
-	0xff, 0xa8, 0x52, 0x6b,
-	0xff, 0xa9, 0x52, 0x6b,
-	0xff, 0xaa, 0x52, 0x6b,
-	0xff, 0xab, 0x52, 0x6b,
-	0x00, 0x65, 0xaa, 0x42,
+	0x00, 0x65, 0xac, 0x42,
+	0x51, 0x6a, 0x5c, 0x5b,
+	0xff, 0xa8, 0x54, 0x6b,
+	0xff, 0xa9, 0x54, 0x6b,
+	0xff, 0xaa, 0x54, 0x6b,
+	0xff, 0xab, 0x54, 0x6b,
+	0x00, 0x65, 0xac, 0x42,
 	0x51, 0x6a, 0x22, 0x01,
-	0x00, 0x65, 0xaa, 0x42,
+	0x00, 0x65, 0xac, 0x42,
 	0x10, 0x3d, 0x06, 0x00,
 	0xff, 0x65, 0x68, 0x0c,
 	0xff, 0x06, 0xd4, 0x08,
-	0x01, 0x0c, 0x5c, 0x7b,
-	0x04, 0x0c, 0x5e, 0x6b,
+	0x01, 0x0c, 0x5e, 0x7b,
+	0x04, 0x0c, 0x60, 0x6b,
 	0xe0, 0x03, 0x7a, 0x08,
-	0xe0, 0x3d, 0x70, 0x63,
+	0xe0, 0x3d, 0x72, 0x63,
 	0xff, 0x65, 0xcc, 0x08,
 	0xff, 0x12, 0xda, 0x0c,
 	0xff, 0x06, 0xd4, 0x0c,
 	0xff, 0x65, 0x0c, 0x08,
-	0x02, 0x0b, 0x6c, 0x7b,
+	0x02, 0x0b, 0x6e, 0x7b,
 	0xff, 0x6a, 0xd4, 0x0c,
 	0xd1, 0x6a, 0x22, 0x01,
-	0x00, 0x65, 0x22, 0x41,
+	0x00, 0x65, 0x24, 0x41,
 	0xff, 0x65, 0x26, 0x09,
-	0x01, 0x0b, 0x84, 0x6b,
-	0x10, 0x0c, 0x76, 0x7b,
-	0x04, 0x0b, 0x7e, 0x6b,
+	0x01, 0x0b, 0x86, 0x6b,
+	0x10, 0x0c, 0x78, 0x7b,
+	0x04, 0x0b, 0x80, 0x6b,
 	0xff, 0x6a, 0xca, 0x08,
-	0x04, 0x93, 0x82, 0x6b,
-	0x01, 0x94, 0x80, 0x7b,
-	0x10, 0x94, 0x82, 0x6b,
+	0x04, 0x93, 0x84, 0x6b,
+	0x01, 0x94, 0x82, 0x7b,
+	0x10, 0x94, 0x84, 0x6b,
 	0xc7, 0x93, 0x26, 0x09,
 	0xff, 0x99, 0xd4, 0x08,
-	0x38, 0x93, 0x86, 0x6b,
+	0x38, 0x93, 0x88, 0x6b,
 	0xff, 0x6a, 0xd4, 0x0c,
-	0x80, 0x36, 0x8a, 0x6b,
+	0x80, 0x36, 0x8c, 0x6b,
 	0x21, 0x6a, 0x22, 0x05,
 	0xff, 0x65, 0x20, 0x09,
-	0xff, 0x51, 0x98, 0x63,
+	0xff, 0x51, 0x9a, 0x63,
 	0xff, 0x37, 0xc8, 0x08,
-	0xa1, 0x6a, 0xa4, 0x43,
+	0xa1, 0x6a, 0xa6, 0x43,
 	0xff, 0x51, 0xc8, 0x08,
-	0xb9, 0x6a, 0xa4, 0x43,
+	0xb9, 0x6a, 0xa6, 0x43,
 	0xff, 0x90, 0xa4, 0x08,
-	0xff, 0xba, 0xa8, 0x73,
+	0xff, 0xba, 0xaa, 0x73,
 	0xff, 0xba, 0x20, 0x09,
 	0xff, 0x65, 0xca, 0x18,
-	0x00, 0x6c, 0x9c, 0x63,
+	0x00, 0x6c, 0x9e, 0x63,
 	0xff, 0x90, 0xca, 0x0c,
 	0xff, 0x6a, 0xca, 0x04,
-	0x20, 0x36, 0xbc, 0x7b,
-	0x00, 0x90, 0x90, 0x5b,
-	0xff, 0x65, 0xbc, 0x73,
-	0xff, 0x52, 0xba, 0x73,
+	0x20, 0x36, 0xbe, 0x7b,
+	0x00, 0x90, 0x92, 0x5b,
+	0xff, 0x65, 0xbe, 0x73,
+	0xff, 0x52, 0xbc, 0x73,
 	0xff, 0xba, 0xcc, 0x08,
 	0xff, 0x52, 0x20, 0x09,
 	0xff, 0x66, 0x74, 0x09,
 	0xff, 0x65, 0x20, 0x0d,
 	0xff, 0xba, 0x7e, 0x0c,
-	0x00, 0x6a, 0xbc, 0x5c,
+	0x00, 0x6a, 0xbe, 0x5c,
 	0x0d, 0x6a, 0x6a, 0x00,
-	0x00, 0x51, 0x48, 0x44,
-	0xff, 0x3f, 0x16, 0x74,
+	0x00, 0x51, 0x4a, 0x44,
+	0xff, 0x3f, 0x18, 0x74,
 	0xff, 0x6a, 0xa2, 0x00,
-	0x00, 0x3f, 0x90, 0x5b,
-	0xff, 0x65, 0x16, 0x74,
+	0x00, 0x3f, 0x92, 0x5b,
+	0xff, 0x65, 0x18, 0x74,
 	0x20, 0x36, 0x6c, 0x00,
-	0x20, 0xa0, 0xd0, 0x6b,
+	0x20, 0xa0, 0xd2, 0x6b,
 	0xff, 0xb9, 0xa2, 0x0c,
 	0xff, 0x6a, 0xa2, 0x04,
 	0xff, 0x65, 0xa4, 0x08,
 	0xe0, 0x6a, 0xcc, 0x00,
-	0x45, 0x6a, 0x3c, 0x5c,
+	0x45, 0x6a, 0x3e, 0x5c,
 	0x01, 0x6a, 0xd0, 0x01,
 	0x09, 0x6a, 0xd6, 0x01,
-	0x80, 0xeb, 0xdc, 0x7b,
+	0x80, 0xeb, 0xde, 0x7b,
 	0x01, 0x6a, 0xd6, 0x01,
 	0x01, 0xe9, 0xa4, 0x34,
 	0x88, 0x6a, 0xcc, 0x00,
-	0x45, 0x6a, 0x3c, 0x5c,
+	0x45, 0x6a, 0x3e, 0x5c,
 	0x01, 0x6a, 0x18, 0x01,
 	0xff, 0x6a, 0x1a, 0x09,
 	0xff, 0x6a, 0x1c, 0x09,
 	0x0d, 0x6a, 0x26, 0x01,
-	0x00, 0x65, 0xae, 0x5c,
+	0x00, 0x65, 0xb0, 0x5c,
 	0xff, 0x99, 0xa4, 0x0c,
 	0xff, 0x65, 0xa4, 0x08,
 	0xe0, 0x6a, 0xcc, 0x00,
-	0x45, 0x6a, 0x3c, 0x5c,
+	0x45, 0x6a, 0x3e, 0x5c,
 	0x01, 0x6a, 0xd0, 0x01,
 	0x01, 0x6a, 0xdc, 0x05,
 	0x88, 0x6a, 0xcc, 0x00,
-	0x45, 0x6a, 0x3c, 0x5c,
+	0x45, 0x6a, 0x3e, 0x5c,
 	0x01, 0x6a, 0x18, 0x01,
 	0xff, 0x6a, 0x1a, 0x09,
 	0xff, 0x6a, 0x1c, 0x09,
 	0x01, 0x6a, 0x26, 0x05,
 	0x01, 0x65, 0xd8, 0x31,
 	0x09, 0xee, 0xdc, 0x01,
-	0x80, 0xee, 0x0c, 0x7c,
+	0x80, 0xee, 0x0e, 0x7c,
 	0xff, 0x6a, 0xdc, 0x0d,
 	0xff, 0x65, 0x32, 0x09,
 	0x0a, 0x93, 0x26, 0x01,
-	0x00, 0x65, 0xae, 0x44,
+	0x00, 0x65, 0xb0, 0x44,
 	0xff, 0x37, 0xc8, 0x08,
-	0x00, 0x6a, 0xd2, 0x5b,
+	0x00, 0x6a, 0xd4, 0x5b,
 	0xff, 0x52, 0xa2, 0x0c,
-	0x01, 0x0c, 0x1c, 0x7c,
-	0x04, 0x0c, 0x1c, 0x6c,
+	0x01, 0x0c, 0x1e, 0x7c,
+	0x04, 0x0c, 0x1e, 0x6c,
 	0xe0, 0x03, 0x06, 0x08,
 	0xe0, 0x03, 0x7a, 0x0c,
 	0xff, 0x8c, 0x10, 0x08,
@@ -552,29 +553,29 @@
 	0x00, 0x6c, 0xda, 0x24,
 	0xff, 0x65, 0xc8, 0x08,
 	0xe0, 0x6a, 0xcc, 0x00,
-	0x41, 0x6a, 0x38, 0x5c,
+	0x41, 0x6a, 0x3a, 0x5c,
 	0xff, 0x90, 0xe2, 0x09,
 	0x20, 0x6a, 0xd0, 0x01,
-	0x04, 0x35, 0x5a, 0x7c,
+	0x04, 0x35, 0x5c, 0x7c,
 	0x1d, 0x6a, 0xdc, 0x01,
-	0xdc, 0xee, 0x56, 0x64,
-	0x00, 0x65, 0x66, 0x44,
+	0xdc, 0xee, 0x58, 0x64,
+	0x00, 0x65, 0x68, 0x44,
 	0x01, 0x6a, 0xdc, 0x01,
 	0x20, 0xa0, 0xd8, 0x31,
 	0x09, 0xee, 0xdc, 0x01,
-	0x80, 0xee, 0x60, 0x7c,
+	0x80, 0xee, 0x62, 0x7c,
 	0x19, 0x6a, 0xdc, 0x01,
-	0xd8, 0xee, 0x64, 0x64,
+	0xd8, 0xee, 0x66, 0x64,
 	0xff, 0x6a, 0xdc, 0x09,
-	0x18, 0xee, 0x68, 0x6c,
+	0x18, 0xee, 0x6a, 0x6c,
 	0xff, 0x6a, 0xd4, 0x0c,
 	0x88, 0x6a, 0xcc, 0x00,
-	0x41, 0x6a, 0x38, 0x5c,
+	0x41, 0x6a, 0x3a, 0x5c,
 	0x20, 0x6a, 0x18, 0x01,
 	0xff, 0x6a, 0x1a, 0x09,
 	0xff, 0x6a, 0x1c, 0x09,
 	0xff, 0x35, 0x26, 0x09,
-	0x04, 0x35, 0x92, 0x6c,
+	0x04, 0x35, 0x94, 0x6c,
 	0xa0, 0x6a, 0xca, 0x00,
 	0x20, 0x65, 0xc8, 0x18,
 	0xff, 0x6c, 0x32, 0x09,
@@ -585,14 +586,14 @@
 	0xff, 0x6c, 0x32, 0x09,
 	0xff, 0x6c, 0x32, 0x09,
 	0xff, 0x6c, 0x32, 0x09,
-	0x00, 0x65, 0x7e, 0x64,
+	0x00, 0x65, 0x80, 0x64,
 	0x0a, 0x93, 0x26, 0x01,
-	0x00, 0x65, 0xae, 0x5c,
-	0x04, 0x35, 0x8a, 0x7b,
-	0xa0, 0x6a, 0x9e, 0x5c,
-	0x00, 0x65, 0xa0, 0x5c,
-	0x00, 0x65, 0xa0, 0x5c,
-	0x00, 0x65, 0xa0, 0x44,
+	0x00, 0x65, 0xb0, 0x5c,
+	0x04, 0x35, 0x8c, 0x7b,
+	0xa0, 0x6a, 0xa0, 0x5c,
+	0x00, 0x65, 0xa2, 0x5c,
+	0x00, 0x65, 0xa2, 0x5c,
+	0x00, 0x65, 0xa2, 0x44,
 	0xff, 0x65, 0xcc, 0x08,
 	0xff, 0x99, 0xda, 0x08,
 	0xff, 0x99, 0xda, 0x08,
@@ -601,19 +602,19 @@
 	0xff, 0x99, 0xda, 0x08,
 	0xff, 0x99, 0xda, 0x08,
 	0xff, 0x99, 0xda, 0x0c,
-	0x08, 0x94, 0xae, 0x7c,
+	0x08, 0x94, 0xb0, 0x7c,
 	0xf7, 0x93, 0x26, 0x09,
-	0x08, 0x93, 0xb2, 0x6c,
+	0x08, 0x93, 0xb4, 0x6c,
 	0xff, 0x6a, 0xd4, 0x0c,
 	0xff, 0x40, 0x74, 0x09,
 	0xff, 0x90, 0x80, 0x08,
 	0xff, 0x6a, 0x72, 0x05,
-	0xff, 0x40, 0xca, 0x64,
-	0xff, 0x3f, 0xc2, 0x64,
+	0xff, 0x40, 0xcc, 0x64,
+	0xff, 0x3f, 0xc4, 0x64,
 	0xff, 0x6a, 0xca, 0x04,
 	0xff, 0x3f, 0x20, 0x09,
 	0x01, 0x6a, 0x6a, 0x00,
-	0x00, 0xb9, 0x48, 0x5c,
+	0x00, 0xb9, 0x4a, 0x5c,
 	0xff, 0xba, 0x7e, 0x0c,
 	0xff, 0x40, 0x20, 0x09,
 	0xff, 0xba, 0x80, 0x0c,
@@ -754,68 +755,68 @@
 	{ aic7xxx_patch4_func, 40, 4, 1 },
 	{ aic7xxx_patch8_func, 44, 3, 2 },
 	{ aic7xxx_patch0_func, 47, 3, 1 },
-	{ aic7xxx_patch9_func, 52, 7, 1 },
-	{ aic7xxx_patch4_func, 60, 3, 1 },
-	{ aic7xxx_patch8_func, 63, 2, 1 },
-	{ aic7xxx_patch1_func, 68, 60, 1 },
-	{ aic7xxx_patch8_func, 162, 1, 2 },
-	{ aic7xxx_patch0_func, 163, 2, 1 },
-	{ aic7xxx_patch2_func, 167, 3, 4 },
-	{ aic7xxx_patch8_func, 167, 2, 2 },
-	{ aic7xxx_patch0_func, 169, 1, 1 },
-	{ aic7xxx_patch0_func, 170, 2, 1 },
-	{ aic7xxx_patch8_func, 173, 1, 2 },
-	{ aic7xxx_patch0_func, 174, 1, 1 },
-	{ aic7xxx_patch2_func, 178, 1, 1 },
-	{ aic7xxx_patch2_func, 181, 3, 2 },
-	{ aic7xxx_patch0_func, 184, 5, 1 },
-	{ aic7xxx_patch2_func, 192, 2, 3 },
-	{ aic7xxx_patch8_func, 192, 1, 1 },
-	{ aic7xxx_patch0_func, 194, 3, 1 },
-	{ aic7xxx_patch10_func, 198, 1, 2 },
-	{ aic7xxx_patch0_func, 199, 1, 1 },
-	{ aic7xxx_patch8_func, 200, 7, 2 },
-	{ aic7xxx_patch0_func, 207, 1, 1 },
-	{ aic7xxx_patch2_func, 212, 14, 3 },
-	{ aic7xxx_patch10_func, 225, 1, 1 },
-	{ aic7xxx_patch0_func, 226, 9, 1 },
-	{ aic7xxx_patch8_func, 240, 2, 1 },
-	{ aic7xxx_patch8_func, 242, 1, 1 },
-	{ aic7xxx_patch10_func, 243, 6, 3 },
-	{ aic7xxx_patch2_func, 243, 2, 2 },
-	{ aic7xxx_patch0_func, 245, 4, 1 },
-	{ aic7xxx_patch8_func, 250, 1, 1 },
-	{ aic7xxx_patch8_func, 254, 19, 1 },
-	{ aic7xxx_patch2_func, 274, 3, 3 },
-	{ aic7xxx_patch10_func, 276, 1, 1 },
-	{ aic7xxx_patch0_func, 277, 5, 1 },
-	{ aic7xxx_patch10_func, 282, 1, 2 },
-	{ aic7xxx_patch0_func, 283, 9, 1 },
-	{ aic7xxx_patch11_func, 299, 1, 2 },
-	{ aic7xxx_patch0_func, 300, 1, 1 },
-	{ aic7xxx_patch5_func, 361, 1, 2 },
-	{ aic7xxx_patch0_func, 362, 1, 1 },
-	{ aic7xxx_patch3_func, 365, 1, 1 },
-	{ aic7xxx_patch2_func, 375, 3, 2 },
-	{ aic7xxx_patch0_func, 378, 5, 1 },
-	{ aic7xxx_patch11_func, 386, 1, 2 },
-	{ aic7xxx_patch0_func, 387, 1, 1 },
-	{ aic7xxx_patch6_func, 392, 1, 1 },
-	{ aic7xxx_patch1_func, 437, 3, 1 },
-	{ aic7xxx_patch10_func, 442, 11, 1 },
-	{ aic7xxx_patch2_func, 490, 7, 2 },
-	{ aic7xxx_patch0_func, 497, 8, 1 },
-	{ aic7xxx_patch2_func, 506, 4, 2 },
-	{ aic7xxx_patch0_func, 510, 6, 1 },
-	{ aic7xxx_patch2_func, 516, 4, 2 },
-	{ aic7xxx_patch0_func, 520, 3, 1 },
-	{ aic7xxx_patch12_func, 530, 10, 1 },
-	{ aic7xxx_patch2_func, 549, 17, 4 },
-	{ aic7xxx_patch13_func, 557, 4, 2 },
-	{ aic7xxx_patch0_func, 561, 2, 1 },
-	{ aic7xxx_patch0_func, 566, 33, 1 },
-	{ aic7xxx_patch12_func, 599, 4, 1 },
-	{ aic7xxx_patch6_func, 603, 2, 1 },
-	{ aic7xxx_patch6_func, 606, 9, 1 },
+	{ aic7xxx_patch9_func, 53, 7, 1 },
+	{ aic7xxx_patch4_func, 61, 3, 1 },
+	{ aic7xxx_patch8_func, 64, 2, 1 },
+	{ aic7xxx_patch1_func, 69, 60, 1 },
+	{ aic7xxx_patch8_func, 163, 1, 2 },
+	{ aic7xxx_patch0_func, 164, 2, 1 },
+	{ aic7xxx_patch2_func, 168, 3, 4 },
+	{ aic7xxx_patch8_func, 168, 2, 2 },
+	{ aic7xxx_patch0_func, 170, 1, 1 },
+	{ aic7xxx_patch0_func, 171, 2, 1 },
+	{ aic7xxx_patch8_func, 174, 1, 2 },
+	{ aic7xxx_patch0_func, 175, 1, 1 },
+	{ aic7xxx_patch2_func, 179, 1, 1 },
+	{ aic7xxx_patch2_func, 182, 3, 2 },
+	{ aic7xxx_patch0_func, 185, 5, 1 },
+	{ aic7xxx_patch2_func, 193, 2, 3 },
+	{ aic7xxx_patch8_func, 193, 1, 1 },
+	{ aic7xxx_patch0_func, 195, 3, 1 },
+	{ aic7xxx_patch10_func, 199, 1, 2 },
+	{ aic7xxx_patch0_func, 200, 1, 1 },
+	{ aic7xxx_patch8_func, 201, 7, 2 },
+	{ aic7xxx_patch0_func, 208, 1, 1 },
+	{ aic7xxx_patch2_func, 213, 14, 3 },
+	{ aic7xxx_patch10_func, 226, 1, 1 },
+	{ aic7xxx_patch0_func, 227, 9, 1 },
+	{ aic7xxx_patch8_func, 241, 2, 1 },
+	{ aic7xxx_patch8_func, 243, 1, 1 },
+	{ aic7xxx_patch10_func, 244, 6, 3 },
+	{ aic7xxx_patch2_func, 244, 2, 2 },
+	{ aic7xxx_patch0_func, 246, 4, 1 },
+	{ aic7xxx_patch8_func, 251, 1, 1 },
+	{ aic7xxx_patch8_func, 255, 19, 1 },
+	{ aic7xxx_patch2_func, 275, 3, 3 },
+	{ aic7xxx_patch10_func, 277, 1, 1 },
+	{ aic7xxx_patch0_func, 278, 5, 1 },
+	{ aic7xxx_patch10_func, 283, 1, 2 },
+	{ aic7xxx_patch0_func, 284, 9, 1 },
+	{ aic7xxx_patch11_func, 300, 1, 2 },
+	{ aic7xxx_patch0_func, 301, 1, 1 },
+	{ aic7xxx_patch5_func, 362, 1, 2 },
+	{ aic7xxx_patch0_func, 363, 1, 1 },
+	{ aic7xxx_patch3_func, 366, 1, 1 },
+	{ aic7xxx_patch2_func, 376, 3, 2 },
+	{ aic7xxx_patch0_func, 379, 5, 1 },
+	{ aic7xxx_patch11_func, 387, 1, 2 },
+	{ aic7xxx_patch0_func, 388, 1, 1 },
+	{ aic7xxx_patch6_func, 393, 1, 1 },
+	{ aic7xxx_patch1_func, 438, 3, 1 },
+	{ aic7xxx_patch10_func, 443, 11, 1 },
+	{ aic7xxx_patch2_func, 491, 7, 2 },
+	{ aic7xxx_patch0_func, 498, 8, 1 },
+	{ aic7xxx_patch2_func, 507, 4, 2 },
+	{ aic7xxx_patch0_func, 511, 6, 1 },
+	{ aic7xxx_patch2_func, 517, 4, 2 },
+	{ aic7xxx_patch0_func, 521, 3, 1 },
+	{ aic7xxx_patch12_func, 531, 10, 1 },
+	{ aic7xxx_patch2_func, 550, 17, 4 },
+	{ aic7xxx_patch13_func, 558, 4, 2 },
+	{ aic7xxx_patch0_func, 562, 2, 1 },
+	{ aic7xxx_patch0_func, 567, 33, 1 },
+	{ aic7xxx_patch12_func, 600, 4, 1 },
+	{ aic7xxx_patch6_func, 604, 2, 1 },
+	{ aic7xxx_patch6_func, 607, 9, 1 },
 
 };
Index: oldkernel/linux/drivers/scsi/hosts.c
diff -u linux/drivers/scsi/hosts.c:1.1.1.1 linux/drivers/scsi/hosts.c:1.2
--- linux/drivers/scsi/hosts.c:1.1.1.1	Wed May 31 12:33:51 2000
+++ linux/drivers/scsi/hosts.c	Fri Jul  7 15:36:43 2000
@@ -339,6 +339,10 @@
 #include "../net/fc/iph5526_scsi.h"
 #endif
 
+#ifdef CONFIG_BLK_DEV_3WARE
+#include "../block/3w-xxxx.h"
+#endif
+
 /*
  * Moved ppa driver to the end of the probe list
  * since it is a removable host adapter.
@@ -609,6 +613,9 @@
 #endif
 #ifdef CONFIG_IPHASE5526
 	IPH5526_SCSI_FC,
+#endif
+#ifdef CONFIG_BLK_DEV_3WARE
+	TWXXXX,
 #endif
 /* "Removable host adapters" below this line (Parallel Port/USB/other) */
 #ifdef CONFIG_SCSI_PPA
Index: oldkernel/linux/drivers/scsi/hosts.h
diff -u linux/drivers/scsi/hosts.h:1.1.1.1 linux/drivers/scsi/hosts.h:1.2
--- linux/drivers/scsi/hosts.h:1.1.1.1	Wed May 31 12:33:51 2000
+++ linux/drivers/scsi/hosts.h	Fri Jul  7 15:36:43 2000
@@ -390,6 +390,13 @@
 
     unsigned reverse_ordering:1;
     
+    /*
+     * Set this bit if the Host Adapter driver supoorts SCSI-3
+     * integrity checking. Default value is 0.
+     */
+
+    unsigned check_integrity:1;    
+
     void (*select_queue_depths)(struct Scsi_Host *, Scsi_Device *);
 
     /*
@@ -484,7 +491,7 @@
 #ifdef CONFIG_SCSI_PLUTO_MODULE
 #define SD_EXTRA_DEVS 40
 #else
-#define SD_EXTRA_DEVS 4
+#define SD_EXTRA_DEVS 40
 #endif
 #define ST_EXTRA_DEVS 2
 #define SR_EXTRA_DEVS 2
Index: oldkernel/linux/drivers/scsi/megaraid.c
diff -u linux/drivers/scsi/megaraid.c:1.2 linux/drivers/scsi/megaraid.c:1.3
--- linux/drivers/scsi/megaraid.c:1.2	Thu Jun  1 15:14:37 2000
+++ linux/drivers/scsi/megaraid.c	Fri Jul  7 15:36:43 2000
@@ -1558,9 +1558,13 @@
 #endif
     if ((flag & BOARD_QUARTZ) && (skip_id == -1)) {
       u16 magic;
+#if LINUX_VERSION_CODE < 0x20100
       pcibios_read_config_word (pciBus, pciDevFun,
 				PCI_CONF_AMISIG,
 				&magic);
+#else
+      pci_read_config_word (pdev, PCI_CONF_AMISIG, &magic);
+#endif
       if ((magic != AMI_SIGNATURE) && (magic != AMI_SIGNATURE_471) ){
         pciIdx++;
 	continue;		/* not an AMI board */
@@ -1644,10 +1648,39 @@
 
     mega_register_mailbox (megaCfg, virt_to_bus ((void *) &megaCfg->mailbox64));
     mega_i_query_adapter (megaCfg);
-    
+   
+    if (flag == BOARD_QUARTZ) {
+      /* Check to see if this is a Dell PERC RAID controller model 466 */
+      u16 subsysid, subsysvid;
+#if LINUX_VERSION_CODE < 0x20100
+      pcibios_read_config_word (pciBus, pciDevFun,
+				PCI_SUBSYSTEM_VENDOR_ID,
+				&subsysvid);
+      pcibios_read_config_word (pciBus, pciDevFun,
+				PCI_SUBSYSTEM_ID,
+				&subsysid);
+#else
+      pci_read_config_word (pdev, PCI_SUBSYSTEM_VENDOR_ID, &subsysvid);
+      pci_read_config_word (pdev, PCI_SUBSYSTEM_ID, &subsysid);
+#endif
+      if ( (subsysid == 0x1111) && (subsysvid == 0x1111) &&
+           (!strcmp(megaCfg->fwVer,"3.00") || !strcmp(megaCfg->fwVer,"3.01"))) {
+	printk(KERN_WARNING
+"megaraid: Your card is a Dell PERC 2/SC RAID controller with firmware\n"
+"megaraid: 3.00 or 3.01.  This driver is known to have corruption issues\n"
+"megaraid: with those firmware versions on this specific card.  In order\n"
+"megaraid: to protect your data, please upgrade your firmware to version\n"
+"megaraid: 3.10 or later, available from the Dell Technical Support web\n"
+"megaraid: site at\n"
+"http://support.dell.com/us/en/filelib/download/index.asp?fileid=2489\n");
+	megaraid_release (host);
+	while(1) schedule_timeout(1 * HZ);
+      }
+    }
+
     /* Initialize SCBs */
     if (mega_initSCB (megaCfg)) {
-      scsi_unregister (host);
+      megaraid_release (host);
       continue;
     }
 
Index: oldkernel/linux/drivers/scsi/ncr53c8xx.c
diff -u linux/drivers/scsi/ncr53c8xx.c:1.2 linux/drivers/scsi/ncr53c8xx.c:1.3
--- linux/drivers/scsi/ncr53c8xx.c:1.2	Wed May 31 14:44:58 2000
+++ linux/drivers/scsi/ncr53c8xx.c	Fri Jul  7 15:36:43 2000
@@ -73,7 +73,7 @@
 */
 
 /*
-**	July 20 1999, version 3.2a-2
+**	Jan 11 2000, version 3.31
 **
 **	Supported SCSI-II features:
 **	    Synchronous negotiation
@@ -83,7 +83,7 @@
 **	    Parity checking
 **	    Etc...
 **
-**	Supported NCR chips:
+**	Supported NCR/SYMBIOS chips:
 **		53C810		(8 bits, Fast SCSI-2, no rom BIOS) 
 **		53C815		(8 bits, Fast SCSI-2, on board rom BIOS)
 **		53C820		(Wide,   Fast SCSI-2, no rom BIOS)
@@ -93,7 +93,6 @@
 **		53C895		(Wide,   Fast 40,     on board rom BIOS)
 **		53C895A		(Wide,   Fast 40,     on board rom BIOS)
 **		53C896		(Wide,   Fast 40,     on board rom BIOS)
-**		53C1510D		(Wide,   Fast 40,     on board rom BIOS)
 **
 **	Other features:
 **		Memory mapped IO (linux-1.3.X and above only)
@@ -104,7 +103,7 @@
 /*
 **	Name and version of the driver
 */
-#define SCSI_NCR_DRIVER_NAME	"ncr53c8xx - version 3.2a-2"
+#define SCSI_NCR_DRIVER_NAME	"ncr53c8xx - 3.31"
 
 #define SCSI_NCR_DEBUG_FLAGS	(0)
 
@@ -124,7 +123,9 @@
 #include <asm/dma.h>
 #include <asm/io.h>
 #include <asm/system.h>
-#if LINUX_VERSION_CODE >= LinuxVersionCode(2,1,93)
+#if LINUX_VERSION_CODE >= LinuxVersionCode(2,3,17)
+#include <linux/spinlock.h>
+#elif LINUX_VERSION_CODE >= LinuxVersionCode(2,1,93)
 #include <asm/spinlock.h>
 #endif
 #include <linux/delay.h>
@@ -145,13 +146,13 @@
 
 #if LINUX_VERSION_CODE >= LinuxVersionCode(2,1,35)
 #include <linux/init.h>
-#else
-#ifndef	__initdata
-#define	__initdata
 #endif
-#ifndef	__initfunc
-#define	__initfunc(__arginit) __arginit
+
+#ifndef	__init
+#define	__init
 #endif
+#ifndef	__initdata
+#define	__initdata
 #endif
 
 #if LINUX_VERSION_CODE <= LinuxVersionCode(2,1,92)
@@ -369,8 +370,9 @@
 **    We need to deal with power of 2, for alignment constraints.
 */
 #if	SCSI_NCR_MAX_TAGS > 64
-#undef	SCSI_NCR_MAX_TAGS
-#define	SCSI_NCR_MAX_TAGS (64)
+#define	MAX_TAGS (64)
+#else
+#define	MAX_TAGS SCSI_NCR_MAX_TAGS
 #endif
 
 #define NO_TAG	(255)
@@ -378,7 +380,7 @@
 /*
 **	Choose appropriate type for tag bitmap.
 */
-#if	SCSI_NCR_MAX_TAGS > 32
+#if	MAX_TAGS > 32
 typedef u_int64 tagmap_t;
 #else
 typedef u_int32 tagmap_t;
@@ -428,10 +430,20 @@
 #ifdef SCSI_NCR_CAN_QUEUE
 #define MAX_START   (SCSI_NCR_CAN_QUEUE + 4)
 #else
-#define MAX_START   (MAX_TARGET + 7 * SCSI_NCR_MAX_TAGS)
+#define MAX_START   (MAX_TARGET + 7 * MAX_TAGS)
 #endif
 
 /*
+**   We limit the max number of pending IO to 250.
+**   since we donnot want to allocate more than 1 
+**   PAGE for 'scripth'.
+*/
+#if	MAX_START > 250
+#undef	MAX_START
+#define	MAX_START 250
+#endif
+
+/*
 **    The maximum number of segments a transfer is split into.
 **    We support up to 127 segments for both read and write.
 **    The data scripts are broken into 2 sub-scripts.
@@ -591,9 +603,7 @@
 #endif
 
 #if defined(__i386__) || !defined(NCR_IOMAPPED)
-__initfunc(
-static vm_offset_t remap_pci_mem(u_long base, u_long size)
-)
+static vm_offset_t __init remap_pci_mem(u_long base, u_long size)
 {
 	u_long page_base	= ((u_long) base) & PAGE_MASK;
 	u_long page_offs	= ((u_long) base) - page_base;
@@ -602,9 +612,7 @@
 	return (vm_offset_t) (page_remapped? (page_remapped + page_offs) : 0UL);
 }
 
-__initfunc(
-static void unmap_pci_mem(vm_offset_t vaddr, u_long size)
-)
+static void __init unmap_pci_mem(vm_offset_t vaddr, u_long size)
 {
 	if (vaddr)
 		iounmap((void *) (vaddr & PAGE_MASK));
@@ -821,7 +829,6 @@
 
 #define DEBUG_ALLOC    (0x0001)
 #define DEBUG_PHASE    (0x0002)
-#define DEBUG_POLL     (0x0004)
 #define DEBUG_QUEUE    (0x0008)
 #define DEBUG_RESULT   (0x0010)
 #define DEBUG_SCATTER  (0x0020)
@@ -830,8 +837,7 @@
 #define DEBUG_TIMING   (0x0100)
 #define DEBUG_NEGO     (0x0200)
 #define DEBUG_TAGS     (0x0400)
-#define DEBUG_FREEZE   (0x0800)
-#define DEBUG_RESTART  (0x1000)
+#define DEBUG_IC       (0x0800)
 
 /*
 **    Enable/Disable debug messages.
@@ -1119,8 +1125,10 @@
 **==========================================================
 */
 
+#define NS_NOCHANGE	(0)
 #define NS_SYNC		(1)
 #define NS_WIDE		(2)
+#define NS_PPR		(4)
 
 /*==========================================================
 **
@@ -1313,6 +1321,11 @@
 /*2*/	u_char	widedone;
 /*3*/	u_char	wval;
 
+	u_char 	ic_min_sync;
+	u_char 	ic_max_width;
+	u_char 	ic_maximums_set;
+	u_char 	ic_done;
+
 	/*----------------------------------------------------------------
 	**	User settable limits and options.
 	**	These limits are read from the NVRAM if present.
@@ -1384,7 +1397,7 @@
 	*/
 	u_char		ia_tag;		/* Allocation index		*/
 	u_char		if_tag;		/* Freeing index		*/
-	u_char cb_tags[SCSI_NCR_MAX_TAGS];	/* Circular tags buffer	*/
+	u_char cb_tags[MAX_TAGS];	/* Circular tags buffer	*/
 	u_char		usetags;	/* Command queuing is active	*/
 	u_char		maxtags;	/* Max nr of tags asked by user	*/
 	u_char		numtags;	/* Current number of tags	*/
@@ -1630,7 +1643,6 @@
 	**----------------------------------------------------------------
 	*/
 	Scsi_Cmnd	*cmd;		/* SCSI command 		*/
-	u_long		tlimit;		/* Deadline for this job	*/
 	int		data_len;	/* Total data length		*/
 
 	/*----------------------------------------------------------------
@@ -1763,8 +1775,6 @@
 	*/
 	u_short		device_id;	/* PCI device id		*/
 	u_char		revision_id;	/* PCI device revision id	*/
-	u_char		pci_bus;	/* PCI bus number		*/
-	u_char		pci_devfn;	/* PCI device and function	*/
 	u_long		port;		/* IO space base address	*/
 	u_int		irq;		/* IRQ level			*/
 	u_int		features;	/* Chip features map		*/
@@ -1845,6 +1855,15 @@
 	struct ccb	*ccb;		/* Global CCB			*/
 	struct usrcmd	user;		/* Command from user		*/
 	u_char		release_stage;	/* Synchronisation stage on release  */
+
+	/*----------------------------------------------------------------
+	**	Fields that are used for integrity check
+	**----------------------------------------------------------------
+	*/
+	unsigned char check_integrity; /* Enable midlayer integ.check on
+					* bus scan. */
+	unsigned char check_integ_par;  /* Set if par or Init. Det. error
+					 * used only during integ check */
 };
 
 #define NCB_SCRIPT_PHYS(np,lbl)	 (np->p_script  + offsetof (struct script, lbl))
@@ -2023,6 +2042,8 @@
 static  void    ncr_int_sto     (ncb_p np);
 static	u_long	ncr_lookup	(char* id);
 static	void	ncr_negotiate	(struct ncb* np, struct tcb* tp);
+static	int	ncr_prepare_nego(ncb_p np, ccb_p cp, u_char *msgptr);
+static	int	ncr_ic_nego(ncb_p np, ccb_p cp, Scsi_Cmnd *cmd, u_char *msgptr);
 
 #ifdef SCSI_NCR_PROFILE_SUPPORT
 static	void	ncb_profile	(ncb_p np, ccb_p cp);
@@ -2037,6 +2058,7 @@
 static	void	ncr_setup_tags	(ncb_p np, u_char tn, u_char ln);
 static	void	ncr_setwide	(ncb_p np, ccb_p cp, u_char wide, u_char ack);
 static	int	ncr_show_msg	(u_char * msg);
+static  void    ncr_print_msg   (ccb_p cp, char *label, u_char *msg);
 static	int	ncr_snooptest	(ncb_p np);
 static	void	ncr_timeout	(ncb_p np);
 static  void    ncr_wakeup      (ncb_p np, u_long code);
@@ -3578,9 +3600,7 @@
 **==========================================================
 */
 
-__initfunc(
-void ncr_script_fill (struct script * scr, struct scripth * scrh)
-)
+void __init ncr_script_fill (struct script * scr, struct scripth * scrh)
 {
 	int	i;
 	ncrcmd	*p;
@@ -3655,9 +3675,8 @@
 **==========================================================
 */
 
-__initfunc(
-static void ncr_script_copy_and_bind (ncb_p np, ncrcmd *src, ncrcmd *dst, int len)
-)
+static void __init 
+ncr_script_copy_and_bind (ncb_p np, ncrcmd *src, ncrcmd *dst, int len)
 {
 	ncrcmd  opcode, new, old, tmp1, tmp2;
 	ncrcmd	*start, *end;
@@ -3913,10 +3932,8 @@
 **	Get target set-up from Symbios format NVRAM.
 */
 
-__initfunc(
-static void
-	ncr_Symbios_setup_target(ncb_p np, int target, Symbios_nvram *nvram)
-)
+static void __init 
+ncr_Symbios_setup_target(ncb_p np, int target, Symbios_nvram *nvram)
 {
 	tcb_p tp = &np->target[target];
 	Symbios_target *tn = &nvram->target[target];
@@ -3924,7 +3941,7 @@
 	tp->usrsync = tn->sync_period ? (tn->sync_period + 3) / 4 : 255;
 	tp->usrwide = tn->bus_width == 0x10 ? 1 : 0;
 	tp->usrtags =
-		(tn->flags & SYMBIOS_QUEUE_TAGS_ENABLED)? SCSI_NCR_MAX_TAGS : 0;
+		(tn->flags & SYMBIOS_QUEUE_TAGS_ENABLED)? MAX_TAGS : 0;
 
 	if (!(tn->flags & SYMBIOS_DISCONNECT_ENABLE))
 		tp->usrflag |= UF_NODISC;
@@ -3936,10 +3953,8 @@
 **	Get target set-up from Tekram format NVRAM.
 */
 
-__initfunc(
-static void
-	ncr_Tekram_setup_target(ncb_p np, int target, Tekram_nvram *nvram)
-)
+static void __init 
+ncr_Tekram_setup_target(ncb_p np, int target, Tekram_nvram *nvram)
 {
 	tcb_p tp = &np->target[target];
 	struct Tekram_target *tn = &nvram->target[target];
@@ -3965,9 +3980,7 @@
 }
 #endif /* SCSI_NCR_NVRAM_SUPPORT */
 
-__initfunc(
-static int ncr_prepare_setting(ncb_p np, ncr_nvram *nvram)
-)
+static int __init ncr_prepare_setting(ncb_p np, ncr_nvram *nvram)
 {
 	u_char	burst_max;
 	u_long	period;
@@ -4137,30 +4150,53 @@
 	ncr_init_burst(np, burst_max);
 
 	/*
-	**	Set differential mode and LED support.
-	**	Ignore these features for boards known to use a 
-	**	specific GPIO wiring (Tekram only for now).
-	**	Probe initial setting of GPREG and GPCNTL for 
-	**	other ones.
-	*/
-	if (!nvram || nvram->type != SCSI_NCR_TEKRAM_NVRAM) {
+	**	Set SCSI BUS mode.
+	**
+	**	- ULTRA2 chips (895/895A/896) report the current 
+	**	  BUS mode through the STEST4 IO register.
+	**	- For previous generation chips (825/825A/875), 
+	**	  user has to tell us how to check against HVD, 
+	**	  since a 100% safe algorithm is not possible.
+	*/
+	np->scsi_mode = SMODE_SE;
+	if	(np->features & FE_ULTRA2)
+		np->scsi_mode = (np->sv_stest4 & SMODE);
+	else if	(np->features & FE_DIFF) {
 		switch(driver_setup.diff_support) {
-		case 3:
+		case 4:	/* Trust previous settings if present, then GPIO3 */
+			if (np->sv_scntl3) {
+				if (np->sv_stest2 & 0x20)
+					np->scsi_mode = SMODE_HVD;
+				break;
+			}
+		case 3:	/* SYMBIOS controllers report HVD through GPIO3 */
+			if (nvram && nvram->type != SCSI_NCR_SYMBIOS_NVRAM)
+				break;
 			if (INB(nc_gpreg) & 0x08)
-			break;
-		case 2:
-			np->rv_stest2	|= 0x20;
-			break;
-		case 1:
-			np->rv_stest2	|= (np->sv_stest2 & 0x20);
+				break;
+		case 2:	/* Set HVD unconditionally */
+			np->scsi_mode = SMODE_HVD;
+		case 1:	/* Trust previous settings for HVD */
+			if (np->sv_stest2 & 0x20)
+				np->scsi_mode = SMODE_HVD;
 			break;
-		default:
+		default:/* Don't care about HVD */	
 			break;
 		}
 	}
+	if (np->scsi_mode == SMODE_HVD)
+		np->rv_stest2 |= 0x20;
+
+	/*
+	**	Set LED support from SCRIPTS.
+	**	Ignore this feature for boards known to use a 
+	**	specific GPIO wiring and for the 895A or 896 
+	**	that drive the LED directly.
+	**	Also probe initial setting of GPIO0 as output.
+	*/
 	if ((driver_setup.led_pin ||
 	     (nvram && nvram->type == SCSI_NCR_SYMBIOS_NVRAM)) &&
-	    !(np->sv_gpcntl & 0x01))
+	    !(np->features & FE_LEDC) && !(np->sv_gpcntl & 0x01))
 		np->features |= FE_LED0;
 
 	/*
@@ -4210,7 +4246,7 @@
 #endif
 			tp->usrsync = driver_setup.default_sync;
 			tp->usrwide = driver_setup.max_wide;
-			tp->usrtags = SCSI_NCR_MAX_TAGS;
+			tp->usrtags = MAX_TAGS;
 			if (!driver_setup.disconnection)
 				np->target[i].usrflag = UF_NODISC;
 		}
@@ -4251,9 +4287,7 @@
 
 #ifdef SCSI_NCR_DEBUG_NVRAM
 
-__initfunc(
-void ncr_display_Symbios_nvram(ncb_p np, Symbios_nvram *nvram)
-)
+void __init ncr_display_Symbios_nvram(ncb_p np, Symbios_nvram *nvram)
 {
 	int i;
 
@@ -4283,9 +4317,7 @@
 
 static u_char Tekram_boot_delay[7] __initdata = {3, 5, 10, 20, 30, 60, 120};
 
-__initfunc(
-void ncr_display_Tekram_nvram(ncb_p np, Tekram_nvram *nvram)
-)
+void __init ncr_display_Tekram_nvram(ncb_p np, Tekram_nvram *nvram)
 {
 	int i, tags, boot_delay;
 	char *rem;
@@ -4344,9 +4376,8 @@
 **	start the timer daemon.
 */
 
-__initfunc(
-static int ncr_attach (Scsi_Host_Template *tpnt, int unit, ncr_device *device)
-)
+static int __init 
+ncr_attach (Scsi_Host_Template *tpnt, int unit, ncr_device *device)
 {
         struct host_data *host_data;
 	ncb_p np;
@@ -4395,8 +4426,6 @@
 	sprintf(np->inst_name, "ncr53c%s-%d", np->chip_name, np->unit);
 	np->device_id	= device->chip.device_id;
 	np->revision_id	= device->chip.revision_id;
-	np->pci_bus	= device->slot.bus;
-	np->pci_devfn	= device->slot.device_fn;
 	np->features	= device->chip.features;
 	np->clock_divn	= device->chip.nr_divisor;
 	np->maxoffs	= device->chip.offset_max;
@@ -4451,7 +4480,6 @@
 
 	request_region(device->slot.io_port, 128, "ncr53c8xx");
 	np->port = device->slot.io_port;
-	np->myaddr = 255;
 
 #ifdef SCSI_NCR_NVRAM_SUPPORT
 	if (nvram) {
@@ -4501,8 +4529,19 @@
 	instance->io_port	= device->slot.io_port;
 	instance->n_io_port	= 128;
 	instance->dma_channel	= 0;
+	instance->cmd_per_lun	= MAX_TAGS;
+	instance->can_queue	= (MAX_START-4);
 	instance->select_queue_depths = ncr53c8xx_select_queue_depths;
 
+	np->check_integrity	  = 0;
+	instance->check_integrity = 0;
+
+#ifdef SCSI_NCR_ENABLE_INTEGRITY_CHECK
+	if ( !(driver_setup.bus_check & 0x04) ) {
+		np->check_integrity	  = 1;
+		instance->check_integrity = 1;
+	}
+#endif
 	/*
 	**	Patch script to physical addresses
 	*/
@@ -4718,6 +4757,264 @@
 	}
 }
 
+/*==========================================================
+**
+**
+**	Prepare the next negotiation message for integrity check,
+**	if needed.
+**
+**	Fill in the part of message buffer that contains the 
+**	negotiation and the nego_status field of the CCB.
+**	Returns the size of the message in bytes.
+**
+**
+**==========================================================
+*/
+
+static int ncr_ic_nego(ncb_p np, ccb_p cp, Scsi_Cmnd *cmd, u_char *msgptr)
+{
+	tcb_p tp = &np->target[cp->target];
+	int msglen = 0;
+	int nego = 0;
+	u_char no_increase;
+
+	if (tp->inq_done) {
+
+		if (!tp->ic_maximums_set) {
+			tp->ic_maximums_set = 1;
+
+			/* check target and host adapter capabilities */
+			if ( (tp->inq_byte7 & INQ7_WIDE16) && 
+					np->maxwide && tp->usrwide ) 
+				tp->ic_max_width = 1;
+			else
+				tp->ic_max_width = 0;
+
+			if ((tp->inq_byte7 & INQ7_SYNC) && tp->maxoffs) {
+				tp->ic_min_sync   = (tp->minsync < np->minsync) ?
+							np->minsync : tp->minsync;
+			}
+			else 
+				tp->ic_min_sync   = 255;
+			
+			tp->period   = 1;
+			tp->widedone = 1;
+		}
+
+		if (DEBUG_FLAGS & DEBUG_IC) {
+			printk("%s: cmd->ic_nego %d, 1st byte 0x%2X\n",
+				ncr_name(np), cmd->ic_nego, cmd->cmnd[0]);
+		}
+
+		/* First command from integrity check routine will request
+		 * a PPR message.  Disable.
+		 */
+		if ((cmd->ic_nego & NS_PPR) == NS_PPR)
+			cmd->ic_nego &= ~NS_PPR;
+		/* Previous command recorded a parity or an initiator
+		 * detected error condition. Force bus to narrow for this
+		 * target. Clear flag. Negotation on request sense.
+		 * Note: kernel forces 2 bus resets :o( but clears itself out.
+		 * Minor bug? in scsi_obsolete.c (ugly)
+		 */
+		if (np->check_integ_par) {
+			printk("%s: Parity Error. Target set to narrow.\n",
+				ncr_name(np));
+			tp->ic_max_width = 0;
+			tp->widedone = tp->period = 0;
+		}
+		
+		/* In case of a bus reset, ncr_negotiate will reset 
+                 * the flags tp->widedone and tp->period to 0, forcing
+		 * a new negotiation. 
+		 */
+		no_increase = 0;
+		if (tp->widedone == 0) {
+			cmd->ic_nego = NS_WIDE;
+			tp->widedone = 1;
+			no_increase = 1;
+		}
+		else if (tp->period == 0) {
+			cmd->ic_nego = NS_SYNC;
+			tp->period = 1;
+			no_increase = 1;
+		}
+			
+		switch (cmd->ic_nego) {
+		case NS_WIDE:
+			/*
+			**	negotiate wide transfers ?
+			**	Do NOT negotiate if device only supports
+			**	narrow.	
+			*/
+			if (tp->ic_max_width | np->check_integ_par) {
+				nego = NS_WIDE;
+
+				msgptr[msglen++] = M_EXTENDED;
+				msgptr[msglen++] = 2;
+				msgptr[msglen++] = M_X_WIDE_REQ;
+				msgptr[msglen++] = cmd->ic_nego_width & tp->ic_max_width;
+			}
+			else
+				cmd->ic_nego_width &= tp->ic_max_width;
+              
+			break;
+
+		case NS_SYNC:
+			/*
+			**	negotiate synchronous transfers?
+			**	Target must support sync transfers.
+			**
+			**	If period becomes longer than max, reset to async
+			*/
+
+			if (tp->inq_byte7 & INQ7_SYNC) {
+
+				nego = NS_SYNC;
+
+				msgptr[msglen++] = M_EXTENDED;
+				msgptr[msglen++] = 3;
+				msgptr[msglen++] = M_X_SYNC_REQ;
+
+				switch (cmd->ic_nego_sync) {
+				case 2: /* increase the period */
+					if (!no_increase) {
+					  if (tp->ic_min_sync <= 0x0A)
+					      tp->ic_min_sync = 0x0C;
+					  else if (tp->ic_min_sync <= 0x0C)
+					      tp->ic_min_sync = 0x19;
+					  else if (tp->ic_min_sync <= 0x19)
+					      tp->ic_min_sync *= 2;
+					  else {
+						tp->ic_min_sync = 255;
+						cmd->ic_nego_sync = 0;
+						tp->maxoffs = 0;
+					   }
+					}
+					msgptr[msglen++] = tp->maxoffs?tp->ic_min_sync:0;
+					msgptr[msglen++] = tp->maxoffs;
+					break;
+
+				case 1: /* nego. to maximum */
+					msgptr[msglen++] = tp->maxoffs?tp->ic_min_sync:0;
+					msgptr[msglen++] = tp->maxoffs;
+					break;
+
+				case 0:	/* nego to async */
+				default:
+					msgptr[msglen++] = 0;
+					msgptr[msglen++] = 0;
+					break;
+				};
+			}
+			else
+				cmd->ic_nego_sync = 0;
+			break;
+
+		case NS_NOCHANGE:
+		default:
+			break;
+		};
+	};
+
+	cp->nego_status = nego;
+	np->check_integ_par = 0;
+
+	if (nego) {
+		tp->nego_cp = cp;
+		if (DEBUG_FLAGS & DEBUG_NEGO) {
+			ncr_print_msg(cp, nego == NS_WIDE ?
+			  "wide/narrow msgout": "sync/async msgout", msgptr);
+		};
+	};
+
+	return msglen;
+}
+
+/*==========================================================
+**
+**
+**	Prepare the next negotiation message if needed.
+**
+**	Fill in the part of message buffer that contains the 
+**	negotiation and the nego_status field of the CCB.
+**	Returns the size of the message in bytes.
+**
+**
+**==========================================================
+*/
+
+
+static int ncr_prepare_nego(ncb_p np, ccb_p cp, u_char *msgptr)
+{
+	tcb_p tp = &np->target[cp->target];
+	int msglen = 0;
+	int nego = 0;
+
+	if (tp->inq_done) {
+
+		/*
+		**	negotiate wide transfers ?
+		*/
+
+		if (!tp->widedone) {
+			if (tp->inq_byte7 & INQ7_WIDE16) {
+				nego = NS_WIDE;
+				if (tp->ic_done)
+		       			 tp->usrwide &= tp->ic_max_width;
+			} else
+				tp->widedone=1;
+
+		};
+
+		/*
+		**	negotiate synchronous transfers?
+		*/
+
+		if (!nego && !tp->period) {
+			if (tp->inq_byte7 & INQ7_SYNC) {
+				nego = NS_SYNC;
+				if ((tp->ic_done) &&
+				 	      (tp->minsync < tp->ic_min_sync))
+		       			 tp->minsync = tp->ic_min_sync;
+			} else {
+				tp->period  =0xffff;
+				PRINT_TARGET(np, cp->target);
+				printk ("target did not report SYNC.\n");
+			};
+		};
+	};
+
+	switch (nego) {
+	case NS_SYNC:
+		msgptr[msglen++] = M_EXTENDED;
+		msgptr[msglen++] = 3;
+		msgptr[msglen++] = M_X_SYNC_REQ;
+		msgptr[msglen++] = tp->maxoffs ? tp->minsync : 0;
+		msgptr[msglen++] = tp->maxoffs;
+		break;
+	case NS_WIDE:
+		msgptr[msglen++] = M_EXTENDED;
+		msgptr[msglen++] = 2;
+		msgptr[msglen++] = M_X_WIDE_REQ;
+		msgptr[msglen++] = tp->usrwide;
+		break;
+	};
+
+	cp->nego_status = nego;
+
+	if (nego) {
+		tp->nego_cp = cp;
+		if (DEBUG_FLAGS & DEBUG_NEGO) {
+			ncr_print_msg(cp, nego == NS_WIDE ?
+					  "wide msgout":"sync_msgout", msgptr);
+		};
+	};
+
+	return msglen;
+}
+
+
 
 /*==========================================================
 **
@@ -4736,7 +5033,7 @@
 	ccb_p cp;
 
 	int	segments;
-	u_char	nego, idmsg, *msgptr;
+	u_char	idmsg, *msgptr;
 	u_int  msglen;
 	int	direction;
 	u_int32	lastp, goalp;
@@ -4782,9 +5079,10 @@
 	**
 	**----------------------------------------------------
 	*/
-	if (np->settle_time && cmd->timeout_per_command >= HZ &&
-		np->settle_time > jiffies + cmd->timeout_per_command - HZ) {
-		np->settle_time = jiffies + cmd->timeout_per_command - HZ;
+	if (np->settle_time && cmd->timeout_per_command >= HZ) {
+		u_long tlimit = ktime_get(cmd->timeout_per_command - HZ);
+		if (ktime_dif(np->settle_time, tlimit) > 0)
+			np->settle_time = tlimit;
 	}
 
         if (np->settle_time || !(cp=ncr_get_ccb (np, cmd->target, cmd->lun))) {
@@ -4817,52 +5115,7 @@
 	cp->phys.header.stamp.start = jiffies;
 #endif
 
-	/*---------------------------------------------------
-	**
-	**	negotiation required?
-	**
-	**---------------------------------------------------
-	*/
-
-	nego = 0;
-
-	if ((!tp->widedone || !tp->period) && !tp->nego_cp && tp->inq_done && lp) {
-
-		/*
-		**	negotiate wide transfers ?
-		*/
-
-		if (!tp->widedone) {
-			if (tp->inq_byte7 & INQ7_WIDE16) {
-				nego = NS_WIDE;
-			} else
-				tp->widedone=1;
-		};
 
-		/*
-		**	negotiate synchronous transfers?
-		*/
-
-		if (!nego && !tp->period) {
-			if (tp->inq_byte7 & INQ7_SYNC) {
-				nego = NS_SYNC;
-			} else {
-				tp->period  =0xffff;
-				PRINT_TARGET(np, cmd->target);
-				printk ("device did not report SYNC.\n");
-			};
-		};
-
-		/*
-		**	remember nego is pending for the target.
-		**	Avoid to start a nego for all queued commands 
-		**	when tagged command queuing is enabled.
-		*/
-
-		if (nego)
-			tp->nego_cp = cp;
-	};
-
 	/*----------------------------------------------------
 	**
 	**	Build the identify / tag / sdtr message
@@ -4887,7 +5140,7 @@
 		**	Force ordered tag if necessary to avoid timeouts 
 		**	and to preserve interactivity.
 		*/
-		if (lp && time_before_eq(lp->tags_stime + 3*HZ, jiffies)) {
+		if (lp && ktime_exp(lp->tags_stime)) {
 			if (lp->tags_smap) {
 				order = M_ORDERED_TAG;
 				if ((DEBUG_FLAGS & DEBUG_TAGS)||bootverbose>2){ 
@@ -4895,7 +5148,7 @@
 					printk("ordered tag forced.\n");
 				}
 			}
-			lp->tags_stime = jiffies;
+			lp->tags_stime = ktime_get(3*HZ);
 			lp->tags_smap = lp->tags_umap;
 		}
 
@@ -4922,34 +5175,6 @@
 		msgptr[msglen++] = (cp->tag << 1) + 1;
 	}
 
-	switch (nego) {
-	case NS_SYNC:
-		msgptr[msglen++] = M_EXTENDED;
-		msgptr[msglen++] = 3;
-		msgptr[msglen++] = M_X_SYNC_REQ;
-		msgptr[msglen++] = tp->maxoffs ? tp->minsync : 0;
-		msgptr[msglen++] = tp->maxoffs;
-		if (DEBUG_FLAGS & DEBUG_NEGO) {
-			PRINT_ADDR(cp->cmd);
-			printk ("sync msgout: ");
-			ncr_show_msg (&cp->scsi_smsg [msglen-5]);
-			printk (".\n");
-		};
-		break;
-	case NS_WIDE:
-		msgptr[msglen++] = M_EXTENDED;
-		msgptr[msglen++] = 2;
-		msgptr[msglen++] = M_X_WIDE_REQ;
-		msgptr[msglen++] = tp->usrwide;
-		if (DEBUG_FLAGS & DEBUG_NEGO) {
-			PRINT_ADDR(cp->cmd);
-			printk ("wide msgout: ");
-			ncr_show_msg (&cp->scsi_smsg [msglen-4]);
-			printk (".\n");
-		};
-		break;
-	};
-
 	/*----------------------------------------------------
 	**
 	**	Build the data descriptors
@@ -4991,6 +5216,78 @@
 		}
 	}
 
+	/*---------------------------------------------------
+	**
+	**	negotiation required?
+	**
+	**	(nego_status is filled by ncr_prepare_nego())
+	**
+	**---------------------------------------------------
+	*/
+
+	cp->nego_status = 0;
+
+	if ((np->check_integrity && tp->ic_done) || !np->check_integrity) {
+		 if ((!tp->widedone || !tp->period) && !tp->nego_cp && lp) {
+			msglen += ncr_prepare_nego (np, cp, msgptr + msglen);
+		 }
+	}
+	else if (np->check_integrity && (cmd->ic_in_progress)) { 
+		msglen += ncr_ic_nego (np, cp, cmd, msgptr + msglen);
+        }
+	else if (np->check_integrity && cmd->ic_complete) {
+                /*
+                 * Midlayer signal to the driver that all of the scsi commands
+                 * for the integrity check have completed. Save the negotiated
+                 * parameters (extracted from sval and wval). 
+                 */ 
+
+		{
+			u_char idiv;
+			idiv = (tp->wval>>4) & 0x07;
+			if ((tp->sval&0x1f) && idiv )
+				tp->period = (((tp->sval>>5)+4)  
+						*div_10M[idiv-1])/np->clock_khz;
+			else
+				tp->period = 0xffff;
+		}
+		/*
+		 * tp->period contains 10 times the transfer period, 
+		 * which itself is 4 * the requested negotiation rate.
+		 */
+		if	(tp->period <= 250)	tp->ic_min_sync = 10;
+		else if	(tp->period <= 303)	tp->ic_min_sync = 11;
+		else if	(tp->period <= 500)	tp->ic_min_sync = 12;
+		else				
+				tp->ic_min_sync = (tp->period + 40 - 1) / 40;
+
+
+		/*
+                 * Negotiation for this target it complete.
+                 */
+		tp->ic_max_width =  (tp->wval & EWS) ? 1: 0;
+		tp->ic_done = 1;
+		tp->widedone = 1;
+
+		printk("%s: Integrity Check Complete: \n", ncr_name(np)); 
+
+		printk("%s: %s %s SCSI", ncr_name(np), 
+				(tp->sval&0x1f)?"SYNC":"ASYNC",
+				tp->ic_max_width?"WIDE":"NARROW");
+
+		if (tp->sval&0x1f) {
+                        u_long mbs = 10000 * (tp->ic_max_width + 1);
+
+                        printk(" %d.%d  MB/s", 
+                                (int) (mbs / tp->period), (int) (mbs % tp->period));
+
+			printk(" (%d ns, %d offset)\n", 
+				  tp->period/10, tp->sval&0x1f);
+		}
+		else
+                        printk(" %d MB/s. \n ", (tp->ic_max_width+1)*5);
+        }
+
 	/*----------------------------------------------------
 	**
 	**	Set the SAVED_POINTER.
@@ -5095,12 +5392,11 @@
 	**	status
 	*/
 	cp->actualquirks		= tp->quirks;
-	cp->host_status			= nego ? HS_NEGOTIATE : HS_BUSY;
+	cp->host_status			= cp->nego_status ? HS_NEGOTIATE : HS_BUSY;
 	cp->scsi_status			= S_ILLEGAL;
 	cp->parity_status		= 0;
 
 	cp->xerr_status			= XE_OK;
-	cp->nego_status			= nego;
 #if 0
 	cp->sync_status			= tp->sval;
 	cp->wide_status			= tp->wval;
@@ -5116,12 +5412,6 @@
 	/*
 	**	activate this job.
 	*/
-
-	/* Compute a time limit greater than the middle-level driver one */
-	if (cmd->timeout_per_command > 0)
-		cp->tlimit	= jiffies + cmd->timeout_per_command + HZ;
-	else
-		cp->tlimit	= jiffies + 86400 * HZ;/* No timeout=24 hours */
 	cp->magic		= CCB_MAGIC;
 
 	/*
@@ -5228,7 +5518,7 @@
 	u_int32 term;
 	int retv = 0;
 
-	np->settle_time	= jiffies + settle_delay * HZ;
+	np->settle_time	= ktime_get(settle_delay * HZ);
 
 	if (bootverbose > 1)
 		printk("%s: resetting, "
@@ -5403,7 +5693,6 @@
 	**	script to abort the command.
 	*/
 
-	cp->tlimit = 0;
 	switch(cp->host_status) {
 	case HS_BUSY:
 	case HS_NEGOTIATE:
@@ -5601,7 +5890,7 @@
 #endif
 
 	if (DEBUG_FLAGS & DEBUG_TINY)
-		printk ("CCB=%lx STAT=%x/%x\n", (unsigned long)cp & 0xfff,
+		printk ("CCB=%lx STAT=%x/%x\n", (unsigned long)cp,
 			cp->host_status,cp->scsi_status);
 
 	/*
@@ -5750,7 +6039,13 @@
 			for (i=0; i<14; i++) printk (" %x", *p++);
 			printk (".\n");
 		}
-
+	} else if ((cp->host_status == HS_COMPLETE)
+		&& (cp->scsi_status == S_CONFLICT)) {
+		/*
+		**   Reservation Conflict condition code
+		*/
+		cmd->result = ScsiResult(DID_OK, S_CONFLICT);
+	
 	} else if ((cp->host_status == HS_COMPLETE)
 		&& (cp->scsi_status == S_BUSY ||
 		    cp->scsi_status == S_QUEUE_FULL)) {
@@ -6335,7 +6630,9 @@
 	/*
 	**	Bells and whistles   ;-)
 	*/
-	PRINT_TARGET(np, target);
+	if (DEBUG_FLAGS & DEBUG_NEGO) {
+		PRINT_TARGET(np, target);
+	}
 	if (sxfer & 0x01f) {
 		unsigned f10 = 100000 << (tp->widedone ? tp->widedone -1 : 0);
 		unsigned mb10 = (f10 + tp->period/2) / tp->period;
@@ -6349,17 +6646,19 @@
 		/*
 		**	Bells and whistles   ;-)
 		*/
-		if	(tp->period < 500)	scsi = "FAST-40";
-		else if	(tp->period < 1000)	scsi = "FAST-20";
-		else if	(tp->period < 2000)	scsi = "FAST-10";
-		else				scsi = "FAST-5";
-
-		printk ("%s %sSCSI %d.%d MB/s (%d ns, offset %d)\n", scsi,
-			tp->widedone > 1 ? "WIDE " : "",
-			mb10 / 10, mb10 % 10, tp->period / 10, sxfer & 0x1f);
-	} else
+		if (DEBUG_FLAGS & DEBUG_NEGO) {
+			if	(tp->period < 500)	scsi = "FAST-40";
+			else if	(tp->period < 1000)	scsi = "FAST-20";
+			else if	(tp->period < 2000)	scsi = "FAST-10";
+			else				scsi = "FAST-5";
+
+			printk ("%s %sSCSI %d.%d MB/s (%d ns, offset %d)\n", scsi,
+					tp->widedone > 1 ? "WIDE " : "",
+					mb10 / 10, mb10 % 10, tp->period / 10, sxfer & 0x1f);
+		}
+	} else if (DEBUG_FLAGS & DEBUG_NEGO) {
 		printk ("%sasynchronous.\n", tp->widedone > 1 ? "wide " : "");
-
+	}
 	/*
 	**	set actual value and sync_status
 	**	patch ALL ccbs of this target.
@@ -6620,7 +6919,7 @@
 
 static void ncr_timeout (ncb_p np)
 {
-	u_long	thistime = jiffies;
+	u_long	thistime = ktime_get(0);
 
 	/*
 	**	If release process in progress, let's go
@@ -6633,7 +6932,7 @@
 		return;
 	}
 
-	np->timer.expires = jiffies + SCSI_NCR_TIMER_INTERVAL;
+	np->timer.expires = ktime_get(SCSI_NCR_TIMER_INTERVAL);
 	add_timer(&np->timer);
 
 	/*
@@ -6927,8 +7226,9 @@
 	**	We are more soft for UDC.
 	**=========================================================
 	*/
-	if (jiffies - np->regtime > 10*HZ) {
-		np->regtime = jiffies;
+
+	if (ktime_exp(np->regtime)) {
+		np->regtime = ktime_get(10*HZ);
 		for (i = 0; i<sizeof(np->regdump); i++)
 			((char*)&np->regdump)[i] = INB_OFF(i);
 		np->regdump.nc_dstat = dstat;
@@ -7044,7 +7344,7 @@
 		**	Suspend command processing for 1 second and 
 		**	reinitialize all except the chip.
 		*/
-		np->settle_time	= jiffies + HZ;
+		np->settle_time	= ktime_get(1*HZ);
 		ncr_init (np, 0, bootverbose ? "scsi mode change" : NULL, HS_RESET);
 		return 1;
 	}
@@ -7104,6 +7404,12 @@
 		msg = M_ID_ERROR;
 
 	/*
+	**      Save error message. For integrity check use only.
+	*/
+	if (np->check_integrity)
+		np->check_integ_par = msg;
+
+	/*
 	 *	If the NCR stopped on a MOVE ^ DATA_IN, we jump to a 
 	 *	script that will ignore all data in bytes until phase 
 	 *	change, since we are not sure the chip will wait the phase 
@@ -7609,6 +7915,16 @@
 	return (1);
 }
 
+static void ncr_print_msg ( ccb_p cp, char *label, u_char *msg)
+{
+	if (cp)
+		PRINT_ADDR(cp->cmd);
+	if (label)
+		printk("%s: ", label);
+	
+	(void) ncr_show_msg (msg);
+	printk(".\n");
+}
 
 void ncr_int_sir (ncb_p np)
 {
@@ -8164,7 +8480,7 @@
 	if (lp) {
 		if (tag != NO_TAG) {
 			++lp->ia_tag;
-			if (lp->ia_tag == SCSI_NCR_MAX_TAGS)
+			if (lp->ia_tag == MAX_TAGS)
 				lp->ia_tag = 0;
 			lp->tags_umap |= (((tagmap_t) 1) << tag);
 		}
@@ -8212,7 +8528,7 @@
 	if (lp) {
 		if (cp->tag != NO_TAG) {
 			lp->cb_tags[lp->if_tag++] = cp->tag;
-			if (lp->if_tag == SCSI_NCR_MAX_TAGS)
+			if (lp->if_tag == MAX_TAGS)
 				lp->if_tag = 0;
 			lp->tags_umap &= ~(((tagmap_t) 1) << cp->tag);
 			lp->tags_smap &= lp->tags_umap;
@@ -8593,10 +8909,10 @@
 		for (i = 0 ; i < 64 ; i++)
 			lp->jump_ccb[i] =
 				cpu_to_scr(NCB_SCRIPTH_PHYS (np, bad_i_t_l_q));
-		for (i = 0 ; i < SCSI_NCR_MAX_TAGS ; i++)
+		for (i = 0 ; i < MAX_TAGS ; i++)
 			lp->cb_tags[i] = i;
-		lp->maxnxs = SCSI_NCR_MAX_TAGS;
-		lp->tags_stime = jiffies;
+		lp->maxnxs = MAX_TAGS;
+		lp->tags_stime = ktime_get(3*HZ);
 	}
 
 	/*
@@ -8691,9 +9007,7 @@
 */
 
 #ifndef NCR_IOMAPPED
-__initfunc(
-static int ncr_regtest (struct ncb* np)
-)
+static int __init ncr_regtest (struct ncb* np)
 {
 	register volatile u_int32 data;
 	/*
@@ -8717,9 +9031,7 @@
 }
 #endif
 
-__initfunc(
-static int ncr_snooptest (struct ncb* np)
-)
+static int __init ncr_snooptest (struct ncb* np)
 {
 	u_int32	ncr_rd, ncr_wr, ncr_bk, host_rd, host_wr, pc;
 	int	i, err=0;
@@ -8982,11 +9294,10 @@
 /*
  *	calculate NCR SCSI clock frequency (in KHz)
  */
-__initfunc(
-static unsigned ncrgetfreq (ncb_p np, int gen)
-)
+static unsigned __init ncrgetfreq (ncb_p np, int gen)
 {
 	unsigned ms = 0;
+	char count = 0;
 
 	/*
 	 * Measure GEN timer delay in order 
@@ -9011,8 +9322,10 @@
 	OUTB (nc_scntl3, 4);	/* set pre-scaler to divide by 3 */
 	OUTB (nc_stime1, 0);	/* disable general purpose timer */
 	OUTB (nc_stime1, gen);	/* set to nominal delay of 1<<gen * 125us */
-	while (!(INW(nc_sist) & GEN) && ms++ < 100000)
-		UDELAY (1000);	/* count ms */
+	while (!(INW(nc_sist) & GEN) && ms++ < 100000) {
+		for (count = 0; count < 10; count ++)
+			UDELAY (100);	/* count ms */
+	}
 	OUTB (nc_stime1, 0);	/* disable general purpose timer */
  	/*
  	 * set prescaler to divide by whatever 0 means
@@ -9032,9 +9345,7 @@
 /*
  *	Get/probe NCR SCSI clock frequency
  */
-__initfunc(
-static void ncr_getclock (ncb_p np, int mult)
-)
+static void __init ncr_getclock (ncb_p np, int mult)
 {
 	unsigned char scntl3 = INB(nc_scntl3);
 	unsigned char stest1 = INB(nc_stest1);
@@ -9122,14 +9433,12 @@
 #define	ARG_SEP	','
 #endif
 
-__initfunc(
-void ncr53c8xx_setup(char *str, int *ints)
-)
+int __init ncr53c8xx_setup(char *str)
 {
 #ifdef SCSI_NCR_BOOT_COMMAND_LINE_SUPPORT
 	char *cur = str;
 	char *pc, *pv;
-	int val;
+	unsigned long val;
 	int base;
 	int c;
 	int xi = 0;
@@ -9217,8 +9526,15 @@
 			++cur;
 	}
 #endif /* SCSI_NCR_BOOT_COMMAND_LINE_SUPPORT */
+	return 0;
 }
 
+#if LINUX_VERSION_CODE >= LinuxVersionCode(2,3,13)
+#ifndef MODULE
+__setup("ncr53c8xx=", ncr53c8xx_setup);
+#endif
+#endif
+
 static int ncr53c8xx_pci_init(Scsi_Host_Template *tpnt,
 	     uchar bus, uchar device_fn, ncr_device *device);
 
@@ -9237,9 +9553,7 @@
 **   Returns the number of boards successfully attached.
 */
 
-__initfunc(
-static void ncr_print_driver_setup(void)
-)
+static void __init ncr_print_driver_setup(void)
 {
 #define YesNo(y)	y ? 'y' : 'n'
 	printk ("ncr53c8xx: setup=disc:%c,specf:%d,ultra:%d,tags:%d,sync:%d,"
@@ -9278,10 +9592,8 @@
 static ushort	ncr_chip_ids[]   __initdata	= SCSI_NCR_CHIP_IDS;
 
 #ifdef SCSI_NCR_NVRAM_SUPPORT
-__initfunc(
-static int
+static int __init 
 ncr_attach_using_nvram(Scsi_Host_Template *tpnt, int nvram_index, int count, ncr_device device[])
-)
 {
 	int i, j;
 	int attach_count = 0;
@@ -9362,9 +9674,7 @@
 }
 #endif /* SCSI_NCR_NVRAM_SUPPORT */
 
-__initfunc(
-int ncr53c8xx_detect(Scsi_Host_Template *tpnt)
-)
+int __init ncr53c8xx_detect(Scsi_Host_Template *tpnt)
 {
 	int i, j;
 	int chips;
@@ -9394,7 +9704,7 @@
 
 #if	defined(SCSI_NCR_BOOT_COMMAND_LINE_SUPPORT) && defined(MODULE)
 if (ncr53c8xx)
-	ncr53c8xx_setup(ncr53c8xx, (int *) 0);
+	ncr53c8xx_setup(ncr53c8xx);
 #endif
 
 	if (initverbose >= 2)
@@ -9441,10 +9751,30 @@
 #else
 			device[count].nvram = 0;
 #endif
+			device[count].host_id = driver_setup.host_id;
 			if (ncr53c8xx_pci_init(tpnt, bus, device_fn, &device[count])) {
 				device[count].nvram = 0;
 				continue;
 			}
+
+			/*
+			 * LH4 Workaround - if two devices have same bus and
+			 *	device function, we have a copy. Throw away.
+			 */
+
+			{
+				int jj;
+				for (jj=0; jj < count; jj++) {
+					if ( (device[jj].slot.bus == bus) &&
+					     (device[jj].slot.device_fn == device_fn))
+						break;
+				}
+				if (jj != count) {
+					device[count].nvram = 0;
+					continue;
+				}
+			}
+			
 #ifdef SCSI_NCR_NVRAM_SUPPORT
 			if (device[count].nvram) {
 				++k;
@@ -9494,10 +9824,8 @@
 **
 */
 #if LINUX_VERSION_CODE <= LinuxVersionCode(2,1,92)
-__initfunc(
-static int 
+static int __init 
 pci_read_base_address(u_char bus, u_char device_fn, int offset, u_long *base)
-)
 {
 	u_int32 tmp;
 
@@ -9513,11 +9841,9 @@
 	}
 	return offset;
 }
-#else	/* LINUX_VERSION_CODE > LinuxVersionCode(2,1,92) */
-__initfunc(
-static int 
+#elif	LINUX_VERSION_CODE <= LinuxVersionCode(2,3,12)
+static int __init 
 pci_get_base_address(struct pci_dev *pdev, int index, u_long *base)
-)
 {
 	*base = pdev->base_address[index++];
 	if ((*base & 0x7) == 0x4) {
@@ -9528,6 +9854,15 @@
 	}
 	return index;
 }
+#else	/* LINUX_VERSION_CODE > LinuxVersionCode(2,3,12) */
+static int __init 
+pci_get_base_address(struct pci_dev *pdev, int index, u_long *base)
+{
+	*base = pdev->resource[index].start;
+	if ((pdev->resource[index].flags & 0x7) == 0x4)
+		++index;
+	return ++index;
+}
 #endif
 
 /*
@@ -9536,10 +9871,8 @@
 **   been detected.
 */
 
-__initfunc(
-static int ncr53c8xx_pci_init(Scsi_Host_Template *tpnt,
+static int __init ncr53c8xx_pci_init(Scsi_Host_Template *tpnt,
 			      uchar bus, uchar device_fn, ncr_device *device)
-)
 {
 	ushort vendor_id, device_id, command;
 	uchar cache_line_size, latency_timer;
@@ -9597,9 +9930,11 @@
 	}
 	/*
 	 *	Check if the chip is supported
+	 *	The C1010 is not supported by this driver.
 	 */
 	chip = 0;
-	for (i = 0; i < sizeof(ncr_chip_table)/sizeof(ncr_chip_table[0]); i++) {
+	if (device_id != PCI_DEVICE_ID_LSI_53C1010) {
+	    for (i = 0; i < sizeof(ncr_chip_table)/sizeof(ncr_chip_table[0]); i++) {
 		if (device_id != ncr_chip_table[i].device_id)
 			continue;
 		if (revision > ncr_chip_table[i].revision_id)
@@ -9608,6 +9943,7 @@
 		memcpy(chip, &ncr_chip_table[i], sizeof(*chip));
 		chip->revision_id = revision;
 		break;
+	    }
 	}
 
 #if defined(__i386__)
@@ -9736,8 +10072,7 @@
 		/* PCI_CACHE_LINE_SIZE value is in 32-bit words. */
 		cache_line_size = 64 / sizeof(u_int32);
 		if (initverbose >= 2)
-			printk("ncr53c8xx: setting PCI_CACHE_LINE_SIZE to %d (fixup)\n",
-			       cache_line_size);
+			printk("ncr53c8xx: setting PCI_CACHE_LINE_SIZE to %d (fixup)\n", cache_line_size);
 		pcibios_write_config_byte(bus, device_fn,
 					  PCI_CACHE_LINE_SIZE, cache_line_size);
 		pcibios_read_config_byte(bus, device_fn,
@@ -9745,15 +10080,9 @@
 	}
 
 	if (!latency_timer) {
-		unsigned char min_gnt;
-
-		pcibios_read_config_byte(bus, device_fn,
-					 PCI_MIN_GNT, &min_gnt);
-		if (min_gnt == 0)
-			latency_timer = 128;
-		else
-			latency_timer = ((min_gnt << 3) & 0xff);
-		printk("ncr53c8xx: setting PCI_LATENCY_TIMER to %d bus clocks (fixup)\n", latency_timer);
+		latency_timer = 128;
+		if (initverbose >= 2)
+			printk("ncr53c8xx: setting PCI_LATENCY_TIMER to %d bus clocks (fixup)\n", latency_timer);
 		pcibios_write_config_byte(bus, device_fn,
 					  PCI_LATENCY_TIMER, latency_timer);
 		pcibios_read_config_byte(bus, device_fn,
@@ -9764,27 +10093,13 @@
 	/*
 	 * Check availability of IO space, memory space and master capability.
 	 */
-	if (command & PCI_COMMAND_IO) { 
-		if ((io_port & 3) != 1) {
-			printk("ncr53c8xx: disabling I/O mapping since base address 0 (0x%x)\n"
-				"           bits 0..1 indicate a non-IO mapping\n", (int) io_port);
-			io_port = 0;
-		}
-		else
-			io_port &= PCI_BASE_ADDRESS_IO_MASK;
-	}
+	if (command & PCI_COMMAND_IO)
+		io_port &= PCI_BASE_ADDRESS_IO_MASK;
 	else
 		io_port = 0;
 
-	if (command & PCI_COMMAND_MEMORY) {
-		if ((base & PCI_BASE_ADDRESS_SPACE) != PCI_BASE_ADDRESS_SPACE_MEMORY) {
-			printk("ncr53c8xx: disabling memory mapping since base address 1\n"
-				"            contains a non-memory mapping\n");
-			base = 0;
-		}
-		else 
-			base &= PCI_BASE_ADDRESS_MEM_MASK;
-	}
+	if (command & PCI_COMMAND_MEMORY)
+		base &= PCI_BASE_ADDRESS_MEM_MASK;
 	else
 		base = 0;
 	
@@ -10066,8 +10381,8 @@
 		device->queue_depth = numtags;
 		if (device->queue_depth < 2)
 			device->queue_depth = 2;
-		if (device->queue_depth > SCSI_NCR_MAX_TAGS)
-			device->queue_depth = SCSI_NCR_MAX_TAGS;
+		if (device->queue_depth > MAX_TAGS)
+			device->queue_depth = MAX_TAGS;
 
 		/*
 		**	Since the queue depth is not tunable under Linux,
@@ -10092,15 +10407,7 @@
 */
 const char *ncr53c8xx_info (struct Scsi_Host *host)
 {
-#ifdef __sparc__
-	/* Ok to do this on all archs? */
-	static char buffer[80];
-	ncb_p np = ((struct host_data *) host->hostdata)->ncb;
-	sprintf (buffer, "%s\nPCI bus %02x device %02x", SCSI_NCR_DRIVER_NAME, np->pci_bus, np->pci_devfn);
-	return buffer;
-#else
 	return SCSI_NCR_DRIVER_NAME;
-#endif
 }
 
 /*
@@ -10558,8 +10865,6 @@
 				uc->data |= DEBUG_ALLOC;
 			else if	((arg_len = is_keyword(ptr, len, "phase")))
 				uc->data |= DEBUG_PHASE;
-			else if	((arg_len = is_keyword(ptr, len, "poll")))
-				uc->data |= DEBUG_POLL;
 			else if	((arg_len = is_keyword(ptr, len, "queue")))
 				uc->data |= DEBUG_QUEUE;
 			else if	((arg_len = is_keyword(ptr, len, "result")))
@@ -10576,10 +10881,6 @@
 				uc->data |= DEBUG_NEGO;
 			else if	((arg_len = is_keyword(ptr, len, "tags")))
 				uc->data |= DEBUG_TAGS;
-			else if	((arg_len = is_keyword(ptr, len, "freeze")))
-				uc->data |= DEBUG_FREEZE;
-			else if	((arg_len = is_keyword(ptr, len, "restart")))
-				uc->data |= DEBUG_RESTART;
 			else
 				return -EINVAL;
 			ptr += arg_len; len -= arg_len;
@@ -10685,8 +10986,6 @@
 	copy_info(&info, "  IO port address 0x%lx, ", (u_long) np->port);
 #ifdef __sparc__
 	copy_info(&info, "IRQ number %s\n", __irq_itoa(np->irq));
-	/* Ok to do this on all archs? */
-	copy_info(&info, "PCI bus %02x device %02x\n", np->pci_bus, np->pci_devfn);
 #else
 	copy_info(&info, "IRQ number %d\n", (int) np->irq);
 #endif
@@ -10697,7 +10996,7 @@
 		                  (u_long) np->reg);
 #endif
 	copy_info(&info, "  Synchronous period factor %d, ", (int) np->minsync);
-	copy_info(&info, "max commands per lun %d\n", SCSI_NCR_MAX_TAGS);
+	copy_info(&info, "max commands per lun %d\n", MAX_TAGS);
 
 	if (driver_setup.debug || driver_setup.verbose > 1) {
 		copy_info(&info, "  Debug flags 0x%x, ", driver_setup.debug);
@@ -10810,9 +11109,7 @@
 static void nvram_stop(ncr_slot *np, u_char *gpreg);
 static void nvram_setBit(ncr_slot *np, u_char write_bit, u_char *gpreg, int bit_mode);
 
-__initfunc(
-static int ncr_get_Symbios_nvram (ncr_slot *np, Symbios_nvram *nvram)
-)
+static int __init ncr_get_Symbios_nvram (ncr_slot *np, Symbios_nvram *nvram)
 {
 	static u_char Symbios_trailer[6] = {0xfe, 0xfe, 0, 0, 0, 0};
 	u_char	gpcntl, gpreg;
@@ -10901,9 +11198,8 @@
 /*
  * Read Symbios NvRAM data and compute checksum.
  */
-__initfunc(
-static u_short nvram_read_data(ncr_slot *np, u_char *data, int len, u_char *gpreg, u_char *gpcntl)
-)
+static u_short __init 
+nvram_read_data(ncr_slot *np, u_char *data, int len, u_char *gpreg, u_char *gpcntl)
 {
 	int	x;
 	u_short	csum;
@@ -10920,9 +11216,7 @@
 /*
  * Send START condition to NVRAM to wake it up.
  */
-__initfunc(
-static void nvram_start(ncr_slot *np, u_char *gpreg)
-)
+static void __init nvram_start(ncr_slot *np, u_char *gpreg)
 {
 	nvram_setBit(np, 1, gpreg, SET_BIT);
 	nvram_setBit(np, 0, gpreg, SET_CLK);
@@ -10934,9 +11228,8 @@
  * WRITE a byte to the NVRAM and then get an ACK to see it was accepted OK,
  * GPIO0 must already be set as an output
  */
-__initfunc(
-static void nvram_write_byte(ncr_slot *np, u_char *ack_data, u_char write_data, u_char *gpreg, u_char *gpcntl)
-)
+static void __init 
+nvram_write_byte(ncr_slot *np, u_char *ack_data, u_char write_data, u_char *gpreg, u_char *gpcntl)
 {
 	int x;
 	
@@ -10950,9 +11243,8 @@
  * READ a byte from the NVRAM and then send an ACK to say we have got it,
  * GPIO0 must already be set as an input
  */
-__initfunc(
-static void nvram_read_byte(ncr_slot *np, u_char *read_data, u_char ack_data, u_char *gpreg, u_char *gpcntl)
-)
+static void __init 
+nvram_read_byte(ncr_slot *np, u_char *read_data, u_char ack_data, u_char *gpreg, u_char *gpcntl)
 {
 	int x;
 	u_char read_bit;
@@ -10970,9 +11262,8 @@
  * Output an ACK to the NVRAM after reading,
  * change GPIO0 to output and when done back to an input
  */
-__initfunc(
-static void nvram_writeAck(ncr_slot *np, u_char write_bit, u_char *gpreg, u_char *gpcntl)
-)
+static void __init 
+nvram_writeAck(ncr_slot *np, u_char write_bit, u_char *gpreg, u_char *gpcntl)
 {
 	OUTB (nc_gpcntl, *gpcntl & 0xfe);
 	nvram_doBit(np, 0, write_bit, gpreg);
@@ -10983,9 +11274,8 @@
  * Input an ACK from NVRAM after writing,
  * change GPIO0 to input and when done back to an output
  */
-__initfunc(
-static void nvram_readAck(ncr_slot *np, u_char *read_bit, u_char *gpreg, u_char *gpcntl)
-)
+static void __init 
+nvram_readAck(ncr_slot *np, u_char *read_bit, u_char *gpreg, u_char *gpcntl)
 {
 	OUTB (nc_gpcntl, *gpcntl | 0x01);
 	nvram_doBit(np, read_bit, 1, gpreg);
@@ -10996,9 +11286,7 @@
  * Read or write a bit to the NVRAM,
  * read if GPIO0 input else write if GPIO0 output
  */
-__initfunc(
-static void nvram_doBit(ncr_slot *np, u_char *read_bit, u_char write_bit, u_char *gpreg)
-)
+static void __init nvram_doBit(ncr_slot *np, u_char *read_bit, u_char write_bit, u_char *gpreg)
 {
 	nvram_setBit(np, write_bit, gpreg, SET_BIT);
 	nvram_setBit(np, 0, gpreg, SET_CLK);
@@ -11011,9 +11299,7 @@
 /*
  * Send STOP condition to NVRAM - puts NVRAM to sleep... ZZzzzz!!
  */
-__initfunc(
-static void nvram_stop(ncr_slot *np, u_char *gpreg)
-)
+static void __init nvram_stop(ncr_slot *np, u_char *gpreg)
 {
 	nvram_setBit(np, 0, gpreg, SET_CLK);
 	nvram_setBit(np, 1, gpreg, SET_BIT);
@@ -11022,9 +11308,8 @@
 /*
  * Set/clear data/clock bit in GPIO0
  */
-__initfunc(
-static void nvram_setBit(ncr_slot *np, u_char write_bit, u_char *gpreg, int bit_mode)
-)
+static void __init 
+nvram_setBit(ncr_slot *np, u_char write_bit, u_char *gpreg, int bit_mode)
 {
 	UDELAY (5);
 	switch (bit_mode){
@@ -11075,9 +11360,7 @@
 static void Tnvram_Stop(ncr_slot *np, u_char *gpreg);
 static void Tnvram_Clk(ncr_slot *np, u_char *gpreg);
 
-__initfunc(
-static int ncr_get_Tekram_nvram (ncr_slot *np, Tekram_nvram *nvram)
-)
+static int __init ncr_get_Tekram_nvram (ncr_slot *np, Tekram_nvram *nvram)
 {
 	u_char gpcntl, gpreg;
 	u_char old_gpcntl, old_gpreg;
@@ -11112,9 +11395,8 @@
 /*
  * Read Tekram NvRAM data and compute checksum.
  */
-__initfunc(
-static u_short Tnvram_read_data(ncr_slot *np, u_short *data, int len, u_char *gpreg)
-)
+static u_short __init 
+Tnvram_read_data(ncr_slot *np, u_short *data, int len, u_char *gpreg)
 {
 	u_char	read_bit;
 	u_short	csum;
@@ -11139,9 +11421,7 @@
 /*
  * Send read command and address to NVRAM
  */
-__initfunc(
-static void Tnvram_Send_Command(ncr_slot *np, u_short write_data, u_char *read_bit, u_char *gpreg)
-)
+static void __init Tnvram_Send_Command(ncr_slot *np, u_short write_data, u_char *read_bit, u_char *gpreg)
 {
 	int x;
 
@@ -11155,9 +11435,7 @@
 /*
  * READ a byte from the NVRAM
  */
-__initfunc(
-static void Tnvram_Read_Word(ncr_slot *np, u_short *nvram_data, u_char *gpreg)
-)
+static void __init Tnvram_Read_Word(ncr_slot *np, u_short *nvram_data, u_char *gpreg)
 {
 	int x;
 	u_char read_bit;
@@ -11176,9 +11454,8 @@
 /* 
  * Read bit from NVRAM
  */
-__initfunc(
-static void Tnvram_Read_Bit(ncr_slot *np, u_char *read_bit, u_char *gpreg)
-)
+static void __init 
+Tnvram_Read_Bit(ncr_slot *np, u_char *read_bit, u_char *gpreg)
 {
 	UDELAY (2);
 	Tnvram_Clk(np, gpreg);
@@ -11188,9 +11465,8 @@
 /*
  * Write bit to GPIO0
  */
-__initfunc(
-static void Tnvram_Write_Bit(ncr_slot *np, u_char write_bit, u_char *gpreg)
-)
+static void __init 
+Tnvram_Write_Bit(ncr_slot *np, u_char write_bit, u_char *gpreg)
 {
 	if (write_bit & 0x01)
 		*gpreg |= 0x02;
@@ -11208,9 +11484,7 @@
 /*
  * Send STOP condition to NVRAM - puts NVRAM to sleep... ZZZzzz!!
  */
-__initfunc(
-static void Tnvram_Stop(ncr_slot *np, u_char *gpreg)
-)
+static void __init Tnvram_Stop(ncr_slot *np, u_char *gpreg)
 {
 	*gpreg &= 0xef;
 	OUTB (nc_gpreg, *gpreg);
@@ -11222,9 +11496,7 @@
 /*
  * Pulse clock bit in GPIO0
  */
-__initfunc(
-static void Tnvram_Clk(ncr_slot *np, u_char *gpreg)
-)
+static void __init Tnvram_Clk(ncr_slot *np, u_char *gpreg)
 {
 	OUTB (nc_gpreg, *gpreg | 0x04);
 	UDELAY (2);
Index: oldkernel/linux/drivers/scsi/scsi.c
diff -u linux/drivers/scsi/scsi.c:1.3 linux/drivers/scsi/scsi.c:1.4
--- linux/drivers/scsi/scsi.c:1.3	Thu Jun  1 15:45:18 2000
+++ linux/drivers/scsi/scsi.c	Fri Jul  7 15:36:43 2000
@@ -115,6 +115,7 @@
 #define BLIST_ISDISK	0x100
 #define BLIST_ISROM	0x200
 #define BLIST_GHOST	0x400
+#define BLIST_NO_IC2	0x800
 
 /*
  * Data declarations.
@@ -190,6 +191,10 @@
 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);
+unsigned char integ_check_basic (struct Scsi_Host *shpnt,
+                 Scsi_Cmnd * SCpnt, char * scsi_result, unsigned char *ppr);
+unsigned char integ_check_enhanced (struct Scsi_Host *shpnt,
+                 Scsi_Cmnd * SCpnt, char * scsi_result, unsigned char ppr);
 void        scsi_build_commandblocks(Scsi_Device * SDpnt);
 static int scsi_unregister_device(struct Scsi_Device_Template * tpnt);
 
@@ -302,6 +307,10 @@
 {"NEC","PD-1 ODX654P","*", BLIST_FORCELUN | BLIST_SINGLELUN},
 {"MATSHITA","PD-1","*", BLIST_FORCELUN | BLIST_SINGLELUN},
 {"iomega","jaz 1GB","J.86", BLIST_NOTQ | BLIST_NOLUN},
+{"MICROP","4345NV","AV10",BLIST_NO_IC2},	/* Locks up if write buffer followed
+ 						   by read buffer */
+{"PIONEER","CD-ROM DR-966","*",BLIST_NO_IC2},	/* Mishandles read buffer cmd */
+{"Seagate","STT20000N","*",BLIST_NO_IC2},       /* Mishandles write buffer cmd */
 {"CREATIVE","DVD-RAM RAM","*", BLIST_GHOST},
 {"MATSHITA","PD-2 LF-D100","*", BLIST_GHOST},
 {"AOpen","PD-2 DVD-520S","*", BLIST_GHOST},
@@ -928,7 +937,88 @@
     }
   }
 
+
   /*
+   * Integrity checking, verifying the integrity of the
+   * scsi bus at the desired width and speed, is part of 
+   * the SCSI-3 specification. Details are contained in
+   * the T10/98-235 and 99-242r2 documents.  Command or 
+   * compare failures result in reducing the bus width 
+   * and/or speed until successful transmission and 
+   * comparison occurs.
+   *
+   * The T10/98-235 r2 specifies basic, enhanced and margined 
+   * tests. Only the basic and enhanced are implemented.
+   *
+   * To utilize this code, low-level driver must initialize
+   * the flag   check_integrity.
+   *
+   * The test functions (integ_check_basic, integ_check_enhan)
+   * are written for one negotiation per command.  
+   * However, the flags are set-up for a low-level
+   * driver to issue multiple negotiations per command or
+   * to issue PPR negotiation sequences.
+   *
+   * Detailed comments on the negotiation sequences
+   * are included prior to integ_check_basic function.
+   */
+
+  if ((shpnt->check_integrity) && (lun == 0)) {
+    unsigned char ic_do_ppr;
+
+    SCpnt->ic_in_progress = 1;
+    SCpnt->ic_complete    = 0;
+
+    /*
+     * Basic test. 
+     */
+    if (!(integ_check_basic (shpnt, SCpnt, scsi_result, &ic_do_ppr))) {
+
+        /*
+         * Enhanced test - if not async or bad device.
+         */
+        if ( SCpnt->ic_nego_sync != 0) {
+           if ( !(get_device_flags (scsi_result) & BLIST_NO_IC2) )
+               integ_check_enhanced (shpnt, SCpnt, scsi_result, ic_do_ppr);
+        }
+    }
+
+    /*
+     * Set the flag ic_complete and issue on INQUIRY command to
+     * notify the low-level driver that the integrity check
+     * is complete AND to return the content of scsi_result
+     * to that upon entering the integrity check routine. 
+     * The low-level driver can use this flag to initiate driver 
+     * specific activities, i.e., save the values to nvram.
+     */
+
+    SCpnt->ic_in_progress = 0;
+    SCpnt->ic_complete = 1;
+
+    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;
+    {
+      struct semaphore sem = MUTEX_LOCKED;
+      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;
+    }
+
+    SCpnt->ic_complete    = 0;
+  }
+
+  /*
    * 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.
    */
@@ -1595,6 +1685,977 @@
 	internal_cmnd (SCpnt);
 
     SCSI_LOG_MLQUEUE(3,printk ("Leaving scsi_do_cmd()\n"));
+}
+
+/* Integrity Check - Basic Test
+ *
+ * Directs low-level driver to negotiate for narrow/async transmission.
+ * Two inquiry commands are issued and the data is saved.
+ * Next, directs low-level driver to negotiate for wide and maximum 
+ * synchronous speed.  An inquiry command is issued.
+ * The inquiry data are compared.  
+ * If the data are the same the test passes and returns 0.
+ * If the data differ, the test is repeated.
+ * If the data differ after the second pass, the bus width/speed are
+ * reduced and the test is repeated until the test passes or async/narrow 
+ * transmission is reached.
+ *
+ * Care should be taken to ensure that the driver does not perform undesired
+ * negotiation due to an auto-request sense.
+ */
+
+/*
+ * Flag bits used for the integrity checking functions
+ */
+
+#define IC_NEGO_NONE          0  /* No Negotiation */
+#define IC_NEGO_SDTR          1  /* Synchronous Negotiation*/
+#define IC_NEGO_WDTR          2  /* Wide Negotiation */
+#define IC_NEGO_PPR           4  /* PPR Negotiation */
+
+#define IC_DO_NARROW          0  /* Set bus width to 8-bits */
+#define IC_DO_WIDE            1  /* Set bus width to 16-bits */
+
+#define IC_DO_ASYNC           0  /* Set bus to async. transmission */
+#define IC_DO_MAX_SPEED       1  /* Use the max. bus speed possible */
+#define IC_DO_DECREASE_SPEED  2  /* Reduce the max. bus speed */
+
+/*
+ * Fallback utility function for the Basic test.
+ */
+unsigned char integ_check_fallback( unsigned char do_ppr, char *widthptr, 
+                             char *speedptr, Scsi_Cmnd *SCpnt)  
+{
+       unsigned char ic_error;
+       /* Doc. 99-242r2 specifies that if the device is using PPR negotation
+        * and fallback is required, a PPR negotiation to narrow async must
+        * occur and then all future negotiations must be WDTR and SDTR
+        */
+            
+       if (do_ppr) {
+           unsigned char scsi_cmd[6];
+           unsigned char current_width = SCpnt->ic_nego_width;
+
+           SCpnt->ic_nego_width = IC_DO_NARROW;
+           SCpnt->ic_nego_sync  = IC_DO_ASYNC;
+           SCpnt->ic_nego =  do_ppr;
+           scsi_cmd[0] = TEST_UNIT_READY;
+           scsi_cmd[1] = 0;
+           scsi_cmd[2] = scsi_cmd[3] = scsi_cmd[4] = scsi_cmd[5] = 0;
+           SCpnt->cmd_len = 0;
+           {
+                   struct semaphore sem = MUTEX_LOCKED;
+                   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, 3);
+                   spin_unlock_irq(&io_request_lock);
+                   down (&sem);
+                   SCpnt->request.sem = NULL;
+           }
+
+           SCpnt->ic_nego_width = current_width;
+           SCpnt->ic_nego_sync  = IC_DO_DECREASE_SPEED;
+           SCpnt->ic_nego = IC_NEGO_NONE;
+          
+           return 0;
+       }
+
+       /* Do Fallback. If wide, go narrow.  If narrow, 
+        * and not async, decrease speed and reset to wide. 
+        * If narrow and async, report error.
+        */
+       ic_error = 0;
+       if (SCpnt->ic_nego_width == IC_DO_WIDE)  { 
+    	    *widthptr = IC_DO_NARROW;
+            *speedptr = (SCpnt->ic_nego_sync == IC_DO_ASYNC ) ? 
+				IC_DO_ASYNC : IC_DO_MAX_SPEED;
+       }
+       else if (SCpnt->ic_nego_sync != IC_DO_ASYNC ) {
+	    	    *widthptr = IC_DO_WIDE;
+		    *speedptr = IC_DO_DECREASE_SPEED;
+       }
+       else
+	     ic_error = 1; /* At Narrow Async, cannot fallback further */
+
+       return ic_error;
+}
+
+/*
+ * Fallback utility function for the Enhanced test.
+ */
+unsigned char integ_check_fallback_enh( unsigned char do_ppr, unsigned char *do_release, 
+                             char *speedptr, Scsi_Cmnd *SCpnt)  
+{
+       unsigned char fallback = 0;
+
+       *do_release = 0;
+
+       if (do_ppr) {
+           unsigned char scsi_cmd[6];
+           unsigned char current_width = SCpnt->ic_nego_width;
+           unsigned char current_speed = SCpnt->ic_nego_sync;
+           unsigned char current_nego  = SCpnt->ic_nego;
+
+           SCpnt->ic_nego_width = IC_DO_NARROW;
+           SCpnt->ic_nego_sync  = IC_DO_ASYNC;
+           SCpnt->ic_nego =  do_ppr;
+           scsi_cmd[0] = TEST_UNIT_READY;
+           scsi_cmd[1] = 0;
+           scsi_cmd[2] = scsi_cmd[3] = scsi_cmd[4] = scsi_cmd[5] = 0;
+           SCpnt->cmd_len = 0;
+           {
+                   struct semaphore sem = MUTEX_LOCKED;
+                   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, 3);
+                   spin_unlock_irq(&io_request_lock);
+                   down (&sem);
+                   SCpnt->request.sem = NULL;
+           }
+
+           SCpnt->ic_nego_width = current_width;
+           SCpnt->ic_nego_sync  = current_speed;
+           SCpnt->ic_nego = current_nego;
+       }
+
+        if ( (!SCpnt->result) && (SCpnt->ic_nego != (IC_NEGO_NONE|do_ppr)) ) { 
+            /* Since a re-negotiation has occurred, most likely had 
+             * a bus reset.  This could be due to a driver timeout. 
+             * Instead of quitting, re-negotiate same width and a slower speed,
+             * then issue release and then reserve commands.
+             */
+             fallback = 1;
+             *do_release = 1;
+        }
+        else if (SCpnt->result) {
+               if ( (status_byte (SCpnt->result) & CHECK_CONDITION) &&
+                    ((SCpnt->sense_buffer[2] & 0xf) == UNIT_ATTENTION)  && 
+                       (SCpnt->sense_buffer[12]  == 0x29)   &&
+                       (SCpnt->ic_nego_sync != IC_DO_ASYNC) ) {
+
+                    fallback = 1;
+                    *do_release = 1;
+                }
+                else if (((driver_byte (SCpnt->result) & DRIVER_TIMEOUT) ||
+                           (host_byte (SCpnt->result) != DID_OK ))) {
+                    fallback = 1;
+                }
+        }
+
+        /* Return 0 if we are to fall back and not currently at async.
+         * Return 1 else.
+         */
+        if ((fallback) && (SCpnt->ic_nego_sync != IC_DO_ASYNC)) {
+                 *speedptr = IC_DO_DECREASE_SPEED;
+                 return 0; 
+        }
+        else 
+            return 1; 
+}
+
+
+unsigned char
+integ_check_basic ( struct Scsi_Host * shpnt, Scsi_Cmnd * SCpnt, 
+                   char * scsi_result, unsigned char *PPRptr)
+{
+
+    char *          ic_inqdata;
+    char            ic_inqdata0[256];   
+    unsigned char   scsi_cmd[12];
+    unsigned char   ic_notdone = 1;
+    unsigned char   ic_error = 0;
+    char            repeat = 2;
+    char            width = IC_DO_WIDE;
+    char            speed = IC_DO_MAX_SPEED;
+    char            first = 1;
+    unsigned char   do_ppr = 0;
+   
+
+    ic_inqdata = ( (!shpnt->unchecked_isa_dma)? 
+			&ic_inqdata0[0]:scsi_init_malloc(512,GFP_DMA));
+
+    if (ic_inqdata == NULL) {
+        printk ("Unable to obtain ic_inqdata buffer\n");
+        return 1;
+    }
+
+    /* 
+     * SCSI-3 utilizes PPR messaging (instead of WDTR and SDTR).  
+     * Extra TUR included to test for PPR messaging suppport.
+     *
+     * If the driver does not support PPR messaging or a message
+     * reject occurs, the driver should clear ic_nego and switch 
+     * to WDTR and SDTR.  If PPR messaging is supported, the 
+     * driver should always check for the flag IC_NEGO_PPR.
+     */
+    SCpnt->ic_nego_width = IC_DO_NARROW;
+    SCpnt->ic_nego_sync  = IC_DO_ASYNC;
+    SCpnt->ic_nego = IC_NEGO_PPR;
+
+    while (repeat) {
+        scsi_cmd[0] = TEST_UNIT_READY;
+        scsi_cmd[1] = 0;
+        scsi_cmd[2] = scsi_cmd[3] = scsi_cmd[4] = scsi_cmd[5] = 0;
+        SCpnt->cmd_len = 0;
+        {
+            struct semaphore sem = MUTEX_LOCKED;
+            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, 3);
+            spin_unlock_irq(&io_request_lock);
+            down (&sem);
+            SCpnt->request.sem = NULL;
+        }
+        do_ppr = SCpnt->ic_nego & IC_NEGO_PPR;
+
+        if (do_ppr) /* Make sure PPR is OK */
+           repeat--;      
+        else
+           repeat = 0;      
+    }
+
+    while (ic_notdone) {
+
+        repeat = 2;
+
+        /* 
+         * Sequentially negotiate narrow and  async, issue INQ
+         * Issue two Inquiry commands
+         */
+        SCpnt->ic_nego_width = IC_DO_NARROW;
+        SCpnt->ic_nego_sync  = IC_DO_ASYNC;
+        SCpnt->ic_nego = IC_NEGO_WDTR | do_ppr;
+
+        scsi_cmd[0] = TEST_UNIT_READY;
+        scsi_cmd[1] = 0;
+        scsi_cmd[2] = scsi_cmd[3] = scsi_cmd[4] = scsi_cmd[5] = 0;
+        SCpnt->cmd_len = 0;
+        {
+            struct semaphore sem = MUTEX_LOCKED;
+            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, 3);
+            spin_unlock_irq(&io_request_lock);
+            down (&sem);
+            SCpnt->request.sem = NULL;
+        }
+
+        SCpnt->ic_nego = IC_NEGO_SDTR | do_ppr;
+
+        while ( repeat-- ) {
+            scsi_cmd[0] = INQUIRY;
+            scsi_cmd[1] = 0;
+            scsi_cmd[2] = 0;
+            scsi_cmd[3] = 0;
+            scsi_cmd[4] = 36;
+            scsi_cmd[5] = 0;
+            SCpnt->cmd_len = 0;
+            {
+                struct semaphore sem = MUTEX_LOCKED;
+                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 *) ic_inqdata,
+                     36, 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));
+         
+            SCpnt->ic_nego = IC_NEGO_NONE | do_ppr;
+        }
+
+        /*
+         * Set parameters for wide and minimum sync.
+         * Sequentially negotiate for maximum width and speed.
+         * If Inquiry cmd hangs or data miscompare, decrease speed/width
+         * until comparison is successful. 
+         */
+
+        SCpnt->ic_nego_sync  = IC_DO_MAX_SPEED;
+        SCpnt->ic_nego_width = width;
+        SCpnt->ic_nego = IC_NEGO_WDTR | do_ppr;
+
+        scsi_cmd[0] = TEST_UNIT_READY;
+        scsi_cmd[1] = 0;
+        scsi_cmd[2] = scsi_cmd[3] = scsi_cmd[4] = scsi_cmd[5] = 0;
+        SCpnt->cmd_len = 0;
+        {
+          struct semaphore sem = MUTEX_LOCKED;
+          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, 3);
+          spin_unlock_irq(&io_request_lock);
+          down (&sem);
+          SCpnt->request.sem = NULL;
+        }
+
+        SCpnt->ic_nego_sync  = speed;
+        SCpnt->ic_nego = IC_NEGO_SDTR | do_ppr;
+
+        scsi_cmd[0] = INQUIRY;
+        scsi_cmd[1] = 0;
+        scsi_cmd[2] = 0;
+        scsi_cmd[3] = 0;
+        scsi_cmd[4] = 36;
+        scsi_cmd[5] = 0;
+        SCpnt->cmd_len = 0;
+        {
+          struct semaphore sem = MUTEX_LOCKED;
+          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,
+                 36, 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 no error, continue.
+         * If error and timeout, fallback. 
+         *          Otherwise quit test with error.
+         */
+
+        /* If timeout, fallback. Otherwise, quit test.
+         * If hang, reduce width and try again.
+         * If hang again, reset to wide and reduce speed.
+         * Quit once reach narrow/async transfers.
+         */
+        if (SCpnt->result) { 
+            ic_error = 1;
+            if (((driver_byte (SCpnt->result) & DRIVER_TIMEOUT) ||
+                  (host_byte (SCpnt->result) != DID_OK ))) {
+
+                  ic_error = integ_check_fallback( do_ppr, &width, 
+                                  &speed, SCpnt);  
+		  do_ppr = 0;
+            }
+            if (!ic_error)
+                   continue;
+        }
+        if ( SCpnt->ic_nego_sync == IC_DO_DECREASE_SPEED) 
+            SCpnt->ic_nego_sync = IC_DO_MAX_SPEED; 
+
+        /* 
+         * Compare Inq. data narrow/async with that
+         * acquired at wide/fastest settings.
+         * If miscompare and first try, repeat the entire test
+         *  if not first try, reduce width (speed) and try again.
+         */
+        if (!ic_error) {
+	  unsigned short ic_index;
+
+          ic_index = 0;
+	  while ( (ic_index < 36) && 
+             (ic_inqdata[ic_index] == scsi_result[ic_index])) 
+	        ic_index++;
+
+          if (ic_index != 36) {
+            if (first)
+                first = 0;
+	    else  {
+               SCSI_LOG_SCAN_BUS(3,
+                 printk ("scsi: INQUIRY TEST: MISCOMPARE. Falling back.\n"));
+
+               ic_error = integ_check_fallback( do_ppr, &width, 
+                                  &speed, SCpnt);  
+               do_ppr = 0;
+            }
+	
+            /* ic_error will be 1 only if miscompare and already
+             *  at async/narrow.
+             */
+            if (!ic_error)
+                continue;
+          }
+        }
+
+        if ( SCpnt->ic_nego_sync == IC_DO_DECREASE_SPEED) 
+            SCpnt->ic_nego_sync = IC_DO_MAX_SPEED; 
+
+        SCpnt->ic_nego = IC_NEGO_NONE | do_ppr; 
+        ic_notdone = 0;
+
+    }   /* End of while ic_notdone loop */
+
+    /*
+     * Free allocated memory and save PPR negotiation flag
+     */
+    if ((ic_inqdata != &ic_inqdata0[0]) && (ic_inqdata != NULL))
+	scsi_init_free(ic_inqdata, 512);
+
+    *PPRptr = do_ppr;
+    return ic_error;
+}
+
+/* Integrity Check - Enhanced Test.
+ *
+ * This function performs a 1Kbyte I/O to the internal buffer
+ * of the target device. First, the reserve command is issued. Failure
+ * results in a return of 0.  Next, the internal buffer size is 
+ * extracted using a mode 0 read buffer command. The write/read
+ * commands are issued and data compared.  
+ * Function returns 
+ *  0 if: successful, buffer size is 0, no read/write buffer support. 
+ *  1 on driver timeout, miscompare or midlayer failure. 
+ */
+
+unsigned char
+integ_check_enhanced ( struct Scsi_Host * shpnt, 
+                           Scsi_Cmnd * SCpnt, char * scsi_result,
+                           unsigned char do_ppr)
+{
+    unsigned long   ic_internal_buff_sz = 0;
+    unsigned long   ic_rdwr_test_sz;
+    unsigned char * ic_writedata;
+    unsigned char * ic_readdata;
+    unsigned char   ic_writedata0[1024];   
+    unsigned char   ic_readdata0[1024];   
+    unsigned char   scsi_cmd[12];
+    unsigned char   odd, even, patt_index;
+    unsigned char   nego, speed, width;
+    unsigned char   ic_notdone = 1;
+    unsigned char   ic_error = 0;
+    unsigned char   ic_do_release_reserve = 0;
+    unsigned short  ic_index;
+    unsigned char   ic_is_cdrom;
+    unsigned char   ic_retry = 2;
+
+    /*
+     * cdrom devices may require quite a while to get ready.
+     */
+    ic_is_cdrom = ((scsi_result[0]&0x1F) == TYPE_ROM) ? 1 : 0;
+
+    /*
+     * Reserve the Target. If reserve fails, return (no error).
+     */
+
+    while (ic_retry) {
+        SCpnt->ic_nego = IC_NEGO_NONE | do_ppr;
+
+        scsi_cmd[0] = RESERVE;
+        scsi_cmd[1] = 0;
+        scsi_cmd[2] =  scsi_cmd[3] =  scsi_cmd[4] =  scsi_cmd[5] = 0;
+        SCpnt->cmd_len = 0;
+        {
+            struct semaphore sem = MUTEX_LOCKED;
+            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: RESERVE %s with code 0x%x\n",
+                    SCpnt->result ? "failed" : "successful", SCpnt->result));
+
+         --ic_retry;
+         if (SCpnt->result) {
+            if (  ic_retry &&  ( status_byte (SCpnt->result) & CHECK_CONDITION) 
+                    && ( SCpnt->sense_buffer[2]  == UNIT_ATTENTION  ))
+                 continue;
+            else
+                 return 0;
+         }
+         else
+            ic_retry = 0;
+    } 
+
+    /*
+     * Clear buffers and (perhaps) allocate new memory
+     */
+
+    ic_writedata = ( (!shpnt->unchecked_isa_dma)? 
+			&ic_writedata0[0]:scsi_init_malloc(1024,GFP_DMA));
+
+    ic_readdata = ( (!shpnt->unchecked_isa_dma)? 
+			&ic_readdata0[0]:scsi_init_malloc(1024,GFP_DMA));
+
+    while (ic_notdone){
+       ic_notdone = 0;
+    
+       /*
+        * Read the Targets Internal Buffer size.
+        */
+
+       SCpnt->ic_nego = IC_NEGO_NONE | do_ppr;
+
+       scsi_cmd[0] = READ_BUFFER;
+       scsi_cmd[1] = 0x03;
+       scsi_cmd[2] = 0; 
+       scsi_cmd[3] =  scsi_cmd[4] =  scsi_cmd[5] = 0;
+       scsi_cmd[6] = 0;
+       scsi_cmd[7] = 0;
+       scsi_cmd[8] = 4; 
+       scsi_cmd[9] = 0;
+
+       SCpnt->cmd_len = 0;
+       {
+           struct semaphore sem = MUTEX_LOCKED;
+           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,
+                4, 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: READ BUFFER %s with code 0x%x\n",
+                   SCpnt->result ? "failed" : "successful", SCpnt->result));
+       /*
+        * Note: On a reservation conflict, the OS will issue a bus reset and a
+        * redo command. In this case, the status of the read buffer command will
+        * be good, but the target is not reserved anymore and all targets are reset
+        * to async and narrow.  The driver MUST re-negotiate to all targets on the
+        * bus. If the ic_nego flag is something other than IC_NEGO_NONE (the value
+        * prior to calling this command), we assume a bus reset and quit
+        * this test without error.
+        */
+
+       if ((!SCpnt->result) && (SCpnt->ic_nego != (IC_NEGO_NONE|do_ppr)) )
+         ic_error = 1;
+       else if (SCpnt->result) { 
+         /*
+          * If cdrom becoming ready, wait 1 second and try again.
+          */           
+         if (  ic_is_cdrom && 
+                      ( status_byte (SCpnt->result) & CHECK_CONDITION) &&
+                      ( SCpnt->sense_buffer[2]  == NOT_READY         ) && 
+                      ( SCpnt->sense_buffer[12] == 0x04              ) && 
+                      ( SCpnt->sense_buffer[13] == 0x01              ) ) {
+                ic_error = 0;
+                ic_retry++;
+                if (ic_retry < 4) 
+                    ic_notdone = 1; 
+                mdelay(1000);
+         }
+         else {
+             /*
+              * Release the device. Show reason.
+              */
+             ic_error = 1;
+             if ( status_byte (SCpnt->result) & RESERVATION_CONFLICT) {
+                 SCSI_LOG_SCAN_BUS(5, printk ("scsi: Reservation Conflict.\n"));
+             }
+             else if ( status_byte (SCpnt->result) & CHECK_CONDITION) {
+                 SCSI_LOG_SCAN_BUS(5, 
+                     printk ("scsi: sense key 0x%2X, ASC 0x%2X, ASCQ 0x%2X\n",
+                     SCpnt->sense_buffer[2] & 0xf, SCpnt->sense_buffer[12],
+                     SCpnt->sense_buffer[13]) );
+             }
+         }
+
+       } /* End of SCpnt check */
+    } /* End of ic_notdone loop */
+   
+    ic_internal_buff_sz = ic_error ? 0 : (scsi_result[1]<<16)|(scsi_result[2]<<8)|scsi_result[3];
+
+    if (!ic_error && ic_internal_buff_sz) {
+
+      SCpnt->ic_nego = IC_NEGO_NONE | do_ppr;
+      nego = IC_NEGO_NONE;
+      speed = (SCpnt->ic_nego_sync == 0) ? IC_DO_ASYNC : IC_DO_MAX_SPEED;
+      width = SCpnt->ic_nego_width;
+
+      /*
+       * Set the size of the write/read and compare size to the maximum of
+       * of 1024 and the targets internal buffer size.
+       */
+
+      ic_rdwr_test_sz = (ic_internal_buff_sz >= 1024) ? 1024 :  ic_internal_buff_sz;
+         
+      /*
+       * Until successful, issue the Mode 2 Write Buffer/ Read Buffer
+       * commands and compare the results.
+       *
+       * Four test patterns: 
+       *  count: 00 01 02 03 or 0001 0203 0405
+       *  alten: 00 FF       or 0000 FFFFF
+       *  cross: 55 AA       or 5555 AAAA
+       *  shift: 00 FE 00 FD 00 FB ... 00 DF 00 EF 
+       *          or 0000 FFFE 0000 FFFD 0000 FFFB ... 0000 EFFF FFFF 0001 FFFF 0002 ... FFFF 8000
+       */
+
+       for (patt_index=0; (patt_index < 4) && (!ic_error); patt_index++) {
+         ic_notdone = 1;
+
+         if (patt_index & 1) {
+                 even = 0;
+                 odd  = 0xFF;
+         }
+         else if (patt_index & 2) {
+                 even = 0x55;
+                 odd  = 0xAA;
+         }
+         else 
+                 even = odd = 0;
+          
+         while (ic_notdone) { 
+
+           /*
+            * Fill buffer with correct pattern
+            */
+           switch (patt_index) {
+           case 0:
+               for (ic_index=0; ic_index < 1024; ic_index++)
+                   ic_writedata[ic_index] = ic_index;
+                break;
+                
+           case 1:
+           case 2:
+                if (SCpnt->ic_nego_width == IC_DO_NARROW) {
+                   for (ic_index = 0; ic_index < 1024; ic_index+=2) {
+                         ic_writedata[ic_index]   = even;
+                         ic_writedata[ic_index+1] = odd;
+                   }
+                } 
+                else {
+                   for (ic_index = 0; ic_index < 1024; ic_index += 4) {
+                         ic_writedata[ic_index]   = even;
+                         ic_writedata[ic_index+1] = even;
+                         ic_writedata[ic_index+2] = odd;
+                         ic_writedata[ic_index+3] = odd;
+                   }
+                }
+                break;
+                    
+           case 3:
+                if (SCpnt->ic_nego_width == IC_DO_NARROW) {
+                   odd = 1;
+                   for (ic_index = 0; ic_index < 1024; ic_index += 2) {
+
+                      ic_writedata[ic_index]   = even;
+                      ic_writedata[ic_index+1] = ( ~even ) ^ odd;
+
+                      odd *= 2;
+                      if (!odd ) {
+                           even ^= 0xFF;
+			   odd = 1;
+		      }
+                   }
+                } 
+                else {
+                   unsigned short value = 1;
+                  
+                   for (ic_index = 0; ic_index < 1024; ic_index += 4) {
+
+                       ic_writedata[ic_index]   = even;
+                       ic_writedata[ic_index+1] = even;
+                       ic_writedata[ic_index+2] = (~even) ^ ((value >> 8) & 0xFF);
+                       ic_writedata[ic_index+3] = (~even) ^ (value  & 0xFF);
+
+		      value *= 2;
+                      if (!value) { 
+                           even ^= 0xFF;
+			   value = 1;
+		      }
+                   }
+                }   
+           } /* End of switch statement */
+
+           /* Issue TUR's if negotiation needs to occur.
+              On multiple, first does width and second does speed. */
+
+           while (nego > 0 ) {
+             SCpnt->ic_nego = nego | do_ppr; 
+             SCpnt->ic_nego_width = width;
+	     if (SCpnt->ic_nego == (IC_NEGO_SDTR | do_ppr))
+                 SCpnt->ic_nego_sync = speed;
+             
+             scsi_cmd[0] = TEST_UNIT_READY;
+             scsi_cmd[1] = 0;
+             scsi_cmd[2] = scsi_cmd[3] = scsi_cmd[4] = scsi_cmd[5] = 0;
+             SCpnt->cmd_len = 0;
+             {
+                  struct semaphore sem = MUTEX_LOCKED;
+                  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;
+             }
+             --nego;
+           }
+           if (SCpnt->ic_nego_sync == IC_DO_DECREASE_SPEED)
+               SCpnt->ic_nego_sync = IC_DO_MAX_SPEED;
+
+           if (ic_do_release_reserve) {
+               /* If it is likely a bus reset has occurred, this flag
+                * is set. It first releases the device (just to be sure)
+                * and then reserves.
+                */
+
+               SCpnt->ic_nego = IC_NEGO_NONE | do_ppr;
+
+               scsi_cmd[0] = RELEASE;
+               scsi_cmd[1] = 0;
+               scsi_cmd[2] = 0; 
+               scsi_cmd[3] =  scsi_cmd[4] =  scsi_cmd[5] = 0;
+               SCpnt->cmd_len = 0;
+               {
+                   struct semaphore sem = MUTEX_LOCKED;
+                   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;
+               }
+
+               if (SCpnt->result)
+                   ic_error = 1;
+
+               SCSI_LOG_SCAN_BUS(3,
+                  printk ("scsi: RELEASE %s with code 0x%x\n",
+                  SCpnt->result ? "failed" : "successful", SCpnt->result));
+
+               SCpnt->ic_nego = IC_NEGO_NONE | do_ppr;
+
+               if (!ic_error) {
+                 scsi_cmd[0] = RESERVE;
+                 scsi_cmd[1] = 0;
+                 scsi_cmd[2] =  scsi_cmd[3] =  scsi_cmd[4] =  scsi_cmd[5] = 0;
+                 SCpnt->cmd_len = 0;
+                 {
+                   struct semaphore sem = MUTEX_LOCKED;
+                   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;
+                 }
+
+                 if (SCpnt->result)
+                   ic_error = 1;
+
+                 SCSI_LOG_SCAN_BUS(3,
+                   printk ("scsi: RESERVE %s with code 0x%x\n",
+                   SCpnt->result ? "failed" : "successful", SCpnt->result));
+               }
+           }
+
+           if (!ic_error) {
+
+             ic_do_release_reserve = 0;
+             SCpnt->ic_nego = IC_NEGO_NONE | do_ppr; 
+
+             scsi_cmd[0] = WRITE_BUFFER;
+             scsi_cmd[1] = 0x02; 
+             scsi_cmd[2] = 0; 
+             scsi_cmd[3] = scsi_cmd[4] = scsi_cmd[5] = 0;
+             scsi_cmd[6] = (ic_rdwr_test_sz >> 16 ) & 0xFF;
+             scsi_cmd[7] = (ic_rdwr_test_sz >>  8 ) & 0xFF;
+             scsi_cmd[8] = ic_rdwr_test_sz &  0xFF;
+             scsi_cmd[9] = 0;
+             SCpnt->cmd_len = 0;
+             {
+                 struct semaphore sem = MUTEX_LOCKED;
+                 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 *) ic_writedata,
+                     ic_rdwr_test_sz, 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: WRITE BUFFER pattern %2X %s with code 0x%x\n",
+                   patt_index,
+                   SCpnt->result ? "failed" : "successful", SCpnt->result));
+
+             if ( (SCpnt->result) ||
+                       ((!SCpnt->result) && 
+                        (SCpnt->ic_nego != (IC_NEGO_NONE|do_ppr)) )) { 
+                 ic_error = integ_check_fallback_enh ( do_ppr, &ic_do_release_reserve, 
+                                                         &speed, SCpnt);  
+		 do_ppr = 0;
+                 if (!ic_error) {
+                     nego = IC_NEGO_WDTR;
+                     continue;
+                 }
+             }
+           }  /* End of if Write Buffer command */
+           if (SCpnt->ic_nego_sync == IC_DO_DECREASE_SPEED)
+             SCpnt->ic_nego_sync = IC_DO_MAX_SPEED;
+
+           if (!ic_error) {
+             SCpnt->ic_nego = IC_NEGO_NONE | do_ppr; 
+
+             scsi_cmd[0] = READ_BUFFER;
+             scsi_cmd[1] = 0x02; 
+             scsi_cmd[2] = 0; 
+             scsi_cmd[3] = scsi_cmd[4] = scsi_cmd[5] = 0;
+             scsi_cmd[6] = (ic_rdwr_test_sz >> 16 ) & 0xFF;
+             scsi_cmd[7] = (ic_rdwr_test_sz >>  8 ) & 0xFF;
+             scsi_cmd[8] = ic_rdwr_test_sz &  0xFF;
+             scsi_cmd[9] = 0;
+             SCpnt->cmd_len = 0;
+             {
+                struct semaphore sem = MUTEX_LOCKED;
+                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 *) ic_readdata,
+                         ic_rdwr_test_sz, 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: READ BUFFER  pattern %2X %s with code 0x%x\n",
+                 patt_index,
+                 SCpnt->result ? "failed" : "successful", SCpnt->result));
+
+             if ( (SCpnt->result) ||
+                       ((!SCpnt->result) && 
+                        (SCpnt->ic_nego != (IC_NEGO_NONE|do_ppr)) )) { 
+                 ic_error = integ_check_fallback_enh ( do_ppr, &ic_do_release_reserve, 
+                                                         &speed, SCpnt);  
+		 do_ppr = 0;
+                 if (!ic_error) {
+                     nego = IC_NEGO_WDTR;
+                     continue;
+                 }
+             }
+           }  /* End of if Read Buffer command */
+           if (SCpnt->ic_nego_sync == IC_DO_DECREASE_SPEED)
+             SCpnt->ic_nego_sync = IC_DO_MAX_SPEED;
+
+           /* 
+            * Compare. If miscompare, fallback and repeat.
+            */
+           if (!ic_error) {
+             unsigned short ic_index = 0;
+
+	     while ( (ic_index < ic_rdwr_test_sz) && 
+                    (ic_readdata[ic_index] == ic_writedata[ic_index])) 
+	        ic_index++;
+		
+             if (ic_index != ic_rdwr_test_sz) {
+                 SCSI_LOG_SCAN_BUS(3,
+                   printk ("scsi: READ/WRITE BUFFER TEST: MISCOMPARE. Falling back.\n"));
+
+                 ic_error = integ_check_fallback( do_ppr, &width, &speed, SCpnt);  
+
+                 /* If PPR messaging, on first fallback, 
+                  * use same width but slower  speed. 
+                  * Otherwise, reduce width to narrow. Unlike basic
+                  * test, do not toggle between wide and narrow in this test.
+                  */
+                 if (!do_ppr) {
+                   width = IC_DO_NARROW;
+                 }
+
+		 do_ppr = 0;
+                 if (!ic_error) {
+                   nego = IC_NEGO_WDTR;
+                   continue;
+                 }
+             }
+           }
+           if (SCpnt->ic_nego_sync == IC_DO_DECREASE_SPEED)
+             SCpnt->ic_nego_sync = IC_DO_MAX_SPEED;
+
+           ic_notdone = 0;
+         }  /* End of while loop in Write/Read Buffer test */
+
+      } /* End of pattern loop */
+
+    } /* End of if !ic_error && ic_internal_buff_sz  */
+
+    /*
+     * Release the Target.
+     */
+
+    SCpnt->ic_nego = IC_NEGO_NONE | do_ppr;
+
+    scsi_cmd[0] = RELEASE;
+    scsi_cmd[1] = 0;
+    scsi_cmd[2] = 0; 
+    scsi_cmd[3] =  scsi_cmd[4] =  scsi_cmd[5] = 0;
+    SCpnt->cmd_len = 0;
+    {
+        struct semaphore sem = MUTEX_LOCKED;
+        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 + 8 * HZ, 3);
+        spin_unlock_irq(&io_request_lock);
+        down (&sem);
+        SCpnt->request.sem = NULL;
+    }
+
+    SCSI_LOG_SCAN_BUS(3, printk ("scsi: RELEASE %s with code 0x%x\n",
+                    SCpnt->result ? "failed" : "successful", SCpnt->result));
+
+    if (SCpnt->result)
+	ic_error = 1;
+
+    /*
+     * Write / Read Buffer test complete. Free allocated storage.
+     */
+
+    if ((ic_writedata != &ic_writedata0[0]) && (ic_writedata != NULL))
+	    scsi_init_free(ic_writedata, 1024);
+
+    if ((ic_readdata != &ic_readdata0[0]) && (ic_readdata != NULL))
+	    scsi_init_free(ic_readdata, 1024);
+
+    /*
+     * Report driver, midlayer and those scsi errors that would prevent a
+     * read from being successful. 
+     */
+    return ic_error&0x01;
 }
 
 /* This function is the mid-level interrupt routine, which decides how
Index: oldkernel/linux/drivers/scsi/scsi.h
diff -u linux/drivers/scsi/scsi.h:1.1.1.1 linux/drivers/scsi/scsi.h:1.2
--- linux/drivers/scsi/scsi.h:1.1.1.1	Wed May 31 12:33:51 2000
+++ linux/drivers/scsi/scsi.h	Fri Jul  7 15:36:43 2000
@@ -621,6 +621,36 @@
     
     unsigned char      tag;	   /* SCSI-II queued command tag */
     unsigned long      pid;	   /* Process ID, starts at 0 */
+
+    /*
+     * The following fields are used for integrity checking.  
+     * Low level drivers may modify ic_nego and may reset to 0 the fields 
+     * ic_nego_width (sync).  All other fields should left alone.
+     * See comments in scsi.c
+     */
+
+    unsigned char ic_nego;	    /* Direct low level driver to negotiate 
+                                       0 (none), 1 (speed), 2 (width)
+                                       Low level driver may modify during
+                                       negotiation. */
+                                     
+    unsigned char ic_nego_width;    /* Request 0 (narrow), 1 (wide). Low
+                                       level driver should reset a wide request 
+                                       to narrow if device/target supports 
+                                       only narrow. */
+
+    unsigned char ic_nego_sync;     /* Reqest 0 (async), 1 (minimum period), 
+				       2 (increase period). Low level driver 
+                                       should reset to 0 for asyn or if period 
+                                       results in speed slower than 
+                                       5Mtrans/sec. */
+
+    unsigned char ic_in_progress;   /* In progress. Negotiate to given 
+                                       settings only. */
+
+    unsigned char ic_complete;      /* Set to 1 prior to last inquiry command.
+                                       Low level driver should save negotiated 
+                                       values if desired. */
 };
 
 
Index: oldkernel/linux/drivers/scsi/sd_ioctl.c
diff -u linux/drivers/scsi/sd_ioctl.c:1.1.1.1 linux/drivers/scsi/sd_ioctl.c:1.2
--- linux/drivers/scsi/sd_ioctl.c:1.1.1.1	Wed May 31 12:33:51 2000
+++ linux/drivers/scsi/sd_ioctl.c	Fri Jul  7 15:36:43 2000
@@ -113,6 +113,10 @@
 	return put_user(blksize_size[MAJOR(dev)][MINOR(dev)&0x0F],
 		(int *)arg);
 				
+    case BLKELVGET:
+    case BLKELVSET:
+            return blkelv_ioctl(inode->i_rdev, cmd, arg);
+
     RO_IOCTLS(dev, arg);
 
     default:
Index: oldkernel/linux/drivers/scsi/sym53c8xx.c
diff -u linux/drivers/scsi/sym53c8xx.c:1.3 linux/drivers/scsi/sym53c8xx.c:1.4
--- linux/drivers/scsi/sym53c8xx.c:1.3	Wed May 31 14:53:04 2000
+++ linux/drivers/scsi/sym53c8xx.c	Fri Jul  7 15:36:43 2000
@@ -1,7 +1,7 @@
 /******************************************************************************
 **  High Performance device driver for the Symbios 53C896 controller.
 **
-**  Copyright (C) 1998  Gerard Roudier <groudier@club-internet.fr>
+**  Copyright (C) 1998-1999  Gerard Roudier <groudier@club-internet.fr>
 **
 **  This driver also supports all the Symbios 53C8XX controller family, 
 **  except 53C810 revisions < 16, 53C825 revisions < 16 and all 
@@ -55,7 +55,7 @@
 */
 
 /*
-**	July 24 1999, sym53c8xx version 1.3g
+**	January 11 2000, sym53c8xx 1.61
 **
 **	Supported SCSI features:
 **	    Synchronous data transfers
@@ -64,7 +64,7 @@
 **	    Tagged command queuing
 **	    SCSI Parity checking
 **
-**	Supported NCR chips:
+**	Supported NCR/SYMBIOS chips:
 **		53C810A	  (8 bits, Fast 10,	 no rom BIOS) 
 **		53C825A	  (Wide,   Fast 10,	 on-board rom BIOS)
 **		53C860	  (8 bits, Fast 20,	 no rom BIOS)
@@ -73,7 +73,7 @@
 **		53C895	  (Wide,   Fast 40,	 on-board rom BIOS)
 **		53C895A	  (Wide,   Fast 40,	 on-board rom BIOS)
 **		53C896	  (Wide,   Fast 40 Dual, on-board rom BIOS)
-**		53C1510D	  (Wide,   Fast 40 Dual, on-board rom BIOS)
+**		53C1010	  (Wide,   Fast 80 Dual, on-board rom BIOS)
 **
 **	Other features:
 **		Memory mapped IO
@@ -84,7 +84,7 @@
 /*
 **	Name and version of the driver
 */
-#define SCSI_NCR_DRIVER_NAME	"sym53c8xx - version 1.3g"
+#define SCSI_NCR_DRIVER_NAME	"sym53c8xx - version 1.61"
 
 /* #define DEBUG_896R1 */
 #define SCSI_NCR_OPTIMIZE_896
@@ -111,7 +111,9 @@
 #include <asm/dma.h>
 #include <asm/io.h>
 #include <asm/system.h>
-#if LINUX_VERSION_CODE >= LinuxVersionCode(2,1,93)
+#if LINUX_VERSION_CODE >= LinuxVersionCode(2,3,17)
+#include <linux/spinlock.h>
+#elif LINUX_VERSION_CODE >= LinuxVersionCode(2,1,93)
 #include <asm/spinlock.h>
 #endif
 #include <linux/delay.h>
@@ -132,13 +134,13 @@
 
 #if LINUX_VERSION_CODE >= LinuxVersionCode(2,1,35)
 #include <linux/init.h>
-#else
-#ifndef	__initdata
-#define	__initdata
 #endif
-#ifndef	__initfunc
-#define	__initfunc(__arginit) __arginit
+
+#ifndef	__init
+#define	__init
 #endif
+#ifndef	__initdata
+#define	__initdata
 #endif
 
 #if LINUX_VERSION_CODE <= LinuxVersionCode(2,1,92)
@@ -291,21 +293,6 @@
 
 /*==========================================================
 **
-**	This driver ensures that no PCI self-mastering will 
-**	be attempted by the PCI chip at any time, provided 
-**	that we can load the on-chip RAM from the C code.
-**	For now, I can only check that on x86, and the 
-**	the SCSI_NCR_PCI_MEM_NOT_SUPPORTED option is here 
-**	to provide previous behaviour for other platforms.
-**
-**==========================================================
-*/
-#if	!defined(__i386__) && !defined(__sparc__)
-#define	SCSI_NCR_PCI_MEM_NOT_SUPPORTED
-#endif
-
-/*==========================================================
-**
 **	Configuration and Debugging
 **
 **==========================================================
@@ -331,26 +318,34 @@
 #endif
 
 /*
-**    TAGS are actually limited to 64 tags/lun.
-**    We need to deal with power of 2, for alignment constraints.
+**    TAGS are actually unlimited (256 tags/lun).
+**    But Linux only supports 255. :)
 */
-#if	SCSI_NCR_MAX_TAGS > 64
-#undef	SCSI_NCR_MAX_TAGS
-#define	SCSI_NCR_MAX_TAGS (64)
+#if	SCSI_NCR_MAX_TAGS > 255
+#define	MAX_TAGS	255
+#else
+#define	MAX_TAGS SCSI_NCR_MAX_TAGS
 #endif
 
-#define NO_TAG	(255)
-
 /*
-**	Choose appropriate type for tag bitmap.
+**    Since the ncr chips only have a 8 bit ALU, we try to be clever 
+**    about offset calculation in the TASK TABLE per LUN that is an 
+**    array of DWORDS = 4 bytes.
 */
-#if	SCSI_NCR_MAX_TAGS > 32
-typedef u_int64 tagmap_t;
+#if	MAX_TAGS > (512/4)
+#define MAX_TASKS  (1024/4)
+#elif	MAX_TAGS > (256/4) 
+#define MAX_TASKS  (512/4)
 #else
-typedef u_int32 tagmap_t;
+#define MAX_TASKS  (256/4)
 #endif
 
 /*
+**    This one means 'NO TAG for this job'
+*/
+#define NO_TAG	(256)
+
+/*
 **    Number of targets supported by the driver.
 **    n permits target numbers 0..n-1.
 **    Default is 16, meaning targets #0..#15.
@@ -394,45 +389,28 @@
 #ifdef SCSI_NCR_CAN_QUEUE
 #define MAX_START   (SCSI_NCR_CAN_QUEUE + 4)
 #else
-#define MAX_START   (MAX_TARGET + 7 * SCSI_NCR_MAX_TAGS)
+#define MAX_START   (MAX_TARGET + 7 * MAX_TAGS)
+#endif
+
+/*
+**    We donnot want to allocate more than 1 PAGE for the 
+**    the start queue and the done queue. We hard-code entry 
+**    size to 8 in order to let cpp do the checking.
+**    Allows 512-4=508 pending IOs for i386 but Linux seems for 
+**    now not able to provide the driver with this amount of IOs.
+*/
+#if	MAX_START > PAGE_SIZE/8
+#undef	MAX_START
+#define MAX_START (PAGE_SIZE/8)
 #endif
 
 /*
 **    The maximum number of segments a transfer is split into.
 **    We support up to 127 segments for both read and write.
-**    Since we try to avoid phase mismatches by testing the PHASE 
-**    before each MOV, the both DATA_IN and DATA_OUT scripts do 
-**    not fit in the 4K on-chip RAM. For this reason, the data 
-**    scripts are broken into 2 sub-scripts.
-**    80 (MAX_SCATTERL) segments are moved from a sub-script 
-**    in on-chip RAM. This makes data transfers shorter than 
-**    80k (assuming 1k fs) as fast as possible.
-**    The 896 allows to handle phase mismatches from SCRIPTS.
-**    So, for this chip, we use a simple array of MOV's.
-**    Perhaps, using a simple array of MOV's and going with 
-**    the phase mismatch interrupt is also the best solution 
-**    for the 895 in Ultra2-mode, since the PHASE test + MOV 
-**    latency may be enough to fill the SCSI offset for very  
-**    fast disks like the Cheatah Wide LVD and so, may waste 
-**    SCSI BUS bandwitch.
 */
 
 #define MAX_SCATTER (SCSI_NCR_MAX_SCATTER)
-
-#ifdef	SCSI_NCR_OPTIMIZE_896
 #define	SCR_SG_SIZE	(2)
-#define MAX_SCATTERL	MAX_SCATTER
-#define MAX_SCATTERH	0
-#else
-#if (MAX_SCATTER > 80)
-#define	SCR_SG_SIZE	(4)
-#define MAX_SCATTERL	80
-#define	MAX_SCATTERH	(MAX_SCATTER - MAX_SCATTERL)
-#else
-#define MAX_SCATTERL	MAX_SCATTER
-#define	MAX_SCATTERH	0
-#endif
-#endif	/* SCSI_NCR_OPTIMIZE_896 */
 
 /*
 **    Io mapped or memory mapped.
@@ -481,17 +459,15 @@
 
 #define DEBUG_ALLOC    (0x0001)
 #define DEBUG_PHASE    (0x0002)
-#define DEBUG_POLL     (0x0004)
 #define DEBUG_QUEUE    (0x0008)
 #define DEBUG_RESULT   (0x0010)
-#define DEBUG_SCATTER  (0x0020)
+#define DEBUG_POINTER  (0x0020)
 #define DEBUG_SCRIPT   (0x0040)
 #define DEBUG_TINY     (0x0080)
 #define DEBUG_TIMING   (0x0100)
 #define DEBUG_NEGO     (0x0200)
 #define DEBUG_TAGS     (0x0400)
-#define DEBUG_FREEZE   (0x0800)
-#define DEBUG_RESTART  (0x1000)
+#define DEBUG_IC       (0x0800)
 
 /*
 **    Enable/Disable debug messages.
@@ -586,11 +562,10 @@
 #endif
 
 #ifdef __sparc__
-#  include <asm/irq.h>
-#  define ioremap(base, size)		((u_long) __va(base))
+#  define ioremap(base, size)	((u_long) __va(base))
 #  define iounmap(vaddr)
 #  define pcivtobus(p)			((p) & pci_dvma_mask)
-#  define memcpy_to_pci(a, b, c)	memcpy_toio((void *) (a), (b), (c))
+#  define memcpy_to_pci(a, b, c)	memcpy_toio((u_long) (a), (b), (c))
 #elif defined(__alpha__)
 #  define pcivtobus(p)			((p) & 0xfffffffful)
 #  define memcpy_to_pci(a, b, c)	memcpy_toio((a), (b), (c))
@@ -600,9 +575,7 @@
 #endif
 
 #ifndef SCSI_NCR_PCI_MEM_NOT_SUPPORTED
-__initfunc(
-static u_long remap_pci_mem(u_long base, u_long size)
-)
+static u_long __init remap_pci_mem(u_long base, u_long size)
 {
 	u_long page_base	= ((u_long) base) & PAGE_MASK;
 	u_long page_offs	= ((u_long) base) - page_base;
@@ -611,9 +584,7 @@
 	return page_remapped? (page_remapped + page_offs) : 0UL;
 }
 
-__initfunc(
-static void unmap_pci_mem(u_long vaddr, u_long size)
-)
+static void __init unmap_pci_mem(u_long vaddr, u_long size)
 {
 	if (vaddr)
 		iounmap((void *) (vaddr & PAGE_MASK));
@@ -812,6 +783,19 @@
 	NCR_UNLOCK_DRIVER(flags);
 }
 
+static void ncr_print_hex(u_char *p, int n)
+{
+	while (n-- > 0)
+		printk (" %x", *p++);
+}
+
+static void ncr_printl_hex(char *label, u_char *p, int n)
+{
+	printk("%s", label);
+	ncr_print_hex(p, n);
+	printk (".\n");
+}
+
 /*
 **	Transfer direction
 **
@@ -1157,36 +1141,38 @@
 
 #define	SIR_BAD_STATUS		(1)
 #define	SIR_SEL_ATN_NO_MSG_OUT	(2)
-#define	SIR_NEGO_SYNC		(3)
-#define	SIR_NEGO_WIDE		(4)
+#define	SIR_MSG_RECEIVED	(3)
+#define	SIR_MSG_WEIRD		(4)
 #define	SIR_NEGO_FAILED		(5)
 #define	SIR_NEGO_PROTO		(6)
-#define	SIR_REJECT_RECEIVED	(7)
+#define	SIR_SCRIPT_STOPPED	(7)
 #define	SIR_REJECT_TO_SEND	(8)
-#define	SIR_IGN_RESIDUE		(9)
-#define	SIR_MISSING_SAVE	(10)
+#define	SIR_SWIDE_OVERRUN	(9)
+#define	SIR_SODL_UNDERRUN	(10)
 #define	SIR_RESEL_NO_MSG_IN	(11)
 #define	SIR_RESEL_NO_IDENTIFY	(12)
 #define	SIR_RESEL_BAD_LUN	(13)
-#define	SIR_UNUSED_14		(14)
+#define	SIR_TARGET_SELECTED	(14)
 #define	SIR_RESEL_BAD_I_T_L	(15)
 #define	SIR_RESEL_BAD_I_T_L_Q	(16)
-#define	SIR_UNUSED_17		(17)
+#define	SIR_ABORT_SENT		(17)
 #define	SIR_RESEL_ABORTED	(18)
 #define	SIR_MSG_OUT_DONE	(19)
-#define	SIR_MAX			(19)
+#define	SIR_AUTO_SENSE_DONE	(20)
+#define	SIR_DUMMY_INTERRUPT	(21)
+#define	SIR_MAX			(21)
 
 /*==========================================================
 **
-**	Extended error codes.
+**	Extended error bits.
 **	xerr_status field of struct ccb.
 **
 **==========================================================
 */
 
-#define	XE_OK		(0)
-#define	XE_EXTRA_DATA	(1)	/* unexpected data phase */
-#define	XE_BAD_PHASE	(2)	/* illegal phase (4/5)   */
+#define	XE_EXTRA_DATA	(1)	/* unexpected data phase	 */
+#define	XE_BAD_PHASE	(2)	/* illegal phase (4/5)		 */
+#define	XE_PARITY_ERR	(4)	/* unrecovered SCSI parity error */
 
 /*==========================================================
 **
@@ -1196,8 +1182,10 @@
 **==========================================================
 */
 
+#define NS_NOCHANGE	(0)
 #define NS_SYNC		(1)
 #define NS_WIDE		(2)
+#define NS_PPR		(4)
 
 /*==========================================================
 **
@@ -1209,9 +1197,6 @@
 */
 
 #define	QUIRK_AUTOSAVE	(0x01)
-#define	QUIRK_NOMSG	(0x02)
-#define QUIRK_NOSYNC	(0x10)
-#define QUIRK_NOWIDE16	(0x20)
 
 /*==========================================================
 **
@@ -1275,6 +1260,8 @@
 #define UC_SETFLAG	15
 #define UC_CLEARPROF	16
 #define UC_SETVERBOSE	17
+#define UC_RESETDEV	18
+#define UC_CLEARDEV	19
 
 #define	UF_TRACE	(0x01)
 #define	UF_NODISC	(0x02)
@@ -1318,6 +1305,7 @@
 	*/
 	u_int32		*luntbl;	/* lcbs bus address table	*/
 	u_int32		b_luntbl;	/* bus address of this table	*/
+	u_int32		b_lun0;		/* bus address of lun0		*/
 	lcb_p		l0p;		/* lcb of LUN #0 (normal case)	*/
 #if MAX_LUN > 1
 	lcb_p		*lmp;		/* Other lcb's [1..MAX_LUN]	*/
@@ -1330,6 +1318,12 @@
 	u_char		inq_byte7;	/* Contains these capabilities	*/
 
 	/*----------------------------------------------------------------
+	**	Some flags.
+	**----------------------------------------------------------------
+	*/
+	u_char		to_reset;	/* This target is to be reset	*/
+
+	/*----------------------------------------------------------------
 	**	Pointer to the ccb used for negotiation.
 	**	Prevent from starting a negotiation for all queued commands 
 	**	when tagged command queuing is enabled.
@@ -1346,7 +1340,7 @@
 
 	/*----------------------------------------------------------------
 	**	negotiation of wide and synch transfer and device quirks.
-	**	sval and wval are read from SCRIPTS and so have alignment 
+	**	sval, wval and uval are read from SCRIPTS and so have alignment 
 	**	constraints.
 	**----------------------------------------------------------------
 	*/
@@ -1357,6 +1351,13 @@
 /*1*/	u_char	quirks;
 /*2*/	u_char	widedone;
 /*3*/	u_char	wval;
+/*0*/	u_char	uval;
+
+	u_char ic_min_sync;
+	u_char ic_max_width;
+	u_char ic_maximums_set;
+	u_char ic_done;
+	u_char ppr_negotiation;
 
 	/*----------------------------------------------------------------
 	**	User settable limits and options.
@@ -1365,7 +1366,7 @@
 	*/
 	u_char	usrsync;
 	u_char	usrwide;
-	u_char	usrtags;
+	u_short	usrtags;
 	u_char	usrflag;
 };
 
@@ -1403,11 +1404,11 @@
 	*/
 	XPT_QUEHEAD	busy_ccbq;	/* Queue of busy CCBs		*/
 	XPT_QUEHEAD	wait_ccbq;	/* Queue of waiting for IO CCBs	*/
-	u_char		busyccbs;	/* CCBs busy for this lun	*/
-	u_char		queuedccbs;	/* CCBs queued to the controller*/
-	u_char		queuedepth;	/* Queue depth for this lun	*/
-	u_char		scdev_depth;	/* SCSI device queue depth	*/
-	u_char		maxnxs;		/* Max possible nexuses		*/
+	u_short		busyccbs;	/* CCBs busy for this lun	*/
+	u_short		queuedccbs;	/* CCBs queued to the controller*/
+	u_short		queuedepth;	/* Queue depth for this lun	*/
+	u_short		scdev_depth;	/* SCSI device queue depth	*/
+	u_short		maxnxs;		/* Max possible nexuses		*/
 
 	/*----------------------------------------------------------------
 	**	Control of tagged command queuing.
@@ -1415,22 +1416,23 @@
 	**	This avoids using a loop for tag allocation.
 	**----------------------------------------------------------------
 	*/
-	u_char		ia_tag;		/* Tag allocation index		*/
-	u_char		if_tag;		/* Tag release index		*/
-	u_char cb_tags[SCSI_NCR_MAX_TAGS]; /* Circular tags buffer	*/
+	u_short		ia_tag;		/* Tag allocation index		*/
+	u_short		if_tag;		/* Tag release index		*/
+	u_char		*cb_tags;	/* Circular tags buffer		*/
+	u_char		inq_byte7;	/* Store unit CmdQ capability	*/
 	u_char		usetags;	/* Command queuing is active	*/
-	u_char		maxtags;	/* Max NR of tags asked by user	*/
-	u_char		numtags;	/* Current number of tags	*/
-	u_char		inq_byte7;	/* Store unit CmdQ capabitility	*/
+	u_char		to_clear;	/* User wants to clear all tasks*/
+	u_short		maxtags;	/* Max NR of tags asked by user	*/
+	u_short		numtags;	/* Current number of tags	*/
 
 	/*----------------------------------------------------------------
 	**	QUEUE FULL and ORDERED tag control.
 	**----------------------------------------------------------------
 	*/
 	u_short		num_good;	/* Nr of GOOD since QUEUE FULL	*/
-	tagmap_t	tags_umap;	/* Used tags bitmap		*/
-	tagmap_t	tags_smap;	/* Tags in use at 'tag_stime'	*/
-	u_long		tags_stime;	/* Last time we set smap=umap	*/
+	u_short		tags_sum[2];	/* Tags sum counters		*/
+	u_char		tags_si;	/* Current index to tags sum	*/
+	u_long		tags_stime;	/* Last time we switch tags_sum	*/
 };
 
 /*========================================================================
@@ -1572,10 +1574,14 @@
 #define HF_IN_PM1	(1u<<1)
 #define HF_ACT_PM	(1u<<2)
 #define HF_DP_SAVED	(1u<<3)
-#define HF_PAR_ERR	(1u<<4)
+#define HF_AUTO_SENSE	(1u<<4)
 #define HF_DATA_ST	(1u<<5)
 #define HF_PM_TO_C	(1u<<6)
 
+#ifdef SCSI_NCR_IARB_SUPPORT
+#define HF_HINT_IARB	(1u<<7)
+#endif
+
 /*
 **	First four bytes (script)
 */
@@ -1620,6 +1626,7 @@
 
 	struct scr_tblsel  select;
 	struct scr_tblmove smsg  ;
+	struct scr_tblmove smsg_ext ;
 	struct scr_tblmove cmd   ;
 	struct scr_tblmove sense ;
 	struct scr_tblmove data [MAX_SCATTER];
@@ -1633,6 +1640,12 @@
 	struct pm_ctx pm0;
 	struct pm_ctx pm1;
 
+	/*
+	**	Extra bytes count transferred 
+	**	in case of data overrun.
+	*/
+	u_int32	extra_bytes;
+
 #ifdef SCSI_NCR_PROFILE_SUPPORT
 	/*
 	**	Disconnection counter
@@ -1663,8 +1676,8 @@
 	**----------------------------------------------------------------
 	*/
 	Scsi_Cmnd	*cmd;		/* SCSI command 		*/
-	u_long		tlimit;		/* Deadline for this job	*/
 	int		data_len;	/* Total data length		*/
+	int		segments;	/* Number of SG segments	*/
 
 	/*----------------------------------------------------------------
 	**	Message areas.
@@ -1680,21 +1693,34 @@
 	u_char		scsi_smsg2[8];
 
 	/*----------------------------------------------------------------
+	**	Saved info for auto-sense
+	**----------------------------------------------------------------
+	*/
+	u_char		sv_scsi_status;
+	u_char		sv_xerr_status;
+
+	/*----------------------------------------------------------------
 	**	Other fields.
 	**----------------------------------------------------------------
 	*/
 	u_long		p_ccb;		/* BUS address of this CCB	*/
 	u_char		sensecmd[6];	/* Sense command		*/
-	u_char		tag;		/* Tag for this transfer	*/
-					/*  255 means no tag		*/
+	u_char		to_abort;	/* This CCB is to be aborted	*/
+	u_short		tag;		/* Tag for this transfer	*/
+					/*  NO_TAG means no tag		*/
+	u_char		tags_si;	/* Lun tags sum index (0,1)	*/
+
 	u_char		target;
 	u_char		lun;
-	u_char		queued;
-	u_char		auto_sense;
+	u_short		queued;
 	ccb_p		link_ccb;	/* Host adapter CCB chain	*/
 	ccb_p		link_ccbh;	/* Host adapter CCB hash chain	*/
 	XPT_QUEHEAD	link_ccbq;	/* Link to unit CCB queue	*/
 	u_int32		startp;		/* Initial data pointer		*/
+	u_int32		lastp0;		/* Initial 'lastp'		*/
+	int		ext_sg;		/* Extreme data pointer, used	*/
+	int		ext_ofs;	/*  to calculate the residual.	*/
+	int		resid;
 };
 
 #define CCB_PHYS(cp,lbl)	(cp->p_ccb + offsetof(struct ccb, lbl))
@@ -1764,7 +1790,7 @@
 	**----------------------------------------------------------------
 	*/
 	u_char	sv_scntl0, sv_scntl3, sv_dmode, sv_dcntl, sv_ctest3, sv_ctest4,
-		sv_ctest5, sv_gpcntl, sv_stest2, sv_stest4;
+		sv_ctest5, sv_gpcntl, sv_stest2, sv_stest4, sv_scntl4;
 
 	/*----------------------------------------------------------------
 	**	Actual initial value of IO register bits used by the 
@@ -1773,7 +1799,7 @@
 	**----------------------------------------------------------------
 	*/
 	u_char	rv_scntl0, rv_scntl3, rv_dmode, rv_dcntl, rv_ctest3, rv_ctest4, 
-		rv_ctest5, rv_stest2, rv_ccntl0, rv_ccntl1;
+		rv_ctest5, rv_stest2, rv_ccntl0, rv_ccntl1, rv_scntl4;
 
 	/*----------------------------------------------------------------
 	**	Target data.
@@ -1805,7 +1831,7 @@
 	**	SCRIPTS virtual and physical bus addresses.
 	**	'script'  is loaded in the on-chip RAM if present.
 	**	'scripth' stays in main memory for all chips except the 
-	**	53C896 that provides 8K on-chip RAM.
+	**	53C895A and 53C896 that provide 8K on-chip RAM.
 	**----------------------------------------------------------------
 	*/
 	struct script	*script0;	/* Copies of script and scripth	*/
@@ -1820,8 +1846,6 @@
 	*/
 	u_short		device_id;	/* PCI device id		*/
 	u_char		revision_id;	/* PCI device revision id	*/
-	u_char		pci_bus;	/* PCI bus number		*/
-	u_char		pci_devfn;	/* PCI device and function	*/
 	u_int		features;	/* Chip features map		*/
 	u_char		myaddr;		/* SCSI id of the adapter	*/
 	u_char		maxburst;	/* log base 2 of dwords burst	*/
@@ -1834,6 +1858,16 @@
 	u_long		clock_khz;	/* SCSI clock frequency in KHz	*/
 
 	/*----------------------------------------------------------------
+	**	Range for the PCI clock frequency measurement result
+	**	that ensures the algorithm used by the driver can be 
+	**	trusted for the SCSI clock frequency measurement.
+	**	(Assuming a PCI clock frequency of 33 MHz).
+	**----------------------------------------------------------------
+	*/
+	u_int		pciclock_min;
+	u_int		pciclock_max;
+
+	/*----------------------------------------------------------------
 	**	Start queue management.
 	**	It is filled up by the host processor and accessed by the 
 	**	SCRIPTS processor in order to start SCSI commands.
@@ -1876,8 +1910,8 @@
 	**	written with a script command.
 	**----------------------------------------------------------------
 	*/
-	u_char		msgout[8];	/* Buffer for MESSAGE OUT 	*/
-	u_char		msgin [8];	/* Buffer for MESSAGE IN	*/
+	u_char		msgout[12];	/* Buffer for MESSAGE OUT 	*/
+	u_char		msgin [12];	/* Buffer for MESSAGE IN	*/
 	u_int32		lastmsg;	/* Last SCSI message sent	*/
 	u_char		scratch;	/* Scratch for SCSI receive	*/
 
@@ -1899,6 +1933,24 @@
 	XPT_QUEHEAD	free_ccbq;	/* Queue of available CCBs	*/
 
 	/*----------------------------------------------------------------
+	**	IMMEDIATE ARBITRATION (IARB) control.
+	**	We keep track in 'last_cp' of the last CCB that has been 
+	**	queued to the SCRIPTS processor and clear 'last_cp' when 
+	**	this CCB completes. If last_cp is not zero at the moment 
+	**	we queue a new CCB, we set a flag in 'last_cp' that is 
+	**	used by the SCRIPTS as a hint for setting IARB.
+	**	We donnot set more than 'iarb_max' consecutive hints for 
+	**	IARB in order to leave devices a chance to reselect.
+	**	By the way, any non zero value of 'iarb_max' is unfair. :)
+	**----------------------------------------------------------------
+	*/
+#ifdef SCSI_NCR_IARB_SUPPORT
+	struct ccb	*last_cp;	/* Last queud CCB used for IARB	*/
+	u_short		iarb_max;	/* Max. # consecutive IARB hints*/
+	u_short		iarb_count;	/* Actual # of these hints	*/
+#endif
+
+	/*----------------------------------------------------------------
 	**	We need the LCB in order to handle disconnections and 
 	**	to count active CCBs for task management. So, we use 
 	**	a unique CCB for LUNs we donnot have the LCB yet.
@@ -1914,11 +1966,31 @@
 	int (*scatter) (ccb_p, Scsi_Cmnd *);
 
 	/*----------------------------------------------------------------
+	**	Command abort handling.
+	**	We need to synchronize tightly with the SCRIPTS 
+	**	processor in order to handle things correctly.
+	**----------------------------------------------------------------
+	*/
+	u_char		abrt_msg[4];	/* Message to send buffer	*/
+	struct scr_tblmove abrt_tbl;	/* Table for the MOV of it 	*/
+	struct scr_tblsel  abrt_sel;	/* Sync params for selection	*/
+	u_char		istat_sem;	/* Tells the chip to stop (SEM)	*/
+
+	/*----------------------------------------------------------------
 	**	Fields that should be removed or changed.
 	**----------------------------------------------------------------
 	*/
 	struct usrcmd	user;		/* Command from user		*/
 	u_char		release_stage;	/* Synchronisation stage on release  */
+
+	/*----------------------------------------------------------------
+	**	Fields that are used for integrity check
+	**----------------------------------------------------------------
+	*/
+	unsigned char  check_integrity; /* Enable midlayer integ. check on
+					 * bus scan. */
+	unsigned char check_integ_par;	/* Set if par or Init. Det. error
+					 * used only during integ check */
 };
 
 #define NCB_SCRIPT_PHYS(np,lbl)	 (np->p_script  + offsetof (struct script, lbl))
@@ -1948,34 +2020,53 @@
 
 /*
 **	Script fragments which are loaded into the on-chip RAM 
-**	of 825A, 875, 876, 895 and 896 chips.
+**	of 825A, 875, 876, 895, 895A and 896 chips.
 */
 struct script {
-	ncrcmd	start		[ 10];
+	ncrcmd	start		[ 14];
 	ncrcmd	getjob_begin	[  4];
 	ncrcmd	getjob_end	[  4];
-	ncrcmd	select		[  4];
+	ncrcmd	select		[  8];
 	ncrcmd	wf_sel_done	[  2];
 	ncrcmd	send_ident	[  2];
-	ncrcmd	select2		[  6];
+#ifdef SCSI_NCR_IARB_SUPPORT
+	ncrcmd	select2		[  8];
+#else
+	ncrcmd	select2		[  2];
+#endif
 	ncrcmd  command		[  2];
-	ncrcmd  dispatch	[ 26];
+	ncrcmd  dispatch	[ 20];
 	ncrcmd  sel_no_cmd	[ 10];
 	ncrcmd  init		[  6];
 	ncrcmd  clrack		[  4];
-	ncrcmd  databreak	[  2];
+	ncrcmd  disp_msg_in	[  2];
+	ncrcmd  disp_status	[  4];
+	ncrcmd  datai_done	[ 16];
+	ncrcmd  datao_done	[ 10];
+	ncrcmd  ign_i_w_r_msg	[  4];
 #ifdef SCSI_NCR_PROFILE_SUPPORT
 	ncrcmd  dataphase	[  4];
 #else
 	ncrcmd  dataphase	[  2];
 #endif
-	ncrcmd  status		[  8];
 	ncrcmd  msg_in		[  2];
-	ncrcmd  msg_in2		[ 16];
-	ncrcmd  msg_bad		[  6];
+	ncrcmd  msg_in2		[ 10];
+#ifdef SCSI_NCR_IARB_SUPPORT
+	ncrcmd  status		[ 14];
+#else
+	ncrcmd  status		[ 10];
+#endif
 	ncrcmd  complete	[  8];
-	ncrcmd  complete2	[  6];
+#ifdef SCSI_NCR_PCIQ_MAY_REORDER_WRITES
+	ncrcmd  complete2	[ 12];
+#else
+	ncrcmd  complete2	[ 10];
+#endif
+#ifdef SCSI_NCR_PCIQ_SYNC_ON_INTR
+	ncrcmd	done		[ 18];
+#else
 	ncrcmd	done		[ 14];
+#endif
 	ncrcmd	done_end	[  2];
 	ncrcmd  save_dp		[  8];
 	ncrcmd  restore_dp	[  4];
@@ -1984,17 +2075,33 @@
 #else
 	ncrcmd  disconnect	[ 20];
 #endif
+#ifdef SCSI_NCR_IARB_SUPPORT
+	ncrcmd  idle		[  4];
+#else
 	ncrcmd  idle		[  2];
+#endif
+#ifdef SCSI_NCR_IARB_SUPPORT
+	ncrcmd  ungetjob	[  6];
+#else
 	ncrcmd  ungetjob	[  4];
+#endif
 	ncrcmd	reselect	[  4];
-	ncrcmd	reselected	[ 44];
+	ncrcmd	reselected	[ 20];
+	ncrcmd	ultra3_bit	[  2];
+	ncrcmd	resel_cont	[ 28];
+#if   MAX_TASKS*4 > 512
+	ncrcmd	resel_tag	[ 16];
+#elif MAX_TASKS*4 > 256
+	ncrcmd	resel_tag	[ 10];
+#else
 	ncrcmd	resel_tag	[  6];
+#endif
 	ncrcmd	resel_go	[  6];
 	ncrcmd	resel_notag	[  4];
 	ncrcmd	resel_dsa	[  8];
-	ncrcmd  data_in		[MAX_SCATTERL * SCR_SG_SIZE];
+	ncrcmd  data_in		[MAX_SCATTER * SCR_SG_SIZE];
 	ncrcmd  data_in2	[  4];
-	ncrcmd  data_out	[MAX_SCATTERL * SCR_SG_SIZE];
+	ncrcmd  data_out	[MAX_SCATTER * SCR_SG_SIZE];
 	ncrcmd  data_out2	[  4];
 	ncrcmd  pm0_data	[ 16];
 	ncrcmd  pm1_data	[ 16];
@@ -2002,33 +2109,34 @@
 
 /*
 **	Script fragments which stay in main memory for all chips 
-**	except for the 896 that support 8K on-chip RAM.
+**	except for the 895A and 896 that support 8K on-chip RAM.
 */
 struct scripth {
 	ncrcmd	start64		[  2];
-	ncrcmd	select_no_atn	[  4];
+	ncrcmd	sel_for_abort	[ 18];
+	ncrcmd	sel_for_abort_1	[  2];
+	ncrcmd	select_no_atn	[  8];
 	ncrcmd	wf_sel_done_no_atn [ 4];
-	ncrcmd	cancel		[  4];
-	ncrcmd	msg_reject	[  8];
-	ncrcmd	msg_ign_residue	[ 24];
-	ncrcmd  msg_extended	[ 10];
-	ncrcmd  msg_ext_2	[ 10];
-	ncrcmd	msg_wdtr	[ 14];
+
+	ncrcmd	msg_in_etc	[ 14];
+	ncrcmd	msg_received	[  4];
+	ncrcmd	msg_weird_seen	[  4];
+	ncrcmd	msg_extended	[ 20];
+	ncrcmd  msg_bad		[  6];
+	ncrcmd	msg_weird	[  4];
+	ncrcmd	msg_weird1	[  8];
+
+	ncrcmd	wdtr_resp	[  6];
 	ncrcmd	send_wdtr	[  4];
-	ncrcmd  msg_ext_3	[ 10];
-	ncrcmd	msg_sdtr	[ 14];
+	ncrcmd	sdtr_resp	[  6];
 	ncrcmd	send_sdtr	[  4];
+	ncrcmd	ppr_resp	[  6];
+	ncrcmd	send_ppr	[  4];
 	ncrcmd	nego_bad_phase	[  4];
 	ncrcmd	msg_out_abort	[ 12];
 	ncrcmd	msg_out		[  6];
 	ncrcmd	msg_out_done	[  4];
-	ncrcmd	no_data		[ 16];
-#if	MAX_SCATTERH != 0
-	ncrcmd  hdata_in	[MAX_SCATTERH * SCR_SG_SIZE];
-	ncrcmd  hdata_in2	[  2];
-	ncrcmd  hdata_out	[MAX_SCATTERH * SCR_SG_SIZE];
-	ncrcmd  hdata_out2	[  2];
-#endif
+	ncrcmd	no_data		[ 28];
 	ncrcmd	abort_resel	[ 16];
 	ncrcmd	resend_ident	[  4];
 	ncrcmd	ident_break	[  4];
@@ -2040,18 +2148,31 @@
 	ncrcmd	bad_identify	[ 12];
 	ncrcmd	bad_i_t_l	[  4];
 	ncrcmd	bad_i_t_l_q	[  4];
-	ncrcmd	bad_status	[ 10];
+	ncrcmd	bad_status	[  6];
 	ncrcmd	tweak_pmj	[ 12];
 	ncrcmd	pm_handle	[ 20];
 	ncrcmd	pm_handle1	[  4];
 	ncrcmd	pm_save		[  4];
-	ncrcmd	pm0_save	[ 10];
-	ncrcmd	pm1_save	[ 10];
+	ncrcmd	pm0_save	[ 14];
+	ncrcmd	pm1_save	[ 14];
 
+	/* SWIDE handling */
+	ncrcmd	swide_ma_32	[  4];
+	ncrcmd	swide_ma_64	[  6];
+	ncrcmd	swide_scr_64	[ 26];
+	ncrcmd	swide_scr_64_1	[ 12];
+	ncrcmd	swide_com_64	[  6];
+	ncrcmd	swide_common	[ 10];
+	ncrcmd	swide_fin_32	[ 24];
+
 	/* Data area */
+	ncrcmd	zero		[  1];
+	ncrcmd	scratch		[  1];
+	ncrcmd	scratch1	[  1];
 	ncrcmd	pm0_data_addr	[  1];
 	ncrcmd	pm1_data_addr	[  1];
 	ncrcmd	saved_dsa	[  1];
+	ncrcmd	saved_drs	[  1];
 	ncrcmd	done_pos	[  1];
 	ncrcmd	startpos	[  1];
 	ncrcmd	targtbl		[  1];
@@ -2088,6 +2209,7 @@
 static	lcb_p	ncr_setup_lcb	(ncb_p np, u_char tn, u_char ln,
 				 u_char *inq_data);
 static	void	ncr_getclock	(ncb_p np, int mult);
+static	u_int	ncr_getpciclock (ncb_p np);
 static	void	ncr_selectclock	(ncb_p np, u_char scntl3);
 static	ccb_p	ncr_get_ccb	(ncb_p np, u_char tn, u_char ln);
 static	void	ncr_init	(ncb_p np, int reset, char * msg, u_long code);
@@ -2097,8 +2219,9 @@
 static	void	ncr_int_sir	(ncb_p np);
 static  void    ncr_int_sto     (ncb_p np);
 static  void    ncr_int_udc     (ncb_p np);
-static	u_long	ncr_lookup	(char* id);
-static	void	ncr_negotiate	(struct ncb* np, struct tcb* tp);
+static	void	ncr_negotiate	(ncb_p np, tcb_p tp);
+static	int	ncr_prepare_nego(ncb_p np, ccb_p cp, u_char *msgptr);
+static	int	ncr_ic_nego(ncb_p np, ccb_p cp, Scsi_Cmnd *cmd, u_char *msgptr);
 #ifdef SCSI_NCR_PROFILE_SUPPORT
 static	void	ncb_profile	(ncb_p np, ccb_p cp);
 #endif
@@ -2108,10 +2231,14 @@
 static	int	ncr_scatter_896R1 (ccb_p cp, Scsi_Cmnd *cmd);
 static	int	ncr_scatter	(ccb_p cp, Scsi_Cmnd *cmd);
 static	void	ncr_getsync	(ncb_p np, u_char sfac, u_char *fakp, u_char *scntl3p);
-static	void	ncr_setsync	(ncb_p np, ccb_p cp, u_char scntl3, u_char sxfer);
+static  void    ncr_get_xfer_info(ncb_p np, tcb_p tp, u_char *factor, u_char *offset, u_char *width);
+static	void	ncr_setsync	(ncb_p np, ccb_p cp, u_char scntl3, u_char sxfer, u_char scntl4);
+static void 	ncr_set_sync_wide_status (ncb_p np, u_char target);
 static	void	ncr_setup_tags	(ncb_p np, u_char tn, u_char ln);
 static	void	ncr_setwide	(ncb_p np, ccb_p cp, u_char wide, u_char ack);
+static	void	ncr_setsyncwide	(ncb_p np, ccb_p cp, u_char scntl3, u_char sxfer, u_char scntl4, u_char wide);
 static	int	ncr_show_msg	(u_char * msg);
+static	void	ncr_print_msg	(ccb_p cp, char *label, u_char * msg);
 static	int	ncr_snooptest	(ncb_p np);
 static	void	ncr_timeout	(ncb_p np);
 static  void    ncr_wakeup      (ncb_p np, u_long code);
@@ -2121,6 +2248,7 @@
 static	void	ncr_soft_reset	(ncb_p np);
 static	void	ncr_start_reset	(ncb_p np);
 static	int	ncr_reset_scsi_bus (ncb_p np, int enab_int, int settle_delay);
+static	int	ncr_compute_residual (ncb_p np, ccb_p cp);
 
 #ifdef SCSI_NCR_USER_COMMAND_SUPPORT
 static	void	ncr_usercmd	(ncb_p np);
@@ -2221,6 +2349,24 @@
 	*/
 	SCR_FROM_REG (ctest2),
 		0,
+
+	/*
+	**	Stop here if the C code wants to perform 
+	**	some error recovery procedure manually.
+	**	(Indicate this by setting SEM in ISTAT)
+	*/
+	SCR_FROM_REG (istat),
+		0,
+	/*
+	**	Report to the C code the next position in 
+	**	the start queue the SCRIPTS will schedule.
+	**	The C code must not change SCRATCHA.
+	*/
+	SCR_LOAD_ABS (scratcha, 4),
+		PADDRH (startpos),
+	SCR_INT ^ IFTRUE (MASK (SEM, SEM)),
+		SIR_SCRIPT_STOPPED,
+
 	/*
 	**	Start the next job.
 	**
@@ -2235,8 +2381,6 @@
 	**	may happen that the job address is not yet in the DSA 
 	**	and the the next queue position points to the next JOB.
 	*/
-	SCR_LOAD_ABS (scratcha, 4),
-		PADDRH (startpos),
 	SCR_LOAD_ABS (dsa, 4),
 		PADDRH (startpos),
 	SCR_LOAD_REL (temp, 4),
@@ -2300,6 +2444,19 @@
 	**	So we have to wait immediately for the next phase 
 	**	or the selection to complete or time-out.
 	*/
+
+	/*
+	**      load the savep (saved pointer) into
+	**      the actual data pointer.
+	*/
+	SCR_LOAD_REL (temp, 4),
+		offsetof (struct ccb, phys.header.savep),
+	/*
+	**      Initialize the status registers
+	*/
+	SCR_LOAD_REL (scr0, 4),
+		offsetof (struct ccb, phys.header.status),
+
 }/*-------------------------< WF_SEL_DONE >----------------------*/,{
 	SCR_INT ^ IFFALSE (WHEN (SCR_MSG_OUT)),
 		SIR_SEL_ATN_NO_MSG_OUT,
@@ -2312,17 +2469,18 @@
 	SCR_MOVE_TBL ^ SCR_MSG_OUT,
 		offsetof (struct dsb, smsg),
 }/*-------------------------< SELECT2 >----------------------*/,{
-	/*
-	**      load the savep (saved pointer) into
-	**      the actual data pointer.
-	*/
-	SCR_LOAD_REL (temp, 4),
-		offsetof (struct ccb, phys.header.savep),
+#ifdef SCSI_NCR_IARB_SUPPORT
 	/*
-	**      Initialize the status registers
+	**	Set IMMEDIATE ARBITRATION if we have been given 
+	**	a hint to do so. (Some job to do after this one).
 	*/
-	SCR_LOAD_REL (scr0, 4),
-		offsetof (struct ccb, phys.header.status),
+	SCR_FROM_REG (HF_REG),
+		0,
+	SCR_JUMPR ^ IFFALSE (MASK (HF_HINT_IARB, HF_HINT_IARB)),
+		8,
+	SCR_REG_REG (scntl1, SCR_OR, IARB),
+		0,
+#endif
 	/*
 	**	Anticipate the COMMAND phase.
 	**	This is the PHASE we expect at this point.
@@ -2358,18 +2516,12 @@
 	/*
 	**      Discard one illegal phase byte, if required.
 	*/
-	SCR_LOAD_REG (scratcha, XE_BAD_PHASE),
+	SCR_LOAD_REL (scratcha, 1),
+		offsetof (struct ccb, xerr_status),
+	SCR_REG_REG (scratcha, SCR_OR, XE_BAD_PHASE),
 		0,
 	SCR_STORE_REL (scratcha, 1),
 		offsetof (struct ccb, xerr_status),
-	SCR_JUMPR ^ IFFALSE (IF (SCR_ILG_OUT)),
-		8,
-	SCR_MOVE_ABS (1) ^ SCR_ILG_OUT,
-		NADDR (scratch),
-	SCR_JUMPR ^ IFFALSE (IF (SCR_ILG_IN)),
-		8,
-	SCR_MOVE_ABS (1) ^ SCR_ILG_IN,
-		NADDR (scratch),
 	SCR_JUMP,
 		PADDR (dispatch),
 
@@ -2422,37 +2574,115 @@
 	SCR_JUMP,
 		PADDR (dispatch),
 
-}/*-------------------------< DATABREAK >-------------------*/,{
+}/*-------------------------< DISP_MSG_IN >----------------------*/,{
 	/*
-	**	Jump to dispatcher.
+	**	Anticipate MSG_IN phase then STATUS phase.
+	**
+	**	May spare 2 SCRIPTS instructions when we have 
+	**	completed the OUTPUT of the data and the device 
+	**	goes directly to STATUS phase.
+	*/
+	SCR_JUMP ^ IFTRUE (WHEN (SCR_MSG_IN)),
+		PADDR (msg_in),
+
+}/*-------------------------< DISP_STATUS >----------------------*/,{
+	/*
+	**	Anticipate STATUS phase.
+	**
+	**	Does spare 3 SCRIPTS instructions when we have 
+	**	completed the INPUT of the data.
 	*/
+	SCR_JUMP ^ IFTRUE (WHEN (SCR_STATUS)),
+		PADDR (status),
 	SCR_JUMP,
 		PADDR (dispatch),
 
-}/*-------------------------< DATAPHASE >------------------*/,{
-#ifdef SCSI_NCR_PROFILE_SUPPORT
-	SCR_REG_REG (HF_REG, SCR_OR, HF_DATA_ST),
+}/*-------------------------< DATAI_DONE >-------------------*/,{
+	/*
+	**	If the SWIDE is not full, jump to dispatcher.
+	**	We anticipate a STATUS phase.
+	**	If we get later an IGNORE WIDE RESIDUE, we 
+	**	will alias it as a MODIFY DP (-1).
+	*/
+	SCR_FROM_REG (scntl2),
 		0,
-#endif
-	SCR_RETURN,
- 		0,
-
-}/*-------------------------< STATUS >--------------------*/,{
+	SCR_JUMP ^ IFFALSE (MASK (WSR, WSR)),
+		PADDR (disp_status),
 	/*
-	**	get the status
+	**	The SWIDE is full.
+	**	Clear this condition.
 	*/
-	SCR_MOVE_ABS (1) ^ SCR_STATUS,
-		NADDR (scratch),
+	SCR_REG_REG (scntl2, SCR_OR, WSR),
+		0,
 	/*
-	**	save status to scsi_status.
-	**	mark as complete.
+	**	Since the device is required to send any 
+	**	IGNORE WIDE RESIDUE message prior to any
+	**	other information, we just snoop the SCSI 
+	**	BUS to check for such a message.
 	*/
-	SCR_TO_REG (SS_REG),
+	SCR_JUMP ^ IFFALSE (WHEN (SCR_MSG_IN)),
+		PADDR (disp_status),
+	SCR_FROM_REG (sbdl),
 		0,
-	SCR_LOAD_REG (HS_REG, HS_COMPLETE),
+	SCR_JUMP ^ IFFALSE (DATA (M_IGN_RESIDUE)),
+		PADDR (disp_status),
+	/*
+	**	We have been ODD at the end of the transfer, 
+	**	but the device hasn't be so.
+	**	Signal a DATA OVERRUN condition to the C code.
+	*/
+	SCR_INT,
+		SIR_SWIDE_OVERRUN,
+	SCR_JUMP,
+		PADDR (dispatch),
+
+}/*-------------------------< DATAO_DONE >-------------------*/,{
+	/*
+	**	If the SODL is not full jump to dispatcher.
+	**	We anticipate a MSG IN phase or a STATUS phase.
+	*/
+	SCR_FROM_REG (scntl2),
 		0,
+	SCR_JUMP ^ IFFALSE (MASK (WSS, WSS)),
+		PADDR (disp_msg_in),
+	/*
+	**	The SODL is full, clear this condition.
+	*/
+	SCR_REG_REG (scntl2, SCR_OR, WSS),
+		0,
+	/*
+	**	And signal a DATA UNDERRUN condition 
+	**	to the C code.
+	*/
+	SCR_INT,
+		SIR_SODL_UNDERRUN,
 	SCR_JUMP,
 		PADDR (dispatch),
+
+}/*-------------------------< IGN_I_W_R_MSG >--------------*/,{
+	/*
+	**	We jump here from the phase mismatch interrupt, 
+	**	When we have a SWIDE and the device has presented 
+	**	a IGNORE WIDE RESIDUE message on the BUS.
+	**	We just have to throw away this message and then 
+	**	to jump to dispatcher.
+	*/
+	SCR_MOVE_ABS (2) ^ SCR_MSG_IN,
+		NADDR (scratch),
+	/*
+	**	Clear ACK and jump to dispatcher.
+	*/
+	SCR_JUMP,
+		PADDR (clrack),
+
+}/*-------------------------< DATAPHASE >------------------*/,{
+#ifdef SCSI_NCR_PROFILE_SUPPORT
+	SCR_REG_REG (HF_REG, SCR_OR, HF_DATA_ST),
+		0,
+#endif
+	SCR_RETURN,
+ 		0,
+
 }/*-------------------------< MSG_IN >--------------------*/,{
 	/*
 	**	Get the first byte of the message.
@@ -2464,7 +2694,8 @@
 		NADDR (msgin[0]),
 }/*-------------------------< MSG_IN2 >--------------------*/,{
 	/*
-	**	Handle this message.
+	**	Check first against 1 byte messages 
+	**	that we handle from SCRIPTS.
 	*/
 	SCR_JUMP ^ IFTRUE (DATA (M_COMPLETE)),
 		PADDR (complete),
@@ -2474,31 +2705,47 @@
 		PADDR (save_dp),
 	SCR_JUMP ^ IFTRUE (DATA (M_RESTORE_DP)),
 		PADDR (restore_dp),
-	SCR_JUMP ^ IFTRUE (DATA (M_EXTENDED)),
-		PADDRH (msg_extended),
-	SCR_JUMP ^ IFTRUE (DATA (M_NOOP)),
-		PADDR (clrack),
-	SCR_JUMP ^ IFTRUE (DATA (M_REJECT)),
-		PADDRH (msg_reject),
-	SCR_JUMP ^ IFTRUE (DATA (M_IGN_RESIDUE)),
-		PADDRH (msg_ign_residue),
 	/*
-	**	Rest of the messages left as
-	**	an exercise ...
-	**
-	**	Unimplemented messages:
-	**	fall through to MSG_BAD.
+	**	We handle all other messages from the 
+	**	C code, so no need to waste on-chip RAM 
+	**	for those ones.
 	*/
-}/*-------------------------< MSG_BAD >------------------*/,{
+	SCR_JUMP,
+		PADDRH (msg_in_etc),
+
+}/*-------------------------< STATUS >--------------------*/,{
 	/*
-	**	unimplemented message - reject it.
+	**	get the status
 	*/
-	SCR_INT,
-		SIR_REJECT_TO_SEND,
-	SCR_SET (SCR_ATN),
+	SCR_MOVE_ABS (1) ^ SCR_STATUS,
+		NADDR (scratch),
+#ifdef SCSI_NCR_IARB_SUPPORT
+	/*
+	**	If STATUS is not GOOD, clear IMMEDIATE ARBITRATION, 
+	**	since we may have to tamper the start queue from 
+	**	the C code.
+	*/
+	SCR_JUMPR ^ IFTRUE (DATA (S_GOOD)),
+		8,
+	SCR_REG_REG (scntl1, SCR_AND, ~IARB),
+		0,
+#endif
+	/*
+	**	save status to scsi_status.
+	**	mark as complete.
+	*/
+	SCR_TO_REG (SS_REG),
+		0,
+	SCR_LOAD_REG (HS_REG, HS_COMPLETE),
 		0,
+	/*
+	**	Anticipate the MESSAGE PHASE for 
+	**	the TASK COMPLETE message.
+	*/
+	SCR_JUMP ^ IFTRUE (WHEN (SCR_MSG_IN)),
+		PADDR (msg_in),
 	SCR_JUMP,
-		PADDR (clrack),
+		PADDR (dispatch),
 
 }/*-------------------------< COMPLETE >-----------------*/,{
 	/*
@@ -2535,6 +2782,18 @@
 	SCR_STORE_REL (scr0, 4),
 		offsetof (struct ccb, phys.header.status),
 
+#ifdef SCSI_NCR_PCIQ_MAY_REORDER_WRITES
+	/*
+	**	Some bridges may reorder DMA writes to memory.
+	**	We donnot want the CPU to deal with completions  
+	**	without all the posted write having been flushed 
+	**	to memory. This DUMMY READ should flush posted 
+	**	buffers prior to the CPU having to deal with 
+	**	completions.
+	*/
+	SCR_LOAD_REL (scr0, 4),	/* DUMMY READ */
+		offsetof (struct ccb, phys.header.status),
+#endif
 	/*
 	**	If command resulted in not GOOD status,
 	**	call the C code if needed.
@@ -2544,7 +2803,35 @@
 	SCR_CALL ^ IFFALSE (DATA (S_GOOD)),
 		PADDRH (bad_status),
 
+	/*
+	**	If we performed an auto-sense, call 
+	**	the C code to synchronyze task aborts 
+	**	with UNIT ATTENTION conditions.
+	*/
+	SCR_FROM_REG (HF_REG),
+		0,
+	SCR_INT ^ IFTRUE (MASK (HF_AUTO_SENSE, HF_AUTO_SENSE)),
+		SIR_AUTO_SENSE_DONE,
+
 }/*------------------------< DONE >-----------------*/,{
+#ifdef SCSI_NCR_PCIQ_SYNC_ON_INTR
+	/*
+	**	It seems that some bridges flush everything 
+	**	when the INTR line is raised. For these ones, 
+	**	we can just ensure that the INTR line will be 
+	**	raised before each completion. So, if it happens 
+	**	that we have been faster that the CPU, we just 
+	**	have to synchronize with it. A dummy programmed 
+	**	interrupt will do the trick.
+	**	Note that we overlap at most 1 IO with the CPU 
+	**	in this situation and that the IRQ line must not 
+	**	be shared.
+	*/
+	SCR_FROM_REG (istat),
+		0,
+	SCR_INT ^ IFTRUE (MASK (INTF, INTF)),
+		SIR_DUMMY_INTERRUPT,
+#endif
 	/*
 	**	Copy the DSA to the DONE QUEUE and 
 	**	signal completion to the host.
@@ -2684,7 +2971,20 @@
 	*/
 	SCR_NO_OP,
 		0,
+#ifdef SCSI_NCR_IARB_SUPPORT
+	SCR_JUMPR,
+		8,
+#endif
 }/*-------------------------< UNGETJOB >-----------------*/,{
+#ifdef SCSI_NCR_IARB_SUPPORT
+	/*
+	**	Set IMMEDIATE ARBITRATION, for the next time.
+	**	This will give us better chance to win arbitration 
+	**	for the job we just wanted to do.
+	*/
+	SCR_REG_REG (scntl1, SCR_OR, IARB),
+		0,
+#endif
 	/*
 	**	We are not able to restart the SCRIPTS if we are 
 	**	interrupted and these instruction haven't been 
@@ -2743,6 +3043,15 @@
 		offsetof(struct tcb, wval),
 	SCR_LOAD_REL (sxfer, 1),
 		offsetof(struct tcb, sval),
+}/*-------------------------< ULTRA3_BIT >------------------*/,{
+	/*
+	**	Write with uval value. Patch if device
+	**	does not support Ultra3.
+	*/
+
+	SCR_LOAD_REL (scntl4, 1),
+		offsetof(struct tcb, uval),
+}/*-------------------------< RESEL_CONT >------------------*/,{
 	/*
 	**	If MESSAGE IN  phase as expected,
 	**	read the data directly from the BUS DATA lines.
@@ -2763,12 +3072,13 @@
 	/*
 	**	It is an IDENTIFY message,
 	**	Load the LUN control block address.
-	**	Avoid nasty address calculation if LUN #0.
+	**	If LUN 0, avoid a PCI BUS ownership by loading 
+	**	directly 'b_lun0' from the TCB.
 	*/
+	SCR_JUMPR ^ IFTRUE (MASK (0x0, 0x3f)),
+		48,
 	SCR_LOAD_REL (dsa, 4),
 		offsetof(struct tcb, b_luntbl),
-	SCR_JUMPR ^ IFTRUE (MASK (0x0, 0x3f)),
-		24,
 	SCR_SFBR_REG (dsa, SCR_SHL, 0),
 		0,
 	SCR_REG_REG (dsa, SCR_SHL, 0),
@@ -2777,6 +3087,14 @@
 		0,
 	SCR_LOAD_REL (dsa, 4),
 		0,
+	SCR_JUMPR,
+		8,
+	/*
+	**	LUN 0 special case (but usual one :))
+	*/
+	SCR_LOAD_REL (dsa, 4),
+		offsetof(struct tcb, b_lun0),
+
 	/*
 	**	Load the reselect task action for this LUN.
 	**	Load the tasks DSA array for this LUN.
@@ -2788,7 +3106,6 @@
 		offsetof(struct lcb, b_tasktbl),
 	SCR_RETURN,
 		0,
-
 }/*-------------------------< RESEL_TAG >-------------------*/,{
 	/*
 	**	Read IDENTIFY + SIMPLE + TAG using a single MOVE.
@@ -2807,6 +3124,23 @@
 	*/
 	SCR_REG_SFBR (sidl, SCR_SHL, 0),
 		0,
+#if MAX_TASKS*4 > 512
+	SCR_JUMPR ^ IFFALSE (CARRYSET),
+		8,
+	SCR_REG_REG (dsa1, SCR_OR, 2),
+		0,
+	SCR_REG_REG (sfbr, SCR_SHL, 0),
+		0,
+	SCR_JUMPR ^ IFFALSE (CARRYSET),
+		8,
+	SCR_REG_REG (dsa1, SCR_OR, 1),
+		0,
+#elif MAX_TASKS*4 > 256
+	SCR_JUMPR ^ IFFALSE (CARRYSET),
+		8,
+	SCR_REG_REG (dsa1, SCR_OR, 1),
+		0,
+#endif
 	/*
 	**	Retrieve the DSA of this task.
 	**	JUMP indirectly to the restart point of the CCB.
@@ -2859,13 +3193,11 @@
 }/*-------------------------< DATA_IN >--------------------*/,{
 /*
 **	Because the size depends on the
-**	#define MAX_SCATTERL parameter,
+**	#define MAX_SCATTER parameter,
 **	it is filled in at runtime.
 **
-**  ##===========< i=0; i<MAX_SCATTERL >=========
-**  ||	SCR_CALL ^ IFFALSE (WHEN (SCR_DATA_IN)),
-**  ||		PADDR (databreak),
-**  ||	SCR_MOVE_TBL ^ SCR_DATA_IN,
+**  ##===========< i=0; i<MAX_SCATTER >=========
+**  ||	SCR_CHMOV_TBL ^ SCR_DATA_IN,
 **  ||		offsetof (struct dsb, data[ i]),
 **  ##==========================================
 **
@@ -2874,19 +3206,17 @@
 0
 }/*-------------------------< DATA_IN2 >-------------------*/,{
 	SCR_CALL,
-		PADDR (databreak),
+		PADDR (datai_done),
 	SCR_JUMP,
 		PADDRH (no_data),
 }/*-------------------------< DATA_OUT >--------------------*/,{
 /*
 **	Because the size depends on the
-**	#define MAX_SCATTERL parameter,
+**	#define MAX_SCATTER parameter,
 **	it is filled in at runtime.
 **
-**  ##===========< i=0; i<MAX_SCATTERL >=========
-**  ||	SCR_CALL ^ IFFALSE (WHEN (SCR_DATA_OUT)),
-**  ||		PADDR (databreak),
-**  ||	SCR_MOVE_TBL ^ SCR_DATA_OUT,
+**  ##===========< i=0; i<MAX_SCATTER >=========
+**  ||	SCR_CHMOV_TBL ^ SCR_DATA_OUT,
 **  ||		offsetof (struct dsb, data[ i]),
 **  ##==========================================
 **
@@ -2895,7 +3225,7 @@
 0
 }/*-------------------------< DATA_OUT2 >-------------------*/,{
 	SCR_CALL,
-		PADDR (databreak),
+		PADDR (datao_done),
 	SCR_JUMP,
 		PADDRH (no_data),
 
@@ -2912,11 +3242,11 @@
 	*/
 	SCR_JUMPR ^ IFFALSE (WHEN (SCR_DATA_IN)),
 		16,
-	SCR_MOVE_TBL ^ SCR_DATA_IN,
+	SCR_CHMOV_TBL ^ SCR_DATA_IN,
 		offsetof (struct ccb, phys.pm0.sg),
 	SCR_JUMPR,
 		8,
-	SCR_MOVE_TBL ^ SCR_DATA_OUT,
+	SCR_CHMOV_TBL ^ SCR_DATA_OUT,
 		offsetof (struct ccb, phys.pm0.sg),
 	/*
 	**	Clear the flag that told we were in 
@@ -2946,11 +3276,11 @@
 	*/
 	SCR_JUMPR ^ IFFALSE (WHEN (SCR_DATA_IN)),
 		16,
-	SCR_MOVE_TBL ^ SCR_DATA_IN,
+	SCR_CHMOV_TBL ^ SCR_DATA_IN,
 		offsetof (struct ccb, phys.pm1.sg),
 	SCR_JUMPR,
 		8,
-	SCR_MOVE_TBL ^ SCR_DATA_OUT,
+	SCR_CHMOV_TBL ^ SCR_DATA_OUT,
 		offsetof (struct ccb, phys.pm1.sg),
 	/*
 	**	Clear the flag that told we were in 
@@ -2973,12 +3303,70 @@
 static	struct scripth scripth0 __initdata = {
 /*------------------------< START64 >-----------------------*/{
 	/*
-	**	SCRIPT entry point for the 896.
+	**	SCRIPT entry point for the 895A and the 896.
 	**	For now, there is no specific stuff for that 
 	**	chip at this point, but this may come.
 	*/
 	SCR_JUMP,
 		PADDR (init),
+
+}/*-----------------------< SEL_FOR_ABORT >------------------*/,{
+	/*
+	**	We are jumped here by the C code, if we have 
+	**	some target to reset or some disconnected 
+	**	job to abort. Since error recovery is a serious 
+	**	busyness, we will really reset the SCSI BUS, if 
+	**	case of a SCSI interrupt occuring in this path.
+	*/
+
+	/*
+	**	Set initiator mode.
+	*/
+	SCR_CLR (SCR_TRG),
+		0,
+	/*
+	**      And try to select this target.
+	*/
+	SCR_SEL_TBL_ATN ^ offsetof (struct ncb, abrt_sel),
+		PADDR (reselect),
+
+	/*
+	**	Wait for the selection to complete or 
+	**	the selection to time out.
+	*/
+	SCR_JUMPR ^ IFFALSE (WHEN (SCR_MSG_OUT)),
+		-8,
+	/*
+	**	Call the C code.
+	*/
+	SCR_INT,
+		SIR_TARGET_SELECTED,
+	/*
+	**	The C code should let us continue here. 
+	**	Send the 'kiss of death' message.
+	**	We expect an immediate disconnect once 
+	**	the target has eaten the message.
+	*/
+	SCR_REG_REG (scntl2, SCR_AND, 0x7f),
+		0,
+	SCR_MOVE_TBL ^ SCR_MSG_OUT,
+		offsetof (struct ncb, abrt_tbl),
+	SCR_CLR (SCR_ACK|SCR_ATN),
+		0,
+	SCR_WAIT_DISC,
+		0,
+	/*
+	**	Tell the C code that we are done.
+	*/
+	SCR_INT,
+		SIR_ABORT_SENT,
+}/*-----------------------< SEL_FOR_ABORT_1 >--------------*/,{
+	/*
+	**	Jump at scheduler.
+	*/
+	SCR_JUMP,
+		PADDR (start),
+
 }/*------------------------< SELECT_NO_ATN >-----------------*/,{
 	/*
 	**	Set Initiator mode.
@@ -2989,6 +3377,18 @@
 		0,
 	SCR_SEL_TBL ^ offsetof (struct dsb, select),
 		PADDR (ungetjob),
+	/*
+	**      load the savep (saved pointer) into
+	**      the actual data pointer.
+	*/
+	SCR_LOAD_REL (temp, 4),
+		offsetof (struct ccb, phys.header.savep),
+	/*
+	**      Initialize the status registers
+	*/
+	SCR_LOAD_REL (scr0, 4),
+		offsetof (struct ccb, phys.header.status),
+
 }/*------------------------< WF_SEL_DONE_NO_ATN >-----------------*/,{
 	/*
 	**	Wait immediately for the next phase or 
@@ -2999,129 +3399,111 @@
 	SCR_JUMP,
 		PADDR (select2),
 
-}/*-------------------------< CANCEL >------------------------*/,{
+}/*-------------------------< MSG_IN_ETC >--------------------*/,{
 	/*
-	**	Load the host status.
+	**	If it is an EXTENDED (variable size message)
+	**	Handle it.
 	*/
-	SCR_LOAD_REG (HS_REG, HS_ABORTED),
-		0,
-	SCR_JUMP,
-		PADDR (complete2),
-
-}/*-------------------------< MSG_REJECT >---------------*/,{
+	SCR_JUMP ^ IFTRUE (DATA (M_EXTENDED)),
+		PADDRH (msg_extended),
 	/*
-	**	If a negotiation was in progress,
-	**	negotiation failed.
-	**	Otherwise just make host log this message
+	**	Let the C code handle any other 
+	**	1 byte message.
 	*/
-	SCR_FROM_REG (HS_REG),
+	SCR_JUMP ^ IFTRUE (MASK (0x00, 0xf0)),
+		PADDRH (msg_received),
+	SCR_JUMP ^ IFTRUE (MASK (0x10, 0xf0)),
+		PADDRH (msg_received),
+	/*
+	**	We donnot handle 2 bytes messages from SCRIPTS.
+	**	So, let the C code deal with these ones too.
+	*/
+	SCR_JUMP ^ IFFALSE (MASK (0x20, 0xf0)),
+		PADDRH (msg_weird_seen),
+	SCR_CLR (SCR_ACK),
 		0,
-	SCR_INT ^ IFFALSE (DATA (HS_NEGOTIATE)),
-		SIR_REJECT_RECEIVED,
-	SCR_INT ^ IFTRUE (DATA (HS_NEGOTIATE)),
-		SIR_NEGO_FAILED,
+	SCR_MOVE_ABS (1) ^ SCR_MSG_IN,
+		NADDR (msgin[1]),
 	SCR_JUMP,
-		PADDR (clrack),
+		PADDRH (msg_received),
 
-}/*-------------------------< MSG_IGN_RESIDUE >----------*/,{
+}/*-------------------------< MSG_RECEIVED >--------------------*/,{
+	SCR_LOAD_REL (scratcha, 4),	/* DUMMY READ */
+		0,
+	SCR_INT,
+		SIR_MSG_RECEIVED,
+
+}/*-------------------------< MSG_WEIRD_SEEN >------------------*/,{
+	SCR_LOAD_REL (scratcha1, 4),	/* DUMMY READ */
+		0,
+	SCR_INT,
+		SIR_MSG_WEIRD,
+
+}/*-------------------------< MSG_EXTENDED >--------------------*/,{
 	/*
-	**	Terminate cycle
+	**	Clear ACK and get the next byte 
+	**	assumed to be the message length.
 	*/
 	SCR_CLR (SCR_ACK),
 		0,
-	SCR_JUMP ^ IFFALSE (WHEN (SCR_MSG_IN)),
-		PADDR (dispatch),
-	/*
-	**	get residue size.
-	*/
 	SCR_MOVE_ABS (1) ^ SCR_MSG_IN,
 		NADDR (msgin[1]),
 	/*
-	**	Size is 0 .. ignore message.
+	**	Try to catch some unlikely situations as 0 length 
+	**	or too large the length.
 	*/
 	SCR_JUMP ^ IFTRUE (DATA (0)),
-		PADDR (clrack),
-	/*
-	**	Size is not 1 .. have to interrupt.
-	*/
-	SCR_JUMPR ^ IFFALSE (DATA (1)),
-		40,
-	/*
-	**	Check for residue byte in swide register
-	*/
-	SCR_FROM_REG (scntl2),
+		PADDRH (msg_weird_seen),
+	SCR_TO_REG (scratcha),
 		0,
-	SCR_JUMPR ^ IFFALSE (MASK (WSR, WSR)),
-		16,
+	SCR_REG_REG (sfbr, SCR_ADD, (256-8)),
+		0,
+	SCR_JUMP ^ IFTRUE (CARRYSET),
+		PADDRH (msg_weird_seen),
 	/*
-	**	There IS data in the swide register.
-	**	Discard it.
+	**	We donnot handle extended messages from SCRIPTS.
+	**	Read the amount of data correponding to the 
+	**	message length and call the C code.
 	*/
-	SCR_REG_REG (scntl2, SCR_OR, WSR),
+	SCR_STORE_REL (scratcha, 1),
+		offsetof (struct dsb, smsg_ext.size),
+	SCR_CLR (SCR_ACK),
 		0,
+	SCR_MOVE_TBL ^ SCR_MSG_IN,
+		offsetof (struct dsb, smsg_ext),
 	SCR_JUMP,
-		PADDR (clrack),
+		PADDRH (msg_received),
+
+}/*-------------------------< MSG_BAD >------------------*/,{
 	/*
-	**	Load again the size to the sfbr register.
+	**	unimplemented message - reject it.
 	*/
-	SCR_FROM_REG (scratcha),
-		0,
 	SCR_INT,
-		SIR_IGN_RESIDUE,
+		SIR_REJECT_TO_SEND,
+	SCR_SET (SCR_ATN),
+		0,
 	SCR_JUMP,
 		PADDR (clrack),
 
-}/*-------------------------< MSG_EXTENDED >-------------*/,{
+}/*-------------------------< MSG_WEIRD >--------------------*/,{
 	/*
-	**	Terminate cycle
+	**	weird message received
+	**	ignore all MSG IN phases and reject it.
 	*/
-	SCR_CLR (SCR_ACK),
+	SCR_INT,
+		SIR_REJECT_TO_SEND,
+	SCR_SET (SCR_ATN),
 		0,
-	SCR_JUMP ^ IFFALSE (WHEN (SCR_MSG_IN)),
-		PADDR (dispatch),
-	/*
-	**	get length.
-	*/
-	SCR_MOVE_ABS (1) ^ SCR_MSG_IN,
-		NADDR (msgin[1]),
-	/*
-	*/
-	SCR_JUMP ^ IFTRUE (DATA (3)),
-		PADDRH (msg_ext_3),
-	SCR_JUMP ^ IFFALSE (DATA (2)),
-		PADDR (msg_bad),
-}/*-------------------------< MSG_EXT_2 >----------------*/,{
+}/*-------------------------< MSG_WEIRD1 >--------------------*/,{
 	SCR_CLR (SCR_ACK),
 		0,
 	SCR_JUMP ^ IFFALSE (WHEN (SCR_MSG_IN)),
 		PADDR (dispatch),
-	/*
-	**	get extended message code.
-	*/
 	SCR_MOVE_ABS (1) ^ SCR_MSG_IN,
-		NADDR (msgin[2]),
-	SCR_JUMP ^ IFTRUE (DATA (M_X_WIDE_REQ)),
-		PADDRH (msg_wdtr),
-	/*
-	**	unknown extended message
-	*/
+		NADDR (scratch),
 	SCR_JUMP,
-		PADDR (msg_bad)
-}/*-------------------------< MSG_WDTR >-----------------*/,{
-	SCR_CLR (SCR_ACK),
-		0,
-	SCR_JUMP ^ IFFALSE (WHEN (SCR_MSG_IN)),
-		PADDR (dispatch),
-	/*
-	**	get data bus width
-	*/
-	SCR_MOVE_ABS (1) ^ SCR_MSG_IN,
-		NADDR (msgin[3]),
-	/*
-	**	let the host do the real work.
-	*/
-	SCR_INT,
-		SIR_NEGO_WIDE,
+		PADDRH (msg_weird1),
+}/*-------------------------< WDTR_RESP >----------------*/,{
 	/*
 	**	let the target fetch our answer.
 	*/
@@ -3141,39 +3523,27 @@
 	SCR_JUMP,
 		PADDRH (msg_out_done),
 
-}/*-------------------------< MSG_EXT_3 >----------------*/,{
-	SCR_CLR (SCR_ACK),
-		0,
-	SCR_JUMP ^ IFFALSE (WHEN (SCR_MSG_IN)),
-		PADDR (dispatch),
+}/*-------------------------< SDTR_RESP >-------------*/,{
 	/*
-	**	get extended message code.
-	*/
-	SCR_MOVE_ABS (1) ^ SCR_MSG_IN,
-		NADDR (msgin[2]),
-	SCR_JUMP ^ IFTRUE (DATA (M_X_SYNC_REQ)),
-		PADDRH (msg_sdtr),
-	/*
-	**	unknown extended message
+	**	let the target fetch our answer.
 	*/
-	SCR_JUMP,
-		PADDR (msg_bad)
-
-}/*-------------------------< MSG_SDTR >-----------------*/,{
+	SCR_SET (SCR_ATN),
+		0,
 	SCR_CLR (SCR_ACK),
 		0,
-	SCR_JUMP ^ IFFALSE (WHEN (SCR_MSG_IN)),
-		PADDR (dispatch),
-	/*
-	**	get period and offset
-	*/
-	SCR_MOVE_ABS (2) ^ SCR_MSG_IN,
-		NADDR (msgin[3]),
+	SCR_JUMP ^ IFFALSE (WHEN (SCR_MSG_OUT)),
+		PADDRH (nego_bad_phase),
+
+}/*-------------------------< SEND_SDTR >-------------*/,{
 	/*
-	**	let the host do the real work.
+	**	Send the M_X_SYNC_REQ
 	*/
-	SCR_INT,
-		SIR_NEGO_SYNC,
+	SCR_MOVE_ABS (5) ^ SCR_MSG_OUT,
+		NADDR (msgout),
+	SCR_JUMP,
+		PADDRH (msg_out_done),
+
+}/*-------------------------< PPR_RESP >-------------*/,{
 	/*
 	**	let the target fetch our answer.
 	*/
@@ -3184,11 +3554,11 @@
 	SCR_JUMP ^ IFFALSE (WHEN (SCR_MSG_OUT)),
 		PADDRH (nego_bad_phase),
 
-}/*-------------------------< SEND_SDTR >-------------*/,{
+}/*-------------------------< SEND_PPR >-------------*/,{
 	/*
-	**	Send the M_X_SYNC_REQ
+	**	Send the M_X_PPR_REQ
 	*/
-	SCR_MOVE_ABS (5) ^ SCR_MSG_OUT,
+	SCR_MOVE_ABS (8) ^ SCR_MSG_OUT,
 		NADDR (msgout),
 	SCR_JUMP,
 		PADDRH (msg_out_done),
@@ -3256,14 +3626,16 @@
 	**	or in the wrong direction.
 	**      Remember that in extended error.
 	*/
-	SCR_LOAD_REG (scratcha, XE_EXTRA_DATA),
+	SCR_LOAD_REL (scratcha, 1),
+		offsetof (struct ccb, xerr_status),
+	SCR_REG_REG (scratcha, SCR_OR, XE_EXTRA_DATA),
 		0,
 	SCR_STORE_REL (scratcha, 1),
 		offsetof (struct ccb, xerr_status),
 	/*
 	**      Discard one data byte, if required.
 	*/
-	SCR_JUMPR ^ IFFALSE (WHEN (SCR_DATA_OUT)),
+	SCR_JUMPR ^ IFFALSE (IF (SCR_DATA_OUT)),
 		8,
 	SCR_MOVE_ABS (1) ^ SCR_DATA_OUT,
 		NADDR (scratch),
@@ -3272,57 +3644,28 @@
 	SCR_MOVE_ABS (1) ^ SCR_DATA_IN,
 		NADDR (scratch),
 	/*
+	**	Count this byte.
+	**	This will allow to return a positive 
+	**	residual to user.
+	*/
+	SCR_LOAD_REL (scratcha, 4),
+		offsetof (struct ccb, phys.extra_bytes),
+	SCR_REG_REG (scratcha,  SCR_ADD,  0x01),
+		0,
+	SCR_REG_REG (scratcha1, SCR_ADDC, 0),
+		0,
+	SCR_REG_REG (scratcha2, SCR_ADDC, 0),
+		0,
+	SCR_STORE_REL (scratcha, 4),
+		offsetof (struct ccb, phys.extra_bytes),
+	/*
 	**      .. and repeat as required.
 	*/
 	SCR_CALL,
-		PADDR (databreak),
+		PADDR (dispatch),
 	SCR_JUMP,
 		PADDRH (no_data),
 
-#if	MAX_SCATTERH != 0
-
-}/*-------------------------< HDATA_IN >-------------------*/,{
-/*
-**	Because the size depends on the
-**	#define MAX_SCATTERH parameter,
-**	it is filled in at runtime.
-**
-**  ##==< i=MAX_SCATTERL; i<MAX_SCATTERL+MAX_SCATTERH >==
-**  ||	SCR_CALL ^ IFFALSE (WHEN (SCR_DATA_IN)),
-**  ||		PADDR (databreak),
-**  ||	SCR_MOVE_TBL ^ SCR_DATA_IN,
-**  ||		offsetof (struct dsb, data[ i]),
-**  ##===================================================
-**
-**---------------------------------------------------------
-*/
-0
-}/*-------------------------< HDATA_IN2 >------------------*/,{
-	SCR_JUMP,
-		PADDR (data_in),
-
-}/*-------------------------< HDATA_OUT >-------------------*/,{
-/*
-**	Because the size depends on the
-**	#define MAX_SCATTERH parameter,
-**	it is filled in at runtime.
-**
-**  ##==< i=MAX_SCATTERL; i<MAX_SCATTERL+MAX_SCATTERH >==
-**  ||	SCR_CALL ^ IFFALSE (WHEN (SCR_DATA_OUT)),
-**  ||		PADDR (databreak),
-**  ||	SCR_MOVE_TBL ^ SCR_DATA_OUT,
-**  ||		offsetof (struct dsb, data[ i]),
-**  ##===================================================
-**
-**---------------------------------------------------------
-*/
-0
-}/*-------------------------< HDATA_OUT2 >------------------*/,{
-	SCR_JUMP,
-		PADDR (data_out),
-
-#endif	/* MAX_SCATTERH */
-
 }/*-------------------------< ABORT_RESEL >----------------*/,{
 	SCR_SET (SCR_ATN),
 		0,
@@ -3366,13 +3709,12 @@
 	SCR_JUMP,
 		PADDR (select2),
 }/*-------------------------< SDATA_IN >-------------------*/,{
-	SCR_MOVE_TBL ^ SCR_DATA_IN,
+	SCR_CHMOV_TBL ^ SCR_DATA_IN,
 		offsetof (struct dsb, sense),
 	SCR_CALL,
-		PADDR (databreak),
+		PADDR (dispatch),
 	SCR_JUMP,
 		PADDRH (no_data),
-
 }/*-------------------------< DATA_IO >--------------------*/,{
 	/*
 	**	We jump here if the data direction was unknown at the 
@@ -3467,17 +3809,14 @@
 		PADDRH (abort_resel),
 }/*-------------------------< BAD_STATUS >-----------------*/,{
 	/*
-	**	If command resulted in either QUEUE FULL,
-	**	CHECK CONDITION or COMMAND TERMINATED,
-	**	call the C code.
+	**	Anything different from INTERMEDIATE 
+	**	CONDITION MET should be a bad SCSI status, 
+	**	given that GOOD status has already been tested.
+	**	Call the C code.
 	*/
 	SCR_LOAD_ABS (scratcha, 4),
 		PADDRH (startpos),
-	SCR_INT ^ IFTRUE (DATA (S_QUEUE_FULL)),
-		SIR_BAD_STATUS,
-	SCR_INT ^ IFTRUE (DATA (S_CHECK_COND)),
-		SIR_BAD_STATUS,
-	SCR_INT ^ IFTRUE (DATA (S_TERMINATED)),
+	SCR_INT ^ IFFALSE (DATA (S_COND_MET)),
 		SIR_BAD_STATUS,
 	SCR_RETURN,
 		0,
@@ -3574,6 +3913,17 @@
 	SCR_JUMP ^ IFTRUE (MASK (HF_ACT_PM, HF_ACT_PM)),
 		PADDRH (pm1_save),
 }/*-------------------------< PM0_SAVE >-------------------*/,{
+	SCR_STORE_REL (ia, 4),
+		offsetof(struct ccb, phys.pm0.ret),
+	/*
+	**	If WSR bit is set, either UA and RBC may 
+	**	have to be changed whatever the device wants 
+	**	to ignore this residue ot not.
+	*/
+	SCR_FROM_REG (scntl2),
+		0,
+	SCR_CALL ^ IFTRUE (MASK (WSR, WSR)),
+		PADDRH (swide_scr_64),
 	/*
 	**	Save the remaining byte count, the updated 
 	**	address and the return address.
@@ -3582,16 +3932,25 @@
 		offsetof(struct ccb, phys.pm0.sg.size),
 	SCR_STORE_REL (ua, 4),
 		offsetof(struct ccb, phys.pm0.sg.addr),
-	SCR_STORE_REL (ia, 4),
-		offsetof(struct ccb, phys.pm0.ret),
 	/*
 	**	Set the current pointer at the PM0 DATA mini-script.
 	*/
 	SCR_LOAD_ABS (temp, 4),
 		PADDRH (pm0_data_addr),
 	SCR_JUMP,
-		PADDR (databreak),
+		PADDR (dispatch),
 }/*-------------------------< PM1_SAVE >-------------------*/,{
+	SCR_STORE_REL (ia, 4),
+		offsetof(struct ccb, phys.pm1.ret),
+	/*
+	**	If WSR bit is set, either UA and RBC may 
+	**	have been changed whatever the device wants 
+	**	to ignore this residue or not.
+	*/
+	SCR_FROM_REG (scntl2),
+		0,
+	SCR_CALL ^ IFTRUE (MASK (WSR, WSR)),
+		PADDRH (swide_scr_64),
 	/*
 	**	Save the remaining byte count, the updated 
 	**	address and the return address.
@@ -3600,61 +3959,260 @@
 		offsetof(struct ccb, phys.pm1.sg.size),
 	SCR_STORE_REL (ua, 4),
 		offsetof(struct ccb, phys.pm1.sg.addr),
-	SCR_STORE_REL (ia, 4),
-		offsetof(struct ccb, phys.pm1.ret),
 	/*
 	**	Set the current pointer at the PM1 DATA mini-script.
 	*/
 	SCR_LOAD_ABS (temp, 4),
 		PADDRH (pm1_data_addr),
 	SCR_JUMP,
-		PADDR (databreak),
-}/*-------------------------< PM0_DATA_ADDR >---------------*/,{
-	SCR_DATA_ZERO,
-}/*-------------------------< PM1_DATA_ADDR >---------------*/,{
-	SCR_DATA_ZERO,
-}/*-------------------------< SAVED_DSA >-------------------*/,{
-	SCR_DATA_ZERO,
-}/*-------------------------< DONE_POS >--------------------*/,{
-	SCR_DATA_ZERO,
-}/*-------------------------< STARTPOS >--------------------*/,{
-	SCR_DATA_ZERO,
-}/*-------------------------< TARGTBL >---------------------*/,{
-	SCR_DATA_ZERO,
-
-
-/*
-** We may use MEMORY MOVE instructions to load the on chip-RAM,
-** if it happens that mapping PCI memory is not possible.
-** But writing the RAM from the CPU is the preferred method, 
-** since PCI 2.2 seems to disallow PCI self-mastering.
-*/
-
-#ifdef SCSI_NCR_PCI_MEM_NOT_SUPPORTED
+		PADDR (dispatch),
 
-}/*-------------------------< START_RAM >-------------------*/,{
+}/*--------------------------< SWIDE_MA_32 >-----------------------*/,{
 	/*
-	**	Load the script into on-chip RAM, 
-	**	and jump to start point.
+	**	Handling of the SWIDE for 32 bit chips.
+	**
+	**	We jump here from the C code with SCRATCHA 
+	**	containing the address to write the SWIDE.
+	**	- Save 32 bit address in <scratch>.
 	*/
-	SCR_COPY (sizeof (struct script)),
-}/*-------------------------< SCRIPT0_BA >--------------------*/,{
-		0,
-		PADDR (start),
+	SCR_STORE_ABS (scratcha, 4),
+		PADDRH (scratch),
 	SCR_JUMP,
-		PADDR (init),
-
-}/*-------------------------< START_RAM64 >--------------------*/,{
+		PADDRH (swide_common),
+}/*--------------------------< SWIDE_MA_64 >-----------------------*/,{
 	/*
-	**	Load the RAM and start for 64 bit PCI (896).
-	**	Both scripts (script and scripth) are loaded into 
-	**	the RAM which is 8K (4K for 825A/875/895).
-	**	We also need to load some 32-63 bit segments 
-	**	address of the SCRIPTS processor.
-	**	LOAD/STORE ABSOLUTE always refers to on-chip RAM 
-	**	in our implementation. The main memory is 
-	**	accessed using LOAD/STORE DSA RELATIVE.
+	**	Handling of the SWIDE for 64 bit chips when the 
+	**	hardware handling of phase mismatch is disabled.
+	**
+	**	We jump here from the C code with SCRATCHA 
+	**	containing the address to write the SWIDE and 
+	**	SBR containing bit 32..39 of this address.
+	**	- Save 32 bit address in <scratch>.
+	**	- Move address bit 32..39 to SFBR.
 	*/
+	SCR_STORE_ABS (scratcha, 4),
+		PADDRH (scratch),
+	SCR_FROM_REG (sbr),
+		0,
+	SCR_JUMP,
+		PADDRH (swide_com_64),
+}/*--------------------------< SWIDE_SCR_64 >-----------------------*/,{
+	/*
+	**	Handling of the SWIDE for 64 bit chips when 
+	**	hardware phase mismatch is enabled.
+	**	We are entered with a SCR_CALL from PMO_SAVE 
+	**	and PM1_SAVE sub-scripts.
+	**
+	**	Snoop the SCSI BUS in case of the device 
+	**	willing to ignore this residue.
+	**	If it does, we must only increment the RBC, 
+	**	since this register does reflect all bytes 
+	**	received from the SCSI BUS including the SWIDE.
+	*/
+	SCR_JUMP ^ IFFALSE (WHEN (SCR_MSG_IN)),
+		PADDRH (swide_scr_64_1),
+	SCR_FROM_REG (sbdl),
+		0,
+	SCR_JUMP ^ IFFALSE (DATA (M_IGN_RESIDUE)),
+		PADDRH (swide_scr_64_1),
+	SCR_REG_REG (rbc, SCR_ADD, 1),
+		0,
+	SCR_REG_REG (rbc1, SCR_ADDC, 0),
+		0,
+	SCR_REG_REG (rbc2, SCR_ADDC, 0),
+		0,
+	/*
+	**	Save UA and RBC, since the PM0/1_SAVE 
+	**	sub-scripts haven't moved them to the 
+	**	context yet and the below MOV may just 
+	**	change their value.
+	*/
+	SCR_STORE_ABS (ua, 4),
+		PADDRH (scratch),
+	SCR_STORE_ABS (rbc, 4),
+		PADDRH (scratch1),
+	/*
+	**	Throw away the IGNORE WIDE RESIDUE message.
+	**	since we just did take care of it.
+	*/
+	SCR_MOVE_ABS (2) ^ SCR_MSG_IN,
+		NADDR (scratch),
+	SCR_CLR (SCR_ACK),
+		0,
+	/*
+	**	Restore UA and RBC registers and return.
+	*/
+	SCR_LOAD_ABS (ua, 4),
+		PADDRH (scratch),
+	SCR_LOAD_ABS (rbc, 4),
+		PADDRH (scratch1),
+	SCR_RETURN,
+		0,
+}/*--------------------------< SWIDE_SCR_64_1 >---------------------*/,{
+	/*
+	**	We must grab the SWIDE and move it to 
+	**	memory.
+	**
+	**	- Save UA (32 bit address) in <scratch>.
+	**	- Move address bit 32..39 to SFBR.
+	**	- Increment UA (updated address).
+	*/
+	SCR_STORE_ABS (ua, 4),
+		PADDRH (scratch),
+	SCR_FROM_REG (rbc3),
+		0,
+	SCR_REG_REG (ua, SCR_ADD, 1),
+		0,
+	SCR_REG_REG (ua1, SCR_ADDC, 0),
+		0,
+	SCR_REG_REG (ua2, SCR_ADDC, 0),
+		0,
+	SCR_REG_REG (ua3, SCR_ADDC, 0),
+		0,
+}/*--------------------------< SWIDE_COM_64 >-----------------------*/,{
+	/*
+	**	- Save DRS.
+	**	- Load DRS with address bit 32..39 of the
+	**	  location to write the SWIDE.
+	**	  SFBR has been loaded with these bits.
+	**	  (Look above).
+	*/
+	SCR_STORE_ABS (drs, 4),
+		PADDRH (saved_drs),
+	SCR_LOAD_ABS (drs, 4),
+		PADDRH (zero),
+	SCR_TO_REG (drs),
+		0,
+}/*--------------------------< SWIDE_COMMON >-----------------------*/,{
+	/*
+	**	- Save current DSA
+	**	- Load DSA with bit 0..31 of the memory 
+	**	  location to write the SWIDE.
+	*/
+	SCR_STORE_ABS (dsa, 4),
+		PADDRH (saved_dsa),
+	SCR_LOAD_ABS (dsa, 4),
+		PADDRH (scratch),
+	/*
+	**	Move the SWIDE to memory.
+	**	Clear the WSR bit.
+	*/
+	SCR_STORE_REL (swide, 1),
+		0,
+	SCR_REG_REG (scntl2, SCR_OR, WSR),
+		0,
+	/*
+	**	Restore the original DSA.
+	*/
+	SCR_LOAD_ABS (dsa, 4),
+		PADDRH (saved_dsa),
+}/*--------------------------< SWIDE_FIN_32 >-----------------------*/,{
+	/*
+	**	For 32 bit chip, the following SCRIPTS 
+	**	instruction is patched with a JUMP to dispatcher.
+	**	(Look into the C code).
+	*/
+	SCR_LOAD_ABS (drs, 4),
+		PADDRH (saved_drs),
+	/*
+	**	64 bit chip only.
+	**	If PM handling from SCRIPTS, we are just 
+	**	a helper for the C code, so jump to 
+	**	dispatcher now.
+	*/
+	SCR_FROM_REG (ccntl0),
+		0,
+	SCR_JUMP ^ IFFALSE (MASK (ENPMJ, ENPMJ)),
+		PADDR (dispatch),
+	/*
+	**	64 bit chip with hardware PM handling enabled.
+	**
+	**	Since we are paranoid:), we donnot want 
+	**	a SWIDE followed by a CHMOV(1) to lead to 
+	**	a CHMOV(0) in our PM context.
+	**	We check against such a condition.
+	**	Also does the C code.
+	*/
+	SCR_FROM_REG (rbc),
+		0,
+	SCR_RETURN ^ IFFALSE (DATA (0)),
+		0,
+	SCR_FROM_REG (rbc1),
+		0,
+	SCR_RETURN ^ IFFALSE (DATA (0)),
+		0,
+	SCR_FROM_REG (rbc2),
+		0,
+	SCR_RETURN ^ IFFALSE (DATA (0)),
+		0,
+	/*
+	**	If we are there, RBC(0..23) is zero, 
+	**	and we just have to load the current 
+	**	DATA SCRIPTS address (register TEMP) 
+	**	with the IA and go to dispatch.
+	**	No PM context is needed.
+	*/
+	SCR_STORE_ABS (ia, 4),
+		PADDRH (scratch),
+	SCR_LOAD_ABS (temp, 4),
+		PADDRH (scratch),
+	SCR_JUMP,
+		PADDR (dispatch),
+
+}/*-------------------------< ZERO >------------------------*/,{
+	SCR_DATA_ZERO,
+}/*-------------------------< SCRATCH >---------------------*/,{
+	SCR_DATA_ZERO,
+}/*-------------------------< SCRATCH1 >--------------------*/,{
+	SCR_DATA_ZERO,
+}/*-------------------------< PM0_DATA_ADDR >---------------*/,{
+	SCR_DATA_ZERO,
+}/*-------------------------< PM1_DATA_ADDR >---------------*/,{
+	SCR_DATA_ZERO,
+}/*-------------------------< SAVED_DSA >-------------------*/,{
+	SCR_DATA_ZERO,
+}/*-------------------------< SAVED_DRS >-------------------*/,{
+	SCR_DATA_ZERO,
+}/*-------------------------< DONE_POS >--------------------*/,{
+	SCR_DATA_ZERO,
+}/*-------------------------< STARTPOS >--------------------*/,{
+	SCR_DATA_ZERO,
+}/*-------------------------< TARGTBL >---------------------*/,{
+	SCR_DATA_ZERO,
+
+
+/*
+** We may use MEMORY MOVE instructions to load the on chip-RAM,
+** if it happens that mapping PCI memory is not possible.
+** But writing the RAM from the CPU is the preferred method, 
+** since PCI 2.2 seems to disallow PCI self-mastering.
+*/
+
+#ifdef SCSI_NCR_PCI_MEM_NOT_SUPPORTED
+
+}/*-------------------------< START_RAM >-------------------*/,{
+	/*
+	**	Load the script into on-chip RAM, 
+	**	and jump to start point.
+	*/
+	SCR_COPY (sizeof (struct script)),
+}/*-------------------------< SCRIPT0_BA >--------------------*/,{
+		0,
+		PADDR (start),
+	SCR_JUMP,
+		PADDR (init),
+
+}/*-------------------------< START_RAM64 >--------------------*/,{
+	/*
+	**	Load the RAM and start for 64 bit PCI (895A,896).
+	**	Both scripts (script and scripth) are loaded into 
+	**	the RAM which is 8K (4K for 825A/875/895).
+	**	We also need to load some 32-63 bit segments 
+	**	address of the SCRIPTS processor.
+	**	LOAD/STORE ABSOLUTE always refers to on-chip RAM 
+	**	in our implementation. The main memory is 
+	**	accessed using LOAD/STORE DSA RELATIVE.
+	*/
 	SCR_LOAD_REL (mmws, 4),
 		offsetof (struct ncb, scr_ram_seg),
 	SCR_COPY (sizeof(struct script)),
@@ -3702,57 +4260,22 @@
 **==========================================================
 */
 
-__initfunc(
-void ncr_script_fill (struct script * scr, struct scripth * scrh)
-)
+void __init ncr_script_fill (struct script * scr, struct scripth * scrh)
 {
 	int	i;
 	ncrcmd	*p;
 
-#if	MAX_SCATTERH != 0
-	p = scrh->hdata_in;
-	for (i=0; i<MAX_SCATTERH; i++) {
-#if	SCR_SG_SIZE == 4
-		*p++ =SCR_CALL ^ IFFALSE (WHEN (SCR_DATA_IN));
-		*p++ =PADDR (databreak);
-#endif
-		*p++ =SCR_MOVE_TBL ^ SCR_DATA_IN;
-		*p++ =offsetof (struct dsb, data[i]);
-	};
-	assert ((u_long)p == (u_long)&scrh->hdata_in + sizeof (scrh->hdata_in));
-#endif
-
 	p = scr->data_in;
-	for (i=MAX_SCATTERH; i<MAX_SCATTERH+MAX_SCATTERL; i++) {
-#if	SCR_SG_SIZE == 4
-		*p++ =SCR_CALL ^ IFFALSE (WHEN (SCR_DATA_IN));
-		*p++ =PADDR (databreak);
-#endif
-		*p++ =SCR_MOVE_TBL ^ SCR_DATA_IN;
+	for (i=0; i<MAX_SCATTER; i++) {
+		*p++ =SCR_CHMOV_TBL ^ SCR_DATA_IN;
 		*p++ =offsetof (struct dsb, data[i]);
 	};
-	assert ((u_long)p == (u_long)&scr->data_in + sizeof (scr->data_in));
 
-#if	MAX_SCATTERH != 0
-	p = scrh->hdata_out;
-	for (i=0; i<MAX_SCATTERH; i++) {
-#if	SCR_SG_SIZE == 4
-		*p++ =SCR_CALL ^ IFFALSE (WHEN (SCR_DATA_OUT));
-		*p++ =PADDR (databreak);
-#endif
-		*p++ =SCR_MOVE_TBL ^ SCR_DATA_OUT;
-		*p++ =offsetof (struct dsb, data[i]);
-	};
-	assert ((u_long)p==(u_long)&scrh->hdata_out + sizeof (scrh->hdata_out));
-#endif
+	assert ((u_long)p == (u_long)&scr->data_in + sizeof (scr->data_in));
 
 	p = scr->data_out;
-	for (i=MAX_SCATTERH; i<MAX_SCATTERH+MAX_SCATTERL; i++) {
-#if SCR_SG_SIZE == 4
-		*p++ =SCR_CALL ^ IFFALSE (WHEN (SCR_DATA_OUT));
-		*p++ =PADDR (databreak);
-#endif
-		*p++ =SCR_MOVE_TBL ^ SCR_DATA_OUT;
+	for (i=0; i<MAX_SCATTER; i++) {
+		*p++ =SCR_CHMOV_TBL ^ SCR_DATA_OUT;
 		*p++ =offsetof (struct dsb, data[i]);
 	};
 
@@ -3768,9 +4291,8 @@
 **==========================================================
 */
 
-__initfunc(
-static void ncr_script_copy_and_bind (ncb_p np,ncrcmd *src,ncrcmd *dst,int len)
-)
+static void __init 
+ncr_script_copy_and_bind (ncb_p np,ncrcmd *src,ncrcmd *dst,int len)
 {
 	ncrcmd  opcode, new, old, tmp1, tmp2;
 	ncrcmd	*start, *end;
@@ -3860,11 +4382,22 @@
 
 		case 0x0:
 			/*
-			**	MOVE (absolute address)
+			**	MOVE/CHMOV (absolute address)
 			*/
+			if (!(np->features & FE_WIDE))
+				dst[-1] = cpu_to_scr(opcode | OPC_MOVE);
 			relocs = 1;
 			break;
 
+		case 0x1:
+			/*
+			**	MOVE/CHMOV (table indirect)
+			*/
+			if (!(np->features & FE_WIDE))
+				dst[-1] = cpu_to_scr(opcode | OPC_MOVE);
+			relocs = 0;
+			break;
+
 		case 0x8:
 			/*
 			**	JUMP / CALL
@@ -3912,6 +4445,7 @@
 				break;
 #ifdef	RELOC_KVAR
 			case RELOC_KVAR:
+				new=0;
 				if (((old & ~RELOC_MASK) < SCRIPT_KVAR_FIRST) ||
 				    ((old & ~RELOC_MASK) > SCRIPT_KVAR_LAST))
 					panic("ncr KVAR out of range");
@@ -3926,6 +4460,7 @@
 				}
 				/* fall through */
 			default:
+				new = 0;	/* For 'cc' not to complain */
 				panic("ncr_script_copy_and_bind: "
 				      "weird relocation %x\n", old);
 				break;
@@ -3993,9 +4528,16 @@
 **	Prepare io register values used by ncr_init() according 
 **	to selected and supported features.
 **
-**	NCR chips allow burst lengths of 2, 4, 8, 16, 32, 64, 128 
-**	transfers. 32,64,128 are only supported by 825A, 875, 895 
-**	and 896 chips.
+**	NCR/SYMBIOS chips allow burst lengths of 2, 4, 8, 16, 32, 64,
+**	128 transfers. All chips support at least 16 transfers bursts. 
+**	The 825A, 875 and 895 chips support bursts of up to 128 
+**	transfers and the 895A and 896 support bursts of up to 64 
+**	transfers. All other chips support up to 16 transfers bursts.
+**
+**	For PCI 32 bit data transfers each transfer is a DWORD (4 bytes).
+**	It is a QUADWORD (8 bytes) for PCI 64 bit data transfers.
+**	Only the 896 is able to perform 64 bit data transfers.
+**
 **	We use log base 2 (burst length) as internal code, with 
 **	value 0 meaning "burst disabled".
 **
@@ -4038,10 +4580,8 @@
 **	Get target set-up from Symbios format NVRAM.
 */
 
-__initfunc(
-static void
-	ncr_Symbios_setup_target(ncb_p np, int target, Symbios_nvram *nvram)
-)
+static void __init 
+ncr_Symbios_setup_target(ncb_p np, int target, Symbios_nvram *nvram)
 {
 	tcb_p tp = &np->target[target];
 	Symbios_target *tn = &nvram->target[target];
@@ -4049,7 +4589,7 @@
 	tp->usrsync = tn->sync_period ? (tn->sync_period + 3) / 4 : 255;
 	tp->usrwide = tn->bus_width == 0x10 ? 1 : 0;
 	tp->usrtags =
-		(tn->flags & SYMBIOS_QUEUE_TAGS_ENABLED)? SCSI_NCR_MAX_TAGS : 0;
+		(tn->flags & SYMBIOS_QUEUE_TAGS_ENABLED)? MAX_TAGS : 0;
 
 	if (!(tn->flags & SYMBIOS_DISCONNECT_ENABLE))
 		tp->usrflag |= UF_NODISC;
@@ -4061,10 +4601,8 @@
 **	Get target set-up from Tekram format NVRAM.
 */
 
-__initfunc(
-static void
-	ncr_Tekram_setup_target(ncb_p np, int target, Tekram_nvram *nvram)
-)
+static void __init
+ncr_Tekram_setup_target(ncb_p np, int target, Tekram_nvram *nvram)
 {
 	tcb_p tp = &np->target[target];
 	struct Tekram_target *tn = &nvram->target[target];
@@ -4090,9 +4628,7 @@
 }
 #endif /* SCSI_NCR_NVRAM_SUPPORT */
 
-__initfunc(
-static int ncr_prepare_setting(ncb_p np, ncr_nvram *nvram)
-)
+static int __init ncr_prepare_setting(ncb_p np, ncr_nvram *nvram)
 {
 	u_char	burst_max;
 	u_long	period;
@@ -4103,15 +4639,27 @@
 	*/
 
 	np->sv_scntl0	= INB(nc_scntl0) & 0x0a;
-	np->sv_scntl3	= INB(nc_scntl3) & 0x07;
 	np->sv_dmode	= INB(nc_dmode)  & 0xce;
 	np->sv_dcntl	= INB(nc_dcntl)  & 0xa8;
 	np->sv_ctest3	= INB(nc_ctest3) & 0x01;
 	np->sv_ctest4	= INB(nc_ctest4) & 0x80;
-	np->sv_ctest5	= INB(nc_ctest5) & 0x24;
 	np->sv_gpcntl	= INB(nc_gpcntl);
 	np->sv_stest2	= INB(nc_stest2) & 0x20;
 	np->sv_stest4	= INB(nc_stest4);
+	np->sv_scntl3   = INB(nc_scntl3) & 0x07;
+
+	if (np->device_id == PCI_DEVICE_ID_LSI_53C1010){
+		/*
+		** C1010 always uses large fifo, bit 5 rsvd
+		** scntl4 used ONLY with C1010
+		*/
+		np->sv_ctest5 = INB(nc_ctest5) & 0x04 ; 
+		np->sv_scntl4 = INB(nc_scntl4); 
+        }
+        else {
+		np->sv_ctest5 = INB(nc_ctest5) & 0x24 ; 
+		np->sv_scntl4 = 0;
+        }
 
 	/*
 	**	Wide ?
@@ -4139,16 +4687,30 @@
 
 	/*
 	 * Divisor to be used for async (timer pre-scaler).
+	 *
+	 * Note: For C1010 the async divisor is 2(8) if he
+	 * quadrupler is disabled (enabled).
 	 */
-	i = np->clock_divn - 1;
-	while (--i >= 0) {
-		if (10ul * SCSI_NCR_MIN_ASYNC * np->clock_khz > div_10M[i]) {
-			++i;
-			break;
+	if (np->device_id != PCI_DEVICE_ID_LSI_53C1010){
+		i = np->clock_divn - 1;
+		while (--i >= 0) {
+			if (10ul * SCSI_NCR_MIN_ASYNC * np->clock_khz 
+							> div_10M[i]) {
+				++i;
+				break;
+			}
 		}
+		np->rv_scntl3 = i+1;
 	}
-	np->rv_scntl3 = i+1;
+	else 
+		np->rv_scntl3 = 0; 
+
+	/*
+	 * Save the ultra3 register for the C1010
+	 */
 
+	np->rv_scntl4 = np->sv_scntl4;
+
 	/*
 	 * Minimum synchronous period factor supported by the chip.
 	 * Btw, 'period' is in tenths of nanoseconds.
@@ -4161,13 +4723,28 @@
 	else				np->minsync = (period + 40 - 1) / 40;
 
 	/*
+	 * Fix up. If sync. factor is 10 (160000Khz clock) and chip
+	 * supports ultra3, then min. sync. period 12.5ns and the factor is 9 
+	 */
+
+	if ((np->minsync == 10) && (np->features & FE_ULTRA3))
+		np->minsync = 9;
+
+	/*
 	 * Check against chip SCSI standard support (SCSI-2,ULTRA,ULTRA2).
+	 *
+	 * Transfer period minimums: SCSI-1 200 (50); Fast 100 (25)
+	 *			Ultra 50 (12); Ultra2 (6); Ultra3 (3)		
 	 */
 
-	if	(np->minsync < 25 && !(np->features & (FE_ULTRA|FE_ULTRA2)))
+	if	(np->minsync < 25 && !(np->features & (FE_ULTRA|FE_ULTRA2|FE_ULTRA3)))
 		np->minsync = 25;
-	else if	(np->minsync < 12 && !(np->features & FE_ULTRA2))
+	else if	(np->minsync < 12 && (np->features & FE_ULTRA))
 		np->minsync = 12;
+	else if	(np->minsync < 10 && (np->features & FE_ULTRA2))
+		np->minsync = 10;
+	else if	(np->minsync < 9 && (np->features & FE_ULTRA3))
+		np->minsync = 9;
 
 	/*
 	 * Maximum synchronous period factor supported by the chip.
@@ -4176,8 +4753,13 @@
 	period = (11 * div_10M[np->clock_divn - 1]) / (4 * np->clock_khz);
 	np->maxsync = period > 2540 ? 254 : period / 10;
 
+	if (DEBUG_FLAGS & DEBUG_NEGO) {
+		printk("%s: MIN sync=0x%2X  and MAX sync=0x%2X\n", 
+			ncr_name(np), np->minsync, np->maxsync);  
+	} 
+
 	/*
-	**	64 bit (53C896) ?
+	**	64 bit (53C895A or 53C896) ?
 	*/
 	if (np->features & FE_64BIT)
 #if BITS_PER_LONG > 32
@@ -4187,8 +4769,8 @@
 #endif
 
 	/*
-	**	Phase mismatch handled by SCRIPTS (53C896) ?
-	*/
+	**	Phase mismatch handled by SCRIPTS (53C895A, 53C896 or C1010) ?
+  	*/
 	if (np->features & FE_NOPM)
 		np->rv_ccntl0	|= (ENPMJ);
 
@@ -4231,6 +4813,13 @@
 		np->features &= ~(FE_WRIE|FE_ERL|FE_ERMP);
 
 	/*
+	**	DEL ? - 53C1010 Rev 1 - Part Number 609-0393638
+	**	64-bit Slave Cycles must be disabled.
+	*/
+	if ((np->device_id == PCI_DEVICE_ID_LSI_53C1010) && ( np->revision_id < 0x02) )
+		np->rv_ccntl1  |=  0x10;
+
+	/*
 	**	Select all supported special features.
 	**	If we are using on-board RAM for scripts, prefetch (PFEN) 
 	**	does not help, but burst op fetch (BOF) does.
@@ -4252,8 +4841,12 @@
 		np->rv_dcntl	|= CLSE;	/* Cache Line Size Enable */
 	if (np->features & FE_WRIE)
 		np->rv_ctest3	|= WRIE;	/* Write and Invalidate */
-	if (np->features & FE_DFS)
+
+
+	if ( (np->device_id != PCI_DEVICE_ID_LSI_53C1010) &&
+			(np->features & FE_DFS))
 		np->rv_ctest5	|= DFS;		/* Dma Fifo Size */
+						/* C1010 always large fifo */
 
 	/*
 	**	Select some other
@@ -4299,28 +4892,51 @@
 	ncr_init_burst(np, burst_max);
 
 	/*
-	**	Set differential mode and LED support.
-	**	Ignore these features for boards known to use a 
-	**	specific GPIO wiring (Tekram only for now) and 
-	**	for the 896 that drives the LED directly.
-	**	Probe initial setting of GPREG and GPCNTL for 
-	**	other ones.
-	*/
-	if (!nvram || nvram->type != SCSI_NCR_TEKRAM_NVRAM) {
+	**	Set SCSI BUS mode.
+	**
+	**	- ULTRA2 chips (895/895A/896) 
+	**	  and ULTRA 3 chips (1010) report the current 
+	**	  BUS mode through the STEST4 IO register.
+	**	- For previous generation chips (825/825A/875), 
+	**	  user has to tell us how to check against HVD, 
+	**	  since a 100% safe algorithm is not possible.
+	*/
+	np->scsi_mode = SMODE_SE;
+	if	(np->features & (FE_ULTRA2 | FE_ULTRA3))
+		np->scsi_mode = (np->sv_stest4 & SMODE);
+	else if	(np->features & FE_DIFF) {
 		switch(driver_setup.diff_support) {
-		case 3:
+		case 4:	/* Trust previous settings if present, then GPIO3 */
+			if (np->sv_scntl3) {
+				if (np->sv_stest2 & 0x20)
+					np->scsi_mode = SMODE_HVD;
+				break;
+			}
+		case 3:	/* SYMBIOS controllers report HVD through GPIO3 */
+			if (nvram && nvram->type != SCSI_NCR_SYMBIOS_NVRAM)
+				break;
 			if (INB(nc_gpreg) & 0x08)
-			break;
-		case 2:
-			np->rv_stest2	|= 0x20;
-			break;
-		case 1:
-			np->rv_stest2	|= (np->sv_stest2 & 0x20);
+				break;
+		case 2:	/* Set HVD unconditionally */
+			np->scsi_mode = SMODE_HVD;
+		case 1:	/* Trust previous settings for HVD */
+			if (np->sv_stest2 & 0x20)
+				np->scsi_mode = SMODE_HVD;
 			break;
-		default:
+		default:/* Don't care about HVD */	
 			break;
 		}
 	}
+	if (np->scsi_mode == SMODE_HVD)
+		np->rv_stest2 |= 0x20;
+
+	/*
+	**	Set LED support from SCRIPTS.
+	**	Ignore this feature for boards known to use a 
+	**	specific GPIO wiring and for the 895A or 896 
+	**	that drive the LED directly.
+	**	Also probe initial setting of GPIO0 as output.
+	*/
 	if ((driver_setup.led_pin ||
 	     (nvram && nvram->type == SCSI_NCR_SYMBIOS_NVRAM)) &&
 	    !(np->features & FE_LEDC) && !(np->sv_gpcntl & 0x01))
@@ -4373,7 +4989,7 @@
 #endif
 			tp->usrsync = driver_setup.default_sync;
 			tp->usrwide = driver_setup.max_wide;
-			tp->usrtags = SCSI_NCR_MAX_TAGS;
+			tp->usrtags = MAX_TAGS;
 			if (!driver_setup.disconnection)
 				np->target[i].usrflag = UF_NODISC;
 		}
@@ -4388,7 +5004,8 @@
 		i  == SCSI_NCR_SYMBIOS_NVRAM ? "Symbios format NVRAM, " :
 		(i == SCSI_NCR_TEKRAM_NVRAM  ? "Tekram format NVRAM, " : ""),
 		np->myaddr,
-		np->minsync < 12 ? 40 : (np->minsync < 25 ? 20 : 10),
+		np->minsync < 10 ? 80 : 
+			(np->minsync < 12 ? 40 : (np->minsync < 25 ? 20 : 10) ),
 		(np->rv_scntl0 & 0xa)	? ", Parity Checking"	: ", NO Parity",
 		(np->rv_stest2 & 0x20)	? ", Differential"	: "");
 
@@ -4414,9 +5031,7 @@
 
 #ifdef SCSI_NCR_DEBUG_NVRAM
 
-__initfunc(
-void ncr_display_Symbios_nvram(ncb_p np, Symbios_nvram *nvram)
-)
+void __init ncr_display_Symbios_nvram(ncb_p np, Symbios_nvram *nvram)
 {
 	int i;
 
@@ -4446,9 +5061,7 @@
 
 static u_char Tekram_boot_delay[7] __initdata = {3, 5, 10, 20, 30, 60, 120};
 
-__initfunc(
-void ncr_display_Tekram_nvram(ncb_p np, Tekram_nvram *nvram)
-)
+void __init ncr_display_Tekram_nvram(ncb_p np, Tekram_nvram *nvram)
 {
 	int i, tags, boot_delay;
 	char *rem;
@@ -4507,9 +5120,8 @@
 **	start the timer daemon.
 */
 
-__initfunc(
-static int ncr_attach (Scsi_Host_Template *tpnt, int unit, ncr_device *device)
-)
+static int __init 
+ncr_attach (Scsi_Host_Template *tpnt, int unit, ncr_device *device)
 {
         struct host_data *host_data;
 	ncb_p np = 0;
@@ -4553,8 +5165,6 @@
 	sprintf(np->inst_name, NAME53C "%s-%d", np->chip_name, np->unit);
 	np->device_id	= device->chip.device_id;
 	np->revision_id	= device->chip.revision_id;
-	np->pci_bus	= device->slot.bus;
-	np->pci_devfn	= device->slot.device_fn;
 	np->features	= device->chip.features;
 	np->clock_divn	= device->chip.nr_divisor;
 	np->maxoffs	= device->chip.offset_max;
@@ -4682,6 +5292,52 @@
 	(void) ncr_prepare_setting(np, nvram);
 
 	/*
+	**	Check the PCI clock frequency if needed.
+	**	
+	**	Must be done after ncr_prepare_setting since it destroys 
+	**	STEST1 that is used to probe for the clock multiplier.
+	**
+	**	The range is currently [22688 - 45375 Khz], given 
+	**	the values used by ncr_getclock().
+	**	This calibration of the frequecy measurement 
+	**	algorithm against the PCI clock frequency is only 
+	**	performed if the driver has had to measure the SCSI 
+	**	clock due to other heuristics not having been enough 
+	**	to deduce the SCSI clock frequency.
+	**
+	**	When the chip has been initialized correctly by the 
+	**	SCSI BIOS, the driver deduces the presence of the 
+	**	clock multiplier and the value of the SCSI clock from 
+	**	initial values of IO registers, and therefore no 
+	**	clock measurement is performed.
+	**	Normally the driver should never have to measure any 
+	**	clock, unless the controller may use a 80 MHz clock 
+	**	or has a clock multiplier and any of the following 
+	**	condition is met:
+	**
+	**	- No SCSI BIOS is present.
+	**	- SCSI BIOS did'nt enable the multiplier for some reason.
+	**	- User has disabled the controller from the SCSI BIOS.
+	**	- User booted the O/S from another O/S that did'nt enable 
+	**	  the multiplier for some reason.
+	**
+	**	As a result, the driver may only have to measure some 
+	**	frequency in very unusual situations.
+	**
+	**	For this reality test against the PCI clock to really 
+	**	protect against flaws in the udelay() calibration or 
+	**	driver problem that affect the clock measurement 
+	**	algorithm, the actual PCI clock frequency must be 33 MHz.
+	*/
+	i = np->pciclock_max ? ncr_getpciclock(np) : 0;
+	if (i && (i < np->pciclock_min  || i > np->pciclock_max)) {
+		printk(KERN_ERR "%s: PCI clock (%u KHz) is out of range "
+			"[%u KHz - %u KHz].\n",
+		       ncr_name(np), i, np->pciclock_min, np->pciclock_max);
+		goto attach_error;
+	}
+
+	/*
 	**	Patch script to physical addresses
 	*/
 	ncr_script_fill (&script0, &scripth0);
@@ -4715,6 +5371,14 @@
 	ncr_script_copy_and_bind (np, (ncrcmd *) &scripth0, (ncrcmd *) np->scripth0, sizeof(struct scripth));
 
 	/*
+	**	If not 64 bit chip, patch some places in SCRIPTS.
+	*/
+	if (!(np->features & FE_64BIT)) {
+		np->scripth0->swide_fin_32[0] = cpu_to_scr(SCR_JUMP);
+		np->scripth0->swide_fin_32[1] = 
+				cpu_to_scr(NCB_SCRIPT_PHYS(np, dispatch));
+	}
+	/*
 	**	Patch some variables in SCRIPTS
 	*/
 	np->scripth0->pm0_data_addr[0] = 
@@ -4722,6 +5386,14 @@
 	np->scripth0->pm1_data_addr[0] = 
 			cpu_to_scr(NCB_SCRIPT_PHYS(np, pm1_data));
 
+	/*
+	**	Patch if not Ultra 3 - Do not write to scntl4
+	*/
+	if (!(np->features & FE_ULTRA3)) {
+		np->script0->ultra3_bit[0] = cpu_to_scr(SCR_NO_OP);
+		np->script0->ultra3_bit[1] = cpu_to_scr(0);
+	}
+
 #ifdef SCSI_NCR_PCI_MEM_NOT_SUPPORTED
 	np->scripth0->script0_ba[0]	= cpu_to_scr(vtobus(np->script0));
 	np->scripth0->script0_ba64[0]	= cpu_to_scr(vtobus(np->script0));
@@ -4767,6 +5439,7 @@
 	for (i = 0 ; i < MAX_TARGET ; i++) {
 		np->targtbl[i] = cpu_to_scr(vtobus(&np->target[i]));
 		np->target[i].b_luntbl = cpu_to_scr(vtobus(np->badluntbl));
+		np->target[i].b_lun0   = cpu_to_scr(vtobus(&np->resel_badlun));
 	}
 
 	/*
@@ -4782,6 +5455,23 @@
 				cpu_to_scr(SCR_REG_REG(gpreg, SCR_AND, 0xfe));
 	}
 
+#ifdef SCSI_NCR_IARB_SUPPORT
+	/*
+	**    If user does not want to use IMMEDIATE ARBITRATION
+	**    when we are reselected while attempting to arbitrate,
+	**    patch the SCRIPTS accordingly with a SCRIPT NO_OP.
+	*/
+	if (!(driver_setup.iarb & 1))
+		np->script0->ungetjob[0] = cpu_to_scr(SCR_NO_OP);
+	/*
+	**    If user wants IARB to be set when we win arbitration 
+	**    and have other jobs, compute the max number of consecutive 
+	**    settings of IARB hint before we leave devices a chance to 
+	**    arbitrate for reselection.
+	*/
+	np->iarb_max = (driver_setup.iarb >> 4);
+#endif
+
 	/*
 	**	DEL 472 - 53C896 Rev 1 - Part Number 609-0393055 - ITEM 5.
 	*/
@@ -4810,6 +5500,9 @@
 	**	We should use ncr_soft_reset(), but we donnot want to do 
 	**	so, since we may not be safe if ABRT interrupt occurs due 
 	**	to the BIOS or previous O/S having enable this interrupt.
+	**
+	**	For C1010 need to set ABRT bit prior to SRST if SCRIPTs
+	**	are running. Not true in this case.
 	*/
 	OUTB (nc_istat, SRST);
 	UDELAY(10);
@@ -4826,14 +5519,20 @@
 
 	/*
 	**	Install the interrupt handler.
+	**	If we synchonize the C code with SCRIPTS on interrupt, 
+	**	we donnot want to share the INTR line at all.
 	*/
 	if (request_irq(device->slot.irq, sym53c8xx_intr,
+#ifdef SCSI_NCR_PCIQ_SYNC_ON_INTR
+			((driver_setup.irqm & 0x20) ? 0 : SA_INTERRUPT),
+#else
 			((driver_setup.irqm & 0x10) ? 0 : SA_SHIRQ) |
 #if LINUX_VERSION_CODE < LinuxVersionCode(2,2,0)
 			((driver_setup.irqm & 0x20) ? 0 : SA_INTERRUPT),
 #else
 			0,
 #endif
+#endif
 			NAME53C8XX, np)) {
 		printk(KERN_ERR "%s: request irq %d failure\n",
 			ncr_name(np), device->slot.irq);
@@ -4904,6 +5603,19 @@
 	instance->io_port	= np->base_io;
 	instance->n_io_port	= np->base_ws;
 	instance->dma_channel	= 0;
+	instance->cmd_per_lun	= MAX_TAGS;
+	instance->can_queue	= (MAX_START-4);
+
+	np->check_integrity       = 0;
+	instance->check_integrity = 0;
+
+#ifdef SCSI_NCR_ENABLE_INTEGRITY_CHECK
+	if ( !(driver_setup.bus_check & 0x04) ) {
+		np->check_integrity       = 1;
+		instance->check_integrity = 1;
+	}
+#endif
+	
 	instance->select_queue_depths = sym53c8xx_select_queue_depths;
 
 	NCR_UNLOCK_NCB(np, flags);
@@ -4969,7 +5681,9 @@
 			if (!lp)
 				continue;
 			if (lp->tasktbl != &lp->tasktbl_0)
-				m_free(lp->tasktbl, 256, "TASKTBL");
+				m_free(lp->tasktbl, MAX_TASKS*4, "TASKTBL");
+			if (lp->cb_tags)
+				m_free(lp->cb_tags, MAX_TAGS, "CB_TAGS");
 			m_free(lp, sizeof(*lp), "LCB");
 		}
 #if MAX_LUN > 1
@@ -5017,108 +5731,316 @@
 	}
 }
 
-
 /*==========================================================
 **
 **
-**	Start execution of a SCSI command.
-**	This is called from the generic SCSI driver.
+**	Prepare the next negotiation message for integrity check,
+**	if needed.
 **
+**	Fill in the part of message buffer that contains the 
+**	negotiation and the nego_status field of the CCB.
+**	Returns the size of the message in bytes.
 **
+**	If tp->ppr_negotiation is 1 and a M_REJECT occurs, then
+**	we disable ppr_negotiation.  If the first ppr_negotiation is
+**	successful, set this flag to 2.
+**
 **==========================================================
 */
-static int ncr_queue_command (ncb_p np, Scsi_Cmnd *cmd)
+
+static int ncr_ic_nego(ncb_p np, ccb_p cp, Scsi_Cmnd *cmd, u_char *msgptr)
 {
-/*	Scsi_Device        *device    = cmd->device; */
-	tcb_p tp                      = &np->target[cmd->target];
-	lcb_p lp		      = ncr_lp(np, tp, cmd->lun);
-	ccb_p cp;
+	tcb_p tp = &np->target[cp->target];
+	int msglen = 0;
+	int nego = 0;
+	u_char new_width, new_offset, new_period;
+	u_char no_increase;
+
+	if (tp->ppr_negotiation == 1)	/* PPR message successful */
+		tp->ppr_negotiation = 2;
+
+	if (tp->inq_done) {
+
+		if (!tp->ic_maximums_set) {
+			tp->ic_maximums_set = 1;
+
+			/* 
+			 * Check against target, host and user limits  
+			 */
+			if ( (tp->inq_byte7 & INQ7_WIDE16) && 
+					np->maxwide  && tp->usrwide) 
+				tp->ic_max_width = 1;
+			else
+				tp->ic_max_width = 0;
+			
 
-	int	segments;
-	u_char	nego, idmsg, *msgptr;
-	u_int  msglen;
-	int	direction;
-	u_int32	lastp, goalp;
+			if ((tp->inq_byte7 & INQ7_SYNC) && tp->maxoffs)
+				tp->ic_min_sync = (tp->minsync < np->minsync) ?
+							np->minsync : tp->minsync;
+			else 
+				tp->ic_min_sync = 255;
+			
+			tp->period   = 1;
+			tp->widedone = 1;
 
-	/*---------------------------------------------
-	**
-	**      Some shortcuts ...
-	**
-	**---------------------------------------------
-	*/
-	if ((cmd->target == np->myaddr	  ) ||
-		(cmd->target >= MAX_TARGET) ||
-		(cmd->lun    >= MAX_LUN   )) {
-		return(DID_BAD_TARGET);
-        }
+			/*
+			 * Enable PPR negotiation - only if Ultra3 support
+			 * is accessible.
+			 */
 
-	/*---------------------------------------------
-	**
-	**	Complete the 1st TEST UNIT READY command
-	**	with error condition if the device is 
-	**	flagged NOSCAN, in order to speed up 
-	**	the boot.
-	**
-	**---------------------------------------------
-	*/
-	if (cmd->cmnd[0] == 0 && (tp->usrflag & UF_NOSCAN)) {
-		tp->usrflag &= ~UF_NOSCAN;
-		return DID_BAD_TARGET;
-	}
+			if (tp->ic_max_width && (tp->ic_min_sync != 255 ))
+				tp->ppr_negotiation = 1;
+#if 0
+			tp->ppr_negotiation = 0;
+			if (np->features & FE_ULTRA3) {
+			    if (tp->ic_max_width && (tp->ic_min_sync == 0x09))
+				tp->ppr_negotiation = 1;
+			}
+#endif
+			if (!tp->ppr_negotiation)
+				cmd->ic_nego &= ~NS_PPR;
+		}
 
-	if (DEBUG_FLAGS & DEBUG_TINY) {
-		PRINT_ADDR(cmd);
-		printk ("CMD=%x ", cmd->cmnd[0]);
-	}
+		if (DEBUG_FLAGS & DEBUG_IC) {
+			printk("%s: cmd->ic_nego %d, 1st byte 0x%2X\n",
+				ncr_name(np), cmd->ic_nego, cmd->cmnd[0]);
+		}
+
+		/* Previous command recorded a parity or an initiator
+		 * detected error condition. Force bus to narrow for this
+		 * target. Clear flag. Negotation on request sense.
+		 * Note: kernel forces 2 bus resets :o( but clears itself out. 
+		 * Minor bug? in scsi_obsolete.c (ugly)
+		 */
+		if (np->check_integ_par) { 
+			printk("%s: Parity Error. Target set to narrow.\n",
+				ncr_name(np));
+			tp->ic_max_width = 0;
+			tp->widedone = tp->period = 0;
+		}
 
-	/*---------------------------------------------------
-	**
-	**	Assign a ccb / bind cmd.
-	**	If resetting, shorten settle_time if necessary
-	**	in order to avoid spurious timeouts.
-	**	If resetting or no free ccb,
-	**	insert cmd into the waiting list.
-	**
-	**----------------------------------------------------
-	*/
-	if (np->settle_time && cmd->timeout_per_command >= HZ &&
-		np->settle_time > jiffies + cmd->timeout_per_command - HZ) {
-		np->settle_time = jiffies + cmd->timeout_per_command - HZ;
-	}
+		/* Initializing:
+		 * If ic_nego == NS_PPR, we are in the initial test for
+		 * PPR messaging support. If driver flag is clear, then
+		 * either we don't support PPR nego (narrow or async device)
+		 * or this is the second TUR and we have had a M. REJECT 
+		 * or unexpected disconnect on the first PPR negotiation.  
+		 * Do not negotiate, reset nego flags (in case a reset has
+		 * occurred), clear ic_nego and return.
+		 * General case: Kernel will clear flag on a fallback. 
+		 * Do only SDTR or WDTR in the future.
+		 */
+                if (!tp->ppr_negotiation &&  (cmd->ic_nego == NS_PPR )) {
+			tp->ppr_negotiation = 0;
+			cmd->ic_nego &= ~NS_PPR;
+			tp->widedone = tp->period = 1;
+			return msglen;
+		}
+		else if (( tp->ppr_negotiation && !(cmd->ic_nego & NS_PPR )) || 
+                        (!tp->ppr_negotiation &&  (cmd->ic_nego & NS_PPR )) ) {
+			tp->ppr_negotiation = 0;
+			cmd->ic_nego &= ~NS_PPR;
+		}
+
+		/* In case of a bus reset, ncr_negotiate will reset 
+                 * the flags tp->widedone and tp->period to 0, forcing
+		 * a new negotiation.  Do WDTR then SDTR. If PPR, do both.
+		 * Do NOT increase the period.  It is possible for the Scsi_Cmnd
+		 * flags to be set to increase the period when a bus reset 
+		 * occurs - we don't want to change anything.
+		 */
+
+		no_increase = 0;
+
+		if (tp->ppr_negotiation && (!tp->widedone) && (!tp->period) ) {
+			cmd->ic_nego = NS_PPR;
+			tp->widedone = tp->period = 1;
+			no_increase = 1;
+		}
+		else if (!tp->widedone) {
+			cmd->ic_nego = NS_WIDE;
+			tp->widedone = 1;
+			no_increase = 1;
+		}
+		else if (!tp->period) {
+			cmd->ic_nego = NS_SYNC;
+			tp->period = 1;
+			no_increase = 1;
+		}
+
+		new_width = cmd->ic_nego_width & tp->ic_max_width;
+
+		switch (cmd->ic_nego_sync) {
+		case 2: /* increase the period */
+			if (!no_increase) {
+			    if (tp->ic_min_sync <= 0x09)      
+				tp->ic_min_sync = 0x0A;
+			    else if (tp->ic_min_sync <= 0x0A) 
+				tp->ic_min_sync = 0x0C;
+			    else if (tp->ic_min_sync <= 0x0C) 
+				tp->ic_min_sync = 0x19;
+			    else if (tp->ic_min_sync <= 0x19) 
+				tp->ic_min_sync *= 2;
+			    else  {
+				tp->ic_min_sync = 255;
+				cmd->ic_nego_sync = 0;
+				tp->maxoffs = 0;
+			    }
+			}
+			new_period  = tp->maxoffs?tp->ic_min_sync:0;
+			new_offset  = tp->maxoffs;
+			break;
 
-        if (np->settle_time || !(cp=ncr_get_ccb (np, cmd->target, cmd->lun))) {
-		insert_into_waiting_list(np, cmd);
-		return(DID_OK);
-	}
-	cp->cmd = cmd;
+		case 1: /* nego. to maximum */
+			new_period  = tp->maxoffs?tp->ic_min_sync:0;
+			new_offset  = tp->maxoffs;
+			break;
 
-	/*---------------------------------------------------
-	**
-	**	Enable tagged queue if asked by scsi ioctl
-	**
-	**----------------------------------------------------
-	*/
-#if 0	/* This stuff was only usefull for linux-1.2.13 */
-	if (lp && !lp->numtags && cmd->device && cmd->device->tagged_queue) {
-		lp->numtags = tp->usrtags;
-		ncr_setup_tags (np, cp->target, cp->lun);
-	}
-#endif
+		case 0:	/* nego to async */
+		default:
+			new_period = 0;
+			new_offset = 0;
+			break;
+		};
+		
 
-#ifdef SCSI_NCR_PROFILE_SUPPORT
-	cp->phys.num_disc = 0;
-#endif
+		nego = NS_NOCHANGE;
+		if (tp->ppr_negotiation) { 
+			u_char options_byte = 0;
 
-	/*---------------------------------------------------
-	**
-	**	negotiation required?
-	**
-	**---------------------------------------------------
-	*/
+			/*
+			** Must make sure data is consistent.
+			** If period is 9 and sync, must be wide and DT bit set.
+			** else period must be larger. If the width is 0, 
+			** reset bus to wide but increase the period to 0x0A.
+			** Note: The strange else clause is due to the integrity check.
+			** If fails at 0x09, wide, the I.C. code will redo at the same
+			** speed but a narrow bus. The driver must take care of slowing
+			** the bus speed down.
+			**
+			** The maximum offset in ST mode is 31, in DT mode 62 (1010 only)
+			*/
+			if ( (new_period==0x09) && new_offset) {
+				if (new_width) 
+					options_byte = 0x02;
+				else {
+					tp->ic_min_sync = 0x0A;
+					new_period = 0x0A;
+					cmd->ic_nego_width = 1;
+					new_width = 1;
+					new_offset &= 0x1f;
+				}
+			}
+			else if (new_period > 0x09)
+				new_offset &= 0x1f;
+
+			nego = NS_PPR;
+			
+			msgptr[msglen++] = M_EXTENDED;
+			msgptr[msglen++] = 6;
+			msgptr[msglen++] = M_X_PPR_REQ;
+			msgptr[msglen++] = new_period;
+			msgptr[msglen++] = 0;
+			msgptr[msglen++] = new_offset;
+			msgptr[msglen++] = new_width;
+			msgptr[msglen++] = options_byte;
+
+		}
+		else {
+			switch (cmd->ic_nego & ~NS_PPR) {
+			case NS_WIDE:
+			    /*
+			    **	WDTR negotiation on if device supports
+			    **  wide or if wide device forced narrow
+			    **	due to a parity error. 
+			    */
+
+			    cmd->ic_nego_width &= tp->ic_max_width;
+
+			    if (tp->ic_max_width | np->check_integ_par) {
+				nego = NS_WIDE;
+				msgptr[msglen++] = M_EXTENDED;
+				msgptr[msglen++] = 2;
+				msgptr[msglen++] = M_X_WIDE_REQ;
+				msgptr[msglen++] = new_width;
+			    }
+		 	    break;
+
+			case NS_SYNC:
+			    /*
+			    **	negotiate synchronous transfers
+			    **	Target must support sync transfers.
+			    **  Min. period = 0x0A, maximum offset of 31=0x1f.
+		    	    */
+
+			    if (tp->inq_byte7 & INQ7_SYNC) {
+
+				if (new_offset && (new_period < 0x0A)) {
+					tp->ic_min_sync = 0x0A;
+					new_period = 0x0A;
+				}
+				nego = NS_SYNC;
+				msgptr[msglen++] = M_EXTENDED;
+				msgptr[msglen++] = 3;
+				msgptr[msglen++] = M_X_SYNC_REQ;
+				msgptr[msglen++] = new_period;
+				msgptr[msglen++] = new_offset & 0x1f;
+			    }
+			    else 
+				cmd->ic_nego_sync = 0;
+			    break;
+
+			case NS_NOCHANGE:
+			    break;
+			}
+		}
+
+	};
+
+	cp->nego_status = nego;
+	np->check_integ_par = 0;
+
+	if (nego) {
+		tp->nego_cp = cp;
+		if (DEBUG_FLAGS & DEBUG_NEGO) {
+			ncr_print_msg(cp, nego == NS_WIDE ?
+				  "wide/narrow msgout":
+				(nego == NS_SYNC ? "sync/async msgout" : "ppr msgout"), 
+				msgptr);
+		};
+	};
+
+	return msglen;
+}
+
+/*==========================================================
+**
+**
+**	Prepare the next negotiation message if needed.
+**
+**	Fill in the part of message buffer that contains the 
+**	negotiation and the nego_status field of the CCB.
+**	Returns the size of the message in bytes.
+**
+**
+**==========================================================
+*/
+
+
+static int ncr_prepare_nego(ncb_p np, ccb_p cp, u_char *msgptr)
+{
+	tcb_p tp = &np->target[cp->target];
+	int msglen = 0;
+	int nego = 0;
+	u_char width, offset, factor, last_byte;
 
-	nego = 0;
 
-	if ((!tp->widedone || !tp->period) && !tp->nego_cp && tp->inq_done && lp) {
+	if (tp->inq_done) {
+		/*
+		 * Get the current width, offset and period
+		 */
+		ncr_get_xfer_info( np, tp, &factor,
+						&offset, &width);
 
 		/*
 		**	negotiate wide transfers ?
@@ -5126,35 +6048,209 @@
 
 		if (!tp->widedone) {
 			if (tp->inq_byte7 & INQ7_WIDE16) {
-				nego = NS_WIDE;
+				if (tp->ppr_negotiation)
+					nego = NS_PPR;
+				else
+					nego = NS_WIDE;
+
+				width = tp->usrwide;
+				if (tp->ic_done)
+		       			 width &= tp->ic_max_width;
 			} else
 				tp->widedone=1;
+
 		};
 
 		/*
 		**	negotiate synchronous transfers?
 		*/
 
-		if (!nego && !tp->period) {
+		if ((nego != NS_WIDE) && !tp->period) {
 			if (tp->inq_byte7 & INQ7_SYNC) {
-				nego = NS_SYNC;
+				if (tp->ppr_negotiation)
+					nego = NS_PPR;
+				else
+					nego = NS_SYNC;
+				
+				/* Check for async flag */
+				if (tp->maxoffs == 0) {
+				    offset = 0;
+				    factor = 0;
+				}
+				else {
+				    offset = tp->maxoffs;
+				    factor = tp->minsync;
+			 	    if ((tp->ic_done) && 
+						(factor < tp->ic_min_sync))
+		       			 factor = tp->ic_min_sync;
+				}
+
 			} else {
+				offset = 0;
+				factor = 0;
 				tp->period  =0xffff;
 				PRINT_TARGET(np, cp->target);
 				printk ("target did not report SYNC.\n");
 			};
 		};
+	};
 
+	switch (nego) {
+	case NS_PPR:
+		/*
+		** Must make sure data is consistent.
+		** If period is 9 and sync, must be wide and DT bit set
+		** else period must be larger. 
+		** Maximum offset is 31=0x1f if ST mode, 62 if DT mode
+		*/
+		last_byte = 0;
+		if ( (factor==9) && offset) {
+			if (!width) {
+				factor = 0x0A;
+				offset &= 0x1f;
+			}
+			else 
+				last_byte = 0x02;
+		}
+		msgptr[msglen++] = M_EXTENDED;
+		msgptr[msglen++] = 6;
+		msgptr[msglen++] = M_X_PPR_REQ;
+		msgptr[msglen++] = factor;
+		msgptr[msglen++] = 0;
+		msgptr[msglen++] = offset;
+		msgptr[msglen++] = width;
+		msgptr[msglen++] = last_byte;
+		break;
+	case NS_SYNC:
 		/*
-		**	remember nego is pending for the target.
-		**	Avoid to start a nego for all queued commands 
-		**	when tagged command queuing is enabled.
+		** Never negotiate faster than Ultra 2 (25ns periods)
 		*/
+		if (offset && (factor < 0x0A)) {
+			factor = 0x0A;
+			tp->minsync = 0x0A;
+		}
 
-		if (nego)
-			tp->nego_cp = cp;
+		msgptr[msglen++] = M_EXTENDED;
+		msgptr[msglen++] = 3;
+		msgptr[msglen++] = M_X_SYNC_REQ;
+		msgptr[msglen++] = factor;
+		msgptr[msglen++] = offset & 0x1f;
+		break;
+	case NS_WIDE:
+		msgptr[msglen++] = M_EXTENDED;
+		msgptr[msglen++] = 2;
+		msgptr[msglen++] = M_X_WIDE_REQ;
+		msgptr[msglen++] = width;
+		break;
+	};
+
+	cp->nego_status = nego;
+
+	if (nego) {
+		tp->nego_cp = cp;
+		if (DEBUG_FLAGS & DEBUG_NEGO) {
+			ncr_print_msg(cp, nego == NS_WIDE ?
+				  "wide msgout":
+				(nego == NS_SYNC ? "sync msgout" : "ppr msgout"), 
+				msgptr);
+		};
 	};
 
+	return msglen;
+}
+
+/*==========================================================
+**
+**
+**	Start execution of a SCSI command.
+**	This is called from the generic SCSI driver.
+**
+**
+**==========================================================
+*/
+static int ncr_queue_command (ncb_p np, Scsi_Cmnd *cmd)
+{
+/*	Scsi_Device        *device    = cmd->device; */
+	tcb_p tp                      = &np->target[cmd->target];
+	lcb_p lp		      = ncr_lp(np, tp, cmd->lun);
+	ccb_p cp;
+
+	int	segments;
+	u_char	idmsg, *msgptr;
+	u_int   msglen;
+	int	direction;
+	u_int32	lastp, goalp;
+
+	/*---------------------------------------------
+	**
+	**      Some shortcuts ...
+	**
+	**---------------------------------------------
+	*/
+	if ((cmd->target == np->myaddr	  ) ||
+		(cmd->target >= MAX_TARGET) ||
+		(cmd->lun    >= MAX_LUN   )) {
+		return(DID_BAD_TARGET);
+        }
+
+	/*---------------------------------------------
+	**
+	**	Complete the 1st TEST UNIT READY command
+	**	with error condition if the device is 
+	**	flagged NOSCAN, in order to speed up 
+	**	the boot.
+	**
+	**---------------------------------------------
+	*/
+	if (cmd->cmnd[0] == 0 && (tp->usrflag & UF_NOSCAN)) {
+		tp->usrflag &= ~UF_NOSCAN;
+		return DID_BAD_TARGET;
+	}
+
+	if (DEBUG_FLAGS & DEBUG_TINY) {
+		PRINT_ADDR(cmd);
+		printk ("CMD=%x ", cmd->cmnd[0]);
+	}
+
+	/*---------------------------------------------------
+	**
+	**	Assign a ccb / bind cmd.
+	**	If resetting, shorten settle_time if necessary
+	**	in order to avoid spurious timeouts.
+	**	If resetting or no free ccb,
+	**	insert cmd into the waiting list.
+	**
+	**----------------------------------------------------
+	*/
+	if (np->settle_time && cmd->timeout_per_command >= HZ) {
+		u_long tlimit = ktime_get(cmd->timeout_per_command - HZ);
+		if (ktime_dif(np->settle_time, tlimit) > 0)
+			np->settle_time = tlimit;
+	}
+
+        if (np->settle_time || !(cp=ncr_get_ccb (np, cmd->target, cmd->lun))) {
+		insert_into_waiting_list(np, cmd);
+		return(DID_OK);
+	}
+	cp->cmd = cmd;
+
+	/*---------------------------------------------------
+	**
+	**	Enable tagged queue if asked by scsi ioctl
+	**
+	**----------------------------------------------------
+	*/
+#if 0	/* This stuff was only usefull for linux-1.2.13 */
+	if (lp && !lp->numtags && cmd->device && cmd->device->tagged_queue) {
+		lp->numtags = tp->usrtags;
+		ncr_setup_tags (np, cp->target, cp->lun);
+	}
+#endif
+
+#ifdef SCSI_NCR_PROFILE_SUPPORT
+	cp->phys.num_disc = 0;
+#endif
+
 	/*----------------------------------------------------
 	**
 	**	Build the identify / tag / sdtr message
@@ -5178,16 +6274,16 @@
 		**	Force ordered tag if necessary to avoid timeouts 
 		**	and to preserve interactivity.
 		*/
-		if (lp && lp->tags_stime + (3*HZ) <= jiffies) {
-			if (lp->tags_smap) {
+		if (lp && ktime_exp(lp->tags_stime)) {
+			lp->tags_si = !(lp->tags_si);
+			if (lp->tags_sum[lp->tags_si]) {
 				order = M_ORDERED_TAG;
-				if ((DEBUG_FLAGS & DEBUG_TAGS)||bootverbose>2){ 
+				if ((DEBUG_FLAGS & DEBUG_TAGS)||bootverbose>0){ 
 					PRINT_ADDR(cmd);
 					printk("ordered tag forced.\n");
 				}
 			}
-			lp->tags_stime = jiffies;
-			lp->tags_smap = lp->tags_umap;
+			lp->tags_stime = ktime_get(3*HZ);
 		}
 
 		if (order == 0) {
@@ -5206,41 +6302,19 @@
 		}
 		msgptr[msglen++] = order;
 		/*
-		**	Actual tags are numbered 1,3,5,..2*MAXTAGS+1,
-		**	since we may have to deal with devices that have 
-		**	problems with #TAG 0 or too great #TAG numbers.
+		**	For less than 128 tags, actual tags are numbered 
+		**	1,3,5,..2*MAXTAGS+1,since we may have to deal 
+		**	with devices that have problems with #TAG 0 or too 
+		**	great #TAG numbers. For more tags (up to 256), 
+		**	we use directly our tag number.
 		*/
+#if MAX_TASKS > (512/4)
+		msgptr[msglen++] = cp->tag;
+#else
 		msgptr[msglen++] = (cp->tag << 1) + 1;
+#endif
 	}
 
-	switch (nego) {
-	case NS_SYNC:
-		msgptr[msglen++] = M_EXTENDED;
-		msgptr[msglen++] = 3;
-		msgptr[msglen++] = M_X_SYNC_REQ;
-		msgptr[msglen++] = tp->maxoffs ? tp->minsync : 0;
-		msgptr[msglen++] = tp->maxoffs;
-		if (DEBUG_FLAGS & DEBUG_NEGO) {
-			PRINT_ADDR(cp->cmd);
-			printk ("sync msgout: ");
-			ncr_show_msg (&cp->scsi_smsg [msglen-5]);
-			printk (".\n");
-		};
-		break;
-	case NS_WIDE:
-		msgptr[msglen++] = M_EXTENDED;
-		msgptr[msglen++] = 2;
-		msgptr[msglen++] = M_X_WIDE_REQ;
-		msgptr[msglen++] = tp->usrwide;
-		if (DEBUG_FLAGS & DEBUG_NEGO) {
-			PRINT_ADDR(cp->cmd);
-			printk ("wide msgout: ");
-			ncr_show_msg (&cp->scsi_smsg [msglen-4]);
-			printk (".\n");
-		};
-		break;
-	};
-
 	cp->host_flags	= 0;
 
 	/*----------------------------------------------------
@@ -5250,13 +6324,74 @@
 	**----------------------------------------------------
 	*/
 
-	segments = np->scatter (cp, cp->cmd);
+	cp->segments = segments = np->scatter (cp, cp->cmd);
 
 	if (segments < 0) {
 		ncr_free_ccb(np, cp);
 		return(DID_ERROR);
 	}
 
+	/*---------------------------------------------------
+	**
+	**	negotiation required?
+	**
+	**	(nego_status is filled by ncr_prepare_nego())
+	**
+	**---------------------------------------------------
+	*/
+
+	cp->nego_status = 0;
+
+	if ((np->check_integrity && tp->ic_done) || !np->check_integrity) {
+		 if ((!tp->widedone || !tp->period) && !tp->nego_cp && lp) {
+			msglen += ncr_prepare_nego (np, cp, msgptr + msglen);
+		 }
+	}
+	else if (np->check_integrity && (cmd->ic_in_progress)) { 
+		msglen += ncr_ic_nego (np, cp, cmd, msgptr + msglen);
+        }
+	else if (np->check_integrity && cmd->ic_complete) {
+		u_long current_period;
+		u_char current_offset, current_width, current_factor;
+
+		ncr_get_xfer_info (np, tp, &current_factor,
+					&current_offset, &current_width);
+
+		tp->ic_max_width = current_width;
+		tp->ic_min_sync  = current_factor;
+
+		if      (current_factor == 9) 	current_period = 125;
+		else if (current_factor == 10) 	current_period = 250;
+		else if (current_factor == 11) 	current_period = 303;
+		else if (current_factor == 12) 	current_period = 500;
+		else  			current_period = current_factor * 40;
+
+		/*
+                 * Negotiation for this target is complete. Update flags.
+                 */
+		tp->period = current_period;
+		tp->widedone = 1;
+		tp->ic_done = 1;
+
+		printk("%s: Integrity Check Complete: \n", ncr_name(np)); 
+
+		printk("%s: %s %s SCSI", ncr_name(np), 
+				current_offset?"SYNC":"ASYNC",
+				tp->ic_max_width?"WIDE":"NARROW");
+		if (current_offset) {
+			u_long mbs = 10000 * (tp->ic_max_width + 1); 
+
+			printk(" %d.%d  MB/s", 
+				(int) (mbs / current_period), (int) (mbs % current_period));
+
+			printk(" (%d ns, %d offset)\n", 
+				  (int) current_period/10, current_offset);
+		}
+		else 
+			printk(" %d MB/s. \n ", (tp->ic_max_width+1)*5);
+        }
+
+
 	/*----------------------------------------------------
 	**
 	**	Determine xfer direction.
@@ -5270,11 +6405,13 @@
 		case 0x08:  /*	READ(6)				08 */
 		case 0x28:  /*	READ(10)			28 */
 		case 0xA8:  /*	READ(12)			A8 */
+		case 0x3C:  /*	READ BUFFER (10)		3C */
 			direction = XFER_IN;
 			break;
 		case 0x0A:  /*	WRITE(6)			0A */
 		case 0x2A:  /*	WRITE(10)			2A */
 		case 0xAA:  /*	WRITE(12)			AA */
+		case 0x3B:  /*	WRITE BUFFER (10)		3B */
 			direction = XFER_OUT;
 			break;
 		default:
@@ -5299,17 +6436,10 @@
 	**	Compute data out pointers, if needed.
 	*/
 	if (direction & XFER_OUT) {
+
 		goalp = NCB_SCRIPT_PHYS (np, data_out2) + 8;
-#if	MAX_SCATTERH != 0
-		if (segments <= MAX_SCATTERL)
-			lastp = goalp - 8 - (segments * (SCR_SG_SIZE*4));
-		else {
-			lastp = NCB_SCRIPTH_PHYS (np, hdata_out2);
-			lastp -= (segments - MAX_SCATTERL) * (SCR_SG_SIZE*4);
-		}
-#else
 		lastp = goalp - 8 - (segments * (SCR_SG_SIZE*4));
-#endif
+
 		/*
 		**	If actual data direction is unknown, save pointers 
 		**	in header. The SCRIPTS will swap them to current 
@@ -5325,17 +6455,9 @@
 	**	Compute data in pointers, if needed.
 	*/
 	if (direction & XFER_IN) {
+
 		goalp = NCB_SCRIPT_PHYS (np, data_in2) + 8;
-#if	MAX_SCATTERH != 0
-		if (segments <= MAX_SCATTERL)
-			lastp = goalp - 8 - (segments * (SCR_SG_SIZE*4));
-		else {
-			lastp = NCB_SCRIPTH_PHYS (np, hdata_in2);
-			lastp -= (segments - MAX_SCATTERL) * (SCR_SG_SIZE*4);
-		}
-#else
 		lastp = goalp - 8 - (segments * (SCR_SG_SIZE*4));
-#endif
 	}
 
 	/*
@@ -5354,8 +6476,13 @@
 	/*
 	**	Save the initial data pointer in order to be able 
 	**	to redo the command.
+	**	We also have to save the initial lastp, since it 
+	**	will be changed to DATA_IO if we don't know the data 
+	**	direction and the device completes the command with 
+	**	QUEUE FULL status (without entering the data phase).
 	*/
 	cp->startp = cp->phys.header.savep;
+	cp->lastp0 = cp->phys.header.lastp;
 
 	/*----------------------------------------------------
 	**
@@ -5379,27 +6506,34 @@
 	cp->phys.select.sel_id		= cp->target;
 	cp->phys.select.sel_scntl3	= tp->wval;
 	cp->phys.select.sel_sxfer	= tp->sval;
+	cp->phys.select.sel_scntl4	= tp->uval;
 	/*
 	**	message
 	*/
-	cp->phys.smsg.addr		= cpu_to_scr(CCB_PHYS (cp, scsi_smsg));
-	cp->phys.smsg.size		= cpu_to_scr(msglen);
+	cp->phys.smsg.addr	= cpu_to_scr(CCB_PHYS (cp, scsi_smsg));
+	cp->phys.smsg.size	= cpu_to_scr(msglen);
 
 	/*
 	**	command
 	*/
-	cp->phys.cmd.addr		= cpu_to_scr(vtobus (&cmd->cmnd[0]));
-	cp->phys.cmd.size		= cpu_to_scr(cmd->cmd_len);
+	cp->phys.cmd.addr	= cpu_to_scr(vtobus (&cmd->cmnd[0]));
+	cp->phys.cmd.size	= cpu_to_scr(cmd->cmd_len);
 
 	/*
 	**	status
 	*/
-	cp->actualquirks		= tp->quirks;
-	cp->host_status			= nego ? HS_NEGOTIATE : HS_BUSY;
-	cp->scsi_status			= S_ILLEGAL;
+	cp->actualquirks	= tp->quirks;
+	cp->host_status		= cp->nego_status ? HS_NEGOTIATE : HS_BUSY;
+	cp->scsi_status		= S_ILLEGAL;
+	cp->xerr_status		= 0;
+	cp->phys.extra_bytes	= 0;
 
-	cp->xerr_status			= XE_OK;
-	cp->nego_status			= nego;
+	/*
+	**	extreme data pointer.
+	**	shall be positive, so -1 is lower than lowest.:)
+	*/
+	cp->ext_sg  = -1;
+	cp->ext_ofs = 0;
 
 	/*----------------------------------------------------
 	**
@@ -5412,17 +6546,10 @@
 	**	activate this job.
 	*/
 
-	/* Compute a time limit greater than the middle-level driver one */
-	if (cmd->timeout_per_command > 0)
-		cp->tlimit	= jiffies + cmd->timeout_per_command + HZ;
-	else
-		cp->tlimit	= jiffies + 86400 * HZ;/* No timeout=24 hours */
-
 	/*
 	**	insert next CCBs into start queue.
 	**	2 max at a time is enough to flush the CCB wait queue.
 	*/
-	cp->auto_sense = 0;
 	if (lp)
 		ncr_start_next_ccb(np, lp, 2);
 	else
@@ -5468,6 +6595,24 @@
 {
 	u_short	qidx;
 
+#ifdef SCSI_NCR_IARB_SUPPORT
+	/*
+	**	If the previously queued CCB is not yet done, 
+	**	set the IARB hint. The SCRIPTS will go with IARB 
+	**	for this job when starting the previous one.
+	**	We leave devices a chance to win arbitration by 
+	**	not using more than 'iarb_max' consecutive 
+	**	immediate arbitrations.
+	*/
+	if (np->last_cp && np->iarb_count < np->iarb_max) {
+		np->last_cp->host_flags |= HF_HINT_IARB;
+		++np->iarb_count;
+	}
+	else
+		np->iarb_count = 0;
+	np->last_cp = cp;
+#endif
+	
 	/*
 	**	insert into start queue.
 	*/
@@ -5489,7 +6634,7 @@
 	**	Wake it up.
 	*/
 	MEMORY_BARRIER();
-	OUTB (nc_istat, SIGP);
+	OUTB (nc_istat, SIGP|np->istat_sem);
 }
 
 
@@ -5536,7 +6681,6 @@
 **
 **
 **	Start reset process.
-**	If reset in progress do nothing.
 **	The interrupt handler will reinitialize the chip.
 **	The timeout handler will wait for settle_time before 
 **	clearing it and so resuming command processing.
@@ -5546,17 +6690,15 @@
 */
 static void ncr_start_reset(ncb_p np)
 {
-	if (!np->settle_time) {
-		(void) ncr_reset_scsi_bus(np, 1, driver_setup.settle_delay);
- 	}
- }
+	(void) ncr_reset_scsi_bus(np, 1, driver_setup.settle_delay);
+}
  
 static int ncr_reset_scsi_bus(ncb_p np, int enab_int, int settle_delay)
 {
 	u_int32 term;
 	int retv = 0;
 
-	np->settle_time	= jiffies + settle_delay * HZ;
+	np->settle_time	= ktime_get(settle_delay * HZ);
 
 	if (bootverbose > 1)
 		printk("%s: resetting, "
@@ -5690,8 +6832,6 @@
 {
 /*	Scsi_Device        *device    = cmd->device; */
 	ccb_p cp;
-	int found;
-	int retv;
 
 /*
  * First, look for the scsi command in the waiting list
@@ -5705,58 +6845,41 @@
 /*
  * Then, look in the wakeup list
  */
-	for (found=0, cp=np->ccbc; cp; cp=cp->link_ccb) {
+	for (cp=np->ccbc; cp; cp=cp->link_ccb) {
 		/*
 		**	look for the ccb of this command.
 		*/
 		if (cp->host_status == HS_IDLE) continue;
-		if (cp->cmd == cmd) {
-			found = 1;
+		if (cp->cmd == cmd)
 			break;
-		}
 	}
 
-	if (!found) {
+	if (!cp) {
 		return SCSI_ABORT_NOT_RUNNING;
 	}
 
-	if (np->settle_time) {
-		return SCSI_ABORT_SNOOZE;
-	}
-
 	/*
-	**	If the CCB is active, patch schedule jumps for the 
-	**	script to abort the command.
+	**	Keep track we have to abort this job.
 	*/
-
-	cp->tlimit = 0;
-	switch(cp->host_status) {
-	case HS_BUSY:
-	case HS_NEGOTIATE:
-		printk ("%s: abort ccb=%p (cancel)\n", ncr_name (np), cp);
-			cp->phys.header.go.start =
-				cpu_to_scr(NCB_SCRIPTH_PHYS (np, cancel));
-		retv = SCSI_ABORT_PENDING;
-		break;
-	case HS_DISCONNECT:
-		cp->phys.header.go.restart =
-				cpu_to_scr(NCB_SCRIPTH_PHYS (np, bad_i_t_l_q));
-		retv = SCSI_ABORT_PENDING;
-		break;
-	default:
-		retv = SCSI_ABORT_NOT_RUNNING;
-		break;
+	cp->to_abort = 1;
 
-	}
+	/*
+	**	Tell the SCRIPTS processor to stop 
+	**	and synchronize with us.
+	*/
+	np->istat_sem = SEM;
 
 	/*
 	**      If there are no requests, the script
 	**      processor will sleep on SEL_WAIT_RESEL.
 	**      Let's wake it up, since it may have to work.
 	*/
-	OUTB (nc_istat, SIGP);
+	OUTB (nc_istat, SIGP|SEM);
 
-	return retv;
+	/*
+	**	Tell user we are working for him.
+	*/
+	return SCSI_ABORT_PENDING;
 }
 
 /*==========================================================
@@ -5871,41 +6994,47 @@
 	if (cp == tp->nego_cp)
 		tp->nego_cp = 0;
 
+#ifdef SCSI_NCR_IARB_SUPPORT
 	/*
-	**	If auto-sense performed, change scsi status.
+	**	We just complete the last queued CCB.
+	**	Clear this info that is no more relevant.
 	*/
-	if (cp->auto_sense) {
-		cp->scsi_status = cp->auto_sense;
-	}
+	if (cp == np->last_cp)
+		np->last_cp = 0;
+#endif
 
 	/*
-	**	Check for parity errors.
+	**	If auto-sense performed, change scsi status, 
+	**	Otherwise, compute the residual.
 	*/
-
-	if (cp->host_flags & HF_PAR_ERR) {
-		PRINT_ADDR(cmd);
-		printk ("unrecovered SCSI parity error.\n");
-		if (cp->host_status==HS_COMPLETE)
-			cp->host_status = HS_FAIL;
+	if (cp->host_flags & HF_AUTO_SENSE) {
+		cp->scsi_status = cp->sv_scsi_status;
+		cp->xerr_status = cp->sv_xerr_status;
 	}
+	else {
+		cp->resid = 0;
+		if (cp->phys.header.lastp != cp->phys.header.goalp)
+			cp->resid = ncr_compute_residual(np, cp);
+	}
 
 	/*
 	**	Check for extended errors.
 	*/
 
-	if (cp->xerr_status != XE_OK) {
-		PRINT_ADDR(cmd);
-		switch (cp->xerr_status) {
-		case XE_EXTRA_DATA:
+	if (cp->xerr_status) {
+		if (cp->xerr_status & XE_PARITY_ERR) {
+			PRINT_ADDR(cmd);
+			printk ("unrecovered SCSI parity error.\n");
+		}
+		if (cp->xerr_status & XE_EXTRA_DATA) {
+			PRINT_ADDR(cmd);
 			printk ("extraneous data discarded.\n");
-			break;
-		case XE_BAD_PHASE:
+		}
+		if (cp->xerr_status & XE_BAD_PHASE) {
+			PRINT_ADDR(cmd);
 			printk ("illegal scsi phase (4/5).\n");
-			break;
-		default:
-			printk ("extended error %d.\n", cp->xerr_status);
-			break;
 		}
+
 		if (cp->host_status==HS_COMPLETE)
 			cp->host_status = HS_FAIL;
 	}
@@ -5914,10 +7043,13 @@
 	**	Print out any error for debugging purpose.
 	*/
 	if (DEBUG_FLAGS & (DEBUG_RESULT|DEBUG_TINY)) {
-		if (cp->host_status!=HS_COMPLETE || cp->scsi_status!=S_GOOD) {
+		if (cp->host_status!=HS_COMPLETE || cp->scsi_status!=S_GOOD ||
+		    cp->resid) {
 			PRINT_ADDR(cmd);
-			printk ("ERROR: cmd=%x host_status=%x scsi_status=%x\n",
-				cmd->cmnd[0], cp->host_status, cp->scsi_status);
+			printk ("ERROR: cmd=%x host_status=%x scsi_status=%x "
+				"data_len=%d residual=%d\n",
+				cmd->cmnd[0], cp->host_status, cp->scsi_status,
+				cp->data_len, -cp->resid);
 		}
 	}
 
@@ -5935,13 +7067,6 @@
 		SetScsiResult(cmd, DID_OK, cp->scsi_status);
 
 		/*
-		**	@RESID@
-		**	Could dig out the correct value for resid,
-		**	but it would be quite complicated.
-		*/
-		/* if (cp->phys.header.lastp != cp->phys.header.goalp) */
-
-		/*
 		**	Allocate the lcb if not yet.
 		*/
 		if (!lp)
@@ -5981,13 +7106,15 @@
 		SetScsiResult(cmd, DID_OK, S_CHECK_COND);
 
 		if (DEBUG_FLAGS & (DEBUG_RESULT|DEBUG_TINY)) {
-			u_char * p = (u_char*) & cmd->sense_buffer;
-			int i;
 			PRINT_ADDR(cmd);
-			printk ("sense data:");
-			for (i=0; i<14; i++) printk (" %x", *p++);
-			printk (".\n");
+			ncr_printl_hex("sense data:", cmd->sense_buffer, 14);
 		}
+	} else if ((cp->host_status == HS_COMPLETE)
+		&& (cp->scsi_status == S_CONFLICT)) {
+		/*
+		**   Reservation Conflict condition code
+		*/
+		SetScsiResult(cmd, DID_OK, S_CONFLICT);
 
 	} else if ((cp->host_status == HS_COMPLETE)
 		&& (cp->scsi_status == S_BUSY ||
@@ -6021,6 +7148,7 @@
 		SetScsiResult(cmd, DID_ABORT, cp->scsi_status);
 
 	} else {
+		int did_status;
 
 		/*
 		**  Other protocol messes
@@ -6028,8 +7156,12 @@
 		PRINT_ADDR(cmd);
 		printk ("COMMAND FAILED (%x %x) @%p.\n",
 			cp->host_status, cp->scsi_status, cp);
+
+		did_status = DID_ERROR;
+		if (cp->xerr_status & XE_PARITY_ERR)
+			did_status = DID_PARITY;
 
-		SetScsiResult(cmd, DID_ERROR, cp->scsi_status);
+		SetScsiResult(cmd, did_status, cp->scsi_status);
 	}
 
 	/*
@@ -6037,12 +7169,9 @@
 	*/
 
 	if (tp->usrflag & UF_TRACE) {
-		u_char * p;
-		int i;
 		PRINT_ADDR(cmd);
 		printk (" CMD:");
-		p = (u_char*) &cmd->cmnd[0];
-		for (i=0; i<cmd->cmd_len; i++) printk (" %x", *p++);
+		ncr_print_hex(cmd->cmnd, cmd->cmd_len);
 
 		if (cp->host_status==HS_COMPLETE) {
 			switch (cp->scsi_status) {
@@ -6051,9 +7180,7 @@
 				break;
 			case S_CHECK_COND:
 				printk ("  SENSE:");
-				p = (u_char*) &cmd->sense_buffer;
-				for (i=0; i<14; i++)
-					printk (" %x", *p++);
+				ncr_print_hex(cmd->sense_buffer, 14);
 				break;
 			default:
 				printk ("  STAT: %x\n", cp->scsi_status);
@@ -6239,7 +7366,10 @@
 	OUTB (nc_ctest3, np->rv_ctest3);	/* Write and invalidate */
 	OUTB (nc_ctest4, np->rv_ctest4);	/* Master parity checking */
 
-	OUTB (nc_stest2, EXT|np->rv_stest2); /* Extended Sreq/Sack filtering */
+	if (np->device_id != PCI_DEVICE_ID_LSI_53C1010){
+		OUTB (nc_stest2, EXT|np->rv_stest2); 
+		/* Extended Sreq/Sack filtering, not supported in C1010 */
+	}
 	OUTB (nc_stest3, TE);			/* TolerANT enable */
 	OUTB (nc_stime0, 0x0c);			/* HTH disabled  STO 0.25 sec */
 
@@ -6247,26 +7377,33 @@
 	**	DEL 441 - 53C876 Rev 5 - Part Number 609-0392787/2788 - ITEM 2.
 	**	Disable overlapped arbitration.
 	**	The 896 Rev 1 needs also this work-around to be applied.
+	**
+	**	Errata applies to all 896 and 1010 parts.
 	*/
 	if (np->device_id == PCI_DEVICE_ID_NCR_53C875 &&
 	    np->revision_id >= 0x10 && np->revision_id <= 0x15)
 		OUTB (nc_ctest0, (1<<5));
-	else if (np->device_id == PCI_DEVICE_ID_NCR_53C896 &&
-		 np->revision_id <= 0x1)
+	else if (np->device_id == PCI_DEVICE_ID_NCR_53C896  ||
+		 np->device_id == PCI_DEVICE_ID_LSI_53C1010 )
 		np->rv_ccntl0 |= DPR;
 
 	/*
-	**	If 64 bit (53C896) enable 40 bit address table 
+	**	If 64 bit (53C895A, 53C896 or 53C1010) enable 40 bit address table 
 	**	indirect addressing for MOVE.
+	**	Note: 64-bit slave addressessing must be disabled, even if
+	**	64 bit features have not been enabled.
 	*/
 
 	if (np->features & FE_64BIT) {
 		OUTB (nc_ccntl1, np->rv_ccntl1);
 	}
+	else if ((np->device_id == PCI_DEVICE_ID_LSI_53C1010) &&
+						(np->revision_id < 0x02)) 
+		OUTB (nc_ccntl1, np->rv_ccntl1);
 
 	/*
-	**	If phase mismatch handled by scripts (53C896),
-	**	set PM jump addresses.
+	**	If phase mismatch handled by scripts (53C895A or 53C896 
+	**	or 53C1010), set PM jump addresses. 
 	*/
 
 	if (np->features & FE_NOPM) {
@@ -6296,9 +7433,10 @@
 	OUTB (nc_dien , MDPE|BF|SSI|SIR|IID);
 
 	/*
-	**	For 895/6 enable SBMC interrupt and save current SCSI bus mode.
+	**	For 895/895A/896/c1010
+	**	Enable SBMC interrupt and save current SCSI bus mode.
 	*/
-	if (np->features & FE_ULTRA2) {
+	if ( (np->features & FE_ULTRA2) || (np->features & FE_ULTRA3) ) {
 		OUTONW (nc_sien, SBMC);
 		np->scsi_mode = INB (nc_stest4) & SMODE;
 	}
@@ -6313,8 +7451,11 @@
 	for (i=0;i<MAX_TARGET;i++) {
 		tcb_p tp = &np->target[i];
 
+		tp->to_reset = 0;
+
 		tp->sval    = 0;
 		tp->wval    = np->rv_scntl3;
+		tp->uval    = np->rv_scntl4;
 
 		if (tp->usrsync != 255) {
 			if (tp->usrsync <= np->maxsync) {
@@ -6366,6 +7507,8 @@
 	else
 		phys = NCB_SCRIPT_PHYS (np, init);
 
+	np->istat_sem = 0;
+
 	OUTL (nc_dsa, vtobus(np));
 	OUTL (nc_dsp, phys);
 }
@@ -6443,6 +7586,10 @@
 
 	/*
 	**	Compute the synchronous period in tenths of nano-seconds
+	**	from sfac.
+	**
+	**	Note, if sfac == 9, DT is being used. Double the period of 125
+	**	to 250. 
 	*/
 	if	(sfac <= 10)	per = 250;
 	else if	(sfac == 11)	per = 303;
@@ -6490,7 +7637,73 @@
 	**	Compute and return sync parameters for the ncr
 	*/
 	*fakp		= fak - 4;
-	*scntl3p	= ((div+1) << 4) + (sfac < 25 ? 0x80 : 0);
+
+	/*
+	** If sfac < 25, and 8xx parts, desire that the chip operate at 
+	** least at Ultra speeds.  Must set bit 7 of scntl3.
+	** For C1010, do not set this bit. If operating at Ultra3 speeds,
+	**	set the U3EN bit instead.
+	*/ 
+	if (np->device_id != PCI_DEVICE_ID_LSI_53C1010 ) {
+		*scntl3p	= ((div+1) << 4) + (sfac < 25 ? 0x80 : 0);
+		*fakp		= fak - 4;
+	}
+	else {
+		*scntl3p	= (div+1) << 4;
+		*fakp		= 0;
+	}
+}
+
+/*==========================================================
+**
+**	Utility routine to return the current bus width	
+**	synchronous period and offset.
+**	Utilizes target sval, wval and uval  
+**
+**==========================================================
+*/
+static void ncr_get_xfer_info(ncb_p np, tcb_p tp, u_char *factor, 
+			u_char *offset, u_char *width)
+{
+
+	u_char idiv;
+	u_long period;
+
+	*width = (tp->wval & EWS) ? 1 : 0;
+
+	if (np->device_id == PCI_DEVICE_ID_LSI_53C1010)
+		*offset  = (tp->sval & 0x3f);
+	else
+		*offset  = (tp->sval & 0x1f);
+
+        /*
+	 * Midlayer signal to the driver that all of the scsi commands
+	 * for the integrity check have completed. Save the negotiated
+ 	 * parameters (extracted from sval, wval and uval). 
+	 * See ncr_setsync for alg. details.
+	 */
+
+	idiv = (tp->wval>>4) & 0x07;
+
+	if ( *offset && idiv ) {
+	  	if (np->device_id == PCI_DEVICE_ID_LSI_53C1010){
+		    if (tp->uval & 0x80)
+			period = (2*div_10M[idiv-1])/np->clock_khz;
+	    	    else 
+	    		period = (4*div_10M[idiv-1])/np->clock_khz;
+	  	}
+	  	else
+	   	    period = (((tp->sval>>5)+4)*div_10M[idiv-1])/np->clock_khz;
+	}
+	else
+		period = 0xffff;
+
+	if	(period <= 125)		*factor =   9;
+	else if	(period <= 250)		*factor =  10;
+	else if	(period <= 303)		*factor  = 11;
+	else if	(period <= 500)		*factor  = 12;
+	else				*factor  = (period + 40 - 1) / 40;
+
 }
 
 
@@ -6504,14 +7717,19 @@
 
 static void ncr_set_sync_wide_status (ncb_p np, u_char target)
 {
-	ccb_p cp;
+	ccb_p cp = np->ccbc;
 	tcb_p tp = &np->target[target];
 
 	/*
 	**	set actual value and sync_status
+	**
+	**	TEMP register contains current scripts address
+	**	which is data type/direction/dependent.
 	*/
 	OUTB (nc_sxfer, tp->sval);
 	OUTB (nc_scntl3, tp->wval);
+	if (np->device_id == PCI_DEVICE_ID_LSI_53C1010) 
+		OUTB (nc_scntl4, tp->uval); 
 
 	/*
 	**	patch ALL ccbs of this target.
@@ -6523,6 +7741,8 @@
 			continue;
 		cp->phys.select.sel_scntl3 = tp->wval;
 		cp->phys.select.sel_sxfer  = tp->sval;
+		if (np->device_id == PCI_DEVICE_ID_LSI_53C1010)
+			cp->phys.select.sel_scntl4 = tp->uval;
 	};
 }
 
@@ -6533,11 +7753,13 @@
 **==========================================================
 */
 
-static void ncr_setsync (ncb_p np, ccb_p cp, u_char scntl3, u_char sxfer)
+static void ncr_setsync (ncb_p np, ccb_p cp, u_char scntl3, u_char sxfer, 
+					u_char scntl4)
 {
 	tcb_p tp;
 	u_char target = INB (nc_sdid) & 0x0f;
 	u_char idiv;
+	u_char offset;
 
 	assert (cp);
 	if (!cp) return;
@@ -6546,9 +7768,20 @@
 
 	tp = &np->target[target];
 
-	if (!scntl3 || !(sxfer & 0x1f))
-		scntl3 = np->rv_scntl3;
-	scntl3 = (scntl3 & 0xf0) | (tp->wval & EWS) | (np->rv_scntl3 & 0x07);
+	if (np->device_id == PCI_DEVICE_ID_LSI_53C1010) {
+		offset = sxfer & 0x3f; /* bits 5-0 */
+		scntl3 = (scntl3 & 0xf0) | (tp->wval & EWS);
+		scntl4 = (scntl4 & 0x80);
+	}
+	else {
+		offset = sxfer & 0x1f; /* bits 4-0 */
+		if (!scntl3 || !offset)
+			scntl3 = np->rv_scntl3;
+
+		scntl3 = (scntl3 & 0xf0) | (tp->wval & EWS) | 
+				(np->rv_scntl3 & 0x07);
+	}
+	
 
 	/*
 	**	Deduce the value of controller sync period from scntl3.
@@ -6556,23 +7789,43 @@
 	*/
 
 	idiv = ((scntl3 >> 4) & 0x7);
-	if ((sxfer & 0x1f) && idiv)
-		tp->period = (((sxfer>>5)+4)*div_10M[idiv-1])/np->clock_khz;
+	if ( offset && idiv) {
+		if (np->device_id == PCI_DEVICE_ID_LSI_53C1010) {
+			/* Note: If extra data hold clocks are used,
+			 * the formulas below must be modified.
+			 * When scntl4 == 0, ST mode.
+			 */
+			if (scntl4 & 0x80)
+				tp->period = (2*div_10M[idiv-1])/np->clock_khz;
+			else
+				tp->period = (4*div_10M[idiv-1])/np->clock_khz;
+		}
+		else 
+			tp->period = (((sxfer>>5)+4)*div_10M[idiv-1])/np->clock_khz;
+	}
 	else
 		tp->period = 0xffff;
 
+
 	/*
 	**	 Stop there if sync parameters are unchanged
 	*/
-	if (tp->sval == sxfer && tp->wval == scntl3) return;
+	if (tp->sval == sxfer && tp->wval == scntl3 && tp->uval == scntl4) return;
 	tp->sval = sxfer;
 	tp->wval = scntl3;
+	tp->uval = scntl4;
 
 	/*
 	**	Bells and whistles   ;-)
+	**	Donnot announce negotiations due to auto-sense, 
+	**	unless user really want us to be verbose. :)
 	*/
-	PRINT_TARGET(np, target);
-	if (sxfer & 0x01f) {
+	if ( bootverbose < 2 && (cp->host_flags & HF_AUTO_SENSE))
+		goto next;
+	if (DEBUG_FLAGS & DEBUG_NEGO) {
+		PRINT_TARGET(np, target);
+	}
+	if (offset) {
 		unsigned f10 = 100000 << (tp->widedone ? tp->widedone -1 : 0);
 		unsigned mb10 = (f10 + tp->period/2) / tp->period;
 		char *scsi;
@@ -6580,22 +7833,28 @@
 		/*
 		**  Disable extended Sreq/Sack filtering
 		*/
-		if (tp->period <= 2000) OUTOFFB (nc_stest2, EXT);
+		if ((tp->period <= 2000) && 
+			(np->device_id != PCI_DEVICE_ID_LSI_53C1010))
+				OUTOFFB (nc_stest2, EXT);
 
 		/*
 		**	Bells and whistles   ;-)
 		*/
-		if	(tp->period < 500)	scsi = "FAST-40";
-		else if	(tp->period < 1000)	scsi = "FAST-20";
-		else if	(tp->period < 2000)	scsi = "FAST-10";
-		else				scsi = "FAST-5";
-
-		printk ("%s %sSCSI %d.%d MB/s (%d ns, offset %d)\n", scsi,
-			tp->widedone > 1 ? "WIDE " : "",
-			mb10 / 10, mb10 % 10, tp->period / 10, sxfer & 0x1f);
-	} else
+		if (DEBUG_FLAGS & DEBUG_NEGO) {
+			if	(tp->period < 250)	scsi = "FAST-80";
+			else if	(tp->period < 500)	scsi = "FAST-40";
+			else if	(tp->period < 1000)	scsi = "FAST-20";
+			else if	(tp->period < 2000)	scsi = "FAST-10";
+			else				scsi = "FAST-5";
+
+			printk ("%s %sSCSI %d.%d MB/s (%d ns, offset %d)\n", scsi,
+					tp->widedone > 1 ? "WIDE " : "",
+					mb10 / 10, mb10 % 10, tp->period / 10, offset);
+		}
+	} else if (DEBUG_FLAGS & DEBUG_NEGO) {
 		printk ("%sasynchronous.\n", tp->widedone > 1 ? "wide " : "");
-
+	}
+next:
 	/*
 	**	set actual value and sync_status
 	**	patch ALL ccbs of this target.
@@ -6603,6 +7862,7 @@
 	ncr_set_sync_wide_status(np, target);
 }
 
+
 /*==========================================================
 **
 **	Switch wide mode for current job and it's target
@@ -6656,6 +7916,128 @@
 	ncr_set_sync_wide_status(np, target);
 }
 
+
+/*==========================================================
+**
+**	Switch sync/wide mode for current job and it's target
+**	PPR negotiations only
+**
+**==========================================================
+*/
+
+static void ncr_setsyncwide (ncb_p np, ccb_p cp, u_char scntl3, u_char sxfer, 
+				u_char scntl4, u_char wide)
+{
+	tcb_p tp;
+	u_char target = INB (nc_sdid) & 0x0f;
+	u_char idiv;
+	u_char offset;
+
+	assert (cp);
+	if (!cp) return;
+
+	assert (target == (cp->target & 0xf));
+
+	tp = &np->target[target];
+	tp->widedone  =  wide+1;
+
+	if (np->device_id == PCI_DEVICE_ID_LSI_53C1010) {
+		offset = sxfer & 0x3f; /* bits 5-0 */
+		scntl3 = (scntl3 & 0xf0) | (wide ? EWS : 0);
+		scntl4 = (scntl4 & 0x80);
+	}
+	else {
+		offset = sxfer & 0x1f; /* bits 4-0 */
+		if (!scntl3 || !offset)
+			scntl3 = np->rv_scntl3;
+
+		scntl3 = (scntl3 & 0xf0) | (wide ? EWS : 0) | 
+				(np->rv_scntl3 & 0x07);
+	}
+	
+
+	/*
+	**	Deduce the value of controller sync period from scntl3.
+	**	period is in tenths of nano-seconds.
+	*/
+
+	idiv = ((scntl3 >> 4) & 0x7);
+	if ( offset && idiv) {
+		if (np->device_id == PCI_DEVICE_ID_LSI_53C1010) {
+			/* Note: If extra data hold clocks are used,
+			 * the formulas below must be modified.
+			 * When scntl4 == 0, ST mode.
+			 */
+			if (scntl4 & 0x80)
+				tp->period = (2*div_10M[idiv-1])/np->clock_khz;
+			else
+				tp->period = (4*div_10M[idiv-1])/np->clock_khz;
+		}
+		else 
+			tp->period = (((sxfer>>5)+4)*div_10M[idiv-1])/np->clock_khz;
+	}
+	else
+		tp->period = 0xffff;
+
+
+	/*
+	**	 Stop there if sync parameters are unchanged
+	*/
+	if (tp->sval == sxfer && tp->wval == scntl3 && tp->uval == scntl4) return;
+	tp->sval = sxfer;
+	tp->wval = scntl3;
+	tp->uval = scntl4;
+
+	/*
+	**	Bells and whistles   ;-)
+	**	Donnot announce negotiations due to auto-sense, 
+	**	unless user really want us to be verbose. :)
+	*/
+	if ( bootverbose < 2 && (cp->host_flags & HF_AUTO_SENSE))
+		goto next;
+	if (DEBUG_FLAGS & DEBUG_NEGO) {
+		PRINT_TARGET(np, target);
+	}
+	if (offset) {
+		unsigned f10 = 100000 << (tp->widedone ? tp->widedone -1 : 0);
+		unsigned mb10 = (f10 + tp->period/2) / tp->period;
+		char *scsi;
+
+		/*
+		**  Disable extended Sreq/Sack filtering
+		*/
+		if ((tp->period <= 2000) && 
+			(np->device_id != PCI_DEVICE_ID_LSI_53C1010))
+				OUTOFFB (nc_stest2, EXT);
+
+		/*
+		**	Bells and whistles   ;-)
+		*/
+		if (DEBUG_FLAGS & DEBUG_NEGO) {
+			if	(tp->period < 250)	scsi = "FAST-80";
+			else if	(tp->period < 500)	scsi = "FAST-40";
+			else if	(tp->period < 1000)	scsi = "FAST-20";
+			else if	(tp->period < 2000)	scsi = "FAST-10";
+			else				scsi = "FAST-5";
+
+			printk ("%s %sSCSI %d.%d MB/s (%d ns, offset %d)\n", scsi,
+					tp->widedone > 1 ? "WIDE " : "",
+					mb10 / 10, mb10 % 10, tp->period / 10, offset);
+		}
+	} else if (DEBUG_FLAGS & DEBUG_NEGO) {
+		printk ("%sasynchronous.\n", tp->widedone > 1 ? "wide " : "");
+	}
+next:
+	/*
+	**	set actual value and sync_status
+	**	patch ALL ccbs of this target.
+	*/
+	ncr_set_sync_wide_status(np, target);
+}
+
+
+
+
 /*==========================================================
 **
 **	Switch tagged mode for a target.
@@ -6667,7 +8049,7 @@
 {
 	tcb_p tp = &np->target[tn];
 	lcb_p lp = ncr_lp(np, tp, ln);
-	u_char   reqtags, maxdepth;
+	u_short reqtags, maxdepth;
 
 	/*
 	**	Just in case ...
@@ -6761,35 +8143,12 @@
 {
 	u_char t;
 	tcb_p tp;
+	int ln;
+	u_long size;
 
 	switch (np->user.cmd) {
-
 	case 0: return;
 
-	case UC_SETSYNC:
-		for (t=0; t<MAX_TARGET; t++) {
-			if (!((np->user.target>>t)&1)) continue;
-			tp = &np->target[t];
-			tp->usrsync = np->user.data;
-			ncr_negotiate (np, tp);
-		};
-		break;
-
-	case UC_SETTAGS:
-		for (t=0; t<MAX_TARGET; t++) {
-			int ln;
-			if (!((np->user.target>>t)&1)) continue;
-			np->target[t].usrtags = np->user.data;
-			for (ln = 0; ln < MAX_LUN; ln++) {
-				lcb_p lp = ncr_lp(np, &np->target[t], ln);
-				if (!lp)
-					continue;
-				lp->maxtags = lp->numtags = np->user.data;
-				ncr_setup_tags (np, t, ln);
-			}
-		};
-		break;
-
 	case UC_SETDEBUG:
 #ifdef SCSI_NCR_DEBUG_INFO_SUPPORT
 		ncr_debug = np->user.data;
@@ -6804,31 +8163,73 @@
 		np->verbose = np->user.data;
 		break;
 
-	case UC_SETWIDE:
-		for (t=0; t<MAX_TARGET; t++) {
-			u_long size;
-			if (!((np->user.target>>t)&1)) continue;
-			tp = &np->target[t];
-			size = np->user.data;
-			if (size > np->maxwide) size=np->maxwide;
-			tp->usrwide = size;
-			ncr_negotiate (np, tp);
-		};
-		break;
-
-	case UC_SETFLAG:
-		for (t=0; t<MAX_TARGET; t++) {
-			if (!((np->user.target>>t)&1)) continue;
-			tp = &np->target[t];
-			tp->usrflag = np->user.data;
-		};
-		break;
-
 #ifdef SCSI_NCR_PROFILE_SUPPORT
 	case UC_CLEARPROF:
 		bzero(&np->profile, sizeof(np->profile));
 		break;
 #endif
+	default:
+		/*
+		**	We assume that other commands apply to targets.
+		**	This should always be the case and avoid the below 
+		**	4 lines to be repeated 5 times.
+		*/
+		for (t = 0; t < MAX_TARGET; t++) {
+			if (!((np->user.target >> t) & 1))
+				continue;
+			tp = &np->target[t];
+
+			switch (np->user.cmd) {
+
+			case UC_SETSYNC:
+				tp->usrsync = np->user.data;
+				ncr_negotiate (np, tp);
+				break;
+
+			case UC_SETWIDE:
+				size = np->user.data;
+				if (size > np->maxwide)
+					size=np->maxwide;
+				tp->usrwide = size;
+				ncr_negotiate (np, tp);
+				break;
+
+			case UC_SETTAGS:
+				tp->usrtags = np->user.data;
+				for (ln = 0; ln < MAX_LUN; ln++) {
+					lcb_p lp;
+					lp = ncr_lp(np, tp, ln);
+					if (!lp)
+						continue;
+					lp->numtags = np->user.data;
+					lp->maxtags = lp->numtags;
+					ncr_setup_tags (np, t, ln);
+				}
+				break;
+
+			case UC_RESETDEV:
+				tp->to_reset = 1;
+				np->istat_sem = SEM;
+				OUTB (nc_istat, SIGP|SEM);
+				break;
+
+			case UC_CLEARDEV:
+				for (ln = 0; ln < MAX_LUN; ln++) {
+					lcb_p lp;
+					lp = ncr_lp(np, tp, ln);
+					if (lp)
+						lp->to_clear = 1;
+				}
+				np->istat_sem = SEM;
+				OUTB (nc_istat, SIGP|SEM);
+				break;
+
+			case UC_SETFLAG:
+				tp->usrflag = np->user.data;
+				break;
+			}
+		}
+		break;
 	}
 	np->user.cmd=0;
 }
@@ -6850,7 +8251,7 @@
 
 static void ncr_timeout (ncb_p np)
 {
-	u_long	thistime = jiffies;
+	u_long	thistime = ktime_get(0);
 
 	/*
 	**	If release process in progress, let's go
@@ -6863,7 +8264,11 @@
 		return;
 	}
 
-	np->timer.expires = jiffies + SCSI_NCR_TIMER_INTERVAL;
+#ifdef SCSI_NCR_PCIQ_BROKEN_INTR
+	np->timer.expires = ktime_get((HZ+9)/10);
+#else
+	np->timer.expires = ktime_get(SCSI_NCR_TIMER_INTERVAL);
+#endif
 	add_timer(&np->timer);
 
 	/*
@@ -6886,8 +8291,20 @@
 	if (np->lasttime + 4*HZ < thistime) {
 		np->lasttime = thistime;
 	}
+
+#ifdef SCSI_NCR_PCIQ_MAY_MISS_COMPLETIONS
+	/*
+	**	Some way-broken PCI bridges may lead to 
+	**	completions being lost when the clearing 
+	**	of the INTFLY flag by the CPU occurs 
+	**	concurrently with the chip raising this flag.
+	**	If this ever happen, lost completions will 
+	**	be reaped here.
+	*/
+	ncr_wakeup_done(np);
+#endif
 
-#ifdef SCSI_NCR_BROKEN_INTR
+#ifdef SCSI_NCR_PCIQ_BROKEN_INTR
 	if (INB(nc_istat) & (INTF|SIP|DIP)) {
 
 		/*
@@ -6897,7 +8314,7 @@
 		ncr_exception (np);
 		if (DEBUG_FLAGS & DEBUG_TINY) printk ("}");
 	}
-#endif /* SCSI_NCR_BROKEN_INTR */
+#endif /* SCSI_NCR_PCIQ_BROKEN_INTR */
 }
 
 /*==========================================================
@@ -6924,7 +8341,7 @@
 **		dsp:	script adress (relative to start of script).
 **		dbc:	first word of script command.
 **
-**	First 16 register of the chip:
+**	First 24 register of the chip:
 **		r0..rf
 **
 **==========================================================
@@ -6973,7 +8390,7 @@
 	}
 
         printk ("%s: regdump:", ncr_name(np));
-        for (i=0; i<16;i++)
+        for (i=0; i<24;i++)
             printk (" %02x", (unsigned)INB_OFF(i));
         printk (".\n");
 }
@@ -7080,7 +8497,7 @@
 	**	with my 895 that unfortunately suffers of the MA int.).
 	*/
 	if (driver_setup.optimize & 1) {
-		OUTB(nc_istat, (INTF | SIGP));
+		OUTB(nc_istat, (INTF | SIGP | np->istat_sem));
 		if (ncr_wakeup_done (np)) {
 #ifdef SCSI_NCR_PROFILE_SUPPORT
 			++np->profile.num_fly;
@@ -7092,10 +8509,17 @@
 
 	/*
 	**	interrupt on the fly ?
+	**
+	**	For bridges that donnot flush posted writes 
+	**	in the reverse direction on read, a dummy read 
+	**	may help not to miss completions.
 	*/
 	istat = INB (nc_istat);
 	if (istat & INTF) {
-		OUTB (nc_istat, (istat & SIGP) | INTF);
+		OUTB (nc_istat, (istat & SIGP) | INTF | np->istat_sem);
+#ifdef SCSI_NCR_PCIQ_MAY_NOT_FLUSH_PW_UPSTREAM
+		istat = INB (nc_istat);		/* DUMMY READ */
+#endif
 		if (DEBUG_FLAGS & DEBUG_TINY) printk ("F ");
 		(void)ncr_wakeup_done (np);
 #ifdef SCSI_NCR_PROFILE_SUPPORT
@@ -7213,8 +8637,8 @@
 	**	Reset everything.
 	**=========================================================
 	*/
-	if (jiffies - np->regtime > 10*HZ) {
-		np->regtime = jiffies;
+	if (ktime_exp(np->regtime)) {
+		np->regtime = ktime_get(10*HZ);
 		for (i = 0; i<sizeof(np->regdump); i++)
 			((char*)&np->regdump)[i] = INB_OFF(i);
 		np->regdump.nc_dstat = dstat;
@@ -7223,6 +8647,27 @@
 
 	ncr_log_hard_error(np, sist, dstat);
 
+	if (np->device_id == PCI_DEVICE_ID_LSI_53C1010) {
+		u_char ctest4_o, ctest4_m;
+		u_char shadow;
+
+		/* 
+		 * Get shadow register data 
+		 * Write 1 to ctest4
+		 */
+		ctest4_o = INB(nc_ctest4);
+
+		OUTB(nc_ctest4, ctest4_o | 0x10);
+		
+		ctest4_m = INB(nc_ctest4);
+		shadow = INW_OFF(0x42);
+
+		OUTB(nc_ctest4, ctest4_o);
+
+		printk("%s: ctest4/sist original 0x%x/0x%X  mod: 0x%X/0x%x\n", 
+			ncr_name(np), ctest4_o, sist, ctest4_m, shadow);
+	}
+
 	if ((sist & (GEN|HTH|SGE)) ||
 		(dstat & (MDPE|BF|ABRT|IID))) {
 		ncr_start_reset(np);
@@ -7287,6 +8732,8 @@
 	       dsp < NCB_SCRIPT_PHYS (np, getjob_end) + 1)) &&
 	    (!(dsp > NCB_SCRIPT_PHYS (np, ungetjob) &&
 	       dsp < NCB_SCRIPT_PHYS (np, reselect) + 1)) &&
+	    (!(dsp > NCB_SCRIPTH_PHYS (np, sel_for_abort) &&
+	       dsp < NCB_SCRIPTH_PHYS (np, sel_for_abort_1) + 1)) &&
 	    (!(dsp > NCB_SCRIPT_PHYS (np, done) &&
 	       dsp < NCB_SCRIPT_PHYS (np, done_end) + 1))) {
 		if (cp) {
@@ -7330,7 +8777,6 @@
 	if (DEBUG_FLAGS & DEBUG_TINY) printk ("T");
 
 	if (dsp == NCB_SCRIPT_PHYS (np, wf_sel_done) + 8 ||
-	    dsp == NCB_SCRIPTH_PHYS (np, wf_sel_done_no_atn) + 8 ||
 	    !(driver_setup.recovery & 1))
 		ncr_recover_scsi_int(np, HS_SEL_TIMEOUT);
 	else
@@ -7347,6 +8793,20 @@
 */
 void ncr_int_udc (ncb_p np)
 {
+	u_int32 dsa = INL (nc_dsa);
+	ccb_p   cp  = ncr_ccb_from_dsa(np, dsa);
+	tcb_p   tp  = &np->target[cp->target];
+
+	/*
+	 * Fix Up. Some disks respond to a PPR negotation with
+	 * a bus free instead of a message reject. 
+	 * Disable ppr negotiation if this is first time
+	 * tried ppr negotiation.
+	 */
+	
+	if (tp->ppr_negotiation == 1)
+		tp->ppr_negotiation = 0;
+	
 	printk ("%s: unexpected disconnect\n", ncr_name(np));
 	ncr_recover_scsi_int(np, HS_UNEXPECTED);
 }
@@ -7382,7 +8842,7 @@
 	**	Suspend command processing for 1 second and 
 	**	reinitialize all except the chip.
 	*/
-	np->settle_time	= jiffies + HZ;
+	np->settle_time	= ktime_get(1*HZ);
 	ncr_init (np, 0, bootverbose ? "scsi mode change" : NULL, HS_RESET);
 }
 
@@ -7408,8 +8868,8 @@
 **	  The chip will then interrupt with both PAR and MA 
 **	  conditions set.
 **
-**	- A phase mismatch occurs before the MOV finished 
-**	  and phase errors are to be handled by SCRIPTS (896).
+**	- A phase mismatch occurs before the MOV finished and 
+**	  phase errors are to be handled by SCRIPTS (895A or 896).
 **	  The chip will load the DSP with the phase mismatch 
 **	  JUMP address and interrupt the host processor.
 **
@@ -7425,6 +8885,7 @@
 	u_char	sbcl	= INB (nc_sbcl);
 	u_char	cmd	= dbc >> 24;
 	int phase	= cmd & 7;
+	ccb_p	cp	= ncr_ccb_from_dsa(np, dsa);
 
 	printk("%s: SCSI parity error detected: SCR1=%d DBC=%x SBCL=%x\n",
 		ncr_name(np), hsts, dbc, sbcl);
@@ -7444,7 +8905,7 @@
 	**	If the nexus is not clearly identified, reset the bus.
 	**	We will try to do better later.
 	*/
-	if (!ncr_ccb_from_dsa(np, dsa))
+	if (!cp)
 		goto reset_all;
 
 	/*
@@ -7457,7 +8918,7 @@
 	/*
 	**	Keep track of the parity error.
 	*/
-	OUTONB (HF_PRT, HF_PAR_ERR);
+	cp->xerr_status |= XE_PARITY_ERR;
 
 	/*
 	**	Prepare the message to send to the device.
@@ -7465,13 +8926,19 @@
 	np->msgout[0] = (phase == 7) ? M_PARITY : M_ID_ERROR;
 
 	/*
-	**	If the old phase was DATA IN phase, we have to deal with
-	**	the 3 situations described above.
-	**	For other input phases (MSG IN and STATUS), the device 
-	**	must resend the whole thing that failed parity checking 
+	**	Save error message. For integrity check use only.
+	*/
+	if (np->check_integrity) 
+		np->check_integ_par = np->msgout[0];
+
+	/*
+	**	If the old phase was DATA IN or DT DATA IN phase, 
+	** 	we have to deal with the 3 situations described above.
+	**	For other input phases (MSG IN and STATUS), the device 
+	**	must resend the whole thing that failed parity checking 
 	**	or signal error. So, jumping to dispatcher should be OK.
 	*/
-	if (phase == 1) {
+	if ((phase == 1) || (phase == 5)) {
 		/* Phase mismatch handled by SCRIPTS */
 		if (dsp == NCB_SCRIPTH_PHYS (np, pm_handle))
 			OUTL (nc_dsp, dsp);
@@ -7481,7 +8948,7 @@
 		/* No phase mismatch occurred */
 		else {
 			OUTL (nc_temp, dsp);
-			OUTL (nc_dsp, NCB_SCRIPT_PHYS (np, databreak));
+			OUTL (nc_dsp, NCB_SCRIPT_PHYS (np, dispatch));
 		}
 	}
 	else 
@@ -7541,44 +9008,62 @@
 	*/
 	cp = ncr_ccb_from_dsa(np, dsa);
 
+	if (DEBUG_FLAGS & DEBUG_PHASE)
+		printk("CCB = %2x %2x %2x %2x %2x %2x\n", 
+			cp->cmd->cmnd[0], cp->cmd->cmnd[1], cp->cmd->cmnd[2],
+			cp->cmd->cmnd[3], cp->cmd->cmnd[4], cp->cmd->cmnd[5]);
+
 	/*
 	**	Donnot take into account dma fifo and various buffers in 
-	**	DATA IN phase since the chip flushes everything before 
+	**	INPUT phase since the chip flushes everything before 
 	**	raising the MA interrupt for interrupted INPUT phases.
+	**	For DATA IN phase, we will check for the SWIDE later.
 	*/
-	if ((cmd & 7) != 1) {
+	if ( !(((cmd & 7) == 1) || ((cmd & 7) == 5) ) ) {
 		u_int32 dfifo;
 		u_char ss0, ss2;
 
 		/*
-		** Read DFIFO, CTEST[4-6] using 1 PCI bus ownership.
+		**  If C1010, DFBC contains number of bytes in DMA fifo.
+		**  else read DFIFO, CTEST[4-6] using 1 PCI bus ownership.
 		*/
-		dfifo = INL(nc_dfifo);
+		if (np->device_id == PCI_DEVICE_ID_LSI_53C1010) 
+			delta = INL(nc_dfbc) & 0xffff;
+		else {
+			dfifo = INL(nc_dfifo);
 
-		/*
-		**	Calculate remaining bytes in DMA fifo.
-		**	(CTEST5 = dfifo >> 16)
-		*/
-		if (dfifo & (DFS << 16))
-			delta = ((((dfifo >> 8) & 0x300) |
-			          (dfifo & 0xff)) - rest) & 0x3ff;
-		else
-			delta = ((dfifo & 0xff) - rest) & 0x7f;
+			/*
+			**	Calculate remaining bytes in DMA fifo.
+			**	C1010 - always large fifo, value in dfbc
+			**	Otherwise, (CTEST5 = dfifo >> 16)
+			*/
+			if (dfifo & (DFS << 16))
+				delta = ((((dfifo >> 8) & 0x300) |
+				          (dfifo & 0xff)) - rest) & 0x3ff;
+			else
+				delta = ((dfifo & 0xff) - rest) & 0x7f;
 
-		/*
-		**	The data in the dma fifo has not been transfered to
-		**	the target -> add the amount to the rest
-		**	and clear the data.
-		**	Check the sstat2 register in case of wide transfer.
-		*/
+			/*
+			**	The data in the dma fifo has not been 
+			**	transferred to the target -> add the amount 
+			**	to the rest and clear the data.
+			**	Check the sstat2 register in case of wide
+			**	transfer.
+			*/
+
+		}
+		
 		rest += delta;
 		ss0  = INB (nc_sstat0);
 		if (ss0 & OLF) rest++;
-		if (ss0 & ORF) rest++;
+		if ((np->device_id != PCI_DEVICE_ID_LSI_53C1010) && (ss0 & ORF)) 
+			rest++;
 		if (cp && (cp->phys.select.sel_scntl3 & EWS)) {
 			ss2 = INB (nc_sstat2);
 			if (ss2 & OLF1) rest++;
-			if (ss2 & ORF1) rest++;
+			if ((np->device_id != PCI_DEVICE_ID_LSI_53C1010) 
+								&& (ss2 & ORF)) 
+				rest++;
 		};
 
 		/*
@@ -7586,7 +9071,7 @@
 		*/
 		OUTB (nc_ctest3, np->rv_ctest3 | CLF);	/* dma fifo  */
 		OUTB (nc_stest3, TE|CSF);		/* scsi fifo */
-	};
+	}
 
 	/*
 	**	log the information
@@ -7670,13 +9155,17 @@
 
 	/*
 	**	if old phase not dataphase, leave here.
+	**	C/D line is low if data.
 	*/
 
-	if (cmd & 0x06) {
-		PRINT_ADDR(cp->cmd);
-		printk ("phase change %x-%x %d@%08x resid=%d.\n",
-			cmd&7, INB(nc_sbcl)&7, (unsigned)olen,
-			(unsigned)oadr, (unsigned)rest);
+	if (cmd & 0x02) {
+		if (!np->check_integrity || !cp->cmd->ic_in_progress ||
+			(DEBUG_FLAGS & DEBUG_NEGO)) {
+			PRINT_ADDR(cp->cmd);
+			printk ("phase change %x-%x %d@%08x resid=%d.\n",
+					cmd&7, INB(nc_sbcl)&7, (unsigned)olen,
+					(unsigned)oadr, (unsigned)rest);
+		}
 		goto unexpected_phase;
 	};
 
@@ -7685,8 +9174,8 @@
 	**
 	**	Look at the PM_SAVE SCRIPT if you want to understand 
 	**	this stuff. The equivalent code is implemented in 
-	**	SCRIPTS for the 896 that is able to handle PM from 
-	**	the SCRIPTS processor.
+	**	SCRIPTS for the 895A and 896 that are able to handle 
+	**	PM from the SCRIPTS processor.
 	*/
 
 	hflags0 = INB (HF_PRT);
@@ -7723,6 +9212,54 @@
 	pm->sg.size = cpu_to_scr(rest);
 	pm->ret     = cpu_to_scr(nxtdsp);
 
+	/*
+	**	If we have a SWIDE,
+	**	- prepare the address to write the SWIDE from SCRIPTS,
+	**	- compute the SCRIPTS address to restart from,
+	**	- move current data pointer context by one byte.
+	*/
+	nxtdsp = NCB_SCRIPT_PHYS (np, dispatch);
+	if ( ((cmd & 7) == 1  || (cmd & 7) == 5)  
+		&& cp && (cp->phys.select.sel_scntl3 & EWS) &&
+	    (INB (nc_scntl2) & WSR)) {
+		/*
+		**	Hmmm... The device may want to also ignore 
+		**	this residue but it must send immediately the
+		**	appropriate message. We snoop the SCSI BUS 
+		**	and will just throw away this message from 
+		**	SCRIPTS if the SWIDE is to be ignored.
+		*/
+		if ((INB (nc_sbcl) & 7) == 7 && 
+		    INB (nc_sbdl) == M_IGN_RESIDUE) {
+			nxtdsp = NCB_SCRIPT_PHYS (np, ign_i_w_r_msg);
+		}
+		/*
+		**	We must grab the SWIDE.
+		**	We will use some complex SCRIPTS for that.
+		*/
+		else {
+			OUTL (nc_scratcha, pm->sg.addr);
+			nxtdsp = NCB_SCRIPTH_PHYS (np, swide_ma_32);
+			if (np->features & FE_64BIT) {
+				OUTB (nc_sbr, (pm->sg.size >> 24));
+				nxtdsp = NCB_SCRIPTH_PHYS (np, swide_ma_64);
+			}
+			/*
+			**	Adjust our data pointer context.
+			*/
+			++pm->sg.addr;
+			--pm->sg.size;
+			/*
+			**	Hmmm... Could it be possible that a SWIDE that 
+			**	is followed by a 1 byte CHMOV would lead to 
+			**	a CHMOV(0). Anyway, we handle it by just 
+			**	skipping context that would attempt a CHMOV(0).
+			*/
+			if (!pm->sg.size)
+				newcmd = pm->ret;
+		}
+	}
+
 	if (DEBUG_FLAGS & DEBUG_PHASE) {
 		PRINT_ADDR(cp->cmd);
 		printk ("PM %x %x %x / %x %x %x.\n",
@@ -7733,12 +9270,11 @@
 	}
 
 	/*
-	**	fake the return address (to the patch).
-	**	and restart script processor at dispatcher.
+	**	Restart the SCRIPTS processor.
 	*/
 
 	OUTL (nc_temp, newcmd);
-	OUTL (nc_dsp, NCB_SCRIPT_PHYS (np, databreak));
+	OUTL (nc_dsp,  nxtdsp);
 	return;
 
 	/*
@@ -7798,7 +9334,8 @@
 				nxtdsp = NCB_SCRIPTH_PHYS (np, ident_break);
 		}
 		else if	(dsp == NCB_SCRIPTH_PHYS (np, send_wdtr) ||
-			 dsp == NCB_SCRIPTH_PHYS (np, send_sdtr)) {
+			 dsp == NCB_SCRIPTH_PHYS (np, send_sdtr) ||
+			 dsp == NCB_SCRIPTH_PHYS (np, send_ppr)) {
 			nxtdsp = NCB_SCRIPTH_PHYS (np, nego_bad_phase);
 		}
 		break;
@@ -7842,6 +9379,10 @@
 **	requeue the CCB that failed in front of the LUN queue.
 **	I just hope this not to be performed too often. :)
 **
+**	If we are using IMMEDIATE ARBITRATION, we clear the 
+**	IARB hint for every commands we encounter in order not 
+**	to be stuck with a won arbitration and no job to queue 
+**	to a device.
 **----------------------------------------------------------
 */
 
@@ -7854,66 +9395,64 @@
 	int		busyccbs = 1;
 	u_int32		startp;
 	u_char		s_status = INB (SS_PRT);
+	int		msglen;
+	int		i, j;
 
+
+	/*
+	**	If the LCB is not yet available, then only 
+	**	1 IO is accepted, so we should have it.
+	*/
+	if (!lp)
+		goto next;	
 	/*
 	**	Remove all CCBs queued to the chip for that LUN and put 
 	**	them back in the LUN CCB wait queue.
 	*/
-	if (lp) {
-		int i = np->squeueput;
-		int j = (INL (nc_scratcha) - vtobus(np->squeue)) / 4;
-		int k = np->squeueput;
-
-		busyccbs = lp->queuedccbs;
-		while (1) {
-			if (i == j)
-				break;
-			if (i == 0)
-				i = MAX_START*2;
-			i = i - 2;
-			cp2 = ncr_ccb_from_dsa(np, scr_to_cpu(np->squeue[i]));
-			if (!cp2)
-				continue;
-			if (cp2->target != cp->target || cp2->lun != cp->lun)
-				continue;
+	busyccbs = lp->queuedccbs;
+	i = (INL (nc_scratcha) - vtobus(np->squeue)) / 4;
+	j = i;
+	while (i != np->squeueput) {
+		cp2 = ncr_ccb_from_dsa(np, scr_to_cpu(np->squeue[i]));
+		assert(cp2);
+#ifdef SCSI_NCR_IARB_SUPPORT
+		/* IARB hints may not be relevant any more. Forget them. */
+		cp2->host_flags &= ~HF_HINT_IARB;
+#endif
+		if (cp2 && cp2->target == cp->target && cp2->lun == cp->lun) {
 			xpt_remque(&cp2->link_ccbq);
 			xpt_insque_head(&cp2->link_ccbq, &lp->wait_ccbq);
 			--lp->queuedccbs;
 			cp2->queued = 0;
-			np->squeue[i] = DSA_INVALID;
-			k = i;
 		}
-
-		/*
-		**	Requeue the interrupted CCB in front of 
-		**	the LUN CCB wait queue.
-		*/
-		xpt_remque(&cp->link_ccbq);
-		xpt_insque_head(&cp->link_ccbq, &lp->wait_ccbq);
-		--lp->queuedccbs;
-		cp->queued = 0;
-
-		/*
-		**	Repair the startqueue if necessary.
-		*/
-		if (k != np->squeueput) {
-			j = k;
-			while (1) {
-				j += 2;
-				if (j >= MAX_START*2)
-					j = 0;
-				if (np->squeue[j] == DSA_INVALID)
-					continue;
-				np->squeue[k] = np->squeue[j];
-				if (j == np->squeueput)
-					break;
-				k += 2;
-				if (k >= MAX_START*2)
-					k = 0;
-			}
-			np->squeueput = k;
+		else {
+			if (i != j)
+				np->squeue[j] = np->squeue[i];
+			if ((j += 2) >= MAX_START*2) j = 0;
 		}
+		if ((i += 2) >= MAX_START*2) i = 0;
 	}
+	if (i != j)		/* Copy back the idle task if needed */
+		np->squeue[j] = np->squeue[i];
+	np->squeueput = j;	/* Update our current start queue pointer */
+
+	/*
+	**	Requeue the interrupted CCB in front of the 
+	**	LUN CCB wait queue to preserve ordering.
+	*/
+	xpt_remque(&cp->link_ccbq);
+	xpt_insque_head(&cp->link_ccbq, &lp->wait_ccbq);
+	--lp->queuedccbs;
+	cp->queued = 0;
+
+next:
+
+#ifdef SCSI_NCR_IARB_SUPPORT
+	/* IARB hint may not be relevant any more. Forget it. */
+	cp->host_flags &= ~HF_HINT_IARB;
+	if (np->last_cp)
+		np->last_cp = 0;
+#endif
 
 	/*
 	**	Now we can restart the SCRIPTS processor safely.
@@ -7922,7 +9461,10 @@
 	OUTL (nc_dsp, NCB_SCRIPT_PHYS (np, start));
 
 	switch(s_status) {
-	default:	/* Just for safety, should never happen */
+	default:
+	case S_BUSY:
+		ncr_complete(np, cp);
+		break;
 	case S_QUEUE_FULL:
 		if (!lp || !lp->queuedccbs) {
 			ncr_complete(np, cp);
@@ -7945,10 +9487,13 @@
 		/*
 		**	Repair the offending CCB.
 		*/
-		cp->phys.header.savep = cp->startp;
-		cp->host_status = HS_BUSY;
-		cp->scsi_status = S_ILLEGAL;
-		cp->host_flags	&= HF_PM_TO_C;
+		cp->phys.header.savep	= cp->startp;
+		cp->phys.header.lastp	= cp->lastp0;
+		cp->host_status 	= HS_BUSY;
+		cp->scsi_status 	= S_ILLEGAL;
+		cp->xerr_status		= 0;
+		cp->phys.extra_bytes	= 0;
+		cp->host_flags		&= HF_PM_TO_C;
 
 		break;
 
@@ -7957,12 +9502,20 @@
 		/*
 		**	If we were requesting sense, give up.
 		*/
-		if (cp->auto_sense) {
+		if (cp->host_flags & HF_AUTO_SENSE) {
 			ncr_complete(np, cp);
 			break;
 		}
 
 		/*
+		**	Save SCSI status and extended error.
+		**	Compute the data residual now.
+		*/
+		cp->sv_scsi_status = cp->scsi_status;
+		cp->sv_xerr_status = cp->xerr_status;
+		cp->resid = ncr_compute_residual(np, cp);
+
+		/*
 		**	Device returned CHECK CONDITION status.
 		**	Prepare all needed data strutures for getting 
 		**	sense data.
@@ -7972,8 +9525,63 @@
 		**	identify message
 		*/
 		cp->scsi_smsg2[0]	= M_IDENTIFY | cp->lun;
+		msglen = 1;
+
+		/*
+		**	If we are currently using anything different from 
+		**	async. 8 bit data transfers with that target,
+		**	start a negotiation, since the device may want 
+		**	to report us a UNIT ATTENTION condition due to 
+		**	a cause we currently ignore, and we donnot want 
+		**	to be stuck with WIDE and/or SYNC data transfer.
+		**
+		**	cp->nego_status is filled by ncr_prepare_nego().
+		**
+		**	Do NOT negotiate if performing integrity check
+		**	or if integrity check has completed, all check
+		**	conditions will have been cleared.
+		*/
+
+		if (DEBUG_FLAGS & DEBUG_IC) {
+		printk("%s: ncr_sir_to_redo: ic_done %2X, in_progress %2X\n",
+			ncr_name(np), tp->ic_done, cp->cmd->ic_in_progress);
+		}
+
+		/*
+		**	If parity error during integrity check,
+		**	set the target width to narrow. Otherwise,
+		**	do not negotiate on a request sense.
+		*/
+		if ( np->check_integ_par && np->check_integrity 
+						&& cp->cmd->ic_in_progress ) { 
+			cp->nego_status = 0;
+			msglen +=
+			    ncr_ic_nego (np, cp, cmd ,&cp->scsi_smsg2[msglen]);
+		}
+
+		if (!np->check_integrity || 
+		   	(np->check_integrity && 
+				(!cp->cmd->ic_in_progress && !tp->ic_done)) ) { 
+		    ncr_negotiate(np, tp);
+		    cp->nego_status = 0;
+		    {
+			u_char sync_offset;
+			if (np->device_id == PCI_DEVICE_ID_LSI_53C1010)
+				sync_offset = tp->sval & 0x3f;
+			else
+				sync_offset = tp->sval & 0x1f;
+
+		        if ((tp->wval & EWS) || sync_offset)
+			  msglen +=
+			    ncr_prepare_nego (np, cp, &cp->scsi_smsg2[msglen]);
+		    }
+
+		}
+		/*
+		**	Message table indirect structure.
+		*/
 		cp->phys.smsg.addr	= cpu_to_scr(CCB_PHYS (cp, scsi_smsg2));
-		cp->phys.smsg.size	= cpu_to_scr(1);
+		cp->phys.smsg.size	= cpu_to_scr(msglen);
 
 		/*
 		**	sense command
@@ -7991,6 +9599,7 @@
 		/*
 		**	sense data
 		*/
+		bzero(cmd->sense_buffer, sizeof(cmd->sense_buffer));
 		cp->phys.sense.addr	=
 				cpu_to_scr(vtobus (&cmd->sense_buffer[0]));
 		cp->phys.sense.size	=
@@ -7999,30 +9608,22 @@
 		/*
 		**	requeue the command.
 		*/
-		startp = cpu_to_scr(NCB_SCRIPTH_PHYS (np, sdata_in));
+		startp = NCB_SCRIPTH_PHYS (np, sdata_in);
 
-		cp->phys.header.savep	= startp;
-		cp->phys.header.goalp	= startp + 24;
-		cp->phys.header.lastp	= startp;
-		cp->phys.header.wgoalp	= startp + 24;
-		cp->phys.header.wlastp	= startp;
+		cp->phys.header.savep	= cpu_to_scr(startp);
+		cp->phys.header.goalp	= cpu_to_scr(startp + 16);
+		cp->phys.header.lastp	= cpu_to_scr(startp);
+		cp->phys.header.wgoalp	= cpu_to_scr(startp + 16);
+		cp->phys.header.wlastp	= cpu_to_scr(startp);
 
-		cp->host_status = HS_BUSY;
+		cp->host_status	= cp->nego_status ? HS_NEGOTIATE : HS_BUSY;
 		cp->scsi_status = S_ILLEGAL;
-		cp->host_flags	= 0;
-		cp->auto_sense	= s_status;
+		cp->host_flags	= HF_AUTO_SENSE;
 
 		cp->phys.header.go.start =
 			cpu_to_scr(NCB_SCRIPT_PHYS (np, select));
 
 		/*
-		**	Select without ATN for quirky devices.
-		*/
-		if (tp->quirks & QUIRK_NOMSG)
-			cp->phys.header.go.start =
-			cpu_to_scr(NCB_SCRIPTH_PHYS (np, select_no_atn));
-
-		/*
 		**	If lp not yet allocated, requeue the command.
 		*/
 		if (!lp)
@@ -8039,507 +9640,1534 @@
 	return;
 }
 
-
-/*==========================================================
+/*----------------------------------------------------------
 **
-**
-**      ncr chip exception handler for programmed interrupts.
-**
-**
-**==========================================================
+**	After a device has accepted some management message 
+**	as BUS DEVICE RESET, ABORT TASK, etc ..., or when 
+**	a device signals a UNIT ATTENTION condition, some 
+**	tasks are thrown away by the device. We are required 
+**	to reflect that on our tasks list since the device 
+**	will never complete these tasks.
+**
+**	This function completes all disconnected CCBs for a 
+**	given target that matches the following criteria:
+**	- lun=-1  means any logical UNIT otherwise a given one.
+**	- task=-1 means any task, otherwise a given one.
+**----------------------------------------------------------
 */
-
-static int ncr_show_msg (u_char * msg)
-{
-	u_char i;
-	printk ("%x",*msg);
-	if (*msg==M_EXTENDED) {
-		for (i=1;i<8;i++) {
-			if (i-1>msg[1]) break;
-			printk ("-%x",msg[i]);
-		};
-		return (i+1);
-	} else if ((*msg & 0xf0) == 0x20) {
-		printk ("-%x",msg[1]);
-		return (2);
-	};
-	return (1);
-}
-
-
-void ncr_int_sir (ncb_p np)
+static int ncr_clear_tasks(ncb_p np, u_char hsts, 
+			   int target, int lun, int task)
 {
-	u_char scntl3;
-	u_char chg, ofs, per, fak, wide;
-	u_char num = INB (nc_dsps);
-	ccb_p	cp=0;
-	u_long	dsa    = INL (nc_dsa);
-	u_char	target = INB (nc_sdid) & 0x0f;
-	tcb_p	tp     = &np->target[target];
-
-	if (DEBUG_FLAGS & DEBUG_TINY) printk ("I#%d", num);
+	int i = 0;
+	ccb_p cp;
 
-	switch (num) {
-	case SIR_SEL_ATN_NO_MSG_OUT:
-		/*
-		**	The device didn't go to MSG OUT phase after having 
-		**	been selected with ATN. We donnot want to handle 
-		**	that.
-		*/
-		printk ("%s:%d: No MSG OUT phase after selection with ATN.\n",
-			ncr_name (np), target);
-		goto out_stuck;
-	case SIR_RESEL_NO_MSG_IN:
-	case SIR_RESEL_NO_IDENTIFY:
-		/*
-		**	If devices reselecting without sending an IDENTIFY 
-		**	message still exist, this should help.
-		**	We just assume lun=0, 1 CCB, no tag.
-		*/
-		if (tp->l0p) { 
-			OUTL (nc_dsa, scr_to_cpu(tp->l0p->tasktbl[0]));
-			OUTL (nc_dsp, NCB_SCRIPT_PHYS (np, resel_go));
-			return;
-		}
-	case SIR_RESEL_BAD_LUN:
-		np->msgout[0] = M_RESET;
-		goto out;
-	case SIR_RESEL_BAD_I_T_L:
-		np->msgout[0] = M_ABORT;
-		goto out;
-	case SIR_RESEL_BAD_I_T_L_Q:
-		np->msgout[0] = M_ABORT_TAG;
-		goto out;
-	case SIR_RESEL_ABORTED:
-		np->lastmsg = np->msgout[0];
-		np->msgout[0] = M_NOOP;
-		printk ("%s:%d: message %d sent on bad reselection.\n",
-			ncr_name (np), target, np->lastmsg);
-		goto out;
-	case SIR_MSG_OUT_DONE:
-		np->lastmsg = np->msgout[0];
-		np->msgout[0] = M_NOOP;
-		/* Should we really care of that */
-		if (np->lastmsg == M_PARITY || np->lastmsg == M_ID_ERROR)
-			OUTOFFB (HF_PRT, HF_PAR_ERR);
-		goto out;
-	case SIR_BAD_STATUS:
-		cp = ncr_ccb_from_dsa(np, dsa);
-		if (!cp)
-			goto out;
-		ncr_sir_to_redo(np, num, cp);
-		return;
-	default:
-		/*
-		**	lookup the ccb
-		*/
-		cp = ncr_ccb_from_dsa(np, dsa);
-		if (!cp)
-			goto out;
+	for (cp = np->ccbc; cp; cp = cp->link_ccb) {
+		if (cp->host_status != HS_DISCONNECT)
+			continue;
+		if (cp->target != target)
+			continue;
+		if (lun != -1 && cp->lun != lun)
+			continue;
+		if (task != -1 && cp->tag != NO_TAG && cp->scsi_smsg[2] != task)
+			continue;
+		cp->host_status = hsts;
+		cp->scsi_status = S_ILLEGAL;
+		ncr_complete(np, cp);
+		++i;
 	}
+	return i;
+}
 
-	switch (num) {
-/*-----------------------------------------------------------------------------
-**
-**	Was Sie schon immer ueber transfermode negotiation wissen wollten ...
-**
-**	We try to negotiate sync and wide transfer only after
-**	a successfull inquire command. We look at byte 7 of the
-**	inquire data to determine the capabilities of the target.
-**
-**	When we try to negotiate, we append the negotiation message
-**	to the identify and (maybe) simple tag message.
-**	The host status field is set to HS_NEGOTIATE to mark this
-**	situation.
+/*==========================================================
 **
-**	If the target doesn't answer this message immidiately
-**	(as required by the standard), the SIR_NEGO_FAIL interrupt
-**	will be raised eventually.
-**	The handler removes the HS_NEGOTIATE status, and sets the
-**	negotiated value to the default (async / nowide).
+**	ncr chip handler for TASKS recovery.
 **
-**	If we receive a matching answer immediately, we check it
-**	for validity, and set the values.
+**==========================================================
 **
-**	If we receive a Reject message immediately, we assume the
-**	negotiation has failed, and fall back to standard values.
+**	We cannot safely abort a command, while the SCRIPTS 
+**	processor is running, since we just would be in race 
+**	with it.
 **
-**	If we receive a negotiation message while not in HS_NEGOTIATE
-**	state, it's a target initiated negotiation. We prepare a
-**	(hopefully) valid answer, set our parameters, and send back 
-**	this answer to the target.
+**	As long as we have tasks to abort, we keep the SEM 
+**	bit set in the ISTAT. When this bit is set, the 
+**	SCRIPTS processor interrupts (SIR_SCRIPT_STOPPED) 
+**	each time it enters the scheduler.
 **
-**	If the target doesn't fetch the answer (no message out phase),
-**	we assume the negotiation has failed, and fall back to default
-**	settings.
+**	If we have to reset a target, clear tasks of a unit,
+**	or to perform the abort of a disconnected job, we 
+**	restart the SCRIPTS for selecting the target. Once 
+**	selected, the SCRIPTS interrupts (SIR_TARGET_SELECTED).
+**	If it loses arbitration, the SCRIPTS will interrupt again 
+**	the next time it will enter its scheduler, and so on ...
 **
-**	When we set the values, we adjust them in all ccbs belonging 
-**	to this target, in the controller's register, and in the "phys"
-**	field of the controller's struct ncb.
+**	On SIR_TARGET_SELECTED, we scan for the more 
+**	appropriate thing to do:
 **
-**	Possible cases:		   hs  sir   msg_in value  send   goto
-**	We try to negotiate:
-**	-> target doesnt't msgin   NEG FAIL  noop   defa.  -      dispatch
-**	-> target rejected our msg NEG FAIL  reject defa.  -      dispatch
-**	-> target answered  (ok)   NEG SYNC  sdtr   set    -      clrack
-**	-> target answered (!ok)   NEG SYNC  sdtr   defa.  REJ--->msg_bad
-**	-> target answered  (ok)   NEG WIDE  wdtr   set    -      clrack
-**	-> target answered (!ok)   NEG WIDE  wdtr   defa.  REJ--->msg_bad
-**	-> any other msgin	   NEG FAIL  noop   defa.  -      dispatch
-**
-**	Target tries to negotiate:
-**	-> incoming message	   --- SYNC  sdtr   set    SDTR   -
-**	-> incoming message	   --- WIDE  wdtr   set    WDTR   -
-**      We sent our answer:
-**	-> target doesn't msgout   --- PROTO ?      defa.  -      dispatch
+**	- If nothing, we just sent a M_ABORT message to the 
+**	  target to get rid of the useless SCSI bus ownership.
+**	  According to the specs, no tasks shall be affected.
+**	- If the target is to be reset, we send it a M_RESET 
+**	  message.
+**	- If a logical UNIT is to be cleared , we send the 
+**	  IDENTIFY(lun) + M_ABORT.
+**	- If an untagged task is to be aborted, we send the 
+**	  IDENTIFY(lun) + M_ABORT.
+**	- If a tagged task is to be aborted, we send the 
+**	  IDENTIFY(lun) + task attributes + M_ABORT_TAG.
 **
-**-----------------------------------------------------------------------------
+**	Once our 'kiss of death' :) message has been accepted 
+**	by the target, the SCRIPTS interrupts again 
+**	(SIR_ABORT_SENT). On this interrupt, we complete 
+**	all the CCBs that should have been aborted by the 
+**	target according to our message.
+**	
+**----------------------------------------------------------
 */
-
-	case SIR_NEGO_FAILED:
-		/*-------------------------------------------------------
-		**
-		**	Negotiation failed.
-		**	Target doesn't send an answer message,
-		**	or target rejected our message.
-		**
-		**      Remove negotiation request.
-		**
-		**-------------------------------------------------------
-		*/
-		OUTB (HS_PRT, HS_BUSY);
+static void ncr_sir_task_recovery(ncb_p np, int num)
+{
+	ccb_p cp;
+	tcb_p tp;
+	int target=-1, lun=-1, task;
+	int i, k;
+	u_char *p;
 
-		/* fall through */
+	switch(num) {
+	/*
+	**	The SCRIPTS processor stopped before starting
+	**	the next command in order to allow us to perform 
+	**	some task recovery.
+	*/
+	case SIR_SCRIPT_STOPPED:
 
-	case SIR_NEGO_PROTO:
-		/*-------------------------------------------------------
-		**
-		**	Negotiation failed.
-		**	Target doesn't fetch the answer message.
-		**
-		**-------------------------------------------------------
+		/*
+		**	Do we have any target to reset or unit to clear ?
 		*/
+		for (i = 0 ; i < MAX_TARGET ; i++) {
+			tp = &np->target[i];
+			if (tp->to_reset || (tp->l0p && tp->l0p->to_clear)) {
+				target = i;
+				break;
+			}
+			if (!tp->lmp)
+				continue;
+			for (k = 1 ; k < MAX_LUN ; k++) {
+				if (tp->lmp[k] && tp->lmp[k]->to_clear) {
+					target	= i;
+					break;
+				}
+			}
+			if (target != -1)
+				break;
+		}
 
-		if (DEBUG_FLAGS & DEBUG_NEGO) {
-			PRINT_ADDR(cp->cmd);
-			printk ("negotiation failed sir=%x status=%x.\n",
-				num, cp->nego_status);
-		};
+		/*
+		**	If not, look at the CCB list for any 
+		**	disconnected CCB to be aborted.
+		*/
+		if (target == -1) {
+			for (cp = np->ccbc; cp; cp = cp->link_ccb) {
+				if (cp->host_status != HS_DISCONNECT)
+					continue;
+				if (cp->to_abort) {
+					target = cp->target;
+					break;
+				}
+			}
+		}
 
 		/*
-		**	any error in negotiation:
-		**	fall back to default mode.
+		**	If some target is to be selected, 
+		**	prepare and start the selection.
 		*/
-		switch (cp->nego_status) {
+		if (target != -1) {
+			tp = &np->target[target];
+			np->abrt_sel.sel_id	= target;
+			np->abrt_sel.sel_scntl3 = tp->wval;
+			np->abrt_sel.sel_sxfer  = tp->sval;
+			np->abrt_sel.sel_scntl4 = tp->uval;
+			OUTL(nc_dsa, vtobus(np));
+			OUTL (nc_dsp, NCB_SCRIPTH_PHYS (np, sel_for_abort));
+			return;
+		}
 
-		case NS_SYNC:
-			ncr_setsync (np, cp, 0, 0xe0);
-			break;
+		/*
+		**	Nothing is to be selected, so we donnot need 
+		**	to synchronize with the SCRIPTS anymore.
+		**	Remove the SEM flag from the ISTAT.
+		*/
+		np->istat_sem = 0;
+		OUTB (nc_istat, SIGP);
+
+		/*
+		**	Now look at CCBs to abort that haven't started yet.
+		**	Remove all those CCBs from the start queue and 
+		**	complete them with appropriate status.
+		**	Btw, the SCRIPTS processor is still stopped, so 
+		**	we are not in race.
+		*/
+		for (cp = np->ccbc; cp; cp = cp->link_ccb) {
+			if (cp->host_status != HS_BUSY &&
+			    cp->host_status != HS_NEGOTIATE)
+				continue;
+			if (!cp->to_abort)
+				continue;
+#ifdef SCSI_NCR_IARB_SUPPORT
+			/*
+			**    If we are using IMMEDIATE ARBITRATION, we donnot 
+			**    want to cancel the last queued CCB, since the 
+			**    SCRIPTS may have anticipated the selection.
+			*/
+			if (cp == np->last_cp) {
+				cp->to_abort = 0;
+				continue;
+			}
+#endif
+			/*
+			**	Compute index of next position in the start 
+			**	queue the SCRIPTS will schedule.
+			*/
+			i = (INL (nc_scratcha) - vtobus(np->squeue)) / 4;
 
-		case NS_WIDE:
-			ncr_setwide (np, cp, 0, 0);
-			break;
+			/*
+			**	Remove the job from the start queue.
+			*/
+			k = -1;
+			while (1) {
+				if (i == np->squeueput)
+					break;
+				if (k == -1) {		/* Not found yet */
+					if (cp == ncr_ccb_from_dsa(np,
+						     scr_to_cpu(np->squeue[i])))
+						k = i;	/* Found */
+				}
+				else {
+					/*
+					**    Once found, we have to move 
+					**    back all jobs by 1 position.
+					*/
+					np->squeue[k] = np->squeue[i];
+					k += 2;
+					if (k >= MAX_START*2)
+						k = 0;
+				}
 
-		};
-		np->msgin [0] = M_NOOP;
-		np->msgout[0] = M_NOOP;
-		cp->nego_status = 0;
+				i += 2;
+				if (i >= MAX_START*2)
+					i = 0;
+			}
+			assert(k != -1);
+			if (k != 1) {
+				np->squeue[k] = np->squeue[i]; /* Idle task */
+				np->squeueput = k; /* Start queue pointer */
+				cp->host_status = HS_ABORTED;
+				cp->scsi_status = S_ILLEGAL;
+				ncr_complete(np, cp);
+			}
+		}
 		break;
+	/*
+	**	The SCRIPTS processor has selected a target 
+	**	we may have some manual recovery to perform for.
+	*/
+	case SIR_TARGET_SELECTED:
+		target = (INB (nc_sdid) & 0xf);
+		tp = &np->target[target];
+
+		np->abrt_tbl.addr = vtobus(np->abrt_msg);
 
-	case SIR_NEGO_SYNC:
 		/*
-		**	Synchronous request message received.
+		**	If the target is to be reset, prepare a 
+		**	M_RESET message and clear the to_reset flag 
+		**	since we donnot expect this operation to fail.
 		*/
+		if (tp->to_reset) {
+			np->abrt_msg[0] = M_RESET;
+			np->abrt_tbl.size = 1;
+			tp->to_reset = 0;
+			break;
+		}
 
-		if (DEBUG_FLAGS & DEBUG_NEGO) {
-			PRINT_ADDR(cp->cmd);
-			printk ("sync msgin: ");
-			(void) ncr_show_msg (np->msgin);
-			printk (".\n");
-		};
+		/*
+		**	Otherwise, look for some logical unit to be cleared.
+		*/
+		if (tp->l0p && tp->l0p->to_clear)
+			lun = 0;
+		else if (tp->lmp) {
+			for (k = 1 ; k < MAX_LUN ; k++) {
+				if (tp->lmp[k] && tp->lmp[k]->to_clear) {
+					lun = k;
+					break;
+				}
+			}
+		}
 
 		/*
-		**	get requested values.
+		**	If a logical unit is to be cleared, prepare 
+		**	an IDENTIFY(lun) + ABORT MESSAGE.
 		*/
+		if (lun != -1) {
+			lcb_p lp = ncr_lp(np, tp, lun);
+			lp->to_clear = 0; /* We donnot expect to fail here */
+			np->abrt_msg[0] = M_IDENTIFY | lun;
+			np->abrt_msg[1] = M_ABORT;
+			np->abrt_tbl.size = 2;
+			break;
+		}
 
-		chg = 0;
-		per = np->msgin[3];
-		ofs = np->msgin[4];
-		if (ofs==0) per=255;
+		/*
+		**	Otherwise, look for some disconnected job to 
+		**	abort for this target.
+		*/
+		for (cp = np->ccbc; cp; cp = cp->link_ccb) {
+			if (cp->host_status != HS_DISCONNECT)
+				continue;
+			if (cp->target != target)
+				continue;
+			if (cp->to_abort)
+				break;
+		}
 
 		/*
-		**      if target sends SDTR message,
-		**	      it CAN transfer synch.
+		**	If we have none, probably since the device has 
+		**	completed the command before we won abitration,
+		**	send a M_ABORT message without IDENTIFY.
+		**	According to the specs, the device must just 
+		**	disconnect the BUS and not abort any task.
 		*/
+		if (!cp) {
+			np->abrt_msg[0] = M_ABORT;
+			np->abrt_tbl.size = 1;
+			break;
+		}
 
-		if (ofs)
-			tp->inq_byte7 |= INQ7_SYNC;
+		/*
+		**	We have some task to abort.
+		**	Set the IDENTIFY(lun)
+		*/
+		np->abrt_msg[0] = M_IDENTIFY | cp->lun;
 
 		/*
-		**	check values against driver limits.
+		**	If we want to abort an untagged command, we 
+		**	will send a IDENTIFY + M_ABORT.
+		**	Otherwise (tagged command), we will send 
+		**	a IDENTITFY + task attributes + ABORT TAG.
 		*/
+		if (cp->tag == NO_TAG) {
+			np->abrt_msg[1] = M_ABORT;
+			np->abrt_tbl.size = 2;
+		}
+		else {
+			np->abrt_msg[1] = cp->scsi_smsg[1];
+			np->abrt_msg[2] = cp->scsi_smsg[2];
+			np->abrt_msg[3] = M_ABORT_TAG;
+			np->abrt_tbl.size = 4;
+		}
+		cp->to_abort = 0; /* We donnot expect to fail here */
+		break;
 
-		if (per < np->minsync)
-			{chg = 1; per = np->minsync;}
-		if (per < tp->minsync)
-			{chg = 1; per = tp->minsync;}
-		if (ofs > tp->maxoffs)
-			{chg = 1; ofs = tp->maxoffs;}
+	/*
+	**	The target has accepted our message and switched 
+	**	to BUS FREE phase as we expected.
+	*/
+	case SIR_ABORT_SENT:
+		target = (INB (nc_sdid) & 0xf);
+		tp = &np->target[target];
+		
+		/*
+		**	If we didn't abort anything, leave here.
+		*/
+		if (np->abrt_msg[0] == M_ABORT)
+			break;
 
 		/*
-		**	Check against controller limits.
+		**	If we sent a M_RESET, then a hardware reset has 
+		**	been performed by the target.
+		**	- Reset everything to async 8 bit
+		**	- Tell ourself to negotiate next time :-)
+		**	- Prepare to clear all disconnected CCBs for 
+		**	  this target from our task list (lun=task=-1)
 		*/
-		fak	= 7;
-		scntl3	= 0;
-		if (ofs != 0) {
-			ncr_getsync(np, per, &fak, &scntl3);
-			if (fak > 7) {
-				chg = 1;
-				ofs = 0;
-			}
-		}
-		if (ofs == 0) {
-			fak	= 7;
-			per	= 0;
-			scntl3	= 0;
-			tp->minsync = 0;
+		lun = -1;
+		task = -1;
+		if (np->abrt_msg[0] == M_RESET) {
+			tp->sval = 0;
+			tp->wval = np->rv_scntl3;
+			tp->uval = np->rv_scntl4; 
+			ncr_set_sync_wide_status(np, target);
+			ncr_negotiate(np, tp);
 		}
 
-		if (DEBUG_FLAGS & DEBUG_NEGO) {
-			PRINT_ADDR(cp->cmd);
-			printk ("sync: per=%d scntl3=0x%x ofs=%d fak=%d chg=%d.\n",
-				per, scntl3, ofs, fak, chg);
+		/*
+		**	Otherwise, check for the LUN and TASK(s) 
+		**	concerned by the cancelation.
+		**	If it is not ABORT_TAG then it is CLEAR_QUEUE 
+		**	or an ABORT message :-)
+		*/
+		else {
+			lun = np->abrt_msg[0] & 0x3f;
+			if (np->abrt_msg[1] == M_ABORT_TAG)
+				task = np->abrt_msg[2];
 		}
 
-		if (INB (HS_PRT) == HS_NEGOTIATE) {
-			OUTB (HS_PRT, HS_BUSY);
-			switch (cp->nego_status) {
+		/*
+		**	Complete all the CCBs the device should have 
+		**	aborted due to our 'kiss of death' message.
+		*/
+		(void) ncr_clear_tasks(np, HS_ABORTED, target, lun, task);
+		break;
 
-			case NS_SYNC:
-				/*
-				**      This was an answer message
-				*/
-				if (chg) {
-					/*
-					**	Answer wasn't acceptable.
-					*/
-					ncr_setsync (np, cp, 0, 0xe0);
-					OUTL (nc_dsp, NCB_SCRIPT_PHYS (np, msg_bad));
-				} else {
-					/*
-					**	Answer is ok.
-					*/
-					ncr_setsync (np, cp, scntl3, (fak<<5)|ofs);
-					OUTL (nc_dsp, NCB_SCRIPT_PHYS (np, clrack));
-				};
-				return;
+	/*
+	**	We have performed a auto-sense that succeeded.
+	**	If the device reports a UNIT ATTENTION condition 
+	**	due to a RESET condition, we must complete all 
+	**	disconnect CCBs for this unit since the device 
+	**	shall have thrown them away.
+	**	Since I haven't time to guess what the specs are 
+	**	expecting for other UNIT ATTENTION conditions, I 
+	**	decided to only care about RESET conditions. :)
+	*/
+	case SIR_AUTO_SENSE_DONE:
+		cp = ncr_ccb_from_dsa(np, INL (nc_dsa));
+		p  = &cp->cmd->sense_buffer[0];
 
-			case NS_WIDE:
-				ncr_setwide (np, cp, 0, 0);
-				break;
-			};
-		};
+		if (p[0] != 0x70 || p[2] != 0x6 || p[12] != 0x29)
+			break;
+		(void) ncr_clear_tasks(np, HS_RESET, cp->target, cp->lun, -1);
+		break;
+	}
 
-		/*
-		**	It was a request. Set value and
-		**      prepare an answer message
-		*/
+	/*
+	**	Print to the log the message we intend to send.
+	*/
+	if (num == SIR_TARGET_SELECTED) {
+		PRINT_TARGET(np, target);
+		ncr_printl_hex("control msgout:", np->abrt_msg,
+			      np->abrt_tbl.size);
+		np->abrt_tbl.size = cpu_to_scr(np->abrt_tbl.size);
+	}
 
-		ncr_setsync (np, cp, scntl3, (fak<<5)|ofs);
+	/*
+	**	Let the SCRIPTS processor continue.
+	*/
+	OUTONB (nc_dcntl, (STD|NOCOM));
+}
 
-		np->msgout[0] = M_EXTENDED;
-		np->msgout[1] = 3;
-		np->msgout[2] = M_X_SYNC_REQ;
-		np->msgout[3] = per;
-		np->msgout[4] = ofs;
 
-		cp->nego_status = NS_SYNC;
+/*==========================================================
+**
+**	Gérard's alchemy:) that deals with with the data 
+**	pointer for both MDP and the residual calculation.
+**
+**==========================================================
+**
+**	I didn't want to bloat the code by more than 200 
+**	lignes for the handling of both MDP and the residual.
+**	This has been achieved by using a data pointer 
+**	representation consisting in an index in the data 
+**	array (dp_sg) and a negative offset (dp_ofs) that 
+**	have the following meaning:
+**
+**	- dp_sg = MAX_SCATTER
+**	  we are at the end of the data script.
+**	- dp_sg < MAX_SCATTER
+**	  dp_sg points to the next entry of the scatter array 
+**	  we want to transfer.
+**	- dp_ofs < 0
+**	  dp_ofs represents the residual of bytes of the 
+**	  previous entry scatter entry we will send first.
+**	- dp_ofs = 0
+**	  no residual to send first.
+**
+**	The function ncr_evaluate_dp() accepts an arbitray 
+**	offset (basically from the MDP message) and returns 
+**	the corresponding values of dp_sg and dp_ofs.
+**
+**----------------------------------------------------------
+*/
 
-		if (DEBUG_FLAGS & DEBUG_NEGO) {
-			PRINT_ADDR(cp->cmd);
-			printk ("sync msgout: ");
-			(void) ncr_show_msg (np->msgout);
-			printk (".\n");
-		}
+static int ncr_evaluate_dp(ncb_p np, ccb_p cp, u_int32 scr, int *ofs)
+{
+	u_int32	dp_scr;
+	int	dp_ofs, dp_sg, dp_sgmin;
+	int	tmp;
+	struct pm_ctx *pm;
 
-		if (!ofs) {
-			OUTL (nc_dsp, NCB_SCRIPT_PHYS (np, msg_bad));
-			return;
+	/*
+	**	Compute the resulted data pointer in term of a script 
+	**	address within some DATA script and a signed byte offset.
+	*/
+	dp_scr = scr;
+	dp_ofs = *ofs;
+	if	(dp_scr == NCB_SCRIPT_PHYS (np, pm0_data))
+		pm = &cp->phys.pm0;
+	else if (dp_scr == NCB_SCRIPT_PHYS (np, pm1_data))
+		pm = &cp->phys.pm1;
+	else
+		pm = 0;
+
+	if (pm) {
+		dp_scr  = pm->ret;
+		dp_ofs -= pm->sg.size;
+	}
+
+	/*
+	**	Deduce the index of the sg entry.
+	**	Keep track of the index of the first valid entry.
+	**	If result is dp_sg = MAX_SCATTER, then we are at the 
+	**	end of the data.
+	*/
+	tmp = scr_to_cpu(cp->phys.header.goalp);
+	dp_sg = MAX_SCATTER - (tmp - 8 - (int)dp_scr) / (SCR_SG_SIZE*4);
+	dp_sgmin = MAX_SCATTER - cp->segments;
+
+	/*
+	**	Move to the sg entry the data pointer belongs to.
+	**
+	**	If we are inside the data area, we expect result to be:
+	**
+	**	Either,
+	**	    dp_ofs = 0 and dp_sg is the index of the sg entry
+	**	    the data pointer belongs to (or the end of the data)
+	**	Or,
+	**	    dp_ofs < 0 and dp_sg is the index of the sg entry 
+	**	    the data pointer belongs to + 1.
+	*/
+	if (dp_ofs < 0) {
+		int n;
+		while (dp_sg > dp_sgmin) {
+			--dp_sg;
+			tmp = scr_to_cpu(cp->phys.data[dp_sg].size);
+			n = dp_ofs + (tmp & 0xffffff);
+			if (n > 0) {
+				++dp_sg;
+				break;
+			}
+			dp_ofs = n;
+		}
+	}
+	else if (dp_ofs > 0) {
+		while (dp_sg < MAX_SCATTER) {
+			++dp_sg;
+			tmp = scr_to_cpu(cp->phys.data[dp_sg].size);
+			dp_ofs -= (tmp & 0xffffff);
+			if (dp_ofs <= 0)
+				break;
 		}
-		np->msgin [0] = M_NOOP;
+	}
 
-		break;
+	/*
+	**	Make sure the data pointer is inside the data area.
+	**	If not, return some error.
+	*/
+	if	(dp_sg < dp_sgmin || (dp_sg == dp_sgmin && dp_ofs < 0))
+		goto out_err;
+	else if	(dp_sg > MAX_SCATTER || (dp_sg == MAX_SCATTER && dp_ofs > 0))
+		goto out_err;
 
-	case SIR_NEGO_WIDE:
-		/*
-		**	Wide request message received.
-		*/
-		if (DEBUG_FLAGS & DEBUG_NEGO) {
-			PRINT_ADDR(cp->cmd);
-			printk ("wide msgin: ");
-			(void) ncr_show_msg (np->msgin);
-			printk (".\n");
-		};
+	/*
+	**	Save the extreme pointer if needed.
+	*/
+	if (dp_sg > cp->ext_sg ||
+            (dp_sg == cp->ext_sg && dp_ofs < cp->ext_ofs)) {
+		cp->ext_sg  = dp_sg;
+		cp->ext_ofs = dp_ofs;
+	}
 
-		/*
-		**	get requested values.
-		*/
+	/*
+	**	Return data.
+	*/
+	*ofs = dp_ofs;
+	return dp_sg;
 
-		chg  = 0;
-		wide = np->msgin[3];
+out_err:
+	return -1;
+}
 
-		/*
-		**      if target sends WDTR message,
-		**	      it CAN transfer wide.
-		*/
+/*==========================================================
+**
+**	ncr chip handler for MODIFY DATA POINTER MESSAGE
+**
+**==========================================================
+**
+**	We also call this function on IGNORE WIDE RESIDUE 
+**	messages that do not match a SWIDE full condition.
+**	Btw, we assume in that situation that such a message 
+**	is equivalent to a MODIFY DATA POINTER (offset=-1).
+**
+**----------------------------------------------------------
+*/
 
-		if (wide)
-			tp->inq_byte7 |= INQ7_WIDE16;
+static void ncr_modify_dp(ncb_p np, tcb_p tp, ccb_p cp, int ofs)
+{
+	int dp_ofs	= ofs;
+	u_int32 dp_scr	= INL (nc_temp);
+	u_int32	dp_ret;
+	u_char	hflags;
+	int	dp_sg;
+	struct pm_ctx *pm;
 
-		/*
-		**	check values against driver limits.
-		*/
+	/*
+	**	Not supported for auto_sense;
+	*/
+	if (cp->host_flags & HF_AUTO_SENSE)
+		goto out_reject;
 
-		if (wide > tp->usrwide)
-			{chg = 1; wide = tp->usrwide;}
+	/*
+	**	Apply our alchemy:) (see comments in ncr_evaluate_dp()), 
+	**	to the resulted data pointer.
+	*/
+	dp_sg = ncr_evaluate_dp(np, cp, dp_scr, &dp_ofs);
+	if (dp_sg < 0)
+		goto out_reject;
 
-		if (DEBUG_FLAGS & DEBUG_NEGO) {
-			PRINT_ADDR(cp->cmd);
-			printk ("wide: wide=%d chg=%d.\n", wide, chg);
+	/*
+	**	And our alchemy:) allows to easily calculate the data 
+	**	script address we want to return for the next data phase.
+	*/
+	dp_ret = cpu_to_scr(cp->phys.header.goalp);
+	dp_ret = dp_ret - 8 - (MAX_SCATTER - dp_sg) * (SCR_SG_SIZE*4);
+
+	/*
+	**	If offset / scatter entry is zero we donnot need 
+	**	a context for the new current data pointer.
+	*/
+	if (dp_ofs == 0) {
+		dp_scr = dp_ret;
+		goto out_ok;
+	}
+
+	/*
+	**	Get a context for the new current data pointer.
+	*/
+	hflags = INB (HF_PRT);
+
+	if (hflags & HF_DP_SAVED)
+		hflags ^= HF_ACT_PM;
+
+	if (!(hflags & HF_ACT_PM)) {
+		pm  = &cp->phys.pm0;
+		dp_scr = NCB_SCRIPT_PHYS (np, pm0_data);
+	}
+	else {
+		pm = &cp->phys.pm1;
+		dp_scr = NCB_SCRIPT_PHYS (np, pm1_data);
+	}
+
+	hflags &= ~(HF_DP_SAVED);
+
+	OUTB (HF_PRT, hflags);
+
+	/*
+	**	Set up the new current data pointer.
+	**	ofs < 0 there, and for the next data phase, we 
+	**	want to transfer part of the data of the sg entry 
+	**	corresponding to index dp_sg-1 prior to returning 
+	**	to the main data script.
+	*/
+	pm->ret = cpu_to_scr(dp_ret);
+	pm->sg.addr = cp->phys.data[dp_sg-1].addr + dp_ofs;
+	pm->sg.size = cp->phys.data[dp_sg-1].size - dp_ofs;
+
+out_ok:
+	OUTL (nc_temp, dp_scr);
+	OUTL (nc_dsp, NCB_SCRIPT_PHYS (np, clrack));
+	return;
+
+out_reject:
+	OUTL (nc_dsp, NCB_SCRIPTH_PHYS (np, msg_bad));
+}
+
+
+/*==========================================================
+**
+**	ncr chip calculation of the data residual.
+**
+**==========================================================
+**
+**	As I used to say, the requirement of data residual 
+**	in SCSI is broken, useless and cannot be achieved 
+**	without huge complexity.
+**	But most OSes and even the official CAM require it.
+**	When stupidity happens to be so widely spread inside 
+**	a community, it gets hard to convince.
+**
+**	Anyway, I don't care, since I am not going to use 
+**	any software that considers this data residual as 
+**	a relevant information. :)
+**	
+**----------------------------------------------------------
+*/
+
+static int ncr_compute_residual(ncb_p np, ccb_p cp)
+{
+	int dp_sg, dp_sgmin, resid, tmp;
+	int dp_ofs = 0;
+
+	/*
+	**	Should have been checked by the caller.
+	*/
+	if (cp->phys.header.lastp == cp->phys.header.goalp)
+		return 0;
+
+	/*
+	**	If the last data pointer is data_io (direction 
+	**	unknown), then no data transfer should have 
+	**	taken place.
+	*/
+	if (cp->phys.header.lastp == NCB_SCRIPTH_PHYS (np, data_io))
+		return -cp->data_len;
+
+	/*
+	**	If the device asked for more data than available, 
+	**	return a positive residual value.
+	*/
+	if (cp->phys.extra_bytes)
+		return scr_to_cpu(cp->phys.extra_bytes);
+
+	/*
+	**	Evaluate the pointer saved on message COMPLETE.
+	**	According to our alchemy:), the extreme data 
+	**	pointer will also be updated if needed.
+	**	On error, assume no data transferred (this may 
+	**	happen if the data direction is unknown).
+	*/
+	tmp = cpu_to_scr(cp->phys.header.lastp);
+	if (ncr_evaluate_dp(np, cp, tmp, &dp_ofs) < 0)
+		return -cp->data_len;
+
+	/*
+	**	We are now full comfortable in the computation 
+	**	of the data residual (2's complement).
+	*/
+	dp_sgmin = MAX_SCATTER - cp->segments;
+	resid = cp->ext_ofs;
+	for (dp_sg = cp->ext_sg; dp_sg < MAX_SCATTER; ++dp_sg) {
+		tmp = scr_to_cpu(cp->phys.data[dp_sg].size);
+		resid -= (tmp & 0xffffff);
+	}
+
+	/*
+	**	Hopefully, the result is not too wrong.
+	*/
+	return resid;
+}
+
+/*==========================================================
+**
+**	Print out the containt of a SCSI message.
+**
+**==========================================================
+*/
+
+static int ncr_show_msg (u_char * msg)
+{
+	u_char i;
+	printk ("%x",*msg);
+	if (*msg==M_EXTENDED) {
+		for (i=1;i<8;i++) {
+			if (i-1>msg[1]) break;
+			printk ("-%x",msg[i]);
+		};
+		return (i+1);
+	} else if ((*msg & 0xf0) == 0x20) {
+		printk ("-%x",msg[1]);
+		return (2);
+	};
+	return (1);
+}
+
+static void ncr_print_msg (ccb_p cp, char *label, u_char *msg)
+{
+	if (cp)
+		PRINT_ADDR(cp->cmd);
+	if (label)
+		printk ("%s: ", label);
+
+	(void) ncr_show_msg (msg);
+	printk (".\n");
+}
+
+/*===================================================================
+**
+**	Negotiation for WIDE and SYNCHRONOUS DATA TRANSFER.
+**
+**===================================================================
+**
+**	Was Sie schon immer ueber transfermode negotiation wissen wollten ...
+**
+**	We try to negotiate sync and wide transfer only after
+**	a successfull inquire command. We look at byte 7 of the
+**	inquire data to determine the capabilities of the target.
+**
+**	When we try to negotiate, we append the negotiation message
+**	to the identify and (maybe) simple tag message.
+**	The host status field is set to HS_NEGOTIATE to mark this
+**	situation.
+**
+**	If the target doesn't answer this message immediately
+**	(as required by the standard), the SIR_NEGO_FAILED interrupt
+**	will be raised eventually.
+**	The handler removes the HS_NEGOTIATE status, and sets the
+**	negotiated value to the default (async / nowide).
+**
+**	If we receive a matching answer immediately, we check it
+**	for validity, and set the values.
+**
+**	If we receive a Reject message immediately, we assume the
+**	negotiation has failed, and fall back to standard values.
+**
+**	If we receive a negotiation message while not in HS_NEGOTIATE
+**	state, it's a target initiated negotiation. We prepare a
+**	(hopefully) valid answer, set our parameters, and send back 
+**	this answer to the target.
+**
+**	If the target doesn't fetch the answer (no message out phase),
+**	we assume the negotiation has failed, and fall back to default
+**	settings (SIR_NEGO_PROTO interrupt).
+**
+**	When we set the values, we adjust them in all ccbs belonging 
+**	to this target, in the controller's register, and in the "phys"
+**	field of the controller's struct ncb.
+**
+**---------------------------------------------------------------------
+*/
+
+/*==========================================================
+**
+**	ncr chip handler for SYNCHRONOUS DATA TRANSFER 
+**	REQUEST (SDTR) message.
+**
+**==========================================================
+**
+**	Read comments above.
+**
+**----------------------------------------------------------
+*/
+static void ncr_sync_nego(ncb_p np, tcb_p tp, ccb_p cp)
+{
+	u_char	scntl3, scntl4;
+	u_char	chg, ofs, per, fak;
+
+	/*
+	**	Synchronous request message received.
+	*/
+
+	if (DEBUG_FLAGS & DEBUG_NEGO) {
+		ncr_print_msg(cp, "sync msg in", np->msgin);
+	};
+
+	/*
+	**	get requested values.
+	*/
+
+	chg = 0;
+	per = np->msgin[3];
+	ofs = np->msgin[4];
+	if (ofs==0) per=255;
+
+	/*
+	**      if target sends SDTR message,
+	**	      it CAN transfer synch.
+	*/
+
+	if (ofs)
+		tp->inq_byte7 |= INQ7_SYNC;
+
+	/*
+	**	check values against driver limits.
+	*/
+
+	if (per < np->minsync)
+		{chg = 1; per = np->minsync;}
+	if (per < tp->minsync)
+		{chg = 1; per = tp->minsync;}
+	if (ofs > tp->maxoffs)
+		{chg = 1; ofs = tp->maxoffs;}
+
+	/*
+	**	Check against controller limits.
+	*/
+	fak	= 7;
+	scntl3	= 0;
+	scntl4  = 0;
+	if (ofs != 0) {
+		ncr_getsync(np, per, &fak, &scntl3);
+		if (fak > 7) {
+			chg = 1;
+			ofs = 0;
+		}
+	}
+	if (ofs == 0) {
+		fak	= 7;
+		per	= 0;
+		scntl3	= 0;
+		scntl4  = 0;
+		tp->minsync = 0;
+	}
+
+	if (DEBUG_FLAGS & DEBUG_NEGO) {
+		PRINT_ADDR(cp->cmd);
+		printk ("sync: per=%d scntl3=0x%x scntl4=0x%x ofs=%d fak=%d chg=%d.\n",
+			per, scntl3, scntl4, ofs, fak, chg);
+	}
+
+	if (INB (HS_PRT) == HS_NEGOTIATE) {
+		OUTB (HS_PRT, HS_BUSY);
+		switch (cp->nego_status) {
+		case NS_SYNC:
+			/*
+			**      This was an answer message
+			*/
+			if (chg) {
+				/*
+				**	Answer wasn't acceptable.
+				*/
+				ncr_setsync (np, cp, 0, 0xe0, 0);
+				OUTL (nc_dsp, NCB_SCRIPTH_PHYS (np, msg_bad));
+			} else {
+				/*
+				**	Answer is ok.
+				*/
+				if (np->device_id != PCI_DEVICE_ID_LSI_53C1010)
+				  ncr_setsync (np, cp, scntl3, (fak<<5)|ofs,0);
+				else
+				  ncr_setsync (np, cp, scntl3, ofs, scntl4);
+
+				OUTL (nc_dsp, NCB_SCRIPT_PHYS (np, clrack));
+			};
+			return;
+
+		case NS_WIDE:
+			ncr_setwide (np, cp, 0, 0);
+			break;
+		};
+	};
+
+	/*
+	**	It was a request. Set value and
+	**      prepare an answer message
+	*/
+
+	if (np->device_id != PCI_DEVICE_ID_LSI_53C1010)
+		ncr_setsync (np, cp, scntl3, (fak<<5)|ofs,0);
+	else
+		ncr_setsync (np, cp, scntl3, ofs, scntl4);
+
+	np->msgout[0] = M_EXTENDED;
+	np->msgout[1] = 3;
+	np->msgout[2] = M_X_SYNC_REQ;
+	np->msgout[3] = per;
+	np->msgout[4] = ofs;
+
+	cp->nego_status = NS_SYNC;
+
+	if (DEBUG_FLAGS & DEBUG_NEGO) {
+		ncr_print_msg(cp, "sync msgout", np->msgout);
+	}
+
+	np->msgin [0] = M_NOOP;
+
+	if (!ofs)
+		OUTL (nc_dsp, NCB_SCRIPTH_PHYS (np, msg_bad));
+	else
+		OUTL (nc_dsp, NCB_SCRIPTH_PHYS (np, sdtr_resp));
+}
+
+/*==========================================================
+**
+**	ncr chip handler for WIDE DATA TRANSFER REQUEST 
+**	(WDTR) message.
+**
+**==========================================================
+**
+**	Read comments above.
+**
+**----------------------------------------------------------
+*/
+static void ncr_wide_nego(ncb_p np, tcb_p tp, ccb_p cp)
+{
+	u_char	chg, wide;
+
+	/*
+	**	Wide request message received.
+	*/
+	if (DEBUG_FLAGS & DEBUG_NEGO) {
+		ncr_print_msg(cp, "wide msgin", np->msgin);
+	};
+
+	/*
+	**	get requested values.
+	*/
+
+	chg  = 0;
+	wide = np->msgin[3];
+
+	/*
+	**      if target sends WDTR message,
+	**	      it CAN transfer wide.
+	*/
+
+	if (wide)
+		tp->inq_byte7 |= INQ7_WIDE16;
+
+	/*
+	**	check values against driver limits.
+	*/
+
+	if (wide > tp->usrwide)
+		{chg = 1; wide = tp->usrwide;}
+
+	if (DEBUG_FLAGS & DEBUG_NEGO) {
+		PRINT_ADDR(cp->cmd);
+		printk ("wide: wide=%d chg=%d.\n", wide, chg);
+	}
+
+	if (INB (HS_PRT) == HS_NEGOTIATE) {
+		OUTB (HS_PRT, HS_BUSY);
+		switch (cp->nego_status) {
+		case NS_WIDE:
+			/*
+			**      This was an answer message
+			*/
+			if (chg) {
+				/*
+				**	Answer wasn't acceptable.
+				*/
+				ncr_setwide (np, cp, 0, 1);
+				OUTL (nc_dsp, NCB_SCRIPTH_PHYS (np, msg_bad));
+			} else {
+				/*
+				**	Answer is ok.
+				*/
+				ncr_setwide (np, cp, wide, 1);
+				OUTL (nc_dsp, NCB_SCRIPT_PHYS (np, clrack));
+			};
+			return;
+
+		case NS_SYNC:
+			ncr_setsync (np, cp, 0, 0xe0, 0);
+			break;
+		};
+	};
+
+	/*
+	**	It was a request, set value and
+	**      prepare an answer message
+	*/
+
+	ncr_setwide (np, cp, wide, 1);
+
+	np->msgout[0] = M_EXTENDED;
+	np->msgout[1] = 2;
+	np->msgout[2] = M_X_WIDE_REQ;
+	np->msgout[3] = wide;
+
+	np->msgin [0] = M_NOOP;
+
+	cp->nego_status = NS_WIDE;
+
+	if (DEBUG_FLAGS & DEBUG_NEGO) {
+		ncr_print_msg(cp, "wide msgout", np->msgout);
+	}
+
+	OUTL (nc_dsp, NCB_SCRIPTH_PHYS (np, wdtr_resp));
+}
+/*==========================================================
+**
+**	ncr chip handler for PARALLEL PROTOCOL REQUEST 
+**	(PPR) message.
+**
+**==========================================================
+**
+**	Read comments above.
+**
+**----------------------------------------------------------
+*/
+static void ncr_ppr_nego(ncb_p np, tcb_p tp, ccb_p cp)
+{
+	u_char	scntl3, scntl4;
+	u_char	chg, ofs, per, fak, wth, dt;
+
+	/*
+	**	PPR message received.
+	*/
+
+	if (DEBUG_FLAGS & DEBUG_NEGO) {
+		ncr_print_msg(cp, "ppr msg in", np->msgin);
+	};
+
+	/*
+	**	get requested values.
+	*/
+
+	chg = 0;
+	per = np->msgin[3];
+	ofs = np->msgin[5];
+	wth = np->msgin[6];
+	dt  = np->msgin[7];
+	if (ofs==0) per=255;
+
+	/*
+	**      if target sends sync (wide),
+	**	      it CAN transfer synch (wide).
+	*/
+
+	if (ofs)
+		tp->inq_byte7 |= INQ7_SYNC;
+
+	if (wth)
+		tp->inq_byte7 |= INQ7_WIDE16;
+
+	/*
+	**	check values against driver limits.
+	*/
+
+	if (wth > tp->usrwide)
+		{chg = 1; wth = tp->usrwide;}
+	if (per < np->minsync)
+		{chg = 1; per = np->minsync;}
+	if (per < tp->minsync)
+		{chg = 1; per = tp->minsync;}
+	if (ofs > tp->maxoffs)
+		{chg = 1; ofs = tp->maxoffs;}
+
+	/*
+	**	Check against controller limits.
+	*/
+	fak	= 7;
+	scntl3	= 0;
+	scntl4  = 0;
+	if (ofs != 0) {
+		scntl4 = dt ? 0x80 : 0;
+		ncr_getsync(np, per, &fak, &scntl3);
+		if (fak > 7) {
+			chg = 1;
+			ofs = 0;
+		}
+	}
+	if (ofs == 0) {
+		fak	= 7;
+		per	= 0;
+		scntl3	= 0;
+		scntl4  = 0;
+		tp->minsync = 0;
+	}
+
+	/*
+	**	If target responds with Ultra 3 speed
+	**	but narrow or not DT, reject.
+	**	If target responds with DT request 
+	**	but not Ultra3 speeds, reject message,
+	**	reset min sync for target to 0x0A and
+	**	set flags to re-negotiate.
+	*/
+
+	if   ((per == 0x09) && ofs && (!wth || !dt))  
+		chg = 1;
+	else if (( (per > 0x09) && dt) ) 
+		chg = 2;
+
+
+	if (DEBUG_FLAGS & DEBUG_NEGO) {
+		PRINT_ADDR(cp->cmd);
+		printk ("ppr: wth=%d per=%d scntl3=0x%x scntl4=0x%x ofs=%d fak=%d chg=%d.\n",
+			wth, per, scntl3, scntl4, ofs, fak, chg);
+	}
+
+	if (INB (HS_PRT) == HS_NEGOTIATE) {
+		OUTB (HS_PRT, HS_BUSY);
+		switch (cp->nego_status) {
+		case NS_PPR:
+			/*
+			**      This was an answer message
+			*/
+			if (chg) {
+				/*
+				**	Answer wasn't acceptable.
+				*/
+				if (chg == 2) {
+					/* Send message reject and reset flags for
+					** host to re-negotiate with min period 0x0A.
+					*/
+					tp->minsync = 0x0A;
+					tp->period = 0;
+					tp->widedone = 0;
+				}
+				ncr_setsyncwide (np, cp, 0, 0xe0, 0, 0);
+				OUTL (nc_dsp, NCB_SCRIPTH_PHYS (np, msg_bad));
+			} else {
+				/*
+				**	Answer is ok.
+				*/
+
+				if (np->device_id != PCI_DEVICE_ID_LSI_53C1010)
+				  ncr_setsyncwide (np, cp, scntl3, (fak<<5)|ofs,0, wth);
+				else
+				  ncr_setsyncwide (np, cp, scntl3, ofs, scntl4, wth);
+
+				OUTL (nc_dsp, NCB_SCRIPT_PHYS (np, clrack));
+				
+			};
+			return;
+
+		case NS_SYNC:
+			ncr_setsync (np, cp, 0, 0xe0, 0);
+			break;
+
+		case NS_WIDE:
+			ncr_setwide (np, cp, 0, 0);
+			break;
+		};
+	};
+
+	/*
+	**	It was a request. Set value and
+	**      prepare an answer message
+	**
+	**	If narrow or not DT and requesting Ultra3
+	**	slow the bus down and force ST. If not
+	**	requesting Ultra3, force ST.
+	**	Max offset is 31=0x1f if ST mode.
+	*/
+
+	if  ((per == 0x09) && ofs && (!wth || !dt)) {
+		per = 0x0A;
+		dt = 0;
+                ofs &= 0x1f;
+	}
+	else if ( per > 0x09)  {
+		dt = 0;
+                ofs &= 0x1f;
+	}
+
+	if (np->device_id != PCI_DEVICE_ID_LSI_53C1010)
+		ncr_setsyncwide (np, cp, scntl3, (fak<<5)|ofs,0, wth);
+	else
+		ncr_setsyncwide (np, cp, scntl3, ofs, scntl4, wth);
+
+	np->msgout[0] = M_EXTENDED;
+	np->msgout[1] = 6;
+	np->msgout[2] = M_X_PPR_REQ;
+	np->msgout[3] = per;
+	np->msgout[4] = 0;		
+	np->msgout[5] = ofs;
+	np->msgout[6] = wth;
+	np->msgout[7] = dt;
+
+	cp->nego_status = NS_PPR;
+
+	if (DEBUG_FLAGS & DEBUG_NEGO) {
+		ncr_print_msg(cp, "ppr msgout", np->msgout);
+	}
+
+	np->msgin [0] = M_NOOP;
+
+	if (!ofs)
+		OUTL (nc_dsp, NCB_SCRIPTH_PHYS (np, msg_bad));
+	else
+		OUTL (nc_dsp, NCB_SCRIPTH_PHYS (np, ppr_resp));
+}
+
+
+
+/*
+**	Reset SYNC or WIDE to default settings.
+**	Called when a negotiation does not succeed either 
+**	on rejection or on protocol error.
+*/
+static void ncr_nego_default(ncb_p np, tcb_p tp, ccb_p cp)
+{
+	/*
+	**	any error in negotiation:
+	**	fall back to default mode.
+	*/
+	switch (cp->nego_status) {
+
+	case NS_SYNC:
+		ncr_setsync (np, cp, 0, 0xe0, 0);
+		break;
+
+	case NS_WIDE:
+		ncr_setwide (np, cp, 0, 0);
+		break;
+
+	case NS_PPR:
+		if (tp->ppr_negotiation == 2)
+			ncr_setsyncwide (np, cp, 0, 0xe0, 0, 0);
+		else
+			tp->ppr_negotiation = 0;
+			ncr_setwide (np, cp, 0, 0);
+		break;
+	};
+	np->msgin [0] = M_NOOP;
+	np->msgout[0] = M_NOOP;
+	cp->nego_status = 0;
+}
+
+/*==========================================================
+**
+**	ncr chip handler for MESSAGE REJECT received for 
+**	a WIDE or SYNCHRONOUS negotiation.
+**
+**	clear the PPR negotiation flag, all future nego.
+**	will be SDTR and WDTR
+**
+**==========================================================
+**
+**	Read comments above.
+**
+**----------------------------------------------------------
+*/
+static void ncr_nego_rejected(ncb_p np, tcb_p tp, ccb_p cp)
+{
+	ncr_nego_default(np, tp, cp);
+	OUTB (HS_PRT, HS_BUSY);
+}
+
+
+/*==========================================================
+**
+**
+**      ncr chip exception handler for programmed interrupts.
+**
+**
+**==========================================================
+*/
+
+void ncr_int_sir (ncb_p np)
+{
+	u_char	num	= INB (nc_dsps);
+	u_long	dsa	= INL (nc_dsa);
+	ccb_p	cp	= ncr_ccb_from_dsa(np, dsa);
+	u_char	target	= INB (nc_sdid) & 0x0f;
+	tcb_p	tp	= &np->target[target];
+	int	tmp;
+
+	if (DEBUG_FLAGS & DEBUG_TINY) printk ("I#%d", num);
+
+	switch (num) {
+	/*
+	**	See comments in the SCRIPTS code.
+	*/
+#ifdef SCSI_NCR_PCIQ_SYNC_ON_INTR
+	case SIR_DUMMY_INTERRUPT:
+		goto out;
+#endif
+	/*
+	**	The C code is currently trying to recover from something.
+	**	Typically, user want to abort some command.
+	*/
+	case SIR_SCRIPT_STOPPED:
+	case SIR_TARGET_SELECTED:
+	case SIR_ABORT_SENT:
+		ncr_sir_task_recovery(np, num);
+		return;
+	/*
+	**	The device didn't go to MSG OUT phase after having 
+	**	been selected with ATN. We donnot want to handle 
+	**	that.
+	*/
+	case SIR_SEL_ATN_NO_MSG_OUT:
+		printk ("%s:%d: No MSG OUT phase after selection with ATN.\n",
+			ncr_name (np), target);
+		goto out_stuck;
+	/*
+	**	The device didn't switch to MSG IN phase after 
+	**	having reseleted the initiator.
+	*/
+	case SIR_RESEL_NO_MSG_IN:
+	/*
+	**	After reselection, the device sent a message that wasn't 
+	**	an IDENTIFY.
+	*/
+	case SIR_RESEL_NO_IDENTIFY:
+		/*
+		**	If devices reselecting without sending an IDENTIFY 
+		**	message still exist, this should help.
+		**	We just assume lun=0, 1 CCB, no tag.
+		*/
+		if (tp->l0p) { 
+			OUTL (nc_dsa, scr_to_cpu(tp->l0p->tasktbl[0]));
+			OUTL (nc_dsp, NCB_SCRIPT_PHYS (np, resel_go));
+			return;
+		}
+	/*
+	**	The device reselected a LUN we donnot know of.
+	*/
+	case SIR_RESEL_BAD_LUN:
+		np->msgout[0] = M_RESET;
+		goto out;
+	/*
+	**	The device reselected for an untagged nexus and we 
+	**	haven't any.
+	*/
+	case SIR_RESEL_BAD_I_T_L:
+		np->msgout[0] = M_ABORT;
+		goto out;
+	/*
+	**	The device reselected for a tagged nexus that we donnot 
+	**	have.
+	*/
+	case SIR_RESEL_BAD_I_T_L_Q:
+		np->msgout[0] = M_ABORT_TAG;
+		goto out;
+	/*
+	**	The SCRIPTS let us know that the device has grabbed 
+	**	our message and will abort the job.
+	*/
+	case SIR_RESEL_ABORTED:
+		np->lastmsg = np->msgout[0];
+		np->msgout[0] = M_NOOP;
+		printk ("%s:%d: message %x sent on bad reselection.\n",
+			ncr_name (np), target, np->lastmsg);
+		goto out;
+	/*
+	**	The SCRIPTS let us know that a message has been 
+	**	successfully sent to the device.
+	*/
+	case SIR_MSG_OUT_DONE:
+		np->lastmsg = np->msgout[0];
+		np->msgout[0] = M_NOOP;
+		/* Should we really care of that */
+		if (np->lastmsg == M_PARITY || np->lastmsg == M_ID_ERROR) {
+			if (cp)
+				cp->xerr_status &= ~XE_PARITY_ERR;
 		}
-
-		if (INB (HS_PRT) == HS_NEGOTIATE) {
-			OUTB (HS_PRT, HS_BUSY);
-			switch (cp->nego_status) {
-
-			case NS_WIDE:
-				/*
-				**      This was an answer message
-				*/
-				if (chg) {
-					/*
-					**	Answer wasn't acceptable.
-					*/
-					ncr_setwide (np, cp, 0, 1);
-					OUTL (nc_dsp, NCB_SCRIPT_PHYS (np, msg_bad));
-				} else {
-					/*
-					**	Answer is ok.
-					*/
-					ncr_setwide (np, cp, wide, 1);
-					OUTL (nc_dsp, NCB_SCRIPT_PHYS (np, clrack));
-				};
+		goto out;
+	/*
+	**	The device didn't send a GOOD SCSI status.
+	**	We may have some work to do prior to allow 
+	**	the SCRIPTS processor to continue.
+	*/
+	case SIR_BAD_STATUS:
+		if (!cp)
+			goto out;
+		ncr_sir_to_redo(np, num, cp);
+		return;
+	/*
+	**	We are asked by the SCRIPTS to prepare a 
+	**	REJECT message.
+	*/
+	case SIR_REJECT_TO_SEND:
+		ncr_print_msg(cp, "M_REJECT to send for ", np->msgin);
+		np->msgout[0] = M_REJECT;
+		goto out;
+	/*
+	**	We have been ODD at the end of a DATA IN 
+	**	transfer and the device didn't send a 
+	**	IGNORE WIDE RESIDUE message.
+	**	It is a data overrun condition.
+	*/
+	case SIR_SWIDE_OVERRUN:
+		if (cp)
+			cp->xerr_status |= XE_EXTRA_DATA;
+		goto out;
+	/*
+	**	We have been ODD at the end of a DATA OUT 
+	**	transfer.
+	**	It is a data underrun condition.
+	*/
+	case SIR_SODL_UNDERRUN:
+		if (cp)
+			cp->xerr_status |= XE_EXTRA_DATA;
+		goto out;
+	/*
+	**	We received a message.
+	*/
+	case SIR_MSG_RECEIVED:
+		if (!cp)
+			goto out_stuck;
+		switch (np->msgin [0]) {
+		/*
+		**	We received an extended message.
+		**	We handle MODIFY DATA POINTER, SDTR, WDTR 
+		**	and reject all other extended messages.
+		*/
+		case M_EXTENDED:
+			switch (np->msgin [2]) {
+			case M_X_MODIFY_DP:
+				if (DEBUG_FLAGS & DEBUG_POINTER)
+					ncr_print_msg(cp,"modify DP",np->msgin);
+				tmp = (np->msgin[3]<<24) + (np->msgin[4]<<16) + 
+				      (np->msgin[5]<<8)  + (np->msgin[6]);
+				ncr_modify_dp(np, tp, cp, tmp);
 				return;
-
-			case NS_SYNC:
-				ncr_setsync (np, cp, 0, 0xe0);
-				break;
-			};
-		};
-
+			case M_X_SYNC_REQ:
+				ncr_sync_nego(np, tp, cp);
+				return;
+			case M_X_WIDE_REQ:
+				ncr_wide_nego(np, tp, cp);
+				return;
+			case M_X_PPR_REQ:
+				ncr_ppr_nego(np, tp, cp);
+				return;
+			default:
+				goto out_reject;
+			}
+			break;
 		/*
-		**	It was a request, set value and
-		**      prepare an answer message
-		*/
-
-		ncr_setwide (np, cp, wide, 1);
-
-		np->msgout[0] = M_EXTENDED;
-		np->msgout[1] = 2;
-		np->msgout[2] = M_X_WIDE_REQ;
-		np->msgout[3] = wide;
-
-		np->msgin [0] = M_NOOP;
-
-		cp->nego_status = NS_WIDE;
-
-		if (DEBUG_FLAGS & DEBUG_NEGO) {
-			PRINT_ADDR(cp->cmd);
-			printk ("wide msgout: ");
-			(void) ncr_show_msg (np->msgin);
-			printk (".\n");
+		**	We received a 1/2 byte message not handled from SCRIPTS.
+		**	We are only expecting MESSAGE REJECT and IGNORE WIDE 
+		**	RESIDUE messages that haven't been anticipated by 
+		**	SCRIPTS on SWIDE full condition. Unanticipated IGNORE 
+		**	WIDE RESIDUE messages are aliased as MODIFY DP (-1).
+		*/
+		case M_IGN_RESIDUE:
+			if (DEBUG_FLAGS & DEBUG_POINTER)
+				ncr_print_msg(cp,"ign wide residue", np->msgin);
+			ncr_modify_dp(np, tp, cp, -1);
+			return;
+		case M_REJECT:
+			if (INB (HS_PRT) == HS_NEGOTIATE)
+				ncr_nego_rejected(np, tp, cp);
+			else {
+				PRINT_ADDR(cp->cmd);
+				printk ("M_REJECT received (%x:%x).\n",
+					scr_to_cpu(np->lastmsg), np->msgout[0]);
+			}
+			goto out_clrack;
+			break;
+		default:
+			goto out_reject;
 		}
-		break;
-
-/*--------------------------------------------------------------------
-**
-**	Processing of special messages
-**
-**--------------------------------------------------------------------
-*/
-
-	case SIR_REJECT_RECEIVED:
-		/*-----------------------------------------------
-		**
-		**	We received a M_REJECT message.
-		**
-		**-----------------------------------------------
-		*/
-
-		PRINT_ADDR(cp->cmd);
-		printk ("M_REJECT received (%x:%x).\n",
-			(unsigned)scr_to_cpu(np->lastmsg), np->msgout[0]);
-		break;
-
-	case SIR_REJECT_TO_SEND:
-		/*-----------------------------------------------
-		**
-		**	We received an unknown message
-		**
-		**-----------------------------------------------
-		*/
-
-		PRINT_ADDR(cp->cmd);
-		printk ("M_REJECT to send for ");
-		(void) ncr_show_msg (np->msgin);
-		printk (".\n");
-		np->msgout[0] = M_REJECT;
-		break;
-
-/*--------------------------------------------------------------------
-**
-**	Processing of special messages
-**
-**--------------------------------------------------------------------
-*/
-
-	case SIR_IGN_RESIDUE:
-		/*-----------------------------------------------
-		**
-		**	We received an IGNORE RESIDUE message,
-		**	which couldn't be handled by the script.
-		**
-		**-----------------------------------------------
-		*/
-
-		PRINT_ADDR(cp->cmd);
-		printk ("M_IGN_RESIDUE received, but not yet implemented.\n");
-		break;
-#if 0
-	case SIR_MISSING_SAVE:
-		/*-----------------------------------------------
-		**
-		**	We received an DISCONNECT message,
-		**	but the datapointer wasn't saved before.
-		**
-		**-----------------------------------------------
-		*/
-
-		PRINT_ADDR(cp->cmd);
-		printk ("M_DISCONNECT received, but datapointer not saved: "
-			"data=%x save=%x goal=%x.\n",
-			(unsigned) INL (nc_temp),
-			(unsigned) scr_to_cpu(np->header.savep),
-			(unsigned) scr_to_cpu(np->header.goalp));
 		break;
-#endif
+	/*
+	**	We received an unknown message.
+	**	Ignore all MSG IN phases and reject it.
+	*/
+	case SIR_MSG_WEIRD:
+		ncr_print_msg(cp, "WEIRD message received", np->msgin);
+		OUTL (nc_dsp, NCB_SCRIPTH_PHYS (np, msg_weird));
+		return;
+	/*
+	**	Negotiation failed.
+	**	Target does not send us the reply.
+	**	Remove the HS_NEGOTIATE status.
+	*/
+	case SIR_NEGO_FAILED:
+		OUTB (HS_PRT, HS_BUSY);
+	/*
+	**	Negotiation failed.
+	**	Target does not want answer message.
+	*/
+	case SIR_NEGO_PROTO:
+		ncr_nego_default(np, tp, cp);
+		goto out;
 	};
 
 out:
 	OUTONB (nc_dcntl, (STD|NOCOM));
+	return;
+out_reject:
+	OUTL (nc_dsp, NCB_SCRIPTH_PHYS (np, msg_bad));
+	return;
+out_clrack:
+	OUTL (nc_dsp, NCB_SCRIPT_PHYS (np, clrack));
+	return;
 out_stuck:
 }
 
+
 /*==========================================================
 **
 **
@@ -8553,7 +11181,7 @@
 {
 	tcb_p tp = &np->target[tn];
 	lcb_p lp = ncr_lp(np, tp, ln);
-	u_char tag = NO_TAG;
+	u_short tag = NO_TAG;
 	XPT_QUEHEAD *qp;
 	ccb_p cp = (ccb_p) 0;
 
@@ -8597,9 +11225,10 @@
 			if (lp->busyccbs < lp->maxnxs) {
 				tag = lp->cb_tags[lp->ia_tag];
 				++lp->ia_tag;
-				if (lp->ia_tag == SCSI_NCR_MAX_TAGS)
+				if (lp->ia_tag == MAX_TAGS)
 					lp->ia_tag = 0;
-				lp->tags_umap |= (((tagmap_t) 1) << tag);
+				cp->tags_si = lp->tags_si;
+				++lp->tags_sum[cp->tags_si];
 			}
 			else
 				goto out_free;
@@ -8616,6 +11245,7 @@
 	/*
 	**	Remember all informations needed to free this CCB.
 	*/
+	cp->to_abort = 0;
 	cp->tag	   = tag;
 	cp->target = tn;
 	cp->lun    = ln;
@@ -8659,10 +11289,9 @@
 	if (lp) {
 		if (cp->tag != NO_TAG) {
 			lp->cb_tags[lp->if_tag++] = cp->tag;
-			if (lp->if_tag == SCSI_NCR_MAX_TAGS)
+			if (lp->if_tag == MAX_TAGS)
 				lp->if_tag = 0;
-			lp->tags_umap &= ~(((tagmap_t) 1) << cp->tag);
-			lp->tags_smap &= lp->tags_umap;
+			--lp->tags_sum[cp->tags_si];
 			lp->tasktbl[cp->tag] = cpu_to_scr(np->p_bad_i_t_l_q);
 		} else {
 			lp->tasktbl[0] = cpu_to_scr(np->p_bad_i_t_l);
@@ -8723,6 +11352,11 @@
 	cp->phys.header.go.restart = cpu_to_scr(NCB_SCRIPTH_PHYS(np,bad_i_t_l));
 
 	/*
+	**	Initilialyze some other fields.
+	*/
+	cp->phys.smsg_ext.addr = cpu_to_scr(vtobus(&np->msgin[2]));
+
+	/*
 	**	Chain into wakeup list and free ccb queue.
 	*/
 	cp->link_ccb	= np->ccbc;
@@ -8773,25 +11407,6 @@
 */
 static void ncr_init_tcb (ncb_p np, u_char tn)
 {
-	tcb_p tp = &np->target[tn];
-
-	/*
-	**	Already bone.
-	*/
-	if (tp->luntbl)
-		return;
-	/*
-	**	Allocate the lcb bus address array.
-	*/
-	tp->luntbl = m_calloc(256, "LUNTBL", MEMO_WARN);
-	if (!tp->luntbl)
-		return;
-
-	/*
-	**	Compute the bus address of this table.
-	*/
-	tp->b_luntbl = cpu_to_scr(vtobus(tp->luntbl));
-
 	/*
 	**	Check some alignments required by the chip.
 	*/	
@@ -8799,6 +11414,10 @@
 		offsetof(struct tcb    , sval    )) &3) == 0);
 	assert (( (offsetof(struct ncr_reg, nc_scntl3) ^
 		offsetof(struct tcb    , wval    )) &3) == 0);
+	if (np->device_id == PCI_DEVICE_ID_LSI_53C1010){
+		assert (( (offsetof(struct ncr_reg, nc_scntl4) ^
+			offsetof(struct tcb    , uval    )) &3) == 0);
+	}
 }
 
 /*------------------------------------------------------------------------
@@ -8823,8 +11442,21 @@
 	**	Initialize the target control block if not yet.
 	*/
 	ncr_init_tcb(np, tn);
-	if (!tp->luntbl)
-		goto fail;
+
+	/*
+	**	Allocate the lcb bus address array.
+	**	Compute the bus address of this table.
+	*/
+	if (ln && !tp->luntbl) {
+		int i;
+
+		tp->luntbl = m_calloc(256, "LUNTBL", MEMO_WARN);
+		if (!tp->luntbl)
+			goto fail;
+		for (i = 0 ; i < 64 ; i++)
+			tp->luntbl[i] = cpu_to_scr(vtobus(&np->resel_badlun));
+		tp->b_luntbl = cpu_to_scr(vtobus(tp->luntbl));
+	}
 
 	/*
 	**	Allocate the table of pointers for LUN(s) > 0, if needed.
@@ -8837,19 +11469,19 @@
 
 	/*
 	**	Allocate the lcb.
+	**	Make it available to the chip.
 	*/
 	lp = m_calloc(sizeof(struct lcb), "LCB", MEMO_WARN);
 	if (!lp)
 		goto fail;
-	if (ln)
+	if (ln) {
 		tp->lmp[ln] = lp;
-	else
+		tp->luntbl[ln] = cpu_to_scr(vtobus(lp));
+	}
+	else {
 		tp->l0p = lp;
-
-	/*
-	**	Make it available to the chip.
-	*/
-	tp->luntbl[ln] = cpu_to_scr(vtobus(lp));
+		tp->b_lun0 = cpu_to_scr(vtobus(lp));
+	}
 
 	/*
 	**	Initialize the CCB queue headers.
@@ -8899,14 +11531,16 @@
 	if (!lp && !(lp = ncr_alloc_lcb(np, tn, ln)))
 		goto fail;
 
+#if 0	/* No more used. Left here as provision */
 	/*
-	**	Get device quirks from a speciality table.
+	**	Get device quirks.
 	*/
-	tp->quirks = ncr_lookup (inq_data);
+	tp->quirks = 0;
 	if (tp->quirks && bootverbose) {
 		PRINT_LUN(np, tn, ln);
 		printk ("quirks=%x.\n", tp->quirks);
 	}
+#endif
 
 	/*
 	**	Evaluate trustable target/unit capabilities.
@@ -8949,18 +11583,23 @@
 	**	initialyze the task table if not yet.
 	*/
 	if ((inq_byte7 & INQ7_QUEUE) && lp->tasktbl == &lp->tasktbl_0) {
-		lp->tasktbl = m_calloc(256, "TASKTBL", MEMO_WARN);
+		lp->tasktbl = m_calloc(MAX_TASKS*4, "TASKTBL", MEMO_WARN);
 		if (!lp->tasktbl) {
 			lp->tasktbl = &lp->tasktbl_0;
 			goto fail;
 		}
 		lp->b_tasktbl = cpu_to_scr(vtobus(lp->tasktbl));
-		for (i = 0 ; i < 64 ; i++)
+		for (i = 0 ; i < MAX_TASKS ; i++)
 			lp->tasktbl[i] = cpu_to_scr(np->p_notask);
-		for (i = 0 ; i < SCSI_NCR_MAX_TAGS ; i++)
+
+		lp->cb_tags = m_calloc(MAX_TAGS, "CB_TAGS", MEMO_WARN);
+		if (!lp->cb_tags)
+			goto fail;
+		for (i = 0 ; i < MAX_TAGS ; i++)
 			lp->cb_tags[i] = i;
-		lp->maxnxs = SCSI_NCR_MAX_TAGS;
-		lp->tags_stime = jiffies;
+
+		lp->maxnxs = MAX_TAGS;
+		lp->tags_stime = ktime_get(3*HZ);
 	}
 
 	/*
@@ -9008,7 +11647,7 @@
 /*
 **	For 64 bit systems, we use the 8 upper bits of the size field 
 **	to provide bus address bits 32-39 to the SCRIPTS processor.
-**	This allows the 896 to access up to 1 tera-bytes of memory.
+**	This allows the 895A and 896 to address up to 1 TB of memory.
 **	For 32 bit chips on 64 bit systems, we must be provided with 
 **	memory addresses that fit into the first 32 bit bus address 
 **	range and so, this does not matter and we expect an error from 
@@ -9145,9 +11784,7 @@
 */
 
 #ifndef NCR_IOMAPPED
-__initfunc(
-static int ncr_regtest (struct ncb* np)
-)
+static int __init ncr_regtest (struct ncb* np)
 {
 	register volatile u_int32 data;
 	/*
@@ -9171,9 +11808,7 @@
 }
 #endif
 
-__initfunc(
-static int ncr_snooptest (struct ncb* np)
-)
+static int __init ncr_snooptest (struct ncb* np)
 {
 	u_int32	ncr_rd, ncr_wr, ncr_bk, host_rd, host_wr, pc;
 	int	i, err=0;
@@ -9294,62 +11929,6 @@
 
 /*==========================================================
 **
-**
-**	Device lookup.
-**
-**	@GENSCSI@ should be integrated to scsiconf.c
-**
-**
-**==========================================================
-*/
-
-struct table_entry {
-	char *	manufacturer;
-	char *	model;
-	char *	version;
-	u_long	info;
-};
-
-static struct table_entry device_tab[] =
-{
-#if 0
-	{"", "", "", QUIRK_NOMSG},
-#endif
-	{"SONY", "SDT-5000", "3.17", QUIRK_NOMSG},
-	{"WangDAT", "Model 2600", "01.7", QUIRK_NOMSG},
-	{"WangDAT", "Model 3200", "02.2", QUIRK_NOMSG},
-	{"WangDAT", "Model 1300", "02.4", QUIRK_NOMSG},
-	{"", "", "", 0} /* catch all: must be last entry. */
-};
-
-static u_long ncr_lookup(char * id)
-{
-	struct table_entry * p = device_tab;
-	char *d, *r, c;
-
-	for (;;p++) {
-
-		d = id+8;
-		r = p->manufacturer;
-		while ((c=*r++)) if (c!=*d++) break;
-		if (c) continue;
-
-		d = id+16;
-		r = p->model;
-		while ((c=*r++)) if (c!=*d++) break;
-		if (c) continue;
-
-		d = id+32;
-		r = p->version;
-		while ((c=*r++)) if (c!=*d++) break;
-		if (c) continue;
-
-		return (p->info);
-	}
-}
-
-/*==========================================================
-**
 **	Determine the ncr's clock frequency.
 **	This is essential for the negotiation
 **	of the synchronous transfer rate.
@@ -9364,7 +11943,8 @@
 **	do not have a clock doubler and so are provided with a 
 **	80 MHz clock. All other fast20 boards incorporate a doubler 
 **	and so should be delivered with a 40 MHz clock.
-**	The recent fast40 chips (895/896) use a 40 Mhz base clock 
+**	The recent fast40 chips  (895/896/895A) and the
+**	fast80 chip (C1010) use a 40 Mhz base clock 
 **	and provide a clock quadrupler (160 Mhz). The code below 
 **	tries to deal as cleverly as possible with all this stuff.
 **
@@ -9385,14 +11965,19 @@
 		printk ("%s: enabling clock multiplier\n", ncr_name(np));
 
 	OUTB(nc_stest1, DBLEN);	   /* Enable clock multiplier		  */
-	if (np->multiplier > 2) {  /* Poll bit 5 of stest4 for quadrupler */
-		int i = 20;
+
+	if ( (np->device_id != PCI_DEVICE_ID_LSI_53C1010) && 
+						(np->multiplier > 2)) {  
+		int i = 20;	 /* Poll bit 5 of stest4 for quadrupler */
 		while (!(INB(nc_stest4) & LCKFRQ) && --i > 0)
 			UDELAY (20);
 		if (!i)
-			printk("%s: the chip cannot lock the frequency\n", ncr_name(np));
-	} else			/* Wait 20 micro-seconds for doubler	*/
-		UDELAY (20);
+		    printk("%s: the chip cannot lock the frequency\n",
+						 ncr_name(np));
+
+	} else			/* Wait 120 micro-seconds for multiplier*/
+		UDELAY (120);
+
 	OUTB(nc_stest3, HSC);		/* Halt the scsi clock		*/
 	OUTB(nc_scntl3,	scntl3);
 	OUTB(nc_stest1, (DBLEN|DBLSEL));/* Select clock multiplier	*/
@@ -9403,11 +11988,11 @@
 /*
  *	calculate NCR SCSI clock frequency (in KHz)
  */
-__initfunc(
-static unsigned ncrgetfreq (ncb_p np, int gen)
-)
+static unsigned __init ncrgetfreq (ncb_p np, int gen)
 {
-	unsigned ms = 0;
+	unsigned int ms = 0;
+	unsigned int f;
+	int count;
 
 	/*
 	 * Measure GEN timer delay in order 
@@ -9424,16 +12009,21 @@
 	 * performed trust the higher delay 
 	 * (lower frequency returned).
 	 */
-	OUTB (nc_stest1, 0);	/* make sure clock doubler is OFF */
-	OUTW (nc_sien , 0);	/* mask all scsi interrupts */
+	OUTW (nc_sien , 0x0);/* mask all scsi interrupts */
+				/* enable general purpose timer */
 	(void) INW (nc_sist);	/* clear pending scsi interrupt */
 	OUTB (nc_dien , 0);	/* mask all dma interrupts */
 	(void) INW (nc_sist);	/* another one, just to be sure :) */
 	OUTB (nc_scntl3, 4);	/* set pre-scaler to divide by 3 */
 	OUTB (nc_stime1, 0);	/* disable general purpose timer */
 	OUTB (nc_stime1, gen);	/* set to nominal delay of 1<<gen * 125us */
-	while (!(INW(nc_sist) & GEN) && ms++ < 100000)
-		UDELAY (1000);	/* count ms */
+				/* Temporary fix for udelay issue with Alpha
+					platform */
+	while (!(INW(nc_sist) & GEN) && ms++ < 100000) {
+		/* count 1ms */
+		for (count = 0; count < 10; count++)
+			UDELAY (100);	
+	}
 	OUTB (nc_stime1, 0);	/* disable general purpose timer */
  	/*
  	 * set prescaler to divide by whatever 0 means
@@ -9442,20 +12032,41 @@
  	 */
  	OUTB (nc_scntl3, 0);
 
-	if (bootverbose >= 2)
-		printk ("%s: Delay (GEN=%d): %u msec\n", ncr_name(np), gen, ms);
   	/*
  	 * adjust for prescaler, and convert into KHz 
+	 * scale values derived empirically. C1010 uses
+	 * different dividers
   	 */
-	return ms ? ((1 << gen) * 4340) / ms : 0;
+#if 0
+	if (np->device_id == PCI_DEVICE_ID_LSI_53C1010)
+		f = ms ? ((1 << gen) * 2866 ) / ms : 0;
+	else
+#endif
+	f = ms ? ((1 << gen) * 4340) / ms : 0;
+
+	if (bootverbose >= 2)
+		printk ("%s: Delay (GEN=%d): %u msec, %u KHz\n",
+			ncr_name(np), gen, ms, f);
+
+	return f;
+}
+
+static unsigned __init ncr_getfreq (ncb_p np)
+{
+	u_int f1, f2;
+	int gen = 11;
+
+	(void) ncrgetfreq (np, gen);	/* throw away first result */
+	f1 = ncrgetfreq (np, gen);
+	f2 = ncrgetfreq (np, gen);
+	if (f1 > f2) f1 = f2;		/* trust lower result	*/
+	return f1;
 }
 
 /*
  *	Get/probe NCR SCSI clock frequency
  */
-__initfunc(
-static void ncr_getclock (ncb_p np, int mult)
-)
+static void __init ncr_getclock (ncb_p np, int mult)
 {
 	unsigned char scntl3 = INB(nc_scntl3);
 	unsigned char stest1 = INB(nc_stest1);
@@ -9465,7 +12076,7 @@
 	f1 = 40000;
 
 	/*
-	**	True with 875/895/896 with clock multiplier selected
+	**	True with 875/895/896/895A with clock multiplier selected
 	*/
 	if (mult > 1 && (stest1 & (DBLEN+DBLSEL)) == DBLEN+DBLSEL) {
 		if (bootverbose >= 2)
@@ -9474,29 +12085,36 @@
 	}
 
 	/*
+	**	If multiplier not found but a C1010, assume a mult of 4.
 	**	If multiplier not found or scntl3 not 7,5,3,
 	**	reset chip and get frequency from general purpose timer.
 	**	Otherwise trust scntl3 BIOS setting.
 	*/
-	if (np->multiplier != mult || (scntl3 & 7) < 3 || !(scntl3 & 1)) {
-		unsigned f2;
-
-		OUTB(nc_istat, SRST); UDELAY (5); OUTB(nc_istat, 0);
-
-		(void) ncrgetfreq (np, 11);	/* throw away first result */
-		f1 = ncrgetfreq (np, 11);
-		f2 = ncrgetfreq (np, 11);
+	if (np->device_id == PCI_DEVICE_ID_LSI_53C1010) {
+		f1=40000;
+		np->multiplier = mult;
+		if (bootverbose >= 2)
+			printk ("%s: clock multiplier assumed\n", ncr_name(np));
+	}
+	else if (np->multiplier != mult || (scntl3 & 7) < 3 || !(scntl3 & 1)) {
+		OUTB (nc_stest1, 0);		/* make sure doubler is OFF */
+		f1 = ncr_getfreq (np);
 
 		if (bootverbose)
-			printk ("%s: NCR clock is %uKHz, %uKHz\n", ncr_name(np), f1, f2);
+			printk ("%s: NCR clock is %uKHz\n", ncr_name(np), f1);
 
-		if (f1 > f2) f1 = f2;		/* trust lower result	*/
-
-		if	(f1 <	45000)		f1 =  40000;
-		else if (f1 <	55000)		f1 =  50000;
+		if	(f1 < 55000)		f1 =  40000;
 		else				f1 =  80000;
+
+		/*
+		**	Suggest to also check the PCI clock frequency 
+		**	to make sure our frequency calculation algorithm 
+		**	is not too biased.
+		*/
+		np->pciclock_min = (33000*55+80-1)/80;
+		np->pciclock_max = (33000*55)/40;
 
-		if (f1 < 80000 && mult > 1) {
+		if (f1 == 40000 && mult > 1) {
 			if (bootverbose >= 2)
 				printk ("%s: clock multiplier assumed\n", ncr_name(np));
 			np->multiplier	= mult;
@@ -9516,6 +12134,20 @@
 	np->clock_khz	= f1;
 }
 
+/*
+ *	Get/probe PCI clock frequency
+ */
+static u_int __init ncr_getpciclock (ncb_p np)
+{
+	static u_int f;
+
+	OUTB (nc_stest1, SCLK);	/* Use the PCI clock as SCSI clock */
+	f = ncr_getfreq (np);
+	OUTB (nc_stest1, 0);
+
+	return f;
+}
+
 /*===================== LINUX ENTRY POINTS SECTION ==========================*/
 
 #ifndef uchar
@@ -9569,6 +12201,10 @@
 #define OPT_EXCLUDE		24
 #define OPT_HOST_ID		25
 
+#ifdef SCSI_NCR_IARB_SUPPORT
+#define OPT_IARB		26
+#endif
+
 static char setup_token[] __initdata = 
 	"tags:"   "mpar:"
 	"spar:"   "disc:"
@@ -9582,7 +12218,11 @@
 	"buschk:" "optim:"
 	"recovery:"
 	"safe:"   "nvram:"
-	"excl:"   "hostid:";
+	"excl:"   "hostid:"
+#ifdef SCSI_NCR_IARB_SUPPORT
+	"iarb:"
+#endif
+	;	/* DONNOT REMOVE THIS ';' */
 
 #ifdef MODULE
 #define	ARG_SEP	' '
@@ -9590,9 +12230,7 @@
 #define	ARG_SEP	','
 #endif
 
-__initfunc(
-static int get_setup_token(char *p)
-)
+static int __init get_setup_token(char *p)
 {
 	char *cur = setup_token;
 	char *pc;
@@ -9609,14 +12247,13 @@
 }
 
 
-__initfunc(
-void sym53c8xx_setup(char *str, int *ints)
-)
+int __init sym53c8xx_setup(char *str)
 {
 #ifdef SCSI_NCR_BOOT_COMMAND_LINE_SUPPORT
 	char *cur = str;
 	char *pc, *pv;
-	int i, val, c;
+	unsigned long val;
+	int i,  c;
 	int xi = 0;
 
 	while (cur != NULL && (pc = strchr(cur, ':')) != NULL) {
@@ -9719,6 +12356,11 @@
 		case OPT_HOST_ID:
 			driver_setup.host_id = val;
 			break;
+#ifdef SCSI_NCR_IARB_SUPPORT
+		case OPT_IARB:
+			driver_setup.iarb = val;
+			break;
+#endif
 		default:
 			printk("sym53c8xx_setup: unexpected boot option '%.*s' ignored\n", (int)(pc-cur+1), cur);
 			break;
@@ -9728,8 +12370,15 @@
 			++cur;
 	}
 #endif /* SCSI_NCR_BOOT_COMMAND_LINE_SUPPORT */
+	return 0;
 }
 
+#if LINUX_VERSION_CODE >= LinuxVersionCode(2,3,13)
+#ifndef MODULE
+__setup("sym53c8xx=", sym53c8xx_setup);
+#endif
+#endif
+
 static int sym53c8xx_pci_init(Scsi_Host_Template *tpnt,
 	     uchar bus, uchar device_fn, ncr_device *device);
 
@@ -9748,9 +12397,7 @@
 **   Returns the number of boards successfully attached.
 */
 
-__initfunc(
-static void ncr_print_driver_setup(void)
-)
+static void __init ncr_print_driver_setup(void)
 {
 #define YesNo(y)	y ? 'y' : 'n'
 	printk (NAME53C8XX ": setup=disc:%c,specf:%d,ultra:%d,tags:%d,sync:%d,"
@@ -9809,9 +12456,7 @@
 #define	SCSI_NCR_MAX_PQS_BUS	16
 static int pqs_bus[SCSI_NCR_MAX_PQS_BUS] __initdata = { 0 };
 
-__initfunc(
-static void ncr_detect_pqs_pds(void)
-)
+static void __init ncr_detect_pqs_pds(void)
 {
 	short index;
 
@@ -9849,9 +12494,7 @@
 **    the the order they are detected.
 **===================================================================
 */
-__initfunc(
-int sym53c8xx_detect(Scsi_Host_Template *tpnt)
-)
+int __init sym53c8xx_detect(Scsi_Host_Template *tpnt)
 {
 	int i, j, chips, hosts, count;
 	u_char bus, device_fn;
@@ -9882,7 +12525,7 @@
 
 #if	defined(SCSI_NCR_BOOT_COMMAND_LINE_SUPPORT) && defined(MODULE)
 if (sym53c8xx)
-	sym53c8xx_setup(sym53c8xx, (int *) 0);
+	sym53c8xx_setup(sym53c8xx);
 #endif
 #ifdef SCSI_NCR_DEBUG_INFO_SUPPORT
 	ncr_debug = driver_setup.debug;
@@ -9934,6 +12577,14 @@
 			continue;
 		}
 		++index;
+		/* Some HW as the HP LH4 may report twice PCI devices */
+		for (i = 0; i < count ; i++) {
+			if (devtbl[i].slot.bus	     == bus && 
+			    devtbl[i].slot.device_fn == device_fn)
+				break;
+		}
+		if (i != count)	/* Ignore this device if we already have it */
+			continue;
 		devp = &devtbl[count];
 		devp->host_id = driver_setup.host_id;
 		devp->attach_done = 0;
@@ -10039,10 +12690,8 @@
 **===================================================================
 */
 #if LINUX_VERSION_CODE <= LinuxVersionCode(2,1,92)
-__initfunc(
-static int 
+static int __init 
 pci_read_base_address(u_char bus, u_char device_fn, int offset, u_long *base)
-)
 {
 	u_int32 tmp;
 
@@ -10058,11 +12707,9 @@
 	}
 	return offset;
 }
-#else	/* LINUX_VERSION_CODE > LinuxVersionCode(2,1,92) */
-__initfunc(
-static int 
+#elif	LINUX_VERSION_CODE <= LinuxVersionCode(2,3,12)
+static int __init 
 pci_get_base_address(struct pci_dev *pdev, int index, u_long *base)
-)
 {
 	*base = pdev->base_address[index++];
 	if ((*base & 0x7) == 0x4) {
@@ -10073,6 +12720,15 @@
 	}
 	return index;
 }
+#else	/* LINUX_VERSION_CODE > LinuxVersionCode(2,3,12) */
+static int __init 
+pci_get_base_address(struct pci_dev *pdev, int index, u_long *base)
+{
+	*base = pdev->resource[index].start;
+	if ((pdev->resource[index].flags & 0x7) == 0x4)
+		++index;
+	return ++index;
+}
 #endif
 
 /*===================================================================
@@ -10081,14 +12737,13 @@
 **   been detected.
 **===================================================================
 */
-__initfunc(
-static int sym53c8xx_pci_init(Scsi_Host_Template *tpnt,
+static int __init sym53c8xx_pci_init(Scsi_Host_Template *tpnt,
 			      uchar bus, uchar device_fn, ncr_device *device)
-)
 {
-	u_short vendor_id, device_id, command;
+	u_short vendor_id, device_id, command, status_reg;
 	u_char cache_line_size, latency_timer;
 	u_char suggested_cache_line_size = 0;
+	u_char pci_fix_up;
 	u_char revision;
 #if LINUX_VERSION_CODE > LinuxVersionCode(2,1,92)
 	struct pci_dev *pdev;
@@ -10131,6 +12786,8 @@
 				 &cache_line_size);
 	pcibios_read_config_byte(bus, device_fn, PCI_LATENCY_TIMER,
 				 &latency_timer);
+	pcibios_read_config_word(bus, device_fn, PCI_STATUS,
+				 &status_reg);
 
 #ifdef SCSI_NCR_PQS_PDS_SUPPORT
 	/*
@@ -10201,7 +12858,7 @@
 			}
 		}
 	}
-#endif /* not def SCSI_NCR_PCI_MEM_NOT_SUPPORTED */
+#endif /* i386 and PCI MEMORY accessible */
 
 	if (!chip) {
 		printk(NAME53C8XX ": not initializing, device not supported\n");
@@ -10268,8 +12925,6 @@
 	if (!cache_line_size)
 		suggested_cache_line_size = 16;
 
-	driver_setup.pci_fix_up |= 0x7;
-
 #endif	/* __sparc__ */
 
 #if defined(__i386__) && !defined(MODULE)
@@ -10299,7 +12954,7 @@
 	*/
 /* #ifdef NCR_IOMAPPED */
 #if 1
-	if (!(command & PCI_COMMAND_IO) || !(io_port & 1)) { 
+	if (!(command & PCI_COMMAND_IO)) { 
 		printk(NAME53C8XX ": I/O base address (0x%lx) disabled.\n",
 			(long) io_port);
 		io_port = 0;
@@ -10354,20 +13009,70 @@
 		if (driver_setup.special_features & 4)
 			chip->features &= ~FE_NOPM;
 	}
+
+	/*
+	** Work around for errant bit in 895A. The 66Mhz
+	** capable bit is set erroneously. Clear this bit.
+	** (Item 1 DEL 533)
+	**
+	** Make sure Config space and Features agree.
+	**
+	** Recall: writes are not normal to status register -
+	** write a 1 to clear and a 0 to leave unchanged.
+	** Can only reset bits.
+	*/
+	if (chip->features & FE_66MHZ) {
+		if (!(status_reg & PCI_STATUS_66MHZ))
+			chip->features &= ~FE_66MHZ;
+	}
+	else {
+		if (status_reg & PCI_STATUS_66MHZ) {
+			status_reg = PCI_STATUS_66MHZ;
+			pcibios_write_config_word(bus, device_fn, PCI_STATUS, status_reg);
+			pcibios_read_config_word(bus, device_fn, PCI_STATUS, &status_reg);
+		}
+	}
+
+	if (driver_setup.ultra_scsi < 3 && (chip->features & FE_ULTRA3)) {
+		chip->features |=  FE_ULTRA2;
+		chip->features &= ~FE_ULTRA3;
+	}
 	if (driver_setup.ultra_scsi < 2 && (chip->features & FE_ULTRA2)) {
 		chip->features |=  FE_ULTRA;
 		chip->features &= ~FE_ULTRA2;
 	}
 	if (driver_setup.ultra_scsi < 1)
 		chip->features &= ~FE_ULTRA;
+
 	if (!driver_setup.max_wide)
 		chip->features &= ~FE_WIDE;
 
+	/*
+	 * C1010 Ultra3 support requires 16 bit data transfers.
+	 */
+	if (!driver_setup.max_wide && (chip->features & FE_ULTRA3)) {
+		chip->features |= FE_ULTRA2;
+		chip->features |= ~FE_ULTRA3;
+	}
+
+	/*
+	**	Some features are required to be enabled in order to 
+	**	work around some chip problems. :) ;)
+	**	(ITEM 12 of a DEL about the 896 I haven't yet).
+	**	We must ensure the chip will use WRITE AND INVALIDATE.
+	**	The revision number limit is for now arbitrary.
+	*/
+	pci_fix_up = driver_setup.pci_fix_up;
+	if (device_id == PCI_DEVICE_ID_NCR_53C896 && revision <= 0x10) {
+		chip->features	|= (FE_WRIE | FE_CLSE);
+		pci_fix_up	|=  3;	/* Force appropriate PCI fix-up */
+	}
+
 #ifdef	SCSI_NCR_PCI_FIX_UP_SUPPORT
 	/*
 	**    Try to fix up PCI config according to wished features.
 	*/
-	if ((driver_setup.pci_fix_up & 1) && (chip->features & FE_CLSE) && 
+	if ((pci_fix_up & 1) && (chip->features & FE_CLSE) && 
 	    !cache_line_size && suggested_cache_line_size) {
 		cache_line_size = suggested_cache_line_size;
 		pcibios_write_config_byte(bus, device_fn,
@@ -10376,7 +13081,7 @@
 			cache_line_size);
 	}
 
-	if ((driver_setup.pci_fix_up & 2) && cache_line_size &&
+	if ((pci_fix_up & 2) && cache_line_size &&
 	    (chip->features & FE_WRIE) && !(command & PCI_COMMAND_INVALIDATE)) {
 		printk(NAME53C8XX": setting PCI_COMMAND_INVALIDATE (fix-up)\n");
 		command |= PCI_COMMAND_INVALIDATE;
@@ -10388,7 +13093,7 @@
 	**    (latency timer >= burst length + 6, we add 10 to be quite sure)
 	*/
 
-	if ((driver_setup.pci_fix_up & 4) && chip->burst_max) {
+	if ((pci_fix_up & 4) && chip->burst_max) {
 		uchar lt = (1 << chip->burst_max) + 6 + 10;
 		if (latency_timer < lt) {
 			latency_timer = lt;
@@ -10430,7 +13135,7 @@
 *===================================================================
 */
 #ifdef SCSI_NCR_NVRAM_SUPPORT
-__initfunc(static void ncr_get_nvram(ncr_device *devp, ncr_nvram *nvp))
+static void __init ncr_get_nvram(ncr_device *devp, ncr_nvram *nvp)
 {
 	devp->nvram = nvp;
 	if (!nvp)
@@ -10557,8 +13262,8 @@
 		device->queue_depth = numtags;
 		if (device->queue_depth < 2)
 			device->queue_depth = 2;
-		if (device->queue_depth > SCSI_NCR_MAX_TAGS)
-			device->queue_depth = SCSI_NCR_MAX_TAGS;
+		if (device->queue_depth > MAX_TAGS)
+			device->queue_depth = MAX_TAGS;
 
 		/*
 		**	Since the queue depth is not tunable under Linux,
@@ -10583,15 +13288,7 @@
 */
 const char *sym53c8xx_info (struct Scsi_Host *host)
 {
-#ifdef __sparc__
-	/* Ok to do this on all archs? */
-	static char buffer[80];
-	ncb_p np = ((struct host_data *) host->hostdata)->ncb;
-	sprintf (buffer, "%s\nPCI bus %02x device %02x", SCSI_NCR_DRIVER_NAME, np->pci_bus, np->pci_devfn);
-	return buffer;
-#else
 	return SCSI_NCR_DRIVER_NAME;
-#endif
 }
 
 /*
@@ -10990,8 +13687,14 @@
 		uc->cmd = UC_SETDEBUG;
 	else if	((arg_len = is_keyword(ptr, len, "setflag")) != 0)
 		uc->cmd = UC_SETFLAG;
+	else if	((arg_len = is_keyword(ptr, len, "resetdev")) != 0)
+		uc->cmd = UC_RESETDEV;
+	else if	((arg_len = is_keyword(ptr, len, "cleardev")) != 0)
+		uc->cmd = UC_CLEARDEV;
+#ifdef SCSI_NCR_PROFILE_SUPPORT
 	else if	((arg_len = is_keyword(ptr, len, "clearprof")) != 0)
 		uc->cmd = UC_CLEARPROF;
+#endif
 	else
 		arg_len = 0;
 
@@ -11008,6 +13711,8 @@
 	case UC_SETTAGS:
 	case UC_SETWIDE:
 	case UC_SETFLAG:
+	case UC_RESETDEV:
+	case UC_CLEARDEV:
 		SKIP_SPACES(1);
 		if ((arg_len = is_keyword(ptr, len, "all")) != 0) {
 			ptr += arg_len; len -= arg_len;
@@ -11051,14 +13756,12 @@
 				uc->data |= DEBUG_ALLOC;
 			else if	((arg_len = is_keyword(ptr, len, "phase")))
 				uc->data |= DEBUG_PHASE;
-			else if	((arg_len = is_keyword(ptr, len, "poll")))
-				uc->data |= DEBUG_POLL;
 			else if	((arg_len = is_keyword(ptr, len, "queue")))
 				uc->data |= DEBUG_QUEUE;
 			else if	((arg_len = is_keyword(ptr, len, "result")))
 				uc->data |= DEBUG_RESULT;
-			else if	((arg_len = is_keyword(ptr, len, "scatter")))
-				uc->data |= DEBUG_SCATTER;
+			else if	((arg_len = is_keyword(ptr, len, "pointer")))
+				uc->data |= DEBUG_POINTER;
 			else if	((arg_len = is_keyword(ptr, len, "script")))
 				uc->data |= DEBUG_SCRIPT;
 			else if	((arg_len = is_keyword(ptr, len, "tiny")))
@@ -11069,10 +13772,6 @@
 				uc->data |= DEBUG_NEGO;
 			else if	((arg_len = is_keyword(ptr, len, "tags")))
 				uc->data |= DEBUG_TAGS;
-			else if	((arg_len = is_keyword(ptr, len, "freeze")))
-				uc->data |= DEBUG_FREEZE;
-			else if	((arg_len = is_keyword(ptr, len, "restart")))
-				uc->data |= DEBUG_RESTART;
 			else
 				return -EINVAL;
 			ptr += arg_len; len -= arg_len;
@@ -11176,13 +13875,7 @@
 	copy_info(&info, "revision id 0x%x\n",	np->revision_id);
 
 	copy_info(&info, "  IO port address 0x%lx, ", (u_long) np->base_io);
-#ifdef __sparc__
-	copy_info(&info, "IRQ number %s\n", __irq_itoa(np->irq));
-	/* Ok to do this on all archs? */
-	copy_info(&info, "PCI bus %02x device %02x\n", np->pci_bus, np->pci_devfn);
-#else
 	copy_info(&info, "IRQ number %d\n", (int) np->irq);
-#endif
 
 #ifndef NCR_IOMAPPED
 	if (np->reg)
@@ -11190,7 +13883,7 @@
 		                  (u_long) np->reg);
 #endif
 	copy_info(&info, "  Synchronous period factor %d, ", (int) np->minsync);
-	copy_info(&info, "max commands per lun %d\n", SCSI_NCR_MAX_TAGS);
+	copy_info(&info, "max commands per lun %d\n", MAX_TAGS);
 
 	if (driver_setup.debug || driver_setup.verbose > 1) {
 		copy_info(&info, "  Debug flags 0x%x, ", driver_setup.debug);
@@ -11309,9 +14002,7 @@
 static void nvram_stop(ncr_slot *np, u_char *gpreg);
 static void nvram_setBit(ncr_slot *np, u_char write_bit, u_char *gpreg, int bit_mode);
 
-__initfunc(
-static int ncr_get_Symbios_nvram (ncr_slot *np, Symbios_nvram *nvram)
-)
+static int __init ncr_get_Symbios_nvram (ncr_slot *np, Symbios_nvram *nvram)
 {
 	static u_char Symbios_trailer[6] = {0xfe, 0xfe, 0, 0, 0, 0};
 	u_char	gpcntl, gpreg;
@@ -11400,9 +14091,8 @@
 /*
  * Read Symbios NvRAM data and compute checksum.
  */
-__initfunc(
-static u_short nvram_read_data(ncr_slot *np, u_char *data, int len, u_char *gpreg, u_char *gpcntl)
-)
+static u_short __init 
+nvram_read_data(ncr_slot *np, u_char *data, int len, u_char *gpreg, u_char *gpcntl)
 {
 	int	x;
 	u_short	csum;
@@ -11419,9 +14109,7 @@
 /*
  * Send START condition to NVRAM to wake it up.
  */
-__initfunc(
-static void nvram_start(ncr_slot *np, u_char *gpreg)
-)
+static void __init nvram_start(ncr_slot *np, u_char *gpreg)
 {
 	nvram_setBit(np, 1, gpreg, SET_BIT);
 	nvram_setBit(np, 0, gpreg, SET_CLK);
@@ -11433,9 +14121,8 @@
  * WRITE a byte to the NVRAM and then get an ACK to see it was accepted OK,
  * GPIO0 must already be set as an output
  */
-__initfunc(
-static void nvram_write_byte(ncr_slot *np, u_char *ack_data, u_char write_data, u_char *gpreg, u_char *gpcntl)
-)
+static void __init 
+nvram_write_byte(ncr_slot *np, u_char *ack_data, u_char write_data, u_char *gpreg, u_char *gpcntl)
 {
 	int x;
 	
@@ -11449,9 +14136,8 @@
  * READ a byte from the NVRAM and then send an ACK to say we have got it,
  * GPIO0 must already be set as an input
  */
-__initfunc(
-static void nvram_read_byte(ncr_slot *np, u_char *read_data, u_char ack_data, u_char *gpreg, u_char *gpcntl)
-)
+static void __init 
+nvram_read_byte(ncr_slot *np, u_char *read_data, u_char ack_data, u_char *gpreg, u_char *gpcntl)
 {
 	int x;
 	u_char read_bit;
@@ -11469,9 +14155,8 @@
  * Output an ACK to the NVRAM after reading,
  * change GPIO0 to output and when done back to an input
  */
-__initfunc(
-static void nvram_writeAck(ncr_slot *np, u_char write_bit, u_char *gpreg, u_char *gpcntl)
-)
+static void __init 
+nvram_writeAck(ncr_slot *np, u_char write_bit, u_char *gpreg, u_char *gpcntl)
 {
 	OUTB (nc_gpcntl, *gpcntl & 0xfe);
 	nvram_doBit(np, 0, write_bit, gpreg);
@@ -11482,9 +14167,8 @@
  * Input an ACK from NVRAM after writing,
  * change GPIO0 to input and when done back to an output
  */
-__initfunc(
-static void nvram_readAck(ncr_slot *np, u_char *read_bit, u_char *gpreg, u_char *gpcntl)
-)
+static void __init 
+nvram_readAck(ncr_slot *np, u_char *read_bit, u_char *gpreg, u_char *gpcntl)
 {
 	OUTB (nc_gpcntl, *gpcntl | 0x01);
 	nvram_doBit(np, read_bit, 1, gpreg);
@@ -11495,9 +14179,8 @@
  * Read or write a bit to the NVRAM,
  * read if GPIO0 input else write if GPIO0 output
  */
-__initfunc(
-static void nvram_doBit(ncr_slot *np, u_char *read_bit, u_char write_bit, u_char *gpreg)
-)
+static void __init 
+nvram_doBit(ncr_slot *np, u_char *read_bit, u_char write_bit, u_char *gpreg)
 {
 	nvram_setBit(np, write_bit, gpreg, SET_BIT);
 	nvram_setBit(np, 0, gpreg, SET_CLK);
@@ -11510,9 +14193,7 @@
 /*
  * Send STOP condition to NVRAM - puts NVRAM to sleep... ZZzzzz!!
  */
-__initfunc(
-static void nvram_stop(ncr_slot *np, u_char *gpreg)
-)
+static void __init nvram_stop(ncr_slot *np, u_char *gpreg)
 {
 	nvram_setBit(np, 0, gpreg, SET_CLK);
 	nvram_setBit(np, 1, gpreg, SET_BIT);
@@ -11521,9 +14202,8 @@
 /*
  * Set/clear data/clock bit in GPIO0
  */
-__initfunc(
-static void nvram_setBit(ncr_slot *np, u_char write_bit, u_char *gpreg, int bit_mode)
-)
+static void __init 
+nvram_setBit(ncr_slot *np, u_char write_bit, u_char *gpreg, int bit_mode)
 {
 	UDELAY (5);
 	switch (bit_mode){
@@ -11574,9 +14254,7 @@
 static void Tnvram_Stop(ncr_slot *np, u_char *gpreg);
 static void Tnvram_Clk(ncr_slot *np, u_char *gpreg);
 
-__initfunc(
-static int ncr_get_Tekram_nvram (ncr_slot *np, Tekram_nvram *nvram)
-)
+static int __init ncr_get_Tekram_nvram (ncr_slot *np, Tekram_nvram *nvram)
 {
 	u_char gpcntl, gpreg;
 	u_char old_gpcntl, old_gpreg;
@@ -11611,9 +14289,8 @@
 /*
  * Read Tekram NvRAM data and compute checksum.
  */
-__initfunc(
-static u_short Tnvram_read_data(ncr_slot *np, u_short *data, int len, u_char *gpreg)
-)
+static u_short __init 
+Tnvram_read_data(ncr_slot *np, u_short *data, int len, u_char *gpreg)
 {
 	u_char	read_bit;
 	u_short	csum;
@@ -11638,9 +14315,8 @@
 /*
  * Send read command and address to NVRAM
  */
-__initfunc(
-static void Tnvram_Send_Command(ncr_slot *np, u_short write_data, u_char *read_bit, u_char *gpreg)
-)
+static void __init 
+Tnvram_Send_Command(ncr_slot *np, u_short write_data, u_char *read_bit, u_char *gpreg)
 {
 	int x;
 
@@ -11654,9 +14330,8 @@
 /*
  * READ a byte from the NVRAM
  */
-__initfunc(
-static void Tnvram_Read_Word(ncr_slot *np, u_short *nvram_data, u_char *gpreg)
-)
+static void __init 
+Tnvram_Read_Word(ncr_slot *np, u_short *nvram_data, u_char *gpreg)
 {
 	int x;
 	u_char read_bit;
@@ -11675,9 +14350,8 @@
 /* 
  * Read bit from NVRAM
  */
-__initfunc(
-static void Tnvram_Read_Bit(ncr_slot *np, u_char *read_bit, u_char *gpreg)
-)
+static void __init 
+Tnvram_Read_Bit(ncr_slot *np, u_char *read_bit, u_char *gpreg)
 {
 	UDELAY (2);
 	Tnvram_Clk(np, gpreg);
@@ -11687,9 +14361,8 @@
 /*
  * Write bit to GPIO0
  */
-__initfunc(
-static void Tnvram_Write_Bit(ncr_slot *np, u_char write_bit, u_char *gpreg)
-)
+static void __init 
+Tnvram_Write_Bit(ncr_slot *np, u_char write_bit, u_char *gpreg)
 {
 	if (write_bit & 0x01)
 		*gpreg |= 0x02;
@@ -11707,9 +14380,7 @@
 /*
  * Send STOP condition to NVRAM - puts NVRAM to sleep... ZZZzzz!!
  */
-__initfunc(
-static void Tnvram_Stop(ncr_slot *np, u_char *gpreg)
-)
+static void __init Tnvram_Stop(ncr_slot *np, u_char *gpreg)
 {
 	*gpreg &= 0xef;
 	OUTB (nc_gpreg, *gpreg);
@@ -11721,9 +14392,7 @@
 /*
  * Pulse clock bit in GPIO0
  */
-__initfunc(
-static void Tnvram_Clk(ncr_slot *np, u_char *gpreg)
-)
+static void __init Tnvram_Clk(ncr_slot *np, u_char *gpreg)
 {
 	OUTB (nc_gpreg, *gpreg | 0x04);
 	UDELAY (2);
Index: oldkernel/linux/drivers/scsi/sym53c8xx.h
diff -u linux/drivers/scsi/sym53c8xx.h:1.1.1.1 linux/drivers/scsi/sym53c8xx.h:1.2
--- linux/drivers/scsi/sym53c8xx.h:1.1.1.1	Wed May 31 12:33:52 2000
+++ linux/drivers/scsi/sym53c8xx.h	Fri Jul  7 15:36:43 2000
@@ -1,7 +1,7 @@
 /******************************************************************************
 **  High Performance device driver for the Symbios 53C896 controller.
 **
-**  Copyright (C) 1998  Gerard Roudier <groudier@club-internet.fr>
+**  Copyright (C) 1998-1999  Gerard Roudier <groudier@club-internet.fr>
 **
 **  This driver also supports all the Symbios 53C8XX controller family, 
 **  except 53C810 revisions < 16, 53C825 revisions < 16 and all 
Index: oldkernel/linux/drivers/scsi/sym53c8xx_defs.h
diff -u linux/drivers/scsi/sym53c8xx_defs.h:1.2 linux/drivers/scsi/sym53c8xx_defs.h:1.3
--- linux/drivers/scsi/sym53c8xx_defs.h:1.2	Wed May 31 14:44:58 2000
+++ linux/drivers/scsi/sym53c8xx_defs.h	Fri Jul  7 15:36:43 2000
@@ -1,7 +1,7 @@
 /******************************************************************************
 **  High Performance device driver for the Symbios 53C896 controller.
 **
-**  Copyright (C) 1998  Gerard Roudier <groudier@club-internet.fr>
+**  Copyright (C) 1998-1999  Gerard Roudier <groudier@club-internet.fr>
 **
 **  This driver also supports all the Symbios 53C8XX controller family, 
 **  except 53C810 revisions < 16, 53C825 revisions < 16 and all 
@@ -66,9 +66,8 @@
 #endif
 #include <linux/config.h>
 
-#ifndef LinuxVersionCode
 #define LinuxVersionCode(v, p, s) (((v)<<16)+((p)<<8)+(s))
-#endif
+
 /*
  * NCR PQS/PDS special device support.
  */
@@ -103,6 +102,14 @@
 #	define	SCSI_NCR_USER_INFO_SUPPORT
 #endif
 
+/*
+**	To disable integrity checking, do not define the 
+**	following option.
+*/
+#ifdef	CONFIG_SCSI_NCR53C8XX_INTEGRITY_CHECK
+#	define SCSI_NCR_ENABLE_INTEGRITY_CHECK
+#endif
+
 /*==========================================================
 **
 ** nvram settings - #define SCSI_NCR_NVRAM_SUPPORT to enable
@@ -122,10 +129,9 @@
 */
 
 /*
- * For Ultra2 SCSI support option, use special features and allow 40Mhz 
- * synchronous data transfers.
+ * For Ultra2 and Ultra3 SCSI support option, use special features. 
  *
- * Value 5 (default) means:
+ * Value (default) means:
  *	bit 0 : all features enabled, except:
  *		bit 1 : PCI Write And Invalidate.
  *		bit 2 : Data Phase Mismatch handling from SCRIPTS.
@@ -134,17 +140,29 @@
  * enabled by the driver.
  */
 #define	SCSI_NCR_SETUP_SPECIAL_FEATURES		(3)
-#define SCSI_NCR_SETUP_ULTRA_SCSI		(2)
-#define SCSI_NCR_MAX_SYNC			(40)
 
 /*
- * Allow tags from 2 to 64, default 8
+ * For Ultra2 and Ultra3 SCSI support allow 80Mhz synchronous data transfers.
+ * Value means:
+ *  0 - Ultra speeds disabled
+ *  1 - Ultra enabled  (Maximum 20Mtrans/sec)
+ *  2 - Ultra2 enabled (Maximum 40Mtrans/sec)
+ *  3 - Ultra3 enabled (Maximum 80Mtrans/sec)
+ *
+ * Use boot options sym53c8xx=ultra:3 to enable Ultra3 support.
  */
+
+#define SCSI_NCR_SETUP_ULTRA_SCSI		(3)
+#define SCSI_NCR_MAX_SYNC			(80)
+
+/*
+ * Allow tags from 2 to 256, default 8
+ */
 #ifdef	CONFIG_SCSI_NCR53C8XX_MAX_TAGS
 #if	CONFIG_SCSI_NCR53C8XX_MAX_TAGS < 2
 #define SCSI_NCR_MAX_TAGS	(2)
-#elif	CONFIG_SCSI_NCR53C8XX_MAX_TAGS > 64
-#define SCSI_NCR_MAX_TAGS	(64)
+#elif	CONFIG_SCSI_NCR53C8XX_MAX_TAGS > 256
+#define SCSI_NCR_MAX_TAGS	(256)
 #else
 #define	SCSI_NCR_MAX_TAGS	CONFIG_SCSI_NCR53C8XX_MAX_TAGS
 #endif
@@ -176,8 +194,15 @@
 #endif
 
 /*
+ * Immediate arbitration
+ */
+#if defined(CONFIG_SCSI_NCR53C8XX_IARB)
+#define SCSI_NCR_IARB_SUPPORT
+#endif
+
+/*
  * Sync transfer frequency at startup.
- * Allow from 5Mhz to 40Mhz default 20 Mhz.
+ * Allow from 5Mhz to 80Mhz default 20 Mhz.
  */
 #ifndef	CONFIG_SCSI_NCR53C8XX_SYNC
 #define	CONFIG_SCSI_NCR53C8XX_SYNC	(20)
@@ -194,8 +219,10 @@
 #define	SCSI_NCR_SETUP_DEFAULT_SYNC	(250/(CONFIG_SCSI_NCR53C8XX_SYNC))
 #elif	CONFIG_SCSI_NCR53C8XX_SYNC <= 33
 #define	SCSI_NCR_SETUP_DEFAULT_SYNC	(11)
-#else
+#elif	CONFIG_SCSI_NCR53C8XX_SYNC <= 40
 #define	SCSI_NCR_SETUP_DEFAULT_SYNC	(10)
+#else
+#define	SCSI_NCR_SETUP_DEFAULT_SYNC 	(9)
 #endif
 
 /*
@@ -251,6 +278,57 @@
 #define SCSI_NCR_SETUP_SETTLE_TIME	(2)
 
 /*
+**	Bridge quirks work-around option defaulted to 1.
+*/
+#ifndef	SCSI_NCR_PCIQ_WORK_AROUND_OPT
+#define	SCSI_NCR_PCIQ_WORK_AROUND_OPT	1
+#endif
+
+/*
+**	Work-around common bridge misbehaviour.
+**
+**	- Do not flush posted writes in the opposite 
+**	  direction on read.
+**	- May reorder DMA writes to memory.
+**
+**	This option should not affect performances 
+**	significantly, so it is the default.
+*/
+#if	SCSI_NCR_PCIQ_WORK_AROUND_OPT == 1
+#define	SCSI_NCR_PCIQ_MAY_NOT_FLUSH_PW_UPSTREAM
+#define	SCSI_NCR_PCIQ_MAY_REORDER_WRITES
+#define	SCSI_NCR_PCIQ_MAY_MISS_COMPLETIONS
+
+/*
+**	Same as option 1, but also deal with 
+**	misconfigured interrupts.
+**
+**	- Edge triggerred instead of level sensitive.
+**	- No interrupt line connected.
+**	- IRQ number misconfigured.
+**	
+**	If no interrupt is delivered, the driver will 
+**	catch the interrupt conditions 10 times per 
+**	second. No need to say that this option is 
+**	not recommended.
+*/
+#elif	SCSI_NCR_PCIQ_WORK_AROUND_OPT == 2
+#define	SCSI_NCR_PCIQ_MAY_NOT_FLUSH_PW_UPSTREAM
+#define	SCSI_NCR_PCIQ_MAY_REORDER_WRITES
+#define	SCSI_NCR_PCIQ_MAY_MISS_COMPLETIONS
+#define	SCSI_NCR_PCIQ_BROKEN_INTR
+
+/*
+**	Some bridge designers decided to flush 
+**	everything prior to deliver the interrupt.
+**	This option tries to deal with such a 
+**	behaviour.
+*/
+#elif	SCSI_NCR_PCIQ_WORK_AROUND_OPT == 3
+#define	SCSI_NCR_PCIQ_SYNC_ON_INTR
+#endif
+
+/*
 **	Other parameters not configurable with "make config"
 **	Avoid to change these constants, unless you know what you are doing.
 */
@@ -258,17 +336,17 @@
 #define SCSI_NCR_ALWAYS_SIMPLE_TAG
 #define SCSI_NCR_MAX_SCATTER	(127)
 #define SCSI_NCR_MAX_TARGET	(16)
-
-/* No need to use a too large adapter queue */
-#if SCSI_NCR_MAX_TAGS <= 32
-#define SCSI_NCR_CAN_QUEUE	(7*SCSI_NCR_MAX_TAGS)
-#else
-#define SCSI_NCR_CAN_QUEUE	(250)
-#endif
 
+/*
+**   Compute some desirable value for CAN_QUEUE 
+**   and CMD_PER_LUN.
+**   The driver will use lower values if these 
+**   ones appear to be too large.
+*/
+#define SCSI_NCR_CAN_QUEUE	(8*SCSI_NCR_MAX_TAGS + 2*SCSI_NCR_MAX_TARGET)
 #define SCSI_NCR_CMD_PER_LUN	(SCSI_NCR_MAX_TAGS)
-#define SCSI_NCR_SG_TABLESIZE	(SCSI_NCR_MAX_SCATTER)
 
+#define SCSI_NCR_SG_TABLESIZE	(SCSI_NCR_MAX_SCATTER)
 #define SCSI_NCR_TIMER_INTERVAL	(HZ)
 
 #if 1 /* defined CONFIG_SCSI_MULTI_LUN */
@@ -280,6 +358,18 @@
 #ifndef HOSTS_C
 
 /*
+**	These simple macros limit expression involving 
+**	kernel time values (jiffies) to some that have 
+**	chance not to be too much incorrect. :-)
+*/
+#define ktime_get(o)		(jiffies + (u_long) o)
+#define ktime_exp(b)		((long)(jiffies) - (long)(b) >= 0)
+#define ktime_dif(a, b)		((long)(a) - (long)(b))
+/* These ones are not used in this driver */
+#define ktime_add(a, o)		((a) + (u_long)(o))
+#define ktime_sub(a, o)		((a) - (u_long)(o))
+
+/*
 **	IO functions definition for big/little endian support.
 **	For now, the NCR is only supported in little endian addressing mode, 
 **	and big endian byte ordering is only supported for the PPC.
@@ -389,8 +479,8 @@
 #define PCI_DEVICE_ID_NCR_53C895A 0x12
 #endif
 
-#ifndef PCI_DEVICE_ID_NCR_53C1510D
-#define PCI_DEVICE_ID_NCR_53C1510D 0xa
+#ifndef PCI_DEVICE_ID_LSI_53C1010
+#define PCI_DEVICE_ID_LSI_53C1010 0x20
 #endif
 
 /*
@@ -400,31 +490,35 @@
 	unsigned short	device_id;
 	unsigned short	revision_id;
 	char	*name;
-	unsigned char	burst_max;
+	unsigned char	burst_max;	/* log-base-2 of max burst */
 	unsigned char	offset_max;
 	unsigned char	nr_divisor;
 	unsigned int	features;
 #define FE_LED0		(1<<0)
-#define FE_WIDE		(1<<1)
-#define FE_ULTRA	(1<<2)
-#define FE_ULTRA2	(1<<3)
-#define FE_DBLR		(1<<4)
-#define FE_QUAD		(1<<5)
-#define FE_ERL		(1<<6)
-#define FE_CLSE		(1<<7)
-#define FE_WRIE		(1<<8)
-#define FE_ERMP		(1<<9)
-#define FE_BOF		(1<<10)
-#define FE_DFS		(1<<11)
-#define FE_PFEN		(1<<12)
-#define FE_LDSTR	(1<<13)
-#define FE_RAM		(1<<14)
-#define FE_CLK80	(1<<15)
-#define FE_RAM8K	(1<<16)
-#define FE_64BIT	(1<<17)
-#define FE_IO256	(1<<18)
-#define FE_NOPM		(1<<19)
-#define FE_LEDC		(1<<20)
+#define FE_WIDE		(1<<1)    /* Wide data transfers */
+#define FE_ULTRA	(1<<2)	  /* Ultra speed 20Mtrans/sec */
+#define FE_ULTRA2	(1<<3)	  /* Ultra 2 - 40 Mtrans/sec */
+#define FE_DBLR		(1<<4)	  /* Clock doubler present */
+#define FE_QUAD		(1<<5)	  /* Clock quadrupler present */
+#define FE_ERL		(1<<6)    /* Enable read line */
+#define FE_CLSE		(1<<7)    /* Cache line size enable */
+#define FE_WRIE		(1<<8)    /* Write & Invalidate enable */
+#define FE_ERMP		(1<<9)    /* Enable read multiple */
+#define FE_BOF		(1<<10)   /* Burst opcode fetch */
+#define FE_DFS		(1<<11)   /* DMA fifo size */
+#define FE_PFEN		(1<<12)   /* Prefetch enable */
+#define FE_LDSTR	(1<<13)   /* Load/Store supported */
+#define FE_RAM		(1<<14)   /* On chip RAM present */
+#define FE_CLK80	(1<<15)   /* Board clock is 80 MHz */
+#define FE_RAM8K	(1<<16)   /* On chip RAM sized 8Kb */
+#define FE_64BIT	(1<<17)   /* Supports 64-bit addressing */
+#define FE_IO256	(1<<18)   /* Requires full 256 bytes in PCI space */
+#define FE_NOPM		(1<<19)   /* Scripts handles phase mismatch */
+#define FE_LEDC		(1<<20)   /* Hardware control of LED */
+#define FE_DIFF		(1<<21)   /* Support Differential SCSI */
+#define FE_ULTRA3	(1<<22)   /* Ultra-3 80Mtrans/sec */
+#define FE_66MHZ 	(1<<23)   /* 66MHz PCI Support */
+
 #define FE_CACHE_SET	(FE_ERL|FE_CLSE|FE_WRIE|FE_ERMP)
 #define FE_SCSI_SET	(FE_WIDE|FE_ULTRA|FE_ULTRA2|FE_DBLR|FE_QUAD|F_CLK80)
 #define FE_SPECIAL_SET	(FE_CACHE_SET|FE_BOF|FE_DFS|FE_LDSTR|FE_PFEN|FE_RAM)
@@ -458,49 +552,57 @@
  FE_WIDE|FE_ERL}							\
  ,									\
  {PCI_DEVICE_ID_NCR_53C825, 0x0f, "825",  4,  8, 4,			\
- FE_WIDE|FE_ERL|FE_BOF}							\
+ FE_WIDE|FE_ERL|FE_BOF|FE_DIFF}						\
  ,									\
  {PCI_DEVICE_ID_NCR_53C825, 0xff, "825a", 6,  8, 4,			\
- FE_WIDE|FE_CACHE0_SET|FE_BOF|FE_DFS|FE_LDSTR|FE_PFEN|FE_RAM}		\
+ FE_WIDE|FE_CACHE0_SET|FE_BOF|FE_DFS|FE_LDSTR|FE_PFEN|FE_RAM|FE_DIFF}	\
  ,									\
  {PCI_DEVICE_ID_NCR_53C860, 0xff, "860",  4,  8, 5,			\
  FE_ULTRA|FE_CLK80|FE_CACHE_SET|FE_BOF|FE_LDSTR|FE_PFEN}		\
  ,									\
  {PCI_DEVICE_ID_NCR_53C875, 0x01, "875",  6, 16, 5,			\
- FE_WIDE|FE_ULTRA|FE_CLK80|FE_CACHE0_SET|FE_BOF|FE_DFS|FE_LDSTR|FE_PFEN|FE_RAM}\
+ FE_WIDE|FE_ULTRA|FE_CLK80|FE_CACHE0_SET|FE_BOF|FE_DFS|FE_LDSTR|FE_PFEN|\
+ FE_RAM|FE_DIFF}							\
  ,									\
  {PCI_DEVICE_ID_NCR_53C875, 0x0f, "875",  6, 16, 5,			\
- FE_WIDE|FE_ULTRA|FE_DBLR|FE_CACHE0_SET|FE_BOF|FE_DFS|FE_LDSTR|FE_PFEN|FE_RAM}\
+ FE_WIDE|FE_ULTRA|FE_DBLR|FE_CACHE0_SET|FE_BOF|FE_DFS|FE_LDSTR|FE_PFEN|	\
+ FE_RAM|FE_DIFF}							\
  ,									\
  {PCI_DEVICE_ID_NCR_53C875, 0x1f, "876",  6, 16, 5,			\
- FE_WIDE|FE_ULTRA|FE_DBLR|FE_CACHE0_SET|FE_BOF|FE_DFS|FE_LDSTR|FE_PFEN|FE_RAM}\
+ FE_WIDE|FE_ULTRA|FE_DBLR|FE_CACHE0_SET|FE_BOF|FE_DFS|FE_LDSTR|FE_PFEN|	\
+ FE_RAM|FE_DIFF}							\
  ,									\
  {PCI_DEVICE_ID_NCR_53C875, 0x2f, "875E",  6, 16, 5,			\
- FE_WIDE|FE_ULTRA|FE_DBLR|FE_CACHE0_SET|FE_BOF|FE_DFS|FE_LDSTR|FE_PFEN|FE_RAM}\
+ FE_WIDE|FE_ULTRA|FE_DBLR|FE_CACHE0_SET|FE_BOF|FE_DFS|FE_LDSTR|FE_PFEN|	\
+ FE_RAM|FE_DIFF}							\
  ,									\
  {PCI_DEVICE_ID_NCR_53C875, 0xff, "876",  6, 16, 5,			\
- FE_WIDE|FE_ULTRA|FE_DBLR|FE_CACHE0_SET|FE_BOF|FE_DFS|FE_LDSTR|FE_PFEN|FE_RAM}\
+ FE_WIDE|FE_ULTRA|FE_DBLR|FE_CACHE0_SET|FE_BOF|FE_DFS|FE_LDSTR|FE_PFEN|	\
+ FE_RAM|FE_DIFF}							\
  ,									\
  {PCI_DEVICE_ID_NCR_53C875J,0xff, "875J", 6, 16, 5,			\
- FE_WIDE|FE_ULTRA|FE_DBLR|FE_CACHE0_SET|FE_BOF|FE_DFS|FE_LDSTR|FE_PFEN|FE_RAM}\
+ FE_WIDE|FE_ULTRA|FE_DBLR|FE_CACHE0_SET|FE_BOF|FE_DFS|FE_LDSTR|FE_PFEN|	\
+ FE_RAM}								\
  ,									\
  {PCI_DEVICE_ID_NCR_53C885, 0xff, "885",  6, 16, 5,			\
- FE_WIDE|FE_ULTRA|FE_DBLR|FE_CACHE0_SET|FE_BOF|FE_DFS|FE_LDSTR|FE_PFEN|FE_RAM}\
+ FE_WIDE|FE_ULTRA|FE_DBLR|FE_CACHE0_SET|FE_BOF|FE_DFS|FE_LDSTR|FE_PFEN|	\
+ FE_RAM|FE_DIFF}							\
  ,									\
  {PCI_DEVICE_ID_NCR_53C895, 0xff, "895",  6, 31, 7,			\
- FE_WIDE|FE_ULTRA2|FE_QUAD|FE_CACHE_SET|FE_BOF|FE_DFS|FE_LDSTR|FE_PFEN|FE_RAM}\
+ FE_WIDE|FE_ULTRA2|FE_QUAD|FE_CACHE_SET|FE_BOF|FE_DFS|FE_LDSTR|FE_PFEN|	\
+ FE_RAM}								\
  ,									\
- {PCI_DEVICE_ID_NCR_53C896, 0xff, "896",  7, 31, 7,			\
- FE_WIDE|FE_ULTRA2|FE_QUAD|FE_CACHE_SET|FE_BOF|FE_DFS|FE_LDSTR|FE_PFEN|FE_RAM|\
- FE_RAM8K|FE_64BIT|FE_IO256|FE_NOPM|FE_LEDC}\
+ {PCI_DEVICE_ID_NCR_53C896, 0xff, "896",  6, 31, 7,			\
+ FE_WIDE|FE_ULTRA2|FE_QUAD|FE_CACHE_SET|FE_BOF|FE_DFS|FE_LDSTR|FE_PFEN|	\
+ FE_RAM|FE_RAM8K|FE_64BIT|FE_IO256|FE_NOPM|FE_LEDC}			\
  ,									\
  {PCI_DEVICE_ID_NCR_53C895A, 0xff, "895a",  6, 31, 7,			\
- FE_WIDE|FE_ULTRA2|FE_QUAD|FE_CACHE_SET|FE_BOF|FE_DFS|FE_LDSTR|FE_PFEN|FE_RAM|\
- FE_RAM8K|FE_64BIT|FE_IO256|FE_NOPM|FE_LEDC}\
+ FE_WIDE|FE_ULTRA2|FE_QUAD|FE_CACHE_SET|FE_BOF|FE_DFS|FE_LDSTR|FE_PFEN|	\
+ FE_RAM|FE_RAM8K|FE_64BIT|FE_IO256|FE_NOPM|FE_LEDC}			\
  ,									\
- {PCI_DEVICE_ID_NCR_53C1510D, 0xff, "1510D",  7, 31, 7,			\
- FE_WIDE|FE_ULTRA2|FE_QUAD|FE_CACHE_SET|FE_BOF|FE_DFS|FE_LDSTR|FE_PFEN|FE_RAM|\
- FE_IO256}\
+ {PCI_DEVICE_ID_LSI_53C1010, 0xff, "1010",  6, 62, 7,			\
+ FE_WIDE|FE_QUAD|FE_CACHE_SET|FE_BOF|FE_DFS|FE_LDSTR|FE_PFEN|		\
+ FE_RAM|FE_RAM8K|FE_64BIT|FE_IO256|FE_NOPM|FE_LEDC|FE_ULTRA3}		\
 }
 
 /*
@@ -519,7 +621,7 @@
 	PCI_DEVICE_ID_NCR_53C895,	\
 	PCI_DEVICE_ID_NCR_53C896,	\
 	PCI_DEVICE_ID_NCR_53C895A,	\
-	PCI_DEVICE_ID_NCR_53C1510D	\
+	PCI_DEVICE_ID_LSI_53C1010	\
 }
 
 /*
@@ -553,7 +655,8 @@
 	u_char	optimize;
 	u_char	recovery;
 	u_char	host_id;
-	u_int	excludes[SCSI_NCR_MAX_EXCLUDES];
+	u_short	iarb;
+	u_long	excludes[SCSI_NCR_MAX_EXCLUDES];
 	char	tag_ctrl[100];
 };
 
@@ -585,7 +688,8 @@
 	1,					\
 	0,					\
 	0,					\
-	255					\
+	255,					\
+	0x00					\
 }
 
 /*
@@ -764,6 +868,7 @@
 /*01*/  u_char    nc_scntl1;    /* no reset                         */
         #define   ISCON   0x10  /* connected to scsi		    */
         #define   CRST    0x08  /* force reset                      */
+        #define   IARB    0x02  /* immediate arbitration            */
 
 /*02*/  u_char    nc_scntl2;    /* no disconnect expected           */
 	#define   SDU     0x80  /* cmd: disconnect will raise error */
@@ -774,12 +879,14 @@
 /*03*/  u_char    nc_scntl3;    /* cnf system clock dependent       */
 	#define   EWS     0x08  /* cmd: enable wide scsi         [W]*/
 	#define   ULTRA   0x80  /* cmd: ULTRA enable                */
+				/* bits 0-2, 7 rsvd for C1010       */
 
 /*04*/  u_char    nc_scid;	/* cnf host adapter scsi address    */
 	#define   RRE     0x40  /* r/w:e enable response to resel.  */
 	#define   SRE     0x20  /* r/w:e enable response to select  */
 
 /*05*/  u_char    nc_sxfer;	/* ### Sync speed and count         */
+				/* bits 6-7 rsvd for C1010          */
 
 /*06*/  u_char    nc_sdid;	/* ### Destination-ID               */
 
@@ -830,7 +937,10 @@
         #define   DM      0x04  /* sta: DIFFSENS mismatch (895/6 only) */
         #define   LDSC    0x02  /* sta: disconnect & reconnect      */
 
-/*10*/  u_int32    nc_dsa;	/* --> Base page                    */
+/*10*/  u_char    nc_dsa;	/* --> Base page                    */
+/*11*/  u_char    nc_dsa1;
+/*12*/  u_char    nc_dsa2;
+/*13*/  u_char    nc_dsa3;
 
 /*14*/  u_char    nc_istat;	/* --> Main Command and status      */
         #define   CABRT   0x80  /* cmd: abort current operation     */
@@ -851,12 +961,14 @@
 
 /*1a*/  u_char    nc_ctest2;
 	#define   CSIGP   0x40
+				/* bits 0-2,7 rsvd for C1010        */
 
 /*1b*/  u_char    nc_ctest3;
 	#define   FLF     0x08  /* cmd: flush dma fifo              */
 	#define   CLF	  0x04	/* cmd: clear dma fifo		    */
 	#define   FM      0x02  /* mod: fetch pin mode              */
 	#define   WRIE    0x01  /* mod: write and invalidate enable */
+				/* bits 4-7 rsvd for C1010          */
 
 /*1c*/  u_int32    nc_temp;	/* ### Temporary stack              */
 
@@ -867,6 +979,7 @@
 
 /*22*/  u_char    nc_ctest5;
 	#define   DFS     0x20  /* mod: dma fifo size               */
+				/* bits 0-1, 3-7 rsvd for C1010          */
 /*23*/  u_char    nc_ctest6;
 
 /*24*/  u_int32    nc_dbc;	/* ### Byte count and command       */
@@ -887,7 +1000,7 @@
 	#define   BOF     0x02  /* mod: burst op code fetch         */
 
 /*39*/  u_char    nc_dien;
-/*3a*/  u_char    nc_dwt;
+/*3a*/  u_char    nc_sbr;
 
 /*3b*/  u_char    nc_dcntl;	/* --> Script execution control     */
 	#define   CLSE    0x80  /* mod: cache line size enable      */
@@ -898,6 +1011,7 @@
 	#define   STD     0x04  /* cmd: start dma mode              */
 	#define   IRQD    0x02  /* mod: irq disable                 */
  	#define	  NOCOM   0x01	/* cmd: protect sfbr while reselect */
+				/* bits 0-1 rsvd for C1010          */
 
 /*3c*/  u_int32    nc_adder;
 
@@ -927,6 +1041,7 @@
 /*4c*/  u_char    nc_stest0;
 
 /*4d*/  u_char    nc_stest1;
+	#define   SCLK    0x80	/* Use the PCI clock as SCSI clock	*/
 	#define   DBLEN   0x08	/* clock doubler running		*/
 	#define   DBLSEL  0x04	/* clock doubler selected		*/
   
@@ -947,6 +1062,7 @@
 	#define    SMODE_SE  0x80	/* Single Ended                    */
 	#define    SMODE_LVD 0xc0	/* Low Voltage Differential        */
 	#define   LCKFRQ 0x20	/* Frequency Lock (895/6 only)     */
+				/* bits 0-5 rsvd for C1010          */
 
 /*53*/  u_char    nc_53_;
 /*54*/  u_short   nc_sodl;	/* Lowlevel: data out to scsi data  */
@@ -960,6 +1076,7 @@
 
 /*57*/	u_char    nc_ccntl1;	/* Chip Control 1 (896)             */
 	#define   ZMOD   0x80	/* High Impedance Mode              */
+	#define	  DIC	 0x10	/* Disable Internal Cycles	    */
 	#define   DDAC   0x08	/* Disable Dual Address Cycle       */
 	#define   XTIMOD 0x04	/* 64-bit Table Ind. Indexing Mode  */
 	#define   EXTIBMV 0x02	/* Enable 64-bit Table Ind. BMOV    */
@@ -981,12 +1098,27 @@
 /*b0*/	u_int32   nc_sbms;	/* Static Block Move Selector       */
 /*b4*/	u_int32   nc_dbms;	/* Dynamic Block Move Selector      */
 /*b8*/	u_int32   nc_dnad64;	/* DMA Next Address 64              */
-/*bc*/	u_int32   nc_bc_;
+/*bc*/	u_short   nc_scntl4;    /* C1010 only                       */
+	#define   U3EN   0x80	/* Enable Ultra 3                   */
+	#define   AIPEN	 0x40   /* Allow check upper byte lanes     */
+	#define   XCLKH_DT 0x08 /* Extra clock of data hold on DT
+					transfer edge	            */
+	#define   XCLKH_ST 0x04 /* Extra clock of data hold on ST
+					transfer edge	            */
 
+/*be*/  u_short   nc_aipcntl;	/* Epat Control 1 C1010 only        */
+
 /*c0*/	u_int32   nc_pmjad1;	/* Phase Mismatch Jump Address 1    */
 /*c4*/	u_int32   nc_pmjad2;	/* Phase Mismatch Jump Address 2    */
-/*c8*/	u_int32   nc_rbc;	/* Remaining Byte Count             */
-/*cc*/	u_int32   nc_ua;	/* Updated Address                  */
+/*c8*/	u_char    nc_rbc;	/* Remaining Byte Count             */
+/*c9*/	u_char    nc_rbc1;	/*                                  */
+/*ca*/	u_char    nc_rbc2;	/*                                  */
+/*cb*/	u_char    nc_rbc3;	/*                                  */
+
+/*cc*/	u_char    nc_ua;	/* Updated Address                  */
+/*cd*/	u_char    nc_ua1;	/*                                  */
+/*ce*/	u_char    nc_ua2;	/*                                  */
+/*cf*/	u_char    nc_ua3;	/*                                  */
 /*d0*/	u_int32   nc_esa;	/* Entry Storage Address            */
 /*d4*/	u_char    nc_ia;	/* Instruction Address              */
 /*d5*/	u_char    nc_ia1;
@@ -994,6 +1126,17 @@
 /*d7*/	u_char    nc_ia3;
 /*d8*/	u_int32   nc_sbc;	/* SCSI Byte Count (3 bytes only)   */
 /*dc*/	u_int32   nc_csbc;	/* Cumulative SCSI Byte Count       */
+
+                                /* Following for C1010 only         */
+/*e0*/ u_short    nc_crcpad;    /* CRC Value                        */
+/*e2*/ u_char     nc_crccntl0;  /* CRC control register             */
+	#define   SNDCRC  0x10	/* Send CRC Request                 */
+/*e3*/ u_char     nc_crccntl1;  /* CRC control register             */
+/*e4*/ u_int32    nc_crcdata;   /* CRC data register                */ 
+/*e8*/ u_int32	  nc_e8_;	/* rsvd 			    */
+/*ec*/ u_int32	  nc_ec_;	/* rsvd 			    */
+/*f0*/ u_short    nc_dfbc;      /* DMA FIFO byte count              */ 
+
 };
 
 /*-----------------------------------------------------------
@@ -1006,16 +1149,14 @@
 #define REGJ(p,r) (offsetof(struct ncr_reg, p ## r))
 #define REG(r) REGJ (nc_, r)
 
-#ifndef TARGET_MODE
-#define TARGET_MODE 0
-#endif
-
 typedef u_int32 ncrcmd;
 
 /*-----------------------------------------------------------
 **
 **	SCSI phases
 **
+**	DT phases illegal for ncr driver.
+**
 **-----------------------------------------------------------
 */
 
@@ -1023,11 +1164,14 @@
 #define	SCR_DATA_IN	0x01000000
 #define	SCR_COMMAND	0x02000000
 #define	SCR_STATUS	0x03000000
-#define SCR_ILG_OUT	0x04000000
-#define SCR_ILG_IN	0x05000000
+#define SCR_DT_DATA_OUT	0x04000000
+#define SCR_DT_DATA_IN	0x05000000
 #define SCR_MSG_OUT	0x06000000
 #define SCR_MSG_IN      0x07000000
 
+#define SCR_ILG_OUT	0x04000000
+#define SCR_ILG_IN	0x05000000
+
 /*-----------------------------------------------------------
 **
 **	Data transfer via SCSI.
@@ -1045,10 +1189,16 @@
 **
 **-----------------------------------------------------------
 */
+
+#define OPC_MOVE          0x08000000
 
-#define SCR_MOVE_ABS(l) ((0x08000000 ^ (TARGET_MODE << 1ul)) | (l))
-#define SCR_MOVE_IND(l) ((0x28000000 ^ (TARGET_MODE << 1ul)) | (l))
-#define SCR_MOVE_TBL     (0x18000000 ^ (TARGET_MODE << 1ul))
+#define SCR_MOVE_ABS(l) ((0x00000000 | OPC_MOVE) | (l))
+#define SCR_MOVE_IND(l) ((0x20000000 | OPC_MOVE) | (l))
+#define SCR_MOVE_TBL     (0x10000000 | OPC_MOVE)
+
+#define SCR_CHMOV_ABS(l) ((0x00000000) | (l))
+#define SCR_CHMOV_IND(l) ((0x20000000) | (l))
+#define SCR_CHMOV_TBL     (0x10000000)
 
 struct scr_tblmove {
         u_int32  size;
@@ -1061,7 +1211,7 @@
 **
 **-----------------------------------------------------------
 **
-**	SEL_ABS | SCR_ID (0..7)     [ | REL_JMP]
+**	SEL_ABS | SCR_ID (0..15)    [ | REL_JMP]
 **	<<alternate_address>>
 **
 **	SEL_TBL | << dnad_offset>>  [ | REL_JMP]
@@ -1076,7 +1226,7 @@
 #define	SCR_SEL_TBL_ATN	0x43000000
 
 struct scr_tblsel {
-        u_char  sel_0;
+        u_char  sel_scntl4;	
         u_char  sel_sxfer;
         u_char  sel_id;
         u_char  sel_scntl3;
@@ -1295,7 +1445,7 @@
 **	Conditions:
 **	     WHEN (phase)
 **	     IF   (phase)
-**	     CARRY
+**	     CARRYSET
 **	     DATA (data, mask)
 **
 **-----------------------------------------------------------
@@ -1360,6 +1510,7 @@
 #define	M_X_MODIFY_DP	(0x00)
 #define	M_X_SYNC_REQ	(0x01)
 #define	M_X_WIDE_REQ	(0x03)
+#define	M_X_PPR_REQ	(0x04)
 
 /*
 **	Status
Index: oldkernel/linux/drivers/scsi/aic7xxx/aic7xxx.seq
diff -u linux/drivers/scsi/aic7xxx/aic7xxx.seq:1.3 linux/drivers/scsi/aic7xxx/aic7xxx.seq:1.4
--- linux/drivers/scsi/aic7xxx/aic7xxx.seq:1.3	Thu Jun  1 15:46:48 2000
+++ linux/drivers/scsi/aic7xxx/aic7xxx.seq	Fri Jul  7 15:36:43 2000
@@ -182,6 +182,15 @@
 		and	SCSIID, OID;		/* Clear old target */
 		or	SCSIID, A;
 	}
+	mov	SCSIDATL, ALLZEROS;		/* clear out the latched */
+						/* data register, this */
+						/* fixes a bug on some */
+						/* controllers where the */
+						/* last byte written to */
+						/* this register can leak */
+						/* onto the data bus at */
+						/* bad times, such as during */
+						/* selection timeouts */
 	mvi	SCSISEQ, ENSELO|ENAUTOATNO|ENRSELI|ENAUTOATNP ret;
 
 /*
Index: oldkernel/linux/drivers/sound/Config.in
diff -u linux/drivers/sound/Config.in:1.2 linux/drivers/sound/Config.in:1.3
--- linux/drivers/sound/Config.in:1.2	Thu Jun  1 16:52:15 2000
+++ linux/drivers/sound/Config.in	Fri Jul  7 15:36:45 2000
@@ -17,6 +17,7 @@
   fi
 fi
 
+dep_tristate 'Creative SBLive! (EMU10K1)' CONFIG_SOUND_EMU10K1 $CONFIG_SOUND
 dep_tristate 'Ensoniq AudioPCI (ES1370)' CONFIG_SOUND_ES1370 $CONFIG_SOUND
 if [ "$CONFIG_SOUND_ES1370" = "y" ]; then
    bool 'Joystick support at boot time' CONFIG_SOUND_ES1370_JOYPORT_BOOT
@@ -30,7 +31,6 @@
 fi
 
 dep_tristate 'ESS Maestro' CONFIG_SOUND_MAESTRO $CONFIG_SOUND
-dep_tristate 'EMU10K1' CONFIG_SOUND_EMU10K1 $CONFIG_SOUND
 
 if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
    dep_tristate 'ESS Solo1 (Experimental)' CONFIG_SOUND_ESSSOLO1 $CONFIG_SOUND
Index: oldkernel/linux/drivers/sound/Makefile
diff -u linux/drivers/sound/Makefile:1.2 linux/drivers/sound/Makefile:1.3
--- linux/drivers/sound/Makefile:1.2	Thu Jun  1 16:52:15 2000
+++ linux/drivers/sound/Makefile	Fri Jul  7 15:36:45 2000
@@ -17,9 +17,12 @@
     MOD_IN_SUB_DIRS	+= lowlevel
 endif
 
-ifeq ($(CONFIG_SOUND_EMU10K1),m)
-    SUB_DIRS		+= emu10k1
+ifeq ($(CONFIG_SOUND_EMU10K1),y)
+    SUB_DIRS		+= emu10k1 
+else
+  ifeq ($(CONFIG_SOUND_EMU10K1),m)
     MOD_IN_SUB_DIRS	+= emu10k1
+  endif
 endif
 
 
@@ -90,6 +93,10 @@
 obj-$(CONFIG_SOUND_MAESTRO)	+= maestro.o
 obj-$(CONFIG_SOUND_SONICVIBES)	+= sonicvibes.o
 
+ifeq ($(CONFIG_SOUND_EMU10K1),y)
+  obj-y             += emu10k1/emu10k1.o
+endif
+
 # Declare multi-part drivers.
 
 list-multi	:= sound.o gus.o pas2.o sb.o softoss2.o vidc_mod.o \
@@ -164,10 +171,6 @@
 
 ifeq ($(CONFIG_LOWLEVEL_SOUND),y)
     L_OBJS	+= lowlevel/lowlevel.o
-endif
-
-ifeq ($(CONFIG_SOUND_EMU10K1),y)
-	M_OBJS	+= emu10k1/emu10k1.o
 endif
 
 include $(TOPDIR)/Rules.make
Index: oldkernel/linux/drivers/sound/emu10k1/8010.h
diff -u linux/drivers/sound/emu10k1/8010.h:1.1 linux/drivers/sound/emu10k1/8010.h:1.2
--- linux/drivers/sound/emu10k1/8010.h:1.1	Thu Jun  1 16:52:15 2000
+++ linux/drivers/sound/emu10k1/8010.h	Fri Jul  7 15:36:45 2000
@@ -39,15 +39,12 @@
 
 /* ------------------- DEFINES -------------------- */
 
-#define EMUPAGESIZE	4096
-#define MAXREQVOICES	8
-#define MAXPAGES	(16384 * 64 / PAGE_SIZE)	/* WAVEOUT_MAXBUFSIZE * NUM_G / PAGE_SIZE */
+#define EMUPAGESIZE	4096		/* don't change */
 #define RESERVED	0
-#define NUM_MIDI	16
 #define NUM_G		64		/* use all channels */
-#define NUM_FXSENDS	4
+#define NUM_FXSENDS	4		/* don't change */
+#define MAXPAGES        (32768 * NUM_G / EMUPAGESIZE)      /* WAVEOUT_MAXBUFSIZE * NUM_G / EMUPAGESIZE */
 
-
 #define TMEMSIZE	256*1024
 #define TMEMSIZEREG	4
 
@@ -58,15 +55,19 @@
 /************************************************************************************************/
 
 #define PTR			0x00		/* Indexed register set pointer register	*/
+						/* NOTE: The CHANNELNUM and ADDRESS words can	*/
+						/* be modified independently of each other.	*/
 #define PTR_CHANNELNUM_MASK	0x0000003f	/* For each per-channel register, indicates the	*/
-/* channel number of the specific register to be*/
-/* accessed.  For non per-channel registers, the*/
-/* value should be set to zero.			*/
+						/* channel number of the register to be		*/
+						/* accessed.  For non per-channel registers the	*/
+						/* value should be set to zero.			*/
 #define PTR_ADDRESS_MASK	0x07ff0000	/* Register index				*/
 
 #define DATA			0x04		/* Indexed register set data register		*/
 
 #define IPR			0x08		/* Global interrupt pending register		*/
+						/* Clear pending interrupts by writing a 1 to	*/
+						/* the relevant bits and zero to the other bits	*/
 #define IPR_SAMPLERATETRACKER	0x01000000	/* Sample rate tracker lock status change	*/
 #define IPR_FXDSP		0x00800000	/* Enable FX DSP interrupts			*/
 #define IPR_FORCEINT		0x00400000	/* Force Sound Blaster interrupt		*/
@@ -87,7 +88,10 @@
 #define IPR_MIDIRECVBUFEMPTY	0x00000080	/* MIDI UART receive buffer empty		*/
 #define IPR_CHANNELLOOP		0x00000040	/* One or more channel loop interrupts pending	*/
 #define IPR_CHANNELNUMBERMASK	0x0000003f	/* When IPR_CHANNELLOOP is set, indicates the	*/
-/* Highest set channel in [finish]		*/
+						/* Highest set channel in CLIPL or CLIPH.  When	*/
+						/* IP is written with CL set, the bit in CLIPL	*/
+						/* or CLIPH corresponding to the CIN value 	*/
+						/* written will be cleared.			*/
 
 #define INTE			0x0c		/* Interrupt enable register			*/
 #define INTE_VIRTUALSB_MASK	0xc0000000	/* Virtual Soundblaster I/O port capture	*/
@@ -110,10 +114,13 @@
 #define INTE_FORCEINT		0x00100000	/* Continuously assert INTAN			*/
 
 #define INTE_MRHANDENABLE	0x00080000	/* Enable the "Mr. Hand" logic			*/
-// Not implemented or relevant under Linux.  It will cause odd behaviour
-// and may cause seg faults if implemented
+						/* NOTE: There is no reason to use this under	*/
+						/* Linux, and it will cause odd hardware 	*/
+						/* behavior and possibly random segfaults and	*/
+						/* lockups if enabled.				*/
 
-#define INTE_SAMPLERATETRACKER	0x00002000	/* Enable sample rate tracker interrupts MUST BE ENABLED */
+#define INTE_SAMPLERATETRACKER	0x00002000	/* Enable sample rate tracker interrupts	*/
+						/* NOTE: This bit must always be enabled       	*/
 #define INTE_FXDSPENABLE	0x00001000	/* Enable FX DSP interrupts			*/
 #define INTE_PCIERRORENABLE	0x00000800	/* Enable PCI bus error interrupts		*/
 #define INTE_VOLINCRENABLE	0x00000400	/* Enable volume increment button interrupts	*/
@@ -132,57 +139,81 @@
 #define WC_SAMPLECOUNTER_MASK	0x03FFFFC0	/* Sample periods elapsed since reset		*/
 #define WC_SAMPLECOUNTER	0x14060010
 #define WC_CURRENTCHANNEL	0x0000003F	/* Channel [0..63] currently being serviced	*/
+						/* NOTE: Each channel takes 1/64th of a sample	*/
+						/* period to be serviced.			*/
 
 #define HCFG			0x14		/* Hardware config register			*/
-#define HCFG_LEGACYFUNC_MASK	0xe0000000	/* Legacy function number - DO NOT USE		*/
-#define HCFG_LEGACYFUNC_MPU	0x00000000	/* Legacy MPU - DO NOT USE under Linux		*/
-#define HCFG_LEGACYFUNC_SB	0x40000000	/* Legacy SB - DO NOT USE under Linux		*/
-#define HCFG_LEGACYFUNC_AD	0x60000000	/* Legacy AD - DO NOT USE under Linux		*/
-#define HCFG_LEGACYFUNC_MPIC	0x80000000	/* Legacy MPIC - DO NOT USE under Linux		*/
-#define HCFG_LEGACYFUNC_MDMA	0x90000000	/* Legacy MDMA - DO NOT USE under Linux		*/
-#define HCFG_LEGACYFUNC_SPCI	0xa0000000	/* Legacy SPCI - DO NOT USE under Linux		*/
-#define HCFG_LEGACYFUNC_SDMA	0xe0000000	/* Legacy SDMA - DO NOT USE under Linux		*/
-#define HCFG_IOCAPTUREADDR	0x1f000000	/* The 4 LSBs of the captured I/O address.  DO NOT USE under Linux	*/
-#define HCFG_LEGACYWRITE	0x00800000	/* 1 = write, 0 = read - DO NOT USE under Linux	*/
-#define HCFG_LEGACYWORD		0x00400000	/* 1 = word, 0 = byte - DO NOT USE under Linux	*/
-#define HCFG_LEGACYINT		0x00200000	/* 1 = legacy event captured. Write 1 to clear. DO NOT USE under Linux */
+						/* NOTE: There is no reason to use the legacy	*/
+						/* SoundBlaster emulation stuff described below	*/
+						/* under Linux, and all kinds of weird hardware	*/
+						/* behavior can result if you try.  Don't.	*/
+#define HCFG_LEGACYFUNC_MASK	0xe0000000	/* Legacy function number 			*/
+#define HCFG_LEGACYFUNC_MPU	0x00000000	/* Legacy MPU	 				*/
+#define HCFG_LEGACYFUNC_SB	0x40000000	/* Legacy SB					*/
+#define HCFG_LEGACYFUNC_AD	0x60000000	/* Legacy AD					*/
+#define HCFG_LEGACYFUNC_MPIC	0x80000000	/* Legacy MPIC					*/
+#define HCFG_LEGACYFUNC_MDMA	0xa0000000	/* Legacy MDMA					*/
+#define HCFG_LEGACYFUNC_SPCI	0xc0000000	/* Legacy SPCI					*/
+#define HCFG_LEGACYFUNC_SDMA	0xe0000000	/* Legacy SDMA					*/
+#define HCFG_IOCAPTUREADDR	0x1f000000	/* The 4 LSBs of the captured I/O address.	*/
+#define HCFG_LEGACYWRITE	0x00800000	/* 1 = write, 0 = read 				*/
+#define HCFG_LEGACYWORD		0x00400000	/* 1 = word, 0 = byte 				*/
+#define HCFG_LEGACYINT		0x00200000	/* 1 = legacy event captured. Write 1 to clear.	*/
+						/* NOTE: The rest of the bits in this register	*/
+						/* _are_ relevant under Linux.			*/
 #define HCFG_CODECFORMAT_MASK	0x00070000	/* CODEC format					*/
 #define HCFG_CODECFORMAT_AC97	0x00000000	/* AC97 CODEC format -- Primary Output		*/
-#define HCFG_CODECFORMAT_I2S	0x00020000	/* I2S CODEC format -- Secondary (Rear) Output	*/
+#define HCFG_CODECFORMAT_I2S	0x00010000	/* I2S CODEC format -- Secondary (Rear) Output	*/
 #define HCFG_GPINPUT0		0x00004000	/* External pin112				*/
 #define HCFG_GPINPUT1		0x00002000	/* External pin110				*/
-#define HCFG_GPOUTPUTMASK	0x00001c00	/* External pins which may be controlled	*/
-#define HCFG_JOYENABLE		0x00000200	/* Joystick enable				*/
+#define HCFG_GPOUTPUT_MASK	0x00001c00	/* External pins which may be controlled	*/
+#define HCFG_JOYENABLE      	0x00000200	/* Internal joystick enable    			*/
 #define HCFG_PHASETRACKENABLE	0x00000100	/* Phase tracking enable			*/
+						/* 1 = Force all 3 async digital inputs to use	*/
+						/* the same async sample rate tracker (ZVIDEO)	*/
 #define HCFG_AC3ENABLE_MASK	0x0x0000e0	/* AC3 async input control - Not implemented	*/
 #define HCFG_AC3ENABLE_ZVIDEO	0x00000080	/* Channels 0 and 1 replace ZVIDEO		*/
 #define HCFG_AC3ENABLE_CDSPDIF	0x00000040	/* Channels 0 and 1 replace CDSPDIF		*/
 #define HCFG_AUTOMUTE		0x00000010	/* When set, the async sample rate convertors	*/
-/* will automatically mute their output when	*/
-/* they are not rate-locked to the external	*/
-/* audio source					*/
-#define HCFG_LOCKSOUNDCACHE	0x00000008	/* 1 = Cancel bustmaster accesses to soundcache - Do not adjust this */
-#define HCFG_LOCKTANKCACHE	0x00000004	/* 1 = Cancel bustmaster accesses to tankcache - Do not adjust this */
-#define HCFG_MUTEBUTTONENABLE	0x00000002	/* 1 = Enable master mute button		*/
+						/* will automatically mute their output when	*/
+						/* they are not rate-locked to the external	*/
+						/* async audio source  				*/
+#define HCFG_LOCKSOUNDCACHE	0x00000008	/* 1 = Cancel bustmaster accesses to soundcache */
+						/* NOTE: This should generally never be used.  	*/
+#define HCFG_LOCKTANKCACHE	0x00000004	/* 1 = Cancel bustmaster accesses to tankcache	*/
+						/* NOTE: This should generally never be used.  	*/
+#define HCFG_MUTEBUTTONENABLE	0x00000002	/* 1 = Master mute button sets AUDIOENABLE = 0.	*/
+						/* NOTE: This is a 'cheap' way to implement a	*/
+						/* master mute function on the mute button, and	*/
+						/* in general should not be used unless a more	*/
+						/* sophisticated master mute function has not	*/
+						/* been written.       				*/
 #define HCFG_AUDIOENABLE	0x00000001	/* 0 = CODECs transmit zero-valued samples	*/
+						/* Should be set to 1 when the EMU10K1 is	*/
+						/* completely initialized.			*/
 
-#define MUDATA			0x18		/* MPU401 data register 			*/
+#define MUDATA			0x18		/* MPU401 data register (8 bits)       		*/
 
-#define MUCMD			0x19		/* MPU401 command register			*/
+#define MUCMD			0x19		/* MPU401 command register (8 bits)    		*/
 #define MUCMD_RESET		0xff		/* RESET command				*/
 #define MUCMD_ENTERUARTMODE	0x3f		/* Enter_UART_mode command			*/
+						/* NOTE: All other commands are ignored		*/
 
-#define MUSTAT			MUCMD		/* MPU401 status register			*/
+#define MUSTAT			MUCMD		/* MPU401 status register (8 bits)     		*/
 #define MUSTAT_IRDYN		0x80		/* 0 = MIDI data or command ACK			*/
 #define MUSTAT_ORDYN		0x40		/* 0 = MUDATA can accept a command or data	*/
 
-#define TIMR			0x1a		/* Timer terminal count register		*/
-#define TIMR_RATE_MASK		0x000003ff	/* Timer interrupt rate in sample periods	*/
-#define TIMR_RATE		0x0a00001a
+#define TIMER			0x1a		/* Timer terminal count register		*/
+						/* NOTE: After the rate is changed, a maximum	*/
+						/* of 1024 sample periods should be allowed	*/
+						/* before the new rate is guaranteed accurate.	*/
+#define TIMER_RATE_MASK		0x000003ff	/* Timer interrupt rate in sample periods	*/
+						/* 0 == 1024 periods, [1..4] are not useful	*/
+#define TIMER_RATE		0x0a00001a
 
-#define AC97DATA		0x1c		/* AC97 indexed register set data register	*/
+#define AC97DATA		0x1c		/* AC97 register set data register (16 bit)	*/
 
-#define AC97ADDRESS		0x1e		/* AC97 indexed register set address register	*/
+#define AC97ADDRESS		0x1e		/* AC97 register set address register (8 bit)	*/
 #define AC97ADDRESS_READY	0x80		/* Read-only bit, reflects CODEC READY signal	*/
 #define AC97ADDRESS_ADDRESS	0x7f		/* Address of indexed AC97 register		*/
 
@@ -198,9 +229,13 @@
 #define JOYSTICK6		0x05		/* Analog joystick port register		*/
 #define JOYSTICK7		0x06		/* Analog joystick port register		*/
 #define JOYSTICK8		0x07		/* Analog joystick port register		*/
+
+/* When writing, any write causes JOYSTICK_COMPARATOR output enable to be pulsed on write.	*/
+/* When reading, use these bitfields: */
 #define JOYSTICK_BUTTONS	0x0f		/* Joystick button data				*/
 #define JOYSTICK_COMPARATOR	0xf0		/* Joystick comparator data			*/
 
+
 /********************************************************************************************************/
 /* AC97 pointer-offset register set, accessed through the AC97ADDRESS and AC97DATA registers		*/
 /********************************************************************************************************/
@@ -225,9 +260,6 @@
 #define AC97_3DCONTROL		0x22
 #define AC97_MODEMRATE		0x24
 #define AC97_POWERDOWN		0x26
-#define AC97_RESERVED4		0x28
-#define AC97_VENDORRESERVED1	0x5a
-#define AC97_VENDORRESERVED2	0x7a
 #define AC97_VENDORID1		0x7c
 #define AC97_VENDORID2		0x7e
 #define AC97_ZVIDEOVOLUME	0xec
@@ -238,7 +270,7 @@
 /********************************************************************************************************/
 
 #define CPF			0x00		/* Current pitch and fraction register			*/
-#define CPF_CURRENTPITCH_MASK	0xffff0000	/* Current pitch (0x4000 == unity pitch shift)		*/
+#define CPF_CURRENTPITCH_MASK	0xffff0000	/* Current pitch (linear, 0x4000 == unity pitch shift) 	*/
 #define CPF_CURRENTPITCH	0x10100000
 #define CPF_STEREO_MASK		0x00008000	/* 1 = Even channel interleave, odd channel locked	*/
 #define CPF_STOP_MASK		0x00004000	/* 1 = Current pitch forced to 0			*/
@@ -267,7 +299,7 @@
 #define Z2			0x04		/* Filter delay memory 2 register			*/
 
 #define PSST			0x06		/* Send C amount and loop start address register	*/
-#define PSST_FXSENDAMOUNT_C_MASK	0xff000000	/* Linear level of channel output sent to FX send bus C	*/
+#define PSST_FXSENDAMOUNT_C_MASK 0xff000000	/* Linear level of channel output sent to FX send bus C	*/
 
 #define PSST_FXSENDAMOUNT_C	0x08180006
 
@@ -283,8 +315,13 @@
 #define DSL_LOOPENDADDR		0x18000007
 
 #define CCCA			0x08		/* Filter Q, interp. ROM, byte size, cur. addr register */
-#define CCCA_RESONANCE		0xf0000000	/* Lowpass filter resonance height			*/
+#define CCCA_RESONANCE		0xf0000000	/* Lowpass filter resonance (Q) height			*/
 #define CCCA_INTERPROMMASK	0x0e000000	/* Selects passband of interpolation ROM		*/
+						/* 1 == full band, 7 == lowpass				*/
+						/* ROM 0 is used when pitch shifting downward or less	*/
+						/* then 3 semitones upward.  Increasingly higher ROM	*/
+						/* numbers are used, typically in steps of 3 semitones,	*/
+						/* as upward pitch shifting is performed.		*/
 #define CCCA_INTERPROM_0	0x00000000	/* Select interpolation ROM 0				*/
 #define CCCA_INTERPROM_1	0x02000000	/* Select interpolation ROM 1				*/
 #define CCCA_INTERPROM_2	0x04000000	/* Select interpolation ROM 2				*/
@@ -298,77 +335,87 @@
 #define CCCA_CURRADDR		0x18000008
 
 #define CCR			0x09		/* Cache control register				*/
-#define CCR_CACHEINVALIDSIZE	0xfe000000	/* Number of invalid samples in the cache		*/
+#define CCR_CACHEINVALIDSIZE	0xfe000000	/* Number of invalid samples cache for this channel    	*/
 #define CCR_CACHELOOPFLAG	0x01000000	/* 1 = Cache has a loop service pending			*/
 #define CCR_INTERLEAVEDSAMPLES	0x00800000	/* 1 = A cache service will fetch interleaved samples	*/
 #define CCR_WORDSIZEDSAMPLES	0x00400000	/* 1 = A cache service will fetch word sized samples	*/
 #define CCR_READADDRESS_MASK	0x003f0000	/* Location of cache just beyond current cache service	*/
 #define CCR_LOOPINVALSIZE	0x0000fe00	/* Number of invalid samples in cache prior to loop	*/
+						/* NOTE: This is valid only if CACHELOOPFLAG is set	*/
 #define CCR_LOOPFLAG		0x00000100	/* Set for a single sample period when a loop occurs	*/
-#define CCR_CACHELOOPADDRHI	0x000000ff	/* DSL_LOOPSTARTADDR's hi byte if CCR_CACHELOOPFLAG = 1 */
+#define CCR_CACHELOOPADDRHI	0x000000ff	/* DSL_LOOPSTARTADDR's hi byte if CACHELOOPFLAG is set	*/
 
-/* NOTE: This register is normally not used */
 #define CLP			0x0a		/* Cache loop register (valid if CCR_CACHELOOPFLAG = 1) */
-#define CLP_CACHELOOPADDR	0x0000ffff	/* Cache loop address (copy of DSL_LOOPSTARTADDR)	*/
+						/* NOTE: This register is normally not used		*/
+#define CLP_CACHELOOPADDR	0x0000ffff	/* Cache loop address (DSL_LOOPSTARTADDR [0..15])	*/
 
 #define FXRT			0x0b		/* Effects send routing register			*/
+						/* NOTE: It is illegal to assign the same routing to	*/
+						/* two effects sends.					*/
 #define FXRT_CHANNELA		0x000f0000	/* Effects send bus number for channel's effects send A	*/
 #define FXRT_CHANNELB		0x00f00000	/* Effects send bus number for channel's effects send B	*/
 #define FXRT_CHANNELC		0x0f000000	/* Effects send bus number for channel's effects send C	*/
 #define FXRT_CHANNELD		0xf0000000	/* Effects send bus number for channel's effects send D	*/
 
 #define MAPA			0x0c		/* Cache map A						*/
-#define MAP_PTE_MASK		0xffffe000	/* The 19 MSBs of the PTE indexed by PTI		*/
-#define MAP_PTI_MASK		0x00001fff	/* The 13 bit index to one of the PTE dwords		*/
 
 #define MAPB			0x0d		/* Cache map B						*/
 
+#define MAP_PTE_MASK		0xffffe000	/* The 19 MSBs of the PTE indexed by the PTI		*/
+#define MAP_PTI_MASK		0x00001fff	/* The 13 bit index to one of the 8192 PTE dwords      	*/
+
 #define ENVVOL			0x10		/* Volume envelope register				*/
-#define ENVVOL_MASK		0x0000ffff	/* 16-bit value						*/
+#define ENVVOL_MASK		0x0000ffff	/* Current value of volume envelope state variable	*/  
+						/* 0x8000-n == 666*n usec delay	       			*/
 
 #define ATKHLDV 		0x11		/* Volume envelope hold and attack register		*/
 #define ATKHLDV_PHASE0		0x00008000	/* 0 = Begin attack phase				*/
 #define ATKHLDV_HOLDTIME_MASK	0x00007f00	/* Envelope hold time (127-n == n*88.2msec)		*/
 #define ATKHLDV_ATTACKTIME_MASK	0x0000007f	/* Envelope attack time, log encoded			*/
-/* 0 = infinite, 1 = 10.9msec, ... 0x7f = 5.5msec	*/
+						/* 0 = infinite, 1 = 10.9msec, ... 0x7f = 5.5msec	*/
 
 #define DCYSUSV 		0x12		/* Volume envelope sustain and decay register		*/
 #define DCYSUSV_PHASE1_MASK	0x00008000	/* 0 = Begin attack phase, 1 = begin release phase	*/
 #define DCYSUSV_SUSTAINLEVEL_MASK 0x00007f00	/* 127 = full, 0 = off, 0.75dB increments		*/
-#define DCYSUSV_CHANNELENABLE_MASK 0x00000080	/* 1 = Inhibit envelope engine from writing to registers*/
-#define DCYSUSV_DECAYTIME_MASK	0x0000007f	/* Envelope decay time, log encoded			*/
-/* 0 = 43.7msec, 1 = 21.8msec, 0x7f = 22msec		*/
+#define DCYSUSV_CHANNELENABLE_MASK 0x00000080	/* 1 = Inhibit envelope engine from writing values in	*/
+						/* this channel and from writing to pitch, filter and	*/
+						/* volume targets.					*/
+#define DCYSUSV_DECAYTIME_MASK	0x0000007f	/* Volume envelope decay time, log encoded     		*/
+						/* 0 = 43.7msec, 1 = 21.8msec, 0x7f = 22msec		*/
 
 #define LFOVAL1 		0x13		/* Modulation LFO value					*/
-#define LFOVAL_MASK		0x0000ffff	/* 16-bit value						*/
+#define LFOVAL_MASK		0x0000ffff	/* Current value of modulation LFO state variable	*/
+						/* 0x8000-n == 666*n usec delay				*/
 
 #define ENVVAL			0x14		/* Modulation envelope register				*/
-#define ENVVAL_MASK		0x0000ffff	/* 16-bit value						*/
+#define ENVVAL_MASK		0x0000ffff	/* Current value of modulation envelope state variable 	*/
+						/* 0x8000-n == 666*n usec delay				*/
 
 #define ATKHLDM			0x15		/* Modulation envelope hold and attack register		*/
 #define ATKHLDM_PHASE0		0x00008000	/* 0 = Begin attack phase				*/
 #define ATKHLDM_HOLDTIME	0x00007f00	/* Envelope hold time (127-n == n*42msec)		*/
 #define ATKHLDM_ATTACKTIME	0x0000007f	/* Envelope attack time, log encoded			*/
-/* 0 = infinite, 1 = 11msec, ... 0x7f = 5.5msec		*/
+						/* 0 = infinite, 1 = 11msec, ... 0x7f = 5.5msec		*/
 
 #define DCYSUSM			0x16		/* Modulation envelope decay and sustain register	*/
 #define DCYSUSM_PHASE1_MASK	0x00008000	/* 0 = Begin attack phase, 1 = begin release phase	*/
 #define DCYSUSM_SUSTAINLEVEL_MASK 0x00007f00	/* 127 = full, 0 = off, 0.75dB increments		*/
 #define DCYSUSM_DECAYTIME_MASK	0x0000007f	/* Envelope decay time, log encoded			*/
-/* 0 = 43.7msec, 1 = 21.8msec, 0x7f = 22msec		*/
+						/* 0 = 43.7msec, 1 = 21.8msec, 0x7f = 22msec		*/
 
 #define LFOVAL2 		0x17		/* Vibrato LFO register					*/
-#define LFOVAL2_MASK		0x0000ffff	/* 16-bit value						*/
+#define LFOVAL2_MASK		0x0000ffff	/* Current value of vibrato LFO state variable 		*/
+						/* 0x8000-n == 666*n usec delay				*/
 
 #define IP			0x18		/* Initial pitch register				*/
-#define IP_MASK			0x0000ffff	/* Exponential initial pitch shift (16-bit value)	*/
-/* 4 bits of octave, 12 bits of fractional octave	*/
+#define IP_MASK			0x0000ffff	/* Exponential initial pitch shift			*/
+						/* 4 bits of octave, 12 bits of fractional octave	*/
 #define IP_UNITY		0x0000e000	/* Unity pitch shift					*/
 
 #define IFATN			0x19		/* Initial filter cutoff and attenuation register	*/
 #define IFATN_FILTERCUTOFF_MASK	0x0000ff00	/* Initial filter cutoff frequency in exponential units	*/
-/* 6 most significant bits are semitones		*/
-/* 2 least significant bits are fractions		*/
+						/* 6 most significant bits are semitones		*/
+						/* 2 least significant bits are fractions		*/
 #define IFATN_FILTERCUTOFF	0x08080019
 #define IFATN_ATTENUATION_MASK	0x000000ff	/* Initial attenuation in 0.375dB steps			*/
 #define IFATN_ATTENUATION	0x08000019
@@ -376,57 +423,61 @@
 
 #define PEFE			0x1a		/* Pitch envelope and filter envelope amount register	*/
 #define PEFE_PITCHAMOUNT_MASK	0x0000ff00	/* Pitch envlope amount					*/
-/* Signed 2's complement, +/- one octave peak extremes	*/
+						/* Signed 2's complement, +/- one octave peak extremes	*/
 #define PEFE_PITCHAMOUNT	0x0808001a
 #define PEFE_FILTERAMOUNT_MASK	0x000000ff	/* Filter envlope amount				*/
-/* Signed 2's complement, +/- six octaves peak extremes */
+						/* Signed 2's complement, +/- six octaves peak extremes */
 #define PEFE_FILTERAMOUNT	0x0800001a
 #define FMMOD			0x1b		/* Vibrato/filter modulation from LFO register		*/
 #define FMMOD_MODVIBRATO	0x0000ff00	/* Vibrato LFO modulation depth				*/
-/* Signed 2's complement, +/- one octave extremes	*/
+						/* Signed 2's complement, +/- one octave extremes	*/
 #define FMMOD_MOFILTER		0x000000ff	/* Filter LFO modulation depth				*/
-/* Signed 2's complement, +/- three octave extremes	*/
+						/* Signed 2's complement, +/- three octave extremes	*/
 
 
 #define TREMFRQ 		0x1c		/* Tremolo amount and modulation LFO frequency register	*/
 #define TREMFRQ_DEPTH		0x0000ff00	/* Tremolo depth					*/
-/* Signed 2's complement, with +/- 12dB extremes	*/
+						/* Signed 2's complement, with +/- 12dB extremes	*/
 
 #define FM2FRQ2 		0x1d		/* Vibrato amount and vibrato LFO frequency register	*/
 #define FM2FRQ2_DEPTH		0x0000ff00	/* Vibrato LFO vibrato depth				*/
-/* Signed 2's complement, +/- one octave extremes	*/
+						/* Signed 2's complement, +/- one octave extremes	*/
 #define FM2FRQ2_FREQUENCY	0x000000ff	/* Vibrato LFO frequency				*/
-/* 0.039Hz steps, maximum of 9.85 Hz.			*/
+						/* 0.039Hz steps, maximum of 9.85 Hz.			*/
 
 #define TEMPENV 		0x1e		/* Tempory envelope register				*/
 #define TEMPENV_MASK		0x0000ffff	/* 16-bit value						*/
+						/* NOTE: All channels contain internal variables; do	*/
+						/* not write to these locations.			*/
 
-#define CD0			0x20		/* Reserved Bit - Do not program			*/
-#define CD1			0x21		/* Reserved Bit - Do not program			*/
-#define CD2			0x22		/* Reserved Bit - Do not program			*/
-#define CD3			0x23		/* Reserved Bit - Do not program			*/
-#define CD4			0x24		/* Reserved Bit - Do not program			*/
-#define CD5			0x25		/* Reserved Bit - Do not program			*/
-#define CD6			0x26		/* Reserved Bit - Do not program			*/
-#define CD7			0x27		/* Reserved Bit - Do not program			*/
-#define CD8			0x28		/* Reserved Bit - Do not program			*/
-#define CD9			0x29		/* Reserved Bit - Do not program			*/
-#define CDA			0x2a		/* Reserved Bit - Do not program			*/
-#define CDB			0x2b		/* Reserved Bit - Do not program			*/
-#define CDC			0x2c		/* Reserved Bit - Do not program			*/
-#define CDD			0x2d		/* Reserved Bit - Do not program			*/
-#define CDE			0x2e		/* Reserved Bit - Do not program			*/
-#define CDF			0x2f		/* Reserved Bit - Do not program			*/
+#define CD0			0x20		/* Cache data 0 register				*/
+#define CD1			0x21		/* Cache data 1 register				*/
+#define CD2			0x22		/* Cache data 2 register				*/
+#define CD3			0x23		/* Cache data 3 register				*/
+#define CD4			0x24		/* Cache data 4 register				*/
+#define CD5			0x25		/* Cache data 5 register				*/
+#define CD6			0x26		/* Cache data 6 register				*/
+#define CD7			0x27		/* Cache data 7 register				*/
+#define CD8			0x28		/* Cache data 8 register				*/
+#define CD9			0x29		/* Cache data 9 register				*/
+#define CDA			0x2a		/* Cache data A register				*/
+#define CDB			0x2b		/* Cache data B register				*/
+#define CDC			0x2c		/* Cache data C register				*/
+#define CDD			0x2d		/* Cache data D register				*/
+#define CDE			0x2e		/* Cache data E register				*/
+#define CDF			0x2f		/* Cache data F register				*/
 
 #define PTB			0x40		/* Page table base register				*/
 #define PTB_MASK		0xfffff000	/* Physical address of the page table in host memory	*/
 
 #define TCB			0x41		/* Tank cache base register    				*/
-#define TCB_MASK		0xfffff000	/* Physical address of the bottom of host based tank memory	*/
+#define TCB_MASK		0xfffff000	/* Physical address of the bottom of host based TRAM	*/
 
 #define ADCCR			0x42		/* ADC sample rate/stereo control register		*/
-#define ADCCR_RCHANENABLE	0x00000010	/* Right channel enable					*/
-#define ADCCR_LCHANENABLE	0x00000008	/* Left channel enable					*/
+#define ADCCR_RCHANENABLE	0x00000010	/* Enables right channel for writing to the host       	*/
+#define ADCCR_LCHANENABLE	0x00000008	/* Enables left channel for writing to the host		*/
+						/* NOTE: To guarantee phase coherency, both channels	*/
+						/* must be disabled prior to enabling both channels.	*/
 #define ADCCR_SAMPLERATE_MASK	0x00000007	/* Sample rate convertor output rate			*/
 #define ADCCR_SAMPLERATE_48	0x00000000	/* 48kHz sample rate					*/
 #define ADCCR_SAMPLERATE_44	0x00000001	/* 44.1kHz sample rate					*/
@@ -438,6 +489,8 @@
 #define ADCCR_SAMPLERATE_8	0x00000007	/* 8kHz sample rate					*/
 
 #define FXWC			0x43		/* FX output write channels register			*/
+						/* When set, each bit enables the writing of the	*/
+						/* corresponding FX output channel into host memory	*/
 
 #define TCBS			0x44		/* Tank cache buffer size register			*/
 #define TCBS_MASK		0x00000007	/* Tank cache buffer size field				*/
@@ -457,12 +510,15 @@
 #define ADCBA_MASK		0xfffff000	/* 20 bit base address					*/
 
 #define FXBA			0x47		/* FX Buffer Address */
+#define FXBA_MASK		0xfffff000	/* 20 bit base address					*/
 
 #define MICBS			0x49		/* Microphone buffer size register			*/
 
 #define ADCBS			0x4a		/* ADC buffer size register				*/
 
-/* The following mask values define the size of the ADC buffers in bytes */
+#define FXBS			0x4b		/* FX buffer size register				*/
+
+/* The following mask values define the size of the ADC, MIX and FX buffers in bytes */
 #define ADCBS_BUFSIZE_NONE	0x00000000
 #define ADCBS_BUFSIZE_384	0x00000001
 #define ADCBS_BUFSIZE_448	0x00000002
@@ -496,7 +552,6 @@
 #define ADCBS_BUFSIZE_57344	0x0000001e
 #define ADCBS_BUFSIZE_65536	0x0000001f
 
-#define FXBS			0x4b		/* FX buffer size register			*/
 
 #define CDCS			0x50		/* CD-ROM digital channel status register	*/
 
@@ -536,7 +591,7 @@
 #define SPCS_NOTAUDIODATA	0x00000002	/* 0 = Digital audio, 1 = not audio		*/
 #define SPCS_PROFESSIONAL	0x00000001	/* 0 = Consumer (IEC-958), 1 = pro (AES3-1992)	*/
 
-/* The 32-bit CLIx registers all have one bit per channel control/status			*/
+/* The 32-bit CLIx and SOLx registers all have one bit per channel control/status      		*/
 #define CLIEL			0x58		/* Channel loop interrupt enable low register	*/
 
 #define CLIEH			0x59		/* Channel loop interrupt enable high register	*/
@@ -550,27 +605,32 @@
 #define SOLEH			0x5d		/* Stop on loop enable high register		*/
 
 #define SPBYPASS		0x5e		/* SPDIF BYPASS mode register			*/
+#define SPBYPASS_ENABLE		0x00000001	/* Enable SPDIF bypass mode			*/
 
 #define CDSRCS			0x60		/* CD-ROM Sample Rate Converter status register	*/
 
 #define GPSRCS			0x61		/* General Purpose SPDIF sample rate cvt status */
 
 #define ZVSRCS			0x62		/* ZVideo sample rate converter status		*/
-/* NOTE: This one has no SPDIFLOCKED field	*/
-/* Assumes sample lock				*/
+						/* NOTE: This one has no SPDIFLOCKED field	*/
+						/* Assumes sample lock				*/
 
 /* These three bitfields apply to CDSRCS, GPSRCS, and (except as noted) ZVSRCS.			*/
 #define SRCS_SPDIFLOCKED	0x02000000	/* SPDIF stream locked				*/
 #define SRCS_RATELOCKED		0x01000000	/* Sample rate locked				*/
 #define SRCS_ESTSAMPLERATE	0x0007ffff	/* Do not modify this field.			*/
 
-#define ADCIDX			0x63		/* ADC recording buffer index register		*/
-#define ADCIDX_MASK		0x0000ffff	/* 16 bit index field				*/
+#define MICIDX                  0x63            /* Microphone recording buffer index register   */
+#define MICIDX_MASK             0x0000ffff      /* 16-bit value                                 */
+#define MICIDX_IDX		0x10000063
 
-#define MICIDX			0x64		/* Microphone recording buffer index register	*/
-#define MICIDX_MASK		0x0000ffff	/* 16-bit value					*/
+#define ADCIDX			0x64		/* ADC recording buffer index register		*/
+#define ADCIDX_MASK		0x0000ffff	/* 16 bit index field				*/
+#define ADCIDX_IDX		0x10000064
 
 #define FXIDX			0x65		/* FX recording buffer index register		*/
+#define FXIDX_MASK		0x0000ffff	/* 16-bit value					*/
+#define FXIDX_IDX		0x10000065
 
 /* Each FX general purpose register is 32 bits in length, all bits are used			*/
 #define FXGPREGBASE		0x100		/* FX general purpose registers base       	*/
@@ -592,7 +652,7 @@
 #define MICROCODEBASE		0x400		/* Microcode data base address			*/
 
 /* Each DSP microcode instruction is mapped into 2 doublewords 					*/
-/* NOTE: When writing, always write the HI doubleword first.  Reads can be in either order.	*/
+/* NOTE: When writing, always write the LO doubleword first.  Reads can be in either order.	*/
 #define LOWORD_OPX_MASK		0x000ffc00	/* Instruction operand X			*/
 #define LOWORD_OPY_MASK		0x000003ff	/* Instruction operand Y			*/
 #define HIWORD_OPCODE_MASK	0x00f00000	/* Instruction opcode				*/
Index: oldkernel/linux/drivers/sound/emu10k1/Makefile
diff -u linux/drivers/sound/emu10k1/Makefile:1.1 linux/drivers/sound/emu10k1/Makefile:1.2
--- linux/drivers/sound/emu10k1/Makefile:1.1	Thu Jun  1 16:52:15 2000
+++ linux/drivers/sound/emu10k1/Makefile	Fri Jul  7 15:36:45 2000
@@ -1,14 +1,27 @@
+# Makefile for Creative Labs SBLive!
+#
+# 19 Apr 2000 Rui Sousa
+
+ifeq ($(CONFIG_SOUND_EMU10K1),y)
+    O_TARGET := emu10k1.o
+    O_OBJS = audio.o cardmi.o cardmo.o cardwi.o cardwo.o efxmgr.o \
+             emuadxmg.o hwaccess.o irqmgr.o main.o midi.o mixer.o \
+             osutils.o recmgr.o timer.o voicemgr.o
+else
+  ifeq ($(CONFIG_SOUND_EMU10K1),m)
+    M_OBJS := emu10k1.o
+    O_TARGET := emu10k1.o
+    O_OBJS = audio.o cardmi.o cardmo.o cardwi.o cardwo.o efxmgr.o \
+             emuadxmg.o hwaccess.o irqmgr.o main.o midi.o mixer.o \
+             osutils.o recmgr.o timer.o voicemgr.o
+  endif
+endif
+
+ifdef DEBUG
+    EXTRA_CFLAGS += -DEMU10K1_DEBUG
+endif
 
-#MOD_LIST_NAME := SOUND_MODULES
-
-EMU = audio.o cardmi.o cardmo.o cardwi.o cardwo.o efxmgr.o emuadxmg.o hwaccess.o irqmgr.o main.o midi.o mixer.o osutils.o recmgr.o sndstat.o timer.o voicemgr.o
-
-M_OBJS := emu10k1.o
-
-$(EMU): %.o: %.c
-	$(CC) -c $(CFLAGS) -I. $< -o $@
-
-emu10k1.o: $(EMU)
-	$(LD) -r $(EMU) -o $@
-
 include $(TOPDIR)/Rules.make
+
+clean:
+	rm -f core *.o *.a *.s
Index: oldkernel/linux/drivers/sound/emu10k1/audio.c
diff -u linux/drivers/sound/emu10k1/audio.c:1.1 linux/drivers/sound/emu10k1/audio.c:1.2
--- linux/drivers/sound/emu10k1/audio.c:1.1	Thu Jun  1 16:52:15 2000
+++ linux/drivers/sound/emu10k1/audio.c	Fri Jul  7 15:36:45 2000
@@ -1,3 +1,4 @@
+
 /*
  **********************************************************************
  *     audio.c -- /dev/dsp interface for emu10k1 driver
@@ -30,356 +31,251 @@
  **********************************************************************
  */
 
-/*
- *	FIXME:
- *		There are some 32bit assumptions here
- *		Cast of pointers to 32bit values is unsafe
- *			- Wave callbacks and elsewhere
- */
-
 #include "hwaccess.h"
-#include "mycommon.h"
-#include "mmwave.h"
 #include "cardwo.h"
 #include "cardwi.h"
+#include "recmgr.h"
 #include "audio.h"
 
-static void calculate_ofrag(struct woinst *woinst);
-static void calculate_ifrag(struct wiinst *wiinst);
+static void calculate_ofrag(struct woinst *);
+static void calculate_ifrag(struct wiinst *);
 
 /* Audio file operations */
 static loff_t emu10k1_audio_llseek(struct file *file, loff_t offset, int nOrigin)
 {
-	DPF(2, "emu10k1_audio_lseek() called\n");
 	return -ESPIPE;
 }
 
 static ssize_t emu10k1_audio_read(struct file *file, char *buffer, size_t count, loff_t * ppos)
 {
-	struct sblive_wavedevice *wave_dev = (struct sblive_wavedevice *) file->private_data;
+	struct emu10k1_wavedevice *wave_dev = (struct emu10k1_wavedevice *) file->private_data;
 	struct wiinst *wiinst = wave_dev->wiinst;
+	struct wave_in *wave_in;
 	ssize_t ret = 0;
-	u32 flags;
+	unsigned long flags;
 
-	spin_lock_irqsave(&wiinst->lock, flags);
+	GET_INODE_STRUCT();
 
-	DPD(4, "emu10k1_audio_read() called, buffer=%x, count=%d\n", (unsigned int) buffer, count);
+	DPD(4, "emu10k1_audio_read(), buffer=%p, count=%x\n", buffer, (u32) count);
 
-	if (wiinst->mapped)
-	{
-		spin_unlock_irqrestore(&wiinst->lock, flags);
-		return -ENXIO;
-	}
+	if (ppos != &file->f_pos)
+		return -ESPIPE;
 
-	if (file->f_mode & FMODE_READ)
-	{
-		struct wave_in *wave_in = wiinst->wave_in;
+	if (!access_ok(VERIFY_WRITE, buffer, count))
+		return -EFAULT;
 
-		if (!wave_in)
-		{
-			calculate_ifrag(wiinst);
+	spin_lock_irqsave(&wiinst->lock, flags);
 
-			if (sblive_waveinOpen(wave_dev->sb_hw, &wiinst->wave_fmt,
-					      &wiinst->fragment_size,
-					      wiinst->numfrags, &wiinst->wave_in) != CTSTATUS_SUCCESS)
-			{
-				spin_unlock_irqrestore(&wiinst->lock, flags);
+	if (wiinst->mapped) {
+		spin_unlock_irqrestore(&wiinst->lock, flags);
+		return -ENXIO;
+	}
 
-				DPF(2, "sblive_waveinOpen failed!\n");
-				return -EINVAL;
-			}
+	if (!wiinst->wave_in) {
+		calculate_ifrag(wiinst);
 
-			DPD(2, "fragment_size size is -> %x\n", wiinst->fragment_size);
+		while (emu10k1_wavein_open(wave_dev) != CTSTATUS_SUCCESS) {
+			spin_unlock_irqrestore(&wiinst->lock, flags);
 
-			wave_in = wiinst->wave_in;
-		}
+			if (file->f_flags & O_NONBLOCK)
+				return -EAGAIN;
 
-		if (!access_ok(VERIFY_WRITE, buffer, count))
-		{
-			spin_unlock_irqrestore(&wiinst->lock, flags);
+			UP_INODE_SEM(&inode->i_sem);
+			interruptible_sleep_on(&wave_dev->card->open_wait);
+			DOWN_INODE_SEM(&inode->i_sem);
 
-			DPF(2, "Cannot write to buffer!\n");
+			if (signal_pending(current))
+				return -ERESTARTSYS;
 
-			return -EFAULT;
+			spin_lock_irqsave(&wiinst->lock, flags);
 		}
-
-		while (count > 0)
-		{
-			u32 bytestocopy, pending;
+	}
 
-			if (wave_dev->enablebits & PCM_ENABLE_INPUT && wave_in->state != CARDWAVE_STATE_STARTED)
-			{
-				if (sblive_waveinStart(wave_dev) != CTSTATUS_SUCCESS)
-				{
-					spin_unlock_irqrestore(&wiinst->lock, flags);
+	wave_in = wiinst->wave_in;
 
-					DPF(2, "sblive_waveinStart() failed.\n");
-					return -EFAULT;
-				}
+	spin_unlock_irqrestore(&wiinst->lock, flags);
 
-				DPF(2, "sblive_waveinStart() succeeded.\n");
-			}
+	while (count > 0) {
+		u32 bytestocopy, dummy;
 
-			if (sblive_waveinGetXferSize(wave_dev->sb_hw->card_wavein, wave_in, &bytestocopy, &pending) != CTSTATUS_SUCCESS)
-			{
-				spin_unlock_irqrestore(&wiinst->lock, flags);
+		spin_lock_irqsave(&wiinst->lock, flags);
 
-				DPF(2, "sblive_waveinGetXferSize failed\n");
-				return -EFAULT;
-			}
+		if ((wave_in->state != CARDWAVE_STATE_STARTED)
+		    && (wave_dev->enablebits & PCM_ENABLE_INPUT))
+			emu10k1_wavein_start(wave_dev);
 
-			DPD(4, "bytestocopy --> %x\n", bytestocopy);
+		emu10k1_wavein_getxfersize(wave_in, &bytestocopy, &dummy);
 
-			if (bytestocopy) {
+		spin_unlock_irqrestore(&wiinst->lock, flags);
 
-				bytestocopy = min(bytestocopy, count);
+		DPD(4, "bytestocopy --> %x\n", bytestocopy);
 
-				if (sblive_waveinXferData(wave_dev->sb_hw->card_wavein, wave_in, (u8 *)buffer, &bytestocopy) != CTSTATUS_SUCCESS)
-				{
-					spin_unlock_irqrestore(&wiinst->lock, flags);
-					DPF(2, "sblive_waveinXferData failed.\n");
-					return ret ? ret : -EFAULT;
-				}
+		if ((bytestocopy >= wiinst->fragment_size)
+		    || (bytestocopy >= count)) {
+			bytestocopy = min(bytestocopy, count);
 
-				count -= bytestocopy;
-				buffer += bytestocopy;
-				ret += bytestocopy;
-			}
+			emu10k1_wavein_xferdata(wiinst, (u8 *) buffer, &bytestocopy);
 
-			if (count > 0)
-			{
-				if ((file->f_flags & O_NONBLOCK)
-				    || (!(wave_dev->enablebits & PCM_ENABLE_INPUT)))
-				{
-					spin_unlock_irqrestore(&wiinst->lock, flags);
-					return (ret ? ret : -EAGAIN);
-				}
+			count -= bytestocopy;
+			buffer += bytestocopy;
+			ret += bytestocopy;
+		}
 
-				spin_unlock_irqrestore(&wiinst->lock, flags);
+		if (count > 0) {
+			if ((file->f_flags & O_NONBLOCK)
+			    || (!(wave_dev->enablebits & PCM_ENABLE_INPUT)))
+				return (ret ? ret : -EAGAIN);
 
-				interruptible_sleep_on(&wiinst->wait_queue);
+			UP_INODE_SEM(&inode->i_sem);
+			interruptible_sleep_on(&wiinst->wait_queue);
+			DOWN_INODE_SEM(&inode->i_sem);
 
-				if (signal_pending(current))
-					return (ret ? ret : -ERESTARTSYS);
+			if (signal_pending(current))
+				return (ret ? ret : -ERESTARTSYS);
 
-				spin_lock_irqsave(&wiinst->lock, flags);
-			}
 		}
-		DPD(4, "bytes copied -> %x\n", ret);
 	}
 
-	spin_unlock_irqrestore(&wiinst->lock, flags);
+	DPD(4, "bytes copied -> %x\n", (u32) ret);
 
 	return ret;
 }
 
-ssize_t emu10k1_audio_write(struct file *file, const char *buffer, size_t count, loff_t * ppos)
+static ssize_t emu10k1_audio_write(struct file *file, const char *buffer, size_t count, loff_t * ppos)
 {
-	struct sblive_wavedevice *wave_dev = (struct sblive_wavedevice *) file->private_data;
+	struct emu10k1_wavedevice *wave_dev = (struct emu10k1_wavedevice *) file->private_data;
 	struct woinst *woinst = wave_dev->woinst;
-	struct wave_out *wave_out = woinst->wave_out;
+	struct wave_out *wave_out;
 	ssize_t ret;
-	u32 flags;
+	unsigned long flags;
+
 	GET_INODE_STRUCT();
 
-	spin_lock_irqsave(&woinst->lock, flags);
+	DPD(4, "emu10k1_audio_write(), buffer=%p, count=%x\n", buffer, (u32) count);
 
-	DPD(4, "emu10k1_audio_write() called, buffer=%#x, count=%d\n", (unsigned int) buffer, count);
+	if (ppos != &file->f_pos)
+		return -ESPIPE;
 
-	if (woinst->mapped)
-	{
+	if (!access_ok(VERIFY_READ, buffer, count))
+		return -EFAULT;
+
+	spin_lock_irqsave(&woinst->lock, flags);
+
+	if (woinst->mapped) {
 		spin_unlock_irqrestore(&woinst->lock, flags);
 		return -ENXIO;
 	}
 
-
-	if (wave_out == NULL)
-	{
-
+	if (!woinst->wave_out) {
 		calculate_ofrag(woinst);
 
-		while (sblive_waveoutOpen(wave_dev->sb_hw, &woinst->wave_fmt,
-					  &woinst->fragment_size,
-					  woinst->numfrags, &woinst->wave_out) != CTSTATUS_SUCCESS)
-		{
+		while (emu10k1_waveout_open(wave_dev) != CTSTATUS_SUCCESS) {
+			spin_unlock_irqrestore(&woinst->lock, flags);
+
 			if (file->f_flags & O_NONBLOCK)
-			{
-				spin_unlock_irqrestore(&woinst->lock, flags);
 				return -EAGAIN;
-			}
 
 			UP_INODE_SEM(&inode->i_sem);
-			spin_unlock_irqrestore(&woinst->lock, flags);
-
-			interruptible_sleep_on(&wave_dev->sb_hw->open_wait);
+			interruptible_sleep_on(&wave_dev->card->open_wait);
 			DOWN_INODE_SEM(&inode->i_sem);
+
 			if (signal_pending(current))
 				return -ERESTARTSYS;
 
 			spin_lock_irqsave(&woinst->lock, flags);
 		}
-		wave_out = woinst->wave_out;
 	}
 
-	if (!access_ok(VERIFY_READ, buffer, count))
-	{
-		spin_unlock_irqrestore(&woinst->lock, flags);
-		return -EFAULT;
-	}
+	wave_out = woinst->wave_out;
 
-	ret = 0;
-	while (count > 0)
-	{
-		u32 bytestocopy, pending;
-		int status;
+	spin_unlock_irqrestore(&woinst->lock, flags);
 
-		status = sblive_waveoutGetXferSize(wave_dev->sb_hw->card_waveout,
-						   wave_out, &bytestocopy, &pending);
+	ret = 0;
+	while (count > 0) {
+		u32 bytestocopy, pending, dummy;
 
-		if (status != CTSTATUS_SUCCESS)
-		{
-			spin_unlock_irqrestore(&woinst->lock, flags);
-			DPF(2, "sblive_waveoutGetXferSize failed\n");
-			return -EFAULT;
-		}
+		spin_lock_irqsave(&woinst->lock, flags);
 
-		if (woinst->silence_filled > 0)
-		{
-			if (woinst->silence_filled == 1)
-			{
-				if (pending <= woinst->fragment_size)
-					woinst->silence_filled = 2;
-				else
-					bytestocopy += woinst->fragment_size;
-			}
+		emu10k1_waveout_getxfersize(wave_out, &bytestocopy, &pending, &dummy);
 
-			if (woinst->silence_filled == 2)
-				bytestocopy = woinst->fragment_size * woinst->numfrags;
-		}
+		spin_unlock_irqrestore(&woinst->lock, flags);
 
 		DPD(4, "bytestocopy --> %x\n", bytestocopy);
 
-		if (bytestocopy) {
+		if ((bytestocopy >= woinst->fragment_size)
+		    || (bytestocopy >= count)) {
 
 			bytestocopy = min(bytestocopy, count);
-
-			if (woinst->silence_filled > 0)
-			{
-				u32 tmp;
-
-				if (woinst->silence_filled == 1)
-					tmp = woinst->silence_start;
-				else
-				{
-					sblive_waveoutGetControl(wave_dev->sb_hw->card_waveout,
-								 wave_out, WAVECURPOS, &tmp);
-					pending = 0;
-				}
 
-				if (pending + bytestocopy < woinst->fragment_size)
-				{
-					woinst->silence_filled = 1;
-					woinst->silence_start = tmp + bytestocopy;
+			emu10k1_waveout_xferdata(woinst, (u8 *) buffer, &bytestocopy);
 
-					if (woinst->silence_start > woinst->fragment_size * woinst->numfrags)
-						woinst->silence_start -= woinst->fragment_size * woinst->numfrags;
-				}
-				else
-					woinst->silence_filled = 0;
-
-				sblive_waveoutSetControl(wave_dev->sb_hw, wave_out,
-							 WAVEWRITEPOINTER, &tmp);
-			}
-
-			status = sblive_waveoutXferData(wave_dev->sb_hw->card_waveout,
-							wave_out, (u8 *)buffer, &bytestocopy);
-
-			if (woinst->silence_filled)
-			{
-				u32 tmp = woinst->fragment_size;
-				sblive_waveoutFillSilence(wave_dev->sb_hw->card_waveout, wave_out, &tmp);
-			}
-
-			if (status != CTSTATUS_SUCCESS)
-			{
-				spin_unlock_irqrestore(&woinst->lock, flags);
-				DPF(2, "sblive_waveoutXferData failed.\n");
-				return (ret ? ret : -EFAULT);
-			}
-
 			count -= bytestocopy;
 			buffer += bytestocopy;
 			ret += bytestocopy;
+
+			spin_lock_irqsave(&woinst->lock, flags);
 			woinst->total_copied += bytestocopy;
 
-			if ((wave_dev->enablebits & PCM_ENABLE_OUTPUT)
-			    && (wave_out->state != CARDWAVE_STATE_STARTED)
-			    && (woinst->total_copied >= woinst->fragment_size))
-			{
-				if (sblive_waveoutStart(wave_dev) != CTSTATUS_SUCCESS)
-				{
+			if ((wave_out->state != CARDWAVE_STATE_STARTED)
+			    && (wave_dev->enablebits & PCM_ENABLE_OUTPUT)
+			    && (woinst->total_copied >= woinst->fragment_size)) {
+
+				if (emu10k1_waveout_start(wave_dev) != CTSTATUS_SUCCESS) {
 					spin_unlock_irqrestore(&woinst->lock, flags);
-					DPF(2, "sblive_waveoutStart failed.\n");
+					ERROR();
 					return -EFAULT;
 				}
-				else
-					DPF(2, "sblive_waveoutStart\n");
 			}
+			spin_unlock_irqrestore(&woinst->lock, flags);
 		}
 
-		if (count > 0)
-		{
+		if (count > 0) {
 			if ((file->f_flags & O_NONBLOCK)
 			    || (!(wave_dev->enablebits & PCM_ENABLE_OUTPUT)))
-			{
-				spin_unlock_irqrestore(&woinst->lock, flags);
 				return (ret ? ret : -EAGAIN);
-			}
 
 			UP_INODE_SEM(&inode->i_sem);
-			spin_unlock_irqrestore(&woinst->lock, flags);
-
 			interruptible_sleep_on(&woinst->wait_queue);
 			DOWN_INODE_SEM(&inode->i_sem);
+
 			if (signal_pending(current))
 				return (ret ? ret : -ERESTARTSYS);
-
-			spin_lock_irqsave(&woinst->lock, flags);
 		}
-
 	}
-
-	spin_unlock_irqrestore(&woinst->lock, flags);
 
-	DPD(4, "bytes copied -> %x\n", ret);
+	DPD(4, "bytes copied -> %x\n", (u32) ret);
 
 	return ret;
 }
 
 static int emu10k1_audio_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg)
 {
-	struct sblive_wavedevice *wave_dev = (struct sblive_wavedevice *) file->private_data;
+	struct emu10k1_wavedevice *wave_dev = (struct emu10k1_wavedevice *) file->private_data;
 	int val = 0;
 	struct woinst *woinst = NULL;
 	struct wave_out *wave_out = NULL;
 	struct wiinst *wiinst = NULL;
 	struct wave_in *wave_in = NULL;
-	u32 flags, pending, bytestocopy, dummy;
+	u32 pending, bytestocopy, dummy;
+	unsigned long flags;
 
-	DPF(4, "emu10k1_audio_ioctl() called:\n");
+	DPF(4, "emu10k1_audio_ioctl()\n");
 
-	if (file->f_mode & FMODE_WRITE){
+	if (file->f_mode & FMODE_WRITE) {
 		woinst = wave_dev->woinst;
+		spin_lock_irqsave(&woinst->lock, flags);
 		wave_out = woinst->wave_out;
+		spin_unlock_irqrestore(&woinst->lock, flags);
 	}
 
-	if (file->f_mode & FMODE_READ){
+	if (file->f_mode & FMODE_READ) {
 		wiinst = wave_dev->wiinst;
+		spin_lock_irqsave(&wiinst->lock, flags);
 		wave_in = wiinst->wave_in;
+		spin_unlock_irqrestore(&wiinst->lock, flags);
 	}
 
-	switch (cmd)
-	{
+	switch (cmd) {
 	case OSS_GETVERSION:
 		DPF(2, "OSS_GETVERSION:\n");
 		return put_user(SOUND_VERSION, (int *) arg);
@@ -388,33 +284,29 @@
 		DPF(2, "SNDCTL_DSP_RESET:\n");
 		wave_dev->enablebits = PCM_ENABLE_OUTPUT | PCM_ENABLE_INPUT;
 
-		if (file->f_mode & FMODE_WRITE)
-		{
+		if (file->f_mode & FMODE_WRITE) {
 			spin_lock_irqsave(&woinst->lock, flags);
 
 			if (wave_out)
-			{
-				sblive_waveoutStop(wave_dev->sb_hw, wave_out, &dummy);
-				wave_out->wavexferbuf->xferpos = 0;
-				wave_out->wavexferbuf->stopposition = 0;
-			}
+				emu10k1_waveout_close(wave_dev);
 
 			woinst->total_copied = 0;
 			woinst->total_played = 0;
-			woinst->silence_filled = 0;
-			woinst->silence_start = 0;
-			woinst->getoptr_blocks = 0;
-			woinst->wave_ptr = 0;
+			woinst->blocks = 0;
+			woinst->curpos = 0;
 
 			spin_unlock_irqrestore(&woinst->lock, flags);
 		}
 
-		if (file->f_mode & FMODE_READ)
-		{
+		if (file->f_mode & FMODE_READ) {
 			spin_lock_irqsave(&wiinst->lock, flags);
 
 			if (wave_in)
-				sblive_waveinStop(wave_dev->sb_hw, wave_in, &dummy);
+				emu10k1_wavein_close(wave_dev);
+
+			wiinst->total_recorded = 0;
+			wiinst->blocks = 0;
+			wiinst->curpos = 0;
 			spin_unlock_irqrestore(&wiinst->lock, flags);
 		}
 
@@ -423,20 +315,39 @@
 	case SNDCTL_DSP_SYNC:
 		DPF(2, "SNDCTL_DSP_SYNC:\n");
 
-		if (file->f_mode & FMODE_WRITE)
-		{
-			spin_lock_irqsave(&woinst->lock, flags);
+		if (file->f_mode & FMODE_WRITE) {
 
-			if (wave_out && wave_out->state == CARDWAVE_STATE_STARTED)
-				while ((woinst->total_played < woinst->total_copied)
-				       && !signal_pending(current))
-				{
-					spin_unlock_irqrestore(&woinst->lock, flags);
-					interruptible_sleep_on(&woinst->wait_queue);
-					spin_lock_irqsave(&woinst->lock, flags);
-				}
+			if (wave_out) {
+				spin_lock_irqsave(&woinst->lock, flags);
 
-			spin_unlock_irqrestore(&woinst->lock, flags);
+				if (wave_out->state == CARDWAVE_STATE_STARTED)
+					while ((woinst->total_played < woinst->total_copied)
+					       && !signal_pending(current)) {
+						spin_unlock_irqrestore(&woinst->lock, flags);
+						interruptible_sleep_on(&woinst->wait_queue);
+						spin_lock_irqsave(&woinst->lock, flags);
+					}
+
+				emu10k1_waveout_close(wave_dev);
+				woinst->total_copied = 0;
+				woinst->total_played = 0;
+				woinst->blocks = 0;
+				woinst->curpos = 0;
+
+				spin_unlock_irqrestore(&woinst->lock, flags);
+			}
+		}
+
+		if (file->f_mode & FMODE_READ) {
+			spin_lock_irqsave(&wiinst->lock, flags);
+
+			if (wave_in)
+				emu10k1_wavein_close(wave_dev);
+
+			wiinst->total_recorded = 0;
+			wiinst->blocks = 0;
+			wiinst->curpos = 0;
+			spin_unlock_irqrestore(&wiinst->lock, flags);
 		}
 
 		break;
@@ -447,7 +358,7 @@
 
 	case SNDCTL_DSP_GETCAPS:
 		DPF(2, "SNDCTL_DSP_GETCAPS:\n");
-		return put_user(DSP_CAP_DUPLEX | DSP_CAP_REALTIME | DSP_CAP_TRIGGER | DSP_CAP_MMAP | DSP_CAP_COPROC, (int *)arg);
+		return put_user(DSP_CAP_DUPLEX | DSP_CAP_REALTIME | DSP_CAP_TRIGGER | DSP_CAP_MMAP | DSP_CAP_COPROC, (int *) arg);
 
 	case SNDCTL_DSP_SPEED:
 		DPF(2, "SNDCTL_DSP_SPEED:\n");
@@ -455,61 +366,39 @@
 		get_user_ret(val, (int *) arg, -EFAULT);
 		DPD(2, "val is %d\n", val);
 
-		if (val >= 0)
-		{
-			if (file->f_mode & FMODE_WRITE)
-			{
-				struct wave_format *wave_fmt;
-
+		if (val >= 0) {
+			if (file->f_mode & FMODE_WRITE) {
 				spin_lock_irqsave(&woinst->lock, flags);
-
-				if (wave_out)
-					sblive_waveoutStop(wave_dev->sb_hw, wave_out, &dummy);
 
-				wave_fmt = &woinst->wave_fmt;
-				wave_fmt->samplingrate = val;
+				woinst->wave_fmt.samplingrate = val;
 
-				sblive_waveoutQueryFormat(wave_dev->sb_hw->card_waveout, wave_fmt, CARDWAVE_QF_RATE);
-
-				if (woinst->mapped)
-				{
-					struct wave_format wave_fmt = woinst->wave_fmt;
+				if (emu10k1_waveout_setformat(wave_dev) != CTSTATUS_SUCCESS)
+					return -EINVAL;
 
-					if (sblive_waveoutSetControl(wave_dev->sb_hw, wave_out, WAVEINSTANCEFORMAT, (u32 *)&wave_fmt)
-					    != CTSTATUS_SUCCESS)
-					{
-						spin_unlock_irqrestore(&woinst->lock, flags);
-						return -EINVAL;
-					}
-				}
+				val = woinst->wave_fmt.samplingrate;
 
 				spin_unlock_irqrestore(&woinst->lock, flags);
 
-				DPD(2, "Set playback sampling rate -> %d\n", woinst->wave_fmt.samplingrate);
+				DPD(2, "set playback sampling rate -> %d\n", val);
 			}
-
-			if (file->f_mode & FMODE_READ)
-			{
-				struct wave_format *wave_fmt;
 
+			if (file->f_mode & FMODE_READ) {
 				spin_lock_irqsave(&wiinst->lock, flags);
 
-				if (wave_in)
-					sblive_waveinStop(wave_dev->sb_hw, wave_in, &dummy);
-
-				wave_fmt = &wiinst->wave_fmt;
-				wave_fmt->samplingrate = val;
+				wiinst->wave_fmt.samplingrate = val;
 
-				sblive_waveinQueryFormat(wave_dev->sb_hw->card_wavein, wave_fmt, CARDWAVE_QF_RATE);
+				if (emu10k1_wavein_setformat(wave_dev) != CTSTATUS_SUCCESS)
+					return -EINVAL;
 
-				DPD(2, "Set recording sampling rate -> %d\n", wave_fmt->samplingrate);
+				val = wiinst->wave_fmt.samplingrate;
 
 				spin_unlock_irqrestore(&wiinst->lock, flags);
+
+				DPD(2, "set recording sampling rate -> %d\n", val);
 			}
 
 			return put_user(val, (int *) arg);
-		} else
-		{
+		} else {
 			if (file->f_mode & FMODE_READ)
 				val = wiinst->wave_fmt.samplingrate;
 			else if (file->f_mode & FMODE_WRITE)
@@ -524,64 +413,38 @@
 
 		get_user_ret(val, (int *) arg, -EFAULT);
 		DPD(2, " val is %d\n", val);
-
-		if (file->f_mode & FMODE_WRITE)
-		{
-			struct wave_format *wave_fmt;
 
+		if (file->f_mode & FMODE_WRITE) {
 			spin_lock_irqsave(&woinst->lock, flags);
 
-			if (wave_out)
-				sblive_waveoutStop(wave_dev->sb_hw, wave_out, &dummy);
-
-			wave_fmt = &woinst->wave_fmt;
-			wave_fmt->channels = val ? 2 : 1;
+			woinst->wave_fmt.channels = val ? 2 : 1;
 
-			if (sblive_waveoutQueryFormat(wave_dev->sb_hw->card_waveout, wave_fmt, CARDWAVE_QF_STEREO) != CTSTATUS_SUCCESS)
-			{
-				spin_unlock_irqrestore(&woinst->lock, flags);
-				DPF(2, "waveoutQueryFormat() failed!\n");
+			if (emu10k1_waveout_setformat(wave_dev) != CTSTATUS_SUCCESS)
 				return -EINVAL;
-			}
 
-			if (woinst->mapped)
-			{
-				if (sblive_waveoutSetControl(wave_dev->sb_hw, wave_out, WAVEINSTANCEFORMAT, (u32 *)&wave_fmt) != CTSTATUS_SUCCESS)
-				{
-					spin_unlock_irqrestore(&woinst->lock, flags);
-					DPF(2, "waveoutSetControl() failed!\n");
-					return -EINVAL;
-				}
-			}
+			val = woinst->wave_fmt.channels - 1;
 
 			spin_unlock_irqrestore(&woinst->lock, flags);
 
-			DPD(2, "Set playback stereo -> %d\n", wave_fmt->channels);
+			DPD(2, "set playback stereo -> %d\n", val);
 		}
 
-		if (file->f_mode & FMODE_READ)
-		{
-			struct wave_format *wave_fmt;
-
+		if (file->f_mode & FMODE_READ) {
 			spin_lock_irqsave(&wiinst->lock, flags);
-
-			if (wave_in)
-				sblive_waveinStop(wave_dev->sb_hw, wave_in, &dummy);
 
-			wave_fmt = &wiinst->wave_fmt;
-			wave_fmt->channels = val ? 2 : 1;
+			wiinst->wave_fmt.channels = val ? 2 : 1;
 
-			if (sblive_waveinQueryFormat(wave_dev->sb_hw->card_wavein, wave_fmt, CARDWAVE_QF_STEREO) != CTSTATUS_SUCCESS)
-			{
-				spin_unlock_irqrestore(&wiinst->lock, flags);
-				DPF(2, "waveinQueryFormat() failed!\n");
+			if (emu10k1_wavein_setformat(wave_dev) != CTSTATUS_SUCCESS)
 				return -EINVAL;
-			}
+
+			val = wiinst->wave_fmt.channels - 1;
 
 			spin_unlock_irqrestore(&wiinst->lock, flags);
-			DPD(2, "Set recording stereo -> %d\n", wave_fmt->channels);
+			DPD(2, "set recording stereo -> %d\n", val);
 		}
 
+		return put_user(val, (int *) arg);
+
 		break;
 
 	case SNDCTL_DSP_CHANNELS:
@@ -589,72 +452,38 @@
 
 		get_user_ret(val, (int *) arg, -EFAULT);
 		DPD(2, " val is %d\n", val);
-
-		if (val != 0)
-		{
-			if (file->f_mode & FMODE_WRITE)
-			{
-				struct wave_format *wave_fmt;
 
+		if (val != 0) {
+			if (file->f_mode & FMODE_WRITE) {
 				spin_lock_irqsave(&woinst->lock, flags);
 
-				if (wave_out)
-					sblive_waveoutStop(wave_dev->sb_hw, wave_out, &dummy);
-
-				wave_fmt = &woinst->wave_fmt;
-				wave_fmt->channels = val;
+				woinst->wave_fmt.channels = val;
 
-				if (sblive_waveoutQueryFormat(wave_dev->sb_hw->card_waveout, wave_fmt, CARDWAVE_QF_CHANNEL) != CTSTATUS_SUCCESS)
-				{
-					spin_unlock_irqrestore(&woinst->lock, flags);
-					DPF(2, "waveoutQueryFormat() called!\n");
+				if (emu10k1_waveout_setformat(wave_dev) != CTSTATUS_SUCCESS)
 					return -EINVAL;
-				}
-				/*
-				if (woinst->mapped)
-				{
-					struct wave_format wave_fmt = woinst->wave_fmt;
 
-					if (sblive_waveoutSetControl(wave_dev->sb_hw, wave_out, WAVEINSTANCEFORMAT, (u32 *)&wave_fmt) != CTSTATUS_SUCCESS)
-					{
-						spin_unlock_irqrestore(&woinst->lock, flags);
-						DPF(2, "waveoutSetControl() failed!\n");
-						return -EINVAL;
-					}
-				}
-				*/
-				DPD(2, "Set playback number of channels -> %d\n", wave_fmt->channels);
+				val = woinst->wave_fmt.channels;
 
 				spin_unlock_irqrestore(&woinst->lock, flags);
+				DPD(2, "set playback number of channels -> %d\n", val);
 			}
 
-			if (file->f_mode & FMODE_READ)
-			{
-				struct wave_format *wave_fmt;
-
+			if (file->f_mode & FMODE_READ) {
 				spin_lock_irqsave(&wiinst->lock, flags);
-
-				if (wave_in)
-					sblive_waveinStop(wave_dev->sb_hw, wave_in, &dummy);
 
-				wave_fmt = &wiinst->wave_fmt;
-				wave_fmt->channels = val;
+				wiinst->wave_fmt.channels = val;
 
-				if (sblive_waveinQueryFormat(wave_dev->sb_hw->card_wavein, wave_fmt, CARDWAVE_QF_CHANNEL) != CTSTATUS_SUCCESS)
-				{
-					spin_unlock_irqrestore(&wiinst->lock, flags);
-					DPF(2, "waveinQueryFormat() called!\n");
+				if (emu10k1_wavein_setformat(wave_dev) != CTSTATUS_SUCCESS)
 					return -EINVAL;
-				}
 
-				spin_unlock_irqrestore(&wiinst->lock, flags);
+				val = wiinst->wave_fmt.channels;
 
-				DPD(2, "Set recording number of channels -> %d\n", wave_fmt->channels);
+				spin_unlock_irqrestore(&wiinst->lock, flags);
+				DPD(2, "set recording number of channels -> %d\n", val);
 			}
 
 			return put_user(val, (int *) arg);
-		} else
-		{
+		} else {
 			if (file->f_mode & FMODE_READ)
 				val = wiinst->wave_fmt.channels;
 			else if (file->f_mode & FMODE_WRITE)
@@ -666,73 +495,55 @@
 
 	case SNDCTL_DSP_GETFMTS:
 		DPF(2, "SNDCTL_DSP_GETFMTS:\n");
-		return put_user(AFMT_S16_LE | AFMT_U8, (int *) arg);
+
+		if (file->f_mode & FMODE_READ)
+			val = AFMT_S16_LE;
+		else if (file->f_mode & FMODE_WRITE)
+			val = AFMT_S16_LE | AFMT_U8;
+
+		return put_user(val, (int *) arg);
 
 	case SNDCTL_DSP_SETFMT:	/* Same as SNDCTL_DSP_SAMPLESIZE */
 		DPF(2, "SNDCTL_DSP_SETFMT:\n");
 
 		get_user_ret(val, (int *) arg, -EFAULT);
 		DPD(2, " val is %d\n", val);
-
-		if (val != AFMT_QUERY)
-		{
-			if (file->f_mode & FMODE_WRITE)
-			{
-				struct wave_format *wave_fmt;
 
+		if (val != AFMT_QUERY) {
+			if (file->f_mode & FMODE_WRITE) {
 				spin_lock_irqsave(&woinst->lock, flags);
-
-				if (wave_out)
-					sblive_waveoutStop(wave_dev->sb_hw, wave_out, &dummy);
 
-				wave_fmt = &woinst->wave_fmt;
-				wave_fmt->bitspersample = val;
+				woinst->wave_fmt.bitsperchannel = val;
 
-				sblive_waveoutQueryFormat(wave_dev->sb_hw->card_waveout, wave_fmt, CARDWAVE_QF_BITS);
+				if (emu10k1_waveout_setformat(wave_dev) != CTSTATUS_SUCCESS)
+					return -EINVAL;
 
-				if (woinst->mapped)
-				{
-					struct wave_format wave_fmt = woinst->wave_fmt;
+				val = woinst->wave_fmt.bitsperchannel;
 
-					if (sblive_waveoutSetControl(wave_dev->sb_hw, wave_out, WAVEINSTANCEFORMAT, (u32 *) &wave_fmt) != CTSTATUS_SUCCESS)
-					{
-						spin_unlock_irqrestore(&woinst->lock, flags);
-						DPF(2, "waveoutSetControl() failed!\n");
-						return -EINVAL;
-					}
-				}
-
 				spin_unlock_irqrestore(&woinst->lock, flags);
-
-				DPD(2, "Set playback sample size -> %d\n", wave_fmt->bitspersample);
+				DPD(2, "set playback sample size -> %d\n", val);
 			}
-
-			if (file->f_mode & FMODE_READ)
-			{
-				struct wave_format *wave_fmt;
 
+			if (file->f_mode & FMODE_READ) {
 				spin_lock_irqsave(&wiinst->lock, flags);
 
-				if (wave_in)
-					sblive_waveinStop(wave_dev->sb_hw, wave_in, &dummy);
+				wiinst->wave_fmt.bitsperchannel = val;
 
-				wave_fmt = &wiinst->wave_fmt;
-				wave_fmt->bitspersample = val;
+				if (emu10k1_wavein_setformat(wave_dev) != CTSTATUS_SUCCESS)
+					return -EINVAL;
 
-				sblive_waveinQueryFormat(wave_dev->sb_hw->card_wavein, wave_fmt, CARDWAVE_QF_BITS);
+				val = wiinst->wave_fmt.bitsperchannel;
 
 				spin_unlock_irqrestore(&wiinst->lock, flags);
-
-				DPD(2, "set recording sample size -> %d\n", wave_fmt->bitspersample);
+				DPD(2, "set recording sample size -> %d\n", val);
 			}
 
-			return put_user((val == 16) ? AFMT_S16_LE : AFMT_U8, (int *)arg);
-		} else
-		{
+			return put_user((val == 16) ? AFMT_S16_LE : AFMT_U8, (int *) arg);
+		} else {
 			if (file->f_mode & FMODE_READ)
-				val = wiinst->wave_fmt.bitspersample;
+				val = wiinst->wave_fmt.bitsperchannel;
 			else if (file->f_mode & FMODE_WRITE)
-				val = woinst->wave_fmt.bitspersample;
+				val = woinst->wave_fmt.bitsperchannel;
 
 			return put_user((val == 16) ? AFMT_S16_LE : AFMT_U8, (int *) arg);
 		}
@@ -741,40 +552,40 @@
 	case SOUND_PCM_READ_BITS:
 
 		if (file->f_mode & FMODE_READ)
-			val = wiinst->wave_fmt.bitspersample;
-		else if ( file->f_mode & FMODE_WRITE )
-			val = woinst->wave_fmt.bitspersample;
+			val = wiinst->wave_fmt.bitsperchannel;
+		else if (file->f_mode & FMODE_WRITE)
+			val = woinst->wave_fmt.bitsperchannel;
 
-		return put_user((val == 16) ? AFMT_S16_LE : AFMT_U8, (int *)arg);
+		return put_user((val == 16) ? AFMT_S16_LE : AFMT_U8, (int *) arg);
 
 	case SOUND_PCM_READ_RATE:
 
 		if (file->f_mode & FMODE_READ)
 			val = wiinst->wave_fmt.samplingrate;
-		else if ( file->f_mode & FMODE_WRITE )
+		else if (file->f_mode & FMODE_WRITE)
 			val = woinst->wave_fmt.samplingrate;
 
-		return put_user(val, (int *)arg);
+		return put_user(val, (int *) arg);
 
 	case SOUND_PCM_READ_CHANNELS:
 
 		if (file->f_mode & FMODE_READ)
 			val = wiinst->wave_fmt.channels;
-		else if ( file->f_mode & FMODE_WRITE )
+		else if (file->f_mode & FMODE_WRITE)
 			val = woinst->wave_fmt.channels;
 
-		return put_user(val, (int *)arg);
+		return put_user(val, (int *) arg);
 
 	case SOUND_PCM_WRITE_FILTER:
-		DPF(2, "SNDCTL_DSP_POST: not implemented\n");
+		DPF(2, "SOUND_PCM_WRITE_FILTER: not implemented\n");
 		break;
 
 	case SOUND_PCM_READ_FILTER:
-		DPF(2, "SNDCTL_DSP_POST: not implemented\n");
+		DPF(2, "SOUND_PCM_READ_FILTER: not implemented\n");
 		break;
 
 	case SNDCTL_DSP_SETSYNCRO:
-		DPF(2, "SNDCTL_DSP_POST: not implemented\n");
+		DPF(2, "SNDCTL_DSP_SETSYNCRO: not implemented\n");
 		break;
 
 	case SNDCTL_DSP_GETTRIGGER:
@@ -792,41 +603,33 @@
 
 		get_user_ret(val, (int *) arg, -EFAULT);
 
-		if (file->f_mode & FMODE_WRITE)
-		{
+		if (file->f_mode & FMODE_WRITE) {
 			spin_lock_irqsave(&woinst->lock, flags);
 
-			if (wave_out)
-			{
-				if (val & PCM_ENABLE_OUTPUT)
-				{
-					sblive_waveoutStart(wave_dev);
-					wave_dev->enablebits |= PCM_ENABLE_OUTPUT;
-				} else
-				{
-					sblive_waveoutStop(wave_dev->sb_hw, wave_out, &dummy);
-					wave_dev->enablebits &= ~PCM_ENABLE_OUTPUT;
-				}
+			if (val & PCM_ENABLE_OUTPUT) {
+				wave_dev->enablebits |= PCM_ENABLE_OUTPUT;
+				if (wave_out)
+					emu10k1_waveout_start(wave_dev);
+			} else {
+				wave_dev->enablebits &= ~PCM_ENABLE_OUTPUT;
+				if (wave_out)
+					emu10k1_waveout_stop(wave_dev);
 			}
 
 			spin_unlock_irqrestore(&woinst->lock, flags);
 		}
 
-		if (file->f_mode & FMODE_READ)
-		{
+		if (file->f_mode & FMODE_READ) {
 			spin_lock_irqsave(&wiinst->lock, flags);
 
-			if (wave_in)
-			{
-				if (val & PCM_ENABLE_INPUT)
-				{
-					sblive_waveinStart(wave_dev);
-					wave_dev->enablebits |= PCM_ENABLE_INPUT;
-				} else
-				{
-					sblive_waveinStop(wave_dev->sb_hw, wave_in, &dummy);
-					wave_dev->enablebits &= ~PCM_ENABLE_INPUT;
-				}
+			if (val & PCM_ENABLE_INPUT) {
+				wave_dev->enablebits |= PCM_ENABLE_INPUT;
+				if (wave_in)
+					emu10k1_wavein_start(wave_dev);
+			} else {
+				wave_dev->enablebits &= ~PCM_ENABLE_INPUT;
+				if (wave_in)
+					emu10k1_wavein_stop(wave_dev);
 			}
 
 			spin_unlock_irqrestore(&wiinst->lock, flags);
@@ -841,46 +644,25 @@
 
 			if (!(file->f_mode & FMODE_WRITE))
 				return -EINVAL;
-
-			spin_lock_irqsave(&woinst->lock, flags);
 
-			if (wave_out)
-			{
-				if (sblive_waveoutGetXferSize(wave_dev->sb_hw->card_waveout, wave_out, &bytestocopy, &pending)
-				    != CTSTATUS_SUCCESS)
-				{
-					DPF(2, "sblive_waveoutGetXferSize failed\n");
+			if (wave_out) {
+				spin_lock_irqsave(&woinst->lock, flags);
+				emu10k1_waveout_getxfersize(wave_out, &bytestocopy, &pending, &dummy);
+				spin_unlock_irqrestore(&woinst->lock, flags);
 
-					spin_unlock_irqrestore(&woinst->lock, flags);
-					return -EFAULT;
-				}
 				info.bytes = bytestocopy;
-			} else
-			{
-				calculate_ofrag(woinst);
-				info.bytes = woinst->numfrags * woinst->fragment_size;
-			}
-
-			if (woinst->silence_filled > 0)
-			{
-				if (woinst->silence_filled == 1)
-				{
-					if (pending <= woinst->fragment_size)
-						woinst->silence_filled = 2;
-					else
-						info.bytes += woinst->fragment_size;
-				}
+			} else {
+				spin_lock_irqsave(&woinst->lock, flags);
+				calculate_ofrag(woinst);
+				spin_unlock_irqrestore(&woinst->lock, flags);
 
-				if (woinst->silence_filled == 2)
-					info.bytes = woinst->numfrags * woinst->fragment_size;
+				info.bytes = woinst->numfrags * woinst->fragment_size;
 			}
 
 			info.fragstotal = woinst->numfrags;
 			info.fragments = info.bytes / woinst->fragment_size;
 			info.fragsize = woinst->fragment_size;
 
-			spin_unlock_irqrestore(&woinst->lock, flags);
-
 			if (copy_to_user((int *) arg, &info, sizeof(info)))
 				return -EFAULT;
 		}
@@ -894,34 +676,25 @@
 
 			if (!(file->f_mode & FMODE_READ))
 				return -EINVAL;
-
-			spin_lock_irqsave(&wiinst->lock, flags);
-
-			if (wave_in)
-			{
-				if (sblive_waveinGetXferSize(wave_dev->sb_hw->card_wavein, wave_in, &bytestocopy, &pending)
-				    != CTSTATUS_SUCCESS)
-				{
-					DPF(2, "sblive_waveinGetXferSize failed\n");
 
-					spin_unlock_irqrestore(&wiinst->lock, flags);
-					return -EFAULT;
-				}
+			if (wave_in) {
+				spin_lock_irqsave(&wiinst->lock, flags);
+				emu10k1_wavein_getxfersize(wave_in, &bytestocopy, &dummy);
+				spin_unlock_irqrestore(&wiinst->lock, flags);
 
 				info.bytes = bytestocopy;
-
-			} else
-			{
+			} else {
+				spin_lock_irqsave(&wiinst->lock, flags);
 				calculate_ifrag(wiinst);
-				info.bytes = wiinst->numfrags * wiinst->fragment_size;
+				spin_unlock_irqrestore(&wiinst->lock, flags);
+
+				info.bytes = 0;
 			}
 
 			info.fragstotal = wiinst->numfrags;
 			info.fragments = info.bytes / wiinst->fragment_size;
 			info.fragsize = wiinst->fragment_size;
 
-			spin_unlock_irqrestore(&wiinst->lock, flags);
-
 			if (copy_to_user((int *) arg, &info, sizeof(info)))
 				return -EFAULT;
 		}
@@ -938,38 +711,15 @@
 
 		if (!(file->f_mode & FMODE_WRITE))
 			return -EINVAL;
-
-		spin_lock_irqsave(&woinst->lock, flags);
-
-		if (wave_out)
-		{
-			if (sblive_waveoutGetXferSize(wave_dev->sb_hw->card_waveout, wave_out, &bytestocopy, &pending)
-			    != CTSTATUS_SUCCESS)
-			{
-				DPF(2, "sblive_waveoutGetXferSize failed\n");
-
-				spin_unlock_irqrestore(&woinst->lock, flags);
-				return -EFAULT;
-			}
-
-			if (woinst->silence_filled > 0)
-			{
-				if (woinst->silence_filled == 1)
-				{
-					if (pending <= woinst->fragment_size)
-						woinst->silence_filled = 2;
-					else
-						pending -= woinst->fragment_size;
-				}
 
-				if (woinst->silence_filled == 2)
-					pending = 0;
-			}
+		if (wave_out) {
+			spin_lock_irqsave(&woinst->lock, flags);
+			emu10k1_waveout_getxfersize(wave_out, &bytestocopy, &pending, &dummy);
+			spin_unlock_irqrestore(&woinst->lock, flags);
 
 			val = pending;
-		}
-
-		spin_unlock_irqrestore(&woinst->lock, flags);
+		} else
+			val = 0;
 
 		return put_user(val, (int *) arg);
 
@@ -984,23 +734,18 @@
 
 			spin_lock_irqsave(&wiinst->lock, flags);
 
-			if (wave_in)
-			{
-				if (sblive_waveinGetControl(wave_dev->sb_hw->card_wavein, wave_in, WAVECURPOS, (u32 *)&cinfo.ptr)
-				    != CTSTATUS_SUCCESS)
-				{
-					spin_unlock_irqrestore(&wiinst->lock, flags);
-					return -EINVAL;
-				}
-			} else
+			if (wave_in) {
+				emu10k1_wavein_getcontrol(wave_in, WAVECURPOS, (u32 *) & cinfo.ptr);
+				cinfo.bytes =
+				    cinfo.ptr + wiinst->total_recorded - wiinst->total_recorded % (wiinst->fragment_size * wiinst->numfrags);
+				cinfo.blocks = cinfo.bytes / wiinst->fragment_size - wiinst->blocks;
+				wiinst->blocks = cinfo.bytes / wiinst->fragment_size;
+			} else {
 				cinfo.ptr = 0;
-
-			DPD(4, "cinfo.ptr -> %d\n", cinfo.ptr);
-
-			cinfo.bytes = cinfo.ptr + wiinst->total_recorded - wiinst->total_recorded % (wiinst->fragment_size * wiinst->numfrags);
-			cinfo.blocks = wiinst->getiptr_blocks;
-
-			wiinst->getiptr_blocks = 0;
+				cinfo.bytes = 0;
+				cinfo.blocks = 0;
+				wiinst->blocks = 0;
+			}
 
 			spin_unlock_irqrestore(&wiinst->lock, flags);
 
@@ -1020,23 +765,17 @@
 
 			spin_lock_irqsave(&woinst->lock, flags);
 
-			if (wave_out)
-			{
-				if (sblive_waveoutGetControl(wave_dev->sb_hw->card_waveout, wave_out, WAVECURPOS, (u32 *)&cinfo.ptr)
-				    != CTSTATUS_SUCCESS)
-				{
-					spin_unlock_irqrestore(&woinst->lock, flags);
-					return -EINVAL;
-				}
-			} else
+			if (wave_out) {
+				emu10k1_waveout_getcontrol(wave_out, WAVECURPOS, (u32 *) & cinfo.ptr);
+				cinfo.bytes = cinfo.ptr + woinst->total_played - woinst->total_played % (woinst->fragment_size * woinst->numfrags);
+				cinfo.blocks = cinfo.bytes / woinst->fragment_size - woinst->blocks;
+				woinst->blocks = cinfo.bytes / woinst->fragment_size;
+			} else {
 				cinfo.ptr = 0;
-
-			DPD(4, "cinfo.ptr -> %d\n", cinfo.ptr);
-
-			cinfo.bytes = cinfo.ptr + woinst->total_played - woinst->total_played % (woinst->fragment_size * woinst->numfrags);
-			cinfo.blocks = cinfo.bytes / woinst->fragment_size - woinst->getoptr_blocks;
-
-			woinst->getoptr_blocks = cinfo.bytes / woinst->fragment_size;
+				cinfo.bytes = 0;
+				cinfo.blocks = 0;
+				woinst->blocks = 0;
+			}
 
 			spin_unlock_irqrestore(&woinst->lock, flags);
 
@@ -1048,27 +787,26 @@
 	case SNDCTL_DSP_GETBLKSIZE:
 		DPF(2, "SNDCTL_DSP_GETBLKSIZE:\n");
 
-		if (file->f_mode & FMODE_WRITE)
-		{
+		if (file->f_mode & FMODE_WRITE) {
 			spin_lock_irqsave(&woinst->lock, flags);
 
 			calculate_ofrag(woinst);
+			val = woinst->fragment_size;
 
 			spin_unlock_irqrestore(&woinst->lock, flags);
-
-			return put_user(woinst->fragment_size, (int *) arg);
 		}
 
-		if (file->f_mode & FMODE_READ)
-		{
+		if (file->f_mode & FMODE_READ) {
 			spin_lock_irqsave(&wiinst->lock, flags);
 
 			calculate_ifrag(wiinst);
+			val = wiinst->fragment_size;
 
 			spin_unlock_irqrestore(&wiinst->lock, flags);
-
-			return put_user(wiinst->fragment_size, (int *) arg);
 		}
+
+		return put_user(val, (int *) arg);
+
 		break;
 
 	case SNDCTL_DSP_POST:
@@ -1089,19 +827,17 @@
 		if (val == 0)
 			return -EIO;
 
-		if (file->f_mode & FMODE_WRITE)
-		{
+		if (file->f_mode & FMODE_WRITE) {
 			if (wave_out)
-				return -EINVAL;		/* too late to change */
+				return -EINVAL;	/* too late to change */
 
 			woinst->ossfragshift = val & 0xffff;
 			woinst->numfrags = (val >> 16) & 0xffff;
 		}
 
-		if (file->f_mode & FMODE_READ)
-		{
+		if (file->f_mode & FMODE_READ) {
 			if (wave_in)
-				return -EINVAL;		/* too late to change */
+				return -EINVAL;	/* too late to change */
 
 			wiinst->ossfragshift = val & 0xffff;
 			wiinst->numfrags = (val >> 16) & 0xffff;
@@ -1113,32 +849,33 @@
 		{
 			copr_buffer buf;
 			u32 i;
-			
+
 			DPF(2, "SNDCTL_COPR_LOAD:\n");
 
 			if (copy_from_user(&buf, (copr_buffer *) arg, sizeof(buf)))
 				return -EFAULT;
-			
+
 			if ((buf.command != 1) && (buf.command != 2))
 				return -EINVAL;
 
-			if ((buf.offs < 0) || (buf.offs + buf.len > 0x500) || (buf.len > 1000))
+			if (((buf.offs < 0x100) && (buf.command == 2))
+			    || (buf.offs < 0x000)
+			    || (buf.offs + buf.len > 0x800) || (buf.len > 1000))
 				return -EINVAL;
 
-			buf.offs += 0x100;
-
 			if (buf.command == 1) {
 				for (i = 0; i < buf.len; i++)
-					((u32 *) buf.data)[i] = sblive_readptr(wave_dev->sb_hw, buf.offs + i, 0);
-                                if (copy_to_user((copr_buffer *) arg, &buf, sizeof(buf)))
-					return -EFAULT;											
+
+					((u32 *) buf.data)[i] = sblive_readptr(wave_dev->card, buf.offs + i, 0);
+				if (copy_to_user((copr_buffer *) arg, &buf, sizeof(buf)))
+					return -EFAULT;
 			} else {
 				for (i = 0; i < buf.len; i++)
-					sblive_writeptr(wave_dev->sb_hw, buf.offs + i, 0, ((u32 *) buf.data)[i]);
+					sblive_writeptr(wave_dev->card, buf.offs + i, 0, ((u32 *) buf.data)[i]);
 			}
 			break;
 		}
-		
+
 	default:		/* Default is unrecognized command */
 		DPD(2, "default: %x\n", cmd);
 		return -EINVAL;
@@ -1148,63 +885,65 @@
 
 static int emu10k1_audio_mmap(struct file *file, struct vm_area_struct *vma)
 {
-	struct sblive_wavedevice *wave_dev = (struct sblive_wavedevice *) file->private_data;
+	struct emu10k1_wavedevice *wave_dev = (struct emu10k1_wavedevice *) file->private_data;
 
-	DPF(2, "emu10k1_audio_mmap() called\n");
+	DPF(2, "emu10k1_audio_mmap()\n");
 
 	if (vma_get_pgoff(vma) != 0)
 		return -ENXIO;
 
-	if (vma->vm_flags & VM_WRITE){
+	if (vma->vm_flags & VM_WRITE) {
 		struct woinst *woinst = wave_dev->woinst;
-		u32 size, flags;
+		struct wave_out *wave_out;
+		u32 size;
+		unsigned long flags;
 		int i;
 
 		spin_lock_irqsave(&woinst->lock, flags);
 
-		if (!woinst->wave_out)
-		{
-			calculate_ofrag(woinst);
+		wave_out = woinst->wave_out;
 
-			if (sblive_waveoutOpen(wave_dev->sb_hw, &woinst->wave_fmt, &woinst->fragment_size, woinst->numfrags, &woinst->wave_out)
-			    != CTSTATUS_SUCCESS)
-			{
-				DPF(2, "sblive_waveoutOpen failed!\n");
+		if (!wave_out) {
+			calculate_ofrag(woinst);
 
+			if (emu10k1_waveout_open(wave_dev) != CTSTATUS_SUCCESS) {
 				spin_unlock_irqrestore(&woinst->lock, flags);
+				ERROR();
 				return -EINVAL;
 			}
 
+			wave_out = woinst->wave_out;
+
 			/* Now mark the pages as reserved, otherwise remap_page_range doesn't do what we want */
-			for (i = 0; i < woinst->wave_out->wavexferbuf->numpages; i++)
-				set_bit(PG_reserved, &mem_map[MAP_NR(woinst->wave_out->pagetable[i])].flags);
+			for (i = 0; i < wave_out->wavexferbuf->numpages; i++)
+				set_bit(PG_reserved, &mem_map[MAP_NR(wave_out->pagetable[i])].flags);
 		}
 
 		size = vma->vm_end - vma->vm_start;
 
-		if (size > (PAGE_SIZE * woinst->wave_out->wavexferbuf->numpages)) {
+		if (size > (PAGE_SIZE * wave_out->wavexferbuf->numpages)) {
 			spin_unlock_irqrestore(&woinst->lock, flags);
 			return -EINVAL;
 		}
 
-		for (i = 0; i < woinst->wave_out->wavexferbuf->numpages; i++) {
-			if (remap_page_range(vma->vm_start + (i * 4096), virt_to_phys(woinst->wave_out->pagetable[i]), 4096, vma->vm_page_prot)) {
+		for (i = 0; i < wave_out->wavexferbuf->numpages; i++) {
+			if (remap_page_range(vma->vm_start + (i * PAGE_SIZE), virt_to_phys(wave_out->pagetable[i]), PAGE_SIZE, vma->vm_page_prot)) {
 				spin_unlock_irqrestore(&woinst->lock, flags);
 				return -EAGAIN;
 			}
 		}
 
-		woinst->mapped = TRUE;
+		woinst->mapped = 1;
 
 		spin_unlock_irqrestore(&woinst->lock, flags);
 	}
 
-	if (vma->vm_flags & VM_READ){
+	if (vma->vm_flags & VM_READ) {
 		struct wiinst *wiinst = wave_dev->wiinst;
-		u32 flags;
+		unsigned long flags;
 
 		spin_lock_irqsave(&wiinst->lock, flags);
-		wiinst->mapped = TRUE;
+		wiinst->mapped = 1;
 		spin_unlock_irqrestore(&wiinst->lock, flags);
 	}
 
@@ -1214,368 +953,336 @@
 static int emu10k1_audio_open(struct inode *inode, struct file *file)
 {
 	int minor = MINOR(inode->i_rdev);
-	struct sblive_hw *sb_hw = sblive_devs;
-	struct sblive_wavedevice *wave_dev;
+	struct emu10k1_card *card;
+	struct list_head *entry;
+	struct emu10k1_wavedevice *wave_dev;
 
-	DPF(2, "emu10k1_audio_open() called\n");
+	DPF(2, "emu10k1_audio_open()\n");
 
 	/* Check for correct device to open */
-	while (sb_hw && ((sb_hw->audio_num ^ minor) & ~0x0f))
-		sb_hw = sb_hw->next;
-
-	if (!sb_hw)
-		return -ENODEV;
 
-	/* Wait for device to become free */
-	down(&sb_hw->open_sem);
+	list_for_each(entry, &emu10k1_devs) {
+		card = list_entry(entry, struct emu10k1_card, list);
 
-	while ((file->f_mode & FMODE_READ) && (sb_hw->open_mode & FMODE_READ))
-	{
-		if (file->f_flags & O_NONBLOCK)
-		{
-			up(&sb_hw->open_sem);
-			return -EAGAIN;
-		}
-
-		up(&sb_hw->open_sem);
-
-		DPF(2, "open sleep....\n");
-		interruptible_sleep_on(&sb_hw->open_wait);
+		if (card->audio1_num == minor || card->audio2_num == minor)
+			break;
+	}
 
-		if (signal_pending(current))
-			return -ERESTARTSYS;
+	if (entry == &emu10k1_devs)
+		return -ENODEV;
 
-		down(&sb_hw->open_sem);
-	}
+	MOD_INC_USE_COUNT;
 
-	wave_dev = (struct sblive_wavedevice *)kmalloc(sizeof(struct sblive_wavedevice), GFP_KERNEL);
-	if (!wave_dev)
-	{
-		DPF(2, "struct sblive_wavedevice alloc fail.\n");
-		up(&sb_hw->open_sem);
+	if ((wave_dev = (struct emu10k1_wavedevice *)
+	     kmalloc(sizeof(struct emu10k1_wavedevice), GFP_KERNEL)) == NULL) {
+		ERROR();
+		MOD_DEC_USE_COUNT;
 		return -EINVAL;
 	}
-
-	DPD(3, "kmalloc: [%p]\n", wave_dev);
 
-	wave_dev->sb_hw = sb_hw;
+	wave_dev->card = card;
 	wave_dev->wiinst = NULL;
 	wave_dev->woinst = NULL;
 	wave_dev->enablebits = PCM_ENABLE_OUTPUT | PCM_ENABLE_INPUT;	/* Default */
 
-	if (file->f_mode & FMODE_WRITE)
-	{
+	if (file->f_mode & FMODE_WRITE) {
 		struct woinst *woinst;
 
-		woinst = (struct woinst *) kmalloc(sizeof(struct woinst), GFP_KERNEL);
-		if (woinst == NULL)
-		{
-			DPF(2, "struct woinst alloc failed.\n");
-			up(&sb_hw->open_sem);
+		if ((woinst = (struct woinst *) kmalloc(sizeof(struct woinst), GFP_KERNEL)) == NULL) {
+			ERROR();
+			MOD_DEC_USE_COUNT;
 			return -ENODEV;
 		}
 
-		DPD(3, "kmalloc: [%p]\n", woinst);
-
-		/* Set default format to : mono 8-bit 8kHz */
-		woinst->wave_fmt.flags = 0;
 		woinst->wave_fmt.samplingrate = 8000;
-		woinst->wave_fmt.bitspersample = 8;
+		woinst->wave_fmt.bitsperchannel = 8;
 		woinst->wave_fmt.channels = 1;
-		woinst->wave_fmt.isinput = (file->f_mode == FMODE_READ) ? TRUE : FALSE;
 		woinst->ossfragshift = 0;
 		woinst->fragment_size = 0;
 		woinst->numfrags = 0;
-		woinst->wave_out = NULL;	// wave_out instance
+		woinst->device = (card->audio2_num == minor);
+		woinst->wave_out = NULL;
 
 		init_waitqueue_head(&woinst->wait_queue);
 
-		woinst->mapped = FALSE;
+		woinst->mapped = 0;
 		woinst->total_copied = 0;
 		woinst->total_played = 0;
-		woinst->silence_filled = 0;
-		woinst->silence_start = 0;
-		woinst->getoptr_blocks = 0;
-		woinst->wave_ptr = 0;
+		woinst->blocks = 0;
+		woinst->curpos = 0;
 		woinst->lock = SPIN_LOCK_UNLOCKED;
 		wave_dev->woinst = woinst;
+
+#ifdef PRIVATE_PCM_VOLUME
+		{
+			int i;
+			int j = -1;
+
+			/*
+			 * find out if we've already been in this table
+			 * xmms reopens dsp on every move of slider
+			 * this way we keep the same local pcm for such
+			 * process
+			 */
+			for (i = 0; i < MAX_PCM_CHANNELS; i++) {
+				if (sblive_pcm_volume[i].files == current->files)
+					break;
+				// here we should select last used memeber
+				// improve me in case its not sufficient
+				if (j < 0 && !sblive_pcm_volume[i].opened)
+					j = i;
+			}
+			// current task not found
+			if (i == MAX_PCM_CHANNELS) {
+				// add new entry
+				if (j < 0)
+					printk("TOO MANY WRITTERS!!!\n");
+				i = (j >= 0) ? j : 0;
+				DPD(2, "new pcm private %p\n", current->files);
+				sblive_pcm_volume[i].files = current->files;
+				sblive_pcm_volume[i].mixer = 0x6464;	// max
+				sblive_pcm_volume[i].attn_l = 0;
+				sblive_pcm_volume[i].attn_r = 0;
+				sblive_pcm_volume[i].channel_l = NUM_G;
+				sblive_pcm_volume[i].channel_r = NUM_G;
+			}
+			sblive_pcm_volume[i].opened++;
+		}
+#endif
 	}
 
-	if (file->f_mode & FMODE_READ)
-	{
+	if (file->f_mode & FMODE_READ) {
 		/* Recording */
 		struct wiinst *wiinst;
 
-		/* Only support one wave input instance */
-		if (sb_hw->card_wavein->numrecordinst >= 1)
-		{
-			DPF(2, "exceed one wave input instance\n");
-			up(&sb_hw->open_sem);
+		if ((wiinst = (struct wiinst *) kmalloc(sizeof(struct wiinst), GFP_KERNEL)) == NULL) {
+			ERROR();
+			MOD_DEC_USE_COUNT;
 			return -ENODEV;
 		}
 
-		wiinst = (struct wiinst *) kmalloc(sizeof(struct wiinst), GFP_KERNEL);
-		if (wiinst == NULL)
-		{
-			DPF(2, "struct wiinst alloc failed\n");
-			up(&sb_hw->open_sem);
-			return -ENODEV;
+		switch (card->wavein->recsrc) {
+		case WAVERECORD_AC97:
+			wiinst->wave_fmt.samplingrate = 8000;
+			wiinst->wave_fmt.bitsperchannel = 8;
+			wiinst->wave_fmt.channels = 1;
+			break;
+		case WAVERECORD_MIC:
+			wiinst->wave_fmt.samplingrate = 8000;
+			wiinst->wave_fmt.bitsperchannel = 8;
+			wiinst->wave_fmt.channels = 1;
+			break;
+		case WAVERECORD_FX:
+			wiinst->wave_fmt.samplingrate = 48000;
+			wiinst->wave_fmt.bitsperchannel = 16;
+			wiinst->wave_fmt.channels = 2;
+			break;
+		default:
+			break;
 		}
-
-		DPD(3, "kmalloc: [%p]\n", wiinst);
 
-		/* Set default format to : mono 8-bit 8kHz */
-		wiinst->wave_fmt.flags = 0;
-		wiinst->wave_fmt.samplingrate = 8000;
-		wiinst->wave_fmt.bitspersample = 8;
-		wiinst->wave_fmt.channels = 1;
-		wiinst->wave_fmt.isinput = (file->f_mode == FMODE_READ) ? TRUE : FALSE;
+		wiinst->recsrc = card->wavein->recsrc;
 		wiinst->ossfragshift = 0;
 		wiinst->fragment_size = 0;
 		wiinst->numfrags = 0;
-		wiinst->wave_in = NULL;	/* sblive_wavein instance */
+		wiinst->wave_in = NULL;
 
 		init_waitqueue_head(&wiinst->wait_queue);
 
-		wiinst->mapped = FALSE;
+		wiinst->mapped = 0;
 		wiinst->total_recorded = 0;
-		wiinst->getiptr_blocks = 0;
+		wiinst->blocks = 0;
+		wiinst->curpos = 0;
 		wiinst->lock = SPIN_LOCK_UNLOCKED;
 		wave_dev->wiinst = wiinst;
-		wave_dev->sb_hw->card_wavein->numrecordinst++;
-
-#ifdef EMU10K1_DEBUG
-		if (wave_dev->woinst != NULL)
-			DPF(2, "audio_open opened both WAVEOUT and WAVEIN!\n");
-#endif
-
 	}
 
 	file->private_data = (void *) wave_dev;
-
-	sb_hw->open_mode |= file->f_mode & FMODE_READ;
-	up(&sb_hw->open_sem);
 
-	MOD_INC_USE_COUNT;
-	return 0; /* Success? */
+	return 0;		/* Success? */
 }
 
-
 static int emu10k1_audio_release(struct inode *inode, struct file *file)
 {
-	struct sblive_wavedevice *wave_dev = (struct sblive_wavedevice *) file->private_data;
-	struct sblive_hw *sb_hw = wave_dev->sb_hw;
-
-	/* FIXME: Do we need a spinlock here? */
+	struct emu10k1_wavedevice *wave_dev = (struct emu10k1_wavedevice *) file->private_data;
+	struct emu10k1_card *card = wave_dev->card;
+	unsigned long flags;
 
-	DPF(2, "emu10k1_audio_release() called\n");
+	DPF(2, "emu10k1_audio_release()\n");
 
-	if (file->f_mode & FMODE_WRITE)
-	{
+	if (file->f_mode & FMODE_WRITE) {
 		struct woinst *woinst = wave_dev->woinst;
-		struct wave_out *wave_out = woinst->wave_out;
+		struct wave_out *wave_out;
 
-		if (wave_out)
-		{
-			if ((wave_out->state == CARDWAVE_STATE_STARTED) && !(file->f_flags & O_NONBLOCK))
-			{
+		spin_lock_irqsave(&woinst->lock, flags);
+
+		wave_out = woinst->wave_out;
+
+		if (wave_out) {
+			if ((wave_out->state == CARDWAVE_STATE_STARTED)
+			    && !(file->f_flags & O_NONBLOCK)) {
 				while (!signal_pending(current)
-				       && (woinst->total_played < woinst->total_copied))
-				{
-					DPF(2, "Buffer hasn't been totally played, sleep....\n");
+				       && (woinst->total_played < woinst->total_copied)) {
+					DPF(4, "Buffer hasn't been totally played, sleep....\n");
+					spin_unlock_irqrestore(&woinst->lock, flags);
 					interruptible_sleep_on(&woinst->wait_queue);
+					spin_lock_irqsave(&woinst->lock, flags);
 				}
 			}
 
-			if (woinst->mapped && wave_out->pagetable)
-			{
+			if (woinst->mapped && wave_out->pagetable) {
 				int i;
+
 				/* Undo marking the pages as reserved */
 				for (i = 0; i < woinst->wave_out->wavexferbuf->numpages; i++)
 					set_bit(PG_reserved, &mem_map[MAP_NR(woinst->wave_out->pagetable[i])].flags);
 			}
+
+			woinst->mapped = 0;
+			emu10k1_waveout_close(wave_dev);
+		}
+#ifdef PRIVATE_PCM_VOLUME
+		{
+			int i;
 
-			woinst->mapped = FALSE;
-			sblive_waveoutClose(wave_dev->sb_hw, wave_out);
+			/* mark as closed
+			 * NOTE: structure remains unchanged for next reopen */
+			for (i = 0; i < MAX_PCM_CHANNELS; i++) {
+				if (sblive_pcm_volume[i].files == current->files) {
+					sblive_pcm_volume[i].opened--;
+					break;
+				}
+			}
 		}
-		kfree((void *) wave_dev->woinst);
+#endif
+		spin_unlock_irqrestore(&woinst->lock, flags);
+		kfree(wave_dev->woinst);
 	}
 
-	if (file->f_mode & FMODE_READ)
-	{
+	if (file->f_mode & FMODE_READ) {
 		struct wiinst *wiinst = wave_dev->wiinst;
-		struct wave_in *wave_in = wiinst->wave_in;
+		struct wave_in *wave_in;
 
-		if (wave_in)
-		{
-			wiinst->mapped = FALSE;
-			sblive_waveinClose(wave_dev->sb_hw, wave_in);
-		}
+		spin_lock_irqsave(&wiinst->lock, flags);
 
-		kfree((void *) wave_dev->wiinst);
+		wave_in = wiinst->wave_in;
 
-		wave_dev->sb_hw->card_wavein->numrecordinst--;
+		if (wave_in) {
+			wiinst->mapped = 0;
+			emu10k1_wavein_close(wave_dev);
+		}
+		spin_unlock_irqrestore(&wiinst->lock, flags);
+		kfree(wave_dev->wiinst);
 	}
 
-	kfree((void *) wave_dev);
+	kfree(wave_dev);
 
-	down(&sb_hw->open_sem);
-	sb_hw->open_mode &= ~(file->f_mode & FMODE_READ);
-	up(&sb_hw->open_sem);
-	wake_up(&sb_hw->open_wait);
+	wake_up_interruptible(&card->open_wait);
 	MOD_DEC_USE_COUNT;
 
 	return 0;
 }
 
-
 static unsigned int emu10k1_audio_poll(struct file *file, struct poll_table_struct *wait)
 {
-	struct sblive_wavedevice *wave_dev = (struct sblive_wavedevice *) file->private_data;
-	u16 mask = 0;
-
-	DPF(4, "emu10k1_audio_poll() called\n");
+	struct emu10k1_wavedevice *wave_dev = (struct emu10k1_wavedevice *) file->private_data;
+	struct woinst *woinst = wave_dev->woinst;
+	struct wiinst *wiinst = wave_dev->wiinst;
+	unsigned int mask = 0;
+	u32 bytestocopy, pending, dummy;
+	unsigned long flags;
 
-	if (file->f_mode & FMODE_READ)
-	{
-		struct wiinst *wiinst = wave_dev->wiinst;
-		struct wave_in *wave_in = wiinst->wave_in;
+	DPF(4, "emu10k1_audio_poll()\n");
 
-		if (wave_in == NULL)
-			mask |= POLLIN | POLLRDNORM;
-		else
-		{
-			u32 flags, bytestocopy, pending;
-			int status;
+	if (file->f_mode & FMODE_WRITE)
+		poll_wait(file, &woinst->wait_queue, wait);
 
-			poll_wait(file, &wiinst->wait_queue, wait);
+	if (file->f_mode & FMODE_READ)
+		poll_wait(file, &wiinst->wait_queue, wait);
 
-			spin_lock_irqsave(&wiinst->lock, flags);
+	if (file->f_mode & FMODE_WRITE) {
+		struct wave_out *wave_out;
 
-			status = sblive_waveinGetXferSize(wave_dev->sb_hw->card_wavein, wave_in, &bytestocopy, &pending);
+		spin_lock_irqsave(&woinst->lock, flags);
 
-			spin_unlock_irqrestore(&wiinst->lock, flags);
+		wave_out = woinst->wave_out;
 
-			if (status == CTSTATUS_SUCCESS)
-				if (bytestocopy > 0)
-					mask |= POLLIN | POLLRDNORM;
-		}
-	}
+		if (wave_out) {
 
-	if (file->f_mode & FMODE_WRITE)
-	{
-		struct woinst *woinst = wave_dev->woinst;
-		struct wave_out *wave_out = woinst->wave_out;
+			emu10k1_waveout_getxfersize(wave_out, &bytestocopy, &pending, &dummy);
 
-		if (wave_out == NULL)
+			if (bytestocopy >= woinst->fragment_size)
+				mask |= POLLOUT | POLLWRNORM;
+		} else
 			mask |= POLLOUT | POLLWRNORM;
-		else
-		{
-			u32 flags, bytestocopy, pending;
-			int status;
 
-			poll_wait(file, &woinst->wait_queue, wait);
+		spin_unlock_irqrestore(&woinst->lock, flags);
+	}
 
-			spin_lock_irqsave(&woinst->lock, flags);
-                        status = sblive_waveoutGetXferSize(wave_dev->sb_hw->card_waveout, wave_out, &bytestocopy, &pending); 
+	if (file->f_mode & FMODE_READ) {
+		struct wave_in *wave_in;
 
-			if(status != CTSTATUS_SUCCESS)
-			{
-				spin_unlock_irqrestore(&woinst->lock, flags);
-				return -EFAULT;
-			}
+		spin_lock_irqsave(&wiinst->lock, flags);
 
-			if (woinst->silence_filled > 0)
-			{
-				if (woinst->silence_filled == 1)
-				{
-					if (pending <= woinst->fragment_size)
-						woinst->silence_filled = 2;
-					else
-						bytestocopy += woinst->fragment_size;
-                        	}
+		wave_in = wiinst->wave_in;
 
-				if (woinst->silence_filled == 2)
-					bytestocopy = woinst->fragment_size * woinst->numfrags;
+		if (!wave_in) {
+			calculate_ifrag(wiinst);
+			if (emu10k1_wavein_open(wave_dev) != CTSTATUS_SUCCESS) {
+				spin_unlock_irqrestore(&wiinst->lock, flags);
+				return (mask |= POLLERR);
 			}
-
-			spin_unlock_irqrestore(&woinst->lock, flags);
-
-			while(bytestocopy < woinst->fragment_size){
-				interruptible_sleep_on(&woinst->wait_queue);
-
-				if(signal_pending(current))
-					return -ERESTARTSYS;
-
-				spin_lock_irqsave(&woinst->lock, flags);
-				status = sblive_waveoutGetXferSize(wave_dev->sb_hw->card_waveout, wave_out, &bytestocopy, &pending);
 
-				if(status != CTSTATUS_SUCCESS)
-				{
-					spin_unlock_irqrestore(&woinst->lock, flags);
-                                        return -EFAULT;
-				}
+			wave_in = wiinst->wave_in;
+		}
 
-				if (woinst->silence_filled > 0)
-				{
-					if (woinst->silence_filled == 1)
-					{
-						if (pending <= woinst->fragment_size)
-							woinst->silence_filled = 2;
-						else
-							bytestocopy += woinst->fragment_size;
-					}
+		if (wave_in->state != CARDWAVE_STATE_STARTED) {
+			wave_dev->enablebits |= PCM_ENABLE_INPUT;
+			emu10k1_wavein_start(wave_dev);
+		}
 
-					if (woinst->silence_filled == 2)
-						bytestocopy = woinst->fragment_size * woinst->numfrags;
-				}
+		emu10k1_wavein_getxfersize(wave_in, &bytestocopy, &dummy);
 
-				spin_unlock_irqrestore(&woinst->lock, flags);
-			}
+		if (bytestocopy >= wiinst->fragment_size)
+			mask |= POLLIN | POLLRDNORM;
 
-			mask |= POLLOUT | POLLWRNORM;	
-		}
+		spin_unlock_irqrestore(&wiinst->lock, flags);
 	}
 
 	return mask;
 }
 
-
 static void calculate_ofrag(struct woinst *woinst)
 {
-	u32 fragsize = 0, bytespersec;
+	u32 fragsize, bytespersec;
 
 	if (woinst->fragment_size)
-	{
-		DPF(2, "fragment_size already calculated!\n");
 		return;
-	}
 
-	bytespersec = woinst->wave_fmt.channels * (woinst->wave_fmt.bitspersample >> 3) * woinst->wave_fmt.samplingrate;
+	bytespersec = woinst->wave_fmt.channels * (woinst->wave_fmt.bitsperchannel >> 3) * woinst->wave_fmt.samplingrate;
 
-	woinst->fragment_size = 1;
-
-	if (woinst->ossfragshift)
-		woinst->fragment_size <<= (woinst->ossfragshift < MINFRAGSHIFT ? MINFRAGSHIFT : woinst->ossfragshift);
-	else
+	if (!woinst->ossfragshift) {
 		fragsize = (bytespersec * WAVEOUT_DEFAULTFRAGLEN) / 1000 - 1;
 
-	while (fragsize)
-	{
-		fragsize >>= 1;
-		woinst->fragment_size <<= 1;
+		while (fragsize) {
+			fragsize >>= 1;
+			woinst->ossfragshift++;
+		}
 	}
 
-	if (!woinst->numfrags)
-	{
+	if (woinst->ossfragshift < WAVEOUT_MINFRAGSHIFT)
+		woinst->ossfragshift = WAVEOUT_MINFRAGSHIFT;
+
+	woinst->fragment_size = 1 << woinst->ossfragshift;
+
+	if (!woinst->numfrags) {
 		u32 numfrags;
 
-		numfrags = (bytespersec * WAVEOUT_DEFAULTBUFLEN)  / (woinst->fragment_size * 1000) - 1;
+		numfrags = (bytespersec * WAVEOUT_DEFAULTBUFLEN) / (woinst->fragment_size * 1000) - 1;
 
 		woinst->numfrags = 1;
 
-		while (numfrags)
-		{
+		while (numfrags) {
 			numfrags >>= 1;
 			woinst->numfrags <<= 1;
 		}
@@ -1584,19 +1291,16 @@
 	if (woinst->numfrags < MINFRAGS)
 		woinst->numfrags = MINFRAGS;
 
-	if (woinst->numfrags * woinst->fragment_size > WAVEOUT_MAXBUFSIZE)
-	{
+	if (woinst->numfrags * woinst->fragment_size > WAVEOUT_MAXBUFSIZE) {
 		woinst->numfrags = WAVEOUT_MAXBUFSIZE / woinst->fragment_size;
 
-		if (woinst->numfrags < MINFRAGS)
-		{
+		if (woinst->numfrags < MINFRAGS) {
 			woinst->numfrags = MINFRAGS;
 			woinst->fragment_size = WAVEOUT_MAXBUFSIZE / MINFRAGS;
 		}
 
-	} else
-		if (woinst->numfrags * woinst->fragment_size < WAVEOUT_MINBUFSIZE)
-			woinst->numfrags = WAVEOUT_MINBUFSIZE / woinst->fragment_size;
+	} else if (woinst->numfrags * woinst->fragment_size < WAVEOUT_MINBUFSIZE)
+		woinst->numfrags = WAVEOUT_MINBUFSIZE / woinst->fragment_size;
 
 	DPD(2, " calculated playback fragment_size -> %d\n", woinst->fragment_size);
 	DPD(2, " calculated playback numfrags -> %d\n", woinst->numfrags);
@@ -1607,195 +1311,133 @@
 	u32 fragsize, bytespersec;
 
 	if (wiinst->fragment_size)
-	{
-		DPF(2, "fragment_size already calculated!\n");
 		return;
-	}
 
-	bytespersec = wiinst->wave_fmt.channels * (wiinst->wave_fmt.bitspersample >> 3) * wiinst->wave_fmt.samplingrate;
+	bytespersec = wiinst->wave_fmt.channels * (wiinst->wave_fmt.bitsperchannel >> 3) * wiinst->wave_fmt.samplingrate;
 
-	wiinst->fragment_size = 1;
-
-	if (wiinst->ossfragshift)
-		wiinst->fragment_size <<= (wiinst->ossfragshift < MINFRAGSHIFT ? MINFRAGSHIFT : wiinst->ossfragshift);
-	else
-	{
+	if (!wiinst->ossfragshift) {
 		fragsize = (bytespersec * WAVEIN_DEFAULTFRAGLEN) / 1000 - 1;
 
-		while (fragsize)
-		{
+		while (fragsize) {
 			fragsize >>= 1;
-			wiinst->fragment_size <<= 1;
+			wiinst->ossfragshift++;
 		}
 	}
 
+	if (wiinst->ossfragshift < WAVEIN_MINFRAGSHIFT)
+		wiinst->ossfragshift = WAVEIN_MINFRAGSHIFT;
+
+	wiinst->fragment_size = 1 << wiinst->ossfragshift;
+
 	if (!wiinst->numfrags)
-		wiinst->numfrags = (WAVEIN_DEFAULTBUFLEN * bytespersec) / (wiinst->fragment_size * 1000);
+		wiinst->numfrags = (bytespersec * WAVEIN_DEFAULTBUFLEN) / (wiinst->fragment_size * 1000) - 1;
 
 	if (wiinst->numfrags < MINFRAGS)
 		wiinst->numfrags = MINFRAGS;
 
 	if (wiinst->numfrags * wiinst->fragment_size > WAVEIN_MAXBUFSIZE) {
 		wiinst->numfrags = WAVEIN_MAXBUFSIZE / wiinst->fragment_size;
+
 		if (wiinst->numfrags < MINFRAGS) {
 			wiinst->numfrags = MINFRAGS;
 			wiinst->fragment_size = WAVEIN_MAXBUFSIZE / MINFRAGS;
 		}
-	}
+	} else if (wiinst->numfrags * wiinst->fragment_size < WAVEIN_MINBUFSIZE)
+		wiinst->numfrags = WAVEIN_MINBUFSIZE / wiinst->fragment_size;
 
 	DPD(2, " calculated recording fragment_size -> %d\n", wiinst->fragment_size);
 	DPD(2, " calculated recording numfrags -> %d\n", wiinst->numfrags);
 }
 
-void waveInCallbackFn(void *refdata)
+void emu10k1_wavein_bh(unsigned long refdata)
 {
-	struct sblive_wavedevice *wave_dev = (struct sblive_wavedevice *) refdata;
+	struct emu10k1_wavedevice *wave_dev = (struct emu10k1_wavedevice *) refdata;
 	struct wiinst *wiinst = wave_dev->wiinst;
 	struct wave_in *wave_in = wiinst->wave_in;
-	u32 bytestocopy, pending;
+	u32 bytestocopy, curpos;
 	unsigned long flags;
 
-	/* Are these locks necessary around the wake_up ? kabi@i.am */
 	spin_lock_irqsave(&wiinst->lock, flags);
-
-	wiinst->getiptr_blocks++;
 
-	wiinst->total_recorded += wiinst->fragment_size;
-
-	if (wiinst->mapped){
+	if (wave_in->state == CARDWAVE_STATE_STOPPED) {
 		spin_unlock_irqrestore(&wiinst->lock, flags);
 		return;
 	}
 
-	if (sblive_waveinGetXferSize(wave_dev->sb_hw->card_wavein, wave_in, &bytestocopy, &pending) == CTSTATUS_SUCCESS)
-	{
-		if (bytestocopy >= wiinst->fragment_size)
-		{
-			DPF(2, "Wake UP!\n");
-			wake_up(&wiinst->wait_queue);
-		} else
-			DPD(4, "Not enough transfer size, %d\n", bytestocopy);
+	emu10k1_wavein_getxfersize(wave_in, &bytestocopy, &curpos);
+
+	wiinst->total_recorded += curpos - wiinst->curpos;
+
+	if (curpos < wiinst->curpos)
+		wiinst->total_recorded += wiinst->fragment_size * wiinst->numfrags;
+
+	wiinst->curpos = curpos;
+
+	if (wiinst->mapped) {
+		spin_unlock_irqrestore(&wiinst->lock, flags);
+		return;
 	}
 
 	spin_unlock_irqrestore(&wiinst->lock, flags);
 
+	if (bytestocopy >= wiinst->fragment_size)
+		wake_up_interruptible(&wiinst->wait_queue);
+	else
+		DPD(4, "Not enough transfer size, %d\n", bytestocopy);
+
 	return;
 }
 
-void waveOutCallbackFn(void *refdata)
+void emu10k1_waveout_bh(unsigned long refdata)
 {
-	struct sblive_wavedevice *wave_dev = (struct sblive_wavedevice *) refdata;
+	struct emu10k1_wavedevice *wave_dev = (struct emu10k1_wavedevice *) refdata;
 	struct woinst *woinst = wave_dev->woinst;
 	struct wave_out *wave_out = woinst->wave_out;
-	u32 bytestocopy, pending, waveptr;
+	u32 bytestocopy, pending, curpos;
 	unsigned long flags;
 
-	if(wave_out->state == CARDWAVE_STATE_STOPPED)
-		return;
-
 	spin_lock_irqsave(&woinst->lock, flags);
 
-	if (sblive_waveoutGetControl(wave_dev->sb_hw->card_waveout, wave_out, WAVECURPOS, (u32 *)&waveptr) == CTSTATUS_SUCCESS)
-	{
-		woinst->total_played += waveptr - woinst->wave_ptr;
-
-		if (waveptr < woinst->wave_ptr)
-			woinst->total_played += woinst->fragment_size * woinst->numfrags;
-
-		woinst->wave_ptr = waveptr;
-	}
-
-	if (woinst->mapped)
-	{
+	if (wave_out->state == CARDWAVE_STATE_STOPPED) {
 		spin_unlock_irqrestore(&woinst->lock, flags);
 		return;
 	}
-
-	if (sblive_waveoutGetXferSize(wave_dev->sb_hw->card_waveout, wave_out, &bytestocopy, &pending) == CTSTATUS_SUCCESS)
-	{
-		if (bytestocopy >= woinst->fragment_size || woinst->silence_filled > 0)
-		{
-			if (pending <= woinst->fragment_size && bytestocopy >= woinst->fragment_size)
-			{
-				if (woinst->silence_filled == 0)
-					sblive_waveoutGetControl(wave_dev->sb_hw->card_waveout, wave_out, WAVEWRITEPOINTER, &woinst->silence_start);
-
-				bytestocopy = woinst->fragment_size;
-
-				sblive_waveoutFillSilence(wave_dev->sb_hw->card_waveout, wave_out, &bytestocopy);
-
-				if (woinst->silence_filled < 2)
-					woinst->silence_filled++;
-			}
-
-			wake_up(&woinst->wait_queue);
-		} else
-			DPD(4, "Not enough transfer size -> %x\n", bytestocopy);
-	}
 
-	spin_unlock_irqrestore(&woinst->lock, flags);
+	emu10k1_waveout_getxfersize(wave_out, &bytestocopy, &pending, &curpos);
 
-	return;
-}
+	woinst->total_played += curpos - woinst->curpos;
 
-int audio_init(struct sblive_hw * sb_hw, u8 * pname)
-{
-	/* Initialize CardwaveOut struct */
-	sb_hw->card_waveout = kmalloc(sizeof(struct sblive_waveout), GFP_KERNEL);
-	if (sb_hw->card_waveout == NULL)
-	{
-		printk(KERN_WARNING "sblive: Unable to allocate struct sblive_waveout: out of memory\n");
-		return CTSTATUS_ERROR;
-	}
+	if (curpos < woinst->curpos)
+		woinst->total_played += woinst->fragment_size * woinst->numfrags;
 
-	DPD(3, "kmalloc: [%p]\n", sb_hw->card_waveout);
+	woinst->curpos = curpos;
 
-	/* Initialize CardwaveIn struct */
-	sb_hw->card_wavein = kmalloc(sizeof(struct sblive_wavein), GFP_KERNEL);
-	if (sb_hw->card_wavein == NULL)
-	{
-		kfree(sb_hw->card_waveout);
-		sb_hw->card_waveout = NULL;
-		printk(KERN_WARNING "sblive: Unable to allocate struct sblive_wavein: out of memory\n");
-		return CTSTATUS_ERROR;
+	if (woinst->mapped) {
+		spin_unlock_irqrestore(&woinst->lock, flags);
+		return;
 	}
-
-	DPD(3, "kmalloc: [%p]\n", sb_hw->card_wavein);
-
-	sblive_waveoutInit(sb_hw->card_waveout, pname);
-	sblive_waveinInit(sb_hw->card_wavein, pname);
-
-	return CTSTATUS_SUCCESS;
-}
 
-int audio_exit(struct sblive_hw *sb_hw)
-{
-	sblive_waveoutExit(sb_hw->card_waveout);
-	sblive_waveinExit(sb_hw->card_wavein);
+	if (wave_out->fill_silence) {
+		spin_unlock_irqrestore(&woinst->lock, flags);
+		emu10k1_waveout_fillsilence(woinst);
+	} else
+		spin_unlock_irqrestore(&woinst->lock, flags);
 
-	kfree(sb_hw->card_waveout);
-	DPD(3, "kfree: [%p]\n", sb_hw->card_waveout);
-	sb_hw->card_waveout = NULL;
-
-	kfree(sb_hw->card_wavein);
-	DPD(3, "kfree: [%p]\n", sb_hw->card_wavein);
-	sb_hw->card_wavein = NULL;
+	if (bytestocopy >= woinst->fragment_size)
+		wake_up_interruptible(&woinst->wait_queue);
+	else
+		DPD(4, "Not enough transfer size -> %x\n", bytestocopy);
 
-	return CTSTATUS_SUCCESS;
+	return;
 }
 
-
-struct file_operations emu10k1_audio_fops =
-{
-	&emu10k1_audio_llseek,
-	&emu10k1_audio_read,
-	&emu10k1_audio_write,
-	NULL,
-	&emu10k1_audio_poll,
-	&emu10k1_audio_ioctl,
-	&emu10k1_audio_mmap,
-	&emu10k1_audio_open,
-	NULL,
-	&emu10k1_audio_release,
-	NULL,
+struct file_operations emu10k1_audio_fops = {
+	llseek:emu10k1_audio_llseek,
+	read:emu10k1_audio_read,
+	write:emu10k1_audio_write,
+	poll:emu10k1_audio_poll,
+	ioctl:emu10k1_audio_ioctl,
+	mmap:emu10k1_audio_mmap,
+	open:emu10k1_audio_open,
+	release:emu10k1_audio_release,
 };
Index: oldkernel/linux/drivers/sound/emu10k1/audio.h
diff -u linux/drivers/sound/emu10k1/audio.h:1.1 linux/drivers/sound/emu10k1/audio.h:1.2
--- linux/drivers/sound/emu10k1/audio.h:1.1	Thu Jun  1 16:52:15 2000
+++ linux/drivers/sound/emu10k1/audio.h	Fri Jul  7 15:36:45 2000
@@ -30,31 +30,17 @@
  **********************************************************************
  */
 
-/*
- *	FIXME:
- *		There are some 32bit assumptions here
- *		Cast of pointers to 32bit values is unsafe
- *			- Wave callbacks and elsewhere
- */
-
 #ifndef _AUDIO_H
 #define _AUDIO_H
 
-#ifdef MODULE
 #define __NO_VERSION__
 #include <linux/module.h>
-#else
-#define MOD_INC_USE_COUNT
-#define MOD_DEC_USE_COUNT
-#endif
-
-#define MINFRAGS	2
-#define MINFRAGSHIFT	4
+#include <linux/poll.h>
+#include <asm/uaccess.h>
 
-void waveOutCallbackFn(void *);
-void waveInCallbackFn(void *);
+#define MINFRAGS	2	/* _don't_ got bellow 2 */
 
-int audio_init(struct sblive_hw *sb_hw, u8 *pname);
-int audio_exit(struct sblive_hw *sb_hw);
+void emu10k1_waveout_bh(unsigned long);
+void emu10k1_wavein_bh(unsigned long);
 
 #endif /* _AUDIO_H */
Index: oldkernel/linux/drivers/sound/emu10k1/cardmi.c
diff -u linux/drivers/sound/emu10k1/cardmi.c:1.1 linux/drivers/sound/emu10k1/cardmi.c:1.2
--- linux/drivers/sound/emu10k1/cardmi.c:1.1	Thu Jun  1 16:52:15 2000
+++ linux/drivers/sound/emu10k1/cardmi.c	Fri Jul  7 15:36:45 2000
@@ -1,3 +1,4 @@
+
 /*
  **********************************************************************
  *     sblive_mi.c - MIDI UART input HAL for emu10k1 driver
@@ -32,122 +33,47 @@
 
 #include "hwaccess.h"
 #include "cardmi.h"
-
-static struct
-{
-	int (*Fn) (struct sblive_mpuin * card_mpuin, u8 data);
-} midistatefn[] =
-{
-	{ sblive_miStateParse },
-	{ sblive_miState3Byte }, 	/* 0x8n, 0x9n, 0xAn, 0xBn, 0xEn */
-	{ sblive_miState3ByteKey },    	/* Byte 1                       */
-	{ sblive_miState3ByteVel },    	/* Byte 2                       */
-	{ sblive_miState2Byte },       	/* 0xCn, 0xDn                   */
-	{ sblive_miState2ByteKey },    	/* Byte 1                       */
-	{ sblive_miStateSysCommon2 },	/* 0xF1 , 0xF3                  */
-	{ sblive_miStateSysCommon2Key },/* 0xF1 , 0xF3, Byte 1          */
-	{ sblive_miStateSysCommon3 },  	/* 0xF2                         */
-	{ sblive_miStateSysCommon3Key },/* 0xF2 , Byte 1                */
-	{ sblive_miStateSysCommon3Vel },/* 0xF2 , Byte 2                */
-	{ sblive_miStateSysExNorm },	/* 0xF0, 0xF7, Normal mode      */
-	{ sblive_miStateSysReal }	/* 0xF4 - 0xF6 ,0xF8 - 0xFF     */
-};
-
-/****************************************************************************/
-/* int    sblive_mpuinInit(struct sblive_mpuin *card_mpuin, PICARD pICard ) */
-/*                                                                          */
-/* Function:   Initialize the parameters and reset the MPU port             */
-/****************************************************************************/
-int sblive_mpuinInit(struct sblive_mpuin *card_mpuin, struct sblive_hw *sb_hw)
-{
-	char name[128];
-
-	DPF(2, "sblive_mpuinInit\n");
-
-	memset(card_mpuin, 0, sizeof(struct sblive_mpuin));
 
-	card_mpuin->status = FLAGS_AVAILABLE;	// clear
+static struct {
+	int (*Fn) (struct emu10k1_mpuin *, u8);
+} midistatefn[] = {
 
-	card_mpuin->caps.cbsize = sizeof(struct midi_caps);
-	card_mpuin->caps.support = MIDICAPS_INPUT;
-	card_mpuin->caps.technology = 0;
-	card_mpuin->caps.product = MM_CREATIVE_MIDIIN;
-	card_mpuin->caps.manufacturer = MM_CREATIVE;
-	card_mpuin->caps.voices = 0;
-	card_mpuin->caps.notes = 0;
-	card_mpuin->caps.channelmask = 0;
-	card_mpuin->caps.caps = CARDMIDI_IN;
-
-	card_mpuin->task.next = NULL;
-	card_mpuin->task.sync = 0;
-	card_mpuin->task.routine = sblive_mpuinDpcCallback;
-	card_mpuin->task.data = card_mpuin;
-
-	spin_lock_init(&card_mpuin->lock);
-
-	strcpy(name, IDS_EMU_MIDIIN_PNAME);
-
-	/* Fill in card caps */
-	sprintf(card_mpuin->caps.MIDIname, "%s [%lx]", name, sb_hw->hwaddr );
-
-	/* Reset the MPU port */
-	if (hwmpuReset(sb_hw) != CTSTATUS_SUCCESS)
 	{
-		DPF(2, "cardmi.c: MPU hardware reset failure\n");
-		return CTSTATUS_NOTENABLED;
-	}
-
-	return CTSTATUS_SUCCESS;
-}
-
-
-/****************************************************************************/
-/* int    sblive_mpuinExit(struct sblive_mpuin *card_mpuin)                 */
-/*                                                                          */
-/* Function:   Disable the IRQ TX and uninstall the IRQ handler             */
-/****************************************************************************/
-int sblive_mpuinExit(struct sblive_hw *sb_hw)
-{
-	DPF(2, "sblive_mpuinExit\n");
-
-	/* Disable RX interrupt */
-	sblive_irqmgrDisableIrq(sb_hw, INTE_MIDIRXENABLE);
-
-	return CTSTATUS_SUCCESS;
-}
+	sblive_miStateParse}, {
+	sblive_miState3Byte},	/* 0x8n, 0x9n, 0xAn, 0xBn, 0xEn */
+	{
+	sblive_miState3ByteKey},	/* Byte 1                       */
+	{
+	sblive_miState3ByteVel},	/* Byte 2                       */
+	{
+	sblive_miState2Byte},	/* 0xCn, 0xDn                   */
+	{
+	sblive_miState2ByteKey},	/* Byte 1                       */
+	{
+	sblive_miStateSysCommon2},	/* 0xF1 , 0xF3                  */
+	{
+	sblive_miStateSysCommon2Key},	/* 0xF1 , 0xF3, Byte 1          */
+	{
+	sblive_miStateSysCommon3},	/* 0xF2                         */
+	{
+	sblive_miStateSysCommon3Key},	/* 0xF2 , Byte 1                */
+	{
+	sblive_miStateSysCommon3Vel},	/* 0xF2 , Byte 2                */
+	{
+	sblive_miStateSysExNorm},	/* 0xF0, 0xF7, Normal mode      */
+	{
+	sblive_miStateSysReal}	/* 0xF4 - 0xF6 ,0xF8 - 0xFF     */
+};
 
-/****************************************************************************/
-/* int    sblive_mpuinGetCaps(struct sblive_mpuin *card_mpuin,              */
-/*                              struct midi_caps *midi_caps)                */
-/*                                                                          */
-/* Function:   Returns the MPU IN capabilities                              */
-/****************************************************************************/
-int sblive_mpuinGetCaps(struct sblive_mpuin *card_mpuin, struct midi_caps *midi_caps)
-{
-	u32 cbsize;
-
-	DPF(2, "sblive_mpuinGetCaps\n");
-
-	cbsize = min(midi_caps->cbsize, card_mpuin->caps.cbsize);
-	memcpy(midi_caps, &card_mpuin->caps, cbsize);
-	midi_caps->cbsize = cbsize;
+/* Installs the IRQ handler for the MPU in port                 */
 
-	return CTSTATUS_SUCCESS;
-}
+/* and initialize parameters                                    */
 
-/****************************************************************************/
-/* int    sblive_mpuinOpen(struct sblive_mpuin *card_mpuin,                 */
-/*                           struct midi_openinfo *openinfo,                */
-/*                           u32 * handle)                                  */
-/*                                                                          */
-/* Function:   Installs the IRQ handler for the MPU in port                 */
-/*             and initialize parameters                                    */
-/****************************************************************************/
-int sblive_mpuinOpen(struct sblive_hw *sb_hw, struct midi_openinfo *openinfo)
+int emu10k1_mpuin_open(struct emu10k1_card *card, struct midi_openinfo *openinfo)
 {
-	struct sblive_mpuin *card_mpuin = sb_hw->card_mpuin;
+	struct emu10k1_mpuin *card_mpuin = card->mpuin;
 
-	DPF(2, "sblive_mpuinOpen\n");
+	DPF(2, "emu10k1_mpuin_open\n");
 
 	if (!(card_mpuin->status & FLAGS_AVAILABLE))
 		return CTSTATUS_INUSE;
@@ -156,7 +82,7 @@
 	card_mpuin->openinfo = *openinfo;
 	card_mpuin->status &= ~FLAGS_AVAILABLE;	/* clear */
 	card_mpuin->status |= FLAGS_READY;	/* set */
-	card_mpuin->status &= ~FLAGS_MIDM_STARTED; /* clear */
+	card_mpuin->status &= ~FLAGS_MIDM_STARTED;	/* clear */
 	card_mpuin->firstmidiq = NULL;
 	card_mpuin->lastmidiq = NULL;
 	card_mpuin->qhead = 0;
@@ -164,86 +90,66 @@
 
 	sblive_miStateInit(card_mpuin);
 
-	hwmpuReset(sb_hw);
-	hwmpuAcquire(sb_hw);
+	emu10k1_mpu_reset(card);
+	emu10k1_mpu_acquire(card);
 
 	return CTSTATUS_SUCCESS;
 }
 
-/****************************************************************************/
-/* int    sblive_mpuinClose(struct sblive_mpuin *card_mpuin,                */
-/*                            u32 handle)                                   */
-/*                                                                          */
-/* Function:   If Midi Buffers are present,                                 */
-/*             return CTSTATUS_STILLPLAYING                                 */
-/*             Otherwise disable and uninstall IRQ handler                  */
-/****************************************************************************/
-int sblive_mpuinClose(struct sblive_hw *sb_hw)
+int emu10k1_mpuin_close(struct emu10k1_card *card)
 {
-	struct sblive_mpuin *card_mpuin = sb_hw->card_mpuin;
+	struct emu10k1_mpuin *card_mpuin = card->mpuin;
 
-	DPF(2, "sblive_mpuinClose\n");
+	DPF(2, "emu10k1_mpuin_close()\n");
 
 	/* Check if there are pending input SysEx buffers */
-	if (card_mpuin->firstmidiq != NULL)
-	{
-		DPF(2, "Cannot close, MIDI buffers are present.\n");
-		return CTSTATUS_STILLPLAYING;
+	if (card_mpuin->firstmidiq != NULL) {
+		ERROR();
+		return CTSTATUS_ERROR;
 	}
 
 	/* Disable RX interrupt */
-	sblive_irqmgrDisableIrq(sb_hw, INTE_MIDIRXENABLE);
+	emu10k1_irq_disable(card, INTE_MIDIRXENABLE);
 
-	hwmpuRelease(sb_hw);
+	emu10k1_mpu_release(card);
 
-	card_mpuin->status |= FLAGS_AVAILABLE;	   /* set */
-	card_mpuin->status &= ~FLAGS_MIDM_STARTED; /* clear */
+	card_mpuin->status |= FLAGS_AVAILABLE;	/* set */
+	card_mpuin->status &= ~FLAGS_MIDM_STARTED;	/* clear */
 
 	return CTSTATUS_SUCCESS;
 }
+
+/* Adds MIDI buffer to local queue list                         */
 
-/****************************************************************************/
-/* int    sblive_mpuinAddBuffer(struct sblive_mpuin *card_mpuin,            */
-/*                                u32 handle,                               */
-/*                                struct midi_hdr *INFO midihdrInfo)        */
-/*                                                                          */
-/* Function:   Adds MIDI buffer to local queue list                         */
-/****************************************************************************/
-int sblive_mpuinAddBuffer(struct sblive_mpuin *card_mpuin, struct midi_hdr *midihdr)
+int emu10k1_mpuin_add_buffer(struct emu10k1_mpuin *card_mpuin, struct midi_hdr *midihdr)
 {
 	struct midi_queue *midiq;
 	unsigned long flags;
 
-	DPF(2, "sblive_mpuinAddBuffer\n");
+	DPF(2, "emu10k1_mpuin_add_buffer()\n");
 
 	/* Update MIDI buffer flags */
-	midihdr->flags |= MIDIBUF_INQUEUE; /* set */
-	midihdr->flags &= ~MIDIBUF_DONE;   /* clear */
+	midihdr->flags |= MIDIBUF_INQUEUE;	/* set */
+	midihdr->flags &= ~MIDIBUF_DONE;	/* clear */
 
-	midiq = (struct midi_queue *) kmalloc(sizeof(struct midi_queue), GFP_ATOMIC);
-	if (midiq == NULL)
-	{
+	if ((midiq = (struct midi_queue *) kmalloc(sizeof(struct midi_queue), GFP_ATOMIC)) == NULL) {
 		/* Message lost */
-		return CTSTATUS_NOMEMORY;
+		return CTSTATUS_ERROR;
 	}
 
-	DPD(3, "kmalloc: [%p]\n", midiq);
-
 	midiq->next = NULL;
 	midiq->qtype = 1;
 	midiq->length = midihdr->bufferlength;
 	midiq->sizeLeft = midihdr->bufferlength;
-	midiq->midibyte = midihdr->lpData;
+	midiq->midibyte = midihdr->data;
 	midiq->refdata = (unsigned long) midihdr;
 
 	spin_lock_irqsave(&card_mpuin->lock, flags);
 
-	if (card_mpuin->firstmidiq == NULL)
-	{
+	if (card_mpuin->firstmidiq == NULL) {
 		card_mpuin->firstmidiq = midiq;
 		card_mpuin->lastmidiq = midiq;
-	} else
-	{
+	} else {
 		(card_mpuin->lastmidiq)->next = midiq;
 		card_mpuin->lastmidiq = midiq;
 	}
@@ -253,75 +159,62 @@
 	return CTSTATUS_SUCCESS;
 }
 
+/* First set the Time Stamp if MIDI IN has not started.         */
+
+/* Then enable RX Irq.                                          */
 
-/****************************************************************************/
-/* int    sblive_mpuinStart(struct sblive_mpuin *card_mpuin,                */
-/*                            u32 handle,                                   */
-/*                                                                          */
-/* Function:   First set the Time Stamp if MIDI IN has not started.         */
-/*             Then enable RX Irq.                                          */
-/****************************************************************************/
-int sblive_mpuinStart(struct sblive_hw *sb_hw)
+int emu10k1_mpuin_start(struct emu10k1_card *card)
 {
-	struct sblive_mpuin *card_mpuin = sb_hw->card_mpuin;
+	struct emu10k1_mpuin *card_mpuin = card->mpuin;
 	u8 dummy;
 
-	DPF(2, "sblive_mpuinStart\n");
+	DPF(2, "emu10k1_mpuin_start()\n");
 
 	/* Set timestamp if not set */
-	if (card_mpuin->status & FLAGS_MIDM_STARTED)
-	{
+	if (card_mpuin->status & FLAGS_MIDM_STARTED) {
 		DPF(2, "Time Stamp not changed\n");
-	} else
-	{
-		while (hwmpuReadData(sb_hw, &dummy) == CTSTATUS_SUCCESS);
+	} else {
+		while (emu10k1_mpu_read_data(card, &dummy) == CTSTATUS_SUCCESS);
 
-		card_mpuin->status |= FLAGS_MIDM_STARTED; /* set */
+		card_mpuin->status |= FLAGS_MIDM_STARTED;	/* set */
 
 		/* Set new time stamp */
-		card_mpuin->timestart = (jiffies * 1000)/HZ;
+		card_mpuin->timestart = (jiffies * 1000) / HZ;
 		DPD(2, "New Time Stamp = %d\n", card_mpuin->timestart);
 
 		card_mpuin->qhead = 0;
 		card_mpuin->qtail = 0;
 
-		sblive_irqmgrEnableIrq(sb_hw, INTE_MIDIRXENABLE);
+		emu10k1_irq_enable(card, INTE_MIDIRXENABLE);
 	}
 
 	return CTSTATUS_SUCCESS;
 }
 
+/* Disable the RX Irq.  If a partial recorded buffer            */
 
-/****************************************************************************/
-/* int    sblive_mpuinStop(struct sblive_mpuin *card_mpuin,                 */
-/*                           u32 handle,                                    */
-/*                                                                          */
-/* Function:   Disable the RX Irq.  If a partial recorded buffer            */
-/*             exist, send it up to IMIDI level.                            */
-/****************************************************************************/
-int sblive_mpuinStop(struct sblive_hw *sb_hw)
+/* exist, send it up to IMIDI level.                            */
+
+int emu10k1_mpuin_stop(struct emu10k1_card *card)
 {
-	struct sblive_mpuin *card_mpuin = sb_hw->card_mpuin;
+	struct emu10k1_mpuin *card_mpuin = card->mpuin;
 	struct midi_queue *midiq;
 	unsigned long flags;
 
-	DPF(2, "sblive_mpuinStop\n");
+	DPF(2, "emu10k1_mpuin_stop()\n");
 
-	sblive_irqmgrDisableIrq(sb_hw, INTE_MIDIRXENABLE);
+	emu10k1_irq_disable(card, INTE_MIDIRXENABLE);
 
-	card_mpuin->status &= ~FLAGS_MIDM_STARTED; /* clear */
+	card_mpuin->status &= ~FLAGS_MIDM_STARTED;	/* clear */
 
-	if (card_mpuin->firstmidiq)
-	{
+	if (card_mpuin->firstmidiq) {
 		spin_lock_irqsave(&card_mpuin->lock, flags);
 
 		midiq = card_mpuin->firstmidiq;
-		if (midiq != NULL)
-		{
+		if (midiq != NULL) {
 			if (midiq->sizeLeft == midiq->length)
 				midiq = NULL;
-			else
-			{
+			else {
 				card_mpuin->firstmidiq = midiq->next;
 				if (card_mpuin->firstmidiq == NULL)
 					card_mpuin->lastmidiq = NULL;
@@ -330,100 +223,37 @@
 
 		spin_unlock_irqrestore(&card_mpuin->lock, flags);
 
-		if (midiq)
-		{
-			sblive_mpuinMidiCallback (card_mpuin, ICARDMIDI_INLONGERROR, (u32)midiq, 0);
+		if (midiq) {
+			emu10k1_mpuin_callback(card_mpuin, ICARDMIDI_INLONGERROR, (unsigned long) midiq, 0);
 			kfree(midiq);
-			DPD(3, "kfree: [%p]\n", midiq);
 		}
 	}
 
 	return CTSTATUS_SUCCESS;
 }
-
-
-/****************************************************************************/
-/* int    sblive_mpuinWriteShortData(struct sblive_mpuin *card_mpuin,       */
-/*                                     u32 handle,                          */
-/*                                     u32 midimsg)                         */
-/*                                                                          */
-/* Function:   Not Used                                                     */
-/****************************************************************************/
-int sblive_mpuinWriteShortData(struct sblive_mpuin *card_mpuin, u32 midimsg)
-{
-	DPF(2, "sblive_mpuinWriteShortData(): not supported\n");
-	return CTSTATUS_NOTSUPPORTED;
-}
-
-
-/****************************************************************************/
-/* int    sblive_mpuinPause(struct sblive_mpuin *card_mpuin,                */
-/*                            u32 handle,                                   */
-/*                                                                          */
-/* Function:   Not Used                                                     */
-/****************************************************************************/
-int sblive_mpuinPause(struct sblive_mpuin *card_mpuin)
-{
-	DPF(2, "sblive_mpuinPause(): not supported\n");
-	return CTSTATUS_NOTSUPPORTED;
-}
-
-
-/****************************************************************************/
-/* int    sblive_mpuinStream(struct sblive_mpuin * card_mpuin,              */
-/*                             u32 handle,                                  */
-/*                             struct midi_hdr *INFO midihdrInfo)           */
-/*                                                                          */
-/* Function:   Not Used                                                     */
-/****************************************************************************/
-int sblive_mpuinStream(struct sblive_mpuin *card_mpuin, struct midi_hdr *midihdr)
-{
-	DPF(2, "sblive_mpuinStream(): not supported\n");
-	return CTSTATUS_NOTSUPPORTED;
-}
 
+/* Disable the RX Irq.  If any buffer                           */
 
-/****************************************************************************/
-/* int    sblive_mpuinRestart(struct sblive_mpuin *card_mpuin,              */
-/*                              u32 handle,                                 */
-/*                                                                          */
-/* Function:   Not Used                                                     */
-/****************************************************************************/
-int sblive_mpuinRestart(struct sblive_mpuin *card_mpuin)
+/* exist, send it up to IMIDI level.                            */
+int emu10k1_mpuin_reset(struct emu10k1_card *card)
 {
-	DPF(2, "sblive_mpuinRestart(): not supported\n");
-	return CTSTATUS_NOTSUPPORTED;
-}
-
-
-/****************************************************************************/
-/* int    sblive_mpuinReset(struct sblive_mpuin *card_mpuin,                */
-/*                            u32 handle,                                   */
-/*                                                                          */
-/* Function:   Disable the RX Irq.  If any buffer                           */
-/*             exist, send it up to IMIDI level.                            */
-/****************************************************************************/
-int sblive_mpuinReset(struct sblive_hw *sb_hw)
-{
-	struct sblive_mpuin *card_mpuin = sb_hw->card_mpuin;
+	struct emu10k1_mpuin *card_mpuin = card->mpuin;
 	struct midi_queue *midiq;
 
-	DPF(2, "sblive_mpuinReset: start\n");
+	DPF(2, "emu10k1_mpuin_reset()\n");
 
-	sblive_irqmgrDisableIrq(sb_hw, INTE_MIDIRXENABLE);
+	emu10k1_irq_disable(card, INTE_MIDIRXENABLE);
 
-	while (card_mpuin->firstmidiq)
-	{
+	while (card_mpuin->firstmidiq) {
 		midiq = card_mpuin->firstmidiq;
 		card_mpuin->firstmidiq = midiq->next;
 
 		if (midiq->sizeLeft == midiq->length)
-			sblive_mpuinMidiCallback(card_mpuin, ICARDMIDI_INLONGDATA, (u32) midiq, 0);
+			emu10k1_mpuin_callback(card_mpuin, ICARDMIDI_INLONGDATA, (unsigned long) midiq, 0);
 		else
-			sblive_mpuinMidiCallback(card_mpuin, ICARDMIDI_INLONGERROR, (u32) midiq, 0);
+			emu10k1_mpuin_callback(card_mpuin, ICARDMIDI_INLONGERROR, (unsigned long) midiq, 0);
 
 		kfree(midiq);
-		DPD(3, "kfree: [%p]\n", midiq);
 	}
 
 	card_mpuin->lastmidiq = NULL;
@@ -431,92 +261,13 @@
 
 	return CTSTATUS_SUCCESS;
 }
-
-
-/****************************************************************************/
-/* int    sblive_mpuinCache(struct sblive_mpuin *card_mpuin,                */
-/*                            u32 handle,                                   */
-/*                            struct midi_cache * midicache)                */
-/*                                                                          */
-/* Function:   Not Used                                                     */
-/****************************************************************************/
-int sblive_mpuinCache(struct sblive_mpuin *card_mpuin, struct midi_cache *midicache)
-{
-	DPF(2, "sblive_mpuinCache(): not supported\n");
-	return CTSTATUS_NOTSUPPORTED;
-}
-
-
-/****************************************************************************/
-/* int    sblive_mpuinGetPosition(struct sblive_mpuin *card_mpuin,          */
-/*                                  u32 handle,                             */
-/*                                  u32 *position)                          */
-/*                                                                          */
-/* Function:   Not Used                                                     */
-/****************************************************************************/
-int sblive_mpuinGetPosition(struct sblive_mpuin *card_mpuin, u32 *position)
-{
-	DPF(2, "sblive_mpuinGetPosition(): not supported\n");
-	return CTSTATUS_NOTSUPPORTED;
-}
-
-
-/****************************************************************************/
-/* int    sblive_mpuinGetControl(struct sblive_mpuin *card_mpuin,           */
-/*                                 u32 handle,                              */
-/*                                 u32 controlid,                           */
-/*                                 u32 *value)                              */
-/*                                                                          */
-/* Function:   Not Used                                                     */
-/****************************************************************************/
-int sblive_mpuinGetControl(struct sblive_mpuin *card_mpuin, u32 controlid, u32 *value)
-{
-	DPF(2, "sblive_mpuinGetControl\n");
-
-	switch (controlid)
-	{
-	case MIDIQUERYACTIVEINST:
-		DPF(2, "controlid = MIDIQUERYACTIVE\n");
-		if (card_mpuin == NULL)
-			return CTSTATUS_ERROR;
-		if (!(card_mpuin->status & FLAGS_AVAILABLE))
-			return CTSTATUS_SUCCESS;
-		else
-			return CTSTATUS_ERROR;
-	default:
-		break;
-	}
-
-	return CTSTATUS_NOTSUPPORTED;
-}
 
+/* Passes the message with the data back to the client          */
 
-/****************************************************************************/
-/* int    sblive_mpuinSetControl(struct sblive_mpuin *card_mpuin,           */
-/*                                 u32 handle,                              */
-/*                                 u32 controlid,                           */
-/*                                 u32 *value)                              */
-/*                                                                          */
-/* Function:   Not Used                                                     */
-/****************************************************************************/
-int sblive_mpuinSetControl(struct sblive_mpuin *card_mpuin, u32 controlid, u32 *value)
+/* via IRQ & DPC callbacks to Ring 3                            */
+int emu10k1_mpuin_callback(struct emu10k1_mpuin *card_mpuin, u32 msg, unsigned long data, u32 bytesvalid)
 {
-	DPF(2, "sblive_mpuinSetControl(): not supported\n");
-	return CTSTATUS_NOTSUPPORTED;
-}
-
-
-/****************************************************************************/
-/* int    sblive_mpuinMidiCallback(struct sblive_mpuin *card_mpuin,         */
-/*                                   u32 msg,                               */
-/*                                   u32 data)                              */
-/*                                                                          */
-/* Function:   Passes the message with the data back to the client          */
-/*             via IRQ & DPC callbacks to Ring 3                            */
-/****************************************************************************/
-int sblive_mpuinMidiCallback(struct sblive_mpuin *card_mpuin, u32 msg, u32 data, u32 bytesvalid)
-{
-	u32 timein;
+	unsigned long timein;
 	struct midi_queue *midiq;
 	unsigned long callback_msg[3];
 	struct midi_hdr *midihdr;
@@ -530,15 +281,13 @@
 	if (card_mpuin->timestart <= timein)
 		callback_msg[0] = timein - card_mpuin->timestart;
 	else
-		callback_msg[0] = (~0x0L- card_mpuin->timestart) + timein;
+		callback_msg[0] = (~0x0L - card_mpuin->timestart) + timein;
 
-	if (msg == ICARDMIDI_INDATA || msg == ICARDMIDI_INDATAERROR)
-	{
+	if (msg == ICARDMIDI_INDATA || msg == ICARDMIDI_INDATAERROR) {
 		callback_msg[1] = data;
 		callback_msg[2] = bytesvalid;
-		DPD(2, "sblive_mpuinMidiCallback: midimsg = %x\n", data);
-	} else
-	{
+		DPD(2, "emu10k1_mpuin_callback: midimsg = %lx\n", data);
+	} else {
 		midiq = (struct midi_queue *) data;
 		midihdr = (struct midi_hdr *) midiq->refdata;
 
@@ -551,24 +300,19 @@
 	}
 
 	/* Notify client that Sysex buffer has been sent */
-	midiCallbackFn(msg, card_mpuin->openinfo.refdata, callback_msg);
+	emu10k1_midi_callback(msg, card_mpuin->openinfo.refdata, callback_msg);
 
 	return CTSTATUS_SUCCESS;
 }
 
-
-/****************************************************************************/
-/* int sblive_mpuinDpcCallback ()                                           */
-/****************************************************************************/
-void sblive_mpuinDpcCallback(void *refdata)
+void emu10k1_mpuin_bh(unsigned long refdata)
 {
 	u8 data;
 	unsigned idx;
-	struct sblive_mpuin *card_mpuin = (struct sblive_mpuin *) refdata;
+	struct emu10k1_mpuin *card_mpuin = (struct emu10k1_mpuin *) refdata;
 	unsigned long flags;
 
-	while (card_mpuin->qhead != card_mpuin->qtail)
-	{
+	while (card_mpuin->qhead != card_mpuin->qtail) {
 		spin_lock_irqsave(&card_mpuin->lock, flags);
 		idx = card_mpuin->qhead;
 		data = card_mpuin->midiq[idx].data;
@@ -583,22 +327,15 @@
 	return;
 }
 
+/* IRQ callback handler routine for the MPU in port */
 
-/****************************************************************************/
-/* int    sblive_mpuinIrqCallback(u32 event,                                */
-/*                                  u32 refdata,                            */
-/*                                  u32 param)                              */
-/*                                                                          */
-/* Function:   IRQ callback handler routine for the MPU in port             */
-/****************************************************************************/
-int sblive_mpuinIrqCallback(struct sblive_hw *sb_hw)
+int emu10k1_mpuin_irqhandler(struct emu10k1_card *card)
 {
 	unsigned idx;
 	unsigned count;
 	u8 MPUIvalue;
-	struct sblive_mpuin *card_mpuin = sb_hw->card_mpuin;
+	struct emu10k1_mpuin *card_mpuin = card->mpuin;
 
-
 	/* IRQ service routine. The data and code touched are:
 	 * 1. card_mpuin
 	 */
@@ -606,41 +343,37 @@
 	count = 0;
 	idx = card_mpuin->qtail;
 
-	while (1)
-	{
-		if (hwmpuReadData(sb_hw, &MPUIvalue) == CTSTATUS_SUCCESS)
-		{
+	while (1) {
+		if (emu10k1_mpu_read_data(card, &MPUIvalue) == CTSTATUS_SUCCESS) {
 			++count;
 			card_mpuin->midiq[idx].data = MPUIvalue;
-			card_mpuin->midiq[idx].timein = (jiffies * 1000)/HZ;
+			card_mpuin->midiq[idx].timein = (jiffies * 1000) / HZ;
 			idx = (idx + 1) % MIDIIN_MAX_BUFFER_SIZE;
-		} else
-		{
+		} else {
 			break;
 		}
 	}
 
-	if (count)
-	{
+	if (count) {
 		card_mpuin->qtail = idx;
 
-		queue_task(&card_mpuin->task, &tq_immediate);
-		mark_bh(IMMEDIATE_BH);
+		tasklet_hi_schedule(&card_mpuin->tasklet);
 	}
 
 	return CTSTATUS_SUCCESS;
 }
 
-
 /*****************************************************************************/
+
 /*   Supporting functions for Midi-In Interpretation State Machine           */
+
 /*****************************************************************************/
 
 /* FIXME: This should be a macro */
-int sblive_miStateInit(struct sblive_mpuin *card_mpuin)
+int sblive_miStateInit(struct emu10k1_mpuin *card_mpuin)
 {
 	card_mpuin->status = 0;	/* For MIDI running status */
-	card_mpuin->fstatus = 0; /* For 0xFn status only */
+	card_mpuin->fstatus = 0;	/* For 0xFn status only */
 	card_mpuin->curstate = STIN_PARSE;
 	card_mpuin->laststate = STIN_PARSE;
 	card_mpuin->data = 0;
@@ -651,16 +384,14 @@
 }
 
 /* FIXME: This should be a macro */
-int sblive_miStateEntry(struct sblive_mpuin *card_mpuin, u8 data)
+int sblive_miStateEntry(struct emu10k1_mpuin *card_mpuin, u8 data)
 {
 	return midistatefn[card_mpuin->curstate].Fn(card_mpuin, data);
 }
 
-
-int sblive_miStateParse(struct sblive_mpuin *card_mpuin, u8 data)
+int sblive_miStateParse(struct emu10k1_mpuin *card_mpuin, u8 data)
 {
-	switch (data & 0xf0)
-	{
+	switch (data & 0xf0) {
 	case 0x80:
 	case 0x90:
 	case 0xA0:
@@ -676,14 +407,12 @@
 
 	case 0xF0:
 		/* System messages do not affect the previous running status! */
-		switch (data & 0x0f)
-		{
+		switch (data & 0x0f) {
 		case 0x0:
 			card_mpuin->laststate = card_mpuin->curstate;
 			card_mpuin->curstate = STIN_SYS_EX_NORM;
 
-			if (card_mpuin->firstmidiq)
-			{
+			if (card_mpuin->firstmidiq) {
 				struct midi_queue *midiq;
 
 				midiq = card_mpuin->firstmidiq;
@@ -695,7 +424,7 @@
 			return CTSTATUS_NEXT_BYTE;
 
 		case 0x7:
-			sblive_mpuinMidiCallback(card_mpuin, ICARDMIDI_INDATAERROR, 0xF7, 0);
+			emu10k1_mpuin_callback(card_mpuin, ICARDMIDI_INDATAERROR, 0xf7, 0);
 			return CTSTATUS_ERROR;
 
 		case 0x2:
@@ -724,46 +453,41 @@
 	return midistatefn[card_mpuin->curstate].Fn(card_mpuin, data);
 }
 
-
-int sblive_miState3Byte(struct sblive_mpuin *card_mpuin, u8 data)
+int sblive_miState3Byte(struct emu10k1_mpuin *card_mpuin, u8 data)
 {
-	u8 bTemp = data & 0xF0;
+	u8 temp = data & 0xf0;
 
-	if (bTemp < 0x80)
-	{
+	if (temp < 0x80) {
 		return midistatefn[STIN_3BYTE_KEY].Fn(card_mpuin, data);
-	} else
-		if (bTemp <= 0xE0 && bTemp != 0xC0 && bTemp != 0xD0)
-		{
-			card_mpuin->status = data;
-			card_mpuin->curstate = STIN_3BYTE_KEY;
+	} else if (temp <= 0xe0 && temp != 0xc0 && temp != 0xd0) {
+		card_mpuin->status = data;
+		card_mpuin->curstate = STIN_3BYTE_KEY;
 
-			return CTSTATUS_NEXT_BYTE;
-		}
+		return CTSTATUS_NEXT_BYTE;
+	}
 
 	return midistatefn[STIN_PARSE].Fn(card_mpuin, data);
 }
 
+int sblive_miState3ByteKey(struct emu10k1_mpuin *card_mpuin, u8 data)
 
-int sblive_miState3ByteKey(struct sblive_mpuin *card_mpuin, u8 data)
 /* byte 1 */
 {
-	u32 tmp;
+	unsigned long tmp;
 
-	if (data > 0x7F)
-	{
+	if (data > 0x7f) {
 		/* Real-time messages check */
-		if (data > 0xF7)
+		if (data > 0xf7)
 			return midistatefn[STIN_SYS_REAL].Fn(card_mpuin, data);
 
 		/* Invalid data! */
 		DPF(2, "Invalid data!\n");
 
 		card_mpuin->curstate = STIN_PARSE;
-		tmp = ((u32) data) << 8;
-		tmp |= card_mpuin->status;
+		tmp = ((unsigned long) data) << 8;
+		tmp |= (unsigned long) card_mpuin->status;
 
-		sblive_mpuinMidiCallback(card_mpuin, ICARDMIDI_INDATAERROR, tmp, 0);
+		emu10k1_mpuin_callback(card_mpuin, ICARDMIDI_INDATAERROR, tmp, 0);
 
 		return CTSTATUS_ERROR;
 	}
@@ -774,100 +498,95 @@
 	return CTSTATUS_NEXT_BYTE;
 }
 
+int sblive_miState3ByteVel(struct emu10k1_mpuin *card_mpuin, u8 data)
 
-int sblive_miState3ByteVel(struct sblive_mpuin *card_mpuin, u8 data)
 /* byte 2 */
 {
-	u32 tmp;
+	unsigned long tmp;
 
-	if (data > 0x7F)
-	{
+	if (data > 0x7f) {
 		/* Real-time messages check */
-		if (data > 0xF7)
+		if (data > 0xf7)
 			return midistatefn[STIN_SYS_REAL].Fn(card_mpuin, data);
 
 		/* Invalid data! */
 		DPF(2, "Invalid data!\n");
 
 		card_mpuin->curstate = STIN_PARSE;
-		tmp = ((u32) data) << 8;
+		tmp = ((unsigned long) data) << 8;
 		tmp |= card_mpuin->data;
 		tmp = tmp << 8;
-		tmp |= card_mpuin->status;
+		tmp |= (unsigned long) card_mpuin->status;
 
-		sblive_mpuinMidiCallback(card_mpuin, ICARDMIDI_INDATAERROR, tmp, 0);
+		emu10k1_mpuin_callback(card_mpuin, ICARDMIDI_INDATAERROR, tmp, 0);
 
 		return CTSTATUS_ERROR;
 	}
 
 	card_mpuin->curstate = STIN_3BYTE;
-	tmp = (u32) data;
+	tmp = (unsigned long) data;
 	tmp = tmp << 8;
-	tmp |= card_mpuin->data;
+	tmp |= (unsigned long) card_mpuin->data;
 	tmp = tmp << 8;
-	tmp |= card_mpuin->status;
+	tmp |= (unsigned long) card_mpuin->status;
 
-	sblive_mpuinMidiCallback(card_mpuin, ICARDMIDI_INDATA, tmp, 3);
+	emu10k1_mpuin_callback(card_mpuin, ICARDMIDI_INDATA, tmp, 3);
 
 	return CTSTATUS_SUCCESS;
 }
-
 
-int sblive_miState2Byte(struct sblive_mpuin *card_mpuin, u8 data)
+int sblive_miState2Byte(struct emu10k1_mpuin *card_mpuin, u8 data)
 {
-	u8 bTemp = data & 0xF0;
+	u8 temp = data & 0xf0;
 
-	if ((bTemp == 0xC0) || (bTemp == 0xD0))
-	{
+	if ((temp == 0xc0) || (temp == 0xd0)) {
 		card_mpuin->status = data;
 		card_mpuin->curstate = STIN_2BYTE_KEY;
 
 		return CTSTATUS_NEXT_BYTE;
 	}
 
-	if (bTemp < 0x80)
+	if (temp < 0x80)
 		return midistatefn[STIN_2BYTE_KEY].Fn(card_mpuin, data);
 
 	return midistatefn[STIN_PARSE].Fn(card_mpuin, data);
 }
 
+int sblive_miState2ByteKey(struct emu10k1_mpuin *card_mpuin, u8 data)
 
-int sblive_miState2ByteKey(struct sblive_mpuin *card_mpuin, u8 data)
 /* byte 1 */
 {
-	u32 tmp;
+	unsigned long tmp;
 
-	if (data > 0x7F)
-	{
+	if (data > 0x7f) {
 		/* Real-time messages check */
-		if (data > 0xF7)
+		if (data > 0xf7)
 			return midistatefn[STIN_SYS_REAL].Fn(card_mpuin, data);
 
 		/* Invalid data! */
 		DPF(2, "Invalid data!\n");
 
 		card_mpuin->curstate = STIN_PARSE;
-		tmp = (u32) data;
+		tmp = (unsigned long) data;
 		tmp = tmp << 8;
-		tmp |= card_mpuin->status;
+		tmp |= (unsigned long) card_mpuin->status;
 
-		sblive_mpuinMidiCallback(card_mpuin, ICARDMIDI_INDATAERROR, tmp, 0);
+		emu10k1_mpuin_callback(card_mpuin, ICARDMIDI_INDATAERROR, tmp, 0);
 
 		return CTSTATUS_ERROR;
 	}
 
 	card_mpuin->curstate = STIN_2BYTE;
-	tmp = (u32) data;
+	tmp = (unsigned long) data;
 	tmp = tmp << 8;
-	tmp |= card_mpuin->status;
+	tmp |= (unsigned long) card_mpuin->status;
 
-	sblive_mpuinMidiCallback(card_mpuin, ICARDMIDI_INDATA, tmp, 2);
+	emu10k1_mpuin_callback(card_mpuin, ICARDMIDI_INDATA, tmp, 2);
 
 	return CTSTATUS_SUCCESS;
 }
 
-
-int sblive_miStateSysCommon2(struct sblive_mpuin *card_mpuin, u8 data)
+int sblive_miStateSysCommon2(struct emu10k1_mpuin *card_mpuin, u8 data)
 {
 	card_mpuin->fstatus = data;
 	card_mpuin->curstate = STIN_SYS_COMMON_2_KEY;
@@ -875,43 +594,41 @@
 	return CTSTATUS_NEXT_BYTE;
 }
 
+int sblive_miStateSysCommon2Key(struct emu10k1_mpuin *card_mpuin, u8 data)
 
-int sblive_miStateSysCommon2Key(struct sblive_mpuin *card_mpuin, u8 data)
 /* byte 1 */
 {
-	u32 tmp;
+	unsigned long tmp;
 
-	if (data > 0x7F)
-	{
+	if (data > 0x7f) {
 		/* Real-time messages check */
-		if (data > 0xF7)
+		if (data > 0xf7)
 			return midistatefn[STIN_SYS_REAL].Fn(card_mpuin, data);
 
 		/* Invalid data! */
 		DPF(2, "Invalid data!\n");
 
 		card_mpuin->curstate = card_mpuin->laststate;
-		tmp = (u32) data;
+		tmp = (unsigned long) data;
 		tmp = tmp << 8;
-		tmp |= card_mpuin->fstatus;
+		tmp |= (unsigned long) card_mpuin->fstatus;
 
-		sblive_mpuinMidiCallback(card_mpuin, ICARDMIDI_INDATAERROR, tmp, 0);
+		emu10k1_mpuin_callback(card_mpuin, ICARDMIDI_INDATAERROR, tmp, 0);
 
 		return CTSTATUS_ERROR;
 	}
 
 	card_mpuin->curstate = card_mpuin->laststate;
-	tmp = (u32) data;
+	tmp = (unsigned long) data;
 	tmp = tmp << 8;
-	tmp |= card_mpuin->fstatus;
+	tmp |= (unsigned long) card_mpuin->fstatus;
 
-	sblive_mpuinMidiCallback(card_mpuin, ICARDMIDI_INDATA, tmp, 2);
+	emu10k1_mpuin_callback(card_mpuin, ICARDMIDI_INDATA, tmp, 2);
 
 	return CTSTATUS_SUCCESS;
 }
 
-
-int sblive_miStateSysCommon3(struct sblive_mpuin *card_mpuin, u8 data)
+int sblive_miStateSysCommon3(struct emu10k1_mpuin *card_mpuin, u8 data)
 {
 	card_mpuin->fstatus = data;
 	card_mpuin->curstate = STIN_SYS_COMMON_3_KEY;
@@ -919,27 +636,26 @@
 	return CTSTATUS_NEXT_BYTE;
 }
 
+int sblive_miStateSysCommon3Key(struct emu10k1_mpuin *card_mpuin, u8 data)
 
-int sblive_miStateSysCommon3Key(struct sblive_mpuin *card_mpuin, u8 data)
 /* byte 1 */
 {
-	u32 tmp;
+	unsigned long tmp;
 
-	if (data > 0x7F)
-	{
+	if (data > 0x7f) {
 		/* Real-time messages check */
-		if (data > 0xF7)
+		if (data > 0xf7)
 			return midistatefn[STIN_SYS_REAL].Fn(card_mpuin, data);
 
 		/* Invalid data! */
 		DPF(2, "Invalid data!\n");
 
 		card_mpuin->curstate = card_mpuin->laststate;
-		tmp = (u32) data;
+		tmp = (unsigned long) data;
 		tmp = tmp << 8;
-		tmp |= card_mpuin->fstatus;
+		tmp |= (unsigned long) card_mpuin->fstatus;
 
-		sblive_mpuinMidiCallback(card_mpuin, ICARDMIDI_INDATAERROR, tmp, 0);
+		emu10k1_mpuin_callback(card_mpuin, ICARDMIDI_INDATAERROR, tmp, 0);
 
 		return CTSTATUS_ERROR;
 	}
@@ -950,54 +666,51 @@
 	return CTSTATUS_NEXT_BYTE;
 }
 
+int sblive_miStateSysCommon3Vel(struct emu10k1_mpuin *card_mpuin, u8 data)
 
-int sblive_miStateSysCommon3Vel(struct sblive_mpuin *card_mpuin, u8 data)
 /* byte 2 */
 {
-	u32 tmp;
+	unsigned long tmp;
 
-	if (data > 0x7F)
-	{
+	if (data > 0x7f) {
 		/* Real-time messages check */
-		if (data > 0xF7)
+		if (data > 0xf7)
 			return midistatefn[STIN_SYS_REAL].Fn(card_mpuin, data);
 
 		/* Invalid data! */
 		DPF(2, "Invalid data!\n");
 
 		card_mpuin->curstate = card_mpuin->laststate;
-		tmp = (u32) data;
+		tmp = (unsigned long) data;
 		tmp = tmp << 8;
-		tmp |= card_mpuin->data;
+		tmp |= (unsigned long) card_mpuin->data;
 		tmp = tmp << 8;
-		tmp |= card_mpuin->fstatus;
+		tmp |= (unsigned long) card_mpuin->fstatus;
 
-		sblive_mpuinMidiCallback(card_mpuin, ICARDMIDI_INDATAERROR, tmp, 0);
+		emu10k1_mpuin_callback(card_mpuin, ICARDMIDI_INDATAERROR, tmp, 0);
 
 		return CTSTATUS_ERROR;
 	}
 
 	card_mpuin->curstate = card_mpuin->laststate;
-	tmp = (u32) data;
+	tmp = (unsigned long) data;
 	tmp = tmp << 8;
-	tmp |= card_mpuin->data;
+	tmp |= (unsigned long) card_mpuin->data;
 	tmp = tmp << 8;
-	tmp |= card_mpuin->fstatus;
+	tmp |= (unsigned long) card_mpuin->fstatus;
 
-	sblive_mpuinMidiCallback(card_mpuin, ICARDMIDI_INDATA, tmp, 3);
+	emu10k1_mpuin_callback(card_mpuin, ICARDMIDI_INDATA, tmp, 3);
 
 	return CTSTATUS_SUCCESS;
 }
 
-
-int sblive_miStateSysExNorm(struct sblive_mpuin *card_mpuin, u8 data)
+int sblive_miStateSysExNorm(struct emu10k1_mpuin *card_mpuin, u8 data)
 {
 	unsigned long flags;
 
-	if ((data > 0x7F) && (data != 0xF7))
-	{
+	if ((data > 0x7f) && (data != 0xf7)) {
 		/* Real-time messages check */
-		if (data > 0xF7)
+		if (data > 0xf7)
 			return midistatefn[STIN_SYS_REAL].Fn(card_mpuin, data);
 
 		/* Invalid Data! */
@@ -1005,9 +718,8 @@
 
 		card_mpuin->curstate = card_mpuin->laststate;
 
-		if (card_mpuin->firstmidiq)
-		{
-			struct midi_queue * midiq;
+		if (card_mpuin->firstmidiq) {
+			struct midi_queue *midiq;
 
 			midiq = card_mpuin->firstmidiq;
 			*midiq->midibyte = data;
@@ -1022,7 +734,7 @@
 
 			spin_unlock_irqrestore(&card_mpuin->lock, flags);
 
-			sblive_mpuinMidiCallback(card_mpuin, ICARDMIDI_INLONGERROR, (u32) midiq, 0);
+			emu10k1_mpuin_callback(card_mpuin, ICARDMIDI_INLONGERROR, (unsigned long) midiq, 0);
 
 			kfree(midiq);
 		}
@@ -1030,8 +742,7 @@
 		return CTSTATUS_ERROR;
 	}
 
-	if (card_mpuin->firstmidiq)
-	{
+	if (card_mpuin->firstmidiq) {
 		struct midi_queue *midiq;
 
 		midiq = card_mpuin->firstmidiq;
@@ -1040,16 +751,14 @@
 		++midiq->midibyte;
 	}
 
-	if (data == 0xF7)
-	{
+	if (data == 0xf7) {
 		/* End of Sysex buffer */
 		/* Send down the buffer */
 
 		card_mpuin->curstate = card_mpuin->laststate;
 
-		if (card_mpuin->firstmidiq)
-		{
-			struct midi_queue * midiq;
+		if (card_mpuin->firstmidiq) {
+			struct midi_queue *midiq;
 
 			midiq = card_mpuin->firstmidiq;
 
@@ -1061,7 +770,7 @@
 
 			spin_unlock_irqrestore(&card_mpuin->lock, flags);
 
-			sblive_mpuinMidiCallback(card_mpuin, ICARDMIDI_INLONGDATA, (u32) midiq, 0);
+			emu10k1_mpuin_callback(card_mpuin, ICARDMIDI_INLONGDATA, (unsigned long) midiq, 0);
 
 			kfree(midiq);
 		}
@@ -1069,14 +778,12 @@
 		return CTSTATUS_SUCCESS;
 	}
 
-	if (card_mpuin->firstmidiq)
-	{
+	if (card_mpuin->firstmidiq) {
 		struct midi_queue *midiq;
 
 		midiq = card_mpuin->firstmidiq;
 
-		if (midiq->sizeLeft == 0)
-		{
+		if (midiq->sizeLeft == 0) {
 			/* Special case */
 
 			spin_lock_irqsave(&card_mpuin->lock, flags);
@@ -1087,7 +794,7 @@
 
 			spin_unlock_irqrestore(&card_mpuin->lock, flags);
 
-			sblive_mpuinMidiCallback(card_mpuin, ICARDMIDI_INLONGDATA, (u32) midiq, 0);
+			emu10k1_mpuin_callback(card_mpuin, ICARDMIDI_INLONGDATA, (unsigned long) midiq, 0);
 
 			kfree(midiq);
 
@@ -1097,11 +804,10 @@
 
 	return CTSTATUS_NEXT_BYTE;
 }
-
 
-int sblive_miStateSysReal(struct sblive_mpuin *card_mpuin, u8 data)
+int sblive_miStateSysReal(struct emu10k1_mpuin *card_mpuin, u8 data)
 {
-	sblive_mpuinMidiCallback(card_mpuin, ICARDMIDI_INDATA, data, 1);
+	emu10k1_mpuin_callback(card_mpuin, ICARDMIDI_INDATA, data, 1);
 
 	return CTSTATUS_NEXT_BYTE;
 }
Index: oldkernel/linux/drivers/sound/emu10k1/cardmi.h
diff -u linux/drivers/sound/emu10k1/cardmi.h:1.1 linux/drivers/sound/emu10k1/cardmi.h:1.2
--- linux/drivers/sound/emu10k1/cardmi.h:1.1	Thu Jun  1 16:52:15 2000
+++ linux/drivers/sound/emu10k1/cardmi.h	Fri Jul  7 15:36:45 2000
@@ -55,7 +55,7 @@
 
 /* flags for card MIDI in object */
 #define FLAGS_MIDM_STARTED          0x00001000      // Data has started to come in after Midm Start
-#define MIDIIN_MAX_BUFFER_SIZE      200             // Definition for struct sblive_mpuin
+#define MIDIIN_MAX_BUFFER_SIZE      200             // Definition for struct emu10k1_mpuin
 
 struct midi_data
 {
@@ -63,16 +63,15 @@
 	u32 timein;
 };
 
-struct sblive_mpuin
+struct emu10k1_mpuin
 {
 	spinlock_t        lock;
 	struct midi_queue *firstmidiq;
 	struct midi_queue *lastmidiq;
 	unsigned          qhead, qtail;
 	struct midi_data  midiq[MIDIIN_MAX_BUFFER_SIZE];
-	struct tq_struct task;
+	struct tasklet_struct tasklet;
 	struct midi_openinfo    openinfo;
-	struct midi_caps        caps;
 
 	/* For MIDI state machine */
 	u8              status;        /* For MIDI running status */
@@ -84,45 +83,31 @@
 	u8              data;
 };
 
-int sblive_mpuinInit(struct sblive_mpuin *, struct sblive_hw *);
-int sblive_mpuinExit(struct sblive_hw *);
-
-int sblive_mpuinGetCaps(struct sblive_mpuin *, struct midi_caps *);
-int sblive_mpuinOpen(struct sblive_hw *, struct midi_openinfo *);
-int sblive_mpuinClose(struct sblive_hw *);
-int sblive_mpuinAddBuffer(struct sblive_mpuin *, struct midi_hdr *);
-int sblive_mpuinStart(struct sblive_hw *);
-int sblive_mpuinStop(struct sblive_hw *);
-int sblive_mpuinWriteShortData(struct sblive_mpuin *, u32);
-int sblive_mpuinPause(struct sblive_mpuin *);
-int sblive_mpuinStream(struct sblive_mpuin *, struct midi_hdr *);
-int sblive_mpuinRestart(struct sblive_mpuin *);
-int sblive_mpuinReset(struct sblive_hw *);
-int sblive_mpuinCache(struct sblive_mpuin *, struct midi_cache *);
-int sblive_mpuinGetPosition(struct sblive_mpuin *, u32 *);
-int sblive_mpuinGetControl(struct sblive_mpuin *, u32, u32 *);
-int sblive_mpuinSetControl(struct sblive_mpuin *, u32, u32 *);
-
-#define IDS_EMU_MIDIIN_PNAME                "SB Live! In"
-
-int sblive_miStateInit(struct sblive_mpuin *);
-int sblive_miStateEntry(struct sblive_mpuin *, u8);
-int sblive_miStateParse(struct sblive_mpuin *, u8);
-int sblive_miState3Byte(struct sblive_mpuin *, u8);
-int sblive_miState3ByteKey(struct sblive_mpuin *, u8);
-int sblive_miState3ByteVel(struct sblive_mpuin *, u8);
-int sblive_miState2Byte(struct sblive_mpuin *, u8);
-int sblive_miState2ByteKey(struct sblive_mpuin *, u8);
-int sblive_miStateSysCommon2(struct sblive_mpuin *, u8);
-int sblive_miStateSysCommon2Key(struct sblive_mpuin *, u8);
-int sblive_miStateSysCommon3(struct sblive_mpuin *, u8);
-int sblive_miStateSysCommon3Key(struct sblive_mpuin *, u8);
-int sblive_miStateSysCommon3Vel(struct sblive_mpuin *, u8);
-int sblive_miStateSysExNorm(struct sblive_mpuin *, u8);
-int sblive_miStateSysReal(struct sblive_mpuin *, u8);
-
-int sblive_mpuinIrqCallback(struct sblive_hw *);
-void sblive_mpuinDpcCallback(void *);
-int sblive_mpuinMidiCallback(struct sblive_mpuin *card_mpuin, u32 msg, u32 data, u32 bytesvalid);
+int emu10k1_mpuin_open(struct emu10k1_card *, struct midi_openinfo *);
+int emu10k1_mpuin_close(struct emu10k1_card *);
+int emu10k1_mpuin_add_buffer(struct emu10k1_mpuin *, struct midi_hdr *);
+int emu10k1_mpuin_start(struct emu10k1_card *);
+int emu10k1_mpuin_stop(struct emu10k1_card *);
+int emu10k1_mpuin_reset(struct emu10k1_card *);
+
+int sblive_miStateInit(struct emu10k1_mpuin *);
+int sblive_miStateEntry(struct emu10k1_mpuin *, u8);
+int sblive_miStateParse(struct emu10k1_mpuin *, u8);
+int sblive_miState3Byte(struct emu10k1_mpuin *, u8);
+int sblive_miState3ByteKey(struct emu10k1_mpuin *, u8);
+int sblive_miState3ByteVel(struct emu10k1_mpuin *, u8);
+int sblive_miState2Byte(struct emu10k1_mpuin *, u8);
+int sblive_miState2ByteKey(struct emu10k1_mpuin *, u8);
+int sblive_miStateSysCommon2(struct emu10k1_mpuin *, u8);
+int sblive_miStateSysCommon2Key(struct emu10k1_mpuin *, u8);
+int sblive_miStateSysCommon3(struct emu10k1_mpuin *, u8);
+int sblive_miStateSysCommon3Key(struct emu10k1_mpuin *, u8);
+int sblive_miStateSysCommon3Vel(struct emu10k1_mpuin *, u8);
+int sblive_miStateSysExNorm(struct emu10k1_mpuin *, u8);
+int sblive_miStateSysReal(struct emu10k1_mpuin *, u8);
+
+int emu10k1_mpuin_irqhandler(struct emu10k1_card *);
+void emu10k1_mpuin_bh(unsigned long);
+int emu10k1_mpuin_callback(struct emu10k1_mpuin *card_mpuin, u32 msg, unsigned long data, u32 bytesvalid);
 
 #endif  /* _CARDMI_H */
Index: oldkernel/linux/drivers/sound/emu10k1/cardmo.c
diff -u linux/drivers/sound/emu10k1/cardmo.c:1.1 linux/drivers/sound/emu10k1/cardmo.c:1.2
--- linux/drivers/sound/emu10k1/cardmo.c:1.1	Thu Jun  1 16:52:15 2000
+++ linux/drivers/sound/emu10k1/cardmo.c	Fri Jul  7 15:36:45 2000
@@ -1,3 +1,4 @@
+
 /*     
  **********************************************************************
  *     cardmo.c - MIDI UART output HAL for emu10k1 driver 
@@ -33,149 +34,59 @@
 #include "hwaccess.h"
 #include "cardmo.h"
 
-/****************************************************************************/
-/*int    sblive_mpuoutInit(PICARDMIDI pICardMidi, PICARD pICard )           */
-/*                                                                          */
-/*Function:   Initialize the parameters + reset the MPU port                */
-/****************************************************************************/
-int sblive_mpuoutInit(struct sblive_mpuout *card_mpuout, struct sblive_hw *sb_hw)
-{
-	u8 name[128];
-	
-	DPF(2, "sblive_mpuoutInit\n");
-
-	memset(card_mpuout, 0, sizeof(struct sblive_mpuout));
-
-	card_mpuout->intr = TRUE;
-	card_mpuout->status = FLAGS_AVAILABLE;
-	card_mpuout->state = CARDMIDIOUT_STATE_DEFAULT;
-	card_mpuout->caps.cbsize = sizeof(struct midi_caps);
-	card_mpuout->caps.support = MIDICAPS_OUTPUT;
-	card_mpuout->caps.technology = MT_MIDIPORT;
-	card_mpuout->caps.product = MM_CREATIVE_MIDIOUT;
-	card_mpuout->caps.manufacturer = MM_CREATIVE;
-	card_mpuout->caps.voices = 0;
-	card_mpuout->caps.notes = 0;
-	card_mpuout->caps.channelmask = 0xffff;
-	card_mpuout->caps.caps = CARDMIDI_OUT;
-
-	card_mpuout->task.next = NULL;
-	card_mpuout->task.sync = 0;
-	card_mpuout->task.routine = sblive_mpuoutDpcCallback;
-	card_mpuout->task.data = sb_hw;
-
-	spin_lock_init(&card_mpuout->lock);
-
-	strcpy(name, IDS_EMU_MIDIOUT_PNAME);
-
-	/* Fill in card caps */
-	sprintf(card_mpuout->caps.MIDIname, "%s [%lx]", name, sb_hw->hwaddr);
-
-	/* Reset the MPU port */
-	if (hwmpuReset(sb_hw) != CTSTATUS_SUCCESS) 
-	{
-		DPF(2, "MPU hardware reset failure\n");
-		return CTSTATUS_NOTENABLED;
-	}
-	
-	return CTSTATUS_SUCCESS;
-}
+/* Installs the IRQ handler for the MPU out port               *
+ * and initialize parameters                                    */
 
-
-/****************************************************************************/
-/*int    sblive_mpuoutExit(struct sblive_mpuout *card_mpuout)               */
-/*                                                                          */
-/*Function:   Disable the IRQ TX and uninstall the IRQ handler              */
-/****************************************************************************/
-int sblive_mpuoutExit(struct sblive_hw *sb_hw)
+int emu10k1_mpuout_open(struct emu10k1_card *card, struct midi_openinfo *openinfo)
 {
-	struct sblive_mpuout *card_mpuout = sb_hw->card_mpuout;
-	
-	DPF(2, "sblive_mpuoutExit\n");
-
-	sblive_irqmgrDisableIrq(sb_hw, INTE_MIDITXENABLE);
+	struct emu10k1_mpuout *card_mpuout = card->mpuout;
 
-	card_mpuout->status |= FLAGS_AVAILABLE;
-	card_mpuout->state = CARDMIDIOUT_STATE_DEFAULT;
+	DPF(2, "emu10k1_mpuout_open()\n");
 
-	return CTSTATUS_SUCCESS;
-}
-
-
-/****************************************************************************/
-/* int    sblive_mpuoutOpen(PICARDMIDI pICardMidi,                          */
-/*                            struct midi_openinfo *openinfo,               */
-/*                            u32 *handle)                                  */
-/*                                                                          */
-/* Function:   Installs the IRQ handler for the MPU out port                */
-/*             and initialize parameters                                    */
-/****************************************************************************/
-int sblive_mpuoutOpen(struct sblive_hw *sb_hw, struct midi_openinfo *openinfo)
-{
-	struct sblive_mpuout *card_mpuout = sb_hw->card_mpuout; 
-	
-	DPF(2, "sblive_mpuoutOpen\n");
-
 	if (!(card_mpuout->status & FLAGS_AVAILABLE))
-	  return CTSTATUS_INUSE;
+		return CTSTATUS_INUSE;
 
 	/* Copy open info and mark channel as in use */
-	card_mpuout->intr = TRUE;
+	card_mpuout->intr = 0;
 	card_mpuout->openinfo = *openinfo;
 	card_mpuout->status &= ~FLAGS_AVAILABLE;
 	card_mpuout->laststatus = 0x80;
 	card_mpuout->firstmidiq = NULL;
 	card_mpuout->lastmidiq = NULL;
 
-	hwmpuReset(sb_hw);
-	hwmpuAcquire(sb_hw);
+	emu10k1_mpu_reset(card);
+	emu10k1_mpu_acquire(card);
 
 	return CTSTATUS_SUCCESS;
 }
-
 
-/****************************************************************************/
-/* int    sblive_mpuoutClose(PICARDMIDI pICardMidi,                         */
-/*                             u32 handle)                                  */
-/*                                                                          */
-/* Function:   If local buffer is not empty,                                */
-/*             return CTSTATUS_STILLPLAYING                                 */
-/*             Otherwise, disable and uninstall TX IRQ                      */
-/****************************************************************************/
-int sblive_mpuoutClose(struct sblive_hw *sb_hw)
+int emu10k1_mpuout_close(struct emu10k1_card *card)
 {
-	struct sblive_mpuout *card_mpuout = sb_hw->card_mpuout;
+	struct emu10k1_mpuout *card_mpuout = card->mpuout;
 	struct midi_queue *midiq;
 	struct midi_hdr *midihdr;
 	unsigned long flags;
-	
-	DPF(2, "sblive_mpuoutClose\n");
 
-	sblive_irqmgrDisableIrq(sb_hw, INTE_MIDITXENABLE);
+	DPF(2, "emu10k1_mpuout_close()\n");
 
+	emu10k1_irq_disable(card, INTE_MIDITXENABLE);
+
 	spin_lock_irqsave(&card_mpuout->lock, flags);
 
-	while(card_mpuout->firstmidiq != NULL){
+	while (card_mpuout->firstmidiq != NULL) {
 		midiq = card_mpuout->firstmidiq;
 		midihdr = (struct midi_hdr *) midiq->refdata;
-
-		card_mpuout->firstmidiq = midiq->next; 
 
-                kfree(midihdr->lpData);
+		card_mpuout->firstmidiq = midiq->next;
 
-		DPD(3, "kfree: [%p]\n", midihdr->lpData);
-
+		kfree(midihdr->data);
 		kfree(midihdr);
-
-                DPD(3, "kfree: [%p]\n", midihdr);
-
 		kfree(midiq);
-		DPD(3, "kfree: [%p]\n", midiq);	
 	}
 
 	card_mpuout->lastmidiq = NULL;
 
-	hwmpuRelease(sb_hw);
+	emu10k1_mpu_release(card);
 
 	card_mpuout->status |= FLAGS_AVAILABLE;
 
@@ -184,291 +95,135 @@
 	return CTSTATUS_SUCCESS;
 }
 
+/* If there isn't enough buffer space, reject Midi Buffer.     *
+* Otherwise, disable TX, create object to hold Midi            *
+*  uffer, update buffer flags and other parameters             *
+* before enabling TX again.                                    */
 
-/****************************************************************************/
-/* int    sblive_mpuoutAddBuffer(PICARDMIDI pICardMidi,                     */
-/*                                 u32 handle,                              */
-/*                                 struct midi_hdr *INFO midihdrInfo)       */
-/*                                                                          */
-/* Function:   If there isn't enough buffer space, reject Midi Buffer.      */
-/*             Otherwise, disable TX, create object to hold Midi            */
-/*             Buffer, update buffer flags and other parameters             */
-/*             before enabling TX again.                                    */
-/****************************************************************************/
-int sblive_mpuoutAddBuffer(struct sblive_hw *sb_hw, struct midi_hdr *midihdr)
+int emu10k1_mpuout_add_buffer(struct emu10k1_card *card, struct midi_hdr *midihdr)
 {
-	struct sblive_mpuout *card_mpuout = sb_hw->card_mpuout;
+	struct emu10k1_mpuout *card_mpuout = card->mpuout;
 	struct midi_queue *midiq;
 	unsigned long flags;
 
-	DPF(2, "sblive_mpuoutAddBuffer\n");
+	DPF(2, "emu10k1_mpuout_add_buffer()\n");
 
 	if (card_mpuout->state == CARDMIDIOUT_STATE_SUSPEND)
-	  return CTSTATUS_SUCCESS;
+		return CTSTATUS_SUCCESS;
 
 	midihdr->flags |= MIDIBUF_INQUEUE;
 	midihdr->flags &= ~MIDIBUF_DONE;
 
-	midiq = (struct midi_queue *) kmalloc(sizeof(struct midi_queue), GFP_KERNEL);
-	if (midiq == NULL) 
-	{
+	if ((midiq = (struct midi_queue *) kmalloc(sizeof(struct midi_queue), GFP_KERNEL)) == NULL) {
 		/* Message lost */
 		return CTSTATUS_NOMEMORY;
 	}
 
-	DPD(3, "kmalloc: [%p]\n", midiq);
-	
 	midiq->next = NULL;
 	midiq->qtype = 1;
 	midiq->length = midihdr->bufferlength;
 	midiq->sizeLeft = midihdr->bufferlength;
-	midiq->midibyte = midihdr->lpData;
+	midiq->midibyte = midihdr->data;
 
 	midiq->refdata = (unsigned long) midihdr;
 
 	spin_lock_irqsave(&card_mpuout->lock, flags);
 
-	if (card_mpuout->firstmidiq == NULL) 
-	{
+	if (card_mpuout->firstmidiq == NULL) {
 		card_mpuout->firstmidiq = midiq;
 		card_mpuout->lastmidiq = midiq;
-	} else 
-	{
+	} else {
 		(card_mpuout->lastmidiq)->next = midiq;
 		card_mpuout->lastmidiq = midiq;
 	}
-
-	card_mpuout->intr = FALSE;
-	
-	sblive_irqmgrEnableIrq(sb_hw, INTE_MIDITXENABLE);
-
-	spin_unlock_irqrestore(&card_mpuout->lock, flags);
-
-	return CTSTATUS_SUCCESS;
-}
-
-
-#if 0 /* what is this function for? (rsousa) */
-
-/****************************************************************************/
-/* int    sblive_mpuoutWriteShortData(PICARDMIDI pICardMidi,                */
-/*                                      u32 handle,                         */
-/*                                      u32 midimsg)                        */
-/*                                                                          */
-/* Function:   Adds the short message to our local buffer                   */
-/* Note:       This writeout must succeed at all cost ... else UART output  */
-/*             will sound wierd at a sound module.                          */
-/****************************************************************************/
-int sblive_mpuoutWriteShortData(struct sblive_hw *sb_hw, u32 midimsg)
-{
-	struct sblive_mpuout *card_mpuout = sb_hw->card_mpuout;
-	int msglen;
-	struct midi_queue *midiq;
-	int status;
-	unsigned long flags;
-
-
-	if (card_mpuout->state == CARDMIDIOUT_STATE_SUSPEND)
-	  return CTSTATUS_SUCCESS;
-
-	if (midimsg & 0x80) 
-	{
-		if (((u8) midimsg) < 0xF0) 
-		{
-			card_mpuout->laststatus = (u8) midimsg;
-			msglen = gabMsgLenChannel[((midimsg & 0xF0) - 0x80) >> 4];
-		} else
-		  msglen = gabMsgLenSystem[midimsg & 0x0F];
-	} else 
-	{
-		if (card_mpuout->laststatus)
-		  msglen = gabMsgLenChannel[((card_mpuout->laststatus & 0xF0) - 0x80) >> 4];
-		else 
-		{
-			DPD(2, "sblive_mpuoutWriteShortData error!!: midimsg = %x\n", midimsg);
-			return CTSTATUS_ERROR;
-		}
-		--msglen;
-	}
-
-	if (card_mpuout->lastmidiq == NULL) 
-	{
-		unsigned long flags;
-		/* Wait until TX interrupt has occurred.
-		 * This means that the FIFO is empty.
-		 */
-		while (card_mpuout->intr != TRUE);
-
-		spin_lock_irqsave(&card_mpuout->lock, flags);
-
-		while (msglen--) 
-		{
-			status = hwmpuWriteData(sb_hw, (u8)midimsg);
-
-			if (status != CTSTATUS_SUCCESS) 
-			{
-				DPD(2, "sblive_mpuoutWriteShortData error!!: byte = %x\n", (u8) midimsg);
-				DPD(2, "UART BYTE OUT (MISSED) = %x\n", (u8)midimsg);
-				msglen++;
-			} else 
-			{
-				DPD(2, "UART BYTE OUT = %x\n", (u8)midimsg);
-				midimsg >>= 8;
-			}
-		}
-
-		card_mpuout->intr = FALSE;
-		sblive_irqmgrEnableIrq(sb_hw, INTE_MIDITXENABLE);
-		spin_unlock_irqrestore(&card_mpuout->lock, flags);
-
-		return CTSTATUS_SUCCESS;
-	}
-	
-	midiq = (struct midi_queue *) kmalloc(sizeof(struct midi_queue), GFP_KERNEL);
-	if (midiq == NULL) 
-	{
-		/* Message lost */
-		DPD(2, "sblive_mpuoutWriteShortData error!!: midimsg = %x\n", midimsg);
-		return CTSTATUS_NOMEMORY;
-	}
 
-	DPD(3, "kmalloc: [%p]\n", midiq);
-	
-	midiq->next = NULL;
-	midiq->qtype = 0;
-	midiq->length = msglen;
-	midiq->sizeLeft = msglen;
-	midiq->midibyte = (u8 *) &midiq->refdata;
-	midiq->refdata = midimsg;
+	card_mpuout->intr = 0;
 
-	spin_lock_irqsave(&card_mpuout->lock, flags);
+	emu10k1_irq_enable(card, INTE_MIDITXENABLE);
 
-	if (card_mpuout->firstmidiq == NULL) 
-	{
-		card_mpuout->lastmidiq = midiq;
-		card_mpuout->firstmidiq = midiq;
-	} else 
-	{
-		(card_mpuout->lastmidiq)->next = midiq;
-		card_mpuout->lastmidiq = midiq;
-	}
-
-	card_mpuout->intr = FALSE;
-	sblive_irqmgrEnableIrq(sb_hw, INTE_MIDITXENABLE);
 	spin_unlock_irqrestore(&card_mpuout->lock, flags);
 
 	return CTSTATUS_SUCCESS;
 }
-
-#endif
 
-/****************************************************************************/
-/* int sblive_mpuoutDpcCallback ()                                          */
-/****************************************************************************/
-void sblive_mpuoutDpcCallback(void *refdata)
+void emu10k1_mpuout_bh(unsigned long refdata)
 {
+	struct emu10k1_card *card = (struct emu10k1_card *) refdata;
+	struct emu10k1_mpuout *card_mpuout = card->mpuout;
 	int cByteSent = 0;
 	int status;
 	struct midi_queue *midiq;
 	struct midi_queue *doneq = NULL;
-	struct sblive_hw *sb_hw = (struct sblive_hw *) refdata;
-	struct sblive_mpuout *card_mpuout = sb_hw->card_mpuout;
 	unsigned long flags;
 
 	spin_lock_irqsave(&card_mpuout->lock, flags);
 
-	while (card_mpuout->firstmidiq != NULL) 
-	{
+	while (card_mpuout->firstmidiq != NULL) {
 		midiq = card_mpuout->firstmidiq;
-		
-		while (cByteSent < 4 && midiq->sizeLeft) 
-		{
-			status = hwmpuWriteData(sb_hw, *midiq->midibyte);
 
-			if (status == CTSTATUS_SUCCESS) 
-			{
+		while (cByteSent < 4 && midiq->sizeLeft) {
+			status = emu10k1_mpu_write_data(card, *midiq->midibyte);
+
+			if (status == CTSTATUS_SUCCESS) {
 				++cByteSent;
 				--midiq->sizeLeft;
 				++midiq->midibyte;
-			} else 
-			{
-				DPF(2, "sblive_mpuoutDpcCallback error!!\n");
+			} else {
+				DPF(2, "emu10k1_mpuoutDpcCallback error!!\n");
 			}
 		}
-		
-		if (midiq->sizeLeft == 0) 
-		{
+
+		if (midiq->sizeLeft == 0) {
 			if (doneq == NULL)
-			  doneq = midiq;
+				doneq = midiq;
 			card_mpuout->firstmidiq = midiq->next;
 		} else
-		  break;
+			break;
 	}
 
 	if (card_mpuout->firstmidiq == NULL)
-	  card_mpuout->lastmidiq = NULL;
+		card_mpuout->lastmidiq = NULL;
 
-	if (doneq != NULL) 
-	{
-		while (doneq != card_mpuout->firstmidiq) 
-		{
+	if (doneq != NULL) {
+		while (doneq != card_mpuout->firstmidiq) {
 			unsigned long callback_msg[3];
 
 			midiq = doneq;
 			doneq = midiq->next;
-			
-			if (midiq->qtype) 
-			{
+
+			if (midiq->qtype) {
 				callback_msg[0] = 0;
 				callback_msg[1] = midiq->length;
 				callback_msg[2] = midiq->refdata;
-				
-				midiCallbackFn(ICARDMIDI_OUTLONGDATA, card_mpuout->openinfo.refdata, callback_msg);
-			} else 
-			  if (((u8) midiq->refdata) < 0xF0 &&
-			      ((u8) midiq->refdata) > 0x7F)
-			    card_mpuout->laststatus = (u8) midiq->refdata;
+
+				emu10k1_midi_callback(ICARDMIDI_OUTLONGDATA, card_mpuout->openinfo.refdata, callback_msg);
+			} else if (((u8) midiq->refdata) < 0xF0 && ((u8) midiq->refdata) > 0x7F)
+				card_mpuout->laststatus = (u8) midiq->refdata;
 
 			kfree(midiq);
-			DPD(3, "kfree: [%p]\n", midiq);
 		}
 	}
-	
-	if ((card_mpuout->firstmidiq != NULL) || cByteSent) 
-	{
-		card_mpuout->intr = FALSE;
-		sblive_irqmgrEnableIrq(sb_hw, INTE_MIDITXENABLE);
+
+	if ((card_mpuout->firstmidiq != NULL) || cByteSent) {
+		card_mpuout->intr = 0;
+		emu10k1_irq_enable(card, INTE_MIDITXENABLE);
 	}
 
 	spin_unlock_irqrestore(&card_mpuout->lock, flags);
-	
+
 	return;
 }
 
-
-/****************************************************************************/
-/* int    sblive_mpuoutIrqCallback(unsigned long event,                     */
-/*                                   unsigned long refdata,                 */
-/*                                   unsigned long param)                   */
-/*                                                                          */
-/* Function:   IRQ callback handler routine for the MPU out port            */
-/****************************************************************************/
-int sblive_mpuoutIrqCallback(struct sblive_hw *sb_hw)
+int emu10k1_mpuout_irqhandler(struct emu10k1_card *card)
 {
-	struct sblive_mpuout *card_mpuout = sb_hw->card_mpuout;
-
-	/* Called during ISR. The data & code touched are:
-	 * 1. card_mpuout
-	 * 2. sblive_irqmgrDisableIrq()
-	 */
+	struct emu10k1_mpuout *card_mpuout = card->mpuout;
 
-	DPF(4, "sblive_mpuoutIrqCallback\n");
+	DPF(4, "emu10k1_mpuout_irqhandler\n");
 
-	card_mpuout->intr = TRUE;
-	sblive_irqmgrDisableIrq(sb_hw, INTE_MIDITXENABLE);
+	card_mpuout->intr = 1;
+	emu10k1_irq_disable(card, INTE_MIDITXENABLE);
 
-	queue_task(&card_mpuout->task, &tq_immediate);
-	mark_bh(IMMEDIATE_BH);
+	tasklet_hi_schedule(&card_mpuout->tasklet);
 
 	return CTSTATUS_SUCCESS;
 }
Index: oldkernel/linux/drivers/sound/emu10k1/cardmo.h
diff -u linux/drivers/sound/emu10k1/cardmo.h:1.1 linux/drivers/sound/emu10k1/cardmo.h:1.2
--- linux/drivers/sound/emu10k1/cardmo.h:1.1	Thu Jun  1 16:52:15 2000
+++ linux/drivers/sound/emu10k1/cardmo.h	Fri Jul  7 15:36:45 2000
@@ -35,11 +35,10 @@
 
 #include "icardmid.h"
 
-#define IDS_EMU_MIDIOUT_PNAME        "SB Live! MIDI Out"
 #define CARDMIDIOUT_STATE_DEFAULT    0x00000000
 #define CARDMIDIOUT_STATE_SUSPEND    0x00000001
 
-struct sblive_mpuout
+struct emu10k1_mpuout
 {
 	u32			status;
 	u32			state;
@@ -47,24 +46,16 @@
 	struct midi_queue	*firstmidiq;
 	struct midi_queue	*lastmidiq;
 	u8			laststatus;
-	struct tq_struct 	task;
+	struct tasklet_struct 	tasklet;
 	spinlock_t		lock;
-	struct midi_caps	caps;
 	struct midi_openinfo	openinfo;
 };
 
-int sblive_mpuoutInit(struct sblive_mpuout *, struct sblive_hw *);
-int sblive_mpuoutExit(struct sblive_hw *);
+int emu10k1_mpuout_open(struct emu10k1_card *, struct midi_openinfo *);
+int emu10k1_mpuout_close(struct emu10k1_card *);
+int emu10k1_mpuout_add_buffer(struct emu10k1_card *, struct midi_hdr *);
 
-int sblive_mpuoutOpen(struct sblive_hw *, struct midi_openinfo *);
-int sblive_mpuoutClose(struct sblive_hw *);
-int sblive_mpuoutAddBuffer(struct sblive_hw *, struct midi_hdr *);
-
-#if 0
-int sblive_mpuoutWriteShortData(struct sblive_hw *, u32);
-#endif
-
-int sblive_mpuoutIrqCallback(struct sblive_hw *);
-void sblive_mpuoutDpcCallback(void *);
+int emu10k1_mpuout_irqhandler(struct emu10k1_card *);
+void emu10k1_mpuout_bh(unsigned long);
 
 #endif  /* _CARDMO_H */
Index: oldkernel/linux/drivers/sound/emu10k1/cardwi.c
diff -u linux/drivers/sound/emu10k1/cardwi.c:1.1 linux/drivers/sound/emu10k1/cardwi.c:1.2
--- linux/drivers/sound/emu10k1/cardwi.c:1.1	Thu Jun  1 16:52:15 2000
+++ linux/drivers/sound/emu10k1/cardwi.c	Fri Jul  7 15:36:45 2000
@@ -1,3 +1,4 @@
+
 /*
  **********************************************************************
  *     cardwi.c - PCM input HAL for emu10k1 driver
@@ -29,96 +30,21 @@
  **********************************************************************
  */
 
-
 #include "hwaccess.h"
-#include "mycommon.h"
-#include "mmwave.h"
 #include "recmgr.h"
 #include "audio.h"
 #include "cardwi.h"
-
-/****************************************************************************/
-/* Function : sblive_waveinInit                                             */
-/*                                                                          */
-/* Input    : card_wavein - pointer to card wavein object                   */
-/*            sb_hw - pointer to hardware object                            */
-/*            mixer - pointer to card mixer                                 */
-/*            carddesc - card description                                   */
-/*                                                                          */
-/* Return   : CTSTATUS_SUCCESS  -- successful                               */
-/*            CTSTATUS_ERROR    -- failure                                  */
-/*                                                                          */
-/* About    : initialize card wave input device.                            */
-/****************************************************************************/
-int sblive_waveinInit(struct sblive_wavein *card_wavein, u8 *carddesc)
-{
-	/* Init Cardwave Caps */
-	memset(card_wavein, 0, sizeof(struct sblive_wavein));
-	card_wavein->caps.product_id = MM_CREATIVE_WAVEIN_PID;
-	card_wavein->caps.caps = CARDWAVE_IN;
-	card_wavein->caps.controls = 0;
-	card_wavein->caps.maxchannels = 2;
-	card_wavein->caps.minrate = 8000;
-	card_wavein->caps.maxrate = 48000;
-	strcpy(card_wavein->caps.wavedesc, carddesc);
-
-	card_wavein->numrecordinst = 0;
-	card_wavein->wave_inlist = NULL;
-
-	return CTSTATUS_SUCCESS;
-}
 
-
-/****************************************************************************/
-/* Function : sblive_waveinExit                                             */
-/*                                                                          */
-/* Input    : card_wavein - pointer to card wavein object                   */
-/*                                                                          */
-/* Return   : CTSTATUS_SUCCESS  -- successful                               */
-/*            CTSTATUS_ERROR    -- failure                                  */
-/*                                                                          */
-/* About    : exit card wave operation.                                     */
-/****************************************************************************/
-int sblive_waveinExit(struct sblive_wavein *card_wavein)
+void query_format(int recsrc, struct wave_format *wave_fmt)
 {
 
-	return CTSTATUS_SUCCESS;
-}
+	switch (recsrc) {
+	case WAVERECORD_AC97:
 
-/****************************************************************************/
-/* Function : sblive_waveinQueryFormat                                      */
-/*                                                                          */
-/* Input    : card_wavein - pointer to card wavein object                   */
-/*            wave_fmt - pointer to wave format object                      */
-/*            flags - flags that identifies the format to be queried.       */
-/*                                                                          */
-/* About    : query whether a specified wave format is supported by wave    */
-/*            device.                                                       */
-/****************************************************************************/
-int sblive_waveinQueryFormat(struct sblive_wavein *card_wavein,
-			     struct wave_format *wave_fmt, u32 flags)
-{
-	if (flags & CARDWAVE_QF_CHANNEL)
-	{
-		/* Only support one wave input instance */
-		if (card_wavein->numrecordinst > 1)
-			return CTSTATUS_INUSE;
-	}
-
-	if (flags & CARDWAVE_QF_STEREO)
-	{
-		if((wave_fmt->channels != 2) && (wave_fmt->channels != 1))
-			return CTSTATUS_BADFORMAT_STEREO;
-	}
-
-	if (flags & CARDWAVE_QF_RATE)
-	{
-		/* Recording
-		 * Sampling rates supported:
-		 * 48kHz, 44.1kHz, 32kHz, 24kHz, 22.05kHz, 16kHz, 11.025kHz, 8kHz.
-		 */
+		if ((wave_fmt->channels != 2) && (wave_fmt->channels != 1))
+			wave_fmt->channels = 2;
 
-		if(wave_fmt->samplingrate >= (0xBB80 + 0xAC44) / 2 )
+		if (wave_fmt->samplingrate >= (0xBB80 + 0xAC44) / 2)
 			wave_fmt->samplingrate = 0xBB80;
 		else if (wave_fmt->samplingrate >= (0xAC44 + 0x7D00) / 2)
 			wave_fmt->samplingrate = 0xAC44;
@@ -134,248 +60,46 @@
 			wave_fmt->samplingrate = 0x2B11;
 		else
 			wave_fmt->samplingrate = 0x1F40;
-	}
-
-	if (flags & CARDWAVE_QF_BITS)
-	{
-		/* 16 bit and 8 bit recording are supported */
-		if ((wave_fmt->bitspersample != 16) && (wave_fmt->bitspersample != 8))
-			wave_fmt->bitspersample = 16;
-	}
-
-	return CTSTATUS_SUCCESS;
-}
-
-
-/****************************************************************************/
-/* Function : sblive_waveinOpen                                             */
-/*                                                                          */
-/* Input    : card_wavein - pointer to card wavein object                   */
-/*            wave_fmt - pointer to wave format object                      */
-/*            CallbackFn - IRQ call back function                           */
-/*            refdata - reference data for call back function               */
-/*            pcallback_size - pointer to the size of data to transfer      */
-/*                              before CallbackFn is called.                */
-/*            numfrags - number of buffer fragments                         */
-/*                                                                          */
-/* Output   : pcallback_size - pointer to the actual call back size.        */
-/*            phandle - pointer to the open handle.                         */
-/*                                                                          */
-/* About    : Open card wave device.                                        */
-/*            1. query whether a specified wave format is supported by      */
-/*               device.                                                    */
-/*            2. allocate emu channel for the specified channel object.     */
-/*            3. attach this wave instance to the channel object list.      */
-/*            4. install wave IRQ handler.                                  */
-/*            5. get wave transfer buffer.                                  */
-/*            6. get wave instance format.                                  */
-/*            7. for recording, install IRQ handler.                        */
-/****************************************************************************/
-int sblive_waveinOpen(struct sblive_hw *sb_hw, struct wave_format *wave_fmt, u32 *callback_size, u32 numfrags, struct wave_in **handle)
-{
-	struct sblive_wavein *card_wavein = sb_hw->card_wavein;
-	struct wave_in *wave_in;
-	int status;
-	u32 bufsiz;
-	u8 *buffer;
-
-	if (!(wave_in = (struct wave_in *)kmalloc(sizeof(struct wave_in), GFP_KERNEL)))
-	{
-		DPF(2, "Failed to allocate wave instance!\n");
-		return CTSTATUS_NOMEMORY;
-	}
-
-	DPD(3, "kmalloc: [%p]\n", wave_in);
-
-	/* Init wave in instance */
-	wave_in->next = NULL;
-	wave_in->status &= ~FLAGS_AVAILABLE;
-	wave_in->state = CARDWAVE_STATE_STOPPED;
-	wave_in->synchstart = FALSE;
-	wave_in->wave_fmt = *wave_fmt;
-	wave_in->emu_voice = NULL;
-	wave_in->memhandle = NULL;
-	wave_in->callbacksize = 0;
-	wave_in->process_id = 0;
-	wave_in->setpos = FALSE;
-	wave_in->position = 0;
-
-	/* Recording */
-
-	if (!(wave_in->rec_ptr = (struct record *) kmalloc(sizeof(struct record), GFP_KERNEL)))
-	{
-		DPF(2, "Failed to allocate recording buffer!\n");
-		kfree((void *) wave_in);
-		return CTSTATUS_NOMEMORY;
-	}
-
-	DPD(3, "kmalloc: [%p]\n", wave_in->rec_ptr);
-
-	initRecordObject(sb_hw, wave_in);
-
-	/* Attach this wave instance to the channel object list */
-	osListAttach((struct sblive_list **) & card_wavein->wave_inlist, (struct sblive_list *) wave_in);
-
-	if (callback_size != NULL)
-		wave_in->callbacksize = *callback_size;
-	else
-		wave_in->callbacksize = 0;
-
-	bufsiz = (wave_in->callbacksize ? wave_in->callbacksize * numfrags : 0xffff);
-
-	if ((status = sblive_emuGetRecBuffer(card_wavein, wave_in, &bufsiz, &buffer)) != CTSTATUS_SUCCESS)
-	{
-		DPF(2, "WaveOpen GetBuffer Fail");
-		sblive_waveinClose(sb_hw, wave_in);
-		return CTSTATUS_ERROR;
-	}
-
-	wave_in->callbacksize = bufsiz / numfrags;
-	*callback_size = bufsiz / numfrags;
-
-	/* This callback size returned is the size in the play buffer.
-	 * For 8-bit samples, callbacksize of user buffer should be
-	 * half of the callbacksize in play buffer. */
-	if (wave_in->wave_fmt.bitspersample == 8)
-		*callback_size >>= 1;
-
-	*handle = wave_in;
-
-	return CTSTATUS_SUCCESS;
-}
-
-
-/****************************************************************************/
-/* Function : sblive_waveinClose                                            */
-/*                                                                          */
-/* Input    : card_wavein - pointer to card wavein object                   */
-/*            wave_in  - open handle which is the pointer to the            */
-/*                          specified channel object                        */
-/*                                                                          */
-/* About    : Close wave device.                                            */
-/*            1. deallocate transfer buffer, for playback,                  */
-/*               free emu addx space.                                       */
-/*            2. free voice channels.                                       */
-/*            3. uninstall wave IRQ handler.                                */
-/*            4. remove wave instance from channel object list.             */
-/****************************************************************************/
-int sblive_waveinClose(struct sblive_hw *sb_hw, struct wave_in *wave_in)
-{
-	struct sblive_wavein *card_wavein= sb_hw->card_wavein;
-	struct wave_in *tmp;
-	u32 dummy;
-
-	/* FIXME: Do we need spinlocks in here? */
-
-	if (wave_in->state != CARDWAVE_STATE_STOPPED)
-		sblive_waveinStop(sb_hw, wave_in, &dummy);
-
-	tmp = card_wavein->wave_inlist;
-	while (tmp)
-	{
-		if (tmp == wave_in)
-		{
-			if (sblive_emuDeallocRecBuffer(wave_in) != CTSTATUS_SUCCESS)
-			{
-				DPF(2, "Failed to deallocate recbuffer\n");
-			}
-
-			wave_in->status |= FLAGS_AVAILABLE;
-			wave_in->state = CARDWAVE_STATE_STOPPED;
-			wave_in->synchstart = FALSE;
-
-			kfree((void *) wave_in->rec_ptr);
-
-			osListRemove((struct sblive_list **) & card_wavein->wave_inlist, (struct sblive_list *) wave_in);
-
-			/* Free channel object which is allocated in sblive_waveOpen(). */
-			kfree((void *) wave_in);
 
-			break;
-		}
-
-		tmp = (struct wave_in *) tmp->next;
-	}
+		if ((wave_fmt->bitsperchannel != 16) && (wave_fmt->bitsperchannel != 8))
+			wave_fmt->bitsperchannel = 16;
 
-	return CTSTATUS_SUCCESS;
-}
+		break;
 
+	case WAVERECORD_MIC:
+		wave_fmt->channels = 1;
+		wave_fmt->samplingrate = 0x1F40;
+		wave_fmt->bitsperchannel = 8;
+		break;
 
-/****************************************************************************/
-/* Function : sblive_emuGetRecBuffer                                        */
-/*                                                                          */
-/* Input    : card_wavein - pointer to card wavein object                   */
-/*            wave_in - pointer to the specified wavein instance            */
-/*            size - pointer to the size requested                          */
-/*                                                                          */
-/* Output   : size - pointer to the size allocated                          */
-/*            buffer - pointer to the buffer pointer allocated              */
-/*                                                                          */
-/* About    : alloc record buffer.                                          */
-/****************************************************************************/
-int sblive_emuGetRecBuffer(struct sblive_wavein *card_wavein, struct wave_in *wave_in, u32 *size, u8 **buffer)
-{
-	DPF(2, "CARDWAVE : GetBuffer\n");
-
-	if (!size || !buffer)
-		return CTSTATUS_INVALIDPARAM;
-
-	if (*size < wave_in->callbacksize)
-	{
-		*size = wave_in->callbacksize;
-		return CTSTATUS_INVALIDVALUE;
-	}
+	case WAVERECORD_FX:
+		wave_fmt->channels = 2;
+		wave_fmt->samplingrate = 0xBB80;
+		wave_fmt->bitsperchannel = 16;
+		break;
 
-	/* Allocate buffer here */
-	if (sblive_emuAllocRecBuffer(wave_in, size, buffer) != CTSTATUS_SUCCESS)
-	{
-		DPF(2, "CARDWAVE: allocate buffer fail.");
-		return CTSTATUS_ERROR;
+	default:
+		break;
 	}
-
-	/* recbufsize contains actual record buffer size */
-	*size = wave_in->rec_ptr->recbufsize;
 
-	wave_in->rec_ptr->recbuffer = *buffer;
-	wave_in->rec_ptr->recpos = 0;
-
-	return CTSTATUS_SUCCESS;
+	return;
 }
-
 
-/****************************************************************************/
-/* Function : sblive_emuAllocRecBuffer                                      */
-/*                                                                          */
-/* Input    : card_wavein - pointer to card wavein object                   */
-/*            size - pointer to the size requested                          */
-/*                                                                          */
-/* Output   : size - pointer to the size returned                           */
-/*            buffer - pointer to the buffer pointer allocated              */
-/*                                                                          */
-/* About    : allocate buffer for wave transfer.                            */
-/*            recording: a) allocate page-aligned, continous PC memory      */
-/*                          for recording buffer.                           */
-/*                       b) determine start, end, startloop and             */
-/*                          endloop.                                        */
-/****************************************************************************/
-int sblive_emuAllocRecBuffer(struct wave_in *wave_in, u32 *bufsize, u8 **buffer)
+static int alloc_recbuffer(struct wave_in *wave_in, u32 * bufsize, u8 ** buffer)
 {
-	int status;
-	u32 numpages, reqsize;
+	u32 reqsize;
 	int i, j;
 	u32 size[4];
 
 	/* NOTE: record buffer size only can be certain sizes.  If the requested
 	 * size is not a nice size, use the smaller nearest size. The minimum size is 1k. */
-	if (!wave_in->rec_ptr->is16bit)
+	if (!wave_in->rec_ptr->is_16bit)
 		*bufsize <<= 1;
 
-	if (*bufsize >= 0x10000)
-	{
+	if (*bufsize >= 0x10000) {
 		*bufsize = reqsize = 0x10000;
-		wave_in->rec_ptr->bufsizereg = 31;
-	} else
-	{
+		wave_in->rec_ptr->bufsize = 31;
+	} else {
 		reqsize = 0;
 		size[0] = 384;
 		size[1] = 448;
@@ -384,497 +108,365 @@
 
 		for (i = 0; i < 8; i++)
 			for (j = 0; j < 4; j++)
-				if (*bufsize >= size[j])
-				{
+				if (*bufsize >= size[j]) {
 					reqsize = size[j];
 					size[j] = size[j] * 2;
-					wave_in->rec_ptr->bufsizereg = i * 4 + j + 1;
+					wave_in->rec_ptr->bufsize = i * 4 + j + 1;
 				} else
 					goto exitloop;
-	exitloop:
-		if (reqsize == 0)
-		{
+	      exitloop:
+		if (reqsize == 0) {
 			reqsize = 384;
-			wave_in->rec_ptr->bufsizereg = 1;
+			wave_in->rec_ptr->bufsize = 1;
 		}
 
 		*bufsize = reqsize;
 	}
-
-	DPD(2, "bufsizereg: %x\n", wave_in->rec_ptr->bufsizereg);
-
-	if (wave_in->rec_ptr->is_stereo)
-	{
-		numpages = (reqsize / (PAGE_SIZE * 2)) * 2;
-		if (reqsize % (PAGE_SIZE * 2))
-			numpages += 2;
-	} else
-	{
-		numpages = reqsize / PAGE_SIZE;
-		if (reqsize % PAGE_SIZE)
-			numpages += 1;
-	}
 
-	reqsize = numpages * PAGE_SIZE;
+	DPD(2, "bufsizereg: %x\n", wave_in->rec_ptr->bufsize);
 
 	/* Recording buffer must be continuous and page-aligned */
-	status = osAllocMemPhysical(reqsize, &wave_in->memhandle);
-
-	if (status != CTSTATUS_SUCCESS)
-		return CTSTATUS_NOMEMORY;
-
-	wave_in->rec_ptr->recbuffer = (u8 *) wave_in->memhandle->virtaddx;
-	wave_in->rec_ptr->physaddx = wave_in->memhandle->physaddx;
-	wave_in->rec_ptr->recbufsize = *bufsize;
+	if ((wave_in->memhandle = emu10k1_alloc_memphysical(reqsize)) == NULL)
+		return CTSTATUS_ERROR;
 
-	DPD(2, "recbufsize: %x\n", wave_in->rec_ptr->recbufsize);
+	DPD(2, "recbufsize: %x\n", *bufsize);
 
 	*buffer = (u8 *) wave_in->memhandle->virtaddx;
 
 	return CTSTATUS_SUCCESS;
 }
-
 
-/****************************************************************************/
-/* Function : sblive_emuDeallocRecBuffer                                    */
-/*                                                                          */
-/* Input    : card_wavein - pointer to card wavein object                   */
-/*                                                                          */
-/* About    : deallocate transfer buffer                                    */
-/*            1. for playback, free emu address space.                      */
-/*            2. free PC memory allocated for transfer buffer.              */
-/*            3. clear VioceParam.                                          */
-/****************************************************************************/
-int sblive_emuDeallocRecBuffer(struct wave_in *wave_in)
+static int get_recbuffer(struct emu10k1_card *card, struct wave_in *wave_in, u32 * size)
 {
-	if (wave_in->memhandle == NULL)
-		return CTSTATUS_ERROR;
+	u8 *buffer;
 
-	osFreeMemPhysical(&wave_in->memhandle);
+	wave_in->rec_ptr->card = card;
+	wave_in->rec_ptr->recpos = 0;
+	wave_in->rec_ptr->samplingrate = wave_in->wave_fmt.samplingrate;
+	wave_in->rec_ptr->is_stereo = (wave_in->wave_fmt.channels == 2) ? 1 : 0;
+	wave_in->rec_ptr->is_16bit = (wave_in->wave_fmt.bitsperchannel == 16) ? 1 : 0;
 
-	if (wave_in->emu_voice != NULL)
-	{
-		struct voice_param *left = &wave_in->emu_voice->voice_params;
-		struct voice_param *right = &wave_in->emu_voice->linked_voice->voice_params;
-
-		/* Clear VoiceParam */
-		left->start = 0;
-		left->startloop = 0;
-		left->end = 0;
-		left->endloop = 0;
-
-		if (wave_in->wave_fmt.channels == 2)
-		{
-			right->start = 0;
-			right->startloop = 0;
-			right->end = 0;
-			right->endloop = 0;
-		}
+	/* Allocate buffer here */
+	if (alloc_recbuffer(wave_in, size, &buffer) != CTSTATUS_SUCCESS) {
+		ERROR();
+		return CTSTATUS_ERROR;
 	}
 
+	/* recbufsize contains actual record buffer size          */
+	/* for 8 bit samples the size is twice the requested      */
+	/* value since we only make use of one in every two bytes */
+	wave_in->rec_ptr->recbufsize = *size;
+	wave_in->rec_ptr->recbuffer = buffer;
+	wave_in->rec_ptr->busaddx = wave_in->memhandle->busaddx;
+
 	return CTSTATUS_SUCCESS;
 }
-
 
-/****************************************************************************/
-/* Function : initRecordObject                                              */
-/*                                                                          */
-/* Input    : card_wavein - pointer to card wavein object                   */
-/*                                                                          */
-/* About    : init recording object                                         */
-/****************************************************************************/
-/* FIXME: This should be a macro [jtaylor] */
-void initRecordObject(struct sblive_hw *sb_hw, struct wave_in *wave_in)
+static void dealloc_recbuffer(struct wave_in *wave_in)
 {
-	wave_in->rec_ptr->reserved = NULL;
-	wave_in->rec_ptr->sb_hw = sb_hw;
-	wave_in->rec_ptr->recpos = 0;
-	wave_in->rec_ptr->recbufsize = 0;
-	wave_in->rec_ptr->recbuffer = NULL;
-	wave_in->rec_ptr->physaddx = 0;
-	wave_in->rec_ptr->samplingrate = wave_in->wave_fmt.samplingrate;
-	wave_in->rec_ptr->is_stereo = (wave_in->wave_fmt.channels == 2) ? 1 : 0;
-	wave_in->rec_ptr->is16bit = (wave_in->wave_fmt.bitspersample == 16) ? 1 : 0;
-	wave_in->rec_ptr->fSetRecSrc = FALSE;
-	wave_in->rec_ptr->prevadcidx = 0;
-	wave_in->rec_ptr->pong = FALSE;
+	emu10k1_free_memphysical(wave_in->memhandle);
+	return;
 }
-
 
-/****************************************************************************/
-/* Function : sblive_waveinStart                                            */
-/*                                                                          */
-/* Input    : card_wavein - pointer to card wavein object                   */
-/*            wave_in - pointer to the specified wavein instance            */
-/*                                                                          */
-/* About    : start wave in transfer.                                       */
-/*            recording: a) setup voices.                                   */
-/*                       b) set recording source.(CCCA_CC, ADCCR)           */
-/*                       c) enable IRQ.                                     */
-/*                       d) start recording.                                */
-/*                       e) start CA (for get position).                    */
-/****************************************************************************/
-int sblive_waveinStart(struct sblive_wavedevice *wave_dev)
+int emu10k1_wavein_open(struct emu10k1_wavedevice *wave_dev)
 {
-	struct sblive_hw *sb_hw = wave_dev->sb_hw;
-	struct wave_in *wave_in = wave_dev->wiinst->wave_in;
+	struct emu10k1_card *card = wave_dev->card;
+	struct wiinst *wiinst = wave_dev->wiinst;
+	struct wave_in *wave_in;
+	struct wave_in **wave_in_tmp = NULL;
+	u32 buffsize, bytespersec, delay;
+	unsigned long flags;
 
-	/* If already started, return success */
-	if (wave_in->state == CARDWAVE_STATE_STARTED)
-		return CTSTATUS_SUCCESS;
+	DPF(2, "emu10k1_wavein_open()\n");
 
-	/* Recording */
-	if (recmgrInit(wave_in->rec_ptr) != CTSTATUS_SUCCESS)
+	if ((wave_in = (struct wave_in *) kmalloc(sizeof(struct wave_in), GFP_KERNEL)) == NULL) {
+		ERROR();
 		return CTSTATUS_ERROR;
+	}
 
-	/* If recording source is not set yet, use default: AC97 ADC */
-	if (!wave_in->rec_ptr->fSetRecSrc)
-	{
-		if (recmgrSetControl(wave_in->rec_ptr, WAVERECORD_AC97, 0) != CTSTATUS_SUCCESS)
-			return CTSTATUS_SUCCESS;
-		wave_in->rec_ptr->fSetRecSrc = TRUE;
-	}
-
-	wave_in->task = (struct tq_struct *) kmalloc(sizeof(struct tq_struct), GFP_KERNEL);
-	if (wave_in->task == NULL)
-	{
-		DPF(2, "task alloc\n");
-		return CTSTATUS_NOMEMORY;
-	}
-
-	DPD(3, "kmalloc: [%p]\n", wave_in->task);
-	wave_in->task->next = NULL;
-	wave_in->task->sync = 0;
-	wave_in->task->routine = waveInCallbackFn;
-	wave_in->task->data = wave_dev;
+	wave_in->state = CARDWAVE_STATE_STOPPED;
+	wave_in->wave_fmt = wiinst->wave_fmt;
+	wave_in->memhandle = NULL;
+	wave_in->timer = NULL;
+
+	switch (wiinst->recsrc) {
+	case WAVERECORD_AC97:
+		wave_in_tmp = &card->wavein->ac97;
+		break;
+	case WAVERECORD_MIC:
+		wave_in_tmp = &card->wavein->mic;
+		break;
+	case WAVERECORD_FX:
+		wave_in_tmp = &card->wavein->fx;
+		break;
+	default:
+		break;
+	}
 
-	if (sblive_irqmgrEnableIrq(sb_hw, INTE_ADCBUFENABLE) != CTSTATUS_SUCCESS)
+	spin_lock_irqsave(&card->lock, flags);
+	if (*wave_in_tmp != NULL) {
+		spin_unlock_irqrestore(&card->lock, flags);
+		kfree(wave_in);
 		return CTSTATUS_ERROR;
+	}
 
-	/* Actual start */
-	if (!wave_in->synchstart)
-	{
-		/* Recording */
-		if (recmgrStartRecord(wave_in->rec_ptr) != CTSTATUS_SUCCESS)
-			return CTSTATUS_ERROR;
-		wave_in->rec_ptr->prevadcidx = recmgrGetRecIdx(wave_in->rec_ptr->sb_hw);
+	*wave_in_tmp = wave_in;
+	spin_unlock_irqrestore(&card->lock, flags);
+
+	wiinst->wave_in = wave_in;
+
+	if ((wave_in->rec_ptr = (struct record *) kmalloc(sizeof(struct record), GFP_KERNEL)) == NULL) {
+		ERROR();
+		emu10k1_wavein_close(wave_dev);
+		return CTSTATUS_ERROR;
 	}
 
-	wave_in->state = CARDWAVE_STATE_STARTED;
-	wave_in->setpos = FALSE;
+	buffsize = wiinst->fragment_size * wiinst->numfrags;
+
+	if (get_recbuffer(card, wave_in, &buffsize) != CTSTATUS_SUCCESS) {
+		ERROR();
+		emu10k1_wavein_close(wave_dev);
+		return CTSTATUS_ERROR;
+	}
+
+	wiinst->fragment_size = buffsize / wiinst->numfrags;
+
+	/* This callback size returned is the size in the play buffer.
+	 * For 8-bit samples, callbacksize of user buffer should be
+	 * half of the callbacksize in play buffer. */
+	if (wave_in->wave_fmt.bitsperchannel == 8)
+		wiinst->fragment_size >>= 1;
+
+	wave_in->callbacksize = wiinst->fragment_size;
+
+	emu10k1_set_record_src(wave_in->rec_ptr, wiinst->recsrc);
+
+	bytespersec = wave_in->wave_fmt.channels * (wave_in->wave_fmt.bitsperchannel >> 3) * (wave_in->wave_fmt.samplingrate);
+	delay = (48000 * wave_in->callbacksize) / bytespersec;
 
-	DPF(2, "sblive_wave Started.\n");
+	if ((wave_in->timer = emu10k1_timer_install(card, emu10k1_wavein_bh, (unsigned long) wave_dev, delay / 2)) == NULL) {
+		ERROR();
+		emu10k1_wavein_close(wave_dev);
+		return CTSTATUS_ERROR;
+	}
 
 	return CTSTATUS_SUCCESS;
 }
 
-
-/****************************************************************************/
-/* Function : sblive_waveinStop                                             */
-/*                                                                          */
-/* Input    : card_wavein - pointer to card wavein object                   */
-/*            wave_in - pointer to the specified wavein instance            */
-/*            pending - for later use                                       */
-/*                                                                          */
-/* About    : stop wave transfer, disable IRQ.                              */
-/****************************************************************************/
-int sblive_waveinStop(struct sblive_hw *sb_hw, struct wave_in *wave_in, u32 *pending)
+void emu10k1_wavein_close(struct emu10k1_wavedevice *wave_dev)
 {
-	if (wave_in->emu_voice != NULL)
-		if (sblive_voiceStop(wave_in->emu_voice) != CTSTATUS_SUCCESS)
-			return CTSTATUS_ERROR;
+	struct emu10k1_card *card = wave_dev->card;
+	struct wave_in *wave_in = wave_dev->wiinst->wave_in;
+	unsigned long flags;
 
-	/* Recording */
-	if (recmgrStopRecord(wave_in->rec_ptr) != CTSTATUS_SUCCESS)
-		return CTSTATUS_ERROR;
-	if (sblive_irqmgrDisableIrq(sb_hw, INTE_ADCBUFENABLE) != CTSTATUS_SUCCESS)
-		return CTSTATUS_ERROR;
+	if (wave_in->state != CARDWAVE_STATE_STOPPED)
+		emu10k1_wavein_stop(wave_dev);
 
-	if (wave_in->emu_voice != NULL)
-	{
-		struct voice_param *left = &wave_in->emu_voice->voice_params;
+	if (wave_in->timer != NULL)
+		emu10k1_timer_uninstall(card, wave_in->timer);
 
-		left->startloop = left->start;
+	if (wave_in->memhandle != NULL)
+		dealloc_recbuffer(wave_in);
 
-		if (wave_in->rec_ptr->is_stereo)
-		{
-			struct voice_param *right = &wave_in->emu_voice->linked_voice->voice_params;
+	if (wave_in->rec_ptr != NULL)
+		kfree(wave_in->rec_ptr);
 
-			right->startloop = right->start;
-		}
+	spin_lock_irqsave(&card->lock, flags);
+	switch (wave_dev->wiinst->recsrc) {
+	case WAVERECORD_AC97:
+		card->wavein->ac97 = NULL;
+		break;
+	case WAVERECORD_MIC:
+		card->wavein->mic = NULL;
+		break;
+	case WAVERECORD_FX:
+		card->wavein->fx = NULL;
+		break;
+	default:
+		break;
 	}
+	spin_unlock_irqrestore(&card->lock, flags);
 
-	kfree(wave_in->task);
+	kfree(wave_in);
+	wave_dev->wiinst->wave_in = NULL;
 
-	DPD(3, "kfree: [%p]\n", wave_in->task);
+	return;
+}
 
-	wave_in->rec_ptr->fSetRecSrc = FALSE;
-	wave_in->rec_ptr->recpos = 0;
-	wave_in->rec_ptr->pong = FALSE;
-	wave_in->state = CARDWAVE_STATE_STOPPED;
-	wave_in->process_id = 0;
+void emu10k1_wavein_start(struct emu10k1_wavedevice *wave_dev)
+{
+	struct wave_in *wave_in = wave_dev->wiinst->wave_in;
 
-	return CTSTATUS_SUCCESS;
-}
+	DPF(2, "emu10k1_wavein_start()\n");
 
+	if (wave_in->state == CARDWAVE_STATE_STARTED)
+		return;
 
-/****************************************************************************/
-/* Function : sblive_waveinGetXferSize                                      */
-/*                                                                          */
-/* Input    : card_wavein - pointer to card wavein object                   */
-/*            wave_in - pointer to the specified wavein instance            */
-/*                                                                          */
-/* Output   : size - pointer to the transfer size                           */
-/*            pending - pointer to the size to be transfered                */
-/*                                                                          */
-/* About    : get the size of data in bytes that the specified wave device  */
-/*            can process at the time of this function is called.           */
-/*                                                                          */
-/* Note     : this transfer size returned is referring to user buffer.      */
-/****************************************************************************/
-int sblive_waveinGetXferSize(struct sblive_wavein *card_wavein,
-			     struct wave_in *wave_in, u32 *size, u32 *pending)
-{
-	struct record *rec_ptr = wave_in->rec_ptr;
-	u32 curpos;
+	emu10k1_start_record(wave_in->rec_ptr);
+	wave_in->state = CARDWAVE_STATE_STARTED;
 
-	/* Get position of current address, this is in no. of bytes in play buffer */
-	if (sblive_waveinGetControl(card_wavein, wave_in, WAVECURPOS, &curpos)
-	    != CTSTATUS_SUCCESS)
-	{
-		DPF(2, "sblive_waveinGetControl() failed!\n");
-		return CTSTATUS_ERROR;
-	}
+	emu10k1_timer_enable(wave_dev->card, wave_in->timer);
 
-	curpos *= (rec_ptr->is_stereo + 1);
+	return;
+}
 
-	/* Recpos is the actual position in user buffer and play buffer */
-	if (curpos >= rec_ptr->recpos)
-		*size = curpos - rec_ptr->recpos;
-	else
-		*size = rec_ptr->recbufsize - (rec_ptr->recpos - curpos);
-
-	/* FIXME: Handle this at runtime [jtaylor] */
-#if defined(EMUA0)
-	/* Only emu8010 A0 silicon needs this workaround,
-	 * A1 silicon, take out this part.
-	 */
-	if (*size > 32)
-		*size -= 32;
-#endif
+void emu10k1_wavein_stop(struct emu10k1_wavedevice *wave_dev)
+{
+	struct wave_in *wave_in = wave_dev->wiinst->wave_in;
 
-	if (!rec_ptr->is16bit)
-		*size >>= 1;
+	DPF(2, "emu10k1_wavein_stop()\n");
 
-	*pending = rec_ptr->recbufsize - *size;
+	emu10k1_stop_record(wave_in->rec_ptr);
+	emu10k1_timer_disable(wave_dev->card, wave_in->timer);
 
-	return CTSTATUS_SUCCESS;
-}
+	wave_in->rec_ptr->recpos = 0;
+	wave_in->state = CARDWAVE_STATE_STOPPED;
 
+	return;
+}
 
-/****************************************************************************/
-/* Function : sblive_waveinXferData                                         */
-/*                                                                          */
-/* Input    : card_wavein - pointer to card wavein object                   */
-/*            wave_in - pointer to the specified wavein instance            */
-/*            Data - pointer to the data to be transfered                   */
-/*            size - data size to be transfered(size in user buffer,        */
-/*                      for 8-bit sample, this is different from play       */
-/*                      buffer.                                             */
-/*                                                                          */
-/* Output   : size - data size transfered                                   */
-/*                                                                          */
-/* About    : transfer the data to/from the wave device.                    */
-/****************************************************************************/
-int sblive_waveinXferData(struct sblive_wavein *card_wavein, struct wave_in *wave_in, u8 *data, u32 *size)
+int emu10k1_wavein_setformat(struct emu10k1_wavedevice *wave_dev)
 {
-	struct record *rec_ptr = wave_in->rec_ptr;
-	u32 sizeToCopy, sizeToCopyNow, sizeCopied;
+	struct emu10k1_card *card = wave_dev->card;
+	struct wiinst *wiinst = wave_dev->wiinst;
+	struct wave_in *wave_in = wiinst->wave_in;
+	u32 bytespersec, delay;
 
-	if (!data || !size)
-		return CTSTATUS_INVALIDPARAM;
+	DPF(2, "emu10k1_wavein_setformat()\n");
 
-	DPD(2, "Size request to xfer = %x\n", *size);
+	query_format(wiinst->recsrc, &wiinst->wave_fmt);
 
-	sizeToCopy = min(rec_ptr->recbufsize * (rec_ptr->is16bit + 1) / 2, *size);
-	sizeCopied = 0;
+	if (!wave_in)
+		return CTSTATUS_SUCCESS;
 
-	if (!sizeToCopy)
-	{
-		*size = 0;
+	if (wave_in->state == CARDWAVE_STATE_STARTED) {
+		wiinst->wave_fmt = wave_in->wave_fmt;
 		return CTSTATUS_SUCCESS;
 	}
 
-	while (sizeCopied < sizeToCopy)
-	{
-		sizeToCopyNow = sizeToCopy - sizeCopied;
-		sizeToCopyNow = min(sizeToCopyNow,(rec_ptr->recbufsize - rec_ptr->recpos) * (rec_ptr->is16bit + 1) / 2);
+	if ((wave_in->wave_fmt.samplingrate != wiinst->wave_fmt.samplingrate)
+	    || (wave_in->wave_fmt.bitsperchannel != wiinst->wave_fmt.bitsperchannel)
+	    || (wave_in->wave_fmt.channels != wiinst->wave_fmt.channels)) {
 
-		if (rec_ptr->is16bit)
-			copy_to_user(&data[sizeCopied], &rec_ptr->recbuffer[rec_ptr->recpos], sizeToCopyNow);
-		else
-		{
-			u8 *DstBuf = &data[sizeCopied];
-			u16 *SrcBuf = (u16 *) & rec_ptr->recbuffer[rec_ptr->recpos];
-			u32 count = sizeToCopyNow;
-
-			while (count--)
-			{
-				long lSample;
-				u8 bSample;
-
-				lSample = (short) *SrcBuf++;
-#ifdef RECTEST
-				DPD(2, " lSample -> %x", lSample);
-#endif
-				lSample += 128;
-				if (lSample > 32767)
-					lSample = 32767;
-				bSample = (u8)((lSample >> 8) ^ 0x80);
-				copy_to_user(DstBuf, &bSample, 1);
-				DstBuf++;
-			}
-		}
+		emu10k1_timer_uninstall(card, wave_in->timer);
 
-		rec_ptr->recpos += sizeToCopyNow * 2 / (rec_ptr->is16bit + 1);
-		rec_ptr->recpos %= rec_ptr->recbufsize;
-		sizeCopied += sizeToCopyNow;
-	}
+		wave_in->wave_fmt = wiinst->wave_fmt;
 
-	*size = sizeToCopy;
+		bytespersec = wave_in->wave_fmt.channels * (wave_in->wave_fmt.bitsperchannel >> 3) * (wave_in->wave_fmt.samplingrate);
+		delay = (48000 * wave_in->callbacksize) / bytespersec;
 
-	DPD(2, "Size copied = %x\n", *size);
+		if ((wave_in->timer = emu10k1_timer_install(card, emu10k1_wavein_bh, (unsigned long) wave_dev, delay / 2)) == NULL) {
+			ERROR();
+			emu10k1_wavein_close(wave_dev);
+			return CTSTATUS_ERROR;
+		}
+	}
 
 	return CTSTATUS_SUCCESS;
 }
 
-/****************************************************************************/
-/* Function : sblive_waveinGetControl                                       */
-/*                                                                          */
-/* Input    : card_wavein - pointer to card wavein object                   */
-/*            wave_in - pointer to the specified wavein instance            */
-/*            ctrlid - control type                                         */
-/*                                                                          */
-/* Output   : value - pointer to the control value                          */
-/*                                                                          */
-/* About    : get the specified control value of the wave device.           */
-/****************************************************************************/
-int sblive_waveinGetControl(struct sblive_wavein *card_wavein, struct wave_in *wave_in, u32 ctrlid, u32 *value)
-{
-	switch (ctrlid)
-	{
-	case WAVEOBJVOLUME:
-	case WAVEOBJREVERB:
-	case WAVEOBJCHORUS:
-		return CTSTATUS_NOTSUPPORTED;
-
-	case WAVEQUERYACTIVEINST:
-		if (card_wavein->wave_inlist != NULL)
-			return CTSTATUS_SUCCESS;
-		else
-			return CTSTATUS_ERROR;
+void emu10k1_wavein_getxfersize(struct wave_in *wave_in, u32 * size, u32 * curpos)
+{
+	struct record *rec_ptr = wave_in->rec_ptr;
 
-	default:
-		break;
+	/* Get position of current address, this is in no. of bytes in play buffer */
+	emu10k1_wavein_getcontrol(wave_in, WAVECURPOS, curpos);
+
+	*size = *curpos - rec_ptr->recpos;
+
+	/* Recpos is the actual position in user buffer and play buffer */
+	if (*curpos < rec_ptr->recpos)
+		*size += rec_ptr->recbufsize;
+
+	if (!rec_ptr->is_16bit)
+		*size >>= 1;
+
+	return;
+}
+
+static void copy_s16_to_u8(u8 * dstbuf, s16 * srcbuf, u32 size)
+{
+	u16 sample;
+	u8 byte;
+
+	while (size--) {
+		sample = (*srcbuf) + 32767;
+		byte = (u8) (sample >> 8);
+		copy_to_user(dstbuf, &byte, 1);
+		dstbuf++;
+		srcbuf++;
 	}
+}
 
-	if (wave_in == NULL)
-		return CTSTATUS_ERROR;
+/* transfer the data from the wave device.                    */
+void emu10k1_wavein_xferdata(struct wiinst *wiinst, u8 * data, u32 * size)
+{
+	struct wave_in *wave_in = wiinst->wave_in;
+	struct record *rec_ptr = wave_in->rec_ptr;
+	u32 sizetocopy, sizetocopy_now, start;
+	unsigned long flags;
 
-	switch (ctrlid)
-	{
-	case WAVEINSTANCEVOLUME:
-	case WAVEINSTANCEREVERB:
-	case WAVEINSTANCECHORUS:
-		return CTSTATUS_NOTSUPPORTED;
+	sizetocopy = min(rec_ptr->recbufsize * (rec_ptr->is_16bit + 1) / 2, *size);
+	*size = sizetocopy;
 
-	case WAVECURPOS:
-		/* There is no actual start yet */
-		if (wave_in->state == CARDWAVE_STATE_STOPPED)
-		{
-			*value = 0;
-			break;
-		}
+	if (!sizetocopy)
+		return;
 
-		if (wave_in->emu_voice == NULL)
-		{
-			/* No voices used for recording, get position from wall clock */
-			if (recmgrGetPos(wave_in->rec_ptr, value) != CTSTATUS_SUCCESS)
-			{
-				DPF(2, "recmgrGetPos() failed!\n");
-				return CTSTATUS_ERROR;
-			}
+	spin_lock_irqsave(&wiinst->lock, flags);
 
-			*value /= (wave_in->rec_ptr->is_stereo + 1);
-		}
-		else
-		{
-			if (sblive_voiceGetControl(wave_in->emu_voice, CCCA_CURRADDR, value) != CTSTATUS_SUCCESS)
-				return CTSTATUS_ERROR;
-
-			/* There is no actual start yet */
-			if (wave_in->state == CARDWAVE_STATE_STOPPED)
-				*value = 0;
-			else
-			{
-				*value -= wave_in->emu_voice->voice_params.start;
-				*value <<= wave_in->rec_ptr->is16bit;
-			}
-		}
+	sizetocopy_now = (rec_ptr->recbufsize - rec_ptr->recpos) * (rec_ptr->is_16bit + 1) / 2;
 
-		break;
+	start = rec_ptr->recpos;
 
-	case WAVESTARTLOOP:
-		if (sblive_voiceGetControl(wave_in->emu_voice, PSST_LOOPSTARTADDR, value) != CTSTATUS_SUCCESS)
-			return CTSTATUS_ERROR;
+	if (sizetocopy > sizetocopy_now) {
+		sizetocopy -= sizetocopy_now;
+		rec_ptr->recpos = sizetocopy * 2 / (rec_ptr->is_16bit + 1);
 
-		*value -= wave_in->emu_voice->voice_params.start;
-		*value <<= wave_in->rec_ptr->is16bit;
-		break;
+		spin_unlock_irqrestore(&wiinst->lock, flags);
 
-	case WAVEENDLOOP:
-		if (sblive_voiceGetControl(wave_in->emu_voice, DSL_LOOPENDADDR, value) != CTSTATUS_SUCCESS)
-			return CTSTATUS_ERROR;
-		*value -= wave_in->emu_voice->voice_params.start;
-		*value <<= wave_in->rec_ptr->is16bit;
-		break;
+		if (rec_ptr->is_16bit) {
+			copy_to_user(data, rec_ptr->recbuffer + start, sizetocopy_now);
+			copy_to_user(data + sizetocopy_now, rec_ptr->recbuffer, sizetocopy);
+		} else {
+			copy_s16_to_u8(data, (s16 *) (rec_ptr->recbuffer + start), sizetocopy_now);
+			copy_s16_to_u8(data + sizetocopy_now, (s16 *) rec_ptr->recbuffer, sizetocopy);
+		}
+	} else {
+		if (sizetocopy == sizetocopy_now)
+			rec_ptr->recpos = 0;
+		else
+			rec_ptr->recpos += sizetocopy * 2 / (rec_ptr->is_16bit + 1);
 
-	case WAVEWRITEPOINTER:
-		/* Get write pointer for a particular wave instance */
-		*value = wave_in->rec_ptr->recpos;
-		break;
+		spin_unlock_irqrestore(&wiinst->lock, flags);
 
-	default:
-		DPF(2, "BUG: Default case\n");
-		return CTSTATUS_ERROR;
+		if (rec_ptr->is_16bit)
+			copy_to_user(data, rec_ptr->recbuffer + start, sizetocopy);
+		else
+			copy_s16_to_u8(data, (s16 *) (rec_ptr->recbuffer + start), sizetocopy);
 	}
 
-	return CTSTATUS_SUCCESS;
+	return;
 }
 
+/* get the specified control value of the wave device. */
 
-/****************************************************************************/
-/* Function : sblive_waveinIrqCallback                                      */
-/*                                                                          */
-/* Input    : event - event that cause the callback                         */
-/*            refdata - reference data for this callback                    */
-/*            param - parameter used for this callback                      */
-/*                                                                          */
-/* About    : wave IRQ callback function.                                   */
-/****************************************************************************/
-int sblive_waveinIrqCallback(struct sblive_hw *sb_hw)
+int emu10k1_wavein_getcontrol(struct wave_in *wave_in, u32 ctrlid, u32 * value)
 {
-	struct wave_in *wave_in = sb_hw->card_wavein->wave_inlist;
-
-	if (wave_in->state == CARDWAVE_STATE_STOPPED)
-		return CTSTATUS_SUCCESS;
+	switch (ctrlid) {
+	case WAVECURPOS:
+		/* There is no actual start yet */
+		if (wave_in->state == CARDWAVE_STATE_STOPPED) {
+			*value = 0;
+		} else {
+			/* value is in byte units */
+			*value = sblive_readptr(wave_in->rec_ptr->card, wave_in->rec_ptr->bufidxreg, 0);
+		}
 
-	wave_in->rec_ptr->prevadcidx = recmgrGetRecIdx(wave_in->rec_ptr->sb_hw);
-	wave_in->rec_ptr->pong ^= 1;
+		break;
 
-	queue_task(wave_in->task, &tq_immediate);
-	mark_bh(IMMEDIATE_BH);
+	default:
+		return CTSTATUS_ERROR;
+	}
 
 	return CTSTATUS_SUCCESS;
 }
-
Index: oldkernel/linux/drivers/sound/emu10k1/cardwi.h
diff -u linux/drivers/sound/emu10k1/cardwi.h:1.1 linux/drivers/sound/emu10k1/cardwi.h:1.2
--- linux/drivers/sound/emu10k1/cardwi.h:1.1	Thu Jun  1 16:52:15 2000
+++ linux/drivers/sound/emu10k1/cardwi.h	Fri Jul  7 15:36:45 2000
@@ -35,19 +35,14 @@
 
 struct wave_in 
 {
-	struct wave_in *next;
-	u32 status;
+	struct list_head list;
+
 	u32 state;
-	int synchstart;
-	struct emu_voice *emu_voice;
 	struct record *rec_ptr;
 	struct memhandle *memhandle;
+	struct emu_timer *timer;
 	u32 callbacksize;
-	u32 process_id;		/* used for synchonize start */
-	int setpos;
-	u32 position;
 	struct wave_format wave_fmt;
-	struct tq_struct *task;
 };
 
 struct wiinst
@@ -60,50 +55,38 @@
 	wait_queue_head_t wait_queue;
 	int mapped;
 	u32 total_recorded;
-	u32 getiptr_blocks;
+	u32 blocks;
+	u32 curpos;
 	spinlock_t lock;
+	u8 recsrc;
+};
+
+struct emu10k1_wavein 
+{
+	struct wave_in *ac97;
+	struct wave_in *mic;
+	struct wave_in *fx;
+
+	u8 recsrc;
 };
 
-/* sblive_wave states */
-#define CARDWAVE_STATE_STOPPED     0x0001
-#define CARDWAVE_STATE_STARTED     0x0002
-#define CARDWAVE_STATE_SUSPEND     0x0004
-
-/* transfer buffer format */
-#define M8                        0x00
-#define M16                       0x01
-#define S8                        0x02
-#define S16                       0x03
 
-#define INTERPOLATION_BYTES       8
 #define WAVEIN_MAXBUFSIZE         65536
-#define WAVEIN_DEFAULTFRAGLEN     50
-#define WAVEIN_DEFAULTBUFLEN      1000
+#define WAVEIN_MINBUFSIZE	  368
 
-struct sblive_wavein 
-{
-	struct wave_caps caps;
-	u32 numrecordinst;
-	struct wave_in *wave_inlist;
-	u32 lineid;
-	u32 ctrlid;
-};
+#define WAVEIN_DEFAULTFRAGLEN     100 
+#define WAVEIN_DEFAULTBUFLEN      1000
 
+#define WAVEIN_MINFRAGSHIFT   	  8 
 
-int sblive_waveinInit(struct sblive_wavein *, u8 *);
-int sblive_waveinExit(struct sblive_wavein *);
-int sblive_waveinQueryFormat(struct sblive_wavein *, struct wave_format *, u32);
-int sblive_waveinOpen(struct sblive_hw *, struct wave_format *, u32 *, u32, struct wave_in **);
-int sblive_waveinClose(struct sblive_hw *, struct wave_in *);
-int sblive_waveinStart(struct sblive_wavedevice *);
-int sblive_waveinStop(struct sblive_hw *, struct wave_in *, u32 *);
-int sblive_waveinGetXferSize(struct sblive_wavein *, struct wave_in *, u32 *, u32 *);
-int sblive_waveinXferData(struct sblive_wavein *, struct wave_in *, u8 *, u32 *);
-int sblive_waveinGetControl(struct sblive_wavein *, struct wave_in *, u32, u32 *);
-int sblive_emuAllocRecBuffer(struct wave_in *, u32 *, u8 **);
-int sblive_emuGetRecBuffer(struct sblive_wavein *, struct wave_in *, u32 *, u8 **);
-int sblive_emuDeallocRecBuffer(struct wave_in *);
-void initRecordObject(struct sblive_hw *, struct wave_in *);
+int emu10k1_wavein_open(struct emu10k1_wavedevice *);
+void emu10k1_wavein_close(struct emu10k1_wavedevice *);
+void emu10k1_wavein_start(struct emu10k1_wavedevice *);
+void emu10k1_wavein_stop(struct emu10k1_wavedevice *);
+void emu10k1_wavein_getxfersize(struct wave_in *, u32 *, u32 *);
+void emu10k1_wavein_xferdata(struct wiinst *, u8 *, u32 *);
+int emu10k1_wavein_setformat(struct emu10k1_wavedevice *);
+int emu10k1_wavein_getcontrol(struct wave_in *, u32, u32 *);
 
 
 #endif /* _CARDWI_H */
Index: oldkernel/linux/drivers/sound/emu10k1/cardwo.c
diff -u linux/drivers/sound/emu10k1/cardwo.c:1.1 linux/drivers/sound/emu10k1/cardwo.c:1.2
--- linux/drivers/sound/emu10k1/cardwo.c:1.1	Thu Jun  1 16:52:15 2000
+++ linux/drivers/sound/emu10k1/cardwo.c	Fri Jul  7 15:36:45 2000
@@ -1,3 +1,4 @@
+
 /*
  **********************************************************************
  *     cardwo.c - PCM output HAL for emu10k1 driver
@@ -30,13 +31,12 @@
  */
 
 #include "hwaccess.h"
-#include "mycommon.h"
-#include "mmwave.h"
 #include "cardwo.h"
 #include "audio.h"
 
 /* Volume calcs */
-static int set_volume_instance(struct sblive_waveout * card_waveout, struct wave_out * wave_out, struct voice_param * left)
+
+static int set_volume_instance(struct emu10k1_waveout *card_waveout, struct wave_out *wave_out, struct voice_param *left)
 {
 	/* only applicable for playback */
 	u32 volL, volR, vol = 0;
@@ -44,8 +44,7 @@
 	volL = (wave_out->localvol & 0xffff);
 	volR = ((wave_out->localvol >> 16) & 0xffff);
 
-	if (wave_out->globalvolFactor)
-	{
+	if (wave_out->globalvolFactor) {
 		volL = ((u32) (((u16) card_waveout->globalvol & 0xffff) * (u16) volL)) / 0xffff;
 		volR = ((u32) (((u16) (card_waveout->globalvol >> 16) & 0xffff) * ((u16) volR))) / 0xffff;
 	}
@@ -53,23 +52,19 @@
 	/* BIG ASSUMPTION HERE THAT DEFAULT WAVE PAN/AUX IS 0xff/0xff */
 	/* New volume and pan */
 
-	if (volL == volR)
-	{
+	if (volL == volR) {
 		vol = volL;
-		left->unSends.tSends.pan_send = 0xff;
-		left->unSends.tSends.aux_send = 0xff;
-	} else
-	{
-		if (volL > volR)
-		{
+		left->send_c = 0xff;
+		left->send_b = 0xff;
+	} else {
+		if (volL > volR) {
 			vol = volL;
-			left->unSends.tSends.pan_send = 0xff;
-			left->unSends.tSends.aux_send = (char) ((volR * 255) / vol);
-		} else
-		{
+			left->send_c = 0xff;
+			left->send_b = (char) ((volR * 255) / vol);
+		} else {
 			vol = volR;
-			left->unSends.tSends.aux_send = 0xff;
-			left->unSends.tSends.pan_send = (char) ((volL * 255) / vol);
+			left->send_b = 0xff;
+			left->send_c = (char) ((volL * 255) / vol);
 		}
 	}
 
@@ -78,1635 +73,671 @@
 	return vol;
 }
 
-static void set_volume(struct sblive_waveout * card_waveout)
+static void query_format(struct wave_format *wave_fmt)
 {
-	struct wave_out * currinst = card_waveout->wave_outlist;
-	struct voice_cntlset setting[3];
+	if ((wave_fmt->channels != 1) && (wave_fmt->channels != 2))
+		wave_fmt->channels = 2;
 
-	while (currinst && currinst->emu_voice)
-	{
-		struct voice_param * left = &currinst->emu_voice->voice_params;
+	if (wave_fmt->samplingrate >= 0x2EE00)
+		wave_fmt->samplingrate = 0x2EE00;
 
-		/* This flag allows a wave instance to be unaffected by changes to global volume. */
+	if ((wave_fmt->bitsperchannel != 8) && (wave_fmt->bitsperchannel != 16))
+		wave_fmt->bitsperchannel = 16;
 
-		if (currinst->globalvolFactor)
-		{
-			u32 volL, volR, vol;
+	return;
+}
 
-			/* Calculate individual channel volumes based on obj and instance volume */
+static int alloc_xferbuffer(struct emu10k1_card *card, struct wave_out *wave_out, u32 * size, void ***buffer)
+{
+	u32 numpages, reqsize, pageindex, pagecount;
+	struct wave_xferbuf *wavexferbuf = wave_out->wavexferbuf;
+	unsigned long busaddx;
+	int i;
 
-			volL = ((u32) (((u16) card_waveout->globalvol & 0xffff) * ((u16) currinst->localvol & 0xffff))) / 0xffff;
-			volR = ((u32) (((u16) (card_waveout->globalvol >> 16) & 0xffff) * ((u16) (currinst->localvol >> 16) & 0xffff))) / 0xffff;
+	reqsize = *size;
+	numpages = reqsize / PAGE_SIZE;
 
-			/* BIG ASSUMPTION HERE THAT DEFAULT WAVE PAN/AUX IS 0xff/0xff */
-			/* New volume and pan */
-			if (volL == volR)
-			{
-				vol = volL;
-				left->unSends.tSends.pan_send = 0xff;
-				left->unSends.tSends.aux_send = 0xff;
-			} else
-			{
-				if (volL > volR)
-				{
-					vol = volL;
-					left->unSends.tSends.pan_send = 0xff;
-					left->unSends.tSends.aux_send = (char) ((volR * 255) / vol);
-				} else
-				{
-					vol = volR;
-					left->unSends.tSends.aux_send = 0xff;
-					left->unSends.tSends.pan_send = (char) ((volL * 255) / vol);
-				}
-			}
+	/* If size is not a multiple of PAGE_SIZE then we need to round up */
+	if (reqsize % PAGE_SIZE)
+		numpages += 1;
 
-			left->initial_attn = 0xff & sumVolumeToAttenuation(vol * 2);
+	DPD(2, "requested pages is: %d\n", numpages);
 
-			if (currinst->wavexferbuf->is_stereo && currinst->emu_voice->linked_voice)
-			{
-				struct voice_param * right = &currinst->emu_voice->linked_voice->voice_params;
+	wavexferbuf->numpages = numpages;
 
-				right->unSends.tSends.pan_send = 0; /* Left output of right channel is always zero */
-				right->unSends.tSends.aux_send = left->unSends.tSends.aux_send; /* Update right channel aux */
-				left->unSends.tSends.aux_send = 0; /* Zero out right output of left channel */
-				right->initial_attn = 0xff & sumVolumeToAttenuation(vol * 2); /* Update right channel attenuation */
-
-				setting[0].paramID = PSST_FXSENDAMOUNT_C;
-				setting[0].value = 0;
-				setting[1].paramID = PTRX_FXSENDAMOUNT_B;
-				setting[1].value = right->unSends.tSends.aux_send;
-				setting[2].paramID = IFATN_ATTENUATION;
-				setting[2].value = right->initial_attn;
+	/* Only for playback, request for emu address space */
+	/* Support non page-aligned buffer, don't need interpolation page */
 
-				sblive_voiceSetControl(currinst->emu_voice->linked_voice, setting, 3);
-			}
+	if ((wave_out->emupageindex = emu10k1_addxmgr_alloc(numpages * PAGE_SIZE, card)) < 0)
+		return CTSTATUS_ERROR;
+
+	if ((wave_out->pagetable = (void **) kmalloc(sizeof(void *) * numpages, GFP_KERNEL)) == NULL)
+		return CTSTATUS_ERROR;
 
-			setting[0].paramID = PSST_FXSENDAMOUNT_C;
-			setting[0].value = left->unSends.tSends.pan_send;
-			setting[1].paramID = PTRX_FXSENDAMOUNT_B;
-			setting[1].value = left->unSends.tSends.aux_send;
-			setting[2].paramID = IFATN_ATTENUATION;
-			setting[2].value = left->initial_attn;
-			sblive_voiceSetControl(currinst->emu_voice, setting, 3);
+	/* Fill in virtual memory table */
+	for (pagecount = 0; pagecount < numpages; pagecount++) {
+		if ((wave_out->pagetable[pagecount] = (void *) __get_free_page(GFP_KERNEL)) == NULL) {
+			wavexferbuf->numpages = pagecount;
+			return CTSTATUS_ERROR;
 		}
 
-		currinst = currinst->next;
-	}
-}
+		DPD(2, "Virtual Addx: %p\n", wave_out->pagetable[pagecount]);
 
+		for (i = 0; i < PAGE_SIZE / EMUPAGESIZE; i++) {
+			busaddx = virt_to_bus((u8 *) wave_out->pagetable[pagecount] + i * EMUPAGESIZE);
 
-/****************************************************************************/
-/* Function : sblive_waveVolumeControlFn                                    */
-/*                                                                          */
-/* About    : Callback function for volume control.                         */
-/****************************************************************************/
-int sblive_waveVolumeControlFn(u32 event, struct sblive_waveout * card_waveout, u32 left, u32 right)
-{
-	switch (event)
-	{
-	case 0:	/* Get */
-		*(u32 *)left = card_waveout->left;
-		*(u32 *)right = card_waveout->right;
-		break;
+			DPD(3, "Bus Addx: %lx\n", busaddx);
+
+			pageindex = wave_out->emupageindex + pagecount * PAGE_SIZE / EMUPAGESIZE + i;
 
-	case 1:	/* Set */
-		/*
-		 ** this is a general set volume affecting all wave instances.
-		 ** WODM_SETVOLUME should result in this controlId and affect
-		 ** the volume of all wave instances. Apps which can set the
-		 ** volume of individual wave instances should use
-		 ** WAVEINSTANCEVOLUME instead
-		 */
-		card_waveout->left = left;
-		card_waveout->right = right;
-
-		if (!card_waveout->mute)
-		{
-			card_waveout->globalvol = (left & 0xffff) | (right << 16);
-			set_volume(card_waveout);
+			((u32 *) card->virtualpagetable->virtaddx)[pageindex] = ((u32) busaddx * 2) | pageindex;
 		}
-		break;
 	}
 
-	return CTSTATUS_SUCCESS;
-}
-
-
-
-/****************************************************************************/
-/* Function : sblive_waveoutInit                                            */
-/*                                                                          */
-/* Input    : card_waveout - pointer to card wave out object structure      */
-/*            sb_hw - pointer to hardware object                            */
-/*                                                                          */
-/* Return   : CTSTATUS_SUCCESS  -- successful                               */
-/*            CTSTATUS_ERROR    -- failure                                  */
-/*                                                                          */
-/* About    : initialize card wave output device.                           */
-/****************************************************************************/
-/* FIXME: This should be a macro */
-int sblive_waveoutInit(struct sblive_waveout *card_waveout, u8 *carddesc)
-{
-	/* Init cardwave caps */
-	memset(card_waveout, 0, sizeof(struct sblive_waveout));
-	card_waveout->caps.product_id = MM_CREATIVE_WAVEOUT_PID;
-	card_waveout->caps.caps = CARDWAVE_OUT;
-	card_waveout->caps.caps |= CARDWAVE_ALLOW_DIRECTXFER;
-	card_waveout->caps.controls = CARDWAVE_CONTROL_VOLUME;
-	card_waveout->caps.maxchannels = 2;
-	card_waveout->caps.minrate = 100;
-	card_waveout->caps.maxrate = 100000;
-	strcpy(card_waveout->caps.wavedesc, carddesc);
-
-	card_waveout->numplaybackinst = 0;
-	card_waveout->maxnumplayinst = CARDWAVE_DEFAULT_MAXPLAYINST;
-	card_waveout->wave_outlist = NULL;
-
-	/* Init to invalid values */
-	card_waveout->lineid = 0xeeeeeeee;
-	card_waveout->ctrlid = 0xffffffff;
-
-	/* Assign default global volume, reverb, chorus */
-	card_waveout->globalvol = 0xFFFFFFFF;
-	card_waveout->left = 0xFFFF;
-	card_waveout->right = 0xFFFF;
-	card_waveout->mute = 0;
-	card_waveout->globalreverb = 0xFFFFFFFF;
-	card_waveout->globalchorus = 0xFFFFFFFF;
+	*buffer = wave_out->pagetable;
 
 	return CTSTATUS_SUCCESS;
 }
-
 
-/****************************************************************************/
-/* Function : sblive_waveoutExit                                            */
-/*                                                                          */
-/* Input    : card_waveout - pointer to card wave object structure          */
-/*                                                                          */
-/* Return   : CTSTATUS_SUCCESS  -- successful                               */
-/*            CTSTATUS_ERROR    -- failure                                  */
-/*                                                                          */
-/* About    : exit card wave operation.                                     */
-/****************************************************************************/
-int sblive_waveoutExit(struct sblive_waveout *card_waveout)
+static int get_xferbuffer(struct emu10k1_card *card, struct wave_out *wave_out, u32 * size)
 {
-	DPF(2, "sblive_waveoutExit()\n");
+	struct wave_xferbuf *wavexferbuf = wave_out->wavexferbuf;
+	void **buffer;
 
-	return CTSTATUS_SUCCESS;
-}
+	wavexferbuf->xferpos = 0;
+	wavexferbuf->silence_xferpos = 0;
+	wavexferbuf->stopposition = 0;
+	wavexferbuf->is_stereo = (wave_out->wave_fmt.channels == 2) ? 1 : 0;
+	wavexferbuf->is_16bit = (wave_out->wave_fmt.bitsperchannel == 16) ? 1 : 0;
+	wavexferbuf->bytespersample = (wavexferbuf->is_stereo + 1) * (wavexferbuf->is_16bit + 1);
 
+	if (alloc_xferbuffer(card, wave_out, size, &buffer) != CTSTATUS_SUCCESS)
+		return CTSTATUS_ERROR;
 
-/**************************************************************************/
-/* Function : sblive_waveoutQueryFormat                                   */
-/*                                                                        */
-/* Input    : card_waveout - pointer to card wave out object structure    */
-/*            pwave_fmt - pointer to wave format object                   */
-/*            flags - flags that identifies the format to be queried.     */
-/*                                                                        */
-/* About    : query whether a specified wave format is supported by wave  */
-/*            out device.                                                 */
-/**************************************************************************/
-int sblive_waveoutQueryFormat(struct sblive_waveout *card_waveout, struct wave_format * wave_fmt, u32 flags)
-{
-	if (flags & CARDWAVE_QF_CHANNEL)
-		if ((card_waveout->numplaybackinst) > card_waveout->maxnumplayinst)
-			return CTSTATUS_INUSE;
-
-	if (flags & CARDWAVE_QF_STEREO)
-		if (wave_fmt->channels != 1 && wave_fmt->channels != 2)
-			return CTSTATUS_BADFORMAT_STEREO;
-
-	if (flags & CARDWAVE_QF_RATE)
-		if (wave_fmt->samplingrate >= 0x2EE00) /* FIXME: 0x2ee00 = 192000! Is this valid??? */
-			wave_fmt->samplingrate = 0x2EE00;
-
-	if (flags & CARDWAVE_QF_BITS)
-		if (wave_fmt->bitspersample != 8 && wave_fmt->bitspersample != 16)
-			wave_fmt->bitspersample = 16;
+	/* xferbufsize contains actual transfer buffer size */
+	wavexferbuf->xferbufsize = *size;
+	wavexferbuf->xferbuffer = buffer;
 
 	return CTSTATUS_SUCCESS;
 }
 
-
-/**************************************************************************/
-/* Function : sblive_waveoutOpen                                          */
-/*                                                                        */
-/* Input    : card_waveout - pointer to card wave object structure        */
-/*            wave_fmt - pointer to wave format object                    */
-/*            CallbackFn - IRQ call back function                         */
-/*            refdata - reference data for call back function             */
-/*            fragment_size - size of buffer fragment                     */
-/*            numfrags - number of buffer fragments                       */
-/*                                                                        */
-/* Output   : fragment_size - pointer to the actual fragment size.        */
-/*            handle - pointer to the open handle.                        */
-/*                                                                        */
-/* About    : Open card wave out device.                                  */
-/*            1. query whether a specified wave format is supported by    */
-/*               device.                                                  */
-/*            2. allocate emu channel for the specified channel object.   */
-/*            3. attach this wave instance to the channel object list.    */
-/*            4. install wave IRQ handler.                                */
-/*            5. get wave transfer buffer.                                */
-/*            6. get wave instance format.                                */
-/**************************************************************************/
-int sblive_waveoutOpen(struct sblive_hw *sb_hw, struct wave_format *wave_fmt, u32 *fragment_size, u32 numfrags, struct wave_out **handle)
+static void dealloc_xferbuffer(struct emu10k1_card *card, struct wave_out *wave_out)
 {
-	struct sblive_waveout *card_waveout = sb_hw->card_waveout;
-	struct wave_out *wave_out;
-	struct voice_allocdesc voice_allocdesc;
-	int status;
-	u32 buffsize;
-	void **buffer;
+	u32 pagecount, pageindex;
+	int i;
 
-	/* If number of wave instances is greater than the maximum instances allowed, fail the open. */
-	if (card_waveout->numplaybackinst + 1 > card_waveout->maxnumplayinst)
-		return CTSTATUS_ERROR;
+	if (wave_out->pagetable != NULL) {
+		for (pagecount = 0; pagecount < wave_out->wavexferbuf->numpages; pagecount++) {
+			free_page((unsigned long) wave_out->pagetable[pagecount]);
 
-	wave_out = (struct wave_out *) kmalloc(sizeof(struct wave_out), GFP_KERNEL);
-	if (wave_out == NULL)
-	{
-		DPF(2, "struct wave_out alloc fail\n");
-		return CTSTATUS_NOMEMORY;
+			for (i = 0; i < PAGE_SIZE / EMUPAGESIZE; i++) {
+				pageindex = wave_out->emupageindex + pagecount * PAGE_SIZE / EMUPAGESIZE + i;
+				((u32 *) card->virtualpagetable->virtaddx)[pageindex] = (card->silentpage->busaddx * 2) | pageindex;
+			}
+		}
+		kfree(wave_out->pagetable);
 	}
-
-	DPD(3, "kmalloc: [%p]\n", wave_out);
-
-	/* Init channel object */
-	wave_out->next = NULL;
-	wave_out->status = 0;
-	wave_out->state = CARDWAVE_STATE_STOPPED;
-	wave_out->synchstart = FALSE;
-	wave_out->wave_fmt = *wave_fmt;
-	wave_out->emu_voice = NULL;
-	wave_out->emuaddr = NULL;
-	wave_out->wavexferbuf = NULL;
-	wave_out->pagetable = NULL;
-	wave_out->callbacksize = 0;
 
-	/* Assign default local volume */
-	/* FIXME: Should we be maxing the initial values like this? */
-	wave_out->localvol = 0xffffffff;
-	wave_out->localreverb = 0xffffffff;
-	wave_out->localchorus = 0xffffffff;
-	wave_out->globalvolFactor = 0xffff;
-	wave_out->globalreverbFactor = 0xffff;
-	wave_out->globalchorusFactor = 0xffff;
-
-	wave_out->process_id = 0;
-	wave_out->setpos = FALSE;
-	wave_out->position = 0;
-
-	wave_out->playflags = CARDWAVE_PLAY_LOOPING;
+	emu10k1_addxmgr_free(card, wave_out->emupageindex);
 
-	wave_out->wavexferbuf = (struct wave_xferbuf *) kmalloc(sizeof(struct wave_xferbuf ), GFP_KERNEL);
-
-	if (!wave_out->wavexferbuf)
-	{
-		DPF(2, "struct wave_xferbuf alloc failed\n");
-		kfree((void *) wave_out);
-		return CTSTATUS_NOMEMORY;
-	}
+	return;
+}
 
-	DPD(3, "kmalloc: [%p]\n", wave_out->wavexferbuf);
-	initWaveOutXferBuffer(wave_out);
+static int get_voice(struct emu10k1_card *card, struct wave_out *wave_out, int device)
+{
+	struct emu10k1_waveout *card_waveout = card->waveout;
+	struct wave_xferbuf *wavexferbuf = wave_out->wavexferbuf;
+	struct voice_allocdesc voice_allocdesc;
+	struct voice_param *left, *right;
+	u32 size;
 
 	/* Allocate voices here, if no voices available, return error.
 	 * Init voice_allocdesc first.*/
 
-	voice_allocdesc.sb_hw = sb_hw;
-	voice_allocdesc.ownertype = VOICEMGR_USAGE_PLAYBACK;
+	voice_allocdesc.usage = VOICEMGR_USAGE_PLAYBACK;
 
-	voice_allocdesc.callback = NULL;
-	voice_allocdesc.callback_data = 0;
-	voice_allocdesc.numvoicereqs = 1;
-	voice_allocdesc.flags[0] = 0;
-
-	if (wave_fmt->channels == 1)
-		voice_allocdesc.flags[0] |= VOICEMGR_FLAGS_MONO;
-
-	if (wave_fmt->bitspersample == 16)
-		voice_allocdesc.flags[0] |= VOICEMGR_FLAGS_16BIT;
-
-	voice_allocdesc.flags[0] |= VOICEMGR_FLAGS_PLAYBACK;
-
-	status = sblive_voiceAlloc(&voice_allocdesc, &wave_out->emu_voice);
-	if (status != CTSTATUS_SUCCESS)
-	{
-		DPF(2, "Channel allocation fail\n");
-		kfree((void *) wave_out->wavexferbuf);
-		kfree((void *) wave_out);
-		return status;
-	}
+	voice_allocdesc.flags = 0;
 
-	DPD(2, "voicenum -> %d\n", wave_out->emu_voice->voicenum);
+	if (device == 1)
+		voice_allocdesc.flags |= VOICEMGR_FLAGS_FXRT2;
 
-	/* Attach this wave instance to the channel object list */
-	card_waveout->numplaybackinst++;
+	if (wave_out->wave_fmt.channels == 1)
+		voice_allocdesc.flags |= VOICEMGR_FLAGS_MONO;
 
-	osListAttach((struct sblive_list **) & card_waveout->wave_outlist, (struct sblive_list *) wave_out);
+	if (wave_out->wave_fmt.bitsperchannel == 16)
+		voice_allocdesc.flags |= VOICEMGR_FLAGS_16BIT;
 
-	wave_out->callbacksize = *fragment_size;
+	if ((wave_out->voice = emu10k1_voice_alloc(&card->voicemgr, &voice_allocdesc)) == NULL)
+		return CTSTATUS_ERROR;
 
-	buffsize = (*fragment_size ? *fragment_size * numfrags : 0xffff);
+	/* voice initialization */
 
-	if (sblive_emuGetXferBuffer(sb_hw, wave_out, &buffsize, &buffer) != CTSTATUS_SUCCESS)
-	{
-		if (buffsize < *fragment_size)
-		{
-			*fragment_size = buffsize;
-			sblive_waveoutClose(sb_hw, wave_out);
-			return CTSTATUS_INVALIDVALUE;
-		}
+	left = &wave_out->voice->params;
 
-		DPF(2, "WaveOpen GetBuffer Fail\n");
-		sblive_waveoutClose(sb_hw, wave_out);
-		return CTSTATUS_ERROR;
-	}
+	/* Calculate pitch */
+	left->initial_pitch = (u16) (srToPitch(wave_out->wave_fmt.samplingrate) >> 8);
 
-	wave_out->callbacksize = buffsize / numfrags;
-	*fragment_size = buffsize / numfrags;
+	DPD(2, "Initial pitch --> %x\n", left->initial_pitch);
 
-	*handle = wave_out;
+	/* Easy way out.. gotta calculate value */
+	left->pitch_target = 0;
+	left->volume_target = 0;
+	left->FC_target = 0;
 
-	return CTSTATUS_SUCCESS;
-}
+	left->byampl_env_sustain = 0x7f;
+	left->byampl_env_decay = 0x7f;
 
+	if (wave_out->globalreverbFactor) {
+		u8 t = (card_waveout->globalreverb & 0xff) + (wave_out->localreverb & 0xff);
 
-/**************************************************************************/
-/* Function : sblive_waveoutClose                                         */
-/*                                                                        */
-/* Input    : card_waveout - pointer to card wave object structure        */
-/*            wave_out - pointer to the specified wave out instance       */
-/*                                                                        */
-/* About    : Close wave device.                                          */
-/*            1. deallocate transfer buffer, for playback,                */
-/*               free emu addx space.                                     */
-/*            2. free voice channels.                                     */
-/*            3. remove wave instance from channel object list.           */
-/**************************************************************************/
-int sblive_waveoutClose(struct sblive_hw *sb_hw, struct wave_out *wave_out)
-{
-	struct sblive_waveout *card_waveout = sb_hw->card_waveout;
-	struct wave_out *tempchan;
-	u32 dummy;
+		left->send_a = (t > 255) ? 255 : t;
+	} else {
+		left->send_a = 0;
+	}
 
-	if (wave_out->state != CARDWAVE_STATE_STOPPED)
-		sblive_waveoutStop(sb_hw, wave_out, &dummy);
+	if (wave_out->globalchorusFactor) {
+		u8 t = (card_waveout->globalchorus & 0xff) + (wave_out->localchorus & 0xff);
 
-	tempchan = card_waveout->wave_outlist;
-	while (tempchan)
-	{
-		if ((tempchan->wavexferbuf->xferbuffer
-		     == wave_out->wavexferbuf->xferbuffer)
-		    && (tempchan != wave_out))
-			break;
-		tempchan = (struct wave_out *) tempchan->next;
+		left->send_d = (t > 255) ? 255 : t;
+	} else {
+		left->send_d = 0;
 	}
 
-	osListRemove((struct sblive_list **) & card_waveout->wave_outlist, (struct sblive_list *) wave_out);
+	set_volume_instance(card_waveout, wave_out, left);
 
-	if (tempchan == NULL)
-	{
-		if (sblive_emuDeallocXferBuffer(wave_out) != CTSTATUS_SUCCESS)
-		{
-			DPF(2, "Failed to deallocate buffer\n");
-		}
+	left->pan_target = left->send_c;
+	left->aux_target = left->send_b;
 
-		kfree((void *) wave_out->wavexferbuf);
-		DPD(3, "kfree: [%p]\n", wave_out->wavexferbuf);
-	}
+	size = wavexferbuf->xferbufsize / wavexferbuf->bytespersample;
+	left->start = 2 * (wave_out->emupageindex << 11) / wavexferbuf->bytespersample;
+	left->end = left->start + size;
+	left->startloop = left->start;
+	left->endloop = left->end;
+
+	if (wave_out->voice->linked_voice) {
+		DPF(2, "is stereo\n");
+		right = &wave_out->voice->linked_voice->params;
 
-	wave_out->status |= FLAGS_AVAILABLE;
-	wave_out->state = CARDWAVE_STATE_STOPPED;
-	wave_out->synchstart = FALSE;
-
-	card_waveout->numplaybackinst--;
+		right->initial_pitch = left->initial_pitch;
 
-	if (sblive_voiceFree(wave_out->emu_voice) != CTSTATUS_SUCCESS)
-	{
-		DPF(2, "Failed to free voice\n");
-	}
+		/* Easy way out.. gotta calculate value */
+		right->pitch_target = 0;
+		right->volume_target = 0;
+		right->FC_target = 0;
 
-	kfree((void *) wave_out);
+		right->byampl_env_sustain = 0x7f;
+		right->byampl_env_decay = 0x7f;
 
-	return CTSTATUS_SUCCESS;
-}
+		right->send_d = left->send_d;
+		right->send_a = left->send_a;
 
+		/* Left output of right channel is always zero */
+		right->send_c = 0;
 
-/**************************************************************************/
-/* Function : sblive_emuGetXferBuffer                                     */
-/*                                                                        */
-/* Input    : card_waveout - pointer to card wave object                  */
-/*            wave_out - pointer to the specified wave out instance       */
-/*            size - pointer to the size requested                        */
-/*                                                                        */
-/* Output   : size - pointer to the size allocated                        */
-/*            buffer - pointer to the buffer pointer allocated            */
-/*                                                                        */
-/* About    : alloc transfer buffer.                                      */
-/**************************************************************************/
-int sblive_emuGetXferBuffer(struct sblive_hw *sb_hw, struct wave_out * wave_out, u32 *size, void ***buffer)
-{
-	DPF(2, "sblive_emuGetXferBuffer()\n");
+		/* Update right channel aux */
+		right->pan_target = 0;
+		right->send_b = left->send_b;
+		right->aux_target = right->send_b;
 
-	if (!size || !buffer)
-		return CTSTATUS_INVALIDPARAM;
+		/* Zero out right output of left channel */
+		left->send_b = 0;
+		left->aux_target = 0;
 
-	if (!wave_out)
-	{
-		DPF(2, "wave_out == NULL\n");
-		return CTSTATUS_ERROR;
-	}
+		/* Update right channel attenuation */
+		right->initial_attn = left->initial_attn;
 
-	if (*size < wave_out->callbacksize)
-	{
-		*size = wave_out->callbacksize;
-		return CTSTATUS_INVALIDVALUE;
-	}
+		right->start = left->start;
+		right->end = left->end;
+		right->startloop = left->startloop;
+		right->endloop = left->endloop;
 
-	if (sblive_emuAllocXferBuffer(sb_hw, wave_out, size, buffer) != CTSTATUS_SUCCESS)
-	{
-		DPF(2, "Allocate buffer failed\n");
-		return CTSTATUS_ERROR;
 	}
 
-	/* xferbufsize contains actual transfer buffer size */
-	wave_out->wavexferbuf->xferbufsize = *size;
-	wave_out->wavexferbuf->xferbuffer = *buffer;
-	wave_out->wavexferbuf->xferpos = 0;
+	DPD(2, "voice: start=%x, end=%x, startloop=%x, endloop=%x\n", left->start, left->end, left->startloop, left->endloop);
 
 	return CTSTATUS_SUCCESS;
 }
-
 
-/****************************************************************************/
-/* Function : sblive_waveoutSynchStart                                      */
-/*                                                                          */
-/* Input    : card_waveout - pointer to card wave object                    */
-/*                                                                          */
-/* About    : Synchronize start all wave playback and recording instances   */
-/*            in a particular application according to process ID.          */
-/*            Application needs to call SYNCHSTART twice, one is to start   */
-/*            all wave playback instances, another to start all wave        */
-/*            recording instances. Because wave out and wave in are         */
-/*            separate devices.                                             */
-/****************************************************************************/
-int sblive_waveoutSynchStart(struct sblive_waveout * card_waveout, u32 process_id)
+int emu10k1_waveout_open(struct emu10k1_wavedevice *wave_dev)
 {
-	struct wave_out * currinst;
-
-	currinst = card_waveout->wave_outlist;
+	struct emu10k1_card *card = wave_dev->card;
+	struct woinst *woinst = wave_dev->woinst;
+	struct wave_out *wave_out;
+	u32 bytespersec, delay;
+	u32 buffsize;
 
-	/* Start wave playback instances */
-	while (currinst)
-	{
-		if (currinst->process_id == process_id)
-		{
-			if (sblive_voiceStart(currinst->emu_voice) != CTSTATUS_SUCCESS)
-				return CTSTATUS_ERROR;
+	DPF(2, "emu10k1_waveout_open()\n");
 
-		}
-		currinst = currinst->next;
+	if ((wave_out = (struct wave_out *) kmalloc(sizeof(struct wave_out), GFP_KERNEL)) == NULL) {
+		ERROR();
+		emu10k1_waveout_close(wave_dev);
+		return CTSTATUS_ERROR;
 	}
-
-	return CTSTATUS_SUCCESS;
-}
-
-
-/****************************************************************************/
-/* Function : sblive_emuAllocXferBuffer                                     */
-/*                                                                          */
-/* Input    : wave_out - pointer to the specified wave out instance         */
-/*            size - pointer to the size requested                          */
-/*                                                                          */
-/* Output   : size - pointer to the size returned                           */
-/*            buffer - pointer to the buffer pointer allocated              */
-/*                                                                          */
-/* About    : allocate buffer for wave out transfer.                        */
-/*            1. playback: a) request for emu address space.                */
-/*                         b) allocate page-aligned PC memory for playback  */
-/*                            buffer.                                       */
-/*                         c) allocate memory for physical address table,   */
-/*                            copy page table.                              */
-/*                         d) determine start, end, startloop and           */
-/*                            endloop.                                      */
-/*                         e) fill in virtual memory table.                 */
-/*                         f) free physical address table.                  */
-/****************************************************************************/
-int sblive_emuAllocXferBuffer(struct sblive_hw *sb_hw, struct wave_out *wave_out, u32 *size, void ***buffer)
-{
-	u32 numpages, reqsize;
-	struct emuaddr_allocdesc dsEmuAddxAllocDesc;
-	struct wave_xferbuf *wavexferbuf = wave_out->wavexferbuf;
-	u32 pagecount;
 
-	reqsize = *size;
-	numpages = reqsize / PAGE_SIZE;
+	woinst->wave_out = wave_out;
 
-	/* If size is not a multiple of PAGE_SIZE then we need to round up */
-	if (reqsize % PAGE_SIZE)
-		numpages += 1;
-
-	DPD(2, "requested pages is: %d\n", numpages);
+	/* Init channel object */
+	wave_out->state = CARDWAVE_STATE_STOPPED;
+	wave_out->wave_fmt = woinst->wave_fmt;
+	wave_out->voice = NULL;
+	wave_out->emupageindex = -1;
+	wave_out->wavexferbuf = NULL;
+	wave_out->pagetable = NULL;
+	wave_out->timer = NULL;
 
-	wavexferbuf->numpages = numpages;
+	/* Assign default local volume */
+	/* FIXME: Should we be maxing the initial values like this? */
+	wave_out->localvol = 0xffffffff;
+	wave_out->localreverb = 0xffffffff;
+	wave_out->localchorus = 0xffffffff;
+	wave_out->globalvolFactor = 0xffff;
+	wave_out->globalreverbFactor = 0xffff;
+	wave_out->globalchorusFactor = 0xffff;
 
-	/* Only for playback, request for emu address space */
-	dsEmuAddxAllocDesc.sb_hw = sb_hw;
-	dsEmuAddxAllocDesc.ownertype = 0;
-	dsEmuAddxAllocDesc.callback = 0;
-	dsEmuAddxAllocDesc.callback_data = 0;
+	wave_out->setpos = 0;
+	wave_out->position = 0;
 
-	/* Support non page-aligned buffer, don't need interpolation page */
-	dsEmuAddxAllocDesc.size = numpages * PAGE_SIZE;
-	dsEmuAddxAllocDesc.flags = 0;
+	wave_out->fill_silence = 0;
 
-	if (emu10kaddxmgrAlloc(&dsEmuAddxAllocDesc, &wave_out->emuaddr) != CTSTATUS_SUCCESS){
-		DPF(2, "no memory, increase MAXPAGES\n");
-		return CTSTATUS_NOMEMORY;
+	if ((wave_out->wavexferbuf = (struct wave_xferbuf *) kmalloc(sizeof(struct wave_xferbuf), GFP_KERNEL)) == NULL) {
+		ERROR();
+		emu10k1_waveout_close(wave_dev);
+		return CTSTATUS_ERROR;
 	}
-
-	wave_out->pagetable = (void **) kmalloc(sizeof(void *) * numpages, GFP_KERNEL);
 
-	if (!wave_out->pagetable) {
-		DPF(2, "no memory\n");
-		emu10kaddxmgrFree(wave_out->emuaddr);
-		return CTSTATUS_NOMEMORY;
-	}
-	
-	/* Fill in virtual memory table */
-	for (pagecount = 0; pagecount < numpages; pagecount++)
-	{
-		/* Preserve emu page number */
-		((u32 *) sb_hw->virtualpagetable->virtaddx)[(wave_out->emuaddr->emustartaddr >> 11) + pagecount] &= 0x1fff;
-
-		if (!(wave_out->pagetable[pagecount] = (void *)__get_free_page(GFP_KERNEL))) {
-			DPF(2, "no memory\n");
-			while (pagecount--)
-				free_page((unsigned long)wave_out->pagetable[pagecount]);
-			emu10kaddxmgrFree(wave_out->emuaddr);
-			kfree(wave_out->pagetable);
-			return CTSTATUS_NOMEMORY;
-		}
-		
-		/* OR with physical address */
-		((u32 *) sb_hw->virtualpagetable->virtaddx)[(wave_out->emuaddr->emustartaddr >> 11) + pagecount] |= (((u32) virt_to_bus((char *) wave_out->pagetable[pagecount])) & 0xfffff000) << 1;
+	buffsize = woinst->fragment_size * woinst->numfrags;
 
-		DPD(2, "Physical Addx: %x\n", ((u32 *) sb_hw->virtualpagetable->virtaddx)[(wave_out->emuaddr->emustartaddr >> 11) + pagecount]);
+	if (get_xferbuffer(card, wave_out, &buffsize) != CTSTATUS_SUCCESS) {
+		ERROR();
+		emu10k1_waveout_close(wave_dev);
+		return CTSTATUS_ERROR;
 	}
 
-	*buffer = wave_out->pagetable;
-
-	{
-		struct voice_param *left = &wave_out->emu_voice->voice_params;
+	woinst->fragment_size = buffsize / woinst->numfrags;
+	wave_out->callbacksize = woinst->fragment_size;
 
-		reqsize = reqsize * (2 - wavexferbuf->is16bit) / (wavexferbuf->is_stereo + 1) / 2;
-		left->start = wave_out->emuaddr->emustartaddr;
-		left->start = left->start / (wavexferbuf->is_stereo + 1) * (2 - wavexferbuf->is16bit);
-		left->end = left->start + reqsize;
-		left->startloop = left->start;
-		left->endloop = left->end;
-
-		DPD(2, "sblive_emuAllocXferBuf: start=%x, end=%x, startloop=%x, endloop=%x\n",
-		    left->start, left->end, left->startloop, left->endloop);
-
-		if (wavexferbuf->is_stereo && wave_out->emu_voice->linked_voice)
-		{
-			struct voice_param *right = &wave_out->emu_voice->linked_voice->voice_params;
-
-			/* Do the same thing for right channel */
-			right->start = left->start;
-			right->end = left->end;
-			right->startloop = left->startloop;
-			right->endloop = left->endloop;
-		}
+	if (get_voice(card, wave_out, woinst->device) != CTSTATUS_SUCCESS) {
+		ERROR();
+		emu10k1_waveout_close(wave_dev);
+		return CTSTATUS_ERROR;
 	}
-
-	return CTSTATUS_SUCCESS;
-}
-
-
-/****************************************************************************/
-/* Function : sblive_emuDeallocXferBuffer                                   */
-/*                                                                          */
-/* Input    : wave_out - pointer to the specified wave out instance         */
-/*                                                                          */
-/* About    : deallocate transfer buffer                                    */
-/*            1. for playback, free emu address space.                      */
-/*            2. free PC memory allocated for transfer buffer.              */
-/*            3. clear VioceParam.                                          */
-/****************************************************************************/
-int sblive_emuDeallocXferBuffer(struct wave_out *wave_out)
-{
-	struct wave_xferbuf *wavexferbuf = wave_out->wavexferbuf;
-	int pagecount;
 
-	/* For playback, free emu address space */
-	if (wave_out->emuaddr)
-		emu10kaddxmgrFree(wave_out->emuaddr);
-
-	if (wave_out->pagetable) {
-		for (pagecount = 0; pagecount < wavexferbuf->numpages; pagecount++)
-			free_page((unsigned long)wave_out->pagetable[pagecount]);
-		kfree(wave_out->pagetable);
-		wave_out->wavexferbuf->xferbuffer = NULL;
-	}
+	bytespersec = wave_out->wave_fmt.channels * (wave_out->wave_fmt.bitsperchannel >> 3) * (wave_out->wave_fmt.samplingrate);
+	delay = (48000 * wave_out->callbacksize) / bytespersec;
 
-	/* Clear VoiceParam */
-	if (wave_out->emu_voice != NULL)
-	{
-		struct voice_param *left = &wave_out->emu_voice->voice_params;
-
-		left->start = 0;
-		left->startloop = 0;
-		left->end = 0;
-		left->endloop = 0;
-
-		if ((wave_out->wave_fmt.channels == 2) && wave_out->emu_voice->linked_voice)
-		{
-			struct voice_param *right = &wave_out->emu_voice->linked_voice->voice_params;
-
-			right->start = 0;
-			right->startloop = 0;
-			right->end = 0;
-			right->endloop = 0;
-		}
+	if ((wave_out->timer = emu10k1_timer_install(card, emu10k1_waveout_bh, (unsigned long) wave_dev, delay / 2)) == NULL) {
+		ERROR();
+		emu10k1_waveout_close(wave_dev);
+		return CTSTATUS_ERROR;
 	}
 
 	return CTSTATUS_SUCCESS;
 }
-
 
-/****************************************************************************/
-/* Function : initWaveOutXferBuffer                                         */
-/*                                                                          */
-/* Input    : wave_out - pointer to the specified wave out instance         */
-/*                                                                          */
-/* About    : init card wave buffer structure                               */
-/****************************************************************************/
-/* FIXME: This should be a macor [jtaylor] */
-void initWaveOutXferBuffer(struct wave_out *wave_out)
+void emu10k1_waveout_close(struct emu10k1_wavedevice *wave_dev)
 {
-	wave_out->wavexferbuf->xferpos = 0;
-	wave_out->wavexferbuf->xferbufsize = 0;
-	wave_out->wavexferbuf->numpages = 0;
-	wave_out->wavexferbuf->xferbuffer = NULL;
-	wave_out->wavexferbuf->is_stereo = (wave_out->wave_fmt.channels == 2) ? 1 : 0;
-	wave_out->wavexferbuf->is16bit = (wave_out->wave_fmt.bitspersample == 16) ? 1 : 0;
-
-	if (wave_out->wave_fmt.channels == 2)
-	{
-		if (wave_out->wave_fmt.bitspersample == 16)
-			wave_out->wavexferbuf->format = S16;
-		else
-			wave_out->wavexferbuf->format = S8;
-	} else
-	{
-		if (wave_out->wave_fmt.bitspersample == 16)
-			wave_out->wavexferbuf->format = M16;
-		else
-			wave_out->wavexferbuf->format = M8;
-	}
-
-	wave_out->wavexferbuf->conv = 0;
-	wave_out->wavexferbuf->interpolationbytes = INTERPOLATION_BYTES * (wave_out->wavexferbuf->is16bit + 1) * (wave_out->wavexferbuf->is_stereo + 1);
-	wave_out->wavexferbuf->offset = 0;
-	wave_out->wavexferbuf->stopposition = 0;
-}
-
+	struct emu10k1_card *card = wave_dev->card;
+	struct wave_out *wave_out = wave_dev->woinst->wave_out;
 
-/****************************************************************************/
-/* Function : sblive_waveoutSetFormat                                       */
-/*                                                                          */
-/* Input    : card_waveout - pointer to card wave object                    */
-/*            wave_out - pointer to the specified wave out instance         */
-/*                                                                          */
-/* About    : sets a new format for the wave instance                       */
-/****************************************************************************/
-int sblive_waveoutSetFormat(struct sblive_hw *sb_hw, struct wave_out *wave_out, struct wave_format *wave_fmt)
-{
-	int status;
-	struct voice_allocdesc voice_allocdesc;
+	DPF(2, "emu10k1_waveout_close()\n");
 
 	if (wave_out->state != CARDWAVE_STATE_STOPPED)
-		return CTSTATUS_ERROR;
-
-	if ((wave_fmt->channels != wave_out->wave_fmt.channels) ||
-	    (wave_fmt->bitspersample != wave_out->wave_fmt.bitspersample))
-	{
-		sblive_voiceFree(wave_out->emu_voice);
-
-		/* Allocate voices here, if no voices available, return error.  Init voice_allocdesc first. */
-		voice_allocdesc.sb_hw = sb_hw;
-		voice_allocdesc.ownertype = VOICEMGR_USAGE_PLAYBACK;
-
-		/* for P10, this is to allocate main voices, don't need IRQ callback */
-		voice_allocdesc.callback = NULL;
-		voice_allocdesc.callback_data = 0;
-		voice_allocdesc.numvoicereqs = 1;
-		voice_allocdesc.flags[0] = 0;
-
-		if (wave_fmt->channels == 1)
-			voice_allocdesc.flags[0] |= VOICEMGR_FLAGS_MONO;
-		if (wave_fmt->bitspersample == 16)
-			voice_allocdesc.flags[0] |= VOICEMGR_FLAGS_16BIT;
+		emu10k1_waveout_stop(wave_dev);
 
-		voice_allocdesc.flags[0] |= VOICEMGR_FLAGS_PLAYBACK;
+	if (wave_out->timer != NULL)
+		emu10k1_timer_uninstall(card, wave_out->timer);
 
-		if ((status = sblive_voiceAlloc(&voice_allocdesc, &wave_out->emu_voice)) != CTSTATUS_SUCCESS)
-			return status;
-	}
+	if (wave_out->voice != NULL)
+		emu10k1_voice_free(&card->voicemgr, wave_out->voice);
 
-	wave_out->wave_fmt = *wave_fmt;
-	wave_out->wavexferbuf->is_stereo = (wave_out->wave_fmt.channels == 2) ? 1 : 0;
-	wave_out->wavexferbuf->is16bit = (wave_out->wave_fmt.bitspersample == 16) ? 1 : 0;
-
-	if (wave_out->wave_fmt.channels == 2)
-	{
-		if (wave_out->wave_fmt.bitspersample == 16)
-			wave_out->wavexferbuf->format = S16;
-		else
-			wave_out->wavexferbuf->format = S8;
-	} else
-	{
-		if (wave_out->wave_fmt.bitspersample == 16)
-			wave_out->wavexferbuf->format = M16;
-		else
-			wave_out->wavexferbuf->format = M8;
-	}
+	if (wave_out->emupageindex >= 0)
+		dealloc_xferbuffer(card, wave_out);
 
-	wave_out->wavexferbuf->interpolationbytes = INTERPOLATION_BYTES * (wave_out->wavexferbuf->is16bit + 1) * (wave_out->wavexferbuf->is_stereo + 1);
+	if (wave_out->wavexferbuf != NULL)
+		kfree(wave_out->wavexferbuf);
 
-	{
-		u32 reqsize;
-		struct wave_xferbuf * wavexferbuf = wave_out->wavexferbuf;
-		struct voice_param * left = &wave_out->emu_voice->voice_params;
-
-		/* emu address space is in words, use start and end for actual
-		 * emu start and end address allocated, startloop and endloop
-		 * for loop points.  startloop and endloop contain number of samples. */
-		reqsize = wavexferbuf->xferbufsize * (2 - wavexferbuf->is16bit) / (wavexferbuf->is_stereo + 1) / 2;
-		left->start = wave_out->emuaddr->emustartaddr;
-		left->start = left->start / (wavexferbuf->is_stereo + 1) * (2 - wavexferbuf->is16bit);
-		left->end = left->start + reqsize;
-		left->startloop = left->start;
-		left->endloop = left->end;
-
-		DPD(2, "SetFormat: start=%x, end=%x, startloop=%x, endloop=%x\n",
-		    left->start, left->end, left->startloop, left->endloop);
-
-		if (wavexferbuf->is_stereo && wave_out->emu_voice->linked_voice)
-		{
-			struct voice_param *right = &wave_out->emu_voice->linked_voice->voice_params;
-
-			/* Do the same thing for right channel */
-			right->start = left->start;
-			right->end = left->end;
-			right->startloop = left->startloop;
-			right->endloop = left->endloop;
-		}
-	}
+	kfree(wave_out);
+	wave_dev->woinst->wave_out = NULL;
 
-	return CTSTATUS_SUCCESS;
+	return;
 }
-
 
-/****************************************************************************/
-/* Function : sblive_waveoutStart                                           */
-/*                                                                          */
-/* Input    : card_waveout - pointer to card wave object                    */
-/*            wave_out - pointer to the specified wave out instance         */
-/*                                                                          */
-/* About    : start wave transfer.                                          */
-/*            playback: a) setup voices.  b) set volume.                    */
-/*                      c) enable IRQ.    d) start playback.                */
-/****************************************************************************/
-int sblive_waveoutStart(struct sblive_wavedevice *wave_dev)
+int emu10k1_waveout_start(struct emu10k1_wavedevice *wave_dev)
 {
-	struct sblive_hw *sb_hw = wave_dev->sb_hw;
+	struct emu10k1_card *card = wave_dev->card;
 	struct wave_out *wave_out = wave_dev->woinst->wave_out;
-	struct sblive_waveout * card_waveout= sb_hw->card_waveout;
-	struct voice_param *left = &wave_out->emu_voice->voice_params;
 	u32 start, startPosition;
-	u32 delay, bytespersec;
 
+	DPF(2, "emu10k1_waveout_start()\n");
+
 	/* If already started, return success */
 	if (wave_out->state == CARDWAVE_STATE_STARTED)
 		return CTSTATUS_SUCCESS;
-
-	/* Calculate pitch */
-	left->initial_pitch = (u16) (srToPitch(wave_out->wave_fmt.samplingrate) >> 8);
-
-	DPD(2, "Initial pitch --> %x\n", left->initial_pitch);
-
-	/* Easy way out.. gotta calculate value */
-	left->pitch_target = 0;
-	left->volume_target = 0;
-	left->FC_target = 0;
 
-	left->byampl_env_sustain = 0x7f;
-	left->byampl_env_decay = 0x7f;
+	if (wave_out->state == CARDWAVE_STATE_STOPPED && wave_out->setpos)
+		startPosition = wave_out->position / (wave_out->wavexferbuf->bytespersample);
+	else
+		startPosition = wave_out->wavexferbuf->stopposition;
 
-	if (wave_out->globalreverbFactor)
-	{
-		u8 t = (card_waveout->globalreverb & 0xff) + (wave_out->localreverb & 0xff);
-		left->unSends.tSends.reverb_send = (t > 255) ? 255 : t;
-	} else
-	{
-		left->unSends.tSends.reverb_send = 0;
-	}
+	start = wave_out->voice->params.start;
+	wave_out->voice->params.start += startPosition;
 
-	if (wave_out->globalchorusFactor)
-	{
-		u8 t = (card_waveout->globalchorus & 0xff) + (wave_out->localchorus & 0xff);
-		left->unSends.tSends.chorus_send = (t > 255) ? 255 : t;
-	} else
-	{
-		left->unSends.tSends.chorus_send = 0;
-	}
+	DPD(2, "CA is %x\n", wave_out->voice->params.start);
 
-	set_volume_instance(card_waveout, wave_out, left);
+	emu10k1_voice_playback_setup(wave_out->voice);
 
-	left->pan_target = left->unSends.tSends.pan_send;
-	left->aux_target = left->unSends.tSends.aux_send;
+	wave_out->voice->params.start = start;
 
-	if (wave_out->wavexferbuf->is_stereo && wave_out->emu_voice->linked_voice)
-	{
-		struct voice_param *right = &wave_out->emu_voice->linked_voice->voice_params;
+	/* Actual start */
+	emu10k1_voice_start(wave_out->voice);
 
-		right->initial_pitch = left->initial_pitch;
+	wave_out->state = CARDWAVE_STATE_STARTED;
+	wave_out->setpos = 0;
 
-		/* Easy way out.. gotta calculate value */
-		right->pitch_target = 0;
-		right->volume_target = 0;
-		right->FC_target = 0;
+	emu10k1_timer_enable(card, wave_out->timer);
 
-		right->byampl_env_sustain = 0x7f;
-		right->byampl_env_decay = 0x7f;
+	return CTSTATUS_SUCCESS;
+}
 
-		right->unSends.tSends.chorus_send = left->unSends.tSends.chorus_send;
-		right->unSends.tSends.reverb_send = left->unSends.tSends.reverb_send;
+int emu10k1_waveout_setformat(struct emu10k1_wavedevice *wave_dev)
+{
+	struct emu10k1_card *card = wave_dev->card;
+	struct woinst *woinst = wave_dev->woinst;
+	struct wave_out *wave_out = woinst->wave_out;
+	u32 bytespersec, delay;
 
-		/* Left output of right channel is always zero */
-		right->unSends.tSends.pan_send = 0;
+	DPF(2, "emu10k1_waveout_setformat()\n");
 
-		/* Update right channel aux */
-		right->pan_target = 0;
-		right->unSends.tSends.aux_send = left->unSends.tSends.aux_send;
-		right->aux_target = right->unSends.tSends.aux_send;
+	query_format(&woinst->wave_fmt);
 
-		/* Zero out right output of left channel */
-		left->unSends.tSends.aux_send = 0;
-		left->aux_target = 0;
+	if (wave_out == NULL)
+		return CTSTATUS_SUCCESS;
 
-		/* Update right channel attenuation */
-		right->initial_attn = left->initial_attn;
+	if (wave_out->state == CARDWAVE_STATE_STARTED) {
+		woinst->wave_fmt = wave_out->wave_fmt;
+		return CTSTATUS_SUCCESS;
 	}
 
-	if (wave_out->state == CARDWAVE_STATE_STOPPED && wave_out->setpos)
-		startPosition = wave_out->position / (wave_out->wavexferbuf->is16bit + 1) / (wave_out->wavexferbuf->is_stereo + 1);
-	else
-		startPosition = wave_out->wavexferbuf->stopposition;
+	if ((wave_out->wave_fmt.samplingrate != woinst->wave_fmt.samplingrate)
+	    || (wave_out->wave_fmt.bitsperchannel != woinst->wave_fmt.bitsperchannel)
+	    || (wave_out->wave_fmt.channels != woinst->wave_fmt.channels)) {
+		struct wave_xferbuf *wavexferbuf = wave_out->wavexferbuf;
 
-	start = wave_out->emu_voice->voice_params.start;
-	wave_out->emu_voice->voice_params.start += startPosition;
+		emu10k1_timer_uninstall(card, wave_out->timer);
 
-	DPD(2, "CA is %x\n", wave_out->emu_voice->voice_params.start);
+		emu10k1_voice_free(&card->voicemgr, wave_out->voice);
 
-	if (sblive_voicePlaybackSetup(wave_out->emu_voice) != CTSTATUS_SUCCESS)
-		return CTSTATUS_ERROR;
-
-	wave_out->emu_voice->voice_params.start = start;
-
-	wave_out->task = (struct tq_struct *) kmalloc(sizeof(struct tq_struct), GFP_KERNEL);
-	if (wave_out->task == NULL)
-	{
-		DPF(2, "task alloc\n");
-		return CTSTATUS_NOMEMORY;
-	}
+		wave_out->wave_fmt = woinst->wave_fmt;
+		wave_out->timer = NULL;
 
-	DPD(3, "kmalloc: [%p]\n", wave_out->task);
-	wave_out->task->next = NULL;
-	wave_out->task->sync = 0;
-	wave_out->task->routine = waveOutCallbackFn;
-	wave_out->task->data = wave_dev;
+		wavexferbuf->xferpos = 0;
+		wavexferbuf->silence_xferpos = 0;
+		wavexferbuf->stopposition = 0;
+		wavexferbuf->is_stereo = (wave_out->wave_fmt.channels == 2) ? 1 : 0;
+		wavexferbuf->is_16bit = (wave_out->wave_fmt.bitsperchannel == 16) ? 1 : 0;
+		wavexferbuf->bytespersample = (wavexferbuf->is_stereo + 1) * (wavexferbuf->is_16bit + 1);
 
-	bytespersec = wave_out->wave_fmt.channels * (wave_out->wave_fmt.bitspersample >> 3) * (wave_out->wave_fmt.samplingrate);
-	delay = (48000 * wave_out->callbacksize) / bytespersec;
+		if (get_voice(card, wave_out, woinst->device) != CTSTATUS_SUCCESS) {
+			ERROR();
+			emu10k1_waveout_close(wave_dev);
+			return CTSTATUS_ERROR;
+		}
 
-	if (sblive_timerinstall(sb_hw, &wave_out->timer, wave_out->task, delay / 2) != CTSTATUS_SUCCESS)
-	{
-		sblive_voiceStop(wave_out->emu_voice);
-		return CTSTATUS_ERROR;
-	}
+		bytespersec = wave_out->wave_fmt.channels * (wave_out->wave_fmt.bitsperchannel >> 3) * (wave_out->wave_fmt.samplingrate);
+		delay = (48000 * wave_out->callbacksize) / bytespersec;
 
-	/* Actual start */
-	if (!wave_out->synchstart)
-		if (sblive_voiceStart(wave_out->emu_voice) != CTSTATUS_SUCCESS)
+		if ((wave_out->timer = emu10k1_timer_install(card, emu10k1_waveout_bh, (unsigned long) wave_dev, delay / 2)) == NULL) {
+			ERROR();
+			emu10k1_waveout_close(wave_dev);
 			return CTSTATUS_ERROR;
-
-	wave_out->state = CARDWAVE_STATE_STARTED;
-	wave_out->setpos = FALSE;
+		}
+	}
 
 	return CTSTATUS_SUCCESS;
 }
 
-
-/****************************************************************************/
-/* Function : sblive_waveoutStop                                            */
-/*                                                                          */
-/* Input    : card_waveout - pointer to card wave object                    */
-/*            wave_out - pointer to the specified wave out instance         */
-/*            ppending - for later use                                      */
-/*                                                                          */
-/* About    : stop wave transfer, disable IRQ.                              */
-/****************************************************************************/
-int sblive_waveoutStop(struct sblive_hw *sb_hw, struct wave_out *wave_out, u32 *pending)
+void emu10k1_waveout_stop(struct emu10k1_wavedevice *wave_dev)
 {
-	struct sblive_waveout *card_waveout = sb_hw->card_waveout;
-	struct wave_xferbuf *wavexferbuf;
-	u32 dummy;
+	struct emu10k1_card *card = wave_dev->card;
+	struct wave_out *wave_out = wave_dev->woinst->wave_out;
+	struct wave_xferbuf *wavexferbuf = wave_out->wavexferbuf;
 	u32 samples = 32;
 	u32 position;
-
-	if (!wave_out)
-		return CTSTATUS_INVALIDPARAM;
-
-	wavexferbuf = wave_out->wavexferbuf;
 
-	if (wave_out->state == CARDWAVE_STATE_STOPPING)
-		return CTSTATUS_SUCCESS;
-
-	if (!wave_out->emu_voice)
-	{
-		wave_out->state = CARDWAVE_STATE_STOPPED;
-		return CTSTATUS_SUCCESS;
-	}
+	DPF(2, "emu10k1_waveout_stop()\n");
 
 	if (wave_out->state == CARDWAVE_STATE_STOPPED)
-		return CTSTATUS_SUCCESS;
+		return;
 
-	wave_out->state = CARDWAVE_STATE_STOPPING;
+	emu10k1_timer_disable(card, wave_out->timer);
 
-	sblive_waveoutGetXferSize(card_waveout, wave_out, &dummy, pending);
+	/* Stop actual voice */
+	emu10k1_voice_stop(wave_out->voice);
 
 	/* Save the stop position */
-	if (sblive_voiceGetControl(wave_out->emu_voice, CCCA_CURRADDR, &wave_out->wavexferbuf->stopposition) != CTSTATUS_SUCCESS)
-	{
-		wave_out->wavexferbuf->stopposition = 0;
-		return CTSTATUS_ERROR;
-	}
+	emu10k1_voice_getcontrol(wave_out->voice, CCCA_CURRADDR, &wavexferbuf->stopposition);
 
-	wave_out->wavexferbuf->stopposition -= wave_out->emu_voice->voice_params.start;
+	wavexferbuf->stopposition -= wave_out->voice->params.start;
 
 	/* Refer to voicemgr.c, CA is not started at zero.  We need to take this into account. */
-	position = wave_out->wavexferbuf->stopposition * (wave_out->wavexferbuf->is16bit + 1) * (wave_out->wavexferbuf->is_stereo + 1);
+	position = wavexferbuf->stopposition * wavexferbuf->bytespersample;
 
-	if (!wave_out->wavexferbuf->is16bit)
+	if (!wavexferbuf->is_16bit)
 		samples <<= 1;
 
-	if (wave_out->wavexferbuf->is_stereo)
+	if (wavexferbuf->is_stereo)
 		samples <<= 1;
 
 	samples -= 4;
 
-	if (position >= samples * (wave_out->wavexferbuf->is16bit + 1))
-		position -= samples * (wave_out->wavexferbuf->is16bit + 1);
+	if (position >= samples * (wavexferbuf->is_16bit + 1))
+		position -= samples * (wavexferbuf->is_16bit + 1);
 	else
-		position += wave_out->wavexferbuf->xferbufsize - samples * (wave_out->wavexferbuf->is16bit + 1);
-
-	wave_out->wavexferbuf->stopposition = position / (wave_out->wavexferbuf->is16bit + 1) / (wave_out->wavexferbuf->is_stereo + 1);
-
-	DPD(2, "sblive_waveoutstop, position is %x\n", wave_out->wavexferbuf->stopposition);
-
-	/* Stop actual voice */
-	if (sblive_voiceStop(wave_out->emu_voice) != CTSTATUS_SUCCESS)
-		return CTSTATUS_ERROR;
-
-	if (sblive_timeruninstall(sb_hw, wave_out->timer) != CTSTATUS_SUCCESS)
-		return CTSTATUS_ERROR;
+		position += wavexferbuf->xferbufsize - samples * (wavexferbuf->is_16bit + 1);
 
-	kfree(wave_out->task);
+	wavexferbuf->stopposition = position / wavexferbuf->bytespersample;
 
-	DPD(3, "kfree: [%p]\n", wave_out->task);
+	DPD(2, "position is %x\n", wavexferbuf->stopposition);
 
 	wave_out->state = CARDWAVE_STATE_STOPPED;
-	wave_out->process_id = 0;
-	wave_out->setpos = FALSE;
+	wave_out->setpos = 0;
 	wave_out->position = 0;
 
-	return CTSTATUS_SUCCESS;
+	return;
 }
-
 
-/****************************************************************************/
-/* Function : sblive_waveoutGetXferSize                                     */
-/*                                                                          */
-/* Input    : card_waveout - pointer to card wave object                    */
-/*            wave_out - pointer to the specified wave out instance         */
-/*                                                                          */
-/* Output   : size - pointer to the transfer size                           */
-/*            pending - pointer to the size to be transfered                */
-/*                                                                          */
-/* About    : get the size of data in bytes that the specified wave device  */
-/*            can process at the time of this function is called.           */
-/*                                                                          */
-/* Note     : this transfer size returned is referring to user buffer.      */
-/****************************************************************************/
-int sblive_waveoutGetXferSize(struct sblive_waveout *card_waveout, struct wave_out *wave_out, u32 *size, u32 *pending)
+void emu10k1_waveout_getxfersize(struct wave_out *wave_out, u32 * size, u32 * pending, u32 * curpos)
 {
-	u32 curpos;
 	struct wave_xferbuf *wavexferbuf = wave_out->wavexferbuf;
 
 	/* Get position of current address, this is in no. of bytes in play buffer */
-	if (sblive_waveoutGetControl(card_waveout, wave_out, WAVECURPOS, &curpos) != CTSTATUS_SUCCESS)
-		return CTSTATUS_ERROR;
+	emu10k1_waveout_getcontrol(wave_out, WAVECURPOS, curpos);
 
-	if ((curpos > wavexferbuf->xferpos) || ((curpos == wavexferbuf->xferpos) && (wave_out->state == CARDWAVE_STATE_STARTED))
-	    || ((curpos == wavexferbuf->xferpos) && (wavexferbuf->xferpos != 0) && (wave_out->state == CARDWAVE_STATE_STOPPED)))
-	{
-		*size = curpos - wavexferbuf->xferpos;
+	if ((*curpos > wavexferbuf->silence_xferpos)
+	    || ((*curpos == wavexferbuf->silence_xferpos)
+		&& (wave_out->state == CARDWAVE_STATE_STARTED))
+	    || ((*curpos == wavexferbuf->silence_xferpos) && (wavexferbuf->silence_xferpos != 0)
+		&& (wave_out->state == CARDWAVE_STATE_STOPPED))) {
+		*size = *curpos - wavexferbuf->silence_xferpos;
 		*pending = wavexferbuf->xferbufsize - *size;
-	} else
-	{
-		*pending = wavexferbuf->xferpos - curpos;
+	} else {
+		*pending = wavexferbuf->silence_xferpos - *curpos;
 		*size = wavexferbuf->xferbufsize - *pending;
 	}
 
-	return CTSTATUS_SUCCESS;
+	if (wavexferbuf->silence_xferpos != wavexferbuf->xferpos) {
+		if (*pending < wave_out->callbacksize) {
+			wave_out->fill_silence = 2;
+			*pending = 0;
+			*size = wavexferbuf->xferbufsize;
+			wavexferbuf->xferpos = *curpos;
+		} else {
+			if (wave_out->fill_silence == 2) {
+				*pending = 0;
+				*size = wavexferbuf->xferbufsize;
+				wavexferbuf->xferpos = *curpos;
+			} else {
+				*pending -= wave_out->callbacksize;
+				*size += wave_out->callbacksize;
+			}
+		}
+	} else {
+		if (*pending < wave_out->callbacksize)
+			wave_out->fill_silence = 1;
+		else
+			wave_out->fill_silence = 0;
+	}
+
+	return;
 }
 
-static void copy_block(u32 dst, u8 *src, u32 len, void **pt)
+static void copy_block(u32 dst, u8 * src, u32 len, void **pt)
 {
 	int i, j, k;
-	i = dst / 4096;
-	j = dst % 4096;
-	k = (len > 4096 - j) ? 4096 - j : len;
+
+	i = dst / PAGE_SIZE;
+	j = dst % PAGE_SIZE;
+	k = (len > PAGE_SIZE - j) ? PAGE_SIZE - j : len;
 	copy_from_user(pt[i] + j, src, k);
-	len -= k;	
-	while (len >= 4096) {
-		copy_from_user(pt[++i], src + k, 4096);
-		k += 4096;
-		len -= 4096;
+	len -= k;
+	while (len >= PAGE_SIZE) {
+		copy_from_user(pt[++i], src + k, PAGE_SIZE);
+		k += PAGE_SIZE;
+		len -= PAGE_SIZE;
 	}
-	copy_from_user(pt[++i], src + k, len);	
+	copy_from_user(pt[++i], src + k, len);
+
+	return;
 }
 
 static void fill_block(u32 dst, u8 val, u32 len, void **pt)
 {
 	int i, j, k;
-	i = dst / 4096;
-	j = dst % 4096;
-	k = (len > 4096 - j) ? 4096 -j : len;
+
+	i = dst / PAGE_SIZE;
+	j = dst % PAGE_SIZE;
+	k = (len > PAGE_SIZE - j) ? PAGE_SIZE - j : len;
 	memset(pt[i] + j, val, k);
 	len -= k;
-	while (len >= 4096) {
-		memset(pt[++i], val, 4096);
-		len -= 4096;
+	while (len >= PAGE_SIZE) {
+		memset(pt[++i], val, PAGE_SIZE);
+		len -= PAGE_SIZE;
 	}
 	memset(pt[++i], val, len);
+
+	return;
 }
 
-/**************************************************************************/
-/* Function : sblive_waveoutXferData                                      */
-/*                                                                        */
-/* Input    : card_waveout - pointer to card wave object                  */
-/*            wave_out - pointer to the specified wave out instance       */
-/*            data - pointer to the data to be transfered                 */
-/*            size - data size to be transfered(size in user buffer,      */
-/*                      for 8-bit sample, this is different from play     */
-/*                      buffer.                                           */
-/*                                                                        */
-/* Output   : size - data size transfered                                 */
-/*                                                                        */
-/* About    : transfer the data to/from the wave device.                  */
-/**************************************************************************/
-int sblive_waveoutXferData(struct sblive_waveout *card_waveout, struct wave_out *wave_out, u8 *data, u32 *size)
+void emu10k1_waveout_xferdata(struct woinst *woinst, u8 * data, u32 * size)
 {
+	struct wave_out *wave_out = woinst->wave_out;
 	struct wave_xferbuf *wavexferbuf = wave_out->wavexferbuf;
-	u32 sizetocopy, sizetocopynow;
+	u32 sizetocopy, sizetocopy_now, start;
+	unsigned long flags;
 
-	/* FIXME: Do we need spinlocks in here? */
-
-	if (!data || !size)
-		return CTSTATUS_INVALIDPARAM;
-
 	sizetocopy = min(wavexferbuf->xferbufsize, *size);
 	*size = sizetocopy;
 
 	if (!sizetocopy)
-		return CTSTATUS_SUCCESS;
+		return;
 
-	sizetocopynow = wavexferbuf->xferbufsize - wavexferbuf->xferpos;
+	spin_lock_irqsave(&woinst->lock, flags);
 
-	if(sizetocopy > sizetocopynow)
-	{
-		copy_block(wavexferbuf->xferpos, data, sizetocopynow, wavexferbuf->xferbuffer);
-                sizetocopy -= sizetocopynow;
-		copy_block(0, data + sizetocopynow, sizetocopy, wavexferbuf->xferbuffer);
+	sizetocopy_now = wavexferbuf->xferbufsize - wavexferbuf->xferpos;
+
+	start = wavexferbuf->xferpos;
+
+	if (sizetocopy > sizetocopy_now) {
+		sizetocopy -= sizetocopy_now;
 		wavexferbuf->xferpos = sizetocopy;
-	}
-	else
-	{
-		copy_block(wavexferbuf->xferpos, data, sizetocopy, wavexferbuf->xferbuffer);
-		if(sizetocopy == sizetocopynow)
+		wavexferbuf->silence_xferpos = wavexferbuf->xferpos;
+		spin_unlock_irqrestore(&woinst->lock, flags);
+
+		copy_block(start, data, sizetocopy_now, wavexferbuf->xferbuffer);
+		copy_block(0, data + sizetocopy_now, sizetocopy, wavexferbuf->xferbuffer);
+	} else {
+		if (sizetocopy == sizetocopy_now)
 			wavexferbuf->xferpos = 0;
 		else
 			wavexferbuf->xferpos += sizetocopy;
-	}
-
-	return CTSTATUS_SUCCESS;
-}
-
-
-/**************************************************************************/
-/* Function : sblive_waveoutFillSilence                                   */
-/*                                                                        */
-/* Input    : card_waveout - pointer to card wave object                  */
-/*            wave_out - pointer to the specified wave out instance       */
-/*            size - data size to be filled                               */
-/*                                                                        */
-/* Output   : size - data size filled                                     */
-/*                                                                        */
-/* About    : fill silent data to play buffer,only used for wave output.  */
-/**************************************************************************/
-int sblive_waveoutFillSilence(struct sblive_waveout *card_waveout, struct wave_out *wave_out, u32 *size)
-{
-	struct wave_xferbuf *wavexferbuf = wave_out->wavexferbuf;
-	u16 wFillData;
-	u32 sizetocopy, sizetocopyNow, sizecopied;
-
-	/* FIXME: Do we need spinlocks here? */
-
-	if (!size)
-		return CTSTATUS_INVALIDPARAM;
 
-	sizetocopy = min(wavexferbuf->xferbufsize, *size);
-	sizecopied = 0;
-
-	if (!sizetocopy)
-	{
-		*size = 0;
-		return CTSTATUS_SUCCESS;
-	}
-
-	if (wave_out->wave_fmt.bitspersample == 8)
-		wFillData = 0x8080;
-	else
-		wFillData = 0x0000;
+		wavexferbuf->silence_xferpos = wavexferbuf->xferpos;
+		spin_unlock_irqrestore(&woinst->lock, flags);
 
-	while (sizecopied < sizetocopy)
-	{
-		sizetocopyNow = sizetocopy - sizecopied;
-		sizetocopyNow = min(sizetocopyNow, wavexferbuf->xferbufsize - wavexferbuf->xferpos);
-
-		fill_block(wavexferbuf->xferpos, wFillData, sizetocopyNow, wavexferbuf->xferbuffer);
-
-		wavexferbuf->xferpos += sizetocopyNow;
-		wavexferbuf->xferpos %= wavexferbuf->xferbufsize;
-		sizecopied += sizetocopyNow;
+		copy_block(start, data, sizetocopy, wavexferbuf->xferbuffer);
 	}
 
-	*size = sizetocopy;
-
-	return CTSTATUS_SUCCESS;
+	return;
 }
 
-
-/****************************************************************************/
-/* Function : sblive_waveoutSetControl                                      */
-/*                                                                          */
-/* Input    : pICardWave - pointer to card wave object                      */
-/*            wave_out - pointer to the specified wave out instance         */
-/*            ctrl_id - control type                                        */
-/*            value - the value of the specified control to be set          */
-/*                                                                          */
-/* About    : set the specified control value of the wave device.           */
-/****************************************************************************/
-int sblive_waveoutSetControl(struct sblive_hw *sb_hw, struct wave_out *wave_out, u32 ctrl_id, u32 *control_value)
+void emu10k1_waveout_fillsilence(struct woinst *woinst)
 {
-	struct sblive_waveout *card_waveout = sb_hw->card_waveout;
-	struct wave_out *currinst = NULL;
-	u32 value;
-	struct voice_cntlset setting[6];
+	struct wave_out *wave_out = woinst->wave_out;
+	struct wave_xferbuf *wavexferbuf = wave_out->wavexferbuf;
+	u16 filldata;
+	u32 sizetocopy, sizetocopy_now, start;
+	unsigned long flags;
 
-	if (card_waveout == NULL)
-		return CTSTATUS_ERROR;
+	sizetocopy = wave_out->callbacksize;
 
-	if (control_value)
-		value = *control_value;
+	if (wave_out->wave_fmt.bitsperchannel == 8)
+		filldata = 0x8080;
 	else
-		value = 0;
-
-	switch (ctrl_id)
-	{
-	case WAVEOBJVOLUME:
-		return CTSTATUS_SUCCESS;
-
-	case WAVEOBJMUTE:
-		/* This is a general mute affecting all wave instances */
-		card_waveout->mute = value;
-		currinst = card_waveout->wave_outlist;
-
-		if (value)
-		{
-			/* Mute */
-			card_waveout->globalvol = 0;
-		} else
-		{
-			/* Unmute */
-			card_waveout->globalvol = (0xffff & card_waveout->left) | ((0xffff & card_waveout->right) << 16);
-
-			set_volume(card_waveout);
-		}
-
-		return CTSTATUS_SUCCESS;
-
-	case WAVEOBJREVERB:
-		/* This is a general set reverb affecting all wave instances.
-		 * Apps which can set the reverb of individual wave instances
-		 * should use WAVEINSTANCEREVERB instead. */
-
-		card_waveout->globalreverb = value;
-		currinst = card_waveout->wave_outlist;
-
-		while (currinst && currinst->emu_voice)
-		{
-			struct voice_param * left = &currinst->emu_voice->voice_params;
-
-			/* This flag allows a wave instance to be unaffected by changes to global volume. */
-			if (currinst->globalreverbFactor)
-			{
-				u8 t = (card_waveout->globalreverb & 0xff) + (currinst->localreverb & 0xff);
-				left->unSends.tSends.reverb_send = (t > 255) ? 255 : t;
-
-				if (currinst->wavexferbuf->is_stereo && currinst->emu_voice->linked_voice)
-				{
-					struct voice_param *right = &currinst->emu_voice->linked_voice->voice_params;
-
-					right->unSends.tSends.reverb_send = left->unSends.tSends.reverb_send;
-
-					setting[0].paramID = PTRX_FXSENDAMOUNT_A;
-					setting[0].value = right->unSends.tSends.reverb_send;
-
-					sblive_voiceSetControl(currinst->emu_voice->linked_voice, setting, 1);
-				}
-
-				setting[0].paramID = PTRX_FXSENDAMOUNT_A;
-				setting[0].value = left->unSends.tSends.reverb_send;
-
-				sblive_voiceSetControl(currinst->emu_voice, setting, 1);
-			}
-			currinst = currinst->next;
-		}
-		return CTSTATUS_SUCCESS;
-
-	case WAVEOBJCHORUS:
-		/* This is a general set chorus affecting all wave instances.
-		 * Apps which can set the chorus of individual wave instances
-		 * should use WAVEINSTANCECHORUS instead. */
-
-		card_waveout->globalchorus = value;
-		currinst = card_waveout->wave_outlist;
-
-		while (currinst && currinst->emu_voice)
-		{
-			struct voice_param *left = &currinst->emu_voice->voice_params;
-
-			if (currinst->globalchorusFactor)
-			{
-				u8 t = (card_waveout->globalchorus & 0xff) + (currinst->localchorus & 0xff);
-				left->unSends.tSends.chorus_send = (t > 255) ? 255 : t;
-
-				if (currinst->wavexferbuf->is_stereo && currinst->emu_voice->linked_voice)
-				{
-					struct voice_param *right = &currinst->emu_voice->linked_voice->voice_params;
-
-					right->unSends.tSends.chorus_send = left->unSends.tSends.chorus_send;
-
-					setting[0].paramID = DSL_FXSENDAMOUNT_D;
-					setting[0].value = right->unSends.tSends.chorus_send;
-
-					sblive_voiceSetControl(currinst->emu_voice->linked_voice, setting, 1);
-				}
-				setting[0].paramID = DSL_FXSENDAMOUNT_D;
-				setting[0].value = left->unSends.tSends.chorus_send;
-
-				sblive_voiceSetControl(currinst->emu_voice, setting, 1);
-			}
-			currinst = currinst->next;
-		}
-		return CTSTATUS_SUCCESS;
-
-	case WAVESYNCHSTART:
-		if (sblive_waveoutSynchStart(card_waveout, value) != CTSTATUS_SUCCESS)
-			return CTSTATUS_ERROR;
-		return CTSTATUS_SUCCESS;
-
-	default:
-		break;
-	}
-
-	if (!wave_out)
-		return CTSTATUS_ERROR;
-
-	switch (ctrl_id)
-	{
-	case WAVECURPOS:
-		if (wave_out->emu_voice == NULL)
-			return CTSTATUS_ERROR;
-
-		if (wave_out->state == CARDWAVE_STATE_STOPPED)
-		{
-			wave_out->setpos = TRUE;
-			wave_out->position = value;
-		} else
-		{
-			struct voice_param * left = &wave_out->emu_voice->voice_params;
-			/* struct wave_xferbuf * wavexferbuf = wave_out->wavexferbuf; */
-
-			if (wave_out->wave_fmt.bitspersample == 8)
-				value <<= 1;
-			if (wave_out->wave_fmt.channels == 2)
-				value >>= 1;
-			/* get no. of samples per channel */
-			value >>= 1;
-
-			/* if the position is already beyond the loop, return error. */
-			/* we could check this value before lock can't we ? */
-			if (value >= (left->end - left->start))
-				return CTSTATUS_ERROR;
-
-			/* Set current position */
-			setting[0].paramID = CCCA_CURRADDR;
-			setting[0].value = value + left->start;
-			sblive_voiceSetControl(wave_out->emu_voice, setting, 1);
-
-			if (wave_out->wavexferbuf->is_stereo && wave_out->emu_voice->linked_voice)
-			{
-				setting[0].paramID = CCCA_CURRADDR;
-				setting[0].value = value + wave_out->emu_voice->linked_voice->voice_params.start;
-
-				sblive_voiceSetControl(wave_out->emu_voice->linked_voice, setting, 1);
-			}
-		}
-		break;
-
-	case WAVESTOPPOSITION:
-		wave_out->wavexferbuf->stopposition = value;
-		break;
-
-	case WAVEWRITEPOINTER:
-		/* For wave output device, set write pointer for a particular wave instance.
-		 * For wave input device, set the offset of write pointer. */
-		wave_out->wavexferbuf->xferpos = value;
-		break;
-
-	case WAVEINSTANCEVOLUME:
-		/* This is a specific set volume affecting only 1 wave instance and can be only called by the owner.
-		 * Apps which can set the volume of individual wave instances should use this message. */
-
-		/* update wave instance volume */
-		wave_out->localvol = value;
-
-		if (wave_out->emu_voice != NULL)
-		{
-			u32 vol;
-			struct voice_param * left = &wave_out->emu_voice->voice_params;
-
-			vol = set_volume_instance(card_waveout, wave_out, left);
-
-			if (wave_out->wavexferbuf->is_stereo && wave_out->emu_voice->linked_voice)
-			{
-				struct voice_param *right = &wave_out->emu_voice->linked_voice->voice_params;
-
-				right->unSends.tSends.pan_send = 0; /* Left output of right channel is always zero */
-				right->unSends.tSends.aux_send = left->unSends.tSends.aux_send; /* Update right channel aux */
-				left->unSends.tSends.aux_send = 0; /* Zero out right output of left channel */
-				right->initial_attn = 0xff & sumVolumeToAttenuation(vol * 2); /* Update right channel attenuation */
-
-				setting[0].paramID = IFATN_ATTENUATION;
-				setting[0].value = right->initial_attn;
-
-				sblive_voiceSetControl(wave_out->emu_voice->linked_voice, setting, 1);
-			}
-
-			setting[0].paramID = IFATN_ATTENUATION;
-			setting[0].value = left->initial_attn;
-
-			sblive_voiceSetControl(wave_out->emu_voice, setting, 1);
-		}
-		break;
-
-
-	case WAVESYNCHSETUP:
-		wave_out->process_id = value;
-		wave_out->synchstart = TRUE;
-		break;
-
-	case WAVESETFREQUENCY:
-		if (wave_out->emu_voice != NULL)
-		{
-			struct voice_param * left = &wave_out->emu_voice->voice_params;
-
-			left->initial_pitch = (u16) (srToPitch(value) >> 8); /* Calculate pitch */
-
-			setting[0].paramID = IP;
-			setting[0].value = left->initial_pitch;
-			sblive_voiceSetControl(wave_out->emu_voice, setting, 1);
-
-			if (wave_out->wavexferbuf->is_stereo && wave_out->emu_voice->linked_voice)
-			{
-				struct voice_param *right = &wave_out->emu_voice->linked_voice->voice_params;
-
-				right->initial_pitch = left->initial_pitch;
-				setting[0].paramID = IP;
-				setting[0].value = right->initial_pitch;
-
-				sblive_voiceSetControl(wave_out->emu_voice->linked_voice, setting, 1);
-			}
-		}
-		wave_out->wave_fmt.samplingrate = value;
-		break;
-
-	case WAVESTARTLOOP:
-		if (wave_out->emu_voice != NULL)
-		{
-			struct voice_param *left = &wave_out->emu_voice->voice_params;
-
-			setting[0].paramID = PSST_LOOPSTARTADDR;
-			setting[0].value = left->startloop;
-
-			sblive_voiceSetControl(wave_out->emu_voice, setting, 1);
-
-			if (wave_out->wavexferbuf->is_stereo && wave_out->emu_voice->linked_voice)
-			{
-				struct voice_param *right = &wave_out->emu_voice->linked_voice->voice_params;
-
-				setting[0].paramID = PSST_LOOPSTARTADDR;
-				setting[0].value = right->startloop;
-
-				sblive_voiceSetControl(wave_out->emu_voice->linked_voice, setting, 1);
-			}
-		}
-		break;
-
-	case WAVEINSTANCEFORMAT:
-		return sblive_waveoutSetFormat(sb_hw, wave_out, (struct wave_format *) control_value);
-	case WAVEVOLFACTOR:
-		wave_out->globalvolFactor = value;
-		break;
-
-	case WAVEREVERBFACTOR:
-		wave_out->globalreverbFactor = value;
-		break;
+		filldata = 0x0000;
 
-	case WAVECHORUSFACTOR:
-		wave_out->globalchorusFactor = value;
-		break;
-
-	case WAVESETSTARTFLAG:
-		if (wave_out->playflags != value && (wave_out->state == CARDWAVE_STATE_STARTED))
-		{
-			struct sblive_hw *sb_hw = wave_out->emu_voice->sb_hw;
-
-			if (value & CARDWAVE_PLAY_LOOPING)
-			{
-				halClearStopOnLoop(sb_hw, wave_out->emu_voice->voicenum);
-				if (wave_out->emu_voice->linked_voice)
-					halClearStopOnLoop(sb_hw, wave_out->emu_voice->linked_voice->voicenum);
-			} else
-			{
-				halSetStopOnLoop(sb_hw, wave_out->emu_voice->voicenum);
-				if (wave_out->emu_voice->linked_voice)
-					halSetStopOnLoop(sb_hw, wave_out->emu_voice->linked_voice->voicenum);
-			}
-		}
-		wave_out->playflags = value;
-		break;
+	spin_lock_irqsave(&woinst->lock, flags);
 
-	case WAVESETSTOPONLOOP:
-		if (wave_out->state == CARDWAVE_STATE_STARTED)
-		{
-			struct sblive_hw * sb_hw = wave_out->emu_voice->sb_hw;
-			u32 CA, offset, endloop;
-			struct voice_param * left = &wave_out->emu_voice->voice_params;
-			struct voice_cntlset setting[3];
-
-			CA = sblive_readptr(sb_hw, CCCA_CURRADDR, wave_out->emu_voice->voicenum) - left->startloop;
-			offset = (CA / wave_out->callbacksize) * wave_out->callbacksize;
-
-			if (CA % wave_out->callbacksize)
-				offset += wave_out->callbacksize;
-
-			if (CA > (offset - 32))
-				offset += 32;
-
-			offset = CA;
-			endloop = offset + left->startloop;
-			setting[0].paramID = DSL_LOOPENDADDR;
-			setting[0].value = endloop;
+	sizetocopy_now = wavexferbuf->xferbufsize - wavexferbuf->silence_xferpos;
+	start = wavexferbuf->silence_xferpos;
 
-			sblive_voiceSetControl(wave_out->emu_voice, setting, 1);
-
-			if (wave_out->wavexferbuf->is_stereo && wave_out->emu_voice->linked_voice)
-			{
-				struct voice_param *right = &wave_out->emu_voice->linked_voice->voice_params;
-
-				endloop = offset + right->startloop;
-				setting[0].paramID = DSL_LOOPENDADDR;
-				setting[0].value = endloop;
-
-				sblive_voiceSetControl(wave_out->emu_voice, setting, 1);
-			}
-
-			halSetStopOnLoop(sb_hw, wave_out->emu_voice->voicenum);
+	if (sizetocopy > sizetocopy_now) {
+		sizetocopy -= sizetocopy_now;
+		wavexferbuf->silence_xferpos = sizetocopy;
+		spin_unlock_irqrestore(&woinst->lock, flags);
+		fill_block(start, filldata, sizetocopy_now, wavexferbuf->xferbuffer);
+		fill_block(0, filldata, sizetocopy, wavexferbuf->xferbuffer);
+	} else {
+		if (sizetocopy == sizetocopy_now)
+			wavexferbuf->silence_xferpos = 0;
+		else
+			wavexferbuf->silence_xferpos += sizetocopy;
 
-			if (wave_out->emu_voice->linked_voice)
-				halSetStopOnLoop(sb_hw, wave_out->emu_voice->linked_voice->voicenum);
-		}
-		break;
+		spin_unlock_irqrestore(&woinst->lock, flags);
 
-	default:
-		return CTSTATUS_NOTSUPPORTED;
+		fill_block(start, filldata, sizetocopy, wavexferbuf->xferbuffer);
 	}
 
-	return CTSTATUS_SUCCESS;
+	return;
 }
 
+/* get the specified control value of the wave device. */
 
-/****************************************************************************/
-/* Function : sblive_waveoutGetControl                                      */
-/*                                                                          */
-/* Input    : card_waveout - pointer to card wave object                    */
-/*            wave_out - pointer to the specified wave out instance         */
-/*            ctrl_id - control type                                        */
-/*                                                                          */
-/* Output   : value - pointer to the control value                          */
-/*                                                                          */
-/* About    : get the specified control value of the wave device.           */
-/****************************************************************************/
-int sblive_waveoutGetControl(struct sblive_waveout *card_waveout, struct wave_out *wave_out, u32 ctrl_id, u32 *value)
+int emu10k1_waveout_getcontrol(struct wave_out *wave_out, u32 ctrl_id, u32 * value)
 {
-	switch (ctrl_id)
-	{
-	case WAVEOBJVOLUME:
-		*value = card_waveout->globalvol;
-		return CTSTATUS_SUCCESS;
-
-	case WAVEOBJREVERB:
-		*value = card_waveout->globalreverb;
-		return CTSTATUS_SUCCESS;
-
-	case WAVEOBJCHORUS:
-		*value = card_waveout->globalchorus;
-		return CTSTATUS_SUCCESS;
-
-	case WAVEQUERYACTIVEINST:
-		if (card_waveout->wave_outlist != NULL)
-			return CTSTATUS_SUCCESS;
-		else
-			return CTSTATUS_ERROR;
-
-	default:
-		break;
-	}
-
-	if (!wave_out)
-		return CTSTATUS_ERROR;
-
-	switch (ctrl_id)
-	{
+	switch (ctrl_id) {
 	case WAVECURPOS:
-		if (wave_out->emu_voice == NULL)
-			return CTSTATUS_ERROR;
-
 		/* There is no actual start yet */
-		if (wave_out->state == CARDWAVE_STATE_STOPPED || wave_out->state == CARDWAVE_STATE_SUSPEND)
-		{
+		if (wave_out->state == CARDWAVE_STATE_STOPPED) {
 			if (wave_out->setpos)
 				*value = wave_out->position;
 			else
-				*value = wave_out->wavexferbuf->stopposition * (wave_out->wavexferbuf->is_stereo + 1) * (wave_out->wavexferbuf->is16bit + 1);
-		} else
-		{
-			if (sblive_voiceGetControl(wave_out->emu_voice, CCCA_CURRADDR, value) != CTSTATUS_SUCCESS)
-				return CTSTATUS_ERROR;
+				*value = wave_out->wavexferbuf->stopposition * wave_out->wavexferbuf->bytespersample;
+		} else {
+			emu10k1_voice_getcontrol(wave_out->voice, CCCA_CURRADDR, value);
 
-			*value -= wave_out->emu_voice->voice_params.start;
+			*value -= wave_out->voice->params.start;
 
 			/* Get number of bytes in play buffer per channel.
 			 * If 8 bit mode is enabled, this needs to be changed. */
 			{
 				u32 samples = 64 * (wave_out->wavexferbuf->is_stereo + 1);
 
-				*value *= (wave_out->wavexferbuf->is_stereo + 1) * (wave_out->wavexferbuf->is16bit + 1);
+				*value *= wave_out->wavexferbuf->bytespersample;
 
 				/* Refer to voicemgr.c, CA is not started at zero.
 				 * We need to take this into account. */
 
-				samples -= 4 * (wave_out->wavexferbuf->is16bit + 1);
+				samples -= 4 * (wave_out->wavexferbuf->is_16bit + 1);
 
 				if (*value >= samples)
 					*value -= samples;
@@ -1716,58 +747,8 @@
 		}
 
 		break;
-
-	case WAVEWRITEPOINTER:
-		/* Get write pointer for a particular wave instance */
-		*value = wave_out->wavexferbuf->xferpos;
-		break;
-
-	case WAVEINSTANCEVOLUME:
-		*value = wave_out->localvol;
-		return CTSTATUS_SUCCESS;
-
-	case WAVEINSTANCEREVERB:
-		*value = wave_out->localreverb;
-		return CTSTATUS_SUCCESS;
-
-	case WAVEINSTANCECHORUS:
-		*value = wave_out->localchorus;
-		return CTSTATUS_SUCCESS;
-
-	case WAVESTARTLOOP:
-		if (wave_out->emu_voice == NULL)
-			return CTSTATUS_ERROR;
-
-		if (sblive_voiceGetControl(wave_out->emu_voice, PSST_LOOPSTARTADDR, value) != CTSTATUS_SUCCESS)
-			return CTSTATUS_ERROR;
-
-		*value -= wave_out->emu_voice->voice_params.start;
-
-		/* Get number of bytes in play buffer per channel.
-		 * If 8 bit mode is enabled, this needs to be changed. */
-		*value <<= 1;
-		*value *= (wave_out->wavexferbuf->is_stereo + 1);
-		*value /= (2 - wave_out->wavexferbuf->is16bit);
-		break;
-
-	case WAVEENDLOOP:
-		if (wave_out->emu_voice == NULL)
-			return CTSTATUS_ERROR;
-
-		if (sblive_voiceGetControl(wave_out->emu_voice, DSL_LOOPENDADDR, value) != CTSTATUS_SUCCESS)
-			return CTSTATUS_ERROR;
-
-		*value -= wave_out->emu_voice->voice_params.start;
-
-		/* Get number of bytes in play buffer per channel.
-		 * Iif 8 bit mode is enabled, this needs to be changed. */
-		*value <<= 1;
-		*value *= (wave_out->wavexferbuf->is_stereo + 1);
-		*value /= (2 - wave_out->wavexferbuf->is16bit);
-		break;
-
 	default:
-		return CTSTATUS_NOTSUPPORTED;
+		return CTSTATUS_ERROR;
 	}
 
 	return CTSTATUS_SUCCESS;
Index: oldkernel/linux/drivers/sound/emu10k1/cardwo.h
diff -u linux/drivers/sound/emu10k1/cardwo.h:1.1 linux/drivers/sound/emu10k1/cardwo.h:1.2
--- linux/drivers/sound/emu10k1/cardwo.h:1.1	Thu Jun  1 16:52:15 2000
+++ linux/drivers/sound/emu10k1/cardwo.h	Fri Jul  7 15:36:45 2000
@@ -37,28 +37,21 @@
 struct wave_xferbuf 
 {
 	u32     xferpos;
+	u32     silence_xferpos;
 	u32     xferbufsize;     /* transfer buffer size */
 	u32     numpages;        /* number of pages in transfer buffer */
 	void    **xferbuffer;    /* pointer to the transfer buffer */
-	u32     format;
 	int     is_stereo;
-	int     is16bit;
-	u32     conv;
-	u32     interpolationbytes;
-	u32     offset;          /* used for non-pagealigned buffer in P10 */
+	int     is_16bit;
+	int	bytespersample;
 	u32     stopposition;
 };
 
-typedef struct tCARDMIXEROBJ  *PCARDMIXEROBJ;
-
 struct wave_out
 {
-    struct wave_out  *next;
-    u32             status;
     u32             state;
-    int              synchstart;
-    struct emu_voice *emu_voice;
-    struct emu_page *emuaddr;
+    struct emu_voice *voice;
+    int             emupageindex;
     struct emu_timer *timer;
     struct wave_xferbuf *wavexferbuf;
     void 	    **pagetable;
@@ -69,40 +62,21 @@
     u32             globalvolFactor;
     u32             globalreverbFactor;
     u32             globalchorusFactor;
-    u32             process_id;        /* used for synchonize start */
-    int              setpos;
+    int             setpos;
     u32             position;
-    short               ZL[6];              /* for pre-comp */
-    short               ZR[6];              /* for pre-comp */
     struct wave_format      wave_fmt;
-    u32             playflags;
-    struct tq_struct *task;
+    int             fill_silence;
 };
 
-
-/* sblive_wave states */
-#define CARDWAVE_STATE_STOPPED      0x0001
-#define CARDWAVE_STATE_STOPPING     0x0008
-#define CARDWAVE_STATE_STARTED      0x0002
-#define CARDWAVE_STATE_SUSPEND      0x0004
-
-
-/* Transfer buffer formats */
-#define M8                          0x00
-#define M16                         0x01
-#define S8                          0x02
-#define S16                         0x03
-
-#define INTERPOLATION_BYTES         8
 /* setting this to other than a power of two
    may break some applications */
-#define WAVEOUT_MAXBUFSIZE          16384
-#define WAVEOUT_MINBUFSIZE	    2048
+#define WAVEOUT_MAXBUFSIZE          32768 
+#define WAVEOUT_MINBUFSIZE	    64
 
 #define WAVEOUT_DEFAULTFRAGLEN      100 /* Time to play a fragment in ms (latency) */
 #define WAVEOUT_DEFAULTBUFLEN       1000 /* Time to play the entire buffer in ms */
 
-#define CARDWAVE_DEFAULT_MAXPLAYINST 64
+#define WAVEOUT_MINFRAGSHIFT	4
 
 struct woinst 
 {
@@ -115,52 +89,30 @@
         int mapped;
         u32 total_copied;
         u32 total_played;
-        int silence_filled;
-        u32 silence_start;
-        u32 getoptr_blocks;
-	u32 wave_ptr;
+        u32 blocks;
+	u32 curpos;
+	u32 device;
 	spinlock_t lock;
 };
 
-struct sblive_waveout
+struct emu10k1_waveout
 {
-    PCARDMIXEROBJ   mixer;
-    int          fWhql;
-
-    struct wave_caps	caps;
-    struct wave_out *wave_outlist;
-	
-    u32	numplaybackinst;
-    u32 maxnumplayinst;
-    u32 globalvol;
-    u32 mute;
-    u32 left;
-    u32 right;
-    u32 globalreverb;
-    u32 globalchorus;
-    u32 lineid;
-    u32 ctrlid;
+	u32 globalvol;
+	u32 mute;
+	u32 left;
+	u32 right;
+	u32 globalreverb;
+	u32 globalchorus;
 };
-
-int sblive_waveoutInit(struct sblive_waveout *, u8 *);
-int sblive_waveoutExit(struct sblive_waveout *);
-int sblive_waveoutQueryFormat(struct sblive_waveout *, struct wave_format *, u32);
-int sblive_waveoutOpen(struct sblive_hw *, struct wave_format *, u32 *, u32, struct wave_out **);
-int sblive_waveoutClose(struct sblive_hw *, struct wave_out *);
-int sblive_waveoutStart(struct sblive_wavedevice *);
-int sblive_waveoutStop(struct sblive_hw *, struct wave_out *, u32 *);
-int sblive_waveoutGetXferSize(struct sblive_waveout *, struct wave_out *, u32 *, u32 *);
-int sblive_waveoutXferData(struct sblive_waveout *, struct wave_out *, u8 *, u32 *);
-int sblive_waveoutFillSilence(struct sblive_waveout *, struct wave_out *, u32 *);
-int sblive_waveoutSetControl(struct sblive_hw *, struct wave_out *, u32, u32 *);
-int sblive_waveoutGetControl(struct sblive_waveout *, struct wave_out *, u32, u32 *);
-int sblive_emuAllocXferBuffer(struct sblive_hw *, struct wave_out *, u32 *, void ***);
-int sblive_emuGetXferBuffer(struct sblive_hw *, struct wave_out *, u32 *, void ***);
-int sblive_emuDeallocXferBuffer(struct wave_out *);
-void initWaveOutXferBuffer(struct wave_out *);
-int sblive_waveoutSynchStart(struct sblive_waveout *, u32);
 
-int sblive_mixerLineChange(PCARDMIXEROBJ, u32, u32);
-int sblive_mixerSetControlValue(PCARDMIXEROBJ, u32, u32, u32, u32, u32);
+int emu10k1_waveout_open(struct emu10k1_wavedevice *);
+void emu10k1_waveout_close(struct emu10k1_wavedevice *);
+int emu10k1_waveout_start(struct emu10k1_wavedevice *);
+void emu10k1_waveout_stop(struct emu10k1_wavedevice *);
+void emu10k1_waveout_getxfersize(struct wave_out *, u32 *, u32 *, u32 *);
+void emu10k1_waveout_xferdata(struct woinst*, u8*, u32 *);
+void emu10k1_waveout_fillsilence(struct woinst*);
+int emu10k1_waveout_setformat(struct emu10k1_wavedevice*);
+int emu10k1_waveout_getcontrol(struct wave_out*, u32, u32 *);
 
 #endif /* _CARDWO_H */
Index: oldkernel/linux/drivers/sound/emu10k1/efxmgr.c
diff -u linux/drivers/sound/emu10k1/efxmgr.c:1.1 linux/drivers/sound/emu10k1/efxmgr.c:1.2
--- linux/drivers/sound/emu10k1/efxmgr.c:1.1	Thu Jun  1 16:52:15 2000
+++ linux/drivers/sound/emu10k1/efxmgr.c	Fri Jul  7 15:36:45 2000
@@ -1,3 +1,4 @@
+
 /*     
  **********************************************************************
  *     sblive_fx.c
@@ -31,160 +32,3 @@
 
 #include "hwaccess.h"
 #include "efxmgr.h"
-
-int sblive_fxInit(struct sblive_hw *sb_hw)
-{
-	int i;
-	u32 z, w, x, y, pc = 16;
-
-	for (i = 0; i < 512; i++) 
-	{
-		WRITE_EFX(sb_hw, i * 2, 0x10040);
-		WRITE_EFX(sb_hw, i * 2 + 1, 0x610040);
-	}
-
-	for (i = 0; i < 256; i++)
-	  sblive_writeptr(sb_hw, FXGPREGBASE + i, 0, 0);
-
-	w = 0x40;
-	x = 1;
-	y = 0x44;
-	z = 0x101;
-	WRITE_EFX(sb_hw, pc * 2, (x << 10) | y);
-	WRITE_EFX(sb_hw, pc * 2 + 1, (4 << 20) | (z << 10) | w);
-	++pc;
-
-	w = 0x101;
-	x = 0x115;
-	y = 0x11;
-	z = 0x101;
-	WRITE_EFX(sb_hw, pc * 2, (x << 10) | y);
-	WRITE_EFX(sb_hw, pc * 2 + 1, (0 << 20) | (z << 10) | w);
-	++pc;
-
-	w = 0x101;
-	x = 0x113;
-	y = 0x13;
-	z = 0x101;
-	WRITE_EFX(sb_hw, pc * 2, (x << 10) | y);
-	WRITE_EFX(sb_hw, pc * 2 + 1, (0 << 20) | (z << 10) | w);
-	++pc;
-
-	w = 0x101;
-	x = 0x40;
-	y = 0x40;
-	z = 0x21;
-	WRITE_EFX(sb_hw, pc * 2, (x << 10) | y);
-	WRITE_EFX(sb_hw, pc * 2 + 1, (6 << 20) | (z << 10) | w);
-	++pc;
-
-	z = 0x23;
-	WRITE_EFX(sb_hw, pc * 2, (x << 10) | y);
-	WRITE_EFX(sb_hw, pc * 2 + 1, (6 << 20) | (z << 10) | w);
-	++pc;
-
-	w = 0x40;
-	x = 0x40;
-	y = 0x40;
-	z = 0x25;
-	WRITE_EFX(sb_hw, pc * 2, (x << 10) | y);
-	WRITE_EFX(sb_hw, pc * 2 + 1, (6 << 20) | (z << 10) | w);
-	++pc;
-
-	z = 0x27;
-	WRITE_EFX(sb_hw, pc * 2, (x << 10) | y);
-	WRITE_EFX(sb_hw, pc * 2 + 1, (6 << 20) | (z << 10) | w);
-	++pc;
-
-	w = 0x40;
-	x = 0x111;
-	y = 0x101;
-	z = 0x29;
-	WRITE_EFX(sb_hw, pc * 2, (x << 10) | y);
-	WRITE_EFX(sb_hw, pc * 2 + 1, (0 << 20) | (z << 10) | w);
-	++pc;
-
-	w = 0x40;
-	x = 0x11;
-	y = 0x40;
-	z = 0x2B;
-	WRITE_EFX(sb_hw, pc * 2, (x << 10) | y);
-	WRITE_EFX(sb_hw, pc * 2 + 1, (6 << 20) | (z << 10) | w);
-	++pc;
-
-	w = 0x40;
-	x = 0;
-	y = 0x44;
-	z = 0x100;
-	WRITE_EFX(sb_hw, pc * 2, (x << 10) | y);
-	WRITE_EFX(sb_hw, pc * 2 + 1, (4 << 20) | (z << 10) | w);
-	++pc;
-
-	w = 0x100;
-	x = 0x114;
-	y = 0x10;
-	z = 0x100;
-	WRITE_EFX(sb_hw, pc * 2, (x << 10) | y);
-	WRITE_EFX(sb_hw, pc * 2 + 1, (0 << 20) | (z << 10) | w);
-	++pc;
-
-	w = 0x100;
-	x = 0x112;
-	y = 0x12;
-	z = 0x100;
-	WRITE_EFX(sb_hw, pc * 2, (x << 10) | y);
-	WRITE_EFX(sb_hw, pc * 2 + 1, (0 << 20) | (z << 10) | w);
-	++pc;
-
-	w = 0x100;
-	x = 0x40;
-	y = 0x40;
-	z = 0x20;
-	WRITE_EFX(sb_hw, pc * 2, (x << 10) | y);
-	WRITE_EFX(sb_hw, pc * 2 + 1, (6 << 20) | (z << 10) | w);
-	++pc;
-
-	z = 0x22;
-	WRITE_EFX(sb_hw, pc * 2, (x << 10) | y);
-	WRITE_EFX(sb_hw, pc * 2 + 1, (6 << 20) | (z << 10) | w);
-	++pc;
-
-	w = 0x40;
-	x = 0x40;
-	y = 0x40;
-	z = 0x24;
-	WRITE_EFX(sb_hw, pc * 2, (x << 10) | y);
-	WRITE_EFX(sb_hw, pc * 2 + 1, (6 << 20) | (z << 10) | w);
-	++pc;
-
-	z = 0x26;
-	WRITE_EFX(sb_hw, pc * 2, (x << 10) | y);
-	WRITE_EFX(sb_hw, pc * 2 + 1, (6 << 20) | (z << 10) | w);
-	++pc;
-
-	w = 0x40;
-	x = 0x110;
-	y = 0x100;
-	z = 0x28;
-	WRITE_EFX(sb_hw, pc * 2, (x << 10) | y);
-	WRITE_EFX(sb_hw, pc * 2 + 1, (0 << 20) | (z << 10) | w);
-	++pc;
-
-	w = 0x40;
-	x = 0x10;
-	y = 0x40;
-	z = 0x2A;
-	WRITE_EFX(sb_hw, pc * 2, (x << 10) | y);
-	WRITE_EFX(sb_hw, pc * 2 + 1, (6 << 20) | (z << 10) | w);
-	++pc;
-
-	sblive_writeptr(sb_hw, DBG, 0, 0);
-
-	return CTSTATUS_SUCCESS;
-}
-
-/* FIXME: We should probably be doing something here */
-int sblive_fxExit(struct sblive_hw *sb_hw)
-{
-	return CTSTATUS_SUCCESS;
-}
Index: oldkernel/linux/drivers/sound/emu10k1/efxmgr.h
diff -u linux/drivers/sound/emu10k1/efxmgr.h:1.1 linux/drivers/sound/emu10k1/efxmgr.h:1.2
--- linux/drivers/sound/emu10k1/efxmgr.h:1.1	Thu Jun  1 16:52:15 2000
+++ linux/drivers/sound/emu10k1/efxmgr.h	Fri Jul  7 15:36:45 2000
@@ -32,7 +32,12 @@
 #ifndef _EFXMGR_H
 #define _EFXMGR_H
 
-int sblive_fxInit(struct sblive_hw *);
-int sblive_fxExit(struct sblive_hw *);
+#define WRITE_EFX(a, b, c) sblive_writeptr((a), MICROCODEBASE + (b), 0, (c))
+
+#define OP(op, z, w, x, y) \
+        do { WRITE_EFX(card, (pc) * 2, ((x) << 10) | (y)); \
+        WRITE_EFX(card, (pc) * 2 + 1, ((op) << 20) | ((z) << 10) | (w)); \
+        ++pc; } while (0)
+
 
 #endif /* _EFXMGR_H */
Index: oldkernel/linux/drivers/sound/emu10k1/emu_wrapper.h
diff -u linux/drivers/sound/emu10k1/emu_wrapper.h:1.1 linux/drivers/sound/emu10k1/emu_wrapper.h:1.2
--- linux/drivers/sound/emu10k1/emu_wrapper.h:1.1	Thu Jun  1 16:52:15 2000
+++ linux/drivers/sound/emu10k1/emu_wrapper.h	Fri Jul  7 15:36:45 2000
@@ -5,21 +5,81 @@
 
 #include <linux/wrapper.h>
 
-#define vma_get_pgoff(v)	 vma_get_offset(v)
-#define wait_queue_head_t	 struct wait_queue *
-#define DECLARE_WAITQUEUE(a, b)  struct wait_queue a = {b, NULL};
-#define init_waitqueue_head(a)	 init_waitqueue(a)
+#define vma_get_pgoff(v)	vma_get_offset(v)
+#define wait_queue_head_t	struct wait_queue *
+#define DECLARE_WAITQUEUE(a, b)	struct wait_queue a = {b, NULL};
+#define init_waitqueue_head(a)	init_waitqueue(a)
 
-#define RSRCADDRESS(dev,num)    ((dev)->base_address[(num)])
+#define init_MUTEX(a)		*(a) = MUTEX
 
-#define RSRCISIOREGION(dev,num) (RSRCADDRESS(dev,num) != 0 && \
-	(RSRCADDRESS(dev,num) & PCI_BASE_ADDRESS_SPACE) == PCI_BASE_ADDRESS_SPACE_IO)
-
-#define init_MUTEX(a) *(a) = MUTEX
-
 #define UP_INODE_SEM(a)		up(a)
 #define DOWN_INODE_SEM(a)	down(a)
 
 #define GET_INODE_STRUCT()	struct inode *inode = file->f_dentry->d_inode
+
+#define tasklet_hi_schedule(t)	queue_task((t), &tq_immediate); \
+				mark_bh(IMMEDIATE_BH)
+
+#define tasklet_init(t,f,d)	(t)->next = NULL; \
+				(t)->sync = 0; \
+				(t)->routine = (void (*)(void *))(f); \
+				(t)->data = (void *)(d)
+
+#define tasklet_struct		tq_struct 
+
+#define tasklet_unlock_wait(t)	while (test_bit(0, &(t)->sync)) { }
+
+struct pci_device_id {
+        unsigned int vendor, device;
+        unsigned int subvendor, subdevice;
+        unsigned int class, class_mask;
+        unsigned long driver_data;
+};
+
+#define PCI_ANY_ID (~0)
+
+#define MODULE_DEVICE_TABLE(type,name)
+
+#define pci_enable_device(dev) 1 
+
+#define pci_dma_supported(dev, mask) 0
+
+struct pci_driver {
+        struct list_head node;
+        char *name;
+        const struct pci_device_id *id_table;
+        int (*probe)(struct pci_dev *dev, const struct pci_device_id *id);
+        void (*remove)(struct pci_dev *dev);
+        void (*suspend)(struct pci_dev *dev);
+        void (*resume)(struct pci_dev *dev);
+};
+
+static __inline__ void list_add_tail(struct list_head *new, struct list_head *head)
+{
+        __list_add(new, head->prev, head);
+}
+
+#define list_for_each(pos, head) \
+        for (pos = (head)->next; pos != (head); pos = pos->next)
+
+#define __exit
+
+#ifndef MODULE
+#define module_init(x)		int init_emu10k1(void) { return x(); }	
+#define module_exit(x)
+#else
+#define module_init(x)		int init_module(void) { return x(); }
+#define module_exit(x)		void cleanup_module(void) { x(); }
+#endif
+
+#ifdef CONFIG_HOTPLUG
+#define __devinit
+#define __devinitdata
+#define __devexit
+#else
+#define __devinit __init
+#define __devinitdata __initdata
+#define __devexit __exit
+#endif
 
 #endif
Index: oldkernel/linux/drivers/sound/emu10k1/emuadxmg.c
diff -u linux/drivers/sound/emu10k1/emuadxmg.c:1.1 linux/drivers/sound/emu10k1/emuadxmg.c:1.2
--- linux/drivers/sound/emu10k1/emuadxmg.c:1.1	Thu Jun  1 16:52:15 2000
+++ linux/drivers/sound/emu10k1/emuadxmg.c	Fri Jul  7 15:36:45 2000
@@ -1,3 +1,4 @@
+
 /*     
  **********************************************************************
  *     emuadxmg.c - Address space manager for emu10k1 driver 
@@ -30,233 +31,71 @@
  */
 
 #include "hwaccess.h"
-
-/************************************************************************
-*
-*   int emu10kaddxmgrInit(struct sblive_hw * sb_hw)
-*
-*   ENTRY
-*       sb_hw  -    Pointer to the HWOBJ to init voice manager
-*
-*   RETURNS
-*       Always returns CTSTATUS_SUCCESS
-*
-*   ABOUT
-*       Inits data
-*
-************************************************************************/
-int emu10kaddxmgrInit(struct sblive_hw *sb_hw)
-{
-	u32 count;
-
-	for (count = 0; count < MAXPAGES; count++) 
-	  sb_hw->emu_addrmgr.emupagetable[count].flags = 0;
-
-	/* Mark first page as used */
-	/* This page is reserved by the driver */
-	sb_hw->emu_addrmgr.emupagetable[0].flags = 0x8001;
-	sb_hw->emu_addrmgr.emupagetable[1].flags = MAXPAGES - RESERVED - 1;
-
-	return CTSTATUS_SUCCESS;
-}
-
 
-/************************************************************************
-*
-*   int emu10kaddxmgrExit(struct sblive_hw * sb_hw)
-*
-*   ENTRY
-*       sb_hw  -    Pointer to the HWOBJ to exit
-*
-*   RETURNS
-*       Always returns CTSTATUS_SUCCESS
-*
-*   ABOUT
-*       Exits
-*
-************************************************************************/
-int emu10kaddxmgrExit(struct sblive_hw *sb_hw)
-{
-	u32 count;
-
-	/* TODO : callback all address owners */
-
-	for (count = 0; count < MAXPAGES; count++)
-	  sb_hw->emu_addrmgr.emupagetable[count].flags = 0;
-	
-	sb_hw->emu_addrmgr.emupagetable[0].flags = MAXPAGES - RESERVED;
-
-	return CTSTATUS_SUCCESS;
-}
-
+/* Allocates emu address space */
 
-/************************************************************************
-*
-*   u32 emu10kaddxmgrMaxContigPages(struct sblive_hw * sb_hw)
-*
-*   ENTRY
-*       sb_hw  -    Pointer to the HWOBJ to check
-*
-*   RETURNS
-*       largest free contiguous block in pages
-*
-*   ABOUT
-*       Gets largest free contiguous block in pages
-*
-************************************************************************/
-u32 emu10kaddxmgrMaxContigPages(struct sblive_hw *sb_hw)
+int emu10k1_addxmgr_alloc(u32 size, struct emu10k1_card *card)
 {
-	u32 maxpages = 0;
-	u16 pageindex = 0;
-	struct emu_addrmgr *mgr;
-
-	mgr = &sb_hw->emu_addrmgr;
-
-	while (pageindex < (MAXPAGES - RESERVED - 1)) 
-	{
-		if (mgr->emupagetable[pageindex].flags & 0x8000) 
-		{
-			/* This block of pages is in use, jump to the start of the next block */
-			pageindex += (mgr->emupagetable[pageindex].flags & 0x7fff);
-		} else 
-		{ 
-			/* Found free block */
-			if (mgr->emupagetable[pageindex].flags > (u16) maxpages) 
-			  maxpages = mgr->emupagetable[pageindex].flags; /* Block is large enough */
-			else 
-			  pageindex += mgr->emupagetable[pageindex].flags; /* Block too small - jump to the start of the next block */
-		}
-	}
-
-	return maxpages;
-}
-
-
-/************************************************************************
-*
-*   int emu10kaddxmgrAlloc(struct emuaddr_allocdesc * emuaddrAllocDesc,
-*                         struct emu_page **pemuaddrObj)
-*
-*   ENTRY
-*       emuaddrAllocDesc -
-*           Pointer to a struct emuaddr_allocdesc that describes the
-*           address space needed.
-*
-*       pemuaddrObj      -
-*           Address to return allocated struct emu_page
-*
-*   RETURNS
-*       SUCCESS -   CTSTATUS_SUCCESS
-*       FAILURE -   CTSTATUS_NOMEMORY (not enough available address space)
-*
-*   ABOUT
-*       Allocates emu address space
-*
-************************************************************************/
-int emu10kaddxmgrAlloc(struct emuaddr_allocdesc *allocdesc, struct emu_page **emu_pageptr)
-{
-	struct sblive_hw * sb_hw;
-	u32 emupageindex = 0;
-	u32 pages;
-	struct emu_page * pemupagetable;
+	u16 *pagetable = card->emupagetable;
+	u16 index = 0;
+	u16 numpages;
 	unsigned long flags;
 
-	sb_hw = allocdesc->sb_hw;
-	pemupagetable = sb_hw->emu_addrmgr.emupagetable;
-	*emu_pageptr = NULL;
-
 	/* Convert bytes to pages */
-	pages = (allocdesc->size / PAGE_SIZE) +
-	    ((allocdesc->size % PAGE_SIZE) ? 1 : 0);
+	numpages = (size / EMUPAGESIZE) + ((size % EMUPAGESIZE) ? 1 : 0);
 
-	while (emupageindex < (MAXPAGES - RESERVED - 1)) 
-	{
-		if (pemupagetable[emupageindex].flags & 0x8000) 
-		{
+	while (index < (MAXPAGES - RESERVED - 1)) {
+		if (pagetable[index] & 0x8000) {
 			/* This block of pages is in use, jump to the start of the next block. */
-			emupageindex += (pemupagetable[emupageindex].flags & 0x7fff);
-		} else 
-		{
+			index += (pagetable[index] & 0x7fff);
+		} else {
 			/* Found free block */
-			if (pemupagetable[emupageindex].flags >= (u16) pages) 
-			{
-				spin_lock_irqsave(&sb_hw->emu_lock, flags);
+			if (pagetable[index] >= numpages) {
+				spin_lock_irqsave(&card->lock, flags);
 
 				/* Block is large enough */
-				
+
 				/* If free block is larger than the block requested
 				 * then adjust the size of the block remaining */
-				if (pemupagetable[emupageindex].flags > (u16) pages) 
-				  pemupagetable[emupageindex + pages].flags = pemupagetable[emupageindex].flags - (u16) pages;
-				
-				pemupagetable[emupageindex].flags = (u16) (pages | 0x8000); /* Mark block as used */
-
-				/* Return emu address */
-				pemupagetable[emupageindex].sb_hw = sb_hw;
-				pemupagetable[emupageindex].emustartaddr = emupageindex << 11;
-				*emu_pageptr = &pemupagetable[emupageindex];
-
-				spin_unlock_irqrestore(&sb_hw->emu_lock, flags);
-
-				return CTSTATUS_SUCCESS;
-			} else 
-			{
+				if (pagetable[index] > numpages)
+					pagetable[index + numpages] = pagetable[index] - numpages;
+
+				pagetable[index] = (numpages | 0x8000);	/* Mark block as used */
+
+				spin_unlock_irqrestore(&card->lock, flags);
+
+				return index;
+			} else {
 				/* Block too small, jump to the start of the next block */
-				emupageindex += pemupagetable[emupageindex].flags;
+				index += pagetable[index];
 			}
 		}
 	}
 
-	return CTSTATUS_NOMEMORY;
+	return -1;
 }
+
+/* Frees a previously allocated emu address space. */
 
-/************************************************************************
-*
-*   int emu10kaddxmgrFree(struct emu_page * emuaddrObj)
-*
-*   ENTRY
-*       emuaddrObj -
-*           pointer to a struct emu_page returned
-*           by a call to emu10kaddxmgrAlloc()
-*
-*   RETURNS
-*       SUCCESS -   CTSTATUS_SUCCESS
-*       FAILURE -   CTSTATUS_ERROR
-*
-*   ABOUT
-*       Frees a previously allocated emu address space.
-*
-************************************************************************/
-int emu10kaddxmgrFree(struct emu_page *page)
+void emu10k1_addxmgr_free(struct emu10k1_card *card, int index)
 {
-	struct sblive_hw * sb_hw;
+	u16 *pagetable = card->emupagetable;
 	u16 origsize = 0;
-	u32 pageindex;
-	struct emu_page * pemupagetable;
 	unsigned long flags;
 
-	sb_hw = page->sb_hw;
-	spin_lock_irqsave(&sb_hw->emu_lock, flags);
+	spin_lock_irqsave(&card->lock, flags);
 
-	pemupagetable = sb_hw->emu_addrmgr.emupagetable;
-	pageindex = page->emustartaddr;
-
-	/* Convert Emu address to Emu page number */
-	pageindex >>= 11;
-
-	if (pemupagetable[pageindex].flags & 0x8000) 
-	{
+	if (pagetable[index] & 0x8000) {
 		/* Block is allocated - mark block as free */
-		origsize = pemupagetable[pageindex].flags & 0x7fff;
-		pemupagetable[pageindex].flags = origsize;
-		pemupagetable[pageindex].emustartaddr = 0;
+		origsize = pagetable[index] & 0x7fff;
+		pagetable[index] = origsize;
 
 		/* If next block is free, we concat both blocks */
-		if (!(pemupagetable[pageindex + origsize].flags & 0x8000)) 
-		  pemupagetable[pageindex].flags += pemupagetable[pageindex + origsize].flags & 0x7fff;
+		if (!(pagetable[index + origsize] & 0x8000))
+			pagetable[index] += pagetable[index + origsize] & 0x7fff;
 	}
-	
-	spin_unlock_irqrestore(&sb_hw->emu_lock, flags);
+
+	spin_unlock_irqrestore(&card->lock, flags);
 
-	return origsize;
+	return;
 }
Index: oldkernel/linux/drivers/sound/emu10k1/hwaccess.c
diff -u linux/drivers/sound/emu10k1/hwaccess.c:1.1 linux/drivers/sound/emu10k1/hwaccess.c:1.2
--- linux/drivers/sound/emu10k1/hwaccess.c:1.1	Thu Jun  1 16:52:15 2000
+++ linux/drivers/sound/emu10k1/hwaccess.c	Fri Jul  7 15:36:45 2000
@@ -1,3 +1,4 @@
+
 /*
  **********************************************************************
  *     hwaccess.c -- Hardware access layer
@@ -31,383 +32,22 @@
  */
 
 #include "hwaccess.h"
-#include "mycommon.h"
-#include "emu_wrapper.h"
-
-
-spinlock_t sblive_spinlock = SPIN_LOCK_UNLOCKED;
-
-int halHWInit(struct sblive_hw *sb_hw);
-
-int halInit(struct sblive_hw *sb_hw, struct sblive_config *config, u32 *hwflags)
-{
-	unsigned long ioaddr;
-
-	/* should fill in default values here */
-	sb_hw->paneffectsbus = 0;
-	sb_hw->auxeffectsbus = 1;
-	sb_hw->choruseffectsbus = 2;
-	sb_hw->reverbeffectsbus = 3;
-
-	/* Setup Critical Sections */
-	spin_lock_init(&sb_hw->emu_lock);
-
-	sb_hw->numvoices = NUM_G;
-	sb_hw->dsCardCfg = *config;
-
-	sb_hw->hwaddr = config->ioportbase[0];
-	ioaddr = config->ioportbase[0];
-
-	sb_hw->mixeraddx = (u32) (ioaddr + AC97DATA);
-	sb_hw->hwconfigaddx = (u32) (ioaddr + HCFG);
-
-	sb_hw->hw_irq.irq = config->IRQregs[0];
-	if (sb_hw->hw_irq.irq)
-	{
-		if (sb_hw->hw_irq.irq == 2)
-			sb_hw->hw_irq.irq = 9;
-	}
-
-	sb_hw->hw_irq.sb_hw = sb_hw;
-
-	/* Init Card */
-	if (halHWInit(sb_hw) != CTSTATUS_SUCCESS)
-		return CTSTATUS_ERROR;
-
-	if (sblive_irqmgrInit(&sb_hw->hw_irq) != CTSTATUS_SUCCESS)
-	{
-		DPF(2, "Failed to initialize IRQ manager\n");
-		sb_hw->hw_irq.irq = 0;
-	}
-
-	sblive_voiceInit(sb_hw);
-	sblive_timerinit(sb_hw);
-	emu10kaddxmgrInit(sb_hw);
-
-	DPD(2, "  hw control register -> %x\n", sblive_readfn0(sb_hw, HCFG));
-
-	return CTSTATUS_SUCCESS;
-}
-
+#include "icardmid.h"
 
-/****************************************************************************/
-/*   halExit(struct sblive_hw * sb_hw)                                      */
-/****************************************************************************/
-int halExit(struct sblive_hw * sb_hw)
-{
-	int ch;
-
-	sblive_voiceExit(sb_hw);
-	emu10kaddxmgrExit(sb_hw);
-
-	if (sb_hw->hw_irq.irq)
-	{
-		sblive_writefn0(sb_hw,INTE, DISABLE);
-		sblive_irqmgrExit(&sb_hw->hw_irq);
-	}
-
-	/** Shutdown the chip **/
-	for (ch = 0; ch < NUM_G; ch++)
-		sblive_writeptr(sb_hw, DCYSUSV, ch, ENV_OFF);
-
-	for (ch = 0; ch < NUM_G; ch++)
-	{
-		sblive_writeptr(sb_hw, VTFT, ch, 0);
-		sblive_writeptr(sb_hw, CVCF, ch, 0);
-		sblive_writeptr(sb_hw, PTRX, ch, 0);
-		sblive_writeptr(sb_hw, CPF, ch, 0);
-	}
-
-	/* Reset recording buffers */
-	sblive_writeptr(sb_hw, MICBS, 0, 0);
-	sblive_writeptr(sb_hw, MICBA, 0, 0);
-	sblive_writeptr(sb_hw, FXBS, 0, 0);
-	sblive_writeptr(sb_hw, FXBA, 0, 0);
-	sblive_writeptr(sb_hw, FXWC, 0, 0);
-	sblive_writeptr(sb_hw, ADCBS, 0, ADCBS_BUFSIZE_NONE);
-	sblive_writeptr(sb_hw, ADCBA, 0, 0);
-	sblive_writeptr(sb_hw, TCBS, 0, TCBS_BUFFSIZE_16K);
-	sblive_writeptr(sb_hw, TCB, 0, 0);
-	sblive_writeptr(sb_hw, DBG, 0, 0x8000);
-
-	/* Disable channel interrupt */
-	sblive_writeptr(sb_hw, CLIEL, 0, 0);
-	sblive_writeptr(sb_hw, CLIEH, 0, 0);
-	sblive_writeptr(sb_hw, SOLEL, 0, 0);
-	sblive_writeptr(sb_hw, SOLEH, 0, 0);
-
-	/* Disable audio and lock cache */
-	sblive_writefn0(sb_hw, HCFG, HCFG_LOCKSOUNDCACHE | HCFG_LOCKTANKCACHE | HCFG_MUTEBUTTONENABLE);
-	sblive_writeptr(sb_hw, PTB, 0, 0);
-
-	osFreeMemPhysical(&sb_hw->silentpage);
-	osFreeMemPhysical(&sb_hw->virtualpagetable);
-	osFreeMemPhysical(&sb_hw->tankmem);
-
-	return CTSTATUS_SUCCESS;
-}
-
-
-/****************************************************************************/
-/*  halHWInit (struct sblive_hw *sb_hw)                                     */
-/****************************************************************************/
-int halHWInit(struct sblive_hw *sb_hw)
-{
-	int nCh;
-	u32 size = 0;
-	u32 sizeIdx = 0;
-	u16 count;
-	int status;
-
-	/* Disable audio and lock cache */
-	sblive_writefn0(sb_hw, HCFG, HCFG_LOCKSOUNDCACHE | HCFG_LOCKTANKCACHE | HCFG_MUTEBUTTONENABLE);
-
-	/* Reset recording buffers */
-	sblive_writeptr(sb_hw, MICBS, 0, 0);
-	sblive_writeptr(sb_hw, MICBA, 0, 0);
-	sblive_writeptr(sb_hw, FXBS, 0, 0);
-	sblive_writeptr(sb_hw, FXBA, 0, 0);
-	sblive_writeptr(sb_hw, ADCBS, 0, ADCBS_BUFSIZE_NONE);
-	sblive_writeptr(sb_hw, ADCBA, 0, 0);
-
-	/* Disable channel interrupt */
-	sblive_writefn0(sb_hw,INTE, DISABLE);
-	sblive_writeptr(sb_hw, CLIEL, 0, 0);
-	sblive_writeptr(sb_hw, CLIEH, 0, 0);
-	sblive_writeptr(sb_hw, SOLEL, 0, 0);
-	sblive_writeptr(sb_hw, SOLEH, 0, 0);
-
-	/* Init envelope engine */
-	for (nCh = 0; nCh < NUM_G; nCh++)
-	{
-		sblive_writeptr(sb_hw, DCYSUSV, nCh, ENV_OFF);
-		sblive_writeptr(sb_hw, IP, nCh, 0);
-		sblive_writeptr(sb_hw, VTFT, nCh, 0xffff);
-		sblive_writeptr(sb_hw, CVCF, nCh, 0xffff);
-		sblive_writeptr(sb_hw, PTRX, nCh, 0);
-		sblive_writeptr(sb_hw, CPF, nCh, 0);
-		sblive_writeptr(sb_hw, CCR, nCh, 0);
-
-		sblive_writeptr(sb_hw, PSST, nCh, 0);
-		sblive_writeptr(sb_hw, DSL, nCh, 0x10);
-		sblive_writeptr(sb_hw, CCCA, nCh, 0);
-		sblive_writeptr(sb_hw, Z1, nCh, 0);
-		sblive_writeptr(sb_hw, Z2, nCh, 0);
-		sblive_writeptr(sb_hw, FXRT, nCh, 0xd01c0000);
-
-		sblive_writeptr(sb_hw, ATKHLDM, nCh, 0);
-		sblive_writeptr(sb_hw, DCYSUSM, nCh, 0);
-		sblive_writeptr(sb_hw, IFATN, nCh, 0xffff);
-		sblive_writeptr(sb_hw, PEFE, nCh, 0);
-		sblive_writeptr(sb_hw, FMMOD, nCh, 0);
-		sblive_writeptr(sb_hw, TREMFRQ, nCh, 24);	/* 1 Hz */
-		sblive_writeptr(sb_hw, FM2FRQ2, nCh, 24);	/* 1 Hz */
-		sblive_writeptr(sb_hw, TEMPENV, nCh, 0);
-
-		/*** These are last so OFF prevents writing ***/
-		sblive_writeptr(sb_hw, LFOVAL2, nCh, 0);
-		sblive_writeptr(sb_hw, LFOVAL1, nCh, 0);
-		sblive_writeptr(sb_hw, ATKHLDV, nCh, 0);
-		sblive_writeptr(sb_hw, ENVVOL, nCh, 0);
-		sblive_writeptr(sb_hw, ENVVAL, nCh, 0);
-	}
-
-
-	/*
-	 ** Init to 0x02109204 :
-	 ** Clock accuracy    = 0     (1000ppm)
-	 ** Sample Rate       = 2     (48kHz)
-	 ** Audio Channel     = 1     (Left of 2)
-	 ** Source Number     = 0     (Unspecified)
-	 ** Generation Status = 1     (Original for Cat Code 12)
-	 ** Cat Code          = 12    (Digital Signal Mixer)
-	 ** Mode              = 0     (Mode 0)
-	 ** Emphasis          = 0     (None)
-	 ** CP                = 1     (Copyright unasserted)
-	 ** AN                = 0     (Digital audio)
-	 ** P                 = 0     (Consumer)
-	 */
-
-	sblive_writeptr(sb_hw, SPCS0, 0, SPCS_CLKACCY_1000PPM | 0x002000000 |
-			SPCS_CHANNELNUM_LEFT | SPCS_SOURCENUM_UNSPEC|
-			SPCS_GENERATIONSTATUS | 0x00001200 |
-			SPCS_EMPHASIS_NONE | SPCS_COPYRIGHT);	/* SPDIF0 */
-
-	sblive_writeptr(sb_hw, SPCS1, 0, SPCS_CLKACCY_1000PPM | 0x002000000 |
-			SPCS_CHANNELNUM_LEFT | SPCS_SOURCENUM_UNSPEC|
-			SPCS_GENERATIONSTATUS | 0x00001200 |
-			SPCS_EMPHASIS_NONE | SPCS_COPYRIGHT);	/* SPDIF1 */
-
-	sblive_writeptr(sb_hw, SPCS2, 0, SPCS_CLKACCY_1000PPM | 0x002000000 |
-			SPCS_CHANNELNUM_LEFT | SPCS_SOURCENUM_UNSPEC|
-			SPCS_GENERATIONSTATUS | 0x00001200 |
-			SPCS_EMPHASIS_NONE | SPCS_COPYRIGHT);	/* SPDIF2 & SPDIF3 */
-
-	sblive_fxInit(sb_hw);	/* initialize effects engine */
-
-#ifdef TANKMEM
-	size = TMEMSIZE;
-	sizeIdx = TMEMSIZEREG;
-	while (size > 16384)
-	{
-		status = osAllocMemPhysical(size,&sb_hw->tankmem);
-
-		if(status == CTSTATUS_SUCCESS)
-			break;
-
-		size /= 2;
-		sizeIdx -= 1;
-	}
-
-	if(status != CTSTATUS_SUCCESS){
-		sb_hw->tmemsize = 0;
-		return CTSTATUS_ERROR;
-	}
-
-	sb_hw->tmemsize = size;
-
-#else /* !TANKMEM */
-	sb_hw->tankmem = NULL;
-	sb_hw->tmemsize = 0;
-#endif /* TANKMEM */
-
-	status = osAllocMemPhysical((MAXPAGES - RESERVED) * sizeof(u32),&sb_hw->virtualpagetable);
-
-	if (status != CTSTATUS_SUCCESS)
-	{
-		DPF(2, "Failed to allocate physical memory (1)\n");
-		osFreeMemPhysical(&sb_hw->tankmem);
-		return status;
-	}
-
-	status = osAllocMemPhysical(EMUPAGESIZE, &sb_hw->silentpage);
-
-	if (status != CTSTATUS_SUCCESS)
-	{
-		DPF(2, "Failed to allocate physical memory (2)\n");
-		osFreeMemPhysical(&sb_hw->tankmem);
-		osFreeMemPhysical(&sb_hw->virtualpagetable);
-		return status;
-	} else
-		memset(sb_hw->silentpage->virtaddx, 0, EMUPAGESIZE); /* FIXME: Use bzero() */
-
-	/* Init page table */
-	/* All the entries are inialized to point to themselves */
-	/* so that when illegal memory access occurs, the system */
-	/* won't hang. */
-	for (count = 0; count < (MAXPAGES - RESERVED); count++)
-		((u32 *) sb_hw->virtualpagetable->virtaddx)[count] = (sb_hw->silentpage->physaddx * 2) | count;
-
-	/* Init page table & tank memory base register */
-	/* is this correct? PTB_MASK is 0xfffff000, it may be a 4k alignment... */
-	sblive_writeptr(sb_hw, PTB, 0, sb_hw->virtualpagetable->physaddx);
-#ifdef TANKMEM
-	sblive_writeptr(sb_hw, TCB, 0, sb_hw->tankmem->physaddx);
-#else
-	sblive_writeptr(sb_hw, TCB, 0, 0);
-#endif
-	sblive_writeptr(sb_hw, TCBS, 0, sizeIdx);
-
-	for (nCh = 0; nCh < NUM_G; nCh++)
-	{
-		sblive_writeptr(sb_hw, MAPA, nCh, MAP_PTI_MASK | (sb_hw->silentpage->physaddx * 2));
-		sblive_writeptr(sb_hw, MAPB, nCh, MAP_PTI_MASK | (sb_hw->silentpage->physaddx * 2));
-	}
-
-	/* Hokay, now enable the AUD bit */
-	/* Enable Audio = 1 */
-	/* Mute Disable Audio = 0 */
-	/* Lock Tank Memory = 1 */
-	/* Lock Sound Memory = 0 */
-	/* Auto Mute = 1 */
-
-	sblive_rmwac97(sb_hw, AC97_MASTERVOLUME, 0x8000, 0x8000);
-
-	sblive_writeac97(sb_hw, AC97_MASTERVOLUME, 0);
-	sblive_writeac97(sb_hw, AC97_PCMOUTVOLUME, 0);
-
-	if (sb_hw->dsCardCfg.chiprev < 6)
-		sblive_writefn0(sb_hw, HCFG, HCFG_AUDIOENABLE | HCFG_LOCKTANKCACHE | HCFG_AUTOMUTE);
-	else
-		/* With on-chip joystick */
-		sblive_writefn0(sb_hw, HCFG, HCFG_AUDIOENABLE | HCFG_LOCKTANKCACHE | HCFG_AUTOMUTE | HCFG_JOYENABLE);
-	/* TOSLink detection */
-	sb_hw->has_toslink = 0;
-
-	size = sblive_readfn0(sb_hw, HCFG);
-	if (size & (HCFG_GPINPUT0 | HCFG_GPINPUT1))
-	{
-		volatile unsigned delay;
-		sblive_writefn0(sb_hw, HCFG, size | 0x800);
-
-		for (delay = 0; delay < 512; delay++); 	/* FIXME: Use udelay() */
-
-		if (size != (sblive_readfn0(sb_hw, HCFG) & ~0x800))
-		{
-			sb_hw->has_toslink = 1;
-			sblive_writefn0(sb_hw, HCFG, size);
-		}
-	}
-
-	return CTSTATUS_SUCCESS;
-}
-
-/* FIXME: This belongs in a headerfile */
-/** Channel status message lengths **/
-u8 gabMsgLenChannel[] =
-{
-	3,			/* 0x80 note off        */
-	3,			/* 0x90 note on         */
-	3,			/* 0xA0 key pressure    */
-	3,			/* 0xB0 control change  */
-	2,			/* 0xC0 program change  */
-	2,			/* 0xD0 channel pressure */
-	3,			/* 0xE0 pitch bend      */
-	1
-};
-
-/** System status message lengths **/
-u8 gabMsgLenSystem[] =
-{
-	1,			/* 0xF0 sysex begin     */
-	2,			/* 0xF1 midi tcqf       */
-	3,			/* 0xF2 song position   */
-	2,			/* 0xF3 song select     */
-	1,			/* 0xF4 undefined       */
-	1,			/* 0xF5 undefined       */
-	1,			/* 0xF6 tune request    */
-	1,			/* 0xF7 sysex eox       */
-
-	1,			/* 0xF8 timing clock    */
-	1,			/* 0xF9 undefined       */
-	1,			/* 0xFA start           */
-	1,			/* 0xFB continue        */
-	1,			/* 0xFC stop            */
-	1,			/* 0xFD undefined       */
-	1,			/* 0xFE active sensing  */
-	1			/* 0xFF system reset    */
-};
-
-
-/****************************************************************************/
-/** Function : srToPitch                                                   **/
-/**                                                                        **/
-/** Input    : sampleRate - sampling rate                                  **/
-/**                                                                        **/
-/** Return   : pitch value                                                 **/
-/**                                                                        **/
-/** About    : convert sampling rate to pitch                              **/
-/**                                                                        **/
-/** Note     : for 8010, sampling rate is at 48kHz, this function should   **/
-/**            be changed.                                                 **/
-/****************************************************************************/
+/*************************************************************************
+* Function : srToPitch                                                   *
+* Input    : sampleRate - sampling rate                                  *
+* Return   : pitch value                                                 *
+* About    : convert sampling rate to pitch                              *
+* Note     : for 8010, sampling rate is at 48kHz, this function should   *
+*            be changed.                                                 *
+*************************************************************************/
 u32 srToPitch(u32 sampleRate)
 {
 	int i;
 
 	/* FIXME: These tables should be defined in a headerfile */
-	static u32 logMagTable[128] =
-	{
+	static u32 logMagTable[128] = {
 		0x00000, 0x02dfc, 0x05b9e, 0x088e6, 0x0b5d6, 0x0e26f, 0x10eb3, 0x13aa2,
 		0x1663f, 0x1918a, 0x1bc84, 0x1e72e, 0x2118b, 0x23b9a, 0x2655d, 0x28ed5,
 		0x2b803, 0x2e0e8, 0x30985, 0x331db, 0x359eb, 0x381b6, 0x3a93d, 0x3d081,
@@ -426,58 +66,45 @@
 		0xf4463, 0xf5c2a, 0xf73da, 0xf8b71, 0xfa2f0, 0xfba57, 0xfd1a7, 0xfe8df
 	};
 
-static char logSlopeTable[128] =
-{
-	0x5c, 0x5c, 0x5b, 0x5a, 0x5a, 0x59, 0x58, 0x58,
-	0x57, 0x56, 0x56, 0x55, 0x55, 0x54, 0x53, 0x53,
-	0x52, 0x52, 0x51, 0x51, 0x50, 0x50, 0x4f, 0x4f,
-	0x4e, 0x4d, 0x4d, 0x4d, 0x4c, 0x4c, 0x4b, 0x4b,
-	0x4a, 0x4a, 0x49, 0x49, 0x48, 0x48, 0x47, 0x47,
-	0x47, 0x46, 0x46, 0x45, 0x45, 0x45, 0x44, 0x44,
-	0x43, 0x43, 0x43, 0x42, 0x42, 0x42, 0x41, 0x41,
-	0x41, 0x40, 0x40, 0x40, 0x3f, 0x3f, 0x3f, 0x3e,
-	0x3e, 0x3e, 0x3d, 0x3d, 0x3d, 0x3c, 0x3c, 0x3c,
-	0x3b, 0x3b, 0x3b, 0x3b, 0x3a, 0x3a, 0x3a, 0x39,
-	0x39, 0x39, 0x39, 0x38, 0x38, 0x38, 0x38, 0x37,
-	0x37, 0x37, 0x37, 0x36, 0x36, 0x36, 0x36, 0x35,
-	0x35, 0x35, 0x35, 0x34, 0x34, 0x34, 0x34, 0x34,
-	0x33, 0x33, 0x33, 0x33, 0x32, 0x32, 0x32, 0x32,
-	0x32, 0x31, 0x31, 0x31, 0x31, 0x31, 0x30, 0x30,
-	0x30, 0x30, 0x30, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f
-};
-
-if (sampleRate == 0)
-	return (0);	/* Bail out if no leading "1" */
-
-sampleRate *= 11185;	/* Scale 48000 to 0x20002380 */
-
-for (i = 31; i > 0; i--)
-{
-	if (sampleRate & 0x80000000)
-	{	/* Detect leading "1" */
-		return (u32) (((s32) (i - 15) << 20) +
-			      logMagTable[0x7f & (sampleRate >> 24)] +
-			      (0x7f & (sampleRate >> 17)) *
-			      logSlopeTable[0x7f & (sampleRate >> 24)]);
+	static char logSlopeTable[128] = {
+		0x5c, 0x5c, 0x5b, 0x5a, 0x5a, 0x59, 0x58, 0x58,
+		0x57, 0x56, 0x56, 0x55, 0x55, 0x54, 0x53, 0x53,
+		0x52, 0x52, 0x51, 0x51, 0x50, 0x50, 0x4f, 0x4f,
+		0x4e, 0x4d, 0x4d, 0x4d, 0x4c, 0x4c, 0x4b, 0x4b,
+		0x4a, 0x4a, 0x49, 0x49, 0x48, 0x48, 0x47, 0x47,
+		0x47, 0x46, 0x46, 0x45, 0x45, 0x45, 0x44, 0x44,
+		0x43, 0x43, 0x43, 0x42, 0x42, 0x42, 0x41, 0x41,
+		0x41, 0x40, 0x40, 0x40, 0x3f, 0x3f, 0x3f, 0x3e,
+		0x3e, 0x3e, 0x3d, 0x3d, 0x3d, 0x3c, 0x3c, 0x3c,
+		0x3b, 0x3b, 0x3b, 0x3b, 0x3a, 0x3a, 0x3a, 0x39,
+		0x39, 0x39, 0x39, 0x38, 0x38, 0x38, 0x38, 0x37,
+		0x37, 0x37, 0x37, 0x36, 0x36, 0x36, 0x36, 0x35,
+		0x35, 0x35, 0x35, 0x34, 0x34, 0x34, 0x34, 0x34,
+		0x33, 0x33, 0x33, 0x33, 0x32, 0x32, 0x32, 0x32,
+		0x32, 0x31, 0x31, 0x31, 0x31, 0x31, 0x30, 0x30,
+		0x30, 0x30, 0x30, 0x2f, 0x2f, 0x2f, 0x2f, 0x2f
+	};
+
+	if (sampleRate == 0)
+		return (0);	/* Bail out if no leading "1" */
+
+	sampleRate *= 11185;	/* Scale 48000 to 0x20002380 */
+
+	for (i = 31; i > 0; i--) {
+		if (sampleRate & 0x80000000) {	/* Detect leading "1" */
+			return (u32) (((s32) (i - 15) << 20) +
+				      logMagTable[0x7f & (sampleRate >> 24)] +
+				      (0x7f & (sampleRate >> 17)) * logSlopeTable[0x7f & (sampleRate >> 24)]);
+		}
+		sampleRate = sampleRate << 1;
 	}
-	sampleRate = sampleRate << 1;
-}
 
-DPF(2, "srToPitch: BUG!\n");
-return 0;		/* Should never reach this point */
+	DPF(2, "srToPitch: BUG!\n");
+	return 0;		/* Should never reach this point */
 }
 
-
-/****************************************************************************/
-/** Function : sumVolumeToAttenuation                                      **/
-/**                                                                        **/
-/** Input    : inputValue - input volume                                   **/
-/**                                                                        **/
-/** Return   : attenuation value                                           **/
-/**                                                                        **/
-/** About    : convert volume to attenuation                               **/
-/****************************************************************************/
 /* Returns an attenuation based upon a cumulative volume value */
+
 /* Algorithm calculates 0x200 - 0x10 log2 (input) */
 u8 sumVolumeToAttenuation(u32 value)
 {
@@ -488,8 +115,7 @@
 		return 0xFF;
 
 	/* Find first SET bit. This is the integer part of the value */
-	while ((value & 0x10000) == 0)
-	{
+	while ((value & 0x10000) == 0) {
 		value <<= 1;
 		count--;
 	}
@@ -502,102 +128,99 @@
 	return (u8) ans;
 }
 
-/**************************************************************/
-/* write/read PCI function 0 registers                        */
-/**************************************************************/
-void sblive_writefn0(struct sblive_hw *sb_hw, u8 reg, u32 data)
+/*******************************************
+* write/read PCI function 0 registers      *
+********************************************/
+void sblive_writefn0(struct emu10k1_card *card, u8 reg, u32 data)
 {
 	unsigned long flags;
 
-	spin_lock_irqsave(&sb_hw->emu_lock, flags);
-	outl(data, sb_hw->hwaddr + reg);
-	spin_unlock_irqrestore(&sb_hw->emu_lock, flags);
+	spin_lock_irqsave(&card->lock, flags);
+	outl(data, card->iobase + reg);
+	spin_unlock_irqrestore(&card->lock, flags);
 
 	return;
 }
 
-void sblive_wrtmskfn0(struct sblive_hw *sb_hw, u8 reg, u32 mask, u32 data)
+void sblive_wrtmskfn0(struct emu10k1_card *card, u8 reg, u32 mask, u32 data)
 {
 	unsigned long flags;
 
 	data &= mask;
 
-	spin_lock_irqsave(&sb_hw->emu_lock, flags);
-	data |= inl(sb_hw->hwaddr + reg) & ~mask;
-	outl(data, sb_hw->hwaddr + reg);
-	spin_unlock_irqrestore(&sb_hw->emu_lock, flags);
+	spin_lock_irqsave(&card->lock, flags);
+	data |= inl(card->iobase + reg) & ~mask;
+	outl(data, card->iobase + reg);
+	spin_unlock_irqrestore(&card->lock, flags);
 
 	return;
 }
 
-u32 sblive_readfn0(struct sblive_hw *sb_hw, u8 reg)
+u32 sblive_readfn0(struct emu10k1_card * card, u8 reg)
 {
 	u32 val;
 	unsigned long flags;
 
-	spin_lock_irqsave(&sb_hw->emu_lock, flags);
-	val = inl(sb_hw->hwaddr + reg);
-	spin_unlock_irqrestore(&sb_hw->emu_lock, flags);
+	spin_lock_irqsave(&card->lock, flags);
+	val = inl(card->iobase + reg);
+	spin_unlock_irqrestore(&card->lock, flags);
 	return val;
 }
 
-u32 sblive_rdmskfn0(struct sblive_hw *sb_hw, u8 reg, u32 mask)
+u32 sblive_rdmskfn0(struct emu10k1_card * card, u8 reg, u32 mask)
 {
 	u32 val;
 	unsigned long flags;
 
-	spin_lock_irqsave(&sb_hw->emu_lock, flags);
-	val = inl(sb_hw->hwaddr + reg);
-	spin_unlock_irqrestore(&sb_hw->emu_lock, flags);
+	spin_lock_irqsave(&card->lock, flags);
+	val = inl(card->iobase + reg);
+	spin_unlock_irqrestore(&card->lock, flags);
 	return val & mask;
 }
 
-/****************************************************************************/
-/* write/read Emu10k1 pointer-offset register set, accessed through         */
-/*  the PTR and DATA registers                                              */
-/****************************************************************************/
-void sblive_writeptr(struct sblive_hw *sb_hw, u32 reg, u32 channel, u32 data)
+/************************************************************************
+* write/read Emu10k1 pointer-offset register set, accessed through      *
+*  the PTR and DATA registers                                           *
+*************************************************************************/
+void sblive_writeptr(struct emu10k1_card *card, u32 reg, u32 channel, u32 data)
 {
 	u32 regptr;
 	unsigned long flags;
 
 	regptr = ((reg << 16) & PTR_ADDRESS_MASK) | (channel & PTR_CHANNELNUM_MASK);
 
-	if (reg & 0xff000000)
-	{
+	if (reg & 0xff000000) {
 		u32 mask;
 		u8 size, offset;
 
 		size = (reg >> 24) & 0x3f;
 		offset = (reg >> 16) & 0x1f;
 		mask = ((1 << size) - 1) << offset;
-		data = (data << offset ) & mask;
+		data = (data << offset) & mask;
 
-		spin_lock_irqsave(&sb_hw->emu_lock, flags);
-		outl(regptr, sb_hw->hwaddr + PTR);
-		data |= inl(sb_hw->hwaddr + DATA) & ~mask;
-		outl(data, sb_hw->hwaddr + DATA);
-		spin_unlock_irqrestore(&sb_hw->emu_lock, flags);
-	} else
-	{
-		spin_lock_irqsave(&sb_hw->emu_lock, flags);
-		outl(regptr, sb_hw->hwaddr + PTR);
-		outl(data, sb_hw->hwaddr + DATA);
-		spin_unlock_irqrestore(&sb_hw->emu_lock, flags);
+		spin_lock_irqsave(&card->lock, flags);
+		outl(regptr, card->iobase + PTR);
+		data |= inl(card->iobase + DATA) & ~mask;
+		outl(data, card->iobase + DATA);
+		spin_unlock_irqrestore(&card->lock, flags);
+	} else {
+		spin_lock_irqsave(&card->lock, flags);
+		outl(regptr, card->iobase + PTR);
+		outl(data, card->iobase + DATA);
+		spin_unlock_irqrestore(&card->lock, flags);
 	}
 
 	return;
 }
 
-u32 sblive_readptr(struct sblive_hw *sb_hw, u32 reg, u32 channel)
+u32 sblive_readptr(struct emu10k1_card * card, u32 reg, u32 channel)
 {
-	u32 regptr,val;
+	u32 regptr, val;
 	unsigned long flags;
 
 	regptr = ((reg << 16) & PTR_ADDRESS_MASK) | (channel & PTR_CHANNELNUM_MASK);
 
-	if (reg & 0xff000000)
-	{
+	if (reg & 0xff000000) {
 		u32 mask;
 		u8 size, offset;
 
@@ -605,66 +228,54 @@
 		offset = (reg >> 16) & 0x1f;
 		mask = ((1 << size) - 1) << offset;
 
-		spin_lock_irqsave(&sb_hw->emu_lock, flags);
-		outl(regptr, sb_hw->hwaddr + PTR);
-		val = inl(sb_hw->hwaddr + DATA);
-		spin_unlock_irqrestore(&sb_hw->emu_lock, flags);
+		spin_lock_irqsave(&card->lock, flags);
+		outl(regptr, card->iobase + PTR);
+		val = inl(card->iobase + DATA);
+		spin_unlock_irqrestore(&card->lock, flags);
 
 		return (val & mask) >> offset;
-	} else
-	{
-		spin_lock_irqsave(&sb_hw->emu_lock, flags);
-		outl(regptr, sb_hw->hwaddr + PTR);
-		val = inl(sb_hw->hwaddr + DATA);
-		spin_unlock_irqrestore(&sb_hw->emu_lock, flags);
+	} else {
+		spin_lock_irqsave(&card->lock, flags);
+		outl(regptr, card->iobase + PTR);
+		val = inl(card->iobase + DATA);
+		spin_unlock_irqrestore(&card->lock, flags);
 
 		return val;
 	}
 }
 
-/*****************************************************************************/
-/*  halSetStopOnLoop (struct sblive_hw *sb_hw, u32 voicenum)                 */
-/*****************************************************************************/
-void halSetStopOnLoop(struct sblive_hw *sb_hw, u32 voicenum)
+void emu10k1_set_stop_on_loop(struct emu10k1_card *card, u32 voicenum)
 {
 	/* Voice interrupt */
 	if (voicenum >= 32)
-		sblive_writeptr(sb_hw, SOLEH | ((0x0100 | (voicenum - 32)) << 16), 0, 1);
+		sblive_writeptr(card, SOLEH | ((0x0100 | (voicenum - 32)) << 16), 0, 1);
 	else
-		sblive_writeptr(sb_hw, SOLEL | ((0x0100 | voicenum) << 16), 0, 1);
+		sblive_writeptr(card, SOLEL | ((0x0100 | voicenum) << 16), 0, 1);
 
 	return;
 }
 
-/*****************************************************************************/
-/*  halClearStopOnLoop (struct sblive_hw *sb_hw, u32 voicenum )              */
-/*****************************************************************************/
-void halClearStopOnLoop(struct sblive_hw *sb_hw, u32 voicenum)
+void emu10k1_clear_stop_on_loop(struct emu10k1_card *card, u32 voicenum)
 {
 	/* Voice interrupt */
 	if (voicenum >= 32)
-		sblive_writeptr(sb_hw, SOLEH | ((0x0100 | (voicenum - 32)) << 16), 0, 0);
+		sblive_writeptr(card, SOLEH | ((0x0100 | (voicenum - 32)) << 16), 0, 0);
 	else
-		sblive_writeptr(sb_hw, SOLEL | ((0x0100 | voicenum) << 16), 0, 0);
+		sblive_writeptr(card, SOLEL | ((0x0100 | voicenum) << 16), 0, 0);
 
 	return;
 }
 
-/*****************************************************************************/
-/*  halWC_WAIT (struct sblive_hw *sb_hw, u32 wait)                           */
-/*****************************************************************************/
-void halWC_WAIT(struct sblive_hw *sb_hw, u32 wait)
+static void sblive_wcwait(struct emu10k1_card *card, u32 wait)
 {
 	volatile unsigned uCount;
 	u32 newtime = 0, curtime;
 
-	curtime = READ_FN0(sb_hw, WC_SAMPLECOUNTER);
-	while (wait--)
-	{
+	curtime = READ_FN0(card, WC_SAMPLECOUNTER);
+	while (wait--) {
 		uCount = 0;
-		while (uCount++ < TIMEOUT)
-		{
-			newtime = READ_FN0(sb_hw, WC_SAMPLECOUNTER);
+		while (uCount++ < TIMEOUT) {
+			newtime = READ_FN0(card, WC_SAMPLECOUNTER);
 			if (newtime != curtime)
 				break;
 		}
@@ -676,171 +287,122 @@
 	}
 }
 
-
-/*****************************************************************************/
-/*  sblive_readac97 (struct sblive_hw *sb_hw, u8 index, u16 *pdata)          */
-/*****************************************************************************/
-int sblive_readac97(struct sblive_hw *sb_hw, u8 index, u16 *pdata)
+int sblive_readac97(struct emu10k1_card *card, u8 index, u16 * data)
 {
 	unsigned long flags;
 
-	spin_lock_irqsave(&sb_hw->emu_lock, flags);
+	spin_lock_irqsave(&card->lock, flags);
 
-	outb(index, sb_hw->mixeraddx + 2);
-	*pdata = inw(sb_hw->mixeraddx);
+	outb(index, card->mixeraddx + 2);
+	*data = inw(card->mixeraddx);
 
-	spin_unlock_irqrestore(&sb_hw->emu_lock, flags);
+	spin_unlock_irqrestore(&card->lock, flags);
 
 	return CTSTATUS_SUCCESS;
 }
-
 
-/*****************************************************************************/
-/*  sblive_writeac97(struct sblive_hw *sb_hw, u8 index, u16 data)            */
-/*****************************************************************************/
-int sblive_writeac97(struct sblive_hw *sb_hw, u8 index, u16 data)
+int sblive_writeac97(struct emu10k1_card *card, u8 index, u16 data)
 {
 	unsigned long flags;
 
-	spin_lock_irqsave(&sb_hw->emu_lock, flags);
+	spin_lock_irqsave(&card->lock, flags);
 
-	outb(index, sb_hw->mixeraddx + 2);
-	outw(data, sb_hw->mixeraddx);
+	outb(index, card->mixeraddx + 2);
+	outw(data, card->mixeraddx);
 
-	spin_unlock_irqrestore(&sb_hw->emu_lock, flags);
+	spin_unlock_irqrestore(&card->lock, flags);
 
 	return CTSTATUS_SUCCESS;
 }
-
 
-/*****************************************************************************/
-/*  sblive_rmwac97(struct sblive_hw *sb_hw, u8 index, u16 data, u16 mask)    */
-/*****************************************************************************/
-int sblive_rmwac97(struct sblive_hw *sb_hw, u8 index, u16 data, u16 mask)
+int sblive_rmwac97(struct emu10k1_card *card, u8 index, u16 data, u16 mask)
 {
 	u16 temp;
 	unsigned long flags;
 
-	spin_lock_irqsave(&sb_hw->emu_lock, flags);
+	spin_lock_irqsave(&card->lock, flags);
 
-	outb(index, sb_hw->mixeraddx + 2);
-	temp = inw(sb_hw->mixeraddx);
+	outb(index, card->mixeraddx + 2);
+	temp = inw(card->mixeraddx);
 	temp &= ~mask;
 	data &= mask;
 	temp |= data;
-	outw(temp, sb_hw->mixeraddx);
+	outw(temp, card->mixeraddx);
 
-	spin_unlock_irqrestore(&sb_hw->emu_lock, flags);
+	spin_unlock_irqrestore(&card->lock, flags);
 
 	return CTSTATUS_SUCCESS;
 }
 
-/****************************************************************/
-/*            MPU access functions                              */
-/****************************************************************/
-
-/*****************************************************************************/
-/* Function Name : hwmpuWriteData                                            */
-/*                                                                           */
-/* Description   : Writing data to MPU with timeout                          */
-/*                                                                           */
-/* Input         : sb_hw | Port object                                       */
-/*                 bData | contain the command                               */
-/*                                                                           */
-/* Return        : int | contain the status of this call                     */
-/*                                                                           */
-/*****************************************************************************/
-int hwmpuWriteData(struct sblive_hw *sb_hw, u8 data)
-{
-	unsigned long flags;
-        int ret;
-
-	spin_lock_irqsave(&sb_hw->emu_lock, flags);
-
-	if ((inb(sb_hw->hwaddr + MUSTAT) & MUSTAT_ORDYN) == 0)
-	{
-		outb(data,  sb_hw->hwaddr + MUDATA);
-                ret = CTSTATUS_SUCCESS;
+/*********************************************************
+*            MPU access functions                        *
+**********************************************************/
+
+int emu10k1_mpu_write_data(struct emu10k1_card *card, u8 data)
+{
+	unsigned long flags;
+	int ret;
+
+	spin_lock_irqsave(&card->lock, flags);
+
+	if ((inb(card->iobase + MUSTAT) & MUSTAT_ORDYN) == 0) {
+		outb(data, card->iobase + MUDATA);
+		ret = CTSTATUS_SUCCESS;
 	} else
-                ret = CTSTATUS_BUSY;
+		ret = CTSTATUS_BUSY;
 
-	spin_unlock_irqrestore(&sb_hw->emu_lock, flags);
+	spin_unlock_irqrestore(&card->lock, flags);
 
 	return ret;
 }
 
+int emu10k1_mpu_read_data(struct emu10k1_card *card, u8 * data)
+{
+	unsigned long flags;
+	int ret;
+
+	spin_lock_irqsave(&card->lock, flags);
 
-/*****************************************************************************/
-/* Function Name : hwmpuReadData                                             */
-/*                                                                           */
-/* Description  : Reading data from MPU with timeout                         */
-/*                                                                           */
-/* Input         : sb_hw | Port object                                       */
-/*                 bData | contain the command                               */
-/*                                                                           */
-/* Return        : int | contain the status of this call                     */
-/*                                                                           */
-/*****************************************************************************/
-int hwmpuReadData(struct sblive_hw *sb_hw, u8 *data)
-{
-	unsigned long flags;
-        int ret;
-
-	spin_lock_irqsave(&sb_hw->emu_lock, flags);
-
-	if ((inb(sb_hw->hwaddr + MUSTAT) & MUSTAT_IRDYN) == 0)
-	{
-		*data = inb(sb_hw->hwaddr + MUDATA);
-                ret = CTSTATUS_SUCCESS;
+	if ((inb(card->iobase + MUSTAT) & MUSTAT_IRDYN) == 0) {
+		*data = inb(card->iobase + MUDATA);
+		ret = CTSTATUS_SUCCESS;
 	} else
 		ret = CTSTATUS_NODATA;
 
-	spin_unlock_irqrestore(&sb_hw->emu_lock, flags);
+	spin_unlock_irqrestore(&card->lock, flags);
 
 	return ret;
 }
-
 
-/*****************************************************************************/
-/* Function Name : hwmpuReset                                                */
-/*                                                                           */
-/* Description  : Hardware reset the MPU                                     */
-/*                                                                           */
-/* Input         : sb_hw | Port object                                       */
-/*                                                                           */
-/* Return        : int | contain the status of this call                     */
-/*                                                                           */
-/*****************************************************************************/
-int hwmpuReset(struct sblive_hw *sb_hw)
+int emu10k1_mpu_reset(struct emu10k1_card *card)
 {
 	u8 status;
 	unsigned long flags;
 
-	DPF(2, "hwmpuReset() called\n");
+	DPF(2, "emu10k1_mpu_reset()\n");
 
-	if (sb_hw->mpuacqcount == 0)
-	{
-		spin_lock_irqsave(&sb_hw->emu_lock, flags);
-		outb(MUCMD_RESET, sb_hw->hwaddr + MUCMD);
-		spin_unlock_irqrestore(&sb_hw->emu_lock, flags);
+	if (card->mpuacqcount == 0) {
+		spin_lock_irqsave(&card->lock, flags);
+		outb(MUCMD_RESET, card->iobase + MUCMD);
+		spin_unlock_irqrestore(&card->lock, flags);
 
-		halWC_WAIT(sb_hw, 8);
+		sblive_wcwait(card, 8);
 
-		spin_lock_irqsave(&sb_hw->emu_lock, flags);
-		outb(MUCMD_RESET, sb_hw->hwaddr + MUCMD);
-		spin_unlock_irqrestore(&sb_hw->emu_lock, flags);
+		spin_lock_irqsave(&card->lock, flags);
+		outb(MUCMD_RESET, card->iobase + MUCMD);
+		spin_unlock_irqrestore(&card->lock, flags);
 
-		halWC_WAIT(sb_hw, 8);
+		sblive_wcwait(card, 8);
 
-		spin_lock_irqsave(&sb_hw->emu_lock, flags);
-		outb(MUCMD_ENTERUARTMODE , sb_hw->hwaddr + MUCMD);
-		spin_unlock_irqrestore(&sb_hw->emu_lock, flags);
+		spin_lock_irqsave(&card->lock, flags);
+		outb(MUCMD_ENTERUARTMODE, card->iobase + MUCMD);
+		spin_unlock_irqrestore(&card->lock, flags);
 
-		halWC_WAIT(sb_hw, 8);
+		sblive_wcwait(card, 8);
 
-		spin_lock_irqsave(&sb_hw->emu_lock, flags);
-		status = inb(sb_hw->hwaddr + MUDATA);
-		spin_unlock_irqrestore(&sb_hw->emu_lock, flags);
+		spin_lock_irqsave(&card->lock, flags);
+		status = inb(card->iobase + MUDATA);
+		spin_unlock_irqrestore(&card->lock, flags);
 
 		if (status == 0xfe)
 			return CTSTATUS_SUCCESS;
@@ -848,44 +410,21 @@
 			return CTSTATUS_ERROR;
 	}
 
-
 	return CTSTATUS_SUCCESS;
 }
 
-
-/*****************************************************************************/
-/* Function Name : hwmpuAcquire                                              */
-/*                                                                           */
-/* Description   : Increase MPU acquire count                                */
-/*                                                                           */
-/* Input         : sb_hw | Port object                                       */
-/*                                                                           */
-/* Return        : int | contain the status of this call                     */
-/*                                                                           */
-/*****************************************************************************/
-int hwmpuAcquire(struct sblive_hw *sb_hw)
+int emu10k1_mpu_acquire(struct emu10k1_card *card)
 {
 	/* FIXME: This should be a macro */
-	++sb_hw->mpuacqcount;
+	++card->mpuacqcount;
 
 	return CTSTATUS_SUCCESS;
 }
-
 
-/*****************************************************************************/
-/* Function Name : hwmpuRelease                                              */
-/*                                                                           */
-/* Description   : Decrease MPU acquire count                                */
-/*                                                                           */
-/* Input         : sb_hw | Port object                                       */
-/*                                                                           */
-/* Return        : int | contain the status of this call                     */
-/*                                                                           */
-/*****************************************************************************/
-int hwmpuRelease(struct sblive_hw *sb_hw)
+int emu10k1_mpu_release(struct emu10k1_card *card)
 {
 	/* FIXME: this should be a macro */
-	--sb_hw->mpuacqcount;
+	--card->mpuacqcount;
 
 	return CTSTATUS_SUCCESS;
 }
Index: oldkernel/linux/drivers/sound/emu10k1/hwaccess.h
diff -u linux/drivers/sound/emu10k1/hwaccess.h:1.1 linux/drivers/sound/emu10k1/hwaccess.h:1.2
--- linux/drivers/sound/emu10k1/hwaccess.h:1.1	Thu Jun  1 16:52:15 2000
+++ linux/drivers/sound/emu10k1/hwaccess.h	Fri Jul  7 15:36:45 2000
@@ -45,181 +45,57 @@
 #include <asm/io.h>
 #include <asm/dma.h>
 
-#include <emu_wrapper.h>
+#include "emu_wrapper.h"
 
-typedef int (*CALLBACKFN)(unsigned long,unsigned long ,unsigned long);
-
 enum GlobalErrorCode
 {
 	CTSTATUS_SUCCESS = 0x0000,
 	CTSTATUS_ERROR,
-	CTSTATUS_INVALIDPARAM,
-	CTSTATUS_NOTSUPPORTED,
 	CTSTATUS_NOMEMORY,
-	CTSTATUS_INVALIDIO,
-	CTSTATUS_INVALIDIRQ,
-	CTSTATUS_INVALIDDMA,
-	CTSTATUS_INVALIDID,
-	CTSTATUS_INVALIDVALUE,
-	CTSTATUS_BADFORMAT_BITS,
-	CTSTATUS_BADFORMAT_RATE,
-	CTSTATUS_BADFORMAT_CHANNELS,
-	CTSTATUS_BADFORMAT_STEREO,
 	CTSTATUS_INUSE,
-	CTSTATUS_STILLPLAYING,
-	CTSTATUS_ALLOCATED,
-	CTSTATUS_INVALID_FORMAT,
-	CTSTATUS_OUT_OF_RESOURCE,
-	CTSTATUS_CHIP_INUSE,
-	CTSTATUS_NOCHIPRESOURCE,
-	CTSTATUS_PORTS_INUSE
-};
-
-enum LocalErrorCode
-{
-	CTSTATUS_NOTENABLED = 0x7000,
-	CTSTATUS_READY,
-	CTSTATUS_BUSY,
-	CTSTATUS_DATAAVAIL,
-	CTSTATUS_NODATA,
-	CTSTATUS_NEXT_BYTE
 };
 
-#define FLAGS_ENABLED       0x0001
-#define FLAGS_AVAILABLE     0x0002
-#define FLAGS_READY         0x0004
-#define FLAGS_CLOSEPENDING  0x0008
-
-/* FIXME: Make this stuff go away please */
-#ifndef TRUE
-#define TRUE    1
-#endif
+#define FLAGS_AVAILABLE     0x0001
+#define FLAGS_READY         0x0002
 
-#ifndef FALSE
-#define FALSE   0
-#endif
-
-#ifndef NULL
-#define NULL    0
-#endif
-
-#define _stdcall
-#define __cdecl
-
 #define min(x,y) ((x) < (y)) ? (x) : (y)
 
-#define MM_CREATIVE         2
-#define MAXPNAMELEN         32      /* max product name length (including NULL) */
-#define MAX_CARD_DESC       80
-
-#define MM_CREATIVE_DRIVER_NAME     "SoundBlaster"
-#define MM_CREATIVE_DRIVER_VERSION  0x400
-#define MM_CREATIVE_MIXER_PID       409
-#define MM_CREATIVE_WAVEOUT_PID     104
-#define MM_CREATIVE_WAVEIN_PID      4
-#define MM_CREATIVE_MIDIOUT_PID     302
-#define MM_CREATIVE_MIDIIN_PID      202
-
 struct memhandle
 {
-	unsigned long physaddx;
+	unsigned long busaddx;
 	void *virtaddx;
 	u32 order;
 };
 
-struct sblive_list
-{
-	struct sblive_list  *next;
-};
-
-int osAllocMemPhysical(u32, struct memhandle **);
-int osFreeMemPhysical(struct memhandle **);
-int osListAttach(struct sblive_list **head, struct sblive_list *new);
-int osListRemove(struct sblive_list **head, struct sblive_list *pDead);
-struct sblive_list *osListGetNext(struct sblive_list *head, struct sblive_list *curr);
-
-#define MAX_MEMREGISTER     1
-#define MAX_IOPORT          4
-#define MAX_IRQ             2
-#define MAX_DMA             2
-
-struct sblive_config
-{
-	u32 vendorid;			/* Vendor ID			*/
-	u32 serialno;			/* Serial number		*/
-	u32 logdevid;			/* Logical device ID		*/
-	u32 chiprev;			/* Chip revision		*/
-	u16 nummemwindows;			/* Number of memory windows	*/
-	u32 membase[MAX_MEMREGISTER];	/* Memory window base		*/
-	u32 memlength[MAX_MEMREGISTER];	/* Memory window length		*/
-	u16 memattrib[MAX_MEMREGISTER];	/* Memory window attributes	*/
-	u16 numioports;			/* Number of I/O ports		*/
-	u16 ioportbase[MAX_IOPORT];		/* I/O port base		*/
-	u16 ioportlenh[MAX_IOPORT];		/* I/O port length		*/
-	u16 numirq;				/* Number of IRQs		*/
-	u8  IRQregs[MAX_IRQ];		/* IRQ list			*/
-	u8  irqattr[MAX_IRQ];		/* IRQ attributes list		*/
-	u16 numdma;				/* Number of DMA channels	*/
-	u8  dmalst[MAX_DMA];		/* DMA list			*/
-	u16 dmaattr[MAX_DMA];		/* DMA attributes list		*/
-};
+struct memhandle *emu10k1_alloc_memphysical(u32);
+void emu10k1_free_memphysical(struct memhandle *);
 
-#define DEBUG_LEVEL 3
+#define DEBUG_LEVEL 2
 
 #ifdef EMU10K1_DEBUG
-# define DPD(level,x,y...) do {if(level <= DEBUG_LEVEL) printk( KERN_NOTICE "emu10k1: %s: %d: " x , __FILE__ , __LINE__ , y );} while(0);
-# define DPF(level,x)   do {if(level <= DEBUG_LEVEL) printk( KERN_NOTICE "emu10k1: %s: %d: " x , __FILE__ , __LINE__ );} while(0);
+# define DPD(level,x,y...) do {if(level <= DEBUG_LEVEL) printk( KERN_NOTICE "emu10k1: %s: %d: " x , __FILE__ , __LINE__ , y );} while(0)
+# define DPF(level,x)   do {if(level <= DEBUG_LEVEL) printk( KERN_NOTICE "emu10k1: %s: %d: " x , __FILE__ , __LINE__ );} while(0)
+#define ERROR() DPF(1,"error\n");
 #else
 # define DPD(level,x,y...) /* not debugging: nothing */
 # define DPF(level,x)
+#define ERROR()
 #endif /* EMU10K1_DEBUG */
 
-
 #include "8010.h"
-
-struct sblive_hw;
-
 #include "voicemgr.h"
-
-struct emuaddr_allocdesc
-{
-	struct sblive_hw *sb_hw;
-	u32     ownertype;
-	CALLBACKFN  callback;
-	unsigned long     callback_data;
-	u32     size;     /* Size in bytes requested */
-	u32     flags;    /* stereo/mono  8/16 */
-};
-
-struct emu_page
-{
-	u16  flags;
-	struct sblive_hw *sb_hw;
-	u32 emustartaddr;
-};
 
-struct emu_addrmgr
-{
-	struct emu_page emupagetable[MAXPAGES];
-};
+int emu10k1_addxmgr_alloc(u32, struct emu10k1_card *);
+void emu10k1_addxmgr_free(struct emu10k1_card *, int);
 
-int emu10kaddxmgrInit(struct sblive_hw *);
-int emu10kaddxmgrExit(struct sblive_hw *);
-int emu10kaddxmgrAlloc(struct emuaddr_allocdesc *,struct emu_page *  *);
-int emu10kaddxmgrFree(struct emu_page *);
-
 #include "timer.h"
 #include "irqmgr.h"
-#include "efxmgr.h"
 
 /* DATA STRUCTURES */
 
-struct sblive_hw
+struct emu10k1_card 
 {
-	struct sblive_hw *next, *prev;
-
-	unsigned long		mixeraddx;
-	unsigned long		hwconfigaddx;
+	struct list_head list;
 
 	struct memhandle	*virtualpagetable;
 
@@ -227,110 +103,102 @@
 	u32 tmemsize;
 	struct memhandle	*silentpage;
 
-	spinlock_t		emu_lock;
+	spinlock_t		lock;
 
-	struct voice_mgr	voice_manager;
-	struct emu_addrmgr	emu_addrmgr;
+	struct voice_manager	voicemgr;
+	u16			emupagetable[MAXPAGES];
 
-	struct emu_timer	*timer;
+	struct list_head	timers;
 	unsigned		timer_delay;
 	spinlock_t		timer_lock;
-
-	struct sblive_irq	hw_irq;
 
-	unsigned long		hwaddr;
+	struct pci_dev		*pci_dev;
+	unsigned long           iobase;
+        unsigned long           mixeraddx;
+	u32  irq; 
 
-	unsigned        numvoices;
-	unsigned        awecount;
-	u32		intrstate;
-
-	unsigned long	joybase;
-	struct pci_dev	*pcidev_joy;
-	unsigned long	audio_num;
+	unsigned long	audio1_num;
+	unsigned long	audio2_num;
 	unsigned long	mixer_num;
 	unsigned long	midi_num;
-	unsigned long	stat_num;
-	struct sblive_waveout	*card_waveout;
-	struct sblive_wavein	*card_wavein;
-	struct sblive_mpuout	*card_mpuout;
-	struct sblive_mpuin	*card_mpuin;
-	u16			arrwVol[25]; /* Size is hardcoded.  Bad! */
+
+	struct emu10k1_waveout	*waveout;
+	struct emu10k1_wavein	*wavein;
+	struct emu10k1_mpuout	*mpuout;
+	struct emu10k1_mpuin	*mpuin;
+
+	u16			arrwVol[SOUND_MIXER_NRDEVICES + 1];
+	/* array is used from the member 1 to save (-1) operation */
+	u32			digmix[9 * 6 * 2];
 	unsigned int		modcnt;
 	struct semaphore	open_sem;
 	mode_t			open_mode;
 	wait_queue_head_t	open_wait;
 
-	u8	    paneffectsbus;
-	u8	    auxeffectsbus;
-	u8	    choruseffectsbus;
-	u8	    reverbeffectsbus;
-
-	u32	    powerstate; 	  // Current Power State
 	u32	    mpuacqcount;	  // Mpu acquire count
-	struct sblive_config	dsCardCfg;
 	u32	    has_toslink;	       // TOSLink detection
+
+	u8 chiprev;                    /* Chip revision                */
+};
+
+#ifdef PRIVATE_PCM_VOLUME
+
+#define MAX_PCM_CHANNELS NUM_G 
+struct sblive_pcm_volume_rec {
+	struct files_struct *files; // identification of the same thread
+	u8 attn_l;		// attenuation for left channel
+	u8 attn_r;		// attenuation for right channel
+	u16 mixer;		// saved mixer value for return
+	u8 channel_l;		// idx of left channel
+	u8 channel_r;		// idx of right channel
+	int opened;		// counter - locks element
 };
+extern struct sblive_pcm_volume_rec sblive_pcm_volume[];
 
+#endif
+
+
 #define ENABLE 			0xffffffff
 #define DISABLE 		0x00000000
 
 #define ENV_ON			0x80
 #define ENV_OFF			0x00
 
-/* EMU Irq Types */
-#define IRQTYPE_PCIBUSERROR	    IPR_PCIERROR
-#define IRQTYPE_MIXERBUTTON	    (IPR_VOLINCR | IPR_VOLDECR | IPR_MUTE)
-#define IRQTYPE_VOICE		    (IPR_CHANNELLOOP | IPR_CHANNELNUMBERMASK)
-#define IRQTYPE_RECORD		    (IPR_ADCBUFFULL | IPR_ADCBUFHALFFULL | IPR_MICBUFFULL | IPR_MICBUFHALFFULL | IPR_EFXBUFFULL | IPR_EFXBUFHALFFULL)
-#define IRQTYPE_MPUOUT		    IPR_MIDITRANSBUFEMPTY
-#define IRQTYPE_MPUIN		    IPR_MIDIRECVBUFEMPTY
-#define IRQTYPE_TIMER		    IPR_INTERVALTIMER
-#define IRQTYPE_SPDIF		    (IPR_GPSPDIFSTATUSCHANGE | IPR_CDROMSTATUSCHANGE)
-#define IRQTYPE_DSP		    IPR_FXDSP
-
 #define TIMEOUT 		    16384
 
 u32 srToPitch(u32);
 u8 sumVolumeToAttenuation(u32);
 
-int halInit(struct sblive_hw *, struct sblive_config *, u32 *);
-int halExit(struct sblive_hw *);
+extern struct list_head emu10k1_devs;
 
-extern u8 gabMsgLenChannel[];
-extern u8 gabMsgLenSystem[];
-extern spinlock_t sblive_spinlock;
-
 /* Hardware Abstraction Layer access functions */
 
 #define WRITE_FN0(a,b,c) sblive_wrtmskfn0((a),(u8)(b), ((1 << (((b) >> 24) & 0x3f)) - 1) << (((b) >> 16) & 0x1f), (c) << (((b) >> 16) & 0x1f))
 
 #define READ_FN0(a,b) sblive_rdmskfn0((a),(u8)(b),((1 << (((b) >> 24) & 0x3f)) - 1) << (((b) >> 16) & 0x1f)) >> (((b) >> 16) & 0x1f)
-
-#define WRITE_EFX(a, b, c) sblive_writeptr((a), MICROCODEBASE + (b), 0, (c))
 
-void sblive_writefn0(struct sblive_hw *, u8 , u32 );
-void sblive_wrtmskfn0(struct sblive_hw *, u8 , u32 , u32 );
+void sblive_writefn0(struct emu10k1_card *, u8 , u32 );
+void sblive_wrtmskfn0(struct emu10k1_card *, u8 , u32 , u32 );
 
-u32 sblive_readfn0(struct sblive_hw *, u8 );
-u32 sblive_rdmskfn0(struct sblive_hw *, u8, u32 );
+u32 sblive_readfn0(struct emu10k1_card *, u8 );
+u32 sblive_rdmskfn0(struct emu10k1_card *, u8, u32 );
 
-void sblive_writeptr(struct sblive_hw *, u32 , u32 , u32 );
-u32 sblive_readptr(struct sblive_hw *, u32 , u32 );
+void sblive_writeptr(struct emu10k1_card *, u32 , u32 , u32 );
+u32 sblive_readptr(struct emu10k1_card *, u32 , u32 );
 
-void halSetStopOnLoop(struct sblive_hw *, u32);
-void halClearStopOnLoop(struct sblive_hw *, u32);
-void halWC_WAIT(struct sblive_hw *, u32);
+void emu10k1_set_stop_on_loop(struct emu10k1_card *, u32);
+void emu10k1_clear_stop_on_loop(struct emu10k1_card *, u32);
 
 /* AC97 Mixer access function */
-int sblive_readac97(struct sblive_hw *, u8, u16 *);
-int sblive_writeac97(struct sblive_hw *, u8, u16);
-int sblive_rmwac97(struct sblive_hw *, u8, u16, u16);
+int sblive_readac97(struct emu10k1_card *, u8, u16 *);
+int sblive_writeac97(struct emu10k1_card *, u8, u16);
+int sblive_rmwac97(struct emu10k1_card *, u8, u16, u16);
 
 /* MPU access function*/
-int hwmpuWriteData(struct sblive_hw *, u8);
-int hwmpuReadData(struct sblive_hw *, u8 *);
-int hwmpuReset(struct sblive_hw *);
-int hwmpuAcquire(struct sblive_hw *);
-int hwmpuRelease(struct sblive_hw *);
+int emu10k1_mpu_write_data(struct emu10k1_card *, u8);
+int emu10k1_mpu_read_data(struct emu10k1_card *, u8 *);
+int emu10k1_mpu_reset(struct emu10k1_card *);
+int emu10k1_mpu_acquire(struct emu10k1_card *);
+int emu10k1_mpu_release(struct emu10k1_card *);
 
 #endif  /* _HWACCESS_H */
Index: oldkernel/linux/drivers/sound/emu10k1/icardmid.h
diff -u linux/drivers/sound/emu10k1/icardmid.h:1.1 linux/drivers/sound/emu10k1/icardmid.h:1.2
--- linux/drivers/sound/emu10k1/icardmid.h:1.1	Thu Jun  1 16:52:15 2000
+++ linux/drivers/sound/emu10k1/icardmid.h	Fri Jul  7 15:36:45 2000
@@ -103,10 +103,6 @@
 #define ICARDMIDI_OUTBUFFEROK           0x00000001
 #define ICARDMIDI_INMIDIOK              0x00000002
 
-#define MIDICAPS_INPUT                  0x00001000
-#define MIDICAPS_OUTPUT                 0x00002000
-#define MIDICAPS_SOUNDFONT              0x00004000
-
 /* Declaration for technology in struct midi_caps */
 #define MT_MIDIPORT                     0x00000001	/* In original MIDIOUTCAPS structure */
 #define MT_FMSYNTH                      0x00000004	/* In original MIDIOUTCAPS structure */
@@ -115,24 +111,15 @@
 #define MT_PCISYNTH64                   0x00004000
 #define CARDMIDI_AWEMASK                0x0000F000
 
-/* Flags for wTechnology field of MIDIOUTCAPS structure */
-#define MOD_MIDIPORT                    1	/* Output port */
-#define MOD_SYNTH                       2	/* Generic internal synth */
-#define MOD_SQSYNTH                     3	/* Square wave internal synth */
-#define MOD_FMSYNTH                     4	/* FM internal synth */
-#define MOD_MAPPER                      5	/* MIDI mapper */
-
-/* Bit definitions for caps for struct midi_caps */
-#define CARDMIDI_OUT                    0x00000001
-#define CARDMIDI_IN                     0x00000002
-
-/* Definitions for product in struct midi_caps */
-#define MM_CREATIVE_MIDIOUT             201
-#define MM_CREATIVE_MIDIIN              202
-#define MM_CREATIVE_FMSYNTH_STEREO      302
-#define MM_CREATIVE_MIDI_AWE32          303
-#define MM_CREATIVE_MIDI_EMU8008        305
-#define MM_CREATIVE_MIDI_EMU10K1        306
+enum LocalErrorCode
+{
+        CTSTATUS_NOTENABLED = 0x7000,
+        CTSTATUS_READY,
+        CTSTATUS_BUSY,
+        CTSTATUS_DATAAVAIL,
+        CTSTATUS_NODATA,
+        CTSTATUS_NEXT_BYTE
+};
 
 /* MIDI data block header */
 struct midi_hdr
@@ -142,32 +129,10 @@
 	u32 bytesrecorded;	/* Used for input only */
 	u32 user;		/* For client's use */
 	u32 flags;		/* Assorted flags (see defines) */
-	struct midi_hdr  *next;	/* Reserved for driver */
-	u8 *lpData;		/* Second copy of first pointer */
-};
-
-struct midi_caps
-{
-	u32 cbsize;
-	u32 support;
-	u32 technology;
-	u32 product;
-	u32 manufacturer;
-	u32 voices;
-	u32 notes;
-	u32 channelmask;
-	u8 MIDIname[MAXPNAMELEN];
-	u32 caps;
+	struct list_head list;	/* Reserved for driver */
+	u8 *data;		/* Second copy of first pointer */
 };
 
-struct midi_cache
-{
-	u32 cbsize;
-	u32 action;
-	u32 bank;
-	u16 array[128];
-};
-
 /* Enumeration for SetControl */
 enum
 {
@@ -175,7 +140,6 @@
 	MIDIQUERYACTIVEINST
 };
 
-
 struct midi_queue
 {
 	struct midi_queue  *next;
@@ -194,6 +158,6 @@
 	u32     streamid;
 };
 
-int midiCallbackFn(unsigned long , unsigned long, unsigned long *);
+int emu10k1_midi_callback(unsigned long , unsigned long, unsigned long *);
 
 #endif /* _ICARDMIDI_H */
Index: oldkernel/linux/drivers/sound/emu10k1/icardwav.h
diff -u linux/drivers/sound/emu10k1/icardwav.h:1.1 linux/drivers/sound/emu10k1/icardwav.h:1.2
--- linux/drivers/sound/emu10k1/icardwav.h:1.1	Thu Jun  1 16:52:15 2000
+++ linux/drivers/sound/emu10k1/icardwav.h	Fri Jul  7 15:36:45 2000
@@ -32,65 +32,21 @@
 #ifndef _ICARDWAV_H
 #define _ICARDWAV_H
 
-#define MAX_CARDWAVE_DESC   80
-
-struct wave_caps 
+/* Enumeration for SetControl */
+enum
 {
-	u32 product_id;
-	u32 caps;
-	u32 controls;
-	u32 maxchannels;
-	u32 minrate, maxrate;
-	char wavedesc[MAX_CARDWAVE_DESC];
+        WAVECURPOS = 0x10,
 };
 
-#define CARDWAVE_OUT                0x0001
-#define CARDWAVE_IN                 0x0002
-#define CARDWAVE_ALLOW_DIRECTXFER   0x0004
-#define CARDWAVE_CONTINUOUS_RATE    0x0008
-#define CARDWAVE_ALLOW_3D           0x0010
-
-#define CARDWAVE_CONTROL_VOLUME     0x0001
-#define CARDWAVE_CONTROL_MUTE       0x0002
-#define CARDWAVE_CONTROL_PAN        0x0004
-#define CARDWAVE_CONTROL_RATE       0x0008
-#define CARDWAVE_CONTROL_XFERPOS    0x1000
-#define CARDWAVE_CONTROL_LOOPING    0x2000
-
-#define CARDWAVE_PLAY_LOOPING       0x00000001
-
 struct wave_format 
 {
 	u32 samplingrate;
-	u32 bitspersample;
+	u32 bitsperchannel;
 	u32 channels;		/* 1 = Mono, 2 = Stereo */
-	int isinput;
-	u32 flags;
 };
-
-#define CARDWAVE_FORMAT_NORMAL              0x0000
-#define CARDWAVE_FORMAT_NOCONVERT_RATE      0x0001
-#define CARDWAVE_FORMAT_NOCONVERT_BITS      0x0002
-#define CARDWAVE_FORMAT_NOCONVERT_CHANNEL   0x0004
-#define CARDWAVE_FORMAT_NOCONVERT_ALL       (CARDWAVE_FORMAT_NOCONVERT_RATE | CARDWAVE_FORMAT_NOCONVERT_BITS | CARDWAVE_FORMAT_CHANNEL )
-#define CARDWAVE_FORMAT_DIRECTSOUND         0x2000
-#define CARDWAVE_FORMAT_DUP_BUFFER          0x4000
-#define CARDWAVE_FORMAT_DO_DIRECTXFER       0x8000
-#define CARDWAVE_FORMAT_3D_BUFFER           0x0100
-#define CARDWAVE_FORMAT_SOFTSYNTH           0x0200
-#define CARDWAVE_FORMAT_PRIMARY_BUFFER      0x0400
-
-/* Flags for QueryFormat */
-#define CARDWAVE_QF_RATE        0x00000001
-#define CARDWAVE_QF_BITS        0x00000002
-#define CARDWAVE_QF_CHANNEL     0x00000004
-#define CARDWAVE_QF_STEREO	0x00000008
-#define CARDWAVE_QF_ALL         (CARDWAVE_QF_RATE | CARDWAVE_QF_BITS | CARDWAVE_QF_CHANNEL | CARDWAVE_QF_STEREO)
-#define CARDWAVE_QF_DIRECTXFER  0x40000000
-#define CARDWAVE_QF_PHYSICAL    0x80000000
 
-/* Buffer type */
-#define CARDWAVE_DMA_BUFFER     0x0001
-#define CARDWAVE_LINEAR_BUFFER  0x0002
+/* emu10k1_wave states */
+#define CARDWAVE_STATE_STOPPED     0x0001
+#define CARDWAVE_STATE_STARTED     0x0002
 
 #endif /* _ICARDWAV_H */
Index: oldkernel/linux/drivers/sound/emu10k1/irqmgr.c
diff -u linux/drivers/sound/emu10k1/irqmgr.c:1.1 linux/drivers/sound/emu10k1/irqmgr.c:1.2
--- linux/drivers/sound/emu10k1/irqmgr.c:1.1	Thu Jun  1 16:52:15 2000
+++ linux/drivers/sound/emu10k1/irqmgr.c	Fri Jul  7 15:36:45 2000
@@ -1,3 +1,4 @@
+
 /*
  **********************************************************************
  *     irqmgr.c - IRQ manager for emu10k1 driver
@@ -35,19 +36,19 @@
 #include "irqmgr.h"
 
 /* Interrupt handler */
-static void emu10k1_interrupt(int nIRQ, void *pvDevID, struct pt_regs *pRegs)
+
+void emu10k1_interrupt(int irq, void *dev_id, struct pt_regs *regs)
 {
-	struct sblive_irq *irq_ptr = (struct sblive_irq *) pvDevID;
-	struct sblive_hw *sb_hw = irq_ptr->sb_hw;
+	struct emu10k1_card *card = (struct emu10k1_card *) dev_id;
 	u32 irqstatus, ptr, tmp;
 
-	if (sb_hw->hw_irq.ID != EMU10K1_INTERRUPT_ID)
+	if (!(irqstatus = sblive_readfn0(card, IPR)))
 		return;
 
-	DPD(4, "emu10k1_interrupt called, nIRQ =  %u\n", nIRQ);
+	DPD(4, "emu10k1_interrupt called, irq =  %u\n", irq);
 
 	/* Preserve PTR register */
-	ptr = sblive_readfn0(sb_hw, PTR);
+	ptr = sblive_readfn0(card, PTR);
 
 	/*
 	 ** NOTE :
@@ -60,138 +61,42 @@
 	 ** (make sure no more interrupts are pending).
 	 ** - Eric
 	 */
-
-	irqstatus = sblive_readfn0(sb_hw, IPR);
 
-	do
-	{
+	do {
 		DPD(4, "irq status %x\n", irqstatus);
 
 		tmp = irqstatus;
 
-		if (irqstatus & IRQTYPE_TIMER)
-		{
-			sblive_timerIrqCallback(sb_hw);
+		if (irqstatus & IRQTYPE_TIMER) {
+			emu10k1_timer_irqhandler(card);
 			irqstatus &= ~IRQTYPE_TIMER;
 		}
-
-		if (irqstatus & IRQTYPE_RECORD)
-		{
-			sblive_waveinIrqCallback(sb_hw);
-			irqstatus &= ~IRQTYPE_RECORD;
-		}
 
-		if (irqstatus & IRQTYPE_MPUIN)
-		{
-			sblive_mpuinIrqCallback(sb_hw);
+		if (irqstatus & IRQTYPE_MPUIN) {
+			emu10k1_mpuin_irqhandler(card);
 			irqstatus &= ~IRQTYPE_MPUIN;
 		}
 
-		if (irqstatus & IRQTYPE_MPUOUT)
-		{
-			sblive_mpuoutIrqCallback(sb_hw);
+		if (irqstatus & IRQTYPE_MPUOUT) {
+			emu10k1_mpuout_irqhandler(card);
 			irqstatus &= ~IRQTYPE_MPUOUT;
 		}
 
-		if(irqstatus)
-			sblive_irqmgrDisableIrq(sb_hw, irqstatus);
+		if (irqstatus)
+			emu10k1_irq_disable(card, irqstatus);
 
-		sblive_writefn0(sb_hw, IPR, tmp);
+		sblive_writefn0(card, IPR, tmp);
 
-	} while ((irqstatus = sblive_readfn0(sb_hw, IPR)));
+	} while ((irqstatus = sblive_readfn0(card, IPR)));
 
-	sblive_writefn0(sb_hw, PTR, ptr);
+	sblive_writefn0(card, PTR, ptr);
 
 	return;
 }
-
-/************************************************************************
- *
- *   int    sblive_irqmgrInit(struct sblive_hw * sb_hw)
- *
- *   ENTRY
- *       sb_hw -   Card object
- *
- *   RETURNS
- *       SUCCESS -   CTSTATUS_SUCCESS
- *       FAILURE -   CTSTATUS_ERROR
- *
- *   ABOUT
- *       Initialization
- *
- ************************************************************************/
-int sblive_irqmgrInit(struct sblive_irq *irq_ptr)
-{
-	unsigned long flags;
-
-	irq_ptr->status = 0;
-	irq_ptr->ID = EMU10K1_INTERRUPT_ID;
-
-	flags = SA_SHIRQ;
-
-	/* Reserve IRQ Line */
-	if (request_irq(irq_ptr->irq, emu10k1_interrupt, flags, "emu10k1", irq_ptr))
-	{
-		DPD(2, "emu10k1: irq %u in use\n", (unsigned int) irq_ptr->irq);
-		irq_ptr->status &= ~FLAGS_ENABLED;
-		DPF(2, "Error initializing IRQ\n");
-		return CTSTATUS_ERROR;
-	}
-
-	irq_ptr->status |= (FLAGS_ENABLED | FLAGS_AVAILABLE);
-
-	if (irq_ptr->status & (FLAGS_ENABLED | FLAGS_AVAILABLE))
-		irq_ptr->status &= (~FLAGS_AVAILABLE);
-	else
-	{
-		DPF(2, "IRQ acquire failure\n");
-		return CTSTATUS_INUSE;
-	}
-
-	DPD(2, "IRQ : Acquired channel %u\n", irq_ptr->irq);
-	return CTSTATUS_SUCCESS;
-}
-
-
-/************************************************************************
- *
- *   int    sblive_irqmgrExit(struct sblive_irq *irq_ptr)
- *
- *   ENTRY
- *       irq_ptr -   Card irq object
- *
- *   RETURNS
- *       Always returns CTSTATUS_SUCCESS
- *
- *   ABOUT
- *       Shutdown code
- *
- ************************************************************************/
-int sblive_irqmgrExit(struct sblive_irq *irq_ptr)
-{
-	irq_ptr->status |= FLAGS_AVAILABLE;
-	free_irq(irq_ptr->irq, irq_ptr);
-	irq_ptr->status &= ~FLAGS_ENABLED;
 
-	return CTSTATUS_SUCCESS;
-}
+/* Enables the specified irq service */
 
-/************************************************************************
- *
- *   int    sblive_irqmgrEnableIrq(struct sblive_hw * sb_hw, u16 wIrqType)
- *
- *   ENTRY
- *       sb_hw -   Card object
- *       wIrqType-   type of service to enable interrupt for
- *
- *   RETURNS
- *       Always returns CTSTATUS_SUCCESS
- *
- *   ABOUT
- *       Enables the specified irq service
- *
- ************************************************************************/
-int sblive_irqmgrEnableIrq(struct sblive_hw *sb_hw, u32 irqtype)
+int emu10k1_irq_enable(struct emu10k1_card *card, u32 irqtype)
 {
 	/*
 	 * TODO :
@@ -199,30 +104,15 @@
 	 * screw-up another cardxxx objects irqs
 	 */
 
-	DPD(4, "sblive_irqmgrEnableIrq %x\n", irqtype);
-	sblive_wrtmskfn0(sb_hw, INTE, irqtype, ENABLE);
+	DPD(4, "emu10k1_irq_enable %x\n", irqtype);
+	sblive_wrtmskfn0(card, INTE, irqtype, ENABLE);
 
 	return CTSTATUS_SUCCESS;
 }
 
-
-/************************************************************************
- *
- *   int    sblive_irqmgrDisableIrq(struct sblive_hw * sb_hw, u16 wIrqType)
- *
- *   ENTRY
- *       sb_hw -   Card object
- *       wIrqType-   type of service to disable interrupt for
- *
- *   RETURNS
- *       Always returns CTSTATUS_SUCCESS
- *
- *   ABOUT
- *       Disables the specified irq service
- *
- ************************************************************************/
+/* Disables the specified irq service */
 
-int sblive_irqmgrDisableIrq(struct sblive_hw *sb_hw, u32 irqtype)
+int emu10k1_irq_disable(struct emu10k1_card *card, u32 irqtype)
 {
 	/*
 	 * TODO :
@@ -230,9 +120,8 @@
 	 * screw-up another cardxxx objects irqs
 	 */
 
-	DPD(4, "sblive_irqmgrDisableIrq %x\n", irqtype);
-	sblive_wrtmskfn0(sb_hw, INTE, irqtype, DISABLE);
+	DPD(4, "emu10k1_irq_disable %x\n", irqtype);
+	sblive_wrtmskfn0(card, INTE, irqtype, DISABLE);
 
 	return CTSTATUS_SUCCESS;
 }
-
Index: oldkernel/linux/drivers/sound/emu10k1/irqmgr.h
diff -u linux/drivers/sound/emu10k1/irqmgr.h:1.1 linux/drivers/sound/emu10k1/irqmgr.h:1.2
--- linux/drivers/sound/emu10k1/irqmgr.h:1.1	Thu Jun  1 16:52:15 2000
+++ linux/drivers/sound/emu10k1/irqmgr.h	Fri Jul  7 15:36:45 2000
@@ -32,30 +32,28 @@
 #ifndef _IRQ_H
 #define _IRQ_H
 
-struct sblive_irq
-{
-	u32     	ID;
-	u32		status;
-	u32 		irq;
-	struct sblive_hw *sb_hw;
-};
+/* EMU Irq Types */
+#define IRQTYPE_PCIBUSERROR         IPR_PCIERROR
+#define IRQTYPE_MIXERBUTTON         (IPR_VOLINCR | IPR_VOLDECR | IPR_MUTE)
+#define IRQTYPE_VOICE               (IPR_CHANNELLOOP | IPR_CHANNELNUMBERMASK)
+#define IRQTYPE_RECORD              (IPR_ADCBUFFULL | IPR_ADCBUFHALFFULL | IPR_MICBUFFULL | IPR_MICBUFHALFFULL | IPR_EFXBUFFULL | IPR_EFXBUFHALFFULL)
+#define IRQTYPE_MPUOUT              IPR_MIDITRANSBUFEMPTY
+#define IRQTYPE_MPUIN               IPR_MIDIRECVBUFEMPTY
+#define IRQTYPE_TIMER               IPR_INTERVALTIMER
+#define IRQTYPE_SPDIF               (IPR_GPSPDIFSTATUSCHANGE | IPR_CDROMSTATUSCHANGE)
+#define IRQTYPE_DSP                 IPR_FXDSP
 
-struct sblive_wavedevice
+struct emu10k1_wavedevice
 {
-        struct sblive_hw *sb_hw;
+        struct emu10k1_card *card;
         struct wiinst *wiinst;
         struct woinst *woinst;
         u16 enablebits;
 };
-
-int sblive_timerIrqCallback(struct sblive_hw *);
-int sblive_waveinIrqCallback(struct sblive_hw *);
 
-int sblive_irqmgrInit(struct sblive_irq *);
-int sblive_irqmgrExit(struct sblive_irq *);
-int sblive_irqmgrEnableIrq(struct sblive_hw *, u32);
-int sblive_irqmgrDisableIrq(struct sblive_hw *, u32);
+void emu10k1_timer_irqhandler(struct emu10k1_card *);
 
-#define EMU10K1_INTERRUPT_ID 0xfeebbeef
+int emu10k1_irq_enable(struct emu10k1_card *, u32);
+int emu10k1_irq_disable(struct emu10k1_card *, u32);
 
 #endif /* _IRQ_H */
Index: oldkernel/linux/drivers/sound/emu10k1/main.c
diff -u linux/drivers/sound/emu10k1/main.c:1.1 linux/drivers/sound/emu10k1/main.c:1.2
--- linux/drivers/sound/emu10k1/main.c:1.1	Thu Jun  1 16:52:15 2000
+++ linux/drivers/sound/emu10k1/main.c	Fri Jul  7 15:36:45 2000
@@ -1,3 +1,4 @@
+
 /*
  **********************************************************************
  *     main.c - Creative EMU10K1 audio driver
@@ -32,7 +33,6 @@
  *      Supported devices:
  *      /dev/dsp:     Standard /dev/dsp device, OSS-compatible
  *      /dev/mixer:   Standard /dev/mixer device, OSS-compatible
- *      /dev/sndstat: Standard /dev/sndstat device, mostly OSS-compatible
  *      /dev/midi:    Raw MIDI UART device, mostly OSS-compatible
  *
  *      Revision history:
@@ -40,25 +40,28 @@
  *      0.2 Lowered initial mixer vol. Improved on stuttering wave playback. Added MIDI UART support.
  *      0.3 Fixed mixer routing bug, added APS, joystick support.
  *      0.4 Added rear-channel, SPDIF support.
- *
+ *	0.5 Source cleanup, SMP fixes, multiopen support, 64 bit arch fixes,
+ *	    moved bh's to tasklets, moved to the new PCI driver initialization style.
  **********************************************************************
  */
 
-
 /* These are only included once per module */
-#ifdef MODULE
 #include <linux/module.h>
-#else
+#include <linux/init.h>
 
-#endif
-
 #include "hwaccess.h"
-#include "mycommon.h"
+#include "efxmgr.h"
 #include "cardwo.h"
-#include "audio.h"
-#include "midi.h"
-#include "sndstat.h"
+#include "cardwi.h"
+#include "cardmo.h"
+#include "cardmi.h"
+#include "recmgr.h"
+
+#define DRIVER_VERSION "0.5"
 
+/* FIXME: is this right? */
+#define EMU10K1_DMA_MASK                0xffffffff	/* DMA buffer mask for pci_alloc_consist */
+
 #ifndef PCI_VENDOR_ID_CREATIVE
 #define PCI_VENDOR_ID_CREATIVE 0x1102
 #endif
@@ -68,302 +71,758 @@
 #endif
 
 #define EMU10K1_EXTENT	0x20	/* 32 byte I/O space */
-#define JOY_EXTENT	0x8	/* 8 byte I/O space */
-#define MAX_EMU10K1	5
+
+enum {
+	EMU10K1 = 0,
+};
+
+static char *card_names[] __devinitdata = {
+	"EMU10K1",
+};
+
+static struct pci_device_id emu10k1_pci_tbl[] __initdata = {
+	{PCI_VENDOR_ID_CREATIVE, PCI_DEVICE_ID_CREATIVE_EMU10K1,
+	 PCI_ANY_ID, PCI_ANY_ID, 0, 0, EMU10K1},
+	{0,}
+};
+
+MODULE_DEVICE_TABLE(pci, emu10k1_pci_tbl);
 
 /* Global var instantiation */
 
-struct sblive_hw *sblive_devs = NULL;
-static unsigned long joystick[MAX_EMU10K1 + 1] =
-{0,};
+LIST_HEAD(emu10k1_devs);
 
-/* Function prototypes */
-extern int sblive_mixer_init(struct sblive_hw *sb_hw);
+extern struct file_operations emu10k1_audio_fops;
+extern struct file_operations emu10k1_mixer_fops;
+extern struct file_operations emu10k1_midi_fops;
 
-/* Driver initialization routine */
-#ifdef MODULE
-int init_module(void)
-#else
-	int __init init_emu10k1(void)
-#endif
+extern void emu10k1_interrupt(int, void *, struct pt_regs *s);
+extern int emu10k1_mixer_wrch(struct emu10k1_card *, unsigned int, int);
+
+static int __devinit audio_init(struct emu10k1_card *card)
 {
-	struct sblive_hw *hw_obj;
-	u32 hwflags = 0;
-	unsigned int index = 0, serial = 0;
-	unsigned long ioaddr;
-	unsigned char bus, devfn, ucRevID = 0;
-	struct sblive_config dsConfig;
-	struct sblive_config *config = &dsConfig;
-	struct pci_dev *pcidev=NULL, *pcidev_joy=NULL;
-	unsigned long irq;
-	unsigned long ioaddr1 = 0;
-
-	DPF(2, "init_module() called\n");
-
-	/* Do not export symbols */
-#ifdef MODULE
-	EXPORT_NO_SYMBOLS;
-#endif /* MODULE */
+	if ((card->waveout = kmalloc(sizeof(struct emu10k1_waveout), GFP_KERNEL)) == NULL) {
+		printk(KERN_WARNING "emu10k1: Unable to allocate emu10k1_waveout: out of memory\n");
+		return CTSTATUS_ERROR;
+	}
+	memset(card->waveout, 0, sizeof(struct emu10k1_waveout));
 
-	if (!pci_present())
-		return -ENODEV;
+	/* Assign default global volume, reverb, chorus */
+	card->waveout->globalvol = 0xffffffff;
+	card->waveout->left = 0xffff;
+	card->waveout->right = 0xffff;
+	card->waveout->mute = 0;
+	card->waveout->globalreverb = 0xffffffff;
+	card->waveout->globalchorus = 0xffffffff;
+
+	if ((card->wavein = kmalloc(sizeof(struct emu10k1_wavein), GFP_KERNEL))
+	    == NULL) {
+		printk(KERN_WARNING "emu10k1: Unable to allocate emu10k1_wavein: out of memory\n");
+		return CTSTATUS_ERROR;
+	}
+	memset(card->wavein, 0, sizeof(struct emu10k1_wavein));
+
+	card->wavein->recsrc = WAVERECORD_AC97;
+
+	return CTSTATUS_SUCCESS;
+}
+
+static void __devinit mixer_init(struct emu10k1_card *card)
+{
+	int count;
+	struct initvol {
+		int mixch;
+		int vol;
+	} initvol[] = {
+		{
+		SOUND_MIXER_VOLUME, 0x5050}, {
+		SOUND_MIXER_OGAIN, 0x3232}, {
+		SOUND_MIXER_SPEAKER, 0x3232}, {
+		SOUND_MIXER_PHONEIN, 0x3232}, {
+		SOUND_MIXER_MIC, 0x0000}, {
+		SOUND_MIXER_LINE, 0x0000}, {
+		SOUND_MIXER_CD, 0x3232}, {
+		SOUND_MIXER_LINE1, 0x3232}, {
+		SOUND_MIXER_LINE3, 0x3232}, {
+		SOUND_MIXER_DIGITAL1, 0x6464}, {
+		SOUND_MIXER_DIGITAL2, 0x6464}, {
+		SOUND_MIXER_PCM, 0x6464}, {
+		SOUND_MIXER_RECLEV, 0x3232}, {
+		SOUND_MIXER_TREBLE, 0x3232}, {
+		SOUND_MIXER_BASS, 0x3232}, {
+		SOUND_MIXER_LINE2, 0x4b4b}};
+
+	int initdig[] = { 0, 1, 2, 3, 6, 7, 18, 19, 20, 21, 24, 25, 72, 73, 74, 75, 78, 79,
+		94, 95
+	};
+
+	/* Reset */
+	sblive_writeac97(card, AC97_RESET, 0);
 
-	/* PCI BIOS detected */
-	for (index = 0; index < MAX_EMU10K1 &&
-	     (pcidev = pci_find_device(PCI_VENDOR_ID_CREATIVE, PCI_DEVICE_ID_CREATIVE_EMU10K1, pcidev));
-	     index++)
+#if 0
+	/* Check status word */
 	{
-		bus = pcidev->bus->number;
-		devfn = pcidev->devfn;
-		DPD(2, "Function 0: devfn %x\n", devfn);
-		/* Joystick is on the same bus and dev, but is function #1 */
-		if ((pcidev_joy=pci_find_slot(bus, devfn + 1))) {
-			DPD(2, "Function 1 exists: devfn %x\n", devfn + 1);
-		}
-		/* Device found - Query PCI BIOS info */
-		DPD(1, "Emu10k1 device %d found!\n", index);
+		u16 reg;
 
-		ioaddr = RSRCADDRESS(pcidev, 0);
-		if (pcidev_joy)
-			ioaddr1 = RSRCADDRESS(pcidev_joy, 0);
+		sblive_readac97(card, AC97_RESET, &reg);
+		DPD(2, "RESET 0x%x\n", reg);
+		sblive_readac97(card, AC97_MASTERTONE, &reg);
+		DPD(2, "MASTER_TONE 0x%x\n", reg);
+	}
+#endif
 
-		if (!RSRCISIOREGION(pcidev, 0) || !RSRCISIOREGION(pcidev_joy, 0))
-			continue;
+	/* Set default recording source to mic in */
+	sblive_writeac97(card, AC97_RECORDSELECT, 0);
 
-		ioaddr = ioaddr & PCI_BASE_ADDRESS_IO_MASK;
-		DPD(1, "Function 0 IO Base Address = %#lx\n", ioaddr);
+	/* Set default AC97 "PCM" volume to acceptable max */
+	//sblive_writeac97(card, AC97_PCMOUTVOLUME, 0);
+	//sblive_writeac97(card, AC97_LINE2, 0);
+
+	/* Set default volumes for all mixer channels */
+
+	for (count = 0; count < sizeof(card->digmix) / sizeof(card->digmix[0]); count++) {
+		card->digmix[count] = 0x80000000;
+		sblive_writeptr(card, FXGPREGBASE + 0x10 + count, 0, 0);
+	}
 
-		if (pcidev_joy)
-		{
-			ioaddr1 = ioaddr1 & PCI_BASE_ADDRESS_IO_MASK;
-			DPD(1, "Function 1 IO Base Address = %#lx\n", ioaddr1);
-		}
+	for (count = 0; count < sizeof(initdig) / sizeof(initdig[0]); count++) {
+		card->digmix[initdig[count]] = 0x7fffffff;
+		sblive_writeptr(card, FXGPREGBASE + 0x10 + initdig[count], 0, 0x7fffffff);
+	}
 
-		irq = pcidev->irq;
+	for (count = 0; count < sizeof(initvol) / sizeof(initvol[0]); count++) {
+		emu10k1_mixer_wrch(card, initvol[count].mixch, initvol[count].vol);
+	}
 
-		/*
-		 *	Some BIOSes screw this stuff up. Its worth reporting
-		 *	to the user
-		 */
+	card->modcnt = 0;	// Should this be here or in open() ?
 
-		if (irq == 0)
-		{
-			printk(KERN_ERR "sblive: No IRQ has been assigned to this device. Check your BIOS settings.\n");
-			continue;
-		}
+	return;
+}
 
-		DPD(1, "IRQ Line = %lu\n", irq);
+static int __devinit midi_init(struct emu10k1_card *card)
+{
+	if ((card->mpuout = kmalloc(sizeof(struct emu10k1_mpuout), GFP_KERNEL))
+	    == NULL) {
+		printk(KERN_WARNING "emu10k1: Unable to allocate emu10k1_mpuout: out of memory\n");
+		return CTSTATUS_ERROR;
+	}
 
-		pci_read_config_byte(pcidev, PCI_REVISION_ID, &ucRevID);
-		DPD(1, "Revision ID = %u\n", ucRevID);
+	memset(card->mpuout, 0, sizeof(struct emu10k1_mpuout));
 
-		pci_read_config_dword(pcidev, PCI_SUBSYSTEM_VENDOR_ID, &serial);
-		DPD(1, "Serial No = %08x\n", serial);
+	card->mpuout->intr = 1;
+	card->mpuout->status = FLAGS_AVAILABLE;
+	card->mpuout->state = CARDMIDIOUT_STATE_DEFAULT;
 
-		/* Initialize device struct */
-		hw_obj = kmalloc(sizeof(*hw_obj), GFP_KERNEL);
-		if (!hw_obj)
-		{
-			printk(KERN_WARNING "emu10k1: out of memory\n");
-			continue;
-		}
-		DPD(3, "kmalloc: [%p]\n", hw_obj);
-		memset(hw_obj, 0, sizeof(*hw_obj)); /* FIXME: use bzero()? */
+	tasklet_init(&card->mpuout->tasklet, emu10k1_mpuout_bh, (unsigned long) card);
 
-		hw_obj->pcidev_joy = pcidev_joy;
-		hw_obj->joybase = ioaddr1;
-		printk(KERN_INFO "Creative SBLive! at %#lx on irq %lu\n", ioaddr, irq);
+	spin_lock_init(&card->mpuout->lock);
 
-		DPD(3, "kmalloc: [%p]\n", config);
-		memset(config, 0, sizeof(*config)); /* FIXME: use bzero()? */
+	if ((card->mpuin = kmalloc(sizeof(struct emu10k1_mpuin), GFP_KERNEL)) == NULL) {
+		kfree(card->mpuout);
+		printk(KERN_WARNING "emu10k1: Unable to allocate emu10k1_mpuin: out of memory\n");
+		return CTSTATUS_ERROR;
+	}
 
-		config->vendorid = PCI_VENDOR_ID_CREATIVE;
-		config->serialno = serial;
-		config->logdevid = PCI_DEVICE_ID_CREATIVE_EMU10K1;
-		config->chiprev = ucRevID;
+	memset(card->mpuin, 0, sizeof(struct emu10k1_mpuin));
 
-		config->nummemwindows = 0;
+	card->mpuin->status = FLAGS_AVAILABLE;
 
-		config->numioports = 1;
-		config->ioportbase[0] = ioaddr;
-		config->ioportlenh[0] = EMU10K1_EXTENT;
+	tasklet_init(&card->mpuin->tasklet, emu10k1_mpuin_bh, (unsigned long) card->mpuin);
 
-		config->numirq = 1;
-		config->IRQregs[0] = irq;
-		config->irqattr[0] = 0;	/* Doesn't matter */
+	spin_lock_init(&card->mpuin->lock);
 
-		config->numdma = 0;
+	/* Reset the MPU port */
+	if (emu10k1_mpu_reset(card) != CTSTATUS_SUCCESS) {
+		ERROR();
+		return CTSTATUS_ERROR;
+	}
 
-		/* Reserve I/O region */
-		if (check_region(ioaddr, EMU10K1_EXTENT))
-		{
-			printk(KERN_ERR "emu10k1: io ports %#lx-%#lx in use\n",
-			       ioaddr, ioaddr + EMU10K1_EXTENT - 1);
-			goto err_region1;
-		}
-		request_region(ioaddr, EMU10K1_EXTENT, "emu10k1");
+	return CTSTATUS_SUCCESS;
+}
 
-		if (check_region(ioaddr1, JOY_EXTENT))
-		{
-			printk(KERN_ERR "emu10k1: io ports %#x-%#x in use\n",
-			       (unsigned int) ioaddr1, (unsigned int) ioaddr1 + JOY_EXTENT - 1);
-			goto err_region2;
-		}
-		request_region(ioaddr1, JOY_EXTENT, "emu10k1 joystick");
+static void __devinit voice_init(struct emu10k1_card *card)
+{
+	struct voice_manager *voicemgr = &card->voicemgr;
+	struct emu_voice *voice;
+	int i;
+
+	voicemgr->card = card;
+	voicemgr->lock = SPIN_LOCK_UNLOCKED;
+
+	voice = voicemgr->voice;
+	for (i = 0; i < NUM_G; i++) {
+		voice->card = card;
+		voice->usage = VOICEMGR_USAGE_FREE;
+		voice->num = i;
+		voice->linked_voice = NULL;
+		voice++;
+	}
 
-		/* Register devices */
-		hw_obj->audio_num = register_sound_dsp(&emu10k1_audio_fops, -1);
-		if (hw_obj->audio_num < 0)
-		{
-			printk(KERN_ERR "emu10k1: cannot register audio device!\n");
-			goto err_dev1;
-		}
+	return;
+}
 
-		hw_obj->mixer_num = register_sound_mixer(&emu10k1_mixer_fops, -1);
-		if (hw_obj->mixer_num < 0)
-		{
-			printk(KERN_ERR "emu10k1: cannot register mixer device!\n");
-			goto err_dev2;
-		}
+static void __devinit timer_init(struct emu10k1_card *card)
+{
+	INIT_LIST_HEAD(&card->timers);
+	card->timer_delay = TIMER_STOPPED;
+	card->timer_lock = SPIN_LOCK_UNLOCKED;
 
-		hw_obj->midi_num = register_sound_midi(&emu10k1_midi_fops, -1);
-		if (hw_obj->midi_num < 0)
-		{
-			printk(KERN_ERR "emu10k1: cannot register MIDI device!\n");
-			goto err_dev4;
+	return;
+}
+
+static void __devinit addxmgr_init(struct emu10k1_card *card)
+{
+	u32 count;
+
+	for (count = 0; count < MAXPAGES; count++)
+		card->emupagetable[count] = 0;
+
+	/* Mark first page as used */
+	/* This page is reserved by the driver */
+	card->emupagetable[0] = 0x8001;
+	card->emupagetable[1] = MAXPAGES - RESERVED - 1;
+
+	return;
+}
+
+static void __devinit fx_init(struct emu10k1_card *card)
+{
+	int i, j, k, l;
+	u32 pc = 0;
+
+	for (i = 0; i < 512; i++)
+		OP(6, 0x40, 0x40, 0x40, 0x40);
+
+	for (i = 0; i < 256; i++)
+		sblive_writeptr(card, FXGPREGBASE + i, 0, 0);
+
+	pc = 0;
+
+	for (j = 0; j < 2; j++) {
+
+		OP(4, 0x100, 0x40, j, 0x44);
+		OP(4, 0x101, 0x40, j + 2, 0x44);
+
+		for (i = 0; i < 6; i++) {
+			k = i * 18 + j;
+			OP(0, 0x102, 0x40, 0x110 + k, 0x100);
+			OP(0, 0x102, 0x102, 0x112 + k, 0x101);
+			OP(0, 0x102, 0x102, 0x114 + k, 0x10 + j);
+			OP(0, 0x102, 0x102, 0x116 + k, 0x12 + j);
+			OP(0, 0x102, 0x102, 0x118 + k, 0x14 + j);
+			OP(0, 0x102, 0x102, 0x11a + k, 0x16 + j);
+			OP(0, 0x102, 0x102, 0x11c + k, 0x18 + j);
+			OP(0, 0x102, 0x102, 0x11e + k, 0x1a + j);
+			OP(0, 0x102, 0x102, 0x120 + k, 0x1c + j);
+
+			k = 0x1a0 + i * 8 + j * 4;
+			OP(0, 0x40, 0x40, 0x102, 0x180 + j);
+			OP(7, k + 1, k, k + 1, 0x184 + j);
+			OP(7, k, 0x102, k, 0x182 + j);
+			OP(7, k + 3, k + 2, k + 3, 0x188 + j);
+			OP(0, k + 2, 0x56, k + 2, 0x186 + j);
+			OP(6, k + 2, k + 2, k + 2, 0x40);
+
+			l = 0x1d0 + i * 8 + j * 4;
+			OP(0, 0x40, 0x40, k + 2, 0x190 + j);
+			OP(7, l + 1, l, l + 1, 0x194 + j);
+			OP(7, l, k + 2, l, 0x192 + j);
+			OP(7, l + 3, l + 2, l + 3, 0x198 + j);
+			OP(0, l + 2, 0x56, l + 2, 0x196 + j);
+			OP(4, l + 2, 0x40, l + 2, 0x46);
+
+			if (i == 0)
+				OP(0, 0x20 + (i * 2) + j, 0x40, l + 2, 0x4e);		/* FIXME: Is this really needed? */
+			else
+				OP(6, 0x20 + (i * 2) + j, l + 2, 0x40, 0x40);
 		}
+	}
+	sblive_writeptr(card, DBG, 0, 0);
 
-		if (pcidev_joy)
-		{
-			if ((joystick[index] & ~0x18) == 0x200)
-			{
-				if (check_region(joystick[index], JOY_EXTENT))
-					printk(KERN_ERR "emu10k1: joystick io ports %lx-%lx in use\n",
-					       joystick[index], joystick[index] + JOY_EXTENT - 1);
-				else {
-					/* Write joystick base address to PCI configuration space */
-					pci_write_config_dword(pcidev_joy, PCI_BASE_ADDRESS_0, joystick[index]);
-#ifdef EMU10K1_DEBUG
-					{
-						u32 base;
-						pci_read_config_dword(pcidev_joy, PCI_BASE_ADDRESS_0, &base);
-						DPD(2, " read back joystick base address is %x\n", base);
-					}
+	return;
+}
+
+static int __devinit hw_init(struct emu10k1_card *card)
+{
+	int nCh;
+
+#ifdef TANKMEM
+	u32 size = 0;
 #endif
-				}
-			}
-		}
+	u32 sizeIdx = 0;
+	u32 pagecount, tmp;
 
-		/* Register-level initialization goes here.... */
-		DPF(2, "Initializing hardware....\n");
-		/* IRQ reservation happens in halInit */
-		if (halInit(hw_obj, config, &hwflags) != CTSTATUS_SUCCESS) {
-			printk(KERN_ERR "emu10k1: cannot initialize device!\n");
-			goto err_hal_init;
+	/* Disable audio and lock cache */
+	sblive_writefn0(card, HCFG, HCFG_LOCKSOUNDCACHE | HCFG_LOCKTANKCACHE | HCFG_MUTEBUTTONENABLE);
+
+	/* Reset recording buffers */
+	sblive_writeptr(card, MICBS, 0, ADCBS_BUFSIZE_NONE);
+	sblive_writeptr(card, MICBA, 0, 0);
+	sblive_writeptr(card, FXBS, 0, ADCBS_BUFSIZE_NONE);
+	sblive_writeptr(card, FXBA, 0, 0);
+	sblive_writeptr(card, ADCBS, 0, ADCBS_BUFSIZE_NONE);
+	sblive_writeptr(card, ADCBA, 0, 0);
+
+	/* Disable channel interrupt */
+	sblive_writefn0(card, INTE, DISABLE);
+	sblive_writeptr(card, CLIEL, 0, 0);
+	sblive_writeptr(card, CLIEH, 0, 0);
+	sblive_writeptr(card, SOLEL, 0, 0);
+	sblive_writeptr(card, SOLEH, 0, 0);
+
+	/* Init envelope engine */
+	for (nCh = 0; nCh < NUM_G; nCh++) {
+		sblive_writeptr(card, DCYSUSV, nCh, ENV_OFF);
+		sblive_writeptr(card, IP, nCh, 0);
+		sblive_writeptr(card, VTFT, nCh, 0xffff);
+		sblive_writeptr(card, CVCF, nCh, 0xffff);
+		sblive_writeptr(card, PTRX, nCh, 0);
+		sblive_writeptr(card, CPF, nCh, 0);
+		sblive_writeptr(card, CCR, nCh, 0);
+
+		sblive_writeptr(card, PSST, nCh, 0);
+		sblive_writeptr(card, DSL, nCh, 0x10);
+		sblive_writeptr(card, CCCA, nCh, 0);
+		sblive_writeptr(card, Z1, nCh, 0);
+		sblive_writeptr(card, Z2, nCh, 0);
+		sblive_writeptr(card, FXRT, nCh, 0xd01c0000);
+
+		sblive_writeptr(card, ATKHLDM, nCh, 0);
+		sblive_writeptr(card, DCYSUSM, nCh, 0);
+		sblive_writeptr(card, IFATN, nCh, 0xffff);
+		sblive_writeptr(card, PEFE, nCh, 0);
+		sblive_writeptr(card, FMMOD, nCh, 0);
+		sblive_writeptr(card, TREMFRQ, nCh, 24);	/* 1 Hz */
+		sblive_writeptr(card, FM2FRQ2, nCh, 24);	/* 1 Hz */
+		sblive_writeptr(card, TEMPENV, nCh, 0);
+
+		/*** These are last so OFF prevents writing ***/
+		sblive_writeptr(card, LFOVAL2, nCh, 0);
+		sblive_writeptr(card, LFOVAL1, nCh, 0);
+		sblive_writeptr(card, ATKHLDV, nCh, 0);
+		sblive_writeptr(card, ENVVOL, nCh, 0);
+		sblive_writeptr(card, ENVVAL, nCh, 0);
+	}
+
+	/*
+	 ** Init to 0x02109204 :
+	 ** Clock accuracy    = 0     (1000ppm)
+	 ** Sample Rate       = 2     (48kHz)
+	 ** Audio Channel     = 1     (Left of 2)
+	 ** Source Number     = 0     (Unspecified)
+	 ** Generation Status = 1     (Original for Cat Code 12)
+	 ** Cat Code          = 12    (Digital Signal Mixer)
+	 ** Mode              = 0     (Mode 0)
+	 ** Emphasis          = 0     (None)
+	 ** CP                = 1     (Copyright unasserted)
+	 ** AN                = 0     (Digital audio)
+	 ** P                 = 0     (Consumer)
+	 */
+
+	/* SPDIF0 */
+	sblive_writeptr(card, SPCS0, 0, SPCS_CLKACCY_1000PPM | 0x002000000 |
+			SPCS_CHANNELNUM_LEFT | SPCS_SOURCENUM_UNSPEC | SPCS_GENERATIONSTATUS | 0x00001200 | SPCS_EMPHASIS_NONE | SPCS_COPYRIGHT);
+
+	/* SPDIF1 */
+	sblive_writeptr(card, SPCS1, 0, SPCS_CLKACCY_1000PPM | 0x002000000 |
+			SPCS_CHANNELNUM_LEFT | SPCS_SOURCENUM_UNSPEC | SPCS_GENERATIONSTATUS | 0x00001200 | SPCS_EMPHASIS_NONE | SPCS_COPYRIGHT);
+
+	/* SPDIF2 & SPDIF3 */
+	sblive_writeptr(card, SPCS2, 0, SPCS_CLKACCY_1000PPM | 0x002000000 |
+			SPCS_CHANNELNUM_LEFT | SPCS_SOURCENUM_UNSPEC | SPCS_GENERATIONSTATUS | 0x00001200 | SPCS_EMPHASIS_NONE | SPCS_COPYRIGHT);
+
+	fx_init(card);		/* initialize effects engine */
+
+	card->tankmem = NULL;
+
+#ifdef TANKMEM
+	size = TMEMSIZE;
+	sizeIdx = TMEMSIZEREG;
+	while (size > 16384) {
+		if ((card->tankmem = emu10k1_alloc_memphysical(size)) != NULL)
+			break;
+
+		size /= 2;
+		sizeIdx -= 1;
+	}
+
+	if (card->tankmem == NULL) {
+		card->tmemsize = 0;
+		return CTSTATUS_ERROR;
+	}
+
+	card->tmemsize = size;
+#else				/* !TANKMEM */
+	card->tmemsize = 0;
+#endif				/* TANKMEM */
+
+	if ((card->virtualpagetable = emu10k1_alloc_memphysical((MAXPAGES - RESERVED) * sizeof(u32))) == NULL) {
+		ERROR();
+		emu10k1_free_memphysical(card->tankmem);
+		return CTSTATUS_ERROR;
+	}
+
+	if ((card->silentpage = emu10k1_alloc_memphysical(EMUPAGESIZE)) == NULL) {
+		ERROR();
+		emu10k1_free_memphysical(card->tankmem);
+		emu10k1_free_memphysical(card->virtualpagetable);
+		return CTSTATUS_ERROR;
+	} else
+		memset(card->silentpage->virtaddx, 0, EMUPAGESIZE);
+
+	for (pagecount = 0; pagecount < (MAXPAGES - RESERVED); pagecount++)
+
+		((u32 *) card->virtualpagetable->virtaddx)[pagecount] = (card->silentpage->busaddx * 2) | pagecount;
+
+	/* Init page table & tank memory base register */
+	sblive_writeptr(card, PTB, 0, card->virtualpagetable->busaddx);
+#ifdef TANKMEM
+	sblive_writeptr(card, TCB, 0, card->tankmem->busaddx);
+#else
+	sblive_writeptr(card, TCB, 0, 0);
+#endif
+	sblive_writeptr(card, TCBS, 0, sizeIdx);
+
+	for (nCh = 0; nCh < NUM_G; nCh++) {
+		sblive_writeptr(card, MAPA, nCh, MAP_PTI_MASK | (card->silentpage->busaddx * 2));
+		sblive_writeptr(card, MAPB, nCh, MAP_PTI_MASK | (card->silentpage->busaddx * 2));
+	}
+
+	/* Hokay, now enable the AUD bit */
+	/* Enable Audio = 1 */
+	/* Mute Disable Audio = 0 */
+	/* Lock Tank Memory = 1 */
+	/* Lock Sound Memory = 0 */
+	/* Auto Mute = 1 */
+
+	sblive_rmwac97(card, AC97_MASTERVOLUME, 0x8000, 0x8000);
+
+	sblive_writeac97(card, AC97_MASTERVOLUME, 0);
+	sblive_writeac97(card, AC97_PCMOUTVOLUME, 0);
+
+	sblive_writefn0(card, HCFG, HCFG_AUDIOENABLE | HCFG_LOCKTANKCACHE | HCFG_AUTOMUTE | HCFG_JOYENABLE);
+
+	/* TOSLink detection */
+	card->has_toslink = 0;
+
+	tmp = sblive_readfn0(card, HCFG);
+	if (tmp & (HCFG_GPINPUT0 | HCFG_GPINPUT1)) {
+		sblive_writefn0(card, HCFG, tmp | 0x800);
+
+		udelay(512);
+
+		if (tmp != (sblive_readfn0(card, HCFG) & ~0x800)) {
+			card->has_toslink = 1;
+			sblive_writefn0(card, HCFG, tmp);
 		}
-		init_MUTEX(&hw_obj->open_sem);
-		hw_obj->open_mode = 0;
-		init_waitqueue_head(&hw_obj->open_wait);
-
-		DPD(2, "Hardware initialized. TRAM allocated: %u bytes\n", (unsigned int) hw_obj->tmemsize);
-
-
-		audio_init(hw_obj, "SBLive!");
-		sblive_mixer_init(hw_obj);
-
-		midi_init(hw_obj);
-
-		/* AOK, update global device list */
-		hw_obj->next = sblive_devs;
-		sblive_devs = hw_obj;
-
-		hw_obj->prev = NULL;
-		if (hw_obj->next)
-			hw_obj->next->prev = hw_obj;
-		continue;
-
-		/* Error handlers */
-		/* FIXME: These must reflect the device init order... */
-	err_hal_init:
-		halExit(hw_obj);	/* Should this be called? */
-
-		unregister_sound_midi(hw_obj->midi_num);
-	err_dev4:
-		unregister_sound_mixer(hw_obj->mixer_num);
-	err_dev2:
-		unregister_sound_dsp(hw_obj->audio_num);
-	err_dev1:
-		/* free_irq(hw_obj->irq, hw_obj); */
-		/*  err_irq: */
-		release_region(ioaddr1, JOY_EXTENT);
-	err_region2:
-		release_region(ioaddr, EMU10K1_EXTENT);
-	err_region1:
-		kfree(hw_obj);
-		DPD(3, "kfree: [%p]\n", hw_obj);
+	}
+
+	return CTSTATUS_SUCCESS;
+}
+
+static int __devinit emu10k1_init(struct emu10k1_card *card)
+{
+	/* Init Card */
+	if (hw_init(card) != CTSTATUS_SUCCESS)
+		return CTSTATUS_ERROR;
+
+	voice_init(card);
+	timer_init(card);
+	addxmgr_init(card);
+
+	DPD(2, "  hw control register -> %x\n", sblive_readfn0(card, HCFG));
+
+	return CTSTATUS_SUCCESS;
+}
+
+static void __devexit audio_exit(struct emu10k1_card *card)
+{
+	kfree(card->waveout);
+	kfree(card->wavein);
+	return;
+}
+
+static void __devexit midi_exit(struct emu10k1_card *card)
+{
+	tasklet_unlock_wait(&card->mpuout->tasklet);
+	kfree(card->mpuout);
+
+	tasklet_unlock_wait(&card->mpuin->tasklet);
+	kfree(card->mpuin);
+
+	return;
+}
+
+static void __devexit emu10k1_exit(struct emu10k1_card *card)
+{
+	int ch;
+
+	sblive_writefn0(card, INTE, DISABLE);
+
+	/** Shutdown the chip **/
+	for (ch = 0; ch < NUM_G; ch++)
+		sblive_writeptr(card, DCYSUSV, ch, ENV_OFF);
+
+	for (ch = 0; ch < NUM_G; ch++) {
+		sblive_writeptr(card, VTFT, ch, 0);
+		sblive_writeptr(card, CVCF, ch, 0);
+		sblive_writeptr(card, PTRX, ch, 0);
+		sblive_writeptr(card, CPF, ch, 0);
+	}
+
+	/* Reset recording buffers */
+	sblive_writeptr(card, MICBS, 0, ADCBS_BUFSIZE_NONE);
+	sblive_writeptr(card, MICBA, 0, 0);
+	sblive_writeptr(card, FXBS, 0, ADCBS_BUFSIZE_NONE);
+	sblive_writeptr(card, FXBA, 0, 0);
+	sblive_writeptr(card, FXWC, 0, 0);
+	sblive_writeptr(card, ADCBS, 0, ADCBS_BUFSIZE_NONE);
+	sblive_writeptr(card, ADCBA, 0, 0);
+	sblive_writeptr(card, TCBS, 0, TCBS_BUFFSIZE_16K);
+	sblive_writeptr(card, TCB, 0, 0);
+	sblive_writeptr(card, DBG, 0, 0x8000);
+
+	/* Disable channel interrupt */
+	sblive_writeptr(card, CLIEL, 0, 0);
+	sblive_writeptr(card, CLIEH, 0, 0);
+	sblive_writeptr(card, SOLEL, 0, 0);
+	sblive_writeptr(card, SOLEH, 0, 0);
+
+	/* Disable audio and lock cache */
+	sblive_writefn0(card, HCFG, HCFG_LOCKSOUNDCACHE | HCFG_LOCKTANKCACHE | HCFG_MUTEBUTTONENABLE);
+	sblive_writeptr(card, PTB, 0, 0);
+
+	emu10k1_free_memphysical(card->silentpage);
+	emu10k1_free_memphysical(card->virtualpagetable);
+#ifdef TANKMEM
+	emu10k1_free_memphysical(card->tankmem);
+#endif
+	return;
+}
+
+/* Driver initialization routine */
+static int __devinit emu10k1_probe(struct pci_dev *pci_dev, const struct pci_device_id *pci_id)
+{
+	struct emu10k1_card *card;
+
+	if ((card = kmalloc(sizeof(struct emu10k1_card), GFP_KERNEL)) == NULL) {
+		printk(KERN_ERR "emu10k1: out of memory\n");
+		return -ENOMEM;
+	}
+	memset(card, 0, sizeof(struct emu10k1_card));
+
+#if LINUX_VERSION_CODE > 0x020320
+	if (!pci_dma_supported(pci_dev, EMU10K1_DMA_MASK)) {
+		printk(KERN_ERR "emu10k1: architecture does not support 32bit PCI busmaster DMA\n");
+		kfree(card);
+		return -ENODEV;
 	}
 
-	if (!sblive_devs)
+	if (pci_enable_device(pci_dev)) {
+		printk(KERN_ERR "emu10k1: couldn't enable device\n");
+		kfree(card);
 		return -ENODEV;
+	}
+
+	pci_set_master(pci_dev);
+
+	card->iobase = pci_dev->resource[0].start;
+
+	if (request_region(card->iobase, EMU10K1_EXTENT, card_names[pci_id->driver_data]) == NULL) {
+		printk(KERN_ERR "emu10k1: IO space in use\n");
+		kfree(card);
+		return -ENODEV;
+	}
+	pci_dev->driver_data = card;
+	pci_dev->dma_mask = EMU10K1_DMA_MASK;
+#else
+	pci_set_master(pci_dev);
+
+	card->iobase = pci_dev->base_address[0] & PCI_BASE_ADDRESS_IO_MASK;
+
+	if (check_region(card->iobase, EMU10K1_EXTENT)) {
+		printk(KERN_ERR "emu10k1: IO space in use\n");
+		kfree(card);
+		return -ENODEV;
+	}
+
+	request_region(card->iobase, EMU10K1_EXTENT, card_names[pci_id->driver_data]);
+#endif
+	card->irq = pci_dev->irq;
+	card->pci_dev = pci_dev;
+
+	/* Reserve IRQ Line */
+	if (request_irq(card->irq, emu10k1_interrupt, SA_SHIRQ, card_names[pci_id->driver_data], card)) {
+		printk(KERN_ERR "emu10k1: IRQ in use\n");
+		goto err_irq;
+	}
+
+	pci_read_config_byte(pci_dev, PCI_REVISION_ID, &card->chiprev);
+
+	printk(KERN_INFO "emu10k1: %s rev %d found at IO 0x%04lx, IRQ %d\n", card_names[pci_id->driver_data], card->chiprev, card->iobase, card->irq);
+
+	spin_lock_init(&card->lock);
+	card->mixeraddx = card->iobase + AC97DATA;
+	init_MUTEX(&card->open_sem);
+	card->open_mode = 0;
+	init_waitqueue_head(&card->open_wait);
+
+	/* Register devices */
+	if ((card->audio1_num = register_sound_dsp(&emu10k1_audio_fops, -1)) < 0) {
+		printk(KERN_ERR "emu10k1: cannot register first audio device!\n");
+		goto err_dev0;
+	}
+
+	if ((card->audio2_num = register_sound_dsp(&emu10k1_audio_fops, -1)) < 0) {
+		printk(KERN_ERR "emu10k1: cannot register second audio device!\n");
+		goto err_dev1;
+	}
 
-	sblive_devs->stat_num = register_sound_special(&emu10k1_sndstat_fops, 6);
-	if (sblive_devs->stat_num < 0)
-		printk(KERN_ERR "emu10k1: cannot register sndstat device!\n");
-	else
-		sndstat_init();
+	if ((card->mixer_num = register_sound_mixer(&emu10k1_mixer_fops, -1)) < 0) {
+		printk(KERN_ERR "emu10k1: cannot register mixer device!\n");
+		goto err_dev2;
+	}
+
+	if ((card->midi_num = register_sound_midi(&emu10k1_midi_fops, -1)) < 0) {
+		printk(KERN_ERR "emu10k1: cannot register midi device!\n");
+		goto err_dev3;
+	}
+
+	if (emu10k1_init(card) != CTSTATUS_SUCCESS) {
+		printk(KERN_ERR "emu10k1: cannot initialize device!\n");
+		goto err_emu10k1_init;
+	}
+
+	if (audio_init(card) != CTSTATUS_SUCCESS) {
+		printk(KERN_ERR "emu10k1: cannot initialize audio!\n");
+		goto err_audio_init;
+	}
 
-	DPF(2, "Module successfully initialized!\n");
+	if (midi_init(card) != CTSTATUS_SUCCESS) {
+		printk(KERN_ERR "emu10k1: cannot initialize midi!\n");
+		goto err_midi_init;
+	}
+
+	mixer_init(card);
+
+	DPD(2, "Hardware initialized. TRAM allocated: %u bytes\n", (unsigned int) card->tmemsize);
+
+	list_add(&card->list, &emu10k1_devs);
+
 	return 0;
+
+      err_midi_init:
+	audio_exit(card);
+
+      err_audio_init:
+	emu10k1_exit(card);
+
+      err_emu10k1_init:
+	unregister_sound_midi(card->midi_num);
+
+      err_dev3:
+	unregister_sound_mixer(card->mixer_num);
+
+      err_dev2:
+	unregister_sound_dsp(card->audio2_num);
+
+      err_dev1:
+	unregister_sound_dsp(card->audio1_num);
+
+      err_dev0:
+	free_irq(card->irq, card);
+
+      err_irq:
+	release_region(card->iobase, EMU10K1_EXTENT);
+	kfree(card);
+
+	return -ENODEV;
+}
+
+static void __devexit emu10k1_remove(struct pci_dev *pci_dev)
+{
+#if LINUX_VERSION_CODE > 0x020320
+	struct emu10k1_card *card = pci_dev->driver_data;
+#else
+	struct emu10k1_card *card = list_entry(emu10k1_devs.next, struct emu10k1_card, list);
+#endif
+	midi_exit(card);
+	audio_exit(card);
+	emu10k1_exit(card);
+
+	unregister_sound_midi(card->midi_num);
+	unregister_sound_mixer(card->mixer_num);
+	unregister_sound_dsp(card->audio2_num);
+	unregister_sound_dsp(card->audio1_num);
+
+	free_irq(card->irq, card);
+	release_region(card->iobase, EMU10K1_EXTENT);
+
+	list_del(&card->list);
+
+	kfree(card);
+	return;
 }
 
-#ifdef MODULE
+MODULE_AUTHOR("Bertrand Lee, Cai Ying. (Email to: emu10k1-devel@opensource.creative.com)");
+MODULE_DESCRIPTION("Creative EMU10K1 PCI Audio Driver v" DRIVER_VERSION "\nCopyright (C) 1999 Creative Technology Ltd.");
 
-MODULE_PARM(joystick, "1-" __MODULE_STRING(MAX_EMU10K1) "i");
-MODULE_PARM_DESC(joystick, "sets address and enables joystick interface (still need separate driver)");
-MODULE_AUTHOR("Bertrand Lee, Cai Ying. (Email to: linux_bug@soundblaster.com)");
-MODULE_DESCRIPTION("Creative EMU10K1 Driver v0.4\nCopyright (C) 1999 Creative Technology Ltd.");
+static struct pci_driver emu10k1_pci_driver __initdata = {
+	name:"emu10k1",
+	id_table:emu10k1_pci_tbl,
+	probe:emu10k1_probe,
+	remove:emu10k1_remove,
+};
 
-/* Driver exit routine */
-void cleanup_module(void)
+#if LINUX_VERSION_CODE > 0x020320
+static int __init emu10k1_init_module(void)
 {
-	struct sblive_hw *hw_obj;
+	printk(KERN_INFO "Creative EMU10K1 PCI Audio Driver, version " DRIVER_VERSION ", " __TIME__ " " __DATE__ "\n");
 
-	DPF(2, "cleanup_module() called\n");
+	return pci_module_init(&emu10k1_pci_driver);
+}
 
-	if (sblive_devs && sblive_devs->stat_num >= 0)
-		unregister_sound_special(6);
+static void __exit emu10k1_cleanup_module(void)
+{
+	pci_unregister_driver(&emu10k1_pci_driver);
+	return;
+}
 
-	while ((hw_obj = sblive_devs))
-	{
-		sblive_devs = sblive_devs->next;
+#else
 
-		/* write original joystick base address to PCI configuration space */
-		pci_write_config_dword(hw_obj->pcidev_joy, PCI_BASE_ADDRESS_0, hw_obj->joybase);
-#ifdef EMU10K1_DEBUG
-		{
-			u32 base;
-			pci_read_config_dword(hw_obj->pcidev_joy, PCI_BASE_ADDRESS_0, &base);
-			DPD(2, "cleanup_module: read back joystick base address is %x\n", base);
-		}
-#endif
+static int __init emu10k1_init_module(void)
+{
+	struct pci_dev *dev = NULL;
+	const struct pci_device_id *pci_id = emu10k1_pci_driver.id_table;
 
-		audio_exit(hw_obj);
-		midi_exit(hw_obj);
+	printk(KERN_INFO "Creative EMU10K1 PCI Audio Driver, version " DRIVER_VERSION ", " __TIME__ " " __DATE__ "\n");
 
-		/* IRQ is freed in halExit */
-		halExit(hw_obj);
-		DPF(2, "halExit completed\n");
+	if (!pci_present())
+		return -ENODEV;
+
+	while (pci_id->vendor) {
+		while ((dev = pci_find_device(pci_id->vendor, pci_id->device, dev)))
+			emu10k1_probe(dev, pci_id);
+
+		pci_id++;
+	}
+	return 0;
+}
+
+static void __exit emu10k1_cleanup_module(void)
+{
+	struct emu10k1_card *card;
 
-		release_region(hw_obj->hwaddr, EMU10K1_EXTENT);
-		release_region(hw_obj->joybase, JOY_EXTENT);
-		unregister_sound_dsp(hw_obj->audio_num);
-		unregister_sound_mixer(hw_obj->mixer_num);
-		unregister_sound_midi(hw_obj->midi_num);
-		kfree(hw_obj);
-		DPD(3, "kfree: [%p]\n", hw_obj);
+	while (!list_empty(&emu10k1_devs)) {
+		card = list_entry(emu10k1_devs.next, struct emu10k1_card, list);
+
+		emu10k1_remove(card->pci_dev);
 	}
 
-	DPF(2, "Module unloaded\n");
+	return;
 }
+
+#endif
 
-#endif				// MODULE
+module_init(emu10k1_init_module);
+module_exit(emu10k1_cleanup_module);
Index: oldkernel/linux/drivers/sound/emu10k1/midi.c
diff -u linux/drivers/sound/emu10k1/midi.c:1.1 linux/drivers/sound/emu10k1/midi.c:1.2
--- linux/drivers/sound/emu10k1/midi.c:1.1	Thu Jun  1 16:52:15 2000
+++ linux/drivers/sound/emu10k1/midi.c	Fri Jul  7 15:36:45 2000
@@ -1,3 +1,4 @@
+
 /*
  **********************************************************************
  *     midi.c - /dev/midi interface for emu10k1 driver
@@ -29,356 +30,334 @@
  **********************************************************************
  */
 
-#ifdef MODULE
 #define __NO_VERSION__
 #include <linux/module.h>
-#else
-#define MOD_INC_USE_COUNT
-#define MOD_DEC_USE_COUNT
-#endif
+#include <asm/uaccess.h>
 
 #include "hwaccess.h"
-#include "mycommon.h"
 #include "cardmo.h"
 #include "cardmi.h"
 #include "midi.h"
 
-
 static spinlock_t midi_spinlock = SPIN_LOCK_UNLOCKED;
 
+static void init_midi_hdr(struct midi_hdr *midihdr)
+{
+	midihdr->bufferlength = MIDIIN_BUFLEN;
+	midihdr->bytesrecorded = 0;
+	midihdr->flags = 0;
+}
+
+static int midiin_add_buffer(struct emu10k1_mididevice *midi_dev, struct midi_hdr **midihdrptr)
+{
+	struct midi_hdr *midihdr;
+
+	if ((midihdr = (struct midi_hdr *) kmalloc(sizeof(struct midi_hdr *), GFP_KERNEL)) == NULL) {
+		ERROR();
+		return -EINVAL;
+	}
+
+	init_midi_hdr(midihdr);
+
+	if ((midihdr->data = (u8 *) kmalloc(MIDIIN_BUFLEN, GFP_KERNEL)) == NULL) {
+		ERROR();
+		kfree(midihdr);
+		return CTSTATUS_ERROR;
+	}
+
+	if (emu10k1_mpuin_add_buffer(midi_dev->card->mpuin, midihdr) != CTSTATUS_SUCCESS) {
+		ERROR();
+		kfree(midihdr->data);
+		kfree(midihdr);
+		return CTSTATUS_ERROR;
+	}
+
+	*midihdrptr = midihdr;
+	list_add_tail(&midihdr->list, &midi_dev->mid_hdrs);
+
+	return CTSTATUS_SUCCESS;
+}
+
 static int emu10k1_midi_open(struct inode *inode, struct file *file)
 {
 	int minor = MINOR(inode->i_rdev);
-	struct sblive_hw *sb_hw = sblive_devs;
-	struct sblive_mididevice *midi_dev;
+	struct emu10k1_card *card;
+	struct emu10k1_mididevice *midi_dev;
+	struct list_head *entry;
 
-	DPF(2, "emu10k1_midi_open() called\n");
+	DPF(2, "emu10k1_midi_open()\n");
 
 	/* Check for correct device to open */
-	while (sb_hw && sb_hw->midi_num != minor)
-	  sb_hw = sb_hw->next;
-	if (!sb_hw)
-	  return -ENODEV;
+	list_for_each(entry, &emu10k1_devs) {
+		card = list_entry(entry, struct emu10k1_card, list);
+
+		if (card->midi_num == minor)
+			break;
+	}
+
+	if (entry == &emu10k1_devs)
+		return -ENODEV;
+
+	MOD_INC_USE_COUNT;
 
 	/* Wait for device to become free */
-	down(&sb_hw->open_sem);
-	while (sb_hw->open_mode & (file->f_mode << FMODE_MIDI_SHIFT)) 
-	{
-		if (file->f_flags & O_NONBLOCK) 
-		{
-			up(&sb_hw->open_sem);
+	down(&card->open_sem);
+	while (card->open_mode & (file->f_mode << FMODE_MIDI_SHIFT)) {
+		if (file->f_flags & O_NONBLOCK) {
+			up(&card->open_sem);
+			MOD_DEC_USE_COUNT;
 			return -EBUSY;
 		}
-		
-		up(&sb_hw->open_sem);
-		interruptible_sleep_on(&sb_hw->open_wait);
-		
-		if (signal_pending(current))
-		  return -ERESTARTSYS;
-		
-		down(&sb_hw->open_sem);
+
+		up(&card->open_sem);
+		interruptible_sleep_on(&card->open_wait);
+
+		if (signal_pending(current)) {
+			MOD_DEC_USE_COUNT;
+			return -ERESTARTSYS;
+		}
+
+		down(&card->open_sem);
 	}
 
-	midi_dev = (struct sblive_mididevice *) kmalloc(sizeof(*midi_dev), GFP_KERNEL);
-	if (midi_dev == NULL) 
-	{
-		DPF(2, " MIDIDEVICEOBJ alloc fail.");
+	if ((midi_dev = (struct emu10k1_mididevice *) kmalloc(sizeof(*midi_dev), GFP_KERNEL)) == NULL) {
+		MOD_DEC_USE_COUNT;
 		return -EINVAL;
 	}
-	
-	DPD(3, "kmalloc: [%p]\n", midi_dev);
-	
-	midi_dev->sb_hw = sb_hw;
+
+	midi_dev->card = card;
 	midi_dev->mistate = MIDIIN_STATE_STOPPED;
 	init_waitqueue_head(&midi_dev->oWait);
 	init_waitqueue_head(&midi_dev->iWait);
 	midi_dev->ird = 0;
 	midi_dev->iwr = 0;
 	midi_dev->icnt = 0;
-	midi_dev->pmiHdrList = NULL;
+	INIT_LIST_HEAD(&midi_dev->mid_hdrs);
 
-	if (file->f_mode & FMODE_READ) 
-	{
+	if (file->f_mode & FMODE_READ) {
 		struct midi_openinfo dsCardMidiOpenInfo;
 		struct midi_hdr *midihdr1;
 		struct midi_hdr *midihdr2;
 
 		dsCardMidiOpenInfo.refdata = (unsigned long) midi_dev;
-
-		if (sblive_mpuinOpen(sb_hw, &dsCardMidiOpenInfo) 
-		    != CTSTATUS_SUCCESS) 
-		{
-			DPF(2, "sblive_mpuinOpen failed.\n");
 
+		if (emu10k1_mpuin_open(card, &dsCardMidiOpenInfo)
+		    != CTSTATUS_SUCCESS) {
+			ERROR();
 			kfree(midi_dev);
-			DPD(3, "kfree: [%p]\n", midi_dev);			
-
+			MOD_DEC_USE_COUNT;
 			return -ENODEV;
 		}
 
 		/* Add two buffers to receive sysex buffer */
-		if (midiInAddBuffer(midi_dev, &midihdr1) != CTSTATUS_SUCCESS) 
-		{
+		if (midiin_add_buffer(midi_dev, &midihdr1) != CTSTATUS_SUCCESS) {
 			kfree(midi_dev);
-			DPD(3, "kfree: [%p]\n", midi_dev);
-
+			MOD_DEC_USE_COUNT;
 			return -ENODEV;
 		}
-
-		if (midiInAddBuffer(midi_dev, &midihdr2) != CTSTATUS_SUCCESS) 
-		{
-			osListRemove((struct sblive_list **) &midi_dev->pmiHdrList, (struct sblive_list *) midihdr1);
 
-			kfree(midihdr1->lpData);
-			DPD(3, "kfree: [%p]\n", midihdr1->lpData);
-
+		if (midiin_add_buffer(midi_dev, &midihdr2) != CTSTATUS_SUCCESS) {
+			list_del(&midihdr1->list);
+			kfree(midihdr1->data);
 			kfree(midihdr1);
 			kfree(midi_dev);
-
-			DPD(3, "kfree: [%p]\n", midihdr1);
-			DPD(3, "kfree: [%p]\n", midi_dev);
-
+			MOD_DEC_USE_COUNT;
 			return -ENODEV;
 		}
 	}
 
-	if (file->f_mode & FMODE_WRITE) 
-	{
+	if (file->f_mode & FMODE_WRITE) {
 		struct midi_openinfo dsCardMidiOpenInfo;
 
 		dsCardMidiOpenInfo.refdata = (unsigned long) midi_dev;
 
-		if (sblive_mpuoutOpen(sb_hw, &dsCardMidiOpenInfo)
-		    != CTSTATUS_SUCCESS) 
-		{
-			DPF(2, "sblive_mpuoutOpen failed.\n");
-
+		if (emu10k1_mpuout_open(card, &dsCardMidiOpenInfo)
+		    != CTSTATUS_SUCCESS) {
+			ERROR();
 			kfree(midi_dev);
-			DPD(3, "kfree: [%p]\n", midi_dev);
-
+			MOD_DEC_USE_COUNT;
 			return -ENODEV;
 		}
 	}
 
 	file->private_data = (void *) midi_dev;
 
-	sb_hw->open_mode |= (file->f_mode << FMODE_MIDI_SHIFT) & (FMODE_MIDI_READ | FMODE_MIDI_WRITE);
+	card->open_mode |= (file->f_mode << FMODE_MIDI_SHIFT) & (FMODE_MIDI_READ | FMODE_MIDI_WRITE);
 
-	up(&sb_hw->open_sem);
+	up(&card->open_sem);
 
-	MOD_INC_USE_COUNT;
 	return 0;
 }
 
 static int emu10k1_midi_release(struct inode *inode, struct file *file)
 {
-	struct sblive_mididevice *midi_dev = (struct sblive_mididevice *) file->private_data;
-	struct sblive_hw *sb_hw = midi_dev->sb_hw;
+	struct emu10k1_mididevice *midi_dev = (struct emu10k1_mididevice *) file->private_data;
+	struct emu10k1_card *card = midi_dev->card;
+
+	DPF(2, "emu10k1_midi_release()\n");
 
-	DPF(2, "emu10k1_midi_release() called\n");
-	
-	if (file->f_mode & FMODE_WRITE) 
-	{
-		if(!(file->f_flags & O_NONBLOCK)){
+	if (file->f_mode & FMODE_WRITE) {
+		if (!(file->f_flags & O_NONBLOCK)) {
 
-			while (!signal_pending(current) && (sb_hw->card_mpuout->firstmidiq !=NULL)){
-				DPF(2, "Cannot close - buffers not empty\n");
+			while (!signal_pending(current) && (card->mpuout->firstmidiq != NULL)) {
+				DPF(4, "Cannot close - buffers not empty\n");
 
-				interruptible_sleep_on(&midi_dev->oWait);		
+				interruptible_sleep_on(&midi_dev->oWait);
 
 			}
 		}
 
-		sblive_mpuoutClose(sb_hw);
+		emu10k1_mpuout_close(card);
 	}
-	
-	if (file->f_mode & FMODE_READ) 
-	{
+
+	if (file->f_mode & FMODE_READ) {
 		struct midi_hdr *midihdr;
 
-		if (midi_dev->mistate == MIDIIN_STATE_STARTED) 
-		{
-			sblive_mpuinStop(sb_hw);
+		if (midi_dev->mistate == MIDIIN_STATE_STARTED) {
+			emu10k1_mpuin_stop(card);
 			midi_dev->mistate = MIDIIN_STATE_STOPPED;
-			DPF(2, "MIDI in stopped\n");
 		}
-		
-		sblive_mpuinReset(sb_hw);
-		sblive_mpuinClose(sb_hw);
-		
-		DPF(2, "MIDI in closed\n");
-		
-		while ((midihdr = (struct midi_hdr *) osListGetNext((struct sblive_list *) midi_dev->pmiHdrList, NULL))) 
-		{
-			osListRemove((struct sblive_list **) &midi_dev-> pmiHdrList, (struct sblive_list *) midihdr);
+
+		emu10k1_mpuin_reset(card);
+		emu10k1_mpuin_close(card);
 
-			kfree(midihdr->lpData);
-			DPD(3, "kfree: [%p]\n", midihdr->lpData);
+		while (!list_empty(&midi_dev->mid_hdrs)) {
+			midihdr = list_entry(midi_dev->mid_hdrs.next, struct midi_hdr, list);
 
+			list_del(midi_dev->mid_hdrs.next);
+			kfree(midihdr->data);
 			kfree(midihdr);
-			DPD(3, "kfree: [%p]\n", midihdr);
 		}
 	}
-	
+
 	kfree(midi_dev);
 
-	DPD(3, "kfree: [%p]\n", midi_dev);
+	down(&card->open_sem);
+	card->open_mode &= ~((file->f_mode << FMODE_MIDI_SHIFT) & (FMODE_MIDI_READ | FMODE_MIDI_WRITE));
+	up(&card->open_sem);
+	wake_up_interruptible(&card->open_wait);
 
-	down(&sb_hw->open_sem);
-	sb_hw->open_mode &= ~((file->f_mode << FMODE_MIDI_SHIFT) & (FMODE_MIDI_READ | FMODE_MIDI_WRITE));
-	up(&sb_hw->open_sem);
-	wake_up(&sb_hw->open_wait);
-	
 	MOD_DEC_USE_COUNT;
 
 	return 0;
 }
-
 
-static ssize_t emu10k1_midi_read(struct file *file, char *buffer, size_t count, loff_t *pos)
+static ssize_t emu10k1_midi_read(struct file *file, char *buffer, size_t count, loff_t * pos)
 {
-	struct sblive_mididevice *midi_dev = (struct sblive_mididevice *) file->private_data;
+	struct emu10k1_mididevice *midi_dev = (struct emu10k1_mididevice *) file->private_data;
 	ssize_t ret = 0;
 	u16 cnt;
 	unsigned long flags;
 
-	DPD(2, "emu10k1_midi_read() called, count %d\n", count);
+	DPD(4, "emu10k1_midi_read(), count %x\n", (u32) count);
 
 	if (pos != &file->f_pos)
-	  return -ESPIPE;
+		return -ESPIPE;
 
 	if (!access_ok(VERIFY_WRITE, buffer, count))
-	  return -EFAULT;
+		return -EFAULT;
 
-	if (midi_dev->mistate == MIDIIN_STATE_STOPPED) 
-	{
-		if (sblive_mpuinStart(midi_dev->sb_hw) 
-		    != CTSTATUS_SUCCESS) 
-		{
-			DPF(2, "sblive_mpuinStart failed.\n");
+	if (midi_dev->mistate == MIDIIN_STATE_STOPPED) {
+		if (emu10k1_mpuin_start(midi_dev->card)
+		    != CTSTATUS_SUCCESS) {
+			ERROR();
 			return -EINVAL;
 		}
-		
+
 		midi_dev->mistate = MIDIIN_STATE_STARTED;
 	}
 
-	while (count > 0) 
-	{
+	while (count > 0) {
 		cnt = MIDIIN_BUFLEN - midi_dev->ird;
-	
+
 		spin_lock_irqsave(&midi_spinlock, flags);
-	
+
 		if (midi_dev->icnt < cnt)
-		  cnt = midi_dev->icnt;
-		
+			cnt = midi_dev->icnt;
+
 		spin_unlock_irqrestore(&midi_spinlock, flags);
-		
+
 		if (cnt > count)
-		  cnt = count;
-		
-		if (cnt <= 0) 
-		{
+			cnt = count;
+
+		if (cnt <= 0) {
 			if (file->f_flags & O_NONBLOCK)
-			  return ret ? ret : -EAGAIN;
+				return ret ? ret : -EAGAIN;
 			DPF(2, " Go to sleep...\n");
-			
+
 			interruptible_sleep_on(&midi_dev->iWait);
-			
+
 			if (signal_pending(current))
 				return ret ? ret : -ERESTARTSYS;
-			
+
 			continue;
 		}
-		
+
 		if (copy_to_user(buffer, midi_dev->iBuf + midi_dev->ird, cnt)) {
-			DPF(2, " copy_to_user failed.");
+			ERROR();
 			return ret ? ret : -EFAULT;
 		}
-		
+
 		midi_dev->ird += cnt;
 		midi_dev->ird %= MIDIIN_BUFLEN;
 
 		spin_lock_irqsave(&midi_spinlock, flags);
 
 		midi_dev->icnt -= cnt;
-		
+
 		spin_unlock_irqrestore(&midi_spinlock, flags);
-		
+
 		count -= cnt;
 		buffer += cnt;
 		ret += cnt;
 
 		if (midi_dev->icnt == 0)
 			break;
-
 	}
-	
+
 	return ret;
 }
 
-
-static ssize_t emu10k1_midi_write(struct file *file, const char *buffer, size_t count, loff_t *pos)
+static ssize_t emu10k1_midi_write(struct file *file, const char *buffer, size_t count, loff_t * pos)
 {
-	struct sblive_mididevice *midi_dev = (struct sblive_mididevice *) file->private_data;
+	struct emu10k1_mididevice *midi_dev = (struct emu10k1_mididevice *) file->private_data;
 	struct midi_hdr *midihdr;
 	ssize_t ret = 0;
 	unsigned long flags;
 
-	DPD(2, "emu10k1_midi_write() called, count=%d\n", count);
+	DPD(4, "emu10k1_midi_write(), count=%x\n", (u32) count);
 
 	if (pos != &file->f_pos)
-	  return -ESPIPE;
+		return -ESPIPE;
 
 	if (!access_ok(VERIFY_READ, buffer, count))
-	  return -EFAULT;
+		return -EFAULT;
 
-	midihdr = (struct midi_hdr *) kmalloc(sizeof(struct midi_hdr *), GFP_KERNEL);
-	if (midihdr == NULL) 
+	if ((midihdr = (struct midi_hdr *) kmalloc(sizeof(struct midi_hdr *), GFP_KERNEL)) == NULL)
 		return -EINVAL;
 
-	DPD(3, "kmalloc: [%p]\n", midihdr);
-	
 	midihdr->bufferlength = count;
 	midihdr->bytesrecorded = 0;
 	midihdr->flags = 0;
-	midihdr->next = NULL;
-	
-	midihdr->lpData = (u8 *) kmalloc(count, GFP_KERNEL);
-	if (midihdr->lpData == NULL) 
-	{
-		DPF(2, "midihdr->lpData alloc failed\n");
 
+	if ((midihdr->data = (u8 *) kmalloc(count, GFP_KERNEL)) == NULL) {
+		ERROR();
 		kfree(midihdr);
-		DPD(3, "kfree: [%p]\n", midihdr);
-	
 		return -EINVAL;
 	}
-
-	DPD(3, "kmalloc: [%p]\n", midihdr->lpData);
-	
-	if (copy_from_user(midihdr->lpData, buffer, count)) 
-	{
-		kfree(midihdr->lpData);
-		DPD(3, "kfree: [%p]\n", midihdr->lpData);
 
+	if (copy_from_user(midihdr->data, buffer, count)) {
+		kfree(midihdr->data);
 		kfree(midihdr);
-		DPD(3, "kfree: [%p]\n", midihdr);
-		
 		return ret ? ret : -EFAULT;
 	}
 
 	spin_lock_irqsave(&midi_spinlock, flags);
 
-	if (sblive_mpuoutAddBuffer(midi_dev->sb_hw, midihdr) != CTSTATUS_SUCCESS) 
-	{
-		DPF(2, "sblive_mpuoutAddBuffer failed.\n");
-
-		kfree(midihdr->lpData);
-		DPD(3, "kfree: [%p]\n", midihdr->lpData);
-
+	if (emu10k1_mpuout_add_buffer(midi_dev->card, midihdr) != CTSTATUS_SUCCESS) {
+		ERROR();
+		kfree(midihdr->data);
 		kfree(midihdr);
-		DPD(3, "kfree: [%p]\n", midihdr);
-	
 		spin_unlock_irqrestore(&midi_spinlock, flags);
 		return -EINVAL;
 	}
@@ -388,61 +367,51 @@
 	return count;
 }
 
-
 static unsigned int emu10k1_midi_poll(struct file *file, struct poll_table_struct *wait)
 {
-	DPF(2, "emu10k1_midi_poll() called\n");
+	DPF(4, "emu10k1_midi_poll() called\n");
 	return 0;
 }
-
 
-int midiCallbackFn(unsigned long msg, unsigned long refdata, unsigned long *pmsg)
+int emu10k1_midi_callback(unsigned long msg, unsigned long refdata, unsigned long *pmsg)
 {
-	struct sblive_mididevice *midi_dev = (struct sblive_mididevice *) refdata;
+	struct emu10k1_mididevice *midi_dev = (struct emu10k1_mididevice *) refdata;
 	struct midi_hdr *midihdr = NULL;
 	unsigned long flags;
 	int i;
 
-	DPF(2, "midiCallbackFn!\n");
-	
+	DPF(4, "emu10k1_midi_callback()\n");
+
 	spin_lock_irqsave(&midi_spinlock, flags);
 
-	switch (msg) 
-	{
+	switch (msg) {
 	case ICARDMIDI_OUTLONGDATA:
 		midihdr = (struct midi_hdr *) pmsg[2];
-
-		kfree(midihdr->lpData);
-		DPD(3, "kfree: [%p]\n", midihdr->lpData);
 
+		kfree(midihdr->data);
 		kfree(midihdr);
-		DPD(3, "kfree: [%p]\n", midihdr);
-
-		wake_up(&midi_dev->oWait);
+		wake_up_interruptible(&midi_dev->oWait);
 
 		break;
 
 	case ICARDMIDI_INLONGDATA:
-		DPF(2, " ICARDMIDI_INLONGDATA\n");
 		midihdr = (struct midi_hdr *) pmsg[2];
 
 		for (i = 0; i < midihdr->bytesrecorded; i++) {
-			midi_dev->iBuf[midi_dev->iwr++] = midihdr->lpData[i];
+			midi_dev->iBuf[midi_dev->iwr++] = midihdr->data[i];
 			midi_dev->iwr %= MIDIIN_BUFLEN;
 		}
 
 		midi_dev->icnt += midihdr->bytesrecorded;
-		
-		if (midi_dev->mistate == MIDIIN_STATE_STARTED) 
-		{
-			initMidiHdr(midihdr);
-			sblive_mpuinAddBuffer(midi_dev->sb_hw->card_mpuin, midihdr);
-			wake_up(&midi_dev->iWait);
+
+		if (midi_dev->mistate == MIDIIN_STATE_STARTED) {
+			init_midi_hdr(midihdr);
+			emu10k1_mpuin_add_buffer(midi_dev->card->mpuin, midihdr);
+			wake_up_interruptible(&midi_dev->iWait);
 		}
 		break;
 
 	case ICARDMIDI_INDATA:
-		DPF(2, " ICARDMIDI_INDATA\n");
 		{
 			u8 *pBuf = (u8 *) & pmsg[1];
 			u16 bytesvalid = pmsg[2];
@@ -454,136 +423,24 @@
 
 			midi_dev->icnt += bytesvalid;
 		}
-		
-		wake_up(&midi_dev->iWait);
+
+		wake_up_interruptible(&midi_dev->iWait);
 		break;
 
 	default:		/* Unknown message */
-		DPF(2, "Unknown message\n");
 		return CTSTATUS_ERROR;
 	}
 
 	spin_unlock_irqrestore(&midi_spinlock, flags);
-	
-	return CTSTATUS_SUCCESS;
-}
-
 
-/* Local functions */
-int midiInAddBuffer(struct sblive_mididevice *midi_dev, struct midi_hdr **midihdrptr)
-{
-	struct midi_hdr *midihdr;
-
-	midihdr = (struct midi_hdr *) kmalloc(sizeof(struct midi_hdr *), GFP_KERNEL);
-	if (midihdr == NULL)
-	  return -EINVAL;
-
-	DPD(3, "kmalloc: [%p]\n", midihdr);
-	
-	initMidiHdr(midihdr);
-	
-	midihdr->lpData = (u8 *) kmalloc(MIDIIN_BUFLEN, GFP_KERNEL);	
-	if (midihdr->lpData == NULL) 
-	{
-		DPF(2, "midihdr->lpData alloc fail.\n");
-
-		kfree(midihdr);
-		DPD(3, "kfree: [%p]\n", midihdr);
-
-		return CTSTATUS_ERROR;
-	}
-
-	DPD(3, "kmalloc: [%p]\n", midihdr->lpData);
-	
-	if (sblive_mpuinAddBuffer(midi_dev->sb_hw->card_mpuin, midihdr) != CTSTATUS_SUCCESS) 
-	{
-		DPF(2, "sblive_mpuinAddBuffer failed.\n");
-
-		kfree(midihdr->lpData);
-		DPD(3, "kfree: [%p]\n", midihdr->lpData);
-
-		kfree(midihdr);
-		DPD(3, "kfree: [%p]\n", midihdr);
-
-		return CTSTATUS_ERROR;
-	}
-	
-	*midihdrptr = midihdr;
-	osListAttach((struct sblive_list **) &midi_dev->pmiHdrList, (struct sblive_list *) midihdr);
-
 	return CTSTATUS_SUCCESS;
 }
 
-void initMidiHdr(struct midi_hdr * midihdr)
-{
-	midihdr->bufferlength = MIDIIN_BUFLEN;
-	midihdr->bytesrecorded = 0;
-	midihdr->flags = 0;
-	midihdr->next = NULL;
-}
-
-/* End of local functions */
-
-
-int midi_init(struct sblive_hw *sb_hw)
-{
-	/* Initialize CardMpuOut struct */
-	sb_hw->card_mpuout = kmalloc(sizeof(struct sblive_mpuout), GFP_KERNEL);
-	if (sb_hw->card_mpuout == NULL) 
-	{
-		printk(KERN_WARNING "alloc struct sblive_mpuout: out of memory\n");
-		return CTSTATUS_ERROR;
-	}
-	
-	DPD(3, "kmalloc: [%p]\n", sb_hw->card_mpuout);
-	
-	sblive_mpuoutInit(sb_hw->card_mpuout, sb_hw);
-
-	/* Initialize CardMpuIn struct */
-	sb_hw->card_mpuin = kmalloc(sizeof(struct sblive_mpuin), GFP_KERNEL);
-	if (sb_hw->card_mpuin == NULL) 
-	{
-		printk(KERN_WARNING "alloc struct sblive_mpuin: out of memory\n");
-		return CTSTATUS_ERROR;
-	}
-	
-	DPD(3, "kmalloc: [%p]\n", sb_hw->card_mpuin);
-	
-	sblive_mpuinInit(sb_hw->card_mpuin, sb_hw);
-
-	return CTSTATUS_SUCCESS;
-}
-
-int midi_exit(struct sblive_hw *sb_hw)
-{
-	sblive_mpuoutExit(sb_hw);
-	sblive_mpuinExit(sb_hw);
-	kfree(sb_hw->card_mpuout);
-	kfree(sb_hw->card_mpuin);
-	
-	DPD(3, "kfree: [%p]\n", sb_hw->card_mpuout);
-	DPD(3, "kfree: [%p]\n", sb_hw->card_mpuin);
-	
-	sb_hw->card_mpuout = NULL;
-	sb_hw->card_mpuin = NULL;
-
-	return CTSTATUS_SUCCESS;
-}
-
-
 /* MIDI file operations */
-struct file_operations emu10k1_midi_fops = 
-{
-	NULL,
-	&emu10k1_midi_read,
-	&emu10k1_midi_write,
-	NULL,			/* readdir */
-	&emu10k1_midi_poll,
-	NULL,			/* ioctl */
-	NULL,			/* mmap */
-	&emu10k1_midi_open,
-	NULL,			/* flush */
-	&emu10k1_midi_release,
-	NULL,			/* fsync */
-	NULL,			/* fasync */
+struct file_operations emu10k1_midi_fops = {
+	read:emu10k1_midi_read,
+	write:emu10k1_midi_write,
+	poll:emu10k1_midi_poll,
+	open:emu10k1_midi_open,
+	release:emu10k1_midi_release,
 };
Index: oldkernel/linux/drivers/sound/emu10k1/midi.h
diff -u linux/drivers/sound/emu10k1/midi.h:1.1 linux/drivers/sound/emu10k1/midi.h:1.2
--- linux/drivers/sound/emu10k1/midi.h:1.1	Thu Jun  1 16:52:15 2000
+++ linux/drivers/sound/emu10k1/midi.h	Fri Jul  7 15:36:45 2000
@@ -41,20 +41,15 @@
 
 #define MIDIIN_BUFLEN 1024
 
-struct sblive_mididevice
+struct emu10k1_mididevice
 {
-	struct sblive_hw *sb_hw;
+	struct emu10k1_card *card;
 	u32 mistate;
 	wait_queue_head_t oWait;
 	wait_queue_head_t iWait;
 	s8 iBuf[MIDIIN_BUFLEN];
 	u16 ird, iwr, icnt;
-	struct midi_hdr *pmiHdrList;
+	struct list_head mid_hdrs;
 };
-
-int midi_init(struct sblive_hw *);
-int midi_exit(struct sblive_hw *);
-int midiInAddBuffer(struct sblive_mididevice *, struct midi_hdr **);
-void initMidiHdr(struct midi_hdr *);
 
 #endif /* _MIDI_H */
Index: oldkernel/linux/drivers/sound/emu10k1/mixer.c
diff -u linux/drivers/sound/emu10k1/mixer.c:1.1 linux/drivers/sound/emu10k1/mixer.c:1.2
--- linux/drivers/sound/emu10k1/mixer.c:1.1	Thu Jun  1 16:52:15 2000
+++ linux/drivers/sound/emu10k1/mixer.c	Fri Jul  7 15:36:45 2000
@@ -1,9 +1,10 @@
+
 /*
  **********************************************************************
  *     mixer.c - /dev/mixer interface for emu10k1 driver
  *     Copyright 1999, 2000 Creative Labs, Inc.
  *
- *     This program uses some code from es1317.c, Copyright 1998-1999
+ *     This program uses some code from es1371.c, Copyright 1998-1999
  *     Thomas Sailer
  *
  **********************************************************************
@@ -33,16 +34,11 @@
  **********************************************************************
  */
 
-#ifdef MODULE
 #define __NO_VERSION__		/* Kernel version only defined once */
 #include <linux/module.h>
-#else
-#define MOD_INC_USE_COUNT
-#define MOD_DEC_USE_COUNT
-#endif
+#include <asm/uaccess.h>
 
 #include "hwaccess.h"
-#include "mycommon.h"
 
 #define AC97_PESSIMISTIC
 #undef OSS_DOCUMENTED_MIXER_SEMANTICS
@@ -53,7 +49,12 @@
 #define vol_to_sw_5(hwvol) (((31 - (hwvol)) * 100) / 31)
 #define vol_to_sw_4(hwvol) (((15 - (hwvol)) * 100) / 15)
 
+#ifdef PRIVATE_PCM_VOLUME
+struct sblive_pcm_volume_rec sblive_pcm_volume[MAX_PCM_CHANNELS];
+#endif
+
 /* --------------------------------------------------------------------- */
+
 /*
  * hweightN: returns the hamming weight (i.e. the number
  * of bits set) of a N-bit word
@@ -66,16 +67,15 @@
 extern __inline__ unsigned int hweight32(unsigned int w)
 {
 	unsigned int res = (w & 0x55555555) + ((w >> 1) & 0x55555555);
+
 	res = (res & 0x33333333) + ((res >> 2) & 0x33333333);
 	res = (res & 0x0F0F0F0F) + ((res >> 4) & 0x0F0F0F0F);
 	res = (res & 0x00FF00FF) + ((res >> 8) & 0x00FF00FF);
 	return (res & 0x0000FFFF) + ((res >> 16) & 0x0000FFFF);
 }
 
-
 /* Mapping arrays */
-static const unsigned int recsrc[] =
-{
+static const unsigned int recsrc[] = {
 	SOUND_MASK_MIC,
 	SOUND_MASK_CD,
 	SOUND_MASK_VIDEO,
@@ -85,19 +85,22 @@
 	SOUND_MASK_OGAIN,	/* Used to be PHONEOUT */
 	SOUND_MASK_PHONEIN,
 	SOUND_MASK_TREBLE,
-	SOUND_MASK_BASS
+	SOUND_MASK_BASS,
+	SOUND_MASK_MONITOR,
+	SOUND_MASK_PCM,
 };
 
-static const unsigned char volreg[SOUND_MIXER_NRDEVICES] =
-{
+static const unsigned char volreg[SOUND_MIXER_NRDEVICES] = {
 	/* 5 bit stereo */
 	[SOUND_MIXER_LINE] = AC97_LINEINVOLUME,
 	[SOUND_MIXER_CD] = AC97_CDVOLUME,
 	[SOUND_MIXER_VIDEO] = AC97_VIDEOVOLUME,
 	[SOUND_MIXER_LINE1] = AC97_AUXVOLUME,
-	[SOUND_MIXER_PCM] = AC97_PCMOUTVOLUME,
+
+/*	[SOUND_MIXER_PCM] = AC97_PCMOUTVOLUME, */
 	/* 5 bit stereo, setting 6th bit equal to maximum attenuation */
-	[SOUND_MIXER_VOLUME] = AC97_MASTERVOLUME,
+
+/*	[SOUND_MIXER_VOLUME] = AC97_MASTERVOLUME, */
 	[SOUND_MIXER_PHONEOUT] = AC97_HEADPHONEVOLUME,
 	/* 5 bit mono, setting 6th bit equal to maximum attenuation */
 	[SOUND_MIXER_OGAIN] = AC97_MASTERVOLUMEMONO,
@@ -113,18 +116,18 @@
 	[SOUND_MIXER_IGAIN] = AC97_RECORDGAINMIC,
 	/* test code */
 	[SOUND_MIXER_BASS] = AC97_GENERALPUPOSE,
-	[SOUND_MIXER_TREBLE] = AC97_MASTERTONE
+	[SOUND_MIXER_TREBLE] = AC97_MASTERTONE,
+	[SOUND_MIXER_LINE2] = AC97_PCMOUTVOLUME,
+	[SOUND_MIXER_DIGITAL2] = AC97_MASTERVOLUME
 };
 
-/* FIXME: OSS_DOCUMENTED_MIXER_SEMANTICS is #undefed.
- * This needs to be explored more and cleaned up [jtaylor] */
 #ifdef OSS_DOCUMENTED_MIXER_SEMANTICS
 
 #define swab(x) ((((x) >> 8) & 0xff) | (((x) << 8) & 0xff00))
 
 /* FIXME: mixer_rdch() is broken. */
 
-static int mixer_rdch(struct sblive_hw * sb_hw, unsigned int ch, int *arg)
+static int mixer_rdch(struct emu10k1_card *card, unsigned int ch, int *arg)
 {
 	u16 reg;
 	int j;
@@ -137,7 +140,7 @@
 	case SOUND_MIXER_LINE1:
 	case SOUND_MIXER_PCM:
 	case SOUND_MIXER_VOLUME:
-		sblive_readac97(sb_hw, volreg[ch], &reg);
+		sblive_readac97(card, volreg[ch], &reg);
 		nL = ((~(reg >> 8) & 0x1f) * 100) / 32;
 		nR = (~(reg & 0x1f) * 100) / 32;
 		DPD(2, "mixer_rdch: l=%d, r=%d\n", nL, nR);
@@ -145,19 +148,19 @@
 
 	case SOUND_MIXER_OGAIN:
 	case SOUND_MIXER_PHONEIN:
-		sblive_readac97(sb_hw, volreg[ch], &reg);
+		sblive_readac97(card, volreg[ch], &reg);
 		return put_user(reg & 0x8000 ? 0 : ~(reg & 0x1f) * 0x64 / 0x20 * 0x101, (int *) arg);
 
 	case SOUND_MIXER_SPEAKER:
-		sblive_readac97(sb_hw, volreg[ch], &reg);
+		sblive_readac97(card, volreg[ch], &reg);
 		return put_user(reg & 0x8000 ? 0 : ~((reg >> 1) & 0xf) * 0x64 / 0x10 * 0x101, (int *) arg);
 
 	case SOUND_MIXER_MIC:
-		sblive_readac97(sb_hw, volreg[ch], &reg);
+		sblive_readac97(card, volreg[ch], &reg);
 		return put_user(reg & 0x8000 ? 0 : ~(reg & 0x1f) * 0x64 / 0x20 * 0x101 + ((reg & 0x40) ? 0x1e1e : 0), (int *) arg);
 
 	case SOUND_MIXER_RECLEV:
-		sblive_readac97(sb_hw, volreg[ch], &reg);
+		sblive_readac97(card, volreg[ch], &reg);
 		nL = ((~(reg >> 8) & 0x1f) * 100) / 16;
 		nR = (~(reg & 0x1f) * 100) / 16;
 		return put_user(reg & 0x8000 ? 0 : (nL << 8) | nR, (int *) arg);
@@ -172,8 +175,7 @@
 
 #endif				/* OSS_DOCUMENTED_MIXER_SEMANTICS */
 
-static const unsigned char volidx[SOUND_MIXER_NRDEVICES] =
-{
+static const unsigned char volidx[SOUND_MIXER_NRDEVICES] = {
 	/* 5 bit stereo */
 	[SOUND_MIXER_LINE] = 1,
 	[SOUND_MIXER_CD] = 2,
@@ -196,27 +198,167 @@
 	[SOUND_MIXER_IGAIN] = 13,
 	[SOUND_MIXER_TREBLE] = 14,
 	[SOUND_MIXER_BASS] = 15,
-	[SOUND_MIXER_DIGITAL1] = 17,
-	[SOUND_MIXER_DIGITAL2] = 18,
-	[SOUND_MIXER_LINE2] = 19
+	[SOUND_MIXER_LINE2] = 16,
+	[SOUND_MIXER_LINE3] = 17,
+	[SOUND_MIXER_DIGITAL1] = 18,
+	[SOUND_MIXER_DIGITAL2] = 19
+};
+
+u32 bass_table[41][5] = {
+	{ 0x3e4f844f, 0x84ed4cc3, 0x3cc69927, 0x7b03553a, 0xc4da8486 },
+	{ 0x3e69a17a, 0x84c280fb, 0x3cd77cd4, 0x7b2f2a6f, 0xc4b08d1d },
+	{ 0x3e82ff42, 0x849991d5, 0x3ce7466b, 0x7b5917c6, 0xc48863ee },
+	{ 0x3e9bab3c, 0x847267f0, 0x3cf5ffe8, 0x7b813560, 0xc461f22c },
+	{ 0x3eb3b275, 0x844ced29, 0x3d03b295, 0x7ba79a1c, 0xc43d223b },
+	{ 0x3ecb2174, 0x84290c8b, 0x3d106714, 0x7bcc5ba3, 0xc419dfa5 },
+	{ 0x3ee2044b, 0x8406b244, 0x3d1c2561, 0x7bef8e77, 0xc3f8170f },
+	{ 0x3ef86698, 0x83e5cb96, 0x3d26f4d8, 0x7c114600, 0xc3d7b625 },
+	{ 0x3f0e5390, 0x83c646c9, 0x3d30dc39, 0x7c319498, 0xc3b8ab97 },
+	{ 0x3f23d60b, 0x83a81321, 0x3d39e1af, 0x7c508b9c, 0xc39ae704 },
+	{ 0x3f38f884, 0x838b20d2, 0x3d420ad2, 0x7c6e3b75, 0xc37e58f1 },
+	{ 0x3f4dc52c, 0x836f60ef, 0x3d495cab, 0x7c8ab3a6, 0xc362f2be },
+	{ 0x3f6245e8, 0x8354c565, 0x3d4fdbb8, 0x7ca602d6, 0xc348a69b },
+	{ 0x3f76845f, 0x833b40ec, 0x3d558bf0, 0x7cc036df, 0xc32f677c },
+	{ 0x3f8a8a03, 0x8322c6fb, 0x3d5a70c4, 0x7cd95cd7, 0xc317290b },
+	{ 0x3f9e6014, 0x830b4bc3, 0x3d5e8d25, 0x7cf1811a, 0xc2ffdfa5 },
+	{ 0x3fb20fae, 0x82f4c420, 0x3d61e37f, 0x7d08af56, 0xc2e9804a },
+	{ 0x3fc5a1cc, 0x82df2592, 0x3d6475c3, 0x7d1ef294, 0xc2d40096 },
+	{ 0x3fd91f55, 0x82ca6632, 0x3d664564, 0x7d345541, 0xc2bf56b9 },
+	{ 0x3fec9120, 0x82b67cac, 0x3d675356, 0x7d48e138, 0xc2ab796e },
+	{ 0x40000000, 0x82a36037, 0x3d67a012, 0x7d5c9fc9, 0xc2985fee },
+	{ 0x401374c7, 0x8291088a, 0x3d672b93, 0x7d6f99c3, 0xc28601f2 },
+	{ 0x4026f857, 0x827f6dd7, 0x3d65f559, 0x7d81d77c, 0xc27457a3 },
+	{ 0x403a939f, 0x826e88c5, 0x3d63fc63, 0x7d9360d4, 0xc2635996 },
+	{ 0x404e4faf, 0x825e5266, 0x3d613f32, 0x7da43d42, 0xc25300c6 },
+	{ 0x406235ba, 0x824ec434, 0x3d5dbbc3, 0x7db473d7, 0xc243468e },
+	{ 0x40764f1f, 0x823fd80c, 0x3d596f8f, 0x7dc40b44, 0xc23424a2 },
+	{ 0x408aa576, 0x82318824, 0x3d545787, 0x7dd309e2, 0xc2259509 },
+	{ 0x409f4296, 0x8223cf0b, 0x3d4e7012, 0x7de175b5, 0xc2179218 },
+	{ 0x40b430a0, 0x8216a7a1, 0x3d47b505, 0x7def5475, 0xc20a1670 },
+	{ 0x40c97a0a, 0x820a0d12, 0x3d4021a1, 0x7dfcab8d, 0xc1fd1cf5 },
+	{ 0x40df29a6, 0x81fdfad6, 0x3d37b08d, 0x7e098028, 0xc1f0a0ca },
+	{ 0x40f54ab1, 0x81f26ca9, 0x3d2e5bd1, 0x7e15d72b, 0xc1e49d52 },
+	{ 0x410be8da, 0x81e75e89, 0x3d241cce, 0x7e21b544, 0xc1d90e24 },
+	{ 0x41231051, 0x81dcccb3, 0x3d18ec37, 0x7e2d1ee6, 0xc1cdef10 },
+	{ 0x413acdd0, 0x81d2b39e, 0x3d0cc20a, 0x7e38184e, 0xc1c33c13 },
+	{ 0x41532ea7, 0x81c90ffb, 0x3cff9585, 0x7e42a58b, 0xc1b8f15a },
+	{ 0x416c40cd, 0x81bfdeb2, 0x3cf15d21, 0x7e4cca7c, 0xc1af0b3f },
+	{ 0x418612ea, 0x81b71cdc, 0x3ce20e85, 0x7e568ad3, 0xc1a58640 },
+	{ 0x41a0b465, 0x81aec7c5, 0x3cd19e7c, 0x7e5fea1e, 0xc19c5f03 },
+	{ 0x41bc3573, 0x81a6dcea, 0x3cc000e9, 0x7e68ebc2, 0xc1939250 }
+};
+
+u32 treble_table[41][5] = {
+	{ 0x0125cba9, 0xfed5debd, 0x00599b6c, 0x0d2506da, 0xfa85b354 },
+	{ 0x0142f67e, 0xfeb03163, 0x0066cd0f, 0x0d14c69d, 0xfa914473 },
+	{ 0x016328bd, 0xfe860158, 0x0075b7f2, 0x0d03eb27, 0xfa9d32d2 },
+	{ 0x0186b438, 0xfe56c982, 0x00869234, 0x0cf27048, 0xfaa97fca },
+	{ 0x01adf358, 0xfe21f5fe, 0x00999842, 0x0ce051c2, 0xfab62ca5 },
+	{ 0x01d949fa, 0xfde6e287, 0x00af0d8d, 0x0ccd8b4a, 0xfac33aa7 },
+	{ 0x02092669, 0xfda4d8bf, 0x00c73d4c, 0x0cba1884, 0xfad0ab07 },
+	{ 0x023e0268, 0xfd5b0e4a, 0x00e27b54, 0x0ca5f509, 0xfade7ef2 },
+	{ 0x0278645c, 0xfd08a2b0, 0x01012509, 0x0c911c63, 0xfaecb788 },
+	{ 0x02b8e091, 0xfcac9d1a, 0x0123a262, 0x0c7b8a14, 0xfafb55df },
+	{ 0x03001a9a, 0xfc45e9ce, 0x014a6709, 0x0c65398f, 0xfb0a5aff },
+	{ 0x034ec6d7, 0xfbd3576b, 0x0175f397, 0x0c4e2643, 0xfb19c7e4 },
+	{ 0x03a5ac15, 0xfb5393ee, 0x01a6d6ed, 0x0c364b94, 0xfb299d7c },
+	{ 0x0405a562, 0xfac52968, 0x01ddafae, 0x0c1da4e2, 0xfb39dca5 },
+	{ 0x046fa3fe, 0xfa267a66, 0x021b2ddd, 0x0c042d8d, 0xfb4a8631 },
+	{ 0x04e4b17f, 0xf975be0f, 0x0260149f, 0x0be9e0f2, 0xfb5b9ae0 },
+	{ 0x0565f220, 0xf8b0fbe5, 0x02ad3c29, 0x0bceba73, 0xfb6d1b60 },
+	{ 0x05f4a745, 0xf7d60722, 0x030393d4, 0x0bb2b578, 0xfb7f084d },
+	{ 0x06923236, 0xf6e279bd, 0x03642465, 0x0b95cd75, 0xfb916233 },
+	{ 0x07401713, 0xf5d3aef9, 0x03d01283, 0x0b77fded, 0xfba42984 },
+	{ 0x08000000, 0xf4a6bd88, 0x0448a161, 0x0b594278, 0xfbb75e9f },
+	{ 0x08d3c097, 0xf3587131, 0x04cf35a4, 0x0b3996c9, 0xfbcb01cb },
+	{ 0x09bd59a2, 0xf1e543f9, 0x05655880, 0x0b18f6b2, 0xfbdf1333 },
+	{ 0x0abefd0f, 0xf04956ca, 0x060cbb12, 0x0af75e2c, 0xfbf392e8 },
+	{ 0x0bdb123e, 0xee806984, 0x06c739fe, 0x0ad4c962, 0xfc0880dd },
+	{ 0x0d143a94, 0xec85d287, 0x0796e150, 0x0ab134b0, 0xfc1ddce5 },
+	{ 0x0e6d5664, 0xea547598, 0x087df0a0, 0x0a8c9cb6, 0xfc33a6ad },
+	{ 0x0fe98a2a, 0xe7e6ba35, 0x097edf83, 0x0a66fe5b, 0xfc49ddc2 },
+	{ 0x118c4421, 0xe536813a, 0x0a9c6248, 0x0a4056d7, 0xfc608185 },
+	{ 0x1359422e, 0xe23d19eb, 0x0bd96efb, 0x0a18a3bf, 0xfc77912c },
+	{ 0x1554982b, 0xdef33645, 0x0d3942bd, 0x09efe312, 0xfc8f0bc1 },
+	{ 0x1782b68a, 0xdb50deb1, 0x0ebf676d, 0x09c6133f, 0xfca6f019 },
+	{ 0x19e8715d, 0xd74d64fd, 0x106fb999, 0x099b3337, 0xfcbf3cd6 },
+	{ 0x1c8b07b8, 0xd2df56ab, 0x124e6ec8, 0x096f4274, 0xfcd7f060 },
+	{ 0x1f702b6d, 0xcdfc6e92, 0x14601c10, 0x0942410b, 0xfcf108e5 },
+	{ 0x229e0933, 0xc89985cd, 0x16a9bcfa, 0x09142fb5, 0xfd0a8451 },
+	{ 0x261b5118, 0xc2aa8409, 0x1930bab6, 0x08e50fdc, 0xfd24604d },
+	{ 0x29ef3f5d, 0xbc224f28, 0x1bfaf396, 0x08b4e3aa, 0xfd3e9a3b },
+	{ 0x2e21a59b, 0xb4f2ba46, 0x1f0ec2d6, 0x0883ae15, 0xfd592f33 },
+	{ 0x32baf44b, 0xad0c7429, 0x227308a3, 0x085172eb, 0xfd741bfd },
+	{ 0x37c4448b, 0xa45ef51d, 0x262f3267, 0x081e36dc, 0xfd8f5d14 }
+};
+
+static void set_bass(struct emu10k1_card *card, int l, int r)
+{
+	int i;
+
+	l = (l * 40 + 50) / 100;
+	r = (r * 40 + 50) / 100;
+	for (i = 0; i < 5; i++) {
+		sblive_writeptr(card, FXGPREGBASE + 0x80 + (i * 2), 0, bass_table[l][i]);
+		sblive_writeptr(card, FXGPREGBASE + 0x80 + (i * 2) + 1, 0, bass_table[r][i]);
+	}
+}
+
+static void set_treble(struct emu10k1_card *card, int l, int r)
+{
+	int i;
+
+	l = (l * 40 + 50) / 100;
+	r = (r * 40 + 50) / 100;
+	for (i = 0; i < 5; i++) {
+		sblive_writeptr(card, FXGPREGBASE + 0x90 + (i * 2), 0, treble_table[l][i]);
+		sblive_writeptr(card, FXGPREGBASE + 0x90 + (i * 2) + 1, 0, treble_table[r][i]);
+	}
+}
+
+u32 db_table[101] = {
+	0x00000000, 0x01571f82, 0x01674b41, 0x01783a1b, 0x0189f540,
+	0x019c8651, 0x01aff763, 0x01c45306, 0x01d9a446, 0x01eff6b8,
+	0x0207567a, 0x021fd03d, 0x0239714c, 0x02544792, 0x027061a1,
+	0x028dcebb, 0x02ac9edc, 0x02cce2bf, 0x02eeabe8, 0x03120cb0,
+	0x0337184e, 0x035de2df, 0x03868173, 0x03b10a18, 0x03dd93e9,
+	0x040c3713, 0x043d0cea, 0x04702ff3, 0x04a5bbf2, 0x04ddcdfb,
+	0x0518847f, 0x0555ff62, 0x05966005, 0x05d9c95d, 0x06206005,
+	0x066a4a52, 0x06b7b067, 0x0708bc4c, 0x075d9a01, 0x07b6779d,
+	0x08138561, 0x0874f5d5, 0x08dafde1, 0x0945d4ed, 0x09b5b4fd,
+	0x0a2adad1, 0x0aa58605, 0x0b25f936, 0x0bac7a24, 0x0c3951d8,
+	0x0ccccccc, 0x0d673b17, 0x0e08f093, 0x0eb24510, 0x0f639481,
+	0x101d3f2d, 0x10dfa9e6, 0x11ab3e3f, 0x12806ac3, 0x135fa333,
+	0x144960c5, 0x153e2266, 0x163e6cfe, 0x174acbb7, 0x1863d04d,
+	0x198a1357, 0x1abe349f, 0x1c00db77, 0x1d52b712, 0x1eb47ee6,
+	0x2026f30f, 0x21aadcb6, 0x23410e7e, 0x24ea64f9, 0x26a7c71d,
+	0x287a26c4, 0x2a62812c, 0x2c61df84, 0x2e795779, 0x30aa0bcf,
+	0x32f52cfe, 0x355bf9d8, 0x37dfc033, 0x3a81dda4, 0x3d43c038,
+	0x4026e73c, 0x432ce40f, 0x46575af8, 0x49a8040f, 0x4d20ac2a,
+	0x50c335d3, 0x54919a57, 0x588dead1, 0x5cba514a, 0x611911ea,
+	0x65ac8c2f, 0x6a773c39, 0x6f7bbc23, 0x74bcc56c, 0x7a3d3272,
+	0x7fffffff,
 };
 
-static void update_rearfront(struct sblive_hw *sb_hw)
+static void update_digital(struct emu10k1_card *card)
 {
-	int i, l1, l2, l3, r1, r2, r3;
-	u16 reg, wval;
+	int i, k, l1, r1, l2, r2, l3, r3, l4, r4;
+	u64 j;
 
-	reg = sb_hw->arrwVol[volidx[SOUND_MIXER_PCM] - 1];
-	l1 = (reg & 0xff);
-	r1 = (reg >> 8) & 0xff;
-
-	reg = sb_hw->arrwVol[volidx[SOUND_MIXER_LINE2] - 1];
-	l2 = (reg & 0xff);
-	r2 = (reg >> 8) & 0xff;
-
-	reg = sb_hw->arrwVol[volidx[SOUND_MIXER_VOLUME] - 1];
-	l3 = (reg & 0xff);
-	r3 = (reg >> 8) & 0xff;
+	i = card->arrwVol[volidx[SOUND_MIXER_VOLUME]];
+	l1 = (i & 0xff);
+	r1 = ((i >> 8) & 0xff);
+	i = card->arrwVol[volidx[SOUND_MIXER_LINE3]];
+	l2 = i & 0xff;
+	r2 = (i >> 8) & 0xff;
+
+	i = card->arrwVol[volidx[SOUND_MIXER_PCM]];
+	l3 = i & 0xff;
+	r3 = (i >> 8) & 0xff;
+
+	i = card->arrwVol[volidx[SOUND_MIXER_DIGITAL1]];
+	l4 = i & 0xff;
+	r4 = (i >> 8) & 0xff;
 
 	i = (r1 * r2) / 50;
 	if (r2 > 50)
@@ -233,18 +375,113 @@
 		l2 = l1;
 		l1 = i;
 	}
+
+	for (i = 0; i < 18; i++) {
+		if (card->digmix[i] != 0x80000000) {
+			if ((i >= 0) && (i < 4))
+				j = (i & 1) ? ((u64) db_table[r1] * (u64) db_table[r3]) : ((u64) db_table[l1] * (u64) db_table[l3]);
+			else if ((i == 6) || (i == 7))
+				j = (i & 1) ? ((u64) db_table[r1] * (u64) db_table[r4]) : ((u64) db_table[l1] * (u64) db_table[l4]);
+			else
+				j = ((i & 1) ? db_table[r1] : db_table[l1]) << 31;
+			card->digmix[i] = j >> 31;
+			sblive_writeptr(card, FXGPREGBASE + 0x10 + i, 0, card->digmix[i]);
+		}
+	}
+
+	for (i = 72; i < 90; i++) {
+		if (card->digmix[i] != 0x80000000) {
+			if ((i >= 72) && (i < 76))
+				j = (i & 1) ? ((u64) db_table[r2] * (u64) db_table[r3]) : ((u64) db_table[l2] * (u64) db_table[l3]);
+			else if ((i == 78) || (i == 79))
+				j = (i & 1) ? ((u64) db_table[r2] * (u64) db_table[r4]) : ((u64) db_table[l2] * (u64) db_table[l4]);
+			else
+				j = ((i & 1) ? db_table[r2] : db_table[l2]) << 31;
+			card->digmix[i] = j >> 31;
+			sblive_writeptr(card, FXGPREGBASE + 0x10 + i, 0, card->digmix[i]);
+		}
+	}
+
+	for (i = 18; i <= 90; i += 18) {
+		if (i != 72) {
+			for (k = 0; k < 4; k++)
+				if (card->digmix[i + k] != 0x80000000) {
+					card->digmix[i + k] = db_table[l3];
+					sblive_writeptr(card, FXGPREGBASE + 0x10 + i + k, 0, card->digmix[i + k]);
+				}
+			if (card->digmix[i + 6] != 0x80000000) {
+				card->digmix[i + 6] = db_table[l4];
+				sblive_writeptr(card, FXGPREGBASE + 0x10 + i + 6, 0, card->digmix[i + 6]);
+			}
+			if (card->digmix[i + 7] != 0x80000000) {
+				card->digmix[i + 7] = db_table[r4];
+				sblive_writeptr(card, FXGPREGBASE + 0x10 + i + 7, 0, card->digmix[i + 7]);
+			}
+		}
+	}
+
+}
+
+#ifdef PRIVATE_PCM_VOLUME
+
+/* calc & set attenuation factor for given channel */
+static int set_pcm_attn(struct emu10k1_card *card, int ch, int l)
+{
+#ifndef PCMLEVEL
+#define PCMLEVEL 140		// almost silence
+#endif
+	int vol = IFATN_ATTENUATION_MASK;	// silence
+
+	if (l > 0)
+		vol = (PCMLEVEL - (l * PCMLEVEL + 50) / 100);
+	sblive_writeptr(card, IFATN, ch, IFATN_FILTERCUTOFF_MASK | vol);
+	DPD(2, "SOUND_MIXER_PCM: channel:%d  level:%d  attn:%d\n", ch, l, vol);
+
+	return vol;
+#undef PCMLEVEL
+}
+
+/* update value of local PCM volume level (using channel attenuation)
+ *
+ * return 1: in case its local change
+ *        0: if the current process doesn't have entry in table
+ *	     (it means this process have not opened audio (mixer usually)
+ */
+static int update_pcm_attn(struct emu10k1_card *card, unsigned l1, unsigned r1)
+{
+	int i;
+	int mixer = (r1 << 8) | l1;
+
+	for (i = 0; i < MAX_PCM_CHANNELS; i++) {
+		if (sblive_pcm_volume[i].files == current->files) {
+			sblive_pcm_volume[i].mixer = mixer;
+			if (sblive_pcm_volume[i].opened) {
+				if (sblive_pcm_volume[i].channel_r < NUM_G) {
+					if (sblive_pcm_volume[i].channel_l < NUM_G)
+						sblive_pcm_volume[i].attn_l = set_pcm_attn(card, sblive_pcm_volume[i].channel_l, l1);
+					sblive_pcm_volume[i].attn_r = set_pcm_attn(card, sblive_pcm_volume[i].channel_r, r1);
+				} else {
+					// mono voice
+					if (sblive_pcm_volume[i].channel_l < NUM_G)
+						sblive_pcm_volume[i].attn_l =
+						    set_pcm_attn(card, sblive_pcm_volume[i].channel_l, (l1 >= r1) ? l1 : r1);
+					// to correctly handle mono voice here we would need
+					// to go into stereo mode and move the voice to the right & left
+					// looks a bit overcomlicated...
+				}
+
+			}
+			return 1;
+		}
+	}
+	if (i == MAX_PCM_CHANNELS)
+		card->arrwVol[volidx[SOUND_MIXER_PCM]] = mixer;
 
-	sblive_writeptr(sb_hw, FXGPREGBASE + 0x10, 0, l2 * l3 * (0x7fffffff / 10000));
-	sblive_writeptr(sb_hw, FXGPREGBASE + 0x11, 0, r2 * r3 * (0x7fffffff / 10000));
-	wval = ((((100 - l1) * 32 + 50) / 100) << 8) | (((100 - r1) * 32 + 50) / 100);
-	if (wval == 0x2020)
-		wval = 0x8000;
-	else
-		wval -= ((wval & 0x2020) / 0x20);
-	sblive_writeac97(sb_hw, volreg[SOUND_MIXER_PCM], wval);
+	return 0;
 }
+#endif
 
-static int mixer_wrch(struct sblive_hw * sb_hw, unsigned int ch, int val)
+int emu10k1_mixer_wrch(struct emu10k1_card *card, unsigned int ch, int val)
 {
 	int i;
 	unsigned l1, r1;
@@ -257,62 +494,59 @@
 	if (r1 > 100)
 		r1 = 100;
 
-	DPD(2, "mixer_wrch() called: ch=%u, l1=%u, r1=%u\n", ch, l1, r1);
+	DPD(4, "emu10k1_mixer_wrch() called: ch=%u, l1=%u, r1=%u\n", ch, l1, r1);
 
-	if (!volidx[ch]) return -EINVAL;
-	sb_hw->arrwVol[volidx[ch] - 1] = (r1 << 8) | l1;
+	if (!volidx[ch])
+		return -EINVAL;
+#ifdef PRIVATE_PCM_VOLUME
+	if (ch != SOUND_MIXER_PCM)
+#endif
+		card->arrwVol[volidx[ch]] = (r1 << 8) | l1;
 
-	switch (ch)
-	{
-	case SOUND_MIXER_LINE2:
-		DPF(2, "SOUND_MIXER_LINE2:\n");
-		update_rearfront(sb_hw);
-		return 0;
-	case SOUND_MIXER_DIGITAL2:
-		DPF(2, "SOUND_MIXER_DIGITAL2:\n");
-		sblive_writeptr(sb_hw, FXGPREGBASE + 0x14, 0, l1 * (0x7fffffff / 100));
-		sblive_writeptr(sb_hw, FXGPREGBASE + 0x15, 0, r1 * (0x7fffffff / 100));
-		return 0;
+	switch (ch) {
+	case SOUND_MIXER_VOLUME:
 	case SOUND_MIXER_DIGITAL1:
-		DPF(2, "SOUND_MIXER_DIGITAL1:\n");
-		sblive_writeptr(sb_hw, FXGPREGBASE + 0x12, 0, l1 * (0x7fffffff / 100));
-		sblive_writeptr(sb_hw, FXGPREGBASE + 0x13, 0, r1 * (0x7fffffff / 100));
+	case SOUND_MIXER_LINE3:
+		DPD(4, "SOUND_MIXER_%s:\n", (ch == SOUND_MIXER_VOLUME) ? "VOLUME" : (ch == SOUND_MIXER_DIGITAL1) ? "DIGITAL1" : "LINE3");
+		update_digital(card);
 		return 0;
 	case SOUND_MIXER_PCM:
-		DPF(2, "SOUND_MIXER_PCM:\n");
-		update_rearfront(sb_hw);
+		DPF(4, "SOUND_MIXER_PCM\n");
+#ifdef PRIVATE_PCM_VOLUME
+		if (update_pcm_attn(card, l1, r1))
+			return 0;
+#endif
+		update_digital(card);
 		return 0;
+	case SOUND_MIXER_DIGITAL2:
+	case SOUND_MIXER_LINE2:
 	case SOUND_MIXER_LINE1:
-		DPF(2, "SOUND_MIXER_LINE1:\n");
 	case SOUND_MIXER_LINE:
-		DPF(2, "SOUND_MIXER_LINE:\n");
 	case SOUND_MIXER_CD:
-		DPF(2, "SOUND_MIXER_CD:\n");
-	case SOUND_MIXER_VOLUME:
-		DPF(2, "SOUND_MIXER_VOLUME:\n");
+		DPD(4, "SOUND_MIXER_%s:\n",
+		    (ch == SOUND_MIXER_LINE1) ? "LINE1" :
+		    (ch == SOUND_MIXER_LINE2) ? "LINE2" : (ch == SOUND_MIXER_LINE) ? "LINE" : (ch == SOUND_MIXER_DIGITAL2) ? "DIGITAL2" : "CD");
 		wval = ((((100 - l1) * 32 + 50) / 100) << 8) | (((100 - r1) * 32 + 50) / 100);
 		if (wval == 0x2020)
 			wval = 0x8000;
 		else
 			wval -= ((wval & 0x2020) / 0x20);
-		sblive_writeac97(sb_hw, volreg[ch], wval);
-		if (ch == SOUND_MIXER_VOLUME) update_rearfront(sb_hw);
+		sblive_writeac97(card, volreg[ch], wval);
 		return 0;
 
 	case SOUND_MIXER_OGAIN:
-		DPF(2, "SOUND_MIXER_OGAIN:\n");
 	case SOUND_MIXER_PHONEIN:
-		DPF(2, "SOUND_MIXER_PHONEIN:\n");
-		sblive_writeac97(sb_hw, volreg[ch], (l1 < 2) ? 0x8000 : ((100 - l1) * 32 + 50) / 100);
+		DPD(4, "SOUND_MIXER_%s:\n", (ch == SOUND_MIXER_PHONEIN) ? "PHONEIN" : "OGAIN");
+		sblive_writeac97(card, volreg[ch], (l1 < 2) ? 0x8000 : ((100 - l1) * 32 + 50) / 100);
 		return 0;
 
 	case SOUND_MIXER_SPEAKER:
-		DPF(2, "SOUND_MIXER_SPEAKER:\n");
-		sblive_writeac97(sb_hw, volreg[ch], (l1 < 4) ? 0x8000 : (((100 - l1) * 16 + 50) / 100) << 1);
+		DPF(4, "SOUND_MIXER_SPEAKER:\n");
+		sblive_writeac97(card, volreg[ch], (l1 < 4) ? 0x8000 : (((100 - l1) * 16 + 50) / 100) << 1);
 		return 0;
 
 	case SOUND_MIXER_MIC:
-		DPF(2, "SOUND_MIXER_MIC:\n");
+		DPF(4, "SOUND_MIXER_MIC:\n");
 		i = 0;
 		if (l1 >= 30)
 			// 20dB / (34.5dB + 12dB + 20dB) * 100 = 30
@@ -320,150 +554,127 @@
 			l1 -= 30;
 			i = 0x40;
 		}
-		sblive_writeac97(sb_hw, volreg[ch], (l1 < 2) ? 0x8000 : ((((70 - l1) * 0x20 + 35) / 70) | i));
+		sblive_writeac97(card, volreg[ch], (l1 < 2) ? 0x8000 : ((((70 - l1) * 0x20 + 35) / 70) | i));
 		return 0;
 
 	case SOUND_MIXER_RECLEV:
-		DPF(2, "SOUND_MIXER_RECLEV:\n");
+		DPF(4, "SOUND_MIXER_RECLEV:\n");
+
 		wval = (((l1 * 16 + 50) / 100) << 8) | ((r1 * 16 + 50) / 100);
 		if (wval == 0)
 			wval = 0x8000;
 		else {
-			if (wval & 0xff) wval--;
-			if (wval & 0xff00) wval -= 0x0100;
+			if (wval & 0xff)
+				wval--;
+			if (wval & 0xff00)
+				wval -= 0x0100;
 		}
-		sblive_writeac97(sb_hw, volreg[ch], wval);
+		sblive_writeac97(card, volreg[ch], wval);
 		return 0;
 
 	case SOUND_MIXER_TREBLE:
-		DPF(2, "SOUND_MIXER_TREBLE:\n");
-
-		{
-			//u8 atnL = sumVolumeToAttenuation(100 - l1);
-			//u8 atnR = sumVolumeToAttenuation(100 - r1);
-			u8 atnL = (100 - l1) * 0xa0 / 100;
-			u8 atnR = (100 - r1) * 0xa0 / 100;
-			int i = 0;
-
-			DPD(2, "atnL = 0x%08x, atnR = 0x%08x\n", atnL, atnR);
-
-			while (i < 64)
-			{
-				sblive_writeptr(sb_hw, IFATN_ATTENUATION, i++, atnL);
-				sblive_writeptr(sb_hw, IFATN_ATTENUATION, i++, atnR);
-			}
-			return 0;
-		}
+		DPF(4, "SOUND_MIXER_TREBLE:\n");
+		set_treble(card, l1, r1);
+		return 0;
 
 	case SOUND_MIXER_BASS:
-		DPF(2, "SOUND_MIXER_BASS:\n");
+		DPF(4, "SOUND_MIXER_BASS:\n");
+		set_bass(card, l1, r1);
+		return 0;
 
-		{
-			static int idxB = 0;
-			u8 peL = (l1 * 255 / 100 - 128) & 0xff;
-			u8 peR = (r1 * 255 / 100 - 128) & 0xff;
-			int i = 0; /* Usually first channel */
-
-			idxB += 1;
-			idxB &= 0xf;
-			DPD(2, "using 0x%08x\n", idxB);
-
-			/* for (i = 9; i <= 9; i++) { */
-			/* sblive_writeptr(sb_hw, CVCF_CURRENTFILTER, i, idx); */
-			/* sblive_writeptr(sb_hw, CVCF_CURRENTVOL, i, idx); */
-
-			/* this is pure hack - its for 4 channels */
-			/* FIXME: This is very odd, most of this code will
-			 * never be executed. */
-			while (i < 64)
-			{
-				if (1)
-				{
-					sblive_writeptr(sb_hw, PEFE_FILTERAMOUNT, i++, peL);
-					sblive_writeptr(sb_hw, PEFE_FILTERAMOUNT, i++, peR);
-				} else if (0)
-				{
-					sblive_writeptr(sb_hw, PEFE_PITCHAMOUNT, i++, peL);
-					sblive_writeptr(sb_hw, PEFE_FILTERAMOUNT, i++, peR);
-				} else if (0)
-				{
-					sblive_writeptr(sb_hw, IFATN_FILTERCUTOFF, i++, peL);
-					sblive_writeptr(sb_hw, IFATN_FILTERCUTOFF, i++, peR);
-				} else if (0)
-				{
-					sblive_writeptr(sb_hw, IP,  i++, idxB << 12);
-					sblive_writeptr(sb_hw, IP, i++, idxB << 12);
-				}
-			}
-			return 0;
-		}
 	default:
 		DPF(2, "Got unknown SOUND_MIXER ioctl\n");
 		return -EINVAL;
 	}
 }
-
 
-static loff_t sblive_mixer_llseek(struct file *file, loff_t offset, int nOrigin)
+static loff_t emu10k1_mixer_llseek(struct file *file, loff_t offset, int origin)
 {
 	DPF(2, "sblive_mixer_llseek() called\n");
 	return -ESPIPE;
 }
 
 /* Mixer file operations */
+
 /* FIXME: Do we need spinlocks in here? */
-static int sblive_mixer_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg)
+static int emu10k1_mixer_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg)
 {
 	static const char id[] = "SBLive";
 	static const char name[] = "Creative SBLive";
 	int i, val;
-	struct sblive_hw * sb_hw = (struct sblive_hw *) file->private_data;
+	struct emu10k1_card *card = (struct emu10k1_card *) file->private_data;
 	u16 reg;
+
+	switch (cmd) {
+
+	case SOUND_MIXER_INFO:{
+			mixer_info info;
+
+			DPF(4, "SOUND_MIXER_INFO\n");
+
+			strncpy(info.id, id, sizeof(info.id));
+			strncpy(info.name, name, sizeof(info.name));
+
+			info.modify_counter = card->modcnt;
+			if (copy_to_user((void *) arg, &info, sizeof(info)))
+				return -EFAULT;
+
+			return 0;
+		}
+		break;
+	case SOUND_OLD_MIXER_INFO:{
+			_old_mixer_info info;
+
+			DPF(4, "SOUND_OLD_MIXER_INFO\n");
 
-	if (cmd == SOUND_MIXER_INFO)
-	{
-		mixer_info info;
-		DPF(2, "SOUND_MIXER_INFO\n");
+			strncpy(info.id, id, sizeof(info.id));
+			strncpy(info.name, name, sizeof(info.name));
 
-		strncpy(info.id, id, sizeof(info.id));
-		strncpy(info.name, name, sizeof(info.name));
+			if (copy_to_user((void *) arg, &info, sizeof(info)))
+				return -EFAULT;
 
-		info.modify_counter = sb_hw->modcnt;
-		if (copy_to_user((void *) arg, &info, sizeof(info)))
+			return 0;
+		}
+		break;
+
+	case OSS_GETVERSION:
+		DPF(4, "OSS_GETVERSION\n");
+		return put_user(SOUND_VERSION, (int *) arg);
+		break;
+
+	case SOUND_MIXER_PRIVATE1:
+		DPF(4, "SOUND_MIXER_PRIVATE1");
+
+		if (copy_to_user((void *) arg, card->digmix, sizeof(card->digmix)))
 			return -EFAULT;
-		return 0;
-	}
 
-	if (cmd == SOUND_OLD_MIXER_INFO)
-	{
-		_old_mixer_info info;
-		DPF(2, "SOUND_OLD_MIXER_INFO\n");
+		return 0;
 
-		strncpy(info.id, id, sizeof(info.id));
-		strncpy(info.name, name, sizeof(info.name));
+		break;
+	case SOUND_MIXER_PRIVATE2:
+		DPF(4, "SOUND_MIXER_PRIVATE2");
 
-		if (copy_to_user((void *) arg, &info, sizeof(info)))
+		if (copy_from_user(card->digmix, (void *) arg, sizeof(card->digmix)))
 			return -EFAULT;
 
+		for (i = 0; i < sizeof(card->digmix) / sizeof(card->digmix[0]); i++)
+			sblive_writeptr(card, FXGPREGBASE + 0x10 + i, 0, (card->digmix[i] & 0x80000000) ? 0 : card->digmix[i]);
 		return 0;
-	}
 
-	if (cmd == OSS_GETVERSION)
-	{
-		DPF(2, "OSS_GETVERSION\n");
-		return put_user(SOUND_VERSION, (int *) arg);
+		break;
+
+	default:
+		break;
 	}
 
 	if (_IOC_TYPE(cmd) != 'M' || _IOC_SIZE(cmd) != sizeof(int))
 		return -EINVAL;
 
-	if (_IOC_DIR(cmd) == _IOC_READ)
-	{
-		switch (_IOC_NR(cmd))
-		{
+	if (_IOC_DIR(cmd) == _IOC_READ) {
+		switch (_IOC_NR(cmd)) {
 		case SOUND_MIXER_RECSRC:	/* Arg contains a bit for each recording source */
 			DPF(2, "SOUND_MIXER_READ_RECSRC\n");
-			sblive_readac97(sb_hw, AC97_RECORDSELECT, &reg);
+			sblive_readac97(card, AC97_RECORDSELECT, &reg);
 			return put_user(recsrc[reg & 7], (int *) arg);
 
 		case SOUND_MIXER_DEVMASK:	/* Arg contains a bit for each supported device */
@@ -472,56 +683,68 @@
 					SOUND_MASK_OGAIN | SOUND_MASK_LINE1 |
 					SOUND_MASK_PCM | SOUND_MASK_VOLUME |
 					SOUND_MASK_PHONEIN | SOUND_MASK_MIC |
-					/* SOUND_MASK_BASS | SOUND_MASK_TREBLE | */ /* Why not enable these? [jtaylor] */
+					SOUND_MASK_BASS | SOUND_MASK_TREBLE |
 					SOUND_MASK_RECLEV | SOUND_MASK_SPEAKER |
-					SOUND_MASK_LINE2 | SOUND_MASK_DIGITAL1 |
-					SOUND_MASK_DIGITAL2,
-					(int *) arg);
+					SOUND_MASK_LINE3 | SOUND_MASK_DIGITAL1 | 
+					SOUND_MASK_DIGITAL2 | SOUND_MASK_LINE2, (int *) arg);
 		case SOUND_MIXER_RECMASK:	/* Arg contains a bit for each supported recording source */
 			DPF(2, "SOUND_MIXER_READ_RECMASK\n");
 			return put_user(SOUND_MASK_MIC | SOUND_MASK_CD |
-					SOUND_MASK_LINE1 | SOUND_MASK_LINE |
-					SOUND_MASK_VOLUME | SOUND_MASK_OGAIN |
-					SOUND_MASK_PHONEIN, (int *) arg);
+					SOUND_MASK_LINE1 | SOUND_MASK_LINE | 
+					SOUND_MASK_VOLUME | SOUND_MASK_OGAIN | 
+					SOUND_MASK_PHONEIN | SOUND_MASK_MONITOR | 
+					SOUND_MASK_PCM, (int *) arg);
 
 		case SOUND_MIXER_STEREODEVS:	/* Mixer channels supporting stereo */
 			DPF(2, "SOUND_MIXER_READ_STEREODEVS\n");
 			return put_user(SOUND_MASK_LINE | SOUND_MASK_CD |
 					SOUND_MASK_OGAIN | SOUND_MASK_LINE1 |
 					SOUND_MASK_PCM | SOUND_MASK_VOLUME |
-					/*SOUND_MASK_BASS | SOUND_MASK_TREBLE |*/ /* ...especially since they are enabled here */
-					SOUND_MASK_RECLEV | SOUND_MASK_LINE2 |
-					SOUND_MASK_DIGITAL1 | SOUND_MASK_DIGITAL2,
-					(int *) arg);
+					SOUND_MASK_BASS | SOUND_MASK_TREBLE |
+					SOUND_MASK_RECLEV | SOUND_MASK_LINE3 |
+					SOUND_MASK_DIGITAL1 | SOUND_MASK_DIGITAL2 | 
+					SOUND_MASK_LINE2, (int *) arg);
 
 		case SOUND_MIXER_CAPS:
 			DPF(2, "SOUND_MIXER_READ_CAPS\n");
 			return put_user(SOUND_CAP_EXCL_INPUT, (int *) arg);
 
+#ifdef PRIVATE_PCM_VOLUME
+		case SOUND_MIXER_PCM:
+			// needs to be before default: !!
+			{
+				int i;
+
+				for (i = 0; i < MAX_PCM_CHANNELS; i++) {
+					if (sblive_pcm_volume[i].files == current->files) {
+						return put_user((int) sblive_pcm_volume[i].mixer, (int *) arg);
+					}
+				}
+			}
+#endif
 		default:
 			i = _IOC_NR(cmd);
 			DPD(4, "SOUND_MIXER_READ(%d)\n", i);
 			if (i >= SOUND_MIXER_NRDEVICES)
 				return -EINVAL;
 #ifdef OSS_DOCUMENTED_MIXER_SEMANTICS
-			return mixer_rdch(sb_hw, i, (int *) arg);
+			return mixer_rdch(card, i, (int *) arg);
 #else				/* OSS_DOCUMENTED_MIXER_SEMANTICS */
 			if (!volidx[i])
 				return -EINVAL;
-			return put_user(sb_hw->arrwVol[volidx[i] - 1], (int *) arg);
+			return put_user(card->arrwVol[volidx[i]], (int *) arg);
 
 #endif				/* OSS_DOCUMENTED_MIXER_SEMANTICS */
 		}
-	}			/* End of _IOC_READ */
-
+	}
+	/* End of _IOC_READ */
 	if (_IOC_DIR(cmd) != (_IOC_READ | _IOC_WRITE))
 		return -EINVAL;
 
 	/* _IOC_WRITE */
-	sb_hw->modcnt++;
+	card->modcnt++;
 
-	switch (_IOC_NR(cmd))
-	{
+	switch (_IOC_NR(cmd)) {
 	case SOUND_MIXER_RECSRC:	/* Arg contains a bit for each recording source */
 		DPF(2, "SOUND_MIXER_WRITE_RECSRC\n");
 
@@ -529,18 +752,15 @@
 		i = hweight32(val);
 		if (i == 0)
 			return 0;	/*val = mixer_recmask(s); */
-		else if (i > 1)
-		{
-			sblive_readac97(sb_hw, AC97_RECORDSELECT, &reg);
+		else if (i > 1) {
+			sblive_readac97(card, AC97_RECORDSELECT, &reg);
 			val &= ~recsrc[reg & 7];
 		}
 
-		for (i = 0; i < 8; i++)
-		{
-			if (val & recsrc[i])
-			{
+		for (i = 0; i < 8; i++) {
+			if (val & recsrc[i]) {
 				DPD(2, "Selecting record source to be 0x%04x\n", 0x0101 * i);
-				sblive_writeac97(sb_hw, AC97_RECORDSELECT, 0x0101 * i);
+				sblive_writeac97(card, AC97_RECORDSELECT, 0x0101 * i);
 				return 0;
 			}
 		}
@@ -548,116 +768,57 @@
 
 	default:
 		i = _IOC_NR(cmd);
-		DPD(2, "SOUND_MIXER_WRITE(%d)\n", i);
+		DPD(4, "SOUND_MIXER_WRITE(%d)\n", i);
 
 		if (i >= SOUND_MIXER_NRDEVICES)
 			return -EINVAL;
 		get_user_ret(val, (int *) arg, -EFAULT);
-		if (mixer_wrch(sb_hw, i, val))
+		if (emu10k1_mixer_wrch(card, i, val))
 			return -EINVAL;
 
 #ifdef OSS_DOCUMENTED_MIXER_SEMANTICS
-		return mixer_rdch(sb_hw, i, (int *) arg);
+		return mixer_rdch(card, i, (int *) arg);
 #else				/* OSS_DOCUMENTED_MIXER_SEMANTICS */
-		return put_user(sb_hw->arrwVol[volidx[i] - 1], (int *) arg);
+		return put_user(card->arrwVol[volidx[i]], (int *) arg);
 #endif				/* OSS_DOCUMENTED_MIXER_SEMANTICS */
 
 	}
 }
 
-static int sblive_mixer_open(struct inode *inode, struct file *file)
+static int emu10k1_mixer_open(struct inode *inode, struct file *file)
 {
-	int nMinor = MINOR(inode->i_rdev);
-	struct sblive_hw * currobj = sblive_devs;
+	int minor = MINOR(inode->i_rdev);
+	struct emu10k1_card *card;
+	struct list_head *entry;
 
-	DPF(4, "sblive_mixer_open() called!\n");
+	DPF(4, "emu10k1_mixer_open()\n");
 
-	while (currobj && currobj->mixer_num != nMinor)
-		currobj = currobj->next;
-	if (!currobj)
+	list_for_each(entry, &emu10k1_devs) {
+		card = list_entry(entry, struct emu10k1_card, list);
+
+		if (card->mixer_num == minor)
+			break;
+	}
+
+	if (entry == &emu10k1_devs)
 		return -ENODEV;
 
-	file->private_data = currobj;
 	MOD_INC_USE_COUNT;
+
+	file->private_data = card;
 	return 0;
 }
 
-static int sblive_mixer_close(struct inode *inode, struct file *file)
+static int emu10k1_mixer_release(struct inode *inode, struct file *file)
 {
-	DPF(4, "sblive_mixer_close() called!\n");
+	DPF(3, "emu10k1_mixer_release()\n");
 	MOD_DEC_USE_COUNT;
 	return 0;
 }
 
-
-struct file_operations emu10k1_mixer_fops =
-{
-	&sblive_mixer_llseek,
-	NULL,			/* read */
-	NULL,			/* write */
-	NULL,			/* readdir */
-	NULL,			/* select/poll */
-	&sblive_mixer_ioctl,
-	NULL,			/* mmap */
-	&sblive_mixer_open,
-	NULL,			/* flush */
-	&sblive_mixer_close,
-	NULL,			/* fsync */
-	NULL,			/* fasync */
-};
-
-static const struct initvol
-{
-	int mixch;
-	int vol;
-} initvol[] __initdata =
-{
-	{ SOUND_MIXER_VOLUME, 0x5050 },
-	{ SOUND_MIXER_OGAIN, 0x5050 },
-	{ SOUND_MIXER_SPEAKER, 0x5050 },
-	{ SOUND_MIXER_PHONEIN, 0x5050 },
-	{ SOUND_MIXER_MIC, 0x5050 },
-	{ SOUND_MIXER_LINE, 0x5050 },
-	{ SOUND_MIXER_CD, 0x5050 },
-	{ SOUND_MIXER_LINE1, 0x5050 },
-	{ SOUND_MIXER_LINE2, 0x3232 },
-	{ SOUND_MIXER_DIGITAL1, 0x5050 },
-	{ SOUND_MIXER_DIGITAL2, 0x0000 },
-	{ SOUND_MIXER_PCM, 0x5050 },
-	{ SOUND_MIXER_RECLEV, 0x5050 } /*,
-	{ SOUND_MIXER_TREBLE, 0x5050 },
-	{ SOUND_MIXER_BASS, 0x5050 } */
+struct file_operations emu10k1_mixer_fops = {
+	llseek:emu10k1_mixer_llseek,
+	ioctl:emu10k1_mixer_ioctl,
+	open:emu10k1_mixer_open,
+	release:emu10k1_mixer_release,
 };
-
-/* FIXME: Do we need spinlocks in here? */
-int sblive_mixer_init(struct sblive_hw * sb_hw)
-{
-	int count;
-
-	/* Reset */
-	sblive_writeac97(sb_hw, AC97_RESET, 0);
-
-#if 0
-	/* Check status word */
-	{
-		u16 reg;
-		sblive_readac97(sb_hw, AC97_RESET, &reg);
-		DPD(2, "RESET 0x%x\n", reg);
-		sblive_readac97(sb_hw, AC97_MASTERTONE, &reg);
-		DPD(2, "MASTER_TONE 0x%x\n", reg);
-	}
-#endif
-
-	/* Set default recording source to mic in */
-	sblive_writeac97(sb_hw, AC97_RECORDSELECT, 0);
-
-	/* Set default volumes for all mixer channels */
-	for (count = 0; count < sizeof(initvol) / sizeof(initvol[0]); count++)
-	{
-		mixer_wrch(sb_hw, initvol[count].mixch, initvol[count].vol);
-	}
-
-	sb_hw->modcnt = 0;	// Should this be here or in open() ?
-
-	return CTSTATUS_SUCCESS;
-}
Index: oldkernel/linux/drivers/sound/emu10k1/mmwave.h
diff -u linux/drivers/sound/emu10k1/mmwave.h:1.1 linux/drivers/sound/emu10k1/mmwave.h:1.2
--- linux/drivers/sound/emu10k1/mmwave.h:1.1	Thu Jun  1 16:52:15 2000
+++ linux/drivers/sound/emu10k1/mmwave.h	Fri Jul  7 15:36:45 2000
@@ -63,14 +63,6 @@
 	WAVEINSTANCEFILTERQ,
 	WAVEINSTANCEFILTERCUTOFF,
 	WAVEINSTANCEFORMAT,
-
-	WAVEPROPERTYSETGET = 0x200,
-	WAVEPROPERTYSETSET,
-	WAVEPROPERTYSETQUERYSUPPORT,
-
-	WAVEGET3DBUFFERPROPERTYSETIFACE = 0x250,
-	WAVEGET3DLISTENERPROPERTYSETIFACE,
-	WAVENUMFREE3DBUFFERS
 };
 
 #endif /* _MMWAVE_H */
Index: oldkernel/linux/drivers/sound/emu10k1/mycommon.h
diff -u linux/drivers/sound/emu10k1/mycommon.h:1.1 linux/drivers/sound/emu10k1/mycommon.h:1.2
--- linux/drivers/sound/emu10k1/mycommon.h:1.1	Thu Jun  1 16:52:15 2000
+++ linux/drivers/sound/emu10k1/mycommon.h	Fri Jul  7 15:36:45 2000
@@ -40,9 +40,7 @@
 /* extern global variables */
 extern struct sblive_hw * sblive_devs;
 extern struct file_operations emu10k1_audio_fops;
-extern struct file_operations emu10k1_dac_fops;
 extern struct file_operations emu10k1_mixer_fops;
 extern struct file_operations emu10k1_midi_fops;
-extern struct file_operations emu10k1_sndstat_fops;
 
 #endif /* _MYCOMMON_H */
Index: oldkernel/linux/drivers/sound/emu10k1/osutils.c
diff -u linux/drivers/sound/emu10k1/osutils.c:1.1 linux/drivers/sound/emu10k1/osutils.c:1.2
--- linux/drivers/sound/emu10k1/osutils.c:1.1	Thu Jun  1 16:52:15 2000
+++ linux/drivers/sound/emu10k1/osutils.c	Fri Jul  7 15:36:45 2000
@@ -1,3 +1,4 @@
+
 /*
  **********************************************************************
  *     osutils.c - OS Services layer for emu10k1 driver
@@ -30,24 +31,17 @@
  **********************************************************************
  */
 
-/* FIXME! This file should not exist!
- * We do not need the crossplatform support anymore
- * This is a Linux-only driver
- */
-
 #include "hwaccess.h"
-#include "mycommon.h"
 
-
-int osAllocMemPhysical(u32 size, struct memhandle **handle)
+struct memhandle *emu10k1_alloc_memphysical(u32 size)
 {
+	struct memhandle *handle;
 	u32 reqpage, order;
 
-	*handle = (struct memhandle *) kmalloc(sizeof(struct memhandle), GFP_KERNEL);
-	if (*handle == NULL)
-		return CTSTATUS_NOMEMORY;
+	if ((handle = (struct memhandle *) kmalloc(sizeof(struct memhandle), GFP_KERNEL)) == NULL)
+		return handle;
 
-	DPD(3, "kmalloc: [%p]\n", *handle);
+	DPD(3, "kmalloc: [%p]\n", handle);
 
 	order = 0;
 	reqpage = size / PAGE_SIZE;
@@ -55,26 +49,20 @@
 	if (size % PAGE_SIZE)
 		reqpage++;
 
-	if (reqpage != 0)
-	{
+	if (reqpage != 0) {
 		reqpage--;
-		while (reqpage > 0)
-		{
+		while (reqpage > 0) {
 			reqpage >>= 1;
 			order++;
 		}
 	}
 
-	if (((*handle)->virtaddx = (void *)__get_free_pages(GFP_KERNEL, order)) == 0)
-	{
-		kfree((void *) *handle);
-
-		DPD(3, "kfree: [%p]\n", *handle);
-		*handle = NULL;
-		return CTSTATUS_NOMEMORY;
-	}
+	if ((handle->virtaddx = (void *) __get_free_pages(GFP_KERNEL, order)) == NULL) {
+		kfree(handle);
 
-	DPD(3, "__get_free_pages: [%p]\n", (*handle)->virtaddx);
+		DPD(3, "kfree: [%p]\n", handle);
+		return (void *) NULL;
+	}
 
 	/* in linux, we can directly access physical address, don't need to do
 	 * phys_to_virt.
@@ -83,92 +71,21 @@
 	 * get_free_pages returns virtual address, we need to convert it
 	 * to physical address. Then this physical address can be used to
 	 * program hardware registers. */
-	(*handle)->physaddx = virt_to_bus((*handle)->virtaddx);
-	(*handle)->order    = order;
-
-	return CTSTATUS_SUCCESS;
-}
-
-int osFreeMemPhysical(struct memhandle **handle)
-{
-	if (*handle == NULL)
-		return CTSTATUS_ERROR;
-
-	free_pages((unsigned long) (*handle)->virtaddx, (*handle)->order);
-	kfree((void*) *handle);
-
-	DPD(3, "free_pages: [%p]\n", (*handle)->virtaddx);
-	DPD(3, "kfree: [%p]\n", *handle);
-
-	*handle = NULL;
-	return CTSTATUS_SUCCESS;
-}
-
-
-int osListAttach(struct sblive_list **head, struct sblive_list *n)
-{
-	unsigned long flags;
+	handle->busaddx = virt_to_bus(handle->virtaddx);
+	handle->order = order;
 
-	if (head == NULL)
-		return CTSTATUS_ERROR;
+	DPD(3, "__get_free_pages: [%p] %lx\n", handle->virtaddx, handle->busaddx);
 
-	spin_lock_irqsave(&sblive_spinlock, flags);
-
-	n->next = NULL;
-
-	if (*head != NULL)
-	{
-		struct sblive_list *t = *head;
-
-		while (t->next != NULL)
-			t = t->next;
-		t->next = n;
-	} else
-		*head = n;
-
-	spin_unlock_irqrestore(&sblive_spinlock, flags);
-
-	return CTSTATUS_SUCCESS;
+	return handle;
 }
 
-
-int osListRemove(struct sblive_list **head, struct sblive_list *dead)
+void emu10k1_free_memphysical(struct memhandle *handle)
 {
-	u32 status = CTSTATUS_SUCCESS;
-	unsigned long flags;
-
-	if (head == NULL)
-		return CTSTATUS_ERROR;
-
-	spin_lock_irqsave(&sblive_spinlock, flags);
-
-	if (*head != dead)
-	{
-		struct sblive_list *t = *head;
+	free_pages((unsigned long) handle->virtaddx, handle->order);
+	kfree(handle);
 
-		while (t != NULL && t->next != dead)
-			t = t->next;
+	DPD(3, "free_pages: [%p]\n", handle->virtaddx);
+	DPD(3, "kfree: [%p]\n", handle);
 
-		if (t != NULL)
-		{
-			t->next = dead->next;
-			dead->next = NULL;
-		} else
-			status = CTSTATUS_ERROR;
-	} else
-		*head = dead->next;
-
-	spin_unlock_irqrestore(&sblive_spinlock, flags);
-
-	return status;
-}
-
-
-struct sblive_list *osListGetNext(struct sblive_list *head, struct sblive_list *curr)
-{
-	if (curr == NULL)
-		return head;
-
-	return curr->next;
+	return;
 }
-
Index: oldkernel/linux/drivers/sound/emu10k1/recmgr.c
diff -u linux/drivers/sound/emu10k1/recmgr.c:1.1 linux/drivers/sound/emu10k1/recmgr.c:1.2
--- linux/drivers/sound/emu10k1/recmgr.c:1.1	Thu Jun  1 16:52:15 2000
+++ linux/drivers/sound/emu10k1/recmgr.c	Fri Jul  7 15:36:45 2000
@@ -1,3 +1,4 @@
+
 /*
  **********************************************************************
  *     recmgr.c -- Recording manager for emu10k1 driver
@@ -32,154 +33,107 @@
 #include "hwaccess.h"
 #include "recmgr.h"
 
-/****************************************************************************/
-/**  Function: recmgrInit                                                  **/
-/**                                                                        **/
-/**  Input   : rec_ptr - pointer recording object                          **/
-/**                                                                        **/
-/**  About   : stop recording when init                                    **/
-/****************************************************************************/
-int recmgrInit(struct record *rec_ptr)
+void emu10k1_start_record(struct record *rec_ptr)
 {
-	struct sblive_hw *hw_ptr = rec_ptr->sb_hw;
+	struct emu10k1_card *hw_ptr = rec_ptr->card;
 
-	/* Disable record transfer */
-	sblive_writeptr(hw_ptr, ADCBS, 0, ADCBS_BUFSIZE_NONE);
-	sblive_writeptr(hw_ptr, ADCCR, 0, 0);
+	DPF(2, "emu10k1_start_record()\n");
+	DPD(2, "bus addx: %lx\n", rec_ptr->busaddx);
 
-	return CTSTATUS_SUCCESS;
-}
+	sblive_writeptr(hw_ptr, rec_ptr->bufaddrreg, 0, rec_ptr->busaddx);
+	sblive_writeptr(hw_ptr, rec_ptr->bufsizereg, 0, rec_ptr->bufsize);
 
+	if (rec_ptr->adcctl)
+		sblive_writeptr(hw_ptr, ADCCR, 0, rec_ptr->adcctl);
 
-/****************************************************************************/
-/**  Function: recmgrStartRecord                                           **/
-/**                                                                        **/
-/**  Input   : rec_ptr - pointer recording object                          **/
-/**                                                                        **/
-/**  About   : start recording                                             **/
-/****************************************************************************/
-int recmgrStartRecord(struct record *rec_ptr)
-{
-	struct sblive_hw *hw_ptr = rec_ptr->sb_hw;
-	u32 adcsr;
-
-
-#ifdef RECTEST
-	DPD(2, " data in 0x120 -> %x\n", sblive_readptr(hw_ptr, FXGPREGBASE + 0x20, 0));
-	DPD(2, " data in 0x121 -> %x\n", sblive_readptr(hw_ptr, FXGPREGBASE + 0x21, 0));
-#endif
-
-	DPD(2, "recmgrStartRecord: base addx: %x\n", rec_ptr->physaddx >> 12);
-	sblive_writeptr(hw_ptr, ADCBA, 0, rec_ptr->physaddx);
-
-	switch (rec_ptr->samplingrate) 
-	{
-	case 0xBB80: adcsr = ADCCR_SAMPLERATE_48; break;
-	case 0xAC44: adcsr = ADCCR_SAMPLERATE_44; break;
-	case 0x7D00: adcsr = ADCCR_SAMPLERATE_32; break;
-	case 0x5DC0: adcsr = ADCCR_SAMPLERATE_24; break;
-	case 0x5622: adcsr = ADCCR_SAMPLERATE_22; break;
-	case 0x3E80: adcsr = ADCCR_SAMPLERATE_16; break;
-	case 0x2B11: adcsr = ADCCR_SAMPLERATE_11; break;
-	case 0x1F40: adcsr = ADCCR_SAMPLERATE_8; break;
-	default:
-		DPF(2, "Unknown sampling rate!\n");
-		return CTSTATUS_ERROR;
-	}
-
-	adcsr |= ADCCR_LCHANENABLE;
-
-	if (rec_ptr->is_stereo)
-	  adcsr |= ADCCR_RCHANENABLE;
-
-	sblive_writeptr(hw_ptr, ADCCR, 0, adcsr);
-	sblive_writeptr(hw_ptr, ADCBS, 0, rec_ptr->bufsizereg);
-
-	return CTSTATUS_SUCCESS;
+	return;
 }
-
 
-/****************************************************************************/
-/**  Function: recmgrStopRecord                                            **/
-/**                                                                        **/
-/**  Input   : rec_ptr - pointer recording object                          **/
-/**                                                                        **/
-/**  About   : stop recording                                              **/
-/****************************************************************************/
-int recmgrStopRecord(struct record *rec_ptr)
+void emu10k1_stop_record(struct record *rec_ptr)
 {
-	struct sblive_hw *hw_ptr = rec_ptr->sb_hw;
+	struct emu10k1_card *hw_ptr = rec_ptr->card;
 
-	/* Disable record transfer */
-	sblive_writeptr(hw_ptr, ADCBS, 0, ADCBS_BUFSIZE_NONE);
-	sblive_writeptr(hw_ptr, ADCCR, 0, 0);
+	DPF(2, "emu10k1_stop_record()\n");
 
-	return CTSTATUS_SUCCESS;
-}
+	/* Disable record transfer */
+	if (rec_ptr->adcctl)
+		sblive_writeptr(hw_ptr, ADCCR, 0, 0);
 
+	sblive_writeptr(hw_ptr, rec_ptr->bufsizereg, 0, ADCBS_BUFSIZE_NONE);
 
-/****************************************************************************/
-/**  Function: recmgrSetControl                                            **/
-/**                                                                        **/
-/**  Input   : rec_ptr - pointer recording object                          **/
-/**            controlid - control ID                                      **/
-/**            value - value to set for a specified control                **/
-/**                                                                        **/
-/**  About   : set recording resource                                      **/
-/**                                                                        **/
-/**  Note    :                                                             **/
-/**                                                                        **/
-/**  XD, DMA, WR and RIGHT bits in CCCA register controls the way to       **/
-/**  record for 8005.                                                      **/
-/**                                                                        **/
-/**  XD   DMA    WR    RIGHT                                               **/
-/**  1     1     0      0      --- record from external(AC97, SPDIF, MIC)  **/
-/**  1     1     1      0      --- record from the output of Emu8000       **/
-/**                                effects engine.                         **/
-/**                                                                        **/
-/****************************************************************************/
-int recmgrSetControl(struct record *rec_ptr, u32 controlid, u32 value)
-{
-	/* FIXME: Implement me! */
-	return CTSTATUS_SUCCESS;
+	return;
 }
 
-
-/****************************************************************************/
-/**  Function: recmgrGetPos                                                **/
-/**                                                                        **/
-/**  Input   : rec_ptr - pointer recording object                          **/
-/**            pos -  pointer to position returned                         **/
-/**                                                                        **/
-/**  About   : get recording position(no. of bytes per channel)            **/
-/**                                                                        **/
-/**  Formula : (WC*SamplingRate/48kHz)%(record buffer size)                **/
-/****************************************************************************/
-int recmgrGetPos(struct record *rec_ptr, u32 *pos)
+void emu10k1_set_record_src(struct record *rec_ptr, u8 recsrc)
 {
-	struct sblive_hw *hw_ptr = rec_ptr->sb_hw;
-
-	u32 curidx;
-
-	curidx = recmgrGetRecIdx(hw_ptr);
-	if (curidx >= rec_ptr->prevadcidx)
-	  *pos = curidx - rec_ptr->prevadcidx;
-	else
-	  *pos = 0xfffff - (rec_ptr->prevadcidx - curidx);
+	DPF(2, "emu10k1_set_record_src()\n");
 
-	*pos = (*pos) * ((u16) rec_ptr->samplingrate) / 48000
-	  * 2 * (rec_ptr->is_stereo + 1);
+	switch (recsrc) {
 
-	DPD(2, " Recmgr: *pos: %x\n", *pos);
-	
-	if (rec_ptr->pong) 
-	  *pos += rec_ptr->recbufsize / 2;
-
-	return CTSTATUS_SUCCESS;
-}
-
+	case WAVERECORD_AC97:
+		DPF(2, "recording source: AC97\n");
+		rec_ptr->bufsizereg = ADCBS;
+		rec_ptr->bufaddrreg = ADCBA;
+		rec_ptr->bufidxreg = ADCIDX_IDX;
+
+		switch (rec_ptr->samplingrate) {
+		case 0xBB80:
+			rec_ptr->adcctl = ADCCR_SAMPLERATE_48;
+			break;
+		case 0xAC44:
+			rec_ptr->adcctl = ADCCR_SAMPLERATE_44;
+			break;
+		case 0x7D00:
+			rec_ptr->adcctl = ADCCR_SAMPLERATE_32;
+			break;
+		case 0x5DC0:
+			rec_ptr->adcctl = ADCCR_SAMPLERATE_24;
+			break;
+		case 0x5622:
+			rec_ptr->adcctl = ADCCR_SAMPLERATE_22;
+			break;
+		case 0x3E80:
+			rec_ptr->adcctl = ADCCR_SAMPLERATE_16;
+			break;
+		case 0x2B11:
+			rec_ptr->adcctl = ADCCR_SAMPLERATE_11;
+			break;
+		case 0x1F40:
+			rec_ptr->adcctl = ADCCR_SAMPLERATE_8;
+			break;
+		default:
+			break;
+		}
+
+		rec_ptr->adcctl |= ADCCR_LCHANENABLE;
+
+		if (rec_ptr->is_stereo)
+			rec_ptr->adcctl |= ADCCR_RCHANENABLE;
+
+		//      rec_ptr->fxwc = 0;
+
+		break;
+
+	case WAVERECORD_MIC:
+		DPF(2, "recording source: MIC\n");
+		rec_ptr->bufsizereg = MICBS;
+		rec_ptr->bufaddrreg = MICBA;
+		rec_ptr->bufidxreg = MICIDX_IDX;
+		rec_ptr->adcctl = 0;
+		//      rec_ptr->fxwc = 0;
+		break;
+
+	case WAVERECORD_FX:
+		DPF(2, "recording source: FX\n");
+		rec_ptr->bufsizereg = FXBS;
+		rec_ptr->bufaddrreg = FXBA;
+		rec_ptr->bufidxreg = FXIDX_IDX;
+		rec_ptr->adcctl = 0;
+		//      rec_ptr->fxwc = 0x000ffff;
+		break;
+	default:
+		break;
+	}
 
-u32 recmgrGetRecIdx(struct sblive_hw *sb_hw)
-{
-	return READ_FN0(sb_hw, WC_SAMPLECOUNTER);
+	return;
 }
Index: oldkernel/linux/drivers/sound/emu10k1/recmgr.h
diff -u linux/drivers/sound/emu10k1/recmgr.h:1.1 linux/drivers/sound/emu10k1/recmgr.h:1.2
--- linux/drivers/sound/emu10k1/recmgr.h:1.1	Thu Jun  1 16:52:15 2000
+++ linux/drivers/sound/emu10k1/recmgr.h	Fri Jul  7 15:36:45 2000
@@ -34,32 +34,29 @@
 
 struct record 
 {
-	void *reserved;
-	struct sblive_hw *sb_hw;
+	struct emu10k1_card *card;
+	u8 *recbuffer;
 	u32 recpos;
+	int is_stereo;
+	int is_16bit;
 	u32 recbufsize;
+	u32 bufsize;
 	u32 bufsizereg;
-	u8 *recbuffer;
-	u32 physaddx;
+	u32 bufaddrreg;
+	u32 bufidxreg;
+	u32 adcctl;
+	unsigned long busaddx;
 	u32 samplingrate;
-	int is_stereo;
-	int is16bit;
-	int fSetRecSrc;
-	u32 recsrc;
-	u32 prevadcidx;
-	int pong;
 };
 
 /* Recording resources */
-#define WAVERECORD_AC97        0x00000001
-#define WAVERECORD_E8K         0x00000002
+#define WAVERECORD_AC97		0x01
+#define WAVERECORD_MIC		0x02
+#define WAVERECORD_FX		0x03
 
-int recmgrInit(struct record *);
-int recmgrStartRecord(struct record *);
-int recmgrStopRecord(struct record *);
-int recmgrSetControl(struct record *, u32, u32);
-int recmgrGetPos(struct record *, u32 *);
-u32 recmgrGetRecIdx(struct sblive_hw *);
+void emu10k1_start_record(struct record *);
+void emu10k1_stop_record(struct record *);
+void emu10k1_set_record_src(struct record *, u8);
 
 
 #endif /* _RECORDMGR_H */
Index: oldkernel/linux/drivers/sound/emu10k1/timer.c
diff -u linux/drivers/sound/emu10k1/timer.c:1.1 linux/drivers/sound/emu10k1/timer.c:1.2
--- linux/drivers/sound/emu10k1/timer.c:1.1	Thu Jun  1 16:52:15 2000
+++ linux/drivers/sound/emu10k1/timer.c	Fri Jul  7 15:36:45 2000
@@ -1,3 +1,4 @@
+
 /*
  **********************************************************************
  *     timer.c
@@ -23,143 +24,153 @@
  **********************************************************************
  */
 
+/* 3/6/2000	Improved support for different timer delays  Rui Sousa */
+
+/* 4/3/2000	Implemented timer list using list.h 	     Rui Sousa */
+
 #include "hwaccess.h"
 
-int sblive_timerIrqCallback(struct sblive_hw *sb_hw)
+/* Try to schedule only once per fragment */
+
+void emu10k1_timer_irqhandler(struct emu10k1_card *card)
 {
-	struct emu_timer *timer;
+	struct emu_timer *t;
+	struct list_head *entry;
+
+	spin_lock(&card->timer_lock);
 
-	spin_lock(&sb_hw->timer_lock);
+	list_for_each(entry, &card->timers) {
+		t = list_entry(entry, struct emu_timer, list);
 
-	timer = sb_hw->timer;
-	while (timer != NULL)
-	{
-		queue_task(timer->task, &tq_immediate);
-		mark_bh(IMMEDIATE_BH);
-		timer = timer->next;
+		if (t->active) {
+			t->count++;
+			if (t->count == t->count_max) {
+				t->count = 0;
+				tasklet_hi_schedule(&t->tasklet);
+			}
+		}
 	}
 
-	spin_unlock(&sb_hw->timer_lock);
+	spin_unlock(&card->timer_lock);
 
-	return CTSTATUS_SUCCESS;
+	return;
 }
 
-int sblive_timerinstall(struct sblive_hw *sb_hw, struct emu_timer **timer, struct tq_struct *task, unsigned delay)
+struct emu_timer *emu10k1_timer_install(struct emu10k1_card *card, void (*func) (unsigned long), unsigned long data, u32 delay)
 {
+	struct emu_timer *timer;
 	struct emu_timer *t;
+	struct list_head *entry;
 	unsigned long flags;
 
-	t = (struct emu_timer *) kmalloc(sizeof(struct emu_timer), GFP_KERNEL);
-	if (t == NULL)
-	{
-		DPF(2, "timer alloc failed\n");
-		return CTSTATUS_NOMEMORY;
-	}
+	if ((timer = (struct emu_timer *) kmalloc(sizeof(struct emu_timer), GFP_KERNEL)) == NULL)
+		return timer;
 
-	DPD(3, "kmalloc: [%p]\n", t);
+	if (delay < 5)
+		delay = 5;
 
-	if(delay < 1 )
-		delay = 1;
-	else if (delay >= 1024)
-		delay = 1023;
-
-	t->delay = delay;
-	t->task = task;
-
-	*timer = t;
-
-	spin_lock_irqsave(&sb_hw->timer_lock, flags);
-
-	if(sb_hw->timer == NULL)
-	{
-		sb_hw->timer = *timer;
-		sb_hw->timer->next = NULL;
-		sb_hw->timer_delay = delay;
-		WRITE_FN0(sb_hw, TIMR_RATE, delay);
-		sblive_irqmgrEnableIrq(sb_hw, INTE_INTERVALTIMERENB);
-	}
-	else
-	{
-		t = sb_hw->timer;
-		sb_hw->timer = *timer;
-		sb_hw->timer->next = t;
-		if (delay < sb_hw->timer_delay)
-		{
-			sb_hw->timer_delay = delay;
-			WRITE_FN0(sb_hw, TIMR_RATE, delay);
+	timer->delay = delay;
+	tasklet_init(&timer->tasklet, func, data);
+	timer->active = 0;
+
+	spin_lock_irqsave(&card->timer_lock, flags);
+
+	timer->count_max = timer->delay / (card->timer_delay < 1024 ? card->timer_delay : 1024);
+	timer->count = timer->count_max - 1;
+
+	list_add(&timer->list, &card->timers);
+
+	if (card->timer_delay > delay) {
+		if (card->timer_delay == TIMER_STOPPED)
+			emu10k1_irq_enable(card, INTE_INTERVALTIMERENB);
+
+		card->timer_delay = delay;
+		delay = (delay < 1024 ? delay : 1024);
+
+		WRITE_FN0(card, TIMER_RATE, delay);
+
+		list_for_each(entry, &card->timers) {
+			t = list_entry(entry, struct emu_timer, list);
+
+			t->count_max = t->delay / delay;
+			/* don't want to think much, just force scheduling 
+			   on the next interrupt */
+			t->count = t->count_max - 1;
 		}
-	}
 
-	spin_unlock_irqrestore(&sb_hw->timer_lock, flags);
+		DPD(2, "timer rate --> %u\n", delay);
+	}
 
-	DPD(2, "timer rate --> %d\n", sb_hw->timer_delay);
+	spin_unlock_irqrestore(&card->timer_lock, flags);
 
-	return CTSTATUS_SUCCESS;
+	return timer;
 }
 
-int sblive_timeruninstall(struct sblive_hw *sb_hw, struct emu_timer *timer)
+void emu10k1_timer_uninstall(struct emu10k1_card *card, struct emu_timer *timer)
 {
 	struct emu_timer *t;
-	unsigned delay;
+	struct list_head *entry;
+	u32 delay = TIMER_STOPPED;
 	unsigned long flags;
 
-	spin_lock_irqsave(&sb_hw->timer_lock, flags);
+	spin_lock_irqsave(&card->timer_lock, flags);
 
-	t = sb_hw->timer;
+	list_del(&timer->list);
 
-	if( t == NULL){
-		spin_unlock_irqrestore(&sb_hw->timer_lock, flags);
-		return CTSTATUS_SUCCESS;
+	list_for_each(entry, &card->timers) {
+		t = list_entry(entry, struct emu_timer, list);
+
+		if (t->delay < delay)
+			delay = t->delay;
 	}
 
-	delay = timer->delay;
+	if (card->timer_delay != delay) {
+		card->timer_delay = delay;
 
-	if(sb_hw->timer == timer)
-	{
-		sb_hw->timer = timer->next;
-	}
-	else
-	{
-		while(t->next != timer)
-			t = t->next;
+		if (delay == TIMER_STOPPED)
+			emu10k1_irq_disable(card, INTE_INTERVALTIMERENB);
+		else {
+			delay = (delay < 1024 ? delay : 1024);
 
-		t->next = timer->next;
-	}
+			WRITE_FN0(card, TIMER_RATE, delay);
 
-	kfree(timer);
+			list_for_each(entry, &card->timers) {
+				t = list_entry(entry, struct emu_timer, list);
 
-	DPD(3, "kfree: [%p]\n", timer);
+				t->count_max = t->delay / delay;
+				t->count = t->count_max - 1;
+			}
+		}
 
-	if(sb_hw->timer == NULL)
-	{
-		sblive_irqmgrDisableIrq(sb_hw, INTE_INTERVALTIMERENB);
+		DPD(2, "timer rate --> %u\n", delay);
 	}
-	else if (delay == sb_hw->timer_delay)
-	{
-		t = sb_hw->timer;
-		sb_hw->timer_delay = 1024;
-
-		while(t != NULL){
-
-			if(t->delay < sb_hw->timer_delay)
-				sb_hw->timer_delay = t->delay;
-			t = t->next;
-		}
 
-		WRITE_FN0(sb_hw, TIMR_RATE, sb_hw->timer_delay);
+	spin_unlock_irqrestore(&card->timer_lock, flags);
 
-		DPD(2, "timer rate --> %d\n", sb_hw->timer_delay);
-	}
+	tasklet_unlock_wait(&timer->tasklet);
+	kfree(timer);
 
-	spin_unlock_irqrestore(&sb_hw->timer_lock, flags);
+	return;
+}
 
-	return CTSTATUS_SUCCESS;
+void emu10k1_timer_enable(struct emu10k1_card *card, struct emu_timer *timer)
+{
+	unsigned long flags;
+
+	spin_lock_irqsave(&card->timer_lock, flags);
+	timer->active = 1;
+	spin_unlock_irqrestore(&card->timer_lock, flags);
+
+	return;
 }
 
-int sblive_timerinit(struct sblive_hw *sb_hw)
+void emu10k1_timer_disable(struct emu10k1_card *card, struct emu_timer *timer)
 {
-	sb_hw->timer = NULL;
-	sb_hw->timer_lock = SPIN_LOCK_UNLOCKED;
+	unsigned long flags;
+
+	spin_lock_irqsave(&card->timer_lock, flags);
+	timer->active = 0;
+	spin_unlock_irqrestore(&card->timer_lock, flags);
 
-	return CTSTATUS_SUCCESS;
+	return;
 }
Index: oldkernel/linux/drivers/sound/emu10k1/timer.h
diff -u linux/drivers/sound/emu10k1/timer.h:1.1 linux/drivers/sound/emu10k1/timer.h:1.2
--- linux/drivers/sound/emu10k1/timer.h:1.1	Thu Jun  1 16:52:15 2000
+++ linux/drivers/sound/emu10k1/timer.h	Fri Jul  7 15:36:45 2000
@@ -29,13 +29,19 @@
 
 struct emu_timer 
 {
-	struct emu_timer *next;
-	struct tq_struct *task;
-	unsigned delay;
+	struct list_head list;
+	struct tasklet_struct tasklet;
+	int active;
+	u32 count;				/* current number of interrupts */
+	u32 count_max;				/* number of interrupts needed to schedule the bh */
+	u32 delay;                              /* timer delay */
 };
 
-int sblive_timerinstall(struct sblive_hw *, struct emu_timer **, struct tq_struct *, unsigned);
-int sblive_timeruninstall(struct sblive_hw *, struct emu_timer *);
-int sblive_timerinit(struct sblive_hw *);
+struct emu_timer *emu10k1_timer_install(struct emu10k1_card *, void (*)(unsigned long), unsigned long, u32);
+void emu10k1_timer_uninstall(struct emu10k1_card *, struct emu_timer *);
+void emu10k1_timer_enable(struct emu10k1_card *, struct emu_timer *);
+void emu10k1_timer_disable(struct emu10k1_card *, struct emu_timer *);
+
+#define TIMER_STOPPED 0xffffffff 
 
 #endif /* _TIMER_H */
Index: oldkernel/linux/drivers/sound/emu10k1/voicemgr.c
diff -u linux/drivers/sound/emu10k1/voicemgr.c:1.1 linux/drivers/sound/emu10k1/voicemgr.c:1.2
--- linux/drivers/sound/emu10k1/voicemgr.c:1.1	Thu Jun  1 16:52:15 2000
+++ linux/drivers/sound/emu10k1/voicemgr.c	Fri Jul  7 15:36:45 2000
@@ -1,6 +1,7 @@
+
 /*
  **********************************************************************
- *     sblive_voice.c - Voice manager for emu10k1 driver
+ *     voicemgr.c - Voice manager for emu10k1 driver
  *     Copyright 1999, 2000 Creative Labs, Inc.
  *
  **********************************************************************
@@ -29,965 +30,320 @@
  **********************************************************************
  */
 
-
 #include "hwaccess.h"
 
-/************************************************************************
- *
- *   static struct emu_voice * sblive_emuVoiceAlloc(struct sblive_hw *sb_hw, u32 flags)
- *
- *   ENTRY
- *       sb_hw -    Pointer to the HWOBJ to allocate voice from
- *       flags -    flags from struct voice_allocdesc from the ICardxxx
- *                  object that called sblive_voiceAlloc
- *
- *   RETURNS
- *       SUCCESS -   Pointer to a struct emu_voice
- *       FAILURE -   NULL
- *
- *   ABOUT
- *       This is a static funciton that searches for free emuvoices
- *       and tries to return the type needed according to flags
- *
- ************************************************************************/
-static struct emu_voice *sblive_emuVoiceAlloc(struct voice_mgr *voice, u32 flags)
+struct emu_voice *emu10k1_voice_alloc(struct voice_manager *voicemgr, struct voice_allocdesc *voiceallocdesc)
 {
-	unsigned int voicenum;
-	struct sblive_hw *sb_hw = voice->sb_hw;
-	struct emu_voice *foundvoice = NULL;
-	struct emu_voice *slavevoice = NULL;
-	struct emu_voice *testvoice, *testslave;
-	u32 curvol, lowestvol, mastervol, slavevol, CA, dcysusv;
-
-	DPF(2, "Entered sblive_emuVoiceAlloc\n");
-
-	if (flags & VOICEMGR_FLAGS_MONO)
-	{
-		DPF(2, "sblive_emuVoiceAlloc MONO PLAYBACK voicei\n");
-
-		/* Check for free voices first */
-		if (voice->free_voices)
-		{
-			voice->free_voices->voicestate = VOICEMGR_STATE_TRANSITION;
-			foundvoice = voice->free_voices;
-			foundvoice->flags = 0;
-			DPD(2, "  Voice found %d\n", foundvoice->voicenum);
-			return foundvoice;
-		}
-
-		/* We couldn't find any free voices so we need to free up
-		 * some voices. We only rip off MIDI voices at the moment. */
-		testvoice = dlFirstNode(&voice->midi_voices);
-
-		lowestvol = 0xffffffff;
-
-		while (testvoice)
-		{
-			/* Voice stealing algorithm goes here */
-			voicenum = testvoice->voicenum;
-
-			if (!(testvoice->voicestate & VOICEMGR_STATE_TRANSITION))
-			{
-				/* Check if voice is looping silence */
-				CA = sblive_readptr(sb_hw, CCCA_CURRADDR, voicenum);
-				if (CA > testvoice->voice_params.end)
-				{
-					testvoice->voicestate |= VOICEMGR_STATE_TRANSITION;
-					if (foundvoice)
-						foundvoice->voicestate &= ~VOICEMGR_STATE_TRANSITION;
-					lowestvol = 0;
-					foundvoice = testvoice;
-					break;
-				}
-
-				curvol = sblive_readptr(sb_hw, CVCF_CURRENTVOL, voicenum);
-				dcysusv = sblive_readptr(sb_hw, DCYSUSV, voicenum);
-				dcysusv = (dcysusv & DCYSUSV_PHASE1_MASK) ? 0 : 0x1000; /* 0x1000 means what? */
-
-				if ((curvol < 0x200) && !dcysusv && (testvoice->voicestate & VOICEMGR_STATE_RELEASE))
-				{
-					/* The volume is less than the threshold and
-					 the volume envelope is in the decaying state.
-					 Stop the pitch to stop the busmaster activities.
-					 */
-					sblive_writeptr(sb_hw, IP, voicenum, 0);
-					sblive_writeptr(sb_hw, VTFT, voicenum, VTFT_FILTERTARGET_MASK);
-					sblive_writeptr(sb_hw, PTRX_PITCHTARGET, voicenum, 0);
-				} else
-				{
-					if (testvoice->voicestate & VOICEMGR_STATE_SUSTAIN)
-						curvol += 0x500 + dcysusv;
-					else if (testvoice->voicestate & VOICEMGR_STATE_ATTACK)
-						curvol += 0x200 + dcysusv;
-				}
-
-				if (curvol < lowestvol)
-				{
-					testvoice->voicestate |= VOICEMGR_STATE_TRANSITION;
-
-					if (foundvoice)
-						foundvoice->voicestate &= ~VOICEMGR_STATE_TRANSITION;
-					foundvoice = testvoice;
-					lowestvol = curvol;
-				}
-			}
-			testvoice = dlNextNode(testvoice);
-		}
-
-		if (foundvoice)
-		{
-			if (foundvoice->callback)
-			{
-				/* Note that this function can change the voice suggested to another voice */
-				if (foundvoice->callback(VOICECALLBACK_EVENT_FREEVOICE, foundvoice->callback_data, (u32)&foundvoice)
-				    != CTSTATUS_SUCCESS)
-				{
-					DPF(2, "Found voide callback failed\n");
-					foundvoice = NULL;
-				}
-			}
-
-			foundvoice->flags = 0;
-			foundvoice->master_voice = NULL;
-			foundvoice->linked_voice = NULL;
-		} else
-		{
-			DPF(2, "Voice not found!\n");
-		}
-
-		return foundvoice;
-	} else
-	{
-		DPF(2, "sblive_emuVoiceAlloc STEREO PLAYBACK voice\n");
-
-		voicenum = 8;
-		lowestvol = 0xffffffff;
-
-		do
-		{
-			/* Since stereo voices must be side-by-side,
-			 we have to check 2 voices at once. */
-			if (((voice->voices[voicenum].usage == VOICEMGR_USAGE_FREE)
-			     || (voice->voices[voicenum].usage == VOICEMGR_USAGE_MIDI))
-			    && ((voice->voices[voicenum + 1].usage == VOICEMGR_USAGE_FREE)
-				|| (voice->voices[voicenum + 1].usage == VOICEMGR_USAGE_MIDI)))
-			{
-				mastervol = 0xffffffff;
-				slavevol = 0xffffffff;
-				testvoice = &voice->voices[voicenum];
-				testslave = &voice->voices[voicenum + 1];
-
-				if ((!(testvoice->voicestate & VOICEMGR_STATE_TRANSITION))
-				    && (!(testslave->voicestate & VOICEMGR_STATE_TRANSITION)))
-				{
-					/* Voice stealing algorithm goes here */
-
-					/* Check master voice */
-					if (testvoice->usage == VOICEMGR_USAGE_FREE)
-						mastervol = 0;
-					else
-					{
-						/* Check if voice is looping silence */
-						CA = sblive_readptr(sb_hw, CCCA_CURRADDR, voicenum);
-
-						if (CA > testvoice->voice_params.end)
-							mastervol = 0;
-						else
-						{
-							mastervol = sblive_readptr(sb_hw, CVCF_CURRENTVOL, voicenum);
-							if (!(testvoice->voicestate & VOICEMGR_STATE_RELEASE))
-								mastervol += 0x1300; /* Why??? */
-						}
-					}
-
-					/* Check slave voice */
-					if (testslave->usage == VOICEMGR_USAGE_FREE)
-						slavevol = 0;
-					else
-					{
-						/* Check if voice is looping silence */
-						CA = sblive_readptr(sb_hw, CCCA_CURRADDR, voicenum + 1);
-
-						if (CA > testslave->voice_params.end)
-							slavevol = 0;
-						else
-						{
-							slavevol = sblive_readptr(sb_hw, CVCF_CURRENTVOL, (voicenum + 1));
-							if (!(testslave->voicestate & VOICEMGR_STATE_RELEASE))
-								slavevol += 0x1300; /* Why??? */
-						}
-					}
-
-					if ((mastervol + slavevol) < lowestvol)
-					{
-						testvoice->voicestate |= VOICEMGR_STATE_TRANSITION;
-						testslave->voicestate |= VOICEMGR_STATE_TRANSITION;
-
-						if (foundvoice)
-						{
-							foundvoice->voicestate &= ~VOICEMGR_STATE_TRANSITION;
-							slavevoice->voicestate &= ~VOICEMGR_STATE_TRANSITION;
-						}
-
-						foundvoice = testvoice;
-						slavevoice = testslave;
-						lowestvol = mastervol + slavevol;
-					}
-				}
-			}
+	struct emu10k1_card *card = voicemgr->card;
+	struct emu_voice *voice_tmp = voicemgr->voice;
+	struct emu_voice *voice = NULL;
+	int i;
+	unsigned long flags;
 
-			voicenum = (voicenum + 2) % NUM_G;
+	DPF(2, "emu10k1_voice_alloc()\n");
 
-		} while (voicenum != 8);
+	spin_lock_irqsave(&voicemgr->lock, flags);
 
-		if (foundvoice)
-		{
-			if (foundvoice->callback)
-			{
-				/* Note that this function can change the voice suggested to another voice */
-				if (foundvoice->callback(VOICECALLBACK_EVENT_FREEVOICE, foundvoice->callback_data, (u32)&foundvoice)
-				    != CTSTATUS_SUCCESS)
-				{
-					DPF(2, "Voice callback failed\n");
-				}
+	if (voiceallocdesc->flags & VOICEMGR_FLAGS_MONO) {
+		for (i = 0; i < NUM_G; i++)
+			if (voice_tmp[i].usage == VOICEMGR_USAGE_FREE) {
+				voice_tmp[i].flags = VOICEMGR_FLAGS_VOICEMASTER | voiceallocdesc->flags;
+				voice_tmp[i].usage = voiceallocdesc->usage;
+				voice = &voice_tmp[i];
+				break;
 			}
-
-			if (slavevoice->callback)
-			{
-				/* Note that this function can change the voice suggested to another voice */
-				testvoice = slavevoice;
-				if (testvoice->callback(VOICECALLBACK_EVENT_FREEVOICE, testvoice->callback_data, (u32)&testvoice)
-				    != CTSTATUS_SUCCESS)
-				{
-					DPF(2, "Voice callback failed\n");
-				}
-
-				if (testvoice != slavevoice)
-				{
-					DPF(2, "testvoice != slavevoice\n");
-					return NULL;
-				}
+	} else {
+		for (i = 0; i < NUM_G; i += 2)
+			if ((voice_tmp[i].usage == VOICEMGR_USAGE_FREE)
+			    && (voice_tmp[i + 1].usage == VOICEMGR_USAGE_FREE)) {
+				voice_tmp[i].linked_voice = &voice_tmp[i + 1];
+				voice_tmp[i].flags = VOICEMGR_FLAGS_VOICEMASTER | voiceallocdesc->flags;
+				voice_tmp[i].usage = voiceallocdesc->usage;
+				voice_tmp[i + 1].flags = VOICEMGR_FLAGS_STEREOSLAVE | voiceallocdesc->flags;
+				voice_tmp[i + 1].usage = voiceallocdesc->usage;
+				voice = &voice_tmp[i];
+				break;
 			}
-
-			DPD(2, "Voice found %x\n", (u32)voicenum);
-
-			/* Link next voice in stereo pair */
-			foundvoice->master_voice = NULL;
-			foundvoice->linked_voice = slavevoice;
-			slavevoice->master_voice = foundvoice;
-			slavevoice->linked_voice = NULL;
-
-			/* Mark second voice as stereo slave */
-			foundvoice->flags = VOICEMGR_FLAGS_VOICEMASTER;
-			slavevoice->flags = VOICEMGR_FLAGS_STEREOSLAVE;
-
-			return foundvoice;
-		}
 	}
 
-	return foundvoice;
-}
+	spin_unlock_irqrestore(&voicemgr->lock, flags);
 
-/************************************************************************
- *
- *   int sblive_voiceInit(struct sblive_hw *sb_hw)
- *
- *   ENTRY
- *       card  -    Pointer to the card obj to init voice manager
- *
- *   RETURNS
- *       Always returns CTSTATUS_SUCCESS
- *
- *   ABOUT
- *       Inits data
- *
- ************************************************************************/
-int sblive_voiceInit(struct sblive_hw *sb_hw)
-{
-	struct voice_mgr *voice;
-	struct emu_voice *emu_voice;
-	int i;
-
-	voice = &sb_hw->voice_manager;
-	voice->free_voices = NULL;
-
-	emu_voice = voice->voices;
-	for (i = 0; i < NUM_G; i++)
-	{
-		unsigned long flags;
+	voice_tmp = voice;
 
-		emu_voice->sb_hw = sb_hw;
-		emu_voice->usage = VOICEMGR_USAGE_FREE;
-		emu_voice->voicestate = VOICEMGR_STATE_IDLE;
-		emu_voice->voicenum = i;
-		emu_voice->linked_voice = NULL;
+	while (voice_tmp != NULL) {
 
-		spin_lock_irqsave(&sblive_spinlock, flags);
+		DPD(2, " voice allocated -> %d\n", voice_tmp->num);
 
-		dlAddNode(&voice->free_voices, emu_voice);
+		sblive_writeptr(card, IFATN, voice_tmp->num, 0xffff);
+		sblive_writeptr(card, DCYSUSV, voice_tmp->num, ENV_OFF);
+		sblive_writeptr(card, VTFT, voice_tmp->num, 0xffff);
+		sblive_writeptr(card, PTRX, voice_tmp->num, 0);
 
-		spin_unlock_irqrestore(&sblive_spinlock, flags);
-
-		++emu_voice;
+		voice_tmp = voice_tmp->linked_voice;
 	}
-
-	voice->sb_hw = sb_hw;
-	voice->playback_voices = NULL;
-	voice->record_voices = NULL;
-	voice->midi_voices = NULL;
 
-	return CTSTATUS_SUCCESS;
+	return voice;
 }
-
 
-/************************************************************************
- *
- *   int sblive_voiceExit(struct sblive_hw *sb_hw)
- *
- *   ENTRY
- *       sb_hw  -    Pointer to the HWOBJ to init voice manager
- *
- *   RETURNS
- *       Always returns CTSTATUS_SUCCESS
- *
- *   ABOUT
- *       Exits
- *
- ************************************************************************/
-int sblive_voiceExit(struct sblive_hw *sb_hw)
+void emu10k1_voice_free(struct voice_manager *voicemgr, struct emu_voice *voice)
 {
+	struct emu10k1_card *card = voice->card;
+	struct emu_voice *voice_tmp;
+	unsigned dcysusv;
+	u32 cra, sample;
 	int i;
-	struct emu_voice *emu_voice;
-
-	emu_voice = sb_hw->voice_manager.voices;
-	for (i = 0; i < NUM_G; i++)
-	{
-		/* TODO: CALL ALL RELEASE CALLBACKS FOR BUSY VOICES */
-
-		emu_voice->usage = VOICEMGR_USAGE_FREE;
-		emu_voice->voicestate = VOICEMGR_STATE_IDLE;
-		emu_voice->voicenum = i;
-		emu_voice->linked_voice = NULL;
-		++emu_voice;
-	}
-
-	sb_hw->voice_manager.sb_hw = NULL;
-	sb_hw->voice_manager.free_voices = NULL;
-	sb_hw->voice_manager.playback_voices = NULL;
-	sb_hw->voice_manager.record_voices = NULL;
-	sb_hw->voice_manager.midi_voices = NULL;
-
-	return CTSTATUS_SUCCESS;
-}
-
-
-/************************************************************************
- *
- *   int sblive_voiceAlloc(struct voice_allocdesc *voiceallocdesc,
- *                         struct emu_voice * *voices)
- *
- *   ENTRY
- *       voiceallocdesc   -
- *           Pointer to a struct voice_allocdesc that describes the
- *           voices needed.
- *
- *       voices        -
- *           Address to return allocated struct emu_voices
- *
- *   RETURNS
- *       SUCCESS -   CTSTATUS_SUCCESS
- *       FAILURE -   CTSTATUS_INUSE (not enough available voices)
- *                   CTSTATUS_ERROR
- *
- *   ABOUT
- *       Allocates voices according to the types requested.
- *
- ************************************************************************/
-int sblive_voiceAlloc(struct voice_allocdesc *voiceallocdesc, struct emu_voice **voices)
-{
-	struct emu_voice **ppOwnerList = NULL;	/* Linux: added initialization */
-	struct emu_voice *allocvoicelist;
-	struct emu_voice *lastvoice = NULL;	/* Linux: added initialization */
-	struct emu_voice *linkvoice;
-	int status = CTSTATUS_SUCCESS;
-	struct sblive_hw *sb_hw = voiceallocdesc->sb_hw;
 	unsigned long flags;
-	int i;
-
-	if (!voiceallocdesc->numvoicereqs)
-	{
-		/* No voices requested??? */
-		DPF(2, "No voices requested!\n");
-		return CTSTATUS_INVALIDPARAM;
-	}
-
-	/* Determine 'busy' list to attach voices to */
-	if (voiceallocdesc->ownertype == VOICEMGR_USAGE_PLAYBACK)
-		ppOwnerList = &sb_hw->voice_manager.playback_voices;
-	else if (voiceallocdesc->ownertype == VOICEMGR_USAGE_MIDI)
-		ppOwnerList = &sb_hw->voice_manager.midi_voices;
-
-	allocvoicelist = NULL;
-
-	/* Satisfy voice requests one by one */
-	for (i = 0; i < voiceallocdesc->numvoicereqs; i++)
-	{
-		/* Allocate voices */
-
-		linkvoice = sblive_emuVoiceAlloc(&sb_hw->voice_manager, voiceallocdesc->flags[i]);
 
-		if (linkvoice)
-		{
-			/* Suitable free voice found */
-			if (allocvoicelist == NULL)
-			{
-				allocvoicelist = linkvoice;
-				linkvoice->master_voice = NULL;
-			} else
-			{
-				lastvoice->linked_voice = linkvoice;
-				linkvoice->master_voice = lastvoice;
-			}
-
-			linkvoice->flags = VOICEMGR_FLAGS_VOICEMASTER;
-
-			/* Repeat for all linked voices */
-			while (linkvoice)
-			{
-				/* Shut off the voice */
-				sblive_writeptr(sb_hw, IFATN, linkvoice->voicenum, 0xffff);
-				sblive_writeptr(sb_hw, DCYSUSV , linkvoice->voicenum, ENV_OFF);
-				sblive_writeptr(sb_hw, VTFT, linkvoice->voicenum, 0xffff);
-				sblive_writeptr(sb_hw, PTRX, linkvoice->voicenum, 0);
-
-				spin_lock_irqsave(&sblive_spinlock, flags);
-
-				dlDelNode(&sb_hw->voice_manager.free_voices, linkvoice); /* Remove voice from free list */
+	DPF(2, "emu10k1_voice_free()\n");
 
-				linkvoice->sb_hw = sb_hw;
-				linkvoice->ownertype = voiceallocdesc->ownertype;
-				linkvoice->callback = voiceallocdesc->callback;
-				linkvoice->callback_data = voiceallocdesc->callback_data;
+	voice_tmp = voice;
 
-				/* We need a transition state to make a voice
-				 as belonging to a owner but not yet assigned
-				 to that owner yet */
-				linkvoice->voicestate |= VOICEMGR_STATE_TRANSITION;
-				linkvoice->usage = voiceallocdesc->ownertype;
-				linkvoice->flags |= voiceallocdesc->flags[i];
+	while (voice_tmp != NULL) {
 
-				dlAddNode(ppOwnerList, linkvoice); /* Attach voice to busy list */
+		DPD(2, " voice freed -> %d\n", voice_tmp->num);
 
-				spin_unlock_irqrestore(&sblive_spinlock, flags);
+		sblive_writeptr(card, IFATN, voice_tmp->num, IFATN_FILTERCUTOFF_MASK | IFATN_ATTENUATION_MASK);
+		sblive_writeptr(card, IP, voice_tmp->num, 0);
 
-				lastvoice = linkvoice; /* Remember last of linked voices */
+		dcysusv = sblive_readptr(card, DCYSUSV, voice_tmp->num) & (DCYSUSV_PHASE1_MASK | DCYSUSV_SUSTAINLEVEL_MASK | DCYSUSV_DECAYTIME_MASK);
+		sblive_writeptr(card, DCYSUSV, voice_tmp->num, dcysusv | ENV_OFF);
 
-				linkvoice = linkvoice->linked_voice;
-			}
-		} else
-		{
-			/* No free suitable voices found - steal from busy voices */
-			status = CTSTATUS_INUSE;
-
-			/* TODO : IMPLEMENT VOICE STEALING ALGORITHM */
+		sblive_writeptr(card, VTFT, voice_tmp->num, VTFT_FILTERTARGET_MASK);
+		sblive_writeptr(card, PTRX_PITCHTARGET, voice_tmp->num, 0);
+		sblive_writeptr(card, CVCF, voice_tmp->num, CVCF_CURRENTFILTER_MASK);
+		sblive_writeptr(card, CPF, voice_tmp->num, 0);
 
-			DPF(2, "Steal a voice: not yet implemented\n");
+		sample = (voice_tmp->flags & VOICEMGR_FLAGS_16BIT) ? 0 : 0x80808080;
+		cra = sblive_readptr(card, CCR, voice_tmp->num) & CCR_READADDRESS_MASK;
+		sblive_writeptr(card, CCR, voice_tmp->num, cra);
+		cra = (cra >> 18) & 0xf;
+		sblive_writeptr(card, CD0 + cra, voice_tmp->num, sample);
+		cra = (cra + 0x1) & 0xf;
+		sblive_writeptr(card, CD0 + cra, voice_tmp->num, sample);
 
-			spin_lock_irqsave(&sblive_spinlock, flags);
+		for (i = 0; i < NUM_FXSENDS; i++)
+			voice_tmp->sendhandle[i] = 0;
 
-			while (allocvoicelist)
-			{
-				linkvoice = allocvoicelist;
-				allocvoicelist = allocvoicelist->linked_voice;
-				dlDelNode(ppOwnerList, linkvoice);
-
-				linkvoice->linked_voice = NULL;
-				linkvoice->master_voice = NULL;
-				linkvoice->flags = 0;
-				linkvoice->callback = 0;
-				linkvoice->callback_data = 0;
-				linkvoice->voicestate = VOICEMGR_STATE_IDLE;
-				linkvoice->usage = VOICEMGR_USAGE_FREE;
+		voice_tmp->flags = 0;
 
-				dlAddNode(&sb_hw->voice_manager.free_voices, linkvoice);
-			}
-
-			spin_unlock_irqrestore(&sblive_spinlock, flags);
+		spin_lock_irqsave(&voicemgr->lock, flags);
+		voice_tmp->usage = VOICEMGR_USAGE_FREE;
 
-			break;
-		}
+		voice_tmp = voice_tmp->linked_voice;
+		voice->linked_voice = NULL;
+		spin_unlock_irqrestore(&voicemgr->lock, flags);
 	}
 
-	if (voiceallocdesc->ownertype != VOICEMGR_USAGE_MIDI)
-	{
-		linkvoice = allocvoicelist;
-
-		while (linkvoice)
-		{
-			linkvoice->voicestate &= ~VOICEMGR_STATE_TRANSITION;
-			linkvoice = linkvoice->linked_voice;
-		}
-	}
-
-	*voices = allocvoicelist;
-
-	return status;
+	return;
 }
 
+/*       Sets up a voices for Wave Playback */
 
-/************************************************************************
- *
- *   int sblive_voiceFree(struct emu_voice * voices)
- *
- *   ENTRY
- *       voices -
- *           pointer to a struct emu_voice returned
- *           by a call to sblive_voiceAlloc()
- *
- *   RETURNS
- *       SUCCESS -   CTSTATUS_SUCCESS
- *       FAILURE -   CTSTATUS_ERROR
- *
- *   ABOUT
- *       Frees a previously allocated voice. Multiple voices can
- *       be allocated at once but must be freed individually.
- *
- ************************************************************************/
-int sblive_voiceFree(struct emu_voice *voices)
+void emu10k1_voice_playback_setup(struct emu_voice *voice)
 {
-	struct emu_voice *voicetemp;
-	struct emu_voice **ppOwnerList;
-	struct sblive_hw *sb_hw;
-	unsigned long flags;
-
-	if (voices == NULL)
-		return CTSTATUS_INVALIDPARAM;
-
-	sb_hw = voices->sb_hw;
-
-	if (voices->usage == VOICEMGR_USAGE_PLAYBACK)
-		ppOwnerList = &sb_hw->voice_manager.playback_voices;
-	else if (voices->usage == VOICEMGR_USAGE_MIDI)
-		ppOwnerList = &sb_hw->voice_manager.midi_voices;
-	else
-	{
-		DPF(2, "Unknown VOICEMGR_USAGE\n");
-		return CTSTATUS_ERROR;
-	}
-
-	if (!(voices->flags & VOICEMGR_FLAGS_VOICEMASTER))
-	{
-		/* Not first voice in list */
-		DPF(2, "Not first voice in list!\n");
-		return CTSTATUS_ERROR;
-	}
-
-	while (voices)
-	{
-		unsigned dcysusv, voicenum;
-
-		voicenum = voices->voicenum;
-
-		sblive_writeptr(sb_hw, IFATN, voicenum, IFATN_FILTERCUTOFF_MASK | IFATN_ATTENUATION_MASK);
-		sblive_writeptr(sb_hw, IP, voicenum, 0);
-
-		dcysusv = sblive_readptr(sb_hw, DCYSUSV, voicenum) & (DCYSUSV_PHASE1_MASK | DCYSUSV_SUSTAINLEVEL_MASK | DCYSUSV_DECAYTIME_MASK);
-		sblive_writeptr(sb_hw, DCYSUSV, voicenum, dcysusv | ENV_OFF);
-
-		sblive_writeptr(sb_hw, VTFT, voicenum, VTFT_FILTERTARGET_MASK);
-		sblive_writeptr(sb_hw, PTRX_PITCHTARGET, voicenum, 0);
-		sblive_writeptr(sb_hw, CVCF,  voicenum, CVCF_CURRENTFILTER_MASK);
-		sblive_writeptr(sb_hw, CPF, voicenum, 0);
-
-		{
-			u32 cra;
-			u32 sample;
-			int i;
-
-			sample = (voices->flags & VOICEMGR_FLAGS_16BIT) ? 0 : 0x80808080;
-			cra = sblive_readptr(sb_hw, CCR, voicenum) & CCR_READADDRESS_MASK;
-			sblive_writeptr(sb_hw, CCR, voicenum, cra);
-			cra = (cra >> 18) & 0xf;
-			sblive_writeptr(sb_hw, CD0 + cra, voicenum, sample);
-			cra = (cra + 0x1) & 0xf;
-			sblive_writeptr(sb_hw, CD0 + cra, voicenum, sample);
-
-			for (i = 0; i < NUM_FXSENDS; i++)
-				if (voices->sendhandle[i])
-					voices->sendhandle[i] = 0;
-		}
+	struct emu10k1_card *card = voice->card;
+	u32 sample, cra = 0, start = 0;
 
-		spin_lock_irqsave(&sblive_spinlock, flags);
+	DPF(2, "emu10k1_voice_playback_setup()\n");
 
-		/* Reattach to free list */
-		voicetemp = voices;
-		voices = voices->linked_voice;
-
-		dlDelNode(ppOwnerList, voicetemp);	/* Detach first */
-		voicetemp->linked_voice = NULL;
-		voicetemp->master_voice = NULL;
-		voicetemp->flags = 0;
-		voicetemp->callback = 0;
-		voicetemp->callback_data = 0;
-		voicetemp->voicestate = VOICEMGR_STATE_IDLE;
-		voicetemp->usage = VOICEMGR_USAGE_FREE;
-		dlAddNode(&sb_hw->voice_manager.free_voices, voicetemp);
+	while (voice != NULL) {
+		sblive_writeptr(card, DCYSUSV, voice->num, ENV_OFF);
+		sblive_writeptr(card, VTFT, voice->num, VTFT_FILTERTARGET_MASK);
+		sblive_writeptr(card, CVCF, voice->num, CVCF_CURRENTFILTER_MASK);
+		sblive_writeptr(card, FXRT, voice->num, (voice->flags & VOICEMGR_FLAGS_FXRT2) ? 0xd23c0000 : 0xd01c0000);
 
-		spin_unlock_irqrestore(&sblive_spinlock, flags);
-
-	}
-
-	return CTSTATUS_SUCCESS;
-}
-
-
-/************************************************************************
- *
- *   int sblive_voicePlaybackSetup(struct emu_voice * voices)
- *
- *   ENTRY
- *       voices -
- *           pointer to a struct emu_voice returned
- *           by a call to sblive_voiceAlloc()
- *       pVoiceSetting -
- *           pointer to an array of setting params
- *
- *   RETURNS
- *       SUCCESS -   CTSTATUS_SUCCESS
- *       FAILURE -   CTSTATUS_ERROR
- *
- *   ABOUT
- *       Sets up a voices for Wave Playback
- *
- ************************************************************************/
-int sblive_voicePlaybackSetup(struct emu_voice *voices)
-{
-	int voicenum;
-	struct sblive_hw *sb_hw;
-	u32 cra = 0;
-	u32 start = 0;
-	struct voice_param *pvoice_params;
-	struct emu_voice *currvoice;
-
-	currvoice = voices;
-	while (currvoice)
-	{
-		/* Or here? (voices can be on different cards) */
-		sb_hw = currvoice->sb_hw;
-		voicenum = currvoice->voicenum;
-		pvoice_params = &currvoice->voice_params;
-
-		sblive_writeptr(sb_hw, DCYSUSV, voicenum, ENV_OFF);
-		sblive_writeptr(sb_hw, VTFT, voicenum, VTFT_FILTERTARGET_MASK);
-		sblive_writeptr(sb_hw, CVCF, voicenum, CVCF_CURRENTFILTER_MASK);
-
 		/* Stop CA */
-		/* Assumption that PT is already 0 so no harm overwriting */
-		sblive_writeptr(sb_hw, PTRX, voicenum,
-				(pvoice_params->unSends.tSends.reverb_send << 8) | pvoice_params->unSends.tSends.aux_send);
-
-		if (currvoice->flags & VOICEMGR_FLAGS_VOICEMASTER)
-		{
-			u32 sample;
+		/* Assumption that PT is alreadt 0 so no harm overwriting */
+		sblive_writeptr(card, PTRX, voice->num, (voice->params.send_a << 8) | voice->params.send_b);
 
-			if (currvoice->linked_voice != NULL)
-			{
+		if (voice->flags & VOICEMGR_FLAGS_VOICEMASTER) {
+			if (voice->linked_voice != NULL) {
 				/* Set stereo bit */
 				cra = 64;
-				sblive_writeptr(sb_hw, CPF, voicenum, CPF_STEREO_MASK);
-				sblive_writeptr(sb_hw, CPF, voicenum + 1, CPF_STEREO_MASK);
-			} else
-			{
+				sblive_writeptr(card, CPF, voice->num, CPF_STEREO_MASK);
+				sblive_writeptr(card, CPF, voice->num + 1, CPF_STEREO_MASK);
+			} else {
 				cra = 32;
-				sblive_writeptr(sb_hw, CPF, voicenum, 0);
+				sblive_writeptr(card, CPF, voice->num, 0);
 			}
 
-			if (currvoice->flags & VOICEMGR_FLAGS_16BIT)
+			if (voice->flags & VOICEMGR_FLAGS_16BIT)
 				sample = 0;
-			else
-			{
+			else {
 				cra = cra * 2;
 				sample = 0x80808080;
 			}
 			cra -= 4;
 
-			if (currvoice->linked_voice != NULL)
-			{
-				sblive_writeptr(sb_hw, CCR, voicenum, 0x3c << 16);
-				sblive_writeptr(sb_hw, CCR, voicenum + 1, cra << 16);
-				sblive_writeptr(sb_hw, CDE, voicenum + 1, sample);
-				sblive_writeptr(sb_hw, CDF, voicenum + 1, sample);
-				start = pvoice_params->start + cra / 2;
-			} else
-			{
-				sblive_writeptr(sb_hw, CCR, voicenum, 0x1c << 16); /* FIXME: Is 0x1c correct? */
-				sblive_writeptr(sb_hw, CDE, voicenum, sample);
-				sblive_writeptr(sb_hw, CDF, voicenum, sample);
-				start = pvoice_params->start + cra;
+			if (voice->linked_voice != NULL) {
+				/* CCR_READADDRESS_MASK */
+				sblive_writeptr(card, CCR, voice->num, 0x3c << 16);
+				sblive_writeptr(card, CCR, voice->num + 1, cra << 16);
+				sblive_writeptr(card, CDE, voice->num + 1, sample);
+				sblive_writeptr(card, CDF, voice->num + 1, sample);
+				start = voice->params.start + cra / 2;
+			} else {
+				sblive_writeptr(card, CCR, voice->num, 0x1c << 16);	/* FIXME: Is 0x1c correct? */
+				sblive_writeptr(card, CDE, voice->num, sample);
+				sblive_writeptr(card, CDF, voice->num, sample);
+				start = voice->params.start + cra;
 			}
 
-			if (start > pvoice_params->endloop)
-			{
-				start -= pvoice_params->endloop;
+			if (start > voice->params.endloop) {
+				start -= voice->params.endloop;
 
-				if (currvoice->linked_voice != NULL)
+				if (voice->linked_voice != NULL)
 					cra = (cra << 25) | 0x1bc0000 | ((cra - start) << 9);
 				else
 					cra = (cra << 25) | 0x11c0000 | ((cra - start) << 9);
 
-				start += pvoice_params->startloop;
+				start += voice->params.startloop;
 
-				if (start >= pvoice_params->endloop)
-					start = pvoice_params->endloop - 1;
-			} else
-				if (currvoice->linked_voice != NULL)
-					cra = (cra << 25) | (0x3c << 16);
-				else
-					cra = (cra << 25) | (0x1c << 16);
+				if (start >= voice->params.endloop)
+					start = voice->params.endloop - 1;
+			} else if (voice->linked_voice != NULL)
+				cra = (cra << 25) | (0x3c << 16);
+			else
+				cra = (cra << 25) | (0x1c << 16);
 
 			start |= CCCA_INTERPROM_0;
 		}
 
 		/* CSL, ST, CA */
-		sblive_writeptr(sb_hw, DSL, voicenum,
-				pvoice_params->endloop | ((u32) pvoice_params->unSends.tSends.chorus_send << 24));
+		sblive_writeptr(card, DSL, voice->num, voice->params.endloop | (voice->params.send_d << 24));
+		sblive_writeptr(card, PSST, voice->num, voice->params.startloop | (voice->params.send_c << 24));
 
-		sblive_writeptr(sb_hw, PSST, voicenum,
-				pvoice_params->startloop | ((u32) pvoice_params->unSends.tSends.pan_send << 24));
-
-		if (currvoice->flags & VOICEMGR_FLAGS_16BIT)
-			sblive_writeptr(sb_hw, CCCA, voicenum, start);
+		if (voice->flags & VOICEMGR_FLAGS_16BIT)
+			sblive_writeptr(card, CCCA, voice->num, start);
 		else
-			sblive_writeptr(sb_hw, CCCA, voicenum, start | CCCA_8BITSELECT);
+			sblive_writeptr(card, CCCA, voice->num, start | CCCA_8BITSELECT);
 
 		/* Clear filter delay memory */
-		sblive_writeptr(sb_hw, Z1, voicenum, 0);
-		sblive_writeptr(sb_hw, Z2, voicenum, 0);
+		sblive_writeptr(card, Z1, voice->num, 0);
+		sblive_writeptr(card, Z2, voice->num, 0);
 
 		/* Invalidate maps */
-		sblive_writeptr(sb_hw, MAPA, voicenum, MAP_PTI_MASK | (sb_hw->silentpage->physaddx * 2));
-		sblive_writeptr(sb_hw, MAPB, voicenum, MAP_PTI_MASK | (sb_hw->silentpage->physaddx * 2));
+		sblive_writeptr(card, MAPA, voice->num, MAP_PTI_MASK | (card->silentpage->busaddx * 2));
+		sblive_writeptr(card, MAPB, voice->num, MAP_PTI_MASK | (card->silentpage->busaddx * 2));
 
 		/* Fill cache */
-		if (currvoice->flags & VOICEMGR_FLAGS_VOICEMASTER)
-			sblive_writeptr(sb_hw, CCR, voicenum, cra);
+		if (voice->flags & VOICEMGR_FLAGS_VOICEMASTER)
+			sblive_writeptr(card, CCR, voice->num, cra);
+
+		sblive_writeptr(card, ATKHLDV, voice->num, ATKHLDV_HOLDTIME_MASK | ATKHLDV_ATTACKTIME_MASK);
+		sblive_writeptr(card, LFOVAL1, voice->num, 0x8000);
+		sblive_writeptr(card, ATKHLDM, voice->num, 0);
+		sblive_writeptr(card, DCYSUSM, voice->num, DCYSUSM_DECAYTIME_MASK);
+		sblive_writeptr(card, LFOVAL2, voice->num, 0x8000);
+		sblive_writeptr(card, IP, voice->num, voice->params.initial_pitch);
+		sblive_writeptr(card, PEFE, voice->num, 0x7f);
+		sblive_writeptr(card, FMMOD, voice->num, 0);
+		sblive_writeptr(card, TREMFRQ, voice->num, 0);
+		sblive_writeptr(card, FM2FRQ2, voice->num, 0);
+		sblive_writeptr(card, ENVVAL, voice->num, 0xbfff);
+		sblive_writeptr(card, ENVVOL, voice->num, 0xbfff);
+
+#ifdef PRIVATE_PCM_VOLUME
+		{
+			int i;
 
-		sblive_writeptr(sb_hw, ATKHLDV, voicenum, ATKHLDV_HOLDTIME_MASK | ATKHLDV_ATTACKTIME_MASK);
-		sblive_writeptr(sb_hw, LFOVAL1, voicenum, 0x8000);
-		sblive_writeptr(sb_hw, ATKHLDM, voicenum, 0);
-		sblive_writeptr(sb_hw, DCYSUSM, voicenum, DCYSUSM_DECAYTIME_MASK);
-		sblive_writeptr(sb_hw, LFOVAL2, voicenum, 0x8000);
-		sblive_writeptr(sb_hw, IP,  voicenum, pvoice_params->initial_pitch);
-		sblive_writeptr(sb_hw, PEFE, voicenum, 0x7f);
-		sblive_writeptr(sb_hw, FMMOD, voicenum, 0);
-		sblive_writeptr(sb_hw, TREMFRQ, voicenum, 0);
-		sblive_writeptr(sb_hw, FM2FRQ2, voicenum, 0);
-		sblive_writeptr(sb_hw, ENVVAL, voicenum, 0xbfff);
-		sblive_writeptr(sb_hw, ENVVOL, voicenum, 0xbfff);
-		sblive_writeptr(sb_hw, IFATN, voicenum, IFATN_FILTERCUTOFF_MASK | pvoice_params->initial_attn);
+			for (i = 0; i < MAX_PCM_CHANNELS; i++) {
+				if (sblive_pcm_volume[i].channel_l == voice->num) {
+					voice->params.initial_attn = (sblive_pcm_volume[i].channel_r < NUM_G) ? sblive_pcm_volume[i].attn_l :
+					    // test for mono channel (reverse logic is correct here!)
+					    (sblive_pcm_volume[i].attn_r >
+					     sblive_pcm_volume[i].attn_l) ? sblive_pcm_volume[i].attn_l : sblive_pcm_volume[i].attn_r;
+					DPD(2, "set left volume  %d\n", voice->params.initial_attn);
+					break;
+				} else if (sblive_pcm_volume[i].channel_r == voice->num) {
+					voice->params.initial_attn = sblive_pcm_volume[i].attn_r;
+					DPD(2, "set right volume  %d\n", voice->params.initial_attn);
+					break;
+				}
+			}
+		}
+#endif
+		sblive_writeptr(card, IFATN, voice->num, IFATN_FILTERCUTOFF_MASK | voice->params.initial_attn);
 
-		pvoice_params->FC_target = 0xffff;
-		pvoice_params->pitch_target = (u16)(IP_TO_CP(pvoice_params->initial_pitch) >> 16);
+		voice->params.FC_target = 0xffff;
+		voice->params.pitch_target = (u16) (IP_TO_CP(voice->params.initial_pitch) >> 16);
 
-		currvoice = currvoice->linked_voice;
+		voice = voice->linked_voice;
 	}
 
-	return CTSTATUS_SUCCESS;
+	return;
 }
 
-/************************************************************************
- *
- *   int sblive_voiceStart(struct emu_voice * voices)
- *
- *   ENTRY
- *       voices -
- *           pointer to a struct emu_voice returned
- *           by a call to sblive_voiceAlloc()
- *
- *   RETURNS
- *       SUCCESS -   CTSTATUS_SUCCESS
- *       FAILURE -   CTSTATUS_ERROR
- *
- *   ABOUT
- *       Starts voices
- *
- ************************************************************************/
-int sblive_voiceStart(struct emu_voice *voices)
+void emu10k1_voice_start(struct emu_voice *voice)
 {
-	struct sblive_hw *sb_hw;
-	struct emu_voice *tempvoice;
-
-	tempvoice = voices;
-	sb_hw = tempvoice->sb_hw;
-
-	/* Actual start */
-	while (tempvoice != NULL)
-	{
-		int voicenum = 0;	/* Linux: Added initialization */
-
-		if (tempvoice->flags & VOICEMGR_FLAGS_PLAYBACK)
-		{
-			struct voice_param *pvoice_params = &tempvoice->voice_params;
-			voicenum = tempvoice->voicenum;
-
-			/* Playback */
-			sblive_writeptr(sb_hw, PTRX_PITCHTARGET, voicenum, pvoice_params->pitch_target);
+	struct emu10k1_card *card = voice->card;
 
-			if (!(tempvoice->flags & VOICEMGR_FLAGS_STEREOSLAVE))
-				sblive_writeptr(sb_hw, CPF_CURRENTPITCH, voicenum, pvoice_params->pitch_target);
+	DPF(2, "emu10k1_voice_start()\n");
 
-			sblive_writeptr(sb_hw, VTFT, voicenum,
-					((u32) pvoice_params->volume_target << 16)
-					| pvoice_params->FC_target);
-			sblive_writeptr(sb_hw, CVCF, voicenum,
-					((u32) pvoice_params->volume_target << 16)
-					| pvoice_params->FC_target);
-			sblive_writeptr(sb_hw, DCYSUSV , voicenum,
-					(pvoice_params->byampl_env_sustain << 8)
-					| ENV_ON | pvoice_params->byampl_env_decay);
-
-			/* Using StopOnLoop for MIDI stops the playback
-			 too early, which may cause a DC level to be played
-			 until the note is released. */
+	while (voice != NULL) {
+		sblive_writeptr(card, PTRX_PITCHTARGET, voice->num, voice->params.pitch_target);
 
-			if (tempvoice->usage == VOICEMGR_USAGE_MIDI)
-				halClearStopOnLoop(sb_hw, voicenum);
+		if (voice->flags & VOICEMGR_FLAGS_VOICEMASTER)
+			sblive_writeptr(card, CPF_CURRENTPITCH, voice->num, voice->params.pitch_target);
+
+		sblive_writeptr(card, VTFT, voice->num, ((u32) voice->params.volume_target << 16)
+				| voice->params.FC_target);
+		sblive_writeptr(card, CVCF, voice->num, ((u32) voice->params.volume_target << 16)
+				| voice->params.FC_target);
+		sblive_writeptr(card, DCYSUSV, voice->num, (voice->params.byampl_env_sustain << 8)
+				| ENV_ON | voice->params.byampl_env_decay);
+
+		/* Using StopOnLoop for MIDI stops the playback
+		   too early, which may cause a DC level to be played
+		   until the note is released. */
+
+		if (voice->usage == VOICEMGR_USAGE_MIDI)
+			emu10k1_clear_stop_on_loop(card, voice->num);
+		else {
+			if (voice->params.startloop > voice->params.end)
+				emu10k1_set_stop_on_loop(card, voice->num);
 			else
-			{
-				if (pvoice_params->startloop > pvoice_params->end)
-					halSetStopOnLoop(sb_hw, voicenum);
-				else
-					halClearStopOnLoop(sb_hw, voicenum);
-			}
-		} else
-			/* Recording */
-			sblive_writeptr(sb_hw, DCYSUSV, voicenum, DCYSUSV_SUSTAINLEVEL_MASK |  DCYSUSV_DECAYTIME_MASK | ENV_ON);
-
-		tempvoice->voicestate |= VOICEMGR_STATE_ATTACK;
-		tempvoice = tempvoice->linked_voice;
+				emu10k1_clear_stop_on_loop(card, voice->num);
+		}
+		voice = voice->linked_voice;
 	}
 
-	return CTSTATUS_SUCCESS;
+	return;
 }
 
-
-/************************************************************************
- *
- *   int sblive_voiceStop(struct emu_voice * voices)
- *
- *   ENTRY
- *       voices -
- *           pointer to a struct emu_voice returned
- *           by a call to sblive_voiceAlloc()
- *
- *   RETURNS
- *       SUCCESS -   CTSTATUS_SUCCESS
- *       FAILURE -   CTSTATUS_ERROR
- *
- *   ABOUT
- *       Stops voices
- *
- ************************************************************************/
-int sblive_voiceStop(struct emu_voice *voices)
+void emu10k1_voice_stop(struct emu_voice *voice)
 {
-	struct sblive_hw *sb_hw = voices->sb_hw;
-	struct emu_voice *tempvoice = voices;
-	unsigned long flags;
-
-	spin_lock_irqsave(&sblive_spinlock, flags);
-
-	while (tempvoice != NULL)
-	{
+	struct emu10k1_card *card = voice->card;
 
-		if (voices->flags & VOICEMGR_FLAGS_PLAYBACK)
-		{
-			int voicenum = tempvoice->voicenum;
-
-			sblive_writeptr(sb_hw, IFATN, voicenum, 0xffff);
-			sblive_writeptr(sb_hw, IP, voicenum, 0);
-			sblive_writeptr(sb_hw, VTFT, voicenum, 0xffff);
-			sblive_writeptr(sb_hw, PTRX_PITCHTARGET, voicenum, 0);
-		}
+	DPF(2, "emu10k1_voice_stop()\n");
 
-		tempvoice->voicestate = VOICEMGR_STATE_IDLE;
-		tempvoice = tempvoice->linked_voice;
+	while (voice != NULL) {
+		sblive_writeptr(card, IFATN, voice->num, 0xffff);
+		sblive_writeptr(card, IP, voice->num, 0);
+		sblive_writeptr(card, VTFT, voice->num, 0xffff);
+		sblive_writeptr(card, PTRX_PITCHTARGET, voice->num, 0);
+		voice = voice->linked_voice;
 	}
 
-	tempvoice = voices;
-
-	spin_unlock_irqrestore(&sblive_spinlock, flags);
-
-	return CTSTATUS_SUCCESS;
+	return;
 }
-
 
-/************************************************************************
- *
- *   int sblive_voiceSetControl(struct emu_voice *voices,
- *                              struct voice_cntlset *pSetting,
- *                              u32 numparam)
- *
- *   ENTRY
- *       voices -
- *           pointer to a struct emu_voice returned
- *           by a call to sblive_voiceAlloc()
- *
- *       pSetting    -
- *           An array of CNTLSET structures
- *
- *       numparam  -
- *           Number of struct voice_cntlset structures in pSetting
- *
- *   RETURNS
- *       SUCCESS -   CTSTATUS_SUCCESS
- *       FAILURE -   CTSTATUS_ERROR
- *
- *   ABOUT
- *       Sets a voice control
- *
- ************************************************************************/
-int sblive_voiceSetControl(struct emu_voice *voices, struct voice_cntlset *setting, u32 numparam)
+void emu10k1_voice_setcontrol(struct emu_voice *voice, struct voice_cntlset *setting, u32 numparam)
 {
-	struct sblive_hw *sb_hw = voices->sb_hw;
-	struct emu_voice *currvoice = voices;
+	struct emu10k1_card *card = voice->card;
 	int count;
 
 	for (count = 0; count < numparam; count++)
-		sblive_writeptr(sb_hw, setting[count].paramID, currvoice->voicenum, setting[count].value);
+		sblive_writeptr(card, setting[count].paramID, voice->num, setting[count].value);
 
-	return CTSTATUS_SUCCESS;
+	return;
 }
-
 
-/************************************************************************
- *
- *   int sblive_voiceGetControl(struct emu_voice * voices,
- *                              u32 controlid, u32 *value)
- *
- *   ENTRY
- *       voices -
- *           pointer to a struct emu_voice returned
- *           by a call to sblive_voiceAlloc()
- *
- *       controlid -
- *           control to get
- *
- *       pvalue    -
- *           address to return control value
- *
- *   RETURNS
- *       SUCCESS -   CTSTATUS_SUCCESS
- *       FAILURE -   CTSTATUS_ERROR
- *
- *   ABOUT
- *       Gets a voice control
- *
- ************************************************************************/
-int sblive_voiceGetControl(struct emu_voice *voices, u32 controlid, u32 *value)
+void emu10k1_voice_getcontrol(struct emu_voice *voice, u32 controlid, u32 * value)
 {
-	struct sblive_hw *sb_hw = voices->sb_hw;
+	struct emu10k1_card *card = voice->card;
 
-	*value = sblive_readptr(sb_hw, controlid, voices->voicenum);
+	*value = sblive_readptr(card, controlid, voice->num);
 
-	return CTSTATUS_SUCCESS;
+	return;
 }
Index: oldkernel/linux/drivers/sound/emu10k1/voicemgr.h
diff -u linux/drivers/sound/emu10k1/voicemgr.h:1.1 linux/drivers/sound/emu10k1/voicemgr.h:1.2
--- linux/drivers/sound/emu10k1/voicemgr.h:1.1	Thu Jun  1 16:52:15 2000
+++ linux/drivers/sound/emu10k1/voicemgr.h	Fri Jul  7 15:36:45 2000
@@ -31,79 +31,18 @@
 
 #ifndef _VOICEMGR_H
 #define _VOICEMGR_H
-
-
-#define SAMPLETYPE_ROMMASK              0x8000
-#define SAMPLETYPE_MONOSAMPLE           1
-#define SAMPLETYPE_RIGHTSAMPLE          2
-#define SAMPLETYPE_LEFTSAMPLE           4
-
-#define SAMPLEMODE_MASK                 3
-#define SAMPLEMODE_RELEASEINLOOP        1
-#define SAMPLEMODE_RELEASEOUTLOOP       3
-
-#define WAVE_RAMP_TIME_TO_TARGET        100
-#define MIDI_RAMP_TIME_TO_TARGET        200
-
-#define RAMP_REVERB_SEND_NUM            0
-#define RAMP_AUX_SEND_NUM               1
-#define RAMP_PAN_SEND_NUM               2
-#define RAMP_CHORUS_SEND_NUM            3
-
 /* struct emu_voice.usage flags */
 #define VOICEMGR_USAGE_FREE         0x00000000
 #define VOICEMGR_USAGE_MIDI         0x00000001
 #define VOICEMGR_USAGE_PLAYBACK     0x00000002
-#define VOICEMGR_USAGE_RECORDING    0x00000004
 
-/* struct emu_voice.voicestate flags */
-#define VOICEMGR_STATE_IDLE         0x00000000
-#define VOICEMGR_STATE_ATTACK       0x00000001
-#define VOICEMGR_STATE_RELEASE      0x00000002
-#define VOICEMGR_STATE_IRQON        0x00000004
-#define VOICEMGR_STATE_TRANSITION   0x00000008
-#define VOICEMGR_STATE_SUSTAIN      0x00000010
-
 /* struct emu_voice.flags flags */
-#define VOICEMGR_FLAGS_PLAYBACK     0x00000001
 #define VOICEMGR_FLAGS_MONO         0x00000002
 #define VOICEMGR_FLAGS_16BIT        0x00000004
 #define VOICEMGR_FLAGS_STEREOSLAVE  0x00000008
 #define VOICEMGR_FLAGS_VOICEMASTER  0x80000000
-#define VOICEMGR_FLAGS_FASTCALLBACK 0x40000000
-
-#define VOICECALLBACK_EVENT_CALLBACKSIZEREACHED  0
-#define VOICECALLBACK_EVENT_FREEVOICE            1
-#define VOICECALLBACK_EVENT_TIMER		 2
-
-#if !defined(DLIST)
-#define DLIST(x)    struct {x  *next,  *pPrev;} DList
-
-#define dlAddNode(list,node) \
-	{ \
-	(node)->DList.next = *(list); \
-	(node)->DList.pPrev = NULL; \
-	if (*list) (*(list))->DList.pPrev = (node); *(list) = (node); \
-	}
-
-#define dlDelNode(list, node) \
-	{ \
-	if ((node)->DList.pPrev == NULL) \
-	*(list) = (node)->DList.next; \
-	else \
-	((node)->DList.pPrev)->DList.next = (node)->DList.next; \
-	if ((node)->DList.next != NULL) \
-	((node)->DList.next)->DList.pPrev = (node)->DList.pPrev; \
-	(node)->DList.next = (node)->DList.pPrev = NULL; \
-	}
-
-
-#define dlFirstNode(list)       (*(list))
-#define dlNextNode(curnode)     ((curnode)->DList.next)
-#define dlPrevNode(curnode)     ((curnode)->DList.pPrev)
-#endif
+#define VOICEMGR_FLAGS_FXRT2        0x00000010
 
-
 struct voice_param
 {
 	/* Sound engine */
@@ -111,29 +50,25 @@
 	u32 startloop;
 	u32 endloop;
 	u32 end;
+
 	u16 current_pitch;
 	u16 pitch_target;
+
 	u16 current_volume;
 	u16 volume_target;
+
 	u16 current_FC;
 	u16 FC_target;
+
 	u8 pan_target;
 	u8 aux_target;
-	u8 coef;
-	u8 sample_mode;
-	u8 sample_type;
-
-	union
-	{
-		struct
-		{
-			/* MUST be in the following order */
-			u8 reverb_send;
-			u8 aux_send;
-			u8 pan_send;
-			u8 chorus_send;
-		} tSends;
-	} unSends;
+
+	/* FX bus amount send */
+
+	u32 send_a;
+	u32 send_b;
+	u32 send_c;
+	u32 send_d;
 
 	/* Envelope engine */
 	u16 ampl_env_delay;
@@ -166,61 +101,36 @@
 	u16 initial_pitch;
 	u8 initial_attn;
 	u8 initial_FC;
-
-	u8 velocity;		/* BUGBUG: to be moved to aweobj */
-
-	u32 bank;
-	u8 program;
-	u16 key_exclusive;
 };
 
 struct voice_allocdesc
 {
-	struct sblive_hw *sb_hw;
-	u32 ownertype;
-	CALLBACKFN callback;
-	u32 callback_data;
-	u32 numvoicereqs;		/* Number of voice requests */
-					/* Stereo voices count as 1 */
-					/* request                  */
-	u32 flags[MAXREQVOICES];	/* stereo/mono rec/playback 8/16 */
+	u32 usage;			/* playback, Midi */
+	u32 flags;			/* stereo/mono rec/playback 8/16 bit*/
 };
 
-
 struct emu_voice
 {
-	DLIST(struct emu_voice);	/* Doubly-linked list */
+	struct list_head list;
 
-	struct sblive_hw *sb_hw;
-	u32 ownertype;
-	CALLBACKFN callback;
-	u32 callback_data;
-	u32 usage;		/* Free, MIDI, playback, recording, etc */
-	u32 voicestate;		/* Release, attack, idle, etc */
-	u32 voicenum;		/* Voice ID */
+	struct emu10k1_card *card;
+	u32 usage;		/* Free, MIDI, playback */
+	u32 num;		/* Voice ID */
 	u32 flags;		/* Stereo/mono, rec/playback, 8/16 bit */
+
+	struct voice_param params;
 
-	struct voice_param voice_params;
-	struct emu_voice *master_voice;	/* Index to previous linked voiceobj */
-	struct emu_voice *linked_voice;	/* Index to linked voiceobj, else set to NULL */
+	struct emu_voice *linked_voice;	/*for stereo voice*/
 
 	u32 sendhandle[NUM_FXSENDS];
 };
 
-
-struct voice_mgr
+struct voice_manager
 {
-	struct sblive_hw *sb_hw;
-	struct emu_voice *free_voices;
-	struct emu_voice *playback_voices;
-	struct emu_voice *record_voices;
-	struct emu_voice *midi_voices;
-
-	struct emu_voice voices[NUM_G];
-
-	/* Shouldn't use this directly.  Just move pointers around from */
-	/* free_voices to the other lists and vice versa. */
-	u32 ramp_eng_handle;
+	struct emu10k1_card *card;
+	spinlock_t lock;
+
+	struct emu_voice voice[NUM_G];
 };
 
 struct voice_cntlset
@@ -229,14 +139,12 @@
 	u32 value;
 };
 
-int sblive_voiceInit(struct sblive_hw *);
-int sblive_voiceExit(struct sblive_hw *);
-int sblive_voiceAlloc(struct voice_allocdesc *, struct emu_voice **);
-int sblive_voiceFree(struct emu_voice *);
-int sblive_voicePlaybackSetup(struct emu_voice *);
-int sblive_voiceStart(struct emu_voice *);
-int sblive_voiceStop(struct emu_voice *);
-int sblive_voiceSetControl(struct emu_voice *, struct voice_cntlset *, u32);
-int sblive_voiceGetControl(struct emu_voice *, u32, u32 *);
+struct emu_voice *emu10k1_voice_alloc(struct voice_manager *, struct voice_allocdesc *);
+void emu10k1_voice_free(struct voice_manager *, struct emu_voice *);
+void emu10k1_voice_playback_setup(struct emu_voice *);
+void emu10k1_voice_start(struct emu_voice *);
+void emu10k1_voice_stop(struct emu_voice *);
+void emu10k1_voice_setcontrol(struct emu_voice *, struct voice_cntlset *, u32);
+void emu10k1_voice_getcontrol(struct emu_voice *, u32, u32 *);
 
 #endif /* _VOICEMGR_H */
Index: oldkernel/linux/fs/Config.in
diff -u linux/fs/Config.in:1.1.1.1 linux/fs/Config.in:1.2
--- linux/fs/Config.in:1.1.1.1	Wed May 31 12:33:48 2000
+++ linux/fs/Config.in	Fri Jul  7 15:36:45 2000
@@ -49,6 +49,13 @@
 fi
 tristate 'ROM filesystem support' CONFIG_ROMFS_FS
 tristate 'Second extended fs support' CONFIG_EXT2_FS
+if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
+   tristate 'Third extended fs development code' CONFIG_EXT3_FS
+   if [ "$CONFIG_EXT3_FS" != "n" ]; then
+      bool '   Third extended fs buffer check' CONFIG_EXT3_FS_JFS_CHECK
+   fi
+fi
+
 tristate 'System V and Coherent filesystem support' CONFIG_SYSV_FS
 tristate 'UFS filesystem support' CONFIG_UFS_FS
 if [ "$CONFIG_UFS_FS" != "n" ]; then
@@ -72,12 +79,10 @@
   if [ "$CONFIG_NFS_FS" = "y" -a "$CONFIG_IP_PNP" = "y" ]; then
     bool '   Root file system on NFS' CONFIG_ROOT_NFS
   fi
+  tristate 'NFS server support' CONFIG_NFSD
   if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
-    tristate 'NFS server support' CONFIG_NFSD
+    bool '   Provide NFSv3 server support (EXPERIMENTAL)' CONFIG_NFSD_V3
   fi
-  if [ "$CONFIG_EXPERIMENTAL" = "y" -a "$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
     define_bool CONFIG_LOCKD y
@@ -89,6 +94,9 @@
       define_bool CONFIG_SUNRPC n
       define_bool CONFIG_LOCKD n
     fi
+  fi
+  if [ "$CONFIG_NFS_FS" != "n" -o "$CONFIG_NFSD" != "n" ]; then
+    bool '   NFS Version 3' CONFIG_NFS_V3
   fi
   tristate 'SMB filesystem support (to mount WfW shares etc.)' CONFIG_SMB_FS
 fi
Index: oldkernel/linux/fs/Makefile
diff -u linux/fs/Makefile:1.2 linux/fs/Makefile:1.3
--- linux/fs/Makefile:1.2	Thu Jun  1 13:06:16 2000
+++ linux/fs/Makefile	Fri Jul  7 15:36:45 2000
@@ -16,9 +16,9 @@
 		dcache.o inode.o attr.o bad_inode.o file.o iobuf.o $(BINFMTS) 
 
 MOD_LIST_NAME := FS_MODULES
-ALL_SUB_DIRS = coda minix ext2 fat msdos vfat proc isofs nfs umsdos ntfs \
+ALL_SUB_DIRS = coda minix ext2 ext3 fat msdos vfat proc isofs nfs umsdos ntfs \
 		hpfs sysv smbfs ncpfs ufs affs romfs autofs hfs lockd \
-		nfsd nls devpts adfs qnx4 efs
+		nfsd nls devpts adfs qnx4 efs jfs
 
 ifeq ($(CONFIG_QUOTA),y)
 O_OBJS += dquot.o
@@ -47,6 +47,14 @@
 else
   ifeq ($(CONFIG_EXT2_FS),m)
   MOD_SUB_DIRS += ext2
+  endif
+endif
+
+ifeq ($(CONFIG_EXT3_FS),y)
+SUB_DIRS += ext3 jfs
+else
+  ifeq ($(CONFIG_EXT3_FS),m)
+  MOD_SUB_DIRS += ext3 jfs
   endif
 endif
 
Index: oldkernel/linux/fs/binfmt_elf.c
diff -u linux/fs/binfmt_elf.c:1.2 linux/fs/binfmt_elf.c:1.3
--- linux/fs/binfmt_elf.c:1.2	Thu Jun  1 15:33:31 2000
+++ linux/fs/binfmt_elf.c	Fri Jul  7 15:36:45 2000
@@ -489,7 +489,7 @@
 		  	if (elf_interpreter ||
 			    elf_ppnt->p_filesz < 2 ||
 			    elf_ppnt->p_filesz > PAGE_SIZE)
-				goto out_free_interp;
+				goto out_free_dentry;
 
 			/* This is the program interpreter used for
 			 * shared libraries - for now assume that this
@@ -526,12 +526,12 @@
 					
 				current->personality = PER_SVR4;
 				interpreter_dentry = open_namei(elf_interpreter,
-								0, 0);
+								1, 0);
 				current->personality = old_pers;
 			} else
 #endif					
 				interpreter_dentry = open_namei(elf_interpreter,
-								0, 0);
+								1, 0);
 			set_fs(old_fs);
 			retval = PTR_ERR(interpreter_dentry);
 			if (IS_ERR(interpreter_dentry))
Index: oldkernel/linux/fs/buffer.c
diff -u linux/fs/buffer.c:1.4 linux/fs/buffer.c:1.5
--- linux/fs/buffer.c:1.4	Thu Jun  1 16:48:40 2000
+++ linux/fs/buffer.c	Fri Jul  7 15:36:45 2000
@@ -40,10 +40,13 @@
 #include <linux/init.h>
 #include <linux/quotaops.h>
 #include <linux/iobuf.h>
+#include <linux/buffer.h>
+#include <linux/jfs.h>
 
 #include <asm/uaccess.h>
 #include <asm/io.h>
 #include <asm/bitops.h>
+#include <asm/pgtable.h>
 
 #define NR_SIZES 7
 static char buffersize_index[65] =
@@ -75,8 +78,9 @@
 
 static struct buffer_head * unused_list = NULL;
 static struct buffer_head * reuse_list = NULL;
-static struct wait_queue * buffer_wait = NULL;
 
+struct wait_queue * buffer_wait = NULL;
+
 static int nr_buffers = 0;
 static int nr_buffers_type[NR_LIST] = {0,};
 static int nr_buffer_heads = 0;
@@ -161,7 +165,7 @@
  * We will ultimately want to put these in a separate list, but for
  * now we search all of the lists for dirty buffers.
  */
-static int sync_buffers(kdev_t dev, int wait)
+int sync_buffers(kdev_t dev, int wait)
 {
 	int i, retry, pass = 0, err = 0;
 	struct buffer_head * bh, *next;
@@ -183,6 +187,8 @@
 		for (i = nr_buffers_type[BUF_DIRTY]*2 ; i-- > 0 ; bh = next) {
 			if (bh->b_list != BUF_DIRTY)
 				goto repeat;
+			J_ASSERT(!bh->b_transaction);
+			J_ASSERT(bh->b_jlist == 0);
 			next = bh->b_next_free;
 			if (!lru_list[BUF_DIRTY])
 				break;
@@ -226,6 +232,8 @@
 			next->b_count++;
 			bh->b_flushtime = 0;
 			ll_rw_block(WRITE, 1, &bh);
+			J_ASSERT(!bh->b_transaction);
+			J_ASSERT(bh->b_jlist == 0);
 			bh->b_count--;
 			next->b_count--;
 			retry = 1;
@@ -267,9 +275,9 @@
 
 void sync_dev(kdev_t dev)
 {
-	sync_supers(dev);
 	sync_inodes(dev);
 	DQUOT_SYNC(dev);
+	sync_supers(dev);
 	/* sync all the dirty buffers out to disk only _after_ all the
 	   high level layers finished generated buffer dirty data
 	   (or we'll return with some buffer still dirty on the blockdevice
@@ -291,8 +299,8 @@
 int fsync_dev(kdev_t dev)
 {
 	sync_buffers(dev, 0);
-	sync_supers(dev);
 	sync_inodes(dev);
+	sync_supers(dev);
 	DQUOT_SYNC(dev);
 	return sync_buffers(dev, 1);
 }
@@ -724,7 +732,7 @@
 	bh->b_dev_id = dev_id;
 }
 
-static void end_buffer_io_sync(struct buffer_head *bh, int uptodate)
+void end_buffer_io_sync(struct buffer_head *bh, int uptodate)
 {
 	mark_buffer_uptodate(bh, uptodate);
 	unlock_buffer(bh);
@@ -816,14 +824,18 @@
 
 	if(buf->b_dev == B_FREE) {
 		printk("Attempt to refile free buffer\n");
+		*((char *) 0) = 0;
 		return;
 	}
-	if (buffer_dirty(buf))
+	if (buf->b_jlist != BJ_None)
+		dispose = BUF_JOURNAL;
+	else if (buffer_dirty(buf))
 		dispose = BUF_DIRTY;
 	else if (buffer_locked(buf))
 		dispose = BUF_LOCKED;
 	else
 		dispose = BUF_CLEAN;
+
 	if(dispose != buf->b_list) {
 		file_buffer(buf, dispose);
 		if(dispose == BUF_DIRTY) {
@@ -844,6 +856,13 @@
 				wakeup_bdflush(1);
 		}
 	}
+
+	/* If we have just written a checkpointed jfs buffer, then we
+	   can now unlink it from its original transaction: there's no
+	   need to keep the transaction pinned in the log once the datat
+	   is safely on disk. */
+	if (dispose == BUF_CLEAN && buf->b_cp_transaction)
+		journal_remove_checkpoint(buf);
 }
 
 /*
@@ -858,9 +877,13 @@
 
 	if (buf->b_count) {
 		buf->b_count--;
+		if (!buf->b_count &&
+		    (buf->b_jlist != BJ_None && buf->b_jlist != BJ_Shadow))
+			J_ASSERT (!test_bit(BH_JWrite, &buf->b_state));
 		return;
 	}
 	printk("VFS: brelse: Trying to free free buffer\n");
+	J_ASSERT(buf->b_count > 0);
 }
 
 /*
@@ -871,7 +894,10 @@
  */
 void __bforget(struct buffer_head * buf)
 {
-	if (buf->b_count != 1 || buffer_locked(buf)) {
+	/* @@@ TODO (non-urgent): Put checkpointed buffers on the
+           current transaction's forget list here. */
+	if (buf->b_count != 1 || buffer_locked(buf) ||
+	    buffer_journaled(buf)) {
 		__brelse(buf);
 		return;
 	}
@@ -966,7 +992,7 @@
 /*
  * Note: the caller should wake up the buffer_wait list if needed.
  */
-static void put_unused_buffer_head(struct buffer_head * bh)
+void put_unused_buffer_head(struct buffer_head * bh)
 {
 	if (nr_unused_buffer_heads >= MAX_UNUSED_BUFFERS) {
 		nr_buffer_heads--;
@@ -1014,7 +1040,7 @@
  * no-buffer-head deadlock.  Return NULL on failure; waiting for
  * buffer heads is now handled in create_buffers().
  */ 
-static struct buffer_head * get_unused_buffer_head(int async)
+struct buffer_head * get_unused_buffer_head(int async)
 {
 	struct buffer_head * bh;
 
@@ -1158,7 +1184,7 @@
 #endif
 	}
 	if (test_and_clear_bit(PG_swap_unlock_after, &page->flags))
-		swap_after_unlock_page(pgoff2ulong(page->index));
+		swap_after_unlock_page(page->offset);
 	if (test_and_clear_bit(PG_free_after, &page->flags))
 		__free_page(page);
 }
@@ -1478,7 +1504,7 @@
 int brw_page(int rw, struct page *page, kdev_t dev, int b[], int size, int bmap)
 {
 	struct buffer_head *bh, *prev, *next, *arr[MAX_BUF_PER_PAGE];
-	int block, nr;
+	int block, nr, need_dcache_flush;
 
 	if (!PageLocked(page))
 		panic("brw_page: page not locked for I/O");
@@ -1497,6 +1523,7 @@
 		return -ENOMEM;
 	}
 	nr = 0;
+	need_dcache_flush = 0;
 	next = bh;
 	do {
 		struct buffer_head * tmp;
@@ -1523,9 +1550,10 @@
 					ll_rw_block(READ, 1, &tmp);
 				wait_on_buffer(tmp);
 			}
-			if (rw == READ) 
+			if (rw == READ) {
 				memcpy(next->b_data, tmp->b_data, size);
-			else {
+				need_dcache_flush = 1;
+			} else {
 				memcpy(tmp->b_data, next->b_data, size);
 				mark_buffer_dirty(tmp, 0);
 			}
@@ -1539,6 +1567,8 @@
 			set_bit(BH_Dirty, &next->b_state);
 		arr[nr++] = next;
 	} while (prev = next, (next = next->b_this_page) != NULL);
+	if (need_dcache_flush)
+		flush_dcache_page(page_address(page));
 	prev->b_this_page = bh;
 	
 	if (nr) {
@@ -1600,46 +1630,15 @@
 	set_bit(PG_locked, &page->flags);
 	set_bit(PG_free_after, &page->flags);
 	
-	/* Blocks within a page */
 	i = PAGE_SIZE >> inode->i_sb->s_blocksize_bits;
-
-	block = pgoff2ulong(page->index);
-	/* Scaled already by PAGE_SHIFT, which said shift should
-	   be same or larger, than that of any filesystem in
-	   this system -- that is, at i386 with 4k pages one
-	   can't use 8k (primitive) blocks at the filesystems... */
-
-	if (i > 0) {
-		/* Filesystem blocksize is same, or smaller than CPU
-		   page size, we can easily process this.. */
-
-		if (i > 1)
-			block *= i;
-		/* Scale by FS blocks per page, presuming FS-blocks are smaller
-		   than the processor page... */
-
-		p = nr;
-		do {
-			*p = inode->i_op->bmap(inode, block);
-			i--;
-			block++;
-			p++;
-		} while (i > 0);
-	} else {
-		/* Filesystem blocksize is larger than CPU page size,
-		   but if the underlying storage system block size is
-		   smaller than CPU page size, all is well, else we
-		   are in deep trouble -- for direct paging in at least.. */
-		/* Nobody needs such monsterous fs block sizes ?
-		   Well, it is the only way to get files in terabyte
-		   range..  Nobody needs them ?  You are for a surprise..
-		   However EXT2 (at least) needs access to internal
-		   blocks and there it needs allocations of 8k/16k (or
-		   whatever the block size is) for internal uses..
-		   Fixing this function alone isn't enough, although
-		   perhaps fairly trivial.. */
-		/* FIXME: WRITE THE CODE HERE !!! */
-	}
+	block = page->offset >> inode->i_sb->s_blocksize_bits;
+	p = nr;
+	do {
+		*p = inode->i_op->bmap(inode, block);
+		i--;
+		block++;
+		p++;
+	} while (i > 0);
 
 	/* IO start */
 	brw_page(READ, page, inode->i_dev, nr, inode->i_sb->s_blocksize, 1);
@@ -1702,7 +1701,20 @@
  * Can the buffer be thrown out?
  */
 #define BUFFER_BUSY_BITS	((1<<BH_Dirty) | (1<<BH_Lock) | (1<<BH_Protected))
-#define buffer_busy(bh)		((bh)->b_count || ((bh)->b_state & BUFFER_BUSY_BITS))
+static inline int buffer_busy(struct buffer_head *bh) 
+{
+	if (bh->b_count)
+		return 1;
+	if (bh->b_state & BUFFER_BUSY_BITS)
+		return 1;
+	if (bh->b_jlist != BJ_None || bh->b_cp_transaction != NULL)
+		return 1;
+	/* @@@ Expensive debugging code, eliminate at some point */
+	J_ASSERT(bh->b_transaction == NULL);
+	J_ASSERT(!test_bit(BH_JWrite, &bh->b_state));
+	return 0;
+}
+
 
 /*
  * try_to_free_buffers() checks if all the buffers on this particular page
@@ -1754,7 +1766,7 @@
 	int found = 0, locked = 0, dirty = 0, used = 0, lastused = 0;
 	int protected = 0;
 	int nlist;
-	static char *buf_types[NR_LIST] = {"CLEAN","LOCKED","DIRTY"};
+	static char *buf_types[NR_LIST] = {"CLEAN","LOCKED","DIRTY","JFS"};
 
 	printk("Buffer memory:   %8ldkB\n",buffermem>>10);
 	printk("Buffer heads:    %6d\n",nr_buffer_heads);
@@ -1901,6 +1913,9 @@
 	for(nlist = BUF_LOCKED; nlist <= BUF_DIRTY; nlist++)
 #endif
 	{
+		if (nlist == BUF_JOURNAL)
+			continue;	/* Never sync journaled buffers, even
+					   when debugging! */
 		ndirty = 0;
 		nwritten = 0;
 	repeat:
@@ -1910,6 +1925,8 @@
 			 for (i = nr_buffers_type[nlist]; i-- > 0; bh = next) {
 				 /* We may have stalled while waiting for I/O to complete. */
 				 if(bh->b_list != nlist) goto repeat;
+				 J_ASSERT(!bh->b_transaction);
+				 J_ASSERT(bh->b_jlist == 0);
 				 next = bh->b_next_free;
 				 if(!lru_list[nlist]) {
 					 printk("Dirty list empty %d\n", i);
@@ -1941,6 +1958,8 @@
 				 if(nlist != BUF_DIRTY) ncount++;
 #endif
 				 ll_rw_block(WRITE, 1, &bh);
+				 J_ASSERT(!bh->b_transaction);
+				 J_ASSERT(bh->b_jlist == 0);
 				 bh->b_count--;
 				 next->b_count--;
 			 }
@@ -2056,6 +2075,12 @@
 #endif
 		 {
 			 ndirty = 0;
+
+			 /* Never sync journaled buffers, even when
+			  * debugging! */
+			 if (nlist == BUF_JOURNAL)
+				 continue;	
+
 		 repeat:
 
 			 bh = lru_list[nlist];
@@ -2064,6 +2089,8 @@
 				       bh = next) {
 					  /* We may have stalled while waiting for I/O to complete. */
 					  if(bh->b_list != nlist) goto repeat;
+					  J_ASSERT(!bh->b_transaction);
+					  J_ASSERT(bh->b_jlist == 0);
 					  next = bh->b_next_free;
 					  if(!lru_list[nlist]) {
 						  printk("Dirty list empty %d\n", i);
@@ -2099,6 +2126,8 @@
 					  }
 					  else
 					  ll_rw_block(WRITE, 1, &bh);
+					  J_ASSERT(!bh->b_transaction);
+					  J_ASSERT(bh->b_jlist == 0);
 #ifdef DEBUG
 					  if(nlist != BUF_DIRTY) ncount++;
 #endif
Index: oldkernel/linux/fs/exec.c
diff -u linux/fs/exec.c:1.2 linux/fs/exec.c:1.3
--- linux/fs/exec.c:1.2	Wed May 31 14:51:00 2000
+++ linux/fs/exec.c	Fri Jul  7 15:36:45 2000
@@ -618,21 +618,18 @@
 	cap_clear(bprm->cap_effective);
 
 	/*  To support inheritance of root-permissions and suid-root
-         *  executables under compatibility mode, we raise the
-         *  effective and inherited bitmasks of the executable file
-         *  (translation: we set the executable "capability dumb" and
-         *  set the allowed set to maximum). We don't set any forced
-         *  bits.
+         *  executables under compatibility mode, we raise all three
+         *  capability sets for the file.
          *
          *  If only the real uid is 0, we only raise the inheritable
-         *  bitmask of the executable file (translation: we set the
-         *  allowed set to maximum and the application to "capability
-         *  smart"). 
+         *  and permitted sets of the executable file.
          */
 
 	if (!issecure(SECURE_NOROOT)) {
-		if (bprm->e_uid == 0 || current->uid == 0)
+		if (bprm->e_uid == 0 || current->uid == 0) {
 			cap_set_full(bprm->cap_inheritable);
+			cap_set_full(bprm->cap_permitted);
+		}
 		if (bprm->e_uid == 0) 
 			cap_set_full(bprm->cap_effective);
 	}
@@ -643,10 +640,12 @@
          * privilege does not go against other system constraints.
          * The new Permitted set is defined below -- see (***). */
 	{
-		kernel_cap_t working =
-			cap_combine(bprm->cap_permitted,
-				    cap_intersect(bprm->cap_inheritable,
-						  current->cap_inheritable));
+		kernel_cap_t permitted, working;
+
+		permitted = cap_intersect(bprm->cap_permitted, cap_bset);
+		working = cap_intersect(bprm->cap_inheritable,
+					current->cap_inheritable);
+		working = cap_combine(permitted, working);
 		if (!cap_issubset(working, current->cap_permitted)) {
 			cap_raised = 1;
 		}
@@ -679,26 +678,29 @@
  * The formula used for evolving capabilities is:
  *
  *       pI' = pI
- * (***) pP' = fP | (fI & pI)
+ * (***) pP' = (fP & X) | (fI & pI)
  *       pE' = pP' & fE          [NB. fE is 0 or ~0]
  *
  * I=Inheritable, P=Permitted, E=Effective // p=process, f=file
- * ' indicates post-exec().
+ * ' indicates post-exec(), and X is the global 'cap_bset'.
  */
 
 void compute_creds(struct linux_binprm *bprm) 
 {
-	int new_permitted = cap_t(bprm->cap_permitted) |
-		(cap_t(bprm->cap_inheritable) & 
-		 cap_t(current->cap_inheritable));
+	kernel_cap_t new_permitted, working;
+
+	new_permitted = cap_intersect(bprm->cap_permitted, cap_bset);
+	working = cap_intersect(bprm->cap_inheritable,
+				current->cap_inheritable);
+	new_permitted = cap_combine(new_permitted, working);
 
 	/* For init, we want to retain the capabilities set
          * in the init_task struct. Thus we skip the usual
          * capability rules */
 	if (current->pid != 1) {
-		cap_t(current->cap_permitted) = new_permitted;
-		cap_t(current->cap_effective) = new_permitted & 
-						cap_t(bprm->cap_effective);
+		current->cap_permitted = new_permitted;
+		current->cap_effective =
+			cap_intersect(new_permitted, bprm->cap_effective);
 	}
 	
         /* AUD: Audit candidate if current->cap_effective is set */
Index: oldkernel/linux/fs/fcntl.c
diff -u linux/fs/fcntl.c:1.3 linux/fs/fcntl.c:1.4
--- linux/fs/fcntl.c:1.3	Thu Jun  1 15:08:25 2000
+++ linux/fs/fcntl.c	Fri Jul  7 15:36:45 2000
@@ -184,19 +184,6 @@
 		case F_SETLKW:
 			err = fcntl_setlk(fd, cmd, (struct flock *) arg);
 			break;
-
-#if BITS_PER_LONG == 32
-		case F_GETLK64:
-			err = fcntl_getlk64(fd, (struct flock64 *) arg);
-			break;
-		case F_SETLK64:
-			err = fcntl_setlk64(fd, cmd, (struct flock64 *) arg);
-			break;
-		case F_SETLKW64:
-			err = fcntl_setlk64(fd, cmd, (struct flock64 *) arg);
-			break;
-#endif
-
 		case F_GETOWN:
 			/*
 			 * XXX If f_owner is a process group, the
Index: oldkernel/linux/fs/filesystems.c
diff -u linux/fs/filesystems.c:1.1.1.1 linux/fs/filesystems.c:1.2
--- linux/fs/filesystems.c:1.1.1.1	Wed May 31 12:33:48 2000
+++ linux/fs/filesystems.c	Fri Jul  7 15:36:45 2000
@@ -11,6 +11,7 @@
 
 #include <linux/minix_fs.h>
 #include <linux/ext2_fs.h>
+#include <linux/ext3_fs.h>
 #include <linux/msdos_fs.h>
 #include <linux/umsdos_fs.h>
 #include <linux/proc_fs.h>
@@ -51,6 +52,10 @@
 
 void __init filesystem_setup(void)
 {
+#ifdef CONFIG_EXT3_FS
+	init_ext3_fs();
+#endif
+
 #ifdef CONFIG_EXT2_FS
 	init_ext2_fs();
 #endif
@@ -205,3 +210,16 @@
 	return ret;
 }
 #endif /* CONFIG_NFSD */
+
+#if defined(CONFIG_EXT3_FS) || defined(CONFIG_EXT3_FS_MODULE)
+void dummy_jfs_function (void *p)
+{
+}
+
+void (*jfs_preclean_buffer_check)(struct buffer_head *)
+	= dummy_jfs_function;
+void (*jfs_prelock_buffer_check)(struct buffer_head *)
+	= dummy_jfs_function;
+void (*journal_remove_checkpoint)(struct buffer_head *)
+	= dummy_jfs_function;
+#endif
Index: oldkernel/linux/fs/inode.c
diff -u linux/fs/inode.c:1.1.1.1 linux/fs/inode.c:1.2
--- linux/fs/inode.c:1.1.1.1	Wed May 31 12:33:48 2000
+++ linux/fs/inode.c	Fri Jul  7 15:36:45 2000
@@ -529,7 +529,7 @@
 /*
  * Called with the inode lock held.
  */
-static struct inode * find_inode(struct super_block * sb, unsigned long ino, struct list_head *head)
+static struct inode * find_inode(struct super_block * sb, unsigned long ino, struct list_head *head, find_inode_t find_actor, void *opaque)
 {
 	struct list_head *tmp;
 	struct inode * inode;
@@ -545,6 +545,8 @@
 			continue;
 		if (inode->i_ino != ino)
 			continue;
+		if (find_actor && !find_actor(inode, ino, opaque))
+			continue;
 		inode->i_count++;
 		break;
 	}
@@ -619,7 +621,7 @@
  * We no longer cache the sb_flags in i_flags - see fs.h
  *	-- rmk@arm.uk.linux.org
  */
-static struct inode * get_new_inode(struct super_block *sb, unsigned long ino, struct list_head *head)
+static struct inode * get_new_inode(struct super_block *sb, unsigned long ino, struct list_head *head, find_inode_t find_actor, void *opaque)
 {
 	struct inode * inode;
 	struct list_head * tmp = inode_unused.next;
@@ -664,7 +666,7 @@
 	inode = grow_inodes();
 	if (inode) {
 		/* We released the lock, so.. */
-		struct inode * old = find_inode(sb, ino, head);
+		struct inode * old = find_inode(sb, ino, head, find_actor, opaque);
 		if (!old)
 			goto add_new_inode;
 		list_add(&inode->i_list, &inode_unused);
@@ -694,7 +696,7 @@
 retry:
 	if (counter > max_reserved) {
 		head = inode_hashtable + hash(sb,counter);
-		inode = find_inode(sb, res = counter++, head);
+		inode = find_inode(sb, res = counter++, head, NULL, NULL);
 		if (!inode) {
 			spin_unlock(&inode_lock);
 			return res;
@@ -720,13 +722,13 @@
 	return inode;
 }
 
-struct inode *iget(struct super_block *sb, unsigned long ino)
+struct inode *iget4(struct super_block *sb, unsigned long ino, find_inode_t find_actor, void *opaque)
 {
 	struct list_head * head = inode_hashtable + hash(sb,ino);
 	struct inode * inode;
 
 	spin_lock(&inode_lock);
-	inode = find_inode(sb, ino, head);
+	inode = find_inode(sb, ino, head, find_actor, opaque);
 	if (inode) {
 		spin_unlock(&inode_lock);
 		wait_on_inode(inode);
@@ -737,7 +739,12 @@
 	 * the inode lock and re-trying the search in case it
 	 * had to block at any point.
 	 */
-	return get_new_inode(sb, ino, head);
+	return get_new_inode(sb, ino, head, find_actor, opaque);
+}
+
+struct inode *iget(struct super_block *sb, unsigned long ino)
+{
+	return iget4(sb, ino, NULL, NULL);
 }
 
 void insert_inode_hash(struct inode *inode)
@@ -898,13 +905,13 @@
 	struct inode * inode;
 
 	spin_lock(&inode_lock);
-	inode = find_inode(sb, ino, head);
+	inode = find_inode(sb, ino, head, NULL, NULL);
 	if (inode) {
 		spin_unlock(&inode_lock);
 		wait_on_inode(inode);
 	}
 	else
-		inode = get_new_inode (sb, ino, head);
+		inode = get_new_inode (sb, ino, head, NULL, NULL);
 
 	/* When we get the inode, we have to check if it is in use. We
 	   have to release it if it is not. */
Index: oldkernel/linux/fs/iobuf.c
diff -u linux/fs/iobuf.c:1.3 linux/fs/iobuf.c:1.4
--- linux/fs/iobuf.c:1.3	Thu Jun  1 16:48:40 2000
+++ linux/fs/iobuf.c	Fri Jul  7 15:36:45 2000
@@ -212,8 +212,8 @@
 		int pagelen = length;
 		
 		if (bounce_page) {
-			if (pagelen > PAGE_SIZE)
-				pagelen = PAGE_SIZE;
+			if ((pagelen+offset) > PAGE_SIZE)
+				pagelen = PAGE_SIZE - offset;
 		
 			if (direction == COPY_TO_BOUNCE) {
 				kin  = kmap(page, KM_READ);
Index: oldkernel/linux/fs/locks.c
diff -u linux/fs/locks.c:1.2 linux/fs/locks.c:1.3
--- linux/fs/locks.c:1.2	Thu Jun  1 15:03:08 2000
+++ linux/fs/locks.c	Fri Jul  7 15:36:45 2000
@@ -111,12 +111,12 @@
 
 #include <asm/uaccess.h>
 
-#define OFFSET_MAX	((loff_t)((~0ULL)>>1))	/* FIXME: move elsewhere? */
+#define OFFSET_MAX	((off_t)LONG_MAX)	/* FIXME: move elsewhere? */
 
 static int flock_make_lock(struct file *filp, struct file_lock *fl,
 			       unsigned int cmd);
 static int posix_make_lock(struct file *filp, struct file_lock *fl,
-			       struct flock64 *l);
+			       struct flock *l);
 static int flock_locks_conflict(struct file_lock *caller_fl,
 				struct file_lock *sys_fl);
 static int posix_locks_conflict(struct file_lock *caller_fl,
@@ -195,7 +195,7 @@
 
 	if (waiter->fl_prevblock) {
 		printk(KERN_ERR "locks_insert_block: remove duplicated lock "
-			"(pid=%d %Ld-%Ld type=%d)\n",
+			"(pid=%d %ld-%ld type=%d)\n",
 			waiter->fl_pid, waiter->fl_start,
 			waiter->fl_end, waiter->fl_type);
 		locks_delete_block(waiter->fl_prevblock, waiter);
@@ -323,15 +323,11 @@
 {
 	struct file *filp;
 	struct file_lock *fl,file_lock;
-	int error = -EFAULT;
-	struct flock64 flock;
+	struct flock flock;
+	int error;
 
-	if (verify_area(VERIFY_READ, l, sizeof(*l))
-	    || __get_user(flock.l_type, &l->l_type)
-	    || __get_user(flock.l_whence, &l->l_whence)
-	    || __get_user(flock.l_start, &l->l_start)
-	    || __get_user(flock.l_len, &l->l_len)
-	    || __get_user(flock.l_pid, &l->l_pid))
+	error = -EFAULT;
+	if (copy_from_user(&flock, l, sizeof(flock)))
 		goto out;
 	error = -EINVAL;
 	if ((flock.l_type != F_RDLCK) && (flock.l_type != F_WRLCK))
@@ -353,7 +349,11 @@
 		error = filp->f_op->lock(filp, F_GETLK, &file_lock);
 		if (error < 0)
 			goto out_putf;
-		fl = &file_lock;
+		else if (error == LOCK_USE_CLNT)
+		  /* Bypass for NFS with no locking - 2.0.36 compat */
+		  fl = posix_test_lock(filp, &file_lock);
+		else
+		  fl = (file_lock.fl_type == F_UNLCK ? NULL : &file_lock);
 	} else {
 		fl = posix_test_lock(filp, &file_lock);
 	}
@@ -367,24 +367,9 @@
 		flock.l_whence = 0;
 		flock.l_type = fl->fl_type;
 	}
-
-	/* Convert to 32-bit offsets (at 32-bit systems) */
-
-	if (!off_t_presentable(flock.l_start) ||
-	    !off_t_presentable(flock.l_len) ||
-	    !off_t_presentable(flock.l_start + flock.l_len)) {
-		error = -EOVERFLOW;
-		goto out_putf;
-	}
-
-	error = 0;
-	if (verify_area(VERIFY_WRITE, l, sizeof(*l))
-	    || __put_user(flock.l_type, &l->l_type)
-	    || __put_user(flock.l_whence, &l->l_whence)
-	    || __put_user(flock.l_start, &l->l_start)
-	    || __put_user(flock.l_len, &l->l_len)
-	    || __put_user(flock.l_pid, &l->l_pid))
-		error = -EFAULT;
+	error = -EFAULT;
+	if (!copy_to_user(l, &flock, sizeof(flock)))
+		error = 0;
   
 out_putf:
 	fput(filp);
@@ -399,7 +384,7 @@
 {
 	struct file *filp;
 	struct file_lock file_lock;
-	struct flock64 flock;
+	struct flock flock;
 	struct dentry * dentry;
 	struct inode *inode;
 	int error;
@@ -408,12 +393,7 @@
 	 * This might block, so we do it before checking the inode.
 	 */
 	error = -EFAULT;
-	if (verify_area(VERIFY_READ, l, sizeof(*l))
-	    || __get_user(flock.l_type, &l->l_type)
-	    || __get_user(flock.l_whence, &l->l_whence)
-	    || __get_user(flock.l_start, &l->l_start)
-	    || __get_user(flock.l_len, &l->l_len)
-	    || __get_user(flock.l_pid, &l->l_pid))
+	if (copy_from_user(&flock, l, sizeof(flock)))
 		goto out;
 
 	/* Get arguments and validate them ...
@@ -495,152 +475,6 @@
 	return error;
 }
 
-#if BITS_PER_LONG == 32
-/* Report the first existing lock that would conflict with l.
- * This implements the F_GETLK command of fcntl().
- */
-int fcntl_getlk64(unsigned int fd, struct flock64 *l)
-{
-	struct file *filp;
-	struct file_lock *fl,file_lock;
-	struct flock64 flock;
-	int error;
-
-	error = -EFAULT;
-	if (copy_from_user(&flock, l, sizeof(flock)))
-		goto out;
-	error = -EINVAL;
-	if ((flock.l_type != F_RDLCK) && (flock.l_type != F_WRLCK))
-		goto out;
-
-	error = -EBADF;
-	filp = fget(fd);
-	if (!filp)
-		goto out;
-
-	error = -EINVAL;
-	if (!filp->f_dentry || !filp->f_dentry->d_inode)
-		goto out_putf;
-
-	if (!posix_make_lock(filp, &file_lock, &flock))
-		goto out_putf;
-
-	if (filp->f_op->lock) {
-		error = filp->f_op->lock(filp, F_GETLK, &file_lock);
-		if (error < 0)
-			goto out_putf;
-		else if (error == LOCK_USE_CLNT)
-		  /* Bypass for NFS with no locking - 2.0.36 compat */
-		  fl = posix_test_lock(filp, &file_lock);
-		else
-		  fl = (file_lock.fl_type == F_UNLCK ? NULL : &file_lock);
-	} else {
-		fl = posix_test_lock(filp, &file_lock);
-	}
- 
-	flock.l_type = F_UNLCK;
-	if (fl != NULL) {
-		flock.l_pid = fl->fl_pid;
-		flock.l_start = fl->fl_start;
-		flock.l_len = fl->fl_end == OFFSET_MAX ? 0 :
-			fl->fl_end - fl->fl_start + 1;
-		flock.l_whence = 0;
-		flock.l_type = fl->fl_type;
-	}
-	error = -EFAULT;
-	if (!copy_to_user(l, &flock, sizeof(flock)))
-		error = 0;
-  
-out_putf:
-	fput(filp);
-out:
-	return error;
-}
-
-/* Apply the lock described by l to an open file descriptor.
- * This implements both the F_SETLK and F_SETLKW commands of fcntl().
- */
-int fcntl_setlk64(unsigned int fd, unsigned int cmd, struct flock64 *l)
-{
-	struct file *filp;
-	struct file_lock file_lock;
-	struct flock64 flock;
-	struct dentry * dentry;
-	struct inode *inode;
-	int error;
-
-	/*
-	 * This might block, so we do it before checking the inode.
-	 */
-	error = -EFAULT;
-	if (copy_from_user(&flock, l, sizeof(flock)))
-		goto out;
-
-	/* Get arguments and validate them ...
-	 */
-
-	error = -EBADF;
-	filp = fget(fd);
-	if (!filp)
-		goto out;
-
-	error = -EINVAL;
-	if (!(dentry = filp->f_dentry))
-		goto out_putf;
-	if (!(inode = dentry->d_inode))
-		goto out_putf;
-
-	/* Don't allow mandatory locks on files that may be memory mapped
-	 * and shared.
-	 */
-	if (IS_MANDLOCK(inode) &&
-	    (inode->i_mode & (S_ISGID | S_IXGRP)) == S_ISGID &&
-	    inode->i_mmap) {
-		struct vm_area_struct *vma = inode->i_mmap;
-		error = -EAGAIN;
-		do {
-			if (vma->vm_flags & VM_MAYSHARE)
-				goto out_putf;
-		} while ((vma = vma->vm_next_share) != NULL);
-	}
-
-	error = -EINVAL;
-	if (!posix_make_lock(filp, &file_lock, &flock))
-		goto out_putf;
-	
-	error = -EBADF;
-	switch (flock.l_type) {
-	case F_RDLCK:
-		if (!(filp->f_mode & FMODE_READ))
-			goto out_putf;
-		break;
-	case F_WRLCK:
-		if (!(filp->f_mode & FMODE_WRITE))
-			goto out_putf;
-		break;
-	case F_UNLCK:
-		break;
-	case F_SHLCK:
-	case F_EXLCK:
-	default:
-		error = -EINVAL;
-		goto out_putf;
-	}
-
-	if (filp->f_op->lock != NULL) {
-		error = filp->f_op->lock(filp, cmd, &file_lock);
-		if (error < 0)
-			goto out_putf;
-	}
-	error = posix_lock_file(filp, &file_lock, cmd == F_SETLKW);
-
-out_putf:
-	fput(filp);
-out:
-	return error;
-}
-#endif /* BITS_PER_LONG == 32 */
-
 /*
  * This function is called when the file is being removed
  * from the task's fd array.
@@ -820,9 +654,9 @@
  * style lock.
  */
 static int posix_make_lock(struct file *filp, struct file_lock *fl,
-			   struct flock64 *l)
+			   struct flock *l)
 {
-	loff_t start;
+	off_t start;
 
 	memset(fl, 0, sizeof(*fl));
 	
@@ -1300,6 +1134,8 @@
 		new->fl_start = fl->fl_start;
 		new->fl_end = fl->fl_end;
 		new->fl_notify = fl->fl_notify;
+		new->fl_insert = fl->fl_insert;
+		new->fl_remove = fl->fl_remove;
 		new->fl_u = fl->fl_u;
 	}
 	return new;
@@ -1318,6 +1154,9 @@
 	fl->fl_next = *pos;	/* insert into file's list */
 	*pos = fl;
 
+	if (fl->fl_insert)
+		fl->fl_insert(fl);
+
 	return;
 }
 
@@ -1345,6 +1184,9 @@
 		prevfl->fl_nextlink = nextfl;
 	else
 		file_lock_table = nextfl;
+
+	if (thisfl->fl_remove)
+		thisfl->fl_remove(thisfl);
 	
 	locks_wake_up_blocks(thisfl, wait);
 	locks_free_lock(thisfl);
@@ -1375,9 +1217,8 @@
 	p += sprintf(p, "%s ", (fl->fl_type == F_RDLCK) ? "READ " : "WRITE");
 	p += sprintf(p, "%d %s:%ld %ld %ld ",
 		     fl->fl_pid,
-		     kdevname(inode->i_dev), inode->i_ino,
-		     (u_long)fl->fl_start,
-		     (u_long)fl->fl_end);
+		     kdevname(inode->i_dev), inode->i_ino, fl->fl_start,
+		     fl->fl_end);
 	sprintf(p, "%08lx %08lx %08lx %08lx %08lx\n",
 		(long)fl, (long)fl->fl_prevlink, (long)fl->fl_nextlink,
 		(long)fl->fl_next, (long)fl->fl_nextblock);
@@ -1438,3 +1279,6 @@
 		*start = buffer;
 	return (q - buffer);
 }
+
+
+
Index: oldkernel/linux/fs/namei.c
diff -u linux/fs/namei.c:1.1.1.1 linux/fs/namei.c:1.2
--- linux/fs/namei.c:1.1.1.1	Wed May 31 12:33:48 2000
+++ linux/fs/namei.c	Fri Jul  7 15:36:45 2000
@@ -136,13 +136,11 @@
  * for filesystem access without changing the "normal" uids which
  * are used for other things..
  */
-int permission(struct inode * inode,int mask)
+int unix_permission(struct inode * inode,int mask)
 {
 	int mode = inode->i_mode;
 
-	if (inode->i_op && inode->i_op->permission)
-		return inode->i_op->permission(inode, mask);
-	else if ((mask & S_IWOTH) && IS_RDONLY(inode) &&
+	if ((mask & S_IWOTH) && IS_RDONLY(inode) &&
 		 (S_ISREG(mode) || S_ISDIR(mode) || S_ISLNK(mode)))
 		return -EROFS; /* Nobody gets write access to a read-only fs */
 	else if ((mask & S_IWOTH) && IS_IMMUTABLE(inode))
@@ -159,6 +157,13 @@
 		if (capable(CAP_DAC_READ_SEARCH))
 			return 0;
 	return -EACCES;
+}
+
+int permission(struct inode * inode,int mask)
+{
+	if (inode->i_op && inode->i_op->permission)
+		return inode->i_op->permission(inode, mask);
+	return unix_permission(inode, mask);
 }
 
 /*
Index: oldkernel/linux/fs/open.c
diff -u linux/fs/open.c:1.2 linux/fs/open.c:1.3
--- linux/fs/open.c:1.2	Thu Jun  1 15:03:08 2000
+++ linux/fs/open.c	Fri Jul  7 15:36:45 2000
@@ -12,7 +12,7 @@
 
 #include <asm/uaccess.h>
 
-asmlinkage long sys_statfs(const char * path, struct statfs * buf)
+asmlinkage int sys_statfs(const char * path, struct statfs * buf)
 {
 	struct dentry * dentry;
 	int error;
@@ -34,7 +34,7 @@
 	return error;
 }
 
-asmlinkage long sys_fstatfs(unsigned int fd, struct statfs * buf)
+asmlinkage int sys_fstatfs(unsigned int fd, struct statfs * buf)
 {
 	struct file * file;
 	struct inode * inode;
@@ -63,16 +63,15 @@
 	return error;
 }
 
-int do_truncate(struct dentry *dentry, loff_t length)
+int do_truncate(struct dentry *dentry, unsigned long length)
 {
 	struct inode *inode = dentry->d_inode;
 	int error;
 	struct iattr newattrs;
 
-	/* Not pretty: "inode->i_size" shouldn't really be signed. But it is. */
-	error = -EINVAL;
-	if (length < 0)
-		goto out;
+	/* Not pretty: "inode->i_size" shouldn't really be "off_t". But it is. */
+	if ((off_t) length < 0)
+		return -EINVAL;
 
 	down(&inode->i_sem);
 	newattrs.ia_size = length;
@@ -85,20 +84,15 @@
 			inode->i_op->truncate(inode);
 	}
 	up(&inode->i_sem);
-out:
 	return error;
 }
 
-static inline long do_sys_truncate(const char * path, loff_t length)
+asmlinkage int sys_truncate(const char * path, unsigned long length)
 {
 	struct dentry * dentry;
 	struct inode * inode;
 	int error;
 
-	error = -EINVAL;
-	if (length < 0)
-		goto out_nolock;
-
 	lock_kernel();
 	dentry = namei(path);
 
@@ -139,17 +133,11 @@
 	dput(dentry);
 out:
 	unlock_kernel();
-out_nolock:
 	return error;
 }
 
-asmlinkage long sys_truncate(const char * path, unsigned long length)
+asmlinkage int sys_ftruncate(unsigned int fd, unsigned long length)
 {
-	return do_sys_truncate(path, length);
-}
-
-static inline long do_sys_ftruncate(unsigned int fd, loff_t length)
-{
 	struct inode * inode;
 	struct dentry *dentry;
 	struct file * file;
@@ -183,24 +171,6 @@
 	return error;
 }
 
-asmlinkage long sys_ftruncate(unsigned int fd, unsigned long length)
-{
-	return do_sys_ftruncate(fd, length);
-}
-
-/* LFS versions of truncate are only needed on 32 bit machines */
-#if BITS_PER_LONG == 32
-asmlinkage long sys_truncate64(const char * path, loff_t length)
-{
-	return do_sys_truncate(path, length);
-}
-
-asmlinkage long sys_ftruncate64(unsigned int fd, loff_t length)
-{
-	return do_sys_ftruncate(fd, length);
-}
-#endif
-
 #ifndef __alpha__
 
 /*
@@ -214,7 +184,7 @@
  * must be owner or have write permission.
  * Else, update from *times, must be owner or super user.
  */
-asmlinkage long sys_utime(char * filename, struct utimbuf * times)
+asmlinkage int sys_utime(char * filename, struct utimbuf * times)
 {
 	int error;
 	struct dentry * dentry;
@@ -262,7 +232,7 @@
  * must be owner or have write permission.
  * Else, update from *times, must be owner or super user.
  */
-asmlinkage long sys_utimes(char * filename, struct timeval * utimes)
+asmlinkage int sys_utimes(char * filename, struct timeval * utimes)
 {
 	int error;
 	struct dentry * dentry;
@@ -308,7 +278,7 @@
  * We do this by temporarily clearing all FS-related capabilities and
  * switching the fsuid/fsgid around to the real ones.
  */
-asmlinkage long sys_access(const char * filename, int mode)
+asmlinkage int sys_access(const char * filename, int mode)
 {
 	struct dentry * dentry;
 	int old_fsuid, old_fsgid;
@@ -349,7 +319,7 @@
 	return res;
 }
 
-asmlinkage long sys_chdir(const char * filename)
+asmlinkage int sys_chdir(const char * filename)
 {
 	int error;
 	struct inode *inode;
@@ -384,7 +354,7 @@
 	return error;
 }
 
-asmlinkage long sys_fchdir(unsigned int fd)
+asmlinkage int sys_fchdir(unsigned int fd)
 {
 	struct file *file;
 	struct dentry *dentry;
@@ -421,7 +391,7 @@
 	return error;
 }
 
-asmlinkage long sys_chroot(const char * filename)
+asmlinkage int sys_chroot(const char * filename)
 {
 	int error;
 	struct inode *inode;
@@ -461,7 +431,7 @@
 	return error;
 }
 
-asmlinkage long sys_fchmod(unsigned int fd, mode_t mode)
+asmlinkage int sys_fchmod(unsigned int fd, mode_t mode)
 {
 	struct inode * inode;
 	struct dentry * dentry;
@@ -499,7 +469,7 @@
 	return err;
 }
 
-asmlinkage long sys_chmod(const char * filename, mode_t mode)
+asmlinkage int sys_chmod(const char * filename, mode_t mode)
 {
 	struct dentry * dentry;
 	struct inode * inode;
@@ -595,7 +565,7 @@
 	return error;
 }
 
-asmlinkage long sys_chown(const char * filename, uid_t user, gid_t group)
+asmlinkage int sys_chown(const char * filename, uid_t user, gid_t group)
 {
 	struct dentry * dentry;
 	int error;
@@ -612,7 +582,7 @@
 	return error;
 }
 
-asmlinkage long sys_lchown(const char * filename, uid_t user, gid_t group)
+asmlinkage int sys_lchown(const char * filename, uid_t user, gid_t group)
 {
 	struct dentry * dentry;
 	int error;
@@ -630,7 +600,7 @@
 }
 
 
-asmlinkage long sys_fchown(unsigned int fd, uid_t user, gid_t group)
+asmlinkage int sys_fchown(unsigned int fd, uid_t user, gid_t group)
 {
 	struct dentry * dentry;
 	struct file * file;
@@ -790,9 +760,6 @@
 	char * tmp;
 	int fd, error;
 
-#if BITS_PER_LONG != 32
-	flags |= O_LARGEFILE;
-#endif
 	tmp = getname(filename);
 	fd = PTR_ERR(tmp);
 	if (!IS_ERR(tmp)) {
@@ -823,7 +790,7 @@
  * For backward compatibility?  Maybe this should be moved
  * into arch/i386 instead?
  */
-asmlinkage long sys_creat(const char * pathname, int mode)
+asmlinkage int sys_creat(const char * pathname, int mode)
 {
 	return sys_open(pathname, O_CREAT | O_WRONLY | O_TRUNC, mode);
 }
@@ -896,7 +863,7 @@
  * This routine simulates a hangup on the tty, to arrange that users
  * are given clean terminals at login time.
  */
-asmlinkage long sys_vhangup(void)
+asmlinkage int sys_vhangup(void)
 {
 	int ret = -EPERM;
 
Index: oldkernel/linux/fs/read_write.c
diff -u linux/fs/read_write.c:1.2 linux/fs/read_write.c:1.3
--- linux/fs/read_write.c:1.2	Thu Jun  1 15:03:08 2000
+++ linux/fs/read_write.c	Fri Jul  7 15:36:45 2000
@@ -39,11 +39,7 @@
 static inline loff_t llseek(struct file *file, loff_t offset, int origin)
 {
 	loff_t (*fn)(struct file *, loff_t, int);
-	umode_t mode = file->f_dentry->d_inode->i_mode;
 
-	if (S_ISFIFO(mode) || S_ISSOCK(mode))
-	  return -ESPIPE;
-
 	fn = default_llseek;
 	if (file->f_op && file->f_op->llseek)
 		fn = file->f_op->llseek;
@@ -52,7 +48,7 @@
 
 asmlinkage off_t sys_lseek(unsigned int fd, off_t offset, unsigned int origin)
 {
-	off_t retval, oldpos;
+	off_t retval;
 	struct file * file;
 	struct dentry * dentry;
 	struct inode * inode;
@@ -66,19 +62,9 @@
 	if (!(dentry = file->f_dentry) ||
 	    !(inode = dentry->d_inode))
 		goto out_putf;
-	oldpos = file->f_pos;
 	retval = -EINVAL;
 	if (origin <= 2)
 		retval = llseek(file, offset, origin);
-
-	/* Demand L-F-S compliance only from normal files,
-	   thus raw devices can do whatever they please.. */
-	if (retval >= 0 && S_ISREG(inode->i_mode) &&
-	    !(file->f_flags & O_LARGEFILE) &&
-	    file->f_pos >= 0x7ffffffeULL) {
-		file->f_pos = oldpos;
-		retval = -EOVERFLOW;
-	}
 out_putf:
 	fput(file);
 bad:
@@ -95,7 +81,7 @@
 	struct file * file;
 	struct dentry * dentry;
 	struct inode * inode;
-	loff_t offset, oldpos;
+	loff_t offset;
 
 	lock_kernel();
 	retval = -EBADF;
@@ -110,7 +96,6 @@
 	if (origin > 2)
 		goto out_putf;
 
-	oldpos = file->f_pos;
 	offset = llseek(file, ((loff_t) offset_high << 32) | offset_low,
 			origin);
 
@@ -120,14 +105,6 @@
 		if (!copy_to_user(result, &offset, sizeof(offset)))
 			retval = 0;
 	}
-	if (!(file->f_flags & O_LARGEFILE) && S_ISREG(inode->i_mode) &&
-	    file->f_pos >= 0x7ffffffeULL) {
-		/* The target position isn't presentable without
-		   O_LARGEFILE flag being set --> yield error, and
-		   restore the file position. */
-		file->f_pos = oldpos;
-		retval = -EOVERFLOW;
-	}
 out_putf:
 	fput(file);
 bad:
@@ -348,7 +325,6 @@
 	ssize_t ret;
 	struct file * file;
 	ssize_t (*read)(struct file *, char *, size_t, loff_t *);
-	struct inode * inode;
 
 	lock_kernel();
 
@@ -356,30 +332,10 @@
 	file = fget(fd);
 	if (!file)
 		goto bad_file;
-
-	inode = file->f_dentry->d_inode;
-
 	if (!(file->f_mode & FMODE_READ))
 		goto out;
-
-	/* Start position must be non-negative! */
-	if (pos < 0) {
-	  ret = -EINVAL;
-	  goto out;
-	}
-	/* Read starting from beyond the end of file ? */
-	if (inode->i_size <= pos) {
-	  ret = -EOVERFLOW;
-	  goto out;
-	}
-
-	if (!(file->f_flags & O_LARGEFILE) && S_ISREG(inode->i_mode) &&
-	    file->f_pos >= 0x7ffffffeULL) {
-	  ret = -EOVERFLOW;
-	  goto out;
-	}
-
-	ret = locks_verify_area(FLOCK_VERIFY_READ, inode, file, pos, count);
+	ret = locks_verify_area(FLOCK_VERIFY_READ, file->f_dentry->d_inode,
+				file, pos, count);
 	if (ret)
 		goto out;
 	ret = -EINVAL;
@@ -401,7 +357,6 @@
 	ssize_t ret;
 	struct file * file;
 	ssize_t (*write)(struct file *, const char *, size_t, loff_t *);
-	struct inode * inode;
 
 	lock_kernel();
 
@@ -411,21 +366,8 @@
 		goto bad_file;
 	if (!(file->f_mode & FMODE_WRITE))
 		goto out;
-	/* Start position must be non-negative! */
-	if (pos < 0) {
-	  ret = -EINVAL;
-	  goto out;
-	}
-
-	inode = file->f_dentry->d_inode;
-
-	if (!(file->f_flags & O_LARGEFILE) && S_ISREG(inode->i_mode) &&
-	    file->f_pos >= 0x7ffffffeULL) {
-	  ret = -EOVERFLOW;
-	  goto out;
-	}
-
-	ret = locks_verify_area(FLOCK_VERIFY_WRITE, inode, file, pos, count);
+	ret = locks_verify_area(FLOCK_VERIFY_WRITE, file->f_dentry->d_inode,
+				file, pos, count);
 	if (ret)
 		goto out;
 	ret = -EINVAL;
@@ -434,9 +376,9 @@
 	if (pos < 0)
 		goto out;
 
-	down(&inode->i_sem);
+	down(&file->f_dentry->d_inode->i_sem);
 	ret = write(file, buf, count, &pos);
-	up(&inode->i_sem);
+	up(&file->f_dentry->d_inode->i_sem);
 
 out:
 	fput(file);
Index: oldkernel/linux/fs/stat.c
diff -u linux/fs/stat.c:1.2 linux/fs/stat.c:1.3
--- linux/fs/stat.c:1.2	Thu Jun  1 15:03:08 2000
+++ linux/fs/stat.c	Fri Jul  7 15:36:45 2000
@@ -280,124 +280,3 @@
 	unlock_kernel();
 	return error;
 }
-
-
-/* ---------- LFS-64 ----------- */
-#if !defined(__alpha__)
-
-static long cp_new_stat64(struct inode * inode, struct stat64 * statbuf)
-{
-	struct stat64 tmp;
-	unsigned int blocks, indirect;
-
-	memset(&tmp, 0, sizeof(tmp));
-	tmp.st_dev = kdev_t_to_nr(inode->i_dev);
-	tmp.st_ino = inode->i_ino;
-	tmp.st_mode = inode->i_mode;
-	tmp.st_nlink = inode->i_nlink;
-	tmp.st_uid = inode->i_uid;
-	tmp.st_gid = inode->i_gid;
-	tmp.st_rdev = kdev_t_to_nr(inode->i_rdev);
-	tmp.st_atime = inode->i_atime;
-	tmp.st_mtime = inode->i_mtime;
-	tmp.st_ctime = inode->i_ctime;
-	tmp.st_size = inode->i_size;
-/*
- * st_blocks and st_blksize are approximated with a simple algorithm if
- * they aren't supported directly by the filesystem. The minix and msdos
- * filesystems don't keep track of blocks, so they would either have to
- * be counted explicitly (by delving into the file itself), or by using
- * this simple algorithm to get a reasonable (although not 100% accurate)
- * value.
- */
-
-/*
- * Use minix fs values for the number of direct and indirect blocks.  The
- * count is now exact for the minix fs except that it counts zero blocks.
- * Everything is in units of BLOCK_SIZE until the assignment to
- * tmp.st_blksize.
- */
-#define D_B   7
-#define I_B   (BLOCK_SIZE / sizeof(unsigned short))
-
-	if (!inode->i_blksize) {
-		blocks = (tmp.st_size + BLOCK_SIZE - 1) >> BLOCK_SIZE_BITS;
-		if (blocks > D_B) {
-			indirect = (blocks - D_B + I_B - 1) / I_B;
-			blocks += indirect;
-			if (indirect > 1) {
-				indirect = (indirect - 1 + I_B - 1) / I_B;
-				blocks += indirect;
-				if (indirect > 1)
-					blocks++;
-			}
-		}
-		tmp.st_blocks = (BLOCK_SIZE / 512) * blocks;
-		tmp.st_blksize = BLOCK_SIZE;
-	} else {
-		tmp.st_blocks = inode->i_blocks;
-		tmp.st_blksize = inode->i_blksize;
-	}
-	return copy_to_user(statbuf,&tmp,sizeof(tmp)) ? -EFAULT : 0;
-}
-
-asmlinkage long sys_stat64(char * filename, struct stat64 * statbuf, long flags)
-{
-	struct dentry * dentry;
-	int error;
-
-	lock_kernel();
-	dentry = namei(filename);
-
-	error = PTR_ERR(dentry);
-	if (!IS_ERR(dentry)) {
-		error = do_revalidate(dentry);
-		if (!error)
-			error = cp_new_stat64(dentry->d_inode, statbuf);
-
-		dput(dentry);
-	}
-	unlock_kernel();
-	return error;
-}
-
-asmlinkage long sys_lstat64(char * filename, struct stat64 * statbuf, long flags)
-{
-	struct dentry * dentry;
-	int error;
-
-	lock_kernel();
-	dentry = lnamei(filename);
-
-	error = PTR_ERR(dentry);
-	if (!IS_ERR(dentry)) {
-		error = do_revalidate(dentry);
-		if (!error)
-			error = cp_new_stat64(dentry->d_inode, statbuf);
-
-		dput(dentry);
-	}
-	unlock_kernel();
-	return error;
-}
-
-asmlinkage long sys_fstat64(unsigned long fd, struct stat64 * statbuf, long flags)
-{
-	struct file * f;
-	int err = -EBADF;
-
-	lock_kernel();
-	f = fget(fd);
-	if (f) {
-		struct dentry * dentry = f->f_dentry;
-
-		err = do_revalidate(dentry);
-		if (!err)
-			err = cp_new_stat64(dentry->d_inode, statbuf);
-		fput(f);
-	}
-	unlock_kernel();
-	return err;
-}
-
-#endif /* LFS-64 */
Index: oldkernel/linux/fs/super.c
diff -u linux/fs/super.c:1.1.1.1 linux/fs/super.c:1.2
--- linux/fs/super.c:1.1.1.1	Wed May 31 12:33:48 2000
+++ linux/fs/super.c	Fri Jul  7 15:36:45 2000
@@ -90,6 +90,62 @@
 	/* NOTREACHED */
 }
 
+static
+struct vfsmount *vfsmnt_find_mt_de(struct inode *inode, struct dentry *nde)
+{
+	struct vfsmount *vmt;
+	struct dentry	*de;
+
+	for (vmt = vfsmntlist; vmt; vmt = vmt->mnt_next) {
+		if (!vmt->mnt_sb		||
+		    !(de = vmt->mnt_sb->s_root) ||
+		    !de->d_covers)
+			continue;
+		if (de->d_covers->d_inode == inode)
+			return vmt;
+	}
+	return NULL;
+}
+
+int vfsmnt_replace_mt_de(struct inode *inode, struct dentry *de_new)
+{
+	struct dentry	*de, *cov;
+	struct vfsmount *vmt;
+	char		*page;
+
+	if (de_new->d_mounts != de_new || !inode)
+		return 0;
+
+	if (!(vmt = vfsmnt_find_mt_de(inode, de_new)))
+		return 0;
+
+	de = vmt->mnt_sb->s_root;
+	cov = de->d_covers;
+	printk(KERN_ERR "VFS: Replacing %s/%s with %s/%s in mount table \n",
+	       cov->d_parent->d_name.name, cov->d_name.name,
+	       de_new->d_parent->d_name.name, de_new->d_name.name);
+	de->d_covers = dget(de_new);
+	de_new->d_mounts = de;
+	cov->d_mounts = cov;
+	dput(cov);
+
+	page = (char *) __get_free_page(GFP_USER);
+	if (page) {
+		char		*cwd = d_path(de_new, page, PAGE_SIZE),
+				*dest;
+		unsigned int	len = PAGE_SIZE + page - cwd;
+
+		dest = kmalloc(len, GFP_KERNEL);
+		if (dest) {
+			memcpy(dest, cwd, len);
+			kfree(vmt->mnt_dirname);
+			vmt->mnt_dirname = dest;
+		}
+		free_page((unsigned long) page);
+	}
+	return 1;
+}
+
 static struct vfsmount *add_vfsmnt(struct super_block *sb,
 			const char *dev_name, const char *dir_name)
 {
@@ -304,8 +360,10 @@
 	{ NFS_MOUNT_SOFT, ",soft" },
 	{ NFS_MOUNT_INTR, ",intr" },
 	{ NFS_MOUNT_POSIX, ",posix" },
+	{ NFS_MOUNT_TCP, ",tcp" },
 	{ NFS_MOUNT_NOCTO, ",nocto" },
 	{ NFS_MOUNT_NOAC, ",noac" },
+	{ NFS_MOUNT_NONLM, ",nolock" },
 	{ 0, NULL }
 };
 
@@ -330,6 +388,8 @@
 		}
 		if (!strcmp("nfs", tmp->mnt_sb->s_type->name)) {
 			nfss = &tmp->mnt_sb->u.nfs_sb.s_server;
+			len += sprintf(buf+len, ",v%d", nfss->rpc_ops->version);
+
 			if (nfss->rsize != NFS_DEF_FILE_IO_BUFFER_SIZE) {
 				len += sprintf(buf+len, ",rsize=%d",
 					       nfss->rsize);
@@ -562,6 +622,7 @@
 	s->s_flags = flags;
 	s->s_dirt = 0;
 	sema_init(&s->s_vfs_rename_sem,1);
+	sema_init(&s->s_nfsd_free_path_sem,1);
 	/* N.B. Should lock superblock now ... */
 	if (!type->read_super(s, data, silent))
 		goto out_fail;
@@ -1133,6 +1194,8 @@
 	goto dput_and_out;
 }
 
+extern char * root_mount_data;
+
 void __init mount_root(void)
 {
 	struct file_system_type * fs_type;
@@ -1150,6 +1213,7 @@
 			sb->s_dev = get_unnamed_dev();
 			sb->s_flags = root_mountflags;
 			sema_init(&sb->s_vfs_rename_sem,1);
+			sema_init(&sb->s_nfsd_free_path_sem,1);
 			vfsmnt = add_vfsmnt(sb, "/dev/root", "/");
 			if (vfsmnt) {
 				if (nfs_root_mount(sb) >= 0) {
@@ -1219,7 +1283,7 @@
 	else for (fs_type = file_systems ; fs_type ; fs_type = fs_type->next) {
   		if (!(fs_type->fs_flags & FS_REQUIRES_DEV))
   			continue;
-  		sb = read_super(ROOT_DEV,fs_type->name,root_mountflags,NULL,1);
+  		sb = read_super(ROOT_DEV,fs_type->name,root_mountflags,root_mount_data,1);
 		if (sb) {
 			sb->s_flags = root_mountflags;
 			current->fs->root = dget(sb->s_root);
Index: oldkernel/linux/fs/adfs/inode.c
diff -u linux/fs/adfs/inode.c:1.2 linux/fs/adfs/inode.c:1.3
--- linux/fs/adfs/inode.c:1.2	Thu Jun  1 15:03:08 2000
+++ linux/fs/adfs/inode.c	Fri Jul  7 15:36:45 2000
@@ -181,7 +181,7 @@
 		inode->i_nlink	 = 2;
 		inode->i_size	 = ADFS_NEWDIR_SIZE;
 		inode->i_blksize = PAGE_SIZE;
-		inode->i_blocks  = inode->i_size >> sb->s_blocksize_bits;
+		inode->i_blocks  = inode->i_size / sb->s_blocksize;
 		inode->i_mtime   =
 		inode->i_atime   =
 		inode->i_ctime   = 0;
Index: oldkernel/linux/fs/affs/file.c
diff -u linux/fs/affs/file.c:1.2 linux/fs/affs/file.c:1.3
--- linux/fs/affs/file.c:1.2	Thu Jun  1 15:03:08 2000
+++ linux/fs/affs/file.c	Fri Jul  7 15:36:45 2000
@@ -580,17 +580,17 @@
 affs_file_write(struct file *filp, const char *buf, size_t count, loff_t *ppos)
 {
 	struct inode		*inode = filp->f_dentry->d_inode;
-	loff_t			 pos;
+	off_t			 pos;
 	ssize_t			 written;
 	ssize_t			 c;
-	ssize_t			 blocksize, blockshift;
+	ssize_t			 blocksize;
 	struct buffer_head	*bh;
 	char			*p;
 
 	if (!count)
 		return 0;
-	pr_debug("AFFS: file_write(ino=%lu,pos=%Lu,count=%d)\n",inode->i_ino,
-		 *ppos,count);
+	pr_debug("AFFS: file_write(ino=%lu,pos=%lu,count=%d)\n",inode->i_ino,
+		 (unsigned long)*ppos,count);
 
 	if (!inode) {
 		affs_error(inode->i_sb,"file_write","Inode = NULL");
@@ -609,22 +609,16 @@
 	else
 		pos = *ppos;
 	written   = 0;
-	blocksize  = AFFS_I2BSIZE(inode);
-	blockshift = AFFS_I2BITS(inode);
-
-	if (pos >= 0x7fffffff) /* Max size: 2G-1 */
-		return -EFBIG;
-	if ((pos + count) > 0x7fffffff)
-		count = 0x7fffffff - pos;
+	blocksize = AFFS_I2BSIZE(inode);
 
 	while (written < count) {
-		bh = affs_getblock(inode, pos >> blockshift);
+		bh = affs_getblock(inode,pos / blocksize);
 		if (!bh) {
 			if (!written)
 				written = -ENOSPC;
 			break;
 		}
-		c = blocksize - (pos & (blocksize -1));
+		c = blocksize - (pos % blocksize);
 		if (c > count - written)
 			c = count - written;
 		if (c != blocksize && !buffer_uptodate(bh)) {
@@ -637,7 +631,7 @@
 				break;
 			}
 		}
-		p  = (pos & (blocksize -1)) + bh->b_data;
+		p  = (pos % blocksize) + bh->b_data;
 		c -= copy_from_user(p,buf,c);
 		if (!c) {
 			affs_brelse(bh);
@@ -668,7 +662,7 @@
 	off_t			 pos;
 	ssize_t			 written;
 	ssize_t			 c;
-	ssize_t			 blocksize, blockshift;
+	ssize_t			 blocksize;
 	struct buffer_head	*bh;
 	char			*p;
 
@@ -696,16 +690,15 @@
 
 	bh        = NULL;
 	blocksize = AFFS_I2BSIZE(inode) - 24;
-	blockshift = AFFS_I2BITS(inode);
 	written   = 0;
 	while (written < count) {
-		bh = affs_getblock(inode,pos >> blockshift);
+		bh = affs_getblock(inode,pos / blocksize);
 		if (!bh) {
 			if (!written)
 				written = -ENOSPC;
 			break;
 		}
-		c = blocksize - (pos & (blocksize -1));
+		c = blocksize - (pos % blocksize);
 		if (c > count - written)
 			c = count - written;
 		if (c != blocksize && !buffer_uptodate(bh)) {
@@ -718,7 +711,7 @@
 				break;
 			}
 		}
-		p  = (pos & (blocksize -1)) + bh->b_data + 24;
+		p  = (pos % blocksize) + bh->b_data + 24;
 		c -= copy_from_user(p,buf,c);
 		if (!c) {
 			affs_brelse(bh);
@@ -787,10 +780,10 @@
 	int	 rem;
 	int	 ext;
 
-	pr_debug("AFFS: truncate(inode=%ld,size=%Lu)\n",inode->i_ino,inode->i_size);
+	pr_debug("AFFS: truncate(inode=%ld,size=%lu)\n",inode->i_ino,inode->i_size);
 
 	net_blocksize = blocksize - ((inode->i_sb->u.affs_sb.s_flags & SF_OFS) ? 24 : 0);
-	first = (u_long)(inode->i_size + net_blocksize - 1) / net_blocksize;
+	first = (inode->i_size + net_blocksize - 1) / net_blocksize;
 	if (inode->u.affs_i.i_lastblock < first - 1) {
 		/* There has to be at least one new block to be allocated */
 		if (!inode->u.affs_i.i_ec && alloc_ext_cache(inode)) {
@@ -800,9 +793,9 @@
 		bh = affs_getblock(inode,first - 1);
 		if (!bh) {
 			affs_warning(inode->i_sb,"truncate","Cannot extend file");
-			inode->i_size = (inode->u.affs_i.i_lastblock + 1) * net_blocksize;
+			inode->i_size = net_blocksize * (inode->u.affs_i.i_lastblock + 1);
 		} else if (inode->i_sb->u.affs_sb.s_flags & SF_OFS) {
-			rem = ((u_long)inode->i_size) & (net_blocksize -1);
+			rem = inode->i_size % net_blocksize;
 			DATA_FRONT(bh)->data_size = cpu_to_be32(rem ? rem : net_blocksize);
 			affs_fix_checksum(blocksize,bh->b_data,5);
 			mark_buffer_dirty(bh,0);
@@ -869,7 +862,7 @@
 			affs_free_block(inode->i_sb,ekey);
 		ekey = key;
 	}
-	block = (((u_long)inode->i_size + net_blocksize - 1) / net_blocksize) - 1;
+	block = ((inode->i_size + net_blocksize - 1) / net_blocksize) - 1;
 	inode->u.affs_i.i_lastblock = block;
 
 	/* If the file is not truncated to a block boundary,
@@ -877,7 +870,7 @@
 	 * so it cannot become accessible again.
 	 */
 
-	rem = inode->i_size & (net_blocksize -1);
+	rem = inode->i_size % net_blocksize;
 	if (rem) {
 		if ((inode->i_sb->u.affs_sb.s_flags & SF_OFS)) 
 			rem += 24;
Index: oldkernel/linux/fs/affs/inode.c
diff -u linux/fs/affs/inode.c:1.2 linux/fs/affs/inode.c:1.3
--- linux/fs/affs/inode.c:1.2	Thu Jun  1 15:03:08 2000
+++ linux/fs/affs/inode.c	Fri Jul  7 15:36:45 2000
@@ -146,7 +146,7 @@
 				block = AFFS_I2BSIZE(inode) - 24;
 			else
 				block = AFFS_I2BSIZE(inode);
-			inode->u.affs_i.i_lastblock = (((u_long)inode->i_size + block - 1) / block) - 1;
+			inode->u.affs_i.i_lastblock = ((inode->i_size + block - 1) / block) - 1;
 			break;
 		case ST_SOFTLINK:
 			inode->i_mode |= S_IFLNK;
Index: oldkernel/linux/fs/coda/file.c
diff -u linux/fs/coda/file.c:1.2 linux/fs/coda/file.c:1.3
--- linux/fs/coda/file.c:1.2	Thu Jun  1 15:03:08 2000
+++ linux/fs/coda/file.c	Fri Jul  7 15:36:45 2000
@@ -99,7 +99,7 @@
 			      &cont_file, &cont_dentry);
 
         CDEBUG(D_INODE, "coda ino: %ld, cached ino %ld, page offset: %lx\n", 
-	       coda_inode->i_ino, cii->c_ovp->i_ino, pgoff2ulong(page->index));
+	       coda_inode->i_ino, cii->c_ovp->i_ino, page->offset);
 
         generic_readpage(&cont_file, page);
         EXIT;
Index: oldkernel/linux/fs/ext2/dir.c
diff -u linux/fs/ext2/dir.c:1.1.1.1 linux/fs/ext2/dir.c:1.2
--- linux/fs/ext2/dir.c:1.1.1.1	Wed May 31 12:33:48 2000
+++ linux/fs/ext2/dir.c	Fri Jul  7 15:36:45 2000
@@ -183,8 +183,8 @@
 						   bh, offset)) {
 				/* On error, skip the f_pos to the
                                    next block. */
-				filp->f_pos = (filp->f_pos & (sb->s_blocksize - 1))
-					      + sb->s_blocksize;
+				filp->f_pos = (filp->f_pos | (sb->s_blocksize - 1))
+					      + 1;
 				brelse (bh);
 				return stored;
 			}
@@ -196,15 +196,18 @@
 				 * version stamp to detect whether or
 				 * not the directory has been modified
 				 * during the copy operation.
+				 * AV: It can't be modified, but it fscking
+				 * can be seeked by another process that shares
+				 * the descriptor.
 				 */
-				unsigned long version = inode->i_version;
+				unsigned long version = filp->f_version;
 
 				error = filldir(dirent, de->name,
 						de->name_len,
 						filp->f_pos, le32_to_cpu(de->inode));
 				if (error)
 					break;
-				if (version != inode->i_version)
+				if (version != filp->f_version)
 					goto revalidate;
 				stored ++;
 			}
Index: oldkernel/linux/fs/ext2/file.c
diff -u linux/fs/ext2/file.c:1.2 linux/fs/ext2/file.c:1.3
--- linux/fs/ext2/file.c:1.2	Thu Jun  1 15:03:08 2000
+++ linux/fs/ext2/file.c	Fri Jul  7 15:36:45 2000
@@ -39,7 +39,11 @@
 static long long ext2_file_lseek(struct file *, long long, int);
 static ssize_t ext2_file_write (struct file *, const char *, size_t, loff_t *);
 static int ext2_release_file (struct inode *, struct file *);
+#if BITS_PER_LONG < 64
+static int ext2_open_file (struct inode *, struct file *);
 
+#else
+
 #define EXT2_MAX_SIZE(bits)							\
 	(((EXT2_NDIR_BLOCKS + (1LL << (bits - 2)) + 				\
 	   (1LL << (bits - 2)) * (1LL << (bits - 2)) + 				\
@@ -51,6 +55,8 @@
 EXT2_MAX_SIZE(10), EXT2_MAX_SIZE(11), EXT2_MAX_SIZE(12), EXT2_MAX_SIZE(13)
 };
 
+#endif
+
 /*
  * We have mostly NULL's here: the current defaults are ok for
  * the ext2 filesystem.
@@ -63,7 +69,11 @@
 	NULL,			/* poll - default */
 	ext2_ioctl,		/* ioctl */
 	generic_file_mmap,	/* mmap */
+#if BITS_PER_LONG == 64	
 	NULL,			/* no special open is needed */
+#else
+	ext2_open_file,
+#endif
 	NULL,			/* flush */
 	ext2_release_file,	/* release */
 	ext2_sync_file,		/* fsync */
@@ -111,8 +121,12 @@
 			offset += file->f_pos;
 	}
 	if (((unsigned long long) offset >> 32) != 0) {
+#if BITS_PER_LONG < 64
+		return -EINVAL;
+#else
 		if (offset > ext2_max_sizes[EXT2_BLOCK_SIZE_BITS(inode->i_sb)])
 			return -EINVAL;
+#endif
 	} 
 	if (offset != file->f_pos) {
 		file->f_pos = offset;
@@ -141,7 +155,7 @@
 				size_t count, loff_t *ppos)
 {
 	struct inode * inode = filp->f_dentry->d_inode;
-	loff_t pos;
+	off_t pos;
 	long block;
 	int offset;
 	int written, c;
@@ -188,18 +202,24 @@
 
 	/* Check for overflow.. */
 
-	/* L-F-S spec 2.2.1.27: */
-	if (!(filp->f_flags & O_LARGEFILE)) {
-		if (pos >= 0x7ffffffeULL) /* pos@2G forbidden */
+#if BITS_PER_LONG < 64
+	/* If the fd's pos is already greater than or equal to the file
+	 * descriptor's offset maximum, then we need to return EFBIG for
+	 * any non-zero count (and we already tested for zero above). */
+	if (((unsigned) pos) >= 0x7FFFFFFFUL)
+		return -EFBIG;
+	
+	/* If we are about to overflow the maximum file size, we also
+	 * need to return the error, but only if no bytes can be written
+	 * successfully. */
+	if (((unsigned) pos + count) > 0x7FFFFFFFUL) {
+		count = 0x7FFFFFFFL - pos;
+		if (((signed) count) < 0)
 			return -EFBIG;
-
-		if (pos + count >= 0x7fffffffULL)
-			/* Write only until end of allowed region */
-			count = 0x7fffffffULL - pos;
 	}
-
+#else
 	{
-		loff_t max = ext2_max_sizes[EXT2_BLOCK_SIZE_BITS(sb)];
+		off_t max = ext2_max_sizes[EXT2_BLOCK_SIZE_BITS(sb)];
 
 		if (pos >= max)
 			return -EFBIG;
@@ -219,6 +239,7 @@
 			mark_buffer_dirty(sb->u.ext2_sb.s_sbh, 1);
 		}
 	}
+#endif
 
 	/* From SUS: We must generate a SIGXFSZ for file size overflow
 	 * only if no bytes were actually written to the file. --sct */
@@ -361,3 +382,15 @@
 	return 0;
 }
 
+#if BITS_PER_LONG < 64
+/*
+ * Called when an inode is about to be open.
+ * We use this to disallow opening RW large files on 32bit systems.
+ */
+static int ext2_open_file (struct inode * inode, struct file * filp)
+{
+	if (inode->u.ext2_i.i_high_size && (filp->f_mode & FMODE_WRITE))
+		return -EFBIG;
+	return 0;
+}
+#endif
Index: oldkernel/linux/fs/ext2/ialloc.c
diff -u linux/fs/ext2/ialloc.c:1.1.1.1 linux/fs/ext2/ialloc.c:1.2
--- linux/fs/ext2/ialloc.c:1.1.1.1	Wed May 31 12:33:48 2000
+++ linux/fs/ext2/ialloc.c	Fri Jul  7 15:36:45 2000
@@ -478,8 +478,14 @@
 	if (inode->u.ext2_i.i_flags & EXT2_SYNC_FL)
 		inode->i_flags |= MS_SYNCHRONOUS;
 	insert_inode_hash(inode);
+	/* 
+	 *   dhXXX:
+	 *  To be really picky we should set i_generation to one more than
+	 *  whatever's on the disk, to ensure a monotonic advance of 
+	 *  generation for NFS.  But the odds of duplicating the last igen 
+	 *  are only 1 in 2^32...
+	 */
 	inode->i_generation = inode_generation_count++;
-	inode->u.ext2_i.i_version = inode->i_generation;
 	mark_inode_dirty(inode);
 
 	unlock_super (sb);
Index: oldkernel/linux/fs/ext2/inode.c
diff -u linux/fs/ext2/inode.c:1.2 linux/fs/ext2/inode.c:1.3
--- linux/fs/ext2/inode.c:1.2	Thu Jun  1 15:03:08 2000
+++ linux/fs/ext2/inode.c	Fri Jul  7 15:36:45 2000
@@ -47,14 +47,14 @@
  */
 void ext2_delete_inode (struct inode * inode)
 {
-	if (inode->i_ino == EXT2_ACL_IDX_INO ||
+	if (is_bad_inode(inode) ||
+	    inode->i_ino == EXT2_ACL_IDX_INO ||
 	    inode->i_ino == EXT2_ACL_DATA_INO)
 		return;
 	inode->u.ext2_i.i_dtime	= CURRENT_TIME;
-	/* When we delete an inode, we increment its i_version. If it
-	   is ever read in from disk again, it will have a different
-	   i_version. */
-	inode->u.ext2_i.i_version++;
+	/* When we delete an inode, we increment its i_generation.
+	   If it is read in from disk again, the generation will differ. */
+	inode->i_generation++;
 	mark_inode_dirty(inode);
 	ext2_update_inode(inode, IS_SYNC(inode));
 	inode->i_size = 0;
@@ -519,9 +519,20 @@
 	inode->i_ctime = le32_to_cpu(raw_inode->i_ctime);
 	inode->i_mtime = le32_to_cpu(raw_inode->i_mtime);
 	inode->u.ext2_i.i_dtime = le32_to_cpu(raw_inode->i_dtime);
+	/* We now have enough fields to check if the inode was active or not.
+	 * This is needed because nfsd might try to access dead inodes
+	 * the test is that same one that e2fsck uses
+	 * NeilBrown 1999oct15
+	 */
+	if (inode->i_nlink == 0 && (inode->i_mode == 0 || inode->u.ext2_i.i_dtime)) {
+		/* this inode is deleted */
+		brelse (bh);
+		goto bad_inode;
+	}
 	inode->i_blksize = PAGE_SIZE;	/* This is the optimal IO size (for stat), not the fs block size */
 	inode->i_blocks = le32_to_cpu(raw_inode->i_blocks);
 	inode->i_version = ++global_event;
+	inode->i_generation = le32_to_cpu(raw_inode->i_generation);
 	inode->u.ext2_i.i_new_inode = 0;
 	inode->u.ext2_i.i_flags = le32_to_cpu(raw_inode->i_flags);
 	inode->u.ext2_i.i_faddr = le32_to_cpu(raw_inode->i_faddr);
@@ -533,11 +544,16 @@
 		inode->u.ext2_i.i_dir_acl = le32_to_cpu(raw_inode->i_dir_acl);
 	else {
 		inode->u.ext2_i.i_dir_acl = 0;
-		inode->i_size = ((__u64)(inode->i_size & 0xFFFFFFFFUL)) |
-			(((__u64)le32_to_cpu(raw_inode->i_size_high)) << 32);
+		inode->u.ext2_i.i_high_size =
+			le32_to_cpu(raw_inode->i_size_high);
+#if BITS_PER_LONG < 64
+		if (raw_inode->i_size_high)
+			inode->i_size = (__u32)-1;
+#else
+		inode->i_size |= ((__u64)le32_to_cpu(raw_inode->i_size_high))
+			<< 32;
+#endif
 	}
-	inode->u.ext2_i.i_version = le32_to_cpu(raw_inode->i_version);
-	inode->i_generation = inode->u.ext2_i.i_version;
 	inode->u.ext2_i.i_block_group = block_group;
 	inode->u.ext2_i.i_next_alloc_block = 0;
 	inode->u.ext2_i.i_next_alloc_goal = 0;
@@ -651,6 +667,7 @@
 	raw_inode->i_ctime = cpu_to_le32(inode->i_ctime);
 	raw_inode->i_mtime = cpu_to_le32(inode->i_mtime);
 	raw_inode->i_blocks = cpu_to_le32(inode->i_blocks);
+	raw_inode->i_generation = cpu_to_le32(inode->i_generation);
 	raw_inode->i_dtime = cpu_to_le32(inode->u.ext2_i.i_dtime);
 	raw_inode->i_flags = cpu_to_le32(inode->u.ext2_i.i_flags);
 	raw_inode->i_faddr = cpu_to_le32(inode->u.ext2_i.i_faddr);
@@ -660,9 +677,13 @@
 	if (S_ISDIR(inode->i_mode))
 		raw_inode->i_dir_acl = cpu_to_le32(inode->u.ext2_i.i_dir_acl);
 	else { 
+#if BITS_PER_LONG < 64
+		raw_inode->i_size_high =
+			cpu_to_le32(inode->u.ext2_i.i_high_size);
+#else
 		raw_inode->i_size_high = cpu_to_le32(inode->i_size >> 32);
+#endif
 	}
-	raw_inode->i_version = cpu_to_le32(inode->u.ext2_i.i_version);
 	if (S_ISCHR(inode->i_mode) || S_ISBLK(inode->i_mode))
 		raw_inode->i_block[0] = cpu_to_le32(kdev_t_to_nr(inode->i_rdev));
 	else if (S_ISLNK(inode->i_mode) && !inode->i_blocks)
@@ -716,18 +737,21 @@
 	}
 
 	if (iattr->ia_valid & ATTR_SIZE) {
-		loff_t size = iattr->ia_size;
+		off_t size = iattr->ia_size;
 		unsigned long limit = current->rlim[RLIMIT_FSIZE].rlim_cur;
 
 		if (size < 0)
 			return -EINVAL;
+#if BITS_PER_LONG == 64	
 		if (size > ext2_max_sizes[EXT2_BLOCK_SIZE_BITS(inode->i_sb)])
 			return -EFBIG;
+#endif
 		if (limit < RLIM_INFINITY && size > limit) {
 			send_sig(SIGXFSZ, current, 0);
 			return -EFBIG;
 		}
 
+#if BITS_PER_LONG == 64	
 		if (size >> 33) {
 			struct super_block *sb = inode->i_sb;
 			struct ext2_super_block *es = sb->u.ext2_sb.s_es;
@@ -740,6 +764,7 @@
 				mark_buffer_dirty(sb->u.ext2_sb.s_sbh, 1);
 			}
 		}
+#endif
 	}
 	
 	retval = inode_change_ok(inode, iattr);
Index: oldkernel/linux/fs/ext2/ioctl.c
diff -u linux/fs/ext2/ioctl.c:1.1.1.1 linux/fs/ext2/ioctl.c:1.2
--- linux/fs/ext2/ioctl.c:1.1.1.1	Wed May 31 12:33:48 2000
+++ linux/fs/ext2/ioctl.c	Fri Jul  7 15:36:45 2000
@@ -68,15 +68,14 @@
 		mark_inode_dirty(inode);
 		return 0;
 	case EXT2_IOC_GETVERSION:
-		return put_user(inode->u.ext2_i.i_version, (int *) arg);
+		return put_user(inode->i_generation, (int *) arg);
 	case EXT2_IOC_SETVERSION:
 		if ((current->fsuid != inode->i_uid) && !capable(CAP_FOWNER))
 			return -EPERM;
 		if (IS_RDONLY(inode))
 			return -EROFS;
-		if (get_user(inode->u.ext2_i.i_version, (int *) arg))
+		if (get_user(inode->i_generation, (int *) arg))
 			return -EFAULT;	
-		inode->i_generation = inode->u.ext2_i.i_version;
 		inode->i_ctime = CURRENT_TIME;
 		mark_inode_dirty(inode);
 		return 0;
Index: oldkernel/linux/fs/ext2/truncate.c
diff -u linux/fs/ext2/truncate.c:1.2 linux/fs/ext2/truncate.c:1.3
--- linux/fs/ext2/truncate.c:1.2	Thu Jun  1 15:03:08 2000
+++ linux/fs/ext2/truncate.c	Fri Jul  7 15:36:45 2000
@@ -53,10 +53,9 @@
  * Currently we always hold the inode semaphore during truncate, so
  * there's no need to test for changes during the operation.
  */
-#define DIRECT_BLOCK(inode)	\
-	((long)			\
-	 ((inode->i_size + inode->i_sb->s_blocksize - 1) >> \
-			  inode->i_sb->s_blocksize_bits))
+#define DIRECT_BLOCK(inode) \
+	((inode->i_size + inode->i_sb->s_blocksize - 1) / \
+			  inode->i_sb->s_blocksize)
 #define INDIRECT_BLOCK(inode,offset) ((int)DIRECT_BLOCK(inode) - offset)
 #define DINDIRECT_BLOCK(inode,offset) \
 	(INDIRECT_BLOCK(inode,offset) / addr_per_block)
Index: oldkernel/linux/fs/ext3/CHANGES
diff -u /dev/null linux/fs/ext3/CHANGES:1.1
--- /dev/null	Mon Jul 31 21:15:07 2000
+++ linux/fs/ext3/CHANGES	Fri Jul  7 16:34:57 2000
@@ -0,0 +1,157 @@
+Changes from version 0.5a to version 0.5b
+=========================================
+	- Now that we have sysctl(), the immutable flag cannot be changed when
+	  the system is running at security level > 0.
+	- Some cleanups in the code.
+	- More consistency checks on directories.
+	- The ext2.diff patch from Tom May <ftom@netcom.com> has been
+	  integrated.  This patch replaces expensive "/" and "%" with
+	  cheap ">>" and "&" where possible.
+
+Changes from version 0.5 to version 0.5a
+========================================
+	- Zero the partial block following the end of the file when a file
+	  is truncated.
+	- Dates updated in the copyright.
+	- More checks when the filesystem is mounted: the count of blocks,
+	  fragments, and inodes per group is checked against the block size.
+	- The buffers used by the error routines are now static variables, to
+	  avoid using space on the kernel stack, as requested by Linus.
+	- Some cleanups in the error messages (some versions of syslog contain
+	  a bug which truncates an error message if it contains '\n').
+	- Check that no data can be written to a file past the 2GB limit.
+	- The famous readdir() bug has been fixed by Stephen Tweedie.
+	- Added a revision level in the superblock.
+	- Full support for O_SYNC flag of the open system call.
+	- New mount options: `resuid=#uid' and `resgid=#gid'.  `resuid' causes
+	  ext2fs to consider user #uid like root for the reserved blocks.
+	  `resgid' acts the same way with group #gid.  New fields in the
+	  superblock contain default values for resuid and resgid and can
+	  be modified by tune2fs.
+	  Idea comes from Rene Cougnenc <cougnenc@renux.frmug.fr.net>.
+	- New mount options: `bsddf' and `minixdf'.  `bsddf' causes ext2fs
+	  to remove the blocks used for FS structures from the total block
+	  count in statfs.  With `minixdf', ext2fs mimics Minix behavior
+	  in statfs (i.e. it returns the total number of blocks on the
+	  partition).  This is intended to make bde happy :-)
+	- New file attributes:
+	  - Immutable files cannot be modified.  Data cannot be written to
+	    these files.  They cannot be removed, renamed and new links cannot
+	    be created.  Even root cannot modify the files.  He has to remove
+	    the immutable attribute first.
+	  - Append-only files: can only be written in append-mode when writing.
+	    They cannot be removed, renamed and new links cannot be created.
+	    Note: files may only be added to an append-only directory.
+	  - No-dump files: the attribute is not used by the kernel.  My port
+	    of dump uses it to avoid backing up files which are not important.
+	- New check in ext2_check_dir_entry: the inode number is checked.
+	- Support for big file systems: the copy of the FS descriptor is now
+	  dynamically allocated (previous versions used a fixed size array).
+	  This allows to mount 2GB+ FS.
+	- Reorganization of the ext2_inode structure to allow other operating
+	  systems to create specific fields if they use ext2fs as their native
+	  file system.  Currently, ext2fs is only implemented in Linux but
+	  will soon be part of Gnu Hurd and of Masix.
+
+Changes from version 0.4b to version 0.5
+========================================
+	- New superblock fields: s_lastcheck and s_checkinterval added
+	  by Uwe Ohse <uwe@tirka.gun.de> to implement timedependent checks
+	  of the file system
+	- Real random numbers for secure rm added by Pierre del Perugia
+	  <delperug@gla.ecoledoc.ibp.fr>
+	- The mount warnings related to the state of a fs are not printed
+	  if the fs is mounted read-only, idea by Nick Holloway
+	  <alfie@dcs.warwick.ac.uk>
+
+Changes from version 0.4a to version 0.4b
+=========================================
+	- Copyrights changed to include the name of my laboratory.
+	- Clean up of balloc.c and ialloc.c.
+	- More consistency checks.
+	- Block preallocation added by Stephen Tweedie.
+	- Direct reads of directories disallowed.
+	- Readahead implemented in readdir by Stephen Tweedie.
+	- Bugs in block and inodes allocation fixed.
+	- Readahead implemented in ext2_find_entry by Chip Salzenberg.
+	- New mount options:
+	  `check=none|normal|strict'
+	  `debug'
+	  `errors=continue|remount-ro|panic'
+	  `grpid', `bsdgroups'
+	  `nocheck'
+	  `nogrpid', `sysvgroups'
+	- truncate() now tries to deallocate contiguous blocks in a single call
+	  to ext2_free_blocks().
+	- lots of cosmetic changes.
+
+Changes from version 0.4 to version 0.4a
+========================================
+        - the `sync' option support is now complete.  Version 0.4 was not
+          supporting it when truncating a file.  I have tested the synchronous
+          writes and they work but they make the system very slow :-(  I have
+          to work again on this to make it faster.
+        - when detecting an error on a mounted filesystem, version 0.4 used
+          to try to write a flag in the super block even if the filesystem had
+          been mounted read-only.  This is fixed.
+        - the `sb=#' option now causes the kernel code to use the filesystem
+          descriptors located at block #+1.  Version 0.4 used the superblock
+          backup located at block # but used the main copy of the descriptors.
+        - a new file attribute `S' is supported.  This attribute causes
+          synchronous writes but is applied to a file not to the entire file
+          system (thanks to Michael Kraehe <kraehe@bakunin.north.de> for
+          suggesting it).
+        - the directory cache is inhibited by default.  The cache management
+          code seems to be buggy and I have to look at it carefully before
+          using it again.
+        - deleting a file with the `s' attribute (secure deletion) causes its
+          blocks to be overwritten with random values not with zeros (thanks to
+          Michael A. Griffith <grif@cs.ucr.edu> for suggesting it).
+        - lots of cosmetic changes have been made.
+
+Changes from version 0.3 to version 0.4
+=======================================
+        - Three new mount options are supported: `check', `sync' and `sb=#'.
+          `check' tells the kernel code to make more consistency checks
+          when the file system is mounted.  Currently, the kernel code checks
+          that the blocks and inodes bitmaps are consistent with the free
+          blocks and inodes counts.  More checks will be added in future
+          releases.
+          `sync' tells the kernel code to use synchronous writes when updating
+          an inode, a bitmap, a directory entry or an indirect block.  This
+          can make the file system much slower but can be a big win for files
+          recovery in case of a crash (and we can now say to the BSD folks
+          that Linux also supports synchronous updates :-).
+          `sb=#' tells the kernel code to use an alternate super block instead
+          of its master copy.  `#' is the number of the block (counted in
+          1024 bytes blocks) which contains the alternate super block.
+          An ext2 file system typically contains backups of the super block
+          at blocks 8193, 16385, and so on.
+        - I have change the meaning of the valid flag used by e2fsck.  it
+          now contains the state of the file system.  If the kernel code
+          detects an inconsistency while the file system is mounted, it flags
+          it as erroneous and e2fsck will detect that on next run.
+        - The super block now contains a mount counter.  This counter is
+          incremented each time the file system is mounted read/write.   When
+          this counter becomes bigger than a maximal mount counts (also stored
+          in the super block), e2fsck checks the file system, even if it had
+          been unmounted cleanly, and resets this counter to 0.
+        - File attributes are now supported.  One can associate a set of
+          attributes to a file.  Three attributes are defined:
+          `c': the file is marked for automatic compression,
+          `s': the file is marked for secure deletion: when the file is
+          deleted, its blocks are zeroed and written back to the disk,
+          `u': the file is marked for undeletion: when the file is deleted,
+          its contents are saved to allow a future undeletion.
+          Currently, only the `s' attribute is implemented in the kernel
+          code.  Support for the other attributes will be added in a future
+          release.
+        - a few bugs related to times updates have been fixed by Bruce
+          Evans and me.
+        - a bug related to the links count of deleted inodes has been fixed.
+          Previous versions used to keep the links count set to 1 when a file
+          was deleted.  The new version now sets links_count to 0 when deleting
+          the last link.
+        - a race condition when deallocating an inode has been fixed by
+          Stephen Tweedie.
+
Index: oldkernel/linux/fs/ext3/Makefile
diff -u /dev/null linux/fs/ext3/Makefile:1.1
--- /dev/null	Mon Jul 31 21:15:07 2000
+++ linux/fs/ext3/Makefile	Fri Jul  7 16:34:57 2000
@@ -0,0 +1,15 @@
+#
+# Makefile for the linux ext2-filesystem routines.
+#
+# Note! Dependencies are done automagically by 'make dep', which also
+# removes any old dependencies. DON'T put your own dependencies here
+# unless it's something special (ie not a .c file).
+#
+# Note 2! The CFLAGS definitions are now in the main makefile...
+
+O_TARGET := ext3.o
+O_OBJS   := acl.o balloc.o bitmap.o dir.o file.o fsync.o ialloc.o inode.o \
+		ioctl.o namei.o super.o symlink.o truncate.o
+M_OBJS   := $(O_TARGET)
+
+include $(TOPDIR)/Rules.make
Index: oldkernel/linux/fs/ext3/TODO
diff -u /dev/null linux/fs/ext3/TODO:1.1
--- /dev/null	Mon Jul 31 21:15:07 2000
+++ linux/fs/ext3/TODO	Fri Jul  7 16:34:57 2000
@@ -0,0 +1,102 @@
+In the middle of doing:
+
+namei.c: got as far as mknod + create
+
+Next:
+
+ext3_new_inode()
+
+* jfs/commit.c:	Free up b_committed_data if appropriate
+
+Longer term:
+
+
+* fs/buffer.c: on IO completion, remove BJ_Data buffers from their
+		transaction list.  Need to think about the locking
+		implications of this one!
+
+		Perhaps use a call into the journaling code to scan
+		the current transactions from bdflushd?
+
+* All:		Think about error recovery a bit more.
+
+* ext3/super.c:	Set up superblock journaling flags on mount/dismount
+		
+		Think about how to mount a journaled filesystem readonly!
+
+* fs/journal.c:	Cache the entire bmap data for the journal for performance
+
+* fs/journal.c: Redundant copies of the journal superblock.
+
+* All:		When deleting metadata, we need a special transaction
+		record to obsolete older copies of that data in the
+		log.  This is necessary to avoid recovering that old
+		data if we subsequently reallocate the block for data.
+		Only required for non-journaled data.
+
+* ext3/balloc.c:Think about preallocation.  Disable it for now, but we
+		may be able to deal with it by recording preallocation
+		in separate bitmap buffers outside of recovery.  That 
+		pins buffers in cache, tho: an undo mechanism would be
+		the most general-purpose solution.
+
+* All: 		Ensure that we preserve lock ranking.  Journal lock is of
+		higher rank than the buffer lock.  (Done, I think;
+		still need to audit it.)
+
+* fs/transaction.c:
+		Make sure commit does the right things if we don't do a
+		journal_dirty_* on a bh after getting write access.
+
+* ext3/ialloc.c, balloc.c:
+		What happens if we drop the superblock locks here?
+		Getting write access on the bitmap buffers may block.
+		Ugh.  Return -EGAIN and restart the transaction??
+
+* All:		Test out readonly mode (especially wrt. null handles!)
+
+* ext3/fsync.c:	Add transactions.  ext3_sync_inode doesn't complete the 
+		transaction on its own.
+
+* fs.h:		Remove BH_Temp?
+ 
+* ext3/super.c:	Add remount of JFS_SYNC, maybe?
+
+Done:
+
+* fs/buffer.c:	Add infrastructure for journaled sync().  Hmm.
+
+* ext3/fsync.c:	Add transactions.  ext3_sync_inode doesn't complete the 
+		transaction on its own.
+
+* fs/journal.c:	Get the endianness right!
+
+* ext3/inode.c:	Prevent ext3_write_inode from flushing a buffer which is
+		on a journal list.  Journal the update if necessary.
+
+* ext3/super.c:	Make ext3_put_super do something sane.
+
+* ext3/namei.c:	Whoops, fixed ext3_mknod: it was doing an
+		ext3_mark_iloc_dirty on the wrong inode.  Directory
+		corrupter!
+
+* jfs/checkpoint.c:
+		Fixed a stupid bug in the management of the checkpoint
+		buffer wait queue.  Checkpoint has a chance of being
+		reliable now.
+
+* ext3/super.c:	Don't load the journal if the _HAS_JOURNAL feature is
+		clear, even if there is a journal inum in the
+		superblock.  If the user has used debugfs or e2fsck to
+		restore the fs to ext2, we want to be absolutely sure
+		we don't replay the journal by accident!
+
+* ext3/super.c: Lots of fixes in the setting/processing of the
+		NEEDS_RECOVERY flag.
+
+* ext3/super.c: Release the journal on umount even on a readonly filesystem.
+
+* fs/buffer.c:	Be a little more cautious about bforget()ing
+		checkpointed buffers, in case other software (such as
+		background soft raid resync) is trying to access the
+		buffer cache behind our backs. 
Index: oldkernel/linux/fs/ext3/acl.c
diff -u /dev/null linux/fs/ext3/acl.c:1.1
--- /dev/null	Mon Jul 31 21:15:07 2000
+++ linux/fs/ext3/acl.c	Fri Jul  7 16:34:57 2000
@@ -0,0 +1,61 @@
+/*
+ * linux/fs/ext3/acl.c
+ *
+ * Copyright (C) 1993, 1994, 1995
+ * Remy Card (card@masi.ibp.fr)
+ * Laboratoire MASI - Institut Blaise Pascal
+ * Universite Pierre et Marie Curie (Paris VI)
+ */
+
+/*
+ * This file will contain the Access Control Lists management for the
+ * second extended file system.
+ */
+
+#include <linux/errno.h>
+#include <linux/fs.h>
+#include <linux/ext3_fs.h>
+#include <linux/sched.h>
+#include <linux/stat.h>
+
+/*
+ * ext3_permission ()
+ *
+ * Check for access rights
+ */
+int ext3_permission (struct inode * inode, int mask)
+{
+	unsigned short mode = inode->i_mode;
+
+	/*
+	 * Nobody gets write access to a file on a readonly-fs
+	 */
+	if ((mask & S_IWOTH) && 
+            (S_ISREG(mode) || S_ISDIR(mode) || S_ISLNK(mode)) &&
+            IS_RDONLY(inode))
+		return -EROFS;
+	/*
+	 * Nobody gets write access to an immutable file
+	 */
+	if ((mask & S_IWOTH) && IS_IMMUTABLE(inode))
+		return -EACCES;
+
+	/*
+	 * If no ACL, checks using the file mode
+	 */
+	else if (current->fsuid == inode->i_uid)
+		mode >>= 6;
+	else if (in_group_p (inode->i_gid))
+		mode >>= 3;
+	/*
+	 * Access is always granted for root. We now check last,
+         * though, for BSD process accounting correctness
+	 */
+	if (((mode & mask & S_IRWXO) == mask) || capable(CAP_DAC_OVERRIDE))
+		return 0;
+	if ((mask == S_IROTH) ||
+	    (S_ISDIR(mode)  && !(mask & ~(S_IROTH | S_IXOTH))))
+		if (capable(CAP_DAC_READ_SEARCH))
+			return 0;
+	return -EACCES;
+}
Index: oldkernel/linux/fs/ext3/balloc.c
diff -u /dev/null linux/fs/ext3/balloc.c:1.1
--- /dev/null	Mon Jul 31 21:15:07 2000
+++ linux/fs/ext3/balloc.c	Fri Jul  7 16:34:57 2000
@@ -0,0 +1,781 @@
+/*
+ *  linux/fs/ext3/balloc.c
+ *
+ * Copyright (C) 1992, 1993, 1994, 1995
+ * Remy Card (card@masi.ibp.fr)
+ * Laboratoire MASI - Institut Blaise Pascal
+ * Universite Pierre et Marie Curie (Paris VI)
+ *
+ *  Enhanced block allocation by Stephen Tweedie (sct@dcs.ed.ac.uk), 1993
+ *  Big-endian to little-endian byte-swapping/bitmaps by
+ *        David S. Miller (davem@caip.rutgers.edu), 1995
+ */
+
+/*
+ * balloc.c contains the blocks allocation and deallocation routines
+ */
+
+/*
+ * The free blocks are managed by bitmaps.  A file system contains several
+ * blocks groups.  Each group contains 1 bitmap block for blocks, 1 bitmap
+ * block for inodes, N blocks for the inode table and data blocks.
+ *
+ * The file system contains group descriptors which are located after the
+ * super block.  Each descriptor contains the number of the bitmap block and
+ * the free blocks count in the block.  The descriptors are loaded in memory
+ * when a file system is mounted (see ext3_read_super).
+ */
+
+#include <linux/sched.h>
+#include <linux/fs.h>
+#include <linux/ext3_fs.h>
+#include <linux/ext3_jfs.h>
+#include <linux/stat.h>
+#include <linux/string.h>
+#include <linux/locks.h>
+#include <linux/quotaops.h>
+
+#include <asm/bitops.h>
+#include <asm/byteorder.h>
+
+#define in_range(b, first, len)		((b) >= (first) && (b) <= (first) + (len) - 1)
+
+struct ext3_group_desc * ext3_get_group_desc(struct super_block * sb,
+					     unsigned int block_group,
+					     struct buffer_head ** bh)
+{
+	unsigned long group_desc;
+	unsigned long desc;
+	struct ext3_group_desc * gdp;
+
+	if (block_group >= sb->u.ext3_sb.s_groups_count) {
+		ext3_error (sb, "ext3_get_group_desc",
+			    "block_group >= groups_count - "
+			    "block_group = %d, groups_count = %lu",
+			    block_group, sb->u.ext3_sb.s_groups_count);
+
+		return NULL;
+	}
+	
+	group_desc = block_group / EXT3_DESC_PER_BLOCK(sb);
+	desc = block_group % EXT3_DESC_PER_BLOCK(sb);
+	if (!sb->u.ext3_sb.s_group_desc[group_desc]) {
+		ext3_error (sb, "ext3_get_group_desc",
+			    "Group descriptor not loaded - "
+			    "block_group = %d, group_desc = %lu, desc = %lu",
+			     block_group, group_desc, desc);
+		return NULL;
+	}
+	
+	gdp = (struct ext3_group_desc *) 
+	      sb->u.ext3_sb.s_group_desc[group_desc]->b_data;
+	if (bh)
+		*bh = sb->u.ext3_sb.s_group_desc[group_desc];
+	return gdp + desc;
+}
+
+/*
+ * Read the bitmap for a given block_group, reading into the specified 
+ * slot in the superblock's bitmap cache.
+ *
+ * Return >=0 on success or a -ve error code.
+ */
+
+static int read_block_bitmap (struct super_block * sb,
+			       unsigned int block_group,
+			       unsigned long bitmap_nr)
+{
+	struct ext3_group_desc * gdp;
+	struct buffer_head * bh = NULL;
+	int retval = -EIO;
+	
+	gdp = ext3_get_group_desc (sb, block_group, NULL);
+	if (!gdp)
+		goto error_out;
+	retval = 0;
+	bh = bread (sb->s_dev, le32_to_cpu(gdp->bg_block_bitmap), sb->s_blocksize);
+	if (!bh) {
+		ext3_error (sb, "read_block_bitmap",
+			    "Cannot read block bitmap - "
+			    "block_group = %d, block_bitmap = %lu",
+			    block_group, (unsigned long) gdp->bg_block_bitmap);
+		retval = -EIO;
+	}
+	/*
+	 * On IO error, just leave a zero in the superblock's block pointer for
+	 * this group.  The IO will be retried next time.
+	 */
+error_out:
+	sb->u.ext3_sb.s_block_bitmap_number[bitmap_nr] = block_group;
+	sb->u.ext3_sb.s_block_bitmap[bitmap_nr] = bh;
+	return retval;
+}
+
+/*
+ * load_block_bitmap loads the block bitmap for a blocks group
+ *
+ * It maintains a cache for the last bitmaps loaded.  This cache is managed
+ * with a LRU algorithm.
+ *
+ * Notes:
+ * 1/ There is one cache per mounted file system.
+ * 2/ If the file system contains less than EXT3_MAX_GROUP_LOADED groups,
+ *    this function reads the bitmap without maintaining a LRU cache.
+ * 
+ * Return the slot used to store the bitmap, or a -ve error code.
+ */
+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;
+
+	if (block_group >= sb->u.ext3_sb.s_groups_count)
+		ext3_panic (sb, "load_block_bitmap",
+			    "block_group >= groups_count - "
+			    "block_group = %d, groups_count = %lu",
+			    block_group, sb->u.ext3_sb.s_groups_count);
+
+	if (sb->u.ext3_sb.s_groups_count <= EXT3_MAX_GROUP_LOADED) {
+		if (sb->u.ext3_sb.s_block_bitmap[block_group]) {
+			if (sb->u.ext3_sb.s_block_bitmap_number[block_group] ==
+			    block_group)
+				return block_group;
+			ext3_error (sb, "load_block_bitmap",
+				    "block_group != block_bitmap_number");
+		}
+		retval = read_block_bitmap (sb, block_group, block_group);
+		if (retval < 0)
+			return retval;
+		return block_group;
+	}
+
+	for (i = 0; i < sb->u.ext3_sb.s_loaded_block_bitmaps &&
+		    sb->u.ext3_sb.s_block_bitmap_number[i] != block_group; i++)
+		;
+	if (i < sb->u.ext3_sb.s_loaded_block_bitmaps &&
+  	    sb->u.ext3_sb.s_block_bitmap_number[i] == block_group) {
+		block_bitmap_number = sb->u.ext3_sb.s_block_bitmap_number[i];
+		block_bitmap = sb->u.ext3_sb.s_block_bitmap[i];
+		for (j = i; j > 0; j--) {
+			sb->u.ext3_sb.s_block_bitmap_number[j] =
+				sb->u.ext3_sb.s_block_bitmap_number[j - 1];
+			sb->u.ext3_sb.s_block_bitmap[j] =
+				sb->u.ext3_sb.s_block_bitmap[j - 1];
+		}
+		sb->u.ext3_sb.s_block_bitmap_number[0] = block_bitmap_number;
+		sb->u.ext3_sb.s_block_bitmap[0] = block_bitmap;
+
+		/*
+		 * There's still one special case here --- if block_bitmap == 0
+		 * then our last attempt to read the bitmap failed and we have
+		 * just ended up caching that failure.  Try again to read it.
+		 */
+		if (!block_bitmap)
+			retval = read_block_bitmap (sb, block_group, 0);
+	} else {
+		if (sb->u.ext3_sb.s_loaded_block_bitmaps < EXT3_MAX_GROUP_LOADED)
+			sb->u.ext3_sb.s_loaded_block_bitmaps++;
+		else
+			brelse (sb->u.ext3_sb.s_block_bitmap[EXT3_MAX_GROUP_LOADED - 1]);
+		for (j = sb->u.ext3_sb.s_loaded_block_bitmaps - 1; j > 0;  j--) {
+			sb->u.ext3_sb.s_block_bitmap_number[j] =
+				sb->u.ext3_sb.s_block_bitmap_number[j - 1];
+			sb->u.ext3_sb.s_block_bitmap[j] =
+				sb->u.ext3_sb.s_block_bitmap[j - 1];
+		}
+		retval = read_block_bitmap (sb, block_group, 0);
+	}
+	return retval;
+}
+
+/*
+ * Load the block bitmap for a given block group.  First of all do a couple
+ * of fast lookups for common cases and then pass the request onto the guts
+ * of the bitmap loader.
+ *
+ * Return the slot number of the group in the superblock bitmap cache's on
+ * success, or a -ve error code.
+ *
+ * There is still one inconsistancy here --- if the number of groups in this
+ * filesystems is <= EXT3_MAX_GROUP_LOADED, then we have no way of 
+ * differentiating between a group for which we have never performed a bitmap
+ * IO request, and a group for which the last bitmap read request failed.
+ */
+static inline int load_block_bitmap (struct super_block * sb,
+				     unsigned int block_group)
+{
+	int slot;
+	
+	/*
+	 * Do the lookup for the slot.  First of all, check if we're asking
+	 * for the same slot as last time, and did we succeed that last time?
+	 */
+	if (sb->u.ext3_sb.s_loaded_block_bitmaps > 0 &&
+	    sb->u.ext3_sb.s_block_bitmap_number[0] == block_group &&
+	    sb->u.ext3_sb.s_block_bitmap[block_group]) {
+		return 0;
+	}
+	/*
+	 * Or can we do a fast lookup based on a loaded group on a filesystem
+	 * small enough to be mapped directly into the superblock?
+	 */
+	else if (sb->u.ext3_sb.s_groups_count <= EXT3_MAX_GROUP_LOADED && 
+		 sb->u.ext3_sb.s_block_bitmap_number[block_group] == block_group &&
+		 sb->u.ext3_sb.s_block_bitmap[block_group]) {
+		slot = block_group;
+	}
+	/*
+	 * If not, then do a full lookup for this block group.
+	 */
+	else {
+		slot = load__block_bitmap (sb, block_group);
+	}
+
+	/*
+	 * <0 means we just got an error
+	 */
+	if (slot < 0)
+		return slot;
+	
+	/*
+	 * If it's a valid slot, we may still have cached a previous IO error,
+	 * in which case the bh in the superblock cache will be zero.
+	 */
+	if (!sb->u.ext3_sb.s_block_bitmap[slot])
+		return -EIO;
+	
+	/*
+	 * Must have been read in OK to get this far.
+	 */
+	return slot;
+}
+
+void ext3_free_blocks (handle_t *handle,
+		       const struct inode * inode, unsigned long block,
+		       unsigned long count)
+{
+	struct buffer_head * bh;
+	struct buffer_head * bh2;
+	unsigned long block_group;
+	unsigned long bit;
+	unsigned long i;
+	int bitmap_nr;
+	unsigned long overflow;
+	struct super_block * sb;
+	struct ext3_group_desc * gdp;
+	struct ext3_super_block * es;
+
+	sb = inode->i_sb;
+	if (!sb) {
+		printk ("ext3_free_blocks: nonexistent device");
+		return;
+	}
+	lock_super (sb);
+	es = sb->u.ext3_sb.s_es;
+	if (block < le32_to_cpu(es->s_first_data_block) || 
+	    (block + count) > le32_to_cpu(es->s_blocks_count)) {
+		ext3_error (sb, "ext3_free_blocks",
+			    "Freeing blocks not in datazone - "
+			    "block = %lu, count = %lu", block, count);
+		goto error_return;
+	}
+
+	ext3_debug ("freeing block %lu\n", block);
+
+do_more:
+	overflow = 0;
+	block_group = (block - le32_to_cpu(es->s_first_data_block)) /
+		      EXT3_BLOCKS_PER_GROUP(sb);
+	bit = (block - le32_to_cpu(es->s_first_data_block)) %
+		      EXT3_BLOCKS_PER_GROUP(sb);
+	/*
+	 * Check to see if we are freeing blocks across a group
+	 * boundary.
+	 */
+	if (bit + count > EXT3_BLOCKS_PER_GROUP(sb)) {
+		overflow = bit + count - EXT3_BLOCKS_PER_GROUP(sb);
+		count -= overflow;
+	}
+	bitmap_nr = load_block_bitmap (sb, block_group);
+	if (bitmap_nr < 0)
+		goto error_return;
+	
+	bh = sb->u.ext3_sb.s_block_bitmap[bitmap_nr];
+	gdp = ext3_get_group_desc (sb, block_group, &bh2);
+	if (!gdp)
+		goto error_return;
+
+	if (test_opt (sb, CHECK_STRICT) &&
+	    (in_range (le32_to_cpu(gdp->bg_block_bitmap), block, count) ||
+	     in_range (le32_to_cpu(gdp->bg_inode_bitmap), block, count) ||
+	     in_range (block, le32_to_cpu(gdp->bg_inode_table),
+		       sb->u.ext3_sb.s_itb_per_group) ||
+	     in_range (block + count - 1, le32_to_cpu(gdp->bg_inode_table),
+		       sb->u.ext3_sb.s_itb_per_group)))
+		ext3_panic (sb, "ext3_free_blocks",
+			    "Freeing blocks in system zones - "
+			    "Block = %lu, count = %lu",
+			    block, count);
+
+	journal_get_write_access(handle, bh);
+	journal_get_write_access(handle, bh2);
+	journal_get_write_access(handle, sb->u.ext3_sb.s_sbh);
+	
+	for (i = 0; i < count; i++) {
+		if (!ext3_clear_bit (bit + i, bh->b_data))
+			ext3_warning (sb, "ext3_free_blocks",
+				      "bit already cleared for block %lu", 
+				      block);
+		else {
+			DQUOT_FREE_BLOCK(sb, inode, 1);
+			gdp->bg_free_blocks_count =
+				cpu_to_le16(le16_to_cpu(gdp->bg_free_blocks_count)+1);
+			es->s_free_blocks_count =
+				cpu_to_le32(le32_to_cpu(es->s_free_blocks_count)+1);
+		}
+	}
+	
+	journal_dirty_metadata(handle, bh);
+	journal_dirty_metadata(handle, bh2);
+	journal_dirty_metadata(handle, sb->u.ext3_sb.s_sbh);
+
+	if (sb->s_flags & MS_SYNCHRONOUS)
+		handle->h_sync = 1;
+
+	if (overflow) {
+		block += count;
+		count = overflow;
+		goto do_more;
+	}
+	sb->s_dirt = 1;
+error_return:
+	unlock_super (sb);
+	return;
+}
+
+/*
+ * ext3_new_block uses a goal block to assist allocation.  If the goal is
+ * free, or there is a free block within 32 blocks of the goal, that block
+ * is allocated.  Otherwise a forward search is made for a free block; within 
+ * each block group the search first looks for an entire free byte in the block
+ * bitmap, and then for any free bit if that fails.
+ */
+int ext3_new_block (handle_t *handle,
+		    const struct inode * inode, unsigned long goal,
+		    u32 * prealloc_count, u32 * prealloc_block, int * err)
+{
+	struct buffer_head * bh;
+	struct buffer_head * bh2;
+	char * p, * r;
+	int i, j, k, tmp;
+	int bitmap_nr;
+	struct super_block * sb;
+	struct ext3_group_desc * gdp;
+	struct ext3_super_block * es;
+#ifdef EXT3FS_DEBUG
+	static int goal_hits = 0, goal_attempts = 0;
+#endif
+	*err = -ENOSPC;
+	sb = inode->i_sb;
+	if (!sb) {
+		printk ("ext3_new_block: nonexistent device");
+		return 0;
+	}
+
+	lock_super (sb);
+	es = sb->u.ext3_sb.s_es;
+	if (le32_to_cpu(es->s_free_blocks_count) <= le32_to_cpu(es->s_r_blocks_count) &&
+	    ((sb->u.ext3_sb.s_resuid != current->fsuid) &&
+	     (sb->u.ext3_sb.s_resgid == 0 ||
+	      !in_group_p (sb->u.ext3_sb.s_resgid)) && 
+	     !capable(CAP_SYS_RESOURCE))) {
+		unlock_super (sb);
+		return 0;
+	}
+
+	ext3_debug ("goal=%lu.\n", goal);
+
+repeat:
+	/*
+	 * First, test whether the goal block is free.
+	 */
+	if (goal < le32_to_cpu(es->s_first_data_block) ||
+	    goal >= le32_to_cpu(es->s_blocks_count))
+		goal = le32_to_cpu(es->s_first_data_block);
+	i = (goal - le32_to_cpu(es->s_first_data_block)) / EXT3_BLOCKS_PER_GROUP(sb);
+	gdp = ext3_get_group_desc (sb, i, &bh2);
+	if (!gdp)
+		goto io_error;
+
+	if (le16_to_cpu(gdp->bg_free_blocks_count) > 0) {
+		j = ((goal - le32_to_cpu(es->s_first_data_block)) % EXT3_BLOCKS_PER_GROUP(sb));
+#ifdef EXT3FS_DEBUG
+		if (j)
+			goal_attempts++;
+#endif
+		bitmap_nr = load_block_bitmap (sb, i);
+		if (bitmap_nr < 0)
+			goto io_error;
+		
+		bh = sb->u.ext3_sb.s_block_bitmap[bitmap_nr];
+
+		ext3_debug ("goal is at %d:%d.\n", i, j);
+
+		if (!ext3_test_bit(j, bh->b_data)) {
+#ifdef EXT3FS_DEBUG
+			goal_hits++;
+			ext3_debug ("goal bit allocated.\n");
+#endif
+			goto got_block;
+		}
+		if (j) {
+			/*
+			 * The goal was occupied; search forward for a free 
+			 * block within the next XX blocks.
+			 *
+			 * end_goal is more or less random, but it has to be
+			 * less than EXT3_BLOCKS_PER_GROUP. Aligning up to the
+			 * next 64-bit boundary is simple..
+			 */
+			int end_goal = (j + 63) & ~63;
+			j = ext3_find_next_zero_bit(bh->b_data, end_goal, j);
+			if (j < end_goal)
+				goto got_block;
+		}
+	
+		ext3_debug ("Bit not found near goal\n");
+
+		/*
+		 * There has been no free block found in the near vicinity
+		 * of the goal: do a search forward through the block groups,
+		 * searching in each group first for an entire free byte in
+		 * the bitmap and then for any free bit.
+		 * 
+		 * Search first in the remainder of the current group; then,
+		 * cyclicly search through the rest of the groups.
+		 */
+		p = ((char *) bh->b_data) + (j >> 3);
+		r = memscan(p, 0, (EXT3_BLOCKS_PER_GROUP(sb) - j + 7) >> 3);
+		k = (r - ((char *) bh->b_data)) << 3;
+		if (k < EXT3_BLOCKS_PER_GROUP(sb)) {
+			j = k;
+			goto search_back;
+		}
+
+		k = ext3_find_next_zero_bit ((unsigned long *) bh->b_data, 
+					EXT3_BLOCKS_PER_GROUP(sb),
+					j);
+		if (k < EXT3_BLOCKS_PER_GROUP(sb)) {
+			j = k;
+			goto got_block;
+		}
+	}
+
+	ext3_debug ("Bit not found in block group %d.\n", i);
+
+	/*
+	 * Now search the rest of the groups.  We assume that 
+	 * i and gdp correctly point to the last group visited.
+	 */
+	for (k = 0; k < sb->u.ext3_sb.s_groups_count; k++) {
+		i++;
+		if (i >= sb->u.ext3_sb.s_groups_count)
+			i = 0;
+		gdp = ext3_get_group_desc (sb, i, &bh2);
+		if (!gdp) {
+			*err = -EIO;
+			unlock_super (sb);
+			return 0;
+		}
+		if (le16_to_cpu(gdp->bg_free_blocks_count) > 0)
+			break;
+	}
+	if (k >= sb->u.ext3_sb.s_groups_count) {
+		unlock_super (sb);
+		return 0;
+	}
+	bitmap_nr = load_block_bitmap (sb, i);
+	if (bitmap_nr < 0)
+		goto io_error;
+	
+	bh = sb->u.ext3_sb.s_block_bitmap[bitmap_nr];
+	r = memscan(bh->b_data, 0, EXT3_BLOCKS_PER_GROUP(sb) >> 3);
+	j = (r - bh->b_data) << 3;
+	if (j < EXT3_BLOCKS_PER_GROUP(sb))
+		goto search_back;
+	else
+		j = ext3_find_first_zero_bit ((unsigned long *) bh->b_data,
+					 EXT3_BLOCKS_PER_GROUP(sb));
+	if (j >= EXT3_BLOCKS_PER_GROUP(sb)) {
+		ext3_error (sb, "ext3_new_block",
+			    "Free blocks count corrupted for block group %d", i);
+		unlock_super (sb);
+		return 0;
+	}
+
+search_back:
+	/* 
+	 * We have succeeded in finding a free byte in the block
+	 * bitmap.  Now search backwards up to 7 bits to find the
+	 * start of this group of free blocks.
+	 */
+	for (k = 0; k < 7 && j > 0 && !ext3_test_bit (j - 1, bh->b_data); k++, j--);
+	
+got_block:
+
+	ext3_debug ("using block group %d(%d)\n", i, gdp->bg_free_blocks_count);
+
+	/*
+	 * Check quota for allocation of this block.
+	 */
+	if(DQUOT_ALLOC_BLOCK(sb, inode, 1)) {
+		unlock_super(sb);
+		*err = -EDQUOT;
+		return 0;
+	}
+
+	journal_get_write_access(handle, bh);
+	journal_get_write_access(handle, bh2);
+	journal_get_write_access(handle, sb->u.ext3_sb.s_sbh);
+	
+	tmp = j + i * EXT3_BLOCKS_PER_GROUP(sb) + le32_to_cpu(es->s_first_data_block);
+
+	if (test_opt (sb, CHECK_STRICT) &&
+	    (tmp == le32_to_cpu(gdp->bg_block_bitmap) ||
+	     tmp == le32_to_cpu(gdp->bg_inode_bitmap) ||
+	     in_range (tmp, le32_to_cpu(gdp->bg_inode_table), sb->u.ext3_sb.s_itb_per_group)))
+		ext3_panic (sb, "ext3_new_block",
+			    "Allocating block in system zone - "
+			    "block = %u", tmp);
+
+	if (ext3_set_bit (j, bh->b_data)) {
+		ext3_warning (sb, "ext3_new_block",
+			      "bit already set for block %d", j);
+		DQUOT_FREE_BLOCK(sb, inode, 1);
+		goto repeat;
+	}
+
+	ext3_debug ("found bit %d\n", j);
+
+	/*
+	 * Do block preallocation now if required.
+	 */
+#ifdef EXT3_PREALLOCATE
+	if (prealloc_block) {
+		int	prealloc_goal;
+
+		prealloc_goal = es->s_prealloc_blocks ?
+			es->s_prealloc_blocks : EXT3_DEFAULT_PREALLOC_BLOCKS;
+
+		*prealloc_count = 0;
+		*prealloc_block = tmp + 1;
+		for (k = 1;
+		     k < prealloc_goal && (j + k) < EXT3_BLOCKS_PER_GROUP(sb);
+		     k++) {
+			if (DQUOT_PREALLOC_BLOCK(sb, inode, 1))
+				break;
+			if (ext3_set_bit (j + k, bh->b_data)) {
+				DQUOT_FREE_BLOCK(sb, inode, 1);
+ 				break;
+			}
+			(*prealloc_count)++;
+		}	
+		gdp->bg_free_blocks_count =
+			cpu_to_le16(le16_to_cpu(gdp->bg_free_blocks_count) -
+			       *prealloc_count);
+		es->s_free_blocks_count =
+			cpu_to_le32(le32_to_cpu(es->s_free_blocks_count) -
+			       *prealloc_count);
+		ext3_debug ("Preallocated a further %lu bits.\n",
+			    *prealloc_count);
+	}
+#endif
+
+	j = tmp;
+
+	journal_dirty_metadata(handle, bh);
+	if (sb->s_flags & MS_SYNCHRONOUS)
+		handle->h_sync = 1;
+
+	if (j >= le32_to_cpu(es->s_blocks_count)) {
+		ext3_error (sb, "ext3_new_block",
+			    "block >= blocks count - "
+			    "block_group = %d, block=%d", i, j);
+		unlock_super (sb);
+		return 0;
+	}
+	if (!(bh = getblk (sb->s_dev, j, sb->s_blocksize))) {
+		ext3_error (sb, "ext3_new_block", "cannot get block %d", j);
+		unlock_super (sb);
+		return 0;
+	}
+
+	/* @@@ This will eventually have to be a data-style operation,
+           not metadata */
+	mark_buffer_uptodate(bh, 1);
+	journal_get_write_access(handle, bh);
+	memset(bh->b_data, 0, sb->s_blocksize);
+	journal_dirty_metadata(handle, bh);
+	brelse (bh);
+
+	ext3_debug ("allocating block %d. "
+		    "Goal hits %d of %d.\n", j, goal_hits, goal_attempts);
+
+	gdp->bg_free_blocks_count = cpu_to_le16(le16_to_cpu(gdp->bg_free_blocks_count) - 1);
+	es->s_free_blocks_count = cpu_to_le32(le32_to_cpu(es->s_free_blocks_count) - 1);
+	journal_dirty_metadata(handle, bh2);
+	journal_dirty_metadata(handle, sb->u.ext3_sb.s_sbh);
+	sb->s_dirt = 1;
+	unlock_super (sb);
+	*err = 0;
+	return j;
+	
+io_error:
+	*err = -EIO;
+	unlock_super (sb);
+	return 0;
+	
+}
+
+unsigned long ext3_count_free_blocks (struct super_block * sb)
+{
+#ifdef EXT3FS_DEBUG
+	struct ext3_super_block * es;
+	unsigned long desc_count, bitmap_count, x;
+	int bitmap_nr;
+	struct ext3_group_desc * gdp;
+	int i;
+	
+	lock_super (sb);
+	es = sb->u.ext3_sb.s_es;
+	desc_count = 0;
+	bitmap_count = 0;
+	gdp = NULL;
+	for (i = 0; i < sb->u.ext3_sb.s_groups_count; i++) {
+		gdp = ext3_get_group_desc (sb, i, NULL);
+		if (!gdp)
+			continue;
+		desc_count += le16_to_cpu(gdp->bg_free_blocks_count);
+		bitmap_nr = load_block_bitmap (sb, i);
+		if (bitmap_nr < 0)
+			continue;
+		
+		x = ext3_count_free (sb->u.ext3_sb.s_block_bitmap[bitmap_nr],
+				     sb->s_blocksize);
+		printk ("group %d: stored = %d, counted = %lu\n",
+			i, le16_to_cpu(gdp->bg_free_blocks_count), x);
+		bitmap_count += x;
+	}
+	printk("ext3_count_free_blocks: stored = %lu, computed = %lu, %lu\n",
+	       le32_to_cpu(es->s_free_blocks_count), desc_count, bitmap_count);
+	unlock_super (sb);
+	return bitmap_count;
+#else
+	return le32_to_cpu(sb->u.ext3_sb.s_es->s_free_blocks_count);
+#endif
+}
+
+static inline int block_in_use (unsigned long block,
+				struct super_block * sb,
+				unsigned char * map)
+{
+	return ext3_test_bit ((block - le32_to_cpu(sb->u.ext3_sb.s_es->s_first_data_block)) %
+			 EXT3_BLOCKS_PER_GROUP(sb), map);
+}
+
+static int test_root(int a, int b)
+{
+	if (a == 0)
+		return 1;
+	while (1) {
+		if (a == 1)
+			return 1;
+		if (a % b)
+			return 0;
+		a = a / b;
+	}
+}
+
+int ext3_group_sparse(int group)
+{
+	return (test_root(group, 3) || test_root(group, 5) ||
+		test_root(group, 7));
+}
+
+void ext3_check_blocks_bitmap (struct super_block * sb)
+{
+	struct buffer_head * bh;
+	struct ext3_super_block * es;
+	unsigned long desc_count, bitmap_count, x;
+	unsigned long desc_blocks;
+	int bitmap_nr;
+	struct ext3_group_desc * gdp;
+	int i, j;
+
+	lock_super (sb);
+	es = sb->u.ext3_sb.s_es;
+	desc_count = 0;
+	bitmap_count = 0;
+	gdp = NULL;
+	desc_blocks = (sb->u.ext3_sb.s_groups_count + EXT3_DESC_PER_BLOCK(sb) - 1) /
+		      EXT3_DESC_PER_BLOCK(sb);
+	for (i = 0; i < sb->u.ext3_sb.s_groups_count; i++) {
+		gdp = ext3_get_group_desc (sb, i, NULL);
+		if (!gdp)
+			continue;
+		desc_count += le16_to_cpu(gdp->bg_free_blocks_count);
+		bitmap_nr = load_block_bitmap (sb, i);
+		if (bitmap_nr < 0)
+			continue;
+		
+		bh = sb->u.ext3_sb.s_block_bitmap[bitmap_nr];
+
+		if (!(sb->u.ext3_sb.s_feature_ro_compat &
+		     EXT3_FEATURE_RO_COMPAT_SPARSE_SUPER) ||
+		    ext3_group_sparse(i)) {
+			if (!ext3_test_bit (0, bh->b_data))
+				ext3_error (sb, "ext3_check_blocks_bitmap",
+					    "Superblock in group %d "
+					    "is marked free", i);
+
+			for (j = 0; j < desc_blocks; j++)
+				if (!ext3_test_bit (j + 1, bh->b_data))
+					ext3_error (sb,
+					    "ext3_check_blocks_bitmap",
+					    "Descriptor block #%d in group "
+					    "%d is marked free", j, i);
+		}
+
+		if (!block_in_use (le32_to_cpu(gdp->bg_block_bitmap), sb, bh->b_data))
+			ext3_error (sb, "ext3_check_blocks_bitmap",
+				    "Block bitmap for group %d is marked free",
+				    i);
+
+		if (!block_in_use (le32_to_cpu(gdp->bg_inode_bitmap), sb, bh->b_data))
+			ext3_error (sb, "ext3_check_blocks_bitmap",
+				    "Inode bitmap for group %d is marked free",
+				    i);
+
+		for (j = 0; j < sb->u.ext3_sb.s_itb_per_group; j++)
+			if (!block_in_use (le32_to_cpu(gdp->bg_inode_table) + j, sb, bh->b_data))
+				ext3_error (sb, "ext3_check_blocks_bitmap",
+					    "Block #%d of the inode table in "
+					    "group %d is marked free", j, i);
+
+		x = ext3_count_free (bh, sb->s_blocksize);
+		if (le16_to_cpu(gdp->bg_free_blocks_count) != x)
+			ext3_error (sb, "ext3_check_blocks_bitmap",
+				    "Wrong free blocks count for group %d, "
+				    "stored = %d, counted = %lu", i,
+				    le16_to_cpu(gdp->bg_free_blocks_count), x);
+		bitmap_count += x;
+	}
+	if (le32_to_cpu(es->s_free_blocks_count) != bitmap_count)
+		ext3_error (sb, "ext3_check_blocks_bitmap",
+			    "Wrong free blocks count in super block, "
+			    "stored = %lu, counted = %lu",
+			    (unsigned long) le32_to_cpu(es->s_free_blocks_count), bitmap_count);
+	unlock_super (sb);
+}
Index: oldkernel/linux/fs/ext3/bitmap.c
diff -u /dev/null linux/fs/ext3/bitmap.c:1.1
--- /dev/null	Mon Jul 31 21:15:07 2000
+++ linux/fs/ext3/bitmap.c	Fri Jul  7 16:34:57 2000
@@ -0,0 +1,26 @@
+/*
+ *  linux/fs/ext3/bitmap.c
+ *
+ * Copyright (C) 1992, 1993, 1994, 1995
+ * Remy Card (card@masi.ibp.fr)
+ * Laboratoire MASI - Institut Blaise Pascal
+ * Universite Pierre et Marie Curie (Paris VI)
+ */
+
+#include <linux/fs.h>
+#include <linux/ext3_fs.h>
+
+static int nibblemap[] = {4, 3, 3, 2, 3, 2, 2, 1, 3, 2, 2, 1, 2, 1, 1, 0};
+
+unsigned long ext3_count_free (struct buffer_head * map, unsigned int numchars)
+{
+	unsigned int i;
+	unsigned long sum = 0;
+	
+	if (!map) 
+		return (0);
+	for (i = 0; i < numchars; i++)
+		sum += nibblemap[map->b_data[i] & 0xf] +
+			nibblemap[(map->b_data[i] >> 4) & 0xf];
+	return (sum);
+}
Index: oldkernel/linux/fs/ext3/dir.c
diff -u /dev/null linux/fs/ext3/dir.c:1.1
--- /dev/null	Mon Jul 31 21:15:07 2000
+++ linux/fs/ext3/dir.c	Fri Jul  7 16:34:57 2000
@@ -0,0 +1,218 @@
+/*
+ *  linux/fs/ext3/dir.c
+ *
+ * Copyright (C) 1992, 1993, 1994, 1995
+ * Remy Card (card@masi.ibp.fr)
+ * Laboratoire MASI - Institut Blaise Pascal
+ * Universite Pierre et Marie Curie (Paris VI)
+ *
+ *  from
+ *
+ *  linux/fs/minix/dir.c
+ *
+ *  Copyright (C) 1991, 1992  Linus Torvalds
+ *
+ *  ext3 directory handling functions
+ *
+ *  Big-endian to little-endian byte-swapping/bitmaps by
+ *        David S. Miller (davem@caip.rutgers.edu), 1995
+ */
+
+#include <asm/uaccess.h>
+
+#include <linux/errno.h>
+#include <linux/fs.h>
+#include <linux/ext3_fs.h>
+#include <linux/sched.h>
+#include <linux/stat.h>
+
+static ssize_t ext3_dir_read (struct file * filp, char * buf,
+			      size_t count, loff_t *ppos)
+{
+	return -EISDIR;
+}
+
+static int ext3_readdir(struct file *, void *, filldir_t);
+
+static struct file_operations ext3_dir_operations = {
+	NULL,			/* lseek - default */
+	ext3_dir_read,		/* read */
+	NULL,			/* write - bad */
+	ext3_readdir,		/* readdir */
+	NULL,			/* poll - default */
+	ext3_ioctl,		/* ioctl */
+	NULL,			/* mmap */
+	NULL,			/* no special open code */
+	NULL,			/* flush */
+	NULL,			/* no special release code */
+	ext3_sync_file,		/* fsync */
+	NULL,			/* fasync */
+	NULL,			/* check_media_change */
+	NULL			/* revalidate */
+};
+
+/*
+ * directories can handle most operations...
+ */
+struct inode_operations ext3_dir_inode_operations = {
+	&ext3_dir_operations,	/* default directory file-ops */
+	ext3_create,		/* create */
+	ext3_lookup,		/* lookup */
+	ext3_link,		/* link */
+	ext3_unlink,		/* unlink */
+	ext3_symlink,		/* symlink */
+	ext3_mkdir,		/* mkdir */
+	ext3_rmdir,		/* rmdir */
+	ext3_mknod,		/* mknod */
+	ext3_rename,		/* rename */
+	NULL,			/* readlink */
+	NULL,			/* follow_link */
+	NULL,			/* readpage */
+	NULL,			/* writepage */
+	NULL,			/* bmap */
+	NULL,			/* truncate */
+	ext3_permission,	/* permission */
+	NULL			/* smap */
+};
+
+int ext3_check_dir_entry (const char * function, struct inode * dir,
+			  struct ext3_dir_entry_2 * de,
+			  struct buffer_head * bh,
+			  unsigned long offset)
+{
+	const char * error_msg = NULL;
+
+	if (le16_to_cpu(de->rec_len) < EXT3_DIR_REC_LEN(1))
+		error_msg = "rec_len is smaller than minimal";
+	else if (le16_to_cpu(de->rec_len) % 4 != 0)
+		error_msg = "rec_len % 4 != 0";
+	else if (le16_to_cpu(de->rec_len) < EXT3_DIR_REC_LEN(de->name_len))
+		error_msg = "rec_len is too small for name_len";
+	else if (dir && ((char *) de - bh->b_data) + le16_to_cpu(de->rec_len) >
+		 dir->i_sb->s_blocksize)
+		error_msg = "directory entry across blocks";
+	else if (dir && le32_to_cpu(de->inode) > le32_to_cpu(dir->i_sb->u.ext3_sb.s_es->s_inodes_count))
+		error_msg = "inode out of bounds";
+
+	if (error_msg != NULL)
+		ext3_error (dir->i_sb, function, "bad entry in directory #%lu: %s - "
+			    "offset=%lu, inode=%lu, rec_len=%d, name_len=%d",
+			    dir->i_ino, error_msg, offset,
+			    (unsigned long) le32_to_cpu(de->inode),
+			    le16_to_cpu(de->rec_len), de->name_len);
+	return error_msg == NULL ? 1 : 0;
+}
+
+static int ext3_readdir(struct file * filp,
+			 void * dirent, filldir_t filldir)
+{
+	int error = 0;
+	unsigned long offset, blk;
+	int i, num, stored;
+	struct buffer_head * bh, * tmp, * bha[16];
+	struct ext3_dir_entry_2 * de;
+	struct super_block * sb;
+	int err;
+	struct inode *inode = filp->f_dentry->d_inode;
+
+	sb = inode->i_sb;
+
+	stored = 0;
+	bh = NULL;
+	offset = filp->f_pos & (sb->s_blocksize - 1);
+
+	while (!error && !stored && filp->f_pos < inode->i_size) {
+		blk = (filp->f_pos) >> EXT3_BLOCK_SIZE_BITS(sb);
+		bh = ext3_bread (0, inode, blk, 0, &err);
+		if (!bh) {
+			ext3_error (sb, "ext3_readdir",
+				    "directory #%lu contains a hole at offset %lu",
+				    inode->i_ino, (unsigned long)filp->f_pos);
+			filp->f_pos += sb->s_blocksize - offset;
+			continue;
+		}
+
+		/*
+		 * Do the readahead
+		 */
+		if (!offset) {
+			for (i = 16 >> (EXT3_BLOCK_SIZE_BITS(sb) - 9), num = 0;
+			     i > 0; i--) {
+				tmp = ext3_getblk (NULL, inode, ++blk, 0, &err);
+				if (tmp && !buffer_uptodate(tmp) && !buffer_locked(tmp))
+					bha[num++] = tmp;
+				else
+					brelse (tmp);
+			}
+			if (num) {
+				ll_rw_block (READA, num, bha);
+				for (i = 0; i < num; i++)
+					brelse (bha[i]);
+			}
+		}
+		
+revalidate:
+		/* If the dir block has changed since the last call to
+		 * readdir(2), then we might be pointing to an invalid
+		 * dirent right now.  Scan from the start of the block
+		 * to make sure. */
+		if (filp->f_version != inode->i_version) {
+			for (i = 0; i < sb->s_blocksize && i < offset; ) {
+				de = (struct ext3_dir_entry_2 *) 
+					(bh->b_data + i);
+				/* It's too expensive to do a full
+				 * dirent test each time round this
+				 * loop, but we do have to test at
+				 * least that it is non-zero.  A
+				 * failure will be detected in the
+				 * dirent test below. */
+				if (le16_to_cpu(de->rec_len) < EXT3_DIR_REC_LEN(1))
+					break;
+				i += le16_to_cpu(de->rec_len);
+			}
+			offset = i;
+			filp->f_pos = (filp->f_pos & ~(sb->s_blocksize - 1))
+				| offset;
+			filp->f_version = inode->i_version;
+		}
+		
+		while (!error && filp->f_pos < inode->i_size 
+		       && offset < sb->s_blocksize) {
+			de = (struct ext3_dir_entry_2 *) (bh->b_data + offset);
+			if (!ext3_check_dir_entry ("ext3_readdir", inode, de,
+						   bh, offset)) {
+				/* On error, skip the f_pos to the
+                                   next block. */
+				filp->f_pos = (filp->f_pos & ~(sb->s_blocksize - 1))
+					      + sb->s_blocksize;
+				brelse (bh);
+				return stored;
+			}
+			offset += le16_to_cpu(de->rec_len);
+			if (le32_to_cpu(de->inode)) {
+				/* We might block in the next section
+				 * if the data destination is
+				 * currently swapped out.  So, use a
+				 * version stamp to detect whether or
+				 * not the directory has been modified
+				 * during the copy operation.
+				 */
+				unsigned long version = inode->i_version;
+
+				error = filldir(dirent, de->name,
+						de->name_len,
+						filp->f_pos, le32_to_cpu(de->inode));
+				if (error)
+					break;
+				if (version != inode->i_version)
+					goto revalidate;
+				stored ++;
+			}
+			filp->f_pos += le16_to_cpu(de->rec_len);
+		}
+		offset = 0;
+		brelse (bh);
+	}
+	UPDATE_ATIME(inode);
+	return 0;
+}
Index: oldkernel/linux/fs/ext3/file.c
diff -u /dev/null linux/fs/ext3/file.c:1.1
--- /dev/null	Mon Jul 31 21:15:07 2000
+++ linux/fs/ext3/file.c	Fri Jul  7 16:34:57 2000
@@ -0,0 +1,453 @@
+/*
+ *  linux/fs/ext3/file.c
+ *
+ * Copyright (C) 1992, 1993, 1994, 1995
+ * Remy Card (card@masi.ibp.fr)
+ * Laboratoire MASI - Institut Blaise Pascal
+ * Universite Pierre et Marie Curie (Paris VI)
+ *
+ *  from
+ *
+ *  linux/fs/minix/file.c
+ *
+ *  Copyright (C) 1991, 1992  Linus Torvalds
+ *
+ *  ext3 fs regular file handling primitives
+ *
+ *  64-bit file support on 64-bit platforms by Jakub Jelinek
+ * 	(jj@sunsite.ms.mff.cuni.cz)
+ */
+
+#include <asm/uaccess.h>
+#include <asm/system.h>
+
+#include <linux/errno.h>
+#include <linux/fs.h>
+#include <linux/sched.h>
+#include <linux/ext3_fs.h>
+#include <linux/ext3_jfs.h>
+#include <linux/fcntl.h>
+#include <linux/stat.h>
+#include <linux/locks.h>
+#include <linux/mm.h>
+#include <linux/pagemap.h>
+
+#define	NBUF	32
+
+#define MIN(a,b) (((a)<(b))?(a):(b))
+#define MAX(a,b) (((a)>(b))?(a):(b))
+
+static long long ext3_file_lseek(struct file *, long long, int);
+static ssize_t ext3_file_write (struct file *, const char *, size_t, loff_t *);
+static int ext3_release_file (struct inode *, struct file *);
+#if BITS_PER_LONG < 64
+static int ext3_open_file (struct inode *, struct file *);
+
+#else
+
+#define EXT3_MAX_SIZE(bits)							\
+	(((EXT3_NDIR_BLOCKS + (1LL << (bits - 2)) + 				\
+	   (1LL << (bits - 2)) * (1LL << (bits - 2)) + 				\
+	   (1LL << (bits - 2)) * (1LL << (bits - 2)) * (1LL << (bits - 2))) * 	\
+	  (1LL << bits)) - 1)
+
+long long ext3_max_sizes[] = {
+0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 
+EXT3_MAX_SIZE(10), EXT3_MAX_SIZE(11), EXT3_MAX_SIZE(12), EXT3_MAX_SIZE(13)
+};
+
+#endif
+
+/*
+ * We have mostly NULL's here: the current defaults are ok for
+ * the ext3 filesystem.
+ */
+static struct file_operations ext3_file_operations = {
+	ext3_file_lseek,	/* lseek */
+	generic_file_read,	/* read */
+	ext3_file_write,	/* write */
+	NULL,			/* readdir - bad */
+	NULL,			/* poll - default */
+	ext3_ioctl,		/* ioctl */
+	generic_file_mmap,	/* mmap */
+#if BITS_PER_LONG == 64	
+	NULL,			/* no special open is needed */
+#else
+	ext3_open_file,
+#endif
+	NULL,			/* flush */
+	ext3_release_file,	/* release */
+	ext3_sync_file,		/* fsync */
+	NULL,			/* fasync */
+	NULL,			/* check_media_change */
+	NULL			/* revalidate */
+};
+
+struct inode_operations ext3_file_inode_operations = {
+	&ext3_file_operations,/* default 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 */
+	generic_readpage,	/* readpage */
+	NULL,			/* writepage */
+	ext3_bmap,		/* bmap */
+	ext3_truncate,		/* truncate */
+	ext3_permission,	/* permission */
+	NULL			/* smap */
+};
+
+/*
+ * Make sure the offset never goes beyond the 32-bit mark..
+ */
+static long long ext3_file_lseek(
+	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;
+	}
+	if (((unsigned long long) offset >> 32) != 0) {
+#if BITS_PER_LONG < 64
+		return -EINVAL;
+#else
+		if (offset > ext3_max_sizes[EXT3_BLOCK_SIZE_BITS(inode->i_sb)])
+			return -EINVAL;
+#endif
+	} 
+	if (offset != file->f_pos) {
+		file->f_pos = offset;
+		file->f_reada = 0;
+		file->f_version = ++global_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 ext3_file_write (struct file * filp, const char * buf,
+				size_t count, loff_t *ppos)
+{
+	struct inode * inode = filp->f_dentry->d_inode;
+	off_t pos;
+	long block;
+	int offset;
+	int written, c, needed;
+	struct buffer_head * bh, *bufferlist[NBUF];
+	struct super_block * sb;
+	int err;
+	int i, buffercount, write_error, new_buffer;
+	unsigned long limit;
+	handle_t *handle;
+	
+	/* POSIX: mtime/ctime may not change for 0 count */
+	if (!count)
+		return 0;
+	/* This makes the bounds-checking arithmetic later on much more
+	 * sane. */
+	if (((signed) count) < 0)
+ 		return -EINVAL;
+	
+	write_error = buffercount = 0;
+	if (!inode) {
+		printk("ext3_file_write: inode = NULL\n");
+		return -EINVAL;
+	}
+	sb = inode->i_sb;
+	if (sb->s_flags & MS_RDONLY)
+		/*
+		 * This fs has been automatically remounted ro because
+		 * of errors 
+		 */
+		return -ENOSPC;
+
+	if (!S_ISREG(inode->i_mode)) {
+		ext3_warning (sb, "ext3_file_write", "mode = %07o",
+			      inode->i_mode);
+		return -EINVAL;
+	}
+	remove_suid(inode);
+
+	if (filp->f_flags & O_APPEND)
+		pos = inode->i_size;
+	else {
+		pos = *ppos;
+		if (pos != *ppos)
+			return -EINVAL;
+#if BITS_PER_LONG >= 64
+		if (pos > ext3_max_sizes[EXT3_BLOCK_SIZE_BITS(sb)])
+			return -EINVAL;
+#endif
+	}
+
+	block = pos >> EXT3_BLOCK_SIZE_BITS(sb);
+	offset = pos & (sb->s_blocksize - 1);
+	c = sb->s_blocksize - offset;
+
+	/* How large a transaction might we need?  We can always
+	 * underestimate and grow later for really large writes */
+	needed = (count >> EXT3_BLOCK_SIZE_BITS(sb)) + 1;
+	if (needed > EXT3_MAX_TRANS_DATA)
+		needed = EXT3_MAX_TRANS_DATA;
+	handle = journal_start(EXT3_JOURNAL(inode), 
+			       EXT3_DATA_TRANS_BLOCKS + needed);
+	
+	/* Check for overflow.. */
+
+#if BITS_PER_LONG < 64
+	/* If the fd's pos is already greater than or equal to the file
+	 * descriptor's offset maximum, then we need to return EFBIG for
+	 * any non-zero count (and we already tested for zero above). */
+	if (((unsigned) pos) >= 0x7FFFFFFFUL)  {
+		written = -EFBIG;
+		goto error_out;
+	}
+	
+	/* If we are about to overflow the maximum file size, we also
+	 * need to return the error, but only if no bytes can be written
+	 * successfully. */
+	if (((unsigned) pos + count) > 0x7FFFFFFFUL) {
+		count = 0x7FFFFFFFL - pos;
+		if (((signed) count) < 0)  {
+			written = -EFBIG;
+			goto error_out;
+		}
+	}
+#else
+	{
+		off_t max = ext3_max_sizes[EXT3_BLOCK_SIZE_BITS(sb)];
+
+		if (pos >= max) {
+			written = -EFBIG;
+			goto error_out;
+		}
+		
+		if (pos + count > max) {
+			count = max - pos;
+			if (!count) {
+				written = -EFBIG;
+				goto error_out;
+			}
+		}
+		if (((pos + count) >> 31) && 
+		    !(sb->u.ext3_sb.s_es->s_feature_ro_compat &
+		      cpu_to_le32(EXT3_FEATURE_RO_COMPAT_LARGE_FILE))) {
+			/* If this is the first large file created, add a flag
+			   to the superblock */
+			journal_get_write_access(handle, sb->u.ext3_sb.s_sbh);
+			sb->u.ext3_sb.s_es->s_feature_ro_compat |=
+				cpu_to_le32(EXT3_FEATURE_RO_COMPAT_LARGE_FILE);
+			journal_dirty_metadata(handle, sb->u.ext3_sb.s_sbh);
+		}
+	}
+#endif
+
+	/* From SUS: We must generate a SIGXFSZ for file size overflow
+	 * only if no bytes were actually written to the file. --sct */
+
+	limit = current->rlim[RLIMIT_FSIZE].rlim_cur;
+	if (limit < RLIM_INFINITY) {
+		if (((unsigned) pos+count) >= limit) {
+			count = limit - pos;
+			if (((signed) count) <= 0) {
+				send_sig(SIGXFSZ, current, 0);
+				written = -EFBIG;
+				goto error_out;
+			}
+		}
+	}
+
+	written = 0;
+	do {
+		/* Each time round the loop, work out whether we can
+		 * continue as part of the current transaction or
+		 * whether we need to start another one.  This obviously
+		 * matters only for large writes. */
+		if (handle->h_buffer_credits < EXT3_RESERVE_TRANS_BLOCKS) {
+			needed = (count >> EXT3_BLOCK_SIZE_BITS(sb)) + 1;
+			if (needed > EXT3_MAX_TRANS_DATA)
+				needed = EXT3_MAX_TRANS_DATA;
+			if (journal_extend(handle, needed)) {
+				/* Couldn't extend: OK, commit the current
+				 * transaction and start a new one. */
+				if (pos > inode->i_size)
+					inode->i_size = pos;
+				inode->i_ctime = inode->i_mtime = CURRENT_TIME;
+				ext3_mark_inode_dirty(handle, inode);
+				journal_stop(handle);
+				handle = journal_start(EXT3_JOURNAL(inode), 
+						       EXT3_DATA_TRANS_BLOCKS
+						       + needed);
+			}
+		}
+
+		bh = ext3_getblk (handle, inode, block, 1, &err);
+		if (!bh) {
+			if (!written)
+				written = err;
+			break;
+		}
+		if (c > count)
+			c = count;
+
+		/* Tricky: what happens if we are writing the complete
+		 * contents of a block which is not currently
+		 * initialised?  We have to obey the same
+		 * synchronisation rules as the IO code, to prevent some
+		 * other process from stomping on the buffer contents by
+		 * refreshing them from disk while we are setting up the
+		 * buffer.  The copy_from_user() can page fault, after
+		 * all.  We also have to throw away partially successful
+		 * copy_from_users to such buffers, since we can't trust
+		 * the rest of the buffer_head in that case.  --sct */
+
+		new_buffer = (!buffer_uptodate(bh) && !buffer_locked(bh) &&
+			      c == sb->s_blocksize);
+
+		if (new_buffer) {
+			set_bit(BH_Lock, &bh->b_state);
+			journal_get_create_access(handle, bh);
+			c -= copy_from_user (bh->b_data + offset, buf, c);
+			if (c != sb->s_blocksize) {
+				c = 0;
+				unlock_buffer(bh);
+				journal_release_buffer(handle, bh);
+				brelse(bh);
+				if (!written)
+					written = -EFAULT;
+				break;
+			}
+			mark_buffer_uptodate(bh, 1);
+			unlock_buffer(bh);
+		} else {
+			if (!buffer_uptodate(bh)) {
+				ll_rw_block (READ, 1, &bh);
+				wait_on_buffer (bh);
+				if (!buffer_uptodate(bh)) {
+					journal_release_buffer(handle, bh);
+					brelse (bh);
+					if (!written)
+						written = -EIO;
+					break;
+				}
+			}
+			journal_get_write_access(handle, bh);
+			c -= copy_from_user (bh->b_data + offset, buf, c);
+		}
+		if (!c) {
+			journal_release_buffer(handle, bh);
+			brelse(bh);
+			if (!written)
+				written = -EFAULT;
+			break;
+		}
+		journal_dirty_metadata(handle, bh);
+		update_vm_cache(inode, pos, bh->b_data + offset, c);
+		pos += c;
+		written += c;
+		buf += c;
+		count -= c;
+		brelse(bh);
+
+		/* @@@ For O_SYNC, we'll need to restore this bit once
+		 * we are doing separate non-journaled data updates. */
+#if 0
+		if (buffercount == NBUF){
+			ll_rw_block(WRITE, buffercount, bufferlist);
+			for(i=0; i<buffercount; i++){
+				wait_on_buffer(bufferlist[i]);
+				if (!buffer_uptodate(bufferlist[i]))
+					write_error=1;
+				brelse(bufferlist[i]);
+			}
+			buffercount=0;
+		}
+		if(write_error)
+			break;
+
+#endif
+		block++;
+		offset = 0;
+		c = sb->s_blocksize;
+	} while (count);
+
+#if 0
+	if ( buffercount ){
+		ll_rw_block(WRITE, buffercount, bufferlist);
+		for(i=0; i<buffercount; i++){
+			wait_on_buffer(bufferlist[i]);
+			if (!buffer_uptodate(bufferlist[i]))
+				write_error=1;
+			brelse(bufferlist[i]);
+		}
+	}		
+#endif
+
+	/*
+	 * If a file has been opened in synchronous mode, we have to ensure
+	 * that meta-data will also be written synchronously.  
+	 */
+	if (filp->f_flags & O_SYNC)
+		handle->h_sync = 1;
+
+	if (pos > inode->i_size)
+		inode->i_size = pos;
+	inode->i_ctime = inode->i_mtime = CURRENT_TIME;
+	*ppos = pos;
+	ext3_mark_inode_dirty(handle, inode);
+error_out:
+	journal_stop(handle);
+	return written;
+}
+
+/*
+ * Called when an inode is released. Note that this is different
+ * from ext3_file_open: open gets called at every open, but release
+ * gets called only when /all/ the files are closed.
+ */
+static int ext3_release_file (struct inode * inode, struct file * filp)
+{
+	if (filp->f_mode & FMODE_WRITE)
+		ext3_discard_prealloc (inode);
+	return 0;
+}
+
+#if BITS_PER_LONG < 64
+/*
+ * Called when an inode is about to be open.
+ * We use this to disallow opening RW large files on 32bit systems.
+ */
+static int ext3_open_file (struct inode * inode, struct file * filp)
+{
+	if (inode->u.ext3_i.i_high_size && (filp->f_mode & FMODE_WRITE))
+		return -EFBIG;
+	return 0;
+}
+#endif
Index: oldkernel/linux/fs/ext3/fsync.c
diff -u /dev/null linux/fs/ext3/fsync.c:1.1
--- /dev/null	Mon Jul 31 21:15:07 2000
+++ linux/fs/ext3/fsync.c	Fri Jul  7 16:34:57 2000
@@ -0,0 +1,294 @@
+/*
+ *  linux/fs/ext3/fsync.c
+ *
+ *  Copyright (C) 1993  Stephen Tweedie (sct@dcs.ed.ac.uk)
+ *  from
+ *  Copyright (C) 1992  Remy Card (card@masi.ibp.fr)
+ *                      Laboratoire MASI - Institut Blaise Pascal
+ *                      Universite Pierre et Marie Curie (Paris VI)
+ *  from
+ *  linux/fs/minix/truncate.c   Copyright (C) 1991, 1992  Linus Torvalds
+ * 
+ *  ext3fs fsync primitive
+ *
+ *  Big-endian to little-endian byte-swapping/bitmaps by
+ *        David S. Miller (davem@caip.rutgers.edu), 1995
+ * 
+ *  Removed unnecessary code duplication for little endian machines
+ *  and excessive __inline__s. 
+ *        Andi Kleen, 1997
+ */
+
+#include <asm/uaccess.h>
+#include <asm/system.h>
+#include <asm/byteorder.h>
+
+#include <linux/errno.h>
+#include <linux/fs.h>
+#include <linux/ext3_fs.h>
+#include <linux/ext3_jfs.h>
+#include <linux/fcntl.h>
+#include <linux/sched.h>
+#include <linux/stat.h>
+#include <linux/locks.h>
+
+
+#define blocksize (EXT3_BLOCK_SIZE(inode->i_sb))
+#define addr_per_block (EXT3_ADDR_PER_BLOCK(inode->i_sb))
+
+static int sync_block (struct inode * inode, u32 * block, int wait)
+{
+	struct buffer_head * bh;
+	
+	if (!*block)
+		return 0;
+	bh = get_hash_table (inode->i_dev, *block, 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);
+	bh->b_count--;
+	return 0;
+}
+
+#ifndef __LITTLE_ENDIAN
+static int sync_block_swab32 (struct inode * inode, u32 * block, int wait)
+{
+	struct buffer_head * bh;
+	
+	if (!le32_to_cpu(*block))
+		return 0;
+	bh = get_hash_table (inode->i_dev, le32_to_cpu(*block), 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);
+	bh->b_count--;
+	return 0;
+}
+#else
+#define sync_block_swab32 sync_block
+#endif
+
+
+static int sync_iblock (struct inode * inode, u32 * iblock, 
+			struct buffer_head ** bh, int wait) 
+{
+	int rc, tmp;
+	
+	*bh = NULL;
+	tmp = *iblock;
+	if (!tmp)
+		return 0;
+	rc = sync_block (inode, iblock, wait);
+	if (rc)
+		return rc;
+	*bh = bread (inode->i_dev, tmp, blocksize);
+	if (!*bh)
+		return -1;
+	return 0;
+}
+
+#ifndef __LITTLE_ENDIAN
+static int sync_iblock_swab32 (struct inode * inode, u32 * iblock, 
+			       struct buffer_head ** bh, int wait) 
+{
+	int rc, tmp;
+	
+	*bh = NULL;
+	tmp = le32_to_cpu(*iblock);
+	if (!tmp)
+		return 0;
+	rc = sync_block_swab32 (inode, iblock, wait);
+	if (rc)
+		return rc;
+	*bh = bread (inode->i_dev, tmp, blocksize);
+	if (!*bh)
+		return -1;
+	return 0;
+}
+#else
+#define sync_iblock_swab32 sync_iblock
+#endif
+
+static int sync_direct (struct inode * inode, int wait)
+{
+	int i;
+	int rc, err = 0;
+
+	for (i = 0; i < EXT3_NDIR_BLOCKS; i++) {
+		rc = sync_block (inode, inode->u.ext3_i.i_data + i, wait);
+		if (rc)
+			err = rc;
+	}
+	return err;
+}
+
+static int sync_indirect (struct inode * inode, u32 * iblock, int wait)
+{
+	int i;
+	struct buffer_head * ind_bh;
+	int rc, err = 0;
+
+	rc = sync_iblock (inode, iblock, &ind_bh, wait);
+	if (rc || !ind_bh)
+		return rc;
+	
+	for (i = 0; i < addr_per_block; i++) {
+		rc = sync_block_swab32 (inode, 
+					((u32 *) ind_bh->b_data) + i,
+					wait);
+		if (rc)
+			err = rc;
+	}
+	brelse (ind_bh);
+	return err;
+}
+
+#ifndef __LITTLE_ENDIAN
+static __inline__ int sync_indirect_swab32 (struct inode * inode, u32 * iblock, int wait)
+{
+	int i;
+	struct buffer_head * ind_bh;
+	int rc, err = 0;
+
+	rc = sync_iblock_swab32 (inode, iblock, &ind_bh, wait);
+	if (rc || !ind_bh)
+		return rc;
+	
+	for (i = 0; i < addr_per_block; i++) {
+		rc = sync_block_swab32 (inode, 
+					((u32 *) ind_bh->b_data) + i,
+					wait);
+		if (rc)
+			err = rc;
+	}
+	brelse (ind_bh);
+	return err;
+}
+#else
+#define sync_indirect_swab32 sync_indirect
+#endif
+
+static int sync_dindirect (struct inode * inode, u32 * diblock, int wait)
+{
+	int i;
+	struct buffer_head * dind_bh;
+	int rc, err = 0;
+
+	rc = sync_iblock (inode, diblock, &dind_bh, wait);
+	if (rc || !dind_bh)
+		return rc;
+	
+	for (i = 0; i < addr_per_block; i++) {
+		rc = sync_indirect_swab32 (inode,
+					   ((u32 *) dind_bh->b_data) + i,
+					   wait);
+		if (rc)
+			err = rc;
+	}
+	brelse (dind_bh);
+	return err;
+}
+
+#ifndef __LITTLE_ENDIAN
+static __inline__ int sync_dindirect_swab32 (struct inode * inode, u32 * diblock, int wait)
+{
+	int i;
+	struct buffer_head * dind_bh;
+	int rc, err = 0;
+
+	rc = sync_iblock_swab32 (inode, diblock, &dind_bh, wait);
+	if (rc || !dind_bh)
+		return rc;
+	
+	for (i = 0; i < addr_per_block; i++) {
+		rc = sync_indirect_swab32 (inode,
+					   ((u32 *) dind_bh->b_data) + i,
+					   wait);
+		if (rc)
+			err = rc;
+	}
+	brelse (dind_bh);
+	return err;
+}
+#else
+#define sync_dindirect_swab32 sync_dindirect
+#endif
+
+static int sync_tindirect (struct inode * inode, u32 * tiblock, int wait)
+{
+	int i;
+	struct buffer_head * tind_bh;
+	int rc, err = 0;
+
+	rc = sync_iblock (inode, tiblock, &tind_bh, wait);
+	if (rc || !tind_bh)
+		return rc;
+	
+	for (i = 0; i < addr_per_block; i++) {
+		rc = sync_dindirect_swab32 (inode,
+					    ((u32 *) tind_bh->b_data) + i,
+					    wait);
+		if (rc)
+			err = rc;
+	}
+	brelse (tind_bh);
+	return err;
+}
+
+/*
+ *	File may be NULL when we are called. Perhaps we shouldn't
+ *	even pass file to fsync ?
+ */
+
+int ext3_sync_file(struct file * file, struct dentry *dentry)
+{
+	int wait, err = 0;
+	struct inode *inode = dentry->d_inode;
+	handle_t *handle;
+
+	handle = journal_start(EXT3_JOURNAL(inode), 1); /* @@@ Error? */
+	handle->h_sync = 1;
+	
+	if (S_ISLNK(inode->i_mode) && !(inode->i_blocks))
+		/*
+		 * Don't sync fast links!
+		 */
+		goto skip;
+
+#if 0 /* Non-journaled data needs to be taken care of here @@@ */
+	for (wait=0; wait<=1; wait++)
+	{
+		err |= sync_direct (inode, wait);
+		err |= sync_indirect (inode,
+				      inode->u.ext3_i.i_data+EXT3_IND_BLOCK,
+				      wait);
+		err |= sync_dindirect (inode,
+				       inode->u.ext3_i.i_data+EXT3_DIND_BLOCK, 
+				       wait);
+		err |= sync_tindirect (inode, 
+				       inode->u.ext3_i.i_data+EXT3_TIND_BLOCK, 
+				       wait);
+	}
+#endif
+
+skip:
+	err |= ext3_mark_inode_dirty (handle, inode);
+	journal_stop(handle);
+	return err ? -EIO : 0;
+}
Index: oldkernel/linux/fs/ext3/ialloc.c
diff -u /dev/null linux/fs/ext3/ialloc.c:1.1
--- /dev/null	Mon Jul 31 21:15:07 2000
+++ linux/fs/ext3/ialloc.c	Fri Jul  7 16:34:57 2000
@@ -0,0 +1,598 @@
+/*
+ *  linux/fs/ext3/ialloc.c
+ *
+ * Copyright (C) 1992, 1993, 1994, 1995
+ * Remy Card (card@masi.ibp.fr)
+ * Laboratoire MASI - Institut Blaise Pascal
+ * Universite Pierre et Marie Curie (Paris VI)
+ *
+ *  BSD ufs-inspired inode and directory allocation by 
+ *  Stephen Tweedie (sct@dcs.ed.ac.uk), 1993
+ *  Big-endian to little-endian byte-swapping/bitmaps by
+ *        David S. Miller (davem@caip.rutgers.edu), 1995
+ */
+
+/*
+ * ialloc.c contains the inodes allocation and deallocation routines
+ */
+
+/*
+ * The free inodes are managed by bitmaps.  A file system contains several
+ * blocks groups.  Each group contains 1 bitmap block for blocks, 1 bitmap
+ * block for inodes, N blocks for the inode table and data blocks.
+ *
+ * The file system contains group descriptors which are located after the
+ * super block.  Each descriptor contains the number of the bitmap block and
+ * the free blocks count in the block.  The descriptors are loaded in memory
+ * when a file system is mounted (see ext3_read_super).
+ */
+
+#include <linux/sched.h>
+#include <linux/fs.h>
+#include <linux/ext3_fs.h>
+#include <linux/ext3_jfs.h>
+#include <linux/stat.h>
+#include <linux/string.h>
+#include <linux/locks.h>
+#include <linux/quotaops.h>
+
+#include <asm/bitops.h>
+#include <asm/byteorder.h>
+
+/*
+ * Read the inode allocation bitmap for a given block_group, reading
+ * into the specified slot in the superblock's bitmap cache.
+ *
+ * Return >=0 on success or a -ve error code.
+ */
+static int read_inode_bitmap (struct super_block * sb,
+			       unsigned long block_group,
+			       unsigned int bitmap_nr)
+{
+	struct ext3_group_desc * gdp;
+	struct buffer_head * bh = NULL;
+	int retval = 0;
+
+	gdp = ext3_get_group_desc (sb, block_group, NULL);
+	if (!gdp) {
+		retval = -EIO;
+		goto error_out;
+	}
+	bh = bread (sb->s_dev, le32_to_cpu(gdp->bg_inode_bitmap), sb->s_blocksize);
+	if (!bh) {
+		ext3_error (sb, "read_inode_bitmap",
+			    "Cannot read inode bitmap - "
+			    "block_group = %lu, inode_bitmap = %lu",
+			    block_group, (unsigned long) gdp->bg_inode_bitmap);
+		retval = -EIO;
+	}
+	/*
+	 * On IO error, just leave a zero in the superblock's block pointer for
+	 * this group.  The IO will be retried next time.
+	 */
+error_out:
+	sb->u.ext3_sb.s_inode_bitmap_number[bitmap_nr] = block_group;
+	sb->u.ext3_sb.s_inode_bitmap[bitmap_nr] = bh;
+	return retval;
+}
+
+/*
+ * load_inode_bitmap loads the inode bitmap for a blocks group
+ *
+ * It maintains a cache for the last bitmaps loaded.  This cache is managed
+ * with a LRU algorithm.
+ *
+ * Notes:
+ * 1/ There is one cache per mounted file system.
+ * 2/ If the file system contains less than EXT3_MAX_GROUP_LOADED groups,
+ *    this function reads the bitmap without maintaining a LRU cache.
+ * 
+ * Return the slot used to store the bitmap, or a -ve error code.
+ */
+static int load_inode_bitmap (struct super_block * sb,
+			      unsigned int block_group)
+{
+	int i, j, retval = 0;
+	unsigned long inode_bitmap_number;
+	struct buffer_head * inode_bitmap;
+
+	if (block_group >= sb->u.ext3_sb.s_groups_count)
+		ext3_panic (sb, "load_inode_bitmap",
+			    "block_group >= groups_count - "
+			    "block_group = %d, groups_count = %lu",
+			     block_group, sb->u.ext3_sb.s_groups_count);
+	if (sb->u.ext3_sb.s_loaded_inode_bitmaps > 0 &&
+	    sb->u.ext3_sb.s_inode_bitmap_number[0] == block_group &&
+	    sb->u.ext3_sb.s_inode_bitmap[0] != NULL)
+		return 0;
+	if (sb->u.ext3_sb.s_groups_count <= EXT3_MAX_GROUP_LOADED) {
+		if (sb->u.ext3_sb.s_inode_bitmap[block_group]) {
+			if (sb->u.ext3_sb.s_inode_bitmap_number[block_group] != block_group)
+				ext3_panic (sb, "load_inode_bitmap",
+					    "block_group != inode_bitmap_number");
+			else
+				return block_group;
+		} else {
+			retval = read_inode_bitmap (sb, block_group,
+						    block_group);
+			if (retval < 0)
+				return retval;
+			return block_group;
+		}
+	}
+
+	for (i = 0; i < sb->u.ext3_sb.s_loaded_inode_bitmaps &&
+		    sb->u.ext3_sb.s_inode_bitmap_number[i] != block_group;
+	     i++)
+		;
+	if (i < sb->u.ext3_sb.s_loaded_inode_bitmaps &&
+  	    sb->u.ext3_sb.s_inode_bitmap_number[i] == block_group) {
+		inode_bitmap_number = sb->u.ext3_sb.s_inode_bitmap_number[i];
+		inode_bitmap = sb->u.ext3_sb.s_inode_bitmap[i];
+		for (j = i; j > 0; j--) {
+			sb->u.ext3_sb.s_inode_bitmap_number[j] =
+				sb->u.ext3_sb.s_inode_bitmap_number[j - 1];
+			sb->u.ext3_sb.s_inode_bitmap[j] =
+				sb->u.ext3_sb.s_inode_bitmap[j - 1];
+		}
+		sb->u.ext3_sb.s_inode_bitmap_number[0] = inode_bitmap_number;
+		sb->u.ext3_sb.s_inode_bitmap[0] = inode_bitmap;
+
+		/*
+		 * There's still one special case here --- if inode_bitmap == 0
+		 * then our last attempt to read the bitmap failed and we have
+		 * just ended up caching that failure.  Try again to read it.
+		 */
+		if (!inode_bitmap)
+			retval = read_inode_bitmap (sb, block_group, 0);
+		
+	} else {
+		if (sb->u.ext3_sb.s_loaded_inode_bitmaps < EXT3_MAX_GROUP_LOADED)
+			sb->u.ext3_sb.s_loaded_inode_bitmaps++;
+		else
+			brelse (sb->u.ext3_sb.s_inode_bitmap[EXT3_MAX_GROUP_LOADED - 1]);
+		for (j = sb->u.ext3_sb.s_loaded_inode_bitmaps - 1; j > 0; j--) {
+			sb->u.ext3_sb.s_inode_bitmap_number[j] =
+				sb->u.ext3_sb.s_inode_bitmap_number[j - 1];
+			sb->u.ext3_sb.s_inode_bitmap[j] =
+				sb->u.ext3_sb.s_inode_bitmap[j - 1];
+		}
+		retval = read_inode_bitmap (sb, block_group, 0);
+	}
+	return retval;
+}
+
+/*
+ * NOTE! When we get the inode, we're the only people
+ * that have access to it, and as such there are no
+ * race conditions we have to worry about. The inode
+ * is not on the hash-lists, and it cannot be reached
+ * through the filesystem because the directory entry
+ * has been deleted earlier.
+ *
+ * HOWEVER: we must make sure that we get no aliases,
+ * which means that we have to call "clear_inode()"
+ * _before_ we mark the inode not in use in the inode
+ * bitmaps. Otherwise a newly created file might use
+ * the same inode number (not actually the same pointer
+ * though), and then we'd have two inodes sharing the
+ * same inode number and space on the harddisk.
+ */
+void ext3_free_inode (handle_t *handle, struct inode * inode)
+{
+	struct super_block * sb = inode->i_sb;
+	int is_directory;
+	unsigned long ino;
+	struct buffer_head * bh;
+	struct buffer_head * bh2;
+	unsigned long block_group;
+	unsigned long bit;
+	int bitmap_nr;
+	struct ext3_group_desc * gdp;
+	struct ext3_super_block * es;
+
+	if (!inode->i_dev) {
+		printk ("ext3_free_inode: inode has no device\n");
+		return;
+	}
+	if (inode->i_count > 1) {
+		printk ("ext3_free_inode: inode has count=%d\n", inode->i_count);
+		return;
+	}
+	if (inode->i_nlink) {
+		printk ("ext3_free_inode: inode has nlink=%d\n",
+			inode->i_nlink);
+		return;
+	}
+	if (!sb) {
+		printk("ext3_free_inode: inode on nonexistent device\n");
+		return;
+	}
+
+	ino = inode->i_ino;
+	ext3_debug ("freeing inode %lu\n", ino);
+
+	/*
+	 * Note: we must free any quota before locking the superblock,
+	 * as writing the quota to disk may need the lock as well.
+	 */
+	DQUOT_FREE_INODE(sb, inode);
+	DQUOT_DROP(inode);
+
+	lock_super (sb);
+	es = sb->u.ext3_sb.s_es;
+	if (ino < EXT3_FIRST_INO(sb) || 
+	    ino > le32_to_cpu(es->s_inodes_count)) {
+		ext3_error (sb, "free_inode",
+			    "reserved inode or nonexistent inode");
+		goto error_return;
+	}
+	block_group = (ino - 1) / EXT3_INODES_PER_GROUP(sb);
+	bit = (ino - 1) % EXT3_INODES_PER_GROUP(sb);
+	bitmap_nr = load_inode_bitmap (sb, block_group);
+	if (bitmap_nr < 0)
+		goto error_return;
+	
+	bh = sb->u.ext3_sb.s_inode_bitmap[bitmap_nr];
+
+	is_directory = S_ISDIR(inode->i_mode);
+
+	/* Do this BEFORE marking the inode not in use */
+	clear_inode (inode);
+
+	journal_get_write_access(handle, bh);
+	/* Ok, now we can actually update the inode bitmaps.. */
+	if (!ext3_clear_bit (bit, bh->b_data))
+		ext3_warning (sb, "ext3_free_inode",
+			      "bit already cleared for inode %lu", ino);
+	else {
+		gdp = ext3_get_group_desc (sb, block_group, &bh2);
+		journal_get_write_access(handle, bh2);
+		journal_get_write_access(handle, sb->u.ext3_sb.s_sbh);
+		if (gdp) {
+			gdp->bg_free_inodes_count =
+				cpu_to_le16(le16_to_cpu(gdp->bg_free_inodes_count) + 1);
+			if (is_directory)
+				gdp->bg_used_dirs_count =
+					cpu_to_le16(le16_to_cpu(gdp->bg_used_dirs_count) - 1);
+		}
+		journal_dirty_metadata(handle, bh2);
+		es->s_free_inodes_count =
+			cpu_to_le32(le32_to_cpu(es->s_free_inodes_count) + 1);
+		journal_dirty_metadata(handle, sb->u.ext3_sb.s_sbh);
+	}
+	journal_dirty_metadata(handle, bh);
+	if (sb->s_flags & MS_SYNCHRONOUS) 
+		handle->h_sync = 1;
+	sb->s_dirt = 1;
+error_return:
+	unlock_super (sb);
+}
+
+/*
+ * This function increments the inode version number
+ *
+ * This may be used one day by the NFS server
+ */
+static void inc_inode_version (struct inode * inode,
+			       struct ext3_group_desc *gdp,
+			       int mode)
+{
+	inode->u.ext3_i.i_version++;
+	mark_inode_dirty(inode);
+
+	return;
+}
+
+/*
+ * There are two policies for allocating an inode.  If the new inode is
+ * a directory, then a forward search is made for a block group with both
+ * free space and a low directory-to-inode ratio; if that fails, then of
+ * the groups with above-average free space, that group with the fewest
+ * directories already is chosen.
+ *
+ * For other inodes, search forward from the parent directory\'s block
+ * group to find a free inode.
+ */
+struct inode * ext3_new_inode (handle_t *handle, const struct inode * dir, 
+			       int mode, int * err)
+{
+	struct super_block * sb;
+	struct buffer_head * bh;
+	struct buffer_head * bh2;
+	int i, j, avefreei;
+	struct inode * inode;
+	int bitmap_nr;
+	struct ext3_group_desc * gdp;
+	struct ext3_group_desc * tmp;
+	struct ext3_super_block * es;
+
+	/* Cannot create files in a deleted directory */
+	if (!dir || !dir->i_nlink) {
+		*err = -EPERM;
+		return NULL;
+	}
+
+	inode = get_empty_inode ();
+	if (!inode) {
+		*err = -ENOMEM;
+		return NULL;
+	}
+
+	sb = dir->i_sb;
+	inode->i_sb = sb;
+	inode->i_flags = 0;
+	lock_super (sb);
+	es = sb->u.ext3_sb.s_es;
+repeat:
+	gdp = NULL; i=0;
+	
+	*err = -ENOSPC;
+	if (S_ISDIR(mode)) {
+		avefreei = le32_to_cpu(es->s_free_inodes_count) /
+			sb->u.ext3_sb.s_groups_count;
+/* I am not yet convinced that this next bit is necessary.
+		i = dir->u.ext3_i.i_block_group;
+		for (j = 0; j < sb->u.ext3_sb.s_groups_count; j++) {
+			tmp = ext3_get_group_desc (sb, i, &bh2);
+			if (tmp &&
+			    (le16_to_cpu(tmp->bg_used_dirs_count) << 8) < 
+			     le16_to_cpu(tmp->bg_free_inodes_count)) {
+				gdp = tmp;
+				break;
+			}
+			else
+			i = ++i % sb->u.ext3_sb.s_groups_count;
+		}
+*/
+		if (!gdp) {
+			for (j = 0; j < sb->u.ext3_sb.s_groups_count; j++) {
+				tmp = ext3_get_group_desc (sb, j, &bh2);
+				if (tmp &&
+				    le16_to_cpu(tmp->bg_free_inodes_count) &&
+				    le16_to_cpu(tmp->bg_free_inodes_count) >= avefreei) {
+					if (!gdp || 
+					    (le16_to_cpu(tmp->bg_free_blocks_count) >
+					     le16_to_cpu(gdp->bg_free_blocks_count))) {
+						i = j;
+						gdp = tmp;
+					}
+				}
+			}
+		}
+	}
+	else 
+	{
+		/*
+		 * Try to place the inode in its parent directory
+		 */
+		i = dir->u.ext3_i.i_block_group;
+		tmp = ext3_get_group_desc (sb, i, &bh2);
+		if (tmp && le16_to_cpu(tmp->bg_free_inodes_count))
+			gdp = tmp;
+		else
+		{
+			/*
+			 * Use a quadratic hash to find a group with a
+			 * free inode
+			 */
+			for (j = 1; j < sb->u.ext3_sb.s_groups_count; j <<= 1) {
+				i += j;
+				if (i >= sb->u.ext3_sb.s_groups_count)
+					i -= sb->u.ext3_sb.s_groups_count;
+				tmp = ext3_get_group_desc (sb, i, &bh2);
+				if (tmp &&
+				    le16_to_cpu(tmp->bg_free_inodes_count)) {
+					gdp = tmp;
+					break;
+				}
+			}
+		}
+		if (!gdp) {
+			/*
+			 * That failed: try linear search for a free inode
+			 */
+			i = dir->u.ext3_i.i_block_group + 1;
+			for (j = 2; j < sb->u.ext3_sb.s_groups_count; j++) {
+				if (++i >= sb->u.ext3_sb.s_groups_count)
+					i = 0;
+				tmp = ext3_get_group_desc (sb, i, &bh2);
+				if (tmp &&
+				    le16_to_cpu(tmp->bg_free_inodes_count)) {
+					gdp = tmp;
+					break;
+				}
+			}
+		}
+	}
+
+	if (!gdp) {
+		unlock_super (sb);
+		iput(inode);
+		return NULL;
+	}
+	bitmap_nr = load_inode_bitmap (sb, i);
+	if (bitmap_nr < 0) {
+		unlock_super (sb);
+		iput(inode);
+		*err = -EIO;
+		return NULL;
+	}
+
+	bh = sb->u.ext3_sb.s_inode_bitmap[bitmap_nr];
+
+	if (sb->s_flags & MS_SYNCHRONOUS) 
+		handle->h_sync = 1;
+	
+	if ((j = ext3_find_first_zero_bit ((unsigned long *) bh->b_data,
+				      EXT3_INODES_PER_GROUP(sb))) <
+	    EXT3_INODES_PER_GROUP(sb)) {
+		journal_get_write_access(handle, bh);
+		if (ext3_set_bit (j, bh->b_data)) {
+			ext3_warning (sb, "ext3_new_inode",
+				      "bit already set for inode %d", j);
+			goto repeat;
+		}
+		journal_dirty_metadata(handle, bh);
+	} else {
+		if (le16_to_cpu(gdp->bg_free_inodes_count) != 0) {
+			ext3_error (sb, "ext3_new_inode",
+				    "Free inodes count corrupted in group %d",
+				    i);
+			unlock_super (sb);
+			iput (inode);
+			return NULL;
+		}
+		goto repeat;
+	}
+	j += i * EXT3_INODES_PER_GROUP(sb) + 1;
+	if (j < EXT3_FIRST_INO(sb) || j > le32_to_cpu(es->s_inodes_count)) {
+		ext3_error (sb, "ext3_new_inode",
+			    "reserved inode or inode > inodes count - "
+			    "block_group = %d,inode=%d", i, j);
+		unlock_super (sb);
+		iput (inode);
+		return NULL;
+	}
+
+	journal_get_write_access(handle, bh2);
+	gdp->bg_free_inodes_count =
+		cpu_to_le16(le16_to_cpu(gdp->bg_free_inodes_count) - 1);
+	if (S_ISDIR(mode))
+		gdp->bg_used_dirs_count =
+			cpu_to_le16(le16_to_cpu(gdp->bg_used_dirs_count) + 1);
+	journal_dirty_metadata(handle, bh2);
+
+	journal_get_write_access(handle, sb->u.ext3_sb.s_sbh);
+	es->s_free_inodes_count =
+		cpu_to_le32(le32_to_cpu(es->s_free_inodes_count) - 1);
+	journal_dirty_metadata(handle, sb->u.ext3_sb.s_sbh);
+	sb->s_dirt = 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 (test_opt (sb, GRPID))
+		inode->i_gid = dir->i_gid;
+	else 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;
+
+	inode->i_ino = j;
+	inode->i_blksize = PAGE_SIZE;	/* This is the optimal IO size (for stat), not the fs block size */
+	inode->i_blocks = 0;
+	inode->i_mtime = inode->i_atime = inode->i_ctime = CURRENT_TIME;
+	inode->u.ext3_i.i_new_inode = 1;
+	inode->u.ext3_i.i_flags = dir->u.ext3_i.i_flags;
+	if (S_ISLNK(mode))
+		inode->u.ext3_i.i_flags &= ~(EXT3_IMMUTABLE_FL | EXT3_APPEND_FL);
+	inode->u.ext3_i.i_faddr = 0;
+	inode->u.ext3_i.i_frag_no = 0;
+	inode->u.ext3_i.i_frag_size = 0;
+	inode->u.ext3_i.i_file_acl = 0;
+	inode->u.ext3_i.i_dir_acl = 0;
+	inode->u.ext3_i.i_dtime = 0;
+	inode->u.ext3_i.i_block_group = i;
+	inode->i_op = NULL;
+	if (inode->u.ext3_i.i_flags & EXT3_SYNC_FL)
+		inode->i_flags |= MS_SYNCHRONOUS;
+	insert_inode_hash(inode);
+	ext3_mark_inode_dirty(handle, inode);
+	inc_inode_version (inode, gdp, mode);
+
+	unlock_super (sb);
+	if(DQUOT_ALLOC_INODE(sb, inode)) {
+		sb->dq_op->drop(inode);
+		inode->i_nlink = 0;
+		iput(inode);
+		*err = -EDQUOT;
+		return NULL;
+	}
+	ext3_debug ("allocating inode %lu\n", inode->i_ino);
+
+	*err = 0;
+	return inode;
+}
+
+unsigned long ext3_count_free_inodes (struct super_block * sb)
+{
+#ifdef EXT3FS_DEBUG
+	struct ext3_super_block * es;
+	unsigned long desc_count, bitmap_count, x;
+	int bitmap_nr;
+	struct ext3_group_desc * gdp;
+	int i;
+
+	lock_super (sb);
+	es = sb->u.ext3_sb.s_es;
+	desc_count = 0;
+	bitmap_count = 0;
+	gdp = NULL;
+	for (i = 0; i < sb->u.ext3_sb.s_groups_count; i++) {
+		gdp = ext3_get_group_desc (sb, i, NULL);
+		if (!gdp)
+			continue;
+		desc_count += le16_to_cpu(gdp->bg_free_inodes_count);
+		bitmap_nr = load_inode_bitmap (sb, i);
+		if (bitmap_nr < 0)
+			continue;
+
+		x = ext3_count_free (sb->u.ext3_sb.s_inode_bitmap[bitmap_nr],
+				     EXT3_INODES_PER_GROUP(sb) / 8);
+		printk ("group %d: stored = %d, counted = %lu\n",
+			i, le16_to_cpu(gdp->bg_free_inodes_count), x);
+		bitmap_count += x;
+	}
+	printk("ext3_count_free_inodes: stored = %lu, computed = %lu, %lu\n",
+		le32_to_cpu(es->s_free_inodes_count), desc_count, bitmap_count);
+	unlock_super (sb);
+	return desc_count;
+#else
+	return le32_to_cpu(sb->u.ext3_sb.s_es->s_free_inodes_count);
+#endif
+}
+
+void ext3_check_inodes_bitmap (struct super_block * sb)
+{
+	struct ext3_super_block * es;
+	unsigned long desc_count, bitmap_count, x;
+	int bitmap_nr;
+	struct ext3_group_desc * gdp;
+	int i;
+
+	lock_super (sb);
+	es = sb->u.ext3_sb.s_es;
+	desc_count = 0;
+	bitmap_count = 0;
+	gdp = NULL;
+	for (i = 0; i < sb->u.ext3_sb.s_groups_count; i++) {
+		gdp = ext3_get_group_desc (sb, i, NULL);
+		if (!gdp)
+			continue;
+		desc_count += le16_to_cpu(gdp->bg_free_inodes_count);
+		bitmap_nr = load_inode_bitmap (sb, i);
+		if (bitmap_nr < 0)
+			continue;
+		
+		x = ext3_count_free (sb->u.ext3_sb.s_inode_bitmap[bitmap_nr],
+				     EXT3_INODES_PER_GROUP(sb) / 8);
+		if (le16_to_cpu(gdp->bg_free_inodes_count) != x)
+			ext3_error (sb, "ext3_check_inodes_bitmap",
+				    "Wrong free inodes count in group %d, "
+				    "stored = %d, counted = %lu", i,
+				    le16_to_cpu(gdp->bg_free_inodes_count), x);
+		bitmap_count += x;
+	}
+	if (le32_to_cpu(es->s_free_inodes_count) != bitmap_count)
+		ext3_error (sb, "ext3_check_inodes_bitmap",
+			    "Wrong free inodes count in super block, "
+			    "stored = %lu, counted = %lu",
+			    (unsigned long) le32_to_cpu(es->s_free_inodes_count),
+			    bitmap_count);
+	unlock_super (sb);
+}
Index: oldkernel/linux/fs/ext3/inode.c
diff -u /dev/null linux/fs/ext3/inode.c:1.1
--- /dev/null	Mon Jul 31 21:15:07 2000
+++ linux/fs/ext3/inode.c	Fri Jul  7 16:34:57 2000
@@ -0,0 +1,884 @@
+/*
+ *  linux/fs/ext3/inode.c
+ *
+ * Copyright (C) 1992, 1993, 1994, 1995
+ * Remy Card (card@masi.ibp.fr)
+ * Laboratoire MASI - Institut Blaise Pascal
+ * Universite Pierre et Marie Curie (Paris VI)
+ *
+ *  from
+ *
+ *  linux/fs/minix/inode.c
+ *
+ *  Copyright (C) 1991, 1992  Linus Torvalds
+ *
+ *  Goal-directed block allocation by Stephen Tweedie
+ * 	(sct@dcs.ed.ac.uk), 1993, 1998
+ *  Big-endian to little-endian byte-swapping/bitmaps by
+ *        David S. Miller (davem@caip.rutgers.edu), 1995
+ *  64-bit file support on 64-bit platforms by Jakub Jelinek
+ * 	(jj@sunsite.ms.mff.cuni.cz)
+ */
+
+#include <asm/uaccess.h>
+#include <asm/system.h>
+
+#include <linux/errno.h>
+#include <linux/fs.h>
+#include <linux/ext3_fs.h>
+#include <linux/ext3_jfs.h>
+#include <linux/sched.h>
+#include <linux/stat.h>
+#include <linux/string.h>
+#include <linux/locks.h>
+#include <linux/mm.h>
+
+/*
+ * Called at each iput()
+ */
+void ext3_put_inode (struct inode * inode)
+{
+	ext3_discard_prealloc (inode);
+}
+
+/*
+ * Called at the last iput() if i_nlink is zero.
+ */
+void ext3_delete_inode (struct inode * inode)
+{
+	handle_t *handle;
+
+	if (inode->i_ino == EXT3_ACL_IDX_INO ||
+	    inode->i_ino == EXT3_ACL_DATA_INO)
+		return;
+	inode->u.ext3_i.i_dtime	= CURRENT_TIME;
+
+	handle = journal_start(EXT3_JOURNAL(inode), 
+			       EXT3_DELETE_TRANS_BLOCKS);
+	
+	if (IS_SYNC(inode))
+		handle->h_sync = 1;
+	ext3_mark_inode_dirty(handle, inode);
+	inode->i_size = 0;
+	if (inode->i_blocks)
+		ext3_truncate (inode);
+	ext3_free_inode (handle, inode);
+	journal_stop(handle);
+}
+
+#define inode_bmap(inode, nr) ((inode)->u.ext3_i.i_data[(nr)])
+
+static inline int block_bmap (struct buffer_head * bh, int nr)
+{
+	int tmp;
+
+	if (!bh)
+		return 0;
+	tmp = le32_to_cpu(((u32 *) bh->b_data)[nr]);
+	brelse (bh);
+	return tmp;
+}
+
+/* 
+ * ext3_discard_prealloc and ext3_alloc_block are atomic wrt. the
+ * superblock in the same manner as are ext3_free_blocks and
+ * ext3_new_block.  We just wait on the super rather than locking it
+ * here, since ext3_new_block will do the necessary locking and we
+ * can't block until then.
+ */
+void ext3_discard_prealloc (struct inode * inode)
+{
+#ifdef EXT3_PREALLOCATE
+	unsigned short total;
+
+	if (inode->u.ext3_i.i_prealloc_count) {
+		total = inode->u.ext3_i.i_prealloc_count;
+		inode->u.ext3_i.i_prealloc_count = 0;
+		ext3_free_blocks (inode, inode->u.ext3_i.i_prealloc_block, total);
+	}
+#endif
+}
+
+static int ext3_alloc_block (handle_t *handle, struct inode * inode, 
+			     unsigned long goal, int * err)
+{
+#ifdef EXT3FS_DEBUG
+	static unsigned long alloc_hits = 0, alloc_attempts = 0;
+#endif
+	unsigned long result;
+	struct buffer_head * bh;
+
+	wait_on_super (inode->i_sb);
+
+#ifdef EXT3_PREALLOCATE
+	if (inode->u.ext3_i.i_prealloc_count &&
+	    (goal == inode->u.ext3_i.i_prealloc_block ||
+	     goal + 1 == inode->u.ext3_i.i_prealloc_block))
+	{		
+		result = inode->u.ext3_i.i_prealloc_block++;
+		inode->u.ext3_i.i_prealloc_count--;
+		ext3_debug ("preallocation hit (%lu/%lu).\n",
+			    ++alloc_hits, ++alloc_attempts);
+
+		/* It doesn't matter if we block in getblk() since
+		   we have already atomically allocated the block, and
+		   are only clearing it now. */
+		if (!(bh = getblk (inode->i_sb->s_dev, result,
+				   inode->i_sb->s_blocksize))) {
+			ext3_error (inode->i_sb, "ext3_alloc_block",
+				    "cannot get block %lu", result);
+			return 0;
+		}
+		/* @@@ Once we start journaling data separately, this
+                   needs to become dependent on the type of inode we
+                   are allocating inside */
+		journal_get_write_access(handle, bh);
+		memset(bh->b_data, 0, inode->i_sb->s_blocksize);
+		mark_buffer_uptodate(bh, 1);
+		journal_dirty_metadata(handle, bh);
+		brelse (bh);
+	} else {
+		ext3_discard_prealloc (inode);
+		ext3_debug ("preallocation miss (%lu/%lu).\n",
+			    alloc_hits, ++alloc_attempts);
+		if (S_ISREG(inode->i_mode))
+			result = ext3_new_block (inode, goal, 
+				 &inode->u.ext3_i.i_prealloc_count,
+				 &inode->u.ext3_i.i_prealloc_block, err);
+		else
+			result = ext3_new_block (handle, inode, goal, 0, 0, err);
+	}
+#else
+	result = ext3_new_block (handle, inode, goal, 0, 0, err);
+#endif
+
+	return result;
+}
+
+
+int ext3_bmap (struct inode * inode, int block)
+{
+	int i;
+	int addr_per_block = EXT3_ADDR_PER_BLOCK(inode->i_sb);
+	int addr_per_block_bits = EXT3_ADDR_PER_BLOCK_BITS(inode->i_sb);
+
+	if (block < 0) {
+		ext3_warning (inode->i_sb, "ext3_bmap", "block < 0");
+		return 0;
+	}
+	if (block >= EXT3_NDIR_BLOCKS + addr_per_block +
+		(1 << (addr_per_block_bits * 2)) +
+		((1 << (addr_per_block_bits * 2)) << addr_per_block_bits)) {
+		ext3_warning (inode->i_sb, "ext3_bmap", "block > big");
+		return 0;
+	}
+	if (block < EXT3_NDIR_BLOCKS)
+		return inode_bmap (inode, block);
+	block -= EXT3_NDIR_BLOCKS;
+	if (block < addr_per_block) {
+		i = inode_bmap (inode, EXT3_IND_BLOCK);
+		if (!i)
+			return 0;
+		return block_bmap (bread (inode->i_dev, i,
+					  inode->i_sb->s_blocksize), block);
+	}
+	block -= addr_per_block;
+	if (block < (1 << (addr_per_block_bits * 2))) {
+		i = inode_bmap (inode, EXT3_DIND_BLOCK);
+		if (!i)
+			return 0;
+		i = block_bmap (bread (inode->i_dev, i,
+				       inode->i_sb->s_blocksize),
+				block >> addr_per_block_bits);
+		if (!i)
+			return 0;
+		return block_bmap (bread (inode->i_dev, i,
+					  inode->i_sb->s_blocksize),
+				   block & (addr_per_block - 1));
+	}
+	block -= (1 << (addr_per_block_bits * 2));
+	i = inode_bmap (inode, EXT3_TIND_BLOCK);
+	if (!i)
+		return 0;
+	i = block_bmap (bread (inode->i_dev, i, inode->i_sb->s_blocksize),
+			block >> (addr_per_block_bits * 2));
+	if (!i)
+		return 0;
+	i = block_bmap (bread (inode->i_dev, i, inode->i_sb->s_blocksize),
+			(block >> addr_per_block_bits) & (addr_per_block - 1));
+	if (!i)
+		return 0;
+	return block_bmap (bread (inode->i_dev, i, inode->i_sb->s_blocksize),
+			   block & (addr_per_block - 1));
+}
+
+static struct buffer_head * inode_getblk (handle_t *handle,
+					  struct inode * inode, int nr,
+					  int create, int new_block, int * err)
+{
+	u32 * p;
+	int tmp, goal = 0;
+	struct buffer_head * result;
+	int blocks = inode->i_sb->s_blocksize / 512;
+
+	p = inode->u.ext3_i.i_data + nr;
+repeat:
+	tmp = *p;
+	if (tmp) {
+		struct buffer_head * result = getblk (inode->i_dev, tmp, inode->i_sb->s_blocksize);
+		if (tmp == *p)
+			return result;
+		brelse (result);
+		goto repeat;
+	}
+	*err = -EFBIG;
+	if (!create)
+		return NULL;
+
+	if (inode->u.ext3_i.i_next_alloc_block == new_block)
+		goal = inode->u.ext3_i.i_next_alloc_goal;
+
+	ext3_debug ("hint = %d,", goal);
+
+	if (!goal) {
+		for (tmp = nr - 1; tmp >= 0; tmp--) {
+			if (inode->u.ext3_i.i_data[tmp]) {
+				goal = inode->u.ext3_i.i_data[tmp];
+				break;
+			}
+		}
+		if (!goal)
+			goal = (inode->u.ext3_i.i_block_group * 
+				EXT3_BLOCKS_PER_GROUP(inode->i_sb)) +
+			       le32_to_cpu(inode->i_sb->u.ext3_sb.s_es->s_first_data_block);
+	}
+
+	ext3_debug ("goal = %d.\n", goal);
+
+	tmp = ext3_alloc_block (handle, inode, goal, err);
+	if (!tmp)
+		return NULL;
+	result = getblk (inode->i_dev, tmp, inode->i_sb->s_blocksize);
+	if (*p) {
+		ext3_free_blocks (handle, inode, tmp, 1);
+		brelse (result);
+		goto repeat;
+	}
+	*p = tmp;
+	inode->u.ext3_i.i_next_alloc_block = new_block;
+	inode->u.ext3_i.i_next_alloc_goal = tmp;
+	inode->i_ctime = CURRENT_TIME;
+	inode->i_blocks += blocks;
+	if (IS_SYNC(inode) || inode->u.ext3_i.i_osync)
+		handle->h_sync = 1;
+	ext3_mark_inode_dirty(handle, inode);
+	return result;
+}
+
+static struct buffer_head * block_getblk (handle_t *handle, 
+					  struct inode * inode,
+					  struct buffer_head * bh, int nr,
+					  int create, int blocksize, 
+					  int new_block, int * err)
+{
+	int tmp, goal = 0;
+	u32 * p;
+	struct buffer_head * result;
+	int blocks = inode->i_sb->s_blocksize / 512;
+	
+	if (!bh)
+		return NULL;
+	if (!buffer_uptodate(bh)) {
+		ll_rw_block (READ, 1, &bh);
+		wait_on_buffer (bh);
+		if (!buffer_uptodate(bh)) {
+			brelse (bh);
+			return NULL;
+		}
+	}
+	p = (u32 *) bh->b_data + nr;
+repeat:
+	tmp = le32_to_cpu(*p);
+	if (tmp) {
+		result = getblk (bh->b_dev, tmp, blocksize);
+		if (tmp == le32_to_cpu(*p)) {
+			brelse (bh);
+			return result;
+		}
+		brelse (result);
+		goto repeat;
+	}
+	*err = -EFBIG;
+	if (!create) {
+		brelse (bh);
+		return NULL;
+	}
+
+	if (inode->u.ext3_i.i_next_alloc_block == new_block)
+		goal = inode->u.ext3_i.i_next_alloc_goal;
+	if (!goal) {
+		for (tmp = nr - 1; tmp >= 0; tmp--) {
+			if (le32_to_cpu(((u32 *) bh->b_data)[tmp])) {
+				goal = le32_to_cpu(((u32 *)bh->b_data)[tmp]);
+				break;
+			}
+		}
+		if (!goal)
+			goal = bh->b_blocknr;
+	}
+	tmp = ext3_alloc_block (handle, inode, goal, err);
+	if (!tmp) {
+		brelse (bh);
+		return NULL;
+	}
+	result = getblk (bh->b_dev, tmp, blocksize);
+	journal_get_write_access(handle, bh);
+	if (le32_to_cpu(*p)) {
+		/* @@@ Major danger here: we are using up more and more
+		 * buffer credits against this transaction by undoing
+		 * the allocation when we get a collision here.  We need
+		 * to be able to extend the transaction if possible, and
+		 * return a retry failure code if we can't. */
+		ext3_free_blocks (handle, inode, tmp, 1);
+		brelse (result);
+		goto repeat;
+	}
+	*p = le32_to_cpu(tmp);
+	journal_dirty_metadata(handle, bh);
+	if (IS_SYNC(inode) || inode->u.ext3_i.i_osync)
+		handle->h_sync = 1;
+	inode->i_ctime = CURRENT_TIME;
+	inode->i_blocks += blocks;
+	inode->u.ext3_i.i_next_alloc_block = new_block;
+	inode->u.ext3_i.i_next_alloc_goal = tmp;
+	ext3_mark_inode_dirty(handle, inode);
+	brelse (bh);
+	return result;
+}
+
+struct buffer_head * ext3_getblk (handle_t *handle, 
+				  struct inode * inode, long block,
+				  int create, int * err)
+{
+	struct buffer_head * bh;
+	unsigned long b;
+	unsigned long addr_per_block = EXT3_ADDR_PER_BLOCK(inode->i_sb);
+	int addr_per_block_bits = EXT3_ADDR_PER_BLOCK_BITS(inode->i_sb);
+
+	*err = -EIO;
+	if (block < 0) {
+		ext3_warning (inode->i_sb, "ext3_getblk", "block < 0");
+		return NULL;
+	}
+	if (block > EXT3_NDIR_BLOCKS + addr_per_block +
+		(1 << (addr_per_block_bits * 2)) +
+		((1 << (addr_per_block_bits * 2)) << addr_per_block_bits)) {
+		ext3_warning (inode->i_sb, "ext3_getblk", "block > big");
+		return NULL;
+	}
+	/*
+	 * If this is a sequential block allocation, set the next_alloc_block
+	 * to this block now so that all the indblock and data block
+	 * allocations use the same goal zone
+	 */
+
+	ext3_debug ("block %lu, next %lu, goal %lu.\n", block, 
+		    inode->u.ext3_i.i_next_alloc_block,
+		    inode->u.ext3_i.i_next_alloc_goal);
+
+	if (block == inode->u.ext3_i.i_next_alloc_block + 1) {
+		inode->u.ext3_i.i_next_alloc_block++;
+		inode->u.ext3_i.i_next_alloc_goal++;
+	}
+
+	*err = -ENOSPC;
+	b = block;
+	if (block < EXT3_NDIR_BLOCKS)
+		return inode_getblk (handle, inode, block, create, b, err);
+	block -= EXT3_NDIR_BLOCKS;
+	if (block < addr_per_block) {
+		bh = inode_getblk (handle, inode, EXT3_IND_BLOCK, create, b, err);
+		return block_getblk (handle, inode, bh, block, create,
+				     inode->i_sb->s_blocksize, b, err);
+	}
+	block -= addr_per_block;
+	if (block < (1 << (addr_per_block_bits * 2))) {
+		bh = inode_getblk (handle, inode, EXT3_DIND_BLOCK, create, b, err);
+		bh = block_getblk (handle, inode, bh, block >> addr_per_block_bits,
+				   create, inode->i_sb->s_blocksize, b, err);
+		return block_getblk (handle, inode, bh, block & (addr_per_block - 1),
+				     create, inode->i_sb->s_blocksize, b, err);
+	}
+	block -= (1 << (addr_per_block_bits * 2));
+	bh = inode_getblk (handle, inode, EXT3_TIND_BLOCK, create, b, err);
+	bh = block_getblk (handle, inode, bh, block >> (addr_per_block_bits * 2),
+			   create, inode->i_sb->s_blocksize, b, err);
+	bh = block_getblk (handle, inode, bh, (block >> addr_per_block_bits) & (addr_per_block - 1),
+			   create, inode->i_sb->s_blocksize, b, err);
+	return block_getblk (handle, inode, bh, block & (addr_per_block - 1), create,
+			     inode->i_sb->s_blocksize, b, err);
+}
+
+/* For ext3_bread, we need a transaction handle iff create is true. */
+
+struct buffer_head * ext3_bread (handle_t *handle, 
+				 struct inode * inode, int block, 
+				 int create, int *err)
+{
+	struct buffer_head * bh;
+	int prev_blocks;
+	
+	prev_blocks = inode->i_blocks;
+	
+	bh = ext3_getblk (handle, inode, block, create, err);
+	if (!bh)
+		return bh;
+	
+	/*
+	 * If the inode has grown, and this is a directory, then perform
+	 * preallocation of a few more blocks to try to keep directory
+	 * fragmentation down.
+	 */
+	if (create && 
+	    S_ISDIR(inode->i_mode) && 
+	    inode->i_blocks > prev_blocks &&
+	    EXT3_HAS_COMPAT_FEATURE(inode->i_sb,
+				    EXT3_FEATURE_COMPAT_DIR_PREALLOC)) {
+		int i;
+		struct buffer_head *tmp_bh;
+		
+		for (i = 1;
+		     i < EXT3_SB(inode->i_sb)->s_es->s_prealloc_dir_blocks;
+		     i++) {
+			/* 
+			 * ext3_getblk will zero out the contents of the
+			 * directory for us
+			 */
+			tmp_bh = ext3_getblk(handle, inode, block+i, create, err);
+			if (!tmp_bh) {
+				brelse (bh);
+				return 0;
+			}
+			brelse (tmp_bh);
+		}
+	}
+	
+	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;
+}
+
+/* 
+ * ext3_get_inode_loc returns with an extra refcount against the
+ * inode's underlying buffer_head on success. 
+ */
+
+int ext3_get_inode_loc (struct inode *inode, struct ext3_iloc *iloc)
+{
+	struct buffer_head *bh = 0;
+	unsigned long block;
+	unsigned long block_group;
+	unsigned long group_desc;
+	unsigned long desc;
+	unsigned long offset;
+	struct ext3_group_desc * gdp;
+		
+	if ((inode->i_ino != EXT3_ROOT_INO && inode->i_ino != EXT3_ACL_IDX_INO &&
+	     inode->i_ino != EXT3_ACL_DATA_INO &&
+	     inode->i_ino < EXT3_FIRST_INO(inode->i_sb)) ||
+	    inode->i_ino > le32_to_cpu(inode->i_sb->u.ext3_sb.s_es->s_inodes_count)) {
+		ext3_error (inode->i_sb, "ext3_get_inode_loc",
+			    "bad inode number: %lu", inode->i_ino);
+		goto bad_inode;
+	}
+	block_group = (inode->i_ino - 1) / EXT3_INODES_PER_GROUP(inode->i_sb);
+	if (block_group >= inode->i_sb->u.ext3_sb.s_groups_count) {
+		ext3_error (inode->i_sb, "ext3_get_inode_loc",
+			    "group >= groups count");
+		goto bad_inode;
+	}
+	group_desc = block_group >> EXT3_DESC_PER_BLOCK_BITS(inode->i_sb);
+	desc = block_group & (EXT3_DESC_PER_BLOCK(inode->i_sb) - 1);
+	bh = inode->i_sb->u.ext3_sb.s_group_desc[group_desc];
+	if (!bh) {
+		ext3_error (inode->i_sb, "ext3_get_inode_loc",
+			    "Descriptor not loaded");
+		goto bad_inode;
+	}
+
+	gdp = (struct ext3_group_desc *) bh->b_data;
+	/*
+	 * Figure out the offset within the block group inode table
+	 */
+	offset = ((inode->i_ino - 1) % EXT3_INODES_PER_GROUP(inode->i_sb)) *
+		EXT3_INODE_SIZE(inode->i_sb);
+	block = le32_to_cpu(gdp[desc].bg_inode_table) +
+		(offset >> EXT3_BLOCK_SIZE_BITS(inode->i_sb));
+	if (!(bh = bread (inode->i_dev, block, inode->i_sb->s_blocksize))) {
+		ext3_error (inode->i_sb, "ext3_get_inode_loc",
+			    "unable to read inode block - "
+			    "inode=%lu, block=%lu", inode->i_ino, block);
+		goto bad_inode;
+	}
+	offset &= (EXT3_BLOCK_SIZE(inode->i_sb) - 1);
+
+	iloc->bh = bh;
+	iloc->raw_inode = (struct ext3_inode *) (bh->b_data + offset);
+	iloc->block_group = block_group;
+	
+	return 0;
+	
+ bad_inode:
+	return -EIO;
+}
+
+void ext3_read_inode (struct inode * inode)
+{
+	struct ext3_iloc iloc;
+	int block;
+	
+	if(ext3_get_inode_loc(inode, &iloc))
+		goto bad_inode;
+
+	inode->i_mode = le16_to_cpu(iloc.raw_inode->i_mode);
+	inode->i_uid = le16_to_cpu(iloc.raw_inode->i_uid);
+	inode->i_gid = le16_to_cpu(iloc.raw_inode->i_gid);
+	inode->i_nlink = le16_to_cpu(iloc.raw_inode->i_links_count);
+	inode->i_size = le32_to_cpu(iloc.raw_inode->i_size);
+	inode->i_atime = le32_to_cpu(iloc.raw_inode->i_atime);
+	inode->i_ctime = le32_to_cpu(iloc.raw_inode->i_ctime);
+	inode->i_mtime = le32_to_cpu(iloc.raw_inode->i_mtime);
+	inode->u.ext3_i.i_dtime = le32_to_cpu(iloc.raw_inode->i_dtime);
+	inode->i_blksize = PAGE_SIZE;	/* This is the optimal IO size (for stat), not the fs block size */
+	inode->i_blocks = le32_to_cpu(iloc.raw_inode->i_blocks);
+	inode->i_version = ++global_event;
+	inode->u.ext3_i.i_new_inode = 0;
+	inode->u.ext3_i.i_flags = le32_to_cpu(iloc.raw_inode->i_flags);
+	inode->u.ext3_i.i_faddr = le32_to_cpu(iloc.raw_inode->i_faddr);
+	inode->u.ext3_i.i_frag_no = iloc.raw_inode->i_frag;
+	inode->u.ext3_i.i_frag_size = iloc.raw_inode->i_fsize;
+	inode->u.ext3_i.i_osync = 0;
+	inode->u.ext3_i.i_file_acl = le32_to_cpu(iloc.raw_inode->i_file_acl);
+	if (S_ISDIR(inode->i_mode))
+		inode->u.ext3_i.i_dir_acl = le32_to_cpu(iloc.raw_inode->i_dir_acl);
+	else {
+		inode->u.ext3_i.i_dir_acl = 0;
+		inode->u.ext3_i.i_high_size =
+			le32_to_cpu(iloc.raw_inode->i_size_high);
+#if BITS_PER_LONG < 64
+		if (iloc.raw_inode->i_size_high)
+			inode->i_size = (__u32)-1;
+#else
+		inode->i_size |= ((__u64)le32_to_cpu(iloc.raw_inode->i_size_high))
+			<< 32;
+#endif
+	}
+	inode->u.ext3_i.i_version = le32_to_cpu(iloc.raw_inode->i_version);
+	inode->u.ext3_i.i_block_group = iloc.block_group;
+	inode->u.ext3_i.i_next_alloc_block = 0;
+	inode->u.ext3_i.i_next_alloc_goal = 0;
+	if (inode->u.ext3_i.i_prealloc_count)
+		ext3_error (inode->i_sb, "ext3_read_inode",
+			    "New inode has non-zero prealloc count!");
+	if (S_ISCHR(inode->i_mode) || S_ISBLK(inode->i_mode))
+		inode->i_rdev = to_kdev_t(le32_to_cpu(iloc.raw_inode->i_block[0]));
+	else if (S_ISLNK(inode->i_mode) && !inode->i_blocks)
+		for (block = 0; block < EXT3_N_BLOCKS; block++)
+			inode->u.ext3_i.i_data[block] = iloc.raw_inode->i_block[block];
+	else for (block = 0; block < EXT3_N_BLOCKS; block++)
+		inode->u.ext3_i.i_data[block] = le32_to_cpu(iloc.raw_inode->i_block[block]);
+	brelse (iloc.bh);
+	inode->i_op = NULL;
+	if (inode->i_ino == EXT3_ACL_IDX_INO ||
+	    inode->i_ino == EXT3_ACL_DATA_INO)
+		/* Nothing to do */ ;
+	else if (S_ISREG(inode->i_mode))
+		inode->i_op = &ext3_file_inode_operations;
+	else if (S_ISDIR(inode->i_mode))
+		inode->i_op = &ext3_dir_inode_operations;
+	else if (S_ISLNK(inode->i_mode))
+		inode->i_op = &ext3_symlink_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);
+	inode->i_attr_flags = 0;
+	if (inode->u.ext3_i.i_flags & EXT3_SYNC_FL) {
+		inode->i_attr_flags |= ATTR_FLAG_SYNCRONOUS;
+		inode->i_flags |= MS_SYNCHRONOUS;
+	}
+	if (inode->u.ext3_i.i_flags & EXT3_APPEND_FL) {
+		inode->i_attr_flags |= ATTR_FLAG_APPEND;
+		inode->i_flags |= S_APPEND;
+	}
+	if (inode->u.ext3_i.i_flags & EXT3_IMMUTABLE_FL) {
+		inode->i_attr_flags |= ATTR_FLAG_IMMUTABLE;
+		inode->i_flags |= S_IMMUTABLE;
+	}
+	if (inode->u.ext3_i.i_flags & EXT3_NOATIME_FL) {
+		inode->i_attr_flags |= ATTR_FLAG_NOATIME;
+		inode->i_flags |= MS_NOATIME;
+	}
+	return;
+	
+bad_inode:
+	make_bad_inode(inode);
+	return;
+}
+
+/*
+ * Post the struct inode info into an on-disk inode location in the
+ * buffer-cache.  This gobbles the caller's reference to the
+ * buffer_head in the inode location struct.  
+ */
+
+int ext3_do_update_inode(handle_t *handle, 
+			 struct inode *inode, 
+			 struct ext3_iloc *iloc,
+			 int do_sync)
+{
+	struct ext3_inode *raw_inode = iloc->raw_inode;
+	struct buffer_head *bh = iloc->bh;
+	int block;
+	int err = 0;
+
+	if (handle)
+		journal_get_write_access(handle, bh);
+	raw_inode->i_mode = cpu_to_le16(inode->i_mode);
+	raw_inode->i_uid = cpu_to_le16(inode->i_uid);
+	raw_inode->i_gid = cpu_to_le16(inode->i_gid);
+	raw_inode->i_links_count = cpu_to_le16(inode->i_nlink);
+	raw_inode->i_size = cpu_to_le32(inode->i_size);
+	raw_inode->i_atime = cpu_to_le32(inode->i_atime);
+	raw_inode->i_ctime = cpu_to_le32(inode->i_ctime);
+	raw_inode->i_mtime = cpu_to_le32(inode->i_mtime);
+	raw_inode->i_blocks = cpu_to_le32(inode->i_blocks);
+	raw_inode->i_dtime = cpu_to_le32(inode->u.ext3_i.i_dtime);
+	raw_inode->i_flags = cpu_to_le32(inode->u.ext3_i.i_flags);
+	raw_inode->i_faddr = cpu_to_le32(inode->u.ext3_i.i_faddr);
+	raw_inode->i_frag = inode->u.ext3_i.i_frag_no;
+	raw_inode->i_fsize = inode->u.ext3_i.i_frag_size;
+	raw_inode->i_file_acl = cpu_to_le32(inode->u.ext3_i.i_file_acl);
+	if (S_ISDIR(inode->i_mode))
+		raw_inode->i_dir_acl = cpu_to_le32(inode->u.ext3_i.i_dir_acl);
+	else { 
+#if BITS_PER_LONG < 64
+		raw_inode->i_size_high =
+			cpu_to_le32(inode->u.ext3_i.i_high_size);
+#else
+		raw_inode->i_size_high = cpu_to_le32(inode->i_size >> 32);
+#endif
+	}
+	raw_inode->i_version = cpu_to_le32(inode->u.ext3_i.i_version);
+	if (S_ISCHR(inode->i_mode) || S_ISBLK(inode->i_mode))
+		raw_inode->i_block[0] = cpu_to_le32(kdev_t_to_nr(inode->i_rdev));
+	else if (S_ISLNK(inode->i_mode) && !inode->i_blocks)
+		for (block = 0; block < EXT3_N_BLOCKS; block++)
+			raw_inode->i_block[block] = inode->u.ext3_i.i_data[block];
+	else for (block = 0; block < EXT3_N_BLOCKS; block++)
+		raw_inode->i_block[block] = cpu_to_le32(inode->u.ext3_i.i_data[block]);
+
+	if (handle) {
+		journal_dirty_metadata(handle, bh);
+		if (do_sync) 
+			handle->h_sync = 1;
+	} else {
+		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 ext3 inode ["
+					"%s:%08lx]\n",
+					bdevname(inode->i_dev), inode->i_ino);
+				err = -EIO;
+			}
+		}
+	}
+		
+	brelse (bh);
+	return err;
+}
+
+/* ext3_write_inode is only used for flushing in-core un-journaled
+ * dirty inodes from the inode cache to the buffer cache when
+ * reclaiming memory or during a sync().
+ *
+ * We don't actually have to flush the resulting buffer cache entry to
+ * disk: for sync(), that will happen during the write_super() or the
+ * sync_buffers() (depending on whether or not we perform the write as
+ * a journaled operation or not).
+ *
+ * CAUTION: This routine has the potential to interact badly with
+ * journaling.  An existing transaction may call get_empty_inode() in
+ * the VFS, and that may in turn result in a call to ext3_write_inode if
+ * there are too many dirty inodes already in the inode cache.  We
+ * cannot use the existing transaction handle here: it may not be for
+ * the correct filesystem.
+ *
+ * Neither can we start a new transaction: that may deadlock as we
+ * already have a lock on the inode by this point, and starting a new
+ * transaction may require us to wait for the existing one to complete
+ * (which our inode lock may obstruct).
+ *
+ * However, a dirty ext3 inode can only result from an update to a
+ * timestamp or something equally benign: any inode update which
+ * requires journaling will be journaled immediately rather than being
+ * flushed asynchronously from the inode cache.  We are saved: it is
+ * safe to simply update the buffer cache directly: if the buffer is
+ * already being journaled then the existing journaling write ordering
+ * will do the right thing, but if it is not, then it can safely be
+ * flushed to disk immediately.
+ */
+
+void ext3_write_inode(struct inode * inode)
+{
+	struct ext3_iloc iloc;
+	struct buffer_head *bh;
+	journal_t *journal = NULL;
+	int err;
+	
+	err = ext3_get_inode_loc(inode, &iloc);
+	if (err)
+		return;
+
+	bh = iloc.bh;
+	if (bh->b_transaction != NULL) {
+		journal = bh->b_transaction->t_journal;
+		/* We aren't going to mess with the journal, but let's
+                   just be safe and make sure that nobody else is doing
+                   something critical with the buffer right now either */
+		lock_journal(journal);
+	}
+	
+	ext3_do_update_inode(NULL, inode, &iloc, 0);
+
+	if (journal)
+		unlock_journal(journal);
+	return;
+}
+
+int ext3_notify_change(struct dentry *dentry, struct iattr *iattr)
+{
+	struct inode *inode = dentry->d_inode;
+	int		retval;
+	unsigned int	flags;
+	handle_t	*handle = 0;
+	struct ext3_iloc iloc;
+	
+	retval = -EPERM;
+	if (iattr->ia_valid & ATTR_ATTR_FLAG) {
+		if ((iattr->ia_attr_flags &
+		    (ATTR_FLAG_APPEND | ATTR_FLAG_IMMUTABLE)) ^
+		    (inode->u.ext3_i.i_flags &
+		     (EXT3_APPEND_FL | EXT3_IMMUTABLE_FL))) {
+			if (!capable(CAP_LINUX_IMMUTABLE))
+				goto out;
+		}
+	}
+	if (iattr->ia_valid & ATTR_UID) {
+		if ((current->fsuid != inode->i_uid) && !capable(CAP_FOWNER))
+			goto out;
+	}
+	if (iattr->ia_valid & ATTR_SIZE) {
+		off_t size = iattr->ia_size;
+		unsigned long limit = current->rlim[RLIMIT_FSIZE].rlim_cur;
+
+		if (size < 0)
+			return -EINVAL;
+#if BITS_PER_LONG == 64	
+		if (size > ext3_max_sizes[EXT3_BLOCK_SIZE_BITS(inode->i_sb)])
+			return -EFBIG;
+#endif
+ 		if (limit < RLIM_INFINITY && size > limit) {
+			send_sig(SIGXFSZ, current, 0);
+			return -EFBIG;
+		}
+
+#if BITS_PER_LONG == 64	
+		if (size >> 33) {
+			struct super_block *sb = inode->i_sb;
+			struct ext3_super_block *es = sb->u.ext3_sb.s_es;
+
+			if (!(es->s_feature_ro_compat &
+			      cpu_to_le32(EXT3_FEATURE_RO_COMPAT_LARGE_FILE))){
+				struct buffer_head *bh = sb->u.ext3_sb.s_sbh;
+				
+				/* @@@ Error, null handle? */
+				handle = journal_start(EXT3_JOURNAL(inode), 1);
+
+				/* If this is the first large file
+				 * created, add a flag to the superblock */
+				es->s_feature_ro_compat |=
+				cpu_to_le32(EXT3_FEATURE_RO_COMPAT_LARGE_FILE);
+				journal_dirty_metadata(handle, bh); /*@@@err*/
+				journal_stop(handle);
+			}
+		}
+#endif
+	}
+	
+
+	retval = inode_change_ok(inode, iattr);
+	if (retval != 0)
+		goto out;
+
+	/* Notify-change transaction.  The maximum number of buffers
+	 * required is one. */
+
+	/* @@@ Error, null handle? */
+	handle = journal_start(EXT3_JOURNAL(inode), 1);
+	retval = ext3_reserve_inode_write(handle, inode, &iloc);
+	if (retval) 			
+		goto out_stop;
+	
+	inode_setattr(inode, iattr);
+
+	if (iattr->ia_valid & ATTR_ATTR_FLAG) {
+		flags = iattr->ia_attr_flags;
+		if (flags & ATTR_FLAG_SYNCRONOUS) {
+			inode->i_flags |= MS_SYNCHRONOUS;
+			inode->u.ext3_i.i_flags = EXT3_SYNC_FL;
+		} else {
+			inode->i_flags &= ~MS_SYNCHRONOUS;
+			inode->u.ext3_i.i_flags &= ~EXT3_SYNC_FL;
+		}
+		if (flags & ATTR_FLAG_NOATIME) {
+			inode->i_flags |= MS_NOATIME;
+			inode->u.ext3_i.i_flags = EXT3_NOATIME_FL;
+		} else {
+			inode->i_flags &= ~MS_NOATIME;
+			inode->u.ext3_i.i_flags &= ~EXT3_NOATIME_FL;
+		}
+		if (flags & ATTR_FLAG_APPEND) {
+			inode->i_flags |= S_APPEND;
+			inode->u.ext3_i.i_flags = EXT3_APPEND_FL;
+		} else {
+			inode->i_flags &= ~S_APPEND;
+			inode->u.ext3_i.i_flags &= ~EXT3_APPEND_FL;
+		}
+		if (flags & ATTR_FLAG_IMMUTABLE) {
+			inode->i_flags |= S_IMMUTABLE;
+			inode->u.ext3_i.i_flags = EXT3_IMMUTABLE_FL;
+		} else {
+			inode->i_flags &= ~S_IMMUTABLE;
+			inode->u.ext3_i.i_flags &= ~EXT3_IMMUTABLE_FL;
+		}
+	}
+	
+	retval = ext3_mark_iloc_dirty(handle, inode, &iloc);
+
+out_stop:
+	journal_stop(handle);
+out:
+	return retval;
+}
+
Index: oldkernel/linux/fs/ext3/ioctl.c
diff -u /dev/null linux/fs/ext3/ioctl.c:1.1
--- /dev/null	Mon Jul 31 21:15:07 2000
+++ linux/fs/ext3/ioctl.c	Fri Jul  7 16:34:57 2000
@@ -0,0 +1,85 @@
+/*
+ * linux/fs/ext3/ioctl.c
+ *
+ * Copyright (C) 1993, 1994, 1995
+ * Remy Card (card@masi.ibp.fr)
+ * Laboratoire MASI - Institut Blaise Pascal
+ * Universite Pierre et Marie Curie (Paris VI)
+ */
+
+#include <asm/uaccess.h>
+
+#include <linux/errno.h>
+#include <linux/fs.h>
+#include <linux/ext3_fs.h>
+#include <linux/ioctl.h>
+#include <linux/sched.h>
+#include <linux/mm.h>
+
+int ext3_ioctl (struct inode * inode, struct file * filp, unsigned int cmd,
+		unsigned long arg)
+{
+	unsigned int flags;
+
+	ext3_debug ("cmd = %u, arg = %lu\n", cmd, arg);
+
+	switch (cmd) {
+	case EXT3_IOC_GETFLAGS:
+		flags = inode->u.ext3_i.i_flags & EXT3_FL_USER_VISIBLE;
+		return put_user(inode->u.ext3_i.i_flags, (int *) arg);
+	case EXT3_IOC_SETFLAGS:
+		if (get_user(flags, (int *) arg))
+			return -EFAULT;
+		flags = flags & EXT3_FL_USER_MODIFIABLE;
+		/*
+		 * The IMMUTABLE and APPEND_ONLY flags can only be changed by
+		 * a process with the relevent capability.
+		 */
+		if ((flags & (EXT3_APPEND_FL | EXT3_IMMUTABLE_FL)) ^
+		    (inode->u.ext3_i.i_flags &
+		     (EXT3_APPEND_FL | EXT3_IMMUTABLE_FL)))
+			/* This test looks nicer. Thanks to Pauline Middelink */
+			if (!capable(CAP_LINUX_IMMUTABLE))
+				return -EPERM;
+
+		if ((current->fsuid != inode->i_uid) && !capable(CAP_FOWNER))
+			return -EPERM;
+		if (IS_RDONLY(inode))
+			return -EROFS;
+		inode->u.ext3_i.i_flags = (inode->u.ext3_i.i_flags &
+					   ~EXT3_FL_USER_MODIFIABLE) | flags;
+		if (flags & EXT3_SYNC_FL)
+			inode->i_flags |= MS_SYNCHRONOUS;
+		else
+			inode->i_flags &= ~MS_SYNCHRONOUS;
+		if (flags & EXT3_APPEND_FL)
+			inode->i_flags |= S_APPEND;
+		else
+			inode->i_flags &= ~S_APPEND;
+		if (flags & EXT3_IMMUTABLE_FL)
+			inode->i_flags |= S_IMMUTABLE;
+		else
+			inode->i_flags &= ~S_IMMUTABLE;
+		if (flags & EXT3_NOATIME_FL)
+			inode->i_flags |= MS_NOATIME;
+		else
+			inode->i_flags &= ~MS_NOATIME;
+		inode->i_ctime = CURRENT_TIME;
+		mark_inode_dirty(inode);
+		return 0;
+	case EXT3_IOC_GETVERSION:
+		return put_user(inode->u.ext3_i.i_version, (int *) arg);
+	case EXT3_IOC_SETVERSION:
+		if ((current->fsuid != inode->i_uid) && !capable(CAP_FOWNER))
+			return -EPERM;
+		if (IS_RDONLY(inode))
+			return -EROFS;
+		if (get_user(inode->u.ext3_i.i_version, (int *) arg))
+			return -EFAULT;	
+		inode->i_ctime = CURRENT_TIME;
+		mark_inode_dirty(inode);
+		return 0;
+	default:
+		return -ENOTTY;
+	}
+}
Index: oldkernel/linux/fs/ext3/namei.c
diff -u /dev/null linux/fs/ext3/namei.c:1.1
--- /dev/null	Mon Jul 31 21:15:07 2000
+++ linux/fs/ext3/namei.c	Fri Jul  7 16:34:57 2000
@@ -0,0 +1,977 @@
+/*
+ *  linux/fs/ext3/namei.c
+ *
+ * Copyright (C) 1992, 1993, 1994, 1995
+ * Remy Card (card@masi.ibp.fr)
+ * Laboratoire MASI - Institut Blaise Pascal
+ * Universite Pierre et Marie Curie (Paris VI)
+ *
+ *  from
+ *
+ *  linux/fs/minix/namei.c
+ *
+ *  Copyright (C) 1991, 1992  Linus Torvalds
+ *
+ *  Big-endian to little-endian byte-swapping/bitmaps by
+ *        David S. Miller (davem@caip.rutgers.edu), 1995
+ *  Directory entry file type support and forward compatibility hooks
+ *  	for B-tree directories by Theodore Ts'o (tytso@mit.edu), 1998
+ */
+
+#include <asm/uaccess.h>
+
+#include <linux/errno.h>
+#include <linux/fs.h>
+#include <linux/ext3_fs.h>
+#include <linux/ext3_jfs.h>
+#include <linux/fcntl.h>
+#include <linux/sched.h>
+#include <linux/stat.h>
+#include <linux/string.h>
+#include <linux/locks.h>
+#include <linux/quotaops.h>
+
+
+/*
+ * define how far ahead to read directories while searching them.
+ */
+#define NAMEI_RA_CHUNKS  2
+#define NAMEI_RA_BLOCKS  4
+#define NAMEI_RA_SIZE        (NAMEI_RA_CHUNKS * NAMEI_RA_BLOCKS)
+#define NAMEI_RA_INDEX(c,b)  (((c) * NAMEI_RA_BLOCKS) + (b))
+
+/*
+ * NOTE! unlike strncmp, ext3_match returns 1 for success, 0 for failure.
+ *
+ * `len <= EXT3_NAME_LEN' is guaranteed by caller.
+ * `de != NULL' is guaranteed by caller.
+ */
+static inline int ext3_match (int len, const char * const name,
+		       struct ext3_dir_entry_2 * de)
+{
+	if (len != de->name_len)
+		return 0;
+	if (!de->inode)
+		return 0;
+	return !memcmp(name, de->name, len);
+}
+
+/*
+ *	ext3_find_entry()
+ *
+ * finds an entry in the specified directory with the wanted name. It
+ * returns the cache buffer in which the entry was found, and the entry
+ * itself (as a parameter - res_dir). It does NOT read the inode of the
+ * entry - you'll have to do that yourself if you want to.
+ */
+static struct buffer_head * ext3_find_entry (struct inode * dir,
+					     const char * const name, int namelen,
+					     struct ext3_dir_entry_2 ** res_dir)
+{
+	struct super_block * sb;
+	struct buffer_head * bh_use[NAMEI_RA_SIZE];
+	struct buffer_head * bh_read[NAMEI_RA_SIZE];
+	unsigned long offset;
+	int block, toread, i, err;
+
+	*res_dir = NULL;
+	sb = dir->i_sb;
+
+	if (namelen > EXT3_NAME_LEN)
+		return NULL;
+
+	memset (bh_use, 0, sizeof (bh_use));
+	toread = 0;
+	for (block = 0; block < NAMEI_RA_SIZE; ++block) {
+		struct buffer_head * bh;
+
+		if ((block << EXT3_BLOCK_SIZE_BITS (sb)) >= dir->i_size)
+			break;
+		bh = ext3_getblk (NULL, dir, block, 0, &err);
+		bh_use[block] = bh;
+		if (bh && !buffer_uptodate(bh))
+			bh_read[toread++] = bh;
+	}
+
+	for (block = 0, offset = 0; offset < dir->i_size; block++) {
+		struct buffer_head * bh;
+		struct ext3_dir_entry_2 * de;
+		char * dlimit;
+
+		if ((block % NAMEI_RA_BLOCKS) == 0 && toread) {
+			ll_rw_block (READ, toread, bh_read);
+			toread = 0;
+		}
+		bh = bh_use[block % NAMEI_RA_SIZE];
+		if (!bh) {
+#if 0
+			ext3_error (sb, "ext3_find_entry",
+				    "directory #%lu contains a hole at offset %lu",
+				    dir->i_ino, offset);
+#endif
+			offset += sb->s_blocksize;
+			continue;
+		}
+		wait_on_buffer (bh);
+		if (!buffer_uptodate(bh)) {
+			/*
+			 * read error: all bets are off
+			 */
+			break;
+		}
+
+		de = (struct ext3_dir_entry_2 *) bh->b_data;
+		dlimit = bh->b_data + sb->s_blocksize;
+		while ((char *) de < dlimit) {
+			/* this code is executed quadratically often */
+			/* do minimal checking `by hand' */
+			int de_len;
+
+			if ((char *) de + namelen <= dlimit &&
+			    ext3_match (namelen, name, de)) {
+				/* found a match -
+				   just to be sure, do a full check */
+				if (!ext3_check_dir_entry("ext3_find_entry",
+							  dir, de, bh, offset))
+					goto failure;
+				for (i = 0; i < NAMEI_RA_SIZE; ++i) {
+					if (bh_use[i] != bh)
+						brelse (bh_use[i]);
+				}
+				*res_dir = de;
+				return bh;
+			}
+			/* prevent looping on a bad block */
+			de_len = le16_to_cpu(de->rec_len);
+			if (de_len <= 0)
+				goto failure;
+			offset += de_len;
+			de = (struct ext3_dir_entry_2 *)
+				((char *) de + de_len);
+		}
+
+		brelse (bh);
+		if (((block + NAMEI_RA_SIZE) << EXT3_BLOCK_SIZE_BITS (sb)) >=
+		    dir->i_size)
+			bh = NULL;
+		else
+			bh = ext3_getblk (NULL, dir, block + NAMEI_RA_SIZE, 0, &err);
+		bh_use[block % NAMEI_RA_SIZE] = bh;
+		if (bh && !buffer_uptodate(bh))
+			bh_read[toread++] = bh;
+	}
+
+failure:
+	for (i = 0; i < NAMEI_RA_SIZE; ++i)
+		brelse (bh_use[i]);
+	return NULL;
+}
+
+struct dentry *ext3_lookup(struct inode * dir, struct dentry *dentry)
+{
+	struct inode * inode;
+	struct ext3_dir_entry_2 * de;
+	struct buffer_head * bh;
+
+	if (dentry->d_name.len > EXT3_NAME_LEN)
+		return ERR_PTR(-ENAMETOOLONG);
+
+	bh = ext3_find_entry (dir, dentry->d_name.name, dentry->d_name.len, &de);
+	inode = NULL;
+	if (bh) {
+		unsigned long ino = le32_to_cpu(de->inode);
+		brelse (bh);
+		inode = iget(dir->i_sb, ino);
+
+		if (!inode)
+			return ERR_PTR(-EACCES);
+	}
+	d_add(dentry, inode);
+	return NULL;
+}
+
+/*
+ *	ext3_add_entry()
+ *
+ * adds a file entry to the specified directory, using the same
+ * semantics as ext3_find_entry(). It returns NULL if it failed.
+ *
+ * NOTE!! The inode part of 'de' is left at 0 - which means you
+ * may not sleep between calling this and putting something into
+ * the entry, as someone else might have used it while you slept.
+ */
+static struct buffer_head * ext3_add_entry (handle_t * handle,
+					    struct inode * dir,
+					    const char * name, int namelen,
+					    struct ext3_dir_entry_2 ** res_dir,
+					    int *err)
+{
+	unsigned long offset;
+	unsigned short rec_len;
+	struct buffer_head * bh;
+	struct ext3_dir_entry_2 * de, * de1;
+	struct super_block * sb;
+
+	*err = -EINVAL;
+	*res_dir = NULL;
+	if (!dir || !dir->i_nlink)
+		return NULL;
+	sb = dir->i_sb;
+
+	if (!namelen)
+		return NULL;
+	/*
+	 * Is this a busy deleted directory?  Can't create new files if so
+	 */
+	if (dir->i_size == 0)
+	{
+		*err = -ENOENT;
+		return NULL;
+	}
+	bh = ext3_bread (0, dir, 0, 0, err);
+	if (!bh)
+		return NULL;
+	rec_len = EXT3_DIR_REC_LEN(namelen);
+	offset = 0;
+	de = (struct ext3_dir_entry_2 *) bh->b_data;
+	*err = -ENOSPC;
+	while (1) {
+		if ((char *)de >= sb->s_blocksize + bh->b_data) {
+			brelse (bh);
+			bh = NULL;
+			bh = ext3_bread (handle, dir, offset >> EXT3_BLOCK_SIZE_BITS(sb), 1, err);
+			if (!bh)
+				return NULL;
+			if (dir->i_size <= offset) {
+				if (dir->i_size == 0) {
+					*err = -ENOENT;
+					return NULL;
+				}
+
+				ext3_debug ("creating next block\n");
+
+				journal_get_write_access(handle, bh);
+				de = (struct ext3_dir_entry_2 *) bh->b_data;
+				de->inode = 0;
+				de->rec_len = le16_to_cpu(sb->s_blocksize);
+				dir->i_size = offset + sb->s_blocksize;
+				dir->u.ext3_i.i_flags &= ~EXT3_BTREE_FL;
+				ext3_mark_inode_dirty(handle, dir);
+				/* Just keep the buffer reserved for now. */
+				goto got_buffer;
+			} else {
+
+				ext3_debug ("skipping to next block\n");
+
+				de = (struct ext3_dir_entry_2 *) bh->b_data;
+			}
+		}
+		if (!ext3_check_dir_entry ("ext3_add_entry", dir, de, bh,
+					   offset)) {
+			*err = -ENOENT;
+			brelse (bh);
+			return NULL;
+		}
+		if (ext3_match (namelen, name, de)) {
+				*err = -EEXIST;
+				brelse (bh);
+				return NULL;
+		}
+		if ((le32_to_cpu(de->inode) == 0 && le16_to_cpu(de->rec_len) >= rec_len) ||
+		    (le16_to_cpu(de->rec_len) >= EXT3_DIR_REC_LEN(de->name_len) + rec_len)) {
+			journal_get_write_access(handle, bh);
+got_buffer:		/* By now the buffer is marked for journaling */
+			offset += le16_to_cpu(de->rec_len);
+			if (le32_to_cpu(de->inode)) {
+				de1 = (struct ext3_dir_entry_2 *) ((char *) de +
+					EXT3_DIR_REC_LEN(de->name_len));
+				de1->rec_len = cpu_to_le16(le16_to_cpu(de->rec_len) -
+					EXT3_DIR_REC_LEN(de->name_len));
+				de->rec_len = cpu_to_le16(EXT3_DIR_REC_LEN(de->name_len));
+				de = de1;
+			}
+			de->inode = 0;
+			de->name_len = namelen;
+			de->file_type = 0;
+			memcpy (de->name, name, namelen);
+			/*
+			 * XXX shouldn't update any times until successful
+			 * completion of syscall, but too many callers depend
+			 * on this.
+			 *
+			 * XXX similarly, too many callers depend on
+			 * ext3_new_inode() setting the times, but error
+			 * recovery deletes the inode, so the worst that can
+			 * happen is that the times are slightly out of date
+			 * and/or different from the directory change time.
+			 */
+			dir->i_mtime = dir->i_ctime = CURRENT_TIME;
+			dir->u.ext3_i.i_flags &= ~EXT3_BTREE_FL;
+			dir->i_version = ++global_event;
+			ext3_mark_inode_dirty(handle, dir);
+			journal_dirty_metadata(handle, bh);
+			*res_dir = de;
+			*err = 0;
+			return bh;
+		}
+		offset += le16_to_cpu(de->rec_len);
+		de = (struct ext3_dir_entry_2 *) ((char *) de + le16_to_cpu(de->rec_len));
+	}
+	brelse (bh);
+	return NULL;
+}
+
+/*
+ * ext3_delete_entry deletes a directory entry by merging it with the
+ * previous entry
+ */
+static int ext3_delete_entry (handle_t *handle, 
+			      struct ext3_dir_entry_2 * dir,
+			      struct buffer_head * bh)
+{
+	struct ext3_dir_entry_2 * de, * pde;
+	int i;
+
+	i = 0;
+	pde = NULL;
+	de = (struct ext3_dir_entry_2 *) bh->b_data;
+	while (i < bh->b_size) {
+		if (!ext3_check_dir_entry ("ext3_delete_entry", NULL, 
+					   de, bh, i))
+			return -EIO;
+		if (de == dir)  {
+			journal_get_write_access(handle, bh);
+			if (pde)
+				pde->rec_len =
+					cpu_to_le16(le16_to_cpu(pde->rec_len) +
+						    le16_to_cpu(dir->rec_len));
+			else
+				dir->inode = 0;
+			journal_dirty_metadata(handle, bh);
+			return 0;
+		}
+		i += le16_to_cpu(de->rec_len);
+		pde = de;
+		de = (struct ext3_dir_entry_2 *) ((char *) de + le16_to_cpu(de->rec_len));
+	}
+	return -ENOENT;
+}
+
+/*
+ * By the time this is called, we already have created
+ * the directory cache entry for the new file, but it
+ * is so far negative - it has no inode.
+ *
+ * If the create succeeds, we fill in the inode information
+ * with d_instantiate(). 
+ */
+int ext3_create (struct inode * dir, struct dentry * dentry, int mode)
+{
+	struct inode * inode;
+	struct buffer_head * bh;
+	struct ext3_dir_entry_2 * de;
+	handle_t *handle;
+	int err = -EIO;
+
+	handle = journal_start(EXT3_JOURNAL(dir), 
+			       EXT3_DATA_TRANS_BLOCKS + 3);
+
+	/*
+	 * N.B. Several error exits in ext3_new_inode don't set err.
+	 */
+	inode = ext3_new_inode (handle, dir, mode, &err);
+	if (!inode)
+		goto out;
+
+	err = 0;
+	
+	inode->i_op = &ext3_file_inode_operations;
+	inode->i_mode = mode;
+	ext3_mark_inode_dirty(handle, inode); /* @@@ Error? */
+	bh = ext3_add_entry (handle, dir, dentry->d_name.name, dentry->d_name.len, &de, &err);
+	if (!bh) {
+		inode->i_nlink--;
+		ext3_mark_inode_dirty(handle, inode);
+		iput (inode);
+		goto out;
+	}
+	de->inode = cpu_to_le32(inode->i_ino);
+	if (EXT3_HAS_INCOMPAT_FEATURE(dir->i_sb,
+				      EXT3_FEATURE_INCOMPAT_FILETYPE))
+		de->file_type = EXT3_FT_REG_FILE;
+	dir->i_version = ++global_event;
+	if (IS_SYNC(dir))
+		handle->h_sync = 1;
+	brelse (bh);
+	d_instantiate(dentry, inode);
+
+out:
+	journal_stop(handle);
+	return err;
+}
+
+int ext3_mknod (struct inode * dir, struct dentry *dentry, int mode, int rdev)
+{
+	struct inode * inode;
+	struct buffer_head * bh;
+	struct ext3_dir_entry_2 * de;
+	int err = -EIO;
+	handle_t *handle = 0;
+
+	handle = journal_start(EXT3_JOURNAL(dir), 
+			       EXT3_DATA_TRANS_BLOCKS + 3);
+	
+	inode = ext3_new_inode (handle, dir, mode, &err);
+	if (!inode)
+		goto out_stop;
+
+	inode->i_uid = current->fsuid;
+	inode->i_mode = mode;
+	inode->i_op = NULL;
+	bh = ext3_add_entry (handle, dir, dentry->d_name.name, dentry->d_name.len, &de, &err);
+	if (!bh)
+		goto out_no_entry;
+	de->inode = cpu_to_le32(inode->i_ino);
+	dir->i_version = ++global_event;
+	if (S_ISREG(inode->i_mode)) {
+		inode->i_op = &ext3_file_inode_operations;
+		if (EXT3_HAS_INCOMPAT_FEATURE(dir->i_sb,
+					      EXT3_FEATURE_INCOMPAT_FILETYPE))
+			de->file_type = EXT3_FT_REG_FILE;
+	} else if (S_ISCHR(inode->i_mode)) {
+		inode->i_op = &chrdev_inode_operations;
+		if (EXT3_HAS_INCOMPAT_FEATURE(dir->i_sb,
+					      EXT3_FEATURE_INCOMPAT_FILETYPE))
+			de->file_type = EXT3_FT_CHRDEV;
+	} else if (S_ISBLK(inode->i_mode)) {
+		inode->i_op = &blkdev_inode_operations;
+		if (EXT3_HAS_INCOMPAT_FEATURE(dir->i_sb,
+					      EXT3_FEATURE_INCOMPAT_FILETYPE))
+			de->file_type = EXT3_FT_BLKDEV;
+	} else if (S_ISFIFO(inode->i_mode))  {
+		init_fifo(inode);
+		if (EXT3_HAS_INCOMPAT_FEATURE(dir->i_sb,
+					      EXT3_FEATURE_INCOMPAT_FILETYPE))
+			de->file_type = EXT3_FT_FIFO;
+	}
+	if (S_ISBLK(mode) || S_ISCHR(mode))
+		inode->i_rdev = to_kdev_t(rdev);
+	ext3_mark_inode_dirty(handle, inode);
+	journal_dirty_metadata(handle, bh);
+	if (IS_SYNC(dir))
+		handle->h_sync = 1;
+	d_instantiate(dentry, inode);
+	brelse(bh);
+out_stop:
+	journal_stop(handle);
+	return err;
+
+out_no_entry:
+	inode->i_nlink--;
+	ext3_mark_inode_dirty(handle, inode);
+	iput(inode);
+	goto out_stop;
+}
+
+int ext3_mkdir(struct inode * dir, struct dentry * dentry, int mode)
+{
+	struct inode * inode;
+	struct buffer_head * bh, * dir_block;
+	struct ext3_dir_entry_2 * de;
+	handle_t *handle = 0;
+	int err;
+
+	err = -EMLINK;
+	if (dir->i_nlink >= EXT3_LINK_MAX)
+		goto out;
+
+	handle = journal_start(EXT3_JOURNAL(dir), 
+			       EXT3_DATA_TRANS_BLOCKS + 4);
+	err = -EIO;
+	inode = ext3_new_inode (handle, dir, S_IFDIR, &err);
+	if (!inode)
+		goto out_stop;
+
+	inode->i_op = &ext3_dir_inode_operations;
+	inode->i_size = inode->i_sb->s_blocksize;
+	inode->i_blocks = 0;	
+	dir_block = ext3_bread (handle, inode, 0, 1, &err);
+	if (!dir_block) {
+		inode->i_nlink--; /* is this nlink == 0? */
+		ext3_mark_inode_dirty(handle, inode);
+		iput (inode);
+		goto out_stop;
+	}
+	journal_get_write_access(handle, dir_block);
+	de = (struct ext3_dir_entry_2 *) dir_block->b_data;
+	de->inode = cpu_to_le32(inode->i_ino);
+	de->name_len = 1;
+	de->rec_len = cpu_to_le16(EXT3_DIR_REC_LEN(de->name_len));
+	strcpy (de->name, ".");
+	if (EXT3_HAS_INCOMPAT_FEATURE(dir->i_sb,
+				      EXT3_FEATURE_INCOMPAT_FILETYPE))
+		de->file_type = EXT3_FT_DIR;
+	de = (struct ext3_dir_entry_2 *) ((char *) de + le16_to_cpu(de->rec_len));
+	de->inode = cpu_to_le32(dir->i_ino);
+	de->rec_len = cpu_to_le16(inode->i_sb->s_blocksize - EXT3_DIR_REC_LEN(1));
+	de->name_len = 2;
+	strcpy (de->name, "..");
+	if (EXT3_HAS_INCOMPAT_FEATURE(dir->i_sb,
+				      EXT3_FEATURE_INCOMPAT_FILETYPE))
+		de->file_type = EXT3_FT_DIR;
+	inode->i_nlink = 2;
+	journal_dirty_metadata(handle, dir_block);
+	brelse (dir_block);
+	inode->i_mode = S_IFDIR | (mode & (S_IRWXUGO|S_ISVTX) & ~current->fs->umask);
+	if (dir->i_mode & S_ISGID)
+		inode->i_mode |= S_ISGID;
+	ext3_mark_inode_dirty(handle, inode);
+	bh = ext3_add_entry (handle, dir, dentry->d_name.name, dentry->d_name.len, &de, &err);
+	if (!bh)
+		goto out_no_entry;
+	de->inode = cpu_to_le32(inode->i_ino);
+	if (EXT3_HAS_INCOMPAT_FEATURE(dir->i_sb,
+				      EXT3_FEATURE_INCOMPAT_FILETYPE))
+		de->file_type = EXT3_FT_DIR;
+	dir->i_version = ++global_event;
+	journal_dirty_metadata(handle, bh);
+	dir->i_nlink++;
+	dir->u.ext3_i.i_flags &= ~EXT3_BTREE_FL;
+	ext3_mark_inode_dirty(handle, dir);
+	if (IS_SYNC(dir)) 
+		handle->h_sync = 1;
+	d_instantiate(dentry, inode);
+	brelse (bh);
+	err = 0;
+
+out_stop:
+	journal_stop(handle);
+out:
+	return err;
+
+out_no_entry:
+	inode->i_nlink = 0;
+	ext3_mark_inode_dirty(handle, inode);
+	/* The implicit delete in the iput() will be dealt with as a
+	 * recursive transaction. */
+	iput (inode);
+	goto out_stop;
+}
+
+/*
+ * routine to check that the specified directory is empty (for rmdir)
+ */
+static int empty_dir (struct inode * inode)
+{
+	unsigned long offset;
+	struct buffer_head * bh;
+	struct ext3_dir_entry_2 * de, * de1;
+	struct super_block * sb;
+	int err;
+
+	sb = inode->i_sb;
+	if (inode->i_size < EXT3_DIR_REC_LEN(1) + EXT3_DIR_REC_LEN(2) ||
+	    !(bh = ext3_bread (NULL, inode, 0, 0, &err))) {
+	    	ext3_warning (inode->i_sb, "empty_dir",
+			      "bad directory (dir #%lu) - no data block",
+			      inode->i_ino);
+		return 1;
+	}
+	de = (struct ext3_dir_entry_2 *) bh->b_data;
+	de1 = (struct ext3_dir_entry_2 *) ((char *) de + le16_to_cpu(de->rec_len));
+	if (le32_to_cpu(de->inode) != inode->i_ino || !le32_to_cpu(de1->inode) || 
+	    strcmp (".", de->name) || strcmp ("..", de1->name)) {
+	    	ext3_warning (inode->i_sb, "empty_dir",
+			      "bad directory (dir #%lu) - no `.' or `..'",
+			      inode->i_ino);
+		brelse (bh);
+		return 1;
+	}
+	offset = le16_to_cpu(de->rec_len) + le16_to_cpu(de1->rec_len);
+	de = (struct ext3_dir_entry_2 *) ((char *) de1 + le16_to_cpu(de1->rec_len));
+	while (offset < inode->i_size ) {
+		if (!bh || (void *) de >= (void *) (bh->b_data + sb->s_blocksize)) {
+			brelse (bh);
+			bh = ext3_bread (NULL, inode, offset >> EXT3_BLOCK_SIZE_BITS(sb), 0, &err);
+			if (!bh) {
+#if 0
+				ext3_error (sb, "empty_dir",
+					    "directory #%lu contains a hole at offset %lu",
+					    inode->i_ino, offset);
+#endif
+				offset += sb->s_blocksize;
+				continue;
+			}
+			de = (struct ext3_dir_entry_2 *) bh->b_data;
+		}
+		if (!ext3_check_dir_entry ("empty_dir", inode, de, bh,
+					   offset)) {
+			brelse (bh);
+			return 1;
+		}
+		if (le32_to_cpu(de->inode)) {
+			brelse (bh);
+			return 0;
+		}
+		offset += le16_to_cpu(de->rec_len);
+		de = (struct ext3_dir_entry_2 *) ((char *) de + le16_to_cpu(de->rec_len));
+	}
+	brelse (bh);
+	return 1;
+}
+
+int ext3_rmdir (struct inode * dir, struct dentry *dentry)
+{
+	int retval;
+	struct inode * inode;
+	struct buffer_head * bh;
+	struct ext3_dir_entry_2 * de;
+	handle_t *handle;
+	
+	handle = journal_start(EXT3_JOURNAL(dir), 
+			       EXT3_DELETE_TRANS_BLOCKS);
+
+	retval = -ENOENT;
+	bh = ext3_find_entry (dir, dentry->d_name.name, dentry->d_name.len, &de);
+	if (!bh)
+		goto end_rmdir;
+
+	inode = dentry->d_inode;
+	DQUOT_INIT(inode);
+
+	retval = -EIO;
+	if (le32_to_cpu(de->inode) != inode->i_ino)
+		goto end_rmdir;
+
+	retval = -ENOTEMPTY;
+	if (!empty_dir (inode))
+		goto end_rmdir;
+
+	retval = ext3_delete_entry (handle, de, bh); /* @@@ handle */
+	dir->i_version = ++global_event;
+
+	if (retval)
+		goto end_rmdir;
+	if (inode->i_nlink != 2)
+		ext3_warning (inode->i_sb, "ext3_rmdir",
+			      "empty directory has nlink!=2 (%d)",
+			      inode->i_nlink);
+	inode->i_version = ++global_event;
+	inode->i_nlink = 0;
+	inode->i_size = 0;
+	ext3_mark_inode_dirty(handle, inode);
+	dir->i_nlink--;
+	inode->i_ctime = dir->i_ctime = dir->i_mtime = CURRENT_TIME;
+	dir->u.ext3_i.i_flags &= ~EXT3_BTREE_FL;
+	ext3_mark_inode_dirty(handle, dir);
+	d_delete(dentry);
+	if (IS_SYNC(dir)) 
+		handle->h_sync = 1;
+
+end_rmdir:
+	journal_stop(handle);
+	brelse (bh);
+	return retval;
+}
+
+int ext3_unlink(struct inode * dir, struct dentry *dentry)
+{
+	int retval;
+	struct inode * inode;
+	struct buffer_head * bh;
+	struct ext3_dir_entry_2 * de;
+	handle_t *handle;
+	
+	handle = journal_start(EXT3_JOURNAL(dir), 
+			       EXT3_DELETE_TRANS_BLOCKS);
+
+	retval = -ENOENT;
+	bh = ext3_find_entry (dir, dentry->d_name.name, dentry->d_name.len, &de);
+	if (!bh)
+		goto end_unlink;
+
+	inode = dentry->d_inode;
+	DQUOT_INIT(inode);
+
+	retval = -EIO;
+	if (le32_to_cpu(de->inode) != inode->i_ino)
+		goto end_unlink;
+	
+	if (!inode->i_nlink) {
+		ext3_warning (inode->i_sb, "ext3_unlink",
+			      "Deleting nonexistent file (%lu), %d",
+			      inode->i_ino, inode->i_nlink);
+		inode->i_nlink = 1;
+	}
+	retval = ext3_delete_entry (handle, de, bh);
+	if (retval)
+		goto end_unlink;
+	dir->i_version = ++global_event;
+	if (IS_SYNC(dir))
+		handle->h_sync = 1;
+	dir->i_ctime = dir->i_mtime = CURRENT_TIME;
+	dir->u.ext3_i.i_flags &= ~EXT3_BTREE_FL;
+	ext3_mark_inode_dirty(handle, dir);
+	inode->i_nlink--;
+	ext3_mark_inode_dirty(handle, inode);
+	inode->i_ctime = dir->i_ctime;
+	retval = 0;
+	d_delete(dentry);	/* This also frees the inode */
+
+end_unlink:
+	journal_stop(handle);
+	brelse (bh);
+	return retval;
+}
+
+int ext3_symlink (struct inode * dir, struct dentry *dentry, const char * symname)
+{
+	struct ext3_dir_entry_2 * de;
+	struct inode * inode;
+	struct buffer_head * bh = NULL, * name_block = NULL;
+	char * link;
+	int i, l, err = -EIO;
+	char c;
+	handle_t *handle;
+	
+	handle = journal_start(EXT3_JOURNAL(dir), 
+			       EXT3_DATA_TRANS_BLOCKS + 5);
+
+	if (!(inode = ext3_new_inode (handle, dir, S_IFLNK, &err)))
+		goto out;
+	inode->i_mode = S_IFLNK | S_IRWXUGO;
+	inode->i_op = &ext3_symlink_inode_operations;
+	for (l = 0; l < inode->i_sb->s_blocksize - 1 &&
+	     symname [l]; l++)
+		;
+	if (l >= sizeof (inode->u.ext3_i.i_data)) {
+
+		ext3_debug ("l=%d, normal symlink\n", l);
+
+		name_block = ext3_bread (handle, inode, 0, 1, &err);
+		if (!name_block) {
+			inode->i_nlink--;
+			ext3_mark_inode_dirty(handle, inode);
+			iput (inode);
+			goto out;
+		}
+		link = name_block->b_data;
+		journal_get_write_access(handle, name_block);
+	} else {
+		link = (char *) inode->u.ext3_i.i_data;
+
+		ext3_debug ("l=%d, fast symlink\n", l);
+
+	}
+	i = 0;
+	while (i < inode->i_sb->s_blocksize - 1 && (c = *(symname++)))
+		link[i++] = c;
+	link[i] = 0;
+	if (name_block) {
+		journal_dirty_metadata(handle, name_block);
+		brelse (name_block);
+	}
+	inode->i_size = i;
+	ext3_mark_inode_dirty(handle, inode);
+
+	bh = ext3_add_entry (handle, dir, dentry->d_name.name, dentry->d_name.len, &de, &err);
+	if (!bh)
+		goto out_no_entry;
+	de->inode = cpu_to_le32(inode->i_ino);
+	if (EXT3_HAS_INCOMPAT_FEATURE(dir->i_sb,
+				      EXT3_FEATURE_INCOMPAT_FILETYPE))
+		de->file_type = EXT3_FT_SYMLINK;
+	dir->i_version = ++global_event;
+	if (IS_SYNC(dir)) 
+		handle->h_sync = 1;
+	brelse (bh);
+	d_instantiate(dentry, inode);
+	err = 0;
+out:
+	journal_stop(handle);
+	return err;
+
+out_no_entry:
+	inode->i_nlink--;
+	ext3_mark_inode_dirty(handle, inode);
+	iput (inode);
+	goto out;
+}
+
+int ext3_link (struct dentry * old_dentry,
+		struct inode * dir, struct dentry *dentry)
+{
+	struct inode *inode = old_dentry->d_inode;
+	struct ext3_dir_entry_2 * de;
+	struct buffer_head * bh;
+	int err;
+	handle_t *handle;
+
+	if (S_ISDIR(inode->i_mode))
+		return -EPERM;
+
+	if (inode->i_nlink >= EXT3_LINK_MAX)
+		return -EMLINK;
+
+	handle = journal_start(EXT3_JOURNAL(dir), 
+			       EXT3_DATA_TRANS_BLOCKS);
+	
+	bh = ext3_add_entry (handle, dir, dentry->d_name.name, dentry->d_name.len, &de, &err);
+	if (!bh)
+		goto out;
+
+	de->inode = cpu_to_le32(inode->i_ino);
+	if (EXT3_HAS_INCOMPAT_FEATURE(inode->i_sb,
+				      EXT3_FEATURE_INCOMPAT_FILETYPE)) {
+		if (S_ISREG(inode->i_mode))
+			de->file_type = EXT3_FT_REG_FILE;
+		else if (S_ISDIR(inode->i_mode))
+			de->file_type = EXT3_FT_DIR;
+		else if (S_ISLNK(inode->i_mode))
+			de->file_type = EXT3_FT_SYMLINK;
+		else if (S_ISCHR(inode->i_mode))
+			de->file_type = EXT3_FT_CHRDEV;
+		else if (S_ISBLK(inode->i_mode))
+			de->file_type = EXT3_FT_BLKDEV;
+		else if (S_ISFIFO(inode->i_mode))  
+			de->file_type = EXT3_FT_FIFO;
+	}
+	dir->i_version = ++global_event;
+	if (IS_SYNC(dir))
+		handle->h_sync = 1;
+	brelse (bh);
+	inode->i_nlink++;
+	inode->i_ctime = CURRENT_TIME;
+	ext3_mark_inode_dirty(handle, inode);
+	inode->i_count++;
+	d_instantiate(dentry, inode);
+	err = 0;
+out:
+	journal_stop(handle);
+	return err;
+}
+
+#define PARENT_INO(buffer) \
+	((struct ext3_dir_entry_2 *) ((char *) buffer + \
+	le16_to_cpu(((struct ext3_dir_entry_2 *) buffer)->rec_len)))->inode
+
+/*
+ * Anybody can rename anything with this: the permission checks are left to the
+ * higher-level routines.
+ */
+int ext3_rename (struct inode * old_dir, struct dentry *old_dentry,
+			   struct inode * new_dir,struct dentry *new_dentry)
+{
+	struct inode * old_inode, * new_inode;
+	struct buffer_head * old_bh, * new_bh, * dir_bh;
+	struct ext3_dir_entry_2 * old_de, * new_de;
+	int retval;
+	handle_t *handle;
+	
+	old_bh = new_bh = dir_bh = NULL;
+
+	handle = journal_start(EXT3_JOURNAL(old_dir), 
+			       2 * EXT3_DATA_TRANS_BLOCKS + 2);
+
+	old_bh = ext3_find_entry (old_dir, old_dentry->d_name.name, old_dentry->d_name.len, &old_de);
+	/*
+	 *  Check for inode number is _not_ due to possible IO errors.
+	 *  We might rmdir the source, keep it as pwd of some process
+	 *  and merrily kill the link to whatever was created under the
+	 *  same name. Goodbye sticky bit ;-<
+	 */
+	old_inode = old_dentry->d_inode;
+	retval = -ENOENT;
+	if (!old_bh || le32_to_cpu(old_de->inode) != old_inode->i_ino)
+		goto end_rename;
+
+	new_inode = new_dentry->d_inode;
+	new_bh = ext3_find_entry (new_dir, new_dentry->d_name.name,
+				new_dentry->d_name.len, &new_de);
+	if (new_bh) {
+		if (!new_inode) {
+			brelse (new_bh);
+			new_bh = NULL;
+		} else {
+			DQUOT_INIT(new_inode);
+		}
+	}
+	if (S_ISDIR(old_inode->i_mode)) {
+		if (new_inode) {
+			retval = -ENOTEMPTY;
+			if (!empty_dir (new_inode))
+				goto end_rename;
+		}
+		retval = -EIO;
+		dir_bh = ext3_bread (NULL, old_inode, 0, 0, &retval);
+		if (!dir_bh)
+			goto end_rename;
+		if (le32_to_cpu(PARENT_INO(dir_bh->b_data)) != old_dir->i_ino)
+			goto end_rename;
+		retval = -EMLINK;
+		if (!new_inode && new_dir!=old_dir &&
+				new_dir->i_nlink >= EXT3_LINK_MAX)
+			goto end_rename;
+	}
+	if (!new_bh) {
+		new_bh = ext3_add_entry (handle, new_dir, new_dentry->d_name.name,
+					new_dentry->d_name.len, &new_de,
+					&retval);
+		if (!new_bh)
+			goto end_rename;
+	}
+	new_dir->i_version = ++global_event;
+
+	/*
+	 * ok, that's it
+	 */
+
+	journal_get_write_access(handle, old_bh);
+	journal_get_write_access(handle, new_bh);
+	if (dir_bh)
+		journal_get_write_access(handle, dir_bh);
+
+	new_de->inode = le32_to_cpu(old_inode->i_ino);
+	if (EXT3_HAS_INCOMPAT_FEATURE(new_dir->i_sb,
+				      EXT3_FEATURE_INCOMPAT_FILETYPE))
+		new_de->file_type = old_de->file_type;
+	
+	ext3_delete_entry (handle, old_de, old_bh); /* @@@ HANDLE */
+
+	old_dir->i_version = ++global_event;
+	if (new_inode) {
+		new_inode->i_nlink--;
+		new_inode->i_ctime = CURRENT_TIME;
+		ext3_mark_inode_dirty(handle, new_inode);
+	}
+	old_dir->i_ctime = old_dir->i_mtime = CURRENT_TIME;
+	old_dir->u.ext3_i.i_flags &= ~EXT3_BTREE_FL;
+	ext3_mark_inode_dirty(handle, old_dir);
+	if (dir_bh) {
+		PARENT_INO(dir_bh->b_data) = le32_to_cpu(new_dir->i_ino);
+		journal_dirty_metadata(handle, dir_bh);
+		old_dir->i_nlink--;
+		ext3_mark_inode_dirty(handle, old_dir);
+		if (new_inode) {
+			new_inode->i_nlink--;
+			ext3_mark_inode_dirty(handle, new_inode);
+		} else {
+			new_dir->i_nlink++;
+			new_dir->u.ext3_i.i_flags &= ~EXT3_BTREE_FL;
+			ext3_mark_inode_dirty(handle, new_dir);
+		}
+	}
+	journal_dirty_metadata(handle, old_bh);
+	journal_dirty_metadata(handle, new_bh);
+	if (IS_SYNC(old_dir) || IS_SYNC(new_dir))
+		handle->h_sync = 1;
+
+	retval = 0;
+
+end_rename:
+	brelse (dir_bh);
+	brelse (old_bh);
+	brelse (new_bh);
+	journal_stop(handle);
+	return retval;
+}
Index: oldkernel/linux/fs/ext3/super.c
diff -u /dev/null linux/fs/ext3/super.c:1.1
--- /dev/null	Mon Jul 31 21:15:07 2000
+++ linux/fs/ext3/super.c	Fri Jul  7 16:34:57 2000
@@ -0,0 +1,1036 @@
+/*
+ *  linux/fs/ext3/super.c
+ *
+ * Copyright (C) 1992, 1993, 1994, 1995
+ * Remy Card (card@masi.ibp.fr)
+ * Laboratoire MASI - Institut Blaise Pascal
+ * Universite Pierre et Marie Curie (Paris VI)
+ *
+ *  from
+ *
+ *  linux/fs/minix/inode.c
+ *
+ *  Copyright (C) 1991, 1992  Linus Torvalds
+ *
+ *  Big-endian to little-endian byte-swapping/bitmaps by
+ *        David S. Miller (davem@caip.rutgers.edu), 1995
+ */
+
+#include <linux/module.h>
+
+#include <stdarg.h>
+
+#include <asm/bitops.h>
+#include <asm/uaccess.h>
+#include <asm/system.h>
+
+#include <linux/errno.h>
+#include <linux/fs.h>
+#include <linux/jfs.h>
+#include <linux/ext3_fs.h>
+#include <linux/malloc.h>
+#include <linux/sched.h>
+#include <linux/stat.h>
+#include <linux/string.h>
+#include <linux/locks.h>
+#include <linux/blkdev.h>
+#include <linux/init.h>
+
+static char error_buf[1024];
+
+static int ext3_load_journal(struct super_block *, struct ext3_super_block *);
+static int ext3_create_journal(struct super_block *, struct ext3_super_block *,
+			       int);
+static void ext3_commit_super (struct super_block * sb,
+			       struct ext3_super_block * es, 
+			       int sync);
+
+void ext3_error (struct super_block * sb, const char * function,
+		 const char * fmt, ...)
+{
+	va_list args;
+
+	if (!(sb->s_flags & MS_RDONLY)) {
+		sb->u.ext3_sb.s_mount_state |= EXT3_ERROR_FS;
+		sb->u.ext3_sb.s_es->s_state =
+			cpu_to_le16(le16_to_cpu(sb->u.ext3_sb.s_es->s_state) | EXT3_ERROR_FS);
+		mark_buffer_dirty(sb->u.ext3_sb.s_sbh, 1);
+		sb->s_dirt = 1;
+	}
+	va_start (args, fmt);
+	vsprintf (error_buf, fmt, args);
+	va_end (args);
+	if (test_opt (sb, ERRORS_PANIC) ||
+	    (le16_to_cpu(sb->u.ext3_sb.s_es->s_errors) == EXT3_ERRORS_PANIC &&
+	     !test_opt (sb, ERRORS_CONT) && !test_opt (sb, ERRORS_RO)))
+		panic ("EXT3-fs panic (device %s): %s: %s\n",
+		       bdevname(sb->s_dev), function, error_buf);
+	printk (KERN_CRIT "EXT3-fs error (device %s): %s: %s\n",
+		bdevname(sb->s_dev), function, error_buf);
+	if (test_opt (sb, ERRORS_RO) ||
+	    (le16_to_cpu(sb->u.ext3_sb.s_es->s_errors) == EXT3_ERRORS_RO &&
+	     !test_opt (sb, ERRORS_CONT) && !test_opt (sb, ERRORS_PANIC))) {
+		printk ("Remounting filesystem read-only\n");
+		sb->s_flags |= MS_RDONLY;
+	}
+}
+
+NORET_TYPE void ext3_panic (struct super_block * sb, const char * function,
+			    const char * fmt, ...)
+{
+	va_list args;
+
+	if (!(sb->s_flags & MS_RDONLY)) {
+		sb->u.ext3_sb.s_mount_state |= EXT3_ERROR_FS;
+		sb->u.ext3_sb.s_es->s_state =
+			cpu_to_le16(le16_to_cpu(sb->u.ext3_sb.s_es->s_state) | EXT3_ERROR_FS);
+		mark_buffer_dirty(sb->u.ext3_sb.s_sbh, 1);
+		sb->s_dirt = 1;
+	}
+	va_start (args, fmt);
+	vsprintf (error_buf, fmt, args);
+	va_end (args);
+	/* this is to prevent panic from syncing this filesystem */
+	if (sb->s_lock)
+		sb->s_lock=0;
+	sb->s_flags |= MS_RDONLY;
+	panic ("EXT3-fs panic (device %s): %s: %s\n",
+	       bdevname(sb->s_dev), function, error_buf);
+}
+
+void ext3_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 "EXT3-fs warning (device %s): %s: %s\n",
+		bdevname(sb->s_dev), function, error_buf);
+}
+
+void ext3_put_super (struct super_block * sb)
+{
+	int db_count;
+	int i;
+	struct ext3_super_block *es = EXT3_SB(sb)->s_es;
+
+	journal_release(EXT3_SB(sb)->s_journal);
+	if (!(sb->s_flags & MS_RDONLY)) {
+		es->s_feature_incompat &= cpu_to_le32(~EXT3_FEATURE_INCOMPAT_RECOVER);
+		es->s_state = le16_to_cpu(EXT3_SB(sb)->s_mount_state);
+		mark_buffer_dirty(EXT3_SB(sb)->s_sbh, 1);
+	}
+
+	db_count = EXT3_SB(sb)->s_db_per_group;
+	for (i = 0; i < db_count; i++)
+		if (EXT3_SB(sb)->s_group_desc[i])
+			brelse (EXT3_SB(sb)->s_group_desc[i]);
+	kfree_s (EXT3_SB(sb)->s_group_desc,
+		 db_count * sizeof (struct buffer_head *));
+	for (i = 0; i < EXT3_MAX_GROUP_LOADED; i++)
+		if (EXT3_SB(sb)->s_inode_bitmap[i])
+			brelse (EXT3_SB(sb)->s_inode_bitmap[i]);
+	for (i = 0; i < EXT3_MAX_GROUP_LOADED; i++)
+		if (EXT3_SB(sb)->s_block_bitmap[i])
+			brelse (EXT3_SB(sb)->s_block_bitmap[i]);
+	brelse (EXT3_SB(sb)->s_sbh);
+
+	MOD_DEC_USE_COUNT;
+	return;
+}
+
+static struct super_operations ext3_sops = {
+	ext3_read_inode,
+	ext3_write_inode,
+	ext3_put_inode,
+	ext3_delete_inode,
+	ext3_notify_change,
+	ext3_put_super,
+	ext3_write_super,
+	ext3_statfs,
+	ext3_remount
+};
+
+/*
+ * This function has been shamelessly adapted from the msdos fs
+ */
+static int parse_options (char * options, unsigned long * sb_block,
+			  unsigned short *resuid, unsigned short * resgid,
+			  unsigned long * mount_options, 
+			  unsigned long * inum)
+{
+	char * this_char;
+	char * value;
+
+	if (!options)
+		return 1;
+	for (this_char = strtok (options, ",");
+	     this_char != NULL;
+	     this_char = strtok (NULL, ",")) {
+		if ((value = strchr (this_char, '=')) != NULL)
+			*value++ = 0;
+		if (!strcmp (this_char, "bsddf"))
+			clear_opt (*mount_options, MINIX_DF);
+		else if (!strcmp (this_char, "check")) {
+			if (!value || !*value)
+				set_opt (*mount_options, CHECK_NORMAL);
+			else if (!strcmp (value, "none")) {
+				clear_opt (*mount_options, CHECK_NORMAL);
+				clear_opt (*mount_options, CHECK_STRICT);
+			}
+			else if (!strcmp (value, "normal"))
+				set_opt (*mount_options, CHECK_NORMAL);
+			else if (!strcmp (value, "strict")) {
+				set_opt (*mount_options, CHECK_NORMAL);
+				set_opt (*mount_options, CHECK_STRICT);
+			}
+			else {
+				printk ("EXT3-fs: Invalid check option: %s\n",
+					value);
+				return 0;
+			}
+		}
+		else if (!strcmp (this_char, "debug"))
+			set_opt (*mount_options, DEBUG);
+		else if (!strcmp (this_char, "errors")) {
+			if (!value || !*value) {
+				printk ("EXT3-fs: the errors option requires "
+					"an argument");
+				return 0;
+			}
+			if (!strcmp (value, "continue")) {
+				clear_opt (*mount_options, ERRORS_RO);
+				clear_opt (*mount_options, ERRORS_PANIC);
+				set_opt (*mount_options, ERRORS_CONT);
+			}
+			else if (!strcmp (value, "remount-ro")) {
+				clear_opt (*mount_options, ERRORS_CONT);
+				clear_opt (*mount_options, ERRORS_PANIC);
+				set_opt (*mount_options, ERRORS_RO);
+			}
+			else if (!strcmp (value, "panic")) {
+				clear_opt (*mount_options, ERRORS_CONT);
+				clear_opt (*mount_options, ERRORS_RO);
+				set_opt (*mount_options, ERRORS_PANIC);
+			}
+			else {
+				printk ("EXT3-fs: Invalid errors option: %s\n",
+					value);
+				return 0;
+			}
+		}
+		else if (!strcmp (this_char, "grpid") ||
+			 !strcmp (this_char, "bsdgroups"))
+			set_opt (*mount_options, GRPID);
+		else if (!strcmp (this_char, "minixdf"))
+			set_opt (*mount_options, MINIX_DF);
+		else if (!strcmp (this_char, "nocheck")) {
+			clear_opt (*mount_options, CHECK_NORMAL);
+			clear_opt (*mount_options, CHECK_STRICT);
+		}
+		else if (!strcmp (this_char, "nogrpid") ||
+			 !strcmp (this_char, "sysvgroups"))
+			clear_opt (*mount_options, GRPID);
+		else if (!strcmp (this_char, "resgid")) {
+			if (!value || !*value) {
+				printk ("EXT3-fs: the resgid option requires "
+					"an argument");
+				return 0;
+			}
+			*resgid = simple_strtoul (value, &value, 0);
+			if (*value) {
+				printk ("EXT3-fs: Invalid resgid option: %s\n",
+					value);
+				return 0;
+			}
+		}
+		else if (!strcmp (this_char, "resuid")) {
+			if (!value || !*value) {
+				printk ("EXT3-fs: the resuid option requires "
+					"an argument");
+				return 0;
+			}
+			*resuid = simple_strtoul (value, &value, 0);
+			if (*value) {
+				printk ("EXT3-fs: Invalid resuid option: %s\n",
+					value);
+				return 0;
+			}
+		}
+		else if (!strcmp (this_char, "sb")) {
+			if (!value || !*value) {
+				printk ("EXT3-fs: the sb option requires "
+					"an argument");
+				return 0;
+			}
+			*sb_block = simple_strtoul (value, &value, 0);
+			if (*value) {
+				printk ("EXT3-fs: Invalid sb option: %s\n",
+					value);
+				return 0;
+			}
+		}
+		/* Silently ignore the quota options */
+		else if (!strcmp (this_char, "grpquota")
+		         || !strcmp (this_char, "noquota")
+		         || !strcmp (this_char, "quota")
+		         || !strcmp (this_char, "usrquota"))
+			/* Don't do anything ;-) */ ;
+		else if (!strcmp (this_char, "journal")) {
+			/* @@@ FIXME */
+			/* Eventually we will want to be able to create
+                           a journal file here.  For now, only allow the
+                           user to specify an existing inode to be the
+                           journal file. */
+			if (!value || !*value) {
+				printk ("EXT3-fs: the journal option requires "
+					"an argument");
+				return 0;
+			}
+			*inum = simple_strtoul (value, &value, 0);
+			if (*value) {
+				printk ("EXT3-fs: Invalid journal option: "
+					"%s\n", value);
+				return 0;
+			}
+		} 
+		else if (!strcmp (this_char, "noload"))
+			set_opt (*mount_options, NOLOAD);
+		else {
+			printk ("EXT3-fs: Unrecognized mount option %s\n", this_char);
+			return 0;
+		}
+	}
+	return 1;
+}
+
+static void ext3_setup_super (struct super_block * sb,
+			      struct ext3_super_block * es)
+{
+	if (le32_to_cpu(es->s_rev_level) > EXT3_MAX_SUPP_REV) {
+			printk ("EXT3-fs warning: revision level too high, "
+				"forcing read/only mode\n");
+			sb->s_flags |= MS_RDONLY;
+	}
+	if (!(sb->s_flags & MS_RDONLY)) {
+		if (!(sb->u.ext3_sb.s_mount_state & EXT3_VALID_FS))
+			printk ("EXT3-fs warning: mounting unchecked fs, "
+				"running e2fsck is recommended\n");
+		else if ((sb->u.ext3_sb.s_mount_state & EXT3_ERROR_FS))
+			printk ("EXT3-fs warning: mounting fs with errors, "
+				"running e2fsck is recommended\n");
+		else if ((__s16) le16_to_cpu(es->s_max_mnt_count) >= 0 &&
+		         le16_to_cpu(es->s_mnt_count) >=
+			 (unsigned short) (__s16) le16_to_cpu(es->s_max_mnt_count))
+			printk ("EXT3-fs warning: maximal mount count reached, "
+				"running e2fsck is recommended\n");
+		else if (le32_to_cpu(es->s_checkinterval) &&
+			(le32_to_cpu(es->s_lastcheck) + le32_to_cpu(es->s_checkinterval) <= CURRENT_TIME))
+			printk ("EXT3-fs warning: checktime reached, "
+				"running e2fsck is recommended\n");
+
+#if 0
+		/* @@@ We _will_ want to clear the valid bit if we find
+                   inconsistencies, to force a fsck at reboot.  But for
+                   a plain journaled filesystem we can keep it set as
+                   valid forever! :) */
+		es->s_state = cpu_to_le16(le16_to_cpu(es->s_state) & ~EXT3_VALID_FS);
+#endif
+		if (!(__s16) le16_to_cpu(es->s_max_mnt_count))
+			es->s_max_mnt_count = (__s16) cpu_to_le16(EXT3_DFL_MAX_MNT_COUNT);
+		es->s_mnt_count=cpu_to_le16(le16_to_cpu(es->s_mnt_count) + 1);
+		es->s_mtime = cpu_to_le32(CURRENT_TIME);
+		es->s_feature_incompat |= cpu_to_le32(EXT3_FEATURE_INCOMPAT_RECOVER);
+		ext3_commit_super (sb, es, 1);
+		if (test_opt (sb, DEBUG))
+			printk ("[EXT II FS %s, %s, bs=%lu, fs=%lu, gc=%lu, "
+				"bpg=%lu, ipg=%lu, mo=%04lx]\n",
+				EXT3FS_VERSION, EXT3FS_DATE, sb->s_blocksize,
+				sb->u.ext3_sb.s_frag_size,
+				sb->u.ext3_sb.s_groups_count,
+				EXT3_BLOCKS_PER_GROUP(sb),
+				EXT3_INODES_PER_GROUP(sb),
+				sb->u.ext3_sb.s_mount_opt);
+		if (test_opt (sb, CHECK)) {
+			ext3_check_blocks_bitmap (sb);
+			ext3_check_inodes_bitmap (sb);
+		}
+	}
+#if 0 /* ibasket's still have unresolved bugs... -DaveM */
+
+	/* [T. Schoebel-Theuer] This limit should be maintained on disk.
+	 * This is just provisionary.
+	 */
+	sb->s_ibasket_max = 100;
+#endif
+}
+
+static int ext3_check_descriptors (struct super_block * sb)
+{
+	int i;
+	int desc_block = 0;
+	unsigned long block = le32_to_cpu(sb->u.ext3_sb.s_es->s_first_data_block);
+	struct ext3_group_desc * gdp = NULL;
+
+	ext3_debug ("Checking group descriptors");
+
+	for (i = 0; i < sb->u.ext3_sb.s_groups_count; i++)
+	{
+		if ((i % EXT3_DESC_PER_BLOCK(sb)) == 0)
+			gdp = (struct ext3_group_desc *) sb->u.ext3_sb.s_group_desc[desc_block++]->b_data;
+		if (le32_to_cpu(gdp->bg_block_bitmap) < block ||
+		    le32_to_cpu(gdp->bg_block_bitmap) >= block + EXT3_BLOCKS_PER_GROUP(sb))
+		{
+			ext3_error (sb, "ext3_check_descriptors",
+				    "Block bitmap for group %d"
+				    " not in group (block %lu)!",
+				    i, (unsigned long) le32_to_cpu(gdp->bg_block_bitmap));
+			return 0;
+		}
+		if (le32_to_cpu(gdp->bg_inode_bitmap) < block ||
+		    le32_to_cpu(gdp->bg_inode_bitmap) >= block + EXT3_BLOCKS_PER_GROUP(sb))
+		{
+			ext3_error (sb, "ext3_check_descriptors",
+				    "Inode bitmap for group %d"
+				    " not in group (block %lu)!",
+				    i, (unsigned long) le32_to_cpu(gdp->bg_inode_bitmap));
+			return 0;
+		}
+		if (le32_to_cpu(gdp->bg_inode_table) < block ||
+		    le32_to_cpu(gdp->bg_inode_table) + sb->u.ext3_sb.s_itb_per_group >=
+		    block + EXT3_BLOCKS_PER_GROUP(sb))
+		{
+			ext3_error (sb, "ext3_check_descriptors",
+				    "Inode table for group %d"
+				    " not in group (block %lu)!",
+				    i, (unsigned long) le32_to_cpu(gdp->bg_inode_table));
+			return 0;
+		}
+		block += EXT3_BLOCKS_PER_GROUP(sb);
+		gdp++;
+	}
+	return 1;
+}
+
+#define log2(n) ffz(~(n))
+
+struct super_block * ext3_read_super (struct super_block * sb, void * data,
+				      int silent)
+{
+	struct buffer_head * bh;
+	struct ext3_super_block * es;
+	unsigned long sb_block = 1;
+	unsigned short resuid = EXT3_DEF_RESUID;
+	unsigned short resgid = EXT3_DEF_RESGID;
+	unsigned long logic_sb_block = 1;
+	unsigned long offset = 0;
+	unsigned long journal_inum = 0;
+	
+	kdev_t dev = sb->s_dev;
+	int blocksize = BLOCK_SIZE;
+	int hblock;
+	int db_count;
+	int i, j, err;
+
+	/*
+	 * See what the current blocksize for the device is, and
+	 * use that as the blocksize.  Otherwise (or if the blocksize
+	 * is smaller than the default) use the default.
+	 * This is important for devices that have a hardware
+	 * sectorsize that is larger than the default.
+	 */
+	blocksize = get_hardblocksize(dev);
+	if( blocksize == 0 || blocksize < BLOCK_SIZE )
+	  {
+	    blocksize = BLOCK_SIZE;
+	  }
+
+	sb->u.ext3_sb.s_mount_opt = 0;
+	set_opt (sb->u.ext3_sb.s_mount_opt, CHECK_NORMAL);
+	if (!parse_options ((char *) data, &sb_block, &resuid, &resgid,
+	    &sb->u.ext3_sb.s_mount_opt, &journal_inum)) {
+		sb->s_dev = 0;
+		return NULL;
+	}
+
+	MOD_INC_USE_COUNT;
+	lock_super (sb);
+	set_blocksize (dev, blocksize);
+
+	/*
+	 * If the superblock doesn't start on a sector boundary,
+	 * calculate the offset.  FIXME(eric) this doesn't make sense
+	 * that we would have to do this.
+	 */
+	if (blocksize != BLOCK_SIZE) {
+		logic_sb_block = (sb_block*BLOCK_SIZE) / blocksize;
+		offset = (sb_block*BLOCK_SIZE) % blocksize;
+	}
+
+	if (!(bh = bread (dev, logic_sb_block, blocksize))) {
+		sb->s_dev = 0;
+		unlock_super (sb);
+		printk ("EXT3-fs: unable to read superblock\n");
+		MOD_DEC_USE_COUNT;
+		return NULL;
+	}
+	/*
+	 * Note: s_es must be initialized s_es as soon as possible because
+	 * some ext3 macro-instructions depend on its value
+	 */
+	es = (struct ext3_super_block *) (((char *)bh->b_data) + offset);
+	sb->u.ext3_sb.s_es = es;
+	sb->s_magic = le16_to_cpu(es->s_magic);
+	if (sb->s_magic != EXT3_SUPER_MAGIC) {
+		if (!silent)
+			printk ("VFS: Can't find an ext3 filesystem on dev "
+				"%s.\n", bdevname(dev));
+	failed_mount:
+		sb->s_dev = 0;
+		unlock_super (sb);
+		if (bh)
+			brelse(bh);
+		MOD_DEC_USE_COUNT;
+		return NULL;
+	}
+	if (le32_to_cpu(es->s_rev_level) > EXT3_GOOD_OLD_REV) {
+		if (le32_to_cpu(es->s_feature_incompat) & ~EXT3_FEATURE_INCOMPAT_SUPP) {
+			printk("EXT3-fs: %s: couldn't mount because of "
+			       "unsupported optional features.\n",
+			       bdevname(dev));
+			goto failed_mount;
+		}
+		if (!(sb->s_flags & MS_RDONLY) &&
+		    (le32_to_cpu(es->s_feature_ro_compat) & ~EXT3_FEATURE_RO_COMPAT_SUPP)) {
+			printk("EXT3-fs: %s: couldn't mount RDWR because of "
+			       "unsupported optional features.\n",
+			       bdevname(dev));
+			goto failed_mount;
+		}
+	}
+	sb->s_blocksize_bits = le32_to_cpu(sb->u.ext3_sb.s_es->s_log_block_size) + 10;
+	sb->s_blocksize = 1 << sb->s_blocksize_bits;
+	if (sb->s_blocksize != BLOCK_SIZE &&
+	    (sb->s_blocksize == 1024 || sb->s_blocksize == 2048 ||
+	     sb->s_blocksize == 4096)) {
+		/*
+		 * Make sure the blocksize for the filesystem is larger
+		 * than the hardware sectorsize for the machine.
+		 */
+		hblock = get_hardblocksize(dev);
+		if(    (hblock != 0)
+		    && (sb->s_blocksize < hblock) )
+		{
+			printk("EXT3-fs: blocksize too small for device.\n");
+			goto failed_mount;
+		}
+
+		brelse (bh);
+		set_blocksize (dev, sb->s_blocksize);
+		logic_sb_block = (sb_block*BLOCK_SIZE) / sb->s_blocksize;
+		offset = (sb_block*BLOCK_SIZE) % sb->s_blocksize;
+		bh = bread (dev, logic_sb_block, sb->s_blocksize);
+		if(!bh) {
+			printk("EXT3-fs: Couldn't read superblock on "
+			       "2nd try.\n");
+			goto failed_mount;
+		}
+		es = (struct ext3_super_block *) (((char *)bh->b_data) + offset);
+		sb->u.ext3_sb.s_es = es;
+		if (es->s_magic != le16_to_cpu(EXT3_SUPER_MAGIC)) {
+			printk ("EXT3-fs: Magic mismatch, very weird !\n");
+			goto failed_mount;
+		}
+	}
+	if (le32_to_cpu(es->s_rev_level) == EXT3_GOOD_OLD_REV) {
+		sb->u.ext3_sb.s_inode_size = EXT3_GOOD_OLD_INODE_SIZE;
+		sb->u.ext3_sb.s_first_ino = EXT3_GOOD_OLD_FIRST_INO;
+	} else {
+		sb->u.ext3_sb.s_inode_size = le16_to_cpu(es->s_inode_size);
+		sb->u.ext3_sb.s_first_ino = le32_to_cpu(es->s_first_ino);
+		if (sb->u.ext3_sb.s_inode_size != EXT3_GOOD_OLD_INODE_SIZE) {
+			printk ("EXT3-fs: unsupported inode size: %d\n",
+				sb->u.ext3_sb.s_inode_size);
+			goto failed_mount;
+		}
+	}
+	sb->u.ext3_sb.s_feature_compat = le32_to_cpu(es->s_feature_compat);
+	sb->u.ext3_sb.s_feature_incompat = le32_to_cpu(es->s_feature_incompat);
+	sb->u.ext3_sb.s_feature_ro_compat = le32_to_cpu(es->s_feature_ro_compat);
+	sb->u.ext3_sb.s_frag_size = EXT3_MIN_FRAG_SIZE <<
+				   le32_to_cpu(es->s_log_frag_size);
+	if (sb->u.ext3_sb.s_frag_size)
+		sb->u.ext3_sb.s_frags_per_block = sb->s_blocksize /
+						  sb->u.ext3_sb.s_frag_size;
+	else
+		sb->s_magic = 0;
+	sb->u.ext3_sb.s_blocks_per_group = le32_to_cpu(es->s_blocks_per_group);
+	sb->u.ext3_sb.s_frags_per_group = le32_to_cpu(es->s_frags_per_group);
+	sb->u.ext3_sb.s_inodes_per_group = le32_to_cpu(es->s_inodes_per_group);
+	sb->u.ext3_sb.s_inodes_per_block = sb->s_blocksize /
+					   EXT3_INODE_SIZE(sb);
+	sb->u.ext3_sb.s_itb_per_group = sb->u.ext3_sb.s_inodes_per_group /
+				        sb->u.ext3_sb.s_inodes_per_block;
+	sb->u.ext3_sb.s_desc_per_block = sb->s_blocksize /
+					 sizeof (struct ext3_group_desc);
+	sb->u.ext3_sb.s_sbh = bh;
+	if (resuid != EXT3_DEF_RESUID)
+		sb->u.ext3_sb.s_resuid = resuid;
+	else
+		sb->u.ext3_sb.s_resuid = le16_to_cpu(es->s_def_resuid);
+	if (resgid != EXT3_DEF_RESGID)
+		sb->u.ext3_sb.s_resgid = resgid;
+	else
+		sb->u.ext3_sb.s_resgid = le16_to_cpu(es->s_def_resgid);
+	sb->u.ext3_sb.s_mount_state = le16_to_cpu(es->s_state);
+	sb->u.ext3_sb.s_addr_per_block_bits =
+		log2 (EXT3_ADDR_PER_BLOCK(sb));
+	sb->u.ext3_sb.s_desc_per_block_bits =
+		log2 (EXT3_DESC_PER_BLOCK(sb));
+	if (sb->s_magic != EXT3_SUPER_MAGIC) {
+		if (!silent)
+			printk ("VFS: Can't find an ext3 filesystem on dev "
+				"%s.\n",
+				bdevname(dev));
+		goto failed_mount;
+	}
+	if (sb->s_blocksize != bh->b_size) {
+		if (!silent)
+			printk ("VFS: Unsupported blocksize on dev "
+				"%s.\n", bdevname(dev));
+		goto failed_mount;
+	}
+
+	if (sb->s_blocksize != sb->u.ext3_sb.s_frag_size) {
+		printk ("EXT3-fs: fragsize %lu != blocksize %lu (not supported yet)\n",
+			sb->u.ext3_sb.s_frag_size, sb->s_blocksize);
+		goto failed_mount;
+	}
+
+	if (sb->u.ext3_sb.s_blocks_per_group > sb->s_blocksize * 8) {
+		printk ("EXT3-fs: #blocks per group too big: %lu\n",
+			sb->u.ext3_sb.s_blocks_per_group);
+		goto failed_mount;
+	}
+	if (sb->u.ext3_sb.s_frags_per_group > sb->s_blocksize * 8) {
+		printk ("EXT3-fs: #fragments per group too big: %lu\n",
+			sb->u.ext3_sb.s_frags_per_group);
+		goto failed_mount;
+	}
+	if (sb->u.ext3_sb.s_inodes_per_group > sb->s_blocksize * 8) {
+		printk ("EXT3-fs: #inodes per group too big: %lu\n",
+			sb->u.ext3_sb.s_inodes_per_group);
+		goto failed_mount;
+	}
+
+	sb->u.ext3_sb.s_groups_count = (le32_to_cpu(es->s_blocks_count) -
+				        le32_to_cpu(es->s_first_data_block) +
+				       EXT3_BLOCKS_PER_GROUP(sb) - 1) /
+				       EXT3_BLOCKS_PER_GROUP(sb);
+	db_count = (sb->u.ext3_sb.s_groups_count + EXT3_DESC_PER_BLOCK(sb) - 1) /
+		   EXT3_DESC_PER_BLOCK(sb);
+	sb->u.ext3_sb.s_group_desc = kmalloc (db_count * sizeof (struct buffer_head *), GFP_KERNEL);
+	if (sb->u.ext3_sb.s_group_desc == NULL) {
+		printk ("EXT3-fs: not enough memory\n");
+		goto failed_mount;
+	}
+	for (i = 0; i < db_count; i++) {
+		sb->u.ext3_sb.s_group_desc[i] = bread (dev, logic_sb_block + i + 1,
+						       sb->s_blocksize);
+		if (!sb->u.ext3_sb.s_group_desc[i]) {
+			for (j = 0; j < i; j++)
+				brelse (sb->u.ext3_sb.s_group_desc[j]);
+			kfree_s (sb->u.ext3_sb.s_group_desc,
+				 db_count * sizeof (struct buffer_head *));
+			printk ("EXT3-fs: unable to read group descriptors\n");
+			goto failed_mount;
+		}
+	}
+	if (!ext3_check_descriptors (sb)) {
+		for (j = 0; j < db_count; j++)
+			brelse (sb->u.ext3_sb.s_group_desc[j]);
+		kfree_s (sb->u.ext3_sb.s_group_desc,
+			 db_count * sizeof (struct buffer_head *));
+		printk ("EXT3-fs: group descriptors corrupted !\n");
+		goto failed_mount;
+	}
+	for (i = 0; i < EXT3_MAX_GROUP_LOADED; i++) {
+		sb->u.ext3_sb.s_inode_bitmap_number[i] = 0;
+		sb->u.ext3_sb.s_inode_bitmap[i] = NULL;
+		sb->u.ext3_sb.s_block_bitmap_number[i] = 0;
+		sb->u.ext3_sb.s_block_bitmap[i] = NULL;
+	}
+	sb->u.ext3_sb.s_loaded_inode_bitmaps = 0;
+	sb->u.ext3_sb.s_loaded_block_bitmaps = 0;
+	sb->u.ext3_sb.s_db_per_group = db_count;
+	/*
+	 * set up enough so that it can read an inode
+	 */
+	sb->s_dev = dev;
+	sb->s_op = &ext3_sops;
+	unlock_super (sb);
+
+	err = 0;
+	sb->s_root = 0;
+
+	/*
+	 * The first inode we look at is the journal inode.  Don't try
+	 * root first: it may be modified in the journal!
+	 */
+	if (!test_opt(sb, NOLOAD) &&
+	    (sb->u.ext3_sb.s_feature_compat & EXT3_FEATURE_COMPAT_HAS_JOURNAL)) {
+		if (ext3_load_journal(sb, es))
+			goto error_out;
+	} else if (journal_inum) {
+		if (ext3_create_journal(sb, es, journal_inum))
+			goto error_out;
+	} else {
+		printk (KERN_ERR "ext3: No journal on filesystem on %s\n",
+			kdevname(dev));
+		goto error_out;
+	}
+
+	/*
+	 * The journal_load will have done any necessary log recovery,
+	 * so we can safely mount the rest of the filesystem now.  
+	 */
+	sb->s_root = d_alloc_root(iget(sb, EXT3_ROOT_INO), NULL);
+	if (!sb->s_root) 
+		goto error_out;
+	ext3_setup_super (sb, es);
+	return sb;
+
+ error_out:
+	sb->s_dev = 0;
+	for (i = 0; i < db_count; i++)
+		if (sb->u.ext3_sb.s_group_desc[i])
+			brelse (sb->u.ext3_sb.s_group_desc[i]);
+	kfree_s (sb->u.ext3_sb.s_group_desc,
+		 db_count * sizeof (struct buffer_head *));
+	brelse (bh);
+	printk ("EXT3-fs: get root inode failed\n");
+	MOD_DEC_USE_COUNT;
+	return NULL;
+}
+
+static journal_t *ext3_get_journal(struct super_block *sb, int journal_inum)
+{
+	struct inode *journal_inode;
+	journal_t *journal;
+	
+	journal_inode = iget(sb, journal_inum);
+	if (!journal_inode) {
+		printk("EXT3-fs: no journal found.\n");
+		return NULL;
+	}
+	jfs_debug(2, "Journal inode found at %p: %ld bytes\n",
+		  journal_inode, journal_inode->i_size);
+	if (!journal_inode->i_nlink ||
+	    !S_ISREG(journal_inode->i_mode)) {
+		printk("EXT3-fs: invalid journal inode.\n");
+		iput(journal_inode);
+		return NULL;
+	}
+
+	journal = journal_init_inode(journal_inode);
+	if (!journal)
+		iput(journal_inode);
+	if (sb->s_flags & MS_SYNCHRONOUS)
+		journal->j_flags |= JFS_SYNC;
+	return journal;
+}
+
+static int ext3_load_journal(struct super_block * sb,
+			     struct ext3_super_block * es)
+{
+	journal_t *journal;
+	int journal_inum = le32_to_cpu(es->s_journal_inum);
+	int err;
+	
+	/*
+	 * Are we loading a blank journal or performing recovery after a
+	 * crash?  For recovery, we need to check in advance whether we
+	 * can get read-write access to the device.
+	 */
+
+	if (es->s_feature_incompat & EXT3_FEATURE_INCOMPAT_RECOVER) {
+		if (sb->s_flags & MS_RDONLY) {
+			printk(KERN_ERR "EXT3-fs: WARNING: recovery required on readonly filesystem.\n");
+			if (is_read_only(sb->s_dev)) {
+				printk(KERN_ERR "EXT3-fs: write access unavailable, cannot proceed.\n");
+				return -EROFS;
+			}
+			printk (KERN_ERR "EXT3-fs: write access will be enabled during recovery.\n");
+		}
+	}
+	
+	if (!(journal = ext3_get_journal(sb, journal_inum)))
+		return -EINVAL;
+
+	err = journal_load(journal);
+	if (err) {
+		printk(KERN_ERR "EXT3-fs: error loading journal.\n");
+
+		/* @@@ Special case: if there was no recovery required,
+                   then we are safe just resetting the journal.  This is
+                   not particularly safe in the long term, but for now
+                   we rely on this behaviour to force superblock
+                   creation on a newly-created journal for root
+                   filesystems. */
+		
+		journal_release(journal);
+		return -EIO;
+	}
+
+	EXT3_SB(sb)->s_journal = journal;
+
+	/* 
+	 * Have we just finished recovery?  If so, and if we are
+	 * mounting the filesystem readonly, then we will end up with a
+	 * consistent fs on disk.  Record that fact if so.  
+	 */
+
+	if (le32_to_cpu(es->s_feature_incompat) & EXT3_FEATURE_INCOMPAT_RECOVER) {
+		printk (KERN_INFO "EXT3-fs: recovery complete.\n");
+		if (sb->s_flags & MS_RDONLY) {
+			es->s_feature_incompat &= ~(cpu_to_le32(EXT3_FEATURE_INCOMPAT_RECOVER));
+			ext3_commit_super(sb, es, 1);
+		}
+	}
+	
+	return 0;
+}
+
+static int ext3_create_journal(struct super_block * sb,
+			       struct ext3_super_block * es,
+			       int journal_inum)
+{
+	journal_t *journal;
+		
+	if (sb->s_flags & MS_RDONLY) {
+		printk("EXT3-fs: readonly filesystem when trying to create journal.\n");
+		return -EROFS;
+	}
+	
+	if (!(journal = ext3_get_journal(sb, journal_inum)))
+		return -EINVAL;
+
+	if (journal_create(journal)) {
+		printk("EXT3-fs: error creating journal.\n");
+		journal_release(journal);
+		return -EIO;
+	}
+
+	EXT3_SB(sb)->s_journal = journal;
+	if (sb->s_flags & MS_SYNCHRONOUS)
+		journal->j_flags |= JFS_SYNC;
+	
+	sb->u.ext3_sb.s_feature_incompat |= EXT3_FEATURE_INCOMPAT_RECOVER;
+	es->s_feature_incompat = cpu_to_le32(sb->u.ext3_sb.s_feature_incompat);
+	
+	sb->u.ext3_sb.s_feature_compat |= EXT3_FEATURE_COMPAT_HAS_JOURNAL;
+	es->s_feature_compat = cpu_to_le32(sb->u.ext3_sb.s_feature_compat);
+	
+	es->s_journal_inum = cpu_to_le32(journal_inum);
+	sb->s_dirt = 1;
+
+	/* Make sure we flush the recovery flag to disk. */
+	ext3_commit_super(sb, es, 1);
+	
+	return 0;
+}
+
+static void ext3_commit_super (struct super_block * sb,
+			       struct ext3_super_block * es, 
+			       int sync)
+{
+	es->s_wtime = cpu_to_le32(CURRENT_TIME);
+	mark_buffer_dirty(sb->u.ext3_sb.s_sbh, 1);
+	sb->s_dirt = 0;
+	if (sync) {
+		ll_rw_block(WRITE, 1, &sb->u.ext3_sb.s_sbh);
+		wait_on_buffer(sb->u.ext3_sb.s_sbh);
+	}
+}
+
+/*
+ * In the second extended file system, it is not necessary to
+ * write the super block since we use a mapping of the
+ * disk super block in a buffer.
+ *
+ * However, this function is still used to set the fs valid
+ * flags to 0.  We need to set this flag to 0 since the fs
+ * may have been checked while mounted and e2fsck may have
+ * set s_state to EXT3_VALID_FS after some corrections.
+ */
+
+void ext3_write_super (struct super_block * sb)
+{
+	struct ext3_super_block * es;
+
+	if (!(sb->s_flags & MS_RDONLY)) {
+		journal_t *journal;
+		
+		journal = EXT3_SB(sb)->s_journal;
+		es = sb->u.ext3_sb.s_es;
+
+		if (journal->j_running_transaction)
+			log_start_commit(journal, journal->j_running_transaction);
+		if (journal->j_committing_transaction)
+			log_wait_commit(journal, journal->j_committing_transaction->t_tid);
+	}
+	sb->s_dirt = 0;
+}
+
+int ext3_remount (struct super_block * sb, int * flags, char * data)
+{
+	struct ext3_super_block * es;
+	unsigned short resuid = sb->u.ext3_sb.s_resuid;
+	unsigned short resgid = sb->u.ext3_sb.s_resgid;
+	unsigned long new_mount_opt;
+	unsigned long tmp;
+
+	/*
+	 * Allow the "check" option to be passed as a remount option.
+	 */
+	new_mount_opt = EXT3_MOUNT_CHECK_NORMAL;
+	if (!parse_options (data, &tmp, &resuid, &resgid,
+			    &new_mount_opt, &tmp))
+		return -EINVAL;
+
+	sb->u.ext3_sb.s_mount_opt = new_mount_opt;
+	sb->u.ext3_sb.s_resuid = resuid;
+	sb->u.ext3_sb.s_resgid = resgid;
+	es = sb->u.ext3_sb.s_es;
+	if ((*flags & MS_RDONLY) == (sb->s_flags & MS_RDONLY))
+		return 0;
+	if (*flags & MS_RDONLY) {
+		/* 
+		 * First of all, the unconditional stuff we have to do
+		 * to disable replay of the journal when we next remount
+		 */
+		sb->s_flags |= MS_RDONLY;
+		journal_flush(EXT3_SB(sb)->s_journal);
+
+		/*
+		 * OK, test if we are remounting a valid rw partition
+		 * rdonly, and if so set the rdonly flag and then mark the
+		 * partition as valid again.  
+		 */
+		if (!(le16_to_cpu(es->s_state) & EXT3_VALID_FS) &&
+		    (sb->u.ext3_sb.s_mount_state & EXT3_VALID_FS))
+			es->s_state = cpu_to_le16(sb->u.ext3_sb.s_mount_state);
+
+		es->s_feature_incompat &= cpu_to_le32(~EXT3_FEATURE_INCOMPAT_RECOVER);
+		es->s_mtime = cpu_to_le32(CURRENT_TIME);
+		mark_buffer_dirty(sb->u.ext3_sb.s_sbh, 1);
+		sb->s_dirt = 1;
+		ext3_commit_super (sb, es, 1);
+	}
+	else {
+		/*
+		 * Mounting a RDONLY partition read-write, so reread and
+		 * store the current valid flag.  (It may have been changed
+		 * by e2fsck since we originally mounted the partition.)
+		 */
+		sb->u.ext3_sb.s_mount_state = le16_to_cpu(es->s_state);
+		sb->s_flags &= ~MS_RDONLY;
+		ext3_setup_super (sb, es);
+	}
+	return 0;
+}
+
+static struct file_system_type ext3_fs_type = {
+	"ext3", 
+	FS_REQUIRES_DEV /* | FS_IBASKET */,	/* ibaskets have unresolved bugs */
+        ext3_read_super, 
+	NULL
+};
+
+__initfunc(int init_ext3_fs(void))
+{
+#ifdef CONFIG_EXT3_FS_JFS_CHECK
+	jfs_preclean_buffer_check = real_jfs_preclean_buffer_check;
+	jfs_prelock_buffer_check = real_jfs_prelock_buffer_check;
+#endif
+	journal_remove_checkpoint = real_journal_remove_checkpoint;
+        return register_filesystem(&ext3_fs_type);
+}
+
+#ifdef MODULE
+EXPORT_NO_SYMBOLS;
+
+int init_module(void)
+{
+	return init_ext3_fs();
+}
+
+void cleanup_module(void)
+{
+#ifdef CONFIG_EXT3_FS_JFS_CHECK
+	jfs_preclean_buffer_check = dummy_jfs_function;
+	jfs_prelock_buffer_check = dummy_jfs_function;
+#endif
+	journal_remove_checkpoint = dummy_jfs_function;
+        unregister_filesystem(&ext3_fs_type);
+}
+
+#endif
+
+int ext3_statfs (struct super_block * sb, struct statfs * buf, int bufsiz)
+{
+	unsigned long overhead;
+	struct statfs tmp;
+	int	ngroups, i;
+
+	if (test_opt (sb, MINIX_DF))
+		overhead = 0;
+	else {
+		/*
+		 * Compute the overhead (FS structures)
+		 */
+
+		/*
+		 * All of the blocks before first_data_block are
+		 * overhead
+		 */
+		overhead = le32_to_cpu(sb->u.ext3_sb.s_es->s_first_data_block);
+
+		/*
+		 * Add the overhead attributed to the superblock and
+		 * block group descriptors.  If this is sparse
+		 * superblocks is turned on, then not all groups have
+		 * this.
+		 */
+		if (sb->u.ext3_sb.s_feature_ro_compat &
+		    EXT3_FEATURE_RO_COMPAT_SPARSE_SUPER) {
+			ngroups = 0;
+			for (i=0 ; i < sb->u.ext3_sb.s_groups_count; i++)
+				if (ext3_group_sparse(i))
+					ngroups++;
+		} else
+			ngroups = sb->u.ext3_sb.s_groups_count;
+		overhead += ngroups * (1 + sb->u.ext3_sb.s_db_per_group);
+
+		/*
+		 * Every block group has an inode bitmap, a block
+		 * bitmap, and an inode table.
+		 */
+		overhead += (sb->u.ext3_sb.s_groups_count *
+			     (2 + sb->u.ext3_sb.s_itb_per_group));
+	}
+
+	tmp.f_type = EXT3_SUPER_MAGIC;
+	tmp.f_bsize = sb->s_blocksize;
+	tmp.f_blocks = le32_to_cpu(sb->u.ext3_sb.s_es->s_blocks_count) - overhead;
+	tmp.f_bfree = ext3_count_free_blocks (sb);
+	tmp.f_bavail = tmp.f_bfree - le32_to_cpu(sb->u.ext3_sb.s_es->s_r_blocks_count);
+	if (tmp.f_bfree < le32_to_cpu(sb->u.ext3_sb.s_es->s_r_blocks_count))
+		tmp.f_bavail = 0;
+	tmp.f_files = le32_to_cpu(sb->u.ext3_sb.s_es->s_inodes_count);
+	tmp.f_ffree = ext3_count_free_inodes (sb);
+	tmp.f_namelen = EXT3_NAME_LEN;
+	return copy_to_user(buf, &tmp, bufsiz) ? -EFAULT : 0;
+}
Index: oldkernel/linux/fs/ext3/symlink.c
diff -u /dev/null linux/fs/ext3/symlink.c:1.1
--- /dev/null	Mon Jul 31 21:15:07 2000
+++ linux/fs/ext3/symlink.c	Fri Jul  7 16:34:57 2000
@@ -0,0 +1,109 @@
+/*
+ *  linux/fs/ext3/symlink.c
+ *
+ * Copyright (C) 1992, 1993, 1994, 1995
+ * Remy Card (card@masi.ibp.fr)
+ * Laboratoire MASI - Institut Blaise Pascal
+ * Universite Pierre et Marie Curie (Paris VI)
+ *
+ *  from
+ *
+ *  linux/fs/minix/symlink.c
+ *
+ *  Copyright (C) 1991, 1992  Linus Torvalds
+ *
+ *  ext3 symlink handling code
+ */
+
+#include <asm/uaccess.h>
+
+#include <linux/errno.h>
+#include <linux/fs.h>
+#include <linux/ext3_fs.h>
+#include <linux/sched.h>
+#include <linux/mm.h>
+#include <linux/stat.h>
+
+static int ext3_readlink (struct dentry *, char *, int);
+static struct dentry *ext3_follow_link(struct dentry *, struct dentry *, unsigned int);
+
+/*
+ * symlinks can't do much...
+ */
+struct inode_operations ext3_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 */
+	ext3_readlink,		/* readlink */
+	ext3_follow_link,	/* follow_link */
+	NULL,			/* readpage */
+	NULL,			/* writepage */
+	NULL,			/* bmap */
+	NULL,			/* truncate */
+	NULL,			/* permission */
+	NULL			/* smap */
+};
+
+static struct dentry * ext3_follow_link(struct dentry * dentry,
+					struct dentry *base,
+					unsigned int follow)
+{
+	struct inode *inode = dentry->d_inode;
+	struct buffer_head * bh = NULL;
+	int error;
+	char * link;
+
+	link = (char *) inode->u.ext3_i.i_data;
+	if (inode->i_blocks) {
+		if (!(bh = ext3_bread (NULL, inode, 0, 0, &error))) {
+			dput(base);
+			return ERR_PTR(-EIO);
+		}
+		link = bh->b_data;
+	}
+	UPDATE_ATIME(inode);
+	base = lookup_dentry(link, base, follow);
+	if (bh)
+		brelse(bh);
+	return base;
+}
+
+static int ext3_readlink (struct dentry * dentry, char * buffer, int buflen)
+{
+	struct inode *inode = dentry->d_inode;
+	struct buffer_head * bh = NULL;
+	char * link;
+	int i;
+
+	if (buflen > inode->i_sb->s_blocksize - 1)
+		buflen = inode->i_sb->s_blocksize - 1;
+
+	link = (char *) inode->u.ext3_i.i_data;
+	if (inode->i_blocks) {
+		int err;
+		bh = ext3_bread (NULL, inode, 0, 0, &err);
+		if (!bh) {
+			if(err < 0) /* indicate type of error */
+				return err;
+			return 0;
+		}
+		link = bh->b_data;
+	}
+
+	i = 0;
+	while (i < buflen && link[i])
+		i++;
+	if (copy_to_user(buffer, link, i))
+		i = -EFAULT;
+ 	UPDATE_ATIME(inode);
+	if (bh)
+		brelse (bh);
+	return i;
+}
Index: oldkernel/linux/fs/ext3/truncate.c
diff -u /dev/null linux/fs/ext3/truncate.c:1.1
--- /dev/null	Mon Jul 31 21:15:07 2000
+++ linux/fs/ext3/truncate.c	Fri Jul  7 16:34:57 2000
@@ -0,0 +1,533 @@
+/*
+ *  linux/fs/ext3/truncate.c
+ *
+ * Copyright (C) 1992, 1993, 1994, 1995
+ * Remy Card (card@masi.ibp.fr)
+ * Laboratoire MASI - Institut Blaise Pascal
+ * Universite Pierre et Marie Curie (Paris VI)
+ *
+ *  from
+ *
+ *  linux/fs/minix/truncate.c
+ *
+ *  Copyright (C) 1991, 1992  Linus Torvalds
+ *
+ *  Big-endian to little-endian byte-swapping/bitmaps by
+ *        David S. Miller (davem@caip.rutgers.edu), 1995
+ *
+ *  General cleanup and race fixes, wsh, 1998
+ */
+
+/*
+ * Real random numbers for secure rm added 94/02/18
+ * Idea from Pierre del Perugia <delperug@gla.ecoledoc.ibp.fr>
+ */
+
+#include <linux/errno.h>
+#include <linux/sched.h>
+#include <linux/fs.h>
+#include <linux/ext3_fs.h>
+#include <linux/ext3_jfs.h>
+#include <linux/fcntl.h>
+#include <linux/stat.h>
+#include <linux/locks.h>
+#include <linux/string.h>
+
+#if 0
+
+/*
+ * Secure deletion currently doesn't work. It interacts very badly
+ * with buffers shared with memory mappings, and for that reason
+ * can't be done in the truncate() routines. It should instead be
+ * done separately in "release()" before calling the truncate routines
+ * that will release the actual file blocks.
+ *
+ *		Linus
+ */
+static int ext3_secrm_seed = 152;	/* Random generator base */
+
+#define RANDOM_INT (ext3_secrm_seed = ext3_secrm_seed * 69069l +1)
+#endif
+
+/*
+ * Macros to return the block number for the inode size and offset.
+ * Currently we always hold the inode semaphore during truncate, so
+ * there's no need to test for changes during the operation.
+ */
+#define DIRECT_BLOCK(inode) \
+	((inode->i_size + inode->i_sb->s_blocksize - 1) / \
+			  inode->i_sb->s_blocksize)
+#define INDIRECT_BLOCK(inode,offset) ((int)DIRECT_BLOCK(inode) - offset)
+#define DINDIRECT_BLOCK(inode,offset) \
+	(INDIRECT_BLOCK(inode,offset) / addr_per_block)
+#define TINDIRECT_BLOCK(inode,offset) \
+	(INDIRECT_BLOCK(inode,offset) / (addr_per_block*addr_per_block))
+
+/*
+ * Truncate has the most races in the whole filesystem: coding it is
+ * a pain in the a**. Especially as I don't do any locking...
+ *
+ * The code may look a bit weird, but that's just because I've tried to
+ * handle things like file-size changes in a somewhat graceful manner.
+ * Anyway, truncating a file at the same time somebody else writes to it
+ * is likely to result in pretty weird behaviour...
+ *
+ * The new code handles normal truncates (size = 0) as well as the more
+ * general case (size = XXX). I hope.
+ *
+ *
+ * Truncate operations have been rewritten to avoid various races. The
+ * previous code was allowing blocking operations to precede a call to
+ * bforget(), possible allowing the buffer to be used again.
+ *
+ * We now ensure that b_count == 1 before calling bforget() and that the
+ * parent buffer (if any) is unlocked before clearing the block pointer.
+ * The operations are always performed in this order:
+ *	(1) Make sure that the parent buffer is unlocked.
+ *	(2) Use find_buffer() to find the block buffer without blocking,
+ *	    and set 'retry' if the buffer is locked or b_count > 1.
+ *	(3) Clear the block pointer in the parent (buffer or inode).
+ *	(4) Update the inode block count and mark the inode dirty.
+ *	(5) Forget the block buffer, if any. This call won't block, as
+ *	    we know the buffer is unlocked from (2).
+ *	(6) If the block pointer is in a (parent) buffer, mark the buffer
+ *	    dirty. (Note that this can block on a loop device.)
+ *	(7) Accumulate the blocks to free and/or update the block bitmap.
+ *	    (This operation will frequently block.)
+ *
+ * The requirement that parent buffers be unlocked follows from the general
+ * principle of not modifying a buffer that may be undergoing I/O. With the
+ * the present kernels there's no problem with modifying a locked inode, as
+ * the I_DIRTY bit is cleared before setting I_LOCK.
+ *		-- WSH, 1998
+ */
+
+
+static inline void ext3_bforget(struct buffer_head *buf)
+{
+	if (buf) {
+		J_ASSERT(buf->b_cp_transaction == NULL);
+		J_ASSERT(buf->b_jlist == BJ_None);
+		J_ASSERT(!test_bit(BH_JWrite, &buf->b_state));
+		__bforget(buf);
+	}
+}
+
+/* 
+ * The journaling doesn't have to break the rules above, as long as we
+ * do a journal_get_write_access() on the appropriate indirect blocks
+ * before entering the find_buffer().   
+ * 
+ * However, there are some new complications.  truncate transactions can
+ * be complex and unbounded in length, so we need to be able to restart
+ * the transaction at a conventient checkpoint to make sure we don't
+ * overflow the journal.
+ *
+ * start_transaction gets us a new handle for a truncate transaction,
+ * and extend_transaction tries to extend the existing one a bit.  If
+ * extend fails, we need to propagate the failure up and restart the
+ * transaction in the top-level truncate loop. --sct 
+ */
+
+static handle_t *start_transaction(struct inode *inode) 
+{
+	long needed;
+	needed = inode->i_blocks;
+	if (needed > EXT3_MAX_TRANS_DATA) 
+		needed = EXT3_MAX_TRANS_DATA;
+
+	return journal_start(EXT3_JOURNAL(inode), 
+			     EXT3_DATA_TRANS_BLOCKS + needed);
+}
+
+static int extend_transaction(handle_t *handle, struct inode *inode)
+{
+	long needed;
+	
+	if (handle->h_buffer_credits > EXT3_RESERVE_TRANS_BLOCKS)
+		return 0;
+	needed = inode->i_blocks;
+	if (needed > EXT3_MAX_TRANS_DATA) 
+		needed = EXT3_MAX_TRANS_DATA;
+	if (!journal_extend(handle, EXT3_RESERVE_TRANS_BLOCKS + needed))
+		return 0;
+
+	jfs_debug(2, "extending handle %p\n", handle);
+	journal_restart(handle, EXT3_DATA_TRANS_BLOCKS + needed);
+	return 1;
+}
+
+	
+
+/*
+ * Check whether any of the slots in an indirect block are
+ * still in use, and if not free the block.
+ */
+static int check_block_empty(handle_t *handle, 
+			     struct inode *inode, struct buffer_head *bh,
+			     u32 *p, struct buffer_head *ind_bh)
+{
+	int addr_per_block = EXT3_ADDR_PER_BLOCK(inode->i_sb);
+	u32 * ind = (u32 *) bh->b_data;
+	int i, retry;
+
+	if (ind_bh)
+		journal_get_write_access(handle, ind_bh);
+	
+	/* Make sure both buffers are unlocked */
+	do {
+		retry = 0;
+		if (buffer_locked(bh)) {
+			__wait_on_buffer(bh);
+			retry = 1;
+		}
+		if (ind_bh && buffer_locked(ind_bh)) {
+			__wait_on_buffer(ind_bh);
+			retry = 1;
+		}
+	} while (retry);
+
+	for (i = 0; i < addr_per_block; i++)
+		if (*(ind++))
+			goto in_use;
+
+	if (!journal_is_buffer_shared(bh)) {
+		int tmp;
+		if (ind_bh)
+			tmp = le32_to_cpu(*p);
+		else
+			tmp = *p;
+		*p = 0;
+		inode->i_blocks -= (inode->i_sb->s_blocksize / 512);
+
+		/*
+		 * Forget the buffer, then mark the parent buffer dirty.
+		 */
+		journal_forget(handle, bh);
+		if (ind_bh)
+			journal_dirty_metadata(handle, ind_bh);
+		ext3_free_blocks (handle, inode, tmp, 1);
+		ext3_mark_inode_dirty(handle, inode);
+		goto out;
+	}
+	jfs_debug(4, "retry\n");
+	retry = 1;
+
+in_use:
+	brelse (bh);
+	if (ind_bh)
+		journal_release_buffer(handle, ind_bh);
+	
+out:
+	return retry;
+}
+
+static int trunc_direct (handle_t *handle, struct inode * inode)
+{
+	struct buffer_head * bh;
+	int i, retry = 0;
+	unsigned long block_to_free = 0, free_count = 0;
+	int blocks = inode->i_sb->s_blocksize / 512;
+	int direct_block = DIRECT_BLOCK(inode);
+	int dirty = 0;
+	
+	for (i = direct_block ; i < EXT3_NDIR_BLOCKS ; i++) {
+		u32 * p = inode->u.ext3_i.i_data + i;
+		int tmp = *p;
+
+		if (!tmp)
+			continue;
+
+		extend_transaction(handle, inode);
+		
+		bh = find_buffer(inode->i_dev, tmp, inode->i_sb->s_blocksize);
+		if (bh) {
+			bh->b_count++;
+			if(journal_is_buffer_shared(bh) || buffer_locked(bh)) {
+				brelse(bh);
+				retry = 1;
+				continue;
+			}
+		}
+		
+		*p = 0;
+		inode->i_blocks -= blocks;
+		dirty = 1;
+		if (bh)
+			journal_forget(handle, bh);
+
+		/* accumulate blocks to free if they're contiguous */
+		if (free_count == 0)
+			goto free_this;
+		else if (block_to_free == tmp - free_count)
+			free_count++;
+		else {
+			ext3_free_blocks (handle, inode, block_to_free, free_count);
+		free_this:
+			block_to_free = tmp;
+			free_count = 1;
+		}
+	}
+	if (free_count > 0)
+		ext3_free_blocks (handle, inode, block_to_free, free_count);
+
+	if (dirty)
+		ext3_mark_inode_dirty(handle, inode);
+	return retry;
+}
+
+static int trunc_indirect (handle_t *handle,
+			   struct inode * inode, int offset, u32 * p,
+			   struct buffer_head *dind_bh)
+{
+	struct buffer_head * ind_bh;
+	int i, tmp, retry = 0;
+	unsigned long block_to_free = 0, free_count = 0;
+	int indirect_block, addr_per_block, blocks;
+	int dirty = 0;
+	
+	tmp = dind_bh ? le32_to_cpu(*p) : *p;
+	if (!tmp)
+		return 0;
+	ind_bh = bread (inode->i_dev, tmp, inode->i_sb->s_blocksize);
+	if (tmp != (dind_bh ? le32_to_cpu(*p) : *p)) {
+		brelse (ind_bh);
+		return 1;
+	}
+
+	/* A read failure? Report error and clear slot (should be rare). */ 
+	if (!ind_bh) {
+		ext3_error(inode->i_sb, "trunc_indirect",
+			"Read failure, inode=%ld, block=%d",
+			inode->i_ino, tmp);
+		if (dind_bh) {
+			journal_get_write_access(handle, dind_bh);
+			*p = 0;
+			journal_dirty_metadata(handle, dind_bh);
+		} else {
+			*p = 0;
+			ext3_mark_inode_dirty(handle, inode);
+		}
+		return 0;
+	}
+
+	journal_get_write_access(handle, ind_bh);
+
+	blocks = inode->i_sb->s_blocksize / 512;
+	addr_per_block = EXT3_ADDR_PER_BLOCK(inode->i_sb);
+	indirect_block = INDIRECT_BLOCK(inode, offset);
+	if (indirect_block < 0)
+		indirect_block = 0;
+	for (i = indirect_block ; i < addr_per_block ; i++) {
+		u32 * ind = i + (u32 *) ind_bh->b_data;
+		struct buffer_head * bh;
+
+		wait_on_buffer(ind_bh);
+		tmp = le32_to_cpu(*ind);
+		if (!tmp)
+			continue;
+
+		if (extend_transaction(handle, inode))
+			journal_get_write_access(handle, ind_bh);
+		/*
+		 * Use find_buffer so we don't block here.
+		 */
+		bh = find_buffer(inode->i_dev, tmp, inode->i_sb->s_blocksize);
+		if (bh) {
+			bh->b_count++;
+			if (journal_is_buffer_shared(bh) || buffer_locked(bh)) {
+				brelse (bh);
+				retry = 1;
+				continue;
+			}
+		}
+
+		*ind = 0;
+		inode->i_blocks -= blocks;
+		dirty = 1;
+		if (bh)
+			journal_forget(handle, bh);
+
+		/* accumulate blocks to free if they're contiguous */
+		if (free_count == 0)
+			goto free_this;
+		else if (block_to_free == tmp - free_count)
+			free_count++;
+		else {
+			ext3_free_blocks (handle, inode, block_to_free, free_count);
+		free_this:
+			block_to_free = tmp;
+			free_count = 1;
+		}
+	}
+	if (free_count > 0)
+		ext3_free_blocks (handle, inode, block_to_free, free_count);
+
+	if (dirty) {
+		journal_dirty_metadata(handle, ind_bh);
+		ext3_mark_inode_dirty(handle, inode);
+	}
+	
+	/*
+	 * Check the block and dispose of the ind_bh buffer.
+	 */
+	retry |= check_block_empty(handle, inode, ind_bh, p, dind_bh);
+
+	return retry;
+}
+
+static int trunc_dindirect (handle_t *handle,
+			    struct inode * inode, int offset, u32 * p,
+			    struct buffer_head * tind_bh)
+{
+	struct buffer_head * dind_bh;
+	int i, tmp, retry = 0;
+	int dindirect_block, addr_per_block;
+
+	tmp = tind_bh ? le32_to_cpu(*p) : *p;
+	if (!tmp)
+		return 0;
+	dind_bh = bread (inode->i_dev, tmp, inode->i_sb->s_blocksize);
+	if (tmp != (tind_bh ? le32_to_cpu(*p) : *p)) {
+		brelse (dind_bh);
+		return 1;
+	}
+	/* A read failure? Report error and clear slot (should be rare). */ 
+	if (!dind_bh) {
+		ext3_error(inode->i_sb, "trunc_dindirect",
+			"Read failure, inode=%ld, block=%d",
+			inode->i_ino, tmp);
+		if (tind_bh) {
+			journal_get_write_access(handle, tind_bh);
+			*p = 0;
+			journal_dirty_metadata(handle, tind_bh);
+		} else {
+			*p = 0;
+			ext3_mark_inode_dirty(handle, inode);
+		}
+		return 0;
+	}
+
+	addr_per_block = EXT3_ADDR_PER_BLOCK(inode->i_sb);
+	dindirect_block = DINDIRECT_BLOCK(inode, offset);
+	if (dindirect_block < 0)
+		dindirect_block = 0;
+	for (i = dindirect_block ; i < addr_per_block ; i++) {
+		u32 * dind = i + (u32 *) dind_bh->b_data;
+
+		retry |= trunc_indirect(handle, inode,
+					offset + (i * addr_per_block),
+					dind, dind_bh);
+	}
+	/*
+	 * Check the block and dispose of the dind_bh buffer.
+	 */
+	retry |= check_block_empty(handle, inode, dind_bh, p, tind_bh);
+
+	return retry;
+}
+
+static int trunc_tindirect (handle_t *handle, struct inode * inode)
+{
+	u32 * p = inode->u.ext3_i.i_data + EXT3_TIND_BLOCK;
+	struct buffer_head * tind_bh;
+	int i, tmp, retry = 0;
+	int tindirect_block, addr_per_block, offset;
+
+	if (!(tmp = *p))
+		return 0;
+	tind_bh = bread (inode->i_dev, tmp, inode->i_sb->s_blocksize);
+	if (tmp != *p) {
+		brelse (tind_bh);
+		return 1;
+	}
+	/* A read failure? Report error and clear slot (should be rare). */ 
+	if (!tind_bh) {
+		ext3_error(inode->i_sb, "trunc_tindirect",
+			"Read failure, inode=%ld, block=%d",
+			inode->i_ino, tmp);
+		*p = 0;
+		ext3_mark_inode_dirty(handle, inode);
+		return 0;
+	}
+
+	addr_per_block = EXT3_ADDR_PER_BLOCK(inode->i_sb);
+	offset = EXT3_NDIR_BLOCKS + addr_per_block + 
+		(addr_per_block * addr_per_block);
+	tindirect_block = TINDIRECT_BLOCK(inode, offset);
+	if (tindirect_block < 0)
+		tindirect_block = 0;
+	for (i = tindirect_block ; i < addr_per_block ; i++) {
+		u32 * tind = i + (u32 *) tind_bh->b_data;
+
+		retry |= trunc_dindirect(handle, inode,
+				offset + (i * addr_per_block * addr_per_block),
+				tind, tind_bh);
+	}
+	/*
+	 * Check the block and dispose of the tind_bh buffer.
+	 */
+	retry |= check_block_empty(handle, inode, tind_bh, p, NULL);
+
+	return retry;
+}
+
+void ext3_truncate (struct inode * inode)
+{
+	int err, offset, retry;
+	handle_t *handle;
+	
+	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;
+	
+	ext3_discard_prealloc(inode);
+
+	handle = start_transaction(inode);
+	
+	while (1) {
+		retry = trunc_direct(handle, inode);
+		retry |= trunc_indirect (handle, inode, 
+				EXT3_IND_BLOCK,
+				(u32 *) &inode->u.ext3_i.i_data[EXT3_IND_BLOCK],
+				NULL);
+		retry |= trunc_dindirect (handle, inode,
+				EXT3_IND_BLOCK+EXT3_ADDR_PER_BLOCK(inode->i_sb),
+				(u32 *)&inode->u.ext3_i.i_data[EXT3_DIND_BLOCK],
+				NULL);
+		retry |= trunc_tindirect (handle, inode);
+		if (!retry)
+			break;
+		journal_stop(handle);
+		current->counter = 0;
+		run_task_queue(&tq_disk);
+		current->policy |= SCHED_YIELD;
+		schedule ();
+		handle = start_transaction(inode);
+	}
+	/*
+	 * If the file is not being truncated to a block boundary, the
+	 * contents of the partial block following the end of the file
+	 * must be zeroed in case it ever becomes accessible again due
+	 * to subsequent file growth.
+	 */
+	offset = inode->i_size & (inode->i_sb->s_blocksize - 1);
+	if (offset) {
+		struct buffer_head * bh;
+		bh = ext3_bread (NULL, inode,
+				 inode->i_size >> EXT3_BLOCK_SIZE_BITS(inode->i_sb),
+				 0, &err);
+		if (bh) {
+			journal_get_write_access(handle, bh);
+			memset (bh->b_data + offset, 0,
+				inode->i_sb->s_blocksize - offset);
+			journal_dirty_metadata(handle, bh); /* @@@ DATA! */
+			brelse (bh);
+		}
+	}
+	inode->i_mtime = inode->i_ctime = CURRENT_TIME;
+	ext3_mark_inode_dirty(handle, inode);
+	journal_stop(handle);
+}
Index: oldkernel/linux/fs/fat/file.c
diff -u linux/fs/fat/file.c:1.2 linux/fs/fat/file.c:1.3
--- linux/fs/fat/file.c:1.2	Thu Jun  1 15:03:08 2000
+++ linux/fs/fat/file.c	Fri Jul  7 15:36:45 2000
@@ -227,7 +227,7 @@
 		Each time we process one block in bhlist, we replace
 		it by a new prefetch block if needed.
 	*/
-	PRINTK (("#### ino %ld pos %ld size %ld count %d\n",inode->i_ino,*ppos,(u_long)inode->i_size,count));
+	PRINTK (("#### ino %ld pos %ld size %ld count %d\n",inode->i_ino,*ppos,inode->i_size,count));
 	{
 		/*
 			We must prefetch complete block, so we must
@@ -253,7 +253,7 @@
 	}
 	pre.nolist = 0;
 	PRINTK (("count %d ahead %d nblist %d\n",count,read_ahead[MAJOR(inode->i_dev)],pre.nblist));
-	while ((left_in_file = (u_long)inode->i_size - *ppos) > 0
+	while ((left_in_file = inode->i_size - *ppos) > 0
 		&& buf < end){
 		struct buffer_head *bh = pre.bhlist[pre.nolist];
 		char *data;
@@ -451,7 +451,7 @@
 
 void fat_truncate(struct inode *inode)
 {
-	int cluster_bytes, cluster_shift;
+	int cluster;
 
 	/* Why no return value?  Surely the disk could fail... */
 	if (IS_IMMUTABLE(inode))
@@ -460,10 +460,8 @@
 		printk("FAT: fat_truncate called though fs is read-only, uhh...\n");
 		return /* -EROFS */;
 	}
-	cluster_bytes = SECTOR_SIZE * MSDOS_SB(inode->i_sb)->cluster_size;
-	cluster_shift = fslog2(cluster_bytes);
-	(void) fat_free(inode,
-			(inode->i_size+(cluster_bytes-1)) >> cluster_shift);
+	cluster = SECTOR_SIZE*MSDOS_SB(inode->i_sb)->cluster_size;
+	(void) fat_free(inode,(inode->i_size+(cluster-1))/cluster);
 	MSDOS_I(inode)->i_attrs |= ATTR_ARCH;
 	mark_inode_dirty(inode);
 }
Index: oldkernel/linux/fs/fat/inode.c
diff -u linux/fs/fat/inode.c:1.2 linux/fs/fat/inode.c:1.3
--- linux/fs/fat/inode.c:1.2	Thu Jun  1 15:03:08 2000
+++ linux/fs/fat/inode.c	Fri Jul  7 15:36:45 2000
@@ -392,9 +392,8 @@
 			sizeof(struct msdos_dir_entry);
 	}
 	inode->i_blksize = MSDOS_SB(sb)->cluster_size* SECTOR_SIZE;
-		inode->i_blocks = (((inode->i_size+inode->i_blksize-1) >>
-				    fslog2(inode->i_blksize)) *
-				   MSDOS_SB(sb)->cluster_size);
+	inode->i_blocks = (inode->i_size+inode->i_blksize-1)/
+		    inode->i_blksize*MSDOS_SB(sb)->cluster_size;
 	MSDOS_I(inode)->i_logstart = 0;
 
 	MSDOS_I(inode)->i_attrs = 0;
@@ -824,9 +823,8 @@
 	MSDOS_I(inode)->i_attrs = de->attr & ATTR_UNUSED;
 	/* this is as close to the truth as we can get ... */
 	inode->i_blksize = MSDOS_SB(sb)->cluster_size*SECTOR_SIZE;
-	inode->i_blocks = (((inode->i_size+inode->i_blksize-1) >>
-			    fslog2(inode->i_blksize)) *
-			   MSDOS_SB(sb)->cluster_size);
+	inode->i_blocks = (inode->i_size+inode->i_blksize-1)/
+	    inode->i_blksize*MSDOS_SB(sb)->cluster_size;
 	inode->i_mtime = inode->i_atime =
 	    date_dos2unix(CF_LE_W(de->time),CF_LE_W(de->date));
 	inode->i_ctime =
Index: oldkernel/linux/fs/fat/mmap.c
diff -u linux/fs/fat/mmap.c:1.1.1.1 linux/fs/fat/mmap.c:1.2
--- linux/fs/fat/mmap.c:1.1.1.1	Wed May 31 12:33:48 2000
+++ linux/fs/fat/mmap.c	Fri Jul  7 15:36:45 2000
@@ -23,6 +23,7 @@
 
 #include <asm/uaccess.h>
 #include <asm/system.h>
+#include <asm/pgtable.h>
 
 /*
  * Fill in the supplied page for mmap
@@ -123,8 +124,12 @@
 	struct dentry * dentry = file->f_dentry;
 	struct inode * inode = dentry->d_inode;
 	if (MSDOS_SB(inode->i_sb)->cvf_format &&
-	    MSDOS_SB(inode->i_sb)->cvf_format->cvf_readpage)
-		return MSDOS_SB(inode->i_sb)->cvf_format->cvf_readpage(inode,page);
+	    MSDOS_SB(inode->i_sb)->cvf_format->cvf_readpage) {
+		int ret = MSDOS_SB(inode->i_sb)->cvf_format->cvf_readpage(inode,page);
+
+		flush_dcache_page(page_address(page));
+		return ret;
+	}
 	    
 	printk("fat_readpage called with no handler (shouldn't happen)\n");
 	return -1;
Index: oldkernel/linux/fs/isofs/inode.c
diff -u linux/fs/isofs/inode.c:1.2 linux/fs/isofs/inode.c:1.3
--- linux/fs/isofs/inode.c:1.2	Thu Jun  1 15:03:08 2000
+++ linux/fs/isofs/inode.c	Fri Jul  7 15:36:45 2000
@@ -877,8 +877,7 @@
 
 int isofs_bmap(struct inode * inode,int block)
 {
-	loff_t b_off;
-	unsigned offset, size;
+	off_t b_off, offset, size;
 	struct inode *ino;
 	unsigned int firstext;
 	unsigned long nextino;
@@ -889,7 +888,7 @@
 		return 0;
 	}
 
-	b_off = (loff_t)block << ISOFS_BUFFER_BITS(inode);
+	b_off = block << ISOFS_BUFFER_BITS(inode);
 
 	/*
 	 * If we are beyond the end of this file, don't give out any
@@ -897,7 +896,7 @@
 	 */
 	if( b_off > inode->i_size )
 	  {
-	    loff_t	max_legal_read_offset;
+	    off_t	max_legal_read_offset;
 
 	    /*
 	     * If we are *way* beyond the end of the file, print a message.
@@ -908,21 +907,20 @@
 	     * I/O errors.
 	     */
 	    max_legal_read_offset = (inode->i_size + PAGE_SIZE - 1)
-					& ~(loff_t)(PAGE_SIZE - 1);
+	      & ~(PAGE_SIZE - 1);
 	    if( b_off >= max_legal_read_offset )
 	      {
 
 		printk("_isofs_bmap: block>= EOF(%d, %ld)\n", block,
-		       (u_long)((inode->i_size >> ISOFS_BUFFER_BITS(inode)) +
-				((inode->i_size & ((1 << ISOFS_BUFFER_BITS(inode))-1)) != 0)));
+		       inode->i_size);
 	      }
 	    return 0;
 	  }
 
 	offset = 0;
 	firstext = inode->u.isofs_i.i_first_extent;
-	size     = inode->u.isofs_i.i_section_size;
-	nextino  = inode->u.isofs_i.i_next_section_ino;
+	size = inode->u.isofs_i.i_section_size;
+	nextino = inode->u.isofs_i.i_next_section_ino;
 #ifdef DEBUG
 	printk("first inode: inode=%x nextino=%x firstext=%u size=%lu\n",
 		inode->i_ino, nextino, firstext, size);
@@ -1157,7 +1155,7 @@
 
 #ifdef DEBUG
 	printk("Get inode %x: %d %d: %d\n",inode->i_ino, block,
-	       ((int)pnt) & 0x3ff, (u_long)inode->i_size);
+	       ((int)pnt) & 0x3ff, inode->i_size);
 #endif
 
 	inode->i_mtime = inode->i_atime = inode->i_ctime =
Index: oldkernel/linux/fs/jfs/Makefile
diff -u /dev/null linux/fs/jfs/Makefile:1.1
--- /dev/null	Mon Jul 31 21:15:07 2000
+++ linux/fs/jfs/Makefile	Fri Jul  7 16:34:57 2000
@@ -0,0 +1,14 @@
+#
+# Makefile for the linux journaling routines.
+#
+# Note! Dependencies are done automagically by 'make dep', which also
+# removes any old dependencies. DON'T put your own dependencies here
+# unless it's something special (ie not a .c file).
+#
+# Note 2! The CFLAGS definitions are now in the main makefile...
+
+O_TARGET := jfs.o
+O_OBJS   := transaction.o journal.o commit.o recovery.o checkpoint.o
+M_OBJS   := $(O_TARGET)
+
+include $(TOPDIR)/Rules.make
Index: oldkernel/linux/fs/jfs/checkpoint.c
diff -u /dev/null linux/fs/jfs/checkpoint.c:1.1
--- /dev/null	Mon Jul 31 21:15:07 2000
+++ linux/fs/jfs/checkpoint.c	Fri Jul  7 16:34:57 2000
@@ -0,0 +1,423 @@
+/*
+ * linux/fs/checkpoint.c
+ * 
+ * Written by Stephen C. Tweedie <sct@redhat.com>, 1999
+ *
+ * Copyright 1999 Red Hat Software --- All Rights Reserved
+ *
+ * This file is part of the Linux kernel and is made available under
+ * the terms of the GNU General Public License, version 2, or at your
+ * option, any later version, incorporated herein by reference.
+ *
+ * Checkpoint routines for the generic filesystem journaling code.  
+ * Part of the ext2fs journaling system.  
+ *
+ * Checkpointing is the process of ensuring that a section of the log is
+ * committed fully to disk, so that that portion of the log can be
+ * reused.
+ */
+
+#include <linux/sched.h>
+#include <linux/fs.h>
+#include <linux/jfs.h>
+#include <linux/errno.h>
+#include <linux/malloc.h>
+#include <linux/locks.h>
+#include <linux/buffer.h>
+
+static int cleanup_journal_tail(journal_t *);
+
+/*
+ * Unlink a buffer from a transaction. 
+ */
+
+static inline void buffer_unlink(struct buffer_head *bh)
+{
+	transaction_t *transaction;
+	
+	transaction = bh->b_cp_transaction;
+	bh->b_cp_transaction = NULL;
+
+	bh->b_cpnext->b_cpprev = bh->b_cpprev;
+	bh->b_cpprev->b_cpnext = bh->b_cpnext;
+	if (transaction->t_checkpoint_list == bh)
+		transaction->t_checkpoint_list = bh->b_cpnext;
+	if (transaction->t_checkpoint_list == bh)
+		transaction->t_checkpoint_list = NULL;
+}
+ 
+
+/*
+ * log_wait_for_space: wait until there is space in the journal.
+ *
+ * Called with the journal already locked, but it will be unlocked if we have
+ * to wait for a checkpoint to free up some space in the log.
+ */
+
+void log_wait_for_space(journal_t *journal, int nblocks)
+{
+	while (log_space_left(journal) < nblocks) {
+		unlock_journal(journal);
+		down(&journal->j_checkpoint_sem);
+		lock_journal(journal);
+		
+		/* Test again, another process may have checkpointed
+		 * while we were waiting for the checkpoint lock */
+		if (log_space_left(journal) < nblocks) {
+			log_do_checkpoint(journal, nblocks);
+			/* @@@ What about errors? */
+		}
+		up(&journal->j_checkpoint_sem);
+	}
+}
+
+
+/*
+ * Clean up a transaction's checkpoint list.  
+ *
+ * We wait for any pending IO to complete and make sure any clean
+ * buffers are removed from the transaction. 
+ *
+ * Return 1 if we performed any actions which might have destroyed the
+ * checkpoint (refile_buffer deletes the transaction when the last
+ * checkpoint buffer is cleansed)
+ */
+
+static int cleanup_transaction(journal_t *journal, transaction_t *transaction)
+{
+	struct buffer_head *bh;
+	
+	bh = transaction->t_checkpoint_list;
+	if (!bh)
+		return 0;
+	
+	do {
+		if (buffer_locked(bh)) {
+			unlock_journal(journal);
+			bh->b_count++;
+			wait_on_buffer(bh);
+			brelse(bh);
+			lock_journal(journal);
+			return 1;
+		}
+		
+		if (bh->b_transaction != NULL) {
+			unlock_journal(journal);
+			log_wait_commit (journal,bh->b_transaction->t_tid);
+			lock_journal(journal);
+			return 1;
+		}
+		
+		if (!buffer_dirty(bh) && bh->b_list != BUF_CLEAN) {
+			unlock_journal(journal);
+			refile_buffer(bh);
+			lock_journal(journal);
+			return 1;
+		}
+		
+		bh = bh->b_cpnext;
+	} while (bh != transaction->t_checkpoint_list);
+	
+	return 0;
+}
+
+
+/*
+ * Try to flush one buffer from the checkpoint list to disk.
+ *
+ * Return 1 if something happened which requires us to abort the current
+ * scan of the checkpoint list.  
+ */
+static inline int flush_buffer(journal_t *journal, transaction_t *transaction,
+			       struct buffer_head *bh)
+{
+	/* 
+	 * Flush out only dirty, writable buffers.  
+	 */
+	
+	if (buffer_dirty(bh) && !buffer_locked(bh) && 
+	    bh->b_jlist == 0) {
+		J_ASSERT(bh->b_transaction == NULL);
+		
+		/*
+		 * Important: we are about to write the buffer, and
+		 * possibly block, while still holding the journal lock.
+		 * We cannot afford to let the transaction logic start
+		 * messing around with this buffer before we write it to
+		 * disk, as that would break recoverability.  
+		 */
+		
+		bh->b_count++;
+
+		J_ASSERT(!test_bit(BH_JWrite, &bh->b_state));
+		set_bit(BH_JWrite, &bh->b_state);
+		ll_rw_block(WRITE, 1, &bh);
+		clear_bit(BH_JWrite, &bh->b_state);
+				
+		/* We may have blocked, so check whether our context is
+		 * still valid and start over the transaction list again
+		 * if not. */
+				
+		if (transaction != journal->j_checkpoint_transactions ||
+		    bh->b_cp_transaction != transaction) {
+			brelse(bh);
+			return 1;
+		}
+		bh->b_count--; /* NOT brelse: don't block! */
+	}
+	return 0;
+}
+
+	
+/*
+ * Perform an actual checkpoint.  We don't write out only enough to
+ * satisfy the current blocked requests: rather we submit a reasonbly
+ * sized chunk of the outstanding data to disk at once for
+ * efficiency.  log_wait_for_space() will retry if we didn't free enough.
+ * 
+ * However, we _do_ take into account the amount requested so that once
+ * the IO has been queued, we can return as soon as enough of it has
+ * completed to disk.  
+ *
+ * The journal should be locked before calling this function.
+ */
+
+int log_do_checkpoint (journal_t *journal, int nblocks)
+{
+	transaction_t * transaction;
+	int result;
+	int target;
+	struct buffer_head *bh;
+	
+	jfs_debug(1, "Start checkpoint\n");
+
+	/* How many buffers will we try to write at once? */
+	#define MAXBUFS 128
+	
+	/* 
+	 * First thing: if there are any transactions in the log which
+	 * don't need checkpointing, just eliminate them from the
+	 * journal straight away.  
+	 */
+	
+	result = cleanup_journal_tail(journal);
+	jfs_debug(1, "cleanup_journal_tail returned %d\n", result);
+	if (result <= 0)
+		return result;
+
+	/*
+	 * OK, we need to start writing disk blocks.  Try to free up a
+	 * quarter of the log in a single checkpoint if we can.
+	 */
+
+	target = (journal->j_last - journal->j_first) / 4;
+	
+ repeat:
+	while (target > 0 && 
+	       (transaction = journal->j_checkpoint_transactions) != NULL) {
+
+		/* 
+		 * We'll remove all of the buffers from the transaction
+		 * first, and then flush them to disk once we are no
+		 * longer worried about the effect of refile_buffer
+		 * trying to checkpoint-unlink the buffers.
+		 */
+		
+		bh = transaction->t_checkpoint_list;
+		J_ASSERT (bh != NULL);
+		
+		do {
+			if (flush_buffer(journal, transaction, bh))
+				goto repeat;
+			bh = bh->b_cpnext;
+		} while (bh != transaction->t_checkpoint_list);
+
+		/*
+		 * We have walked the whole transaction list without
+		 * finding anything to write to disk.  We had better be
+		 * able to make some progress or we are in trouble. 
+		 */
+			
+		J_ASSERT(cleanup_transaction(journal, transaction));
+	}
+
+	cleanup_journal_tail(journal);
+	return 0;
+}
+
+
+/*
+ * Check the list of checkpoint transactions for the journal to see if
+ * we have already got rid of any since the last update of the log tail
+ * in the journal superblock.  If so, we can instantly roll the
+ * superblock forward to remove those transactions from the log.
+ * 
+ * Return <0 on error, 0 on success, 1 if there was nothing to clean up.
+ * 
+ * Called with the journal lock held.
+ */
+
+
+static int cleanup_journal_tail(journal_t *journal)
+{
+	transaction_t * transaction;
+	tid_t		first_tid;
+	unsigned long	blocknr, freed;
+
+	/* OK, work out the oldest transaction remaining in the log, and
+	 * the log block it starts at. 
+	 * 
+	 * If the log is now empty, we need to work out which is the
+	 * next transaction ID we will write, and where it will
+	 * start. */
+
+	transaction = journal->j_checkpoint_transactions;
+	if (transaction) {
+		first_tid = transaction->t_tid;
+		blocknr = transaction->t_log_start;
+	} else if ((transaction = journal->j_committing_transaction) != NULL) {
+		first_tid = transaction->t_tid;
+		blocknr = transaction->t_log_start;
+	} else if ((transaction = journal->j_running_transaction) != NULL) {
+		first_tid = transaction->t_tid;
+		blocknr = journal->j_head;
+	} else {
+		first_tid = journal->j_transaction_sequence;
+		blocknr = journal->j_head;
+	}
+	J_ASSERT (blocknr != 0);
+
+	/* If the oldest pinned transaction is at the tail of the log
+           already then there's not much we can do right now. */
+	if (journal->j_tail_sequence == first_tid)
+		return 1;
+	
+	/* OK, update the superblock to recover the freed space.
+	 * Physical blocks come first: have we wrapped beyond the end of
+	 * the log?  */
+	freed = blocknr - journal->j_tail;
+	if (blocknr < journal->j_tail)
+		freed = freed + journal->j_last - journal->j_first;
+	else
+
+	jfs_debug(1,
+		  "Cleaning journal tail from %ld to %ld (offset %lu), "
+		  "freeing %lu\n",
+		  journal->j_tail_sequence, first_tid, blocknr, freed);
+
+	journal->j_free += freed;
+	journal->j_tail_sequence = first_tid;
+	journal->j_tail = blocknr;
+	journal_update_superblock(journal, 1);
+	return 0;
+}
+
+
+/* Checkpoint list management */
+
+/* 
+ * journal_remove_checkpoint: called after a buffer has been committed
+ * to disk (either by being write-back flushed to disk, or being
+ * committed to the log).
+ *
+ * We cannot safely clean a transaction out of the log until all of the
+ * buffer updates committed in that transaction have safely been stored
+ * elsewhere on disk.  To achieve this, all of the buffers in a
+ * transaction need to be maintained on the transaction's checkpoint
+ * list until they have been rewritten, at which point this function is
+ * called to remove the buffer from the existing transaction's
+ * checkpoint list.  
+ */
+
+void real_journal_remove_checkpoint(struct buffer_head *bh)
+{
+	transaction_t *transaction;
+	journal_t *journal;
+
+	if ((transaction = bh->b_cp_transaction) == NULL)
+		return;
+
+	buffer_unlink(bh);
+
+	if (transaction->t_checkpoint_list != NULL)
+		return;
+
+	journal = transaction->t_journal;
+
+	/* There is one special case to worry about: if we have just
+           pulled the buffer off a committing transaction's forget list,
+           then even if the checkpoint list is empty, the transaction
+           obviously cannot be dropped! */
+
+	if (transaction == journal->j_committing_transaction)
+		return;
+
+	/* OK, that was the last buffer for the transaction: we can now
+	   safely remove this transaction from the log */
+
+	journal_drop_transaction(journal, transaction);
+	
+	/* Just in case anybody was waiting for more transactions to be
+           checkpointed... */
+	wake_up(&journal->j_wait_logspace);
+}
+
+/*
+ * journal_insert_checkpoint: put a committed buffer onto a checkpoint
+ * list so that we know when it is safe to clean the transaction out of
+ * the log. 
+ */
+
+void journal_insert_checkpoint(struct buffer_head *bh, 
+			       transaction_t *transaction)
+{
+	J_ASSERT (buffer_dirty(bh));
+	J_ASSERT (bh->b_cp_transaction == NULL);
+
+	bh->b_cp_transaction = transaction;
+
+	if (!transaction->t_checkpoint_list) {
+		bh->b_cpnext = bh->b_cpprev = bh;
+	} else {
+		bh->b_cpnext = transaction->t_checkpoint_list;
+		bh->b_cpprev = transaction->t_checkpoint_list->b_cpprev;
+		bh->b_cpprev->b_cpnext = bh;
+		bh->b_cpnext->b_cpprev = bh;
+	}
+	transaction->t_checkpoint_list = bh;
+}
+
+/*
+ * We've finished with this transaction structure: adios...
+ * 
+ * The transaction must have no links except for the checkpoint by this
+ * point.  */
+
+void journal_drop_transaction(journal_t *journal, transaction_t *transaction)
+{
+	if (transaction->t_cpnext) {
+		transaction->t_cpnext->t_cpprev = transaction->t_cpprev;
+		transaction->t_cpprev->t_cpnext = transaction->t_cpnext;
+		if (journal->j_checkpoint_transactions == transaction)
+			journal->j_checkpoint_transactions = transaction->t_cpnext;
+		if (journal->j_checkpoint_transactions == transaction)
+			journal->j_checkpoint_transactions = NULL;
+	}
+
+	J_ASSERT (transaction->t_ilist == NULL);
+	J_ASSERT (transaction->t_buffers == NULL);
+	J_ASSERT (transaction->t_datalist == NULL);
+	J_ASSERT (transaction->t_forget == NULL);
+	J_ASSERT (transaction->t_iobuf_list == NULL);
+	J_ASSERT (transaction->t_shadow_list == NULL);
+	J_ASSERT (transaction->t_log_list == NULL);
+	J_ASSERT (transaction->t_checkpoint_list == NULL);
+	J_ASSERT (transaction->t_updates == 0);
+	
+	J_ASSERT (transaction->t_journal->j_committing_transaction != transaction);
+	
+	jfs_debug (1, "Dropping transaction %ld, all done\n", 
+		   transaction->t_tid);
+	kfree (transaction);
+}
+
Index: oldkernel/linux/fs/jfs/commit.c
diff -u /dev/null linux/fs/jfs/commit.c:1.1
--- /dev/null	Mon Jul 31 21:15:08 2000
+++ linux/fs/jfs/commit.c	Fri Jul  7 16:34:57 2000
@@ -0,0 +1,435 @@
+/*
+ * linux/fs/commit.c
+ * 
+ * Written by Stephen C. Tweedie <sct@redhat.com>, 1998
+ *
+ * Copyright 1998 Red Hat corp --- All Rights Reserved
+ *
+ * This file is part of the Linux kernel and is made available under
+ * the terms of the GNU General Public License, version 2, or at your
+ * option, any later version, incorporated herein by reference.
+ *
+ * Journal commit routines for the generic filesystem journaling code;
+ * part of the ext2fs journaling system.
+ */
+
+#include <linux/sched.h>
+#include <linux/fs.h>
+#include <linux/jfs.h>
+#include <linux/errno.h>
+#include <linux/malloc.h>
+#include <linux/locks.h>
+#include <linux/buffer.h>
+
+/*
+ * journal_commit_transaction
+ *
+ * The primary function for committing a transaction to the log.  This
+ * function is called by the journal thread to begin a complete commit.
+ */
+
+void journal_commit_transaction(journal_t *journal)
+{
+	transaction_t *commit_transaction;
+	struct buffer_head *bh, *new_bh, *descriptor;
+	struct buffer_head *wbuf[journal_flush_nr_buffers];
+	int bufs;
+	int flags;
+	int blocknr;
+	char *tagp = NULL;
+	journal_header_t *header;
+	journal_block_tag_t *tag = NULL, *last_tag;
+	int space_left = 0;
+	int first_tag = 0;
+	int tag_flag;
+	
+	int i;
+	
+	/*
+	 * First job: lock down the current transaction and wait for 
+	 * all outstanding updates to complete. 
+	 */
+	
+	lock_journal(journal);
+
+	J_ASSERT (journal->j_running_transaction != NULL);
+	J_ASSERT (journal->j_committing_transaction == NULL);
+	
+	commit_transaction = journal->j_running_transaction;
+	J_ASSERT (commit_transaction->t_state == T_RUNNING);
+
+	jfs_debug (1, "Starting commit of transaction %ld\n",
+		   commit_transaction->t_tid);
+	
+	commit_transaction->t_state = T_LOCKED;
+	while (commit_transaction->t_updates != 0) {
+		unlock_journal(journal);
+		sleep_on(&commit_transaction->t_wait);
+		lock_journal(journal);
+	}
+
+	J_ASSERT (commit_transaction->t_outstanding_credits <= journal->j_max_transaction_buffers);
+	
+	/*
+	 * First thing we are allowed to do is to discard any remaining
+	 * BJ_Reserved buffers.  Note, it is _not_ permissible to assume
+	 * that there are no such buffers: if a large filesystem
+	 * operation like a truncate needs to split itself over multiple
+	 * transactions, then it may try to do a journal_restart() while
+	 * there are still BJ_Reserved buffers outstanding.  These must
+	 * be released cleanly from the current transaction.
+	 *
+	 * In this case, the filesystem must still reserve write access
+	 * again before modifying the buffer in the new transaction, but
+	 * we do not require it to remember exactly which old buffers it
+	 * has reserved.  This is consistent with the existing behaviour
+	 * that multiple journal_get_write_access() calls to the same
+	 * buffer are perfectly permissable.
+	 */
+
+	while (commit_transaction->t_reserved_list) {
+		bh = commit_transaction->t_reserved_list;
+		journal_refile_buffer(bh);
+	}
+	
+
+	/* 
+	 * Start committing the old transaction: time to get a new
+	 * running transaction for incoming filesystem updates */
+
+	jfs_debug (3, "commit phase 1\n");
+
+	commit_transaction->t_state = T_FLUSH;
+	wake_up(&journal->j_wait_transaction_locked);
+	
+	journal->j_committing_transaction = commit_transaction;
+	journal->j_running_transaction = NULL;
+	
+	commit_transaction->t_log_start = journal->j_head;
+
+	/* 
+	 * Now start flushing things to disk, in the order they appear
+	 * on the transaction lists.  Data blocks go first.  
+	 */
+	
+ wait_for_data:
+	bufs = 0;
+	
+	/* Cleanup any flushed data buffers from the data list. */
+	journal_clean_data_list(commit_transaction);
+
+	bh = commit_transaction->t_datalist;
+	
+	if (bh) do {
+		if (buffer_dirty(bh) && !buffer_locked(bh)) {
+			set_bit(BH_JWrite, &bh->b_state);
+			wbuf[bufs++] = bh;
+		}
+		bh = bh->b_tnext;
+	} while (bufs < journal_flush_nr_buffers &&
+		 bh != commit_transaction->t_datalist);
+
+	if (bufs) {
+		unlock_journal(journal);
+		ll_rw_block(WRITE, bufs, wbuf);
+		run_task_queue(&tq_disk);
+		lock_journal(journal);
+		goto wait_for_data;
+	}
+
+	/*
+	 * If we got through the write loop without submitting any new
+	 * IO, then wait for all previously submitted IO on the data
+	 * list to complete. 
+	 */
+
+	bh = commit_transaction->t_datalist;
+	
+	if (bh) do {
+		clear_bit(BH_JWrite, &bh->b_state);
+		if (buffer_locked(bh)) {
+			unlock_journal(journal);
+			wait_on_buffer(bh);
+			lock_journal(journal);
+			goto wait_for_data;
+		}
+		
+		bh = bh->b_tnext;
+	} while (bh != commit_transaction->t_datalist);
+
+	/*
+	 * If we found any dirty or locked buffers, then we should have
+	 * looped back up to the wait_for_data label.  If there weren't
+	 * any then journal_clean_data_list should have wiped the list
+	 * clean by now, so check that it is in fact empty. 
+	 */
+	
+	J_ASSERT (commit_transaction->t_datalist == NULL);
+
+	jfs_debug (3, "Commit phase 2\n");
+
+	/*
+	 * Way to go: we have now written out all of the data for a
+	 * transaction!  Now comes the tricky part: we need to write out
+	 * metadata now.  Loop over the transaction's entire buffer list:
+	 */
+
+	commit_transaction->t_state = T_COMMIT;
+	descriptor = 0;
+	bufs = 0;
+	
+	while (commit_transaction->t_buffers) {
+
+		/* Find the next buffer to be journaled... */
+
+		bh = commit_transaction->t_buffers;
+
+		/* And make sure we have a descriptor block in which to 
+		   record the metadata buffer. */
+
+		if (!descriptor) {
+			J_ASSERT (bufs == 0);
+			
+			jfs_debug(4, "get descriptor\n");
+
+			descriptor = journal_get_descriptor_buffer(journal);
+			jfs_debug(4, "JFS: got buffer %ld (%p)\n", 
+				  descriptor->b_blocknr, descriptor->b_data);
+			header = (journal_header_t *) &descriptor->b_data[0];
+			header->h_magic     = htonl(JFS_MAGIC_NUMBER);
+			header->h_blocktype = htonl(JFS_DESCRIPTOR_BLOCK);
+			header->h_sequence  = htonl(commit_transaction->t_tid);
+
+			tagp = &descriptor->b_data[sizeof(journal_header_t)];
+			space_left = descriptor->b_size - sizeof(journal_header_t);
+			first_tag = 1;
+			set_bit(BH_JWrite, &descriptor->b_state);
+			wbuf[bufs++] = descriptor;
+			
+			/* Record it so that we can wait for IO
+                           completion later */
+			journal_file_buffer(descriptor, 
+					    commit_transaction,
+					    BJ_LogCtl);
+		}
+
+		/* Where is the buffer to be written? */
+		
+		blocknr = journal_next_log_block(journal);
+		
+		/* Make a temporary IO buffer with which to write it out
+                   (this will requeue both the metadata buffer and the
+                   temporary IO buffer). */
+
+		set_bit(BH_JWrite, &bh->b_state);
+		flags = journal_write_metadata_buffer(commit_transaction,
+						      bh, 
+						      &new_bh,
+						      blocknr);
+		set_bit(BH_JWrite, &new_bh->b_state);
+		wbuf[bufs++] = new_bh;
+		
+		/* Record the new block's tag in the current descriptor
+                   buffer */
+
+		tag_flag = 0;
+		if (flags & 1)
+			tag_flag |= JFS_FLAG_ESCAPE;
+		if (!first_tag)
+			tag_flag |= JFS_FLAG_SAME_UUID;
+
+		tag = (journal_block_tag_t *) tagp;
+		tag->t_blocknr = htonl(bh->b_blocknr);
+		tag->t_flags = htonl(tag_flag);
+		tagp += sizeof(journal_block_tag_t);
+		space_left -= sizeof(journal_block_tag_t);
+		
+		if (first_tag) {
+			memcpy (tagp, journal->j_uuid, 16);
+			tagp += 16;
+			space_left -= 16;
+			first_tag = 0;
+		}
+		
+		/* If there's no more to do, or if the descriptor is full,
+		   let the IO rip! */
+
+		if (bufs == journal_flush_nr_buffers ||
+		    commit_transaction->t_buffers == NULL ||		    
+		    space_left < sizeof(journal_block_tag_t) + 16) {
+
+			jfs_debug(4, "JFS: Submit %d IOs\n", bufs);
+			
+			/* Write an end-of-descriptor marker before
+                           submitting the IOs.  "tag" still points to
+                           the last tag we set up. */
+			
+			tag->t_flags |= htonl(JFS_FLAG_LAST_TAG);
+
+			unlock_journal(journal);
+			ll_rw_block (WRITE, bufs, wbuf);
+			lock_journal(journal);
+			
+			/* Force a new descriptor to be generated next
+                           time round the loop. */
+			descriptor = NULL;
+			bufs = 0;
+		}
+	}
+
+	/* Lo and behold: we have just managed to send a transaction to
+           the log.  Before we can commit it, wait for the IO so far to
+           complete.  Control buffers being written are on the
+           transaction's t_log_list queue, and metadata buffers are on
+           the t_iobuf_list queue. 
+	
+	   Wait for the transactions in reverse order.  That way we are
+	   less likely to be woken up until all IOs have completed, and
+	   so we incur less scheduling load.
+	*/
+
+	jfs_debug(3, "JFS: commit phase 3\n");
+
+ wait_for_iobuf:
+	while (commit_transaction->t_iobuf_list != NULL) {
+		struct buffer_head *bh = commit_transaction->t_iobuf_list->b_tprev;
+		if (buffer_locked(bh)) {
+			unlock_journal(journal); 
+			wait_on_buffer(bh);
+			lock_journal(journal); 
+			goto wait_for_iobuf;
+		}
+		
+		clear_bit(BH_JWrite, &bh->b_state);
+
+		journal_unfile_buffer(bh);
+		put_unused_buffer_head(bh);
+		
+		/* We also have to unlock and free the corresponding
+                   shadowed buffer */
+
+		bh = commit_transaction->t_shadow_list->b_tprev;
+		clear_bit(BH_JWrite, &bh->b_state);
+		J_ASSERT(buffer_dirty(bh));
+		
+		/* The metadata is now released for reuse, but we need
+                   to remember it against this transaction so that when
+                   we finally commit, we can do any checkpointing
+                   required. */
+
+		journal_file_buffer(bh, commit_transaction, BJ_Forget);
+
+		/* Wake up any transactions which were waiting for this
+		   IO to complete */
+		wake_up(&bh->b_wait);
+		
+		/* Found an unlocked buffer: remove it */
+		
+		if (bh->b_frozen_data) {
+			kfree(bh->b_frozen_data);
+			bh->b_frozen_data = NULL;
+		}
+	}
+
+	J_ASSERT (commit_transaction->t_shadow_list == NULL);
+	
+	jfs_debug(3, "JFS: commit phase 4\n");
+
+ wait_for_ctlbuf:
+	while (commit_transaction->t_log_list != NULL) {
+		struct buffer_head *bh = commit_transaction->t_log_list->b_tprev;
+		
+		if (buffer_locked(bh)) {
+			unlock_journal(journal); 
+			wait_on_buffer(bh);
+			lock_journal(journal); 
+			goto wait_for_ctlbuf;
+		}
+		
+		clear_bit(BH_JWrite, &bh->b_state);	
+		journal_unfile_buffer(bh);
+		bh->b_transaction = NULL;
+		brelse(bh);
+	}
+	
+	jfs_debug(3, "JFS: commit phase 5\n");
+
+	/* Done it all: now write the commit record */
+
+	descriptor = journal_get_descriptor_buffer(journal);
+
+	for (i = 0; i < descriptor->b_size; i += 512) {
+		journal_header_t *tmp = (journal_header_t*)descriptor->b_data;
+		tmp->h_magic = htonl(JFS_MAGIC_NUMBER);
+		tmp->h_blocktype = htonl(JFS_COMMIT_BLOCK);
+		tmp->h_sequence = htonl(commit_transaction->t_tid);
+	}
+
+	unlock_journal(journal); 
+	ll_rw_block(WRITE, 1, &descriptor);
+	wait_on_buffer(descriptor);
+	brelse(descriptor);
+	lock_journal(journal); 
+	
+	/* End of a transaction!  Finally, we can do checkpoint
+           processing: any buffers committed as a result of this
+           transaction can be removed from any checkpoint list it was on
+           before. */
+
+	jfs_debug(3, "JFS: commit phase 6\n");
+
+	J_ASSERT(commit_transaction->t_datalist == NULL);
+	J_ASSERT(commit_transaction->t_buffers == NULL);
+	J_ASSERT(commit_transaction->t_checkpoint_list == NULL);
+	J_ASSERT(commit_transaction->t_iobuf_list == NULL);
+	J_ASSERT(commit_transaction->t_shadow_list == NULL);
+	J_ASSERT(commit_transaction->t_log_list == NULL);
+
+	while (commit_transaction->t_forget) {
+		transaction_t *cp_transaction;
+		
+		bh = commit_transaction->t_forget;
+		J_ASSERT (bh->b_transaction == commit_transaction || 
+			  bh->b_transaction == journal->j_running_transaction);
+
+		cp_transaction = bh->b_cp_transaction;
+		if (cp_transaction) {
+			J_ASSERT (commit_transaction != cp_transaction);
+			journal_remove_checkpoint(bh);
+		}
+		journal_insert_checkpoint(bh, commit_transaction);
+       
+		journal_refile_buffer(bh);
+	}
+	
+	/* Done with this transaction! */
+
+	jfs_debug(3, "JFS: commit phase 7\n");
+
+	J_ASSERT (commit_transaction->t_state == T_COMMIT);
+	commit_transaction->t_state = T_FINISHED;
+
+	J_ASSERT (commit_transaction == journal->j_committing_transaction);
+	journal->j_commit_sequence = commit_transaction->t_tid;
+	journal->j_committing_transaction = NULL;
+
+	if (commit_transaction->t_checkpoint_list == NULL) {
+		journal_drop_transaction(journal, commit_transaction);
+	} else {
+		if (journal->j_checkpoint_transactions == NULL) {
+			journal->j_checkpoint_transactions = commit_transaction;
+			commit_transaction->t_cpnext = commit_transaction;
+			commit_transaction->t_cpprev = commit_transaction;
+		} else {
+			commit_transaction->t_cpnext = journal->j_checkpoint_transactions;
+			commit_transaction->t_cpprev = commit_transaction->t_cpnext->t_cpprev;
+			commit_transaction->t_cpnext->t_cpprev = commit_transaction;
+			commit_transaction->t_cpprev->t_cpnext = commit_transaction;
+		}
+	}
+	
+	jfs_debug(1, "Commit complete\n");
+
+	unlock_journal(journal); 
+	wake_up(&journal->j_wait_done_commit);
+}
Index: oldkernel/linux/fs/jfs/journal.c
diff -u /dev/null linux/fs/jfs/journal.c:1.1
--- /dev/null	Mon Jul 31 21:15:08 2000
+++ linux/fs/jfs/journal.c	Fri Jul  7 16:34:57 2000
@@ -0,0 +1,797 @@
+/*
+ * linux/fs/journal.c
+ * 
+ * Written by Stephen C. Tweedie <sct@redhat.com>, 1998
+ *
+ * Copyright 1998 Red Hat corp --- All Rights Reserved
+ *
+ * This file is part of the Linux kernel and is made available under
+ * the terms of the GNU General Public License, version 2, or at your
+ * option, any later version, incorporated herein by reference.
+ *
+ * Generic filesystem journal-writing code; part of the ext2fs
+ * journaling system.  
+ *
+ * This file manages journals: areas of disk reserved for logging
+ * transactional updates.  This includes the kernel journaling thread
+ * which is responsible for scheduling updates to the log.
+ *
+ * We do not actually manage the physical storage of the journal in this
+ * file: that is left to a per-journal policy function, which allows us
+ * to store the journal within a filesystem-specified area for ext2
+ * journaling (ext2 can use a reserved inode for storing the log).
+ */
+
+#include <linux/module.h>
+#include <linux/sched.h>
+#include <linux/fs.h>
+#include <linux/jfs.h>
+#include <linux/errno.h>
+#include <linux/malloc.h>
+#include <linux/locks.h>
+#include <linux/buffer.h>
+#include <linux/smp_lock.h>
+
+#define __KERNEL_SYSCALLS__
+#include <linux/unistd.h>
+
+/*
+ * Tunable parameters
+ */
+
+/* Number of buffers to flush out at once before starting the disk up */
+int journal_flush_nr_buffers = 64;
+
+
+#ifdef JFS_DEBUG
+int jfs_enable_debug = 0;
+#endif
+
+/*
+ * Helper function used to manage commit timeouts
+ */
+
+static void commit_timeout(unsigned long __data)
+{
+	struct task_struct * p = (struct task_struct *) __data;
+
+	wake_up_process(p);
+}
+
+
+/* 
+ * kjournald: The main thread function used to manage a logging device
+ * journal.
+ *
+ * This kernel thread is responsible for two things:
+ *
+ * 1) COMMIT:  Every so often we need to commit the current state of the
+ *    filesystem to disk.  The journal thread is responsible for writing
+ *    all of the metadata buffers to disk.
+ *
+ * 2) CHECKPOINT: We cannot reuse a used section of the log file until all
+ *    of the data in that part of the log has been rewritten elsewhere on 
+ *    the disk.  Flushing these old buffers to reclaim space in the log is
+ *    known as checkpointing, and this thread is responsible for that job.
+ */
+
+int kjournald(void *arg)
+{
+	journal_t *journal = (journal_t *) arg;
+	transaction_t *transaction;
+	struct timer_list timer;
+	
+	lock_kernel();
+	
+	exit_files(current);
+	exit_mm(current);
+
+	spin_lock_irq(&current->sigmask_lock);
+	sigfillset(&current->blocked);
+	recalc_sigpending(current);
+	spin_unlock_irq(&current->sigmask_lock);
+
+	current->session = 1;
+	current->pgrp = 1;
+	sprintf(current->comm, "kjournald");
+
+	/* Set up an interval timer which can be used to trigger a
+           commit wakeup after the commit interval expires */
+	init_timer(&timer);
+	timer.data = (unsigned long) current;
+	timer.function = commit_timeout;
+	journal->j_commit_timer = &timer;
+	
+	/* Record that the journal thread is running */
+	journal->j_task = current;
+	wake_up(&journal->j_wait_done_commit);
+
+	jfs_debug(1, "Journal thread starting.\n");
+	
+	/* And now, wait forever for commit wakeup events. */
+	while (1) {
+		if (journal->j_flags & JFS_UNMOUNT)
+			break;
+
+		if (journal->j_commit_sequence != journal->j_commit_request) {
+			if (journal->j_commit_timer_active) {
+				journal->j_commit_timer_active = 0;
+				del_timer(journal->j_commit_timer);
+			}
+			
+			journal_commit_transaction(journal);
+			continue;
+		}
+		
+		wake_up(&journal->j_wait_done_commit);
+		interruptible_sleep_on(&journal->j_wait_commit);
+
+		/* Were we woken up by a commit wakeup event? */
+		if ((transaction = journal->j_running_transaction) != NULL &&
+		    time_after_eq(jiffies, transaction->t_expires))
+			journal->j_commit_request = transaction->t_tid;
+	}
+	
+	if (journal->j_commit_timer_active) {
+		journal->j_commit_timer_active = 0;
+		del_timer(journal->j_commit_timer);
+	}
+
+	journal->j_task = NULL;
+	wake_up(&journal->j_wait_done_commit);
+	jfs_debug(1, "Journal thread exiting.\n");
+	return 0;
+}
+
+static void journal_start_thread(journal_t *journal)
+{
+	kernel_thread(kjournald, (void *) journal, 
+		      CLONE_VM | CLONE_FS | CLONE_FILES);
+	while (!journal->j_task)
+		sleep_on(&journal->j_wait_done_commit);
+}
+	
+static void journal_kill_thread(journal_t *journal)
+{
+	journal->j_flags |= JFS_UNMOUNT;
+	
+	while (journal->j_task) {
+		wake_up(&journal->j_wait_commit);
+		sleep_on(&journal->j_wait_done_commit);
+	}
+}
+	
+
+/*
+ * journal_clean_data_list: cleanup after data IO.
+ *
+ * Once the IO system has finished writing the buffers on the transaction's
+ * data list, we can remove those buffers from the list.  This function 
+ * scans the list for such buffers and removes them cleanly.
+ *
+ * We assume that the journal is already locked.  This function does not block.
+ */
+
+void journal_clean_data_list(transaction_t *transaction)
+{
+	struct buffer_head *bh, *next, *last;
+	
+	next = transaction->t_datalist;
+	if (!next)
+		return;
+
+	last = next->b_tprev;
+	
+	do {
+		bh = next;
+		next = bh->b_tnext;
+		
+		if (!buffer_locked(bh) && 
+		    !buffer_dirty(bh)) {
+			journal_unfile_buffer(bh);
+			bh->b_transaction = NULL;
+			refile_buffer(bh);
+		}
+	} while (bh != last);
+}
+
+/*
+ * journal_write_metadata_buffer: write a metadata buffer to the journal.
+ *
+ * Writes a metadata buffer to a given disk block.  The actual IO is not
+ * performed but a new buffer_head is constructed which labels the data
+ * to be written with the correct destination disk block.
+ *
+ * Any magic-number escaping which needs to be done will cause a
+ * copy-out here.  If the buffer happens to start with the
+ * JFS_MAGIC_NUMBER, then we can't write it to the log directly: the
+ * magic number is only written to the log for descripter blocks.  In
+ * this case, we copy the data and replace the first word with 0, and we
+ * return a result code which indicates that this buffer needs to be
+ * marked as an escaped buffer in the corresponding log descriptor
+ * block.  The missing word can then be restored when the block is read
+ * during recovery.
+ * 
+ * If the source buffer has already been modified by a new transaction
+ * since we took the last commit snapshot, we use the frozen copy of
+ * that data for IO.  If we end up using the existing buffer_head's data
+ * for the write, then we *have* to lock the buffer to prevent anyone
+ * else from using and possibly modifying it while the IO is in
+ * progress.
+ *
+ * The function returns a pointer to the buffer_heads to be used for IO.
+ *
+ * We assume that the journal has already been locked in this function.
+ *
+ * Return value:
+ *  <0: Error
+ * >=0: Finished OK
+ * 
+ * On success:
+ * Bit 0 set == escape performed on the data
+ * Bit 1 set == buffer copy-out performed (kfree the data after IO)
+ */
+
+int journal_write_metadata_buffer(transaction_t *transaction,
+				  struct buffer_head  *bh_in,
+				  struct buffer_head **bh_out,
+				  int blocknr)
+{
+	int need_copy_out = 0;
+	int done_copy_out = 0;
+	int do_escape = 0;
+	char *new_data;
+	struct buffer_head * new_bh;
+
+	/* 
+	 * The buffer really shouldn't be locked: only the current committing
+	 * transaction is allowed to write it, so nobody else is allowed
+	 * to do any IO.
+	 */
+
+	J_ASSERT (!buffer_locked(bh_in));
+	J_ASSERT (buffer_dirty(bh_in));
+
+	/*
+	 * If a new transaction has already done a buffer copy-out, then 
+	 * we use that version of the data for the commit.
+	 */
+
+	if (bh_in->b_frozen_data) {
+		done_copy_out = 1;
+		new_data = bh_in->b_frozen_data;
+	} else
+		new_data = bh_in->b_data;
+		
+	/*
+	 * Check for escaping 
+	 */
+
+	if (* ((unsigned int *) new_data) == htonl(JFS_MAGIC_NUMBER)) {
+		need_copy_out = 1;
+		do_escape = 1;
+	}
+
+	/*
+	 * Do we need to do a data copy?
+	 */
+
+	if (need_copy_out && !done_copy_out) {
+		char *tmp = kmalloc(bh_in->b_size, GFP_BUFFER);
+		if (!tmp)
+			return -ENOMEM; /* @@@ Really need to loop! */
+
+		bh_in->b_frozen_data = tmp;
+		memcpy (tmp, new_data, bh_in->b_size);
+		new_data = tmp;
+		done_copy_out = 1;
+	}
+	
+	/*
+	 * Right, time to make up the new buffer_head.
+	 */
+
+	new_bh = get_unused_buffer_head(0);
+	
+	/* @@@ Check for ENOMEM */
+
+	J_ASSERT (new_bh != NULL);
+
+	init_buffer(new_bh, transaction->t_journal->j_dev, blocknr, 
+		    end_buffer_io_sync, NULL);
+
+	new_bh->b_size    = bh_in->b_size;
+	new_bh->b_data    = new_data;
+	new_bh->b_state	  = (1 << BH_Temp) | (1 << BH_Dirty);
+	new_bh->b_count	  = 1;
+
+	*bh_out = new_bh;
+
+	/* 
+	 * Did we need to do an escaping?  Now we've done all the
+	 * copying, we can finally do so.
+	 */
+
+	if (do_escape)
+		* ((unsigned int *) new_data) = 0;
+
+	/* 
+	 * The to-be-written buffer needs to get moved to the io queue,
+	 * and the original buffer whose contents we are shadowing or
+	 * copying is moved to the transaction's shadow queue. 
+	 */
+
+	journal_file_buffer(bh_in, transaction, BJ_Shadow);
+	journal_file_buffer(new_bh, transaction, BJ_IO);
+	
+	return do_escape + (done_copy_out << 1);
+}
+
+
+/* The call to lock_buffer() above should be the only place we ever lock
+ * a buffer which is being journaled (ignoring the checkpoint lists). */
+
+#ifdef CONFIG_EXT3_FS_JFS_CHECK
+void real_jfs_prelock_buffer_check(struct buffer_head *bh)
+{
+	if (bh->b_jlist == 0 && bh->b_transaction == NULL)
+		return;
+	J_ASSERT(bh->b_jlist == 0 || bh->b_jlist == BJ_LogCtl || bh->b_jlist == BJ_IO);
+	J_ASSERT(bh->b_transaction != NULL);
+	J_ASSERT(bh->b_transaction == bh->b_transaction->t_journal->j_committing_transaction);
+	J_ASSERT(test_bit(BH_JWrite, &bh->b_state));
+}
+
+/* We are not allowed to forget the dirty status on any buffer which is
+ * being journaled! */
+
+void real_jfs_preclean_buffer_check(struct buffer_head *bh)
+{
+	jfs_prelock_buffer_check(bh);
+}
+#endif
+
+
+
+
+/*
+ * Allocation code for the journal file.  Manage the space left in the
+ * journal, so that we can begin checkpointing when appropriate.
+ */
+
+/*
+ * log_space_left: Return the number of free blocks left in the journal.
+ *
+ * Called with the journal already locked.
+ */
+
+int log_space_left (journal_t *journal)
+{
+	int left = journal->j_free;
+
+	/* Be pessimistic here about the number of those free blocks
+	 * which might be required for log descriptor control blocks. */
+
+#define MIN_LOG_RESERVED_BLOCKS 32 /* Allow for rounding errors */
+
+	left -= MIN_LOG_RESERVED_BLOCKS;
+	
+	if (left <= 0)
+		return 0;
+	left -= (left >> 3);
+	return left;
+}
+
+
+void log_start_commit (journal_t *journal, transaction_t *transaction)
+{
+	/*
+	 * Are we already doing a recent enough commit?
+	 */
+	if ((long)(journal->j_commit_request - transaction->t_tid) > 0)
+		return;
+
+	/* 
+	 * We want a new commit: OK, mark the request and wakup the
+	 * commit thread.  We do _not_ do the commit ourselves.  
+	 */
+	
+	journal->j_commit_request = transaction->t_tid;
+	jfs_debug(1, "JFS: requesting commit %ld/%ld\n", 
+		  journal->j_commit_request,
+		  journal->j_commit_sequence);
+	wake_up(&journal->j_wait_commit);
+}
+
+/* Wait for a specified commit to complete. */
+void log_wait_commit (journal_t *journal, tid_t tid)
+{
+	while (((long) (journal->j_commit_sequence - tid)) < 0) {
+		wake_up(&journal->j_wait_commit);
+		sleep_on(&journal->j_wait_done_commit);
+	}
+}
+
+/* 
+ * Log buffer allocation routines: 
+ */
+
+unsigned long journal_next_log_block(journal_t *journal)
+{
+	unsigned long blocknr;
+
+	J_ASSERT(journal->j_free > 1);
+	
+	blocknr = journal->j_head;
+	journal->j_head++;
+	journal->j_free--;
+	if (journal->j_head == journal->j_last)
+		journal->j_head = journal->j_first;
+	
+	if (journal->j_inode) {
+		blocknr = bmap(journal->j_inode, blocknr);
+		J_ASSERT(blocknr != 0);
+	}
+	return blocknr;
+}
+
+/* 
+ * We play buffer_head aliasing tricks to write data/metadata blocks to
+ * the journal without copying their contents, but for journal
+ * descriptor blocks we do need to generate bona fide buffers.
+ */
+
+struct buffer_head * journal_get_descriptor_buffer(journal_t *journal)
+{
+	struct buffer_head *bh;
+	unsigned long blocknr = journal_next_log_block(journal);
+	bh = getblk(journal->j_dev, blocknr, journal->j_blocksize);
+	bh->b_state |= (1 << BH_Dirty);
+	J_ASSERT(bh != NULL);
+	return bh;
+}
+
+
+
+
+/*
+ * Management for journal control blocks: functions to create and
+ * destroy journal_t structures, and to initialise and read existing
+ * journal blocks from disk.  */
+
+/* First: create and setup a journal_t object in memory.  We initialise
+ * very few fields yet: that has to wait until we have created the
+ * journal structures from from scratch, or loaded them from disk. */
+
+static journal_t * journal_init_common (void)
+{
+	journal_t *journal;
+	
+	journal = kmalloc(sizeof(*journal), GFP_KERNEL);
+	if (!journal)
+		return 0;
+	memset(journal, 0, sizeof(*journal));
+
+	init_waitqueue(&journal->j_wait_lock);
+	init_waitqueue(&journal->j_wait_transaction_locked);
+	init_waitqueue(&journal->j_wait_logspace);
+	init_waitqueue(&journal->j_wait_done_commit);
+	init_waitqueue(&journal->j_wait_checkpoint);
+	init_waitqueue(&journal->j_wait_commit);
+	journal->j_checkpoint_sem = MUTEX;
+	return journal;
+}
+
+/* journal_init_dev and journal_init_inode:
+ *
+ * Create a journal structure assigned some fixed set of disk blocks to
+ * the journal.  We don't actually touch those disk blocks yet, but we
+ * need to set up all of the mapping information to tell the journaling
+ * system where the journal blocks are.
+ *
+ * journal_init_dev creates a journal which maps a fixed contiguous
+ * range of blocks on an arbitrary block device.
+ * 
+ * journal_init_inode creates a journal which maps an on-disk inode as
+ * the journal.  The inode must exist already, must support bmap() and
+ * must have all data blocks preallocated.  
+ */
+
+journal_t * journal_init_dev (kdev_t dev, int start, int len, int blocksize)
+{
+	journal_t *journal = journal_init_common();
+	struct buffer_head *bh;
+	
+	if (!journal)
+		return 0;
+	
+	journal->j_dev = dev;
+	journal->j_blk_offset = start;
+	journal->j_maxlen = len;
+	journal->j_blocksize = blocksize;
+	
+	bh = getblk(journal->j_dev, start, journal->j_blocksize);
+	J_ASSERT(bh != NULL);
+	journal->j_sb_buffer = bh;
+	journal->j_superblock = (journal_superblock_t *) bh->b_data;
+
+	return journal;
+}
+
+journal_t * journal_init_inode (struct inode *inode)
+{
+	struct buffer_head *bh;
+	journal_t *journal = journal_init_common();
+	int blocknr;
+	
+	if (!journal)
+		return 0;
+	
+	journal->j_dev = inode->i_dev;
+	journal->j_inode = inode;
+	jfs_debug(0, 
+		  "journal %p: inode %s/%ld, size %ld, bits %d, blksize %ld\n",
+		  journal,
+		  kdevname(inode->i_dev), inode->i_ino, inode->i_size, 
+		  inode->i_sb->s_blocksize_bits, inode->i_sb->s_blocksize);
+	
+	journal->j_maxlen = inode->i_size >> inode->i_sb->s_blocksize_bits;
+	journal->j_blocksize = inode->i_sb->s_blocksize;
+
+	blocknr = bmap(journal->j_inode, 0);
+	J_ASSERT(blocknr != 0);
+	bh = getblk(journal->j_dev, blocknr, journal->j_blocksize);
+	J_ASSERT(bh != NULL);
+	journal->j_sb_buffer = bh;
+	journal->j_superblock = (journal_superblock_t *) bh->b_data;
+
+	return journal;
+}
+
+/*
+ * Given a journal_t structure, initialise the various fields for
+ * startup of a new journaling session.  We use this both when creating
+ * a journal, and after recovering an old journal to reset it for
+ * subsequent use.  
+ */
+
+static int journal_reset (journal_t *journal)
+{
+	journal_superblock_t *sb = journal->j_superblock;
+	unsigned int first, last;
+	
+	first = ntohl(sb->s_first);
+	last = ntohl(sb->s_maxlen);
+
+	journal->j_first = first;
+	journal->j_last = last;
+	
+	journal->j_head = first;
+	journal->j_tail = first;
+	journal->j_free = last - first;
+	
+	journal->j_tail_sequence = journal->j_transaction_sequence;
+	journal->j_commit_sequence = journal->j_transaction_sequence - 1;
+	journal->j_commit_request = journal->j_commit_sequence;	
+
+	journal->j_max_transaction_buffers = journal->j_maxlen / 4;
+	journal->j_commit_interval = (HZ * 5);
+
+	/* Add the dynamic fields and write it to disk. */
+	journal_update_superblock(journal, 1);
+
+	lock_journal(journal);
+	journal_start_thread(journal);
+	unlock_journal(journal);
+
+	return 0;
+}
+
+/* 
+ * Given a journal_t structure which tells us which disk blocks we can
+ * use, create a new journal superblock and initialise all of the
+ * journal fields from scratch.  */
+
+int journal_create (journal_t *journal)
+{
+	int blocknr;
+	struct buffer_head *bh;
+	journal_superblock_t *sb;
+	int i;
+	
+	if (journal->j_maxlen < JFS_MIN_JOURNAL_BLOCKS) {
+		printk (KERN_ERR "Journal length (%d blocks) too short.\n",
+			journal->j_maxlen);
+		return -EINVAL;
+	}
+
+	/* Zero out the entire journal on disk.  We cannot afford to
+	   have any blocks on disk beginning with JFS_MAGIC_NUMBER. */
+	jfs_debug(1, "JFS: Zeroing out journal blocks...\n");
+	for (i = 1; i < journal->j_maxlen; i++) {
+		blocknr = i;
+		if (journal->j_inode) {
+			blocknr = bmap(journal->j_inode, blocknr);
+			if (blocknr == 0) {
+				printk (KERN_ERR 
+					"Error writing journal block %d\n", i);
+				return -EIO;
+			}
+		}
+		bh = getblk(journal->j_dev, blocknr, journal->j_blocksize);
+		memset (bh->b_data, 0, journal->j_blocksize);
+		mark_buffer_dirty(bh, 0);
+		brelse(bh);
+	}
+	sync_buffers(journal->j_dev, 1);
+	jfs_debug(1, "JFS: journal cleared.\n");
+	
+	/* OK, fill in the initial static fields in the new superblock */
+	sb = journal->j_superblock;
+
+	sb->s_header.h_magic	 = htonl(JFS_MAGIC_NUMBER);
+	sb->s_header.h_blocktype = htonl(JFS_SUPERBLOCK);
+	
+	sb->s_blocksize	= htonl(journal->j_blocksize);
+	sb->s_maxlen	= htonl(journal->j_maxlen);
+	sb->s_first	= htonl(1);
+
+	journal->j_transaction_sequence = 1;
+	
+	return journal_reset(journal);
+}
+
+/*
+ * Update a journal's dynamic superblock fields and write it to disk,
+ * optionally waiting for the IO to complete. 
+*/
+
+void journal_update_superblock(journal_t *journal, int wait)
+{
+	journal_superblock_t *sb = journal->j_superblock;
+	struct buffer_head *bh = journal->j_sb_buffer;
+	
+	sb->s_sequence = htonl(journal->j_tail_sequence);
+	sb->s_start    = htonl(journal->j_tail);
+	
+	mark_buffer_dirty(bh, 0);
+	ll_rw_block(WRITE, 1, &bh);
+	if (wait)
+		wait_on_buffer(bh);
+}
+	
+
+/*
+ * Given a journal_t structure which tells us which disk blocks contain
+ * a journal, read the journal from disk to initialise the in-memory
+ * structures.
+ */
+
+int journal_load (journal_t *journal)
+{
+	struct buffer_head *bh;
+	journal_superblock_t *sb;
+	unsigned long blocknr;
+	
+	blocknr = 0;
+	if (journal->j_inode) {
+		blocknr = bmap(journal->j_inode, blocknr);
+		J_ASSERT(blocknr != 0);
+	}
+
+	/* 
+	 * Read the superblock.  
+	 */
+
+	bh = journal->j_sb_buffer;
+	J_ASSERT(bh != NULL);
+	ll_rw_block(READ, 1, &bh);
+	wait_on_buffer(bh);
+	if (!bh) {
+		printk (KERN_ERR "JFS: IO error reading journal superblock\n");
+		return -EIO;
+	}
+
+	sb = journal->j_superblock;
+	
+	if (sb->s_header.h_magic != htonl(JFS_MAGIC_NUMBER) ||
+	    sb->s_header.h_blocktype != htonl(JFS_SUPERBLOCK) ||
+	    sb->s_blocksize != htonl(journal->j_blocksize)) {
+		printk (KERN_WARNING "JFS: no valid journal superblock found\n");
+		return -EINVAL;
+	}
+	
+	if (ntohl(sb->s_maxlen) < journal->j_maxlen)
+		journal->j_maxlen = ntohl(sb->s_maxlen);
+	else if (ntohl(sb->s_maxlen) > journal->j_maxlen) {
+		printk (KERN_WARNING "JFS: journal file too short\n");
+		return -EINVAL;
+	}
+	
+	journal->j_tail_sequence = ntohl(sb->s_sequence);
+	journal->j_tail = ntohl(sb->s_start);
+	journal->j_first = ntohl(sb->s_first);
+	journal->j_last = ntohl(sb->s_maxlen);
+
+	/* Let the recovery code check whether it needs to recover any
+	 * data from the journal. */
+	/* @@@ URGENT: Worry about error returns from recovery! */
+	journal_recover(journal);
+	
+	/* OK, we've finished with the dynamic journal bits:
+	 * reinitialise the dynamic contents of the superblock in memory
+	 * and reset them on disk. */
+	if (journal_reset(journal)) {
+		printk (KERN_WARNING "JFS: recovery failed\n");
+		return -EIO;
+	}
+
+	return 0;
+}
+
+/* 
+ * Release a journal_t structure once it is no longer in use by the
+ * journaled object.  
+ */
+
+void journal_release (journal_t *journal)
+{
+	/* Wait for the commit thread to wake up and die. */
+	journal_kill_thread(journal);
+
+	/* Force a final log commit */
+	if (journal->j_running_transaction)
+		journal_commit_transaction(journal);
+
+	/* Force any old transactions to disk */
+	lock_journal(journal);
+	while (journal->j_checkpoint_transactions != NULL)
+		log_do_checkpoint(journal, 1);
+
+	J_ASSERT(journal->j_running_transaction == NULL);	
+	J_ASSERT(journal->j_committing_transaction == NULL);
+	J_ASSERT(journal->j_checkpoint_transactions == NULL);
+
+	/* We can now mark the journal as empty. */
+	journal->j_tail = 0;
+	journal->j_tail_sequence = ++journal->j_transaction_sequence;
+	journal_update_superblock(journal, 1);
+
+	if (journal->j_inode)
+		iput(journal->j_inode);
+
+	unlock_journal(journal);
+	brelse(journal->j_sb_buffer);
+	kfree(journal);
+}
+
+/* 
+ * Flush all data for a given journal to disk and empty the journal.
+ * Filesystems can use this when remounting readonly to ensure that
+ * recovery does not need to happen on remount.  
+ */
+
+int journal_flush (journal_t *journal)
+{
+	int err = 0;
+	transaction_t *transaction = NULL;
+	
+	/* Force everything buffered to the log... */
+	if (journal->j_running_transaction) {
+		transaction = journal->j_running_transaction;
+		log_start_commit(journal, transaction);
+	} else if (journal->j_committing_transaction)
+		transaction = journal->j_committing_transaction;
+
+	/* Wait for the log commit to complete... */
+	if (transaction)
+		log_wait_commit(journal, transaction->t_tid);
+	
+	/* ...and flush everything in the log out to disk. */
+	lock_journal(journal);
+	while (!err && journal->j_checkpoint_transactions != NULL)
+		err = log_do_checkpoint(journal, journal->j_maxlen);
+	unlock_journal(journal);
+	
+	return err;
+}
Index: oldkernel/linux/fs/jfs/recovery.c
diff -u /dev/null linux/fs/jfs/recovery.c:1.1
--- /dev/null	Mon Jul 31 21:15:08 2000
+++ linux/fs/jfs/recovery.c	Fri Jul  7 16:34:57 2000
@@ -0,0 +1,415 @@
+/*
+ * linux/fs/recovery.c
+ * 
+ * Written by Stephen C. Tweedie <sct@redhat.com>, 1999
+ *
+ * Copyright 1999 Red Hat Software --- All Rights Reserved
+ *
+ * This file is part of the Linux kernel and is made available under
+ * the terms of the GNU General Public License, version 2, or at your
+ * option, any later version, incorporated herein by reference.
+ *
+ * Journal recovery routines for the generic filesystem journaling code;
+ * part of the ext2fs journaling system.  
+ */
+
+#include <linux/sched.h>
+#include <linux/fs.h>
+#include <linux/jfs.h>
+#include <linux/errno.h>
+#include <linux/malloc.h>
+#include <linux/locks.h>
+#include <linux/buffer.h>
+
+
+/* Release readahead buffers after use */
+static void brelse_array(struct buffer_head *b[], int n)
+{
+	while (--n >= 0)
+		brelse (b[n]);
+}
+
+
+/*
+ * When reading from the journal, we are going through the block device
+ * layer directly and so there is no readahead being done for us.  We
+ * need to implement any readahead ourselves if we want it to happen at
+ * all.  Recovery is basically one long sequential read, so make sure we
+ * do the IO in reasonably large chunks.
+ *
+ * This is not so critical that we need to be enormously clever about
+ * the readahead size, though.  128K is a purely arbitrary, good-enough
+ * fixed value.
+ */
+
+static int do_readahead(journal_t *journal, unsigned int start)
+{
+	int err;
+	unsigned int max, nbufs, next, blocknr;
+	struct buffer_head *bh;
+	
+	#define MAXBUF 8
+	struct buffer_head * bufs[MAXBUF];
+	
+	/* Do up to 128K of readahead */
+	max = start + (128 * 1024 / journal->j_blocksize);
+	if (max > journal->j_maxlen)
+		max = journal->j_maxlen;
+
+	/* Do the readahead itself.  We'll submit MAXBUF buffer_heads at
+	 * a time to the block device IO layer. */
+	
+	nbufs = 0;
+	
+	for (next = start; next < max; next++) {
+		blocknr = next;
+		if (journal->j_inode)
+			blocknr = bmap(journal->j_inode, next);
+		if (!blocknr) {
+			printk (KERN_ERR "JFS: bad block at offset %u\n",
+				next);
+			err = -EIO;
+			goto failed;
+		}
+		
+		bh = getblk(journal->j_dev, blocknr, journal->j_blocksize);
+		if (!bh) {
+			err = -ENOMEM;
+			goto failed;
+		}
+
+		if (!buffer_uptodate(bh) && !buffer_locked(bh)) {
+			bufs[nbufs++] = bh;
+			if (nbufs == MAXBUF) {
+				ll_rw_block(READ, nbufs, bufs);
+				brelse_array(bufs, nbufs);
+				nbufs = 0;
+			}
+		} else
+			brelse(bh);
+	}
+
+	if (nbufs)
+		ll_rw_block(READ, nbufs, bufs);
+	err = 0;
+	
+failed:	
+	if (nbufs) 
+		brelse_array(bufs, nbufs);
+	return err;
+}
+
+/*
+ * Read a block from the journal
+ */
+
+static int jread(struct buffer_head **bhp, journal_t *journal, 
+		 unsigned int offset)
+{
+	unsigned int blocknr;
+	struct buffer_head *bh;
+
+	*bhp = NULL;
+
+	J_ASSERT (offset < journal->j_maxlen);
+			
+	blocknr = offset;
+	if (journal->j_inode)
+		blocknr = bmap(journal->j_inode, offset);
+	
+	if (!blocknr) {
+		printk (KERN_ERR "JFS: bad block at offset %u\n",
+			offset);
+		return -EIO;
+	}
+	
+	bh = getblk(journal->j_dev, blocknr, journal->j_blocksize);
+	if (!bh)
+		return -ENOMEM;
+	
+	if (!buffer_uptodate(bh)) {
+		/* If this is a brand new buffer, start readahead.
+                   Otherwise, we assume we are already reading it.  */
+		if (!buffer_req(bh))
+			do_readahead(journal, offset);
+		wait_on_buffer(bh);
+	}
+	
+	if (!buffer_uptodate(bh)) {
+		printk (KERN_ERR "JFS: Failed to read block at offset %u\n",
+			offset);
+		brelse(bh);
+		return -EIO;
+	}
+		
+	*bhp = bh;
+	return 0;
+}
+
+
+/*
+ * Count the number of in-use tags in a journal descriptor block.
+ */
+
+int count_tags(struct buffer_head *bh, int size)
+{
+	char *			tagp;
+	journal_block_tag_t *	tag;
+	int			nr = 0;
+	
+	tagp = &bh->b_data[sizeof(journal_header_t)];
+	
+	while ((tagp - bh->b_data + sizeof(journal_block_tag_t)) <= size) {
+		tag = (journal_block_tag_t *) tagp;
+		
+		nr++;
+		tagp += sizeof(journal_block_tag_t);
+		if (!(tag->t_flags & htonl(JFS_FLAG_SAME_UUID)))
+			tagp += 16;
+
+		if (tag->t_flags & htonl(JFS_FLAG_LAST_TAG))
+			break;
+	}
+	
+	return nr;
+}
+
+
+/* Make sure we wrap around the log correctly! */
+#define wrap(journal, var)						\
+do {									\
+	if (var >= (journal)->j_last)					\
+		var -= ((journal)->j_last - (journal)->j_first);	\
+} while (0)
+
+/*
+ * journal_recover
+ *
+ * The primary function for recovering the log contents when mounting a
+ * journaled device.  
+ */
+
+int journal_recover(journal_t *journal)
+{
+	unsigned int		first_commit_ID, next_commit_ID;
+	unsigned long		next_log_block;
+	unsigned long		transaction_start;
+	int			err, success = 0;
+	journal_superblock_t *	sb;
+	journal_header_t * 	tmp;
+	struct buffer_head *	bh;
+
+	/* Precompute the maximum metadata descriptors in a descriptor block */
+	int			MAX_BLOCKS_PER_DESC;
+	MAX_BLOCKS_PER_DESC = ((journal->j_blocksize-sizeof(journal_header_t))
+			       / sizeof(journal_block_tag_t));
+
+	/* 
+	 * First thing is to establish what we expect to find in the log
+	 * (in terms of transaction IDs), and where (in terms of log
+	 * block offsets): query the superblock.  
+	 */
+
+	sb = journal->j_superblock;
+	next_commit_ID = ntohl(sb->s_sequence);
+	next_log_block = ntohl(sb->s_start);
+
+	first_commit_ID = next_commit_ID;
+	
+	/* 
+	 * The journal superblock's s_start field (the current log head)
+	 * is always zero if, and only if, the journal was cleanly
+	 * unmounted.  
+	 */
+
+	if (!sb->s_start) {
+		jfs_debug(1, "No recovery required, last transaction %ld\n",
+			  ntohl(sb->s_sequence));
+		journal->j_transaction_sequence = ++next_commit_ID;
+		return 0;
+	}
+	
+	jfs_debug(1, "Starting recovery\n");
+	
+	/*
+	 * Now we walk through the log, transaction by transaction,
+	 * making sure that each transaction has a commit block in the
+	 * expected place.  Each complete transaction gets replayed back
+	 * into the main filesystem. 
+	 */
+
+	while (1) { 
+		jfs_debug(2, "Looking for commit ID %u at %lu/%lu\n",
+			  next_commit_ID, next_log_block, journal->j_last);
+ 		transaction_start = next_log_block;
+
+		while (next_log_block < journal->j_last) {
+			/* Skip over each chunk of the transaction
+			 * looking either the next descriptor block or
+			 * the final commit record. */
+
+			jfs_debug(3, "JFS: checking block %ld\n", 
+				  next_log_block);
+			err = jread(&bh, journal, next_log_block);
+			if (err)
+				goto failed;
+			
+			/* What kind of buffer is it? 
+			 * 
+			 * If it is a descriptor block, work out the
+			 * expected location of the next and skip to it.
+			 *
+			 * If it is the right commit block, end the
+			 * search and start recovering the transaction.
+			 *
+			 * Any non-control block, or an unexpected
+			 * control block is interpreted as old data from
+			 * a previous wrap of the log: stop recovery at
+			 * this point.  
+			 */
+		
+			tmp = (journal_header_t *) bh->b_data;
+			
+			if (tmp->h_magic == htonl(JFS_MAGIC_NUMBER)) {
+				int blocktype = ntohl(tmp->h_blocktype);
+				jfs_debug(3, "Found magic %d\n", blocktype);
+				
+				if (blocktype == JFS_DESCRIPTOR_BLOCK) {
+					/* Work out where the next descriptor
+					 * should be. */
+					next_log_block++;
+					next_log_block += count_tags(bh, journal->j_blocksize);
+					wrap(journal, next_log_block);
+					brelse(bh);
+					continue;
+				} else if (blocktype == JFS_COMMIT_BLOCK) {
+					unsigned int sequence = tmp->h_sequence;
+					brelse(bh);
+					if (sequence == htonl(next_commit_ID))
+						goto commit;
+					jfs_debug(2, "found sequence %ld, expected %d.\n", ntohl(sequence), next_commit_ID);
+					goto finished;
+				}
+			}
+
+			/* We didn't recognise it?  OK, we've gone off
+			 * the tail of the log in that case. */
+			brelse(bh);
+			break;
+		}
+
+		goto finished;
+		
+	commit:
+		jfs_debug(2, "Found transaction %d\n", next_commit_ID);
+
+		/* OK, we have a transaction to commit.  Rewind to the
+		 * start of it, gather up all of the buffers in each
+		 * transaction segment, and replay the segments one by
+		 * one. */
+
+		next_log_block = transaction_start;
+		
+		while (1) {
+			int			flags;
+			char *			tagp;
+			journal_block_tag_t *	tag;
+			struct buffer_head *	obh;
+			struct buffer_head *	nbh;
+			
+			err = jread(&bh, journal, next_log_block++);
+			wrap(journal, next_log_block);
+			if (err)
+				goto failed;
+			
+			tmp = (journal_header_t *) bh->b_data;
+			J_ASSERT(tmp->h_magic == htonl(JFS_MAGIC_NUMBER));
+			
+			/* If it is the commit block, then we are all done! */
+
+			if (tmp->h_blocktype == htonl(JFS_COMMIT_BLOCK))
+				break;
+			
+			/* A descriptor block: we can now write all of
+			 * the data blocks.  Yay, useful work is finally
+			 * getting done here! */
+
+			tagp = &bh->b_data[sizeof(journal_header_t)];
+			
+			while ((tagp - bh->b_data +sizeof(journal_block_tag_t))
+			       <= journal->j_blocksize) {
+				tag = (journal_block_tag_t *) tagp;
+				flags = ntohl(tag->t_flags);
+				
+				err = jread(&obh, journal, next_log_block++);
+				wrap(journal, next_log_block);
+				if (err) {
+					/* Recover what we can, but
+					 * report failure at the end. */
+					success = -EIO;
+					printk (KERN_ERR 
+						"JFS: IO error recovering "
+						"block %ld in log\n",
+						next_log_block-1);
+				} else {
+					J_ASSERT(obh != NULL);
+
+					/* And find a buffer for the new data
+					 * being restored */
+					nbh = getblk(journal->j_dev, 
+						     ntohl(tag->t_blocknr),
+						     journal->j_blocksize);
+					if (nbh == NULL) {
+						printk(KERN_ERR 
+						       "JFS: Out of memory "
+						       "during recovery.\n");
+						err = -ENOMEM;
+						brelse(bh);
+						brelse(obh);
+						goto failed;
+					}
+
+					memcpy(nbh->b_data, obh->b_data, 
+					       journal->j_blocksize);
+					if (flags & JFS_FLAG_ESCAPE) {
+						* ((unsigned int *) bh->b_data) = htonl(JFS_MAGIC_NUMBER);
+					}
+					
+					mark_buffer_dirty(nbh, 1);
+					ll_rw_block(WRITE, 1, &nbh);
+					brelse(obh);
+					brelse(nbh);
+				}
+				
+				tagp += sizeof(journal_block_tag_t);
+				if (!(flags & JFS_FLAG_SAME_UUID))
+					tagp += 16;
+
+				if (flags & JFS_FLAG_LAST_TAG)
+					break;
+
+			} /* end of tag loop */
+			
+		} /* end of descriptor block loop */
+		brelse(bh);
+		
+		/* We have now replayed that entire transaction: start
+		 * looking for the next transaction. */
+		next_commit_ID++;
+	}
+		
+ finished:
+	err = success;
+	fsync_dev(journal->j_dev);
+
+ failed:
+	
+	/* Restart the log at the next transaction ID, thus invalidating
+	 * any existing commit records in the log. */
+	jfs_debug(0, "JFS: recovery, exit status %d, "
+		  "recovered transactions %u to %u\n", 
+		  err, first_commit_ID, next_commit_ID);
+	journal->j_transaction_sequence = ++next_commit_ID;
+
+	return err;
+}
Index: oldkernel/linux/fs/jfs/transaction.c
diff -u /dev/null linux/fs/jfs/transaction.c:1.1
--- /dev/null	Mon Jul 31 21:15:08 2000
+++ linux/fs/jfs/transaction.c	Fri Jul  7 16:34:57 2000
@@ -0,0 +1,1021 @@
+/*
+ * linux/fs/transaction.c
+ * 
+ * Written by Stephen C. Tweedie <sct@redhat.com>, 1998
+ *
+ * Copyright 1998 Red Hat corp --- All Rights Reserved
+ *
+ * This file is part of the Linux kernel and is made available under
+ * the terms of the GNU General Public License, version 2, or at your
+ * option, any later version, incorporated herein by reference.
+ *
+ * Generic filesystem transaction handling code; part of the ext2fs
+ * journaling system.  
+ *
+ * This file manages transactions (compound commits managed by the
+ * journaling code) and handles (individual atomic operations by the
+ * filesystem).
+ */
+
+#include <linux/sched.h>
+#include <linux/fs.h>
+#include <linux/jfs.h>
+#include <linux/errno.h>
+#include <linux/malloc.h>
+#include <linux/locks.h>
+#include <linux/timer.h>
+
+
+/* 
+ * Forward declarations for internal use by this file only.
+ */
+
+static inline void 
+blist_add_buffer(struct buffer_head **, struct buffer_head *);
+static inline void
+blist_del_buffer(struct buffer_head **, struct buffer_head *);
+
+
+/*
+ * Journal locking.
+ *
+ * We need to lock the journal during transaction state changes so that
+ * nobody ever tries to take a handle on the running transaction while
+ * we are in the middle of moving it to the commit phase.  
+ *
+ * Note that the locking is completely interrupt unsafe.  We never touch
+ * journal structures from interrupts.
+ */
+
+void __wait_on_journal (journal_t * journal)
+{
+	while (journal->j_locked)
+		sleep_on (&journal->j_wait_lock);
+}
+
+
+/*
+ * get_transaction: obtain a new transaction_t object.
+ *
+ * Simply allocate and initialise a new transaction.  Create it in
+ * RUNNING state and add it to the current journal (which should not
+ * have an existing running transaction: we only make a new transaction
+ * once we have started to commit the old one).
+ *
+ * Preconditions:
+ *	The journal MUST be locked.  We don't perform atomic mallocs on the
+ *	new transaction	and we can't block without protecting against other
+ *	processes trying to touch the journal while it is in transition.
+ */
+
+transaction_t * get_transaction (journal_t * journal)
+{
+	transaction_t * transaction;
+
+	J_ASSERT (journal->j_locked);
+	
+	transaction = kmalloc (sizeof (transaction_t), GFP_KERNEL);
+	if (!transaction)
+		return NULL;
+	
+	memset (transaction, 0, sizeof (transaction_t));
+	
+	transaction->t_journal = journal;
+	transaction->t_state = T_RUNNING;
+	transaction->t_tid = journal->j_transaction_sequence++;
+	transaction->t_expires = jiffies + journal->j_commit_interval;
+
+	/* Set up the commit timer for the new transaction. */
+	J_ASSERT (!journal->j_commit_timer_active);
+	journal->j_commit_timer_active = 1;
+	journal->j_commit_timer->expires = transaction->t_expires;
+	add_timer(journal->j_commit_timer);
+	
+	J_ASSERT (journal->j_running_transaction == NULL);
+	journal->j_running_transaction = transaction;
+
+	return transaction;
+}
+
+
+
+/*
+ * Handle management.
+ *
+ * A handle_t is an object which represents a single atomic update to a
+ * filesystem, and which tracks all of the modifications which form part
+ * of that one update.
+ */
+
+/*
+ * start_this_handle: Given a handle, deal with any locking or stalling
+ * needed to make sure that there is enough journal space for the handle
+ * to begin.  Attach the handle to a transaction and set up the
+ * transaction's buffer credits.  
+ */
+
+static int start_this_handle(journal_t *journal, handle_t *handle)
+{
+	transaction_t *transaction;
+	int needed;
+	int nblocks = handle->h_buffer_credits;
+	
+	jfs_debug(4, "New handle %p going live.\n", handle);
+
+repeat:
+
+	lock_journal(journal);
+
+repeat_locked:
+	if (!journal->j_running_transaction)
+		get_transaction(journal);
+	/* @@@ Error? */
+	J_ASSERT(journal->j_running_transaction);
+	
+	transaction = journal->j_running_transaction;
+
+	/* If the current transaction is locked down for commit, wait
+	 * for the lock to be released. */
+
+	if (transaction->t_state == T_LOCKED) {
+		unlock_journal(journal);
+		jfs_debug(3, "Handle %p stalling...\n", handle);
+		sleep_on(&journal->j_wait_transaction_locked);
+		goto repeat;
+	}
+	
+	/* If there is not enough space left in the log to write all
+	 * potential buffers requested by this operation, we need to
+	 * stall pending a log checkpoint to free some more log
+	 * space. */
+
+	needed = transaction->t_outstanding_credits + nblocks;
+
+	if (needed > journal->j_max_transaction_buffers) {
+		tid_t tid = transaction->t_tid;
+
+		/* If the current transaction is already too large, then
+		 * start to commit it: we can then go back and attach
+		 * this handle to a new transaction. */
+
+		jfs_debug(2, "Handle %p starting new commit...\n", handle);
+		log_start_commit(journal, transaction);
+
+		while ((long)(journal->j_commit_sequence - tid) < 0) {
+			unlock_journal(journal);
+			sleep_on(&journal->j_wait_done_commit);
+			lock_journal(journal);
+		}
+		goto repeat_locked;
+	}
+
+	/* 
+	 * The commit code assumes that it can get enough log space
+	 * without forcing a checkpoint.  This is *critical* for
+	 * correctness: a checkpoint of a buffer which is also
+	 * associated with a committing transaction creates a deadlock,
+	 * so commit simply cannot force through checkpoints.
+	 *
+	 * We must therefore ensure the necessary space in the journal
+	 * *before* starting to dirty potentially checkpointed buffers
+	 * in the new transaction. 
+	 *
+	 * The worst part is, any transaction currently committing can
+	 * reduce the free space arbitrarily.  Be careful to account for
+	 * those buffers when checkpointing.
+	 */
+
+	needed = journal->j_max_transaction_buffers;
+	if (journal->j_committing_transaction) 
+		needed += journal->j_committing_transaction->t_outstanding_credits;
+	
+	if (log_space_left(journal) < needed) {
+		jfs_debug(2, "Handle %p waiting for checkpoint...\n", handle);
+		log_wait_for_space(journal, needed);
+		goto repeat_locked;
+	}
+
+	/* OK, account for the buffers that this operation expects to
+	 * use and add the handle to the running transaction. */
+
+	handle->h_transaction = transaction;
+	transaction->t_outstanding_credits += nblocks;
+	transaction->t_updates++;
+	jfs_debug(4, "Handle %p given %d credits (total %d, free %d)\n",
+		  handle, nblocks, transaction->t_outstanding_credits,
+		  log_space_left(journal));
+
+	unlock_journal(journal);
+	
+	return 0;
+}
+
+
+/*
+ * Obtain a new handle.  
+ *
+ * We make sure that the transaction can guarantee at least nblocks of
+ * modified buffers in the log.  We block until the log can guarantee
+ * that much space.  
+ *
+ * This function is visible to journal users (like ext2fs), so is not
+ * called with the journal already locked.
+ *
+ * Return a pointer to a newly allocated handle, or NULL on failure
+ */
+
+handle_t *journal_start (journal_t *journal, int nblocks)
+{
+	handle_t *handle;
+	
+	if (!journal)
+		return NULL;
+	
+	if (current->j_handle) {
+		current->j_handle->h_ref++;
+		return current->j_handle;
+	}
+	
+	handle = kmalloc (sizeof (handle_t), GFP_KERNEL);
+	if (!handle)
+		return NULL;
+	memset (handle, 0, sizeof (handle_t));
+
+	handle->h_buffer_credits = nblocks;
+	handle->h_ref = 1;
+	current->j_handle = handle;
+
+	start_this_handle(journal, handle); /* @@@ Error? */
+	return handle;
+}
+
+
+/*
+ * journal_extend: extend buffer credits.
+ *
+ * Some transactions, such as large extends and truncates, can be done
+ * atomically all at once or in several stages.  The operation requests
+ * a credit for a number of buffer modications in advance, but can
+ * extend its credit if it needs more.  
+ *
+ * journal_extend tries to give the running handle more buffer credits.
+ * It does not guarantee that allocation: this is a best-effort only.
+ * The calling process MUST be able to deal cleanly with a failure to
+ * extend here.
+ *
+ * Return 0 on success, non-zero on failure.
+ */
+
+int journal_extend (handle_t *handle, int nblocks)
+{
+	transaction_t *transaction = handle->h_transaction;
+	journal_t *journal = transaction->t_journal;
+	int result = 1;
+	int wanted;
+	
+	lock_journal (journal);
+
+	/* Don't extend a locked-down transaction! */
+	if (handle->h_transaction->t_state != T_RUNNING) {
+		jfs_debug(3, "denied handle %p %d blocks: "
+			  "transaction not running\n", handle, nblocks);
+		goto error_out;
+	}
+	
+	wanted = transaction->t_outstanding_credits + nblocks;
+	
+	if (wanted > journal->j_max_transaction_buffers) {
+		jfs_debug(3, "denied handle %p %d blocks: "
+			  "transaction too large\n", handle, nblocks);
+		goto error_out;
+	}
+
+	if (wanted > log_space_left(journal)) {
+		jfs_debug(3, "denied handle %p %d blocks: "
+			  "insufficient log space\n", handle, nblocks);
+		goto error_out;
+	}
+	
+	handle->h_buffer_credits += nblocks;
+	transaction->t_outstanding_credits += nblocks;
+	result = 0;
+
+	jfs_debug(3, "extended handle %p by %d\n", handle, nblocks);
+	
+error_out:
+	unlock_journal (journal);
+	return result;
+}
+
+
+/*
+ * journal_restart: restart a handle for a multi-transaction filesystem
+ * operation.
+ *
+ * If the journal_extend() call above fails to grant new buffer credits
+ * to a running handle, a call to journal_restart will commit the
+ * handle's transaction so far and reattach the handle to a new
+ * transaction capabable of guaranteeing the requested number of
+ * credits.
+ */
+
+int journal_restart(handle_t *handle, int nblocks)
+{
+	transaction_t *transaction = handle->h_transaction;
+	journal_t *journal = transaction->t_journal;
+		
+	/* First unlink the handle from its current transaction, and
+	 * start the commit on that. */
+	
+	J_ASSERT (transaction->t_updates > 0);
+	J_ASSERT (current->j_handle == handle);
+
+	transaction->t_outstanding_credits -= handle->h_buffer_credits;
+	transaction->t_updates--;
+
+	if (!transaction->t_updates)
+		wake_up(&transaction->t_wait);
+
+	log_start_commit(journal, transaction);
+
+	handle->h_buffer_credits = nblocks;
+	return start_this_handle(journal, handle);
+}
+
+
+/*
+ * journal_get_write_access: notify intent to modify a buffer for metadata
+ * (not data) update.
+ *
+ * If the buffer is already part of the current transaction, then there
+ * is nothing we need to do.  If it is already part of a prior
+ * transaction which we are still committing to disk, then we need to
+ * make sure that we do not overwrite the old copy: we do copy-out to
+ * preserve the copy going to disk.  We also account the buffer against
+ * the handle's metadata buffer credits (unless the buffer is already
+ * part of the transaction, that is).
+ *
+ * Returns an error code or 0 on success.  */
+
+int journal_get_write_access (handle_t *handle, struct buffer_head *bh) 
+{
+	transaction_t *transaction = handle->h_transaction;
+	journal_t *journal = transaction->t_journal;
+	int error = 0;
+	
+	/* We do not want to get caught playing with fields which the
+	 * log thread also manipulates.  Make sure that the buffer
+	 * completes any outstanding IO before proceeding. */
+
+repeat:
+	wait_on_buffer(bh);
+	lock_journal(journal);
+	if (buffer_locked(bh)) {
+		unlock_journal(journal);
+		goto repeat;
+	}
+
+	/* @@@ Need to check for errors here at some point. */
+
+	J_ASSERT (buffer_uptodate(bh));
+	
+	/* The buffer is already part of this transaction if
+	 * b_transaction or b_next_transaction points to it. */
+
+	if (bh->b_transaction == transaction ||
+	    bh->b_next_transaction == transaction)
+		goto done;
+
+	/* If there is already a copy-out version of this buffer, then
+	 * we don't need to make another one. */
+
+	if (bh->b_frozen_data) {
+		J_ASSERT(bh->b_next_transaction == NULL);
+		bh->b_next_transaction = transaction;
+
+		J_ASSERT(handle->h_buffer_credits > 0);
+		handle->h_buffer_credits--;
+		goto done;
+	}
+	
+	/* Is there data here we need to preserve? */
+	
+	if (bh->b_transaction && bh->b_transaction != transaction) {
+		J_ASSERT (bh->b_next_transaction == NULL);
+		J_ASSERT (bh->b_transaction == journal->j_committing_transaction);
+		J_ASSERT (bh->b_list == BUF_JOURNAL);
+
+		/* There is one case we have to be very careful about.
+		 * If the committing transaction is currently writing
+		 * this buffer out to disk and has NOT made a copy-out,
+		 * then we cannot modify the buffer contents at all
+		 * right now.  The essence of copy-out is that it is the
+		 * extra copy, not the primary copy, which gets
+		 * journaled.  If the primary copy is already going to
+		 * disk then we cannot do copy-out here. */
+
+		if (bh->b_jlist == BJ_Shadow) {
+			unlock_journal(journal);
+			/* commit wakes up all shadow buffers after IO */
+			sleep_on(&bh->b_wait);
+			goto repeat;
+		}
+			
+		bh->b_next_transaction = transaction;
+
+		/* Only do the copy if the currently-owning transaction
+		 * still needs it.  If it is on the Forget list, the
+		 * committing transaction is past that stage.  The
+		 * buffer had better remain locked during the kmalloc,
+		 * but that should be true --- we hold the journal lock
+		 * still and the buffer is already on the BUF_JOURNAL
+		 * list so won't be flushed. */
+
+		if (bh->b_jlist != BJ_Forget) {
+			bh->b_frozen_data = kmalloc(bh->b_size, GFP_KERNEL);
+			if (!bh->b_frozen_data) {
+				error = -ENOMEM;
+				goto done;
+			}
+			memcpy (bh->b_frozen_data, bh->b_data, bh->b_size);
+		}
+	}
+
+	J_ASSERT(handle->h_buffer_credits > 0);
+	handle->h_buffer_credits--;
+	
+	/* Finally, if the buffer is not journaled right now, we need to
+	 * make sure it doesn't get written to disk before the caller
+	 * actually commits the new data. */
+
+	if (!bh->b_transaction) {
+		bh->b_transaction = transaction;
+		journal_file_buffer(bh, transaction, BJ_Reserved);
+	}
+	
+ done:
+	if (bh->b_list != BUF_JOURNAL)
+		refile_buffer(bh);
+	unlock_journal(journal);
+	return error;
+}
+
+
+/*
+ * When the user wants to journal a newly created buffer_head
+ * (ie. getblk() returned a new buffer and we are going to populate it
+ * manually rather than reading off disk), then we need to keep the
+ * buffer_head locked until it has been completely filled with new
+ * data.  In this case, we should be able to make the assertion that
+ * the bh is not already part of an existing transaction.  
+ * 
+ * The buffer should already be locked by the caller by this point.
+ * There is no lock ranking violation: it was a newly created,
+ * unlocked buffer beforehand. */
+
+int journal_get_create_access (handle_t *handle, struct buffer_head *bh) 
+{
+	transaction_t *transaction = handle->h_transaction;
+	journal_t *journal = transaction->t_journal;
+
+	J_ASSERT (buffer_locked(bh));
+	lock_journal(journal);
+
+	J_ASSERT(handle->h_buffer_credits > 0);
+	handle->h_buffer_credits--;
+	
+	bh->b_transaction = transaction;
+	journal_file_buffer(bh, transaction, BJ_Reserved);
+	refile_buffer(bh);
+	unlock_journal(journal);
+	return 0;
+}
+
+
+
+/*
+ * journal_get_undo_access: Notify intent to modify metadata with non-
+ * rewindable consequences
+ *
+ * Sometimes there is a need to distinguish between metadata which has
+ * been committed to disk and that which has not.  The ext2fs code uses
+ * this for freeing and allocating space: we have to make sure that we
+ * do not reuse freed space until the deallocation has been committed,
+ * since if we overwrote that space we would make the delete
+ * un-rewindable in case of a crash.
+ * 
+ * To deal with that, journal_get_undo_access requests write access to a
+ * buffer for parts of non-rewindable operations such as delete
+ * operations on the bitmaps.  The journaling code must keep a copy of
+` * the buffer's contents prior to the undo_access call until such time
+ * as we know that the buffer has definitely been committed to disk.
+ * 
+ * We never need to know which transaction the committed data is part
+ * of: buffers touched here are guaranteed to be dirtied later and so
+ * will be committed to a new transaction in due course, at which point
+ * we can discard the old committed data pointer.
+ *
+ * Returns error number or 0 on success.  
+ */
+
+int journal_get_undo_access (handle_t *handle, struct buffer_head *bh)
+{
+	/* If we already have a copy of the buffer's committed contents,
+	 * then just carry on. */
+
+	if (bh->b_committed_data)
+		goto done;
+
+	lock_journal(handle->h_transaction->t_journal);
+
+	/* Make sure it didn't change while we slept... */
+
+	if (!bh->b_committed_data) {
+
+		/* Copy out the current buffer contents into the
+		 * preserved, committed copy. */
+
+		bh->b_committed_data = kmalloc(bh->b_size, GFP_KERNEL);
+		if (!bh->b_committed_data)
+			return -ENOMEM;
+		memcpy (bh->b_committed_data, bh->b_data, bh->b_size);
+	}
+	
+	unlock_journal(handle->h_transaction->t_journal);
+	
+done:
+	return journal_get_write_access (handle, bh);
+}
+
+
+
+/* 
+ * journal_dirty_data: mark a buffer as containing dirty data which
+ * needs to be flushed before we can commit the current transaction.  
+ *
+ * The buffer is placed on the transaction's data list and is marked as
+ * belonging to the transaction.
+ * 
+ * Returns error number or 0 on success.  
+ */
+
+int journal_dirty_data (handle_t *handle, struct buffer_head *bh)
+{
+	journal_t *journal = handle->h_transaction->t_journal;
+	lock_journal(journal);
+
+	mark_buffer_dirty(bh, 0);
+	
+	/*
+	 * What if the buffer is already part of a running transaction?
+	 * 
+	 * There are two cases:
+	 * 1) It is part of the current running transaction.  Refile it,
+	 *    just in case we have allocated it as metadata, deallocated
+	 *    it, then reallocated it as data. 
+	 * 2) It is part of the previous, still-committing transaction.
+	 *    More tricky: given that journal_dirty_data is for newly 
+	 *    allocated data, the only time this should happen is if the
+	 *    space was allocated then freed by the previous transaction.
+	 *    In that case, it is legal to remove the buffer from that old
+	 *    transaction and move it onto the new transaction.
+	 */
+
+	if (bh->b_transaction) {
+		if (bh->b_transaction != handle->h_transaction) {
+			/* Case 2, we remove the buffer from its
+			 * current transaction. */
+			journal_unfile_buffer(bh);
+			bh->b_transaction = 0;
+		}
+	}
+
+	journal_file_buffer(bh, handle->h_transaction, BJ_Data);
+	unlock_journal(journal);
+	return 0;
+}
+
+
+/* 
+ * journal_dirty_metadata: mark a buffer as containing dirty metadata
+ * which needs to be journaled as part of the current transaction.
+ *
+ * The buffer is placed on the transaction's metadata list and is marked
+ * as belonging to the transaction.  
+ *
+ * Special care needs to be taken if the buffer already belongs to the
+ * current committing transaction (in which case we should have frozen
+ * data present for that commit).  In that case, we don't relink the
+ * buffer: that only gets done when the old transaction finally
+ * completes its commit.
+ * 
+ * Returns error number or 0 on success.  
+ */
+
+int journal_dirty_metadata (handle_t *handle, struct buffer_head *bh)
+{
+	transaction_t *transaction = handle->h_transaction;
+	journal_t *journal = transaction->t_journal;
+	lock_journal(journal);
+
+	mark_buffer_dirty(bh, 0);
+
+	J_ASSERT(bh->b_transaction != NULL);
+	
+	/* 
+	 * Metadata already on the current transaction list doesn't
+	 * need to be filed.  Metadata on another transaction's list must
+	 * be committing, and will be refiled once the commit completes:
+	 * leave it alone for now. 
+	 */
+
+	if (bh->b_transaction != transaction) {
+		J_ASSERT (bh->b_transaction == journal->j_committing_transaction);
+		J_ASSERT (bh->b_next_transaction == transaction);
+		/* And this case is illegal: we can't reuse another
+		 * transaction's data buffer, ever. */
+		J_ASSERT (bh->b_jlist != BJ_Data);
+		goto done;
+	}
+	
+	/* That test should have eliminated the following case: */
+	J_ASSERT (bh->b_frozen_data == 0);
+
+	journal_file_buffer (bh, handle->h_transaction, BJ_Metadata);
+
+ done:
+	unlock_journal(journal);
+	return 0;
+}
+
+
+/* 
+ * journal_release_buffer: undo a get_write_access without any buffer
+ * updates, if the transaction decided in the end that it didn't need
+ * access.
+ *
+ * journal_get_write_access() can block, so it is quite possible for a
+ * journaling component to decide after the write access is returned
+ * that global state has changed and the update is no longer required.  
+ */
+
+void journal_release_buffer (handle_t *handle, struct buffer_head *bh)
+{
+	transaction_t *transaction = handle->h_transaction;
+	journal_t *journal = transaction->t_journal;
+	lock_journal(journal);
+
+	/* If the buffer is reserved but not modified by this
+	 * transaction, then it is safe to release it.  In all other
+	 * cases, just leave the buffer as it is. */
+
+	if (bh->b_jlist == BJ_Reserved && bh->b_transaction == transaction) {
+		handle->h_buffer_credits++;
+		journal_refile_buffer(bh);
+	}
+	
+	unlock_journal(journal);
+}
+
+
+/* 
+ * journal_forget: bforget() for potentially-journaled buffers.  We can
+ * only do the bforget if there are no commits pending against the
+ * buffer.  If the buffer is dirty in the current running transaction we
+ * can safely unlink it.  */
+
+void journal_forget (handle_t *handle, struct buffer_head *bh)
+{
+	journal_t * journal = handle->h_transaction->t_journal;
+
+	/* If we can't lock the journal because somebody else already
+	 * has the lock, then just release the buffer: that's better
+	 * than changing the semantics of bforget() to include a possible
+	 * context switch. */
+	if (try_lock_journal(journal))
+		goto nolock;
+	
+	if (bh->b_transaction == handle->h_transaction) {
+		/* If we are forgetting a buffer which is already part
+		 * of this transaction, then we can just drop it from
+		 * the transaction immediately. */
+		journal_unfile_buffer(bh);
+		bh->b_transaction = 0;
+	} else if (bh->b_transaction) {
+		/* However, if the buffer is still owned by a prior
+		 * (committing) transaction, we can't do anything with
+		 * it right now. */
+		unlock_journal(journal);
+		brelse(bh);
+		return;
+	}
+
+	J_ASSERT(!bh->b_frozen_data);
+	J_ASSERT(!bh->b_committed_data);
+
+	unlock_journal(journal);
+
+	/* @@@ DEBUG ONLY.  Eventually we will indeed want to be able to
+	 * discard forgotten buffers a bit more intelligently. */
+
+ nolock:
+	brelse(bh);
+	return;
+	
+	/* Now we know that the buffer isn't being committed anywhere,
+	 * but it might still be on a transaction's checkpoint list.  If
+	 * so, we want to place it on the new transaction's forget list:
+	 * on commit it will undo the old checkpoint.  Remember, we have
+	 * to be able to unwind the forget() if we take a crash before
+	 * the commit! */
+	
+	if (bh->b_cp_transaction) {
+		journal_file_buffer(bh, handle->h_transaction, BJ_Forget);
+		bh->b_transaction = handle->h_transaction;
+		brelse(bh);
+	} else
+		__bforget(bh);	
+}
+
+
+/*
+ * journal_sync_buffer: flush a potentially-journaled buffer to disk.
+ *
+ * Used for O_SYNC filesystem operations.  If the buffer is journaled,
+ * we need to complete the O_SYNC by waiting for the transaction to
+ * complete.  It is an error to call journal_sync_buffer before
+ * journal_stop!
+ */
+
+void journal_sync_buffer(struct buffer_head *bh)
+{
+	transaction_t *transaction;
+	journal_t *journal;
+	long sequence;
+	
+	/* If the buffer isn't journaled, this is easy: just sync it to
+	 * disk.  */
+
+	if (bh->b_transaction == NULL) {
+		/* If the buffer has already been journaled, then this
+		 * is a noop. */
+		if (bh->b_cp_transaction == NULL) 
+			return;
+		ll_rw_block (WRITE, 1, &bh);
+		wait_on_buffer (bh);
+		return;
+	}
+	
+	/* Otherwise, just wait until the transaction is synced to disk. */
+	transaction = bh->b_transaction;
+	journal = transaction->t_journal;
+	sequence = transaction->t_tid;
+	
+	log_start_commit (journal, transaction);
+	
+	while (((long) (journal->j_commit_sequence - sequence)) < 0) {
+		wake_up(&journal->j_wait_done_commit);
+		sleep_on(&journal->j_wait_done_commit);
+	}
+}
+
+
+
+/*
+ * All done for a particular handle.
+ *
+ * There is not much action needed here.  We just return any remaining
+ * buffer credits to the transaction and remove the handle.  The only
+ * complication is that we need to start a commit operation if the
+ * filesystem is marked for synchronous update.
+ */
+
+int journal_stop (handle_t *handle)
+{
+	transaction_t *transaction = handle->h_transaction;
+	journal_t *journal = transaction->t_journal;
+	int force_sync;
+	
+	if (!handle)
+		return 0;
+	
+	J_ASSERT (transaction->t_updates > 0);
+	J_ASSERT (current->j_handle == handle);
+	
+	if (--handle->h_ref > 0)
+		return 0;
+
+	jfs_debug(4, "Handle %p going down\n", handle);
+	
+	current->j_handle = NULL;
+	transaction->t_outstanding_credits -= handle->h_buffer_credits;
+	transaction->t_updates--;
+	if (!transaction->t_updates)
+		wake_up(&transaction->t_wait);
+
+	/* 
+	 * If the journal is marked SYNC, we need to set another commit
+	 * going!  We also want to force a commit if the current
+	 * transaction is occupying too much of the log, or if the
+	 * transaction is too old now.
+	 */
+
+	force_sync = (journal->j_flags & JFS_SYNC) || handle->h_sync;
+	
+	if (force_sync ||
+	    transaction->t_outstanding_credits > journal->j_max_transaction_buffers ||
+	    time_after_eq(jiffies, transaction->t_expires)) {
+		tid_t tid = transaction->t_tid;
+		
+		log_start_commit(journal, transaction);
+		
+		/*
+		 * Special case: JFS_SYNC synchronous updates require us
+		 * to wait for the commit to complete.  
+		 */
+		if (force_sync) 
+			log_wait_commit(journal, tid);
+	}
+	
+	kfree(handle);
+	
+	return 0;
+}
+
+
+
+/*
+ *
+ * List management code snippets: various functions for manipulating the
+ * transaction buffer lists.
+ *
+ */
+
+/*
+ * Add a buffer to a transaction list, given the transaction's list head
+ * pointer
+ */
+
+static inline void 
+blist_add_buffer(struct buffer_head **list, struct buffer_head *buf)
+{
+	if (!*list) {
+		buf->b_tnext = buf->b_tprev = buf;
+		*list = buf;
+	} else {
+		/* Insert at the tail of the list to preserve order */
+		struct buffer_head *first = *list, *last = first->b_tprev;
+		buf->b_tprev = last;
+		buf->b_tnext = first;
+		last->b_tnext = first->b_tprev = buf;
+	}
+}
+
+/* 
+ * Remove a buffer from a transaction list, given the transaction's list
+ * head pointer
+ */
+
+static inline void
+blist_del_buffer(struct buffer_head **list, struct buffer_head *buf)
+{
+	if (*list == buf) {
+		*list = buf->b_tnext;
+		if (*list == buf)
+			*list = 0;
+	}
+	buf->b_tprev->b_tnext = buf->b_tnext;
+	buf->b_tnext->b_tprev = buf->b_tprev;
+}
+
+/* 
+ * Remove a buffer from the appropriate transaction list. 
+ */
+
+void journal_unfile_buffer(struct buffer_head *buf)
+{
+	struct buffer_head **list = 0;
+	transaction_t * transaction;
+	
+	J_ASSERT (buf->b_jlist < BJ_Types);
+	
+	transaction = buf->b_transaction;
+	if (buf->b_jlist != BJ_None)
+		J_ASSERT (transaction != 0);
+	
+	switch (buf->b_jlist) {
+	case BJ_None:
+		return;
+	case BJ_Data:
+		list = &transaction->t_datalist;
+		break;
+	case BJ_Metadata:
+		transaction->t_nr_buffers--;
+		J_ASSERT(transaction->t_nr_buffers >= 0);
+		list = &transaction->t_buffers;
+		break;
+	case BJ_Forget:
+		list = &transaction->t_forget;
+		break;
+	case BJ_IO:
+		list = &transaction->t_iobuf_list;
+		break;
+	case BJ_Shadow:
+		list = &transaction->t_shadow_list;
+		break;
+	case BJ_LogCtl:
+		list = &transaction->t_log_list;
+		break;
+	case BJ_Reserved:
+		list = &transaction->t_reserved_list;
+		break;
+	}
+	
+	blist_del_buffer(list, buf);
+	buf->b_jlist = BJ_None;
+}
+
+
+/* 
+ * File a buffer on the given transaction list. 
+ */
+
+void journal_file_buffer(struct buffer_head *buf, 
+			 transaction_t *transaction, 
+			 int jlist)
+{
+	struct buffer_head **list = 0;
+	
+	J_ASSERT (buf->b_jlist < BJ_Types);
+	J_ASSERT (buf->b_transaction == transaction || buf->b_transaction ==0);
+
+	if (buf->b_transaction) {
+		if (buf->b_jlist == jlist)
+			return;
+		journal_unfile_buffer(buf);
+	} else
+		buf->b_transaction = transaction;
+
+	switch (jlist) {
+	case BJ_None:
+		return;
+	case BJ_Data:
+		list = &transaction->t_datalist;
+		break;
+	case BJ_Metadata:
+		transaction->t_nr_buffers++;
+		list = &transaction->t_buffers;
+		break;
+	case BJ_Forget:
+		list = &transaction->t_forget;
+		break;
+	case BJ_IO:
+		list = &transaction->t_iobuf_list;
+		break;
+	case BJ_Shadow:
+		list = &transaction->t_shadow_list;
+		break;
+	case BJ_LogCtl:
+		list = &transaction->t_log_list;
+		break;
+	case BJ_Reserved:
+		list = &transaction->t_reserved_list;
+		break;
+	}
+	
+	blist_add_buffer(list, buf);
+	buf->b_jlist = jlist;
+}
+
+
+/* 
+ * Remove a buffer from its current buffer list in preparation for
+ * dropping it from its current transaction entirely.  If the buffer has
+ * already started to be used by a subsequent transaction, refile the
+ * buffer on that transaction's metadata list.
+ */
+
+void journal_refile_buffer(struct buffer_head *bh)
+{
+	journal_unfile_buffer(bh);
+
+	/* If the buffer is now unused, just drop it.  If it has been
+	   modified by a later transaction, add it to the new
+	   transaction's metadata list. */
+
+	bh->b_transaction = bh->b_next_transaction;
+	bh->b_next_transaction = NULL;
+	
+	if (bh->b_transaction != NULL) {
+		int tstate;
+		journal_file_buffer(bh, bh->b_transaction, BJ_Metadata);
+		tstate = bh->b_transaction->t_state;
+		J_ASSERT(tstate == T_RUNNING);
+	}
+		
+	/* If necessary, remove it from the global journaled
+	   buffer list and replace it back on the main dirty
+	   buffer list. */
+	refile_buffer(bh);
+}
+
Index: oldkernel/linux/fs/lockd/Makefile
diff -u linux/fs/lockd/Makefile:1.1.1.1 linux/fs/lockd/Makefile:1.2
--- linux/fs/lockd/Makefile:1.1.1.1	Wed May 31 12:33:48 2000
+++ linux/fs/lockd/Makefile	Fri Jul  7 15:36:45 2000
@@ -9,7 +9,12 @@
 
 O_TARGET := lockd.o
 O_OBJS   := clntlock.o clntproc.o host.o svc.o svclock.o svcshare.o \
-	    svcproc.o svcsubs.o mon.o xdr.o
+	    svcproc.o svcsubs.o mon.o xdr.o 
+
+#ifdef CONFIG_NFS_V3
+  O_OBJS += xdr4.o svc4proc.o
+#endif
+
 OX_OBJS  := lockd_syms.o
 M_OBJS   := $(O_TARGET)
 
Index: oldkernel/linux/fs/lockd/clntlock.c
diff -u linux/fs/lockd/clntlock.c:1.1.1.1 linux/fs/lockd/clntlock.c:1.2
--- linux/fs/lockd/clntlock.c:1.1.1.1	Wed May 31 12:33:48 2000
+++ linux/fs/lockd/clntlock.c	Fri Jul  7 15:36:45 2000
@@ -71,7 +71,7 @@
 	 * a 1 minute timeout would do. See the comment before
 	 * nlmclnt_lock for an explanation.
 	 */
-	sleep_on_timeout(&block.b_wait, 30*HZ);
+	interruptible_sleep_on_timeout(&block.b_wait, 30*HZ);
 
 	for (head = &nlm_blocked; *head; head = &(*head)->b_next) {
 		if (*head == &block) {
@@ -152,7 +152,7 @@
 		host->h_monitored = 0;
 		host->h_nsmstate = newstate;
 		host->h_state++;
-		host->h_count++;
+		nlm_get_host(host);
 		kernel_thread(reclaimer, host, 0);
 	}
 }
Index: oldkernel/linux/fs/lockd/clntproc.c
diff -u linux/fs/lockd/clntproc.c:1.1.1.1 linux/fs/lockd/clntproc.c:1.2
--- linux/fs/lockd/clntproc.c:1.1.1.1	Wed May 31 12:33:48 2000
+++ linux/fs/lockd/clntproc.c	Fri Jul  7 15:36:45 2000
@@ -46,11 +46,13 @@
 {
 	struct nlm_args	*argp = &req->a_args;
 	struct nlm_lock	*lock = &argp->lock;
+	struct dentry   *dentry = fl->fl_file->f_dentry;
+	struct nfs_fh   *fh = NFS_FH(dentry);
 
 	memset(argp, 0, sizeof(*argp));
 	nlmclnt_next_cookie(&argp->cookie);
 	argp->state   = nsm_local_state;
-	lock->fh      = *NFS_FH(fl->fl_file->f_dentry);
+	memcpy(&lock->fh, fh, sizeof(*fh));
 	lock->caller  = system_utsname.nodename;
 	lock->oh.data = req->a_owner;
 	lock->oh.len  = sprintf(req->a_owner, "%d@%s",
@@ -100,16 +102,23 @@
 int
 nlmclnt_proc(struct inode *inode, int cmd, struct file_lock *fl)
 {
-	struct nfs_server	*nfssrv = NFS_SERVER(inode);
 	struct nlm_host		*host;
 	struct nlm_rqst		reqst, *call = &reqst;
 	sigset_t		oldset;
 	unsigned long		flags;
-	int			status;
+	int			status, proto, vers;
 
-	/* Always use NLM version 1 over UDP for now... */
-	if (!(host = nlmclnt_lookup_host(NFS_ADDR(inode), IPPROTO_UDP, 1)))
+	vers = (NFS_PROTO(inode)->version == 3) ? 4 : 1;
+	if (NFS_PROTO(inode)->version > 3) {
+		printk(KERN_NOTICE "NFSv4 file locking not implemented!\n");
 		return -ENOLCK;
+	}
+
+	/* Retrieve transport protocol from NFS client */
+	proto = NFS_CLIENT(inode)->cl_xprt->prot;
+
+	if (!(host = nlmclnt_lookup_host(NFS_ADDR(inode), proto, vers)))
+		return -ENOLCK;
 
 	/* Create RPC client handle if not there, and copy soft
 	 * and intr flags from NFS client. */
@@ -122,9 +131,9 @@
 			status = -ENOLCK;
 			goto done;
 		}
-		clnt->cl_softrtry = nfssrv->client->cl_softrtry;
-		clnt->cl_intr     = nfssrv->client->cl_intr;
-		clnt->cl_chatty   = nfssrv->client->cl_chatty;
+		clnt->cl_softrtry = NFS_CLIENT(inode)->cl_softrtry;
+		clnt->cl_intr     = NFS_CLIENT(inode)->cl_intr;
+		clnt->cl_chatty   = NFS_CLIENT(inode)->cl_chatty;
 	}
 
 	/* Keep the old signal mask */
@@ -141,6 +150,10 @@
 		spin_unlock_irqrestore(&current->sigmask_lock, flags);
 
 		call = nlmclnt_alloc_call();
+		if (!call) {
+			status = -ENOMEM;
+			goto out_restore;
+		}
 		call->a_flags = RPC_TASK_ASYNC;
 	} else {
 		spin_unlock_irqrestore(&current->sigmask_lock, flags);
@@ -164,8 +177,9 @@
 	}
 
 	if (status < 0 && (call->a_flags & RPC_TASK_ASYNC))
-		rpc_free(call);
+		kfree(call);
 
+out_restore:
 	spin_lock_irqsave(&current->sigmask_lock, flags);
 	current->blocked = oldset;
 	recalc_sigpending(current);
@@ -199,8 +213,7 @@
 	struct nlm_rqst	*call;
 
 	while (!signalled()) {
-		call = (struct nlm_rqst *) rpc_allocate(RPC_TASK_ASYNC,
-					sizeof(struct nlm_rqst));
+		call = (struct nlm_rqst *) kmalloc(sizeof(struct nlm_rqst), GFP_KERNEL);
 		if (call)
 			return call;
 		printk("nlmclnt_alloc_call: failed, waiting for memory\n");
@@ -220,11 +233,21 @@
 	struct rpc_clnt	*clnt;
 	struct nlm_args	*argp = &req->a_args;
 	struct nlm_res	*resp = &req->a_res;
+	struct file	*filp = argp->lock.fl.fl_file;
+	struct rpc_message msg;
 	int		status;
 
 	dprintk("lockd: call procedure %s on %s\n",
 			nlm_procname(proc), host->h_name);
 
+	msg.rpc_proc = proc;
+	msg.rpc_argp = argp;
+	msg.rpc_resp = resp;
+	if (filp)
+		msg.rpc_cred = nfs_file_cred(filp);
+	else
+		msg.rpc_cred = NULL;
+
 	do {
 		if (host->h_reclaiming && !argp->reclaim) {
 			interruptible_sleep_on(&host->h_gracewait);
@@ -236,7 +259,7 @@
 			return -ENOLCK;
 
 		/* Perform the RPC call. If an error occurs, try again */
-		if ((status = rpc_call(clnt, proc, argp, resp, 0)) < 0) {
+		if ((status = rpc_call_sync(clnt, &msg, 0)) < 0) {
 			dprintk("lockd: rpc_call returned error %d\n", -status);
 			switch (status) {
 			case -EPROTONOSUPPORT:
@@ -245,6 +268,7 @@
 			case -ECONNREFUSED:
 			case -ETIMEDOUT:
 			case -ENOTCONN:
+				nlm_rebind_host(host);
 				status = -EAGAIN;
 				break;
 			case -ERESTARTSYS:
@@ -252,10 +276,7 @@
 			default:
 				break;
 			}
-			if (req->a_args.block)
-				nlm_rebind_host(host);
-			else
-				break;
+			break;
 		} else
 		if (resp->status == NLM_LCK_DENIED_GRACE_PERIOD) {
 			dprintk("lockd: server in grace period\n");
@@ -288,13 +309,15 @@
 /*
  * Generic NLM call, async version.
  */
-int
-nlmclnt_async_call(struct nlm_rqst *req, u32 proc, rpc_action callback)
+static int
+_nlmclnt_async_call(struct nlm_rqst *req, u32 proc, rpc_action callback,
+		    struct rpc_cred *cred)
 {
 	struct nlm_host	*host = req->a_host;
 	struct rpc_clnt	*clnt;
 	struct nlm_args	*argp = &req->a_args;
 	struct nlm_res	*resp = &req->a_res;
+	struct rpc_message msg;
 	int		status;
 
 	dprintk("lockd: call procedure %s on %s (async)\n",
@@ -304,16 +327,42 @@
 	if ((clnt = nlm_bind_host(host)) == NULL)
 		return -ENOLCK;
 
+	/* Increment host refcount */
+        nlm_get_host(host);
+
         /* bootstrap and kick off the async RPC call */
-        status = rpc_do_call(clnt, proc, argp, resp, RPC_TASK_ASYNC,
-					callback, req);
+	msg.rpc_proc = proc;
+	msg.rpc_argp = argp;
+	msg.rpc_resp =resp;
+	msg.rpc_cred = cred;
+        status = rpc_call_async(clnt, &msg, RPC_TASK_ASYNC, callback, req);
 
-	/* If the async call is proceeding, increment host refcount */
-        if (status >= 0 && (req->a_flags & RPC_TASK_ASYNC))
-                host->h_count++;
+	if (status < 0)
+		nlm_release_host(host);
 	return status;
 }
 
+
+int
+nlmclnt_async_call(struct nlm_rqst *req, u32 proc, rpc_action callback)
+{
+	struct nlm_args	*argp = &req->a_args;
+	struct file	*filp = argp->lock.fl.fl_file;
+	struct rpc_cred *cred = NULL;
+
+	if (filp)
+		cred = nfs_file_cred(filp);
+
+	return _nlmclnt_async_call(req, proc, callback, cred);
+}
+
+int
+nlmsvc_async_call(struct nlm_rqst *req, u32 proc, rpc_action callback)
+{
+	return _nlmclnt_async_call(req, proc, callback, NULL);
+}
+
+
 /*
  * TEST for the presence of a conflicting lock
  */
@@ -328,7 +377,7 @@
 	status = req->a_res.status;
 	if (status == NLM_LCK_GRANTED) {
 		fl->fl_type = F_UNLCK;
-	} if (status == NLM_LCK_DENIED) {
+	} else if (status == NLM_LCK_DENIED) {
 		/*
 		 * Report the conflicting lock back to the application.
 		 * FIXME: Is it OK to report the pid back as well?
@@ -342,6 +391,21 @@
 	return 0;
 }
 
+static
+void nlmclnt_insert_lock_callback(struct file_lock *fl)
+{
+	nlm_get_host(fl->fl_u.nfs_fl.host);
+}
+static
+void nlmclnt_remove_lock_callback(struct file_lock *fl)
+{
+	if (fl->fl_u.nfs_fl.host) {
+		nlm_release_host(fl->fl_u.nfs_fl.host);
+		fl->fl_u.nfs_fl.host = NULL;
+	}
+}
+
+
 /*
  * LOCK: Try to create a lock
  *
@@ -375,7 +439,7 @@
 		return -ENOLCK;
 	}
 
-	while (1) {
+	do {
 		if ((status = nlmclnt_call(req, NLMPROC_LOCK)) >= 0) {
 			if (resp->status != NLM_LCK_BLOCKED)
 				break;
@@ -383,11 +447,14 @@
 		}
 		if (status < 0)
 			return status;
-	}
+	} while (resp->status == NLM_LCK_BLOCKED);
 
 	if (resp->status == NLM_LCK_GRANTED) {
 		fl->fl_u.nfs_fl.state = host->h_state;
 		fl->fl_u.nfs_fl.flags |= NFS_LCK_GRANTED;
+		fl->fl_u.nfs_fl.host = host;
+		fl->fl_insert = nlmclnt_insert_lock_callback;
+		fl->fl_remove = nlmclnt_remove_lock_callback;
 	}
 
 	return nlm_stat_to_errno(resp->status);
@@ -439,15 +506,9 @@
 static int
 nlmclnt_unlock(struct nlm_rqst *req, struct file_lock *fl)
 {
-	struct nlm_host	*host = req->a_host;
 	struct nlm_res	*resp = &req->a_res;
 	int		status;
 
-	/* No monitor, no lock: see nlmclnt_lock().
-	 * Since this is an UNLOCK, don't try to setup monitoring here. */
-	if (!host->h_monitored)
-		return -ENOLCK;
-
 	/* Clean the GRANTED flag now so the lock doesn't get
 	 * reclaimed while we're stuck in the unlock call. */
 	fl->fl_u.nfs_fl.flags &= ~NFS_LCK_GRANTED;
@@ -482,17 +543,20 @@
 
 	if (task->tk_status < 0) {
 		dprintk("lockd: unlock failed (err = %d)\n", -task->tk_status);
-		nlm_rebind_host(req->a_host);
-		rpc_restart_call(task);
-		return;
+		goto retry_unlock;
 	}
 	if (status != NLM_LCK_GRANTED
 	 && status != NLM_LCK_DENIED_GRACE_PERIOD) {
 		printk("lockd: unexpected unlock status: %d\n", status);
 	}
-
-die:
-	rpc_release_task(task);
+ die:
+	nlm_release_host(req->a_host);
+	kfree(req);
+	return;
+ retry_unlock:
+	nlm_rebind_host(req->a_host);
+	rpc_restart_call(task);
+	return;
 }
 
 /*
@@ -515,10 +579,9 @@
 	recalc_sigpending(current);
 	spin_unlock_irqrestore(&current->sigmask_lock, flags);
 
-	do {
-		req = (struct nlm_rqst *) rpc_allocate(RPC_TASK_ASYNC,
-							sizeof(*req));
-	} while (req == NULL);
+	req = nlmclnt_alloc_call();
+	if (!req)
+		return -ENOMEM;
 	req->a_host  = host;
 	req->a_flags = RPC_TASK_ASYNC;
 
@@ -527,7 +590,7 @@
 	status = nlmclnt_async_call(req, NLMPROC_CANCEL,
 					nlmclnt_cancel_callback);
 	if (status < 0)
-		rpc_free(req);
+		kfree(req);
 
 	spin_lock_irqsave(&current->sigmask_lock, flags);
 	current->blocked = oldset;
@@ -568,7 +631,6 @@
 	}
 
 die:
-	rpc_release_task(task);
 	nlm_release_host(req->a_host);
 	kfree(req);
 	return;
Index: oldkernel/linux/fs/lockd/host.c
diff -u linux/fs/lockd/host.c:1.1.1.1 linux/fs/lockd/host.c:1.2
--- linux/fs/lockd/host.c:1.1.1.1	Wed May 31 12:33:48 2000
+++ linux/fs/lockd/host.c	Fri Jul  7 15:36:45 2000
@@ -15,6 +15,7 @@
 #include <linux/sunrpc/clnt.h>
 #include <linux/sunrpc/svc.h>
 #include <linux/lockd/lockd.h>
+#include <linux/lockd/sm_inter.h>
 
 
 #define NLMDBG_FACILITY		NLMDBG_HOSTCACHE
@@ -105,8 +106,7 @@
 				host->h_next = nlm_hosts[hash];
 				nlm_hosts[hash] = host;
 			}
-			host->h_expires = jiffies + NLM_HOST_EXPIRE;
-			host->h_count++;
+			nlm_get_host(host);
 			up(&nlm_host_sema);
 			return host;
 		}
@@ -171,9 +171,12 @@
 	down(&host->h_sema);
 
 	/* If we've already created an RPC client, check whether
-	 * RPC rebind is required */
+	 * RPC rebind is required
+	 * Note: why keep rebinding if we're on a tcp connection?
+	 */
 	if ((clnt = host->h_rpcclnt) != NULL) {
-		if (time_after_eq(jiffies, host->h_nextrebind)) {
+		xprt = clnt->cl_xprt;
+		if (!xprt->stream && time_after_eq(jiffies, host->h_nextrebind)) {
 			clnt->cl_port = 0;
 			host->h_nextrebind = jiffies + NLM_HOST_REBIND;
 			dprintk("lockd: next rebind in %ld jiffies\n",
@@ -229,13 +232,27 @@
 }
 
 /*
+ * Increment NLM host count
+ */
+struct nlm_host * nlm_get_host(struct nlm_host *host)
+{
+	if (host) {
+		dprintk("lockd: get host %s\n", host->h_name);
+		host->h_count ++;
+		host->h_expires = jiffies + NLM_HOST_EXPIRE;
+	}
+	return host;
+}
+
+/*
  * Release NLM host after use
  */
-void
-nlm_release_host(struct nlm_host *host)
+void nlm_release_host(struct nlm_host *host)
 {
-	dprintk("lockd: release host %s\n", host->h_name);
-	host->h_count -= 1;
+	if (host && host->h_count) {
+		dprintk("lockd: release host %s\n", host->h_name);
+		host->h_count --;
+	}
 }
 
 /*
@@ -307,6 +324,8 @@
 			}
 			dprintk("lockd: delete host %s\n", host->h_name);
 			*q = host->h_next;
+			if (host->h_monitored)
+				nsm_unmonitor(host);
 			if ((clnt = host->h_rpcclnt) != NULL) {
 				if (clnt->cl_users) {
 					printk(KERN_WARNING
Index: oldkernel/linux/fs/lockd/lockd_syms.c
diff -u linux/fs/lockd/lockd_syms.c:1.1.1.1 linux/fs/lockd/lockd_syms.c:1.2
--- linux/fs/lockd/lockd_syms.c:1.1.1.1	Wed May 31 12:33:48 2000
+++ linux/fs/lockd/lockd_syms.c	Fri Jul  7 15:36:45 2000
@@ -23,6 +23,7 @@
 #include <linux/sunrpc/clnt.h>
 #include <linux/sunrpc/svc.h>
 #include <linux/lockd/lockd.h>
+#include <linux/lockd/xdr4.h>
 #include <linux/lockd/syscall.h>
 
 /* Start/stop the daemon */
@@ -40,5 +41,18 @@
 /* Configuration at insmod time */
 EXPORT_SYMBOL(nlmsvc_grace_period);
 EXPORT_SYMBOL(nlmsvc_timeout);
+
+/* NLM4 exported symbols */ 
+EXPORT_SYMBOL(nlm4_lck_denied_grace_period);
+EXPORT_SYMBOL(nlm4_lck_denied);
+EXPORT_SYMBOL(nlm4_lck_blocked);
+EXPORT_SYMBOL(nlm4_rofs);
+EXPORT_SYMBOL(nlm4_stale_fh);
+EXPORT_SYMBOL(nlm4_granted);
+EXPORT_SYMBOL(nlm4_deadlock);
+EXPORT_SYMBOL(nlm4_failed);
+EXPORT_SYMBOL(nlm4_fbig);
+EXPORT_SYMBOL(nlm4_lck_denied_nolocks);
+
 
 #endif /* CONFIG_MODULES */
Index: oldkernel/linux/fs/lockd/mon.c
diff -u linux/fs/lockd/mon.c:1.1.1.1 linux/fs/lockd/mon.c:1.2
--- linux/fs/lockd/mon.c:1.1.1.1	Wed May 31 12:33:48 2000
+++ linux/fs/lockd/mon.c	Fri Jul  7 15:36:45 2000
@@ -4,6 +4,10 @@
  * The kernel statd client.
  *
  * Copyright (C) 1996, Olaf Kirch <okir@monad.swb.de>
+ *
+ * Note: In a future release, we should fold all NSM activity into
+ * rpc.mountd and the mount program, respectively. Stuff like this
+ * really doesn't belong in the kernel.	--okir
  */
 
 #include <linux/types.h>
@@ -30,14 +34,12 @@
  * Common procedure for SM_MON/SM_UNMON calls
  */
 static int
-nsm_mon_unmon(struct nlm_host *host, char *what, u32 proc)
+nsm_mon_unmon(struct nlm_host *host, u32 proc, struct nsm_res *res)
 {
 	struct rpc_clnt	*clnt;
 	int		status;
 	struct nsm_args	args;
-	struct nsm_res	res;
 
-	dprintk("lockd: nsm_%s(%s)\n", what, host->h_name);
 	status = -EACCES;
 	clnt = nsm_create();
 	if (!clnt)
@@ -47,23 +49,15 @@
 	args.prog = NLM_PROGRAM;
 	args.vers = 1;
 	args.proc = NLMPROC_NSM_NOTIFY;
+	memset(res, 0, sizeof(*res));
 
-	status = rpc_call(clnt, proc, &args, &res, 0);
-	if (status < 0) {
+	status = rpc_call(clnt, proc, &args, res, 0);
+	if (status < 0)
 		printk(KERN_DEBUG "nsm_mon_unmon: rpc failed, status=%d\n",
 			status);
-		goto out;
-	}
-
-	status = -EACCES;
-	if (res.status != 0) {
-		printk(KERN_NOTICE "lockd: cannot %s %s\n", what, host->h_name);
-		goto out;
-	}
-
-	nsm_local_state = res.state;
-	status = 0;
-out:
+	else
+		status = 0;
+ out:
 	return status;
 }
 
@@ -73,10 +67,16 @@
 int
 nsm_monitor(struct nlm_host *host)
 {
+	struct nsm_res	res;
 	int		status;
+
+	dprintk("lockd: nsm_monitor(%s)\n", host->h_name);
+
+	status = nsm_mon_unmon(host, SM_MON, &res);
 
-	status = nsm_mon_unmon(host, "monitor", SM_MON);
-	if (status >= 0)
+	if (status < 0 || res.status != 0)
+		printk(KERN_NOTICE "lockd: cannot monitor %s\n", host->h_name);
+	else
 		host->h_monitored = 1;
 	return status;
 }
@@ -87,9 +87,15 @@
 int
 nsm_unmonitor(struct nlm_host *host)
 {
+	struct nsm_res	res;
 	int		status;
+
+	dprintk("lockd: nsm_unmonitor(%s)\n", host->h_name);
 
-	if ((status = nsm_mon_unmon(host, "unmonitor", SM_UNMON)) >= 0)
+	status = nsm_mon_unmon(host, SM_UNMON, &res);
+	if (status < 0)
+		printk(KERN_NOTICE "lockd: cannot unmonitor %s\n", host->h_name);
+	else
 		host->h_monitored = 0;
 	return status;
 }
@@ -155,15 +161,15 @@
 	 */
 	sprintf(buffer, "%d.%d.%d.%d", (addr>>24) & 0xff, (addr>>16) & 0xff,
 				 	(addr>>8) & 0xff,  (addr) & 0xff);
-	if (!(p = xdr_encode_string(p, buffer))
-	 || !(p = xdr_encode_string(p, system_utsname.nodename)))
+	if (!(p = xdr_encode_string(p, buffer, -1))
+	 || !(p = xdr_encode_string(p, system_utsname.nodename, -1)))
 		return -EIO;
 	*p++ = htonl(argp->prog);
 	*p++ = htonl(argp->vers);
 	*p++ = htonl(argp->proc);
 
 	/* This is the private part. Needed only for SM_MON call */
-	if (rqstp->rq_task->tk_proc == SM_MON) {
+	if (rqstp->rq_task->tk_msg.rpc_proc == SM_MON) {
 		*p++ = argp->addr;
 		*p++ = 0;
 		*p++ = 0;
@@ -187,7 +193,7 @@
 static int
 xdr_decode_stat(struct rpc_rqst *rqstp, u32 *p, struct nsm_res *resp)
 {
-	resp->status = ntohl(*p++);
+	resp->state = ntohl(*p++);
 	return 0;
 }
 
Index: oldkernel/linux/fs/lockd/svc.c
diff -u linux/fs/lockd/svc.c:1.1.1.1 linux/fs/lockd/svc.c:1.2
--- linux/fs/lockd/svc.c:1.1.1.1	Wed May 31 12:33:48 2000
+++ linux/fs/lockd/svc.c	Fri Jul  7 15:36:45 2000
@@ -230,6 +230,7 @@
 
 	error = -ENOMEM;
 	serv = svc_create(&nlmsvc_program, 0, NLMSVC_XDRSIZE);
+
 	if (!serv) {
 		printk(KERN_WARNING "lockd_up: create service failed\n");
 		goto out;
@@ -350,7 +351,7 @@
 static struct svc_version	nlmsvc_version3 = {
 	3, 24, nlmsvc_procedures, NULL
 };
-#ifdef CONFIG_NFSD_NFS3
+#if (defined(CONFIG_NFSD) || defined(CONFIG_NFSD_MODULE)) && defined(CONFIG_NFS_V3)
 static struct svc_version	nlmsvc_version4 = {
 	4, 24, nlmsvc_procedures4, NULL
 };
@@ -360,7 +361,7 @@
 	&nlmsvc_version1,
 	NULL,
 	&nlmsvc_version3,
-#ifdef CONFIG_NFSD_NFS3
+#if (defined(CONFIG_NFSD) || defined(CONFIG_NFSD_MODULE)) && defined(CONFIG_NFS_V3)
 	&nlmsvc_version4,
 #endif
 };
@@ -380,6 +381,7 @@
 int
 lockdctl(int cmd, void *opaque_argp, void *opaque_resp)
 {
+#if 0
 	int err;
 
 	MOD_INC_USE_COUNT;
@@ -395,4 +397,14 @@
 	MOD_DEC_USE_COUNT;
 
 	return err;
+#else
+	/*
+	 *  For the moment, unless a real need for locks on NFS root
+	 *  emerges, we revert to automatic lockd start.  But we will leave the
+	 *  manual call machinery in place in case we ever want to go
+	 *  back to it.
+	 */
+	 printk("lockd: note, lockd is automatic in this kernel.  Remove rpc.lockd from any rc scripts.\n"); 
+	return (0);
+#endif
 }
Index: oldkernel/linux/fs/lockd/svc4proc.c
diff -u /dev/null linux/fs/lockd/svc4proc.c:1.1
--- /dev/null	Mon Jul 31 21:15:08 2000
+++ linux/fs/lockd/svc4proc.c	Fri Jul  7 16:18:17 2000
@@ -0,0 +1,561 @@
+/*
+ * linux/fs/lockd/svc4proc.c
+ *
+ * Lockd server procedures. We don't implement the NLM_*_RES 
+ * procedures because we don't use the async procedures.
+ *
+ * Copyright (C) 1996, Olaf Kirch <okir@monad.swb.de>
+ */
+
+#include <linux/types.h>
+#include <linux/sched.h>
+#include <linux/malloc.h>
+#include <linux/in.h>
+#include <linux/sunrpc/svc.h>
+#include <linux/sunrpc/clnt.h>
+#include <linux/nfsd/nfsd.h>
+#include <linux/lockd/xdr4.h>
+#include <linux/lockd/lockd.h>
+#include <linux/lockd/share.h>
+#include <linux/lockd/sm_inter.h>
+
+
+#define NLMDBG_FACILITY		NLMDBG_CLIENT
+
+static u32	nlm4svc_callback(struct svc_rqst *, u32, struct nlm_res *);
+static void	nlm4svc_callback_exit(struct rpc_task *);
+
+/*
+ * Obtain client and file from arguments
+ */
+static u32
+nlm4svc_retrieve_args(struct svc_rqst *rqstp, struct nlm_args *argp,
+			struct nlm_host **hostp, struct nlm_file **filp)
+{
+	struct nlm_host		*host = NULL;
+	struct nlm_file		*file = NULL;
+	struct nlm_lock		*lock = &argp->lock;
+	u32			error = 0;
+
+	/* nfsd callbacks must have been installed for this procedure */
+	if (!nlmsvc_ops)
+		return nlm4_lck_denied_nolocks;
+
+	/* Obtain handle for client host */
+	if (rqstp->rq_client == NULL) {
+		printk(KERN_NOTICE
+			"lockd: unauthenticated request from (%08lx:%d)\n",
+			ntohl(rqstp->rq_addr.sin_addr.s_addr),
+			ntohs(rqstp->rq_addr.sin_port));
+		return nlm4_lck_denied_nolocks;
+	}
+
+	/* Obtain host handle */
+	if (!(host = nlmsvc_lookup_host(rqstp))
+	 || (argp->monitor && !host->h_monitored && nsm_monitor(host) < 0))
+		goto no_locks;
+	*hostp = host;
+
+	/* Obtain file pointer. Not used by FREE_ALL call. */
+	if (filp != NULL) {
+		if ((error = nlm_lookup_file(rqstp, &file, &lock->fh)) != 0)
+			goto no_locks;
+		*filp = file;
+
+		/* Set up the missing parts of the file_lock structure */
+		lock->fl.fl_file  = &file->f_file;
+		lock->fl.fl_owner = (fl_owner_t) host;
+	}
+
+	return 0;
+
+no_locks:
+	if (host)
+		nlm_release_host(host);
+	/* check the error to see if its a stale fh error */
+ 	if (error)
+		return error;	
+	return nlm4_lck_denied_nolocks;
+}
+
+/*
+ * NULL: Test for presence of service
+ */
+static int
+nlm4svc_proc_null(struct svc_rqst *rqstp, void *argp, void *resp)
+{
+	dprintk("lockd: NULL          called\n");
+	return rpc_success;
+}
+
+/*
+ * TEST: Check for conflicting lock
+ */
+static int
+nlm4svc_proc_test(struct svc_rqst *rqstp, struct nlm_args *argp,
+				         struct nlm_res  *resp)
+{
+	struct nlm_host	*host;
+	struct nlm_file	*file;
+
+	dprintk("lockd: TEST4        called\n");
+	resp->cookie = argp->cookie;
+
+	/* Don't accept test requests during grace period */
+	if (nlmsvc_grace_period) {
+		resp->status = nlm4_lck_denied_grace_period;
+		return rpc_success;
+	}
+
+	/* Obtain client and file */
+	if ((resp->status = nlm4svc_retrieve_args(rqstp, argp, &host, &file)))
+		return rpc_success;
+
+	/* Now check for conflicting locks */
+	resp->status = nlmsvc_testlock(file, &argp->lock, &resp->lock);
+
+	dprintk("lockd: TEST4          status %ld\n", ntohl(resp->status));
+	nlm_release_host(host);
+	nlm_release_file(file);
+	return rpc_success;
+}
+
+static int
+nlm4svc_proc_lock(struct svc_rqst *rqstp, struct nlm_args *argp,
+				         struct nlm_res  *resp)
+{
+	struct nlm_host	*host;
+	struct nlm_file	*file;
+
+	dprintk("lockd: LOCK          called\n");
+
+	resp->cookie = argp->cookie;
+
+	/* Don't accept new lock requests during grace period */
+	if (nlmsvc_grace_period && !argp->reclaim) {
+		resp->status = nlm4_lck_denied_grace_period;
+		return rpc_success;
+	}
+
+	/* Obtain client and file */
+	if ((resp->status = nlm4svc_retrieve_args(rqstp, argp, &host, &file)))
+		return rpc_success;
+
+#if 0
+	/* If supplied state doesn't match current state, we assume it's
+	 * an old request that time-warped somehow. Any error return would
+	 * do in this case because it's irrelevant anyway.
+	 *
+	 * NB: We don't retrieve the remote host's state yet.
+	 */
+	if (host->h_nsmstate && host->h_nsmstate != argp->state) {
+		resp->status = nlm4_lck_denied_nolocks;
+	} else
+#endif
+
+	/* Now try to lock the file */
+	resp->status = nlmsvc_lock(rqstp, file, &argp->lock,
+					argp->block, &argp->cookie);
+
+	dprintk("lockd: LOCK          status %ld\n", ntohl(resp->status));
+	nlm_release_host(host);
+	nlm_release_file(file);
+	return rpc_success;
+}
+
+static int
+nlm4svc_proc_cancel(struct svc_rqst *rqstp, struct nlm_args *argp,
+				           struct nlm_res  *resp)
+{
+	struct nlm_host	*host;
+	struct nlm_file	*file;
+
+	dprintk("lockd: CANCEL        called\n");
+
+	resp->cookie = argp->cookie;
+
+	/* Don't accept requests during grace period */
+	if (nlmsvc_grace_period) {
+		resp->status = nlm4_lck_denied_grace_period;
+		return rpc_success;
+	}
+
+	/* Obtain client and file */
+	if ((resp->status = nlm4svc_retrieve_args(rqstp, argp, &host, &file)))
+		return rpc_success;
+
+	/* Try to cancel request. */
+	resp->status = nlmsvc_cancel_blocked(file, &argp->lock);
+
+	dprintk("lockd: CANCEL        status %ld\n", ntohl(resp->status));
+	nlm_release_host(host);
+	nlm_release_file(file);
+	return rpc_success;
+}
+
+/*
+ * UNLOCK: release a lock
+ */
+static int
+nlm4svc_proc_unlock(struct svc_rqst *rqstp, struct nlm_args *argp,
+				           struct nlm_res  *resp)
+{
+	struct nlm_host	*host;
+	struct nlm_file	*file;
+
+	dprintk("lockd: UNLOCK        called\n");
+
+	resp->cookie = argp->cookie;
+
+	/* Don't accept new lock requests during grace period */
+	if (nlmsvc_grace_period) {
+		resp->status = nlm4_lck_denied_grace_period;
+		return rpc_success;
+	}
+
+	/* Obtain client and file */
+	if ((resp->status = nlm4svc_retrieve_args(rqstp, argp, &host, &file)))
+		return rpc_success;
+
+	/* Now try to remove the lock */
+	resp->status = nlmsvc_unlock(file, &argp->lock);
+
+	dprintk("lockd: UNLOCK        status %ld\n", ntohl(resp->status));
+	nlm_release_host(host);
+	nlm_release_file(file);
+	return rpc_success;
+}
+
+/*
+ * GRANTED: A server calls us to tell that a process' lock request
+ * was granted
+ */
+static int
+nlm4svc_proc_granted(struct svc_rqst *rqstp, struct nlm_args *argp,
+				            struct nlm_res  *resp)
+{
+	resp->cookie = argp->cookie;
+
+	dprintk("lockd: GRANTED       called\n");
+	resp->status = nlmclnt_grant(&argp->lock);
+	dprintk("lockd: GRANTED       status %ld\n", ntohl(resp->status));
+	return rpc_success;
+}
+
+/*
+ * `Async' versions of the above service routines. They aren't really,
+ * because we send the callback before the reply proper. I hope this
+ * doesn't break any clients.
+ */
+static int
+nlm4svc_proc_test_msg(struct svc_rqst *rqstp, struct nlm_args *argp,
+					     void	     *resp)
+{
+	struct nlm_res	res;
+	u32		stat;
+
+	dprintk("lockd: TEST_MSG      called\n");
+
+	if ((stat = nlm4svc_proc_test(rqstp, argp, &res)) == 0)
+		stat = nlm4svc_callback(rqstp, NLMPROC_TEST_RES, &res);
+	return stat;
+}
+
+static int
+nlm4svc_proc_lock_msg(struct svc_rqst *rqstp, struct nlm_args *argp,
+					     void	     *resp)
+{
+	struct nlm_res	res;
+	u32		stat;
+
+	dprintk("lockd: LOCK_MSG      called\n");
+
+	if ((stat = nlm4svc_proc_lock(rqstp, argp, &res)) == 0)
+		stat = nlm4svc_callback(rqstp, NLMPROC_LOCK_RES, &res);
+	return stat;
+}
+
+static int
+nlm4svc_proc_cancel_msg(struct svc_rqst *rqstp, struct nlm_args *argp,
+					       void	       *resp)
+{
+	struct nlm_res	res;
+	u32		stat;
+
+	dprintk("lockd: CANCEL_MSG    called\n");
+
+	if ((stat = nlm4svc_proc_cancel(rqstp, argp, &res)) == 0)
+		stat = nlm4svc_callback(rqstp, NLMPROC_CANCEL_RES, &res);
+	return stat;
+}
+
+static int
+nlm4svc_proc_unlock_msg(struct svc_rqst *rqstp, struct nlm_args *argp,
+                                               void            *resp)
+{
+	struct nlm_res	res;
+	u32		stat;
+
+	dprintk("lockd: UNLOCK_MSG    called\n");
+
+	if ((stat = nlm4svc_proc_unlock(rqstp, argp, &res)) == 0)
+		stat = nlm4svc_callback(rqstp, NLMPROC_UNLOCK_RES, &res);
+	return stat;
+}
+
+static int
+nlm4svc_proc_granted_msg(struct svc_rqst *rqstp, struct nlm_args *argp,
+                                                void            *resp)
+{
+	struct nlm_res	res;
+	u32		stat;
+
+	dprintk("lockd: GRANTED_MSG   called\n");
+
+	if ((stat = nlm4svc_proc_granted(rqstp, argp, &res)) == 0)
+		stat = nlm4svc_callback(rqstp, NLMPROC_GRANTED_RES, &res);
+	return stat;
+}
+
+/*
+ * SHARE: create a DOS share or alter existing share.
+ */
+static int
+nlm4svc_proc_share(struct svc_rqst *rqstp, struct nlm_args *argp,
+				          struct nlm_res  *resp)
+{
+	struct nlm_host	*host;
+	struct nlm_file	*file;
+
+	dprintk("lockd: SHARE         called\n");
+
+	resp->cookie = argp->cookie;
+
+	/* Don't accept new lock requests during grace period */
+	if (nlmsvc_grace_period && !argp->reclaim) {
+		resp->status = nlm4_lck_denied_grace_period;
+		return rpc_success;
+	}
+
+	/* Obtain client and file */
+	if ((resp->status = nlm4svc_retrieve_args(rqstp, argp, &host, &file)))
+		return rpc_success;
+
+	/* Now try to create the share */
+	resp->status = nlmsvc_share_file(host, file, argp);
+
+	dprintk("lockd: SHARE         status %ld\n", ntohl(resp->status));
+	nlm_release_host(host);
+	nlm_release_file(file);
+	return rpc_success;
+}
+
+/*
+ * UNSHARE: Release a DOS share.
+ */
+static int
+nlm4svc_proc_unshare(struct svc_rqst *rqstp, struct nlm_args *argp,
+				            struct nlm_res  *resp)
+{
+	struct nlm_host	*host;
+	struct nlm_file	*file;
+
+	dprintk("lockd: UNSHARE       called\n");
+
+	resp->cookie = argp->cookie;
+
+	/* Don't accept requests during grace period */
+	if (nlmsvc_grace_period) {
+		resp->status = nlm4_lck_denied_grace_period;
+		return rpc_success;
+	}
+
+	/* Obtain client and file */
+	if ((resp->status = nlm4svc_retrieve_args(rqstp, argp, &host, &file)))
+		return rpc_success;
+
+	/* Now try to lock the file */
+	resp->status = nlmsvc_unshare_file(host, file, argp);
+
+	dprintk("lockd: UNSHARE       status %ld\n", ntohl(resp->status));
+	nlm_release_host(host);
+	nlm_release_file(file);
+	return rpc_success;
+}
+
+/*
+ * NM_LOCK: Create an unmonitored lock
+ */
+static int
+nlm4svc_proc_nm_lock(struct svc_rqst *rqstp, struct nlm_args *argp,
+				            struct nlm_res  *resp)
+{
+	dprintk("lockd: NM_LOCK       called\n");
+
+	argp->monitor = 0;		/* just clean the monitor flag */
+	return nlm4svc_proc_lock(rqstp, argp, resp);
+}
+
+/*
+ * FREE_ALL: Release all locks and shares held by client
+ */
+static int
+nlm4svc_proc_free_all(struct svc_rqst *rqstp, struct nlm_args *argp,
+					     void            *resp)
+{
+	struct nlm_host	*host;
+
+	/* Obtain client */
+	if (nlm4svc_retrieve_args(rqstp, argp, &host, NULL))
+		return rpc_success;
+
+	nlmsvc_free_host_resources(host);
+	nlm_release_host(host);
+	return rpc_success;
+}
+
+/*
+ * SM_NOTIFY: private callback from statd (not part of official NLM proto)
+ */
+static int
+nlm4svc_proc_sm_notify(struct svc_rqst *rqstp, struct nlm_reboot *argp,
+					      void	        *resp)
+{
+	struct sockaddr_in	saddr = rqstp->rq_addr;
+	struct nlm_host		*host;
+
+	dprintk("lockd: SM_NOTIFY     called\n");
+	if (saddr.sin_addr.s_addr != htonl(INADDR_LOOPBACK)
+	 || ntohs(saddr.sin_port) >= 1024) {
+		printk(KERN_WARNING
+			"lockd: rejected NSM callback from %08lx:%d\n",
+			ntohl(rqstp->rq_addr.sin_addr.s_addr),
+			ntohs(rqstp->rq_addr.sin_port));
+		return rpc_system_err;
+	}
+
+	/* Obtain the host pointer for this NFS server and try to
+	 * reclaim all locks we hold on this server.
+	 */
+	saddr.sin_addr.s_addr = argp->addr;	
+	if ((host = nlm_lookup_host(NULL, &saddr, IPPROTO_UDP, 1)) != NULL) {
+		nlmclnt_recovery(host, argp->state);
+		nlm_release_host(host);
+	}
+
+	/* If we run on an NFS server, delete all locks held by the client */
+	if (nlmsvc_ops != NULL) {
+		struct svc_client	*clnt;
+		saddr.sin_addr.s_addr = argp->addr;	
+		if ((clnt = nlmsvc_ops->exp_getclient(&saddr)) != NULL 
+		 && (host = nlm_lookup_host(clnt, &saddr, 0, 0)) != NULL) {
+			nlmsvc_free_host_resources(host);
+		}
+		nlm_release_host(host);
+	}
+
+	return rpc_success;
+}
+
+/*
+ * This is the generic lockd callback for async RPC calls
+ */
+static u32
+nlm4svc_callback(struct svc_rqst *rqstp, u32 proc, struct nlm_res *resp)
+{
+	struct nlm_host	*host;
+	struct nlm_rqst	*call;
+
+	if (!(call = nlmclnt_alloc_call()))
+		return rpc_system_err;
+
+	host = nlmclnt_lookup_host(&rqstp->rq_addr,
+				rqstp->rq_prot, rqstp->rq_vers);
+	if (!host) {
+		rpc_free(call);
+		return rpc_system_err;
+	}
+
+	call->a_flags = RPC_TASK_ASYNC;
+	call->a_host  = host;
+	memcpy(&call->a_args, resp, sizeof(*resp));
+
+	if (nlmsvc_async_call(call, proc, nlm4svc_callback_exit) < 0)
+		return rpc_system_err;
+
+	return rpc_success;
+}
+
+static void
+nlm4svc_callback_exit(struct rpc_task *task)
+{
+	struct nlm_rqst	*call = (struct nlm_rqst *) task->tk_calldata;
+
+	if (task->tk_status < 0) {
+		dprintk("lockd: %4d callback failed (errno = %d)\n",
+					task->tk_pid, -task->tk_status);
+	}
+	nlm_release_host(call->a_host);
+	rpc_free(call);
+}
+
+/*
+ * NLM Server procedures.
+ */
+
+#define nlm4svc_encode_norep	nlm4svc_encode_void
+#define nlm4svc_decode_norep	nlm4svc_decode_void
+#define nlm4svc_decode_testres	nlm4svc_decode_void
+#define nlm4svc_decode_lockres	nlm4svc_decode_void
+#define nlm4svc_decode_unlockres	nlm4svc_decode_void
+#define nlm4svc_decode_cancelres	nlm4svc_decode_void
+#define nlm4svc_decode_grantedres	nlm4svc_decode_void
+
+#define nlm4svc_proc_none	nlm4svc_proc_null
+#define nlm4svc_proc_test_res	nlm4svc_proc_null
+#define nlm4svc_proc_lock_res	nlm4svc_proc_null
+#define nlm4svc_proc_cancel_res	nlm4svc_proc_null
+#define nlm4svc_proc_unlock_res	nlm4svc_proc_null
+#define nlm4svc_proc_granted_res	nlm4svc_proc_null
+
+struct nlm_void			{ int dummy; };
+
+#define PROC(name, xargt, xrest, argt, rest)	\
+ { (svc_procfunc) nlm4svc_proc_##name,	\
+   (kxdrproc_t) nlm4svc_decode_##xargt,	\
+   (kxdrproc_t) nlm4svc_encode_##xrest,	\
+   NULL,				\
+   sizeof(struct nlm_##argt),		\
+   sizeof(struct nlm_##rest),		\
+   0,					\
+   0					\
+ }
+struct svc_procedure		nlmsvc_procedures4[] = {
+  PROC(null,		void,		void,		void,	void),
+  PROC(test,		testargs,	testres,	args,	res),
+  PROC(lock,		lockargs,	res,		args,	res),
+  PROC(cancel,		cancargs,	res,		args,	res),
+  PROC(unlock,		unlockargs,	res,		args,	res),
+  PROC(granted,		testargs,	res,		args,	res),
+  PROC(test_msg,	testargs,	norep,		args,	void),
+  PROC(lock_msg,	lockargs,	norep,		args,	void),
+  PROC(cancel_msg,	cancargs,	norep,		args,	void),
+  PROC(unlock_msg,	unlockargs,	norep,		args,	void),
+  PROC(granted_msg,	testargs,	norep,		args,	void),
+  PROC(test_res,	testres,	norep,		res,	void),
+  PROC(lock_res,	lockres,	norep,		res,	void),
+  PROC(cancel_res,	cancelres,	norep,		res,	void),
+  PROC(unlock_res,	unlockres,	norep,		res,	void),
+  PROC(granted_res,	grantedres,	norep,		res,	void),
+  PROC(none,		void,		void,		void,	void),
+  PROC(none,		void,		void,		void,	void),
+  PROC(none,		void,		void,		void,	void),
+  PROC(none,		void,		void,		void,	void),
+  PROC(share,		shareargs,	shareres,	args,	res),
+  PROC(unshare,		shareargs,	shareres,	args,	res),
+  PROC(nm_lock,		lockargs,	res,		args,	res),
+  PROC(free_all,	notify,		void,		args,	void),
+
+  /* statd callback */
+  PROC(sm_notify,	reboot,		void,		reboot,	void),
+};
Index: oldkernel/linux/fs/lockd/svclock.c
diff -u linux/fs/lockd/svclock.c:1.2 linux/fs/lockd/svclock.c:1.3
--- linux/fs/lockd/svclock.c:1.2	Thu Jun  1 15:03:08 2000
+++ linux/fs/lockd/svclock.c	Fri Jul  7 15:36:45 2000
@@ -26,6 +26,7 @@
 #include <linux/sunrpc/clnt.h>
 #include <linux/sunrpc/svc.h>
 #include <linux/lockd/nlm.h>
+#include <linux/lockd/xdr4.h>
 #include <linux/lockd/lockd.h>
 
 
@@ -94,15 +95,14 @@
 	struct file_lock	*fl;
 
 	dprintk("lockd: nlmsvc_lookup_block f=%p pd=%d %ld-%ld ty=%d\n",
-		file, lock->fl.fl_pid,
-		(u_long)lock->fl.fl_start, (u_long)lock->fl.fl_end,
-		lock->fl.fl_type);
+				file, lock->fl.fl_pid, lock->fl.fl_start,
+				lock->fl.fl_end, lock->fl.fl_type);
 	for (head = &nlm_blocked; (block = *head); head = &block->b_next) {
 		fl = &block->b_call.a_args.lock.fl;
-		dprintk("       check f=%p pd=%d %ld-%ld ty=%d\n",
-				block->b_file, fl->fl_pid,
-				(u_long)fl->fl_start, (u_long)fl->fl_end,
-				fl->fl_type);
+		dprintk("lockd: check f=%p pd=%d %ld-%ld ty=%d cookie=%x\n",
+				block->b_file, fl->fl_pid, fl->fl_start,
+				fl->fl_end, fl->fl_type, 
+				*(u32 *)(&block->b_call.a_args.cookie.data));
 		if (block->b_file == file && nlm_compare_locks(fl, &lock->fl)) {
 			if (remove)
 				*head = block->b_next;
@@ -131,6 +131,8 @@
 	struct nlm_block *block;
 
 	for (block = nlm_blocked; block; block = block->b_next) {
+		dprintk("cookie: head of blocked queue %p, block %p\n", 
+			nlm_blocked, block);
 		if (nlm_cookie_match(&block->b_call.a_args.cookie,cookie))
 			break;
 	}
@@ -282,15 +284,20 @@
 {
 	struct file_lock	*conflock;
 	struct nlm_block	*block;
+	struct inode            *inode = file->f_file.f_dentry->d_inode;
 	int			error;
 
 	dprintk("lockd: nlmsvc_lock(%04x/%ld, ty=%d, pi=%d, %ld-%ld, bl=%d)\n",
 				file->f_file.f_dentry->d_inode->i_dev,
 				file->f_file.f_dentry->d_inode->i_ino,
 				lock->fl.fl_type, lock->fl.fl_pid,
-				(u_long)lock->fl.fl_start,
-				(u_long)lock->fl.fl_end,
+				lock->fl.fl_start,
+				lock->fl.fl_end,
 				wait);
+	
+	/* Checking for read only file system */
+	if (IS_RDONLY(inode))
+		return nlm4_rofs;
 
 	/* Lock file against concurrent access */
 	down(&file->f_sema);
@@ -303,7 +310,7 @@
 again:
 	if (!(conflock = posix_test_lock(&file->f_file, &lock->fl))) {
 		error = posix_lock_file(&file->f_file, &lock->fl, 0);
-
+		
 		if (block)
 			nlmsvc_delete_block(block, 0);
 		up(&file->f_sema);
@@ -311,18 +318,19 @@
 		dprintk("lockd: posix_lock_file returned %d\n", -error);
 		switch(-error) {
 		case 0:
-			return nlm_granted;
-		case EDEADLK:			/* no applicable NLM status */
+			return nlm4_granted;
+		case EDEADLK:		
+			return nlm4_deadlock;
 		case EAGAIN:
-			return nlm_lck_denied;
+			return nlm4_lck_denied;
 		default:			/* includes ENOLCK */
-			return nlm_lck_denied_nolocks;
+			return nlm4_lck_denied_nolocks;
 		}
 	}
 
 	if (!wait) {
 		up(&file->f_sema);
-		return nlm_lck_denied;
+		return nlm4_lck_denied;
 	}
 
 	/* If we don't have a block, create and initialize it. Then
@@ -330,7 +338,7 @@
 	if (block == NULL) {
 		dprintk("lockd: blocking on this lock (allocating).\n");
 		if (!(block = nlmsvc_create_block(rqstp, file, lock, cookie)))
-			return nlm_lck_denied_nolocks;
+			return nlm4_lck_denied_nolocks;
 		goto again;
 	}
 
@@ -345,7 +353,7 @@
 	}
 
 	up(&file->f_sema);
-	return nlm_lck_blocked;
+	return nlm4_lck_blocked;
 }
 
 /*
@@ -361,20 +369,20 @@
 				file->f_file.f_dentry->d_inode->i_dev,
 				file->f_file.f_dentry->d_inode->i_ino,
 				lock->fl.fl_type,
-				(u_long)lock->fl.fl_start,
-				(u_long)lock->fl.fl_end);
+				lock->fl.fl_start,
+				lock->fl.fl_end);
 
 	if ((fl = posix_test_lock(&file->f_file, &lock->fl)) != NULL) {
 		dprintk("lockd: conflicting lock(ty=%d, %ld-%ld)\n",
-				fl->fl_type,
-				(u_long)fl->fl_start, (u_long)fl->fl_end);
+				fl->fl_type, fl->fl_start, fl->fl_end );
+
 		conflock->caller = "somehost";	/* FIXME */
 		conflock->oh.len = 0;		/* don't return OH info */
 		conflock->fl = *fl;
-		return nlm_lck_denied;
+		return nlm4_lck_denied;
 	}
 
-	return nlm_granted;
+	return nlm4_granted;
 }
 
 /*
@@ -393,8 +401,8 @@
 				file->f_file.f_dentry->d_inode->i_dev,
 				file->f_file.f_dentry->d_inode->i_ino,
 				lock->fl.fl_pid,
-				(u_long)lock->fl.fl_start,
-				(u_long)lock->fl.fl_end);
+				lock->fl.fl_start,
+				lock->fl.fl_end);
 
 	/* First, cancel any lock that might be there */
 	nlmsvc_cancel_blocked(file, lock);
@@ -402,7 +410,7 @@
 	lock->fl.fl_type = F_UNLCK;
 	error = posix_lock_file(&file->f_file, &lock->fl, 0);
 
-	return (error < 0)? nlm_lck_denied_nolocks : nlm_granted;
+	return (error < 0)? nlm4_lck_denied_nolocks : nlm4_granted;
 }
 
 /*
@@ -421,14 +429,14 @@
 				file->f_file.f_dentry->d_inode->i_dev,
 				file->f_file.f_dentry->d_inode->i_ino,
 				lock->fl.fl_pid,
-				(u_long)lock->fl.fl_start,
-				(u_long)lock->fl.fl_end);
+				lock->fl.fl_start,
+				lock->fl.fl_end);
 
 	down(&file->f_sema);
 	if ((block = nlmsvc_lookup_block(file, lock, 1)) != NULL)
 		nlmsvc_delete_block(block, 1);
 	up(&file->f_sema);
-	return nlm_granted;
+	return nlm4_granted;
 }
 
 /*
@@ -523,7 +531,7 @@
 	nlmsvc_insert_block(block, jiffies + 30 * HZ);
 
 	/* Call the client */
-	nlmclnt_async_call(&block->b_call, NLMPROC_GRANTED_MSG,
+	nlmsvc_async_call(&block->b_call, NLMPROC_GRANTED_MSG,
 						nlmsvc_grant_callback);
 	up(&file->f_sema);
 }
@@ -544,6 +552,8 @@
 	unsigned long		timeout;
 
 	dprintk("lockd: GRANT_MSG RPC callback\n");
+	dprintk("callback: looking for cookie %x \n", 
+		*(u32 *)(call->a_args.cookie.data));
 	if (!(block = nlmsvc_find_block(&call->a_args.cookie))) {
 		dprintk("lockd: no block for cookie %x\n", *(u32 *)(call->a_args.cookie.data));
 		return;
@@ -567,7 +577,6 @@
 	block->b_incall = 0;
 
 	nlm_release_host(call->a_host);
-	rpc_release_task(task);
 }
 
 /*
@@ -620,7 +629,7 @@
 	dprintk("nlmsvc_retry_blocked(%p, when=%ld)\n",
 			nlm_blocked,
 			nlm_blocked? nlm_blocked->b_when : 0);
-	while ((block = nlm_blocked) && block->b_when < jiffies) {
+	while ((block = nlm_blocked) && block->b_when <= jiffies) {
 		dprintk("nlmsvc_retry_blocked(%p, when=%ld, done=%d)\n",
 			block, block->b_when, block->b_done);
 		if (block->b_done)
@@ -631,6 +640,5 @@
 
 	if ((block = nlm_blocked) && block->b_when != NLM_NEVER)
 		return (block->b_when - jiffies);
-
 	return MAX_SCHEDULE_TIMEOUT;
 }
Index: oldkernel/linux/fs/lockd/svcproc.c
diff -u linux/fs/lockd/svcproc.c:1.1.1.1 linux/fs/lockd/svcproc.c:1.2
--- linux/fs/lockd/svcproc.c:1.1.1.1	Wed May 31 12:33:48 2000
+++ linux/fs/lockd/svcproc.c	Fri Jul  7 15:36:45 2000
@@ -14,6 +14,8 @@
 #include <linux/sunrpc/svc.h>
 #include <linux/sunrpc/clnt.h>
 #include <linux/nfsd/nfsd.h>
+#include <linux/lockd/xdr.h>
+#include <linux/lockd/xdr4.h>
 #include <linux/lockd/lockd.h>
 #include <linux/lockd/share.h>
 #include <linux/lockd/sm_inter.h>
@@ -23,6 +25,7 @@
 
 static u32	nlmsvc_callback(struct svc_rqst *, u32, struct nlm_res *);
 static void	nlmsvc_callback_exit(struct rpc_task *);
+static u32	cast_to_nlm(u32, u32);
 
 /*
  * Obtain client and file from arguments
@@ -93,6 +96,7 @@
 {
 	struct nlm_host	*host;
 	struct nlm_file	*file;
+	u32 status;
 
 	dprintk("lockd: TEST          called\n");
 	resp->cookie = argp->cookie;
@@ -108,9 +112,12 @@
 		return rpc_success;
 
 	/* Now check for conflicting locks */
-	resp->status = nlmsvc_testlock(file, &argp->lock, &resp->lock);
+	status = nlmsvc_testlock(file, &argp->lock, &resp->lock);
+	dprintk("test: status before %ld\n", ntohl(status));
+	resp->status = cast_to_nlm(status, rqstp->rq_vers); 
 
-	dprintk("lockd: TEST          status %d\n", ntohl(resp->status));
+	dprintk("lockd: TEST          status %ld vers %d\n", 
+		ntohl(resp->status), rqstp->rq_vers);
 	nlm_release_host(host);
 	nlm_release_file(file);
 	return rpc_success;
@@ -122,6 +129,7 @@
 {
 	struct nlm_host	*host;
 	struct nlm_file	*file;
+	u32 status;
 
 	dprintk("lockd: LOCK          called\n");
 
@@ -150,8 +158,9 @@
 #endif
 
 	/* Now try to lock the file */
-	resp->status = nlmsvc_lock(rqstp, file, &argp->lock,
-					argp->block, &argp->cookie);
+	status = nlmsvc_lock(rqstp, file, &argp->lock, 
+				argp->block, &argp->cookie);
+	resp->status = cast_to_nlm(status, rqstp->rq_vers);
 
 	dprintk("lockd: LOCK          status %d\n", ntohl(resp->status));
 	nlm_release_host(host);
@@ -165,6 +174,7 @@
 {
 	struct nlm_host	*host;
 	struct nlm_file	*file;
+	u32 status;
 
 	dprintk("lockd: CANCEL        called\n");
 
@@ -181,7 +191,8 @@
 		return rpc_success;
 
 	/* Try to cancel request. */
-	resp->status = nlmsvc_cancel_blocked(file, &argp->lock);
+	status = nlmsvc_cancel_blocked(file, &argp->lock);
+	resp->status = cast_to_nlm(status, rqstp->rq_vers);
 
 	dprintk("lockd: CANCEL        status %d\n", ntohl(resp->status));
 	nlm_release_host(host);
@@ -198,6 +209,7 @@
 {
 	struct nlm_host	*host;
 	struct nlm_file	*file;
+	u32 status;
 
 	dprintk("lockd: UNLOCK        called\n");
 
@@ -214,7 +226,8 @@
 		return rpc_success;
 
 	/* Now try to remove the lock */
-	resp->status = nlmsvc_unlock(file, &argp->lock);
+	status = nlmsvc_unlock(file, &argp->lock);
+	resp->status = cast_to_nlm(status, rqstp->rq_vers);	
 
 	dprintk("lockd: UNLOCK        status %d\n", ntohl(resp->status));
 	nlm_release_host(host);
@@ -322,6 +335,7 @@
 {
 	struct nlm_host	*host;
 	struct nlm_file	*file;
+	u32 status;
 
 	dprintk("lockd: SHARE         called\n");
 
@@ -338,7 +352,8 @@
 		return rpc_success;
 
 	/* Now try to create the share */
-	resp->status = nlmsvc_share_file(host, file, argp);
+	status = nlmsvc_share_file(host, file, argp);
+	resp->status = cast_to_nlm(status, rqstp->rq_vers);
 
 	dprintk("lockd: SHARE         status %d\n", ntohl(resp->status));
 	nlm_release_host(host);
@@ -355,6 +370,7 @@
 {
 	struct nlm_host	*host;
 	struct nlm_file	*file;
+	u32 status;
 
 	dprintk("lockd: UNSHARE       called\n");
 
@@ -371,7 +387,8 @@
 		return rpc_success;
 
 	/* Now try to lock the file */
-	resp->status = nlmsvc_unshare_file(host, file, argp);
+	status = nlmsvc_unshare_file(host, file, argp);
+	resp->status = cast_to_nlm(status, rqstp->rq_vers);
 
 	dprintk("lockd: UNSHARE       status %d\n", ntohl(resp->status));
 	nlm_release_host(host);
@@ -476,7 +493,7 @@
 	call->a_host  = host;
 	memcpy(&call->a_args, resp, sizeof(*resp));
 
-	if (nlmclnt_async_call(call, proc, nlmsvc_callback_exit) < 0)
+	if (nlmsvc_async_call(call, proc, nlmsvc_callback_exit) < 0)
 		return rpc_system_err;
 
 	return rpc_success;
@@ -492,10 +509,30 @@
 					task->tk_pid, -task->tk_status);
 	}
 	nlm_release_host(call->a_host);
-	rpc_release_task(task);
 	kfree(call);
 }
 
+static u32
+cast_to_nlm(u32 status, u32 vers)
+{
+
+	if (vers != 4){
+		switch(ntohl(status)){
+		case NLM_LCK_GRANTED:
+		case NLM_LCK_DENIED:
+		case NLM_LCK_DENIED_NOLOCKS:
+		case NLM_LCK_BLOCKED:
+		case NLM_LCK_DENIED_GRACE_PERIOD:
+			break;
+		default:
+			status = NLM_LCK_DENIED_NOLOCKS;
+		}
+	}
+
+	return (status);
+	
+}
+	
 /*
  * NLM Server procedures.
  */
Index: oldkernel/linux/fs/lockd/svcshare.c
diff -u linux/fs/lockd/svcshare.c:1.1.1.1 linux/fs/lockd/svcshare.c:1.2
--- linux/fs/lockd/svcshare.c:1.1.1.1	Wed May 31 12:33:48 2000
+++ linux/fs/lockd/svcshare.c	Fri Jul  7 15:36:45 2000
@@ -12,6 +12,7 @@
 
 #include <linux/sunrpc/clnt.h>
 #include <linux/sunrpc/svc.h>
+#include <linux/lockd/xdr4.h>
 #include <linux/lockd/lockd.h>
 #include <linux/lockd/share.h>
 
@@ -35,13 +36,13 @@
 			goto update;
 		if ((argp->fsm_access & share->s_mode)
 		 || (argp->fsm_mode   & share->s_access ))
-			return nlm_lck_denied;
+			return nlm4_lck_denied;
 	}
 
 	share = (struct nlm_share *) kmalloc(sizeof(*share) + oh->len,
 						GFP_KERNEL);
 	if (share == NULL)
-		return nlm_lck_denied_nolocks;
+		return nlm4_lck_denied_nolocks;
 
 	/* Copy owner handle */
 	ohdata = (u8 *) (share + 1);
@@ -58,7 +59,7 @@
 update:
 	share->s_access = argp->fsm_access;
 	share->s_mode   = argp->fsm_mode;
-	return nlm_granted;
+	return nlm4_granted;
 }
 
 /*
@@ -75,13 +76,13 @@
 		if (share->s_host == host && nlm_cmp_owner(share, oh)) {
 			*shpp = share->s_next;
 			kfree(share);
-			return nlm_granted;
+			return nlm4_granted;
 		}
 	}
 
 	/* X/Open spec says return success even if there was no
 	 * corresponding share. */
-	return nlm_granted;
+	return nlm4_granted;
 }
 
 /*
Index: oldkernel/linux/fs/lockd/svcsubs.c
diff -u linux/fs/lockd/svcsubs.c:1.1.1.1 linux/fs/lockd/svcsubs.c:1.2
--- linux/fs/lockd/svcsubs.c:1.1.1.1	Wed May 31 12:33:48 2000
+++ linux/fs/lockd/svcsubs.c	Fri Jul  7 15:36:45 2000
@@ -13,6 +13,7 @@
 #include <linux/sunrpc/clnt.h>
 #include <linux/nfsd/nfsfh.h>
 #include <linux/nfsd/export.h>
+#include <linux/lockd/xdr4.h>
 #include <linux/lockd/lockd.h>
 #include <linux/lockd/share.h>
 #include <linux/lockd/sm_inter.h>
@@ -48,7 +49,7 @@
 nlm_lookup_file(struct svc_rqst *rqstp, struct nlm_file **result,
 					struct nfs_fh *f)
 {
-	struct knfs_fh	*fh = (struct knfs_fh *) f;
+	struct knfs_fh	*fh = (struct knfs_fh *) f->data;
 	struct nlm_file	*file;
 	unsigned int	hash;
 	u32		nfserr;
@@ -69,7 +70,7 @@
 
 	dprintk("lockd: creating file for %s/%u\n",
 		kdevname(u32_to_kdev_t(fh->fh_dev)), fh->fh_ino);
-	nfserr = nlm_lck_denied_nolocks;
+	nfserr = nlm4_lck_denied_nolocks;
 	file = (struct nlm_file *) kmalloc(sizeof(*file), GFP_KERNEL);
 	if (!file)
 		goto out_unlock;
@@ -104,7 +105,10 @@
 
 out_free:
 	kfree(file);
-	nfserr = nlm_lck_denied;
+        if (nfserr == 1)
+                nfserr = nlm4_stale_fh;
+        else
+		nfserr = nlm4_lck_denied;
 	goto out_unlock;
 }
 
Index: oldkernel/linux/fs/lockd/xdr.c
diff -u linux/fs/lockd/xdr.c:1.2 linux/fs/lockd/xdr.c:1.3
--- linux/fs/lockd/xdr.c:1.2	Thu Jun  1 15:03:08 2000
+++ linux/fs/lockd/xdr.c	Fri Jul  7 15:36:45 2000
@@ -15,11 +15,13 @@
 #include <linux/sunrpc/clnt.h>
 #include <linux/sunrpc/svc.h>
 #include <linux/sunrpc/stats.h>
+#include <linux/lockd/xdr4.h>
 #include <linux/lockd/lockd.h>
 #include <linux/lockd/sm_inter.h>
 
 #define NLMDBG_FACILITY		NLMDBG_XDR
 #define NLM_MAXSTRLEN		1024
+#define OFFSET_MAX		LONG_MAX
 
 #define QUADLEN(len)		(((len) + 3) >> 2)
 
@@ -29,6 +31,8 @@
 
 
 typedef struct nlm_args	nlm_args;
+static void nlm_register_stats(void);
+static void nlm_unregister_stats(void);
 
 /*
  * Initialization of NFS status variables
@@ -47,7 +51,26 @@
 	nlm_lck_blocked = htonl(NLM_LCK_BLOCKED);
 	nlm_lck_denied_grace_period = htonl(NLM_LCK_DENIED_GRACE_PERIOD);
 
+        nlm4_granted = htonl(NLM_LCK_GRANTED);
+        nlm4_lck_denied = htonl(NLM_LCK_DENIED);
+        nlm4_lck_denied_nolocks = htonl(NLM_LCK_DENIED_NOLOCKS);
+        nlm4_lck_blocked = htonl(NLM_LCK_BLOCKED);
+        nlm4_lck_denied_grace_period = htonl(NLM_LCK_DENIED_GRACE_PERIOD);
+	nlm4_deadlock = htonl(NLM_DEADLCK);
+	nlm4_rofs = htonl(NLM_ROFS);
+	nlm4_stale_fh = htonl(NLM_STALE_FH);
+	nlm4_fbig = htonl(NLM_FBIG);
+	nlm4_failed = htonl(NLM_FAILED);
+
 	inited = 1;
+
+	nlm_register_stats();
+}
+
+void
+nlmxdr_shutdown(void)
+{
+	nlm_unregister_stats();
 }
 
 /*
@@ -93,22 +116,23 @@
 {
 	unsigned int	len;
 
-	if ((len = ntohl(*p++)) != sizeof(*f)) {
+	if ((len = ntohl(*p++)) != NFS2_FHSIZE) {
 		printk(KERN_NOTICE
 			"lockd: bad fhandle size %x (should be %d)\n",
-			len, sizeof(*f));
+			len, NFS2_FHSIZE);
 		return NULL;
 	}
-	memcpy(f, p, sizeof(*f));
-	return p + XDR_QUADLEN(sizeof(*f));
+	f->size = NFS2_FHSIZE;
+	memcpy(f->data, p, NFS2_FHSIZE);
+	return p + XDR_QUADLEN(NFS2_FHSIZE);
 }
 
 static inline u32 *
 nlm_encode_fh(u32 *p, struct nfs_fh *f)
 {
-	*p++ = htonl(sizeof(*f));
-	memcpy(p, f, sizeof(*f));
-	return p + XDR_QUADLEN(sizeof(*f));
+	*p++ = htonl(NFS2_FHSIZE);
+	memcpy(p, f->data, NFS2_FHSIZE);
+	return p + XDR_QUADLEN(NFS2_FHSIZE);
 }
 
 /*
@@ -142,10 +166,10 @@
 	fl->fl_pid   = ntohl(*p++);
 	fl->fl_flags = FL_POSIX;
 	fl->fl_type  = F_RDLCK;		/* as good as anything else */
-	fl->fl_start = (u_long)ntohl(*p++);
+	fl->fl_start = ntohl(*p++);
 	len = ntohl(*p++);
 	if (len == 0 || (fl->fl_end = fl->fl_start + len - 1) < 0)
-		fl->fl_end = NLM_OFFSET_MAX;
+		fl->fl_end = OFFSET_MAX;
 	return p;
 }
 
@@ -157,17 +181,21 @@
 {
 	struct file_lock	*fl = &lock->fl;
 
-	if (!(p = xdr_encode_string(p, lock->caller))
+	if (!(p = xdr_encode_string(p, lock->caller, -1))
 	 || !(p = nlm_encode_fh(p, &lock->fh))
 	 || !(p = nlm_encode_oh(p, &lock->oh)))
 		return NULL;
 
+	if (fl->fl_start > NLM_OFFSET_MAX
+	 || (fl->fl_end > NLM_OFFSET_MAX && fl->fl_end != OFFSET_MAX))
+		return NULL;
+
 	*p++ = htonl(fl->fl_pid);
-	*p++ = htonl((u_long)lock->fl.fl_start);
-	if (lock->fl.fl_end == NLM_OFFSET_MAX)
+	*p++ = htonl(fl->fl_start);
+	if (fl->fl_end == OFFSET_MAX)
 		*p++ = xdr_zero;
 	else
-		*p++ = htonl((u_long)(lock->fl.fl_end - lock->fl.fl_start + 1));
+		*p++ = htonl(fl->fl_end - fl->fl_start + 1);
 
 	return p;
 }
@@ -192,11 +220,11 @@
 		if (!(p = xdr_encode_netobj(p, &resp->lock.oh)))
 			return 0;
 
-		*p++ = htonl((u_long)fl->fl_start);
-		if (fl->fl_end == NLM_OFFSET_MAX)
+		*p++ = htonl(fl->fl_start);
+		if (fl->fl_end == OFFSET_MAX)
 			*p++ = xdr_zero;
 		else
-			*p++ = htonl((u_long)(fl->fl_end - fl->fl_start + 1));
+			*p++ = htonl(fl->fl_end - fl->fl_start + 1);
 	}
 
 	return p;
@@ -425,10 +453,10 @@
 
 		fl->fl_flags = FL_POSIX;
 		fl->fl_type  = excl? F_WRLCK : F_RDLCK;
-		fl->fl_start = (u_long)ntohl(*p++);
+		fl->fl_start = ntohl(*p++);
 		len = ntohl(*p++);
 		if (len == 0 || (fl->fl_end = fl->fl_start + len - 1) < 0)
-			fl->fl_end = NLM_OFFSET_MAX;
+			fl->fl_end = OFFSET_MAX;
 	}
 	return 0;
 }
@@ -512,10 +540,10 @@
  */
 #define NLM_void_sz		0
 #define NLM_cookie_sz		3	/* 1 len , 2 data */
-#define NLM_caller_sz		1+QUADLEN(sizeof(system_utsname.nodename))
+#define NLM_caller_sz		1+QUADLEN(NLM_MAXSTRLEN)
 #define NLM_netobj_sz		1+QUADLEN(XDR_MAX_NETOBJ)
 /* #define NLM_owner_sz		1+QUADLEN(NLM_MAXOWNER) */
-#define NLM_fhandle_sz		1+QUADLEN(NFS_FHSIZE)
+#define NLM_fhandle_sz		1+QUADLEN(NFS2_FHSIZE)
 #define NLM_lock_sz		3+NLM_caller_sz+NLM_netobj_sz+NLM_fhandle_sz
 #define NLM_holder_sz		4+NLM_netobj_sz
 
@@ -541,7 +569,8 @@
     { "nlm_" #proc,						\
       (kxdrproc_t) nlmclt_encode_##argtype,			\
       (kxdrproc_t) nlmclt_decode_##restype,			\
-      MAX(NLM_##argtype##_sz, NLM_##restype##_sz) << 2		\
+      MAX(NLM_##argtype##_sz, NLM_##restype##_sz) << 2,		\
+      0                                                         \
     }
 
 static struct rpc_procinfo	nlm_procedures[] = {
@@ -586,14 +615,21 @@
 	3, 24, nlm_procedures,
 };
 
+#ifdef CONFIG_NFS_V3
+extern struct rpc_version nlm_version4;
+#endif
+
 static struct rpc_version *	nlm_versions[] = {
 	NULL,
 	&nlm_version1,
 	NULL,
 	&nlm_version3,
+#ifdef CONFIG_NFS_V3
+	&nlm_version4,
+#endif
 };
 
-static struct rpc_stat		nlm_stats;
+static struct rpc_stat		nlm_stats = { &nlm_program };
 
 struct rpc_program		nlm_program = {
 	"lockd",
@@ -613,3 +649,13 @@
 }
 #endif
 
+static void nlm_register_stats(void) {
+#ifdef CONFIG_PROC_FS
+	rpc_proc_register(&nlm_stats);
+#endif
+}
+static void nlm_unregister_stats(void) {
+#ifdef CONFIG_PROC_FS
+	rpc_proc_unregister("lockd");
+#endif
+}
Index: oldkernel/linux/fs/lockd/xdr4.c
diff -u /dev/null linux/fs/lockd/xdr4.c:1.1
--- /dev/null	Mon Jul 31 21:15:08 2000
+++ linux/fs/lockd/xdr4.c	Fri Jul  7 16:18:17 2000
@@ -0,0 +1,592 @@
+/*
+ * linux/fs/lockd/xdr4.c
+ *
+ * XDR support for lockd and the lock client.
+ *
+ * Copyright (C) 1995, 1996 Olaf Kirch <okir@monad.swb.de>
+ * Copyright (C) 1999, Trond Myklebust <trond.myklebust@fys.uio.no>
+ */
+
+#include <linux/types.h>
+#include <linux/sched.h>
+#include <linux/utsname.h>
+#include <linux/nfs.h>
+
+#include <linux/sunrpc/xdr.h>
+#include <linux/sunrpc/clnt.h>
+#include <linux/sunrpc/svc.h>
+#include <linux/sunrpc/stats.h>
+#include <linux/lockd/lockd.h>
+#include <linux/lockd/sm_inter.h>
+
+#define NLMDBG_FACILITY		NLMDBG_XDR
+#define NLM_MAXSTRLEN		1024
+#define OFFSET_MAX		((off_t)LONG_MAX)
+
+#define QUADLEN(len)		(((len) + 3) >> 2)
+
+u32      nlm4_granted, nlm4_lck_denied, nlm4_lck_denied_nolocks,
+         nlm4_lck_blocked, nlm4_lck_denied_grace_period, nlm4_deadlock,
+         nlm4_rofs, nlm4_stale_fh, nlm4_fbig, nlm4_failed;
+
+
+typedef struct nlm_args	nlm_args;
+
+static inline off_t
+size_to_off_t(__s64 size)
+{
+        size = (size > (__s64)LONG_MAX) ? (off_t)LONG_MAX : (off_t) size;
+        return (size < (__s64)-LONG_MAX) ? (off_t)-LONG_MAX : (off_t) size;
+}
+
+/*
+ * XDR functions for basic NLM types
+ */
+static u32 *
+nlm4_decode_cookie(u32 *p, struct nlm_cookie *c)
+{
+	unsigned int	len;
+
+	len = ntohl(*p++);
+	
+	if(len==0)
+	{
+		c->len=4;
+		memset(c->data, 0, 4);	/* hockeypux brain damage */
+	}
+	else if(len<=8)
+	{
+		c->len=len;
+		memcpy(c->data, p, len);
+		p+=(len+3)>>2;
+	}
+	else 
+	{
+		printk(KERN_NOTICE
+			"lockd: bad cookie size %d (only cookies under 8 bytes are supported.)\n", len);
+		return NULL;
+	}
+	return p;
+}
+
+static u32 *
+nlm4_encode_cookie(u32 *p, struct nlm_cookie *c)
+{
+	*p++ = htonl(c->len);
+	memcpy(p, c->data, c->len);
+	p+=(c->len+3)>>2;
+	return p;
+}
+
+static u32 *
+nlm4_decode_fh(u32 *p, struct nfs_fh *f)
+{
+	memset(f->data, 0, sizeof(f->data));
+	f->size = ntohl(*p++);
+	if (f->size > NFS_MAXFHSIZE) {
+		printk(KERN_NOTICE
+			"lockd: bad fhandle size %x (should be %d)\n",
+			f->size, NFS_MAXFHSIZE);
+		return NULL;
+	}
+      	memcpy(f->data, p, f->size);
+	return p + XDR_QUADLEN(f->size);
+}
+
+static u32 *
+nlm4_encode_fh(u32 *p, struct nfs_fh *f)
+{
+	*p++ = htonl(f->size);
+	memcpy(p, f->data, f->size);
+	return p + XDR_QUADLEN(f->size);
+}
+
+/*
+ * Encode and decode owner handle
+ */
+static u32 *
+nlm4_decode_oh(u32 *p, struct xdr_netobj *oh)
+{
+	return xdr_decode_netobj(p, oh);
+}
+
+static u32 *
+nlm4_encode_oh(u32 *p, struct xdr_netobj *oh)
+{
+	return xdr_encode_netobj(p, oh);
+}
+
+static u32 *
+nlm4_decode_lock(u32 *p, struct nlm_lock *lock)
+{
+	struct file_lock	*fl = &lock->fl;
+	__s64			len, start, end;
+	int			tmp;
+
+	if (!(p = xdr_decode_string(p, &lock->caller, &tmp, NLM_MAXSTRLEN))
+	 || !(p = nlm4_decode_fh(p, &lock->fh))
+	 || !(p = nlm4_decode_oh(p, &lock->oh)))
+		return NULL;
+
+	memset(fl, 0, sizeof(*fl));
+	fl->fl_owner = current->files;
+	fl->fl_pid   = ntohl(*p++);
+	fl->fl_flags = FL_POSIX;
+	fl->fl_type  = F_RDLCK;		/* as good as anything else */
+	p = xdr_decode_hyper(p, &start);
+	p = xdr_decode_hyper(p, &len);
+	end = start + len - 1;
+
+	fl->fl_start = size_to_off_t(start);
+	fl->fl_end = size_to_off_t(end);
+
+	if (len == 0 || fl->fl_end < 0)
+		fl->fl_end = OFFSET_MAX;
+	return p;
+}
+
+/*
+ * Encode a lock as part of an NLM call
+ */
+static u32 *
+nlm4_encode_lock(u32 *p, struct nlm_lock *lock)
+{
+	struct file_lock	*fl = &lock->fl;
+
+	if (!(p = xdr_encode_string(p, lock->caller, -1))
+	 || !(p = nlm4_encode_fh(p, &lock->fh))
+	 || !(p = nlm4_encode_oh(p, &lock->oh)))
+		return NULL;
+
+	*p++ = htonl(fl->fl_pid);
+	p = xdr_encode_hyper(p, fl->fl_start);
+	if (fl->fl_end == OFFSET_MAX)
+		p = xdr_encode_hyper(p, 0);
+	else
+		p = xdr_encode_hyper(p, fl->fl_end - fl->fl_start + 1);
+
+	return p;
+}
+
+/*
+ * Encode result of a TEST/TEST_MSG call
+ */
+static u32 *
+nlm4_encode_testres(u32 *p, struct nlm_res *resp)
+{
+
+	dprintk("xdr: before encode_testres (p %p resp %p)\n", p, resp);
+	if (!(p = nlm4_encode_cookie(p, &resp->cookie)))
+		return 0;
+	*p++ = resp->status;
+
+	if (resp->status == nlm4_lck_denied) {
+		struct file_lock	*fl = &resp->lock.fl;
+
+		*p++ = (fl->fl_type == F_RDLCK)? xdr_zero : xdr_one;
+		*p++ = htonl(fl->fl_pid);
+
+		/* Encode owner handle. */
+		if (!(p = xdr_encode_netobj(p, &resp->lock.oh)))
+			return 0;
+
+		p = xdr_encode_hyper(p, fl->fl_start);
+		if (fl->fl_end == OFFSET_MAX)
+			p = xdr_encode_hyper(p, 0);
+		else
+			p = xdr_encode_hyper(p, fl->fl_end - fl->fl_start + 1);
+		dprintk("xdr: encode_testres (status %d pid %d type %d start %ld end %ld)\n", resp->status, fl->fl_pid, fl->fl_type, fl->fl_start,  fl->fl_end);
+
+
+	}
+
+	dprintk("xdr: after encode_testres (p %p resp %p)\n", p, resp);
+	return p;
+}
+
+
+/*
+ * Check buffer bounds after decoding arguments
+ */
+static int
+xdr_argsize_check(struct svc_rqst *rqstp, u32 *p)
+{
+	struct svc_buf	*buf = &rqstp->rq_argbuf;
+
+	return p - buf->base <= buf->buflen;
+}
+
+static int
+xdr_ressize_check(struct svc_rqst *rqstp, u32 *p)
+{
+	struct svc_buf	*buf = &rqstp->rq_resbuf;
+
+	buf->len = p - buf->base;
+	return (buf->len <= buf->buflen);
+}
+
+/*
+ * First, the server side XDR functions
+ */
+int
+nlm4svc_decode_testargs(struct svc_rqst *rqstp, u32 *p, nlm_args *argp)
+{
+	u32	exclusive;
+
+	if (!(p = nlm4_decode_cookie(p, &argp->cookie)))
+		return 0;
+
+	exclusive = ntohl(*p++);
+	if (!(p = nlm4_decode_lock(p, &argp->lock)))
+		return 0;
+	if (exclusive)
+		argp->lock.fl.fl_type = F_WRLCK;
+
+	return xdr_argsize_check(rqstp, p);
+}
+
+int
+nlm4svc_encode_testres(struct svc_rqst *rqstp, u32 *p, struct nlm_res *resp)
+{
+	if (!(p = nlm4_encode_testres(p, resp)))
+		return 0;
+	return xdr_ressize_check(rqstp, p);
+}
+
+int
+nlm4svc_decode_lockargs(struct svc_rqst *rqstp, u32 *p, nlm_args *argp)
+{
+	u32	exclusive;
+
+	if (!(p = nlm4_decode_cookie(p, &argp->cookie)))
+		return 0;
+	argp->block  = ntohl(*p++);
+	exclusive    = ntohl(*p++);
+	if (!(p = nlm4_decode_lock(p, &argp->lock)))
+		return 0;
+	if (exclusive)
+		argp->lock.fl.fl_type = F_WRLCK;
+	argp->reclaim = ntohl(*p++);
+	argp->state   = ntohl(*p++);
+	argp->monitor = 1;		/* monitor client by default */
+
+	return xdr_argsize_check(rqstp, p);
+}
+
+int
+nlm4svc_decode_cancargs(struct svc_rqst *rqstp, u32 *p, nlm_args *argp)
+{
+	u32	exclusive;
+
+	if (!(p = nlm4_decode_cookie(p, &argp->cookie)))
+		return 0;
+	argp->block = ntohl(*p++);
+	exclusive = ntohl(*p++);
+	if (!(p = nlm4_decode_lock(p, &argp->lock)))
+		return 0;
+	if (exclusive)
+		argp->lock.fl.fl_type = F_WRLCK;
+	return xdr_argsize_check(rqstp, p);
+}
+
+int
+nlm4svc_decode_unlockargs(struct svc_rqst *rqstp, u32 *p, nlm_args *argp)
+{
+	if (!(p = nlm4_decode_cookie(p, &argp->cookie))
+	 || !(p = nlm4_decode_lock(p, &argp->lock)))
+		return 0;
+	argp->lock.fl.fl_type = F_UNLCK;
+	return xdr_argsize_check(rqstp, p);
+}
+
+int
+nlm4svc_decode_shareargs(struct svc_rqst *rqstp, u32 *p, nlm_args *argp)
+{
+	struct nlm_lock	*lock = &argp->lock;
+	int		len;
+
+	memset(lock, 0, sizeof(*lock));
+	lock->fl.fl_pid = ~(u32) 0;
+
+	if (!(p = nlm4_decode_cookie(p, &argp->cookie))
+	 || !(p = xdr_decode_string(p, &lock->caller, &len, NLM_MAXSTRLEN))
+	 || !(p = nlm4_decode_fh(p, &lock->fh))
+	 || !(p = nlm4_decode_oh(p, &lock->oh)))
+		return 0;
+	argp->fsm_mode = ntohl(*p++);
+	argp->fsm_access = ntohl(*p++);
+	return xdr_argsize_check(rqstp, p);
+}
+
+int
+nlm4svc_encode_shareres(struct svc_rqst *rqstp, u32 *p, struct nlm_res *resp)
+{
+	if (!(p = nlm4_encode_cookie(p, &resp->cookie)))
+		return 0;
+	*p++ = resp->status;
+	*p++ = xdr_zero;		/* sequence argument */
+	return xdr_ressize_check(rqstp, p);
+}
+
+int
+nlm4svc_encode_res(struct svc_rqst *rqstp, u32 *p, struct nlm_res *resp)
+{
+	if (!(p = nlm4_encode_cookie(p, &resp->cookie)))
+		return 0;
+	*p++ = resp->status;
+	return xdr_ressize_check(rqstp, p);
+}
+
+int
+nlm4svc_decode_notify(struct svc_rqst *rqstp, u32 *p, struct nlm_args *argp)
+{
+	struct nlm_lock	*lock = &argp->lock;
+	int		len;
+
+	if (!(p = xdr_decode_string(p, &lock->caller, &len, NLM_MAXSTRLEN)))
+		return 0;
+	argp->state = ntohl(*p++);
+	return xdr_argsize_check(rqstp, p);
+}
+
+int
+nlm4svc_decode_reboot(struct svc_rqst *rqstp, u32 *p, struct nlm_reboot *argp)
+{
+	if (!(p = xdr_decode_string(p, &argp->mon, &argp->len, SM_MAXSTRLEN)))
+		return 0;
+	argp->state = ntohl(*p++);
+	argp->addr = ntohl(*p++);
+	return xdr_argsize_check(rqstp, p);
+}
+
+int
+nlm4svc_decode_res(struct svc_rqst *rqstp, u32 *p, struct nlm_res *resp)
+{
+	if (!(p = nlm4_decode_cookie(p, &resp->cookie)))
+		return 0;
+	resp->status = ntohl(*p++);
+	return xdr_argsize_check(rqstp, p);
+}
+
+int
+nlm4svc_decode_void(struct svc_rqst *rqstp, u32 *p, void *dummy)
+{
+	return xdr_argsize_check(rqstp, p);
+}
+
+int
+nlm4svc_encode_void(struct svc_rqst *rqstp, u32 *p, void *dummy)
+{
+	return xdr_ressize_check(rqstp, p);
+}
+
+/*
+ * Now, the client side XDR functions
+ */
+static int
+nlm4clt_encode_void(struct rpc_rqst *req, u32 *p, void *ptr)
+{
+	req->rq_slen = xdr_adjust_iovec(req->rq_svec, p);
+	return 0;
+}
+
+static int
+nlm4clt_decode_void(struct rpc_rqst *req, u32 *p, void *ptr)
+{
+	return 0;
+}
+
+static int
+nlm4clt_encode_testargs(struct rpc_rqst *req, u32 *p, nlm_args *argp)
+{
+	struct nlm_lock	*lock = &argp->lock;
+
+	if (!(p = nlm4_encode_cookie(p, &argp->cookie)))
+		return -EIO;
+	*p++ = (lock->fl.fl_type == F_WRLCK)? xdr_one : xdr_zero;
+	if (!(p = nlm4_encode_lock(p, lock)))
+		return -EIO;
+	req->rq_slen = xdr_adjust_iovec(req->rq_svec, p);
+	return 0;
+}
+
+static int
+nlm4clt_decode_testres(struct rpc_rqst *req, u32 *p, struct nlm_res *resp)
+{
+	if (!(p = nlm4_decode_cookie(p, &resp->cookie)))
+		return -EIO;
+	resp->status = ntohl(*p++);
+	if (resp->status == NLM_LCK_DENIED) {
+		struct file_lock	*fl = &resp->lock.fl;
+		u32			excl;
+		s64			start, end, len;
+
+		memset(&resp->lock, 0, sizeof(resp->lock));
+		excl = ntohl(*p++);
+		fl->fl_pid = ntohl(*p++);
+		if (!(p = nlm4_decode_oh(p, &resp->lock.oh)))
+			return -EIO;
+
+		fl->fl_flags = FL_POSIX;
+		fl->fl_type  = excl? F_WRLCK : F_RDLCK;
+		p = xdr_decode_hyper(p, &start);
+		p = xdr_decode_hyper(p, &len);
+		end = start + len - 1;
+
+		fl->fl_start = size_to_off_t(start);
+		fl->fl_end = size_to_off_t(end);
+		if (len == 0 || fl->fl_end < 0)
+			fl->fl_end = OFFSET_MAX;
+	}
+	return 0;
+}
+
+
+static int
+nlm4clt_encode_lockargs(struct rpc_rqst *req, u32 *p, nlm_args *argp)
+{
+	struct nlm_lock	*lock = &argp->lock;
+
+	if (!(p = nlm4_encode_cookie(p, &argp->cookie)))
+		return -EIO;
+	*p++ = argp->block? xdr_one : xdr_zero;
+	*p++ = (lock->fl.fl_type == F_WRLCK)? xdr_one : xdr_zero;
+	if (!(p = nlm4_encode_lock(p, lock)))
+		return -EIO;
+	*p++ = argp->reclaim? xdr_one : xdr_zero;
+	*p++ = htonl(argp->state);
+	req->rq_slen = xdr_adjust_iovec(req->rq_svec, p);
+	return 0;
+}
+
+static int
+nlm4clt_encode_cancargs(struct rpc_rqst *req, u32 *p, nlm_args *argp)
+{
+	struct nlm_lock	*lock = &argp->lock;
+
+	if (!(p = nlm4_encode_cookie(p, &argp->cookie)))
+		return -EIO;
+	*p++ = argp->block? xdr_one : xdr_zero;
+	*p++ = (lock->fl.fl_type == F_WRLCK)? xdr_one : xdr_zero;
+	if (!(p = nlm4_encode_lock(p, lock)))
+		return -EIO;
+	req->rq_slen = xdr_adjust_iovec(req->rq_svec, p);
+	return 0;
+}
+
+static int
+nlm4clt_encode_unlockargs(struct rpc_rqst *req, u32 *p, nlm_args *argp)
+{
+	struct nlm_lock	*lock = &argp->lock;
+
+	if (!(p = nlm4_encode_cookie(p, &argp->cookie)))
+		return -EIO;
+	if (!(p = nlm4_encode_lock(p, lock)))
+		return -EIO;
+	req->rq_slen = xdr_adjust_iovec(req->rq_svec, p);
+	return 0;
+}
+
+static int
+nlm4clt_encode_res(struct rpc_rqst *req, u32 *p, struct nlm_res *resp)
+{
+	if (!(p = nlm4_encode_cookie(p, &resp->cookie)))
+		return -EIO;
+	*p++ = resp->status;
+	req->rq_slen = xdr_adjust_iovec(req->rq_svec, p);
+	return 0;
+}
+
+static int
+nlm4clt_encode_testres(struct rpc_rqst *req, u32 *p, struct nlm_res *resp)
+{
+	if (!(p = nlm4_encode_testres(p, resp)))
+		return -EIO;
+	req->rq_slen = xdr_adjust_iovec(req->rq_svec, p);
+	return 0;
+}
+
+static int
+nlm4clt_decode_res(struct rpc_rqst *req, u32 *p, struct nlm_res *resp)
+{
+	if (!(p = nlm4_decode_cookie(p, &resp->cookie)))
+		return -EIO;
+	resp->status = ntohl(*p++);
+	return 0;
+}
+
+/*
+ * Buffer requirements for NLM
+ */
+#define NLM4_void_sz		0
+#define NLM4_cookie_sz		3	/* 1 len , 2 data */
+#define NLM4_caller_sz		1+XDR_QUADLEN(NLM_MAXSTRLEN)
+#define NLM4_netobj_sz		1+XDR_QUADLEN(XDR_MAX_NETOBJ)
+/* #define NLM4_owner_sz		1+XDR_QUADLEN(NLM4_MAXOWNER) */
+#define NLM4_fhandle_sz		1+XDR_QUADLEN(NFS3_FHSIZE)
+#define NLM4_lock_sz		5+NLM4_caller_sz+NLM4_netobj_sz+NLM4_fhandle_sz
+#define NLM4_holder_sz		6+NLM4_netobj_sz
+
+#define NLM4_testargs_sz	NLM4_cookie_sz+1+NLM4_lock_sz
+#define NLM4_lockargs_sz	NLM4_cookie_sz+4+NLM4_lock_sz
+#define NLM4_cancargs_sz	NLM4_cookie_sz+2+NLM4_lock_sz
+#define NLM4_unlockargs_sz	NLM4_cookie_sz+NLM4_lock_sz
+
+#define NLM4_testres_sz		NLM4_cookie_sz+1+NLM4_holder_sz
+#define NLM4_res_sz		NLM4_cookie_sz+1
+#define NLM4_norep_sz		0
+
+#ifndef MAX
+# define MAX(a,b)		(((a) > (b))? (a) : (b))
+#endif
+
+/*
+ * For NLM, a void procedure really returns nothing
+ */
+#define nlm4clt_decode_norep	NULL
+
+#define PROC(proc, argtype, restype)				\
+    { "nlm4_" #proc,						\
+      (kxdrproc_t) nlm4clt_encode_##argtype,			\
+      (kxdrproc_t) nlm4clt_decode_##restype,			\
+      MAX(NLM4_##argtype##_sz, NLM4_##restype##_sz) << 2,	\
+      0                                                         \
+    }
+
+static struct rpc_procinfo	nlm4_procedures[] = {
+    PROC(null,		void,		void),
+    PROC(test,		testargs,	testres),
+    PROC(lock,		lockargs,	res),
+    PROC(canc,		cancargs,	res),
+    PROC(unlock,	unlockargs,	res),
+    PROC(granted,	testargs,	res),
+    PROC(test_msg,	testargs,	norep),
+    PROC(lock_msg,	lockargs,	norep),
+    PROC(canc_msg,	cancargs,	norep),
+    PROC(unlock_msg,	unlockargs,	norep),
+    PROC(granted_msg,	testargs,	norep),
+    PROC(test_res,	testres,	norep),
+    PROC(lock_res,	res,		norep),
+    PROC(canc_res,	res,		norep),
+    PROC(unlock_res,	res,		norep),
+    PROC(granted_res,	res,		norep),
+    PROC(undef,		void,		void),
+    PROC(undef,		void,		void),
+    PROC(undef,		void,		void),
+    PROC(undef,		void,		void),
+#ifdef NLMCLNT_SUPPORT_SHARES
+    PROC(share,		shareargs,	shareres),
+    PROC(unshare,	shareargs,	shareres),
+    PROC(nm_lock,	lockargs,	res),
+    PROC(free_all,	notify,		void),
+#else
+    PROC(undef,		void,		void),
+    PROC(undef,		void,		void),
+    PROC(undef,		void,		void),
+    PROC(undef,		void,		void),
+#endif
+};
+
+struct rpc_version	nlm_version4 = {
+	4, 24, nlm4_procedures,
+};
Index: oldkernel/linux/fs/minix/file.c
diff -u linux/fs/minix/file.c:1.2 linux/fs/minix/file.c:1.3
--- linux/fs/minix/file.c:1.2	Thu Jun  1 15:03:08 2000
+++ linux/fs/minix/file.c	Fri Jul  7 15:36:45 2000
@@ -70,7 +70,7 @@
 				size_t count, loff_t *ppos)
 {
 	struct inode * inode = filp->f_dentry->d_inode;
-	loff_t pos;
+	off_t pos;
 	ssize_t written, c;
 	struct buffer_head * bh;
 	char * p;
@@ -87,24 +87,6 @@
 		pos = inode->i_size;
 	else
 		pos = *ppos;
-
-	/* L-F-S spec 2.2.1.27: */
-	if (!(filp->f_flags & O_LARGEFILE)) {
-		if (pos >= 0x7ffffffeULL) /* pos@2G forbidden */
-			return -EFBIG;
-
-		if (pos + count >= 0x7fffffffULL)
-			/* Write only until end of allowed region */
-			count = 0x7fffffffULL - pos;
-	}
-	/* MINIX i-node file-size can't exceed 4G-1 */
-	/* With 1k blocks and triple indirection MINIX can have files
-	   up to 16 GB in size -- filesystem maximum is then 4G*1k = 4T */
-	if (pos >= 0xffffffffULL)
-		return -EFBIG; /* Absolutely too much! */
-	if ((pos + count) >= 0x100000000ULL) /* too much to write! */
-		count = 0xffffffffULL - pos;
-
 	written = 0;
 	while (written < count) {
 		bh = minix_getblk(inode,pos/BLOCK_SIZE,1);
Index: oldkernel/linux/fs/ncpfs/file.c
diff -u linux/fs/ncpfs/file.c:1.2 linux/fs/ncpfs/file.c:1.3
--- linux/fs/ncpfs/file.c:1.2	Thu Jun  1 15:03:08 2000
+++ linux/fs/ncpfs/file.c	Fri Jul  7 15:36:45 2000
@@ -17,7 +17,6 @@
 #include <linux/mm.h>
 #include <linux/locks.h>
 #include <linux/malloc.h>
-#include <linux/unistd.h>
 
 #include <linux/ncp_fs.h>
 #include "ncplib_kernel.h"
@@ -150,7 +149,7 @@
 	/* First read in as much as possible for each bufsize. */
 	while (already_read < count) {
 		int read_this_time;
-		size_t to_read = min(bufsize - (pos & (bufsize-1)),
+		size_t to_read = min(bufsize - (pos % bufsize),
 				  count - already_read);
 
 		error = ncp_read_bounce(NCP_SERVER(inode),
@@ -190,7 +189,7 @@
 	struct dentry *dentry = file->f_dentry;
 	struct inode *inode = dentry->d_inode;
 	size_t already_written = 0;
-	loff_t pos;
+	off_t pos;
 	size_t bufsize;
 	int errno;
 	void* bouncebuffer;
@@ -227,18 +226,12 @@
 
 	already_written = 0;
 
-	/* Maximum file size: 2G-1 */
-	if (pos >= 0x7fffffffULL)
-		return -EFBIG;
-	if ((pos + count) >= 0x7fffffffULL)
-		count = 0x7fffffffULL - pos;
-
 	bouncebuffer = kmalloc(bufsize, GFP_NFS);
 	if (!bouncebuffer)
 		return -EIO;	/* -ENOMEM */
 	while (already_written < count) {
 		int written_this_time;
-		size_t to_write = min(bufsize - (pos & (bufsize-1)),
+		size_t to_write = min(bufsize - (pos % bufsize),
 				   count - already_written);
 
 		if (copy_from_user(bouncebuffer, buf, to_write)) {
Index: oldkernel/linux/fs/ncpfs/inode.c
diff -u linux/fs/ncpfs/inode.c:1.2 linux/fs/ncpfs/inode.c:1.3
--- linux/fs/ncpfs/inode.c:1.2	Thu Jun  1 15:03:08 2000
+++ linux/fs/ncpfs/inode.c	Fri Jul  7 15:36:45 2000
@@ -132,7 +132,7 @@
 	}
 	inode->i_blocks = 0;
 	if ((inode->i_size)&&(inode->i_blksize)) {
-		inode->i_blocks = ((inode->i_size-1) >> fslog2(inode->i_blksize)) +1;
+		inode->i_blocks = (inode->i_size-1)/(inode->i_blksize)+1;
 	}
 
 	inode->i_mtime = ncp_date_dos2unix(le16_to_cpu(nwi->modifyTime),
@@ -203,7 +203,8 @@
 
 	inode->i_blocks = 0;
 	if ((inode->i_blksize != 0) && (inode->i_size != 0)) {
-		inode->i_blocks = ((inode->i_size - 1) >> fslog2(inode->i_blksize)) + 1;
+		inode->i_blocks =
+		    (inode->i_size - 1) / inode->i_blksize + 1;
 	}
 
 	inode->i_mtime = ncp_date_dos2unix(le16_to_cpu(nwi->modifyTime),
Index: oldkernel/linux/fs/nfs/Makefile
diff -u linux/fs/nfs/Makefile:1.1.1.1 linux/fs/nfs/Makefile:1.2
--- linux/fs/nfs/Makefile:1.1.1.1	Wed May 31 12:33:48 2000
+++ linux/fs/nfs/Makefile	Fri Jul  7 15:36:46 2000
@@ -9,10 +9,13 @@
 
 O_TARGET := nfs.o
 O_OBJS   := inode.o file.o read.o write.o dir.o symlink.o proc.o \
-	    nfs2xdr.o
+	    nfs2xdr.o flushd.o
 
 ifdef CONFIG_ROOT_NFS
   O_OBJS += nfsroot.o mount_clnt.o
+endif
+ifdef CONFIG_NFS_V3
+  O_OBJS += nfs3proc.o nfs3xdr.o
 endif
 
 M_OBJS   := $(O_TARGET)
Index: oldkernel/linux/fs/nfs/dir.c
diff -u linux/fs/nfs/dir.c:1.1.1.1 linux/fs/nfs/dir.c:1.2
--- linux/fs/nfs/dir.c:1.1.1.1	Wed May 31 12:33:48 2000
+++ linux/fs/nfs/dir.c	Fri Jul  7 15:36:46 2000
@@ -14,6 +14,9 @@
  *              Following Linus comments on my original hack, this version
  *              depends only on the dcache stuff and doesn't touch the inode
  *              layer (iput() and friends).
+ *  6 Jun 1999  Cache readdir lookups in the page cache. -DaveM
+ *  7 Oct 1999  Rewrite of Dave's readdir stuff for NFSv3 support, and in order
+ *              to simplify cookie handling. -Trond
  */
 
 #include <linux/sched.h>
@@ -25,31 +28,21 @@
 #include <linux/malloc.h>
 #include <linux/mm.h>
 #include <linux/sunrpc/types.h>
+#include <linux/nfs.h>
+#include <linux/nfs2.h>
+#include <linux/nfs3.h>
 #include <linux/nfs_fs.h>
+#include <linux/nfs_mount.h>
+#include <linux/sunrpc/auth.h>
+#include <linux/sunrpc/clnt.h>
 
 #include <asm/segment.h>	/* for fs functions */
 
 #define NFS_PARANOIA 1
 /* #define NFS_DEBUG_VERBOSE 1 */
 
-/*
- * Head for a dircache entry. Currently still very simple; when
- * the cache grows larger, we will need a LRU list.
- */
-struct nfs_dirent {
-	dev_t			dev;		/* device number */
-	ino_t			ino;		/* inode number */
-	u32			cookie;		/* cookie of first entry */
-	unsigned short		valid  : 1,	/* data is valid */
-				locked : 1;	/* entry locked */
-	unsigned int		size;		/* # of entries */
-	unsigned long		age;		/* last used */
-	unsigned long		mtime;		/* last attr stamp */
-	struct wait_queue *	wait;
-	__u32 *			entry;		/* three __u32's per entry */
-};
-
 static int nfs_safe_remove(struct dentry *);
+static int _nfs_safe_remove(struct dentry *, struct rpc_cred *);
 
 static ssize_t nfs_dir_read(struct file *, char *, size_t, loff_t *);
 static int nfs_readdir(struct file *, void *, filldir_t);
@@ -95,273 +88,405 @@
 	NULL,			/* writepage */
 	NULL,			/* bmap */
 	NULL,			/* truncate */
-	NULL,			/* permission */
+	nfs_permission,		/* permission */
 	NULL,			/* smap */
 	NULL,			/* updatepage */
 	nfs_revalidate,		/* revalidate */
 };
 
 static ssize_t
-nfs_dir_read(struct file *filp, char *buf, size_t count, loff_t *ppos)
+nfs_dir_read(struct file *file, char *buf, size_t count, loff_t *ppos)
 {
 	return -EISDIR;
 }
 
-static struct nfs_dirent	dircache[NFS_MAX_DIRCACHE];
+typedef u32 * (*decode_dirent_t)(u32 *, struct nfs_entry *, int);
 
 /*
- * We need to do caching of directory entries to prevent an
- * incredible amount of RPC traffic.  Only the most recent open
- * directory is cached.  This seems sufficient for most purposes.
- * Technically, we ought to flush the cache on close but this is
- * not a problem in practice.
+ * Given a pointer to a buffer that has already been filled by a call
+ * to readdir, find the next entry.
  *
- * XXX: Do proper directory caching by stuffing data into the
- * page cache (may require some fiddling for rsize < PAGE_SIZE).
+ * If the end of the buffer has been reached, return -EAGAIN, if not,
+ * return the offset within the buffer of the next entry to be
+ * read.
  */
-
-static int nfs_readdir(struct file *filp, void *dirent, filldir_t filldir)
-{
-	struct dentry 		*dentry = filp->f_dentry;
-	struct inode 		*inode = dentry->d_inode;
-	static struct wait_queue *readdir_wait = NULL;
-	struct wait_queue	**waitp = NULL;
-	struct nfs_dirent	*cache, *free;
-	unsigned long		age, dead;
-	u32			cookie;
-	int			ismydir, result;
-	int			i, j, index = 0;
-	__u32			*entry;
-	char			*name, *start;
+static inline
+long find_dirent(struct page *page, loff_t offset,
+		 struct nfs_entry *entry,
+		 decode_dirent_t decode, int plus, int use_cookie)
+{
+	u8		*p = (u8 *)page_address(page),
+			*start = p;
+	unsigned long	base = page_offset(page),
+			pg_offset = 0;
+	int		loop_count = 0;
+
+	if (!p)
+		return -EIO;
+	for(;;) {
+		u64 cookie;
+		p = (u8*)decode((__u32*)p, entry, plus);
+		if (IS_ERR(p))
+			break;
+		pg_offset = p - start;
+		entry->prev = entry->offset;
+		entry->offset = base + pg_offset;
+		cookie = use_cookie ? entry->cookie : entry->offset;
+		if (cookie > (u64)offset)
+			break;
+		if (loop_count++ > 200) {
+			loop_count = 0;
+			schedule();
+		}
+	}
 
-	dfprintk(VFS, "NFS: nfs_readdir(%s/%s)\n",
-		dentry->d_parent->d_name.name, dentry->d_name.name);
+	return (IS_ERR(p)) ?  PTR_ERR(p) : (long)pg_offset;
+}
 
-	result = nfs_revalidate_inode(NFS_DSERVER(dentry), dentry);
-	if (result < 0)
-		goto out;
+/*
+ * Find the given page, and call find_dirent() in order to try to
+ * return the next entry.
+ *
+ * Returns -EIO if the page is not available, or up to date.
+ */
+static inline
+long find_dirent_page(struct inode *inode, loff_t offset,
+		      struct nfs_entry *entry)
+{
+	decode_dirent_t	decode = NFS_PROTO(inode)->decode_dirent;
+	struct page	*page;
+	long		status = -EIO;
+	int		plus = NFS_USE_READDIRPLUS(inode),
+			use_cookie = NFS_MONOTONE_COOKIES(inode);
+
+	dfprintk(VFS, "NFS: find_dirent_page() searching directory page %ld\n", entry->offset & PAGE_CACHE_MASK);
+
+	if (entry->page)
+		page_cache_release(entry->page);
+
+	page = find_page(inode, entry->offset & PAGE_CACHE_MASK);
+	if (page && PageUptodate(page))
+		status = find_dirent(page, offset, entry, decode, plus, use_cookie);
+
+	/* NB: on successful return we will be holding the page */
+	if (status < 0) {
+		entry->page = NULL;
+		if (page)
+			page_cache_release(page);
+	} else
+		entry->page = page;
 
-	/*
-	 * Try to find the entry in the cache
-	 */
-again:
-	if (waitp) {
-		interruptible_sleep_on(waitp);
-		if (signal_pending(current))
-			return -ERESTARTSYS;
-		waitp = NULL;
-	}
+	dfprintk(VFS, "NFS: find_dirent_page() returns %ld\n", status);
+	return status;
+}
 
-	cookie = filp->f_pos;
-	entry  = NULL;
-	free   = NULL;
-	age    = ~(unsigned long) 0;
-	dead   = jiffies - NFS_ATTRTIMEO(inode);
 
-	for (i = 0, cache = dircache; i < NFS_MAX_DIRCACHE; i++, cache++) {
-		/*
-		dprintk("NFS: dircache[%d] valid %d locked %d\n",
-					i, cache->valid, cache->locked);
-		 */
-		ismydir = (cache->dev == inode->i_dev
-				&& cache->ino == inode->i_ino);
-		if (cache->locked) {
-			if (!ismydir || cache->cookie != cookie)
-				continue;
-			dfprintk(DIRCACHE, "NFS: waiting on dircache entry\n");
-			waitp = &cache->wait;
-			goto again;
+/*
+ * Recurse through the page cache pages, and return a
+ * filled nfs_entry structure of the next directory entry if possible.
+ *
+ * We start the search at position 'offset'.
+ */
+static inline
+long search_cached_dirent_pages(struct inode *inode, loff_t offset,
+				struct nfs_entry *entry)
+{
+	long		res = 0;
+	int		loop_count = 0;
+
+	dfprintk(VFS, "NFS: search_cached_dirent_pages() searching for cookie %Ld\n", (long long)offset);
+	for (;;) {
+		res = find_dirent_page(inode, offset, entry);
+		if (res == -EAGAIN) {
+			/* Align to beginning of next page */
+			entry->offset &= PAGE_CACHE_MASK;
+			entry->offset += PAGE_CACHE_SIZE;
 		}
-
-		if (ismydir && cache->mtime != inode->i_mtime)
-			cache->valid = 0;
-
-		if (!cache->valid || cache->age < dead) {
-			free = cache;
-			age  = 0;
-		} else if (cache->age < age) {
-			free = cache;
-			age  = cache->age;
+		if (res != -EAGAIN)
+			break;
+		if (loop_count++ > 200) {
+			loop_count = 0;
+			schedule();
 		}
+	}
+	if (res < 0 && entry->page) {
+		page_cache_release(entry->page);
+		entry->page = NULL;
+	}
+	dfprintk(VFS, "NFS: search_cached_dirent_pages() returned %ld\n", res);
+	return res;
+}
 
-		if (!ismydir || !cache->valid)
-			continue;
 
-		if (cache->cookie == cookie && cache->size > 0) {
-			entry = cache->entry + (index = 0);
-			cache->locked = 1;
-			break;
+/* Now we cache directories properly, by stuffing the dirent
+ * data directly in the page cache.
+ *
+ * Inode invalidation due to refresh etc. takes care of
+ * _everything_, no sloppy entry flushing logic, no extraneous
+ * copying, network direct to page cache, the way it was meant
+ * to be.
+ *
+ * NOTE: Dirent information verification is done always by the
+ *	 page-in of the RPC reply, nowhere else, this simplies
+ *	 things substantially.
+ */
+static inline
+long try_to_get_dirent_page(struct file *file, struct inode *inode,
+			    struct nfs_entry *entry)
+{
+	struct dentry	*dir = file->f_dentry;
+	struct page	*page;
+	struct rpc_cred	*cred = nfs_file_cred(file);
+	struct nfs_fattr	dir_attr;
+	__u32		*p;
+	unsigned long	offset = entry->offset;
+	long		res = 0;
+	unsigned int	dtsize = NFS_SERVER(inode)->dtsize;
+	int		plus = NFS_USE_READDIRPLUS(inode);
+
+	offset &= PAGE_CACHE_MASK;
+	dfprintk(VFS, "NFS: try_to_get_dirent_page() reading directory page @ offset %ld\n", offset);
+	page = nfs_grab_cache_page(inode, offset);
+
+	if (!page) {
+		res = -ENOMEM;
+		goto out;
+	}
+	if (PageUptodate(page)) {
+		dfprintk(VFS, "NFS: try_to_get_dirent_page(): page already up to date.\n");
+		goto unlock_out;
+	}
+
+	p = (__u32 *)page_address(page);
+
+	if (dtsize > PAGE_CACHE_SIZE)
+		dtsize = PAGE_CACHE_SIZE;
+	res = NFS_CALL(readdir, inode, (dir, &dir_attr, cred,
+					entry->cookie,
+					p, dtsize, plus));
+	if (res < 0)
+		goto error;
+	nfs_refresh_inode(inode, &dir_attr);
+	if (PageError(page))
+		clear_bit(PG_error, &page->flags);
+	set_bit(PG_uptodate, &page->flags);
+ unlock_out:
+	nfs_unlock_page(page);
+	page_cache_release(page);
+ out:
+	dfprintk(VFS, "NFS: try_to_get_dirent_page() returns %ld\n", res);
+	return res;
+
+ error:
+	set_bit(PG_error, &page->flags);
+	goto unlock_out;
+}
+
+/* Recover from a revalidation flush.  The case here is that
+ * the inode for the directory got invalidated somehow, and
+ * all of our cached information is lost.  In order to get
+ * a correct cookie for the current readdir request from the
+ * user, we must (re-)fetch all the older readdir page cache
+ * entries.
+ *
+ * Returns < 0 if some error occurs.
+ */
+static inline
+long refetch_to_readdir(struct file *file, struct inode *inode,
+			loff_t off, struct nfs_entry *entry)
+{
+	struct nfs_entry	my_dirent,
+				*dirent = &my_dirent;
+	long			res;
+	int			plus = NFS_USE_READDIRPLUS(inode),
+				use_cookie = NFS_MONOTONE_COOKIES(inode),
+				loop_count = 0;
+
+	dfprintk(VFS, "NFS: refetch_to_readdir() searching for cookie %Ld\n", (long long)off);
+	*dirent = *entry;
+	entry->page = NULL;
+
+	for (res = 0;res >= 0;) {
+		if (loop_count++ > 200) {
+			loop_count = 0;
+			schedule();
 		}
-		for (j = 0; j < cache->size; j++) {
-			__u32 *this_ent = cache->entry + j*3;
+
+		/* Search for last cookie in page cache */
+		res = search_cached_dirent_pages(inode, off, dirent);
 
-			if (*(this_ent+1) != cookie)
-				continue;
-			if (j < cache->size - 1) {
-				index = j + 1;
-				entry = this_ent + 3;
-			} else if (*(this_ent+2) & (1 << 15)) {
-				/* eof */
-				return 0;
+		if (res >= 0) {
+			u64 cookie = use_cookie ? dirent->cookie : (u64)dirent->offset;
+			/* Cookie was found */
+			if (cookie > (u64)off) {
+				*entry = *dirent;
+				dirent->page = NULL;
+				break;
 			}
-			break;
+			continue;
 		}
-		if (entry) {
-			dfprintk(DIRCACHE, "NFS: found dircache entry %d\n",
-						(int)(cache - dircache));
-			cache->locked = 1;
+
+		if (dirent->page)
+			page_cache_release(dirent->page);
+		dirent->page = NULL;
+
+		if (res != -EIO) {
+			*entry = *dirent;
 			break;
 		}
-	}
 
-	/*
-	 * Okay, entry not present in cache, or locked and inaccessible.
-	 * Set up the cache entry and attempt a READDIR call.
-	 */
-	if (entry == NULL) {
-		if ((cache = free) == NULL) {
-			dfprintk(DIRCACHE, "NFS: dircache contention\n");
-			waitp = &readdir_wait;
-			goto again;
+		/* Read in a new page */
+		res = try_to_get_dirent_page(file, inode, dirent);
+		if (res == -EBADCOOKIE) {
+			memset(dirent, 0, sizeof(*dirent));
+			nfs_zap_caches(inode);
+			res = 0;
 		}
-		dfprintk(DIRCACHE, "NFS: using free dircache entry %d\n",
-				(int)(free - dircache));
-		cache->cookie = cookie;
-		cache->locked = 1;
-		cache->valid  = 0;
-		cache->dev    = inode->i_dev;
-		cache->ino    = inode->i_ino;
-		if (!cache->entry) {
-			result = -ENOMEM;
-			cache->entry = (__u32 *) get_free_page(GFP_KERNEL);
-			if (!cache->entry)
-				goto done;
+		/* We requested READDIRPLUS, but the server doesn't grok it */
+		if (plus && res == -ENOTSUPP) {
+			NFS_FLAGS(inode) &= ~NFS_INO_ADVISE_RDPLUS;
+			memset(dirent, 0, sizeof(*dirent));
+			nfs_zap_caches(inode);
+			plus = 0;
+			res = 0;
 		}
-
-		result = nfs_proc_readdir(NFS_SERVER(inode), NFS_FH(dentry),
-					cookie, PAGE_SIZE, cache->entry);
-		if (result <= 0)
-			goto done;
-		cache->size  = result;
-		cache->valid = 1;
-		entry = cache->entry + (index = 0);
+		/* If we're using the page offset scheme, and the page cache
+		 * is invalidated, we just restart reading at the next entry
+		 * since the file position pointer is going to be screwed up
+		 * anyway */
+		if (!use_cookie && off > dirent->offset)
+			off = dirent->offset;
 	}
-	cache->mtime = inode->i_mtime;
-	cache->age = jiffies;
-
-	/*
-	 * Yowza! We have a cache entry...
-	 */
-	start = (char *) cache->entry;
-	while (index < cache->size) {
-		__u32	fileid  = *entry++;
-		__u32	nextpos = *entry++; /* cookie */
-		__u32	length  = *entry++;
+	if (dirent->page)
+		page_cache_release(dirent->page);
 
-		/*
-		 * Unpack the eof flag, offset, and length
-		 */
-		result = length & (1 << 15); /* eof flag */
-		name = start + ((length >> 16) & 0xFFFF);
-		length &= 0x7FFF;
-		/*
-		dprintk("NFS: filldir(%p, %.*s, %d, %d, %x, eof %x)\n", entry,
-				(int) length, name, length,
-				(unsigned int) filp->f_pos,
-				fileid, result);
-		 */
-
-		if (filldir(dirent, name, length, cookie, fileid) < 0)
-			break;
-		cookie = nextpos;
-		index++;
-	}
-	filp->f_pos = cookie;
-	result = 0;
-
-	/* XXX: May want to kick async readdir-ahead here. Not too hard
-	 * to do. */
-
-done:
-	dfprintk(DIRCACHE, "NFS: nfs_readdir complete\n");
-	cache->locked = 0;
-	wake_up(&cache->wait);
-	wake_up(&readdir_wait);
-
-out:
-	return result;
+	dfprintk(VFS, "NFS: refetch_to_readdir() returns %ld\n", res);
+	return res;
 }
 
 /*
- * Invalidate dircache entries for an inode.
+ * Once we've found the start of the dirent within a page: fill 'er up...
  */
-void
-nfs_invalidate_dircache(struct inode *inode)
+static
+int nfs_do_filldir(struct file *file, struct inode *inode,
+		   struct nfs_entry *entry, void *dirent, filldir_t filldir)
 {
-	struct nfs_dirent *cache = dircache;
-	dev_t		dev = inode->i_dev;
-	ino_t		ino = inode->i_ino;
-	int		i;
-
-	dfprintk(DIRCACHE, "NFS: invalidate dircache for %x/%ld\n", dev, (long)ino);
-	for (i = NFS_MAX_DIRCACHE; i--; cache++) {
-		if (cache->ino != ino)
-			continue;
-		if (cache->dev != dev)
-			continue;
-		if (cache->locked) {
-			printk("NFS: cache locked for %s/%ld\n",
-				kdevname(dev), (long) ino);
-			continue;
+	decode_dirent_t	decode = NFS_PROTO(inode)->decode_dirent;
+	struct page	*page = entry->page;
+	__u8		*p,
+			*start;
+	unsigned long	base = page_offset(page),
+			offset = entry->offset,
+			pg_offset;
+	ino_t		fileid;
+	int		plus = NFS_USE_READDIRPLUS(inode),
+			use_cookie = NFS_MONOTONE_COOKIES(inode),
+			loop_count = 0,
+			res = 0;
+
+	dfprintk(VFS, "NFS: nfs_do_filldir() filling starting @ offset %ld\n", entry->offset);
+	pg_offset = offset & ~PAGE_CACHE_MASK;
+	start = (u8*)page_address(page);
+	p = start + pg_offset;
+
+	for(;;) {
+		/* Note: entry->prev contains the offset of the start of the
+		 *       current dirent */
+		fileid = nfs_fileid_to_ino_t(entry->ino);
+		if (use_cookie)
+			res = filldir(dirent, entry->name, entry->len, entry->prev_cookie, fileid);
+		else
+			res = filldir(dirent, entry->name, entry->len, entry->prev, fileid);
+		if (res < 0)
+			break;
+		file->f_pos = (use_cookie) ? entry->cookie : entry->offset;
+		p = (u8*)decode((__u32*)p, entry, plus);
+		if (!p || IS_ERR(p))
+			break;
+		pg_offset = p - start;
+		entry->prev = entry->offset;
+		entry->offset = base + pg_offset;
+		/* Is the server violating our monotonicity assumption ? */
+		if (use_cookie && entry->prev_cookie > entry->cookie) {
+			use_cookie = 0;
+			NFS_SERVER(inode)->flags |= NFS_NONMONOTONE_COOKIES;
+			file->f_pos = 0;
+		}
+		if (loop_count++ > 200) {
+			loop_count = 0;
+			schedule();
 		}
-		cache->valid = 0;	/* brute force */
 	}
+
+	dfprintk(VFS, "NFS: nfs_do_filldir() filling ended @ offset %ld; returning = %d\n", entry->offset, res);
+	return res;
 }
 
-/*
- * Invalidate the dircache for a super block (or all caches),
- * and release the cache memory.
+/* The file offset position is now represented as a true offset into the
+ * page cache as is the case in most of the other filesystems.
  */
-void
-nfs_invalidate_dircache_sb(struct super_block *sb)
+static int nfs_readdir(struct file *filp, void *dirent, filldir_t filldir)
 {
-	struct nfs_dirent *cache = dircache;
-	int		i;
+	struct dentry	*dentry = filp->f_dentry;
+	struct inode	*inode = dentry->d_inode;
+	struct page	*page;
+	struct nfs_entry my_entry,
+			*entry = &my_entry;
+	loff_t		offset;
+	long		res;
+
+	res = nfs_revalidate_inode(dentry);
+	if (res < 0)
+		return res;
 
-	for (i = NFS_MAX_DIRCACHE; i--; cache++) {
-		if (sb && sb->s_dev != cache->dev)
-			continue;
-		if (cache->locked) {
-			printk("NFS: cache locked at umount %s\n",
-				(cache->entry ? "(lost a page!)" : ""));
-			continue;
+	/*
+	 * filp->f_pos points to the file offset in the page cache.
+	 * but if the cache has meanwhile been zapped, we need to
+	 * read from the last dirent to revalidate f_pos
+	 * itself.
+	 */
+	memset(entry, 0, sizeof(*entry));
+
+	offset = filp->f_pos;
+
+	while(!entry->eof) {
+		res = search_cached_dirent_pages(inode, offset, entry);
+
+		if (res < 0) {
+			if (entry->eof)
+				break;
+			res = refetch_to_readdir(filp, inode, offset, entry);
+			if (res < 0)
+				break;
 		}
-		cache->valid = 0;	/* brute force */
-		if (cache->entry) {
-			free_page((unsigned long) cache->entry);
-			cache->entry = NULL;
+
+		page = entry->page;
+		if (!page)
+			printk(KERN_ERR "NFS: Missing page...\n");
+		res = nfs_do_filldir(filp, inode, entry, dirent, filldir);
+		page_cache_release(page);
+		entry->page = NULL;
+		if (res < 0) {
+			res = 0;
+			break;
 		}
+		offset = filp->f_pos;
 	}
-}
-
-/*
- * Free directory cache memory
- * Called from cleanup_module
- */
-void
-nfs_free_dircache(void)
-{
-	dfprintk(DIRCACHE, "NFS: freeing dircache\n");
-	nfs_invalidate_dircache_sb(NULL);
+	if (entry->page)
+		page_cache_release(entry->page);
+	if (res < 0 && res != -EBADCOOKIE)
+		return res;
+	return 0;
 }
 
 /*
  * Whenever an NFS operation succeeds, we know that the dentry
  * is valid, so we update the revalidation timestamp.
  */
-static inline void nfs_renew_times(struct dentry * dentry)
+static inline void
+nfs_renew_times(struct dentry * dentry)
 {
-	dentry->d_time = jiffies;
+		dentry->d_time = jiffies;
 }
 
 static inline int nfs_dentry_force_reval(struct dentry *dentry, int flags)
@@ -384,7 +509,7 @@
 		if (diff < 15*60)
 			timeout = 0;
 	}
-	
+
 	return time_after(jiffies,dentry->d_time + timeout);
 }
 
@@ -398,8 +523,9 @@
 #define NFS_REVALIDATE_NEGATIVE (1 * HZ)
 static inline int nfs_neg_need_reval(struct dentry *dentry)
 {
-	unsigned long timeout = NFS_ATTRTIMEO(dentry->d_parent->d_inode);
-	long diff = CURRENT_TIME - dentry->d_parent->d_inode->i_mtime;
+	struct inode *dir = dentry->d_parent->d_inode;
+	unsigned long timeout = NFS_ATTRTIMEO(dir);
+	long diff = CURRENT_TIME - dir->i_mtime;
 
 	if (diff < 5*60 && timeout > NFS_REVALIDATE_NEGATIVE)
 		timeout = NFS_REVALIDATE_NEGATIVE;
@@ -421,11 +547,12 @@
  */
 static int nfs_lookup_revalidate(struct dentry * dentry, int flags)
 {
-	struct dentry * parent = dentry->d_parent;
-	struct inode * inode = dentry->d_inode;
+	struct dentry		*dir = dentry->d_parent;
+	struct inode		*inode = dentry->d_inode,
+				*dir_i = dir->d_inode;
+	struct nfs_fh		fhandle;
+	struct nfs_fattr	fattr, dir_attr;
 	int error;
-	struct nfs_fh fhandle;
-	struct nfs_fattr fattr;
 
 	/*
 	 * If we don't have an inode, let's look at the parent
@@ -440,39 +567,52 @@
 
 	if (is_bad_inode(inode)) {
 		dfprintk(VFS, "nfs_lookup_validate: %s/%s has dud inode\n",
-			parent->d_name.name, dentry->d_name.name);
+			dir->d_name.name, dentry->d_name.name);
 		goto out_bad;
 	}
 
-	if (IS_ROOT(dentry))
-		goto out_valid;
-
 	if (!nfs_dentry_force_reval(dentry, flags))
 		goto out_valid;
 
+	if (IS_ROOT(dentry)) {
+		__nfs_revalidate_inode(dentry);
+		goto out_valid_renew;
+	}
+
+	if (NFS_FLAGS(inode) & NFS_INO_STALE)
+		goto out_bad;
+
 	/*
 	 * Do a new lookup and check the dentry attributes.
 	 */
-	error = nfs_proc_lookup(NFS_DSERVER(parent), NFS_FH(parent),
-				dentry->d_name.name, &fhandle, &fattr);
-	if (error)
+	error = NFS_CALL(lookup, dir_i, (dir, &dir_attr,
+				  &dentry->d_name, &fhandle, &fattr));
+	if (error < 0)
 		goto out_bad;
 
 	/* Inode number matches? */
-	if (fattr.fileid != inode->i_ino)
+	if (!(fattr.valid & NFS_ATTR_FATTR) ||
+	    NFS_FSID(inode) != fattr.fsid ||
+	    NFS_FILEID(inode) != fattr.fileid)
 		goto out_bad;
 
 	/* Filehandle matches? */
-	if (memcmp(dentry->d_fsdata, &fhandle, sizeof(struct nfs_fh)))
+	if (NFS_FH(dentry)->size == 0)
+		goto out_bad;
+
+	if (NFS_FH(dentry)->size != fhandle.size ||
+	    memcmp(NFS_FH(dentry)->data, fhandle.data, fhandle.size))
 		goto out_bad;
 
 	/* Ok, remeber that we successfully checked it.. */
-	nfs_renew_times(dentry);
 	nfs_refresh_inode(inode, &fattr);
+	nfs_refresh_inode(dir_i, &dir_attr);
 
-out_valid:
+ out_valid_renew:
+	nfs_renew_times(dentry);
+ out_valid:
 	return 1;
-out_bad:
+ out_bad:
 	if (!list_empty(&dentry->d_subdirs))
 		shrink_dcache_parent(dentry);
 	/* If we have submounts, don't unhash ! */
@@ -480,9 +620,9 @@
 		goto out_valid;
 	d_drop(dentry);
 	if (dentry->d_parent->d_inode)
-		nfs_invalidate_dircache(dentry->d_parent->d_inode);
+		NFS_CACHEINV(dentry->d_parent->d_inode);
 	if (inode && S_ISDIR(inode->i_mode))
-		nfs_invalidate_dircache(inode);
+		NFS_CACHEINV(inode);
 	return 0;
 }
 
@@ -497,18 +637,45 @@
 		dentry->d_flags);
 
 	if (dentry->d_flags & DCACHE_NFSFS_RENAMED) {
+		struct rpc_auth *auth = NULL;
+		struct rpc_cred *cred = nfs_dentry_cred(dentry);
 		int error;
 		
 		dentry->d_flags &= ~DCACHE_NFSFS_RENAMED;
+		NFS_DENTRY(dentry)->cred = NULL;
+		if (dentry->d_inode)
+			auth = NFS_CLIENT(dentry->d_inode)->cl_auth;
 		/* Unhash it first */
 		d_drop(dentry);
-		error = nfs_safe_remove(dentry);
+		error = _nfs_safe_remove(dentry, cred);
+		if (cred && auth)
+			rpcauth_releasecred(auth, cred);
 		if (error)
-			printk("NFS: can't silly-delete %s/%s, error=%d\n",
+			printk(KERN_INFO "NFS: can't silly-delete %s/%s, error=%d\n",
 				dentry->d_parent->d_name.name,
 				dentry->d_name.name, error);
 	}
+}
+
+__inline__ struct nfs_dentry *nfs_fh_alloc(void)
+{
+	struct nfs_dentry *p;
 
+	p = kmalloc(sizeof(*p), GFP_KERNEL);
+	if (!p)
+		return NULL;
+	memset(p, 0, sizeof(*p));
+	p->magic = NFS_DENTRY_MAGIC;
+	return p;
+}
+
+__inline__ void nfs_fh_free(struct nfs_dentry *p)
+{
+	if (p->magic == NFS_DENTRY_MAGIC) {
+		p->magic = 0;
+		kfree(p);
+	} else
+		printk(KERN_ERR "NFS: corrupt dentry structure!\n");
 }
 
 /*
@@ -516,8 +683,10 @@
  */
 static void nfs_dentry_release(struct dentry *dentry)
 {
-	if (dentry->d_fsdata)
-		kfree(dentry->d_fsdata);
+	if (NFS_DENTRY(dentry)) {
+		nfs_fh_free(NFS_DENTRY(dentry));
+		NFS_DENTRY(dentry) = NULL;
+	}
 }
 
 struct dentry_operations nfs_dentry_operations = {
@@ -529,33 +698,44 @@
 	NULL			/* d_iput */
 };
 
-static struct dentry *nfs_lookup(struct inode *dir, struct dentry * dentry)
+static struct dentry *nfs_lookup(struct inode *dir_i, struct dentry * dentry)
 {
+	struct dentry *dir = dentry->d_parent;
 	struct inode *inode;
 	int error;
 	struct nfs_fh fhandle;
-	struct nfs_fattr fattr;
+	struct nfs_fattr fattr, dir_attr;
 
 	dfprintk(VFS, "NFS: lookup(%s/%s)\n",
 		dentry->d_parent->d_name.name, dentry->d_name.name);
 
 	error = -ENAMETOOLONG;
-	if (dentry->d_name.len > NFS_MAXNAMLEN)
+	if (dentry->d_name.len > NFS_SERVER(dir_i)->namelen)
 		goto out;
+
+	dentry->d_op = &nfs_dentry_operations;
 
-	error = -ENOMEM;
 	if (!dentry->d_fsdata) {
-		dentry->d_fsdata = kmalloc(sizeof(struct nfs_fh), GFP_KERNEL);
-		if (!dentry->d_fsdata)
+		dentry->d_fsdata = nfs_fh_alloc();
+		if (!dentry->d_fsdata) {
+			error = -ENOMEM;
 			goto out;
+		}
 	}
-	dentry->d_op = &nfs_dentry_operations;
 
-	error = nfs_proc_lookup(NFS_SERVER(dir), NFS_FH(dentry->d_parent), 
-				dentry->d_name.name, &fhandle, &fattr);
+#if NFS_FIXME
+	inode = nfs_dircache_lookup(dir_i, dentry);
+	if (inode)
+		goto no_entry;
+#endif
+
+	error = NFS_CALL(lookup, dir_i, (dir, &dir_attr,
+				 &dentry->d_name, &fhandle, &fattr));
+	nfs_refresh_inode(dir_i, &dir_attr);
 	inode = NULL;
 	if (error == -ENOENT)
 		goto no_entry;
+
 	if (!error) {
 		error = -EACCES;
 		inode = nfs_fhget(dentry, &fhandle, &fattr);
@@ -564,6 +744,8 @@
 			d_add(dentry, inode);
 			nfs_renew_times(dentry);
 			error = 0;
+			/* Sync any submount points with server */
+			vfsmnt_replace_mt_de(inode, dentry);
 		}
 	}
 out:
@@ -594,112 +776,143 @@
  * that the operation succeeded on the server, but an error in the
  * reply path made it appear to have failed.
  */
-static int nfs_create(struct inode *dir, struct dentry *dentry, int mode)
+static int nfs_create(struct inode *dir_i, struct dentry *dentry, int mode)
 {
-	int error;
-	struct nfs_sattr sattr;
-	struct nfs_fattr fattr;
-	struct nfs_fh fhandle;
+	struct dentry	*dir = dentry->d_parent;
+	struct iattr	 attr;
+	struct nfs_fattr fattr, dir_attr;
+	struct nfs_fh	 fhandle;
+	int		 error;
 
 	dfprintk(VFS, "NFS: create(%x/%ld, %s\n",
-		dir->i_dev, dir->i_ino, dentry->d_name.name);
+		dir_i->i_dev, dir_i->i_ino, dentry->d_name.name);
 
-	sattr.mode = mode;
-	sattr.uid = sattr.gid = sattr.size = (unsigned) -1;
-	sattr.atime.seconds = sattr.mtime.seconds = (unsigned) -1;
+#ifdef NFSD_BROKEN_UID
+	/* We set uid/gid in the request because IBM's broken nfsd
+	 * uses the root uid/gid otherwise. Argh!
+	 * (Hopefully the server will override the gid when the directory
+	 * has the sticky bit set. Irix may have a problem here...)
+	 */
+	attr.ia_mode = mode;
+	attr.ia_valid = ATTR_MODE | ATTR_UID | ATTR_GID;
+	attr.ia_uid = current->fsuid;
+	attr.ia_gid = current->fsgid;
+#else
+	attr.ia_mode = mode;
+	attr.ia_valid = ATTR_MODE;
+#endif
 
 	/*
 	 * Invalidate the dir cache before the operation to avoid a race.
+	 * The 0 argument passed into the create function should one day
+	 * contain the O_EXCL flag if requested. This allows NFSv3 to
+	 * select the appropriate create strategy. Currently open_namei
+	 * does not pass the create flags.
 	 */
-	nfs_invalidate_dircache(dir);
-	error = nfs_proc_create(NFS_SERVER(dir), NFS_FH(dentry->d_parent),
-			dentry->d_name.name, &sattr, &fhandle, &fattr);
-	if (!error)
+	error = NFS_CALL(create, dir_i, (dir, &dir_attr, &dentry->d_name,
+			&attr, 0, &fhandle, &fattr));
+	if (!error && fhandle.size != 0)
 		error = nfs_instantiate(dentry, &fhandle, &fattr);
-	if (error)
+	if (error || fhandle.size == 0)
 		d_drop(dentry);
+	nfs_refresh_inode(dir_i, &dir_attr);
+	nfs_zap_caches(dir_i);
 	return error;
 }
 
 /*
  * See comments for nfs_proc_create regarding failed operations.
  */
-static int nfs_mknod(struct inode *dir, struct dentry *dentry, int mode, int rdev)
+static int nfs_mknod(struct inode *dir_i, struct dentry *dentry, int mode, int rdev)
 {
-	int error;
-	struct nfs_sattr sattr;
-	struct nfs_fattr fattr;
-	struct nfs_fh fhandle;
+	struct dentry	*dir = dentry->d_parent;
+	struct iattr	 attr;
+	struct nfs_fattr fattr, dir_attr;
+	struct nfs_fh	 fhandle;
+	int		 error;
 
 	dfprintk(VFS, "NFS: mknod(%x/%ld, %s\n",
-		dir->i_dev, dir->i_ino, dentry->d_name.name);
+		dir_i->i_dev, dir_i->i_ino, dentry->d_name.name);
 
-	sattr.mode = mode;
-	sattr.uid = sattr.gid = sattr.size = (unsigned) -1;
-	if (S_ISCHR(mode) || S_ISBLK(mode))
-		sattr.size = rdev; /* get out your barf bag */
-	sattr.atime.seconds = sattr.mtime.seconds = (unsigned) -1;
-
-	nfs_invalidate_dircache(dir);
-	error = nfs_proc_create(NFS_SERVER(dir), NFS_FH(dentry->d_parent),
-				dentry->d_name.name, &sattr, &fhandle, &fattr);
-	if (!error)
+#ifdef NFSD_BROKEN_UID
+	attr.ia_valid = ATTR_MODE | ATTR_UID | ATTR_GID;
+	attr.ia_mode = mode;
+	attr.ia_uid = current->fsuid;
+	attr.ia_gid = current->fsgid;
+#else
+	attr.ia_valid = ATTR_MODE;
+	attr.ia_mode = mode;
+#endif
+
+
+	error = NFS_CALL(mknod, dir_i, (dir, &dir_attr, &dentry->d_name,
+				&attr, rdev, &fhandle, &fattr));
+	if (!error && fhandle.size != 0)
 		error = nfs_instantiate(dentry, &fhandle, &fattr);
-	if (error)
+	if (error || fhandle.size == 0)
 		d_drop(dentry);
+	nfs_refresh_inode(dir_i, &dir_attr);
+	nfs_zap_caches(dir_i);
 	return error;
 }
 
 /*
  * See comments for nfs_proc_create regarding failed operations.
  */
-static int nfs_mkdir(struct inode *dir, struct dentry *dentry, int mode)
+static int nfs_mkdir(struct inode *dir_i, struct dentry *dentry, int mode)
 {
-	int error;
-	struct nfs_sattr sattr;
-	struct nfs_fattr fattr;
-	struct nfs_fh fhandle;
-
-	dfprintk(VFS, "NFS: mkdir(%x/%ld, %s\n",
-		dir->i_dev, dir->i_ino, dentry->d_name.name);
-
-	sattr.mode = mode | S_IFDIR;
-	sattr.uid = sattr.gid = sattr.size = (unsigned) -1;
-	sattr.atime.seconds = sattr.mtime.seconds = (unsigned) -1;
+	struct dentry   *dir = dentry->d_parent;
+	struct iattr	 attr;
+	struct nfs_fattr fattr, dir_attr;
+	struct nfs_fh	 fhandle;
+	int		 error;
+
+	dfprintk(VFS, "NFS: mkdir(%x/%ld, %s)\n",
+		dir_i->i_dev, dir_i->i_ino, dentry->d_name.name);
+
+#ifdef NFSD_BROKEN_UID
+	attr.ia_valid = ATTR_MODE | ATTR_UID | ATTR_GID;
+	attr.ia_mode = mode | S_IFDIR;
+	attr.ia_uid = current->fsuid;
+	attr.ia_gid = current->fsgid;
+#else
+	attr.ia_valid = ATTR_MODE;
+	attr.ia_mode = mode | S_IFDIR;
+#endif
 
-	/*
-	 * Always drop the dentry, we can't always depend on
-	 * the fattr returned by the server (AIX seems to be
-	 * broken). We're better off doing another lookup than
-	 * depending on potentially bogus information.
-	 */
-	d_drop(dentry);
-	nfs_invalidate_dircache(dir);
-	error = nfs_proc_mkdir(NFS_DSERVER(dentry), NFS_FH(dentry->d_parent),
-				dentry->d_name.name, &sattr, &fhandle, &fattr);
-	if (!error)
-		dir->i_nlink++;
+	error = NFS_CALL(mkdir, dir_i, (dir, &dir_attr,
+				&dentry->d_name, &attr, &fhandle, &fattr));
+	if (!error && fhandle.size != 0) {
+		dir_i->i_nlink ++;
+		error = nfs_instantiate(dentry, &fhandle, &fattr);
+	}
+	if (error || fhandle.size == 0)
+		d_drop(dentry);
+	nfs_refresh_inode(dir_i, &dir_attr);
+	nfs_zap_caches(dir_i);
 	return error;
 }
 
-static int nfs_rmdir(struct inode *dir, struct dentry *dentry)
+static int nfs_rmdir(struct inode *dir_i, struct dentry *dentry)
 {
-	int error;
+	struct dentry	*dir = dentry->d_parent;
+	struct nfs_fattr dir_attr;
+	int		 error;
 
 	dfprintk(VFS, "NFS: rmdir(%x/%ld, %s\n",
-		dir->i_dev, dir->i_ino, dentry->d_name.name);
+		dir_i->i_dev, dir_i->i_ino, dentry->d_name.name);
 
-	nfs_invalidate_dircache(dir);
-	error = nfs_proc_rmdir(NFS_SERVER(dir), NFS_FH(dentry->d_parent),
-				dentry->d_name.name);
+	error = NFS_CALL(rmdir, dir_i, (dir, &dir_attr, &dentry->d_name));
 
 	/* Update i_nlink and invalidate dentry. */
 	if (!error) {
-		d_drop(dentry);
-		if (dir->i_nlink)
-			dir->i_nlink--;
+		d_delete(dentry);
+		if (dir_i->i_nlink)
+			dir_i->i_nlink --;
 	}
 
+	nfs_refresh_inode(dir_i, &dir_attr);
+	nfs_zap_caches(dir_i);
 	return error;
 }
 
@@ -758,15 +971,18 @@
 	return sdentry;
 }
 
-static int nfs_sillyrename(struct inode *dir, struct dentry *dentry)
+static int nfs_sillyrename(struct inode *dir_i, struct dentry *dentry)
 {
+	struct dentry	*dir = dentry->d_parent;
 	static unsigned int sillycounter = 0;
-	const int      i_inosize  = sizeof(dir->i_ino)*2;
-	const int      countersize = sizeof(sillycounter)*2;
-	const int      slen       = strlen(".nfs") + i_inosize + countersize;
-	char           silly[slen+1];
-	struct dentry *sdentry;
-	int            error = -EIO;
+	struct nfs_fattr dir_attr;
+	const int        i_inosize  = sizeof(dir_i->i_ino)*2;
+	const int        countersize = sizeof(sillycounter)*2;
+	const int        slen       = strlen(".nfs") + i_inosize + countersize;
+	struct qstr      qsilly;
+	char             silly[slen+1];
+	struct dentry *  sdentry;
+	int              error = -EIO;
 
 	dfprintk(VFS, "NFS: silly-rename(%s/%s, ct=%d)\n",
 		dentry->d_parent->d_name.name, dentry->d_name.name, 
@@ -782,9 +998,9 @@
 	}
 
 #ifdef NFS_PARANOIA
-if (!dentry->d_inode)
-printk("NFS: silly-renaming %s/%s, negative dentry??\n",
-dentry->d_parent->d_name.name, dentry->d_name.name);
+	if (!dentry->d_inode)
+		printk(KERN_ERR "NFS: silly-renaming %s/%s, negative dentry??\n",
+		       dentry->d_parent->d_name.name, dentry->d_name.name);
 #endif
 	/*
 	 * We don't allow a dentry to be silly-renamed twice.
@@ -800,7 +1016,8 @@
 	do {
 		char *suffix = silly + slen - countersize;
 
-		dput(sdentry);
+		if (sdentry)
+			dput(sdentry);
 		sillycounter++;
 		sprintf(suffix, "%*.*x", countersize, countersize, sillycounter);
 
@@ -816,16 +1033,19 @@
 			goto out;
 	} while(sdentry->d_inode != NULL); /* need negative lookup */
 
-	nfs_invalidate_dircache(dir);
-	error = nfs_proc_rename(NFS_SERVER(dir),
-				NFS_FH(dentry->d_parent), dentry->d_name.name,
-				NFS_FH(dentry->d_parent), silly);
+	qsilly.name = silly;
+	qsilly.len  = strlen(silly);
+	error = NFS_CALL(rename, dir_i, (dir, &dir_attr, &dentry->d_name,
+				  dir, &dir_attr, &qsilly));
 	if (!error) {
 		nfs_renew_times(dentry);
 		d_move(dentry, sdentry);
 		dentry->d_flags |= DCACHE_NFSFS_RENAMED;
+		NFS_DENTRY(dentry)->cred = rpcauth_lookupcred(NFS_CLIENT(dentry->d_inode)->cl_auth, 0);
  		/* If we return 0 we don't unlink */
 	}
+	nfs_refresh_inode(dir_i, &dir_attr);
+	nfs_zap_caches(dir_i);
 	dput(sdentry);
 out:
 	return error;
@@ -838,11 +1058,13 @@
  * We update inode->i_nlink and free the inode prior to the operation
  * to avoid possible races if the server reuses the inode.
  */
-static int nfs_safe_remove(struct dentry *dentry)
+static int _nfs_safe_remove(struct dentry *dentry, struct rpc_cred *cred)
 {
-	struct inode *dir = dentry->d_parent->d_inode;
-	struct inode *inode = dentry->d_inode;
-	int error, rehash = 0;
+	struct nfs_fattr dir_attr;
+	struct dentry	*dir = dentry->d_parent;
+	struct inode	*dir_i = dir->d_inode,   
+			*inode = dentry->d_inode;
+	int		 error, rehash = 0;
 		
 	dfprintk(VFS, "NFS: safe_remove(%s/%s, %ld)\n",
 		dentry->d_parent->d_name.name, dentry->d_name.name,
@@ -852,18 +1074,19 @@
 	error = -EBUSY;
 	if (!inode) {
 #ifdef NFS_PARANOIA
-printk("nfs_safe_remove: %s/%s already negative??\n",
-dentry->d_parent->d_name.name, dentry->d_name.name);
+		printk(KERN_ERR "nfs_safe_remove: %s/%s already negative??\n",
+		       dentry->d_parent->d_name.name, dentry->d_name.name);
 #endif
 	}
 
 	if (dentry->d_count > 1) {
 #ifdef NFS_PARANOIA
-printk("nfs_safe_remove: %s/%s busy, d_count=%d\n",
-dentry->d_parent->d_name.name, dentry->d_name.name, dentry->d_count);
+		printk(KERN_INFO "nfs_safe_remove: %s/%s busy, d_count=%d\n",
+		       dentry->d_parent->d_name.name, dentry->d_name.name, dentry->d_count);
 #endif
 		goto out;
 	}
+
 	/*
 	 * Unhash the dentry while we remove the file ...
 	 */
@@ -871,6 +1094,13 @@
 		d_drop(dentry);
 		rehash = 1;
 	}
+
+	error = NFS_CALL(remove, dir_i, (dir, &dir_attr, &dentry->d_name, cred));
+	nfs_refresh_inode(dir_i, &dir_attr);
+	nfs_zap_caches(dir_i);
+	if (error < 0)
+		goto out;
+
 	/*
 	 * Update i_nlink and free the inode before unlinking.
 	 */
@@ -879,18 +1109,21 @@
 			inode->i_nlink --;
 		d_delete(dentry);
 	}
-	nfs_invalidate_dircache(dir);
-	error = nfs_proc_remove(NFS_SERVER(dir), NFS_FH(dentry->d_parent),
-				dentry->d_name.name);
 	/*
 	 * Rehash the negative dentry if the operation succeeded.
 	 */
-	if (!error && rehash)
-		d_add(dentry, NULL);
+	if (rehash)
+		d_rehash(dentry);
 out:
 	return error;
 }
 
+static int nfs_safe_remove(struct dentry *dentry)
+{
+	return _nfs_safe_remove(dentry, NULL);
+}
+
+
 /*  We do silly rename. In case sillyrename() returns -EBUSY, the inode
  *  belongs to an active ".nfs..." file and we return -EBUSY.
  *
@@ -903,6 +1136,8 @@
 	dfprintk(VFS, "NFS: unlink(%x/%ld, %s)\n",
 		dir->i_dev, dir->i_ino, dentry->d_name.name);
 
+	if (dentry->d_inode)
+		nfs_wb_all(dentry->d_inode);
 	error = nfs_sillyrename(dir, dentry);
 	if (error && error != -EBUSY) {
 		error = nfs_safe_remove(dentry);
@@ -914,45 +1149,60 @@
 }
 
 static int
-nfs_symlink(struct inode *dir, struct dentry *dentry, const char *symname)
+nfs_symlink(struct inode *dir_i, struct dentry *dentry, const char *symname)
 {
-	struct nfs_sattr sattr;
-	int error;
+	struct dentry	*dir = dentry->d_parent;
+	struct nfs_fattr dir_attr, sym_attr;
+	struct nfs_fh    sym_fh;
+	struct iattr     attr;
+	struct qstr      qsymname;
+	int              error, mode, maxlen;
 
 	dfprintk(VFS, "NFS: symlink(%x/%ld, %s, %s)\n",
-		dir->i_dev, dir->i_ino, dentry->d_name.name, symname);
+		dir_i->i_dev, dir_i->i_ino, dentry->d_name.name, symname);
 
 	error = -ENAMETOOLONG;
-	if (strlen(symname) > NFS_MAXPATHLEN)
+	maxlen = (NFS_PROTO(dir_i)->version==2) ? NFS2_MAXPATHLEN : NFS3_MAXPATHLEN;
+	if (strlen(symname) > maxlen)
 		goto out;
 
 #ifdef NFS_PARANOIA
-if (dentry->d_inode)
-printk("nfs_proc_symlink: %s/%s not negative!\n",
-dentry->d_parent->d_name.name, dentry->d_name.name);
+	if (dentry->d_inode)
+		printk(KERN_WARNING "nfs_proc_symlink: %s/%s not negative!\n",
+		       dentry->d_parent->d_name.name, dentry->d_name.name);
 #endif
 	/*
 	 * Fill in the sattr for the call.
+
  	 * Note: SunOS 4.1.2 crashes if the mode isn't initialized!
 	 */
-	sattr.mode = S_IFLNK | S_IRWXUGO;
-	sattr.uid = sattr.gid = sattr.size = (unsigned) -1;
-	sattr.atime.seconds = sattr.mtime.seconds = (unsigned) -1;
+#ifdef NFSD_BROKEN_UID
+	attr.ia_valid = ATTR_MODE|ATTR_UID|ATTR_GID;
+	attr.ia_mode = mode = S_IFLNK | S_IRWXUGO;
+	attr.ia_uid = current->fsuid;
+	attr.ia_gid = current->fsgid;
+#else
+	attr.ia_valid = ATTR_MODE;
+	attr.ia_mode = mode = S_IFLNK | S_IRWXUGO;
+#endif
 
-	/*
-	 * Drop the dentry in advance to force a new lookup.
-	 * Since nfs_proc_symlink doesn't return a fattr, we
-	 * can't instantiate the new inode.
-	 */
-	d_drop(dentry);
-	nfs_invalidate_dircache(dir);
-	error = nfs_proc_symlink(NFS_SERVER(dir), NFS_FH(dentry->d_parent),
-				dentry->d_name.name, symname, &sattr);
-	if (!error) {
-		nfs_renew_times(dentry->d_parent);
-	} else if (error == -EEXIST) {
-		printk("nfs_proc_symlink: %s/%s already exists??\n",
-			dentry->d_parent->d_name.name, dentry->d_name.name);
+
+	qsymname.name = symname;
+	qsymname.len  = strlen(symname);
+
+	error = NFS_CALL(symlink, dir_i, (dir, &dir_attr,
+				&dentry->d_name, &qsymname, &attr,
+				&sym_fh, &sym_attr));
+	nfs_refresh_inode(dir_i, &dir_attr);
+	nfs_zap_caches(dir_i);
+	if (!error && sym_fh.size != 0 && (sym_attr.valid & NFS_ATTR_FATTR)) {
+		error = nfs_instantiate(dentry, &sym_fh, &sym_attr);
+	} else {
+		if (error == -EEXIST)
+			printk(KERN_INFO "nfs_proc_symlink: %s/%s already exists??\n",
+			       dentry->d_parent->d_name.name,
+			       dentry->d_name.name);
+		d_drop(dentry);
 	}
 
 out:
@@ -960,10 +1210,12 @@
 }
 
 static int 
-nfs_link(struct dentry *old_dentry, struct inode *dir, struct dentry *dentry)
+nfs_link(struct dentry *old_dentry, struct inode *dir_i, struct dentry *dentry)
 {
-	struct inode *inode = old_dentry->d_inode;
-	int error;
+	struct dentry	*dir = dentry->d_parent;
+	struct inode	*inode = old_dentry->d_inode;
+	struct nfs_fattr old_attr, dir_attr;
+	int		 error;
 
 	dfprintk(VFS, "NFS: link(%s/%s -> %s/%s)\n",
 		old_dentry->d_parent->d_name.name, old_dentry->d_name.name,
@@ -975,16 +1227,18 @@
 	 * we can't use the existing dentry.
 	 */
 	d_drop(dentry);
-	nfs_invalidate_dircache(dir);
-	error = nfs_proc_link(NFS_DSERVER(old_dentry), NFS_FH(old_dentry),
-				NFS_FH(dentry->d_parent), dentry->d_name.name);
+	error = NFS_CALL(link, inode, (old_dentry, &old_attr,
+				       dir, &dir_attr, &dentry->d_name));
 	if (!error) {
- 		/*
+		/*
 		 * Update the link count immediately, as some apps
 		 * (e.g. pine) test this after making a link.
 		 */
 		inode->i_nlink++;
 	}
+	nfs_refresh_inode(inode, &old_attr);
+	nfs_refresh_inode(dir_i, &dir_attr);
+	nfs_zap_caches(dir_i);
 	return error;
 }
 
@@ -1011,14 +1265,19 @@
  * no pending writes (if it's a file), and the use count must be 1.
  * If these conditions are met, we can drop the dentries before doing
  * the rename.
+ *
+ * FIXME: Sun seems to take this even one step further. The connectathon
+ * test suite has a file that renames open file A to open file B,
+ * and expects a silly rename to happen for B.
  */
 static int nfs_rename(struct inode *old_dir, struct dentry *old_dentry,
 		      struct inode *new_dir, struct dentry *new_dentry)
 {
-	struct inode *old_inode = old_dentry->d_inode;
-	struct inode *new_inode = new_dentry->d_inode;
-	struct dentry *dentry = NULL;
-	int error, rehash = 0;
+	struct nfs_fattr old_attr, new_attr;
+	struct inode *   old_inode = old_dentry->d_inode;
+	struct inode *   new_inode = new_dentry->d_inode;
+	struct dentry *  dentry = NULL;
+	int              error, rehash = 0;
 
 	dfprintk(VFS, "NFS: rename(%s/%s -> %s/%s, ct=%d)\n",
 		old_dentry->d_parent->d_name.name, old_dentry->d_name.name,
@@ -1036,6 +1295,8 @@
 	 * With directories check is done in VFS.
 	 */
 	error = -EBUSY;
+	if (new_inode)
+		nfs_wb_all(new_inode);
 	if (new_dentry->d_count > 1 && new_inode) {
 		int err;
 		/* copy the target dentry's name */
@@ -1056,8 +1317,9 @@
 		/* dentry still busy? */
 		if (new_dentry->d_count > 1) {
 #ifdef NFS_PARANOIA
-printk("nfs_rename: target %s/%s busy, d_count=%d\n",
-new_dentry->d_parent->d_name.name,new_dentry->d_name.name,new_dentry->d_count);
+		printk(KERN_INFO "nfs_rename: target %s/%s busy, d_count=%d\n",
+			new_dentry->d_parent->d_name.name,
+			new_dentry->d_name.name,new_dentry->d_count);
 #endif
 			goto out;
 		}
@@ -1073,8 +1335,8 @@
 
 	if (new_dentry->d_count > 1 && new_inode) {
 #ifdef NFS_PARANOIA
-printk("nfs_rename: new dentry %s/%s busy, d_count=%d\n",
-new_dentry->d_parent->d_name.name,new_dentry->d_name.name,new_dentry->d_count);
+		printk(KERN_INFO "nfs_rename: new dentry %s/%s busy, d_count=%d\n",
+			new_dentry->d_parent->d_name.name,new_dentry->d_name.name,new_dentry->d_count);
 #endif
 		goto out;
 	}
@@ -1087,26 +1349,55 @@
 		d_drop(new_dentry);
 		rehash = 1;
 	}
+
 	if (new_inode)
 		d_delete(new_dentry);
 
-	nfs_invalidate_dircache(new_dir);
-	nfs_invalidate_dircache(old_dir);
-	error = nfs_proc_rename(NFS_DSERVER(old_dentry),
-			NFS_FH(old_dentry->d_parent), old_dentry->d_name.name,
-			NFS_FH(new_dentry->d_parent), new_dentry->d_name.name);
+	error = NFS_CALL(rename, old_dir,
+			 (old_dentry->d_parent, &old_attr, &old_dentry->d_name,
+			  new_dentry->d_parent, &new_attr, &new_dentry->d_name));
+	nfs_refresh_inode(old_dir, &old_attr);
+	nfs_zap_caches(old_dir);
+	nfs_refresh_inode(new_dir, &new_attr);
+	nfs_zap_caches(new_dir);
 
 	/* Update the dcache if needed */
 	if (rehash)
-		d_add(new_dentry, NULL);
+		d_rehash(new_dentry);
 	if (!error && !S_ISDIR(old_inode->i_mode))
 		d_move(old_dentry, new_dentry);
-
 out:
 	/* new dentry created? */
 	if (dentry)
 		dput(dentry);
 	return error;
+}
+
+int
+nfs_permission(struct inode *i, int msk)
+{
+	struct nfs_fattr	fattr;
+	struct dentry		*de = NULL;
+	int			err;
+	struct list_head	*start, *tmp;
+
+	if (!NFS_PROTO(i)->access)
+		return unix_permission(i, msk);
+	tmp = start = &i->i_dentry;
+	while ((tmp = tmp->next) != start) {
+		de = list_entry(tmp, struct dentry, d_alias);
+		if (de->d_inode == i)
+			break;
+	}
+	if (!de || de->d_inode != i)
+		return 0;
+
+	err = NFS_CALL(access, i, (de, msk, &fattr, 0));
+	if (err == -EACCES && (current->fsuid != current->uid ||
+			       current->fsgid != current->gid))
+		err = NFS_CALL(access, i, (de, msk, &fattr, 1));
+	nfs_refresh_inode(i, &fattr);
+	return err;
 }
 
 /*
Index: oldkernel/linux/fs/nfs/file.c
diff -u linux/fs/nfs/file.c:1.2 linux/fs/nfs/file.c:1.3
--- linux/fs/nfs/file.c:1.2	Thu Jun  1 15:03:08 2000
+++ linux/fs/nfs/file.c	Fri Jul  7 15:36:46 2000
@@ -1,6 +1,8 @@
 /*
  *  linux/fs/nfs/file.c
  *
+ *  NFS regular file handling.
+ *
  *  Copyright (C) 1992  Rick Sladkey
  *
  *  Changes Copyright (C) 1994 by Florian La Roche
@@ -12,8 +14,6 @@
  *  Expire cache on write to a file by Wai S Kok (Oct 1994).
  *
  *  Total rewrite of read side for new NFS buffer cache.. Linus.
- *
- *  nfs regular file handling functions
  */
 
 #include <linux/sched.h>
@@ -21,11 +21,16 @@
 #include <linux/errno.h>
 #include <linux/fcntl.h>
 #include <linux/stat.h>
+#include <linux/nfs.h>
+#include <linux/nfs3.h>
 #include <linux/nfs_fs.h>
+#include <linux/nfs_mount.h>
 #include <linux/mm.h>
 #include <linux/malloc.h>
 #include <linux/pagemap.h>
 #include <linux/lockd/bind.h>
+#include <linux/sunrpc/auth.h>
+#include <linux/sunrpc/clnt.h>
 
 #include <asm/segment.h>
 #include <asm/system.h>
@@ -73,7 +78,7 @@
 	nfs_writepage,		/* writepage */
 	NULL,			/* bmap */
 	NULL,			/* truncate */
-	NULL,			/* permission */
+	nfs_permission,		/* permission */
 	NULL,			/* smap */
 	nfs_updatepage,		/* updatepage */
 	nfs_revalidate,		/* revalidate */
@@ -91,17 +96,11 @@
 static int
 nfs_file_flush(struct file *file)
 {
-	struct inode	*inode = file->f_dentry->d_inode;
-	int		status;
+	struct dentry	*dentry = file->f_dentry;
+	struct inode	*inode = dentry->d_inode;
 
 	dfprintk(VFS, "nfs: flush(%x/%ld)\n", inode->i_dev, inode->i_ino);
-
-	status = nfs_wb_file(inode, file);
-	if (!status) {
-		status = file->f_error;
-		file->f_error = 0;
-	}
-	return status;
+	return nfs_fsync(file, dentry);
 }
 
 static ssize_t
@@ -114,12 +113,7 @@
 		dentry->d_parent->d_name.name, dentry->d_name.name,
 		(unsigned long) count, (unsigned long) *ppos);
 
-	/* Unconditionally allow only up to 2G files */
-	/* FIXME: NFSv3 could allow 64-bit file offsets! */
-	if (*ppos >= 0x7ffffffeULL)
-		return -EOVERFLOW;
-
-	result = nfs_revalidate_inode(NFS_DSERVER(dentry), dentry);
+	result = nfs_revalidate_inode(dentry);
 	if (!result)
 		result = generic_file_read(file, buf, count, ppos);
 	return result;
@@ -134,7 +128,7 @@
 	dfprintk(VFS, "nfs: mmap(%s/%s)\n",
 		dentry->d_parent->d_name.name, dentry->d_name.name);
 
-	status = nfs_revalidate_inode(NFS_DSERVER(dentry), dentry);
+	status = nfs_revalidate_inode(dentry);
 	if (!status)
 		status = generic_file_mmap(file, vma);
 	return status;
@@ -179,17 +173,10 @@
 	result = -EBUSY;
 	if (IS_SWAPFILE(inode))
 		goto out_swapfile;
-	result = nfs_revalidate_inode(NFS_DSERVER(dentry), dentry);
+	result = nfs_revalidate_inode(dentry);
 	if (result)
 		goto out;
 
-	/* Unconditionally allow only up to 2G files */
-	/* FIXME: NFSv3 could allow 64-bit file offsets! */
-	if (*ppos >= 0x7ffffffeULL) {
-		result = -EOVERFLOW;
-		goto out;
-	}
-
 	result = count;
 	if (!count)
 		goto out;
@@ -209,13 +196,14 @@
 int
 nfs_lock(struct file *filp, int cmd, struct file_lock *fl)
 {
-	struct inode * inode = filp->f_dentry->d_inode;
+	struct dentry * dentry = filp->f_dentry;
+	struct inode * inode = dentry->d_inode;
 	int	status = 0;
 
 	dprintk("NFS: nfs_lock(f=%4x/%ld, t=%x, fl=%x, r=%ld:%ld)\n",
 			inode->i_dev, inode->i_ino,
 			fl->fl_type, fl->fl_flags,
-			(u_long)fl->fl_start, (u_long)fl->fl_end);
+			fl->fl_start, fl->fl_end);
 
 	if (!inode)
 		return -EINVAL;
@@ -247,17 +235,17 @@
 	 */
 	status = nfs_wb_all(inode);
 	if (status < 0)
-		return status;
+		goto out_unlock;
 
-	if ((status = nlmclnt_proc(inode, cmd, fl)) < 0)
-		return status;
-	else
+	status = nlmclnt_proc(inode, cmd, fl);
+	if (status > 0)
 		status = 0;
 
 	/*
 	 * Make sure we re-validate anything we've got cached.
 	 * This makes locking act as a cache coherency point.
 	 */
+ out_unlock:
  out_ok:
 	NFS_CACHEINV(inode);
 	return status;
Index: oldkernel/linux/fs/nfs/flushd.c
diff -u /dev/null linux/fs/nfs/flushd.c:1.1
--- /dev/null	Mon Jul 31 21:15:08 2000
+++ linux/fs/nfs/flushd.c	Fri Jul  7 16:18:17 2000
@@ -0,0 +1,299 @@
+/*
+ * linux/fs/nfs/flushd.c
+ *
+ * For each NFS mount, there is a separate cache object that contains
+ * a hash table of all clusters. With this cache, an async RPC task
+ * (`flushd') is associated, which wakes up occasionally to inspect
+ * its list of dirty buffers.
+ * (Note that RPC tasks aren't kernel threads. Take a look at the
+ * rpciod code to understand what they are).
+ *
+ * Inside the cache object, we also maintain a count of the current number
+ * of dirty pages, which may not exceed a certain threshold.
+ * (FIXME: This threshold should be configurable).
+ *
+ * The code is streamlined for what I think is the prevalent case for
+ * NFS traffic, which is sequential write access without concurrent
+ * access by different processes.
+ *
+ * Copyright (C) 1996, 1997, Olaf Kirch <okir@monad.swb.de>
+ *
+ * Rewritten 6/3/2000 by Trond Myklebust
+ * Copyright (C) 1999, 2000, Trond Myklebust <trond.myklebust@fys.uio.no>
+ */
+
+#include <linux/types.h>
+#include <linux/malloc.h>
+#include <linux/pagemap.h>
+#include <linux/file.h>
+
+#include <linux/sched.h>
+
+#include <linux/sunrpc/auth.h>
+#include <linux/sunrpc/clnt.h>
+#include <linux/sunrpc/sched.h>
+
+#include <asm/spinlock.h>
+
+#include <linux/nfs.h>
+#include <linux/nfs_fs.h>
+#include <linux/nfs_fs_sb.h>
+#include <linux/nfs_flushd.h>
+#include <linux/nfs_mount.h>
+
+/*
+ * Various constants
+ */
+#define NFSDBG_FACILITY         NFSDBG_PAGECACHE
+
+/*
+ * This is the wait queue all cluster daemons sleep on
+ */
+static struct rpc_wait_queue    flushd_queue = RPC_INIT_WAITQ("nfs_flushd");
+
+/*
+ * Spinlock
+ */
+spinlock_t nfs_flushd_lock = SPIN_LOCK_UNLOCKED;
+
+/*
+ * Local function declarations.
+ */
+static void	nfs_flushd(struct rpc_task *);
+static void	nfs_flushd_exit(struct rpc_task *);
+
+
+int nfs_reqlist_init(struct nfs_server *server)
+{
+	struct nfs_reqlist	*cache;
+	struct rpc_task		*task;
+	int			status = 0;
+
+	dprintk("NFS: writecache_init\n");
+	spin_lock(&nfs_flushd_lock);
+	cache = server->rw_requests;
+
+	if (cache->task)
+		goto out_unlock;
+
+	/* Create the RPC task */
+	status = -ENOMEM;
+	task = rpc_new_task(server->client, NULL, RPC_TASK_ASYNC);
+	if (!task)
+		goto out_unlock;
+
+	task->tk_calldata = server;
+
+	cache->task = task;
+
+	/* Run the task */
+	cache->runat = jiffies;
+
+	cache->auth = server->client->cl_auth;
+	task->tk_action   = nfs_flushd;
+	task->tk_exit   = nfs_flushd_exit;
+
+	spin_unlock(&nfs_flushd_lock);
+	rpc_execute(task);
+	return 0;
+ out_unlock:
+	spin_unlock(&nfs_flushd_lock);
+	return status;
+}
+
+void nfs_reqlist_exit(struct nfs_server *server)
+{
+	struct nfs_reqlist      *cache;
+
+	cache = server->rw_requests;
+	if (!cache)
+		return;
+
+	dprintk("NFS: reqlist_exit (ptr %p rpc %p)\n", cache, cache->task);
+	while (cache->task || cache->inodes) {
+		spin_lock(&nfs_flushd_lock);
+		if (!cache->task) {
+			spin_unlock(&nfs_flushd_lock);
+			nfs_reqlist_init(server);
+		} else {
+			cache->task->tk_status = -ENOMEM;
+			rpc_wake_up_task(cache->task);
+			spin_unlock(&nfs_flushd_lock);
+		}
+		interruptible_sleep_on_timeout(&cache->request_wait, 1 * HZ);
+	}
+}
+
+int nfs_reqlist_alloc(struct nfs_server *server)
+{
+	struct nfs_reqlist	*cache;
+	if (server->rw_requests)
+		return 0;
+
+	cache = (struct nfs_reqlist *)kmalloc(sizeof(*cache), GFP_KERNEL);
+	if (!cache)
+		return -ENOMEM;
+
+	memset(cache, 0, sizeof(*cache));
+	server->rw_requests = cache;
+
+	return 0;
+}
+
+void nfs_reqlist_free(struct nfs_server *server)
+{
+	if (server->rw_requests) {
+		kfree(server->rw_requests);
+		server->rw_requests = NULL;
+	}
+}
+
+void nfs_wake_flushd()
+{
+	rpc_wake_up_status(&flushd_queue, -ENOMEM);
+}
+
+static void inode_append_flushd(struct inode *inode)
+{
+	struct nfs_reqlist	*cache = NFS_REQUESTLIST(inode);
+	struct inode		**q;
+
+	spin_lock(&nfs_flushd_lock);
+	if (NFS_FLAGS(inode) & NFS_INO_FLUSH)
+		goto out;
+	inode->u.nfs_i.hash_next = NULL;
+
+	q = &cache->inodes;
+	while (*q)
+		q = &(*q)->u.nfs_i.hash_next;
+	*q = inode;
+
+	/* Note: we increase the inode i_count in order to prevent
+	 *	 it from disappearing when on the flush list
+	 */
+	NFS_FLAGS(inode) |= NFS_INO_FLUSH;
+	inode->i_count++;
+ out:
+	spin_unlock(&nfs_flushd_lock);
+}
+
+void inode_remove_flushd(struct inode *inode)
+{
+	struct nfs_reqlist	*cache = NFS_REQUESTLIST(inode);
+	struct inode		**q;
+
+	spin_lock(&nfs_flushd_lock);
+	if (!(NFS_FLAGS(inode) & NFS_INO_FLUSH))
+		goto out;
+
+	q = &cache->inodes;
+	while (*q && *q != inode)
+		q = &(*q)->u.nfs_i.hash_next;
+	if (*q) {
+		*q = inode->u.nfs_i.hash_next;
+		NFS_FLAGS(inode) &= ~NFS_INO_FLUSH;
+		iput(inode);
+	}
+ out:
+	spin_unlock(&nfs_flushd_lock);
+}
+
+void inode_schedule_scan(struct inode *inode, unsigned long time)
+{
+	struct nfs_reqlist	*cache = NFS_REQUESTLIST(inode);
+	struct rpc_task		*task;
+	unsigned long		mintimeout;
+
+	if (time_after(NFS_NEXTSCAN(inode), time))
+		NFS_NEXTSCAN(inode) = time;
+	mintimeout = jiffies + 1 * HZ;
+	if (time_before(mintimeout, NFS_NEXTSCAN(inode)))
+		mintimeout = NFS_NEXTSCAN(inode);
+	inode_append_flushd(inode);
+
+	spin_lock(&nfs_flushd_lock);
+	task = cache->task;
+	if (!task) {
+		spin_unlock(&nfs_flushd_lock);
+		nfs_reqlist_init(NFS_SERVER(inode));
+	} else {
+		if (time_after(cache->runat, mintimeout))
+			rpc_wake_up_task(task);
+		spin_unlock(&nfs_flushd_lock);
+	}
+}
+
+
+static void
+nfs_flushd(struct rpc_task *task)
+{
+	struct nfs_server	*server;
+	struct nfs_reqlist	*cache;
+	struct inode		*inode, *next;
+	unsigned long		delay = jiffies + NFS_WRITEBACK_LOCKDELAY;
+	int			flush = (task->tk_status == -ENOMEM);
+
+        dprintk("NFS: %4d flushd starting\n", task->tk_pid);
+	server = (struct nfs_server *) task->tk_calldata;
+        cache = server->rw_requests;
+
+	spin_lock(&nfs_flushd_lock);
+	next = cache->inodes;
+	cache->inodes = NULL;
+	spin_unlock(&nfs_flushd_lock);
+
+	while ((inode = next) != NULL) {
+		next = next->u.nfs_i.hash_next;
+		inode->u.nfs_i.hash_next = NULL;
+		NFS_FLAGS(inode) &= ~NFS_INO_FLUSH;
+
+		if (flush) {
+			nfs_sync_file(inode, NULL, 0, 0, FLUSH_AGING);
+		} else if (time_after(jiffies, NFS_NEXTSCAN(inode))) {
+			NFS_NEXTSCAN(inode) = jiffies + NFS_WRITEBACK_LOCKDELAY;
+			nfs_flush_timeout(inode, FLUSH_AGING);
+			nfs_commit_timeout(inode, FLUSH_AGING);
+		}
+
+		if (nfs_have_writebacks(inode)) {
+			inode_append_flushd(inode);
+			if (time_after(delay, NFS_NEXTSCAN(inode)))
+				delay = NFS_NEXTSCAN(inode);
+		}
+		iput(inode);
+	}
+
+	dprintk("NFS: %4d flushd back to sleep\n", task->tk_pid);
+	if (time_after(jiffies + 1 * HZ, delay))
+		delay = 1 * HZ;
+	else
+		delay = delay - jiffies;
+	task->tk_status = 0;
+	task->tk_action = nfs_flushd;
+	task->tk_timeout = delay;
+	cache->runat = jiffies + task->tk_timeout;
+
+	spin_lock(&nfs_flushd_lock);
+	if (!cache->nr_requests && !cache->inodes) {
+		cache->task = NULL;
+		task->tk_action = NULL;
+	} else
+		rpc_sleep_on(&flushd_queue, task, NULL, NULL);
+	spin_unlock(&nfs_flushd_lock);
+}
+
+static void
+nfs_flushd_exit(struct rpc_task *task)
+{
+	struct nfs_server	*server;
+	struct nfs_reqlist	*cache;
+	server = (struct nfs_server *) task->tk_calldata;
+	cache = server->rw_requests;
+
+	spin_lock(&nfs_flushd_lock);
+	if (cache->task == task)
+		cache->task = NULL;
+	spin_unlock(&nfs_flushd_lock);
+	wake_up(&cache->request_wait);
+}
+
Index: oldkernel/linux/fs/nfs/inode.c
diff -u linux/fs/nfs/inode.c:1.3 linux/fs/nfs/inode.c:1.4
--- linux/fs/nfs/inode.c:1.3	Thu Jun  1 15:37:13 2000
+++ linux/fs/nfs/inode.c	Fri Jul  7 15:36:46 2000
@@ -24,11 +24,19 @@
 #include <linux/errno.h>
 #include <linux/locks.h>
 #include <linux/unistd.h>
+#include <linux/major.h>
 #include <linux/sunrpc/clnt.h>
 #include <linux/sunrpc/stats.h>
+#include <linux/nfs.h>
+#include <linux/nfs2.h>
+#include <linux/nfs3.h>
 #include <linux/nfs_fs.h>
+#include <linux/nfs_mount.h>
+#include <linux/nfs_flushd.h>
 #include <linux/lockd/bind.h>
 
+#include <asm/spinlock.h>
+
 #include <asm/system.h>
 #include <asm/uaccess.h>
 
@@ -37,16 +45,16 @@
 #define NFS_PARANOIA 1
 
 static struct inode * __nfs_fhget(struct super_block *, struct nfs_fattr *);
-static void nfs_zap_caches(struct inode *);
-static void nfs_invalidate_inode(struct inode *);
 
 static void nfs_read_inode(struct inode *);
 static void nfs_put_inode(struct inode *);
 static void nfs_delete_inode(struct inode *);
 static int  nfs_notify_change(struct dentry *, struct iattr *);
 static void nfs_put_super(struct super_block *);
-static void nfs_umount_begin(struct super_block *);
 static int  nfs_statfs(struct super_block *, struct statfs *, int);
+static void nfs_umount_begin(struct super_block *);
+static struct nfs_file *nfs_file_alloc(void);
+static void nfs_file_free(struct nfs_file *p);
 
 static struct super_operations nfs_sops = { 
 	nfs_read_inode,		/* read inode */
@@ -57,12 +65,44 @@
 	nfs_put_super,		/* put superblock */
 	NULL,			/* write superblock */
 	nfs_statfs,		/* stat filesystem */
-	NULL,			/* no remount */
-	NULL,			/* no clear inode */
+	NULL,			/* remount */
+	NULL,			/* clear inode */
 	nfs_umount_begin	/* umount attempt begin */
 };
+
+
+/*
+ * RPC crutft for NFS
+ */
+static struct rpc_stat		nfs_rpcstat = { &nfs_program };
+static struct rpc_version *	nfs_version[] = {
+	NULL,
+	NULL,
+	&nfs_version2,
+#ifdef CONFIG_NFS_V3
+	&nfs_version3,
+#endif
+};
+
+struct rpc_program		nfs_program = {
+	"nfs",
+	NFS_PROGRAM,
+	sizeof(nfs_version) / sizeof(nfs_version[0]),
+	nfs_version,
+	&nfs_rpcstat,
+};
+
+static inline unsigned long
+nfs_fattr_to_ino_t(struct nfs_fattr *fattr)
+{
+	return nfs_fileid_to_ino_t(fattr->fileid);
+}
 
-struct rpc_stat			nfs_rpcstat = { &nfs_program };
+/*
+ * We don't keep the file handle in the inode anymore to avoid bloating
+ * struct inode and use a pointer to external memory instead.
+ */
+#define NFS_SB_FHSIZE(sb)	((sb)->u.nfs_sb.s_fhsize)
 
 /*
  * The "read_inode" function doesn't actually do anything:
@@ -78,8 +118,17 @@
 	inode->i_mode = 0;
 	inode->i_rdev = 0;
 	inode->i_op = NULL;
+	NFS_FILEID(inode) = 0;
+	NFS_FSID(inode) = 0;
+	INIT_LIST_HEAD(&inode->u.nfs_i.dirty);
+	INIT_LIST_HEAD(&inode->u.nfs_i.commit);
+	INIT_LIST_HEAD(&inode->u.nfs_i.writeback);
+	inode->u.nfs_i.ndirty = 0;
+	inode->u.nfs_i.ncommit = 0;
+	inode->u.nfs_i.npages = 0;
 	NFS_CACHEINV(inode);
 	NFS_ATTRTIMEO(inode) = NFS_MINATTRTIMEO(inode);
+	NFS_ATTRTIMEO_UPDATE(inode) = jiffies;
 }
 
 static void
@@ -96,32 +145,15 @@
 static void
 nfs_delete_inode(struct inode * inode)
 {
-	int failed;
-
 	dprintk("NFS: delete_inode(%x/%ld)\n", inode->i_dev, inode->i_ino);
+#ifdef NFS_DEBUG_VERBOSE
 	/*
 	 * Flush out any pending write requests ...
 	 */
-	if (NFS_WRITEBACK(inode) != NULL) {
-		unsigned long timeout = jiffies + 5*HZ;
-#ifdef NFS_DEBUG_VERBOSE
-printk("nfs_delete_inode: inode %ld has pending RPC requests\n", inode->i_ino);
-#endif
-		nfs_inval(inode);
-		while (NFS_WRITEBACK(inode) != NULL &&
-		       time_before(jiffies, timeout)) {
-			current->state = TASK_INTERRUPTIBLE;
-			schedule_timeout(HZ/10);
-		}
-		current->state = TASK_RUNNING;
-		if (NFS_WRITEBACK(inode) != NULL)
-			printk("NFS: Arghhh, stuck RPC requests!\n");
+	if (nfs_have_writebacks(inode)) {
+		printk(KERN_ERR "nfs_delete_inode: inode %ld has pending RPC requests\n", inode->i_ino);
 	}
-
-	failed = nfs_check_failed_request(inode);
-	if (failed)
-		printk("NFS: inode %ld had %d failed requests\n",
-			inode->i_ino, failed);
+#endif
 	clear_inode(inode);
 }
 
@@ -131,18 +163,22 @@
 	struct nfs_server *server = &sb->u.nfs_sb.s_server;
 	struct rpc_clnt	*rpc;
 
+	/*
+	 * First get rid of the request flushing daemon.
+	 * Relies on rpc_shutdown_client() waiting on all
+	 * client tasks to finish.
+	 */
+	nfs_reqlist_exit(server);
+
 	if ((rpc = server->client) != NULL)
 		rpc_shutdown_client(rpc);
 
-#if 0
+	nfs_reqlist_free(server);
+
 	if (!(server->flags & NFS_MOUNT_NONLM))
 		lockd_down();	/* release rpc.lockd */
-#endif
+
 	rpciod_down();		/* release rpciod */
-	/*
-	 * Invalidate the dircache for this superblock.
-	 */
-	nfs_invalidate_dircache_sb(sb);
 
 	kfree(server->hostname);
 
@@ -160,17 +196,10 @@
 		rpc_killall_tasks(rpc);
 }
 
-/*
- * Compute and set NFS server blocksize
- */
-static unsigned int
-nfs_block_size(unsigned int bsize, unsigned char *nrbitsp)
-{
-	if (bsize < 1024)
-		bsize = NFS_DEF_FILE_IO_BUFFER_SIZE;
-	else if (bsize >= NFS_MAX_FILE_IO_BUFFER_SIZE)
-		bsize = NFS_MAX_FILE_IO_BUFFER_SIZE;
 
+static inline unsigned long
+nfs_block_bits(unsigned long bsize, unsigned char *nrbitsp)
+{
 	/* make sure blocksize is a power of two */
 	if ((bsize & (bsize - 1)) || nrbitsp) {
 		unsigned int	nrbits;
@@ -180,14 +209,56 @@
 		bsize = 1 << nrbits;
 		if (nrbitsp)
 			*nrbitsp = nrbits;
-		if (bsize < NFS_DEF_FILE_IO_BUFFER_SIZE)
-			bsize = NFS_DEF_FILE_IO_BUFFER_SIZE;
 	}
 
 	return bsize;
 }
 
 /*
+ * Calculate the number of 512byte blocks used.
+ */
+static inline unsigned long
+nfs_calc_block_size(u64 tsize)
+{
+	off_t used = nfs_size_to_off_t(tsize);
+	return (used + 511) >> 9;
+}
+
+/*
+ * Compute and set NFS server blocksize
+ */
+static inline unsigned long
+nfs_block_size(unsigned long bsize, unsigned char *nrbitsp)
+{
+	if (bsize < 1024)
+		bsize = NFS_DEF_FILE_IO_BUFFER_SIZE;
+	else if (bsize >= NFS_MAX_FILE_IO_BUFFER_SIZE)
+		bsize = NFS_MAX_FILE_IO_BUFFER_SIZE;
+
+	return nfs_block_bits(bsize, nrbitsp);
+}
+
+/*
+ * Obtain the root inode of the file system.
+ */
+static struct inode *
+nfs_get_root(struct super_block *sb, struct nfs_fh *rootfh)
+{
+	struct nfs_server	*server = &sb->u.nfs_sb.s_server;
+	struct nfs_fattr	fattr;
+	struct inode		*inode;
+	int			error;
+
+	if ((error = server->rpc_ops->getroot(server, rootfh, &fattr)) < 0) {
+		printk(KERN_NOTICE "nfs_get_root: getattr error = %d\n", -error);
+		return NULL;
+	}
+
+	inode = __nfs_fhget(sb, &fattr);
+	return inode;
+}
+
+/*
  * The way this works is that the mount process passes a structure
  * in the data argument which contains the server's IP address
  * and the root file handle obtained from the server's mount
@@ -198,38 +269,46 @@
 {
 	struct nfs_mount_data	*data = (struct nfs_mount_data *) raw_data;
 	struct nfs_server	*server;
-	struct rpc_xprt		*xprt;
-	struct rpc_clnt		*clnt;
-	struct nfs_fh		*root_fh;
-	struct inode		*root_inode;
+	struct rpc_xprt		*xprt = 0;
+	struct rpc_clnt		*clnt = 0;
+	struct nfs_dentry	*root_d_fsdata = NULL;
+	struct nfs_fh		*root = &data->root, *root_fh, fh;
+	struct inode		*root_inode = NULL;
 	unsigned int		authflavor;
-	int			tcp;
 	struct sockaddr_in	srvaddr;
 	struct rpc_timeout	timeparms;
-	struct nfs_fattr	fattr;
+	struct nfs_fsinfo       fsinfo;
+	int                     tcp, version, maxlen;
 
 	MOD_INC_USE_COUNT;
-	if (!data)
-		goto out_miss_args;
+	memset(&sb->u.nfs_sb, 0, sizeof(sb->u.nfs_sb));
+	if (!data) {
+		printk(KERN_NOTICE "nfs_read_super: missing data argument\n");
+		goto failure;
+	}
 
-	/* No NFS V3. */
-	if (data->flags & NFS_MOUNT_VER3)
-		goto out_fail;
-
-	/* Don't complain if "mount" is newer. */
-	if (data->version < NFS_MOUNT_VERSION) {
-		printk("nfs warning: mount version %s than kernel\n",
+	memset(&fh, 0, sizeof(fh));
+	if (data->version != NFS_MOUNT_VERSION) {
+		printk(KERN_WARNING "nfs warning: mount version %s than kernel\n",
 			data->version < NFS_MOUNT_VERSION ? "older" : "newer");
 		if (data->version < 2)
 			data->namlen = 0;
 		if (data->version < 3)
 			data->bsize  = 0;
+		if (data->version < 4) {
+			data->flags &= ~NFS_MOUNT_VER3;
+			root = &fh;
+			root->size = NFS2_FHSIZE;
+			memcpy(root->data, data->old_root.data, NFS2_FHSIZE);
+		}
 	}
 
 	/* We now require that the mount process passes the remote address */
 	memcpy(&srvaddr, &data->addr, sizeof(srvaddr));
-	if (srvaddr.sin_addr.s_addr == INADDR_ANY)
-		goto out_no_remote;
+	if (srvaddr.sin_addr.s_addr == INADDR_ANY) {
+		printk(KERN_WARNING "NFS: mount program didn't pass remote address!\n");
+		goto failure;
+	}
 
 	lock_super(sb);
 
@@ -237,12 +316,16 @@
 
 	sb->s_magic      = NFS_SUPER_MAGIC;
 	sb->s_op         = &nfs_sops;
-	sb->s_blocksize  = nfs_block_size(data->bsize, &sb->s_blocksize_bits);
-	sb->u.nfs_sb.s_root = data->root;
+
+	sb->s_blocksize_bits = 0;
+	sb->s_blocksize = nfs_block_bits(data->bsize, &sb->s_blocksize_bits);
+
 	server           = &sb->u.nfs_sb.s_server;
+	memset(server, 0, sizeof(*server));
+
 	server->rsize    = nfs_block_size(data->rsize, NULL);
 	server->wsize    = nfs_block_size(data->wsize, NULL);
-	server->flags    = data->flags;
+	server->flags    = data->flags & NFS_MOUNT_FLAGMASK;
 
 	if (data->flags & NFS_MOUNT_NOAC) {
 		data->acregmin = data->acregmax = 0;
@@ -253,11 +336,34 @@
 	server->acdirmin = data->acdirmin*HZ;
 	server->acdirmax = data->acdirmax*HZ;
 
+	server->namelen  = data->namlen;
 	server->hostname = kmalloc(strlen(data->hostname) + 1, GFP_KERNEL);
 	if (!server->hostname)
-		goto out_unlock;
+		goto failure_unlock;
 	strcpy(server->hostname, data->hostname);
 
+ nfsv3_try_again:
+	/* Check NFS protocol revision and initialize RPC op vector
+	 * and file handle pool. */
+	if (data->flags & NFS_MOUNT_VER3) {
+#ifdef CONFIG_NFS_V3
+		server->rpc_ops = &nfs_v3_clientops;
+		NFS_SB_FHSIZE(sb) = sizeof(unsigned short) + NFS3_FHSIZE;
+		version = 3;
+		if (data->version < 4) {
+			printk(KERN_NOTICE "NFS: NFSv3 not supported by mount program.\n");
+			goto failure_unlock;
+		}
+#else
+		printk(KERN_NOTICE "NFS: NFSv3 not supported.\n");
+		goto failure_unlock;
+#endif
+	} else {
+		server->rpc_ops = &nfs_v2_clientops;
+		NFS_SB_FHSIZE(sb) = sizeof(unsigned short) + NFS2_FHSIZE;
+		version = 2;
+	}
+
 	/* Which protocol do we use? */
 	tcp   = (data->flags & NFS_MOUNT_TCP);
 
@@ -267,11 +373,18 @@
 	timeparms.to_maxval  = tcp? RPC_MAX_TCP_TIMEOUT : RPC_MAX_UDP_TIMEOUT;
 	timeparms.to_exponential = 1;
 
+	if (!timeparms.to_initval)
+		timeparms.to_initval = (tcp ? 600 : 11) * HZ / 10;
+	if (!timeparms.to_retries)
+		timeparms.to_retries = 5;
+
 	/* Now create transport and client */
 	xprt = xprt_create_proto(tcp? IPPROTO_TCP : IPPROTO_UDP,
 						&srvaddr, &timeparms);
-	if (xprt == NULL)
-		goto out_no_xprt;
+	if (xprt == NULL) {
+		printk(KERN_NOTICE "NFS: cannot create RPC transport. \n");
+		goto failure_unlock;
+	}
 
 	/* Choose authentication flavor */
 	authflavor = RPC_AUTH_UNIX;
@@ -281,9 +394,11 @@
 		authflavor = RPC_AUTH_KRB;
 
 	clnt = rpc_create_client(xprt, server->hostname, &nfs_program,
-						NFS_VERSION, authflavor);
-	if (clnt == NULL)
-		goto out_no_client;
+						version, authflavor);
+	if (clnt == NULL) {
+		printk(KERN_NOTICE "NFS: cannot create RPC client \n");
+		goto failure_unlock;
+	}
 
 	clnt->cl_intr     = (data->flags & NFS_MOUNT_INTR)? 1 : 0;
 	clnt->cl_softrtry = (data->flags & NFS_MOUNT_SOFT)? 1 : 0;
@@ -291,82 +406,130 @@
 	server->client    = clnt;
 
 	/* Fire up rpciod if not yet running */
-	if (rpciod_up() != 0)
-		goto out_no_iod;
+	if (rpciod_up() != 0) {
+		printk(KERN_NOTICE "NFS: cannot start rpciod!\n");
+		goto failure_unlock;
+	}
 
 	/*
 	 * Keep the super block locked while we try to get 
 	 * the root fh attributes.
 	 */
-	root_fh = kmalloc(sizeof(struct nfs_fh), GFP_KERNEL);
-	if (!root_fh)
+	root_d_fsdata = nfs_fh_alloc();
+	if (!root_d_fsdata)
 		goto out_no_fh;
-	*root_fh = data->root;
 
-	if (nfs_proc_getattr(server, root_fh, &fattr) != 0)
-		goto out_no_fattr;
+	root_fh = &root_d_fsdata->fh;
+	memcpy((u8*)root_fh, (u8*)root, sizeof(*root));
 
-	root_inode = __nfs_fhget(sb, &fattr);
+	/* Did getting the root inode fail? */
+	if ((root->size > NFS_SB_FHSIZE(sb)
+	     || ! (root_inode = nfs_get_root(sb, root)))
+	    && (data->flags & NFS_MOUNT_VER3)) {
+		data->flags &= ~NFS_MOUNT_VER3;
+		nfs_fh_free(root_d_fsdata);
+		rpciod_down();
+		rpc_shutdown_client(server->client);
+		goto nfsv3_try_again;
+	}
 	if (!root_inode)
-		goto out_no_root;
-	sb->s_root = d_alloc_root(root_inode, NULL);
-	if (!sb->s_root)
-		goto out_no_root;
+		goto failure_put_root;
+
+	if (! (sb->s_root = d_alloc_root(root_inode, NULL)))
+		goto failure_put_root;
+
 	sb->s_root->d_op = &nfs_dentry_operations;
-	sb->s_root->d_fsdata = root_fh;
+	sb->s_root->d_fsdata = root_d_fsdata;
+	sb->u.nfs_sb.s_root = root_fh;
 
+	/* Get some general file system info */
+	if (server->rpc_ops->statfs(server, root, &fsinfo) >= 0) {
+		if (server->namelen == 0)
+			server->namelen = fsinfo.namelen;
+	} else {
+		printk(KERN_NOTICE "NFS: cannot retrieve file system info.\n");
+		goto failure_put_root;
+	}
+
+	/* Fire up the writeback cache */
+	if (nfs_reqlist_alloc(server) < 0) {
+		printk(KERN_NOTICE "NFS: cannot initialize writeback cache.\n");
+                goto failure_kill_reqlist;
+	}
+
+	if (data->rsize == 0)
+		server->rsize = nfs_block_size(fsinfo.rtpref, NULL);
+	if (data->wsize == 0)
+		server->wsize = nfs_block_size(fsinfo.wtpref, NULL);
+
+	server->dtsize = nfs_block_size(fsinfo.dtpref, NULL);
+
+	/* NFSv3: we don't have bsize, but rather rtmult and wtmult... */
+	if (!fsinfo.bsize)
+		fsinfo.bsize = (fsinfo.rtmult>fsinfo.wtmult) ? fsinfo.rtmult : fsinfo.wtmult;
+	/* Also make sure we don't go below rsize/wsize since
+	 * RPC calls are expensive */
+	if (fsinfo.bsize < server->rsize)
+		fsinfo.bsize = server->rsize;
+	if (fsinfo.bsize < server->wsize)
+		fsinfo.bsize = server->wsize;
+
+	if (data->bsize == 0)
+		sb->s_blocksize = nfs_block_bits(fsinfo.bsize, &sb->s_blocksize_bits);
+	if (server->rsize > fsinfo.rtmax)
+		server->rsize = fsinfo.rtmax;
+	server->rpages = (server->rsize + PAGE_CACHE_SIZE - 1) >> PAGE_CACHE_SHIFT;
+	if (server->rpages > NFS_READ_MAXIOV) {
+		server->rpages = NFS_READ_MAXIOV;
+		server->rsize = server->rpages << PAGE_CACHE_SHIFT;
+	}
+
+	if (server->wsize > fsinfo.wtmax)
+		server->wsize = fsinfo.wtmax;
+	server->wpages = (server->wsize + PAGE_CACHE_SIZE - 1) >> PAGE_CACHE_SHIFT;
+	if (server->wpages > NFS_WRITE_MAXIOV) {
+		server->wpages = NFS_WRITE_MAXIOV;
+		server->wsize = server->wpages << PAGE_CACHE_SHIFT;
+	}
+
+	maxlen = (version == 2) ? NFS2_MAXNAMLEN : NFS3_MAXNAMLEN;
+
+	if (server->namelen == 0 || server->namelen > maxlen)
+		server->namelen = maxlen;
+
 	/* We're airborne */
 	unlock_super(sb);
 
-#if 0
 	/* Check whether to start the lockd process */
 	if (!(server->flags & NFS_MOUNT_NONLM))
 		lockd_up();
-#endif
+
 	return sb;
 
 	/* Yargs. It didn't work out. */
-out_no_root:
-	printk("nfs_read_super: get root inode failed\n");
-	iput(root_inode);
-	goto out_free_fh;
-
-out_no_fattr:
-	printk("nfs_read_super: get root fattr failed\n");
-out_free_fh:
-	kfree(root_fh);
-out_no_fh:
+ failure_kill_reqlist:
+	nfs_reqlist_exit(server);
+ failure_put_root:
+	if (root_inode)
+		iput(root_inode);
+	if (root_d_fsdata)
+		nfs_fh_free(root_d_fsdata);
+ out_no_fh:
 	rpciod_down();
-	goto out_shutdown;
-
-out_no_iod:
-	printk(KERN_WARNING "NFS: couldn't start rpciod!\n");
-out_shutdown:
-	rpc_shutdown_client(server->client);
-	goto out_free_host;
-
-out_no_client:
-	printk(KERN_WARNING "NFS: cannot create RPC client.\n");
-	xprt_destroy(xprt);
-	goto out_free_host;
-
-out_no_xprt:
-	printk(KERN_WARNING "NFS: cannot create RPC transport.\n");
 
-out_free_host:
-	kfree(server->hostname);
-out_unlock:
+ failure_unlock:
+	/* Yargs. It didn't work out. */
+	if (clnt)
+		rpc_shutdown_client(server->client);
+	else if (xprt)
+		xprt_destroy(xprt);
 	unlock_super(sb);
-	goto out_fail;
-
-out_no_remote:
-	printk("NFS: mount program didn't pass remote address!\n");
-	goto out_fail;
-
-out_miss_args:
-	printk("nfs_read_super: missing data argument\n");
+	nfs_reqlist_free(server);
+	if (server->hostname)
+		kfree(server->hostname);
+	printk(KERN_NOTICE "NFS: cannot create RPC transport.\n");
 
-out_fail:
+failure:
 	sb->s_dev = 0;
 	MOD_DEC_USE_COUNT;
 	return NULL;
@@ -375,27 +538,51 @@
 static int
 nfs_statfs(struct super_block *sb, struct statfs *buf, int bufsiz)
 {
-	int error;
-	struct nfs_fsinfo res;
-	struct statfs tmp;
+	struct nfs_sb_info	*si = &sb->u.nfs_sb;
+	struct nfs_server	*server = &si->s_server;
+	unsigned char		blockbits;
+	unsigned long		blockres;
+	int			error;
+	struct nfs_fsinfo	res;
+	struct statfs		tmp;
 
-	error = nfs_proc_statfs(&sb->u.nfs_sb.s_server, &sb->u.nfs_sb.s_root,
-		&res);
+	error = server->rpc_ops->statfs(server, NFS_FH(sb->s_root), &res);
 	if (error) {
-		printk("nfs_statfs: statfs error = %d\n", -error);
-		res.bsize = res.blocks = res.bfree = res.bavail = 0;
+		printk(KERN_NOTICE "nfs_statfs: statfs error = %d\n", -error);
+		memset(&res, 0, sizeof(res));
 	}
 	tmp.f_type = NFS_SUPER_MAGIC;
-	tmp.f_bsize = res.bsize;
-	tmp.f_blocks = res.blocks;
-	tmp.f_bfree = res.bfree;
-	tmp.f_bavail = res.bavail;
-	tmp.f_files = 0;
-	tmp.f_ffree = 0;
-	tmp.f_namelen = NAME_MAX;
+	if (res.bsize == 0)
+		res.bsize = sb->s_blocksize;
+	if (res.namelen == 0)
+		res.namelen = server->namelen;
+	tmp.f_bsize   = nfs_block_bits(res.bsize, &blockbits);
+	blockres = (1 << blockbits) - 1;
+	tmp.f_blocks  = (res.tbytes + blockres) >> blockbits;
+	tmp.f_bfree   = (res.fbytes + blockres) >> blockbits;
+	tmp.f_bavail  = (res.abytes + blockres) >> blockbits;
+	tmp.f_files   = res.tfiles;
+	tmp.f_ffree   = res.ffiles;
+	tmp.f_namelen = res.namelen;
 	return copy_to_user(buf, &tmp, bufsiz) ? -EFAULT : 0;
 }
 
+#if 0
+int nfs_remountfs(struct super_block *sb, int *flags, char *data)
+{
+	struct nfs_server *server = &sb->u.nfs_sb.s_server;
+
+	if (*flags & ~(NFS_MOUNT_NONLM|MS_RDONLY))
+		return -EINVAL;
+
+	if (*flags & ~NFS_MOUNT_NONLM)
+		return 0;
+
+	if ((*flags & NFS_MOUNT_NONLM) == (server->flags & NFS_MOUNT_NONLM))
+		return 0;
+}
+#endif
+
 /*
  * Free all unused dentries in an inode's alias list.
  *
@@ -417,11 +604,11 @@
 	unhashed = 0;
 	while ((tmp = tmp->next) != head) {
 		struct dentry *dentry = list_entry(tmp, struct dentry, d_alias);
-		if (!list_empty(&dentry->d_subdirs))
-			shrink_dcache_parent(dentry);
 		dprintk("nfs_free_dentries: found %s/%s, d_count=%d, hashed=%d\n",
 			dentry->d_parent->d_name.name, dentry->d_name.name,
 			dentry->d_count, !list_empty(&dentry->d_hash));
+		if (!list_empty(&dentry->d_subdirs))
+			shrink_dcache_parent(dentry);
 		if (!dentry->d_count) {
 			dget(dentry);
 			d_drop(dentry);
@@ -435,23 +622,19 @@
 }
 
 /*
- * Invalidate the local caches
+ * Zap the caches.
  */
-static void
-nfs_zap_caches(struct inode *inode)
+void nfs_zap_caches(struct inode *inode)
 {
 	NFS_ATTRTIMEO(inode) = NFS_MINATTRTIMEO(inode);
-	NFS_CACHEINV(inode);
+	NFS_ATTRTIMEO_UPDATE(inode) = jiffies;
 
-	if (S_ISDIR(inode->i_mode))
-		nfs_invalidate_dircache(inode);
-	else
-		invalidate_inode_pages(inode);
+	invalidate_inode_pages(inode);
+
+	memset(NFS_COOKIEVERF(inode), 0, sizeof(NFS_COOKIEVERF(inode)));
+	NFS_CACHEINV(inode);
 }
 
-/*
- * Invalidate, but do not unhash, the inode
- */
 static void
 nfs_invalidate_inode(struct inode *inode)
 {
@@ -459,7 +642,6 @@
 
 	make_bad_inode(inode);
 	inode->i_mode = save_mode;
-	nfs_inval(inode);
 	nfs_zap_caches(inode);
 }
 
@@ -474,6 +656,8 @@
 	 * do this once. (We don't allow inodes to change types.)
 	 */
 	if (inode->i_mode == 0) {
+		NFS_FILEID(inode) = fattr->fileid;
+		NFS_FSID(inode) = fattr->fsid;
 		inode->i_mode = fattr->mode;
 		if (S_ISREG(inode->i_mode))
 			inode->i_op = &nfs_file_inode_operations;
@@ -494,26 +678,62 @@
 		/*
 		 * Preset the size and mtime, as there's no need
 		 * to invalidate the caches.
-		 */ 
-		inode->i_size  = fattr->size;
-		inode->i_mtime = fattr->mtime.seconds;
-		NFS_OLDMTIME(inode) = fattr->mtime.seconds;
+		 */
+		inode->i_size  = nfs_size_to_off_t(fattr->size);
+		inode->i_mtime = nfs_time_to_secs(fattr->mtime);
+		inode->i_atime = nfs_time_to_secs(fattr->atime);
+		inode->i_ctime = nfs_time_to_secs(fattr->ctime);
+		NFS_CACHE_CTIME(inode) = fattr->ctime;
+		NFS_CACHE_MTIME(inode) = fattr->mtime;
+		NFS_CACHE_ATIME(inode) = fattr->atime;
+		NFS_CACHE_ISIZE(inode) = fattr->size;
+		NFS_ATTRTIMEO(inode) = NFS_MINATTRTIMEO(inode);
+		NFS_ATTRTIMEO_UPDATE(inode) = jiffies;
 	}
 	nfs_refresh_inode(inode, fattr);
 }
 
+static struct inode *
+nfs_make_new_inode(struct super_block *sb, struct nfs_fattr *fattr)
+{
+	struct inode *inode = get_empty_inode();
+
+	if (!inode)
+		return NULL;	
+	inode->i_sb = sb;
+	inode->i_dev = sb->s_dev;
+	inode->i_flags = 0;
+	inode->i_ino = nfs_fattr_to_ino_t(fattr);
+	nfs_read_inode(inode);
+	nfs_fill_inode(inode, fattr);
+	return inode;
+}
+
 /*
- * The following may seem pretty minimal, but the stateless nature
- * of NFS means that we can't do too much more. Previous attempts to use
- * fattr->nlink to determine how well the cached state matches the
- * server suffer from races with stale dentries. You also risk killing
- * off processes by just doing 'mv file newdir' on the server.
- *
- * FIXME: Of course, if 2 exported files have the same fileid (but
- * different fsid which makes it legal) you're still buggered...
- *                                      Trond, August 1999.
+ * In NFSv3 we can have 64bit inode numbers. In order to support
+ * this, and re-exported directories (also seen in NFSv2)
+ * we are forced to allow 2 different inodes to have the same
+ * i_ino.
  */
 static int
+nfs_find_actor(struct inode *inode, unsigned long ino, void *opaque)
+{
+	struct nfs_fattr *fattr = (struct nfs_fattr *)opaque;
+	if (NFS_FSID(inode) != fattr->fsid)
+		return 0;
+	if (NFS_FILEID(inode) != fattr->fileid)
+		return 0;
+	if (inode->i_mode &&
+	    (fattr->mode & S_IFMT) != (inode->i_mode & S_IFMT))
+		return 0;
+	if (is_bad_inode(inode))
+		return 0;
+	if (NFS_FLAGS(inode) & NFS_INO_STALE)
+		return 0;
+	return 1;
+}
+
+static int
 nfs_inode_is_stale(struct inode *inode, struct nfs_fattr *fattr)
 {
 	int unhashed;
@@ -527,16 +747,16 @@
 		is_stale = 1;
 
 	/*
-	 * Free up unused cached dentries to see if it's wise to unhash
-	 * the inode (which we can do if all the dentries have been unhashed).
+	 * If the inode seems stale, free up cached dentries.
 	 */
 	unhashed = nfs_free_dentries(inode);
 
-	/* Assume we're holding 1 lock on the inode from 'iget'
+	/* Assume we're holding an i_count
 	 *
 	 * NB: sockets sometimes have volatile file handles
 	 *     don't invalidate their inodes even if all dentries are
-	 *     unhashed. */
+	 *     unhashed.
+	 */
 	if (unhashed && inode->i_count == unhashed + 1
 	    && !S_ISSOCK(inode->i_mode) && !S_ISFIFO(inode->i_mode))
 		is_stale = 1;
@@ -559,12 +779,12 @@
 {
 	struct super_block *sb = dentry->d_sb;
 
-	dprintk("NFS: nfs_fhget(%s/%s fileid=%d)\n",
+	dprintk("NFS: nfs_fhget(%s/%s fileid=%Lu)\n",
 		dentry->d_parent->d_name.name, dentry->d_name.name,
-		fattr->fileid);
+		(long long) fattr->fileid);
 
 	/* Install the file handle in the dentry */
-	*((struct nfs_fh *) dentry->d_fsdata) = *fhandle;
+	memcpy(NFS_FH(dentry), (u8*)fhandle, sizeof(*fhandle));
 
 #ifdef CONFIG_NFS_SNAPSHOT
 	/*
@@ -574,15 +794,9 @@
 	if ((dentry->d_parent->d_inode->u.nfs_i.flags & NFS_IS_SNAPSHOT) ||
 	    (dentry->d_name.len == 9 &&
 	     memcmp(dentry->d_name.name, ".snapshot", 9) == 0)) {
-		struct inode *inode = get_empty_inode();
+		struct inode *inode = nfs_make_new_inode(sb, fattr);
 		if (!inode)
-			goto out;	
-		inode->i_sb = sb;
-		inode->i_dev = sb->s_dev;
-		inode->i_flags = 0;
-		inode->i_ino = fattr->fileid;
-		nfs_read_inode(inode);
-		nfs_fill_inode(inode, fattr);
+			goto out;
 		inode->u.nfs_i.flags |= NFS_IS_SNAPSHOT;
 		dprintk("NFS: nfs_fhget(snapshot ino=%ld)\n", inode->i_ino);
 	out:
@@ -603,27 +817,39 @@
 static struct inode *
 __nfs_fhget(struct super_block *sb, struct nfs_fattr *fattr)
 {
-	struct inode *inode = NULL;
+	struct inode	*inode = NULL;
+	unsigned long	ino;
 
-	if (!fattr)
+	if ((fattr->valid & NFS_ATTR_FATTR) == 0)
 		goto out_no_inode;
 
-	while (!inode) {
-		inode = iget(sb, fattr->fileid);
-		if (!inode)
-			goto out_no_inode;
-		/* N.B. This should be impossible ... */
-		if (inode->i_ino != fattr->fileid)
-			goto out_bad_id;
+	ino = nfs_fattr_to_ino_t(fattr);
+
+	while((inode = iget4(sb, ino, nfs_find_actor, fattr)) != NULL) {
 
+		/*
+		 * Check for busy inodes, and attempt to get rid of any
+		 * unused local references. If successful, we release the
+		 * inode and try again.
+		 *
+		 * Note that the busy test uses the values in the fattr,
+		 * as the inode may have become a different object.
+		 * (We can probably handle modes changes here, too.)
+		 */
 		if (!nfs_inode_is_stale(inode,fattr))
 			break;
 
-		remove_inode_hash(inode);
-		nfs_invalidate_inode(inode);
+		dprintk("__nfs_fhget: inode %ld still busy, i_count=%d\n",
+		       inode->i_ino, inode->i_count);
+		/* Mark the inode as being stale */
+		NFS_FLAGS(inode) |= NFS_INO_STALE;
+		nfs_zap_caches(inode);
 		iput(inode);
-		inode = NULL;
 	}
+
+	if (!inode)
+		goto out_no_inode;
+
 	nfs_fill_inode(inode, fattr);
 	dprintk("NFS: __nfs_fhget(%x/%ld ct=%d)\n",
 		inode->i_dev, inode->i_ino, inode->i_count);
@@ -632,10 +858,7 @@
 	return inode;
 
 out_no_inode:
-	printk("__nfs_fhget: iget failed\n");
-	goto out;
-out_bad_id:
-	printk("__nfs_fhget: unexpected inode from iget\n");
+	printk(KERN_NOTICE "__nfs_fhget: iget failed\n");
 	goto out;
 }
 
@@ -643,9 +866,8 @@
 nfs_notify_change(struct dentry *dentry, struct iattr *attr)
 {
 	struct inode *inode = dentry->d_inode;
-	int error;
-	struct nfs_sattr sattr;
 	struct nfs_fattr fattr;
+	int              error;
 
 	/*
 	 * Make sure the inode is up-to-date.
@@ -653,87 +875,123 @@
 	error = nfs_revalidate(dentry);
 	if (error) {
 #ifdef NFS_PARANOIA
-printk("nfs_notify_change: revalidate failed, error=%d\n", error);
+		printk(KERN_DEBUG "nfs_notify_change: revalidate failed, error=%d\n", error);
 #endif
 		goto out;
 	}
 
-	sattr.mode = (u32) -1;
-	if (attr->ia_valid & ATTR_MODE) 
-		sattr.mode = attr->ia_mode;
-
-	sattr.uid = (u32) -1;
-	if (attr->ia_valid & ATTR_UID)
-		sattr.uid = attr->ia_uid;
-
-	sattr.gid = (u32) -1;
-	if (attr->ia_valid & ATTR_GID)
-		sattr.gid = attr->ia_gid;
-
-	sattr.size = (u32) -1;
-	if ((attr->ia_valid & ATTR_SIZE) && S_ISREG(inode->i_mode))
-		sattr.size = attr->ia_size;
-
-	sattr.mtime.seconds = sattr.mtime.useconds = (u32) -1;
-	if (attr->ia_valid & ATTR_MTIME) {
-		sattr.mtime.seconds = attr->ia_mtime;
-		sattr.mtime.useconds = 0;
-	}
-
-	sattr.atime.seconds = sattr.atime.useconds = (u32) -1;
-	if (attr->ia_valid & ATTR_ATIME) {
-		sattr.atime.seconds = attr->ia_atime;
-		sattr.atime.useconds = 0;
-	}
+	if (!S_ISREG(inode->i_mode))
+		attr->ia_valid &= ~ATTR_SIZE;
 
 	error = nfs_wb_all(inode);
-	if (error)
+	if (error < 0)
 		goto out;
 
-	error = nfs_proc_setattr(NFS_DSERVER(dentry), NFS_FH(dentry),
-				&sattr, &fattr);
-	if (error)
+	/* Now perform the setattr call */
+	error = NFS_CALL(setattr, inode, (dentry, &fattr, attr));
+	if (error || !(fattr.valid & NFS_ATTR_FATTR)) {
+		nfs_zap_caches(inode);
 		goto out;
+	}
 	/*
 	 * If we changed the size or mtime, update the inode
 	 * now to avoid invalidating the page cache.
 	 */
-	if (sattr.size != (u32) -1) {
-		if (sattr.size != fattr.size)
-			printk("nfs_notify_change: sattr=%Ld, fattr=%Ld??\n",
-				sattr.size, fattr.size);
-		inode->i_size  = sattr.size;
-		inode->i_mtime = fattr.mtime.seconds;
+	if (!(fattr.valid & NFS_ATTR_WCC)) {
+		fattr.pre_size = NFS_CACHE_ISIZE(inode);
+		fattr.pre_mtime = NFS_CACHE_MTIME(inode);
+		fattr.pre_ctime = NFS_CACHE_CTIME(inode);
+		fattr.valid |= NFS_ATTR_WCC;
 	}
-	if (sattr.mtime.seconds != (u32) -1)
-		inode->i_mtime = fattr.mtime.seconds;
 	error = nfs_refresh_inode(inode, &fattr);
 out:
 	return error;
 }
 
+int
+nfs_update_atime(struct dentry *dentry)
+{
+	struct iattr attr;
+	struct inode *inode = dentry->d_inode;
+
+	nfs_revalidate(dentry);
+	if (!inode || time_before(inode->i_atime,nfs_time_to_secs(NFS_CACHE_ATIME(inode))))
+		return 0;
+
+	attr.ia_valid = ATTR_ATIME|ATTR_ATIME_SET;
+	attr.ia_atime = inode->i_atime;
+	return nfs_notify_change(dentry, &attr);
+}
+
 /*
- * Externally visible revalidation function
+ * Wait for the inode to get unlocked.
+ * (Used for NFS_INO_LOCKED and NFS_INO_REVALIDATING).
  */
 int
-nfs_revalidate(struct dentry *dentry)
+nfs_wait_on_inode(struct inode *inode, int flag)
 {
-	return nfs_revalidate_inode(NFS_DSERVER(dentry), dentry);
+	struct rpc_clnt		*clnt = NFS_CLIENT(inode);
+	int error;
+	if (!(NFS_FLAGS(inode) & flag))
+		return 0;
+	inode->i_count++;
+	error = nfs_wait_event(clnt, inode->i_wait, !(NFS_FLAGS(inode) & flag));
+	iput(inode);
+	return error;
 }
 
 /*
- * These are probably going to contain hooks for
- * allocating and releasing RPC credentials for
- * the file. I'll have to think about Tronds patch
- * a bit more..
+ * Externally visible revalidation function
  */
+int
+nfs_revalidate(struct dentry *dentry)
+{
+	return nfs_revalidate_inode(dentry);
+}
+
+static __inline__ struct nfs_file *nfs_file_alloc(void)
+{
+	struct nfs_file	*p;
+	p = kmalloc(sizeof(*p), GFP_KERNEL);
+	if (p) {
+		memset(p, 0, sizeof(*p));
+		p->magic = NFS_FILE_MAGIC;
+	}
+	return p;
+}
+
+static __inline__ void nfs_file_free(struct nfs_file *p)
+{
+	if (p->magic == NFS_FILE_MAGIC) {
+		p->magic = 0;
+		kfree(p);
+	} else
+		printk(KERN_ERR "NFS: extra file info corrupted!\n");
+}
+
 int nfs_open(struct inode *inode, struct file *filp)
 {
+	struct rpc_auth	*auth = NFS_CLIENT(inode)->cl_auth;
+	struct nfs_file	*data;
+
+	data = nfs_file_alloc();
+	if (!data)
+		return -ENOMEM;
+	data->cred = rpcauth_lookupcred(auth, 0);
+	filp->private_data = data;
 	return 0;
 }
 
 int nfs_release(struct inode *inode, struct file *filp)
 {
+	struct nfs_file	*data = NFS_FILE(filp);
+	struct rpc_auth	*auth = NFS_CLIENT(inode)->cl_auth;
+	struct rpc_cred	*cred;
+
+	cred = nfs_file_cred(filp);
+	if (cred)
+		rpcauth_releasecred(auth, cred);
+	nfs_file_free(data);
 	return 0;
 }
 
@@ -742,25 +1000,44 @@
  * the cached attributes have to be refreshed.
  */
 int
-_nfs_revalidate_inode(struct nfs_server *server, struct dentry *dentry)
+__nfs_revalidate_inode(struct dentry *dentry)
 {
 	struct inode	*inode = dentry->d_inode;
-	int		 status = 0;
 	struct nfs_fattr fattr;
+	int		 status = 0;
 
 	dfprintk(PAGECACHE, "NFS: revalidating %s/%s, ino=%ld\n",
 		dentry->d_parent->d_name.name, dentry->d_name.name,
 		inode->i_ino);
-	status = nfs_proc_getattr(server, NFS_FH(dentry), &fattr);
+
+	if (!inode || is_bad_inode(inode))
+		return -ESTALE;
+
+	while (NFS_REVALIDATING(inode)) {
+		status = nfs_wait_on_inode(inode, NFS_INO_REVALIDATING);
+		if (status < 0)
+			return status;
+		if (time_before(jiffies,NFS_READTIME(inode)+NFS_ATTRTIMEO(inode)))
+			return 0;
+	}
+	NFS_FLAGS(inode) |= NFS_INO_REVALIDATING;
+
+	status = NFS_CALL(getattr, inode, (dentry, &fattr));
 	if (status) {
 		int error;
 		u32 *fh;
+		struct dentry *dir = dentry->d_parent;
 		struct nfs_fh fhandle;
+		struct nfs_fattr dir_attr;
+
 		dfprintk(PAGECACHE, "nfs_revalidate_inode: %s/%s getattr failed, ino=%ld, error=%d\n",
-			dentry->d_parent->d_name.name,
-			dentry->d_name.name, inode->i_ino, status);
+		       dentry->d_parent->d_name.name, dentry->d_name.name,
+		       inode->i_ino, status);
+		nfs_zap_caches(inode);
+
 		if (status != -ESTALE)
 			goto out;
+
 		/*
 		 * A "stale filehandle" error ... show the current fh
 		 * and find out what the filehandle should be.
@@ -768,8 +1045,9 @@
 		fh = (u32 *) NFS_FH(dentry);
 		dfprintk(PAGECACHE, "NFS: bad fh %08x%08x%08x%08x%08x%08x%08x%08x\n",
 			fh[0],fh[1],fh[2],fh[3],fh[4],fh[5],fh[6],fh[7]);
-		error = nfs_proc_lookup(server, NFS_FH(dentry->d_parent), 
-					dentry->d_name.name, &fhandle, &fattr);
+		error = NFS_CALL(lookup, dir->d_inode, (dir, &dir_attr, 
+					&dentry->d_name, &fhandle, &fattr));
+		nfs_refresh_inode(dir->d_inode, &dir_attr);
 		if (error) {
 			dfprintk(PAGECACHE, "NFS: lookup failed, error=%d\n", error);
 			goto out;
@@ -785,13 +1063,16 @@
 	status = nfs_refresh_inode(inode, &fattr);
 	if (status) {
 		dfprintk(PAGECACHE, "nfs_revalidate_inode: %s/%s refresh failed, ino=%ld, error=%d\n",
-			dentry->d_parent->d_name.name,
-			dentry->d_name.name, inode->i_ino, status);
+			 dentry->d_parent->d_name.name, dentry->d_name.name,
+			 inode->i_ino, status);
 		goto out;
 	}
+
 	dfprintk(PAGECACHE, "NFS: %s/%s revalidation complete\n",
 		dentry->d_parent->d_name.name, dentry->d_name.name);
 out:
+	NFS_FLAGS(inode) &= ~NFS_INO_REVALIDATING;
+	wake_up(&inode->i_wait);
 	return status;
 }
 
@@ -800,29 +1081,54 @@
  * an operation.  Here we update the inode to reflect the state
  * of the server's inode.
  *
- * This is a bit tricky because we have to make sure all dirty pages
- * have been sent off to the server before calling invalidate_inode_pages.
- * To make sure no other process adds more write requests while we try
- * our best to flush them, we make them sleep during the attribute refresh.
+ * If we have reason to believe that any data we cached has become
+ * invalid, we schedule it to be flushed on the next occasion
+ * (i.e. when nfs_revalidate_inode is called).
  *
- * A very similar scenario holds for the dir cache.
+ * The reason we don't do it here is because nfs_refresh_inode can
+ * be called outside of the process context, e.g. from nfs_readpage_result,
+ * which is invoked by rpciod.
  */
 int
 nfs_refresh_inode(struct inode *inode, struct nfs_fattr *fattr)
 {
-	int invalid = 0;
-	int error = -EIO;
+	off_t		new_size, new_isize;
+	__u64		new_mtime;
+	int		invalid = 0;
+	int		error = -EIO;
 
-	dfprintk(VFS, "NFS: refresh_inode(%x/%ld ct=%d)\n",
-		 inode->i_dev, inode->i_ino, inode->i_count);
-
 	if (!inode || !fattr) {
-		printk("nfs_refresh_inode: inode or fattr is NULL\n");
+		printk(KERN_ERR "nfs_refresh_inode: inode or fattr is NULL\n");
+		goto out;
+	}
+	if (inode->i_mode == 0) {
+		printk(KERN_ERR "nfs_refresh_inode: empty inode\n");
 		goto out;
 	}
-	if (inode->i_ino != fattr->fileid) {
-		printk("nfs_refresh_inode: mismatch, ino=%ld, fattr=%d\n",
-			inode->i_ino, fattr->fileid);
+
+	if ((fattr->valid & NFS_ATTR_FATTR) == 0)
+		goto out;
+
+	if (is_bad_inode(inode))
+		goto out;
+
+	dfprintk(VFS, "NFS: refresh_inode(%x/%ld ct=%d info=0x%x)\n",
+			inode->i_dev, inode->i_ino, inode->i_count,
+			fattr->valid);
+
+
+	if (NFS_FSID(inode) != fattr->fsid ||
+	    NFS_FILEID(inode) != fattr->fileid) {
+		printk(KERN_ERR "nfs_refresh_inode: inode number mismatch\n"
+		       "expected (0x%lx%08lx/0x%lx%08lx), got (0x%lx%08lx/0x%lx%08lx)\n",
+		       (unsigned long) (NFS_FSID(inode)>>32),
+		       (unsigned long) (NFS_FSID(inode) & 0xFFFFFFFFUL),
+		       (unsigned long) (NFS_FILEID(inode)>>32),
+		       (unsigned long) (NFS_FILEID(inode) & 0xFFFFFFFFUL),
+		       (unsigned long) (fattr->fsid >> 32),
+		       (unsigned long) (fattr->fsid & 0xFFFFFFFFUL),
+		       (unsigned long) (fattr->fileid >> 32),
+		       (unsigned long) (fattr->fileid & 0xFFFFFFFFUL));
 		goto out;
 	}
 
@@ -832,55 +1138,102 @@
 	if ((inode->i_mode & S_IFMT) != (fattr->mode & S_IFMT))
 		goto out_changed;
 
-	inode->i_mode = fattr->mode;
-	inode->i_nlink = fattr->nlink;
-	inode->i_uid = fattr->uid;
-	inode->i_gid = fattr->gid;
+ 	new_mtime = fattr->mtime;
+	new_size = fattr->size;
+ 	new_isize = nfs_size_to_off_t(fattr->size);
 
-	inode->i_blocks = fattr->blocks;
-	inode->i_atime = fattr->atime.seconds;
-	inode->i_ctime = fattr->ctime.seconds;
+	error = 0;
 
 	/*
 	 * Update the read time so we don't revalidate too often.
 	 */
 	NFS_READTIME(inode) = jiffies;
-	error = 0;
 
 	/*
-	 * If we have pending write-back entries, we don't want
-	 * to look at the size or the mtime the server sends us
-	 * too closely, as we're in the middle of modifying them.
+	 * Note: NFS_CACHE_ISIZE(inode) reflects the state of the cache.
+	 *       NOT inode->i_size!!!
 	 */
-	if (NFS_WRITEBACK(inode))
-		goto out;
-
-	if (inode->i_size != fattr->size) {
+	if (NFS_CACHE_ISIZE(inode) != new_size) {
 #ifdef NFS_DEBUG_VERBOSE
-printk("NFS: size change on %x/%ld\n", inode->i_dev, inode->i_ino);
+		printk(KERN_DEBUG "NFS: isize change on %x/%ld\n", inode->i_dev, inode->i_ino);
 #endif
-		inode->i_size = fattr->size;
 		invalid = 1;
 	}
 
-	if (inode->i_mtime != fattr->mtime.seconds) {
+	/*
+	 * Note: we don't check inode->i_mtime since pipes etc.
+	 *       can change this value in VFS without requiring a
+	 *	 cache revalidation.
+	 */
+	if (NFS_CACHE_MTIME(inode) != new_mtime) {
 #ifdef NFS_DEBUG_VERBOSE
-printk("NFS: mtime change on %x/%ld\n", inode->i_dev, inode->i_ino);
+		printk(KERN_DEBUG "NFS: mtime change on %x/%ld\n", inode->i_dev, inode->i_ino);
 #endif
-		inode->i_mtime = fattr->mtime.seconds;
 		invalid = 1;
 	}
 
-	if (invalid)
-		goto out_invalid;
+	/* Check Weak Cache Consistency data.
+	 * If size and mtime match the pre-operation values, we can
+	 * assume that any attribute changes were caused by our NFS
+         * operation, so there's no need to invalidate the caches.
+         */
+        if ((fattr->valid & NFS_ATTR_WCC)
+	    && NFS_CACHE_ISIZE(inode) == fattr->pre_size
+	    && NFS_CACHE_MTIME(inode) == fattr->pre_mtime) {
+		invalid = 0;
+	}
+
+	/*
+	 * If we have pending writebacks, things can get
+	 * messy.
+	 */
+	if (nfs_have_writebacks(inode) && new_isize < inode->i_size)
+		new_isize = inode->i_size;
+
+	NFS_CACHE_CTIME(inode) = fattr->ctime;
+	inode->i_ctime = nfs_time_to_secs(fattr->ctime);
+	/* If we've been messing around with atime, don't
+	 * update it. Save the server value in NFS_CACHE_ATIME.
+	 */
+	NFS_CACHE_ATIME(inode) = fattr->atime;
+	if (time_before(inode->i_atime, nfs_time_to_secs(fattr->atime)))
+		inode->i_atime = nfs_time_to_secs(fattr->atime);
+
+	NFS_CACHE_MTIME(inode) = new_mtime;
+	inode->i_mtime = nfs_time_to_secs(new_mtime);
+
+	NFS_CACHE_ISIZE(inode) = new_size;
+	inode->i_size = new_isize;
 
+	inode->i_mode = fattr->mode;
+	inode->i_nlink = fattr->nlink;
+	inode->i_uid = fattr->uid;
+	inode->i_gid = fattr->gid;
+
+	if (fattr->valid & NFS_ATTR_FATTR_V3) {
+		/*
+		 * report the blocks in 512byte units
+		 */
+		inode->i_blocks = nfs_calc_block_size(fattr->du.nfs3.used);
+		inode->i_blksize = inode->i_sb->s_blocksize;
+ 	} else {
+ 		inode->i_blocks = fattr->du.nfs2.blocks;
+ 		inode->i_blksize = fattr->du.nfs2.blocksize;
+ 	}
+ 	inode->i_rdev = 0;
+ 	if (S_ISCHR(inode->i_mode) || S_ISBLK(inode->i_mode))
+ 		inode->i_rdev = to_kdev_t(fattr->rdev);
+ 
 	/* Update attrtimeo value */
-	if (fattr->mtime.seconds == NFS_OLDMTIME(inode)) {
+	if (!invalid && time_after(jiffies, NFS_ATTRTIMEO_UPDATE(inode)+NFS_ATTRTIMEO(inode))) {
 		if ((NFS_ATTRTIMEO(inode) <<= 1) > NFS_MAXATTRTIMEO(inode))
 			NFS_ATTRTIMEO(inode) = NFS_MAXATTRTIMEO(inode);
+		NFS_ATTRTIMEO_UPDATE(inode) = jiffies;
 	}
-	NFS_OLDMTIME(inode) = fattr->mtime.seconds;
 
+	if (invalid)
+		nfs_zap_caches(inode);
+
 out:
 	return error;
 
@@ -889,22 +1242,16 @@
 	 * Big trouble! The inode has become a different object.
 	 */
 #ifdef NFS_PARANOIA
-printk("nfs_refresh_inode: inode %ld mode changed, %07o to %07o\n",
-inode->i_ino, inode->i_mode, fattr->mode);
+	printk(KERN_DEBUG "nfs_refresh_inode: inode %ld mode changed, %07o to %07o\n",
+	       inode->i_ino, inode->i_mode, fattr->mode);
 #endif
 	/*
 	 * No need to worry about unhashing the dentry, as the
 	 * lookup validation will know that the inode is bad.
+	 * (But we fall through to invalidate the caches.)
 	 */
 	nfs_invalidate_inode(inode);
 	goto out;
-
-out_invalid:
-#ifdef NFS_DEBUG_VERBOSE
-printk("nfs_refresh_inode: invalidating %ld pages\n", inode->i_nrpages);
-#endif
-	nfs_zap_caches(inode);
-	goto out;
 }
 
 /*
@@ -924,8 +1271,6 @@
 init_nfs_fs(void)
 {
 #ifdef CONFIG_PROC_FS
-	rpc_register_sysctl();
-	rpc_proc_init();
 	rpc_proc_register(&nfs_rpcstat);
 #endif
         return register_filesystem(&nfs_fs_type);
@@ -953,6 +1298,5 @@
 	rpc_proc_unregister("nfs");
 #endif
 	unregister_filesystem(&nfs_fs_type);
-	nfs_free_dircache();
 }
 #endif
Index: oldkernel/linux/fs/nfs/mount_clnt.c
diff -u linux/fs/nfs/mount_clnt.c:1.1.1.1 linux/fs/nfs/mount_clnt.c:1.2
--- linux/fs/nfs/mount_clnt.c:1.1.1.1	Wed May 31 12:33:48 2000
+++ linux/fs/nfs/mount_clnt.c	Fri Jul  7 15:36:46 2000
@@ -17,17 +17,14 @@
 #include <linux/sunrpc/clnt.h>
 #include <linux/sunrpc/xprt.h>
 #include <linux/sunrpc/sched.h>
+#include <linux/nfs2.h>
+#include <linux/nfs3.h>
 #include <linux/nfs_fs.h>
 
 #ifdef RPC_DEBUG
 # define NFSDBG_FACILITY	NFSDBG_ROOT
 #endif
 
-#ifndef MAX
-# define MAX(a, b)	(((a) > (b))? (a) : (b))
-#endif
-
-
 /*
 #define MOUNT_PROGRAM		100005
 #define MOUNT_VERSION		1
@@ -35,7 +32,9 @@
 #define MOUNT_UMNT		3
  */
 
-static struct rpc_clnt *	mnt_create(char *, struct sockaddr_in *);
+static int			nfs_gen_mount(struct sockaddr_in *, char *,
+					      struct nfs_fh *, int);
+static struct rpc_clnt *	mnt_create(char *, struct sockaddr_in *, int);
 extern struct rpc_program	mnt_program;
 
 struct mnt_fhstatus {
@@ -43,30 +42,44 @@
 	struct nfs_fh *		fh;
 };
 
+int
+nfs_mount(struct sockaddr_in *addr, char *path, struct nfs_fh *fh)
+{
+	return nfs_gen_mount(addr, path, fh, NFS_MNT_VERSION);
+}
+
+int
+nfs3_mount(struct sockaddr_in *addr, char *path, struct nfs_fh *fh)
+{
+	return nfs_gen_mount(addr, path, fh, NFS_MNT3_VERSION);
+}
+
 /*
  * Obtain an NFS file handle for the given host and path
  */
-int
-nfs_mount(struct sockaddr_in *addr, char *path, struct nfs_fh *fh)
+static int
+nfs_gen_mount(struct sockaddr_in *addr, char *path, struct nfs_fh *fh, int version)
 {
 	struct rpc_clnt		*mnt_clnt;
 	struct mnt_fhstatus	result = { 0, fh };
 	char			hostname[32];
 	int			status;
+	int			call;
 
 	dprintk("NFS:      nfs_mount(%08x:%s)\n",
 			(unsigned)ntohl(addr->sin_addr.s_addr), path);
 
 	strcpy(hostname, in_ntoa(addr->sin_addr.s_addr));
-	if (!(mnt_clnt = mnt_create(hostname, addr)))
+	if (!(mnt_clnt = mnt_create(hostname, addr, version)))
 		return -EACCES;
 
-	status = rpc_call(mnt_clnt, NFS_MNTPROC_MNT, path, &result, 0);
+	call = (version == 3) ? MOUNTPROC3_MNT : MNTPROC_MNT;
+	status = rpc_call(mnt_clnt, call, path, &result, 0);
 	return status < 0? status : (result.status? -EACCES : 0);
 }
 
 static struct rpc_clnt *
-mnt_create(char *hostname, struct sockaddr_in *srvaddr)
+mnt_create(char *hostname, struct sockaddr_in *srvaddr, int version)
 {
 	struct rpc_xprt	*xprt;
 	struct rpc_clnt	*clnt;
@@ -75,7 +88,7 @@
 		return NULL;
 
 	clnt = rpc_create_client(xprt, hostname,
-				&mnt_program, NFS_MNT_VERSION,
+				&mnt_program, version,
 				RPC_AUTH_NULL);
 	if (!clnt) {
 		xprt_destroy(xprt);
@@ -100,7 +113,7 @@
 static int
 xdr_encode_dirpath(struct rpc_rqst *req, u32 *p, const char *path)
 {
-	p = xdr_encode_string(p, path);
+	p = xdr_encode_string(p, path, -1);
 
 	req->rq_slen = xdr_adjust_iovec(req->rq_svec, p);
 	return 0;
@@ -109,14 +122,39 @@
 static int
 xdr_decode_fhstatus(struct rpc_rqst *req, u32 *p, struct mnt_fhstatus *res)
 {
-	if ((res->status = ntohl(*p++)) == 0)
-		memcpy(res->fh, p, sizeof(*res->fh));
+	struct nfs_fh *fh = res->fh;
+
+	memset((void *)fh, 0, sizeof(*fh));
+	if ((res->status = ntohl(*p++)) == 0) {
+		res->fh->size = NFS2_FHSIZE;
+		memcpy(res->fh->data, p, NFS2_FHSIZE);
+	}
+	return 0;
+}
+
+static int
+xdr_decode_fhstatus3(struct rpc_rqst *req, u32 *p, struct mnt_fhstatus *res)
+{
+	struct nfs_fh *fh = res->fh;
+
+	memset((void *)fh, 0, sizeof(*fh));
+	if ((res->status = ntohl(*p++)) == 0) {
+		unsigned int size = ntohl(*p++);
+		if (size <= NFS3_FHSIZE) {
+			res->fh->size = size;
+			memcpy(res->fh->data, p, size);
+		}
+	}
 	return 0;
 }
 
 #define MNT_dirpath_sz		(1 + 256)
 #define MNT_fhstatus_sz		(1 + 8)
 
+#ifndef MAX
+# define MAX(a, b)      (((a) > (b))? (a) : (b))
+#endif
+
 static struct rpc_procinfo	mnt_procedures[2] = {
 	{ "mnt_null",
 		(kxdrproc_t) xdr_error,	
@@ -124,16 +162,32 @@
 	{ "mnt_mount",
 		(kxdrproc_t) xdr_encode_dirpath,	
 		(kxdrproc_t) xdr_decode_fhstatus,
-		MAX(MNT_dirpath_sz, MNT_fhstatus_sz)<<2, 0},
+		MAX(MNT_dirpath_sz, MNT_fhstatus_sz) << 2, 0 },
+};
+
+static struct rpc_procinfo mnt3_procedures[2] = {
+	{ "mnt3_null",
+		(kxdrproc_t) xdr_error,
+		(kxdrproc_t) xdr_error, 0, 0 },
+	{ "mnt3_mount",
+		(kxdrproc_t) xdr_encode_dirpath,
+		(kxdrproc_t) xdr_decode_fhstatus3,
+		MAX(MNT_dirpath_sz, MNT_fhstatus_sz) << 2, 0 },
 };
 
 static struct rpc_version	mnt_version1 = {
 	1, 2, mnt_procedures
 };
 
+static struct rpc_version	mnt_version3 = {
+	3, 2, mnt3_procedures
+};
+
 static struct rpc_version *	mnt_version[] = {
 	NULL,
 	&mnt_version1,
+	NULL,
+	&mnt_version3,
 };
 
 static struct rpc_stat		mnt_stats;
Index: oldkernel/linux/fs/nfs/nfs2xdr.c
diff -u linux/fs/nfs/nfs2xdr.c:1.1.1.1 linux/fs/nfs/nfs2xdr.c:1.2
--- linux/fs/nfs/nfs2xdr.c:1.1.1.1	Wed May 31 12:33:48 2000
+++ linux/fs/nfs/nfs2xdr.c	Fri Jul  7 15:36:46 2000
@@ -1,13 +1,15 @@
 /*
- * linux/fs/nfs/xdr.c
+ * linux/fs/nfs/nfs2xdr.c
  *
  * XDR functions to encode/decode NFS RPC arguments and results.
  *
  * Copyright (C) 1992, 1993, 1994  Rick Sladkey
  * Copyright (C) 1996 Olaf Kirch
+ * 04 Aug 1998  Ion Badulescu <ionut@cs.columbia.edu>
+ * 		FIFO's need special handling in NFSv2
  */
 
-#define NFS_NEED_XDR_TYPES
+#define NFS_NEED_NFS2_XDR_TYPES
 
 #include <linux/param.h>
 #include <linux/sched.h>
@@ -20,6 +22,8 @@
 #include <linux/pagemap.h>
 #include <linux/proc_fs.h>
 #include <linux/sunrpc/clnt.h>
+#include <linux/nfs.h>
+#include <linux/nfs2.h>
 #include <linux/nfs_fs.h>
 
 /* Uncomment this to support servers requiring longword lengths */
@@ -28,8 +32,7 @@
 #define NFSDBG_FACILITY		NFSDBG_XDR
 /* #define NFS_PARANOIA 1 */
 
-#define QUADLEN(len)		(((len) + 3) >> 2)
-static int			nfs_stat_to_errno(int stat);
+extern int			nfs_stat_to_errno(int stat);
 
 /* Mapping from NFS error code to "errno" error code. */
 #define errno_NFSERR_IO		EIO
@@ -40,8 +43,8 @@
  */
 #define NFS_fhandle_sz		8
 #define NFS_sattr_sz		8
-#define NFS_filename_sz		1+(NFS_MAXNAMLEN>>2)
-#define NFS_path_sz		1+(NFS_MAXPATHLEN>>2)
+#define NFS_filename_sz		1+(NFS2_MAXNAMLEN>>2)
+#define NFS_path_sz		1+(NFS2_MAXPATHLEN>>2)
 #define NFS_fattr_sz		17
 #define NFS_info_sz		5
 #define NFS_entry_sz		NFS_filename_sz+3
@@ -49,6 +52,7 @@
 #define NFS_enc_void_sz		0
 #define NFS_diropargs_sz	NFS_fhandle_sz+NFS_filename_sz
 #define NFS_sattrargs_sz	NFS_fhandle_sz+NFS_sattr_sz
+#define NFS_readlinkargs_sz	NFS_fhandle_sz
 #define NFS_readargs_sz		NFS_fhandle_sz+3
 #define NFS_writeargs_sz	NFS_fhandle_sz+4
 #define NFS_createargs_sz	NFS_diropargs_sz+NFS_sattr_sz
@@ -60,8 +64,9 @@
 #define NFS_dec_void_sz		0
 #define NFS_attrstat_sz		1+NFS_fattr_sz
 #define NFS_diropres_sz		1+NFS_fhandle_sz+NFS_fattr_sz
-#define NFS_readlinkres_sz	1+NFS_path_sz
+#define NFS_readlinkres_sz	1
 #define NFS_readres_sz		1+NFS_fattr_sz+1
+#define NFS_writeres_sz         NFS_attrstat_sz
 #define NFS_stat_sz		1
 #define NFS_readdirres_sz	1
 #define NFS_statfsres_sz	1+NFS_info_sz
@@ -72,15 +77,19 @@
 static inline u32 *
 xdr_encode_fhandle(u32 *p, struct nfs_fh *fhandle)
 {
-	*((struct nfs_fh *) p) = *fhandle;
-	return p + QUADLEN(sizeof(*fhandle));
+	memcpy(p, fhandle->data, NFS2_FHSIZE);
+	return p + XDR_QUADLEN(NFS2_FHSIZE);
 }
 
 static inline u32 *
 xdr_decode_fhandle(u32 *p, struct nfs_fh *fhandle)
 {
-	*fhandle = *((struct nfs_fh *) p);
-	return p + QUADLEN(sizeof(*fhandle));
+	/* Zero handle first to allow comparisons */
+	memset(fhandle, 0, sizeof(*fhandle));
+	/* NFSv2 handles have a fixed length */
+	fhandle->size = NFS2_FHSIZE;
+	memcpy(fhandle->data, p, NFS2_FHSIZE);
+	return p + XDR_QUADLEN(NFS2_FHSIZE);
 }
 
 static inline u32 *
@@ -91,9 +100,16 @@
 	if (*len > maxlen)
 		return NULL;
 	*string = (char *) p;
-	return p + QUADLEN(*len);
+	return p + XDR_QUADLEN(*len);
 }
 
+static inline u32*
+xdr_decode_time(u32 *p, u64 *timep)
+{
+	*timep = ((u64)ntohl(*p++) << 32) + (u64)ntohl(*p++);
+	return p;
+}
+
 static inline u32 *
 xdr_decode_fattr(u32 *p, struct nfs_fattr *fattr)
 {
@@ -103,33 +119,51 @@
 	fattr->uid = ntohl(*p++);
 	fattr->gid = ntohl(*p++);
 	fattr->size = ntohl(*p++);
-	fattr->blocksize = ntohl(*p++);
+	fattr->du.nfs2.blocksize = ntohl(*p++);
 	fattr->rdev = ntohl(*p++);
-	fattr->blocks = ntohl(*p++);
+	fattr->du.nfs2.blocks = ntohl(*p++);
 	fattr->fsid = ntohl(*p++);
 	fattr->fileid = ntohl(*p++);
-	fattr->atime.seconds = ntohl(*p++);
-	fattr->atime.useconds = ntohl(*p++);
-	fattr->mtime.seconds = ntohl(*p++);
-	fattr->mtime.useconds = ntohl(*p++);
-	fattr->ctime.seconds = ntohl(*p++);
-	fattr->ctime.useconds = ntohl(*p++);
+	p = xdr_decode_time(p, &fattr->atime);
+	p = xdr_decode_time(p, &fattr->mtime);
+	p = xdr_decode_time(p, &fattr->ctime);
+	fattr->valid |= NFS_ATTR_FATTR;
+	if (fattr->type == NFCHR && fattr->rdev == NFS2_FIFO_DEV) {
+		fattr->type = NFFIFO;
+		fattr->mode = (fattr->mode & ~S_IFMT) | S_IFIFO;
+		fattr->rdev = 0;
+	}
 	return p;
 }
 
+#define SATTR(p, attr, flag, field) \
+        *p++ = (attr->ia_valid & flag) ? htonl(attr->field) : ~(u32) 0
 static inline u32 *
-xdr_encode_sattr(u32 *p, struct nfs_sattr *sattr)
+xdr_encode_sattr(u32 *p, struct iattr *attr)
 {
-	*p++ = htonl(sattr->mode);
-	*p++ = htonl(sattr->uid);
-	*p++ = htonl(sattr->gid);
-	*p++ = htonl(sattr->size);
-	*p++ = htonl(sattr->atime.seconds);
-	*p++ = htonl(sattr->atime.useconds);
-	*p++ = htonl(sattr->mtime.seconds);
-	*p++ = htonl(sattr->mtime.useconds);
-	return p;
+	SATTR(p, attr, ATTR_MODE, ia_mode);
+	SATTR(p, attr, ATTR_UID, ia_uid);
+	SATTR(p, attr, ATTR_GID, ia_gid);
+	SATTR(p, attr, ATTR_SIZE, ia_size);
+
+	if (attr->ia_valid & (ATTR_ATIME|ATTR_ATIME_SET)) {
+		*p++ = htonl(attr->ia_atime);
+		*p++ = 0;
+	} else {
+		*p++ = ~(u32) 0;
+		*p++ = ~(u32) 0;
+	}
+
+	if (attr->ia_valid & (ATTR_MTIME|ATTR_MTIME_SET)) {
+		*p++ = htonl(attr->ia_mtime);
+		*p++ = 0;
+	} else {
+		*p++ = ~(u32) 0;	
+		*p++ = ~(u32) 0;
+	}
+  	return p;
 }
+#undef SATTR;
 
 /*
  * NFS encode functions
@@ -176,7 +210,7 @@
 nfs_xdr_diropargs(struct rpc_rqst *req, u32 *p, struct nfs_diropargs *args)
 {
 	p = xdr_encode_fhandle(p, args->fh);
-	p = xdr_encode_string(p, args->name);
+	p = xdr_encode_string(p, args->name, args->len);
 	req->rq_slen = xdr_adjust_iovec(req->rq_svec, p);
 	return 0;
 }
@@ -190,29 +224,34 @@
 nfs_xdr_readargs(struct rpc_rqst *req, u32 *p, struct nfs_readargs *args)
 {
 	struct rpc_auth	*auth = req->rq_task->tk_auth;
-	int		replen, buflen;
+	int		buflen, replen;
+	unsigned int	nr;
 
 	p = xdr_encode_fhandle(p, args->fh);
 	*p++ = htonl(args->offset);
 	*p++ = htonl(args->count);
 	*p++ = htonl(args->count);
 	req->rq_slen = xdr_adjust_iovec(req->rq_svec, p);
+
+	/* Get the number of buffers in the receive iovec */
+        nr = args->nriov;
+
+        if (nr+2 > MAX_IOVEC) {
+                printk(KERN_ERR "NFS: Bad number of iov's in xdr_readargs\n");
+                return -EINVAL;
+        }
 
-#if 1
 	/* set up reply iovec */
 	replen = (RPC_REPHDRSIZE + auth->au_rslack + NFS_readres_sz) << 2;
 	buflen = req->rq_rvec[0].iov_len;
 	req->rq_rvec[0].iov_len  = replen;
-	req->rq_rvec[1].iov_base = args->buffer;
-	req->rq_rvec[1].iov_len  = args->count;
-	req->rq_rvec[2].iov_base = (u8 *) req->rq_rvec[0].iov_base + replen;
-	req->rq_rvec[2].iov_len  = buflen - replen;
+        /* Copy the iovec */
+        memcpy(req->rq_rvec + 1, args->iov, nr * sizeof(struct iovec));
+
+	req->rq_rvec[nr+1].iov_base = (u8 *) req->rq_rvec[0].iov_base + replen;
+	req->rq_rvec[nr+1].iov_len  = buflen - replen;
 	req->rq_rlen = args->count + buflen;
-	req->rq_rnr = 3;
-#else
-	replen = (RPC_REPHDRSIZE + auth->au_rslack + NFS_readres_sz) << 2;
-	req->rq_rvec[0].iov_len  = replen;
-#endif
+	req->rq_rnr += nr+1;
 
 	return 0;
 }
@@ -226,7 +265,6 @@
 	struct iovec *iov = req->rq_rvec;
 	int	status, count, recvd, hdrlen;
 
-	dprintk("RPC:      readres OK status %lx\n", (long)ntohl(*p));
 	if ((status = ntohl(*p++)))
 		return -nfs_stat_to_errno(status);
 	p = xdr_decode_fattr(p, res->fattr);
@@ -234,22 +272,26 @@
 	count = ntohl(*p++);
 	hdrlen = (u8 *) p - (u8 *) iov->iov_base;
 	recvd = req->rq_rlen - hdrlen;
-	if (p != iov[2].iov_base) {
+	if (p != iov[req->rq_rnr-1].iov_base) {
 		/* Unexpected reply header size. Punt.
 		 * XXX: Move iovec contents to align data on page
 		 * boundary and adjust RPC header size guess */
-		printk("NFS: Odd RPC header size in read reply: %d\n", hdrlen);
+		printk(KERN_WARNING "NFS: Odd RPC header size in read reply: %d\n", hdrlen);
 		return -errno_NFSERR_IO;
 	}
 	if (count > recvd) {
-		printk("NFS: server cheating in read reply: "
+		printk(KERN_WARNING "NFS: server cheating in read reply: "
 			"count %d > recvd %d\n", count, recvd);
 		count = recvd;
 	}
 
 	dprintk("RPC:      readres OK count %d\n", count);
-	if (count < res->count)
-		memset((u8 *)(iov[1].iov_base+count), 0, res->count-count);
+	if (count < res->count) {
+		xdr_zero_iovec(iov+1, req->rq_rnr-2, res->count - count);
+		res->count = count;
+		res->eof = 1;  /* Silly NFSv3ism which can't be helped */
+	} else
+		res->eof = 0;
 
 	return count;
 }
@@ -261,6 +303,7 @@
 static int
 nfs_xdr_writeargs(struct rpc_rqst *req, u32 *p, struct nfs_writeargs *args)
 {
+	unsigned int nr;
 	u32 count = args->count;
 
 	p = xdr_encode_fhandle(p, args->fh);
@@ -270,28 +313,35 @@
 	*p++ = htonl(count);
 	req->rq_slen = xdr_adjust_iovec(req->rq_svec, p);
 
-	req->rq_svec[1].iov_base = (void *) args->buffer;
-	req->rq_svec[1].iov_len = count;
-	req->rq_slen += count;
-	req->rq_snr = 2;
+	/* Get the number of buffers in the send iovec */
+	nr = args->nriov;
+
+	if (nr+2 > MAX_IOVEC) {
+                printk(KERN_ERR "NFS: Bad number of iov's in xdr_writeargs "
+                        "(nr %d max %d)\n", nr, MAX_IOVEC);
+                return -EINVAL;
+        }
+
+	/* Copy the iovec */
+        memcpy(req->rq_svec + 1, args->iov, nr * sizeof(struct iovec));
 
 #ifdef NFS_PAD_WRITES
 	/*
 	 * Some old servers require that the message length
 	 * be a multiple of 4, so we pad it here if needed.
 	 */
-	count = ((count + 3) & ~3) - count;
-	if (count) {
-#if 0
-printk("nfs_writeargs: padding write, len=%d, slen=%d, pad=%d\n",
-req->rq_svec[1].iov_len, req->rq_slen, count);
-#endif
-		req->rq_svec[2].iov_base = (void *) "\0\0\0";
-		req->rq_svec[2].iov_len  = count;
-		req->rq_slen += count;
-		req->rq_snr = 3;
+	if (count & 3) {
+		struct iovec	*iov = req->rq_svec + nr + 1;
+		int		pad = 4 - (count & 3);
+
+		iov->iov_base = (void *) "\0\0\0";
+		iov->iov_len  = pad;
+		count += pad;
+		nr++;
 	}
 #endif
+	req->rq_slen += count;
+	req->rq_snr += nr;
 
 	return 0;
 }
@@ -304,7 +354,7 @@
 nfs_xdr_createargs(struct rpc_rqst *req, u32 *p, struct nfs_createargs *args)
 {
 	p = xdr_encode_fhandle(p, args->fh);
-	p = xdr_encode_string(p, args->name);
+	p = xdr_encode_string(p, args->name, args->len);
 	p = xdr_encode_sattr(p, args->sattr);
 	req->rq_slen = xdr_adjust_iovec(req->rq_svec, p);
 	return 0;
@@ -317,9 +367,9 @@
 nfs_xdr_renameargs(struct rpc_rqst *req, u32 *p, struct nfs_renameargs *args)
 {
 	p = xdr_encode_fhandle(p, args->fromfh);
-	p = xdr_encode_string(p, args->fromname);
+	p = xdr_encode_string(p, args->fromname, args->fromlen);
 	p = xdr_encode_fhandle(p, args->tofh);
-	p = xdr_encode_string(p, args->toname);
+	p = xdr_encode_string(p, args->toname, args->tolen);
 	req->rq_slen = xdr_adjust_iovec(req->rq_svec, p);
 	return 0;
 }
@@ -332,7 +382,7 @@
 {
 	p = xdr_encode_fhandle(p, args->fromfh);
 	p = xdr_encode_fhandle(p, args->tofh);
-	p = xdr_encode_string(p, args->toname);
+	p = xdr_encode_string(p, args->toname, args->tolen);
 	req->rq_slen = xdr_adjust_iovec(req->rq_svec, p);
 	return 0;
 }
@@ -344,8 +394,8 @@
 nfs_xdr_symlinkargs(struct rpc_rqst *req, u32 *p, struct nfs_symlinkargs *args)
 {
 	p = xdr_encode_fhandle(p, args->fromfh);
-	p = xdr_encode_string(p, args->fromname);
-	p = xdr_encode_string(p, args->topath);
+	p = xdr_encode_string(p, args->fromname, args->fromlen);
+	p = xdr_encode_string(p, args->topath, args->tolen);
 	p = xdr_encode_sattr(p, args->sattr);
 	req->rq_slen = xdr_adjust_iovec(req->rq_svec, p);
 	return 0;
@@ -360,7 +410,7 @@
 	struct rpc_task	*task = req->rq_task;
 	struct rpc_auth	*auth = task->tk_auth;
 	u32		bufsiz = args->bufsiz;
-	int		replen;
+	int		buflen, replen;
 
 	/*
 	 * Some servers (e.g. HP OS 9.5) seem to expect the buffer size
@@ -376,51 +426,37 @@
 
 	/* set up reply iovec */
 	replen = (RPC_REPHDRSIZE + auth->au_rslack + NFS_readdirres_sz) << 2;
-	/*
-	dprintk("RPC: readdirargs: slack is 4 * (%d + %d + %d) = %d\n",
-		RPC_REPHDRSIZE, auth->au_rslack, NFS_readdirres_sz, replen);
-	 */
+	buflen = req->rq_rvec[0].iov_len;
 	req->rq_rvec[0].iov_len  = replen;
 	req->rq_rvec[1].iov_base = args->buffer;
 	req->rq_rvec[1].iov_len  = args->bufsiz;
-	req->rq_rlen = replen + args->bufsiz;
-	req->rq_rnr = 2;
-
-	/*
-	dprintk("RPC:      readdirargs set up reply vec:\n");
-	dprintk("          rvec[0] = %p/%d\n",
-			req->rq_rvec[0].iov_base,
-			req->rq_rvec[0].iov_len);
-	dprintk("          rvec[1] = %p/%d\n",
-			req->rq_rvec[1].iov_base,
-			req->rq_rvec[1].iov_len);
-	 */
+	req->rq_rvec[2].iov_base = (u8 *) req->rq_rvec[0].iov_base + replen;
+	req->rq_rvec[2].iov_len  = buflen - replen;
+	req->rq_rlen = buflen + args->bufsiz;
+	req->rq_rnr += 2;
 
 	return 0;
 }
 
 /*
- * Decode the result of a readdir call. We decode the result in place
- * to avoid a malloc of NFS_MAXNAMLEN+1 for each file name.
- * After decoding, the layout in memory looks like this:
- *	entry1 entry2 ... entryN <space> stringN ... string2 string1
- * Each entry consists of three __u32 values, the same space as NFS uses.
- * Note that the strings are not null-terminated so that the entire number
- * of entries returned by the server should fit into the buffer.
+ * Decode the result of a readdir call.
+ * We're not really decoding anymore, we just leave the buffer untouched
+ * and only check that it is syntactically correct.
+ * The real decoding happens in nfs_decode_entry below, called directly
+ * from nfs_readdir for each entry.
  */
 static int
 nfs_xdr_readdirres(struct rpc_rqst *req, u32 *p, struct nfs_readdirres *res)
 {
 	struct iovec		*iov = req->rq_rvec;
 	int			 status, nr;
-	char			*string, *start;
-	u32			*end, *entry, len, fileid, cookie;
+	u32			*end, *entry, len;
 
 	if ((status = ntohl(*p++)))
 		return -nfs_stat_to_errno(status);
 	if ((void *) p != ((u8 *) iov->iov_base+iov->iov_len)) {
 		/* Unexpected reply header size. Punt. */
-		printk("NFS: Odd RPC header size in readdirres reply\n");
+		printk(KERN_WARNING "NFS: Odd RPC header size in readdirres reply\n");
 		return -errno_NFSERR_IO;
 	}
 
@@ -429,66 +465,59 @@
 	end = (u32 *) ((u8 *) p + iov[1].iov_len);
 
 	/* Get start and end of dirent buffer */
-	entry  = (u32 *) res->buffer;
-	start  = (char *) res->buffer;
-	string = (char *) res->buffer + res->bufsiz;
-	for (nr = 0; *p++; nr++) {
-		fileid = ntohl(*p++);
+	if (res->buffer != p) {
+		printk(KERN_ERR "NFS: Bad result buffer in readdir\n");
+		return -errno_NFSERR_IO;
+	}
 
+	for (nr = 0; *p++; nr++) {
+		entry = p - 1;
+		p++; /* fileid */
 		len = ntohl(*p++);
-		/*
-		 * Check whether the server has exceeded our reply buffer,
-		 * and set a flag to convert the size to longwords.
-		 */
-		if ((p + QUADLEN(len) + 3) > end) {
-			struct rpc_clnt *clnt = req->rq_task->tk_client;
-			printk(KERN_WARNING
-				"NFS: server %s, readdir reply truncated\n",
-				clnt->cl_server);
-			printk(KERN_WARNING "NFS: nr=%d, slots=%d, len=%d\n",
-				nr, (end - p), len);
-			clnt->cl_flags |= NFS_CLNTF_BUFSIZE;
-			break;
-		}
-		if (len > NFS_MAXNAMLEN) {
-			printk("NFS: giant filename in readdir (len %x)!\n",
+		p += XDR_QUADLEN(len) + 1;	/* name plus cookie */
+		if (len > NFS2_MAXNAMLEN) {
+			printk(KERN_WARNING "NFS: giant filename in readdir (len 0x%x)!\n",
 						len);
 			return -errno_NFSERR_IO;
 		}
-		string -= len;
-		if ((void *) (entry+3) > (void *) string) {
-			/* 
-			 * This error is impossible as long as the temp
-			 * buffer is no larger than the user buffer. The 
-			 * current packing algorithm uses the same amount
-			 * of space in the user buffer as in the XDR data,
-			 * so it's guaranteed to fit.
-			 */
-			printk("NFS: incorrect buffer size in %s!\n",
-				__FUNCTION__);
+		if (p + 2 > end) {
+			printk(KERN_NOTICE
+				"NFS: short packet in readdir reply!\n");
+			entry[0] = entry[1] = 0;
 			break;
 		}
+	}
+	p++; /* EOF flag */
 
-		memmove(string, p, len);
-		p += QUADLEN(len);
-		cookie = ntohl(*p++);
-		/*
-		 * To make everything fit, we encode the length, offset,
-		 * and eof flag into 32 bits. This works for filenames
-		 * up to 32K and PAGE_SIZE up to 64K.
-		 */
-		status = !p[0] && p[1] ? (1 << 15) : 0; /* eof flag */
-		*entry++ = fileid;
-		*entry++ = cookie;
-		*entry++ = ((string - start) << 16) | status | (len & 0x7FFF);
-	}
-#ifdef NFS_PARANOIA
-printk("nfs_xdr_readdirres: %d entries, ent sp=%d, str sp=%d\n",
-nr, ((char *) entry - start), (start + res->bufsiz - string));
-#endif
+	if (p > end) {
+		printk(KERN_NOTICE
+			"NFS: short packet in readdir reply!\n");
+		return -errno_NFSERR_IO;
+	}
 	return nr;
 }
 
+u32 *
+nfs_decode_dirent(u32 *p, struct nfs_entry *entry, int plus)
+{
+	if (!*p++) {
+		if (!*p)
+			return ERR_PTR(-EAGAIN);
+		entry->eof = 1;
+		return ERR_PTR(-EBADCOOKIE);
+	}
+
+	entry->ino	  = ntohl(*p++);
+	entry->len	  = ntohl(*p++);
+	entry->name	  = (const char *) p;
+	p		 += XDR_QUADLEN(entry->len);
+	entry->prev_cookie	  = entry->cookie;
+	entry->cookie	  = ntohl(*p++);
+	entry->eof	  = !p[0] && p[1];
+
+	return p;
+}
+
 /*
  * NFS XDR decode functions
  */
@@ -523,12 +552,9 @@
 {
 	int	status;
 
-	dprintk("RPC:      attrstat status %lx\n", (long)ntohl(*p));
 	if ((status = ntohl(*p++)))
 		return -nfs_stat_to_errno(status);
 	xdr_decode_fattr(p, fattr);
-	dprintk("RPC:      attrstat OK type %d mode %o dev %x ino %x\n",
-		fattr->type, fattr->mode, fattr->fsid, fattr->fileid);
 	return 0;
 }
 
@@ -541,14 +567,34 @@
 {
 	int	status;
 
-	dprintk("RPC:      diropres status %lx\n", (long)ntohl(*p));
 	if ((status = ntohl(*p++)))
 		return -nfs_stat_to_errno(status);
 	p = xdr_decode_fhandle(p, res->fh);
 	xdr_decode_fattr(p, res->fattr);
-	dprintk("RPC:      diropres OK type %x mode %o dev %x ino %x\n",
-		res->fattr->type, res->fattr->mode,
-		res->fattr->fsid, res->fattr->fileid);
+	return 0;
+}
+
+/*
+ * Encode READLINK args
+ */
+static int
+nfs_xdr_readlinkargs(struct rpc_rqst *req, u32 *p, struct nfs_readlinkargs *args)
+{
+	struct rpc_task *task = req->rq_task;
+	struct rpc_auth *auth = task->tk_auth;
+	int		buflen, replen;
+
+	p = xdr_encode_fhandle(p, args->fh);
+	req->rq_slen = xdr_adjust_iovec(req->rq_svec, p);
+	replen = (RPC_REPHDRSIZE + auth->au_rslack + NFS_readlinkres_sz) << 2;
+	buflen = req->rq_rvec[0].iov_len;
+	req->rq_rvec[0].iov_len  = replen;
+	req->rq_rvec[1].iov_base = args->buffer;
+	req->rq_rvec[1].iov_len  = args->bufsiz;
+	req->rq_rvec[2].iov_base = (u8 *) req->rq_rvec[0].iov_base + replen;
+	req->rq_rvec[2].iov_len  = buflen - replen;
+	req->rq_rlen = buflen + args->bufsiz;
+	req->rq_rnr += 2;
 	return 0;
 }
 
@@ -558,33 +604,70 @@
 static int
 nfs_xdr_readlinkres(struct rpc_rqst *req, u32 *p, struct nfs_readlinkres *res)
 {
+	u32	*strlen;
+	char	*string;
 	int	status;
+	unsigned int len;
 
 	if ((status = ntohl(*p++)))
 		return -nfs_stat_to_errno(status);
-	xdr_decode_string2(p, res->string, res->lenp, res->maxlen);
-
-	/* Caller takes over the buffer here to avoid extra copy */
-	res->buffer = req->rq_task->tk_buffer;
-	req->rq_task->tk_buffer = NULL;
+	strlen = (u32*)res->buffer;
+	/* Convert length of symlink */
+	len = ntohl(*strlen);
+	if (len > res->bufsiz - 5)
+		len = res->bufsiz - 5;
+	*strlen = len;
+	/* NULL terminate the string we got */
+	string = (char *)(strlen + 1);
+	string[len] = 0;
 	return 0;
 }
 
 /*
+ * Decode WRITE reply
+ */
+static int
+nfs_xdr_writeres(struct rpc_rqst *req, u32 *p, struct nfs_writeres *res)
+{
+	res->verf->committed = NFS_FILE_SYNC;
+	return nfs_xdr_attrstat(req, p, res->fattr);
+}
+
+/*
  * Decode STATFS reply
  */
 static int
 nfs_xdr_statfsres(struct rpc_rqst *req, u32 *p, struct nfs_fsinfo *res)
 {
 	int	status;
+	u32	xfer_size;
 
 	if ((status = ntohl(*p++)))
 		return -nfs_stat_to_errno(status);
-	res->tsize = ntohl(*p++);
-	res->bsize = ntohl(*p++);
-	res->blocks = ntohl(*p++);
-	res->bfree = ntohl(*p++);
-	res->bavail = ntohl(*p++);
+
+	/* For NFSv2, we more or less have to guess the preferred
+	 * read/write/readdir sizes from the single 'transfer size'
+	 * value.
+	 */
+	xfer_size = ntohl(*p++);	/* tsize */
+	res->rtmax  = 8 * 1024;
+	res->rtpref = xfer_size;
+	res->rtmult = xfer_size;
+	res->wtmax  = 8 * 1024;
+	res->wtpref = xfer_size;
+	res->wtmult = xfer_size;
+	res->dtpref = PAGE_CACHE_SIZE;
+	res->maxfilesize = 0x7FFFFFFF;	/* just a guess */
+	res->bsize  = ntohl(*p++);
+
+	res->tbytes = ntohl(*p++) * res->bsize;
+	res->fbytes = ntohl(*p++) * res->bsize;
+	res->abytes = ntohl(*p++) * res->bsize;
+	res->tfiles = 0;
+	res->ffiles = 0;
+	res->afiles = 0;
+	res->namelen = 0;
+
 	return 0;
 }
 
@@ -601,7 +684,7 @@
 	{ NFSERR_NOENT,		ENOENT		},
 	{ NFSERR_IO,		errno_NFSERR_IO	},
 	{ NFSERR_NXIO,		ENXIO		},
-	{ NFSERR_EAGAIN,	EAGAIN		},
+/*	{ NFSERR_EAGAIN,	EAGAIN		}, */
 	{ NFSERR_ACCES,		EACCES		},
 	{ NFSERR_EXIST,		EEXIST		},
 	{ NFSERR_XDEV,		EXDEV		},
@@ -612,18 +695,31 @@
 	{ NFSERR_FBIG,		EFBIG		},
 	{ NFSERR_NOSPC,		ENOSPC		},
 	{ NFSERR_ROFS,		EROFS		},
-	{ NFSERR_OPNOTSUPP,	EOPNOTSUPP	},
+	{ NFSERR_MLINK,		EMLINK		},
 	{ NFSERR_NAMETOOLONG,	ENAMETOOLONG	},
 	{ NFSERR_NOTEMPTY,	ENOTEMPTY	},
 	{ NFSERR_DQUOT,		EDQUOT		},
 	{ NFSERR_STALE,		ESTALE		},
+	{ NFSERR_REMOTE,	EREMOTE		},
 #ifdef EWFLUSH
 	{ NFSERR_WFLUSH,	EWFLUSH		},
 #endif
+	{ NFSERR_BADHANDLE,	EBADHANDLE	},
+	{ NFSERR_NOT_SYNC,	ENOTSYNC	},
+	{ NFSERR_BAD_COOKIE,	EBADCOOKIE	},
+	{ NFSERR_NOTSUPP,	ENOTSUPP	},
+	{ NFSERR_TOOSMALL,	ETOOSMALL	},
+	{ NFSERR_SERVERFAULT,	ESERVERFAULT	},
+	{ NFSERR_BADTYPE,	EBADTYPE	},
+	{ NFSERR_JUKEBOX,	EJUKEBOX	},
 	{ -1,			EIO		}
 };
 
-static int
+/*
+ * Convert an NFS error code to a local one.
+ * This one is used jointly by NFSv2 and NFSv3.
+ */
+int
 nfs_stat_to_errno(int stat)
 {
 	int i;
@@ -632,7 +728,7 @@
 		if (nfs_errtbl[i].stat == stat)
 			return nfs_errtbl[i].errno;
 	}
-	printk("nfs_stat_to_errno: bad nfs status return value: %d\n", stat);
+	printk(KERN_ERR "nfs_stat_to_errno: bad nfs status return value: %d\n", stat);
 	return nfs_errtbl[i].errno;
 }
 
@@ -644,7 +740,8 @@
     { "nfs_" #proc,					\
       (kxdrproc_t) nfs_xdr_##argtype,			\
       (kxdrproc_t) nfs_xdr_##restype,			\
-      MAX(NFS_##argtype##_sz,NFS_##restype##_sz) << 2	\
+      MAX(NFS_##argtype##_sz,NFS_##restype##_sz) << 2,	\
+      0							\
     }
 
 static struct rpc_procinfo	nfs_procedures[18] = {
@@ -653,10 +750,10 @@
     PROC(setattr,	sattrargs,	attrstat),
     PROC(root,		enc_void,	dec_void),
     PROC(lookup,	diropargs,	diropres),
-    PROC(readlink,	fhandle,	readlinkres),
+    PROC(readlink,	readlinkargs,	readlinkres),
     PROC(read,		readargs,	readres),
     PROC(writecache,	enc_void,	dec_void),
-    PROC(write,		writeargs,	attrstat),
+    PROC(write,		writeargs,	writeres),
     PROC(create,	createargs,	diropres),
     PROC(remove,	diropargs,	stat),
     PROC(rename,	renameargs,	stat),
@@ -668,22 +765,8 @@
     PROC(statfs,	fhandle,	statfsres),
 };
 
-static struct rpc_version	nfs_version2 = {
+struct rpc_version		nfs_version2 = {
 	2,
 	sizeof(nfs_procedures)/sizeof(nfs_procedures[0]),
 	nfs_procedures
-};
-
-static struct rpc_version *	nfs_version[] = {
-	NULL,
-	NULL,
-	&nfs_version2
-};
-
-struct rpc_program	nfs_program = {
-	"nfs",
-	NFS_PROGRAM,
-	sizeof(nfs_version) / sizeof(nfs_version[0]),
-	nfs_version,
-	&nfs_rpcstat,
 };
Index: oldkernel/linux/fs/nfs/nfs3proc.c
diff -u /dev/null linux/fs/nfs/nfs3proc.c:1.1
--- /dev/null	Mon Jul 31 21:15:08 2000
+++ linux/fs/nfs/nfs3proc.c	Fri Jul  7 16:18:17 2000
@@ -0,0 +1,474 @@
+/*
+ *  linux/fs/nfs/nfs3proc.c
+ *
+ *  Client-side NFSv3 procedures stubs.
+ *
+ *  Copyright (C) 1997, Olaf Kirch
+ */
+
+#define NFS_NEED_NFS3_XDR_TYPES
+
+#include <linux/param.h>
+#include <linux/sched.h>
+#include <linux/mm.h>
+#include <linux/malloc.h>
+#include <linux/utsname.h>
+#include <linux/errno.h>
+#include <linux/string.h>
+#include <linux/in.h>
+#include <linux/pagemap.h>
+#include <linux/sunrpc/clnt.h>
+#include <linux/nfs.h>
+#include <linux/nfs3.h>
+#include <linux/nfs_fs.h>
+
+#include <asm/segment.h>
+
+#define NFSDBG_FACILITY		NFSDBG_PROC
+
+/*
+ * Bare-bones access to getattr: this is for nfs_read_super.
+ */
+static int
+nfs3_proc_get_root(struct nfs_server *server, struct nfs_fh *fhandle,
+				struct nfs_fattr *fattr)
+{
+	int	status;
+
+	dprintk("NFS call  getroot\n");
+	fattr->valid = 0;
+	status = rpc_call(server->client, NFS3PROC_GETATTR, fhandle, fattr, 0);
+	dprintk("NFS reply getroot\n");
+	return status;
+}
+
+/*
+ * One function for each procedure in the NFS protocol.
+ */
+static int
+nfs3_proc_getattr(struct dentry *dentry, struct nfs_fattr *fattr)
+{
+	int	status;
+
+	dprintk("NFS call  getattr\n");
+	fattr->valid = 0;
+	status = rpc_call(NFS_CLIENT(dentry->d_inode), NFS3PROC_GETATTR,
+			  NFS_FH(dentry), fattr, 0);
+	dprintk("NFS reply getattr\n");
+	return status;
+}
+
+static int
+nfs3_proc_setattr(struct dentry *dentry, struct nfs_fattr *fattr,
+			struct iattr *sattr)
+{
+	struct nfs3_sattrargs	arg = { NFS_FH(dentry), sattr, 0, 0 };
+	int	status;
+
+	dprintk("NFS call  setattr\n");
+	fattr->valid = 0;
+	status = rpc_call(NFS_CLIENT(dentry->d_inode), NFS3PROC_SETATTR, &arg, fattr, 0);
+	dprintk("NFS reply setattr\n");
+	return status;
+}
+
+static int
+nfs3_proc_lookup(struct dentry *dir, struct nfs_fattr *dir_attr,
+			struct qstr *name,
+			struct nfs_fh *fhandle, struct nfs_fattr *fattr)
+{
+	struct nfs3_diropargs	arg = { NFS_FH(dir), name->name, name->len };
+	struct nfs3_diropres	res = { dir_attr, fhandle, fattr };
+	int			status;
+
+	dprintk("NFS call  lookup %s\n", name->name);
+	dir_attr->valid = 0;
+	fattr->valid = 0;
+	status = rpc_call(NFS_CLIENT(dir->d_inode), NFS3PROC_LOOKUP, &arg, &res, 0);
+	if (status >= 0 && !(fattr->valid & NFS_ATTR_FATTR))
+		status = rpc_call(NFS_CLIENT(dir->d_inode), NFS3PROC_GETATTR,
+			 fhandle, fattr, 0);
+	dprintk("NFS reply lookup: %d\n", status);
+	return status;
+}
+
+static int
+nfs3_proc_access(struct dentry *dentry, int mode, struct nfs_fattr *fattr, int ruid)
+{
+	struct nfs3_accessargs	arg = { NFS_FH(dentry), 0 };
+	struct nfs3_accessres	res = { fattr, 0 };
+	int	status, flags;
+
+	dprintk("NFS call  access\n");
+	fattr->valid = 0;
+
+	if (mode & MAY_READ)
+		arg.access |= NFS3_ACCESS_READ;
+	if (S_ISDIR(dentry->d_inode->i_mode)) {
+		if (mode & MAY_WRITE)
+			arg.access |= NFS3_ACCESS_MODIFY | NFS3_ACCESS_EXTEND | NFS3_ACCESS_DELETE;
+		if (mode & MAY_EXEC)
+			arg.access |= NFS3_ACCESS_LOOKUP;
+	} else {
+		if (mode & MAY_WRITE)
+			arg.access |= NFS3_ACCESS_MODIFY | NFS3_ACCESS_EXTEND;
+		if (mode & MAY_EXEC)
+			arg.access |= NFS3_ACCESS_EXECUTE;
+	}
+	flags = (ruid) ? RPC_CALL_REALUID : 0;
+	status = rpc_call(NFS_CLIENT(dentry->d_inode), NFS3PROC_ACCESS, &arg, &res, flags);
+	dprintk("NFS reply access\n");
+
+	if (status == 0 && (arg.access & res.access) != arg.access)
+		status = -EACCES;
+	return status;
+}
+
+static int
+nfs3_proc_readlink(struct dentry *dentry, struct nfs_fattr *fattr,
+			void *buffer, unsigned int buflen)
+{
+	struct nfs3_readlinkargs args = { NFS_FH(dentry), buffer, buflen };
+	struct nfs3_readlinkres	res = { fattr, buffer, buflen };
+	int			status;
+
+	dprintk("NFS call  readlink\n");
+	fattr->valid = 0;
+	status = rpc_call(NFS_CLIENT(dentry->d_inode), NFS3PROC_READLINK,
+					&args, &res, 0);
+	dprintk("NFS reply readlink: %d\n", status);
+	return status;
+}
+
+static int
+nfs3_proc_read(struct dentry *dentry, struct nfs_fattr *fattr,
+	       struct rpc_cred *cred, int flags,
+	       unsigned long offset, unsigned int count,
+	       void *buffer, int *eofp)
+{
+	struct nfs_readargs	arg = { NFS_FH(dentry), offset, count, 1,
+					{{buffer, count}, {0,0}, {0,0}, {0,0},
+					 {0,0}, {0,0}, {0,0}, {0,0}} };
+	struct nfs_readres	res = { fattr, count, 0 };
+	struct rpc_message	msg = { NFS3PROC_READ, &arg, &res, cred };
+	int			status;
+
+	dprintk("NFS call  read %d @ %ld\n", count, offset);
+	fattr->valid = 0;
+	status = rpc_call_sync(NFS_CLIENT(dentry->d_inode), &msg, flags);
+	dprintk("NFS reply read: %d\n", status);
+	*eofp = res.eof;
+	return status;
+}
+
+static int
+nfs3_proc_write(struct dentry *dentry, struct nfs_fattr *fattr,
+		struct rpc_cred *cred, int flags,
+		unsigned long offset, unsigned int count,
+		void *buffer, struct nfs_writeverf *verf)
+{
+	struct nfs_writeargs	arg = { NFS_FH(dentry), offset, count,
+					NFS_FILE_SYNC, 1,
+					{{buffer, count}, {0,0}, {0,0}, {0,0},
+					 {0,0}, {0,0}, {0,0}, {0,0}} };
+	struct nfs_writeres	res = { fattr, verf, 0 };
+	struct rpc_message	msg = { NFS3PROC_WRITE, &arg, &res, cred };
+	int			status, rpcflags = 0;
+
+	dprintk("NFS call  write %d @ %ld\n", count, offset);
+	fattr->valid = 0;
+	if (flags & NFS_RW_SWAP)
+		rpcflags |= NFS_RPC_SWAPFLAGS;
+	arg.stable = (flags & NFS_RW_SYNC) ? NFS_FILE_SYNC : NFS_UNSTABLE;
+
+	status = rpc_call_sync(NFS_CLIENT(dentry->d_inode), &msg, rpcflags);
+
+	dprintk("NFS reply read: %d\n", status);
+	return status < 0? status : res.count;
+}
+
+/*
+ * Create a regular file.
+ * For now, we don't implement O_EXCL.
+ */
+static int
+nfs3_proc_create(struct dentry *dir, struct nfs_fattr *dir_attr,
+			struct qstr *name, struct iattr *sattr, int flags,
+			struct nfs_fh *fhandle, struct nfs_fattr *fattr)
+{
+	struct nfs3_createargs	arg = { NFS_FH(dir), name->name, name->len,
+					sattr, 0, { 0, 0 } };
+	struct nfs3_diropres	res = { dir_attr, fhandle, fattr };
+	int			status;
+
+	dprintk("NFS call  create %s\n", name->name);
+	dir_attr->valid = 0;
+	fattr->valid = 0;
+
+	arg.createmode = NFS3_CREATE_UNCHECKED;
+	if (flags & O_EXCL) {
+		arg.createmode  = NFS3_CREATE_EXCLUSIVE;
+		arg.verifier[0] = jiffies;
+		arg.verifier[1] = current->pid;
+	}
+
+again:
+	status = rpc_call(NFS_CLIENT(dir->d_inode), NFS3PROC_CREATE, &arg, &res, 0);
+
+	/* If the server doesn't support the exclusive creation semantics,
+	 * try again with simple 'guarded' mode. */
+	if (status == NFSERR_NOTSUPP) {
+		switch (arg.createmode) {
+			case NFS3_CREATE_EXCLUSIVE:
+				arg.createmode = NFS3_CREATE_GUARDED;
+				break;
+
+			case NFS3_CREATE_GUARDED:
+				arg.createmode = NFS3_CREATE_UNCHECKED;
+				break;
+
+			case NFS3_CREATE_UNCHECKED:
+				goto exit;
+		}
+		goto again;
+	}
+
+exit:
+	dprintk("NFS reply create: %d\n", status);
+
+	/* When we created the file with exclusive semantics, make
+	 * sure we set the attributes afterwards. */
+	if (status == 0 && arg.createmode == NFS3_CREATE_EXCLUSIVE) {
+		struct nfs3_sattrargs	arg = { fhandle, sattr, 0, 0 };
+		dprintk("NFS call  setattr (post-create)\n");
+
+		/* Note: we could use a guarded setattr here, but I'm
+		 * not sure this buys us anything (and I'd have
+		 * to revamp the NFSv3 XDR code) */
+		fattr->valid = 0;
+		status = rpc_call(NFS_CLIENT(dir->d_inode), NFS3PROC_SETATTR,
+						&arg, fattr, 0);
+		dprintk("NFS reply setattr (post-create): %d\n", status);
+	}
+
+	return status;
+}
+
+static int
+nfs3_proc_remove(struct dentry *dir, struct nfs_fattr *dir_attr,
+				struct qstr *name, struct rpc_cred *cred)
+{
+	struct nfs3_diropargs	arg = { NFS_FH(dir), name->name, name->len };
+	struct rpc_message	msg = {NFS3PROC_REMOVE, &arg, dir_attr, cred };
+	int			status;
+
+	dprintk("NFS call  remove %s\n", name->name);
+	dir_attr->valid = 0;
+	status = rpc_call_sync(NFS_CLIENT(dir->d_inode), &msg, 0);
+	dprintk("NFS reply remove: %d\n", status);
+	return status;
+}
+
+static int
+nfs3_proc_rename(struct dentry *old_dir, struct nfs_fattr *old_attr,
+			struct qstr *old_name,
+			struct dentry *new_dir, struct nfs_fattr *new_attr,
+			struct qstr *new_name)
+{
+	struct nfs3_renameargs	arg = { NFS_FH(old_dir),
+					old_name->name, old_name->len,
+					NFS_FH(new_dir),
+					new_name->name, new_name->len };
+	struct nfs3_renameres	res = { old_attr, new_attr };
+	int			status;
+
+	dprintk("NFS call  rename %s -> %s\n", old_name->name, new_name->name);
+	old_attr->valid = 0;
+	new_attr->valid = 0;
+	status = rpc_call(NFS_CLIENT(old_dir->d_inode), NFS3PROC_RENAME, &arg, &res, 0);
+	dprintk("NFS reply rename: %d\n", status);
+	return status;
+}
+
+static int
+nfs3_proc_link(struct dentry *dentry, struct nfs_fattr *fattr,
+			struct dentry *dir, struct nfs_fattr *dir_attr,
+			struct qstr *name)
+{
+	struct nfs3_linkargs	arg = { NFS_FH(dentry), NFS_FH(dir),
+					name->name, name->len };
+	struct nfs3_linkres	res = { dir_attr, fattr };
+	int			status;
+
+	dprintk("NFS call  link %s\n", name->name);
+	dir_attr->valid = 0;
+	fattr->valid = 0;
+	status = rpc_call(NFS_CLIENT(dentry->d_inode), NFS3PROC_LINK, &arg, &res, 0);
+	dprintk("NFS reply link: %d\n", status);
+	return status;
+}
+
+static int
+nfs3_proc_symlink(struct dentry *dir, struct nfs_fattr *dir_attr,
+			struct qstr *name, struct qstr *path,
+			struct iattr *sattr,
+			struct nfs_fh *fhandle, struct nfs_fattr *fattr)
+{
+	struct nfs3_symlinkargs	arg = { NFS_FH(dir), name->name, name->len,
+					path->name, path->len, sattr };
+	struct nfs3_diropres	res = { dir_attr, fhandle, fattr };
+	int			status;
+
+	dprintk("NFS call  symlink %s -> %s\n", name->name, path->name);
+	dir_attr->valid = 0;
+	fattr->valid = 0;
+	status = rpc_call(NFS_CLIENT(dir->d_inode), NFS3PROC_SYMLINK, &arg, &res, 0);
+	dprintk("NFS reply symlink: %d\n", status);
+	return status;
+}
+
+static int
+nfs3_proc_mkdir(struct dentry *dir, struct nfs_fattr *dir_attr,
+			struct qstr *name, struct iattr *sattr,
+			struct nfs_fh *fhandle, struct nfs_fattr *fattr)
+{
+	struct nfs3_createargs	arg = { NFS_FH(dir), name->name, name->len,
+					sattr, 0, { 0, 0 } };
+	struct nfs3_diropres	res = { dir_attr, fhandle, fattr };
+	int			status;
+
+	dprintk("NFS call  mkdir %s\n", name->name);
+	dir_attr->valid = 0;
+	fattr->valid = 0;
+	status = rpc_call(NFS_CLIENT(dir->d_inode), NFS3PROC_MKDIR, &arg, &res, 0);
+	dprintk("NFS reply mkdir: %d\n", status);
+	return status;
+}
+
+static int
+nfs3_proc_rmdir(struct dentry *dir, struct nfs_fattr *dir_attr,
+				struct qstr *name)
+{
+	struct nfs3_diropargs	arg = { NFS_FH(dir), name->name, name->len };
+	int			status;
+
+	dprintk("NFS call  rmdir %s\n", name->name);
+	dir_attr->valid = 0;
+	status = rpc_call(NFS_CLIENT(dir->d_inode), NFS3PROC_RMDIR, &arg, dir_attr, 0);
+	dprintk("NFS reply rmdir: %d\n", status);
+	return status;
+}
+
+/*
+ * The READDIR implementation is somewhat hackish - we pass the user buffer
+ * to the encode function, which installs it in the receive iovec.
+ * The decode function itself doesn't perform any decoding, it just makes
+ * sure the reply is syntactically correct.
+ *
+ * Also note that this implementation handles both plain readdir and
+ * readdirplus.
+ */
+static int
+nfs3_proc_readdir(struct dentry *dir, struct nfs_fattr *dir_attr,
+		  struct rpc_cred *cred,
+		  u64 cookie, void *entry, unsigned int size, int plus)
+{
+	struct nfs3_readdirargs	arg = { NFS_FH(dir), cookie, {0, 0}, 0, 0, 0 };
+	struct nfs3_readdirres	res = { dir_attr, 0, 0, 0, 0 };
+	struct rpc_message	msg = { NFS3PROC_READDIR, &arg, &res, cred };
+	u32			*verf = NFS_COOKIEVERF(dir->d_inode);
+	int			status;
+
+	arg.buffer  = entry;
+	arg.bufsiz  = size;
+	arg.verf[0] = verf[0];
+	arg.verf[1] = verf[1];
+	arg.plus    = plus;
+	res.buffer  = entry;
+	res.bufsiz  = size;
+	res.verf    = verf;
+	res.plus    = plus;
+
+	if (plus)
+		msg.rpc_proc = NFS3PROC_READDIRPLUS;
+
+	dprintk("NFS call  readdir%s %d\n",
+			plus? "plus" : "", (unsigned int) cookie);
+
+	dir_attr->valid = 0;
+	status = rpc_call_sync(NFS_CLIENT(dir->d_inode), &msg, 0);
+	dprintk("NFS reply readdir: %d\n", status);
+	return status;
+}
+
+static int
+nfs3_proc_mknod(struct dentry *dir, struct nfs_fattr *dir_attr,
+			struct qstr *name, struct iattr *sattr,
+			dev_t rdev, struct nfs_fh *fh, struct nfs_fattr *fattr)
+{
+	struct nfs3_mknodargs	arg = { NFS_FH(dir), name->name, name->len, 0,
+					sattr, rdev };
+	struct nfs3_diropres	res = { dir_attr, fh, fattr };
+	int			status;
+
+	switch (sattr->ia_mode & S_IFMT) {
+	case S_IFBLK:	arg.type = NF3BLK;  break;
+	case S_IFCHR:	arg.type = NF3CHR;  break;
+	case S_IFIFO:	arg.type = NF3FIFO; break;
+	case S_IFSOCK:	arg.type = NF3SOCK; break;
+	default:	return -EINVAL;
+	}
+
+	dprintk("NFS call  mknod %s %x\n", name->name, rdev);
+	dir_attr->valid = 0;
+	fattr->valid = 0;
+	status = rpc_call(NFS_CLIENT(dir->d_inode), NFS3PROC_MKNOD, &arg, &res, 0);
+	dprintk("NFS reply mknod: %d\n", status);
+	return status;
+}
+
+/*
+ * This is a combo call of fsstat and fsinfo
+ */
+static int
+nfs3_proc_statfs(struct nfs_server *server, struct nfs_fh *fhandle,
+			struct nfs_fsinfo *info)
+{
+	int	status;
+
+	dprintk("NFS call  fsstat\n");
+	memset((char *)info, 0, sizeof(*info));
+	status = rpc_call(server->client, NFS3PROC_FSSTAT, fhandle, info, 0);
+	if (status < 0)
+		goto error;
+	status = rpc_call(server->client, NFS3PROC_FSINFO, fhandle, info, 0);
+
+error:
+	dprintk("NFS reply statfs: %d\n", status);
+	return status;
+}
+
+struct nfs_rpc_ops	nfs_v3_clientops = {
+	3,			/* protocol version */
+	nfs3_proc_get_root,
+	nfs3_proc_getattr,
+	nfs3_proc_setattr,
+	nfs3_proc_lookup,
+	nfs3_proc_access,
+	nfs3_proc_readlink,
+	nfs3_proc_read,
+	nfs3_proc_write,
+	NULL,			/* commit */
+	nfs3_proc_create,
+	nfs3_proc_remove,
+	nfs3_proc_rename,
+	nfs3_proc_link,
+	nfs3_proc_symlink,
+	nfs3_proc_mkdir,
+	nfs3_proc_rmdir,
+	nfs3_proc_readdir,
+	nfs3_proc_mknod,
+	nfs3_proc_statfs,
+
+	nfs3_decode_dirent,
+};
Index: oldkernel/linux/fs/nfs/nfs3xdr.c
diff -u linux/fs/nfs/nfs3xdr.c:1.1.1.1 linux/fs/nfs/nfs3xdr.c:1.2
--- linux/fs/nfs/nfs3xdr.c:1.1.1.1	Wed May 31 12:33:48 2000
+++ linux/fs/nfs/nfs3xdr.c	Fri Jul  7 15:36:46 2000
@@ -1,94 +1,160 @@
 /*
- * linux/fs/nfs/nfs2xdr.c
+ * linux/fs/nfs/nfs3xdr.c
  *
  * XDR functions to encode/decode NFSv3 RPC arguments and results.
- * Note: this is incomplete!
  *
- * Copyright (C) 1996 Olaf Kirch
+ * Copyright (C) 1996, 1997 Olaf Kirch
  */
 
-#define NFS_NEED_XDR_TYPES
+#define NFS_NEED_NFS3_XDR_TYPES
 
 #include <linux/param.h>
 #include <linux/sched.h>
 #include <linux/mm.h>
 #include <linux/malloc.h>
-#include <linux/nfs_fs.h>
 #include <linux/utsname.h>
 #include <linux/errno.h>
 #include <linux/string.h>
 #include <linux/in.h>
 #include <linux/pagemap.h>
 #include <linux/proc_fs.h>
+#include <linux/kdev_t.h>
 #include <linux/sunrpc/clnt.h>
+#include <linux/nfs.h>
+#include <linux/nfs3.h>
+#include <linux/nfs_fs.h>
 
-#ifdef RPC_DEBUG
-# define RPC_FACILITY		RPCDBG_NFS
-#endif
+/* Uncomment this to support servers requiring longword lengths */
+#define NFS_PAD_WRITES		1
 
-#define QUADLEN(len)		(((len) + 3) >> 2)
-static int			nfs_stat_to_errno(int stat);
+#define NFSDBG_FACILITY		NFSDBG_XDR
 
 /* Mapping from NFS error code to "errno" error code. */
 #define errno_NFSERR_IO		EIO
 
+extern int			nfs_stat_to_errno(int);
+
 /*
  * Declare the space requirements for NFS arguments and replies as
  * number of 32bit-words
  */
-#define NFS_fhandle_sz		(1+16)
-#define NFS_sattr_sz		8
-#define NFS_filename_sz		1+(NFS_MAXNAMLEN>>2)
-#define NFS_path_sz		1+(NFS_MAXPATHLEN>>2)
-#define NFS_fattr_sz		17
-#define NFS_info_sz		5
-#define NFS_entry_sz		NFS_filename_sz+3
-
-#define NFS_enc_void_sz		0
-#define NFS_diropargs_sz	NFS_fhandle_sz+NFS_filename_sz
-#define NFS_sattrargs_sz	NFS_fhandle_sz+NFS_sattr_sz
-#define NFS_readargs_sz		NFS_fhandle_sz+3
-#define NFS_writeargs_sz	NFS_fhandle_sz+4
-#define NFS_createargs_sz	NFS_diropargs_sz+NFS_sattr_sz
-#define NFS_renameargs_sz	NFS_diropargs_sz+NFS_diropargs_sz
-#define NFS_linkargs_sz		NFS_fhandle_sz+NFS_diropargs_sz
-#define NFS_symlinkargs_sz	NFS_diropargs_sz+NFS_path_sz+NFS_sattr_sz
-#define NFS_readdirargs_sz	NFS_fhandle_sz+2
-
-#define NFS_dec_void_sz		0
-#define NFS_attrstat_sz		1+NFS_fattr_sz
-#define NFS_diropres_sz		1+NFS_fhandle_sz+NFS_fattr_sz
-#define NFS_readlinkres_sz	1+NFS_path_sz
-#define NFS_readres_sz		1+NFS_fattr_sz+1
-#define NFS_stat_sz		1
-#define NFS_readdirres_sz	1
-#define NFS_statfsres_sz	1+NFS_info_sz
+#define NFS3_fhandle_sz		1+16
+#define NFS3_fh_sz		NFS3_fhandle_sz	/* shorthand */
+#define NFS3_sattr_sz		15
+#define NFS3_filename_sz	1+(NFS3_MAXNAMLEN>>2)
+#define NFS3_path_sz		1+(NFS3_MAXPATHLEN>>2)
+#define NFS3_fattr_sz		21
+#define NFS3_wcc_attr_sz		6
+#define NFS3_pre_op_attr_sz	1+NFS3_wcc_attr_sz
+#define NFS3_post_op_attr_sz	1+NFS3_fattr_sz
+#define NFS3_wcc_data_sz		NFS3_pre_op_attr_sz+NFS3_post_op_attr_sz
+#define NFS3_fsstat_sz		
+#define NFS3_fsinfo_sz		
+#define NFS3_pathconf_sz		
+#define NFS3_entry_sz		NFS3_filename_sz+3
+
+#define NFS3_enc_void_sz	0
+#define NFS3_sattrargs_sz	NFS3_fh_sz+NFS3_sattr_sz+3
+#define NFS3_diropargs_sz	NFS3_fh_sz+NFS3_filename_sz
+#define NFS3_accessargs_sz	NFS3_fh_sz+1
+#define NFS3_readlinkargs_sz	NFS3_fh_sz
+#define NFS3_readargs_sz	NFS3_fh_sz+3
+#define NFS3_writeargs_sz	NFS3_fh_sz+5
+#define NFS3_createargs_sz	NFS3_diropargs_sz+NFS3_sattr_sz
+#define NFS3_mkdirargs_sz	NFS3_diropargs_sz+NFS3_sattr_sz
+#define NFS3_symlinkargs_sz	NFS3_diropargs_sz+NFS3_path_sz+NFS3_sattr_sz
+#define NFS3_mknodargs_sz	NFS3_diropargs_sz+2+NFS3_sattr_sz
+#define NFS3_renameargs_sz	NFS3_diropargs_sz+NFS3_diropargs_sz
+#define NFS3_linkargs_sz		NFS3_fh_sz+NFS3_diropargs_sz
+#define NFS3_readdirargs_sz	NFS3_fh_sz+2
+#define NFS3_commitargs_sz	NFS3_fh_sz+3
+
+#define NFS3_dec_void_sz	0
+#define NFS3_attrstat_sz	1+NFS3_fattr_sz
+#define NFS3_wccstat_sz		1+NFS3_wcc_data_sz
+#define NFS3_lookupres_sz	1+NFS3_fh_sz+(2 * NFS3_post_op_attr_sz)
+#define NFS3_accessres_sz	1+NFS3_post_op_attr_sz+1
+#define NFS3_readlinkres_sz	1+NFS3_post_op_attr_sz
+#define NFS3_readres_sz		1+NFS3_post_op_attr_sz+3
+#define NFS3_writeres_sz	1+NFS3_wcc_data_sz+4
+#define NFS3_createres_sz	1+NFS3_fh_sz+NFS3_post_op_attr_sz+NFS3_wcc_data_sz
+#define NFS3_renameres_sz	1+(2 * NFS3_wcc_data_sz)
+#define NFS3_linkres_sz		1+NFS3_post_op_attr_sz+NFS3_wcc_data_sz
+#define NFS3_readdirres_sz	1+NFS3_post_op_attr_sz+2
+#define NFS3_fsstatres_sz	1+NFS3_post_op_attr_sz+13
+#define NFS3_fsinfores_sz	1+NFS3_post_op_attr_sz+12
+#define NFS3_pathconfres_sz	1+NFS3_post_op_attr_sz+6
+#define NFS3_commitres_sz	1+NFS3_wcc_data_sz+2
 
 /*
+ * Map file type to S_IFMT bits
+ */
+static struct {
+	unsigned int	mode;
+	unsigned int	nfs2type;
+} nfs_type2fmt[] = {
+      { 0,		NFNON	},
+      { S_IFREG,	NFREG	},
+      { S_IFDIR,	NFDIR	},
+      { S_IFBLK,	NFBLK	},
+      { S_IFCHR,	NFCHR	},
+      { S_IFLNK,	NFLNK	},
+      { S_IFSOCK,	NFSOCK	},
+      { S_IFIFO,	NFFIFO	},
+      { 0,		NFBAD	}
+};
+
+/*
  * Common NFS XDR functions as inlines
  */
 static inline u32 *
-xdr_encode_fhandle(u32 *p, struct nfs3_fh *fh)
+xdr_encode_fhandle(u32 *p, struct nfs_fh *fh)
 {
 	*p++ = htonl(fh->size);
 	memcpy(p, fh->data, fh->size);
-	return p + QUADLEN(fh->size);
+	return p + XDR_QUADLEN(fh->size);
 }
 
 static inline u32 *
-xdr_decode_fhandle(u32 *p, struct nfs3_fh *fh)
+xdr_decode_fhandle(u32 *p, struct nfs_fh *fh)
 {
+	/*
+	 * Zero all nonused bytes
+	 */
+	memset((u8 *)fh, 0, sizeof(*fh));
 	if ((fh->size = ntohl(*p++)) <= NFS3_FHSIZE) {
 		memcpy(fh->data, p, fh->size);
-		return p + QUADLEN(fh->size);
+		return p + XDR_QUADLEN(fh->size);
 	}
 	return NULL;
 }
+
+/*
+ * Encode/decode time.
+ * Since the VFS doesn't care for fractional times, we ignore the
+ * nanosecond field.
+ */
+static inline u32 *
+xdr_encode_time(u32 *p, time_t time)
+{
+	*p++ = htonl(time);
+	*p++ = 0;
+	return p;
+}
+
+static inline u32 *
+xdr_decode_time3(u32 *p, u64 *timep)
+{
+	*timep = ((u64)ntohl(*p++) << 32) + (u64)ntohl(*p++);
+	return p;
+}
 
-static inline enum nfs_ftype
-xdr_decode_ftype(u32 type)
+static inline u32 *
+xdr_encode_time3(u32 *p, u64 time)
 {
-	return (type == NF3FIFO)? NFFIFO : (enum nfs_ftype) type;
+	*p++ = htonl(time >> 32);
+	*p++ = htonl(time & 0xFFFFFFFF);
+	return p;
 }
 
 static inline u32 *
@@ -99,47 +165,119 @@
 	if (*len > maxlen)
 		return NULL;
 	*string = (char *) p;
-	return p + QUADLEN(*len);
+	return p + XDR_QUADLEN(*len);
 }
 
 static inline u32 *
-xdr_decode_fattr(u32 *p, struct nfs3_fattr *fattr)
+xdr_decode_fattr(u32 *p, struct nfs_fattr *fattr)
 {
-	fattr->type = xdr_decode_ftype(ntohl(*p++));
-	fattr->mode = ntohl(*p++);
+	unsigned int	type;
+	int		fmode;
+
+	type = ntohl(*p++);
+	if (type >= NF3BAD)
+		type = NF3BAD;
+	fmode = nfs_type2fmt[type].mode;
+	fattr->type = nfs_type2fmt[type].nfs2type;
+	fattr->mode = (ntohl(*p++) & ~S_IFMT) | fmode;
 	fattr->nlink = ntohl(*p++);
 	fattr->uid = ntohl(*p++);
 	fattr->gid = ntohl(*p++);
-	fattr->size = ((u64) ntohl(*p++) << 32) | ntohl(*p++);
-	fattr->used = ((u64) ntohl(*p++) << 32) | ntohl(*p++);
-	fattr->rdev_maj = ntohl(*p++);
-	fattr->rdev_min = ntohl(*p++);
-	fattr->fsid = ntohl(*p++);
-	fattr->fileid = ntohl(*p++);
-	fattr->atime.seconds = ntohl(*p++);
-	fattr->atime.useconds = ntohl(*p++);
-	fattr->mtime.seconds = ntohl(*p++);
-	fattr->mtime.useconds = ntohl(*p++);
-	fattr->ctime.seconds = ntohl(*p++);
-	fattr->ctime.useconds = ntohl(*p++);
+	p = xdr_decode_hyper(p, &fattr->size);
+	p = xdr_decode_hyper(p, &fattr->du.nfs3.used);
+	/* Turn remote device info into Linux-specific dev_t */
+	fattr->rdev = (ntohl(*p++) << MINORBITS) | (ntohl(*p++) & MINORMASK);
+	p = xdr_decode_hyper(p, &fattr->fsid);
+	p = xdr_decode_hyper(p, &fattr->fileid);
+	p = xdr_decode_time3(p, &fattr->atime);
+	p = xdr_decode_time3(p, &fattr->mtime);
+	p = xdr_decode_time3(p, &fattr->ctime);
+
+	/* Update the mode bits */
+	fattr->valid |= (NFS_ATTR_FATTR | NFS_ATTR_FATTR_V3);
 	return p;
 }
 
 static inline u32 *
-xdr_encode_sattr(u32 *p, struct nfs_sattr *sattr)
+xdr_encode_sattr(u32 *p, struct iattr *attr)
 {
-	*p++ = htonl(sattr->mode);
-	*p++ = htonl(sattr->uid);
-	*p++ = htonl(sattr->gid);
-	*p++ = htonl(sattr->size >> 32);
-	*p++ = htonl(sattr->size & 0xFFFFFFFF);
-	*p++ = htonl(sattr->atime.seconds);
-	*p++ = htonl(sattr->atime.useconds);
-	*p++ = htonl(sattr->mtime.seconds);
-	*p++ = htonl(sattr->mtime.useconds);
+	if (attr->ia_valid & ATTR_MODE) {
+		*p++ = xdr_one;
+		*p++ = htonl(attr->ia_mode);
+	} else {
+		*p++ = xdr_zero;
+	}
+	if (attr->ia_valid & ATTR_UID) {
+		*p++ = xdr_one;
+		*p++ = htonl(attr->ia_uid);
+	} else {
+		*p++ = xdr_zero;
+	}
+	if (attr->ia_valid & ATTR_GID) {
+		*p++ = xdr_one;
+		*p++ = htonl(attr->ia_gid);
+	} else {
+		*p++ = xdr_zero;
+	}
+	if (attr->ia_valid & ATTR_SIZE) {
+		*p++ = xdr_one;
+		p = xdr_encode_hyper(p, (__u64) attr->ia_size);
+	} else {
+		*p++ = xdr_zero;
+	}
+	if (attr->ia_valid & ATTR_ATIME_SET) {
+		*p++ = xdr_two;
+		p = xdr_encode_time(p, attr->ia_atime);
+	} else if (attr->ia_valid & ATTR_ATIME) {
+		*p++ = xdr_one;
+	} else {
+		*p++ = xdr_zero;
+	}
+	if (attr->ia_valid & ATTR_MTIME_SET) {
+		*p++ = xdr_two;
+		p = xdr_encode_time(p, attr->ia_mtime);
+	} else if (attr->ia_valid & ATTR_MTIME) {
+		*p++ = xdr_one;
+	} else {
+		*p++ = xdr_zero;
+	}
+	return p;
+}
+
+static inline u32 *
+xdr_decode_wcc_attr(u32 *p, struct nfs_fattr *fattr)
+{
+	p = xdr_decode_hyper(p, &fattr->pre_size);
+	p = xdr_decode_time3(p, &fattr->pre_mtime);
+	p = xdr_decode_time3(p, &fattr->pre_ctime);
+	fattr->valid |= NFS_ATTR_WCC;
 	return p;
 }
 
+static inline u32 *
+xdr_decode_post_op_attr(u32 *p, struct nfs_fattr *fattr)
+{
+	if (*p++)
+		p = xdr_decode_fattr(p, fattr);
+	return p;
+}
+
+static inline u32 *
+xdr_decode_pre_op_attr(u32 *p, struct nfs_fattr *fattr)
+{
+	if (*p++)
+		return xdr_decode_wcc_attr(p, fattr);
+	return p;
+}
+
+
+static inline u32 *
+xdr_decode_wcc_data(u32 *p, struct nfs_fattr *fattr)
+{
+	p = xdr_decode_pre_op_attr(p, fattr);
+	return xdr_decode_post_op_attr(p, fattr);
+}
+
 /*
  * NFS encode functions
  */
@@ -147,7 +285,7 @@
  * Encode void argument
  */
 static int
-nfs_xdr_enc_void(struct rpc_rqst *req, u32 *p, void *dummy)
+nfs3_xdr_enc_void(struct rpc_rqst *req, u32 *p, void *dummy)
 {
 	req->rq_slen = xdr_adjust_iovec(req->rq_svec, p);
 	return 0;
@@ -155,10 +293,9 @@
 
 /*
  * Encode file handle argument
- * GETATTR, READLINK, STATFS
  */
 static int
-nfs_xdr_fhandle(struct rpc_rqst *req, u32 *p, struct nfs3_fh *fh)
+nfs3_xdr_fhandle(struct rpc_rqst *req, u32 *p, struct nfs_fh *fh)
 {
 	p = xdr_encode_fhandle(p, fh);
 	req->rq_slen = xdr_adjust_iovec(req->rq_svec, p);
@@ -169,173 +306,219 @@
  * Encode SETATTR arguments
  */
 static int
-nfs_xdr_sattrargs(struct rpc_rqst *req, u32 *p, struct nfs_sattrargs *args)
+nfs3_xdr_sattrargs(struct rpc_rqst *req, u32 *p, struct nfs3_sattrargs *args)
 {
 	p = xdr_encode_fhandle(p, args->fh);
 	p = xdr_encode_sattr(p, args->sattr);
+	*p++ = htonl(args->guard);
+	if (args->guard)
+		p = xdr_encode_time3(p, args->guardtime);
 	req->rq_slen = xdr_adjust_iovec(req->rq_svec, p);
 	return 0;
 }
 
 /*
  * Encode directory ops argument
- * LOOKUP, REMOVE, RMDIR
  */
 static int
-nfs_xdr_diropargs(struct rpc_rqst *req, u32 *p, struct nfs_diropargs *args)
+nfs3_xdr_diropargs(struct rpc_rqst *req, u32 *p, struct nfs3_diropargs *args)
 {
 	p = xdr_encode_fhandle(p, args->fh);
-	p = xdr_encode_string(p, args->name);
+	p = xdr_encode_string(p, args->name, args->len);
 	req->rq_slen = xdr_adjust_iovec(req->rq_svec, p);
 	return 0;
 }
 
 /*
+ * Encode access() argument
+ */
+static int
+nfs3_xdr_accessargs(struct rpc_rqst *req, u32 *p, struct nfs3_accessargs *args)
+{
+	p = xdr_encode_fhandle(p, args->fh);
+	*p++ = htonl(args->access);
+	req->rq_slen = xdr_adjust_iovec(req->rq_svec, p);
+	return 0;
+}
+
+/*
  * Arguments to a READ call. Since we read data directly into the page
  * cache, we also set up the reply iovec here so that iov[1] points
- * exactly to the page wewant to fetch.
+ * exactly to the page we want to fetch.
  */
 static int
-nfs_xdr_readargs(struct rpc_rqst *req, u32 *p, struct nfs_readargs *args)
+nfs3_xdr_readargs(struct rpc_rqst *req, u32 *p, struct nfs_readargs *args)
 {
 	struct rpc_auth	*auth = req->rq_task->tk_auth;
-	int		replen, buflen;
+	int		buflen, replen;
+	unsigned int	nr;
 
 	p = xdr_encode_fhandle(p, args->fh);
-	*p++ = htonl(args->offset);
-	*p++ = htonl(args->count);
+	p = xdr_encode_hyper(p, args->offset);
 	*p++ = htonl(args->count);
 	req->rq_slen = xdr_adjust_iovec(req->rq_svec, p);
 
-#if 1
+	/* Get the number of buffers in the receive iovec */
+	nr = args->nriov;
+
+	if (nr+2 > MAX_IOVEC) {
+		printk(KERN_ERR "NFS: Bad number of iov's in xdr_readargs\n");
+		return -EINVAL;
+	}
+
 	/* set up reply iovec */
-	replen = (RPC_REPHDRSIZE + auth->au_rslack + NFS_readres_sz) << 2;
+	replen = (RPC_REPHDRSIZE + auth->au_rslack + NFS3_readres_sz) << 2;
 	buflen = req->rq_rvec[0].iov_len;
 	req->rq_rvec[0].iov_len  = replen;
-	req->rq_rvec[1].iov_base = args->buffer;
-	req->rq_rvec[1].iov_len  = args->count;
-	req->rq_rvec[2].iov_base = (u8 *) req->rq_rvec[0].iov_base + replen;
-	req->rq_rvec[2].iov_len  = buflen - replen;
+
+	/* Copy the iovec */
+	memcpy(req->rq_rvec + 1, args->iov, nr * sizeof(struct iovec));
+
+	req->rq_rvec[nr+1].iov_base = (u8 *) req->rq_rvec[0].iov_base + replen;
+	req->rq_rvec[nr+1].iov_len  = buflen - replen;
 	req->rq_rlen = args->count + buflen;
-	req->rq_rnr = 3;
-#else
-	replen = (RPC_REPHDRSIZE + auth->au_rslack + NFS_readres_sz) << 2;
-	req->rq_rvec[0].iov_len  = replen;
-#endif
+	req->rq_rnr += nr+1;
 
 	return 0;
 }
 
 /*
- * Decode READ reply
+ * Write arguments. Splice the buffer to be written into the iovec.
  */
 static int
-nfs_xdr_readres(struct rpc_rqst *req, u32 *p, struct nfs_readres *res)
+nfs3_xdr_writeargs(struct rpc_rqst *req, u32 *p, struct nfs_writeargs *args)
 {
-	struct iovec *iov = req->rq_rvec;
-	int	status, count, recvd, hdrlen;
+	unsigned int	nr;
+	u32 count = args->count;
 
-	dprintk("RPC:      readres OK status %lx\n", ntohl(*p));
-	if ((status = ntohl(*p++)))
-		return -nfs_stat_to_errno(status);
-	p = xdr_decode_fattr(p, res->fattr);
+	p = xdr_encode_fhandle(p, args->fh);
+	p = xdr_encode_hyper(p, args->offset);
+	*p++ = htonl(count);
+	*p++ = htonl(args->stable);
+	*p++ = htonl(count);
+	req->rq_slen = xdr_adjust_iovec(req->rq_svec, p);
 
-	count = ntohl(*p++);
-	hdrlen = (u8 *) p - (u8 *) iov->iov_base;
-	recvd = req->rq_rlen - hdrlen;
-	if (p != iov[2].iov_base) {
-		/* Unexpected reply header size. Punt.
-		 * XXX: Move iovec contents to align data on page
-		 * boundary and adjust RPC header size guess */
-		printk("NFS: Odd RPC header size in read reply: %d\n", hdrlen);
-		return -errno_NFSERR_IO;
-	}
-	if (count > recvd) {
-		printk("NFS: server cheating in read reply: "
-			"count %d > recvd %d\n", count, recvd);
-		count = recvd;
+	/* Get the number of buffers in the send iovec */
+	nr = args->nriov;
+
+	if (nr+2 > MAX_IOVEC) {
+		printk(KERN_ERR "NFS: Bad number of iov's in xdr_writeargs\n");
+		return -EINVAL;
 	}
 
-	dprintk("RPC:      readres OK count %d\n", count);
-	if (count < res->count)
-		memset((u8 *)(iov[1].iov_base+count), 0, res->count-count);
+	/* Copy the iovec */
+	memcpy(req->rq_svec + 1, args->iov, nr * sizeof(struct iovec));
 
-	return count;
-}
+#ifdef NFS_PAD_WRITES
+	/*
+	 * Some old servers require that the message length
+	 * be a multiple of 4, so we pad it here if needed.
+	 */
+	if (count & 3) {
+		struct iovec	*iov = req->rq_svec + nr + 1;
+		int		pad = 4 - (count & 3);
+
+		iov->iov_base = (void *) "\0\0\0";
+		iov->iov_len  = pad;
+		count += pad;
+		nr++;
+	}
+#endif
+	req->rq_slen += count;
+	req->rq_snr  += nr;
 
+	return 0;
+}
 
 /*
- * Write arguments. Splice the buffer to be written into the iovec.
+ * Encode CREATE arguments
  */
 static int
-nfs_xdr_writeargs(struct rpc_rqst *req, u32 *p, struct nfs_writeargs *args)
+nfs3_xdr_createargs(struct rpc_rqst *req, u32 *p, struct nfs3_createargs *args)
 {
 	p = xdr_encode_fhandle(p, args->fh);
-	*p++ = htonl(args->offset);
-	*p++ = htonl(args->offset);
-	*p++ = htonl(args->count);
-	*p++ = htonl(args->count);
-	req->rq_slen = xdr_adjust_iovec(req->rq_svec, p);
+	p = xdr_encode_string(p, args->name, args->len);
 
-	req->rq_svec[1].iov_base = (void *) args->buffer;
-	req->rq_svec[1].iov_len = args->count;
-	req->rq_slen += args->count;
-	req->rq_snr = 2;
+	*p++ = htonl(args->createmode);
+	if (args->createmode == NFS3_CREATE_EXCLUSIVE) {
+		*p++ = args->verifier[0];
+		*p++ = args->verifier[1];
+	} else
+		p = xdr_encode_sattr(p, args->sattr);
 
+	req->rq_slen = xdr_adjust_iovec(req->rq_svec, p);
 	return 0;
 }
 
 /*
- * Encode create arguments
- * CREATE, MKDIR
+ * Encode MKDIR arguments
  */
 static int
-nfs_xdr_createargs(struct rpc_rqst *req, u32 *p, struct nfs_createargs *args)
+nfs3_xdr_mkdirargs(struct rpc_rqst *req, u32 *p, struct nfs3_mkdirargs *args)
 {
 	p = xdr_encode_fhandle(p, args->fh);
-	p = xdr_encode_string(p, args->name);
+	p = xdr_encode_string(p, args->name, args->len);
 	p = xdr_encode_sattr(p, args->sattr);
 	req->rq_slen = xdr_adjust_iovec(req->rq_svec, p);
 	return 0;
 }
 
 /*
- * Encode RENAME arguments
+ * Encode SYMLINK arguments
  */
 static int
-nfs_xdr_renameargs(struct rpc_rqst *req, u32 *p, struct nfs_renameargs *args)
+nfs3_xdr_symlinkargs(struct rpc_rqst *req, u32 *p, struct nfs3_symlinkargs *args)
 {
 	p = xdr_encode_fhandle(p, args->fromfh);
-	p = xdr_encode_string(p, args->fromname);
-	p = xdr_encode_fhandle(p, args->tofh);
-	p = xdr_encode_string(p, args->toname);
+	p = xdr_encode_string(p, args->fromname, args->fromlen);
+	p = xdr_encode_sattr(p, args->sattr);
+	p = xdr_encode_string(p, args->topath, args->tolen);
 	req->rq_slen = xdr_adjust_iovec(req->rq_svec, p);
 	return 0;
 }
 
 /*
- * Encode LINK arguments
+ * Encode MKNOD arguments
+ */
+static int
+nfs3_xdr_mknodargs(struct rpc_rqst *req, u32 *p, struct nfs3_mknodargs *args)
+{
+	p = xdr_encode_fhandle(p, args->fh);
+	p = xdr_encode_string(p, args->name, args->len);
+	*p++ = htonl(args->type);
+	p = xdr_encode_sattr(p, args->sattr);
+	if (args->type == NF3CHR || args->type == NF3BLK) {
+		*p++ = htonl(args->rdev >> MINORBITS);
+		*p++ = htonl(args->rdev & MINORMASK);
+	}
+
+	req->rq_slen = xdr_adjust_iovec(req->rq_svec, p);
+	return 0;
+}
+
+/*
+ * Encode RENAME arguments
  */
 static int
-nfs_xdr_linkargs(struct rpc_rqst *req, u32 *p, struct nfs_linkargs *args)
+nfs3_xdr_renameargs(struct rpc_rqst *req, u32 *p, struct nfs3_renameargs *args)
 {
 	p = xdr_encode_fhandle(p, args->fromfh);
+	p = xdr_encode_string(p, args->fromname, args->fromlen);
 	p = xdr_encode_fhandle(p, args->tofh);
-	p = xdr_encode_string(p, args->toname);
+	p = xdr_encode_string(p, args->toname, args->tolen);
 	req->rq_slen = xdr_adjust_iovec(req->rq_svec, p);
 	return 0;
 }
 
 /*
- * Encode SYMLINK arguments
+ * Encode LINK arguments
  */
 static int
-nfs_xdr_symlinkargs(struct rpc_rqst *req, u32 *p, struct nfs_symlinkargs *args)
+nfs3_xdr_linkargs(struct rpc_rqst *req, u32 *p, struct nfs3_linkargs *args)
 {
 	p = xdr_encode_fhandle(p, args->fromfh);
-	p = xdr_encode_string(p, args->fromname);
-	p = xdr_encode_string(p, args->topath);
-	p = xdr_encode_sattr(p, args->sattr);
+	p = xdr_encode_fhandle(p, args->tofh);
+	p = xdr_encode_string(p, args->toname, args->tolen);
 	req->rq_slen = xdr_adjust_iovec(req->rq_svec, p);
 	return 0;
 }
@@ -344,191 +527,257 @@
  * Encode arguments to readdir call
  */
 static int
-nfs_xdr_readdirargs(struct rpc_rqst *req, u32 *p, struct nfs_readdirargs *args)
+nfs3_xdr_readdirargs(struct rpc_rqst *req, u32 *p, struct nfs3_readdirargs *args)
 {
 	struct rpc_auth	*auth = req->rq_task->tk_auth;
-	int		replen;
+	int		buflen, replen;
 
 	p = xdr_encode_fhandle(p, args->fh);
-	*p++ = htonl(args->cookie);
+	p = xdr_encode_hyper(p, args->cookie);
+	*p++ = args->verf[0];
+	*p++ = args->verf[1];
+	if (args->plus) {
+		/* readdirplus: need dircount + buffer size.
+		 * We just make sure we make dircount big enough */
+		*p++ = htonl(args->bufsiz >> 3);
+	}
 	*p++ = htonl(args->bufsiz);
 	req->rq_slen = xdr_adjust_iovec(req->rq_svec, p);
 
 	/* set up reply iovec */
-	replen = (RPC_REPHDRSIZE + auth->au_rslack + NFS_readdirres_sz) << 2;
-	/*
-	dprintk("RPC: readdirargs: slack is 4 * (%d + %d + %d) = %d\n",
-		RPC_REPHDRSIZE, auth->au_rslack, NFS_readdirres_sz, replen);
-	 */
+	replen = (RPC_REPHDRSIZE + auth->au_rslack + NFS3_readdirres_sz) << 2;
+	buflen = req->rq_rvec[0].iov_len;
 	req->rq_rvec[0].iov_len  = replen;
 	req->rq_rvec[1].iov_base = args->buffer;
 	req->rq_rvec[1].iov_len  = args->bufsiz;
-	req->rq_rlen = replen + args->bufsiz;
-	req->rq_rnr = 2;
-
-	/*
-	dprintk("RPC:      readdirargs set up reply vec:\n");
-	dprintk("          rvec[0] = %p/%d\n",
-			req->rq_rvec[0].iov_base,
-			req->rq_rvec[0].iov_len);
-	dprintk("          rvec[1] = %p/%d\n",
-			req->rq_rvec[1].iov_base,
-			req->rq_rvec[1].iov_len);
-	 */
+	req->rq_rvec[2].iov_base = (u8 *) req->rq_rvec[0].iov_base + replen;
+	req->rq_rvec[2].iov_len  = buflen - replen;
+	req->rq_rlen = buflen + args->bufsiz;
+	req->rq_rnr += 2;
 
 	return 0;
 }
 
 /*
- * Decode the result of a readdir call. We decode the result in place
- * to avoid a malloc of NFS_MAXNAMLEN+1 for each file name.
- * After decoding, the layout in memory looks like this:
- *	entry1 entry2 ... entryN <space> stringN ... string2 string1
- * Each entry consists of three __u32 values, the same space as NFS uses.
- * Note that the strings are not null-terminated so that the entire number
- * of entries returned by the server should fit into the buffer.
- */
-static int
-nfs_xdr_readdirres(struct rpc_rqst *req, u32 *p, struct nfs_readdirres *res)
-{
-	struct iovec		*iov = req->rq_rvec;
-	int			status, nr, len;
-	char			*string, *start;
-	u32			*end;
-	__u32			fileid, cookie, *entry;
-
-	if ((status = ntohl(*p++)))
+ * Decode the result of a readdir call.
+ * We just check for syntactical correctness.
+ */
+static int
+nfs3_xdr_readdirres(struct rpc_rqst *req, u32 *p, struct nfs3_readdirres *res)
+{
+	struct iovec	*iov = req->rq_rvec;
+	int		hdrlen;
+	int		status, nr;
+	unsigned int	len;
+	u32		*entry, *end;
+
+	status = ntohl(*p++);
+	/* Decode post_op_attrs */
+	p = xdr_decode_post_op_attr(p, res->dir_attr);
+	if (status)
 		return -nfs_stat_to_errno(status);
-	if ((void *) p != ((u8 *) iov->iov_base+iov->iov_len)) {
-		/* Unexpected reply header size. Punt. */
-		printk("NFS: Odd RPC header size in readdirres reply\n");
-		return -errno_NFSERR_IO;
+	/* Decode verifier cookie */
+	if (res->verf) {
+		res->verf[0] = *p++;
+		res->verf[1] = *p++;
+	} else {
+		p += 2;
 	}
-
-	p = (u32 *) iov[1].iov_base;
-	end = (u32 *) ((u8 *) p + iov[1].iov_len);
 
-	if (p != res->buffer) {
-		printk("NFS: p != res->buffer in %s:%d!!!\n",
-					__FILE__, __LINE__);
-		return -errno_NFSERR_IO;
+	hdrlen = (u8 *) p - (u8 *) iov->iov_base;
+	if (iov->iov_len > hdrlen) {
+		dprintk("NFS: READDIR header is short. iovec will be shifted.\n");
+		xdr_shift_iovec(iov, req->rq_rnr, iov->iov_len - hdrlen);
 	}
 
-	entry  = (__u32 *) res->buffer;
-	start  = (char *) res->buffer;
-	string = start + res->bufsiz;
+	p   = (u32 *) iov[1].iov_base;
+	end = (u32 *) ((u8 *) p + iov[1].iov_len);
 	for (nr = 0; *p++; nr++) {
-		fileid = ntohl(*p++);
-
-		len = ntohl(*p++);
-		if ((p + QUADLEN(len) + 3) > end) {
-			printk(KERN_NOTICE
-				"NFS: short packet in readdir reply!\n");
-			break;
-		}
-		if (len > NFS_MAXNAMLEN) {
-			printk("NFS: giant filename in readdir (len %x)!\n",
+		entry = p - 1;
+		p += 2;				/* inode # */
+		len = ntohl(*p++);		/* string length */
+		p += XDR_QUADLEN(len) + 2;	/* name + cookie */
+		if (len > NFS3_MAXNAMLEN) {
+			printk(KERN_WARNING "NFS: giant filename in readdir (len %x)!\n",
 						len);
 			return -errno_NFSERR_IO;
+		}
+
+		if (res->plus) {
+			/* post_op_attr */
+			if (*p++)
+				p += 21;
+			/* post_op_fh3 */
+			if (*p++) {
+				len = ntohl(*p++);
+				if (len > NFS3_FHSIZE) {
+					printk(KERN_WARNING "NFS: giant filehandle in "
+						"readdir (len %x)!\n", len);
+					return -errno_NFSERR_IO;
+				}
+				p += XDR_QUADLEN(len);
+			}
 		}
-		string -= len;
-		if ((void *) (entry+3) > (void *) string) {
-			/* 
-			 * This error is impossible as long as the temp
-			 * buffer is no larger than the user buffer. The 
-			 * current packing algorithm uses the same amount
-			 * of space in the user buffer as in the XDR data,
-			 * so it's guaranteed to fit.
-			 */
-			printk("NFS: incorrect buffer size in %s!\n",
-				__FUNCTION__);
+
+		if (p + 2 > end) {
+			printk(KERN_NOTICE
+				"NFS: short packet in readdir reply!\n");
+			/* truncate listing */
+			entry[0] = entry[1] = 0;
 			break;
 		}
+	}
 
-		memmove(string, p, len);
-		p += QUADLEN(len);
-		cookie = ntohl(*p++);
-		/*
-		 * To make everything fit, we encode the length, offset,
-		 * and eof flag into 32 bits. This works for filenames
-		 * up to 32K and PAGE_SIZE up to 64K.
-		 */
-		status = !p[0] && p[1] ? (1 << 15) : 0; /* eof flag */
-		*entry++ = fileid;
-		*entry++ = cookie;
-		*entry++ = ((string - start) << 16) | status | (len & 0x7FFF);
-		/*
-		dprintk("NFS: decoded dirent %.*s cookie %d eof %d\n",
-			len, string, cookie, status);
-		 */
-	}
-#ifdef NFS_PARANOIA
-printk("nfs_xdr_readdirres: %d entries, ent sp=%d, str sp=%d\n",
-nr, ((char *) entry - start), (start + res->bufsiz - string));
-#endif
 	return nr;
 }
 
+u32 *
+nfs3_decode_dirent(u32 *p, struct nfs_entry *entry, int plus)
+{
+	struct nfs_entry old = *entry;
+
+	if (!*p++) {
+		if (!*p)
+			return ERR_PTR(-EAGAIN);
+		entry->eof = 1;
+		return ERR_PTR(-EBADCOOKIE);
+	}
+
+	p = xdr_decode_hyper(p, &entry->ino);
+	entry->len  = ntohl(*p++);
+	entry->name = (const char *) p;
+	p += XDR_QUADLEN(entry->len);
+	entry->prev_cookie = entry->cookie;
+	p = xdr_decode_hyper(p, &entry->cookie);
+
+	if (plus) {
+		p = xdr_decode_post_op_attr(p, &entry->fattr);
+		/* In fact, a post_op_fh3: */
+		if (*p++) {
+			p = xdr_decode_fhandle(p, &entry->fh);
+			/* Ugh -- server reply was truncated */
+			if (p == NULL) {
+				dprintk("NFS: FH truncated\n");
+				*entry = old;
+				return ERR_PTR(-EAGAIN);
+			}
+		} else {
+			/* If we don't get a file handle, the attrs
+			 * aren't worth a lot. */
+			entry->fattr.valid = 0;
+		}
+	}
+
+	entry->eof = !p[0] && p[1];
+	return p;
+}
+
 /*
+ * Encode COMMIT arguments
+ */
+static int
+nfs3_xdr_commitargs(struct rpc_rqst *req, u32 *p, struct nfs_writeargs *args)
+{
+	p = xdr_encode_fhandle(p, args->fh);
+	p = xdr_encode_hyper(p, args->offset);
+	*p++ = htonl(args->count);
+	req->rq_slen = xdr_adjust_iovec(req->rq_svec, p);
+	return 0;
+}
+
+/*
  * NFS XDR decode functions
  */
 /*
  * Decode void reply
  */
 static int
-nfs_xdr_dec_void(struct rpc_rqst *req, u32 *p, void *dummy)
+nfs3_xdr_dec_void(struct rpc_rqst *req, u32 *p, void *dummy)
 {
 	return 0;
 }
 
 /*
- * Decode simple status reply
+ * Decode attrstat reply.
  */
 static int
-nfs_xdr_stat(struct rpc_rqst *req, u32 *p, void *dummy)
+nfs3_xdr_attrstat(struct rpc_rqst *req, u32 *p, struct nfs_fattr *fattr)
 {
 	int	status;
 
-	if ((status = ntohl(*p++)) != 0)
-		status = -nfs_stat_to_errno(status);
-	return status;
+	if ((status = ntohl(*p++)))
+		return -nfs_stat_to_errno(status);
+	xdr_decode_fattr(p, fattr);
+	return 0;
 }
 
 /*
- * Decode attrstat reply
- * GETATTR, SETATTR, WRITE
+ * Decode status+wcc_data reply
+ * SATTR, REMOVE, RMDIR
  */
 static int
-nfs_xdr_attrstat(struct rpc_rqst *req, u32 *p, struct nfs_fattr *fattr)
+nfs3_xdr_wccstat(struct rpc_rqst *req, u32 *p, struct nfs_fattr *fattr)
 {
 	int	status;
 
-	dprintk("RPC:      attrstat status %lx\n", ntohl(*p));
 	if ((status = ntohl(*p++)))
-		return -nfs_stat_to_errno(status);
-	xdr_decode_fattr(p, fattr);
-	dprintk("RPC:      attrstat OK type %d mode %o dev %x ino %x\n",
-		fattr->type, fattr->mode, fattr->fsid, fattr->fileid);
-	return 0;
+		status = -nfs_stat_to_errno(status);
+	xdr_decode_wcc_data(p, fattr);
+	return status;
 }
 
 /*
- * Decode diropres reply
- * LOOKUP, CREATE, MKDIR
+ * Decode LOOKUP reply
  */
 static int
-nfs_xdr_diropres(struct rpc_rqst *req, u32 *p, struct nfs_diropok *res)
+nfs3_xdr_lookupres(struct rpc_rqst *req, u32 *p, struct nfs3_diropres *res)
 {
 	int	status;
 
-	dprintk("RPC:      diropres status %lx\n", ntohl(*p));
-	if ((status = ntohl(*p++)))
+	if ((status = ntohl(*p++))) {
+		status = -nfs_stat_to_errno(status);
+	} else {
+		if (!(p = xdr_decode_fhandle(p, res->fh)))
+			return -errno_NFSERR_IO;
+		p = xdr_decode_post_op_attr(p, res->fattr);
+	}
+	xdr_decode_post_op_attr(p, res->dir_attr);
+	return status;
+}
+
+/*
+ * Decode ACCESS reply
+ */
+static int
+nfs3_xdr_accessres(struct rpc_rqst *req, u32 *p, struct nfs3_accessres *res)
+{
+	int	status = ntohl(*p++);
+
+	p = xdr_decode_post_op_attr(p, res->fattr);
+	if (status)
 		return -nfs_stat_to_errno(status);
-	p = xdr_decode_fhandle(p, res->fh);
-	xdr_decode_fattr(p, res->fattr);
-	dprintk("RPC:      diropres OK type %x mode %o dev %x ino %x\n",
-		res->fattr->type, res->fattr->mode,
-		res->fattr->fsid, res->fattr->fileid);
+	res->access = ntohl(*p++);
+	return 0;
+}
+
+static int
+nfs3_xdr_readlinkargs(struct rpc_rqst *req, u32 *p, struct nfs3_readlinkargs *args)
+{
+	struct rpc_task *task = req->rq_task;
+	struct rpc_auth *auth = task->tk_auth;
+	int		buflen, replen;
+
+	p = xdr_encode_fhandle(p, args->fh);
+	req->rq_slen = xdr_adjust_iovec(req->rq_svec, p);
+	replen = (RPC_REPHDRSIZE + auth->au_rslack + NFS3_readlinkres_sz) << 2;
+	buflen = req->rq_rvec[0].iov_len;
+	req->rq_rvec[0].iov_len  = replen;
+	req->rq_rvec[1].iov_base = args->buffer;
+	req->rq_rvec[1].iov_len  = args->bufsiz;
+	req->rq_rvec[2].iov_base = (u8 *) req->rq_rvec[0].iov_base + replen;
+	req->rq_rvec[2].iov_len  = buflen - replen;
+	req->rq_rlen = buflen + args->bufsiz;
+	req->rq_rnr += 2;
 	return 0;
 }
 
@@ -536,155 +785,299 @@
  * Decode READLINK reply
  */
 static int
-nfs_xdr_readlinkres(struct rpc_rqst *req, u32 *p, struct nfs_readlinkres *res)
+nfs3_xdr_readlinkres(struct rpc_rqst *req, u32 *p, struct nfs3_readlinkres *res)
 {
+	struct iovec	*iov = req->rq_rvec;
+	int		hdrlen;
+	u32	*strlen;
+	char	*string;
 	int	status;
+	unsigned int len;
 
-	if ((status = ntohl(*p++)))
+	status = ntohl(*p++);
+	p = xdr_decode_post_op_attr(p, res->fattr);
+
+	if (status != 0)
 		return -nfs_stat_to_errno(status);
-	xdr_decode_string2(p, res->string, res->lenp, res->maxlen);
 
-	/* Caller takes over the buffer here to avoid extra copy */
-	res->buffer = req->rq_task->tk_buffer;
-	req->rq_task->tk_buffer = NULL;
+	hdrlen = (u8 *) p - (u8 *) iov->iov_base;
+	if (iov->iov_len > hdrlen) {
+		dprintk("NFS: READLINK header is short. iovec will be shifted.\n");
+		xdr_shift_iovec(iov, req->rq_rnr, iov->iov_len - hdrlen);
+	}
+
+	strlen = (u32*)res->buffer;
+	/* Convert length of symlink */
+	len = ntohl(*strlen);
+	if (len > res->bufsiz - 5)
+		len = res->bufsiz - 5;
+	*strlen = len;
+	/* NULL terminate the string we got */
+	string = (char *)(strlen + 1);
+	string[len] = 0;
 	return 0;
 }
 
 /*
- * Decode STATFS reply
+ * Decode READ reply
  */
 static int
-nfs_xdr_statfsres(struct rpc_rqst *req, u32 *p, struct nfs_fsinfo *res)
+nfs3_xdr_readres(struct rpc_rqst *req, u32 *p, struct nfs_readres *res)
 {
-	int	status;
+	struct iovec *iov = req->rq_rvec;
+	int	status, count, ocount, recvd, hdrlen;
 
-	if ((status = ntohl(*p++)))
+	status = ntohl(*p++);
+	p = xdr_decode_post_op_attr(p, res->fattr);
+
+	if (status != 0)
 		return -nfs_stat_to_errno(status);
-	res->tsize = ntohl(*p++);
-	res->bsize = ntohl(*p++);
-	res->blocks = ntohl(*p++);
-	res->bfree = ntohl(*p++);
-	res->bavail = ntohl(*p++);
-	return 0;
+
+	/* Decode reply could and EOF flag. NFSv3 is somewhat redundant
+	 * in that it puts the count both in the res struct and in the
+	 * opaque data count. */
+	count    = ntohl(*p++);
+	res->eof = ntohl(*p++);
+	ocount   = ntohl(*p++);
+
+	if (ocount != count) {
+		printk(KERN_WARNING "NFS: READ count doesn't match RPC opaque count.\n");
+		return -errno_NFSERR_IO;
+	}
+
+	hdrlen = (u8 *) p - (u8 *) iov->iov_base;
+	if (iov->iov_len > hdrlen) {
+		dprintk("NFS: READ header is short. iovec will be shifted.\n");
+		xdr_shift_iovec(iov, req->rq_rnr, iov->iov_len - hdrlen);
+	}
+
+	recvd = req->rq_rlen - hdrlen;
+	if (count > recvd) {
+		printk(KERN_WARNING "NFS: server cheating in read reply: "
+			"count %d > recvd %d\n", count, recvd);
+		count = recvd;
+	}
+
+	if (count < res->count) {
+		xdr_zero_iovec(iov+1, req->rq_rnr-2, res->count - count);
+		res->count = count;
+	}
+
+	return count;
 }
 
 /*
- * We need to translate between nfs status return values and
- * the local errno values which may not be the same.
+ * Decode WRITE response
  */
-static struct {
-	int stat;
-	int errno;
-} nfs_errtbl[] = {
-	{ NFS_OK,		0		},
-	{ NFSERR_PERM,		EPERM		},
-	{ NFSERR_NOENT,		ENOENT		},
-	{ NFSERR_IO,		errno_NFSERR_IO	},
-	{ NFSERR_NXIO,		ENXIO		},
-	{ NFSERR_EAGAIN,	EAGAIN		},
-	{ NFSERR_ACCES,		EACCES		},
-	{ NFSERR_EXIST,		EEXIST		},
-	{ NFSERR_XDEV,		EXDEV		},
-	{ NFSERR_NODEV,		ENODEV		},
-	{ NFSERR_NOTDIR,	ENOTDIR		},
-	{ NFSERR_ISDIR,		EISDIR		},
-	{ NFSERR_INVAL,		EINVAL		},
-	{ NFSERR_FBIG,		EFBIG		},
-	{ NFSERR_NOSPC,		ENOSPC		},
-	{ NFSERR_ROFS,		EROFS		},
-	{ NFSERR_NAMETOOLONG,	ENAMETOOLONG	},
-	{ NFSERR_NOTEMPTY,	ENOTEMPTY	},
-	{ NFSERR_DQUOT,		EDQUOT		},
-	{ NFSERR_STALE,		ESTALE		},
-#ifdef EWFLUSH
-	{ NFSERR_WFLUSH,	EWFLUSH		},
-#endif
-	{ -1,			EIO		}
-};
+static int
+nfs3_xdr_writeres(struct rpc_rqst *req, u32 *p, struct nfs_writeres *res)
+{
+	int	status;
 
+	status = ntohl(*p++);
+	p = xdr_decode_wcc_data(p, res->fattr);
+
+	if (status != 0)
+		return -nfs_stat_to_errno(status);
+
+	res->count = ntohl(*p++);
+	res->verf->committed = (enum nfs3_stable_how)ntohl(*p++);
+	res->verf->verifier[0] = *p++;
+	res->verf->verifier[1] = *p++;
+
+	return res->count;
+}
+
+/*
+ * Decode a CREATE response
+ */
 static int
-nfs_stat_to_errno(int stat)
+nfs3_xdr_createres(struct rpc_rqst *req, u32 *p, struct nfs3_diropres *res)
 {
-	int i;
+	int	status;
 
-	for (i = 0; nfs_errtbl[i].stat != -1; i++) {
-		if (nfs_errtbl[i].stat == stat)
-			return nfs_errtbl[i].errno;
+	status = ntohl(*p++);
+	if (status == 0) {
+		if (*p++) {
+			if (!(p = xdr_decode_fhandle(p, res->fh)))
+				return -errno_NFSERR_IO;
+			p = xdr_decode_post_op_attr(p, res->fattr);
+		} else {
+			memset(res->fh, 0, sizeof(*res->fh));
+			/* Do decode post_op_attr but set it to NULL */
+			p = xdr_decode_post_op_attr(p, res->fattr);
+			res->fattr->valid = 0;
+		}
+	} else {
+		status = -nfs_stat_to_errno(status);
 	}
-	printk("nfs_stat_to_errno: bad nfs status return value: %d\n", stat);
-	return nfs_errtbl[i].errno;
+	p = xdr_decode_wcc_data(p, res->dir_attr);
+	return status;
 }
 
-#ifndef MAX
-# define MAX(a, b)	(((a) > (b))? (a) : (b))
-#endif
+/*
+ * Decode RENAME reply
+ */
+static int
+nfs3_xdr_renameres(struct rpc_rqst *req, u32 *p, struct nfs3_renameres *res)
+{
+	int	status;
 
-#define PROC(proc, argtype, restype)	\
-    { "nfs_" #proc,					\
-      (kxdrproc_t) nfs_xdr_##argtype,			\
-      (kxdrproc_t) nfs_xdr_##restype,			\
-      MAX(NFS_##argtype##_sz,NFS_##restype##_sz) << 2	\
-    }
+	if ((status = ntohl(*p++)) != 0)
+		status = -nfs_stat_to_errno(status);
+	p = xdr_decode_wcc_data(p, res->fromattr);
+	p = xdr_decode_wcc_data(p, res->toattr);
+	return status;
+}
 
-static struct rpc_procinfo	nfs_procedures[18] = {
-    PROC(null,		enc_void,	dec_void),
-    PROC(getattr,	fhandle,	attrstat),
-    PROC(setattr,	sattrargs,	attrstat),
-    PROC(root,		enc_void,	dec_void),
-    PROC(lookup,	diropargs,	diropres),
-    PROC(readlink,	fhandle,	readlinkres),
-    PROC(read,		readargs,	readres),
-    PROC(writecache,	enc_void,	dec_void),
-    PROC(write,		writeargs,	attrstat),
-    PROC(create,	createargs,	diropres),
-    PROC(remove,	diropargs,	stat),
-    PROC(rename,	renameargs,	stat),
-    PROC(link,		linkargs,	stat),
-    PROC(symlink,	symlinkargs,	stat),
-    PROC(mkdir,		createargs,	diropres),
-    PROC(rmdir,		diropargs,	stat),
-    PROC(readdir,	readdirargs,	readdirres),
-    PROC(statfs,	fhandle,	statfsres),
-};
+/*
+ * Decode LINK reply
+ */
+static int
+nfs3_xdr_linkres(struct rpc_rqst *req, u32 *p, struct nfs3_linkres *res)
+{
+	int	status;
 
-static struct rpc_version	nfs_version2 = {
-	2,
-	sizeof(nfs_procedures)/sizeof(nfs_procedures[0]),
-	nfs_procedures
-};
+	if ((status = ntohl(*p++)) != 0)
+		status = -nfs_stat_to_errno(status);
+	p = xdr_decode_post_op_attr(p, res->fattr);
+	p = xdr_decode_wcc_data(p, res->dir_attr);
+	return status;
+}
 
-static struct rpc_version *	nfs_version[] = {
-	NULL,
-	NULL,
-	&nfs_version2
-};
+/*
+ * Decode FSSTAT reply
+ */
+static int
+nfs3_xdr_fsstatres(struct rpc_rqst *req, u32 *p, struct nfs_fsinfo *res)
+{
+	struct nfs_fattr dummy;
+	int		status;
 
-struct rpc_program	nfs_program = {
-	"nfs",
-	NFS_PROGRAM,
-	sizeof(nfs_version) / sizeof(nfs_version[0]),
-	nfs_version,
-	&nfs_rpcstat,
-};
+	status = ntohl(*p++);
+
+	p = xdr_decode_post_op_attr(p, &dummy);
+	if (status != 0)
+		return -nfs_stat_to_errno(status);
 
+	p = xdr_decode_hyper(p, &res->tbytes);
+	p = xdr_decode_hyper(p, &res->fbytes);
+	p = xdr_decode_hyper(p, &res->abytes);
+	p = xdr_decode_hyper(p, &res->tfiles);
+	p = xdr_decode_hyper(p, &res->ffiles);
+	p = xdr_decode_hyper(p, &res->afiles);
+
+	/* ignore invarsec */
+	return 0;
+}
+
 /*
- * RPC stats support
+ * Decode FSINFO reply
  */
 static int
-nfs_get_info(char *buffer, char **start, off_t offset, int length, int dummy)
+nfs3_xdr_fsinfores(struct rpc_rqst *req, u32 *p, struct nfs_fsinfo *res)
 {
-	return rpcstat_get_info(&nfs_rpcstat, buffer, start, offset, length);
+	struct nfs_fattr dummy;
+	int		status;
+
+	status = ntohl(*p++);
+
+	p = xdr_decode_post_op_attr(p, &dummy);
+	if (status != 0)
+		return -nfs_stat_to_errno(status);
+
+	res->rtmax  = ntohl(*p++);
+	res->rtpref = ntohl(*p++);
+	res->rtmult = ntohl(*p++);
+	res->wtmax  = ntohl(*p++);
+	res->wtpref = ntohl(*p++);
+	res->wtmult = ntohl(*p++);
+	res->dtpref = ntohl(*p++);
+	p = xdr_decode_hyper(p, &res->maxfilesize);
+
+	/* ignore time_delta and properties */
+	return 0;
 }
+
+/*
+ * Decode PATHCONF reply
+ */
+static int
+nfs3_xdr_pathconfres(struct rpc_rqst *req, u32 *p, struct nfs_fsinfo *res)
+{
+	struct nfs_fattr dummy;
+	int		status;
+
+	status = ntohl(*p++);
+
+	p = xdr_decode_post_op_attr(p, &dummy);
+	if (status != 0)
+		return -nfs_stat_to_errno(status);
+	res->linkmax = ntohl(*p++);
+	res->namelen = ntohl(*p++);
 
-static struct proc_dir_entry	proc_nfsclnt = {
-	0, 3, "nfs",
-	S_IFREG | S_IRUGO, 1, 0, 0,
-	6, &proc_net_inode_operations,
-	nfs_get_info
+	/* ignore remaining fields */
+	return 0;
+}
+
+/*
+ * Decode COMMIT reply
+ */
+static int
+nfs3_xdr_commitres(struct rpc_rqst *req, u32 *p, struct nfs_writeres *res)
+{
+	int		status;
+
+	status = ntohl(*p++);
+	p = xdr_decode_wcc_data(p, res->fattr);
+	if (status != 0)
+		return -nfs_stat_to_errno(status);
+
+	res->verf->verifier[0] = *p++;
+	res->verf->verifier[1] = *p++;
+	return 0;
+}
+
+#ifndef MAX
+# define MAX(a, b)	(((a) > (b))? (a) : (b))
+#endif
+
+#define PROC(proc, argtype, restype)				\
+    { "nfs3_" #proc,						\
+      (kxdrproc_t) nfs3_xdr_##argtype,				\
+      (kxdrproc_t) nfs3_xdr_##restype,				\
+      MAX(NFS3_##argtype##_sz,NFS3_##restype##_sz) << 2,	\
+      0							\
+    }
+
+static struct rpc_procinfo	nfs3_procedures[22] = {
+  PROC(null,		enc_void,	dec_void),
+  PROC(getattr,		fhandle,	attrstat),
+  PROC(setattr, 	sattrargs,	wccstat),
+  PROC(lookup,		diropargs,	lookupres),
+  PROC(access,		accessargs,	accessres),
+  PROC(readlink,	readlinkargs,	readlinkres),
+  PROC(read,		readargs,	readres),
+  PROC(write,		writeargs,	writeres),
+  PROC(create,		createargs,	createres),
+  PROC(mkdir,		mkdirargs,	createres),
+  PROC(symlink,		symlinkargs,	createres),
+  PROC(mknod,		mknodargs,	createres),
+  PROC(remove,		diropargs,	wccstat),
+  PROC(rmdir,		diropargs,	wccstat),
+  PROC(rename,		renameargs,	renameres),
+  PROC(link,		linkargs,	linkres),
+  PROC(readdir,		readdirargs,	readdirres),
+  PROC(readdirplus,	readdirargs,	readdirres),
+  PROC(fsstat,		fhandle,	fsstatres),
+  PROC(fsinfo,  	fhandle,	fsinfores),
+  PROC(pathconf,	fhandle,	pathconfres),
+  PROC(commit,		commitargs,	commitres),
 };
 
-struct rpc_stat			nfs_rpcstat = {
-	NULL,			/* next */
-	&proc_nfsclnt,		/* /proc/net directory entry */
-	&nfs_program,		/* RPC program */
+struct rpc_version		nfs_version3 = {
+	3,
+	sizeof(nfs3_procedures)/sizeof(nfs3_procedures[0]),
+	nfs3_procedures
 };
+
Index: oldkernel/linux/fs/nfs/nfsroot.c
diff -u linux/fs/nfs/nfsroot.c:1.1.1.1 linux/fs/nfs/nfsroot.c:1.2
--- linux/fs/nfs/nfsroot.c:1.1.1.1	Wed May 31 12:33:48 2000
+++ linux/fs/nfs/nfsroot.c	Fri Jul  7 15:36:46 2000
@@ -61,6 +61,9 @@
  *	Martin Mares	:	Use root_server_addr appropriately during setup.
  *	Martin Mares	:	Rewrote parameter parsing, now hopefully giving
  *				correct overriding.
+ *	Trond Myklebust :	Add in preliminary support for NFSv3 and TCP.
+ *				Fix bug in root_nfs_addr(). nfs_data.namlen
+ *				is NOT for the length of the hostname.
  */
 
 #include <linux/types.h>
@@ -70,7 +73,8 @@
 #include <linux/fs.h>
 #include <linux/init.h>
 #include <linux/sunrpc/clnt.h>
-#include <linux/nfs.h>
+#include <linux/nfs2.h>
+#include <linux/nfs3.h>
 #include <linux/nfs_fs.h>
 #include <linux/nfs_mount.h>
 #include <linux/in.h>
@@ -85,6 +89,7 @@
 
 /* Default path we try to mount. "%s" gets replaced by our IP address */
 #define NFS_ROOT		"/tftpboot/%s"
+#define NFS_PORT		NFS2_PORT
 
 /* Parameters passed from the kernel command line */
 static char nfs_root_name[256] __initdata = "";
@@ -93,7 +98,7 @@
 static __u32 servaddr __initdata = 0;
 
 /* Name of directory to mount */
-static char nfs_path[NFS_MAXPATHLEN] __initdata = { 0, };
+static char nfs_path[PATH_MAX] __initdata = { 0, };
 
 /* NFS-related data */
 static struct nfs_mount_data nfs_data __initdata = { 0, };/* NFS mount info */
@@ -145,6 +150,14 @@
 	{ "nocto",	~NFS_MOUNT_NOCTO,	NFS_MOUNT_NOCTO },
 	{ "ac",		~NFS_MOUNT_NOAC,	0 },
 	{ "noac",	~NFS_MOUNT_NOAC,	NFS_MOUNT_NOAC },
+	{ "lock",	~NFS_MOUNT_NONLM,	0 },
+	{ "nolock",	~NFS_MOUNT_NONLM,	NFS_MOUNT_NONLM },
+#ifdef CONFIG_NFS_V3
+	{ "v2",		~NFS_MOUNT_VER3,	0 },
+	{ "v3",		~NFS_MOUNT_VER3,	NFS_MOUNT_VER3 },
+#endif
+	{ "udp",	~NFS_MOUNT_TCP,		0 },
+	{ "tcp",	~NFS_MOUNT_TCP,		NFS_MOUNT_TCP },
 	{ NULL,		0,			0 }
 };
 
@@ -211,8 +224,8 @@
 		}
 	}
 	if (name[0] && strcmp(name, "default")) {
-		strncpy(buf, name, NFS_MAXPATHLEN-1);
-		buf[NFS_MAXPATHLEN-1] = 0;
+		strncpy(buf, name, PATH_MAX-1);
+		buf[PATH_MAX-1] = 0;
 	}
 }
 
@@ -222,17 +235,19 @@
  */
 __initfunc(static int root_nfs_name(char *name))
 {
-	char buf[NFS_MAXPATHLEN];
+	char buf[PATH_MAX];
 	char *cp;
 
 	/* Set some default values */
 	memset(&nfs_data, 0, sizeof(nfs_data));
 	nfs_port          = -1;
 	nfs_data.version  = NFS_MOUNT_VERSION;
-	nfs_data.flags    = NFS_MOUNT_NONLM;	/* No lockd in nfs root yet */
-	nfs_data.rsize    = NFS_DEF_FILE_IO_BUFFER_SIZE;
-	nfs_data.wsize    = NFS_DEF_FILE_IO_BUFFER_SIZE;
-	nfs_data.bsize	  = 0;
+	/*
+	 *  dhiggen: nobody has yet demonstrated a convincing need for NFS root
+	 *  locking, so I am reverting to automatic lockd start and disabling
+	 *  NLM locking on an NFS root.
+	 */
+	nfs_data.flags    = NFS_MOUNT_NONLM;
 	nfs_data.timeo    = 7;
 	nfs_data.retrans  = 3;
 	nfs_data.acregmin = 3;
@@ -248,7 +263,7 @@
 	root_nfs_parse(name, buf);
 
 	cp = system_utsname.nodename;
-	if (strlen(buf) + strlen(cp) > NFS_MAXPATHLEN) {
+	if (strlen(buf) + strlen(cp) > PATH_MAX) {
 		printk(KERN_ERR "Root-NFS: Pathname for remote directory too long.\n");
 		return -1;
 	}
@@ -269,7 +284,6 @@
 	}
 
 	strncpy(nfs_data.hostname, in_ntoa(servaddr), sizeof(nfs_data.hostname)-1);
-	nfs_data.namlen = strlen(nfs_data.hostname);
 	return 0;
 }
 
@@ -356,14 +370,14 @@
 /*
  *  Query server portmapper for the port of a daemon program.
  */
-__initfunc(static int root_nfs_getport(int program, int version))
+__initfunc(static int root_nfs_getport(int program, int version, int proto))
 {
 	struct sockaddr_in sin;
 
 	printk(KERN_NOTICE "Looking up port of RPC %d/%d on %s\n",
 		program, version, in_ntoa(servaddr));
 	set_sockaddr(&sin, servaddr, 0);
-	return rpc_getport_external(&sin, program, version, IPPROTO_UDP);
+	return rpc_getport_external(&sin, program, version, proto);
 }
 
 
@@ -375,22 +389,39 @@
 __initfunc(static int root_nfs_ports(void))
 {
 	int port;
+	int nfsd_ver, mountd_ver;
+	int nfsd_port, mountd_port;
+	int proto;
+
+	if (nfs_data.flags & NFS_MOUNT_VER3) {
+		nfsd_ver = NFS3_VERSION;
+		mountd_ver = NFS_MNT3_VERSION;
+		nfsd_port = NFS_PORT;
+		mountd_port = NFS_MNT_PORT;
+	} else {
+		nfsd_ver = NFS2_VERSION;
+		mountd_ver = NFS_MNT_VERSION;
+		nfsd_port = NFS_PORT;
+		mountd_port = NFS_MNT_PORT;
+	}
+
+	proto = (nfs_data.flags & NFS_MOUNT_TCP) ? IPPROTO_TCP : IPPROTO_UDP;
 
 	if (nfs_port < 0) {
-		if ((port = root_nfs_getport(NFS_PROGRAM, NFS_VERSION)) < 0) {
+		if ((port = root_nfs_getport(NFS_PROGRAM, nfsd_ver, proto)) < 0) {
 			printk(KERN_ERR "Root-NFS: Unable to get nfsd port "
 					"number from server, using default\n");
-			port = NFS_PORT;
+			port = nfsd_port;
 		}
 		nfs_port = htons(port);
 		dprintk("Root-NFS: Portmapper on server returned %d "
 			"as nfsd port\n", port);
 	}
 
-	if ((port = root_nfs_getport(NFS_MNT_PROGRAM, NFS_MNT_VERSION)) < 0) {
+	if ((port = root_nfs_getport(NFS_MNT_PROGRAM, mountd_ver, proto)) < 0) {
 		printk(KERN_ERR "Root-NFS: Unable to get mountd port "
 				"number from server, using default\n");
-		port = NFS_MNT_PORT;
+		port = mountd_port;
 	}
 	mount_port = htons(port);
 	dprintk("Root-NFS: mountd port is %d\n", port);
@@ -409,7 +440,10 @@
 	int status;
 
 	set_sockaddr(&sin, servaddr, mount_port);
-	status = nfs_mount(&sin, nfs_path, &nfs_data.root);
+	if (nfs_data.flags & NFS_MOUNT_VER3)
+		status = nfs3_mount(&sin, nfs_path, &nfs_data.root);
+	else
+		status = nfs_mount(&sin, nfs_path, &nfs_data.root);
 	if (status < 0)
 		printk(KERN_ERR "Root-NFS: Server returned error %d "
 				"while mounting %s\n", status, nfs_path);
Index: oldkernel/linux/fs/nfs/proc.c
diff -u linux/fs/nfs/proc.c:1.2 linux/fs/nfs/proc.c:1.3
--- linux/fs/nfs/proc.c:1.2	Thu Jun  1 15:03:08 2000
+++ linux/fs/nfs/proc.c	Fri Jul  7 15:36:46 2000
@@ -13,10 +13,6 @@
  *  Note: Error returns are optimized for NFS_OK, which isn't translated via
  *  nfs_stat_to_errno(), but happens to be already the right return code.
  *
- *  FixMe: We ought to define a sensible small max size for
- *  things like getattr that are tiny packets and use the
- *  old get_free_page stuff with it.
- *
  *  Also, the code currently doesn't check the size of the packet, when
  *  it decodes the packet.
  *
@@ -25,211 +21,317 @@
  *  Completely rewritten to support the new RPC call interface;
  *  rewrote and moved the entire XDR stuff to xdr.c
  *  --Olaf Kirch June 1996
+ *
+ *  The code below initializes all auto variables explicitly, otherwise
+ *  it will fail to work as a module (gcc generates a memset call for an
+ *  incomplete struct).
  */
 
-#define NFS_NEED_XDR_TYPES
+#define NFS_NEED_NFS2_XDR_TYPES
 
+#include <linux/types.h>
 #include <linux/param.h>
+#include <linux/malloc.h>
 #include <linux/sched.h>
 #include <linux/mm.h>
-#include <linux/malloc.h>
 #include <linux/utsname.h>
 #include <linux/errno.h>
 #include <linux/string.h>
 #include <linux/in.h>
 #include <linux/pagemap.h>
 #include <linux/sunrpc/clnt.h>
+#include <linux/nfs.h>
+#include <linux/nfs2.h>
 #include <linux/nfs_fs.h>
 
 #include <asm/segment.h>
+
+
+
+/*
+ * Typing short-hands
+ */
+typedef struct nfs_fattr	fattr;
+typedef struct qstr		qstr;
 
-#ifdef NFS_DEBUG
-# define NFSDBG_FACILITY	NFSDBG_PROC
-#endif
+#define NFSDBG_FACILITY		NFSDBG_PROC
 
 
 /*
+ * Bare-bones access to getattr: this is for nfs_read_super.
+ */
+static int
+nfs_proc_get_root(struct nfs_server *server, struct nfs_fh *fhandle,
+			fattr *fattr)
+{
+	int		status;
+
+	dprintk("NFS call  getroot\n");
+	fattr->valid = 0;
+	status = rpc_call(server->client, NFSPROC_GETATTR, fhandle, fattr, 0);
+	dprintk("NFS reply getroot\n");
+	return status;
+}
+
+/*
  * One function for each procedure in the NFS protocol.
  */
-int
-nfs_proc_getattr(struct nfs_server *server, struct nfs_fh *fhandle,
-			struct nfs_fattr *fattr)
+static int
+nfs_proc_getattr(struct dentry *dentry, fattr *fattr)
 {
 	int	status;
 
 	dprintk("NFS call  getattr\n");
-	status = rpc_call(server->client, NFSPROC_GETATTR, fhandle, fattr, 0);
+	fattr->valid = 0;
+	status = rpc_call(NFS_CLIENT(dentry->d_inode), NFSPROC_GETATTR,
+				NFS_FH(dentry), fattr, 0);
 	dprintk("NFS reply getattr\n");
 	return status;
 }
 
-int
-nfs_proc_setattr(struct nfs_server *server, struct nfs_fh *fhandle,
-			struct nfs_sattr *sattr, struct nfs_fattr *fattr)
+static int
+nfs_proc_setattr(struct dentry *dentry, fattr *fattr,
+				struct iattr *sattr)
 {
-	struct nfs_sattrargs	arg = { fhandle, sattr };
+	struct nfs_sattrargs	arg = { NFS_FH(dentry), sattr };
 	int	status;
 
 	dprintk("NFS call  setattr\n");
-	status = rpc_call(server->client, NFSPROC_SETATTR, &arg, fattr, 0);
+	fattr->valid = 0;
+	status = rpc_call(NFS_CLIENT(dentry->d_inode), NFSPROC_SETATTR, &arg, fattr, 0);
 	dprintk("NFS reply setattr\n");
 	return status;
 }
 
-int
-nfs_proc_lookup(struct nfs_server *server, struct nfs_fh *dir, const char *name,
-		    struct nfs_fh *fhandle, struct nfs_fattr *fattr)
+static int
+nfs_proc_lookup(struct dentry *dir, fattr *dir_attr, qstr *name,
+		struct nfs_fh *fhandle, fattr *fattr)
 {
-	struct nfs_diropargs	arg = { dir, name };
+	struct nfs_diropargs	arg = { NFS_FH(dir), name->name, name->len };
 	struct nfs_diropok	res = { fhandle, fattr };
 	int			status;
 
-	dprintk("NFS call  lookup %s\n", name);
-	status = rpc_call(server->client, NFSPROC_LOOKUP, &arg, &res, 0);
+	dprintk("NFS call  lookup %s\n", name->name);
+	dir_attr->valid = 0;
+	fattr->valid = 0;
+	status = rpc_call(NFS_CLIENT(dir->d_inode), NFSPROC_LOOKUP, &arg, &res, 0);
 	dprintk("NFS reply lookup: %d\n", status);
 	return status;
 }
 
-int
-nfs_proc_readlink(struct nfs_server *server, struct nfs_fh *fhandle,
-			void **p0, char **string, unsigned int *len,
-			unsigned int maxlen)
+static int
+nfs_proc_readlink(struct dentry *dentry, fattr *fattr,
+			void *buffer, unsigned int bufsiz)
 {
-	struct nfs_readlinkres	res = { string, len, maxlen, NULL };
+	struct nfs_readlinkargs	args = { NFS_FH(dentry), buffer, bufsiz };
+	struct nfs_readlinkres	res = { buffer, bufsiz };
 	int			status;
 
 	dprintk("NFS call  readlink\n");
-	status = rpc_call(server->client, NFSPROC_READLINK, fhandle, &res, 0);
+	fattr->valid = 0;
+	status = rpc_call(NFS_CLIENT(dentry->d_inode), NFSPROC_READLINK,
+					&args, &res, 0);
 	dprintk("NFS reply readlink: %d\n", status);
-	if (!status)
-		*p0 = res.buffer;
-	else if (res.buffer)
-		kfree(res.buffer);
 	return status;
 }
 
-int
-nfs_proc_read(struct nfs_server *server, struct nfs_fh *fhandle, int swap,
-	      loff_t offset, unsigned int count,
-	      void *buffer, struct nfs_fattr *fattr)
-{
-	struct nfs_readargs	arg = { fhandle, offset, count, buffer };
-	struct nfs_readres	res = { fattr, count };
-	int			status;
+static int
+nfs_proc_read(struct dentry *dentry, fattr *fattr,
+	      struct rpc_cred *cred, int flags,
+	      unsigned long offset, unsigned int count,
+	      void *buffer, int *eofp)
+{
+	struct nfs_readargs	arg = { NFS_FH(dentry), offset, count, 1,
+				       {{ buffer, count }, {0,0}, {0,0}, {0,0},
+					{0,0}, {0,0}, {0,0}, {0,0}} };
+	struct nfs_readres	res = { fattr, count, 0};
+	struct rpc_message	msg = { NFSPROC_READ, &arg, &res, cred };
+	int			status;
+
+	dprintk("NFS call  read %d @ %ld\n", count, offset);
+	fattr->valid = 0;
+	status = rpc_call_sync(NFS_CLIENT(dentry->d_inode), &msg, flags);
 
-	dprintk("NFS call  read %d @ %Ld\n", count, offset);
-	status = rpc_call(server->client, NFSPROC_READ, &arg, &res,
-			swap? NFS_RPC_SWAPFLAGS : 0);
 	dprintk("NFS reply read: %d\n", status);
+	*eofp = res.eof;
 	return status;
 }
 
-int
-nfs_proc_write(struct nfs_server *server, struct nfs_fh *fhandle, int swap,
-	       loff_t offset, unsigned int count,
-	       const void *buffer, struct nfs_fattr *fattr)
-{
-	struct nfs_writeargs	arg = { fhandle, offset, count, buffer };
-	int			status;
+static int
+nfs_proc_write(struct dentry *dentry, fattr *fattr,
+	       struct rpc_cred *cred, int how,
+	       unsigned long offset, unsigned int count,
+	       void *buffer, struct nfs_writeverf *verf)
+{
+	struct nfs_writeargs	arg = {NFS_FH(dentry), offset, count,
+					NFS_FILE_SYNC, 1,
+					{{buffer, count}, {0,0}, {0,0}, {0,0},
+					 {0,0}, {0,0}, {0,0}, {0,0}}};
+	struct nfs_writeres     res = {fattr, verf, count};
+	struct rpc_message	msg = { NFSPROC_WRITE, &arg, &res, cred };
+	int			status, flags = 0;
+
+	dprintk("NFS call  write %d @ %ld\n", count, offset);
+	fattr->valid = 0;
+	if (how & NFS_RW_SWAP)
+		flags |= NFS_RPC_SWAPFLAGS;
+	status = rpc_call_sync(NFS_CLIENT(dentry->d_inode), &msg, flags);
 
-	dprintk("NFS call  write %d @ %Ld\n", count, offset);
-	status = rpc_call(server->client, NFSPROC_WRITE, &arg, fattr,
-			swap? (RPC_TASK_SWAPPER|RPC_TASK_ROOTCREDS) : 0);
-	dprintk("NFS reply read: %d\n", status);
+	dprintk("NFS reply write: %d\n", status);
+	verf->committed = NFS_FILE_SYNC;      /* NFSv2 always syncs data */
 	return status < 0? status : count;
 }
 
-int
-nfs_proc_create(struct nfs_server *server, struct nfs_fh *dir,
-			const char *name, struct nfs_sattr *sattr,
-			struct nfs_fh *fhandle, struct nfs_fattr *fattr)
+static int
+nfs_proc_create(struct dentry *dir, fattr *dir_attr,
+		qstr *name, struct iattr *sattr, int flags,
+		struct nfs_fh *fhandle, fattr *fattr)
 {
-	struct nfs_createargs	arg = { dir, name, sattr };
+	struct nfs_createargs	arg = { NFS_FH(dir), name->name,
+					name->len, sattr };
 	struct nfs_diropok	res = { fhandle, fattr };
 	int			status;
 
-	dprintk("NFS call  create %s\n", name);
-	status = rpc_call(server->client, NFSPROC_CREATE, &arg, &res, 0);
+	dir_attr->valid = 0;
+	fattr->valid = 0;
+	dprintk("NFS call  create %s\n", name->name);
+	status = rpc_call(NFS_CLIENT(dir->d_inode), NFSPROC_CREATE, &arg, &res, 0);
 	dprintk("NFS reply create: %d\n", status);
 	return status;
 }
 
-int
-nfs_proc_remove(struct nfs_server *server, struct nfs_fh *dir, const char *name)
+/*
+ * In NFSv2, mknod is grafted onto the create call.
+ */
+static int
+nfs_proc_mknod(struct dentry *dir, fattr *dir_attr,
+			qstr *name, struct iattr *sattr, dev_t rdev,
+			struct nfs_fh *fhandle, fattr *fattr)
 {
-	struct nfs_diropargs	arg = { dir, name };
-	int			status;
+	struct nfs_createargs	arg = { NFS_FH(dir), name->name,
+						     name->len, sattr };
+	struct nfs_diropok	res = { fhandle, fattr };
+	int			status, mode;
+
+	dprintk("NFS call  mknod %s\n", name->name);
 
-	dprintk("NFS call  remove %s\n", name);
-	status = rpc_call(server->client, NFSPROC_REMOVE, &arg, NULL, 0);
+	mode = sattr->ia_mode;
+	if (S_ISFIFO(mode)) {
+		sattr->ia_mode = (mode & ~S_IFMT) | S_IFCHR;
+		sattr->ia_valid &= ~ATTR_SIZE;
+	} else if (S_ISCHR(rdev) || S_ISBLK(rdev)) {
+		sattr->ia_valid |= ATTR_SIZE;
+		sattr->ia_size   = rdev;	/* get out your barf bag */
+	}
+
+	dir_attr->valid = 0;
+	fattr->valid = 0;
+	status = rpc_call(NFS_CLIENT(dir->d_inode), NFSPROC_CREATE, &arg, &res, 0);
+
+	if (status == -EINVAL && S_ISFIFO(mode)) {
+		sattr->ia_mode = mode;
+		dir_attr->valid = 0;
+		fattr->valid = 0;
+		status = rpc_call(NFS_CLIENT(dir->d_inode), NFSPROC_CREATE, &arg, &res, 0);
+	}
+	dprintk("NFS reply mknod: %d\n", status);
+	return status;
+}
+  
+static int
+nfs_proc_remove(struct dentry *dir, fattr *dir_attr,
+		qstr *name, struct rpc_cred *cred)
+{
+	struct nfs_diropargs	arg = { NFS_FH(dir), name->name, name->len };
+	struct rpc_message	msg = { NFSPROC_REMOVE, &arg, NULL, cred };
+	int			status;
+
+	dir_attr->valid = 0;
+	dprintk("NFS call  remove %s\n", name->name);
+	status = rpc_call_sync(NFS_CLIENT(dir->d_inode), &msg, 0);
+
 	dprintk("NFS reply remove: %d\n", status);
 	return status;
 }
 
-int
-nfs_proc_rename(struct nfs_server *server,
-		struct nfs_fh *old_dir, const char *old_name,
-		struct nfs_fh *new_dir, const char *new_name)
-{
-	struct nfs_renameargs	arg = { old_dir, old_name, new_dir, new_name };
+static int
+nfs_proc_rename(struct dentry *old_dir, fattr *old_attr, qstr *old_name,
+		struct dentry *new_dir, fattr *new_attr, qstr *new_name)
+{
+	struct nfs_renameargs	arg = { NFS_FH(old_dir), old_name->name,
+					old_name->len,
+					NFS_FH(new_dir), new_name->name,
+					new_name->len};
 	int			status;
 
-	dprintk("NFS call  rename %s -> %s\n", old_name, new_name);
-	status = rpc_call(server->client, NFSPROC_RENAME, &arg, NULL, 0);
+	dprintk("NFS call  rename %s -> %s\n", old_name->name, new_name->name);
+	old_attr->valid = 0;
+	new_attr->valid = 0;
+	status = rpc_call(NFS_CLIENT(old_dir->d_inode), NFSPROC_RENAME, &arg, NULL, 0);
 	dprintk("NFS reply rename: %d\n", status);
 	return status;
 }
 
-int
-nfs_proc_link(struct nfs_server *server, struct nfs_fh *fhandle,
-			struct nfs_fh *dir, const char *name)
-{
-	struct nfs_linkargs	arg = { fhandle, dir, name };
+static int
+nfs_proc_link(struct dentry *dentry, fattr *attr,
+	      struct dentry *dir, fattr *dir_attr, qstr *name)
+{
+	struct nfs_linkargs	arg = { NFS_FH(dentry), NFS_FH(dir),
+					name->name, name->len };
 	int			status;
 
-	dprintk("NFS call  link %s\n", name);
-	status = rpc_call(server->client, NFSPROC_LINK, &arg, NULL, 0);
+	dprintk("NFS call  link %s\n", name->name);
+	dir_attr->valid = 0;
+	attr->valid = 0;
+	status = rpc_call(NFS_CLIENT(dentry->d_inode), NFSPROC_LINK, &arg, NULL, 0);
 	dprintk("NFS reply link: %d\n", status);
 	return status;
 }
 
-int
-nfs_proc_symlink(struct nfs_server *server, struct nfs_fh *dir,
-			const char *name, const char *path,
-			struct nfs_sattr *sattr)
-{
-	struct nfs_symlinkargs	arg = { dir, name, path, sattr };
+static int
+nfs_proc_symlink(struct dentry *dir, fattr *dir_attr, qstr *name,
+		 qstr *path, struct iattr *sattr,
+		 struct nfs_fh *sym_fh, fattr *sym_attr)
+{
+	struct nfs_symlinkargs	arg = { NFS_FH(dir), name->name, name->len,
+					path->name, path->len, sattr };
 	int			status;
 
-	dprintk("NFS call  symlink %s -> %s\n", name, path);
-	status = rpc_call(server->client, NFSPROC_SYMLINK, &arg, NULL, 0);
+	dprintk("NFS call  symlink %s -> %s\n", name->name, path->name);
+	dir_attr->valid = 0;
+	sym_attr->valid = 0;
+	status = rpc_call(NFS_CLIENT(dir->d_inode), NFSPROC_SYMLINK, &arg, NULL, 0);
 	dprintk("NFS reply symlink: %d\n", status);
 	return status;
 }
 
-int
-nfs_proc_mkdir(struct nfs_server *server, struct nfs_fh *dir,
-			const char *name, struct nfs_sattr *sattr,
-			struct nfs_fh *fhandle, struct nfs_fattr *fattr)
+static int
+nfs_proc_mkdir(struct dentry *dir, fattr *dir_attr, qstr *name,
+	       struct iattr *sattr,
+	       struct nfs_fh *fhandle, fattr *fattr)
 {
-	struct nfs_createargs	arg = { dir, name, sattr };
+	struct nfs_createargs	arg = { NFS_FH(dir), name->name, name->len,
+					sattr };
 	struct nfs_diropok	res = { fhandle, fattr };
 	int			status;
 
-	dprintk("NFS call  mkdir %s\n", name);
-	status = rpc_call(server->client, NFSPROC_MKDIR, &arg, &res, 0);
+	dprintk("NFS call  mkdir %s\n", name->name);
+	dir_attr->valid = 0;
+	fattr->valid = 0;
+	status = rpc_call(NFS_CLIENT(dir->d_inode), NFSPROC_MKDIR, &arg, &res, 0);
 	dprintk("NFS reply mkdir: %d\n", status);
 	return status;
 }
 
-int
-nfs_proc_rmdir(struct nfs_server *server, struct nfs_fh *dir, const char *name)
+static int
+nfs_proc_rmdir(struct dentry *dir, fattr *dir_attr, qstr *name)
 {
-	struct nfs_diropargs	arg = { dir, name };
+	struct nfs_diropargs	arg = { NFS_FH(dir), name->name, name->len };
 	int			status;
 
-	dprintk("NFS call  rmdir %s\n", name);
-	status = rpc_call(server->client, NFSPROC_RMDIR, &arg, NULL, 0);
+	dprintk("NFS call  rmdir %s\n", name->name);
+	dir_attr->valid = 0;
+	status = rpc_call(NFS_CLIENT(dir->d_inode), NFSPROC_RMDIR, &arg, NULL, 0);
 	dprintk("NFS reply rmdir: %d\n", status);
 	return status;
 }
@@ -237,66 +339,73 @@
 /*
  * The READDIR implementation is somewhat hackish - we pass a temporary
  * buffer to the encode function, which installs it in the receive
- * iovec. The dirent buffer itself is passed in the result struct.
+ * the receive iovec. The decode function just parses the reply to make
+ * sure it is syntactically correct; the entries itself are decoded
+ * from nfs_readdir by calling the decode_entry function directly.
  */
-int
-nfs_proc_readdir(struct nfs_server *server, struct nfs_fh *fhandle,
-			u32 cookie, unsigned int size, __u32 *entry)
+static int
+nfs_proc_readdir(struct dentry *dir, fattr *dir_attr,
+		 struct rpc_cred *cred,
+		 __u64 cookie, void *entry, unsigned int size, int plus)
 {
 	struct nfs_readdirargs	arg;
 	struct nfs_readdirres	res;
-	void *			buffer;
-	unsigned int		buf_size = PAGE_SIZE;
+	struct rpc_message	msg = { NFSPROC_READDIR, &arg, &res, cred };
+	struct nfs_server       *server = NFS_DSERVER(dir);
 	int			status;
 
-	/* First get a temp buffer for the readdir reply */
-	/* N.B. does this really need to be cleared? */
-	status = -ENOMEM;
-	buffer = (void *) get_free_page(GFP_KERNEL);
-	if (!buffer)
-		goto out;
-
-	/*
-	 * Calculate the effective size the buffer.  To make sure
-	 * that the returned data will fit into the user's buffer,
-	 * we decrease the buffer size as necessary.
-	 *
-	 * Note: NFS returns three __u32 values for each entry,
-	 * and we assume that the data is packed into the user
-	 * buffer with the same efficiency. 
-	 */
-	if (size < buf_size)
-		buf_size = size;
-	if (server->rsize < buf_size)
-		buf_size = server->rsize;
-#if 0
-printk("nfs_proc_readdir: user size=%d, rsize=%d, buf_size=%d\n",
-size, server->rsize, buf_size);
-#endif
+	if (server->rsize < size)
+		size = server->rsize;
 
-	arg.fh = fhandle;
+	dir_attr->valid = 0;
+	arg.fh = NFS_FH(dir);
 	arg.cookie = cookie;
-	arg.buffer = buffer;
-	arg.bufsiz = buf_size;
+	arg.buffer = entry;
+	arg.bufsiz = size;
 	res.buffer = entry;
 	res.bufsiz = size;
 
-	dprintk("NFS call  readdir %d\n", cookie);
-	status = rpc_call(server->client, NFSPROC_READDIR, &arg, &res, 0);
+	dir_attr->valid = 0;
+	dprintk("NFS call  readdir %d\n", (unsigned int)cookie);
+	status = rpc_call_sync(NFS_CLIENT(dir->d_inode), &msg, 0);
+
 	dprintk("NFS reply readdir: %d\n", status);
-	free_page((unsigned long) buffer);
-out:
 	return status;
 }
 
-int
+static int
 nfs_proc_statfs(struct nfs_server *server, struct nfs_fh *fhandle,
 			struct nfs_fsinfo *info)
 {
 	int	status;
 
 	dprintk("NFS call  statfs\n");
+	memset((char *)info, 0, sizeof(*info));
 	status = rpc_call(server->client, NFSPROC_STATFS, fhandle, info, 0);
 	dprintk("NFS reply statfs: %d\n", status);
 	return status;
 }
+
+struct nfs_rpc_ops     nfs_v2_clientops = {
+       2,		       /* protocol version */
+       nfs_proc_get_root,
+       nfs_proc_getattr,
+       nfs_proc_setattr,
+       nfs_proc_lookup,
+       NULL,		       /* access */
+       nfs_proc_readlink,
+       nfs_proc_read,
+       nfs_proc_write,
+       NULL,		       /* commit */
+       nfs_proc_create,
+       nfs_proc_remove,
+       nfs_proc_rename,
+       nfs_proc_link,
+       nfs_proc_symlink,
+       nfs_proc_mkdir,
+       nfs_proc_rmdir,
+       nfs_proc_readdir,
+       nfs_proc_mknod,
+       nfs_proc_statfs,
+       nfs_decode_dirent,
+};
Index: oldkernel/linux/fs/nfs/read.c
diff -u linux/fs/nfs/read.c:1.2 linux/fs/nfs/read.c:1.3
--- linux/fs/nfs/read.c:1.2	Thu Jun  1 15:03:08 2000
+++ linux/fs/nfs/read.c	Fri Jul  7 15:36:46 2000
@@ -15,7 +15,7 @@
  * within the RPC code when root squashing is suspected.
  */
 
-#define NFS_NEED_XDR_TYPES
+#define NFS_NEED_NFS2_XDR_TYPES
 #include <linux/sched.h>
 #include <linux/kernel.h>
 #include <linux/errno.h>
@@ -24,17 +24,24 @@
 #include <linux/mm.h>
 #include <linux/malloc.h>
 #include <linux/pagemap.h>
+#include <linux/file.h>
 #include <linux/sunrpc/clnt.h>
+#include <linux/nfs.h>
+#include <linux/nfs2.h>
+#include <linux/nfs3.h>
 #include <linux/nfs_fs.h>
 
 #include <asm/segment.h>
 #include <asm/system.h>
+#include <asm/pgtable.h>
 
 #define NFSDBG_FACILITY		NFSDBG_PAGECACHE
 
 struct nfs_rreq {
-	struct inode *		ra_inode;	/* inode from which to read */
-	struct page *		ra_page;	/* page to be read */
+	struct inode		*ra_inode;	/* inode to be read */
+	unsigned int		ra_npages;	/* number of pages to read */
+	struct page		*ra_page[NFS_READ_MAXIOV]; /* pages to read */
+	struct nfs_fh		ra_handle;	/* filehandle */
 	struct nfs_readargs	ra_args;	/* XDR argument struct */
 	struct nfs_readres	ra_res;		/* ... and result struct */
 	struct nfs_fattr	ra_fattr;	/* fattr storage */
@@ -45,20 +52,42 @@
 # define IS_SWAPFILE(inode)	(0)
 #endif
 
+static __inline__ struct nfs_rreq *nfs_rreq_alloc(void)
+{
+	return kmalloc(sizeof(struct nfs_rreq), GFP_KERNEL);
+}
+
+static __inline__ void nfs_rreq_free(struct nfs_rreq *p)
+{
+	kfree(p);
+}
 
 /*
  * Set up the NFS read request struct
  */
 static inline void
-nfs_readreq_setup(struct nfs_rreq *req, struct nfs_fh *fh,
-		  loff_t offset, void *buffer, unsigned int rsize)
+nfs_readreq_setup(struct nfs_rreq *req, struct inode *inode,
+		  struct nfs_fh *fh,
+		  struct page **pages, unsigned int nr)
 {
-	req->ra_args.fh     = fh;
-	req->ra_args.offset = offset;
-	req->ra_args.count  = rsize;
-	req->ra_args.buffer = buffer;
+	int i;
+
+	req->ra_inode	    = inode;
+	req->ra_args.fh	    = &req->ra_handle;
+	req->ra_handle	    = *fh;
+	req->ra_args.offset = page_offset(pages[0]);
+	req->ra_args.count  = nr*PAGE_CACHE_SIZE;
+	req->ra_args.nriov  = nr;
+	req->ra_npages	    = nr;
+	for (i = 0; i < nr; i++) {
+		req->ra_args.iov[i].iov_base = (void *)page_address(pages[i]);
+		req->ra_args.iov[i].iov_len = PAGE_CACHE_SIZE;
+		req->ra_page[i] = pages[i];
+	}
+	req->ra_fattr.valid = 0;
 	req->ra_res.fattr   = &req->ra_fattr;
-	req->ra_res.count   = rsize;
+	req->ra_res.count   = req->ra_args.count;
+	req->ra_res.eof     = 0;
 }
 
 
@@ -66,48 +95,38 @@
  * Read a page synchronously.
  */
 static int
-nfs_readpage_sync(struct dentry *dentry, struct inode *inode, struct page *page)
+nfs_readpage_sync(struct file *file, struct page *page)
 {
-	struct nfs_rreq	rqst;
-	loff_t	offset = pgoff2loff(page->index);
-	char	*buffer = (char *) page_address(page);
-	int	rsize = NFS_SERVER(inode)->rsize;
-	int	result = 0, refresh = 0;
-	int	count = PAGE_SIZE;
-	int	flags = IS_SWAPFILE(inode)? NFS_RPC_SWAPFLAGS : 0;
+	struct dentry	*dentry = file->f_dentry;
+	struct inode	*inode = dentry->d_inode;
+	struct rpc_cred	*cred = nfs_file_cred(file);
+	struct nfs_fattr fattr;
+	unsigned long	offset = page_offset(page);
+	char		*buffer = (char *) page_address(page);
+	int		rsize = NFS_SERVER(inode)->rsize;
+	int		result, refresh = 0;
+	int		count = PAGE_CACHE_SIZE, chunk, eof = 0;
+	int		flags = 0;
+
+	if (IS_SWAPFILE(inode))
+		flags |= NFS_RPC_SWAPFLAGS;
 
 	dprintk("NFS: nfs_readpage_sync(%p)\n", page);
 	clear_bit(PG_error, &page->flags);
 
 	do {
-		if (count < rsize)
-			rsize = count;
+		if ((chunk = rsize) > count)
+			chunk = count;
 
-		dprintk("NFS: nfs_proc_read(%s, (%s/%s), %Ld, %d, %p)\n",
+		dprintk("NFS: nfs_proc_read(%s, (%s/%s), %ld, %d, %p)\n",
 			NFS_SERVER(inode)->hostname,
 			dentry->d_parent->d_name.name, dentry->d_name.name,
-			offset, rsize, buffer);
+			offset, chunk, buffer);
 
-		/* FIXME: NFSv3 could allow 64-bit offsets! ... */
+		result = NFS_CALL(read, inode, (dentry, &fattr, cred, flags,
+						offset, chunk, buffer, &eof));
+		nfs_refresh_inode(inode, &fattr);
 
-		if (offset > 0x7ffffffeULL) {
-		  if (result)
-		  	break;
-		  result = -EOVERFLOW;
-		  goto io_error;
-		}
-		if ((offset + rsize) > 0x7fffffffULL) /* 2G-1 */
-		  rsize = 0x7fffffffULL - offset;
-
-		/* ... END FIXME! */
-
-		/* Set up arguments and perform rpc call */
-		nfs_readreq_setup(&rqst, NFS_FH(dentry), offset,
-				  buffer, rsize);
-
-		result = rpc_call(NFS_CLIENT(inode), NFSPROC_READ,
-					&rqst.ra_args, &rqst.ra_res, flags);
-
 		/*
 		 * Even if we had a partial success we can't mark the page
 		 * cache valid.
@@ -121,24 +140,83 @@
 		count  -= result;
 		offset += result;
 		buffer += result;
-		if (result < rsize)	/* NFSv2ism */
+		if (eof)
 			break;
 	} while (count);
 
 	memset(buffer, 0, count);
+	flush_dcache_page(page_address(page));
 	set_bit(PG_uptodate, &page->flags);
 	result = 0;
 
 io_error:
 	/* Note: we don't refresh if the call returned error */
-	if (refresh && result >= 0)
-		nfs_refresh_inode(inode, &rqst.ra_fattr);
-	/* N.B. Use nfs_unlock_page here? */
-	clear_bit(PG_locked, &page->flags);
-	wake_up(&page->wait);
+	if (result < 0)
+		set_bit(PG_error, &page->flags);
 	return result;
 }
 
+struct page *
+nfs_grab_cache_page(struct inode *inode, unsigned long offset)
+{
+	struct page	*page,
+			**hash;
+	unsigned long	new_addr = 0;
+
+	offset &= PAGE_CACHE_MASK;
+	hash = page_hash(inode, offset);
+	do {
+		page = __find_page(inode, offset, *hash);
+		if (page) {
+			if (new_addr)
+				page_cache_free(new_addr);
+			break;
+		}
+		if (!new_addr) {
+			new_addr = page_cache_alloc();
+			if (new_addr)
+				continue;
+			return NULL;
+		}
+		page = page_cache_entry(new_addr);
+		add_to_page_cache(page, inode, offset, hash);
+		new_addr = 0;
+	} while (!page);
+	while(!nfs_lock_page(page))
+		wait_on_page(page);
+	return page;
+}
+
+/* Page Readahead. We try to allocate and/or lock up to 'nr' empty
+ * pages that are to be read in by the same RPC call.
+ *
+ * FIXME: Allocating pages and handing them down to the nfs_read
+ * routine really should be done by generic_file_read.  */
+static int
+nfs_grab_readahead_pages(struct inode *inode, struct page **pages,
+			 unsigned long offset, int nr)
+{
+	struct page	*page;
+	int		error, count = 0;
+
+	offset &= PAGE_CACHE_MASK;
+	for (; nr; offset += PAGE_CACHE_SIZE, nr--) {
+		if (offset >= inode->i_size)
+			break;
+		page = nfs_grab_cache_page(inode, offset);
+		if (!page)
+			break;
+		error = nfs_wb_page(inode, page);
+		if (error < 0 || PageUptodate(page)) {
+			nfs_unlock_page(page);
+			page_cache_release(page);
+			break;
+		}
+		pages[count++] = page;
+	}
+	return count;
+}
+
 /*
  * This is the callback from RPC telling us whether a reply was
  * received or some error occurred (timeout or socket shutdown).
@@ -147,88 +225,119 @@
 nfs_readpage_result(struct rpc_task *task)
 {
 	struct nfs_rreq	*req = (struct nfs_rreq *) task->tk_calldata;
-	struct page	*page = req->ra_page;
-	unsigned long	address = page_address(page);
-	int		result = task->tk_status;
-	static int	succ = 0, fail = 0;
+	struct inode	*inode = req->ra_inode;
+	struct page	**pages = req->ra_page;
+	int		i, result = task->tk_status;
+	int		count, npages = req->ra_npages;
+
+	dprintk("NFS: %4d received callback for %d pages %lx, result %d\n",
+			task->tk_pid, npages, page_address(*pages), result);
 
-	dprintk("NFS: %4d received callback for page %lx, result %d\n",
-			task->tk_pid, address, result);
+	nfs_refresh_inode(inode, &req->ra_fattr);
 
+	i = 0;
 	if (result >= 0) {
-		result = req->ra_res.count;
-		if (result < PAGE_SIZE) {
-			memset((char *) address + result, 0, PAGE_SIZE - result);
+		count = req->ra_res.count;
+		/* NFSv3 may return less data than requested,
+		 * and have the client issue another request for
+		 * the remaining data but only if the client sets
+		 * a too large rsize.
+		 */
+		if (!req->ra_res.eof && result < npages*PAGE_CACHE_SIZE) {
+			printk(KERN_WARNING
+				"NFS: server sends short reads. "
+				"Expected %lu, got %u. "
+				"Try reducing the value of rsize.\n",
+				PAGE_CACHE_SIZE, result);
 		}
-		nfs_refresh_inode(req->ra_inode, &req->ra_fattr);
-		set_bit(PG_uptodate, &page->flags);
-		succ++;
-	} else {
-		set_bit(PG_error, &page->flags);
-		fail++;
-		dprintk("NFS: %d successful reads, %d failures\n", succ, fail);
+
+		/*
+		 * Refresh before we set PG_uptodate in case of invalidation
+		 */
+		for (; i < npages && count > 0; i++, count -= PAGE_CACHE_SIZE) {
+			struct page *page = pages[i];
+			if (count < PAGE_CACHE_SIZE)
+				memset((char *) page_address(page) + count, 0,
+				       PAGE_CACHE_SIZE - count);
+			set_bit(PG_uptodate, &page->flags);
+		}
 	}
-	/* N.B. Use nfs_unlock_page here? */
-	clear_bit(PG_locked, &page->flags);
-	wake_up(&page->wait);
+	for (; i < npages; i++)
+		set_bit(PG_error, &pages[i]->flags);
 
-	free_page(address);
+	/* N.B. Use nfs_unlock_page here? */
+	for (i = 0; i < npages; i++) {
+		nfs_unlock_page(pages[i]);
+		page_cache_release(pages[i]);
+	}
 
-	rpc_release_task(task);
-	kfree(req);
+	nfs_rreq_free(req);
 }
 
 static inline int
-nfs_readpage_async(struct dentry *dentry, struct inode *inode,
-			struct page *page)
+nfs_readpage_async(struct file *file, struct page *page)
 {
-	unsigned long address = page_address(page);
+	struct dentry	*dentry = file->f_dentry;
+	struct inode	*inode = dentry->d_inode;
+	struct rpc_message msg;
 	struct nfs_rreq	*req;
-	int		result = -1, flags;
-	loff_t	loffset = pgoff2loff(page->index);
+	struct page	*pages[NFS_READ_MAXIOV];
+	int		result = -ENOMEM,
+			i, flags, rpages;
 
 	dprintk("NFS: nfs_readpage_async(%p)\n", page);
 
-	/* FIXME: NFSv3 allows 64-bit offsets.. */
-	if ((loffset + PAGE_SIZE) >= 0x7fffffffULL) {
-	  dprintk("NFS: Async read beyond 2G-1 marker!\n");
-	  return -EOVERFLOW;
-	}
+	/* N.B. Do we need to test? Never called for swapfile inode */
+	flags = RPC_TASK_ASYNC;
 
-	if (NFS_CONGESTED(inode))
-		goto out_defer;
+	if (IS_SWAPFILE(inode))
+		flags |= NFS_RPC_SWAPFLAGS;
 
-	/* N.B. Do we need to test? Never called for swapfile inode */
-	flags = RPC_TASK_ASYNC | (IS_SWAPFILE(inode)? NFS_RPC_SWAPFLAGS : 0);
-	req = (struct nfs_rreq *) rpc_allocate(flags, sizeof(*req));
+	req = nfs_rreq_alloc();
 	if (!req)
 		goto out_defer;
 
+	pages[0] = page;
+	rpages = 1;
+	if (NFS_SERVER(inode)->rpages > 1) {
+		int npages = NFS_SERVER(inode)->rpages - 1;
+		if (npages > NFS_READ_MAXIOV - 1)
+			npages = NFS_READ_MAXIOV - 1;
+
+		rpages += nfs_grab_readahead_pages(inode, &pages[1], page->offset+PAGE_CACHE_SIZE, npages);
+	}
+
 	/* Initialize request */
 	/* N.B. Will the dentry remain valid for life of request? */
-	nfs_readreq_setup(req, NFS_FH(dentry), loffset,
-			  (void *) address, PAGE_SIZE);
-
-	req->ra_inode = inode;
-	req->ra_page = page; /* count has been incremented by caller */
+	nfs_readreq_setup(req, inode, NFS_FH(dentry), pages, rpages);
 
 	/* Start the async call */
 	dprintk("NFS: executing async READ request.\n");
-	result = rpc_do_call(NFS_CLIENT(inode), NFSPROC_READ,
-				&req->ra_args, &req->ra_res, flags,
+
+	msg.rpc_proc = (NFS_PROTO(inode)->version == 3) ? NFS3PROC_READ : NFSPROC_READ;
+	msg.rpc_argp = &req->ra_args;
+	msg.rpc_resp = &req->ra_res;
+	msg.rpc_cred = nfs_file_cred(file);
+
+	result = rpc_call_async(NFS_CLIENT(inode), &msg, flags,
 				nfs_readpage_result, req);
 	if (result < 0)
 		goto out_free;
 	result = 0;
-out:
+ out:
 	return result;
 
-out_defer:
+ out_defer:
 	dprintk("NFS: deferring async READ request.\n");
 	goto out;
-out_free:
+ out_free:
 	dprintk("NFS: failed to enqueue async READ request.\n");
-	kfree(req);
+	for(i = 1; i < rpages; i++) {
+		set_bit(PG_error, &pages[i]->flags);
+		nfs_unlock_page(pages[i]);
+		page_cache_release(pages[i]);
+	}
+	nfs_rreq_free(req);
 	goto out;
 }
 
@@ -237,7 +346,7 @@
  * We read the page synchronously in the following cases:
  *  -	The file is a swap file. Swap-ins are always sync operations,
  *	so there's no need bothering to make async reads 100% fail-safe.
- *  -	The NFS rsize is smaller than PAGE_SIZE. We could kludge our way
+ *  -	The NFS rsize is smaller than PAGE_CACHE_SIZE. We could kludge our way
  *	around this by creating several consecutive read requests, but
  *	that's hardly worth it.
  *  -	The error flag is set for this page. This happens only when a
@@ -249,41 +358,38 @@
 {
 	struct dentry *dentry = file->f_dentry;
 	struct inode *inode = dentry->d_inode;
-	int		error;
+	int		error = 0,
+			rsize = NFS_SERVER(inode)->rsize,
+			rpages = NFS_SERVER(inode)->rpages;
 
-	dprintk("NFS: nfs_readpage (%p %ld@%Ld)\n",
-		page, PAGE_SIZE, pgoff2loff(page->index));
 	atomic_inc(&page->count);
-	set_bit(PG_locked, &page->flags);
+	while (!nfs_lock_page(page))
+		wait_on_page(page);
+
+	dprintk("NFS: nfs_readpage (%p %d@%ld)\n",
+		page, rsize, page->offset);
 
 	/*
-	 * Try to flush any pending writes to the file..
-	 *
-	 * NOTE! Because we own the page lock, there cannot
-	 * be any new pending writes generated at this point
-	 * for this page (other pages can be written to).
+	 * Try to flush any pending writes to the file
 	 */
-	error = nfs_wb_page(inode, page);
-	if (error)
-		goto out_error;
+	error = nfs_sync_file(inode, 0, page_index(page), rpages, FLUSH_WAIT|FLUSH_STABLE);
+	if (error < 0)
+		goto out_unlock;
 
 	error = -1;
-	if (!IS_SWAPFILE(inode) && !PageError(page) &&
-	    NFS_SERVER(inode)->rsize >= PAGE_SIZE)
-		error = nfs_readpage_async(dentry, inode, page);
+	if (!IS_SWAPFILE(inode) && !PageError(page) && rsize >= PAGE_CACHE_SIZE)
+		error = nfs_readpage_async(file, page);
+
 	if (error >= 0)
 		goto out;
 
-	error = nfs_readpage_sync(dentry, inode, page);
+	error = nfs_readpage_sync(file, page);
 	if (error < 0 && IS_SWAPFILE(inode))
-		printk("Aiee.. nfs swap-in of page failed!\n");
-	goto out_free;
+		printk(KERN_ERR "Aiee.. nfs swap-in of page failed!\n");
 
-out_error:
-	clear_bit(PG_locked, &page->flags);
-	wake_up(&page->wait);
-out_free:
-	free_page(page_address(page));
-out:
+ out_unlock:
+	nfs_unlock_page(page);
+	page_cache_release(page);
+ out:
 	return error;
 }
Index: oldkernel/linux/fs/nfs/symlink.c
diff -u linux/fs/nfs/symlink.c:1.1.1.1 linux/fs/nfs/symlink.c:1.2
--- linux/fs/nfs/symlink.c:1.1.1.1	Wed May 31 12:33:48 2000
+++ linux/fs/nfs/symlink.c	Fri Jul  7 15:36:46 2000
@@ -5,12 +5,18 @@
  *
  *  Optimization changes Copyright (C) 1994 Florian La Roche
  *
+ *  Jun 7 1999, cache symlink lookups in the page cache.  -DaveM
+ *
  *  nfs symlink handling code
  */
 
+#define NFS_NEED_XDR_TYPES
 #include <linux/sched.h>
 #include <linux/errno.h>
+#include <linux/sunrpc/clnt.h>
 #include <linux/nfs_fs.h>
+#include <linux/nfs.h>
+#include <linux/pagemap.h>
 #include <linux/stat.h>
 #include <linux/mm.h>
 #include <linux/malloc.h>
@@ -37,70 +43,122 @@
 	NULL,			/* rename */
 	nfs_readlink,		/* readlink */
 	nfs_follow_link,	/* follow_link */
+	NULL,			/* get_block */
 	NULL,			/* readpage */
 	NULL,			/* writepage */
-	NULL,			/* bmap */
+	NULL,			/* flushpage */
 	NULL,			/* truncate */
-	NULL			/* permission */
+	NULL,			/* permission */
+	NULL,			/* smap */
+	NULL			/* revalidate */
 };
 
+/* Symlink caching in the page cache is even more simplistic
+ * and straight-forward than readdir caching.
+ */
+static struct page *try_to_get_symlink_page(struct dentry *dentry, struct inode *inode)
+{
+	struct nfs_fattr fattr;
+	struct page *page;
+	void * buffer;
+	unsigned int error;
+
+	page = nfs_grab_cache_page(inode, 0);
+	if (!page)
+		goto out;
+
+	if (PageUptodate(page))
+		goto unlock_out;
+
+	/* We place the length at the beginning of the page,
+	 * in client byte order, followed by the string.
+	 */
+	buffer = (void *)page_address(page);
+	memset(buffer, 0, PAGE_CACHE_SIZE);
+	error = NFS_CALL(readlink, inode, (dentry, &fattr, buffer,
+					   PAGE_CACHE_SIZE-sizeof(u32)-4));
+	if (error < 0)
+		goto error;
+	nfs_refresh_inode(inode, &fattr);
+	if (PageError(page))
+		clear_bit(PG_error, &page->flags);
+	set_bit(PG_uptodate, &page->flags);
+
+unlock_out:
+	nfs_unlock_page(page);
+out:
+	return page;
+
+error:
+	set_bit(PG_error, &page->flags);
+	goto unlock_out;
+}
+
 static int nfs_readlink(struct dentry *dentry, char *buffer, int buflen)
 {
-	int error;
-	unsigned int len;
-	char *res;
-	void *mem;
-
-	dfprintk(VFS, "nfs: readlink(%s/%s)\n",
-		dentry->d_parent->d_name.name, dentry->d_name.name);
-
-	error = nfs_proc_readlink(NFS_DSERVER(dentry), NFS_FH(dentry),
-					&mem, &res, &len, NFS_MAXPATHLEN);
-	if (! error) {
-		if (len > buflen)
-			len = buflen;
-		copy_to_user(buffer, res, len);
-		error = len;
-		kfree(mem);
+	struct inode *inode = dentry->d_inode;
+	struct page *page;
+	u32 *p, len;
+
+	/* Caller revalidated the directory inode already. */
+	page = find_page(inode, 0);
+	if (!page)
+		goto no_readlink_page;
+	if (!PageUptodate(page)) {
+		page_cache_release(page);
+		goto no_readlink_page;
 	}
-	return error;
+success:
+	p = (u32 *) page_address(page);
+	len = *p++;
+	if (len > buflen)
+		len = buflen;
+	copy_to_user(buffer, p, len);
+	page_cache_release(page);
+	return len;
+
+no_readlink_page:
+	page = try_to_get_symlink_page(dentry, inode);
+	if (!page)
+		goto no_page;
+	if (PageUptodate(page))
+		goto success;
+	page_cache_release(page);
+	return -EIO;
+no_page:
+	return -ENOMEM;
 }
 
 static struct dentry *
-nfs_follow_link(struct dentry * dentry, struct dentry *base, unsigned int follow)
+nfs_follow_link(struct dentry *dentry, struct dentry *base, unsigned int follow)
 {
-	int error;
-	unsigned int len;
-	char *res;
-	void *mem;
-	char *path;
 	struct dentry *result;
-
-	dfprintk(VFS, "nfs: follow_link(%s/%s)\n",
-		dentry->d_parent->d_name.name, dentry->d_name.name);
-
-	error = nfs_proc_readlink(NFS_DSERVER(dentry), NFS_FH(dentry),
-				 &mem, &res, &len, NFS_MAXPATHLEN);
-	result = ERR_PTR(error);
-	if (error)
-		goto out_dput;
-
-	result = ERR_PTR(-ENOMEM);
-	path = kmalloc(len + 1, GFP_KERNEL);
-	if (!path)
-		goto out_mem;
-	memcpy(path, res, len);
-	path[len] = 0;
-	kfree(mem);
-
-	result = lookup_dentry(path, base, follow);
-	kfree(path);
-out:
+	struct inode *inode = dentry->d_inode;
+	struct page *page;
+	u32 *p;
+
+	/* Caller revalidated the directory inode already. */
+	page = find_page(inode, 0);
+	if (!page)
+		goto no_followlink_page;
+	if (!PageUptodate(page)) {
+		page_cache_release(page);
+		goto no_followlink_page;
+	}
+success:
+	p = (u32 *) page_address(page);
+	result = lookup_dentry((char *) (p + 1), base, follow);
+	page_cache_release(page);
 	return result;
 
-out_mem:
-	kfree(mem);
-out_dput:
-	dput(base);
-	goto out;
+no_followlink_page:
+	page = try_to_get_symlink_page(dentry, inode);
+	if (!page)
+		goto no_page;
+	if (PageUptodate(page))
+		goto success;
+	page_cache_release(page);
+	return ERR_PTR(-EIO);
+no_page:
+	return ERR_PTR(-ENOMEM);
 }
Index: oldkernel/linux/fs/nfs/write.c
diff -u linux/fs/nfs/write.c:1.2 linux/fs/nfs/write.c:1.3
--- linux/fs/nfs/write.c:1.2	Thu Jun  1 15:03:08 2000
+++ linux/fs/nfs/write.c	Fri Jul  7 15:36:46 2000
@@ -10,26 +10,19 @@
  * RPC call to write the page is scheduled immediately; otherwise, the call
  * is delayed for a few seconds.
  *
- * Just like readahead, no async I/O is performed if wsize < PAGE_SIZE.
+ * Just like readahead, no async I/O is performed if wsize < PAGE_CACHE_SIZE.
  *
- * Write requests are kept on the inode's writeback list. Each entry in
+ * Write requests are kept on the inode's dirty list. Each entry in
  * that list references the page (portion) to be written. When the
- * cache timeout has expired, the RPC task is woken up, and tries to
- * lock the page. As soon as it manages to do so, the request is moved
- * from the writeback list to the writelock list.
+ * cache timeout has expired, the flushd task is woken up, and tries to
+ * lock the request. As soon as it manages to do so, the request is removed
+ * from the dirty list. When the RPC write call completes, the request
+ * is either released or put on the inode's commit list.
  *
  * Note: we must make sure never to confuse the inode passed in the
  * write_page request with the one in page->inode. As far as I understand
  * it, these are different when doing a swap-out.
  *
- * To understand everything that goes on here and in the NFS read code,
- * one should be aware that a page is locked in exactly one of the following
- * cases:
- *
- *  -	A write request is in progress.
- *  -	A user process is in generic_file_write/nfs_update_page
- *  -	A user process is in generic_file_read
- *
  * Also note that because of the way pages are invalidated in
  * nfs_revalidate_inode, the following assertions hold:
  *
@@ -38,92 +31,173 @@
  *  -	If the page is not uptodate, there will be no pending write
  *	requests, and no process will be in nfs_update_page.
  *
- * FIXME: Interaction with the vmscan routines is not optimal yet.
- * Either vmscan must be made nfs-savvy, or we need a different page
- * reclaim concept that supports something like FS-independent
- * buffer_heads with a b_ops-> field.
- *
  * Copyright (C) 1996, 1997, Olaf Kirch <okir@monad.swb.de>
+ *
+ * Rewritten 6/3/2000 by Trond Myklebust.
+ * Copyright (C) 1999, 2000, Trond Myklebust <trond.myklebust@fys.uio.no>
  */
 
 #include <linux/types.h>
 #include <linux/malloc.h>
 #include <linux/swap.h>
 #include <linux/pagemap.h>
-#include <linux/file.h>
 
+#include <linux/sunrpc/auth.h>
 #include <linux/sunrpc/clnt.h>
+#include <asm/spinlock.h>
+#include <linux/nfs.h>
+#include <linux/nfs2.h>
+#include <linux/nfs3.h>
 #include <linux/nfs_fs.h>
+#include <linux/nfs_mount.h>
+#include <linux/nfs_flushd.h>
 #include <asm/uaccess.h>
+#include <linux/file.h>
+
 
 #define NFS_PARANOIA 1
 #define NFSDBG_FACILITY		NFSDBG_PAGECACHE
 
-static void			nfs_wback_begin(struct rpc_task *task);
-static void			nfs_wback_result(struct rpc_task *task);
-static void			nfs_cancel_request(struct nfs_wreq *req);
+/*
+ * Spinlock
+ */
+spinlock_t nfs_wreq_lock = SPIN_LOCK_UNLOCKED;
+static unsigned int	nfs_nr_requests = 0;
 
 /*
- * Cache parameters
+ * Local structures
+ *
+ * Valid flags for a dirty buffer
  */
-#define NFS_WRITEBACK_DELAY	(10 * HZ)
-#define NFS_WRITEBACK_MAX	64
+#define PG_BUSY			0x0001
 
 /*
- * Limit number of delayed writes
+ * This is the struct where the WRITE/COMMIT arguments go.
  */
-static int			nr_write_requests = 0;
-static struct rpc_wait_queue	write_queue = RPC_INIT_WAITQ("write_chain");
+struct nfs_write_data {
+	struct rpc_task		task;
+	struct file		*file;
+	struct rpc_cred		*cred;
+	struct nfs_writeargs	args;		/* argument struct */
+	struct nfs_writeres	res;		/* result struct */
+	struct nfs_fattr	fattr;
+	struct nfs_writeverf	verf;
+	struct list_head	pages;		/* Coalesced requests we wish to flush */
+};
+
+struct nfs_page {
+	struct list_head	wb_hash,	/* Inode */
+				wb_list,
+				*wb_list_head;
+	struct file		*wb_file;
+	struct rpc_cred		*wb_cred;
+	struct page		*wb_page;	/* page to write out */
+	struct wait_queue	*wb_wait;	/* wait queue */
+	unsigned long		wb_timeout;	/* when to write/commit */
+	unsigned int		wb_offset,	/* Offset of write */
+				wb_bytes,	/* Length of request */
+				wb_count,	/* reference count */
+				wb_flags;
+	struct nfs_writeverf	wb_verf;	/* Commit cookie */
+};
 
+#define NFS_WBACK_BUSY(req)	((req)->wb_flags & PG_BUSY)
+
+/*
+ * Local function declarations
+ */
+static void	nfs_writeback_done(struct rpc_task *);
+static void	nfs_commit_done(struct rpc_task *);
+
 /* Hack for future NFS swap support */
 #ifndef IS_SWAPFILE
 # define IS_SWAPFILE(inode)	(0)
 #endif
 
+static __inline__ struct nfs_page *nfs_page_alloc(void)
+{
+	struct nfs_page *p;
+	p = (struct nfs_page *) kmalloc(sizeof(*p), GFP_KERNEL);
+	if (p) {
+		memset(p, 0, sizeof(*p));
+		INIT_LIST_HEAD(&p->wb_hash);
+		INIT_LIST_HEAD(&p->wb_list);
+	}
+	return p;
+}
+
+static __inline__ void nfs_page_free(struct nfs_page *p)
+{
+	kfree(p);
+}
+
+static __inline__ struct nfs_write_data *nfs_writedata_alloc(void)
+{
+	struct nfs_write_data   *p;
+	p = (struct nfs_write_data *) kmalloc(sizeof(*p), GFP_NFS);
+	if (p) {
+		memset(p, 0, sizeof(*p));
+		INIT_LIST_HEAD(&p->pages);
+	}
+	return p;
+}
+
+static __inline__ void nfs_writedata_free(struct nfs_write_data *p)
+{
+	kfree(p);
+}
+
+static void nfs_writedata_release(struct rpc_task *task)
+{
+	nfs_writedata_free(task->tk_calldata);
+}
+
+static __inline__ int
+nfs_write_attributes(struct inode *inode, struct nfs_fattr *fattr)
+{
+	if ((fattr->valid & NFS_ATTR_FATTR) && !(fattr->valid & NFS_ATTR_WCC)) {
+		fattr->pre_size  = NFS_CACHE_ISIZE(inode);
+		fattr->pre_mtime = NFS_CACHE_MTIME(inode);
+		fattr->pre_ctime = NFS_CACHE_CTIME(inode);
+		fattr->valid |= NFS_ATTR_WCC;
+	}
+	return nfs_refresh_inode(inode, fattr);
+}
+
 /*
  * Write a page synchronously.
  * Offset is the data offset within the page.
  */
 static int
-nfs_writepage_sync(struct dentry *dentry, struct inode *inode,
-		   struct page *page, unsigned int offset, unsigned int count)
+nfs_writepage_sync(struct file *file, struct page *page,
+		   unsigned long offset, unsigned int count)
 {
+	struct dentry	*dentry = file->f_dentry;
+	struct inode	*inode = dentry->d_inode;
+	struct rpc_cred	*cred = nfs_file_cred(file);
 	unsigned int	wsize = NFS_SERVER(inode)->wsize;
-	int		result, refresh = 0, written = 0;
+	int		result, refresh = 0, written = 0, flags;
 	u8		*buffer;
 	struct nfs_fattr fattr;
-	loff_t		loffset = pgoff2loff(page->index)+offset;
+	struct nfs_writeverf verifier;
 
 	dprintk("NFS:      nfs_writepage_sync(%s/%s %d@%Ld)\n",
 		dentry->d_parent->d_name.name, dentry->d_name.name,
-		count, loffset);
+		count, (long long)(page_offset(page) + offset));
 
 	buffer = (u8 *) page_address(page) + offset;
+	offset += page_offset(page);
 
-	/* FIXME: NFSv3 !!! */
-#if 1
-	if (loffset >= 0x7ffffffeULL)
-	  return -EFBIG;
-	if (loffset + count >= 0x7fffffffULL) {
-	  /* At MOST this much! */
-	  count = 0x7fffffffULL - loffset;
-	}
-#else
-	if (S_ISREG(inode->i_flags) &&
-	    !(dentry->d_file->f_flags & O_LARGEFILE) &&
-	    (loffset >= 0x7ffffffeULL ||
-	     loffset + count >= 0x7fffffffULL) {
-	  /* Writing beyond LargeFile maximums without O_LARGEFILE */
-	}
-#endif
+	flags = ((IS_SWAPFILE(inode)) ? NFS_RW_SWAP : 0) | NFS_RW_SYNC;
 
 	do {
 		if (count < wsize && !IS_SWAPFILE(inode))
 			wsize = count;
 
-		result = nfs_proc_write(NFS_DSERVER(dentry), NFS_FH(dentry),
-					IS_SWAPFILE(inode), loffset, wsize,
-					buffer, &fattr);
+		result = NFS_CALL(write, inode, (dentry, &fattr, cred, flags,
+						 offset, wsize, buffer,
+						 &verifier));
+		nfs_write_attributes(inode, &fattr);
 
 		if (result < 0) {
 			/* Must mark the page invalid after I/O error */
@@ -131,290 +205,742 @@
 			goto io_error;
 		}
 		if (result != wsize)
-			printk("NFS: short write, wsize=%u, result=%d\n",
+			printk(KERN_ERR "NFS: short write, size=%u, result=%d\n",
 			wsize, result);
 		refresh = 1;
 		buffer  += wsize;
-		loffset += wsize;
+		offset  += wsize;
 		written += wsize;
 		count   -= wsize;
 		/*
 		 * If we've extended the file, update the inode
 		 * now so we don't invalidate the cache.
 		 */
-		if (loffset > inode->i_size)
-			inode->i_size = loffset;
+		if (offset > inode->i_size)
+			inode->i_size = offset;
 	} while (count);
 
 io_error:
-	/* Note: we don't refresh if the call failed (fattr invalid) */
-	if (refresh && result >= 0) {
-		/* See comments in nfs_wback_result */
-		/* N.B. I don't think this is right -- sync writes in order */
-		if (fattr.size < inode->i_size)
-			fattr.size = inode->i_size;
-		if (fattr.mtime.seconds < inode->i_mtime)
-			printk("nfs_writepage_sync: prior time??\n");
-		/* Solaris 2.5 server seems to send garbled
-		 * fattrs occasionally */
-		if (inode->i_ino == fattr.fileid) {
-			/*
-			 * We expect the mtime value to change, and
-			 * don't want to invalidate the caches.
-			 */
-			inode->i_mtime = fattr.mtime.seconds;
-			nfs_refresh_inode(inode, &fattr);
-		} 
-		else
-			printk("nfs_writepage_sync: inode %ld, got %u?\n",
-				inode->i_ino, fattr.fileid);
-	}
-
 	return written? written : result;
 }
 
 /*
- * Append a writeback request to a list
+ * Write a page to the server. This will be used for NFS swapping only
+ * (for now), and we currently do this synchronously only.
  */
-static inline void
-append_write_request(struct nfs_wreq **q, struct nfs_wreq *wreq)
+int
+nfs_writepage(struct file * file, struct page *page)
 {
-	dprintk("NFS:      append_write_request(%p, %p)\n", q, wreq);
-	rpc_append_list(q, wreq);
+	struct inode *inode = file->f_dentry->d_inode;
+	unsigned offset = PAGE_CACHE_SIZE;
+
+	if (page->offset >= inode->i_size)
+		return -EIO;
+	if (page->offset + offset > inode->i_size)
+		offset = inode->i_size & (PAGE_CACHE_SIZE-1);
+	return nfs_writepage_sync(file, page, 0, offset);
 }
 
 /*
- * Remove a writeback request from a list
+ * Check whether the file range we want to write to is locked by
+ * us.
  */
+static int
+region_locked(struct inode *inode, struct nfs_page *req)
+{
+	struct file_lock	*fl;
+	unsigned long		rqstart, rqend;
+
+	/* Don't optimize writes if we don't use NLM */
+	if (NFS_SERVER(inode)->flags & NFS_MOUNT_NONLM)
+		return 0;
+
+	rqstart = page_offset(req->wb_page) + req->wb_offset;
+	rqend = rqstart + req->wb_bytes;
+	for (fl = inode->i_flock; fl; fl = fl->fl_next) {
+		if (fl->fl_owner == current->files && (fl->fl_flags & FL_POSIX)
+		    && fl->fl_type == F_WRLCK
+		    && fl->fl_start <= rqstart && rqend <= fl->fl_end) {
+			return 1;
+		}
+	}
+
+	return 0;
+}
+
+static inline struct nfs_page *
+nfs_inode_wb_entry(struct list_head *head)
+{
+	return list_entry(head, struct nfs_page, wb_hash);
+}
+
+/*
+ * Insert a write request into an inode
+ */
 static inline void
-remove_write_request(struct nfs_wreq **q, struct nfs_wreq *wreq)
+nfs_inode_add_request(struct inode *inode, struct nfs_page *req)
 {
-	dprintk("NFS:      remove_write_request(%p, %p)\n", q, wreq);
-	rpc_remove_list(q, wreq);
+	if (!list_empty(&req->wb_hash))
+		return;
+	if (!NFS_WBACK_BUSY(req))
+		printk(KERN_ERR "NFS: unlocked request attempted hashed!\n");
+	inode->u.nfs_i.npages++;
+	list_add(&req->wb_hash, &inode->u.nfs_i.writeback);
+	req->wb_count++;
 }
 
 /*
- * Find a non-busy write request for a given page to
- * try to combine with.
+ * Insert a write request into an inode
  */
-static inline struct nfs_wreq *
-find_write_request(struct inode *inode, struct page *page)
+static inline void
+nfs_inode_remove_request(struct nfs_page *req)
 {
-	pid_t pid = current->pid;
-	struct nfs_wreq	*head, *req;
+	struct inode *inode;
+	spin_lock(&nfs_wreq_lock);
+	if (list_empty(&req->wb_hash)) {
+		spin_unlock(&nfs_wreq_lock);
+		return;
+	}
+	if (!NFS_WBACK_BUSY(req))
+		printk(KERN_ERR "NFS: unlocked request attempted unhashed!\n");
+	inode = req->wb_file->f_dentry->d_inode;
+	list_del(&req->wb_hash);
+	INIT_LIST_HEAD(&req->wb_hash);
+	inode->u.nfs_i.npages--;
+	if ((inode->u.nfs_i.npages == 0) != list_empty(&inode->u.nfs_i.writeback))
+		printk(KERN_ERR "NFS: desynchronized value of nfs_i.npages.\n");
+	if (!nfs_have_writebacks(inode))
+		inode_remove_flushd(inode);
+	spin_unlock(&nfs_wreq_lock);
+	nfs_release_request(req);
+}
 
-	dprintk("NFS:      find_write_request(%x/%ld, %p)\n",
-				inode->i_dev, inode->i_ino, page);
-	if (!(req = head = NFS_WRITEBACK(inode)))
-		return NULL;
-	do {
-		/*
-		 * We can't combine with canceled requests or
-		 * requests that have already been started..
-		 */
-		if (req->wb_flags & (NFS_WRITE_CANCELLED | NFS_WRITE_INPROGRESS))
+/*
+ * Find a request
+ */
+static inline struct nfs_page *
+_nfs_find_request(struct inode *inode, struct page *page)
+{
+	struct list_head	*head, *next;
+
+	head = &inode->u.nfs_i.writeback;
+	next = head->next;
+	while (next != head) {
+		struct nfs_page *req = nfs_inode_wb_entry(next);
+		next = next->next;
+		if (page_index(req->wb_page) != page_index(page))
 			continue;
+		req->wb_count++;
+		return req;
+	}
+	return NULL;
+}
 
-		if (req->wb_page == page && req->wb_pid == pid)
-			return req;
+struct nfs_page *
+nfs_find_request(struct inode *inode, struct page *page)
+{
+	struct nfs_page		*req;
 
-		/*
-		 * Ehh, don't keep too many tasks queued..
-		 */
-		rpc_wake_up_task(&req->wb_task);
+	spin_lock(&nfs_wreq_lock);
+	req = _nfs_find_request(inode, page);
+	spin_unlock(&nfs_wreq_lock);
+	return req;
+}
 
-	} while ((req = WB_NEXT(req)) != head);
-	return NULL;
+static inline struct nfs_page *
+nfs_list_entry(struct list_head *head)
+{
+	return list_entry(head, struct nfs_page, wb_list);
 }
 
 /*
- * Find and release all failed requests for this inode.
+ * Insert a write request into a sorted list
  */
-int
-nfs_check_failed_request(struct inode * inode)
+static inline void
+nfs_list_add_request(struct nfs_page *req, struct list_head *head)
 {
-	/* FIXME! */
-	return 0;
+	struct list_head *prev;
+
+	if (!list_empty(&req->wb_list)) {
+		printk(KERN_ERR "NFS: Add to list failed!\n");
+		return;
+	}
+	if (list_empty(&req->wb_hash)) {
+		printk(KERN_ERR "NFS: Unhashed request attempted added to a list!\n");
+		return;
+	}
+	if (!NFS_WBACK_BUSY(req))
+		printk(KERN_ERR "NFS: unlocked request attempted added to list!\n");
+	prev = head->prev;
+	while (prev != head) {
+		struct nfs_page	*p = nfs_list_entry(prev);
+		if (page_index(p->wb_page) < page_index(req->wb_page))
+			break;
+		prev = prev->prev;
+	}
+	list_add(&req->wb_list, prev);
+	req->wb_list_head = head;
 }
 
 /*
- * Try to merge adjacent write requests. This works only for requests
- * issued by the same user.
+ * Insert a write request into an inode
  */
-static inline int
-update_write_request(struct nfs_wreq *req, unsigned int first,
-			unsigned int bytes)
+static inline void
+nfs_list_remove_request(struct nfs_page *req)
 {
-	unsigned int	rqfirst = req->wb_offset,
-			rqlast = rqfirst + req->wb_bytes,
-			last = first + bytes;
+	if (list_empty(&req->wb_list))
+		return;
+	if (!NFS_WBACK_BUSY(req))
+		printk(KERN_ERR "NFS: unlocked request attempted removed from list!\n");
+	list_del(&req->wb_list);
+	INIT_LIST_HEAD(&req->wb_list);
+	req->wb_list_head = NULL;
+}
 
-	dprintk("nfs:      trying to update write request %p\n", req);
+/*
+ * Add a request to the inode's dirty list.
+ */
+static inline void
+nfs_mark_request_dirty(struct nfs_page *req)
+{
+	struct inode *inode = req->wb_file->f_dentry->d_inode;
 
-	/* not contiguous? */
-	if (rqlast < first || last < rqfirst)
-		return 0;
+	spin_lock(&nfs_wreq_lock);
+	if (list_empty(&req->wb_list)) {
+		nfs_list_add_request(req, &inode->u.nfs_i.dirty);
+		inode->u.nfs_i.ndirty++;
+	}
+	spin_unlock(&nfs_wreq_lock);
+	/*
+	 * NB: the call to inode_schedule_scan() must lie outside the
+	 *     spinlock since it can run flushd().
+	 */
+	inode_schedule_scan(inode, req->wb_timeout);
+}
 
-	if (first < rqfirst)
-		rqfirst = first;
-	if (rqlast < last)
-		rqlast = last;
+/*
+ * Check if a request is dirty
+ */
+static inline int
+nfs_dirty_request(struct nfs_page *req)
+{
+	struct inode *inode = req->wb_file->f_dentry->d_inode;
+	return !list_empty(&req->wb_list) && req->wb_list_head == &inode->u.nfs_i.dirty;
+}
 
-	req->wb_offset = rqfirst;
-	req->wb_bytes  = rqlast - rqfirst;
-	req->wb_count++;
+/*
+ * Add a request to the inode's commit list.
+ */
+static inline void
+nfs_mark_request_commit(struct nfs_page *req)
+{
+	struct inode *inode = req->wb_file->f_dentry->d_inode;
+
+	spin_lock(&nfs_wreq_lock);
+	if (list_empty(&req->wb_list)) {
+		nfs_list_add_request(req, &inode->u.nfs_i.commit);
+		inode->u.nfs_i.ncommit++;
+	}
+	spin_unlock(&nfs_wreq_lock);
+	/*
+	 * NB: the call to inode_schedule_scan() must lie outside the
+	 *     spinlock since it can run flushd().
+	 */
+	inode_schedule_scan(inode, req->wb_timeout);
+}
 
+/*
+ * Lock the page of an asynchronous request
+ */
+static inline int
+nfs_lock_request(struct nfs_page *req)
+{
+	if (NFS_WBACK_BUSY(req))
+		return 0;
+	req->wb_count++;
+	req->wb_flags |= PG_BUSY;
 	return 1;
 }
 
 static inline void
-free_write_request(struct nfs_wreq * req)
+nfs_unlock_request(struct nfs_page *req)
 {
-	if (!--req->wb_count)
-		kfree(req);
+	if (!NFS_WBACK_BUSY(req)) {
+		printk(KERN_ERR "NFS: Invalid unlock attempted\n");
+		return;
+	}
+	req->wb_flags &= ~PG_BUSY;
+	wake_up(&req->wb_wait);
+	nfs_release_request(req);
 }
 
 /*
- * Create and initialize a writeback request
+ * Create a write request.
+ * Page must be locked by the caller. This makes sure we never create
+ * two different requests for the same page, and avoids possible deadlock
+ * when we reach the hard limit on the number of dirty pages.
  */
-static inline struct nfs_wreq *
-create_write_request(struct file * file, struct page *page, unsigned int offset, unsigned int bytes)
+static struct nfs_page *
+nfs_create_request(struct inode *inode, struct file *file, struct page *page,
+		   unsigned int offset, unsigned int count)
 {
-	struct dentry	*dentry = file->f_dentry;
-	struct inode	*inode = dentry->d_inode;
-	struct rpc_clnt	*clnt = NFS_CLIENT(inode);
-	struct nfs_wreq *wreq;
-	struct rpc_task	*task;
+	struct nfs_reqlist	*cache = NFS_REQUESTLIST(inode);
+	struct nfs_page		*req = NULL;
+	long			timeout;
 
-	dprintk("NFS:      create_write_request(%s/%s, %ld+%d)\n",
-		dentry->d_parent->d_name.name, dentry->d_name.name,
-		(u_long)pgoff2loff(page->index) + offset, bytes);
+	/* Deal with hard/soft limits.
+	 */
+	do {
+		/* If we're over the soft limit, flush out old requests */
+		if (nfs_nr_requests >= MAX_REQUEST_SOFT)
+			nfs_wb_file(inode, file);
+
+		/* If we're still over the soft limit, wake up some requests */
+		if (nfs_nr_requests >= MAX_REQUEST_SOFT) {
+			dprintk("NFS:      hit soft limit (%d requests)\n",
+				nfs_nr_requests);
+			if (!cache->task)
+				nfs_reqlist_init(NFS_SERVER(inode));
+			nfs_wake_flushd();
+		}
 
-	/* FIXME: Enforce hard limit on number of concurrent writes? */
-	wreq = (struct nfs_wreq *) kmalloc(sizeof(*wreq), GFP_KERNEL);
-	if (!wreq)
-		goto out_fail;
-	memset(wreq, 0, sizeof(*wreq));
-
-	task = &wreq->wb_task;
-	rpc_init_task(task, clnt, nfs_wback_result, RPC_TASK_NFSWRITE);
-	task->tk_calldata = wreq;
-	task->tk_action = nfs_wback_begin;
-
-	rpcauth_lookupcred(task);	/* Obtain user creds */
-	if (task->tk_status < 0)
-		goto out_req;
-
-	/* Put the task on inode's writeback request list. */
-	wreq->wb_file = file;
-	wreq->wb_pid    = current->pid;
-	wreq->wb_page   = page;
-	wreq->wb_offset = offset;
-	wreq->wb_bytes  = bytes;
-	wreq->wb_count	= 2;		/* One for the IO, one for us */
-
-	append_write_request(&NFS_WRITEBACK(inode), wreq);
-
-	if (nr_write_requests++ > NFS_WRITEBACK_MAX*3/4)
-		rpc_wake_up_next(&write_queue);
-
-	return wreq;
-
-out_req:
-	rpc_release_task(task);
-	kfree(wreq);
-out_fail:
-	return NULL;
+		/* If we haven't reached the hard limit yet,
+		 * try to allocate the request struct */
+		if (nfs_nr_requests < MAX_REQUEST_HARD) {
+			req = nfs_page_alloc();
+			if (req != NULL)
+				break;
+		}
+
+		/* We're over the hard limit. Wait for better times */
+		dprintk("NFS:      create_request sleeping (total %d pid %d)\n",
+			nfs_nr_requests, current->pid);
+
+		timeout = 1 * HZ;
+		if (NFS_SERVER(inode)->flags & NFS_MOUNT_INTR) {
+			interruptible_sleep_on_timeout(&cache->request_wait,
+						       timeout);
+			if (signalled())
+				break;
+		} else
+			sleep_on_timeout(&cache->request_wait, timeout);
+
+		dprintk("NFS:      create_request waking up (tot %d pid %d)\n",
+			nfs_nr_requests, current->pid);
+	} while (!req);
+	if (!req)
+		return NULL;
+
+	/* Initialize the request struct. Initially, we assume a
+	 * long write-back delay. This will be adjusted in
+	 * update_nfs_request below if the region is not locked. */
+	req->wb_page    = page;
+	atomic_inc(&page->count);
+	req->wb_offset  = offset;
+	req->wb_bytes   = count;
+	/* If the region is locked, adjust the timeout */
+	if (region_locked(inode, req))
+		req->wb_timeout = jiffies + NFS_WRITEBACK_LOCKDELAY;
+	else
+		req->wb_timeout = jiffies + NFS_WRITEBACK_DELAY;
+	req->wb_file    = file;
+	req->wb_cred	= nfs_file_cred(file);
+	file->f_count++;
+	req->wb_count   = 1;
+
+	/* register request's existence */
+	cache->nr_requests++;
+	nfs_nr_requests++;
+	return req;
 }
 
+
 /*
- * Schedule a writeback RPC call.
- * If the server is congested, don't add to our backlog of queued
- * requests but call it synchronously.
- * The function returns whether we should wait for the thing or not.
- *
- * FIXME: Here we could walk the inode's lock list to see whether the
- * page we're currently writing to has been write-locked by the caller.
- * If it is, we could schedule an async write request with a long
- * delay in order to avoid writing back the page until the lock is
- * released.
+ * Release all resources associated with a write request after it
+ * has been committed to stable storage
+ *
+ * Note: Should always be called with the spinlock held!
  */
-static inline int
-schedule_write_request(struct nfs_wreq *req, int sync)
+void
+nfs_release_request(struct nfs_page *req)
 {
-	struct rpc_task	*task = &req->wb_task;
-	struct file	*file = req->wb_file;
-	struct dentry	*dentry = file->f_dentry;
-	struct inode	*inode = dentry->d_inode;
-
-	if (NFS_CONGESTED(inode) || nr_write_requests >= NFS_WRITEBACK_MAX)
-		sync = 1;
+	struct inode		*inode = req->wb_file->f_dentry->d_inode;
+	struct nfs_reqlist	*cache = NFS_REQUESTLIST(inode);
+	struct page		*page = req->wb_page;
+
+	spin_lock(&nfs_wreq_lock);
+	if (--req->wb_count) {
+		spin_unlock(&nfs_wreq_lock);
+		return;
+	}
+	spin_unlock(&nfs_wreq_lock);
 
-	if (sync) {
-		sigset_t	oldmask;
-		struct rpc_clnt *clnt = NFS_CLIENT(inode);
-		dprintk("NFS: %4d schedule_write_request (sync)\n",
-					task->tk_pid);
-		/* Page is already locked */
-		rpc_clnt_sigmask(clnt, &oldmask);
-		rpc_execute(task);
-		rpc_clnt_sigunmask(clnt, &oldmask);
-	} else {
-		dprintk("NFS: %4d schedule_write_request (async)\n",
-					task->tk_pid);
-		task->tk_flags |= RPC_TASK_ASYNC;
-		task->tk_timeout = NFS_WRITEBACK_DELAY;
-		rpc_sleep_on(&write_queue, task, NULL, NULL);
+	if (!list_empty(&req->wb_list)) {
+		printk(KERN_ERR "NFS: Request released while still on a list!\n");
+		nfs_list_remove_request(req);
 	}
+	if (!list_empty(&req->wb_hash)) {
+		printk(KERN_ERR "NFS: Request released while still hashed!\n");
+		nfs_inode_remove_request(req);
+	}
+	if (NFS_WBACK_BUSY(req))
+		printk(KERN_ERR "NFS: Request released while still locked!\n");
 
-	return sync;
+	fput(req->wb_file);
+	page_cache_release(page);
+	nfs_page_free(req);
+	/* wake up anyone waiting to allocate a request */
+	cache->nr_requests--;
+	nfs_nr_requests--;
+	wake_up(&cache->request_wait);
 }
 
 /*
- * Wait for request to complete.
+ * Wait for a request to complete.
+ *
+ * Interruptible by signals only if mounted with intr flag.
  */
 static int
-wait_on_write_request(struct nfs_wreq *req)
+nfs_wait_on_request(struct nfs_page *req)
 {
-	struct file		*file = req->wb_file;
-	struct dentry		*dentry = file->f_dentry;
-	struct inode		*inode = dentry->d_inode;
-	struct rpc_clnt		*clnt = NFS_CLIENT(inode);
-	struct wait_queue	wait = { current, NULL };
-	sigset_t		oldmask;
-	int retval;
-
-	/* Make sure it's started.. */
-	if (!WB_INPROGRESS(req))
-		rpc_wake_up_task(&req->wb_task);
+	struct inode	*inode = req->wb_file->f_dentry->d_inode;
+        struct rpc_clnt	*clnt = NFS_CLIENT(inode);
+        int retval;
 
-	rpc_clnt_sigmask(clnt, &oldmask);
-	add_wait_queue(&req->wb_wait, &wait);
+	if (!NFS_WBACK_BUSY(req))
+		return 0;
+	req->wb_count++;
+	retval = nfs_wait_event(clnt, req->wb_wait, !NFS_WBACK_BUSY(req));
+	nfs_release_request(req);
+        return retval;
+}
+
+/*
+ * Wait for a request to complete.
+ *
+ * Interruptible by signals only if mounted with intr flag.
+ */
+static int
+nfs_wait_on_requests(struct inode *inode, struct file *file, unsigned long idx_start, unsigned int npages)
+{
+	struct list_head	*p, *head;
+	unsigned long		idx_end;
+	unsigned int		res = 0;
+	int			error;
+
+	if (npages == 0)
+		idx_end = ~0;
+	else
+		idx_end = idx_start + npages - 1;
+
+	spin_lock(&nfs_wreq_lock);
+	head = &inode->u.nfs_i.writeback;
+	p = head->next;
+	while (p != head) {
+		unsigned long pg_idx;
+		struct nfs_page *req = nfs_inode_wb_entry(p);
+
+		p = p->next;
+
+		if (file && req->wb_file != file)
+			continue;
+
+		pg_idx = page_index(req->wb_page);
+		if (pg_idx < idx_start || pg_idx > idx_end)
+			continue;
+
+		if (!NFS_WBACK_BUSY(req))
+			continue;
+		req->wb_count++;
+		spin_unlock(&nfs_wreq_lock);
+		error = nfs_wait_on_request(req);
+		nfs_release_request(req);
+		if (error < 0)
+			return error;
+		spin_lock(&nfs_wreq_lock);
+		p = head->next;
+		res++;
+	}
+	spin_unlock(&nfs_wreq_lock);
+	return res;
+}
+
+/*
+ * Scan cluster for dirty pages and send as many of them to the
+ * server as possible.
+ */
+static int
+nfs_scan_list_timeout(struct list_head *head, struct list_head *dst, struct inode *inode)
+{
+	struct list_head	*p;
+        struct nfs_page		*req;
+        int			pages = 0;
+
+	p = head->next;
+        while (p != head) {
+		req = nfs_list_entry(p);
+		p = p->next;
+		if (time_after(req->wb_timeout, jiffies)) {
+			if (time_after(NFS_NEXTSCAN(inode), req->wb_timeout))
+				NFS_NEXTSCAN(inode) = req->wb_timeout;
+			continue;
+		}
+		if (!nfs_lock_request(req))
+			continue;
+		nfs_list_remove_request(req);
+		nfs_list_add_request(req, dst);
+		pages++;
+	}
+	return pages;
+}
+
+static int
+nfs_scan_dirty_timeout(struct inode *inode, struct list_head *dst)
+{
+	int	pages;
+	spin_lock(&nfs_wreq_lock);
+	pages = nfs_scan_list_timeout(&inode->u.nfs_i.dirty, dst, inode);
+	inode->u.nfs_i.ndirty -= pages;
+	if ((inode->u.nfs_i.ndirty == 0) != list_empty(&inode->u.nfs_i.dirty))
+		printk(KERN_ERR "NFS: desynchronized value of nfs_i.ndirty.\n");
+	spin_unlock(&nfs_wreq_lock);
+	return pages;
+}
+
+static int
+nfs_scan_commit_timeout(struct inode *inode, struct list_head *dst)
+{
+	int	pages;
+	spin_lock(&nfs_wreq_lock);
+	pages = nfs_scan_list_timeout(&inode->u.nfs_i.commit, dst, inode);
+	inode->u.nfs_i.ncommit -= pages;
+	if ((inode->u.nfs_i.ncommit == 0) != list_empty(&inode->u.nfs_i.commit))
+		printk(KERN_ERR "NFS: desynchronized value of nfs_i.ncommit.\n");
+	spin_unlock(&nfs_wreq_lock);
+	return pages;
+}
+
+static int
+nfs_scan_list(struct list_head *src, struct list_head *dst, struct file *file, unsigned long idx_start, unsigned int npages)
+{
+	struct list_head	*p;
+	struct nfs_page		*req;
+	unsigned long		idx_end;
+	int			res;
+
+	res = 0;
+	if (npages == 0)
+		idx_end = ~0;
+	else
+		idx_end = idx_start + npages - 1;
+	p = src->next;
+	while (p != src) {
+		unsigned long pg_idx;
+
+		req = nfs_list_entry(p);
+		p = p->next;
+
+		if (file && req->wb_file != file)
+			continue;
+
+		pg_idx = page_index(req->wb_page);
+		if (pg_idx < idx_start || pg_idx > idx_end)
+			continue;
+
+		if (!nfs_lock_request(req))
+			continue;
+		nfs_list_remove_request(req);
+		nfs_list_add_request(req, dst);
+		res++;
+	}
+	return res;
+}
+
+static int
+nfs_scan_dirty(struct inode *inode, struct list_head *dst, struct file *file, unsigned long idx_start, unsigned int npages)
+{
+	int	res;
+	spin_lock(&nfs_wreq_lock);
+	res = nfs_scan_list(&inode->u.nfs_i.dirty, dst, file, idx_start, npages);
+	inode->u.nfs_i.ndirty -= res;
+	if ((inode->u.nfs_i.ndirty == 0) != list_empty(&inode->u.nfs_i.dirty))
+		printk(KERN_ERR "NFS: desynchronized value of nfs_i.ndirty.\n");
+	spin_unlock(&nfs_wreq_lock);
+	return res;
+}
+
+static int
+nfs_scan_commit(struct inode *inode, struct list_head *dst, struct file *file, unsigned long idx_start, unsigned int npages)
+{
+	int	res;
+	spin_lock(&nfs_wreq_lock);
+	res = nfs_scan_list(&inode->u.nfs_i.commit, dst, file, idx_start, npages);
+	inode->u.nfs_i.ncommit -= res;
+	if ((inode->u.nfs_i.ncommit == 0) != list_empty(&inode->u.nfs_i.commit))
+		printk(KERN_ERR "NFS: desynchronized value of nfs_i.ncommit.\n");
+	spin_unlock(&nfs_wreq_lock);
+	return res;
+}
+
+
+static int
+coalesce_requests(struct list_head *src, struct list_head *dst, unsigned int maxpages)
+{
+	struct nfs_page		*req = NULL;
+	unsigned int		pages = 0;
+
+	while (!list_empty(src)) {
+		struct nfs_page	*prev = req;
+
+		req = nfs_list_entry(src->next);
+		if (prev) {
+			if (req->wb_file != prev->wb_file)
+				break;
+
+			if (page_index(req->wb_page) != page_index(prev->wb_page)+1)
+				break;
+
+			if (req->wb_offset != 0)
+				break;
+		}
+		nfs_list_remove_request(req);
+		nfs_list_add_request(req, dst);
+		pages++;
+		if (req->wb_offset + req->wb_bytes != PAGE_CACHE_SIZE)
+			break;
+		if (pages >= maxpages)
+			break;
+	}
+	return pages;
+}
+
+/*
+ * Try to update any existing write request, or create one if there is none.
+ * In order to match, the request's credentials must match those of
+ * the calling process.
+ *
+ * Note: Should always be called with the Page Lock held!
+ */
+static struct nfs_page *
+nfs_update_request(struct file* file, struct page *page,
+		   unsigned long offset, unsigned int bytes)
+{
+	struct inode		*inode = file->f_dentry->d_inode;
+	struct nfs_page		*req, *new = NULL;
+	unsigned long		rqend, end;
+
+	end = offset + bytes;
+
 	for (;;) {
-		current->state = TASK_INTERRUPTIBLE;
-		retval = 0;
-		if (req->wb_flags & NFS_WRITE_COMPLETE)
+		/* Loop over all inode entries and see if we find
+		 * A request for the page we wish to update
+		 */
+		spin_lock(&nfs_wreq_lock);
+		req = _nfs_find_request(inode, page);
+		if (req) {
+			if (!nfs_lock_request(req)) {
+				spin_unlock(&nfs_wreq_lock);
+				nfs_wait_on_request(req);
+				nfs_release_request(req);
+				continue;
+			}
+			spin_unlock(&nfs_wreq_lock);
+			if (new)
+				nfs_release_request(new);
 			break;
-		retval = -ERESTARTSYS;
-		if (signalled())
+		}
+
+		req = new;
+		if (req) {
+			nfs_lock_request(req);
+			nfs_inode_add_request(inode, req);
+			spin_unlock(&nfs_wreq_lock);
+			nfs_mark_request_dirty(req);
 			break;
-		schedule();
+		}
+		spin_unlock(&nfs_wreq_lock);
+
+		/* Create the request. It's safe to sleep in this call because
+		 * we only get here if the page is locked.
+		 */
+		new = nfs_create_request(inode, file, page, offset, bytes);
+		if (!new)
+			return ERR_PTR(-ENOMEM);
+	}
+
+	/* We have a request for our page.
+	 * If the creds don't match, or the
+	 * page addresses don't match,
+	 * tell the caller to wait on the conflicting
+	 * request.
+	 */
+	rqend = req->wb_offset + req->wb_bytes;
+	if (req->wb_file != file
+	    || req->wb_page != page
+	    || !nfs_dirty_request(req)
+	    || offset > rqend || end < req->wb_offset) {
+		nfs_unlock_request(req);
+		nfs_release_request(req);
+		return ERR_PTR(-EBUSY);
 	}
-	remove_wait_queue(&req->wb_wait, &wait);
-	current->state = TASK_RUNNING;
-	rpc_clnt_sigunmask(clnt, &oldmask);
-	return retval;
+
+	/* Okay, the request matches. Update the region */
+	if (offset < req->wb_offset) {
+		req->wb_offset = offset;
+		req->wb_bytes = rqend - req->wb_offset;
+	}
+
+	if (end > rqend)
+		req->wb_bytes = end - req->wb_offset;
+
+	nfs_unlock_request(req);
+
+	return req;
 }
 
 /*
- * Write a page to the server. This will be used for NFS swapping only
- * (for now), and we currently do this synchronously only.
+ * This is the strategy routine for NFS.
+ * It is called by nfs_updatepage whenever the user wrote up to the end
+ * of a page.
+ *
+ * We always try to submit a set of requests in parallel so that the
+ * server's write code can gather writes. This is mainly for the benefit
+ * of NFSv2.
+ *
+ * We never submit more requests than we think the remote can handle.
+ * For UDP sockets, we make sure we don't exceed the congestion window;
+ * for TCP, we limit the number of requests to 8.
+ *
+ * NFS_STRATEGY_PAGES gives the minimum number of requests for NFSv2 that
+ * should be sent out in one go. This is for the benefit of NFSv2 servers
+ * that perform write gathering.
+ *
+ * FIXME: Different servers may have different sweet spots.
+ * Record the average congestion window in server struct?
  */
-int
-nfs_writepage(struct file * file, struct page *page)
+#define NFS_STRATEGY_PAGES      8
+static void
+nfs_strategy(struct file *file)
 {
-	struct dentry *dentry = file->f_dentry;
-	return nfs_writepage_sync(dentry, dentry->d_inode, page, 0, PAGE_SIZE);
+	struct inode	*inode = file->f_dentry->d_inode;
+	unsigned int	dirty, wpages;
+
+	dirty  = inode->u.nfs_i.ndirty;
+	wpages = NFS_SERVER(inode)->wpages;
+	if (NFS_PROTO(inode)->version == 2) {
+		if (dirty >= NFS_STRATEGY_PAGES * wpages)
+			nfs_flush_file(inode, file, 0, 0, 0);
+	} else {
+		if (dirty >= wpages)
+			nfs_flush_file(inode, file, 0, 0, 0);
+	}
+
+	/*
+	 * If we're running out of requests, flush out everything
+	 * in order to reduce memory useage...
+	 */
+	if (nfs_nr_requests > MAX_REQUEST_SOFT)
+		nfs_wb_file(inode, file);
 }
 
 /*
@@ -424,274 +950,562 @@
  * things with a page scheduled for an RPC call (e.g. invalidate it).
  */
 int
-nfs_updatepage(struct file *file, struct page *page, unsigned long offset, unsigned int count, int sync)
+nfs_updatepage(struct file *file, struct page *page, const char *buf, unsigned long offset, unsigned int count, int sync)
 {
-	struct dentry	*dentry = file->f_dentry;
-	struct inode	*inode = dentry->d_inode;
-	struct nfs_wreq	*req;
-	int		synchronous = sync;
-	int		retval;
+	struct dentry		*dentry = file->f_dentry;
+	struct inode		*inode = dentry->d_inode;
+	struct nfs_page		*req;
+	void			*dest;
+	int			status = 0;
 
 	dprintk("NFS:      nfs_updatepage(%s/%s %d@%ld, sync=%d)\n",
 		dentry->d_parent->d_name.name, dentry->d_name.name,
-		count, (u_long)pgoff2loff(page->index)+offset, sync);
+		count, page_offset(page)+offset, sync);
 
 	/*
-	 * Try to find a corresponding request on the writeback queue.
-	 * If there is one, we can be sure that this request is not
-	 * yet being processed, because we hold a lock on the page.
-	 *
-	 * If the request was created by us, update it. Otherwise,
-	 * transfer the page lock and flush out the dirty page now.
-	 * After returning, generic_file_write will wait on the
-	 * page and retry the update.
+	 * Look for a request corresponding to this page. If there
+	 * is one, and it belongs to another file, we flush it out
+	 * before we try to copy anything into the page. Do this
+	 * due to the lack of an ACCESS-type call in NFSv2.
+	 * Also do the same if we find a request from an existing
+	 * dropped page.
 	 */
-	req = find_write_request(inode, page);
-	if (req && req->wb_file == file && update_write_request(req, offset, count))
-		goto updated;
+	req = nfs_find_request(inode,page);
+	if (req) {
+		if (req->wb_file != file || req->wb_page != page)
+			status = nfs_wb_page(inode, page);
+		nfs_release_request(req);
+		if (status < 0)
+			goto done;
+	}
 
 	/*
 	 * If wsize is smaller than page size, update and write
 	 * page synchronously.
 	 */
-	if (NFS_SERVER(inode)->wsize < PAGE_SIZE)
-		return nfs_writepage_sync(dentry, inode, page, offset, count);
-
-	/* Create the write request. */
-	req = create_write_request(file, page, offset, count);
-	if (!req)
-		return -ENOBUFS;
-
-	/*
-	 * Ok, there's another user of this page with the new request..
-	 * The IO completion will then free the page and the dentry.
-	 */
-	atomic_inc(&page->count);
-	file->f_count++;
+	dest = (u8*)page_address(page) + offset;
+	if (dest != buf)
+		count -= copy_from_user(dest, buf, count);
+	if (!count) {
+		status = -EFAULT;
+		goto done;
+	}
+	if (NFS_SERVER(inode)->wsize < PAGE_CACHE_SIZE) {
+		status = nfs_writepage_sync(file, page, offset, count);
+		goto done;
+	}
 
-	/* Schedule request */
-	synchronous = schedule_write_request(req, sync);
+        /*
+         * Try to find an NFS request corresponding to this page
+         * and update it.
+         * If the existing request cannot be updated, we must flush
+	 * it out now.
+         */
+	do {
+		req = nfs_update_request(file, page, offset, count);
+		if (IS_ERR(req))
+			status = PTR_ERR(req);
+		if (status != -EBUSY)
+			break;
+		/* Request could not be updated. Flush it out and try again */
+		status = nfs_wb_page(inode, page);
+	} while (status >= 0);
+	if (status < 0)
+		goto done;
 
-updated:
-	if (req->wb_bytes == PAGE_SIZE)
+	if (req->wb_bytes == PAGE_CACHE_SIZE)
 		set_bit(PG_uptodate, &page->flags);
 
-	retval = count;
-	if (synchronous) {
-		int status = wait_on_write_request(req);
-		if (status) {
-			nfs_cancel_request(req);
-			retval = status;
-		} else {
-			status = req->wb_status;
-			if (status < 0)
-				retval = status;
-		}
+        status = count;         /* unless we detect an error */
 
-		if (retval < 0)
-			clear_bit(PG_uptodate, &page->flags);
-	}
+	/* If the user requested a sync write, do it now */
+	if (sync) {
+		int     error;
 
-	free_write_request(req);
-	return retval;
+		error = nfs_sync_file(inode, file, page_index(page), 1, FLUSH_SYNC|FLUSH_STABLE);
+		if (error < 0 || (error = file->f_error) < 0)
+			status = error;
+		file->f_error = 0;
+	} else {
+		/* If we wrote past the end of the page.
+		 * Call the strategy routine so it can send out a bunch
+		 * of requests.
+		 */
+		if (req->wb_offset == 0 && req->wb_bytes == PAGE_CACHE_SIZE)
+			nfs_strategy(file);
+	}
+	nfs_release_request(req);
+done:
+        dprintk("NFS:      nfs_updatepage returns %d (isize %ld)\n",
+                                                status, inode->i_size);
+	if (status < 0)
+		clear_bit(PG_uptodate, &page->flags);
+	return status;
 }
 
 /*
- * Cancel a write request. We always mark it cancelled,
- * but if it's already in progress there's no point in
- * calling rpc_exit, and we don't want to overwrite the
- * tk_status field.
- */ 
+ * Set up the argument/result storage required for the RPC call.
+ */
 static void
-nfs_cancel_request(struct nfs_wreq *req)
+nfs_write_rpcsetup(struct list_head *head, struct nfs_write_data *data)
 {
-	req->wb_flags |= NFS_WRITE_CANCELLED;
-	if (!WB_INPROGRESS(req)) {
-		rpc_exit(&req->wb_task, 0);
-		rpc_wake_up_task(&req->wb_task);
+	struct nfs_page		*req;
+	struct iovec		*iov;
+	unsigned int		count;
+
+	/* Set up the RPC argument and reply structs
+	 * NB: take care not to mess about with data->commit et al. */
+
+	iov = data->args.iov;
+	count = 0;
+	while (!list_empty(head)) {
+		struct nfs_page *req = nfs_list_entry(head->next);
+		nfs_list_remove_request(req);
+		nfs_list_add_request(req, &data->pages);
+		iov->iov_base = (void *)(page_address(req->wb_page) + req->wb_offset);
+		iov->iov_len = req->wb_bytes;
+		count += req->wb_bytes;
+		iov++;
+		data->args.nriov++;
 	}
+	req = nfs_list_entry(data->pages.next);
+	data->file = req->wb_file;
+	data->cred = req->wb_cred;
+	data->args.fh     = NFS_FH(req->wb_file->f_dentry);
+	data->args.offset = page_offset(req->wb_page) + req->wb_offset;
+	data->args.count  = count;
+	data->res.fattr   = &data->fattr;
+	data->res.count   = count;
+	data->res.verf    = &data->verf;
 }
 
+
 /*
- * Cancel all writeback requests, both pending and in progress.
+ * Create an RPC task for the given write request and kick it.
+ * The page must have been locked by the caller.
+ *
+ * It may happen that the page we're passed is not marked dirty.
+ * This is the case if nfs_updatepage detects a conflicting request
+ * that has been written but not committed.
  */
-static void
-nfs_cancel_dirty(struct inode *inode, pid_t pid)
+static int
+nfs_flush_one(struct list_head *head, struct file *file, int how)
 {
-	struct nfs_wreq *head, *req;
+	struct dentry           *dentry = file->f_dentry;
+	struct inode            *inode = dentry->d_inode;
+	struct rpc_clnt 	*clnt = NFS_CLIENT(inode);
+	struct nfs_write_data	*data;
+	struct nfs_write_data	my_data;
+	struct rpc_task		*task;
+	struct rpc_message	msg;
+	int                     flags,
+				async = !(how & FLUSH_SYNC),
+				stable = (how & FLUSH_STABLE);
+	sigset_t		oldset;
+
+
+	if (async)
+		data = nfs_writedata_alloc();
+	else {
+		memset(&my_data, 0, sizeof(my_data));
+		INIT_LIST_HEAD(&my_data.pages);
+		data = &my_data;
+	}
 
-	req = head = NFS_WRITEBACK(inode);
-	while (req != NULL) {
-		if (pid == 0 || req->wb_pid == pid)
-			nfs_cancel_request(req);
-		if ((req = WB_NEXT(req)) == head)
+	if (!data)
+		goto out_bad;
+	task = &data->task;
+
+	/* Set the initial flags for the task.  */
+	flags = (async) ? RPC_TASK_ASYNC : 0;
+
+	/* Set up the argument struct */
+	nfs_write_rpcsetup(head, data);
+	if (stable) {
+		if (!inode->u.nfs_i.ncommit)
+			data->args.stable = NFS_FILE_SYNC;
+		else
+			data->args.stable = NFS_DATA_SYNC;
+	} else
+		data->args.stable = NFS_UNSTABLE;
+
+	/* Finalize the task. */
+	rpc_init_task(task, clnt, nfs_writeback_done, flags);
+	task->tk_calldata = data;
+	/* Release requests */
+	if (async)
+		task->tk_release = nfs_writedata_release;
+
+	msg.rpc_proc = (NFS_PROTO(inode)->version == 3) ? NFS3PROC_WRITE : NFSPROC_WRITE;
+	msg.rpc_argp = &data->args;
+	msg.rpc_resp = &data->res;
+	msg.rpc_cred = data->cred;
+
+	dprintk("NFS: %4d initiated write call (req %s/%s count %d nriov %d)\n",
+		task->tk_pid, 
+		dentry->d_parent->d_name.name,
+		dentry->d_name.name,
+		data->args.count, data->args.nriov);
+
+	rpc_clnt_sigmask(clnt, &oldset);
+	rpc_call_setup(task, &msg, 0);
+	rpc_execute(task);
+	rpc_clnt_sigunmask(clnt, &oldset);
+	return 0;
+ out_bad:
+	while (!list_empty(head)) {
+		struct nfs_page *req = nfs_list_entry(head->next);
+		nfs_list_remove_request(req);
+		nfs_mark_request_dirty(req);
+		nfs_unlock_request(req);
+	}
+	return -ENOMEM;
+}
+
+static int
+nfs_flush_list(struct inode *inode, struct list_head *head, int how)
+{
+	LIST_HEAD(one_request);
+	struct nfs_page		*req;
+	int			error = 0;
+	unsigned int		pages = 0,
+				wpages = NFS_SERVER(inode)->wpages;
+
+	while (!list_empty(head)) {
+		pages += coalesce_requests(head, &one_request, wpages);
+		req = nfs_list_entry(one_request.next);
+		error = nfs_flush_one(&one_request, req->wb_file, how);
+		if (error < 0)
 			break;
 	}
+	if (error >= 0)
+		return pages;
+
+	while (!list_empty(head)) {
+		req = nfs_list_entry(head->next);
+		nfs_list_remove_request(req);
+		nfs_mark_request_dirty(req);
+		nfs_unlock_request(req);
+	}
+	return error;
 }
 
+
 /*
- * If we're waiting on somebody else's request
- * we need to increment the counter during the
- * wait so that the request doesn't disappear
- * from under us during the wait..
+ * This function is called when the WRITE call is complete.
  */
-static int FASTCALL(wait_on_other_req(struct nfs_wreq *));
-static int wait_on_other_req(struct nfs_wreq *req)
+static void
+nfs_writeback_done(struct rpc_task *task)
 {
-	int retval;
-	req->wb_count++;
-	retval = wait_on_write_request(req);
-	free_write_request(req);
-	return retval;
-}
+	struct nfs_write_data	*data = (struct nfs_write_data *) task->tk_calldata;
+	struct nfs_writeargs	*argp = &data->args;
+	struct nfs_writeres	*resp = &data->res;
+	struct dentry		*dentry = data->file->f_dentry;
+	struct inode		*inode = dentry->d_inode;
+	struct nfs_page		*req;
 
-/*
- * This writes back a set of requests according to the condition.
- *
- * If this ever gets much more convoluted, use a fn pointer for
- * the condition..
- */
-#define NFS_WB(inode, cond) { int retval = 0 ; \
-	do { \
-		struct nfs_wreq *req = NFS_WRITEBACK(inode); \
-		struct nfs_wreq *head = req; \
-		if (!req) break; \
-		for (;;) { \
-			if (!(req->wb_flags & NFS_WRITE_COMPLETE)) \
-				if (cond) break; \
-			req = WB_NEXT(req); \
-			if (req == head) goto out; \
-		} \
-		retval = wait_on_other_req(req); \
-	} while (!retval); \
-out:	return retval; \
-}
+	dprintk("NFS: %4d nfs_writeback_done (status %d)\n",
+		task->tk_pid, task->tk_status);
 
-int
-nfs_wb_all(struct inode *inode)
-{
-	NFS_WB(inode, 1);
+	/* We can't handle that yet but we check for it nevertheless */
+	if (resp->count < argp->count && task->tk_status >= 0) {
+		static unsigned long    complain = 0;
+		if (time_before(complain, jiffies)) {
+			printk(KERN_WARNING
+			       "NFS: Server wrote less than requested.\n");
+			complain = jiffies + 300 * HZ;
+		}
+		/* Can't do anything about it right now except throw
+		 * an error. */
+		task->tk_status = -EIO;
+	}
+	if (resp->verf->committed < argp->stable && task->tk_status >= 0) {
+		/* We tried a write call, but the server did not
+		 * commit data to stable storage even though we
+		 * requested it.
+		 */
+		static unsigned long    complain = 0;
+
+		if (time_before(complain, jiffies)) {
+			dprintk("NFS: faulty NFSv3 server %s:"
+				" (committed = %d) != (stable = %d)\n",
+				NFS_SERVER(inode)->hostname,
+				resp->verf->committed, argp->stable);
+			complain = jiffies + 300 * HZ;
+		}
+	}
+
+	/* Update attributes as result of writeback. */
+	nfs_write_attributes(inode, resp->fattr);
+
+	while (!list_empty(&data->pages)) {
+		req = nfs_list_entry(data->pages.next);
+		nfs_list_remove_request(req);
+
+		dprintk("NFS: write (%s/%s %d@%Ld)",
+			req->wb_file->f_dentry->d_parent->d_name.name,
+			req->wb_file->f_dentry->d_name.name,
+			req->wb_bytes,
+			(long long)(page_offset(req->wb_page) + req->wb_offset));
+
+		if (task->tk_status < 0) {
+			req->wb_file->f_error = task->tk_status;
+			nfs_inode_remove_request(req);
+			dprintk(", error = %d\n", task->tk_status);
+			goto next;
+		}
+
+		if (resp->verf->committed != NFS_UNSTABLE) {
+			nfs_inode_remove_request(req);
+			dprintk(" OK\n");
+			goto next;
+		}
+
+		memcpy(&req->wb_verf, resp->verf, sizeof(req->wb_verf));
+		req->wb_timeout = jiffies + NFS_COMMIT_DELAY;
+		nfs_mark_request_commit(req);
+		dprintk(" marked for commit\n");
+	next:
+		nfs_unlock_request(req);
+	}
 }
 
 /*
- * Write back all requests on one page - we do this before reading it.
+ * Set up the argument/result storage required for the RPC call.
  */
-int
-nfs_wb_page(struct inode *inode, struct page *page)
+static void
+nfs_commit_rpcsetup(struct list_head *head, struct nfs_write_data *data)
 {
-	NFS_WB(inode, req->wb_page == page);
+	struct nfs_page		*req;
+	struct dentry		*dentry;
+	struct inode		*inode;
+	unsigned long		start, end, len;
+
+	/* Set up the RPC argument and reply structs
+	 * NB: take care not to mess about with data->commit et al. */
+
+	end = 0;
+	start = ~0;
+	req = nfs_list_entry(head->next);
+	data->file = req->wb_file;
+	data->cred = req->wb_cred;
+	dentry = data->file->f_dentry;
+	inode = dentry->d_inode;
+	while (!list_empty(head)) {
+		struct nfs_page	*req;
+		unsigned long	rqstart, rqend;
+		req = nfs_list_entry(head->next);
+		nfs_list_remove_request(req);
+		nfs_list_add_request(req, &data->pages);
+		rqstart = page_offset(req->wb_page) + req->wb_offset;
+		rqend = rqstart + req->wb_bytes;
+		if (rqstart < start)
+			start = rqstart;
+		if (rqend > end)
+			end = rqend;
+	}
+	data->args.fh     = NFS_FH(dentry);
+	data->args.offset = start;
+	len = end - start;
+	if (end >= inode->i_size || len > (~((u32)0) >> 1))
+		len = 0;
+	data->res.count   = data->args.count = (u32)len;
+	data->res.fattr   = &data->fattr;
+	data->res.verf    = &data->verf;
 }
 
 /*
- * Write back all pending writes from one file descriptor..
+ * Commit dirty pages
  */
-int
-nfs_wb_file(struct inode *inode, struct file *file)
+static int
+nfs_commit_list(struct list_head *head, int how)
 {
-	NFS_WB(inode, req->wb_file == file);
-}
+	struct rpc_message	msg;
+	struct file		*file;
+	struct rpc_clnt		*clnt;
+	struct nfs_write_data	*data;
+	struct nfs_write_data	my_data;
+	struct rpc_task         *task;
+	struct nfs_page         *req;
+	int                     flags,
+				async = !(how & FLUSH_SYNC);
+	sigset_t		oldset;
+
+	if (async)
+		data = nfs_writedata_alloc();
+	else {
+		memset(&my_data, 0, sizeof(my_data));
+		INIT_LIST_HEAD(&my_data.pages);
+		data = &my_data;
+	}
 
-void
-nfs_inval(struct inode *inode)
-{
-	nfs_cancel_dirty(inode,0);
+	if (!data)
+		goto out_bad;
+	task = &data->task;
+
+	flags = (async) ? RPC_TASK_ASYNC : 0;
+
+	/* Set up the argument struct */
+	nfs_commit_rpcsetup(head, data);
+	req = nfs_list_entry(data->pages.next);
+	file = req->wb_file;
+	clnt = NFS_CLIENT(file->f_dentry->d_inode);
+
+	rpc_init_task(task, clnt, nfs_commit_done, flags);
+	task->tk_calldata = data;
+	if (async)
+		task->tk_release = nfs_writedata_release;
+
+	msg.rpc_proc = NFS3PROC_COMMIT;
+	msg.rpc_argp = &data->args;
+	msg.rpc_resp = &data->res;
+	msg.rpc_cred = data->cred;
+
+	dprintk("NFS: %4d initiated commit call\n", task->tk_pid);
+	rpc_clnt_sigmask(clnt, &oldset);
+	rpc_call_setup(task, &msg, 0);
+	rpc_execute(task);
+	rpc_clnt_sigunmask(clnt, &oldset);
+	return 0;
+ out_bad:
+	while (!list_empty(head)) {
+		req = nfs_list_entry(head->next);
+		nfs_list_remove_request(req);
+		nfs_mark_request_commit(req);
+		nfs_unlock_request(req);
+	}
+	return -ENOMEM;
 }
 
 /*
- * The following procedures make up the writeback finite state machinery:
- *
- * 1.	Try to lock the page if not yet locked by us,
- *	set up the RPC call info, and pass to the call FSM.
+ * COMMIT call returned
  */
 static void
-nfs_wback_begin(struct rpc_task *task)
+nfs_commit_done(struct rpc_task *task)
 {
-	struct nfs_wreq	*req = (struct nfs_wreq *) task->tk_calldata;
-	struct page	*page = req->wb_page;
-	struct file	*file = req->wb_file;
-	struct dentry	*dentry = file->f_dentry;
+	struct nfs_write_data	*data = (struct nfs_write_data *)task->tk_calldata;
+	struct nfs_writeres	*resp = &data->res;
+	struct nfs_page		*req;
+	struct dentry		*dentry = data->file->f_dentry;
+	struct inode		*inode = dentry->d_inode;
 
-	dprintk("NFS: %4d nfs_wback_begin (%s/%s, status=%d flags=%x)\n",
-		task->tk_pid, dentry->d_parent->d_name.name,
-		dentry->d_name.name, task->tk_status, req->wb_flags);
+        dprintk("NFS: %4d nfs_commit_done (status %d)\n",
+                                task->tk_pid, task->tk_status);
 
-	task->tk_status = 0;
+	nfs_refresh_inode(inode, resp->fattr);
+	while (!list_empty(&data->pages)) {
+		req = nfs_list_entry(data->pages.next);
+		nfs_list_remove_request(req);
+
+		dprintk("NFS: commit (%s/%s %d@%ld)",
+			req->wb_file->f_dentry->d_parent->d_name.name,
+			req->wb_file->f_dentry->d_name.name,
+			req->wb_bytes,
+			page_offset(req->wb_page) + req->wb_offset);
+		if (task->tk_status < 0) {
+			req->wb_file->f_error = task->tk_status;
+			nfs_inode_remove_request(req);
+			dprintk(", error = %d\n", task->tk_status);
+			goto next;
+		}
 
-	/* Setup the task struct for a writeback call */
-	req->wb_flags |= NFS_WRITE_INPROGRESS;
-	req->wb_args.fh     = NFS_FH(dentry);
-	req->wb_args.offset = pgoff2loff(page->index) + req->wb_offset;
-	req->wb_args.count  = req->wb_bytes;
-	req->wb_args.buffer = (void *) (page_address(page) + req->wb_offset);
+		/* Okay, COMMIT succeeded, apparently. Check the verifier
+		 * returned by the server against all stored verfs. */
+		if (!memcmp(req->wb_verf.verifier, data->verf.verifier, sizeof(data->verf.verifier))) {
+			/* We have a match */
+			nfs_inode_remove_request(req);
+			dprintk(" OK\n");
+			goto next;
+		}
+		/* We have a mismatch. Write the page again */
+		dprintk(" mismatch\n");
+		nfs_mark_request_dirty(req);
+	next:
+		nfs_unlock_request(req);
+	}
+}
 
-	rpc_call_setup(task, NFSPROC_WRITE, &req->wb_args, &req->wb_fattr, 0);
+int nfs_flush_file(struct inode *inode, struct file *file, unsigned long idx_start,
+		   unsigned int npages, int how)
+{
+	LIST_HEAD(head);
+	int			res,
+				error = 0;
 
-	return;
+	res = nfs_scan_dirty(inode, &head, file, idx_start, npages);
+	if (res)
+		error = nfs_flush_list(inode, &head, how);
+	if (error < 0)
+		return error;
+	return res;
 }
 
-/*
- * 2.	Collect the result
- */
-static void
-nfs_wback_result(struct rpc_task *task)
+int nfs_commit_file(struct inode *inode, struct file *file, unsigned long idx_start,
+		    unsigned int npages, int how)
 {
-	struct nfs_wreq *req = (struct nfs_wreq *) task->tk_calldata;
-	struct file	*file = req->wb_file;
-	struct page	*page = req->wb_page;
-	int		status = task->tk_status;
-	struct dentry	*dentry = file->f_dentry;
-	struct inode	*inode = dentry->d_inode;
+	LIST_HEAD(head);
+	int			res,
+				error = 0;
 
-	dprintk("NFS: %4d nfs_wback_result (%s/%s, status=%d, flags=%x)\n",
-		task->tk_pid, dentry->d_parent->d_name.name,
-		dentry->d_name.name, status, req->wb_flags);
-
-	/* Set the WRITE_COMPLETE flag, but leave WRITE_INPROGRESS set */
-	req->wb_flags |= NFS_WRITE_COMPLETE;
-	req->wb_status = status;
-
-	if (status < 0) {
-		req->wb_flags |= NFS_WRITE_INVALIDATE;
-		file->f_error = status;
-	} else if (!WB_CANCELLED(req)) {
-		struct nfs_fattr *fattr = &req->wb_fattr;
-		/* Update attributes as result of writeback. 
-		 * Beware: when UDP replies arrive out of order, we
-		 * may end up overwriting a previous, bigger file size.
-		 *
-		 * When the file size shrinks we cancel all pending
-		 * writebacks. 
-		 */
-		if (fattr->mtime.seconds >= inode->i_mtime) {
-			if (fattr->size < inode->i_size)
-				fattr->size = inode->i_size;
-
-			/* possible Solaris 2.5 server bug workaround */
-			if (inode->i_ino == fattr->fileid) {
-				/*
-				 * We expect these values to change, and
-				 * don't want to invalidate the caches.
-				 */
-				inode->i_size  = fattr->size;
-				inode->i_mtime = fattr->mtime.seconds;
-				nfs_refresh_inode(inode, fattr);
-			}
-			else
-				printk("nfs_wback_result: inode %ld, got %u?\n",
-					inode->i_ino, fattr->fileid);
-		}
+	res = nfs_scan_commit(inode, &head, file, idx_start, npages);
+	if (res)
+		error = nfs_commit_list(&head, how);
+	if (error < 0)
+		return error;
+	return res;
+}
+
+int nfs_flush_timeout(struct inode *inode, int how)
+{
+	LIST_HEAD(head);
+	int			pages,
+				error = 0;
+
+	pages = nfs_scan_dirty_timeout(inode, &head);
+	if (pages)
+		error = nfs_flush_list(inode, &head, how);
+	if (error < 0)
+		return error;
+	return pages;
+}
+
+int nfs_commit_timeout(struct inode *inode, int how)
+{
+	LIST_HEAD(head);
+	int			pages,
+				error = 0;
+
+	pages = nfs_scan_commit_timeout(inode, &head);
+	if (pages) {
+		pages += nfs_scan_commit(inode, &head, NULL, 0, 0);
+		error = nfs_commit_list(&head, how);
 	}
+	if (error < 0)
+		return error;
+	return pages;
+}
 
-	rpc_release_task(task);
+int nfs_sync_file(struct inode *inode, struct file *file, unsigned long idx_start,
+		  unsigned int npages, int how)
+{
+	int	error,
+		wait;
 
-	if (WB_INVALIDATE(req))
-		clear_bit(PG_uptodate, &page->flags);
+	wait = how & FLUSH_WAIT;
+	how &= ~FLUSH_WAIT;
 
-	__free_page(page);
-	remove_write_request(&NFS_WRITEBACK(inode), req);
-	nr_write_requests--;
-	fput(req->wb_file);
+	if (!inode && file)
+		inode = file->f_dentry->d_inode;
 
-	wake_up(&req->wb_wait);
-	free_write_request(req);
+	do {
+		error = 0;
+		if (wait)
+			error = nfs_wait_on_requests(inode, file, idx_start, npages);
+		if (error == 0)
+			error = nfs_flush_file(inode, file, idx_start, npages, how);
+		if (error == 0)
+			error = nfs_commit_file(inode, file, idx_start, npages, how);
+	} while (error > 0);
+	return error;
 }
+
Index: oldkernel/linux/fs/nfsd/Makefile
diff -u linux/fs/nfsd/Makefile:1.1.1.1 linux/fs/nfsd/Makefile:1.2
--- linux/fs/nfsd/Makefile:1.1.1.1	Wed May 31 12:33:48 2000
+++ linux/fs/nfsd/Makefile	Fri Jul  7 15:36:46 2000
@@ -11,6 +11,9 @@
 O_OBJS   := nfssvc.o nfsctl.o nfsproc.o nfsfh.o vfs.o \
 	    export.o auth.o lockd.o nfscache.o nfsxdr.o \
 	    stats.o
+ifdef CONFIG_NFSD_V3
+  O_OBJS += nfs3proc.o nfs3xdr.o
+endif
 
 M_OBJS   := $(O_TARGET)
 
Index: oldkernel/linux/fs/nfsd/export.c
diff -u linux/fs/nfsd/export.c:1.1.1.1 linux/fs/nfsd/export.c:1.2
--- linux/fs/nfsd/export.c:1.1.1.1	Wed May 31 12:33:48 2000
+++ linux/fs/nfsd/export.c	Fri Jul  7 15:36:46 2000
@@ -105,20 +105,6 @@
 	return exp;
 }
 
-/*
- * Check whether there are any exports for a device.
- */
-static int
-exp_device_in_use(kdev_t dev)
-{
-	struct svc_client *clp;
-
-	for (clp = clients; clp; clp = clp->cl_next) {
-		if (exp_find(clp, dev))
-			return 1;
-	}
-	return 0;
-}
 
 /*
  * Look up the device of the parent fs.
@@ -168,9 +154,8 @@
 					}
 				} while (NULL != (exp = exp->ex_next));
 		} while (nfsd_parentdev(&xdev));
-		if (xdentry == xdentry->d_parent) {
+		if (IS_ROOT(xdentry))
 			break;
-		}
 	} while ((xdentry = xdentry->d_parent));
 	exp = NULL;
 out:
@@ -204,7 +189,7 @@
 #endif
 						goto out;
 					}
-					if (ndentry == ndentry->d_parent)
+					if (IS_ROOT(ndentry))
 						break;
 				}
 		} while (NULL != (exp = exp->ex_next));
@@ -287,6 +272,12 @@
 		goto finish;
 
 	err = -EINVAL;
+	if (!(inode->i_sb->s_type->fs_flags & FS_REQUIRES_DEV) ||
+	    inode->i_sb->s_op->read_inode == NULL) {
+		dprintk("exp_export: export of invalid fs type.\n");
+		goto finish;
+	}
+
 	if ((parent = exp_child(clp, dev, dentry)) != NULL) {
 		dprintk("exp_export: export not valid (Rule 3).\n");
 		goto finish;
@@ -366,16 +357,6 @@
 				exp->ex_parent = unexp->ex_parent;
 	}
 
-	/*
-	 * Check whether this is the last export for this device,
-	 * and if so flush any cached dentries.
-	 */
-	if (!exp_device_in_use(unexp->ex_dev)) {
-printk("exp_do_unexport: %s last use, flushing cache\n",
-	kdevname(unexp->ex_dev));
-		nfsd_fh_flush(unexp->ex_dev);
-	}
-
 	dentry = unexp->ex_dentry;
 	inode = dentry->d_inode;
 	if (unexp->ex_dev != inode->i_dev || unexp->ex_ino != inode->i_ino)
@@ -628,7 +609,9 @@
 	{ NFSEXP_UIDMAP, {"uidmap", ""}},
 	{ NFSEXP_KERBEROS, { "kerberos", ""}},
 	{ NFSEXP_SUNSECURE, { "sunsecure", ""}},
-	{ NFSEXP_CROSSMNT, {"crossmnt", ""}},
+	{ NFSEXP_CROSSMNT, {"nohide", ""}},
+	{ NFSEXP_NOSUBTREECHECK, {"no_subtree_check", ""}},
+	{ NFSEXP_NOAUTHNLM, {"no_auth_nlm", ""}},
 	{ 0, {"", ""}}
 };
 
Index: oldkernel/linux/fs/nfsd/lockd.c
diff -u linux/fs/nfsd/lockd.c:1.1.1.1 linux/fs/nfsd/lockd.c:1.2
--- linux/fs/nfsd/lockd.c:1.1.1.1	Wed May 31 12:33:48 2000
+++ linux/fs/nfsd/lockd.c	Fri Jul  7 15:36:46 2000
@@ -30,11 +30,21 @@
 	fh.fh_handle = *f;
 	fh.fh_export = NULL;
 
-	nfserr = nfsd_open(rqstp, &fh, S_IFREG, 0, filp);
+	nfserr = nfsd_open(rqstp, &fh, S_IFREG, MAY_LOCK, filp);
 	if (!nfserr)
 		dget(filp->f_dentry);
 	fh_put(&fh);
-	return nfserr;
+        /* nlm and nfsd don't share error codes.
+         * we invent: 0 = no error
+         *            1 = stale file handle
+         *            2 = other error
+         */
+        if (nfserr == 0)
+                return 0;
+        else if (nfserr == nfserr_stale)
+                return 1;
+        else return 2;
+
 }
 
 static void
Index: oldkernel/linux/fs/nfsd/nfs3proc.c
diff -u linux/fs/nfsd/nfs3proc.c:1.1.1.1 linux/fs/nfsd/nfs3proc.c:1.2
--- linux/fs/nfsd/nfs3proc.c:1.1.1.1	Wed May 31 12:33:48 2000
+++ linux/fs/nfsd/nfs3proc.c	Fri Jul  7 15:36:46 2000
@@ -3,7 +3,7 @@
  *
  * Process version 3 NFS requests.
  *
- * Copyright (C) 1996 Olaf Kirch <okir@monad.swb.de>
+ * Copyright (C) 1996, 1997, 1998 Olaf Kirch <okir@monad.swb.de>
  */
 
 #include <linux/linkage.h>
@@ -18,19 +18,32 @@
 #include <linux/version.h>
 #include <linux/unistd.h>
 #include <linux/malloc.h>
+#include <linux/major.h>
 
 #include <linux/sunrpc/svc.h>
 #include <linux/nfsd/nfsd.h>
 #include <linux/nfsd/cache.h>
 #include <linux/nfsd/xdr3.h>
+#include <linux/nfs3.h>
 
-typedef struct svc_rqst	svc_rqst;
-typedef struct svc_buf	svc_buf;
-
 #define NFSDDBG_FACILITY		NFSDDBG_PROC
 
 #define RETURN(st)	{ resp->status = (st); return (st); }
 
+static int	nfs3_ftypes[] = {
+	0,			/* NF3NON */
+	S_IFREG,		/* NF3REG */
+	S_IFDIR,		/* NF3DIR */
+	S_IFBLK,		/* NF3BLK */
+	S_IFCHR,		/* NF3CHR */
+	S_IFLNK,		/* NF3LNK */
+	S_IFSOCK,		/* NF3SOCK */
+	S_IFIFO,		/* NF3FIFO */
+};
+
+/*
+ * Reserve room in the send buffer
+ */
 static void
 svcbuf_reserve(struct svc_buf *buf, u32 **ptr, int *len, int nr)
 {
@@ -38,6 +51,9 @@
 	*len = buf->buflen - buf->len - nr;
 }
 
+/*
+ * NULL call.
+ */
 static int
 nfsd3_proc_null(struct svc_rqst *rqstp, void *argp, void *resp)
 {
@@ -46,7 +62,6 @@
 
 /*
  * Get a file's attributes
- * N.B. After this call resp->fh needs an fh_put
  */
 static int
 nfsd3_proc_getattr(struct svc_rqst *rqstp, struct nfsd_fhandle  *argp,
@@ -54,18 +69,17 @@
 {
 	int	nfserr;
 
-	dprintk("nfsd: GETATTR  %x/%ld\n",
+	dprintk("nfsd: GETATTR(3)  %x/%ld\n",
 				SVCFH_DEV(&argp->fh),
-				SVCFH_INO(&argp->fh));
+				(long)SVCFH_INO(&argp->fh));
 
-	resp->fh = argp->fh;
+	fh_copy(&resp->fh, &argp->fh);
 	nfserr = fh_verify(rqstp, &resp->fh, 0, MAY_NOP);
 	RETURN(nfserr);
 }
 
 /*
  * Set a file's attributes
- * N.B. After this call resp->fh needs an fh_put
  */
 static int
 nfsd3_proc_setattr(struct svc_rqst *rqstp, struct nfsd3_sattrargs *argp,
@@ -73,31 +87,30 @@
 {
 	int	nfserr;
 
-	dprintk("nfsd: SETATTR  %x/%ld\n",
+	dprintk("nfsd: SETATTR(3)  %x/%ld\n",
 				SVCFH_DEV(&argp->fh),
-				SVCFH_INO(&argp->fh));
+				(long)SVCFH_INO(&argp->fh));
 
-	resp->fh = argp->fh;
+	fh_copy(&resp->fh, &argp->fh);
 	nfserr = nfsd_setattr(rqstp, &resp->fh, &argp->attrs);
 	RETURN(nfserr);
 }
 
 /*
  * Look up a path name component
- * N.B. After this call _both_ resp->dirfh and resp->fh need an fh_put
  */
 static int
 nfsd3_proc_lookup(struct svc_rqst *rqstp, struct nfsd3_diropargs *argp,
-					  struct nfsd3_lookupres *resp)
+					  struct nfsd3_diropres  *resp)
 {
 	int	nfserr;
 
-	dprintk("nfsd: LOOKUP   %x/%ld %s\n",
+	dprintk("nfsd: LOOKUP(3)   %x/%ld %s\n",
 				SVCFH_DEV(&argp->fh),
-				SVCFH_INO(&argp->fh),
+				(long)SVCFH_INO(&argp->fh),
 				argp->name);
 
-	resp->dirfh = argp->fh;
+	fh_copy(&resp->dirfh, &argp->fh);
 	nfserr = nfsd_lookup(rqstp, &resp->dirfh,
 				    argp->name,
 				    argp->len,
@@ -109,12 +122,20 @@
  * Check file access
  */
 static int
-nfsd3_proc_access(struct svc_rqst *rqstp, struct nfsd_fhandle   *argp,
+nfsd3_proc_access(struct svc_rqst *rqstp, struct nfsd3_accessargs *argp,
 					  struct nfsd3_accessres *resp)
 {
-	/* to be done */
-	resp->fh = argp->fh;
-	return nfserr_notsupp;
+	int	nfserr;
+
+	dprintk("nfsd: ACCESS(3)   %x/%ld 0x%x\n",
+				SVCFH_DEV(&argp->fh),
+				(long)SVCFH_INO(&argp->fh),
+				argp->access);
+
+	fh_copy(&resp->fh, &argp->fh);
+	resp->access = argp->access;
+	nfserr = nfsd_access(rqstp, &resp->fh, &resp->access);
+	RETURN(nfserr);
 }
 
 /*
@@ -127,23 +148,23 @@
 	u32		*path;
 	int		dummy, nfserr;
 
-	dprintk("nfsd: READLINK %x/%ld\n",
+	dprintk("nfsd: READLINK(3) %x/%ld\n",
 				SVCFH_DEV(&argp->fh),
-				SVCFH_INO(&argp->fh));
+				(long)SVCFH_INO(&argp->fh));
 
 	/* Reserve room for status, post_op_attr, and path length */
-	svcbuf_reserve(&rqstp->rq_resbuf, &path, &dummy, 1 + 22 + 1);
+	svcbuf_reserve(&rqstp->rq_resbuf, &path, &dummy,
+				1 + NFS3_POST_OP_ATTR_WORDS + 1);
 
 	/* Read the symlink. */
+	fh_copy(&resp->fh, &argp->fh);
 	resp->len = NFS3_MAXPATHLEN;
-	nfserr = nfsd_readlink(rqstp, &argp->fh, (char *) path, &resp->len);
-	fh_put(&argp->fh);
+	nfserr = nfsd_readlink(rqstp, &resp->fh, (char *) path, &resp->len);
 	RETURN(nfserr);
 }
 
 /*
  * Read a portion of a file.
- * N.B. After this call resp->fh needs an fh_put
  */
 static int
 nfsd3_proc_read(struct svc_rqst *rqstp, struct nfsd3_readargs *argp,
@@ -152,9 +173,9 @@
 	u32 *	buffer;
 	int	nfserr, avail;
 
-	dprintk("nfsd: READ %x/%ld %lu bytes at %lu\n",
+	dprintk("nfsd: READ(3) %x/%ld %lu bytes at %lu\n",
 				SVCFH_DEV(&argp->fh),
-				SVCFH_INO(&argp->fh),
+				(long)SVCFH_INO(&argp->fh),
 				(unsigned long) argp->count,
 				(unsigned long) argp->offset);
 
@@ -162,30 +183,29 @@
 	 * 1 (status) + 22 (post_op_attr) + 1 (count) + 1 (eof)
 	 * + 1 (xdr opaque byte count) = 26
 	 */
-	svcbuf_reserve(&rqstp->rq_resbuf, &buffer, &avail, 26);
+	svcbuf_reserve(&rqstp->rq_resbuf, &buffer, &avail,
+			1 + NFS3_POST_OP_ATTR_WORDS + 3);
 
-	if ((avail << 2) < argp->count) {
-		printk(KERN_NOTICE
-			"oversized read request from %08lx:%d (%d bytes)\n",
-				ntohl(rqstp->rq_addr.sin_addr.s_addr),
-				ntohs(rqstp->rq_addr.sin_port),
-				argp->count);
-		argp->count = avail;
-	}
-
 	resp->count = argp->count;
-	resp->fh    = argp->fh;
+	if ((avail << 2) < resp->count)
+		resp->count = avail << 2;
+
+	fh_copy(&resp->fh, &argp->fh);
 	nfserr = nfsd_read(rqstp, &resp->fh,
 				  argp->offset,
 				  (char *) buffer,
 				  &resp->count);
+	if (nfserr == 0) {
+		struct inode	*inode = resp->fh.fh_dentry->d_inode;
 
+		resp->eof = (argp->offset + resp->count) >= inode->i_size;
+	}
+
 	RETURN(nfserr);
 }
 
 /*
  * Write data to a file
- * N.B. After this call resp->fh needs an fh_put
  */
 static int
 nfsd3_proc_write(struct svc_rqst *rqstp, struct nfsd3_writeargs *argp,
@@ -193,19 +213,21 @@
 {
 	int	nfserr;
 
-	dprintk("nfsd: WRITE    %x/%ld %d bytes at %ld\n",
+	dprintk("nfsd: WRITE(3)    %x/%ld %d bytes at %ld%s\n",
 				SVCFH_DEV(&argp->fh),
-				SVCFH_INO(&argp->fh),
+				(long)SVCFH_INO(&argp->fh),
 				argp->len,
-				(unsigned long) argp->offset);
+				(unsigned long) argp->offset,
+				argp->stable? " stable" : "");
 
-	resp->fh = argp->fh;
+	fh_copy(&resp->fh, &argp->fh);
 	nfserr = nfsd_write(rqstp, &resp->fh,
 				   argp->offset,
 				   argp->data,
 				   argp->len,
 				   argp->stable);
 	resp->committed = argp->stable;
+	resp->count = argp->count;
 	RETURN(nfserr);
 }
 
@@ -213,20 +235,18 @@
  * With NFSv3, CREATE processing is a lot easier than with NFSv2.
  * At least in theory; we'll see how it fares in practice when the
  * first reports about SunOS compatibility problems start to pour in...
- * N.B. After this call _both_ resp->dirfh and resp->fh need an fh_put
  */
 static int
 nfsd3_proc_create(struct svc_rqst *rqstp, struct nfsd3_createargs *argp,
-					  struct nfsd3_createres  *resp)
+					  struct nfsd3_diropres   *resp)
 {
 	svc_fh		*dirfhp, *newfhp = NULL;
 	struct iattr	*attr;
-	int		mode;
 	u32		nfserr;
 
-	dprintk("nfsd: CREATE   %x/%ld %s\n",
+	dprintk("nfsd: CREATE(3)   %x/%ld %s\n",
 				SVCFH_DEV(&argp->fh),
-				SVCFH_INO(&argp->fh),
+				(long)SVCFH_INO(&argp->fh),
 				argp->name);
 
 	dirfhp = fh_copy(&resp->dirfh, &argp->fh);
@@ -243,131 +263,114 @@
 	if (!(attr->ia_valid & ATTR_MODE)) { 
 		attr->ia_valid |= ATTR_MODE;
 		attr->ia_mode = S_IFREG;
+	} else {
+		attr->ia_mode = (attr->ia_mode & ~S_IFMT) | S_IFREG;
 	}
-	mode = attr->ia_mode & ~S_IFMT;
 
 	/* Now create the file and set attributes */
-	nfserr = nfsd_create(rqstp, dirfhp, argp->name, argp->len,
-				attr, S_IFREG, 0, newfhp);
+	nfserr = nfsd_create_v3(rqstp, dirfhp, argp->name, argp->len,
+				attr, newfhp,
+				argp->createmode, argp->verf);
 
 	RETURN(nfserr);
 }
 
-/* N.B. Is nfsd3_attrstat * correct for resp?? table says "void" */
+/*
+ * Make directory. This operation is not idempotent.
+ */
 static int
-nfsd3_proc_remove(struct svc_rqst *rqstp, struct nfsd3_diropargs *argp,
-					  struct nfsd3_attrstat  *resp)
+nfsd3_proc_mkdir(struct svc_rqst *rqstp, struct nfsd3_createargs *argp,
+					 struct nfsd3_diropres   *resp)
 {
 	int	nfserr;
 
-	dprintk("nfsd: REMOVE   %x/%ld %s\n",
+	dprintk("nfsd: MKDIR(3)    %x/%ld %s\n",
 				SVCFH_DEV(&argp->fh),
-				SVCFH_INO(&argp->fh),
+				(long)SVCFH_INO(&argp->fh),
 				argp->name);
 
-	/* Is this correct?? */
-	fh_copy(&resp->fh, &argp->fh);
+	argp->attrs.ia_valid &= ~ATTR_SIZE;
+	fh_copy(&resp->dirfh, &argp->fh);
+	fh_init(&resp->fh);
+	nfserr = nfsd_create(rqstp, &resp->dirfh, argp->name, argp->len,
+				    &argp->attrs, S_IFDIR, 0, &resp->fh);
 
-	/* Unlink. -S_IFDIR means file must not be a directory */
-	nfserr = nfsd_unlink(rqstp, &resp->fh, -S_IFDIR, argp->name, argp->len);
-	/* 
-	 * N.B. Should be an fh_put here ... nfsd3_proc_rmdir has one,
-	 * or else as an xdr release function
-	 */
-	fh_put(&resp->fh);
 	RETURN(nfserr);
 }
 
 static int
-nfsd3_proc_rename(struct svc_rqst *rqstp, struct nfsd3_renameargs *argp,
-				  	 void		        *resp)
+nfsd3_proc_symlink(struct svc_rqst *rqstp, struct nfsd3_symlinkargs *argp,
+					   struct nfsd3_diropres    *resp)
 {
 	int	nfserr;
 
-	dprintk("nfsd: RENAME   %x/%ld %s -> %x/%ld %s\n",
+	dprintk("nfsd: SYMLINK(3)  %x/%ld %s -> %s\n",
 				SVCFH_DEV(&argp->ffh),
-				SVCFH_INO(&argp->ffh),
-				argp->fname,
-				SVCFH_DEV(&argp->tfh),
-				SVCFH_INO(&argp->tfh),
-				argp->tname);
+				(long)SVCFH_INO(&argp->ffh),
+				argp->fname, argp->tname);
 
-	nfserr = nfsd_rename(rqstp, &argp->ffh, argp->fname, argp->flen,
-				    &argp->tfh, argp->tname, argp->tlen);
-	fh_put(&argp->ffh);
-	fh_put(&argp->tfh);
+	fh_copy(&resp->dirfh, &argp->ffh);
+	fh_init(&resp->fh);
+	nfserr = nfsd_symlink(rqstp, &resp->dirfh, argp->fname, argp->flen,
+						   argp->tname, argp->tlen,
+						   &resp->fh, &argp->attrs);
 	RETURN(nfserr);
 }
 
+/*
+ * Make socket/fifo/device.
+ */
 static int
-nfsd3_proc_link(struct svc_rqst *rqstp, struct nfsd3_linkargs *argp,
-				void			    *resp)
+nfsd3_proc_mknod(struct svc_rqst *rqstp, struct nfsd3_mknodargs *argp,
+					 struct nfsd3_diropres  *resp)
 {
-	int	nfserr;
+	int	nfserr, type;
+	dev_t	rdev = 0;
 
-	dprintk("nfsd: LINK     %x/%ld -> %x/%ld %s\n",
-				SVCFH_DEV(&argp->ffh),
-				SVCFH_INO(&argp->ffh),
-				SVCFH_DEV(&argp->tfh),
-				SVCFH_INO(&argp->tfh),
-				argp->tname);
-
-	nfserr = nfsd_link(rqstp, &argp->tfh, argp->tname, argp->tlen,
-				  &argp->ffh);
-	fh_put(&argp->ffh);
-	fh_put(&argp->tfh);
-	RETURN(nfserr);
-}
-
-static int
-nfsd3_proc_symlink(struct svc_rqst *rqstp, struct nfsd3_symlinkargs *argp,
-				          void			  *resp)
-{
-	struct svc_fh	newfh;
-	int		nfserr;
+	dprintk("nfsd: MKNOD(3)    %x/%ld %s\n",
+				SVCFH_DEV(&argp->fh),
+				(long)SVCFH_INO(&argp->fh),
+				argp->name);
 
-	dprintk("nfsd: SYMLINK  %x/%ld %s -> %s\n",
-				SVCFH_DEV(&argp->ffh),
-				SVCFH_INO(&argp->ffh),
-				argp->fname, argp->tname);
+	fh_copy(&resp->dirfh, &argp->fh);
+	fh_init(&resp->fh);
 
-	memset(&newfh, 0, sizeof(newfh));
+	if (argp->ftype == 0 || argp->ftype >= NF3BAD)
+		return nfserr_inval;
+	if (argp->ftype == NF3CHR || argp->ftype == NF3BLK) {
+		if ((argp->ftype == NF3CHR && argp->major >= MAX_CHRDEV)
+		    || (argp->ftype == NF3BLK && argp->major >= MAX_BLKDEV)
+		    || argp->minor > 0xFF)
+			return nfserr_inval;
+		rdev = ((argp->major) << 8) | (argp->minor);
+	} else
+		if (argp->ftype != NF3SOCK && argp->ftype != NF3FIFO)
+			return nfserr_inval;
 
-	/*
-	 * Create the link, look up new file and set attrs.
-	 */
-	nfserr = nfsd_symlink(rqstp, &argp->ffh, argp->fname, argp->flen,
-						 argp->tname, argp->tlen,
-						 &newfh);
-	if (!nfserr) {
-		argp->attrs.ia_valid &= ~ATTR_SIZE;
-		nfserr = nfsd_setattr(rqstp, &newfh, &argp->attrs);
-	}
+	type = nfs3_ftypes[argp->ftype];
+	nfserr = nfsd_create(rqstp, &resp->dirfh, argp->name, argp->len,
+				    &argp->attrs, type, rdev, &resp->fh);
 
-	fh_put(&argp->ffh);
-	fh_put(&newfh);
 	RETURN(nfserr);
 }
 
 /*
- * Make directory. This operation is not idempotent.
- * N.B. After this call resp->fh needs an fh_put
+ * Remove file/fifo/socket etc.
  */
 static int
-nfsd3_proc_mkdir(struct svc_rqst *rqstp, struct nfsd3_createargs *argp,
-					struct nfsd3_diropres   *resp)
+nfsd3_proc_remove(struct svc_rqst *rqstp, struct nfsd3_diropargs *argp,
+					  struct nfsd3_attrstat  *resp)
 {
 	int	nfserr;
 
-	dprintk("nfsd: MKDIR    %x/%ld %s\n",
+	dprintk("nfsd: REMOVE(3)   %x/%ld %s\n",
 				SVCFH_DEV(&argp->fh),
-				SVCFH_INO(&argp->fh),
+				(long)SVCFH_INO(&argp->fh),
 				argp->name);
 
-	argp->attrs.ia_valid &= ~ATTR_SIZE;
-	nfserr = nfsd_create(rqstp, &argp->fh, argp->name, argp->len,
-				    &argp->attrs, S_IFDIR, 0, &resp->fh);
-	fh_put(&argp->fh);
+	/* Unlink. -S_IFDIR means file must not be a directory */
+	fh_copy(&resp->fh, &argp->fh);
+	nfserr = nfsd_unlink(rqstp, &resp->fh, -S_IFDIR, argp->name, argp->len);
 	RETURN(nfserr);
 }
 
@@ -376,65 +379,145 @@
  */
 static int
 nfsd3_proc_rmdir(struct svc_rqst *rqstp, struct nfsd3_diropargs *argp,
-				 	void		      *resp)
+					 struct nfsd3_attrstat  *resp)
 {
 	int	nfserr;
 
-	dprintk("nfsd: RMDIR    %x/%ld %s\n",
+	dprintk("nfsd: RMDIR(3)    %x/%ld %s\n",
 				SVCFH_DEV(&argp->fh),
-				SVCFH_INO(&argp->fh),
+				(long)SVCFH_INO(&argp->fh),
 				argp->name);
 
-	nfserr = nfsd_unlink(rqstp, &argp->fh, S_IFDIR, argp->name, argp->len);
-	fh_put(&argp->fh);
+	fh_copy(&resp->fh, &argp->fh);
+	nfserr = nfsd_unlink(rqstp, &resp->fh, S_IFDIR, argp->name, argp->len);
 	RETURN(nfserr);
 }
 
+static int
+nfsd3_proc_rename(struct svc_rqst *rqstp, struct nfsd3_renameargs *argp,
+					  struct nfsd3_renameres  *resp)
+{
+	int	nfserr;
+
+	dprintk("nfsd: RENAME(3)   %x/%ld %s -> %x/%ld %s\n",
+				SVCFH_DEV(&argp->ffh),
+				(long)SVCFH_INO(&argp->ffh),
+				argp->fname,
+				SVCFH_DEV(&argp->tfh),
+				(long)SVCFH_INO(&argp->tfh),
+				argp->tname);
+
+	fh_copy(&resp->ffh, &argp->ffh);
+	fh_copy(&resp->tfh, &argp->tfh);
+	nfserr = nfsd_rename(rqstp, &resp->ffh, argp->fname, argp->flen,
+				    &resp->tfh, argp->tname, argp->tlen);
+	RETURN(nfserr);
+}
+
+static int
+nfsd3_proc_link(struct svc_rqst *rqstp, struct nfsd3_linkargs *argp,
+					struct nfsd3_linkres  *resp)
+{
+	int	nfserr;
+
+	dprintk("nfsd: LINK(3)     %x/%ld -> %x/%ld %s\n",
+				SVCFH_DEV(&argp->ffh),
+				(long)SVCFH_INO(&argp->ffh),
+				SVCFH_DEV(&argp->tfh),
+				(long)SVCFH_INO(&argp->tfh),
+				argp->tname);
+
+	fh_copy(&resp->fh,  &argp->ffh);
+	fh_copy(&resp->tfh, &argp->tfh);
+	nfserr = nfsd_link(rqstp, &resp->tfh, argp->tname, argp->tlen,
+				  &resp->fh);
+	RETURN(nfserr);
+}
+
 /*
  * Read a portion of a directory.
  */
 static int
 nfsd3_proc_readdir(struct svc_rqst *rqstp, struct nfsd3_readdirargs *argp,
-					  struct nfsd3_readdirres  *resp)
+					   struct nfsd3_readdirres  *resp)
+{
+	u32 *		buffer;
+	int		nfserr, count;
+	unsigned int	want;
+
+	dprintk("nfsd: READDIR(3)  %x/%ld %d bytes at %d\n",
+				SVCFH_DEV(&argp->fh),
+				(long)SVCFH_INO(&argp->fh),
+				argp->count, (u32) argp->cookie);
+
+	/* Reserve buffer space for status, attributes and verifier */
+	svcbuf_reserve(&rqstp->rq_resbuf, &buffer, &count,
+				1 + NFS3_POST_OP_ATTR_WORDS + 2);
+
+	/* Make sure we've room for the NULL ptr & eof flag, and shrink to
+	 * client read size */
+	if ((count -= 2) > (want = (argp->count >> 2) - 2))
+		count = want;
+
+	/* Read directory and encode entries on the fly */
+	fh_copy(&resp->fh, &argp->fh);
+	nfserr = nfsd_readdir(rqstp, &resp->fh, (loff_t) argp->cookie, 
+					nfs3svc_encode_entry,
+					buffer, &count, argp->verf);
+	memcpy(resp->verf, argp->verf, 8);
+	resp->count = count;
+
+	RETURN(nfserr);
+}
+
+/*
+ * Read a portion of a directory, including file handles and attrs.
+ * For now, we choose to ignore the dircount parameter.
+ */
+static int
+nfsd3_proc_readdirplus(struct svc_rqst *rqstp, struct nfsd3_readdirargs *argp,
+					       struct nfsd3_readdirres  *resp)
 {
 	u32 *	buffer;
-	int	nfserr, count;
+	int	nfserr, count, want;
 
-	dprintk("nfsd: READDIR  %x/%ld %d bytes at %d\n",
+	dprintk("nfsd: READDIR+(3) %x/%ld %d bytes at %d\n",
 				SVCFH_DEV(&argp->fh),
-				SVCFH_INO(&argp->fh),
-				argp->count, argp->cookie);
+				(long)SVCFH_INO(&argp->fh),
+				argp->count, (u32) argp->cookie);
 
-	/* Reserve buffer space for status */
-	svcbuf_reserve(&rqstp->rq_resbuf, &buffer, &count, 1);
+	/* Reserve buffer space for status, attributes and verifier */
+	svcbuf_reserve(&rqstp->rq_resbuf, &buffer, &count,
+				1 + NFS3_POST_OP_ATTR_WORDS + 2);
 
 	/* Make sure we've room for the NULL ptr & eof flag, and shrink to
 	 * client read size */
-	if ((count -= 8) > argp->count)
-		count = argp->count;
+	if ((count -= 2) > (want = argp->count >> 2))
+		count = want;
 
 	/* Read directory and encode entries on the fly */
-	nfserr = nfsd_readdir(rqstp, &argp->fh, (loff_t) argp->cookie, 
-					nfssvc_encode_entry,
-					buffer, &count);
+	fh_copy(&resp->fh, &argp->fh);
+	nfserr = nfsd_readdir(rqstp, &resp->fh, (loff_t) argp->cookie, 
+					nfs3svc_encode_entry_plus,
+					buffer, &count, argp->verf);
+	memcpy(resp->verf, argp->verf, 8);
 	resp->count = count;
 
-	fh_put(&argp->fh);
 	RETURN(nfserr);
 }
 
 /*
- * Get file system info
+ * Get file system stats
  */
 static int
-nfsd3_proc_statfs(struct svc_rqst * rqstp, struct nfsd_fhandle   *argp,
-					  struct nfsd3_statfsres *resp)
+nfsd3_proc_fsstat(struct svc_rqst * rqstp, struct nfsd_fhandle    *argp,
+					   struct nfsd3_fsstatres *resp)
 {
 	int	nfserr;
 
-	dprintk("nfsd: STATFS   %x/%ld\n",
+	dprintk("nfsd: FSSTAT(3)   %x/%ld\n",
 				SVCFH_DEV(&argp->fh),
-				SVCFH_INO(&argp->fh));
+				(long)SVCFH_INO(&argp->fh));
 
 	nfserr = nfsd_statfs(rqstp, &argp->fh, &resp->stats);
 	fh_put(&argp->fh);
@@ -442,104 +525,165 @@
 }
 
 /*
- * NFSv2 Server procedures.
- * Only the results of non-idempotent operations are cached.
+ * Get file system info
  */
-#define nfsd3_proc_none		NULL
-#define nfssvc_encode_void	NULL
-#define nfssvc_decode_void	NULL
-#define nfssvc_release_void	NULL
-struct nfsd3_void { int dummy; };
+static int
+nfsd3_proc_fsinfo(struct svc_rqst * rqstp, struct nfsd_fhandle    *argp,
+					   struct nfsd3_fsinfores *resp)
+{
+	int	nfserr;
 
-#define PROC(name, argt, rest, relt, cache)	\
- { (svc_procfunc) nfsd3_proc_##name,	\
-   (kxdrproc_t) nfssvc_decode_##argt,	\
-   (kxdrproc_t) nfssvc_encode_##rest,	\
-   (kxdrproc_t) nfssvc_release_##relt,	\
-   sizeof(struct nfsd3_##argt),		\
-   sizeof(struct nfsd3_##rest),		\
-   0,					\
-   cache				\
- }
-struct svc_procedure		nfsd3_procedures2[18] = {
-  PROC(null,	 void,		void,		void,	 RC_NOCACHE),
-  PROC(getattr,	 fhandle,	attrstat,	fhandle, RC_NOCACHE),
-  PROC(setattr,  sattrargs,	attrstat,	fhandle, RC_REPLBUFF),
-  PROC(none,	 void,		void,		void,	 RC_NOCACHE),
-  PROC(lookup,	 diropargs,	diropres,	fhandle2,RC_NOCACHE),
-  PROC(readlink, fhandle,	readlinkres,	void,	 RC_NOCACHE),
-  PROC(read,	 readargs,	readres,	fhandle, RC_NOCACHE),
-  PROC(none,	 void,		void,		void,	 RC_NOCACHE),
-  PROC(write,	 writeargs,	attrstat,	fhandle, RC_REPLBUFF),
-  PROC(create,	 createargs,	diropres,	fhandle2,RC_REPLBUFF),
-  PROC(remove,	 diropargs,	void,/* ??*/	void,	 RC_REPLSTAT),
-  PROC(rename,	 renameargs,	void,		void,	 RC_REPLSTAT),
-  PROC(link,	 linkargs,	void,		void,	 RC_REPLSTAT),
-  PROC(symlink,	 symlinkargs,	void,		void,	 RC_REPLSTAT),
-  PROC(mkdir,	 createargs,	diropres,	fhandle, RC_REPLBUFF),
-  PROC(rmdir,	 diropargs,	void,		void,	 RC_REPLSTAT),
-  PROC(readdir,	 readdirargs,	readdirres,	void,	 RC_REPLSTAT),
-  PROC(statfs,	 fhandle,	statfsres,	void,	 RC_NOCACHE),
-};
+	dprintk("nfsd: FSINFO(3)   %x/%ld\n",
+				SVCFH_DEV(&argp->fh),
+				(long)SVCFH_INO(&argp->fh));
 
+	resp->f_rtmax  = NFSSVC_MAXBLKSIZE;
+	resp->f_rtpref = NFSSVC_MAXBLKSIZE;
+	resp->f_rtmult = PAGE_SIZE;
+	resp->f_wtmax  = NFSSVC_MAXBLKSIZE;
+	resp->f_wtpref = NFSSVC_MAXBLKSIZE;
+	resp->f_wtmult = PAGE_SIZE;
+	resp->f_dtpref = PAGE_SIZE;
+	resp->f_maxfilesize = LONG_MAX;
+	resp->f_properties = NFS3_FSF_DEFAULT;
+
+	nfserr = fh_verify(rqstp, &argp->fh, 0, MAY_NOP);
+
+	/* Check special features of the file system. May request
+	 * different read/write sizes for file systems known to have
+	 * problems with large blocks */
+	if (nfserr == 0) {
+		struct super_block *sb = argp->fh.fh_dentry->d_inode->i_sb;
+
+		/* Note that we don't care for remote fs's here */
+		if (sb->s_magic == 0x4d44 /* MSDOS_SUPER_MAGIC */) {
+			resp->f_properties = NFS3_FSF_BILLYBOY;
+		}
+	}
+
+	fh_put(&argp->fh);
+	RETURN(nfserr);
+}
 
 /*
- * Map errnos to NFS errnos.
+ * Get pathconf info for the specified file
  */
-int
-nfserrno (int errno)
+static int
+nfsd3_proc_pathconf(struct svc_rqst * rqstp, struct nfsd_fhandle      *argp,
+					     struct nfsd3_pathconfres *resp)
 {
-	static struct {
-		int	nfserr;
-		int	syserr;
-	} nfs_errtbl[] = {
-		{ NFS_OK, 0 },
-		{ NFSERR_PERM, EPERM },
-		{ NFSERR_NOENT, ENOENT },
-		{ NFSERR_IO, EIO },
-		{ NFSERR_NXIO, ENXIO },
-		{ NFSERR_ACCES, EACCES },
-		{ NFSERR_EXIST, EEXIST },
-		{ NFSERR_NODEV, ENODEV },
-		{ NFSERR_NOTDIR, ENOTDIR },
-		{ NFSERR_ISDIR, EISDIR },
-		{ NFSERR_INVAL, EINVAL },
-		{ NFSERR_FBIG, EFBIG },
-		{ NFSERR_NOSPC, ENOSPC },
-		{ NFSERR_ROFS, EROFS },
-		{ NFSERR_NAMETOOLONG, ENAMETOOLONG },
-		{ NFSERR_NOTEMPTY, ENOTEMPTY },
-#ifdef EDQUOT
-		{ NFSERR_DQUOT, EDQUOT },
-#endif
-		{ NFSERR_STALE, ESTALE },
-		{ NFSERR_WFLUSH, EIO },
-		{ -1, EIO }
-	};
-	int	i;
-
-	for (i = 0; nfs_errtbl[i].nfserr != -1; i++) {
-		if (nfs_errtbl[i].syserr == errno)
-			return htonl (nfs_errtbl[i].nfserr);
+	int	nfserr;
+
+	dprintk("nfsd: PATHCONF(3) %x/%ld\n",
+				SVCFH_DEV(&argp->fh),
+				(long)SVCFH_INO(&argp->fh));
+
+	/* Set default pathconf */
+	resp->p_link_max = 255;		/* at least */
+	resp->p_name_max = 255;		/* at least */
+	resp->p_no_trunc = 0;
+	resp->p_chown_restricted = 1;
+	resp->p_case_insensitive = 0;
+	resp->p_case_preserving = 1;
+
+	nfserr = fh_verify(rqstp, &argp->fh, 0, MAY_NOP);
+
+	if (nfserr == 0) {
+		struct super_block *sb = argp->fh.fh_dentry->d_inode->i_sb;
+
+		/* Note that we don't care for remote fs's here */
+		switch (sb->s_magic) {
+		case EXT2_SUPER_MAGIC:
+			resp->p_link_max = EXT2_LINK_MAX;
+			resp->p_name_max = EXT2_NAME_LEN;
+			break;
+		case 0x4d44:	/* MSDOS_SUPER_MAGIC */
+			resp->p_case_insensitive = 1;
+			resp->p_case_preserving  = 0;
+			break;
+		}
 	}
-	printk (KERN_INFO "nfsd: non-standard errno: %d\n", errno);
-	return nfserr_io;
+
+	fh_put(&argp->fh);
+	RETURN(nfserr);
 }
 
-#if 0
-static void
-nfsd3_dump(char *tag, u32 *buf, int len)
+
+/*
+ * Commit a file (range) to stable storage.
+ */
+static int
+nfsd3_proc_commit(struct svc_rqst * rqstp, struct nfsd3_commitargs *argp,
+					   struct nfsd3_commitres  *resp)
 {
-	int	i;
+	int	nfserr;
 
-	printk(KERN_NOTICE
-		"nfsd: %s (%d words)\n", tag, len);
+	dprintk("nfsd: COMMIT(3)   %x/%ld %d@%ld\n",
+				SVCFH_DEV(&argp->fh),
+				(long)SVCFH_INO(&argp->fh),
+				argp->count,
+				(unsigned long) argp->offset);
 
-	for (i = 0; i < len && i < 32; i += 8)
-		printk(KERN_NOTICE
-			" %08lx %08lx %08lx %08lx"
-			" %08lx %08lx %08lx %08lx\n",
-			buf[i],   buf[i+1], buf[i+2], buf[i+3],
-			buf[i+4], buf[i+5], buf[i+6], buf[i+7]);
+	if (argp->offset > NFS_OFFSET_MAX)
+		return nfserr_inval;
+
+	fh_copy(&resp->fh, &argp->fh);
+	nfserr = nfsd_commit(rqstp, &resp->fh, argp->offset, argp->count);
+
+	RETURN(nfserr);
 }
-#endif
+
+
+/*
+ * NFSv3 Server procedures.
+ * Only the results of non-idempotent operations are cached.
+ */
+#define nfs3svc_decode_voidargs		NULL
+#define nfs3svc_release_void		NULL
+#define nfs3svc_decode_fhandleargs	nfs3svc_decode_fhandle
+#define nfs3svc_encode_attrstatres	nfs3svc_encode_attrstat
+#define nfs3svc_encode_wccstatres	nfs3svc_encode_wccstat
+#define nfsd3_mkdirargs			nfsd3_createargs
+#define nfsd3_readdirplusargs		nfsd3_readdirargs
+#define nfsd3_fhandleargs		nfsd_fhandle
+#define nfsd3_fhandleres		nfsd3_attrstat
+#define nfsd3_attrstatres		nfsd3_attrstat
+#define nfsd3_wccstatres		nfsd3_attrstat
+#define nfsd3_createres			nfsd3_diropres
+#define nfsd3_voidres			nfsd3_voidargs
+struct nfsd3_voidargs { int dummy; };
+
+#define PROC(name, argt, rest, relt, cache)	\
+ { (svc_procfunc) nfsd3_proc_##name,		\
+   (kxdrproc_t) nfs3svc_decode_##argt##args,	\
+   (kxdrproc_t) nfs3svc_encode_##rest##res,	\
+   (kxdrproc_t) nfs3svc_release_##relt,		\
+   sizeof(struct nfsd3_##argt##args),		\
+   sizeof(struct nfsd3_##rest##res),		\
+   0,						\
+   cache					\
+ }
+struct svc_procedure		nfsd_procedures3[22] = {
+  PROC(null,	 void,		void,		void,	 RC_NOCACHE),
+  PROC(getattr,	 fhandle,	attrstat,	fhandle, RC_NOCACHE),
+  PROC(setattr,  sattr,		wccstat,	fhandle,  RC_REPLBUFF),
+  PROC(lookup,	 dirop,		dirop,		fhandle2, RC_NOCACHE),
+  PROC(access,	 access,	access,		fhandle,  RC_NOCACHE),
+  PROC(readlink, fhandle,	readlink,	fhandle,  RC_NOCACHE),
+  PROC(read,	 read,		read,		fhandle, RC_NOCACHE),
+  PROC(write,	 write,		write,		fhandle,  RC_REPLBUFF),
+  PROC(create,	 create,	create,		fhandle2, RC_REPLBUFF),
+  PROC(mkdir,	 mkdir,		create,		fhandle2, RC_REPLBUFF),
+  PROC(symlink,	 symlink,	create,		fhandle2, RC_REPLBUFF),
+  PROC(mknod,	 mknod,		create,		fhandle2, RC_REPLBUFF),
+  PROC(remove,	 dirop,		wccstat,	fhandle,  RC_REPLBUFF),
+  PROC(rmdir,	 dirop,		wccstat,	fhandle,  RC_REPLBUFF),
+  PROC(rename,	 rename,	rename,		fhandle,  RC_REPLBUFF),
+  PROC(link,	 link,		link,		fhandle2, RC_REPLBUFF),
+  PROC(readdir,	 readdir,	readdir,	fhandle,  RC_NOCACHE),
+  PROC(readdirplus,readdirplus,	readdir,	fhandle,  RC_NOCACHE),
+  PROC(fsstat,	 fhandle,	fsstat,		void,     RC_NOCACHE),
+  PROC(fsinfo,   fhandle,	fsinfo,		void,     RC_NOCACHE),
+  PROC(pathconf, fhandle,	pathconf,	void,     RC_NOCACHE),
+  PROC(commit,	 commit,	commit,		fhandle,  RC_NOCACHE)
+};
Index: oldkernel/linux/fs/nfsd/nfs3xdr.c
diff -u linux/fs/nfsd/nfs3xdr.c:1.1.1.1 linux/fs/nfsd/nfs3xdr.c:1.2
--- linux/fs/nfsd/nfs3xdr.c:1.1.1.1	Wed May 31 12:33:48 2000
+++ linux/fs/nfsd/nfs3xdr.c	Fri Jul  7 15:36:46 2000
@@ -3,7 +3,7 @@
  *
  * XDR support for nfsd/protocol version 3.
  *
- * Copyright (C) 1995, 1996 Olaf Kirch <okir@monad.swb.de>
+ * Copyright (C) 1995, 1996, 1997 Olaf Kirch <okir@monad.swb.de>
  */
 
 #include <linux/types.h>
@@ -17,16 +17,16 @@
 
 #define NFSDDBG_FACILITY		NFSDDBG_XDR
 
-u32	nfs_ok, nfserr_perm, nfserr_noent, nfserr_io, nfserr_nxio,
-	nfserr_acces, nfserr_exist, nfserr_nodev, nfserr_notdir,
-	nfserr_isdir, nfserr_fbig, nfserr_nospc, nfserr_rofs,
-	nfserr_nametoolong, nfserr_dquot, nfserr_stale;
-
 #ifdef NFSD_OPTIMIZE_SPACE
 # define inline
 #endif
 
 /*
+ * Size of encoded NFS3 file handle, in words
+ */
+#define NFS3_FHANDLE_WORDS	(1 + XDR_QUADLEN(sizeof(struct knfs_fh)))
+
+/*
  * Mapping of S_IF* types to NFS file types
  */
 static u32	nfs3_ftypes[] = {
@@ -37,48 +37,9 @@
 };
 
 /*
- * Initialization of NFS status variables
- */
-void
-nfs3xdr_init(void)
-{
-	static int	inited = 0;
-
-	if (inited)
-		return;
-
-	nfs_ok = htonl(NFS_OK);
-	nfserr_perm = htonl(NFSERR_PERM);
-	nfserr_noent = htonl(NFSERR_NOENT);
-	nfserr_io = htonl(NFSERR_IO);
-	nfserr_nxio = htonl(NFSERR_NXIO);
-	nfserr_acces = htonl(NFSERR_ACCES);
-	nfserr_exist = htonl(NFSERR_EXIST);
-	nfserr_nodev = htonl(NFSERR_NODEV);
-	nfserr_notdir = htonl(NFSERR_NOTDIR);
-	nfserr_isdir = htonl(NFSERR_ISDIR);
-	nfserr_fbig = htonl(NFSERR_FBIG);
-	nfserr_nospc = htonl(NFSERR_NOSPC);
-	nfserr_rofs = htonl(NFSERR_ROFS);
-	nfserr_nametoolong = htonl(NFSERR_NAMETOOLONG);
-	nfserr_dquot = htonl(NFSERR_DQUOT);
-	nfserr_stale = htonl(NFSERR_STALE);
-
-	inited = 1;
-}
-
-/*
  * XDR functions for basic NFS types
  */
 static inline u32 *
-enc64(u32 *p, u64 val)
-{
-	*p++ = (val >> 32);
-	*p++ = (val & 0xffffffff);
-	return p;
-}
-
-static inline u32 *
 dec64(u32 *p, u64 *valp)
 {
 	*valp  = ((u64) ntohl(*p++)) << 32;
@@ -103,13 +64,10 @@
 static inline u32 *
 decode_fh(u32 *p, struct svc_fh *fhp)
 {
-	if (*p++ != sizeof(struct knfs_fh))
+	if (ntohl(*p++) != sizeof(struct knfs_fh))
 		return NULL;
 
 	memcpy(&fhp->fh_handle, p, sizeof(struct knfs_fh));
-	fhp->fh_inode  = NULL;
-	fhp->fh_export = NULL;
-
 	return p + (sizeof(struct knfs_fh) >> 2);
 }
 
@@ -179,27 +137,35 @@
 		iap->ia_gid = ntohl(*p++);
 	}
 	if (*p++) {
+		u64	newsize;
+
 		iap->ia_valid |= ATTR_SIZE;
-		iap->ia_size = ntohl(*p++);
+		p = dec64(p, &newsize);
+		if (newsize <= NFS_OFFSET_MAX)
+			iap->ia_size = (u32) newsize;
+		else
+			iap->ia_size = ~(size_t) 0;
 	}
-	if ((tmp = *p++) == 1) {
+	if ((tmp = ntohl(*p++)) == 1) {	/* set to server time */
 		iap->ia_valid |= ATTR_ATIME;
-	} else if (tmp == 2) {
+	} else if (tmp == 2) {		/* set to client time */
 		iap->ia_valid |= ATTR_ATIME | ATTR_ATIME_SET;
 		iap->ia_atime = ntohl(*p++), p++;
 	}
-	if ((tmp = *p++) != 0) {
-		iap->ia_valid |= ATTR_MTIME | ATTR_MTIME_SET;
-	} else if (tmp == 2) {
+	if ((tmp = ntohl(*p++)) == 1) {	/* set to server time */
 		iap->ia_valid |= ATTR_MTIME;
+	} else if (tmp == 2) {		/* set to client time */
+		iap->ia_valid |= ATTR_MTIME | ATTR_MTIME_SET;
 		iap->ia_mtime = ntohl(*p++), p++;
 	}
 	return p;
 }
 
 static inline u32 *
-encode_fattr3(struct svc_rqst *rqstp, u32 *p, struct inode *inode)
+encode_fattr3(struct svc_rqst *rqstp, u32 *p, struct dentry *dentry)
 {
+	struct inode	*inode = dentry->d_inode;
+
 	if (!inode) {
 		printk("nfsd: NULL inode in %s:%d", __FILE__, __LINE__);
 		return NULL;
@@ -214,8 +180,17 @@
 		p = enc64(p, (u64) NFS3_MAXPATHLEN);
 	} else {
 		p = enc64(p, (u64) inode->i_size);
+	}
+	/*
+	 *  For the 'used' member, we take i_blocks if set; assuming 512-byte
+	 *  units.  Some FSs don't set this, so all we can do then is
+	 *  use the size.
+	 */
+	if (inode->i_blocks) {
+		p = enc64(p,  ((u64)inode->i_blocks)<<9 );
+	} else {
+		p = enc64(p, (u64) inode->i_size);
 	}
-	p = enc64(p, inode->i_blksize * inode->i_blocks);
 	*p++ = htonl((u32) MAJOR(inode->i_rdev));
 	*p++ = htonl((u32) MINOR(inode->i_rdev));
 	p = enc64(p, (u64) inode->i_dev);
@@ -227,19 +202,54 @@
 	return p;
 }
 
+static inline u32 *
+encode_saved_post_attr(struct svc_rqst *rqstp, u32 *p, struct svc_fh *fhp)
+{
+	struct inode	*inode = fhp->fh_dentry->d_inode;
+
+	/* Attributes to follow */
+	*p++ = xdr_one;
+
+	*p++ = htonl(nfs3_ftypes[(fhp->fh_post_mode & S_IFMT) >> 12]);
+	*p++ = htonl((u32) fhp->fh_post_mode);
+	*p++ = htonl((u32) fhp->fh_post_nlink);
+	*p++ = htonl((u32) nfsd_ruid(rqstp, fhp->fh_post_uid));
+	*p++ = htonl((u32) nfsd_rgid(rqstp, fhp->fh_post_gid));
+	if (S_ISLNK(fhp->fh_post_mode) && fhp->fh_post_size > NFS3_MAXPATHLEN) {
+		p = enc64(p, (u64) NFS3_MAXPATHLEN);
+	} else {
+		p = enc64(p, (u64) fhp->fh_post_size);
+	}
+	if (fhp->fh_post_blocks) {
+		p = enc64(p, ((u64)fhp->fh_post_blocks)<<9);
+	} else {
+		p = enc64(p, (u64) fhp->fh_post_size);
+	}
+	*p++ = htonl((u32) MAJOR(fhp->fh_post_rdev));
+	*p++ = htonl((u32) MINOR(fhp->fh_post_rdev));
+	p = enc64(p, (u64) inode->i_dev);
+	p = enc64(p, (u64) inode->i_ino);
+	p = encode_time3(p, fhp->fh_post_atime);
+	p = encode_time3(p, fhp->fh_post_mtime);
+	p = encode_time3(p, fhp->fh_post_ctime);
+
+	return p;
+}
+
 /*
  * Encode post-operation attributes.
  * The inode may be NULL if the call failed because of a stale file
  * handle. In this case, no attributes are returned.
  */
 static u32 *
-encode_post_op_attr(struct svc_rqst *rqstp, u32 *p, struct inode *inode)
+encode_post_op_attr(struct svc_rqst *rqstp, u32 *p, struct dentry *dentry)
 {
-	if (inode == NULL) {
-		*p++ = xdr_zero;
-		return p;
+	if (dentry && dentry->d_inode != NULL) {
+		*p++ = xdr_one;		/* attributes follow */
+		return encode_fattr3(rqstp, p, dentry);
 	}
-	return encode_fattr3(rqstp, p, inode);
+	*p++ = xdr_zero;
+	return p;
 }
 
 /*
@@ -248,17 +258,22 @@
 static u32 *
 encode_wcc_data(struct svc_rqst *rqstp, u32 *p, struct svc_fh *fhp)
 {
-	struct inode	*inode = fhp->fh_inode;
+	struct dentry	*dentry = fhp->fh_dentry;
 
-	if (fhp->fh_post_version == inode->i_version) {
-		*p++ = xdr_one;
-		p = enc64(p, (u64) fhp->fh_pre_size);
-		p = encode_time3(p, fhp->fh_pre_mtime);
-		p = encode_time3(p, fhp->fh_pre_ctime);
-	} else {
-		*p++ = xdr_zero;
+	if (dentry && dentry->d_inode && fhp->fh_post_saved) {
+		if (fhp->fh_pre_saved) {
+			*p++ = xdr_one;
+			p = enc64(p, (u64) fhp->fh_pre_size);
+			p = encode_time3(p, fhp->fh_pre_mtime);
+			p = encode_time3(p, fhp->fh_pre_ctime);
+		} else {
+			*p++ = xdr_zero;
+		}
+		return encode_saved_post_attr(rqstp, p, fhp);
 	}
-	return encode_post_op_attr(rqstp, p, inode);
+	/* no pre- or post-attrs */
+	*p++ = xdr_zero;
+	return encode_post_op_attr(rqstp, p, dentry);
 }
 
 /*
@@ -299,10 +314,12 @@
 					struct nfsd3_sattrargs *args)
 {
 	if (!(p = decode_fh(p, &args->fh))
-	 || !(p = decode_sattr3(p, &args->attrs))
-	 || (*p++ && !(p = decode_time3(p, &args->guardtime))))
+	 || !(p = decode_sattr3(p, &args->attrs)))
 		return 0;
 
+	if ((args->check_guard = ntohl(*p++)) != 0)
+		p = decode_time3(p, &args->guardtime);
+
 	return xdr_argsize_check(rqstp, p);
 }
 
@@ -333,10 +350,10 @@
 					struct nfsd3_readargs *args)
 {
 	if (!(p = decode_fh(p, &args->fh))
-	 || !(p = dec64(p, &args->offset))
-	 || !(p = dec64(p, &args->count)))
+	 || !(p = dec64(p, &args->offset)))
 		return 0;
 
+	args->count = ntohl(*p++);
 	return xdr_argsize_check(rqstp, p);
 }
 
@@ -345,14 +362,14 @@
 					struct nfsd3_writeargs *args)
 {
 	if (!(p = decode_fh(p, &args->fh))
-	 || !(p = dec64(p, &args->offset))
-	 || !(p = dec64(p, &args->count)))
+	 || !(p = dec64(p, &args->offset)))
 		return 0;
 
+	args->count = ntohl(*p++);
 	args->stable = ntohl(*p++);
 	args->len = ntohl(*p++);
 	args->data = (char *) p;
-	p += (args->len + 3) >> 2;
+	p += XDR_QUADLEN(args->len);
 
 	return xdr_argsize_check(rqstp, p);
 }
@@ -366,11 +383,12 @@
 		return 0;
 
 	switch (args->createmode = ntohl(*p++)) {
-	case 0: case 1:
+	case NFS3_CREATE_UNCHECKED:
+	case NFS3_CREATE_GUARDED:
 		if (!(p = decode_sattr3(p, &args->attrs)))
 			return 0;
 		break;
-	case 2:
+	case NFS3_CREATE_EXCLUSIVE:
 		args->verf = p;
 		p += 2;
 		break;
@@ -460,8 +478,9 @@
 {
 	if (!(p = decode_fh(p, &args->fh)))
 		return 0;
-	args->cookie = ntohl(*p++);
+	p = dec64(p, &args->cookie);
 	args->verf   = p; p += 2;
+	args->dircount = ~0;
 	args->count  = ntohl(*p++);
 
 	return xdr_argsize_check(rqstp, p);
@@ -473,7 +492,7 @@
 {
 	if (!(p = decode_fh(p, &args->fh)))
 		return 0;
-	args->cookie   = ntohl(*p++);
+	p = dec64(p, &args->cookie);
 	args->verf     = p; p += 2;
 	args->dircount = ntohl(*p++);
 	args->count    = ntohl(*p++);
@@ -485,9 +504,9 @@
 nfs3svc_decode_commitargs(struct svc_rqst *rqstp, u32 *p,
 					struct nfsd3_commitargs *args)
 {
-	if (!(p = decode_fh(p, &args->fh))
-	 || !(p = dec64(p, &args->offset)))
+	if (!(p = decode_fh(p, &args->fh)))
 		return 0;
+	p = dec64(p, &args->offset);
 	args->count = ntohl(*p++);
 
 	return xdr_argsize_check(rqstp, p);
@@ -496,12 +515,23 @@
 /*
  * XDR encode functions
  */
+/*
+ * There must be an encoding function for void results so svc_process
+ * will work properly.
+ */
+int
+nfs3svc_encode_voidres(struct svc_rqst *rqstp, u32 *p, void *dummy)
+{
+	return xdr_ressize_check(rqstp, p);
+}
+
 /* GETATTR */
 int
 nfs3svc_encode_attrstat(struct svc_rqst *rqstp, u32 *p,
 					struct nfsd3_attrstat *resp)
 {
-	if (!(p = encode_fattr3(rqstp, p, resp->fh.fh_inode)))
+	if (resp->status == 0
+	 && !(p = encode_fattr3(rqstp, p, resp->fh.fh_dentry)))
 		return 0;
 	return xdr_ressize_check(rqstp, p);
 }
@@ -518,15 +548,14 @@
 
 /* LOOKUP */
 int
-nfs3svc_encode_lookupres(struct svc_rqst *rqstp, u32 *p,
-					struct nfsd3_lookupres *resp)
+nfs3svc_encode_diropres(struct svc_rqst *rqstp, u32 *p,
+					struct nfsd3_diropres *resp)
 {
 	if (resp->status == 0) {
 		p = encode_fh(p, &resp->fh);
-		if (!(p = encode_fattr3(rqstp, p, resp->fh.fh_inode)))
-			return 0;
+		p = encode_post_op_attr(rqstp, p, resp->fh.fh_dentry);
 	}
-	p = encode_post_op_attr(rqstp, p, resp->dirfh.fh_inode);
+	p = encode_post_op_attr(rqstp, p, resp->dirfh.fh_dentry);
 	return xdr_ressize_check(rqstp, p);
 }
 
@@ -535,7 +564,7 @@
 nfs3svc_encode_accessres(struct svc_rqst *rqstp, u32 *p,
 					struct nfsd3_accessres *resp)
 {
-	p = encode_post_op_attr(rqstp, p, resp->fh.fh_inode);
+	p = encode_post_op_attr(rqstp, p, resp->fh.fh_dentry);
 	if (resp->status == 0)
 		*p++ = htonl(resp->access);
 	return xdr_ressize_check(rqstp, p);
@@ -546,7 +575,7 @@
 nfs3svc_encode_readlinkres(struct svc_rqst *rqstp, u32 *p,
 					struct nfsd3_readlinkres *resp)
 {
-	p = encode_post_op_attr(rqstp, p, resp->fh.fh_inode);
+	p = encode_post_op_attr(rqstp, p, resp->fh.fh_dentry);
 	if (resp->status == 0) {
 		*p++ = htonl(resp->len);
 		p += XDR_QUADLEN(resp->len);
@@ -559,7 +588,7 @@
 nfs3svc_encode_readres(struct svc_rqst *rqstp, u32 *p,
 					struct nfsd3_readres *resp)
 {
-	p = encode_post_op_attr(rqstp, p, resp->fh.fh_inode);
+	p = encode_post_op_attr(rqstp, p, resp->fh.fh_dentry);
 	if (resp->status == 0) {
 		*p++ = htonl(resp->count);
 		*p++ = htonl(resp->eof);
@@ -587,11 +616,12 @@
 /* CREATE, MKDIR, SYMLINK, MKNOD */
 int
 nfs3svc_encode_createres(struct svc_rqst *rqstp, u32 *p,
-					struct nfsd3_createres *resp)
+					struct nfsd3_diropres *resp)
 {
 	if (resp->status == 0) {
+		*p++ = xdr_one;
 		p = encode_fh(p, &resp->fh);
-		p = encode_post_op_attr(rqstp, p, resp->fh.fh_inode);
+		p = encode_post_op_attr(rqstp, p, resp->fh.fh_dentry);
 	}
 	p = encode_wcc_data(rqstp, p, &resp->dirfh);
 	return xdr_ressize_check(rqstp, p);
@@ -612,7 +642,7 @@
 nfs3svc_encode_linkres(struct svc_rqst *rqstp, u32 *p,
 					struct nfsd3_linkres *resp)
 {
-	p = encode_post_op_attr(rqstp, p, resp->fh.fh_inode);
+	p = encode_post_op_attr(rqstp, p, resp->fh.fh_dentry);
 	p = encode_wcc_data(rqstp, p, &resp->tfh);
 	return xdr_ressize_check(rqstp, p);
 }
@@ -622,73 +652,116 @@
 nfs3svc_encode_readdirres(struct svc_rqst *rqstp, u32 *p,
 					struct nfsd3_readdirres *resp)
 {
-	p = encode_post_op_attr(rqstp, p, resp->fh.fh_inode);
+	p = encode_post_op_attr(rqstp, p, resp->fh.fh_dentry);
 	if (resp->status == 0) {
 		/* stupid readdir cookie */
-		*p++ = ntohl(resp->fh.fh_inode->i_mtime);
-		*p++ = xdr_zero;
-		p = resp->list_end;
+		memcpy(p, resp->verf, 8); p += 2;
+		p += XDR_QUADLEN(resp->count);
 	}
 
 	return xdr_ressize_check(rqstp, p);
 }
 
-#define NFS3_ENTRYPLUS_BAGGAGE	((1 + 20 + 1 + NFS3_FHSIZE) << 2)
-int
-nfs3svc_encode_entry(struct readdir_cd *cd, const char *name,
-				int namlen, unsigned long offset, ino_t ino)
+/*
+ * Encode a directory entry. This one works for both normal readdir
+ * and readdirplus.
+ * The normal readdir reply requires 2 (fileid) + 1 (stringlen)
+ * + string + 2 (cookie) + 1 (next) words, i.e. 6 + strlen.
+ * 
+ * The readdirplus baggage is 1+21 words for post_op_attr, plus the
+ * file handle.
+ */
+
+#define NFS3_ENTRY_BAGGAGE	(2 + 1 + 2 + 1)
+#define NFS3_ENTRYPLUS_BAGGAGE	(1 + 21 + 1 + (NFS3_FHSIZE >> 2))
+static int
+encode_entry(struct readdir_cd *cd, const char *name,
+			int namlen, off_t offset, ino_t ino, int plus)
 {
 	u32		*p = cd->buffer;
 	int		buflen, slen, elen;
-	struct svc_fh	fh;
 
-	if (offset > ~((u64) 0))
-		return -EINVAL;
 	if (cd->offset)
-		*cd->offset = htonl(offset);
+		enc64(cd->offset, (u64) offset);
 
-	/* For readdirplus, look up the inode */
-	if (cd->plus && nfsd_lookup(cd->rqstp, cd->dirfh, name, namlen, &fh))
+	/* nfsd_readdir calls us with name == 0 when it wants us to
+	 * set the last offset entry. */
+	if (name == 0)
 		return 0;
 
+	/*
+	dprintk("encode_entry(%.*s @%ld%s)\n",
+		namlen, name, (long) offset, plus? " plus" : "");
+	 */
+
 	/* truncate filename if too long */
 	if (namlen > NFS3_MAXNAMLEN)
 		namlen = NFS3_MAXNAMLEN;
 
 	slen = XDR_QUADLEN(namlen);
-	elen = slen + (cd->plus? NFS3_ENTRYPLUS_BAGGAGE : 0);
-	if ((buflen = cd->buflen - elen - 4) < 0) {
+	elen = slen + NFS3_ENTRY_BAGGAGE
+		+ (plus? NFS3_ENTRYPLUS_BAGGAGE : 0);
+	if ((buflen = cd->buflen - elen) < 0) {
 		cd->eob = 1;
-		if (cd->plus)
-			fh_put(&fh);
 		return -EINVAL;
 	}
-	*p++ = xdr_one;			/* mark entry present */
-	*p++ = xdr_zero;		/* file id (64 bit) */
-	*p++ = htonl((u32) ino);
-	*p++ = htonl((u32) namlen);	/* name length & name */
+	*p++ = xdr_one;				   /* mark entry present */
+	p    = enc64(p, ino);			   /* file id */
+#ifdef XDR_ENCODE_STRING_TAKES_LENGTH
+	p    = xdr_encode_string(p, name, namlen); /* name length & name */
+#else
+	/* just like nfsproc.c */
+	*p++ = htonl((u32) namlen);
 	memcpy(p, name, namlen);
 	p += slen;
+#endif
+	p[slen - 1] = 0;		/* don't leak kernel data */
+
+	cd->offset = p;			/* remember pointer */
+	p = enc64(p, NFS_OFFSET_MAX);	/* offset of next entry */
 
 	/* throw in readdirplus baggage */
-	if (cd->plus) {
-		p = encode_post_op_attr(cd->rqstp, p, fh.fh_inode);
-		p = encode_fh(p, &fh);
-		fh_put(&fh);
-	}
+	if (plus) {
+		struct svc_fh	fh;
 
-	cd->offset = p;			/* remember pointer */
-	p = enc64(p, ~(u64) 0);	/* offset of next entry */
+		fh_init(&fh);
+		/* Disabled for now because of lock-up */
+		if (0 && nfsd_lookup(cd->rqstp, cd->dirfh, name, namlen, &fh) == 0) {
+			p = encode_post_op_attr(cd->rqstp, p, fh.fh_dentry);
+			p = encode_fh(p, &fh);
+			fh_put(&fh);
+		} else {
+			/* Didn't find this entry... weird.
+			 * Proceed without the attrs anf fh anyway.
+			 */
+			*p++ = 0;
+			*p++ = 0;
+		}
+	}
 
 	cd->buflen = buflen;
 	cd->buffer = p;
 	return 0;
 }
 
+int
+nfs3svc_encode_entry(struct readdir_cd *cd, const char *name,
+				int namlen, off_t offset, ino_t ino)
+{
+	return encode_entry(cd, name, namlen, offset, ino, 0);
+}
+
+int
+nfs3svc_encode_entry_plus(struct readdir_cd *cd, const char *name,
+				int namlen, off_t offset, ino_t ino)
+{
+	return encode_entry(cd, name, namlen, offset, ino, 1);
+}
+
 /* FSSTAT */
 int
-nfs3svc_encode_statfsres(struct svc_rqst *rqstp, u32 *p,
-					struct nfsd3_statfsres *resp)
+nfs3svc_encode_fsstatres(struct svc_rqst *rqstp, u32 *p,
+					struct nfsd3_fsstatres *resp)
 {
 	struct statfs	*s = &resp->stats;
 	u64		bs = s->f_bsize;
@@ -722,9 +795,9 @@
 		*p++ = htonl(resp->f_wtpref);
 		*p++ = htonl(resp->f_wtmult);
 		*p++ = htonl(resp->f_dtpref);
-		*p++ = htonl(resp->f_maxfilesize);
+		p = enc64(p, resp->f_maxfilesize);
+		*p++ = xdr_one;
 		*p++ = xdr_zero;
-		*p++ = htonl(1000000000 / HZ);
 		*p++ = htonl(resp->f_properties);
 	}
 
@@ -741,8 +814,8 @@
 	if (resp->status == 0) {
 		*p++ = htonl(resp->p_link_max);
 		*p++ = htonl(resp->p_name_max);
-		*p++ = xdr_one;	/* always reject long file names */
-		*p++ = xdr_one;	/* chown restricted */
+		*p++ = htonl(resp->p_no_trunc);
+		*p++ = htonl(resp->p_chown_restricted);
 		*p++ = htonl(resp->p_case_insensitive);
 		*p++ = htonl(resp->p_case_preserving);
 	}
@@ -769,7 +842,7 @@
  */
 int
 nfs3svc_release_fhandle(struct svc_rqst *rqstp, u32 *p,
-					struct nfsd_fhandle *resp)
+					struct nfsd3_attrstat *resp)
 {
 	fh_put(&resp->fh);
 	return 1;
@@ -777,7 +850,7 @@
 
 int
 nfs3svc_release_fhandle2(struct svc_rqst *rqstp, u32 *p,
-					struct nfsd3_fhandle2 *resp)
+					struct nfsd3_fhandle_pair *resp)
 {
 	fh_put(&resp->fh1);
 	fh_put(&resp->fh2);
Index: oldkernel/linux/fs/nfsd/nfsctl.c
diff -u linux/fs/nfsd/nfsctl.c:1.2 linux/fs/nfsd/nfsctl.c:1.3
--- linux/fs/nfsd/nfsctl.c:1.2	Wed May 31 14:52:10 2000
+++ linux/fs/nfsd/nfsctl.c	Fri Jul  7 15:36:46 2000
@@ -18,7 +18,6 @@
 #include <linux/fcntl.h>
 #include <linux/net.h>
 #include <linux/in.h>
-#include <linux/version.h>
 #include <linux/unistd.h>
 #include <linux/malloc.h>
 #include <linux/proc_fs.h>
@@ -345,7 +344,7 @@
 int
 init_module(void)
 {
-	printk(KERN_INFO "Installing knfsd (copyright (C) 1996 okir@monad.swb.de)\n");
+	printk("Installing knfsd (copyright (C) 1996 okir@monad.swb.de).\n");
 	do_nfsservctl = handle_sys_nfsservctl;
 	return 0;
 }
@@ -363,7 +362,6 @@
 	do_nfsservctl = NULL;
 	nfsd_export_shutdown();
 	nfsd_cache_shutdown();
-	nfsd_fh_free();
 	remove_proc_entry("fs/nfs/time-diff-margin", NULL);
 	remove_proc_entry("fs/nfs/exports", NULL);
 	remove_proc_entry("fs/nfs", NULL);
Index: oldkernel/linux/fs/nfsd/nfsfh.c
diff -u linux/fs/nfsd/nfsfh.c:1.3 linux/fs/nfsd/nfsfh.c:1.4
--- linux/fs/nfsd/nfsfh.c:1.3	Thu Jun  1 17:06:35 2000
+++ linux/fs/nfsd/nfsfh.c	Fri Jul  7 15:36:46 2000
@@ -5,6 +5,7 @@
  *
  * Copyright (C) 1995, 1996 Olaf Kirch <okir@monad.swb.de>
  * Portions Copyright (C) 1999 G. Allen Morris III <gam3@acm.org>
+ * Extensive rewrite by Neil Brown <neilb@cse.unsw.edu.au> Southern-Spring 1999
  */
 
 #include <linux/sched.h>
@@ -22,334 +23,50 @@
 #define NFSDDBG_FACILITY		NFSDDBG_FH
 #define NFSD_PARANOIA 1
 /* #define NFSD_DEBUG_VERBOSE 1 */
-/* #define NFSD_DEBUG_VERY_VERBOSE 1 */
 
-extern unsigned long max_mapnr;
 
-#define NFSD_FILE_CACHE 0
-#define NFSD_DIR_CACHE  1
-struct fh_entry {
-	struct dentry * dentry;
-	unsigned long reftime;
-	ino_t	ino;
-	kdev_t	dev;
-};
-
-#define NFSD_MAXFH \
-  (((nfsd_nservers + 1) >> 1) * PAGE_SIZE/sizeof(struct fh_entry))
-static struct fh_entry *filetable = NULL;
-static struct fh_entry *dirstable = NULL;
-
 static int nfsd_nr_verified = 0;
 static int nfsd_nr_put = 0;
-static unsigned long nfsd_next_expire = 0;
-
-static int add_to_fhcache(struct dentry *, int);
-struct dentry * lookup_inode(kdev_t, ino_t, ino_t);
-
-static LIST_HEAD(fixup_head);
-static LIST_HEAD(path_inuse);
-static int nfsd_nr_fixups = 0;
-static int nfsd_nr_paths = 0;
-#define NFSD_MAX_PATHS 500
-#define NFSD_MAX_FIXUPS 500
-#define NFSD_MAX_FIXUP_AGE 30*HZ
-
-struct nfsd_fixup {
-	struct list_head lru;
-	unsigned long reftime;
-	ino_t	dirino;
-	ino_t	ino;
-	kdev_t	dev;
-	ino_t	new_dirino;
-};
-
-struct nfsd_path {
-	struct list_head lru;
-	unsigned long reftime;
-	int	users;
-	ino_t	ino;
-	kdev_t	dev;
-	char	name[1];
-};
-
-static struct nfsd_fixup *
-find_cached_lookup(kdev_t dev, ino_t dirino, ino_t ino)
-{
-	struct list_head *tmp = fixup_head.next;
-
-	for (; tmp != &fixup_head; tmp = tmp->next) {
-		struct nfsd_fixup *fp;
-
-		fp = list_entry(tmp, struct nfsd_fixup, lru);
-#ifdef NFSD_DEBUG_VERY_VERBOSE
-printk("fixup %lu %lu, %lu %lu %s %s\n",
-        fp->ino, ino,
-	fp->dirino, dirino,
-	kdevname(fp->dev), kdevname(dev));
-#endif
-		if (fp->ino != ino)
-			continue;
-		if (fp->dirino != dirino)
-			continue;
-		if (fp->dev != dev)
-			continue;
-		fp->reftime = jiffies;	
-		list_del(tmp);
-		list_add(tmp, &fixup_head);
-		return fp;
-	}
-	return NULL;
-}
 
-/*
- * Save the dirino from a rename.
- */
-void
-add_to_rename_cache(ino_t new_dirino,
-                    kdev_t dev, ino_t dirino, ino_t ino)
-{
-	struct nfsd_fixup *fp;
-
-	if (dirino == new_dirino)
-		return;
-
-	fp = find_cached_lookup(dev, 
-				dirino,
-				ino);
-	if (fp) {
-		fp->new_dirino = new_dirino;
-		return;
-	}
-
-	/*
-	 * Add a new entry. The small race here is unimportant:
-	 * if another task adds the same lookup, both entries
-	 * will be consistent.
-	 */
-	fp = kmalloc(sizeof(struct nfsd_fixup), GFP_KERNEL);
-	if (fp) {
-		fp->dirino = dirino;
-		fp->ino = ino;
-		fp->dev = dev;
-		fp->new_dirino = new_dirino;
-		list_add(&fp->lru, &fixup_head);
-		nfsd_nr_fixups++;
-	}
-}
-
-/*
- * Save the dentry pointer from a successful lookup.
- */
 
-static void free_fixup_entry(struct nfsd_fixup *fp)
-{
-	list_del(&fp->lru);
-#ifdef NFSD_DEBUG_VERY_VERBOSE
-printk("free_rename_entry: %lu->%lu %lu/%s\n",
-		fp->dirino,
-		fp->new_dirino,
-		fp->ino,
-		kdevname(fp->dev),
-		(jiffies - fp->reftime));
-#endif
-	kfree(fp);
-	nfsd_nr_fixups--;
-}
-
-/*
- * Copy a dentry's path into the specified buffer.
- */
-static int copy_path(char *buffer, struct dentry *dentry, int namelen)
-{
-	char *p, *b = buffer;
-	int result = 0, totlen = 0, len; 
-
-	while (1) {
-		struct dentry *parent;
-		dentry = dentry->d_covers;
-		parent = dentry->d_parent;
-		len = dentry->d_name.len;
-		p = (char *) dentry->d_name.name + len;
-		totlen += len;
-		if (totlen > namelen)
-			goto out;
-		while (len--)
-			*b++ = *(--p);
-		if (dentry == parent)
-			break;
-		dentry = parent;
-		totlen++;
-		if (totlen > namelen)
-			goto out;
-		*b++ = '/';
-	}
-	*b = 0;
-
-	/*
-	 * Now reverse in place ...
-	 */
-	p = buffer;
-	while (p < b) {
-		char c = *(--b);
-		*b = *p;
-		*p++ = c;
-	} 
-	result = 1;
-out:
-	return result;
-}
-
-/*
- * Add a dentry's path to the path cache.
- */
-static int add_to_path_cache(struct dentry *dentry)
-{
-	struct inode *inode = dentry->d_inode;
-	struct dentry *this;
-	struct nfsd_path *new;
-	int len, result = 0;
-
-#ifdef NFSD_DEBUG_VERBOSE
-printk("add_to_path_cache: caching %s/%s\n",
-dentry->d_parent->d_name.name, dentry->d_name.name);
-#endif
-	/*
-	 * Get the length of the full pathname.
-	 */
-restart:
-	len = 0;
-	this = dentry;
-	while (1) {
-		struct dentry *parent;
-		this = this->d_covers;
-		parent = this->d_parent;
-		len += this->d_name.len;
-		if (this == parent)
-			break;
-		this = parent;
-		len++;
-	}
-	/*
-	 * Allocate a structure to hold the path.
-	 */
-	new = kmalloc(sizeof(struct nfsd_path) + len, GFP_KERNEL);
-	if (new) {
-		new->users = 0;	
-		new->reftime = jiffies;	
-		new->ino = inode->i_ino;
-		new->dev = inode->i_dev;
-		result = copy_path(new->name, dentry, len);
-		if (!result)
-			goto retry;
-		list_add(&new->lru, &path_inuse);
-		nfsd_nr_paths++;
-#ifdef NFSD_DEBUG_VERBOSE
-printk("add_to_path_cache: added %s, paths=%d\n", new->name, nfsd_nr_paths);
-#endif
-	}
-	return result;
-
-	/*
-	 * If the dentry's path length changed, just try again.
-	 */
-retry:
-	kfree(new);
-	printk(KERN_DEBUG "add_to_path_cache: path length changed, retrying\n");
-	goto restart;
-}
-
-/*
- * Search for a path entry for the specified (dev, inode).
- */
-static struct nfsd_path *get_path_entry(kdev_t dev, ino_t ino)
-{
-	struct nfsd_path *pe;
-	struct list_head *tmp;
-
-	for (tmp = path_inuse.next; tmp != &path_inuse; tmp = tmp->next) {
-		pe = list_entry(tmp, struct nfsd_path, lru);
-		if (pe->ino != ino)
-			continue;
-		if (pe->dev != dev)
-			continue;
-		list_del(tmp);
-		list_add(tmp, &path_inuse);
-		pe->users++;
-		pe->reftime = jiffies;
-#ifdef NFSD_PARANOIA
-printk("get_path_entry: found %s for %s/%ld\n", pe->name, kdevname(dev), ino);
-#endif
-		return pe;
-	}
-	return NULL;
-}
-
-static void put_path(struct nfsd_path *pe)
-{
-	pe->users--;
-}
-
-static void free_path_entry(struct nfsd_path *pe)
-{
-	if (pe->users)
-		printk(KERN_DEBUG "free_path_entry: %s in use, users=%d\n",
-			pe->name, pe->users);
-	list_del(&pe->lru);
-	kfree(pe);
-	nfsd_nr_paths--;
-}
-
 struct nfsd_getdents_callback {
-	struct nfsd_dirent *dirent;
-	ino_t dirino;		/* parent inode number */
-	int found;		/* dirent inode matched? */
+	struct qstr *name;	/* name that was found. name->name already points to a buffer */
+	unsigned long ino;	/* the inum we are looking for */
+	int found;		/* inode matched? */
 	int sequence;		/* sequence counter */
 };
 
-struct nfsd_dirent {
-	ino_t ino;		/* preset to desired entry */
-	int len;
-	char name[256];
-};
-
 /*
- * A rather strange filldir function to capture the inode number
- * for the second entry (the parent inode) and the name matching
- * the specified inode number.
+ * A rather strange filldir function to capture
+ * the name matching the specified inode number.
  */
-static int filldir_one(void * __buf, const char * name, int len, 
+static int filldir_one(void * __buf, const char * name, int len,
 			off_t pos, ino_t ino)
 {
 	struct nfsd_getdents_callback *buf = __buf;
-	struct nfsd_dirent *dirent = buf->dirent;
+	struct qstr *qs = buf->name;
+	char *nbuf = (char*)qs->name; /* cast is to get rid of "const" */
 	int result = 0;
 
 	buf->sequence++;
-#ifdef NFSD_DEBUG_VERY_VERBOSE
-printk("filldir_one: seq=%d, ino=%lu, name=%s\n", buf->sequence, ino, name);
+#ifdef NFSD_DEBUG_VERBOSE
+dprintk("filldir_one: seq=%d, ino=%ld, name=%s\n", buf->sequence, ino, name);
 #endif
-	if (buf->sequence == 2) {
-		buf->dirino = ino;
-		goto out;
-	}
-	if (dirent->ino == ino) {
-		dirent->len = len;
-		memcpy(dirent->name, name, len);
-		dirent->name[len] = '\0';
+	if (buf->ino == ino) {
+		qs->len = len;
+		memcpy(nbuf, name, len);
+		nbuf[len] = '\0';
 		buf->found = 1;
 		result = -1;
 	}
-out:
 	return result;
 }
 
 /*
- * Read a directory and return the parent inode number and the name
- * of the specified entry. The dirent must be initialized with the
- * inode number of the desired entry.
+ * Read a directory and return the name of the specified entry.  
+ * i_sem is already down().
  */
-static int get_parent_ino(struct dentry *dentry, struct nfsd_dirent *dirent)
+static int get_ino_name(struct dentry *dentry, struct qstr *name, unsigned long ino)
 {
 	struct inode *dir = dentry->d_inode;
 	int error;
@@ -372,15 +89,13 @@
 	if (!file.f_op->readdir)
 		goto out_close;
 
-	buffer.dirent = dirent;
-	buffer.dirino = 0;
+	buffer.name = name;
+	buffer.ino = ino;
 	buffer.found = 0;
 	buffer.sequence = 0;
 	while (1) {
 		int old_seq = buffer.sequence;
-		down(&dir->i_sem);
 		error = file.f_op->readdir(&file, &buffer, filldir_one);
-		up(&dir->i_sem);
 		if (error < 0)
 			break;
 
@@ -391,7 +106,6 @@
 		if (old_seq == buffer.sequence)
 			break;
 	}
-	dirent->ino = buffer.dirino;
 
 out_close:
 	if (file.f_op->release)
@@ -400,707 +114,380 @@
 	return error;
 }
 
-/*
- * Look up a dentry given inode and parent inode numbers.
- *
- * This relies on the ability of a Unix-like filesystem to return
- * the parent inode of a directory as the ".." (second) entry.
- *
- * This could be further optimized if we had an efficient way of
- * searching for a dentry given the inode: as we walk up the tree,
- * it's likely that a dentry exists before we reach the root.
+/* this should be provided by each filesystem in an nfsd_operations interface as
+ * iget isn't really the right interface
  */
-struct dentry * lookup_inode(kdev_t dev, ino_t dirino, ino_t ino)
+static struct dentry *nfsd_iget(struct super_block *sb, unsigned long ino, __u32 generation)
 {
-	struct super_block *sb;
-	struct dentry *root, *dentry, *result;
-	struct inode *dir;
-	char *name;
-	unsigned long page;
-	ino_t root_ino;
-	int error;
-	struct nfsd_dirent dirent;
-
-	result = ERR_PTR(-ENOMEM);
-	page = __get_free_page(GFP_KERNEL);
-	if (!page)
-		goto out;
 
-	/*
-	 * Get the root dentry for the device.
+	/* 
+	 * ext2fs' read_inode has been strengthed to return a bad_inode if 
+	 * the inode had been deleted.
+	 *
+	 * Currently we don't know the generation for parent directory, 
+	 * so a generation of 0 means "accept any"
 	 */
-	result = ERR_PTR(-ENOENT);
-	sb = get_super(dev);
-	if (!sb)
-		goto out_page;
-	root = dget(sb->s_root);
-	root_ino = root->d_inode->i_ino; /* usually 2 */
-
-	name = (char *) page + PAGE_SIZE;
-	*(--name) = 0;
-
-	/*
-	 * Walk up the tree to construct the name string.
-	 * When we reach the root inode, look up the name
-	 * relative to the root dentry.
-	 */
-	while (1) {
-		if (ino == root_ino) {
-			if (*name == '/')
-				name++;
-			/*
-			 * Note: this dput()s the root dentry.
-			 */
-			result = lookup_dentry(name, root, 0);
-			break;
-		}
-
-		/*
-		 *  Fix for /// bad export bug: if dirino is the root,
-		 *  get the real root dentry rather than creating a temporary
-		 *  "root" dentry.  XXX We could extend this to use
-		 *  any existing dentry for the located 'dir', but all
-		 *  of this code is going to be completely rewritten soon,
-		 *  so I won't bother. 
-		 */
-
-		if (dirino == root_ino) {
-			dentry = dget(root);
-		}
-		else {
-			result = ERR_PTR(-ENOENT);
-			dir = iget_in_use(sb, dirino);
-			if (!dir)
-				goto out_root;
-			dentry = d_alloc_root(dir, NULL);
-			if (!dentry)
-				goto out_iput;
-		}
-
-		/*
-		 * Get the name for this inode and the next parent inode.
-		 */
-		dirent.ino = ino;
-		error = get_parent_ino(dentry, &dirent);
-		result = ERR_PTR(error);
-		dput(dentry);
-		if (error)
-			goto out_root;
-		/*
-		 * Prepend the name to the buffer.
-		 */
-		result = ERR_PTR(-ENAMETOOLONG);
-		name -= (dirent.len + 1);
-		if ((unsigned long) name <= page)
-			goto out_root;
-		memcpy(name + 1, dirent.name, dirent.len);
-		*name = '/';
-
-		/*
-		 * Make sure we can't get caught in a loop ...
-		 */
-		if (dirino == dirent.ino && dirino != root_ino) {
-			printk(KERN_DEBUG 
-			       "lookup_inode: looping?? (ino=%ld, path=%s)\n",
-				dirino, name);	
-			goto out_root;
-		}
-		ino = dirino;
-		dirino = dirent.ino;
-	}
-
-out_page:
-	free_page(page);
-out:
-	return result;
-
-	/*
-	 * Error exits ...
-	 */
-out_iput:
-	result = ERR_PTR(-ENOMEM);
-	iput(dir);
-out_root:
-	dput(root);
-	goto out_page;
-}
-
-/*
- * Find an entry in the cache matching the given dentry pointer.
- */
-static struct fh_entry *find_fhe(struct dentry *dentry, int cache,
-				struct fh_entry **empty)
-{
-	struct fh_entry *fhe;
-	int i, found = (empty == NULL) ? 1 : 0;
-
-	if (!dentry)
-		goto out;
-
-	fhe = (cache == NFSD_FILE_CACHE) ? &filetable[0] : &dirstable[0];
-	for (i = 0; i < NFSD_MAXFH; i++, fhe++) {
-		if (fhe->dentry == dentry) {
-			fhe->reftime = jiffies;
-			return fhe;
-		}
-		if (!found && !fhe->dentry) {
-			found = 1;
-			*empty = fhe;
-		}
-	}
-out:
-	return NULL;
-}
-
-/*
- * Expire a cache entry.
- */
-static void expire_fhe(struct fh_entry *empty, int cache)
-{
-	struct dentry *dentry = empty->dentry;
-
-#ifdef NFSD_DEBUG_VERBOSE
-printk("expire_fhe: expiring %s %s/%s, d_count=%d, ino=%lu\n",
-(cache == NFSD_FILE_CACHE) ? "file" : "dir",
-dentry->d_parent->d_name.name, dentry->d_name.name, dentry->d_count,empty->ino);
-#endif
-	empty->dentry = NULL;	/* no dentry */
-	/*
-	 * Add the parent to the dir cache before releasing the dentry,
-	 * and check whether to save a copy of the dentry's path.
-	 */
-	if (dentry != dentry->d_parent) {
-		struct dentry *parent = dget(dentry->d_parent);
-		if (add_to_fhcache(parent, NFSD_DIR_CACHE))
-			nfsd_nr_verified++;
-		else
-			dput(parent);
-		/*
-		 * If we're expiring a directory, copy its path.
-		 */
-		if (cache == NFSD_DIR_CACHE) {
-			add_to_path_cache(dentry);
-		}
-	}
-	dput(dentry);
-	nfsd_nr_put++;
-}
-
-/*
- * Look for an empty slot, or select one to expire.
- */
-static void expire_slot(int cache)
-{
-	struct fh_entry *fhe, *empty = NULL;
-	unsigned long oldest = -1;
-	int i;
-
-	fhe = (cache == NFSD_FILE_CACHE) ? &filetable[0] : &dirstable[0];
-	for (i = 0; i < NFSD_MAXFH; i++, fhe++) {
-		if (!fhe->dentry)
-			goto out;
-		if (fhe->reftime < oldest) {
-			oldest = fhe->reftime;
-			empty = fhe;
-		}
-	}
-	if (empty)
-		expire_fhe(empty, cache);
-
-out:
-	return;
-}
-
-/*
- * Expire any cache entries older than a certain age.
- */
-static void expire_old(int cache, int age)
-{
-	struct fh_entry *fhe;
-	int i;
-
-#ifdef NFSD_DEBUG_VERY_VERBOSE
-printk("expire_old: expiring %s older than %d\n",
-(cache == NFSD_FILE_CACHE) ? "file" : "dir", age);
-#endif
-	fhe = (cache == NFSD_FILE_CACHE) ? &filetable[0] : &dirstable[0];
-	for (i = 0; i < NFSD_MAXFH; i++, fhe++) {
-		if (!fhe->dentry)
-			continue;
-		if ((jiffies - fhe->reftime) > age)
-			expire_fhe(fhe, cache);
-	}
-
-	/*
-	 * Trim the fixup cache ...
-	 */
-	while (nfsd_nr_fixups > NFSD_MAX_FIXUPS) {
-		struct nfsd_fixup *fp;
-		fp = list_entry(fixup_head.prev, struct nfsd_fixup, lru);
-		if ((jiffies - fp->reftime) < NFSD_MAX_FIXUP_AGE)
-			break;
-		free_fixup_entry(fp);
-	}
-
-	/*
-	 * Trim the path cache ...
-	 */
-	while (nfsd_nr_paths > NFSD_MAX_PATHS) {
-		struct nfsd_path *pe;
-		pe = list_entry(path_inuse.prev, struct nfsd_path, lru);
-		if (pe->users)
-			break;
-		free_path_entry(pe);
-	}
-}
-
-/*
- * Add a dentry to the file or dir cache.
- *
- * Note: As NFS file handles must have an inode, we don't accept
- * negative dentries.
- */
-static int add_to_fhcache(struct dentry *dentry, int cache)
-{
-	struct fh_entry *fhe, *empty = NULL;
-	struct inode *inode = dentry->d_inode;
-
+	struct inode *inode;
+	struct list_head *lp;
+	struct dentry *result;
+	inode = iget_in_use(sb, ino);
 	if (!inode) {
-#ifdef NFSD_PARANOIA
-printk("add_to_fhcache: %s/%s rejected, no inode!\n",
-dentry->d_parent->d_name.name, dentry->d_name.name);
-#endif
-		return 0;
-	}
+		dprintk("nfsd_iget: failed to find ino: %lu on %s\n",
+			ino, bdevname(sb->s_dev));
+		return ERR_PTR(-ESTALE);
+	}
+	if (is_bad_inode(inode)
+	    || (generation && inode->i_generation != generation)
+		) {
+		/* we didn't find the right inode.. */
+		dprintk("fh_verify: Inode %lu, Bad count: %d %d or version  %u %u\n",
+			inode->i_ino,
+			inode->i_nlink, inode->i_count,
+			inode->i_generation,
+			generation);
 
-repeat:
-	fhe = find_fhe(dentry, cache, &empty);
-	if (fhe) {
-		return 0;
+		iput(inode);
+		return ERR_PTR(-ESTALE);
 	}
-
-	/*
-	 * Not found ... make a new entry.
+	/* now to find a dentry.
+	 * If possible, get a well-connected one
 	 */
-	if (empty) {
-		empty->dentry = dentry;
-		empty->reftime = jiffies;
-		empty->ino = inode->i_ino;
-		empty->dev = inode->i_dev;
-		return 1;
-	}
-
-	expire_slot(cache);
-	goto repeat;
-}
-
-/*
- * Find an entry in the dir cache for the specified inode number.
- */
-static struct fh_entry *find_fhe_by_ino(kdev_t dev, ino_t ino)
-{
-	struct fh_entry * fhe = &dirstable[0];
-	int i;
-
-	for (i = 0; i < NFSD_MAXFH; i++, fhe++) {
-		if (fhe->ino == ino && fhe->dev == dev) {
-			fhe->reftime = jiffies;
-			return fhe;
+	for (lp = inode->i_dentry.next; lp != &inode->i_dentry ; lp=lp->next) {
+		result = list_entry(lp,struct dentry, d_alias);
+		if (! (result->d_flags & DCACHE_NFSD_DISCONNECTED)) {
+			dget(result);
+			iput(inode);
+			return result;
 		}
 	}
-	return NULL;
+	result = d_alloc_root(inode, NULL);
+	if (result == NULL) {
+		iput(inode);
+		return ERR_PTR(-ENOMEM);
+	}
+	result->d_flags |= DCACHE_NFSD_DISCONNECTED;
+	d_rehash(result); /* so a dput won't loose it */
+	return result;
 }
 
-/*
- * Find the (directory) dentry with the specified (dev, inode) number.
- * Note: this leaves the dentry in the cache.
+/* this routine links an IS_ROOT dentry into the dcache tree.  It gains "parent"
+ * as a parent and "name" as a name
+ * It should possibly go in dcache.c
  */
-static struct dentry *find_dentry_by_ino(kdev_t dev, ino_t ino)
+int d_splice(struct dentry *target, struct dentry *parent, struct qstr *name)
 {
-	struct fh_entry *fhe;
-	struct nfsd_path *pe;
-	struct dentry * dentry;
-
-#ifdef NFSD_DEBUG_VERBOSE
-printk("find_dentry_by_ino: looking for inode %ld\n", ino);
-#endif
-	/*
-	 * Special case: inode number 2 is the root inode,
-	 * so we can use the root dentry for the device.
-	 */
-	if (ino == 2) {
-		struct super_block *sb = get_super(dev);
-		if (sb) {
+	struct dentry *tdentry;
 #ifdef NFSD_PARANOIA
-printk("find_dentry_by_ino: getting root dentry for %s\n", kdevname(dev));
-#endif
-			if (sb->s_root) {
-				dentry = dget(sb->s_root);
-				goto out;
-			} else {
+	if (!IS_ROOT(target))
+		printk("nfsd: d_splice with no-root target: %s/%s\n", parent->d_name.name, name->name);
+	if (!(target->d_flags & DCACHE_NFSD_DISCONNECTED))
+		printk("nfsd: d_splice with non-DISCONNECTED target: %s/%s\n", parent->d_name.name, name->name);
+#endif
+	name->hash = full_name_hash(name->name, name->len);
+	tdentry = d_alloc(parent, name);
+	if (tdentry == NULL)
+		return -ENOMEM;
+	d_move(target, tdentry);
+
+	/* tdentry will have been made a "child" of target (the parent of target)
+	 * make it an IS_ROOT instead
+	 */
+	list_del(&tdentry->d_child);
+	tdentry->d_parent = tdentry;
+	d_rehash(target);
+	dput(tdentry);
+
+	/* if parent is properly connected, then we can assert that
+	 * the children are connected, but it must be a singluar (non-forking)
+	 * branch
+	 */
+	if (!(parent->d_flags & DCACHE_NFSD_DISCONNECTED)) {
+		while (target) {
+			target->d_flags &= ~DCACHE_NFSD_DISCONNECTED;
+			parent = target;
+			if (list_empty(&parent->d_subdirs))
+				target = NULL;
+			else {
+				target = list_entry(parent->d_subdirs.next, struct dentry, d_child);
 #ifdef NFSD_PARANOIA
-				printk("find_dentry_by_ino: %s has no root??\n",
-					kdevname(dev));
+				/* must be only child */
+				if (target->d_child.next != &parent->d_subdirs
+				    || target->d_child.prev != &parent->d_subdirs)
+					printk("nfsd: d_splice found non-singular disconnected branch: %s/%s\n",
+					       parent->d_name.name, target->d_name.name);
 #endif
 			}
 		}
 	}
+	return 0;
+}
 
-	/*
-	 * Search the dentry cache ...
-	 */
-	fhe = find_fhe_by_ino(dev, ino);
-	if (fhe) {
-		dentry = dget(fhe->dentry);
-		goto out;
-	}
-	/*
-	 * Search the path cache ...
-	 */
-	dentry = NULL;
-	pe = get_path_entry(dev, ino);
-	if (pe) {
-		struct dentry *res;
-		res = lookup_dentry(pe->name, NULL, 0);
-		if (!IS_ERR(res)) {
-			struct inode *inode = res->d_inode;
-			if (inode && inode->i_ino == ino &&
-				     inode->i_dev == dev) {
-				dentry = res;
-#ifdef NFSD_PARANOIA
-printk("find_dentry_by_ino: found %s/%s, ino=%ld\n",
-dentry->d_parent->d_name.name, dentry->d_name.name, ino);
-#endif
-				if (add_to_fhcache(dentry, NFSD_DIR_CACHE)) {
-					dget(dentry);
-					nfsd_nr_verified++;
-				}
-				put_path(pe);
-			} else {
-				dput(res);
-				put_path(pe);
-				/* We should delete it from the cache. */
-				free_path_entry(pe);
+/* this routine finds the dentry of the parent of a given directory
+ * it should be in the filesystem accessed by nfsd_operations
+ * it assumes lookup("..") works.
+ */
+struct dentry *nfsd_findparent(struct dentry *child)
+{
+	struct dentry *tdentry, *pdentry;
+	tdentry = d_alloc(child, &(const struct qstr) {"..", 2, 0});
+	if (!tdentry)
+		return ERR_PTR(-ENOMEM);
+
+	/* I'm going to assume that if the returned dentry is different, then
+	 * it is well connected.  But nobody returns different dentrys do they?
+	 */
+	pdentry = child->d_inode->i_op->lookup(child->d_inode, tdentry);
+	d_drop(tdentry); /* we never want ".." hashed */
+	if (!pdentry) {
+		/* I don't want to return a ".." dentry.
+		 * I would prefer to return an unconnected "IS_ROOT" dentry,
+		 * though a properly connected dentry is even better
+		 */
+		/* if first or last of alias list is not tdentry, use that
+		 * else make a root dentry
+		 */
+		struct list_head *aliases = &tdentry->d_inode->i_dentry;
+		if (aliases->next != aliases) {
+			pdentry = list_entry(aliases->next, struct dentry, d_alias);
+			if (pdentry == tdentry)
+				pdentry = list_entry(aliases->prev, struct dentry, d_alias);
+			if (pdentry == tdentry)
+				pdentry = NULL;
+			if (pdentry) dget(pdentry);
+		}
+		if (pdentry == NULL) {
+			pdentry = d_alloc_root(igrab(tdentry->d_inode), NULL);
+			if (pdentry) {
+				pdentry->d_flags |= DCACHE_NFSD_DISCONNECTED;
+				d_rehash(pdentry);
 			}
-		} else {
-#ifdef NFSD_PARANOIA
-printk("find_dentry_by_ino: %s lookup failed\n", pe->name);
-#endif
-			put_path(pe);
-			/* We should delete it from the cache. */
-			free_path_entry(pe);
 		}
+		if (pdentry == NULL)
+			pdentry = ERR_PTR(-ENOMEM);
 	}
-out:
-	return dentry;
+	dput(tdentry); /* it is not hashed, it will be discarded */
+	return pdentry;
 }
 
-/*
- * Look for an entry in the file cache matching the dentry pointer,
- * and verify that the (dev, inode) numbers are correct. If found,
- * the entry is removed from the cache.
- */
-static struct dentry *find_dentry_in_fhcache(struct knfs_fh *fh)
+static struct dentry *splice(struct dentry *child, struct dentry *parent)
 {
-/* FIXME: this must use the dev/ino/dir_ino triple. */ 
-#if 0
-	struct fh_entry * fhe;
-
-	fhe = find_fhe(fh->fh_dcookie, NFSD_FILE_CACHE, NULL);
-	if (fhe) {
-		struct dentry *parent, *dentry;
-		struct inode *inode;
-
-		dentry = fhe->dentry;
-		inode = dentry->d_inode;
+	int err = 0;
+	struct qstr qs;
+	char namebuf[256];
+	struct list_head *lp;
+	struct dentry *tmp;
+	/* child is an IS_ROOT (anonymous) dentry, but it is hypothesised that
+	 * it should be a child of parent.
+	 * We see if we can find a name and, if we can - splice it in.
+	 * We hold the i_sem on the parent the whole time to try to follow 
+	 * locking protocols.
+	 */
+	qs.name = namebuf;
+	down(&parent->d_inode->i_sem);
 
-		if (!inode) {
-#ifdef NFSD_PARANOIA
-printk("find_dentry_in_fhcache: %s/%s has no inode!\n",
-dentry->d_parent->d_name.name, dentry->d_name.name);
-#endif
+	/* Now, things might have changed while we waited.
+	 * Possibly a friendly filesystem found child and spliced it in in 
+	 * response to a lookup (though nobody does this yet).  
+	 * In this case, just succeed.
+	 */
+	if (child->d_parent == parent) goto out;
+	/* Possibly a new dentry has been made for this child->d_inode in 
+	 * parent by a lookup.  In this case return that dentry. 
+	 * caller must notice and act accordingly
+	 */
+	for (lp = child->d_inode->i_dentry.next; lp != &child->d_inode->i_dentry ; lp=lp->next) {
+		tmp = list_entry(lp,struct dentry, d_alias);
+		if (tmp->d_parent == parent) {
+			child = dget(tmp);
 			goto out;
 		}
-		if (inode->i_ino != u32_to_ino_t(fh->fh_ino))
-			goto out;
- 		if (inode->i_dev != u32_to_kdev_t(fh->fh_dev))
-			goto out;
-
-		fhe->dentry = NULL;
-		fhe->ino = 0;
-		fhe->dev = 0;
-		nfsd_nr_put++;
-		/*
-		 * Make sure the parent is in the dir cache ...
-		 */
-		parent = dget(dentry->d_parent);
-		if (add_to_fhcache(parent, NFSD_DIR_CACHE))
-			nfsd_nr_verified++;
-		else
-			dput(parent);
-		return dentry;
 	}
-out:
-#endif
-	return NULL;
-}
-
-/*
- * Look for an entry in the parent directory with the specified
- * inode number.
- */
-static struct dentry *lookup_by_inode(struct dentry *parent, ino_t ino)
-{
-	struct dentry *dentry;
-	int error;
-	struct nfsd_dirent dirent;
-
-	/*
-	 * Search the directory for the inode number.
+	/* well, if we can find a name for child in parent, it should be 
+	 * safe to splice it in 
 	 */
-	dirent.ino = ino;
-	error = get_parent_ino(parent, &dirent);
-	if (error) {
-#ifdef NFSD_PARANOIA_EXTREME
-printk("lookup_by_inode: ino %ld not found in %s\n", ino, parent->d_name.name);
-#endif
-		goto no_entry;
-	}
-#ifdef NFSD_PARANOIA_EXTREME
-printk("lookup_by_inode: found %s\n", dirent.name);
-#endif
-
-	dentry = lookup_dentry(dirent.name, parent, 0);
-	if (!IS_ERR(dentry)) {
-		if (dentry->d_inode && dentry->d_inode->i_ino == ino)
-			goto out;
-#ifdef NFSD_PARANOIA_EXTREME
-printk("lookup_by_inode: %s/%s inode mismatch??\n",
-parent->d_name.name, dentry->d_name.name);
-#endif
-		dput(dentry);
-	} else {
-#ifdef NFSD_PARANOIA_EXTREME
-printk("lookup_by_inode: %s lookup failed, error=%ld\n",
-dirent.name, PTR_ERR(dentry));
-#endif
+	err = get_ino_name(parent, &qs, child->d_inode->i_ino);
+	if (err)
+		goto out;
+	tmp = d_lookup(parent, &qs);
+	if (tmp) {
+		/* Now that IS odd.  I wonder what it means... */
+		err = -EEXIST;
+		printk("nfsd-fh: found a name that I didn't expect: %s/%s\n", parent->d_name.name, qs.name);
+		dput(tmp);
+		goto out;
 	}
-
-no_entry:
-	dentry = NULL;
-out:
-	return dentry;
+	err = d_splice(child, parent, &qs);
+	dprintk("nfsd_fh: found name %s for ino %ld\n", child->d_name.name, child->d_inode->i_ino);
+ out:
+	up(&parent->d_inode->i_sem);
+	if (err)
+		return ERR_PTR(err);
+	else
+		return child;
 }
 
 /*
- * Search the fix-up list for a dentry from a prior lookup.
+ * This is the basic lookup mechanism for turning an NFS file handle
+ * into a dentry.
+ * We use nfsd_iget and if that doesn't return a suitably connected dentry,
+ * we try to find the parent, and the parent of that and so-on until a
+ * connection if made.
  */
-static ino_t nfsd_cached_lookup(struct knfs_fh *fh)
-{
-	struct nfsd_fixup *fp;
-
-	fp = find_cached_lookup(u32_to_kdev_t(fh->fh_dev),
-				u32_to_ino_t(fh->fh_dirino),
-				u32_to_ino_t(fh->fh_ino));
-	if (fp)
-		return fp->new_dirino;
-	return 0;
-}
-
-void
-expire_all(void)
+static struct dentry *
+find_fh_dentry(struct super_block *sb, struct knfs_fh *fh, int needpath)
 {
- 	if (time_after_eq(jiffies, nfsd_next_expire)) {
- 		expire_old(NFSD_FILE_CACHE,  5*HZ);
- 		expire_old(NFSD_DIR_CACHE , 60*HZ);
- 		nfsd_next_expire = jiffies + 5*HZ;
- 	}
-}
+	struct dentry *dentry, *result = NULL;
+	struct dentry *tmp;
+	int  found =0;
+	int err;
+	/* the sb->s_nfsd_free_path_sem semaphore is needed to make sure that only one unconnected (free)
+	 * dcache path ever exists, as otherwise two partial paths might get
+	 * joined together, which would be very confusing.
+	 * If there is ever an unconnected non-root directory, then this lock
+	 * must be held.
+	 */
 
-/* 
- * Free cache after unlink/rmdir.
- */
-void
-expire_by_dentry(struct dentry *dentry)
-{
-	struct fh_entry *fhe;
 
-	fhe = find_fhe(dentry, NFSD_FILE_CACHE, NULL);
-	if (fhe) {
-		expire_fhe(fhe, NFSD_FILE_CACHE);
-	}
-	fhe = find_fhe(dentry, NFSD_DIR_CACHE, NULL);
-	if (fhe) {
-		expire_fhe(fhe, NFSD_DIR_CACHE);
+	nfsdstats.fh_lookup++;
+	/*
+	 * Attempt to find the inode.
+	 */
+ retry:
+	result = nfsd_iget(sb, fh->fh_ino, fh->fh_generation);
+	err = PTR_ERR(result);
+	if (IS_ERR(result))
+		goto err_out;
+	err = -ESTALE;
+	if (!result) {
+		dprintk("find_fh_dentry: No inode found.\n");
+		goto err_out;
 	}
-}
+	if (! (result->d_flags & DCACHE_NFSD_DISCONNECTED))
+		return result;
 
-/*
- * The is the basic lookup mechanism for turning an NFS file handle 
- * into a dentry. There are several levels to the search:
- * (1) Look for the dentry pointer the short-term fhcache,
- *     and verify that it has the correct inode number.
- *
- * (2) Try to validate the dentry pointer in the file handle,
- *     and verify that it has the correct inode number. If this
- *     fails, check for a cached lookup in the fix-up list and
- *     repeat step (2) using the new dentry pointer.
- *
- * (3) Look up the dentry by using the inode and parent inode numbers
- *     to build the name string. This should succeed for any Unix-like
- *     filesystem.
- *
- * (4) Search for the parent dentry in the dir cache, and then
- *     look for the name matching the inode number.
- *
- * (5) The most general case ... search the whole volume for the inode.
- *
- * If successful, we return a dentry with the use count incremented.
- *
- * Note: steps (4) and (5) above are probably unnecessary now that (3)
- * is working. Remove the code once this is verified ...
- */
-static struct dentry *
-find_fh_dentry(struct knfs_fh *fh)
-{
-	struct super_block *sb;
-	struct dentry *dentry, *parent;
-	struct inode * inode;
-	struct list_head *lst;
-	int looked_up = 0, retry = 0;
-	ino_t dirino;
+	/* result is now an anonymous dentry, which may be adequate as it 
+	 * stands, or else will get spliced into the dcache tree */
 
-	/*
-	 * Stage 1: Look for the dentry in the short-term fhcache.
-	 */
-	dentry = find_dentry_in_fhcache(fh);
-	if (dentry) {
-		nfsdstats.fh_cached++;
-		goto out;
+	if (!S_ISDIR(result->d_inode->i_mode) && ! needpath) {
+		nfsdstats.fh_anon++;
+		return result;
 	}
-	/*
-	 * Stage 2: Attempt to find the inode.
+
+	/* It's a directory, or we are required to confirm the file's
+	 * location in the tree.
 	 */
-	sb = get_super(fh->fh_dev);
-	if (NULL == sb) {
-		printk("find_fh_dentry: No SuperBlock for device %s.",
-		       kdevname(fh->fh_dev));
-		dentry = NULL;
-		goto out;
-	}
+	dprintk("nfs_fh: need to look harder for %d/%d\n",sb->s_dev,fh->fh_ino);
+	down(&sb->s_nfsd_free_path_sem);
 
-	dirino = u32_to_ino_t(fh->fh_dirino);
-	inode = iget_in_use(sb, fh->fh_ino);
-	if (!inode) {
-		dprintk("find_fh_dentry: No inode found.\n");
-		goto out_five;
-	}
-	goto check;
-recheck:
-	if (!inode) {
-		dprintk("find_fh_dentry: No inode found.\n");
-		goto out_three;
+	/* claiming the semaphore might have allow things to get fixed up */
+	if (! (result->d_flags & DCACHE_NFSD_DISCONNECTED)) {
+		up(&sb->s_nfsd_free_path_sem);
+		return result;
 	}
-check:
-	for (lst = inode->i_dentry.next;
-	     lst != &inode->i_dentry;
-	     lst = lst->next) {
-		dentry = list_entry(lst, struct dentry, d_alias);
-
-/* if we are looking up a directory then we don't need the parent! */
-		if (!dentry ||
-		    !dentry->d_parent ||
-		    !dentry->d_parent->d_inode) {
-printk("find_fh_dentry: Found a useless inode %lu\n", inode->i_ino);
-			continue;
-		}
-		if (dentry->d_parent->d_inode->i_ino != dirino)
-			continue;
 
-		dget(dentry);
-		iput(inode);
-#ifdef NFSD_DEBUG_VERBOSE
-		printk("find_fh_dentry: Found%s %s/%s filehandle dirino = %lu, %lu\n",
-		       retry ? " Renamed" : "",
-		       dentry->d_parent->d_name.name,
-		       dentry->d_name.name,
-		       dentry->d_parent->d_inode->i_ino,
-		       dirino);
-#endif
-		goto out;
-	} /* for inode->i_dentry */
 
-	/*
-	 * Before proceeding to a lookup, check for a rename
-	 */
-	if (!retry && (dirino = nfsd_cached_lookup(fh))) {
-		dprintk("find_fh_dentry: retry with %lu\n", dirino);
-		retry = 1;
-		goto recheck;
+	found = 0;
+	if (!S_ISDIR(result->d_inode->i_mode)) {
+		nfsdstats.fh_nocache_nondir++;
+		if (fh->fh_dirino == 0)
+			goto err_result; /* don't know how to find parent */
+		else {
+			/* need to iget fh->fh_dirino and make sure this 
+			 * inode is in that directory 
+			 */
+			dentry = nfsd_iget(sb, fh->fh_dirino, 0);
+			err = PTR_ERR(dentry);
+			if (IS_ERR(dentry))
+				goto err_result;
+			err = -ESTALE;
+			if (!dentry->d_inode
+			    || !S_ISDIR(dentry->d_inode->i_mode)) {
+				goto err_dentry;
+			}
+			if ((!dentry->d_flags & DCACHE_NFSD_DISCONNECTED))
+				found = 1;
+			tmp = splice(result, dentry);
+			err = PTR_ERR(tmp);
+			if (IS_ERR(tmp))
+				goto err_dentry;
+			if (tmp != result) {
+				/* it is safe to just use tmp instead, but 
+				 * we must discard result first 
+				 */
+				d_drop(result);
+				dput(result);
+				result = tmp;
+				/* If !found, then this is really wierd, 
+				 * but it shouldn't hurt */
+			}
+		}
+	} else {
+		nfsdstats.fh_nocache_dir++;
+		dentry = dget(result);
 	}
 
-	iput(inode);
+	while(!found) {
+		/* LOOP INVARIANT */
+		/* haven't found a place in the tree yet, but we do have a 
+		 * free path from dentry down to result, and dentry is a 
+		 * directory.  Have a hold on dentry and result 
+		 */
+		struct dentry *pdentry;
+		struct inode *parent;
 
-	dprintk("find_fh_dentry: dirino not found %lu\n", dirino);
+		pdentry = nfsd_findparent(dentry);
+		err = PTR_ERR(pdentry);
+		if (IS_ERR(pdentry))
+			goto err_dentry;
+		parent = pdentry->d_inode;
+		err = -EACCES;
+		if (!parent) {
+			dput(pdentry);
+			goto err_dentry;
+		}
 
-out_three:
+		if (!(dentry->d_flags & DCACHE_NFSD_DISCONNECTED))
+			found = 1;
 
-	/*
-	 * Stage 3: Look up the dentry based on the inode and parent inode
-	 * numbers. This should work for all Unix-like filesystems.
-	 */
-	looked_up = 1;
-	dentry = lookup_inode(u32_to_kdev_t(fh->fh_dev),
-			      u32_to_ino_t(fh->fh_dirino),
-			      u32_to_ino_t(fh->fh_ino));
-	if (!IS_ERR(dentry)) {
-		struct inode * inode = dentry->d_inode;
-#ifdef NFSD_DEBUG_VERBOSE
-printk("find_fh_dentry: looked up %s/%s\n",
-       dentry->d_parent->d_name.name, dentry->d_name.name);
-#endif
-		if (inode && inode->i_ino == u32_to_ino_t(fh->fh_ino)) {
-			nfsdstats.fh_lookup++;
-			goto out;
+		tmp = splice(dentry, pdentry);
+		if (tmp != dentry) {
+			/* Something wrong.  We need to drop the whole 
+			 * dentry->result path whatever it was
+			 */
+			struct dentry *d;
+			for (d=result ; d ; d=(d->d_parent == d)?NULL:d->d_parent)
+				d_drop(d);
+		}
+		if (IS_ERR(tmp)) {
+			err = PTR_ERR(tmp);
+			dput(pdentry);
+			goto err_dentry;
 		}
-#ifdef NFSD_PARANOIA
-printk("find_fh_dentry: %s/%s lookup mismatch!\n",
-       dentry->d_parent->d_name.name, dentry->d_name.name);
-#endif
+		if (tmp != dentry) {
+			/* we lost a race,  try again
+			 */
+			dput(tmp);
+			dput(dentry);
+			dput(result);	/* this will discard the whole free path, so we can up the semaphore */
+			up(&sb->s_nfsd_free_path_sem);
+			goto retry;
+		}
 		dput(dentry);
-	}
-
-	/*
-	 * Stage 4: Look for the parent dentry in the fhcache ...
-	 */
-	parent = find_dentry_by_ino(u32_to_kdev_t(fh->fh_dev),
-				    u32_to_ino_t(fh->fh_dirino));
-	if (parent) {
-		/*
-		 * ... then search for the inode in the parent directory.
-		 */
-		dget(parent);
-		dentry = lookup_by_inode(parent, u32_to_ino_t(fh->fh_ino));
-		dput(parent);
-		if (dentry)
-			goto out;
+		dentry = pdentry;
 	}
-
-out_five:
+	dput(dentry);
+	up(&sb->s_nfsd_free_path_sem);
+	return result;
 
-	/*
-	 * Stage 5: Search the whole volume, Yea Right.
-	 */
-#ifdef NFSD_PARANOIA_EXTREME
-printk("find_fh_dentry: %s/%u dir/%u not found!\n",
-       kdevname(u32_to_kdev_t(fh->fh_dev)), fh->fh_ino, fh->fh_dirino);
-#endif
-	dentry = NULL;
-	nfsdstats.fh_stale++;
-	
-out:
-	expire_all();
-	return dentry;
+err_dentry:
+	dput(dentry);
+err_result:
+	dput(result);
+	up(&sb->s_nfsd_free_path_sem);
+err_out:
+	if (err == -ESTALE)
+		nfsdstats.fh_stale++;
+	return ERR_PTR(err);
 }
 
 /*
@@ -1108,6 +495,9 @@
  *
  * Note that the file handle dentry may need to be freed even after
  * an error return.
+ *
+ * This is only called at the start of an nfsproc call, so fhp points to
+ * a svc_fh which is all 0 except for the over-the-wire file handle.
  */
 u32
 fh_verify(struct svc_rqst *rqstp, struct svc_fh *fhp, int type, int access)
@@ -1125,69 +515,80 @@
 		fh->fh_ino,
 		fh->fh_dirino);
 
-	if (fhp->fh_dverified)
-		goto check_type;
-	/*
-	 * Look up the export entry.
-	 */
-	error = nfserr_stale;
-	exp = exp_get(rqstp->rq_client,
-		      u32_to_kdev_t(fh->fh_xdev),
-		      u32_to_ino_t(fh->fh_xino));
-	if (!exp) {
-		/* export entry revoked */
-		nfsdstats.fh_stale++;
-		goto out;
-	}
+	if (!fhp->fh_dverified) {
+		/*
+		 * Security: Check that the fh is internally consistant 
+		 * (from <gam3@acm.org>)
+		 */
+		if (fh->fh_dev != fh->fh_xdev) {
+			printk("fh_verify: Security: export on other device (%s, %s).\n",
+			       kdevname(fh->fh_dev), kdevname(fh->fh_xdev));
+			error = nfserr_stale;
+			nfsdstats.fh_stale++;
+			goto out;
+		}
 
-	/* Check if the request originated from a secure port. */
-	error = nfserr_perm;
-	if (!rqstp->rq_secure && EX_SECURE(exp)) {
-		printk(KERN_WARNING
-			"nfsd: request from insecure port (%08x:%d)!\n",
-				ntohl(rqstp->rq_addr.sin_addr.s_addr),
-				ntohs(rqstp->rq_addr.sin_port));
-		goto out;
-	}
+		/*
+		 * Look up the export entry.
+		 */
+		error = nfserr_stale; 
+		exp = exp_get(rqstp->rq_client,
+			      u32_to_kdev_t(fh->fh_xdev),
+			      u32_to_ino_t(fh->fh_xino));
+		if (!exp) {
+			/* export entry revoked */
+			nfsdstats.fh_stale++;
+			goto out;
+		}
+
+		/* Check if the request originated from a secure port. */
+		error = nfserr_perm;
+		if (!rqstp->rq_secure && EX_SECURE(exp)) {
+			printk(KERN_WARNING
+			       "nfsd: request from insecure port (%08x:%d)!\n",
+			       ntohl(rqstp->rq_addr.sin_addr.s_addr),
+			       ntohs(rqstp->rq_addr.sin_port));
+			goto out;
+		}
 
-	/* Set user creds if we haven't done so already. */
-	nfsd_setuser(rqstp, exp);
+		/* Set user creds if we haven't done so already. */
+		nfsd_setuser(rqstp, exp);
 
-	/*
-	 * Look up the dentry using the NFS file handle.
-	 */
-	error = nfserr_noent;
-	dentry = find_fh_dentry(fh);
-	if (!dentry) {
-		/* Usually inode number 0 shouldn't appear in any
-		   filehandle. We want to know who has it. */
-		if (!fh->fh_ino || !fh->fh_dirino)
-			printk("fh_verify: not found %s: exp %s/%u file (%s/%u dir %u) coookie 0x%lx, generation 0x%x\n",
-				rqstp->rq_client->cl_ident,
-				kdevname(fh->fh_xdev),
-				fh->fh_xino,
-				kdevname(fh->fh_dev),
-				fh->fh_ino,
-				fh->fh_dirino,
-				(long) fh->fh_dcookie,
-				fh->fh_generation);
-		goto out;
-	}
-	if (IS_ERR(dentry)) {
-		error = nfserrno(-PTR_ERR(dentry));
-		goto out;
+		/*
+		 * Look up the dentry using the NFS file handle.
+		 */
+
+		dentry = find_fh_dentry(exp->ex_dentry->d_inode->i_sb,
+					fh,
+					!(exp->ex_flags & NFSEXP_NOSUBTREECHECK));
+
+		if (IS_ERR(dentry)) {
+			error = nfserrno(-PTR_ERR(dentry));
+			goto out;
+		}
+#ifdef NFSD_PARANOIA
+		if (S_ISDIR(dentry->d_inode->i_mode) &&
+		    (dentry->d_flags & DCACHE_NFSD_DISCONNECTED)) {
+			printk("nfsd: find_fh_dentry returned a DISCONNECTED directory: %s/%s\n",
+			       dentry->d_parent->d_name.name, dentry->d_name.name);
+		}
+#endif
+
+		fhp->fh_dentry = dentry;
+		fhp->fh_export = exp;
+		fhp->fh_dverified = 1;
+		nfsd_nr_verified++;
+	} else {
+		/* just rechecking permissions
+		 * (e.g. nfsproc_create calls fh_verify, then nfsd_create 
+		 * does as well)
+		 */
+		dprintk("nfsd: fh_verify - just checking\n");
+		dentry = fhp->fh_dentry;
+		exp = fhp->fh_export;
 	}
 
-	/*
-	 * Note:  it's possible the returned dentry won't be the one in the
-	 * file handle.  We can correct the file handle for our use, but
-	 * unfortunately the client will keep sending the broken one.  Let's
-	 * hope the lookup will keep patching things up.
-	 */
-	fhp->fh_dentry = dentry;
-	fhp->fh_export = exp;
-	fhp->fh_dverified = 1;
-	nfsd_nr_verified++;
+	inode = dentry->d_inode;
 
 	/* Type check. The correct error return for type mismatches
 	 * does not seem to be generally agreed upon. SunOS seems to
@@ -1195,39 +596,7 @@
 	 * spec says this is incorrect (implementation notes for the
 	 * write call).
 	 */
-check_type:
-	dentry = fhp->fh_dentry;
-	inode = dentry->d_inode;
-	error = nfserr_stale;
-	/* On a heavily loaded SMP machine, more than one identical
-	   requests may run at the same time on different processors.
-	   One thread may get here with unfinished fh after another
-	   thread just fetched the inode. It doesn't make any senses
-	   to check fh->fh_generation here since it has not been set
-	   yet. In that case, we shouldn't send back the stale
-	   filehandle to the client. We use fh->fh_dcookie to indicate
-	   if fh->fh_generation is set or not. If fh->fh_dcookie is
-	   not set, don't return stale filehandle. */
-	if (fh->fh_dcookie) {
-		if (inode->i_generation != fh->fh_generation) {
-			dprintk("fh_verify: Bad version %lu %u %u: 0x%x, 0x%x\n",
-				inode->i_ino,
-				inode->i_generation,
-				fh->fh_generation,
-				type, access);
-			nfsdstats.fh_stale++;
-			goto out;
-		}
-	}
-	else {
-		/* We get here when inode is fetched by other
-		   threads. We just use what is in there. */
-		fh->fh_ino = ino_t_to_u32(inode->i_ino);
-		fh->fh_generation = inode->i_generation;
-		fh->fh_dcookie = (struct dentry *)0xfeebbaca;
-		nfsdstats.fh_concurrent++;
-	}
-	exp = fhp->fh_export;
+
 	if (type > 0 && (inode->i_mode & S_IFMT) != type) {
 		error = (type == S_IFDIR)? nfserr_notdir : nfserr_isdir;
 		goto out;
@@ -1241,38 +610,37 @@
 	 * Security: Check that the export is valid for dentry <gam3@acm.org>
 	 */
 	error = 0;
-	if (fh->fh_dev != fh->fh_xdev) {
-		printk("fh_verify: Security: export on other device (%s, %s).\n",
-		       kdevname(fh->fh_dev), kdevname(fh->fh_xdev));
-		error = nfserr_stale;
-		nfsdstats.fh_stale++;
-	} else if (exp->ex_dentry != dentry) {
-		struct dentry *tdentry = dentry;
 
-		do {
-			tdentry = tdentry->d_parent;
-			if (exp->ex_dentry == tdentry)
-				break;
-			/* executable only by root and we can't be root */
-			if (current->fsuid
-			    && !(tdentry->d_inode->i_uid
-			         && (tdentry->d_inode->i_mode & S_IXUSR))
-			    && !(tdentry->d_inode->i_gid
-				 && (tdentry->d_inode->i_mode & S_IXGRP))
-			    && !(tdentry->d_inode->i_mode & S_IXOTH)
-			    && (exp->ex_flags & NFSEXP_ROOTSQUASH)) {
+	if (!(exp->ex_flags & NFSEXP_NOSUBTREECHECK)) {
+		if (exp->ex_dentry != dentry) {
+			struct dentry *tdentry = dentry;
+
+			do {
+				tdentry = tdentry->d_parent;
+				if (exp->ex_dentry == tdentry)
+					break;
+				/* executable only by root and we can't be root */
+				if (current->fsuid
+				    && (exp->ex_flags & NFSEXP_ROOTSQUASH)
+				    && !(tdentry->d_inode->i_uid
+					 && (tdentry->d_inode->i_mode & S_IXUSR))
+				    && !(tdentry->d_inode->i_gid
+					 && (tdentry->d_inode->i_mode & S_IXGRP))
+				    && !(tdentry->d_inode->i_mode & S_IXOTH)
+					) {
+					error = nfserr_stale;
+					nfsdstats.fh_stale++;
+					dprintk("fh_verify: no root_squashed access.\n");
+				}
+			} while ((tdentry != tdentry->d_parent));
+			if (exp->ex_dentry != tdentry) {
 				error = nfserr_stale;
 				nfsdstats.fh_stale++;
-dprintk("fh_verify: no root_squashed access.\n");
+				printk("nfsd Security: %s/%s bad export.\n",
+				       dentry->d_parent->d_name.name,
+				       dentry->d_name.name);
+				goto out;
 			}
-		} while ((tdentry != tdentry->d_parent));
-		if (exp->ex_dentry != tdentry) {
-			error = nfserr_stale;
-			nfsdstats.fh_stale++;
-			printk("nfsd Security: %s/%s bad export.\n",
-			       dentry->d_parent->d_name.name,
-			       dentry->d_name.name);
-			goto out;
 		}
 	}
 
@@ -1281,9 +649,10 @@
 		error = nfsd_permission(exp, dentry, access);
 	}
 #ifdef NFSD_PARANOIA
-if (error)
-printk("fh_verify: %s/%s permission failure, acc=%x, error=%d\n",
-dentry->d_parent->d_name.name, dentry->d_name.name, access, (error >> 24));
+	if (error) {
+		printk("fh_verify: %s/%s permission failure, acc=%x, error=%d\n",
+		       dentry->d_parent->d_name.name, dentry->d_name.name, access, (error >> 24));
+	}
 #endif
 out:
 	return error;
@@ -1303,7 +672,7 @@
 	struct dentry *parent = dentry->d_parent;
 
 	dprintk("nfsd: fh_compose(exp %x/%ld %s/%s, ino=%ld)\n",
-		exp->ex_dev, exp->ex_ino,
+		exp->ex_dev, (long) exp->ex_ino,
 		parent->d_name.name, dentry->d_name.name,
 		(inode ? inode->i_ino : 0));
 
@@ -1318,15 +687,17 @@
 	}
 	fh_init(fhp);
 
+	fhp->fh_handle.fh_dirino = ino_t_to_u32(parent->d_inode->i_ino);
+	fhp->fh_handle.fh_dev    = kdev_t_to_u32(parent->d_inode->i_dev);
+	fhp->fh_handle.fh_xdev   = kdev_t_to_u32(exp->ex_dev);
+	fhp->fh_handle.fh_xino   = ino_t_to_u32(exp->ex_ino);
+	fhp->fh_handle.fh_dcookie = (struct dentry *)0xfeebbaca;
 	if (inode) {
 		fhp->fh_handle.fh_ino = ino_t_to_u32(inode->i_ino);
 		fhp->fh_handle.fh_generation = inode->i_generation;
-		fhp->fh_handle.fh_dcookie = (struct dentry *)0xfeebbaca;
+		if (S_ISDIR(inode->i_mode) || (exp->ex_flags & NFSEXP_NOSUBTREECHECK))
+			fhp->fh_handle.fh_dirino = 0;
 	}
-	fhp->fh_handle.fh_dirino = ino_t_to_u32(parent->d_inode->i_ino);
-	fhp->fh_handle.fh_dev	 = kdev_t_to_u32(parent->d_inode->i_dev);
-	fhp->fh_handle.fh_xdev	 = kdev_t_to_u32(exp->ex_dev);
-	fhp->fh_handle.fh_xino	 = ino_t_to_u32(exp->ex_ino);
 
 	fhp->fh_dentry = dentry; /* our internal copy */
 	fhp->fh_export = exp;
@@ -1338,6 +709,7 @@
 
 /*
  * Update file handle information after changing a dentry.
+ * This is only called by nfsd_create
  */
 void
 fh_update(struct svc_fh *fhp)
@@ -1354,7 +726,9 @@
 		goto out_negative;
 	fhp->fh_handle.fh_ino = ino_t_to_u32(inode->i_ino);
 	fhp->fh_handle.fh_generation = inode->i_generation;
-	fhp->fh_handle.fh_dcookie = (struct dentry *)0xfeebbaca;
+	if (S_ISDIR(inode->i_mode) || (fhp->fh_export->ex_flags & NFSEXP_NOSUBTREECHECK))
+		fhp->fh_handle.fh_dirino = 0;
+
 out:
 	return;
 
@@ -1368,8 +742,7 @@
 }
 
 /*
- * Release a file handle.  If the file handle carries a dentry count,
- * we add the dentry to the short-term cache rather than release it.
+ * Release a file handle.
  */
 void
 fh_put(struct svc_fh *fhp)
@@ -1380,10 +753,8 @@
 		fhp->fh_dverified = 0;
 		if (!dentry->d_count)
 			goto out_bad;
-		if (!dentry->d_inode || !add_to_fhcache(dentry, 0)) {
-			dput(dentry);
-			nfsd_nr_put++;
-		}
+		dput(dentry);
+		nfsd_nr_put++;
 	}
 	return;
 
@@ -1391,118 +762,4 @@
 	printk(KERN_ERR "fh_put: %s/%s has d_count 0!\n",
 		dentry->d_parent->d_name.name, dentry->d_name.name);
 	return;
-}
-
-/*
- * Flush any cached dentries for the specified device
- * or for all devices.
- *
- * This is called when revoking the last export for a
- * device, so that it can be unmounted cleanly.
- */
-void nfsd_fh_flush(kdev_t dev)
-{
-	struct fh_entry *fhe;
-	int i, pass = 2;
-
-	fhe = &filetable[0];
-	while (pass--) {
-		for (i = 0; i < NFSD_MAXFH; i++, fhe++) {
-			struct dentry *dentry = fhe->dentry;
-			if (!dentry)
-				continue;
-			if (dev && dentry->d_inode->i_dev != dev)
-				continue;
-			fhe->dentry = NULL;
-			dput(dentry);
-			nfsd_nr_put++;
-		}
-		fhe = &dirstable[0];
-	}
-}
-
-/*
- * Free the rename and path caches.
- */
-void nfsd_fh_free(void)
-{
-	struct list_head *tmp;
-	int i;
-
-	/* Flush dentries for all devices */
-	nfsd_fh_flush(0);
-
-	/*
-	 * N.B. write a destructor for these lists ...
-	 */
-	i = 0;
-	while ((tmp = fixup_head.next) != &fixup_head) {
-		struct nfsd_fixup *fp;
-		fp = list_entry(tmp, struct nfsd_fixup, lru);
-		free_fixup_entry(fp);
-		i++;
-	}
-	printk(KERN_DEBUG "nfsd_fh_free: %d fixups freed\n", i);
-
-	i = 0;
-	while ((tmp = path_inuse.next) != &path_inuse) {
-		struct nfsd_path *pe;
-		pe = list_entry(tmp, struct nfsd_path, lru);
-		free_path_entry(pe);
-		i++;
-	}
-	printk(KERN_DEBUG "nfsd_fh_free: %d paths freed\n", i);
-
-	printk(KERN_DEBUG "nfsd_fh_free: verified %d, put %d\n",
-		nfsd_nr_verified, nfsd_nr_put);
-}
-
-void nfsd_fh_init(void)
-{
-	extern void __my_nfsfh_is_too_big(void); 
-
-	if (filetable)
-		return;
-
-	/* Sanity check */ 
-	if (sizeof(struct nfs_fhbase) > 32) 
-		__my_nfsfh_is_too_big(); 
-
-	filetable = kmalloc(sizeof(struct fh_entry) * NFSD_MAXFH,
-			    GFP_KERNEL);
-	dirstable = kmalloc(sizeof(struct fh_entry) * NFSD_MAXFH,
-			    GFP_KERNEL);
-
-	if (filetable == NULL || dirstable == NULL) {
-		printk(KERN_WARNING "nfsd_fh_init : Could not allocate fhcache\n");
-		nfsd_nservers = 0;
-		return;
-	}
-
-	memset(filetable, 0, NFSD_MAXFH*sizeof(struct fh_entry));
-	memset(dirstable, 0, NFSD_MAXFH*sizeof(struct fh_entry));
-	INIT_LIST_HEAD(&path_inuse);
-	INIT_LIST_HEAD(&fixup_head);
-
-	printk(KERN_DEBUG 
-		"nfsd_fh_init : initialized fhcache, entries=%lu\n", NFSD_MAXFH);
-	/*
-	 * Display a warning if the ino_t is larger than 32 bits.
-	 */
-	if (sizeof(ino_t) > sizeof(__u32))
-		printk(KERN_INFO 
-			"NFSD: ino_t is %d bytes, using lower 4 bytes\n",
-			sizeof(ino_t));
-}
-
-void
-nfsd_fh_shutdown(void)
-{
-	if (!filetable)
-		return;
-	printk(KERN_DEBUG 
-		"nfsd_fh_shutdown : freeing %ld fhcache entries.\n", NFSD_MAXFH);
-	kfree(filetable);
-	kfree(dirstable);
-	filetable = dirstable = NULL;
 }
Index: oldkernel/linux/fs/nfsd/nfsproc.c
diff -u linux/fs/nfsd/nfsproc.c:1.2 linux/fs/nfsd/nfsproc.c:1.3
--- linux/fs/nfsd/nfsproc.c:1.2	Thu Jun  1 15:37:13 2000
+++ linux/fs/nfsd/nfsproc.c	Fri Jul  7 15:36:46 2000
@@ -1,7 +1,10 @@
 /*
  * nfsproc2.c	Process version 2 NFS requests.
+ * linux/fs/nfsd/nfs2proc.c
+ * 
+ * Process version 2 NFS requests.
  *
- * Copyright (C) 1995 Olaf Kirch <okir@monad.swb.de>
+ * Copyright (C) 1995-1997 Olaf Kirch <okir@monad.swb.de>
  */
 
 #include <linux/linkage.h>
@@ -27,6 +30,9 @@
 
 #define NFSDDBG_FACILITY		NFSDDBG_PROC
 
+/* Check for dir entries '.' and '..' */
+#define isdotent(n, l)	(l < 3 && n[0] == '.' && (l == 1 || n[1] == '.'))
+
 #define RETURN(st)	return st
 
 static void
@@ -144,7 +150,7 @@
 				ntohl(rqstp->rq_addr.sin_addr.s_addr),
 				ntohs(rqstp->rq_addr.sin_port),
 				argp->count);
-		argp->count = avail;
+		argp->count = avail << 2;
 	}
 
 	resp->count = argp->count;
@@ -210,7 +216,9 @@
 		rdonly = 1;	/* Non-fatal error for echo > /dev/null */
 	} else if (nfserr)
 		goto done;
-
+	nfserr = nfserr_exist;
+	if (isdotent(argp->name, argp->len))
+		goto done;
 	/*
 	 * Do a lookup to verify the new file handle.
 	 */
@@ -261,7 +269,7 @@
 		goto out_unlock;
 
 	attr->ia_valid |= ATTR_MODE;
-	attr->ia_mode = type | mode;
+	attr->ia_mode = mode;
 
 	/* Special treatment for non-regular files according to the
 	 * gospel of sun micro
@@ -279,22 +287,21 @@
 			type = S_IFIFO;
 		} else if (size != rdev) {
 			/* dev got truncated because of 16bit Linux dev_t */
-			nfserr = nfserr_io;	/* or nfserr_inval? */
+			nfserr = nfserr_inval;
 			goto out_unlock;
 		} else {
 			/* Okay, char or block special */
 			is_borc = 1;
 		}
 
+		/* we've used the SIZE information, so discard it */
+		attr->ia_valid &= ~ATTR_SIZE;
+
 		/* Make sure the type and device matches */
 		nfserr = nfserr_exist;
 		if (inode && (type != (inode->i_mode & S_IFMT) || 
 		    (is_borc && inode->i_rdev != rdev)))
 			goto out_unlock;
-
-		/* invalidate size because only (type == S_IFREG) has
-		   size. */
-		attr->ia_valid &= ~ATTR_SIZE;
 	}
 	
 	nfserr = 0;
@@ -388,11 +395,8 @@
 	 */
 	nfserr = nfsd_symlink(rqstp, &argp->ffh, argp->fname, argp->flen,
 						 argp->tname, argp->tlen,
-						 &newfh);
-	if (!nfserr) {
-		argp->attrs.ia_valid &= ~ATTR_SIZE;
-		nfserr = nfsd_setattr(rqstp, &newfh, &argp->attrs);
-	}
+				 		 &newfh, &argp->attrs);
+
 
 	fh_put(&argp->ffh);
 	fh_put(&newfh);
@@ -446,8 +450,8 @@
 nfsd_proc_readdir(struct svc_rqst *rqstp, struct nfsd_readdirargs *argp,
 					  struct nfsd_readdirres  *resp)
 {
-	u32 *	buffer;
-	int	nfserr, count;
+	u32 *		buffer;
+	int		nfserr, count;
 
 	dprintk("nfsd: READDIR  %d/%d %d bytes at %d\n",
 		SVCFH_DEV(&argp->fh), SVCFH_INO(&argp->fh),
@@ -467,7 +471,8 @@
 
 	/* Read directory and encode entries on the fly */
 	nfserr = nfsd_readdir(rqstp, &argp->fh, (loff_t) argp->cookie, 
-				nfssvc_encode_entry, buffer, &count);
+			      nfssvc_encode_entry,
+			      buffer, &count, NULL);
 	resp->count = count;
 
 	fh_put(&argp->fh);
@@ -547,6 +552,8 @@
 		{ NFSERR_NXIO, ENXIO },
 		{ NFSERR_ACCES, EACCES },
 		{ NFSERR_EXIST, EEXIST },
+		{ NFSERR_XDEV, EXDEV },
+		{ NFSERR_MLINK, EMLINK },
 		{ NFSERR_NODEV, ENODEV },
 		{ NFSERR_NOTDIR, ENOTDIR },
 		{ NFSERR_ISDIR, EISDIR },
@@ -554,39 +561,22 @@
 		{ NFSERR_FBIG, EFBIG },
 		{ NFSERR_NOSPC, ENOSPC },
 		{ NFSERR_ROFS, EROFS },
+		{ NFSERR_MLINK, EMLINK },
 		{ NFSERR_NAMETOOLONG, ENAMETOOLONG },
 		{ NFSERR_NOTEMPTY, ENOTEMPTY },
 #ifdef EDQUOT
 		{ NFSERR_DQUOT, EDQUOT },
 #endif
 		{ NFSERR_STALE, ESTALE },
-		{ NFSERR_WFLUSH, EIO },
 		{ -1, EIO }
 	};
 	int	i;
 
 	for (i = 0; nfs_errtbl[i].nfserr != -1; i++) {
 		if (nfs_errtbl[i].syserr == errno)
-			return htonl (nfs_errtbl[i].nfserr);
+			return htonl(nfs_errtbl[i].nfserr);
 	}
 	printk (KERN_INFO "nfsd: non-standard errno: %d\n", errno);
 	return nfserr_io;
 }
 
-#if 0
-static void
-nfsd_dump(char *tag, u32 *buf, int len)
-{
-	int	i;
-
-	printk(KERN_NOTICE
-		"nfsd: %s (%d words)\n", tag, len);
-
-	for (i = 0; i < len && i < 32; i += 8)
-		printk(KERN_NOTICE
-			" %08lx %08lx %08lx %08lx"
-			" %08lx %08lx %08lx %08lx\n",
-			buf[i],   buf[i+1], buf[i+2], buf[i+3],
-			buf[i+4], buf[i+5], buf[i+6], buf[i+7]);
-}
-#endif
Index: oldkernel/linux/fs/nfsd/nfssvc.c
diff -u linux/fs/nfsd/nfssvc.c:1.1.1.1 linux/fs/nfsd/nfssvc.c:1.2
--- linux/fs/nfsd/nfssvc.c:1.1.1.1	Wed May 31 12:33:48 2000
+++ linux/fs/nfsd/nfssvc.c	Fri Jul  7 15:36:46 2000
@@ -42,7 +42,7 @@
 extern struct svc_program	nfsd_program;
 static void			nfsd(struct svc_rqst *rqstp);
 struct timeval			nfssvc_boot = { 0, 0 };
-static int			nfsd_active = 0;
+static atomic_t			nfsd_active = ATOMIC_INIT(0);
 
 /*
  * Maximum number of nfsd processes
@@ -55,24 +55,19 @@
 	struct svc_serv *	serv;
 	int			error;
 
-	dprintk("nfsd: creating service\n");
 	error = -EINVAL;
+	if (atomic_read(&nfsd_active))
+		goto out;	/* already running */
 	if (nrservs <= 0)
 		goto out;
 	if (nrservs > NFSD_MAXSERVS)
 		nrservs = NFSD_MAXSERVS;
+
+	dprintk("nfsd: creating service (%d)\n", nrservs);
 	nfsd_nservers = nrservs;
+	nfssvc_boot = xtime;
 
 	error = -ENOMEM;
-	nfsd_fh_init();		/* NFS dentry cache */
-	if (nfsd_nservers == 0)
-		goto out;
-	  
-	error = -ENOMEM;
-	nfsd_racache_init();     /* Readahead param cache */
-	if (nfsd_nservers == 0)
-		goto out;
-	  
 	serv = svc_create(&nfsd_program, NFSD_BUFSIZE, NFSSVC_XDRSIZE);
 	if (serv == NULL)
 		goto out;
@@ -87,6 +82,8 @@
 		goto failure;
 #endif
 
+	nfsd_racache_init();	/* Readahead param cache */
+
 	while (nrservs--) {
 		error = svc_create_thread(nfsd, serv);
 		if (error < 0)
@@ -106,28 +103,28 @@
 nfsd(struct svc_rqst *rqstp)
 {
 	struct svc_serv	*serv = rqstp->rq_server;
-	int		oldumask, err, first = 0;
+	int		err;
 
-	/* Lock module and set up kernel thread */
+	/* Lock module */
 	MOD_INC_USE_COUNT;
+
+	/* Set up kernel thread */
 	lock_kernel();
 	exit_mm(current);
+	sprintf(current->comm, "nfsd");
 	current->session = 1;
 	current->pgrp = 1;
+	current->fs->umask = 0;
+
+	/* Count active threads */
+	atomic_inc(&nfsd_active);
+
+	/* Start lockd */
+	lockd_up();
+
 	/* Let svc_process check client's authentication. */
 	rqstp->rq_auth = 1;
-	sprintf(current->comm, "nfsd");
 
-	oldumask = current->fs->umask;		/* Set umask to 0.  */
-	current->fs->umask = 0;
-	if (!nfsd_active++) {
-		nfssvc_boot = xtime;		/* record boot time */
-		first = 1;
-	}
-#if 0
-	lockd_up();				/* start lockd */
-#endif
-
 	/*
 	 * The main request loop
 	 */
@@ -143,13 +140,8 @@
 		 * recvfrom routine.
 		 */
 		while ((err = svc_recv(serv, rqstp,
-		        first?5*HZ:MAX_SCHEDULE_TIMEOUT)) == -EAGAIN) {
-			if (first && 1) {
-				exp_readlock();
-				expire_all();
-				exp_unlock();
-			}
-		}
+				       MAX_SCHEDULE_TIMEOUT)) == -EAGAIN)
+		    ;
 		if (err < 0)
 			break;
 
@@ -184,23 +176,17 @@
 		printk(KERN_WARNING "nfsd: terminating on signal %d\n", signo);
 	}
 
-#if 0
+	/* Count active threads */
+	if (atomic_dec_and_test(&nfsd_active)) {
+		nfsd_export_shutdown();		/* revoke all exports */
+	        nfsd_racache_shutdown();	/* release read-ahead cache */
+	}
+
 	/* Release lockd */
 	lockd_down();
-#endif
-	if (!--nfsd_active) {
-		printk("nfsd: last server exiting\n");
-		/* revoke all exports */
-		nfsd_export_shutdown();
-		/* release fhcache */
-		nfsd_fh_shutdown ();
-		/* release read-ahead cache */
-	        nfsd_racache_shutdown();
-	}
 
-	/* Destroy the thread */
+	/* Destroy the thread's resources */
 	svc_exit_thread(rqstp);
-	current->fs->umask = oldumask;
 
 	/* Release module */
 	MOD_DEC_USE_COUNT;
@@ -213,7 +199,8 @@
 	kxdrproc_t		xdr;
 	u32			nfserr;
 
-	dprintk("nfsd_dispatch: proc %d\n", rqstp->rq_proc);
+	dprintk("nfsd_dispatch: vers %d proc %d\n",
+				rqstp->rq_vers, rqstp->rq_proc);
 	proc = rqstp->rq_procinfo;
 
 	/* Check whether we have this call in the cache. */
@@ -242,8 +229,20 @@
 		svc_putlong(&rqstp->rq_resbuf, nfserr);
 
 	/* Encode result.
-	 * FIXME: Most NFSv3 calls return wcc data even when the call failed
+	 * For NFSv2, additional info is never returned in case of an error.
 	 */
+#ifdef CONFIG_NFSD_V3
+	if (!(nfserr && rqstp->rq_vers == 2)) {
+		xdr = proc->pc_encode;
+		if (xdr && !xdr(rqstp, rqstp->rq_resbuf.buf, rqstp->rq_resp)) {
+			/* Failed to encode result. Release cache entry */
+			dprintk("nfsd: failed to encode result!\n");
+			nfsd_cache_update(rqstp, RC_NOCACHE, NULL);
+			*statp = rpc_system_err;
+			return 1;
+		}
+	}
+#else
 	xdr = proc->pc_encode;
 	if (!nfserr && xdr
 	 && !xdr(rqstp, rqstp->rq_resbuf.buf, rqstp->rq_resp)) {
@@ -253,6 +252,7 @@
 		*statp = rpc_system_err;
 		return 1;
 	}
+#endif /* CONFIG_NFSD_V3 */
 
 	/* Store reply in cache. */
 	nfsd_cache_update(rqstp, proc->pc_cachetype, statp + 1);
@@ -262,16 +262,16 @@
 static struct svc_version	nfsd_version2 = {
 	2, 18, nfsd_procedures2, nfsd_dispatch
 };
-#ifdef CONFIG_NFSD_NFS3
+#ifdef CONFIG_NFSD_V3
 static struct svc_version	nfsd_version3 = {
-	3, 23, nfsd_procedures3, nfsd_dispatch
+	3, 22, nfsd_procedures3, nfsd_dispatch
 };
 #endif
 static struct svc_version *	nfsd_version[] = {
 	NULL,
 	NULL,
 	&nfsd_version2,
-#ifdef CONFIG_NFSD_NFS3
+#ifdef CONFIG_NFSD_V3
 	&nfsd_version3,
 #endif
 };
Index: oldkernel/linux/fs/nfsd/nfsxdr.c
diff -u linux/fs/nfsd/nfsxdr.c:1.1.1.1 linux/fs/nfsd/nfsxdr.c:1.2
--- linux/fs/nfsd/nfsxdr.c:1.1.1.1	Wed May 31 12:33:48 2000
+++ linux/fs/nfsd/nfsxdr.c	Fri Jul  7 15:36:46 2000
@@ -18,10 +18,15 @@
 #define NFSDDBG_FACILITY		NFSDDBG_XDR
 
 u32	nfs_ok, nfserr_perm, nfserr_noent, nfserr_io, nfserr_nxio,
-	nfserr_inval, nfserr_acces, nfserr_exist, nfserr_nodev, nfserr_notdir,
-	nfserr_isdir, nfserr_fbig, nfserr_nospc, nfserr_rofs,
-	nfserr_nametoolong, nfserr_dquot, nfserr_stale;
+	nfserr_acces, nfserr_exist, nfserr_xdev, nfserr_nodev,
+	nfserr_notdir, nfserr_isdir, nfserr_inval, nfserr_fbig,
+	nfserr_nospc, nfserr_rofs, nfserr_mlink,
+	nfserr_nametoolong, nfserr_notempty, nfserr_dquot, nfserr_stale,
+	nfserr_remote, nfserr_badhandle, nfserr_notsync,
+	nfserr_badcookie, nfserr_notsupp, nfserr_toosmall,
+	nfserr_serverfault, nfserr_badtype, nfserr_jukebox;
 
+
 #ifdef NFSD_OPTIMIZE_SPACE
 # define inline
 #endif
@@ -51,19 +56,33 @@
 	nfserr_perm	= htonl(NFSERR_PERM);
 	nfserr_noent	= htonl(NFSERR_NOENT);
 	nfserr_io	= htonl(NFSERR_IO);
+	nfserr_inval	= htonl(NFSERR_INVAL);
+	nfserr_nxio	= htonl(NFSERR_NXIO);
+	nfserr_acces	= htonl(NFSERR_ACCES);
+	nfserr_exist	= htonl(NFSERR_EXIST);
+	nfserr_xdev	= htonl(NFSERR_XDEV);
+	nfserr_nodev	= htonl(NFSERR_NODEV);
+	nfserr_notdir	= htonl(NFSERR_NOTDIR);
+	nfserr_isdir	= htonl(NFSERR_ISDIR);
 	nfserr_inval	= htonl(NFSERR_INVAL);
-	nfserr_nxio = htonl(NFSERR_NXIO);
-	nfserr_acces = htonl(NFSERR_ACCES);
-	nfserr_exist = htonl(NFSERR_EXIST);
-	nfserr_nodev = htonl(NFSERR_NODEV);
-	nfserr_notdir = htonl(NFSERR_NOTDIR);
-	nfserr_isdir = htonl(NFSERR_ISDIR);
-	nfserr_fbig = htonl(NFSERR_FBIG);
-	nfserr_nospc = htonl(NFSERR_NOSPC);
-	nfserr_rofs = htonl(NFSERR_ROFS);
+	nfserr_fbig	= htonl(NFSERR_FBIG);
+	nfserr_nospc	= htonl(NFSERR_NOSPC);
+	nfserr_rofs	= htonl(NFSERR_ROFS);
+	nfserr_mlink	= htonl(NFSERR_MLINK);
 	nfserr_nametoolong = htonl(NFSERR_NAMETOOLONG);
-	nfserr_dquot = htonl(NFSERR_DQUOT);
-	nfserr_stale = htonl(NFSERR_STALE);
+	nfserr_notempty	= htonl(NFSERR_NOTEMPTY);
+	nfserr_dquot	= htonl(NFSERR_DQUOT);
+	nfserr_stale	= htonl(NFSERR_STALE);
+	nfserr_remote	= htonl(NFSERR_REMOTE);
+	nfserr_badhandle = htonl(NFSERR_BADHANDLE);
+	nfserr_notsync	= htonl(NFSERR_NOT_SYNC);
+	nfserr_badcookie = htonl(NFSERR_BAD_COOKIE);
+	nfserr_notsupp	= htonl(NFSERR_NOTSUPP);
+	nfserr_toosmall	= htonl(NFSERR_TOOSMALL);
+	nfserr_serverfault = htonl(NFSERR_SERVERFAULT);
+	nfserr_badtype	= htonl(NFSERR_BADTYPE);
+	nfserr_jukebox	= htonl(NFSERR_JUKEBOX);
+
 
 	inited = 1;
 }
Index: oldkernel/linux/fs/nfsd/stats.c
diff -u linux/fs/nfsd/stats.c:1.1.1.1 linux/fs/nfsd/stats.c:1.2
--- linux/fs/nfsd/stats.c:1.1.1.1	Wed May 31 12:33:48 2000
+++ linux/fs/nfsd/stats.c	Fri Jul  7 15:36:46 2000
@@ -32,16 +32,15 @@
 {
 	int	len;
 
-	len = sprintf(buffer, "rc %d %d %d  %d %d %d %d %d %d\n",
+	len = sprintf(buffer, "rc %d %d %d  %d %d %d %d %d\n",
 			nfsdstats.rchits,
 			nfsdstats.rcmisses,
 			nfsdstats.rcnocache,
-			nfsdstats.fh_cached,
-			nfsdstats.fh_valid,
-			nfsdstats.fh_fixup,
 			nfsdstats.fh_lookup,
-			nfsdstats.fh_stale,
-			nfsdstats.fh_concurrent);
+			nfsdstats.fh_anon,
+			nfsdstats.fh_nocache_nondir,
+			nfsdstats.fh_nocache_dir,
+			nfsdstats.fh_stale);
 
 	/* Assume we haven't hit EOF yet. Will be set by svc_proc_read. */
 	*eof = 0;
Index: oldkernel/linux/fs/nfsd/vfs.c
diff -u linux/fs/nfsd/vfs.c:1.2 linux/fs/nfsd/vfs.c:1.3
--- linux/fs/nfsd/vfs.c:1.2	Thu Jun  1 15:03:08 2000
+++ linux/fs/nfsd/vfs.c	Fri Jul  7 15:36:46 2000
@@ -31,6 +31,10 @@
 
 #include <linux/sunrpc/svc.h>
 #include <linux/nfsd/nfsd.h>
+#ifdef CONFIG_NFSD_V3
+#include <linux/nfs3.h>
+#include <linux/nfsd/xdr3.h>
+#endif /* CONFIG_NFSD_V3 */
 #include <linux/nfsd/nfsfh.h>
 #include <linux/quotaops.h>
 
@@ -41,16 +45,15 @@
 #define NFSDDBG_FACILITY		NFSDDBG_FILEOP
 #define NFSD_PARANOIA
 
-/* Open mode for nfsd_open */
-#define OPEN_READ	0
-#define OPEN_WRITE	1
-
-/* Hack until we have a macro check for mandatory locks. */
-#ifndef IS_ISMNDLK
-#define IS_ISMNDLK(i)	(((i)->i_mode & (S_ISGID|S_IXGRP|S_IFMT)) \
-			 == (S_ISGID|S_IFREG))
-#endif
 
+/* We must ignore files (but only files) which might have mandatory
+ * locks on them because there is no way to know if the accesser has
+ * the lock.
+ */
+/* MANDATORY_LOCK taken from 2.3 */
+#define MANDATORY_LOCK(inode) \
+	(IS_MANDLOCK(inode) && ((inode)->i_mode & (S_ISGID | S_IXGRP)) == S_ISGID)
+#define IS_ISMNDLK(i)	(S_ISREG((i)->i_mode) && MANDATORY_LOCK(i))
 /* Time difference margin in seconds for comparison. It is a
    dynamically-tunable parameter via /proc/fs/nfs/time-diff-margin.
  */
@@ -83,65 +86,58 @@
 static struct raparms *		raparml = NULL;
 static struct raparms *		raparm_cache = NULL;
 
+
+/*
+ * We need to do a check-parent every time
+ * after we have locked the parent - to verify
+ * that the parent is still our parent and
+ * that we are still hashed onto it..
+ *
+ * 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 identical
+ * the check_parent in linux/fs/namei.c.
+ */
+#define nfsd_check_parent(dir, dentry) \
+	((dir) == (dentry)->d_parent && !list_empty(&dentry->d_hash))
+
 /*
  * Lock a parent directory following the VFS locking protocol.
  */
 int
 fh_lock_parent(struct svc_fh *parent_fh, struct dentry *dchild)
 {
-	int	nfserr = 0;
-
 	fh_lock(parent_fh);
 	/*
 	 * Make sure the parent->child relationship still holds,
 	 * and that the child is still hashed.
 	 */
-	if (dchild->d_parent != parent_fh->fh_dentry) 
-		goto out_not_parent;
-	if (list_empty(&dchild->d_hash))
-		goto out_not_hashed; 
-out:
-	return nfserr;
+	if (nfsd_check_parent(parent_fh->fh_dentry, dchild))
+	    return 0;
 
-out_not_parent:
-	printk(KERN_WARNING
-		"fh_lock_parent: %s/%s parent changed\n",
-		dchild->d_parent->d_name.name, dchild->d_name.name);
-	goto out_unlock;
-out_not_hashed:
 	printk(KERN_WARNING
-		"fh_lock_parent: %s/%s unhashed\n",
+		"fh_lock_parent: %s/%s parent changed or child unhashed\n",
 		dchild->d_parent->d_name.name, dchild->d_name.name);
-out_unlock:
-	nfserr = nfserr_noent;
-	fh_unlock(parent_fh);
-	goto out;
-}
 
-/*
- * Deny access to certain file systems
- */
-static inline int
-fs_off_limits(struct super_block *sb)
-{
-	return !sb || sb->s_magic == NFS_SUPER_MAGIC
-	           || sb->s_magic == PROC_SUPER_MAGIC;
+	fh_unlock(parent_fh);
+	return nfserr_noent;
 }
 
-/*
- * Check whether directory is a mount point, but it is all right if
- * this is precisely the local mount point being exported.
- */
-static inline int
-nfsd_iscovered(struct dentry *dentry, struct svc_export *exp)
-{
-	return (dentry != dentry->d_covers &&
-		dentry != exp->ex_dentry);
-}
 
 /*
  * Look up one component of a pathname.
  * N.B. After this call _both_ fhp and resfh need an fh_put
+ *
+ * If the lookup would cross a mountpoint, and the mounted filesystem
+ * is exported to the client with NFSEXP_CROSSMNT, then the lookup is
+ * accepted as it stands and the mounted directory is
+ * returned. Otherwise the covered directory is returned.
+ * NOTE: this mountpoint crossing is not supported properly by all
+ *   clients and is explicitly disallowed for NFSv3
+ *      NeilBrown <neilb@cse.unsw.edu.au>
  */
 int
 nfsd_lookup(struct svc_rqst *rqstp, struct svc_fh *fhp, const char *name,
@@ -166,33 +162,62 @@
 	if (err)
 		goto out;
 #endif
-	err = nfserr_noent;
-	if (fs_off_limits(dparent->d_sb))
-		goto out;
 	err = nfserr_acces;
-	if (nfsd_iscovered(dparent, exp))
-		goto out;
 
 	/* Lookup the name, but don't follow links */
-	dchild = lookup_dentry(name, dget(dparent), 0);
-	if (IS_ERR(dchild))
-		goto out_nfserr;
-	/*
-	 * check if we have crossed a mount point ...
-	 */
-	if (dchild->d_sb != dparent->d_sb) {
-		struct dentry *tdentry;
-		tdentry = dchild->d_covers;
-		if (tdentry == dchild)
-			goto out_dput;
-	        dput(dchild);
-		dchild = dget(tdentry);
-	        if (dchild->d_sb != dparent->d_sb) {
-printk("nfsd_lookup: %s/%s crossed mount point!\n", dparent->d_name.name, dchild->d_name.name);
-			goto out_dput;
+	if (strcmp(name, "..")==0) {
+		/* checking mountpoint crossing is very different when stepping up */
+		if (dparent == exp->ex_dentry) {
+			if (!EX_CROSSMNT(exp))
+				dchild = dget(dparent); /* .. == . just like at / */
+			else
+			{
+				struct svc_export *exp2 = NULL;
+				struct dentry *dp;
+				dchild = dparent->d_covers->d_parent;
+				for (dp=dchild;
+				     exp2 == NULL && dp->d_covers->d_parent != dp;
+				     dp=dp->d_covers->d_parent)
+					exp2 = exp_get(exp->ex_client, dp->d_inode->i_dev, dp->d_inode->i_ino);
+				if (exp2==NULL || dchild->d_sb != exp2->ex_dentry->d_sb) {
+					dchild = dget(dparent);
+				} else {
+					dget(dchild);
+					exp = exp2;
+				}
+			}
+		} else
+			dchild = dget(dparent->d_parent);
+	} else {
+		dchild = lookup_dentry(name, dget(dparent), 0);
+		if (IS_ERR(dchild))
+			goto out_nfserr;
+		/*
+		 * check if we have crossed a mount point ...
+		 */
+		if (dchild->d_sb != dparent->d_sb) {
+			struct svc_export *exp2 = NULL;
+			exp2 = exp_get(rqstp->rq_client,
+				       dchild->d_inode->i_dev,
+				       dchild->d_inode->i_ino);
+			if (exp2 && EX_CROSSMNT(exp2))
+				/* successfully crossed mount point */
+				exp = exp2;
+			else if (dchild->d_covers->d_sb == dparent->d_sb) {
+				/* stay in the original filesystem */
+				struct dentry *tdentry = dget(dchild->d_covers);
+				dput(dchild);
+				dchild = tdentry;
+			} else {
+				/* This cannot possibly happen */
+				printk("nfsd_lookup: %s/%s impossible mount point!\n", dparent->d_name.name, dchild->d_name.name);
+				dput(dchild);
+				err = nfserr_acces;
+				goto out;
+
+			}
 		}
 	}
-
 	/*
 	 * Note: we compose the file handle now, but as the
 	 * dentry may be negative, it may need to be updated.
@@ -207,10 +232,6 @@
 out_nfserr:
 	err = nfserrno(-PTR_ERR(dchild));
 	goto out;
-out_dput:
-	dput(dchild);
-	err = nfserr_acces;
-	goto out;
 }
 
 /*
@@ -226,6 +247,8 @@
 	int		ftype = 0;
 	int		imode;
 	int		err;
+	kernel_cap_t	saved_cap = 0;
+	int		size_change = 0;
 
 	if (iap->ia_valid & (ATTR_ATIME | ATTR_MTIME | ATTR_SIZE))
 		accmode |= MAY_WRITE;
@@ -234,39 +257,43 @@
 
 	/* Get inode */
 	err = fh_verify(rqstp, fhp, ftype, accmode);
-	if (err)
+	if (err || !iap->ia_valid)
 		goto out;
 
 	dentry = fhp->fh_dentry;
 	inode = dentry->d_inode;
 
 	err = inode_change_ok(inode, iap);
-	if (err) {
-		/* It is very tricky. When you are not the file owner,
-		   but have the write permission, you should be allowed
-		   to set atime and mtime to the current time on the
-		   server. However, the NFS V2 protocol doesn't support
-		   it. It has been fixed in V3. Here we do this: if the
-		   current server time and atime/mtime are close enough,
-		   we use the current server time. */
-#define CURRENT_TIME_SET	(ATTR_ATIME_SET | ATTR_MTIME_SET)
-		if (iap->ia_mtime == iap->ia_atime
-		    && ((iap->ia_valid & (CURRENT_TIME_SET))
-			== CURRENT_TIME_SET)) {
-			time_t now = CURRENT_TIME;
-			time_t delta = iap->ia_atime - now;
-			if (delta < 0) delta = -delta;
-			if (delta <= nfsd_time_diff_margin) {
-				iap->ia_valid &= ~CURRENT_TIME_SET;
-				goto current_time_ok;
-			}
+	/* could be a "touch" (utimes) request where the user is not the owner but does
+	 * have write permission. In this case the user should be allowed to set
+	 * both times to the current time.  We could just assume any such SETATTR
+	 * is intended to set the times to "now", but we do a couple of simple tests
+	 * to increase our confidence.
+	 */
+#define BOTH_TIME_SET (ATTR_ATIME_SET | ATTR_MTIME_SET)
+#define	MAX_TOUCH_TIME_ERROR (30*60)
+	if (err
+	    && (iap->ia_valid & BOTH_TIME_SET) == BOTH_TIME_SET
+	    && iap->ia_mtime == iap->ia_ctime
+	    ) {
+	    /* looks good.  now just make sure time is in the right ballpark.
+	     * solaris, at least, doesn't seem to care what the time request is
+	     */
+	    time_t delta = iap->ia_atime - CURRENT_TIME;
+	    if (delta<0) delta = -delta;
+	    if (delta < MAX_TOUCH_TIME_ERROR) {
+		/* turn off ATTR_[AM]TIME_SET but leave ATTR_[AM]TIME
+		 * this will cause notify_change to setthese times to "now"
+		 */
+		iap->ia_valid &= ~BOTH_TIME_SET;
+		err = inode_change_ok(inode, iap);
 		}
-		goto out_nfserr;
 	}
 
-current_time_ok:
+	if (err)
+		goto out_nfserr;
 
-	/* The size case is special... */
+	/* The size case is special. It changes the file as well as the attributes.  */
 	if (iap->ia_valid & ATTR_SIZE) {
 if (!S_ISREG(inode->i_mode))
 printk("nfsd_setattr: size change??\n");
@@ -275,22 +302,11 @@
 			if (err)
 				goto out;
 		}
-		DQUOT_INIT(inode);
 		err = get_write_access(inode);
-		if (err) {
-			DQUOT_DROP(inode);
+		if (err)
 			goto out_nfserr;
-		}
-		/* N.B. Should we update the inode cache here? */
-		inode->i_size = iap->ia_size;
-		if (inode->i_op && inode->i_op->truncate)
-			inode->i_op->truncate(inode);
-		mark_inode_dirty(inode);
-		put_write_access(inode);
-		DQUOT_DROP(inode);
-		iap->ia_valid &= ~ATTR_SIZE;
-		iap->ia_valid |= ATTR_MTIME;
-		iap->ia_mtime = CURRENT_TIME;
+
+		DQUOT_INIT(inode);
 	}
 
 	imode = inode->i_mode;
@@ -312,24 +328,55 @@
 	}
 
 	/* Change the attributes. */
-	if (iap->ia_valid) {
-		kernel_cap_t	saved_cap = 0;
 
-		iap->ia_valid |= ATTR_CTIME;
-		iap->ia_ctime = CURRENT_TIME;
-		if (current->fsuid != 0) {
-			saved_cap = current->cap_effective;
-			cap_clear(current->cap_effective);
-		}
+
+	iap->ia_valid |= ATTR_CTIME;
+	if (current->fsuid != 0) {
+		saved_cap = current->cap_effective;
+		cap_clear(current->cap_effective);
+	}
+#ifdef CONFIG_QUOTA
+	/* DQUOT_TRANSFER needs both ia_uid and ia_gid defined */
+	if (iap->ia_valid & (ATTR_UID|ATTR_GID)) {
+		if (! (iap->ia_valid & ATTR_UID))
+			iap->ia_uid = inode->i_uid;
+		if (! (iap->ia_valid & ATTR_GID))
+			iap->ia_gid = inode->i_gid;
+		iap->ia_valid |= ATTR_UID|ATTR_GID;
+	}
+#endif /* CONFIG_QUOTA */
+
+	if (iap->ia_valid & ATTR_SIZE) {
+		fh_lock(fhp);
+		size_change = 1;
+	}
+#ifdef CONFIG_QUOTA
+	if (iap->ia_valid & (ATTR_UID|ATTR_GID)) 
+		err = DQUOT_TRANSFER(dentry, iap);
+	else
+#endif
 		err = notify_change(dentry, iap);
-		if (current->fsuid != 0)
-			current->cap_effective = saved_cap;
-		if (err)
-			goto out_nfserr;
-		if (EX_ISSYNC(fhp->fh_export))
-			write_inode_now(inode);
+
+	if (size_change) {
+		if (!err) {
+			vmtruncate(inode,iap->ia_size);		
+			if (inode->i_op && inode->i_op->truncate)
+				inode->i_op->truncate(inode);
+		}
+		fh_unlock(fhp);
+		put_write_access(inode);
 	}
+
+	if (current->fsuid != 0)
+		current->cap_effective = saved_cap;
+	if (err)
+		goto out_nfserr;
+	if (EX_ISSYNC(fhp->fh_export))
+		write_inode_now(inode);
 	err = 0;
+
+	/* Don't unlock inode; the nfssvc_release functions are supposed
+	 * to do this. */
 out:
 	return err;
 
@@ -338,20 +385,107 @@
 	goto out;
 }
 
+#ifdef CONFIG_NFSD_V3
 /*
+ * Check server access rights to a file system object
+ */
+struct accessmap {
+	u32		access;
+	int		how;
+};
+static struct accessmap	nfs3_regaccess[] = {
+    {	NFS3_ACCESS_READ,	MAY_READ			},
+    {	NFS3_ACCESS_EXECUTE,	MAY_EXEC			},
+    {	NFS3_ACCESS_MODIFY,	MAY_WRITE|MAY_TRUNC		},
+    {	NFS3_ACCESS_EXTEND,	MAY_WRITE			},
+
+    {	0,			0				}
+};
+
+static struct accessmap	nfs3_diraccess[] = {
+    {	NFS3_ACCESS_READ,	MAY_READ			},
+    {	NFS3_ACCESS_LOOKUP,	MAY_EXEC			},
+    {	NFS3_ACCESS_MODIFY,	MAY_EXEC|MAY_WRITE|MAY_TRUNC	},
+    {	NFS3_ACCESS_EXTEND,	MAY_EXEC|MAY_WRITE		},
+    {	NFS3_ACCESS_DELETE,	MAY_REMOVE			},
+
+    {	0,			0				}
+};
+
+static struct accessmap	nfs3_anyaccess[] = {
+    /* XXX: should we try to cover read/write here for clients that
+     * rely on us to do their access checking for special files? */
+
+    {	0,			0				}
+};
+
+int
+nfsd_access(struct svc_rqst *rqstp, struct svc_fh *fhp, u32 *access)
+{
+	struct accessmap	*map;
+	struct svc_export	*export;
+	struct dentry		*dentry;
+	u32			query, result = 0;
+	int			error;
+
+	error = fh_verify(rqstp, fhp, 0, MAY_NOP);
+	if (error)
+		goto out;
+
+	export = fhp->fh_export;
+	dentry = fhp->fh_dentry;
+
+	if (S_ISREG(dentry->d_inode->i_mode)) {
+		map = nfs3_regaccess;
+	} else if (S_ISDIR(dentry->d_inode->i_mode)) {
+		map = nfs3_diraccess;
+	} else {
+		map = nfs3_anyaccess;
+	}
+
+	query = *access;
+	while (map->access) {
+		if (map->access & query) {
+			error = nfsd_permission(export, dentry, (map->how | NO_OWNER_OVERRIDE));
+			if (error == 0)
+				result |= map->access;
+			else if ((error == nfserr_perm) || (error == nfserr_acces)) {
+				/*
+				 *  This access type is denyed; but the 
+				 *  access query itself succeeds.
+				 */
+				error = 0;
+			} else {
+				/*
+				 *  Some fatal error.  Fail the query.
+				 */
+				goto out;
+			}
+		}
+		map++;
+	}
+	*access = result;
+
+out:
+	return error;
+}
+#endif
+
+
+
+/*
  * Open an existing file or directory.
- * The wflag argument indicates write access.
+ * The access argument indicates the type of open (read/write/lock)
  * N.B. After this call fhp needs an fh_put
  */
 int
 nfsd_open(struct svc_rqst *rqstp, struct svc_fh *fhp, int type,
-			int wflag, struct file *filp)
+			int access, struct file *filp)
 {
 	struct dentry	*dentry;
 	struct inode	*inode;
-	int		access, err;
+	int		err;
 
-	access = wflag? MAY_WRITE : MAY_READ;
 	err = fh_verify(rqstp, fhp, type, access);
 	if (err)
 		goto out;
@@ -368,24 +502,27 @@
 	if (!inode->i_op || !inode->i_op->default_file_ops)
 		goto out;
 
-	if (wflag && (err = get_write_access(inode)) != 0)
+	if ((access & MAY_WRITE) && (err = get_write_access(inode)) != 0)
 		goto out_nfserr;
 
 	memset(filp, 0, sizeof(*filp));
 	filp->f_op    = inode->i_op->default_file_ops;
 	filp->f_count = 1;
-	filp->f_flags = wflag? O_WRONLY : O_RDONLY;
-	filp->f_mode  = wflag? FMODE_WRITE : FMODE_READ;
 	filp->f_dentry = dentry;
-
-	if (wflag)
+	if (access & MAY_WRITE) {
+		filp->f_flags = O_WRONLY;
+		filp->f_mode  = FMODE_WRITE;
 		DQUOT_INIT(inode);
+	} else {
+		filp->f_flags = O_RDONLY;
+		filp->f_mode  = FMODE_READ;
+	}
 
 	err = 0;
 	if (filp->f_op && filp->f_op->open) {
 		err = filp->f_op->open(inode, filp);
 		if (err) {
-			if (wflag)
+			if (access & MAY_WRITE)
 				put_write_access(inode);
 
 			/* I nearly added put_filp() call here, but this filp
@@ -419,19 +556,35 @@
 		filp->f_op->release(inode, filp);
 	if (filp->f_mode & FMODE_WRITE) {
 		put_write_access(inode);
-		DQUOT_DROP(inode);
 	}
 }
 
 /*
  * Sync a file
+ * As this calls fsync (not fdatasync) there is no need for a write_inode
+ * after it.
  */
 void
-nfsd_sync(struct inode *inode, struct file *filp)
+nfsd_sync(struct file *filp)
 {
+	dprintk("nfsd: sync file %s\n", filp->f_dentry->d_name.name);
+	down(&filp->f_dentry->d_inode->i_sem);
 	filp->f_op->fsync(filp, filp->f_dentry);
+	up(&filp->f_dentry->d_inode->i_sem);
 }
 
+void
+nfsd_sync_dir(struct dentry *dp)
+{
+	struct inode *inode = dp->d_inode;
+	int (*fsync) (struct file *, struct dentry *);
+	
+	if (inode->i_op->default_file_ops
+	    && (fsync = inode->i_op->default_file_ops->fsync)) {
+		fsync(NULL, dp);
+	}
+}
+
 /*
  * Obtain the readahead parameters for the file
  * specified by (dev, ino).
@@ -478,7 +631,7 @@
 	int		err;
 	struct file	file;
 
-	err = nfsd_open(rqstp, fhp, S_IFREG, OPEN_READ, &file);
+	err = nfsd_open(rqstp, fhp, S_IFREG, MAY_READ, &file);
 	if (err)
 		goto out;
 	err = nfserr_perm;
@@ -503,9 +656,8 @@
 	/* Write back readahead params */
 	if (ra != NULL) {
 		dprintk("nfsd: raparms %ld %ld %ld %ld %ld\n",
-			(u_long)file.f_reada, (u_long)file.f_ramax,
-			(u_long)file.f_raend, (u_long)file.f_ralen,
-			(u_long)file.f_rawin);
+			file.f_reada, file.f_ramax, file.f_raend,
+			file.f_ralen, file.f_rawin);
 		ra->p_reada = file.f_reada;
 		ra->p_ramax = file.f_ramax;
 		ra->p_raend = file.f_raend;
@@ -544,11 +696,11 @@
 	uid_t			saved_euid;
 #endif
 
-	if (!cnt)
-		goto out;
-	err = nfsd_open(rqstp, fhp, S_IFREG, OPEN_WRITE, &file);
+	err = nfsd_open(rqstp, fhp, S_IFREG, MAY_WRITE, &file);
 	if (err)
 		goto out;
+	if (!cnt)
+		goto out_close;
 	err = nfserr_perm;
 	if (!file.f_op->write)
 		goto out_close;
@@ -561,11 +713,21 @@
 	 * Request sync writes if
 	 *  -	the sync export option has been set, or
 	 *  -	the client requested O_SYNC behavior (NFSv3 feature).
+	 *  -   The file system doesn't support fsync().
 	 * When gathered writes have been configured for this volume,
 	 * flushing the data to disk is handled separately below.
 	 */
+#ifdef CONFIG_NFSD_V3
+	if (rqstp->rq_vers == 2)
+		stable = EX_ISSYNC(exp);
+	else if (file.f_op->fsync == 0)
+	       stable = 1;
+	if (stable && !EX_WGATHER(exp))
+		file.f_flags |= O_SYNC;
+#else
 	if ((stable || (stable = EX_ISSYNC(exp))) && !EX_WGATHER(exp))
 		file.f_flags |= O_SYNC;
+#endif /* CONFIG_NFSD_V3 */
 
 	fh_lock(fhp);			/* lock inode */
 	file.f_pos = offset;		/* set write offset */
@@ -623,6 +785,7 @@
 			interruptible_sleep_on_timeout(&inode->i_wait, 10 * HZ / 1000);
 #else
 			dprintk("nfsd: write defer %d\n", current->pid);
+/* FIXME: Olaf commented this out [gam3] */
 			schedule_timeout((HZ+99)/100);
 			dprintk("nfsd: write resume %d\n", current->pid);
 #endif
@@ -630,15 +793,14 @@
 
 		if (inode->i_state & I_DIRTY) {
 			dprintk("nfsd: write sync %d\n", current->pid);
-			nfsd_sync(inode, &file);
-			write_inode_now(inode);
+			nfsd_sync(&file);
 		}
 		wake_up(&inode->i_wait);
 		last_ino = inode->i_ino;
 		last_dev = inode->i_dev;
 	}
 
-	dprintk("nfsd: write complete\n");
+	dprintk("nfsd: write complete err=%d\n", err);
 	if (err >= 0)
 		err = 0;
 	else 
@@ -649,7 +811,37 @@
 	return err;
 }
 
+
+#ifdef CONFIG_NFSD_V3
 /*
+ * Commit all pendig writes to stable storage.
+ * Strictly speaking, we could sync just indicated the file region here,
+ * but there's currently no way we can ask the VFS to do so.
+ *
+ * We lock the file to make sure we return full WCC data to the client.
+ */
+int
+nfsd_commit(struct svc_rqst *rqstp, struct svc_fh *fhp,
+               off_t offset, unsigned long count)
+{
+	struct file	file;
+	int		err;
+
+	if ((err = nfsd_open(rqstp, fhp, S_IFREG, MAY_WRITE, &file)) != 0)
+		return err;
+
+	if (file.f_op && file.f_op->fsync) {
+		nfsd_sync(&file);
+	} else {
+		err = nfserr_notsupp;
+	}
+
+	nfsd_close(&file);
+	return err;
+}
+#endif /* CONFIG_NFSD_V3 */
+
+/*
  * Create a file (regular, directory, device, fifo); UNIX sockets 
  * not yet implemented.
  * If the response fh has been verified, the parent directory should
@@ -670,6 +862,7 @@
 	err = nfserr_perm;
 	if (!flen)
 		goto out;
+
 	err = fh_verify(rqstp, fhp, S_IFDIR, MAY_CREATE);
 	if (err)
 		goto out;
@@ -680,6 +873,10 @@
 	err = nfserr_notdir;
 	if(!dirp->i_op || !dirp->i_op->lookup)
 		goto out;
+
+	err = nfserr_exist;
+	if (isdotent(fname, flen))
+		goto out;
 	/*
 	 * Check whether the response file handle has been verified yet.
 	 * If it has, the parent directory should already be locked.
@@ -690,30 +887,28 @@
 		if (IS_ERR(dchild))
 			goto out_nfserr;
 		fh_compose(resfhp, fhp->fh_export, dchild);
+		/* Lock the parent and check for errors ... */
+		err = fh_lock_parent(fhp, dchild);
+		if (err)
+			goto out;
 	} else {
 		dchild = resfhp->fh_dentry;
-		if (!fhp->fh_locked)
+		if (!fhp->fh_locked) {
+			/* not actually possible */
 			printk(KERN_ERR
 				"nfsd_create: parent %s/%s not locked!\n",
 				dentry->d_parent->d_name.name,
 				dentry->d_name.name);
-	}
-	err = nfserr_exist;
-	if (dchild->d_inode)
-		goto out;
-	if (!fhp->fh_locked) {
-		/* Lock the parent and check for errors ... */
-		err = fh_lock_parent(fhp, dchild);
-		if (err)
+			err = -EIO;
 			goto out;
 	}
+	}
 	/*
 	 * Make sure the child dentry is still negative ...
 	 */
 	err = nfserr_exist;
 	if (dchild->d_inode) {
-		printk(KERN_WARNING
-			"nfsd_create: dentry %s/%s not negative!\n",
+		dprintk("nfsd_create: dentry %s/%s not negative!\n",
 			dentry->d_name.name, dchild->d_name.name);
 		goto out; 
 	}
@@ -740,24 +935,29 @@
 	case S_IFSOCK:
 		opfunc = dirp->i_op->mknod;
 		break;
+	default:
+	        printk("nfsd: bad file type %o in nfsd_create\n", type);
+		err = nfserr_inval;
 	}
 	if (!opfunc)
 		goto out;
 
 	if (!(iap->ia_valid & ATTR_MODE))
 		iap->ia_mode = 0;
+	iap->ia_mode = (iap->ia_mode & S_IALLUGO) | type;
 
 	/*
 	 * Call the dir op function to create the object.
 	 */
 	DQUOT_INIT(dirp);
 	err = opfunc(dirp, dchild, iap->ia_mode, rdev);
-	DQUOT_DROP(dirp);
 	if (err < 0)
 		goto out_nfserr;
 
-	if (EX_ISSYNC(fhp->fh_export))
-		write_inode_now(dirp);
+	if (EX_ISSYNC(fhp->fh_export)) {
+		nfsd_sync_dir(dentry);
+		write_inode_now(dchild->d_inode);
+	}
 
 	/*
 	 * Update the file handle to get the new inode info.
@@ -780,6 +980,129 @@
 	goto out;
 }
 
+#ifdef CONFIG_NFSD_V3
+/*
+ * NFSv3 version of nfsd_create
+ */
+int
+nfsd_create_v3(struct svc_rqst *rqstp, struct svc_fh *fhp,
+		char *fname, int flen, struct iattr *iap,
+		struct svc_fh *resfhp, int createmode, u32 *verifier)
+{
+	struct dentry	*dentry, *dchild;
+	struct inode	*dirp;
+	int		err;
+
+	err = nfserr_perm;
+	if (!flen)
+		goto out;
+	if (!(iap->ia_valid & ATTR_MODE))
+		iap->ia_mode = 0;
+	err = fh_verify(rqstp, fhp, S_IFDIR, MAY_CREATE);
+	if (err)
+		goto out;
+
+	dentry = fhp->fh_dentry;
+	dirp = dentry->d_inode;
+
+	/* Get all the sanity checks out of the way before
+	 * we lock the parent. */
+	err = nfserr_notdir;
+	if(!dirp->i_op || !dirp->i_op->lookup)
+		goto out;
+	err = nfserr_perm;
+	if(!dirp->i_op->create)
+		goto out;
+
+	err = nfserr_exist;
+	if (isdotent(fname, flen))
+		goto out;
+	/*
+	 * Compose the response file handle.
+	 */
+	dchild = lookup_dentry(fname, dget(dentry), 0);
+	err = PTR_ERR(dchild);
+	if(IS_ERR(dchild))
+		goto out_nfserr;
+	fh_compose(resfhp, fhp->fh_export, dchild);
+
+	/*
+	 * We must lock the directory before we check for the inode.
+	 */
+	err = fh_lock_parent(fhp, dchild);
+	if (err)
+	    goto out;
+
+	if (dchild->d_inode) {
+		err = 0;
+
+		if (resfhp->fh_handle.fh_ino == 0)
+		     /* inode might have been instantiated while we slept */
+		    fh_update(resfhp);
+		
+		switch (createmode) {
+		case NFS3_CREATE_UNCHECKED:
+			if (! S_ISREG(dchild->d_inode->i_mode))
+				err = nfserr_exist;
+			else {
+				iap->ia_valid &= ATTR_SIZE;
+				goto set_attr;
+			}
+			break;
+		case NFS3_CREATE_EXCLUSIVE:
+			if (   dchild->d_inode->i_mtime == verifier[0]
+			    && dchild->d_inode->i_atime == verifier[1]
+			    && dchild->d_inode->i_mode == S_IFREG
+			    && dchild->d_inode->i_size == 0 )
+				break;
+			 /* fallthru */
+		case NFS3_CREATE_GUARDED:
+			err = nfserr_exist;
+		}
+		goto out;
+	}
+
+	err = dirp->i_op->create(dirp, dchild, iap->ia_mode);
+	if (err < 0)
+		goto out_nfserr;
+
+	if (EX_ISSYNC(fhp->fh_export)) {
+		nfsd_sync_dir(dentry);
+		/* setattr will sync the child (or not) */
+	}
+
+	/*
+	 * Update the filehandle to get the new inode info.
+	 */
+	fh_update(resfhp);
+	err = 0;
+
+	if (createmode == NFS3_CREATE_EXCLUSIVE) {
+		/* Cram the verifier into atime/mtime */
+		iap->ia_valid = ATTR_MTIME|ATTR_ATIME|ATTR_MTIME_SET|ATTR_ATIME_SET;
+		iap->ia_mtime = verifier[0];
+		iap->ia_atime = verifier[1];
+	}
+
+	/* Set file attributes. Mode has already been set and
+	 * setting uid/gid works only for root. Irix appears to
+	 * send along the gid when it tries to implement setgid
+	 * directories via NFS. Clear out all that cruft.
+	 */
+ set_attr:
+	if ((iap->ia_valid &= ~(ATTR_UID|ATTR_GID|ATTR_MODE)) != 0)
+ 		err = nfsd_setattr(rqstp, resfhp, iap);
+
+ out:
+	fh_unlock(fhp);
+ 	return err;
+ 
+ out_nfserr:
+	err = nfserrno(-err);
+	goto out;
+}
+#endif /* CONFIG_NFSD_V3 */
+
 /*
  * Truncate a file.
  * The calling routines must make sure to update the ctime
@@ -818,15 +1141,16 @@
 		cap_clear(current->cap_effective);
 	}
 	err = notify_change(dentry, &newattrs);
-	if (current->fsuid != 0)
-		current->cap_effective = saved_cap;
 	if (!err) {
 		vmtruncate(inode, size);
 		if (inode->i_op && inode->i_op->truncate)
 			inode->i_op->truncate(inode);
 	}
+	if (current->fsuid != 0)
+		current->cap_effective = saved_cap;
 	put_write_access(inode);
-	DQUOT_DROP(inode);
+	if (EX_ISSYNC(fhp->fh_export))
+		nfsd_sync_dir(dentry);
 	fh_unlock(fhp);
 out_nfserr:
 	if (err)
@@ -860,7 +1184,10 @@
 		goto out;
 
 	UPDATE_ATIME(inode);
-	/* N.B. Why does this call need a get_fs()?? */
+	/* N.B. Why does this call need a get_fs()??
+	 * Remove the set_fs and watch the fireworks:-) --okir
+	 */
+
 	oldfs = get_fs(); set_fs(KERNEL_DS);
 	err = inode->i_op->readlink(dentry, buf, *lenp);
 	set_fs(oldfs);
@@ -885,7 +1212,8 @@
 nfsd_symlink(struct svc_rqst *rqstp, struct svc_fh *fhp,
 				char *fname, int flen,
 				char *path,  int plen,
-				struct svc_fh *resfhp)
+				struct svc_fh *resfhp,
+				struct iattr *iap)
 {
 	struct dentry	*dentry, *dnew;
 	struct inode	*dirp;
@@ -900,9 +1228,11 @@
 		goto out;
 	dentry = fhp->fh_dentry;
 
-	err = nfserr_perm;
-	if (nfsd_iscovered(dentry, fhp->fh_export))
+	err = nfserr_exist;
+	if (isdotent(fname, flen))
 		goto out;
+
+	err = nfserr_perm;
 	dirp = dentry->d_inode;
 	if (!dirp->i_op	|| !dirp->i_op->symlink)
 		goto out;
@@ -923,10 +1253,20 @@
 	if (!dnew->d_inode) {
 		DQUOT_INIT(dirp);
 		err = dirp->i_op->symlink(dirp, dnew, path);
-		DQUOT_DROP(dirp);
 		if (!err) {
 			if (EX_ISSYNC(fhp->fh_export))
-				write_inode_now(dirp);
+				nfsd_sync_dir(dentry);
+			if (iap) {
+				iap->ia_valid &= ATTR_MODE /* ~(ATTR_MODE|ATTR_UID|ATTR_GID)*/;
+				if (iap->ia_valid) {
+					iap->ia_valid |= ATTR_CTIME;
+					iap->ia_mode = (iap->ia_mode&S_IALLUGO)
+						| S_IFLNK;
+					err = notify_change(dnew, iap);
+					if (!err && EX_ISSYNC(fhp->fh_export))
+						write_inode_now(dentry->d_inode);
+			       }
+			}
 		} else
 			err = nfserrno(-err);
 	}
@@ -950,7 +1290,7 @@
  */
 int
 nfsd_link(struct svc_rqst *rqstp, struct svc_fh *ffhp,
-				char *fname, int len, struct svc_fh *tfhp)
+				char *fname, int flen, struct svc_fh *tfhp)
 {
 	struct dentry	*ddir, *dnew, *dold;
 	struct inode	*dirp, *dest;
@@ -959,12 +1299,16 @@
 	err = fh_verify(rqstp, ffhp, S_IFDIR, MAY_CREATE);
 	if (err)
 		goto out;
-	err = fh_verify(rqstp, tfhp, S_IFREG, MAY_NOP);
+	err = fh_verify(rqstp, tfhp, -S_IFDIR, MAY_NOP);
 	if (err)
 		goto out;
 
 	err = nfserr_perm;
-	if (!len)
+	if (!flen)
+		goto out;
+
+	err = nfserr_exist;
+	if (isdotent(fname, flen))
 		goto out;
 
 	ddir = ffhp->fh_dentry;
@@ -988,10 +1332,7 @@
 	dold = tfhp->fh_dentry;
 	dest = dold->d_inode;
 
-	err = nfserr_acces;
-	if (nfsd_iscovered(ddir, ffhp->fh_export))
-		goto out_unlock;
-	/* FIXME: nxdev for NFSv3 */
+	err = (rqstp->rq_vers == 2) ? nfserr_acces : nfserr_xdev;
 	if (dirp->i_dev != dest->i_dev)
 		goto out_unlock;
 
@@ -1003,10 +1344,9 @@
 
 	DQUOT_INIT(dirp);
 	err = dirp->i_op->link(dold, dirp, dnew);
-	DQUOT_DROP(dirp);
 	if (!err) {
 		if (EX_ISSYNC(ffhp->fh_export)) {
-			write_inode_now(dirp);
+			nfsd_sync_dir(ddir);
 			write_inode_now(dest);
 		}
 	} else
@@ -1025,26 +1365,12 @@
 }
 
 /*
- * We need to do a check-parent every time
- * after we have locked the parent - to verify
- * that the parent is still our parent and
- * that we are still hashed onto it..
- *
- * This is requied 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..
- */
-#define check_parent(dir, dentry) \
-	((dir) == (dentry)->d_parent->d_inode && !list_empty(&dentry->d_hash))
-
-/*
  * This follows the model of double_lock() in the VFS.
  */
 static inline void nfsd_double_down(struct semaphore *s1, struct semaphore *s2)
 {
 	if (s1 != s2) {
-		if ((unsigned long) s1 > (unsigned long) s2) {
+		if ((unsigned long) s1 < (unsigned long) s2) {
 			struct semaphore *tmp = s1;
 			s1 = s2;
 			s2 = tmp;
@@ -1086,12 +1412,12 @@
 	tdentry = tfhp->fh_dentry;
 	tdir = tdentry->d_inode;
 
-	/* N.B. We shouldn't need this ... dentry layer handles it */
+	err = (rqstp->rq_vers == 2) ? nfserr_acces : nfserr_xdev;
+	if (fdir->i_dev != tdir->i_dev)
+		goto out;
+
 	err = nfserr_perm;
-	if (!flen || (fname[0] == '.' && 
-	    (flen == 1 || (flen == 2 && fname[1] == '.'))) ||
-	    !tlen || (tname[0] == '.' && 
-	    (tlen == 1 || (tlen == 2 && tname[1] == '.'))))
+	if (!flen || isdotent(fname, flen) || !tlen || isdotent(tname, tlen))
 		goto out;
 
 	odentry = lookup_dentry(fname, dget(fdentry), 0);
@@ -1112,31 +1438,36 @@
 	 * Lock the parent directories.
 	 */
 	nfsd_double_down(&tdir->i_sem, &fdir->i_sem);
+
+#ifdef CONFIG_NFSD_V3
+	/* Fill in the pre-op attr for the wcc data for both 
+	 * tdir and fdir
+	 */ 
+	fill_pre_wcc(ffhp);
+	fill_pre_wcc(tfhp);
+#endif /* CONFIG_NFSD_V3 */
+
 	err = -ENOENT;
 	/* GAM3 check for parent changes after locking. */
-	if (check_parent(fdir, odentry) &&
-	    check_parent(tdir, ndentry)) {
+	if (nfsd_check_parent(fdentry, odentry) &&
+	    nfsd_check_parent(tdentry, ndentry)) {
 
 		err = vfs_rename(fdir, odentry, tdir, ndentry);
 		if (!err && EX_ISSYNC(tfhp->fh_export)) {
-			write_inode_now(fdir);
-			write_inode_now(tdir);
+			nfsd_sync_dir(tdentry);
+			nfsd_sync_dir(fdentry);
 		}
 	} else
 		dprintk("nfsd: Caught race in nfsd_rename");
-	DQUOT_DROP(fdir);
-	DQUOT_DROP(tdir);
 
+#ifdef CONFIG_NFSD_V3
+        /* Fill in the post-op attr for the wcc data for both 
+         * tdir and fdir
+         */
+	fill_post_wcc(ffhp);
+	fill_post_wcc(tfhp);
+#endif /* CONFIG_NFSD_V3 */
 	nfsd_double_up(&tdir->i_sem, &fdir->i_sem);
-
-	if (!err && odentry->d_inode) {
-		add_to_rename_cache(tdir->i_ino,
-				    odentry->d_inode->i_dev,
-				    fdir->i_ino,
-				    odentry->d_inode->i_ino);
-	} else {
-		printk(": no inode in rename or err: %d.\n", err);
-	}
 	dput(ndentry);
 
 out_dput_old:
@@ -1163,13 +1494,12 @@
 	struct inode	*dirp;
 	int		err;
 
-	/* N.B. We shouldn't need this test ... handled by dentry layer */
-	err = nfserr_acces;
-	if (!flen || isdotent(fname, flen))
-		goto out;
 	err = fh_verify(rqstp, fhp, S_IFDIR, MAY_REMOVE);
 	if (err)
 		goto out;
+	err = nfserr_acces;
+	if (!flen || isdotent(fname, flen))
+		goto out;
 
 	dentry = fhp->fh_dentry;
 	dirp = dentry->d_inode;
@@ -1178,13 +1508,13 @@
 	err = PTR_ERR(rdentry);
 	if (IS_ERR(rdentry))
 		goto out_nfserr;
+
 	if (!rdentry->d_inode) {
 		dput(rdentry);
 		err = nfserr_noent;
 		goto out;
 	}
 
-	expire_by_dentry(rdentry);
 
 	if (type != S_IFDIR) {
 		/* It's UNLINK */
@@ -1195,30 +1525,33 @@
 
 		err = vfs_unlink(dirp, rdentry);
 
-		DQUOT_DROP(dirp);
 		fh_unlock(fhp);
 
 		dput(rdentry);
-		expire_by_dentry(rdentry);
+
 	} else {
 		/* It's RMDIR */
 		/* See comments in fs/namei.c:do_rmdir */
 
 		rdentry->d_count++;
 		nfsd_double_down(&dirp->i_sem, &rdentry->d_inode->i_sem);
-		if (!fhp->fh_pre_mtime)
-			fhp->fh_pre_mtime = dirp->i_mtime;
+
+#ifdef CONFIG_NFSD_V3
+		fill_pre_wcc(fhp);
+#else
 		fhp->fh_locked = 1;
+#endif /* CONFIG_NFSD_V3 */
 
 		err = -ENOENT;
-		if (check_parent(dirp, rdentry))
+		if (nfsd_check_parent(dentry, rdentry))
 			err = vfs_rmdir(dirp, rdentry);
 
 		rdentry->d_count--;
-		DQUOT_DROP(dirp);
-		if (!fhp->fh_post_version)
-			fhp->fh_post_version = dirp->i_version;
+#ifdef CONFIG_NFSD_V3
+		fill_post_wcc(fhp);
+#else
 		fhp->fh_locked = 0;
+#endif /* CONFIG_NFSD_V3 */
 		nfsd_double_up(&dirp->i_sem, &rdentry->d_inode->i_sem);
 
 		dput(rdentry);
@@ -1226,9 +1559,11 @@
 
 	if (err)
 		goto out_nfserr;
-	if (EX_ISSYNC(fhp->fh_export))
-		write_inode_now(dirp);
-
+	if (EX_ISSYNC(fhp->fh_export)) {
+		down(&dentry->d_inode->i_sem);
+		nfsd_sync_dir(dentry);
+		up(&dentry->d_inode->i_sem);
+	}
 out:
 	return err;
 
@@ -1239,10 +1574,11 @@
 
 /*
  * Read entries from a directory.
+ * The verifier is an NFSv3 thing we ignore for now.
  */
 int
 nfsd_readdir(struct svc_rqst *rqstp, struct svc_fh *fhp, loff_t offset, 
-			encode_dent_fn func, u32 *buffer, int *countp)
+             encode_dent_fn func, u32 *buffer, int *countp, u32 *verf)
 {
 	struct inode	*inode;
 	u32		*p;
@@ -1254,7 +1590,7 @@
 	if (offset > ~(u32) 0)
 		goto out;
 
-	err = nfsd_open(rqstp, fhp, S_IFDIR, OPEN_READ, &file);
+	err = nfsd_open(rqstp, fhp, S_IFDIR, MAY_READ, &file);
 	if (err)
 		goto out;
 
@@ -1268,6 +1604,7 @@
 	cd.rqstp  = rqstp;
 	cd.buffer = buffer;
 	cd.buflen = *countp; /* count of words */
+	cd.dirfh  = fhp;
 
 	/*
 	 * Read the directory entries. This silly loop is necessary because
@@ -1297,8 +1634,14 @@
 	/* If we didn't fill the buffer completely, we're at EOF */
 	eof = !cd.eob;
 
-	if (cd.offset)
-		*cd.offset = htonl(file.f_pos);
+	if (cd.offset) {
+#ifdef CONFIG_NFSD_V3
+		if (rqstp->rq_vers == 3)
+			(void)enc64(cd.offset, file.f_pos);
+		else
+#endif /* CONFIG_NFSD_V3 */
+			*cd.offset = htonl(file.f_pos);
+	}
 
 	p = cd.buffer;
 	*p++ = 0;			/* no more entries */
@@ -1361,17 +1704,33 @@
 	struct inode	*inode = dentry->d_inode;
 	int		err;
 	kernel_cap_t	saved_cap = 0;
+	int		owneraccess;
+
+	/*
+	 *  Check if we are to use "owner may always access" semantics,
+	 *  then clean out the flag bit which controls this. It might be
+	 *  clearer to reverse the logic of this flag, but I didn't
+	 *  want to change a lot of code in a stable kernel - dhiggen.
+	 */
 
+	if (acc & NO_OWNER_OVERRIDE) {
+		owneraccess = 0;
+		acc &= ~NO_OWNER_OVERRIDE;
+	} else {
+		owneraccess = 1;
+	}
+
 	if (acc == MAY_NOP)
 		return 0;
 #if 0
-	dprintk("nfsd: permission 0x%x%s%s%s%s%s mode 0%o%s%s%s\n",
+	dprintk("nfsd: permission 0x%x%s%s%s%s%s%s mode 0%o%s%s%s\n",
 		acc,
 		(acc & MAY_READ)?	" read"  : "",
 		(acc & MAY_WRITE)?	" write" : "",
 		(acc & MAY_EXEC)?	" exec"  : "",
 		(acc & MAY_SATTR)?	" sattr" : "",
 		(acc & MAY_TRUNC)?	" trunc" : "",
+		(acc & MAY_LOCK)?	" lock"  : "",
 		inode->i_mode,
 		IS_IMMUTABLE(inode)?	" immut" : "",
 		IS_APPEND(inode)?	" append" : "",
@@ -1379,33 +1738,40 @@
 	dprintk("      owner %d/%d user %d/%d\n",
 		inode->i_uid, inode->i_gid, current->fsuid, current->fsgid);
 #endif
-#ifndef CONFIG_NFSD_SUN
-	if (dentry->d_mounts != dentry) {
-		return nfserr_perm;
-	}
-#endif
 
 	if (acc & (MAY_WRITE | MAY_SATTR | MAY_TRUNC)) {
 		if (EX_RDONLY(exp) || IS_RDONLY(inode))
 			return nfserr_rofs;
-		if (S_ISDIR(inode->i_mode) && nfsd_iscovered(dentry, exp))
-			return nfserr_perm;
 		if (/* (acc & MAY_WRITE) && */ IS_IMMUTABLE(inode))
 			return nfserr_perm;
 	}
 	if ((acc & MAY_TRUNC) && IS_APPEND(inode))
 		return nfserr_perm;
 
+	if (acc & MAY_LOCK) {
+		/* If we cannot rely on authentication in NLM requests,
+		 * just allow locks, others require read permission
+		 */
+		if (exp->ex_flags & NFSEXP_NOAUTHNLM)
+			return 0;
+		else
+			acc = MAY_READ;
+	}
 	/*
-	 * The file owner always gets access permission. This is to make
-	 * file access work even when the client has done a fchmod(fd, 0).
+	 * The file owner always gets access permission (except in the 
+	 * special case of a V3 ACCESS call, which is used for checking at 
+	 * open() time). This is to make file access work even when the 
+	 * client has done a fchmod(fd, 0).
 	 *
 	 * However, `cp foo bar' should fail nevertheless when bar is
 	 * readonly. A sensible way to do this might be to reject all
 	 * attempts to truncate a read-only file, because a creat() call
 	 * always implies file truncation.
+	 *  dhXXX we are not currently setting MAY_TRUNC from a SETATTR which
+	 *  changes the size, so this check is not enforced.  It probably
+	 *  should be?
 	 */
-	if (inode->i_uid == current->fsuid /* && !(acc & MAY_TRUNC) */)
+	if (owneraccess && inode->i_uid == current->fsuid /* && !(acc & MAY_TRUNC) */)
 		return 0;
 
 	if (current->fsuid != 0) {
Index: oldkernel/linux/fs/ntfs/fs.c
diff -u linux/fs/ntfs/fs.c:1.2 linux/fs/ntfs/fs.c:1.3
--- linux/fs/ntfs/fs.c:1.2	Thu Jun  1 15:03:09 2000
+++ linux/fs/ntfs/fs.c	Fri Jul  7 15:36:46 2000
@@ -818,7 +818,6 @@
 	struct statfs fs;
 	struct inode *mft;
 	ntfs_volume *vol;
-	ntfs_u64 size;
 	int error;
 
 	ntfs_debug(DEBUG_OTHER, "ntfs_statfs\n");
@@ -827,17 +826,16 @@
 	fs.f_type=NTFS_SUPER_MAGIC;
 	fs.f_bsize=vol->clustersize;
 
-	error = ntfs_get_volumesize( NTFS_SB2VOL( sb ), &size );
+	error = ntfs_get_volumesize( NTFS_SB2VOL( sb ), &fs.f_blocks );
 	if( error )
 		return -error;
-	fs.f_blocks = size;
 	fs.f_bfree=ntfs_get_free_cluster_count(vol->bitmap);
 	fs.f_bavail=fs.f_bfree;
 
 	/* Number of files is limited by free space only, so we lie here */
 	fs.f_ffree=0;
 	mft=iget(sb,FILE_MFT);
-	fs.f_files = (long)mft->i_size / vol->mft_recordsize;
+	fs.f_files=mft->i_size/vol->mft_recordsize;
 	iput(mft);
 
 	/* should be read from volume */
Index: oldkernel/linux/fs/ntfs/super.c
diff -u linux/fs/ntfs/super.c:1.2 linux/fs/ntfs/super.c:1.3
--- linux/fs/ntfs/super.c:1.2	Thu Jun  1 15:03:09 2000
+++ linux/fs/ntfs/super.c	Fri Jul  7 15:36:46 2000
@@ -253,7 +253,7 @@
  * Writes the volume size into vol_size. Returns 0 if successful
  * or error.
  */
-int ntfs_get_volumesize(ntfs_volume *vol, ntfs_u64 *vol_size )
+int ntfs_get_volumesize(ntfs_volume *vol, long *vol_size )
 {
 	ntfs_io io;
 	ntfs_u64 size;
@@ -274,7 +274,9 @@
 	ntfs_getput_clusters(vol,0,0,&io);
 	size=NTFS_GETU64(cluster0+0x28);
 	ntfs_free(cluster0);
-	*vol_size = size;
+	/* FIXME: more than 2**32 cluster */
+	/* FIXME: gcc will emit udivdi3 if we don't truncate it */
+	*vol_size = ((unsigned long)size)/vol->clusterfactor;
 	return 0;
 }
 
Index: oldkernel/linux/fs/ntfs/super.h
diff -u linux/fs/ntfs/super.h:1.2 linux/fs/ntfs/super.h:1.3
--- linux/fs/ntfs/super.h:1.2	Thu Jun  1 15:03:09 2000
+++ linux/fs/ntfs/super.h	Fri Jul  7 15:36:46 2000
@@ -10,7 +10,7 @@
 #define ALLOC_REQUIRE_SIZE     2
 
 int ntfs_get_free_cluster_count(ntfs_inode *bitmap);
-int ntfs_get_volumesize(ntfs_volume *vol, ntfs_u64 *vol_size );
+int ntfs_get_volumesize(ntfs_volume *vol, long *vol_size );
 int ntfs_init_volume(ntfs_volume *vol,char *boot);
 int ntfs_load_special_files(ntfs_volume *vol);
 int ntfs_release_volume(ntfs_volume *vol);
Index: oldkernel/linux/fs/proc/array.c
diff -u linux/fs/proc/array.c:1.4 linux/fs/proc/array.c:1.5
--- linux/fs/proc/array.c:1.4	Thu Jun  1 17:02:44 2000
+++ linux/fs/proc/array.c	Fri Jul  7 15:36:46 2000
@@ -1151,11 +1151,11 @@
  *         + (index into the line)
  */
 /* for systems with sizeof(void*) == 4: */
-#define MAPS_LINE_FORMAT4	  "%08lx-%08lx %s %016Lx %s %lu"
-#define MAPS_LINE_MAX4	57 /* sum of 8  1  8  1 4 1 16 1 5 1 10 1 */
+#define MAPS_LINE_FORMAT4	  "%08lx-%08lx %s %08lx %s %lu"
+#define MAPS_LINE_MAX4	49 /* sum of 8  1  8  1 4 1 8 1 5 1 10 1 */
 
 /* for systems with sizeof(void*) == 8: */
-#define MAPS_LINE_FORMAT8	  "%016lx-%016lx %s %016Lx %s %lu"
+#define MAPS_LINE_FORMAT8	  "%016lx-%016lx %s %016lx %s %lu"
 #define MAPS_LINE_MAX8	73 /* sum of 16  1  16  1 4 1 16 1 5 1 10 1 */
 
 #define MAPS_LINE_MAX	MAPS_LINE_MAX8
Index: oldkernel/linux/fs/proc/proc_tty.c
diff -u linux/fs/proc/proc_tty.c:1.1.1.1 linux/fs/proc/proc_tty.c:1.2
--- linux/fs/proc/proc_tty.c:1.1.1.1	Wed May 31 12:33:48 2000
+++ linux/fs/proc/proc_tty.c	Fri Jul  7 15:36:47 2000
@@ -93,7 +93,7 @@
 		*eof = 1;
 	if (off >= len+begin)
 		return 0;
-	*start = page + (begin-off);
+	*start = page + (off-begin);
 	return ((count < begin+len-off) ? count : begin+len-off);
 }
 
@@ -123,7 +123,7 @@
 		*eof = 1;
 	if (off >= len+begin)
 		return 0;
-	*start = page + (begin-off);
+	*start = page + (off-begin);
 	return ((count < begin+len-off) ? count : begin+len-off);
 }
 
Index: oldkernel/linux/fs/qnx4/file.c
diff -u linux/fs/qnx4/file.c:1.2 linux/fs/qnx4/file.c:1.3
--- linux/fs/qnx4/file.c:1.2	Thu Jun  1 15:03:09 2000
+++ linux/fs/qnx4/file.c	Fri Jul  7 15:36:47 2000
@@ -213,8 +213,7 @@
 	struct buffer_head *bh;
 	int res = -EIO;
 
-	QNX4DEBUG(("qnx4: readpage offset=[%ld]\n",
-		   (u_long) pgoff2ulong(page->index)));
+	QNX4DEBUG(("qnx4: readpage offset=[%ld]\n", (long) page->offset));
 
 	if (qnx4_ino->i_xblk != 0) {
 		printk("qnx4: sorry, this file is extended, don't know how to handle it (yet) !\n");
@@ -225,7 +224,7 @@
 	buf = page_address(page);
 	clear_bit(PG_uptodate, &page->flags);
 	clear_bit(PG_error, &page->flags);
-	offset = pgoff2loff(page->index);
+	offset = page->offset;
 
 	if (offset < inode->i_size) {
 		res = 0;
Index: oldkernel/linux/fs/romfs/inode.c
diff -u linux/fs/romfs/inode.c:1.2 linux/fs/romfs/inode.c:1.3
--- linux/fs/romfs/inode.c:1.2	Thu Jun  1 15:03:09 2000
+++ linux/fs/romfs/inode.c	Fri Jul  7 15:36:47 2000
@@ -59,6 +59,7 @@
 #include <linux/init.h>
 
 #include <asm/uaccess.h>
+#include <asm/pgtable.h>
 
 static int inline min(int a, int b)
 {
@@ -395,7 +396,7 @@
 	buf = page_address(page);
 	clear_bit(PG_uptodate, &page->flags);
 	clear_bit(PG_error, &page->flags);
-	offset = pgoff2loff(page->index);
+	offset = page->offset;
 	if (offset < inode->i_size) {
 		avail = inode->i_size-offset;
 		readlen = min(avail, PAGE_SIZE);
@@ -403,6 +404,7 @@
 			if (readlen < PAGE_SIZE) {
 				memset((void *)(buf+readlen),0,PAGE_SIZE-readlen);
 			}
+			flush_dcache_page(page_address(page));
 			set_bit(PG_uptodate, &page->flags);
 			result = 0;
 		}
Index: oldkernel/linux/fs/smbfs/cache.c
diff -u linux/fs/smbfs/cache.c:1.2 linux/fs/smbfs/cache.c:1.3
--- linux/fs/smbfs/cache.c:1.2	Thu Jun  1 15:03:09 2000
+++ linux/fs/smbfs/cache.c	Fri Jul  7 15:36:47 2000
@@ -41,13 +41,14 @@
 printk("smb_get_dircache: finding cache for %s/%s\n",
 dentry->d_parent->d_name.name, dentry->d_name.name);
 #endif
-	cachep = (struct cache_head *) get_cached_page(inode,ulong2pgoff(0),1);
+	cachep = (struct cache_head *) get_cached_page(inode, 0, 1);
 	if (!cachep)
 		goto out;
 	if (cachep->valid)
 	{
 		struct cache_index * index = cachep->index;
 		struct cache_block * block;
+		unsigned long offset;
 		int i;
 
 		cachep->valid = 0;
@@ -61,10 +62,9 @@
 printk("smb_get_dircache: cache %s/%s has existing block!\n",
 dentry->d_parent->d_name.name, dentry->d_name.name);
 #endif
-			/* byte_offset = PAGE_SIZE + (i << PAGE_SHIFT); */
-			/*    --> page_offset = 1 + i  */ 
-			block = (struct cache_block *)
-				get_cached_page(inode, ulong2pgoff(i+1), 0);
+			offset = PAGE_SIZE + (i << PAGE_SHIFT);
+			block = (struct cache_block *) get_cached_page(inode,
+								offset, 0);
 			if (!block)
 				goto out;
 			index->block = block;
@@ -135,7 +135,7 @@
 	struct inode * inode = get_cache_inode(cachep);
 	struct cache_index * index;
 	struct cache_block * block;
-	pgoff_t page_off;
+	unsigned long page_off;
 	unsigned int nent, offset, len = entry->len;
 	unsigned int needed = len + sizeof(struct cache_entry);
 
@@ -191,8 +191,7 @@
 	 */
 get_block:
 	cachep->pages++;
-	/* page_byte_off = PAGE_SIZE + (cachep->idx << PAGE_SHIFT); */
-	page_off = ulong2pgoff(1 + cachep->idx);
+	page_off = PAGE_SIZE + (cachep->idx << PAGE_SHIFT);
 	block = (struct cache_block *) get_cached_page(inode, page_off, 1);
 	if (block)
 	{
@@ -200,7 +199,7 @@
 		index->space = PAGE_SIZE;
 #ifdef SMBFS_DEBUG_VERBOSE
 printk("smb_add_to_cache: inode=%p, pages=%d, block at %ld\n",
-inode, cachep->pages, (u_long)pgoff2loff(page_off));
+inode, cachep->pages, page_off);
 #endif
 		goto add_entry;
 	}
Index: oldkernel/linux/fs/smbfs/file.c
diff -u linux/fs/smbfs/file.c:1.2 linux/fs/smbfs/file.c:1.3
--- linux/fs/smbfs/file.c:1.2	Thu Jun  1 15:03:09 2000
+++ linux/fs/smbfs/file.c	Fri Jul  7 15:36:47 2000
@@ -14,10 +14,10 @@
 #include <linux/mm.h>
 #include <linux/malloc.h>
 #include <linux/pagemap.h>
-#include <linux/unistd.h>
 
 #include <asm/uaccess.h>
 #include <asm/system.h>
+#include <asm/pgtable.h>
 
 #include <linux/smbno.h>
 #include <linux/smb_fs.h>
@@ -56,7 +56,7 @@
 smb_readpage_sync(struct dentry *dentry, struct page *page)
 {
 	char *buffer = (char *) page_address(page);
-	loff_t loffset = pgoff2loff(page->index);
+	unsigned long offset = page->offset;
 	int rsize = smb_get_rsize(server_from_dentry(dentry));
 	int count = PAGE_SIZE;
 	int result;
@@ -64,8 +64,8 @@
 	clear_bit(PG_error, &page->flags);
 
 #ifdef SMBFS_DEBUG_VERBOSE
-printk("smb_readpage_sync: file %s/%s, count=%d@%Ld, rsize=%d\n",
-dentry->d_parent->d_name.name, dentry->d_name.name, count, loffset, rsize);
+printk("smb_readpage_sync: file %s/%s, count=%d@%ld, rsize=%d\n",
+dentry->d_parent->d_name.name, dentry->d_name.name, count, offset, rsize);
 #endif
 	result = smb_open(dentry, SMB_O_RDONLY);
 	if (result < 0)
@@ -81,12 +81,12 @@
 		if (count < rsize)
 			rsize = count;
 
-		result = smb_proc_read(dentry, loffset, rsize, buffer);
+		result = smb_proc_read(dentry, offset, rsize, buffer);
 		if (result < 0)
 			goto io_error;
 
 		count -= result;
-		loffset += result;
+		offset += result;
 		buffer += result;
 		dentry->d_inode->i_atime = CURRENT_TIME;
 		if (result < rsize)
@@ -94,6 +94,7 @@
 	} while (count);
 
 	memset(buffer, 0, count);
+	flush_dcache_page(page_address(page));
 	set_bit(PG_uptodate, &page->flags);
 	result = 0;
 
@@ -125,40 +126,25 @@
  * Offset is the data offset within the page.
  */
 static int
-smb_writepage_sync(struct file *file, struct page *page,
+smb_writepage_sync(struct dentry *dentry, struct page *page,
 		   unsigned long offset, unsigned int count)
 {
-	struct dentry * dentry = file->f_dentry;
 	struct inode *inode = dentry->d_inode;
 	u8 *buffer = (u8 *) page_address(page) + offset;
 	int wsize = smb_get_wsize(server_from_dentry(dentry));
 	int result, written = 0;
-	loff_t loffset = pgoff2loff(page->index) + offset;
 
+	offset += page->offset;
 #ifdef SMBFS_DEBUG_VERBOSE
 printk("smb_writepage_sync: file %s/%s, count=%d@%ld, wsize=%d\n",
-       dentry->d_parent->d_name.name, dentry->d_name.name, count,
-       loffset, wsize);
+dentry->d_parent->d_name.name, dentry->d_name.name, count, offset, wsize);
 #endif
 
-	if (!(file->f_flags & O_LARGEFILE) &&
-	    loffset >= 0x7ffffffeULL)
-	  return -EFBIG;
-
-	if (!(file->f_flags & O_LARGEFILE) &&
-	    loffset + count >= 0x7fffffffULL)
-	  count = LONG_MAX - loffset;
-
-	if (loffset >= 0xffffffffULL) /* 4G-1 ???  Or 2G-1 ??? */
-	  return -EFBIG;
-	if ((loffset + count) >= 0xffffffffULL)
-	  count = 0xffffffffULL - loffset;
-
 	do {
 		if (count < wsize)
 			wsize = count;
 
-		result = smb_proc_write(dentry, loffset, wsize, buffer);
+		result = smb_proc_write(dentry, offset, wsize, buffer);
 		if (result < 0)
 			break;
 		/* N.B. what if result < wsize?? */
@@ -166,27 +152,29 @@
 if (result < wsize)
 printk("smb_writepage_sync: short write, wsize=%d, result=%d\n", wsize, result);
 #endif
-		buffer  += wsize;
-		loffset += wsize;
+		buffer += wsize;
+		offset += wsize;
 		written += wsize;
-		count   -= wsize;
+		count -= wsize;
 		/*
 		 * Update the inode now rather than waiting for a refresh.
 		 */
 		inode->i_mtime = inode->i_atime = CURRENT_TIME;
-		if (loffset > inode->i_size)
-			inode->i_size = loffset;
+		if (offset > inode->i_size)
+			inode->i_size = offset;
 		inode->u.smbfs_i.cache_valid |= SMB_F_LOCALWRITE;
 	} while (count);
 	return written ? written : result;
 }
 
 /*
- * Write a page to the server.
+ * Write a page to the server. This will be used for NFS swapping only
+ * (for now), and we currently do this synchronously only.
  */
 static int
 smb_writepage(struct file *file, struct page *page)
 {
+	struct dentry *dentry = file->f_dentry;
 	int 	result;
 
 #ifdef SMBFS_PARANOIA
@@ -195,22 +183,34 @@
 #endif
 	set_bit(PG_locked, &page->flags);
 	atomic_inc(&page->count);
-	result = smb_writepage_sync(file, page, 0, PAGE_SIZE);
+	result = smb_writepage_sync(dentry, page, 0, PAGE_SIZE);
 	smb_unlock_page(page);
 	free_page(page_address(page));
 	return result;
 }
 
 static int
-smb_updatepage(struct file *file, struct page *page, unsigned long offset, unsigned int count, int sync)
+smb_updatepage(struct file *file, struct page *page, const char *buf, unsigned long offset, unsigned int count, int sync)
 {
 	struct dentry *dentry = file->f_dentry;
+	void *dest;
+	int result = -EFAULT;
 
-	pr_debug("SMBFS: smb_updatepage(%s/%s %d@%Ld, sync=%d)\n",
+	pr_debug("SMBFS: smb_updatepage(%s/%s %d@%ld, sync=%d)\n",
 		dentry->d_parent->d_name.name, dentry->d_name.name,
-	 	count, pgoff2loff(page->index)+offset, sync);
+	 	count, page->offset+offset, sync);
+
+	dest = (u8*)page_address(page) + offset;
+	if (dest != buf)
+		count -= copy_from_user(dest, buf, count);
+	if (!count) {
+		clear_bit(PG_uptodate, &page->flags);
+		goto out;
+	}
 
-	return smb_writepage_sync(file, page, offset, count);
+	result = smb_writepage_sync(dentry, page, offset, count);
+ out:
+	return result;
 }
 
 static ssize_t
@@ -220,9 +220,9 @@
 	ssize_t	status;
 
 #ifdef SMBFS_DEBUG_VERBOSE
-printk("smb_file_read: file %s/%s, count=%lu@%Lu\n",
-       dentry->d_parent->d_name.name, dentry->d_name.name,
-       (unsigned long) count, *ppos);
+printk("smb_file_read: file %s/%s, count=%lu@%lu\n",
+dentry->d_parent->d_name.name, dentry->d_name.name,
+(unsigned long) count, (unsigned long) *ppos);
 #endif
 
 	status = smb_revalidate_inode(dentry);
@@ -253,8 +253,7 @@
 
 #ifdef SMBFS_DEBUG_VERBOSE
 printk("smb_file_mmap: file %s/%s, address %lu - %lu\n",
-       dentry->d_parent->d_name.name, dentry->d_name.name,
-       vma->vm_start, vma->vm_end);
+dentry->d_parent->d_name.name, dentry->d_name.name, vma->vm_start, vma->vm_end);
 #endif
 
 	status = smb_revalidate_inode(dentry);
@@ -262,7 +261,7 @@
 	{
 #ifdef SMBFS_PARANOIA
 printk("smb_file_mmap: %s/%s validation failed, error=%d\n",
-       dentry->d_parent->d_name.name, dentry->d_name.name, status);
+dentry->d_parent->d_name.name, dentry->d_name.name, status);
 #endif
 		goto out;
 	}
@@ -281,9 +280,9 @@
 	ssize_t	result;
 
 #ifdef SMBFS_DEBUG_VERBOSE
-printk("smb_file_write: file %s/%s, count=%lu@%Lu, pages=%ld\n",
-       dentry->d_parent->d_name.name, dentry->d_name.name,
-       (unsigned long) count, *ppos, dentry->d_inode->i_nrpages);
+printk("smb_file_write: file %s/%s, count=%lu@%lu, pages=%ld\n",
+dentry->d_parent->d_name.name, dentry->d_name.name,
+(unsigned long) count, (unsigned long) *ppos, dentry->d_inode->i_nrpages);
 #endif
 
 	result = smb_revalidate_inode(dentry);
@@ -291,7 +290,7 @@
 	{
 #ifdef SMBFS_PARANOIA
 printk("smb_file_write: %s/%s validation failed, error=%d\n",
-       dentry->d_parent->d_name.name, dentry->d_name.name, result);
+dentry->d_parent->d_name.name, dentry->d_name.name, result);
 #endif
 			goto out;
 	}
@@ -304,9 +303,9 @@
 	{
 		result = generic_file_write(file, buf, count, ppos);
 #ifdef SMBFS_DEBUG_VERBOSE
-printk("smb_file_write: pos=%Ld, size=%ld, mtime=%ld, atime=%ld\n",
-       file->f_pos, dentry->d_inode->i_size, dentry->d_inode->i_mtime,
-       dentry->d_inode->i_atime);
+printk("smb_file_write: pos=%ld, size=%ld, mtime=%ld, atime=%ld\n",
+(long) file->f_pos, dentry->d_inode->i_size, dentry->d_inode->i_mtime,
+dentry->d_inode->i_atime);
 #endif
 	}
 out:
Index: oldkernel/linux/fs/smbfs/proc.c
diff -u linux/fs/smbfs/proc.c:1.2 linux/fs/smbfs/proc.c:1.3
--- linux/fs/smbfs/proc.c:1.2	Thu Jun  1 15:03:09 2000
+++ linux/fs/smbfs/proc.c	Fri Jul  7 15:36:47 2000
@@ -1008,16 +1008,13 @@
    file-id would not be valid after a reconnection. */
 
 int
-smb_proc_read(struct dentry *dentry, loff_t offset, int count, char *data)
+smb_proc_read(struct dentry *dentry, off_t offset, int count, char *data)
 {
 	struct smb_sb_info *server = server_from_dentry(dentry);
 	__u16 returned_count, data_len;
 	char *buf;
 	int result;
 
-	if (offset > 0xffffffff)
-		return -EIO;
-
 	smb_lock_server(server);
 	smb_setup_header(server, SMBread, 5, 0);
 	buf = server->packet;
@@ -1053,17 +1050,14 @@
 }
 
 int
-smb_proc_write(struct dentry *dentry, loff_t offset, int count, const char *data)
+smb_proc_write(struct dentry *dentry, off_t offset, int count, const char *data)
 {
 	struct smb_sb_info *server = server_from_dentry(dentry);
 	int result;
 	__u8 *p;
 
-	if (offset > 0xffffffff)
-		return -EIO;
-
 #if SMBFS_DEBUG_VERBOSE
-printk("smb_proc_write: file %s/%s, count=%d@%Ld, packet_size=%d\n",
+printk("smb_proc_write: file %s/%s, count=%d@%ld, packet_size=%d\n",
        DENTRY_PATH(dentry), count, offset, server->packet_size);
 #endif
 	smb_lock_server(server);
@@ -1811,7 +1805,7 @@
 	fattr->f_mtime = date_dos2unix(server, date, time);
 #ifdef SMBFS_DEBUG_VERBOSE
 printk("smb_proc_getattr_ff: name=%s, date=%x, time=%x, mtime=%ld\n",
-       mask, date, time, fattr->f_mtime);
+mask, date, time, fattr->f_mtime);
 #endif
 	fattr->f_size = DVAL(resp_data, 12);
 	/* ULONG allocation size */
@@ -2069,7 +2063,7 @@
 	WSET(server->packet, smb_vwv6, time);
 #ifdef SMBFS_DEBUG_TIMESTAMP
 printk("smb_proc_setattr_ext: date=%d, time=%d, mtime=%ld\n", 
-       date, time, fattr->f_mtime);
+date, time, fattr->f_mtime);
 #endif
 
 	result = smb_request_ok(server, SMBsetattrE, 0, 0);
Index: oldkernel/linux/fs/sysv/file.c
diff -u linux/fs/sysv/file.c:1.2 linux/fs/sysv/file.c:1.3
--- linux/fs/sysv/file.c:1.2	Thu Jun  1 15:03:09 2000
+++ linux/fs/sysv/file.c	Fri Jul  7 15:36:47 2000
@@ -207,7 +207,7 @@
 {
 	struct inode * inode = filp->f_dentry->d_inode;
 	struct super_block * sb = inode->i_sb;
-	loff_t pos;
+	off_t pos;
 	ssize_t written, c;
 	struct buffer_head * bh;
 	char * p;
@@ -232,21 +232,6 @@
 	else
 		pos = *ppos;
 	written = 0;
-
-	/* L-F-S spec 2.2.1.27: */
-	if (!(filp->f_flags & O_LARGEFILE)) {
-		if (pos >= 0x7ffffffeULL) /* pos@2G forbidden */
-			return -EFBIG;
-
-		if (pos + count >= 0x7fffffffULL)
-			/* Write only until end of allowed region */
-			count = 0x7fffffffULL - pos;
-	}
-	if (pos >= 0xffffffffULL)
-		return -EFBIG; /* Only up to 4G-1! */
-	if ((pos + count) > 0xffffffffULL)
-		count = 0xffffffffULL - pos;
-
 	while (written<count) {
 		bh = sysv_getblk (inode, pos >> sb->sv_block_size_bits, 1);
 		if (!bh) {
Index: oldkernel/linux/fs/ufs/balloc.c
diff -u linux/fs/ufs/balloc.c:1.2 linux/fs/ufs/balloc.c:1.3
--- linux/fs/ufs/balloc.c:1.2	Thu Jun  1 15:03:09 2000
+++ linux/fs/ufs/balloc.c	Fri Jul  7 15:36:47 2000
@@ -660,9 +660,9 @@
 	struct ufs_sb_private_info * uspi;
 	struct ufs_super_block_first * usb1;
 	struct ufs_cylinder_group * ucg;
-	unsigned int start, length, location, result;
-	unsigned int possition, fragsize, blockmap, mask;
-	unsigned int swab;
+	unsigned start, length, location, result;
+	unsigned possition, fragsize, blockmap, mask;
+	unsigned swab;
 	
 	UFSD(("ENTER, cg %u, goal %u, count %u\n", ucpi->c_cgx, goal, count))
 
@@ -676,7 +676,7 @@
 	else
 		start = ucpi->c_frotor >> 3;
 		
-	length = ((uspi->s_fpg + 7) >> 3) - start;
+	length = howmany(uspi->s_fpg, 8) - start;
 	location = ubh_scanc(UCPI_UBH, ucpi->c_freeoff + start, length,
 		(uspi->s_fpb == 8) ? ufs_fragtable_8fpb : ufs_fragtable_other,
 		1 << (count - 1 + (uspi->s_fpb & 7))); 
Index: oldkernel/linux/fs/ufs/dir.c
diff -u linux/fs/ufs/dir.c:1.2 linux/fs/ufs/dir.c:1.3
--- linux/fs/ufs/dir.c:1.2	Thu Jun  1 15:03:09 2000
+++ linux/fs/ufs/dir.c	Fri Jul  7 15:36:47 2000
@@ -15,7 +15,6 @@
 
 #include <linux/fs.h>
 #include <linux/ufs_fs.h>
-#include <linux/unistd.h>
 
 #include "swab.h"
 #include "util.h"
@@ -171,7 +170,7 @@
 		error_msg = "inode out of bounds";
 
 	if (error_msg != NULL)
-		ufs_error (sb, function, "bad entry in directory #%lu, size %Lu: %s - "
+		ufs_error (sb, function, "bad entry in directory #%lu, size %lu: %s - "
 			    "offset=%lu, inode=%lu, reclen=%d, namlen=%d",
 			    dir->i_ino, dir->i_size, error_msg, offset,
 			    (unsigned long) SWAB32(de->d_ino),
Index: oldkernel/linux/fs/ufs/file.c
diff -u linux/fs/ufs/file.c:1.2 linux/fs/ufs/file.c:1.3
--- linux/fs/ufs/file.c:1.2	Thu Jun  1 15:03:09 2000
+++ linux/fs/ufs/file.c	Fri Jul  7 15:36:47 2000
@@ -140,7 +140,7 @@
 	loff_t *ppos )
 {
 	struct inode * inode = filp->f_dentry->d_inode;
-	loff_t pos;
+	__u32 pos;
 	long block;
 	int offset;
 	int written, c;
@@ -177,14 +177,11 @@
 			return -EINVAL;
 	}
 
-	/* L-F-S spec 2.2.1.27: */
-	if (!(filp->f_flags & O_LARGEFILE)) {
-		if (pos >= 0x7ffffffeULL) /* pos@2G forbidden */
+	/* Check for overflow.. */
+	if (pos > (__u32) (pos + count)) {
+		count = ~pos; /* == 0xFFFFFFFF - pos */
+		if (!count)
 			return -EFBIG;
-
-		if (pos + count >= 0x7fffffffULL)
-			/* Write only until end of allowed region */
-			count = 0x7fffffffULL - pos;
 	}
 
 	/*
Index: oldkernel/linux/fs/ufs/inode.c
diff -u linux/fs/ufs/inode.c:1.2 linux/fs/ufs/inode.c:1.3
--- linux/fs/ufs/inode.c:1.2	Thu Jun  1 15:03:09 2000
+++ linux/fs/ufs/inode.c	Fri Jul  7 15:36:47 2000
@@ -54,7 +54,7 @@
 {
 	unsigned swab = inode->i_sb->u.ufs_sb.s_swab;
 	printk("ino %lu  mode 0%6.6o  nlink %d  uid %d  uid32 %u"
-	       "  gid %d  gid32 %u  size %Lu blocks %lu\n",
+	       "  gid %d  gid32 %u  size %lu blocks %lu\n",
 	       inode->i_ino, inode->i_mode, inode->i_nlink,
 	       inode->i_uid, inode->u.ufs_i.i_uid, inode->i_gid, 
 	       inode->u.ufs_i.i_gid, inode->i_size, inode->i_blocks);
@@ -213,14 +213,13 @@
 	if (!create)
 		return NULL;
 	limit = current->rlim[RLIMIT_FSIZE].rlim_cur;
-	if (limit != RLIM_INFINITY) {
+	if (limit < RLIM_INFINITY) {
 		limit >>= sb->s_blocksize_bits;
 		if (new_fragment >= limit) {
 			send_sig(SIGXFSZ, current, 0);
 			return NULL;
 		}
 	}
-
 	lastblock = ufs_fragstoblks (lastfrag);
 	lastblockoff = ufs_fragnum (lastfrag);
 	/*
@@ -322,8 +321,7 @@
 		brelse (result);
 		goto repeat;
 	}
-	if (!create || (current->rlim[RLIMIT_FSIZE].rlim_cur != RLIM_INFINITY &&
-			new_fragment >= (current->rlim[RLIMIT_FSIZE].rlim_cur >> sb->s_blocksize))) {
+	if (!create || new_fragment >= (current->rlim[RLIMIT_FSIZE].rlim_cur >> sb->s_blocksize)) {
 		brelse (bh);
 		*err = -EFBIG;
 		return NULL;
@@ -498,10 +496,13 @@
 	}
 	
 	/*
-	 * Linux i_size used to be 32 bits on some architectures.
-	 * These days we allow access to the entire file as is..
+	 * Linux i_size can be 32 on some architectures. We will mark 
+	 * big files as read only and let user access first 32 bits.
 	 */
-	inode->i_size = SWAB64(ufs_inode->ui_size);
+	inode->u.ufs_i.i_size = SWAB64(ufs_inode->ui_size);
+	inode->i_size = (off_t) inode->u.ufs_i.i_size;
+	if (sizeof(off_t) == 4 && (inode->u.ufs_i.i_size >> 32))
+		inode->i_size = (__u32)-1;
 
 	inode->i_atime = SWAB32(ufs_inode->ui_atime.tv_sec);
 	inode->i_ctime = SWAB32(ufs_inode->ui_ctime.tv_sec);
@@ -514,7 +515,7 @@
 	inode->u.ufs_i.i_gen = SWAB32(ufs_inode->ui_gen);
 	inode->u.ufs_i.i_shadow = SWAB32(ufs_inode->ui_u3.ui_sun.ui_shadow);
 	inode->u.ufs_i.i_oeftflag = SWAB32(ufs_inode->ui_u3.ui_sun.ui_oeftflag);
-	inode->u.ufs_i.i_lastfrag = (inode->i_size + uspi->s_fsize -1) >> uspi->s_fshift;
+	inode->u.ufs_i.i_lastfrag = howmany (inode->i_size, uspi->s_fsize);
 	
 	if (S_ISCHR(inode->i_mode) || S_ISBLK(inode->i_mode))
 		inode->i_rdev = to_kdev_t(SWAB32(ufs_inode->ui_u2.ui_addr.ui_db[0]));
Index: oldkernel/linux/fs/ufs/super.c
diff -u linux/fs/ufs/super.c:1.2 linux/fs/ufs/super.c:1.3
--- linux/fs/ufs/super.c:1.2	Thu Jun  1 15:03:09 2000
+++ linux/fs/ufs/super.c	Fri Jul  7 15:36:47 2000
@@ -328,7 +328,7 @@
 	 * on the device. 
 	 */
 	size = uspi->s_cssize;
-	blks = (size + uspi->s_fsize-1) >> uspi->s_fshift;
+	blks = howmany(size, uspi->s_fsize);
 	base = space = kmalloc(size, GFP_KERNEL);
 	if (!base)
 		goto failed; 
@@ -405,7 +405,7 @@
 	uspi = sb->u.ufs_sb.s_uspi;
 
 	size = uspi->s_cssize;
-	blks = (size + uspi->s_fsize-1) >> uspi->s_fshift;
+	blks = howmany(size, uspi->s_fsize);
 	base = space = (char*) sb->u.ufs_sb.s_csp[0];
 	for (i = 0; i < blks; i += uspi->s_fpb) {
 		size = uspi->s_bsize;
Index: oldkernel/linux/fs/ufs/truncate.c
diff -u linux/fs/ufs/truncate.c:1.2 linux/fs/ufs/truncate.c:1.3
--- linux/fs/ufs/truncate.c:1.2	Thu Jun  1 15:03:09 2000
+++ linux/fs/ufs/truncate.c	Fri Jul  7 15:36:47 2000
@@ -59,8 +59,8 @@
  *		Linus
  */
 
-#define DIRECT_BLOCK ((inode->i_size + uspi->s_bsize -1) >> uspi->s_bshift)
-#define DIRECT_FRAGMENT ((inode->i_size + uspi->s_fsize -1) >> uspi->s_fshift)
+#define DIRECT_BLOCK howmany (inode->i_size, uspi->s_bsize)
+#define DIRECT_FRAGMENT howmany (inode->i_size, uspi->s_fsize)
 
 static int ufs_trunc_direct (struct inode * inode)
 {
@@ -194,7 +194,7 @@
 }
 
 
-static int ufs_trunc_indirect (struct inode * inode, u_long offset, u32 * p)
+static int ufs_trunc_indirect (struct inode * inode, unsigned offset, u32 * p)
 {
 	struct super_block * sb;
 	struct ufs_sb_private_info * uspi;
@@ -297,7 +297,7 @@
 	struct super_block * sb;
 	struct ufs_sb_private_info * uspi;
 	struct ufs_buffer_head * dind_bh;
-	unsigned int i, tmp, dindirect_block;
+	unsigned i, tmp, dindirect_block;
 	u32 * dind;
 	int retry = 0;
 	unsigned swab;
@@ -308,8 +308,8 @@
 	swab = sb->u.ufs_sb.s_swab;
 	uspi = sb->u.ufs_sb.s_uspi;
 
-	dindirect_block = ((DIRECT_BLOCK > offset) ?
-			   ((DIRECT_BLOCK - offset) >> uspi->s_apbshift) : 0);
+	dindirect_block = (DIRECT_BLOCK > offset) 
+		? ((DIRECT_BLOCK - offset) / uspi->s_apb) : 0;
 	retry = 0;
 	
 	tmp = SWAB32(*p);
@@ -379,7 +379,7 @@
 	retry = 0;
 	
 	tindirect_block = (DIRECT_BLOCK > (UFS_NDADDR + uspi->s_apb + uspi->s_2apb))
-		? ((DIRECT_BLOCK - UFS_NDADDR - uspi->s_apb - uspi->s_2apb) >> uspi->s_2apbshift) : 0;
+		? ((DIRECT_BLOCK - UFS_NDADDR - uspi->s_apb - uspi->s_2apb) / uspi->s_2apb) : 0;
 	p = inode->u.ufs_i.i_u1.i_data + UFS_TIND_BLOCK;
 	if (!(tmp = SWAB32(*p)))
 		return 0;
@@ -467,8 +467,7 @@
 		}
 	}
 	inode->i_mtime = inode->i_ctime = CURRENT_TIME;
-	inode->u.ufs_i.i_lastfrag =
-	  (inode->i_size + uspi->s_fsize -1) >> uspi->s_fshift;
+	inode->u.ufs_i.i_lastfrag = howmany (inode->i_size, uspi->s_fsize);
 	mark_inode_dirty(inode);
 	UFSD(("EXIT\n"))
 }
Index: oldkernel/linux/fs/ufs/util.h
diff -u linux/fs/ufs/util.h:1.2 linux/fs/ufs/util.h:1.3
--- linux/fs/ufs/util.h:1.2	Thu Jun  1 15:03:09 2000
+++ linux/fs/ufs/util.h	Fri Jul  7 15:36:47 2000
@@ -14,6 +14,7 @@
  * some useful macros
  */
 #define in_range(b,first,len)	((b)>=(first)&&(b)<(first)+(len))
+#define howmany(x,y)		(((x)+(y)-1)/(y))
 #define min(x,y)		((x)<(y)?(x):(y))
 #define max(x,y)		((x)>(y)?(x):(y))
 
Index: oldkernel/linux/ibcs/iBCSemul/bsd.c
diff -u linux/ibcs/iBCSemul/bsd.c:1.1.1.1 linux/ibcs/iBCSemul/bsd.c:1.2
--- linux/ibcs/iBCSemul/bsd.c:1.1.1.1	Wed May 31 12:41:32 2000
+++ linux/ibcs/iBCSemul/bsd.c	Fri Jul  7 15:36:47 2000
@@ -36,6 +36,7 @@
 #include <ibcs/trace.h>
 #endif
 
+#include "compat.h"
 
 int
 bsd_getpagesize(void)
@@ -75,7 +76,7 @@
 int
 bsd_getdtablesize(void)
 {
-	return NR_OPEN;
+	return FDS_RLIMIT;
 }
 
 
Index: oldkernel/linux/ibcs/iBCSemul/compat.h
diff -u /dev/null linux/ibcs/iBCSemul/compat.h:1.1
--- /dev/null	Mon Jul 31 21:15:08 2000
+++ linux/ibcs/iBCSemul/compat.h	Fri Jul  7 16:18:17 2000
@@ -0,0 +1,34 @@
+/*
+ * compatibility wrapper for file table changes
+ *
+ * Copyright 2000 Manfred Spraul, based on the initial
+ *      bugfix from Christian Lademann
+ *
+ */
+
+#if LINUX_VERSION_CODE < 0x02020c    /* less than 2.2.12 */
+
+#define FDS_RLIMIT		NR_OPEN
+
+#define	FDS_TABLE_LEN		NR_OPEN
+#define OPEN_FDS_ADDR		(&current->files->open_fds)
+#define CLOSE_ON_EXEC_FDS_ADDR	(&current->files->close_on_exec)
+
+
+#else /* from 2.2.12: dynamic file tables added */
+
+#define FDS_RLIMIT		(current->rlim[RLIMIT_NOFILE].rlim_cur)
+
+#define FDS_TABLE_LEN		(current->files->max_fdset)
+#define OPEN_FDS_ADDR		(current->files->open_fds)
+#define CLOSE_ON_EXEC_FDS_ADDR	(current->files->close_on_exec)
+
+#endif
+
+#define CHECK_LOCK()		do { } while(0)
+
+/* debugging code, only usable for SMP kernels:
+
+#define CHECK_LOCK()	if(current->lock_depth < 0) do { *(int*)0=0; } while(0)
+*/
+
Index: oldkernel/linux/ibcs/iBCSemul/emulate.c
diff -u linux/ibcs/iBCSemul/emulate.c:1.1.1.1 linux/ibcs/iBCSemul/emulate.c:1.2
--- linux/ibcs/iBCSemul/emulate.c:1.1.1.1	Wed May 31 12:41:32 2000
+++ linux/ibcs/iBCSemul/emulate.c	Fri Jul  7 15:36:47 2000
@@ -24,6 +24,13 @@
  *     the Linux TCP/IP stack.
  *     -- Mike Jagdis (jaggy@purplet.demon.co.uk)
  *
+ *  May 01 1999
+ *	Bugfix for Linux 2.2.x:
+ *	You must own the kernel lock if you use fget(), fput() etc.
+ *	I added lock_kernel() and unlock_kernel() to the main entry
+ *	point.
+ *	-- Manfred Spraul (masp0008@stud.uni-sb.de)
+ *
  * $Id: emulate.c,v 1.41 1998/06/29 21:52:38 jaggy Exp $
  * $Source: /u/CVS/ibcs/iBCSemul/emulate.c,v $
  */
@@ -54,6 +61,7 @@
 #include <ibcs/ibcs.h>
 #include <ibcs/abi4.h>
 #include <ibcs/xnx.h>
+#include <linux/smp_lock.h>
 
 #ifdef EMU_SVR4
 #include <ibcs/svr4.h>
@@ -139,6 +147,7 @@
 #ifdef IBCS_TRACE
 	int	id = ++ibcs_id;
 #endif
+	lock_kernel();
 
 	/* First decide which personality map we should be looking
 	 * at by looking at the personality of this process.
@@ -155,6 +164,7 @@
 #endif
 		regs->eflags |= 1; /* Set carry flag */
 		regs->eax = iABI_errors(EINVAL);
+		unlock_kernel();
 		return;
 	}
 
@@ -180,6 +190,7 @@
 #endif
 		regs->eflags |= 1; /* Set carry flag */
 		regs->eax = iABI_errors(EINVAL);
+		unlock_kernel();
 		return;
 	}
 
@@ -256,6 +267,7 @@
 					signr+1, sig_names[signr]);
 			}
 #endif
+			unlock_kernel();
 			return;
 		case Spl:
 			rvalue = ((sysfun_p)kfunc)(regs);
@@ -344,6 +356,7 @@
 			current->signal.sig[0]);
 	}
 #endif
+	unlock_kernel();
 }
 
 
Index: oldkernel/linux/ibcs/iBCSemul/ioctl.c
diff -u linux/ibcs/iBCSemul/ioctl.c:1.1.1.1 linux/ibcs/iBCSemul/ioctl.c:1.2
--- linux/ibcs/iBCSemul/ioctl.c:1.1.1.1	Wed May 31 12:41:32 2000
+++ linux/ibcs/iBCSemul/ioctl.c	Fri Jul  7 15:36:47 2000
@@ -37,6 +37,7 @@
 #include <ibcs/trace.h>
 #endif
 
+#include "compat.h"
 
 static int bsd_ioctl_file(int fd, unsigned int func, void *arg);
 static int sco_ioctl_tape(int fd, unsigned int func, unsigned long arg);
@@ -222,11 +223,12 @@
 {
 	switch (func) {
 		case BSD__IOV('f', 1): case BSD__IO('f', 1): /* FIOCLEX */
-			FD_SET(fd, &current->files->close_on_exec);
+			FD_SET(fd, CLOSE_ON_EXEC_FDS_ADDR);
 			return 0;
 
 		case BSD__IOV('f', 2): case BSD__IO('f', 2): /* FIONCLEX */
-			FD_CLR(fd, &current->files->close_on_exec);
+
+			FD_CLR(fd, CLOSE_ON_EXEC_FDS_ADDR);
 			return 0;
 
 		case BSD__IOV('f', 3): case BSD__IO('f', 3): { /* FIORDCHK */
Index: oldkernel/linux/ibcs/iBCSemul/open.c
diff -u linux/ibcs/iBCSemul/open.c:1.1.1.1 linux/ibcs/iBCSemul/open.c:1.2
--- linux/ibcs/iBCSemul/open.c:1.1.1.1	Wed May 31 12:41:32 2000
+++ linux/ibcs/iBCSemul/open.c	Fri Jul  7 15:36:47 2000
@@ -46,6 +46,7 @@
 #include <ibcs/trace.h>
 #endif
 
+#include "compat.h"
 
 #ifdef __cplusplus
 extern "C" 
@@ -552,15 +553,15 @@
 		/* This could be SCO's get highest fd open if the fd we
 		 * are called on is -1 otherwise it could be F_CHKFL.
 		 */
-		case  8: /* F_GETHFDO */
+ 		case  8: /* F_GETHFDO */
 			if (arg1 == -1)
-				return find_first_zero_bit(&current->files->open_fds,
-							NR_OPEN);
+				return find_first_zero_bit(OPEN_FDS_ADDR,
+							FDS_TABLE_LEN);
 			/* else fall through to fail */
-#else
+#else /* EMU_SCO */
 		/* The following are defined but reserved and unknown. */
 		case  8: /* F_CHKFL */
-#endif
+#endif /* EMU_SCO */
 
 		/* These are made from the Xenix locking() system call.
 		 * According to available documentation these would
Index: oldkernel/linux/ibcs/iBCSemul/socksys.c
diff -u linux/ibcs/iBCSemul/socksys.c:1.1.1.1 linux/ibcs/iBCSemul/socksys.c:1.2
--- linux/ibcs/iBCSemul/socksys.c:1.1.1.1	Wed May 31 12:41:32 2000
+++ linux/ibcs/iBCSemul/socksys.c	Fri Jul  7 15:36:47 2000
@@ -48,6 +48,7 @@
 #include <ibcs/socksys.h>
 #include <ibcs/tli.h>
 
+#include "compat.h"
 
 int socksys_major;
 
@@ -407,9 +408,12 @@
 	 * replaced this with a socket we have changed the file ops
 	 * too surely?
 	 */
+
+	CHECK_LOCK();
+
 	if (ino && !ino->i_sock) {
 		int fd;
-		for (fd=0; fd<NR_OPEN; fd++) {
+               for (fd=0; fd<FDS_TABLE_LEN; fd++) {
 			if (fcheck(fd) == filep) {
 				int error;
 				error = ibcs_socksys_fd_init(fd, 0, NULL, NULL);
@@ -436,9 +440,10 @@
 	 * replaced this with a socket we have changed the file ops
 	 * too surely?
 	 */
+	CHECK_LOCK();
 	if (ino && !ino->i_sock) {
 		int fd;
-		for (fd=0; fd<NR_OPEN; fd++) {
+               for (fd=0; fd<FDS_TABLE_LEN; fd++) {
 			if (fcheck(fd) == filep) {
 				int error;
 				error = ibcs_socksys_fd_init(fd, 1, buf, &count);
Index: oldkernel/linux/ibcs/iBCSemul/solaris.c
diff -u linux/ibcs/iBCSemul/solaris.c:1.1.1.1 linux/ibcs/iBCSemul/solaris.c:1.2
--- linux/ibcs/iBCSemul/solaris.c:1.1.1.1	Wed May 31 12:41:32 2000
+++ linux/ibcs/iBCSemul/solaris.c	Fri Jul  7 15:36:47 2000
@@ -28,6 +28,13 @@
  *     Linux/SPARC Solaris emulation
  *     Separated from main program to avoid ifdef mania.
  *
+ *  May 01 1999
+ *	Bugfix for Linux 2.2.x:
+ *	You must own the kernel lock if you use fget(), fput() etc.
+ *	I added lock_kernel() and unlock_kernel() to the main entry
+ *	point. THIS CODE IS UNTESTED.
+ *	-- Manfred Spraul (masp0008@stud.uni-sb.de)
+ *
  * $Id: solaris.c,v 1.7 1998/06/09 21:57:27 jaggy Exp $
  * $Source: /u/CVS/ibcs/iBCSemul/solaris.c,v $
  */
@@ -60,6 +67,7 @@
 #include <ibcs/xnx.h>
 
 #include <ibcs/svr4.h>
+#include <linux/smp_lock.h>
 
 #ifdef IBCS_TRACE
 #include <ibcs/trace.h>
@@ -134,6 +142,7 @@
 #ifdef IBCS_TRACE
 	int	id = ++ibcs_id;
 #endif
+	lock_kernel();
 
         syscall = regs->u_regs [UREG_G1];
 #if 0
@@ -141,6 +150,7 @@
 #endif
 	if (syscall > ELEMENTS(Solaris_funcs)){
 		send_sig(SIGSEGV, current, 1);
+		unlock_kernel();
                 return;
 	}
 #if 0
@@ -204,6 +214,7 @@
 					signr+1, sig_names[signr]);
 			}
 #endif
+			unlock_kernel();
 			return;
 		case Spl:
 			rvalue = ((sysfun_p)kfunc)(regs);
@@ -256,6 +267,7 @@
 	       rvalue, rvalue);
 #endif
         set_result (regs, rvalue);
+	unlock_kernel();
 }
 
 
Index: oldkernel/linux/ibcs/iBCSemul/ulimit.c
diff -u linux/ibcs/iBCSemul/ulimit.c:1.1.1.1 linux/ibcs/iBCSemul/ulimit.c:1.2
--- linux/ibcs/iBCSemul/ulimit.c:1.1.1.1	Wed May 31 12:41:32 2000
+++ linux/ibcs/iBCSemul/ulimit.c	Fri Jul  7 15:36:47 2000
@@ -35,6 +35,8 @@
 #include <ibcs/ibcs.h>
 #include <ibcs/trace.h>
 
+#include "compat.h"
+
 #define U_GETFSIZE 	(1)		  /* get max file size in blocks */
 #define U_SETFSIZE 	(2)		  /* set max file size in blocks */
 #define U_GETMEMLIM	(3)		  /* get process size limit */
@@ -72,7 +74,7 @@
 			return current->rlim[RLIMIT_DATA].rlim_cur;
 
 		case U_GETMAXOPEN:
-			return NR_OPEN;
+			return FDS_RLIMIT;
 
 		default:
 #ifdef IBCS_TRACE
Index: oldkernel/linux/include/asm-alpha/pgtable.h
diff -u linux/include/asm-alpha/pgtable.h:1.1.1.1 linux/include/asm-alpha/pgtable.h:1.2
--- linux/include/asm-alpha/pgtable.h:1.1.1.1	Wed May 31 12:33:49 2000
+++ linux/include/asm-alpha/pgtable.h	Fri Jul  7 15:36:47 2000
@@ -23,7 +23,18 @@
 #define flush_cache_range(mm, start, end)	do { } while (0)
 #define flush_cache_page(vma, vmaddr)		do { } while (0)
 #define flush_page_to_ram(page)			do { } while (0)
-#define flush_icache_range(start, end)		do { } while (0)
+/*
+ * The icache is not coherent with the dcache on alpha, thus before
+ * running self modified code like kernel modules we must always run
+ * an imb().
+ */
+#ifndef __SMP__
+#define flush_icache_range(start, end)		imb()
+#else
+#define flush_icache_range(start, end)		smp_imb()
+extern void smp_imb(void);
+#endif
+#define flush_dcache_page(page)			do { } while (0)
 
 /*
  * Use a few helper functions to hide the ugly broken ASN
Index: oldkernel/linux/include/asm-arm/pgtable.h
diff -u linux/include/asm-arm/pgtable.h:1.1.1.1 linux/include/asm-arm/pgtable.h:1.2
--- linux/include/asm-arm/pgtable.h:1.1.1.1	Wed May 31 12:33:49 2000
+++ linux/include/asm-arm/pgtable.h	Fri Jul  7 15:36:47 2000
@@ -9,6 +9,8 @@
 
 extern int do_check_pgt_cache(int, int);
 
+#define flush_dcache_page(page)			do { } while (0)
+
 /* Needs to be defined here and not in linux/mm.h, as it is arch dependent */
 #define PageSkip(page)			(0)
 #define kern_addr_valid(addr)		(1)
Index: oldkernel/linux/include/asm-i386/bugs.h
diff -u linux/include/asm-i386/bugs.h:1.2 linux/include/asm-i386/bugs.h:1.3
--- linux/include/asm-i386/bugs.h:1.2	Thu Jun  1 15:05:19 2000
+++ linux/include/asm-i386/bugs.h	Fri Jul  7 15:36:47 2000
@@ -459,7 +459,5 @@
 	check_amd_k6();
 	check_pentium_f00f();
 	check_cyrix_coma();
-	boot_cpu_data.enable_fixups = 1; /* should be safe to use MMX/MMX2 */
-					 /* kernel functions now */
 	system_utsname.machine[1] = '0' + boot_cpu_data.x86;
 }
Index: oldkernel/linux/include/asm-i386/i387.h
diff -u linux/include/asm-i386/i387.h:1.2 linux/include/asm-i386/i387.h:1.3
--- linux/include/asm-i386/i387.h:1.2	Thu Jun  1 17:04:57 2000
+++ linux/include/asm-i386/i387.h	Fri Jul  7 15:36:47 2000
@@ -11,6 +11,7 @@
  * Copyright (c) 1999 Ingo Molnar <mingo@redhat.com>,
  *                   Gabriel Paubert <paubert@iram.es>
  */
+#include <linux/config.h>
 
 #ifndef __ASM_I386_I387_H
 #define __ASM_I386_I387_H
@@ -59,21 +60,21 @@
 	} \
 } while(0)
 
-#define i387_set_swd(x,v) \
+#define i387_get_swd(x,v) \
 do { \
 	if (boot_cpu_data.x86_capability & X86_FEATURE_FXSR) { \
-		(x).fxsave.fxswd = (short)(v); \
+		(v) = (unsigned long) (x).fxsave.fxswd; \
 	} else { \
-		(x).fsave.swd = ((long)(v) | 0xffff0000); \
+		(v) = (unsigned long) (x).fsave.swd; \
 	} \
 } while(0)
 
-#define i387_get_swd(v,x) \
+#define i387_set_swd(x,v) \
 do { \
 	if (boot_cpu_data.x86_capability & X86_FEATURE_FXSR) { \
-		v = (unsigned long) (x).fxsave.fxswd; \
+		(x).fxsave.fxswd = (short)(v); \
 	} else { \
-		v = (unsigned long) (x).fsave.swd; \
+		(x).fsave.swd = ((long)(v) | 0xffff0000); \
 	} \
 } while(0)
 
@@ -121,12 +122,12 @@
 #define i387_set_cwd(x,v) \
 do { (x).fsave.cwd = ((long)(v) | 0xffff0000); } while(0)
 
+#define i387_get_swd(x,v) \
+do { (v) = (unsigned long) (x).fsave.swd; } while(0)
+
 #define i387_set_swd(x,v) \
 do { (x).fsave.swd = ((long)(v) | 0xffff0000); } while(0)
 
-#define i387_get_swd(v,x) \
-do { v = (unsigned long) (x).fsave.swd; } while(0)
-
 #define i387_set_twd(x,v) \
 do { (x).fsave.twd = ((long)(v) | 0xffff0000); } while(0)
 
@@ -135,191 +136,22 @@
 /*
  * FPU lazy state save handling..
  */
-#define save_kern_fpu(tsk) do { \
-	if(tsk->tss.mmx_reg_space != NULL) \
-		__asm__("movq %%mm0, 0x00(%0)\n\t" \
-			"movq %%mm1, 0x08(%0)\n\t" \
-			"movq %%mm2, 0x10(%0)\n\t" \
-			"movq %%mm3, 0x18(%0)\n\t" \
-			:: "r" (tsk->tss.mmx_reg_space):"memory"); \
-	if(tsk->tss.kni_reg_space != NULL) \
-		__asm__("movups %%xmm0, 0x00(%0)\n\t" \
-			"movups %%xmm1, 0x10(%0)\n\t" \
-			"movups %%xmm2, 0x20(%0)\n\t" \
-			"movups %%xmm3, 0x30(%0)\n\t" \
-			:: "r" (tsk->tss.kni_reg_space):"memory"); \
+#define save_fpu(tsk) do { \
+	i387_save_hard(tsk->tss.i387); \
+	tsk->flags &= ~PF_USEDFPU; \
+	stts(); \
 } while (0)
 
 #define unlazy_fpu(tsk) do { \
-	if (tsk->tss.x86_fpustate & X86_FPUSTATE_KERN_ANY) { \
-		save_kern_fpu(tsk); \
-		if (!(tsk->flags & PF_USEDFPU)) { \
-			stts(); \
-		} \
-	} \
-	if (tsk->flags & PF_USEDFPU) { \
-		if (!(tsk->tss.x86_fpustate & X86_FPUSTATE_USER_SAVED)) { \
-			i387_save_hard(tsk->tss.i387); \
-		} \
-		tsk->flags &= ~PF_USEDFPU; \
-		stts(); \
-	} \
+	if (tsk->flags & PF_USEDFPU) \
+		save_fpu(tsk); \
 } while (0)
 
 #define clear_fpu(tsk) do { \
-	if ( (tsk->flags & PF_USEDFPU) || \
-	     (tsk->tss.x86_fpustate) ) { \
+	if (tsk->flags & PF_USEDFPU) { \
 		tsk->flags &= ~PF_USEDFPU; \
-		tsk->tss.x86_fpustate = 0; \
-		stts(); \
-	} \
-} while (0)
-
-/*
- * For when we want to use the FPU in kernel code
- * 
- * These functions allow the use of up to 4 KNI based xmm registers on the
- * Pentium III processors or up to 4 MMX registers on Pentium MMX and above
- * or compatible processors.  Pick the routines that you need based on the
- * regs you are going to use.  Keep in mind that these are intended to be
- * used only after you've verified that the processor supports these
- * operations.  Use them before you've done that and watch your machine go
- * boom.  Take a look in arch/i386/lib/best_function.c for an example of
- * how to fixup the kernel with kni/mmx using functions once the CPU
- * capabilities have been determined.
- *
- * In all of these functions:
- *
- *   recursive - int, used to determine what the state is at restore time
- *   regs - char * to an array that is 32 bytes for mmx and 64 bytes for kni
- *          which is then used to save off the contents of the current
- *          regs to be recursively safe
- *   task_switch_regs - char * to another array of the same size as the one
- *          above, but this array is optional.  If your function might get 
- *          pre-empted by another task then this pointer should be non-NULL
- *          so that at unlazy_fpu() time in the switch_to() function we
- *          can save your register state (copy_*_user functions are an example
- *          of functions that need this, since they can take a page fault and
- *          while that fault is being serviced the scheduler is free to run
- *          another task entirely).
- *   irqflags - unsigned long used to store IRQ state
- */
-
-#define SAVE_MMX_REGS(regs) \
-	__asm__ __volatile__("movq %%mm0, 0x00(%0)\n\t" \
-			     "movq %%mm1, 0x08(%0)\n\t" \
-			     "movq %%mm2, 0x10(%0)\n\t" \
-			     "movq %%mm3, 0x18(%0)\n\t" \
-			     : : "r" ((regs)) : "memory" );
-
-#define RESTORE_MMX_REGS(regs) \
-	__asm__ __volatile__("movq 0x00(%0), %%mm0\n\t" \
-			     "movq 0x08(%0), %%mm1\n\t" \
-			     "movq 0x10(%0), %%mm2\n\t" \
-			     "movq 0x18(%0), %%mm3\n\t" \
-			     : : "r" ((regs)));
-
-#define SAVE_KNI_REGS(regs) \
-	__asm__ __volatile__("movups %%xmm0, 0x00(%0)\n\t" \
-			     "movups %%xmm1, 0x10(%0)\n\t" \
-			     "movups %%xmm2, 0x20(%0)\n\t" \
-			     "movups %%xmm3, 0x30(%0)\n\t" \
-			     : : "r" ((regs)) : "memory" );
-
-#define RESTORE_KNI_REGS(regs) \
-	__asm__ __volatile__("movups 0x00(%0), %%xmm0\n\t" \
-			     "movups 0x10(%0), %%xmm1\n\t" \
-			     "movups 0x20(%0), %%xmm2\n\t" \
-			     "movups 0x30(%0), %%xmm3\n\t" \
-			     : : "r" ((regs)));
-
-#define SFENCE() \
-	__asm__ __volatile__("sfence":::"memory")
-
-
-extern spinlock_t kern_fpu_lock;
-
-/*
- * Although it seems wasteful to do a unilateral clts() in the take_fpu
- * functions, the reason I did it that way is because the alternative is
- * to test for:
- *
- * if ( ( (current->flags & PF_USEDFPU) &&
- *        (current->tss.x86_fpustate & X86_FPUSTATE_USER_SAVED) ) ||
- *      ( !(current->flags & PF_USEDFPU) &&
- *        !(current->tss.x86_fpustate & X86_FPUSTATE_KERN_ANY) ) )
- *
- */
-
-#define kernel_take_fpu_mmx(recursive, regs, task_switch_regs, irqflags) do { \
-	spin_lock_irqsave(&kern_fpu_lock, (irqflags)); \
-	clts(); \
-	(recursive) = (current->tss.x86_fpustate & X86_FPUSTATE_KERN_ANY); \
-	if ( (current->flags & PF_USEDFPU) && \
-	    !(current->tss.x86_fpustate & X86_FPUSTATE_USER_SAVED) ){ \
-		i387_save_hard(current->tss.i387); \
-		current->tss.x86_fpustate |= X86_FPUSTATE_USER_SAVED; \
-	} \
-	if ((recursive) & X86_FPUSTATE_KERN_MMX) { \
-		SAVE_MMX_REGS((regs)); \
-	} else { \
-		current->tss.mmx_reg_space = (task_switch_regs); \
-		current->tss.x86_fpustate |= X86_FPUSTATE_KERN_MMX; \
-	} \
-	spin_unlock_irqrestore(&kern_fpu_lock, (irqflags)); \
-} while (0)
-
-#define kernel_release_fpu_mmx(recursive, regs, irqflags) do { \
-	spin_lock_irqsave(&kern_fpu_lock, (irqflags)); \
-	if ((recursive) & X86_FPUSTATE_KERN_MMX) { \
-		RESTORE_MMX_REGS((regs)); \
-	} else { \
-		current->tss.x86_fpustate &= ~X86_FPUSTATE_KERN_MMX; \
-		current->tss.mmx_reg_space = NULL; \
-	} \
-	if ((recursive) == 0) { \
 		stts(); \
 	} \
-	spin_unlock_irqrestore(&kern_fpu_lock, (irqflags)); \
 } while (0)
-
-#define kernel_take_fpu_kni(recursive, regs, task_switch_regs, irqflags) do { \
-	spin_lock_irqsave(&kern_fpu_lock, (irqflags)); \
-	clts(); \
-	(recursive) = current->tss.x86_fpustate; \
-	if ( (current->flags & PF_USEDFPU) || \
-	     (current->tss.x86_fpustate & X86_FPUSTATE_KERN_KNI) ) { \
-		SAVE_KNI_REGS((regs)); \
-	} \
-	if (!(current->tss.x86_fpustate & X86_FPUSTATE_KERN_KNI)) { \
-		current->tss.kni_reg_space = (task_switch_regs); \
-		current->tss.x86_fpustate |= X86_FPUSTATE_KERN_KNI; \
-	} \
-	spin_unlock_irqrestore(&kern_fpu_lock, (irqflags)); \
-} while (0)
-		
-	
-#define kernel_release_fpu_kni(recursive, regs, irqflags) do { \
-	spin_lock_irqsave(&kern_fpu_lock, (irqflags)); \
-	if ( (current->tss.x86_fpustate & X86_FPUSTATE_USER_SAVED) && \
-	     !(((recursive) & X86_FPUSTATE_USER_SAVED) && \
-		(current->flags & PF_USEDFPU)) ) { \
-		i387_restore_hard(current->tss.i387); \
-		current->tss.x86_fpustate &= ~X86_FPUSTATE_USER_SAVED; \
-	} \
-	if ( ((recursive) & X86_FPUSTATE_KERN_KNI) || \
-	     (current->flags & PF_USEDFPU) ) { \
-		RESTORE_KNI_REGS((regs)); \
-	} \
-	if (((recursive) & X86_FPUSTATE_KERN_KNI) == 0) { \
-		current->tss.x86_fpustate &= ~X86_FPUSTATE_KERN_KNI; \
-		current->tss.kni_reg_space = NULL; \
-	} \
-	if ( ((recursive) == 0) && ((current->flags & PF_USEDFPU) == 0) ) { \
-		stts(); \
-	} \
-	spin_unlock_irqrestore(&kern_fpu_lock, (irqflags)); \
-} while (0)
-
 
 #endif /* __ASM_I386_I387_H */
Index: oldkernel/linux/include/asm-i386/io.h
diff -u linux/include/asm-i386/io.h:1.3 linux/include/asm-i386/io.h:1.4
--- linux/include/asm-i386/io.h:1.3	Thu Jun  1 16:47:27 2000
+++ linux/include/asm-i386/io.h	Fri Jul  7 15:36:47 2000
@@ -166,9 +166,9 @@
 #define writew(b,addr) (*(volatile unsigned short *) __io_virt(addr) = (b))
 #define writel(b,addr) (*(volatile unsigned int *) __io_virt(addr) = (b))
 
-#define memset_io(a,b,c)	__memset_generic(__io_virt(a),(b),(c))
-#define memcpy_fromio(a,b,c)	__memcpy((a),__io_virt(b),(c))
-#define memcpy_toio(a,b,c)	__memcpy(__io_virt(a),(b),(c))
+#define memset_io(a,b,c)	memset(__io_virt(a),(b),(c))
+#define memcpy_fromio(a,b,c)	memcpy((a),__io_virt(b),(c))
+#define memcpy_toio(a,b,c)	memcpy(__io_virt(a),(b),(c))
 
 /*
  * Again, i386 does not require mem IO specific function.
Index: oldkernel/linux/include/asm-i386/pgtable.h
diff -u linux/include/asm-i386/pgtable.h:1.1.1.1 linux/include/asm-i386/pgtable.h:1.2
--- linux/include/asm-i386/pgtable.h:1.1.1.1	Wed May 31 12:33:49 2000
+++ linux/include/asm-i386/pgtable.h	Fri Jul  7 15:36:47 2000
@@ -24,6 +24,7 @@
 #define flush_cache_page(vma, vmaddr)		do { } while (0)
 #define flush_page_to_ram(page)			do { } while (0)
 #define flush_icache_range(start, end)		do { } while (0)
+#define flush_dcache_page(page)			do { } while (0)
 
 /*
  * TLB flushing:
Index: oldkernel/linux/include/asm-i386/processor.h
diff -u linux/include/asm-i386/processor.h:1.2 linux/include/asm-i386/processor.h:1.3
--- linux/include/asm-i386/processor.h:1.2	Thu Jun  1 15:05:19 2000
+++ linux/include/asm-i386/processor.h	Fri Jul  7 15:36:47 2000
@@ -38,7 +38,6 @@
 	int	fdiv_bug;
 	int	f00f_bug;
 	int	coma_bug;
-	int	enable_fixups;
 	unsigned long loops_per_sec;
 	unsigned long *pgd_quick;
 	unsigned long *pte_quick;
@@ -106,16 +105,6 @@
 					/* handler is available */
 
 /*
- * Some defines for using with the x86_fpu_state variable in the new
- * thread struct.  We use these because the rest of the kernel doesn't
- * like us messing with current->flags at arbitrary times ;-)
- */
-#define X86_FPUSTATE_USER_SAVED	0x0001
-#define X86_FPUSTATE_KERN_ANY	0x0006
-#define X86_FPUSTATE_KERN_MMX	0x0002
-#define X86_FPUSTATE_KERN_KNI	0x0004
-
-/*
  * Save the cr4 feature set we're using (ie
  * Pentium 4MB enable and PPro Global page
  * enable), so that any CPU's that boot up
@@ -346,10 +335,6 @@
 	struct vm86_struct * vm86_info;
 	unsigned long screen_bitmap;
 	unsigned long v86flags, v86mask, v86mode, saved_esp0;
-	volatile long x86_fpustate;
-	char *mmx_reg_space;
-	char *kni_reg_space;
-
 };
 
 #define INIT_MMAP \
@@ -373,7 +358,6 @@
 	{ 0, },							\
 	{ { { 0, }, }, },  /* 387 state */			\
 	NULL, 0, 0, 0, 0, 0, /* vm86_info */			\
-	0, NULL, NULL /* fpustate, mmx, and xmm_reg_space */	\
 }
 
 #define start_thread(regs, new_eip, new_esp) do {		\
Index: oldkernel/linux/include/asm-i386/serial.h
diff -u linux/include/asm-i386/serial.h:1.1.1.1 linux/include/asm-i386/serial.h:1.2
--- linux/include/asm-i386/serial.h:1.1.1.1	Wed May 31 12:33:49 2000
+++ linux/include/asm-i386/serial.h	Fri Jul  7 15:36:47 2000
@@ -27,6 +27,9 @@
 #define ACCENT_FLAGS 0
 #define BOCA_FLAGS 0
 #define HUB6_FLAGS 0
+#define RS_TABLE_SIZE	64
+#else
+#define RS_TABLE_SIZE
 #endif
 	
 /*
Index: oldkernel/linux/include/asm-i386/shmparam.h
diff -u linux/include/asm-i386/shmparam.h:1.1.1.1 linux/include/asm-i386/shmparam.h:1.2
--- linux/include/asm-i386/shmparam.h:1.1.1.1	Wed May 31 12:33:49 2000
+++ linux/include/asm-i386/shmparam.h	Fri Jul  7 15:36:47 2000
@@ -21,7 +21,7 @@
  * Keep _SHM_ID_BITS as low as possible since SHMMNI depends on it and
  * there is a static array of size SHMMNI.
  */
-#define _SHM_ID_BITS	7
+#define _SHM_ID_BITS	9
 #define SHM_ID_MASK	((1<<_SHM_ID_BITS)-1)
 
 #define SHM_IDX_SHIFT	(_SHM_ID_BITS)
Index: oldkernel/linux/include/asm-i386/string.h
diff -u linux/include/asm-i386/string.h:1.2 linux/include/asm-i386/string.h:1.3
--- linux/include/asm-i386/string.h:1.2	Thu Jun  1 15:05:19 2000
+++ linux/include/asm-i386/string.h	Fri Jul  7 15:36:47 2000
@@ -14,10 +14,6 @@
 #include <asm/string-486.h>
 #else
 
-#ifndef _LINUX_CONFIG_H
-#include <linux/config.h>
-#endif
-
 /*
  * This string-include defines all string functions as inline
  * functions. Use gcc. It also assumes ds=es=data space, this should be
@@ -297,21 +293,10 @@
 }
 
 #define __HAVE_ARCH_MEMCPY
-#ifdef CONFIG_X86_CPU_OPTIMIZATIONS
-extern void * __kni_memcpy(void * to, const void * from, size_t n);
-extern void * best_memcpy(void * to, const void * from, size_t n);
-#define memcpy(t, f, n) \
-(__builtin_constant_p(n) ? \
- (((n) < 128) ? \
- __constant_memcpy((t),(f),(n)) : \
- best_memcpy((t),(f),(n))) : \
- best_memcpy((t),(f),(n)))
-#else
 #define memcpy(t, f, n) \
 (__builtin_constant_p(n) ? \
  __constant_memcpy((t),(f),(n)) : \
  __memcpy((t),(f),(n)))
-#endif
 
 #define __HAVE_ARCH_MEMMOVE
 extern inline void * memmove(void * dest,const void * src, size_t n)
@@ -464,32 +449,21 @@
 #undef COMMON
 }
 
-#define __constant_x_count_memset(s, c, count) \
-(__builtin_constant_p(c) ? \
- __constant_c_and_count_memset((s),(0x01010101UL*(unsigned char)(c)),(count)) :\
- __constant_count_memset((s),(c),(count)))
+#define __constant_c_x_memset(s, c, count) \
+(__builtin_constant_p(count) ? \
+ __constant_c_and_count_memset((s),(c),(count)) : \
+ __constant_c_memset((s),(c),(count)))
 
 #define __memset(s, c, count) \
-(__builtin_constant_p(c) ? \
- __constant_c_memset((s),(0x01010101UL*(unsigned char)(c)),(count)) : \
+(__builtin_constant_p(count) ? \
+ __constant_count_memset((s),(c),(count)) : \
  __memset_generic((s),(c),(count)))
 
 #define __HAVE_ARCH_MEMSET
-#ifdef CONFIG_X86_CPU_OPTIMIZATIONS
-extern void * __kni_memset(void * s, char c, size_t count);
-extern void * best_memset(void * s, char c, size_t count);
-#define memset(s, c, count) \
-(__builtin_constant_p(count) ? \
- (((count) < 128) ? \
- __constant_x_count_memset((s),(c),(count)) : \
- best_memset((s),(c),(count))) : \
- best_memset((s),(c),(count)))
-#else
 #define memset(s, c, count) \
-(__builtin_constant_p(count) ? \
- __constant_x_count_memset((s),(c),(count)) : \
+(__builtin_constant_p(c) ? \
+ __constant_c_x_memset((s),(0x01010101UL*(unsigned char)(c)),(count)) : \
  __memset((s),(c),(count)))
-#endif
 
 /*
  * find the first occurrence of byte 'c', or 1 past the area if none
Index: oldkernel/linux/include/asm-i386/uaccess.h
diff -u linux/include/asm-i386/uaccess.h:1.2 linux/include/asm-i386/uaccess.h:1.3
--- linux/include/asm-i386/uaccess.h:1.2	Thu Jun  1 15:05:19 2000
+++ linux/include/asm-i386/uaccess.h	Fri Jul  7 15:36:47 2000
@@ -571,52 +571,6 @@
 	return n;
 }
 
-#ifdef CONFIG_X86_CPU_OPTIMIZATIONS
-
-/*
- * The XMM based copy_*_user() function declarations...the best_*_user()
- * routines need this
- */
-unsigned long kni_copy_to_user(void *, const void *, unsigned long);
-unsigned long kni_copy_from_user(void *, const void *, unsigned long);
-unsigned long __kni_copy_to_user_nocheck(void *, const void *, unsigned long);
-unsigned long __kni_copy_from_user_nocheck(void *, const void *, unsigned long);
-
-unsigned long best_copy_to_user(void *, const void *, unsigned long);
-unsigned long best_copy_from_user(void *, const void *, unsigned long);
-unsigned long __best_copy_to_user(void *, const void *, unsigned long);
-unsigned long __best_copy_from_user(void *, const void *, unsigned long);
-
-#define copy_to_user(to,from,n)				\
-	(__builtin_constant_p(n) ?			\
-	(((n) < 128) ? 					\
-	 __constant_copy_to_user((to),(from),(n)) :	\
-	 best_copy_to_user((to),(from),(n))) : 		\
-	 best_copy_to_user((to),(from),(n)))
-
-#define copy_from_user(to,from,n)			\
-	(__builtin_constant_p(n) ?			\
-	(((n) < 128) ? 					\
-	 __constant_copy_from_user((to),(from),(n)) :	\
-	 best_copy_from_user((to),(from),(n))) :	\
-	 best_copy_from_user((to),(from),(n)))
-
-#define __copy_to_user(to,from,n)			\
-	(__builtin_constant_p(n) ?			\
-	(((n) < 128) ? 					\
-	 __constant_copy_to_user_nocheck((to),(from),(n)) :	\
-	 __best_copy_to_user((to),(from),(n))) :	\
-	 __best_copy_to_user((to),(from),(n)))
-
-#define __copy_from_user(to,from,n)			\
-	(__builtin_constant_p(n) ?			\
-	(((n) < 128) ? 					\
-	 __constant_copy_from_user_nocheck((to),(from),(n)) :	\
-	 __best_copy_from_user((to),(from),(n))) :	\
-	 __best_copy_from_user((to),(from),(n)))
-
-#else /* CONFIG_X86_CPU_OPTIMIZATIONS */
-
 #define copy_to_user(to,from,n)				\
 	(__builtin_constant_p(n) ?			\
 	 __constant_copy_to_user((to),(from),(n)) :	\
@@ -627,6 +581,10 @@
 	 __constant_copy_from_user((to),(from),(n)) :	\
 	 __generic_copy_from_user((to),(from),(n)))
 
+#define copy_to_user_ret(to,from,n,retval) ({ if (copy_to_user(to,from,n)) return retval; })
+
+#define copy_from_user_ret(to,from,n,retval) ({ if (copy_from_user(to,from,n)) return retval; })
+
 #define __copy_to_user(to,from,n)			\
 	(__builtin_constant_p(n) ?			\
 	 __constant_copy_to_user_nocheck((to),(from),(n)) :	\
@@ -636,11 +594,6 @@
 	(__builtin_constant_p(n) ?			\
 	 __constant_copy_from_user_nocheck((to),(from),(n)) :	\
 	 __generic_copy_from_user_nocheck((to),(from),(n)))
-#endif
-
-#define copy_to_user_ret(to,from,n,retval) ({ if (copy_to_user(to,from,n)) return retval; })
-
-#define copy_from_user_ret(to,from,n,retval) ({ if (copy_from_user(to,from,n)) return retval; })
 
 long strncpy_from_user(char *dst, const char *src, long count);
 long __strncpy_from_user(char *dst, const char *src, long count);
Index: oldkernel/linux/include/asm-m68k/pgtable.h
diff -u linux/include/asm-m68k/pgtable.h:1.1.1.1 linux/include/asm-m68k/pgtable.h:1.2
--- linux/include/asm-m68k/pgtable.h:1.1.1.1	Wed May 31 12:33:49 2000
+++ linux/include/asm-m68k/pgtable.h	Fri Jul  7 15:36:47 2000
@@ -161,6 +161,7 @@
     }
 }
 
+#define flush_dcache_page(page)			do { } while (0)
 
 /*
  * flush all user-space atc entries.
Index: oldkernel/linux/include/asm-mips/pgtable.h
diff -u linux/include/asm-mips/pgtable.h:1.1.1.1 linux/include/asm-mips/pgtable.h:1.2
--- linux/include/asm-mips/pgtable.h:1.1.1.1	Wed May 31 12:33:49 2000
+++ linux/include/asm-mips/pgtable.h	Fri Jul  7 15:36:47 2000
@@ -33,6 +33,7 @@
 extern void (*flush_cache_sigtramp)(unsigned long addr);
 extern void (*flush_page_to_ram)(unsigned long page);
 #define flush_icache_range(start, end) flush_cache_all()
+#define flush_dcache_page(page)			do { } while (0)
 
 /* TLB flushing:
  *
Index: oldkernel/linux/include/asm-ppc/pgtable.h
diff -u linux/include/asm-ppc/pgtable.h:1.1.1.1 linux/include/asm-ppc/pgtable.h:1.2
--- linux/include/asm-ppc/pgtable.h:1.1.1.1	Wed May 31 12:33:49 2000
+++ linux/include/asm-ppc/pgtable.h	Fri Jul  7 15:36:47 2000
@@ -34,6 +34,7 @@
 
 extern void flush_icache_range(unsigned long, unsigned long);
 extern void flush_page_to_ram(unsigned long);
+#define flush_dcache_page(page)			do { } while (0)
 
 extern unsigned long va_to_phys(unsigned long address);
 extern pte_t *va_to_pte(struct task_struct *tsk, unsigned long address);
Index: oldkernel/linux/include/asm-s390/pgtable.h
diff -u linux/include/asm-s390/pgtable.h:1.1.1.1 linux/include/asm-s390/pgtable.h:1.2
--- linux/include/asm-s390/pgtable.h:1.1.1.1	Wed May 31 12:33:49 2000
+++ linux/include/asm-s390/pgtable.h	Fri Jul  7 15:36:47 2000
@@ -33,6 +33,7 @@
 #define flush_cache_page(vma, vmaddr)           do { } while (0)
 #define flush_page_to_ram(page)                 do { } while (0)
 #define flush_icache_range(start, end)          do { } while (0)
+#define flush_dcache_page(page)			do { } while (0)
 
 /*
  * TLB flushing:
Index: oldkernel/linux/include/asm-sparc/pgtable.h
diff -u linux/include/asm-sparc/pgtable.h:1.1.1.1 linux/include/asm-sparc/pgtable.h:1.2
--- linux/include/asm-sparc/pgtable.h:1.1.1.1	Wed May 31 12:33:49 2000
+++ linux/include/asm-sparc/pgtable.h	Fri Jul  7 15:36:47 2000
@@ -461,6 +461,7 @@
 #define flush_cache_range(mm,start,end) BTFIXUP_CALL(flush_cache_range)(mm,start,end)
 #define flush_cache_page(vma,addr) BTFIXUP_CALL(flush_cache_page)(vma,addr)
 #define flush_icache_range(start, end)		do { } while (0)
+#define flush_dcache_page(page)			do { } while (0)
 
 BTFIXUPDEF_CALL(void, flush_tlb_all, void)
 BTFIXUPDEF_CALL(void, flush_tlb_mm, struct mm_struct *)
Index: oldkernel/linux/include/asm-sparc/vaddrs.h
diff -u linux/include/asm-sparc/vaddrs.h:1.1.1.1 linux/include/asm-sparc/vaddrs.h:1.2
--- linux/include/asm-sparc/vaddrs.h:1.1.1.1	Wed May 31 12:33:49 2000
+++ linux/include/asm-sparc/vaddrs.h	Fri Jul  7 15:36:47 2000
@@ -20,8 +20,8 @@
 #define  IOBASE_LEN     0x00300000  /* Length of the IO area */
 #define  IOBASE_END     0xfe300000
 #define  DVMA_VADDR     0xfff00000  /* Base area of the DVMA on suns */
-#define  DVMA_LEN       0x00040000  /* Size of the DVMA address space */
-#define  DVMA_END       0xfff40000
+#define  DVMA_LEN       0x000c0000  /* Size of the DVMA address space */
+#define  DVMA_END       0xfffc0000
 
 /* IOMMU Mapping area, must be on a 16MB boundary!  Note this
  * doesn't count the DVMA areas, the prom lives between the
Index: oldkernel/linux/include/asm-sparc64/floppy.h
diff -u linux/include/asm-sparc64/floppy.h:1.2 linux/include/asm-sparc64/floppy.h:1.3
--- linux/include/asm-sparc64/floppy.h:1.2	Thu Jun  1 15:44:43 2000
+++ linux/include/asm-sparc64/floppy.h	Fri Jul  7 15:36:47 2000
@@ -183,6 +183,8 @@
 	doing_pdma = 0;
 	if (pdma_base) {
 		mmu_unlockarea(pdma_base, pdma_areasize);
+		__flush_dcache_range((unsigned long)pdma_base,
+				     (unsigned long)pdma_base + pdma_areasize);
 		pdma_base = 0;
 	}
 }
Index: oldkernel/linux/include/asm-sparc64/pgtable.h
diff -u linux/include/asm-sparc64/pgtable.h:1.1.1.1 linux/include/asm-sparc64/pgtable.h:1.2
--- linux/include/asm-sparc64/pgtable.h:1.1.1.1	Wed May 31 12:33:49 2000
+++ linux/include/asm-sparc64/pgtable.h	Fri Jul  7 15:36:47 2000
@@ -174,6 +174,7 @@
 /* These operations are unnecessary on the SpitFire since D-CACHE is write-through. */
 #define flush_icache_range(start, end)		do { } while (0)
 #define flush_page_to_ram(page)			do { } while (0)
+extern void flush_dcache_page(unsigned long page);
 
 extern void __flush_dcache_range(unsigned long start, unsigned long end);
 
Index: oldkernel/linux/include/asm-sparc64/system.h
diff -u linux/include/asm-sparc64/system.h:1.1.1.1 linux/include/asm-sparc64/system.h:1.2
--- linux/include/asm-sparc64/system.h:1.1.1.1	Wed May 31 12:33:49 2000
+++ linux/include/asm-sparc64/system.h	Fri Jul  7 15:36:47 2000
@@ -106,7 +106,16 @@
 #define read_pcr(__p)  __asm__ __volatile__("rd	%%pcr, %0" : "=r" (__p))
 #define write_pcr(__p) __asm__ __volatile__("wr	%0, 0x0, %%pcr" : : "r" (__p));
 #define read_pic(__p)  __asm__ __volatile__("rd %%pic, %0" : "=r" (__p))
-#define reset_pic()    __asm__ __volatile__("wr	%g0, 0x0, %pic");
+
+/* Blackbird errata workaround.  See commentary in
+ * arch/sparc64/kernel/smp.c:smp_percpu_timer_interrupt()
+ * for more information.
+ */
+#define reset_pic()    						\
+	__asm__ __volatile__("ba,pt	%xcc, 99f\n\t"		\
+			     ".align	64\n"			\
+			  "99:wr	%g0, 0x0, %pic\n\t"	\
+			     "rd	%pic, %g0")
 
 #ifndef __ASSEMBLY__
 
Index: oldkernel/linux/include/linux/blkdev.h
diff -u linux/include/linux/blkdev.h:1.3 linux/include/linux/blkdev.h:1.4
--- linux/include/linux/blkdev.h:1.3	Thu Jun  1 17:02:44 2000
+++ linux/include/linux/blkdev.h	Fri Jul  7 15:36:47 2000
@@ -32,11 +32,38 @@
 	struct buffer_head * bh;
 	struct buffer_head * bhtail;
 	struct request * next;
+	int elevator_latency;
 };
 
 typedef void (request_fn_proc) (void);
 typedef struct request ** (queue_proc) (kdev_t dev);
 
+typedef struct elevator_s
+{
+	int read_latency;
+	int write_latency;
+	int max_bomb_segments;
+} elevator_t;
+
+#define ELEVATOR_DEFAULTS				\
+((elevator_t) {						\
+	128,			/* read_latency */	\
+	8192,			/* write_latency */	\
+	4,			/* max_bomb_segments */	\
+	})
+
+extern int blkelv_ioctl(kdev_t, unsigned long, unsigned long);
+
+typedef struct blkelv_ioctl_arg_s {
+	void * queue_ID;
+	int read_latency;
+	int write_latency;
+	int max_bomb_segments;
+} blkelv_ioctl_arg_t;
+
+#define BLKELVGET   _IO(0x12,106)
+#define BLKELVSET   _IO(0x12,107)
+
 struct blk_dev_struct {
 	request_fn_proc		*request_fn;
 	/*
@@ -47,6 +74,8 @@
 	struct request		*current_request;
 	struct request   plug;
 	struct tq_struct plug_tq;
+
+	elevator_t elevator;
 };
 
 struct sec_size {
Index: oldkernel/linux/include/linux/buffer.h
diff -u /dev/null linux/include/linux/buffer.h:1.1
--- /dev/null	Mon Jul 31 21:15:09 2000
+++ linux/include/linux/buffer.h	Fri Jul  7 16:18:17 2000
@@ -0,0 +1,23 @@
+#ifndef _LINUX_BUFFER_H
+#define _LINUX_BUFFER_H
+
+/*
+ * This file has definitions for buffer management structures shared between
+ * the main buffer cache management and the journaling code.  
+ */
+
+
+#ifdef __KERNEL__
+
+extern struct wait_queue * buffer_wait;
+
+extern int sync_buffers(kdev_t dev, int wait);
+
+extern void end_buffer_io_sync(struct buffer_head *, int);
+
+void put_unused_buffer_head(struct buffer_head * bh);
+struct buffer_head * get_unused_buffer_head(int async);
+
+#endif /* __KERNEL__ */
+
+#endif /*_LINUX_BUFFER_H */
Index: oldkernel/linux/include/linux/capability.h
diff -u linux/include/linux/capability.h:1.1.1.1 linux/include/linux/capability.h:1.2
--- linux/include/linux/capability.h:1.1.1.1	Wed May 31 12:33:49 2000
+++ linux/include/linux/capability.h	Fri Jul  7 15:36:47 2000
@@ -4,6 +4,10 @@
  * Andrew G. Morgan <morgan@transmeta.com>
  * Alexander Kjeldaas <astor@guardian.no>
  * with help from Aleph1, Roland Buresund and Andrew Main.
+ *
+ * See here for the libcap library ("POSIX draft" compliance):
+ *
+ * ftp://linux.kernel.org/pub/linux/libs/security/linux-privs/kernel-2.2/
  */ 
 
 #ifndef _LINUX_CAPABILITY_H
@@ -168,8 +172,8 @@
 
 #define CAP_IPC_OWNER        15
 
-/* Insert and remove kernel modules */
-
+/* Insert and remove kernel modules - modify kernel without limit */
+/* Modify cap_bset */
 #define CAP_SYS_MODULE       16
 
 /* Allow ioperm/iopl access */
@@ -288,12 +292,12 @@
 #define CAP_EMPTY_SET       to_cap_t(0)
 #define CAP_FULL_SET        to_cap_t(~0)
 #define CAP_INIT_EFF_SET    to_cap_t(~0 & ~CAP_TO_MASK(CAP_SETPCAP))
-#define CAP_INIT_INH_SET    to_cap_t(~0 & ~CAP_TO_MASK(CAP_SETPCAP))
+#define CAP_INIT_INH_SET    to_cap_t(0)
 
 #define CAP_TO_MASK(x) (1 << (x))
 #define cap_raise(c, flag)   (cap_t(c) |=  CAP_TO_MASK(flag))
 #define cap_lower(c, flag)   (cap_t(c) &= ~CAP_TO_MASK(flag))
-#define cap_raised(c, flag)  (cap_t(c) & CAP_TO_MASK(flag) & cap_bset)
+#define cap_raised(c, flag)  (cap_t(c) & CAP_TO_MASK(flag))
 
 static inline kernel_cap_t cap_combine(kernel_cap_t a, kernel_cap_t b)
 {
Index: oldkernel/linux/include/linux/circ_buf.h
diff -u /dev/null linux/include/linux/circ_buf.h:1.1
--- /dev/null	Mon Jul 31 21:15:09 2000
+++ linux/include/linux/circ_buf.h	Fri Jul  7 16:18:17 2000
@@ -0,0 +1,32 @@
+#ifndef _LINUX_CIRC_BUF_H
+#define _LINUX_CIRC_BUF_H 1
+
+struct circ_buf {
+	char *buf;
+	int head;
+	int tail;
+};
+
+/* Return count in buffer.  */
+#define CIRC_CNT(head,tail,size) (((head) - (tail)) & ((size)-1))
+
+/* Return space available, 0..size-1.  We always leave one free char
+   as a completely full buffer has head == tail, which is the same as
+   empty.  */
+#define CIRC_SPACE(head,tail,size) CIRC_CNT((tail),((head)+1),(size))
+
+/* Return count up to the end of the buffer.  Carefully avoid
+   accessing head and tail more than once, so they can change
+   underneath us without returning inconsistent results.  */
+#define CIRC_CNT_TO_END(head,tail,size) \
+	({int end = (size) - (tail); \
+	  int n = ((head) + end) & ((size)-1); \
+	  n < end ? n : end;})
+
+/* Return space available up to the end of the buffer.  */
+#define CIRC_SPACE_TO_END(head,tail,size) \
+	({int end = (size) - 1 - (head); \
+	  int n = (end + (tail)) & ((size)-1); \
+	  n <= end ? n : end+1;})
+
+#endif /* _LINUX_CIRC_BUF_H  */
Index: oldkernel/linux/include/linux/dcache.h
diff -u linux/include/linux/dcache.h:1.1.1.1 linux/include/linux/dcache.h:1.2
--- linux/include/linux/dcache.h:1.1.1.1	Wed May 31 12:33:49 2000
+++ linux/include/linux/dcache.h	Fri Jul  7 15:36:47 2000
@@ -100,6 +100,12 @@
 					 * renamed" and has to be
 					 * deleted on the last dput()
 					 */
+#define	DCACHE_NFSD_DISCONNECTED 0x0004	/* This dentry is not currently connected to the
+					 * dcache tree. Its parent will either be itself,
+					 * or will have this flag as well.
+					 * If this dentry points to a directory, then
+					 * s_nfsd_free_path semaphore will be down
+					 */
 
 /*
  * d_drop() unhashes the entry from the parent
@@ -151,7 +157,7 @@
 /* test whether root is busy without destroying dcache */
 extern int is_root_busy(struct dentry *);
 
-/* test whether we have any submounts in a subdir tree */
+/* test whether we have any submounts */
 extern int have_submounts(struct dentry *);
 
 /*
Index: oldkernel/linux/include/linux/errno.h
diff -u linux/include/linux/errno.h:1.1.1.1 linux/include/linux/errno.h:1.2
--- linux/include/linux/errno.h:1.1.1.1	Wed May 31 12:33:48 2000
+++ linux/include/linux/errno.h	Fri Jul  7 15:36:47 2000
@@ -11,6 +11,16 @@
 #define ERESTARTNOHAND	514	/* restart if no handler.. */
 #define ENOIOCTLCMD	515	/* No ioctl command */
 
+/* Defined for the NFSv3 protocol */
+#define EBADHANDLE	521	/* Illegal NFS file handle */
+#define ENOTSYNC	522	/* Update synchronization mismatch */
+#define EBADCOOKIE	523	/* Cookie is stale */
+#define ENOTSUPP	524	/* Operation is not supported */
+#define ETOOSMALL	525	/* Buffer or request is too small */
+#define ESERVERFAULT	526	/* An untranslatable error occurred */
+#define EBADTYPE	527	/* Type not supported by server */
+#define EJUKEBOX	528	/* Request initiated, but will not complete before timeout */
+
 #endif
 
 #endif
Index: oldkernel/linux/include/linux/ext2_fs.h
diff -u linux/include/linux/ext2_fs.h:1.1.1.1 linux/include/linux/ext2_fs.h:1.2
--- linux/include/linux/ext2_fs.h:1.1.1.1	Wed May 31 12:33:49 2000
+++ linux/include/linux/ext2_fs.h	Fri Jul  7 15:36:47 2000
@@ -238,7 +238,7 @@
 		} masix1;
 	} osd1;				/* OS dependent 1 */
 	__u32	i_block[EXT2_N_BLOCKS];/* Pointers to blocks */
-	__u32	i_version;	/* File version (for NFS) */
+	__u32	i_generation;	/* File version (for NFS) */
 	__u32	i_file_acl;	/* File ACL */
 	__u32	i_dir_acl;	/* Directory ACL */
 	__u32	i_faddr;	/* Fragment address */
Index: oldkernel/linux/include/linux/ext2_fs_i.h
diff -u linux/include/linux/ext2_fs_i.h:1.2 linux/include/linux/ext2_fs_i.h:1.3
--- linux/include/linux/ext2_fs_i.h:1.2	Thu Jun  1 15:03:09 2000
+++ linux/include/linux/ext2_fs_i.h	Fri Jul  7 15:36:47 2000
@@ -29,12 +29,13 @@
 	__u32	i_file_acl;
 	__u32	i_dir_acl;
 	__u32	i_dtime;
-	__u32	i_version;
+	__u32	not_used_1;	/* FIX: not used/ 2.2 placeholder */
 	__u32	i_block_group;
 	__u32	i_next_alloc_block;
 	__u32	i_next_alloc_goal;
 	__u32	i_prealloc_block;
 	__u32	i_prealloc_count;
+	__u32	i_high_size;
 	int	i_new_inode:1;	/* Is a freshly allocated inode */
 };
 
Index: oldkernel/linux/include/linux/ext3_fs.h
diff -u /dev/null linux/include/linux/ext3_fs.h:1.1
--- /dev/null	Mon Jul 31 21:15:09 2000
+++ linux/include/linux/ext3_fs.h	Fri Jul  7 16:18:17 2000
@@ -0,0 +1,659 @@
+/*
+ *  linux/include/linux/ext3_fs.h
+ *
+ * Copyright (C) 1992, 1993, 1994, 1995
+ * Remy Card (card@masi.ibp.fr)
+ * Laboratoire MASI - Institut Blaise Pascal
+ * Universite Pierre et Marie Curie (Paris VI)
+ *
+ *  from
+ *
+ *  linux/include/linux/minix_fs.h
+ *
+ *  Copyright (C) 1991, 1992  Linus Torvalds
+ */
+
+#ifndef _LINUX_EXT3_FS_H
+#define _LINUX_EXT3_FS_H
+
+#include <linux/types.h>
+
+/*
+ * The second extended filesystem constants/structures
+ */
+
+/*
+ * Define EXT3FS_DEBUG to produce debug messages
+ */
+#undef EXT3FS_DEBUG
+
+/*
+ * Define EXT3_PREALLOCATE to preallocate data blocks for expanding files
+ */
+#undef  EXT3_PREALLOCATE /* @@@ Fix this! */
+#define EXT3_DEFAULT_PREALLOC_BLOCKS	8
+
+/*
+ * The second extended file system version
+ */
+#define EXT3FS_DATE		"2000/3/22"
+#define EXT3FS_VERSION		"0.0.2d"
+
+/*
+ * Debug code
+ */
+#ifdef EXT3FS_DEBUG
+#	define ext3_debug(f, a...)	{ \
+					printk ("EXT3-fs DEBUG (%s, %d): %s:", \
+						__FILE__, __LINE__, __FUNCTION__); \
+				  	printk (f, ## a); \
+					}
+#else
+#	define ext3_debug(f, a...)	/**/
+#endif
+
+/*
+ * Special inodes numbers
+ */
+#define	EXT3_BAD_INO		 1	/* Bad blocks inode */
+#define EXT3_ROOT_INO		 2	/* Root inode */
+#define EXT3_ACL_IDX_INO	 3	/* ACL inode */
+#define EXT3_ACL_DATA_INO	 4	/* ACL inode */
+#define EXT3_BOOT_LOADER_INO	 5	/* Boot loader inode */
+#define EXT3_UNDEL_DIR_INO	 6	/* Undelete directory inode */
+
+/* First non-reserved inode for old ext3 filesystems */
+#define EXT3_GOOD_OLD_FIRST_INO	11
+
+/*
+ * The second extended file system magic number
+ */
+#define EXT3_SUPER_MAGIC	0xEF53
+
+/*
+ * Maximal count of links to a file
+ */
+#define EXT3_LINK_MAX		32000
+
+/*
+ * Macro-instructions used to manage several block sizes
+ */
+#define EXT3_MIN_BLOCK_SIZE		1024
+#define	EXT3_MAX_BLOCK_SIZE		4096
+#define EXT3_MIN_BLOCK_LOG_SIZE		  10
+#ifdef __KERNEL__
+# define EXT3_BLOCK_SIZE(s)		((s)->s_blocksize)
+#else
+# define EXT3_BLOCK_SIZE(s)		(EXT3_MIN_BLOCK_SIZE << (s)->s_log_block_size)
+#endif
+#define EXT3_ACLE_PER_BLOCK(s)		(EXT3_BLOCK_SIZE(s) / sizeof (struct ext3_acl_entry))
+#define	EXT3_ADDR_PER_BLOCK(s)		(EXT3_BLOCK_SIZE(s) / sizeof (__u32))
+#ifdef __KERNEL__
+# define EXT3_BLOCK_SIZE_BITS(s)	((s)->s_blocksize_bits)
+#else
+# define EXT3_BLOCK_SIZE_BITS(s)	((s)->s_log_block_size + 10)
+#endif
+#ifdef __KERNEL__
+#define	EXT3_ADDR_PER_BLOCK_BITS(s)	((s)->u.ext3_sb.s_addr_per_block_bits)
+#define EXT3_INODE_SIZE(s)		((s)->u.ext3_sb.s_inode_size)
+#define EXT3_FIRST_INO(s)		((s)->u.ext3_sb.s_first_ino)
+#else
+#define EXT3_INODE_SIZE(s)	(((s)->s_rev_level == EXT3_GOOD_OLD_REV) ? \
+				 EXT3_GOOD_OLD_INODE_SIZE : \
+				 (s)->s_inode_size)
+#define EXT3_FIRST_INO(s)	(((s)->s_rev_level == EXT3_GOOD_OLD_REV) ? \
+				 EXT3_GOOD_OLD_FIRST_INO : \
+				 (s)->s_first_ino)
+#endif
+
+/*
+ * Macro-instructions used to manage fragments
+ */
+#define EXT3_MIN_FRAG_SIZE		1024
+#define	EXT3_MAX_FRAG_SIZE		4096
+#define EXT3_MIN_FRAG_LOG_SIZE		  10
+#ifdef __KERNEL__
+# define EXT3_FRAG_SIZE(s)		((s)->u.ext3_sb.s_frag_size)
+# define EXT3_FRAGS_PER_BLOCK(s)	((s)->u.ext3_sb.s_frags_per_block)
+#else
+# define EXT3_FRAG_SIZE(s)		(EXT3_MIN_FRAG_SIZE << (s)->s_log_frag_size)
+# define EXT3_FRAGS_PER_BLOCK(s)	(EXT3_BLOCK_SIZE(s) / EXT3_FRAG_SIZE(s))
+#endif
+
+/*
+ * ACL structures
+ */
+struct ext3_acl_header	/* Header of Access Control Lists */
+{
+	__u32	aclh_size;
+	__u32	aclh_file_count;
+	__u32	aclh_acle_count;
+	__u32	aclh_first_acle;
+};
+
+struct ext3_acl_entry	/* Access Control List Entry */
+{
+	__u32	acle_size;
+	__u16	acle_perms;	/* Access permissions */
+	__u16	acle_type;	/* Type of entry */
+	__u16	acle_tag;	/* User or group identity */
+	__u16	acle_pad1;
+	__u32	acle_next;	/* Pointer on next entry for the */
+					/* same inode or on next free entry */
+};
+
+/*
+ * Structure of a blocks group descriptor
+ */
+struct ext3_group_desc
+{
+	__u32	bg_block_bitmap;		/* Blocks bitmap block */
+	__u32	bg_inode_bitmap;		/* Inodes bitmap block */
+	__u32	bg_inode_table;		/* Inodes table block */
+	__u16	bg_free_blocks_count;	/* Free blocks count */
+	__u16	bg_free_inodes_count;	/* Free inodes count */
+	__u16	bg_used_dirs_count;	/* Directories count */
+	__u16	bg_pad;
+	__u32	bg_reserved[3];
+};
+
+/*
+ * Macro-instructions used to manage group descriptors
+ */
+#ifdef __KERNEL__
+# define EXT3_BLOCKS_PER_GROUP(s)	((s)->u.ext3_sb.s_blocks_per_group)
+# define EXT3_DESC_PER_BLOCK(s)		((s)->u.ext3_sb.s_desc_per_block)
+# define EXT3_INODES_PER_GROUP(s)	((s)->u.ext3_sb.s_inodes_per_group)
+# define EXT3_DESC_PER_BLOCK_BITS(s)	((s)->u.ext3_sb.s_desc_per_block_bits)
+#else
+# define EXT3_BLOCKS_PER_GROUP(s)	((s)->s_blocks_per_group)
+# define EXT3_DESC_PER_BLOCK(s)		(EXT3_BLOCK_SIZE(s) / sizeof (struct ext3_group_desc))
+# define EXT3_INODES_PER_GROUP(s)	((s)->s_inodes_per_group)
+#endif
+
+/*
+ * Constants relative to the data blocks
+ */
+#define	EXT3_NDIR_BLOCKS		12
+#define	EXT3_IND_BLOCK			EXT3_NDIR_BLOCKS
+#define	EXT3_DIND_BLOCK			(EXT3_IND_BLOCK + 1)
+#define	EXT3_TIND_BLOCK			(EXT3_DIND_BLOCK + 1)
+#define	EXT3_N_BLOCKS			(EXT3_TIND_BLOCK + 1)
+
+/*
+ * Inode flags
+ */
+#define	EXT3_SECRM_FL			0x00000001 /* Secure deletion */
+#define	EXT3_UNRM_FL			0x00000002 /* Undelete */
+#define	EXT3_COMPR_FL			0x00000004 /* Compress file */
+#define EXT3_SYNC_FL			0x00000008 /* Synchronous updates */
+#define EXT3_IMMUTABLE_FL		0x00000010 /* Immutable file */
+#define EXT3_APPEND_FL			0x00000020 /* writes to file may only append */
+#define EXT3_NODUMP_FL			0x00000040 /* do not dump file */
+#define EXT3_NOATIME_FL			0x00000080 /* do not update atime */
+/* Reserved for compression usage... */
+#define EXT3_DIRTY_FL			0x00000100
+#define EXT3_COMPRBLK_FL		0x00000200 /* One or more compressed clusters */
+#define EXT3_NOCOMP_FL			0x00000400 /* Don't compress */
+#define EXT3_ECOMPR_FL			0x00000800 /* Compression error */
+/* End compression flags --- maybe not all used */	
+#define EXT3_BTREE_FL			0x00001000 /* btree format dir */
+#define EXT3_RESERVED_FL		0x80000000 /* reserved for ext3 lib */
+
+#define EXT3_FL_USER_VISIBLE		0x00001FFF /* User visible flags */
+#define EXT3_FL_USER_MODIFIABLE		0x000000FF /* User modifiable flags */
+
+/*
+ * ioctl commands
+ */
+#define	EXT3_IOC_GETFLAGS		_IOR('f', 1, long)
+#define	EXT3_IOC_SETFLAGS		_IOW('f', 2, long)
+#define	EXT3_IOC_GETVERSION		_IOR('v', 1, long)
+#define	EXT3_IOC_SETVERSION		_IOW('v', 2, long)
+
+/*
+ * Structure of an inode on the disk
+ */
+struct ext3_inode {
+	__u16	i_mode;		/* File mode */
+	__u16	i_uid;		/* Owner Uid */
+	__u32	i_size;		/* Size in bytes */
+	__u32	i_atime;	/* Access time */
+	__u32	i_ctime;	/* Creation time */
+	__u32	i_mtime;	/* Modification time */
+	__u32	i_dtime;	/* Deletion Time */
+	__u16	i_gid;		/* Group Id */
+	__u16	i_links_count;	/* Links count */
+	__u32	i_blocks;	/* Blocks count */
+	__u32	i_flags;	/* File flags */
+	union {
+		struct {
+			__u32  l_i_reserved1;
+		} linux1;
+		struct {
+			__u32  h_i_translator;
+		} hurd1;
+		struct {
+			__u32  m_i_reserved1;
+		} masix1;
+	} osd1;				/* OS dependent 1 */
+	__u32	i_block[EXT3_N_BLOCKS];/* Pointers to blocks */
+	__u32	i_version;	/* File version (for NFS) */
+	__u32	i_file_acl;	/* File ACL */
+	__u32	i_dir_acl;	/* Directory ACL */
+	__u32	i_faddr;	/* Fragment address */
+	union {
+		struct {
+			__u8	l_i_frag;	/* Fragment number */
+			__u8	l_i_fsize;	/* Fragment size */
+			__u16	i_pad1;
+			__u32	l_i_reserved2[2];
+		} linux2;
+		struct {
+			__u8	h_i_frag;	/* Fragment number */
+			__u8	h_i_fsize;	/* Fragment size */
+			__u16	h_i_mode_high;
+			__u16	h_i_uid_high;
+			__u16	h_i_gid_high;
+			__u32	h_i_author;
+		} hurd2;
+		struct {
+			__u8	m_i_frag;	/* Fragment number */
+			__u8	m_i_fsize;	/* Fragment size */
+			__u16	m_pad1;
+			__u32	m_i_reserved2[2];
+		} masix2;
+	} osd2;				/* OS dependent 2 */
+};
+
+#define i_size_high	i_dir_acl
+
+#if defined(__KERNEL__) || defined(__linux__)
+#define i_reserved1	osd1.linux1.l_i_reserved1
+#define i_frag		osd2.linux2.l_i_frag
+#define i_fsize		osd2.linux2.l_i_fsize
+#define i_reserved2	osd2.linux2.l_i_reserved2
+#endif
+
+#ifdef	__hurd__
+#define i_translator	osd1.hurd1.h_i_translator
+#define i_frag		osd2.hurd2.h_i_frag;
+#define i_fsize		osd2.hurd2.h_i_fsize;
+#define i_uid_high	osd2.hurd2.h_i_uid_high
+#define i_gid_high	osd2.hurd2.h_i_gid_high
+#define i_author	osd2.hurd2.h_i_author
+#endif
+
+#ifdef	__masix__
+#define i_reserved1	osd1.masix1.m_i_reserved1
+#define i_frag		osd2.masix2.m_i_frag
+#define i_fsize		osd2.masix2.m_i_fsize
+#define i_reserved2	osd2.masix2.m_i_reserved2
+#endif
+
+/*
+ * File system states
+ */
+#define	EXT3_VALID_FS			0x0001	/* Unmounted cleanly */
+#define	EXT3_ERROR_FS			0x0002	/* Errors detected */
+
+/*
+ * Mount flags
+ */
+#define EXT3_MOUNT_CHECK_NORMAL		0x0001	/* Do some more checks */
+#define EXT3_MOUNT_CHECK_STRICT		0x0002	/* Do again more checks */
+#define EXT3_MOUNT_CHECK		(EXT3_MOUNT_CHECK_NORMAL | \
+					 EXT3_MOUNT_CHECK_STRICT)
+#define EXT3_MOUNT_GRPID		0x0004	/* Create files with directory's group */
+#define EXT3_MOUNT_DEBUG		0x0008	/* Some debugging messages */
+#define EXT3_MOUNT_ERRORS_CONT		0x0010	/* Continue on errors */
+#define EXT3_MOUNT_ERRORS_RO		0x0020	/* Remount fs ro on errors */
+#define EXT3_MOUNT_ERRORS_PANIC		0x0040	/* Panic on errors */
+#define EXT3_MOUNT_MINIX_DF		0x0080	/* Mimics the Minix statfs */
+#define EXT3_MOUNT_NOLOAD		0x0100	/* Mimics the Minix statfs */
+
+/* Compatibility, for having both ext2_fs.h and ext3_fs.h included at once */
+#ifndef _LINUX_EXT2_FS_H
+#define clear_opt(o, opt)		o &= ~EXT3_MOUNT_##opt
+#define set_opt(o, opt)			o |= EXT3_MOUNT_##opt
+#define test_opt(sb, opt)		((sb)->u.ext3_sb.s_mount_opt & \
+					 EXT3_MOUNT_##opt)
+#else
+#define EXT2_MOUNT_NOLOAD		EXT3_MOUNT_NOLOAD
+#endif
+
+#define ext3_set_bit			ext2_set_bit
+#define ext3_clear_bit			ext2_clear_bit
+#define ext3_test_bit			ext2_test_bit
+#define ext3_find_first_zero_bit	ext2_find_first_zero_bit
+#define ext3_find_next_zero_bit		ext2_find_next_zero_bit
+
+/*
+ * Maximal mount counts between two filesystem checks
+ */
+#define EXT3_DFL_MAX_MNT_COUNT		20	/* Allow 20 mounts */
+#define EXT3_DFL_CHECKINTERVAL		0	/* Don't use interval check */
+
+/*
+ * Behaviour when detecting errors
+ */
+#define EXT3_ERRORS_CONTINUE		1	/* Continue execution */
+#define EXT3_ERRORS_RO			2	/* Remount fs read-only */
+#define EXT3_ERRORS_PANIC		3	/* Panic */
+#define EXT3_ERRORS_DEFAULT		EXT3_ERRORS_CONTINUE
+
+/*
+ * Structure of the super block
+ */
+struct ext3_super_block {
+	__u32	s_inodes_count;		/* Inodes count */
+	__u32	s_blocks_count;		/* Blocks count */
+	__u32	s_r_blocks_count;	/* Reserved blocks count */
+	__u32	s_free_blocks_count;	/* Free blocks count */
+	__u32	s_free_inodes_count;	/* Free inodes count */
+	__u32	s_first_data_block;	/* First Data Block */
+	__u32	s_log_block_size;	/* Block size */
+	__s32	s_log_frag_size;	/* Fragment size */
+	__u32	s_blocks_per_group;	/* # Blocks per group */
+	__u32	s_frags_per_group;	/* # Fragments per group */
+	__u32	s_inodes_per_group;	/* # Inodes per group */
+	__u32	s_mtime;		/* Mount time */
+	__u32	s_wtime;		/* Write time */
+	__u16	s_mnt_count;		/* Mount count */
+	__s16	s_max_mnt_count;	/* Maximal mount count */
+	__u16	s_magic;		/* Magic signature */
+	__u16	s_state;		/* File system state */
+	__u16	s_errors;		/* Behaviour when detecting errors */
+	__u16	s_minor_rev_level; 	/* minor revision level */
+	__u32	s_lastcheck;		/* time of last check */
+	__u32	s_checkinterval;	/* max. time between checks */
+	__u32	s_creator_os;		/* OS */
+	__u32	s_rev_level;		/* Revision level */
+	__u16	s_def_resuid;		/* Default uid for reserved blocks */
+	__u16	s_def_resgid;		/* Default gid for reserved blocks */
+	/*
+	 * These fields are for EXT3_DYNAMIC_REV superblocks only.
+	 *
+	 * Note: the difference between the compatible feature set and
+	 * the incompatible feature set is that if there is a bit set
+	 * in the incompatible feature set that the kernel doesn't
+	 * know about, it should refuse to mount the filesystem.
+	 * 
+	 * e2fsck's requirements are more strict; if it doesn't know
+	 * about a feature in either the compatible or incompatible
+	 * feature set, it must abort and not try to meddle with
+	 * things it doesn't understand...
+	 */
+	__u32	s_first_ino; 		/* First non-reserved inode */
+	__u16   s_inode_size; 		/* size of inode structure */
+	__u16	s_block_group_nr; 	/* block group # of this superblock */
+	__u32	s_feature_compat; 	/* compatible feature set */
+	__u32	s_feature_incompat; 	/* incompatible feature set */
+	__u32	s_feature_ro_compat; 	/* readonly-compatible feature set */
+	__u8	s_uuid[16];		/* 128-bit uuid for volume */
+	char	s_volume_name[16]; 	/* volume name */
+	char	s_last_mounted[64]; 	/* directory where last mounted */
+	__u32	s_algorithm_usage_bitmap; /* For compression */
+	/*
+	 * Performance hints.  Directory preallocation should only
+	 * happen if the EXT3_COMPAT_PREALLOC flag is on.
+	 */
+	__u8	s_prealloc_blocks;	/* Nr of blocks to try to preallocate*/
+	__u8	s_prealloc_dir_blocks;	/* Nr to preallocate for dirs */
+	__u16	s_padding1;
+	/* 
+	 * Journaling support.
+	 */
+	__u8	s_journal_uuid[16];	/* uuid of journal superblock */
+	__u32	s_journal_inum;		/* inode number of journal file */
+	
+	__u32	s_reserved[199];	/* Padding to the end of the block */
+};
+
+#ifdef __KERNEL__
+#define EXT3_SB(sb)	(&((sb)->u.ext3_sb))
+#else
+/* Assume that user mode programs are passing in an ext3fs superblock, not
+ * a kernel struct super_block.  This will allow us to call the feature-test
+ * macros from user land. */
+#define EXT3_SB(sb)	(sb)
+#endif
+
+/*
+ * Codes for operating systems
+ */
+#define EXT3_OS_LINUX		0
+#define EXT3_OS_HURD		1
+#define EXT3_OS_MASIX		2
+#define EXT3_OS_FREEBSD		3
+#define EXT3_OS_LITES		4
+
+/*
+ * Revision levels
+ */
+#define EXT3_GOOD_OLD_REV	0	/* The good old (original) format */
+#define EXT3_DYNAMIC_REV	1 	/* V2 format w/ dynamic inode sizes */
+
+#define EXT3_CURRENT_REV	EXT3_GOOD_OLD_REV
+#define EXT3_MAX_SUPP_REV	EXT3_DYNAMIC_REV
+
+#define EXT3_GOOD_OLD_INODE_SIZE 128
+
+/*
+ * Feature set definitions
+ */
+
+#define EXT3_HAS_COMPAT_FEATURE(sb,mask)			\
+	( EXT3_SB(sb)->s_feature_compat & (mask) )
+#define EXT3_HAS_RO_COMPAT_FEATURE(sb,mask)			\
+	( EXT3_SB(sb)->s_feature_ro_compat & (mask) )
+#define EXT3_HAS_INCOMPAT_FEATURE(sb,mask)			\
+	( EXT3_SB(sb)->s_feature_incompat & (mask) )
+
+#define EXT3_FEATURE_COMPAT_DIR_PREALLOC	0x0001
+/*      EXT3_FEATURE_COMPAT_<reserved for AFS>	0x0002 */
+#define EXT3_FEATURE_COMPAT_HAS_JOURNAL		0x0004
+
+#define EXT3_FEATURE_RO_COMPAT_SPARSE_SUPER	0x0001
+#define EXT3_FEATURE_RO_COMPAT_LARGE_FILE	0x0002
+#define EXT3_FEATURE_RO_COMPAT_BTREE_DIR	0x0004
+
+#define EXT3_FEATURE_INCOMPAT_COMPRESSION	0x0001
+#define EXT3_FEATURE_INCOMPAT_FILETYPE		0x0002
+#define EXT3_FEATURE_INCOMPAT_RECOVER		0x0004
+
+#define EXT3_FEATURE_COMPAT_SUPP	0
+#define EXT3_FEATURE_INCOMPAT_SUPP	(EXT3_FEATURE_INCOMPAT_FILETYPE| \
+					 EXT3_FEATURE_INCOMPAT_RECOVER)
+#define EXT3_FEATURE_RO_COMPAT_SUPP	(EXT3_FEATURE_RO_COMPAT_SPARSE_SUPER| \
+					 EXT3_FEATURE_RO_COMPAT_LARGE_FILE| \
+					 EXT3_FEATURE_RO_COMPAT_BTREE_DIR)
+
+/*
+ * Default values for user and/or group using reserved blocks
+ */
+#define	EXT3_DEF_RESUID		0
+#define	EXT3_DEF_RESGID		0
+
+/*
+ * Structure of a directory entry
+ */
+#define EXT3_NAME_LEN 255
+
+struct ext3_dir_entry {
+	__u32	inode;			/* Inode number */
+	__u16	rec_len;		/* Directory entry length */
+	__u16	name_len;		/* Name length */
+	char	name[EXT3_NAME_LEN];	/* File name */
+};
+
+/*
+ * The new version of the directory entry.  Since EXT3 structures are
+ * stored in intel byte order, and the name_len field could never be
+ * bigger than 255 chars, it's safe to reclaim the extra byte for the
+ * file_type field.
+ */
+struct ext3_dir_entry_2 {
+	__u32	inode;			/* Inode number */
+	__u16	rec_len;		/* Directory entry length */
+	__u8	name_len;		/* Name length */
+	__u8	file_type;
+	char	name[EXT3_NAME_LEN];	/* File name */
+};
+
+/*
+ * Ext3 directory file types.  Only the low 3 bits are used.  The
+ * other bits are reserved for now.
+ */
+#define EXT3_FT_UNKNOWN		0
+#define EXT3_FT_REG_FILE	1
+#define EXT3_FT_DIR		2
+#define EXT3_FT_CHRDEV		3
+#define EXT3_FT_BLKDEV 		4
+#define EXT3_FT_FIFO		5
+#define EXT3_FT_SOCK		6
+#define EXT3_FT_SYMLINK		7
+
+#define EXT3_FT_MAX		8
+
+/*
+ * EXT3_DIR_PAD defines the directory entries boundaries
+ *
+ * NOTE: It must be a multiple of 4
+ */
+#define EXT3_DIR_PAD		 	4
+#define EXT3_DIR_ROUND 			(EXT3_DIR_PAD - 1)
+#define EXT3_DIR_REC_LEN(name_len)	(((name_len) + 8 + EXT3_DIR_ROUND) & \
+					 ~EXT3_DIR_ROUND)
+
+#ifdef __KERNEL__
+
+/* Filesize hard limits for 64-bit file offsets */
+extern long long ext3_max_sizes[];
+
+/*
+ * Describe an inode's exact location on disk and in memory
+ */
+struct ext3_iloc
+{
+	struct buffer_head *bh;
+	struct ext3_inode *raw_inode;
+	unsigned long block_group;
+};
+
+/*
+ * Function prototypes
+ */
+
+/*
+ * Ok, these declarations are also in <linux/kernel.h> but none of the
+ * ext3 source programs needs to include it so they are duplicated here.
+ */
+# define NORET_TYPE    /**/
+# define ATTRIB_NORET  __attribute__((noreturn))
+# define NORET_AND     noreturn,
+
+/* acl.c */
+extern int ext3_permission (struct inode *, int);
+
+/* balloc.c */
+extern int ext3_group_sparse(int group);
+extern int ext3_new_block (handle_t *, const struct inode *, unsigned long,
+			   __u32 *, __u32 *, int *);
+extern void ext3_free_blocks (handle_t *, const struct inode *, unsigned long,
+			      unsigned long);
+extern unsigned long ext3_count_free_blocks (struct super_block *);
+extern void ext3_check_blocks_bitmap (struct super_block *);
+extern struct ext3_group_desc * ext3_get_group_desc(struct super_block * sb,
+						    unsigned int block_group,
+						    struct buffer_head ** bh);
+
+/* bitmap.c */
+extern unsigned long ext3_count_free (struct buffer_head *, unsigned);
+
+/* dir.c */
+extern int ext3_check_dir_entry (const char *, struct inode *,
+				 struct ext3_dir_entry_2 *, struct buffer_head *,
+				 unsigned long);
+
+/* file.c */
+extern int ext3_read (struct inode *, struct file *, char *, int);
+extern int ext3_write (struct inode *, struct file *, char *, int);
+
+/* fsync.c */
+extern int ext3_sync_file (struct file *, struct dentry *);
+
+/* ialloc.c */
+extern struct inode * ext3_new_inode (handle_t *, const struct inode *, int, int *);
+extern void ext3_free_inode (handle_t *, struct inode *);
+extern unsigned long ext3_count_free_inodes (struct super_block *);
+extern void ext3_check_inodes_bitmap (struct super_block *);
+
+/* inode.c */
+extern int ext3_bmap (struct inode *, int);
+
+extern struct buffer_head * ext3_getblk (handle_t *, struct inode *, long, int, int *);
+extern struct buffer_head * ext3_bread (handle_t *, struct inode *, int, int, int *);
+
+extern int  ext3_getcluster (struct inode * inode, long block);
+extern int  ext3_get_inode_loc (struct inode *, struct ext3_iloc *);
+extern int  ext3_do_update_inode (handle_t *, struct inode *, struct ext3_iloc *, int);
+extern void ext3_read_inode (struct inode *);
+extern void ext3_write_inode (struct inode *);
+extern void ext3_put_inode (struct inode *);
+extern void ext3_delete_inode (struct inode *);
+extern int  ext3_sync_inode (handle_t *, struct inode *);
+extern int  ext3_notify_change(struct dentry *, struct iattr *);
+extern void ext3_discard_prealloc (struct inode *);
+
+/* ioctl.c */
+extern int ext3_ioctl (struct inode *, struct file *, unsigned int,
+		       unsigned long);
+
+/* namei.c */
+extern void ext3_release (struct inode *, struct file *);
+extern struct dentry *ext3_lookup (struct inode *, struct dentry *);
+extern int ext3_create (struct inode *,struct dentry *,int);
+extern int ext3_mkdir (struct inode *,struct dentry *,int);
+extern int ext3_rmdir (struct inode *,struct dentry *);
+extern int ext3_unlink (struct inode *,struct dentry *);
+extern int ext3_symlink (struct inode *,struct dentry *,const char *);
+extern int ext3_link (struct dentry *, struct inode *, struct dentry *);
+extern int ext3_mknod (struct inode *, struct dentry *, int, int);
+extern int ext3_rename (struct inode *, struct dentry *,
+			struct inode *, struct dentry *);
+
+/* super.c */
+extern void ext3_error (struct super_block *, const char *, const char *, ...)
+	__attribute__ ((format (printf, 3, 4)));
+extern NORET_TYPE void ext3_panic (struct super_block *, const char *,
+				   const char *, ...)
+	__attribute__ ((NORET_AND format (printf, 3, 4)));
+extern void ext3_warning (struct super_block *, const char *, const char *, ...)
+	__attribute__ ((format (printf, 3, 4)));
+extern void ext3_put_super (struct super_block *);
+extern void ext3_write_super (struct super_block *);
+extern int ext3_remount (struct super_block *, int *, char *);
+extern struct super_block * ext3_read_super (struct super_block *,void *,int);
+extern int init_ext3_fs(void);
+extern int ext3_statfs (struct super_block *, struct statfs *, int);
+
+/* truncate.c */
+extern void ext3_truncate (struct inode *);
+
+/*
+ * Inodes and files operations
+ */
+
+/* dir.c */
+extern struct inode_operations ext3_dir_inode_operations;
+
+/* file.c */
+extern struct inode_operations ext3_file_inode_operations;
+
+/* symlink.c */
+extern struct inode_operations ext3_symlink_inode_operations;
+
+#endif	/* __KERNEL__ */
+
+#endif	/* _LINUX_EXT3_FS_H */
Index: oldkernel/linux/include/linux/ext3_fs_i.h
diff -u /dev/null linux/include/linux/ext3_fs_i.h:1.1
--- /dev/null	Mon Jul 31 21:15:09 2000
+++ linux/include/linux/ext3_fs_i.h	Fri Jul  7 16:18:17 2000
@@ -0,0 +1,42 @@
+/*
+ *  linux/include/linux/ext3_fs_i.h
+ *
+ * Copyright (C) 1992, 1993, 1994, 1995
+ * Remy Card (card@masi.ibp.fr)
+ * Laboratoire MASI - Institut Blaise Pascal
+ * Universite Pierre et Marie Curie (Paris VI)
+ *
+ *  from
+ *
+ *  linux/include/linux/minix_fs_i.h
+ *
+ *  Copyright (C) 1991, 1992  Linus Torvalds
+ */
+
+#ifndef _LINUX_EXT3_FS_I
+#define _LINUX_EXT3_FS_I
+
+/*
+ * second extended file system inode data in memory
+ */
+struct ext3_inode_info {
+	__u32	i_data[15];
+	__u32	i_flags;
+	__u32	i_faddr;
+	__u8	i_frag_no;
+	__u8	i_frag_size;
+	__u16	i_osync;
+	__u32	i_file_acl;
+	__u32	i_dir_acl;
+	__u32	i_dtime;
+	__u32	i_version;
+	__u32	i_block_group;
+	__u32	i_next_alloc_block;
+	__u32	i_next_alloc_goal;
+	__u32	i_prealloc_block;
+	__u32	i_prealloc_count;
+	__u32	i_high_size;
+	int	i_new_inode:1;	/* Is a freshly allocated inode */
+};
+
+#endif	/* _LINUX_EXT3_FS_I */
Index: oldkernel/linux/include/linux/ext3_fs_sb.h
diff -u /dev/null linux/include/linux/ext3_fs_sb.h:1.1
--- /dev/null	Mon Jul 31 21:15:09 2000
+++ linux/include/linux/ext3_fs_sb.h	Fri Jul  7 16:18:17 2000
@@ -0,0 +1,70 @@
+/*
+ *  linux/include/linux/ext3_fs_sb.h
+ *
+ * Copyright (C) 1992, 1993, 1994, 1995
+ * Remy Card (card@masi.ibp.fr)
+ * Laboratoire MASI - Institut Blaise Pascal
+ * Universite Pierre et Marie Curie (Paris VI)
+ *
+ *  from
+ *
+ *  linux/include/linux/minix_fs_sb.h
+ *
+ *  Copyright (C) 1991, 1992  Linus Torvalds
+ */
+
+#ifndef _LINUX_EXT3_FS_SB
+#define _LINUX_EXT3_FS_SB
+
+#include <linux/ext3_fs.h>
+
+/*
+ * The following is not needed anymore since the descriptors buffer
+ * heads are now dynamically allocated
+ */
+/* #define EXT3_MAX_GROUP_DESC	8 */
+
+#define EXT3_MAX_GROUP_LOADED	8
+
+/*
+ * second extended-fs super-block data in memory
+ */
+struct ext3_sb_info {
+	unsigned long s_frag_size;	/* Size of a fragment in bytes */
+	unsigned long s_frags_per_block;/* Number of fragments per block */
+	unsigned long s_inodes_per_block;/* Number of inodes per block */
+	unsigned long s_frags_per_group;/* Number of fragments in a group */
+	unsigned long s_blocks_per_group;/* Number of blocks in a group */
+	unsigned long s_inodes_per_group;/* Number of inodes in a group */
+	unsigned long s_itb_per_group;	/* Number of inode table blocks per group */
+	unsigned long s_db_per_group;	/* Number of descriptor blocks per group */
+	unsigned long s_desc_per_block;	/* Number of group descriptors per block */
+	unsigned long s_groups_count;	/* Number of groups in the fs */
+	struct buffer_head * s_sbh;	/* Buffer containing the super block */
+	struct ext3_super_block * s_es;	/* Pointer to the super block in the buffer */
+	struct buffer_head ** s_group_desc;
+	unsigned short s_loaded_inode_bitmaps;
+	unsigned short s_loaded_block_bitmaps;
+	unsigned long s_inode_bitmap_number[EXT3_MAX_GROUP_LOADED];
+	struct buffer_head * s_inode_bitmap[EXT3_MAX_GROUP_LOADED];
+	unsigned long s_block_bitmap_number[EXT3_MAX_GROUP_LOADED];
+	struct buffer_head * s_block_bitmap[EXT3_MAX_GROUP_LOADED];
+	unsigned long  s_mount_opt;
+	unsigned short s_resuid;
+	unsigned short s_resgid;
+	unsigned short s_mount_state;
+	unsigned short s_pad;
+	int s_addr_per_block_bits;
+	int s_desc_per_block_bits;
+	int s_inode_size;
+	int s_first_ino;
+	int s_feature_compat;
+	int s_feature_incompat;
+	int s_feature_ro_compat;
+
+	/* Journaling */
+	struct inode * s_journal_inode;
+	struct journal_s * s_journal;
+};
+
+#endif	/* _LINUX_EXT3_FS_SB */
Index: oldkernel/linux/include/linux/ext3_jfs.h
diff -u /dev/null linux/include/linux/ext3_jfs.h:1.1
--- /dev/null	Mon Jul 31 21:15:09 2000
+++ linux/include/linux/ext3_jfs.h	Fri Jul  7 16:18:17 2000
@@ -0,0 +1,116 @@
+/*
+ * linux/include/linux/ext3_jfs.h
+ *
+ * Written by Stephen C. Tweedie <sct@redhat.com>, 1999
+ *
+ * Copyright 1998--1999 Red Hat corp --- All Rights Reserved
+ *
+ * This file is part of the Linux kernel and is made available under
+ * the terms of the GNU General Public License, version 2, or at your
+ * option, any later version, incorporated herein by reference.
+ *
+ * Ext3-specific journaling extensions.
+ */
+
+#ifndef _LINUX_EXT3_JFS_H
+#define _LINUX_EXT3_JFS_H
+
+#include <linux/fs.h>
+#include <linux/jfs.h>
+#include <linux/ext3_fs.h>
+
+#define EXT3_JOURNAL(inode)	(EXT3_SB((inode)->i_sb)->s_journal)
+
+/* Define the number of blocks we need to account to a transaction to
+ * modify one block of data.
+ * 
+ * We may have to touch one inode, one bitmap buffer, up to three
+ * indirection blocks, the group and superblock summaries, and the data
+ * block to complete the transaction.  */
+
+#define EXT3_SINGLEDATA_TRANS_BLOCKS	8
+
+/* Define the minimum size for a transaction which modifies data.  This
+ * needs to take into account the fact that we may end up modifying two
+ * quota files too (one for the group, one for the user quota).  The
+ * superblock only gets updated once, of course, so don't bother
+ * counting that again for the quota updates. */
+
+#define EXT3_DATA_TRANS_BLOCKS		(3 * EXT3_SINGLEDATA_TRANS_BLOCKS - 2)
+
+/* Delete operations potentially hit one directory's namespace plus an
+ * entire inode, plus arbitrary amounts of bitmap/indirection data.  Be
+ * generous.  We can grow the delete transaction later if necessary. */
+
+#define EXT3_DELETE_TRANS_BLOCKS	(2 * EXT3_DATA_TRANS_BLOCKS + 64)
+
+/* Define an arbitrary limit for the amount of data we will anticipate
+ * writing to any given transaction.  For unbounded transactions such as
+ * write(2) and truncate(2) we can write more than this, but we always
+ * start off at the maximum transaction size and grow the transaction
+ * optimistically as we go. */
+
+#define EXT3_MAX_TRANS_DATA		64
+
+/* We break up a large truncate or write transaction once the handle's
+ * buffer credits gets this low, we need either to extend the
+ * transaction or to start a new one.  Reserve enough space here for
+ * inode, bitmap, superblock, group and indirection updates for at least
+ * one block, plus two quota updates.  Quota allocations are not
+ * needed. */
+
+#define EXT3_RESERVE_TRANS_BLOCKS	12
+
+static inline int
+ext3_mark_iloc_dirty(handle_t *handle, 
+		     struct inode *inode,
+		     struct ext3_iloc *iloc)
+{
+	if (handle) {
+		/* the do_update_inode consumes one bh->b_count */
+		iloc->bh->b_count++;
+		ext3_do_update_inode(handle, inode, iloc, 0); /* @@@ ERROR */
+		journal_dirty_metadata(handle, iloc->bh); /* @@@ ERROR */
+		brelse(iloc->bh);
+	} else
+		mark_inode_dirty(inode);		
+	return 0;
+}
+
+/* 
+ * On success, We end up with an outstanding reference count against
+ * iloc->bh.  This _must_ be cleaned up later. 
+ */
+
+static inline int
+ext3_reserve_inode_write(handle_t *handle, struct inode *inode, 
+			 struct ext3_iloc *iloc)
+{
+	int err = 0;
+	if (handle) {
+		err = ext3_get_inode_loc(inode, iloc); /* @@@ ERROR */
+		if (!err) {
+			err = journal_get_write_access(handle, iloc->bh);
+			if (err) {
+				brelse(iloc->bh);
+				iloc->bh = NULL;
+			}
+		}
+	}
+	return err;
+}
+
+static inline int
+ext3_mark_inode_dirty(handle_t *handle, 
+		      struct inode *inode)
+{
+	struct ext3_iloc iloc;
+	int err;
+
+	err = ext3_reserve_inode_write(handle, inode, &iloc);
+	if (!err)
+		err = ext3_mark_iloc_dirty(handle, inode, &iloc);
+	return err;
+}
+
+#endif	/* _LINUX_EXT3_JFS_H */
Index: oldkernel/linux/include/linux/fs.h
diff -u linux/include/linux/fs.h:1.5 linux/include/linux/fs.h:1.6
--- linux/include/linux/fs.h:1.5	Thu Jun  1 16:48:05 2000
+++ linux/include/linux/fs.h	Fri Jul  7 15:36:47 2000
@@ -18,6 +18,7 @@
 #include <linux/list.h>
 #include <linux/dcache.h>
 #include <linux/stat.h>
+#include <linux/jfs_check.h>
 
 #include <asm/atomic.h>
 #include <linux/bitops.h>
@@ -154,6 +155,10 @@
 #define BLKSECTSET _IO(0x12,102)/* set max sectors per request (ll_rw_blk.c) */
 #define BLKSECTGET _IO(0x12,103)/* get max sectors per request (ll_rw_blk.c) */
 #define BLKSSZGET  _IO(0x12,104) /* get block device sector size */
+#if 0
+#define BLKELVGET   _IO(0x12,106)
+#define BLKELVSET   _IO(0x12,107)
+#endif
 
 #define BMAP_IOCTL 1		/* obsolete - kept for compatibility */
 #define FIBMAP	   _IO(0x00,1)	/* bmap access */
@@ -173,6 +178,12 @@
 extern void file_table_init(void);
 extern void dcache_init(unsigned long);
 
+/* We declare a few opaque types for use by the journaling code. */
+typedef unsigned long		tid_t;		/* Unique transaction ID */
+typedef struct transaction_s	transaction_t;	/* Compound transaction type */
+typedef struct handle_s		handle_t;	/* Atomic operation type */
+typedef struct journal_s	journal_t;	/* Journal control structure */
+
 typedef char buffer_block[BLOCK_SIZE];
 
 /* bh state bits */
@@ -182,6 +193,19 @@
 #define BH_Req		3	/* 0 if the buffer has been invalidated */
 #define BH_Protected	6	/* 1 if the buffer is protected */
 #define BH_LowPrio	7	/* 1 if the buffer is lowprio */
+#define BH_Temp		8	/* 1 if the buffer is temporary (unlinked) */
+#define BH_JWrite	9	/* 1 if being written to log (@@@ DEBUGGING) */
+
+/* journaling buffer types */
+#define BJ_None		0	/* Not journaled */
+#define BJ_Data		1	/* Normal data: flush before commit */
+#define BJ_Metadata	2	/* Normal journaled metadata */
+#define BJ_Forget	3	/* Buffer superceded by this transaction */
+#define BJ_IO		4	/* Buffer is for temporary IO use */
+#define BJ_Shadow	5	/* Buffer contents being shadowed to the log */
+#define BJ_LogCtl	6	/* Buffer contains log descriptors */
+#define BJ_Reserved	7	/* Buffer is reserved for access by journal */
+#define BJ_Types	8
 
 /*
  * Try to keep the most commonly used fields in single cache lines (16
@@ -210,7 +234,8 @@
 
 	/* Non-performance-critical data follows. */
 	char * b_data;			/* pointer to data block (1024 bytes) */
-	unsigned int b_list;		/* List that this buffer appears */
+	unsigned char b_list;		/* List that this buffer appears */
+	unsigned char b_jlist;		/* Journaling list for this buffer */
 	unsigned long b_flushtime;      /* Time when this (dirty) buffer
 					 * should be written */
 	struct wait_queue * b_wait;
@@ -223,6 +248,41 @@
 	 */
 	void (*b_end_io)(struct buffer_head *bh, int uptodate);
 	void *b_dev_id;
+
+	/* Journaling-related fields */
+
+	/* Copy of the buffer data frozen for writing to the log. */
+	char * b_frozen_data;
+
+	/* Pointer to a saved copy of the buffer containing no
+           uncommitted deallocation references, so that allocations can
+           avoid overwriting uncommitted deletes. */
+	char * b_committed_data;
+	
+	/* Pointer to the compound transaction which owns this buffer's
+           metadata: either the running transaction or the committing
+           transaction (if there is one).  Only applies to buffers on a
+           transaction's data or metadata journaling list. */
+	transaction_t * b_transaction;
+	
+	/* Pointer to the running compound transaction which is
+           currently modifying the buffer's metadata, if there was
+           already a transaction committing it when the new transaction
+           touched it. */
+	transaction_t * b_next_transaction;
+	
+	/* Doubly-linked list of buffers on a transaction's data,
+           metadata or forget queue. */
+	struct buffer_head *b_tnext, *b_tprev;
+
+	/* Pointer to the compound transaction against which this buffer
+           is checkpointed.  Only dirty buffers can be checkpointed. */
+	transaction_t * b_cp_transaction;
+	
+	/* Doubly-linked list of buffers still remaining to be flushed
+           before an old transaction can be checkpointed. */
+	struct buffer_head *b_cpnext, *b_cpprev;
+
 };
 
 typedef void (bh_end_io_t)(struct buffer_head *bh, int uptodate);
@@ -253,32 +313,19 @@
 {
 	return test_bit(BH_Protected, &bh->b_state);
 }
-
-#define buffer_page(bh)		(mem_map + MAP_NR((bh)->b_data))
-#define touch_buffer(bh)	set_bit(PG_referenced, &buffer_page(bh)->flags)
-
-/* log of base-2 for filesystem uses, in case their super-blocks
-   don't have the shift counts readily calculated.. -- presuming
-   the divisors in question are power-of-two values! */
-static int fslog2(unsigned long val) __attribute__ ((const));
-static __inline__ int fslog2(unsigned long val)
-{
-	int i;
-	for (i = 0; val != 0; ++i, val >>= 1) {
-	  if (val & 1) return i;
-	}
-	return 0;
-}
 
-static int off_t_presentable(loff_t) __attribute((const));
-static __inline__ int off_t_presentable(loff_t loff)
+static inline int buffer_journaled(struct buffer_head * bh)
 {
-	return ((unsigned long long)loff < (long)(~0UL >> 1));
+	return (bh->b_jlist != BJ_None || bh->b_cp_transaction != NULL);
 }
 
+#define buffer_page(bh)		(mem_map + MAP_NR((bh)->b_data))
+#define touch_buffer(bh)	set_bit(PG_referenced, &buffer_page(bh)->flags)
+
 #include <linux/pipe_fs_i.h>
 #include <linux/minix_fs_i.h>
 #include <linux/ext2_fs_i.h>
+#include <linux/ext3_fs_i.h>
 #include <linux/hpfs_fs_i.h>
 #include <linux/ntfs_fs_i.h>
 #include <linux/msdos_fs_i.h>
@@ -326,7 +373,7 @@
 	umode_t		ia_mode;
 	uid_t		ia_uid;
 	gid_t		ia_gid;
-	loff_t		ia_size;
+	off_t		ia_size;
 	time_t		ia_atime;
 	time_t		ia_mtime;
 	time_t		ia_ctime;
@@ -361,7 +408,7 @@
 	uid_t			i_uid;
 	gid_t			i_gid;
 	kdev_t			i_rdev;
-	loff_t			i_size;
+	off_t			i_size;
 	time_t			i_atime;
 	time_t			i_mtime;
 	time_t			i_ctime;
@@ -388,10 +435,26 @@
 	int			i_writecount;
 	unsigned int		i_attr_flags;
 	__u32			i_generation;
+
+	/* Journaling support fields */
+
+	/* Transaction which owns the latest modifications in this inode */
+	transaction_t	      * i_transaction;
+	
+	/* Doubly-linked list of inodes which have been modified by that
+           transaction */
+	struct inode	      * i_tnext, ** i_tprev;
+	
+	/* Pointer to the buffer which backs this inode, to save massive
+           repeated getblk()s when modifying files */
+	struct buffer_head    * i_ibuf;
+	
+	/* Filesystem-specific data: */
 	union {
 		struct pipe_inode_info		pipe_i;
 		struct minix_inode_info		minix_i;
 		struct ext2_inode_info		ext2_i;
+		struct ext3_inode_info		ext3_i;
 		struct hpfs_inode_info		hpfs_i;
 		struct ntfs_inode_info          ntfs_i;
 		struct msdos_inode_info		msdos_i;
@@ -438,7 +501,7 @@
 	mode_t			f_mode;
 	loff_t			f_pos;
 	unsigned int 		f_count, f_flags;
-	loff_t			f_reada, f_ramax, f_raend, f_ralen, f_rawin;
+	unsigned long 		f_reada, f_ramax, f_raend, f_ralen, f_rawin;
 	struct fown_struct	f_owner;
 	unsigned int		f_uid, f_gid;
 	int			f_error;
@@ -478,10 +541,12 @@
 	struct file *fl_file;
 	unsigned char fl_flags;
 	unsigned char fl_type;
-	loff_t fl_start;
-	loff_t fl_end;
+	off_t fl_start;
+	off_t fl_end;
 
 	void (*fl_notify)(struct file_lock *);	/* unblock callback */
+	void (*fl_insert)(struct file_lock *);	/* lock insertion callback */
+	void (*fl_remove)(struct file_lock *);	/* lock removal callback */
 
 	union {
 		struct nfs_lock_info	nfs_fl;
@@ -495,9 +560,6 @@
 extern int fcntl_getlk(unsigned int fd, struct flock *l);
 extern int fcntl_setlk(unsigned int fd, unsigned int cmd, struct flock *l);
 
-extern int fcntl_getlk64(unsigned int fd, struct flock64 *l);
-extern int fcntl_setlk64(unsigned int fd, unsigned int cmd, struct flock64 *l);
-
 /* fs/locks.c */
 extern void locks_remove_posix(struct file *, fl_owner_t id);
 extern void locks_remove_flock(struct file *);
@@ -519,6 +581,7 @@
 
 #include <linux/minix_fs_sb.h>
 #include <linux/ext2_fs_sb.h>
+#include <linux/ext3_fs_sb.h>
 #include <linux/hpfs_fs_sb.h>
 #include <linux/ntfs_fs_sb.h>
 #include <linux/msdos_fs_sb.h>
@@ -559,9 +622,14 @@
 	short int		s_ibasket_max;
 	struct list_head	s_dirty;	/* dirty inodes */
 
+	/* Pointer to journaling control structure for this filesystem */
+	journal_t	      * s_journal;
+	
+	/* Filesystem-specific data: */
 	union {
 		struct minix_sb_info	minix_sb;
 		struct ext2_sb_info	ext2_sb;
+		struct ext3_sb_info	ext3_sb;
 		struct hpfs_sb_info	hpfs_sb;
 		struct ntfs_sb_info     ntfs_sb;
 		struct msdos_sb_info	msdos_sb;
@@ -583,6 +651,15 @@
 	 * even looking at it. You had been warned.
 	 */
 	struct semaphore s_vfs_rename_sem;	/* Kludge */
+
+	/* The next field is used by knfsd when converting a (inode number based)
+	 * file handle into a dentry. As it builds a path in the dcache tree from
+	 * the bottom up, there may for a time be a subpath of dentrys which is not
+	 * connected to the main tree.  This semaphore ensure that there is only ever
+	 * one such free path per filesystem.  Note that unconnected files (or other
+	 * non-directories) are allowed, but not unconnected diretories.
+	 */
+	struct semaphore s_nfsd_free_path_sem;
 };
 
 /*
@@ -638,7 +715,7 @@
 	void (*truncate) (struct inode *);
 	int (*permission) (struct inode *, int);
 	int (*smap) (struct inode *,int);
-	int (*updatepage) (struct file *, struct page *, unsigned long, unsigned int, int);
+	int (*updatepage) (struct file *, struct page *, const char *, unsigned long, unsigned int, int);
 	int (*revalidate) (struct dentry *);
 };
 
@@ -719,7 +796,7 @@
 
 asmlinkage int sys_open(const char *, int, int);
 asmlinkage int sys_close(unsigned int);		/* yes, it's really unsigned */
-extern int do_truncate(struct dentry *, loff_t);
+extern int do_truncate(struct dentry *, unsigned long);
 extern int get_unused_fd(void);
 extern void put_unused_fd(unsigned int);
 
@@ -769,6 +846,8 @@
 extern int fs_may_remount_ro(struct super_block *);
 extern int fs_may_mount(kdev_t dev);
 
+extern int vfsmnt_replace_mt_de(struct inode *, struct dentry *);
+
 extern struct file *inuse_filps;
 
 extern void refile_buffer(struct buffer_head * buf);
@@ -782,13 +861,15 @@
 
 #define BUF_CLEAN	0
 #define BUF_LOCKED	1	/* Buffers scheduled for write */
-#define BUF_DIRTY	2	/* Dirty buffers, not yet scheduled for write */
-#define NR_LIST		3
+#define BUF_DIRTY	2	/* Dirty buffers, not yet scheduled for write*/
+#define BUF_JOURNAL	3
+#define NR_LIST		4
 
 void mark_buffer_uptodate(struct buffer_head * bh, int on);
 
 extern inline void mark_buffer_clean(struct buffer_head * bh)
 {
+	call_jfs_preclean_buffer_check(bh); /* @@@ Expensive debugging */
 	if (test_and_clear_bit(BH_Dirty, &bh->b_state)) {
 		if (bh->b_list == BUF_DIRTY)
 			refile_buffer(bh);
@@ -854,6 +935,7 @@
 extern void sync_supers(kdev_t dev);
 extern int bmap(struct inode * inode,int block);
 extern int notify_change(struct dentry *, struct iattr *);
+extern int unix_permission(struct inode * inode,int mask);
 extern int permission(struct inode * inode,int mask);
 extern int get_write_access(struct inode *inode);
 extern void put_write_access(struct inode *inode);
@@ -898,7 +980,10 @@
 extern void iput(struct inode *);
 extern struct inode * igrab(struct inode *inode);
 extern ino_t iunique(struct super_block *, ino_t);
-extern struct inode * iget(struct super_block *, unsigned long);
+
+typedef int (*find_inode_t)(struct inode *, unsigned long, void *);
+extern struct inode * iget4(struct super_block *, unsigned long, find_inode_t, void *);
+extern struct inode * iget(struct super_block *sb, unsigned long ino);
 extern struct inode * iget_in_use (struct super_block *, unsigned long);
 extern void clear_inode(struct inode *);
 extern struct inode * get_empty_inode(void);
Index: oldkernel/linux/include/linux/jfs.h
diff -u /dev/null linux/include/linux/jfs.h:1.1
--- /dev/null	Mon Jul 31 21:15:09 2000
+++ linux/include/linux/jfs.h	Fri Jul  7 16:18:17 2000
@@ -0,0 +1,508 @@
+/*
+ * linux/include/linux/jfs.h
+ * 
+ * Written by Stephen C. Tweedie <sct@redhat.com>, 1998
+ *
+ * Copyright 1998 Red Hat corp --- All Rights Reserved
+ *
+ * This file is part of the Linux kernel and is made available under
+ * the terms of the GNU General Public License, version 2, or at your
+ * option, any later version, incorporated herein by reference.
+ *
+ * Definitions for transaction data structures for the buffer cache
+ * filesystem journaling support.
+ */
+
+#ifndef _LINUX_JFS_H
+#define _LINUX_JFS_H
+
+#include <asm/semaphore.h>
+
+/*
+ * Debug code
+ */
+
+#define JFS_DEBUG
+
+extern int jfs_enable_debug;
+
+#ifdef JFS_DEBUG
+#define jfs_debug(n, f, a...)						\
+	do {								\
+		if ((n) <= jfs_enable_debug) {				\
+			printk (KERN_DEBUG "JFS DEBUG: (%s, %d): %s: ",	\
+				__FILE__, __LINE__, __FUNCTION__);	\
+		  	printk (f, ## a);			\
+		}							\
+	} while (0)
+#else
+#define jfs_debug(f, a...)	/**/
+#endif
+
+#define JFS_MIN_JOURNAL_BLOCKS 1024
+
+/*
+ * Internal structures used by the logging mechanism:
+ */
+
+#define JFS_MAGIC_NUMBER 0xc03b3998U /* The first 4 bytes of /dev/random! */
+
+
+/*
+ * On-disk structures
+ */
+
+/* 
+ * Descriptor block types:
+ */
+
+#define JFS_DESCRIPTOR_BLOCK	1
+#define JFS_COMMIT_BLOCK	2
+#define JFS_SUPERBLOCK		3
+
+/*
+ * Standard header for all descriptor blocks:
+ */
+typedef struct journal_header_s
+{
+	__u32		h_magic;
+	__u32		h_blocktype;
+	__u32		h_sequence;
+} journal_header_t;
+
+
+/* 
+ * The block tag: used to describe a single buffer in the journal 
+ */
+typedef struct journal_block_tag_s
+{
+	__u32		t_blocknr;	/* The on-disk block number */
+	__u32		t_flags;	/* See below */
+} journal_block_tag_t;
+
+/* Definitions for the journal tag flags word: */
+#define JFS_FLAG_ESCAPE		1	/* on-disk block is escaped */
+#define JFS_FLAG_SAME_UUID	2	/* block has same uuid as previous */
+#define JFS_FLAG_DELETED	4	/* block deleted by this transaction */
+#define JFS_FLAG_LAST_TAG	8	/* last tag in this descriptor block */
+
+
+/*
+ * The journal superblock
+ */
+typedef struct journal_superblock_s
+{
+	journal_header_t s_header;
+
+	/* Static information describing the journal */
+	__u32		s_blocksize;	/* journal device blocksize */
+	__u32		s_maxlen;	/* total blocks in journal file */
+	__u32		s_first;	/* first block of log information */
+	
+	/* Dynamic information describing the current state of the log */
+	__u32		s_sequence;	/* first commit ID expected in log */
+	__u32		s_start;	/* blocknr of start of log */
+	
+} journal_superblock_t;
+
+#ifdef __KERNEL__
+
+#include <linux/fs.h>
+
+
+#define J_ASSERT(assert)						\
+	do { if (!(assert)) {						\
+		printk (KERN_CRIT					\
+			"Assertion failure in %s() at %s line %d: "	\
+			"\"%s\"\n",					\
+			__FUNCTION__, __FILE__, __LINE__, # assert);	\
+		* ((char *) 0) = 0;					\
+	} } while (0)
+
+
+
+/* The handle_t type represents a single atomic update being performed
+ * by some process.  All filesystem modifications made by the process go
+ * through this handle.  Recursive operations (such as quota operations)
+ * are gathered into a single update.
+ *
+ * The buffer credits field is used to account for journaled buffers
+ * being modified by the running process.  To ensure that there is
+ * enough log space for all outstanding operations, we need to limit the
+ * number of outstanding buffers possible at any time.  When the
+ * operation completes, any buffer credits not used are credited back to
+ * the transaction, so that at all times we know how many buffers the
+ * outstanding updates on a transaction might possibly touch. */
+
+struct handle_s 
+{
+	/* Which compound transaction is this update a part of? */
+	transaction_t	      * h_transaction;
+
+	/* Number of remaining buffers we are allowed to dirty: */
+	int			h_buffer_credits;
+
+	/* Reference count on this handle */
+	int			h_ref;
+
+	/* Flags */
+	unsigned int		h_sync	: 1;	/* sync-on-close */
+};
+
+
+/* The transaction_t type is the guts of the journaling mechanism.  It
+ * tracks a compound transaction through its various states:
+ *
+ * RUNNING:	accepting new updates
+ * LOCKED:	Updates still running but we don't accept new ones
+ * RUNDOWN:	Updates are tidying up but have finished requesting
+ *		new buffers to modify (state not used for now)
+ * FLUSH:       All updates complete, but we are still writing to disk
+ * COMMIT:      All data on disk, writing commit record
+ * FINISHED:	We still have to keep the transaction for checkpointing.
+ *
+ * The transaction keeps track of all of the buffers modified by a
+ * running transaction, and all of the buffers committed but not yet
+ * flushed to home for finished transactions.
+ */
+
+struct transaction_s 
+{
+	/* Pointer to the journal for this transaction. */
+	journal_t *		t_journal;
+	
+	/* Sequence number for this transaction */
+	tid_t			t_tid;
+	
+	/* Transaction's current state */
+	enum {
+		T_RUNNING,
+		T_LOCKED,
+		T_RUNDOWN,
+		T_FLUSH,
+		T_COMMIT,
+		T_FINISHED 
+	}			t_state;
+
+	/* Where in the log does this transaction's commit start? */
+	unsigned long		t_log_start;
+	
+	/* Doubly-linked circular list of all inodes owned by this
+           transaction */
+	struct inode *		t_ilist;
+	
+	/* Number of buffers on the t_buffers list */
+	int			t_nr_buffers;
+	
+	/* Doubly-linked circular list of all buffers reserved but not
+           yet modified by this transaction */
+	struct buffer_head *	t_reserved_list;
+	
+	/* Doubly-linked circular list of all metadata buffers owned by this
+           transaction */
+	struct buffer_head *	t_buffers;
+	
+	/* Doubly-linked circular list of all data buffers still to be
+           flushed before this transaction can be committed */
+	struct buffer_head *	t_datalist;
+	
+	/* Doubly-linked circular list of all forget buffers (superceded
+           buffers which we can un-checkpoint once this transaction
+           commits) */
+	struct buffer_head *	t_forget;
+	
+	/* Doubly-linked circular list of all buffers still to be
+           flushed before this transaction can be checkpointed */
+	struct buffer_head *	t_checkpoint_list;
+	
+	/* Doubly-linked circular list of temporary buffers currently
+           undergoing IO in the log */
+	struct buffer_head *	t_iobuf_list;
+	
+	/* Doubly-linked circular list of metadata buffers being
+           shadowed by log IO.  The IO buffers on the iobuf list and the
+           shadow buffers on this list match each other one for one at
+           all times. */
+	struct buffer_head *	t_shadow_list;
+	
+	/* Doubly-linked circular list of control buffers being written
+           to the log. */
+	struct buffer_head *	t_log_list;
+	
+	/* Number of outstanding updates running on this transaction */
+	int			t_updates;
+
+	/* Number of buffers reserved for use by all handles in this
+	 * transaction handle but not yet modified. */
+	int			t_outstanding_credits;
+	
+	/* Wait queue to wait for updates to complete */
+	struct wait_queue *	t_wait;
+
+	/* Forward and backward links for the circular list of all
+	 * transactions awaiting checkpoint */
+	transaction_t		*t_cpnext, *t_cpprev;
+
+	/* When will the transaction expire (become due for commit), in
+	 * jiffies ? */
+	unsigned long		t_expires;
+};
+
+
+/* The journal_t maintains all of the journaling state information for a
+ * single filesystem.  It is linked to from the fs superblock structure.
+ * 
+ * We use the journal_t to keep track of all outstanding transaction
+ * activity on the filesystem, and to manage the state of the log
+ * writing process. */
+
+struct journal_s
+{
+	/* General journaling state flags */
+	unsigned long		j_flags;
+	
+	/* The superblock buffer */
+	struct buffer_head *	j_sb_buffer;
+	journal_superblock_t *	j_superblock;
+	
+	/* Transactions: The current running transaction... */
+	transaction_t *		j_running_transaction;
+	
+	/* ... the transaction we are pushing to disk ... */
+	transaction_t *		j_committing_transaction;
+	
+	/* ... and a linked circular list of all transactions waiting
+	 * for checkpointing. */
+	transaction_t *		j_checkpoint_transactions;
+
+	/* Wait queue for locking of the journal structure.  */
+	struct wait_queue *	j_wait_lock;
+
+	/* Wait queue for waiting for a locked transaction to start
+           committing */
+	struct wait_queue *	j_wait_transaction_locked;
+	
+	/* Wait queue for waiting for checkpointing to complete */
+	struct wait_queue *	j_wait_logspace;
+	
+	/* Wait queue for waiting for commit to complete */
+	struct wait_queue *	j_wait_done_commit;
+	
+	/* Wait queue to trigger checkpointing */
+	struct wait_queue *	j_wait_checkpoint;
+	
+	/* Wait queue to trigger commit */
+	struct wait_queue *	j_wait_commit;
+	
+	/* Semaphore for locking against concurrent checkpoints */
+	struct semaphore 	j_checkpoint_sem;
+		
+	/* Journal running state: */
+	/* The lock flag is *NEVER* touched from interrupts. */
+	unsigned int		j_locked : 1;
+
+	/* Journal head: identifies the first unused block in the journal. */
+	unsigned long		j_head;
+	
+	/* Journal tail: identifies the oldest still-used block in the
+	 * journal. */
+	unsigned long		j_tail;
+
+	/* Journal free: how many free blocks are there in the journal? */
+	unsigned long		j_free;
+
+	/* Journal start and end: the block numbers of the first usable
+	 * block and one beyond the last usable block in the journal. */
+	unsigned long		j_first, j_last;
+
+	/* Device, blocksize and starting block offset for the location
+	 * where we store the journal. */
+	kdev_t			j_dev;
+	int			j_blocksize;
+	unsigned int		j_blk_offset;
+
+	/* Total maximum capacity of the journal region on disk. */
+	unsigned int		j_maxlen;
+
+	/* Optional inode where we store the journal.  If present, all
+	 * journal block numbers are mapped into this inode via
+	 * bmap(). */
+	struct inode *		j_inode;
+
+	/* Sequence number of the oldest transaction in the log */
+	tid_t			j_tail_sequence;
+	/* Sequence number of the next transaction to grant */
+	tid_t			j_transaction_sequence;
+	/* Sequence number of the most recently committed transaction */
+	tid_t			j_commit_sequence;
+	/* Sequence number of the most recent transaction wanting commit */
+	tid_t			j_commit_request;
+
+	/* Journal uuid: identifies the object (filesystem, LVM volume
+	 * etc) backed by this journal.  This will eventually be
+	 * replaced by an array of uuids, allowing us to index multiple
+	 * devices within a single journal and to perform atomic updates
+	 * across them.  */
+
+	__u8			j_uuid[16];
+
+	/* Pointer to the current commit thread for this journal */
+	struct task_struct *	j_task;
+
+	/* Maximum number of metadata buffers to allow in a single
+	 * compound commit transaction */
+	int			j_max_transaction_buffers;
+
+	/* What is the maximum transaction lifetime before we begin a
+	 * commit? */
+	unsigned long		j_commit_interval;
+
+	/* The timer used to wakeup the commit thread: */
+	struct timer_list *	j_commit_timer;
+	int			j_commit_timer_active;
+};
+
+/* 
+ * Journal flag definitions 
+ */
+#define JFS_UNMOUNT	1	/* Journal thread is being destroyed */
+#define JFS_SYNC	2	/* Perform synchronous transaction commits */
+
+/* 
+ * Journaling internal variables/parameters 
+ */
+
+extern int journal_flush_nr_buffers;
+
+
+/* 
+ * Function declarations for the journaling transaction and buffer
+ * management
+ */
+
+/* Filing buffers */
+extern void journal_unfile_buffer(struct buffer_head *);
+extern void journal_refile_buffer(struct buffer_head *);
+extern void journal_file_buffer(struct buffer_head *, transaction_t *, int);
+extern void journal_clean_data_list(transaction_t *transaction);
+
+/* Log buffer allocation */
+extern struct buffer_head * journal_get_descriptor_buffer(journal_t *);
+extern unsigned long journal_next_log_block(journal_t *);
+
+/* Commit management */
+extern void journal_commit_transaction(journal_t *);
+
+/* Checkpoint list management */
+extern void real_journal_remove_checkpoint(struct buffer_head *);
+extern void (*journal_remove_checkpoint)(struct buffer_head *);
+extern void journal_insert_checkpoint(struct buffer_head *, transaction_t *);
+
+/* Buffer IO */
+extern int 
+journal_write_metadata_buffer(transaction_t	  *transaction,
+			      struct buffer_head  *bh_in,
+			      struct buffer_head **bh_out,
+			      int		   blocknr);
+
+/* Create and destroy transactions */
+extern transaction_t *	get_transaction (journal_t *);
+extern void		put_transaction (transaction_t *);
+
+/* Notify state transitions (called by the log writer thread): */
+extern int		set_transaction_state (transaction_t *, int);
+
+
+/* Transaction locking */
+extern void		__wait_on_journal (journal_t *);
+
+/* Journal locking.  In 2.2, we assume that the kernel lock is already
+ * held. */
+static inline void lock_journal (journal_t * journal)
+{
+	if (journal->j_locked)
+		__wait_on_journal(journal);
+	journal->j_locked = 1;
+}
+
+static inline int try_lock_journal (journal_t * journal)
+{
+	if (journal->j_locked)
+		return 1;
+	journal->j_locked = 1;
+	return 0;
+}
+
+static inline void unlock_journal (journal_t * journal)
+{
+	J_ASSERT (journal->j_locked);
+	journal->j_locked = 0;
+	wake_up(&journal->j_wait_lock);
+}
+
+/* This function is gross, but unfortunately we need it as long as
+ * existing filesystems want to guard against races by testing
+ * bh->b_count.  @@@ Remove this?  We no longer abuse b_count so badly!
+ */
+
+static inline int journal_is_buffer_shared(struct buffer_head *bh)
+{
+	int count = bh->b_count;
+	J_ASSERT (count >= 1);
+	return (count > 1);
+}
+
+/* The journaling code user interface:
+ *
+ * Create and destroy handles
+ * Register buffer modifications against the current transaction. 
+ */
+
+extern handle_t *journal_start (journal_t *, int nblocks);
+extern int	 journal_restart (handle_t *, int nblocks);
+extern int	 journal_extend (handle_t *, int nblocks);
+extern int	 journal_get_write_access (handle_t *, struct buffer_head *);
+extern int	 journal_get_create_access (handle_t *, struct buffer_head *);
+extern int	 journal_get_undo_access (handle_t *, struct buffer_head *);
+extern int	 journal_dirty_data (handle_t *, struct buffer_head *);
+extern int	 journal_dirty_metadata (handle_t *, struct buffer_head *);
+extern void	 journal_release_buffer (handle_t *, struct buffer_head *);
+extern void	 journal_forget (handle_t *, struct buffer_head *);
+extern void	 journal_sync_buffer (struct buffer_head *);
+extern int	 journal_stop (handle_t *);
+extern int	 journal_flush (journal_t *);
+
+extern journal_t * journal_init_dev   (kdev_t, int start, int len, int bsize);
+extern journal_t * journal_init_inode (struct inode *);
+extern int	   journal_create     (journal_t *);
+extern int	   journal_load       (journal_t *);
+extern void	   journal_release    (journal_t *);
+extern int	   journal_recover    (journal_t *);
+extern void	   journal_update_superblock (journal_t *, int);
+
+/* The log thread user interface:
+ *
+ * Request space in the current transaction, and force transaction commit
+ * transitions on demand.
+ */
+
+extern int	log_space_left (journal_t *); /* Called with journal locked */
+extern void	log_start_commit (journal_t *, transaction_t *);
+extern void	log_wait_commit (journal_t *, tid_t);
+extern int	log_do_checkpoint (journal_t *, int);
+
+extern void	log_wait_for_space(journal_t *, int nblocks);
+extern void	journal_drop_transaction(journal_t *, transaction_t *);
+
+
+/* Debugging code only: */
+
+#define jfs_ENOSYS() \
+do {								      \
+	printk (KERN_ERR "JFS unimplemented function " __FUNCTION__); \
+	current->state = TASK_UNINTERRUPTIBLE;			      \
+	schedule();						      \
+} while (1)
+
+#endif /* __KERNEL__   */
+#endif /* _LINUX_JFS_H */
Index: oldkernel/linux/include/linux/jfs_check.h
diff -u /dev/null linux/include/linux/jfs_check.h:1.1
--- /dev/null	Mon Jul 31 21:15:09 2000
+++ linux/include/linux/jfs_check.h	Fri Jul  7 16:18:17 2000
@@ -0,0 +1,20 @@
+#ifndef _LINUX_JFS_CHECK_H
+#define _LINUX_JFS_CHECK_H
+
+#include <linux/autoconf.h>
+
+#if defined(CONFIG_EXT3_FS_JFS_CHECK) && (defined(CONFIG_EXT3_FS) || defined(CONFIG_EXT3_FS_MODULE))
+struct buffer_head;
+extern void real_jfs_preclean_buffer_check(struct buffer_head *);
+extern void real_jfs_prelock_buffer_check(struct buffer_head *);
+extern void dummy_jfs_function(void *);
+extern void (*jfs_preclean_buffer_check)(struct buffer_head *);
+extern void (*jfs_prelock_buffer_check)(struct buffer_head *);
+#define call_jfs_preclean_buffer_check(bh) (*jfs_preclean_buffer_check) (bh)
+#define call_jfs_prelock_buffer_check(bh) (*jfs_prelock_buffer_check) (bh)
+#else 
+#define call_jfs_preclean_buffer_check(bh)	do {} while (0)
+#define call_jfs_prelock_buffer_check(bh)	do {} while (0)
+#endif
+
+#endif /* _LINUX_JFS_CHECK_H */
Index: oldkernel/linux/include/linux/locks.h
diff -u linux/include/linux/locks.h:1.1.1.1 linux/include/linux/locks.h:1.2
--- linux/include/linux/locks.h:1.1.1.1	Wed May 31 12:33:49 2000
+++ linux/include/linux/locks.h	Fri Jul  7 15:36:48 2000
@@ -7,6 +7,7 @@
 #ifndef _LINUX_PAGEMAP_H
 #include <linux/pagemap.h>
 #endif
+#include <linux/jfs_check.h>
 
 /*
  * Buffer cache locking - note that interrupts may only unlock, not
@@ -22,6 +23,8 @@
 
 extern inline void lock_buffer(struct buffer_head * bh)
 {
+	/* @@@ Debugging for the journaling code */
+	call_jfs_prelock_buffer_check(bh);
 	while (test_and_set_bit(BH_Lock, &bh->b_state))
 		__wait_on_buffer(bh);
 }
Index: oldkernel/linux/include/linux/mm.h
diff -u linux/include/linux/mm.h:1.3 linux/include/linux/mm.h:1.4
--- linux/include/linux/mm.h:1.3	Thu Jun  1 16:47:27 2000
+++ linux/include/linux/mm.h	Fri Jul  7 15:36:48 2000
@@ -54,7 +54,7 @@
 	struct vm_area_struct **vm_pprev_share;
 
 	struct vm_operations_struct * vm_ops;
-	loff_t vm_offset;
+	unsigned long vm_offset;
 	struct file * vm_file;
 	unsigned long vm_pte;			/* shared mem */
 };
@@ -106,47 +106,10 @@
 	unsigned long (*wppage)(struct vm_area_struct * area, unsigned long address,
 		unsigned long page);
 	int (*swapout)(struct vm_area_struct *, struct page *);
-	pte_t (*swapin)(struct vm_area_struct *, loff_t, unsigned long);
+	pte_t (*swapin)(struct vm_area_struct *, unsigned long, unsigned long);
 };
 
-
 /*
- *  pgoff_t  type -- a complex one, and its simple alternate.
- *  The complex one has type that compiler can trap at compile
- *  time, but the simple one does simpler code (?)
- */
-
-#if 0
-typedef struct pgoff_t {
-  unsigned long pgoff;
-} pgoff_t;
-
-#define pgoff2ulong(pgof) ((pgof).pgoff)
-extern __inline__ pgoff_t ulong2pgoff(unsigned long ul) {
-  pgoff_t up;
-  up.pgoff = ul;
-  return up;
-}
-
-#define pgoff2loff(pgof) (((loff_t)(pgof).pgoff) << PAGE_SHIFT)
-#define loff2pgoff(loff) ulong2pgoff((loff) >> PAGE_SHIFT)
-
-#else /* Integer scalars -- simpler code.. */
-
-typedef unsigned long pgoff_t;
-
-#define pgoff2ulong(pgof) (pgof)
-#define ulong2pgoff(pgof) (pgof)
-
-#define pgoff2loff(pgof) (((loff_t)(pgof)) << PAGE_SHIFT)
-#define loff2pgoff(loff) ulong2pgoff((loff) >> PAGE_SHIFT)
-
-#endif
-
-#define PAGE_MASK_loff ((loff_t)(long)(PAGE_MASK))
-
-
-/*
  * Try to keep the most commonly accessed fields in single cache lines
  * here (16 bytes or greater).  This ordering should be particularly
  * beneficial on 32-bit processors.
@@ -154,13 +117,12 @@
  * The first line is data used in page cache lookup, the second line
  * is used for linear searches (eg. clock algorithm scans). 
  */
-
 typedef struct page {
 	/* these must be first (free area handling) */
 	struct page *next;
 	struct page *prev;
-	pgoff_t index;
 	struct inode *inode;
+	unsigned long offset;
 	struct page *next_hash;
 	atomic_t count;
 	unsigned long flags;	/* atomic flags, some possibly updated asynchronously */
@@ -334,7 +296,7 @@
 extern int remap_page_range(unsigned long from, unsigned long to, unsigned long size, pgprot_t prot);
 extern int zeromap_page_range(unsigned long from, unsigned long size, pgprot_t prot);
 
-extern void vmtruncate(struct inode * inode, loff_t offset);
+extern void vmtruncate(struct inode * inode, unsigned long offset);
 extern int handle_mm_fault(struct task_struct *tsk,struct vm_area_struct *vma, unsigned long address, int write_access);
 extern int make_pages_present(unsigned long addr, unsigned long end);
 
@@ -353,32 +315,17 @@
 extern void build_mmap_avl(struct mm_struct *);
 extern void exit_mmap(struct mm_struct *);
 extern unsigned long get_unmapped_area(unsigned long, unsigned long);
-
-extern unsigned long do_mmap_pgoff(struct file *file, unsigned long addr,
-	unsigned long len, unsigned long prot,
-	unsigned long flag, unsigned long pgoff);
-
-extern inline unsigned long do_mmap(struct file *file, unsigned long addr,
-	unsigned long len, unsigned long prot,
-	unsigned long flag, unsigned long offset)
-{
-	unsigned long ret = -EINVAL;
-	if ((offset + PAGE_ALIGN(len)) < offset)
-		goto out;
-	if (!(offset & ~PAGE_MASK))
-		ret = do_mmap_pgoff(file, addr, len, prot, flag, offset >> PAGE_SHIFT);
-out:
-	return ret;
-}
 
+extern unsigned long do_mmap(struct file *, unsigned long, unsigned long,
+	unsigned long, unsigned long, unsigned long);
 extern int do_munmap(unsigned long, size_t);
 
 /* filemap.c */
 extern void remove_inode_page(struct page *);
 extern unsigned long page_unuse(struct page *);
 extern int shrink_mmap(int, int);
-extern void truncate_inode_pages(struct inode *, loff_t);
-extern unsigned long get_cached_page(struct inode *, pgoff_t, int);
+extern void truncate_inode_pages(struct inode *, unsigned long);
+extern unsigned long get_cached_page(struct inode *, unsigned long, int);
 extern void put_cached_page(unsigned long);
 
 /*
Index: oldkernel/linux/include/linux/nfs.h
diff -u linux/include/linux/nfs.h:1.2 linux/include/linux/nfs.h:1.3
--- linux/include/linux/nfs.h:1.2	Thu Jun  1 15:03:09 2000
+++ linux/include/linux/nfs.h	Fri Jul  7 15:36:48 2000
@@ -1,54 +1,60 @@
 /*
  * NFS protocol definitions
+ *
+ * This file contains constants mostly for Version 2 of the protocol,
+ * but also has a couple of NFSv3 bits in (notably the error codes).
  */
 #ifndef _LINUX_NFS_H
 #define _LINUX_NFS_H
 
 #include <linux/sunrpc/msg_prot.h>
 
-#define NFS_PORT	2049
-#define NFS_MAXDATA	8192
-#define NFS_MAXPATHLEN	1024
-#define NFS_MAXNAMLEN	255
-#define NFS_MAXGROUPS	16
-#define NFS_FHSIZE	32
-#define NFS_COOKIESIZE	4
-#define NFS_FIFO_DEV	(-1)
-#define NFSMODE_FMT	0170000
-#define NFSMODE_DIR	0040000
-#define NFSMODE_CHR	0020000
-#define NFSMODE_BLK	0060000
-#define NFSMODE_REG	0100000
-#define NFSMODE_LNK	0120000
-#define NFSMODE_SOCK	0140000
-#define NFSMODE_FIFO	0010000
+#define NFS_PROGRAM		100003
 
-	
+/*
+ * NFS stats. The good thing with these values is that NFSv3 errors are
+ * a superset of NFSv2 errors (with the exception of NFSERR_WFLUSH which
+ * no-one uses anyway), so we can happily mix code as long as we make sure
+ * no NFSv3 errors are returned to NFSv2 clients.
+ * Error codes that have a `--' in the v2 column are not part of the
+ * standard, but seem to be widely used nevertheless.
+ */
 enum nfs_stat {
-	NFS_OK = 0,
-	NFSERR_PERM = 1,
-	NFSERR_NOENT = 2,
-	NFSERR_IO = 5,
-	NFSERR_NXIO = 6,
-	NFSERR_EAGAIN = 11,
-	NFSERR_ACCES = 13,
-	NFSERR_EXIST = 17,
-	NFSERR_XDEV = 18,
-	NFSERR_NODEV = 19,
-	NFSERR_NOTDIR = 20,
-	NFSERR_ISDIR = 21,
-	NFSERR_INVAL = 22,	/* that Sun forgot */
-	NFSERR_FBIG = 27,
-	NFSERR_NOSPC = 28,
-	NFSERR_ROFS = 30,
-	NFSERR_OPNOTSUPP = 45,
-	NFSERR_NAMETOOLONG = 63,
-	NFSERR_NOTEMPTY = 66,
-	NFSERR_DQUOT = 69,
-	NFSERR_STALE = 70,
-	NFSERR_WFLUSH = 99
+	NFS_OK = 0,			/* v2 v3 */
+	NFSERR_PERM = 1,		/* v2 v3 */
+	NFSERR_NOENT = 2,		/* v2 v3 */
+	NFSERR_IO = 5,			/* v2 v3 */
+	NFSERR_NXIO = 6,		/* v2 v3 */
+	NFSERR_EAGAIN = 11,		/* v2 v3 */
+	NFSERR_ACCES = 13,		/* v2 v3 */
+	NFSERR_EXIST = 17,		/* v2 v3 */
+	NFSERR_XDEV = 18,		/*    v3 */
+	NFSERR_NODEV = 19,		/* v2 v3 */
+	NFSERR_NOTDIR = 20,		/* v2 v3 */
+	NFSERR_ISDIR = 21,		/* v2 v3 */
+	NFSERR_INVAL = 22,		/* v2 v3 that Sun forgot */
+	NFSERR_FBIG = 27,		/* v2 v3 */
+	NFSERR_NOSPC = 28,		/* v2 v3 */
+	NFSERR_ROFS = 30,		/* v2 v3 */
+	NFSERR_MLINK = 31,		/*    v3 */
+	NFSERR_OPNOTSUPP = 45,		/* v2 v3 */
+	NFSERR_NAMETOOLONG = 63,	/* v2 v3 */
+	NFSERR_NOTEMPTY = 66,		/* v2 v3 */
+	NFSERR_DQUOT = 69,		/* v2 v3 */
+	NFSERR_STALE = 70,		/* v2 v3 */
+	NFSERR_REMOTE = 71,		/* v2 v3 */
+	NFSERR_WFLUSH = 99,		/* v2    */
+	NFSERR_BADHANDLE = 10001,	/*    v3 */
+	NFSERR_NOT_SYNC = 10002,	/*    v3 */
+	NFSERR_BAD_COOKIE = 10003,	/*    v3 */
+	NFSERR_NOTSUPP = 10004,		/*    v3 */
+	NFSERR_TOOSMALL = 10005,	/*    v3 */
+	NFSERR_SERVERFAULT = 10006,	/*    v3 */
+	NFSERR_BADTYPE = 10007,		/*    v3 */
+	NFSERR_JUKEBOX = 10008		/*    v3 */
 };
 
+/* NFSv2 file types - beware, these are not the same in NFSv3 */
 enum nfs_ftype {
 	NFNON = 0,
 	NFREG = 1,
@@ -61,166 +67,149 @@
 	NFFIFO = 8
 };
 
-struct nfs_fh {
-	char			data[NFS_FHSIZE];
-};
 
-#define NFS_PROGRAM		100003
-#define NFS_VERSION		2
-#define NFSPROC_NULL		0
-#define NFSPROC_GETATTR		1
-#define NFSPROC_SETATTR		2
-#define NFSPROC_ROOT		3
-#define NFSPROC_LOOKUP		4
-#define NFSPROC_READLINK	5
-#define NFSPROC_READ		6
-#define NFSPROC_WRITECACHE	7
-#define NFSPROC_WRITE		8
-#define NFSPROC_CREATE		9
-#define NFSPROC_REMOVE		10
-#define NFSPROC_RENAME		11
-#define NFSPROC_LINK		12
-#define NFSPROC_SYMLINK		13
-#define NFSPROC_MKDIR		14
-#define NFSPROC_RMDIR		15
-#define NFSPROC_READDIR		16
-#define NFSPROC_STATFS		17
-
-/* Mount support for NFSroot */
 #ifdef __KERNEL__
+/* 
+ * Mount support for NFSroot
+ */
 #define NFS_MNT_PROGRAM		100005
 #define NFS_MNT_VERSION		1
 #define NFS_MNT_PORT		627
 #define NFS_MNTPROC_MNT		1
 #define NFS_MNTPROC_UMNT	3
-#endif
 
+/*
+ * This is really a general kernel constant, but since nothing like
+ * this is defined in the kernel headers, I have to do it here.
+ */
+#define NFS_OFFSET_MAX		LONG_MAX
+
+#endif /* __KERNEL__ */
+
 #if defined(__KERNEL__) || defined(NFS_NEED_KERNEL_TYPES)
 
-extern struct rpc_program	nfs_program;
-extern struct rpc_stat		nfs_rpcstat;
+/*
+ * These data types are used exlusively by the NFS client implementation.
+ * They support both NFSv2 and NFSv3.
+ */
 
-struct nfs_time {
-	__u32			seconds;
-	__u32			useconds;
+/*
+ * This is the kernel NFS client file handle representation
+ */
+#define NFS_MAXFHSIZE		64
+struct nfs_fh {
+	unsigned short		size;
+	unsigned char		data[NFS_MAXFHSIZE];
 };
 
 struct nfs_fattr {
-	enum nfs_ftype		type;
+	unsigned short          valid;		/* which fields are valid */
+	__u64                   pre_size;	/* pre_op_attr.size       */
+	__u64			pre_mtime;	/* pre_op_attr.mtime */
+	__u64			pre_ctime;	/* pre_op_attr.ctime */
+	enum nfs_ftype		type;           /* always use NFSv2 types */
 	__u32			mode;
 	__u32			nlink;
 	__u32			uid;
 	__u32			gid;
 	__u64			size;
-	__u32			blocksize;
+	union {
+		struct {
+			__u32	blocksize;
+			__u32	blocks;
+		} nfs2;
+		struct {
+			__u64   used;
+		} nfs3;
+	} du;
 	__u32			rdev;
-	__u32			blocks;
-	__u32			fsid;
-	__u32			fileid;
-	struct nfs_time		atime;
-	struct nfs_time		mtime;
-	struct nfs_time		ctime;
+	__u64			fsid;
+	__u64			fileid;
+	__u64		        atime;
+        __u64		        mtime;
+	__u64		        ctime;
 };
 
-struct nfs_sattr {
-	__u32			mode;
-	__u32			uid;
-	__u32			gid;
-	__u64			size;
-	struct nfs_time		atime;
-	struct nfs_time		mtime;
-};
 
-struct nfs_fsinfo {
-	__u32			tsize;
-	__u32			bsize;
-	__u32			blocks;
-	__u32			bfree;
-	__u32			bavail;
-};
-
-struct nfs_writeargs {
-	struct nfs_fh *		fh;
-	__u64			offset;
-	__u32			count;
-	const void *		buffer;
-};
 
-#ifdef NFS_NEED_XDR_TYPES
+#define NFS_ATTR_WCC		0x0001		/* pre-op WCC data */
+#define NFS_ATTR_FATTR		0x0002		/* post-op attributes */
+#define NFS_ATTR_FATTR_V3	0x0004		/* NFSv3 attributes */
 
-struct nfs_sattrargs {
-	struct nfs_fh *		fh;
-	struct nfs_sattr *	sattr;
+/*
+ * Info on the file system
+ */
+struct nfs_fsinfo {
+	__u32			rtmax;	/* max.  read transfer size */
+	__u32			rtpref;	/* pref. read transfer size */
+	__u32			rtmult;	/* reads should be multiple of this */
+	__u32			wtmax;	/* max.  write transfer size */
+	__u32			wtpref;	/* pref. write transfer size */
+	__u32			wtmult;	/* writes should be multiple of this */
+	__u32			dtpref;	/* pref. readdir transfer size */
+	__u64			maxfilesize;
+	__u64			bsize;	/* block size */
+	__u64			tbytes;	/* total size in bytes */
+	__u64			fbytes;	/* # of free bytes */
+	__u64			abytes;	/* # of bytes available to user */
+	__u64			tfiles;	/* # of files */
+	__u64			ffiles;	/* # of free files */
+	__u64			afiles;	/* # of files available to user */
+	__u32			linkmax;/* max # of hard links */
+	__u32			namelen;/* max name length */
 };
 
-struct nfs_diropargs {
-	struct nfs_fh *		fh;
-	const char *		name;
-};
+/* Arguments to the read call.
+ * Note that NFS_READ_MAXIOV must be <= (MAX_IOVEC-2) from sunrpc/xprt.h
+ */
+#define NFS_READ_MAXIOV 8
 
 struct nfs_readargs {
 	struct nfs_fh *		fh;
 	__u64			offset;
 	__u32			count;
-	void *			buffer;
-};
-
-struct nfs_createargs {
-	struct nfs_fh *		fh;
-	const char *		name;
-	struct nfs_sattr *	sattr;
-};
-
-struct nfs_renameargs {
-	struct nfs_fh *		fromfh;
-	const char *		fromname;
-	struct nfs_fh *		tofh;
-	const char *		toname;
+	unsigned int            nriov;
+	struct iovec            iov[NFS_READ_MAXIOV];
 };
 
-struct nfs_linkargs {
-	struct nfs_fh *		fromfh;
-	struct nfs_fh *		tofh;
-	const char *		toname;
+struct nfs_readres {
+	struct nfs_fattr *	fattr;
+	unsigned int		count;
+	int                     eof;
 };
 
-struct nfs_symlinkargs {
-	struct nfs_fh *		fromfh;
-	const char *		fromname;
-	const char *		topath;
-	struct nfs_sattr *	sattr;
-};
+/* Arguments to the write call.
+ * Note that NFS_WRITE_MAXIOV must be <= (MAX_IOVEC-2) from sunrpc/xprt.h
+ */
+#define NFS_WRITE_MAXIOV        8
 
-struct nfs_readdirargs {
-	struct nfs_fh *		fh;
-	__u32			cookie;
-	void *			buffer;
-	unsigned int		bufsiz;
-};
+enum nfs3_stable_how {
+                  NFS_UNSTABLE = 0,
+                  NFS_DATA_SYNC = 1,
+                  NFS_FILE_SYNC = 2
+              };
 
-struct nfs_diropok {
+struct nfs_writeargs {
 	struct nfs_fh *		fh;
-	struct nfs_fattr *	fattr;
+	__u64			offset;
+	__u32			count;
+	enum nfs3_stable_how	stable;
+	unsigned int		nriov;
+	struct iovec		iov[NFS_WRITE_MAXIOV];
 };
 
-struct nfs_readres {
-	struct nfs_fattr *	fattr;
-	unsigned int		count;
+struct nfs_writeverf {
+	enum nfs3_stable_how	committed;
+	__u32			verifier[2];
 };
 
-struct nfs_readlinkres {
-	char **			string;
-	unsigned int *		lenp;
-	unsigned int		maxlen;
-	void *			buffer;
+struct nfs_writeres {
+        struct nfs_fattr *      fattr;
+        struct nfs_writeverf *  verf;
+        __u32                   count;
 };
 
-struct nfs_readdirres {
-	void *			buffer;
-	unsigned int		bufsiz;
-};
+#endif /* __KERNEL__ || NFS_NEED_KERNEL_TYPES */
 
-#endif /* NFS_NEED_XDR_TYPES */
-#endif /* __KERNEL__ */
 
 #endif
Index: oldkernel/linux/include/linux/nfs2.h
diff -u /dev/null linux/include/linux/nfs2.h:1.1
--- /dev/null	Mon Jul 31 21:15:09 2000
+++ linux/include/linux/nfs2.h	Fri Jul  7 16:18:17 2000
@@ -0,0 +1,153 @@
+/*
+ * NFS protocol definitions
+ *
+ * This file contains constants for Version 2 of the protocol.
+ */
+#ifndef _LINUX_NFS2_H
+#define _LINUX_NFS2_H
+
+#define NFS2_PORT	2049
+#define NFS2_MAXDATA	8192
+#define NFS2_MAXPATHLEN	1024
+#define NFS2_MAXNAMLEN	255
+#define NFS2_MAXGROUPS	16
+#define NFS2_FHSIZE	32
+#define NFS2_COOKIESIZE	4
+#define NFS2_FIFO_DEV	(-1)
+#define NFS2MODE_FMT	0170000
+#define NFS2MODE_DIR	0040000
+#define NFS2MODE_CHR	0020000
+#define NFS2MODE_BLK	0060000
+#define NFS2MODE_REG	0100000
+#define NFS2MODE_LNK	0120000
+#define NFS2MODE_SOCK	0140000
+#define NFS2MODE_FIFO	0010000
+
+	
+
+
+/* NFSv2 file types - beware, these are not the same in NFSv3 */
+enum nfs2_ftype {
+	NF2NON = 0,
+	NF2REG = 1,
+	NF2DIR = 2,
+	NF2BLK = 3,
+	NF2CHR = 4,
+	NF2LNK = 5,
+	NF2SOCK = 6,
+	NF2BAD = 7,
+	NF2FIFO = 8
+};
+
+struct nfs2_fh {
+	char			data[NFS2_FHSIZE];
+};
+
+/*
+ * Procedure numbers for NFSv2
+ */
+#define NFS2_VERSION		2
+#define NFSPROC_NULL		0
+#define NFSPROC_GETATTR		1
+#define NFSPROC_SETATTR		2
+#define NFSPROC_ROOT		3
+#define NFSPROC_LOOKUP		4
+#define NFSPROC_READLINK	5
+#define NFSPROC_READ		6
+#define NFSPROC_WRITECACHE	7
+#define NFSPROC_WRITE		8
+#define NFSPROC_CREATE		9
+#define NFSPROC_REMOVE		10
+#define NFSPROC_RENAME		11
+#define NFSPROC_LINK		12
+#define NFSPROC_SYMLINK		13
+#define NFSPROC_MKDIR		14
+#define NFSPROC_RMDIR		15
+#define NFSPROC_READDIR		16
+#define NFSPROC_STATFS		17
+
+#define NFS_MNT_PROGRAM		100005
+#define NFS_MNT_VERSION		1
+#define MNTPROC_NULL		0
+#define MNTPROC_MNT		1
+#define MNTPROC_UMNT		3
+#define MNTPROC_UMNTALL		4
+
+/*
+ * The following types are for NFSv2 only.
+ */
+#if (defined(__KERNEL__) || defined (NFS_NEED_KERNEL_TYPES)) && defined(NFS_NEED_NFS2_XDR_TYPES)
+struct nfs_sattrargs {
+	struct nfs_fh *		fh;
+	struct iattr *	        sattr;
+};
+
+struct nfs_diropargs {
+	struct nfs_fh *		fh;
+	const char *		name;
+	int                     len;
+};
+
+
+struct nfs_createargs {
+	struct nfs_fh *		fh;
+	const char *		name;
+	int                     len;
+	struct iattr *	        sattr;
+};
+
+struct nfs_renameargs {
+	struct nfs_fh *		fromfh;
+	const char *		fromname;
+	int                     fromlen;
+	struct nfs_fh *		tofh;
+	const char *		toname;
+	int                     tolen;
+};
+
+struct nfs_linkargs {
+	struct nfs_fh *		fromfh;
+	struct nfs_fh *		tofh;
+	const char *		toname;
+	int                     tolen;
+};
+
+struct nfs_symlinkargs {
+	struct nfs_fh *		fromfh;
+	const char *		fromname;
+	int                     fromlen;
+	const char *		topath;
+	int                     tolen;
+	struct iattr *	        sattr;
+};
+
+struct nfs_readdirargs {
+	struct nfs_fh *		fh;
+	__u32			cookie;
+	void *			buffer;
+	unsigned int		bufsiz;
+};
+
+struct nfs_diropok {
+	struct nfs_fh *		fh;
+	struct nfs_fattr *	fattr;
+};
+
+struct nfs_readlinkargs {
+	struct nfs_fh *		fh;
+	void *			buffer;
+	unsigned int		bufsiz;
+};
+
+struct nfs_readlinkres {
+	void *			buffer;
+	unsigned int		bufsiz;
+};
+
+struct nfs_readdirres {
+	void *			buffer;
+	unsigned int		bufsiz;
+};
+#endif /* NFS_NEED_NFS2_XDR_TYPES */
+
+#endif
Index: oldkernel/linux/include/linux/nfs3.h
diff -u linux/include/linux/nfs3.h:1.1.1.1 linux/include/linux/nfs3.h:1.2
--- linux/include/linux/nfs3.h:1.1.1.1	Wed May 31 12:33:49 2000
+++ linux/include/linux/nfs3.h	Fri Jul  7 15:36:48 2000
@@ -4,15 +4,12 @@
 #ifndef _LINUX_NFS3_H
 #define _LINUX_NFS3_H
 
-#include <linux/sunrpc/msg_prot.h>
-#include <linux/nfs.h>
-
 #define NFS3_PORT		2049
-#define NFS3_MAXDATA		8192
+#define NFS3_MAXDATA		32768
 #define NFS3_MAXPATHLEN		PATH_MAX
 #define NFS3_MAXNAMLEN		NAME_MAX
 #define NFS3_MAXGROUPS		16
-#define NFS3_FHSIZE		NFS_FHSIZE
+#define NFS3_FHSIZE		64
 #define NFS3_COOKIESIZE		4
 #define NFS3_FIFO_DEV		(-1)
 #define NFS3MODE_FMT		0170000
@@ -24,39 +21,30 @@
 #define NFS3MODE_SOCK		0140000
 #define NFS3MODE_FIFO		0010000
 
-	
-enum nfs3_stat {
-	NFS3_OK			= 0,
-	NFS3ERR_PERM		= 1,
-	NFS3ERR_NOENT		= 2,
-	NFS3ERR_IO		= 5,
-	NFS3ERR_NXIO		= 6,
-	NFS3ERR_EAGAIN		= 11,
-	NFS3ERR_ACCES		= 13,
-	NFS3ERR_EXIST		= 17,
-	NFS3ERR_XDEV		= 18,	/* new in NFSv3 */
-	NFS3ERR_NODEV		= 19,
-	NFS3ERR_NOTDIR		= 20,
-	NFS3ERR_ISDIR		= 21,
-	NFS3ERR_INVAL		= 22,	/* new in NFSv3 */
-	NFS3ERR_FBIG		= 27,
-	NFS3ERR_NOSPC		= 28,
-	NFS3ERR_ROFS		= 30,
-	NFS3ERR_MLINK		= 31,	/* new in NFSv3 */
-	NFS3ERR_NAMETOOLONG	= 63,
-	NFS3ERR_NOTEMPTY	= 66,
-	NFS3ERR_DQUOT		= 69,
-	NFS3ERR_STALE		= 70,
-	NFS3ERR_REMOTE		= 71,	/* new in NFSv3 */
-	NFS3ERR_BADHANDLE	= 10001,/* ditto */
-	NFS3ERR_NOT_SYNC	= 10002,/* ditto */
-	NFS3ERR_BAD_COOKIE	= 10003,/* ditto */
-	NFS3ERR_NOTSUPP		= 10004,/* ditto */
-	NFS3ERR_TOOSMALL	= 10005,/* ditto */
-	NFS3ERR_SERVERFAULT	= 10006,/* ditto */
-	NFS3ERR_BADTYPE		= 10007,/* ditto */
-	NFS3ERR_JUKEBOX		= 10008,/* ditto */
-};
+/* Flags for access() call */
+#define NFS3_ACCESS_READ	0x0001
+#define NFS3_ACCESS_LOOKUP	0x0002
+#define NFS3_ACCESS_MODIFY	0x0004
+#define NFS3_ACCESS_EXTEND	0x0008
+#define NFS3_ACCESS_DELETE	0x0010
+#define NFS3_ACCESS_EXECUTE	0x0020
+
+/* Flags for create mode */
+enum nfs3_createmode {
+	NFS3_CREATE_UNCHECKED = 0,
+	NFS3_CREATE_GUARDED = 1,
+	NFS3_CREATE_EXCLUSIVE =	2
+};
+
+/* NFSv3 file system properties */
+#define NFS3_FSF_LINK		0x0001
+#define NFS3_FSF_SYMLINK	0x0002
+#define NFS3_FSF_HOMOGENEOUS	0x0008
+#define NFS3_FSF_CANSETTIME	0x0010
+/* Some shorthands. See fs/nfsd/nfs3proc.c */
+#define NFS3_FSF_DEFAULT	0x001B
+#define NFS3_FSF_BILLYBOY	0x0018
+#define NFS3_FSF_READONLY	0x0008
 
 enum nfs3_ftype {
 	NF3NON  = 0,
@@ -71,182 +59,164 @@
 };
 
 #define NFS3_VERSION		3
-#define NFSPROC_NULL		0
-#define NFSPROC_GETATTR		1
-#define NFSPROC_SETATTR		2
-#define NFSPROC_ROOT		3
-#define NFSPROC_LOOKUP		4
-#define NFSPROC_READLINK	5
-#define NFSPROC_READ		6
-#define NFSPROC_WRITECACHE	7
-#define NFSPROC_WRITE		8
-#define NFSPROC_CREATE		9
-#define NFSPROC_REMOVE		10
-#define NFSPROC_RENAME		11
-#define NFSPROC_LINK		12
-#define NFSPROC_SYMLINK		13
-#define NFSPROC_MKDIR		14
-#define NFSPROC_RMDIR		15
-#define NFSPROC_READDIR		16
-#define NFSPROC_STATFS		17
+#define NFS3PROC_NULL		0
+#define NFS3PROC_GETATTR	1
+#define NFS3PROC_SETATTR	2
+#define NFS3PROC_LOOKUP		3
+#define NFS3PROC_ACCESS		4
+#define NFS3PROC_READLINK	5
+#define NFS3PROC_READ		6
+#define NFS3PROC_WRITE		7
+#define NFS3PROC_CREATE		8
+#define NFS3PROC_MKDIR		9
+#define NFS3PROC_SYMLINK	10
+#define NFS3PROC_MKNOD		11
+#define NFS3PROC_REMOVE		12
+#define NFS3PROC_RMDIR		13
+#define NFS3PROC_RENAME		14
+#define NFS3PROC_LINK		15
+#define NFS3PROC_READDIR	16
+#define NFS3PROC_READDIRPLUS	17
+#define NFS3PROC_FSSTAT		18
+#define NFS3PROC_FSINFO		19
+#define NFS3PROC_PATHCONF	20
+#define NFS3PROC_COMMIT		21
+
+#define NFS_MNT3_PROGRAM	100005
+#define NFS_MNT3_VERSION	3
+#define MOUNTPROC3_NULL		0
+#define MOUNTPROC3_MNT		1
+#define MOUNTPROC3_UMNT		3
+#define MOUNTPROC3_UMNTALL	4
+ 
 
 #if defined(__KERNEL__) || defined(NFS_NEED_KERNEL_TYPES)
-
-struct nfs3_fh {
-	__u32			size;
-	__u8			data[NFS3_FHSIZE];
-};
 
-struct nfs3_fattr {
-	enum nfs3_ftype		type;
-	__u32			mode;
-	__u32			nlink;
-	__u32			uid;
-	__u32			gid;
-	__u64			size;
-	__u64			used;
-	__u32			rdev_maj;
-	__u32			rdev_min;
-	__u32			fsid;
-	__u32			fileid;
-	struct nfs_time		atime;
-	struct nfs_time		mtime;
-	struct nfs_time		ctime;
-};
-
-struct nfs3_wcc_attr {
-	__u64			size;
-	struct nfs_time		mtime;
-	struct nfs_time		ctime;
-};
-
-struct nfs3_wcc_data {
-	struct nfs3_wcc_attr	before;
-	struct nfs3_wcc_attr	after;
-};
-
-struct nfs3_sattr {
-	__u32			valid;
-	__u32			mode;
-	__u32			uid;
-	__u32			gid;
-	__u64			size;
-	struct nfs_time		atime;
-	struct nfs_time		mtime;
-};
-
-struct nfs3_entry {
-	__u32			fileid;
-	char *			name;
-	unsigned int		length;
-	__u32			cookie;
-	__u32			eof;
-};
-
-struct nfs3_fsinfo {
-	__u32			tsize;
-	__u32			bsize;
-	__u32			blocks;
-	__u32			bfree;
-	__u32			bavail;
-};
+/* Number of 32bit words in post_op_attr */
+#define NFS3_POST_OP_ATTR_WORDS		22
 
-#ifdef NFS_NEED_XDR_TYPES
+#ifdef NFS_NEED_NFS3_XDR_TYPES
 
 struct nfs3_sattrargs {
 	struct nfs_fh *		fh;
-	struct nfs_sattr *	sattr;
+	struct iattr *		sattr;
+	unsigned int		guard;
+	__u64			guardtime;
 };
 
 struct nfs3_diropargs {
 	struct nfs_fh *		fh;
 	const char *		name;
+	int			len;
 };
 
-struct nfs3_readargs {
+struct nfs3_accessargs {
 	struct nfs_fh *		fh;
-	__u32			offset;
-	__u32			count;
-	void *			buffer;
+	__u32			access;
 };
 
-struct nfs3_writeargs {
+struct nfs3_createargs {
 	struct nfs_fh *		fh;
-	__u32			offset;
-	__u32			count;
-	const void *		buffer;
+	const char *		name;
+	int			len;
+	struct iattr *		sattr;
+	enum nfs3_createmode	createmode;
+	__u32			verifier[2];
 };
 
-struct nfs3_createargs {
+struct nfs3_mkdirargs {
 	struct nfs_fh *		fh;
 	const char *		name;
-	struct nfs_sattr *	sattr;
+	int			len;
+	struct iattr *		sattr;
+};
+
+struct nfs3_symlinkargs {
+	struct nfs_fh *		fromfh;
+	const char *		fromname;
+	int			fromlen;
+	const char *		topath;
+	int			tolen;
+	struct iattr *		sattr;
+};
+
+struct nfs3_mknodargs {
+	struct nfs_fh *		fh;
+	const char *		name;
+	int			len;
+	enum nfs3_ftype		type;
+	struct iattr *		sattr;
+	dev_t			rdev;
 };
 
 struct nfs3_renameargs {
 	struct nfs_fh *		fromfh;
 	const char *		fromname;
+	int			fromlen;
 	struct nfs_fh *		tofh;
 	const char *		toname;
+	int			tolen;
 };
 
 struct nfs3_linkargs {
 	struct nfs_fh *		fromfh;
 	struct nfs_fh *		tofh;
 	const char *		toname;
+	int			tolen;
 };
 
-struct nfs3_symlinkargs {
-	struct nfs_fh *		fromfh;
-	const char *		fromname;
-	const char *		topath;
-	struct nfs_sattr *	sattr;
-};
-
 struct nfs3_readdirargs {
 	struct nfs_fh *		fh;
-	__u32			cookie;
+	__u64			cookie;
+	__u32			verf[2];
 	void *			buffer;
 	unsigned int		bufsiz;
+	int			plus;
 };
 
-struct nfs3_diropok {
+struct nfs3_diropres {
+	struct nfs_fattr *	dir_attr;
 	struct nfs_fh *		fh;
 	struct nfs_fattr *	fattr;
 };
 
-struct nfs3_readres {
+struct nfs3_accessres {
 	struct nfs_fattr *	fattr;
-	unsigned int		count;
+	__u32			access;
 };
 
-struct nfs3_readlinkres {
-	char **			string;
-	unsigned int *		lenp;
-	unsigned int		maxlen;
+struct nfs3_readlinkargs {
+	struct nfs_fh *		fh;
 	void *			buffer;
+	unsigned int		bufsiz;
 };
 
-struct nfs3_readdirres {
+struct nfs3_readlinkres {
+	struct nfs_fattr *	fattr;
 	void *			buffer;
 	unsigned int		bufsiz;
 };
 
-/*
- * The following are for NFSv3
- */
-struct nfs3_fh {
-	__u32			size;
-	__u8			data[NFS3_FHSIZE]
+struct nfs3_renameres {
+	struct nfs_fattr *	fromattr;
+	struct nfs_fattr *	toattr;
 };
 
-struct nfs3_wcc_attr {
-	__u64			size;
-	struct nfs_time		mtime;
-	struct nfs_time		ctime;
+struct nfs3_linkres {
+	struct nfs_fattr *	dir_attr;
+	struct nfs_fattr *	fattr;
+};
+
+struct nfs3_readdirres {
+	struct nfs_fattr *	dir_attr;
+	__u32 *			verf;
+	void *			buffer;
+	unsigned int		bufsiz;
+	int			plus;
 };
 
 #endif /* NFS_NEED_XDR_TYPES */
-#endif /* __KERNEL__ */
 
-#endif
+
+#endif /* __KERNEL__ */
+#endif /* _LINUX_NFS3_H */
Index: oldkernel/linux/include/linux/nfs_flushd.h
diff -u /dev/null linux/include/linux/nfs_flushd.h:1.1
--- /dev/null	Mon Jul 31 21:15:09 2000
+++ linux/include/linux/nfs_flushd.h	Fri Jul  7 16:18:17 2000
@@ -0,0 +1,64 @@
+#ifndef NFS_CLUSTER_H
+#define NFS_CLUSTER_H
+
+
+
+#ifdef __KERNEL__
+#include <linux/nfs_fs_sb.h>
+
+/*
+ * Counters of total number and pending number of requests.
+ * When the total number of requests exceeds the soft limit, we start
+ * flushing out requests. If it exceeds the hard limit, we stall until
+ * it drops again.
+ */
+#define MAX_REQUEST_SOFT        192
+#define MAX_REQUEST_HARD        256
+
+/*
+ * Maximum number of requests per write cluster.
+ * 32 requests per cluster account for 128K of data on an intel box.
+ * Note: it's a good idea to make this number smaller than MAX_REQUEST_SOFT.
+ *
+ * For 100Mbps Ethernet, 128 pages (i.e. 256K) per cluster gives much
+ * better performance.
+ */
+#define REQUEST_HASH_SIZE	16
+#define REQUEST_NR(off)		((off) >> PAGE_CACHE_SHIFT)
+#define REQUEST_HASH(ino, off)	(((ino) ^ REQUEST_NR(off)) & (REQUEST_HASH_SIZE - 1))
+
+
+/*
+ * Functions
+ */
+extern int		nfs_reqlist_alloc(struct nfs_server *);
+extern void		nfs_reqlist_free(struct nfs_server *);
+extern int		nfs_reqlist_init(struct nfs_server *);
+extern void		nfs_reqlist_exit(struct nfs_server *);
+extern void		inode_schedule_scan(struct inode *, unsigned long);
+extern void		inode_remove_flushd(struct inode *);
+extern void		nfs_wake_flushd(void);
+
+/*
+ * This is the per-mount writeback cache.
+ */
+struct nfs_reqlist {
+	unsigned int		nr_requests;
+	unsigned long		runat;
+	struct wait_queue	*request_wait;
+
+	/* The async RPC task that is responsible for scanning the
+	 * requests.
+	 */
+	struct rpc_task		*task;		/* request flush task */
+
+	/* Authentication flavor handle for this NFS client */
+	struct rpc_auth		*auth;
+
+	/* The list of all inodes with pending writebacks.  */
+	struct inode		*inodes;
+};
+
+#endif
+
+#endif
Index: oldkernel/linux/include/linux/nfs_fs.h
diff -u linux/include/linux/nfs_fs.h:1.2 linux/include/linux/nfs_fs.h:1.3
--- linux/include/linux/nfs_fs.h:1.2	Thu Jun  1 15:03:09 2000
+++ linux/include/linux/nfs_fs.h	Fri Jul  7 15:36:48 2000
@@ -9,13 +9,18 @@
 #ifndef _LINUX_NFS_FS_H
 #define _LINUX_NFS_FS_H
 
+#ifdef __KERNEL__
 #include <linux/signal.h>
 #include <linux/sched.h>
+#include <linux/kernel.h>
 #include <linux/in.h>
+#include <linux/mm.h>
+#include <linux/pagemap.h>
 
 #include <linux/sunrpc/sched.h>
+#endif /* __KERNEL__ */
+
 #include <linux/nfs.h>
-#include <linux/nfs_mount.h>
 
 /*
  * Enable debugging support for nfs client.
@@ -25,48 +30,46 @@
 # define NFS_DEBUG
 #endif
 
-/*
- * NFS_MAX_DIRCACHE controls the number of simultaneously cached
- * directory chunks. Each chunk holds the list of nfs_entry's returned
- * in a single readdir call in a memory region of size PAGE_SIZE.
- *
- * Note that at most server->rsize bytes of the cache memory are used.
- */
-#define NFS_MAX_DIRCACHE		16
-
-#define NFS_MAX_FILE_IO_BUFFER_SIZE	16384
+#define NFS_MAX_FILE_IO_BUFFER_SIZE	32768
 #define NFS_DEF_FILE_IO_BUFFER_SIZE	4096
 
 /*
  * The upper limit on timeouts for the exponential backoff algorithm.
  */
 #define NFS_MAX_RPC_TIMEOUT		(6*HZ)
-
-/*
- * Size of the lookup cache in units of number of entries cached.
- * It is better not to make this too large although the optimum
- * depends on a usage and environment.
- */
-#define NFS_LOOKUP_CACHE_SIZE		64
+#define NFS_WRITEBACK_DELAY		(5*HZ)
+#define NFS_WRITEBACK_LOCKDELAY		(60*HZ)
+#define NFS_COMMIT_DELAY		(5*HZ)
 
 /*
  * superblock magic number for NFS
  */
 #define NFS_SUPER_MAGIC			0x6969
+#define NFS_DENTRY_MAGIC		0x2439
+#define NFS_FILE_MAGIC			0xA4F0
 
-#define NFS_FH(dentry)			((struct nfs_fh *) ((dentry)->d_fsdata))
+#ifdef __KERNEL__
+/*
+ * Convenience macros
+ */
+#define NFS_FH(dentry)			(&NFS_DENTRY(dentry)->fh)
 #define NFS_DSERVER(dentry)		(&(dentry)->d_sb->u.nfs_sb.s_server)
 #define NFS_SERVER(inode)		(&(inode)->i_sb->u.nfs_sb.s_server)
 #define NFS_CLIENT(inode)		(NFS_SERVER(inode)->client)
+#define NFS_PROTO(inode)		(NFS_SERVER(inode)->rpc_ops)
+#define NFS_REQUESTLIST(inode)		(NFS_SERVER(inode)->rw_requests)
 #define NFS_ADDR(inode)			(RPC_PEERADDR(NFS_CLIENT(inode)))
 #define NFS_CONGESTED(inode)		(RPC_CONGESTED(NFS_CLIENT(inode)))
-
+#define NFS_COOKIEVERF(inode)		((inode)->u.nfs_i.cookieverf)
 #define NFS_READTIME(inode)		((inode)->u.nfs_i.read_cache_jiffies)
-#define NFS_OLDMTIME(inode)		((inode)->u.nfs_i.read_cache_mtime)
+#define NFS_CACHE_CTIME(inode)		((inode)->u.nfs_i.read_cache_ctime)
+#define NFS_CACHE_MTIME(inode)		((inode)->u.nfs_i.read_cache_mtime)
+#define NFS_CACHE_ATIME(inode)		((inode)->u.nfs_i.read_cache_atime)
+#define NFS_CACHE_ISIZE(inode)		((inode)->u.nfs_i.read_cache_isize)
+#define NFS_NEXTSCAN(inode)		((inode)->u.nfs_i.nextscan)
 #define NFS_CACHEINV(inode) \
 do { \
-	NFS_READTIME(inode) = jiffies - 1000000; \
-	NFS_OLDMTIME(inode) = 0; \
+	NFS_READTIME(inode) = jiffies - NFS_MAXATTRTIMEO(inode) - 1; \
 } while (0)
 #define NFS_ATTRTIMEO(inode)		((inode)->u.nfs_i.attrtimeo)
 #define NFS_MINATTRTIMEO(inode) \
@@ -75,11 +78,22 @@
 #define NFS_MAXATTRTIMEO(inode) \
 	(S_ISDIR(inode->i_mode)? NFS_SERVER(inode)->acdirmax \
 			       : NFS_SERVER(inode)->acregmax)
+#define NFS_ATTRTIMEO_UPDATE(inode)	((inode)->u.nfs_i.attrtimeo_timestamp)
 
 #define NFS_FLAGS(inode)		((inode)->u.nfs_i.flags)
-#define NFS_REVALIDATING(inode)		(NFS_FLAGS(inode) & NFS_INO_REVALIDATE)
-#define NFS_WRITEBACK(inode)		((inode)->u.nfs_i.writeback)
+#define NFS_REVALIDATING(inode)		(NFS_FLAGS(inode) & NFS_INO_REVALIDATING)
+
+#define NFS_FILEID(inode)	((inode)->u.nfs_i.fileid)
+#define NFS_FSID(inode)		((inode)->u.nfs_i.fsid)
 
+#define NFS_FILE(file)		((struct nfs_file *)(file)->private_data)
+#define NFS_DENTRY(dentry)	((struct nfs_dentry*)(dentry)->d_fsdata)
+
+
+/* Inode Flags */
+#define NFS_USE_READDIRPLUS(inode)	((NFS_FLAGS(inode) & NFS_INO_ADVISE_RDPLUS) ? 1 : 0)
+#define NFS_MONOTONE_COOKIES(inode)	((NFS_SERVER(inode)->flags & NFS_NONMONOTONE_COOKIES) ? 0 : 1)
+
 /*
  * These are the default flags for swap requests
  */
@@ -88,117 +102,188 @@
 /* Flags in the RPC client structure */
 #define NFS_CLNTF_BUFSIZE	0x0001	/* readdir buffer in longwords */
 
-#ifdef __KERNEL__
+#define NFS_RW_SYNC		0x0001	/* O_SYNC handling */
+#define NFS_RW_SWAP		0x0002	/* This is a swap request */
+
+/*
+ * When flushing a cluster of dirty pages, there can be different
+ * strategies:
+ */
+#define FLUSH_AGING		0	/* only flush old buffers */
+#define FLUSH_SYNC		1	/* file being synced, or contention */
+#define FLUSH_WAIT		2	/* wait for completion */
+#define FLUSH_STABLE		4	/* commit to stable storage */
+
+
+/*
+ * Structure for dentry->d_fsdata;
+ */
+struct nfs_dentry {
+	unsigned long		magic;		/* Magic number */
+	struct nfs_fh		fh;		/* File handle */
+	struct rpc_cred*	cred;		/* RPC Credentials */
+};
+
+static inline int
+nfs_check_dentry(struct dentry *dentry)
+{
+	if (NFS_DENTRY(dentry)->magic != NFS_DENTRY_MAGIC) {
+		printk(KERN_ERR "NFS: corrupt dentry structure!\n");
+		return 0;
+	}
+	return 1;
+}
 
 /*
- * This struct describes a file region to be written.
- * It's kind of a pity we have to keep all these lists ourselves, rather
- * than sticking an extra pointer into struct page.
- */
-struct nfs_wreq {
-	struct rpc_listitem	wb_list;	/* linked list of req's */
-	struct rpc_task		wb_task;	/* RPC task */
-	struct file *		wb_file;	/* dentry referenced */
-	struct page *		wb_page;	/* page to be written */
-	struct wait_queue *	wb_wait;	/* wait for completion */
-	unsigned int		wb_offset;	/* offset within page */
-	unsigned int		wb_bytes;	/* dirty range */
-	unsigned int		wb_count;	/* user count */
-	int			wb_status;
-	pid_t			wb_pid;		/* owner process */
-	unsigned short		wb_flags;	/* status flags */
+ * Structure for file->private_data;
+ */
+struct nfs_file {
+	unsigned long		magic;		/* Magic number */
+	struct rpc_cred*	cred;		/* RPC Credentials */
+};
+
+static inline int
+nfs_check_file(struct file *file)
+{
+	if (NFS_FILE(file)->magic != NFS_FILE_MAGIC) {
+		printk(KERN_ERR "NFS: corrupt file structure!\n");
+		return 0;
+	}
+	return 1;
+}
+
+static inline
+unsigned long page_offset(struct page *page)
+{
+        return page->offset;
+}
 
-	struct nfs_writeargs	wb_args;	/* NFS RPC stuff */
-	struct nfs_fattr	wb_fattr;	/* file attributes */
+static inline
+unsigned long page_index(struct page *page)
+{
+	return page->offset >> PAGE_CACHE_SHIFT;
+}
+
+/*
+ * Argument struct for decode_entry function
+ */
+struct nfs_entry {
+	struct page *		page;
+	__u64			ino;
+	__u64			cookie,
+				prev_cookie;
+	const char *		name;
+	unsigned int		len;
+	int			eof;
+	struct nfs_fh		fh;
+	struct nfs_fattr	fattr;
+	unsigned long		offset,
+				prev;
 };
 
-#define WB_NEXT(req)		((struct nfs_wreq *) ((req)->wb_list.next))
+/*
+ * RPC procedure vector for NFSv2/NFSv3 demuxing
+ */
+struct nfs_rpc_ops {
+	int	version;		/* Protocol version */
 
+	int	(*getroot)(struct nfs_server *,
+			struct nfs_fh *, struct nfs_fattr *);
+	int	(*getattr)(struct dentry *, struct nfs_fattr *);
+	int	(*setattr)(struct dentry *, struct nfs_fattr *, struct iattr *);
+	int	(*lookup)(struct dentry *, struct nfs_fattr *, struct qstr *,
+			struct nfs_fh *, struct nfs_fattr *);
+	int	(*access)(struct dentry *, int fmode, struct nfs_fattr *, int);
+	int	(*readlink)(struct dentry *, struct nfs_fattr *,
+			void *buffer, unsigned int buflen);
+	int	(*read)(struct dentry *, struct nfs_fattr *,
+			struct rpc_cred *,
+			int flags, unsigned long offset,
+			unsigned int count, void *buffer, int *eofp);
+	int	(*write)(struct dentry *, struct nfs_fattr *,
+			struct rpc_cred *,
+			int flags, unsigned long offset,
+			unsigned int count, void *buffer,
+			struct nfs_writeverf *verfp);
+	int	(*commit)(struct dentry *, struct nfs_fattr *,
+			struct rpc_cred *,
+			unsigned long, unsigned int);
+	int	(*create)(struct dentry *, struct nfs_fattr *,
+			struct qstr *, struct iattr *, int flags,
+			struct nfs_fh *, struct nfs_fattr *);
+	int	(*remove)(struct dentry *, struct nfs_fattr *,
+			  struct qstr *, struct rpc_cred *);
+	int	(*rename)(struct dentry *, struct nfs_fattr *, struct qstr *,
+			struct dentry *, struct nfs_fattr *, struct qstr *);
+	int	(*link)(struct dentry *, struct nfs_fattr *,
+			struct dentry *, struct nfs_fattr *, struct qstr *);
+	int	(*symlink)(struct dentry *, struct nfs_fattr *, struct qstr *,
+			struct qstr *, struct iattr *,
+			struct nfs_fh *, struct nfs_fattr *);
+	int	(*mkdir)(struct dentry *, struct nfs_fattr *, struct qstr *,
+			struct iattr *, struct nfs_fh *, struct nfs_fattr *);
+	int	(*rmdir)(struct dentry *, struct nfs_fattr *, struct qstr *);
+	int	(*readdir)(struct dentry *, struct nfs_fattr *,
+			struct rpc_cred *,
+			u64 cookie, void *, unsigned int size, int plus);
+	int	(*mknod)(struct dentry *, struct nfs_fattr *, struct qstr *,
+			struct iattr *, dev_t,
+			struct nfs_fh *, struct nfs_fattr *);
+	int	(*statfs)(struct nfs_server *, struct nfs_fh *,
+			struct nfs_fsinfo *);
+	u32 *	(*decode_dirent)(u32 *, struct nfs_entry *, int plus);
+};
+
 /*
- * Various flags for wb_flags
+ * 	NFS_CALL(getattr, inode, (fattr));
+ * into
+ *	NFS_PROTO(inode)->getattr(fattr);
  */
-#define NFS_WRITE_CANCELLED	0x0004	/* has been cancelled */
-#define NFS_WRITE_UNCOMMITTED	0x0008	/* written but uncommitted (NFSv3) */
-#define NFS_WRITE_INVALIDATE	0x0010	/* invalidate after write */
-#define NFS_WRITE_INPROGRESS	0x0100	/* RPC call in progress */
-#define NFS_WRITE_COMPLETE	0x0200	/* RPC call completed */
-
-#define WB_CANCELLED(req)	((req)->wb_flags & NFS_WRITE_CANCELLED)
-#define WB_UNCOMMITTED(req)	((req)->wb_flags & NFS_WRITE_UNCOMMITTED)
-#define WB_INVALIDATE(req)	((req)->wb_flags & NFS_WRITE_INVALIDATE)
-#define WB_INPROGRESS(req)	((req)->wb_flags & NFS_WRITE_INPROGRESS)
-#define WB_COMPLETE(req)	((req)->wb_flags & NFS_WRITE_COMPLETE)
-
-/*
- * linux/fs/nfs/proc.c
- */
-extern int nfs_proc_getattr(struct nfs_server *server, struct nfs_fh *fhandle,
-			struct nfs_fattr *fattr);
-extern int nfs_proc_setattr(struct nfs_server *server, struct nfs_fh *fhandle,
-			struct nfs_sattr *sattr, struct nfs_fattr *fattr);
-extern int nfs_proc_lookup(struct nfs_server *server, struct nfs_fh *dir,
-			const char *name, struct nfs_fh *fhandle,
-			struct nfs_fattr *fattr);
-extern int nfs_proc_readlink(struct nfs_server *server, struct nfs_fh *fhandle,
-			void **p0, char **string, unsigned int *len,
-			unsigned int maxlen);
-extern int nfs_proc_read(struct nfs_server *server, struct nfs_fh *fhandle,
-			int swap, loff_t offset, unsigned int count,
-			void *buffer, struct nfs_fattr *fattr);
-extern int nfs_proc_write(struct nfs_server *server, struct nfs_fh *fhandle,
-			int swap, loff_t offset, unsigned int count,
-			const void *buffer, struct nfs_fattr *fattr);
-extern int nfs_proc_create(struct nfs_server *server, struct nfs_fh *dir,
-			const char *name, struct nfs_sattr *sattr,
-			struct nfs_fh *fhandle, struct nfs_fattr *fattr);
-extern int nfs_proc_remove(struct nfs_server *server, struct nfs_fh *dir,
-			const char *name);
-extern int nfs_proc_rename(struct nfs_server *server,
-			struct nfs_fh *old_dir, const char *old_name,
-			struct nfs_fh *new_dir, const char *new_name);
-extern int nfs_proc_link(struct nfs_server *server, struct nfs_fh *fhandle,
-			struct nfs_fh *dir, const char *name);
-extern int nfs_proc_symlink(struct nfs_server *server, struct nfs_fh *dir,
-			const char *name, const char *path,
-			struct nfs_sattr *sattr);
-extern int nfs_proc_mkdir(struct nfs_server *server, struct nfs_fh *dir,
-			const char *name, struct nfs_sattr *sattr,
-			struct nfs_fh *fhandle, struct nfs_fattr *fattr);
-extern int nfs_proc_rmdir(struct nfs_server *server, struct nfs_fh *dir,
-			const char *name);
-extern int nfs_proc_readdir(struct nfs_server *server, struct nfs_fh *fhandle,
-			u32 cookie, unsigned int size, __u32 *entry);
-extern int nfs_proc_statfs(struct nfs_server *server, struct nfs_fh *fhandle,
-			struct nfs_fsinfo *res);
+#define NFS_CALL(op, inode, args)	NFS_PROTO(inode)->op args
+
 
+/*
+ * Function vectors etc. for the NFS client
+ */
+extern struct nfs_rpc_ops	nfs_v2_clientops;
+extern struct nfs_rpc_ops	nfs_v3_clientops;
+extern struct rpc_version	nfs_version2;
+extern struct rpc_version	nfs_version3;
+extern struct rpc_program	nfs_program;
 
 /*
  * linux/fs/nfs/inode.c
  */
-extern struct super_block *nfs_read_super(struct super_block *, void *, int);
-extern int init_nfs_fs(void);
 extern struct inode *nfs_fhget(struct dentry *, struct nfs_fh *,
-				struct nfs_fattr *);
-extern int nfs_refresh_inode(struct inode *, struct nfs_fattr *);
-extern int nfs_revalidate(struct dentry *);
-extern int nfs_open(struct inode *, struct file *);
-extern int nfs_release(struct inode *, struct file *);
-extern int _nfs_revalidate_inode(struct nfs_server *, struct dentry *);
+			       struct nfs_fattr *);
+extern struct super_block *nfs_read_super(struct super_block *, void *, int);
+extern int	init_nfs_fs(void);
+extern void	nfs_zap_caches(struct inode *);
+extern int	nfs_revalidate(struct dentry *);
+extern int	nfs_open(struct inode *, struct file *);
+extern int	nfs_release(struct inode *, struct file *);
+extern int	__nfs_revalidate_inode(struct dentry *);
+extern int	nfs_refresh_inode(struct inode *, struct nfs_fattr *);
+extern int	nfs_wait_on_inode(struct inode *, int flag);
+extern void	nfs_unlock_inode(struct inode *);
+extern int	nfs_update_atime(struct dentry *);
+
 
 /*
  * linux/fs/nfs/file.c
  */
 extern struct inode_operations nfs_file_inode_operations;
+extern int	nfs_permission(struct inode *i, int msk);
 
 /*
  * linux/fs/nfs/dir.c
  */
 extern struct inode_operations nfs_dir_inode_operations;
 extern struct dentry_operations nfs_dentry_operations;
-extern void nfs_free_dircache(void);
-extern void nfs_invalidate_dircache(struct inode *);
-extern void nfs_invalidate_dircache_sb(struct super_block *);
+extern struct nfs_dentry *nfs_fh_alloc(void);
+extern void nfs_fh_free(struct nfs_dentry *);
 
+
 /*
  * linux/fs/nfs/symlink.c
  */
@@ -212,51 +297,163 @@
 /*
  * linux/fs/nfs/write.c
  */
+extern struct nfs_page*	nfs_find_request(struct inode *, struct page *);
+extern void nfs_release_request(struct nfs_page *req);
 extern int  nfs_writepage(struct file *, struct page *);
-extern int  nfs_check_failed_request(struct inode *);
-
+extern int  nfs_updatepage(struct file *, struct page *, const char *,
+                        unsigned long, unsigned int, int);
 /*
  * Try to write back everything synchronously (but check the
  * return value!)
  */
-extern int  nfs_wb_all(struct inode *);
-extern int  nfs_wb_page(struct inode *, struct page *);
-extern int  nfs_wb_file(struct inode *, struct file *);
+extern int  nfs_sync_file(struct inode *, struct file *, unsigned long, unsigned int, int);
+extern int  nfs_flush_file(struct inode *, struct file *, unsigned long, unsigned int, int);
+extern int  nfs_commit_file(struct inode *, struct file *, unsigned long, unsigned int, int);
+extern int  nfs_flush_timeout(struct inode *, int);
+extern int  nfs_commit_timeout(struct inode *, int);
+
+static inline int
+nfs_have_writebacks(struct inode *inode)
+{
+	return !list_empty(&inode->u.nfs_i.writeback);
+}
 
+static inline int
+nfs_wb_all(struct inode *inode)
+{
+	int error = nfs_sync_file(inode, 0, 0, 0, FLUSH_WAIT);
+	return (error < 0) ? error : 0;
+}
+
 /*
- * Invalidate write-backs, possibly trying to write them
- * back first..
+ * Write back all requests on one page - we do this before reading it.
  */
-extern void nfs_inval(struct inode *);
-extern int  nfs_updatepage(struct file *, struct page *, unsigned long, unsigned int, int);
+static inline int
+nfs_wb_page(struct inode *inode, struct page* page)
+{
+	int error = nfs_sync_file(inode, 0, page_index(page), 1, FLUSH_WAIT | FLUSH_STABLE);
+	return (error < 0) ? error : 0;
+}
+
+/*
+ * Write back all pending writes for one user.. 
+ */
+static inline int
+nfs_wb_file(struct inode *inode, struct file *file)
+{
+	int error = nfs_sync_file(inode, file, 0, 0, FLUSH_WAIT);
+	return (error < 0) ? error : 0;
+}
+
+/*
+ * Lock the page of an asynchronous request
+ */
+static __inline__ int
+nfs_lock_page(struct page *page)
+{
+	return !test_and_set_bit(PG_locked, &page->flags);
+}
+
+static __inline__ void
+nfs_unlock_page(struct page *page)
+{
+        clear_bit(PG_locked, &page->flags);
+        wake_up(&page->wait);
+}
 
 /*
  * linux/fs/nfs/read.c
  */
 extern int  nfs_readpage(struct file *, struct page *);
+extern struct page *  nfs_grab_cache_page(struct inode *, unsigned long);
+
+/*
+ * linux/fs/nfs2xdr.c
+ */
+extern u32 *nfs_decode_dirent(u32 *, struct nfs_entry *, int);
+
+/*
+ * linux/fs/nfs2xdr.c
+ */
+extern u32 *nfs3_decode_dirent(u32 *, struct nfs_entry *, int);
 
 /*
  * linux/fs/mount_clnt.c
  * (Used only by nfsroot module)
  */
 extern int  nfs_mount(struct sockaddr_in *, char *, struct nfs_fh *);
+extern int  nfs3_mount(struct sockaddr_in *, char *, struct nfs_fh *);
 
 /*
  * inline functions
  */
 static inline int
-nfs_revalidate_inode(struct nfs_server *server, struct dentry *dentry)
+nfs_revalidate_inode(struct dentry *dentry)
 {
 	struct inode *inode = dentry->d_inode;
-	if (jiffies - NFS_READTIME(inode) < NFS_ATTRTIMEO(inode))
+	if (time_before(jiffies,NFS_READTIME(inode)+NFS_ATTRTIMEO(inode)))
 		return 0;
-	return _nfs_revalidate_inode(server, dentry);
+	return __nfs_revalidate_inode(dentry);
+}
+
+static inline off_t
+nfs_size_to_off_t(__u64 size)
+{
+	return (size > (__u64)LONG_MAX) ? (off_t)LONG_MAX : (off_t) size;
+}
+
+static inline ino_t
+nfs_fileid_to_ino_t(u64 fileid)
+{
+	ino_t ino = (unsigned long) fileid;
+	if (sizeof(unsigned long) < sizeof(u64))
+		ino ^= fileid >> (sizeof(u64)-sizeof(unsigned long)) * 8;
+	return ino;
 }
 
+static inline time_t
+nfs_time_to_secs(__u64 time)
+{
+	return (time_t)(time >> 32);
+}
+
+static __inline__ struct rpc_cred *
+nfs_file_cred(struct file *file)
+{
+	if (!NFS_FILE(file) || !nfs_check_file(file)) {
+		printk("nfs_file_cred: invalid file!\n");
+		return NULL;
+	}
+	return NFS_FILE(file)->cred;
+}
+
+static __inline__ struct rpc_cred *
+nfs_dentry_cred(struct dentry *dentry)
+{
+
+	if (!NFS_DENTRY(dentry) || !nfs_check_dentry(dentry))
+		return NULL;
+	return NFS_DENTRY(dentry)->cred;
+}
+
+
 /* NFS root */
 
 extern int nfs_root_mount(struct super_block *sb);
 
+#define nfs_wait_event(clnt, wq, condition)				\
+({									\
+	int __retval = 0;						\
+	if (clnt->cl_intr) {						\
+		sigset_t oldmask;					\
+		rpc_clnt_sigmask(clnt, &oldmask);			\
+		__retval = wait_event_interruptible(wq, condition);	\
+		rpc_clnt_sigunmask(clnt, &oldmask);			\
+	} else								\
+		wait_event(wq, condition);				\
+	__retval;							\
+})
+
 #endif /* __KERNEL__ */
 
 /*
@@ -270,6 +467,7 @@
 #define NFSDBG_XDR		0x0020
 #define NFSDBG_FILE		0x0040
 #define NFSDBG_ROOT		0x0080
+#define NFSDBG_PARANOID		0x0100
 #define NFSDBG_ALL		0xFFFF
 
 #ifdef __KERNEL__
@@ -278,6 +476,11 @@
 #  define ifdebug(fac)		if (nfs_debug & NFSDBG_##fac)
 # else
 #  define ifdebug(fac)		if (0)
+# endif
+# ifdef NFS_PARANOIA
+#  define nfsparanoid(args...)	dfprintk(PARANOID, ##args)
+# else
+#  define nfsparanoid(args...)	do { } while (0)
 # endif
 #endif /* __KERNEL */
 
Index: oldkernel/linux/include/linux/nfs_fs_i.h
diff -u linux/include/linux/nfs_fs_i.h:1.1.1.1 linux/include/linux/nfs_fs_i.h:1.2
--- linux/include/linux/nfs_fs_i.h:1.1.1.1	Wed May 31 12:33:49 2000
+++ linux/include/linux/nfs_fs_i.h	Fri Jul  7 15:36:48 2000
@@ -1,4 +1,4 @@
-#ifndef _NFS_FS_I
+#ifndef _NFS_FS_i
 #define _NFS_FS_I
 
 #include <linux/nfs.h>
@@ -16,6 +16,12 @@
 	struct pipe_inode_info	pipeinfo;
 
 	/*
+	 * The 64bit fileid
+	 */
+	__u64 fsid;
+	__u64 fileid;
+
+	/*
 	 * Various flags
 	 */
 	unsigned short		flags;
@@ -38,22 +44,66 @@
 	 *	mtime != read_cache_mtime
 	 */
 	unsigned long		read_cache_jiffies;
-	unsigned long		read_cache_mtime;
+	__u64			read_cache_ctime;
+	__u64			read_cache_mtime;
+	__u64			read_cache_atime;
+	__u64			read_cache_isize;
 	unsigned long		attrtimeo;
+	unsigned long		attrtimeo_timestamp;
+
+	/*
+	 * This is the cookie verifier used for NFSv3 readdir
+	 * operations
+	 */
+	__u32			cookieverf[2];
 
 	/*
-	 * This is the list of dirty unwritten pages.
-	 * NFSv3 will want to add a list for written but uncommitted
-	 * pages.
+	 * This is the list of dirty pages.
 	 */
-	struct nfs_wreq *	writeback;
+	struct list_head	dirty;
+	struct list_head	commit;
+	struct list_head	writeback;
+
+	unsigned int		ndirty,
+				ncommit,
+				npages;
+
+	/* Flush daemon info */
+	struct inode		*hash_next,
+				*hash_prev;
+	unsigned long		nextscan;
 };
 
 /*
  * Legal inode flag values
  */
-#define NFS_INO_REVALIDATE	0x0001		/* revalidating attrs */
+#define NFS_INO_LOCKED          0x0001          /* locked for revalidation */
+#define NFS_INO_ADVISE_RDPLUS   0x0002          /* advise readdirplus */
+#define NFS_INO_REVALIDATING    0x0004          /* in nfs_revalidate() */
+#define NFS_INO_INVALIDATE      0x0008          /* zap cache on next occasion */
 #define NFS_IS_SNAPSHOT		0x0010		/* a snapshot file */
+#define NFS_INO_STALE		0x0020		/* We suspect inode is stale */
+#define NFS_INO_FLUSH		0x0040		/* inode is due for flushing */
+
+/*
+ * NFS ACL info.
+ * This information will be used by nfs_permission() in the obvious fashion,
+ * but also helps the RPC engine to select whether to try the operation first
+ * with the effective or real uid/gid first.
+ *
+ * For NFSv2, this info is obtained by just trying the operation in
+ * question and updating the ACL info according to the result.
+ * For NFSv3, the access() call is used to fill in the permission bits.
+ *
+ * Not yet used.
+ */
+struct nfs_acl_info {
+	struct nfs_acl_info *	acl_next;
+	unsigned long		acl_read_time;
+	uid_t			acl_uid;
+	gid_t			acl_gid;
+	unsigned int		acl_bits;
+};
 
 /*
  * NFS lock info
@@ -61,6 +111,7 @@
 struct nfs_lock_info {
 	u32		state;
 	u32		flags;
+	struct nlm_host	*host;
 };
 
 /*
Index: oldkernel/linux/include/linux/nfs_fs_sb.h
diff -u linux/include/linux/nfs_fs_sb.h:1.1.1.1 linux/include/linux/nfs_fs_sb.h:1.2
--- linux/include/linux/nfs_fs_sb.h:1.1.1.1	Wed May 31 12:33:49 2000
+++ linux/include/linux/nfs_fs_sb.h	Fri Jul  7 15:36:48 2000
@@ -1,7 +1,6 @@
 #ifndef _NFS_FS_SB
 #define _NFS_FS_SB
 
-#include <linux/nfs.h>
 #include <linux/in.h>
 
 /*
@@ -9,23 +8,32 @@
  */
 struct nfs_server {
 	struct rpc_clnt *	client;		/* RPC client handle */
+	struct nfs_rpc_ops *	rpc_ops;	/* NFS protocol vector */
 	int			flags;		/* various flags */
-	int			rsize;		/* read size */
-	int			wsize;		/* write size */
+	unsigned int		rsize;		/* read size */
+	unsigned int		rpages;		/* read size (in pages) */
+	unsigned int		wsize;		/* write size */
+	unsigned int		wpages;		/* write size (in pages) */
+	unsigned int		dtsize;		/* readdir size */
 	unsigned int		bsize;		/* server block size */
 	unsigned int		acregmin;	/* attr cache timeouts */
 	unsigned int		acregmax;
 	unsigned int		acdirmin;
 	unsigned int		acdirmax;
+	unsigned int		namelen;
 	char *			hostname;	/* remote hostname */
+	struct nfs_dircache *	dircache;	/* readdir cache info */
+	struct nfs_reqlist *	rw_requests;    /* async read/write requests */
 };
 
+
 /*
  * nfs super-block data in memory
  */
 struct nfs_sb_info {
-	struct nfs_server	s_server;
-	struct nfs_fh		s_root;
+	struct nfs_server	s_server;	/* NFS server info */
+	unsigned int		s_fhsize;	/* File handle size */
+	struct nfs_fh *		s_root;		/* The root file handle */
 };
 
 #endif
Index: oldkernel/linux/include/linux/nfs_mount.h
diff -u linux/include/linux/nfs_mount.h:1.1.1.1 linux/include/linux/nfs_mount.h:1.2
--- linux/include/linux/nfs_mount.h:1.1.1.1	Wed May 31 12:33:49 2000
+++ linux/include/linux/nfs_mount.h	Fri Jul  7 15:36:48 2000
@@ -8,6 +8,9 @@
  *
  *  structure passed from user-space to kernel-space during an nfs mount
  */
+#include <linux/nfs.h>
+#include <linux/nfs2.h>
+#include <linux/nfs_fs.h>
 
 /*
  * WARNING!  Do not delete or change the order of these fields.  If
@@ -15,13 +18,17 @@
  * tracks which fields are present.  This will ensure some measure of
  * mount-to-kernel version compatibility.  Some of these aren't used yet
  * but here they are anyway.
+ *
+ * Lugging around two file handles is inevitable if we want to pass
+ * version 3 handles while maintaining compatibility. We may want to
+ * break it for the 2.2 kernel eventually...
  */
-#define NFS_MOUNT_VERSION	3
+#define NFS_MOUNT_VERSION	4
 
 struct nfs_mount_data {
 	int		version;		/* 1 */
 	int		fd;			/* 1 */
-	struct nfs_fh	root;			/* 1 */
+	struct nfs2_fh	old_root;		/* 1 */
 	int		flags;			/* 1 */
 	int		rsize;			/* 1 */
 	int		wsize;			/* 1 */
@@ -35,6 +42,7 @@
 	char		hostname[256];		/* 1 */
 	int		namlen;			/* 2 */
 	unsigned int	bsize;			/* 3 */
+	struct nfs_fh	root;			/* 4 */
 };
 
 /* bits in the flags field */
@@ -49,5 +57,13 @@
 #define NFS_MOUNT_VER3		0x0080	/* 3 */
 #define NFS_MOUNT_KERBEROS	0x0100	/* 3 */
 #define NFS_MOUNT_NONLM		0x0200	/* 3 */
+#define NFS_MOUNT_FLAGMASK	0xFFFF
+
+/*
+ * Private flags - not to be set by mount program
+ */
+#ifdef __KERNEL__
+#define NFS_NONMONOTONE_COOKIES	0x00010000
+#endif /* __KERNEL__ */
  
 #endif
Index: oldkernel/linux/include/linux/pagemap.h
diff -u linux/include/linux/pagemap.h:1.2 linux/include/linux/pagemap.h:1.3
--- linux/include/linux/pagemap.h:1.2	Thu Jun  1 15:03:09 2000
+++ linux/include/linux/pagemap.h	Fri Jul  7 15:36:48 2000
@@ -28,7 +28,6 @@
 #define PAGE_CACHE_SHIFT	PAGE_SHIFT
 #define PAGE_CACHE_SIZE		PAGE_SIZE
 #define PAGE_CACHE_MASK		PAGE_MASK
-#define PAGE_CACHE_MASK_loff	PAGE_MASK_loff
 
 #define page_cache_alloc()	__get_free_page(GFP_USER)
 #define page_cache_free(x)	free_page(x)
@@ -55,10 +54,10 @@
  * inode pointer and offsets are distributed (ie, we
  * roughly know which bits are "significant")
  */
-static inline unsigned long _page_hashfn(struct inode * inode, pgoff_t index)
+static inline unsigned long _page_hashfn(struct inode * inode, unsigned long offset)
 {
 #define i (((unsigned long) inode)/(sizeof(struct inode) & ~ (sizeof(struct inode) - 1)))
-#define o ((pgoff2ulong(index) >> PAGE_SHIFT) + (pgoff2ulong(index) & ~PAGE_MASK))
+#define o ((offset >> PAGE_SHIFT) + (offset & ~PAGE_MASK))
 	return ((i+o) & PAGE_HASH_MASK);
 #undef i
 #undef o
@@ -66,7 +65,7 @@
 
 #define page_hash(inode,offset) (page_hash_table+_page_hashfn(inode,offset))
 
-static inline struct page * __find_page(struct inode * inode, pgoff_t index, struct page *page)
+static inline struct page * __find_page(struct inode * inode, unsigned long offset, struct page *page)
 {
 	goto inside;
 	for (;;) {
@@ -76,7 +75,7 @@
 			goto not_found;
 		if (page->inode != inode)
 			continue;
-		if (pgoff2ulong(page->index) == pgoff2ulong(index))
+		if (page->offset == offset)
 			break;
 	}
 	/* Found the page. */
@@ -86,9 +85,9 @@
 	return page;
 }
 
-static inline struct page *find_page(struct inode * inode, pgoff_t poffset)
+static inline struct page *find_page(struct inode * inode, unsigned long offset)
 {
-	return __find_page(inode, poffset, *page_hash(inode, poffset));
+	return __find_page(inode, offset, *page_hash(inode, offset));
 }
 
 static inline void remove_page_from_hash_queue(struct page * page)
@@ -111,9 +110,9 @@
 	page->pprev_hash = p;
 }
 
-static inline void add_page_to_hash_queue(struct page * page, struct inode * inode, pgoff_t poffset)
+static inline void add_page_to_hash_queue(struct page * page, struct inode * inode, unsigned long offset)
 {
-	__add_page_to_hash_queue(page, page_hash(inode,poffset));
+	__add_page_to_hash_queue(page, page_hash(inode,offset));
 }
 
 static inline void remove_page_from_inode_queue(struct page * page)
@@ -151,7 +150,18 @@
 		__wait_on_page(page);
 }
 
-extern void update_vm_cache_conditional(struct inode *, loff_t, const char *, int, unsigned long);
-extern void update_vm_cache(struct inode *, loff_t, const char *, int);
+static inline void add_to_page_cache(struct page * page, struct inode * inode,
+				     unsigned long offset, struct page **hash)
+{
+	atomic_inc(&page->count);
+	page->flags &= ~((1 << PG_uptodate) | (1 << PG_error));
+	page->flags |= (1 << PG_referenced);
+	page->offset = offset;
+	add_page_to_inode_queue(inode, page);
+	__add_page_to_hash_queue(page, hash);
+}
+
+extern void update_vm_cache_conditional(struct inode *, unsigned long, const char *, int, unsigned long);
+extern void update_vm_cache(struct inode *, unsigned long, const char *, int);
 
 #endif
Index: oldkernel/linux/include/linux/pci.h
diff -u linux/include/linux/pci.h:1.4 linux/include/linux/pci.h:1.5
--- linux/include/linux/pci.h:1.4	Thu Jun  1 16:52:50 2000
+++ linux/include/linux/pci.h	Fri Jul  7 15:36:48 2000
@@ -1,5 +1,5 @@
 /*
- *	$Id: pci.h,v 1.2 2000/05/31 21:56:52 ccr Exp $
+ *	$Id: pci.h,v 1.87 1998/10/11 15:13:12 mj Exp $
  *
  *	PCI defines and function prototypes
  *	Copyright 1994, Drew Eckhardt
@@ -310,6 +310,8 @@
 #define PCI_DEVICE_ID_NCR_53C885	0x000d
 #define PCI_DEVICE_ID_NCR_53C875	0x000f
 #define PCI_DEVICE_ID_NCR_53C1510	0x0010
+#define PCI_DEVICE_ID_NCR_53C895A	0x0012
+#define PCI_DEVICE_ID_NCR_53C1010	0x0020
 #define PCI_DEVICE_ID_NCR_53C875J	0x008f
 
 #define PCI_VENDOR_ID_ATI		0x1002
@@ -556,10 +558,12 @@
 #define PCI_DEVICE_ID_PICOP_PT80C524	0x8002
 
 #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_DEVICE_ID_MYLEX_DAC960_P	0x0001
+#define PCI_DEVICE_ID_MYLEX_DAC960_PD	0x0002
+#define PCI_DEVICE_ID_MYLEX_DAC960_PG	0x0010
+#define PCI_DEVICE_ID_MYLEX_DAC960_LA	0x0020
+#define PCI_DEVICE_ID_MYLEX_DAC960_LP	0x0050
+#define PCI_DEVICE_ID_MYLEX_DAC960_BA	0xBA56
 
 #define PCI_VENDOR_ID_APPLE		0x106b
 #define PCI_DEVICE_ID_APPLE_BANDIT	0x0001
@@ -1088,6 +1092,7 @@
 #define PCI_DEVICE_ID_INTEL_82430	0x0486
 #define PCI_DEVICE_ID_INTEL_82434	0x04a3
 #define PCI_DEVICE_ID_INTEL_I960	0x0960
+#define PCI_DEVICE_ID_INTEL_I960RN	0x0964
 #define PCI_DEVICE_ID_INTEL_82559ER	0x1209
 #define PCI_DEVICE_ID_INTEL_82092AA_0	0x1221
 #define PCI_DEVICE_ID_INTEL_82092AA_1	0x1222
Index: oldkernel/linux/include/linux/sched.h
diff -u linux/include/linux/sched.h:1.2 linux/include/linux/sched.h:1.3
--- linux/include/linux/sched.h:1.2	Thu Jun  1 15:03:09 2000
+++ linux/include/linux/sched.h	Fri Jul  7 15:36:48 2000
@@ -299,7 +299,7 @@
         kernel_cap_t   cap_effective, cap_inheritable, cap_permitted;
 	struct user_struct *user;
 /* limits */
-	struct rlimit   rlim[RLIM_NLIMITS];
+	struct rlimit rlim[RLIM_NLIMITS];
 	unsigned short used_math;
 	char comm[16];
 /* file system info */
@@ -328,6 +328,9 @@
 /* Thread group tracking */
    	u32 parent_exec_id;
    	u32 self_exec_id;
+
+/* local vfs journaling data */
+	struct handle_s *j_handle;
 };
 
 /*
@@ -395,6 +398,7 @@
 /* mm */	&init_mm, \
 /* signals */	SPIN_LOCK_UNLOCKED, &init_signals, {{0}}, {{0}}, NULL, &init_task.sigqueue, 0, 0, \
 /* exec cts */	0,0, \
+/* jfs */	NULL, \
 }
 
 union task_union {
Index: oldkernel/linux/include/linux/sem.h
diff -u linux/include/linux/sem.h:1.1.1.1 linux/include/linux/sem.h:1.2
--- linux/include/linux/sem.h:1.1.1.1	Wed May 31 12:33:49 2000
+++ linux/include/linux/sem.h	Fri Jul  7 15:36:48 2000
@@ -60,7 +60,7 @@
 	int semaem;
 };
 
-#define SEMMNI  128             /* ?  max # of semaphore identifiers */
+#define SEMMNI  512             /* ?  max # of semaphore identifiers */
 #define SEMMSL  250              /* <= 512 max num of semaphores per id */
 #define SEMMNS  (SEMMNI*SEMMSL) /* ? max # of semaphores in system */
 #define SEMOPM  32	        /* ~ 100 max num of ops per semop call */
Index: oldkernel/linux/include/linux/serial.h
diff -u linux/include/linux/serial.h:1.1.1.1 linux/include/linux/serial.h:1.2
--- linux/include/linux/serial.h:1.1.1.1	Wed May 31 12:33:48 2000
+++ linux/include/linux/serial.h	Fri Jul  7 15:36:48 2000
@@ -10,21 +10,46 @@
 #ifndef _LINUX_SERIAL_H
 #define _LINUX_SERIAL_H
 
+#ifdef __KERNEL__
+
+#include <asm/page.h>
+
+/*
+ * Counters of the input lines (CTS, DSR, RI, CD) interrupts
+ */
+
+struct async_icount {
+	__u32	cts, dsr, rng, dcd, tx, rx;
+	__u32	frame, parity, overrun, brk;
+	__u32	buf_overrun;
+};
+
+#endif /* __KERNEL__ */
+
+/*
+ * The size of the serial xmit buffer is 1 page, or 4096 bytes
+ */
+#define SERIAL_XMIT_SIZE PAGE_SIZE
+
 struct serial_struct {
 	int	type;
 	int	line;
-	int	port;
+	unsigned int	port;
 	int	irq;
 	int	flags;
 	int	xmit_fifo_size;
 	int	custom_divisor;
 	int	baud_base;
 	unsigned short	close_delay;
-	char	reserved_char[2];
+	char	io_type;
+	char	reserved_char[1];
 	int	hub6;
 	unsigned short	closing_wait; /* time to wait before closing */
 	unsigned short	closing_wait2; /* no longer used... */
-	int	reserved[4];
+	unsigned char	*iomem_base;
+	unsigned short	iomem_reg_shift;
+	unsigned int	port_high;
+	int	reserved[1];
 };
 
 /*
@@ -47,7 +72,15 @@
 #define PORT_16650V2	7
 #define PORT_16750	8
 #define PORT_STARTECH	9	/* usurped by cyclades.c */
-#define PORT_MAX	9
+#define PORT_16C950	10	/* Oxford Semiconductor */
+#define PORT_16654	11
+#define PORT_16850	12
+#define PORT_MAX	12
+
+#define SERIAL_IO_PORT	0
+#define SERIAL_IO_HUB6	1
+#define SERIAL_IO_MEM	2
+#define SERIAL_IO_GSC	3
 
 struct serial_uart_config {
 	char	*name;
@@ -86,8 +119,11 @@
 #define ASYNC_SPD_WARP	0x1010	/* Use 460800 instead of 38400 bps */
 
 #define ASYNC_LOW_LATENCY 0x2000 /* Request low latency behaviour */
+
+#define ASYNC_BUGGY_UART  0x4000 /* This is a buggy UART, skip some safety
+				  * checks.  Note: can be dangerous! */
 
-#define ASYNC_FLAGS	0x3FFF	/* Possible legal async flags */
+#define ASYNC_FLAGS	0x7FFF	/* Possible legal async flags */
 #define ASYNC_USR_MASK	0x3430	/* Legal flags that non-privileged
 				 * users can set or reset */
 
@@ -99,7 +135,8 @@
 #define ASYNC_CLOSING		0x08000000 /* Serial port is closing */
 #define ASYNC_CTS_FLOW		0x04000000 /* Do CTS flow control */
 #define ASYNC_CHECK_CD		0x02000000 /* i.e., CLOCAL */
-#define ASYNC_SHARE_IRQ		0x01000000 /* for multifunction cards */
+#define ASYNC_SHARE_IRQ		0x01000000 /* for multifunction cards
+					     --- no longer used */
 
 #define ASYNC_INTERNAL_FLAGS	0xFF000000 /* Internal flags */
 
Index: oldkernel/linux/include/linux/serialP.h
diff -u linux/include/linux/serialP.h:1.1.1.1 linux/include/linux/serialP.h:1.2
--- linux/include/linux/serialP.h:1.1.1.1	Wed May 31 12:33:49 2000
+++ linux/include/linux/serialP.h	Fri Jul  7 15:36:48 2000
@@ -19,41 +19,44 @@
  * For definitions of the flags field, see tty.h
  */
 
+#include <linux/config.h>
 #include <linux/termios.h>
 #include <linux/tqueue.h>
+#include <linux/circ_buf.h>
+#include <linux/wait.h>
+#if (LINUX_VERSION_CODE < 0x020300)
+/* Unfortunate, but Linux 2.2 needs async_icount defined here and
+ * it got moved in 2.3 */
+#include <linux/serial.h>
+#endif
 
-/*
- * Counters of the input lines (CTS, DSR, RI, CD) interrupts
- */
-struct async_icount {
-	__u32	cts, dsr, rng, dcd, tx, rx;
-	__u32	frame, parity, overrun, brk;
-	__u32	buf_overrun;
-};
-
 struct serial_state {
 	int	magic;
 	int	baud_base;
-	int	port;
+	unsigned long	port;
 	int	irq;
 	int	flags;
 	int	hub6;
 	int	type;
 	int	line;
+	int	revision;	/* Chip revision (950) */
 	int	xmit_fifo_size;
 	int	custom_divisor;
 	int	count;
+	u8	*iomem_base;
+	u16	iomem_reg_shift;
 	unsigned short	close_delay;
 	unsigned short	closing_wait; /* time to wait before closing */
 	struct async_icount	icount;	
 	struct termios		normal_termios;
 	struct termios		callout_termios;
+	int	io_type;
 	struct async_struct *info;
 };
 
 struct async_struct {
 	int			magic;
-	int			port;
+	unsigned long		port;
 	int			hub6;
 	int			flags;
 	int			xmit_fifo_size;
@@ -69,33 +72,39 @@
 	unsigned short		closing_wait2;
 	int			IER; 	/* Interrupt Enable Register */
 	int			MCR; 	/* Modem control register */
+	int			LCR; 	/* Line control register */
+	int			ACR;	 /* 16950 Additional Control Reg. */
 	unsigned long		event;
 	unsigned long		last_active;
 	int			line;
 	int			blocked_open; /* # of blocked opens */
 	long			session; /* Session of opening process */
 	long			pgrp; /* pgrp of opening process */
-	unsigned char 		*xmit_buf;
-	int			xmit_head;
-	int			xmit_tail;
-	int			xmit_cnt;
+ 	struct circ_buf		xmit;
+ 	spinlock_t		xmit_lock;
+	u8			*iomem_base;
+	u16			iomem_reg_shift;
+	int			io_type;
 	struct tq_struct	tqueue;
+#ifdef DECLARE_WAITQUEUE
+	wait_queue_head_t	open_wait;
+	wait_queue_head_t	close_wait;
+	wait_queue_head_t	delta_msr_wait;
+#else	
 	struct wait_queue	*open_wait;
 	struct wait_queue	*close_wait;
 	struct wait_queue	*delta_msr_wait;
+#endif	
 	struct async_struct	*next_port; /* For the linked list */
 	struct async_struct	*prev_port;
 };
 
+#define CONFIGURED_SERIAL_PORT(info) ((info)->port || ((info)->iomem_base))
+
 #define SERIAL_MAGIC 0x5301
 #define SSTATE_MAGIC 0x5302
 
 /*
- * The size of the serial xmit buffer is 1 page, or 4096 bytes
- */
-#define SERIAL_XMIT_SIZE 4096
-
-/*
  * Events are used to schedule things to happen at timer-interrupt
  * time, instead of at rs interrupt time.
  */
@@ -115,5 +124,77 @@
 	unsigned char	mask4, match4;
 	int		port_monitor;
 };
+
+#if defined(__alpha__) && !defined(CONFIG_PCI)
+/*
+ * Digital did something really horribly wrong with the OUT1 and OUT2
+ * lines on at least some ALPHA's.  The failure mode is that if either
+ * is cleared, the machine locks up with endless interrupts.
+ */
+#define ALPHA_KLUDGE_MCR  (UART_MCR_OUT2 | UART_MCR_OUT1)
+#else
+#define ALPHA_KLUDGE_MCR 0
+#endif
+
+/*
+ * Structures and definitions for PCI support
+ */
+struct pci_dev;
+struct pci_board {
+	unsigned short vendor;
+	unsigned short device;
+	unsigned short subvendor;
+	unsigned short subdevice;
+	int flags;
+	int num_ports;
+	int base_baud;
+	int uart_offset;
+	int reg_shift;
+	int (*init_fn)(struct pci_dev *dev, struct pci_board *board,
+			int enable);
+	int first_uart_offset;
+};
+
+struct pci_board_inst {
+	struct pci_board	board;
+	struct pci_dev		*dev;
+};
+
+#ifndef PCI_ANY_ID
+#define PCI_ANY_ID (~0)
+#endif
+
+#define SPCI_FL_BASE_MASK	0x0007
+#define SPCI_FL_BASE0	0x0000
+#define SPCI_FL_BASE1	0x0001
+#define SPCI_FL_BASE2	0x0002
+#define SPCI_FL_BASE3	0x0003
+#define SPCI_FL_BASE4	0x0004
+#define SPCI_FL_GET_BASE(x)	(x & SPCI_FL_BASE_MASK)
+
+#define SPCI_FL_IRQ_MASK       (0x0007 << 4)
+#define SPCI_FL_IRQBASE0       (0x0000 << 4)
+#define SPCI_FL_IRQBASE1       (0x0001 << 4)
+#define SPCI_FL_IRQBASE2       (0x0002 << 4)
+#define SPCI_FL_IRQBASE3       (0x0003 << 4)
+#define SPCI_FL_IRQBASE4       (0x0004 << 4)
+#define SPCI_FL_GET_IRQBASE(x)        ((x & SPCI_FL_IRQ_MASK) >> 4)
+
+/* Use sucessiveentries base resource table */
+#define SPCI_FL_BASE_TABLE	0x0100
+
+/* Use successive entries in the irq resource table */
+#define SPCI_FL_IRQ_TABLE	0x0200
+
+/* Use the irq resource table instead of dev->irq */
+#define SPCI_FL_IRQRESOURCE	0x0400
+
+/* Use the Base address register size to cap number of ports */
+#define SPCI_FL_REGION_SZ_CAP	0x0800
+
+/* Do not use irq sharing for this device */
+#define SPCI_FL_NO_SHIRQ	0x1000
+
+#define SPCI_FL_PNPDEFAULT	(SPCI_FL_IRQRESOURCE)
 
 #endif /* _LINUX_SERIAL_H */
Index: oldkernel/linux/include/linux/serial_reg.h
diff -u linux/include/linux/serial_reg.h:1.1.1.1 linux/include/linux/serial_reg.h:1.2
--- linux/include/linux/serial_reg.h:1.1.1.1	Wed May 31 12:33:49 2000
+++ linux/include/linux/serial_reg.h	Fri Jul  7 15:36:48 2000
@@ -17,17 +17,29 @@
 #define UART_RX		0	/* In:  Receive buffer (DLAB=0) */
 #define UART_TX		0	/* Out: Transmit buffer (DLAB=0) */
 #define UART_DLL	0	/* Out: Divisor Latch Low (DLAB=1) */
+#define UART_TRG	0	/* (LCR=BF) FCTR bit 7 selects Rx or Tx
+				 * In: Fifo count
+				 * Out: Fifo custom trigger levels
+				 * XR16C85x only */
+
 #define UART_DLM	1	/* Out: Divisor Latch High (DLAB=1) */
 #define UART_IER	1	/* Out: Interrupt Enable Register */
+#define UART_FCTR	1	/* (LCR=BF) Feature Control Register
+				 * XR16C85x only */
+
 #define UART_IIR	2	/* In:  Interrupt ID Register */
 #define UART_FCR	2	/* Out: FIFO Control Register */
 #define UART_EFR	2	/* I/O: Extended Features Register */
 				/* (DLAB=1, 16C660 only) */
+
 #define UART_LCR	3	/* Out: Line Control Register */
 #define UART_MCR	4	/* Out: Modem Control Register */
 #define UART_LSR	5	/* In:  Line Status Register */
 #define UART_MSR	6	/* In:  Modem Status Register */
 #define UART_SCR	7	/* I/O: Scratch Register */
+#define UART_EMSR	7	/* (LCR=BF) Extended Mode Select Register 
+				 * FCTR bit 6 selects SCR or EMSR
+				 * XR16c85x only */
 
 /*
  * These are the definitions for the FIFO Control Register
@@ -139,6 +151,83 @@
 /*
  * the low four bits control software flow control
  */
+
+/*
+ * These register definitions are for the 16C950
+ */
+#define UART_ASR	0x01	/* Additional Status Register */
+#define UART_RFL	0x03	/* Transmitter FIFO level */
+#define UART_TFL 	0x04	/* Receiver FIFO level */
+#define UART_ICR	0x05	/* Index Control Register */
+
+/* The 16950 ICR registers */
+#define UART_ACR	0x00	/* Additional Control Register */
+#define UART_CPR	0x01	/* Clock Prescalar Register */
+#define UART_TCR	0x02	/* Times Clock Register */
+#define UART_CKS	0x03	/* Clock Select Register */
+#define UART_TTL	0x04	/* Transmitter Interrupt Trigger Level */
+#define UART_RTL	0x05	/* Receiver Interrupt Trigger Level */
+#define UART_FCL	0x06	/* Flow Control Level Lower */
+#define UART_FCH	0x07	/* Flow Control Level Higher */
+#define UART_ID1	0x08	/* ID #1 */
+#define UART_ID2	0x09	/* ID #2 */
+#define UART_ID3	0x0A	/* ID #3 */
+#define UART_REV	0x0B	/* Revision */
+#define UART_CSR	0x0C	/* Channel Software Reset */
+#define UART_NMR	0x0D	/* Nine-bit Mode Register */
+#define UART_CTR	0xFF
+
+/*
+ * The 16C950 Additional Control Reigster
+ */
+#define UART_ACR_RXDIS	0x01	/* Receiver disable */
+#define UART_ACR_TXDIS	0x02	/* Receiver disable */
+#define UART_ACR_DSRFC	0x04	/* DSR Flow Control */
+#define UART_ACR_TLENB	0x20	/* 950 trigger levels enable */
+#define UART_ACR_ICRRD	0x40	/* ICR Read enable */
+#define UART_ACR_ASREN	0x80	/* Additional status enable */
+
+/*
+ * These are the definitions for the Feature Control Register
+ * (XR16C85x only, when LCR=bf; doubles with the Interrupt Enable
+ * Register, UART register #1)
+ */
+#define UART_FCTR_RTS_NODELAY	0x00  /* RTS flow control delay */
+#define UART_FCTR_RTS_4DELAY	0x01
+#define UART_FCTR_RTS_6DELAY	0x02
+#define UART_FCTR_RTS_8DELAY	0x03
+#define UART_FCTR_IRDA	0x04  /* IrDa data encode select */
+#define UART_FCTR_TX_INT	0x08  /* Tx interrupt type select */
+#define UART_FCTR_TRGA	0x00  /* Tx/Rx 550 trigger table select */
+#define UART_FCTR_TRGB	0x10  /* Tx/Rx 650 trigger table select */
+#define UART_FCTR_TRGC	0x20  /* Tx/Rx 654 trigger table select */
+#define UART_FCTR_TRGD	0x30  /* Tx/Rx 850 programmable trigger select */
+#define UART_FCTR_SCR_SWAP	0x40  /* Scratch pad register swap */
+#define UART_FCTR_RX	0x00  /* Programmable trigger mode select */
+#define UART_FCTR_TX	0x80  /* Programmable trigger mode select */
+
+/*
+ * These are the definitions for the Enhanced Mode Select Register
+ * (XR16C85x only, when LCR=bf and FCTR bit 6=1; doubles with the
+ * Scratch register, UART register #7)
+ */
+#define UART_EMSR_FIFO_COUNT	0x01  /* Rx/Tx select */
+#define UART_EMSR_ALT_COUNT	0x02  /* Alternating count select */
+
+/*
+ * These are the definitions for the Programmable Trigger
+ * Register (XR16C85x only, when LCR=bf; doubles with the UART RX/TX
+ * register, UART register #0)
+ */
+#define UART_TRG_1	0x01
+#define UART_TRG_4	0x04
+#define UART_TRG_8	0x08
+#define UART_TRG_16	0x10
+#define UART_TRG_32	0x20
+#define UART_TRG_64	0x40
+#define UART_TRG_96	0x60
+#define UART_TRG_120	0x78
+#define UART_TRG_128	0x80
 
 #endif /* _LINUX_SERIAL_REG_H */
 
Index: oldkernel/linux/include/linux/smb_fs.h
diff -u linux/include/linux/smb_fs.h:1.2 linux/include/linux/smb_fs.h:1.3
--- linux/include/linux/smb_fs.h:1.2	Thu Jun  1 15:03:09 2000
+++ linux/include/linux/smb_fs.h	Fri Jul  7 15:36:48 2000
@@ -128,8 +128,8 @@
 void smb_close_dentry(struct dentry *);
 int smb_close_fileid(struct dentry *, __u16);
 int smb_open(struct dentry *, int);
-int smb_proc_read(struct dentry *, loff_t, int, char *);
-int smb_proc_write(struct dentry *, loff_t, int, const char *);
+int smb_proc_read(struct dentry *, off_t, int, char *);
+int smb_proc_write(struct dentry *, off_t, int, const char *);
 int smb_proc_create(struct dentry *, __u16, time_t, __u16 *);
 int smb_proc_mv(struct dentry *, struct dentry *);
 int smb_proc_mkdir(struct dentry *);
Index: oldkernel/linux/include/linux/swap.h
diff -u linux/include/linux/swap.h:1.2 linux/include/linux/swap.h:1.3
--- linux/include/linux/swap.h:1.2	Thu Jun  1 15:03:09 2000
+++ linux/include/linux/swap.h	Fri Jul  7 15:36:48 2000
@@ -114,7 +114,7 @@
 extern unsigned int nr_swapfiles;
 extern struct swap_info_struct swap_info[];
 void si_swapinfo(struct sysinfo *);
-extern unsigned long  get_swap_page(void);
+unsigned long get_swap_page(void);
 extern void FASTCALL(swap_free(unsigned long));
 struct swap_list_t {
 	int head;	/* head of priority-ordered swapfile list */
@@ -147,7 +147,7 @@
 extern inline unsigned long in_swap_cache(struct page *page)
 {
 	if (PageSwapCache(page))
-		return pgoff2ulong(page->index);
+		return page->offset;
 	return 0;
 }
 
@@ -164,7 +164,7 @@
 		return 1;
 	count = atomic_read(&page->count);
 	if (PageSwapCache(page))
-		count += swap_count(pgoff2ulong(page->index)) - 2;
+		count += swap_count(page->offset) - 2;
 	if (PageFreeAfter(page))
 		count--;
 	return  count > 1;
diff -ru linux/include/linux/sysctl.h linux.new/include/linux/sysctl.h
--- linux/include/linux/sysctl.h	Tue Aug  8 17:33:10 2000
+++ linux.new/include/linux/sysctl.h	Tue Aug  8 17:31:16 2000
@@ -228,7 +228,8 @@
 	NET_IPV4_ICMP_ECHOREPLY_RATE=63,
 	NET_IPV4_ICMP_IGNORE_BOGUS_ERROR_RESPONSES=64,
 	NET_IPV4_IGMP_MAX_MEMBERSHIPS=65,
-	NET_IPV4_ALWAYS_DEFRAG=67
+	NET_IPV4_ALWAYS_DEFRAG=67,
+	NET_IPV4_IP_MASQ_UDP_DLOOSE=68
 };
 
 enum {
Index: oldkernel/linux/include/linux/ufs_fs_i.h
diff -u linux/include/linux/ufs_fs_i.h:1.2 linux/include/linux/ufs_fs_i.h:1.3
--- linux/include/linux/ufs_fs_i.h:1.2	Thu Jun  1 15:03:09 2000
+++ linux/include/linux/ufs_fs_i.h	Fri Jul  7 15:36:48 2000
@@ -18,6 +18,7 @@
 		__u32	i_data[15];
 		__u8	i_symlink[4*15];
 	} i_u1;
+	__u64	i_size;
 	__u32	i_flags;
 	__u32	i_gen;
 	__u32	i_shadow;
Index: oldkernel/linux/include/linux/lockd/debug.h
diff -u linux/include/linux/lockd/debug.h:1.1.1.1 linux/include/linux/lockd/debug.h:1.2
--- linux/include/linux/lockd/debug.h:1.1.1.1	Wed May 31 12:33:49 2000
+++ linux/include/linux/lockd/debug.h	Fri Jul  7 15:36:48 2000
@@ -45,6 +45,7 @@
 #define NLMDBG_CLNTSUBS		0x0020
 #define NLMDBG_SVCSUBS		0x0040
 #define NLMDBG_HOSTCACHE	0x0080
+#define NLMDBG_XDR		0x0100
 #define NLMDBG_ALL		0x7fff
 
 
Index: oldkernel/linux/include/linux/lockd/lockd.h
diff -u linux/include/linux/lockd/lockd.h:1.1.1.1 linux/include/linux/lockd/lockd.h:1.2
--- linux/include/linux/lockd/lockd.h:1.1.1.1	Wed May 31 12:33:49 2000
+++ linux/include/linux/lockd/lockd.h	Fri Jul  7 15:36:48 2000
@@ -17,6 +17,7 @@
 #include <linux/nfsd/nfsfh.h>
 #include <linux/lockd/bind.h>
 #include <linux/lockd/xdr.h>
+#include <linux/lockd/xdr4.h>
 #include <linux/lockd/debug.h>
 
 /*
@@ -112,6 +113,7 @@
  */
 extern struct rpc_program	nlm_program;
 extern struct svc_procedure	nlmsvc_procedures[];
+extern struct svc_procedure     nlmsvc_procedures4[];
 extern unsigned long		nlmsvc_grace_period;
 extern unsigned long		nlmsvc_timeout;
 
@@ -138,12 +140,14 @@
 					struct sockaddr_in *, int, int);
 struct rpc_clnt * nlm_bind_host(struct nlm_host *);
 void		  nlm_rebind_host(struct nlm_host *);
+struct nlm_host * nlm_get_host(struct nlm_host *);
 void		  nlm_release_host(struct nlm_host *);
 void		  nlm_shutdown_hosts(void);
 
 /*
  * Server-side lock handling
  */
+int		  nlmsvc_async_call(struct nlm_rqst *, u32, rpc_action);
 u32		  nlmsvc_lock(struct svc_rqst *, struct nlm_file *,
 					struct nlm_lock *, int, struct nlm_cookie *);
 u32		  nlmsvc_unlock(struct nlm_file *, struct nlm_lock *);
Index: oldkernel/linux/include/linux/lockd/nlm.h
diff -u linux/include/linux/lockd/nlm.h:1.1.1.1 linux/include/linux/lockd/nlm.h:1.2
--- linux/include/linux/lockd/nlm.h:1.1.1.1	Wed May 31 12:33:49 2000
+++ linux/include/linux/lockd/nlm.h	Fri Jul  7 15:36:48 2000
@@ -10,19 +10,21 @@
 #define LINUX_LOCKD_NLM_H
 
 /* Maximum file offset in file_lock.fl_end */
-#ifdef OFFSET_MAX
-# define NLM_OFFSET_MAX		OFFSET_MAX
-#else
 # define NLM_OFFSET_MAX		((off_t) 0x7fffffff)
-#endif
+# define NLM4_OFFSET_MAX	((s64) ((~(u64)0) >> 1))
 
 /* Return states for NLM */
 enum {
-	NLM_LCK_GRANTED = 0,
-	NLM_LCK_DENIED,
-	NLM_LCK_DENIED_NOLOCKS,
-	NLM_LCK_BLOCKED,
-	NLM_LCK_DENIED_GRACE_PERIOD,
+	NLM_LCK_GRANTED			= 0,
+	NLM_LCK_DENIED			= 1,
+	NLM_LCK_DENIED_NOLOCKS		= 2,
+	NLM_LCK_BLOCKED			= 3,
+	NLM_LCK_DENIED_GRACE_PERIOD	= 4,
+	NLM_DEADLCK			= 5,
+	NLM_ROFS			= 6,
+	NLM_STALE_FH			= 7,
+	NLM_FBIG			= 8,
+	NLM_FAILED			= 9,
 };
 
 #define NLM_PROGRAM		100021
Index: oldkernel/linux/include/linux/lockd/xdr.h
diff -u linux/include/linux/lockd/xdr.h:1.1.1.1 linux/include/linux/lockd/xdr.h:1.2
--- linux/include/linux/lockd/xdr.h:1.1.1.1	Wed May 31 12:33:49 2000
+++ linux/include/linux/lockd/xdr.h	Fri Jul  7 15:36:48 2000
@@ -74,6 +74,7 @@
 #define NLMSVC_XDRSIZE		sizeof(struct nlm_args)
 
 void	nlmxdr_init(void);
+void	nlmxdr_shutdown(void);
 int	nlmsvc_decode_testargs(struct svc_rqst *, u32 *, struct nlm_args *);
 int	nlmsvc_encode_testres(struct svc_rqst *, u32 *, struct nlm_res *);
 int	nlmsvc_decode_lockargs(struct svc_rqst *, u32 *, struct nlm_args *);
Index: oldkernel/linux/include/linux/lockd/xdr4.h
diff -u /dev/null linux/include/linux/lockd/xdr4.h:1.1
--- /dev/null	Mon Jul 31 21:15:09 2000
+++ linux/include/linux/lockd/xdr4.h	Fri Jul  7 16:18:18 2000
@@ -0,0 +1,43 @@
+/*
+ * linux/include/linux/lockd/xdr.h
+ *
+ * XDR types for the NLM protocol
+ *
+ * Copyright (C) 1996 Olaf Kirch <okir@monad.swb.de>
+ */
+
+#ifndef LOCKD_XDR4_H
+#define LOCKD_XDR4_H
+
+#include <linux/fs.h>
+#include <linux/nfs.h>
+#include <linux/sunrpc/xdr.h>
+#include <linux/lockd/xdr.h>
+
+extern u32	nlm4_granted, nlm4_lck_denied, nlm4_lck_denied_nolocks,
+		nlm4_lck_blocked, nlm4_lck_denied_grace_period, nlm4_deadlock,
+		nlm4_rofs, nlm4_stale_fh, nlm4_fbig, nlm4_failed;
+
+#define NLMSVC_XDRSIZE		sizeof(struct nlm_args)
+
+int	nlm4svc_decode_testargs(struct svc_rqst *, u32 *, struct nlm_args *);
+int	nlm4svc_encode_testres(struct svc_rqst *, u32 *, struct nlm_res *);
+int	nlm4svc_decode_lockargs(struct svc_rqst *, u32 *, struct nlm_args *);
+int	nlm4svc_decode_cancargs(struct svc_rqst *, u32 *, struct nlm_args *);
+int	nlm4svc_decode_unlockargs(struct svc_rqst *, u32 *, struct nlm_args *);
+int	nlm4svc_encode_res(struct svc_rqst *, u32 *, struct nlm_res *);
+int	nlm4svc_decode_res(struct svc_rqst *, u32 *, struct nlm_res *);
+int	nlm4svc_encode_void(struct svc_rqst *, u32 *, void *);
+int	nlm4svc_decode_void(struct svc_rqst *, u32 *, void *);
+int	nlm4svc_decode_shareargs(struct svc_rqst *, u32 *, struct nlm_args *);
+int	nlm4svc_encode_shareres(struct svc_rqst *, u32 *, struct nlm_res *);
+int	nlm4svc_decode_notify(struct svc_rqst *, u32 *, struct nlm_args *);
+int	nlm4svc_decode_reboot(struct svc_rqst *, u32 *, struct nlm_reboot *);
+/*
+int	nlmclt_encode_testargs(struct rpc_rqst *, u32 *, struct nlm_args *);
+int	nlmclt_encode_lockargs(struct rpc_rqst *, u32 *, struct nlm_args *);
+int	nlmclt_encode_cancargs(struct rpc_rqst *, u32 *, struct nlm_args *);
+int	nlmclt_encode_unlockargs(struct rpc_rqst *, u32 *, struct nlm_args *);
+ */
+
+#endif /* LOCKD_XDR4_H */
Index: oldkernel/linux/include/linux/nfsd/const.h
diff -u linux/include/linux/nfsd/const.h:1.1.1.1 linux/include/linux/nfsd/const.h:1.2
--- linux/include/linux/nfsd/const.h:1.1.1.1	Wed May 31 12:33:49 2000
+++ linux/include/linux/nfsd/const.h	Fri Jul  7 15:36:48 2000
@@ -1,21 +1,20 @@
 /*
- * include/linux/nfsd/nfsconst.h
+ * include/linux/nfsd/const.h
  *
  * Various constants related to NFS.
  *
- * Copyright (C) 1995 Olaf Kirch <okir@monad.swb.de>
+ * Copyright (C) 1995-1997 Olaf Kirch <okir@monad.swb.de>
  */
 
-#ifndef __NFSCONST_H__
-#define __NFSCONST_H__
+#ifndef _LINUX_NFSD_CONST_H
+#define _LINUX_NFSD_CONST_H
 
-#include <linux/limits.h>
-#include <linux/types.h>
-#include <linux/unistd.h>
-#include <linux/dirent.h>
-#include <linux/fs.h>
 #include <linux/nfs.h>
 
+#define NFS_FHSIZE		32
+#define NFS_MAXPATHLEN		1024
+#define NFS_MAXNAMLEN		255
+
 /*
  * Maximum protocol version supported by knfsd
  */
@@ -33,7 +32,7 @@
 
 #define NFS3_MAXPATHLEN		PATH_MAX
 #define NFS3_MAXNAMLEN		NAME_MAX
-#define NFS3_FHSIZE		NFS_FHSIZE
+#define NFS3_FHSIZE		64
 #define NFS3_COOKIEVERFSIZE	8
 #define NFS3_CREATEVERFSIZE	8
 #define NFS3_WRITEVERFSIZE	8
@@ -44,43 +43,6 @@
 # define NFS_SUPER_MAGIC	0x6969
 #endif
 
-/*
- * NFS stats. The good thing with these values is that NFSv3 errors are
- * a superset of NFSv2 errors (with the exception of NFSERR_WFLUSH which
- * no-one uses anyway), so we can happily mix code as long as we make sure
- * no NFSv3 errors are returned to NFSv2 clients.
- */
-#define NFS_OK			0		/* v2 v3 */
-#define NFSERR_PERM		1		/* v2 v3 */
-#define NFSERR_NOENT		2		/* v2 v3 */
-#define NFSERR_IO		5		/* v2 v3 */
-#define NFSERR_NXIO		6		/* v2 v3 */
-#define NFSERR_ACCES		13		/* v2 v3 */
-#define NFSERR_EXIST		17		/* v2 v3 */
-#define NFSERR_XDEV		18		/*    v3 */
-#define NFSERR_NODEV		19		/* v2 v3 */
-#define NFSERR_NOTDIR		20		/* v2 v3 */
-#define NFSERR_ISDIR		21		/* v2 v3 */
-#define NFSERR_INVAL		22		/*    v3 */
-#define NFSERR_FBIG		27		/* v2 v3 */
-#define NFSERR_NOSPC		28		/* v2 v3 */
-#define NFSERR_ROFS		30		/* v2 v3 */
-#define NFSERR_MLINK		31		/*    v3 */
-#define NFSERR_NAMETOOLONG	63		/* v2 v3 */
-#define NFSERR_NOTEMPTY		66		/* v2 v3 */
-#define NFSERR_DQUOT		69		/* v2 v3 */
-#define NFSERR_STALE		70		/* v2 v3 */
-#define NFSERR_REMOTE		71		/*    v3 */
-#define NFSERR_WFLUSH		99		/* v2    */
-#define NFSERR_BADHANDLE	10001		/*    v3 */
-#define NFSERR_NOT_SYNC		10002		/*    v3 */
-#define NFSERR_BAD_COOKIE	10003		/*    v3 */
-#define NFSERR_NOTSUPP		10004		/*    v3 */
-#define NFSERR_TOOSMALL		10005		/*    v3 */
-#define NFSERR_SERVERFAULT	10006		/*    v3 */
-#define NFSERR_BADTYPE		10007		/*    v3 */
-#define NFSERR_JUKEBOX		10008		/*    v3 */
-
 #endif /* __KERNEL__ */
 
-#endif /* __NFSCONST_H__ */
+#endif /* _LINUX_NFSD_CONST_H */
Index: oldkernel/linux/include/linux/nfsd/export.h
diff -u linux/include/linux/nfsd/export.h:1.1.1.1 linux/include/linux/nfsd/export.h:1.2
--- linux/include/linux/nfsd/export.h:1.1.1.1	Wed May 31 12:33:49 2000
+++ linux/include/linux/nfsd/export.h	Fri Jul  7 15:36:48 2000
@@ -4,16 +4,17 @@
  * Public declarations for NFS exports. The definitions for the
  * syscall interface are in nfsctl.h
  *
- * Copyright (C) 1995, 1996 Olaf Kirch <okir@monad.swb.de>
+ * Copyright (C) 1995-1997 Olaf Kirch <okir@monad.swb.de>
  */
 
 #ifndef NFSD_EXPORT_H
 #define NFSD_EXPORT_H
 
-#include <linux/types.h>
-#include <linux/socket.h>
-#include <linux/in.h>
-#include <linux/fs.h>
+#include <asm/types.h>
+#ifdef __KERNEL__
+# include <linux/types.h>
+# include <linux/in.h>
+#endif
 
 /*
  * Important limits for the exports stuff.
@@ -34,8 +35,10 @@
 #define NFSEXP_UIDMAP		0x0040
 #define NFSEXP_KERBEROS		0x0080		/* not available */
 #define NFSEXP_SUNSECURE	0x0100
-#define NFSEXP_CROSSMNT		0x0200		/* not available */
-#define NFSEXP_ALLFLAGS		0x03FF
+#define NFSEXP_CROSSMNT		0x0200
+#define NFSEXP_NOSUBTREECHECK	0x0400
+#define	NFSEXP_NOAUTHNLM	0x0800		/* Don't authenticate NLM requests - just trust */
+#define NFSEXP_ALLFLAGS		0x0FFF
 
 
 #ifdef __KERNEL__
Index: oldkernel/linux/include/linux/nfsd/nfsd.h
diff -u linux/include/linux/nfsd/nfsd.h:1.1.1.1 linux/include/linux/nfsd/nfsd.h:1.2
--- linux/include/linux/nfsd/nfsd.h:1.1.1.1	Wed May 31 12:33:49 2000
+++ linux/include/linux/nfsd/nfsd.h	Fri Jul  7 15:36:48 2000
@@ -4,7 +4,7 @@
  * Hodge-podge collection of knfsd-related stuff.
  * I will sort this out later.
  *
- * Copyright (C) 1995 Olaf Kirch <okir@monad.swb.de>
+ * Copyright (C) 1995-1997 Olaf Kirch <okir@monad.swb.de>
  */
 
 #ifndef LINUX_NFSD_NFSD_H
@@ -24,18 +24,21 @@
 /*
  * nfsd version
  */
-#define NFSD_VERSION		"0.4"
+#define NFSD_VERSION		"0.5"
 
 #ifdef __KERNEL__
 /*
  * Special flags for nfsd_permission. These must be different from MAY_READ,
  * MAY_WRITE, and MAY_EXEC.
  */
-#define MAY_NOP			0
-#define MAY_SATTR		8
-#define MAY_TRUNC		16
-#if (MAY_SATTR | MAY_TRUNC) & (MAY_READ | MAY_WRITE | MAY_EXEC)
-# error "please use a different value for MAY_SATTR or MAY_TRUNC."
+#define MAY_NOP			0x00000000
+#define MAY_SATTR		0x00000008
+#define MAY_TRUNC		0x00000010
+#define MAY_LOCK		0x00000020
+#define NO_OWNER_OVERRIDE	0x00000040
+
+#if (MAY_SATTR | MAY_TRUNC | MAY_LOCK | NO_OWNER_OVERRIDE) & (MAY_READ | MAY_WRITE | MAY_EXEC)
+# error "please use a different value for MAY_SATTR or MAY_TRUNC or MAY_LOCK or NO_OWNER_OVERRIDE."
 #endif
 #define MAY_CREATE		(MAY_EXEC|MAY_WRITE)
 #define MAY_REMOVE		(MAY_EXEC|MAY_WRITE|MAY_TRUNC)
@@ -61,6 +64,9 @@
  * Procedure table for NFSv2
  */
 extern struct svc_procedure	nfsd_procedures2[];
+#ifdef CONFIG_NFSD_V3
+extern struct svc_procedure	nfsd_procedures3[];
+#endif /* CONFIG_NFSD_V3 */
 extern struct svc_program	nfsd_program;
 
 /*
@@ -74,11 +80,20 @@
 void		nfsd_racache_shutdown(void);
 int		nfsd_lookup(struct svc_rqst *, struct svc_fh *,
 				const char *, int, struct svc_fh *);
+#ifdef CONFIG_NFSD_V3
+int		nfsd_access(struct svc_rqst *, struct svc_fh *, u32 *);
+#endif /* CONFIG_NFSD_V3 */
 int		nfsd_setattr(struct svc_rqst *, struct svc_fh *,
 				struct iattr *);
 int		nfsd_create(struct svc_rqst *, struct svc_fh *,
 				char *name, int len, struct iattr *attrs,
 				int type, dev_t rdev, struct svc_fh *res);
+#ifdef CONFIG_NFSD_V3
+int		nfsd_create_v3(struct svc_rqst *, struct svc_fh *,
+				char *name, int len, struct iattr *attrs,
+				struct svc_fh *res, int createmode,
+				u32 *verifier);
+#endif /* CONFIG_NFSD_V3 */
 int		nfsd_open(struct svc_rqst *, struct svc_fh *, int,
 				int, struct file *);
 void		nfsd_close(struct file *);
@@ -90,7 +105,7 @@
 				char *, int *);
 int		nfsd_symlink(struct svc_rqst *, struct svc_fh *,
 				char *name, int len, char *path, int plen,
-				struct svc_fh *res);
+				struct svc_fh *res, struct iattr *);
 int		nfsd_link(struct svc_rqst *, struct svc_fh *,
 				char *, int, struct svc_fh *);
 int		nfsd_rename(struct svc_rqst *,
@@ -104,9 +119,13 @@
 				unsigned long size);
 int		nfsd_readdir(struct svc_rqst *, struct svc_fh *,
 				loff_t, encode_dent_fn,
-				u32 *buffer, int *countp);
+				u32 *buffer, int *countp, u32 *verf);
 int		nfsd_statfs(struct svc_rqst *, struct svc_fh *,
 				struct statfs *);
+#ifdef CONFIG_NFSD_V3
+int		nfsd_commit(struct svc_rqst *, struct svc_fh *,
+				off_t, unsigned long);
+#endif /* CONFIG_NFSD_V3 */
 int		nfsd_notify_change(struct inode *, struct iattr *);
 int		nfsd_permission(struct svc_export *, struct dentry *, int);
 
@@ -146,6 +165,7 @@
 		nfserr_rofs,
 		nfserr_mlink,
 		nfserr_nametoolong,
+		nfserr_notempty,
 		nfserr_dquot,
 		nfserr_stale,
 		nfserr_remote,
Index: oldkernel/linux/include/linux/nfsd/nfsfh.h
diff -u linux/include/linux/nfsd/nfsfh.h:1.1.1.1 linux/include/linux/nfsd/nfsfh.h:1.2
--- linux/include/linux/nfsd/nfsfh.h:1.1.1.1	Wed May 31 12:33:49 2000
+++ linux/include/linux/nfsd/nfsfh.h	Fri Jul  7 15:36:48 2000
@@ -11,12 +11,15 @@
  * Copyright (C) 1995-1999 Olaf Kirch <okir@monad.swb.de>
  */
 
-#ifndef NFSD_FH_H
-#define NFSD_FH_H
+#ifndef _LINUX_NFSD_FH_H
+#define _LINUX_NFSD_FH_H
 
-#include <linux/types.h>
-#include <linux/string.h>
-#include <linux/fs.h>
+#include <asm/types.h>
+#ifdef __KERNEL__
+# include <linux/types.h>
+# include <linux/string.h>
+# include <linux/fs.h>
+#endif
 #include <linux/nfsd/const.h>
 #include <linux/nfsd/debug.h>
 
@@ -83,12 +86,33 @@
 	struct knfs_fh		fh_handle;	/* FH data */
 	struct dentry *		fh_dentry;	/* validated dentry */
 	struct svc_export *	fh_export;	/* export pointer */
-	size_t			fh_pre_size;	/* size before operation */
-	time_t			fh_pre_mtime;	/* mtime before oper */
-	time_t			fh_pre_ctime;	/* ctime before oper */
-	unsigned long		fh_post_version;/* inode version after oper */
+#ifdef CONFIG_NFSD_V3
+	unsigned char		fh_post_saved;	/* post-op attrs saved */
+	unsigned char		fh_pre_saved;	/* pre-op attrs saved */
+#endif /* CONFIG_NFSD_V3 */
 	unsigned char		fh_locked;	/* inode locked by us */
 	unsigned char		fh_dverified;	/* dentry has been checked */
+
+#ifdef CONFIG_NFSD_V3
+	/* Pre-op attributes saved during fh_lock */
+	__u64			fh_pre_size;	/* size before operation */
+	time_t			fh_pre_mtime;	/* mtime before oper */
+	time_t			fh_pre_ctime;	/* ctime before oper */
+
+	/* Post-op attributes saved in fh_unlock */
+	umode_t			fh_post_mode;	/* i_mode */
+	nlink_t			fh_post_nlink;	/* i_nlink */
+	uid_t			fh_post_uid;	/* i_uid */
+	gid_t			fh_post_gid;	/* i_gid */
+	__u64			fh_post_size;	/* i_size */
+	unsigned long		fh_post_blocks; /* i_blocks */
+	unsigned long		fh_post_blksize;/* i_blksize */
+	kdev_t			fh_post_rdev;	/* i_rdev */
+	time_t			fh_post_atime;	/* i_atime */
+	time_t			fh_post_mtime;	/* i_mtime */
+	time_t			fh_post_ctime;	/* i_ctime */
+#endif /* CONFIG_NFSD_V3 */
+
 } svc_fh;
 
 /*
@@ -105,14 +129,7 @@
 void	fh_compose(struct svc_fh *, struct svc_export *, struct dentry *);
 void	fh_update(struct svc_fh *);
 void	fh_put(struct svc_fh *);
-void	nfsd_fh_flush(kdev_t);
-void	nfsd_fh_init(void);
-void	nfsd_fh_shutdown(void);
-void	nfsd_fh_free(void);
 
-void	expire_all(void);
-void	expire_by_dentry(struct dentry *);
-
 static __inline__ struct svc_fh *
 fh_copy(struct svc_fh *dst, struct svc_fh *src)
 {
@@ -133,7 +150,54 @@
 	return fhp;
 }
 
+#ifdef CONFIG_NFSD_V3
+/*
+ * Fill in the pre_op attr for the wcc data
+ */
+static inline void
+fill_pre_wcc(struct svc_fh *fhp)
+{
+        struct inode    *inode;
+
+        inode = fhp->fh_dentry->d_inode;
+        if (!fhp->fh_pre_saved) {
+                fhp->fh_pre_mtime = inode->i_mtime;
+                        fhp->fh_pre_ctime = inode->i_ctime;
+                        fhp->fh_pre_size  = inode->i_size;
+                        fhp->fh_pre_saved = 1;
+        }
+        fhp->fh_locked = 1;
+}
+
 /*
+ * Fill in the post_op attr for the wcc data
+ */
+static inline void
+fill_post_wcc(struct svc_fh *fhp)
+{
+        struct inode    *inode = fhp->fh_dentry->d_inode;
+
+        if (fhp->fh_post_saved)
+                printk("nfsd: inode locked twice during operation.\n");
+
+        fhp->fh_post_mode       = inode->i_mode;
+        fhp->fh_post_nlink      = inode->i_nlink;
+        fhp->fh_post_uid        = inode->i_uid;
+        fhp->fh_post_gid        = inode->i_gid;
+        fhp->fh_post_size       = inode->i_size;
+        fhp->fh_post_blksize    = inode->i_blksize;
+        fhp->fh_post_blocks     = inode->i_blocks;
+        fhp->fh_post_rdev       = inode->i_rdev;
+        fhp->fh_post_atime      = inode->i_atime;
+        fhp->fh_post_mtime      = inode->i_mtime;
+        fhp->fh_post_ctime      = inode->i_ctime;
+        fhp->fh_post_saved      = 1;
+        fhp->fh_locked          = 0;
+}
+#endif /* CONFIG_NFSD_V3 */
+
+
+/*
  * Lock a file handle/inode
  */
 static inline void
@@ -142,10 +206,9 @@
 	struct dentry	*dentry = fhp->fh_dentry;
 	struct inode	*inode;
 
-	/*
 	dfprintk(FILEOP, "nfsd: fh_lock(%x/%ld) locked = %d\n",
-			SVCFH_DEV(fhp), SVCFH_INO(fhp), fhp->fh_locked);
-	 */
+			SVCFH_DEV(fhp), (long)SVCFH_INO(fhp), fhp->fh_locked);
+
 	if (!fhp->fh_dverified) {
 		printk(KERN_ERR "fh_lock: fh not verified!\n");
 		return;
@@ -158,9 +221,11 @@
 
 	inode = dentry->d_inode;
 	down(&inode->i_sem);
-	if (!fhp->fh_pre_mtime)
-		fhp->fh_pre_mtime = inode->i_mtime;
+#ifdef CONFIG_NFSD_V3
+	fill_pre_wcc(fhp);
+#else
 	fhp->fh_locked = 1;
+#endif /* CONFIG_NFSD_V3 */
 }
 
 /*
@@ -173,21 +238,19 @@
 		printk(KERN_ERR "fh_unlock: fh not verified!\n");
 
 	if (fhp->fh_locked) {
+#ifdef CONFIG_NFSD_V3
+		fill_post_wcc(fhp);
+		up(&fhp->fh_dentry->d_inode->i_sem);
+#else
 		struct dentry *dentry = fhp->fh_dentry;
 		struct inode *inode = dentry->d_inode;
 
-		if (!fhp->fh_post_version)
-			fhp->fh_post_version = inode->i_version;
 		fhp->fh_locked = 0;
 		up(&inode->i_sem);
+#endif /* CONFIG_NFSD_V3 */
 	}
 }
-
-/*
- * This is a long term cache to help find renamed files.
- */
-void add_to_rename_cache(ino_t new_dirino, kdev_t dev, ino_t dirino, ino_t ino);
-
 #endif /* __KERNEL__ */
+
 
-#endif /* NFSD_FH_H */
+#endif /* _LINUX_NFSD_FH_H */
Index: oldkernel/linux/include/linux/nfsd/stats.h
diff -u linux/include/linux/nfsd/stats.h:1.1.1.1 linux/include/linux/nfsd/stats.h:1.2
--- linux/include/linux/nfsd/stats.h:1.1.1.1	Wed May 31 12:33:49 2000
+++ linux/include/linux/nfsd/stats.h	Fri Jul  7 15:36:48 2000
@@ -13,12 +13,11 @@
 	unsigned int	rchits;		/* repcache hits */
 	unsigned int	rcmisses;	/* repcache hits */
 	unsigned int	rcnocache;	/* uncached reqs */
-	unsigned int	fh_cached;	/* dentry cached */
-	unsigned int	fh_valid;	/* dentry validated */
-	unsigned int	fh_fixup;	/* dentry fixup validated */
 	unsigned int	fh_lookup;	/* new lookup required */
+	unsigned int	fh_anon;	
+	unsigned int	fh_nocache_nondir;	
+	unsigned int	fh_nocache_dir;	
 	unsigned int	fh_stale;	/* FH stale error */
-	unsigned int    fh_concurrent;	/* concurrent request */
 };
 
 #ifdef __KERNEL__
Index: oldkernel/linux/include/linux/nfsd/syscall.h
diff -u linux/include/linux/nfsd/syscall.h:1.1.1.1 linux/include/linux/nfsd/syscall.h:1.2
--- linux/include/linux/nfsd/syscall.h:1.1.1.1	Wed May 31 12:33:49 2000
+++ linux/include/linux/nfsd/syscall.h	Fri Jul  7 15:36:48 2000
@@ -3,15 +3,18 @@
  *
  * This file holds all declarations for the knfsd syscall interface.
  *
- * Copyright (C) 1995 Olaf Kirch <okir@monad.swb.de>
+ * Copyright (C) 1995-1997 Olaf Kirch <okir@monad.swb.de>
  */
 
 #ifndef NFSD_SYSCALL_H
 #define NFSD_SYSCALL_H
 
-#include <linux/config.h>
-#include <linux/types.h>
-#include <linux/socket.h>
+#include <asm/types.h>
+#ifdef __KERNEL__
+# include <linux/config.h>
+# include <linux/types.h>
+# include <linux/in.h>
+#endif 
 #include <linux/posix_types.h>
 #include <linux/nfsd/const.h>
 #include <linux/nfsd/export.h>
Index: oldkernel/linux/include/linux/nfsd/xdr3.h
diff -u linux/include/linux/nfsd/xdr3.h:1.1.1.1 linux/include/linux/nfsd/xdr3.h:1.2
--- linux/include/linux/nfsd/xdr3.h:1.1.1.1	Wed May 31 12:33:49 2000
+++ linux/include/linux/nfsd/xdr3.h	Fri Jul  7 15:36:48 2000
@@ -3,17 +3,18 @@
  *
  * XDR types for NFSv3 in nfsd.
  *
- * Copyright (C) 1996, Olaf Kirch <okir@monad.swb.de>
+ * Copyright (C) 1996-1998, Olaf Kirch <okir@monad.swb.de>
  */
 
-#ifndef LINUX_NFSD_XDR3_H
-#define LINUX_NFSD_XDR3_H
+#ifndef _LINUX_NFSD_XDR3_H
+#define _LINUX_NFSD_XDR3_H
 
 #include <linux/nfsd/xdr.h>
 
 struct nfsd3_sattrargs {
 	struct svc_fh		fh;
 	struct iattr		attrs;
+	int			check_guard;
 	time_t			guardtime;
 };
 
@@ -88,7 +89,7 @@
 
 struct nfsd3_readdirargs {
 	struct svc_fh		fh;
-	__u32			cookie;
+	__u64			cookie;
 	__u32			dircount;
 	__u32			count;
 	__u32 *			verf;
@@ -97,7 +98,7 @@
 struct nfsd3_commitargs {
 	struct svc_fh		fh;
 	__u64			offset;
-	__u64			count;
+	__u32			count;
 };
 
 struct nfsd3_attrstat {
@@ -105,7 +106,8 @@
 	struct svc_fh		fh;
 };
 
-struct nfsd3_lookupres  {
+/* LOOKUP, CREATE, MKDIR, SYMLINK, MKNOD */
+struct nfsd3_diropres  {
 	__u32			status;
 	struct svc_fh		dirfh;
 	struct svc_fh		fh;
@@ -137,12 +139,6 @@
 	int			committed;
 };
 
-struct nfsd3_createres {
-	__u32			status;
-	struct svc_fh		dirfh;
-	struct svc_fh		fh;
-};
-
 struct nfsd3_renameres {
 	__u32			status;
 	struct svc_fh		ffh;
@@ -158,10 +154,11 @@
 struct nfsd3_readdirres {
 	__u32			status;
 	struct svc_fh		fh;
-	__u32 *			list_end;
+	int			count;
+	__u32			verf[2];
 };
 
-struct nfsd3_statfsres {
+struct nfsd3_fsstatres {
 	__u32			status;
 	struct statfs		stats;
 	__u32			invarsec;
@@ -184,6 +181,8 @@
 	__u32			status;
 	__u32			p_link_max;
 	__u32			p_name_max;
+	__u32			p_no_trunc;
+	__u32			p_chown_restricted;
 	__u32			p_case_insensitive;
 	__u32			p_case_preserving;
 };
@@ -194,7 +193,7 @@
 };
 
 /* dummy type for release */
-struct nfsd3_fhandle2 {
+struct nfsd3_fhandle_pair {
 	__u32			dummy;
 	struct svc_fh		fh1;
 	struct svc_fh		fh2;
@@ -213,16 +212,15 @@
 	struct nfsd3_linkargs		linkargs;
 	struct nfsd3_symlinkargs	symlinkargs;
 	struct nfsd3_readdirargs	readdirargs;
-	struct nfsd3_lookupres 		lookupres;
+	struct nfsd3_diropres 		diropres;
 	struct nfsd3_accessres		accessres;
 	struct nfsd3_readlinkres	readlinkres;
 	struct nfsd3_readres		readres;
 	struct nfsd3_writeres		writeres;
-	struct nfsd3_createres		createres;
 	struct nfsd3_renameres		renameres;
 	struct nfsd3_linkres		linkres;
 	struct nfsd3_readdirres		readdirres;
-	struct nfsd3_statfsres		statfsres;
+	struct nfsd3_fsstatres		fsstatres;
 	struct nfsd3_fsinfores		fsinfores;
 	struct nfsd3_pathconfres	pathconfres;
 	struct nfsd3_commitres		commitres;
@@ -230,39 +228,87 @@
 
 #define NFS3_SVC_XDRSIZE		sizeof(union nfsd3_xdrstore)
 
-void nfsxdr_init(void);
-
 int nfs3svc_decode_fhandle(struct svc_rqst *, u32 *, struct svc_fh *);
-int nfs3svc_decode_sattr3args(struct svc_rqst *, u32 *,
+int nfs3svc_decode_sattrargs(struct svc_rqst *, u32 *,
 				struct nfsd3_sattrargs *);
-int nfs3svc_decode_dirop3args(struct svc_rqst *, u32 *,
+int nfs3svc_decode_diropargs(struct svc_rqst *, u32 *,
 				struct nfsd3_diropargs *);
-int nfs3svc_decode_read3args(struct svc_rqst *, u32 *,
+int nfs3svc_decode_accessargs(struct svc_rqst *, u32 *,
+				struct nfsd3_accessargs *);
+int nfs3svc_decode_readargs(struct svc_rqst *, u32 *,
 				struct nfsd3_readargs *);
-int nfs3svc_decode_write3args(struct svc_rqst *, u32 *,
+int nfs3svc_decode_writeargs(struct svc_rqst *, u32 *,
 				struct nfsd3_writeargs *);
-int nfs3svc_decode_create3args(struct svc_rqst *, u32 *,
+int nfs3svc_decode_createargs(struct svc_rqst *, u32 *,
+				struct nfsd3_createargs *);
+int nfs3svc_decode_mkdirargs(struct svc_rqst *, u32 *,
 				struct nfsd3_createargs *);
-int nfs3svc_decode_rename3args(struct svc_rqst *, u32 *,
+int nfs3svc_decode_mknodargs(struct svc_rqst *, u32 *,
+				struct nfsd3_mknodargs *);
+int nfs3svc_decode_renameargs(struct svc_rqst *, u32 *,
 				struct nfsd3_renameargs *);
-int nfs3svc_decode_link3args(struct svc_rqst *, u32 *,
+int nfs3svc_decode_linkargs(struct svc_rqst *, u32 *,
 				struct nfsd3_linkargs *);
-int nfs3svc_decode_symlink3args(struct svc_rqst *, u32 *,
+int nfs3svc_decode_symlinkargs(struct svc_rqst *, u32 *,
 				struct nfsd3_symlinkargs *);
-int nfs3svc_decode_readdir3args(struct svc_rqst *, u32 *,
+int nfs3svc_decode_readdirargs(struct svc_rqst *, u32 *,
 				struct nfsd3_readdirargs *);
+int nfs3svc_decode_readdirplusargs(struct svc_rqst *, u32 *,
+				struct nfsd3_readdirargs *);
+int nfs3svc_decode_commitargs(struct svc_rqst *, u32 *,
+				struct nfsd3_commitargs *);
+int nfs3svc_encode_voidres(struct svc_rqst *, u32 *, void *);
+int nfs3svc_encode_attrstat(struct svc_rqst *, u32 *,
+				struct nfsd3_attrstat *);
+int nfs3svc_encode_wccstat(struct svc_rqst *, u32 *,
+				struct nfsd3_attrstat *);
+int nfs3svc_encode_diropres(struct svc_rqst *, u32 *,
+				struct nfsd3_diropres *);
+int nfs3svc_encode_accessres(struct svc_rqst *, u32 *,
+				struct nfsd3_accessres *);
 int nfs3svc_encode_readlinkres(struct svc_rqst *, u32 *,
 				struct nfsd3_readlinkres *);
 int nfs3svc_encode_readres(struct svc_rqst *, u32 *, struct nfsd3_readres *);
-int nfs3svc_encode_statfsres(struct svc_rqst *, u32 *,
-				struct nfsd3_statfsres *);
+int nfs3svc_encode_writeres(struct svc_rqst *, u32 *, struct nfsd3_writeres *);
+int nfs3svc_encode_createres(struct svc_rqst *, u32 *,
+				struct nfsd3_diropres *);
+int nfs3svc_encode_renameres(struct svc_rqst *, u32 *,
+				struct nfsd3_renameres *);
+int nfs3svc_encode_linkres(struct svc_rqst *, u32 *,
+				struct nfsd3_linkres *);
 int nfs3svc_encode_readdirres(struct svc_rqst *, u32 *,
 				struct nfsd3_readdirres *);
+int nfs3svc_encode_fsstatres(struct svc_rqst *, u32 *,
+				struct nfsd3_fsstatres *);
+int nfs3svc_encode_fsinfores(struct svc_rqst *, u32 *,
+				struct nfsd3_fsinfores *);
+int nfs3svc_encode_pathconfres(struct svc_rqst *, u32 *,
+				struct nfsd3_pathconfres *);
+int nfs3svc_encode_commitres(struct svc_rqst *, u32 *,
+				struct nfsd3_commitres *);
+
 int nfs3svc_release_fhandle(struct svc_rqst *, u32 *,
-				struct nfsd_fhandle *);
+				struct nfsd3_attrstat *);
 int nfs3svc_release_fhandle2(struct svc_rqst *, u32 *,
-				struct nfsd3_fhandle2 *);
+				struct nfsd3_fhandle_pair *);
 int nfs3svc_encode_entry(struct readdir_cd *, const char *name,
-				int namlen, unsigned long offset, ino_t ino);
+				int namlen, off_t offset, ino_t ino);
+int nfs3svc_encode_entry_plus(struct readdir_cd *, const char *name,
+				int namlen, off_t offset, ino_t ino);
+
+#ifdef __KERNEL__
+
+/*
+ * This is needed in nfs_readdir for encoding NFS3 directory cookies.
+ */
+static inline u32 *
+enc64(u32 *p, u64 val)
+{
+	*p++ = htonl(val >> 32);
+	*p++ = htonl(val & 0xffffffff);
+	return p;
+}
+
+#endif /* __KERNEL__ */
 
-#endif /* LINUX_NFSD_XDR3_H */
+#endif /* _LINUX_NFSD_XDR3_H */
Index: oldkernel/linux/include/linux/sunrpc/auth.h
diff -u linux/include/linux/sunrpc/auth.h:1.1.1.1 linux/include/linux/sunrpc/auth.h:1.2
--- linux/include/linux/sunrpc/auth.h:1.1.1.1	Wed May 31 12:33:49 2000
+++ linux/include/linux/sunrpc/auth.h	Fri Jul  7 15:36:48 2000
@@ -64,10 +64,10 @@
 	struct rpc_auth *	(*create)(struct rpc_clnt *);
 	void			(*destroy)(struct rpc_auth *);
 
-	struct rpc_cred *	(*crcreate)(struct rpc_task *);
+	struct rpc_cred *	(*crcreate)(int);
 	void			(*crdestroy)(struct rpc_cred *);
 
-	int			(*crmatch)(struct rpc_task *, struct rpc_cred*);
+	int			(*crmatch)(struct rpc_cred *, int);
 	u32 *			(*crmarshal)(struct rpc_task *, u32 *, int);
 	int			(*crrefresh)(struct rpc_task *);
 	u32 *			(*crvalidate)(struct rpc_task *, u32 *);
@@ -83,10 +83,14 @@
 int			rpcauth_unregister(struct rpc_authops *);
 struct rpc_auth *	rpcauth_create(unsigned int, struct rpc_clnt *);
 void			rpcauth_destroy(struct rpc_auth *);
-struct rpc_cred *	rpcauth_lookupcred(struct rpc_task *);
+struct rpc_cred *	rpcauth_lookupcred(struct rpc_auth *, int);
+struct rpc_cred *	rpcauth_bindcred(struct rpc_task *);
 void			rpcauth_holdcred(struct rpc_task *);
-void			rpcauth_releasecred(struct rpc_task *);
-int			rpcauth_matchcred(struct rpc_task *, struct rpc_cred *);
+void			rpcauth_releasecred(struct rpc_auth *,
+					    struct rpc_cred *);
+void			rpcauth_unbindcred(struct rpc_task *);
+int			rpcauth_matchcred(struct rpc_auth *,
+					  struct rpc_cred *, int);
 u32 *			rpcauth_marshcred(struct rpc_task *, u32 *);
 u32 *			rpcauth_checkverf(struct rpc_task *, u32 *);
 int			rpcauth_refreshcred(struct rpc_task *);
Index: oldkernel/linux/include/linux/sunrpc/clnt.h
diff -u linux/include/linux/sunrpc/clnt.h:1.1.1.1 linux/include/linux/sunrpc/clnt.h:1.2
--- linux/include/linux/sunrpc/clnt.h:1.1.1.1	Wed May 31 12:33:49 2000
+++ linux/include/linux/sunrpc/clnt.h	Fri Jul  7 15:36:48 2000
@@ -111,21 +111,23 @@
 void		rpc_getport(struct rpc_task *, struct rpc_clnt *);
 int		rpc_register(u32, u32, int, unsigned short, int *);
 
-int		rpc_call(struct rpc_clnt *clnt, u32 proc,
-				void *argp, void *resp, int flags);
-int		rpc_call_async(struct rpc_task *task, u32 proc,
-				void *argp, void *resp, int flags);
-void		rpc_call_setup(struct rpc_task *task, u32 proc,
-				void *argp, void *resp, int flags);
-int		rpc_do_call(struct rpc_clnt *clnt, u32 proc,
-				void *argp, void *resp, int flags,
-				rpc_action callback, void *clntdata);
+void		rpc_call_setup(struct rpc_task *, struct rpc_message *, int);
+
+int		rpc_call_async(struct rpc_clnt *clnt, struct rpc_message *msg,
+			       int flags, rpc_action callback, void *clntdata);
+int		rpc_call_sync(struct rpc_clnt *clnt, struct rpc_message *msg,
+			      int flags);
 void		rpc_restart_call(struct rpc_task *);
 void		rpc_clnt_sigmask(struct rpc_clnt *clnt, sigset_t *oldset);
 void		rpc_clnt_sigunmask(struct rpc_clnt *clnt, sigset_t *oldset);
 
-#define rpc_call(clnt, proc, argp, resp, flags)	\
-		rpc_do_call(clnt, proc, argp, resp, flags, NULL, NULL)
+static __inline__
+int rpc_call(struct rpc_clnt *clnt, u32 proc, void *argp, void *resp, int flags)
+{
+	struct rpc_message msg = { proc, argp, resp, NULL };
+	return rpc_call_sync(clnt, &msg, flags);
+}
+		
 
 extern __inline__ void
 rpc_set_timeout(struct rpc_clnt *clnt, unsigned int retr, unsigned long incr)
Index: oldkernel/linux/include/linux/sunrpc/sched.h
diff -u linux/include/linux/sunrpc/sched.h:1.1.1.1 linux/include/linux/sunrpc/sched.h:1.2
--- linux/include/linux/sunrpc/sched.h:1.1.1.1	Wed May 31 12:33:49 2000
+++ linux/include/linux/sunrpc/sched.h	Fri Jul  7 15:36:48 2000
@@ -11,6 +11,7 @@
 
 #include <linux/timer.h>
 #include <linux/tqueue.h>
+#include <asm/errno.h>
 #include <linux/sunrpc/types.h>
 
 /*
@@ -20,6 +21,16 @@
 #undef  CONFIG_RPC_FASTSCHED
 
 /*
+ * This is the actual RPC procedure call info.
+ */
+struct rpc_message {
+	__u32			rpc_proc;	/* Procedure number */
+	void *			rpc_argp;	/* Arguments */
+	void *			rpc_resp;	/* Result */
+	struct rpc_cred *	rpc_cred;	/* Credentials */
+};
+
+/*
  * This is the RPC task struct
  */
 struct rpc_task {
@@ -32,17 +43,14 @@
 	struct rpc_task *	tk_prev_task;	/* global list of tasks */
 	struct rpc_clnt *	tk_client;	/* RPC client */
 	struct rpc_rqst *	tk_rqstp;	/* RPC request */
-	struct rpc_cred *	tk_cred;	/* RPC credentials */
 	int			tk_status;	/* result of last operation */
 	struct rpc_wait_queue *	tk_rpcwait;	/* RPC wait queue we're on */
 
 	/*
 	 * RPC call state
 	 */
-	__u32			tk_proc;	/* procedure number */
+	struct rpc_message	tk_msg;		/* RPC call info */
 	__u32 *			tk_buffer;	/* XDR buffer */
-	void *			tk_argp;	/* argument storage */
-	void *			tk_resp;	/* result storage */
 	__u8			tk_garb_retry,
 				tk_cred_retry,
 				tk_suid_retry;
@@ -55,6 +63,7 @@
 	void			(*tk_callback)(struct rpc_task *);
 	void			(*tk_action)(struct rpc_task *);
 	void			(*tk_exit)(struct rpc_task *);
+	void			(*tk_release)(struct rpc_task *);
 	void *			tk_calldata;
 
 	/*
@@ -66,6 +75,10 @@
 	struct wait_queue *	tk_wait;	/* sync: sleep on this q */
 	unsigned long		tk_timeout;	/* timeout for rpc_sleep() */
 	unsigned short		tk_flags;	/* misc flags */
+	unsigned short		tk_lock;	/* Task lock counter */
+	unsigned int		tk_wakeup   : 1,/* Task waiting to wake up */
+				tk_sleeping : 1,/* Task is truly asleep */
+				tk_active   : 1;/* Task has been activated */
 #ifdef RPC_DEBUG
 	unsigned short		tk_pid;		/* debugging aid */
 #endif
@@ -89,6 +102,7 @@
 #define RPC_TASK_ROOTCREDS	0x0100		/* force root creds */
 #define RPC_TASK_DYNAMIC	0x0200		/* task was kmalloc'ed */
 #define RPC_TASK_KILLED		0x0400		/* task was killed */
+#define RPC_TASK_PRIORITY	0x0800		/* resched when waking up */
 #define RPC_TASK_NFSWRITE	0x1000		/* an NFS writeback */
 
 #define RPC_IS_RUNNING(t)	((t)->tk_flags & RPC_TASK_RUNNING)
@@ -99,6 +113,8 @@
 #define RPC_DO_CALLBACK(t)	((t)->tk_flags & RPC_TASK_CALLBACK)
 #define RPC_DO_ROOTOVERRIDE(t)	((t)->tk_flags & RPC_TASK_ROOTCREDS)
 #define RPC_ASSASSINATED(t)	((t)->tk_flags & RPC_TASK_KILLED)
+#define RPC_IS_SLEEPING(t)	((t)->tk_sleeping)
+#define RPC_IS_ACTIVATED(t)	((t)->tk_active)
 
 /*
  * RPC synchronization objects
@@ -110,6 +126,7 @@
 #endif
 };
 
+#define RPC_WAITQ_EMPTY(q)	((q)->task == NULL)
 #ifndef RPC_DEBUG
 # define RPC_INIT_WAITQ(name)	((struct rpc_wait_queue) { NULL })
 #else
@@ -125,29 +142,29 @@
 					rpc_action exitfunc, int flags);
 void		rpc_release_task(struct rpc_task *);
 void		rpc_killall_tasks(struct rpc_clnt *);
-void		rpc_execute(struct rpc_task *);
+int		rpc_execute(struct rpc_task *);
 void		rpc_run_child(struct rpc_task *parent, struct rpc_task *child,
 					rpc_action action);
-int		rpc_add_wait_queue(struct rpc_wait_queue *, struct rpc_task *);
+int		rpc_add_wait_queue(struct rpc_wait_queue *,
+				     struct rpc_task *);
 void		rpc_remove_wait_queue(struct rpc_task *);
 void		rpc_sleep_on(struct rpc_wait_queue *, struct rpc_task *,
-					rpc_action action, rpc_action timer);
-void		rpc_cond_wait(struct rpc_wait_queue *, struct rpc_task *,
-					unsigned char *,
 					rpc_action action, rpc_action timer);
+void		rpc_sleep_locked(struct rpc_wait_queue *, struct rpc_task *,
+				 rpc_action action, rpc_action timer);
+void		rpc_add_timer(struct rpc_task *task, rpc_action timer);
 void		rpc_wake_up_task(struct rpc_task *);
 void		rpc_wake_up(struct rpc_wait_queue *);
 struct rpc_task *rpc_wake_up_next(struct rpc_wait_queue *);
 void		rpc_wake_up_status(struct rpc_wait_queue *, int);
-void		rpc_add_timer(struct rpc_task *, rpc_action);
-void		rpc_del_timer(struct rpc_task *);
+int		rpc_lock_task(struct rpc_task *);
+void		rpc_unlock_task(struct rpc_task *);
 void		rpc_delay(struct rpc_task *, unsigned long);
 void *		rpc_allocate(unsigned int flags, unsigned int);
 void		rpc_free(void *);
 int		rpciod_up(void);
 void		rpciod_down(void);
 void		rpciod_wake_up(void);
-void		rpciod_tcp_dispatcher(void);
 #ifdef RPC_DEBUG
 void		rpc_show_tasks(void);
 #endif
@@ -165,11 +182,18 @@
 	task->tk_action = NULL;
 }
 
+extern __inline__ void
+rpc_kill(struct rpc_task *task, int status)
+{
+        rpc_exit(task, status);
+        rpc_wake_up_task(task);
+}
+
 #ifdef RPC_DEBUG
 extern __inline__ char *
 rpc_qname(struct rpc_wait_queue *q)
 {
-	return q->name? q->name : "unknown";
+	return q? (q->name? q->name : "unknown") : "none";
 }
 #endif
 
Index: oldkernel/linux/include/linux/sunrpc/svc.h
diff -u linux/include/linux/sunrpc/svc.h:1.1.1.1 linux/include/linux/sunrpc/svc.h:1.2
--- linux/include/linux/sunrpc/svc.h:1.1.1.1	Wed May 31 12:33:49 2000
+++ linux/include/linux/sunrpc/svc.h	Fri Jul  7 15:36:48 2000
@@ -91,6 +91,8 @@
 	struct svc_rqst *	rq_next;
 	struct svc_sock *	rq_sock;	/* socket */
 	struct sockaddr_in	rq_addr;	/* peer address */
+	char			rq_mesg [sizeof (struct cmsghdr)
+					 + sizeof (struct in_pktinfo)];
 	int			rq_addrlen;
 
 	struct svc_serv *	rq_server;	/* RPC service definition */
Index: oldkernel/linux/include/linux/sunrpc/types.h
diff -u linux/include/linux/sunrpc/types.h:1.1.1.1 linux/include/linux/sunrpc/types.h:1.2
--- linux/include/linux/sunrpc/types.h:1.1.1.1	Wed May 31 12:33:49 2000
+++ linux/include/linux/sunrpc/types.h	Fri Jul  7 15:36:48 2000
@@ -58,6 +58,7 @@
 	}
 	if (*q == item)
 		*q = next;
+	item->prev = item->next = 0;
 }
 
 #define rpc_insert_list(q, i) \
Index: oldkernel/linux/include/linux/sunrpc/xdr.h
diff -u linux/include/linux/sunrpc/xdr.h:1.1.1.1 linux/include/linux/sunrpc/xdr.h:1.2
--- linux/include/linux/sunrpc/xdr.h:1.1.1.1	Wed May 31 12:33:49 2000
+++ linux/include/linux/sunrpc/xdr.h	Fri Jul  7 15:36:48 2000
@@ -1,7 +1,7 @@
 /*
  * include/linux/sunrpc/xdr.h
  *
- * Copyright (C) 1995, 1996 Olaf Kirch <okir@monad.swb.de>
+ * Copyright (C) 1995-1997 Olaf Kirch <okir@monad.swb.de>
  */
 
 #ifndef _SUNRPC_XDR_H_
@@ -59,13 +59,32 @@
 /*
  * Miscellaneous XDR helper functions
  */
-u32 *	xdr_encode_string(u32 *p, const char *s);
+u32 *	xdr_encode_string(u32 *p, const char *s, int len);
 u32 *	xdr_decode_string(u32 *p, char **sp, int *lenp, int maxlen);
 u32 *	xdr_encode_netobj(u32 *p, const struct xdr_netobj *);
 u32 *	xdr_decode_netobj(u32 *p, struct xdr_netobj *);
 u32 *	xdr_decode_netobj_fixed(u32 *p, void *obj, unsigned int len);
 
 /*
+ * Decode 64bit quantities (NFSv3 support)
+ */
+static inline u32 *
+xdr_encode_hyper(u32 *p, __u64 val)
+{
+	*p++ = htonl(val >> 32);
+	*p++ = htonl(val & 0xFFFFFFFF);
+	return p;
+}
+
+static inline u32 *
+xdr_decode_hyper(u32 *p, __u64 *valp)
+{
+	*valp  = ((__u64) ntohl(*p++)) << 32;
+	*valp |= ntohl(*p++);
+	return p;
+}
+
+/*
  * Adjust iovec to reflect end of xdr'ed data (RPC client XDR)
  */
 static inline int
@@ -73,6 +92,9 @@
 {
 	return iov->iov_len = ((u8 *) p - (u8 *) iov->iov_base);
 }
+
+void xdr_shift_iovec(struct iovec *, int, size_t);
+void xdr_zero_iovec(struct iovec *, int, size_t);
 
 #endif /* __KERNEL__ */
 
Index: oldkernel/linux/include/linux/sunrpc/xprt.h
diff -u linux/include/linux/sunrpc/xprt.h:1.1.1.1 linux/include/linux/sunrpc/xprt.h:1.2
--- linux/include/linux/sunrpc/xprt.h:1.1.1.1	Wed May 31 12:33:49 2000
+++ linux/include/linux/sunrpc/xprt.h	Fri Jul  7 15:36:48 2000
@@ -12,12 +12,13 @@
 #include <linux/uio.h>
 #include <linux/socket.h>
 #include <linux/in.h>
+#include <linux/list.h>
 #include <linux/sunrpc/sched.h>
 
 /*
  * Maximum number of iov's we use.
  */
-#define MAX_IOVEC	8
+#define MAX_IOVEC	10
 
 /*
  * The transport code maintains an estimate on the maximum number of out-
@@ -44,10 +45,10 @@
 #define RPC_MAXCWND		(RPC_MAXCONG * RPC_CWNDSCALE)
 #define RPC_INITCWND		RPC_CWNDSCALE
 #define RPCXPRT_CONGESTED(xprt) \
-	((xprt)->cong >= ((xprt)->nocong? RPC_MAXCWND : (xprt)->cwnd))
+	((xprt)->cong >= (xprt)->cwnd)
 
 /* Default timeout values */
-#define RPC_MAX_UDP_TIMEOUT	(6*HZ)
+#define RPC_MAX_UDP_TIMEOUT	(60*HZ)
 #define RPC_MAX_TCP_TIMEOUT	(600*HZ)
 
 /* RPC call and reply header size as number of 32bit words (verifier
@@ -96,8 +97,7 @@
 	struct rpc_task *	rq_task;	/* RPC task data */
 	__u32			rq_xid;		/* request XID */
 	struct rpc_rqst *	rq_next;	/* free list */
-	unsigned char		rq_gotit;	/* reply received */
-	unsigned char		rq_damaged;	/* being received */
+	unsigned char		rq_damaged;	/* reply being received */
 
 	/*
 	 * For authentication (e.g. auth_des)
@@ -122,14 +122,6 @@
 #define rq_rlen			rq_rcv_buf.io_len
 
 struct rpc_xprt {
-	struct rpc_xprt *	link;		/* list of all clients */
-	struct rpc_xprt *	rx_pending;	/* receive pending list */
-	struct rpc_xprt *	tx_pending;	/* transmit pending list */
-	
-	int 			rx_pending_flag;/* are we on the rcv pending list ? */
-	int 			tx_pending_flag;/* are we on the xmit pending list ? */
-
-	struct file *		file;		/* VFS layer */
 	struct socket *		sock;		/* BSD socket layer */
 	struct sock *		inet;		/* INET layer */
 
@@ -147,9 +139,9 @@
 	struct rpc_wait_queue	reconn;		/* waiting for reconnect */
 	struct rpc_rqst *	free;		/* free slots */
 	struct rpc_rqst		slot[RPC_MAXREQS];
-	unsigned char		connected;	/* TCP: connected */
-	unsigned char		write_space;	/* TCP: can send */
-	unsigned int		shutdown   : 1,	/* being shut down */
+	unsigned int		connected  : 1,	/* TCP: connected */
+				write_space: 1,	/* TCP: can send */
+				shutdown   : 1,	/* being shut down */
 				nocong	   : 1,	/* no congestion control */
 				stream     : 1,	/* TCP */
 				tcp_more   : 1,	/* more record fragments */
@@ -158,40 +150,32 @@
 	/*
 	 * State of TCP reply receive stuff
 	 */
-	union {					/* record marker & XID */
-		u32		header[2];
-		u8 		data[8];
-	}			tcp_recm;
-	struct rpc_rqst *	tcp_rqstp;
-	struct iovec		tcp_iovec[MAX_IOVEC];
-	u32			tcp_total;	/* overall record length */
-	u32			tcp_reclen;	/* fragment length */
-	u32			tcp_offset;	/* fragment offset */
-	u32			tcp_copied;	/* copied to request */
+	u32			tcp_recm;	/* Fragment header */
+	u32			tcp_xid;	/* Current XID */
+	unsigned int		tcp_reclen,	/* fragment length */
+				tcp_offset,	/* fragment offset */
+				tcp_copied;	/* copied to request */
+	struct list_head	rx_pending;	/* receive pending list */
 
 	/*
-	 * TCP send stuff
+	 * Send stuff
 	 */
-	struct rpc_iov		snd_buf;	/* send buffer */
 	struct rpc_task *	snd_task;	/* Task blocked in send */
-	u32			snd_sent;	/* Bytes we have sent */
 
 
 	void			(*old_data_ready)(struct sock *, int);
 	void			(*old_state_change)(struct sock *);
 	void			(*old_write_space)(struct sock *);
+
+	struct wait_queue *	cong_wait;
 };
-#define tcp_reclen		tcp_recm.header[0]
-#define tcp_xid			tcp_recm.header[1]
 
 #ifdef __KERNEL__
 
-struct rpc_xprt *	xprt_create(struct file *socket,
-					struct sockaddr_in *addr,
-					struct rpc_timeout *toparms);
 struct rpc_xprt *	xprt_create_proto(int proto, struct sockaddr_in *addr,
 					struct rpc_timeout *toparms);
 int			xprt_destroy(struct rpc_xprt *);
+void			xprt_shutdown(struct rpc_xprt *);
 void			xprt_default_timeout(struct rpc_timeout *, int);
 void			xprt_set_timeout(struct rpc_timeout *, unsigned int,
 					unsigned long);
@@ -202,6 +186,23 @@
 int			xprt_adjust_timeout(struct rpc_timeout *);
 void			xprt_release(struct rpc_task *);
 void			xprt_reconnect(struct rpc_task *);
+int			xprt_clear_backlog(struct rpc_xprt *);
+void			__rpciod_tcp_dispatcher(void);
+
+extern struct list_head	rpc_xprt_pending;
+
+static inline
+int xprt_tcp_pending(void)
+{
+	return !list_empty(&rpc_xprt_pending);
+}
+
+static inline
+void rpciod_tcp_dispatcher(void)
+{
+	if (xprt_tcp_pending())
+		__rpciod_tcp_dispatcher();
+}
 
 #endif /* __KERNEL__*/
 
Index: oldkernel/linux/init/main.c
diff -u linux/init/main.c:1.7 linux/init/main.c:1.8
--- linux/init/main.c:1.7	Thu Jun  1 17:12:57 2000
+++ linux/init/main.c	Fri Jul  7 15:36:48 2000
@@ -66,6 +66,8 @@
 #error sorry, your GCC is too old. It builds incorrect kernels.
 #endif
 
+char * root_mount_data = NULL;
+
 extern char _stext, _etext;
 extern char *linux_banner;
 
@@ -623,6 +625,14 @@
 	ROOT_DEV = name_to_kdev_t(line);
 }
 
+static void root_data_setup(char *line, int *num)
+{
+	static char buffer[128];
+
+	strcpy(buffer, line);
+	root_mount_data = buffer;
+}
+
 /*
  * List of kernel command line parameters. The first table lists parameters
  * which are subject to values parsing (leading numbers are converted to
@@ -988,6 +998,7 @@
 
 static struct kernel_param raw_params[] __initdata = {
 	{ "root=", root_dev_setup },
+	{ "rootflags=", root_data_setup },
 #ifdef CONFIG_ROOT_NFS
 	{ "nfsroot=", nfs_root_setup },
 	{ "nfsaddrs=", ip_auto_config_setup },
Index: oldkernel/linux/kernel/capability.c
diff -u linux/kernel/capability.c:1.1.1.1 linux/kernel/capability.c:1.2
--- linux/kernel/capability.c:1.1.1.1	Wed May 31 12:33:48 2000
+++ linux/kernel/capability.c	Fri Jul  7 15:36:48 2000
@@ -8,6 +8,8 @@
 #include <linux/mm.h>
 #include <asm/uaccess.h>
 
+kernel_cap_t cap_bset = CAP_INIT_EFF_SET;
+
 /* Note: never hold tasklist_lock while spinning for this one */
 spinlock_t task_capability_lock;
 
@@ -16,8 +18,6 @@
  * capability set pointers may be NULL -- indicating that that set is
  * uninteresting and/or not to be changed.
  */
-
-kernel_cap_t cap_bset = CAP_FULL_SET;
 
 asmlinkage int sys_capget(cap_user_header_t header, cap_user_data_t dataptr)
 {
Index: oldkernel/linux/kernel/kmod.c
diff -u linux/kernel/kmod.c:1.1.1.1 linux/kernel/kmod.c:1.2
--- linux/kernel/kmod.c:1.1.1.1	Wed May 31 12:33:48 2000
+++ linux/kernel/kmod.c	Fri Jul  7 15:36:49 2000
@@ -73,9 +73,8 @@
 	/* Drop the "current user" thing */
 	free_uid(current);
 
-	/* Give kmod all privileges.. */
+	/* Give kmod all effective privileges.. */
 	current->uid = current->euid = current->fsuid = 0;
-	cap_set_full(current->cap_inheritable);
 	cap_set_full(current->cap_effective);
 
 	/* Allow execve args to be in kernel space. */
Index: oldkernel/linux/kernel/ksyms.c
diff -u linux/kernel/ksyms.c:1.2 linux/kernel/ksyms.c:1.3
--- linux/kernel/ksyms.c:1.2	Thu Jun  1 15:03:09 2000
+++ linux/kernel/ksyms.c	Fri Jul  7 15:36:49 2000
@@ -39,6 +39,7 @@
 #include <linux/poll.h>
 #include <linux/mm.h>
 #include <linux/capability.h>
+#include <linux/buffer.h>
 
 #if defined(CONFIG_PROC_FS)
 #include <linux/proc_fs.h>
@@ -64,6 +65,7 @@
 extern int request_dma(unsigned int dmanr, char * deviceID);
 extern void free_dma(unsigned int dmanr);
 extern spinlock_t dma_spin_lock;
+extern void (*journal_remove_checkpoint)(struct buffer_head *);
 
 #ifdef CONFIG_MODVERSIONS
 const struct module_symbol __export_Using_Versions
@@ -83,7 +85,7 @@
 EXPORT_SYMBOL(get_options);
 
 /* process memory management */
-EXPORT_SYMBOL(do_mmap_pgoff);
+EXPORT_SYMBOL(do_mmap);
 EXPORT_SYMBOL(do_munmap);
 EXPORT_SYMBOL(exit_mm);
 EXPORT_SYMBOL(exit_files);
@@ -124,6 +126,7 @@
 EXPORT_SYMBOL(igrab);
 EXPORT_SYMBOL(iunique);
 EXPORT_SYMBOL(iget);
+EXPORT_SYMBOL(iget4);
 EXPORT_SYMBOL(iget_in_use);
 EXPORT_SYMBOL(iput);
 EXPORT_SYMBOL(__namei);
@@ -154,6 +157,7 @@
 EXPORT_SYMBOL(invalidate_inode_pages);
 EXPORT_SYMBOL(truncate_inode_pages);
 EXPORT_SYMBOL(fsync_dev);
+EXPORT_SYMBOL(unix_permission);
 EXPORT_SYMBOL(permission);
 EXPORT_SYMBOL(inode_setattr);
 EXPORT_SYMBOL(inode_change_ok);
@@ -196,6 +200,12 @@
 EXPORT_SYMBOL(ROOT_DEV);
 EXPORT_SYMBOL(inode_generation_count);
 
+EXPORT_SYMBOL(page_cache_size);
+EXPORT_SYMBOL(page_hash_table);
+EXPORT_SYMBOL(page_hash_mask);
+EXPORT_SYMBOL(page_hash_bits);
+EXPORT_SYMBOL(__wait_on_page);
+
 #if !defined(CONFIG_NFSD) && defined(CONFIG_NFSD_MODULE)
 EXPORT_SYMBOL(do_nfsservctl);
 #endif
@@ -238,6 +248,18 @@
 EXPORT_SYMBOL(max_sectors);
 EXPORT_SYMBOL(max_segments);
 EXPORT_SYMBOL(max_readahead);
+EXPORT_SYMBOL(show_buffers);
+
+/* JFS debugging only: */
+EXPORT_SYMBOL(jfs_prelock_buffer_check);
+EXPORT_SYMBOL(jfs_preclean_buffer_check);
+EXPORT_SYMBOL(dummy_jfs_function);
+EXPORT_SYMBOL(journal_remove_checkpoint);
+EXPORT_SYMBOL(get_unused_buffer_head);
+EXPORT_SYMBOL(put_unused_buffer_head);
+EXPORT_SYMBOL(sync_buffers);
+EXPORT_SYMBOL(wake_up_process);
+EXPORT_SYMBOL(end_buffer_io_sync);
 
 /* tty routines */
 EXPORT_SYMBOL(tty_hangup);
@@ -252,6 +274,9 @@
 /* filesystem registration */
 EXPORT_SYMBOL(register_filesystem);
 EXPORT_SYMBOL(unregister_filesystem);
+
+/* Mount table */
+EXPORT_SYMBOL(vfsmnt_replace_mt_de);
 
 /* executable format registration */
 EXPORT_SYMBOL(register_binfmt);
Index: oldkernel/linux/kernel/printk.c
diff -u linux/kernel/printk.c:1.1.1.1 linux/kernel/printk.c:1.2
--- linux/kernel/printk.c:1.1.1.1	Wed May 31 12:33:48 2000
+++ linux/kernel/printk.c	Fri Jul  7 15:36:49 2000
@@ -22,7 +22,7 @@
 
 #include <asm/uaccess.h>
 
-#define LOG_BUF_LEN	(16384)
+#define LOG_BUF_LEN	(65536)
 #define LOG_BUF_MASK	(LOG_BUF_LEN-1)
 
 static char buf[1024];
Index: oldkernel/linux/kernel/sysctl.c
diff -u linux/kernel/sysctl.c:1.1.1.1 linux/kernel/sysctl.c:1.2
--- linux/kernel/sysctl.c:1.1.1.1	Wed May 31 12:33:48 2000
+++ linux/kernel/sysctl.c	Fri Jul  7 15:36:49 2000
@@ -22,6 +22,8 @@
 #include <linux/smp_lock.h>
 #include <linux/init.h>
 #include <linux/sysrq.h>
+#include <linux/fs.h>
+#include <linux/jfs.h>
 
 #include <asm/uaccess.h>
 
@@ -280,6 +282,10 @@
 	 0644, NULL, &proc_dointvec},
 	{FS_DENTRY, "dentry-state", &dentry_stat, 6*sizeof(int),
 	 0444, NULL, &proc_dointvec},
+#if defined(CONFIG_EXT3_FS) && defined(JFS_DEBUG)
+	{KERN_SHMMAX, "jfs-debug", &jfs_enable_debug, sizeof (int),
+	 0644, NULL, &proc_dointvec},
+#endif
 	{0}
 };
 
@@ -821,8 +827,11 @@
 int proc_dointvec_bset(ctl_table *table, int write, struct file *filp,
 			void *buffer, size_t *lenp)
 {
+	if (!capable(CAP_SYS_MODULE)) {
+		return -EPERM;
+	}
 	return do_proc_dointvec(table,write,filp,buffer,lenp,1,
-		(current->pid == 1) ? OP_SET : OP_AND);
+				(current->pid == 1) ? OP_SET : OP_AND);
 }
 
 
Index: oldkernel/linux/ksymoops-0.7c/Makefile
diff -u linux/ksymoops-0.7c/Makefile:1.2 linux/ksymoops-0.7c/Makefile:1.3
--- linux/ksymoops-0.7c/Makefile:1.2	Thu Jun  1 15:09:40 2000
+++ linux/ksymoops-0.7c/Makefile	Fri Jul  7 15:36:49 2000
@@ -70,7 +70,7 @@
 	rm -f core *.o $(PROGS)
 
 install: all
-	$(INSTALL) -d -o root -g root $(INSTALL_PREFIX)/bin
-	$(INSTALL) -s -o root -g root ksymoops $(INSTALL_PREFIX)/bin
-	$(INSTALL) -d -o root -g root $(INSTALL_PREFIX)/man/man8
-	$(INSTALL) -o root -g root ksymoops.8 $(INSTALL_PREFIX)/man/man8
+	$(INSTALL) -d $(INSTALL_PREFIX)/bin
+	$(INSTALL) -s ksymoops $(INSTALL_PREFIX)/bin
+	$(INSTALL) -d $(INSTALL_PREFIX)/man/man8
+	$(INSTALL) ksymoops.8 $(INSTALL_PREFIX)/man/man8
Index: oldkernel/linux/ksymoops-0.7c/ksymoops.h
diff -u linux/ksymoops-0.7c/ksymoops.h:1.1.1.1 linux/ksymoops-0.7c/ksymoops.h:1.2
--- linux/ksymoops-0.7c/ksymoops.h:1.1.1.1	Wed May 31 12:46:02 2000
+++ linux/ksymoops-0.7c/ksymoops.h	Fri Jul  7 15:36:49 2000
@@ -240,3 +240,26 @@
 
 /* modutils interface */
 #define MODUTILS_PREFIX "__insmod_"
+
+/* It is very tricky with versioning. */
+#define strip_symbol(s) \
+  ({ char *__naked; \
+     int __len, __end, __i; \
+     __naked = (s); \
+     __len = strlen (__naked); \
+     if (__len > 10 && !strncmp(__naked + __len - 10, "_R", 2)) \
+       __end = __len - 10; \
+     else if (__len > 13 && !strncmp(__naked + __len - 13, "_Rsmp", 5)) \
+       __end = __len - 13; \
+     else \
+       __end = 0; \
+     if (__end) { \
+       for (__i = __len - 8; __i < __len; __i++) \
+	 if (!isxdigit(__naked[__i])) \
+	   break; \
+	 if (__i == __len) __len = __end; \
+	 __naked = alloca (__len + 1); \
+	 memcpy (__naked, (s), __len); \
+	 __naked [__len] = '\0'; \
+     } \
+     __naked; })
Index: oldkernel/linux/ksymoops-0.7c/map.c
diff -u linux/ksymoops-0.7c/map.c:1.1.1.1 linux/ksymoops-0.7c/map.c:1.2
--- linux/ksymoops-0.7c/map.c:1.1.1.1	Wed May 31 12:46:02 2000
+++ linux/ksymoops-0.7c/map.c	Fri Jul  7 15:36:49 2000
@@ -10,6 +10,8 @@
 
 #include "ksymoops.h"
 #include <malloc.h>
+#include <string.h>
+#include <ctype.h>
 
 /* Read the symbols from System.map */
 void read_system_map(const char *system_map)
@@ -64,6 +66,8 @@
     SYMBOL *s1, *s2, **sdrop = precedence == 1 ? &s2 : &s1;
     const SYMBOL_SET **ssdrop = precedence == 1 ? &ss2 : &ss1;
     static char const procname[] = "compare_maps";
+    char *name;
+    int old_start;
 
     if (!(ss1->used && ss2->used))
 	return;
@@ -75,7 +79,17 @@
 	s1 = ss1->symbol+i;
 	if (!(s1->keep))
 	    continue;
+
+	old_start = start;
 	s2 = find_symbol_name(ss2, s1->name, &start);
+	if (!s2 && ss2->source) {
+	    name = strip_symbol (s1->name);
+	    if (name != s1->name) {
+		start = old_start;
+		s2 = find_symbol_name(ss2, name, &start);
+	    }
+	}
+
 	if (!s2) {
 	    /* Some types only appear in nm output, not in things
 	     * like System.map.  Silently ignore them.
Index: oldkernel/linux/ksymoops-0.7c/symbol.c
diff -u linux/ksymoops-0.7c/symbol.c:1.1.1.1 linux/ksymoops-0.7c/symbol.c:1.2
--- linux/ksymoops-0.7c/symbol.c:1.1.1.1	Wed May 31 12:46:02 2000
+++ linux/ksymoops-0.7c/symbol.c	Fri Jul  7 15:36:49 2000
@@ -13,6 +13,7 @@
 #include <malloc.h>
 #include <stdlib.h>
 #include <string.h>
+#include <ctype.h>
 
 /* Initialise a symbol source */
 void ss_init(SYMBOL_SET *ss, const char *msg)
@@ -298,11 +299,14 @@
     SYMBOL *c = (SYMBOL *) a;
     SYMBOL *d = (SYMBOL *) b;
     int i;
+    char *cnaked, *dnaked;
 
     /* obsolete symbols to the top */
     if (c->keep != d->keep)
 	return(d->keep - c->keep);
-    if ((i = strcmp(c->name, d->name)))
+    cnaked = strip_symbol (c->name);
+    dnaked = strip_symbol (d->name);
+    if ((i = strcmp(cnaked, dnaked)))
 	return(i);
     if (c->address > d->address)
 	return(1);
Index: oldkernel/linux/lib/vsprintf.c
diff -u linux/lib/vsprintf.c:1.2 linux/lib/vsprintf.c:1.3
--- linux/lib/vsprintf.c:1.2	Thu Jun  1 15:03:09 2000
+++ linux/lib/vsprintf.c	Fri Jul  7 15:36:49 2000
@@ -67,107 +67,11 @@
 #define LARGE	64		/* use 'ABCDEF' instead of 'abcdef' */
 
 #define do_div(n,base) ({ \
-  int __res; \
-  __res = ((unsigned long) n) % (unsigned) base; \
-  n = ((unsigned long) n) / (unsigned) base; \
-  __res; })
-
-#if BITS_PER_LONG < 64
-
-/* Note: do_ldiv assumes that unsigned long long is a 64 bit long
- * and unsigned long is at least a 32 bits long.
- */
-#define do_ldiv(n, base) \
-({ \
-	unsigned long long value = n; \
-	unsigned long long leftover; \
-	unsigned long temp; \
-	unsigned long result_div1, result_div2, result_div3, result_mod; \
-\
-	temp = value >> 32; \
-	result_div1 = temp/(base); \
-	result_mod = temp%(base); \
-\
-	temp = (result_mod << 24) | ((value >> 8) & 0xFFFFFF); \
-	result_div2 = temp/(base); \
-	result_mod = temp%(base); \
-\
-	temp = (result_mod << 8) | (value & 0xFF); \
-	result_div3 = temp/(base); \
-	result_mod = temp%(base);\
-\
-	leftover = ((unsigned long long)result_div1 << 32) | \
-		((unsigned long long)result_div2 << 8) | (result_div3); \
-\
-	n = leftover; \
-	result_mod; \
-})
+int __res; \
+__res = ((unsigned long) n) % (unsigned) base; \
+n = ((unsigned long) n) / (unsigned) base; \
+__res; })
 
-
-static char * lnumber(char * str, long long num, int base, int size,
-		      int precision, int type)
-{
-	char c,sign,tmp[66];
-	const char *digits="0123456789abcdef";
-	int i;
-
-	if (type & LARGE)
-		digits = "0123456789ABCDEF";
-	if (type & LEFT)
-		type &= ~ZEROPAD;
-	if (base < 2 || base > 36)
-		return 0;
-	c = (type & ZEROPAD) ? '0' : ' ';
-	sign = 0;
-	if (type & SIGN) {
-		if (num < 0) {
-			sign = '-';
-			num = -num;
-			size--;
-		} else if (type & PLUS) {
-			sign = '+';
-			size--;
-		} else if (type & SPACE) {
-			sign = ' ';
-			size--;
-		}
-	}
-	if (type & SPECIAL) {
-		if (base == 16)
-			size -= 2;
-	}
-	i = 0;
-	if (num == 0)
-		tmp[i++]='0';
-	else while (num != 0)
-		tmp[i++] = digits[do_ldiv(num,base)];
-	if (i > precision)
-		precision = i;
-	size -= precision;
-	if (!(type&(ZEROPAD+LEFT)))
-		while(size-->0)
-			*str++ = ' ';
-	if (sign)
-		*str++ = sign;
-	if (type & SPECIAL) {
-		if (base==16) {
-			*str++ = '0';
-			*str++ = digits[33];
-		}
-	}
-	if (!(type & LEFT))
-		while (size-- > 0)
-			*str++ = c;
-	while (i < precision--)
-		*str++ = '0';
-	while (i-- > 0)
-		*str++ = tmp[i];
-	while (size-- > 0)
-		*str++ = ' ';
-	return str;
-}
-#endif
-
 static char * number(char * str, long num, int base, int size, int precision
 	,int type)
 {
@@ -303,10 +207,7 @@
 		/* get the conversion qualifier */
 		qualifier = -1;
 		if (*fmt == 'h' || *fmt == 'l' || *fmt == 'L') {
-			if (*fmt == 'l' && qualifier == 'l')
-				qualifier = 'L';
-			else
-				qualifier = *fmt;
+			qualifier = *fmt;
 			++fmt;
 		}
 
@@ -389,22 +290,7 @@
 				--fmt;
 			continue;
 		}
-		if (qualifier == 'L') {
-
-#if BITS_PER_LONG < 64
-		/* 64-bit printout in 32-bit systems !!
-		   Needed at some point for 64-bit file offsets and
-		   mmap() reporting functions. */
-
-			unsigned long long lnum;
-			lnum = va_arg(args, unsigned long long);
-			str = lnumber(str, lnum, base, field_width,
-				      precision, flags);
-			continue;
-#else
-			num = va_arg(args, unsigned long); /* 64-bit longs..*/
-#endif
-		} else if (qualifier == 'l')
+		if (qualifier == 'l')
 			num = va_arg(args, unsigned long);
 		else if (qualifier == 'h') {
 			num = (unsigned short) va_arg(args, int);
Index: oldkernel/linux/mm/bigmem.c
diff -u linux/mm/bigmem.c:1.1 linux/mm/bigmem.c:1.2
--- linux/mm/bigmem.c:1.1	Thu Jun  1 16:47:27 2000
+++ linux/mm/bigmem.c	Fri Jul  7 15:36:49 2000
@@ -60,7 +60,7 @@
 				kunmap(vaddr, KM_WRITE);
 
 				/* Preserve the caching of the swap_entry. */
-				bigmem_page->index = page->index;
+				bigmem_page->offset = page->offset;
 
 				/* We can just forget the old page since 
 				   we stored its data into the new
Index: oldkernel/linux/mm/filemap.c
diff -u linux/mm/filemap.c:1.3 linux/mm/filemap.c:1.4
--- linux/mm/filemap.c:1.3	Thu Jun  1 16:47:27 2000
+++ linux/mm/filemap.c	Fri Jul  7 15:36:50 2000
@@ -88,7 +88,7 @@
  * Truncate the page cache at a set offset, removing the pages
  * that are beyond that offset (and zeroing out partial pages).
  */
-void truncate_inode_pages(struct inode * inode, loff_t start)
+void truncate_inode_pages(struct inode * inode, unsigned long start)
 {
 	struct page ** p;
 	struct page * page;
@@ -96,10 +96,10 @@
 repeat:
 	p = &inode->i_pages;
 	while ((page = *p) != NULL) {
-		loff_t loffset = pgoff2loff(page->index);
+		unsigned long offset = page->offset;
 
 		/* page wholly truncated - free it */
-		if (loffset >= start) {
+		if (offset >= start) {
 			if (PageLocked(page)) {
 				wait_on_page(page);
 				goto repeat;
@@ -115,10 +115,9 @@
 			continue;
 		}
 		p = &page->next;
-		loffset = start - loffset;
+		offset = start - offset;
 		/* partial truncate, clear end of page */
-		if (loffset < PAGE_CACHE_SIZE) {
-			unsigned int  offset  = loffset; /* truncate ok */
+		if (offset < PAGE_CACHE_SIZE) {
 			unsigned long address = page_address(page);
 			memset((void *) (offset + address), 0, PAGE_CACHE_SIZE - offset);
 			flush_page_to_ram(address);
@@ -188,8 +187,7 @@
 		 * were to be marked referenced..
 		 */
 		if (PageSwapCache(page)) {
-			if (referenced &&
-			    swap_count(pgoff2ulong(page->index)) != 1)
+			if (referenced && swap_count(page->offset) != 1)
 				continue;
 			delete_from_swap_cache(page);
 			return 1;
@@ -240,12 +238,11 @@
  * memory maps.  --sct
  */
 
-void update_vm_cache_conditional(struct inode * inode, loff_t pos, const char * buf, int count, unsigned long source_address)
+void update_vm_cache_conditional(struct inode * inode, unsigned long pos, const char * buf, int count, unsigned long source_address)
 {
 	unsigned long offset, len;
-	pgoff_t pgoff = loff2pgoff(pos);
 
-	offset = ((unsigned long)pos & ~PAGE_CACHE_MASK);
+	offset = (pos & ~PAGE_CACHE_MASK);
 	pos = pos & PAGE_CACHE_MASK;
 	len = PAGE_CACHE_SIZE - offset;
 	do {
@@ -253,13 +250,14 @@
 
 		if (len > count)
 			len = count;
-		page = find_page(inode, pgoff);
+		page = find_page(inode, pos);
 		if (page) {
 			char *dest = (char*) (offset + page_address(page));
 
 			if ((unsigned long)dest != source_address) {
 				wait_on_page(page);
 				memcpy(dest, buf, len);
+				flush_dcache_page(page_address(page));
 			}
 			page_cache_release(page);
 		}
@@ -271,56 +269,41 @@
 	} while (count);
 }
 
-void update_vm_cache(struct inode * inode, loff_t pos, const char * buf, int count)
+void update_vm_cache(struct inode * inode, unsigned long pos, const char * buf, int count)
 {
 	update_vm_cache_conditional(inode, pos, buf, count, 0);
 }
 
 
-static inline void add_to_page_cache(struct page * page,
-				     struct inode * inode,
-				     pgoff_t pgoff,
-				     struct page **hash)
-{
-	atomic_inc(&page->count);
-	page->flags = (page->flags & ~((1 << PG_uptodate) | (1 << PG_error))) | (1 << PG_referenced);
-	page->index = pgoff;
-	add_page_to_inode_queue(inode, page);
-	__add_page_to_hash_queue(page, hash);
-}
-
 /*
  * Try to read ahead in the file. "page_cache" is a potentially free page
  * that we could use for the cache (if it is 0 we can try to create one,
  * this is all overlapped with the IO on the previous page finishing anyway)
  */
 static unsigned long try_to_read_ahead(struct file * file,
-				       pgoff_t pgoff, unsigned long page_cache)
+				unsigned long offset, unsigned long page_cache)
 {
 	struct inode *inode = file->f_dentry->d_inode;
-	pgoff_t pg_size;
-
-	/* Calculate file size in 'pages' -- if even one byte (according to
-	   the 'i_size') exceeds the final page-size block, round up. */
-	pg_size = loff2pgoff(inode->i_size+(PAGE_SIZE-1));
+	struct page * page;
+	struct page ** hash;
 
-	if (!page_cache) {
+	offset &= PAGE_CACHE_MASK;
+	switch (page_cache) {
+	case 0:
 		page_cache = page_cache_alloc();
 		if (!page_cache)
-			return 0; /* Can't allocate! */
-	}
-	/* Ok, we have a page, make sure it is in the page cache */
-	if (pgoff2ulong(pgoff) < pgoff2ulong(pg_size)) {
-		struct page * page;
-		struct page ** hash;
-		hash = page_hash(inode, pgoff);
-		page = __find_page(inode, pgoff, *hash);
+			break;
+	default:
+		if (offset >= inode->i_size)
+			break;
+		hash = page_hash(inode, offset);
+		page = __find_page(inode, offset, *hash);
 		if (!page) {
 			/*
 			 * Ok, add the new page to the hash-queues...
 			 */
 			page = page_cache_entry(page_cache);
-			add_to_page_cache(page, inode, pgoff, hash);
+			add_to_page_cache(page, inode, offset, hash);
 			inode->i_op->readpage(file, page);
 			page_cache = 0;
 		}
@@ -374,11 +357,11 @@
 
 #define PROFILE_MAXREADCOUNT 1000
 
-static u_long total_reada;
-static u_long total_async;
-static u_long total_ramax;
-static u_long total_ralen;
-static u_long total_rawin;
+static unsigned long total_reada;
+static unsigned long total_async;
+static unsigned long total_ramax;
+static unsigned long total_ralen;
+static unsigned long total_rawin;
 
 static void profile_readahead(int async, struct file *filp)
 {
@@ -486,13 +469,13 @@
 
 static inline unsigned long generic_file_readahead(int reada_ok,
 	struct file * filp, struct inode * inode,
-	loff_t ppos, struct page * page, unsigned long page_cache)
+	unsigned long ppos, struct page * page, unsigned long page_cache)
 {
-	loff_t max_ahead, ahead;
-	loff_t raend;
+	unsigned long max_ahead, ahead;
+	unsigned long raend;
 	int max_readahead = get_max_readahead(inode);
 
-	raend = filp->f_raend & PAGE_CACHE_MASK_loff;
+	raend = filp->f_raend & PAGE_CACHE_MASK;
 	max_ahead = 0;
 
 /*
@@ -550,7 +533,7 @@
 	ahead = 0;
 	while (ahead < max_ahead) {
 		ahead += PAGE_CACHE_SIZE;
-		page_cache = try_to_read_ahead(filp, loff2pgoff(raend + ahead),
+		page_cache = try_to_read_ahead(filp, raend + ahead,
 						page_cache);
 	}
 /*
@@ -616,17 +599,14 @@
 {
 	struct dentry *dentry = filp->f_dentry;
 	struct inode *inode = dentry->d_inode;
-	size_t page_cache;
-	pgoff_t pgpos;
-	loff_t pos, posp;
+	size_t pos, pgpos, page_cache;
 	int reada_ok;
 	int max_readahead = get_max_readahead(inode);
 
 	page_cache = 0;
 
 	pos = *ppos;
-	posp = pos & PAGE_CACHE_MASK_loff;
-	pgpos = loff2pgoff(pos);
+	pgpos = pos & PAGE_CACHE_MASK;
 /*
  * If the current position is outside the previous read-ahead window, 
  * we reset the current read-ahead context and set read ahead max to zero
@@ -634,7 +614,7 @@
  * otherwise, we assume that the file accesses are sequential enough to
  * continue read-ahead.
  */
-	if (posp > filp->f_raend || posp + filp->f_rawin < filp->f_raend) {
+	if (pgpos > filp->f_raend || pgpos + filp->f_rawin < filp->f_raend) {
 		reada_ok = 0;
 		filp->f_raend = 0;
 		filp->f_ralen = 0;
@@ -650,12 +630,12 @@
  * Then, at least MIN_READAHEAD if read ahead is ok,
  * and at most MAX_READAHEAD in all cases.
  */
-	if (pos + desc->count <= (loff_t)(PAGE_CACHE_SIZE >> 1)) {
+	if (pos + desc->count <= (PAGE_CACHE_SIZE >> 1)) {
 		filp->f_ramax = 0;
 	} else {
-		loff_t needed;
+		unsigned long needed;
 
-		needed = ((pos + desc->count) & PAGE_CACHE_MASK) - posp;
+		needed = ((pos + desc->count) & PAGE_CACHE_MASK) - pgpos;
 
 		if (filp->f_ramax < needed)
 			filp->f_ramax = needed;
@@ -668,7 +648,6 @@
 
 	for (;;) {
 		struct page *page, **hash;
-		pgoff_t pgoff;
 
 		if (pos >= inode->i_size)
 			break;
@@ -676,9 +655,8 @@
 		/*
 		 * Try to find the data in the page cache..
 		 */
-		pgoff = loff2pgoff(pos);
-		hash = page_hash(inode, pgoff);
-		page = __find_page(inode, pgoff, *hash);
+		hash = page_hash(inode, pos & PAGE_CACHE_MASK);
+		page = __find_page(inode, pos & PAGE_CACHE_MASK, *hash);
 		if (!page)
 			goto no_cached_page;
 
@@ -691,7 +669,7 @@
  * the page has been rewritten.
  */
 		if (PageUptodate(page) || PageLocked(page))
-			page_cache = generic_file_readahead(reada_ok, filp, inode, pos & PAGE_CACHE_MASK_loff, page, page_cache);
+			page_cache = generic_file_readahead(reada_ok, filp, inode, pos & PAGE_CACHE_MASK, page, page_cache);
 		else if (reada_ok && filp->f_ramax > MIN_READAHEAD)
 				filp->f_ramax = MIN_READAHEAD;
 
@@ -709,8 +687,8 @@
 		unsigned long offset, nr;
 
 		offset = pos & ~PAGE_CACHE_MASK;
-		nr = PAGE_CACHE_SIZE - offset; /* small value */
-		if ((loff_t)nr > (inode->i_size - pos))
+		nr = PAGE_CACHE_SIZE - offset;
+		if (nr > inode->i_size - pos)
 			nr = inode->i_size - pos;
 
 		/*
@@ -750,7 +728,7 @@
 		 */
 		page = page_cache_entry(page_cache);
 		page_cache = 0;
-		add_to_page_cache(page, inode, pgoff, hash);
+		add_to_page_cache(page, inode, pos & PAGE_CACHE_MASK, hash);
 
 		/*
 		 * Error handling is tricky. If we get a read error,
@@ -831,26 +809,10 @@
 ssize_t generic_file_read(struct file * filp, char * buf, size_t count, loff_t *ppos)
 {
 	ssize_t retval;
-	struct inode *inode = filp->f_dentry->d_inode;
 
 	retval = -EFAULT;
 	if (access_ok(VERIFY_WRITE, buf, count)) {
 		retval = 0;
-
-		/* L-F-S spec 2.2.1.25: */
-		if (count && !(filp->f_flags & O_LARGEFILE) &&
-		    S_ISREG(inode->i_mode) &&
-		    (*ppos < inode->i_size) &&
-		    (*ppos >= 0x7ffffffeULL)) /* pos@2G forbidden */
-			return -EOVERFLOW;
-		if (count && !(filp->f_flags & O_LARGEFILE) &&
-		    S_ISREG(inode->i_mode) &&
-		    (*ppos < inode->i_size) &&
-		    (*ppos + count >= 0x7fffffffULL)) {
-			/* Read only until end of allowed region */
-			count = LONG_MAX - *ppos;
-		}
-
 		if (count) {
 			read_descriptor_t desc;
 
@@ -992,25 +954,20 @@
 	struct file * file = area->vm_file;
 	struct dentry * dentry = file->f_dentry;
 	struct inode * inode = dentry->d_inode;
-	loff_t offset;
-	pgoff_t pgoff, reada;
-	int i;
+	unsigned long offset, reada, i;
 	struct page * page, **hash;
 	unsigned long old_page, new_page;
 
 	new_page = 0;
-	offset = ((loff_t)((address & PAGE_MASK) - area->vm_start) +
-		  area->vm_offset);
-
+	offset = (address & PAGE_MASK) - area->vm_start + area->vm_offset;
 	if (offset >= inode->i_size && (area->vm_flags & VM_SHARED) && area->vm_mm == current->mm)
 		goto no_page;
 
 	/*
 	 * Do we have something in the page cache already?
 	 */
-	pgoff = loff2pgoff(offset);
-	hash = page_hash(inode, pgoff);
-	page = __find_page(inode, pgoff, *hash);
+	hash = page_hash(inode, offset);
+	page = __find_page(inode, offset, *hash);
 	if (!page)
 		goto no_cached_page;
 
@@ -1061,12 +1018,11 @@
 	/*
 	 * Try to read in an entire cluster at once.
 	 */
-	reada   = loff2pgoff(offset);
-	/* Mask lowest  'page_cluster'  worth of the lowest bits */
-	reada   = ulong2pgoff(pgoff2ulong(reada) & ((~(0UL)) << page_cluster));
+	reada   = offset;
+	reada >>= PAGE_CACHE_SHIFT + page_cluster;
+	reada <<= PAGE_CACHE_SHIFT + page_cluster;
 
-	for (i = 1 << page_cluster; i > 0;
-	     --i, reada = ulong2pgoff(pgoff2ulong(reada)+1))
+	for (i = 1 << page_cluster; i > 0; --i, reada += PAGE_CACHE_SIZE)
 		new_page = try_to_read_ahead(file, reada, new_page);
 
 	if (!new_page)
@@ -1080,7 +1036,7 @@
 	 * cache.. The page we just got may be useful if we
 	 * can't share, so don't get rid of it here.
 	 */
-	page = find_page(inode, pgoff);
+	page = find_page(inode, offset);
 	if (page)
 		goto found_page;
 
@@ -1089,7 +1045,7 @@
 	 */
 	page = page_cache_entry(new_page);
 	new_page = 0;
-	add_to_page_cache(page, inode, pgoff, hash);
+	add_to_page_cache(page, inode, offset, hash);
 
 	if (inode->i_op->readpage(file, page) != 0)
 		goto failure;
@@ -1138,10 +1094,10 @@
  * if the disk is full.
  */
 static inline int do_write_page(struct inode * inode, struct file * file,
-				const char * page, loff_t offset)
+	const char * page, unsigned long offset)
 {
 	int retval;
-	loff_t size;
+	unsigned long size;
 	loff_t loff = offset;
 	mm_segment_t old_fs;
 
@@ -1165,7 +1121,7 @@
 }
 
 static int filemap_write_page(struct vm_area_struct * vma,
-			      loff_t offset,
+			      unsigned long offset,
 			      unsigned long page,
 			      int wait)
 {
@@ -1211,7 +1167,7 @@
  */
 int filemap_swapout(struct vm_area_struct * vma, struct page * page)
 {
-	return filemap_write_page(vma, pgoff2loff(page->index), page_address(page), 0);
+	return filemap_write_page(vma, page->offset, page_address(page), 0);
 }
 
 static inline int filemap_sync_pte(pte_t * ptep, struct vm_area_struct *vma,
@@ -1510,7 +1466,7 @@
 {
 	struct dentry	*dentry = file->f_dentry; 
 	struct inode	*inode = dentry->d_inode; 
-	loff_t		pos = *ppos;
+	unsigned long	pos = *ppos;
 	unsigned long	limit = current->rlim[RLIMIT_FSIZE].rlim_cur;
 	struct page	*page, **hash;
 	unsigned long	page_cache = 0;
@@ -1536,7 +1492,7 @@
 	 * Check whether we've reached the file size limit.
 	 */
 	status = -EFBIG;
-	if (limit != RLIM_INFINITY && pos >= limit) {
+	if (pos >= limit) {
 		send_sig(SIGXFSZ, current, 0);
 		goto out;
 	}
@@ -1546,21 +1502,20 @@
 	 * Check whether to truncate the write,
 	 * and send the signal if we do.
 	 */
-	if (limit != RLIM_INFINITY && count > limit - pos) {
+	if (count > limit - pos) {
 		send_sig(SIGXFSZ, current, 0);
 		count = limit - pos;
 	}
 
 	while (count) {
-		unsigned long bytes, offset;
-		pgoff_t pgpos = loff2pgoff(pos);
-		char * dest;
+		unsigned long bytes, pgpos, offset;
 
 		/*
 		 * Try to find the page in the cache. If it isn't there,
 		 * allocate a free page.
 		 */
-		offset = ((unsigned long)pos & ~PAGE_CACHE_MASK);
+		offset = (pos & ~PAGE_CACHE_MASK);
+		pgpos = pos & PAGE_CACHE_MASK;
 		bytes = PAGE_CACHE_SIZE - offset;
 		if (bytes > count)
 			bytes = count;
@@ -1589,12 +1544,7 @@
 		 * the writer needs to increment the page use counts until he
 		 * is done with the page.
 		 */
-		dest = (char *) page_address(page) + offset;
-		if (dest != buf) /* See comment in update_vm_cache_cond. */
-			bytes -= copy_from_user(dest, buf, bytes);
-		status = -EFAULT;
-		if (bytes)
-			status = inode->i_op->updatepage(file, page, offset, bytes, sync);
+		status = inode->i_op->updatepage(file, page, buf, offset, bytes, sync);
 
 		/* Mark it unlocked again and drop the page.. */
 		clear_bit(PG_locked, &page->flags);
@@ -1630,14 +1580,15 @@
  * Note: we don't have to worry about races here, as the caller
  * is holding the inode semaphore.
  */
-unsigned long get_cached_page(struct inode * inode, pgoff_t pgoff, int new)
+unsigned long get_cached_page(struct inode * inode, unsigned long offset,
+				int new)
 {
 	struct page * page;
 	struct page ** hash;
 	unsigned long page_cache = 0;
 
-	hash = page_hash(inode, pgoff);
-	page = __find_page(inode, pgoff, *hash);
+	hash = page_hash(inode, offset);
+	page = __find_page(inode, offset, *hash);
 	if (!page) {
 		if (!new)
 			goto out;
@@ -1646,7 +1597,7 @@
 			goto out;
 		clear_page(page_cache);
 		page = page_cache_entry(page_cache);
-		add_to_page_cache(page, inode, pgoff, hash);
+		add_to_page_cache(page, inode, offset, hash);
 	}
 	if (atomic_read(&page->count) != 2)
 		printk(KERN_ERR "get_cached_page: page count=%d\n",
Index: oldkernel/linux/mm/memory.c
diff -u linux/mm/memory.c:1.4 linux/mm/memory.c:1.5
--- linux/mm/memory.c:1.4	Thu Jun  1 16:47:27 2000
+++ linux/mm/memory.c	Fri Jul  7 15:36:50 2000
@@ -822,7 +822,7 @@
 	case 2:
 		if (!PageSwapCache(page_map))
 			break;
-		if (swap_count(pgoff2ulong(page_map->index)) != 1)
+		if (swap_count(page_map->offset) != 1)
 			break;
 		delete_from_swap_cache(page_map);
 		/* FallThrough */
@@ -913,7 +913,7 @@
  * between the file and the memory map for a potential last
  * incomplete page.  Ugly, but necessary.
  */
-void vmtruncate(struct inode * inode, loff_t offset)
+void vmtruncate(struct inode * inode, unsigned long offset)
 {
 	struct vm_area_struct * mpnt;
 
Index: oldkernel/linux/mm/mmap.c
diff -u linux/mm/mmap.c:1.2 linux/mm/mmap.c:1.3
--- linux/mm/mmap.c:1.2	Thu Jun  1 15:03:09 2000
+++ linux/mm/mmap.c	Fri Jul  7 15:36:50 2000
@@ -169,12 +169,11 @@
 #undef _trans
 }
 
-unsigned long do_mmap_pgoff(struct file * file, unsigned long addr, unsigned long len,
-	unsigned long prot, unsigned long flags, unsigned long pg_off)
+unsigned long do_mmap(struct file * file, unsigned long addr, unsigned long len,
+	unsigned long prot, unsigned long flags, unsigned long off)
 {
 	struct mm_struct * mm = current->mm;
 	struct vm_area_struct * vma;
-	loff_t off = (loff_t)pg_off << PAGE_SHIFT;
 	int error;
 
 	if (file && (!file->f_op || !file->f_op->mmap))
@@ -833,8 +832,7 @@
 		 * the offsets must be contiguous..
 		 */
 		if ((mpnt->vm_file != NULL) || (mpnt->vm_flags & VM_SHM)) {
-			loff_t off = (prev->vm_offset +
-				      (loff_t)(prev->vm_end - prev->vm_start));
+			unsigned long off = prev->vm_offset+prev->vm_end-prev->vm_start;
 			if (off != mpnt->vm_offset)
 				continue;
 		}
Index: oldkernel/linux/mm/page_io.c
diff -u linux/mm/page_io.c:1.2 linux/mm/page_io.c:1.3
--- linux/mm/page_io.c:1.2	Thu Jun  1 15:03:09 2000
+++ linux/mm/page_io.c	Fri Jul  7 15:36:50 2000
@@ -99,7 +99,7 @@
 		 * as if it were: we are not allowed to manipulate the inode
 		 * hashing for locked pages.
 		 */
-		if (pgoff2ulong(page->index) != entry) {
+		if (page->offset != entry) {
 			printk ("swap entry mismatch");
 			return;
 		}
@@ -252,8 +252,8 @@
 		printk("VM: swap page is not in swap cache\n");
 		return;
 	}
-	if (pgoff2ulong(page->index) != entry) {
-		printk ("VM: swap entry mismatch");
+	if (page->offset != entry) {
+		printk ("swap entry mismatch");
 		return;
 	}
 	rw_swap_page_base(rw, entry, page, wait);
@@ -278,12 +278,12 @@
 		printk ("VM: read_swap_page: page already in page cache!\n");
 		return;
 	}
-	page->inode     = &swapper_inode;
-	page->index = ulong2pgoff(entry);
+	page->inode = &swapper_inode;
+	page->offset = entry;
 	atomic_inc(&page->count);	/* Protect from shrink_mmap() */
 	rw_swap_page(rw, entry, buffer, 1);
 	atomic_dec(&page->count);
-	page->inode     = 0;
+	page->inode = 0;
 	clear_bit(PG_swap_cache, &page->flags);
 }
 
Index: oldkernel/linux/mm/slab.c
diff -u linux/mm/slab.c:1.1.1.1 linux/mm/slab.c:1.2
--- linux/mm/slab.c:1.1.1.1	Wed May 31 12:33:48 2000
+++ linux/mm/slab.c	Fri Jul  7 15:36:50 2000
@@ -125,7 +125,7 @@
  * SLAB_SELFTEST	- 1 to perform a few tests, mainly for development.
  */
 #define		SLAB_MGMT_CHECKS	1
-#define		SLAB_DEBUG_SUPPORT	0
+#define		SLAB_DEBUG_SUPPORT	1
 #define		SLAB_STATS		0
 #define		SLAB_SELFTEST		0
 
@@ -471,7 +471,7 @@
 			 * allow tighter packing of the smaller caches. */
 			if (!(sizes->cs_cachep =
 			      kmem_cache_create(*names++, sizes->cs_size,
-						0, SLAB_HWCACHE_ALIGN, NULL, NULL)))
+						0, SLAB_HWCACHE_ALIGN|SLAB_POISON, NULL, NULL)))
 				goto panic_time;
 			if (!found) {
 				/* Inc off-slab bufctl limit until the ceiling is hit. */
Index: oldkernel/linux/mm/swap_state.c
diff -u linux/mm/swap_state.c:1.2 linux/mm/swap_state.c:1.3
--- linux/mm/swap_state.c:1.2	Thu Jun  1 15:03:09 2000
+++ linux/mm/swap_state.c	Fri Jul  7 15:36:50 2000
@@ -54,7 +54,7 @@
 	if (PageTestandSetSwapCache(page)) {
 		printk(KERN_ERR "swap_cache: replacing non-empty entry %08lx "
 		       "on page %08lx\n",
-		       pgoff2ulong(page->index), page_address(page));
+		       page->offset, page_address(page));
 		return 0;
 	}
 	if (page->inode) {
@@ -64,8 +64,8 @@
 	}
 	atomic_inc(&page->count);
 	page->inode = &swapper_inode;
-	page->index = ulong2pgoff(entry);
-	add_page_to_hash_queue(page, &swapper_inode, ulong2pgoff(entry));
+	page->offset = entry;
+	add_page_to_hash_queue(page, &swapper_inode, entry);
 	add_page_to_inode_queue(&swapper_inode, page);
 	return 1;
 }
@@ -203,7 +203,7 @@
  */
 void delete_from_swap_cache(struct page *page)
 {
-	long entry = pgoff2ulong(page->index);
+	long entry = page->offset;
 
 #ifdef SWAP_CACHE_INFO
 	swap_cache_del_total++;
@@ -251,7 +251,7 @@
 	swap_cache_find_total++;
 #endif
 	while (1) {
-		found = find_page(&swapper_inode, ulong2pgoff(entry));
+		found = find_page(&swapper_inode, entry);
 		if (!found)
 			return 0;
 		if (found->inode != &swapper_inode || !PageSwapCache(found))
Index: oldkernel/linux/mm/vmscan.c
diff -u linux/mm/vmscan.c:1.3 linux/mm/vmscan.c:1.4
--- linux/mm/vmscan.c:1.3	Thu Jun  1 16:47:27 2000
+++ linux/mm/vmscan.c	Fri Jul  7 15:36:50 2000
@@ -74,7 +74,7 @@
 	 * memory, and we should just continue our scan.
 	 */
 	if (PageSwapCache(page_map)) {
-		entry = pgoff2ulong(page_map->index);
+		entry = page_map->offset;
 		swap_duplicate(entry);
 		set_pte(page_table, __pte(entry));
 drop_pte:
Index: oldkernel/linux/net/ipv4/Config.in
diff -u linux/net/ipv4/Config.in:1.2 linux/net/ipv4/Config.in:1.3
--- linux/net/ipv4/Config.in:1.2	Thu Jun  1 17:28:49 2000
+++ linux/net/ipv4/Config.in	Fri Jul  7 15:36:50 2000
@@ -41,6 +41,7 @@
     bool 'IP: masquerading' CONFIG_IP_MASQUERADE
     if [ "$CONFIG_IP_MASQUERADE" != "n" ]; then
       comment 'Protocol-specific masquerading support will be built as modules.'
+      bool 'IP: UDP masquerading loose checking' CONFIG_IP_MASQUERADE_UDP_LOOSE
       bool 'IP: ICMP masquerading' CONFIG_IP_MASQUERADE_ICMP
       comment 'Protocol-specific masquerading support will be built as modules.'
       if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
Index: oldkernel/linux/net/ipv4/arp.c
diff -u linux/net/ipv4/arp.c:1.2 linux/net/ipv4/arp.c:1.3
--- linux/net/ipv4/arp.c:1.2	Wed May 31 14:50:06 2000
+++ linux/net/ipv4/arp.c	Fri Jul  7 15:36:50 2000
@@ -1,6 +1,6 @@
 /* linux/net/inet/arp.c
  *
- * Version:	$Id: arp.c,v 1.1.1.1 2000/05/31 19:33:49 ccr Exp $
+ * Version:	$Id: arp.c,v 1.77.2.5 1999/12/14 10:32:39 davem Exp $
  *
  * Copyright (C) 1994 by Florian  La Roche
  *
Index: oldkernel/linux/net/ipv4/ip_masq.c
diff -u linux/net/ipv4/ip_masq.c:1.2 linux/net/ipv4/ip_masq.c:1.3
--- linux/net/ipv4/ip_masq.c:1.2	Thu Jun  1 17:28:49 2000
+++ linux/net/ipv4/ip_masq.c	Fri Jul  7 15:36:50 2000
@@ -79,6 +79,7 @@
 #include <net/tcp.h>
 #include <net/udp.h>
 #include <net/checksum.h>
+#include <net/sock.h>
 #include <net/ip_masq.h>
 
 #ifdef CONFIG_IP_MASQUERADE_MOD
@@ -94,6 +95,7 @@
 #endif /* CONFIG_IP_MASQUERADE_VS */
 
 int sysctl_ip_masq_debug = 0;
+int sysctl_ip_masq_udp_dloose = 0;
 
 /*
  *	Exported wrapper 
@@ -454,12 +456,6 @@
 #define MASQ_DPORT_PASS	(IP_MASQ_F_NO_DPORT|IP_MASQ_F_DLOOSE)
 
 /*
- *	By default enable dest loose semantics
- */
-#define CONFIG_IP_MASQ_LOOSE_DEFAULT 1
-
-
-/*
  * 	Set masq expiration (deletion) and adds timer,
  *	if timeout==0 cancel expiration.
  *	Warning: it does not check/delete previous timer!
@@ -1003,17 +999,29 @@
 	atomic_set(&ms->n_control,0);
 	atomic_set(&ms->refcnt,0);
 
-        if (proto == IPPROTO_UDP && !mport)
-#ifdef CONFIG_IP_MASQ_LOOSE_DEFAULT
-		/*
-		 *	Flag this tunnel as "dest loose"
-		 *	
-		 */
-		ms->flags |= IP_MASQ_F_DLOOSE;
-#else
-                ms->flags |= IP_MASQ_F_NO_DADDR;
-#endif
+        if (proto == IPPROTO_UDP && !mport) {
 
+		switch( sysctl_ip_masq_udp_dloose ) {
+		case 2:
+			/*
+		 	*	Flag this tunnel as "dest loose"
+		 	*	
+		 	*/
+			ms->flags |= IP_MASQ_F_DLOOSE;
+			break;
+		case 1:
+			if( ntohs(sport) < PROT_SOCK ) {
+				ms->flags |= IP_MASQ_F_NO_DADDR;
+			}
+			else {
+				ms->flags |= IP_MASQ_F_DLOOSE;
+			}
+			break;
+		default:
+			ms->flags |= IP_MASQ_F_NO_DADDR;
+			break;
+		}
+	}
         
         /* get masq address from rif */
         ms->maddr	   = maddr;
diff -ru linux/net/ipv4/ip_masq_ftp.c linux.new/net/ipv4/ip_masq_ftp.c
--- linux/net/ipv4/ip_masq_ftp.c	Tue Aug  8 17:33:10 2000
+++ linux.new/net/ipv4/ip_masq_ftp.c	Tue Aug  8 17:32:22 2000
@@ -17,6 +17,7 @@
  *	Juan Jose Ciarlante	:	use ip_masq_listen() 
  *	Juan Jose Ciarlante	: 	use private app_data for own flag(s)
  *	Wensong Zhang           :       Added virtual server support
+ *	Bjarni R. Einarsson :     Added protection against "extended FTP ALG attack"
  *
  *
  *
@@ -35,7 +35,21 @@
  *	/etc/conf.modules (or /etc/modules.conf depending on your config)
  *	where modload will pick it up should you use modload to load your
  *	modules.
- *	
+ * 
+ * Protection against the "extended FTP ALG vulnerability".
+ *	This vulnerability was reported in:
+ *
+ *	http://www.securityfocus.com/templates/archive.pike?list=82&date=2000-03-08&msg=38C8C8EE.544524B1@enternet.se
+ * 
+ *	The protection here is very simplistic, but it at least denies access 
+ *	to all ports under 1024, and allows the user to specify an additional 
+ *	list of high ports on the insmod command line, like this:
+ *		noport=x1,x2,x3, ...
+ *	Up to MAX_MASQ_APP_PORTS (normally 12) ports may be specified, the 
+ *	default blocks access to the X server (port 6000) only.
+ * 
+ *	Patch by Bjarni R. Einarsson <bre@netverjar.is>.  The original patch is
+ *	available at: http://bre.klaki.net/programs/ip_masq_ftp.2000-03-20.diff
  */
 
 #include <linux/config.h>
@@ -62,6 +76,13 @@
 struct ip_masq_app *masq_incarnations[MAX_MASQ_APP_PORTS];
 
 /*
+ * List of ports (up to MAX_MASQ_APP_PORTS) we don't allow ftp-data 
+ * connections to.  Default is to block connections to port 6000 (X servers).
+ * This is in addition to all ports under 1024.
+ */
+static int noport[MAX_MASQ_APP_PORTS] = {6000, 0}; /* I rely on the trailing items being set to zero */
+
+/*
  *	Debug level
  */
 #ifdef CONFIG_IP_MASQ_DEBUG
@@ -70,6 +91,7 @@
 #endif
 
 MODULE_PARM(ports, "1-" __MODULE_STRING(MAX_MASQ_APP_PORTS) "i");
+MODULE_PARM(noport, "1-" __MODULE_STRING(MAX_MASQ_APP_PORTS) "i");
 
 /*	Dummy variable */
 static int masq_ftp_pasv;
@@ -105,7 +127,7 @@
 	struct ip_masq *n_ms;
 	char buf[24];		/* xxx.xxx.xxx.xxx,ppp,ppp\000 */
         unsigned buf_len;
-	int diff;
+	int diff, i, unsafe;
 
 #ifdef CONFIG_IP_MASQUERADE_VS
 	if (ms->app_data == &ipvs_ftp_pasv) {
@@ -254,6 +276,20 @@
 
 		from = (p1<<24) | (p2<<16) | (p3<<8) | p4;
 		port = (p5<<8) | p6;
+
+		if (port < 1024) 
+		{
+			IP_MASQ_DEBUG(1-debug, "Unsafe PORT %X:%X detected, ignored\n",from,port);
+			continue;
+		}
+
+		for (unsafe = i = 0; (i < MAX_MASQ_APP_PORTS) && (noport[i]); i++)
+		  if (port == noport[i])
+		{
+			IP_MASQ_DEBUG(1-debug, "Unsafe PORT %X:%X detected, ignored\n",from,port);
+			unsafe = 1;
+		}
+		if (unsafe) continue;
 
 		IP_MASQ_DEBUG(1-debug, "PORT %X:%X detected\n",from,port);
 
Index: oldkernel/linux/net/ipv4/ip_masq_user.c
diff -u linux/net/ipv4/ip_masq_user.c:1.1.1.1 linux/net/ipv4/ip_masq_user.c:1.2
--- linux/net/ipv4/ip_masq_user.c:1.1.1.1	Wed May 31 12:33:49 2000
+++ linux/net/ipv4/ip_masq_user.c	Fri Jul  7 15:36:50 2000
@@ -2,7 +2,7 @@
  *	IP_MASQ_USER user space control module
  *
  *
- *	$Id: ip_masq_user.c,v 1.1.2.3 1999/11/16 06:33:51 davem Exp $
+ *	$Id: ip_masq_user.c,v 1.1.2.4 2000/02/29 23:50:24 davem Exp $
  */
 
 #include <linux/config.h>
@@ -186,8 +186,10 @@
 				ums->saddr, ums->sport,
 				ums->daddr, ums->dport);
 		end_bh_atomic();
-	} else
+	} else {
+		end_bh_atomic();
 		return EINVAL;	
+	}
 	
 	if (ms == NULL) {
 		return ESRCH;
@@ -224,8 +226,10 @@
 				ums->saddr, ums->sport,
 				ums->daddr, ums->dport);
 		end_bh_atomic();
-	} else
+	} else {
+		end_bh_atomic();
 		*err = EINVAL;	
+	}
 	
 	if (ms == NULL) *err = ESRCH;
 	return ms;
Index: oldkernel/linux/net/irda/ircomm/irvtd_driver.c
diff -u linux/net/irda/ircomm/irvtd_driver.c:1.1.1.1 linux/net/irda/ircomm/irvtd_driver.c:1.2
--- linux/net/irda/ircomm/irvtd_driver.c:1.1.1.1	Wed May 31 12:33:49 2000
+++ linux/net/irda/ircomm/irvtd_driver.c	Fri Jul  7 15:36:50 2000
@@ -1960,7 +1960,7 @@
 done:
 	if (offset >= count+begin)
 		return 0;
-	*start = buf + (begin-offset);
+	*start = buf + (offset-begin);
 	return ((len < begin+count-offset) ? len : begin+count-offset);
 }
 
Index: oldkernel/linux/net/sunrpc/auth.c
diff -u linux/net/sunrpc/auth.c:1.1.1.1 linux/net/sunrpc/auth.c:1.2
--- linux/net/sunrpc/auth.c:1.1.1.1	Wed May 31 12:33:49 2000
+++ linux/net/sunrpc/auth.c	Fri Jul  7 15:36:50 2000
@@ -12,6 +12,7 @@
 #include <linux/errno.h>
 #include <linux/socket.h>
 #include <linux/sunrpc/clnt.h>
+#include <asm/spinlock.h>
 
 #ifdef RPC_DEBUG
 # define RPCDBG_FACILITY	RPCDBG_AUTH
@@ -68,6 +69,8 @@
 	auth->au_ops->destroy(auth);
 }
 
+spinlock_t rpc_credcache_lock = SPIN_LOCK_UNLOCKED;
+
 /*
  * Initialize RPC credential cache
  */
@@ -78,6 +81,15 @@
 	auth->au_nextgc = jiffies + (auth->au_expire >> 1);
 }
 
+static inline void
+rpcauth_crdestroy(struct rpc_auth *auth, struct rpc_cred *cred)
+{
+	if (auth->au_ops->crdestroy)
+		auth->au_ops->crdestroy(cred);
+	else
+		rpc_free(cred);
+}
+
 /*
  * Clear the RPC credential cache
  */
@@ -91,6 +103,7 @@
 	if (!(destroy = auth->au_ops->crdestroy))
 		destroy = (void (*)(struct rpc_cred *)) rpc_free;
 
+	spin_lock(&rpc_credcache_lock);
 	for (i = 0; i < RPC_CREDCACHE_NR; i++) {
 		q = &auth->au_credcache[i];
 		while ((cred = *q) != NULL) {
@@ -98,6 +111,7 @@
 			destroy(cred);
 		}
 	}
+	spin_unlock(&rpc_credcache_lock);
 }
 
 /*
@@ -107,17 +121,15 @@
 rpcauth_gc_credcache(struct rpc_auth *auth)
 {
 	struct rpc_cred	**q, *cred, *free = NULL;
-	int		i, safe = 0;
+	int		i;
 
 	dprintk("RPC: gc'ing RPC credentials for auth %p\n", auth);
+	spin_lock(&rpc_credcache_lock);
 	for (i = 0; i < RPC_CREDCACHE_NR; i++) {
 		q = &auth->au_credcache[i];
 		while ((cred = *q) != NULL) {
-			if (++safe > 500) {
-				printk("RPC: rpcauth_gc_credcache looping!\n");
-				break;
-			}
-			if (!cred->cr_count && time_before(cred->cr_expire, jiffies)) {
+			if (!cred->cr_count &&
+			    time_before(cred->cr_expire, jiffies)) {
 				*q = cred->cr_next;
 				cred->cr_next = free;
 				free = cred;
@@ -126,9 +138,10 @@
 			q = &cred->cr_next;
 		}
 	}
+	spin_unlock(&rpc_credcache_lock);
 	while ((cred = free) != NULL) {
 		free = cred->cr_next;
-		rpc_free(cred);
+		rpcauth_crdestroy(auth, cred);
 	}
 	auth->au_nextgc = jiffies + auth->au_expire;
 }
@@ -136,44 +149,49 @@
 /*
  * Insert credential into cache
  */
-inline void
+void
 rpcauth_insert_credcache(struct rpc_auth *auth, struct rpc_cred *cred)
 {
 	int		nr;
 
 	nr = (cred->cr_uid % RPC_CREDCACHE_NR);
+	spin_lock(&rpc_credcache_lock);
 	cred->cr_next = auth->au_credcache[nr];
 	auth->au_credcache[nr] = cred;
-	cred->cr_expire = jiffies + auth->au_expire;
 	cred->cr_count++;
+	cred->cr_expire = jiffies + auth->au_expire;
+	spin_unlock(&rpc_credcache_lock);
 }
 
 /*
  * Look up a process' credentials in the authentication cache
  */
 static struct rpc_cred *
-rpcauth_lookup_credcache(struct rpc_task *task)
+rpcauth_lookup_credcache(struct rpc_auth *auth, int taskflags)
 {
-	struct rpc_auth	*auth = task->tk_auth;
 	struct rpc_cred	**q, *cred = NULL;
-	int		nr;
+	int		nr = 0;
 
-	nr = RPC_DO_ROOTOVERRIDE(task)? 0 : (current->uid % RPC_CREDCACHE_NR);
+	if (!(taskflags & RPC_TASK_ROOTCREDS))
+		nr = current->uid % RPC_CREDCACHE_NR;
 
 	if (time_before(auth->au_nextgc, jiffies))
 		rpcauth_gc_credcache(auth);
 
+	spin_lock(&rpc_credcache_lock);
 	q = &auth->au_credcache[nr];
 	while ((cred = *q) != NULL) {
-		if (auth->au_ops->crmatch(task, cred)) {
+		if (!(cred->cr_flags & RPCAUTH_CRED_DEAD) &&
+		    auth->au_ops->crmatch(cred, taskflags)) {
 			*q = cred->cr_next;
 			break;
 		}
 		q = &cred->cr_next;
 	}
+	spin_unlock(&rpc_credcache_lock);
 
 	if (!cred)
-		cred = auth->au_ops->crcreate(task);
+		cred = auth->au_ops->crcreate(taskflags);
 
 	if (cred)
 		rpcauth_insert_credcache(auth, cred);
@@ -184,76 +202,99 @@
 /*
  * Remove cred handle from cache
  */
-static inline void
+static void
 rpcauth_remove_credcache(struct rpc_auth *auth, struct rpc_cred *cred)
 {
 	struct rpc_cred	**q, *cr;
 	int		nr;
 
 	nr = (cred->cr_uid % RPC_CREDCACHE_NR);
+	spin_lock(&rpc_credcache_lock);
 	q = &auth->au_credcache[nr];
 	while ((cr = *q) != NULL) {
 		if (cred == cr) {
 			*q = cred->cr_next;
-			return;
+			cred->cr_next = NULL;
+			break;
 		}
 		q = &cred->cr_next;
 	}
+	spin_unlock(&rpc_credcache_lock);
+}
+
+struct rpc_cred *
+rpcauth_lookupcred(struct rpc_auth *auth, int taskflags)
+{
+	dprintk("RPC:     looking up %s cred\n",
+		auth->au_ops->au_name);
+	return rpcauth_lookup_credcache(auth, taskflags);
 }
 
 struct rpc_cred *
-rpcauth_lookupcred(struct rpc_task *task)
+rpcauth_bindcred(struct rpc_task *task)
 {
+	struct rpc_auth *auth = task->tk_auth;
+
 	dprintk("RPC: %4d looking up %s cred\n",
 		task->tk_pid, task->tk_auth->au_ops->au_name);
-	return task->tk_cred = rpcauth_lookup_credcache(task);
+	task->tk_msg.rpc_cred = rpcauth_lookup_credcache(auth, task->tk_flags);
+	if (task->tk_msg.rpc_cred == 0)
+		task->tk_status = -ENOMEM;
+	return task->tk_msg.rpc_cred;
 }
 
 int
-rpcauth_matchcred(struct rpc_task *task, struct rpc_cred *cred)
+rpcauth_matchcred(struct rpc_auth *auth, struct rpc_cred *cred, int taskflags)
 {
-	struct rpc_auth	*auth = task->tk_auth;
-
-	dprintk("RPC: %4d matching %s cred %p\n",
-		task->tk_pid, auth->au_ops->au_name, task->tk_cred);
-	return auth->au_ops->crmatch(task, cred);
+	dprintk("RPC:     matching %s cred %d\n",
+		auth->au_ops->au_name, taskflags);
+	return auth->au_ops->crmatch(cred, taskflags);
 }
 
 void
 rpcauth_holdcred(struct rpc_task *task)
 {
 	dprintk("RPC: %4d holding %s cred %p\n",
-		task->tk_pid, task->tk_auth->au_ops->au_name, task->tk_cred);
-	if (task->tk_cred)
-		task->tk_cred->cr_count++;
+		task->tk_pid, task->tk_auth->au_ops->au_name, task->tk_msg.rpc_cred);
+	if (task->tk_msg.rpc_cred) {
+		task->tk_msg.rpc_cred->cr_count++;
+		task->tk_msg.rpc_cred->cr_expire = jiffies + task->tk_auth->au_expire;
+	}
 }
 
 void
-rpcauth_releasecred(struct rpc_task *task)
+rpcauth_releasecred(struct rpc_auth *auth, struct rpc_cred *cred)
 {
-	struct rpc_auth	*auth = task->tk_auth;
-	struct rpc_cred	*cred;
-
-	dprintk("RPC: %4d releasing %s cred %p\n",
-		task->tk_pid, auth->au_ops->au_name, task->tk_cred);
-	if ((cred = task->tk_cred) != NULL) {
+	if (cred != NULL && cred->cr_count > 0) {
 		cred->cr_count--;
 		if (cred->cr_flags & RPCAUTH_CRED_DEAD) {
 			rpcauth_remove_credcache(auth, cred);
 			if (!cred->cr_count)
-				auth->au_ops->crdestroy(cred);
+				rpcauth_crdestroy(auth, cred);
 		}
-		task->tk_cred = NULL;
 	}
 }
 
+void
+rpcauth_unbindcred(struct rpc_task *task)
+{
+	struct rpc_auth	*auth = task->tk_auth;
+	struct rpc_cred	*cred = task->tk_msg.rpc_cred;
+
+	dprintk("RPC: %4d releasing %s cred %p\n",
+		task->tk_pid, auth->au_ops->au_name, cred);
+
+	rpcauth_releasecred(auth, cred);
+	task->tk_msg.rpc_cred = NULL;
+}
+
 u32 *
 rpcauth_marshcred(struct rpc_task *task, u32 *p)
 {
 	struct rpc_auth	*auth = task->tk_auth;
 
 	dprintk("RPC: %4d marshaling %s cred %p\n",
-		task->tk_pid, auth->au_ops->au_name, task->tk_cred);
+		task->tk_pid, auth->au_ops->au_name, task->tk_msg.rpc_cred);
 	return auth->au_ops->crmarshal(task, p,
 				task->tk_flags & RPC_CALL_REALUID);
 }
@@ -264,7 +305,7 @@
 	struct rpc_auth	*auth = task->tk_auth;
 
 	dprintk("RPC: %4d validating %s cred %p\n",
-		task->tk_pid, auth->au_ops->au_name, task->tk_cred);
+		task->tk_pid, auth->au_ops->au_name, task->tk_msg.rpc_cred);
 	return auth->au_ops->crvalidate(task, p);
 }
 
@@ -274,7 +315,7 @@
 	struct rpc_auth	*auth = task->tk_auth;
 
 	dprintk("RPC: %4d refreshing %s cred %p\n",
-		task->tk_pid, auth->au_ops->au_name, task->tk_cred);
+		task->tk_pid, auth->au_ops->au_name, task->tk_msg.rpc_cred);
 	task->tk_status = auth->au_ops->crrefresh(task);
 	return task->tk_status;
 }
@@ -283,14 +324,14 @@
 rpcauth_invalcred(struct rpc_task *task)
 {
 	dprintk("RPC: %4d invalidating %s cred %p\n",
-		task->tk_pid, task->tk_auth->au_ops->au_name, task->tk_cred);
-	if (task->tk_cred)
-		task->tk_cred->cr_flags &= ~RPCAUTH_CRED_UPTODATE;
+		task->tk_pid, task->tk_auth->au_ops->au_name, task->tk_msg.rpc_cred);
+	if (task->tk_msg.rpc_cred)
+		task->tk_msg.rpc_cred->cr_flags &= ~RPCAUTH_CRED_UPTODATE;
 }
 
 int
 rpcauth_uptodatecred(struct rpc_task *task)
 {
-	return !(task->tk_cred) ||
-		(task->tk_cred->cr_flags & RPCAUTH_CRED_UPTODATE);
+	return !(task->tk_msg.rpc_cred) ||
+		(task->tk_msg.rpc_cred->cr_flags & RPCAUTH_CRED_UPTODATE);
 }
Index: oldkernel/linux/net/sunrpc/auth_null.c
diff -u linux/net/sunrpc/auth_null.c:1.1.1.1 linux/net/sunrpc/auth_null.c:1.2
--- linux/net/sunrpc/auth_null.c:1.1.1.1	Wed May 31 12:33:49 2000
+++ linux/net/sunrpc/auth_null.c	Fri Jul  7 15:36:50 2000
@@ -38,6 +38,7 @@
 nul_destroy(struct rpc_auth *auth)
 {
 	dprintk("RPC: destroying NULL authenticator %p\n", auth);
+	rpcauth_free_credcache(auth);
 	rpc_free(auth);
 }
 
@@ -45,15 +46,12 @@
  * Create NULL creds for current process
  */
 static struct rpc_cred *
-nul_create_cred(struct rpc_task *task)
+nul_create_cred(int flags)
 {
 	struct rpc_cred	*cred;
 
-	if (!(cred = (struct rpc_cred *) rpc_malloc(task, sizeof(*cred)))) {
-		task->tk_status = -ENOMEM;
+	if (!(cred = (struct rpc_cred *) rpc_allocate(flags, sizeof(*cred))))
 		return NULL;
-	}
-
 	cred->cr_count = 0;
 	cred->cr_flags = RPCAUTH_CRED_UPTODATE;
 
@@ -73,7 +71,7 @@
  * Match cred handle against current process
  */
 static int
-nul_match(struct rpc_task *task, struct rpc_cred *cred)
+nul_match(struct rpc_cred *cred, int taskflags)
 {
 	return 1;
 }
Index: oldkernel/linux/net/sunrpc/auth_unix.c
diff -u linux/net/sunrpc/auth_unix.c:1.1.1.1 linux/net/sunrpc/auth_unix.c:1.2
--- linux/net/sunrpc/auth_unix.c:1.1.1.1	Wed May 31 12:33:49 2000
+++ linux/net/sunrpc/auth_unix.c	Fri Jul  7 15:36:50 2000
@@ -60,7 +60,7 @@
 }
 
 static struct rpc_cred *
-unx_create_cred(struct rpc_task *task)
+unx_create_cred(int flags)
 {
 	struct unx_cred	*cred;
 	int		i;
@@ -68,14 +68,12 @@
 	dprintk("RPC:      allocating UNIX cred for uid %d gid %d\n",
 				current->uid, current->gid);
 
-	if (!(cred = (struct unx_cred *) rpc_malloc(task, sizeof(*cred)))) {
-		task->tk_status = -ENOMEM;
+	if (!(cred = (struct unx_cred *) rpc_allocate(flags, sizeof(*cred))))
 		return NULL;
-	}
 
 	cred->uc_count = 0;
 	cred->uc_flags = RPCAUTH_CRED_UPTODATE;
-	if (RPC_DO_ROOTOVERRIDE(task)) {
+	if (flags & RPC_TASK_ROOTCREDS) {
 		cred->uc_uid = cred->uc_fsuid = 0;
 		cred->uc_gid = cred->uc_fsgid = 0;
 		cred->uc_gids[0] = NOGROUP;
@@ -116,7 +114,7 @@
 	cred->uc_fsgid = gid;
 	cred->uc_gids[0] = (gid_t) NOGROUP;
 
-	return task->tk_cred = (struct rpc_cred *) cred;
+	return task->tk_msg.rpc_cred = (struct rpc_cred *) cred;
 }
 
 static void
@@ -131,12 +129,12 @@
  * request root creds (e.g. for NFS swapping).
  */
 static int
-unx_match(struct rpc_task * task, struct rpc_cred *rcred)
+unx_match(struct rpc_cred *rcred, int taskflags)
 {
 	struct unx_cred	*cred = (struct unx_cred *) rcred;
 	int		i;
 
-	if (!RPC_DO_ROOTOVERRIDE(task)) {
+	if (!(taskflags & RPC_TASK_ROOTCREDS)) {
 		int groups;
 
 		if (cred->uc_uid != current->uid
@@ -166,7 +164,7 @@
 unx_marshal(struct rpc_task *task, u32 *p, int ruid)
 {
 	struct rpc_clnt	*clnt = task->tk_client;
-	struct unx_cred	*cred = (struct unx_cred *) task->tk_cred;
+	struct unx_cred	*cred = (struct unx_cred *) task->tk_msg.rpc_cred;
 	u32		*base, *hold;
 	int		i, n;
 
@@ -207,7 +205,7 @@
 static int
 unx_refresh(struct rpc_task *task)
 {
-	task->tk_cred->cr_flags |= RPCAUTH_CRED_UPTODATE;
+	task->tk_msg.rpc_cred->cr_flags |= RPCAUTH_CRED_UPTODATE;
 	return task->tk_status = -EACCES;
 }
 
Index: oldkernel/linux/net/sunrpc/clnt.c
diff -u linux/net/sunrpc/clnt.c:1.1.1.1 linux/net/sunrpc/clnt.c:1.2
--- linux/net/sunrpc/clnt.c:1.1.1.1	Wed May 31 12:33:49 2000
+++ linux/net/sunrpc/clnt.c	Fri Jul  7 15:36:50 2000
@@ -29,6 +29,7 @@
 #include <linux/malloc.h>
 #include <linux/in.h>
 #include <linux/utsname.h>
+#include <linux/interrupt.h>
 
 #include <linux/sunrpc/clnt.h>
 
@@ -42,14 +43,13 @@
 static struct wait_queue *	destroy_wait = NULL;
 
 
-static void	call_bind(struct rpc_task *task);
 static void	call_reserve(struct rpc_task *task);
 static void	call_reserveresult(struct rpc_task *task);
 static void	call_allocate(struct rpc_task *task);
 static void	call_encode(struct rpc_task *task);
 static void	call_decode(struct rpc_task *task);
+static void	call_bind(struct rpc_task *task);
 static void	call_transmit(struct rpc_task *task);
-static void	call_receive(struct rpc_task *task);
 static void	call_status(struct rpc_task *task);
 static void	call_refresh(struct rpc_task *task);
 static void	call_refreshresult(struct rpc_task *task);
@@ -76,6 +76,12 @@
 	dprintk("RPC: creating %s client for %s (xprt %p)\n",
 		program->name, servname, xprt);
 
+	xdr_init();
+
+#ifdef RPC_DEBUG
+	rpc_register_sysctl();
+#endif
+
 	if (!xprt)
 		goto out;
 	if (vers >= program->nrvers || !(version = program->version[vers]))
@@ -94,7 +100,7 @@
 	clnt->cl_port     = xprt->addr.sin_port;
 	clnt->cl_prog     = program->number;
 	clnt->cl_vers     = version->number;
-	clnt->cl_prot     = IPPROTO_UDP;
+	clnt->cl_prot     = xprt->prot;
 	clnt->cl_stats    = program->stats;
 	clnt->cl_bindwait = RPC_INIT_WAITQ("bindwait");
 
@@ -113,10 +119,10 @@
 	return clnt;
 
 out_no_clnt:
-	printk("RPC: out of memory in rpc_create_client\n");
+	printk(KERN_INFO "RPC: out of memory in rpc_create_client\n");
 	goto out;
 out_no_auth:
-	printk("RPC: Couldn't create auth handle (flavor %d)\n",
+	printk(KERN_INFO "RPC: Couldn't create auth handle (flavor %d)\n",
 		flavor);
 	rpc_free(clnt);
 	clnt = NULL;
@@ -136,7 +142,7 @@
 		clnt->cl_protname, clnt->cl_server);
 	while (clnt->cl_users) {
 #ifdef RPC_DEBUG
-		printk("rpc_shutdown_client: client %s, tasks=%d\n",
+		dprintk("RPC: rpc_shutdown_client: client %s, tasks=%d\n",
 			clnt->cl_protname, clnt->cl_users);
 #endif
 		/* Don't let rpc_release_client destroy us */
@@ -195,7 +201,6 @@
 static void
 rpc_default_callback(struct rpc_task *task)
 {
-	rpc_release_task(task);
 }
 
 /*
@@ -236,42 +241,73 @@
 /*
  * New rpc_call implementation
  */
-int
-rpc_do_call(struct rpc_clnt *clnt, u32 proc, void *argp, void *resp,
-				int flags, rpc_action func, void *data)
+int rpc_call_sync(struct rpc_clnt *clnt, struct rpc_message *msg, int flags)
 {
 	struct rpc_task	my_task, *task = &my_task;
 	sigset_t	oldset;
-	int		async, status;
+	int		status;
 
 	/* If this client is slain all further I/O fails */
 	if (clnt->cl_dead) 
 		return -EIO;
 
+	if (flags & RPC_TASK_ASYNC) {
+		printk("rpc_call_sync: Illegal flag combination for synchronous task\n");
+		flags &= ~RPC_TASK_ASYNC;
+	}
+
 	rpc_clnt_sigmask(clnt, &oldset);		
 
 	/* Create/initialize a new RPC task */
-	if ((async = (flags & RPC_TASK_ASYNC)) != 0) {
-		if (!func)
-			func = rpc_default_callback;
-		status = -ENOMEM;
-		if (!(task = rpc_new_task(clnt, func, flags)))
-			goto out;
-		task->tk_calldata = data;
-	} else {
-		rpc_init_task(task, clnt, NULL, flags);
+	rpc_init_task(task, clnt, NULL, flags);
+	rpc_call_setup(task, msg, 0);
+
+	/* Set up the call info struct and execute the task */
+	if (task->tk_status == 0)
+		status = rpc_execute(task);
+	else {
+		status = task->tk_status;
+		rpc_release_task(task);
 	}
 
-	/* Bind the user cred, set up the call info struct and
-	 * execute the task */
-	if (rpcauth_lookupcred(task) != NULL) {
-		rpc_call_setup(task, proc, argp, resp, 0);
-		rpc_execute(task);
-	} else
-		async = 0;
+	rpc_clnt_sigunmask(clnt, &oldset);		
+
+	return status;
+}
+
+/*
+ * New rpc_call implementation
+ */
+int
+rpc_call_async(struct rpc_clnt *clnt, struct rpc_message *msg, int flags,
+	       rpc_action callback, void *data)
+{
+	struct rpc_task	*task;
+	sigset_t	oldset;
+	int		status;
+
+	/* If this client is slain all further I/O fails */
+	if (clnt->cl_dead) 
+		return -EIO;
+
+	flags |= RPC_TASK_ASYNC;
 
-	status = 0;
-	if (!async) {
+	rpc_clnt_sigmask(clnt, &oldset);		
+
+	/* Create/initialize a new RPC task */
+	if (!callback)
+		callback = rpc_default_callback;
+	status = -ENOMEM;
+	if (!(task = rpc_new_task(clnt, callback, flags)))
+		goto out;
+	task->tk_calldata = data;
+
+	rpc_call_setup(task, msg, 0);
+
+	/* Set up the call info struct and execute the task */
+	if (task->tk_status == 0)
+		status = rpc_execute(task);
+	else {
 		status = task->tk_status;
 		rpc_release_task(task);
 	}
@@ -284,17 +320,24 @@
 
 
 void
-rpc_call_setup(struct rpc_task *task, u32 proc,
-				void *argp, void *resp, int flags)
+rpc_call_setup(struct rpc_task *task, struct rpc_message *msg, int flags)
 {
-	task->tk_action = call_bind;
-	task->tk_proc   = proc;
-	task->tk_argp   = argp;
-	task->tk_resp   = resp;
+	task->tk_msg   = *msg;
 	task->tk_flags |= flags;
+	/* Bind the user cred */
+	if (task->tk_msg.rpc_cred != NULL) {
+		rpcauth_holdcred(task);
+	} else
+		rpcauth_bindcred(task);
+
+	if (task->tk_status == 0)
+		task->tk_action = call_reserve;
+	else
+		task->tk_action = NULL;
 
 	/* Increment call count */
-	rpcproc_count(task->tk_client, proc)++;
+	if (task->tk_msg.rpc_proc < task->tk_client->cl_maxproc)
+		rpcproc_count(task->tk_client, task->tk_msg.rpc_proc)++;
 }
 
 /*
@@ -304,26 +347,11 @@
 void
 rpc_restart_call(struct rpc_task *task)
 {
-	if (task->tk_flags & RPC_TASK_KILLED) {
-		rpc_release_task(task);
+	if (RPC_ASSASSINATED(task))
 		return;
-	}
-	task->tk_action = call_bind;
-	rpcproc_count(task->tk_client, task->tk_proc)++;
-}
 
-/*
- * 0.	Get the server port number if not yet set
- */
-static void
-call_bind(struct rpc_task *task)
-{
-	struct rpc_clnt	*clnt = task->tk_client;
-
 	task->tk_action = call_reserve;
-	task->tk_status = 0;
-	if (!clnt->cl_port)
-		rpc_getport(task, clnt);
+	rpcproc_count(task->tk_client, task->tk_msg.rpc_proc)++;
 }
 
 /*
@@ -334,25 +362,22 @@
 {
 	struct rpc_clnt	*clnt = task->tk_client;
 
-	dprintk("RPC: %4d call_reserve\n", task->tk_pid);
-	if (!clnt->cl_port) {
-		printk(KERN_NOTICE "%s: couldn't bind to server %s - %s.\n",
-			clnt->cl_protname, clnt->cl_server,
-			clnt->cl_softrtry? "giving up" : "retrying");
-		if (!clnt->cl_softrtry) {
-			rpc_delay(task, 5*HZ);
-			return;
-		}
+	if (task->tk_msg.rpc_proc >= clnt->cl_maxproc) {
+		printk(KERN_WARNING "%s (vers %d): bad procedure number %d\n",
+			clnt->cl_protname, clnt->cl_vers, task->tk_msg.rpc_proc);
 		rpc_exit(task, -EIO);
 		return;
 	}
+
+	dprintk("RPC: %4d call_reserve\n", task->tk_pid);
 	if (!rpcauth_uptodatecred(task)) {
 		task->tk_action = call_refresh;
 		return;
 	}
+
+	task->tk_status  = 0;
 	task->tk_action  = call_reserveresult;
 	task->tk_timeout = clnt->cl_timeout.to_resrvval;
-	task->tk_status  = 0;
 	clnt->cl_stats->rpccnt++;
 	xprt_reserve(task);
 }
@@ -363,6 +388,8 @@
 static void
 call_reserveresult(struct rpc_task *task)
 {
+	int status = task->tk_status;
+
 	dprintk("RPC: %4d call_reserveresult (status %d)\n",
 				task->tk_pid, task->tk_status);
 	/*
@@ -376,25 +403,27 @@
 
 	if (task->tk_status >= 0) {
 		task->tk_action = call_allocate;
-		goto out;
-	} else if (task->tk_status == -EAGAIN) {
+		return;
+	}
+
+	task->tk_status = 0;
+	switch (status) {
+	case -EAGAIN:
+	case -ENOBUFS:
 		task->tk_timeout = task->tk_client->cl_timeout.to_resrvval;
-		task->tk_status = 0;
-		xprt_reserve(task);
-		goto out;
-	} else if (task->tk_status == -ETIMEDOUT) {
+		task->tk_action = call_reserve;
+		break;
+	case -ETIMEDOUT:
 		dprintk("RPC: task timed out\n");
 		task->tk_action = call_timeout;
-		goto out;
-	} else {
-		task->tk_action = NULL;
-	}
-	if (!task->tk_rqstp) {
-		printk("RPC: task has no request, exit EIO\n");
-		rpc_exit(task, -EIO);
+		break;
+	default:
+		if (!task->tk_rqstp) {
+			printk(KERN_INFO "RPC: task has no request, exit EIO\n");
+			rpc_exit(task, -EIO);
+		} else
+			rpc_exit(task, status);
 	}
-out:
-	return;
 }
 
 /*
@@ -415,16 +444,15 @@
 
 	/* FIXME: compute buffer requirements more exactly using
 	 * auth->au_wslack */
-	bufsiz = rpcproc_bufsiz(clnt, task->tk_proc) + RPC_SLACK_SPACE;
+	bufsiz = rpcproc_bufsiz(clnt, task->tk_msg.rpc_proc) + RPC_SLACK_SPACE;
 
 	if ((task->tk_buffer = rpc_malloc(task, bufsiz)) != NULL)
 		return;
-	printk("RPC: buffer allocation failed for task %p\n", task); 
+	printk(KERN_INFO "RPC: buffer allocation failed for task %p\n", task); 
 
-	if (!signalled()) {
-		xprt_release(task);
-		task->tk_action = call_reserve;
-		rpc_delay(task, HZ);
+	if (RPC_IS_ASYNC(task) || !(task->tk_client->cl_intr && signalled())) {
+		task->tk_action = call_allocate;
+		rpc_delay(task, HZ>>4);
 		return;
 	}
 
@@ -447,10 +475,10 @@
 	dprintk("RPC: %4d call_encode (status %d)\n", 
 				task->tk_pid, task->tk_status);
 
-	task->tk_action = call_transmit;
+	task->tk_action = call_bind;
 
 	/* Default buffer setup */
-	bufsiz = rpcproc_bufsiz(clnt, task->tk_proc)+RPC_SLACK_SPACE;
+	bufsiz = rpcproc_bufsiz(clnt, task->tk_msg.rpc_proc)+RPC_SLACK_SPACE;
 	req->rq_svec[0].iov_base = task->tk_buffer;
 	req->rq_svec[0].iov_len  = bufsiz;
 	req->rq_slen		 = 0;
@@ -459,24 +487,18 @@
 	req->rq_rvec[0].iov_len  = bufsiz;
 	req->rq_rlen		 = bufsiz;
 	req->rq_rnr		 = 1;
+	req->rq_damaged		 = 0;
 
-	if (task->tk_proc > clnt->cl_maxproc) {
-		printk(KERN_WARNING "%s (vers %d): bad procedure number %d\n",
-			clnt->cl_protname, clnt->cl_vers, task->tk_proc);
-		rpc_exit(task, -EIO);
-		return;
-	}
-
 	/* Zero buffer so we have automatic zero-padding of opaque & string */
 	memset(task->tk_buffer, 0, bufsiz);
 
 	/* Encode header and provided arguments */
-	encode = rpcproc_encode(clnt, task->tk_proc);
+	encode = rpcproc_encode(clnt, task->tk_msg.rpc_proc);
 	if (!(p = call_header(task))) {
-		printk("RPC: call_header failed, exit EIO\n");
+		printk(KERN_INFO "RPC: call_header failed, exit EIO\n");
 		rpc_exit(task, -EIO);
 	} else
-	if ((status = encode(req, p, task->tk_argp)) < 0) {
+	if (encode && (status = encode(req, p, task->tk_msg.rpc_argp)) < 0) {
 		printk(KERN_WARNING "%s: can't encode arguments: %d\n",
 				clnt->cl_protname, -status);
 		rpc_exit(task, status);
@@ -484,42 +506,60 @@
 }
 
 /*
- * 4.	Transmit the RPC request
+ * 4.	Get the server port number if not yet set
  */
 static void
-call_transmit(struct rpc_task *task)
+call_bind(struct rpc_task *task)
 {
-	dprintk("RPC: %4d call_transmit (status %d)\n", 
+	struct rpc_clnt	*clnt = task->tk_client;
+	struct rpc_xprt *xprt = task->tk_xprt;
+
+	task->tk_action = (xprt->connected) ? call_transmit : call_reconnect;
+
+	if (!clnt->cl_port) {
+		task->tk_action = call_reconnect;
+		task->tk_timeout = clnt->cl_timeout.to_maxval;
+		rpc_getport(task, clnt);
+	}
+}
+
+/*
+ * 4a.	Reconnect to the RPC server (TCP case)
+ */
+static void
+call_reconnect(struct rpc_task *task)
+{
+	struct rpc_clnt *clnt = task->tk_client;
+
+	dprintk("RPC: %4d call_reconnect status %d\n",
 				task->tk_pid, task->tk_status);
 
-	task->tk_action = call_receive;
-	task->tk_status = 0;
-	xprt_transmit(task);
+	task->tk_action = call_transmit;
+	if (task->tk_status < 0 || !clnt->cl_xprt->stream)
+		return;
+	clnt->cl_stats->netreconn++;
+	xprt_reconnect(task);
 }
 
 /*
- * 5.	Wait for the RPC reply
+ * 5.	Transmit the RPC request, and wait for reply
  */
 static void
-call_receive(struct rpc_task *task)
+call_transmit(struct rpc_task *task)
 {
-	dprintk("RPC: %4d call_receive (status %d)\n", 
-		task->tk_pid, task->tk_status);
+	struct rpc_clnt	*clnt = task->tk_client;
+
+	dprintk("RPC: %4d call_transmit (status %d)\n", 
+				task->tk_pid, task->tk_status);
 
 	task->tk_action = call_status;
-	/* In case of error, evaluate status */
 	if (task->tk_status < 0)
 		return;
-
-	/* If we have no decode function, this means we're performing
-	 * a void call (a la lockd message passing). */
-	if (!rpcproc_decode(task->tk_client, task->tk_proc)) {
-		rpc_remove_wait_queue(task); /* remove from xprt_pending */
+	xprt_transmit(task);
+	if (!rpcproc_decode(clnt, task->tk_msg.rpc_proc)) {
 		task->tk_action = NULL;
-		return;
+		rpc_wake_up_task(task);
 	}
-
-	xprt_receive(task);
 }
 
 /*
@@ -529,6 +569,7 @@
 call_status(struct rpc_task *task)
 {
 	struct rpc_clnt	*clnt = task->tk_client;
+	struct rpc_xprt	*xprt = clnt->cl_xprt;
 	struct rpc_rqst	*req;
 	int		status = task->tk_status;
 
@@ -537,28 +578,45 @@
 
 	if (status >= 0) {
 		task->tk_action = call_decode;
-	} else if (status == -ETIMEDOUT) {
+		return;
+	}
+
+	task->tk_status = 0;
+	req = task->tk_rqstp;
+	switch(status) {
+	case -ETIMEDOUT:
 		task->tk_action = call_timeout;
-	} else if (status == -EAGAIN) {
-		if (!(req = task->tk_rqstp))
-			task->tk_action = call_reserve;
-		else if (!task->tk_buffer)
-			task->tk_action = call_allocate;
-		else if (req->rq_damaged)
+		break;
+	case -ECONNREFUSED:
+	case -ENOTCONN:
+		req->rq_bytes_sent = 0;
+		if (clnt->cl_autobind || !clnt->cl_port) {
+			clnt->cl_port = 0;
+			task->tk_action = call_bind;
+			break;
+		}
+		if (xprt->stream) {
+			task->tk_action = call_reconnect;
+			break;
+		}
+		/*
+		 * Sleep and dream of an open connection
+		 */
+		task->tk_timeout = 5 * HZ;
+		rpc_sleep_on(&xprt->sending, task, NULL, NULL);
+	case -ENOMEM:
+	case -EAGAIN:
+		if (req->rq_damaged)
 			task->tk_action = call_encode;
 		else
 			task->tk_action = call_transmit;
-	} else if (status == -ENOTCONN) {
-		task->tk_action = call_reconnect;
-	} else if (status == -ECONNREFUSED && clnt->cl_autobind) {
-		task->tk_action = call_bind;
-		clnt->cl_port = 0;
-	} else {
+		clnt->cl_stats->rpcretrans++;
+		break;
+	default:
 		if (clnt->cl_chatty)
 			printk("%s: RPC call returned error %d\n",
-				clnt->cl_protname, -status);
-		task->tk_action = NULL;
-		return;
+			       clnt->cl_protname, -status);
+		rpc_exit(task, status);
 	}
 }
 
@@ -581,39 +639,46 @@
 				task->tk_pid);
 			goto minor_timeout;
 		}
-		to->to_initval <<= 1;
-		if (to->to_initval > to->to_maxval)
-			to->to_initval = to->to_maxval;
+		to->to_retries = clnt->cl_timeout.to_retries;
+	} else {
+		printk(KERN_NOTICE "%s: task %d can't get a request slot\n",
+		       clnt->cl_protname, task->tk_pid);
+		goto minor_timeout;
 	}
 
 	dprintk("RPC: %4d call_timeout (major timeo)\n", task->tk_pid);
 	if (clnt->cl_softrtry) {
 		if (clnt->cl_chatty && !task->tk_exit)
-			printk("%s: server %s not responding, timed out\n",
+			printk(KERN_NOTICE "%s: server %s not responding, timed out\n",
 				clnt->cl_protname, clnt->cl_server);
 		rpc_exit(task, -EIO);
 		return;
 	}
+
 	if (clnt->cl_chatty && !(task->tk_flags & RPC_CALL_MAJORSEEN)) {
 		task->tk_flags |= RPC_CALL_MAJORSEEN;
-		if (req)
-			printk("%s: server %s not responding, still trying\n",
-				clnt->cl_protname, clnt->cl_server);
-		else 
-			printk("%s: task %d can't get a request slot\n",
-				clnt->cl_protname, task->tk_pid);
+		printk(KERN_NOTICE "%s: server %s not responding, timed out\n",
+		       clnt->cl_protname, clnt->cl_server);
+	} else if (clnt->cl_chatty) {
+		printk(KERN_NOTICE "%s: server %s not responding, still trying\n",
+		       clnt->cl_protname, clnt->cl_server);
 	}
+
 	if (clnt->cl_autobind)
 		clnt->cl_port = 0;
 
 minor_timeout:
-	if (!clnt->cl_port) {
-		task->tk_action = call_bind;
-	} else if (!req) {
+	if (!req)
 		task->tk_action = call_reserve;
-	} else if (req->rq_damaged) {
+	else if (req->rq_damaged) {
 		task->tk_action = call_encode;
 		clnt->cl_stats->rpcretrans++;
+	} else if (!clnt->cl_port) {
+		task->tk_action = call_bind;
+		clnt->cl_stats->rpcretrans++;
+	} else if (clnt->cl_xprt->stream && !clnt->cl_xprt->connected) {
+		task->tk_action = call_reconnect;
+		clnt->cl_stats->rpcretrans++;
 	} else {
 		task->tk_action = call_transmit;
 		clnt->cl_stats->rpcretrans++;
@@ -622,23 +687,6 @@
 }
 
 /*
- * 6b.	Reconnect to the RPC server (TCP case)
- */
-static void
-call_reconnect(struct rpc_task *task)
-{
-	dprintk("RPC: %4d call_reconnect status %d\n",
-				task->tk_pid, task->tk_status);
-	if (task->tk_status == 0) {
-		task->tk_action = call_status;
-		task->tk_status = -EAGAIN;
-		return;
-	}
-	task->tk_client->cl_stats->netreconn++;
-	xprt_reconnect(task);
-}
-
-/*
  * 7.	Decode the RPC reply
  */
 static void
@@ -646,20 +694,20 @@
 {
 	struct rpc_clnt	*clnt = task->tk_client;
 	struct rpc_rqst	*req = task->tk_rqstp;
-	kxdrproc_t	decode = rpcproc_decode(clnt, task->tk_proc);
+	kxdrproc_t	decode = rpcproc_decode(clnt, task->tk_msg.rpc_proc);
 	u32		*p;
 
 	dprintk("RPC: %4d call_decode (status %d)\n", 
 				task->tk_pid, task->tk_status);
 
 	if (clnt->cl_chatty && (task->tk_flags & RPC_CALL_MAJORSEEN)) {
-		printk("%s: server %s OK\n",
+		printk(KERN_NOTICE "%s: server %s OK\n",
 			clnt->cl_protname, clnt->cl_server);
 		task->tk_flags &= ~RPC_CALL_MAJORSEEN;
 	}
 
 	if (task->tk_status < 12) {
-		printk("%s: too small RPC reply size (%d bytes)\n",
+		printk(KERN_WARNING "%s: too small RPC reply size (%d bytes)\n",
 			clnt->cl_protname, task->tk_status);
 		rpc_exit(task, -EIO);
 		return;
@@ -675,16 +723,19 @@
 	 */
 	if (task->tk_client->cl_prog == 100003 && 
             (ntohl(*p) == NFSERR_ACCES || ntohl(*p) == NFSERR_PERM)) {
-		if (RPC_IS_SETUID(task) && (task->tk_suid_retry)--) {
+		if (RPC_IS_SETUID(task) && task->tk_suid_retry) {
 			dprintk("RPC: %4d retry squashed uid\n", task->tk_pid);
 			task->tk_flags ^= RPC_CALL_REALUID;
 			task->tk_action = call_encode;
+			task->tk_suid_retry--;
 			return;
 		}
 	}
 
 	task->tk_action = NULL;
-	task->tk_status = decode(req, p, task->tk_resp);
+
+	if (decode)
+		task->tk_status = decode(req, p, task->tk_msg.rpc_resp);
 	dprintk("RPC: %4d call_decode result %d\n", task->tk_pid,
 					task->tk_status);
 }
@@ -713,10 +764,9 @@
 	dprintk("RPC: %4d call_refreshresult (status %d)\n", 
 				task->tk_pid, task->tk_status);
 
-	if (task->tk_status < 0) {
-		task->tk_status = -EACCES;
-		task->tk_action = NULL;
-	} else
+	if (task->tk_status < 0)
+		rpc_exit(task, -EACCES);
+	else
 		task->tk_action = call_reserve;
 }
 
@@ -738,7 +788,7 @@
 	*p++ = htonl(RPC_VERSION);	/* RPC version */
 	*p++ = htonl(clnt->cl_prog);	/* program number */
 	*p++ = htonl(clnt->cl_vers);	/* program version */
-	*p++ = htonl(task->tk_proc);	/* procedure */
+	*p++ = htonl(task->tk_msg.rpc_proc);	/* procedure */
 	return rpcauth_marshcred(task, p);
 }
 
@@ -753,20 +803,21 @@
 	p += 1;	/* skip XID */
 
 	if ((n = ntohl(*p++)) != RPC_REPLY) {
-		printk("call_verify: not an RPC reply: %x\n", n);
+		printk(KERN_WARNING "call_verify: not an RPC reply: %x\n", n);
 		goto garbage;
 	}
 	if ((n = ntohl(*p++)) != RPC_MSG_ACCEPTED) {
 		int	error = -EACCES;
 
 		if ((n = ntohl(*p++)) != RPC_AUTH_ERROR) {
-			printk("call_verify: RPC call rejected: %x\n", n);
+			printk(KERN_WARNING "call_verify: RPC call rejected: %x\n", n);
 		} else
 		switch ((n = ntohl(*p++))) {
 		case RPC_AUTH_REJECTEDCRED:
 		case RPC_AUTH_REJECTEDVERF:
-			if (!task->tk_cred_retry--)
+			if (!task->tk_cred_retry)
 				break;
+			task->tk_cred_retry--;
 			dprintk("RPC: %4d call_verify: retry stale creds\n",
 							task->tk_pid);
 			rpcauth_invalcred(task);
@@ -775,17 +826,18 @@
 		case RPC_AUTH_BADCRED:
 		case RPC_AUTH_BADVERF:
 			/* possibly garbled cred/verf? */
-			if (!task->tk_garb_retry--)
+			if (!task->tk_garb_retry)
 				break;
+			task->tk_garb_retry--;
 			dprintk("RPC: %4d call_verify: retry garbled creds\n",
 							task->tk_pid);
 			task->tk_action = call_encode;
 			return NULL;
 		case RPC_AUTH_TOOWEAK:
-			printk("call_verify: server requires stronger "
+			printk(KERN_NOTICE "call_verify: server requires stronger "
 			       "authentication.\n");
 		default:
-			printk("call_verify: unknown auth error: %x\n", n);
+			printk(KERN_WARNING "call_verify: unknown auth error: %x\n", n);
 			error = -EIO;
 		}
 		dprintk("RPC: %4d call_verify: call rejected %d\n",
@@ -794,7 +846,7 @@
 		return NULL;
 	}
 	if (!(p = rpcauth_checkverf(task, p))) {
-		printk("call_verify: auth check failed\n");
+		printk(KERN_WARNING "call_verify: auth check failed\n");
 		goto garbage;		/* bad verifier, retry */
 	}
 	switch ((n = ntohl(*p++))) {
@@ -803,19 +855,20 @@
 	case RPC_GARBAGE_ARGS:
 		break;			/* retry */
 	default:
-		printk("call_verify: server accept status: %x\n", n);
+		printk(KERN_WARNING "call_verify: server accept status: %x\n", n);
 		/* Also retry */
 	}
 
 garbage:
 	dprintk("RPC: %4d call_verify: server saw garbage\n", task->tk_pid);
 	task->tk_client->cl_stats->rpcgarbage++;
-	if (task->tk_garb_retry--) {
-		printk("RPC: garbage, retrying %4d\n", task->tk_pid);
+	if (task->tk_garb_retry) {
+		printk(KERN_WARNING "RPC: garbage, retrying %4d\n", task->tk_pid);
 		task->tk_action = call_encode;
+		task->tk_garb_retry--;
 		return NULL;
 	}
-	printk("RPC: garbage, exit EIO\n");
+	printk(KERN_WARNING "RPC: garbage, exit EIO\n");
 	rpc_exit(task, -EIO);
 	return NULL;
 }
Index: oldkernel/linux/net/sunrpc/pmap_clnt.c
diff -u linux/net/sunrpc/pmap_clnt.c:1.1.1.1 linux/net/sunrpc/pmap_clnt.c:1.2
--- linux/net/sunrpc/pmap_clnt.c:1.1.1.1	Wed May 31 12:33:49 2000
+++ linux/net/sunrpc/pmap_clnt.c	Fri Jul  7 15:36:50 2000
@@ -41,6 +41,7 @@
 {
 	struct rpc_portmap *map = &clnt->cl_pmap;
 	struct sockaddr_in *sap = &clnt->cl_xprt->addr;
+	struct rpc_message msg = { PMAP_GETPORT, map, &clnt->cl_port, NULL };
 	struct rpc_clnt	*pmap_clnt;
 	struct rpc_task	*child;
 
@@ -66,7 +67,7 @@
 		goto bailout;
 
 	/* Setup the call info struct */
-	rpc_call_setup(child, PMAP_GETPORT, map, &clnt->cl_port, 0);
+	rpc_call_setup(child, &msg, 0);
 
 	/* ... and run the child task */
 	rpc_run_child(task, child, pmap_getport_done);
@@ -121,7 +122,7 @@
 		task->tk_action = NULL;
 	} else if (clnt->cl_port == 0) {
 		/* Program not registered */
-		task->tk_status = -EACCES;
+		task->tk_status = -EPROTONOSUPPORT;
 		task->tk_action = NULL;
 	} else {
 		/* byte-swap port number first */
Index: oldkernel/linux/net/sunrpc/sched.c
diff -u linux/net/sunrpc/sched.c:1.2 linux/net/sunrpc/sched.c:1.3
--- linux/net/sunrpc/sched.c:1.2	Thu Jun  1 15:39:01 2000
+++ linux/net/sunrpc/sched.c	Fri Jul  7 15:36:50 2000
@@ -18,6 +18,7 @@
 #include <linux/unistd.h>
 #include <linux/smp.h>
 #include <linux/smp_lock.h>
+#include <asm/spinlock.h>
 
 #include <linux/sunrpc/clnt.h>
 
@@ -68,12 +69,84 @@
 static int			rpc_inhibit = 0;
 
 /*
+ * Spinlock for wait queues. Access to the latter also has to be
+ * interrupt-safe in order to allow timers to wake up sleeping tasks.
+ */
+spinlock_t rpc_queue_lock = SPIN_LOCK_UNLOCKED;
+/*
+ * Spinlock for other critical sections of code.
+ */
+spinlock_t rpc_sched_lock = SPIN_LOCK_UNLOCKED;
+
+/*
  * This is the last-ditch buffer for NFS swap requests
  */
 static u32			swap_buffer[PAGE_SIZE >> 2];
 static int			swap_buffer_used = 0;
 
 /*
+ * Make allocation of the swap_buffer SMP-safe
+ */
+static __inline__ int rpc_lock_swapbuf(void)
+{
+	return !test_and_set_bit(1, &swap_buffer_used);
+}
+static __inline__ void rpc_unlock_swapbuf(void)
+{
+	clear_bit(1, &swap_buffer_used);
+}
+
+/*
+ * Set up a timer for the current task.
+ */
+static inline void
+__rpc_add_timer(struct rpc_task *task, rpc_action timer)
+{
+	if (!task->tk_timeout)
+		return;
+
+	dprintk("RPC: %4d setting alarm for %lu ms\n",
+			task->tk_pid, task->tk_timeout * 1000 / HZ);
+
+	if (timer_pending(&task->tk_timer)) {
+		printk(KERN_ERR "RPC: Bug! Overwriting active timer\n");
+		del_timer(&task->tk_timer);
+	}
+	if (!timer)
+		timer = __rpc_default_timer;
+	init_timer(&task->tk_timer);
+	task->tk_timer.expires  = jiffies + task->tk_timeout;
+	task->tk_timer.data     = (unsigned long) task;
+	task->tk_timer.function = (void (*)(unsigned long)) timer;
+	add_timer(&task->tk_timer);
+}
+
+/*
+ * Set up a timer for an already sleeping task.
+ */
+void rpc_add_timer(struct rpc_task *task, rpc_action timer)
+{
+	unsigned long	oldflags;
+
+	spin_lock_irqsave(&rpc_queue_lock, oldflags);
+	if (!(RPC_IS_RUNNING(task) || task->tk_wakeup))
+		__rpc_add_timer(task, timer);
+	spin_unlock_irqrestore(&rpc_queue_lock, oldflags);
+}
+
+/*
+ * Delete any timer for the current task.
+ */
+static inline void
+__rpc_del_timer(struct rpc_task *task)
+{
+	dprintk("RPC: %4d deleting timer\n", task->tk_pid);
+	if (timer_pending(&task->tk_timer))
+		del_timer(&task->tk_timer);
+	task->tk_timeout = 0;
+}
+
+/*
  * Add new request to wait queue.
  *
  * Swapper tasks always get inserted at the head of the queue.
@@ -81,16 +154,17 @@
  * improve overall performance.
  * Everyone else gets appended to the queue to ensure proper FIFO behavior.
  */
-int
-rpc_add_wait_queue(struct rpc_wait_queue *queue, struct rpc_task *task)
+static inline int
+__rpc_add_wait_queue(struct rpc_wait_queue *queue, struct rpc_task *task)
 {
-	if (task->tk_rpcwait) {
-		if (task->tk_rpcwait != queue)
-		{
-			printk(KERN_WARNING "RPC: doubly enqueued task!\n");
-			return -EWOULDBLOCK;
-		}
+	if (task->tk_rpcwait == queue)
 		return 0;
+
+	if (task->tk_rpcwait) {
+		printk(KERN_WARNING "RPC: task already queued!\n");
+		dprintk("task already on %s, to be added to %s\n",
+			rpc_qname(task->tk_rpcwait), rpc_qname(queue));
+		return -EWOULDBLOCK;
 	}
 	if (RPC_IS_SWAPPER(task))
 		rpc_insert_list(&queue->task, task);
@@ -104,17 +178,30 @@
 	return 0;
 }
 
+int
+rpc_add_wait_queue(struct rpc_wait_queue *q, struct rpc_task *task)
+{
+	unsigned long	oldflags;
+	int		result;
+
+	spin_lock_irqsave(&rpc_queue_lock, oldflags);
+	result = __rpc_add_wait_queue(q, task);
+	spin_unlock_irqrestore(&rpc_queue_lock, oldflags);
+	return result;
+}
+
 /*
  * Remove request from queue.
- * Note: must be called with interrupts disabled.
+ * Note: must be called with spin lock held.
  */
-void
-rpc_remove_wait_queue(struct rpc_task *task)
+static inline void
+__rpc_remove_wait_queue(struct rpc_task *task)
 {
-	struct rpc_wait_queue *queue;
+	struct rpc_wait_queue *queue = task->tk_rpcwait;
 
-	if (!(queue = task->tk_rpcwait))
+	if (!queue)
 		return;
+
 	rpc_remove_list(&queue->task, task);
 	task->tk_rpcwait = NULL;
 
@@ -122,50 +209,23 @@
 				task->tk_pid, queue, rpc_qname(queue));
 }
 
-/*
- * Set up a timer for the current task.
- */
-inline void
-rpc_add_timer(struct rpc_task *task, rpc_action timer)
+void
+rpc_remove_wait_queue(struct rpc_task *task)
 {
-	unsigned long	expires = jiffies + task->tk_timeout;
-
-	dprintk("RPC: %4d setting alarm for %lu ms\n",
-			task->tk_pid, task->tk_timeout * 1000 / HZ);
-	if (!timer)
-		timer = __rpc_default_timer;
-	if (time_before(expires, jiffies)) {
-		printk(KERN_ERR "RPC: bad timeout value %ld - setting to 10 sec!\n",
-					task->tk_timeout);
-		expires = jiffies + 10 * HZ;
-	}
-	task->tk_timer.expires  = expires;
-	task->tk_timer.data     = (unsigned long) task;
-	task->tk_timer.function = (void (*)(unsigned long)) timer;
-	task->tk_timer.prev     = NULL;
-	task->tk_timer.next     = NULL;
-	add_timer(&task->tk_timer);
-}
+	unsigned long	oldflags;
 
-/*
- * Delete any timer for the current task.
- * Must be called with interrupts off.
- */
-inline void
-rpc_del_timer(struct rpc_task *task)
-{
-	if (task->tk_timeout) {
-		dprintk("RPC: %4d deleting timer\n", task->tk_pid);
-		del_timer(&task->tk_timer);
-		task->tk_timeout = 0;
-	}
+	if (!task->tk_rpcwait)
+		return;
+	spin_lock_irqsave(&rpc_queue_lock, oldflags);
+	__rpc_remove_wait_queue(task);
+	spin_unlock_irqrestore(&rpc_queue_lock, oldflags);
 }
 
 /*
  * Make an RPC task runnable.
  *
  * Note: If the task is ASYNC, this must be called with 
- * interrupts disabled to protect the wait queue operation.
+ * the spinlock held to protect the wait queue operation.
  */
 static inline void
 rpc_make_runnable(struct rpc_task *task)
@@ -176,19 +236,36 @@
 	}
 	task->tk_flags |= RPC_TASK_RUNNING;
 	if (RPC_IS_ASYNC(task)) {
-		int status;
-		status = rpc_add_wait_queue(&schedq, task);
-		if (status)
-		{
-			printk(KERN_WARNING "RPC: failed to add task to queue: error: %d!\n", status);
-			task->tk_status = status;
+		if (RPC_IS_SLEEPING(task)) {
+			int status;
+			status = __rpc_add_wait_queue(&schedq, task);
+			if (status < 0) {
+				printk(KERN_WARNING "RPC: failed to add task to queue: error: %d!\n", status);
+				task->tk_status = status;
+			} else
+				task->tk_sleeping = 0;
 		}
 		wake_up(&rpciod_idle);
 	} else {
+		task->tk_sleeping = 0;
 		wake_up(&task->tk_wait);
 	}
 }
 
+/*
+ * Place a newly initialized task on the schedq.
+ */
+static inline void
+rpc_schedule_run(struct rpc_task *task)
+{
+	/* Don't run a child twice! */
+	if (RPC_IS_ACTIVATED(task))
+		return;
+	task->tk_active = 1;
+	task->tk_sleeping = 1;
+	rpc_make_runnable(task);
+}
+
 
 /*
  *	For other people who may need to wake the I/O daemon
@@ -198,9 +275,7 @@
 void rpciod_wake_up(void)
 {
 	if(rpciod_pid==0)
-	{
 		printk(KERN_ERR "rpciod: wot no daemon?\n");
-	}
 	wake_up(&rpciod_idle);
 }
 
@@ -214,33 +289,32 @@
 __rpc_sleep_on(struct rpc_wait_queue *q, struct rpc_task *task,
 			rpc_action action, rpc_action timer)
 {
-	unsigned long	oldflags;
 	int status;
 
 	dprintk("RPC: %4d sleep_on(queue \"%s\" time %ld)\n", task->tk_pid,
 				rpc_qname(q), jiffies);
 
-	/*
-	 * Protect the execution below.
-	 */
-	save_flags(oldflags); cli();
+	if (!RPC_IS_ASYNC(task) && !RPC_IS_ACTIVATED(task)) {
+		printk(KERN_ERR "RPC: Inactive synchronous task put to sleep!\n");
+		return;
+	}
 
-	status = rpc_add_wait_queue(q, task);
-	if (status)
-	{
+	/* Mark the task as being activated if so needed */
+	if (!RPC_IS_ACTIVATED(task)) {
+		task->tk_active = 1;
+		task->tk_sleeping = 1;
+	}
+
+	status = __rpc_add_wait_queue(q, task);
+	if (status) {
 		printk(KERN_WARNING "RPC: failed to add task to queue: error: %d!\n", status);
 		task->tk_status = status;
-		task->tk_flags |= RPC_TASK_RUNNING;
-	}
-	else
-	{
-		task->tk_callback = action;
-		if (task->tk_timeout)
-			rpc_add_timer(task, timer);
+	} else {
 		task->tk_flags &= ~RPC_TASK_RUNNING;
+		task->tk_callback = action;
+		__rpc_add_timer(task, timer);
 	}
 
-	restore_flags(oldflags);
 	return;
 }
 
@@ -248,11 +322,33 @@
 rpc_sleep_on(struct rpc_wait_queue *q, struct rpc_task *task,
 				rpc_action action, rpc_action timer)
 {
+	unsigned long	oldflags;
+
+	/*
+	 * Protect the queue operations.
+	 */
+	spin_lock_irqsave(&rpc_queue_lock, oldflags);
+	__rpc_sleep_on(q, task, action, timer);
+	spin_unlock_irqrestore(&rpc_queue_lock, oldflags);
+}
+
+void
+rpc_sleep_locked(struct rpc_wait_queue *q, struct rpc_task *task,
+		 rpc_action action, rpc_action timer)
+{
+	unsigned long	oldflags;
+
+	/*
+	 * Protect the queue operations.
+	 */
+	spin_lock_irqsave(&rpc_queue_lock, oldflags);
 	__rpc_sleep_on(q, task, action, timer);
+	rpc_lock_task(task);
+	spin_unlock_irqrestore(&rpc_queue_lock, oldflags);
 }
 
 /*
- * Wake up a single task -- must be invoked with bottom halves off.
+ * Wake up a single task -- must be invoked with spin lock held.
  *
  * It would probably suffice to cli/sti the del_timer and remove_wait_queue
  * operations individually.
@@ -267,16 +363,33 @@
 	if (task->tk_magic != 0xf00baa) {
 		printk(KERN_ERR "RPC: attempt to wake up non-existing task!\n");
 		rpc_debug = ~0;
+		rpc_show_tasks();
 		return;
 	}
 #endif
-	rpc_del_timer(task);
-	if (task->tk_rpcwait != &schedq)
-		rpc_remove_wait_queue(task);
-	if (!RPC_IS_RUNNING(task)) {
-		task->tk_flags |= RPC_TASK_CALLBACK;
-		rpc_make_runnable(task);
+	/* Has the task been executed yet? If not, we cannot wake it up! */
+	if (!RPC_IS_ACTIVATED(task)) {
+		printk(KERN_ERR "RPC: Inactive task (%p) being woken up!\n", task);
+		return;
 	}
+	if (RPC_IS_RUNNING(task))
+		return;
+
+	__rpc_del_timer(task);
+
+	/* If the task has been locked, then set tk_wakeup so that
+	 * rpc_unlock_task() wakes us up... */
+	if (task->tk_lock) {
+		task->tk_wakeup = 1;
+		return;
+	} else
+		task->tk_wakeup = 0;
+
+	if (task->tk_rpcwait != &schedq)
+		__rpc_remove_wait_queue(task);
+	task->tk_flags |= RPC_TASK_CALLBACK;
+	rpc_make_runnable(task);
+
 	dprintk("RPC:      __rpc_wake_up done\n");
 }
 
@@ -286,10 +399,10 @@
 static void
 __rpc_default_timer(struct rpc_task *task)
 {
-	dprintk("RPC: %d timeout (default timer)\n", task->tk_pid);
+	dprintk("RPC: %4d timeout (default timer)\n", task->tk_pid);
 	task->tk_status = -ETIMEDOUT;
 	task->tk_timeout = 0;
-	__rpc_wake_up(task);
+	rpc_wake_up_task(task);
 }
 
 /*
@@ -300,9 +413,11 @@
 {
 	unsigned long	oldflags;
 
-	save_flags(oldflags); cli();
+	if (RPC_IS_RUNNING(task))
+		return;
+	spin_lock_irqsave(&rpc_queue_lock, oldflags);
 	__rpc_wake_up(task);
-	restore_flags(oldflags);
+	spin_unlock_irqrestore(&rpc_queue_lock, oldflags);
 }
 
 /*
@@ -311,14 +426,14 @@
 struct rpc_task *
 rpc_wake_up_next(struct rpc_wait_queue *queue)
 {
-	unsigned long	oldflags;
 	struct rpc_task	*task;
+	unsigned long	oldflags;
 
 	dprintk("RPC:      wake_up_next(%p \"%s\")\n", queue, rpc_qname(queue));
-	save_flags(oldflags); cli();
+	spin_lock_irqsave(&rpc_queue_lock, oldflags);
 	if ((task = queue->task) != 0)
 		__rpc_wake_up(task);
-	restore_flags(oldflags);
+	spin_unlock_irqrestore(&rpc_queue_lock, oldflags);
 
 	return task;
 }
@@ -331,10 +446,10 @@
 {
 	unsigned long	oldflags;
 
-	save_flags(oldflags); cli();
+	spin_lock_irqsave(&rpc_queue_lock, oldflags);
 	while (queue->task)
 		__rpc_wake_up(queue->task);
-	restore_flags(oldflags);
+	spin_unlock_irqrestore(&rpc_queue_lock, oldflags);
 }
 
 /*
@@ -346,12 +461,38 @@
 	struct rpc_task	*task;
 	unsigned long	oldflags;
 
-	save_flags(oldflags); cli();
+	spin_lock_irqsave(&rpc_queue_lock, oldflags);
 	while ((task = queue->task) != NULL) {
 		task->tk_status = status;
 		__rpc_wake_up(task);
 	}
-	restore_flags(oldflags);
+	spin_unlock_irqrestore(&rpc_queue_lock, oldflags);
+}
+
+/*
+ * Lock down a sleeping task to prevent it from waking up
+ * and disappearing from beneath us.
+ *
+ * This function should always be called with the
+ * rpc_queue_lock held.
+ */
+int
+rpc_lock_task(struct rpc_task *task)
+{
+	if (!RPC_IS_RUNNING(task))
+		return ++task->tk_lock;
+	return 0;
+}
+
+void
+rpc_unlock_task(struct rpc_task *task)
+{
+	unsigned long	oldflags;
+
+	spin_lock_irqsave(&rpc_queue_lock, oldflags);
+	if (task->tk_lock && !--task->tk_lock && task->tk_wakeup)
+		__rpc_wake_up(task);
+	spin_unlock_irqrestore(&rpc_queue_lock, oldflags);
 }
 
 /*
@@ -369,7 +510,7 @@
 __rpc_atrun(struct rpc_task *task)
 {
 	task->tk_status = 0;
-	__rpc_wake_up(task);
+	rpc_wake_up_task(task);
 }
 
 /*
@@ -389,11 +530,12 @@
 		return 0;
 	}
 
+restarted:
 	while (1) {
 		/*
 		 * Execute any pending callback.
 		 */
-		if (task->tk_flags & RPC_TASK_CALLBACK) {
+		if (RPC_DO_CALLBACK(task)) {
 			/* Define a callback save pointer */
 			void (*save_callback)(struct rpc_task *);
 	
@@ -425,86 +567,96 @@
 
 		/*
 		 * Check whether task is sleeping.
-		 * Note that if the task may go to sleep in tk_action,
+		 * Note that if the task goes to sleep in tk_action,
 		 * and the RPC reply arrives before we get here, it will
 		 * have state RUNNING, but will still be on schedq.
+		 * 27/9/99: The above has been attempted fixed by
+		 *          introduction of task->tk_sleeping.
 		 */
-		save_flags(oldflags); cli();
-		if (RPC_IS_RUNNING(task)) {
-			if (task->tk_rpcwait == &schedq)
-				rpc_remove_wait_queue(task);
-		} else while (!RPC_IS_RUNNING(task)) {
+		spin_lock_irqsave(&rpc_queue_lock, oldflags);
+		if (!RPC_IS_RUNNING(task)) {
+			task->tk_sleeping = 1;
 			if (RPC_IS_ASYNC(task)) {
-				restore_flags(oldflags);
+				spin_unlock_irqrestore(&rpc_queue_lock, oldflags);
 				return 0;
 			}
+		} else
+			task->tk_sleeping = 0;
+		spin_unlock_irqrestore(&rpc_queue_lock, oldflags);
 
+		while (RPC_IS_SLEEPING(task)) {
 			/* sync task: sleep here */
 			dprintk("RPC: %4d sync task going to sleep\n",
 							task->tk_pid);
 			if (current->pid == rpciod_pid)
 				printk(KERN_ERR "RPC: rpciod waiting on sync task!\n");
 
-			sti();
-			__wait_event(task->tk_wait, RPC_IS_RUNNING(task));
-			cli();
+			__wait_event(task->tk_wait, !RPC_IS_SLEEPING(task));
+			dprintk("RPC: %4d sync task resuming\n", task->tk_pid);
 
 			/*
-			 * When the task received a signal, remove from
-			 * any queues etc, and make runnable again.
+			 * When a sync task receives a signal, it exits with
+			 * -ERESTARTSYS. In order to catch any callbacks that
+			 * clean up after sleeping on some queue, we don't
+			 * break the loop here, but go around once more.
 			 */
-			if (signalled())
-				__rpc_wake_up(task);
-
-			dprintk("RPC: %4d sync task resuming\n",
-							task->tk_pid);
-		}
-		restore_flags(oldflags);
-
-		/*
-		 * When a sync task receives a signal, it exits with
-		 * -ERESTARTSYS. In order to catch any callbacks that
-		 * clean up after sleeping on some queue, we don't
-		 * break the loop here, but go around once more.
-		 */
-		if (!RPC_IS_ASYNC(task) && signalled()) {
-			dprintk("RPC: %4d got signal\n", task->tk_pid);
-			rpc_exit(task, -ERESTARTSYS);
+			if (task->tk_client->cl_intr && signalled()) {
+				dprintk("RPC: %4d got signal\n", task->tk_pid);
+				task->tk_flags |= RPC_TASK_KILLED;
+				rpc_exit(task, -ERESTARTSYS);
+				rpc_wake_up_task(task);
+			}
 		}
 	}
 
 	dprintk("RPC: %4d exit() = %d\n", task->tk_pid, task->tk_status);
 	if (task->tk_exit) {
-		status = task->tk_status;
 		task->tk_exit(task);
+		/* If tk_action is non-null, the user wants us to restart */
+		if (task->tk_action) {
+			if (!RPC_ASSASSINATED(task)) {
+					/* Release RPC slot and buffer memory */
+					if (task->tk_rqstp)
+						xprt_release(task);
+					if (task->tk_buffer) {
+						rpc_free(task->tk_buffer);
+						task->tk_buffer = NULL;
+					}
+					goto restarted;
+			}
+			printk(KERN_ERR "RPC: dead task tries to walk away.\n");
+		}
 	}
 
+	/* Save the task exit status */
+	status = task->tk_status;
+
+	/* Release all resources associated with the task */
+	rpc_release_task(task);
 	return status;
 }
 
 /*
  * User-visible entry point to the scheduler.
- * The recursion protection is for debugging. It should go away once
- * the code has stabilized.
+ *
+ * This may be called recursively if e.g. an async NFS task updates
+ * the attributes and finds that dirty pages must be flushed.
  */
-void
+int
 rpc_execute(struct rpc_task *task)
 {
-	static int	executing = 0;
-	int		incr = RPC_IS_ASYNC(task)? 1 : 0;
-
-	if (incr) {
-		if (rpc_inhibit) {
-			printk(KERN_INFO "RPC: execution inhibited!\n");
-			return;
-		}
-		if (executing)
-			printk(KERN_WARNING "RPC: %d tasks executed\n", executing);
+	if (rpc_inhibit) {
+		printk(KERN_INFO "RPC: execution inhibited!\n");
+		return -EIO;
 	}
+	task->tk_flags |= RPC_TASK_RUNNING;
+	if (task->tk_active) {
+		printk(KERN_ERR "RPC: active task was run twice!\n");
+		return -EWOULDBLOCK;
+	}
+	task->tk_active = 1;
 	
-	executing += incr;
-	__rpc_execute(task);
-	executing -= incr;
+	return __rpc_execute(task);
 }
 
 /*
@@ -514,31 +666,36 @@
 __rpc_schedule(void)
 {
 	struct rpc_task	*task;
-	int		count = 0;
 	unsigned long	oldflags;
-	int need_resched = current->need_resched;
+	int		count = 0;
 
 	dprintk("RPC:      rpc_schedule enter\n");
-	save_flags(oldflags);
 	while (1) {
-		cli();
-		if (!(task = schedq.task))
+		/* Ensure equal rights for tcp tasks... */
+		rpciod_tcp_dispatcher();
+
+		spin_lock_irqsave(&rpc_queue_lock, oldflags);
+		if (!(task = schedq.task)) {
+			spin_unlock_irqrestore(&rpc_queue_lock, oldflags);
+			break;
+		}
+		if (task->tk_lock) {
+			spin_unlock_irqrestore(&rpc_queue_lock, oldflags);
+			printk(KERN_ERR "RPC: Locked task was scheduled !!!!\n");
+			rpc_debug = ~0;
+			rpc_show_tasks();
 			break;
-		rpc_del_timer(task);
-		rpc_remove_wait_queue(task);
-		task->tk_flags |= RPC_TASK_RUNNING;
-		restore_flags(oldflags);
+		}
+		__rpc_remove_wait_queue(task);
+		spin_unlock_irqrestore(&rpc_queue_lock, oldflags);
 
 		__rpc_execute(task);
 
-		if (++count >= 200) {
+		if (++count >= 200 || current->need_resched) {
+			schedule();
 			count = 0;
-			need_resched = 1;
 		}
-		if (need_resched)
-			schedule();
 	}
-	restore_flags(oldflags);
 	dprintk("RPC:      rpc_schedule leave\n");
 }
 
@@ -579,7 +736,8 @@
 			dprintk("RPC:      allocated buffer %p\n", buffer);
 			return buffer;
 		}
-		if ((flags & RPC_TASK_SWAPPER) && !swap_buffer_used++) {
+		if ((flags & RPC_TASK_SWAPPER) && size <= sizeof(swap_buffer)
+		 && rpc_lock_swapbuf()) {
 			dprintk("RPC:      used last-ditch swap buffer\n");
 			return swap_buffer;
 		}
@@ -587,6 +745,7 @@
 			return NULL;
 		current->state = TASK_INTERRUPTIBLE;
 		schedule_timeout(HZ>>4);
+		current->state = TASK_RUNNING;
 	} while (!signalled());
 
 	return NULL;
@@ -599,20 +758,21 @@
 		kfree(buffer);
 		return;
 	}
-	swap_buffer_used = 0;
+	rpc_unlock_swapbuf();
 }
 
 /*
  * Creation and deletion of RPC task structures
  */
-inline void
+void
 rpc_init_task(struct rpc_task *task, struct rpc_clnt *clnt,
 				rpc_action callback, int flags)
 {
 	memset(task, 0, sizeof(*task));
+	init_timer(&task->tk_timer);
 	task->tk_client = clnt;
-	task->tk_flags  = RPC_TASK_RUNNING | flags;
 	task->tk_exit   = callback;
+	task->tk_flags  = flags;
 	if (current->uid != current->fsuid || current->gid != current->fsgid)
 		task->tk_flags |= RPC_TASK_SETUID;
 
@@ -621,22 +781,26 @@
 	task->tk_cred_retry = 2;
 	task->tk_suid_retry = 1;
 
+#ifdef RPC_DEBUG
+	task->tk_magic = 0xf00baa;
+	task->tk_pid = rpc_task_id++;
+#endif
+
 	/* Add to global list of all tasks */
+	spin_lock(&rpc_sched_lock);
 	task->tk_next_task = all_tasks;
 	task->tk_prev_task = NULL;
 	if (all_tasks)
 		all_tasks->tk_prev_task = task;
 	all_tasks = task;
+	spin_unlock(&rpc_sched_lock);
 
 	if (clnt)
 		clnt->cl_users++;
 
-#ifdef RPC_DEBUG
-	task->tk_magic = 0xf00baa;
-	task->tk_pid = rpc_task_id++;
-#endif
-	dprintk("RPC: %4d new task procpid %d\n", task->tk_pid,
-				current->pid);
+	dprintk("RPC: %d new task procpid %d%s\n",
+			task->tk_pid, current->pid,
+			(flags & RPC_TASK_DYNAMIC) ? " (alloc)" : "");
 }
 
 /*
@@ -653,10 +817,7 @@
 	if (!task)
 		goto cleanup;
 
-	rpc_init_task(task, clnt, callback, flags);
-
-	dprintk("RPC: %4d allocated task\n", task->tk_pid);
-	task->tk_flags |= RPC_TASK_DYNAMIC;
+	rpc_init_task(task, clnt, callback, flags | RPC_TASK_DYNAMIC);
 out:
 	return task;
 
@@ -675,10 +836,21 @@
 rpc_release_task(struct rpc_task *task)
 {
 	struct rpc_task	*next, *prev;
+	unsigned long	oldflags;
 
 	dprintk("RPC: %4d release task\n", task->tk_pid);
 
+#ifdef RPC_DEBUG
+	if (task->tk_magic != 0xf00baa) {
+		printk(KERN_ERR "RPC: attempt to release a non-existing task!\n");
+		rpc_debug = ~0;
+		rpc_show_tasks();
+		return;
+	}
+#endif
+
 	/* Remove from global task list */
+	spin_lock(&rpc_sched_lock);
 	prev = task->tk_prev_task;
 	next = task->tk_next_task;
 	if (next)
@@ -687,12 +859,27 @@
 		prev->tk_next_task = next;
 	else
 		all_tasks = next;
+	task->tk_next_task = task->tk_prev_task = NULL;
+	spin_unlock(&rpc_sched_lock);
+
+	/* Protect the execution below. */
+	spin_lock_irqsave(&rpc_queue_lock, oldflags);
 
+	/* Delete any running timer */
+	__rpc_del_timer(task);
+
+	/* Remove from any wait queue we're still on */
+	__rpc_remove_wait_queue(task);
+
+	task->tk_active = 0;
+
+	spin_unlock_irqrestore(&rpc_queue_lock, oldflags);
+
 	/* Release resources */
 	if (task->tk_rqstp)
 		xprt_release(task);
-	if (task->tk_cred)
-		rpcauth_releasecred(task);
+	if (task->tk_msg.rpc_cred)
+		rpcauth_unbindcred(task);
 	if (task->tk_buffer) {
 		rpc_free(task->tk_buffer);
 		task->tk_buffer = NULL;
@@ -708,9 +895,12 @@
 
 	if (task->tk_flags & RPC_TASK_DYNAMIC) {
 		dprintk("RPC: %4d freeing task\n", task->tk_pid);
+		if (task->tk_release)
+			task->tk_release(task);
 		task->tk_flags &= ~RPC_TASK_DYNAMIC;
 		rpc_free(task);
-	}
+	} else if (task->tk_release)
+			task->tk_release(task);
 }
 
 /*
@@ -735,12 +925,14 @@
 rpc_child_exit(struct rpc_task *child)
 {
 	struct rpc_task	*parent;
+	unsigned long	oldflags;
 
+	spin_lock_irqsave(&rpc_queue_lock, oldflags);
 	if ((parent = rpc_find_parent(child)) != NULL) {
 		parent->tk_status = child->tk_status;
-		rpc_wake_up_task(parent);
+		__rpc_wake_up(parent);
 	}
-	rpc_release_task(child);
+	spin_unlock_irqrestore(&rpc_queue_lock, oldflags);
 }
 
 /*
@@ -766,13 +958,13 @@
 void
 rpc_run_child(struct rpc_task *task, struct rpc_task *child, rpc_action func)
 {
-	unsigned long oldflags;
+	unsigned long	oldflags;
 
-	save_flags(oldflags); cli();
-	rpc_make_runnable(child);
-	restore_flags(oldflags);
+	spin_lock_irqsave(&rpc_queue_lock, oldflags);
 	/* N.B. Is it possible for the child to have already finished? */
-	rpc_sleep_on(&childq, task, func, NULL);
+	__rpc_sleep_on(&childq, task, func, NULL);
+	rpc_schedule_run(child);
+	spin_unlock_irqrestore(&rpc_queue_lock, oldflags);
 }
 
 /*
@@ -785,8 +977,10 @@
 	struct rpc_task	**q, *rovr;
 
 	dprintk("RPC:      killing all tasks for client %p\n", clnt);
-	/* N.B. Why bother to inhibit? Nothing blocks here ... */
-	rpc_inhibit++;
+	/*
+	 * Spin lock all_tasks to prevent changes...
+	 */
+	spin_lock(&rpc_sched_lock);
 	for (q = &all_tasks; (rovr = *q); q = &rovr->tk_next_task) {
 		if (!clnt || rovr->tk_client == clnt) {
 			rovr->tk_flags |= RPC_TASK_KILLED;
@@ -794,11 +988,17 @@
 			rpc_wake_up_task(rovr);
 		}
 	}
-	rpc_inhibit--;
+	spin_unlock(&rpc_sched_lock);
 }
 
 static struct semaphore rpciod_running = MUTEX_LOCKED;
 
+static inline int
+rpciod_task_pending(void)
+{
+	return schedq.task != NULL || xprt_tcp_pending();
+}
+
 /*
  * This is the rpciod kernel thread
  */
@@ -806,11 +1006,12 @@
 rpciod(void *ptr)
 {
 	struct wait_queue **assassin = (struct wait_queue **) ptr;
-	unsigned long	oldflags;
 	int		rounds = 0;
 
 	MOD_INC_USE_COUNT;
+
 	lock_kernel();
+
 	/*
 	 * Let our maker know we're running ...
 	 */
@@ -837,22 +1038,17 @@
 		}
 		__rpc_schedule();
 
-		if (++rounds >= 64) {	/* safeguard */
+		if (++rounds >= 64 || current->need_resched) {	/* safeguard */
 			schedule();
 			rounds = 0;
 		}
-		save_flags(oldflags); cli();
-		dprintk("RPC: rpciod running checking dispatch\n");
-		rpciod_tcp_dispatcher();
 
-		if (!schedq.task) {
+		if (!rpciod_task_pending()) {
 			dprintk("RPC: rpciod back to sleep\n");
-			interruptible_sleep_on(&rpciod_idle);
+			wait_event_interruptible(rpciod_idle, rpciod_task_pending());
 			dprintk("RPC: switch to rpciod\n");
-			rpciod_tcp_dispatcher();
 			rounds = 0;
 		}
-		restore_flags(oldflags);
 	}
 
 	dprintk("RPC: rpciod shutdown commences\n");
@@ -882,6 +1078,7 @@
 			dprintk("rpciod_killall: waiting for tasks to exit\n");
 			current->state = TASK_INTERRUPTIBLE;
 			schedule_timeout(1);
+			current->state = TASK_RUNNING;
 		}
 	}
 
@@ -953,6 +1150,7 @@
 	current->sigpending = 0;
 	current->state = TASK_INTERRUPTIBLE;
 	schedule_timeout(1);
+	current->state = TASK_RUNNING;
 	/*
 	 * Display a message if we're going to wait longer.
 	 */
@@ -972,36 +1170,26 @@
 	MOD_DEC_USE_COUNT;
 }
 
-#ifdef RPC_DEBUG
-#include <linux/nfs_fs.h>
 void rpc_show_tasks(void)
 {
 	struct rpc_task *t = all_tasks, *next;
-	struct nfs_wreq *wreq;
 
-	if (!t)
+	spin_lock(&rpc_sched_lock);
+	t = all_tasks;
+	if (!t) {
+		spin_unlock(&rpc_sched_lock);
 		return;
+	}
 	printk("-pid- proc flgs status -client- -prog- --rqstp- -timeout "
 		"-rpcwait -action- --exit--\n");
 	for (; t; t = next) {
 		next = t->tk_next_task;
 		printk("%05d %04d %04x %06d %8p %6d %8p %08ld %8s %8p %8p\n",
-			t->tk_pid, t->tk_proc, t->tk_flags, t->tk_status,
+			t->tk_pid, t->tk_msg.rpc_proc, t->tk_flags, t->tk_status,
 			t->tk_client, t->tk_client->cl_prog,
 			t->tk_rqstp, t->tk_timeout,
 			t->tk_rpcwait ? rpc_qname(t->tk_rpcwait) : " <NULL> ",
 			t->tk_action, t->tk_exit);
-
-		if (!(t->tk_flags & RPC_TASK_NFSWRITE))
-			continue;
-		/* NFS write requests */
-		wreq = (struct nfs_wreq *) t->tk_calldata;
-		printk("     NFS: flgs=%08x, pid=%d, pg=%p, off=(%d, %d)\n",
-			wreq->wb_flags, wreq->wb_pid, wreq->wb_page,
-			wreq->wb_offset, wreq->wb_bytes);
-		printk("          name=%s/%s\n",
-			wreq->wb_file->f_dentry->d_parent->d_name.name,
-			wreq->wb_file->f_dentry->d_name.name);
 	}
+	spin_unlock(&rpc_sched_lock);
 }
-#endif
Index: oldkernel/linux/net/sunrpc/stats.c
diff -u linux/net/sunrpc/stats.c:1.1.1.1 linux/net/sunrpc/stats.c:1.2
--- linux/net/sunrpc/stats.c:1.1.1.1	Wed May 31 12:33:49 2000
+++ linux/net/sunrpc/stats.c	Fri Jul  7 15:36:50 2000
@@ -128,6 +128,7 @@
 {
 	struct proc_dir_entry	*ent;
 
+	rpc_proc_init();
 	dprintk("RPC: registering /proc/net/rpc/%s\n", name);
 	ent = create_proc_entry(name, 0, proc_net_rpc);
 	ent->read_proc = issvc? svc_proc_read : rpc_proc_read;
@@ -174,6 +175,9 @@
 			proc_net_rpc = ent;
 		}
 	}
+#ifdef RPC_DEBUG
+	rpc_register_sysctl();
+#endif
 }
 
 void
@@ -184,6 +188,9 @@
 		proc_net_rpc = NULL;
 		remove_proc_entry("net/rpc", 0);
 	}
+#ifdef RPC_DEBUG
+	rpc_unregister_sysctl();
+#endif
 }
 
 #ifdef MODULE
@@ -206,9 +213,6 @@
 int
 init_module(void)
 {
-#ifdef RPC_DEBUG
-	rpc_register_sysctl();
-#endif
 	rpc_proc_init();
 	return 0;
 }
@@ -216,9 +220,6 @@
 void
 cleanup_module(void)
 {
-#ifdef RPC_DEBUG
-	rpc_unregister_sysctl();
-#endif
 	rpc_proc_exit();
 }
 #endif
Index: oldkernel/linux/net/sunrpc/sunrpc_syms.c
diff -u linux/net/sunrpc/sunrpc_syms.c:1.1.1.1 linux/net/sunrpc/sunrpc_syms.c:1.2
--- linux/net/sunrpc/sunrpc_syms.c:1.1.1.1	Wed May 31 12:33:49 2000
+++ linux/net/sunrpc/sunrpc_syms.c	Fri Jul  7 15:36:50 2000
@@ -26,13 +26,17 @@
 EXPORT_SYMBOL(rpc_allocate);
 EXPORT_SYMBOL(rpc_free);
 EXPORT_SYMBOL(rpc_execute);
+EXPORT_SYMBOL(rpc_new_task);
 EXPORT_SYMBOL(rpc_init_task);
 EXPORT_SYMBOL(rpc_release_task);
 EXPORT_SYMBOL(rpc_sleep_on);
+EXPORT_SYMBOL(rpc_wake_up);
 EXPORT_SYMBOL(rpc_wake_up_next);
 EXPORT_SYMBOL(rpc_wake_up_task);
+EXPORT_SYMBOL(rpc_wake_up_status);
 EXPORT_SYMBOL(rpc_new_child);
 EXPORT_SYMBOL(rpc_run_child);
+EXPORT_SYMBOL(rpciod_wake_up);
 EXPORT_SYMBOL(rpciod_down);
 EXPORT_SYMBOL(rpciod_up);
 
@@ -41,7 +45,8 @@
 EXPORT_SYMBOL(rpc_destroy_client);
 EXPORT_SYMBOL(rpc_shutdown_client);
 EXPORT_SYMBOL(rpc_killall_tasks);
-EXPORT_SYMBOL(rpc_do_call);
+EXPORT_SYMBOL(rpc_call_sync);
+EXPORT_SYMBOL(rpc_call_async);
 EXPORT_SYMBOL(rpc_call_setup);
 EXPORT_SYMBOL(rpc_clnt_sigmask);
 EXPORT_SYMBOL(rpc_clnt_sigunmask);
@@ -60,7 +65,9 @@
 EXPORT_SYMBOL(rpcauth_free_credcache);
 EXPORT_SYMBOL(rpcauth_insert_credcache);
 EXPORT_SYMBOL(rpcauth_lookupcred);
+EXPORT_SYMBOL(rpcauth_bindcred);
 EXPORT_SYMBOL(rpcauth_matchcred);
+EXPORT_SYMBOL(rpcauth_holdcred);
 EXPORT_SYMBOL(rpcauth_releasecred);
 
 /* RPC server stuff */
@@ -93,6 +100,9 @@
 EXPORT_SYMBOL(xdr_encode_netobj);
 EXPORT_SYMBOL(xdr_zero);
 EXPORT_SYMBOL(xdr_one);
+EXPORT_SYMBOL(xdr_two);
+EXPORT_SYMBOL(xdr_shift_iovec);
+EXPORT_SYMBOL(xdr_zero_iovec);
 
 /* RPC errors */
 EXPORT_SYMBOL(rpc_success);
Index: oldkernel/linux/net/sunrpc/svc.c
diff -u linux/net/sunrpc/svc.c:1.1.1.1 linux/net/sunrpc/svc.c:1.2
--- linux/net/sunrpc/svc.c:1.1.1.1	Wed May 31 12:33:49 2000
+++ linux/net/sunrpc/svc.c	Fri Jul  7 15:36:50 2000
@@ -32,6 +32,9 @@
 	struct svc_serv	*serv;
 
 	xdr_init();
+#ifdef RPC_DEBUG
+	rpc_register_sysctl();
+#endif
 
 	if (!(serv = (struct svc_serv *) kmalloc(sizeof(*serv), GFP_KERNEL)))
 		return NULL;
Index: oldkernel/linux/net/sunrpc/svcauth.c
diff -u linux/net/sunrpc/svcauth.c:1.1.1.1 linux/net/sunrpc/svcauth.c:1.2
--- linux/net/sunrpc/svcauth.c:1.1.1.1	Wed May 31 12:33:49 2000
+++ linux/net/sunrpc/svcauth.c	Fri Jul  7 15:36:50 2000
@@ -4,6 +4,9 @@
  * The generic interface for RPC authentication on the server side.
  * 
  * Copyright (C) 1995, 1996 Olaf Kirch <okir@monad.swb.de>
+ *
+ * CHANGES
+ * 19-Apr-2000 Chris Evans      - Security fix
  */
 
 #include <linux/types.h>
@@ -117,7 +120,8 @@
 	struct svc_buf	*resp = &rqstp->rq_resbuf;
 	struct svc_cred	*cred = &rqstp->rq_cred;
 	u32		*bufp = argp->buf;
-	int		len   = argp->len, slen, i;
+	int		len   = argp->len;
+	u32		slen, i;
 
 	if ((len -= 3) < 0) {
 		*statp = rpc_garbage_args;
@@ -127,7 +131,7 @@
 	bufp++;					/* length */
 	bufp++;					/* time stamp */
 	slen = (ntohl(*bufp++) + 3) >> 2;	/* machname length */
-	if (slen > 64 || (len -= slen) < 0)
+	if (slen > 64 || (len -= slen + 3) < 0)
 		goto badcred;
 	bufp += slen;				/* skip machname */
 
Index: oldkernel/linux/net/sunrpc/svcsock.c
diff -u linux/net/sunrpc/svcsock.c:1.1.1.1 linux/net/sunrpc/svcsock.c:1.2
--- linux/net/sunrpc/svcsock.c:1.1.1.1	Wed May 31 12:33:49 2000
+++ linux/net/sunrpc/svcsock.c	Fri Jul  7 15:36:50 2000
@@ -249,8 +249,14 @@
 	msg.msg_namelen = sizeof(rqstp->rq_addr);
 	msg.msg_iov     = iov;
 	msg.msg_iovlen  = nr;
-	msg.msg_control = NULL;
-	msg.msg_controllen = 0;
+	if (sock->type == SOCK_DGRAM) {
+		msg.msg_control = &rqstp->rq_mesg [0];
+		msg.msg_controllen = sizeof (rqstp->rq_mesg);
+	}
+	else {
+		msg.msg_control = NULL;
+		msg.msg_controllen = 0;
+	}
 
 #if LINUX_VERSION_CODE >= 0x020100
 	msg.msg_flags	= MSG_DONTWAIT;
@@ -359,6 +365,9 @@
 	struct sk_buff	*skb;
 	u32		*data;
 	int		err, len;
+	struct cmsghdr	*cm;
+	struct in_pktinfo *info;
+	struct rtable	*rt;
 
 	svsk->sk_data = 0;
 	while ((skb = skb_recv_datagram(svsk->sk_sk, 0, 1, &err)) == NULL) {
@@ -390,6 +399,24 @@
 #else
 	rqstp->rq_addr.sin_addr.s_addr = skb->saddr;
 #endif
+
+	cm = (struct cmsghdr *) &rqstp->rq_mesg [0];
+	info = (struct in_pktinfo *)
+		&rqstp->rq_mesg [sizeof(struct cmsghdr)];
+	rt = (struct rtable *)skb->dst;
+
+	cm->cmsg_level = SOL_IP;
+	cm->cmsg_type = IP_PKTINFO;
+	cm->cmsg_len = CMSG_LEN (sizeof (struct in_pktinfo));
+	info->ipi_addr.s_addr = skb->nh.iph->daddr;
+	if (rt) {
+		info->ipi_ifindex = rt->rt_iif;
+		info->ipi_spec_dst.s_addr = rt->rt_spec_dst;
+	}
+	else {
+		info->ipi_ifindex = 0;
+		info->ipi_spec_dst.s_addr = 0;
+	}
 
 	if (serv->sv_stats)
 		serv->sv_stats->netudpcnt++;
Index: oldkernel/linux/net/sunrpc/sysctl.c
diff -u linux/net/sunrpc/sysctl.c:1.1.1.1 linux/net/sunrpc/sysctl.c:1.2
--- linux/net/sunrpc/sysctl.c:1.1.1.1	Wed May 31 12:33:49 2000
+++ linux/net/sunrpc/sysctl.c	Fri Jul  7 15:36:50 2000
@@ -99,9 +99,8 @@
 			left--, p++;
 		*(unsigned int *) table->data = value;
 		/* Display the RPC tasks on writing to rpc_debug */
-		if (table->ctl_name == CTL_RPCDEBUG) {
+		if (table->ctl_name == CTL_RPCDEBUG)
 			rpc_show_tasks();
-		}
 	} else {
 		if (!access_ok(VERIFY_WRITE, buffer, left))
 			return -EFAULT;
Index: oldkernel/linux/net/sunrpc/xdr.c
diff -u linux/net/sunrpc/xdr.c:1.1.1.1 linux/net/sunrpc/xdr.c:1.2
--- linux/net/sunrpc/xdr.c:1.1.1.1	Wed May 31 12:33:49 2000
+++ linux/net/sunrpc/xdr.c	Fri Jul  7 15:36:50 2000
@@ -9,6 +9,7 @@
 #include <linux/types.h>
 #include <linux/socket.h>
 #include <linux/string.h>
+#include <linux/kernel.h>
 #include <linux/in.h>
 #include <linux/sunrpc/xdr.h>
 #include <linux/sunrpc/msg_prot.h>
@@ -84,11 +85,13 @@
 }
 
 u32 *
-xdr_encode_string(u32 *p, const char *string)
+xdr_encode_string(u32 *p, const char *string, int len)
 {
-	int len = strlen(string);
-	int quadlen = XDR_QUADLEN(len);
+	int quadlen;
 
+	if (len < 0)
+		len = strlen(string);
+	quadlen = XDR_QUADLEN(len);
 	p[quadlen] = 0;
 	*p++ = htonl(len);
 	memcpy(p, string, len);
@@ -116,3 +119,51 @@
 	return p + XDR_QUADLEN(len);
 }
 
+/*
+ * Realign the iovec if the server missed out some reply elements
+ * (such as post-op attributes,...)
+ * Note: This is a simple implementation that assumes that
+ *            len <= iov->iov_len !!!
+ *       The RPC header (assumed to be the 1st element in the iov array)
+ *            is not shifted.
+ */
+void xdr_shift_iovec(struct iovec *iov, int nr, size_t len)
+{
+	struct iovec *pvec;
+
+	for (pvec = iov + nr - 1; nr > 1; nr--, pvec--) {
+		struct iovec *svec = pvec - 1;
+
+		if (len > pvec->iov_len) {
+			printk(KERN_DEBUG "RPC: Urk! Large shift of short iovec.\n");
+			return;
+		}
+		memmove((char *)pvec->iov_base + len, pvec->iov_base,
+			pvec->iov_len - len);
+
+		if (len > svec->iov_len) {
+			printk(KERN_DEBUG "RPC: Urk! Large shift of short iovec.\n");
+			return;
+		}
+		memcpy(pvec->iov_base,
+		       (char *)svec->iov_base + svec->iov_len - len, len);
+	}
+}
+
+/*
+ * Zero the last n bytes in an iovec array of 'nr' elements
+ */
+void xdr_zero_iovec(struct iovec *iov, int nr, size_t n)
+{
+	struct iovec *pvec;
+
+	for (pvec = iov + nr - 1; n && nr > 0; nr--, pvec--) {
+		if (n < pvec->iov_len) {
+			memset((char *)pvec->iov_base + pvec->iov_len - n, 0, n);
+			n = 0;
+		} else {
+			memset(pvec->iov_base, 0, pvec->iov_len);
+			n -= pvec->iov_len;
+		}
+	}
+}
Index: oldkernel/linux/net/sunrpc/xprt.c
diff -u linux/net/sunrpc/xprt.c:1.1.1.1 linux/net/sunrpc/xprt.c:1.2
--- linux/net/sunrpc/xprt.c:1.1.1.1	Wed May 31 12:33:49 2000
+++ linux/net/sunrpc/xprt.c	Fri Jul  7 15:36:50 2000
@@ -31,7 +31,7 @@
  *  primitives that `transparently' work for processes as well as async
  *  tasks that rely on callbacks.
  *
- *  Copyright (C) 1995, 1996, Olaf Kirch <okir@monad.swb.de>
+ *  Copyright (C) 1995-1997, Olaf Kirch <okir@monad.swb.de>
  *
  *  TCP callback races fixes (C) 1998 Red Hat Software <alan@redhat.com>
  *  TCP send fixes (C) 1998 Red Hat Software <alan@redhat.com>
@@ -59,15 +59,19 @@
 
 #include <asm/uaccess.h>
 
-#define SOCK_HAS_USER_DATA
+/* Following value should be > 32k + RPC overhead */
+#define XPRT_MIN_WRITE_SPACE 35000
 
+extern spinlock_t rpc_queue_lock;
+
 /*
  * Local variables
  */
-#ifndef SOCK_HAS_USER_DATA
-static struct rpc_xprt *	sock_list = NULL;
-#endif
 
+/* Spinlock for critical sections in the code. */
+spinlock_t xprt_sock_lock = SPIN_LOCK_UNLOCKED;
+spinlock_t xprt_lock = SPIN_LOCK_UNLOCKED;
+
 #ifdef RPC_DEBUG
 # undef  RPC_DEBUG_DATA
 # define RPCDBG_FACILITY	RPCDBG_XPRT
@@ -82,13 +86,13 @@
  * Local functions
  */
 static void	xprt_request_init(struct rpc_task *, struct rpc_xprt *);
-static void	xprt_transmit_status(struct rpc_task *task);
-static void	xprt_receive_status(struct rpc_task *task);
+static void	do_xprt_transmit(struct rpc_task *);
 static void	xprt_reserve_status(struct rpc_task *task);
-static void	xprt_reconn_timeout(struct rpc_task *task);
+static void	xprt_disconnect(struct rpc_xprt *);
 static void	xprt_reconn_status(struct rpc_task *task);
-static struct socket *xprt_create_socket(int, struct sockaddr_in *,
-					struct rpc_timeout *);
+static struct socket *xprt_create_socket(int, struct rpc_timeout *);
+static int	xprt_bind_socket(struct rpc_xprt *, struct socket *);
+static void	xprt_remove_pending(struct rpc_xprt *);
 
 #ifdef RPC_DEBUG_DATA
 /*
@@ -127,54 +131,42 @@
 static inline struct rpc_xprt *
 xprt_from_sock(struct sock *sk)
 {
-#ifndef SOCK_HAS_USER_DATA
-	struct rpc_xprt		*xprt;
-
-	for (xprt = sock_list; xprt && sk != xprt->inet; xprt = xprt->link)
-		;
-	return xprt;
-#else
 	return (struct rpc_xprt *) sk->user_data;
-#endif
 }
 
 /*
  *	Adjust the iovec to move on 'n' bytes
  */
  
-extern inline void xprt_move_iov(struct msghdr *msg, struct iovec *niv, int amount)
+extern inline void
+xprt_move_iov(struct msghdr *msg, struct iovec *niv, unsigned amount)
 {
 	struct iovec *iv=msg->msg_iov;
+	int i;
 	
 	/*
 	 *	Eat any sent iovecs
 	 */
-
-	while(iv->iov_len < amount)
-	{
-		amount-=iv->iov_len;
+	while (iv->iov_len <= amount) {
+		amount -= iv->iov_len;
 		iv++;
 		msg->msg_iovlen--;
 	}
-	
-	msg->msg_iov=niv;
-	
+
 	/*
 	 *	And chew down the partial one
 	 */
-
 	niv[0].iov_len = iv->iov_len-amount;
 	niv[0].iov_base =((unsigned char *)iv->iov_base)+amount;
 	iv++;
-	
+
 	/*
 	 *	And copy any others
 	 */
-	 
-	for(amount=1;amount<msg->msg_iovlen; amount++)
-	{
-		niv[amount]=*iv++;
-	}
+	for(i = 1; i < msg->msg_iovlen; i++)
+		niv[i]=*iv++;
+
+	msg->msg_iov=niv;
 }
  
 /*
@@ -182,43 +174,45 @@
  */
 
 static inline int
-xprt_sendmsg(struct rpc_xprt *xprt)
+xprt_sendmsg(struct rpc_xprt *xprt, struct rpc_rqst *req)
 {
 	struct socket	*sock = xprt->sock;
 	struct msghdr	msg;
 	mm_segment_t	oldfs;
 	int		result;
+	int		slen = req->rq_slen - req->rq_bytes_sent;
 	struct iovec	niv[MAX_IOVEC];
 
+	if (slen <= 0)
+		return 0;
+
+	if (!sock)
+		return -ENOTCONN;
+
 	xprt_pktdump("packet data:",
-				xprt->snd_buf.io_vec->iov_base,
-				xprt->snd_buf.io_vec->iov_len);
+				req->rq_svec->iov_base,
+				req->rq_svec->iov_len);
 
-	msg.msg_flags   = MSG_DONTWAIT;
-	msg.msg_iov	= xprt->snd_buf.io_vec;
-	msg.msg_iovlen	= xprt->snd_buf.io_nr;
+	msg.msg_flags   = MSG_DONTWAIT|MSG_NOSIGNAL;
+	msg.msg_iov	= req->rq_svec;
+	msg.msg_iovlen	= req->rq_snr;
 	msg.msg_name	= (struct sockaddr *) &xprt->addr;
 	msg.msg_namelen = sizeof(xprt->addr);
 	msg.msg_control = NULL;
 	msg.msg_controllen = 0;
 
 	/* Dont repeat bytes */
-	
-	if(xprt->snd_sent)
-		xprt_move_iov(&msg, niv, xprt->snd_sent);
-		
+	if (req->rq_bytes_sent)
+		xprt_move_iov(&msg, niv, req->rq_bytes_sent);
+
 	oldfs = get_fs(); set_fs(get_ds());
-	result = sock_sendmsg(sock, &msg, xprt->snd_buf.io_len);
+	result = sock_sendmsg(sock, &msg, slen);
 	set_fs(oldfs);
 
-	dprintk("RPC:      xprt_sendmsg(%d) = %d\n",
-				xprt->snd_buf.io_len, result);
+	dprintk("RPC:      xprt_sendmsg(%d) = %d\n", slen, result);
 
-	if (result >= 0) {
-		xprt->snd_buf.io_len -= result;
-		xprt->snd_sent += result;
+	if (result >= 0)
 		return result;
-	}
 
 	switch (result) {
 	case -ECONNREFUSED:
@@ -227,9 +221,14 @@
 		 */
 		break;
 	case -EAGAIN:
-		return 0;
-	case -ENOTCONN: case -EPIPE:
+		if (sock->flags & SO_NOSPACE)
+			result = -ENOMEM;
+		break;
+	case -ENOTCONN:
+	case -EPIPE:
 		/* connection broken */
+		if (xprt->stream)
+			result = -ENOTCONN;
 		break;
 	default:
 		printk(KERN_NOTICE "RPC: sendmsg returned error %d\n", -result);
@@ -241,41 +240,33 @@
 /*
  * Read data from socket
  */
-static inline int
-xprt_recvmsg(struct rpc_xprt *xprt, struct iovec *iov, int nr, int len)
+static int
+xprt_recvmsg(struct rpc_xprt *xprt, struct iovec *iov, int nr, unsigned len, unsigned shift)
 {
 	struct socket	*sock = xprt->sock;
-	struct sockaddr_in sin;
 	struct msghdr	msg;
 	mm_segment_t	oldfs;
+	struct iovec	niv[MAX_IOVEC];
 	int		result;
 
-#if LINUX_VERSION_CODE >= 0x020100
-	msg.msg_flags   = MSG_DONTWAIT;
-	msg.msg_iov	= iov;
-	msg.msg_iovlen	= nr;
-	msg.msg_name	= &sin;
-	msg.msg_namelen = sizeof(sin);
-	msg.msg_control = NULL;
-	msg.msg_controllen = 0;
+	if (!sock)
+		return -ENOTCONN;
 
-	oldfs = get_fs(); set_fs(get_ds());
-	result = sock_recvmsg(sock, &msg, len, MSG_DONTWAIT);
-	set_fs(oldfs);
-#else
-	int		alen = sizeof(sin);
-	msg.msg_flags   = 0;
+	msg.msg_flags   = MSG_DONTWAIT|MSG_NOSIGNAL;
 	msg.msg_iov	= iov;
 	msg.msg_iovlen	= nr;
-	msg.msg_name	= &sin;
-	msg.msg_namelen = sizeof(sin);
+	msg.msg_name	= NULL;
+	msg.msg_namelen = 0;
 	msg.msg_control = NULL;
 	msg.msg_controllen = 0;
 
+	/* Adjust the iovec if we've already filled it */
+	if (shift)
+		xprt_move_iov(&msg, niv, shift);
+
 	oldfs = get_fs(); set_fs(get_ds());
-	result = sock->ops->recvmsg(sock, &msg, len, 1, 0, &alen);
+	result = sock_recvmsg(sock, &msg, len, MSG_DONTWAIT);
 	set_fs(oldfs);
-#endif
 
 	dprintk("RPC:      xprt_recvmsg(iov %p, len %d) = %d\n",
 						iov, len, result);
@@ -327,21 +318,30 @@
 int
 xprt_adjust_timeout(struct rpc_timeout *to)
 {
-	if (to->to_exponential)
-		to->to_current <<= 1;
-	else
-		to->to_current += to->to_increment;
-	if (to->to_maxval && to->to_current >= to->to_maxval) {
-		to->to_current = to->to_maxval;
-		to->to_retries = 0;
+	if (to->to_retries > 0) {
+		if (to->to_exponential)
+			to->to_current <<= 1;
+		else
+			to->to_current += to->to_increment;
+		if (to->to_maxval && to->to_current >= to->to_maxval)
+			to->to_current = to->to_maxval;
+	} else {
+		if (to->to_exponential)
+			to->to_initval <<= 1;
+		else
+			to->to_initval += to->to_increment;
+		if (to->to_maxval && to->to_initval >= to->to_maxval)
+			to->to_initval = to->to_maxval;
+		to->to_current = to->to_initval;
 	}
+
 	if (!to->to_current) {
 		printk(KERN_WARNING "xprt_adjust_timeout: to_current = 0!\n");
 		to->to_current = 5 * HZ;
 	}
 	pprintk("RPC: %lu %s\n", jiffies,
 			to->to_retries? "retrans" : "timeout");
-	return (to->to_retries)--;
+	return to->to_retries-- > 0;
 }
 
 /*
@@ -350,24 +350,28 @@
 static void
 xprt_close(struct rpc_xprt *xprt)
 {
+	struct socket	*sock = xprt->sock;
 	struct sock	*sk = xprt->inet;
 
-#ifdef SOCK_HAS_USER_DATA
+	if (!sk)
+		return;
+
+	xprt->inet = NULL;
+	xprt->sock = NULL;
+
 	sk->user_data    = NULL;
-#endif
 	sk->data_ready   = xprt->old_data_ready;
 	sk->state_change = xprt->old_state_change;
 	sk->write_space  = xprt->old_write_space;
 
-	if (xprt->file)
-		fput(xprt->file);
-	else
-		sock_release(xprt->sock);
+	xprt_disconnect(xprt);
+
+	sock_release(sock);
 	/*
 	 *	TCP doesnt require the rpciod now - other things may
 	 *	but rpciod handles that not us.
 	 */
-	if(xprt->stream && !xprt->connecting)
+	if(xprt->stream)
 		rpciod_down();
 }
 
@@ -378,9 +382,12 @@
 xprt_disconnect(struct rpc_xprt *xprt)
 {
 	dprintk("RPC:      disconnected transport %p\n", xprt);
-	rpc_wake_up_status(&xprt->pending, -ENOTCONN);
-	rpc_wake_up_status(&xprt->sending, -ENOTCONN);
 	xprt->connected = 0;
+	xprt->tcp_offset = 0;
+	xprt->tcp_copied = 0;
+	xprt->tcp_more = 0;
+	xprt_remove_pending(xprt);
+	rpc_wake_up_status(&xprt->pending, -ENOTCONN);
 }
 
 /*
@@ -390,94 +397,88 @@
 xprt_reconnect(struct rpc_task *task)
 {
 	struct rpc_xprt	*xprt = task->tk_xprt;
-	struct socket	*sock;
-	struct sock	*inet;
+	struct socket	*sock = xprt->sock;
+	struct sock	*inet = xprt->inet;
+	unsigned long	oldflags;
 	int		status;
 
 	dprintk("RPC: %4d xprt_reconnect %p connected %d\n",
 				task->tk_pid, xprt, xprt->connected);
-	task->tk_status = 0;
+	if (xprt->shutdown)
+		return;
 
+	if (!xprt->stream)
+		return;
+
+	if (!xprt->addr.sin_port) {
+		task->tk_status = -EIO;
+		return;
+	}
+
+	spin_lock(&xprt_lock);
 	if (xprt->connecting) {
-		task->tk_timeout = xprt->timeout.to_maxval;
+		task->tk_timeout = 0;
 		rpc_sleep_on(&xprt->reconn, task, NULL, NULL);
+		spin_unlock(&xprt_lock);
 		return;
 	}
 	xprt->connecting = 1;
+	spin_unlock(&xprt_lock);
 
-	/* Create an unconnected socket */
-	if (!(sock = xprt_create_socket(xprt->prot, NULL, &xprt->timeout)))
-		goto defer;
-
-#if LINUX_VERSION_CODE >= 0x020100
-	inet = sock->sk;
-#else
-	inet = (struct sock *) sock->data;
-#endif
-	inet->data_ready   = xprt->inet->data_ready;
-	inet->state_change = xprt->inet->state_change;
-	inet->write_space  = xprt->inet->write_space;
-#ifdef SOCK_HAS_USER_DATA
-	inet->user_data    = xprt;
-#endif
+	status = -ENOTCONN;
+	if (!inet) {
+		/* Create an unconnected socket */
+		if (!(sock = xprt_create_socket(xprt->prot, &xprt->timeout)))
+			goto defer;
+		xprt_bind_socket(xprt, sock);
+		inet = sock->sk;
+	}
 
-	dprintk("RPC: %4d closing old socket\n", task->tk_pid);
 	xprt_disconnect(xprt);
-	xprt_close(xprt);
-
-	/* Reset to new socket and default congestion */
-	xprt->sock = sock;
-	xprt->inet = inet;
-	xprt->cwnd = RPC_INITCWND;
 
 	/* Now connect it asynchronously. */
 	dprintk("RPC: %4d connecting new socket\n", task->tk_pid);
 	status = sock->ops->connect(sock, (struct sockaddr *) &xprt->addr,
 				sizeof(xprt->addr), O_NONBLOCK);
+
 	if (status < 0) {
-		if (status != -EINPROGRESS && status != -EALREADY) {
+		switch (status) {
+		case -EALREADY:
+		case -EINPROGRESS:
+			status = 0;
+			break;
+		case -EISCONN:
+		case -EPIPE:
+			status = 0;
+			xprt_close(xprt);
+			goto defer;
+		default:
 			printk("RPC: TCP connect error %d!\n", -status);
+			xprt_close(xprt);
 			goto defer;
 		}
 
 		dprintk("RPC: %4d connect status %d connected %d\n",
 				task->tk_pid, status, xprt->connected);
-		task->tk_timeout = 60 * HZ;
 
-		start_bh_atomic();
+		spin_lock_irqsave(&xprt_sock_lock, oldflags);
 		if (!xprt->connected) {
-			rpc_sleep_on(&xprt->reconn, task,
-				xprt_reconn_status, xprt_reconn_timeout);
-			end_bh_atomic();
+			task->tk_timeout = xprt->timeout.to_maxval;
+			rpc_sleep_on(&xprt->reconn, task, xprt_reconn_status, NULL);
+			spin_unlock_irqrestore(&xprt_sock_lock, oldflags);
 			return;
 		}
-		end_bh_atomic();
+		spin_unlock_irqrestore(&xprt_sock_lock, oldflags);
 	}
-
-	xprt->connecting = 0;
-	rpc_wake_up(&xprt->reconn);
-	return;
-
 defer:
-	task->tk_timeout = 30 * HZ;
-	rpc_sleep_on(&xprt->reconn, task, NULL, NULL);
+	spin_lock(&xprt_lock);
 	xprt->connecting = 0;
-}
-
-/*
- * Reconnect status
- */
-static void
-xprt_reconn_status(struct rpc_task *task)
-{
-	struct rpc_xprt	*xprt = task->tk_xprt;
-
-	dprintk("RPC: %4d xprt_reconn_status %d\n",
-				task->tk_pid, task->tk_status);
-	if (!xprt->connected && task->tk_status != -ETIMEDOUT) {
-		task->tk_timeout = 30 * HZ;
-		rpc_sleep_on(&xprt->reconn, task, NULL, xprt_reconn_timeout);
+	if (status < 0) {
+		rpc_delay(task, 5*HZ);
+		task->tk_status = -ENOTCONN;
 	}
+	rpc_wake_up(&xprt->reconn);
+	spin_unlock(&xprt_lock);
 }
 
 /*
@@ -485,40 +486,51 @@
  * process of reconnecting, and leave the rest to the upper layers.
  */
 static void
-xprt_reconn_timeout(struct rpc_task *task)
+xprt_reconn_status(struct rpc_task *task)
 {
+	struct rpc_xprt	*xprt = task->tk_xprt;
+
 	dprintk("RPC: %4d xprt_reconn_timeout %d\n",
 				task->tk_pid, task->tk_status);
-	task->tk_status = -ENOTCONN;
-	task->tk_xprt->connecting = 0;
-	task->tk_timeout = 0;
-	rpc_wake_up_task(task);
+
+	spin_lock(&xprt_lock);
+	xprt->connecting = 0;
+	rpc_wake_up(&xprt->reconn);
+	spin_unlock(&xprt_lock);
 }
 
 /*
- * Look up the RPC request corresponding to a reply.
+ * Look up the RPC request corresponding to a reply, and then lock it.
  */
 static inline struct rpc_rqst *
 xprt_lookup_rqst(struct rpc_xprt *xprt, u32 xid)
 {
 	struct rpc_task	*head, *task;
 	struct rpc_rqst	*req;
+	unsigned long	oldflags;
 	int		safe = 0;
 
+	spin_lock_irqsave(&rpc_queue_lock, oldflags);
 	if ((head = xprt->pending.task) != NULL) {
 		task = head;
 		do {
 			if ((req = task->tk_rqstp) && req->rq_xid == xid)
-				return req;
+				goto out;
 			task = task->tk_next;
 			if (++safe > 100) {
 				printk("xprt_lookup_rqst: loop in Q!\n");
-				return NULL;
+				goto out_bad;
 			}
 		} while (task != head);
 	}
 	dprintk("RPC:      unknown XID %08x in reply.\n", xid);
-	return NULL;
+ out_bad:
+	req = NULL;
+ out:
+	if (req && !rpc_lock_task(req->rq_task))
+		req = NULL;
+	spin_unlock_irqrestore(&rpc_queue_lock, oldflags);
+	return req;
 }
 
 /*
@@ -530,9 +542,6 @@
 {
 	struct rpc_task	*task = req->rq_task;
 
-	req->rq_rlen   = copied;
-	req->rq_gotit  = 1;
-
 	/* Adjust congestion window */
 	xprt_adjust_cwnd(xprt, copied);
 
@@ -555,10 +564,10 @@
 	}
 #endif
 
-	/* ... and wake up the process. */
 	dprintk("RPC: %4d has input (%d bytes)\n", task->tk_pid, copied);
 	task->tk_status = copied;
 
+	/* ... and wake up the process. */
 	rpc_wake_up_task(task);
 	return;
 }
@@ -578,255 +587,323 @@
 	int		err, repsize, copied;
 
 	dprintk("RPC:      udp_data_ready...\n");
-	if (!(xprt = xprt_from_sock(sk)))
+	if (!(xprt = xprt_from_sock(sk))) {
+		printk("RPC:      udp_data_ready request not found!\n");
 		return;
+	}
+
 	dprintk("RPC:      udp_data_ready client %p\n", xprt);
 
 	if ((skb = skb_recv_datagram(sk, 0, 1, &err)) == NULL)
 		return;
-	repsize = skb->len - 8;	/* don't account for UDP header */
 
+	if (xprt->shutdown)
+		goto dropit;
+
+	repsize = skb->len - sizeof(struct udphdr);
 	if (repsize < 4) {
 		printk("RPC: impossible RPC reply size %d!\n", repsize);
 		goto dropit;
 	}
 
-	/* Look up the request corresponding to the given XID */
-	if (!(rovr = xprt_lookup_rqst(xprt, *(u32 *) (skb->h.raw + 8))))
+	/* Look up and lock the request corresponding to the given XID */
+	rovr = xprt_lookup_rqst(xprt, *(u32 *) (skb->h.raw + sizeof(struct udphdr)));
+	if (!rovr)
 		goto dropit;
 	task = rovr->rq_task;
 
 	dprintk("RPC: %4d received reply\n", task->tk_pid);
-	xprt_pktdump("packet data:", (u32 *) (skb->h.raw+8), repsize);
+	xprt_pktdump("packet data:",
+		     (u32 *) (skb->h.raw+sizeof(struct udphdr)), repsize);
 
 	if ((copied = rovr->rq_rlen) > repsize)
 		copied = repsize;
 
 	/* Okay, we have it. Copy datagram... */
+	rovr->rq_damaged  = 1;
 	memcpy(iov, rovr->rq_rvec, rovr->rq_rnr * sizeof(iov[0]));
 	/* This needs to stay tied with the usermode skb_copy_dagram... */
 	memcpy_tokerneliovec(iov, skb->data+8, copied);
 
 	xprt_complete_rqst(xprt, rovr, copied);
+	rpc_unlock_task(task);
 
-dropit:
+ dropit:
 	skb_free_datagram(sk, skb);
-	return;
 }
 
 /*
- * TCP record receive routine
- * This is not the most efficient code since we call recvfrom twice--
- * first receiving the record marker and XID, then the data.
- * 
- * The optimal solution would be a RPC support in the TCP layer, which
- * would gather all data up to the next record marker and then pass us
- * the list of all TCP segments ready to be copied.
+ * TCP read fragment marker
  */
 static inline int
-tcp_input_record(struct rpc_xprt *xprt)
+tcp_read_fraghdr(struct rpc_xprt *xprt)
 {
-	struct rpc_rqst	*req;
-	struct iovec	*iov;
 	struct iovec	riov;
-	u32		offset;
-	int		result, maxcpy, reclen, avail, want;
+	int		want, result;
 
-	dprintk("RPC:      tcp_input_record\n");
-	offset = xprt->tcp_offset;
-	result = -EAGAIN;
-	if (offset < 4 || (!xprt->tcp_more && offset < 8)) {
-		want = (xprt->tcp_more? 4 : 8) - offset;
-		dprintk("RPC:      reading header (%d bytes)\n", want);
-		riov.iov_base = xprt->tcp_recm.data + offset;
+	if (xprt->tcp_offset >= xprt->tcp_reclen + sizeof(xprt->tcp_recm)) {
+		xprt->tcp_offset = 0;
+		xprt->tcp_reclen = 0;
+	}
+	if (xprt->tcp_offset >= sizeof(xprt->tcp_recm))
+		goto done;
+
+	want = sizeof(xprt->tcp_recm) - xprt->tcp_offset;
+	dprintk("RPC:      reading header (%d bytes)\n", want);
+	do {
+		riov.iov_base = ((u8*) &xprt->tcp_recm) + xprt->tcp_offset;
 		riov.iov_len  = want;
-		result = xprt_recvmsg(xprt, &riov, 1, want);
-		if (!result)
-		{
-			dprintk("RPC: empty TCP record.\n");
-			return -ENOTCONN;
-		}
+		result = xprt_recvmsg(xprt, &riov, 1, want, 0);
 		if (result < 0)
-			goto done;
-		offset += result;
-		if (result < want) {
-			result = -EAGAIN;
-			goto done;
-		}
+			return result;
+		xprt->tcp_offset += result;
+		want -= result;
+	} while (want);
 
-		/* Get the record length and mask out the more_fragments bit */
-		reclen = ntohl(xprt->tcp_reclen);
-		dprintk("RPC:      reclen %08x\n", reclen);
-		xprt->tcp_more = (reclen & 0x80000000)? 0 : 1;
-		reclen &= 0x7fffffff;
-		xprt->tcp_total += reclen;
-		xprt->tcp_reclen = reclen;
-
-		dprintk("RPC:      got xid %08x reclen %d morefrags %d\n",
-			xprt->tcp_xid, xprt->tcp_reclen, xprt->tcp_more);
-		if (!xprt->tcp_copied
-		 && (req = xprt_lookup_rqst(xprt, xprt->tcp_xid))) {
-			iov = xprt->tcp_iovec;
-			memcpy(iov, req->rq_rvec, req->rq_rnr * sizeof(iov[0]));
-#if 0
-*(u32 *)iov->iov_base = req->rq_xid;
-#endif
-			iov->iov_base += 4;
-			iov->iov_len  -= 4;
-			xprt->tcp_copied = 4;
-			xprt->tcp_rqstp  = req;
-		}
-	} else {
-		reclen = xprt->tcp_reclen;
-	}
+	/* Is this another fragment in the last message */
+	if (!xprt->tcp_more)
+		xprt->tcp_copied = 0; /* No, so we're reading a new message */
+
+	/* Get the record length and mask out the last fragment bit */
+	xprt->tcp_reclen = ntohl(xprt->tcp_recm);
+	xprt->tcp_more = (xprt->tcp_reclen & 0x80000000) ? 0 : 1;
+	xprt->tcp_reclen &= 0x7fffffff;
+
+	dprintk("RPC:      New record reclen %d morefrags %d\n",
+				   xprt->tcp_reclen, xprt->tcp_more);
+ done:
+	return xprt->tcp_reclen + sizeof(xprt->tcp_recm) - xprt->tcp_offset;
+}
+
+/*
+ * TCP read xid
+ */
+static inline int
+tcp_read_xid(struct rpc_xprt *xprt, int avail)
+{
+	struct iovec	riov;
+	int		want, result;
+
+	if (xprt->tcp_copied >= sizeof(xprt->tcp_xid) || !avail)
+		goto done;
+	want = MIN(sizeof(xprt->tcp_xid) - xprt->tcp_copied, avail);
+	do {
+		dprintk("RPC:      reading xid (%d bytes)\n", want);
+		riov.iov_base = ((u8*) &xprt->tcp_xid) + xprt->tcp_copied;
+		riov.iov_len  = want;
+		result = xprt_recvmsg(xprt, &riov, 1, want, 0);
+		if (result < 0)
+			return result;
+		xprt->tcp_copied += result;
+		xprt->tcp_offset += result;
+		want  -= result;
+		avail -= result;
+	} while (want);
+ done:
+	return avail;
+}
 
-	avail = reclen - (offset - 4);
-	if ((req = xprt->tcp_rqstp) && req->rq_xid == xprt->tcp_xid
-	 && req->rq_task->tk_rpcwait == &xprt->pending) {
-		want = MIN(req->rq_rlen - xprt->tcp_copied, avail);
+/*
+ * TCP read and complete request
+ */
+static inline int
+tcp_read_request(struct rpc_xprt *xprt, struct rpc_rqst *req, int avail)
+{
+	int	want, result;
 
+	if (req->rq_rlen <= xprt->tcp_copied || !avail)
+		goto done;
+	want = MIN(req->rq_rlen - xprt->tcp_copied, avail);
+	do {
 		dprintk("RPC: %4d TCP receiving %d bytes\n",
-					req->rq_task->tk_pid, want);
-		result = xprt_recvmsg(xprt, xprt->tcp_iovec, req->rq_rnr, want);
-		if (!result && want)
-			result = -EAGAIN;
+			req->rq_task->tk_pid, want);
+
+		result = xprt_recvmsg(xprt, req->rq_rvec, req->rq_rnr, want, xprt->tcp_copied);
 		if (result < 0)
-			goto done;
+			return result;
 		xprt->tcp_copied += result;
-		offset += result;
+		xprt->tcp_offset += result;
 		avail  -= result;
-		if (result < want) {
-			result = -EAGAIN;
-			goto done;
-		}
+		want   -= result;
+	} while (want);
 
-		maxcpy = MIN(req->rq_rlen, xprt->tcp_total);
-		if (xprt->tcp_copied == maxcpy && !xprt->tcp_more) {
-			dprintk("RPC: %4d received reply complete\n",
-					req->rq_task->tk_pid);
-			xprt_complete_rqst(xprt, req, xprt->tcp_total);
-			xprt->tcp_copied = 0;
-			xprt->tcp_rqstp  = NULL;
-		}
-		/* Request must be re-encoded before retransmit */
-		req->rq_damaged = 1;
-	}
+ done:
+	if (req->rq_rlen > xprt->tcp_copied && xprt->tcp_more)
+		return avail;
+	dprintk("RPC: %4d received reply complete\n", req->rq_task->tk_pid);
+	xprt_complete_rqst(xprt, req, xprt->tcp_copied);
 
-	/* Skip over any trailing bytes on short reads */
-	while (avail) {
-		static u8	dummy[64];
+	return avail;
+}
+
+/*
+ * TCP discard extra bytes from a short read
+ */
+static inline int
+tcp_read_discard(struct rpc_xprt *xprt, int avail)
+{
+	struct iovec	riov;
+	static u8	dummy[64];
+	int		want, result = 0;
 
+	while (avail) {
 		want = MIN(avail, sizeof(dummy));
 		riov.iov_base = dummy;
 		riov.iov_len  = want;
 		dprintk("RPC:      TCP skipping %d bytes\n", want);
-		result = xprt_recvmsg(xprt, &riov, 1, want);
-		if (!result && want)
-			result=-EAGAIN;
+		result = xprt_recvmsg(xprt, &riov, 1, want, 0);
 		if (result < 0)
-			goto done;
-		offset += result;
+			return result;
+		xprt->tcp_offset += result;
 		avail  -= result;
-		if (result < want) {
-			result = -EAGAIN;
-			goto done;
-		}
 	}
-	if (!xprt->tcp_more)
-		xprt->tcp_total = 0;
-	offset = 0;
-
-done:
-	dprintk("RPC:      tcp_input_record done (off %d total %d copied %d)\n",
-			offset, xprt->tcp_total, xprt->tcp_copied);
-	xprt->tcp_offset = offset;
-	return result;
+	return avail;
 }
 
-static __inline__ void tcp_output_record(struct rpc_xprt *xprt)
+/*
+ * TCP record receive routine
+ * This is not the most efficient code since we call recvfrom thrice--
+ * first receiving the record marker, then the XID, then the data.
+ * 
+ * The optimal solution would be a RPC support in the TCP layer, which
+ * would gather all data up to the next record marker and then pass us
+ * the list of all TCP segments ready to be copied.
+ */
+static int
+tcp_input_record(struct rpc_xprt *xprt)
 {
-	if(xprt->snd_sent && xprt->snd_task)
-		dprintk("RPC: write space\n");
-	if(xprt->write_space == 0)
-	{
-		xprt->write_space = 1;
-		if (xprt->snd_task && !RPC_IS_RUNNING(xprt->snd_task))
-		{
-			if(xprt->snd_sent)
-				dprintk("RPC: Write wakeup snd_sent =%d\n",
-					xprt->snd_sent);
-			rpc_wake_up_task(xprt->snd_task);			
+	struct rpc_rqst	*req = NULL;
+	struct rpc_task	*task = NULL;
+	int		avail, result;
+
+	dprintk("RPC:      tcp_input_record\n");
+
+	if (xprt->shutdown)
+		return -EIO;
+	if (!xprt->connected)
+		return -ENOTCONN;
+
+	/* Read in a new fragment marker if necessary */
+	/* Can we ever really expect to get completely empty fragments? */
+	if ((result = tcp_read_fraghdr(xprt)) <= 0)
+		return result;
+	avail = result;
+
+	/* Read in the xid if necessary */
+	if ((result = tcp_read_xid(xprt, avail)) <= 0)
+		return result;
+	avail = result;
+
+	/* Find and lock the request corresponding to this xid */
+	req = xprt_lookup_rqst(xprt, xprt->tcp_xid);
+	if (req) {
+		task = req->rq_task;
+		if (xprt->tcp_copied == sizeof(xprt->tcp_xid) || req->rq_damaged) {
+			req->rq_damaged = 1;
+			/* Read in the request data */
+			result = tcp_read_request(xprt,  req, avail);
 		}
+		rpc_unlock_task(task);
+		if (result < 0)
+			return result;
+		avail = result;
 	}
+
+	/* Skip over any trailing bytes on short reads */
+	if ((result = tcp_read_discard(xprt, avail)) < 0)
+		return result;
+
+	dprintk("RPC:      tcp_input_record done (off %d reclen %d copied %d)\n",
+			xprt->tcp_offset, xprt->tcp_reclen, xprt->tcp_copied);
+	result = xprt->tcp_reclen;
+	return result;
 }
 
 /*
  *	TCP task queue stuff
  */
- 
-static struct rpc_xprt *rpc_rx_xprt_pending = NULL;	/* Chain by rx_pending of rpc_xprt's */
-static struct rpc_xprt *rpc_tx_xprt_pending = NULL;	/* Chain by tx_pending of rpc_xprt's */
+LIST_HEAD(rpc_xprt_pending);	/* List of xprts having pending tcp requests */
+
+static inline
+void tcp_rpciod_queue(void)
+{
+	rpciod_wake_up();
+}
+
+static inline
+void xprt_append_pending(struct rpc_xprt *xprt)
+{
+	unsigned long	oldflags;
+
+	if (!list_empty(&xprt->rx_pending))
+		return;
+	spin_lock_irqsave(&rpc_queue_lock, oldflags);
+	if (list_empty(&xprt->rx_pending)) {
+		list_add(&xprt->rx_pending, rpc_xprt_pending.prev);
+		dprintk("RPC:     xprt queue %p\n", xprt);
+		tcp_rpciod_queue();
+	}
+	spin_unlock_irqrestore(&rpc_queue_lock, oldflags);
+}
+
+static
+void xprt_remove_pending(struct rpc_xprt *xprt)
+{
+	unsigned long	oldflags;
+
+	spin_lock_irqsave(&rpc_queue_lock, oldflags);
+	if (!list_empty(&xprt->rx_pending)) {
+		list_del(&xprt->rx_pending);
+		INIT_LIST_HEAD(&xprt->rx_pending);
+	}
+	spin_unlock_irqrestore(&rpc_queue_lock, oldflags);
+}
+
+static inline
+struct rpc_xprt *xprt_remove_pending_next(void)
+{
+	struct rpc_xprt	*xprt = NULL;
+	unsigned long	oldflags;
+
+	spin_lock_irqsave(&rpc_queue_lock, oldflags);
+	if (!list_empty(&rpc_xprt_pending)) {
+		xprt = list_entry(rpc_xprt_pending.next, struct rpc_xprt, rx_pending);
+		list_del(&xprt->rx_pending);
+		INIT_LIST_HEAD(&xprt->rx_pending);
+	}
+	spin_unlock_irqrestore(&rpc_queue_lock, oldflags);
+	return xprt;
+}
 
 /*
  *	This is protected from tcp_data_ready and the stack as its run
  *	inside of the RPC I/O daemon
  */
-
-void rpciod_tcp_dispatcher(void)
+void
+__rpciod_tcp_dispatcher(void)
 {
 	struct rpc_xprt *xprt;
-	int result;
+	int safe_retry = 0, result;
 
 	dprintk("rpciod_tcp_dispatcher: Queue Running\n");
-	
+
 	/*
 	 *	Empty each pending socket
 	 */
-	 
-	while((xprt=rpc_rx_xprt_pending)!=NULL)
-	{
-		int safe_retry=0;
-		
-		rpc_rx_xprt_pending=xprt->rx_pending;
-		xprt->rx_pending_flag=0;
-		
+	while ((xprt = xprt_remove_pending_next()) != NULL) {
 		dprintk("rpciod_tcp_dispatcher: Processing %p\n", xprt);
-		
-		do 
-		{
-			if (safe_retry++ > 50)
-				break;
+
+		do {
 			result = tcp_input_record(xprt);
-		}
-		while (result >= 0);
-	
-		switch (result) {
-			case -EAGAIN:
-				continue;
-			case -ENOTCONN:
-			case -EPIPE:
-				xprt_disconnect(xprt);
-				continue;
-			default:
-				printk(KERN_WARNING "RPC: unexpected error %d from tcp_input_record\n",
-					result);
-		}
-	}
+		} while (result >= 0);
 
-	while((xprt=rpc_tx_xprt_pending)!=NULL)
-	{
-		rpc_tx_xprt_pending = xprt->tx_pending;
-		xprt->tx_pending_flag = 0;
-		tcp_output_record(xprt);
+		if (safe_retry++ > 200) {
+			schedule();
+			safe_retry = 0;
+		}
 	}
 }
 
-
-extern inline void tcp_rpciod_queue(void)
-{
-	rpciod_wake_up();
-}
-
 /*
  *	data_ready callback for TCP. We can't just jump into the
  *	tcp recvmsg functions inside of the network receive bh or
@@ -844,32 +921,16 @@
 		printk("Not a socket with xprt %p\n", sk);
 		return;
 	}
+
+	if (xprt->shutdown)
+		return;
+
+	xprt_append_pending(xprt);
+
 	dprintk("RPC:      tcp_data_ready client %p\n", xprt);
 	dprintk("RPC:      state %x conn %d dead %d zapped %d\n",
 				sk->state, xprt->connected,
 				sk->dead, sk->zapped);
-	/*
-	 *	If we are not waiting for the RPC bh run then
-	 *	we are now
-	 */
-	if (!xprt->rx_pending_flag)
-	{
-		int start_queue=0;
-
-		dprintk("RPC:     xprt queue %p\n", rpc_rx_xprt_pending);
-		if(rpc_rx_xprt_pending==NULL)
-			start_queue=1;
-		xprt->rx_pending_flag=1;
-		xprt->rx_pending=rpc_rx_xprt_pending;
-		rpc_rx_xprt_pending=xprt;
-		if (start_queue)
-		  {
-		    tcp_rpciod_queue();
-		    start_queue=0;
-		  }
-	}
-	else
-		dprintk("RPC:     xprt queued already %p\n", xprt);
 }
 
 
@@ -877,6 +938,7 @@
 tcp_state_change(struct sock *sk)
 {
 	struct rpc_xprt	*xprt;
+	unsigned long oldflags;
 
 	if (!(xprt = xprt_from_sock(sk)))
 		return;
@@ -885,35 +947,79 @@
 				sk->state, xprt->connected,
 				sk->dead, sk->zapped);
 
-	if (sk->state == TCP_ESTABLISHED && !xprt->connected) {
+	spin_lock_irqsave(&xprt_sock_lock, oldflags);
+	switch (sk->state) {
+	case TCP_ESTABLISHED:
 		xprt->connected = 1;
-		xprt->connecting = 0;
+		if (xprt->snd_task && xprt->snd_task->tk_rpcwait == &xprt->sending)
+			rpc_wake_up_task(xprt->snd_task);
 		rpc_wake_up(&xprt->reconn);
-	} else if (sk->zapped) {
+		break;
+	default:
+		xprt->connected = 0;
 		rpc_wake_up_status(&xprt->pending, -ENOTCONN);
-		rpc_wake_up_status(&xprt->sending, -ENOTCONN);
-		rpc_wake_up_status(&xprt->reconn,  -ENOTCONN);
+		break;
 	}
+	spin_unlock_irqrestore(&xprt_sock_lock, oldflags);
 }
 
+/*
+ * The following 2 routines allow a task to sleep while socket memory is
+ * low.
+ */
 static void
 tcp_write_space(struct sock *sk)
 {
 	struct rpc_xprt	*xprt;
+	unsigned long	oldflags;
+
+	if (!(xprt = xprt_from_sock(sk)))
+		return;
+	if (xprt->shutdown)
+		return;
+
+	/* Wait until we have enough socket memory */
+	if (sock_wspace(sk) < min(sk->sndbuf,XPRT_MIN_WRITE_SPACE))
+		return;
+
+	spin_lock_irqsave(&xprt_sock_lock, oldflags);
+	if (xprt->write_space)
+		goto out_unlock;
+
+	xprt->write_space = 1;
+
+	if (xprt->snd_task && xprt->snd_task->tk_rpcwait == &xprt->sending)
+		rpc_wake_up_task(xprt->snd_task);
+ out_unlock:
+	spin_unlock_irqrestore(&xprt_sock_lock, oldflags);
+}
 
+static void
+udp_write_space(struct sock *sk)
+{
+	struct rpc_xprt *xprt;
+	unsigned long	oldflags;
+
 	if (!(xprt = xprt_from_sock(sk)))
 		return;
-	if (!xprt->tx_pending_flag) {
-		int start_queue = 0;
+	if (xprt->shutdown)
+		return;
 
-		if (rpc_tx_xprt_pending == NULL)
-			start_queue = 1;
-		xprt->tx_pending_flag = 1;
-		xprt->tx_pending = rpc_tx_xprt_pending;
-		rpc_tx_xprt_pending = xprt;
-		if (start_queue)
-			tcp_rpciod_queue();
-	}
+
+	/* Wait until we have enough socket memory */
+	if (sock_wspace(sk) < min(sk->sndbuf,XPRT_MIN_WRITE_SPACE))
+		return;
+
+	spin_lock_irqsave(&xprt_sock_lock, oldflags);
+	if (xprt->write_space)
+		goto out_unlock;
+
+	xprt->write_space = 1;
+
+	if (xprt->snd_task && xprt->snd_task->tk_rpcwait == &xprt->sending)
+		rpc_wake_up_task(xprt->snd_task);
+ out_unlock:
+	spin_unlock_irqrestore(&xprt_sock_lock, oldflags);
 }
 
 /*
@@ -924,9 +1030,8 @@
 {
 	struct rpc_rqst	*req = task->tk_rqstp;
 
-	if (req) {
+	if (req)
 		xprt_adjust_cwnd(task->tk_xprt, -ETIMEDOUT);
-	}
 
 	dprintk("RPC: %4d xprt_timer (%s request)\n",
 		task->tk_pid, req ? "pending" : "backlogged");
@@ -936,32 +1041,49 @@
 	rpc_wake_up_task(task);
 }
 
+
 /*
- * (Partly) transmit the RPC packet
- * Note that task->tk_status is either 0 or negative on return.
- * Only when the reply is received will the status be set to a
- * positive value.
+ * Serialize access to sockets, in order to prevent different
+ * requests from interfering with each other.
  */
-static inline int
-xprt_transmit_some(struct rpc_xprt *xprt, struct rpc_task *task)
+static int
+xprt_down_transmit(struct rpc_task *task)
 {
+	struct rpc_xprt *xprt = task->tk_rqstp->rq_xprt;
 	struct rpc_rqst	*req = task->tk_rqstp;
-	int		result;
 
-	task->tk_status = 0;
-	if ((result = xprt_sendmsg(xprt)) >= 0) {
-		if (!xprt->snd_buf.io_len || !xprt->stream) {
-			rpc_wake_up_next(&xprt->sending);
-			return req->rq_slen;
-		}
-		result = -EAGAIN;
-	} else if (xprt->stream) {
-		if (result == -ENOTCONN || result == -EPIPE) {
-			xprt_disconnect(xprt);
-			result = -ENOTCONN;
-		}
+	spin_lock(&xprt_lock);
+	if (xprt->snd_task && xprt->snd_task != task) {
+		dprintk("RPC: %4d TCP write queue full (task %d)\n",
+			task->tk_pid, xprt->snd_task->tk_pid);
+		task->tk_timeout = 0;
+		task->tk_status = -EAGAIN;
+		rpc_sleep_on(&xprt->sending, task, NULL, NULL);
+	} else if (!xprt->snd_task) {
+		xprt->snd_task = task;
+#ifdef RPC_PROFILE
+		req->rq_xtime = jiffies;
+#endif
+		req->rq_bytes_sent = 0;
+	}
+	spin_unlock(&xprt_lock);
+	return xprt->snd_task == task;
+}
+
+/*
+ * Releases the socket for use by other requests.
+ */
+static inline void
+xprt_up_transmit(struct rpc_task *task)
+{
+	struct rpc_xprt *xprt = task->tk_rqstp->rq_xprt;
+
+	if (xprt->snd_task && xprt->snd_task == task) {
+		spin_lock(&xprt_lock);
+		xprt->snd_task = NULL;
+		rpc_wake_up_next(&xprt->sending);
+		spin_unlock(&xprt_lock);
 	}
-	return task->tk_status = result;
 }
 
 /*
@@ -971,129 +1093,131 @@
 void
 xprt_transmit(struct rpc_task *task)
 {
-	struct rpc_timeout *timeo;
 	struct rpc_rqst	*req = task->tk_rqstp;
 	struct rpc_xprt	*xprt = req->rq_xprt;
-	int status;
 
 	dprintk("RPC: %4d xprt_transmit(%x)\n", task->tk_pid, 
 				*(u32 *)(req->rq_svec[0].iov_base));
 
-	if (xprt->shutdown) {
+	if (xprt->shutdown)
 		task->tk_status = -EIO;
-		return;
-	}
 
-	/* If we're not already in the process of transmitting our call,
-	 * set up everything as needed. */
-	if (xprt->snd_task != task) {
-		/* Write the record marker */
-		if (xprt->stream) {
-			u32	marker;
+	if (!xprt->connected)
+		task->tk_status = -ENOTCONN;
 
-			if (!xprt->connected) {
-				task->tk_status = -ENOTCONN;
-				return;
-			}
-			marker = htonl(0x80000000|(req->rq_slen-4));
-			*((u32 *) req->rq_svec[0].iov_base) = marker;
-		}
+	if (task->tk_status < 0)
+		return;
 
-		/* Reset timeout parameters */
-		timeo = &req->rq_timeout;
-		if (timeo->to_retries < 0) {
-			dprintk("RPC: %4d xprt_transmit reset timeo\n",
-						task->tk_pid);
-			timeo->to_retries = xprt->timeout.to_retries;
-			timeo->to_current = timeo->to_initval;
-		}
+	if (task->tk_rpcwait)
+		rpc_remove_wait_queue(task);
 
-#ifdef RPC_PROFILE
-		req->rq_xtime = jiffies;
-#endif
-		req->rq_gotit = 0;
+	/* set up everything as needed. */
+	/* Write the record marker */
+	if (xprt->stream) {
+		u32	*marker = req->rq_svec[0].iov_base;
 
-		if (xprt->snd_task) {
-			dprintk("RPC: %4d TCP write queue full (task %d)\n",
-					task->tk_pid, xprt->snd_task->tk_pid);
-			rpc_sleep_on(&xprt->sending, task,
-					xprt_transmit_status, NULL);
-			return;
-		}
-		xprt->snd_buf  = req->rq_snd_buf;
-		xprt->snd_task = task;
-		xprt->snd_sent = 0;
+		*marker = htonl(0x80000000|(req->rq_slen-sizeof(*marker)));
 	}
 
+	if (!xprt_down_transmit(task))
+		return;
+
+	do_xprt_transmit(task);
+}
+
+static void
+do_xprt_transmit(struct rpc_task *task)
+{
+	struct rpc_rqst	*req = task->tk_rqstp;
+	struct rpc_xprt	*xprt = req->rq_xprt;
+	unsigned long	oldflags;
+	int status, retry = 0;
+
+
 	/* For fast networks/servers we have to put the request on
 	 * the pending list now:
+	 * Note that we don't want the task timing out during the
+	 * call to xprt_sendmsg(), so we initially disable the timeout,
+	 * and then reset it later...
 	 */
-	start_bh_atomic();
-	status = rpc_add_wait_queue(&xprt->pending, task);
-	if (!status)
-		task->tk_callback = NULL;
-	end_bh_atomic();
+	xprt_receive(task);
 
-	if (status)
-	{
-		printk(KERN_WARNING "RPC: failed to add task to queue: error: %d!\n", status);
-		task->tk_status = status;
-		return;
-	}
-
 	/* Continue transmitting the packet/record. We must be careful
 	 * to cope with writespace callbacks arriving _after_ we have
 	 * called xprt_sendmsg().
 	 */
 	while (1) {
 		xprt->write_space = 0;
-		if (xprt_transmit_some(xprt, task) != -EAGAIN) {
-			dprintk("RPC: %4d xmit complete\n", task->tk_pid);
-			xprt->snd_task = NULL;
-			return;
+		status = xprt_sendmsg(xprt, req);
+
+		if (status < 0)
+			break;
+
+		if (xprt->stream) {
+			req->rq_bytes_sent += status;
+
+			if (req->rq_bytes_sent >= req->rq_slen)
+				goto out_receive;
+		} else {
+			if (status >= req->rq_slen)
+				goto out_receive;
+			status = -ENOMEM;
+			break;
 		}
 
-		/*d*/dprintk("RPC: %4d xmit incomplete (%d left of %d)\n",
-				task->tk_pid, xprt->snd_buf.io_len,
+		dprintk("RPC: %4d xmit incomplete (%d left of %d)\n",
+				task->tk_pid, req->rq_slen - req->rq_bytes_sent,
 				req->rq_slen);
-		task->tk_status = 0;
-		start_bh_atomic();
-		if (!xprt->write_space) {
-			/* Remove from pending */
-			rpc_remove_wait_queue(task);
-			rpc_sleep_on(&xprt->sending, task,
-					xprt_transmit_status, NULL);
-			end_bh_atomic();
-			return;
-		}
-		end_bh_atomic();
+
+		status = -EAGAIN;
+		if (retry++ > 50)
+			break;
 	}
-}
+	rpc_unlock_task(task);
 
-/*
- * This callback is invoked when the sending task is forced to sleep
- * because the TCP write buffers are full
- */
-static void
-xprt_transmit_status(struct rpc_task *task)
-{
-	struct rpc_xprt	*xprt = task->tk_client->cl_xprt;
+	task->tk_status = status;
 
-	dprintk("RPC: %4d transmit_status %d\n", task->tk_pid, task->tk_status);
-	if (xprt->snd_task == task) 
-	{
-		if (task->tk_status < 0)
-		{
-			xprt->snd_task = NULL;
-			xprt_disconnect(xprt);
-		}
-		else
-			xprt_transmit(task);
+	/* Note: at this point, task->tk_sleeping has not yet been set,
+	 *	 hence there is no danger of the waking up task being put on
+	 *	 schedq, and being picked up by a parallel run of rpciod().
+	 */
+	rpc_wake_up_task(task);
+	if (!RPC_IS_RUNNING(task))
+		goto out_release;
+
+	switch (status) {
+	case -ENOMEM:
+		/* Protect against (udp|tcp)_write_space */
+		task->tk_timeout = req->rq_timeout.to_current;
+		spin_lock_irqsave(&xprt_sock_lock, oldflags);
+		if (!xprt->write_space)
+			rpc_sleep_on(&xprt->sending, task, NULL, NULL);
+		spin_unlock_irqrestore(&xprt_sock_lock, oldflags);
+		return;
+	case -EAGAIN:
+		/* Keep holding the socket if it is blocked */
+		rpc_delay(task, HZ>>4);
+		return;
+	case -ECONNREFUSED:
+	case -ENOTCONN:
+		if (!xprt->stream)
+			return;
+	default:
+		goto out_release;
 	}
+
+ out_receive:
+	dprintk("RPC: %4d xmit complete\n", task->tk_pid);
+	/* Set the task's receive timeout value */
+	task->tk_timeout = req->rq_timeout.to_current;
+	rpc_add_timer(task, xprt_timer);
+	rpc_unlock_task(task);
+ out_release:
+	xprt_up_transmit(task);
 }
 
 /*
- * Wait for the reply to our call.
+ * Queue the task for a reply to our call.
  * When the callback is invoked, the congestion window should have
  * been updated already.
  */
@@ -1104,34 +1228,9 @@
 	struct rpc_xprt	*xprt = req->rq_xprt;
 
 	dprintk("RPC: %4d xprt_receive\n", task->tk_pid);
-	if (xprt->connected == 0) {
-		task->tk_status = -ENOTCONN;
-		return;
-	}
-
-	/*
-	 * Wait until rq_gotit goes non-null, or timeout elapsed.
-	 */
-	task->tk_timeout = req->rq_timeout.to_current;
-
-	start_bh_atomic();
-	if (!req->rq_gotit) {
-		rpc_sleep_on(&xprt->pending, task,
-				xprt_receive_status, xprt_timer);
-	}
-	end_bh_atomic();
-
-	dprintk("RPC: %4d xprt_receive returns %d\n",
-				task->tk_pid, task->tk_status);
-}
-
-static void
-xprt_receive_status(struct rpc_task *task)
-{
-	struct rpc_xprt	*xprt = task->tk_xprt;
 
-	if (xprt->stream && xprt->tcp_rqstp == task->tk_rqstp)
-		xprt->tcp_rqstp = NULL;
+	task->tk_timeout = 0;
+	rpc_sleep_locked(&xprt->pending, task, NULL, NULL);
 }
 
 /*
@@ -1148,7 +1247,7 @@
 
 	dprintk("RPC: %4d xprt_reserve cong = %ld cwnd = %ld\n",
 				task->tk_pid, xprt->cong, xprt->cwnd);
-	if ((!RPCXPRT_CONGESTED(xprt) && xprt->free)) {
+	if (!RPCXPRT_CONGESTED(xprt) && xprt->free) {
 		xprt_reserve_status(task);
 		task->tk_timeout = 0;
 	} else if (!task->tk_timeout) {
@@ -1177,40 +1276,30 @@
 		/* NOP */
 	} else if (task->tk_rqstp) {
 		/* We've already been given a request slot: NOP */
-	} else if (!RPCXPRT_CONGESTED(xprt)) {
+	} else if (!RPCXPRT_CONGESTED(xprt) && xprt->free) {
 		/* OK: There's room for us. Grab a free slot and bump
 		 * congestion value */
-		req = xprt->free;
-		if (!req)
-			goto bad_list;
-		if (req->rq_xid)
-			goto bad_used;
+		spin_lock(&xprt_lock);
+		if (!(req = xprt->free)) {
+			spin_unlock(&xprt_lock);
+			goto out_nofree;
+		}
 		xprt->free     = req->rq_next;
+		req->rq_next   = NULL;
+		spin_unlock(&xprt_lock);
 		xprt->cong    += RPC_CWNDSCALE;
 		task->tk_rqstp = req;
-		req->rq_next   = NULL;
 		xprt_request_init(task, xprt);
-	} else {
-		task->tk_status = -EAGAIN;
-	}
 
-	if (xprt->free && !RPCXPRT_CONGESTED(xprt))
-		rpc_wake_up_next(&xprt->backlog);
+		if (xprt->free)
+			xprt_clear_backlog(xprt);
+	} else
+		goto out_nofree;
 
 	return;
 
-bad_list:
-	printk(KERN_ERR 
-		"RPC: %4d inconsistent free list (cong %ld cwnd %ld)\n",
-		task->tk_pid, xprt->cong, xprt->cwnd);
-	rpc_debug = ~0;
-	goto bummer;
-bad_used:
-	printk(KERN_ERR "RPC: used rqst slot %p on free list!\n", req);
-bummer:
-	task->tk_status = -EIO;
-	xprt->free = NULL;
-	return;
+out_nofree:
+	task->tk_status = -EAGAIN;
 }
 
 /*
@@ -1227,7 +1316,6 @@
 
 	dprintk("RPC: %4d reserved req %p xid %08x\n", task->tk_pid, req, xid);
 	task->tk_status = 0;
-	req->rq_gotit	= 0;
 	req->rq_timeout = xprt->timeout;
 	req->rq_task	= task;
 	req->rq_xprt    = xprt;
@@ -1245,6 +1333,7 @@
 	struct rpc_xprt	*xprt = task->tk_xprt;
 	struct rpc_rqst	*req;
 
+	xprt_up_transmit(task);
 	if (!(req = task->tk_rqstp))
 		return;
 	task->tk_rqstp = NULL;
@@ -1252,46 +1341,24 @@
 
 	dprintk("RPC: %4d release request %p\n", task->tk_pid, req);
 
+	spin_lock(&xprt_lock);
+	req->rq_next = xprt->free;
+	xprt->free   = req;
+
 	/* remove slot from queue of pending */
-	start_bh_atomic();
 	if (task->tk_rpcwait) {
 		printk("RPC: task of released request still queued!\n");
 #ifdef RPC_DEBUG
 		printk("RPC: (task is on %s)\n", rpc_qname(task->tk_rpcwait));
 #endif
-		rpc_del_timer(task);
 		rpc_remove_wait_queue(task);
 	}
-	end_bh_atomic();
+	spin_unlock(&xprt_lock);
 
 	/* Decrease congestion value. */
 	xprt->cong -= RPC_CWNDSCALE;
-
-#if 0
-	/* If congestion threshold is not yet reached, pass on the request slot.
-	 * This looks kind of kludgy, but it guarantees backlogged requests
-	 * are served in order.
-	 * N.B. This doesn't look completely safe, as the task is still
-	 * on the backlog list after wake-up.
-	 */
-	if (!RPCXPRT_CONGESTED(xprt)) {
-		struct rpc_task	*next = rpc_wake_up_next(&xprt->backlog);
-
-		if (next && next->tk_rqstp == 0) {
-			xprt->cong += RPC_CWNDSCALE;
-			next->tk_rqstp = req;
-			xprt_request_init(next, xprt);
-			return;
-		}
-	}
-#endif
-
-	req->rq_next = xprt->free;
-	xprt->free   = req;
 
-	/* If not congested, wake up the next backlogged process */
-	if (!RPCXPRT_CONGESTED(xprt))
-		rpc_wake_up_next(&xprt->backlog);
+	xprt_clear_backlog(xprt);
 }
 
 /*
@@ -1303,7 +1370,7 @@
 	if (proto == IPPROTO_UDP)
 		xprt_set_timeout(to, 5,  5 * HZ);
 	else
-		xprt_set_timeout(to, 5, 15 * HZ);
+		xprt_set_timeout(to, 5, 60 * HZ);
 }
 
 /*
@@ -1330,56 +1397,32 @@
 {
 	struct rpc_xprt	*xprt;
 	struct rpc_rqst	*req;
-	struct sock	*inet;
 	int		i;
 
 	dprintk("RPC:      setting up %s transport...\n",
 				proto == IPPROTO_UDP? "UDP" : "TCP");
 
-#if LINUX_VERSION_CODE >= 0x020100
-	inet = sock->sk;
-#else
-	inet = (struct sock *) sock->data;
-#endif
-
 	if ((xprt = kmalloc(sizeof(struct rpc_xprt), GFP_KERNEL)) == NULL)
 		return NULL;
 	memset(xprt, 0, sizeof(*xprt)); /* Nnnngh! */
 
-	xprt->file = NULL;
-	xprt->sock = sock;
-	xprt->inet = inet;
 	xprt->addr = *ap;
 	xprt->prot = proto;
 	xprt->stream = (proto == IPPROTO_TCP)? 1 : 0;
-	xprt->cwnd = RPC_INITCWND;
-#ifdef SOCK_HAS_USER_DATA
-	inet->user_data = xprt;
-#else
-	xprt->link = sock_list;
-	sock_list = xprt;
-#endif
-	xprt->old_data_ready = inet->data_ready;
-	xprt->old_state_change = inet->state_change;
-	xprt->old_write_space = inet->write_space;
-	if (proto == IPPROTO_UDP) {
-		inet->data_ready = udp_data_ready;
-	} else {
-		inet->data_ready = tcp_data_ready;
-		inet->state_change = tcp_state_change;
-		inet->write_space = tcp_write_space;
+	if (xprt->stream) {
+		xprt->cwnd = RPC_MAXCWND;
 		xprt->nocong = 1;
-	}
-	xprt->connected = 1;
+	} else
+		xprt->cwnd = RPC_INITCWND;
+	xprt->congtime = jiffies;
 
 	/* Set timeout parameters */
 	if (to) {
 		xprt->timeout = *to;
 		xprt->timeout.to_current = to->to_initval;
 		xprt->timeout.to_resrvval = to->to_maxval << 1;
-	} else {
+	} else
 		xprt_default_timeout(&xprt->timeout, xprt->prot);
-	}
 
 	xprt->pending = RPC_INIT_WAITQ("xprt_pending");
 	xprt->sending = RPC_INIT_WAITQ("xprt_sending");
@@ -1392,48 +1435,13 @@
 	req->rq_next = NULL;
 	xprt->free = xprt->slot;
 
+	INIT_LIST_HEAD(&xprt->rx_pending);
+
 	dprintk("RPC:      created transport %p\n", xprt);
 	
-	/*
-	 *	TCP requires the rpc I/O daemon is present
-	 */
-	if(proto==IPPROTO_TCP)
-		rpciod_up();
-	return xprt;
-}
-
-/*
- * Create and initialize an RPC client given an open file.
- * This is obsolete now.
- */
-#if 0
-struct rpc_xprt *
-xprt_create(struct file *file, struct sockaddr_in *ap, struct rpc_timeout *to)
-{
-	struct rpc_xprt	*xprt;
-	struct socket	*sock;
-	int		proto;
-
-	if (!file) {
-		printk("RPC: file == NULL in xprt_create!\n");
-		return NULL;
-	}
-
-	sock = &file->f_inode->u.socket_i;
-	if (sock->ops->family != PF_INET) {
-		printk(KERN_WARNING "RPC: only INET sockets supported\n");
-		return NULL;
-	}
-
-	proto = (sock->type == SOCK_DGRAM)? IPPROTO_UDP : IPPROTO_TCP;
-	if ((xprt = xprt_setup(sock, proto, ap, to)) != NULL) {
-		xprt->file = file;
-		file->f_count++;
-	}
-
+	xprt_bind_socket(xprt, sock);
 	return xprt;
 }
-#endif
 
 /*
  * Bind to a reserved port
@@ -1459,38 +1467,64 @@
 	return err;
 }
 
+static int 
+xprt_bind_socket(struct rpc_xprt *xprt, struct socket *sock)
+{
+	struct sock	*sk = sock->sk;
+
+	if (xprt->inet)
+		return -EBUSY;
+
+	sk->user_data = xprt;
+	xprt->old_data_ready = sk->data_ready;
+	xprt->old_state_change = sk->state_change;
+	xprt->old_write_space = sk->write_space;
+	if (xprt->prot == IPPROTO_UDP) {
+		sk->data_ready = udp_data_ready;
+		sk->write_space = udp_write_space;
+		xprt->connected = 1;
+	} else {
+		sk->data_ready = tcp_data_ready;
+		sk->state_change = tcp_state_change;
+		sk->write_space = tcp_write_space;
+		xprt->connected = 0;
+	}
+
+	/* Reset to new socket */
+	xprt->sock = sock;
+	xprt->inet = sk;
+	/*
+	 *	TCP requires the rpc I/O daemon is present
+	 */
+	if(xprt->stream)
+		rpciod_up();
+
+	return 0;
+}
+
 /*
  * Create a client socket given the protocol and peer address.
  */
 static struct socket *
-xprt_create_socket(int proto, struct sockaddr_in *sap, struct rpc_timeout *to)
+xprt_create_socket(int proto, struct rpc_timeout *to)
 {
 	struct socket	*sock;
 	int		type, err;
 
-	dprintk("RPC:      xprt_create_socket(%08x, %s %d)\n",
-			   sap? ntohl(sap->sin_addr.s_addr) : 0,
+	dprintk("RPC:      xprt_create_socket(%s %d)\n",
 			   (proto == IPPROTO_UDP)? "udp" : "tcp", proto);
 
 	type = (proto == IPPROTO_UDP)? SOCK_DGRAM : SOCK_STREAM;
+
 	if ((err = sock_create(PF_INET, type, proto, &sock)) < 0) {
 		printk("RPC: can't create socket (%d).\n", -err);
 		goto failed;
 	}
 
-	/* If the caller has root privs, bind to a reserved port */
-	if (!current->fsuid && xprt_bindresvport(sock) < 0)
+	/* If the caller has the capability, bind to a reserved port */
+	if (capable(CAP_NET_BIND_SERVICE) && xprt_bindresvport(sock) < 0)
 		goto failed;
 
-	if (type == SOCK_STREAM && sap) {
-		err = sock->ops->connect(sock, (struct sockaddr *) sap,
-						sizeof(*sap), 0);
-		if (err < 0) {
-			printk("RPC: TCP connect failed (%d).\n", -err);
-			goto failed;
-		}
-	}
-
 	return sock;
 
 failed:
@@ -1509,7 +1543,7 @@
 
 	dprintk("RPC:      xprt_create_proto called\n");
 
-	if (!(sock = xprt_create_socket(proto, sap, to)))
+	if (!(sock = xprt_create_socket(proto, to)))
 		return NULL;
 
 	if (!(xprt = xprt_setup(sock, proto, sap, to)))
@@ -1529,6 +1563,19 @@
 	rpc_wake_up(&xprt->pending);
 	rpc_wake_up(&xprt->backlog);
 	rpc_wake_up(&xprt->reconn);
+	wake_up(&xprt->cong_wait);
+}
+
+/*
+ * Clear the xprt backlog queue
+ */
+int
+xprt_clear_backlog(struct rpc_xprt *xprt) {
+	if (RPCXPRT_CONGESTED(xprt))
+		return 0;
+	rpc_wake_up_next(&xprt->backlog);
+	wake_up(&xprt->cong_wait);
+	return 1;
 }
 
 /*
@@ -1537,19 +1584,8 @@
 int
 xprt_destroy(struct rpc_xprt *xprt)
 {
-#ifndef SOCK_HAS_USER_DATA
-	struct rpc_xprt	**q;
-
-	for (q = &sock_list; *q && *q != xprt; q = &((*q)->link))
-		;
-	if (!*q) {
-		printk(KERN_WARNING "xprt_destroy: unknown socket!\n");
-		return -EIO;	/* why is there no EBUGGYSOFTWARE */
-	}
-	*q = xprt->link;
-#endif
-
 	dprintk("RPC:      destroying transport %p\n", xprt);
+	xprt_shutdown(xprt);
 	xprt_close(xprt);
 	kfree(xprt);
 
Index: oldkernel/linux/net/unix/af_unix.c
diff -u linux/net/unix/af_unix.c:1.2 linux/net/unix/af_unix.c:1.3
--- linux/net/unix/af_unix.c:1.2	Thu Jun  1 15:08:25 2000
+++ linux/net/unix/af_unix.c	Fri Jul  7 15:36:50 2000
@@ -969,6 +969,10 @@
 			return -ENOTCONN;
 	}
 
+	err = -EMSGSIZE;
+	if (len > sk->sndbuf)
+		goto out;
+
 	if (sock->passcred && !sk->protinfo.af_unix.addr)
 		unix_autobind(sock);
 
Index: oldkernel/linux/pcmcia-cs-3.1.15/BUGS
diff -u /dev/null linux/pcmcia-cs-3.1.15/BUGS:1.1
--- /dev/null	Mon Jul 31 21:15:09 2000
+++ linux/pcmcia-cs-3.1.15/BUGS	Fri Jul  7 16:18:18 2000
@@ -0,0 +1,169 @@
+Known problems and limitations for the 3.1.15 PCMCIA release
+============================================================
+
+Bug summaries:
+
+o CardBus devices with 2.0.* kernels not recommended
+o PCI interrupt routing issue for CardBus bridges on some systems
+o PCI configuration problems with 2.3.* kernels
+o O2Micro and ToPIC CardBus bridge configuration problems
+o On the Sony VAIO PCG-N505VE, interrupts break after a suspend
+o SCSI drivers are not hot swap safe
+o Iomega Clik! drives require a kernel patch
+o Token ring memory allocation issues
+o Interrupt lossage with Megahertz multifunction cards
+o The aic7xxx/apa1480_cb driver misbehaves if the cable is detached
+o Ositech Jack of Diamonds firmware issue
+o Serial interrupt sharing bug in certain 2.2.*, 2.3.* kernels
+o aha152x interrupt bug in certain 2.2.* kernels
+o IDE driver shutdown bug in certain 2.2.*, 2.3.* kernels
+o Tedious IDE probes for nonexistent slave devices
+o parport_cs doesn't work in 2.3.*
+o Xircom CardBus driver instability
+o epic_cb driver broken in 2.2.15pre
+
+Bug details:
+
+o Use of CardBus cards with 2.0.* kernels is discouraged.  It may work
+  on some systems, but not on others, due to PCI BIOS limitations.
+  Also, it is harder to diagnose problems, because /proc/bus/pccard is
+  not available with these kernels.
+
+o With some PCI host bridges, the PCMCIA subsystem is not able to
+  determine the PCI interrupt routing for CardBus bridges.  For some
+  types of CardBus bridges, this means that we can't configure
+  interrupts for CardBus cards at all.  When the PCMCIA drivers are
+  loaded, they may complain about an "unknown interrupt router".
+
+  Prognosis: I think the latest drivers now handle most common host
+  bridges correctly.  The "dump_pirq" tool in debug-tools will return
+  interrupt routing information for all supported bridges.
+
+o Some 2.3.* kernels may make mistakes when autoconfiguring CardBus
+  bridges.  Specifically, the kernel may memory map bridges at invalid
+  addresses.  The i82365 driver reports a "Bad bridge mapping".  In
+  other cases, the PCI subsystem may misconfigure PCI interrupts for
+  CardBus bridges.
+
+  Prognosis: either upgrade to a newer 2.3.* kernel if possible, or
+  revert to a 2.2.* kernel.
+
+o Interrupt routing on O2Micro CardBus bridges seems to have problems.
+  Toshiba ToPIC97 bridges also seem to have problems, particularly
+  with Cardbus cards.
+
+  Prognosis: I think the O2Micro problems should now be fixed.  For
+  the ToPIC problem, Toshiba does not seem willing and/or able to
+  provide adequate help, so I've mostly given up on it.  For both the
+  O2Micro and ToPIC problems, fixes would require someone with device
+  driver experience and the relevant hardware to work on it: data
+  sheets are available, and I can make suggestions of things to try,
+  but I can't debug the problems by email.
+
+  With ToPIC chipsets, some systems seem to work better if the bridge
+  mode is changed to either "PCIC" or "CardBus", rather than "Auto",
+  in the BIOS setup menu.
+
+o On the Sony VAIO PCG-N505VE, after a suspend, no interrupts are
+  delivered by the CardBus bridge until the system is rebooted.
+
+  Prognosis: I've spent a lot of time trying to track this down, but
+  I'm completely stumped.  The PCMCIA drivers appear to restore the
+  state of the CardBus bridge correctly, and the PCI interrupt router
+  is also configured properly.  But no interrupts get through.
+
+o All of the SCSI drivers, and most of the CardBus drivers, do not
+  implement suspend/resume handling.  The only workaround now is to
+  eject these cards (or do "cardctl eject") before suspending.
+  
+  Prognosis: CardBus Network cards will probably be fixed eventually,
+  but it has not been a high priority.  SCSI drivers are less likely
+  to be fixed since we're more dependent on kernel code.
+
+o The Iomega Clik! drive is incompatible with the kernel ide-floppy
+  driver.  A kernel patch for 2.2.14 and later 2.2 kernels is
+  available at http://paulbristow.net/linux/clik.html.
+
+o The token ring driver tweaks a problem in the memory management
+  code.  To work around the problem, remove all high memory windows
+  from /etc/pcmcia/config.opts.  The driver is also completely broken
+  for late 2.1 and early 2.2 kernels.  A fix is in 2.2.7.
+
+o Megahertz EM1144, EM3288, and EM3336 cards drop interrupts if the
+  modem and ethernet are used simultaneously.
+  
+  Prognosis: Unlikely to be fixed, since these cards are old and we
+  are unlikely to ever get more complete tech info.
+
+o The kernel aic7xxx driver, which is linked into the apa1480_cb
+  driver, can generate spurious interrupts when a card is initialized,
+  which can cause system lockups.  This will usually happen if the
+  card is inserted with no SCSI cable attached.
+
+  Prognosis: I've sent a patch to the driver maintainer.  The problem
+  can be mostly mitigated by disabling use of PCI interrupts for
+  CardBus cards, by setting PCIC_OPTS="pci_int=0".  This setting does
+  not work on some newer laptops; in those cases, you'll have to wait
+  for a kernel update to fix the problem.
+
+o Some Ositech Jack of Diamonds 33.6K modem/ethernet cards don't work
+  because of a firmware issue.  With these cards, the smc91c92_cs
+  driver reports "Bad chip signature".
+
+  A DOS program to update the card firmware to v8.1B is available from
+  Ositech's web site at ftp://www.ositech.com/pub/jod/JDCEL422.EXE
+
+o The 2.2.*/2.3.* serial driver had a bug that interfered with
+  interrupt sharing for multifunction cards.  The effect is that
+  opening a serial port on a multifunction card fails, giving an IO
+  error.  It was fixed in 2.2.11 and 2.3.9.
+
+  The bug can be fixed by editing linux/drivers/char/serial.c and
+  changing each use of IRQ_T(info) to IRQ_T(state).
+
+o The kernel aha152x driver, used for Adaptec 16-bit SCSI adapters,
+  had a PCMCIA compatibility problem in 2.2.* that was fixed in 2.2.9.
+  The effect was that interrupts were ignored, unless the card
+  happened to be configured for irq 9..12.
+
+  Either upgrade to a 2.2.9 or later kernel, or if you have an
+  appropriate interrupt available, add to /etc/pcmcia/config.opts:
+
+    module "aha152x_cs" opts "irq_list=9,10,11,12"
+
+o The kernel IDE driver had a bug that causes shutdown of some PCMCIA
+  IDE cards to cause a kernel trap.  It was introduced in 2.2.9/2.3.1
+  and fixed in 2.2.10/2.3.4.
+
+o For some ATA/IDE devices, the IDE driver will lock up the system for
+  up to 15 seconds while probing for (non-existent) slave devices.
+
+  I've told the IDE maintainer about the issue and it is just a matter
+  of getting the kernel driver updated.  There are two aspects to the
+  fix; one is to improve automatic detection of flash memory cards,
+  and the other is to change the probe to sleep instead of freezing
+  the system during the probe.
+
+o The 2.3.6 kernel update broke the PCMCIA parport_cs driver.
+
+  Prognosis: it should be fixable in newer 2.3.* kernels, but I just
+  have not gotten around to doing it.
+
+o Xircom CBEM support in the tulip_cb driver seems to be extremely
+  unreliable.  A wide range of symptoms are reported, ranging from no
+  packet reception, to correct operation at certain speed/duplex
+  combinations but not others, to frequent missed interrupts.  Also,
+  some people have reported kernel faults when a Xircom card is shut
+  down with "ifconfig down".
+
+  Prognosis: there seem to be multiple revisions of the (apparently)
+  not-quite-tulip-compatible chipset in the Xircom cards, and fixes
+  that seem to help for some cards, break other cards.  Until someone
+  can try to characterize what the revision differences might be, this
+  is not going to get fixed.
+
+  Setting the card to promiscuous mode ("ifconfig eth0 promisc") seems
+  to help in some cases.
+
+o CardBus support got deleted from the epic100 driver in 2.2.15pre2.
+
Index: oldkernel/linux/pcmcia-cs-3.1.15/CHANGES
diff -u /dev/null linux/pcmcia-cs-3.1.15/CHANGES:1.1
--- /dev/null	Mon Jul 31 21:15:09 2000
+++ linux/pcmcia-cs-3.1.15/CHANGES	Fri Jul  7 16:18:18 2000
@@ -0,0 +1,1654 @@
+[16-May-00] Version 3.1.15
+-- Added test_setup, test_network, test_modem to debug-tools.
+-- Added D-Link DL10022 chipset support to pcnet_cs driver.
+-- Dropped dump_i365 debug tool, added dump_exca and dump_cardbus.
+-- Added TI 1410 bridge support.
+-- Added some PCI fixups for VIA and SiS PCI-to-ISA bridges.
+-- Fixed another device eject bug in ray_cs driver.
+-- Fixed amazingly braindead bug in ide_info.
+-- Changed tulip_cb driver to set up receive filter differently for
+   Xircom CardBus cards.
+-- Fixed big-endian transmit bug in smc91c92_cs driver.
+-- Changed i82365 module to default to probing 0x3e2 (in addition to
+   0x3e0) for ISA bus bridges, if it doesn't find anything else.
+-- Replaced most of etc/Makefile with a simpler shell script.
+-- Updated a few modules to use newer PCI, procfs, and timer API's.
+-- Changed i82365 module to not trust PCI irq test on Ricoh bridges.
+-- Changed cardmgr to use modprobe whenever it is available.
+-- Changed dump_pirq to scan for known irq routers if there is no PCI
+   interrupt routing table.
+-- Updated pcnet_cs driver to reject AX88190 chipsets for now.
+-- A couple of minor Makefile changes; one 2.3.* build problem fixed.
+-- Minor iflash2+_mtd driver tune-up; added new write option that is
+   faster but spins instead of sleeping during page writes.
+-- Better heuristic for automatic detection of flash memory cards.
+-- Fixed glitches in new wireless config scripts.
+-- Added MTU parameter to network script.
+-- Fixed problems with INITTAB handling in serial config script.
+
+[10-Apr-00] Version 3.1.14
+-- Added wireless.opts config script for drivers that support the
+   wireless tools API.
+-- Made the i82365 module's wedged-irq test more conservative.
+-- Updated scsi_info to use SCSI_IOCTL_GET_BUS_NUMBER when available.
+-- Added more info about CardBus interrupt routing issues to the HOWTO
+   and the i82365 man page.
+-- Fixed apa1480 driver for compatibility with latest aic7xxx driver.
+-- Changed i82365 module to also report chip revision for PCI bridges.
+-- Fixed i82365 driver to ignore phantom card in unwired second socket
+   of Lucent/SCM TI 1225 based card docks.
+-- Fixed power management to be compatible with 2.3.* stuff.
+-- Added ALI M1533 chipset support to dump_pirq and pci_fixup.
+-- Changed alpha builds to use the "generic" hardware configuration.
+-- Fixed config scripts to quote $ADDRESS in a few spots, to handle a
+   Maxtor IDE card with a non-ascii serial number.
+-- Updated airo_cs driver to build with 2.3.*.
+-- Added a DHCP_HOSTNAME parameter to network script.
+-- Fixed a 2.3.99pre3 module compilation quirk.
+-- Updated ray_cs driver to release 1.70.
+-- Added MII access routines for DL10019 cards to pcnet_cs driver.
+-- Minor smc91c92_cs driver cleanup, added SMC91C110 identification.
+-- Added --sysv, --bsd, --rcdir options to Configure script.
+-- Added PCI interrupt fixup support for the Intel 440MX chipset.
+-- Added another sanity check to PnP resource allocator.
+-- Added SS_CAP_STATIC_MAP: support for architectures that map PCMCIA
+   memory at fixed addresses in host memory.
+-- Fixed i82365 /proc cleanup bug exposed in 2.2.14/2.2.15 kernels.
+
+[14-Mar-00] Version 3.1.13
+-- Added 3.3V card detection for Cirrus PD6729 bridges.
+-- Added PCI fixup support for VIA and OPTi bridges, and "cb_pci_irq"
+   parameter for overriding the PCI interrupt routing table.
+-- Improved "dump_pirq": added OPTi and PicoPower chipset support, and
+   serial irq reporting for PIIX bridges.
+-- Fixed i82365 no-PCI builds, and a PowerPC bug.
+-- Fixed brain dead ray_cs bug introduced in 3.1.12.
+-- Fixed two 2.0.* kernel compatibility glitches.
+
+[08-Mar-00] Version 3.1.12
+-- Added "dump_pirq" utility to debug-tools.
+-- Added support for parsing PIRQ tables for VIA PCI-to-ISA bridges.
+-- Added PCI interrupt support for Cirrus PD6729-based PCI card docks.
+-- Tweaked CIS validation algorithm to be a bit less picky.
+-- Updated network drivers to use the 2.3.* softnet API's.
+-- wavelan_cs, wvlan_cs, and airo_cs driver updates.
+-- Fixed network script to not set up unnecessary default routes when
+   doing DHCP and BOOTP on a newer kernel.
+-- Fixed Configure script to better handle extraversion info for
+   current kernel, when checking kernel versions.
+-- More checking of PCI interrupts, so the i82365 module can usually 
+   figure out if they won't work.
+
+[17-Feb-00] Version 3.1.11
+-- Changed master Makefile to not build any modules for new kernels.
+-- Added support for TI 1031 bridge.
+-- Changed cb_mem_base parameter semantics so that it can override an
+   existing bridge register mapping.
+-- Fixed out-of-order kfree() bug in 3c575_cb and tulip_cb drivers.
+-- Fixed the dhcpcd version check so it doesn't log strange messages.
+-- Fixed serial script to work with older versions of setserial.
+-- Fixed typo in bootp handler in network script.
+-- Added code to enable PCI interrupts in certain cases where they are
+   disabled in the PCI host bridge.
+-- Renamed pci_irq.c to pci_fixup.c, and moved most of the PCI bus
+   hacks from the i82365 driver into this file.  The cb_bus_base,
+   cb_bus_step, and cb_mem_base parameters all moved, also.
+-- Fix for systems that have trouble with card voltage detection
+   following a suspend.
+-- Changed Configure script to automatically decide how to get kernel
+   configuration options, whenever safe to do so.
+-- Fixed Configure script bug in parsing of 'ksyms' output, triggered
+   by lucent winmodem module.
+-- Partial fix for APA1480 lockup when card is inserted with no
+   devices.  The other part requires an aic7xxx driver update.
+
+[01-Feb-00] Version 3.1.10
+-- More complete PCI interrupt lookup code for 2.2.* kernels.
+-- Fixed dumb bug that broke 2.0.* kernel builds.
+-- Fixed no-PCI compilation bug in i82365 driver.
+-- Fixed airo_cs and ftl_cs drivers for recent 2.3.* kernels.
+
+[26-Jan-00] Version 3.1.9
+-- Added workaround for serial-driver initialization bug, that messes
+   up devices at non-standard IO ports.
+-- Made PCI interrupt table lookup mandatory, and changed pci_csc and
+   pci_int to default to "on" in the i82365 driver.
+-- Updated tulip driver to Donald Becker's "0.91g" version.
+-- Various updates for 2.3.37 and later kernels.
+-- Filled in some gaps in dump_cis output.
+-- Added "indirect addressing" support for Zoomed Video cards.
+-- Created a separate directory for all the wireless drivers; added
+   the Raylink, Aironet, and Wavelan IEEE drivers.
+-- Added replacement CIS for MultiTech MT5634ZLX modems.
+-- Fixed tx/rx byte counts for 3c574_cs driver.
+-- Fixed a very obscure memory allocation bug in cardmgr.
+-- Fixed a bug in "cardctl config" reporting of memory window status.
+-- Fixed 3c575_cb reset and resume code to initialize the rx ring, and
+   fixed the "too much work" recovery code, and a small memory leak.
+-- Fixed hot eject bugs in 3c575_cb and tulip_cb drivers.
+-- More aggressive checking of CardBus bridge register mapping.
+-- Fixed a bug in the 3c589, 3c574, smc91c92 missed-interrupt handling
+   code, that was introduced in 3.1.5.
+-- Minor Makefile cleanup, including a fix for token ring with 2.3.
+-- General i82365 driver cleanup.
+-- Updated cardmgr to support PCI device lookups for CardBus cards.
+-- Updated Makefiles to mesh better with in-kernel PCMCIA if present.
+
+[21-Dec-99] Version 3.1.8
+-- Updated drivers to use capabilities instead of suser().
+-- Added "p2cclk" option to i82365 driver... see man page for details.
+-- Fixes for block device driver API changes in 2.3.32 kernel.
+-- Fixed a 3c575_cb driver bug, in the "HostError" recovery code.
+-- Fixed man/Makefile to install the Intel flash driver man pages.
+
+[16-Dec-99] Version 3.1.7
+-- Took out some i82365 options that have turned out to probably never
+   be needed: has_clkrun, clkrun_sel, pci_latency, and cb_latency.
+-- Retired the (unsafe) PCI interrupt scan in i82365 module.
+-- Removed glibc dependency in 3.1.6 cardmgr update.
+-- Fixed a bug in 3c575_cb "too much work in interrupt" handler.
+-- Fixed bug in i82365 power selection code for CardBus bridges.
+-- Fixed a resource allocation bug in the PnP module that could
+   sometimes cause free resources to be marked as unavailable.
+
+[10-Dec-99] Version 3.1.6
+-- Added modinfo strings to basic modules.
+-- Added filename globbing to cardmgr's "source" command.
+-- Changed i82365 module to enable speaker output on all TI bridges.
+-- Changed xirc2ps_cs driver to be silent about dropped rx packets.
+-- Relaxed an IO port allocation check in serial_cs driver.
+-- Added Toshiba ToPIC100 bridge device ID's.
+-- Fixed memory allocation bug mainly affecting ibmtr_cs driver.
+-- Fixed obscure CardBus setup problem with APA1480 cards.
+-- Fixed bug in PCI resource management code affecting ROM regions.
+
+[02-Dec-99] Version 3.1.5
+-- Minor updates to default *.opts files.
+-- Fixed CardBus setup code to initialize the address space bits in a
+   new pci_dev structure properly.
+-- Fixed reset bug in cb_enabler module.
+-- Updated ide_info to use /proc/ide when possible.
+-- Added a couple more sanity checks to i82365 driver, and fixed it to
+   exclude interrupts reserved for PnP devices.
+-- In xirc2ps_cs, added back ability to force 100baseT with newer
+   cards, and changed busy loop to sleep whenever possible.
+-- Fixed memory_cb driver to use 32-bit transfers whenever possible.
+-- Added CONFIG_NET_FASTROUTE check to Configure script.
+-- Removed "compiler flags for debugging?" from interactive Configure
+   options: now you have to set it using a command-line option.
+-- General cleanup: added checks for kmalloc() failure, and simplified
+   some client driver data structure handling.
+-- Fixed a bug in the CardBus resource allocator, related to the 3.1.4
+   IO allocation change, but also sometimes affecting memory windows.
+
+[11-Nov-99] Version 3.1.4
+-- Relaxed the IO port allocation rules to do a better job with cards
+   that don't decode all 16 address lines.
+-- Tweaked qlogic_cs driver for Panasonic KXL-810AN.
+-- Added dhclient support to network script.
+-- Added /proc/pccard/drivers to ds module, and changed cardmgr to use
+   it to avoid unnecessary module load attempts.
+-- Made status change interrupt selection more conservative.
+-- Minor config file and Makefile tweaks.
+-- Yet another change to card voltage interrogation sequence.
+-- Reverted to not using PCI card status change interrupts by default
+   because they do bad things on some systems.
+-- Work-around for 2.2.13 powerpc spinlock kernel header lameness.
+-- Small tweak for O2Micro OZ6812 bridge.
+-- A proper fix for the transceiver selection problem with Xircom
+   16-bit 100baseT cards.  Also some code cleanup.
+-- Fixed pcnet_cs, smc91c92_cs to return "operation not supported" for
+   attempts to set the transceiver type on cards that can't do that.
+-- Fixed transceiver flakiness with DL10019 based fast ethernet cards
+   such as the D-Link DFE-650, Linksys Etherfast, etc.
+-- Fixed cardinfo to look for stab in all the right places.
+-- Fixed a 2.0.* kernel compatibility glitch.
+
+[25-Oct-99] Version 3.1.3
+-- Deleted manual configuration option from Configure script: it is
+   almost always a bad idea.
+-- Increased Vcc settle time from 300ms to 400ms, to fix flaky card
+   detect on some Toshiba laptops running on battery power.
+-- Changed i82365 startup-time card voltage detection to be more
+   bullet proof, again to fix trouble on Toshiba laptops.
+-- Documentation updates.
+-- Fixed build if <linux/compile.h> is missing.
+-- Fixed config scripts to handle broken "fuser -s" behavior.
+
+[20-Oct-99] Version 3.1.2
+-- Minor wavelan & netwave driver update.
+-- Updated Xircom support in tulip_cb, from Doug Ledford.
+-- Added WIN_STRICT_ALIGN option for aligning memory windows, for the
+   nasty ibmtr cards.
+-- Added 3CCFE575CT support to 3c575_cb driver.
+-- Added 'free_ports' option to dummy_cs module, so it can be used to
+   prepare a card for use by a non-PCMCIA-aware driver.
+-- Changed etc/Makefile to prefer to use /etc/modules.conf over
+   /etc/conf.modules.
+-- Moved the stab and pcmcia scheme files: they will go either to
+   /var/state/pcmcia or /var/lib/pcmcia, depending on /var layout.
+-- Added O2Micro OZ6812 bridge info.
+-- Switched on PCI card status irq's in i82365 module, by default.
+-- Changed module Makefiles to use "cp" instead of "cp -p".
+-- Better argument checking for 'setpnp'.
+-- Fixed NFS mount unwinding bug in network script.
+-- Fixed duplex selection and tx/rx byte counts in 3c575_cb driver.
+-- Fixed bug where ifuser skipped the first line of routing info.
+-- Cleaned up data types for IO port addresses.
+-- In 3c574_cs, changed "too much work" to a debugging message, since
+   it is mostly normal and we can't do anything about it.
+-- Fixed PCMCIA shutdown bug affecting sockets with Cardbus cards.
+-- Fixed 3c574_cs to autonegotiate full duplex without help.
+-- Fixed a card status interrupt bug that could cause unhandled PCI
+   interrupts.
+
+[28-Sep-99] Version 3.1.1
+-- A bunch of code tweaks to simplify kernel integration.
+-- Fixed data structure corruption bug in cardmgr config file reload.
+-- Fixed Toshiba ToPIC CardBus card insert/eject detection problem.
+-- Fixed an O2Micro OZ6833 interrupt delivery problem.
+-- Fixed PCI Interrupt Routing Table parser to gracefully handle a few
+   more special cases.
+-- Fixed Configure script bug in constructing module directory paths
+   for some kernels with extra version info (i.e., ac* kernels).
+-- Fixed ifuser bug in parsing of non-English-language netstat output.
+-- Fixed xirc2ps_cs problem with fast ethernet cards on 10baseT links.
+-- Fixed creation/removal rules for /var/run/cardmgr.pid.
+-- Fixed cardmgr to close some open file descriptors.
+-- Fixed a CardBus hot-eject bug introduced in the 3.1.0 PCI fixes.
+-- Fixed a debug macro mistake in bulkmem.
+-- Fixed ide script to mknod new devices, instead of using MAKEDEV.
+
+[10-Sep-99] Version 3.1.0
+-- Changed output of "cardctl config" to have a more consistent look,
+   and added stuff for reporting memory windows.
+-- Added PCI id's for TI 1211 and 1420 CardBus bridges.
+-- Added check to i82365 module for bad bridge register mappings.
+-- Added more entries to the PnP device list.
+-- Added /sbin/pump support to network script.
+-- Added broken-interrupt detection and recovery to pcnet_cs driver.
+-- Minor cosmetic update to Wavelan driver.
+-- Updated Configure script: made CC and LD options only available
+   from the command line, since they're not used much.
+-- Minimal changes to accommodate 2.3.13 resource management code.
+-- Better system resource conflict avoidance, using PnP BIOS services,
+   and added PnP utilities lspnp & setpnp.
+-- Commented out a couple of bogus config file entries that were
+   causing the tulip_cb driver to load for various 16-bit cards.
+-- Fixed 2.3.16 serial_cb/serial_cs and CardBus breakage.
+-- Fixed smc91c92_cs 100baseT operation with smc91c100fd chipsets.
+-- Fixed module cleanup bug in apa1480_cb driver causing kernel panics
+   if there are no attached devices.
+-- Fixed IDE setup script to create missing device files.
+-- Fixed Toshiba ToPIC initial card type detection.
+-- Fixed network drivers for 2.3.14 kernel.
+-- Fixed install bug causing /etc/conf.modules to accumulate cruft.
+-- Fixed obscure bug in tcic driver causing irq 11 to be tied up if
+   polled status changes are selected.
+-- Three CardBus bug fixes: fixed /proc/bus/pci/* for multifunction
+   cards, fixed a kernel oops if a 32-bit driver is loaded for a
+   16-bit card, and added more sanity checks to CIS reading code.
+
+[30-Jul-99] Version 3.0.14
+-- Updated license to version 1.1 of MPL.
+-- Updated for 2.3.12 kernel.
+-- Added --kflags, --uflags options for Configure script.
+-- Added Ositech Seven of Diamonds support.
+-- Added delay to serial_cb initialization sequence.
+-- Rewrite of smc91c92_cs transceiver detection code.
+-- Incorporated 0.91 tulip driver, with Xircom CardBus tweaks.
+-- The usual handful of config file updates.
+-- Tweaked 3c589_cs transceiver detection algorithm.
+-- Fixed endianness problem in pcnet_cs driver.
+-- Fixed memory allocation bug in rsrc_mgr that was exposed under
+   recent *-ac kernels.
+-- Fixed small error in formatted size calculation in ftl_format.
+-- Fixed memory probe problem introduced in 3.0.13.
+-- Fixed cardinfo to be less picky about version checking.
+-- Fixed bug in cb_enabler cleanup code when a card config fails.
+-- Implemented suspend/resume support for 3c575_cb driver, and fixed
+   3CCFEM656B network operation... but modem is a Winmodem :(
+
+[24-Jun-99] Version 3.0.13
+-- Updated spin lock code to deal with 2.3.7 kernel update.
+-- Updated resource management code to fit with new kernel resource
+   handling code that I'm working on.
+-- Changed "make config" to silently do a "make clean".
+-- Changed smc91c92_cs driver to report memory size, and to do a
+   better job of selecting between 8-bit and 16-bit accesses.
+-- Improved the 3c589 transceiver detection logic, to avoid a problem
+   where XJack cards could get stuck on 10base2.
+-- Added back support for 3.3V 16-bit cards with ToPIC97 bridges.
+-- Updated Configure script for 2.3.6 and Alan Cox's large-memory
+   kernel updates.
+-- Added CIS fix for Advantech COMpad-32/85.
+-- Changed serial script to be smarter about choosing between cua* and
+   ttyS* devices with newer kernels.
+-- Updated network script to cleanly handle recent versions of dhcpcd.
+-- Updated memory_cs and ftl_cs for 2.3.3 kernel changes.
+-- Some config tweaks from David Parsons: fixed handling of multiword
+   options in Configure script.
+-- Fixed xirc2ps_cs driver to count bytes received and transmitted.
+-- Fixed parport_cs driver breakage and added support for EPP mode.
+-- Fixed ISA interrupt routing problem for card status interrupts with
+   TI 1250A controllers.
+-- Fixed i82365 module to disable write posting on TI1130 revision 4
+   bridges by default, since it seems flaky.  This was reported to
+   cause trouble with various cards for PCMCIA releases 3.0.6 onwards.
+
+[06-Jun-99] Version 3.0.12
+-- Fixed suspend/resume bug in transceiver monitoring code in 3c589_cs
+   and 3c574_cs drivers.
+-- Updated 3c575_cb driver to Donald Becker's 0.99L version.
+-- Tweaked smc91c92_cs driver to handle smc91c100fd cards.
+-- Changed the active-socket check in i82365 module to also work for
+   CardBus sockets, and to give more informative messages.
+-- Changed high memory probe to probe regions from the highest address
+   downwards, and updated default config.opts, so the defaults should
+   work for ThinkPad 600's.
+-- Added access to another interrupt routing mode for TI controllers
+   via the irq_mode parameter.
+-- Relaxed too-strict alignment rules for memory windows.
+-- Tweaked PCI bus management code in i82365 driver.
+-- Fixed Configure script to keep better track of where modules should
+   go, when the kernel source tree is updated.
+-- Fixed new bugs in CardBus CIS identification.
+-- Fixed suspend/resume breakage from 3.0.11.
+-- Fixed 2.3.* kernel breakage that snuck into 3.0.11.
+
+[28-May-1999] Version 3.0.11
+-- Added support for Quatech SPP-100 parallel port card.
+-- Tweaked pcnet_cs driver's algorithm for choosing shared memory
+   versus polled IO, to be safer.
+-- Changed smc91c92_cs driver to handle some 100baseT smc91c100 cards.
+-- Fixed dual-voltage IDE and serial device support.
+-- Fixed bug in multifunction CardBus card shutdown logic, and fixed
+   handling of CardBus devices in /proc/bus/pci.
+-- Fixed the 3c589_cs driver to enable the link LED for 3C589E cards.
+-- Fixed the 3c574_cs transceiver initialization bug.  Also did a lot
+   of general code cleanup, and added nicer link status reporting.
+
+[17-May-1999] Version 3.0.10 
+-- Updated for 2.3.1 kernel wait queue changes.
+-- Updated wavelan_cs, ibmtr_cs drivers.
+-- Started to add support for foreign host bridge architectures.
+-- Config file updates for PE-200, KTI PE520 ethernet.
+-- Changed ide_cs driver to accommodate some smartmedia cards with
+   inadequate CIS information.
+-- Changed pcnet_cs driver to autodetect whether or not to use shared
+   memory, and removed use_shmem parameter.
+-- Changed network script to undo NFS mounts in reverse order, and to
+   avoid dhcpd blocking problem.
+-- Changed module install directory to be specified relative to the
+   alternate target directory.
+-- Added more sanity checks to CardBus expansion ROM validation.
+-- Added support for TI 1225 CardBus bridge.
+-- Tweaked Configure script for bash-2.0.
+-- Cleaned up 3c589_cs driver: fixed some corner cases, added better
+   media detection and broken-interrupt recovery.
+-- Better handling of removable SCSI devices with missing media.
+-- Fixed bug in driver cleanup logic that could sometimes prevent
+   proper driver shutdown.
+-- Fixed all 16-bit network clients to deal with 2.2.* restrictions on
+   when devices can be unregistered.
+-- Fixed pack_cis to be more flexible about number formats, added
+   packing of device info tuples.
+-- Fixed several bugs in FTL layer driver.
+-- Fixed CardBus card shutdown race condition.
+-- Fixed rx/tx buffer sizing, tx available bugs in 3c574_cs driver.
+-- Fixed ToPIC chipset bug affecting odd-numbered sockets.
+-- Fixed power description coding in pack_cis.
+-- Fixed 'ifuser' to check routes in proper order.
+
+[16-Feb-1999] Version 3.0.9
+-- Moved cardinfo to /usr/X11R6/bin where it belongs.
+-- Added support for 4-socket configurations with I82092AA bridge.
+-- Added D-Link DMF560TX support.
+-- Added command-line options, noninteractive mode to Configure.
+-- Added Justin Seger's roaming support to wavelan_cs driver.
+-- Added do_pci_probe parameter to i82365 module.
+-- Added Configure and Makefile hooks to build tulip_cb and epic_cb
+   drivers using source files from the kernel tree, for 2.2 kernels.
+-- Changed power-up sequencing to use Vpp=Vcc until told otherwise,
+   and fixed serial_cs to handle cards that need Vpp.
+-- Changed memory probe to detect more types of failures.
+-- Changed cardmgr to not load memory card driver for unsupported
+   Cardbus cards, and fixed modules to report unsupported card types.
+   Also added some checks to prevent Cardbus drivers being bound to
+   16-bit cards, and vice-versa.
+-- Tweaked O2Micro bridge initialization to be sure DMA is off.
+-- Added fix for buggy PCI bus enumeration on some Toshiba laptops.
+-- Fixed network script to handle net-tools-1.46 ifconfig output.
+-- Fixed SMP compilation with 2.2-pre9 and later kernels.
+
+[22-Jan-1999] Version 3.0.8
+-- Minor changes in TI and O2Micro Cardbus bridge initialization.
+-- Changed semantics of i82365 cb_bus_base parameter (and put it in
+   the man page).
+-- Added interlock to prevent ide_cs module from being unloaded at
+   inappropriate times.
+-- Changed cardmgr to not shut down busy sockets when it gets SIGTERM,
+   and to only reload config files (and not reinitialize all sockets)
+   when it gets SIGHUP.
+-- Added (untested) support for TI 1251A, 1251B, 1450 Cardbus bridges.
+-- Added support for Psion 56K+10Mb multifunction cards.
+-- Fixed obscure BIOS bug in Cardbus bridge setup on some systems.
+-- Fixed fatal bug in pcinitrd script.
+-- Fixed Adaptec APA1480A support with 2.2.0-pre kernels.
+-- Fixed several configuration problems with 2.2.0-pre kernels.
+-- Fixed another Cardbus hot-eject problem.
+
+[05-Jan-1999] Version 3.0.7
+-- Added DHCP support to network script.
+-- Fixed configure script for 2.2.0-pre kernels.
+-- Cleaned up memory probe algorithm.
+-- Changed i82365 interrupt probe to be less aggressive.
+-- Cleaned up some obsolete cruft for old kernels, in network drivers.
+-- Updated ibmtr_cs driver for 2.1.* kernels, tweaked memory mapping
+   algorithm, and added a man page.
+-- Updated SCSI clients for changes in kernel module support.
+-- Fixed glitch in Configure script reading of kernel config options.
+-- Fixed dumb bug in 3c575_cb driver introduced in 3.0.6.
+-- Fixed compilation under 2.0.* SMP.
+
+[19-Nov-1998] Version 3.0.6
+-- Performance improvements in CardBus bridge setup code.
+-- Minor Xircom driver update.
+-- Updated 3c575_cb driver for 3c575B (3CCFE575) cards, and fixed
+   hot-eject lockup problem.
+-- Improved ifuser (thanks to Regis Duchesne).
+-- Added memory window support to pack_cis.
+-- Added support for 3CCFEM556B cards: still flaky.
+-- Added description of socket driver layer to programming guide.
+-- Added some support for PCI power management specification.
+-- Improved interrupt scan logic, with better fault recovery.
+-- Improved probe logic for PCI host controllers.
+-- Cleaner multifunction card detection logic in serial driver.
+-- Cleaner, simpler IO port configuration logic in pcnet_cs driver.
+-- Stricter alignment rules for CardBus memory windows.
+-- Made the suspend/resume code more systematic about reconfiguring
+   sockets after a suspend.
+-- Accommodated a few RedHat-5.1-isms in install scripts.
+-- Fixed initialization bug in the TCIC socket driver.
+-- Fixed D-Link EtherFast initialization problem.
+-- Fixed startup with an already-inserted CardBus card.
+-- Fixed several ToPIC95 chipset configuration problems.
+-- Fixed IDE driver to retry ide_register() to give slow drives time
+   to spin up.
+-- Fixed Cardbus structure initialization bug.
+-- Fixed 2.1 kernel compiler options for ppc and alpha.
+-- Fixed Cirrus CardBus status interrupt selection bug.
+-- Fixed for 2.1.118-2.1.124 kernels.
+-- Fixed controller option flag mixup in i82365 driver.
+-- Fixed dump_cis bug in multifunction card handling.
+
+[20-Aug-1998] Version 3.0.5
+-- Various minor code cleanups.
+-- Reorganized i82365 header files.
+-- Major redo of dump_cis and pack_cis tools: now they are installed
+   in /sbin, have man pages, and have mostly compatible file formats.
+-- Better O2Micro controller support.
+-- Added memory_cb driver for Cardbus memory access.
+-- Attempt to fix flash driver instabilities.
+-- Workaround for SMP kernel header glitch in late 2.1.* kernels.
+-- Fixed hopefully the last memory probe bug.
+-- Fixed some endian-ness problems in client drivers.
+-- Fixed MTD unloading bug.
+-- Fixed 'cardctl ident' bug with some multifunction cards.
+-- Fixed Cardbus CIS handling and resource management bugs.
+
+[18-Jul-1998] Version 3.0.4
+-- Split "modules" subdirectory: moved client drivers to "clients".
+-- Added "cardctl ident" to display card identification information.
+-- Added /proc/bus/pccard tree for 2.1.105 and later kernels.
+-- Improved option handling in startup script.
+-- Lots of code rearrangement to improve portability.
+-- Fixed 2.0.35 kernel incompatibilities.
+-- Fixed an SMP bug in memory allocation code introduced in 3.0.2.
+-- Fixed kernel build date handling bug in Configure script.
+-- Fixed bug in memory probe logic introduced in 3.0.3.
+-- Fixed bug in VIA controller detection logic.
+-- Fixed bugs in probe tool and added new controllers.
+-- Fix in i82365 module Vpp handling for older controllers.
+
+[27-May-1998] Version 3.0.3
+-- Minor updates to HOWTO, config file, xirc2ps_cs driver.
+-- Removed apparently broken 3V/5V detection for Cirrus controllers.
+-- Fixed procfs bug in Configure script.
+
+[24-May-1998] Version 3.0.2
+-- Updated CardBus support for 2.1.90 and later kernels.
+-- Renamed 'dump_tuples' as 'dump_cis'.
+-- Added SMP spinlock support.
+-- Added '-V' option to cardmgr and cardctl to just show version info.
+-- Added low-level support for socket controllers with unusual memory
+   mapping capabilities, and updated memory card drivers to use it.
+-- Started terminology switch-over from "PCMCIA" to "PC Card".
+-- Fixed cs_irq handling bug in i82365 module.
+-- Fixed bad bug in memory window allocation logic.
+
+[10-May-1998] Version 3.0.1
+-- Adopted Mozilla Public License for all core components, and cleaned
+   up various copyrights and attributions.
+-- Updated skeleton driver to work as generic IO card enabler, renamed
+   as "dummy_cs".
+-- Updated for 2.1.89, 2.1.90, 2.1.94 kernels.
+-- Updated 3c574_cs and 3c575_cb drivers (note new driver name).
+-- Adapted all drivers to not rely on direct mapping of physical to
+   virtual addresses (i.e., the 640K-1MB "hole") for memory windows. 
+-- More HOWTO revisions: added section with info about different Linux
+   distributions.
+-- Made 'cardmgr -v' generate a bit more verbose messages.
+-- Made CIS processing for Cardbus cards much more complete, also
+   fixed host byte order dependencies.
+-- Added Adaptec SlimSCSI 1480 CardBus support.
+-- Added ReplaceCIS service to core modules, and added support for
+   this to cardmgr.
+-- Added support for PCI functional interrupts for IO cards to i82365
+   module, for Cardbus controllers.
+-- Added support for automatic detection of low voltage cards.
+-- Added support for TI 1220 and TI 1250A host controllers.
+-- Added 'SEARCH' parameter to network setup scripts.
+-- Changed iflash2_mtd and iflash2+_mtd timing options to all be
+   expressed in milliseconds for consistency.
+-- Changed pcnet_cs hardware address probe order to fix interference
+   of Linksys EtherFast probe with some clones.
+-- Changed name of ATA/IDE driver from "fixed_cs" to "ide_cs".
+-- Changed i82365 module to use memory mapped registers for CardBus,
+   instead of legacy IO port mode, and to set Cirrus timing registers
+   to sane values if they are zeroed out at startup time.
+-- Fixed voltage scaling bug in ide_cs driver.
+-- Fixed multicast code in fmvj18x_cs driver.
+-- Fixed resource allocation bug in suspend/resume handling for
+   CardBus cards.
+-- Fixed hot eject bug in fmvj18x_cs driver.
+-- Fixed network script to properly detect open connections and NFS
+   mounts on an interface, using the new 'ifuser' utility.
+
+[19-Feb-1998] Version 3.0.0
+-- Added 3c574_cs module.
+-- Major update of HOWTO and programming guide.
+-- Various new sections of code to support Cardbus cards.
+-- Major reorganization of i82365 module and probe logic.
+-- Rewrite of CIS parsing logic to also handle Cardbus cards.
+-- Code cleanup, and switch-over of many things from 'long' to 'int'.
+-- Made the memory and IO probes a bit more conservative.
+-- Updated xirc2ps_cs driver.
+-- Updated pcinitrd: glibc fix, more sanity checks, more verbose.
+-- Updates for 2.1.68, 2.1.76, and 2.1.86 kernels.
+-- Fixed cardinfo to work in "trusted" mode.
+-- Fixed ready/busy status reporting for IO cards.
+-- Fixed interrupts on second serial port for Socket dual-port cards.
+-- Fixed memory_cs access to attribute memory devices.
+-- Fixed smc91c92_cs IO bus width selection.
+-- Fixed bug in Cirrus PD6832 socket addressing.
+-- Fixed bad bug in fmvj18x_cs driver's card setup code.
+-- Fixed version checking for new modutils in Configure script.
+-- Fixed i82365 module to disable zoom-video where appropriate, and to
+   not probe PCI interrupts.
+-- Fixed bug in pcnet_cs driver that breaks 2.1.60 and later kernels.
+-- Fixed bug in wavelan_cs interrupt handling introduced in 2.9.12,
+   and fixed EEPROM checksum bug.
+-- Fixed some 32/64-bit issues that cause trouble on Alpha platform.
+
+[14-Nov-1997] Version 2.9.12
+-- Updated to handle 2.1.60 kernel changes.
+-- Updated the Xircom driver, fixing CEM56 support.
+-- Updated the Wavelan driver
+-- Changed network script to be slightly smarter about when it allows
+   a card to be ejected.
+-- Added O2Micro OZ6832 CardBus and Intel 82092AA PCI support.
+-- Made the memory window scan a bit safer and more reliable.
+-- Fixed smc91c92 driver to work with 91c94-based cards.
+-- Fixed several minor install script bugs.
+-- Fixed bug in partition code in ftl_cs driver.
+-- Fixed bug in multiple-cardbus-controller setup code.
+-- Fixed config file install glitch.
+
+[09-Oct-1997] Version 2.9.11
+-- Fixed Configure script to automatically detect SCSI modules, and to
+   do a better job of figuring out kernel symbol version information.
+-- Config file updates.
+-- Fixed Linksys EtherFast configuration code.
+-- Fixed several 1.2.X kernel incompatibilities.
+
+[25-Sep-1997] Version 2.9.10
+-- Added support for Linksys EtherFast 10/100 network adapter.
+-- Extended ftl_cs driver to support partition tables within an FTL
+   partition.
+-- Updated Werner Koch's Xircom driver, now including CE3 support.
+-- Updated Makefiles to facilitate add-on client drivers, and added
+   automatic dependency handling.
+-- Fixed the fixed-disk driver to deal with 12V cards.
+-- Fixed bug in Macnica SCSI support in the qlogic_cs driver.
+-- Fixed several bad bugs in the memory_cs driver.
+-- Fixed cardmgr to create stab file even if no cards are present.
+
+[10-Sep-1997] Version 2.9.9
+-- Added support for Novell/Eagle NE200 ethernet adapter.
+-- Replaced "irq_mask" module options with more intuitive "irq_list"
+   options.  For compatibility, "irq_mask" will still work.
+-- Fixed several typos, and an event handling bug added in 2.9.8.
+
+[05-Sep-1997] Version 2.9.8
+-- Better module tool version checking.
+-- Merged pcmem_cs driver into memory_cs.
+-- Updates of Xircom Netwave and ethernet drivers
+-- Added support for the Motorola Mariner.
+-- Removed the frequently-misleading card name information from the
+   card information table in pcnet_cs.
+-- Fixed PCI controller probe problem in i82365 driver.
+-- Fixed configuration scripts to still set up proper fstab entries
+   when a filesystem type is not explicitly specified.
+-- Fixed race condition in 3c589_cs driver unload sequencing.
+-- Fixed incompatibilities with both 1.2.* and post-2.1.44 kernels.
+-- Fixed file handling bug in cardmgr with delayed-fork option.
+-- Fixed resume handling bug when suspended cards are ejected.
+-- Various compilation fixes for Alpha platform.
+-- Changed syntax of ReportError service.
+-- Various changes to Card Services interface to accommodate future
+   CardBus card support.
+
+[03-Jul-1997] Version 2.9.7
+-- Added Werner Koch's driver for Xircom ethernet and ethernet/modem
+   adapters.  
+-- Simplified multifunction card handling in the serial driver.
+-- Added code to serial configuration scripts to create entries in
+   inittab if desired.
+-- Changed Cirrus timing parameters to be a bit more conservative.
+-- Made Configure script more bullet-proof.
+-- Changed cardmgr to, by default, try 'modprobe' if 'insmod' fails.
+-- Rewrite of code for memory mapping CardBus controller registers.
+-- Fixed bash-2.0 incompatibility in default network.opts script.
+-- Fixed memory resource parsing bug that messed up memory windows
+   in the upper 2GB.
+-- Fixed some interrupt-picking problems in the i82365 driver, that
+   most directly affected Cirrus controllers.
+-- Fixed glibc header clash in smc91c92_cs driver.
+-- Fixed bug in initialization code for the second socket of CardBus
+   controllers.
+
+[04-Jun-1997] Version 2.9.6
+-- Added stuff to configuration scripts and cardctl so that when the
+   scheme is changed, we only reconfigure devices that need it.
+-- Added an improved memory-scanner that should be able to figure out
+   most memory window position problems without intervention.
+-- Added New Media BASICS Ethernet support.
+-- Cleaned up a lot of debugging code.
+-- Changed output of scsi_info to be more consistent with ide_info.
+-- Update for 2.1.38 and later kernels.
+-- Update for the Wavelan driver.
+-- Improved CIS validation tests.
+-- Relaxed some arbitrary port allocation restrictions on 3c589,
+   pcnet, smc91c92, and xircnw drivers.
+-- Minor improvements to error and informational messages.
+-- More reorganization in i82365 driver.
+-- Fixed bug in multiport serial card configuration.
+-- Fixed bogus cardctl output when a socket isn't bound to anything.
+-- Fixed missing "#include <pcmcia/config.h>" in cardctl.c.
+-- Fixed various minor bugs/typos
+
+[25-Apr-1997] Version 2.9.5
+-- Added support for Quatech quad serial card.
+-- Added "pcinitrd" helper script, info to the HOWTO.
+-- Updated IBM token-ring driver for 2.1.X kernels.
+-- Updated Wavelan driver.
+-- More fixes to i82365 probe code for multiple controllers.
+-- Fixed ancient bug in CIS handling code that broke the 3Com 3c562D.
+-- Fixed bug in SCSI and fixed-disk configuration scripts when the
+   config file describes multiple partitions for one device.
+
+[15-Apr-1997] Version 2.9.4
+-- More kernel version tweaks for 2.1.31 and later kernels.
+-- Fixed network script to *always* shut down an interface at card
+   eject time, whether or not this script turned it on.
+-- Fixed 3c589_cs autodetect code, again.
+-- Fixed i82365 breakage in 2.9.3.
+
+[14-Apr-1997] Version 2.9.3
+-- Reorganized the PCMCIA-HOWTO.
+-- Added a configuration option to allow cardctl, cardinfo to be
+   compiled in "unsafe" mode so non-root users can modify cards.
+-- Added a default path of /bin:/sbin:/usr/bin:/usr/sbin to cardmgr.
+-- Changed card status change interrupt selection algorithm in the
+   i82365 module, to use the same irq for all controllers.
+-- Fixed 3c589_cs transceiver autodetection code.
+-- Fixed Configure script to work with bash-2.0.
+-- Fixed /var/run/stab parsing bug in card configuration scripts.
+
+[21-Mar-1997] Version 2.9.2
+-- Minor updates to docs and config files.
+-- Added new card identification method to cardmgr, based on the
+   MANFID tuple.
+-- Added support for Omega Micro 82C092G PCI-to-PCMCIA controller.
+-- Added code to all network drivers to count bytes sent and received
+   for newer (> 2.1.25) kernels.
+-- Two new flags for cardmgr: '-f' causes it to run in the foreground
+   until any already-inserted cards are configured. '-o' causes it to
+   make one pass at configuring cards, then exit.
+-- Consolidated common device configuration functions into a separate
+   shell script file.
+-- Changed i82365 module to disable dynamic power mode on Cirrus
+   controllers.
+-- Updated to work with latest (post-2.1.17) kernel module code, and
+   various other fixes for 2.1.X kernels.
+-- Rewrite of i82365 module to better handle multiple controllers, and
+   combinations of PCI-to-PCMCIA, PCI-to-Cardbus, and ISA stuff.
+-- Fixed kernel compatibility bug on Alpha systems.
+-- Partly fixed multicast support in New Media ethernet driver.
+-- Fixed smc91c92_cs driver to only make a 10baseT/10base2 switch when
+   an interface is first configured.
+-- Fixed another configuration bug in the Wavelan driver.
+-- Fixed all troubles with Linksys LANmodem multifunction cards.
+-- Fixed problem with retrieving status information from unconfigured
+   or empty sockets.
+-- Fixed all the memory card drivers (memory_cs, pcmem_cs, ftl_cs) to
+   invalidate the buffer cache when a card is ejected.
+-- Fixed Ricoh RL5C466 CardBus controller setup bug.
+
+[23-Dec-1996] Version 2.9.1
+-- Added support for MACNICA and IO-DATA SCSI adapters.
+-- Increased write timeout in iflash2+_mtd driver, and made it a
+   configurable parameter.
+-- New feature in cardmgr to parse PCCARD_OPTS environment variable
+   after the main config file.
+-- Updated serial driver to support Advantech dual serial card, and
+   fixed bug in configuration of second port on dual-port cards.
+-- Fixed bug in PCMCIA shutdown code for systems with SYSV init (well,
+   Red Hat for sure, maybe others).
+-- Fixed major instability in iflash2+_mtd driver.
+-- Fixed bug in Megahertz multifunction card configuration logic.
+-- Fixed difficult-to-trigger bug in cardmgr file descriptor handling.
+-- Fixed some sort of bug in the Wavelan driver.
+-- Fixed bug in probe for TI 1130 CardBus chips.
+
+[28-Nov-1996] Version 2.9.0
+-- Updated for 2.1.X kernels (retaining compatibility with older
+   kernels, of course).
+-- Updated the Wavelan driver.
+-- Reorganized file layout: moved headers to separate include tree.
+-- Added command-line options to cardctl to allow control over
+   file placement, including the scheme file.
+-- Added '-d' flag to cardmgr to use depmod/modprobe for module
+   dependencies.
+-- Added two new timing parameters to pcmcia_core module: resume_delay
+   and reset_delay.  See the man page for details.
+-- Added experimental support for SMC, Cirrus, TI, and Ricoh CardBus
+   controllers (in legacy 16-bit card mode).
+-- Changed cardmgr to log child program output to the system log.
+-- Changed socket drivers to never use irq 12 for monitoring card
+   status changes, to avoid trouble with PS/2 mice.
+-- Changed i82365 driver so that extra_sockets implies poll_status.
+-- Updated probe command to find PCI controllers.
+-- Updated smc91c92_cs driver for SMC EtherEZ cards.
+-- Fixed initialization bug in smc91c92_cs driver.
+-- Fixed IO port allocation bug in the serial driver.
+-- Fixed setup bug in aha152x driver for 1.2.X kernels.
+-- Fixed several bugs and race conditions in card power-up sequencing
+   and resume handling.
+
+[03-Oct-1996] Version 2.8.23
+-- Added 'ide_info' utility so that IDE configuration scripts can
+   look up a card's serial number.
+-- Updated network configuration script to support IPX setup.
+-- Experimental support for Quatech/IOTech dual serial port cards.
+-- Improved the forms library checking in the Configure script.
+-- Updated the fmvj18x_cs driver.
+-- Fixed ftl_cs so that it can handle partitions bigger than 16MB.
+   Also fixed kernel trap problem in the device close code.
+-- Fixed bug in installing startup scripts when an alternate target
+   directory is specified.
+-- Fixed i82365 driver to distinguish between VLSI and i82365SL DF
+   controllers.  Also updated 'probe' command.
+-- Fixed wavelan_cs check for stopped card in interrupt handler.
+
+[29-Aug-1996] Version 2.8.22
+-- Added Wavelan man pages.
+-- Fixed configure problem for DEC Alpha UDB systems.
+-- Fixed missed interrupt problem with simultaneous ethernet/modem
+   operation on Ositech cards.
+-- Fixed bugs in card status interrupt selection in i82365 and tcic
+   modules.
+-- Fixed aha152x_cs driver to compile with 2.0.14 kernels, and also
+   fixed a null pointer dereference in the reset code.
+-- Fixed bug in promiscuous mode selection code in 3c589 driver.
+-- Fixed bug in the TCIC-2 chip identification code.
+-- Fixed Wavelan driver so that the multicast code will only reset the
+   card when the setting actually changes.  Also fixed problems with
+   card eject and driver unloading, increased the xmit timeout, and
+   took out code that forces the card to use a fixed port address.
+
+[06-Aug-1996] Version 2.8.21
+-- Fixed network and serial configuration scripts to do appropriate
+   things when a card is suspended or resumed.
+-- Fixed bug in fsck exit code checking in scsi and fixed-disk
+   scripts.
+-- Fixed cardmgr to correctly report cards in /var/run/stab even if
+   they are not configured, instead of claiming the socket is empty.
+-- Fixed bug in cardinfo device name reporting.
+-- Fixed missing #include in the fmvj18x_cs driver.
+-- Fixed race condition in resume handling that would sometimes cause
+   sockets to be powered down just after a resume.
+-- Fixed bug in Megahertz EM3288 power-up sequence in smc91c92_cs.
+-- Fixed interrupt handling bug in wavelan_cs.
+
+[29-Jul-1996] Version 2.8.20
+-- Updated the Fujitsu ethernet driver to support the TDK LAC-CD02x.
+-- Added Logitec ethernet, Digital Mobile Media CD-ROM to config file
+   and supported cards list.
+-- Cleaned up some if_port handling code in various ethernet drivers.
+-- Fixed bug in cardinfo with newer Forms library.
+-- Fixed wavelan_cs driver to build with 1.2.X kernels.
+-- Fixed two bugs in smc91c92 driver for Megahertz cards.
+
+[19-Jul-1996] Version 2.8.19
+-- Added support for IBM "KING" PCIC, added decoding of TCIC-2 chip
+   revision codes to tcic module and probe command.
+-- Added DO_FSCK flag to all configuration scripts that can mount
+   filesystems (scsi, fixed, memory, ftl).
+-- Added do_scan parameters to i82365 and tcic modules, to allow
+   blocking the normal interrupt scan.
+-- Added code to cache CIS information, for cards whose CIS is not
+   readable once they are configured.
+-- Added AT&T WaveLAN version 2.0 driver.
+-- Added support for Megahertz 1144 and 3288 ethernet/modem cards.
+-- Fixed exit status values in cardctl.
+-- Fixed bug in suspend/resume handling for Ositech multifunction
+   cards (and maybe some others).
+
+[26-Jun-1996] Version 2.8.18
+-- Added support for new revision of Vadem VG469 host controller.
+-- Added Xircom Netwave driver.
+-- Added Micronet EtherFast, 3Com 3c689 token ring, and Trimble GPS
+   card to supported cards list.
+-- Fixed serial_cs driver to handle some quirky modem cards with
+   deceptive CIS information.  This should fix the Compaq 192.
+-- Fixed interrupt release bug with multifunction cards.
+-- Fixed scsi, fixed-disk config scripts to respect DO_FSTAB flag when
+   removing entries from /etc/fstab.
+-- Fixed network script to ignore inactive connections when checking
+   network status.
+-- Fixed stupid bug in smc91c92_cs driver that broke Ositech
+   multifunction cards.
+
+[11-Jun-1996] Version 2.8.17
+-- Added code to check for spurious APM suspend/resume events.
+-- Changed serial_cs driver to be more aggressive about finding IO
+   ports for modems when the standard locations are all unavailable.
+   Also changed the device name passed to cardmgr from the 'cua'
+   device to the 'ttyS' device.
+-- Changed serial device script to expect 'ttyS' device names, and to
+   create device files if needed.
+-- Changed network drivers to do more checking of if_port values.
+-- Fixed Configure script to recognize 2.0 kernels.
+-- Fixed probe.c and dump_i365.c to use the same probe logic as the
+   i82365 module.
+-- Fixed mistake in the fix for the qlogic_cs driver for pre-2.0.
+-- Fixed interrupt allocation bugs in smc91c92_cs.c and pcnet_cs.c
+   that goofed up Ositech and Linksys ethernet/modem combo cards.
+
+[02-Jun-1996] Version 2.8.16
+-- Added 'ifport' command for selecting transceiver types for network
+   adapters.  Also cleaned up all the transceiver selection code in
+   the various network drivers, and updated the HOWTO.
+-- Added support for Linksys ethernet/modem multifunction card.
+-- Cleaned up timer handling code in all the modules, for better
+   platform independence.
+-- Added priority coding to all module printk()'s.
+-- Moved /etc/stab to /var/run/stab for consistency.
+-- Changed CIS parsing to tolerate errors in long link tuples.  This
+   should fix the New Media Net Surfer.
+-- Fixed modules/Makefile to work with pre-2.0.6 kernel.
+-- Fixed several bugs in the card status interrupt allocation code in
+   the i82365 module, for supporting multiple controllers.
+
+[15-May-1996] Version 2.8.15
+-- Updated Configure to handle 1.99.* (i.e., "pre-2.0") kernels.
+-- More changes to the socket-ignoring code.
+-- Added support for 3Com 3c562B, and Motorola Marquis cards.
+-- Fixed more SCSI problems with 1.3.98 and later kernels.
+-- Fixed Ositech problem in smc91c92_cs module.
+
+Version 2.8.14
+-- Changed the socket-ignoring code so now it should work properly.
+-- Cleaned up some of the resource manager code.
+-- Added smc91c92_cs driver, for SMC, Megahertz, and Ositech ethernet
+   adapters.
+-- Updated serial_cs to handle quirky Ositech multifunction cards.
+-- Fixed incompatibility with 1.3.98 and later kernels.
+-- Fixed bug in error reporting in cardmgr's config file parsing code,
+   and fixed bug in config file.
+
+[25-Apr-1996] Version 2.8.13
+-- One more fix for 1.2.X kernels.
+-- Added Fujitsu FMV-J181, FMV-J182 ethernet driver.
+-- Added mention of CONFIG_TR to HOWTO, also fixed Configure script
+   and modules/Makefile to check for this before building ibmtr_cs.o.
+-- Changed core drivers so that if a socket contains a card that is
+   already active when CS is loaded, it will be left alone... this
+   should remove the need to use "ignore" with the socket drivers.
+-- Fixed bug in debug flag handling in modules/Makefile.
+-- Fixed modem support for IBM Home and Away Adapter.
+
+Version 2.8.12
+-- Minor cleanup of multifunction card support.
+-- Added more CIS tuple definitions.
+-- Fixed (hopefully) the last 1.2.X kernel compatibility bug.
+
+[05-Apr-1996] Version 2.8.11
+-- Minor updates to config file.
+-- Changed the pcnet_cs, ibmtr_cs, memory card drivers, and socket
+   drivers to be architecture independent, for DEC Multia.
+-- Fixed to work with 1.2.X kernels again.
+
+[01-Apr-1996] Version 2.8.10
+-- Added New Media Toast & Jam SCSI-only support.
+-- Added Panasonic KXL-D740 to supported cards.
+-- Added a new header file, ciscode.h, to keep track of manufacturer
+   and product ID codes.
+-- Updated pcnet_cs to support the Longshine Ethernet card.
+-- Updated pcnet_cs and serial_cs to work with IBM Home and Away Card.
+-- Changed CIS handling code to work with the DEC Multia.
+-- Changed network scripts to handle NFS mounts.
+-- Fixed serial_cs to use ASYNC_SKIP_TEST: some PCMCIA modems don't
+   pass the test, and it was always skipped for pre-1.3.72 kernels.
+-- Fixed risky parsing code in fixed_cs driver.
+-- Fixed error reporting bug in ibmtr_cs.c, added token-ring port
+   range to config.opts.
+-- Fixed bugs in rc.pcmcia shutdown and cleanup code.
+-- Fixed two Future Domain/IBM SCSI typos.
+-- Fixed another rare CIS parsing bug.
+-- Fixed flags for Epson ethernet in pcnet_cs.
+
+[13-Mar-1996] Version 2.8.9
+-- Updated for kernels up to and including 1.3.73.
+-- Made some drivers a bit less verbose.
+-- Changed PCMCIA startup script to clean up old devices after an
+   unclean shutdown.
+-- Moved /tmp/.pcmcia-scheme to /var/run/pcmcia-scheme
+-- Added IBM SCSI and Future Domain SCSI2GO support.
+-- Added IBM Token Ring support.
+-- Added config entries for Accton 2216, CNet CN40BC, Epson ethernet,
+   Raven CD-Note.
+-- Added true simultaneous ethernet/modem support for the 3c562 with
+   1.3.73 and later kernels.
+-- Fixed scsi script to not complain about nonexistent device files
+   when shutting down devices.
+-- Fixed bug in cardmgr SCSI disk device name handling.
+-- Fixed bug in Configure script for 1.3.49 kernel with SCSI support.
+-- Fixed bug in nmclan_cs.c with 1.3.X kernels.
+-- Fixed umask bug in cardctl.
+-- Fixed obscure bug in CIS parsing for IO windows.
+-- Fixed ATA/IDE driver to be more flexible about choosing IO ports.
+-- Fixed race condition in 3c589_cs transceiver detection code, also
+   fixed "missed interrupt" problem.
+
+[11-Feb-1996] Version 2.8.8
+-- Made the scheme stuff more secure.
+-- Fixed serial driver to work better with 3c562... see HOWTO.
+-- Faster and better transceiver autodetection for 3c589 cards.
+-- Fixed debug-tools/Makefile to work when CFLAGS is set in the
+   environment.  
+-- Fixed kernel version parsing bug in Configure script.
+-- Fixed bug with unmounting multiple partitions in the "scsi" and
+   "fixed" device scripts.
+-- Fixed modules/Makefile to include dependencies for objects built
+   from source code in the Linux kernel tree.
+
+[28-Jan-1996] Version 2.8.7
+-- Added NDC Instant-Link support.
+-- Fixed 3c589 transceiver selection problem, probably.
+-- Fixed bug in modules/Makefile with fixed_cs.o module.
+-- Fixed bug in cardmgr "resume" processing.
+-- Fixed network script to shut down BOOTP setups properly, and to
+   handle some more special cases.
+
+[25-Jan-1996] Version 2.8.6
+-- Cleaned up Makefiles.
+-- Changed the default debug level in nmclan_cs to 2, and got rid of
+   the "checking if_port..." messages in 3c589_cs.c.
+-- Changed i82365 module to only probe for additional controllers if
+   the "extra_sockets" parameter is set.
+-- Added Kingston, SCM address signatures to pcnet_cs.c.
+-- Added "beta" IDE/ATA driver.
+-- Fixed cardctl to have some functionality for non-root users.
+-- Fixed scsi_info to compile with 1.2.X kernels.
+-- Fixed the device scripts to set scheme to "default" if it is unset,
+   and changed cardctl to do the same.
+
+[16-Jan-1996] Version 2.8.5
+-- Tweaks for kernels up to 1.3.57.
+-- Modified device scripts to grab more info from /etc/stab.  Now, all
+   the device scripts pass an "address" to the corresponding option
+   script, which can be used to tailor the configuration of specific
+   devices.
+-- Added support for multiple PCMCIA configuration "schemes", such as
+   home and work.  There is an example in the HOWTO.
+-- Added 'scsi_info' utility for looking up SCSI device information,
+   used by the SCSI device config script.
+-- Added automatic transceiver detection to 3c589_cs.
+-- Added "do_sound" parameter to serial driver, so that the speaker
+   can be turned off if desired.
+-- Extended config file syntax so that config.opts can specify extra
+   parameters for kernel modules.  So, now, all local info should be
+   in config.opts, and the main config file should be completely
+   general.
+-- Changed i82365 and tcic drivers to automatically poll for card
+   status changes when interrupts are scarce.
+-- Fixed reset problem in New Media ethernet driver.
+-- Fixed error reporting bug in pcnet_cs.
+-- Fixed bug in i82365 socket counting code for systems with just one
+   socket.
+
+[28-Dec-1995] Version 2.8.4
+-- Added support for DataTrek NetCard, config entry for Megahertz
+   V.34 modem.
+-- Added '00 04 ac ...' signature for IBM cards to pcnet_cs driver.
+-- Added 'scsi.opts' file, where 1.2.X kernel users can list SCSI
+   devices that should be checked when unloading SCSI adapters.
+-- Added more configuration options to network.opts, serial.opts.  The
+   network script now handles bootp, and nameserver configuration.
+-- Added a sanity check for results of the automatic IO port probe.
+-- Changed the installation for SysV-type setups to use /etc/pcmcia
+   like everybody else, instead of /etc/sysconfig/pcmcia-scripts.
+-- Changed etc/Makefile to only update /etc/pcmcia stuff that has
+   actually changed.
+-- Changed rc.pcmcia so that there are new PCIC_OPTS and CORE_OPTS
+   environment variables for customization.
+-- Worked around 'insmod' bug: 'symbol=value' stuff silently fails
+   when another symbol is a longer version of the intended one.
+-- Fixed bug in cardmgr, where it would only recognize the first
+   device associated with a particular driver module.
+-- Fixed up memory_cs to work better with static RAM cards.
+-- Fixed possible kernel stack overflow problem in pcmem_cs module.
+-- Fixed bug in cardmgr include-file handling, which caused re-loading
+   the config file to fail.  Also fixed error recovery.
+-- Fixed bug in modules/Makefile that causes compiling the patched
+   aha152x driver to fail.
+-- Fixed 3c589_cs driver's card recognition check.
+-- Fixed bug in dump_tuples and dump_cisreg that left extra device
+   files hanging around in /tmp.
+
+[20-Dec-1995] Version 2.8.3
+-- Fixed bug in Configure script, common symptom was deciding that
+   CONFIG_MODVERSIONS was set when it wasn't.
+
+[19-Dec-1995] Version 2.8.2
+-- Added '00 20 af ...' address signature to 3c589_cs driver.
+
+[18-Dec-1995] Version 2.8.1
+-- A few dumb typo fixes.
+-- Extended config file format to support nesting files, split the
+   config file, and the network and serial scripts into generic and
+   local options.
+-- A fix for the New Media ethernet slowdown problem?
+
+Version 2.8.0
+-- New way of passing device info from client drivers to cardmgr, to
+   better support cards that may have several logical devices (i.e.,
+   SCSI, multiport cards, etc).
+-- Modified SCSI clients to identify attached devices, for 1.3.X
+   kernels.
+-- Modified ftl_format to support reserving space for a boot image.
+-- Added code to automatically identify resource conflicts for IO and
+   memory windows.  Memory checking is not reliable, and disabled by
+   default.  
+-- Simplified the config file format, updated all the device control
+   scripts.  Added new script for managing SCSI adapters.  The new
+   scripts can determine if it is safe to remove a card, for all
+   supported card types.
+-- Fixed the eject request code so that it correctly rejects requests
+   when a device is in use.
+-- Changed shutdown code to make sure sockets are deactivated.
+-- Modified dump_tcic and dump_i365 to compile with Borland C++ under
+   MS-DOS.
+-- Added Allied Telesis Ethernet support.
+-- Fixed module version checking problems with 1.3.39 and 1.3.40.
+   Updated multicast stuff in 3c589 and nmclan drivers for 1.3.44.
+   Tested with 1.3.43 and 1.3.45.
+-- Fixed bug in i82365 interrupt probe that caused the probe to goof
+   up after a warm boot.
+-- Fixed bug in i82365 socket probe code.
+-- Fixed install procedure to handle Debian startup script layout, and
+   fixed a bug affecting installs for System V style init scripts.
+-- Fixed pcnet_cs driver to respect CIS config entries for cards that
+   seem to have valid info (fixes Grey Cell Ethernet).
+-- Fixed Qlogic driver to support Eiger SCSI adapter.
+-- Fixed Configure script and Makefiles to handle multi-word options
+   properly.
+-- Fixed 3c589 driver to refuse to bind to non-3Com cards.
+-- Working on interrupt sharing for multifunction cards.
+
+[21-Nov-1995] Version 2.7.6
+-- Fixed resource allocation bug that affected IO port availability
+   after restarting cardmgr.
+-- Fixed typo in qlogic_cs module initialization.
+-- Fixed "kfree of non-kmalloced memory" bug associated with "flushing
+   pending setup".
+-- Fixed a bug in SCSI driver unloading.
+
+[11-Nov-1995] Version 2.7.5
+-- Made the configuration procedure a little more bullet-proof.
+-- Fixed bug in module version support for 1.2.X kernels.
+
+[10-Nov-1995] Version 2.7.4
+-- Fixed 3Com 3c562 support in serial_cs and 3c589_cs.
+-- Fixed infrequent bug in alignment logic for IO and memory windows.
+-- Fixed various kernel incompatibilities, tested with 1.3.37 through
+   1.3.39.
+-- Fixed sizing bug in pcmem_cs.
+-- Fixed memory window setup bug in the TCIC-2 driver.
+-- Made the serial card driver slightly better at dealing with cards
+   with not-quite-right CIS info.
+-- Revamped some of the module startup code, to facilitate optionally
+   linking stuff into the kernel.
+
+[16-Oct-1995] Version 2.7.3
+-- Changed default bus timing in i82365.c to 8.33 MHz.
+-- Fixed i82365 driver to deal with VG-469 3V/5V decision.  Also
+   changed probe logic to do a better job with docking stations.
+-- Updated pcmem driver.  Added write for char device, fixed up
+   seeking, etc, thanks to Don Wanigasekar.
+-- Changed pcnet driver to support reading the PROM to get a network
+   card's station address.  Verified with Linksys v2.00 card.
+-- Added support for multifunction cards that conform to the PC Card
+   95 standard.  3Com 3C562 almost works.
+
+Version 2.7.2
+-- Consolidated most kernel version differences in "k_compat.h".
+-- Replaced de650 and ibmcc drivers with merged "pcnet" driver.  Note
+   that people will *have* to update their config files...
+-- Changed cardmgr to only load MTD's for memory-related drivers.
+-- Updated i82365.c to handle Vadem VG-469 controller, and to wake up
+   Cirrus chips after a suspend.
+
+Version 2.7.1
+-- Fixed typo in toaster_cs driver.
+-- Fixed module unloading in network drivers.
+-- Fixed problem with new timer behavior in 1.3.X.
+
+[22-Sep-95] Version 2.7.0
+-- New interactive configuration procedure.
+-- Updated to work with 1.3.X kernels.
+-- Fixed iflash2_mtd driver to work with IBM flash cards.  Added more
+   config entries for IBM, Maxtor flash cards.
+-- Fixed module building so that CONFIG_MODVERSIONS should work for
+   all drivers, including the SCSI drivers.
+-- Fixed New Media Ethernet reset bug.
+-- Added stuff to cardmgr to support user specified actions during
+   suspend and resume processing.
+-- Changed Makefile to build 8390.o on the fly.
+-- Fix to toaster_cs for CIS parsing problem.
+
+[10-Aug-1995] Version 2.6.3a
+-- Fixed dumb bug in de650_cs driver.
+
+Version 2.6.3
+-- Another fix for 'kill -HUP' cardmgr.
+-- More flash, FTL fixes.  Better error recovery in iflash2_mtd.
+   Added man pages for ftl_format and ftl_check.
+-- Added support for "hardwiring" the hardware addresses for de650
+   type cards, if they can't be probed properly.
+-- Fixed "too much work..." problem with de650-type cards.
+-- Cleaned up suspend/resume a bit?
+-- First attempt at Adaptec/Trantor T460 driver.
+-- Changed interrupt scanning rules in i82365 and tcic drivers.  Now,
+   both drivers accept irq_mask and cs_irq parameters.
+-- Changed CS, cardinfo to properly update Vcc, Vpp for memory cards.
+-- Added support for Caldera installation.
+-- Added code to 'checkme' and modules/Makefile to decide whether or
+   not to try building the t460_cs module.
+-- Added test to cardinfo to make sure it is setuid root.
+-- Took out some warnings about conflicting CIS tuples for memory
+   regions.
+
+Version 2.6.2
+-- Streamlined install procedure; moved etc stuff into separate
+   subdirectory.
+-- First draft of Flash Translation Layer module, and FTL formatting
+   tools (ftl_format, ftl_check).
+-- Fixed bug in resource allocation that sometimes causes bad things
+   to happen when unloading modules or when restarting cardmgr.
+-- Updated Roger Pao's New Media ethernet driver to v0.14.
+-- Changed pcmem_cs to use memcpy() for block reads and writes.
+-- Changed de650_cs to use larger packet buffer on Socket EA cards.
+-- Fixed cardmgr 'kill -HUP' behavior.
+-- Updated some man pages.
+
+Version 2.6.1
+-- Changed 'checkme' and docs to ask for kernel 1.2.8.
+-- Fixed bug in modules/Makefile
+-- Fixed bug in module version mismatch reporting.
+-- Fixed a couple of minor bugs in cardmgr.
+-- Fixed uninitialized variable bug in CIS parsing stuff in network
+   drivers.
+
+[12-May-95] Version 2.6.0
+-- More robust handling of some i82365 timing parameters.
+-- Moved all CIS handling stuff from cs.c to cistpl.c.  Added more CIS
+   parsing, mainly for memory cards.  Changed default for "strict_cis"
+   to "off".
+-- Moved all the resource management stuff into rsrc_mgr.{c,h}, merged
+   with the old mem_region.{c,h}.
+-- Added cs_internal.h for stuff shared between parts of pcmcia_core.
+-- Added support for Memory Technology Drivers.  Added new sram_mtd,
+   also added generic MTD-aware memory card driver, 'memory_cs'.
+-- Added MTD stuff to Programmer's Guide.
+-- Fixed bug in CS that prevented clean unloading of drivers that use
+   memory windows.
+-- Changed i82365 module to detect Vadem chip in Vadem-Rev mode.
+-- Added MTD's for Intel Series 2 and Series 2+ Flash.
+-- Incorporated recent updates to Linux NE2000 driver into de650_cs
+   driver.
+-- Fixed bad uninitialized variable bug in pcmem_cs.
+-- Added config entry for Adaptec APA-1460 SlimSCSI.
+
+Version 2.5.6
+-- Fixed rc.pcmcia so that "stop" doesn't bomb if you're not running
+   cardinfo.
+-- Added back a few modem config entries.
+-- Added version checking to all PCMCIA modules and utilities.
+-- Fixed bug in i82365 socket counting code.
+-- Fixed 'checkme' and HOWTO to give better info about version.h,
+   added more network checks, better formatting.
+-- Clarified NE2000 instructions in HOWTO.
+-- Added support for KCI PE-520 Ethernet.
+-- Fixed bug in pcmem driver that could cause the first byte of a card
+   to get scrambled.
+
+Version 2.5.5
+-- Added function-based card identification to cardmgr.  Deleted all
+   modem card entries from standard config file.
+-- Added 'strict_cis' parameter to pcmcia_core module to control
+   strict CIS parsing rules (default is turned on).
+-- Changed power-up sequence: reset will only be asserted after
+   vcc_settle, reset timing tweaked to conform to standard.
+-- Fixed bugs in suspend/resume losing track of socket state.
+-- Added definitions for Ricoh controllers.
+
+Version 2.5.4
+-- Fix for CIS long link tuple handling.
+-- Fixed CIS config table parsing bug in parse_irq().
+-- Changed cardmgr so that wildcard product strings will match
+   not-present strings.
+-- A few new sanity checks for 'make prereq' and 'make install-etc'.
+
+[03-Apr-95] Version 2.5.3
+-- Another fix to cistpl.c version string parsing.
+-- Another fix to CIS end-of-chain handling.
+
+Version 2.5.2
+-- Changed cistpl.c to accept some non-conforming version tuples.
+-- Duh, took floating point code out of kernel modules.
+
+Version 2.5.1
+-- Fixed bug in 'cardinfo' updating of device info.
+-- Changed defaults in i82365 module to disable irqs 12 and 15 for
+   Cirrus chips.  Also made interrupt scans more robust, and fixed
+   probe for two controllers.
+-- More module unloading bugs fixed (ethernet, scsi modules).
+-- Fixed a couple of minor bugs in Makefiles, etc.
+-- Added more extensive CIS parsing, improved dump_tuples, added long
+   link handling.  Some error responses may have changed.
+-- Changed 'attr_speed' parameter to 'cis_speed', since code now also
+   handles CIS stuff in common memory.  Default changed to 300 ns.
+-- Added text to the Programmer's Guide describing new CIS stuff.
+-- Fixed suspend/resume problem where an empty socket isn't set up
+   properly after a resume.
+-- Fixed race condition in socket initialization that could sometimes
+   cause a card to be configured twice.
+
+[22-Mar-95] Version 2.5.0
+-- Verified with Linux 1.2.0
+-- Added a lot of new text to the Programmer's Guide.
+-- Added Roger Pao's alpha driver for New Media Ethernet.
+-- Added %c% substitution for 'cardmgr' start/stop commands, to map to
+   the card name.
+-- Rewrote Driver Services event handling to deal with more than one
+   reader.  Rewrote handing of eject requests so that cardmgr can
+   clean up before a card is shut down.
+-- Added event report window to 'cardinfo' display.  Made 'cardinfo' a
+   setuid program so that regular users can run it to get status info,
+   but not modify sockets.  Added file locking to /etc/stab.
+-- Changed socket initialization sequence to conform to PCMCIA docs;
+   should fix Megahertz 2144 modem and some suspend/resume problems.
+-- Changed interrupt mask code in i82365 and tcic to probe for working
+   interrupt lines at startup time.  Added ability for tcic driver to
+   use irq 11.
+-- Fixed 'checkme' to do more SCSI option sanity checking, and to look
+   in $LINUX/include/linux instead of /usr/include/linux.
+-- Fixed module unloading bugs in toaster_cs and qlogic_cs.
+-- Fixed bug in /etc/stab updating at card removal.
+-- Fixed Vpp display bug in cardinfo.
+-- Fixed power setting bug in GetSocket in i82365.
+-- Fixed serial_cs shutdown bug for case of two modems.
+
+Version 2.4.9
+-- Minor fixes to HOWTO, Programmer's Guide.
+-- Included missing man pages for cardinfo, stab.
+
+Version 2.4.8
+-- Added Maxtech Ethernet support.  Added text to HOWTO for how to add
+   support for any NE2000-compatible card.
+-- Fixed serial driver suspend bug, but it is still goofy.
+-- Added status beeps to cardmgr.
+-- Fixed Makefiles to include ${LINUX}/include, to better support
+   systems with more than one Linux source tree.
+-- Made 'cardinfo' tool part of distribution.
+-- New man pages for /etc/stab, cardinfo.
+
+Version 2.4.7
+-- Changed cardmgr to use uname() instead of /bin/uname.
+-- Moved cardmgr PID file from /var/pid to /var/run.
+-- Changed 'checkme' script to also work with ksh.
+-- Overhaul of suspend/resume and reset event handling.  Goal is to
+   fix trouble with cards not waking up after resume.
+-- Added some more tests to 'checkme'; now it creates 'xtra.options'
+   to hold extra Makefile settings.
+-- Changed Makefile to autoconfigure rc.pcmcia using 'probe -m'.
+-- Added '/etc/stab' file output to cardmgr to hold current card info.
+-- Added more interlocks to shutdown code in de650_cs.
+-- Updated Qlogic driver for 1.1.93, for rev 1.10 card.
+
+Version 2.4.6
+-- More fixes for Socket EA card, that should also fix Accton file
+   transfer problems.  Added 'delay_time' parameter to de650_cs.
+-- Fixed reset code for Compaq modem.  New 'reset_time' parameter for
+   pcmcia_core module.  Changed default reset timing parameters.
+
+Version 2.4.5
+-- Added support for EP-210 Ethernet
+-- Fixed Socket EA card, for real!
+
+Version 2.4.4
+-- Changed Bus Toaster driver to use CIS tuples to pick IO addresses.
+-- Added 'wakeup' parameter to i82365 module for sleepy Cirrus chips.
+-- Fixed minor Makefile bugs.
+-- Fixed bugs in de650_cs for Socket EA card.
+-- Added 'mem_speed' parameter to ibmcc_cs module.
+
+Version 2.4.3
+-- Fixed bug in PCI controller handling in i82365 module.
+-- Changed qlogic module to support turbo DMA.
+-- Increased tuple buffer in serial_cs for Toshiba V.34 modem.
+-- Added 'eject' and 'insert' commands to cardctl.
+-- Disabled Bus Toaster driver by default, since it is broken.
+-- Changed rc.sample to rc.pcmcia, added 'start' and 'stop'.
+-- Fixed interlocks between socket drivers and pcmcia_core.
+
+Version 2.4.2
+-- Fixed several bugs in Qlogic, Bus Toaster SCSI drivers.
+
+Version 2.4.1
+-- Fixed bug in TCIC-2 bus sizing code.
+
+Version 2.4.0
+-- Changed default spot for cardmgr pid file to /var/pid/cardmgr.pid
+   to conform to Linux standards.
+-- Converted FAQ to linuxdoc-sgml HOWTO format.
+-- More fixes for reset handling in cardmgr.
+-- 'cardctl status' will now report if a socket is suspended.
+-- When cardmgr gets a SIGHUP, it will reload the config file.
+-- Changed i82365 driver to handle multiple controllers better.
+-- Replaced old 'exclude=' options in i82365 and tcic with new
+   'ignore=' option to specifically ignore any one socket.  The old
+   option ignored sockets starting from 0.
+-- Cleaned up resource management stuff in cardmgr, so that SIGHUP
+   will work properly, and no more "could not adjust resource" stuff.
+-- Fixed some device locking bugs in the memory card driver.
+-- Fixed small memory leak in CS resource handling.
+-- Wrote Programmer's Guide.
+-- Small fixes in cs.c and 3c589 driver for very fast systems.
+-- Added 'checkme' script and 'make prereq' target to check system for
+   PCMCIA prerequisites.
+-- Fixed up module handling in cardmgr for dealing with several cards
+   of the same type.
+-- Got rid of CONFIG_APM and CONFIG_PCI options -- they will be set
+   automatically using /usr/include/linux/autoconf.h.
+-- Updated for 1.1.85 kernel.
+-- Fixed up Qlogic, Bus Toaster SCSI drivers.
+-- Kernel modules now installed under /lib/modules/<rev>/pcmcia.
+   Updated cardmgr to use the new module location.
+-- Changed cardmgr to bind anonymous card driver to unsupported cards
+   whenever possible.
+-- Added more timing controls to i82365 and tcic modules.  Implemented
+   AccessSpeed for memory windows.  Added attr_speed and io_speed
+   parameters to pcmcia_core module.
+-- Added IO window attribute IO_DATA_WIDTH_AUTO for auto-sizing IO
+   windows.
+
+Version 2.3.9
+-- Changed default compile options for modules to include "-g".
+-- Added 'reset' command to cardctl.  Made cardmgr more sensible about
+   dealing with failed resets.
+-- Added device locking to pcmem_cs driver for "clean" suspend/resume.
+-- Cleaned up network driver shutdown code -- fixed "device still
+   locked" message when drivers are unloaded.
+-- Fixed memory card size determination algorithm so that it doesn't
+   return garbage for I/O cards.
+-- Cleaning up spurious interrupts when net cards are ejected: a new
+   patch for 8390.c.
+
+Version 2.3.8
+-- Fixed bug in 3c589_cs.c that prevented clean unloading.
+-- Fixed 3c589_cs.c to work with 3c589B cards.
+
+Version 2.3.7
+-- Fixed bad bug in tcic.c.
+
+Version 2.3.6
+-- Fixed 'exclude' bug in i82365
+-- Update for Linux 1.1.72.
+-- Replaced 'status' with new 'cardctl' utility.  Added options for
+   suspending and resuming individual sockets.
+-- Added RPTI ethernet support.
+-- Added stuff to i82365 and tcic modules to fix interrupt selection.
+   Also added flags for Cirrus controllers with optional features like
+   status LED's, ring indicate, and DMA.
+
+Version 2.3.5
+-- Fixed ifconfig problem in 3c589 driver.
+-- Fixed up PCI support some more.
+-- Fixed i82365 to handle VLSI with > 1 socket
+-- Changes for APM support.  These include revamping the socket setup
+   stuff in i82365 and tcic, and adding event handling to all clients.
+-- Changes for Qlogic SCSI support
+
+[15-Nov-94] Version 2.3.4
+-- Added support for Cirrus PCI controller.
+-- Cleaned up serial driver shutdown code.
+-- Added 'patches' subdirectory for useful kernel patches.
+-- Added PCMCIA-FAQ
+-- Added 'exclude=#' parameter to i82365 and tcic modules to better
+   accommodate cards with point enablers.
+-- Fixed bug in dump_tcic -- mode register wasn't read correctly.
+-- Fixed TCIC-2 event handler problem
+
+[08-Nov-94] Version 2.3.3
+-- Fixed some TCIC-2 bugs.
+
+Version 2.3.2
+-- Changed i82365 so if it is limited with a 'sockets=#' option, it
+   will never touch any higher numbered socket -- for SCSI drivers
+   with point enablers.
+-- More debugging code in i82365, tcic modules.
+-- Added stuff to 'cardmgr' to maintain a /etc/pcmcia/cardmgr.pid file.
+-- Fixed blocksize problem, module unloading bug in pcmem_cs driver.
+-- Fixed bug in cardmgr 'kill -HUP' handling (actually in Card Services)
+
+Version 2.3.1
+-- Fixed TCIC-2 polling bug.
+
+Version 2.3
+-- Major rewrite of low-level i82365 and tcic driver interface.  Card
+   status polling put in the low level drivers instead of pcmcia_core.
+-- Rewrite of low-level card status event handling.
+-- Better TCIC-2 register dump utility.
+-- DMA and speaker output control for TCIC-2, Cirrus controllers.
+-- Added signal handling to cardmgr
+-- Checked with 1.1.61 kernel.
+
+Version 2.2.10
+-- Small fix in Vadem probe code.
+-- Fix for New Media hardware address probe.
+-- Cleaned up memory window handling in Card Services.
+-- Added a heavily-commented "skeleton" client driver
+
+Version 2.2.9
+-- One more VLSI controller fix.
+-- Accton and New Media ethernet support merged into de650 driver.
+
+Version 2.2.8
+-- Fixed handling of second socket with VLSI controller.
+-- Fixed event handling bug in ibmcc and pcmem drivers.
+
+Version 2.2.7
+-- Added TCIC_SCF2_IDBR fix to tcic.c.
+-- Fixed bug in 3c589 interrupt handler.
+
+Version 2.2.6
+-- Changed distribution to include lex and yacc output files.
+-- Added support for Vadem VG-468 controller.
+-- Changed i82365 code to support suspend/resume (sometimes, anyway).
+-- Fixes in TCIC-2 autodetect and event handling.
+-- Updated 3c589_cs driver to parallel changes to 3c509 driver.
+-- Changed all client drivers so they can be manually unloaded as long
+   as their devices are not in use.
+-- Working on Accton EN2212 driver.
+-- Checked with 1.1.54 kernel.
+
+Version 2.2.5
+-- Fixed event mask bug in ibmcc_cs, socket numbering bug in i82365.
+
+Version 2.2.4
+-- Changed cardmgr to handle modules that take parameters.
+-- Minor cleanups of Makefiles.
+-- Better error handling for all Card Services stuff.
+-- Minor improvements in debug tools.
+-- Small fix in 3c589_cs driver.
+-- Checked with 1.1.51 kernel.
+
+Version 2.2.3
+-- Added 'expert' flag (-x) to probe -- this does a somewhat risky but
+   thorough search for a TCIC-2 chip.  But, it doesn't work yet.
+-- Fixed bug in CS that prevented clean unloading of modules.
+-- Fixed 'kmalloc called nonatomically' bug in ibmcc_cs.
+-- Added extra test to i82365 to fix socket counting for some clones.
+-- Added write protect test to memory card driver.
+-- Man pages for cardmgr, config file, and drivers!
+-- Changed default config script to automatically link /dev/modem to
+   a modem or serial card.
+
+Version 2.2.2
+-- Added 'anonymous' card type to cardmgr, so that cards with no CIS
+   information can be bound to the memory card driver.
+
+Version 2.2.1
+-- Checked with 1.1.49.
+-- Minor install bug fixes.
+
+[30-Aug-94] Version 2.2
+-- Cleaned up README's
+
+Version 2.1.4
+-- Added 'poll_delay' parameter to tcic module to control busy loop.
+-- Checked against 1.1.48.
+-- Fixed the shared-memory IBM CCAE driver.
+-- Removed (broken) IBM CCAE support from DE650 driver.
+-- Better Cirrus PD67xx register dumping in dump_i365
+-- Minor improvements to trim down module sizes
+
+Version 2.1.3
+-- Added preliminary shared memory driver for IBM CCAE cards.
+
+Version 2.1.2
+-- Added setup of "misc" register for IBM CCAE cards.
+-- Cleaned up header files.
+-- Fixed pcmem_cs for 1.1.47.
+
+Version 2.1.1
+-- Fixed network setup bug in config.sample.
+
+Version 2.1
+-- Checked against 1.1.46
+-- Added memory card driver, pcmem_cs, providing character and block
+   devices for accessing PCMCIA card memory.
+-- Moved cardmgr from /usr/sbin to /sbin.
+-- Added 'sockets' parameter to i82365 for systems where the probe
+   does not give the right answer.
+-- Added support for memory windows to CS.
+-- Working on support for IBM CCAE in de650_cs.c.
+-- Changed ds.c to relay major and minor device #'s as well as device
+   names; now cardmgr can create device files on the fly.
+-- Changed tcic driver to support alternate base addresses for the
+   TCIC-2 chip, via an 'insmod' parameter setting.
+-- Moved all configuration options to 'make.options', cleaned up the
+   Makefiles, so that builds will be warning-free.
+-- Updated modules for 1.1.44.
+-- Cleaned up event handling in CS to make insert/removal detection
+   more robust -- seems to help with MHz XJ2144.
+-- Fixed bug in cardmgr temporary device file unlinking that was
+   causing /tmp to fill up with bogus device files.
+-- Fixed cardmgr to log messages on the console when syslogd is not
+   running.
+-- No patches needed for 1.1.43 kernel!
+-- Added some hooks to CS so that it can be tweaked when you load it.
+-- Added sti()'s to all the CS interrupt routines, added more timeouts
+   to hopefully lower chance of deadlocks.
+
+Version 2.0
+-- Updated patches for 1.1.42 kernel.
+-- Major file reorganization: now all the pcmcia stuff is segregated
+   in one directory tree.
+-- Changed device code in ds.c to grab the first free character
+   device number.  Also changed cardmgr to read /proc/devices to
+   determine what device number was found.  This eliminates the
+   need for a kernel patch to include/linux/major.h.
+-- Moved the "improved" resource registrar code out of ioport.c and
+   into drivers/pcmcia, since it seems unlikely to be adopted any time
+   soon.  
+-- Changed DE650 driver so that it will pick I/O ports aligned to a 32
+   port boundary between 0x300 and 0x400, since odd boundaries don't
+   work.
+-- Fixed IBM modem test in serial driver so it won't bail on modems
+   with incomplete CIS's.
+-- Working on simplifying configuration of 3c589 driver.  Now you can
+   set if_port from insmod: "insmod 3c589_cs.o if_port=#".  This still
+   isn't useful, because cardmgr doesn't allow arguments for modules.
+
+[06-Aug-94] Version 1.7
+-- Changed serial driver to actually use the ports specified in the
+   CIS.  This fixes Intel modems (and others??).
+-- Support for 3Com 3c589 ethernet!
+-- Support for IBM high-speed modems.
+
+Version 1.6
+-- Updated patches for kernel level 1.1.38.
+-- Fixed serial driver to enable audio output.
+-- Added GetStatus call to Card Services, added to 'status' reports.
+-- Added 'probe' program to report PCMCIA controller type.
+-- Added 'dump_i365' program to dump Intel and Cirrus registers.
+-- Added 'dump_tcic' program to dump TCIC-2 registers.
+-- Added -DPOLL_STATUS option to cs.c, to support explicit polling of
+   card status changes on systems where card insertion/removal irq's
+   don't seem to work.
+-- Added 'dump_cisreg' program to dump CIS registers.
+-- Better card status change handling with TCIC-2 controller.
+
+Version 1.5
+-- Attempt to fix card insertion/removal detection for TCIC-2.
+-- Installation bug fixes.
+-- Added 'tuples' program to dump CIS data.
+
+Version 1.4
+-- Updated patches for kernel level 1.1.35.
+-- Fixed cardmgr to look in /sbin for the module utilities.
+
+Version 1.3
+-- Alpha support for TCIC-2 controller.
+
+Version 1.1
+-- Included missing cisreg.h header file.
+
+Version 1.0
+-- First release.
Index: oldkernel/linux/pcmcia-cs-3.1.15/COPYING
diff -u /dev/null linux/pcmcia-cs-3.1.15/COPYING:1.1
--- /dev/null	Mon Jul 31 21:15:09 2000
+++ linux/pcmcia-cs-3.1.15/COPYING	Fri Jul  7 16:18:18 2000
@@ -0,0 +1,20 @@
+Copyright (c) 1998, 1999 David A. Hinds
+
+Unless otherwise indicated, this code is distributed under version 1.1
+of the Mozilla Public License ("MPL"), included in the LICENSE file.
+
+Where this software is combined with software released under the terms
+of the GNU Public License ("GPL") and the terms of the GPL would
+require the combined work to also be released under the terms of the
+GPL, the terms and conditions of the MPL will apply in addition to
+those of the GPL with the exception of any terms or conditions of the
+MPL that conflict with, or are expressly prohibited by, the GPL.
+
+Some of the client drivers (nmclan_cs.c, 3c589_cs.c, 3c574_cs.c,
+3c575_cb.c, ibmtr_cs.c, pcnet_cs.c, smc91c92_cs.c, fmvj18x_cs.c,
+wavelan_cs.c, wvlan_cs.c, netwave_cs.c, xirc2ps_cs.c, serial_cb.c)
+contain code written by others, subject to more restrictive (GPL)
+licensing requirements.
+
+	-- David Hinds
+	   dhinds@pcmcia.sourceforge.org
Index: oldkernel/linux/pcmcia-cs-3.1.15/Configure
diff -u /dev/null linux/pcmcia-cs-3.1.15/Configure:1.1
--- /dev/null	Mon Jul 31 21:15:09 2000
+++ linux/pcmcia-cs-3.1.15/Configure	Fri Jul  7 16:18:18 2000
@@ -0,0 +1,852 @@
+#!/bin/sh
+#
+# Configure 1.156 2000/05/16 21:35:31
+#
+# 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@pcmcia.sourceforge.org>.  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.
+#
+#=======================================================================
+
+fail ()
+{
+    echo ""
+    echo "Configuration failed."
+    echo ""
+    exit 1
+}
+
+# Minimal requirements for sanity
+if [ ! -L include/linux/config.h ] ; then
+    echo "Ack!  The PCMCIA distribution is incomplete/damaged!"
+    echo "    Unpack again -- and try using a Linux filesystem this time."
+    fail
+fi
+
+if [ -r config.out ] ; then
+    . ./config.out 2>/dev/null
+else
+    if [ ! -r config.in ] ; then
+	echo "config.in does not exist!"
+	fail
+    fi
+    . ./config.in
+fi
+
+#=======================================================================
+
+PROMPT=y
+
+arg () {
+    VALUE="`echo X"$2" | sed -e 's/^X--[a-zA-Z_]*=//'`"
+    eval $1=\"$VALUE\"
+}
+
+usage () {
+    echo "usage: $0 [-n|--noprompt] [--kernel=src-dir] [--target=dir]"
+    echo "    [--moddir=dir] [--cc=path] [--ld=path] [--debug=debug-flags]"
+    echo "    [--uflags=user-flags] [--kflags=kernel-flags] [--{no}trust]"
+    echo "    [--{no}cardbus] [--{no}pnp] [--{no}apm] [--current] [--srctree]"
+    echo ""
+    echo "  -n, --noprompt     non-interactive mode: no prompting"
+    echo "  --kernel=DIR       use kernel source tree at DIR"
+    echo "  --target=DIR       install all files using DIR as root"
+    echo "  --moddir=DIR       install modules under DIR"
+    echo "  --arch=ARCH        select target architecture for build"
+    echo "  --cc=PATH          use another C compiler"
+    echo "  --ld=PATH          use another linker"
+    echo "  --debug=FLAGS      set compiler flags for debugging"
+    echo "  --uflags=FLAGS     set compiler flags for user-mode tools"
+    echo "  --kflags=FLAGS     set compiler flags for kernel modules"
+    echo "  --{no}trust        disable or enable trusted user tools"
+    echo "  --{no}cardbus      disable or enable CardBus card support"
+    echo "  --{no}pnp          disable or enable PnP BIOS support"
+    echo "  --{no}apm          disable or enable power management support"
+    echo "  --current          read configuration of current kernel"
+    echo "  --srctree          read kernel configuration from source tree"
+    echo "  --sysv             target has SysV init script layout"
+    echo "  --bsd              target uses BSD init scripts"
+    echo "  --rcdir=DIR        SysV init scripts are under DIR"
+    exit 1
+}
+
+while [ $# -gt 0 ] ; do
+    case "$1" in
+    -n|--noprompt)	PROMPT=n		;;
+    --kernel=*)		arg LINUX $1 		;;
+    --target=*)		arg PREFIX $1		;;
+    --moddir=*)		arg MODDIR $1		;;
+    --cc=*)		arg CC "$1"		;;
+    --ld=*)		arg LD "$1"		;;
+    --debug=*)		arg PCDEBUG "$1"	;;
+    --kflags=*)		arg KFLAGS "$1"		;;
+    --uflags=*)		arg UFLAGS "$1"		;;
+    --arch=*)		arg ARCH "$1"		;;
+    --trust)		UNSAFE_TOOLS=y		;;
+    --notrust)		UNSAFE_TOOLS=n		;;
+    --cardbus)		CONFIG_CARDBUS=y	;;
+    --nocardbus)	CONFIG_CARDBUS=n	;;
+    --pnp)		CONFIG_PNP_BIOS=y	;;
+    --nopnp)		CONFIG_PNP_BIOS=n	;;
+    --apm)		USE_PM=y		;;
+    --noapm)		USE_PM=n		;;
+    --current)		CONF_SRC=1		;;
+    --srctree)		CONF_SRC=2		;;
+    --sysv)		SYSV_INIT=y		;;
+    --bsd)		SYSV_INIT=n		;;
+    --rcdir=*)		arg RC_DIR "$1"		;;
+    *)			usage			;;
+    esac
+    shift
+done
+
+#=======================================================================
+
+CONFIG=config.new
+CONFIG_H=include/pcmcia/config.h
+CONFIG_MK=config.mk
+MODVER=include/linux/modversions.h
+rm -f .prereq.ok $CONFIG $CONFIG_H $CONFIG_MK $MODVER
+
+cat << 'EOF' > $CONFIG
+#
+# Automatically generated by 'make config' -- don't edit!
+#
+EOF
+
+cat << 'EOF' > $CONFIG_H
+/*
+  Automatically generated by 'make config' -- don't edit!
+*/
+#ifndef _PCMCIA_CONFIG_H
+#define _PCMCIA_CONFIG_H
+
+#define AUTOCONF_INCLUDED
+
+EOF
+
+write_bool() {
+    value=`eval echo '$'$1`
+    if [ "$value" = "y" ] ; then
+	echo "$1=y" >> $CONFIG
+	echo "$1=y" >> $CONFIG_MK
+	echo "#define $1 1" >> $CONFIG_H
+    else
+	echo "# $1 is not defined" >> $CONFIG
+	echo "# $1 is not defined" >> $CONFIG_MK
+	echo "#undef  $1" >> $CONFIG_H
+    fi
+}
+
+write_int () {
+    value=`eval echo '$'$1`
+    echo "$1"=$value >> $CONFIG
+    echo "$1=$value" >> $CONFIG_MK
+    echo "#define $1 $value" >> $CONFIG_H
+}
+
+write_str () {
+    value=`eval echo '$'$1`
+    echo "$1"=\"$value\" >> $CONFIG
+    echo "$1=$value" >> $CONFIG_MK
+    echo "#define $1 \"$value\"" >> $CONFIG_H
+}
+
+prompt () {
+    eval $3=\"$2\"
+    if [ "$PROMPT" = "y" ] ; then
+	/bin/echo -e "$1 [$2]: \c"
+	read tmp
+	if [ ! -t 1 ] ; then echo $tmp ; fi
+	if [ -n "$tmp" ] ; then eval $3=\"$tmp\" ; fi
+    else
+	/bin/echo "$1 [$2]"
+    fi
+}
+
+ask_bool () {
+    default=`eval echo '$'$2`
+    if [ ! "$default" ] ; then default=n ; fi
+    answer=""
+    while [ "$answer" != "n" -a "$answer" != "y" ] ; do
+	prompt "$1 (y/n)" "$default" answer
+    done
+    eval "$2=$answer"
+    write_bool $2
+}
+
+ask_str () {
+    default=`eval echo '$'$2`
+    prompt "$1" "`echo $default`" answer
+    eval $2=\"$answer\"
+    write_str $2
+}
+
+#=======================================================================
+
+echo ""
+echo "    -------- Linux PCMCIA Configuration Script --------"
+echo ""
+echo "The default responses for each question are correct for most users."
+echo "Consult the PCMCIA-HOWTO for additional info about each option."
+echo ""
+
+ask_str "Linux source directory" LINUX
+
+if [ ! -f $LINUX/kernel/Makefile ] ; then
+    echo "Linux source tree $LINUX is incomplete or missing!"
+    if [ -d $LINUX/include/linux ] ; then
+	echo "    The kernel header files are present, but not " \
+	     "the full source code."
+    fi
+    echo "    See the HOWTO for a list of FTP sites for current" \
+	 "kernel sources."
+    fail
+fi
+
+# What kernel are we compiling for?
+
+version () {
+    expr $1 \* 65536 + $2 \* 256 + $3
+}
+
+echo ""
+for TAG in VERSION PATCHLEVEL SUBLEVEL EXTRAVERSION ; do
+    eval `sed -ne "/^$TAG/s/[ 	]//gp" $LINUX/Makefile`
+done
+SRC_RELEASE=$VERSION.$PATCHLEVEL.$SUBLEVEL$EXTRAVERSION
+SRC_BASE=$VERSION.$PATCHLEVEL.$SUBLEVEL
+VERSION_CODE=`version $VERSION $PATCHLEVEL $SUBLEVEL`
+echo "The kernel source tree is version $SRC_RELEASE."
+if [ $VERSION_CODE -lt `version 2 0 0` ] ; then
+    echo "This package requires at least a 2.0 series kernel."
+    fail
+fi
+
+HOST_ARCH=`uname -m | sed -e 's/i.86/i386/'`
+if [ ! "$ARCH" ] ; then ARCH=$HOST_ARCH ; fi
+CUR_RELEASE=`uname -r`
+CUR_VERSION=`uname -v`
+CUR_BASE=`uname -r | sed -e "s/^\([0-9]\.[0-9]\.[0-9]*\).*/\1/"`
+MATCH=0 # default: different releases and/or architectures
+if [ $ARCH = $HOST_ARCH ] ; then
+    if [ $CUR_RELEASE = $SRC_RELEASE ] ; then
+	MATCH=1 # same release, perfect match
+    elif [ $CUR_BASE = $SRC_BASE ] ; then
+	MATCH=1 # well, maybe same source tree
+	echo "  WARNING: the current kernel is sublevel $CUR_RELEASE."
+    else
+	echo "  WARNING: the current kernel is version $CUR_RELEASE."
+    fi
+fi
+
+# Check for consistent kernel build dates
+
+CUR_D=`uname -v | sed -e 's/^#[0-9]* //;s/SMP //'`
+CUR_D=`echo $CUR_D | sed -e 's/\(:[0-9][0-9]\) .* \([12][90]\)/\1 \2/'`
+echo "The current kernel build date is $CUR_D."
+SRC_VERSION="unknown";
+if [ -f $LINUX/include/linux/compile.h ] ; then
+    SRC_VERSION=`grep UTS_VERSION $LINUX/include/linux/compile.h |
+	sed -e 's/.*"\(.*\)"/\1/'`
+    SRC_D=`echo $SRC_VERSION | sed -e 's/^#[0-9]* //;s/SMP //'`
+    SRC_D=`echo $SRC_D | sed -e 's/\(:[0-9][0-9]\) .* \([12][90]\)/\1 \2/'`
+    if [ $MATCH = 1 -a "$SRC_D" != "$CUR_D" ] ; then
+	echo "  WARNING: the source tree has a build date of $SRC_D."
+	if [ `date -d "$SRC_D" +%s` -gt `date -d "$CUR_D" +%s` ] ; then
+	    echo "  Did you forget to install your new kernel?"
+	fi
+    elif [ $MATCH = 1 ] ; then
+	MATCH=2 # same release & date
+    fi
+fi
+echo ""
+
+ask_str "Alternate target install directory" PREFIX
+
+for x in CC LD KFLAGS UFLAGS PCDEBUG ; do
+    write_str $x
+done
+write_bool USE_PM
+
+ask_bool "Build 'trusting' versions of card utilities" UNSAFE_TOOLS
+ask_bool "Include 32-bit (CardBus) card support" CONFIG_CARDBUS
+if [ $ARCH = "i386" -a $VERSION_CODE -gt `version 2 2 0` -a \
+     $VERSION_CODE -lt `version 2 3 37` ] ; then
+    ask_bool "Include PnP BIOS resource checking" CONFIG_PNP_BIOS
+else
+    CONFIG_PNP_BIOS=n
+    write_bool CONFIG_PNP_BIOS
+fi
+
+if [ $MATCH = 0 -o $MATCH = 2 ] ; then
+    CONF_SRC=2 # Use source tree when required or safe to do so
+elif [ $MATCH = 1 -a ! -r $LINUX/.config ] ; then
+    CONF_SRC=1 # Use running kernel if tree is not configured
+else
+    echo ""
+    echo "The PCMCIA drivers need to be compiled to match the kernel they"
+    echo "will be used with, or some or all of the modules may fail to load."
+    echo "If you are not sure what to do, please consult the PCMCIA-HOWTO."
+    echo ""
+    echo "How would you like to set kernel-specific options?"
+    echo "    1 - Read from the currently running kernel"
+    echo "    2 - Read from the Linux source tree"
+
+    ans=""
+    while [ "$ans" != 1 -a "$ans" != 2 ] ; do
+	prompt "Enter option (1-2)" "$CONF_SRC" ans
+    done
+    CONF_SRC=$ans
+    echo ""
+fi
+echo "CONF_SRC=$CONF_SRC" >> $CONFIG
+
+if [ $CONF_SRC -eq 1 ] ; then
+    UTS_VERSION=$CUR_VERSION ; UTS_RELEASE=$CUR_RELEASE
+else
+    UTS_VERSION=$SRC_VERSION ; UTS_RELEASE=$SRC_RELEASE
+fi
+
+if [ ! "$MODDIR" ] ; then
+    if [ -d /lib/modules/preferred ] ; then
+	MODDIR=/lib/modules/preferred
+    else
+	MODDIR=/lib/modules/$UTS_RELEASE
+    fi
+else
+    MODDIR=`echo $MODDIR | \
+        sed -e "s/[0-9]\.[0-9]\.[0-9]*.*/$UTS_RELEASE/"`
+fi
+ask_str "Module install directory" MODDIR
+echo ""
+
+#=======================================================================
+
+symcheck () {
+    eval "$1=n"
+    if $KSYMS | grep "$2" >/dev/null ; then eval "$1=y" ; fi
+    if [ "$3" ] ; then
+	insmod $3 > /dev/null 2>&1
+	if $KSYMS | grep "$2" > /dev/null ; then
+	    eval "$1=y"
+	fi
+    fi
+}
+
+configcheck () {
+    eval "$1=n"
+    if grep "^$1=y" $AUTOCONF >/dev/null ; then
+	eval "$1=y"
+    elif grep "^$1=m" $AUTOCONF >/dev/null ; then
+	eval "$1=y"
+    fi
+}
+
+printflag() {
+    value=`eval echo '$'$2`
+    /bin/echo -e "    $1 is \c"
+    if [ "$value" = "y" ] ; then
+	echo "enabled."
+    else
+	echo "disabled."
+    fi
+    write_bool $2
+}
+
+tweak () {
+    if [ $VERSION_CODE -ge `version 2 2 0` ] ; then
+	if [ $CONFIG_SMP = "y" ] ; then
+	    CONFIG_X86_LOCAL_APIC=y
+	    CONFIG_X86_IO_APIC=y
+	    write_bool CONFIG_X86_LOCAL_APIC
+	    write_bool CONFIG_X86_IO_APIC
+	fi
+	if [ $CONFIG_PCI = "y" ] ; then
+	    CONFIG_PCI_QUIRKS=y
+	    write_bool CONFIG_PCI_QUIRKS
+	fi
+    fi
+}
+
+printconfig () {
+    echo "Kernel configuration options:"
+    if [ $VERSION_CODE -ge `version 2 3 18` ] ; then
+	printflag "Kernel-tree PCMCIA support" CONFIG_PCMCIA
+    fi
+    printflag "Symmetric multiprocessing support" CONFIG_SMP
+    printflag "PCI BIOS support" CONFIG_PCI
+    tweak
+    printflag "Power management (APM) support" CONFIG_PM
+    printflag "SCSI support" CONFIG_SCSI
+    printflag "Networking support" CONFIG_INET
+    printflag " Radio network interface support" CONFIG_NET_RADIO
+    printflag " Token Ring device support" CONFIG_TR
+    printflag " Fast switching" CONFIG_NET_FASTROUTE
+    printflag "Module version checking" CONFIG_MODVERSIONS
+    if [ $VERSION_CODE -lt `version 2 1 7` ] ; then
+	printflag "PCMCIA IDE device support" CONFIG_BLK_DEV_IDE_PCMCIA
+    fi
+    if [ $ARCH = "i386" ] ; then
+	CONFIG_X86_L1_CACHE_BYTES=32
+	write_int CONFIG_X86_L1_CACHE_BYTES
+    fi
+    if [ $ARCH = "alpha" ] ; then
+	if [ $VERSION_CODE -lt `version 2 2 0` ] ; then
+	    CONFIG_ALPHA_LCA=y
+	    write_bool CONFIG_ALPHA_LCA
+	else
+	    CONFIG_ALPHA_GENERIC=y
+	    write_bool CONFIG_ALPHA_GENERIC
+	fi
+    fi
+    if [ $ARCH = "arm" ] ; then
+	printflag "Brutus architecture" CONFIG_ARCH_BRUTUS
+	printflag "Itsy target platform" CONFIG_ITSY
+    fi
+    printflag "/proc filesystem support" CONFIG_PROC_FS
+    if [ "$BIGMEM" ] ; then
+	if [ "$CONFIG_3GB" = "y" ] ; then MEMMAX=3GB
+	elif [ "$CONFIG_2GB" = "y" ] ; then MEMMAX=2GB
+	else MEMMAX=1GB ; fi
+	echo "    Maximum physical memory: $MEMMAX"
+	echo "MEMMAX=$MEMMAX" >> $CONFIG
+	write_bool CONFIG_1GB
+	write_bool CONFIG_2GB
+	write_bool CONFIG_3GB
+    fi
+}
+
+echo "" >> $CONFIG
+echo "" >> $CONFIG_MK
+echo "" >> $CONFIG_H
+
+if [ $ARCH = "i386" ] && \
+    grep -qs CONFIG_1GB $LINUX/include/asm-i386/page_offset.h ; then
+    BIGMEM=y
+fi
+CONFIG_PCMCIA=n
+
+case $CONF_SRC in
+    1)
+	if [ -x /sbin/ksyms ] ; then
+	    KSYMS="/sbin/ksyms -a"
+	else
+	    echo "Hmmm... /sbin/ksyms is broken.  Using /proc/ksyms..."
+	    KSYMS="cat /proc/ksyms"
+	fi
+	echo "# Options from current kernel" >> $CONFIG
+	echo "# Options from current kernel" >> $CONFIG_MK
+	echo "/* Options from current kernel */" >> $CONFIG_H
+	echo "CHECK=\"/proc/version\"" >> $CONFIG
+	echo "CKSUM=\"`cksum < /proc/version`\"" >> $CONFIG
+	echo "#define CONFIG_MODULES 1" >> $CONFIG_H
+	if [ $VERSION_CODE -lt `version 2 3 37` ] ; then
+	    if $KSYMS | grep CardServices | grep -v pcmcia > /dev/null ; then
+		CONFIG_PCMCIA=y
+	    fi
+	else
+	    symcheck CONFIG_PCMCIA CardServices pcmcia_core
+	fi
+	symcheck CONFIG_SMP smp_invalidate_needed
+	symcheck CONFIG_PCI pcibios
+	if [ $VERSION_CODE -lt `version 2 3 43` ] ; then
+	    symcheck CONFIG_PM apm_register_callback
+	else
+	    symcheck CONFIG_PM pm_register
+	fi
+	symcheck CONFIG_SCSI scsi_register scsi_mod
+	symcheck CONFIG_SERIAL register_serial serial
+	symcheck CONFIG_PARPORT parport_register parport
+	symcheck CONFIG_PARPORT_PC parport_pc_ops parport_pc
+	symcheck CONFIG_INET register_netdev
+	symcheck CONFIG_NET_FASTROUTE dev_fastroute_stat
+	if [ -r /proc/net/wireless ] ; then
+	    CONFIG_NET_RADIO=y
+	else
+	    CONFIG_NET_RADIO=n
+	fi
+	symcheck CONFIG_MODVERSIONS printk_R
+	if [ $VERSION_CODE -lt `version 2 1 7` ] ; then
+	    symcheck CONFIG_BLK_DEV_IDE_PCMCIA ide_register
+	fi
+	symcheck CONFIG_TR tr_setup
+	if [ "$BIGMEM" ] ; then
+	    symcheck CONFIG_1GB ^c01
+	    symcheck CONFIG_2GB ^801
+	    symcheck CONFIG_3GB ^401
+	fi
+	symcheck CONFIG_PROC_FS proc_root
+	echo "#ifndef __LINUX_MODVERSIONS_H" > $MODVER
+	echo "#define __LINUX_MODVERSIONS_H" >> $MODVER
+	H='[0-9a-f][0-9a-f]'
+	$KSYMS | sed -ne 's/.* \(.*\)_R\(.*'$H$H$H$H'\)/\1 \2/p' | \
+	    awk '{ printf "#define %s\t%s_R%s\n", $1, $1, $2 }' \
+	    >> $MODVER
+	echo "#endif" >> $MODVER
+	;;
+    2)
+	AUTOCONF=$LINUX/.config
+	if [ ! -r $AUTOCONF ] ; then
+	    echo "Config file $AUTOCONF not present!"
+	    echo "    To fix, run 'make config' in $LINUX."
+	    fail
+	fi
+	echo "# Options from $AUTOCONF" >> $CONFIG
+	echo "# Options from $AUTOCONF" >> $CONFIG_MK
+	echo "/* Options from $AUTOCONF */" >> $CONFIG_H
+	echo "CHECK=\"$AUTOCONF\"" >> $CONFIG
+	echo "CKSUM=\"`cksum < $AUTOCONF`\"" >> $CONFIG
+	echo "#define CONFIG_MODULES 1" >> $CONFIG_H
+	if [ $VERSION_CODE -lt `version 2 3 37` ] ; then
+	    if grep "^CONFIG_PCMCIA=y" $AUTOCONF >/dev/null ; then
+		CONFIG_PCMCIA=y
+	    fi
+	else
+	    configcheck CONFIG_PCMCIA
+	fi
+	if grep "^ *SMP *= *1" $LINUX/Makefile >/dev/null ; then
+	    CONFIG_SMP=y
+	else
+	    configcheck CONFIG_SMP
+	fi
+	if [ $VERSION_CODE -lt `version 2 1 7` ] ; then
+	    configcheck CONFIG_BLK_DEV_IDE_PCMCIA
+	fi
+	if [ $VERSION_CODE -lt `version 2 3 43` ] ; then
+	    configcheck CONFIG_APM ; CONFIG_PM=$CONFIG_APM
+	else
+	    configcheck CONFIG_PM
+	fi
+	for C in CONFIG_PCI CONFIG_SCSI CONFIG_INET \
+	    CONFIG_NET_FASTROUTE CONFIG_NET_RADIO CONFIG_TR \
+	    CONFIG_MODVERSIONS CONFIG_PROC_FS CONFIG_PARPORT \
+	    CONFIG_PARPORT_PC CONFIG_SERIAL ; do
+	    configcheck $C
+	done
+	if [ $ARCH = "arm" ] ; then
+	    configcheck CONFIG_ARCH_BRUTUS
+	    configcheck CONFIG_ITSY
+	fi
+	if [ "$BIGMEM" ] ; then
+	    configcheck CONFIG_1GB
+	    configcheck CONFIG_2GB
+	    configcheck CONFIG_3GB
+	fi
+	;;
+esac
+
+if [ "$USE_APM" != "y" ] ; then CONFIG_APM=n ; fi
+printconfig
+echo ""
+
+#=======================================================================
+
+if [ "$CONFIG_PCI" != "y" -a "$CONFIG_CARDBUS" = "y" ] ; then
+    echo "Cardbus support requires kernel PCI BIOS support!"
+    echo "    To fix, re-run 'make config' and disable Cardbus support."
+    fail
+fi
+
+#if [ $VERSION_CODE -ge `version 2 3 37` -a "$CONFIG_PCMCIA" != "y" ] ; then
+#    echo "2.3.37 and later kernels require that PCMCIA be configured in the"
+#    echo "    kernel source tree.  To fix, reconfigure and rebuild your"
+#    echo "    kernel with PCMCIA enabled."
+#    fail
+#fi
+
+if [ ! -r $LINUX/include/asm ] ; then
+    cd $LINUX/include ; ln -s asm-$ARCH asm 2>/dev/null
+fi
+if [ ! -r $LINUX/include/asm ] ; then
+    echo "$LINUX/include/asm does not exist!"
+    echo "    To fix, do 'ln -s asm-$ARCH asm' in $LINUX/include."
+    fail
+fi
+
+AFLAGS=
+CONFIG_ISA=y
+CONFIG_UID16=y
+if [ $ARCH = "ppc" ] ; then
+    CONFIG_ISA=n
+    AFLAGS="-fno-builtin -msoft-float"
+    if [ $VERSION_CODE -ge `version 2 1 26` ] ; then
+	AFLAGS="$AFLAGS -ffixed-r2"
+    fi
+elif [ $ARCH = "alpha" ] ; then
+    AFLAGS="-mno-fp-regs"
+    if [ $VERSION_CODE -ge `version 2 1 26` ] ; then
+	AFLAGS="$AFLAGS -ffixed-8"
+    fi
+    CONFIG_UID16=n
+fi
+write_str ARCH
+write_str HOST_ARCH
+write_str AFLAGS
+write_bool CONFIG_ISA
+if [ $VERSION_CODE -ge `version 2 3 40` ] ; then
+    write_bool CONFIG_UID16
+fi
+
+if [ $CONF_SRC != "1" -a "$CONFIG_MODVERSIONS" = "y" ] ; then
+    MODVER="$LINUX/$MODVER"
+    if [ ! -r $MODVER ] ; then
+	echo "$MODVER does not exist!"
+	echo "    To fix, run 'make dep' in $LINUX."
+	fail
+    fi
+else
+    # We may need at least an empty modversions.h file
+    touch $MODVER
+    MODVER="../$MODVER"
+fi
+
+if [ "$CONFIG_SMP" = "y" ] ; then
+    echo "#define __SMP__ 1" >> $CONFIG_H
+fi
+
+echo "" >> $CONFIG
+echo "" >> $CONFIG_MK
+echo "" >> $CONFIG_H
+
+#=======================================================================
+
+HAS_PROC_BUS=n
+if [ "$CONFIG_MODVERSIONS" = "y" ] ; then
+    echo "MFLAG=-DMODVERSIONS -include $MODVER" >> $CONFIG_MK
+else
+    echo "MFLAG=" >> $CONFIG_MK
+fi
+if [ "$CONFIG_PCMCIA" = "y" ] ; then
+    # Use our kernel config, then kernel headers, then our headers
+    CPPFLAGS="-I../include/static -I\$(LINUX)/include -I../include"
+else
+    # Use our kernel config and headers, then kernel headers
+    CPPFLAGS="-I../include -I\$(LINUX)/include"
+fi
+echo "CPPFLAGS=$CPPFLAGS" >> $CONFIG_MK
+
+if [ $VERSION_CODE -ge `version 2 1 31` -a \
+     $VERSION_CODE -le `version 2 1 34` ] ; then
+    echo "Kernel versions 2.1.31-33 are broken.  Upgrade to 2.1.34."
+    fail
+fi
+if [ $VERSION_CODE -ge `version 2 1 90` -a \
+     $VERSION_CODE -le `version 2 1 102` ] ; then
+    echo "Kernel versions 2.1.90-2.1.102 are broken.  Upgrade to 2.2."
+    fail
+fi
+if [ "$CONFIG_CARDBUS" = "y" -a \
+     $VERSION_CODE -ge `version 2 1 90` ] ; then
+    if [ $VERSION_CODE -lt `version 2 1 125` -o \
+	 $VERSION_CODE -ge `version 2 1 132` ] ; then
+	DO_APA1480=y
+    fi
+fi
+if [ $VERSION_CODE -gt `version 2 1 104` ] ; then
+    HAS_PROC_BUS=$CONFIG_PROC_FS
+fi
+
+write_str UTS_RELEASE
+write_str UTS_VERSION
+echo "LINUX_VERSION_CODE=$VERSION_CODE" >> $CONFIG
+echo "LINUX_VERSION_CODE=$VERSION_CODE" >> $CONFIG_MK
+echo "#define LINUX_VERSION_CODE $VERSION_CODE" >> $CONFIG_H
+echo "#define KERNEL_VERSION(v,p,s)	(((v)<<16)+((p)<<8)+(s))" >> $CONFIG_H
+echo "" >> $CONFIG
+echo "" >> $CONFIG_MK
+echo "" >> $CONFIG_H
+
+write_bool HAS_PROC_BUS
+
+if [ $VERSION_CODE -ge `version 2 1 7` -o \
+     "$CONFIG_BLK_DEV_IDE_PCMCIA" = "y" ] ; then
+    echo "DO_IDE=y" >> $CONFIG_MK
+fi
+
+if [ $CONFIG_PARPORT_PC = "y" -a $VERSION_CODE -ge `version 2 2 0` -a \
+     $VERSION_CODE -lt `version 2 3 6` ] ; then
+    echo "DO_PARPORT=y" >> $CONFIG_MK
+fi
+
+if [ "$CONFIG_NET_RADIO" = "y" -a \
+      -r ${LINUX}/include/linux/wireless.h ] ; then
+    echo "#define HAS_WIRELESS_EXTENSIONS 1" >> $CONFIG_H
+else
+    echo "#undef  HAS_WIRELESS_EXTENSIONS" >> $CONFIG_H
+fi
+
+SCSI=$LINUX/drivers/scsi
+if [ "$CONFIG_SCSI" = "y" ] ; then
+    if [ "$DO_APA1480" = "y" ] ; then
+	echo "DO_APA1480=y" >> $CONFIG_MK
+	if grep ADAPTEC_1480A $SCSI/aic7xxx.c >/dev/null ; then
+	    echo "# FIX_AIC7XXX is not defined" >> $CONFIG_MK
+	else
+	    echo "FIX_AIC7XXX=y" >> $CONFIG_MK
+	fi
+    fi
+fi
+
+if [ "$CONFIG_CARDBUS" = "y" ] ; then
+    if grep CARDBUS ${LINUX}/drivers/net/epic100.c >/dev/null ; then
+	echo DO_EPIC_CB=y >> $CONFIG_MK
+    fi
+fi
+
+#=======================================================================
+
+# Check out the module stuff
+
+if [ ! -x /sbin/insmod -o ! -x /sbin/rmmod -o ! -x /sbin/lsmod ] ; then
+    echo "Your module utilities (insmod, rmmod) are missing from /sbin!"
+    echo "    To fix, you should build and install the latest set" \
+         "of module tools,"
+    echo "    available from FTP sites listed in the HOWTO."
+    fail
+fi
+
+MOD_RELEASE=`/sbin/insmod -V 2>&1 | \
+    sed -n -e 's/.*[Vv]ersion \([0-9][0-9.]*[0-9]\).*/\1/p'`
+X=`echo $MOD_RELEASE | sed -e 's/\./ /g'`
+MOD_CODE=`version $X`
+if [ $VERSION_CODE -ge `version 2 1 85` ] ; then
+    NEED=`version 2 1 85` ; T=2.1.85
+elif [ $VERSION_CODE -ge `version 2 1 18` ] ; then
+    NEED=`version 2 1 23` ; T=2.1.23
+else
+    NEED=`version 2 0 0` ; T=2.0.0
+fi
+
+if [ $NEED -gt $MOD_CODE ] ; then
+    echo "Your module utilities are version $MOD_RELEASE.  That is too old"
+    echo "    for this kernel!  To fix, upgrade to at least version $T."
+    fail
+fi
+
+#=======================================================================
+
+# Is the boot setup OK?
+
+if [ "$PREFIX" = "" ] ; then
+    if [ -f /etc/lilo.conf -a -f /boot/map ] ; then
+	if [ /vmlinuz -nt /boot/map ] ; then
+	    echo "Your boot map file is older than /vmlinuz. "\
+		 "If you installed /vmlinuz"
+	    echo "by hand, please run 'lilo' to update your boot"\
+		 "data, and then reboot."
+#	else
+#	    echo "Your 'lilo' installation appears to be OK."
+	fi
+    else
+	echo "It doesn't look like you are using 'lilo'."
+    fi
+fi
+
+#=======================================================================
+
+# How should the startup scripts be configured?
+
+if [ "$PREFIX" = "" ] ; then
+    if [ -d /etc/rc.d/init.d -o -d /etc/init.d -o -d /sbin/init.d ] ; then
+	echo "It looks like you have a System V init file setup."
+	SYSV_INIT=y
+	if [ -d /etc/rc.d/init.d ] ; then
+	    RC_DIR=/etc/rc.d
+	elif [ -d /sbin/init.d ] ; then
+	    RC_DIR=/sbin
+	else
+	    RC_DIR=/etc
+	fi
+    else
+	echo "It looks like you have a BSD-ish init file setup."
+	if ! grep rc.pcmcia /etc/rc.d/rc.S >/dev/null ; then
+	    echo "    You'll need to edit /etc/rc.d/rc.S to invoke" \
+		 "/etc/rc.d/rc.pcmcia"
+	    echo "    so that PCMCIA services will start at boot time."
+	fi
+	SYSV_INIT=
+    fi
+    write_bool SYSV_INIT
+    if [ "$SYSV_INIT" = "y" ] ; then write_str RC_DIR ; fi
+else
+    ask_bool "System V init script layout" SYSV_INIT
+    if [ "$SYSV_INIT" = "y" ] ; then
+	ask_str "Top-level directory for RC scripts" RC_DIR
+    fi
+fi
+
+echo ""
+
+#=======================================================================
+
+# Optional stuff
+
+HAS_FORMS=n
+if [ -r /usr/include/X11/Xlib.h -o \
+     -r /usr/X11R6/include/X11/Xlib.h ] ; then
+    echo "X Windows include files found."
+    for f in /usr/{X11/,X11R6/,local/,}lib/libforms.{so,a} ; do
+	if [ -r $f ] ; then break ; fi
+    done
+    for g in /usr/{X11/,X11R6/,local/,}include/{,X11/}forms.h ; do
+	if [ -r $g ] ; then break ; fi
+    done
+    if [ -r $f -a -r $g ] ; then
+	echo "$f and $g found."
+	HAS_FORMS=y
+    else
+	echo "Forms library not installed."
+    fi
+else
+    echo "X Windows include files not installed."
+fi
+
+if [ "$HAS_FORMS" != "y" ] ; then
+    echo "    If you wish to build the 'cardinfo' control panel, you" \
+	 "need the Forms"
+    echo "    library and the X Windows include files.  See the HOWTO" \
+	 "for details."
+    HAS_FORMS=n
+fi
+write_bool HAS_FORMS
+
+#=======================================================================
+
+if [ ! -d /var/run ] ; then
+    echo "WARNING: /var/run not found."
+    echo "    To fix, do 'mkdir /var/run'."
+fi
+
+#=======================================================================
+
+echo "" >> $CONFIG_H
+echo "#endif /* _PCMCIA_CONFIG_H */" >> $CONFIG_H
+
+mv $CONFIG config.out
+
+touch .prereq.ok
+
+echo ""
+echo "Configuration successful."
+echo ""
Index: oldkernel/linux/pcmcia-cs-3.1.15/LICENSE
diff -u /dev/null linux/pcmcia-cs-3.1.15/LICENSE:1.1
--- /dev/null	Mon Jul 31 21:15:09 2000
+++ linux/pcmcia-cs-3.1.15/LICENSE	Fri Jul  7 16:18:18 2000
@@ -0,0 +1,563 @@
+                           MOZILLA PUBLIC LICENSE
+                                Version 1.1
+
+                              ----------------
+
+1. Definitions.
+
+     1.0.1. "Commercial Use" means distribution or otherwise making the
+     Covered Code available to a third party.
+
+     1.1. ''Contributor'' means each entity that creates or contributes to
+     the creation of Modifications.
+
+     1.2. ''Contributor Version'' means the combination of the Original
+     Code, prior Modifications used by a Contributor, and the Modifications
+     made by that particular Contributor.
+
+     1.3. ''Covered Code'' means the Original Code or Modifications or the
+     combination of the Original Code and Modifications, in each case
+     including portions thereof.
+
+     1.4. ''Electronic Distribution Mechanism'' means a mechanism generally
+     accepted in the software development community for the electronic
+     transfer of data.
+
+     1.5. ''Executable'' means Covered Code in any form other than Source
+     Code.
+
+     1.6. ''Initial Developer'' means the individual or entity identified as
+     the Initial Developer in the Source Code notice required by Exhibit A.
+
+     1.7. ''Larger Work'' means a work which combines Covered Code or
+     portions thereof with code not governed by the terms of this License.
+
+     1.8. ''License'' means this document.
+
+     1.8.1. "Licensable" means having the right to grant, to the maximum
+     extent possible, whether at the time of the initial grant or
+     subsequently acquired, any and all of the rights conveyed herein.
+
+     1.9. ''Modifications'' means any addition to or deletion from the
+     substance or structure of either the Original Code or any previous
+     Modifications. When Covered Code is released as a series of files, a
+     Modification is:
+     
+          A. Any addition to or deletion from the contents of a file
+          containing Original Code or previous Modifications.
+
+          B. Any new file that contains any part of the Original Code or
+          previous Modifications.
+
+     1.10. ''Original Code'' means Source Code of computer software code
+     which is described in the Source Code notice required by Exhibit A as
+     Original Code, and which, at the time of its release under this License
+     is not already Covered Code governed by this License.
+
+     1.10.1. "Patent Claims" means any patent claim(s), now owned or
+     hereafter acquired, including without limitation,  method, process, and
+     apparatus claims, in any patent Licensable by grantor.
+
+     1.11. ''Source Code'' means the preferred form of the Covered Code for
+     making modifications to it, including all modules it contains, plus any
+     associated interface definition files, scripts used to control
+     compilation and installation of an Executable, or source code
+     differential comparisons against either the Original Code or another
+     well known, available Covered Code of the Contributor's choice. The
+     Source Code can be in a compressed or archival form, provided the
+     appropriate decompression or de-archiving software is widely available
+     for no charge.
+
+     1.12. "You'' (or "Your")  means an individual or a legal entity
+     exercising rights under, and complying with all of the terms of, this
+     License or a future version of this License issued under Section 6.1.
+     For legal entities, "You'' includes any entity which controls, is
+     controlled by, or is under common control with You. For purposes of
+     this definition, "control'' means (a) the power, direct or indirect, to
+     cause the direction or management of such entity, whether by contract
+     or otherwise, or (b) ownership of more than fifty percent (50%) of the
+     outstanding shares or beneficial ownership of such entity.
+
+2. Source Code License.
+
+     2.1. The Initial Developer Grant.
+     The Initial Developer hereby grants You a world-wide, royalty-free,
+     non-exclusive license, subject to third party intellectual property
+     claims:
+     
+          (a)  under intellectual property rights (other than patent or
+          trademark) Licensable by Initial Developer to use, reproduce,
+          modify, display, perform, sublicense and distribute the Original
+          Code (or portions thereof) with or without Modifications, and/or
+          as part of a Larger Work; and
+
+          (b) under Patents Claims infringed by the making, using or selling
+          of Original Code, to make, have made, use, practice, sell, and
+          offer for sale, and/or otherwise dispose of the Original Code (or
+          portions thereof).
+
+          (c) the licenses granted in this Section 2.1(a) and (b) are
+          effective on the date Initial Developer first distributes Original
+          Code under the terms of this License.
+
+          (d) Notwithstanding Section 2.1(b) above, no patent license is
+          granted: 1) for code that You delete from the Original Code; 2)
+          separate from the Original Code;  or 3) for infringements caused
+          by: i) the modification of the Original Code or ii) the
+          combination of the Original Code with other software or devices.
+
+     2.2. Contributor Grant.
+     Subject to third party intellectual property claims, each Contributor
+     hereby grants You a world-wide, royalty-free, non-exclusive license
+
+          (a)  under intellectual property rights (other than patent or
+          trademark) Licensable by Contributor, to use, reproduce, modify,
+          display, perform, sublicense and distribute the Modifications
+          created by such Contributor (or portions thereof) either on an
+          unmodified basis, with other Modifications, as Covered Code and/or
+          as part of a Larger Work; and
+
+          (b) under Patent Claims infringed by the making, using, or selling
+          of  Modifications made by that Contributor either alone and/or in
+          combination with its Contributor Version (or portions of such
+          combination), to make, use, sell, offer for sale, have made,
+          and/or otherwise dispose of: 1) Modifications made by that
+          Contributor (or portions thereof); and 2) the combination of
+          Modifications made by that Contributor with its Contributor
+          Version (or portions of such combination).
+
+          (c) the licenses granted in Sections 2.2(a) and 2.2(b) are
+          effective on the date Contributor first makes Commercial Use of
+          the Covered Code.
+
+          (d)    Notwithstanding Section 2.2(b) above, no patent license is
+          granted: 1) for any code that Contributor has deleted from the
+          Contributor Version; 2)  separate from the Contributor Version;
+          3)  for infringements caused by: i) third party modifications of
+          Contributor Version or ii)  the combination of Modifications made
+          by that Contributor with other software  (except as part of the
+          Contributor Version) or other devices; or 4) under Patent Claims
+          infringed by Covered Code in the absence of Modifications made by
+          that Contributor.
+
+3. Distribution Obligations.
+
+     3.1. Application of License.
+     The Modifications which You create or to which You contribute are
+     governed by the terms of this License, including without limitation
+     Section 2.2. The Source Code version of Covered Code may be distributed
+     only under the terms of this License or a future version of this
+     License released under Section 6.1, and You must include a copy of this
+     License with every copy of the Source Code You distribute. You may not
+     offer or impose any terms on any Source Code version that alters or
+     restricts the applicable version of this License or the recipients'
+     rights hereunder. However, You may include an additional document
+     offering the additional rights described in Section 3.5.
+
+     3.2. Availability of Source Code.
+     Any Modification which You create or to which You contribute must be
+     made available in Source Code form under the terms of this License
+     either on the same media as an Executable version or via an accepted
+     Electronic Distribution Mechanism to anyone to whom you made an
+     Executable version available; and if made available via Electronic
+     Distribution Mechanism, must remain available for at least twelve (12)
+     months after the date it initially became available, or at least six
+     (6) months after a subsequent version of that particular Modification
+     has been made available to such recipients. You are responsible for
+     ensuring that the Source Code version remains available even if the
+     Electronic Distribution Mechanism is maintained by a third party.
+
+     3.3. Description of Modifications.
+     You must cause all Covered Code to which You contribute to contain a
+     file documenting the changes You made to create that Covered Code and
+     the date of any change. You must include a prominent statement that the
+     Modification is derived, directly or indirectly, from Original Code
+     provided by the Initial Developer and including the name of the Initial
+     Developer in (a) the Source Code, and (b) in any notice in an
+     Executable version or related documentation in which You describe the
+     origin or ownership of the Covered Code.
+
+     3.4. Intellectual Property Matters
+     
+          (a) Third Party Claims.
+          If Contributor has knowledge that a license under a third party's
+          intellectual property rights is required to exercise the rights
+          granted by such Contributor under Sections 2.1 or 2.2, Contributor
+          must include a text file with the Source Code distribution titled
+          "LEGAL'' which describes the claim and the party making the claim
+          in sufficient detail that a recipient will know whom to contact.
+          If Contributor obtains such knowledge after the Modification is
+          made available as described in Section 3.2, Contributor shall
+          promptly modify the LEGAL file in all copies Contributor makes
+          available thereafter and shall take other steps (such as notifying
+          appropriate mailing lists or newsgroups) reasonably calculated to
+          inform those who received the Covered Code that new knowledge has
+          been obtained.
+
+          (b) Contributor APIs.
+          If Contributor's Modifications include an application programming
+          interface and Contributor has knowledge of patent licenses which
+          are reasonably necessary to implement that API, Contributor must
+          also include this information in the LEGAL file.
+
+          (c) Representations.
+          Contributor represents that, except as disclosed pursuant to
+          Section 3.4(a) above, Contributor believes that Contributor's
+          Modifications are Contributor's original creation(s) and/or
+          Contributor has sufficient rights to grant the rights conveyed by
+          this License.
+
+     3.5. Required Notices.
+     You must duplicate the notice in Exhibit A in each file of the Source
+     Code.  If it is not possible to put such notice in a particular Source
+     Code file due to its structure, then You must include such notice in a
+     location (such as a relevant directory) where a user would be likely to
+     look for such a notice.  If You created one or more Modification(s) You
+     may add your name as a Contributor to the notice described in Exhibit
+     A.  You must also duplicate this License in any documentation for the
+     Source Code where You describe recipients' rights or ownership rights
+     relating to Covered Code.  You may choose to offer, and to charge a fee
+     for, warranty, support, indemnity or liability obligations to one or
+     more recipients of Covered Code. However, You may do so only on Your
+     own behalf, and not on behalf of the Initial Developer or any
+     Contributor. You must make it absolutely clear than any such warranty,
+     support, indemnity or liability obligation is offered by You alone, and
+     You hereby agree to indemnify the Initial Developer and every
+     Contributor for any liability incurred by the Initial Developer or such
+     Contributor as a result of warranty, support, indemnity or liability
+     terms You offer.
+
+     3.6. Distribution of Executable Versions.
+     You may distribute Covered Code in Executable form only if the
+     requirements of Section 3.1-3.5 have been met for that Covered Code,
+     and if You include a notice stating that the Source Code version of the
+     Covered Code is available under the terms of this License, including a
+     description of how and where You have fulfilled the obligations of
+     Section 3.2. The notice must be conspicuously included in any notice in
+     an Executable version, related documentation or collateral in which You
+     describe recipients' rights relating to the Covered Code. You may
+     distribute the Executable version of Covered Code or ownership rights
+     under a license of Your choice, which may contain terms different from
+     this License, provided that You are in compliance with the terms of
+     this License and that the license for the Executable version does not
+     attempt to limit or alter the recipient's rights in the Source Code
+     version from the rights set forth in this License. If You distribute
+     the Executable version under a different license You must make it
+     absolutely clear that any terms which differ from this License are
+     offered by You alone, not by the Initial Developer or any Contributor.
+     You hereby agree to indemnify the Initial Developer and every
+     Contributor for any liability incurred by the Initial Developer or such
+     Contributor as a result of any such terms You offer.
+
+     3.7. Larger Works.
+     You may create a Larger Work by combining Covered Code with other code
+     not governed by the terms of this License and distribute the Larger
+     Work as a single product. In such a case, You must make sure the
+     requirements of this License are fulfilled for the Covered Code.
+
+4. Inability to Comply Due to Statute or Regulation.
+
+     If it is impossible for You to comply with any of the terms of this
+     License with respect to some or all of the Covered Code due to statute,
+     judicial order, or regulation then You must: (a) comply with the terms
+     of this License to the maximum extent possible; and (b) describe the
+     limitations and the code they affect. Such description must be included
+     in the LEGAL file described in Section 3.4 and must be included with
+     all distributions of the Source Code. Except to the extent prohibited
+     by statute or regulation, such description must be sufficiently
+     detailed for a recipient of ordinary skill to be able to understand it.
+
+5. Application of this License.
+
+     This License applies to code to which the Initial Developer has
+     attached the notice in Exhibit A and to related Covered Code.
+
+6. Versions of the License.
+
+     6.1. New Versions.
+     Netscape Communications Corporation (''Netscape'') may publish revised
+     and/or new versions of the License from time to time. Each version will
+     be given a distinguishing version number.
+
+     6.2. Effect of New Versions.
+     Once Covered Code has been published under a particular version of the
+     License, You may always continue to use it under the terms of that
+     version. You may also choose to use such Covered Code under the terms
+     of any subsequent version of the License published by Netscape. No one
+     other than Netscape has the right to modify the terms applicable to
+     Covered Code created under this License.
+
+     6.3. Derivative Works.
+     If You create or use a modified version of this License (which you may
+     only do in order to apply it to code which is not already Covered Code
+     governed by this License), You must (a) rename Your license so that the
+     phrases ''Mozilla'', ''MOZILLAPL'', ''MOZPL'', ''Netscape'', "MPL",
+     ''NPL'' or any confusingly similar phrase do not appear in your license
+     (except to note that your license differs from this License) and (b)
+     otherwise make it clear that Your version of the license contains terms
+     which differ from the Mozilla Public License and Netscape Public
+     License. (Filling in the name of the Initial Developer, Original Code
+     or Contributor in the notice described in Exhibit A shall not of
+     themselves be deemed to be modifications of this License.)
+
+7. DISCLAIMER OF WARRANTY.
+
+     COVERED CODE IS PROVIDED UNDER THIS LICENSE ON AN "AS IS'' BASIS,
+     WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING,
+     WITHOUT LIMITATION, WARRANTIES THAT THE COVERED CODE IS FREE OF
+     DEFECTS, MERCHANTABLE, FIT FOR A PARTICULAR PURPOSE OR NON-INFRINGING.
+     THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE COVERED CODE
+     IS WITH YOU. SHOULD ANY COVERED CODE PROVE DEFECTIVE IN ANY RESPECT,
+     YOU (NOT THE INITIAL DEVELOPER OR ANY OTHER CONTRIBUTOR) ASSUME THE
+     COST OF ANY NECESSARY SERVICING, REPAIR OR CORRECTION. THIS DISCLAIMER
+     OF WARRANTY CONSTITUTES AN ESSENTIAL PART OF THIS LICENSE. NO USE OF
+     ANY COVERED CODE IS AUTHORIZED HEREUNDER EXCEPT UNDER THIS DISCLAIMER.
+
+8. TERMINATION.
+
+     8.1.  This License and the rights granted hereunder will terminate
+     automatically if You fail to comply with terms herein and fail to cure
+     such breach within 30 days of becoming aware of the breach. All
+     sublicenses to the Covered Code which are properly granted shall
+     survive any termination of this License. Provisions which, by their
+     nature, must remain in effect beyond the termination of this License
+     shall survive.
+
+     8.2.  If You initiate litigation by asserting a patent infringement
+     claim (excluding declatory judgment actions) against Initial Developer
+     or a Contributor (the Initial Developer or Contributor against whom You
+     file such action is referred to as "Participant")  alleging that:
+
+     (a)  such Participant's Contributor Version directly or indirectly
+     infringes any patent, then any and all rights granted by such
+     Participant to You under Sections 2.1 and/or 2.2 of this License shall,
+     upon 60 days notice from Participant terminate prospectively, unless if
+     within 60 days after receipt of notice You either: (i)  agree in
+     writing to pay Participant a mutually agreeable reasonable royalty for
+     Your past and future use of Modifications made by such Participant, or
+     (ii) withdraw Your litigation claim with respect to the Contributor
+     Version against such Participant.  If within 60 days of notice, a
+     reasonable royalty and payment arrangement are not mutually agreed upon
+     in writing by the parties or the litigation claim is not withdrawn, the
+     rights granted by Participant to You under Sections 2.1 and/or 2.2
+     automatically terminate at the expiration of the 60 day notice period
+     specified above.
+
+     (b)  any software, hardware, or device, other than such Participant's
+     Contributor Version, directly or indirectly infringes any patent, then
+     any rights granted to You by such Participant under Sections 2.1(b) and
+     2.2(b) are revoked effective as of the date You first made, used, sold,
+     distributed, or had made, Modifications made by that Participant.
+
+     8.3.  If You assert a patent infringement claim against Participant
+     alleging that such Participant's Contributor Version directly or
+     indirectly infringes any patent where such claim is resolved (such as
+     by license or settlement) prior to the initiation of patent
+     infringement litigation, then the reasonable value of the licenses
+     granted by such Participant under Sections 2.1 or 2.2 shall be taken
+     into account in determining the amount or value of any payment or
+     license.
+
+     8.4.  In the event of termination under Sections 8.1 or 8.2 above,  all
+     end user license agreements (excluding distributors and resellers)
+     which have been validly granted by You or any distributor hereunder
+     prior to termination shall survive termination.
+
+9. LIMITATION OF LIABILITY.
+
+     UNDER NO CIRCUMSTANCES AND UNDER NO LEGAL THEORY, WHETHER TORT
+     (INCLUDING NEGLIGENCE), CONTRACT, OR OTHERWISE, SHALL YOU, THE INITIAL
+     DEVELOPER, ANY OTHER CONTRIBUTOR, OR ANY DISTRIBUTOR OF COVERED CODE,
+     OR ANY SUPPLIER OF ANY OF SUCH PARTIES, BE LIABLE TO ANY PERSON FOR ANY
+     INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES OF ANY
+     CHARACTER INCLUDING, WITHOUT LIMITATION, DAMAGES FOR LOSS OF GOODWILL,
+     WORK STOPPAGE, COMPUTER FAILURE OR MALFUNCTION, OR ANY AND ALL OTHER
+     COMMERCIAL DAMAGES OR LOSSES, EVEN IF SUCH PARTY SHALL HAVE BEEN
+     INFORMED OF THE POSSIBILITY OF SUCH DAMAGES. THIS LIMITATION OF
+     LIABILITY SHALL NOT APPLY TO LIABILITY FOR DEATH OR PERSONAL INJURY
+     RESULTING FROM SUCH PARTY'S NEGLIGENCE TO THE EXTENT APPLICABLE LAW
+     PROHIBITS SUCH LIMITATION. SOME JURISDICTIONS DO NOT ALLOW THE
+     EXCLUSION OR LIMITATION OF INCIDENTAL OR CONSEQUENTIAL DAMAGES, SO THIS
+     EXCLUSION AND LIMITATION MAY NOT APPLY TO YOU.
+
+10. U.S. GOVERNMENT END USERS.
+
+     The Covered Code is a ''commercial item,'' as that term is defined in
+     48 C.F.R. 2.101 (Oct. 1995), consisting of ''commercial computer
+     software'' and ''commercial computer software documentation,'' as such
+     terms are used in 48 C.F.R. 12.212 (Sept. 1995). Consistent with 48
+     C.F.R. 12.212 and 48 C.F.R. 227.7202-1 through 227.7202-4 (June 1995),
+     all U.S. Government End Users acquire Covered Code with only those
+     rights set forth herein.
+
+11. MISCELLANEOUS.
+
+     This License represents the complete agreement concerning subject
+     matter hereof. If any provision of this License is held to be
+     unenforceable, such provision shall be reformed only to the extent
+     necessary to make it enforceable. This License shall be governed by
+     California law provisions (except to the extent applicable law, if any,
+     provides otherwise), excluding its conflict-of-law provisions. With
+     respect to disputes in which at least one party is a citizen of, or an
+     entity chartered or registered to do business in the United States of
+     America, any litigation relating to this License shall be subject to
+     the jurisdiction of the Federal Courts of the Northern District of
+     California, with venue lying in Santa Clara County, California, with
+     the losing party responsible for costs, including without limitation,
+     court costs and reasonable attorneys' fees and expenses. The
+     application of the United Nations Convention on Contracts for the
+     International Sale of Goods is expressly excluded. Any law or
+     regulation which provides that the language of a contract shall be
+     construed against the drafter shall not apply to this License.
+
+12. RESPONSIBILITY FOR CLAIMS.
+
+     As between Initial Developer and the Contributors, each party is
+     responsible for claims and damages arising, directly or indirectly, out
+     of its utilization of rights under this License and You agree to work
+     with Initial Developer and Contributors to distribute such
+     responsibility on an equitable basis. Nothing herein is intended or
+     shall be deemed to constitute any admission of liability.
+
+13. MULTIPLE-LICENSED CODE.
+
+     Initial Developer may designate portions of the Covered Code as
+     "Multiple-Licensed".  "Multiple-Licensed" means that the Initial
+     Developer permits you to utilize portions of the Covered Code under
+     Your choice of the NPL or the alternative licenses, if any, specified
+     by the Initial Developer in the file described in Exhibit A.
+
+EXHIBIT A -Mozilla Public License.
+
+     ``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 Original Code is ______________________________________.
+
+     The Initial Developer of the Original Code is ________________________.
+     Portions created by ______________________ are Copyright (C) ______
+     _______________________. All Rights Reserved.
+
+     Contributor(s): ______________________________________.
+
+     Alternatively, the contents of this file may be used under the terms of
+     the _____ license (the "[___] License"), in which case the provisions
+     of [______] License are applicable  instead of those above.  If you
+     wish to allow use of your version of this file only under the terms of
+     the [____] License 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 [___] License.  If you do not delete the provisions above, a
+     recipient may use your version of this file under either the MPL or the
+     [___] License."
+
+     [NOTE: The text of this Exhibit A may differ slightly from the text of
+     the notices in the Source Code files of the Original Code. You should
+     use the text of this Exhibit A rather than the text found in the
+     Original Code Source Code for Your Modifications.]
+
+     -----------------------------------------------------------------------
+
+     AMENDMENTS
+
+     The Netscape Public License Version 1.1 ("NPL") consists of the Mozilla
+     Public License Version 1.1 with the following Amendments, including
+     Exhibit A-Netscape Public License.  Files identified with "Exhibit
+     A-Netscape Public License" are governed by the Netscape Public License
+     Version 1.1.
+
+     Additional Terms applicable to the Netscape Public License.
+          I. Effect.
+          These additional terms described in this Netscape Public
+          License -- Amendments shall apply to the Mozilla Communicator
+          client code and to all Covered Code under this License.
+
+          II. ''Netscape's Branded Code'' means Covered Code that Netscape
+          distributes and/or permits others to distribute under one or more
+          trademark(s) which are controlled by Netscape but which are not
+          licensed for use under this License.
+
+          III. Netscape and logo.
+          This License does not grant any rights to use the trademarks
+          "Netscape'', the "Netscape N and horizon'' logo or the "Netscape
+          lighthouse" logo, "Netcenter", "Gecko", "Java" or "JavaScript",
+          "Smart Browsing" even if such marks are included in the Original
+          Code or Modifications.
+
+          IV. Inability to Comply Due to Contractual Obligation.
+          Prior to licensing the Original Code under this License, Netscape
+          has licensed third party code for use in Netscape's Branded Code.
+          To the extent that Netscape is limited contractually from making
+          such third party code available under this License, Netscape may
+          choose to reintegrate such code into Covered Code without being
+          required to distribute such code in Source Code form, even if such
+          code would otherwise be considered ''Modifications'' under this
+          License.
+
+          V. Use of Modifications and Covered Code by Initial Developer.
+               V.1. In General.
+               The obligations of Section 3 apply to Netscape, except to the
+               extent specified in this Amendment, Section V.2 and V.3.
+
+               V.2. Other Products.
+               Netscape may include Covered Code in products other than the
+               Netscape's Branded Code which are released by Netscape during
+               the two (2) years following the release date of the Original
+               Code, without such additional products becoming subject to
+               the terms of this License, and may license such additional
+               products on different terms from those contained in this
+               License.
+
+               V.3. Alternative Licensing.
+               Netscape may license the Source Code of Netscape's Branded
+               Code, including Modifications incorporated therein, without
+               such Netscape Branded Code becoming subject to the terms of
+               this License, and may license such Netscape Branded Code on
+               different terms from those contained in this License.
+
+          VI. Litigation.
+          Notwithstanding the limitations of Section 11 above, the
+          provisions regarding litigation in Section 11(a), (b) and (c) of
+          the License shall apply to all disputes relating to this License.
+
+     EXHIBIT A-Netscape Public License.
+
+          ''The contents of this file are subject to the Netscape 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/NPL/
+
+          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 Original Code is Mozilla Communicator client code, released
+          March 31, 1998.
+
+          The Initial Developer of the Original Code is Netscape
+          Communications Corporation. Portions created by Netscape are
+          Copyright (C) 1998-1999 Netscape Communications Corporation. All
+          Rights Reserved.
+
+          Contributor(s): ______________________________________.
+
+          Alternatively, the contents of this file may be used under the
+          terms of the _____ license (the "[___] License"), in which case
+          the provisions of [______] License are applicable  instead of
+          those above.  If you wish to allow use of your version of this
+          file only under the terms of the [____] License and not to allow
+          others to use your version of this file under the NPL, indicate
+          your decision by deleting  the provisions above and replace  them
+          with the notice and other provisions required by the [___]
+          License.  If you do not delete the provisions above, a recipient
+          may use your version of this file under either the NPL or the
+          [___] License."
Index: oldkernel/linux/pcmcia-cs-3.1.15/MAINTAINERS
diff -u /dev/null linux/pcmcia-cs-3.1.15/MAINTAINERS:1.1
--- /dev/null	Mon Jul 31 21:15:09 2000
+++ linux/pcmcia-cs-3.1.15/MAINTAINERS	Fri Jul  7 16:18:18 2000
@@ -0,0 +1,52 @@
+		Linux PCMCIA Maintainers List
+
+		Last updated: 2000/04/05 21:01:43
+
+The following PCMCIA driver components have active maintainers.  Bug
+reports and questions are often best addressed to the maintainer of
+the appropriate driver.
+
+[core modules, socket drivers, 3c589_cs, 3c574_cs, pcnet_cs,
+serial_cs, memory_cs, ftl_cs, dummy_cs, ide_cs, aha152x_cs, etc]
+David Hinds <dhinds@pcmcia.sourceforge.org>
+http://pcmcia.sourceforge.org
+
+[3c575_cb, epic_cb, tulip_cb]
+Donald Becker <becker@cesdis.gsfc.nasa.gov>
+http://cesdis.gsfc.nasa.gov/linux/driver
+
+[airo_cs]
+Ben Reed <breed@almaden.ibm.com>
+
+[ibmtr_cs]
+Mike Phillips <phillim@amtrak.com>
+http://www.linuxtr.org
+
+[netwave_cs]
+Dag Brattli <dagb@cs.uit.no>
+
+[ray_cs]
+Corey Thomas <coreythomas@charter.net>
+http://world.std.com/~corey/raylink.html
+
+[wavelan_cs]
+Jean Tourrilhes <jt@hpl.hp.com>
+http://www.hpl.hp.com/personal/Jean_Tourrilhes/Linux/
+Justin Seger <jseger@media.mit.edu>
+http://www.media.mit.edu/~jseger
+
+[wvlan_cs]
+Andreas Neuhaus <andy@fasta.fh-dortmund.de>
+http://www.fasta.fh-dortmund.de/users/andy/wvlan
+
+[xirc2ps_cs]
+Allan Baker <al527261@prodigy.net.mx>
+Werner Koch <werner.koch@guug.de> is the ex-maintainer and has some
+info at http://www.d.shuttle.de/isil/xircom/xirc2ps.html
+
+The following PCMCIA sub-projects need maintainers.  If you would be
+interested in helping out, let me know.
+
+o PCMCIA on Amiga
+o PCMCIA on PowerPC
+o PCMCIA on Alpha
Index: oldkernel/linux/pcmcia-cs-3.1.15/Makefile
diff -u /dev/null linux/pcmcia-cs-3.1.15/Makefile:1.1
--- /dev/null	Mon Jul 31 21:15:09 2000
+++ linux/pcmcia-cs-3.1.15/Makefile	Fri Jul  7 16:18:18 2000
@@ -0,0 +1,61 @@
+#
+# Makefile 1.39 2000/02/14 22:16:30 (David Hinds)
+#
+
+ifeq (config.mk, $(wildcard config.mk))
+include config.mk
+endif
+
+ALL  = modules clients wireless cardmgr flash debug-tools man etc
+DIRS = cardmgr flash debug-tools man etc
+ifndef CONFIG_PCMCIA
+DIRS := modules clients wireless $(DIRS)
+endif
+
+help:
+	@echo "Pick one of the following targets:"
+	@echo -e "\tmake config\t\t- configure and check system setup"
+	@echo -e "\tmake oldconfig\t\t- reconfigure without prompting"
+	@echo -e "\tmake all\t\t- build modules and programs"
+	@echo -e "\tmake install\t\t- install modules and programs"
+	@echo -e "\tmake clean\t\t- remove old binaries and dependency files"
+
+config .prereq.ok:
+	@touch config.mk
+	@$(MAKE) -s clean
+	@./Configure
+
+oldconfig:
+	@touch config.mk
+	@$(MAKE) -s clean
+	@./Configure -n
+
+all:	.prereq.ok kcheck
+	@set -e ; for d in $(DIRS) ; do $(MAKE) -C $$d ; done
+	@for f in *.mk ; do \
+	    if [ $$f != config.mk -a $$f != rules.mk ] ; then \
+	    $(MAKE) -f $$f all ; \
+	fi ; done
+
+clean:
+	@touch config.mk
+	@set -e ; for d in $(ALL) ; do $(MAKE) -C $$d clean ; done
+	rm -f .prereq.ok config.mk include/pcmcia/config.h
+	rm -f include/linux/modversions.h
+
+install: .prereq.ok kcheck
+	@set -e ; for d in $(DIRS) ; do $(MAKE) -C $$d install ; done
+	@for f in *.mk ; do \
+	    if [ $$f != config.mk -a $$f != rules.mk ] ; then \
+	    $(MAKE) -f $$f install ; \
+	fi ; done
+
+kcheck:
+	@. ./config.out ; \
+	if [ "$$CHECK" != "" ] ; then \
+	    if [ "`cksum < $$CHECK`" != "$$CKSUM" ] ; then \
+		/bin/echo -n "Kernel configuration has changed." ; \
+		/bin/echo "  Please re-run 'make config'." ; \
+		exit 1 ; \
+	    fi ; \
+	fi
Index: oldkernel/linux/pcmcia-cs-3.1.15/PCMCIA-HOWTO
diff -u /dev/null linux/pcmcia-cs-3.1.15/PCMCIA-HOWTO:1.1
--- /dev/null	Mon Jul 31 21:15:09 2000
+++ linux/pcmcia-cs-3.1.15/PCMCIA-HOWTO	Fri Jul  7 16:18:18 2000
@@ -0,0 +1,3049 @@
+  Linux PCMCIA HOWTO
+  David Hinds, dhinds@pcmcia.sourceforge.org.
+  v2.60, 14 May 2000
+
+  This document describes how to install and use PCMCIA Card Services
+  for Linux, and answers some frequently asked questions.  The latest
+  version of this document can always be found at <ftp://source-
+  forge.org/pcmcia/doc>.  An HTML version is at  <http://pcmcia.source-
+  forge.org>.
+  ______________________________________________________________________
+
+  Table of Contents
+
+  1. General information and hardware requirements
+
+     1.1 Introduction
+     1.2 Copyright notice and disclaimer
+     1.3 What is the latest version, and where can I get it?
+     1.4 What systems are supported?
+     1.5 What cards are supported?
+     1.6 When will my favorite (unsupported) card become supported?
+     1.7 Mailing lists and other information sources
+     1.8 Why don't you distribute binaries?
+     1.9 Why is the package so darned big?
+
+  2. Compilation and installation
+
+     2.1 Prerequisites and kernel setup
+     2.2 Installation
+     2.3 Startup options
+     2.4 System resource settings
+     2.5 Notes about specific Linux distributions
+        2.5.1 Debian
+        2.5.2 Red Hat, Caldera, Mandrake
+        2.5.3 Slackware
+        2.5.4 SuSE
+
+  3. Resolving installation and configuration problems
+
+     3.1 Base PCMCIA kernel modules do not load
+     3.2 Some client driver modules do not load
+     3.3 Interrupt scan failures
+     3.4 IO port scan failures
+     3.5 Memory probe failures
+     3.6 Failure to detect card insertions and removals
+     3.7 Interrupt delivery problems
+     3.8 System resource starvation
+     3.9 Resource conflict only with two cards inserted
+     3.10 Device configuration does not complete
+
+  4. Usage and features
+
+     4.1 Tools for configuring and monitoring PCMCIA devices
+        4.1.1 The cardmgr configuration daemon
+        4.1.2 The socket status file, stab
+        4.1.3 The cardctl and cardinfo utilities
+        4.1.4 Inserting and ejecting cards
+        4.1.5 Card Services and Advanced Power Management
+        4.1.6 Shutting down the PCMCIA system
+     4.2 Overview of the PCMCIA configuration scripts
+     4.3 PCMCIA network adapters
+        4.3.1 Network device parameters
+        4.3.2 Comments about specific cards
+        4.3.3 Diagnosing problems with network adapters
+     4.4 PCMCIA serial and modem devices
+        4.4.1 Serial device parameters
+        4.4.2 Comments about specific cards
+        4.4.3 Diagnosing problems with serial devices
+     4.5 PCMCIA parallel port devices
+        4.5.1 Parallel device parameters
+        4.5.2 Diagnosing problems with parallel port devices
+     4.6 PCMCIA SCSI adapters
+        4.6.1 SCSI device parameters
+        4.6.2 Comments about specific cards
+        4.6.3 Diagnosing problems with SCSI adapters
+     4.7 PCMCIA memory cards
+        4.7.1 Memory device parameters
+        4.7.2 Using linear flash memory cards
+     4.8 PCMCIA ATA/IDE card drives
+        4.8.1 ATA/IDE fixed-disk device parameters
+        4.8.2 Diagnosing problems with ATA/IDE adapters
+     4.9 Multifunction cards
+
+  5. Advanced topics
+
+     5.1 Resource allocation for PCMCIA devices
+     5.2 How can I have separate device setups for home and work?
+     5.3 Booting from a PCMCIA device
+        5.3.1 The pcinitrd helper script
+        5.3.2 Creating an initrd boot floppy
+        5.3.3 Installing an initrd image on a non-Linux drive
+
+  6. Dealing with unsupported cards
+
+     6.1 Configuring unrecognized cards
+     6.2 Adding support for an NE2000-compatible ethernet card
+     6.3 PCMCIA floppy interface cards
+
+  7. Debugging tips and programming information
+
+     7.1 Submitting useful bug reports
+     7.2 Interpreting kernel trap reports
+     7.3 Low level PCMCIA debugging aids
+     7.4 /proc/bus/pccard
+     7.5 Writing Card Services drivers for new cards
+     7.6 Guidelines for PCMCIA client driver authors
+     7.7 Guidelines for Linux distribution maintainers
+
+  ______________________________________________________________________
+
+  11..  GGeenneerraall iinnffoorrmmaattiioonn aanndd hhaarrddwwaarree rreeqquuiirreemmeennttss
+
+  11..11..  IInnttrroodduuccttiioonn
+
+  Card Services for Linux is a complete PCMCIA or ``PC Card'' support
+  package.  It includes a set of loadable kernel modules that implement
+  a version of the Card Services applications program interface, a set
+  of client drivers for specific cards, and a card manager daemon that
+  can respond to card insertion and removal events, loading and
+  unloading drivers on demand.  It supports ``hot swapping'' of most
+  card types, so cards can be safely inserted and ejected at any time.
+
+  This software is continually under development.  It probably contains
+  bugs, and should be used with caution.  I'll do my best to fix
+  problems that are reported to me, but if you don't tell me, I may
+  never know.  If you use this code, I hope you will send me your
+  experiences, good or bad!
+
+  If you have any suggestions for how this document could be improved,
+  please let me know (dhinds@pcmcia.sourceforge.org).
+
+  11..22..  CCooppyyrriigghhtt nnoottiiccee aanndd ddiissccllaaiimmeerr
+
+  Copyright (c) 1998 David A. Hinds
+
+  This document may be reproduced or distributed in any form without my
+  prior permission.  Modified versions of this document, including
+  translations into other languages, may be freely distributed, provided
+  that they are clearly identified as such, and this copyright is
+  included intact.
+
+  This document may be included in commercial distributions without my
+  prior consent.  While it is not required, I would like to be informed
+  of such usage.  If you intend to incorporate this document in a
+  published work, please contact me to make sure you have the latest
+  available version.
+
+  This document is provided ``AS IS'', with no express or implied
+  warranties.  Use the information in this document at your own risk.
+
+  11..33..  WWhhaatt iiss tthhee llaatteesstt vveerrssiioonn,, aanndd wwhheerree ccaann II ggeett iitt??
+
+  The current major release of Card Services is version 3.1, and minor
+  updates or bug fixes are numbered 3.1.1, 3.1.2, and so on.
+
+  Source code for the latest version is available from sourceforge.org
+  in the /pcmcia directory, as pcmcia-cs-3.1.?.tar.gz.  There will
+  usually be several versions here.  I generally only keep the latest
+  minor release for a given major release.  New major releases may
+  contain relatively untested code, so I also keep the latest version of
+  the previous major release as a relatively stable fallback; the
+  current fallback is 3.0.14.  It is up to you to decide which version
+  is more appropriate, but the CHANGES file will summarize the most
+  important differences.
+
+  sourceforge.org is mirrored at sunsite.unc.edu (and all sunsite mirror
+  sites) in /pub/Linux/kernel/pcmcia.
+
+  If you do not feel up to compiling the drivers from scratch, pre-
+  compiled drivers are included with current releases of most of the
+  major Linux distributions, including Slackware, Debian, Red Hat,
+  Caldera, SuSE, and Yggdrasil, among others.
+
+  11..44..  WWhhaatt ssyysstteemmss aarree ssuuppppoorrtteedd??
+
+  This package should run on almost Intel-based Linux-capable laptop.
+  It also runs on Alpha-based platforms (i.e., the DEC Multia).  Work is
+  being done to make the package fully dual-endian, so that it will also
+  support PowerPC-based platforms (i.e., Apple Powerbooks).  Most common
+  socket controllers are supported.  Card docks for desktop systems
+  should work as long as they use a supported controller, and are
+  plugged directly into the ISA or PCI bus, as opposed to SCSI-to-PCMCIA
+  or IDE-to-PCMCIA adapters.  The following controllers are recognized
+  by the supplied socket drivers:
+
+  +o  Cirrus Logic PD6710, PD6720, PD6722, PD6729, PD6730, PD6732, PD6832
+
+  +o  Intel i82365sl B, C, and DF steps, 82092AA
+
+  +o  O2Micro OZ6729, OZ6730, OZ6812, OZ6832, OZ6833, OZ6836, OZ6860
+
+  +o  Omega Micro 82C365G, 82C092G
+
+  +o  Ricoh RF5C296, RF5C396, RL5C465, RL5C466, RL5C475, RL5C476, RL5C478
+
+  +o  SMC 34C90
+
+  +o  Texas Instruments PCI1031, PCI1130, PCI1131, PCI1210, PCI1211,
+     PCI1220, PCI1221, PCI1225, PCI1250A, PCI1251A, PCI1251B, PCI1420,
+     PCI1450
+
+  +o  Toshiba ToPIC95, ToPIC97, ToPIC100 (experimental, incomplete)
+
+  +o  Vadem VG465, VG468, VG469
+
+  +o  VLSI Technologies 82C146, VCF94365
+
+  +o  VIA VT83C469
+
+  +o  Databook DB86082, DB86082A, DB86084, DB86084A, DB86072, DB86082B
+
+  Other controllers that are register compatible with the Intel i82365sl
+  will generally work, as well.
+
+  Support for 32-bit CardBus cards is still somewhat experimental.
+  Drivers prior to version 3.0 only support 16-bit cards in CardBus
+  sockets.  Due to the rapid pace of technological change for laptop
+  hardware, new controllers appear frequently, and there may be delays
+  between when a new model appears on the market, and when driver
+  support becomes available.
+
+  Toshiba has made available some documentation for their ToPIC95 and
+  ToPIC97 chipsets, however the information they have provided has not
+  really been adequate.  Despite conflicting reports to the contrary,
+  Toshiba has not made any effective effort to remedy this situation.
+  There are serious bugs in Linux support for the ToPIC chipsets, that
+  cannot be resolved until better documentation or help from Toshiba
+  becomes available.  I do not recommend use of Toshiba laptops at this
+  time.  For use of 16-bit cards, I recommend setting the bridge mode to
+  ``PCIC'' in the BIOS setup; for CardBus cards, you are on your own.
+
+  The Motorola 6AHC05GA controller used in some Hyundai laptops is not
+  supported.  The custom host controller in the HP Omnibook 600 is also
+  unsupported.
+
+  11..55..  WWhhaatt ccaarrddss aarree ssuuppppoorrtteedd??
+
+  The current release includes drivers for a variety of ethernet cards,
+  a driver for modem and serial port cards, several SCSI adapter
+  drivers, a driver for ATA/IDE drive cards, and memory card drivers
+  that should support most SRAM cards and some flash cards.  The
+  SUPPORTED.CARDS file included with each release of Card Services lists
+  all cards that are known to work in at least one actual system.
+
+  The likelihood that a card not on the supported list will work depends
+  on the type of card.  Essentially all modems should work with the
+  supplied driver.  Some network cards may work if they are OEM versions
+  of supported cards.  Other types of IO cards (frame buffers, sound
+  cards, etc) will not work until someone writes the appropriate
+  drivers.
+
+  11..66..  WWhheenn wwiillll mmyy ffaavvoorriittee ((uunnssuuppppoorrtteedd)) ccaarrdd bbeeccoommee ssuuppppoorrtteedd??
+
+  Unfortunately, they usually don't pay me to write device drivers, so
+  if you would like to have a driver for your favorite card, you are
+  probably going to have to do at least some of the work.  Ideally, I'd
+  like to work towards a model like the Linux kernel, where I would be
+  responsible mainly for the ``core'' driver code and other authors
+  would contribute and maintain client drivers for specific cards.  The
+  SUPPORTED.CARDS file mentions some cards for which driver work is
+  currently in progress.  I will try to help where I can, but be warned
+  that debugging kernel device drivers by email is not particularly
+  effective.
+
+  Manufacturers interested in helping provide Linux support for their
+  products can contact me about consulting arrangements.
+
+  11..77..  MMaaiilliinngg lliissttss aanndd ootthheerr iinnffoorrmmaattiioonn ssoouurrcceess
+
+  I used to maintain a database and mailing list of Linux PCMCIA users.
+  More recently, I've turned my web page for Linux PCMCIA information
+  into a ``HyperNews'' site, with a set of message lists for Linux
+  PCMCIA issues.  There are lists for installation and configuration
+  issues, for different types of cards, and for programming and
+  debugging issues.  The Linux PCMCIA information page is at
+  <http://pcmcia.sourceforge.org>.  Users can request email notification
+  of new responses to particular questions, or notification for all new
+  messages in a given category.  I hope that this will become a useful
+  repository of information, for questions that go beyond the scope of
+  the HOWTO.
+
+  There is a Linux mailing list devoted to laptop issues, the ``linux-
+  laptop'' list.  For more information, send a message containing the
+  word ``help'' to majordomo@vger.rutgers.edu.  To subscribe, send a
+  message containing ``subscribe linux-laptop'' to the same address.
+  This mailing list might be a good forum for discussion of Linux PCMCIA
+  issues.
+
+  The Linux Laptop Home Page at
+  <http://www.cs.utexas.edu/users/kharker/linux-laptop> has links to
+  many sites that have information about configuring specific types of
+  laptops for Linux.  There is also a searchable database of system
+  configuration information.
+
+  11..88..  WWhhyy ddoonn''tt yyoouu ddiissttrriibbuuttee bbiinnaarriieess??
+
+  For me, distributing binaries would be a significant hassle.  It is
+  complicated because some features can only be selected at compile
+  time, and because the modules are somewhat dependent on having the
+  ``right'' kernel configuration.  So, I would probably need to
+  distribute precompiled modules along with matching kernels.  Beyond
+  this, the greatest need for precompiled modules is when installing
+  Linux on a clean system.  This typically requires setting up drivers
+  so they can be used in the installation process for a particular Linux
+  distribution.  Each Linux distribution has its own ideosyncracies, and
+  it is not feasible for me to provide boot and root disks for even just
+  the common combinations of drivers and distributions.
+
+  PCMCIA is now a part of many of the major Linux distributions,
+  including Red Hat, Caldera, Slackware, Yggdrasil, Craftworks, and
+  Nascent Technology.
+
+  11..99..  WWhhyy iiss tthhee ppaacckkaaggee ssoo ddaarrnneedd bbiigg??
+
+  Well, first of all, it isn't actually that large.  All the driver
+  modules together take up about 500K of disk space.  The utility
+  programs add up to about 70K, and the scripts in /etc/pcmcia are about
+  50K.  The core driver modules take up about 55K of system memory.  The
+  cardmgr daemon will generally be swapped out except when cards are
+  inserted or removed.  The total package size is comparable to
+  DOS/Windows Card Services implementations.
+
+  Compared to DOS ``point enablers'', this may still seem like a lot of
+  overhead, especially for people that don't plan on using many of the
+  features of PCMCIA, such as power management or hot swapping.  Point
+  enablers can be tiny because they generally support only one or a
+  small set of cards, and also generally support a restricted set of
+  host controllers.  If someone were to write a genuinely ``generic''
+  modem enabler, it would end up incorporating much of the functionality
+  of Card Services, to handle cards from different vendors and the full
+  range of host controller variants.
+  22..  CCoommppiillaattiioonn aanndd iinnssttaallllaattiioonn
+
+  22..11..  PPrreerreeqquuiissiitteess aanndd kkeerrnneell sseettuupp
+
+  Before starting, you should think about whether you really need to
+  compile the PCMCIA package yourself.  All common Linux distributions
+  come with pre-compiled driver packages.  Generally, you only need to
+  install the drivers from scratch if you need a new feature of the
+  current drivers, or if you've updated and/or reconfigured your kernel
+  in a way that is incompatible with the drivers included with your
+  Linux distribution.  While compiling the package is not technically
+  difficult, it does require some general Linux familiarity.
+
+  The following things should be installed on your system before you
+  begin:
+
+  +o  A 2.0.*, 2.2.*, or 2.3.* series kernel source tree.
+
+  +o  An appropriate set of module utilities.
+
+  +o  (Optional) the ``XForms'' X11 user interface toolkit.
+
+  You need to have a complete linux source tree for your kernel, not
+  just an up-to-date kernel image.  The driver modules contain some
+  references to kernel source files.  While you may want to build a new
+  kernel to remove unnecessary drivers, installing PCMCIA does not
+  require you to do so.
+
+  Current ``stable'' kernel sources and patches are available from
+  <ftp://sunsite.unc.edu/pub/Linux/kernel/v2.2>, or from
+  <ftp://tsx-11.mit.edu/pub/linux/sources/system/v2.2>.  Development
+  kernels can be found in the corresponding v2.3 subdirectories.
+  Current module utilities can be found in the same locations.
+
+  In the Linux kernel source tree, the Documentation/Changes file
+  describes the versions of all sorts of other system components that
+  are required for that kernel release.  You may want to check through
+  this and verify that your system is up to date, especially if you have
+  updated your kernel.  If you are using a development kernel, be sure
+  that you are using the right combination of shared libraries and
+  module tools.
+
+  When configuring your kernel, if you plan on using a PCMCIA ethernet
+  card, you should turn on networking support but turn off the normal
+  Linux network card drivers, including the ``pocket and portable
+  adapters''.  The PCMCIA network card drivers are all implemented as
+  loadable modules.  Any drivers compiled into your kernel will only
+  waste space.
+
+  If you want to use SLIP, PPP, or PLIP, you do need to either configure
+  your kernel with these enabled, or use the loadable module versions of
+  these drivers.  There is an unfortunate deficiency in the kernel
+  config process in 1.2.X kernels, in that it is not possible to set
+  configuration options (like SLIP compression) for a loadable module,
+  so it is probably better to just link SLIP into the kernel if you need
+  it.
+
+  In order to use a PCMCIA token ring adapter, your kernel should be
+  configured with ``Token Ring driver support'' (CONFIG_TR) enabled,
+  though you should leave CONFIG_IBMTR off.
+
+  If you want to use a PCMCIA IDE adapter, your kernel should be
+  configured with CONFIG_BLK_DEV_IDE_PCMCIA enabled, for 2.0.*  through
+  2.1.7 kernels.  Older kernels do not support removeable IDE devices;
+  newer kernels do not require a special configuration setting.
+
+  If you will be using a PCMCIA SCSI adapter, then enable CONFIG_SCSI
+  when configuring your kernel.  Also, enable any top level drivers
+  (SCSI disk, tape, cdrom, generic) that you expect to use.  All low-
+  level drivers for particular host adapters should be disabled, as they
+  will just take up space.
+
+  If you want to modularize a driver that is needed for a PCMCIA device,
+  you must modify /etc/pcmcia/config to specify what modules need to be
+  loaded for what card types.  For example, if the serial driver is
+  modularized, then the serial device definition should be:
+
+       device "serial_cs"
+         class "serial" module "misc/serial", "serial_cs"
+
+  This package includes an X-based card status utility called cardinfo.
+  This utility is based on a freely distributed user interface toolkit
+  called the XForms Library.  This library is available as a separate
+  package with most Linux distributions.  If you would like to build
+  cardinfo, you should install XForms and all the normal X header files
+  and libraries before configuring the PCMCIA package.
+
+  22..22..  IInnssttaallllaattiioonn
+
+  Here is a synopsis of the installation process:
+
+  +o  Unpack pcmcia-cs-3.1.?.tar.gz in /usr/src.
+
+  +o  Run ``make config'' in the new pcmcia-cs-3.1.? directory.
+
+  +o  Run ``make all'', then ``make install''.
+
+  +o  Customize the startup script and the option files in /etc/pcmcia
+     for your site, if needed.
+
+  If you plan to install any contributed client drivers not included in
+  the core PCMCIA distribution, unpack each of them in the top-level
+  directory of the PCMCIA source tree.  Then follow the normal build
+  instructions.  The extra drivers will be compiled and installed
+  automatically.
+
+  Running ``make config'' prompts for a few configuration options, and
+  checks out your system to verify that it satisfies all prerequisites
+  for installing PCMCIA support.  In most cases, you'll be able to just
+  accept all the default configuration options.  Be sure to carefully
+  check the output of this command in case there are problems.  The
+  following options are available:
+
+     AAlltteerrnnaattee ttaarrggeett iinnssttaallll ddiirreeccttoorryy??
+        If you are compiling the package for installation on another
+        machine, specify an alternate target directory when prompted.
+        This should be an absolute path.  All files will be installed
+        relative to this directory.  You will then be able to tar this
+        directory tree and copy to your target machine, and unpack
+        relative to its root directory to install everything in the
+        proper places.
+
+     BBuuiilldd ''ttrruussttiinngg'' vveerrssiioonnss ooff ccaarrdd uuttiilliittiieess??
+        Some of the support utilities (cardctl and cardinfo) can be
+        compiled either in ``safe'' or ``trusting'' forms.  The ``safe''
+        forms prevent non-root users from modifying card configurations.
+        The ``trusting'' forms permit ordinary users to issue commands
+        to suspend and resume cards, reset cards, and change the current
+        configuration scheme.  The default is to build the safe forms.
+
+     IInncclluuddee 3322--bbiitt ((CCaarrddBBuuss)) ccaarrdd ssuuppppoorrtt??
+        This option must be selected if you wish to use 32-bit CardBus
+        cards.  It is not required for CardBus bridge support, if you
+        only plan to use 16-bit PC Cards.
+
+     IInncclluuddee PPnnPP BBIIOOSS rreessoouurrccee cchheecckkiinngg??
+        This builds additional code into the PCMCIA core module to
+        communicate with a system's PnP BIOS to obtain resource
+        information for built-in ``motherboard'' devices (serial and
+        parallel ports, sound, etc), to help avoid resource conflicts.
+        If enabled, some extra resource files will be created under
+        /proc/bus/pccard, and the lspnp and setpnp tools can be used to
+        view and manipulate PnP BIOS devices.  However, this setting
+        causes problems on some laptops and is not turned on by default.
+
+     HHooww ttoo sseett kkeerrnneell--ssppeecciiffiicc ooppttiioonnss??
+        There are a few kernel configuration options that affect the
+        PCMCIA tools.  The configuration script can deduce these from
+        the running kernel (the default and most common case).
+        Alternatively, if you are compiling for installation on another
+        machine, it can read the configuration from a kernel source
+        tree, or each option can be set interactively.
+
+  The Configure script can also be executed non-interactively, for
+  automatic builds or to quickly reconfigure after a kernel update.
+  Some additional less-frequently-used options can be only be set from
+  the command line.  Running ``Configure --help'' lists all available
+  options.
+
+  Running ``make all'' followed by ``make install'' will build and then
+  install the kernel modules and utility programs.  Kernel modules are
+  installed under /lib/modules/<version>/pcmcia.  The cardmgr and
+  cardctl programs are installed in /sbin.  If cardinfo is built, it is
+  installed in /usr/bin/X11.
+
+  Configuration files will be installed in the /etc/pcmcia directory.
+  If you are installing over an older version, your old config scripts
+  will be backed up before being replaced.  The saved scripts will be
+  given an *.O extension.
+
+  If you don't know what kind of host controller your system uses, you
+  can use the probe utility in the cardmgr/ subdirectory to determine
+  this.  There are two major types: the Databook TCIC-2 type and the
+  Intel i82365SL-compatible type.
+
+  In a few cases, the probe command will be unable to determine your
+  controller type automatically.  If you have a Halikan NBD 486 system,
+  it has a TCIC-2 controller at an unusual location: you'll need to edit
+  rc.pcmcia to load the tcic module, and also set the PCIC_OPTS
+  parameter to ``tcic_base=0x02c0''.
+
+  On some systems using Cirrus controllers, including the NEC Versa M,
+  the BIOS puts the controller in a special suspended state at system
+  startup time.  On these systems, the probe command will fail to find
+  any known host controller.  If this happens, edit rc.pcmcia and set
+  PCIC to i82365, and PCIC_OPTS to ``wakeup=1''.
+
+  22..33..  SSttaarrttuupp ooppttiioonnss
+
+  The PCMCIA startup script recognizes several groups of startup
+  options, set via environment variables.  Multiple options should be
+  separated by spaces and enclosed in quotes.  Placement of startup
+  options depends on the Linux distribution used.  They may be placed
+  directly in the startup script, or they may be kept in a separate
+  option file.  See the ``Notes about specific Linux distributions'' for
+  specifics.  The following variables can be set:
+
+     PCMCIA
+        This variable specifies whether PCMCIA support should be started
+        up, or not.  If it is set to anything other than ``yes'', then
+        the startup script will be disabled.
+
+     PCIC
+        This identifies the PC Card Interface Controller driver module.
+        There are two options: ``tcic'' or ``i82365''.  Virtually all
+        current controllers are in the ``i82365'' group.  This is the
+        only mandatory option setting.
+
+     PCIC_OPTS
+        This specifies options for the PCIC module.  Some host
+        controllers have optional features that may or may not be
+        implemented in a particular system.  In some cases, it is
+        impossible for the socket driver to detect if these features are
+        implemented.  See the corresponding man page for a complete
+        description of the available options.
+
+     CORE_OPTS
+        This specifies options for the pcmcia_core module, which
+        implements the core PC Card driver services.  See ``man
+        pcmcia_core'' for more information.
+
+     CARDMGR_OPTS
+        This specifies options to be passed to the cardmgr daemon.  See
+        ``man cardmgr'' for more information.
+
+     SCHEME
+        If set, then the PC Card configuration scheme will be
+        initialized to this at driver startup time.  See the ``Overview
+        of the PCMCIA configuration scripts'' for a discussion of
+        schemes.
+
+  The low level socket drivers, tcic and i82365, have various bus timing
+  parameters that may need to be adjusted for certain systems with
+  unusual bus clocking.  Symptoms of timing problems can include card
+  recognition problems, lock-ups under heavy loads, high error rates, or
+  poor device performance.  Only certain host bridges have adjustable
+  timing parameters: check the corresponding man page to see what
+  options are available for your controller.  Here is a brief summary:
+
+  +o  Cirrus controllers have numerous configurable timing parameters.
+     The most important seems to be the cmd_time flag, which determines
+     the length of PCMCIA bus cycles.  Fast 486 systems (i.e., DX4-100)
+     seem to often benefit from increasing this from 6 (the default) to
+     12 or 16.
+
+  +o  The Cirrus PD6729 PCI controller has the fast_pci flag, which
+     should be set if the PCI bus speed is greater than 25 MHz.
+  +o  For Vadem VG-468 controllers, the async_clock flag changes the
+     relative clocking of PCMCIA bus and host bus cycles.  Setting this
+     flag adds extra wait states to some operations.  However, I have
+     yet to hear of a laptop that needs this.
+
+  +o  The pcmcia_core module has the cis_speed parameter for changing the
+     memory speed used for accessing a card's Card Information Structure
+     (CIS).  On some systems with fast bus clocks, increasing this
+     parameter (i.e., slowing down card accesses) may be beneficial for
+     card recognition problems.
+
+  +o  This is not a timing issue, but if you have more than one ISA-to-
+     PCMCIA controller in your system or extra sockets in a laptop
+     docking station, the i82365 module should be loaded with the
+     extra_sockets parameter set to 1.  This should not be necessary for
+     detection of PCI-to-PCMCIA or PCI-to-CardBus bridges.
+
+  +o  With SCM Microsystems SBP series PCI card readers (which are also
+     being distributed with Lucent WaveLan cards), it is necessary to
+     specify irq_mode=0 for the i82365 module, to force use of PCI
+     interrupts.
+
+  Here are some timing settings for specific systems:
+
+  +o  On the ARM Pentium-90 or Midwest Micro Soundbook Plus, use
+     ``freq_bypass=1 cmd_time=8''.
+
+  +o  On a Midwest Micro Soundbook Elite, use ``cmd_time=12''.
+
+  +o  On a Gateway Liberty, try ``cmd_time=16''.
+
+  +o  On a Samsung SENS 810, use ``fast_pci=1''.
+
+  22..44..  SSyysstteemm rreessoouurrccee sseettttiinnggss
+
+  Card Services should automatically avoid allocating IO ports and
+  interrupts already in use by other standard devices.  It will also
+  attempt to detect conflicts with unknown devices, but this is not
+  completely reliable.  In some cases, you may need to explicitly
+  exclude resources for a device in /etc/pcmcia/config.opts.
+
+  Here are some resource settings for specific laptop types.  View this
+  list with suspicion: it may give useful hints for solving problems,
+  but it is inevitably out of date and certainly contains mistakes.
+  Corrections and additions are welcome.
+
+  +o  On the AMS SoundPro, exclude irq 10.
+
+  +o  On some AMS TravelPro 5300 models, use memory 0xc8000-0xcffff.
+
+  +o  On the BMX 486DX2-66, exclude irq 5, irq 9.
+
+  +o  On the Chicony NB5, use memory 0xda000-0xdffff.
+
+  +o  On the Compaq Presario 1020, exclude port 0x2f8-0x2ff, irq 3, irq
+     5.
+
+  +o  On the Dell Inspiron 7000, exclude irq 3, irq 5.
+
+  +o  On the Fujitsu C series, exclude port 0x200-0x27f.
+
+  +o  On the HP Omnibook 4000C, exclude port 0x300-0x30f.
+
+  +o  On the IBM ThinkPad 380, and maybe the 385 and 600 series, exclude
+     port 0x230-0x233, and irq 5.
+
+  +o  On IBM ThinkPad 600 and 770 models with internal modems, exclude
+     port 0x2f8-0x2ff.
+
+  +o  On the IBM ThinkPad 600E and 770Z, change the high memory window to
+     0x60000000-0x60ffffff.
+
+  +o  On the Micron Millenia Transport, exclude irq 5, irq 9.
+
+  +o  On the NEC Versa M, exclude irq 9, port 0x2e0-2ff.
+
+  +o  On the NEC Versa P/75, exclude irq 5, irq 9.
+
+  +o  On the NEC Versa S, exclude irq 9, irq 12.
+
+  +o  On the NEC Versa 6000 series, exclude port 0x2f8-0x33f, irq 9, irq
+     10.
+
+  +o  On the NEC Versa SX, exclude port 0x300-0x31f.
+
+  +o  On the ProStar 9200, Altima Virage, and Acquiline Hurricane
+     DX4-100, exclude irq 5, port 0x330-0x35f.  Maybe use memory
+     0xd8000-0xdffff.
+
+  +o  On the Siemens Nixdorf SIMATIC PG 720C, use memory 0xc0000-0xcffff,
+     port 0x300-0x3bf.
+
+  +o  On the TI TravelMate 5000, use memory 0xd4000-0xdffff.
+
+  +o  On the Toshiba Satellite 4030CDS, exclude irq 9.
+
+  +o  On the Toshiba T4900 CT, exclude irq 5, port 0x2e0-0x2e8, port
+     0x330-0x338.
+
+  +o  On the Toshiba Tecra 8000, exclude irq 3, irq 5, irq 9.
+
+  +o  On the Twinhead 5100, HP 4000, Sharp PC-8700 and PC-8900, exclude
+     irq 9 (sound), irq 12.
+
+  +o  On an MPC 800 Series, exclude irq 5, port 0x300-0x30f for the CD-
+     ROM.
+
+  22..55..  NNootteess aabboouutt ssppeecciiffiicc LLiinnuuxx ddiissttrriibbuuttiioonnss
+
+  This section is incomplete.  Corrections and additions are welcome.
+
+  22..55..11..  DDeebbiiaann
+
+  Debian uses a System V boot script arrangement.  The PCMCIA startup
+  script is installed as /etc/init.d/pcmcia, and startup options are
+  specified in /etc/pcmcia.conf.  Debian's syslog configuration will
+  place kernel messages in /var/log/messages and cardmgr messages in
+  /var/log/daemon.log.
+
+  Debian distributes the PCMCIA system in two packages: the ``pcmcia-
+  cs'' package contains cardmgr and other tools, man pages, and
+  configuration scripts; and the ``pcmcia-modules'' package contains the
+  kernel driver modules.
+
+  22..55..22..  RReedd HHaatt,, CCaallddeerraa,, MMaannddrraakkee
+
+  These distributions use a System V boot script organization.  The
+  PCMCIA startup script is installed as /etc/rc.d/init.d/pcmcia, and
+  boot options are kept in /etc/sysconfig/pcmcia.  Beware that
+  installing the Red Hat package may install a default boot option file
+  that has PCMCIA disabled.  To enable PCMCIA, the ``PCMCIA'' variable
+  should be set to ``yes''.  Red Hat's default syslogd configuration
+  will record all interesting messages in /var/log/messages.
+
+  Red Hat's PCMCIA package contains a replacement for the network setup
+  script, /etc/pcmcia/network, which meshes with the Red Hat linuxconf
+  configuration system.  This is convenient for the case where just one
+  network adapter is used, with one set of network parameters, but does
+  not have the full flexibility of the regular PCMCIA network script.
+  Compiling and installing a clean PCMCIA source distribution will
+  overwrite the network script, breaking the link to the Red Hat tools.
+  If you prefer using the Red Hat tools, either use only Red Hat RPM's,
+  or replace /etc/pcmcia/network.opts with the following:
+
+       if [ -f /etc/sysconfig/network-scripts/ifcfg-eth0 ] ; then
+           start_fn () {
+               /sbin/ifup $1
+           }
+           stop_fn () {
+               /sbin/ifdown $1
+           }
+       fi
+
+  If you do use linuxconf (or netconf) to configure your network
+  interface, leave the ``kernel module'', ``I/O port'', and ``irq''
+  parameters blank.  Setting these parameters may interfere with proper
+  operation of the PCMCIA subsystem.
+
+  At boot time, when the Red Hat network subsystem starts up, it may say
+  ``Delaying eth0 initialization'' and ``[FAILED]''.  This is actually
+  not a failure: it means that this network interface will not be
+  initialized until after the PCMCIA network device is configured.
+
+  Red Hat bundles their slightly modified PCMCIA source distribution in
+  their kernel SRPM, rather than as a separate source package.
+
+  22..55..33..  SSllaacckkwwaarree
+
+  Slackware uses a BSD boot script arrangement.  The PCMCIA startup
+  script is installed as /etc/rc.d/rc.pcmcia, and boot options are
+  specified in rc.pcmcia itself.  The PCMCIA startup script is invoked
+  from /etc/rc.d/rc.S.
+
+  22..55..44..  SSuuSSEE
+
+  SuSE uses a System V init script arrangement, with init scripts stored
+  under /sbin/init.d.  The PCMCIA startup script is installed as
+  /sbin/init.d/pcmcia, and startup options are kept in /etc/rc.config.
+  The SuSE startup script is somewhat limited and does not allow PCMCIA
+  startup variables to be overridden from the lilo boot prompt.
+
+  33..  RReessoollvviinngg iinnssttaallllaattiioonn aanndd ccoonnffiigguurraattiioonn pprroobblleemmss
+
+  This section describes some of the most common failure modes for the
+  PCMCIA subsystem.  Try to match your symptoms against the examples.
+  This section only describes general failures that are not specific to
+  a particular client driver or type of card.
+
+  Before trying to diagnose a problem, you have to know where your
+  system log is kept (see ``Notes about specific Linux distributions'').
+  You should also be familiar with basic diagnostic tools like dmesg and
+  lsmod.  Also, be aware that most driver components (including all the
+  kernel modules) have their own individual man pages.
+
+  In 3.1.15 and later releases, the debug-tools subdirectory of the
+  PCMCIA source tree has a few scripts to help diagnose some of the most
+  common configuration problems.  The test_setup script checks your
+  PCMCIA installation for completeness.  The test_network and test_modem
+  scripts will try to diagnose problems with PCMCIA network and modem
+  cards.  These scripts can be particularly helpful if you are
+  unfamiliar with Linux and are not sure how to approach a problem.
+
+  Try to define your problem as narrowly as possible.  If you have
+  several cards, try each card in isolation, and in different
+  combinations.  Try cold Linux boots, versus warm boots from Windows.
+  Compare booting with cards inserted, versus inserting cards after
+  boot.  If you normally use your laptop docked, try it undocked.  And
+  sometimes, two sockets will behave differently.
+
+  It is nearly impossible to debug driver problems encountered when
+  attempting to install Linux via a PCMCIA device.  Even if you can
+  identify the problem based on its symptoms, installation disks are
+  difficult to modify, especially without access to a running Linux
+  system.  Customization of installation disks is completely dependent
+  on the choice of Linux distribution, and is beyond the scope of this
+  document.  In general, the best course of action is to install Linux
+  using some other means, obtain the latest drivers, and then debug the
+  problem if it persists.
+
+  33..11..  BBaassee PPCCMMCCIIAA kkeerrnneell mmoodduulleess ddoo nnoott llooaadd
+
+  Symptoms:
+
+  +o  Kernel version mismatch errors are reported when the PCMCIA startup
+     script runs.
+
+  +o  After startup, lsmod does not show any PCMCIA modules.
+
+  +o  cardmgr reports ``no pcmcia driver in /proc/devices'' in the system
+     log.
+
+  Kernel modules contain version information that is checked against the
+  current kernel when a module is loaded.  The type of checking depends
+  on the setting of the CONFIG_MODVERSIONS kernel option.  If this is
+  false, then the kernel version number is compiled into each module,
+  and insmod checks this for a match with the running kernel.  If
+  CONFIG_MODVERSIONS is true, then each symbol exported by the kernel is
+  given a sort of checksum.  These codes are all compared against the
+  corresponding codes compiled into a module.  The intent was for this
+  to make modules less version-dependent, because the checksums would
+  only change if a kernel interface changed, and would generally stay
+  the same across minor kernel updates.  In practice, the checksums have
+  turned out to be even more restrictive, because many kernel interfaces
+  depend on compile-time kernel option settings.  Also, the checksums
+  turned out to be an excessively pessimistic judge of compatibility.
+
+  The practical upshot of this is that kernel modules are closely tied
+  to both the kernel version, and the setting of many kernel
+  configuration options.  Generally, a set of modules compiled for one
+  2.0.31 kernel will not load against some other 2.0.31 kernel unless
+  special care is taken to ensure that the two were built with similar
+  configurations.  This makes distribution of precompiled kernel modules
+  a tricky business.
+
+  You have several options:
+
+  +o  If you obtained precompiled drivers as part of a Linux
+     distribution, verify that you are using an unmodified kernel as
+     supplied with that distribution.  If you intend to use precompiled
+     modules, you generally must stick with the corresponding kernel.
+
+  +o  If you have reconfigured or upgraded your kernel, you will probably
+     need to compile and install the PCMCIA package from scratch.  This
+     is easily done if you already have the kernel source tree
+     installed.  See ``Compilation and installation'' for detailed
+     instructions.
+
+  +o  In some cases, incompatibilities in other system components can
+     prevent correct loading of kernel modules.  If you have upgraded
+     your own kernel, pay attention to the ``minimal requirements'' for
+     module utilities and binutils listed in the Documentation/Changes
+     file in the kernel source code tree.
+
+  33..22..  SSoommee cclliieenntt ddrriivveerr mmoodduulleess ddoo nnoott llooaadd
+
+  Symptoms:
+
+  +o  The base modules (pcmcia_core, ds, i82365) load correctly.
+
+  +o  Inserting a card gives a high beep + low beep pattern.
+
+  +o  cardmgr reports version mismatch errors in the system log.
+
+  Some of the driver modules require kernel services that may or may not
+  be present, depending on kernel configuration.  For instance, the SCSI
+  card drivers require that the kernel be configured with SCSI support,
+  and the network drivers require a networking kernel.  If a kernel
+  lacks a necessary feature, insmod may report undefined symbols and
+  refuse to load a particular module. Note that insmod error messages do
+  not distinguish between version mismatch errors and missing symbol
+  errors.
+
+  Specifically:
+
+  +o  The serial client driver serial_cs requires the kernel serial
+     driver to be enabled with CONFIG_SERIAL.  This driver may be built
+     as a module.
+
+  +o  Support for multiport serial cards or multifunction cards that
+     include serial or modem devices requires CONFIG_SERIAL_SHARE_IRQ to
+     be enabled.
+
+  +o  The SCSI client drivers require that CONFIG_SCSI be enabled, along
+     with the appropriate top level driver options (CONFIG_BLK_DEV_SD,
+     CONFIG_BLK_DEV_SR, etc for 2.1 kernels).  These may be built as
+     modules.
+
+  +o  The network client drivers require that CONFIG_INET is enabled.
+     Kernel networking support cannot be compiled as a module.
+  +o  The token-ring client requires that the kernel be compiled with
+     CONFIG_TR enabled.
+
+  There are two ways to proceed:
+
+  +o  Rebuild your kernel with the necessary features enabled.
+
+  +o  If the features have been compiled as modules, then modify
+     /etc/pcmcia/config to preload these modules.
+
+  The /etc/pcmcia/config file can specify that additional modules need
+  to be loaded for a particular client.  For example, for the serial
+  driver, one would use:
+
+       device "serial_cs"
+         class "serial" module "misc/serial", "serial_cs"
+
+  Module paths are specified relative to the top-level module directory
+  for the current kernel version; if no relative path is given, then the
+  path defaults to the pcmcia subdirectory.
+
+  33..33..  IInntteerrrruupptt ssccaann ffaaiilluurreess
+
+  Symptoms:
+
+  +o  The system locks up when the PCMCIA drivers are loaded, even with
+     no cards present.
+
+  +o  The system log shows a successful host controller probe just before
+     the lock-up, but does not show interrupt probe results.
+
+  After identifying the host controller type, the socket driver probes
+  for free interrupts.  The probe involves programming the controller
+  for each apparently free interrupt, then generating a ``soft''
+  interrupt, to see if the interrupt can be detected correctly.  In some
+  cases, probing a particular interrupt can interfere with another
+  system device.
+
+  The reason for the probe is to identify interrupts which appear to be
+  free (i.e., are not reserved by any other Linux device driver), yet
+  are either not physically wired to the host controller, or are
+  connected to another device that does not have a driver.
+
+  In the system log, a successful probe might look like:
+
+       Intel PCIC probe:
+         TI 1130 CardBus at mem 0x10211000, 2 sockets
+         ...
+         ISA irqs (scanned) = 5,7,9,10 status change on irq 10
+
+  There are two ways to proceed:
+
+  +o  The interrupt probe can be restricted to a list of interrupts using
+     the irq_list parameter for the socket drivers.  For example,
+     ``irq_list=5,9,10'' would limit the scan to three interrupts.  All
+     PCMCIA devices will be restricted to using these interrupts
+     (assuming they pass the probe).  You may need to use trial and
+     error to find out which interrupts can be safely probed.
+
+  +o  The interrupt probe can be disabled entirely by loading the socket
+     driver with the ``do_scan=0'' option.  In this case, a default
+     interrupt list will be used, which avoids interrupts already
+     allocated for other devices.
+
+  In either case, the probe options can be specified using the PCIC_OPTS
+  definition in the PCMCIA startup script, for example:
+
+       PCIC_OPTS="irq_list=5,9,10"
+
+  It should be noted that /proc/interrupts is completely useless when it
+  comes to diagnosing interrupt probe problems.  The probe is sensible
+  enough to never attempt to use an interrupt that is already in use by
+  another Linux driver.  So, the PCMCIA drivers are already using all
+  the information in /proc/interrupts.  Depending on system design, an
+  inactive device can still occupy an interrupt and cause trouble if it
+  is probed for PCMCIA.
+
+  33..44..  IIOO ppoorrtt ssccaann ffaaiilluurreess
+
+  Symptoms:
+
+  +o  The system locks up when cardmgr is first started, even with no
+     cards present.
+
+  +o  The system log shows a successful host controller probe, including
+     interrupt probe results, but does not show IO probe results.
+
+  +o  In some cases, the IO probe will succeed, but report large numbers
+     of random exclusions.
+
+  When cardmgr processes IO port ranges listed in
+  /etc/pcmcia/config.opts, the kernel probes these ranges to detect
+  latent devices that occupy IO space but are not associated with a
+  Linux driver.  The probe is read-only, but in rare cases, reading from
+  a device may interfere with an important system function, resulting in
+  a lock-up.
+
+  Your system user's guide may include a map of system devices, showing
+  their IO and memory ranges.  These can be explicitly excluded in
+  config.opts.
+
+  Alternatively, if the probe is unreliable on your system, it can be
+  disabled by setting CORE_OPTS to ``probe_io=0''.  In this case, you
+  should be very careful to specify only genuinely available ranges of
+  ports in config.opts, instead of using the default settings.
+
+  33..55..  MMeemmoorryy pprroobbee ffaaiilluurreess
+
+  Symptoms:
+
+  +o  The core drivers load correctly when no cards are present, with no
+     errors in the system log.
+
+  +o  The system freezes and/or reboots as soon as any card is inserted,
+     before any beeps are heard.
+
+  Or alternately:
+
+  +o  All card insertions generate a high beep followed by a low beep.
+
+  +o  All cards are identified as ``anonymous memory cards''.
+
+  +o  The system log reports that various memory ranges have been
+     excluded.
+
+  The core modules perform a memory scan at the time of first 16-bit
+  card insertion.  This scan can potentially interfere with other memory
+  mapped devices.  Also, pre-3.0.0 driver packages perform a more
+  aggressive scan than more recent drivers.  The memory window is
+  defined in /etc/pcmcia/config.opts.  The default window is large, so
+  it may help to restrict the scan to a narrower range.  Reasonable
+  ranges to try include 0xd0000-0xdffff, 0xc0000-0xcffff,
+  0xc8000-0xcffff, or 0xd8000-0xdffff.
+
+  If you have DOS or Windows PCMCIA drivers, you may be able to deduce
+  what memory region those drivers use.  Note that DOS memory addresses
+  are often specified in ``segment'' form, which leaves off the final
+  hex digit (so an absolute address of 0xd0000 might be given as
+  0xd000).  Be sure to add the extra digit back when making changes to
+  config.opts.
+
+  In unusual cases, a memory probe failure can indicate a timing
+  register setup problem with the host controller.  See the ``Startup
+  options'' section for information about dealing with common timing
+  problems.
+
+  +o  cs: warning: no high memory space available!
+
+  CardBus bridges can allocate memory windows outside of the 640KB-1MB
+  ``memory hole'' in the ISA bus architecture.  It is generally a good
+  idea to configure CardBus bridges to use high memory windows, because
+  these are unlikely to conflict with other devices.  Also, CardBus
+  cards may require large memory windows, which may be difficult or
+  impossible to fit into low memory.  Card Services will preferentially
+  allocate windows in high memory for CardBus bridges, if both low and
+  high memory windows are defined in config.opts.  The default
+  config.opts now includes a high memory window of
+  0xa0000000-0xa0ffffff.  If you have a CardBus bridge and have upgraded
+  from an older PCMCIA driver release, add this memory window if it is
+  not already defined.
+
+  In some cases, the default high memory window is not usable.  On some
+  IBM Thinkpad models, a window of 0x60000000-0x60ffffff will work in
+  place of the default window.
+
+  33..66..  FFaaiilluurree ttoo ddeetteecctt ccaarrdd iinnsseerrttiioonnss aanndd rreemmoovvaallss
+
+  Symptoms:
+
+  +o  Cards are detected and configured properly if present at boot time.
+
+  +o  The drivers do not respond to insertion and removal events, either
+     by recording events in the system log, or by beeping.
+  In most cases, the socket driver (i82365 or tcic) will automatically
+  probe and select an appropriate interrupt to signal card status
+  changes.  The automatic interrupt probe doesn't work on some Intel-
+  compatible controllers, including Cirrus chips and the chips used in
+  some IBM ThinkPads.  If a device is inactive at probe time, its
+  interrupt may also appear to be available.  In these cases, the socket
+  driver may pick an interrupt that is used by another device.
+
+  With the i82365 and tcic drivers, the irq_list option can be used to
+  limit the interrupts that will be tested.  This list limits the set of
+  interrupts that can be used by PCMCIA cards as well as for monitoring
+  card status changes.  The cs_irq option can also be used to explicitly
+  set the interrupt to be used for monitoring card status changes.
+
+  If you can't find an interrupt number that works, there is also a
+  polled status mode: both i82365 and tcic will accept a
+  poll_interval=100 option, to poll for card status changes once per
+  second.  This option should also be used if your system has a shortage
+  of interrupts available for use by PCMCIA cards.  Especially for
+  systems with more than one host controller, there is little point in
+  dedicating interrupts for monitoring card status changes.
+
+  All these options should be set in the PCIC_OPTS= line in either
+  /etc/rc.d/rc.pcmcia or /etc/sysconfig/pcmcia, depending on your site
+  setup.
+
+  33..77..  IInntteerrrruupptt ddeelliivveerryy pprroobblleemmss
+
+  Symptoms:
+
+  +o  Cards appear to be configured successfully, but don't work.
+
+  +o  Serial and modem cards may respond very sluggishly.
+
+  +o  Network cards may report ``interrupt(s) dropped'', and/or transmit
+     timeouts.
+
+  The most simple interrupt delivery problems are due to conflicts with
+  other system devices.  These can generally be resolved by excluding
+  problem interrupts in /etc/pcmcia/config.opts.  To test, just exclude
+  interrupts one by one until either the problem is fixed or you run out
+  of interrupts.  If no interrupts work, then device conflicts are
+  probably not the problem.
+
+  CardBus bridges usually support two types of interrupts, PCI and ISA.
+  Partly for historical reasons, it has become conventional to use PCI
+  interrupts for signaling card insertion and removal events, and for
+  CardBus card interrupts; and ISA interrupts for 16-bit cards.  Since
+  version 3.1.9, this is the scheme that the Linux PCMCIA system will
+  use by default.  Most CardBus bridges support multiple methods for
+  delivering interrupts to the host CPU.  Methods include ``parallel''
+  interrupts, where each supported irq has a dedicated pin on the
+  bridge; various serial interrupt protocols, where one or two pins are
+  used to communicate with an interrupt controller; and hybrids, where,
+  for instance, PCI interrupts may be signalled using dedicated pins,
+  while ISA interrupts are delivered via a serial controller.
+
+  In general, it is the responsibility of the BIOS to program a bridge
+  for the appropriate interrupt delivery method.  However, there are
+  systems that do this incorrectly, and in some cases, there is no way
+  for software to safely detect the correct delivery method.  The i82365
+  module reports the bridge mode at startup time, and has a parameter,
+  irq_mode, that can be used to reconfigure it.  Not all bridges support
+  this parameter, and the meaning of irq_mode depends on the bridge
+  type.  See the i82365 man page for a description of what values are
+  supported by your bridge.  In some cases, a bridge may function
+  correctly in more than one interrupt mode.
+
+  Most PCMCIA card readers that fit in a PCI bus slot only provide PCI
+  interrupt routing.  The Linux drivers assume that all bridges have ISA
+  interrupt capability, since that is usually correct.  In this case, it
+  will be necessary to use the irq_mode parameter to specify a ``PCI
+  only'' interrupt delivery mode; the value of the parameter depends on
+  the bridge type, so check the i82365 man page.
+
+  33..88..  SSyysstteemm rreessoouurrccee ssttaarrvvaattiioonn
+
+  Symptoms:
+
+  +o  When a card is inserted, it is identified correctly but cannot be
+     configured (high/low beep pattern).
+
+  +o  One of the following messages will appear in the system log:
+
+       RequestIO: Resource in use
+       RequestIRQ: Resource in use
+       RequestWindow: Resource in use
+       GetNextTuple: No more items
+       could not allocate nn IO ports for CardBus socket n
+       could not allocate nnK memory for CardBus socket n
+       could not allocate interrupt for CardBus socket n
+
+  Interrupt starvation often indicates a problem with the interrupt
+  probe (see ``Interrupt scan failures'').  In some cases, the probe
+  will seem to work, but only report one or two available interrupts.
+  Check your system log to see if the scan results look sensible.
+  Disabling the probe and selecting interrupts manually should help.
+
+  If the interrupt probe is not working properly, the socket driver may
+  allocate an interrupt for monitoring card insertions, even when
+  interrupts are too scarce for this to be a good idea.  In that case,
+  you can switch the controller to polled mode by setting PCIC_OPTS to
+  ``poll_interval=100'.  Or, if you have a CardBus controller, try
+  ``pci_csc=1'', which selects a PCI interrupt (if available) for card
+  status changes.
+
+  IO port starvation is fairly uncommon, but sometimes happens with
+  cards that require large, contiguous, aligned regions of IO port
+  space, or that only recognize a few specific IO port positions.  The
+  default IO port ranges in /etc/pcmcia/config.opts are normally
+  sufficient, but may be extended.  In rare cases, starvation may
+  indicate that the IO port probe failed (see ``IO port scan
+  failures'').
+
+  Memory starvation is also uncommon with the default memory window
+  settings in config.opts.  CardBus cards may require larger memory
+  regions than typical 16-bit cards.  Since CardBus memory windows can
+  be mapped anywhere in the host's PCI address space (rather than just
+  in the 640K-1MB ``hole'' in PC systems), it is helpful to specify
+  large memory windows in high memory, such as 0xa0000000-0xa0ffffff.
+
+  33..99..  RReessoouurrccee ccoonnfflliicctt oonnllyy wwiitthh ttwwoo ccaarrddss iinnsseerrtteedd
+
+  Symptoms:
+
+  +o  Two cards each work fine when used separately.
+
+  +o  When both cards are inserted, only one works.
+
+  This usually indicates a resource conflict with a system device that
+  Linux does not know about.  PCMCIA devices are dynamically configured,
+  so, for example, interrupts are allocated as needed, rather than
+  specifically assigned to particular cards or sockets.  Given a list of
+  resources that appear to be available, cards are assigned resources in
+  the order they are configured.  In this case, the card configured last
+  is being assigned a resource that in fact is not free.
+
+  Check the system log to see what resources are used by the non-working
+  card.  Exclude these in /etc/pcmcia/config.opts, and restart the
+  cardmgr daemon to reload the resource database.
+
+  33..1100..  DDeevviiccee ccoonnffiigguurraattiioonn ddooeess nnoott ccoommpplleettee
+
+  Symptoms:
+
+  +o  When a card is inserted, exactly one high beep is heard.
+
+  +o  Subsequent card insertions and removals may be ignored.
+
+  This indicates that the card was identified successfully, however,
+  cardmgr has been unable to complete the configuration process for some
+  reason.  The most likely reason is that a step in the card setup
+  script has blocked.  A good example would be the network script
+  blocking if a network card is inserted with no actual network hookup
+  present.
+
+  To pinpoint the problem, you can manually run a setup script to see
+  where it is blocking.  The scripts are in the /etc/pcmcia directory.
+  They take two parameters: a device name, and an action.  The cardmgr
+  daemon records the configuration commands in the system log.  For
+  example, if the system log shows that the command ``./network start
+  eth0'' was the last command executed by cardmgr, the following command
+  would trace the script:
+
+       sh -x /etc/pcmcia/network start eth0
+
+  44..  UUssaaggee aanndd ffeeaattuurreess
+
+  44..11..  TToooollss ffoorr ccoonnffiigguurriinngg aanndd mmoonniittoorriinngg PPCCMMCCIIAA ddeevviicceess
+
+  If the modules are all loaded correctly, the output of the lsmod
+  command should look like the following, when no cards are inserted:
+
+  Module                  Size  Used by
+  ds                      5640   2
+  i82365                 15452   2
+  pcmcia_core            30012   3  [ds i82365]
+
+  The system log should also include output from the socket driver
+  describing the host controller(s) found and the number of sockets
+  detected.
+
+  44..11..11..  TThhee ccaarrddmmggrr ccoonnffiigguurraattiioonn ddaaeemmoonn
+
+  The cardmgr daemon is responsible for monitoring PCMCIA sockets,
+  loading client drivers when needed, and running user-level scripts in
+  response to card insertions and removals.  It records its actions in
+  the system log, but also uses beeps to signal card status changes.
+  The tones of the beeps indicate success or failure of particular
+  configuration steps.  Two high beeps indicate that a card was
+  identified and configured successfully.  A high beep followed by a low
+  beep indicates that a card was identified, but could not be configured
+  for some reason.  One low beep indicates that a card could not be
+  identified.
+
+  The cardmgr daemon configures cards based on a database of known card
+  types kept in /etc/pcmcia/config.  This file describes the various
+  client drivers, then describes how to identify various cards, and
+  which driver(s) belong with which cards.  The format of this file is
+  described in the pcmcia(5) man page.
+
+  44..11..22..  TThhee ssoocckkeett ssttaattuuss ffiillee,, ssttaabb
+
+  Cardmgr records device information for each socket in
+  /var/state/pcmcia/stab or /var/lib/pcmcia/stab, depending on
+  filesystem layout.  Here is a sample stab listing:
+
+       Socket 0: Adaptec APA-1460 SlimSCSI
+       0       scsi    aha152x_cs      0       sda     8       0
+       0       scsi    aha152x_cs      1       scd0    11      0
+       Socket 1: Serial or Modem Card
+       1       serial  serial_cs       0       ttyS1   5       65
+
+  For the lines describing devices, the first field is the socket, the
+  second is the device class, the third is the driver name, the fourth
+  is used to number multiple devices associated with the same driver,
+  the fifth is the device name, and the final two fields are the major
+  and minor device numbers for this device (if applicable).  See the
+  stab man page for more info.
+
+  44..11..33..  TThhee ccaarrddccttll aanndd ccaarrddiinnffoo uuttiilliittiieess
+
+  The cardctl command can be used to check the status of a socket, or to
+  see how it is configured.  It can also be used to alter the
+  configuration status of a card.  Here is an example of the output of
+  the ``cardctl config'' command:
+       Socket 0:
+         not configured
+       Socket 1:
+         Vcc = 5.0, Vpp1 = 0.0, Vpp2 = 0.0
+         Card type is memory and I/O
+         IRQ 3 is dynamic shared, level mode, enabled
+         Speaker output is enabled
+         Function 0:
+           Config register base = 0x0800
+             Option = 0x63, status = 0x08
+           I/O window 1: 0x0280 to 0x02bf, auto sized
+           I/O window 2: 0x02f8 to 0x02ff, 8 bit
+
+  Or ``cardctl ident'', to get card identification information:
+
+       Socket 0:
+         no product info available
+       Socket 1:
+         product info: "LINKSYS", "PCMLM336", "A", "0040052D6400"
+         manfid: 0x0143, 0xc0ab
+         function: 0 (multifunction)
+
+  The ``cardctl suspend'' and ``cardctl resume'' commands can be used to
+  shut down a card without unloading its associated drivers.  The
+  ``cardctl reset'' command attempts to reset and reconfigure a card.
+  ``cardctl insert'' and ``cardctl eject'' mimic the actions performed
+  when a card is physically inserted or ejected, including loading or
+  unloading drivers, and configuring or shutting down devices.
+
+  If you are running X, the cardinfo utility produces a graphical
+  display showing the current status of all PCMCIA sockets, similar in
+  content to ``cardctl config''.  It also provides a graphical interface
+  to most other cardctl functions.
+
+  44..11..44..  IInnsseerrttiinngg aanndd eejjeeccttiinngg ccaarrddss
+
+  In theory, you can insert and remove PCMCIA cards at any time.
+  However, it is a good idea not to eject a card that is currently being
+  used by an application program.  Kernels older than 1.1.77 would often
+  lock up when serial/modem cards were ejected, but this should be fixed
+  now.
+
+  Some card types cannot be safely hot ejected.  Specifically, ATA/IDE
+  and SCSI interface cards are not hot-swap-safe.  This is unlikely to
+  be fixed, because a complete solution would require significant
+  changes to the Linux block device model.  Also, it is generally not
+  safe to hot eject CardBus cards of any type.  This is likely to
+  improve gradually as hot swap bugs in the CardBus drivers are found
+  and fixed.  For these card types (IDE, SCSI, CardBus), it is
+  recommended that you always use ``cardctl eject'' before ejecting.
+
+  44..11..55..  CCaarrdd SSeerrvviicceess aanndd AAddvvaanncceedd PPoowweerr MMaannaaggeemmeenntt
+
+  Card Services can be compiled with support for APM (Advanced Power
+  Management) if you've configured your kernel with APM support.  The
+  APM kernel driver is maintained by Stephen Rothwell
+  (Stephen.Rothwell@canb.auug.org.au).  The apmd daemon is maintained by
+  Avery Pennarun (apenwarr@worldvisions.ca), with more information
+  available at <http://www.worldvisions.ca/~apenwarr/apmd/>.  The PCMCIA
+  modules will automatically be configured for APM if a compatible
+  version is detected on your system.
+
+  Whether or not APM is configured, you can use ``cardctl suspend''
+  before suspending your laptop, and ``cardctl resume'' after resuming,
+  to cleanly shut down and restart your PCMCIA cards.  This will not
+  work with a modem that is in use, because the serial driver isn't able
+  to save and restore the modem operating parameters.
+
+  APM seems to be unstable on some systems.  If you experience trouble
+  with APM and PCMCIA on your system, try to narrow down the problem to
+  one package or the other before reporting a bug.
+
+  Some drivers, notably the PCMCIA SCSI drivers, cannot recover from a
+  suspend/resume cycle.  When using a PCMCIA SCSI card, always use
+  ``cardctl eject'' prior to suspending the system.
+
+  44..11..66..  SShhuuttttiinngg ddoowwnn tthhee PPCCMMCCIIAA ssyysstteemm
+
+  To unload the entire PCMCIA package, invoke rc.pcmcia with:
+
+       /etc/rc.d/rc.pcmcia stop
+
+  This script will take several seconds to run, to give all client
+  drivers time to shut down gracefully.  If a device is currently in
+  use, the shutdown will be incomplete, and some kernel modules may not
+  be unloaded.  To avoid this, use ``cardctl eject'' to shut down all
+  sockets before invoking rc.pcmcia.  The exit status of the cardctl
+  command will indicate if any sockets could not be shut down.
+
+  44..22..  OOvveerrvviieeww ooff tthhee PPCCMMCCIIAA ccoonnffiigguurraattiioonn ssccrriippttss
+
+  Each PCMCIA device has an associated ``class'' that describes how it
+  should be configured and managed.  Classes are associated with device
+  drivers in /etc/pcmcia/config.  There are currently five IO device
+  classes (network, SCSI, cdrom, fixed disk, and serial) and two memory
+  device classes (memory and FTL).  For each class, there are two
+  scripts in /etc/pcmcia: a main configuration script (i.e.,
+  /etc/pcmcia/scsi for SCSI devices), and an options script (i.e.,
+  /etc/pcmcia/scsi.opts).  The main script for a device will be invoked
+  to configure that device when a card is inserted, and to shut down the
+  device when the card is removed.  For cards with several associated
+  devices, the script will be invoked for each device.
+
+  The config scripts start by extracting some information about a device
+  from the stab file.  Each script constructs a ``device address'', that
+  uniquely describes the device it has been asked to configure, in the
+  ADDRESS shell variable.  This is passed to the *.opts script, which
+  should return information about how a device at this address should be
+  configured.  For some devices, the device address is just the socket
+  number.  For others, it includes extra information that may be useful
+  in deciding how to configure the device.  For example, network devices
+  pass their hardware ethernet address as part of the device address, so
+  the network.opts script could use this to select from several
+  different configurations.
+
+  The first part of all device addresses is the current PCMCIA
+  ``scheme''.  This parameter is used to support multiple sets of device
+  configurations based on a single external user-specified variable.
+  One use of schemes would be to have a ``home'' scheme, and a ``work''
+  scheme, which would include different sets of network configuration
+  parameters.  The current scheme is selected using the ``cardctl
+  scheme'' command.  The default if no scheme is set is ``default''.
+
+  As a general rule, when configuring Linux for a laptop, PCMCIA devices
+  should only be configured from the PCMCIA device scripts.  Do not try
+  to configure a PCMCIA device the same way you would configure a
+  permanently attached device.  However, some Linux distributions
+  provide PCMCIA packages that are hooked into those distributions' own
+  device configuration tools.  In that case, some of the following
+  sections may not apply; ideally, this will be documented by the
+  distribution maintainers.
+
+  44..33..  PPCCMMCCIIAA nneettwwoorrkk aaddaapptteerrss
+
+  Linux ethernet-type network interfaces normally have names like eth0,
+  eth1, and so on.  Token-ring adapters are handled similarly, however
+  they are named tr0, tr1, and so on.  The ifconfig command is used to
+  view or modify the state of a network interface.  A peculiarity of
+  Linux is that network interfaces do not have corresponding device
+  files under /dev, so do not be surprised when you do not find them.
+
+  When an ethernet card is detected, it will be assigned the first free
+  interface name, which will normally be eth0.  Cardmgr will run the
+  /etc/pcmcia/network script to configure the interface, which normally
+  reads network settings from /etc/pcmcia/network.opts.  The network and
+  network.opts scripts will be executed only when your ethernet card is
+  actually present.  If your system has an automatic network
+  configuration facility, it may or may not be PCMCIA-aware.  Consult
+  the documentation of your Linux distribution and the ``Notes about
+  specific Linux distributions''  to determine if PCMCIA network devices
+  should be configured with the automatic tools, or by editing
+  network.opts.
+
+  The device address passed to network.opts consists of four comma-
+  separated fields: the scheme, the socket number, the device instance,
+  and the card's hardware ethernet address.  The device instance is used
+  to number devices for cards that have several network interfaces, so
+  it will usually be 0.  If you have several network cards used for
+  different purposes, one option would be to configure the cards based
+  on socket position, as in:
+
+       case "$ADDRESS" in
+       *,0,*,*)
+           # definitions for network card in socket 0
+           ;;
+       *,1,*,*)
+           # definitions for network card in socket 1
+           ;;
+       esac
+
+  Alternatively, they could be configured using their hardware
+  addresses, as in:
+
+  case "$ADDRESS" in
+  *,*,*,00:80:C8:76:00:B1)
+      # definitions for a D-Link card
+      ;;
+  *,*,*,08:00:5A:44:80:01)
+      # definitions for an IBM card
+  esac
+
+  44..33..11..  NNeettwwoorrkk ddeevviiccee ppaarraammeetteerrss
+
+  The following parameters can be defined in network.opts:
+
+     IF_PORT
+        Specifies the ethernet transceiver type, for certain 16-bit
+        cards that do not autodetect.  See ``man ifport'' for more
+        information.
+
+     BOOTP
+        A boolean (y/n) value: indicates if the host's IP address and
+        routing information should be obtained using the BOOTP protocol,
+        with bootpc or pump.
+
+     DHCP
+        A boolean (y/n) value: indicates if the host's IP address and
+        routing information should be obtained from a DHCP server.  The
+        network script first looks for dhcpcd, then dhclient, then pump.
+
+     DHCP_HOSTNAME
+        Specifies a hostname to be passed to dhcpcd or pump, for
+        inclusion in DHCP messages.
+
+     IPADDR
+        The IP address for this interface.
+
+     NETMASK, BROADCAST, NETWORK
+        Basic network parameters: see the networking HOWTO for more
+        information.
+
+     GATEWAY
+        The IP address of a gateway for this host's subnet.  Packets
+        with destinations outside this subnet will be routed to this
+        gateway.
+
+     DOMAIN
+        The local network domain name for this host, to be used in
+        creating /etc/resolv.conf.
+
+     SEARCH
+        A search list for host name lookup, to be added to
+        /etc/resolv.conf.  DOMAIN and SEARCH are mutually exclusive: see
+        ``man resolver'' for more information.
+
+     DNS_1, DNS_2, DNS_3
+        Host names or IP addresses for nameservers for this interface,
+        to be added to /etc/resolv.conf
+
+     MOUNTS
+        A space-separated list of NFS mount points to be mounted for
+        this interface.
+
+     IPX_FRAME, IPX_NETNUM
+        For IPX networks: the frame type and network number, passed to
+        the ipx_interface command.
+
+  For example:
+
+       case "$ADDRESS" in
+       *,*,*,*)
+           IF_PORT="10base2"
+           BOOTP="n"
+           IPADDR="10.0.0.1"
+           NETMASK="255.255.255.0"
+           NETWORK="10.0.0.0"
+           BROADCAST="10.0.0.255"
+           GATEWAY="10.0.0.1"
+           DOMAIN="domain.org"
+           DNS_1="dns1.domain.org"
+           ;;
+       esac
+
+  To automatically mount and unmount NFS filesystems, first add all
+  these filesystems to /etc/fstab, but include noauto in the mount
+  options.  In network.opts, list the filesystem mount points in the
+  MOUNTS variable.  It is especially important to use either cardctl or
+  cardinfo to shut down a network card when NFS mounts are active.  It
+  is not possible to cleanly unmount NFS filesystems if a network card
+  is simply ejected without warning.
+
+  In addition to the usual network configuration parameters, the
+  network.opts script can specify extra actions to be taken after an
+  interface is configured, or before an interface is shut down.  If
+  network.opts defines a shell function called start_fn, it will be
+  invoked by the network script after the interface is configured, and
+  the interface name will be passed to the function as its first (and
+  only) argument.  Similarly, if it is defined, stop_fn will be invoked
+  before shutting down an interface.
+
+  The transceiver type for some cards can be selected using the IF_PORT
+  setting.  This can either be a numeric value, or a keyword identifying
+  the transceiver type.  All the network drivers default to either
+  autodetect the interface if possible, or 10baseT otherwise.  The
+  ifport command can be used to check or set the current transceiver
+  type.  For example:
+
+       # ifport eth0 10base2
+       #
+       # ifport eth0
+       eth0    2 (10base2)
+
+  The current (3.0.10 or later) 3c589 driver should quickly autodetect
+  transceiver changes at any time.  Earlier releases of the 3c589 driver
+  had a somewhat slow and flaky transceiver autodetection algorithm.
+  For these releases, the appropriate network cable should be connected
+  to the card when the card is configured, or you can force
+  autodetection with:
+
+       ifconfig eth0 down up
+
+  44..33..22..  CCoommmmeennttss aabboouutt ssppeecciiffiicc ccaarrddss
+
+  +o  With IBM CCAE and Socket EA cards, the transceiver type (10base2,
+     10baseT, AUI) needs to be set when the network device is
+     configured.  Make sure that the transceiver type reported in the
+     system log matches your connection.
+
+  +o  The Farallon EtherWave is actually based on the 3Com 3c589, with a
+     special transceiver.  Though the EtherWave uses 10baseT-style
+     connections, its transceiver requires that the 3c589 be configured
+     in 10base2 mode.
+
+  +o  If you have trouble with an IBM CCAE, NE4100, Thomas Conrad, or
+     Kingston adapter, try increasing the memory access time with the
+     mem_speed=# option to the pcnet_cs module.  An example of how to do
+     this is given in the standard config.opts file.  Try speeds of up
+     to 1000 (in nanoseconds).
+
+  +o  For the New Media Ethernet adapter, on some systems, it may be
+     necessary to increase the IO port access time with the io_speed=#
+     option when the pcmcia_core module is loaded.  Edit CORE_OPTS in
+     the startup script  to set this option.
+
+  +o  The multicast support in the New Media Ethernet driver is
+     incomplete.  The latest driver will function with multicast
+     kernels, but will ignore multicast packets.  Promiscuous mode
+     should work properly.
+
+  +o  The driver used by the IBM and 3Com token ring adapters seems to
+     behave very badly if the cards are not connected to a ring when
+     they get initialized.  Always connect these cards to the net before
+     they are powered up.  If ifconfig reports the hardware address as
+     all 0's, this is likely to be due to a memory window configuration
+     problem.
+
+  +o  Some Linksys, D-Link, and IC-Card 10baseT/10base2 cards have a
+     unique way of selecting the transceiver type that isn't handled by
+     the Linux drivers.  One workaround is to boot DOS and use the
+     vendor-supplied utility to select the transceiver, then warm boot
+     Linux.  Alternatively, a Linux utility to perform this function is
+     available at  <ftp://sourceforge.org/pcmcia/extras/dlport.c>.
+
+  +o  16-bit PCMCIA cards have a maximum performance of 1.5-2 MB/sec.
+     That means that any 16-bit 100baseT card (i.e., any card that uses
+     the pcnet_cs, 3c574_cs, smc91c92_cs, or xirc2ps_cs driver) will
+     never achieve full 100baseT throughput.  Only CardBus network
+     adapters can fully exploit 100baseT data rates.
+
+  +o  For WaveLAN wireless network adapters, Jean Tourrilhes
+     (jt@hpl.hp.com) has put together a wireless HOWTO at
+     <http://www.hpl.hp.com/personal/Jean_Tourrilhes/Linux/>.
+
+  44..33..33..  DDiiaaggnnoossiinngg pprroobblleemmss wwiitthh nneettwwoorrkk aaddaapptteerrss
+
+  +o  In 3.1.15 and later PCMCIA releases, the test_network script in the
+     debug-tools subdirectory of the PCMCIA source tree will spot some
+     common problems.
+
+  +o  Is your card recognized as an ethernet card?  Check the system log
+     and make sure that cardmgr identifies the card correctly and starts
+     up one of the network drivers.  If it doesn't, your card might
+     still be usable if it is compatible with a supported card.  This
+     will be most easily done if the card claims to be ``NE2000
+     compatible''.
+
+  +o  Is the card configured properly?  If you are using a supported
+     card, and it was recognized by cardmgr, but still doesn't work,
+     there might be an interrupt or port conflict with another device.
+     Find out what resources the card is using (from the system log),
+     and try excluding these in /etc/pcmcia/config.opts to force the
+     card to use something different.
+
+  +o  If your card seems to be configured properly, but sometimes locks
+     up, particularly under high load, you may need to try changing your
+     socket driver timing parameters.  See the ``Startup options''
+     section for more information.
+
+  +o  If you get ``Network is unreachable'' messages when you try to
+     access the network, then the routing information specified in
+     /etc/pcmcia/network.opts is incorrect.  This exact message is an
+     absolutely foolproof indication of a routing error.  On the other
+     hand, mis-configured cards will usually fail silently.
+
+  +o  If you are trying to use DHCP to configure your network interface,
+     try testing things with a static IP address instead, to rule out a
+     DHCP configuration problem.
+
+  +o  To diagnose problems in /etc/pcmcia/network.opts, start by trying
+     to ping other systems on the same subnet using their IP addresses.
+     Then try to ping your gateway, and then machines on other subnets.
+     Ping machines by name only after trying these simpler tests.
+
+  +o  Make sure your problem is really a PCMCIA one.  It may help to see
+     see if the card works under DOS with the vendor's drivers.  Double
+     check your modifications to the /etc/pcmcia/network.opts script.
+     Make sure your drop cable, ``T'' jack, terminator, etc are working.
+
+  +o  Use real network cables.  Don't even think about using that old
+     phone cord you found in your basement.  And this means Category 5
+     cable for 100baseT.  It really matters.
+
+  44..44..  PPCCMMCCIIAA sseerriiaall aanndd mmooddeemm ddeevviicceess
+
+  Linux serial devices are accessed via the /dev/ttyS* and /dev/cua*
+  special device files.  In pre-2.2 kernels, the ttyS* devices were for
+  incoming connections, such as directly connected terminals, and the
+  cua* devices were for outgoing connections, such as modems.  Use of
+  cua* devices is deprecated in current kernels, and ttyS* can be used
+  for all applications.  The configuration of a serial device can be
+  examined and modified with the setserial command.
+
+  When a serial or modem card is detected, it will be assigned to the
+  first available serial device slot.  This will usually be /dev/ttyS1
+  (cua1) or /dev/ttyS2 (cua2), depending on the number of built-in
+  serial ports.  The ttyS* device is the one reported in stab.  The
+  default serial device option script, /etc/pcmcia/serial.opts, will
+  link the device file to /dev/modem as a convenience.  For pre-2.2
+  kernels, the link is made to the cua* device.
+
+  Do not try to use /etc/rc.d/rc.serial to configure a PCMCIA modem.
+  This script should only be used to configure non-removable devices.
+  Modify /etc/pcmcia/serial.opts if you want to do anything special to
+  set up your modem.  Also, do not try to change the IO port and
+  interrupt settings of a serial device using setserial.  This would
+  tell the serial driver to look for the device in a different place,
+  but would not change how the card's hardware is actually configured.
+  The serial configuration script allows you to specify other setserial
+  options, as well as whether a line should be added to /etc/inittab for
+  this port.
+
+  The device address passed to serial.opts has three comma-separated
+  fields: the first is the scheme, the second is the socket number, and
+  the third is the device instance.  The device instance may take
+  several values for cards that support multiple serial ports, but for
+  single-port cards, it will always be 0.  If you commonly use more than
+  one modem, you may want to specify different settings based on socket
+  position, as in:
+
+       case "$ADDRESS" in
+       *,0,*)
+           # Options for modem in socket 0
+           LINK=/dev/modem0
+           ;;
+       *,1,*)
+           # Options for modem in socket 1
+           LINK=/dev/modem1
+           ;;
+       esac
+
+  If a PCMCIA modem is already configured when Linux boots, it may be
+  incorrectly identified as an ordinary built-in serial port.  This is
+  harmless, however, when the PCMCIA drivers take control of the modem,
+  it will be assigned a different device slot.  It is best to either
+  parse stab or use /dev/modem, rather than expecting a PCMCIA modem to
+  always have the same device assignment.
+
+  If you configure your kernel to load the basic Linux serial port
+  driver as a module, you must edit /etc/pcmcia/config to indicate that
+  this module must be loaded.  Edit the serial device entry to read:
+
+       device "serial_cs"
+         class "serial" module "misc/serial", "serial_cs"
+
+  44..44..11..  SSeerriiaall ddeevviiccee ppaarraammeetteerrss
+
+  The following parameters can be defined in serial.opts:
+
+     LINK
+        Specifies a path for a symbolic link to be created to the
+        ``callout'' device (e.g., /dev/cua* for pre-2.2, or /dev/ttyS*
+        for 2.2 kernels).
+
+     SERIAL_OPTS
+        Specifies options to be passed to the setserial command.
+     INITTAB
+        If specified, this will be used to construct an inittab entry
+        for the device.
+
+  For example:
+
+       case "$ADDRESS" in
+       *,*,*,*)
+           LINK="/dev/modem"
+           SERIAL_OPTS=""
+           INITTAB="/sbin/getty"
+
+  44..44..22..  CCoommmmeennttss aabboouutt ssppeecciiffiicc ccaarrddss
+
+  +o  The Uniden Data 2000 Wireless CDPD card has some special dialing
+     strings for initiating SLIP and PPP mode.  For SLIP, use ``ATDT2'';
+     for PPP, "ATDT0".
+
+  44..44..33..  DDiiaaggnnoossiinngg pprroobblleemmss wwiitthh sseerriiaall ddeevviicceess
+
+  +o  In 3.1.15 and later PCMCIA releases, the test_modem script in the
+     debug-tools subdirectory of the PCMCIA source tree will spot some
+     common problems.
+
+  +o  Is your card recognized as a modem?  Check the system log and make
+     sure that cardmgr identifies the card correctly and starts up the
+     serial_cs driver.  If it doesn't, you may need to add a new entry
+     to your /etc/pcmcia/config file so that it will be identified
+     properly.  See the ``Configuring unrecognized cards'' section for
+     details.
+
+  +o  Is the modem configured successfully by serial_cs?  Again, check
+     the system log and look for messages from the serial_cs driver.  If
+     you see ``register_serial() failed'', you may have an I/O port
+     conflict with another device.  Another tip-off of a conflict is if
+     the device is reported to be an 8250; most modern modems should be
+     identified as 16550A UART's.  If you think you're seeing a port
+     conflict, edit /etc/pcmcia/config.opts and exclude the port range
+     that was allocated for the modem.
+
+  +o  Is there an interrupt conflict?  If the system log looks good, but
+     the modem just doesn't seem to work, try using setserial to change
+     the irq to 0, and see if the modem works.  This causes the serial
+     driver to use a slower polled mode instead of using interrupts.  If
+     this seems to fix the problem, it is likely that some other device
+     in your system is using the interrupt selected by serial_cs.  You
+     should add a line to /etc/pcmcia/config.opts to exclude this
+     interrupt.
+
+  +o  If the modem seems to work only very, very slowly, this is an
+     almost certain indicator of an interrupt conflict.
+
+  +o  Make sure your problem is really a PCMCIA one.  It may help to see
+     if the card works under DOS with the vendor's drivers.  Also, don't
+     test the card with something complex like SLIP or PPP until you are
+     sure you can make simple connections.  If simple things work but
+     SLIP does not, your problem is most likely with SLIP, not with
+     PCMCIA.
+
+  +o  If you get kernel messages indicating that the serial_cs module
+     cannot be loaded, it means that your kernel does not have serial
+     device support.  If you have compiled the serial driver as a
+     module, you must modify /etc/pcmcia/config to indicate that the
+     serial module should be loaded before serial_cs.
+
+  44..55..  PPCCMMCCIIAA ppaarraalllleell ppoorrtt ddeevviicceess
+
+  The Linux parallel port driver is layered so that several high-level
+  device types can share use of the same low level port driver.  Printer
+  devices are accessed via the /dev/lp* special device files.  The
+  configuration of a printer device can be examined and modified with
+  the tunelp command.
+
+  The parport_cs module depends on the parport and parport_pc drivers,
+  which may be either compiled into the kernel or compiled as modules.
+  The layered driver structure means that any top-level parallel drivers
+  (such as the plip driver, the printer driver, etc) must be compiled as
+  modules.  These drivers only recognize parallel port devices at module
+  startup time, so they need to be loaded after any PC Card parallel
+  devices are configured.
+
+  The device address passed to parport.opts has three comma-separated
+  fields: the first is the scheme, the second is the socket number, and
+  the third is the device instance.  The device instance may take
+  several values for cards that support multiple parallel ports, but for
+  single-port cards, it will always be 0.  If you commonly use more than
+  one such card, you may want to specify different settings based on
+  socket position, as in:
+
+       case "$ADDRESS" in
+       *,0,*)
+           # Options for card in socket 0
+           LINK=/dev/printer0
+           ;;
+       *,1,*)
+           # Options for card in socket 1
+           LINK=/dev/printer1
+           ;;
+       esac
+
+  If you configure your kernel to load the basic Linux parallel port
+  driver as a module, you must edit /etc/pcmcia/config to indicate that
+  the appropriate modules must be loaded.  Edit the parallel device
+  entry to read:
+
+       device "parport_cs"
+         class "parport" module "misc/parport", "misc/parport_pc", "parport_cs"
+
+  44..55..11..  PPaarraalllleell ddeevviiccee ppaarraammeetteerrss
+
+  The following parameters can be defined in parport.opts:
+
+     LINK
+        Specifies a path for a symbolic link to be created to the
+        printer port.
+
+     LP_OPTS
+        Specifies options to be passed to the tunelp command.
+
+  For example:
+
+       case "$ADDRESS" in
+       *,*,*,*)
+           LINK="/dev/printer"
+           LP_OPTS=""
+
+  44..55..22..  DDiiaaggnnoossiinngg pprroobblleemmss wwiitthh ppaarraalllleell ppoorrtt ddeevviicceess
+
+  +o  Is there an interrupt conflict?  If the system log looks good, but
+     the port just doesn't seem to work, try using tunelp to change the
+     irq to 0, and see if things improve.  This switches the driver to
+     polling mode.  If this seems to fix the problem, it is likely that
+     some other device in your system is using the interrupt selected by
+     parport_cs.  You should add a line to /etc/pcmcia/config.opts to
+     exclude this interrupt.
+
+  +o  If you get kernel messages indicating that the parport_cs module
+     cannot be loaded, it means that your kernel does not have parallel
+     device support.  If you have compiled the parallel driver as a
+     module, you may need to modify /etc/pcmcia/config to indicate that
+     the parport and parport_pc modules should be loaded before
+     parport_cs.
+
+  44..66..  PPCCMMCCIIAA SSCCSSII aaddaapptteerrss
+
+  All the currently supported PCMCIA SCSI cards are work-alikes of one
+  of the following ISA bus cards: the Qlogic, the Adaptec AHA-152X, or
+  the Future Domain TMC-16x0.  The PCMCIA drivers are built by linking
+  some PCMCIA-specific code (in qlogic_cs.c, aha152x_cs.c, or
+  fdomain_cs.c) with the normal Linux SCSI driver, pulled from the Linux
+  kernel source tree.  The Adaptec APA1480 CardBus driver is based on
+  the kernel aic7xxx PCI driver.  Due to limitations in the Linux SCSI
+  driver model, only one removable card per driver is supported.
+
+  When a new SCSI host adapter is detected, the SCSI drivers will probe
+  for devices.  Check the system log to make sure your devices are
+  detected properly.  New SCSI devices will be assigned to the first
+  available SCSI device files.  The first SCSI disk will be /dev/sda,
+  the first SCSI tape will be /dev/st0, and the first CD-ROM will be
+  /dev/scd0.
+
+  A list of SCSI devices connected to this host adapter will be shown in
+  stab, and the SCSI configuration script, /etc/pcmcia/scsi, will be
+  called once for each attached device, to either configure or shut down
+  that device.  The default script does not take any actions to
+  configure SCSI devices, but will properly unmount filesystems on SCSI
+  devices when a card is removed.
+
+  The device addresses passed to scsi.opts are complicated, because of
+  the variety of things that can be attached to a SCSI adapter.
+  Addresses consist of either six or seven comma-separated fields: the
+  current scheme, the device type, the socket number, the SCSI channel,
+  ID, and logical unit number, and optionally, the partition number.
+  The device type will be ``sd'' for disks, ``st'' for tapes, ``sr'' for
+  CD-ROM devices, and ``sg'' for generic SCSI devices.  For most setups,
+  the SCSI channel and logical unit number will be 0.  For disk devices
+  with several partitions, scsi.opts will first be called for the whole
+  device, with a five-field address.  The script should set the PARTS
+  variable to a list of partitions.  Then, scsi.opts will be called for
+  each partition, with the longer seven-field addresses.
+
+  If your kernel does not have a top-level driver (disk, tape, etc) for
+  a particular SCSI device, then the device will not be configured by
+  the PCMCIA drivers.  As a side effect, the device's name in stab will
+  be something like ``sd#nnnn'' where ``nnnn'' is a four-digit hex
+  number.  This happens when cardmgr is unable to translate a SCSI
+  device ID into a corresponding Linux device name.
+
+  It is possible to modularize the top-level SCSI drivers so that they
+  are loaded on demand.  To do so, you need to edit /etc/pcmcia/config
+  to tell cardmgr which extra modules need to be loaded when your
+  adapter is configured.  For example:
+
+       device "aha152x_cs"
+         class "scsi" module "scsi/scsi_mod", "scsi/sd_mod", "aha152x_cs"
+
+  would say to load the core SCSI module and the top-level disk driver
+  module before loading the regular PCMCIA driver module.  The PCMCIA
+  Configure script will not automatically detect modularized SCSI
+  modules, so you will need use the manual configure option to enable
+  SCSI support.
+
+  Always turn on SCSI devices before powering up your laptop, or before
+  inserting the adapter card, so that the SCSI bus is properly
+  terminated when the adapter is configured.  Also be very careful about
+  ejecting a SCSI adapter.  Be sure that all associated SCSI devices are
+  unmounted and closed before ejecting the card.  The best way to ensure
+  this is to use either cardctl or cardinfo to request card removal
+  before physically ejecting the card.  For now, all SCSI devices should
+  be powered up before plugging in a SCSI adapter, and should stay
+  connected until after you unplug the adapter and/or power down your
+  laptop.
+
+  There is a potential complication when using these cards that does not
+  arise with ordinary ISA bus adapters.  The SCSI bus carries a
+  ``termination power'' signal that is necessary for proper operation of
+  ordinary passive SCSI terminators.  PCMCIA SCSI adapters do not supply
+  termination power, so if it is required, an external device must
+  supply it.  Some external SCSI devices may be configured to supply
+  termination power.  Others, such as the Zip Drive and the Syquest EZ-
+  Drive, use active terminators that do not depend on it.  In some
+  cases, it may be necessary to use a special terminator block such as
+  the APS SCSI Sentry 2, which has an external power supply.  When
+  configuring your SCSI device chain, be aware of whether or not any of
+  your devices require or can provide termination power.
+
+  44..66..11..  SSCCSSII ddeevviiccee ppaarraammeetteerrss
+
+  The following parameters can be defined in scsi.opts:
+
+     DO_FSTAB
+        A boolean (y/n) setting: specifies if an entry should be added
+        to /etc/fstab for this device.
+
+     DO_FSCK
+        A boolean (y/n) setting: specifies if the filesystem should be
+        checked before being mounted, with ``fsck -Ta''.
+
+     DO_MOUNT
+        A boolean (y/n) setting: specifies if this device should be
+        automatically mounted at card insertion time.
+
+     FSTYPE, OPTS, MOUNTPT
+        The filesystem type, mount options, and mount point to be used
+        for the fstab entry and/or mounting the device.
+
+  For example, here is a script for configuring a disk device at SCSI ID
+  3, with two partitions, and a CD-ROM at SCSI ID 6:
+
+       case "$ADDRESS" in
+       *,sd,*,0,3,0)
+           # This device has two partitions...
+           PARTS="1 2"
+           ;;
+       *,sd,*,0,3,0,1)
+           # Options for partition 1:
+           #  update /etc/fstab, and mount an ext2 fs on /usr1
+           DO_FSTAB="y" ; DO_FSCK="y" ; DO_MOUNT="y"
+           FSTYPE="ext2"
+           OPTS=""
+           MOUNTPT="/usr1"
+           ;;
+       *,sd,*,0,3,0,2)
+           # Options for partition 2:
+           #  update /etc/fstab, and mount an MS-DOS fs on /usr2
+           DO_FSTAB="y" ; DO_FSCK="y" ; DO_MOUNT="y"
+           FSTYPE="msdos"
+           OPTS=""
+           MOUNTPT="/usr2"
+           ;;
+       *,sr,*,0,6,0)
+           # Options for CD-ROM at SCSI ID 6
+           PARTS=""
+           DO_FSTAB="y" ; DO_FSCK="n" ; DO_MOUNT="y"
+           FSTYPE="iso9660"
+           OPTS="ro"
+           MOUNTPT="/cdrom"
+           ;;
+       esac
+
+  44..66..22..  CCoommmmeennttss aabboouutt ssppeecciiffiicc ccaarrddss
+
+  +o  The Adaptec APA-1480 CardBus card needs a large IO port window (256
+     contiguous ports aligned on a 256-port boundary).  It may be
+     necessary to expand the IO port regions in /etc/pcmcia/config.opts
+     to guarantee that such a large window can be found.
+
+  +o  The Adaptec APA-460 SlimSCSI adapter is not supported.  This card
+     was originally sold under the Trantor name, and when Adaptec merged
+     with Trantor, they continued to sell the Trantor card with an
+     Adaptec label.  The APA-460 is not compatible with any existing
+     Linux driver.
+
+  +o  I have had one report of a bad interaction between the New Media
+     Bus Toaster and a UMAX Astra 1200s scanner.  Due to the complexity
+     of the SCSI protocol, when diagnosing problems with SCSI devices,
+     it is worth considering that incompatible combinations like this
+     may exist and may not be documented.
+
+  44..66..33..  DDiiaaggnnoossiinngg pprroobblleemmss wwiitthh SSCCSSII aaddaapptteerrss
+
+  +o  With the aha152x_cs driver (used by Adaptec, New Media, and a few
+     others), it seems that SCSI disconnect/reconnect support is a
+     frequent source of trouble with tape drives.  To disable this
+     ``feature,'' add the following to /etc/pcmcia/config.opts:
+
+       module "aha152x_cs" opts "reconnect=0"
+
+  +o  Also with the aha152x_cs driver, certain devices seem to require a
+     longer startup delay, controlled via the reset_delay module
+     parameter.  The Yamaha 4416S CDR drive is one such device.  The
+     result is the device is identified successfully, then hangs the
+     system.  In such cases, try:
+
+       module "aha152x_cs" opts "reset_delay=500"
+
+  +o  Another potential source of SCSI device probe problems is probing
+     of multiple LUN's.  If you see successful detection of a device,
+     followed by SCSI bus timeouts when LUN 1 for that device is probed,
+     then disable the kernel's CONFIG_SCSI_MULTI_LUN option.
+
+  +o  If you have compiled SCSI support as modules (CONFIG_SCSI is
+     ``m''), you must modify /etc/pcmcia/config to load the SCSI modules
+     before the appropriate *_cs driver is loaded.
+
+  +o  If you get ``aborting command due to timeout'' messages when the
+     SCSI bus is probed, you almost certainly have an interrupt
+     conflict.
+
+  +o  If the host driver reports ``no SCSI devices found'', verify that
+     your kernel was compiled with the appropriate top-level SCSI
+     drivers for your devices (i.e., disk, tape, CD-ROM, and/or
+     generic).  If a top-level driver is missing, devices of that type
+     will be ignored.
+
+  44..77..  PPCCMMCCIIAA mmeemmoorryy ccaarrddss
+
+  The memory_cs driver handles all types of memory cards, as well as
+  providing direct access to the PCMCIA memory address space for cards
+  that have other functions.  When loaded, it creates a combination of
+  character and block devices.  See the man page for the module for a
+  complete description of the device naming scheme.  Block devices are
+  used for disk-like access (creating and mounting filesystems, etc).
+  The character devices are for "raw" unbuffered reads and writes at
+  arbitrary locations.
+
+  The device address passed to memory.opts consists of two fields: the
+  scheme, and the socket number.  The options are applied to the first
+  common memory partition on the corresponding memory card.
+
+  Some older memory cards, and most simple static RAM cards, lack a
+  ``Card Information Structure'' (CIS), which is the scheme PCMCIA cards
+  use to identify themselves.  Normally, cardmgr will assume that any
+  card that lacks a CIS is a simple memory card, and load the memory_cs
+  driver.  Thus, a common side effect of a general card identification
+  problem is that other types of cards may be misdetected as memory
+  cards.
+
+  The memory_cs driver uses a heuristic to guess the capacity of these
+  cards.  The heuristic does not work for write protected cards, and may
+  make mistakes in some other cases as well.  If a card is misdetected,
+  its size should then be explicitly specified when using commands such
+  as dd or mkfs.
+
+  44..77..11..  MMeemmoorryy ddeevviiccee ppaarraammeetteerrss
+
+  The following parameters can be specified in memory.opts:
+
+     DO_FSTAB
+        A boolean (y/n) setting: specifies if an entry should be added
+        to /etc/fstab for this device.
+
+     DO_FSCK
+        A boolean (y/n) setting: specifies if the filesystem should be
+        checked before being mounted, with ``fsck -Ta''.
+
+     DO_MOUNT
+        A boolean (y/n) setting: specifies if this device should be
+        automatically mounted at card insertion time.
+
+     FSTYPE, OPTS, MOUNTPT
+        The filesystem type, mount options, and mount point to be used
+        for the fstab entry and/or mounting the device.
+
+  Here is an example of a script that will automatically mount memory
+  cards based on which socket they are inserted into:
+
+  case "$ADDRESS" in
+  *,0,0)
+      # Mount filesystem, but don't update /etc/fstab
+      DO_FSTAB="n" ; DO_FSCK="y" ; DO_MOUNT="y"
+      FSTYPE="ext2" ; OPTS=""
+      MOUNTPT="/mem0"
+      ;;
+  *,1,0)
+      # Mount filesystem, but don't update /etc/fstab
+      DO_FSTAB="n" ; DO_FSCK="y" ; DO_MOUNT="y"
+      FSTYPE="ext2" ; OPTS=""
+      MOUNTPT="/mem1"
+      ;;
+  esac
+
+  44..77..22..  UUssiinngg lliinneeaarr ffllaasshh mmeemmoorryy ccaarrddss
+
+  The following information applies only to so-called ``linear flash''
+  memory cards.  Many flash cards, including all SmartMedia and
+  CompactFlash cards, actually include circuitry to emulate an IDE disk
+  device.  Those cards are thus handled as IDE devices, not memory
+  cards.
+
+  There are two major formats for flash memory cards: the FTL or ``flash
+  translation layer'' style, and the Microsoft Flash File System.  The
+  FTL format is generally more flexible because it allows any ordinary
+  high-level filesystem (ext2, ms-dos, etc) to be used on a flash card
+  as if it were an ordinary disk device.  The FFS is a completely
+  different filesystem type.  Linux cannot currently handle cards
+  formated with FFS.
+
+  To use a flash memory card as an ordinary disk-like block device,
+  first create an FTL partition on the device with the ftl_format
+  command.  This layer hides the device-specific details of flash memory
+  programming and make the card look like a simple block device.  For
+  example:
+
+       ftl_format -i /dev/mem0c0c
+
+  Note that this command accesses the card through the ``raw'' memory
+  card interface.  Once formatted, the card can be accessed as an
+  ordinary block device via the ftl_cs driver.  For example:
+
+       mke2fs /dev/ftl0c0
+       mount -t ext2 /dev/ftl0c0 /mnt
+
+  Device naming for FTL devices is tricky.  Minor device numbers have
+  three parts: the card number, the region number on that card, and
+  optionally, the partition within that region.  A region can either be
+  treated as a single block device with no partition table (like a
+  floppy), or it can be partitioned like a hard disk device.  The
+  ``ftl0c0'' device is card 0, common memory region 0, the entire
+  region.  The ``ftl0c0p1'' through ``ftl0c0p4'' devices are primary
+  partitions 1 through 4 if the region has been partitioned.
+
+  Configuration options for FTL partitions can be given in ftl.opts,
+  which is similar in structure to memory.opts.  The device address
+  passed to ftl.opts consists of three or four fields: the scheme, the
+  socket number, the region number, and optionally, the partition
+  number.  Most flash cards have just one flash memory region, so the
+  region number will generally always be zero.
+
+  Intel Series 100 flash cards use the first 128K flash block to store
+  the cards' configuration information.  To prevent accidental erasure
+  of this information, ftl_format will automatically detect this and
+  skip the first block when creating an FTL partition.
+
+  44..88..  PPCCMMCCIIAA AATTAA//IIDDEE ccaarrdd ddrriivveess
+
+  ATA/IDE drive support is based on the regular kernel IDE driver.  This
+  includes SmartMedia and CompactFlash devices: these flash memory cards
+  are set up so that they emulate an IDE interface.  The PCMCIA-specific
+  part of the driver is ide_cs.  Be sure to use cardctl or cardinfo to
+  shut down an ATA/IDE card before ejecting it, as the driver has not
+  been made ``hot-swap-proof''.
+
+  The device addresses passed to ide.opts consist of either three or
+  four fields: the current scheme, the socket number, the drive's serial
+  number, and an optional partition number.  The ide_info command can be
+  used to obtain an IDE device's serial number.  As with SCSI devices,
+  ide.opts is first called for the entire device.  If ide.opts returns a
+  list of partitions in the PARTS variable, the script will then be
+  called for each partition.
+
+  44..88..11..  AATTAA//IIDDEE ffiixxeedd--ddiisskk ddeevviiccee ppaarraammeetteerrss
+
+  The following parameters can be specified in ide.opts:
+
+     DO_FSTAB
+        A boolean (y/n) setting: specifies if an entry should be added
+        to /etc/fstab for this device.
+
+     DO_FSCK
+        A boolean (y/n) setting: specifies if the filesystem should be
+        checked before being mounted, with ``fsck -Ta''.
+
+     DO_MOUNT
+        A boolean (y/n) setting: specifies if this device should be
+        automatically mounted at card insertion time.
+
+     FSTYPE, OPTS, MOUNTPT
+        The filesystem type, mount options, and mount point to be used
+        for the fstab entry and/or mounting the device.
+
+  Here is an example ide.opts file to mount the first partition of any
+  ATA/IDE card on /mnt.
+
+  case "$ADDRESS" in
+  *,*,*,1)
+      DO_FSTAB="y" ; DO_FSCK="y" ; DO_MOUNT="y"
+      FSTYPE="msdos"
+      OPTS=""
+      MOUNTPT="/mnt"
+      ;;
+  *,*,*)
+      PARTS="1"
+      ;;
+  esac
+
+  44..88..22..  DDiiaaggnnoossiinngg pprroobblleemmss wwiitthh AATTAA//IIDDEE aaddaapptteerrss
+
+  +o  An IO port conflict may cause the IDE driver to misdetect the drive
+     geometry and report ``INVALID GEOMETRY: 0 PHYSICAL HEADS?''.  To
+     fix, try excluding the selected IO port range in
+     /etc/pcmcia/config.opts.
+
+  +o  Some IDE drives violate the PCMCIA specification by requiring a
+     longer time to spin up than the maximum allowed card setup time.
+     Starting with release 3.0.6, the ide_cs driver will automatically
+     retry the device probe to give these drives time to spin up.  With
+     older drivers, you may need to load the pcmcia_core module with:
+
+       CORE_OPTS="unreset_delay=400"
+
+  +o  To use an ATA/IDE CD-ROM device, your kernel must be compiled with
+     CONFIG_BLK_DEV_IDECD enabled.  This will normally be the case for
+     standard kernels, however it is something to be aware of if you
+     compile a custom kernel.
+
+  +o  A common error when using IDE drives is try to mount the wrong
+     device file.  Generally, you want to mount a partition of the
+     device, not the entire device (i.e., /dev/hde1, not /dev/hde).
+
+  +o  The Linux IDE driver may have trouble configuring certain
+     removable-media drives if no media is present at insertion time.
+     The IBM Portable DriveBay has this problem.
+
+  +o  Some kernels will report a pair of ``drive_cmd'' errors at
+     insertion time.  These errors can be ignored: they pop up when a
+     removable IDE device does not accept the IDE ``door lock'' command.
+
+  44..99..  MMuullttiiffuunnccttiioonn ccaarrddss
+
+  A single interrupt can be shared by several drivers, such as the
+  serial driver and an ethernet driver: in fact, the PCMCIA
+  specification requires all card functions to share the same interrupt.
+  Normally, all card functions are available without having to swap
+  drivers.  Any remotely recent Linux kernel (i.e., 1.3.72 or later)
+  supports this kind of interrupt sharing.
+
+  Simultaneous use of two card functions is ``tricky'' and various
+  hardware vendors have implemented interrupt sharing in their own
+  incompatible (and sometimes proprietary) ways.  The drivers for some
+  cards (Ositech Jack of Diamonds, 3Com 3c562 and related cards, Linksys
+  cards) properly support simultaneous access, but others (older
+  Megahertz cards in particular) do not.  If you have trouble using a
+  card with both functions active, try using each function in isolation.
+  That may require explicitly doing an ``ifconfig down'' to shut down a
+  network interface and use a modem on the same card.
+
+  55..  AAddvvaanncceedd ttooppiiccss
+
+  55..11..  RReessoouurrccee aallllooccaattiioonn ffoorr PPCCMMCCIIAA ddeevviicceess
+
+  In theory, it should not really matter which interrupt is allocated to
+  which device, as long as two devices are not configured to use the
+  same interrupt.  In /etc/pcmcia/config.opts you'll find a place for
+  excluding interrupts that are used by non-PCMCIA devices.
+
+  Similarly, there is no way to directly specify the I/O addresses for a
+  card to use.  The /etc/pcmcia/config.opts file allows you to specify
+  ranges of ports available for use by any card, or to exclude ranges
+  that conflict with other devices.
+
+  After modifying /etc/pcmcia/config.opts, you can reinitialize cardmgr
+  with ``kill -HUP''.
+
+  The interrupt used to monitor card status changes is chosen by the
+  low-level socket driver module (i82365 or tcic) before cardmgr parses
+  /etc/pcmcia/config, so it is not affected by changes to this file.  To
+  set this interrupt, use the cs_irq= option when the socket driver is
+  loaded, by setting the PCIC_OPTS variable in /etc/rc.d/rc.pcmcia.
+
+  All the client card drivers have a parameter called irq_list for
+  specifying which interrupts they may try to allocate.  These driver
+  options should be set in your /etc/pcmcia/config file.  For example:
+
+       device "serial_cs"
+         module "serial_cs" opts "irq_list=8,12"
+         ...
+
+  would specify that the serial driver should only use irq 8 or irq 12.
+  Regardless of irq_list settings, Card Services will never allocate an
+  interrupt that is already in use by another device, or an interrupt
+  that is excluded in the config file.
+
+  55..22..  HHooww ccaann II hhaavvee sseeppaarraattee ddeevviiccee sseettuuppss ffoorr hhoommee aanndd wwoorrkk??
+
+  This is fairly easy using ``scheme'' support.  Use two configuration
+  schemes, called ``home'' and ``work''.  Here is an example of a
+  network.opts script with scheme-specific settings:
+
+  case "$ADDRESS" in
+  work,*,*,*)
+      # definitions for network card in work scheme
+      ...
+      ;;
+  home,*,*,*|default,*,*,*)
+      # definitions for network card in home scheme
+      ...
+      ;;
+  esac
+
+  The first part of a device address is always the configuration scheme.
+  In this example, the second ``case'' clause will select for both the
+  ``home'' and ``default'' schemes.  So, if the scheme is unset for any
+  reason, it will default to the ``home'' setup.
+
+  Now, to select between the two sets of settings, run either:
+
+       cardctl scheme home
+
+  or
+
+       cardctl scheme work
+
+  The cardctl command does the equivalent of shutting down all your
+  cards and restarting them.  The command can be safely executed whether
+  or not the PCMCIA system is loaded, but the command may fail if you
+  are using other PCMCIA devices at the time (even if their
+  configurations are not explicitly dependant on the scheme setting).
+
+  To find out the current scheme setting, run:
+
+       cardctl scheme
+
+  By default, the scheme setting is persistent across boots.  This can
+  have undesirable effects if networking is initialized for the wrong
+  environment.  Optionally, you can set the initial scheme value with
+  the SCHEME startup option (see ``Startup options'' for details).  It
+  is also possible to set the scheme from the lilo boot prompt.  Since
+  lilo passes unrecognized options to init as environment variables, a
+  value for SCHEME (or any other PCMCIA startup option) at the boot
+  prompt will be propagated into the PCMCIA startup script.
+
+  To save even more keystrokes, schemes can be specified in lilo's
+  configuration file.  For instance, you could have:
+
+  root = /dev/hda1
+  read-only
+  image = /boot/vmlinuz
+    label  = home
+    append = "SCHEME=home"
+  image = /boot/vmlinuz
+    label  = work
+    append = "SCHEME=work"
+
+  Typing ``home'' or ``work'' at the boot prompt would then boot into
+  the appropriate scheme.
+
+  55..33..  BBoooottiinngg ffrroomm aa PPCCMMCCIIAA ddeevviiccee
+
+  Having the root filesystem on a PCMCIA device is tricky because the
+  Linux PCMCIA system is not designed to be linked into the kernel.  Its
+  core components, the loadable kernel modules and the user mode cardmgr
+  daemon, depend on an already running system.  The kernel's ``initrd''
+  facility works around this requirement by allowing Linux to boot using
+  a temporary ram disk as a minimal root image, load drivers, and then
+  re-mount a different root filesystem.  The temporary root can
+  configure PCMCIA devices and then re-mount a PCMCIA device as root.
+
+  The initrd image absolutely must reside on a bootable device: this
+  generally cannot be put on a PCMCIA device.  This is a BIOS
+  limitation, not a kernel limitation.  It is useful here to distinguish
+  between ``boot-able'' devices (i.e., devices that can be booted), and
+  ``root-able'' devices (i.e., devices that can be mounted as root).
+  ``Boot-able'' devices are determined by the BIOS, and are generally
+  limited to internal floppy and hard disk drives.  ``Root-able''
+  devices are any block devices that the kernel supports once it has
+  been loaded.  The initrd facility makes more devices ``root-able'',
+  not ``boot-able''.
+
+  Some Linux distributions will allow installation to a device connected
+  to a PCMCIA SCSI adapter, as an unintended side-effect of their
+  support for installs from PCMCIA SCSI CD-ROM devices.  However, at
+  present, no Linux installation tools support configuring an
+  appropriate ``initrd'' to boot Linux with a PCMCIA root filesystem.
+  Setting up a system with a PCMCIA root thus requires that you use
+  another Linux system to create the ``initrd'' image.  If another Linux
+  system is not available, another option would be to temporarily
+  install a minimal Linux setup on a non-PCMCIA drive, create an initrd
+  image, and then reinstall to the PCMCIA target.
+
+  The Linux Bootdisk-HOWTO has some general information about setting up
+  boot disks but nothing specific to initrd.  The main initrd document
+  is included with recent kernel source code distributions, in
+  linux/Documentation/initrd.txt.  Before beginning, you should read
+  this document.  A familiarity with lilo is also helpful.  Using initrd
+  also requires that you have a kernel compiled with CONFIG_BLK_DEV_RAM
+  and CONFIG_BLK_DEV_INITRD enabled.
+
+  This is an advanced configuration technique, and requires a high level
+  of familiarity with Linux and the PCMCIA system.  Be sure to read all
+  the relevant documentation before starting.  The following cookbook
+  instructions should work, but deviations from the examples will
+  quickly put you in uncharted and ``unsupported'' territory, and you
+  will be on your own.
+
+  This method absolutely requires that you use a PCMCIA driver release
+  of 2.9.5 or later.  Older PCMCIA packages or individual components
+  will not work in the initrd context.  Do not mix components from
+  different releases.
+
+  55..33..11..  TThhee ppcciinniittrrdd hheellppeerr ssccrriipptt
+
+  The pcinitrd script creates a basic initrd image for booting with a
+  PCMCIA root partition.  The image includes a minimal directory
+  heirarchy, a handful of device files, a few binaries, shared
+  libraries, and a set of PCMCIA driver modules.  When invoking
+  pcinitrd, you specify the driver modules that you want to be included
+  in the image.  The core PCMCIA components, pcmcia_core and ds, are
+  automatically included.
+
+  As an example, say that your laptop uses an i82365-compatible host
+  controller, and you want to boot Linux with the root filesystem on a
+  hard drive attached to an Adaptec SlimSCSI adapter.  You could create
+  an appropriate initrd image with:
+
+       pcinitrd -v initrd pcmcia/i82365.o pcmcia/aha152x_cs.o
+
+  To customize the initrd startup sequence, you could mount the image
+  using the ``loopback'' device with a command like:
+
+       mount -o loop -t ext2 initrd /mnt
+
+  and then edit the linuxrc script.  The configuration files will be
+  installed under /etc in the image, and can also be customized.  See
+  the man page for pcinitrd for more information.
+
+  55..33..22..  CCrreeaattiinngg aann iinniittrrdd bboooott ffllooppppyy
+
+  After creating an image with pcinitrd, you can create a boot floppy by
+  copying the kernel, the compressed initrd image, and a few support
+  files for lilo to a clean floppy.  In the following example, we assume
+  that the desired PCMCIA root device is /dev/sda1:
+
+       mke2fs /dev/fd0
+       mount /dev/fd0 /mnt
+       mkdir /mnt/etc /mnt/boot /mnt/dev
+       cp -a /dev/fd0 /dev/sda1 /mnt/dev
+       cp [kernel-image] /mnt/vmlinuz
+       cp /boot/boot.b /mnt/boot/boot.b
+       gzip < [initrd-image] > /mnt/initrd
+
+  Create /mnt/etc/lilo.conf with the contents:
+
+       boot=/dev/fd0
+       compact
+       image=/vmlinuz
+           label=linux
+           initrd=/initrd
+           read-only
+           root=/dev/sda1
+
+  Finally, invoke lilo with:
+
+       lilo -r /mnt
+
+  When lilo is invoked with -r, it performs all actions relative to the
+  specified alternate root directory.  The reason for creating the
+  device files under /mnt/dev was that lilo will not be able to use the
+  files in /dev when it is running in this alternate-root mode.
+
+  55..33..33..  IInnssttaalllliinngg aann iinniittrrdd iimmaaggee oonn aa nnoonn--LLiinnuuxx ddrriivvee
+
+  One common use of the initrd facility would be on systems where the
+  internal hard drive is dedicated to another operating system.  The
+  Linux kernel and initrd image can be placed in a non-Linux partition,
+  and lilo or LOADLIN can be set up to boot Linux from these images.
+
+  Assuming that you have a kernel has been configured for the
+  appropriate root device, and an initrd image created on another
+  system, the easiest way to get started is to boot Linux using LOADLIN,
+  as:
+
+       LOADLIN <kernel> initrd=<initrd-image>
+
+  Once you can boot Linux on your target machine, you could then install
+  lilo to allow booting Linux directly.  For example, say that /dev/hda1
+  is the non-Linux target partition and /mnt can be used as a mount
+  point.  First, create a subdirectory on the target for the Linux
+  files:
+
+       mount /dev/hda1 /mnt
+       mkdir /mnt/linux
+       cp [kernel-image] /mnt/linux/vmlinuz
+       cp [initrd-image] /mnt/linux/initrd
+
+  In this example, say that /dev/sda1 is the desired Linux root
+  partition, a SCSI hard drive mounted via a PCMCIA SCSI adapter.  To
+  install lilo, create a lilo.conf file with the contents:
+
+       boot=/dev/hda
+       map=/mnt/linux/map
+       compact
+       image=/mnt/linux/vmlinuz
+               label=linux
+               root=/dev/sda1
+               initrd=/mnt/linux/initrd
+               read-only
+       other=/dev/hda1
+               table=/dev/hda
+               label=windows
+
+  The boot= line says to install the boot loader in the master boot
+  record of the specified device.  The root= line identifies the desired
+  root filesystem to be used after loading the initrd image, and may be
+  unnecessary if the kernel image is already configured this way.  The
+  other= section is used to describe the other operating system
+  installed on /dev/hda1.
+
+  To install lilo in this case, use:
+
+       lilo -C lilo.conf
+
+  Note that in this case, the lilo.conf file uses absolute paths that
+  include /mnt.  I did this in the example because the target filesystem
+  may not support the creation of Linux device files for the boot= and
+  root= options.
+
+  66..  DDeeaalliinngg wwiitthh uunnssuuppppoorrtteedd ccaarrddss
+
+  66..11..  CCoonnffiigguurriinngg uunnrreeccooggnniizzeedd ccaarrddss
+
+  Assuming that your card is supported by an existing driver, all that
+  needs to be done is to add an entry to /etc/pcmcia/config to tell
+  cardmgr how to identify the card, and which driver(s) need to be
+  linked up to this card.  Check the man page for pcmcia for more
+  information about the config file format.  If you insert an unknown
+  card, cardmgr will normally record some identification information in
+  the system log that can be used to construct the config entry.  This
+  information can also be displayed with the ``cardctl ident'' command.
+
+  Here is an example of how cardmgr will report an unsupported card in
+  /usr/adm/messages.
+
+       cardmgr[460]: unsupported card in socket 1
+       cardmgr[460]: product info: "MEGAHERTZ", "XJ2288", "V.34 PCMCIA MODEM"
+       cardmgr[460]: manfid: 0x0101, 0x1234  function: 2 (serial)
+
+  The corresponding entry in /etc/pcmcia/config would be:
+
+       card "Megahertz XJ2288 V.34 Fax Modem"
+         version "MEGAHERTZ", "XJ2288", "V.34 PCMCIA MODEM"
+         bind "serial_cs"
+
+  or using the more compact product ID codes:
+
+       card "Megahertz XJ2288 V.34 Fax Modem"
+         manfid 0x0101, 0x1234
+         bind "serial_cs"
+
+  You can use ``*'' to match strings that don't need to match exactly,
+  like version numbers.  When making new config entries, be careful to
+  copy the strings exactly, preserving case and blank spaces.  Also be
+  sure that the config entry has the same number of strings as are
+  reported in the log file.
+
+  Beware that you can specify just about any driver for a card, but if
+  you're just shooting in the dark, there is not much reason to expect
+  this to be productive.  You may get lucky and find that your card is
+  supported by an existing driver.  However, the most likely outcome is
+  that the driver won't work, and may have unfortunate side effects like
+  locking up your system.  Unlike most ordinary device drivers, which
+  probe for an appropriate card, the probe for a PCMCIA device is done
+  by cardmgr, and the driver itself may not do much validation before
+  attempting to communicate with the device.
+
+  After editing /etc/pcmcia/config, you can signal cardmgr to reload the
+  file with:
+
+       kill -HUP `cat /var/run/cardmgr.pid`
+
+  If you do set up an entry for a new card, please send me a copy so
+  that I can include it in the standard config file.
+
+  66..22..  AAddddiinngg ssuuppppoorrtt ffoorr aann NNEE22000000--ccoommppaattiibbllee eetthheerrnneett ccaarrdd
+
+  Before you begin: this procedure will only work for simple ethernet
+  cards.  Multifunction cards (i.e., ethernet/modem combo cards) have an
+  extra layer of complexity regarding how the two functions are
+  integrated, and generally cannot be supported without obtaining some
+  configuration information from the card vendor.  Using the following
+  procedure for a multifunction card will not be productive.
+
+  First, see if the card is already recognized by cardmgr.  Some cards
+  not listed in SUPPORTED.CARDS are actually OEM versions of cards that
+  are supported.  If you find a card like this, let me know so I can add
+  it to the list.
+
+  If your card is not recognized, follow the instructions in the
+  ``Configuring unrecognized cards'' section to create a config entry
+  for your card, and bind the card to the pcnet_cs driver.  Restart
+  cardmgr to use the updated config file.
+
+  If the pcnet_cs driver says that it is unable to determine your card's
+  hardware ethernet address, then edit your new config entry to bind the
+  card to the memory card driver, memory_cs.  Restart cardmgr to use the
+  new updated config file.  You will need to know your card's hardware
+  ethernet address.  This address is a series of six two-digit hex
+  numbers, often printed on the card itself.  If it is not printed on
+  the card, you may be able to use a DOS driver to display the address.
+  In any case, once you know it, run:
+
+       dd if=/dev/mem0a count=20 | od -Ax -t x1
+
+  and search the output for your address.  Only the even bytes are
+  defined, so ignore the odd bytes in the dump.  Record the hex offset
+  of the first byte of the address.  Now, edit clients/pcnet_cs.c and
+  find the hw_info structure.  You'll need to create a new entry for
+  your card.  The first field is the memory offset.  The next three
+  fields are the first three bytes of the hardware address.  The final
+  field contains some flags for specific card features; to start, try
+  setting it to 0.
+
+  After editing pcnet_cs.c, compile and install the new module.  Edit
+  /etc/pcmcia/config again, and change the card binding from memory_cs
+  to pcnet_cs.  Follow the instructions for reloading the config file,
+  and you should be all set.  Please send me copies of your new hw_info
+  and config entries.
+
+  If you can't find your card's hardware address in the hex dump, as a
+  method of last resort, it is possible to ``hard-wire'' the address
+  when the pcnet_cs module is initialized.  Edit /etc/pcmcia/config.opts
+  and add a hw_addr= option, like so:
+
+       module "pcnet_cs" opts "hw_addr=0x00,0x80,0xc8,0x01,0x02,0x03"
+
+  Substitute your own card's hardware address in the appropriate spot,
+  of course.  Beware that if you've gotten this far, it is very unlikely
+  that your card is genuinely NE2000 compatible.  In fact, I'm not sure
+  if there are _a_n_y cards that are not handled by one of the first two
+  methods.
+
+  66..33..  PPCCMMCCIIAA ffllooppppyy iinntteerrffaaccee ccaarrddss
+
+  The PCMCIA floppy interface used in the Compaq Aero and a few other
+  laptops is not yet supported by this package.  The snag in supporting
+  the Aero floppy is that the Aero seems to use a customized PCMCIA
+  controller to support DMA to the floppy.  Without knowing exactly how
+  this is done, there isn't any way to implement support under Linux.
+
+  If the floppy adapter card is present when an Aero is booted, the Aero
+  BIOS will configure the card, and Linux will identify it as a normal
+  floppy drive.  When the Linux PCMCIA drivers are loaded, they will
+  notice that the card is already configured and attached to a Linux
+  driver, and this socket will be left alone.  So, the drive can be used
+  if it is present at boot time, but the card is not hot swappable.
+
+  77..  DDeebbuuggggiinngg ttiippss aanndd pprrooggrraammmmiinngg iinnffoorrmmaattiioonn
+
+  77..11..  SSuubbmmiittttiinngg uusseeffuull bbuugg rreeppoorrttss
+
+  The best way to submit bug reports is to use the HyperNews message
+  lists on the Linux PCMCIA information site.  That way, other people
+  can see current problems (and fixes or workarounds, if available).
+  Here are some things that should be included in all bug reports:
+
+  +o  Your system brand and model.
+
+  +o  What PCMCIA card(s) you are using.
+
+  +o  Your Linux kernel version (i.e., ``uname -rv''), and PCMCIA driver
+     version (i.e., ``cardctl -V'').
+
+  +o  Any changes you have made to the startup files in /etc/pcmcia, or
+     to the PCMCIA startup script.
+
+  +o  All PCMCIA-related messages in your system log file.  That includes
+     startup messages, and messages generated when your cards are
+     configured.
+
+  All the PCMCIA modules and the cardmgr daemon send status messages to
+  the system log.  This will usually be something like /var/log/messages
+  or /usr/adm/messages.  This file should be the first place to look
+  when tracking down a problem.  When submitting a bug report, always
+  include the relevant contents of this file.  If you are having trouble
+  finding your system messages, check /etc/syslog.conf to see how
+  different classes of messages are handled.
+
+  Before submitting a bug report, please check to make sure that you are
+  using an up-to-date copy of the driver package.  While it is somewhat
+  gratifying to read bug reports for things I've already fixed, it isn't
+  a particularly constructive use of my time.
+
+  If you do not have web access, bug reports can be sent to me at
+  dhinds@pcmcia.sourceforge.org.  However, I prefer that bug reports be
+  posted to my web site, so that they can be seen by others.
+
+  77..22..  IInntteerrpprreettiinngg kkeerrnneell ttrraapp rreeppoorrttss
+
+  If your problem involves a kernel fault, the register dump from the
+  fault is only useful if you can translate the fault address, EIP, to
+  something meaningful.  Recent versions of klogd attempt to translate
+  fault addresses based on the current kernel symbol map, but this may
+  not work if the fault is in a module, or if the problem is severe
+  enough that klogd cannot finish writing the fault information to the
+  system log.
+
+  If a fault is in the main kernel, the fault address can be looked up
+  in the System.map file.  This may be installed in /System.map or
+  /boot/System.map.  If a fault is in a module, the nm command gives the
+  same information, however, the fault address has to be adjusted based
+  on the module's load address.  Let's say that you have the following
+  kernel fault:
+
+  Unable to handle kernel NULL pointer dereference
+  current->tss.cr3 = 014c9000, %cr3 = 014c9000
+  *pde = 00000000
+  Oops: 0002
+  CPU:    0
+  EIP:    0010:[<c2026081>]
+  EFLAGS: 00010282
+
+  The fault address is 0xc2026081.  Looking at System.map, we see that
+  this is past the end of the kernel, i.e., is in a kernel module.  To
+  determine which module, check the output of ``ksyms -m | sort'':
+
+       Address   Symbol                            Defined by
+       c200d000  (35k)                             [pcmcia_core]
+       c200d10c  register_ss_entry                 [pcmcia_core]
+       c200d230  unregister_ss_entry               [pcmcia_core]
+                 ...
+       c2026000  (9k)                              [3c574_cs]
+       c202a000  (4k)                              [serial_cs]
+
+  So, 0xc2026081 is in the 3c574_cs module, and is at an offset of
+  0x0081 from the start of the module.  We cannot look up this offset in
+  3c574_cs.o yet: when the kernel loads a module, it inserts a header at
+  the module load address, so the real start of the module is offset
+  from the address shown in ksyms.  The size of the header varies with
+  kernel version: to find out the size for your kernel, check a module
+  that exports symbols (like pcmcia_core above), and compare a symbol
+  address with nm output for that symbol.  In this example,
+  register_ss_entry is loaded at an offset of 0xc200d10c - 0xc200d000 =
+  0x010c, while ``nm pcmcia_core.o'' shows the offset as 0x00c0, so the
+  header size is 0x010c - 0x00c0 = 0x004c bytes.
+
+  Back to 3c574_cs, our fault offset is 0x0081, and subtracting the
+  0x004c header, the real module offset is 0x0035.  Now looking at ``nm
+  3c574_cs.o | sort'', we see:
+
+       0000002c d if_names
+       0000002c t tc574_attach
+       00000040 d mii_preamble_required
+       00000041 d dev_info
+
+  So, the fault is located in tc574_attach().
+
+  In this example, the fault did not cause a total system lockup, so
+  ksyms could be executed after the fault happened.  In other cases, you
+  may have to infer the module load addresses indirectly.  The same
+  sequence of events will normally load modules in the same order and at
+  the same addresses.  If a fault happens when a certain card is
+  inserted, get the ksyms output before inserting the card, or with a
+  different card inserted.  You can also manually load the card's driver
+  modules with insmod and run ksyms before inserting the card.
+
+  For more background, see ``man insmod'', ``man ksyms'', and ``man
+  klogd''.  In the kernel source tree, Documentation/oops-tracing.txt is
+  also relevant.  Here are a few more kernel debugging hints:
+
+  +o  Depending on the fault, it may also be useful to translate
+     addresses in the ``Call Trace'', using the same procedure as for
+     the main fault address.
+
+  +o  To diagnose a silent lock-up, try to provoke the problem with X
+     disabled, since kernel messages sent to the text console will not
+     be visible under X.
+
+  +o  If you kill klogd, most kernel messages will be echoed directly on
+     the text console, which may be helpful if the problem prevents
+     klogd from writing to the system log.
+
+  +o  To cause all kernel messages to be sent to the console, for 2.1
+     kernels, if /proc/sys/kernel/printk exists, do:
+
+       echo 8 > /proc/sys/kernel/printk
+
+  +o  The key combination <RightAlt><ScrLk> prints a register dump on the
+     text console.  This may work even if the system is otherwise
+     completely unresponsive, and the EIP address can be interpreted as
+     for a kernel fault.
+
+  +o  For 2.1 kernels configured with CONFIG_MAGIC_SYSRQ enabled, various
+     emergency functions are available via special <Alt><SysRq> key
+     combinations, documented in Documentation/sysrq.txt in the kernel
+     source tree.
+
+  77..33..  LLooww lleevveell PPCCMMCCIIAA ddeebbuuggggiinngg aaiiddss
+
+  The PCMCIA modules contain a lot of conditionally-compiled debugging
+  code.  Most of this code is under control of the PCMCIA_DEBUG
+  preprocessor define.  If this is undefined, debugging code will not be
+  compiled.  If set to 0, the code is compiled but inactive.  Larger
+  numbers specify increasing levels of verbosity.  Each module built
+  with PCMCIA_DEBUG defined will have an integer parameter, pc_debug,
+  that controls the verbosity of its output.  This can be adjusted when
+  the module is loaded, so output can be controlled on a per-module
+  basis without recompiling.
+
+  Your default configuration for syslogd may discard kernel debugging
+  messages.  To ensure that they are recorded, edit /etc/syslog.conf to
+  ensure that ``kern.debug'' messages are recorded somewhere.  See ``man
+  syslog.conf'' for details.
+
+  There are a few register-level debugging tools in the debug_tools/
+  subdirectory of the PCMCIA distribution.  The dump_tcic and dump_i365
+  utilities generate register dumps for ISA-to-PCMCIA controllers.  In
+  3.1.15 and later releases, dump_i365 is replaced by dump_exca, which
+  is similar but also works for PCI-to-CardBus bridges.  Also new in
+  3.1.15 for CardBus bridges is the dump_cardbus tool, which interprets
+  the CardBus-specific registers.  These are all most useful if you have
+  access to a datasheet for the corresponding controller chip.  The
+  dump_cis utility (dump_tuples in pre-3.0.2 distributions) lists the
+  contents of a card's CIS (Card Information Structure), and decodes
+  most of the important bits.  And the dump_cisreg utility displays a
+  card's local configuration registers.
+  The memory_cs memory card driver is also sometimes useful for
+  debugging problems with 16-bit PC Cards.  It can be bound to any card,
+  and does not interfere with other drivers.  It can be used to directly
+  access any card's attribute memory or common memory.  Similarly for
+  CardBus cards, the memory_cb driver can be bound to any 32-bit card,
+  to give direct access to that card's address spaces.  See the man
+  pages for more information.
+
+  77..44..  //pprroocc//bbuuss//ppccccaarrdd
+
+  Starting with 2.1.103 kernels, the PCMCIA package will create a tree
+  of status information under /proc/bus/pccard.  Much of the information
+  can only be interpreted using the data sheets for the PCMCIA host
+  controller.  Its contents may depend on how the drivers were
+  configured, but may include all or some of the following:
+
+     /proc/bus/pccard/{irq,ioport,memory}
+        If present, these files contain resource allocation information
+        to supplement the normal kernel resource tables.  Recent
+        versions of the PCMCIA system may obtain additional resource
+        information from the Plug and Play BIOS if configured to do so.
+
+     /proc/bus/pccard/drivers
+        In recent releases, this lists all currently loaded PCMCIA
+        client drivers.  Unlike /proc/modules, it also lists drivers
+        that may be statically linked into the kernel.
+
+     /proc/bus/pccard/*/info
+        For each socket, describes that socket's host controller and its
+        capabilities.
+
+     /proc/bus/pccard/*/exca
+        This contains a dump of a controller's ``ExCA'' Intel i82365sl-
+        compatible register set.
+
+     /proc/bus/pccard/*/{pci,cardbus}
+        For CardBus bridges, a dump of the bridge's PCI configuration
+        space, and a dump of the bridge's CardBus configuration
+        registers.
+
+  77..55..  WWrriittiinngg CCaarrdd SSeerrvviicceess ddrriivveerrss ffoorr nneeww ccaarrddss
+
+  The Linux PCMCIA Programmer's Guide is the best documentation for the
+  client driver interface.  The latest version is always available from
+  sourceforge.org in /pcmcia/doc, or on the web at
+  <http://pcmcia.sourceforge.org>.
+
+  For devices that are close relatives of normal ISA devices, you will
+  probably be able to use parts of existing Linux drivers.  In some
+  cases, the biggest stumbling block will be modifying an existing
+  driver so that it can handle adding and removing devices after boot
+  time.  Of the current drivers, the memory card driver is the only
+  ``self-contained'' driver that does not depend on other parts of the
+  Linux kernel to do most of the dirty work.
+
+  In many cases, the largest barrier to supporting a new card type is
+  obtaining technical information from the manufacturer.  It may be
+  difficult to figure out who to ask, or to explain exactly what
+  information is needed.  However, with a few exceptions, it is very
+  difficult if not impossible to implement a driver for a card without
+  technical information from the manufacturer.
+
+  I have written a dummy driver with lots of comments that explains a
+  lot of how a driver communicates with Card Services; you will find
+  this in the PCMCIA source distribution in clients/dummy_cs.c.
+
+  77..66..  GGuuiiddeelliinneess ffoorr PPCCMMCCIIAA cclliieenntt ddrriivveerr aauutthhoorrss
+
+  I have decided that it is not really feasible for me to distribute all
+  PCMCIA client drivers as part of the PCMCIA package.  Each new driver
+  makes the main package incrementally harder to maintain, and including
+  a driver inevitably transfers some of the maintenance work from the
+  driver author to me.  Instead, I will decide on a case by case basis
+  whether or not to include contributed drivers, based on user demand as
+  well as maintainability.  For drivers not included in the core
+  package, I suggest that driver authors adopt the following scheme for
+  packaging their drivers for distribution.
+
+  Driver files should be arranged in the same directory scheme used in
+  the PCMCIA source distribution, so that the driver can be unpacked on
+  top of a complete PCMCIA source tree.  A driver should include source
+  files (in ./modules/), a man page (in ./man/), and configuration files
+  (in ./etc/).  The top level directory should also include a README
+  file.
+
+  The top-level directory should include a makefile, set up so that
+  ``make -f ... all'' and ``make -f ... install'' compile the driver and
+  install all appropriate files.  If this makefile is given an extension
+  of .mk, then it will automatically be invoked by the top-level
+  Makefile for the all and install targets.  Here is an example of how
+  such a makefile could be constructed:
+
+       # Sample Makefile for contributed client driver
+       FILES = sample_cs.mk README.sample_cs \
+               modules/sample_cs.c modules/sample_cs.h \
+               etc/sample.conf etc/sample etc/sample.opts \
+               man/sample_cs.4
+       all:
+               $(MAKE) -C modules MODULES=sample_cs.o
+       install:
+               $(MAKE) -C modules install-modules MODULES=sample_cs.o
+               $(MAKE) -C etc install-clients CLIENTS=sample
+               $(MAKE) -C man install-man4 MAN4=sample_cs.4
+       dist:
+               tar czvf sample_cs.tar.gz $(FILES)
+
+  This makefile uses install targets defined in 2.9.10 and later
+  versions of the PCMCIA package.  This makefile also includes a
+  ``dist'' target for the convenience of the driver author.  You would
+  probably want to add a version number to the final package filename
+  (for example, sample_cs-1.5.tar.gz).  A complete distribution could
+  look like:
+
+  sample_cs.mk
+  README.sample_cs
+  modules/sample_cs.c
+  modules/sample_cs.h
+  etc/sample.conf
+  etc/sample
+  etc/sample.opts
+  man/sample_cs.4
+
+  With this arrangement, when the contributed driver is unpacked, it
+  becomes essentially part of the PCMCIA source tree.  It can make use
+  of the PCMCIA header files, as well as the machinery for checking the
+  user's system configuration, and automatic dependency checking, just
+  like a ``normal'' client driver.
+
+  In this example, etc/sample and etc/sample.opts would be the new
+  driver's configuration scripts (if needed), and etc/sample.conf would
+  contain any additions to the PCMCIA card configuration file.  Starting
+  with the 3.1.6 release, cardmgr will automatically process any *.conf
+  files installed in /etc/pcmcia, so installation of contributed drivers
+  should no longer require hand editing configuration files.
+
+  I will accept client drivers prepared according to this specification
+  and place them in the /pcmcia/contrib directory on sourceforge.org.
+  The README in this directory will describe how to unpack a contributed
+  driver.
+
+  The client driver interface has not changed much over time, and has
+  almost always preserved backwards compatibility.  A client driver will
+  not normally need to be updated for minor revisions in the main
+  package.  I will try to notify authors of contributed drivers of
+  changes that require updates to their drivers.
+
+  77..77..  GGuuiiddeelliinneess ffoorr LLiinnuuxx ddiissttrriibbuuttiioonn mmaaiinnttaaiinneerrss
+
+  If your distribution has system configuration tools that you would
+  like to be PCMCIA-aware, please use the *.opts files in /etc/pcmcia
+  for your ``hooks.''  These files will not be modified if a user
+  compiles and installs a new release of the PCMCIA package.  If you
+  modify the main configuration scripts, then a fresh install will
+  silently overwrite your custom scripts and break the connection with
+  your configuration tools.  Contact me if you are not sure how to write
+  an appropriate option script, or if you need additional capabilities.
+
+  It is helpful for users (and for me) if you can document how your
+  distribution deviates from the PCMCIA package as described in this
+  document.  In particular, please document changes to the startup
+  script and configuration scripts.  If you send me the appropriate
+  information, I will include it in the ``Notes about specific Linux
+  distributions''.
+
+  When building PCMCIA for distribution, consider including contributed
+  drivers that are not part of the main PCMCIA package.  For reasons of
+  maintainability, I am trying to limit the core package size, by only
+  adding new drivers if I think they are of particularly broad interest.
+  Other drivers will be distributed separately, as described in the
+  previous section.  The split between integral and separate drivers is
+  somewhat arbitrary and partly historical, and should not imply a
+  difference in quality.
+
Index: oldkernel/linux/pcmcia-cs-3.1.15/README
diff -u /dev/null linux/pcmcia-cs-3.1.15/README:1.1
--- /dev/null	Mon Jul 31 21:15:09 2000
+++ linux/pcmcia-cs-3.1.15/README	Fri Jul  7 16:18:18 2000
@@ -0,0 +1,10 @@
+This version of Card Services should work with 2.0 and 2.2 kernels,
+and most 2.3 kernels.  It will not work with 1.3 or earlier kernels,
+and may not work with 2.1 kernels.
+
+The PCMCIA-HOWTO now includes all installation instructions.
+
+See the COPYING and LICENSE files for license information.
+
+	-- David Hinds
+	   dhinds@pcmcia.sourceforge.org
Index: oldkernel/linux/pcmcia-cs-3.1.15/SUPPORTED.CARDS
diff -u /dev/null linux/pcmcia-cs-3.1.15/SUPPORTED.CARDS:1.1
--- /dev/null	Mon Jul 31 21:15:09 2000
+++ linux/pcmcia-cs-3.1.15/SUPPORTED.CARDS	Fri Jul  7 16:18:18 2000
@@ -0,0 +1,622 @@
+		Linux PCMCIA Supported Device List
+
+		Last updated: 2000/05/08 19:42:08
+
+The following cards are known to work in at least one actual system.
+Other cards may also work -- if you can get a card to work that is not
+on this list, please let me know.  This list is complete to the best
+of my knowledge.
+
+CardBus cards are listed at the end of each section.  At this time,
+all CardBus drivers should be treated as experimental.  Beware that
+some cards have 16-bit and CardBus versions with very similar names.
+If the CardBus version is not specifically listed as supported here,
+then you should not expect it to work.
+
+Next to each driver, I've tried to indicate which system architectures
+(x86,ppc,axp) are known to be supported.  This information is likely
+to be incomplete, and additions/corrections would be very welcome.
+
+	-- David Hinds <dhinds@pcmcia.sourceforge.org>
+
+Ethernet cards:
+
+	[3c589_cs driver] [x86,ppc]
+	3Com 3c589, 3c589B, 3c589C, 3c589D
+	3Com Megahertz 3CXE589D, 3CXE589EC, 3CCE589ET
+	Farallon EtherWave, EtherMac
+
+	[fmvj18x_cs driver] [x86,ppc]
+	CONTEC C-NET(PC)C
+	Eagle NE200 Ethernet
+	Eiger Labs EPX-10BT, EPX-ET 10BT, EPX-ET 10TZ
+	Fujitsu FMV-J181, FMV-J182A, FMV-J183
+	Fujitsu Towa LA501, FMV-1080, FM50N-183
+	Hitachi HT-4840-11 EtherCard
+	NextCom NC5310
+	RATOC REX-9822, REX-5588A/W, REX-R280
+	TDK LAC-CD02x, LAK-CD021, LAK-CD022A, LAK-CD021AX, LAK-CD021BX
+
+	[nmclan_cs driver] [x86,ppc]
+	New Media EthernetLAN
+	New Media LiveWire	[ NOT the LiveWire+ ]
+
+	[pcnet_cs driver] [x86,axp]
+	4Lan EP100 Ethernet
+	Accton EN2212, EN2216 EtherCard
+	Accton SOHO BASIC EN220
+	Addtron Ethernet
+	AIBrain EPCM-T
+	Allied Telesis CentreCOM CE6001, LA-PCM, LA-PCM V2
+	AmbiCom AMB8002, AMB8002T, AMB8010
+	AnyCom ECO Ethernet
+	Apollo RE450CT
+	Archtek Ethernet
+	Argosy EN210
+	Ark Sky-Link Express PA2100
+	Arowana RE 450 Ethernet
+	Asante FriendlyNet	[ new cards seem to not work!! ]
+	AST 1082 Ethernet
+	Atelco ethernet
+	Billionton LNT-10TB, LNT-10TN
+	California Access LAN Adapter
+	CeLAN EPCMCIA
+	CNet CN30BC, CN40BC Ethernet
+	Compex/ReadyLINK Ethernet Combo
+	Compex LinkPort Ethernet
+	COMPU-SHACK BASEline Ethernet
+	Connectware LANdingGear Adapter
+	Corega Ether PCC-T, PCM-T
+	CyQ've ELA-010 10baseT
+	Danpex EN-6200P2 Ethernet
+	Datatrek NetCard
+	Dayna Communications CommuniCard E
+	Digital DEPCM-AA, PCP78-AC Ethernet
+	Digital EtherWORKS Turbo Ethernet
+	D-Link DE-650, DE-660
+	DynaLink L10C Ethernet
+	Edimax Technology Ethernet Combo
+	EFA InfoExpress 205, 207 Combo
+	Eiger Labs EPX-ET10T2 Combo
+	ELECOM Laneed LD-CDWA, LD-CDX, LD-CDNIA, LD-CDY, LD-CDF
+	EP-210 Ethernet
+	Epson Ethernet
+	EtherPRIME Ethernet
+	Explorer NE-10000 Ethernet
+	EZLink 4109 Ethernet
+	Fiberline FL-4680
+	Gateway 2000 Ethernet
+	Genius ME3000II Ethernet
+	Grey Cell Ethernet
+	GVC NIC-2000P Ethernet Combo
+	Hamlet LM560
+	Hawking PN650TX
+	Hypertec HyperNet
+	IBM CreditCard Ethernet Adapter
+	IC-Card Ethernet
+	Infotel IN650ct Ethernet
+	IO DATA PCLA/T, PCLA/TE
+	Katron PE-520 Ethernet
+	KingMax Technology EN10-T2 Ethernet
+	Kingston KNE-PCM/M, KNE-PC2, KNE-PC2T
+	KTI PE-520 Plus
+	LANEED LD-CDW Ethernet
+	LanPro EP4000A
+	Lantech Ethernet
+	Level One EPC-0100TB
+	Linksys EtherCard, EC2T Combo
+	Logitec LPM-LN10T, LPM-LN10BA, LPM-LN20T Ethernet
+	Longshine ShineNet LCS-8534TB Ethernet
+	Macnica ME-1 Ethernet
+	Maxtech PCN2000 Ethernet
+	Melco LPC-TJ, LPC-TS, LPC-T, LPC2-T
+	Microdyne NE4200 Ethernet
+	Micronet SP122
+	Midori LANNER LT-PCMT
+	NDC Instant-Link
+	NEC PC-9801N-J12
+	Network General "Sniffer"
+	New Media LanSurfer
+	UNEX NexNIC MA010
+	Novell/National NE4100 InfoMover
+	OvisLink Ethernet
+	Panasonic CF-VEL211P-B
+	Planet SmartCOM 2000, 3500, ENW-3501-T, ENW-3502-T
+	Pretec Ethernet
+	PreMax PE-200 Ethernet
+	Proteon Ethernet
+	Psion Gold Card Ethernet
+	Relia RE2408T Ethernet
+	Reliasys 2400A Ethernet
+	RPTI EP400, EP401, 1625B Ethernet
+	SCM Ethernet		[ Yes, SCM != SMC ]
+	Sky Link Express
+	SMC 8022 EZCard-10
+	Socket Communications EA LAN Adapter
+	Socket Communications LP-E Ethernet
+	Socket Communications LP-E CF+ Ethernet
+	SOHOware ND5120-E Ethernet
+	SuperSocket RE450T
+	Surecom Ethernet
+	SVEC PN605C
+	Thomas-Conrad Ethernet
+	TRENDnet Ethernet
+	Trust Ethernet Combo
+	Volktek NPL-402CT Ethernet
+
+	[smc91c92_cs driver] [x86,ppc]
+	Farallon Enet
+	Megahertz XJ10BT, XJ10BC, CC10BT Ethernet
+	New Media BASICS Ethernet
+	Ositech Four of Diamonds
+	SMC 8020BT EtherEZ	[ NOT the EliteCard! ]
+
+	[xirc2ps_cs driver] [x86,axp]
+	Compaq Ethernet Adapter
+	Xircom CreditCard CE2, CE IIps, RE-10
+
+Fast Ethernet (10/100baseT) adapters:
+
+	[3c574_cs driver] [x86]
+	3Com 3c574TX, 3CCFE574BT, 3CXFE574BT, 3CCSH572BT, 3CXSH572BT
+
+	[pcnet_cs driver] [x86]
+	Abocom LinkMate FE1000
+	AnyCom ECO Ethernet 10/100
+	Apollo Fast Ethernet
+	COMPU-SHACK FASTline 10/100
+	Corega FastEther PCC-TX
+	Digicom Palladio
+	D-Link DFE-650
+	EXP ThinLan 100
+	Fiberline Fast Ethernet
+	Hamlet FE1000 10/100
+	IO DATA PCET/TX
+	KTI KF-C16
+	Laneed LD-10/100CD
+	LevelOne FPC-0100TX
+	Linksys PCMPC100 EtherFast, PCM100H1 HomeLink 10/100, NP100
+	Logitec LPM-LN100TX
+	Melco LPC2-TX
+	Microcom TravelCard 10/100
+	Micronet EtherFast Adapter
+	NetGear FA410TXC
+	New Media LiveWire 10/100
+	Planex FNW-3600T
+	ZONET Fast Ethernet
+
+	[smc91c92_cs driver] [x86]
+	Argosy EN220
+	Dynalink L100C
+	EXP ThinLan-110
+	Lantech FastNet/TX
+	Melco/SMC LPC-TX
+	Ositech Seven of Diamonds
+	Psion Gold Card Netglobal
+	WiseCom WC-PC400
+	
+	[xirc2ps_cs driver] [x86,axp]
+	Accton Fast EtherCard-16
+	Compaq Netelligent 10/100
+	Intel EtherExpress PRO/100 16-bit
+	Toshiba IPC5008A, Advanced Network 10/100
+	Xircom CreditCard CE3-100, CE3B, RE-100
+
+	[3c575_cb driver] [x86]
+	3Com 3c575TX, 3CCFE575BT, 3CXFE575BT, 3CCFE575CT, 3CXFE575CT
+
+	[epic_cb driver] [x86]
+	[requires a 2.2 kernel, experimental!]
+	Ositech Seven of Spades CardBus
+
+	[tulip_cb driver] [x86]
+	[requires a 2.2 kernel, experimental!]
+	Accton EN2220 CardBus
+	Allied Telesyn AT-2800
+	AmbiCom AMB8100
+	Apollo FE2000
+	Asante FriendlyNET CardBus
+	Compex Linkport TX
+	D-Link DFE-660TX
+	Genius MF3000			[ some do not work?? ]
+	Kingston KNE-CB4TX
+	Laneed LD-10/100CB
+	LevelOne FPC-0101TX 10/100Mbps CardBus
+	Linksys PCMPC200 EtherFast CardBus
+	NetGear FA510C
+	OvisLink LFS PCM 32
+	PLANET ENW-3502-FC
+	PrimeXpress Fast Ethernet
+	SMC EZ CardBus 10/100 Ethernet	[ some do not work?? ]
+	SVEC FD606 10/100 Ethernet
+	TDK NetworkFlyer LAK-CB100X, LAK-CB100AX CardBus
+	UMAX Technologies UMAX250
+	[ Not recommended: support is experimental and unreliable ]
+	IBM 10/100 EtherJet CardBus
+	Intel EtherExpress PRO/100 CardBus Mobile Adapter32
+	Xircom CBEII-10/100, RBE-100
+
+Token-ring adapters:
+
+	[ibmtr_cs driver] [x86]
+	3Com 3c389 TokenLink Velocity
+	3Com 3c689 TokenLink III
+	IBM Token Ring Adapter
+	IBM Token Ring 16/4 Credit Card Adapter
+	IBM Token Ring Auto 16/4 Credit Card Adapter
+	IBM Turbo 16/4 Token Ring PC Card
+
+Wireless network adapters:
+
+	[airo_cs driver]
+	Aironet PC4500, PC4800 wireless network adapters
+
+	[netwave_cs driver] [x86]
+	Breezenet SA-PX
+	Xircom CreditCard Netwave
+
+	[ray_cs driver] [x86,axp]
+	Raytheon Raylink
+	WebGear Aviator 2.4, Aviator Pro
+
+	[wavelan_cs driver] [x86]
+	AT&T / NCR / Lucent WaveLAN version 2.0
+	DEC RoamAbout/DS
+
+	[wvlan_cs driver] [x86,axp]
+	Lucent WaveLAN/IEEE 802.11(b)
+	Melco WLI-PCM-L11
+	NCR WaveLAN/IEEE 802.11
+	Cabletron RoamAbout 802.11 DS
+
+Modem and serial cards:
+
+	[ Virtually all modem cards, simple serial port cards, and
+	digital cellular modems should work.  The only exceptions are
+	so-called "WinModems" that require special Windows drivers.
+	ISDN modems that emulate a standard UART are also supported. ]
+
+	[serial_cs driver] [x86,axp]
+	Advantech COMpad-32/85 dual serial
+	Argosy dual serial
+	Black Box I114A RS-422/485
+	National Instruments PCMCIA-232, PCMCIA-232/2, PCMCIA-232/4
+	National Instruments PCMCIA-485, PCMCIA-485/2
+	Omega Engineering QSP-100
+	Quatech, IOTech dual RS-232 cards
+	Quatech quad RS-232 card
+	Socket Communications dual RS-232 card
+	Trimble Mobile GPS
+
+	[ The following cards are WinModems and are NOT supported ]
+	3Com/Megahertz 3CXM356/3CCM356, 3CXM656/3CCM656
+	3Com/USRobotics 3014a
+	Abocom FM560CB
+	Billionton 56K HSP
+	Com1 Platinum MC221 Discovery 56K
+	Compaq 192
+	IBM 10L7394
+	Megahertz XJ/CC2560
+	Motorola Montana
+	New Media WinSurfer
+	
+Parallel port cards:
+
+	 [parport_cs driver] [x86]
+	 [requires a 2.2 or later kernel]
+	 Quatech SPP-100
+	 IOtech DBK35, WBK20A
+
+Memory cards:
+
+	[ All SRAM cards should work.  Unsupported flash cards can be
+	read but not written. ]
+
+	[memory_cs driver] [x86,axp,ppc]
+	Intel Series 2, Series 2+, and Value Series 100 Flash
+	Maxtor MobileMax 16MB Flash
+	IBM 8MB Flash
+	RATOC SmartMedia Adapter
+	TDK Flash Memory SFM20W/C 20MB
+
+SCSI adapters:
+
+	[ Be careful.  Many vendors. particularly CD-ROM vendors, seem
+	to switch controller chips more or less at will.  Generally,
+	they'll use a different product code, but not always: older
+	(supported) New Media Bus Toaster cards are not easily
+	distinguishable from the current Symbios-based cards, which
+	use the sym53c500_cs driver, distributed separately. ]
+
+	[aha152x_cs driver] [x86]
+	Adaptec APA-1460, APA-1450A, APA-1460A/B/C/D SlimSCSI
+	Iomega Zip and Jaz Cards
+	New Media Bus Toaster SCSI	[ older cards ]
+	New Media Toast 'n Jam		[ SCSI only ]
+	Noteworthy Bus Toaster SCSI
+	Sony CD-ROM Discman PRD-250
+	Toshiba HandyCard SCSI
+
+	[fdomain_cs driver] [x86]
+	Future Domain SCSI2GO
+	IBM SCSI
+	Simple Technologies SCSI
+
+	[qlogic_cs driver] [x86]
+	Eiger Labs SCSI			[ only cards w/FCC ID LXL... ]
+	Epson SC200
+	MACNICA mPS110, mPS110-LP SCSI
+	Midori CN-SC43
+	NEC PC-9801N-J03R
+	Qlogic FastSCSI
+	Panasonic KXL-D740, KXL-DN740A, KXL-DN740A-NB 4X CD-ROM
+	Panasonic KXL-810AN, KXL-783A
+	Pioneer PCP-PR2W
+	Raven CD-Note 4X
+	RATOC REX-9530 SCSI-2
+	Toshiba NWB0107ABK, SCSC200A, SCSC200B
+
+	[not sure which driver]
+	Digital SCSI II adapter
+	IO DATA PCSC-II, PCSC-II-L
+	IO DATA CDG-PX44/PCSC CD-ROM
+	Logitec LPM-SCSI2
+	Logitec LCD-601 CD-ROM
+	Melco IFC-SC2, IFC-DC
+	Pioneer PCP-PR1W, PCP-PR2W CD-ROM
+	Taxan ICD-400PN
+
+	[apa1480_cb driver] [x86]
+	[recommend 2.2 or later kernel, experimental!]
+	Adaptec SlimSCSI 1480 CardBus
+
+Multifunction ethernet/modem cards:
+
+	[3c589_cs driver] [x86]
+	3Com 3c562, 3c562B/C/D, 3c563B/C/D
+	3Com Megahertz 3CCEM556, 3CXEM556, 3CCEM556B
+	Motorola Marquis
+
+	[3c574_cs driver] [x86]
+	3Com Megahertz 3CCFEM556B
+
+	[pcnet_cs driver] [x86,axp]
+	Accton EN2218, UE2218
+	ActionTec ComNet 33.6
+	AnyCom Fast Ethernet + 56K Combo
+	Asus combo card
+	Billionton LM5LT-10B
+	Dayna Communicard
+	D-Link DME-336T, DMF-560TX, DMF-560TXD
+	Grey Cell GCS3400
+	GVC LAN modem
+	IBM Home and Away
+	IBM Home and Away 28.8
+	IO DATA PCEM-336T
+	Linksys LANmodem 28.8 (PCMLM28), 33.6 (PCMLM336)
+	Linksys EtherFast LANmodem 56K (PCMLM56)
+	PREMAX LAN modem
+	Psion V.34 Gold Card
+	Rover ComboCard 33.6
+	TDK 3000/3400/5670
+	TDK DFL5610WS Fast Ethernet/Modem
+	Telecom Device SuperSocket LM336
+
+	[smc91c92_cs driver] [x86]
+	Gateway Telepath Combo
+	Megahertz/U.S. Robotics EM1144, EM3288, EM3336
+	Motorola Mariner
+	Ositech Jack of Diamonds, Jack of Hearts
+	Psion Gold Card Netglobal 56K+10Mb 
+
+	[xirc2ps_cs driver] [x86]
+	Compaq Microcom CPQ550 Modem + 10/100 LAN
+	Intel EtherExpress PRO/100 LAN/Modem
+	Xircom CreditCard CEM28, CEM33, CEM56
+	Xircom RealPort REM10BT, REM56G-100
+
+	[3c575_cb driver] [x86]
+	[ ethernet only: the modem is a WinModem! ]
+	3Com 3CCFEM656B, 3CCFEM656C, 3CXFEM656C
+
+	[epic_cb driver] [x86]
+	[requires a 2.2 kernel, experimental!]
+	Ositech Jack of Spades CardBus
+	Psion Gold Card Netglobal 56K+10/100Mb
+
+	[tulip_cb driver] [x86]
+	[ Not recommended: support is experimental and unreliable ]
+	Xircom RBEM56G-100BTX, CBEM56G-100BTX
+
+ATA/IDE card drives:
+
+	[ide_cs driver] [x86]
+	Most cards should work fine, including adapters for external
+	IDE devices.  Both Flash-ATA cards and 	rotating-media cards
+	are supported, including "Smartmedia" flash and Compact flash
+	cards.
+
+	The very old Western Digital 40MB drives are not supported,
+	because they do not conform to the PCMCIA ATA specification.
+
+ATA/IDE Interface Cards:
+
+	[ide_cs driver] [x86]
+	Apricorn ATA card, EZ-GIG transfer kit
+	Archos Zip100 MiniDrive
+	Microtech International XpressDock
+	DataStor Technology PCMCIA ATA/ATAPI Card
+	Creo DNBoy
+	GREYSTONE DD-25
+	IBM Portable Drive Bay		[ only CD-ROM tested ]
+	Shining Technology CitiDISK 250PE
+	Sicon Periperal Micro Mate
+
+ATA/IDE CD-ROM adapters:
+
+	[ide_cs driver] [x86]
+	Argosy EIDE CD-ROM
+	Caravelle CD-36N
+	CNF CARDport CD-ROM		[ 6/10/20/32X, but NOT 2X! ]
+	Creative Technology CD-ROM
+	Digital Mobile Media CD-ROM
+	EXP CD940 CD-ROM		[ Some work, some do NOT! ]
+	EXP Traveler 620, 3220 CD-ROM
+	Freecom IQ Traveller CD-ROM
+	H45 Technologies Quick 2X CD-ROM
+	H45 Technologies QuickCD 16X
+	IBM Max 20X CD-ROM
+	IO DATA CDP-TX4/PCIDE, CDP-TX6/PCIDE, CDV-HDN6/PCIDE
+	IO DATA CDP-TX10/PCIDE, CDP-FX24/CBIDE, MOP-230/PCIDE
+	IO DATA HDP-1G/PCIDE, HDP-1.6G/PCIDE
+	MCD601p CD-ROM
+	Microtech International MicroCD
+	Microtech Mii Zip 100
+	NOVAC NV-CD410
+	Sony PCGA-CD5, PCGA-CD51 CD-ROM
+	TEAC IDE Card/II
+
+The following cards have contributed drivers which are distributed as
+separate packages.  The drivers are not included in the base PCMCIA
+package for maintenance reasons: they are for less common cards and I
+cannot test them.  Most are available on the Linux PCMCIA FTP site, at
+ftp://sourceforge.org/pcmcia/contrib; some have their own web sites.
+
+	[asplus_cs driver]
+	Netwave AirSurfer Plus wireless network adapter
+	  http://ipoint.vlsi.uiuc.edu/wireless/asplus.html
+	  (Jay Moorman <jrmoorma@uiuc.edu>)
+
+	[cs89x0_cs driver]
+	IBM EtherJet
+	  (Danilo Beuche <danili@cs.uni-magdeburg.de>)
+
+	[das16s driver]
+	Computer Boards PCM-DAS16s/16 ADC
+	  ftp://fsmlabs.com/pub/rtlinux/
+	  (Steve Rosenbluth <stever@la.creatureshop.henson.com>)
+
+	[elsa_cs driver]
+	Elsa MicroLink ISDN adapter
+	  (Klaus Lichtenwalder <Klaus.Lichtenwalder@WebForum.DE>)
+
+	[floppy_cs driver]
+	Y-E Data FlashBuster floppy drive adapter
+	  (David Bateman <dbateman@eng.uts.edu.au>)
+
+	[iscc_cs driver]
+	IBM Smart Capture
+	RATOC REX-9590
+	  (Koji Okamura <oka@ec.kyushu-u.ac.jp>)
+
+	[mpsuni_cs driver]
+	MPS ISLINEnote ISDN adapter
+	  (Detlef Glaschick <glaschick@mps-software.de>)
+
+	[nin_cs driver]
+	IO Data PCSC-F SCSI adapter
+	  http://www.workbit.co.jp/workbit/products/nscsi-3.html
+	  (Yokota Hiroshi <yokota@netlab.is.tsukuba.ac.jp>)
+
+	[sedl_cs driver]
+	Sedlbauer Speed Star ISDN adapter
+	  (Marcus Niemann <niemann@www-bib.fh-bielefeld.de>)
+
+	[sym53c500_cs driver]
+	New Media Bus Toaster SCSI [ new version ]
+	New Media BASICS SCSI
+	SIMA TECH SCSI9000
+	  (Tim Corner <tcorner@via.at>)
+
+	[teles_cs driver]
+	Teles ISDN adapter
+	  http://home.wtal.de/petig/ISDN/index.html
+	  (Christof Petig <ea0141@uni-wuppertal.de>)
+
+	[ss5136dn_cs driver]  
+	SST 5136-DN-PC DeviceNet Interface
+	  http://www.spectra-one.com/dn5136man.html
+	  (Mark Sutton <marksu@spectra-one.com>)
+
+	[wavelan2_cs driver]
+	Lucent WaveLAN/IEEE wireless network adapter
+	  http://www.wavelan.com
+	  (Lucent Technologies <betasupport@wavelan.com>)
+
+	BreezeCOM SA-PCR Pro.11
+	  [ a driver is available from BreezeCOM ]
+
+	GemPlus GPR400 Smart Card Reader
+	  http://www.linuxnet.com/smartcard/code.html
+	  (Wolf Geldmacher <wgeldmacher@paus.ch>)
+
+	Harris PRISM/AM79C930 IEEE 802.11 wireless LAN
+	Nokia/InTalk ST-500A
+	Nokia C020
+	Samsung MagicWave SWL-1000N
+	Zoom Telephonics ZoomAir 4000
+	  http://www.absoval.com/linux-wlan
+	  (Mark Mathews <mark@absoval.com>)
+
+	National Instruments DAQcard700
+	  ftp://fsmlabs.com/pub/rtlinux/v1/drivers/daqcard700-1.02.tar.gz
+	  ftp://fsmlabs.com/pub/rtlinux/v2/new_drivers/daqcard700-1.04.tar.gz
+	  (Steve Rosenbluth <stever@la.creatureshop.henson.com>)
+
+	Proxim RangeLAN2 and Symphony wireless LAN cards
+	  http://www.komacke.com/distribution.html
+	  (Dave Koberstein <davek@komacke.com>)
+	
+	Silicom SPE ethernet, SEM EtherModem, SES EtherSerial
+	  http://www.silicom.co.il/linux.htm
+	
+	Winnov Videum Traveler camera
+	  http://www.eecs.umich.edu/~bnoble/group/wnv-pcmcia
+	  (Jim Zajkowski <jamesez@umich.edu>)
+	
+People are working on the following cards:
+
+	Roland SCP-55 MIDI (Toshiaki Nakatsu <risyu@zo-kun.to>)
+	CyberRom CD-ROM (David Rowntree <rowntree@dircon.co.uk>)
+	DAQCard-AI-16E-4 (Shao Zhang <shao@linuxfreak.com>,
+			  Cyrus Patel <cyrus@linuxfan.com>)
+	IO DATA PCSC-II (Katayama Nobuhiro <kata-n@po.iijnet.or.jp>)
+	Macnica mPS-1x0 (Katayama Nobuhiro <kata-n@po.iijnet.or.jp>)
+	TView Preso (Brenden Tuck <friar@zendragon.com>)
+	Proxim RangeLAN/2 (Jim Duchek <jimducheck@primary.net>
+	  http://students.ou.edu/D/James.R.Duchek-1/rangelan2.html
+
+The following cards are NOT supported.  This list is not meant to be
+comprehensive: I list these cards because people frequently ask about
+them.  In general, there are no technical reasons why a card is not
+supported: simply put, as far as I know, no one is working on these
+cards, therefore, drivers will not be written.  Most cards on this
+list have been there for a very long time, so please do not send me
+email just to ask if their status has changed.
+
+	Adaptec/Trantor APA-460 SlimSCSI
+	Eiger Labs SCSI w/FCC ID K36...
+	Melco LPC3-TX
+	New Media .WAVjammer and all other sound cards
+	New Media LiveWire+
+	Nikon CoolPix100
+	Panasonic KXL-D720, KXL-D745
+	SMC 8016 EliteCard
+	Xircom CEM II Ethernet/Modem
+	Xircom CE-10BT Ethernet
+	Xircom CBE-10/100 CardBus
+
+The following vendors have assisted in the development of the Linux
+PCMCIA driver package by contributing hardware and/or technical
+documentation about their products.  It could be inferred that since
+these vendors support Linux development and have provided technical
+help, that their cards are likely to be better supported under Linux.
+
+	3Com/Megahertz 	[ ethernet and multifunction cards ]
+	Adaptec		[ SCSI adapter cards ]
+	Intel		[ linear flash memory cards ]
+	Linksys		[ ethernet and multifunction cards ]
+	Ositech		[ ethernet/modem combo cards ]
+	Sandisk		[ ATA/IDE flash cards ]
+	Quatech		[ parallel port adapters ]
+	Xircom		[ ethernet and multifunction cards ]
Index: oldkernel/linux/pcmcia-cs-3.1.15/config.in
diff -u /dev/null linux/pcmcia-cs-3.1.15/config.in:1.1
--- /dev/null	Mon Jul 31 21:15:09 2000
+++ linux/pcmcia-cs-3.1.15/config.in	Fri Jul  7 16:18:18 2000
@@ -0,0 +1,15 @@
+#
+# config.in 1.15 2000/03/31 03:27:12 (David Hinds)
+#
+LINUX=/usr/src/linux
+MODPATH=/lib/modules
+CC=cc
+LD=ld
+PCDEBUG=
+# UNSAFE_TOOLS is not set
+CONFIG_CARDBUS=y
+CONFIG_PNP=n
+USE_PM=y
+CONF_SRC=1
+SYSV_INIT=n
+RC_DIR=/etc
Index: oldkernel/linux/pcmcia-cs-3.1.15/rules.mk
diff -u /dev/null linux/pcmcia-cs-3.1.15/rules.mk:1.1
--- /dev/null	Mon Jul 31 21:15:09 2000
+++ linux/pcmcia-cs-3.1.15/rules.mk	Fri Jul  7 16:18:18 2000
@@ -0,0 +1,20 @@
+# Global defaults
+
+COFLAGS = -kv
+YFLAGS = -d
+
+%.c %.h : %.y
+	$(YACC) $(YFLAGS) $<
+	mv y.tab.c $*.c
+	mv y.tab.h $*.h
+
+%.s : %.c
+	$(CC) $(CFLAGS) $(CPPFLAGS) -S $<
+
+# Stuff to automatically maintain dependency files
+
+%.o : %.c
+	$(CC) -MD $(CFLAGS) $(CPPFLAGS) -c $<
+	@mkdir -p .depfiles ; mv $*.d .depfiles
+
+-include $(SRCS:%.c=.depfiles/%.d)
Index: oldkernel/linux/pcmcia-cs-3.1.15/cardmgr/Makefile
diff -u /dev/null linux/pcmcia-cs-3.1.15/cardmgr/Makefile:1.1
--- /dev/null	Mon Jul 31 21:15:09 2000
+++ linux/pcmcia-cs-3.1.15/cardmgr/Makefile	Fri Jul  7 16:34:57 2000
@@ -0,0 +1,78 @@
+#
+# cardmgr/Makefile 1.81 2000/05/11 02:33:24 (David Hinds)
+#
+
+# Include site dependent options
+include ../config.mk
+
+CFLAGS = -O -Wall -Wstrict-prototypes -pipe
+CPPFLAGS += -I../modules
+
+CC += $(UFLAGS)
+
+SRCS  = cardmgr.c cardctl.c yacc_config.c lex_config.c probe.c
+TOOLS = cardmgr cardctl
+
+ifdef CONFIG_INET
+SRCS  += ifport.c ifuser.c
+TOOLS += ifport ifuser
+endif
+
+ifdef CONFIG_SCSI
+SRCS  += scsi_info.c
+TOOLS += scsi_info
+endif
+
+ifdef DO_IDE
+SRCS  += ide_info.c
+TOOLS += ide_info
+endif
+
+ifdef HAS_FORMS
+SRCS  += cardinfo.c
+CPPFLAGS += -I/usr/X11R6/include -I/usr/X11/include -I/usr/X11R6/include/X11
+EXTRA += cardinfo
+I_EXTRA += install-cardinfo
+endif
+
+ifdef CONFIG_ISA
+PROBE = probe
+ifdef PREFIX
+I_EXTRA += install-probe
+endif
+endif
+
+all:	$(SRCS) $(TOOLS) $(EXTRA) $(PROBE)
+
+clean:
+	rm -f core core.* *.o *.s *.a *~ .depend .depfiles/*.d
+	rm -f $(TOOLS) $(EXTRA) probe
+
+cardmgr: cardmgr.o yacc_config.o lex_config.o
+
+yacc_config.o lex_config.o: %.o: %.c
+	$(CC) -c -MD -O -pipe $(CPPFLAGS) $<
+	@mkdir -p .depfiles ; mv $*.d .depfiles
+
+parser: lex_config.o yacc_config.c
+	$(CC) -O $(CPPFLAGS) -DYYDEBUG=1 -o $@ yacc_config.c lex_config.o
+
+cardinfo: cardinfo.o
+	$(CC) $< -o $@ -L/usr/X11R6/lib -L/usr/X11/lib -lforms -lX11 -lm
+
+install-cardinfo: cardinfo
+	@mkdir -p $(PREFIX)/usr/X11R6/bin
+	cp -f cardinfo $(PREFIX)/usr/X11R6/bin
+	chmod u+s $(PREFIX)/usr/X11R6/bin/cardinfo
+
+install-probe:
+	@mkdir -p $(PREFIX)/sbin
+	cp -f probe $(PREFIX)/sbin
+
+install: $(TOOLS) $(I_EXTRA)
+	@mkdir -p $(PREFIX)/sbin
+	@rm -f $(PREFIX)/sbin/cardmgr
+	cp -f $(TOOLS) pcinitrd $(PREFIX)/sbin
+	chmod u+s $(PREFIX)/sbin/cardctl
+
+include ../rules.mk
Index: oldkernel/linux/pcmcia-cs-3.1.15/cardmgr/cardctl.c
diff -u /dev/null linux/pcmcia-cs-3.1.15/cardmgr/cardctl.c:1.1
--- /dev/null	Mon Jul 31 21:15:09 2000
+++ linux/pcmcia-cs-3.1.15/cardmgr/cardctl.c	Fri Jul  7 16:34:57 2000
@@ -0,0 +1,712 @@
+/*======================================================================
+
+    PCMCIA device control program
+
+    cardctl.c 1.53 2000/01/25 01:40:12
+
+    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@pcmcia.sourceforge.org>.  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__
+#include <pcmcia/u_compat.h>
+#endif
+
+#include <sys/types.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <ctype.h>
+#include <sys/time.h>
+#include <sys/ioctl.h>
+#include <sys/stat.h>
+#include <sys/wait.h>
+#include <sys/stat.h>
+
+#include <pcmcia/version.h>
+#include <pcmcia/config.h>
+#include <pcmcia/cs_types.h>
+#include <pcmcia/cs.h>
+#include <pcmcia/cistpl.h>
+#include <pcmcia/ds.h>
+
+/*====================================================================*/
+
+#ifdef ETC
+static char *configpath = ETC;
+#else
+static char *configpath = "/etc/pcmcia";
+#endif
+
+static char *scheme, *stabfile;
+
+/*====================================================================*/
+
+#ifdef __linux__
+
+static int major = 0;
+
+static int lookup_dev(char *name)
+{
+    FILE *f;
+    int n;
+    char s[32], t[32];
+    
+    f = fopen("/proc/devices", "r");
+    if (f == NULL)
+	return -errno;
+    while (fgets(s, 32, f) != NULL) {
+	if (sscanf(s, "%d %s", &n, t) == 2)
+	    if (strcmp(name, t) == 0)
+		break;
+    }
+    fclose(f);
+    if (strcmp(name, t) == 0)
+	return n;
+    else
+	return -ENODEV;
+} /* lookup_dev */
+
+#endif /* __linux__ */
+
+/*====================================================================*/
+
+static int open_sock(int sock)
+{
+#ifdef __linux__
+    int fd;
+    char *fn;
+    dev_t dev = (major<<8) + sock;
+    if ((fn = tmpnam(NULL)) == NULL)
+	return -1;
+    if (mknod(fn, (S_IFCHR|S_IREAD|S_IWRITE), dev) != 0)
+	return -1;
+    fd = open(fn, O_RDONLY);
+    unlink(fn);
+    return fd;
+#endif
+#ifdef __BEOS__
+    char fn[B_OS_NAME_LENGTH];
+    sprintf(fn, "/dev/pcmcia/sock%d", sock);
+    return open(fn, O_RDONLY);
+#endif
+} /* open_sock */
+
+/*====================================================================*/
+
+static void print_status(cs_status_t *status)
+{
+    char *v = "5";
+    if (status->Function == 0) {
+	printf("  ");
+	if (status->CardState & CS_EVENT_3VCARD)
+	    v = "3.3";
+	else if (status->CardState & CS_EVENT_XVCARD)
+	    v = "X.X";
+	if (status->CardState & CS_EVENT_CB_DETECT)
+	    printf("%sV CardBus card", v);
+	else if (status->CardState & CS_EVENT_CARD_DETECT)
+	    printf("%sV 16-bit PC Card", v);
+	else
+	    printf("no card");
+	if (status->CardState & CS_EVENT_PM_SUSPEND)
+	    printf(" [suspended]");
+	printf("\n");
+    }
+    if ((status->CardState & CS_EVENT_PM_SUSPEND) ||
+	!(status->CardState & CS_EVENT_CARD_DETECT))
+	return;
+    printf("  function %d: ", status->Function);
+    printf("%s", (status->CardState & CS_EVENT_READY_CHANGE)
+	   ? "[ready]" : "[busy]");
+    if (status->CardState & CS_EVENT_WRITE_PROTECT)
+	printf(", [wp]");
+    if (status->CardState & CS_EVENT_BATTERY_DEAD)
+	printf(", [bat dead]");
+    if (status->CardState & CS_EVENT_BATTERY_LOW)
+	printf(", [bat low]");
+    if (status->CardState & CS_EVENT_REQUEST_ATTENTION)
+	printf(", [req attn]");
+    printf("\n");
+} /* print_status */
+
+/*====================================================================*/
+
+static void print_config(config_info_t *config)
+{
+    if (config->Function == 0) {
+	printf("  Vcc %.1fV  Vpp1 %.1fV  Vpp2 %.1fV\n",
+	       config->Vcc/10.0, config->Vpp1/10.0, config->Vpp2/10.0);
+	if (!(config->Attributes & CONF_VALID_CLIENT))
+	    return;
+	printf("  interface type is ");
+	switch (config->IntType) {
+	case INT_MEMORY:
+	    printf("\"memory-only\"\n"); break;
+	case INT_MEMORY_AND_IO:
+	    printf("\"memory and I/O\"\n"); break;
+	case INT_CARDBUS:
+	    printf("\"cardbus\"\n"); break;
+	}
+	if (config->AssignedIRQ != 0) {
+	    printf("  irq %d", config->AssignedIRQ);
+	    switch (config->IRQAttributes & IRQ_TYPE) {
+	    case IRQ_TYPE_EXCLUSIVE:
+		printf(" [exclusive]"); break;
+	    case IRQ_TYPE_TIME:
+		printf(" [multiplexed]"); break;
+	    case IRQ_TYPE_DYNAMIC_SHARING:
+		printf(" [shared]"); break;
+	    }
+	    if (config->IRQAttributes & IRQ_PULSE_ALLOCATED)
+		printf(" [pulse]");
+	    else
+		printf(" [level]");
+	    if (!(config->Attributes & CONF_ENABLE_IRQ))
+		printf(" [disabled]");
+	    printf("\n");
+	}
+	if (config->Attributes & CONF_ENABLE_DMA)
+	    printf("  DMA mode is enabled\n");
+	if (config->Attributes & CONF_ENABLE_SPKR)
+	    printf("  Speaker output is enabled\n");
+    
+    }
+
+    if (!(config->Attributes & CONF_VALID_CLIENT))
+	return;
+    
+    printf("  function %d:\n", config->Function);
+
+    if (config->CardValues) {
+	printf("    config base %#06x\n", config->ConfigBase);
+	printf("    ");
+	if (config->CardValues & CV_OPTION_VALUE)
+	    printf("  option 0x%02x", config->Option);
+	if (config->CardValues & CV_STATUS_VALUE)
+	    printf(" status 0x%02x", config->Status);
+	if (config->CardValues & CV_PIN_REPLACEMENT)
+	    printf(" pin 0x%02x", config->Pin);
+	if (config->CardValues & CV_COPY_VALUE)
+	    printf(" copy 0x%02x", config->Copy);
+	if (config->CardValues & CV_EXT_STATUS)
+	    printf(" ext 0x%02x", config->ExtStatus);
+	printf("\n");
+    }
+
+    if (config->NumPorts1 > 0) {
+	printf("    io %#06x-%#06x", config->BasePort1,
+	       config->BasePort1 + config->NumPorts1 - 1);
+	if (config->IntType == INT_CARDBUS) {
+	    printf(" [32bit]\n");
+	} else {
+	    if (config->Attributes1 & IO_SHARED)
+		printf(" [shared]");
+	    if (config->Attributes1 & IO_FORCE_ALIAS_ACCESS)
+		printf(" [alias]");
+	    switch (config->Attributes1 & IO_DATA_PATH_WIDTH) {
+	    case IO_DATA_PATH_WIDTH_8:
+		printf(" [8bit]\n"); break;
+	    case IO_DATA_PATH_WIDTH_16:
+		printf(" [16bit]\n"); break;
+	    case IO_DATA_PATH_WIDTH_AUTO:
+		printf(" [auto]\n"); break;
+	    }
+	}
+    }
+    if (config->NumPorts2 > 0) {
+	printf("    io %#06x-%#06x", config->BasePort2,
+	       config->BasePort2 + config->NumPorts2 - 1);
+	if (config->Attributes2 & IO_SHARED)
+	    printf(" [shared]");
+	if (config->Attributes2 & IO_FORCE_ALIAS_ACCESS)
+	    printf(" [alias]");
+	switch (config->Attributes2 & IO_DATA_PATH_WIDTH) {
+	case IO_DATA_PATH_WIDTH_8:
+	    printf(" [8bit]\n"); break;
+	case IO_DATA_PATH_WIDTH_16:
+	    printf(" [16bit]\n"); break;
+	case IO_DATA_PATH_WIDTH_AUTO:
+	    printf(" [auto]\n"); break;
+	}
+    }
+} /* print_config */
+
+/*====================================================================*/
+
+static void print_windows(int fd)
+{
+    ds_ioctl_arg_t arg1, arg2;
+    int ret;
+    win_req_t *win = &arg1.win_info.window;
+    memreq_t *req = &arg2.win_info.map;
+    
+    ret = ioctl(fd, DS_GET_FIRST_WINDOW, &arg1);
+    while (ret == 0) {
+	arg2.win_info.handle = arg1.win_info.handle;
+	ioctl(fd, DS_GET_MEM_PAGE, &arg2);
+	printf("  memory 0x%04x-0x%04x @ 0x%08lx",
+	       req->CardOffset, req->CardOffset+win->Size-1,
+	       win->Base);
+	if (win->Attributes & WIN_MEMORY_TYPE_AM)
+	    printf(" [attr]");
+	if (!(win->Attributes & WIN_ENABLE))
+	    printf(" [disabled]");
+	if (win->Attributes & WIN_USE_WAIT)
+	    printf(" [wait]");
+	switch (win->Attributes & WIN_DATA_WIDTH) {
+	case WIN_DATA_WIDTH_8:
+	    printf(" [8bit]\n"); break;
+	case WIN_DATA_WIDTH_16:
+	    printf(" [16bit]\n"); break;
+	case WIN_DATA_WIDTH_32:
+	    printf(" [32bit]\n"); break;
+	}
+	ret = ioctl(fd, DS_GET_NEXT_WINDOW, &arg1);
+    }
+}
+
+/*====================================================================*/
+
+static int get_tuple(int fd, cisdata_t code, ds_ioctl_arg_t *arg)
+{
+    arg->tuple.DesiredTuple = code;
+    arg->tuple.Attributes = TUPLE_RETURN_COMMON;
+    arg->tuple.TupleOffset = 0;
+    if ((ioctl(fd, DS_GET_FIRST_TUPLE, arg) == 0) &&
+	(ioctl(fd, DS_GET_TUPLE_DATA, arg) == 0) &&
+	(ioctl(fd, DS_PARSE_TUPLE, arg) == 0))
+	return 0;
+    else
+	return -1;
+}
+
+static void print_ident(int fd)
+{
+    ds_ioctl_arg_t arg;
+    cistpl_vers_1_t *vers = &arg.tuple_parse.parse.version_1;
+    cistpl_manfid_t *manfid = &arg.tuple_parse.parse.manfid;
+    cistpl_funcid_t *funcid = &arg.tuple_parse.parse.funcid;
+    int i;
+    static char *fn[] = {
+	"multifunction", "memory", "serial", "parallel",
+	"fixed disk", "video", "network", "AIMS", "SCSI"
+    };
+    
+    if (get_tuple(fd, CISTPL_VERS_1, &arg) == 0) {
+	printf("  product info: ");
+	for (i = 0; i < vers->ns; i++)
+	    printf("%s\"%s\"", (i>0) ? ", " : "",
+		   vers->str+vers->ofs[i]);
+	printf("\n");
+    } else {
+	printf("  no product info available\n");
+    }
+    if (get_tuple(fd, CISTPL_MANFID, &arg) == 0)
+	printf("  manfid: 0x%04x, 0x%04x\n",
+	       manfid->manf, manfid->card);
+    if (get_tuple(fd, CISTPL_FUNCID, &arg) == 0)
+	printf("  function: %d (%s)\n", funcid->func,
+	       fn[funcid->func]);
+}
+
+/*====================================================================*/
+
+typedef enum cmd_t {
+    C_STATUS, C_CONFIG, C_IDENT, C_SUSPEND,
+    C_RESUME, C_RESET, C_EJECT, C_INSERT
+} cmd_t;
+
+static char *cmdname[] = {
+    "status", "config", "ident", "suspend",
+    "resume", "reset", "eject", "insert"
+};
+
+#define NCMD (sizeof(cmdname)/sizeof(char *))
+
+static int do_cmd(int fd, int cmd)
+{
+    int i, ret;
+    cs_status_t status;
+    config_info_t config;
+
+    ret = 0;
+    switch (cmd) {
+	
+    case C_STATUS:
+	for (i = 0; i < 4; i++) {
+	    status.Function = i;
+	    if (ioctl(fd, DS_GET_STATUS, &status) == 0)
+		print_status(&status);
+	    else {
+		if (i == 0) {
+		    if (errno == ENODEV)
+			printf("  no card\n");
+		    else
+			perror("ioctl()");
+		}
+		break;
+	    }
+	}
+	break;
+	
+    case C_CONFIG:
+	for (i = 0; i < 4; i++) {
+	    config.Function = i;
+	    if (ioctl(fd, DS_GET_CONFIGURATION_INFO, &config) == 0) 
+		print_config(&config);
+	    else {
+		if (i == 0) printf("  not configured\n");
+		break;
+	    }
+	    print_windows(fd);
+	}
+	break;
+
+    case C_IDENT:
+	print_ident(fd);
+	break;
+	
+    case C_SUSPEND:
+	ret = ioctl(fd, DS_SUSPEND_CARD);
+	break;
+	
+    case C_RESUME:
+	ret = ioctl(fd, DS_RESUME_CARD);
+	break;
+
+    case C_RESET:
+	ret = ioctl(fd, DS_RESET_CARD);
+	break;
+
+    case C_EJECT:
+	ret = ioctl(fd, DS_EJECT_CARD);
+	break;
+	
+    case C_INSERT:
+	ret = ioctl(fd, DS_INSERT_CARD);
+	break;
+    }
+    return ret;
+}
+
+/*======================================================================
+
+    A utility function to scan /var/run/stab and apply a specified action
+    to each device, in turn.  If any command returns a non-zero exit
+    code, execute() returns -1.
+    
+======================================================================*/
+
+typedef struct stab_t {
+    int		status;
+    char	class[33];
+    char	dev[33];
+} stab_t;
+
+static stab_t stab[256];
+static int nstab;
+
+static int fetch_stab(void)
+{
+    char s[133];
+    FILE *f;
+
+    f = fopen(stabfile, "r");
+    if (f == NULL)
+	return -1;
+    for (nstab = 0; fgets(s, 132, f); ) {
+	if (s[0] != 'S') {
+	    sscanf(s, "%*d\t%s\t%*s\t%*d\t%s",
+		   stab[nstab].class, stab[nstab].dev);
+	    stab[nstab].status = 0;
+	    nstab++;
+	}
+    }
+    fclose(f);
+    return 0;
+}
+
+static int execute(stab_t *s, char *action, char *scheme)
+{
+    int ret;
+    char cmd[133];
+    
+    if (scheme)
+	sprintf(cmd, "./%s %s %s %s", s->class, action, s->dev, scheme);
+    else
+	sprintf(cmd, "./%s %s %s", s->class, action, s->dev);
+    ret = system(cmd);
+    if (!WIFEXITED(ret) || WEXITSTATUS(ret))
+	return -1;
+    return 0;
+}
+
+static int stop_scheme(char *new)
+{
+    int i;
+    
+    fprintf(stderr, "checking:");
+    for (i = 0; i < nstab; i++) {
+	fprintf(stderr, " %s", stab[i].dev);
+	stab[i].status = execute(stab+i, "cksum", new);
+	if (stab[i].status &&
+	    (execute(stab+i, "check", NULL) != 0)) break;
+    }
+    fprintf(stderr, "\n");
+    if (i < nstab) {
+	fprintf(stderr, "Device '%s' busy: scheme unchanged.\n",
+		stab[i].dev);
+	return -1;
+    }
+    for (i = 0; i < nstab; i++)
+	if (stab[i].status) execute(stab+i, "stop", NULL);
+    return 0;
+}
+
+static int start_scheme(void)
+{
+    int i, j = 0;
+    
+    for (i = 0; i < nstab; i++)
+	if (stab[i].status) j |= execute(stab+i, "start", NULL);
+    return j;
+}
+
+/*======================================================================
+
+    do_scheme() is in charge of checking and updating the current 
+    PCMCIA configuration scheme.  The current scheme is kept in a
+    file, /var/run/pcmcia-scheme.  When updating the scheme, we first
+    stop all PCMCIA devices, then update the scheme, then restart.
+    
+======================================================================*/
+
+static int do_scheme(char *new)
+{
+    FILE *f;
+    char old[33];
+    int i;
+    
+    f = fopen(scheme, "r");
+    if (f && fgets(old, 32, f))
+	old[strlen(old)-1] = '\0';
+    else
+	old[0] = '\0';
+    if (f) fclose(f);
+    
+    if (new) {
+
+#ifndef UNSAFE_TOOLS
+	if (getuid() != 0) {
+	    fprintf(stderr, "Only root can select a new scheme.\n");
+	    return -1;
+	}
+#else
+	setuid(geteuid());
+#endif
+	
+	/* Sanity checks... */
+	for (i = 0; i < strlen(new); i++)
+	    if (!isalnum(new[i])) break;
+	if ((i != strlen(new)) || (strlen(new) < 1) ||
+	    (strlen(new) > 32)) {
+	    fprintf(stderr, "Bad scheme name.\n");
+	    return -1;
+	}
+	if (strcmp(old, new) == 0) {
+	    fprintf(stderr, "Scheme unchanged.\n");
+	    return 0;
+	}
+
+	if (chdir(configpath) != 0) {
+	    fprintf(stderr, "Could not change to %s.\n", configpath);
+	    return -1;
+	}
+	
+	/* Shut down devices in old scheme */
+	if ((fetch_stab() == 0) && (stop_scheme(new) != 0))
+	    return -1;
+
+	/* Update scheme state */
+	if (old[0])
+	    printf("Changing scheme from '%s' to '%s'...\n", old, new);
+	else
+	    printf("Changing scheme to '%s'...\n", new);
+	
+	umask(022);
+	f = fopen(scheme, "w");
+	if (f) {
+	    fprintf(f, "%s\n", new);
+	    fclose(f);
+	} else
+	    perror("Could not set scheme.");
+
+	/* Start up devices in new scheme */
+	if (start_scheme() != 0)
+	    fprintf(stderr, "Some devices did not start cleanly.\n");
+	
+    } else {
+	if (old[0])
+	    printf("Current scheme: '%s'.\n", old);
+	else
+	    printf("Current scheme: 'default'.\n");
+    }
+    return 0;
+}
+
+/*====================================================================*/
+
+void usage(char *name)
+{
+    int i;
+    fprintf(stderr, "usage: %s command [socket #]\n", name);
+    fprintf(stderr, "    or %s [-c configpath] [-f scheme]"
+	    " [-s stab] scheme [name]\n", name);
+    fprintf(stderr, "    commands:");
+    for (i = 0; i < NCMD; i++)
+	fprintf(stderr, " %s", cmdname[i]);
+    fprintf(stderr, "\n");
+    exit(EXIT_FAILURE);
+}
+
+/*====================================================================*/
+
+#define MAX_SOCKS 8
+
+int main(int argc, char *argv[])
+{
+    int cmd, fd[MAX_SOCKS], ns, ret, i;
+    int optch, errflg = 0;
+    char *s, *opts = (getuid() == 0) ? "Vc:f:s:" : "V";
+
+    if (access("/var/state/pcmcia", R_OK) == 0) {
+	scheme = "/var/state/pcmcia/scheme";
+	stabfile = "/var/state/pcmcia/stab";
+    } else if (access("/var/lib/pcmcia", R_OK) == 0) {
+	scheme = "/var/lib/pcmcia/scheme";
+	stabfile = "/var/lib/pcmcia/stab";
+    } else {
+	scheme = "/var/run/pcmcia-scheme";
+	stabfile = "/var/run/stab";
+    }
+    
+    while ((optch = getopt(argc, argv, opts)) != -1) {
+	switch (optch) {
+	case 'V':
+	    fprintf(stderr, "cardctl version " CS_RELEASE "\n");
+	    return 0;
+	    break;
+	case 'c':
+	    configpath = strdup(optarg); break;
+	case 'f':
+	    scheme = strdup(optarg); break;
+	case 's':
+	    stabfile = strdup(optarg); break;
+	default:
+	    errflg = 1; break;
+	}
+    }
+    
+    if (errflg || (argc == optind) || (argc > optind+2))
+	usage(argv[0]);
+
+    if (geteuid() != 0) {
+        fprintf(stderr, "cardctl must be setuid root\n");
+	exit(EXIT_FAILURE);
+    }
+
+#ifdef __linux__
+    major = lookup_dev("pcmcia");
+    if (major < 0) {
+	if (major == -ENODEV)
+	    fprintf(stderr, "no pcmcia driver in /proc/devices\n");
+	else
+	    perror("could not open /proc/devices");
+	exit(EXIT_FAILURE);
+    }
+#endif
+
+    if (strcmp(argv[optind], "scheme") == 0) {
+#ifndef UNSAFE_TOOLS
+	setuid(getuid());
+#endif
+	if (do_scheme((argc == optind+1) ? NULL : argv[optind+1]) == 0)
+	    exit(EXIT_SUCCESS);
+	else
+	    exit(EXIT_FAILURE);
+    }
+    
+    for (cmd = 0; cmd < NCMD; cmd++)
+	if (strcmp(argv[optind], cmdname[cmd]) == 0) break;
+    if (cmd == NCMD)
+	usage(argv[0]);
+
+    ret = 0;
+    if (argc == optind+2) {
+	ns = strtol(argv[optind+1], &s, 0);
+	if ((*argv[optind+1] == '\0') || (*s != '\0'))
+	    usage(argv[0]);
+	fd[0] = open_sock(ns);
+	if (fd[0] < 0) {
+	    perror("open_sock()");
+	    exit(EXIT_FAILURE);
+	}
+#ifndef UNSAFE_TOOLS
+	setuid(getuid());
+#endif
+	ret = do_cmd(fd[0], cmd);
+	if (ret != 0)
+	    perror("ioctl()");
+    } else {
+	for (ns = 0; ns < MAX_SOCKS; ns++) {
+	    fd[ns] = open_sock(ns);
+	    if (fd[ns] < 0) break;
+	}
+#ifndef UNSAFE_TOOLS
+	setuid(getuid());
+#endif
+	if (ns == 0) {
+	    perror("open_sock()");
+	    exit(EXIT_FAILURE);
+	}
+	for (ns = 0; (ns < MAX_SOCKS) && (fd[ns] >= 0); ns++) {
+	    if (cmd <= C_IDENT)
+		printf("Socket %d:\n", ns);
+	    i = do_cmd(fd[ns], cmd);
+	    if ((i != 0) && (errno != ENODEV)) {
+		perror("ioctl()");
+		ret = i;
+	    }
+	}
+    }
+    if (ret != 0)
+	exit(EXIT_FAILURE);
+    return 0;
+}
Index: oldkernel/linux/pcmcia-cs-3.1.15/cardmgr/cardinfo.c
diff -u /dev/null linux/pcmcia-cs-3.1.15/cardmgr/cardinfo.c:1.1
--- /dev/null	Mon Jul 31 21:15:09 2000
+++ linux/pcmcia-cs-3.1.15/cardmgr/cardinfo.c	Fri Jul  7 16:34:57 2000
@@ -0,0 +1,555 @@
+/*======================================================================
+
+    X Windows PCMCIA device control program
+
+    cardinfo.c 1.30 1999/10/26 18:55:10
+
+    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@pcmcia.sourceforge.org>.  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 <sys/types.h>
+#include <stdio.h>
+#include <stdarg.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <signal.h>
+#include <sys/time.h>
+#include <sys/ioctl.h>
+#include <sys/stat.h>
+#include <sys/file.h>
+
+#include <forms.h>
+
+#undef Status
+#include <pcmcia/config.h>
+#include <pcmcia/version.h>
+#include <pcmcia/cs_types.h>
+#include <pcmcia/cs.h>
+#include <pcmcia/cistpl.h>
+#include <pcmcia/ds.h>
+
+/*====================================================================*/
+
+typedef enum s_state {
+    S_EMPTY, S_PRESENT, S_READY, S_BUSY, S_SUSPEND
+} s_state;
+
+typedef struct field_t {
+    char *str;
+    FL_OBJECT *obj;
+} field_t;
+
+typedef struct flag_t {
+    int val;
+    FL_OBJECT *obj;
+} flag_t;
+
+typedef struct socket_info_t {
+    int fd, o_state;
+    FL_OBJECT *menu;
+    field_t card, state, dev, io, irq;
+    flag_t cd, vcc, vpp, wp;
+} socket_info_t;
+
+#define MAX_SOCK 8
+
+static int ns;
+static socket_info_t st[MAX_SOCK];
+
+static FL_OBJECT *event_log;
+
+static char *pidfile = "/var/run/cardmgr.pid";
+static char *stabfile;
+
+/*====================================================================*/
+
+typedef struct event_tag_t {
+    event_t event;
+    char *name;
+} event_tag_t;
+
+static event_tag_t event_tag[] = {
+    { CS_EVENT_CARD_INSERTION, "card insertion" },
+    { CS_EVENT_CARD_REMOVAL, "card removal" },
+    { CS_EVENT_RESET_PHYSICAL, "prepare for reset" },
+    { CS_EVENT_CARD_RESET, "card reset successful" },
+    { CS_EVENT_RESET_COMPLETE, "reset request complete" },
+    { CS_EVENT_EJECTION_REQUEST, "user eject request" },
+    { CS_EVENT_INSERTION_REQUEST, "user insert request" },
+    { CS_EVENT_PM_SUSPEND, "suspend card" },
+    { CS_EVENT_PM_RESUME, "resume card" },
+    { CS_EVENT_REQUEST_ATTENTION, "request attention" },
+};
+#define NTAGS (sizeof(event_tag)/sizeof(event_tag_t))
+
+/*====================================================================*/
+
+static int lookup_dev(char *name)
+{
+    FILE *f;
+    int n;
+    char s[32], t[32];
+    
+    f = fopen("/proc/devices", "r");
+    if (f == NULL)
+	return -errno;
+    while (fgets(s, 32, f) != NULL) {
+	if (sscanf(s, "%d %s", &n, t) == 2)
+	    if (strcmp(name, t) == 0)
+		break;
+    }
+    fclose(f);
+    if (strcmp(name, t) == 0)
+	return n;
+    else
+	return -ENODEV;
+} /* lookup_dev */
+
+/*====================================================================*/
+
+static int open_dev(dev_t dev)
+{
+    char *fn;
+    int fd;
+    
+    if ((fn = tmpnam(NULL)) == NULL)
+	return -1;
+    if (mknod(fn, (S_IFCHR|S_IREAD), dev) != 0)
+	return -1;
+    if ((fd = open(fn, O_RDONLY)) < 0) {
+	unlink(fn);
+	return -1;
+    }
+    if (unlink(fn) != 0) {
+	close(fd);
+	return -1;
+    }
+    return fd;
+} /* open_dev */
+
+/*====================================================================*/
+
+static void do_alert(char *fmt, ...)
+{
+    char msg[132];
+    va_list args;
+    va_start(args, fmt);
+    vsprintf(msg, fmt, args);
+    fl_show_alert(msg, "", "", 0);
+    va_end(args);
+} /* do_alert */
+
+/*====================================================================*/
+
+static void do_menu(FL_OBJECT *obj, long i)
+{
+    int ret = 0;
+
+    switch (fl_get_menu(obj)) {
+    case 1:
+	/* do_opts(); */ break;
+    case 2:
+	ret = ioctl(st[i].fd, DS_RESET_CARD); break;
+    case 3:
+	ret = ioctl(st[i].fd, DS_SUSPEND_CARD); break;
+    case 4:
+	ret = ioctl(st[i].fd, DS_RESUME_CARD); break;
+    case 5:
+	ret = ioctl(st[i].fd, DS_EJECT_CARD); break;
+    case 6:
+	ret = ioctl(st[i].fd, DS_INSERT_CARD); break;
+    }
+    if (ret != 0)
+	do_alert("ioctl() operation failed: %s", strerror(errno));
+} /* do_menu */
+
+/*====================================================================*/
+
+static void do_quit(FL_OBJECT *obj, long data)
+{
+    exit(0);
+}
+
+/*====================================================================*/
+
+static void do_reset(FL_OBJECT *obj, long data)
+{
+    FILE *f;
+    pid_t pid;
+    
+    f = fopen(pidfile, "r");
+    if (f == NULL) {
+	do_alert("Could not open pidfile: %s", strerror(errno));
+	return;
+    }
+    if (fscanf(f, "%d", &pid) != 1) {
+	do_alert("Could not read pidfile");
+	return;
+    }
+    if (kill(pid, SIGHUP) != 0)
+	do_alert("Could not signal cardmgr: %s", strerror(errno));
+}
+
+/*====================================================================*/
+
+void new_field(field_t *field, int x, int y, int w1, int w2, char *label)
+{
+    FL_OBJECT *obj;
+    if (w1 > 0) {
+	obj = fl_add_text(FL_NORMAL_TEXT, x, y, w1, 20, label);
+	fl_set_object_boxtype(obj, FL_NO_BOX);
+    }
+    field->str = strdup("");
+    field->obj = fl_add_box(FL_BORDER_BOX, x+w1, y, w2, 20, "");
+    fl_set_object_color(field->obj, FL_MCOL, 0);
+}
+
+void update_field(field_t *field, char *new)
+{
+    if (strcmp(field->str, new) != 0) {
+	free(field->str);
+	field->str = strdup(new);
+	fl_set_object_label(field->obj, new);
+    }
+}
+
+void new_flag(flag_t *flag, int x, int y, char *label)
+{
+    flag->obj = fl_add_box(FL_ROUNDED_BOX, x, y, 30, 20, label);
+    fl_set_object_color(flag->obj, FL_MCOL, 0);
+    fl_hide_object(flag->obj);
+    flag->val = 0;
+}
+
+void update_flag(flag_t *flag, int new)
+{
+    if (flag->val != new) {
+	flag->val = new;
+	if (new)
+	    fl_show_object(flag->obj);
+	else
+	    fl_hide_object(flag->obj);
+    }
+}
+
+/*====================================================================*/
+
+static void do_update(FL_OBJECT *obj, long data)
+{
+    FILE *f;
+    int i, j, event, ret, state;
+    cs_status_t status;
+    config_info_t cfg;
+    char s[80], *t, d[80], io[20], irq[4];
+    ioaddr_t stop;
+    struct stat buf;
+    static time_t last = 0;
+    time_t now;
+    struct tm *tm;
+    fd_set fds;
+    struct timeval timeout;
+
+    fl_set_timer(obj, 0.3);
+
+    /* Poll for events */
+    FD_ZERO(&fds);
+    for (i = 0; i < ns; i++)
+	FD_SET(st[i].fd, &fds);
+    timeout.tv_sec = timeout.tv_usec = 0;
+    ret = select(MAX_SOCK+4, &fds, NULL, NULL, &timeout);
+    now = time(NULL);
+    tm = localtime(&now);
+    if (ret > 0) {
+	for (i = 0; i < ns; i++) {
+	    if (!FD_ISSET(st[i].fd, &fds))
+		continue;
+	    ret = read(st[i].fd, &event, 4);
+	    if (ret != 4) continue;
+	    for (j = 0; j < NTAGS; j++)
+		if (event_tag[j].event == event) break;
+	    if (j == NTAGS)
+		sprintf(s, "%2d:%02d:%02d  socket %d: unknown event 0x%x",
+			tm->tm_hour, tm->tm_min, tm->tm_sec, i, event);
+	    else
+		sprintf(s, "%2d:%02d:%02d  socket %d: %s", tm->tm_hour,
+			tm->tm_min, tm->tm_sec, i, event_tag[j].name);
+	    fl_addto_browser(event_log, s);
+	}
+    }
+
+    if ((stat(stabfile, &buf) == 0) && (buf.st_mtime >= last)) {
+	f = fopen(stabfile, "r");
+	if (f == NULL)
+	    return;
+	
+	if (flock(fileno(f), LOCK_SH) != 0) {
+	    do_alert("flock(stabfile) failed: %s", strerror(errno));
+	    return;
+	}
+	last = now;
+	fgetc(f);
+	for (i = 0; i < ns; i++) {
+	    if (!fgets(s, 80, f)) break;
+	    s[strlen(s)-1] = '\0';
+	    update_field(&st[i].card, s+9);
+	    *d = '\0';
+	    for (;;) {
+		int c = fgetc(f);
+		if ((c == EOF) || (c == 'S')) {
+		    update_field(&st[i].dev, d);
+		    break;
+		} else {
+		    fgets(s, 80, f);
+		    for (t = s, j = 0; j < 4; j++)
+			t = strchr(t, '\t')+1;
+		    t[strcspn(t, "\t\n")] = '\0';
+		    if (*d == '\0')
+			strcpy(d, t);
+		    else {
+			strcat(d, ", ");
+			strcat(d, t);
+		    }
+		}
+	    }
+	}
+	flock(fileno(f), LOCK_UN);
+	fclose(f);
+    }
+
+    for (i = 0; i < ns; i++) {
+	
+	state = S_EMPTY;
+	status.Function = 0;
+	ioctl(st[i].fd, DS_GET_STATUS, &status);
+	if (strcmp(st[i].card.str, "empty") == 0) {
+	    if (status.CardState & CS_EVENT_CARD_DETECT)
+		state = S_PRESENT;
+	} else {
+	    if (status.CardState & CS_EVENT_PM_SUSPEND)
+		state = S_SUSPEND;
+	    else {
+		if (status.CardState & CS_EVENT_READY_CHANGE)
+		    state = S_READY;
+		else
+		    state = S_BUSY;
+	    }
+	}
+	
+	if (state != st[i].o_state) {
+	    st[i].o_state = state;
+	    for (j = 1; j <= 6; j++)
+		fl_set_menu_item_mode(st[i].menu, j, FL_PUP_GRAY);
+	    switch (state) {
+	    case S_EMPTY:
+		update_field(&st[i].state, "");
+		break;
+	    case S_PRESENT:
+		fl_set_menu_item_mode(st[i].menu, 6, FL_PUP_NONE);
+		update_field(&st[i].state, "");
+		break;
+	    case S_READY:
+		fl_set_menu_item_mode(st[i].menu, 1, FL_PUP_NONE);
+		fl_set_menu_item_mode(st[i].menu, 2, FL_PUP_NONE);
+		fl_set_menu_item_mode(st[i].menu, 3, FL_PUP_NONE);
+		fl_set_menu_item_mode(st[i].menu, 5, FL_PUP_NONE);
+		update_field(&st[i].state, "ready");
+		break;
+	    case S_BUSY:
+		fl_set_menu_item_mode(st[i].menu, 1, FL_PUP_NONE);
+		fl_set_menu_item_mode(st[i].menu, 2, FL_PUP_NONE);
+		fl_set_menu_item_mode(st[i].menu, 3, FL_PUP_NONE);
+		fl_set_menu_item_mode(st[i].menu, 5, FL_PUP_NONE);
+		update_field(&st[i].state, "not ready");
+		break;
+	    case S_SUSPEND:
+		fl_set_menu_item_mode(st[i].menu, 1, FL_PUP_NONE);
+		fl_set_menu_item_mode(st[i].menu, 4, FL_PUP_NONE);
+		fl_set_menu_item_mode(st[i].menu, 5, FL_PUP_NONE);
+		update_field(&st[i].state, "suspended");
+		break;
+	    }
+	}
+
+	strcpy(io, "");
+	strcpy(irq, "");
+	memset(&cfg, 0, sizeof(cfg));
+	ret = ioctl(st[i].fd, DS_GET_CONFIGURATION_INFO, &cfg);
+	if (cfg.Attributes & CONF_VALID_CLIENT) {
+	    if (cfg.AssignedIRQ != 0)
+		sprintf(irq, "%d", cfg.AssignedIRQ);
+	    if (cfg.NumPorts1 > 0) {
+		stop = cfg.BasePort1+cfg.NumPorts1;
+		if (cfg.NumPorts2 > 0) {
+		    if (stop == cfg.BasePort2)
+			sprintf(io, "%#x-%#x", cfg.BasePort1,
+				stop+cfg.NumPorts2-1);
+		    else
+			sprintf(io, "%#x-%#x, %#x-%#x", cfg.BasePort1, stop-1,
+				cfg.BasePort2, cfg.BasePort2+cfg.NumPorts2-1);
+		} else
+		    sprintf(io, "%#x-%#x", cfg.BasePort1, stop-1);
+	    }
+	}
+	update_field(&st[i].irq, irq);
+	update_field(&st[i].io, io);
+
+	update_flag(&st[i].cd, status.CardState & CS_EVENT_CARD_DETECT);
+	update_flag(&st[i].vcc, cfg.Vcc > 0);
+	update_flag(&st[i].vpp, cfg.Vpp1 > 0);
+	update_flag(&st[i].wp, status.CardState & CS_EVENT_WRITE_PROTECT);
+    }
+}
+
+/*====================================================================*/
+
+int main(int argc, char *argv[])
+{
+    int i, ret, y, major;
+    servinfo_t serv;
+    char name[12];
+    FL_FORM *form;
+    FL_OBJECT *obj;
+
+    if (geteuid() != 0) {
+	fprintf(stderr, "cardinfo must be setuid root\n");
+	exit(EXIT_FAILURE);
+    }
+
+    if (access("/var/state/pcmcia", R_OK) == 0) {
+	stabfile = "/var/state/pcmcia/stab";
+    } else if (access("/var/lib/pcmcia", R_OK) == 0) {
+	stabfile = "/var/lib/pcmcia/stab";
+    } else {
+	stabfile = "/var/run/stab";
+    }
+    
+    major = lookup_dev("pcmcia");
+    if (major < 0) {
+	if (major == -ENODEV)
+	    fprintf(stderr, "no pcmcia driver in /proc/devices\n");
+	else
+	    perror("could not open /proc/devices");
+	exit(EXIT_FAILURE);
+    }
+    
+    for (ns = 0; ns < MAX_SOCK; ns++) {
+	st[ns].fd = open_dev((major<<8)+ns);
+	if (st[ns].fd < 0) break;
+    }
+    if (ns == 0) {
+	fprintf(stderr, "no sockets found\n");
+	exit(EXIT_FAILURE);
+    }
+
+    if (ioctl(st[0].fd, DS_GET_CARD_SERVICES_INFO, &serv) == 0) {
+	if (serv.Revision != CS_RELEASE_CODE)
+	    fprintf(stderr, "Card Services release does not match!\n");
+    } else {
+	fprintf(stderr, "could not get CS revision info!\n");
+	exit(EXIT_FAILURE);
+    }
+    
+    /* Switch back to real user privileges, to be safe */
+#ifndef UNSAFE_TOOLS
+    setuid(getuid());
+#endif
+
+    if ((ret = fork()) > 0) exit(0);
+    if (ret == -1)
+	perror("forking");
+    if (setsid() < 0)
+	perror("detaching from tty");
+
+#if (FL_REVISION >= 80)
+    fl_flip_yorigin();
+    fl_initialize(&argc, argv, "cardinfo", 0, 0);
+#else
+    fl_initialize(argv[0], "cardinfo", 0, 0, &argc, argv);
+#endif
+    
+    form = fl_bgn_form(FL_BORDER_BOX, 400, ns*100+70);
+    
+    for (i = 0; i < ns; i++) {
+	y = 100*(ns-i)+45;
+	sprintf(name, "Socket %d", i);
+	st[i].menu = obj =
+	    fl_add_menu(FL_PULLDOWN_MENU, 10, y, 90, 20, name);
+	fl_set_object_boxtype(obj, FL_UP_BOX);
+	fl_set_object_callback(obj, do_menu, i);
+	fl_show_menu_symbol(obj, 1);
+	fl_set_menu(obj, "opts...|reset|suspend|resume|eject|insert");
+	new_field(&st[i].card, 110, y, 0, 280, "");
+
+	y -= 25;
+	new_field(&st[i].state, 110, y, 40, 80, "state:");
+	new_flag(&st[i].cd, 240, y, "CD");
+	new_flag(&st[i].vcc, 280, y, "Vcc");
+	new_flag(&st[i].vpp, 320, y, "Vpp");
+	new_flag(&st[i].wp, 360, y, "WP");
+	
+	y -= 25;
+	new_field(&st[i].dev, 110, y, 60, 160, "device(s):");
+
+	y -= 25;
+	new_field(&st[i].io, 110, y, 50, 150, "IO ports:");
+	new_field(&st[i].irq, 310, y, 60, 20, "interrupt:");
+	
+    }
+
+    event_log = fl_add_browser(FL_NORMAL_BROWSER, 10, 5, 270, 60, "");
+#if (FL_REVISION < 88)
+    fl_set_browser_leftslider(event_log, 1);
+#endif
+    fl_set_browser_fontsize(event_log, FL_SMALL_SIZE);
+    
+    obj = fl_add_button(FL_NORMAL_BUTTON, 300, 35, 90, 25, "reset");
+    fl_set_object_callback(obj, do_reset, 0);
+    obj = fl_add_button(FL_NORMAL_BUTTON, 300, 5, 90, 25, "quit");
+    fl_set_object_callback(obj, do_quit, 0);
+
+    obj = fl_add_timer(FL_HIDDEN_TIMER, 0, 0, 1, 2, "");
+    fl_set_object_callback(obj, do_update, 0);
+    
+    fl_end_form();
+
+    fl_show_form(form, FL_PLACE_SIZE, FL_FULLBORDER, "cardinfo");
+
+    fl_set_timer(obj, 0.2);
+
+    do {
+	
+	obj = fl_do_forms();
+
+    } while (1);
+    
+    fl_hide_form(form);
+    exit(EXIT_SUCCESS);
+    return 0;
+}
Index: oldkernel/linux/pcmcia-cs-3.1.15/cardmgr/cardmgr.c
diff -u /dev/null linux/pcmcia-cs-3.1.15/cardmgr/cardmgr.c:1.1
--- /dev/null	Mon Jul 31 21:15:09 2000
+++ linux/pcmcia-cs-3.1.15/cardmgr/cardmgr.c	Fri Jul  7 16:34:57 2000
@@ -0,0 +1,1487 @@
+/*======================================================================
+
+    PCMCIA Card Manager daemon
+
+    cardmgr.c 1.135 2000/05/16 22:44: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@pcmcia.sourceforge.org>.  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__
+#include <pcmcia/u_compat.h>
+#endif
+
+#include <sys/types.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <syslog.h>
+#include <getopt.h>
+#include <signal.h>
+#include <sys/time.h>
+#include <sys/ioctl.h>
+#include <sys/wait.h>
+#include <sys/stat.h>
+#include <sys/utsname.h>
+#include <sys/file.h>
+
+#include <pcmcia/version.h>
+#include <pcmcia/config.h>
+#include <pcmcia/cs_types.h>
+#include <pcmcia/cs.h>
+#include <pcmcia/cistpl.h>
+#include <pcmcia/ds.h>
+
+#include "cardmgr.h"
+
+/*====================================================================*/
+
+typedef struct socket_info_t {
+    int			fd;
+    int			state;
+    card_info_t		*card;
+    bind_info_t		*bind[MAX_BINDINGS];
+    mtd_ident_t		*mtd[2*CISTPL_MAX_DEVICES];
+} socket_info_t;
+
+#define SOCKET_PRESENT	0x01
+#define SOCKET_READY	0x02
+#define SOCKET_BOUND	0x04
+
+/* Linked list of resource adjustments */
+struct adjust_list_t *root_adjust = NULL;
+
+/* Linked list of device definitions */
+struct device_info_t *root_device = NULL;
+
+/* Special pointer to "anonymous" card definition */
+struct card_info_t *blank_card = NULL;
+
+/* Linked list of card definitions */
+struct card_info_t *root_card = NULL;
+
+/* Linked list of function definitions */
+struct card_info_t *root_func = NULL;
+
+/* Linked list of MTD definitions */
+struct mtd_ident_t *root_mtd = NULL;
+
+/* Default MTD */
+struct mtd_ident_t *default_mtd = NULL;
+
+static int sockets;
+static struct socket_info_t socket[MAX_SOCKS];
+
+/* Default path for config file, device scripts */
+#ifdef ETC
+static char *configpath = ETC;
+#else
+static char *configpath = "/etc/pcmcia";
+#endif
+
+/* Default path for pid file */
+static char *pidfile = "/var/run/cardmgr.pid";
+
+#ifdef __linux__
+/* Default path for finding modules */
+static char *modpath = NULL;
+#endif
+
+/* Default path for socket info table */
+static char *stabfile;
+
+/* If set, don't generate beeps when cards are inserted */
+static int be_quiet = 0;
+
+/* If set, use modprobe instead of insmod */
+static int do_modprobe = 0;
+
+/* If set, configure already inserted cards, then exit */
+static int one_pass = 0;
+
+/* Extra message logging? */
+static int verbose = 0;
+
+/*====================================================================*/
+
+#ifdef __linux__
+
+static int major = 0;
+
+static int lookup_dev(char *name)
+{
+    FILE *f;
+    int n;
+    char s[32], t[32];
+    
+    f = fopen("/proc/devices", "r");
+    if (f == NULL)
+	return -errno;
+    while (fgets(s, 32, f) != NULL) {
+	if (sscanf(s, "%d %s", &n, t) == 2)
+	    if (strcmp(name, t) == 0)
+		break;
+    }
+    fclose(f);
+    if (strcmp(name, t) == 0)
+	return n;
+    else
+	return -ENODEV;
+}
+
+int open_dev(dev_t dev, int mode)
+{
+    char *fn;
+    int fd;
+    if ((fn = tmpnam(NULL)) == NULL)
+	return -1;
+    if (mknod(fn, mode, dev) != 0)
+	return -1;
+    fd = open(fn, (mode&S_IWRITE)?O_RDWR:O_RDONLY);
+    if (fd < 0)
+	fd = open(fn, O_NONBLOCK|((mode&S_IWRITE)?O_RDWR:O_RDONLY));
+    unlink(fn);
+    return fd;
+}
+
+#endif /* __linux__ */
+
+int open_sock(int sock, int mode)
+{
+#ifdef __linux__
+    dev_t dev = (major<<8)+sock;
+    return open_dev(dev, mode);
+#endif
+#ifdef __BEOS__
+    int fd;
+    char fn[B_OS_NAME_LENGTH];
+    sprintf(fn, "/dev/pcmcia/sock%d", sock);
+    return open(fn, (mode & S_IWRITE) ? O_RDWR: O_RDONLY);
+#endif
+}
+
+/*======================================================================
+
+    xlate_scsi_name() is a sort-of-hack used to deduce the minor
+    device numbers of SCSI devices, from the information available to
+    the low-level driver.
+    
+======================================================================*/
+
+#ifdef __linux__
+
+#include <linux/major.h>
+#include <scsi/scsi.h>
+#define VERSION(v,p,s) (((v)<<16)+(p<<8)+s)
+#if (LINUX_VERSION_CODE < VERSION(2,1,126))
+#define SCSI_DISK0_MAJOR SCSI_DISK_MAJOR
+#endif
+
+static int xlate_scsi_name(bind_info_t *bind)
+{
+    int i, fd, mode, minor;
+    u_long arg[2], id1, id2;
+
+    id1 = strtol(bind->name+3, NULL, 16);
+    if ((bind->major == SCSI_DISK0_MAJOR) ||
+	(bind->major == SCSI_CDROM_MAJOR))
+	mode = S_IREAD|S_IFBLK;
+    else
+	mode = S_IREAD|S_IFCHR;
+    
+    for (i = 0; i < 16; i++) {
+	minor = (bind->major == SCSI_DISK0_MAJOR) ? (i<<4) : i;
+	fd = open_dev((bind->major<<8)+minor, mode);
+	if (fd < 0)
+	    continue;
+	if (ioctl(fd, SCSI_IOCTL_GET_IDLUN, arg) == 0) {
+	    id2 = (arg[0]&0x0f) + ((arg[0]>>4)&0xf0) +
+		((arg[0]>>8)&0xf00) + ((arg[0]>>12)&0xf000);
+	    if (id1 == id2) {
+		close(fd);
+		switch (bind->major) {
+		case SCSI_DISK0_MAJOR:
+		case SCSI_GENERIC_MAJOR:
+		    sprintf(bind->name+2, "%c", 'a'+i); break;
+		case SCSI_CDROM_MAJOR:
+		    sprintf(bind->name, "scd%d", i); break;
+		case SCSI_TAPE_MAJOR:
+		    sprintf(bind->name+2, "%d", i); break;
+		}
+		bind->minor = minor;
+		return 0;
+	    }
+	}
+	close(fd);
+    }
+    return -1;
+}
+#endif
+
+/*====================================================================*/
+
+#define BEEP_TIME 150
+#define BEEP_OK   1000
+#define BEEP_WARN 2000
+#define BEEP_ERR  4000
+
+#ifdef __linux__
+
+#include <sys/kd.h>
+
+static void beep(unsigned int ms, unsigned int freq)
+{
+    int fd, arg;
+
+    if (be_quiet)
+	return;
+    fd = open("/dev/console", O_RDWR);
+    if (fd < 0)
+	return;
+    arg = (ms << 16) | freq;
+    ioctl(fd, KDMKTONE, arg);
+    close(fd);
+    usleep(ms*1000);
+}
+
+#endif /* __linux__ */
+
+#ifdef __BEOS__
+static void beep(unsigned int ms, unsigned int freq)
+{
+    if (!be_quiet) system("/bin/beep");
+}
+#endif
+
+/*====================================================================*/
+
+static void write_pid(void)
+{
+    FILE *f;
+    f = fopen(pidfile, "w");
+    if (f == NULL)
+	syslog(LOG_INFO, "could not open %s: %m", pidfile);
+    else {
+	fprintf(f, "%d\n", getpid());
+	fclose(f);
+    }
+}
+
+static void write_stab(void)
+{
+    int i, j, k;
+    FILE *f;
+    socket_info_t *s;
+    bind_info_t *bind;
+
+    f = fopen(stabfile, "w");
+    if (f == NULL) {
+	syslog(LOG_INFO, "fopen(stabfile) failed: %m");
+	return;
+    }
+#ifndef __BEOS__
+    if (flock(fileno(f), LOCK_EX) != 0) {
+	syslog(LOG_INFO, "flock(stabfile) failed: %m");
+	return;
+    }
+#endif
+    for (i = 0; i < sockets; i++) {
+	s = &socket[i];
+	if (!(s->state & SOCKET_PRESENT))
+	    fprintf(f, "Socket %d: empty\n", i);
+	else if (!s->card)
+	    fprintf(f, "Socket %d: unsupported card\n", i);
+	else {
+	    fprintf(f, "Socket %d: %s\n", i, s->card->name);
+	    for (j = 0; j < s->card->bindings; j++)
+		for (k = 0, bind = s->bind[j];
+		     bind != NULL;
+		     k++, bind = bind->next) {
+		    fprintf(f, "%d\t%s\t%s\t%d\t%s",
+			    i, s->card->device[j]->class,
+			    bind->dev_info, k, bind->name);
+		    if (bind->major)
+			fprintf(f, "\t%d\t%d\n",
+				bind->major, bind->minor);
+		    else
+			fputc('\n', f);
+		}
+	}
+    }
+    fflush(f);
+#ifndef __BEOS__
+    flock(fileno(f), LOCK_UN);
+#endif
+    fclose(f);
+}
+
+/*====================================================================*/
+
+static int get_tuple(int ns, cisdata_t code, ds_ioctl_arg_t *arg)
+{
+    socket_info_t *s = &socket[ns];
+    
+    arg->tuple.DesiredTuple = code;
+    arg->tuple.Attributes = 0;
+    if (ioctl(s->fd, DS_GET_FIRST_TUPLE, arg) != 0)
+	return -1;
+    arg->tuple.TupleOffset = 0;
+    if (ioctl(s->fd, DS_GET_TUPLE_DATA, arg) != 0) {
+	syslog(LOG_INFO, "error reading CIS data on socket %d: %m", ns);
+	return -1;
+    }
+    if (ioctl(s->fd, DS_PARSE_TUPLE, arg) != 0) {
+	syslog(LOG_INFO, "error parsing CIS on socket %d: %m", ns);
+	return -1;
+    }
+    return 0;
+}
+
+/*====================================================================*/
+
+static void log_card_info(cistpl_vers_1_t *vers,
+			  cistpl_manfid_t *manfid,
+			  cistpl_funcid_t *funcid)
+{
+    char v[256] = "";
+    int i;
+    static char *fn[] = {
+	"multi", "memory", "serial", "parallel", "fixed disk",
+	"video", "network", "AIMS", "SCSI"
+    };
+    
+    if (vers) {
+	for (i = 0; i < vers->ns; i++)
+	    sprintf(v+strlen(v), "%s\"%s\"",
+		    (i>0) ? ", " : "", vers->str+vers->ofs[i]);
+	syslog(LOG_INFO, "  product info: %s", v);
+    } else {
+	syslog(LOG_INFO, "  no product info available");
+    }
+    *v = '\0';
+    if (manfid->manf != 0)
+	sprintf(v, "  manfid: 0x%04x, 0x%04x",
+		manfid->manf, manfid->card);
+    if (funcid->func != 0xff)
+	sprintf(v+strlen(v), "  function: %d (%s)", funcid->func,
+		fn[funcid->func]);
+    if (strlen(v) > 0) syslog(LOG_INFO, "%s", v);
+}
+
+static card_info_t *lookup_card(int ns)
+{
+    socket_info_t *s = &socket[ns];
+    card_info_t *card;
+    ds_ioctl_arg_t arg;
+    cistpl_vers_1_t *vers = NULL;
+    cistpl_manfid_t manfid = { 0, 0 };
+    cistpl_funcid_t funcid = { 0xff, 0xff };
+    cs_status_t status;
+    int i, ret, match;
+    int has_cis = 0;
+
+    /* Do we have a CIS structure? */
+    ret = ioctl(s->fd, DS_VALIDATE_CIS, &arg);
+    has_cis = ((ret == 0) && (arg.cisinfo.Chains > 0));
+    
+    /* Try to read VERS_1, MANFID tuples */
+    if (has_cis) {
+	/* rule of thumb: cards with no FUNCID, but with common memory
+	   device geometry information, are probably memory cards */
+	if (get_tuple(ns, CISTPL_FUNCID, &arg) == 0)
+	    memcpy(&funcid, &arg.tuple_parse.parse.funcid,
+		   sizeof(funcid));
+	else if (get_tuple(ns, CISTPL_DEVICE_GEO, &arg) == 0)
+	    funcid.func = CISTPL_FUNCID_MEMORY;
+	if (get_tuple(ns, CISTPL_MANFID, &arg) == 0)
+	    memcpy(&manfid, &arg.tuple_parse.parse.manfid,
+		   sizeof(manfid));
+	if (get_tuple(ns, CISTPL_VERS_1, &arg) == 0)
+	    vers = &arg.tuple_parse.parse.version_1;
+
+	match = 0;
+	for (card = root_card; card; card = card->next) {
+	    switch (card->ident_type) {
+		
+	    case VERS_1_IDENT:
+		if (vers == NULL)
+		    break;
+		for (i = 0; i < card->id.vers.ns; i++) {
+		    if (strcmp(card->id.vers.pi[i], "*") == 0)
+			continue;
+		    if (i >= vers->ns)
+			break;
+		    if (strcmp(card->id.vers.pi[i],
+			       vers->str+vers->ofs[i]) != 0)
+			break;
+		}
+		if (i < card->id.vers.ns)
+		    break;
+		match = 1;
+		break;
+
+	    case MANFID_IDENT:
+		if ((manfid.manf == card->id.manfid.manf) &&
+		    (manfid.card == card->id.manfid.card))
+		    match = 1;
+		break;
+		
+	    case TUPLE_IDENT:
+		arg.tuple.DesiredTuple = card->id.tuple.code;
+		arg.tuple.Attributes = 0;
+		ret = ioctl(s->fd, DS_GET_FIRST_TUPLE, &arg);
+		if (ret != 0) break;
+		arg.tuple.TupleOffset = card->id.tuple.ofs;
+		ret = ioctl(s->fd, DS_GET_TUPLE_DATA, &arg);
+		if (ret != 0) break;
+		if (strncmp((char *)arg.tuple_parse.data,
+			    card->id.tuple.info,
+			    strlen(card->id.tuple.info)) != 0)
+		    break;
+		match = 1;
+		break;
+
+	    default:
+		/* Skip */
+		break;
+	    }
+	    if (match) break;
+	}
+	if (match) {
+	    syslog(LOG_INFO, "socket %d: %s", ns, card->name);
+	    beep(BEEP_TIME, BEEP_OK);
+	    if (verbose) log_card_info(vers, &manfid, &funcid);
+	    return card;
+	}
+    }
+
+    /* Try for a FUNCID match */
+    if (funcid.func != 0xff) {
+	for (card = root_func; card; card = card->next)
+	    if (card->id.func.funcid == funcid.func)
+		break;
+	if (card) {
+	    syslog(LOG_INFO, "socket %d: %s", ns, card->name);
+	    beep(BEEP_TIME, BEEP_OK);
+	    if (verbose) log_card_info(vers, &manfid, &funcid);
+	    return card;
+	}
+    }
+
+    status.Function = 0;
+    if ((ioctl(s->fd, DS_GET_STATUS, &status) != 0) ||
+	(status.CardState & CS_EVENT_CB_DETECT) ||
+	manfid.manf || manfid.card || vers || !blank_card) {
+	syslog(LOG_INFO, "unsupported card in socket %d", ns);
+	if (one_pass) return NULL;
+	beep(BEEP_TIME, BEEP_ERR);
+	log_card_info(vers, &manfid, &funcid);
+	return NULL;
+    } else {
+	card = blank_card;
+	syslog(LOG_INFO, "socket %d: %s", ns, card->name);
+	beep(BEEP_TIME, BEEP_WARN);
+	return card;
+    }
+}
+
+/*====================================================================*/
+
+static void load_config(void)
+{
+    if (chdir(configpath) != 0)
+	syslog(LOG_INFO, "chdir to %s failed: %m", configpath);
+    if (parse_configfile("config") != 0)
+	exit(EXIT_FAILURE);
+    if (root_device == NULL)
+	syslog(LOG_INFO, "no device drivers defined");
+    if ((root_card == NULL) && (root_func == NULL))
+	syslog(LOG_INFO, "no cards defined");
+}
+
+/*====================================================================*/
+
+static void free_card(card_info_t *card)
+{
+    if (card && (--card->refs == 0)) {
+	int i;
+	free(card->name);
+	switch(card->ident_type) {
+	case VERS_1_IDENT:
+	    for (i = 0; i < card->id.vers.ns; i++)
+		free(card->id.vers.pi[i]);
+	break;
+	case TUPLE_IDENT:
+	    free(card->id.tuple.info);
+	    break;
+	default:
+	    break;
+	}
+	free(card);
+    }
+}
+
+static void free_device(device_info_t *dev)
+{
+    if (dev && (--dev->refs == 0)) {
+	int i;
+	for (i = 0; i < dev->modules; i++) {
+	    free(dev->module[i]);
+	    if (dev->opts[i]) free(dev->opts[i]);
+	}
+	if (dev->class) free(dev->class);
+	free(dev);
+    }
+}
+
+static void free_mtd(mtd_ident_t *mtd)
+{
+    if (mtd && (--mtd->refs == 0)) {
+	free(mtd->name);
+	free(mtd->module);
+	free(mtd);
+    }
+}
+
+static void free_config(void)
+{
+    while (root_adjust != NULL) {
+	adjust_list_t *adj = root_adjust;
+	root_adjust = root_adjust->next;
+	free(adj);
+    }
+    
+    while (root_device != NULL) {
+	device_info_t *dev = root_device;
+	root_device = root_device->next;
+	free_device(dev);
+    }
+
+    while (root_card != NULL) {
+	card_info_t *card = root_card;
+	root_card = root_card->next;
+	free_card(card);
+    }
+    
+    while (root_func != NULL) {
+	card_info_t *card = root_func;
+	root_func = root_func->next;
+	free_card(card);
+    }
+    blank_card = NULL;
+    
+    while (root_mtd != NULL) {
+	mtd_ident_t *mtd = root_mtd;
+	root_mtd = root_mtd->next;
+	free_mtd(mtd);
+    }
+    default_mtd = NULL;
+}
+
+/*====================================================================*/
+
+static int execute(char *msg, char *cmd)
+{
+    int ret;
+    FILE *f;
+    char line[256];
+    
+    syslog(LOG_INFO, "executing: '%s'", cmd);
+    strcat(cmd, " 2>&1");
+    f = popen(cmd, "r");
+    while (fgets(line, 255, f)) {
+	line[strlen(line)-1] = '\0';
+	syslog(LOG_INFO, "+ %s", line);
+    }
+    ret = pclose(f);
+    if (WIFEXITED(ret)) {
+	if (WEXITSTATUS(ret))
+	    syslog(LOG_INFO, "%s exited with status %d",
+		   msg, WEXITSTATUS(ret));
+	return WEXITSTATUS(ret);
+    } else
+	syslog(LOG_INFO, "%s exited on signal %d",
+	       msg, WTERMSIG(ret));
+    return -1;
+}
+
+/*====================================================================*/
+
+static int execute_on_dev(char *action, char *class, char *dev)
+{
+    char msg[128], cmd[512];
+
+    sprintf(msg, "%s cmd", action);
+    sprintf(cmd, "./%s %s %s", class, action, dev);
+    return execute(msg, cmd);
+}
+
+static int execute_on_all(char *cmd, char *class, int sn, int fn)
+{
+    socket_info_t *s = &socket[sn];
+    bind_info_t *bind;
+    int ret = 0;
+    for (bind = s->bind[fn]; bind != NULL; bind = bind->next)
+	if (bind->name[2] != '#')
+	    ret |= execute_on_dev(cmd, class, bind->name);
+    return ret;
+}
+
+/*====================================================================*/
+
+#ifdef __linux__
+
+typedef struct module_list_t {
+    char *mod;
+    int usage;
+    struct module_list_t *next;
+} module_list_t;
+
+static module_list_t *module_list = NULL;
+
+static int try_insmod(char *mod, char *opts)
+{
+    char path[128], cmd[128];
+    if (strchr(mod, '/') != NULL)
+	sprintf(path, "%s/%s.o", modpath, mod);
+    else
+	sprintf(path, "%s/pcmcia/%s.o", modpath, mod);
+    if (access(path, R_OK) != 0) {
+	syslog(LOG_INFO, "module %s not available", path);
+	return -1;
+    }
+    sprintf(cmd, "insmod %s", path);
+    if (opts) {
+	strcat(cmd, " ");
+	strcat(cmd, opts);
+    }
+    return execute("insmod", cmd);
+}
+
+static int try_modprobe(char *mod, char *opts)
+{
+    char cmd[128], *s = strrchr(mod, '/');
+    sprintf(cmd, "modprobe %s", (s) ? s+1 : mod);
+    if (opts) {
+	strcat(cmd, " ");
+	strcat(cmd, opts);
+    }
+    return execute("modprobe", cmd);
+}
+
+static void install_module(char *mod, char *opts)
+{
+    module_list_t *ml;
+
+    for (ml = module_list; ml != NULL; ml = ml->next)
+	if (strcmp(mod, ml->mod) == 0) break;
+    if (ml == NULL) {
+	ml = (module_list_t *)malloc(sizeof(struct module_list_t));
+	ml->mod = mod;
+	ml->usage = 0;
+	ml->next = module_list;
+	module_list = ml;
+    }
+    ml->usage++;
+    if (ml->usage != 1)
+	return;
+
+#ifdef __linux__
+    if (access("/proc/bus/pccard/drivers", R_OK) == 0) {
+	FILE *f = fopen("/proc/bus/pccard/drivers", "r");
+	if (f) {
+	    char a[61], s[33];
+	    while (fgets(a, 60, f)) {
+		int is_kernel;
+		sscanf(a, "%s %d", s, &is_kernel);
+		if (strcmp(s, mod) != 0) continue;
+		/* If it isn't a module, we won't try to rmmod */
+		ml->usage += is_kernel;
+		fclose(f);
+		return;
+	    }
+	    fclose(f);
+	}
+    }
+#endif
+
+    if (do_modprobe) {
+	if (try_modprobe(mod, opts) != 0)
+	    try_insmod(mod, opts);
+    } else {
+	if (try_insmod(mod, opts) != 0)
+	    try_modprobe(mod, opts);
+    }
+}
+
+static void remove_module(char *mod)
+{
+    char *s, cmd[128];
+    module_list_t *ml;
+
+    for (ml = module_list; ml != NULL; ml = ml->next)
+	if (strcmp(mod, ml->mod) == 0) break;
+    if (ml != NULL) {
+	ml->usage--;
+	if (ml->usage == 0) {
+	    /* Strip off leading path names */
+	    s = strrchr(mod, '/');
+	    s = (s) ? s+1 : mod;
+	    sprintf(cmd, do_modprobe ? "modprobe -r %s" : "rmmod %s", s);
+	    execute(do_modprobe ? "modprobe" : "rmmod", cmd);
+	}
+    }
+}
+
+#endif /* __linux__ */
+
+/*====================================================================*/
+
+#ifdef __BEOS__
+
+#define install_module(a,b)
+#define remove_module(a)
+
+static void republish_driver(char *mod)
+{
+    int fd = open("/dev", O_RDWR);
+    write(fd, mod, strlen(mod));
+    close(fd);
+}
+
+#endif /* __BEOS__ */
+
+/*====================================================================*/
+
+static mtd_ident_t *lookup_mtd(region_info_t *region)
+{
+    mtd_ident_t *mtd;
+    int match = 0;
+    
+    for (mtd = root_mtd; mtd; mtd = mtd->next) {
+	switch (mtd->mtd_type) {
+	case JEDEC_MTD:
+	    if ((mtd->jedec_mfr == region->JedecMfr) &&
+		(mtd->jedec_info == region->JedecInfo)) {
+		match = 1;
+		break;
+	    }
+	case DTYPE_MTD:
+	    break;
+	default:
+	    break;
+	}
+	if (match) break;
+    }
+    if (mtd)
+	return mtd;
+    else
+	return default_mtd;
+}
+
+/*====================================================================*/
+
+static void bind_mtd(int sn)
+{
+    socket_info_t *s = &socket[sn];
+    region_info_t region;
+    bind_info_t bind;
+    mtd_info_t mtd_info;
+    mtd_ident_t *mtd;
+    int i, attr, ret, nr;
+
+    nr = 0;
+    for (attr = 0; attr < 2; attr++) {
+	region.Attributes = attr;
+	ret = ioctl(s->fd, DS_GET_FIRST_REGION, &region);
+	while (ret == 0) {
+	    mtd = lookup_mtd(&region);
+	    if (mtd) {
+		/* Have we seen this MTD before? */
+		for (i = 0; i < nr; i++)
+		    if (s->mtd[i] == mtd) break;
+		if (i == nr) {
+		    install_module(mtd->module, mtd->opts);
+		    s->mtd[nr] = mtd;
+		    mtd->refs++;
+		    nr++;
+		}
+		syslog(LOG_INFO, "  %s memory region at 0x%lx: %s",
+		       attr ? "Attribute" : "Common", region.CardOffset,
+		       mtd->name);
+		/* Bind MTD to this region */
+		strcpy(mtd_info.dev_info, s->mtd[i]->module);
+		mtd_info.Attributes = region.Attributes;
+		mtd_info.CardOffset = region.CardOffset;
+		if (ioctl(s->fd, DS_BIND_MTD, &mtd_info) != 0) {
+		    syslog(LOG_INFO,
+			   "bind MTD '%s' to region at 0x%lx failed: %m",
+			   (char *)mtd_info.dev_info, region.CardOffset);
+		}
+	    }
+	    ret = ioctl(s->fd, DS_GET_NEXT_REGION, &region);
+	}
+    }
+    s->mtd[nr] = NULL;
+    
+    /* Now bind each unique MTD as a normal client of this socket */
+    for (i = 0; i < nr; i++) {
+	strcpy(bind.dev_info, s->mtd[i]->module);
+	if (ioctl(s->fd, DS_BIND_REQUEST, &bind) != 0)
+	    syslog(LOG_INFO, "bind MTD '%s' to socket %d failed: %m",
+		   (char *)bind.dev_info, sn);
+    }
+}
+
+/*====================================================================*/
+
+static void update_cis(socket_info_t *s)
+{
+    cisdump_t cis;
+    FILE *f = fopen(s->card->cis_file, "r");
+    if (f == NULL)
+	syslog(LOG_INFO, "could not open '%s': %m", s->card->cis_file);
+    else {
+	cis.Length = fread(cis.Data, 1, CISTPL_MAX_CIS_SIZE, f);
+	fclose(f);
+	if (ioctl(s->fd, DS_REPLACE_CIS, &cis) != 0)
+	    syslog(LOG_INFO, "could not replace CIS: %m");
+    }
+}
+
+/*====================================================================*/
+
+static void do_insert(int sn)
+{
+    socket_info_t *s = &socket[sn];
+    card_info_t *card;
+    device_info_t **dev;
+    bind_info_t *bind, **tail;
+    int i, j, ret;
+
+    /* Already identified? */
+    if ((s->card != NULL) && (s->card != blank_card))
+	return;
+    
+    syslog(LOG_INFO, "initializing socket %d", sn);
+    card = lookup_card(sn);
+    /* Make sure we've learned something new before continuing */
+    if (card == s->card)
+	return;
+    s->card = card;
+    card->refs++;
+    if (card->cis_file) update_cis(s);
+
+    dev = card->device;
+
+    /* Set up MTD's */
+    for (i = 0; i < card->bindings; i++)
+	if (dev[i]->needs_mtd)
+	    break;
+    if (i < card->bindings)
+	bind_mtd(sn);
+
+#ifdef __linux__
+    /* Install kernel modules */
+    for (i = 0; i < card->bindings; i++) {
+	dev[i]->refs++;
+	for (j = 0; j < dev[i]->modules; j++)
+	    install_module(dev[i]->module[j], dev[i]->opts[j]);
+    }
+#endif
+    
+    /* Bind drivers by their dev_info identifiers */
+    for (i = 0; i < card->bindings; i++) {
+	bind = calloc(1, sizeof(bind_info_t));
+	strcpy((char *)bind->dev_info, (char *)dev[i]->dev_info);
+	if (strcmp(bind->dev_info, "cb_enabler") == 0)
+	    bind->function = BIND_FN_ALL;
+	else
+	    bind->function = card->dev_fn[i];
+	if (ioctl(s->fd, DS_BIND_REQUEST, bind) != 0) {
+	    if (errno == EBUSY) {
+		syslog(LOG_INFO, "'%s' already bound to socket %d",
+		       (char *)bind->dev_info, sn);
+	    } else {
+		syslog(LOG_INFO, "bind '%s' to socket %d failed: %m",
+		       (char *)bind->dev_info, sn);
+		beep(BEEP_TIME, BEEP_ERR);
+		write_stab();
+		return;
+	    }
+	}
+
+#ifdef __BEOS__
+	republish_driver(dev[i]->module[0]);
+#endif
+
+	for (ret = j = 0; j < 10; j++) {
+	    ret = ioctl(s->fd, DS_GET_DEVICE_INFO, bind);
+	    if ((ret == 0) || (errno != EAGAIN))
+		break;
+	    usleep(100000);
+	}
+	if (ret != 0) {
+	    syslog(LOG_INFO, "get dev info on socket %d failed: %m",
+		   sn);
+	    ioctl(s->fd, DS_UNBIND_REQUEST, bind);
+	    beep(BEEP_TIME, BEEP_ERR);
+	    write_stab();
+	    return;
+	}
+	tail = &s->bind[i];
+	while (ret == 0) {
+	    bind_info_t *old;
+#ifdef __linux__
+	    if ((strlen(bind->name) > 3) &&
+		(bind->name[2] == '#'))
+		xlate_scsi_name(bind);
+#endif
+	    old = *tail = bind; tail = (bind_info_t **)&bind->next;
+	    bind = (bind_info_t *)malloc(sizeof(bind_info_t));
+	    memcpy(bind, old, sizeof(bind_info_t));
+	    ret = ioctl(s->fd, DS_GET_NEXT_DEVICE, bind);
+	}
+	*tail = NULL; free(bind);
+	write_stab();
+    }
+
+    /* Run "start" commands */
+    for (i = ret = 0; i < card->bindings; i++)
+	if (dev[i]->class)
+	    ret |= execute_on_all("start", dev[i]->class, sn, i);
+    if (ret)
+	beep(BEEP_TIME, BEEP_ERR);
+    else
+	beep(BEEP_TIME, BEEP_OK);
+    
+}
+
+/*====================================================================*/
+
+static int do_check(int sn)
+{
+    socket_info_t *s = &socket[sn];
+    card_info_t *card;
+    device_info_t **dev;
+    int i, ret;
+
+    card = s->card;
+    if (card == NULL)
+	return 0;
+    
+    /* Run "check" commands */
+    dev = card->device;
+    for (i = 0; i < card->bindings; i++) {
+	if (dev[i]->class) {
+	    ret = execute_on_all("check", dev[i]->class, sn, i);
+	    if (ret != 0)
+		return CS_IN_USE;
+	}
+    }
+    return 0;
+}
+
+/*====================================================================*/
+
+static void do_remove(int sn)
+{
+    socket_info_t *s = &socket[sn];
+    card_info_t *card;
+    device_info_t **dev;
+    bind_info_t *bind;
+    int i, j;
+
+    card = s->card;
+    if (card == NULL)
+	goto done;
+    
+    syslog(LOG_INFO, "shutting down socket %d", sn);
+    
+    /* Run "stop" commands */
+    dev = card->device;
+    for (i = 0; i < card->bindings; i++) {
+	if (dev[i]->class) {
+	    execute_on_all("stop", dev[i]->class, sn, i);
+	}
+    }
+
+    /* unbind driver instances */
+    for (i = 0; i < card->bindings; i++) {
+	if (s->bind[i]) {
+	    if (ioctl(s->fd, DS_UNBIND_REQUEST, s->bind[i]) != 0)
+		syslog(LOG_INFO, "unbind '%s' from socket %d failed: %m",
+		       (char *)s->bind[i]->dev_info, sn);
+	    while (s->bind[i]) {
+		bind = s->bind[i];
+		s->bind[i] = bind->next;
+		free(bind);
+	    }
+	}
+    }
+    for (i = 0; (s->mtd[i] != NULL); i++) {
+	bind_info_t b;
+	strcpy(b.dev_info, s->mtd[i]->module);
+	if (ioctl(s->fd, DS_UNBIND_REQUEST, &b) != 0)
+	    syslog(LOG_INFO, "unbind MTD '%s' from socket %d failed: %m",
+		   s->mtd[i]->module, sn);
+    }
+
+    /* remove kernel modules in inverse order */
+    for (i = 0; i < card->bindings; i++) {
+	for (j = dev[i]->modules-1; j >= 0; j--)
+	    remove_module(dev[i]->module[j]);
+	free_device(dev[i]);
+    }
+    /* Remove any MTD's bound to this socket */
+    for (i = 0; (s->mtd[i] != NULL); i++) {
+	remove_module(s->mtd[i]->module);
+	free_mtd(s->mtd[i]);
+	s->mtd[i] = NULL;
+    }
+
+done:
+    beep(BEEP_TIME, BEEP_OK);
+    free_card(card);
+    s->card = NULL;
+    write_stab();
+}
+
+/*====================================================================*/
+
+static void do_suspend(int sn)
+{
+    socket_info_t *s = &socket[sn];
+    card_info_t *card;
+    device_info_t **dev;
+    int i, ret;
+    
+    card = s->card;
+    if (card == NULL)
+	return;
+    dev = card->device;
+    for (i = 0; i < card->bindings; i++) {
+	if (dev[i]->class) {
+	    ret = execute_on_all("suspend", dev[i]->class, sn, i);
+	    if (ret != 0)
+		beep(BEEP_TIME, BEEP_ERR);
+	}
+    }
+}
+
+/*====================================================================*/
+
+static void do_resume(int sn)
+{
+    socket_info_t *s = &socket[sn];
+    card_info_t *card;
+    device_info_t **dev;
+    int i, ret;
+    
+    card = s->card;
+    if (card == NULL)
+	return;
+    dev = card->device;
+    for (i = 0; i < card->bindings; i++) {
+	if (dev[i]->class) {
+	    ret = execute_on_all("resume", dev[i]->class, sn, i);
+	    if (ret != 0)
+		beep(BEEP_TIME, BEEP_ERR);
+	}
+    }
+}
+
+/*====================================================================*/
+
+static void wait_for_pending(void)
+{
+    cs_status_t status;
+    int i;
+    status.Function = 0;
+    for (;;) {
+	usleep(100000);
+	for (i = 0; i < sockets; i++)
+	    if ((ioctl(socket[i].fd, DS_GET_STATUS, &status) == 0) &&
+		(status.CardState & CS_EVENT_CARD_INSERTION))
+		break;
+	if (i == sockets) break;
+    }
+}
+
+/*====================================================================*/
+
+static void free_resources(void)
+{
+    adjust_list_t *al;
+    int fd = socket[0].fd;
+
+    for (al = root_adjust; al; al = al->next) {
+	if (al->adj.Action == ADD_MANAGED_RESOURCE) {
+	    al->adj.Action = REMOVE_MANAGED_RESOURCE;
+	    ioctl(fd, DS_ADJUST_RESOURCE_INFO, &al->adj);
+	} else if ((al->adj.Action == REMOVE_MANAGED_RESOURCE) &&
+		   (al->adj.Resource == RES_IRQ)) {
+	    al->adj.Action = ADD_MANAGED_RESOURCE;
+	    ioctl(fd, DS_ADJUST_RESOURCE_INFO, &al->adj);
+	}
+    }
+    
+}
+
+/*====================================================================*/
+
+static void adjust_resources(void)
+{
+    adjust_list_t *al;
+    int ret;
+    char tmp[64];
+    int fd = socket[0].fd;
+    
+    for (al = root_adjust; al; al = al->next) {
+	ret = ioctl(fd, DS_ADJUST_RESOURCE_INFO, &al->adj);
+	if (ret != 0) {
+	    switch (al->adj.Resource) {
+	    case RES_MEMORY_RANGE:
+		sprintf(tmp, "memory %#lx-%#lx",
+			al->adj.resource.memory.Base,
+			al->adj.resource.memory.Base +
+			al->adj.resource.memory.Size - 1);
+		break;
+	    case RES_IO_RANGE:
+		sprintf(tmp, "IO ports %#x-%#x",
+			al->adj.resource.io.BasePort,
+			al->adj.resource.io.BasePort +
+			al->adj.resource.io.NumPorts - 1);
+		break;
+	    case RES_IRQ:
+		sprintf(tmp, "irq %u", al->adj.resource.irq.IRQ);
+		break;
+	    }
+	    syslog(LOG_INFO, "could not adjust resource: %s: %m", tmp);
+	}
+    }
+}
+    
+/*====================================================================*/
+
+static int cleanup_files = 0;
+
+static void fork_now(void)
+{
+    int ret;
+    if ((ret = fork()) > 0) {
+	cleanup_files = 0;
+	exit(0);
+    }
+    if (ret == -1)
+	syslog(LOG_INFO, "forking: %m");
+    if (setsid() < 0)
+	syslog(LOG_INFO, "detaching from tty: %m");
+}    
+
+static void done(void)
+{
+    syslog(LOG_INFO, "exiting");
+    if (cleanup_files) {
+	unlink(pidfile);
+	unlink(stabfile);
+    }
+}
+
+/*====================================================================*/
+
+/* most recent signal */
+static int caught_signal = 0;
+
+static void catch_signal(int sig)
+{
+    caught_signal = sig;
+    if (signal(sig, catch_signal) == SIG_ERR)
+	syslog(LOG_INFO, "signal(%d): %m", sig);
+}
+
+static void handle_signal(void)
+{
+    int i;
+    switch (caught_signal) {
+    case SIGTERM:
+    case SIGINT:
+	for (i = 0; i < sockets; i++)
+	    if ((socket[i].state & SOCKET_PRESENT) &&
+		(do_check(i) == 0)) do_remove(i);
+	free_resources();
+	exit(0);
+	break;
+    case SIGHUP:
+	free_resources();
+	free_config();
+	syslog(LOG_INFO, "re-loading config file");
+	load_config();
+	adjust_resources();
+	break;
+#ifdef SIGPWR
+    case SIGPWR:
+	break;
+#endif
+    }
+}
+
+/*====================================================================*/
+
+static int init_sockets(void)
+{
+    int fd, i;
+    servinfo_t serv;
+
+#ifdef __linux__
+    major = lookup_dev("pcmcia");
+    if (major < 0) {
+	if (major == -ENODEV)
+	    syslog(LOG_INFO, "no pcmcia driver in /proc/devices");
+	else
+	    syslog(LOG_INFO, "could not open /proc/devices: %m");
+	exit(EXIT_FAILURE);
+    }
+#endif
+    for (fd = -1, i = 0; i < MAX_SOCKS; i++) {
+	fd = open_sock(i, S_IFCHR|S_IREAD|S_IWRITE);
+	if (fd < 0) break;
+	socket[i].fd = fd;
+	socket[i].state = 0;
+    }
+    if ((fd < 0) && (errno != ENODEV) && (errno != ENOENT))
+	syslog(LOG_INFO, "open_sock(socket %d) failed: %m", i);
+    sockets = i;
+    if (sockets == 0) {
+	syslog(LOG_INFO, "no sockets found!");
+	return -1;
+    } else
+	syslog(LOG_INFO, "watching %d sockets", sockets);
+
+    if (ioctl(socket[0].fd, DS_GET_CARD_SERVICES_INFO, &serv) == 0) {
+	if (serv.Revision != CS_RELEASE_CODE)
+	    syslog(LOG_INFO, "Card Services release does not match!");
+    } else {
+	syslog(LOG_INFO, "could not get CS revision info!");
+	return -1;
+    }
+    adjust_resources();
+    return 0;
+}
+
+/*====================================================================*/
+
+int main(int argc, char *argv[])
+{
+    int optch, errflg;
+    int i, max_fd, ret, event, pass;
+    int delay_fork = 0;
+    struct timeval tv;
+    fd_set fds;
+
+    if (access("/var/state/pcmcia", R_OK) == 0) {
+	stabfile = "/var/state/pcmcia/stab";
+    } else if (access("/var/lib/pcmcia", R_OK) == 0) {
+	stabfile = "/var/lib/pcmcia/stab";
+    } else {
+	stabfile = "/var/run/stab";
+    }
+
+    errflg = 0;
+    while ((optch = getopt(argc, argv, "Vqdvofc:m:p:s:")) != -1) {
+	switch (optch) {
+	case 'V':
+	    fprintf(stderr, "cardmgr version " CS_RELEASE "\n");
+	    return 0;
+	    break;
+	case 'q':
+	    be_quiet = 1; break;
+	case 'v':
+	    verbose = 1; break;
+	case 'o':
+	    one_pass = 1; break;
+	case 'f':
+	    delay_fork = 1; break;
+	case 'c':
+	    configpath = strdup(optarg); break;
+#ifdef __linux__
+	case 'd':
+	    do_modprobe = 1; break;
+	case 'm':
+	    modpath = strdup(optarg); break;
+#endif
+	case 'p':
+	    pidfile = strdup(optarg); break;
+	case 's':
+	    stabfile = strdup(optarg); break;
+	default:
+	    errflg = 1; break;
+	}
+    }
+    if (errflg || (optind < argc)) {
+	fprintf(stderr, "usage: %s [-V] [-q] [-v] [-d] [-o] [-f] "
+		"[-c configpath] [-m modpath]\n               "
+		"[-p pidfile] [-s stabfile]\n", argv[0]);
+	exit(EXIT_FAILURE);
+    }
+
+#ifdef DEBUG
+    openlog("cardmgr", LOG_PID|LOG_PERROR, LOG_DAEMON);
+#else
+    openlog("cardmgr", LOG_PID|LOG_CONS, LOG_DAEMON);
+    close(0); close(1); close(2);
+    if (!delay_fork && !one_pass)
+	fork_now();
+#endif
+    
+    syslog(LOG_INFO, "starting, version is " CS_RELEASE);
+    atexit(&done);
+    putenv("PATH=/bin:/sbin:/usr/bin:/usr/sbin");
+
+#ifdef __linux__
+    if (modpath == NULL) {
+	if (access("/lib/modules/preferred", X_OK) == 0)
+	    modpath = "/lib/modules/preferred";
+	else {
+	    struct utsname utsname;
+	    if (uname(&utsname) != 0) {
+		syslog(LOG_INFO, "uname(): %m");
+		exit(EXIT_FAILURE);
+	    }
+	    modpath = (char *)malloc(strlen(utsname.release)+14);
+	    sprintf(modpath, "/lib/modules/%s", utsname.release);
+	}
+    }
+    if (access(modpath, X_OK) != 0) {
+	syslog(LOG_INFO, "cannot access %s: %m", modpath);
+	exit(EXIT_FAILURE);
+    }
+    /* We default to using modprobe if it is available */
+    do_modprobe |= (access("/sbin/modprobe", X_OK) == 0);
+#endif /* __linux__ */
+    
+    load_config();
+    
+    if (init_sockets() != 0)
+	exit(EXIT_FAILURE);
+
+    /* If we've gotten this far, then clean up pid and stab at exit */
+    write_pid();
+    write_stab();
+    cleanup_files = 1;
+    
+    if (signal(SIGHUP, catch_signal) == SIG_ERR)
+	syslog(LOG_INFO, "signal(SIGHUP): %m");
+    if (signal(SIGTERM, catch_signal) == SIG_ERR)
+	syslog(LOG_INFO, "signal(SIGTERM): %m");
+    if (signal(SIGINT, catch_signal) == SIG_ERR)
+	syslog(LOG_INFO, "signal(SIGINT): %m");
+#ifdef SIGPWR
+    if (signal(SIGPWR, catch_signal) == SIG_ERR)
+	syslog(LOG_INFO, "signal(SIGPWR): %m");
+#endif
+    
+    for (i = max_fd = 0; i < sockets; i++)
+	max_fd = (socket[i].fd > max_fd) ? socket[i].fd : max_fd;
+
+    /* First select() call: poll, don't wait */
+    tv.tv_sec = tv.tv_usec = 0;
+
+    /* Wait for sockets in setup-pending state to settle */
+    if (one_pass || delay_fork)
+	wait_for_pending();
+    
+    for (pass = 0; ; pass++) {
+	FD_ZERO(&fds);
+	for (i = 0; i < sockets; i++)
+	    FD_SET(socket[i].fd, &fds);
+
+	while ((ret = select(max_fd+1, &fds, NULL, NULL,
+			     ((pass == 0) ? &tv : NULL))) < 0) {
+	    if (errno == EINTR) {
+		handle_signal();
+	    } else {
+		syslog(LOG_INFO, "select(): %m");
+		exit(EXIT_FAILURE);
+	    }
+	}
+
+	for (i = 0; i < sockets; i++) {
+	    if (!FD_ISSET(socket[i].fd, &fds))
+		continue;
+	    ret = read(socket[i].fd, &event, 4);
+	    if ((ret == -1) && (errno != EAGAIN))
+		syslog(LOG_INFO, "read(%d): %m\n", i);
+	    if (ret != 4)
+		continue;
+	    
+	    switch (event) {
+	    case CS_EVENT_CARD_REMOVAL:
+		socket[i].state &= ~(SOCKET_PRESENT | SOCKET_READY);
+		do_remove(i);
+		break;
+	    case CS_EVENT_EJECTION_REQUEST:
+		ret = do_check(i);
+		if (ret == 0) {
+		    socket[i].state &= ~(SOCKET_PRESENT | SOCKET_READY);
+		    do_remove(i);
+		}
+		write(socket[i].fd, &ret, 4);
+		break;
+	    case CS_EVENT_CARD_INSERTION:
+	    case CS_EVENT_INSERTION_REQUEST:
+		socket[i].state |= SOCKET_PRESENT;
+	    case CS_EVENT_CARD_RESET:
+		socket[i].state |= SOCKET_READY;
+		do_insert(i);
+		break;
+	    case CS_EVENT_RESET_PHYSICAL:
+		socket[i].state &= ~SOCKET_READY;
+		break;
+	    case CS_EVENT_PM_SUSPEND:
+		do_suspend(i);
+		break;
+	    case CS_EVENT_PM_RESUME:
+		do_resume(i);
+		break;
+	    }
+	    
+	}
+
+	if (one_pass)
+	    exit(EXIT_SUCCESS);
+	if (delay_fork) {
+	    fork_now();
+	    write_pid();
+	}
+	
+    } /* repeat */
+    return 0;
+}
Index: oldkernel/linux/pcmcia-cs-3.1.15/cardmgr/cardmgr.h
diff -u /dev/null linux/pcmcia-cs-3.1.15/cardmgr/cardmgr.h:1.1
--- /dev/null	Mon Jul 31 21:15:09 2000
+++ linux/pcmcia-cs-3.1.15/cardmgr/cardmgr.h	Fri Jul  7 16:34:58 2000
@@ -0,0 +1,107 @@
+/*
+ * cardmgr.h 1.34 1999/12/29 00:57:15
+ *
+ * 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@pcmcia.sourceforge.org>.  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 MAX_SOCKS	8
+#define MAX_BINDINGS	4
+#define MAX_MODULES	4
+
+typedef struct adjust_list_t {
+    adjust_t		adj;
+    struct adjust_list_t *next;
+} adjust_list_t;
+
+typedef struct func_ident_t {
+    u_char		funcid;
+} func_ident_t;
+
+typedef struct manfid_ident_t {
+    u_short		manf;
+    u_short		card;
+} manfid_ident_t;
+
+typedef struct vers_ident_t {
+    int			ns;
+    char		*pi[4];
+} vers_ident_t;
+
+typedef struct tuple_ident_t {
+    cisdata_t		code;
+    long		ofs;
+    char		*info;
+} tuple_ident_t;
+
+typedef struct device_info_t {
+    dev_info_t		dev_info;
+    int			needs_mtd;
+    int			modules;
+    char		*module[MAX_MODULES];
+    char		*opts[MAX_MODULES];
+    char		*class;
+    int			refs;
+    struct device_info_t *next;
+} device_info_t;
+
+typedef struct card_info_t {
+    char		*name;
+    enum {
+	VERS_1_IDENT=1, MANFID_IDENT, TUPLE_IDENT, FUNC_IDENT,
+	BLANK_IDENT, PCI_IDENT
+    } ident_type;
+    union {
+	vers_ident_t	vers;
+	manfid_ident_t	manfid;
+	tuple_ident_t	tuple;
+	func_ident_t	func;
+    } id;
+    int			bindings;
+    device_info_t	*device[MAX_BINDINGS];
+    int			dev_fn[MAX_BINDINGS];
+    char		*cis_file;
+    int			refs;
+    struct card_info_t	*next;
+} card_info_t;
+
+typedef struct mtd_ident_t {
+    char		*name;
+    enum {
+	JEDEC_MTD=1, DTYPE_MTD, DEFAULT_MTD
+    } mtd_type;
+    int			dtype, jedec_mfr, jedec_info;
+    char		*module, *opts;
+    int			refs;
+    struct mtd_ident_t	*next;
+} mtd_ident_t;
+    
+extern adjust_list_t	*root_adjust;
+extern device_info_t	*root_device;
+extern card_info_t	*blank_card;
+extern card_info_t	*root_card, *root_func;
+extern mtd_ident_t	*root_mtd, *default_mtd;
+
+int parse_configfile(char *fn);
Index: oldkernel/linux/pcmcia-cs-3.1.15/cardmgr/ide_info.c
diff -u /dev/null linux/pcmcia-cs-3.1.15/cardmgr/ide_info.c:1.1
--- /dev/null	Mon Jul 31 21:15:09 2000
+++ linux/pcmcia-cs-3.1.15/cardmgr/ide_info.c	Fri Jul  7 16:34:58 2000
@@ -0,0 +1,127 @@
+/*======================================================================
+
+    Utility to look up information about IDE devices
+
+    ide_info.c 1.11 2000/05/09 18:12:20
+
+    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@pcmcia.sourceforge.org>.  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 <sys/types.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <unistd.h>
+#include <string.h>
+#include <fcntl.h>
+#include <endian.h>
+#include <sys/ioctl.h>
+#include <dirent.h>
+
+#include <linux/major.h>
+#include <linux/hdreg.h>
+
+#if (__BYTE_ORDER == _BIG_ENDIAN)
+#define flip16(n)       (n)
+#else
+#define flip16(n) ((((n)&0x00ff)<<8) | (((n)&0xff00)>>8))
+#endif
+
+/*====================================================================*/
+
+#include <ctype.h>
+
+static void fix_string(char *s, int len)
+{
+    char *t = s, *x = s+len;
+
+    while (t < x) {
+	for (; t < x; t++)
+	    if (*t != ' ') break;
+	while (t < x) {
+	    *s++ = *t;
+	    if (*t++ == ' ') break;
+	}
+    }
+    if ((s > x-len) && (s[-1] == ' ')) s--;
+    if (s < t) *s = '\0';
+}
+
+
+static int read_proc_identify(char *dev, struct hd_driveid *id)
+{
+    char proc[] = "/proc/ide/hd#/identify";
+    char s[42];
+    int i;
+    
+    if ((strncmp(dev, "/dev/hd", 7) != 0) || (strlen(dev) != 8))
+	return -1;
+    proc[12] = dev[7];
+    if (access(proc, R_OK) == 0) {
+	FILE *f = fopen(proc, "r");
+	short *b = (short *)id;
+	while (fgets(s, 41, f)) {
+	    for (i = 0; i < 40; i += 5, b++) {
+		*b = flip16(strtol(s+i, NULL, 16));
+	    }
+	}
+	fclose(f);
+	fix_string(id->model, sizeof(id->model));
+	fix_string(id->fw_rev, sizeof(id->fw_rev));
+	fix_string(id->serial_no, sizeof(id->serial_no));
+	return 0;
+    }
+    return -1;
+}
+
+int main(int argc, char *argv[])
+{
+    int fd;
+    struct hd_driveid id;
+
+    if (argc != 2) {
+	fprintf(stderr, "usage: %s [device]\n", argv[0]);
+	exit(EXIT_FAILURE);
+    }
+
+    if (read_proc_identify(argv[1], &id) != 0) {
+	fd = open(argv[1], O_RDONLY);
+	if (fd < 0) {
+	    perror("open() failed");
+	    exit(1);
+	}
+	if (ioctl(fd, HDIO_GET_IDENTITY, &id) != 0) {
+	    perror("could not get IDE device info");
+	    exit(1);
+	}
+    }
+
+    printf("MODEL=\"%.40s\"\n", id.model);
+    printf("FW_REV=\"%.8s\"\n", id.fw_rev);
+    printf("SERIAL_NO=\"%.20s\"\n", id.serial_no);
+    exit(0);
+    return 0;
+}
Index: oldkernel/linux/pcmcia-cs-3.1.15/cardmgr/ifport.c
diff -u /dev/null linux/pcmcia-cs-3.1.15/cardmgr/ifport.c:1.1
--- /dev/null	Mon Jul 31 21:15:09 2000
+++ linux/pcmcia-cs-3.1.15/cardmgr/ifport.c	Fri Jul  7 16:34:58 2000
@@ -0,0 +1,115 @@
+/*======================================================================
+
+    Utility to select the transceiver type for a network device
+
+    ifport.c 1.12 1999/10/25 20:00: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@pcmcia.sourceforge.org>.  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 <sys/types.h>
+#include <sys/socket.h>
+#include <sys/ioctl.h>
+#include <net/if.h>
+#include <stdio.h>
+#include <errno.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+char *if_names[] = {
+    "Auto", "10baseT", "10base2", "AUI", "100baseT"
+};
+#define NR_NAMES (sizeof(if_names)/sizeof(char *))
+
+/*====================================================================*/
+
+static int sockets_open(void)
+{
+    int sock;
+    if ((sock = socket(AF_INET, SOCK_DGRAM, 0)) != -1)
+	return sock;
+    else if ((sock = socket(AF_IPX, SOCK_DGRAM, 0)) != -1)
+	return sock;
+    else if ((sock = socket(AF_AX25, SOCK_DGRAM, 0)) != -1)
+	return sock;
+    else
+	return socket(AF_APPLETALK, SOCK_DGRAM, 0);
+}
+
+/*====================================================================*/
+
+void usage(char *s)
+{
+    fprintf(stderr, "usage: %s interface "
+	    "[auto|10baseT|10base2|aui|100baseT|##]\n", s);
+    exit(1);
+}
+
+int main(int argc, char **argv)
+{
+    struct ifreq ifr;
+    int i, skfd;
+
+    if ((argc < 2) || (argc > 3))
+	usage(argv[0]);
+    skfd = sockets_open();
+    if (skfd == -1) {
+	perror("socket");
+	exit(1);
+    }
+    strcpy(ifr.ifr_name, argv[1]);
+    if (ioctl(skfd, SIOCGIFMAP, &ifr) < 0)
+	fprintf(stderr, "%s: unknown interface.\n", argv[1]);
+    else {
+	if (argc == 2) {
+	    printf("%s\t%d", argv[1], ifr.ifr_map.port);
+	    if (ifr.ifr_map.port < NR_NAMES)
+		printf(" (%s)\n", if_names[ifr.ifr_map.port]);
+	    else
+		printf("\n");
+	}
+	else {
+	    for (i = 0; i < NR_NAMES; i++)
+		if (strcasecmp(argv[2], if_names[i]) == 0)
+		    break;
+	    if (i < 5)
+		ifr.ifr_map.port = i;
+	    else {
+		char *s;
+		ifr.ifr_map.port = strtoul(argv[2], &s, 0);
+		if ((s == argv[2]) || (*s != '\0'))
+		    usage(argv[0]);
+	    }
+	    if (ioctl(skfd, SIOCSIFMAP, &ifr) < 0)
+		perror("ioctl");
+	}
+    }
+    close(skfd);
+    exit(0);
+    return 0;
+}
Index: oldkernel/linux/pcmcia-cs-3.1.15/cardmgr/ifuser.c
diff -u /dev/null linux/pcmcia-cs-3.1.15/cardmgr/ifuser.c:1.1
--- /dev/null	Mon Jul 31 21:15:09 2000
+++ linux/pcmcia-cs-3.1.15/cardmgr/ifuser.c	Fri Jul  7 16:34:58 2000
@@ -0,0 +1,166 @@
+/*======================================================================
+
+    This utility checks to see if any of a list of hosts or network
+    addresses are routed through a specified interface.  Destinations
+    may be specified either by IP address or by name.
+    
+    usage: ifuser [-v] interface [target ...]
+
+    The exit code is 0 if any host is using the specified interface,
+    and 1 if the interface is not in use (just like fuser).
+    
+    ifuser.c 1.14 1999/10/25 20:00:14
+
+    1998/10/24: Regis "HPReg" Duchesne <regis@via.ecp.fr>
+      . Added network names (/etc/networks) management
+      . Used u_int32_t instead of u_int
+      . Handled a malloc error
+
+    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@pcmcia.sourceforge.org>.  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.
+    Portions created by Regis "HPReg" Duchesne are Copyright (C) 1998
+    Regis "HPReg" Duchesne.  All Rights Reserved.
+
+======================================================================*/
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+#include <netdb.h>
+#include <errno.h>
+#include <ctype.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+
+typedef struct route_t {
+    u_int32_t		dest, mask;
+    int			match;
+    struct route_t	*next;
+} route_t;
+
+/*====================================================================*/
+
+static int resolv_name(char *s, u_int32_t *a)
+{
+    struct in_addr addr;
+    struct hostent *hp;
+    struct netent *np;
+    
+    if (inet_aton(s, &addr)) {
+	*a = (u_int32_t)ntohl(addr.s_addr);
+	return 0;
+    }
+    np = getnetbyname(s);
+    if (np) {
+	*a = (u_int32_t)np->n_net;
+	return 0;
+    }
+    hp = gethostbyname(s);
+    if (hp) {
+	*a = (u_int32_t)ntohl(*(u_int32_t *)hp->h_addr_list[0]);
+	return 0;
+    }
+    return -1;
+}
+
+/*====================================================================*/
+
+static void usage(char *s)
+{
+    fprintf(stderr, "usage: %s [-v] interface [target ...]\n", s);
+    exit(1);
+}
+
+int main(int argc, char *argv[])
+{
+    char *dev, s[129], dest[16], mask[16], iface[10];
+    route_t *r, *tbl, **tail;
+    int i, verbose = 0, busy = 0;
+    FILE *f;
+
+    i = 1;
+    if (argc < 2) usage(argv[0]);
+    if (strcmp(argv[1], "-v") == 0) {
+	verbose = 1; i++;
+    }
+    if ((*argv[i] == '-') || (argc < i+1)) usage(argv[0]);
+    dev = argv[i]; i++;
+    
+    /* Get routing table */
+    f = popen("netstat -nr", "r");
+    if (f == NULL) {
+	fprintf(stderr, "%s: could not get routing table: %s\n",
+		argv[0], strerror(errno));
+	return 2;
+    }
+    
+    do {
+	fgets(s, 128, f);
+    } while (!feof(f) && !isdigit(s[0]));
+    
+    tail = &tbl;
+    do {
+	r = malloc(sizeof(route_t));
+	if (r == NULL) {
+	    fprintf(stderr, "%s: out of memory\n", argv[0]);
+	    return 2;
+	}
+	sscanf(s, "%s %*s %s %*s %*s %*s %*s %s", dest, mask, iface);
+	resolv_name(dest, &r->dest);
+	resolv_name(mask, &r->mask);
+	r->match = (strcmp(iface, dev) == 0);
+	*tail = r; tail = &(r->next);
+    } while (fgets(s, 128, f) != NULL);
+    *tail = NULL;
+    pclose(f);
+
+    /* Check each host on command line */
+    for (; i < argc; i++) {
+	u_int32_t a;
+	if (resolv_name(argv[i], &a) != 0) {
+	    fprintf(stderr, "%s: lookup failed: %s\n",
+		    argv[0], argv[i]);
+	    continue;
+	}
+
+	for (r = tbl; r; r = r->next) {
+	    if ((a & r->mask) == r->dest) {
+		if (r->match) {
+		    if (verbose) {
+			if (!busy) printf("%s:", dev);
+			printf(" %s", argv[i]);
+		    }
+		    busy = 1;
+		}
+		break;
+	    }
+	}
+    }
+    
+    if (busy && verbose)
+	printf("\n");
+    return (!busy);
+}
Index: oldkernel/linux/pcmcia-cs-3.1.15/cardmgr/lex_config.c
diff -u /dev/null linux/pcmcia-cs-3.1.15/cardmgr/lex_config.c:1.1
--- /dev/null	Mon Jul 31 21:15:09 2000
+++ linux/pcmcia-cs-3.1.15/cardmgr/lex_config.c	Fri Jul  7 16:34:58 2000
@@ -0,0 +1,2052 @@
+/* A lexical scanner generated by flex */
+
+/* Scanner skeleton version:
+ * $Header: /src/cvs/valinux/oldkernel/linux/pcmcia-cs-3.1.15/cardmgr/lex_config.c,v 1.1 2000/07/07 23:34:58 sflory Exp $
+ */
+
+#define FLEX_SCANNER
+#define YY_FLEX_MAJOR_VERSION 2
+#define YY_FLEX_MINOR_VERSION 5
+
+#include <stdio.h>
+
+
+/* cfront 1.2 defines "c_plusplus" instead of "__cplusplus" */
+#ifdef c_plusplus
+#ifndef __cplusplus
+#define __cplusplus
+#endif
+#endif
+
+
+#ifdef __cplusplus
+
+#include <stdlib.h>
+#include <unistd.h>
+
+/* Use prototypes in function declarations. */
+#define YY_USE_PROTOS
+
+/* The "const" storage-class-modifier is valid. */
+#define YY_USE_CONST
+
+#else	/* ! __cplusplus */
+
+#if __STDC__
+
+#define YY_USE_PROTOS
+#define YY_USE_CONST
+
+#endif	/* __STDC__ */
+#endif	/* ! __cplusplus */
+
+#ifdef __TURBOC__
+ #pragma warn -rch
+ #pragma warn -use
+#include <io.h>
+#include <stdlib.h>
+#define YY_USE_CONST
+#define YY_USE_PROTOS
+#endif
+
+#ifdef YY_USE_CONST
+#define yyconst const
+#else
+#define yyconst
+#endif
+
+
+#ifdef YY_USE_PROTOS
+#define YY_PROTO(proto) proto
+#else
+#define YY_PROTO(proto) ()
+#endif
+
+/* Returned upon end-of-file. */
+#define YY_NULL 0
+
+/* Promotes a possibly negative, possibly signed char to an unsigned
+ * integer for use as an array index.  If the signed char is negative,
+ * we want to instead treat it as an 8-bit unsigned char, hence the
+ * double cast.
+ */
+#define YY_SC_TO_UI(c) ((unsigned int) (unsigned char) c)
+
+/* Enter a start condition.  This macro really ought to take a parameter,
+ * but we do it the disgusting crufty way forced on us by the ()-less
+ * definition of BEGIN.
+ */
+#define BEGIN yy_start = 1 + 2 *
+
+/* Translate the current start state into a value that can be later handed
+ * to BEGIN to return to the state.  The YYSTATE alias is for lex
+ * compatibility.
+ */
+#define YY_START ((yy_start - 1) / 2)
+#define YYSTATE YY_START
+
+/* Action number for EOF rule of a given start state. */
+#define YY_STATE_EOF(state) (YY_END_OF_BUFFER + state + 1)
+
+/* Special action meaning "start processing a new file". */
+#define YY_NEW_FILE yyrestart( yyin )
+
+#define YY_END_OF_BUFFER_CHAR 0
+
+/* Size of default input buffer. */
+#define YY_BUF_SIZE 16384
+
+typedef struct yy_buffer_state *YY_BUFFER_STATE;
+
+extern int yyleng;
+extern FILE *yyin, *yyout;
+
+#define EOB_ACT_CONTINUE_SCAN 0
+#define EOB_ACT_END_OF_FILE 1
+#define EOB_ACT_LAST_MATCH 2
+
+/* The funky do-while in the following #define is used to turn the definition
+ * int a single C statement (which needs a semi-colon terminator).  This
+ * avoids problems with code like:
+ *
+ * 	if ( condition_holds )
+ *		yyless( 5 );
+ *	else
+ *		do_something_else();
+ *
+ * Prior to using the do-while the compiler would get upset at the
+ * "else" because it interpreted the "if" statement as being all
+ * done when it reached the ';' after the yyless() call.
+ */
+
+/* Return all but the first 'n' matched characters back to the input stream. */
+
+#define yyless(n) \
+	do \
+		{ \
+		/* Undo effects of setting up yytext. */ \
+		*yy_cp = yy_hold_char; \
+		YY_RESTORE_YY_MORE_OFFSET \
+		yy_c_buf_p = yy_cp = yy_bp + n - YY_MORE_ADJ; \
+		YY_DO_BEFORE_ACTION; /* set up yytext again */ \
+		} \
+	while ( 0 )
+
+#define unput(c) yyunput( c, yytext_ptr )
+
+/* The following is because we cannot portably get our hands on size_t
+ * (without autoconf's help, which isn't available because we want
+ * flex-generated scanners to compile on their own).
+ */
+typedef unsigned int yy_size_t;
+
+
+struct yy_buffer_state
+	{
+	FILE *yy_input_file;
+
+	char *yy_ch_buf;		/* input buffer */
+	char *yy_buf_pos;		/* current position in input buffer */
+
+	/* Size of input buffer in bytes, not including room for EOB
+	 * characters.
+	 */
+	yy_size_t yy_buf_size;
+
+	/* Number of characters read into yy_ch_buf, not including EOB
+	 * characters.
+	 */
+	int yy_n_chars;
+
+	/* Whether we "own" the buffer - i.e., we know we created it,
+	 * and can realloc() it to grow it, and should free() it to
+	 * delete it.
+	 */
+	int yy_is_our_buffer;
+
+	/* Whether this is an "interactive" input source; if so, and
+	 * if we're using stdio for input, then we want to use getc()
+	 * instead of fread(), to make sure we stop fetching input after
+	 * each newline.
+	 */
+	int yy_is_interactive;
+
+	/* Whether we're considered to be at the beginning of a line.
+	 * If so, '^' rules will be active on the next match, otherwise
+	 * not.
+	 */
+	int yy_at_bol;
+
+	/* Whether to try to fill the input buffer when we reach the
+	 * end of it.
+	 */
+	int yy_fill_buffer;
+
+	int yy_buffer_status;
+#define YY_BUFFER_NEW 0
+#define YY_BUFFER_NORMAL 1
+	/* When an EOF's been seen but there's still some text to process
+	 * then we mark the buffer as YY_EOF_PENDING, to indicate that we
+	 * shouldn't try reading from the input source any more.  We might
+	 * still have a bunch of tokens to match, though, because of
+	 * possible backing-up.
+	 *
+	 * When we actually see the EOF, we change the status to "new"
+	 * (via yyrestart()), so that the user can continue scanning by
+	 * just pointing yyin at a new input file.
+	 */
+#define YY_BUFFER_EOF_PENDING 2
+	};
+
+static YY_BUFFER_STATE yy_current_buffer = 0;
+
+/* We provide macros for accessing buffer states in case in the
+ * future we want to put the buffer states in a more general
+ * "scanner state".
+ */
+#define YY_CURRENT_BUFFER yy_current_buffer
+
+
+/* yy_hold_char holds the character lost when yytext is formed. */
+static char yy_hold_char;
+
+static int yy_n_chars;		/* number of characters read into yy_ch_buf */
+
+
+int yyleng;
+
+/* Points to current character in buffer. */
+static char *yy_c_buf_p = (char *) 0;
+static int yy_init = 1;		/* whether we need to initialize */
+static int yy_start = 0;	/* start state number */
+
+/* Flag which is used to allow yywrap()'s to do buffer switches
+ * instead of setting up a fresh yyin.  A bit of a hack ...
+ */
+static int yy_did_buffer_switch_on_eof;
+
+void yyrestart YY_PROTO(( FILE *input_file ));
+
+void yy_switch_to_buffer YY_PROTO(( YY_BUFFER_STATE new_buffer ));
+void yy_load_buffer_state YY_PROTO(( void ));
+YY_BUFFER_STATE yy_create_buffer YY_PROTO(( FILE *file, int size ));
+void yy_delete_buffer YY_PROTO(( YY_BUFFER_STATE b ));
+void yy_init_buffer YY_PROTO(( YY_BUFFER_STATE b, FILE *file ));
+void yy_flush_buffer YY_PROTO(( YY_BUFFER_STATE b ));
+#define YY_FLUSH_BUFFER yy_flush_buffer( yy_current_buffer )
+
+YY_BUFFER_STATE yy_scan_buffer YY_PROTO(( char *base, yy_size_t size ));
+YY_BUFFER_STATE yy_scan_string YY_PROTO(( yyconst char *yy_str ));
+YY_BUFFER_STATE yy_scan_bytes YY_PROTO(( yyconst char *bytes, int len ));
+
+static void *yy_flex_alloc YY_PROTO(( yy_size_t ));
+static void *yy_flex_realloc YY_PROTO(( void *, yy_size_t ));
+static void yy_flex_free YY_PROTO(( void * ));
+
+#define yy_new_buffer yy_create_buffer
+
+#define yy_set_interactive(is_interactive) \
+	{ \
+	if ( ! yy_current_buffer ) \
+		yy_current_buffer = yy_create_buffer( yyin, YY_BUF_SIZE ); \
+	yy_current_buffer->yy_is_interactive = is_interactive; \
+	}
+
+#define yy_set_bol(at_bol) \
+	{ \
+	if ( ! yy_current_buffer ) \
+		yy_current_buffer = yy_create_buffer( yyin, YY_BUF_SIZE ); \
+	yy_current_buffer->yy_at_bol = at_bol; \
+	}
+
+#define YY_AT_BOL() (yy_current_buffer->yy_at_bol)
+
+typedef unsigned char YY_CHAR;
+FILE *yyin = (FILE *) 0, *yyout = (FILE *) 0;
+typedef int yy_state_type;
+extern char *yytext;
+#define yytext_ptr yytext
+
+static yy_state_type yy_get_previous_state YY_PROTO(( void ));
+static yy_state_type yy_try_NUL_trans YY_PROTO(( yy_state_type current_state ));
+static int yy_get_next_buffer YY_PROTO(( void ));
+static void yy_fatal_error YY_PROTO(( yyconst char msg[] ));
+
+/* Done after the current pattern has been matched and before the
+ * corresponding action - sets up yytext.
+ */
+#define YY_DO_BEFORE_ACTION \
+	yytext_ptr = yy_bp; \
+	yyleng = (int) (yy_cp - yy_bp); \
+	yy_hold_char = *yy_cp; \
+	*yy_cp = '\0'; \
+	yy_c_buf_p = yy_cp;
+
+#define YY_NUM_RULES 45
+#define YY_END_OF_BUFFER 46
+static yyconst short int yy_accept[247] =
+    {   0,
+        5,    5,    2,    2,   46,   44,    5,    4,    5,   44,
+        6,   41,   41,   44,   44,   44,   44,   44,   44,   44,
+       44,   44,   44,   44,   44,   44,   44,   44,   44,    3,
+        2,   45,    5,    5,    6,    0,   43,    0,    6,   41,
+        0,    0,    0,    0,    0,    0,    0,    0,    0,    0,
+        0,    0,    0,    0,    0,    0,    0,    0,    0,    0,
+        0,    0,    0,    0,    0,    0,    0,    0,   30,    0,
+        0,    0,    3,    2,    0,   43,    0,   42,    0,    0,
+        0,    0,    9,    0,    0,    0,    0,    0,    0,    0,
+        0,   18,    0,    0,    0,    0,   23,    0,    0,    0,
+
+        0,   26,    0,    0,    0,    0,    0,    0,    0,    0,
+        0,    0,    0,    8,   10,    0,    0,    0,    0,    0,
+        0,    0,    0,    0,    0,    0,    0,    0,    0,   25,
+        0,   27,    0,    0,    0,    0,    0,    0,    0,    0,
+        0,    0,   11,    0,    0,   14,    0,    0,    0,    0,
+       19,    0,    0,    0,    0,    0,    0,    0,    0,    0,
+        0,    0,   31,    0,    0,    0,    0,    0,   13,    0,
+        0,    0,    0,   20,   21,   22,    0,    0,    0,   28,
+        0,    0,    0,    1,    0,    0,    0,    0,   12,   15,
+        0,    0,   17,    0,    0,    0,    0,   29,    0,    0,
+
+       32,    0,    0,    0,    0,   16,    0,    0,    0,    0,
+        0,    0,    0,   39,    7,    0,    0,   24,    0,    0,
+        0,    0,    0,   36,    0,    0,    0,    0,    0,    0,
+       33,    0,    0,    0,   34,    0,    0,    0,   40,    0,
+        0,   35,   37,    0,   38,    0
+    } ;
+
+static yyconst int yy_ec[256] =
+    {   0,
+        1,    1,    1,    1,    1,    1,    1,    1,    2,    3,
+        1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
+        1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
+        1,    4,    1,    5,    6,    1,    1,    1,    1,    1,
+        1,    1,    1,    1,    1,    1,    1,    7,    8,    8,
+        8,    8,    8,    8,    8,    8,    8,    1,    6,    1,
+        1,    1,    1,    1,    9,    9,    9,    9,    9,    9,
+        1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
+        1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
+        1,   10,    1,    1,   11,    1,   12,   13,   14,   15,
+
+       16,   17,   18,    1,   19,   20,   21,   22,   23,   24,
+       25,   26,   27,   28,   29,   30,   31,   32,   33,   34,
+       35,    1,    1,    1,    1,    1,    1,    1,    1,    1,
+        1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
+        1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
+        1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
+        1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
+        1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
+        1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
+        1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
+
+        1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
+        1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
+        1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
+        1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
+        1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
+        1,    1,    1,    1,    1
+    } ;
+
+static yyconst int yy_meta[36] =
+    {   0,
+        1,    2,    3,    2,    1,    1,    4,    4,    4,    1,
+        1,    4,    4,    4,    4,    4,    4,    1,    1,    1,
+        1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
+        1,    1,    1,    1,    1
+    } ;
+
+static yyconst short int yy_base[253] =
+    {   0,
+        0,    0,   34,   37,  293,  294,   40,  294,   41,   41,
+        0,   41,   45,   31,  273,   42,   40,  257,   38,   34,
+      274,   47,  273,  262,   53,  271,   57,   35,   60,    0,
+       79,  294,   82,   83,    0,   83,  294,   87,    0,   87,
+        0,  263,  260,  260,  255,  253,  269,   74,  245,  265,
+      244,  253,  262,  248,  259,  249,  249,  256,  255,   80,
+      239,  240,  248,  238,   80,  236,  236,  232,  294,  236,
+      233,  245,    0,   97,   95,   97,  108,    0,  230,  234,
+      242,  241,  294,  226,  242,  234,  226,  229,  234,  235,
+      226,  294,  231,  229,  220,  213,  294,  228,  209,  212,
+
+      228,  294,  209,  219,  221,  217,  216,  206,  211,  203,
+      215,  219,  194,  294,  294,  199,  196,  212,  209,  193,
+      208,  192,  190,  206,  200,  190,  195,  187,  190,  294,
+      192,  294,  188,  184,  200,  198,  195,  192,  188,  181,
+      191,  181,  294,  181,  186,  294,  186,  189,  180,  183,
+      294,  182,  161,  179,  183,  165,  170,  167,  158,  177,
+      166,  171,  294,  161,  174,  172,  158,  152,  294,  165,
+      165,  154,  162,  294,  166,  294,  153,  154,  158,  294,
+      157,  157,  160,  294,  146,  157,  140,  136,  294,  294,
+      147,  141,  294,  150,  133,  151,  139,  294,  148,  133,
+
+      294,  143,  142,  127,  126,  294,  142,  138,  140,  140,
+      124,  124,  136,  294,  294,  126,  118,  294,  130,  118,
+      113,  114,  115,  294,  125,  127,  108,  116,   99,   87,
+      294,   90,   87,   86,  294,   96,   78,   74,  294,   75,
+       64,  294,  294,   46,  294,  294,  118,  122,  126,  130,
+      134,   64
+    } ;
+
+static yyconst short int yy_def[253] =
+    {   0,
+      246,    1,  247,  247,  246,  246,  246,  246,  246,  248,
+      249,  246,  246,  246,  246,  246,  246,  246,  246,  246,
+      246,  246,  246,  246,  246,  246,  246,  246,  246,  250,
+      246,  246,  246,  246,  249,  248,  246,  251,  249,  246,
+      252,  246,  246,  246,  246,  246,  246,  246,  246,  246,
+      246,  246,  246,  246,  246,  246,  246,  246,  246,  246,
+      246,  246,  246,  246,  246,  246,  246,  246,  246,  246,
+      246,  246,  250,  246,  248,  248,  251,  252,  246,  246,
+      246,  246,  246,  246,  246,  246,  246,  246,  246,  246,
+      246,  246,  246,  246,  246,  246,  246,  246,  246,  246,
+
+      246,  246,  246,  246,  246,  246,  246,  246,  246,  246,
+      246,  246,  246,  246,  246,  246,  246,  246,  246,  246,
+      246,  246,  246,  246,  246,  246,  246,  246,  246,  246,
+      246,  246,  246,  246,  246,  246,  246,  246,  246,  246,
+      246,  246,  246,  246,  246,  246,  246,  246,  246,  246,
+      246,  246,  246,  246,  246,  246,  246,  246,  246,  246,
+      246,  246,  246,  246,  246,  246,  246,  246,  246,  246,
+      246,  246,  246,  246,  246,  246,  246,  246,  246,  246,
+      246,  246,  246,  246,  246,  246,  246,  246,  246,  246,
+      246,  246,  246,  246,  246,  246,  246,  246,  246,  246,
+
+      246,  246,  246,  246,  246,  246,  246,  246,  246,  246,
+      246,  246,  246,  246,  246,  246,  246,  246,  246,  246,
+      246,  246,  246,  246,  246,  246,  246,  246,  246,  246,
+      246,  246,  246,  246,  246,  246,  246,  246,  246,  246,
+      246,  246,  246,  246,  246,    0,  246,  246,  246,  246,
+      246,  246
+    } ;
+
+static yyconst short int yy_nxt[330] =
+    {   0,
+        6,    7,    8,    9,   10,   11,   12,   13,    6,    6,
+        6,   14,   15,   16,   17,   18,   19,    6,   20,   21,
+        6,    6,   22,   23,   24,   25,    6,   26,   27,   28,
+        6,   29,    6,    6,    6,   31,   32,   31,   31,   32,
+       31,   33,   33,   33,   34,   37,   35,   40,   40,   42,
+       38,   40,   40,   45,   43,   48,   51,   53,   56,   69,
+       46,   54,   57,   47,   62,   70,   63,   78,   52,   49,
+       66,   58,   67,  245,   41,   71,   59,   64,   72,  244,
+       74,   68,   74,   33,   33,   33,   34,   37,   35,   36,
+       85,   76,   38,   40,   40,   98,   77,  104,   74,   37,
+
+       74,   37,  243,  242,   38,   86,   38,  241,  105,   99,
+       36,  240,   76,  239,  238,  237,  236,   77,   30,   30,
+       30,   30,   36,   36,   36,   36,   39,   39,  235,   39,
+       73,  234,  233,   73,   75,   75,   75,   75,  232,  231,
+      230,  229,  228,  227,  226,  225,  224,  223,  222,  221,
+      220,  219,  218,  217,  216,  215,  214,  213,  212,  211,
+      210,  209,  208,  207,  206,  205,  204,  203,  202,  201,
+      200,  199,  198,  197,  196,  195,  194,  193,  192,  191,
+      190,  189,  188,  187,  186,  185,  184,  183,  182,  181,
+      180,  179,  178,  177,  176,  175,  174,  173,  172,  171,
+
+      170,  169,  168,  167,  166,  165,  164,  163,  162,  161,
+      160,  159,  158,  157,  156,  155,  154,  153,  152,  151,
+      150,  149,  148,  147,  146,  145,  144,  143,  142,  141,
+      140,  139,  138,  137,  136,  135,  134,  133,  132,  131,
+      130,  129,  128,  127,  126,  125,  124,  123,  122,  121,
+      120,  119,  118,  117,  116,  115,  114,  113,  112,  111,
+      110,  109,  108,  107,  106,  103,  102,  101,  100,   97,
+       96,   95,   94,   93,   92,   91,   90,   89,   88,   87,
+       84,   83,   82,   81,   80,   79,   65,   61,   60,   55,
+       50,   44,  246,    5,  246,  246,  246,  246,  246,  246,
+
+      246,  246,  246,  246,  246,  246,  246,  246,  246,  246,
+      246,  246,  246,  246,  246,  246,  246,  246,  246,  246,
+      246,  246,  246,  246,  246,  246,  246,  246,  246
+    } ;
+
+static yyconst short int yy_chk[330] =
+    {   0,
+        1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
+        1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
+        1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
+        1,    1,    1,    1,    1,    3,    3,    3,    4,    4,
+        4,    7,    9,    7,    9,   10,    9,   12,   12,   14,
+       10,   13,   13,   16,   14,   17,   19,   20,   22,   28,
+       16,   20,   22,   16,   25,   28,   25,  252,   19,   17,
+       27,   22,   27,  244,   12,   29,   22,   25,   29,  241,
+       31,   27,   31,   33,   34,   33,   34,   36,   34,   38,
+       48,   38,   36,   40,   40,   60,   38,   65,   74,   75,
+
+       74,   76,  240,  238,   75,   48,   76,  237,   65,   60,
+       77,  236,   77,  234,  233,  232,  230,   77,  247,  247,
+      247,  247,  248,  248,  248,  248,  249,  249,  229,  249,
+      250,  228,  227,  250,  251,  251,  251,  251,  226,  225,
+      223,  222,  221,  220,  219,  217,  216,  213,  212,  211,
+      210,  209,  208,  207,  205,  204,  203,  202,  200,  199,
+      197,  196,  195,  194,  192,  191,  188,  187,  186,  185,
+      183,  182,  181,  179,  178,  177,  175,  173,  172,  171,
+      170,  168,  167,  166,  165,  164,  162,  161,  160,  159,
+      158,  157,  156,  155,  154,  153,  152,  150,  149,  148,
+
+      147,  145,  144,  142,  141,  140,  139,  138,  137,  136,
+      135,  134,  133,  131,  129,  128,  127,  126,  125,  124,
+      123,  122,  121,  120,  119,  118,  117,  116,  113,  112,
+      111,  110,  109,  108,  107,  106,  105,  104,  103,  101,
+      100,   99,   98,   96,   95,   94,   93,   91,   90,   89,
+       88,   87,   86,   85,   84,   82,   81,   80,   79,   72,
+       71,   70,   68,   67,   66,   64,   63,   62,   61,   59,
+       58,   57,   56,   55,   54,   53,   52,   51,   50,   49,
+       47,   46,   45,   44,   43,   42,   26,   24,   23,   21,
+       18,   15,    5,  246,  246,  246,  246,  246,  246,  246,
+
+      246,  246,  246,  246,  246,  246,  246,  246,  246,  246,
+      246,  246,  246,  246,  246,  246,  246,  246,  246,  246,
+      246,  246,  246,  246,  246,  246,  246,  246,  246
+    } ;
+
+static yy_state_type yy_last_accepting_state;
+static char *yy_last_accepting_cpos;
+
+/* The intent behind this definition is that it'll catch
+ * any uses of REJECT which flex missed.
+ */
+#define REJECT reject_used_but_not_detected
+#define yymore() yymore_used_but_not_detected
+#define YY_MORE_ADJ 0
+#define YY_RESTORE_YY_MORE_OFFSET
+char *yytext;
+#line 1 "lex_config.l"
+#define INITIAL 0
+/* Special state for handling include files */
+#define src 1
+
+#line 5 "lex_config.l"
+/*
+ * lex_config.l 1.38 1999/12/29 00:57: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@pcmcia.sourceforge.org>.  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.
+ */
+
+#undef src
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+#include <syslog.h>
+#include <glob.h>
+#define src 1
+
+#include <pcmcia/cs_types.h>
+#include <pcmcia/cs.h>
+
+#include "yacc_config.h"
+
+/* For assembling nice error messages */
+char *current_file;
+int current_lineno;
+
+static int lex_number(char *s);
+static int lex_string(char *s);
+static void do_source(char *fn);
+static int do_eof(void);
+
+
+/* Macros after this point can all be overridden by user definitions in
+ * section 1.
+ */
+
+#ifndef YY_SKIP_YYWRAP
+#ifdef __cplusplus
+extern "C" int yywrap YY_PROTO(( void ));
+#else
+extern int yywrap YY_PROTO(( void ));
+#endif
+#endif
+
+#ifndef YY_NO_UNPUT
+static void yyunput YY_PROTO(( int c, char *buf_ptr ));
+#endif
+
+#ifndef yytext_ptr
+static void yy_flex_strncpy YY_PROTO(( char *, yyconst char *, int ));
+#endif
+
+#ifdef YY_NEED_STRLEN
+static int yy_flex_strlen YY_PROTO(( yyconst char * ));
+#endif
+
+#ifndef YY_NO_INPUT
+#ifdef __cplusplus
+static int yyinput YY_PROTO(( void ));
+#else
+static int input YY_PROTO(( void ));
+#endif
+#endif
+
+#if YY_STACK_USED
+static int yy_start_stack_ptr = 0;
+static int yy_start_stack_depth = 0;
+static int *yy_start_stack = 0;
+#ifndef YY_NO_PUSH_STATE
+static void yy_push_state YY_PROTO(( int new_state ));
+#endif
+#ifndef YY_NO_POP_STATE
+static void yy_pop_state YY_PROTO(( void ));
+#endif
+#ifndef YY_NO_TOP_STATE
+static int yy_top_state YY_PROTO(( void ));
+#endif
+
+#else
+#define YY_NO_PUSH_STATE 1
+#define YY_NO_POP_STATE 1
+#define YY_NO_TOP_STATE 1
+#endif
+
+#ifdef YY_MALLOC_DECL
+YY_MALLOC_DECL
+#else
+#if __STDC__
+#ifndef __cplusplus
+#include <stdlib.h>
+#endif
+#else
+/* Just try to get by without declaring the routines.  This will fail
+ * miserably on non-ANSI systems for which sizeof(size_t) != sizeof(int)
+ * or sizeof(void*) != sizeof(int).
+ */
+#endif
+#endif
+
+/* Amount of stuff to slurp up with each read. */
+#ifndef YY_READ_BUF_SIZE
+#define YY_READ_BUF_SIZE 8192
+#endif
+
+/* Copy whatever the last rule matched to the standard output. */
+
+#ifndef ECHO
+/* This used to be an fputs(), but since the string might contain NUL's,
+ * we now use fwrite().
+ */
+#define ECHO (void) fwrite( yytext, yyleng, 1, yyout )
+#endif
+
+/* Gets input and stuffs it into "buf".  number of characters read, or YY_NULL,
+ * is returned in "result".
+ */
+#ifndef YY_INPUT
+#define YY_INPUT(buf,result,max_size) \
+	if ( yy_current_buffer->yy_is_interactive ) \
+		{ \
+		int c = '*', n; \
+		for ( n = 0; n < max_size && \
+			     (c = getc( yyin )) != EOF && c != '\n'; ++n ) \
+			buf[n] = (char) c; \
+		if ( c == '\n' ) \
+			buf[n++] = (char) c; \
+		if ( c == EOF && ferror( yyin ) ) \
+			YY_FATAL_ERROR( "input in flex scanner failed" ); \
+		result = n; \
+		} \
+	else if ( ((result = fread( buf, 1, max_size, yyin )) == 0) \
+		  && ferror( yyin ) ) \
+		YY_FATAL_ERROR( "input in flex scanner failed" );
+#endif
+
+/* No semi-colon after return; correct usage is to write "yyterminate();" -
+ * we don't want an extra ';' after the "return" because that will cause
+ * some compilers to complain about unreachable statements.
+ */
+#ifndef yyterminate
+#define yyterminate() return YY_NULL
+#endif
+
+/* Number of entries by which start-condition stack grows. */
+#ifndef YY_START_STACK_INCR
+#define YY_START_STACK_INCR 25
+#endif
+
+/* Report a fatal error. */
+#ifndef YY_FATAL_ERROR
+#define YY_FATAL_ERROR(msg) yy_fatal_error( msg )
+#endif
+
+/* Default declaration of generated scanner - a define so the user can
+ * easily add parameters.
+ */
+#ifndef YY_DECL
+#define YY_DECL int yylex YY_PROTO(( void ))
+#endif
+
+/* Code executed at the beginning of each rule, after yytext and yyleng
+ * have been set up.
+ */
+#ifndef YY_USER_ACTION
+#define YY_USER_ACTION
+#endif
+
+/* Code executed at the end of each rule. */
+#ifndef YY_BREAK
+#define YY_BREAK break;
+#endif
+
+#define YY_RULE_SETUP \
+	YY_USER_ACTION
+
+YY_DECL
+	{
+	register yy_state_type yy_current_state;
+	register char *yy_cp, *yy_bp;
+	register int yy_act;
+
+#line 63 "lex_config.l"
+
+
+
+	if ( yy_init )
+		{
+		yy_init = 0;
+
+#ifdef YY_USER_INIT
+		YY_USER_INIT;
+#endif
+
+		if ( ! yy_start )
+			yy_start = 1;	/* first start state */
+
+		if ( ! yyin )
+			yyin = stdin;
+
+		if ( ! yyout )
+			yyout = stdout;
+
+		if ( ! yy_current_buffer )
+			yy_current_buffer =
+				yy_create_buffer( yyin, YY_BUF_SIZE );
+
+		yy_load_buffer_state();
+		}
+
+	while ( 1 )		/* loops until end-of-file is reached */
+		{
+		yy_cp = yy_c_buf_p;
+
+		/* Support of yytext. */
+		*yy_cp = yy_hold_char;
+
+		/* yy_bp points to the position in yy_ch_buf of the start of
+		 * the current run.
+		 */
+		yy_bp = yy_cp;
+
+		yy_current_state = yy_start;
+yy_match:
+		do
+			{
+			register YY_CHAR yy_c = yy_ec[YY_SC_TO_UI(*yy_cp)];
+			if ( yy_accept[yy_current_state] )
+				{
+				yy_last_accepting_state = yy_current_state;
+				yy_last_accepting_cpos = yy_cp;
+				}
+			while ( yy_chk[yy_base[yy_current_state] + yy_c] != yy_current_state )
+				{
+				yy_current_state = (int) yy_def[yy_current_state];
+				if ( yy_current_state >= 247 )
+					yy_c = yy_meta[(unsigned int) yy_c];
+				}
+			yy_current_state = yy_nxt[yy_base[yy_current_state] + (unsigned int) yy_c];
+			++yy_cp;
+			}
+		while ( yy_base[yy_current_state] != 294 );
+
+yy_find_action:
+		yy_act = yy_accept[yy_current_state];
+		if ( yy_act == 0 )
+			{ /* have to back up */
+			yy_cp = yy_last_accepting_cpos;
+			yy_current_state = yy_last_accepting_state;
+			yy_act = yy_accept[yy_current_state];
+			}
+
+		YY_DO_BEFORE_ACTION;
+
+
+do_action:	/* This label is used only to access EOF actions. */
+
+
+		switch ( yy_act )
+	{ /* beginning of action switch */
+			case 0: /* must back up */
+			/* undo the effects of YY_DO_BEFORE_ACTION */
+			*yy_cp = yy_hold_char;
+			yy_cp = yy_last_accepting_cpos;
+			yy_current_state = yy_last_accepting_state;
+			goto yy_find_action;
+
+case 1:
+YY_RULE_SETUP
+#line 65 "lex_config.l"
+BEGIN(src);
+	YY_BREAK
+case 2:
+YY_RULE_SETUP
+#line 66 "lex_config.l"
+/* skip */ ;
+	YY_BREAK
+case 3:
+YY_RULE_SETUP
+#line 67 "lex_config.l"
+do_source(yytext); BEGIN(INITIAL);
+	YY_BREAK
+case YY_STATE_EOF(INITIAL):
+case YY_STATE_EOF(src):
+#line 68 "lex_config.l"
+if (do_eof()) yyterminate();
+	YY_BREAK
+case 4:
+YY_RULE_SETUP
+#line 70 "lex_config.l"
+current_lineno++;
+	YY_BREAK
+case 5:
+YY_RULE_SETUP
+#line 71 "lex_config.l"
+/* skip */ ;
+	YY_BREAK
+case 6:
+YY_RULE_SETUP
+#line 72 "lex_config.l"
+/* skip */ ;
+	YY_BREAK
+case 7:
+YY_RULE_SETUP
+#line 74 "lex_config.l"
+return ANONYMOUS;
+	YY_BREAK
+case 8:
+YY_RULE_SETUP
+#line 75 "lex_config.l"
+return BIND;
+	YY_BREAK
+case 9:
+YY_RULE_SETUP
+#line 76 "lex_config.l"
+return CIS;
+	YY_BREAK
+case 10:
+YY_RULE_SETUP
+#line 77 "lex_config.l"
+return CARD;
+	YY_BREAK
+case 11:
+YY_RULE_SETUP
+#line 78 "lex_config.l"
+return CLASS;
+	YY_BREAK
+case 12:
+YY_RULE_SETUP
+#line 79 "lex_config.l"
+return DEFAULT;
+	YY_BREAK
+case 13:
+YY_RULE_SETUP
+#line 80 "lex_config.l"
+return DEVICE;
+	YY_BREAK
+case 14:
+YY_RULE_SETUP
+#line 81 "lex_config.l"
+return DTYPE;
+	YY_BREAK
+case 15:
+YY_RULE_SETUP
+#line 82 "lex_config.l"
+return EXCLUDE;
+	YY_BREAK
+case 16:
+YY_RULE_SETUP
+#line 83 "lex_config.l"
+return FUNCTION;
+	YY_BREAK
+case 17:
+YY_RULE_SETUP
+#line 84 "lex_config.l"
+return INCLUDE;
+	YY_BREAK
+case 18:
+YY_RULE_SETUP
+#line 85 "lex_config.l"
+return IRQ_NO;
+	YY_BREAK
+case 19:
+YY_RULE_SETUP
+#line 86 "lex_config.l"
+return JEDEC;
+	YY_BREAK
+case 20:
+YY_RULE_SETUP
+#line 87 "lex_config.l"
+return MANFID;
+	YY_BREAK
+case 21:
+YY_RULE_SETUP
+#line 88 "lex_config.l"
+return MEMORY;
+	YY_BREAK
+case 22:
+YY_RULE_SETUP
+#line 89 "lex_config.l"
+return MODULE;
+	YY_BREAK
+case 23:
+YY_RULE_SETUP
+#line 90 "lex_config.l"
+return MTD;
+	YY_BREAK
+case 24:
+YY_RULE_SETUP
+#line 91 "lex_config.l"
+return NEEDS_MTD;
+	YY_BREAK
+case 25:
+YY_RULE_SETUP
+#line 92 "lex_config.l"
+return OPTS;
+	YY_BREAK
+case 26:
+YY_RULE_SETUP
+#line 93 "lex_config.l"
+return PCI;
+	YY_BREAK
+case 27:
+YY_RULE_SETUP
+#line 94 "lex_config.l"
+return PORT;
+	YY_BREAK
+case 28:
+YY_RULE_SETUP
+#line 95 "lex_config.l"
+return REGION;
+	YY_BREAK
+case 29:
+YY_RULE_SETUP
+#line 96 "lex_config.l"
+return RESERVE;
+	YY_BREAK
+case 30:
+YY_RULE_SETUP
+#line 97 "lex_config.l"
+return TO;
+	YY_BREAK
+case 31:
+YY_RULE_SETUP
+#line 98 "lex_config.l"
+return TUPLE;
+	YY_BREAK
+case 32:
+YY_RULE_SETUP
+#line 99 "lex_config.l"
+return VERSION;
+	YY_BREAK
+case 33:
+YY_RULE_SETUP
+#line 101 "lex_config.l"
+return lex_number("1");
+	YY_BREAK
+case 34:
+YY_RULE_SETUP
+#line 102 "lex_config.l"
+return lex_number("2");
+	YY_BREAK
+case 35:
+YY_RULE_SETUP
+#line 103 "lex_config.l"
+return lex_number("3");
+	YY_BREAK
+case 36:
+YY_RULE_SETUP
+#line 104 "lex_config.l"
+return lex_number("4");
+	YY_BREAK
+case 37:
+YY_RULE_SETUP
+#line 105 "lex_config.l"
+return lex_number("5");
+	YY_BREAK
+case 38:
+YY_RULE_SETUP
+#line 106 "lex_config.l"
+return lex_number("6");
+	YY_BREAK
+case 39:
+YY_RULE_SETUP
+#line 107 "lex_config.l"
+return lex_number("7");
+	YY_BREAK
+case 40:
+YY_RULE_SETUP
+#line 108 "lex_config.l"
+return lex_number("8");
+	YY_BREAK
+case 41:
+YY_RULE_SETUP
+#line 110 "lex_config.l"
+return lex_number(yytext);
+	YY_BREAK
+case 42:
+YY_RULE_SETUP
+#line 112 "lex_config.l"
+return lex_number(yytext);
+	YY_BREAK
+case 43:
+YY_RULE_SETUP
+#line 114 "lex_config.l"
+return lex_string(yytext);
+	YY_BREAK
+case 44:
+YY_RULE_SETUP
+#line 116 "lex_config.l"
+return yytext[0];
+	YY_BREAK
+case 45:
+YY_RULE_SETUP
+#line 118 "lex_config.l"
+ECHO;
+	YY_BREAK
+
+	case YY_END_OF_BUFFER:
+		{
+		/* Amount of text matched not including the EOB char. */
+		int yy_amount_of_matched_text = (int) (yy_cp - yytext_ptr) - 1;
+
+		/* Undo the effects of YY_DO_BEFORE_ACTION. */
+		*yy_cp = yy_hold_char;
+		YY_RESTORE_YY_MORE_OFFSET
+
+		if ( yy_current_buffer->yy_buffer_status == YY_BUFFER_NEW )
+			{
+			/* We're scanning a new file or input source.  It's
+			 * possible that this happened because the user
+			 * just pointed yyin at a new source and called
+			 * yylex().  If so, then we have to assure
+			 * consistency between yy_current_buffer and our
+			 * globals.  Here is the right place to do so, because
+			 * this is the first action (other than possibly a
+			 * back-up) that will match for the new input source.
+			 */
+			yy_n_chars = yy_current_buffer->yy_n_chars;
+			yy_current_buffer->yy_input_file = yyin;
+			yy_current_buffer->yy_buffer_status = YY_BUFFER_NORMAL;
+			}
+
+		/* Note that here we test for yy_c_buf_p "<=" to the position
+		 * of the first EOB in the buffer, since yy_c_buf_p will
+		 * already have been incremented past the NUL character
+		 * (since all states make transitions on EOB to the
+		 * end-of-buffer state).  Contrast this with the test
+		 * in input().
+		 */
+		if ( yy_c_buf_p <= &yy_current_buffer->yy_ch_buf[yy_n_chars] )
+			{ /* This was really a NUL. */
+			yy_state_type yy_next_state;
+
+			yy_c_buf_p = yytext_ptr + yy_amount_of_matched_text;
+
+			yy_current_state = yy_get_previous_state();
+
+			/* Okay, we're now positioned to make the NUL
+			 * transition.  We couldn't have
+			 * yy_get_previous_state() go ahead and do it
+			 * for us because it doesn't know how to deal
+			 * with the possibility of jamming (and we don't
+			 * want to build jamming into it because then it
+			 * will run more slowly).
+			 */
+
+			yy_next_state = yy_try_NUL_trans( yy_current_state );
+
+			yy_bp = yytext_ptr + YY_MORE_ADJ;
+
+			if ( yy_next_state )
+				{
+				/* Consume the NUL. */
+				yy_cp = ++yy_c_buf_p;
+				yy_current_state = yy_next_state;
+				goto yy_match;
+				}
+
+			else
+				{
+				yy_cp = yy_c_buf_p;
+				goto yy_find_action;
+				}
+			}
+
+		else switch ( yy_get_next_buffer() )
+			{
+			case EOB_ACT_END_OF_FILE:
+				{
+				yy_did_buffer_switch_on_eof = 0;
+
+				if ( yywrap() )
+					{
+					/* Note: because we've taken care in
+					 * yy_get_next_buffer() to have set up
+					 * yytext, we can now set up
+					 * yy_c_buf_p so that if some total
+					 * hoser (like flex itself) wants to
+					 * call the scanner after we return the
+					 * YY_NULL, it'll still work - another
+					 * YY_NULL will get returned.
+					 */
+					yy_c_buf_p = yytext_ptr + YY_MORE_ADJ;
+
+					yy_act = YY_STATE_EOF(YY_START);
+					goto do_action;
+					}
+
+				else
+					{
+					if ( ! yy_did_buffer_switch_on_eof )
+						YY_NEW_FILE;
+					}
+				break;
+				}
+
+			case EOB_ACT_CONTINUE_SCAN:
+				yy_c_buf_p =
+					yytext_ptr + yy_amount_of_matched_text;
+
+				yy_current_state = yy_get_previous_state();
+
+				yy_cp = yy_c_buf_p;
+				yy_bp = yytext_ptr + YY_MORE_ADJ;
+				goto yy_match;
+
+			case EOB_ACT_LAST_MATCH:
+				yy_c_buf_p =
+				&yy_current_buffer->yy_ch_buf[yy_n_chars];
+
+				yy_current_state = yy_get_previous_state();
+
+				yy_cp = yy_c_buf_p;
+				yy_bp = yytext_ptr + YY_MORE_ADJ;
+				goto yy_find_action;
+			}
+		break;
+		}
+
+	default:
+		YY_FATAL_ERROR(
+			"fatal flex scanner internal error--no action found" );
+	} /* end of action switch */
+		} /* end of scanning one token */
+	} /* end of yylex */
+
+
+/* yy_get_next_buffer - try to read in a new buffer
+ *
+ * Returns a code representing an action:
+ *	EOB_ACT_LAST_MATCH -
+ *	EOB_ACT_CONTINUE_SCAN - continue scanning from current position
+ *	EOB_ACT_END_OF_FILE - end of file
+ */
+
+static int yy_get_next_buffer()
+	{
+	register char *dest = yy_current_buffer->yy_ch_buf;
+	register char *source = yytext_ptr;
+	register int number_to_move, i;
+	int ret_val;
+
+	if ( yy_c_buf_p > &yy_current_buffer->yy_ch_buf[yy_n_chars + 1] )
+		YY_FATAL_ERROR(
+		"fatal flex scanner internal error--end of buffer missed" );
+
+	if ( yy_current_buffer->yy_fill_buffer == 0 )
+		{ /* Don't try to fill the buffer, so this is an EOF. */
+		if ( yy_c_buf_p - yytext_ptr - YY_MORE_ADJ == 1 )
+			{
+			/* We matched a single character, the EOB, so
+			 * treat this as a final EOF.
+			 */
+			return EOB_ACT_END_OF_FILE;
+			}
+
+		else
+			{
+			/* We matched some text prior to the EOB, first
+			 * process it.
+			 */
+			return EOB_ACT_LAST_MATCH;
+			}
+		}
+
+	/* Try to read more data. */
+
+	/* First move last chars to start of buffer. */
+	number_to_move = (int) (yy_c_buf_p - yytext_ptr) - 1;
+
+	for ( i = 0; i < number_to_move; ++i )
+		*(dest++) = *(source++);
+
+	if ( yy_current_buffer->yy_buffer_status == YY_BUFFER_EOF_PENDING )
+		/* don't do the read, it's not guaranteed to return an EOF,
+		 * just force an EOF
+		 */
+		yy_current_buffer->yy_n_chars = yy_n_chars = 0;
+
+	else
+		{
+		int num_to_read =
+			yy_current_buffer->yy_buf_size - number_to_move - 1;
+
+		while ( num_to_read <= 0 )
+			{ /* Not enough room in the buffer - grow it. */
+#ifdef YY_USES_REJECT
+			YY_FATAL_ERROR(
+"input buffer overflow, can't enlarge buffer because scanner uses REJECT" );
+#else
+
+			/* just a shorter name for the current buffer */
+			YY_BUFFER_STATE b = yy_current_buffer;
+
+			int yy_c_buf_p_offset =
+				(int) (yy_c_buf_p - b->yy_ch_buf);
+
+			if ( b->yy_is_our_buffer )
+				{
+				int new_size = b->yy_buf_size * 2;
+
+				if ( new_size <= 0 )
+					b->yy_buf_size += b->yy_buf_size / 8;
+				else
+					b->yy_buf_size *= 2;
+
+				b->yy_ch_buf = (char *)
+					/* Include room in for 2 EOB chars. */
+					yy_flex_realloc( (void *) b->yy_ch_buf,
+							 b->yy_buf_size + 2 );
+				}
+			else
+				/* Can't grow it, we don't own it. */
+				b->yy_ch_buf = 0;
+
+			if ( ! b->yy_ch_buf )
+				YY_FATAL_ERROR(
+				"fatal error - scanner input buffer overflow" );
+
+			yy_c_buf_p = &b->yy_ch_buf[yy_c_buf_p_offset];
+
+			num_to_read = yy_current_buffer->yy_buf_size -
+						number_to_move - 1;
+#endif
+			}
+
+		if ( num_to_read > YY_READ_BUF_SIZE )
+			num_to_read = YY_READ_BUF_SIZE;
+
+		/* Read in more data. */
+		YY_INPUT( (&yy_current_buffer->yy_ch_buf[number_to_move]),
+			yy_n_chars, num_to_read );
+
+		yy_current_buffer->yy_n_chars = yy_n_chars;
+		}
+
+	if ( yy_n_chars == 0 )
+		{
+		if ( number_to_move == YY_MORE_ADJ )
+			{
+			ret_val = EOB_ACT_END_OF_FILE;
+			yyrestart( yyin );
+			}
+
+		else
+			{
+			ret_val = EOB_ACT_LAST_MATCH;
+			yy_current_buffer->yy_buffer_status =
+				YY_BUFFER_EOF_PENDING;
+			}
+		}
+
+	else
+		ret_val = EOB_ACT_CONTINUE_SCAN;
+
+	yy_n_chars += number_to_move;
+	yy_current_buffer->yy_ch_buf[yy_n_chars] = YY_END_OF_BUFFER_CHAR;
+	yy_current_buffer->yy_ch_buf[yy_n_chars + 1] = YY_END_OF_BUFFER_CHAR;
+
+	yytext_ptr = &yy_current_buffer->yy_ch_buf[0];
+
+	return ret_val;
+	}
+
+
+/* yy_get_previous_state - get the state just before the EOB char was reached */
+
+static yy_state_type yy_get_previous_state()
+	{
+	register yy_state_type yy_current_state;
+	register char *yy_cp;
+
+	yy_current_state = yy_start;
+
+	for ( yy_cp = yytext_ptr + YY_MORE_ADJ; yy_cp < yy_c_buf_p; ++yy_cp )
+		{
+		register YY_CHAR yy_c = (*yy_cp ? yy_ec[YY_SC_TO_UI(*yy_cp)] : 1);
+		if ( yy_accept[yy_current_state] )
+			{
+			yy_last_accepting_state = yy_current_state;
+			yy_last_accepting_cpos = yy_cp;
+			}
+		while ( yy_chk[yy_base[yy_current_state] + yy_c] != yy_current_state )
+			{
+			yy_current_state = (int) yy_def[yy_current_state];
+			if ( yy_current_state >= 247 )
+				yy_c = yy_meta[(unsigned int) yy_c];
+			}
+		yy_current_state = yy_nxt[yy_base[yy_current_state] + (unsigned int) yy_c];
+		}
+
+	return yy_current_state;
+	}
+
+
+/* yy_try_NUL_trans - try to make a transition on the NUL character
+ *
+ * synopsis
+ *	next_state = yy_try_NUL_trans( current_state );
+ */
+
+#ifdef YY_USE_PROTOS
+static yy_state_type yy_try_NUL_trans( yy_state_type yy_current_state )
+#else
+static yy_state_type yy_try_NUL_trans( yy_current_state )
+yy_state_type yy_current_state;
+#endif
+	{
+	register int yy_is_jam;
+	register char *yy_cp = yy_c_buf_p;
+
+	register YY_CHAR yy_c = 1;
+	if ( yy_accept[yy_current_state] )
+		{
+		yy_last_accepting_state = yy_current_state;
+		yy_last_accepting_cpos = yy_cp;
+		}
+	while ( yy_chk[yy_base[yy_current_state] + yy_c] != yy_current_state )
+		{
+		yy_current_state = (int) yy_def[yy_current_state];
+		if ( yy_current_state >= 247 )
+			yy_c = yy_meta[(unsigned int) yy_c];
+		}
+	yy_current_state = yy_nxt[yy_base[yy_current_state] + (unsigned int) yy_c];
+	yy_is_jam = (yy_current_state == 246);
+
+	return yy_is_jam ? 0 : yy_current_state;
+	}
+
+
+#ifndef YY_NO_UNPUT
+#ifdef YY_USE_PROTOS
+static void yyunput( int c, register char *yy_bp )
+#else
+static void yyunput( c, yy_bp )
+int c;
+register char *yy_bp;
+#endif
+	{
+	register char *yy_cp = yy_c_buf_p;
+
+	/* undo effects of setting up yytext */
+	*yy_cp = yy_hold_char;
+
+	if ( yy_cp < yy_current_buffer->yy_ch_buf + 2 )
+		{ /* need to shift things up to make room */
+		/* +2 for EOB chars. */
+		register int number_to_move = yy_n_chars + 2;
+		register char *dest = &yy_current_buffer->yy_ch_buf[
+					yy_current_buffer->yy_buf_size + 2];
+		register char *source =
+				&yy_current_buffer->yy_ch_buf[number_to_move];
+
+		while ( source > yy_current_buffer->yy_ch_buf )
+			*--dest = *--source;
+
+		yy_cp += (int) (dest - source);
+		yy_bp += (int) (dest - source);
+		yy_current_buffer->yy_n_chars =
+			yy_n_chars = yy_current_buffer->yy_buf_size;
+
+		if ( yy_cp < yy_current_buffer->yy_ch_buf + 2 )
+			YY_FATAL_ERROR( "flex scanner push-back overflow" );
+		}
+
+	*--yy_cp = (char) c;
+
+
+	yytext_ptr = yy_bp;
+	yy_hold_char = *yy_cp;
+	yy_c_buf_p = yy_cp;
+	}
+#endif	/* ifndef YY_NO_UNPUT */
+
+
+#ifdef __cplusplus
+static int yyinput()
+#else
+static int input()
+#endif
+	{
+	int c;
+
+	*yy_c_buf_p = yy_hold_char;
+
+	if ( *yy_c_buf_p == YY_END_OF_BUFFER_CHAR )
+		{
+		/* yy_c_buf_p now points to the character we want to return.
+		 * If this occurs *before* the EOB characters, then it's a
+		 * valid NUL; if not, then we've hit the end of the buffer.
+		 */
+		if ( yy_c_buf_p < &yy_current_buffer->yy_ch_buf[yy_n_chars] )
+			/* This was really a NUL. */
+			*yy_c_buf_p = '\0';
+
+		else
+			{ /* need more input */
+			int offset = yy_c_buf_p - yytext_ptr;
+			++yy_c_buf_p;
+
+			switch ( yy_get_next_buffer() )
+				{
+				case EOB_ACT_LAST_MATCH:
+					/* This happens because yy_g_n_b()
+					 * sees that we've accumulated a
+					 * token and flags that we need to
+					 * try matching the token before
+					 * proceeding.  But for input(),
+					 * there's no matching to consider.
+					 * So convert the EOB_ACT_LAST_MATCH
+					 * to EOB_ACT_END_OF_FILE.
+					 */
+
+					/* Reset buffer status. */
+					yyrestart( yyin );
+
+					/* fall through */
+
+				case EOB_ACT_END_OF_FILE:
+					{
+					if ( yywrap() )
+						return EOF;
+
+					if ( ! yy_did_buffer_switch_on_eof )
+						YY_NEW_FILE;
+#ifdef __cplusplus
+					return yyinput();
+#else
+					return input();
+#endif
+					}
+
+				case EOB_ACT_CONTINUE_SCAN:
+					yy_c_buf_p = yytext_ptr + offset;
+					break;
+				}
+			}
+		}
+
+	c = *(unsigned char *) yy_c_buf_p;	/* cast for 8-bit char's */
+	*yy_c_buf_p = '\0';	/* preserve yytext */
+	yy_hold_char = *++yy_c_buf_p;
+
+
+	return c;
+	}
+
+
+#ifdef YY_USE_PROTOS
+void yyrestart( FILE *input_file )
+#else
+void yyrestart( input_file )
+FILE *input_file;
+#endif
+	{
+	if ( ! yy_current_buffer )
+		yy_current_buffer = yy_create_buffer( yyin, YY_BUF_SIZE );
+
+	yy_init_buffer( yy_current_buffer, input_file );
+	yy_load_buffer_state();
+	}
+
+
+#ifdef YY_USE_PROTOS
+void yy_switch_to_buffer( YY_BUFFER_STATE new_buffer )
+#else
+void yy_switch_to_buffer( new_buffer )
+YY_BUFFER_STATE new_buffer;
+#endif
+	{
+	if ( yy_current_buffer == new_buffer )
+		return;
+
+	if ( yy_current_buffer )
+		{
+		/* Flush out information for old buffer. */
+		*yy_c_buf_p = yy_hold_char;
+		yy_current_buffer->yy_buf_pos = yy_c_buf_p;
+		yy_current_buffer->yy_n_chars = yy_n_chars;
+		}
+
+	yy_current_buffer = new_buffer;
+	yy_load_buffer_state();
+
+	/* We don't actually know whether we did this switch during
+	 * EOF (yywrap()) processing, but the only time this flag
+	 * is looked at is after yywrap() is called, so it's safe
+	 * to go ahead and always set it.
+	 */
+	yy_did_buffer_switch_on_eof = 1;
+	}
+
+
+#ifdef YY_USE_PROTOS
+void yy_load_buffer_state( void )
+#else
+void yy_load_buffer_state()
+#endif
+	{
+	yy_n_chars = yy_current_buffer->yy_n_chars;
+	yytext_ptr = yy_c_buf_p = yy_current_buffer->yy_buf_pos;
+	yyin = yy_current_buffer->yy_input_file;
+	yy_hold_char = *yy_c_buf_p;
+	}
+
+
+#ifdef YY_USE_PROTOS
+YY_BUFFER_STATE yy_create_buffer( FILE *file, int size )
+#else
+YY_BUFFER_STATE yy_create_buffer( file, size )
+FILE *file;
+int size;
+#endif
+	{
+	YY_BUFFER_STATE b;
+
+	b = (YY_BUFFER_STATE) yy_flex_alloc( sizeof( struct yy_buffer_state ) );
+	if ( ! b )
+		YY_FATAL_ERROR( "out of dynamic memory in yy_create_buffer()" );
+
+	b->yy_buf_size = size;
+
+	/* yy_ch_buf has to be 2 characters longer than the size given because
+	 * we need to put in 2 end-of-buffer characters.
+	 */
+	b->yy_ch_buf = (char *) yy_flex_alloc( b->yy_buf_size + 2 );
+	if ( ! b->yy_ch_buf )
+		YY_FATAL_ERROR( "out of dynamic memory in yy_create_buffer()" );
+
+	b->yy_is_our_buffer = 1;
+
+	yy_init_buffer( b, file );
+
+	return b;
+	}
+
+
+#ifdef YY_USE_PROTOS
+void yy_delete_buffer( YY_BUFFER_STATE b )
+#else
+void yy_delete_buffer( b )
+YY_BUFFER_STATE b;
+#endif
+	{
+	if ( ! b )
+		return;
+
+	if ( b == yy_current_buffer )
+		yy_current_buffer = (YY_BUFFER_STATE) 0;
+
+	if ( b->yy_is_our_buffer )
+		yy_flex_free( (void *) b->yy_ch_buf );
+
+	yy_flex_free( (void *) b );
+	}
+
+
+#ifndef YY_ALWAYS_INTERACTIVE
+#ifndef YY_NEVER_INTERACTIVE
+extern int isatty YY_PROTO(( int ));
+#endif
+#endif
+
+#ifdef YY_USE_PROTOS
+void yy_init_buffer( YY_BUFFER_STATE b, FILE *file )
+#else
+void yy_init_buffer( b, file )
+YY_BUFFER_STATE b;
+FILE *file;
+#endif
+
+
+	{
+	yy_flush_buffer( b );
+
+	b->yy_input_file = file;
+	b->yy_fill_buffer = 1;
+
+#if YY_ALWAYS_INTERACTIVE
+	b->yy_is_interactive = 1;
+#else
+#if YY_NEVER_INTERACTIVE
+	b->yy_is_interactive = 0;
+#else
+	b->yy_is_interactive = file ? (isatty( fileno(file) ) > 0) : 0;
+#endif
+#endif
+	}
+
+
+#ifdef YY_USE_PROTOS
+void yy_flush_buffer( YY_BUFFER_STATE b )
+#else
+void yy_flush_buffer( b )
+YY_BUFFER_STATE b;
+#endif
+
+	{
+	if ( ! b )
+		return;
+
+	b->yy_n_chars = 0;
+
+	/* We always need two end-of-buffer characters.  The first causes
+	 * a transition to the end-of-buffer state.  The second causes
+	 * a jam in that state.
+	 */
+	b->yy_ch_buf[0] = YY_END_OF_BUFFER_CHAR;
+	b->yy_ch_buf[1] = YY_END_OF_BUFFER_CHAR;
+
+	b->yy_buf_pos = &b->yy_ch_buf[0];
+
+	b->yy_at_bol = 1;
+	b->yy_buffer_status = YY_BUFFER_NEW;
+
+	if ( b == yy_current_buffer )
+		yy_load_buffer_state();
+	}
+
+
+#ifndef YY_NO_SCAN_BUFFER
+#ifdef YY_USE_PROTOS
+YY_BUFFER_STATE yy_scan_buffer( char *base, yy_size_t size )
+#else
+YY_BUFFER_STATE yy_scan_buffer( base, size )
+char *base;
+yy_size_t size;
+#endif
+	{
+	YY_BUFFER_STATE b;
+
+	if ( size < 2 ||
+	     base[size-2] != YY_END_OF_BUFFER_CHAR ||
+	     base[size-1] != YY_END_OF_BUFFER_CHAR )
+		/* They forgot to leave room for the EOB's. */
+		return 0;
+
+	b = (YY_BUFFER_STATE) yy_flex_alloc( sizeof( struct yy_buffer_state ) );
+	if ( ! b )
+		YY_FATAL_ERROR( "out of dynamic memory in yy_scan_buffer()" );
+
+	b->yy_buf_size = size - 2;	/* "- 2" to take care of EOB's */
+	b->yy_buf_pos = b->yy_ch_buf = base;
+	b->yy_is_our_buffer = 0;
+	b->yy_input_file = 0;
+	b->yy_n_chars = b->yy_buf_size;
+	b->yy_is_interactive = 0;
+	b->yy_at_bol = 1;
+	b->yy_fill_buffer = 0;
+	b->yy_buffer_status = YY_BUFFER_NEW;
+
+	yy_switch_to_buffer( b );
+
+	return b;
+	}
+#endif
+
+
+#ifndef YY_NO_SCAN_STRING
+#ifdef YY_USE_PROTOS
+YY_BUFFER_STATE yy_scan_string( yyconst char *yy_str )
+#else
+YY_BUFFER_STATE yy_scan_string( yy_str )
+yyconst char *yy_str;
+#endif
+	{
+	int len;
+	for ( len = 0; yy_str[len]; ++len )
+		;
+
+	return yy_scan_bytes( yy_str, len );
+	}
+#endif
+
+
+#ifndef YY_NO_SCAN_BYTES
+#ifdef YY_USE_PROTOS
+YY_BUFFER_STATE yy_scan_bytes( yyconst char *bytes, int len )
+#else
+YY_BUFFER_STATE yy_scan_bytes( bytes, len )
+yyconst char *bytes;
+int len;
+#endif
+	{
+	YY_BUFFER_STATE b;
+	char *buf;
+	yy_size_t n;
+	int i;
+
+	/* Get memory for full buffer, including space for trailing EOB's. */
+	n = len + 2;
+	buf = (char *) yy_flex_alloc( n );
+	if ( ! buf )
+		YY_FATAL_ERROR( "out of dynamic memory in yy_scan_bytes()" );
+
+	for ( i = 0; i < len; ++i )
+		buf[i] = bytes[i];
+
+	buf[len] = buf[len+1] = YY_END_OF_BUFFER_CHAR;
+
+	b = yy_scan_buffer( buf, n );
+	if ( ! b )
+		YY_FATAL_ERROR( "bad buffer in yy_scan_bytes()" );
+
+	/* It's okay to grow etc. this buffer, and we should throw it
+	 * away when we're done.
+	 */
+	b->yy_is_our_buffer = 1;
+
+	return b;
+	}
+#endif
+
+
+#ifndef YY_NO_PUSH_STATE
+#ifdef YY_USE_PROTOS
+static void yy_push_state( int new_state )
+#else
+static void yy_push_state( new_state )
+int new_state;
+#endif
+	{
+	if ( yy_start_stack_ptr >= yy_start_stack_depth )
+		{
+		yy_size_t new_size;
+
+		yy_start_stack_depth += YY_START_STACK_INCR;
+		new_size = yy_start_stack_depth * sizeof( int );
+
+		if ( ! yy_start_stack )
+			yy_start_stack = (int *) yy_flex_alloc( new_size );
+
+		else
+			yy_start_stack = (int *) yy_flex_realloc(
+					(void *) yy_start_stack, new_size );
+
+		if ( ! yy_start_stack )
+			YY_FATAL_ERROR(
+			"out of memory expanding start-condition stack" );
+		}
+
+	yy_start_stack[yy_start_stack_ptr++] = YY_START;
+
+	BEGIN(new_state);
+	}
+#endif
+
+
+#ifndef YY_NO_POP_STATE
+static void yy_pop_state()
+	{
+	if ( --yy_start_stack_ptr < 0 )
+		YY_FATAL_ERROR( "start-condition stack underflow" );
+
+	BEGIN(yy_start_stack[yy_start_stack_ptr]);
+	}
+#endif
+
+
+#ifndef YY_NO_TOP_STATE
+static int yy_top_state()
+	{
+	return yy_start_stack[yy_start_stack_ptr - 1];
+	}
+#endif
+
+#ifndef YY_EXIT_FAILURE
+#define YY_EXIT_FAILURE 2
+#endif
+
+#ifdef YY_USE_PROTOS
+static void yy_fatal_error( yyconst char msg[] )
+#else
+static void yy_fatal_error( msg )
+char msg[];
+#endif
+	{
+	(void) fprintf( stderr, "%s\n", msg );
+	exit( YY_EXIT_FAILURE );
+	}
+
+
+
+/* Redefine yyless() so it works in section 3 code. */
+
+#undef yyless
+#define yyless(n) \
+	do \
+		{ \
+		/* Undo effects of setting up yytext. */ \
+		yytext[yyleng] = yy_hold_char; \
+		yy_c_buf_p = yytext + n; \
+		yy_hold_char = *yy_c_buf_p; \
+		*yy_c_buf_p = '\0'; \
+		yyleng = n; \
+		} \
+	while ( 0 )
+
+
+/* Internal utility routines. */
+
+#ifndef yytext_ptr
+#ifdef YY_USE_PROTOS
+static void yy_flex_strncpy( char *s1, yyconst char *s2, int n )
+#else
+static void yy_flex_strncpy( s1, s2, n )
+char *s1;
+yyconst char *s2;
+int n;
+#endif
+	{
+	register int i;
+	for ( i = 0; i < n; ++i )
+		s1[i] = s2[i];
+	}
+#endif
+
+#ifdef YY_NEED_STRLEN
+#ifdef YY_USE_PROTOS
+static int yy_flex_strlen( yyconst char *s )
+#else
+static int yy_flex_strlen( s )
+yyconst char *s;
+#endif
+	{
+	register int n;
+	for ( n = 0; s[n]; ++n )
+		;
+
+	return n;
+	}
+#endif
+
+
+#ifdef YY_USE_PROTOS
+static void *yy_flex_alloc( yy_size_t size )
+#else
+static void *yy_flex_alloc( size )
+yy_size_t size;
+#endif
+	{
+	return (void *) malloc( size );
+	}
+
+#ifdef YY_USE_PROTOS
+static void *yy_flex_realloc( void *ptr, yy_size_t size )
+#else
+static void *yy_flex_realloc( ptr, size )
+void *ptr;
+yy_size_t size;
+#endif
+	{
+	/* The cast to (char *) in the following accommodates both
+	 * implementations that use char* generic pointers, and those
+	 * that use void* generic pointers.  It works with the latter
+	 * because both ANSI C and C++ allow castless assignment from
+	 * any pointer type to void*, and deal with argument conversions
+	 * as though doing an assignment.
+	 */
+	return (void *) realloc( (char *) ptr, size );
+	}
+
+#ifdef YY_USE_PROTOS
+static void yy_flex_free( void *ptr )
+#else
+static void yy_flex_free( ptr )
+void *ptr;
+#endif
+	{
+	free( ptr );
+	}
+
+#if YY_MAIN
+int main()
+	{
+	yylex();
+	return 0;
+	}
+#endif
+#line 118 "lex_config.l"
+
+
+#ifndef yywrap
+int yywrap() { return 1; }
+#endif
+
+/*======================================================================
+
+    Stuff to parse basic data types
+
+======================================================================*/
+
+static int lex_number(char *s)
+{
+    yylval.num = strtoul(s, NULL, 0);
+    return NUMBER;
+}
+
+static int lex_string(char *s)
+{
+    int n = strlen(s);
+    yylval.str = malloc(n-1);
+    strncpy(yylval.str, s+1, n-2);
+    yylval.str[n-2] = '\0';
+    return STRING;
+}
+
+/*======================================================================
+
+    Code to support nesting of configuration files
+
+======================================================================*/
+
+#define MAX_SOURCE_DEPTH 4
+struct source_stack {
+    YY_BUFFER_STATE	buffer;
+    char		*filename;
+    int			lineno, fileno;
+    FILE		*file;
+    glob_t		glob;
+} source_stack[MAX_SOURCE_DEPTH];
+static int source_stack_ptr = 0;
+static int parse_env = 0;
+
+static int get_glob(void)
+{
+    struct source_stack *s = &source_stack[source_stack_ptr];
+    while (s->fileno < s->glob.gl_pathc) {
+	char *fn = s->glob.gl_pathv[s->fileno];
+	s->file = fopen(fn, "r");
+	if (s->file == NULL) {
+	    if (strpbrk(fn, "?*[") == NULL)
+		syslog(LOG_INFO, "could not open '%s': %m", fn);
+	    s->fileno++;
+	} else {
+	    current_lineno = 1;
+	    current_file = strdup(fn);
+	    yy_switch_to_buffer(yy_create_buffer(s->file, YY_BUF_SIZE));
+	    source_stack_ptr++;
+	    s->fileno++;
+	    return 0;
+	}
+    }
+    return -1;
+}
+
+static void do_source(char *fn)
+{
+    struct source_stack *s = &source_stack[source_stack_ptr];
+
+    if (source_stack_ptr >= MAX_SOURCE_DEPTH) {
+	syslog(LOG_INFO, "source depth limit exceeded");
+	return;
+    }
+    glob(fn, GLOB_NOCHECK, NULL, &s->glob);
+    s->fileno = 0;
+    s->buffer = YY_CURRENT_BUFFER;
+    s->lineno = current_lineno;
+    s->filename = current_file;
+    get_glob();
+}
+
+static int do_eof(void)
+{
+    struct source_stack *s = &source_stack[--source_stack_ptr];
+    if (source_stack_ptr < 0) {
+	if (parse_env == 0) {
+	    char *t = getenv("PCMCIA_OPTS");
+	    if (t == NULL) return -1;
+	    parse_env = 1;
+	    source_stack_ptr = 0;
+	    current_file = "PCMCIA_OPTS";
+	    current_lineno = 1;
+	    yy_scan_string(t);
+	    return 0;
+	} else
+	    return -1;
+    }
+    fclose(s->file);
+    free(current_file);
+    yy_delete_buffer(YY_CURRENT_BUFFER);
+    if (get_glob() != 0) {
+	yy_switch_to_buffer(s->buffer);
+	current_lineno = s->lineno;
+	current_file = s->filename;
+    }
+    return 0;
+}
+
+/*======================================================================
+
+    The main entry point... returns -1 if the file can't be accessed.
+
+======================================================================*/
+
+int parse_configfile(char *fn)
+{
+    FILE *f;
+    
+    f = fopen(fn, "r");
+    if (!f) {
+	syslog(LOG_INFO, "could not open '%s': %m", fn);
+	return -1;
+    }
+    current_lineno = 1;
+    current_file = fn;
+    source_stack_ptr = 0;
+    yyrestart(f);
+    yyparse();
+    fclose(f);
+    return 0;
+}
+
Index: oldkernel/linux/pcmcia-cs-3.1.15/cardmgr/lex_config.l
diff -u /dev/null linux/pcmcia-cs-3.1.15/cardmgr/lex_config.l:1.1
--- /dev/null	Mon Jul 31 21:15:10 2000
+++ linux/pcmcia-cs-3.1.15/cardmgr/lex_config.l	Fri Jul  7 16:34:58 2000
@@ -0,0 +1,250 @@
+/* Special state for handling include files */
+%x src
+
+%{
+/*
+ * lex_config.l 1.38 1999/12/29 00:57: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@pcmcia.sourceforge.org>.  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.
+ */
+
+#undef src
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+#include <syslog.h>
+#include <glob.h>
+#define src 1
+
+#include <pcmcia/cs_types.h>
+#include <pcmcia/cs.h>
+
+#include "yacc_config.h"
+
+/* For assembling nice error messages */
+char *current_file;
+int current_lineno;
+
+static int lex_number(char *s);
+static int lex_string(char *s);
+static void do_source(char *fn);
+static int do_eof(void);
+
+%}
+
+int	[0-9]+
+hex	0x[0-9a-fA-F]+
+str	\"([^"]|\\.)*\"
+
+%%
+
+source		BEGIN(src);
+<src>[ \t]*	/* skip */ ;
+<src>[^ \t\n]+	do_source(yytext); BEGIN(INITIAL);
+<<EOF>>		if (do_eof()) yyterminate();
+
+\n		current_lineno++;
+[ \t]*		/* skip */ ;
+[ ]*[#;].*	/* skip */ ;
+
+anonymous	return ANONYMOUS;
+bind		return BIND;
+cis		return CIS;
+card		return CARD;
+class		return CLASS;
+default		return DEFAULT;
+device		return DEVICE;
+dtype		return DTYPE;
+exclude		return EXCLUDE;
+function	return FUNCTION;
+include		return INCLUDE;
+irq		return IRQ_NO;
+jedec		return JEDEC;
+manfid		return MANFID;
+memory		return MEMORY;
+module		return MODULE;
+mtd		return MTD;
+needs_mtd	return NEEDS_MTD;
+opts		return OPTS;
+pci		return PCI;
+port		return PORT;
+region		return REGION;
+reserve		return RESERVE;
+to		return TO;
+tuple		return TUPLE;
+version		return VERSION;
+
+memory_card	return lex_number("1");
+serial_port	return lex_number("2");
+parallel_port	return lex_number("3");
+fixed_disk	return lex_number("4");
+video_adapter	return lex_number("5");
+network_adapter	return lex_number("6");
+aims_card	return lex_number("7");
+scsi_adapter	return lex_number("8");
+
+{int}		return lex_number(yytext);
+
+{hex}		return lex_number(yytext);
+
+{str}		return lex_string(yytext);
+
+.		return yytext[0];
+
+%%
+
+#ifndef yywrap
+int yywrap() { return 1; }
+#endif
+
+/*======================================================================
+
+    Stuff to parse basic data types
+
+======================================================================*/
+
+static int lex_number(char *s)
+{
+    yylval.num = strtoul(s, NULL, 0);
+    return NUMBER;
+}
+
+static int lex_string(char *s)
+{
+    int n = strlen(s);
+    yylval.str = malloc(n-1);
+    strncpy(yylval.str, s+1, n-2);
+    yylval.str[n-2] = '\0';
+    return STRING;
+}
+
+/*======================================================================
+
+    Code to support nesting of configuration files
+
+======================================================================*/
+
+#define MAX_SOURCE_DEPTH 4
+struct source_stack {
+    YY_BUFFER_STATE	buffer;
+    char		*filename;
+    int			lineno, fileno;
+    FILE		*file;
+    glob_t		glob;
+} source_stack[MAX_SOURCE_DEPTH];
+static int source_stack_ptr = 0;
+static int parse_env = 0;
+
+static int get_glob(void)
+{
+    struct source_stack *s = &source_stack[source_stack_ptr];
+    while (s->fileno < s->glob.gl_pathc) {
+	char *fn = s->glob.gl_pathv[s->fileno];
+	s->file = fopen(fn, "r");
+	if (s->file == NULL) {
+	    if (strpbrk(fn, "?*[") == NULL)
+		syslog(LOG_INFO, "could not open '%s': %m", fn);
+	    s->fileno++;
+	} else {
+	    current_lineno = 1;
+	    current_file = strdup(fn);
+	    yy_switch_to_buffer(yy_create_buffer(s->file, YY_BUF_SIZE));
+	    source_stack_ptr++;
+	    s->fileno++;
+	    return 0;
+	}
+    }
+    return -1;
+}
+
+static void do_source(char *fn)
+{
+    struct source_stack *s = &source_stack[source_stack_ptr];
+
+    if (source_stack_ptr >= MAX_SOURCE_DEPTH) {
+	syslog(LOG_INFO, "source depth limit exceeded");
+	return;
+    }
+    glob(fn, GLOB_NOCHECK, NULL, &s->glob);
+    s->fileno = 0;
+    s->buffer = YY_CURRENT_BUFFER;
+    s->lineno = current_lineno;
+    s->filename = current_file;
+    get_glob();
+}
+
+static int do_eof(void)
+{
+    struct source_stack *s = &source_stack[--source_stack_ptr];
+    if (source_stack_ptr < 0) {
+	if (parse_env == 0) {
+	    char *t = getenv("PCMCIA_OPTS");
+	    if (t == NULL) return -1;
+	    parse_env = 1;
+	    source_stack_ptr = 0;
+	    current_file = "PCMCIA_OPTS";
+	    current_lineno = 1;
+	    yy_scan_string(t);
+	    return 0;
+	} else
+	    return -1;
+    }
+    fclose(s->file);
+    free(current_file);
+    yy_delete_buffer(YY_CURRENT_BUFFER);
+    if (get_glob() != 0) {
+	yy_switch_to_buffer(s->buffer);
+	current_lineno = s->lineno;
+	current_file = s->filename;
+    }
+    return 0;
+}
+
+/*======================================================================
+
+    The main entry point... returns -1 if the file can't be accessed.
+
+======================================================================*/
+
+int parse_configfile(char *fn)
+{
+    FILE *f;
+    
+    f = fopen(fn, "r");
+    if (!f) {
+	syslog(LOG_INFO, "could not open '%s': %m", fn);
+	return -1;
+    }
+    current_lineno = 1;
+    current_file = fn;
+    source_stack_ptr = 0;
+    yyrestart(f);
+    yyparse();
+    fclose(f);
+    return 0;
+}
+
Index: oldkernel/linux/pcmcia-cs-3.1.15/cardmgr/pcinitrd
diff -u /dev/null linux/pcmcia-cs-3.1.15/cardmgr/pcinitrd:1.1
--- /dev/null	Mon Jul 31 21:15:10 2000
+++ linux/pcmcia-cs-3.1.15/cardmgr/pcinitrd	Fri Jul  7 16:34:58 2000
@@ -0,0 +1,227 @@
+#!/bin/sh
+#
+# Utility for constructing PCMCIA initrd boot images
+#
+# Copyright (C) 1999 David A. Hinds -- dhinds@pcmcia.sourceforge.org
+#
+# pcinitrd 1.21 1999/10/25 20:02:14
+#
+RELEASE=""
+ALL=""
+SIZE=1440
+MODULES="pcmcia/pcmcia_core.o pcmcia/ds.o"
+
+# Things to install when "all" is selected
+SOCK="i82365.o tcic.o"
+BLK="ide_cs.o pcmem_cs.o aha152x_cs.o fdomain_cs.o qlogic_cs.o"
+MEM="ftl_cs.o memory_cs.o sram_mtd.o iflash2_mtd.o iflash2+_mtd.o"
+
+usage()
+{
+    echo "usage: $0 [-v] [-a|-all] [-u|--update] [-r|--kernel=kernel-release]" >&2
+    echo "       [-s|--size=image-size] [-d|--dir=root-dir] <initrd-image> [modules ...]" >&2
+    exit 1
+}
+
+while [ $# -gt 0 ] ; do
+    case $1 in
+    -a|--all)
+	ALL=y
+	;;
+    -d)
+	ROOT=$2 ; shift
+	;;
+    --dir=*)
+	ROOT=`echo $1 | sed -e 's/^--dir=//'`
+	;;
+    -r)
+	KERNEL=$2 ; shift
+	;;
+    --release=*)
+	KERNEL=`echo $1 | sed -e 's/^--kernel=//'`
+	;;
+    -s)
+	SIZE=$2 ; shift
+	;;
+    --size=*)
+	SIZE=`echo $1 | sed -e 's/^--size=//'`
+	;;
+    -u|--update)
+	UPDATE=y
+	;;
+    -v|--verbose)
+	VERBOSE=--verbose
+	;;
+    -*)
+	usage
+	exit 1
+	;;
+    *)
+	break
+	;;
+    esac
+    shift
+done
+
+if [ "$KERNEL" = "" ] ; then
+    KERNEL=`uname -r`
+fi
+[ "$VERBOSE" ] && echo "Using version $KERNEL modules"
+MODDIR=$ROOT/lib/modules/$KERNEL
+
+if [ $# -lt 1 ] ; then usage ; fi
+TARGET=$1 ; shift
+if [ "$ALL" = "y" ] ; then
+    for MOD in $SOCK $BLK $MEM ; do
+	if [ -f $MODDIR/pcmcia/$MOD ] ; then
+	    MODULES="$MODULES pcmcia/$MOD"
+	fi
+    done
+fi
+
+BIN="bin/mount bin/umount sbin/insmod sbin/cardmgr"
+LIB=`ls $ROOT/lib/libc.so.? | sort | tail -1`
+ETC="/etc/ld.so.cache /etc/pcmcia/config /etc/pcmcia/config.opts"
+DEV="/dev/console /dev/null /dev/ram /dev/tty1 /dev/tty2 /dev/tty3 /dev/tty4"
+LF=`file -bL $LIB`
+for F in $* ; do
+    if [ -f $MODDIR/$F ] ; then
+	MODULES="$MODULES $F"
+    elif [ -x $ROOT/$F ] ; then
+	FT=`file -bL $ROOT/$F`
+	if [ "$FT" = "$LF" ] ; then
+	    LIB="$LIB $F"
+	else
+	    BIN="$BIN $F"
+	fi
+    elif [ -b $ROOT/$F -o -c $ROOT/$F ] ; then
+	DEV="$DEV $F"
+    elif [ -f $ROOT/$F ] ; then
+	ETC="$ETC $F"
+    else
+	echo "$F not found." 1>&2
+	exit 1
+    fi
+done
+
+fail()
+{
+    umount $VERBOSE $MNT
+    rmdir $MNT
+    exit 1
+}
+trap fail SIGTERM SIGINT
+
+strip_cp()
+{
+    if [ -d $3 ] ; then
+	DEST=$3/`basename $2`
+    else
+	DEST=$3
+    fi
+    strip $1 $VERBOSE -o $DEST $2 | sed -e 's/([^ ]*)//g' || fail
+}
+
+MNT=$ROOT/tmp/initrd.mnt-$$
+mkdir $VERBOSE $MNT || exit 1
+
+if [ "$UPDATE" = "y" ] ; then
+    if [ -b $TARGET ] ; then
+	mount $VERBOSE -t ext2 $TARGET $MNT || fail
+    else
+	mount $VERBOSE -t ext2 -o loop $TARGET $MNT || fail
+    fi
+    strip_cp --strip-all $ROOT/sbin/cardmgr $MNT/sbin || fail
+    CD=`pwd` ; cd $MNT
+    for DIR in block misc fs net pcmcia ; do
+	for MOD in $DIR/*.o ; do
+	    strip_cp --discard-all $ROOT/lib/modules/$MOD $DIR || fail
+	done
+    done
+    cd $CD
+    umount $VERBOSE $MNT
+    rmdir $MNT
+    exit 0
+fi
+
+[ "$VERBOSE" ] && echo "Creating filesystem on $TARGET"
+if [ -b $TARGET ] ; then
+    mke2fs $TARGET $SIZE > /dev/null || fail
+    mount $VERBOSE -t ext2 $TARGET $MNT || fail
+else
+    dd if=$ROOT/dev/zero of=$TARGET bs=1k count=$SIZE
+    echo "y" | mke2fs $TARGET $SIZE >/dev/null || fail
+    mount $VERBOSE -t ext2 -o loop $TARGET $MNT || fail
+fi
+
+rm -rf $MNT/lost+found
+for DIR in bin dev etc lib proc tmp mnt ; do
+    mkdir $VERBOSE $MNT/$DIR || fail
+done
+for DIR in block misc fs net pcmcia ; do
+    mkdir $VERBOSE $MNT/lib/$DIR || fail
+done
+
+for F in $DEV ; do
+    cp -a $VERBOSE $ROOT/$F $MNT/dev || fail
+done
+if [ -e $ROOT/dev/systty ] ; then
+    cp -a $VERBOSE $ROOT/dev/systty $MNT/dev || fail
+fi
+
+for F in $BIN ; do
+    strip_cp --strip-all $ROOT/$F $MNT/bin
+done
+strip_cp --strip-all $ROOT/bin/ash $MNT/bin/sh
+
+for F in $LIB ; do
+    strip_cp --strip-debug $ROOT/$F $MNT/lib
+done
+cp $VERBOSE $ROOT/lib/ld-linux.so.? $MNT/lib || fail
+
+for F in $ETC ; do
+    cp $VERBOSE $ROOT/$F $MNT/etc || fail
+done
+for F in scsi network ftl ide memory serial ; do
+    touch $MNT/etc/$F ; chmod +x $MNT/etc/$F
+done
+
+for MOD in $MODULES ; do
+    strip_cp --strip-debug $MODDIR/$MOD $MNT/lib/$MOD
+done
+
+[ "$VERBOSE" ] && echo "Creating linuxrc startup script"
+cat > $MNT/linuxrc <<- 'EOF'
+	#!/bin/sh
+	
+	# Should be either i82365 or tcic
+	PCIC=i82365
+	# Put socket driver timing parameters here
+	PCIC_OPTS=
+	# Put pcmcia_core options here
+	CORE_OPTS=
+	
+	mount -t proc /proc /proc
+
+	echo ""
+	echo "==== initrd: starting PCMCIA services ===="
+	echo ""
+	PC=/lib/pcmcia
+	insmod $PC/pcmcia_core.o $CORE_OPTS
+	insmod $PC/$PCIC.o $PCIC_OPTS
+	insmod $PC/ds.o
+	if [ "$DEBUG" != "" ] ; then V=-v ; fi
+	cardmgr $V -q -o -c /etc -m /lib -s /tmp/stab -p /tmp/pid
+	umount /proc
+	echo ""
+	
+	if [ "$DEBUG" != "" ] ; then
+	    /bin/sh < /dev/console
+	fi
+EOF
+chmod +x $MNT/linuxrc 
+
+df -P $MNT | awk '/tmp/ { printf "%dK/%dK used\n",$3,$2 }'
+umount $VERBOSE $MNT
+rmdir $MNT
+exit 0
Index: oldkernel/linux/pcmcia-cs-3.1.15/cardmgr/probe.c
diff -u /dev/null linux/pcmcia-cs-3.1.15/cardmgr/probe.c:1.1
--- /dev/null	Mon Jul 31 21:15:10 2000
+++ linux/pcmcia-cs-3.1.15/cardmgr/probe.c	Fri Jul  7 16:34:58 2000
@@ -0,0 +1,449 @@
+/*======================================================================
+
+    PCMCIA controller probe
+
+    probe.c 1.50 2000/05/10 18:23:11
+
+    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@pcmcia.sourceforge.org>.  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 <sys/types.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+#include <errno.h>
+#include <fcntl.h>
+
+#ifdef __GLIBC__
+#include <sys/io.h>
+#else
+#include <asm/io.h>
+#endif
+
+#include <pcmcia/config.h>
+#include "i82365.h"
+#include "cirrus.h"
+#include "vg468.h"
+#include "tcic.h"
+
+static int i365_base = 0x03e0;
+
+typedef u_short ioaddr_t;
+
+/*====================================================================*/
+
+#ifdef CONFIG_PCI
+
+typedef struct {
+    u_short	vendor, device;
+    char	*tag;
+    char	*name;
+} pci_id_t;
+
+pci_id_t pci_id[] = {
+    { 0x1013, 0x1100, "Cirrus Logic CL 6729", "Cirrus PD6729" },
+    { 0x1013, 0x1110, "Cirrus Logic PD 6832", "Cirrus PD6832" },
+    { 0x10b3, 0xb106, "SMC 34C90", "SMC 34C90" },
+    { 0x1180, 0x0465, "Ricoh RL5C465", "Ricoh RL5C465" },
+    { 0x1180, 0x0466, "Ricoh RL5C466", "Ricoh RL5C466" },
+    { 0x1180, 0x0475, "Ricoh RL5C475", "Ricoh RL5C475" },
+    { 0x1180, 0x0476, "Ricoh RL5C476", "Ricoh RL5C476" },
+    { 0x1180, 0x0478, "Ricoh RL5C478", "Ricoh RL5C478" },
+    { 0x104c, 0xac12, "Texas Instruments PCI1130", "TI 1130" },
+    { 0x104c, 0xac13, "Texas Instruments PCI1031", "TI 1031" },
+    { 0x104c, 0xac15, "Texas Instruments PCI1131", "TI 1131" },
+    { 0x104c, 0xac16, "Texas Instruments PCI1250", "TI 1250A" },
+    { 0x104c, 0xac17, "Texas Instruments PCI1220", "TI 1220" },
+    { 0x104c, 0xac19, "Texas Instruments PCI1221", "TI 1221" },
+    { 0x104c, 0xac1a, "Texas Instruments PCI1210", "TI 1210" },
+    { 0x104c, 0xac1d, "Texas Instruments PCI1251A", "TI 1251A" },
+    { 0x104c, 0xac1f, "Texas Instruments PCI1251B", "TI 1251B" },
+    { 0x104c, 0xac1b, "Texas Instruments PCI1450", "TI 1450" },
+    { 0x104c, 0xac1c, "Texas Instruments PCI1225", "TI 1225" },
+    { 0x104c, 0xac1e, "Texas Instruments PCI1211", "TI 1211" },
+    { 0x104c, 0xac50, "Texas Instruments PCI1410", "TI 1410" },
+    { 0x104c, 0xac51, "Texas Instruments PCI1420", "TI 1420" },
+    { 0x1217, 0x6729, "O2 Micro 6729", "O2Micro OZ6729" },
+    { 0x1217, 0x673a, "O2 Micro 6730", "O2Micro OZ6730" },
+    { 0x1217, 0x6832, "O2 Micro 6832/6833", "O2Micro OZ6832/OZ6833" },
+    { 0x1217, 0x6836, "O2 Micro 6836/6860", "O2Micro OZ6836/OZ6860" },
+    { 0x1217, 0x6872, "O2 Micro 6812", "O2Micro OZ6812" },
+    { 0x1179, 0x0603, "Toshiba ToPIC95-A", "Toshiba ToPIC95-A" },
+    { 0x1179, 0x060a, "Toshiba ToPIC95-B", "Toshiba ToPIC95-B" },
+    { 0x1179, 0x060f, "Toshiba ToPIC97", "Toshiba ToPIC97" },
+    { 0x1179, 0x0617, "Toshiba ToPIC100", "Toshiba ToPIC100" },
+    { 0x119b, 0x1221, "Omega Micro 82C092G", "Omega Micro 82C092G" },
+    { 0x8086, 0x1221, "Intel 82092AA", "Intel 82092AA" }
+};
+#define PCI_COUNT (sizeof(pci_id)/sizeof(pci_id_t))
+
+static int pci_probe(int verbose, int module)
+{
+    char s[256], *t, *name = NULL;
+    u_int device, vendor, i;
+    FILE *f;
+    
+    if (!module)
+	printf("PCI bridge probe: ");
+
+    if ((f = fopen("/proc/bus/pci/devices", "r")) != NULL) {
+	while (fgets(s, 256, f) != NULL) {
+	    u_int n = strtoul(s+5, NULL, 16);
+	    vendor = (n >> 16); device = (n & 0xffff);
+	    for (i = 0; i < PCI_COUNT; i++)
+		if ((vendor == pci_id[i].vendor) &&
+		    (device == pci_id[i].device)) break;
+	    if (i < PCI_COUNT) {
+		name = pci_id[i].name;
+		break;
+	    }
+	}
+    } else if ((f = fopen("/proc/pci", "r")) != NULL) {
+	while (fgets(s, 256, f) != NULL) {
+	    t = strstr(s, "Device id=");
+	    if (t) {
+		device = strtoul(t+10, NULL, 16);
+		t = strstr(s, "Vendor id=");
+		vendor = strtoul(t+10, NULL, 16);
+		for (i = 0; i < PCI_COUNT; i++)
+		    if ((vendor == pci_id[i].vendor) &&
+			(device == pci_id[i].device)) break;
+	    } else
+		for (i = 0; i < PCI_COUNT; i++)
+		    if (strstr(s, pci_id[i].tag) != NULL) break;
+	    if (i != PCI_COUNT) {
+		name = pci_id[i].name;
+		break;
+	    } else {
+		t = strstr(s, "CardBus bridge");
+		if (t != NULL) {
+		    name = t + 16;
+		    t = strchr(s, '(');
+		    t[-1] = '\0';
+		    break;
+		}
+	    }
+	}
+    }
+    
+    if (name) {
+	if (module)
+	    printf("i82365\n");
+	else
+	    printf("%s found, 2 sockets.\n", name);
+	return 0;
+    } else {
+	if (!module)
+	    printf("not found.\n");
+	return -ENODEV;
+    }
+}
+#endif
+
+/*====================================================================*/
+
+static u_char i365_get(u_short sock, u_short reg)
+{
+    u_char val = I365_REG(sock, reg);
+    outb(val, i365_base); val = inb(i365_base+1);
+    return val;
+}
+
+static void i365_set(u_short sock, u_short reg, u_char data)
+{
+    u_char val = I365_REG(sock, reg);
+    outb(val, i365_base); outb(data, i365_base+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);
+}
+
+/*====================================================================*/
+
+int i365_probe(int verbose, int module)
+{
+    int val, sock, done;
+    char *name = "i82365sl";
+
+    if (!module)
+	printf("Intel PCIC probe: ");
+    if (verbose) printf("\n");
+    
+    sock = done = 0;
+    ioperm(i365_base, 4, 1);
+    ioperm(0x80, 1, 1);
+    for (; sock < 2; sock++) {
+	val = i365_get(sock, I365_IDENT);
+	if (verbose)
+	    printf("  ident(%d)=%#2.2x", sock, val); 
+	switch (val) {
+	case 0x82:
+	    name = "i82365sl A step";
+	    break;
+	case 0x83:
+	    name = "i82365sl B step";
+	    break;
+	case 0x84:
+	    name = "VLSI 82C146";
+	    break;
+	case 0x88: case 0x89: case 0x8a:
+	    name = "IBM Clone";
+	    break;
+	case 0x8b: case 0x8c:
+	    break;
+	default:
+	    done = 1;
+	}
+	if (done) break;
+    }
+
+    if (verbose) printf("\n  ");
+    if (sock == 0) {
+	if (!module)
+	    printf("not found.\n");
+	return -ENODEV;
+    }
+
+    if ((sock == 2) && (strcmp(name, "VLSI 82C146") == 0))
+	name = "i82365sl DF";
+
+    /* Check for Vadem chips */
+    outb(0x0e, i365_base);
+    outb(0x37, i365_base);
+    i365_bset(0, VG468_MISC, VG468_MISC_VADEMREV);
+    val = i365_get(0, I365_IDENT);
+    if (val & I365_IDENT_VADEM) {
+	if ((val & 7) < 4)
+	    name = "Vadem VG-468";
+	else
+	    name = "Vadem VG-469";
+	i365_bclr(0, VG468_MISC, VG468_MISC_VADEMREV);
+    }
+    
+    /* Check for Cirrus CL-PD67xx chips */
+    i365_set(0, PD67_CHIP_INFO, 0);
+    val = i365_get(0, PD67_CHIP_INFO);
+    if ((val & PD67_INFO_CHIP_ID) == PD67_INFO_CHIP_ID) {
+	val = i365_get(0, PD67_CHIP_INFO);
+	if ((val & PD67_INFO_CHIP_ID) == 0) {
+	    if (val & PD67_INFO_SLOTS)
+		name = "Cirrus CL-PD672x";
+	    else {
+		name = "Cirrus CL-PD6710";
+		sock = 1;
+	    }
+	    i365_set(0, PD67_EXT_INDEX, 0xe5);
+	    if (i365_get(0, PD67_EXT_INDEX) != 0xe5)
+		name = "VIA VT83C469";
+	}
+    }
+
+    if (module)
+	printf("i82365\n");
+    else
+	printf("%s found, %d sockets.\n", name, sock);
+    return 0;
+    
+} /* i365_probe */
+  
+/*====================================================================*/
+
+static u_char tcic_getb(ioaddr_t base, u_char reg)
+{
+    u_char val = inb(base+reg);
+    return val;
+}
+
+static void tcic_setb(ioaddr_t base, u_char reg, u_char data)
+{
+    outb(data, base+reg);
+}
+
+static u_short tcic_getw(ioaddr_t base, u_char reg)
+{
+    u_short val = inw(base+reg);
+    return val;
+}
+
+static void tcic_setw(ioaddr_t base, u_char reg, u_short data)
+{
+    outw(data, base+reg);
+}
+
+static u_short tcic_aux_getw(ioaddr_t base, u_short reg)
+{
+    u_char mode = (tcic_getb(base, TCIC_MODE) & TCIC_MODE_PGMMASK) | reg;
+    tcic_setb(base, TCIC_MODE, mode);
+    return tcic_getw(base, TCIC_AUX);
+}
+
+static void tcic_aux_setw(ioaddr_t base, u_short reg, u_short data)
+{
+    u_char mode = (tcic_getb(base, TCIC_MODE) & TCIC_MODE_PGMMASK) | reg;
+    tcic_setb(base, TCIC_MODE, mode);
+    tcic_setw(base, TCIC_AUX, data);
+}
+
+static int get_tcic_id(ioaddr_t base)
+{
+    u_short id;
+    tcic_aux_setw(base, TCIC_AUX_TEST, TCIC_TEST_DIAG);
+    id = tcic_aux_getw(base, TCIC_AUX_ILOCK);
+    id = (id & TCIC_ILOCKTEST_ID_MASK) >> TCIC_ILOCKTEST_ID_SH;
+    tcic_aux_setw(base, TCIC_AUX_TEST, 0);
+    return id;
+}
+
+int tcic_probe_at(ioaddr_t base, int module)
+{
+    int i;
+    u_short old;
+    
+    /* Anything there?? */
+    for (i = 0; i < 0x10; i += 2)
+	if (tcic_getw(base, i) == 0xffff)
+	    return -1;
+
+    if (!module)
+	printf("  at %#3.3x: ", base); fflush(stdout);
+
+    /* Try to reset the chip */
+    tcic_setw(base, TCIC_SCTRL, TCIC_SCTRL_RESET);
+    tcic_setw(base, TCIC_SCTRL, 0);
+    
+    /* Can we set the addr register? */
+    old = tcic_getw(base, TCIC_ADDR);
+    tcic_setw(base, TCIC_ADDR, 0);
+    if (tcic_getw(base, TCIC_ADDR) != 0) {
+	tcic_setw(base, TCIC_ADDR, old);
+	return -2;
+    }
+    
+    tcic_setw(base, TCIC_ADDR, 0xc3a5);
+    if (tcic_getw(base, TCIC_ADDR) != 0xc3a5)
+	return -3;
+
+    return 2;
+}
+
+int tcic_probe(int verbose, int module, ioaddr_t base)
+{
+    int sock, id;
+
+    if (!module)
+	printf("Databook TCIC-2 probe: "); fflush(stdout);
+    
+    ioperm(base, 16, 1);
+    ioperm(0x80, 1, 1);
+    sock = tcic_probe_at(base, module);
+    
+    if (sock <= 0) {
+	if (!module)
+	    printf("not found.\n");
+	return -ENODEV;
+    }
+
+    if (module)
+	printf("tcic\n");
+    else {
+	id = get_tcic_id(base);
+	switch (id) {
+	case TCIC_ID_DB86082:
+	    printf("DB86082"); break;
+	case TCIC_ID_DB86082A:
+	    printf("DB86082A"); break;
+	case TCIC_ID_DB86084:
+	    printf("DB86084"); break;
+	case TCIC_ID_DB86084A:
+	    printf("DB86084A"); break;
+	case TCIC_ID_DB86072:
+	    printf("DB86072"); break;
+	case TCIC_ID_DB86184:
+	    printf("DB86184"); break;
+	case TCIC_ID_DB86082B:
+	    printf("DB86082B"); break;
+	default:
+	    printf("Unknown TCIC-2 ID 0x%02x", id);
+	}
+	printf(" found at %#6x, %d sockets.\n", base, sock);
+    }
+    return 0;
+    
+} /* tcic_probe */
+
+/*====================================================================*/
+
+int main(int argc, char *argv[])
+{
+    int optch, errflg;
+    extern char *optarg;
+    int verbose = 0, module = 0;
+    ioaddr_t tcic_base = TCIC_BASE;
+    
+    errflg = 0;
+    while ((optch = getopt(argc, argv, "t:vxm")) != -1) {
+	switch (optch) {
+	case 't':
+	    tcic_base = strtoul(optarg, NULL, 0); break;
+	case 'v':
+	    verbose = 1; break;
+	case 'm':
+	    module = 1; break;
+	default:
+	    errflg = 1; break;
+	}
+    }
+    if (errflg || (optind < argc)) {
+	fprintf(stderr, "usage: %s [-t tcic_base] [-v] [-m]\n", argv[0]);
+	exit(EXIT_FAILURE);
+    }
+
+#ifdef CONFIG_PCI
+    if (pci_probe(verbose, module) == 0)
+	exit(EXIT_SUCCESS);
+    else
+#endif
+    if (i365_probe(verbose, module) == 0)
+	exit(EXIT_SUCCESS);
+    else if (tcic_probe(verbose, module, tcic_base) == 0)
+	exit(EXIT_SUCCESS);
+    else
+	exit(EXIT_FAILURE);
+    return 0;
+}
Index: oldkernel/linux/pcmcia-cs-3.1.15/cardmgr/scsi_info.c
diff -u /dev/null linux/pcmcia-cs-3.1.15/cardmgr/scsi_info.c:1.1
--- /dev/null	Mon Jul 31 21:15:10 2000
+++ linux/pcmcia-cs-3.1.15/cardmgr/scsi_info.c	Fri Jul  7 16:34:58 2000
@@ -0,0 +1,148 @@
+/*======================================================================
+
+    Utility to look up information about SCSI devices
+
+    scsi_info.c 1.15 2000/04/03 19:44:50
+
+    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@pcmcia.sourceforge.org>.  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 <sys/types.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <unistd.h>
+#include <string.h>
+#include <fcntl.h>
+#include <sys/ioctl.h>
+#include <dirent.h>
+
+#include <linux/version.h>
+#include <linux/config.h>
+
+#include <linux/major.h>
+#include <scsi/scsi.h>
+
+/*====================================================================*/
+
+static int get_host_no(int host)
+{
+    DIR *dir;
+    struct dirent *ent;
+    char fn[128];
+    
+    dir = opendir("/proc/scsi");
+    if (dir == NULL)
+	return -1;
+    while ((ent = readdir(dir)) != NULL)
+	if ((ent->d_ino & 0xff) == host)
+	    break;
+    closedir(dir);
+    if (!ent) {
+	perror("could not find SCSI host in /proc/scsi");
+	return -1;
+    }
+    
+    sprintf(fn, "/proc/scsi/%s", ent->d_name);
+    dir = opendir(fn);
+    if (dir == NULL) {
+	return -1;
+    }
+    do {
+	ent = readdir(dir);
+    } while ((ent) && (ent->d_name[0] == '.'));
+    closedir(dir);
+    if (ent)
+	return atoi(ent->d_name);
+    else
+	return -1;
+}
+
+/*====================================================================*/
+
+int main(int argc, char *argv[])
+{
+    int i, fd, host, channel, id, lun;
+    u_int arg[2];
+    char match[128], s[128], vendor[9], model[17], rev[5];
+    FILE *f;
+
+    if (argc != 2) {
+	fprintf(stderr, "usage: %s [device]\n", argv[0]);
+	exit(EXIT_FAILURE);
+    }
+    
+    fd = open(argv[1], O_RDONLY);
+    if (fd < 0)
+	fd = open(argv[1], O_RDONLY|O_NONBLOCK);
+    if (fd < 0) {
+	perror("open() failed");
+	exit(1);
+    }
+    if (ioctl(fd, SCSI_IOCTL_GET_IDLUN, arg) != 0) {
+	perror("could not get SCSI device info");
+	exit(1);
+    }
+
+    id = arg[0] & 0xff;
+    lun = (arg[0] >> 8) & 0xff;
+    channel = (arg[0] >> 16) & 0xff;
+    host = ((arg[0] >> 24) & 0xff);
+
+#ifdef SCSI_IOCTL_GET_BUS_NUMBER
+    if (ioctl(fd, SCSI_IOCTL_GET_BUS_NUMBER, arg) == 0)
+	host = arg[0];
+    else
+#endif
+	host = get_host_no(host);
+
+    sprintf(match, "Host: scsi%d Channel: %02x Id: %02x Lun: %02x\n",
+	    host, channel, id, lun);
+
+    printf("SCSI_ID=\"%d,%d,%d\"\n", channel, id, lun);
+    
+    f = fopen("/proc/scsi/scsi", "r");
+    if (f == NULL) {
+	printf("MODEL=\"Unknown\"\nFW_REV=\"Unknown\"\n");
+	exit(0);
+    }
+
+    while (fgets(s, 128, f) != NULL)
+	if (strcmp(s, match) == 0) break;
+    fgets(s, 128, f);
+    strncpy(vendor, s+10, 8); vendor[8] = '\0';
+    for (i = 7; (i >= 0) && (vendor[i] == ' '); i--)
+	vendor[i] = '\0';
+    strncpy(model, s+26, 16); model[16] = '\0';
+    for (i = 15; (i >= 0) && (model[i] == ' '); i--)
+	model[i] = '\0';
+    strncpy(rev, s+48, 4); rev[4] = '\0';
+    for (i = 3; (i >= 0) && (rev[i] == ' '); i--)
+	rev[i] = '\0';
+    printf("MODEL=\"%s %s\"\nFW_REV=\"%s\"\n", vendor, model, rev);
+    exit(0);
+    return 0;
+}
Index: oldkernel/linux/pcmcia-cs-3.1.15/cardmgr/yacc_config.c
diff -u /dev/null linux/pcmcia-cs-3.1.15/cardmgr/yacc_config.c:1.1
--- /dev/null	Mon Jul 31 21:15:10 2000
+++ linux/pcmcia-cs-3.1.15/cardmgr/yacc_config.c	Fri Jul  7 16:34:58 2000
@@ -0,0 +1,1021 @@
+#ifndef lint
+static char yysccsid[] = "@(#)yaccpar	1.9 (Berkeley) 02/21/93";
+#endif
+#define YYBYACC 1
+#define YYMAJOR 1
+#define YYMINOR 9
+#define yyclearin (yychar=(-1))
+#define yyerrok (yyerrflag=0)
+#define YYRECOVERING (yyerrflag!=0)
+#define YYPREFIX "yy"
+#line 2 "yacc_config.y"
+/*
+ * yacc_config.y 1.49 1999/12/29 00:57: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@pcmcia.sourceforge.org>.  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 <stdlib.h>
+#include <stdarg.h>
+#include <stdio.h>
+#include <string.h>
+#include <syslog.h>
+#include <sys/types.h>
+
+#include <pcmcia/cs_types.h>
+#include <pcmcia/cs.h>
+#include <pcmcia/cistpl.h>
+#include <pcmcia/ds.h>
+    
+#include "cardmgr.h"
+
+/* If bison: generate nicer error messages */ 
+#define YYERROR_VERBOSE 1
+ 
+/* from lex_config, for nice error messages */
+extern char *current_file;
+extern int current_lineno;
+
+void yyerror(char *msg, ...);
+
+static int add_binding(card_info_t *card, char *name, int fn);
+static int add_module(device_info_t *card, char *name);
+
+#line 65 "yacc_config.y"
+typedef union {
+    char *str;
+    u_long num;
+    struct device_info_t *device;
+    struct card_info_t *card;
+    struct mtd_ident_t *mtd;
+    struct adjust_list_t *adjust;
+} YYSTYPE;
+#line 77 "y.tab.c"
+#define DEVICE 257
+#define CARD 258
+#define ANONYMOUS 259
+#define TUPLE 260
+#define MANFID 261
+#define VERSION 262
+#define FUNCTION 263
+#define PCI 264
+#define BIND 265
+#define CIS 266
+#define TO 267
+#define NEEDS_MTD 268
+#define MODULE 269
+#define OPTS 270
+#define CLASS 271
+#define REGION 272
+#define JEDEC 273
+#define DTYPE 274
+#define DEFAULT 275
+#define MTD 276
+#define INCLUDE 277
+#define EXCLUDE 278
+#define RESERVE 279
+#define IRQ_NO 280
+#define PORT 281
+#define MEMORY 282
+#define STRING 283
+#define NUMBER 284
+#define YYERRCODE 256
+short yylhs[] = {                                        -1,
+    0,    0,    0,    0,    0,    0,    0,    0,    1,    1,
+    1,    1,    2,    2,    2,    3,    3,    3,    3,    7,
+    7,    7,    7,    7,    7,    7,    7,    7,    8,    9,
+   10,   11,   12,   12,   13,   15,   14,   14,   14,   14,
+    4,   21,    5,    5,    5,    6,   16,   16,   16,   16,
+   18,   17,   19,   20,   20,   22,
+};
+short yylen[] = {                                         2,
+    0,    2,    2,    2,    2,    2,    2,    2,    2,    2,
+    2,    3,    2,    4,    4,    2,    1,    1,    1,    2,
+    1,    1,    1,    1,    1,    1,    1,    1,    2,    7,
+    5,    5,    3,    3,    3,    3,    3,    5,    3,    5,
+    2,    4,    3,    3,    3,    3,    2,    1,    1,    1,
+    3,    4,    2,    3,    3,    4,
+};
+short yydefred[] = {                                      1,
+    0,    8,    0,    0,    0,    0,    0,    0,    0,    0,
+    0,    0,   17,    0,   19,    0,   21,   22,   23,   24,
+    0,   26,    0,   28,    0,   49,   48,   50,    0,    6,
+    7,   16,   20,    0,   47,    0,    0,    0,    0,    9,
+   10,   11,    0,   41,    0,    0,    0,    0,   29,    0,
+    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,
+   53,    0,    0,    0,    0,   13,    0,    0,   12,   43,
+   46,   44,   45,    0,    0,   33,   35,    0,    0,   36,
+   34,    0,    0,   51,   54,   55,   42,   56,    0,    0,
+    0,    0,    0,    0,    0,   52,   14,   15,    0,   31,
+   32,   38,   40,    0,   30,
+};
+short yydgoto[] = {                                       1,
+   11,   40,   12,   13,   14,   15,   16,   17,   18,   19,
+   20,   21,   22,   23,   24,   25,   26,   27,   28,   29,
+   30,   31,
+};
+short yysindex[] = {                                      0,
+ -250,    0, -279, -278, -274, -265, -259, -242, -242, -242,
+  -10, -248,    0,  -44,    0, -249,    0,    0,    0,    0,
+   -9,    0,   -3,    0, -243,    0,    0,    0, -233,    0,
+    0,    0,    0, -228,    0, -227, -240, -238, -237,    0,
+    0,    0, -242,    0, -235, -232, -231, -230,    0, -234,
+ -229, -226, -225, -224, -222, -221, -220, -219, -218, -217,
+    0, -215, -213, -212, -211,    0,    9,   11,    0,    0,
+    0,    0,    0,   14,   21,    0,    0,   30, -192,    0,
+    0, -191, -207,    0,    0,    0,    0,    0, -206, -205,
+ -204, -203, -202, -201, -200,    0,    0,    0,   41,    0,
+    0,    0,    0, -197,    0,
+};
+short yyrindex[] = {                                      0,
+    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,
+  107,  149,    0,   90,    0,  124,    0,    0,    0,    0,
+   49,    0,   73,    0,    0,    0,    0,    0,  141,    0,
+    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,
+    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,
+    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,
+    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,
+    0,    0,    0,    0,    0,    0,    0,    0,    1,    0,
+    0,   25,    0,    0,    0,    0,    0,    0,    0,    0,
+    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,
+    0,    0,    0,    0,    0,
+};
+short yygindex[] = {                                      0,
+    0,   -7,    0,    0,    0,    0,    0,    0,    0,    0,
+    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,
+    0,    0,
+};
+#define YYTABLESIZE 428
+short yytable[] = {                                      48,
+   37,   41,   42,   32,   33,    2,    3,    4,   34,   49,
+   50,   51,   52,   53,   54,   55,   56,   35,    5,   44,
+   45,    6,   46,   36,   39,    7,    8,    9,   10,   59,
+   60,   61,   62,   43,   57,   69,   63,   37,   38,   39,
+   58,   64,   65,   66,   37,   67,   68,   70,   25,   74,
+   71,   72,   73,   89,   75,   90,   76,   91,   77,   78,
+   79,   80,   81,   82,   92,   83,   84,   85,   39,   86,
+   87,   88,   27,   93,   94,   95,   96,   97,   98,   99,
+  100,  101,  102,  103,  104,  105,    0,    0,    0,   18,
+    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,
+    0,    0,    0,    0,    0,    0,    2,    0,    0,    0,
+    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,
+    0,    0,    0,    5,    0,    0,    0,    0,    0,    0,
+    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,
+    4,    0,    0,    0,    0,    0,    0,    0,    3,    0,
+    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,
+    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,
+    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,
+    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,
+    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,
+    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,
+    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,
+    0,    0,    0,    0,    0,   47,    0,    0,    0,    0,
+    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,
+    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,
+    0,    0,    0,    0,    0,    0,   37,   37,   37,   37,
+   37,   37,   37,   37,   37,   37,   37,    0,    0,   37,
+    0,    0,   37,    0,    0,    0,   37,   37,   37,   37,
+   39,   39,   39,   39,   39,   39,   39,   39,   39,   39,
+   39,    0,    0,   39,    0,    0,   39,    0,    0,    0,
+   39,   39,   39,   39,   25,   25,   25,   25,   25,   25,
+   25,   25,   25,   25,   25,    0,    0,   25,    0,    0,
+   25,    0,    0,    0,   25,   25,   25,   25,   27,   27,
+   27,   27,   27,   27,   27,   27,   27,   27,   27,    0,
+    0,   27,    0,    0,   27,   18,   18,   18,   27,   27,
+   27,   27,    0,    0,    0,    0,    0,   18,   18,    0,
+   18,   18,    2,    2,    2,   18,   18,   18,   18,    0,
+    0,    0,    0,    0,    0,    2,    0,    0,    2,    5,
+    5,    5,    2,    2,    2,    2,    0,    0,    0,    0,
+    0,    0,    5,    0,    0,    5,    4,    4,    4,    5,
+    5,    5,    5,    0,    3,    3,    3,    0,    0,    4,
+    0,    0,    4,    0,    0,    0,    4,    4,    4,    4,
+    3,    0,    0,    0,    3,    3,    3,    3,
+};
+short yycheck[] = {                                      44,
+    0,    9,   10,  283,  283,  256,  257,  258,  283,  259,
+  260,  261,  262,  263,  264,  265,  266,  283,  269,  268,
+  269,  272,  271,  283,    0,  276,  277,  278,  279,  273,
+  274,  275,  276,   44,   44,   43,  270,  280,  281,  282,
+   44,  270,  270,  284,   44,  284,  284,  283,    0,  284,
+  283,  283,  283,   45,  284,   45,  283,   44,  284,  284,
+  283,  283,  283,  283,   44,  284,  284,  283,   44,  283,
+  283,  283,    0,   44,  267,  267,  284,  284,  284,  284,
+  284,  284,  284,  284,   44,  283,   -1,   -1,   -1,    0,
+   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,
+   -1,   -1,   -1,   -1,   -1,   -1,    0,   -1,   -1,   -1,
+   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,
+   -1,   -1,   -1,    0,   -1,   -1,   -1,   -1,   -1,   -1,
+   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,
+    0,   -1,   -1,   -1,   -1,   -1,   -1,   -1,    0,   -1,
+   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,
+   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,
+   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,
+   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,
+   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,
+   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,
+   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,
+   -1,   -1,   -1,   -1,   -1,  270,   -1,   -1,   -1,   -1,
+   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,
+   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,
+   -1,   -1,   -1,   -1,   -1,   -1,  256,  257,  258,  259,
+  260,  261,  262,  263,  264,  265,  266,   -1,   -1,  269,
+   -1,   -1,  272,   -1,   -1,   -1,  276,  277,  278,  279,
+  256,  257,  258,  259,  260,  261,  262,  263,  264,  265,
+  266,   -1,   -1,  269,   -1,   -1,  272,   -1,   -1,   -1,
+  276,  277,  278,  279,  256,  257,  258,  259,  260,  261,
+  262,  263,  264,  265,  266,   -1,   -1,  269,   -1,   -1,
+  272,   -1,   -1,   -1,  276,  277,  278,  279,  256,  257,
+  258,  259,  260,  261,  262,  263,  264,  265,  266,   -1,
+   -1,  269,   -1,   -1,  272,  256,  257,  258,  276,  277,
+  278,  279,   -1,   -1,   -1,   -1,   -1,  268,  269,   -1,
+  271,  272,  256,  257,  258,  276,  277,  278,  279,   -1,
+   -1,   -1,   -1,   -1,   -1,  269,   -1,   -1,  272,  256,
+  257,  258,  276,  277,  278,  279,   -1,   -1,   -1,   -1,
+   -1,   -1,  269,   -1,   -1,  272,  256,  257,  258,  276,
+  277,  278,  279,   -1,  256,  257,  258,   -1,   -1,  269,
+   -1,   -1,  272,   -1,   -1,   -1,  276,  277,  278,  279,
+  272,   -1,   -1,   -1,  276,  277,  278,  279,
+};
+#define YYFINAL 1
+#ifndef YYDEBUG
+#define YYDEBUG 0
+#endif
+#define YYMAXTOKEN 284
+#if YYDEBUG
+char *yyname[] = {
+"end-of-file",0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,"','","'-'",0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,"DEVICE","CARD",
+"ANONYMOUS","TUPLE","MANFID","VERSION","FUNCTION","PCI","BIND","CIS","TO",
+"NEEDS_MTD","MODULE","OPTS","CLASS","REGION","JEDEC","DTYPE","DEFAULT","MTD",
+"INCLUDE","EXCLUDE","RESERVE","IRQ_NO","PORT","MEMORY","STRING","NUMBER",
+};
+char *yyrule[] = {
+"$accept : list",
+"list :",
+"list : list adjust",
+"list : list device",
+"list : list mtd",
+"list : list card",
+"list : list opts",
+"list : list mtd_opts",
+"list : list error",
+"adjust : INCLUDE resource",
+"adjust : EXCLUDE resource",
+"adjust : RESERVE resource",
+"adjust : adjust ',' resource",
+"resource : IRQ_NO NUMBER",
+"resource : PORT NUMBER '-' NUMBER",
+"resource : MEMORY NUMBER '-' NUMBER",
+"device : DEVICE STRING",
+"device : needs_mtd",
+"device : module",
+"device : class",
+"card : CARD STRING",
+"card : anonymous",
+"card : tuple",
+"card : manfid",
+"card : pci",
+"card : version",
+"card : function",
+"card : bind",
+"card : cis",
+"anonymous : card ANONYMOUS",
+"tuple : card TUPLE NUMBER ',' NUMBER ',' STRING",
+"manfid : card MANFID NUMBER ',' NUMBER",
+"pci : card PCI NUMBER ',' NUMBER",
+"version : card VERSION STRING",
+"version : version ',' STRING",
+"function : card FUNCTION NUMBER",
+"cis : card CIS STRING",
+"bind : card BIND STRING",
+"bind : card BIND STRING TO NUMBER",
+"bind : bind ',' STRING",
+"bind : bind ',' STRING TO NUMBER",
+"needs_mtd : device NEEDS_MTD",
+"opts : MODULE STRING OPTS STRING",
+"module : device MODULE STRING",
+"module : module OPTS STRING",
+"module : module ',' STRING",
+"class : device CLASS STRING",
+"region : REGION STRING",
+"region : dtype",
+"region : jedec",
+"region : default",
+"dtype : region DTYPE NUMBER",
+"jedec : region JEDEC NUMBER NUMBER",
+"default : region DEFAULT",
+"mtd : region MTD STRING",
+"mtd : mtd OPTS STRING",
+"mtd_opts : MTD STRING OPTS STRING",
+};
+#endif
+#ifdef YYSTACKSIZE
+#undef YYMAXDEPTH
+#define YYMAXDEPTH YYSTACKSIZE
+#else
+#ifdef YYMAXDEPTH
+#define YYSTACKSIZE YYMAXDEPTH
+#else
+#define YYSTACKSIZE 500
+#define YYMAXDEPTH 500
+#endif
+#endif
+int yydebug;
+int yynerrs;
+int yyerrflag;
+int yychar;
+short *yyssp;
+YYSTYPE *yyvsp;
+YYSTYPE yyval;
+YYSTYPE yylval;
+short yyss[YYSTACKSIZE];
+YYSTYPE yyvs[YYSTACKSIZE];
+#define yystacksize YYSTACKSIZE
+#line 468 "yacc_config.y"
+void yyerror(char *msg, ...)
+{
+     va_list ap;
+     char str[256];
+
+     va_start(ap, msg);
+     sprintf(str, "config error, file '%s' line %d: ",
+	     current_file, current_lineno);
+     vsprintf(str+strlen(str), msg, ap);
+#if YYDEBUG
+     fprintf(stderr, "%s\n", str);
+#else
+     syslog(LOG_INFO, "%s", str);
+#endif
+     va_end(ap);
+}
+
+static int add_binding(card_info_t *card, char *name, int fn)
+{
+    device_info_t *dev = root_device;
+    if (card->bindings == MAX_BINDINGS) {
+	yyerror("too many bindings\n");
+	return -1;
+    }
+    for (; dev; dev = dev->next)
+	if (strcmp((char *)dev->dev_info, name) == 0) break;
+    if (dev == NULL) {
+	yyerror("unknown device: %s", name);
+	return -1;
+    }
+    card->device[card->bindings] = dev;
+    card->dev_fn[card->bindings] = fn;
+    card->bindings++;
+    free(name);
+    return 0;
+}
+
+static int add_module(device_info_t *dev, char *name)
+{
+    if (dev->modules == MAX_MODULES) {
+	yyerror("too many modules");
+	return -1;
+    }
+    dev->module[dev->modules] = name;
+    dev->opts[dev->modules] = NULL;
+    dev->modules++;
+    return 0;
+}
+
+#if YYDEBUG
+adjust_list_t *root_adjust = NULL;
+device_info_t *root_device = NULL;
+card_info_t *root_card = NULL, *blank_card = NULL, *root_func = NULL;
+mtd_ident_t *root_mtd = NULL, *default_mtd = NULL;
+
+void main(int argc, char *argv[])
+{
+    yydebug = 1;
+    if (argc > 1)
+	parse_configfile(argv[1]);
+}
+#endif
+#line 426 "y.tab.c"
+#define YYABORT goto yyabort
+#define YYREJECT goto yyabort
+#define YYACCEPT goto yyaccept
+#define YYERROR goto yyerrlab
+int
+yyparse()
+{
+    register int yym, yyn, yystate;
+#if YYDEBUG
+    register char *yys;
+    extern char *getenv();
+
+    if (yys = getenv("YYDEBUG"))
+    {
+        yyn = *yys;
+        if (yyn >= '0' && yyn <= '9')
+            yydebug = yyn - '0';
+    }
+#endif
+
+    yynerrs = 0;
+    yyerrflag = 0;
+    yychar = (-1);
+
+    yyssp = yyss;
+    yyvsp = yyvs;
+    *yyssp = yystate = 0;
+
+yyloop:
+    if (yyn = yydefred[yystate]) goto yyreduce;
+    if (yychar < 0)
+    {
+        if ((yychar = yylex()) < 0) yychar = 0;
+#if YYDEBUG
+        if (yydebug)
+        {
+            yys = 0;
+            if (yychar <= YYMAXTOKEN) yys = yyname[yychar];
+            if (!yys) yys = "illegal-symbol";
+            printf("%sdebug: state %d, reading %d (%s)\n",
+                    YYPREFIX, yystate, yychar, yys);
+        }
+#endif
+    }
+    if ((yyn = yysindex[yystate]) && (yyn += yychar) >= 0 &&
+            yyn <= YYTABLESIZE && yycheck[yyn] == yychar)
+    {
+#if YYDEBUG
+        if (yydebug)
+            printf("%sdebug: state %d, shifting to state %d\n",
+                    YYPREFIX, yystate, yytable[yyn]);
+#endif
+        if (yyssp >= yyss + yystacksize - 1)
+        {
+            goto yyoverflow;
+        }
+        *++yyssp = yystate = yytable[yyn];
+        *++yyvsp = yylval;
+        yychar = (-1);
+        if (yyerrflag > 0)  --yyerrflag;
+        goto yyloop;
+    }
+    if ((yyn = yyrindex[yystate]) && (yyn += yychar) >= 0 &&
+            yyn <= YYTABLESIZE && yycheck[yyn] == yychar)
+    {
+        yyn = yytable[yyn];
+        goto yyreduce;
+    }
+    if (yyerrflag) goto yyinrecovery;
+#ifdef lint
+    goto yynewerror;
+#endif
+yynewerror:
+    yyerror("syntax error");
+#ifdef lint
+    goto yyerrlab;
+#endif
+yyerrlab:
+    ++yynerrs;
+yyinrecovery:
+    if (yyerrflag < 3)
+    {
+        yyerrflag = 3;
+        for (;;)
+        {
+            if ((yyn = yysindex[*yyssp]) && (yyn += YYERRCODE) >= 0 &&
+                    yyn <= YYTABLESIZE && yycheck[yyn] == YYERRCODE)
+            {
+#if YYDEBUG
+                if (yydebug)
+                    printf("%sdebug: state %d, error recovery shifting\
+ to state %d\n", YYPREFIX, *yyssp, yytable[yyn]);
+#endif
+                if (yyssp >= yyss + yystacksize - 1)
+                {
+                    goto yyoverflow;
+                }
+                *++yyssp = yystate = yytable[yyn];
+                *++yyvsp = yylval;
+                goto yyloop;
+            }
+            else
+            {
+#if YYDEBUG
+                if (yydebug)
+                    printf("%sdebug: error recovery discarding state %d\n",
+                            YYPREFIX, *yyssp);
+#endif
+                if (yyssp <= yyss) goto yyabort;
+                --yyssp;
+                --yyvsp;
+            }
+        }
+    }
+    else
+    {
+        if (yychar == 0) goto yyabort;
+#if YYDEBUG
+        if (yydebug)
+        {
+            yys = 0;
+            if (yychar <= YYMAXTOKEN) yys = yyname[yychar];
+            if (!yys) yys = "illegal-symbol";
+            printf("%sdebug: state %d, error recovery discards token %d (%s)\n",
+                    YYPREFIX, yystate, yychar, yys);
+        }
+#endif
+        yychar = (-1);
+        goto yyloop;
+    }
+yyreduce:
+#if YYDEBUG
+    if (yydebug)
+        printf("%sdebug: state %d, reducing by rule %d (%s)\n",
+                YYPREFIX, yystate, yyn, yyrule[yyn]);
+#endif
+    yym = yylen[yyn];
+    yyval = yyvsp[1-yym];
+    switch (yyn)
+    {
+case 2:
+#line 84 "yacc_config.y"
+{
+		    adjust_list_t **tail = &root_adjust;
+		    while (*tail != NULL) tail = &(*tail)->next;
+		    *tail = yyvsp[0].adjust;
+		}
+break;
+case 3:
+#line 90 "yacc_config.y"
+{
+		    yyvsp[0].device->next = root_device;
+		    root_device = yyvsp[0].device;
+		}
+break;
+case 4:
+#line 95 "yacc_config.y"
+{
+		    if (yyvsp[0].mtd->mtd_type == 0) {
+			yyerror("no ID method for this card");
+			YYERROR;
+		    }
+		    if (yyvsp[0].mtd->module == NULL) {
+			yyerror("no MTD module specified");
+			YYERROR;
+		    }
+		    yyvsp[0].mtd->next = root_mtd;
+		    root_mtd = yyvsp[0].mtd;
+		}
+break;
+case 5:
+#line 108 "yacc_config.y"
+{
+		    if (yyvsp[0].card->ident_type == 0) {
+			yyerror("no ID method for this card");
+			YYERROR;
+		    }
+		    if (yyvsp[0].card->bindings == 0) {
+			yyerror("no function bindings");
+			YYERROR;
+		    }
+		    if (yyvsp[0].card->ident_type == FUNC_IDENT) {
+			yyvsp[0].card->next = root_func;
+			root_func = yyvsp[0].card;
+		    } else {
+			yyvsp[0].card->next = root_card;
+			root_card = yyvsp[0].card;
+		    }
+		}
+break;
+case 9:
+#line 131 "yacc_config.y"
+{
+		    yyvsp[0].adjust->adj.Action = ADD_MANAGED_RESOURCE;
+		    yyval.adjust = yyvsp[0].adjust;
+		}
+break;
+case 10:
+#line 136 "yacc_config.y"
+{
+		    yyvsp[0].adjust->adj.Action = REMOVE_MANAGED_RESOURCE;
+		    yyval.adjust = yyvsp[0].adjust;
+		}
+break;
+case 11:
+#line 141 "yacc_config.y"
+{
+		    yyvsp[0].adjust->adj.Action = ADD_MANAGED_RESOURCE;
+		    yyvsp[0].adjust->adj.Attributes |= RES_RESERVED;
+		    yyval.adjust = yyvsp[0].adjust;
+		}
+break;
+case 12:
+#line 147 "yacc_config.y"
+{
+		    yyvsp[0].adjust->adj.Action = yyvsp[-2].adjust->adj.Action;
+		    yyvsp[0].adjust->adj.Attributes = yyvsp[-2].adjust->adj.Attributes;
+		    yyvsp[0].adjust->next = yyvsp[-2].adjust;
+		    yyval.adjust = yyvsp[0].adjust;
+		}
+break;
+case 13:
+#line 156 "yacc_config.y"
+{
+		    yyval.adjust = calloc(sizeof(adjust_list_t), 1);
+		    yyval.adjust->adj.Resource = RES_IRQ;
+		    yyval.adjust->adj.resource.irq.IRQ = yyvsp[0].num;
+		}
+break;
+case 14:
+#line 162 "yacc_config.y"
+{
+		    if ((yyvsp[0].num < yyvsp[-2].num) || (yyvsp[0].num > 0xffff)) {
+			yyerror("invalid port range");
+			YYERROR;
+		    }
+		    yyval.adjust = calloc(sizeof(adjust_list_t), 1);
+		    yyval.adjust->adj.Resource = RES_IO_RANGE;
+		    yyval.adjust->adj.resource.io.BasePort = yyvsp[-2].num;
+		    yyval.adjust->adj.resource.io.NumPorts = yyvsp[0].num - yyvsp[-2].num + 1;
+		}
+break;
+case 15:
+#line 173 "yacc_config.y"
+{
+		    if (yyvsp[0].num < yyvsp[-2].num) {
+			yyerror("invalid address range");
+			YYERROR;
+		    }
+		    yyval.adjust = calloc(sizeof(adjust_list_t), 1);
+		    yyval.adjust->adj.Resource = RES_MEMORY_RANGE;
+		    yyval.adjust->adj.resource.memory.Base = yyvsp[-2].num;
+		    yyval.adjust->adj.resource.memory.Size = yyvsp[0].num - yyvsp[-2].num + 1;
+		}
+break;
+case 16:
+#line 186 "yacc_config.y"
+{
+		    yyval.device = calloc(sizeof(device_info_t), 1);
+		    yyval.device->refs = 1;
+		    strcpy(yyval.device->dev_info, yyvsp[0].str);
+		    free(yyvsp[0].str);
+		}
+break;
+case 20:
+#line 198 "yacc_config.y"
+{
+		    yyval.card = calloc(sizeof(card_info_t), 1);
+		    yyval.card->refs = 1;
+		    yyval.card->name = yyvsp[0].str;
+		}
+break;
+case 29:
+#line 214 "yacc_config.y"
+{
+		    if (yyvsp[-1].card->ident_type != 0) {
+			yyerror("ID method already defined");
+			YYERROR;
+		    }
+		    if (blank_card) {
+			yyerror("Anonymous card already defined");
+			YYERROR;
+		    }
+		    yyvsp[-1].card->ident_type = BLANK_IDENT;
+		    blank_card = yyvsp[-1].card;
+		}
+break;
+case 30:
+#line 229 "yacc_config.y"
+{
+		    if (yyvsp[-6].card->ident_type != 0) {
+			yyerror("ID method already defined");
+			YYERROR;
+		    }
+		    yyvsp[-6].card->ident_type = TUPLE_IDENT;
+		    yyvsp[-6].card->id.tuple.code = yyvsp[-4].num;
+		    yyvsp[-6].card->id.tuple.ofs = yyvsp[-2].num;
+		    yyvsp[-6].card->id.tuple.info = yyvsp[0].str;
+		}
+break;
+case 31:
+#line 242 "yacc_config.y"
+{
+		    if (yyvsp[-4].card->ident_type != 0) {
+			yyerror("ID method already defined");
+			YYERROR;
+		    }
+		    yyvsp[-4].card->ident_type = MANFID_IDENT;
+		    yyvsp[-4].card->id.manfid.manf = yyvsp[-2].num;
+		    yyvsp[-4].card->id.manfid.card = yyvsp[0].num;
+		}
+break;
+case 32:
+#line 253 "yacc_config.y"
+{
+		    if (yyvsp[-4].card->ident_type != 0) {
+			yyerror("ID method already defined");
+			YYERROR;
+		    }
+		    yyvsp[-4].card->ident_type = PCI_IDENT;
+		    yyvsp[-4].card->id.manfid.manf = yyvsp[-2].num;
+		    yyvsp[-4].card->id.manfid.card = yyvsp[0].num;
+		}
+break;
+case 33:
+#line 264 "yacc_config.y"
+{
+		    if (yyvsp[-2].card->ident_type != 0) {
+			yyerror("ID method already defined\n");
+			YYERROR;
+		    }
+		    yyvsp[-2].card->ident_type = VERS_1_IDENT;
+		    yyvsp[-2].card->id.vers.ns = 1;
+		    yyvsp[-2].card->id.vers.pi[0] = yyvsp[0].str;
+		}
+break;
+case 34:
+#line 274 "yacc_config.y"
+{
+		    if (yyvsp[-2].card->id.vers.ns == 4) {
+			yyerror("too many version strings");
+			YYERROR;
+		    }
+		    yyvsp[-2].card->id.vers.pi[yyvsp[-2].card->id.vers.ns] = yyvsp[0].str;
+		    yyvsp[-2].card->id.vers.ns++;
+		}
+break;
+case 35:
+#line 285 "yacc_config.y"
+{
+		    if (yyvsp[-2].card->ident_type != 0) {
+			yyerror("ID method already defined\n");
+			YYERROR;
+		    }
+		    yyvsp[-2].card->ident_type = FUNC_IDENT;
+		    yyvsp[-2].card->id.func.funcid = yyvsp[0].num;
+		}
+break;
+case 36:
+#line 296 "yacc_config.y"
+{ yyvsp[-2].card->cis_file = strdup(yyvsp[0].str); }
+break;
+case 37:
+#line 300 "yacc_config.y"
+{
+		    if (add_binding(yyvsp[-2].card, yyvsp[0].str, 0) != 0)
+			YYERROR;
+		}
+break;
+case 38:
+#line 305 "yacc_config.y"
+{
+		    if (add_binding(yyvsp[-4].card, yyvsp[-2].str, yyvsp[0].num) != 0)
+			YYERROR;
+		}
+break;
+case 39:
+#line 310 "yacc_config.y"
+{
+		    if (add_binding(yyvsp[-2].card, yyvsp[0].str, 0) != 0)
+			YYERROR;
+		}
+break;
+case 40:
+#line 315 "yacc_config.y"
+{
+		    if (add_binding(yyvsp[-4].card, yyvsp[-2].str, yyvsp[0].num) != 0)
+			YYERROR;
+		}
+break;
+case 41:
+#line 322 "yacc_config.y"
+{
+		    yyvsp[-1].device->needs_mtd = 1;
+		}
+break;
+case 42:
+#line 328 "yacc_config.y"
+{
+		    device_info_t *d;
+		    int i, found = 0;
+		    for (d = root_device; d; d = d->next) {
+			for (i = 0; i < d->modules; i++)
+			    if (strcmp(yyvsp[-2].str, d->module[i]) == 0) break;
+			if (i < d->modules) {
+			    if (d->opts[i])
+				free(d->opts[i]);
+			    d->opts[i] = strdup(yyvsp[0].str);
+			    found = 1;
+			}
+		    }
+		    free(yyvsp[-2].str); free(yyvsp[0].str);
+		    if (!found) {
+			yyerror("module name not found!");
+			YYERROR;
+		    }
+		}
+break;
+case 43:
+#line 350 "yacc_config.y"
+{
+		    if (add_module(yyvsp[-2].device, yyvsp[0].str) != 0)
+			YYERROR;
+		}
+break;
+case 44:
+#line 355 "yacc_config.y"
+{
+		    if (yyvsp[-2].device->opts[yyvsp[-2].device->modules-1] == NULL) {
+			yyvsp[-2].device->opts[yyvsp[-2].device->modules-1] = yyvsp[0].str;
+		    } else {
+			yyerror("too many options");
+			YYERROR;
+		    }
+		}
+break;
+case 45:
+#line 364 "yacc_config.y"
+{
+		    if (add_module(yyvsp[-2].device, yyvsp[0].str) != 0)
+			YYERROR;
+		}
+break;
+case 46:
+#line 371 "yacc_config.y"
+{
+		    if (yyvsp[-2].device->class != NULL) {
+			yyerror("extra class string");
+			YYERROR;
+		    }
+		    yyvsp[-2].device->class = yyvsp[0].str;
+		}
+break;
+case 47:
+#line 381 "yacc_config.y"
+{
+		    yyval.mtd = calloc(sizeof(mtd_ident_t), 1);
+		    yyval.mtd->refs = 1;
+		    yyval.mtd->name = yyvsp[0].str;
+		}
+break;
+case 51:
+#line 392 "yacc_config.y"
+{
+		    if (yyvsp[-2].mtd->mtd_type != 0) {
+			yyerror("ID method already defined");
+			YYERROR;
+		    }
+		    yyvsp[-2].mtd->mtd_type = DTYPE_MTD;
+		    yyvsp[-2].mtd->dtype = yyvsp[0].num;
+		}
+break;
+case 52:
+#line 403 "yacc_config.y"
+{
+		    if (yyvsp[-3].mtd->mtd_type != 0) {
+			yyerror("ID method already defined");
+			YYERROR;
+		    }
+		    yyvsp[-3].mtd->mtd_type = JEDEC_MTD;
+		    yyvsp[-3].mtd->jedec_mfr = yyvsp[-1].num;
+		    yyvsp[-3].mtd->jedec_info = yyvsp[0].num;
+		}
+break;
+case 53:
+#line 415 "yacc_config.y"
+{
+		    if (yyvsp[-1].mtd->mtd_type != 0) {
+			yyerror("ID method already defined");
+			YYERROR;
+		    }
+		    if (default_mtd) {
+			yyerror("Default MTD already defined");
+			YYERROR;
+		    }
+		    yyvsp[-1].mtd->mtd_type = DEFAULT_MTD;
+		    default_mtd = yyvsp[-1].mtd;
+		}
+break;
+case 54:
+#line 430 "yacc_config.y"
+{
+		    if (yyvsp[-2].mtd->module != NULL) {
+			yyerror("extra MTD entry");
+			YYERROR;
+		    }
+		    yyvsp[-2].mtd->module = yyvsp[0].str;
+		}
+break;
+case 55:
+#line 438 "yacc_config.y"
+{
+		    if (yyvsp[-2].mtd->opts == NULL) {
+			yyvsp[-2].mtd->opts = yyvsp[0].str;
+		    } else {
+			yyerror("too many options");
+			YYERROR;
+		    }
+		}
+break;
+case 56:
+#line 449 "yacc_config.y"
+{
+		    mtd_ident_t *m;
+		    int found = 0;
+		    for (m = root_mtd; m; m = m->next)
+			if (strcmp(yyvsp[-2].str, m->module) == 0) break;
+		    if (m) {
+			if (m->opts) free(m->opts);
+			m->opts = strdup(yyvsp[0].str);
+			found = 1;
+		    }
+		    free(yyvsp[-2].str); free(yyvsp[0].str);
+		    if (!found) {
+			yyerror("MTD name not found!");
+			YYERROR;
+		    }
+		}
+break;
+#line 966 "y.tab.c"
+    }
+    yyssp -= yym;
+    yystate = *yyssp;
+    yyvsp -= yym;
+    yym = yylhs[yyn];
+    if (yystate == 0 && yym == 0)
+    {
+#if YYDEBUG
+        if (yydebug)
+            printf("%sdebug: after reduction, shifting from state 0 to\
+ state %d\n", YYPREFIX, YYFINAL);
+#endif
+        yystate = YYFINAL;
+        *++yyssp = YYFINAL;
+        *++yyvsp = yyval;
+        if (yychar < 0)
+        {
+            if ((yychar = yylex()) < 0) yychar = 0;
+#if YYDEBUG
+            if (yydebug)
+            {
+                yys = 0;
+                if (yychar <= YYMAXTOKEN) yys = yyname[yychar];
+                if (!yys) yys = "illegal-symbol";
+                printf("%sdebug: state %d, reading %d (%s)\n",
+                        YYPREFIX, YYFINAL, yychar, yys);
+            }
+#endif
+        }
+        if (yychar == 0) goto yyaccept;
+        goto yyloop;
+    }
+    if ((yyn = yygindex[yym]) && (yyn += yystate) >= 0 &&
+            yyn <= YYTABLESIZE && yycheck[yyn] == yystate)
+        yystate = yytable[yyn];
+    else
+        yystate = yydgoto[yym];
+#if YYDEBUG
+    if (yydebug)
+        printf("%sdebug: after reduction, shifting from state %d \
+to state %d\n", YYPREFIX, *yyssp, yystate);
+#endif
+    if (yyssp >= yyss + yystacksize - 1)
+    {
+        goto yyoverflow;
+    }
+    *++yyssp = yystate;
+    *++yyvsp = yyval;
+    goto yyloop;
+yyoverflow:
+    yyerror("yacc stack overflow");
+yyabort:
+    return (1);
+yyaccept:
+    return (0);
+}
Index: oldkernel/linux/pcmcia-cs-3.1.15/cardmgr/yacc_config.h
diff -u /dev/null linux/pcmcia-cs-3.1.15/cardmgr/yacc_config.h:1.1
--- /dev/null	Mon Jul 31 21:15:10 2000
+++ linux/pcmcia-cs-3.1.15/cardmgr/yacc_config.h	Fri Jul  7 16:34:58 2000
@@ -0,0 +1,37 @@
+#define DEVICE 257
+#define CARD 258
+#define ANONYMOUS 259
+#define TUPLE 260
+#define MANFID 261
+#define VERSION 262
+#define FUNCTION 263
+#define PCI 264
+#define BIND 265
+#define CIS 266
+#define TO 267
+#define NEEDS_MTD 268
+#define MODULE 269
+#define OPTS 270
+#define CLASS 271
+#define REGION 272
+#define JEDEC 273
+#define DTYPE 274
+#define DEFAULT 275
+#define MTD 276
+#define INCLUDE 277
+#define EXCLUDE 278
+#define RESERVE 279
+#define IRQ_NO 280
+#define PORT 281
+#define MEMORY 282
+#define STRING 283
+#define NUMBER 284
+typedef union {
+    char *str;
+    u_long num;
+    struct device_info_t *device;
+    struct card_info_t *card;
+    struct mtd_ident_t *mtd;
+    struct adjust_list_t *adjust;
+} YYSTYPE;
+extern YYSTYPE yylval;
Index: oldkernel/linux/pcmcia-cs-3.1.15/cardmgr/yacc_config.y
diff -u /dev/null linux/pcmcia-cs-3.1.15/cardmgr/yacc_config.y:1.1
--- /dev/null	Mon Jul 31 21:15:10 2000
+++ linux/pcmcia-cs-3.1.15/cardmgr/yacc_config.y	Fri Jul  7 16:34:58 2000
@@ -0,0 +1,529 @@
+%{
+/*
+ * yacc_config.y 1.49 1999/12/29 00:57: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@pcmcia.sourceforge.org>.  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 <stdlib.h>
+#include <stdarg.h>
+#include <stdio.h>
+#include <string.h>
+#include <syslog.h>
+#include <sys/types.h>
+
+#include <pcmcia/cs_types.h>
+#include <pcmcia/cs.h>
+#include <pcmcia/cistpl.h>
+#include <pcmcia/ds.h>
+    
+#include "cardmgr.h"
+
+/* If bison: generate nicer error messages */ 
+#define YYERROR_VERBOSE 1
+ 
+/* from lex_config, for nice error messages */
+extern char *current_file;
+extern int current_lineno;
+
+void yyerror(char *msg, ...);
+
+static int add_binding(card_info_t *card, char *name, int fn);
+static int add_module(device_info_t *card, char *name);
+
+%}
+
+%token DEVICE CARD ANONYMOUS TUPLE MANFID VERSION FUNCTION PCI
+%token BIND CIS TO NEEDS_MTD MODULE OPTS CLASS
+%token REGION JEDEC DTYPE DEFAULT MTD
+%token INCLUDE EXCLUDE RESERVE IRQ_NO PORT MEMORY
+%token STRING NUMBER
+
+%union {
+    char *str;
+    u_long num;
+    struct device_info_t *device;
+    struct card_info_t *card;
+    struct mtd_ident_t *mtd;
+    struct adjust_list_t *adjust;
+}
+
+%type <str> STRING
+%type <num> NUMBER
+%type <adjust> adjust resource
+%type <device> device needs_mtd module class
+%type <card> card anonymous tuple manfid pci version function bind cis
+%type <mtd> region jedec dtype default mtd
+%%
+
+list:	  /* nothing */
+	| list adjust
+		{
+		    adjust_list_t **tail = &root_adjust;
+		    while (*tail != NULL) tail = &(*tail)->next;
+		    *tail = $2;
+		}
+	| list device
+		{
+		    $2->next = root_device;
+		    root_device = $2;
+		}
+	| list mtd
+		{
+		    if ($2->mtd_type == 0) {
+			yyerror("no ID method for this card");
+			YYERROR;
+		    }
+		    if ($2->module == NULL) {
+			yyerror("no MTD module specified");
+			YYERROR;
+		    }
+		    $2->next = root_mtd;
+		    root_mtd = $2;
+		}
+	| list card
+		{
+		    if ($2->ident_type == 0) {
+			yyerror("no ID method for this card");
+			YYERROR;
+		    }
+		    if ($2->bindings == 0) {
+			yyerror("no function bindings");
+			YYERROR;
+		    }
+		    if ($2->ident_type == FUNC_IDENT) {
+			$2->next = root_func;
+			root_func = $2;
+		    } else {
+			$2->next = root_card;
+			root_card = $2;
+		    }
+		}
+	| list opts
+	| list mtd_opts
+	| list error
+	;
+
+adjust:   INCLUDE resource
+		{
+		    $2->adj.Action = ADD_MANAGED_RESOURCE;
+		    $$ = $2;
+		}
+	| EXCLUDE resource
+		{
+		    $2->adj.Action = REMOVE_MANAGED_RESOURCE;
+		    $$ = $2;
+		}
+	| RESERVE resource
+		{
+		    $2->adj.Action = ADD_MANAGED_RESOURCE;
+		    $2->adj.Attributes |= RES_RESERVED;
+		    $$ = $2;
+		}
+	| adjust ',' resource
+		{
+		    $3->adj.Action = $1->adj.Action;
+		    $3->adj.Attributes = $1->adj.Attributes;
+		    $3->next = $1;
+		    $$ = $3;
+		}
+	;
+
+resource: IRQ_NO NUMBER
+		{
+		    $$ = calloc(sizeof(adjust_list_t), 1);
+		    $$->adj.Resource = RES_IRQ;
+		    $$->adj.resource.irq.IRQ = $2;
+		}
+	| PORT NUMBER '-' NUMBER
+		{
+		    if (($4 < $2) || ($4 > 0xffff)) {
+			yyerror("invalid port range");
+			YYERROR;
+		    }
+		    $$ = calloc(sizeof(adjust_list_t), 1);
+		    $$->adj.Resource = RES_IO_RANGE;
+		    $$->adj.resource.io.BasePort = $2;
+		    $$->adj.resource.io.NumPorts = $4 - $2 + 1;
+		}
+	| MEMORY NUMBER '-' NUMBER
+		{
+		    if ($4 < $2) {
+			yyerror("invalid address range");
+			YYERROR;
+		    }
+		    $$ = calloc(sizeof(adjust_list_t), 1);
+		    $$->adj.Resource = RES_MEMORY_RANGE;
+		    $$->adj.resource.memory.Base = $2;
+		    $$->adj.resource.memory.Size = $4 - $2 + 1;
+		}
+	;
+
+device:	  DEVICE STRING
+		{
+		    $$ = calloc(sizeof(device_info_t), 1);
+		    $$->refs = 1;
+		    strcpy($$->dev_info, $2);
+		    free($2);
+		}
+	| needs_mtd
+	| module
+	| class
+	;
+
+card:	  CARD STRING
+		{
+		    $$ = calloc(sizeof(card_info_t), 1);
+		    $$->refs = 1;
+		    $$->name = $2;
+		}
+	| anonymous
+	| tuple
+	| manfid
+	| pci
+	| version
+	| function
+	| bind
+	| cis
+	;
+
+anonymous: card ANONYMOUS
+		{
+		    if ($1->ident_type != 0) {
+			yyerror("ID method already defined");
+			YYERROR;
+		    }
+		    if (blank_card) {
+			yyerror("Anonymous card already defined");
+			YYERROR;
+		    }
+		    $1->ident_type = BLANK_IDENT;
+		    blank_card = $1;
+		}
+	;
+
+tuple:	  card TUPLE NUMBER ',' NUMBER ',' STRING
+		{
+		    if ($1->ident_type != 0) {
+			yyerror("ID method already defined");
+			YYERROR;
+		    }
+		    $1->ident_type = TUPLE_IDENT;
+		    $1->id.tuple.code = $3;
+		    $1->id.tuple.ofs = $5;
+		    $1->id.tuple.info = $7;
+		}
+	;
+
+manfid:	  card MANFID NUMBER ',' NUMBER
+		{
+		    if ($1->ident_type != 0) {
+			yyerror("ID method already defined");
+			YYERROR;
+		    }
+		    $1->ident_type = MANFID_IDENT;
+		    $1->id.manfid.manf = $3;
+		    $1->id.manfid.card = $5;
+		}
+
+pci:	  card PCI NUMBER ',' NUMBER
+		{
+		    if ($1->ident_type != 0) {
+			yyerror("ID method already defined");
+			YYERROR;
+		    }
+		    $1->ident_type = PCI_IDENT;
+		    $1->id.manfid.manf = $3;
+		    $1->id.manfid.card = $5;
+		}
+
+version:  card VERSION STRING
+		{
+		    if ($1->ident_type != 0) {
+			yyerror("ID method already defined\n");
+			YYERROR;
+		    }
+		    $1->ident_type = VERS_1_IDENT;
+		    $1->id.vers.ns = 1;
+		    $1->id.vers.pi[0] = $3;
+		}
+	| version ',' STRING
+		{
+		    if ($1->id.vers.ns == 4) {
+			yyerror("too many version strings");
+			YYERROR;
+		    }
+		    $1->id.vers.pi[$1->id.vers.ns] = $3;
+		    $1->id.vers.ns++;
+		}
+	;
+
+function: card FUNCTION NUMBER
+		{
+		    if ($1->ident_type != 0) {
+			yyerror("ID method already defined\n");
+			YYERROR;
+		    }
+		    $1->ident_type = FUNC_IDENT;
+		    $1->id.func.funcid = $3;
+		}
+	;
+
+cis:	  card CIS STRING
+		{ $1->cis_file = strdup($3); }
+	;
+
+bind:	  card BIND STRING
+		{
+		    if (add_binding($1, $3, 0) != 0)
+			YYERROR;
+		}
+	| card BIND STRING TO NUMBER
+		{
+		    if (add_binding($1, $3, $5) != 0)
+			YYERROR;
+		}
+	| bind ',' STRING
+		{
+		    if (add_binding($1, $3, 0) != 0)
+			YYERROR;
+		}
+	| bind ',' STRING TO NUMBER
+		{
+		    if (add_binding($1, $3, $5) != 0)
+			YYERROR;
+		}
+	;
+
+needs_mtd: device NEEDS_MTD
+		{
+		    $1->needs_mtd = 1;
+		}
+	;
+
+opts:	  MODULE STRING OPTS STRING
+		{
+		    device_info_t *d;
+		    int i, found = 0;
+		    for (d = root_device; d; d = d->next) {
+			for (i = 0; i < d->modules; i++)
+			    if (strcmp($2, d->module[i]) == 0) break;
+			if (i < d->modules) {
+			    if (d->opts[i])
+				free(d->opts[i]);
+			    d->opts[i] = strdup($4);
+			    found = 1;
+			}
+		    }
+		    free($2); free($4);
+		    if (!found) {
+			yyerror("module name not found!");
+			YYERROR;
+		    }
+		}
+	;
+
+module:	  device MODULE STRING
+		{
+		    if (add_module($1, $3) != 0)
+			YYERROR;
+		}
+	| module OPTS STRING
+		{
+		    if ($1->opts[$1->modules-1] == NULL) {
+			$1->opts[$1->modules-1] = $3;
+		    } else {
+			yyerror("too many options");
+			YYERROR;
+		    }
+		}
+	| module ',' STRING
+		{
+		    if (add_module($1, $3) != 0)
+			YYERROR;
+		}
+	;
+
+class:	  device CLASS STRING
+		{
+		    if ($1->class != NULL) {
+			yyerror("extra class string");
+			YYERROR;
+		    }
+		    $1->class = $3;
+		}
+	;
+
+region:	  REGION STRING
+		{
+		    $$ = calloc(sizeof(mtd_ident_t), 1);
+		    $$->refs = 1;
+		    $$->name = $2;
+		}
+	| dtype
+	| jedec
+	| default
+	;
+
+dtype:	  region DTYPE NUMBER
+		{
+		    if ($1->mtd_type != 0) {
+			yyerror("ID method already defined");
+			YYERROR;
+		    }
+		    $1->mtd_type = DTYPE_MTD;
+		    $1->dtype = $3;
+		}
+	;
+
+jedec:	  region JEDEC NUMBER NUMBER
+		{
+		    if ($1->mtd_type != 0) {
+			yyerror("ID method already defined");
+			YYERROR;
+		    }
+		    $1->mtd_type = JEDEC_MTD;
+		    $1->jedec_mfr = $3;
+		    $1->jedec_info = $4;
+		}
+	;
+
+default:  region DEFAULT
+		{
+		    if ($1->mtd_type != 0) {
+			yyerror("ID method already defined");
+			YYERROR;
+		    }
+		    if (default_mtd) {
+			yyerror("Default MTD already defined");
+			YYERROR;
+		    }
+		    $1->mtd_type = DEFAULT_MTD;
+		    default_mtd = $1;
+		}
+	;
+
+mtd:	  region MTD STRING
+		{
+		    if ($1->module != NULL) {
+			yyerror("extra MTD entry");
+			YYERROR;
+		    }
+		    $1->module = $3;
+		}
+	| mtd OPTS STRING
+		{
+		    if ($1->opts == NULL) {
+			$1->opts = $3;
+		    } else {
+			yyerror("too many options");
+			YYERROR;
+		    }
+		}
+	;
+
+mtd_opts:  MTD STRING OPTS STRING
+		{
+		    mtd_ident_t *m;
+		    int found = 0;
+		    for (m = root_mtd; m; m = m->next)
+			if (strcmp($2, m->module) == 0) break;
+		    if (m) {
+			if (m->opts) free(m->opts);
+			m->opts = strdup($4);
+			found = 1;
+		    }
+		    free($2); free($4);
+		    if (!found) {
+			yyerror("MTD name not found!");
+			YYERROR;
+		    }
+		}
+	;
+
+%%
+void yyerror(char *msg, ...)
+{
+     va_list ap;
+     char str[256];
+
+     va_start(ap, msg);
+     sprintf(str, "config error, file '%s' line %d: ",
+	     current_file, current_lineno);
+     vsprintf(str+strlen(str), msg, ap);
+#if YYDEBUG
+     fprintf(stderr, "%s\n", str);
+#else
+     syslog(LOG_INFO, "%s", str);
+#endif
+     va_end(ap);
+}
+
+static int add_binding(card_info_t *card, char *name, int fn)
+{
+    device_info_t *dev = root_device;
+    if (card->bindings == MAX_BINDINGS) {
+	yyerror("too many bindings\n");
+	return -1;
+    }
+    for (; dev; dev = dev->next)
+	if (strcmp((char *)dev->dev_info, name) == 0) break;
+    if (dev == NULL) {
+	yyerror("unknown device: %s", name);
+	return -1;
+    }
+    card->device[card->bindings] = dev;
+    card->dev_fn[card->bindings] = fn;
+    card->bindings++;
+    free(name);
+    return 0;
+}
+
+static int add_module(device_info_t *dev, char *name)
+{
+    if (dev->modules == MAX_MODULES) {
+	yyerror("too many modules");
+	return -1;
+    }
+    dev->module[dev->modules] = name;
+    dev->opts[dev->modules] = NULL;
+    dev->modules++;
+    return 0;
+}
+
+#if YYDEBUG
+adjust_list_t *root_adjust = NULL;
+device_info_t *root_device = NULL;
+card_info_t *root_card = NULL, *blank_card = NULL, *root_func = NULL;
+mtd_ident_t *root_mtd = NULL, *default_mtd = NULL;
+
+void main(int argc, char *argv[])
+{
+    yydebug = 1;
+    if (argc > 1)
+	parse_configfile(argv[1]);
+}
+#endif
Index: oldkernel/linux/pcmcia-cs-3.1.15/clients/3c574_cs.c
diff -u /dev/null linux/pcmcia-cs-3.1.15/clients/3c574_cs.c:1.1
--- /dev/null	Mon Jul 31 21:15:10 2000
+++ linux/pcmcia-cs-3.1.15/clients/3c574_cs.c	Fri Jul  7 16:34:58 2000
@@ -0,0 +1,1341 @@
+/* 3c574.c: A PCMCIA ethernet driver for the 3com 3c574 "RoadRunner".
+
+	Written 1993-1998 by
+	Donald Becker, becker@cesdis.gsfc.nasa.gov, (driver core) and
+	David Hinds, dhinds@pcmcia.sourceforge.org (from his PC card code).
+
+	This software may be used and distributed according to the terms of
+	the GNU Public License, incorporated herein by reference.
+
+	This driver derives from Donald Becker's 3c509 core, which has the
+	following copyright:
+	Copyright 1993 United States Government as represented by the
+	Director, National Security Agency.
+
+*/
+
+/* Driver author info must always be in the binary.  Version too.. */
+static const char *tc574_version =
+"3c574_cs.c v1.08 9/24/98 Donald Becker/David Hinds, becker@cesdis.gsfc.nasa.gov.\n";
+
+/*
+				Theory of Operation
+
+I. Board Compatibility
+
+This device driver is designed for the 3Com 3c574 PC card Fast Ethernet
+Adapter.
+
+II. Board-specific settings
+
+None -- PC cards are autoconfigured.
+
+III. Driver operation
+
+The 3c574 uses a Boomerang-style interface, without the bus-master capability.
+See the Boomerang driver and documentation for most details.
+
+IV. Notes and chip documentation.
+
+Two added registers are used to enhance PIO performance, RunnerRdCtrl and
+RunnerWrCtrl.  These are 11 bit down-counters that are preloaded with the
+count of word (16 bits) reads or writes the driver is about to do to the Rx
+or Tx FIFO.  The chip is then able to hide the internal-PCI-bus to PC-card
+translation latency by buffering the I/O operations with an 8 word FIFO.
+Note: No other chip accesses are permitted when this buffer is used.
+
+A second enhancement is that both attribute and common memory space
+0x0800-0x0fff can translated to the PIO FIFO.  Thus memory operations (faster
+with *some* PCcard bridges) may be used instead of I/O operations.
+This is enabled by setting the 0x10 bit in the PCMCIA LAN COR.
+
+Some slow PC card bridges work better if they never see a WAIT signal.
+This is configured by setting the 0x20 bit in the PCMCIA LAN COR.
+Only do this after testing that it is reliable and improves performance.
+
+The upper five bits of RunnerRdCtrl are used to window into PCcard
+configuration space registers.  Window 0 is the regular Boomerang/Odie
+register set, 1-5 are various PC card control registers, and 16-31 are
+the (reversed!) CIS table.
+
+A final note: writing the InternalConfig register in window 3 with an
+invalid ramWidth is Very Bad.
+
+V. References
+
+http://cesdis.gsfc.nasa.gov/linux/misc/NWay.html
+http://www.national.com/pf/DP/DP83840.html
+
+Thanks to Terry Murphy of 3Com for providing development information for
+earlier 3Com products.
+
+*/
+
+#include <pcmcia/config.h>
+#include <pcmcia/k_compat.h>
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/sched.h>
+#include <linux/malloc.h>
+#include <linux/string.h>
+#include <linux/timer.h>
+#include <linux/interrupt.h>
+#include <linux/in.h>
+#include <linux/delay.h>
+#include <asm/io.h>
+#include <asm/system.h>
+#include <asm/bitops.h>
+
+#include <linux/netdevice.h>
+#include <linux/etherdevice.h>
+#include <linux/skbuff.h>
+#include <linux/if_arp.h>
+#include <linux/ioport.h>
+
+#include <pcmcia/version.h>
+#include <pcmcia/cs_types.h>
+#include <pcmcia/cs.h>
+#include <pcmcia/cistpl.h>
+#include <pcmcia/cisreg.h>
+#include <pcmcia/ciscode.h>
+#include <pcmcia/ds.h>
+#include <pcmcia/mem_op.h>
+
+/* A few values that may be tweaked. */
+MODULE_PARM(irq_mask, "i");
+MODULE_PARM(irq_list, "1-4i");
+MODULE_PARM(max_interrupt_work, "i");
+MODULE_PARM(full_duplex, "i");
+
+/* Now-standard PC card module parameters. */
+static u_int irq_mask = 0xdeb8;			/* IRQ3,4,5,7,9,10,11,12,14,15 */
+static int irq_list[4] = { -1 };
+
+/* Time in jiffies before concluding the transmitter is hung. */
+#define TX_TIMEOUT  ((800*HZ)/1000)
+
+/* Maximum events (Rx packets, etc.) to handle at each interrupt. */
+static int max_interrupt_work = 32;
+
+/* Force full duplex modes? */
+static int full_duplex = 0;
+
+/* To minimize the size of the driver source and make the driver more
+   readable not all constants are symbolically defined.
+   You'll need the manual if you want to understand driver details anyway. */
+/* Offsets from base I/O address. */
+#define EL3_DATA	0x00
+#define EL3_CMD		0x0e
+#define EL3_STATUS	0x0e
+
+#define EL3WINDOW(win_num) outw(SelectWindow + (win_num), ioaddr + EL3_CMD)
+
+/* The top five bits written to EL3_CMD are a command, the lower
+   11 bits are the parameter, if applicable. */
+enum el3_cmds {
+	TotalReset = 0<<11, SelectWindow = 1<<11, StartCoax = 2<<11,
+	RxDisable = 3<<11, RxEnable = 4<<11, RxReset = 5<<11, RxDiscard = 8<<11,
+	TxEnable = 9<<11, TxDisable = 10<<11, TxReset = 11<<11,
+	FakeIntr = 12<<11, AckIntr = 13<<11, SetIntrEnb = 14<<11,
+	SetStatusEnb = 15<<11, SetRxFilter = 16<<11, SetRxThreshold = 17<<11,
+	SetTxThreshold = 18<<11, SetTxStart = 19<<11, StatsEnable = 21<<11,
+	StatsDisable = 22<<11, StopCoax = 23<<11,
+};
+
+enum elxl_status {
+	IntLatch = 0x0001, AdapterFailure = 0x0002, TxComplete = 0x0004,
+	TxAvailable = 0x0008, RxComplete = 0x0010, RxEarly = 0x0020,
+	IntReq = 0x0040, StatsFull = 0x0080, CmdBusy = 0x1000 };
+
+/* The SetRxFilter command accepts the following classes: */
+enum RxFilter {
+	RxStation = 1, RxMulticast = 2, RxBroadcast = 4, RxProm = 8
+};
+
+enum Window0 {
+	Wn0EepromCmd = 10, Wn0EepromData = 12, /* EEPROM command/address, data. */
+	IntrStatus=0x0E,		/* Valid in all windows. */
+};
+/* These assumes the larger EEPROM. */
+enum Win0_EEPROM_cmds {
+	EEPROM_Read = 0x200, EEPROM_WRITE = 0x100, EEPROM_ERASE = 0x300,
+	EEPROM_EWENB = 0x30,		/* Enable erasing/writing for 10 msec. */
+	EEPROM_EWDIS = 0x00,		/* Disable EWENB before 10 msec timeout. */
+};
+
+/* Register window 1 offsets, the window used in normal operation.
+   On the "Odie" this window is always mapped at offsets 0x10-0x1f.
+   Except for TxFree, which is overlapped by RunnerWrCtrl. */
+enum Window1 {
+	TX_FIFO = 0x10,  RX_FIFO = 0x10,  RxErrors = 0x14,
+	RxStatus = 0x18,  Timer=0x1A, TxStatus = 0x1B,
+	TxFree = 0x0C, /* Remaining free bytes in Tx buffer. */
+	RunnerRdCtrl = 0x16, RunnerWrCtrl = 0x1c,
+};
+
+enum Window3 {			/* Window 3: MAC/config bits. */
+	Wn3_Config=0, Wn3_MAC_Ctrl=6, Wn3_Options=8,
+};
+union wn3_config {
+	int i;
+	struct w3_config_fields {
+		unsigned int ram_size:3, ram_width:1, ram_speed:2, rom_size:2;
+		int pad8:8;
+		unsigned int ram_split:2, pad18:2, xcvr:3, pad21:1, autoselect:1;
+		int pad24:7;
+	} u;
+};
+
+enum Window4 {		/* Window 4: Xcvr/media bits. */
+	Wn4_FIFODiag = 4, Wn4_NetDiag = 6, Wn4_PhysicalMgmt=8, Wn4_Media = 10,
+};
+
+
+#define MEDIA_TP	0x00C0	/* Enable link beat and jabber for 10baseT. */
+
+struct el3_private {
+	dev_link_t link;
+	struct net_device dev;
+	dev_node_t node;
+	struct net_device_stats stats;
+	u16 advertising, partner;			/* NWay media advertisement */
+	unsigned char phys[2];				/* MII device addresses. */
+	unsigned int
+	  autoselect:1, default_media:3;	/* Read from the EEPROM/Wn3_Config. */
+	/* for transceiver monitoring */
+	struct timer_list media;
+	u_short media_status;
+	u_short fast_poll;
+	u_long last_irq;
+};
+
+/* Set iff a MII transceiver on any interface requires mdio preamble.
+   This only set with the original DP83840 on older 3c905 boards, so the extra
+   code size of a per-interface flag is not worthwhile. */
+static char mii_preamble_required = 0;
+
+#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 =
+"3c574_cs.c 1.000 1998/1/8 Donald Becker, becker@cesdis.gsfc.nasa.gov.\n";
+#else
+#define DEBUG(n, args...)
+#endif
+
+/* Index of functions. */
+
+static void tc574_config(dev_link_t *link);
+static void tc574_release(u_long arg);
+static int tc574_event(event_t event, int priority,
+					   event_callback_args_t *args);
+
+static void mdio_sync(ioaddr_t ioaddr, int bits);
+static int mdio_read(ioaddr_t ioaddr, int phy_id, int location);
+static void mdio_write(ioaddr_t ioaddr, int phy_id, int location, int value);
+static u_short read_eeprom(ioaddr_t ioaddr, int index);
+static void wait_for_completion(struct net_device *dev, int cmd);
+
+static void tc574_reset(struct net_device *dev);
+static void media_check(u_long arg);
+static int el3_open(struct net_device *dev);
+static int el3_start_xmit(struct sk_buff *skb, struct net_device *dev);
+static void el3_interrupt(int irq, void *dev_id, struct pt_regs *regs);
+static void update_stats(struct net_device *dev);
+static struct net_device_stats *el3_get_stats(struct net_device *dev);
+static int el3_rx(struct net_device *dev, int worklimit);
+static int el3_close(struct net_device *dev);
+static void el3_tx_timeout(struct net_device *dev);
+static int el3_ioctl(struct net_device *dev, struct ifreq *rq, int cmd);
+static void set_rx_mode(struct net_device *dev);
+
+static dev_info_t dev_info = "3c574_cs";
+
+static dev_link_t *tc574_attach(void);
+static void tc574_detach(dev_link_t *);
+
+static dev_link_t *dev_list = NULL;
+
+static void flush_stale_links(void)
+{
+	dev_link_t *link, *next;
+	for (link = dev_list; link; link = next) {
+		next = link->next;
+	    if (link->state & DEV_STALE_LINK)
+			tc574_detach(link);
+    }
+}
+
+static void cs_error(client_handle_t handle, int func, int ret)
+{
+#if CS_RELEASE_CODE < 0x2911
+    CardServices(ReportError, dev_info, (void *)func, (void *)ret);
+#else
+	error_info_t err = { func, ret };
+	CardServices(ReportError, handle, &err);
+#endif
+}
+
+/*
+	tc574_attach() creates an "instance" of the driver, allocating
+	local data structures for one device.  The device is registered
+	with Card Services.
+*/
+
+static dev_link_t *tc574_attach(void)
+{
+	struct el3_private *lp;
+	client_reg_t client_reg;
+	dev_link_t *link;
+	struct net_device *dev;
+	int i, ret;
+
+	DEBUG(0, "3c574_attach()\n");
+	flush_stale_links();
+
+	/* Create the PC card device object. */
+	lp = kmalloc(sizeof(*lp), GFP_KERNEL);
+	if (!lp) return NULL;
+	memset(lp, 0, sizeof(*lp));
+	link = &lp->link; dev = &lp->dev;
+	link->priv = dev->priv = link->irq.Instance = lp;
+	
+	link->release.function = &tc574_release;
+	link->release.data = (u_long)link;
+	link->io.NumPorts1 = 32;
+	link->io.Attributes1 = IO_DATA_PATH_WIDTH_16;
+	link->irq.Attributes = IRQ_TYPE_EXCLUSIVE | IRQ_HANDLE_PRESENT;
+	link->irq.IRQInfo1 = IRQ_INFO2_VALID|IRQ_LEVEL_ID;
+	if (irq_list[0] == -1)
+		link->irq.IRQInfo2 = irq_mask;
+	else
+		for (i = 0; i < 4; i++)
+			link->irq.IRQInfo2 |= 1 << irq_list[i];
+	link->irq.Handler = &el3_interrupt;
+	link->conf.Attributes = CONF_ENABLE_IRQ;
+	link->conf.Vcc = 50;
+	link->conf.IntType = INT_MEMORY_AND_IO;
+	link->conf.ConfigIndex = 1;
+	link->conf.Present = PRESENT_OPTION;
+
+	/* The EL3-specific entries in the device structure. */
+	dev->hard_start_xmit = &el3_start_xmit;
+	dev->get_stats = &el3_get_stats;
+	dev->do_ioctl = &el3_ioctl;
+	dev->set_multicast_list = &set_rx_mode;
+	ether_setup(dev);
+	dev->name = lp->node.dev_name;
+	dev->open = &el3_open;
+	dev->stop = &el3_close;
+#ifdef HAVE_NETIF_QUEUE
+	dev->tx_timeout = el3_tx_timeout;
+	dev->watchdog_timeo = TX_TIMEOUT;
+#endif
+
+	/* Register with Card Services */
+	link->next = dev_list;
+	dev_list = link;
+	client_reg.dev_info = &dev_info;
+	client_reg.Attributes = INFO_IO_CLIENT | INFO_CARD_SHARE;
+	client_reg.EventMask =
+		CS_EVENT_CARD_INSERTION | CS_EVENT_CARD_REMOVAL |
+			CS_EVENT_RESET_PHYSICAL | CS_EVENT_CARD_RESET |
+				CS_EVENT_PM_SUSPEND | CS_EVENT_PM_RESUME;
+	client_reg.event_handler = &tc574_event;
+	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);
+		tc574_detach(link);
+		return NULL;
+	}
+
+	return link;
+} /* tc574_attach */
+
+/*
+
+	This deletes a driver "instance".  The device is de-registered
+	with Card Services.  If it has been released, all local data
+	structures are freed.  Otherwise, the structures will be freed
+	when the device is released.
+
+*/
+
+static void tc574_detach(dev_link_t *link)
+{
+	struct el3_private *lp = link->priv;
+	dev_link_t **linkp;
+
+	DEBUG(0, "3c574_detach(0x%p)\n", link);
+
+	/* Locate device structure */
+	for (linkp = &dev_list; *linkp; linkp = &(*linkp)->next)
+		if (*linkp == link) break;
+	if (*linkp == NULL)
+	return;
+
+	del_timer(&link->release);
+	if (link->state & DEV_CONFIG) {
+		tc574_release((u_long)link);
+		if (link->state & DEV_STALE_CONFIG) {
+			link->state |= DEV_STALE_LINK;
+			return;
+		}
+	}
+
+	if (link->handle)
+		CardServices(DeregisterClient, link->handle);
+
+	/* Unlink device structure, free bits */
+	*linkp = link->next;
+	if (link->dev)
+		unregister_netdev(&lp->dev);
+	kfree(lp);
+
+} /* tc574_detach */
+
+/*
+	tc574_config() is scheduled to run after a CARD_INSERTION event
+	is received, to configure the PCMCIA socket, and to make the
+	ethernet device available to the system.
+*/
+
+#define CS_CHECK(fn, args...) \
+while ((last_ret=CardServices(last_fn=(fn), args))!=0) goto cs_failed
+
+static void tc574_config(dev_link_t *link)
+{
+	client_handle_t handle = link->handle;
+	struct el3_private *lp = link->priv;
+	struct net_device *dev = &lp->dev;
+	tuple_t tuple;
+	cisparse_t parse;
+	u_short buf[32];
+	int last_fn, last_ret, i, j;
+	ioaddr_t ioaddr;
+	u16 *phys_addr;
+	char *cardname;
+
+	phys_addr = (u16 *)dev->dev_addr;
+
+	DEBUG(0, "3c574_config(0x%p)\n", link);
+
+	tuple.Attributes = 0;
+	tuple.DesiredTuple = CISTPL_CONFIG;
+	CS_CHECK(GetFirstTuple, handle, &tuple);
+	tuple.TupleData = (cisdata_t *)buf;
+	tuple.TupleDataMax = 64;
+	tuple.TupleOffset = 0;
+	CS_CHECK(GetTupleData, handle, &tuple);
+	CS_CHECK(ParseTuple, handle, &tuple, &parse);
+	link->conf.ConfigBase = parse.config.base;
+	link->conf.Present = parse.config.rmask[0];
+
+	/* Configure card */
+	link->state |= DEV_CONFIG;
+
+	link->io.IOAddrLines = 16;
+	for (i = j = 0; j < 0x400; j += 0x20) {
+		link->io.BasePort1 = j ^ 0x300;
+		i = CardServices(RequestIO, link->handle, &link->io);
+		if (i == CS_SUCCESS) break;
+	}
+	if (i != CS_SUCCESS) {
+		cs_error(link->handle, RequestIO, i);
+		goto failed;
+	}
+	CS_CHECK(RequestIRQ, link->handle, &link->irq);
+	CS_CHECK(RequestConfiguration, link->handle, &link->conf);
+
+	dev->irq = link->irq.AssignedIRQ;
+	dev->base_addr = link->io.BasePort1;
+
+	if (register_netdev(dev) != 0) {
+		printk(KERN_NOTICE "3c574_cs: register_netdev() failed\n");
+		goto failed;
+	}
+
+	ioaddr = dev->base_addr;
+	link->dev = &lp->node;
+	link->state &= ~DEV_CONFIG_PENDING;
+
+	/* The 3c574 normally uses an EEPROM for configuration info, including
+	   the hardware address.  The future products may include a modem chip
+	   and put the address in the CIS. */
+	tuple.DesiredTuple = 0x88;
+	if (CardServices(GetFirstTuple, handle, &tuple) == CS_SUCCESS) {
+		CardServices(GetTupleData, handle, &tuple);
+		for (i = 0; i < 3; i++)
+			phys_addr[i] = htons(buf[i]);
+	} else {
+		EL3WINDOW(0);
+		for (i = 0; i < 3; i++)
+			phys_addr[i] = htons(read_eeprom(ioaddr, i + 10));
+		if (phys_addr[0] == 0x6060) {
+			printk(KERN_NOTICE "3c574_cs: IO port conflict at 0x%03lx"
+				   "-0x%03lx\n", dev->base_addr, dev->base_addr+15);
+			goto failed;
+		}
+	}
+	tuple.DesiredTuple = CISTPL_VERS_1;
+	if (CardServices(GetFirstTuple, handle, &tuple) == CS_SUCCESS &&
+		CardServices(GetTupleData, handle, &tuple) == CS_SUCCESS &&
+		CardServices(ParseTuple, handle, &tuple, &parse) == CS_SUCCESS) {
+		cardname = parse.version_1.str + parse.version_1.ofs[1];
+	} else
+		cardname = "3Com 3c574";
+
+	printk(KERN_INFO "%s: %s at io %#3lx, irq %d, hw_addr ",
+		   dev->name, cardname, dev->base_addr, dev->irq);
+
+	for (i = 0; i < 6; i++)
+		printk("%02X%s", dev->dev_addr[i], ((i<5) ? ":" : ".\n"));
+
+	{
+		u_char mcr, *ram_split[] = {"5:3", "3:1", "1:1", "3:5"};
+		union wn3_config config;
+		outw(2<<11, ioaddr + RunnerRdCtrl);
+		mcr = inb(ioaddr + 2);
+		outw(0<<11, ioaddr + RunnerRdCtrl);
+		printk(KERN_INFO "  ASIC rev %d,", mcr>>3);
+		EL3WINDOW(3);
+		config.i = inl(ioaddr + Wn3_Config);
+		printk(" %dK FIFO split %s Rx:Tx, %sMII interface.\n",
+			   8 << config.u.ram_size, ram_split[config.u.ram_split],
+			   config.u.autoselect ? "autoselect " : "");
+		lp->default_media = config.u.xcvr;
+		lp->autoselect = config.u.autoselect;
+	}
+
+	{
+		int phy, phy_idx = 0;
+		
+		/* Roadrunner only: Turn on the MII transceiver */
+		outw(0x8040, ioaddr + Wn3_Options);
+		udelay(1000);
+		outw(0xc040, ioaddr + Wn3_Options);
+		wait_for_completion(dev, TxReset);
+		wait_for_completion(dev, RxReset);
+		udelay(1000);
+		outw(0x8040, ioaddr + Wn3_Options);
+		
+		EL3WINDOW(4);
+		for (phy = 1; phy <= 32 && phy_idx < sizeof(lp->phys); phy++) {
+			int mii_status;
+			mdio_sync(ioaddr, 32);
+			mii_status = mdio_read(ioaddr, phy & 0x1f, 1);
+			if (mii_status != 0xffff) {
+				lp->phys[phy_idx++] = phy & 0x1f;
+				DEBUG(0, "  MII transceiver at index %d, status %x.\n",
+					  phy, mii_status);
+				if ((mii_status & 0x0040) == 0)
+					mii_preamble_required = 1;
+			}
+		}
+		if (phy_idx == 0) {
+			printk(KERN_NOTICE "  No MII transceivers found!\n");
+			goto failed;
+		}
+		i = mdio_read(ioaddr, lp->phys[0], 16) | 0x40;
+		mdio_write(ioaddr, lp->phys[0], 16, i);
+		lp->advertising = mdio_read(ioaddr, lp->phys[0], 4);
+		if (full_duplex) {
+			/* Only advertise the FD media types. */
+			lp->advertising &= ~0x02a0;
+			mdio_write(ioaddr, lp->phys[0], 4, lp->advertising);
+		}
+	}
+
+	return;
+
+cs_failed:
+	cs_error(link->handle, last_fn, last_ret);
+failed:
+	tc574_release((u_long)link);
+	return;
+
+} /* tc574_config */
+
+/*
+	After a card is removed, tc574_release() will unregister the net
+	device, and release the PCMCIA configuration.  If the device is
+	still open, this will be postponed until it is closed.
+*/
+
+static void tc574_release(u_long arg)
+{
+	dev_link_t *link = (dev_link_t *)arg;
+
+	DEBUG(0, "3c574_release(0x%p)\n", link);
+
+	if (link->open) {
+		DEBUG(1, "3c574_cs: release postponed, '%s' still open\n",
+			  link->dev->dev_name);
+		link->state |= DEV_STALE_CONFIG;
+		return;
+	}
+
+	CardServices(ReleaseConfiguration, link->handle);
+	CardServices(ReleaseIO, link->handle, &link->io);
+	CardServices(ReleaseIRQ, link->handle, &link->irq);
+
+	link->state &= ~DEV_CONFIG;
+
+} /* tc574_release */
+
+/*
+	The card status event handler.  Mostly, this schedules other
+	stuff to run after an event is received.  A CARD_REMOVAL event
+	also sets some flags to discourage the net drivers from trying
+	to talk to the card any more.
+*/
+
+static int tc574_event(event_t event, int priority,
+					   event_callback_args_t *args)
+{
+	dev_link_t *link = args->client_data;
+	struct el3_private *lp = link->priv;
+	struct net_device *dev = &lp->dev;
+
+	DEBUG(1, "3c574_event(0x%06x)\n", event);
+
+	switch (event) {
+	case CS_EVENT_CARD_REMOVAL:
+		link->state &= ~DEV_PRESENT;
+		if (link->state & DEV_CONFIG) {
+			netif_device_detach(dev);
+			mod_timer(&link->release, jiffies + HZ/20);
+		}
+		break;
+	case CS_EVENT_CARD_INSERTION:
+		link->state |= DEV_PRESENT | DEV_CONFIG_PENDING;
+		tc574_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 (link->open)
+				netif_device_detach(dev);
+			CardServices(ReleaseConfiguration, link->handle);
+		}
+		break;
+	case CS_EVENT_PM_RESUME:
+		link->state &= ~DEV_SUSPEND;
+		/* Fall through... */
+	case CS_EVENT_CARD_RESET:
+		if (link->state & DEV_CONFIG) {
+			CardServices(RequestConfiguration, link->handle, &link->conf);
+			if (link->open) {
+				tc574_reset(dev);
+				netif_device_attach(dev);
+			}
+		}
+		break;
+	}
+	return 0;
+} /* tc574_event */
+
+static void dump_status(struct net_device *dev)
+{
+	ioaddr_t ioaddr = dev->base_addr;
+	EL3WINDOW(1);
+    printk(KERN_INFO "  irq status %04x, rx status %04x, tx status "
+		   "%02x, tx free %04x\n", inw(ioaddr+EL3_STATUS),
+		   inw(ioaddr+RxStatus), inb(ioaddr+TxStatus),
+		   inw(ioaddr+TxFree));
+	EL3WINDOW(4);
+    printk(KERN_INFO "  diagnostics: fifo %04x net %04x ethernet %04x"
+		   " media %04x\n", inw(ioaddr+0x04), inw(ioaddr+0x06),
+		   inw(ioaddr+0x08), inw(ioaddr+0x0a));
+	EL3WINDOW(1);
+}
+
+/*
+  Use this for commands that may take time to finish
+*/
+static void wait_for_completion(struct net_device *dev, int cmd)
+{
+    int i = 1500;
+    outw(cmd, dev->base_addr + EL3_CMD);
+    while (--i > 0)
+		if (!(inw(dev->base_addr + EL3_STATUS) & 0x1000)) break;
+    if (i == 0)
+		printk(KERN_NOTICE "%s: command 0x%04x did not complete!\n",
+			   dev->name, cmd);
+}
+
+/* Read a word from the EEPROM using the regular EEPROM access register.
+   Assume that we are in register window zero.
+ */
+static u_short read_eeprom(ioaddr_t ioaddr, int index)
+{
+	int timer;
+	outw(EEPROM_Read + index, ioaddr + Wn0EepromCmd);
+	/* Pause for at least 162 usec for the read to take place. */
+	for (timer = 1620; timer >= 0; timer--) {
+		if ((inw(ioaddr + Wn0EepromCmd) & 0x8000) == 0)
+			break;
+	}
+	return inw(ioaddr + Wn0EepromData);
+}
+
+/* MII transceiver control section.
+   Read and write the MII registers using software-generated serial
+   MDIO protocol.  See the MII specifications or DP83840A data sheet
+   for details.
+   The maxium data clock rate is 2.5 Mhz.  The timing is easily met by the
+   slow PC card interface. */
+
+#define MDIO_SHIFT_CLK	0x01
+#define MDIO_DIR_WRITE	0x04
+#define MDIO_DATA_WRITE0 (0x00 | MDIO_DIR_WRITE)
+#define MDIO_DATA_WRITE1 (0x02 | MDIO_DIR_WRITE)
+#define MDIO_DATA_READ	0x02
+#define MDIO_ENB_IN		0x00
+
+/* Generate the preamble required for initial synchronization and
+   a few older transceivers. */
+static void mdio_sync(ioaddr_t ioaddr, int bits)
+{
+	int mdio_addr = ioaddr + Wn4_PhysicalMgmt;
+
+	/* Establish sync by sending at least 32 logic ones. */
+	while (-- bits >= 0) {
+		outw(MDIO_DATA_WRITE1, mdio_addr);
+		outw(MDIO_DATA_WRITE1 | MDIO_SHIFT_CLK, mdio_addr);
+	}
+}
+
+static int mdio_read(ioaddr_t ioaddr, int phy_id, int location)
+{
+	int i;
+	int read_cmd = (0xf6 << 10) | (phy_id << 5) | location;
+	unsigned int retval = 0;
+	int mdio_addr = ioaddr + Wn4_PhysicalMgmt;
+
+	if (mii_preamble_required)
+		mdio_sync(ioaddr, 32);
+
+	/* Shift the read command bits out. */
+	for (i = 14; i >= 0; i--) {
+		int dataval = (read_cmd&(1<<i)) ? MDIO_DATA_WRITE1 : MDIO_DATA_WRITE0;
+		outw(dataval, mdio_addr);
+		outw(dataval | MDIO_SHIFT_CLK, mdio_addr);
+	}
+	/* Read the two transition, 16 data, and wire-idle bits. */
+	for (i = 19; i > 0; i--) {
+		outw(MDIO_ENB_IN, mdio_addr);
+		retval = (retval << 1) | ((inw(mdio_addr) & MDIO_DATA_READ) ? 1 : 0);
+		outw(MDIO_ENB_IN | MDIO_SHIFT_CLK, mdio_addr);
+	}
+	return (retval>>1) & 0xffff;
+}
+
+static void mdio_write(ioaddr_t ioaddr, int phy_id, int location, int value)
+{
+	int write_cmd = 0x50020000 | (phy_id << 23) | (location << 18) | value;
+	int mdio_addr = ioaddr + Wn4_PhysicalMgmt;
+	int i;
+
+	if (mii_preamble_required)
+		mdio_sync(ioaddr, 32);
+
+	/* Shift the command bits out. */
+	for (i = 31; i >= 0; i--) {
+		int dataval = (write_cmd&(1<<i)) ? MDIO_DATA_WRITE1 : MDIO_DATA_WRITE0;
+		outw(dataval, mdio_addr);
+		outw(dataval | MDIO_SHIFT_CLK, mdio_addr);
+	}
+	/* Leave the interface idle. */
+	for (i = 1; i >= 0; i--) {
+		outw(MDIO_ENB_IN, mdio_addr);
+		outw(MDIO_ENB_IN | MDIO_SHIFT_CLK, mdio_addr);
+	}
+
+	return;
+}
+
+/* Reset and restore all of the 3c574 registers. */
+static void tc574_reset(struct net_device *dev)
+{
+	struct el3_private *lp = (struct el3_private *)dev->priv;
+	int i, ioaddr = dev->base_addr;
+
+	wait_for_completion(dev, TotalReset|0x10);
+
+	/* Clear any transactions in progress. */
+	outw(0, ioaddr + RunnerWrCtrl);
+	outw(0, ioaddr + RunnerRdCtrl);
+
+	/* Set the station address and mask. */
+	EL3WINDOW(2);
+	for (i = 0; i < 6; i++)
+		outb(dev->dev_addr[i], ioaddr + i);
+	for (; i < 12; i+=2)
+		outw(0, ioaddr + i);
+
+	/* Reset config options */
+	EL3WINDOW(3);
+	outb((dev->mtu > 1500 ? 0x40 : 0), ioaddr + Wn3_MAC_Ctrl);
+	outl((lp->autoselect ? 0x01000000 : 0) | 0x0062001b,
+		 ioaddr + Wn3_Config);
+	
+	/* Roadrunner only: Turn on the MII transceiver. */
+	outw(0x8040, ioaddr + Wn3_Options);
+	udelay(1000);
+	outw(0xc040, ioaddr + Wn3_Options);
+	wait_for_completion(dev, TxReset);
+	wait_for_completion(dev, RxReset);
+	udelay(1000);
+	outw(0x8040, ioaddr + Wn3_Options);
+
+	/* Switch to the stats window, and clear all stats by reading. */
+	outw(StatsDisable, ioaddr + EL3_CMD);
+	EL3WINDOW(6);
+	for (i = 0; i < 10; i++)
+		inb(ioaddr + i);
+	inw(ioaddr + 10);
+	inw(ioaddr + 12);
+	EL3WINDOW(4);
+	inb(ioaddr + 12);
+	inb(ioaddr + 13);
+
+	/* .. enable any extra statistics bits.. */
+	outw(0x0040, ioaddr + Wn4_NetDiag);
+	/* .. re-sync MII and re-fill what NWay is advertising. */
+	mdio_sync(ioaddr, 32);
+	mdio_write(ioaddr, lp->phys[0], 4, lp->advertising);
+
+	/* Switch to register set 1 for normal use, just for TxFree. */
+	EL3WINDOW(1);
+
+	set_rx_mode(dev);
+	outw(StatsEnable, ioaddr + EL3_CMD); /* Turn on statistics. */
+	outw(RxEnable, ioaddr + EL3_CMD); /* Enable the receiver. */
+	outw(TxEnable, ioaddr + EL3_CMD); /* Enable transmitter. */
+	/* Allow status bits to be seen. */
+	outw(SetStatusEnb | 0xff, ioaddr + EL3_CMD);
+	/* Ack all pending events, and set active indicator mask. */
+	outw(AckIntr | IntLatch | TxAvailable | RxEarly | IntReq,
+		 ioaddr + EL3_CMD);
+	outw(SetIntrEnb | IntLatch | TxAvailable | RxComplete | StatsFull
+		 | AdapterFailure | RxEarly, ioaddr + EL3_CMD);
+}
+
+static int el3_open(struct net_device *dev)
+{
+	struct el3_private *lp = (struct el3_private *)dev->priv;
+	dev_link_t *link = &lp->link;
+
+	if (!DEV_OK(link))
+		return -ENODEV;
+	
+	link->open++;
+	MOD_INC_USE_COUNT;
+	netif_start_queue(dev);
+	netif_mark_up(dev);
+	
+	tc574_reset(dev);
+	lp->media.function = &media_check;
+	lp->media.data = (u_long)lp;
+	lp->media.expires = jiffies + HZ;
+	add_timer(&lp->media);
+	
+	DEBUG(2, "%s: opened, status %4.4x.\n",
+		  dev->name, inw(dev->base_addr + EL3_STATUS));
+	
+	return 0;
+}
+
+static void el3_tx_timeout(struct net_device *dev)
+{
+	struct el3_private *lp = (struct el3_private *)dev->priv;
+	ioaddr_t ioaddr = dev->base_addr;
+	
+	printk(KERN_NOTICE "%s: Transmit timed out!\n", dev->name);
+	dump_status(dev);
+	lp->stats.tx_errors++;
+	dev->trans_start = jiffies;
+	/* Issue TX_RESET and TX_START commands. */
+	wait_for_completion(dev, TxReset);
+	outw(TxEnable, ioaddr + EL3_CMD);
+	netif_start_queue(dev);
+}
+
+static void pop_tx_status(struct net_device *dev)
+{
+    struct el3_private *lp = (struct el3_private *)dev->priv;
+    ioaddr_t ioaddr = dev->base_addr;
+    int i;
+    
+    /* Clear the Tx status stack. */
+    for (i = 32; i > 0; i--) {
+		u_char tx_status = inb(ioaddr + TxStatus);
+		if (!(tx_status & 0x84)) break;
+		/* reset transmitter on jabber error or underrun */
+		if (tx_status & 0x30)
+			wait_for_completion(dev, TxReset);
+		if (tx_status & 0x38) {
+			DEBUG(1, "%s: transmit error: status 0x%02x\n",
+				  dev->name, tx_status);
+			outw(TxEnable, ioaddr + EL3_CMD);
+			lp->stats.tx_aborted_errors++;
+		}
+		outb(0x00, ioaddr + TxStatus); /* Pop the status stack. */
+    }
+}
+
+static int el3_start_xmit(struct sk_buff *skb, struct net_device *dev)
+{
+	ioaddr_t ioaddr = dev->base_addr;
+
+	tx_timeout_check(dev, el3_tx_timeout);
+	skb_tx_check(dev, skb);
+
+	DEBUG(3, "%s: el3_start_xmit(length = %ld) called, "
+		  "status %4.4x.\n", dev->name, (long)skb->len,
+		  inw(ioaddr + EL3_STATUS));
+
+	outw(skb->len, ioaddr + TX_FIFO);
+	outw(0, ioaddr + TX_FIFO);
+	outsl_ns(ioaddr + TX_FIFO, skb->data, (skb->len+3)>>2);
+
+	dev->trans_start = jiffies;
+
+	/* TxFree appears only in Window 1, not offset 0x1c. */
+	if (inw(ioaddr + TxFree) > 1536) {
+		netif_start_queue(dev);
+	} else
+		/* Interrupt us when the FIFO has room for max-sized packet. 
+		   The threshold is in units of dwords. */
+		outw(SetTxThreshold + (1536>>2), ioaddr + EL3_CMD);
+
+	DEV_KFREE_SKB (skb);
+	pop_tx_status(dev);
+
+	return 0;
+}
+
+/* The EL3 interrupt handler. */
+static void el3_interrupt(int irq, void *dev_id, struct pt_regs *regs)
+{
+	struct el3_private *lp = dev_id;
+	struct net_device *dev = &lp->dev;
+	ioaddr_t ioaddr, status;
+	int work_budget = max_interrupt_work;
+
+	if (!netif_device_present(dev))
+		return;
+	ioaddr = dev->base_addr;
+
+	DEBUG(3, "%s: interrupt, status %4.4x.\n",
+		  dev->name, inw(ioaddr + EL3_STATUS));
+
+	while ((status = inw(ioaddr + EL3_STATUS)) &
+		   (IntLatch | RxComplete | RxEarly | StatsFull)) {
+		if (!netif_device_present(dev) ||
+			((status & 0xe000) != 0x2000)) {
+			DEBUG(1, "%s: Interrupt from dead card\n", dev->name);
+			break;
+		}
+
+		if (status & RxComplete)
+			work_budget = el3_rx(dev, work_budget);
+
+		if (status & TxAvailable) {
+			DEBUG(3, "  TX room bit was handled.\n");
+			/* There's room in the FIFO for a full-sized packet. */
+			outw(AckIntr | TxAvailable, ioaddr + EL3_CMD);
+			netif_wake_queue(dev);
+		}
+
+		if (status & TxComplete)
+			pop_tx_status(dev);
+
+		if (status & (AdapterFailure | RxEarly | StatsFull)) {
+			/* Handle all uncommon interrupts. */
+			if (status & StatsFull)
+				update_stats(dev);
+			if (status & RxEarly) {
+				work_budget = el3_rx(dev, work_budget);
+				outw(AckIntr | RxEarly, ioaddr + EL3_CMD);
+			}
+			if (status & AdapterFailure) {
+				u16 fifo_diag;
+				EL3WINDOW(4);
+				fifo_diag = inw(ioaddr + Wn4_FIFODiag);
+				EL3WINDOW(1);
+				printk(KERN_NOTICE "%s: adapter failure, FIFO diagnostic"
+					   " register %04x.\n", dev->name, fifo_diag);
+				if (fifo_diag & 0x0400) {
+					/* Tx overrun */
+					wait_for_completion(dev, TxReset);
+					outw(TxEnable, ioaddr + EL3_CMD);
+				}
+				if (fifo_diag & 0x2000) {
+					/* Rx underrun */
+					wait_for_completion(dev, RxReset);
+					set_rx_mode(dev);
+					outw(RxEnable, ioaddr + EL3_CMD);
+				}
+				outw(AckIntr | AdapterFailure, ioaddr + EL3_CMD);
+			}
+		}
+
+		if (--work_budget < 0) {
+			DEBUG(0, "%s: Too much work in interrupt, "
+				  "status %4.4x.\n", dev->name, status);
+			/* Clear all interrupts */
+			outw(AckIntr | 0xFF, ioaddr + EL3_CMD);
+			break;
+		}
+		/* Acknowledge the IRQ. */
+		outw(AckIntr | IntReq | IntLatch, ioaddr + EL3_CMD);
+	}
+
+	DEBUG(3, "%s: exiting interrupt, status %4.4x.\n",
+		  dev->name, inw(ioaddr + EL3_STATUS));
+	return;
+}
+
+/*
+    This timer serves two purposes: to check for missed interrupts
+	(and as a last resort, poll the NIC for events), and to monitor
+	the MII, reporting changes in cable status.
+*/
+static void media_check(u_long arg)
+{
+    struct el3_private *lp = (struct el3_private *)arg;
+    struct net_device *dev = &lp->dev;
+    ioaddr_t ioaddr = dev->base_addr;
+    u_long flags;
+	u_short /* cable, */ media, partner;
+
+	if (!netif_device_present(dev))
+		goto reschedule;
+	
+    /* Check for pending interrupt with expired latency timer: with
+       this, we can limp along even if the interrupt is blocked */
+    if ((inw(ioaddr + EL3_STATUS) & IntLatch) &&
+		(inb(ioaddr + Timer) == 0xff)) {
+		if (!lp->fast_poll)
+			printk(KERN_INFO "%s: interrupt(s) dropped!\n", dev->name);
+		el3_interrupt(dev->irq, lp, NULL);
+		lp->fast_poll = HZ;
+    }
+    if (lp->fast_poll) {
+		lp->fast_poll--;
+		lp->media.expires = jiffies + 2;
+		add_timer(&lp->media);
+		return;
+    }
+
+	save_flags(flags);
+	cli();
+#if 0
+	outw(2<<11, ioaddr + RunnerRdCtrl);
+	cable = inb(ioaddr);
+	outb(0x20, ioaddr);
+	outw(0, ioaddr + RunnerRdCtrl);
+#endif
+	EL3WINDOW(4);
+	media = mdio_read(ioaddr, lp->phys[0], 1);
+	partner = mdio_read(ioaddr, lp->phys[0], 5);
+	EL3WINDOW(1);
+	restore_flags(flags);
+
+#if 0
+	if (cable & 0x20)
+		printk(KERN_INFO "%s: cable %s\n", dev->name,
+			   ((cable & 0x08) ? "fixed" : "problem"));
+#endif
+	if (media != lp->media_status) {
+		if ((media ^ lp->media_status) & 0x0004)
+			printk(KERN_INFO "%s: %s link beat\n", dev->name,
+				   (lp->media_status & 0x0004) ? "lost" : "found");
+		if ((media ^ lp->media_status) & 0x0020) {
+			lp->partner = 0;
+			if (lp->media_status & 0x0020) {
+				printk(KERN_INFO "%s: autonegotiation restarted\n",
+					   dev->name);
+			} else if (partner) {
+				partner &= lp->advertising;
+				lp->partner = partner;
+				printk(KERN_INFO "%s: autonegotiation complete: "
+					   "%sbaseT-%cD selected\n", dev->name,
+					   ((partner & 0x0180) ? "100" : "10"),
+					   ((partner & 0x0140) ? 'F' : 'H'));
+			} else {
+				printk(KERN_INFO "%s: link partner did not autonegotiate\n",
+					   dev->name);
+			}
+
+			EL3WINDOW(3);
+			outb((partner & 0x0140 ? 0x20 : 0) |
+				 (dev->mtu > 1500 ? 0x40 : 0), ioaddr + Wn3_MAC_Ctrl);
+			EL3WINDOW(1);
+
+		}
+		if (media & 0x0010)
+			printk(KERN_INFO "%s: remote fault detected\n",
+				   dev->name);
+		if (media & 0x0002)
+			printk(KERN_INFO "%s: jabber detected\n", dev->name);
+		lp->media_status = media;
+	}
+
+reschedule:
+    lp->media.expires = jiffies + HZ;
+    add_timer(&lp->media);
+}
+
+static struct net_device_stats *el3_get_stats(struct net_device *dev)
+{
+	struct el3_private *lp = (struct el3_private *)dev->priv;
+
+	if (netif_device_present(dev))
+		update_stats(dev);
+	return &lp->stats;
+}
+
+/*  Update statistics.
+	Suprisingly this need not be run single-threaded, but it effectively is.
+	The counters clear when read, so the adds must merely be atomic.
+ */
+static void update_stats(struct net_device *dev)
+{
+	struct el3_private *lp = (struct el3_private *)dev->priv;
+	ioaddr_t ioaddr = dev->base_addr;
+	u8 rx, tx, up;
+
+	DEBUG(2, "%s: updating the statistics.\n", dev->name);
+
+	if (inw(ioaddr+EL3_STATUS) == 0xffff) /* No card. */
+		return;
+
+	/* Unlike the 3c509 we need not turn off stats updates while reading. */
+	/* Switch to the stats window, and read everything. */
+	EL3WINDOW(6);
+	lp->stats.tx_carrier_errors 	+= inb(ioaddr + 0);
+	lp->stats.tx_heartbeat_errors	+= inb(ioaddr + 1);
+	/* Multiple collisions. */	   	inb(ioaddr + 2);
+	lp->stats.collisions			+= inb(ioaddr + 3);
+	lp->stats.tx_window_errors		+= inb(ioaddr + 4);
+	lp->stats.rx_fifo_errors		+= inb(ioaddr + 5);
+	lp->stats.tx_packets			+= inb(ioaddr + 6);
+	up		 						 = inb(ioaddr + 9);
+	lp->stats.tx_packets			+= (up&0x30) << 4;
+	/* Rx packets   */				   inb(ioaddr + 7);
+	/* Tx deferrals */				   inb(ioaddr + 8);
+	rx		 						 = inw(ioaddr + 10);
+	tx								 = inw(ioaddr + 12);
+
+	EL3WINDOW(4);
+	/* BadSSD */					   inb(ioaddr + 12);
+	up								 = inb(ioaddr + 13);
+
+	add_rx_bytes(&lp->stats, rx + ((up & 0x0f) << 16));
+	add_tx_bytes(&lp->stats, tx + ((up & 0xf0) << 12));
+
+	EL3WINDOW(1);
+}
+
+static int el3_rx(struct net_device *dev, int worklimit)
+{
+	struct el3_private *lp = (struct el3_private *)dev->priv;
+	ioaddr_t ioaddr = dev->base_addr;
+	short rx_status;
+	
+	DEBUG(3, "%s: in rx_packet(), status %4.4x, rx_status %4.4x.\n",
+		  dev->name, inw(ioaddr+EL3_STATUS), inw(ioaddr+RxStatus));
+    while (!((rx_status = inw(ioaddr + RxStatus)) & 0x8000) &&
+		   (--worklimit >= 0)) {
+		if (rx_status & 0x4000) { /* Error, update stats. */
+			short error = rx_status & 0x3800;
+			lp->stats.rx_errors++;
+			switch (error) {
+			case 0x0000:	lp->stats.rx_over_errors++; break;
+			case 0x0800:	lp->stats.rx_length_errors++; break;
+			case 0x1000:	lp->stats.rx_frame_errors++; break;
+			case 0x1800:	lp->stats.rx_length_errors++; break;
+			case 0x2000:	lp->stats.rx_frame_errors++; break;
+			case 0x2800:	lp->stats.rx_crc_errors++; break;
+			}
+		} else {
+			short pkt_len = rx_status & 0x7ff;
+			struct sk_buff *skb;
+
+			skb = dev_alloc_skb(pkt_len+5);
+
+			DEBUG(3, "  Receiving packet size %d status %4.4x.\n",
+				  pkt_len, rx_status);
+			if (skb != NULL) {
+				skb->dev = dev;
+				skb_reserve(skb, 2);
+
+				insl_ns(ioaddr+RX_FIFO, skb_put(skb, pkt_len),
+						((pkt_len+3)>>2));
+
+				skb->protocol = eth_type_trans(skb, dev);
+				netif_rx(skb);
+				lp->stats.rx_packets++;
+			} else {
+				DEBUG(1, "%s: couldn't allocate a sk_buff of"
+					  " size %d.\n", dev->name, pkt_len);
+				lp->stats.rx_dropped++;
+			}
+		}
+		wait_for_completion(dev, RxDiscard);
+	}
+
+	return worklimit;
+}
+
+/* Provide ioctl() calls to examine the MII xcvr state. */
+static int el3_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
+{
+	struct el3_private *lp = (struct el3_private *)dev->priv;
+	ioaddr_t ioaddr = dev->base_addr;
+	u16 *data = (u16 *)&rq->ifr_data;
+	int phy = lp->phys[0] & 0x1f;
+
+	DEBUG(2, "%s: In ioct(%-.6s, %#4.4x) %4.4x %4.4x %4.4x %4.4x.\n",
+		  dev->name, rq->ifr_ifrn.ifrn_name, cmd,
+		  data[0], data[1], data[2], data[3]);
+
+    switch(cmd) {
+	case SIOCDEVPRIVATE:		/* Get the address of the PHY in use. */
+		data[0] = phy;
+	case SIOCDEVPRIVATE+1:		/* Read the specified MII register. */
+		{
+			int saved_window;
+			long flags;
+
+			save_flags(flags);
+			cli();
+			saved_window = inw(ioaddr + EL3_CMD) >> 13;
+			EL3WINDOW(4);
+			data[3] = mdio_read(ioaddr, data[0] & 0x1f, data[1] & 0x1f);
+			EL3WINDOW(saved_window);
+			restore_flags(flags);
+			return 0;
+		}
+	case SIOCDEVPRIVATE+2:		/* Write the specified MII register */
+		{
+			int saved_window;
+			long flags;
+
+			if (!capable(CAP_NET_ADMIN))
+				return -EPERM;
+			save_flags(flags);
+			cli();
+			saved_window = inw(ioaddr + EL3_CMD) >> 13;
+			EL3WINDOW(4);
+			mdio_write(ioaddr, data[0] & 0x1f, data[1] & 0x1f, data[2]);
+			EL3WINDOW(saved_window);
+			restore_flags(flags);
+			return 0;
+		}
+	default:
+		return -EOPNOTSUPP;
+	}
+}
+
+/* The Odie chip has a 64 bin multicast filter, but the bit layout is not
+   documented.  Until it is we revert to receiving all multicast frames when
+   any multicast reception is desired.
+   Note: My other drivers emit a log message whenever promiscuous mode is
+   entered to help detect password sniffers.  This is less desirable on
+   typical PC card machines, so we omit the message.
+   */
+
+static void set_rx_mode(struct net_device *dev)
+{
+	ioaddr_t ioaddr = dev->base_addr;
+
+	if (dev->flags & IFF_PROMISC)
+		outw(SetRxFilter | RxStation | RxMulticast | RxBroadcast | RxProm,
+			 ioaddr + EL3_CMD);
+	else if (dev->mc_count || (dev->flags & IFF_ALLMULTI))
+		outw(SetRxFilter|RxStation|RxMulticast|RxBroadcast, ioaddr + EL3_CMD);
+	else
+		outw(SetRxFilter | RxStation | RxBroadcast, ioaddr + EL3_CMD);
+}
+
+static int el3_close(struct net_device *dev)
+{
+	ioaddr_t ioaddr = dev->base_addr;
+	struct el3_private *lp = dev->priv;
+	dev_link_t *link = &lp->link;
+
+	DEBUG(2, "%s: shutting down ethercard.\n", dev->name);
+	
+	if (DEV_OK(link)) {
+		/* Turn off statistics ASAP.  We update lp->stats below. */
+		outw(StatsDisable, ioaddr + EL3_CMD);
+		
+		/* Disable the receiver and transmitter. */
+		outw(RxDisable, ioaddr + EL3_CMD);
+		outw(TxDisable, ioaddr + EL3_CMD);
+		
+		/* Note: Switching to window 0 may disable the IRQ. */
+		EL3WINDOW(0);
+		
+		update_stats(dev);
+	}
+
+	link->open--;
+	netif_stop_queue(dev);
+	netif_mark_down(dev);
+	del_timer(&lp->media);
+	if (link->state & DEV_STALE_CONFIG)
+		mod_timer(&link->release, jiffies + HZ/20);
+
+	MOD_DEC_USE_COUNT;
+
+	return 0;
+}
+
+static int __init init_3c574_cs(void)
+{
+	servinfo_t serv;
+
+	/* Always emit the version, before any failure. */
+	printk(KERN_INFO"%s", tc574_version);
+	DEBUG(0, "%s\n", version);
+	CardServices(GetCardServicesInfo, &serv);
+	if (serv.Revision != CS_RELEASE_CODE) {
+		printk(KERN_NOTICE "3c574_cs: Card Services release "
+			   "does not match!\n");
+		return -1;
+	}
+	register_pccard_driver(&dev_info, &tc574_attach, &tc574_detach);
+	return 0;
+}
+
+static void __exit exit_3c574_cs(void)
+{
+	DEBUG(0, "3c574_cs: unloading\n");
+	unregister_pccard_driver(&dev_info);
+	while (dev_list != NULL)
+		tc574_detach(dev_list);
+}
+
+module_init(init_3c574_cs);
+module_exit(exit_3c574_cs);
+
+/*
+ * Local variables:
+ *  compile-command: "make 3c574_cs.o"
+ *  c-indent-level: 4
+ *  c-basic-offset: 4
+ *  tab-width: 4
+ * End:
+ */
Index: oldkernel/linux/pcmcia-cs-3.1.15/clients/3c575_cb.c
diff -u /dev/null linux/pcmcia-cs-3.1.15/clients/3c575_cb.c:1.1
--- /dev/null	Mon Jul 31 21:15:10 2000
+++ linux/pcmcia-cs-3.1.15/clients/3c575_cb.c	Fri Jul  7 16:34:58 2000
@@ -0,0 +1,2296 @@
+/* EtherLinkXL.c: A 3Com EtherLink PCI III/XL ethernet driver for linux. */
+/*
+	Written 1996-1999 by Donald Becker.
+
+	This software may be used and distributed according to the terms
+	of the GNU Public License, incorporated herein by reference.
+
+	This driver is for the 3Com "Vortex" and "Boomerang" series ethercards.
+	Members of the series include Fast EtherLink 3c590/3c592/3c595/3c597
+	and the EtherLink XL 3c900 and 3c905 cards.
+
+	The author may be reached as becker@CESDIS.gsfc.nasa.gov, or C/O
+	Center of Excellence in Space Data and Information Sciences
+	   Code 930.5, Goddard Space Flight Center, Greenbelt MD 20771
+*/
+
+static char *version =
+"3c59x.c:v0.99L 5/28/99 Donald Becker http://cesdis.gsfc.nasa.gov/linux/drivers/vortex.html\n";
+
+/* "Knobs" that adjust features and parameters. */
+/* Set the copy breakpoint for the copy-only-tiny-frames scheme.
+   Setting to > 1512 effectively disables this feature. */
+static const int rx_copybreak = 200;
+/* Allow setting MTU to a larger size, bypassing the normal ethernet setup. */
+static const int mtu = 1500;
+/* Maximum events (Rx packets, etc.) to handle at each interrupt. */
+static int max_interrupt_work = 32;
+
+/* Put out somewhat more debugging messages. (0: no msg, 1 minimal .. 6). */
+#define vortex_debug debug
+#ifdef VORTEX_DEBUG
+static int vortex_debug = VORTEX_DEBUG;
+#else
+static int vortex_debug = 1;
+#endif
+
+/* Some values here only for performance evaluation and path-coverage
+   debugging. */
+static int rx_nocopy = 0, rx_copy = 0, queued_packet = 0, rx_csumhits;
+
+/* A few values that may be tweaked. */
+/* Time in jiffies before concluding the transmitter is hung. */
+#define TX_TIMEOUT  ((400*HZ)/1000)
+
+/* Keep the ring sizes a power of two for efficiency. */
+#define TX_RING_SIZE	16
+#define RX_RING_SIZE	32
+#define PKT_BUF_SZ		1536			/* Size of each temporary Rx buffer.*/
+
+#ifndef __OPTIMIZE__
+#warning  You must compile this file with the correct options!
+#warning  See the last lines of the source file.
+#error You must compile this driver with "-O".
+#endif
+
+#include <linux/config.h>
+#include <linux/version.h>
+#ifdef MODULE
+#ifdef MODVERSIONS
+#include <linux/modversions.h>
+#endif
+#include <linux/module.h>
+#else
+#define MOD_INC_USE_COUNT
+#define MOD_DEC_USE_COUNT
+#endif
+
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/string.h>
+#include <linux/timer.h>
+#include <linux/errno.h>
+#include <linux/in.h>
+#include <linux/ioport.h>
+#include <linux/malloc.h>
+#include <linux/interrupt.h>
+#include <linux/pci.h>
+#include <linux/netdevice.h>
+#include <linux/etherdevice.h>
+#include <linux/skbuff.h>
+#if LINUX_VERSION_CODE < 0x20155
+#include <linux/bios32.h>
+#endif
+#include <asm/irq.h>			/* For NR_IRQS only. */
+#include <asm/bitops.h>
+#include <asm/io.h>
+
+/* Kernel compatibility defines, some common to David Hinds' PCMCIA package.
+   This is only in the support-all-kernels source code. */
+
+#include <linux/delay.h>
+
+#if (LINUX_VERSION_CODE <= 0x20100)
+#ifndef __alpha__
+#define ioremap(a,b) \
+	(((a)<0x100000) ? (void *)((u_long)(a)) : vremap(a,b))
+#define iounmap(v) \
+	do { if ((u_long)(v) > 0x100000) vfree(v); } while (0)
+#endif
+#endif
+#if LINUX_VERSION_CODE <= 0x20139
+#define	net_device_stats enet_statistics
+#define NETSTATS_VER2
+#endif
+#if LINUX_VERSION_CODE < 0x20138
+#define test_and_set_bit(val, addr) set_bit(val, addr)
+#define le32_to_cpu(val) (val)
+#define cpu_to_le32(val) (val)
+#endif
+#if LINUX_VERSION_CODE < 0x20155
+#define PCI_SUPPORT_VER1
+#else
+#define PCI_SUPPORT_VER2
+#endif
+#if LINUX_VERSION_CODE < 0x20159
+#define DEV_FREE_SKB(skb) dev_kfree_skb (skb, FREE_WRITE);
+#else  /* Grrr, incompatible changes should change the name. */
+#define DEV_FREE_SKB(skb) dev_kfree_skb(skb);
+#endif
+#if ! defined(CAP_NET_ADMIN)
+#define capable(CAP_XXX) (suser())
+#endif
+#if LINUX_VERSION_CODE < 0x2030e
+#define net_device device
+#endif
+#ifndef HAVE_NETIF_QUEUE
+#define netif_stop_queue(dev) set_bit(0, (void *)&(dev)->tbusy)
+#define netif_start_queue(dev) clear_bit(0, (void *)&(dev)->tbusy)
+#define netif_wake_queue(dev) \
+    do { netif_start_queue(dev); mark_bh(NET_BH); } while (0)
+#define netif_device_attach(dev) \
+    do { (dev)->start = 1; netif_start_queue(dev); } while (0)
+#define netif_device_detach(dev) \
+    do { (dev)->start = 0; netif_stop_queue(dev); } while (0)
+#define netif_device_present(dev) ((dev)->start)
+#define netif_running(dev) ((dev)->start)
+#define netif_mark_up(dev) do { (dev)->start = 1; } while (0)
+#define netif_mark_down(dev) do { (dev)->start = 0; } while (0)
+#define netif_queue_stopped(dev) ((dev)->tbusy)
+#define tx_timeout_check(dev, tx_timeout) \
+    do { if (test_and_set_bit(0, (void *)&(dev)->tbusy) != 0) { \
+	if (jiffies - (dev)->trans_start < TX_TIMEOUT) return 1; \
+	tx_timeout(dev); \
+    } } while (0)
+#define dev_kfree_skb_irq(skb) DEV_FREE_SKB(skb)
+#else
+#define tx_timeout_check(dev, handler) netif_stop_queue(dev)
+#define netif_mark_up(dev) do { } while (0)
+#define netif_mark_down(dev) do { } while (0)
+#endif
+
+#if defined(MODULE) && LINUX_VERSION_CODE > 0x20115
+MODULE_AUTHOR("Donald Becker <becker@cesdis.gsfc.nasa.gov>");
+MODULE_DESCRIPTION("3Com 3c590/3c900 series Vortex/Boomerang driver");
+MODULE_PARM(debug, "i");
+MODULE_PARM(options, "1-" __MODULE_STRING(8) "i");
+MODULE_PARM(full_duplex, "1-" __MODULE_STRING(8) "i");
+MODULE_PARM(rx_copybreak, "i");
+MODULE_PARM(max_interrupt_work, "i");
+MODULE_PARM(compaq_ioaddr, "i");
+MODULE_PARM(compaq_irq, "i");
+MODULE_PARM(compaq_device_id, "i");
+#endif
+
+/* Operational parameter that usually are not changed. */
+
+/* The Vortex size is twice that of the original EtherLinkIII series: the
+   runtime register window, window 1, is now always mapped in.
+   The Boomerang size is twice as large as the Vortex -- it has additional
+   bus master control registers. */
+#define VORTEX_TOTAL_SIZE 0x20
+#define BOOMERANG_TOTAL_SIZE 0x40
+
+/* Set iff a MII transceiver on any interface requires mdio preamble.
+   This only set with the original DP83840 on older 3c905 boards, so the extra
+   code size of a per-interface flag is not worthwhile. */
+static char mii_preamble_required = 0;
+
+/*
+				Theory of Operation
+
+I. Board Compatibility
+
+This device driver is designed for the 3Com FastEtherLink and FastEtherLink
+XL, 3Com's PCI to 10/100baseT adapters.  It also works with the 10Mbs
+versions of the FastEtherLink cards.  The supported product IDs are
+  3c590, 3c592, 3c595, 3c597, 3c900, 3c905
+
+The related ISA 3c515 is supported with a separate driver, 3c515.c, included
+with the kernel source or available from
+    cesdis.gsfc.nasa.gov:/pub/linux/drivers/3c515.html
+
+II. Board-specific settings
+
+PCI bus devices are configured by the system at boot time, so no jumpers
+need to be set on the board.  The system BIOS should be set to assign the
+PCI INTA signal to an otherwise unused system IRQ line.
+
+The EEPROM settings for media type and forced-full-duplex are observed.
+The EEPROM media type should be left at the default "autoselect" unless using
+10base2 or AUI connections which cannot be reliably detected.
+
+III. Driver operation
+
+The 3c59x series use an interface that's very similar to the previous 3c5x9
+series.  The primary interface is two programmed-I/O FIFOs, with an
+alternate single-contiguous-region bus-master transfer (see next).
+
+The 3c900 "Boomerang" series uses a full-bus-master interface with separate
+lists of transmit and receive descriptors, similar to the AMD LANCE/PCnet,
+DEC Tulip and Intel Speedo3.  The first chip version retains a compatible
+programmed-I/O interface that has been removed in 'B' and subsequent board
+revisions.
+
+One extension that is advertised in a very large font is that the adapters
+are capable of being bus masters.  On the Vortex chip this capability was
+only for a single contiguous region making it far less useful than the full
+bus master capability.  There is a significant performance impact of taking
+an extra interrupt or polling for the completion of each transfer, as well
+as difficulty sharing the single transfer engine between the transmit and
+receive threads.  Using DMA transfers is a win only with large blocks or
+with the flawed versions of the Intel Orion motherboard PCI controller.
+
+The Boomerang chip's full-bus-master interface is useful, and has the
+currently-unused advantages over other similar chips that queued transmit
+packets may be reordered and receive buffer groups are associated with a
+single frame.
+
+With full-bus-master support, this driver uses a "RX_COPYBREAK" scheme.
+Rather than a fixed intermediate receive buffer, this scheme allocates
+full-sized skbuffs as receive buffers.  The value RX_COPYBREAK is used as
+the copying breakpoint: it is chosen to trade-off the memory wasted by
+passing the full-sized skbuff to the queue layer for all frames vs. the
+copying cost of copying a frame to a correctly-sized skbuff.
+
+
+IIIC. Synchronization
+The driver runs as two independent, single-threaded flows of control.
+One is the send-packet routine, which is single threaded by the tx
+queue system.  The other thread is the interrupt handler, which is
+single threaded by the hardware and other software.
+
+IV. Notes
+
+Thanks to Cameron Spitzer and Terry Murphy of 3Com for providing development
+3c590, 3c595, and 3c900 boards.
+The name "Vortex" is the internal 3Com project name for the PCI ASIC, and
+the EISA version is called "Demon".  According to Terry these names come
+from rides at the local amusement park.
+
+The new chips support both ethernet (1.5K) and FDDI (4.5K) packet sizes!
+This driver only supports ethernet packets because of the skbuff allocation
+limit of 4K.
+*/
+
+/* This table drives the PCI probe routines.  It's mostly boilerplate in all
+   of the drivers, and will likely be provided by some future kernel.
+*/
+enum pci_flags_bit {
+	PCI_USES_IO=1, PCI_USES_MEM=2, PCI_USES_MASTER=4,
+	PCI_ADDR0=0x10<<0, PCI_ADDR1=0x10<<1, PCI_ADDR2=0x10<<2, PCI_ADDR3=0x10<<3,
+};
+struct pci_id_info {
+	const char *name;
+	u16	vendor_id, device_id, device_id_mask, flags;
+	int drv_flags, io_size;
+	struct net_device *(*probe1)(int pci_bus, int pci_devfn, struct net_device *dev,
+							 long ioaddr, int irq, int chip_idx, int fnd_cnt);
+};
+
+enum { IS_VORTEX=1, IS_BOOMERANG=2, IS_CYCLONE=4,
+	   HAS_PWR_CTRL=0x10, HAS_MII=0x20, HAS_NWAY=0x40, HAS_CB_FNS=0x80, };
+static struct net_device *vortex_probe1(int pci_bus, int pci_devfn,
+									struct net_device *dev, long ioaddr,
+									int irq, int dev_id, int card_idx);
+static struct pci_id_info pci_tbl[] = {
+	{"3c590 Vortex 10Mbps",			0x10B7, 0x5900, 0xffff,
+	 PCI_USES_IO|PCI_USES_MASTER, IS_VORTEX, 32, vortex_probe1},
+	{"3c595 Vortex 100baseTx",		0x10B7, 0x5950, 0xffff,
+	 PCI_USES_IO|PCI_USES_MASTER, IS_VORTEX, 32, vortex_probe1},
+	{"3c595 Vortex 100baseT4",		0x10B7, 0x5951, 0xffff,
+	 PCI_USES_IO|PCI_USES_MASTER, IS_VORTEX, 32, vortex_probe1},
+	{"3c595 Vortex 100base-MII",	0x10B7, 0x5952, 0xffff,
+	 PCI_USES_IO|PCI_USES_MASTER, IS_VORTEX, 32, vortex_probe1},
+	{"3Com Vortex",					0x10B7, 0x5900, 0xff00,
+	 PCI_USES_IO|PCI_USES_MASTER, IS_BOOMERANG, 64, vortex_probe1},
+	{"3c900 Boomerang 10baseT",		0x10B7, 0x9000, 0xffff,
+	 PCI_USES_IO|PCI_USES_MASTER, IS_BOOMERANG, 64, vortex_probe1},
+	{"3c900 Boomerang 10Mbps Combo", 0x10B7, 0x9001, 0xffff,
+	 PCI_USES_IO|PCI_USES_MASTER, IS_BOOMERANG, 64, vortex_probe1},
+	{"3c900 Cyclone 10Mbps Combo", 0x10B7, 0x9005, 0xffff,
+	 PCI_USES_IO|PCI_USES_MASTER, IS_CYCLONE, 128, vortex_probe1},
+	{"3c900B-FL Cyclone 10base-FL",	0x10B7, 0x900A, 0xffff,
+	 PCI_USES_IO|PCI_USES_MASTER, IS_CYCLONE, 128, vortex_probe1},
+	{"3c905 Boomerang 100baseTx",	0x10B7, 0x9050, 0xffff,
+	 PCI_USES_IO|PCI_USES_MASTER, IS_BOOMERANG|HAS_MII, 64, vortex_probe1},
+	{"3c905 Boomerang 100baseT4",	0x10B7, 0x9051, 0xffff,
+	 PCI_USES_IO|PCI_USES_MASTER, IS_BOOMERANG|HAS_MII, 64, vortex_probe1},
+	{"3c905B Cyclone 100baseTx",	0x10B7, 0x9055, 0xffff,
+	 PCI_USES_IO|PCI_USES_MASTER, IS_CYCLONE|HAS_NWAY, 128, vortex_probe1},
+	{"3c905B Cyclone 10/100/BNC",	0x10B7, 0x9058, 0xffff,
+	 PCI_USES_IO|PCI_USES_MASTER, IS_CYCLONE|HAS_NWAY, 128, vortex_probe1},
+	{"3c905B-FX Cyclone 100baseFx",	0x10B7, 0x905A, 0xffff,
+	 PCI_USES_IO|PCI_USES_MASTER, IS_CYCLONE, 128, vortex_probe1},
+	{"3c905C Tornado",	0x10B7, 0x9200, 0xffff,
+	 PCI_USES_IO|PCI_USES_MASTER, IS_CYCLONE, 128, vortex_probe1},
+	{"3c980 Cyclone",	0x10B7, 0x9800, 0xfff0,
+	 PCI_USES_IO|PCI_USES_MASTER, IS_CYCLONE, 128, vortex_probe1},
+	{"3cSOHO100-TX Hurricane",	0x10B7, 0x7646, 0xffff,
+	 PCI_USES_IO|PCI_USES_MASTER, IS_CYCLONE, 128, vortex_probe1},
+	{"3c555 Laptop Hurricane",	0x10B7, 0x5055, 0xffff,
+	 PCI_USES_IO|PCI_USES_MASTER, IS_CYCLONE, 128, vortex_probe1},
+	{"3c575 Boomerang CardBus",		0x10B7, 0x5057, 0xffff,
+	 PCI_USES_IO|PCI_USES_MASTER, IS_BOOMERANG|HAS_MII, 64, vortex_probe1},
+	{"3CCFE575 Cyclone CardBus",	0x10B7, 0x5157, 0xffff,
+	 PCI_USES_IO|PCI_USES_MASTER, IS_CYCLONE|HAS_NWAY|HAS_CB_FNS,
+	 128, vortex_probe1},
+	{"3CCFE575CT Cyclone CardBus",	0x10B7, 0x5257, 0xffff,
+	 PCI_USES_IO|PCI_USES_MASTER, IS_CYCLONE|HAS_NWAY|HAS_CB_FNS,
+	 128, vortex_probe1},
+	{"3CCFE656 Cyclone CardBus",	0x10B7, 0x6560, 0xffff,
+	 PCI_USES_IO|PCI_USES_MASTER, IS_CYCLONE|HAS_NWAY|HAS_CB_FNS,
+	 128, vortex_probe1},
+	{"3CCFEM656 Cyclone CardBus",	0x10B7, 0x6562, 0xffff,
+	 PCI_USES_IO|PCI_USES_MASTER, IS_CYCLONE|HAS_NWAY|HAS_CB_FNS,
+	 128, vortex_probe1},
+	{"3CCFEM656 Cyclone CardBus",	0x10B7, 0x6564, 0xffff,
+	 PCI_USES_IO|PCI_USES_MASTER, IS_CYCLONE|HAS_NWAY|HAS_CB_FNS,
+	 128, vortex_probe1},
+	{"3c575 series CardBus (unknown version)", 0x10B7, 0x5057, 0xf0ff,
+	 PCI_USES_IO|PCI_USES_MASTER, IS_BOOMERANG|HAS_MII, 64, vortex_probe1},
+	{"3Com Boomerang (unknown version)",	0x10B7, 0x9000, 0xff00,
+	 PCI_USES_IO|PCI_USES_MASTER, IS_BOOMERANG, 64, vortex_probe1},
+	{0,},						/* 0 terminated list. */
+};
+
+/* Operational definitions.
+   These are not used by other compilation units and thus are not
+   exported in a ".h" file.
+
+   First the windows.  There are eight register windows, with the command
+   and status registers available in each.
+   */
+#define EL3WINDOW(win_num) outw(SelectWindow + (win_num), ioaddr + EL3_CMD)
+#define EL3_CMD 0x0e
+#define EL3_STATUS 0x0e
+
+/* The top five bits written to EL3_CMD are a command, the lower
+   11 bits are the parameter, if applicable.
+   Note that 11 parameters bits was fine for ethernet, but the new chip
+   can handle FDDI length frames (~4500 octets) and now parameters count
+   32-bit 'Dwords' rather than octets. */
+
+enum vortex_cmd {
+	TotalReset = 0<<11, SelectWindow = 1<<11, StartCoax = 2<<11,
+	RxDisable = 3<<11, RxEnable = 4<<11, RxReset = 5<<11,
+	UpStall = 6<<11, UpUnstall = (6<<11)+1,
+	DownStall = (6<<11)+2, DownUnstall = (6<<11)+3,
+	RxDiscard = 8<<11, TxEnable = 9<<11, TxDisable = 10<<11, TxReset = 11<<11,
+	FakeIntr = 12<<11, AckIntr = 13<<11, SetIntrEnb = 14<<11,
+	SetStatusEnb = 15<<11, SetRxFilter = 16<<11, SetRxThreshold = 17<<11,
+	SetTxThreshold = 18<<11, SetTxStart = 19<<11,
+	StartDMAUp = 20<<11, StartDMADown = (20<<11)+1, StatsEnable = 21<<11,
+	StatsDisable = 22<<11, StopCoax = 23<<11, SetFilterBit = 25<<11,};
+
+/* The SetRxFilter command accepts the following classes: */
+enum RxFilter {
+	RxStation = 1, RxMulticast = 2, RxBroadcast = 4, RxProm = 8 };
+
+/* Bits in the general status register. */
+enum vortex_status {
+	IntLatch = 0x0001, HostError = 0x0002, TxComplete = 0x0004,
+	TxAvailable = 0x0008, RxComplete = 0x0010, RxEarly = 0x0020,
+	IntReq = 0x0040, StatsFull = 0x0080,
+	DMADone = 1<<8, DownComplete = 1<<9, UpComplete = 1<<10,
+	DMAInProgress = 1<<11,			/* DMA controller is still busy.*/
+	CmdInProgress = 1<<12,			/* EL3_CMD is still busy.*/
+};
+
+/* Register window 1 offsets, the window used in normal operation.
+   On the Vortex this window is always mapped at offsets 0x10-0x1f. */
+enum Window1 {
+	TX_FIFO = 0x10,  RX_FIFO = 0x10,  RxErrors = 0x14,
+	RxStatus = 0x18,  Timer=0x1A, TxStatus = 0x1B,
+	TxFree = 0x1C, /* Remaining free bytes in Tx buffer. */
+};
+enum Window0 {
+	Wn0EepromCmd = 10,		/* Window 0: EEPROM command register. */
+	Wn0EepromData = 12,		/* Window 0: EEPROM results register. */
+	IntrStatus=0x0E,		/* Valid in all windows. */
+};
+enum Win0_EEPROM_bits {
+	EEPROM_Read = 0x80, EEPROM_WRITE = 0x40, EEPROM_ERASE = 0xC0,
+	EEPROM_EWENB = 0x30,		/* Enable erasing/writing for 10 msec. */
+	EEPROM_EWDIS = 0x00,		/* Disable EWENB before 10 msec timeout. */
+};
+/* EEPROM locations. */
+enum eeprom_offset {
+	PhysAddr01=0, PhysAddr23=1, PhysAddr45=2, ModelID=3,
+	EtherLink3ID=7, IFXcvrIO=8, IRQLine=9,
+	NodeAddr01=10, NodeAddr23=11, NodeAddr45=12,
+	DriverTune=13, Checksum=15};
+
+enum Window2 {			/* Window 2. */
+	Wn2_ResetOptions=12,
+};
+enum Window3 {			/* Window 3: MAC/config bits. */
+	Wn3_Config=0, Wn3_MAC_Ctrl=6, Wn3_Options=8,
+};
+union wn3_config {
+	int i;
+	struct w3_config_fields {
+		unsigned int ram_size:3, ram_width:1, ram_speed:2, rom_size:2;
+		int pad8:8;
+		unsigned int ram_split:2, pad18:2, xcvr:4, autoselect:1;
+		int pad24:7;
+	} u;
+};
+
+enum Window4 {		/* Window 4: Xcvr/media bits. */
+	Wn4_FIFODiag = 4, Wn4_NetDiag = 6, Wn4_PhysicalMgmt=8, Wn4_Media = 10,
+};
+enum Win4_Media_bits {
+	Media_SQE = 0x0008,		/* Enable SQE error counting for AUI. */
+	Media_10TP = 0x00C0,	/* Enable link beat and jabber for 10baseT. */
+	Media_Lnk = 0x0080,		/* Enable just link beat for 100TX/100FX. */
+	Media_LnkBeat = 0x0800,
+};
+enum Window7 {					/* Window 7: Bus Master control. */
+	Wn7_MasterAddr = 0, Wn7_MasterLen = 6, Wn7_MasterStatus = 12,
+};
+/* Boomerang bus master control registers. */
+enum MasterCtrl {
+	PktStatus = 0x20, DownListPtr = 0x24, FragAddr = 0x28, FragLen = 0x2c,
+	TxFreeThreshold = 0x2f, UpPktStatus = 0x30, UpListPtr = 0x38,
+};
+
+/* The Rx and Tx descriptor lists.
+   Caution Alpha hackers: these types are 32 bits!  Note also the 8 byte
+   alignment contraint on tx_ring[] and rx_ring[]. */
+#define LAST_FRAG  0x80000000			/* Last Addr/Len pair in descriptor. */
+struct boom_rx_desc {
+	u32 next;					/* Last entry points to 0.   */
+	s32 status;
+	u32 addr;					/* Up to 63 addr/len pairs possible. */
+	s32 length;					/* Set LAST_FRAG to indicate last pair. */
+};
+/* Values for the Rx status entry. */
+enum rx_desc_status {
+	RxDComplete=0x00008000, RxDError=0x4000,
+	/* See boomerang_rx() for actual error bits */
+	IPChksumErr=1<<25, TCPChksumErr=1<<26, UDPChksumErr=1<<27,
+	IPChksumValid=1<<29, TCPChksumValid=1<<30, UDPChksumValid=1<<31,
+};
+
+struct boom_tx_desc {
+	u32 next;					/* Last entry points to 0.   */
+	s32 status;					/* bits 0:12 length, others see below.  */
+	u32 addr;
+	s32 length;
+};
+
+/* Values for the Tx status entry. */
+enum tx_desc_status {
+	CRCDisable=0x2000, TxDComplete=0x8000,
+	AddIPChksum=0x02000000, AddTCPChksum=0x04000000, AddUDPChksum=0x08000000,
+	TxIntrUploaded=0x80000000,		/* IRQ when in FIFO, but maybe not sent. */
+};
+
+/* Chip features we care about in vp->capabilities, read from the EEPROM. */
+enum ChipCaps { CapBusMaster=0x20, CapPwrMgmt=0x2000 };
+
+struct vortex_private {
+	/* The Rx and Tx rings should be quad-word-aligned. */
+	struct boom_rx_desc rx_ring[RX_RING_SIZE];
+	struct boom_tx_desc tx_ring[TX_RING_SIZE];
+	/* The addresses of transmit- and receive-in-place skbuffs. */
+	struct sk_buff* rx_skbuff[RX_RING_SIZE];
+	struct sk_buff* tx_skbuff[TX_RING_SIZE];
+	struct net_device *next_module;
+	void *priv_addr;
+	unsigned int cur_rx, cur_tx;		/* The next free ring entry */
+	unsigned int dirty_rx, dirty_tx;	/* The ring entries to be free()ed. */
+	struct net_device_stats stats;
+	struct sk_buff *tx_skb;		/* Packet being eaten by bus master ctrl.  */
+
+	/* PCI configuration space information. */
+	u8 pci_bus, pci_devfn;		/* PCI bus location, for power management. */
+	char *cb_fn_base;			/* CardBus function status addr space. */
+	int chip_id;
+
+	/* The remainder are related to chip state, mostly media selection. */
+	struct timer_list timer;	/* Media selection timer. */
+	int options;				/* User-settable misc. driver options. */
+	unsigned int media_override:4, 			/* Passed-in media type. */
+		default_media:4,				/* Read from the EEPROM/Wn3_Config. */
+		full_duplex:1, force_fd:1, autoselect:1,
+		bus_master:1,				/* Vortex can only do a fragment bus-m. */
+		full_bus_master_tx:1, full_bus_master_rx:2, /* Boomerang  */
+		hw_csums:1,				/* Has hardware checksums. */
+		tx_full:1,
+		open:1,
+		reap:1;
+	u16 status_enable;
+	u16 intr_enable;
+	u16 available_media;				/* From Wn3_Options. */
+	u16 capabilities, info1, info2;		/* Various, from EEPROM. */
+	u16 advertising;					/* NWay media advertisement */
+	unsigned char phys[2];				/* MII device addresses. */
+	u16 deferred;
+};
+
+/* The action to take with a media selection timer tick.
+   Note that we deviate from the 3Com order by checking 10base2 before AUI.
+ */
+enum xcvr_types {
+	XCVR_10baseT=0, XCVR_AUI, XCVR_10baseTOnly, XCVR_10base2, XCVR_100baseTx,
+	XCVR_100baseFx, XCVR_MII=6, XCVR_NWAY=8, XCVR_ExtMII=9, XCVR_Default=10,
+};
+
+static struct media_table {
+	char *name;
+	unsigned int media_bits:16,		/* Bits to set in Wn4_Media register. */
+		mask:8,				/* The transceiver-present bit in Wn3_Config.*/
+		next:8;				/* The media type to try next. */
+	int wait;			/* Time before we check media status. */
+} media_tbl[] = {
+  {	"10baseT",   Media_10TP,0x08, XCVR_10base2, (14*HZ)/10},
+  { "10Mbs AUI", Media_SQE, 0x20, XCVR_Default, (1*HZ)/10},
+  { "undefined", 0,			0x80, XCVR_10baseT, 10000},
+  { "10base2",   0,			0x10, XCVR_AUI,		(1*HZ)/10},
+  { "100baseTX", Media_Lnk, 0x02, XCVR_100baseFx, (14*HZ)/10},
+  { "100baseFX", Media_Lnk, 0x04, XCVR_MII,		(14*HZ)/10},
+  { "MII",		 0,			0x41, XCVR_10baseT, 3*HZ },
+  { "undefined", 0,			0x01, XCVR_10baseT, 10000},
+  { "Autonegotiate", 0,		0x41, XCVR_10baseT, 3*HZ},
+  { "MII-External",	 0,		0x41, XCVR_10baseT, 3*HZ },
+  { "Default",	 0,			0xFF, XCVR_10baseT, 10000},
+};
+
+#ifndef CARDBUS
+static int vortex_scan(struct net_device *dev, struct pci_id_info pci_tbl[]);
+#endif
+static void vortex_up(struct net_device *dev);
+static void vortex_down(struct net_device *dev);
+static int vortex_open(struct net_device *dev);
+static void mdio_sync(long ioaddr, int bits);
+static int mdio_read(long ioaddr, int phy_id, int location);
+static void mdio_write(long ioaddr, int phy_id, int location, int value);
+static void vortex_timer(unsigned long arg);
+static int vortex_start_xmit(struct sk_buff *skb, struct net_device *dev);
+static int boomerang_start_xmit(struct sk_buff *skb, struct net_device *dev);
+static int vortex_rx(struct net_device *dev);
+static int boomerang_rx(struct net_device *dev);
+static void vortex_interrupt(int irq, void *dev_id, struct pt_regs *regs);
+static int vortex_close(struct net_device *dev);
+static void update_stats(long ioaddr, struct net_device *dev);
+static struct net_device_stats *vortex_get_stats(struct net_device *dev);
+static void set_rx_mode(struct net_device *dev);
+static int vortex_ioctl(struct net_device *dev, struct ifreq *rq, int cmd);
+static void acpi_wake(int pci_bus, int pci_devfn);
+static void acpi_set_WOL(struct net_device *dev);
+static void vortex_tx_timeout(struct net_device *dev);
+
+
+/* This driver uses 'options' to pass the media type, full-duplex flag, etc. */
+/* Option count limit only -- unlimited interfaces are supported. */
+#define MAX_UNITS 8
+static int options[MAX_UNITS] = { -1, -1, -1, -1, -1, -1, -1, -1,};
+static int full_duplex[MAX_UNITS] = {-1, -1, -1, -1, -1, -1, -1, -1};
+/* A list of all installed Vortex devices, for removing the driver module. */
+static struct net_device *root_vortex_dev = NULL;
+
+#ifdef MODULE
+#ifndef CARDBUS
+/* Variables to work-around the Compaq PCI BIOS32 problem. */
+static int compaq_ioaddr = 0, compaq_irq = 0, compaq_device_id = 0x5900;
+#endif
+
+#ifdef CARDBUS
+
+#include <pcmcia/driver_ops.h>
+
+static void vortex_reap(void)
+{
+	struct net_device **devp, **next;
+	for (devp = &root_vortex_dev; *devp; devp = next) {
+		struct vortex_private *vp = (*devp)->priv;
+		next = &vp->next_module;
+		if (vp->open || !vp->reap) continue;
+		unregister_netdev(*devp);
+		if (vp->cb_fn_base) iounmap(vp->cb_fn_base);
+		kfree(*devp);
+		*devp = *next; next = devp;
+		kfree(vp->priv_addr);
+	}
+}
+
+static dev_node_t *vortex_attach(dev_locator_t *loc)
+{
+	u16 dev_id, vendor_id;
+	u32 io;
+	u8 bus, devfn, irq;
+	struct net_device *dev;
+	int chip_idx;
+
+	vortex_reap();
+	if (loc->bus != LOC_PCI) return NULL;
+	bus = loc->b.pci.bus; devfn = loc->b.pci.devfn;
+	pcibios_read_config_dword(bus, devfn, PCI_BASE_ADDRESS_0, &io);
+	pcibios_read_config_byte(bus, devfn, PCI_INTERRUPT_LINE, &irq);
+	pcibios_read_config_word(bus, devfn, PCI_VENDOR_ID, &vendor_id);
+	pcibios_read_config_word(bus, devfn, PCI_DEVICE_ID, &dev_id);
+	printk(KERN_INFO "vortex_attach(device %02x:%02x.%d)\n",
+		   bus, PCI_SLOT(devfn), PCI_FUNC(devfn));
+	io &= ~3;
+	if (io == 0 || irq == 0) {
+		printk(KERN_ERR "The 3Com CardBus Ethernet interface was not "
+			   "assigned an %s.\n" KERN_ERR "  It will not be activated.\n",
+			   io == 0 ? "I/O address" : "IRQ");
+		return NULL;
+	}
+	for (chip_idx = 0; pci_tbl[chip_idx].vendor_id; chip_idx++)
+		if (vendor_id == pci_tbl[chip_idx].vendor_id
+			&& (dev_id & pci_tbl[chip_idx].device_id_mask) ==
+			pci_tbl[chip_idx].device_id)
+			break;
+	if (pci_tbl[chip_idx].vendor_id == 0) { 		/* Compiled out! */
+		printk(KERN_INFO "Unable to match chip type %4.4x %4.4x in "
+			   "vortex_attach().\n", vendor_id, dev_id);
+		return NULL;
+	}
+	dev = vortex_probe1(bus, devfn, NULL, io, irq, chip_idx, MAX_UNITS+1);
+	if (dev) {
+		dev_node_t *node = kmalloc(sizeof(dev_node_t), GFP_KERNEL);
+		strcpy(node->dev_name, dev->name);
+		node->major = node->minor = 0;
+		node->next = NULL;
+		MOD_INC_USE_COUNT;
+		return node;
+	}
+	return NULL;
+}
+
+static void vortex_detach(dev_node_t *node)
+{
+	struct net_device *dev, *next;
+	printk(KERN_DEBUG "vortex_detach(%s)\n", node->dev_name);
+	for (dev = root_vortex_dev; dev; dev = next) {
+		next = ((struct vortex_private *)dev->priv)->next_module;
+		if (strcmp(dev->name, node->dev_name) == 0) break;
+	}
+	if (dev && dev->priv) {
+		struct vortex_private *vp = dev->priv;
+		netif_device_detach(dev);
+		if (vp->open) vortex_down(dev);
+		vp->reap = 1;
+		kfree(node);
+		MOD_DEC_USE_COUNT;
+	}
+}
+
+static void vortex_suspend(dev_node_t *node)
+{
+	struct net_device *dev, *next;
+	printk(KERN_DEBUG "vortex_suspend(%s)\n", node->dev_name);
+	for (dev = root_vortex_dev; dev; dev = next) {
+		next = ((struct vortex_private *)dev->priv)->next_module;
+		if (strcmp(dev->name, node->dev_name) == 0) break;
+	}
+	if (dev && dev->priv) {
+		struct vortex_private *vp = (struct vortex_private *)dev->priv;
+		netif_device_detach(dev);
+		if (vp->open) vortex_down(dev);
+	}
+}
+
+static void vortex_resume(dev_node_t *node)
+{
+	struct net_device *dev, *next;
+	printk(KERN_DEBUG "vortex_resume(%s)\n", node->dev_name);
+	for (dev = root_vortex_dev; dev; dev = next) {
+		next = ((struct vortex_private *)dev->priv)->next_module;
+		if (strcmp(dev->name, node->dev_name) == 0) break;
+	}
+	if (dev && dev->priv) {
+		struct vortex_private *vp = (struct vortex_private *)dev->priv;
+		if (vp->open) vortex_up(dev);
+		netif_device_attach(dev);
+	}
+}
+
+struct driver_operations vortex_ops = {
+	"3c575_cb", vortex_attach, vortex_suspend, vortex_resume, vortex_detach
+};
+
+#endif  /* Cardbus support */
+
+
+int init_module(void)
+{
+	if (vortex_debug)
+		printk(KERN_INFO "%s", version);
+#ifdef CARDBUS
+	register_driver(&vortex_ops);
+	return 0;
+#else
+	return vortex_scan(0, pci_tbl);
+#endif
+}
+
+#else
+int tc59x_probe(struct net_device *dev)
+{
+	static int did_version = -1;
+	if (++did_version <= 0)
+		printk(KERN_INFO "%s", version);
+	return vortex_scan(dev, pci_tbl);
+}
+#endif  /* not MODULE */
+
+#ifndef CARDBUS
+static int vortex_scan(struct net_device *dev, struct pci_id_info pci_tbl[])
+{
+	int cards_found = 0;
+
+	/* Allow an EISA-only driver. */
+#if defined(CONFIG_PCI) || (defined(MODULE) && !defined(NO_PCI))
+	/* Ideally we would detect all cards in slot order.  That would
+	   be best done a central PCI probe dispatch, which wouldn't work
+	   well with the current structure.  So instead we detect 3Com cards
+	   in slot order. */
+	if (pcibios_present()) {
+		static int pci_index = 0;
+		unsigned char pci_bus, pci_device_fn;
+
+		for (;pci_index < 0xff; pci_index++) {
+			u16 vendor, device, pci_command, new_command;
+			int chip_idx, irq;
+			long ioaddr;
+
+			if (pcibios_find_class (PCI_CLASS_NETWORK_ETHERNET << 8, pci_index,
+									&pci_bus, &pci_device_fn)
+				!= PCIBIOS_SUCCESSFUL)
+				break;
+			pcibios_read_config_word(pci_bus, pci_device_fn,
+									 PCI_VENDOR_ID, &vendor);
+			pcibios_read_config_word(pci_bus, pci_device_fn,
+									 PCI_DEVICE_ID, &device);
+			for (chip_idx = 0; pci_tbl[chip_idx].vendor_id; chip_idx++)
+				if (vendor == pci_tbl[chip_idx].vendor_id
+					&& (device & pci_tbl[chip_idx].device_id_mask) ==
+					pci_tbl[chip_idx].device_id)
+					break;
+			if (pci_tbl[chip_idx].vendor_id == 0) 		/* Compiled out! */
+				continue;
+
+			/* The Cyclone requires config space re-write if powered down. */
+			acpi_wake(pci_bus, pci_device_fn);
+
+			{
+#if LINUX_VERSION_CODE >= 0x2030d
+				struct pci_dev *pdev = pci_find_slot(pci_bus, pci_device_fn);
+				ioaddr = pdev->resource[0].start;
+				irq = pdev->irq;
+#elif LINUX_VERSION_CODE >= 0x20155
+				struct pci_dev *pdev = pci_find_slot(pci_bus, pci_device_fn);
+				ioaddr = pdev->base_address[0] & ~3;
+				irq = pdev->irq;
+#else
+				u32 pci_ioaddr;
+				u8 pci_irq_line;
+				pcibios_read_config_byte(pci_bus, pci_device_fn,
+										 PCI_INTERRUPT_LINE, &pci_irq_line);
+				pcibios_read_config_dword(pci_bus, pci_device_fn,
+										  PCI_BASE_ADDRESS_0, &pci_ioaddr);
+				ioaddr = pci_ioaddr & ~3;;
+				irq = pci_irq_line;
+#endif
+			}
+
+			if (ioaddr == 0) {
+				printk(KERN_WARNING "  A 3Com network adapter has been found, "
+					   "however it has not been assigned an I/O address.\n"
+					   "  You may need to power-cycle the machine for this "
+					   "device to work!\n");
+				continue;
+			}
+
+			/* Activate the card. */
+			pcibios_read_config_word(pci_bus, pci_device_fn,
+									 PCI_COMMAND, &pci_command);
+			new_command = pci_command | PCI_COMMAND_MASTER|PCI_COMMAND_IO;
+			if (pci_command != new_command) {
+				printk(KERN_INFO "  The PCI BIOS has not enabled the device "
+					   "at %d/%d. Updating PCI command %4.4x->%4.4x.\n",
+					   pci_bus, pci_device_fn, pci_command, new_command);
+				pcibios_write_config_word(pci_bus, pci_device_fn,
+										  PCI_COMMAND, new_command);
+			}
+
+			dev = vortex_probe1(pci_bus, pci_device_fn, dev, ioaddr, irq,
+								chip_idx, cards_found);
+
+			if (dev) {
+				/* Get and check the latency values.  On the 3c590 series
+				   the latency timer must be set to the maximum value to avoid
+				   data corruption that occurs when the timer expires during
+				   a transfer -- a bug in the Vortex chip only. */
+				u8 pci_latency;
+				u8 new_latency = (device & 0xff00) == 0x5900 ? 248 : 32;
+				
+				pcibios_read_config_byte(pci_bus, pci_device_fn,
+										 PCI_LATENCY_TIMER, &pci_latency);
+				if (pci_latency < new_latency) {
+					printk(KERN_INFO "%s: Overriding PCI latency"
+						   " timer (CFLT) setting of %d, new value is %d.\n",
+						   dev->name, pci_latency, new_latency);
+					pcibios_write_config_byte(pci_bus, pci_device_fn,
+											  PCI_LATENCY_TIMER, new_latency);
+				}
+				dev = 0;
+				cards_found++;
+			}
+		}
+	}
+#endif /* NO_PCI */
+
+	/* Now check all slots of the EISA bus. */
+	if (EISA_bus) {
+		static long ioaddr = 0x1000;
+		for ( ; ioaddr < 0x9000; ioaddr += 0x1000) {
+			int device_id;
+			if (check_region(ioaddr, VORTEX_TOTAL_SIZE))
+				continue;
+			/* Check the standard EISA ID register for an encoded '3Com'. */
+			if (inw(ioaddr + 0xC80) != 0x6d50)
+				continue;
+			/* Check for a product that we support, 3c59{2,7} any rev. */
+			device_id = (inb(ioaddr + 0xC82)<<8) + inb(ioaddr + 0xC83);
+			if ((device_id & 0xFF00) != 0x5900)
+				continue;
+			vortex_probe1(0, 0, dev, ioaddr, inw(ioaddr + 0xC88) >> 12,
+						  4, cards_found);
+			dev = 0;
+			cards_found++;
+		}
+	}
+
+#ifdef MODULE
+	/* Special code to work-around the Compaq PCI BIOS32 problem. */
+	if (compaq_ioaddr) {
+		vortex_probe1(0, 0, dev, compaq_ioaddr, compaq_irq,
+					  compaq_device_id, cards_found++);
+		dev = 0;
+	}
+#endif
+
+	return cards_found ? 0 : -ENODEV;
+}
+#endif  /* ! Cardbus */
+
+static struct net_device *vortex_probe1(int pci_bus, int pci_devfn,
+									struct net_device *dev, long ioaddr,
+									int irq, int chip_idx, int card_idx)
+{
+	struct vortex_private *vp;
+	int option;
+	unsigned int eeprom[0x40], checksum = 0;		/* EEPROM contents */
+	int i;
+
+	dev = init_etherdev(dev, 0);
+
+	printk(KERN_INFO "%s: 3Com %s at 0x%lx, ",
+		   dev->name, pci_tbl[chip_idx].name, ioaddr);
+
+	dev->base_addr = ioaddr;
+	dev->irq = irq;
+	dev->mtu = mtu;
+
+	/* Make certain the descriptor lists are aligned. */
+	{
+		void *mem = kmalloc(sizeof(*vp) + 15, GFP_KERNEL);
+		vp =  (void *)(((long)mem + 15) & ~15);
+		memset(vp, 0, sizeof(*vp));
+		vp->priv_addr = mem;
+	}
+	dev->priv = vp;
+
+	vp->next_module = root_vortex_dev;
+	root_vortex_dev = dev;
+
+	vp->chip_id = chip_idx;
+	vp->pci_bus = pci_bus;
+	vp->pci_devfn = pci_devfn;
+
+	/* The lower four bits are the media type. */
+	if (dev->mem_start)
+		option = dev->mem_start;
+	else if (card_idx < MAX_UNITS)
+		option = options[card_idx];
+	else
+		option = -1;
+
+	if (option >= 0) {
+		vp->media_override = ((option & 7) == 2)  ?  0  :  option & 15;
+		vp->full_duplex = (option & 0x200) ? 1 : 0;
+		vp->bus_master = (option & 16) ? 1 : 0;
+	} else {
+		vp->media_override = 7;
+		vp->full_duplex = 0;
+		vp->bus_master = 0;
+	}
+	if (card_idx < MAX_UNITS  &&  full_duplex[card_idx] > 0)
+		vp->full_duplex = 1;
+
+	vp->force_fd = vp->full_duplex;
+	vp->options = option;
+
+	/* Read the station address from the EEPROM. */
+	EL3WINDOW(0);
+	for (i = 0; i < 0x40; i++) {
+		int timer;
+#ifdef CARDBUS
+		outw(0x230 + i, ioaddr + Wn0EepromCmd);
+#else
+		outw(EEPROM_Read + i, ioaddr + Wn0EepromCmd);
+#endif
+		/* Pause for at least 162 us. for the read to take place. */
+		for (timer = 10; timer >= 0; timer--) {
+			udelay(162);
+			if ((inw(ioaddr + Wn0EepromCmd) & 0x8000) == 0)
+				break;
+		}
+		eeprom[i] = inw(ioaddr + Wn0EepromData);
+	}
+	for (i = 0; i < 0x18; i++)
+		checksum ^= eeprom[i];
+	checksum = (checksum ^ (checksum >> 8)) & 0xff;
+	if (checksum != 0x00) {		/* Grrr, needless incompatible change 3Com. */
+		while (i < 0x21)
+			checksum ^= eeprom[i++];
+		checksum = (checksum ^ (checksum >> 8)) & 0xff;
+	}
+	if (checksum != 0x00)
+		printk(" ***INVALID CHECKSUM %4.4x*** ", checksum);
+
+	for (i = 0; i < 3; i++)
+		((u16 *)dev->dev_addr)[i] = htons(eeprom[i + 10]);
+	for (i = 0; i < 6; i++)
+		printk("%c%2.2x", i ? ':' : ' ', dev->dev_addr[i]);
+	EL3WINDOW(2);
+	for (i = 0; i < 6; i++)
+		outb(dev->dev_addr[i], ioaddr + i);
+
+#ifdef __sparc__
+	printk(", IRQ %s\n", __irq_itoa(dev->irq));
+#else
+	printk(", IRQ %d\n", dev->irq);
+	/* Tell them about an invalid IRQ. */
+	if (vortex_debug && (dev->irq <= 0 || dev->irq >= NR_IRQS))
+		printk(KERN_WARNING " *** Warning: IRQ %d is unlikely to work! ***\n",
+			   dev->irq);
+#endif
+
+	if (pci_tbl[vp->chip_id].drv_flags & HAS_CB_FNS) {
+		u32 fn_st_addr;			/* Cardbus function status space */
+		pcibios_read_config_dword(pci_bus, pci_devfn, PCI_BASE_ADDRESS_2,
+								  &fn_st_addr);
+		if (fn_st_addr)
+			vp->cb_fn_base = ioremap(fn_st_addr & ~3, 128);
+		printk(KERN_INFO "%s: CardBus functions mapped %8.8x->%p\n",
+			   dev->name, fn_st_addr, vp->cb_fn_base);
+	}
+
+	/* Extract our information from the EEPROM data. */
+	vp->info1 = eeprom[13];
+	vp->info2 = eeprom[15];
+	vp->capabilities = eeprom[16];
+
+	if (vp->info1 & 0x8000)
+		vp->full_duplex = 1;
+
+	{
+		char *ram_split[] = {"5:3", "3:1", "1:1", "3:5"};
+		union wn3_config config;
+		EL3WINDOW(3);
+		vp->available_media = inw(ioaddr + Wn3_Options);
+		if ((vp->available_media & 0xff) == 0)		/* Broken 3c916 */
+			vp->available_media = 0x40;
+		config.i = inl(ioaddr + Wn3_Config);
+		if (vortex_debug > 1)
+			printk(KERN_DEBUG "  Internal config register is %4.4x, "
+				   "transceivers %#x.\n", config.i, inw(ioaddr + Wn3_Options));
+		printk(KERN_INFO "  %dK %s-wide RAM %s Rx:Tx split, %s%s interface.\n",
+			   8 << config.u.ram_size,
+			   config.u.ram_width ? "word" : "byte",
+			   ram_split[config.u.ram_split],
+			   config.u.autoselect ? "autoselect/" : "",
+			   config.u.xcvr > XCVR_ExtMII ? "<invalid transceiver>" :
+			   media_tbl[config.u.xcvr].name);
+		vp->default_media = config.u.xcvr;
+		vp->autoselect = config.u.autoselect;
+	}
+
+	if (vp->media_override != 7) {
+		printk(KERN_INFO "  Media override to transceiver type %d (%s).\n",
+			   vp->media_override, media_tbl[vp->media_override].name);
+		dev->if_port = vp->media_override;
+	} else
+		dev->if_port = vp->default_media;
+
+	if (dev->if_port == XCVR_MII || dev->if_port == XCVR_NWAY) {
+		int phy, phy_idx = 0;
+		EL3WINDOW(4);
+		mii_preamble_required++;
+		mii_preamble_required++;
+		mdio_read(ioaddr, 24, 1);
+		for (phy = 1; phy <= 32 && phy_idx < sizeof(vp->phys); phy++) {
+			int mii_status, phyx = phy & 0x1f;
+			mii_status = mdio_read(ioaddr, phyx, 1);
+			if (mii_status  &&  mii_status != 0xffff) {
+				vp->phys[phy_idx++] = phyx;
+				printk(KERN_INFO "  MII transceiver found at address %d,"
+					   " status %4x.\n", phyx, mii_status);
+				if ((mii_status & 0x0040) == 0)
+					mii_preamble_required++;
+			}
+		}
+		mii_preamble_required--;
+		if (phy_idx == 0) {
+			printk(KERN_WARNING"  ***WARNING*** No MII transceivers found!\n");
+			vp->phys[0] = 24;
+		} else {
+			vp->advertising = mdio_read(ioaddr, vp->phys[0], 4);
+			if (vp->full_duplex) {
+				/* Only advertise the FD media types. */
+				vp->advertising &= ~0x02A0;
+				mdio_write(ioaddr, vp->phys[0], 4, vp->advertising);
+			}
+		}
+	}
+
+	if (vp->capabilities & CapPwrMgmt)
+		acpi_set_WOL(dev);
+
+	if (vp->capabilities & CapBusMaster) {
+		vp->full_bus_master_tx = 1;
+		printk(KERN_INFO"  Enabling bus-master transmits and %s receives.\n",
+			   (vp->info2 & 1) ? "early" : "whole-frame" );
+		vp->full_bus_master_rx = (vp->info2 & 1) ? 1 : 2;
+	}
+
+	/* We do a request_region() to register /proc/ioports info. */
+	request_region(ioaddr, pci_tbl[chip_idx].io_size, dev->name);
+
+	/* The 3c59x-specific entries in the device structure. */
+	dev->open = &vortex_open;
+	dev->hard_start_xmit = &vortex_start_xmit;
+	dev->stop = &vortex_close;
+	dev->get_stats = &vortex_get_stats;
+	dev->do_ioctl = &vortex_ioctl;
+	dev->set_multicast_list = &set_rx_mode;
+#ifdef HAVE_NETIF_QUEUE
+	dev->tx_timeout = vortex_tx_timeout;
+	dev->watchdog_timeo = TX_TIMEOUT;
+#endif
+
+	return dev;
+}
+
+static void wait_for_completion(struct net_device *dev, int cmd)
+{
+	int i = 2000;
+	outw(cmd, dev->base_addr + EL3_CMD);
+	while (--i > 0)
+		if (!(inw(dev->base_addr + EL3_STATUS) & CmdInProgress))
+			break;
+	if (i == 0)
+		printk(KERN_NOTICE "%s: command 0x%04x did not complete!\n",
+			   dev->name, cmd);
+}
+
+
+static void
+vortex_up(struct net_device *dev)
+{
+	long ioaddr = dev->base_addr;
+	struct vortex_private *vp = (struct vortex_private *)dev->priv;
+	union wn3_config config;
+	int i;
+	
+	/* Should be if(HAS_ACPI) */
+	acpi_wake(vp->pci_bus, vp->pci_devfn);
+
+	/* Before initializing select the active media port. */
+	EL3WINDOW(3);
+	config.i = inl(ioaddr + Wn3_Config);
+
+	if (vp->media_override != 7) {
+		if (vortex_debug > 1)
+			printk(KERN_INFO "%s: Media override to transceiver %d (%s).\n",
+				   dev->name, vp->media_override,
+				   media_tbl[vp->media_override].name);
+		dev->if_port = vp->media_override;
+	} else if (vp->autoselect) {
+		if (pci_tbl[vp->chip_id].drv_flags & HAS_NWAY)
+			dev->if_port = XCVR_NWAY;
+		else {
+			/* Find first available media type, starting with 100baseTx. */
+			dev->if_port = XCVR_100baseTx;
+			while (! (vp->available_media & media_tbl[dev->if_port].mask))
+				dev->if_port = media_tbl[dev->if_port].next;
+		}
+	} else
+		dev->if_port = vp->default_media;
+
+	init_timer(&vp->timer);
+	vp->timer.expires = jiffies + media_tbl[dev->if_port].wait;
+	vp->timer.data = (unsigned long)dev;
+	vp->timer.function = &vortex_timer;		/* timer handler */
+	add_timer(&vp->timer);
+
+	if (vortex_debug > 1)
+		printk(KERN_DEBUG "%s: Initial media type %s.\n",
+			   dev->name, media_tbl[dev->if_port].name);
+
+	vp->full_duplex = vp->force_fd;
+	config.u.xcvr = dev->if_port;
+	if ( ! (pci_tbl[vp->chip_id].drv_flags & HAS_NWAY))
+		outl(config.i, ioaddr + Wn3_Config);
+
+	if (dev->if_port == XCVR_MII || dev->if_port == XCVR_NWAY) {
+		int mii_reg1, mii_reg5;
+		EL3WINDOW(4);
+		/* Read BMSR (reg1) only to clear old status. */
+		mii_reg1 = mdio_read(ioaddr, vp->phys[0], 1);
+		mii_reg5 = mdio_read(ioaddr, vp->phys[0], 5);
+		if (mii_reg5 == 0xffff  ||  mii_reg5 == 0x0000)
+			;					/* No MII device or no link partner report */
+		else if ((mii_reg5 & 0x0100) != 0	/* 100baseTx-FD */
+				 || (mii_reg5 & 0x00C0) == 0x0040) /* 10T-FD, but not 100-HD */
+			vp->full_duplex = 1;
+		if (vortex_debug > 1)
+			printk(KERN_INFO "%s: MII #%d status %4.4x, link partner capability %4.4x,"
+				   " setting %s-duplex.\n", dev->name, vp->phys[0],
+				   mii_reg1, mii_reg5, vp->full_duplex ? "full" : "half");
+		EL3WINDOW(3);
+	}
+
+	/* Set the full-duplex bit. */
+	outb(((vp->info1 & 0x8000) || vp->full_duplex ? 0x20 : 0) |
+		 (dev->mtu > 1500 ? 0x40 : 0), ioaddr + Wn3_MAC_Ctrl);
+
+	if (vortex_debug > 1) {
+		printk(KERN_DEBUG "%s: vortex_open() InternalConfig %8.8x.\n",
+			dev->name, config.i);
+	}
+
+	wait_for_completion(dev, TxReset);
+	wait_for_completion(dev, RxReset);
+
+	outw(SetStatusEnb | 0x00, ioaddr + EL3_CMD);
+
+	if (vortex_debug > 1) {
+		EL3WINDOW(4);
+		printk(KERN_DEBUG "%s: vortex_open() irq %d media status %4.4x.\n",
+			   dev->name, dev->irq, inw(ioaddr + Wn4_Media));
+	}
+
+	/* Set the station address and mask in window 2 each time opened. */
+	EL3WINDOW(2);
+	for (i = 0; i < 6; i++)
+		outb(dev->dev_addr[i], ioaddr + i);
+	for (; i < 12; i+=2)
+		outw(0, ioaddr + i);
+	if (vp->cb_fn_base) {
+		u_short n = inw(ioaddr + Wn2_ResetOptions);
+		/* Inverted LED polarity */
+		if ((pci_tbl[vp->chip_id].device_id != 0x5257) &&
+			(pci_tbl[vp->chip_id].device_id != 0x6564))
+			n |= 0x0010;
+		/* Inverted polarity of MII power bit */
+		if ((pci_tbl[vp->chip_id].device_id == 0x6560) ||
+			(pci_tbl[vp->chip_id].device_id == 0x6562) ||
+			(pci_tbl[vp->chip_id].device_id == 0x6564) ||
+			(pci_tbl[vp->chip_id].device_id == 0x5257))
+			n |= 0x4000;
+		outw(n, ioaddr + Wn2_ResetOptions);
+	}
+
+	if (dev->if_port == XCVR_10base2)
+		/* Start the thinnet transceiver. We should really wait 50ms...*/
+		outw(StartCoax, ioaddr + EL3_CMD);
+	if (dev->if_port != XCVR_NWAY) {
+		EL3WINDOW(4);
+		outw((inw(ioaddr + Wn4_Media) & ~(Media_10TP|Media_SQE)) |
+			 media_tbl[dev->if_port].media_bits, ioaddr + Wn4_Media);
+	}
+
+	/* Switch to the stats window, and clear all stats by reading. */
+	outw(StatsDisable, ioaddr + EL3_CMD);
+	EL3WINDOW(6);
+	for (i = 0; i < 10; i++)
+		inb(ioaddr + i);
+	inw(ioaddr + 10);
+	inw(ioaddr + 12);
+	/* New: On the Vortex we must also clear the BadSSD counter. */
+	EL3WINDOW(4);
+	inb(ioaddr + 12);
+	/* ..and on the Boomerang we enable the extra statistics bits. */
+	outw(0x0040, ioaddr + Wn4_NetDiag);
+
+	/* Switch to register set 7 for normal use. */
+	EL3WINDOW(7);
+
+	if (vp->full_bus_master_rx) { /* Boomerang bus master. */
+		vp->cur_rx = vp->dirty_rx = 0;
+		/* Initialize the RxEarly register as recommended. */
+		outw(SetRxThreshold + (1536>>2), ioaddr + EL3_CMD);
+		outl(0x0020, ioaddr + PktStatus);
+		outl(virt_to_bus(&vp->rx_ring[0]), ioaddr + UpListPtr);
+	}
+	if (vp->full_bus_master_tx) { 		/* Boomerang bus master Tx. */
+		dev->hard_start_xmit = &boomerang_start_xmit;
+		vp->cur_tx = vp->dirty_tx = 0;
+		outb(PKT_BUF_SZ>>8, ioaddr + TxFreeThreshold); /* Room for a packet. */
+		/* Clear the Rx, Tx rings. */
+		for (i = 0; i < RX_RING_SIZE; i++)
+			vp->rx_ring[i].status = 0;
+		for (i = 0; i < TX_RING_SIZE; i++)
+			vp->tx_skbuff[i] = 0;
+		outl(0, ioaddr + DownListPtr);
+	}
+	/* Set receiver mode: presumably accept b-case and phys addr only. */
+	set_rx_mode(dev);
+	outw(StatsEnable, ioaddr + EL3_CMD); /* Turn on statistics. */
+
+	outw(RxEnable, ioaddr + EL3_CMD); /* Enable the receiver. */
+	outw(TxEnable, ioaddr + EL3_CMD); /* Enable transmitter. */
+	/* Allow status bits to be seen. */
+	vp->status_enable = SetStatusEnb | HostError|IntReq|StatsFull|TxComplete|
+		(vp->full_bus_master_tx ? DownComplete : TxAvailable) |
+		(vp->full_bus_master_rx ? UpComplete : RxComplete) |
+		(vp->bus_master ? DMADone : 0);
+	vp->intr_enable = SetIntrEnb | IntLatch | TxAvailable | RxComplete |
+		StatsFull | HostError | TxComplete | IntReq
+		| (vp->bus_master ? DMADone : 0) | UpComplete | DownComplete;
+	outw(vp->status_enable, ioaddr + EL3_CMD);
+	/* Ack all pending events, and set active indicator mask. */
+	outw(AckIntr | IntLatch | TxAvailable | RxEarly | IntReq,
+		 ioaddr + EL3_CMD);
+	outw(vp->intr_enable, ioaddr + EL3_CMD);
+	if (vp->cb_fn_base)			/* The PCMCIA people are idiots.  */
+		writel(0x8000, vp->cb_fn_base + 4);
+}
+
+static int
+vortex_open(struct net_device *dev)
+{
+	struct vortex_private *vp = (struct vortex_private *)dev->priv;
+	int i;
+
+#ifdef CARDBUS
+	if (vp->reap)
+		return -ENODEV;
+#endif
+	/* Use the now-standard shared IRQ implementation. */
+	if (request_irq(dev->irq, &vortex_interrupt, SA_SHIRQ, dev->name, dev)) {
+		return -EAGAIN;
+	}
+
+	if (vp->full_bus_master_rx) { /* Boomerang bus master. */
+		if (vortex_debug > 2)
+			printk(KERN_DEBUG "%s:  Filling in the Rx ring.\n", dev->name);
+		for (i = 0; i < RX_RING_SIZE; i++) {
+			struct sk_buff *skb;
+			vp->rx_ring[i].next = cpu_to_le32(virt_to_bus(&vp->rx_ring[i+1]));
+			vp->rx_ring[i].status = 0;	/* Clear complete bit. */
+			vp->rx_ring[i].length = cpu_to_le32(PKT_BUF_SZ | LAST_FRAG);
+			skb = dev_alloc_skb(PKT_BUF_SZ);
+			vp->rx_skbuff[i] = skb;
+			if (skb == NULL)
+				break;			/* Bad news!  */
+			skb->dev = dev;			/* Mark as being used by this device. */
+			skb_reserve(skb, 2);	/* Align IP on 16 byte boundaries */
+			vp->rx_ring[i].addr = cpu_to_le32(virt_to_bus(skb->tail));
+		}
+		/* Wrap the ring. */
+		vp->rx_ring[i-1].next = cpu_to_le32(virt_to_bus(&vp->rx_ring[0]));
+	}
+	if (vp->full_bus_master_tx)
+		dev->hard_start_xmit = &boomerang_start_xmit;
+
+	vortex_up(dev);
+	vp->open = 1;
+	netif_start_queue(dev);
+	netif_mark_up(dev);
+	MOD_INC_USE_COUNT;
+
+	return 0;
+}
+
+static void vortex_timer(unsigned long data)
+{
+	struct net_device *dev = (struct net_device *)data;
+	struct vortex_private *vp = (struct vortex_private *)dev->priv;
+	long ioaddr = dev->base_addr;
+	int next_tick = 60*HZ;
+	int ok = 0;
+	int media_status, mii_status, old_window;
+
+	if (vortex_debug > 1)
+		printk(KERN_DEBUG "%s: Media selection timer tick happened, %s.\n",
+			   dev->name, media_tbl[dev->if_port].name);
+
+	disable_irq(dev->irq);
+	old_window = inw(ioaddr + EL3_CMD) >> 13;
+	EL3WINDOW(4);
+	media_status = inw(ioaddr + Wn4_Media);
+	switch (dev->if_port) {
+	case XCVR_10baseT:  case XCVR_100baseTx:  case XCVR_100baseFx:
+		if (media_status & Media_LnkBeat) {
+			ok = 1;
+			if (vortex_debug > 1)
+				printk(KERN_DEBUG "%s: Media %s has link beat, %x.\n",
+					   dev->name, media_tbl[dev->if_port].name, media_status);
+		} else if (vortex_debug > 1)
+			printk(KERN_DEBUG "%s: Media %s is has no link beat, %x.\n",
+				   dev->name, media_tbl[dev->if_port].name, media_status);
+		break;
+	case XCVR_MII: case XCVR_NWAY:
+		  mii_status = mdio_read(ioaddr, vp->phys[0], 1);
+		  ok = 1;
+		  if (debug > 1)
+			  printk(KERN_DEBUG "%s: MII transceiver has status %4.4x.\n",
+					 dev->name, mii_status);
+		  if (mii_status & 0x0004) {
+			  int mii_reg5 = mdio_read(ioaddr, vp->phys[0], 5);
+			  if (! vp->force_fd  &&  mii_reg5 != 0xffff) {
+				  int duplex = (mii_reg5&0x0100) ||
+					  (mii_reg5 & 0x01C0) == 0x0040;
+				  if (vp->full_duplex != duplex) {
+					  vp->full_duplex = duplex;
+					  printk(KERN_INFO "%s: Setting %s-duplex based on MII "
+							 "#%d link partner capability of %4.4x.\n",
+							 dev->name, vp->full_duplex ? "full" : "half",
+							 vp->phys[0], mii_reg5);
+					  /* Set the full-duplex bit. */
+					  EL3WINDOW(3);
+					  outb((vp->full_duplex ? 0x20 : 0) |
+						   (dev->mtu > 1500 ? 0x40 : 0),
+						   ioaddr + Wn3_MAC_Ctrl);
+				  }
+				  next_tick = 60*HZ;
+			  }
+		  }
+		  break;
+	  default:					/* Other media types handled by Tx timeouts. */
+		if (vortex_debug > 1)
+		  printk(KERN_DEBUG "%s: Media %s is has no indication, %x.\n",
+				 dev->name, media_tbl[dev->if_port].name, media_status);
+		ok = 1;
+	}
+	if ( ! ok) {
+		union wn3_config config;
+
+		do {
+			dev->if_port = media_tbl[dev->if_port].next;
+		} while ( ! (vp->available_media & media_tbl[dev->if_port].mask));
+		if (dev->if_port == XCVR_Default) { /* Go back to default. */
+		  dev->if_port = vp->default_media;
+		  if (vortex_debug > 1)
+			printk(KERN_DEBUG "%s: Media selection failing, using default "
+				   "%s port.\n",
+				   dev->name, media_tbl[dev->if_port].name);
+		} else {
+			if (vortex_debug > 1)
+				printk(KERN_DEBUG "%s: Media selection failed, now trying "
+					   "%s port.\n",
+					   dev->name, media_tbl[dev->if_port].name);
+			next_tick = media_tbl[dev->if_port].wait;
+		}
+		outw((media_status & ~(Media_10TP|Media_SQE)) |
+			 media_tbl[dev->if_port].media_bits, ioaddr + Wn4_Media);
+
+		EL3WINDOW(3);
+		config.i = inl(ioaddr + Wn3_Config);
+		config.u.xcvr = dev->if_port;
+		outl(config.i, ioaddr + Wn3_Config);
+
+		outw(dev->if_port == XCVR_10base2 ? StartCoax : StopCoax,
+			 ioaddr + EL3_CMD);
+	}
+	EL3WINDOW(old_window);
+	enable_irq(dev->irq);
+
+	if (vortex_debug > 2)
+	  printk(KERN_DEBUG "%s: Media selection timer finished, %s.\n",
+			 dev->name, media_tbl[dev->if_port].name);
+
+	vp->timer.expires = jiffies + next_tick;
+	add_timer(&vp->timer);
+	if (vp->deferred)
+		outw(FakeIntr, ioaddr + EL3_CMD);
+	return;
+}
+
+static void vortex_tx_timeout(struct net_device *dev)
+{
+	struct vortex_private *vp = (struct vortex_private *)dev->priv;
+	long ioaddr = dev->base_addr;
+
+	printk(KERN_ERR "%s: transmit timed out, tx_status %2.2x status %4.4x.\n",
+		   dev->name, inb(ioaddr + TxStatus),
+		   inw(ioaddr + EL3_STATUS));
+	/* Slight code bloat to be user friendly. */
+	if ((inb(ioaddr + TxStatus) & 0x88) == 0x88)
+		printk(KERN_ERR "%s: Transmitter encountered 16 collisions --"
+			   " network cable problem?\n", dev->name);
+	if (inw(ioaddr + EL3_STATUS) & IntLatch) {
+		printk(KERN_ERR "%s: Interrupt posted but not delivered --"
+			   " IRQ blocked by another device?\n", dev->name);
+		/* Bad idea here.. but we might as well handle a few events. */
+		vortex_interrupt(dev->irq, dev, 0);
+	}
+
+#if ! defined(final_version)
+	if (vp->full_bus_master_tx) {
+		int i;
+		printk(KERN_DEBUG "  Flags; bus-master %d, full %d; dirty %d "
+			   "current %d.\n",
+			   vp->full_bus_master_tx, vp->tx_full, vp->dirty_tx, vp->cur_tx);
+		printk(KERN_DEBUG "  Transmit list %8.8x vs. %p.\n",
+			   inl(ioaddr + DownListPtr),
+			   &vp->tx_ring[vp->dirty_tx % TX_RING_SIZE]);
+		for (i = 0; i < TX_RING_SIZE; i++) {
+			printk(KERN_DEBUG "  %d: @%p  length %8.8x status %8.8x\n", i,
+				   &vp->tx_ring[i],
+				   le32_to_cpu(vp->tx_ring[i].length),
+				   le32_to_cpu(vp->tx_ring[i].status));
+		}
+	}
+#endif
+	wait_for_completion(dev, TxReset);
+
+	vp->stats.tx_errors++;
+	if (vp->full_bus_master_tx) {
+		if (vortex_debug > 0)
+			printk(KERN_DEBUG "%s: Resetting the Tx ring pointer.\n",
+				   dev->name);
+		if (vp->cur_tx - vp->dirty_tx > 0  &&  inl(ioaddr + DownListPtr) == 0)
+			outl(virt_to_bus(&vp->tx_ring[vp->dirty_tx % TX_RING_SIZE]),
+				 ioaddr + DownListPtr);
+		if (vp->tx_full && (vp->cur_tx - vp->dirty_tx <= TX_RING_SIZE - 1)) {
+			vp->tx_full = 0;
+			netif_start_queue(dev);
+		}
+		outb(PKT_BUF_SZ>>8, ioaddr + TxFreeThreshold);
+		outw(DownUnstall, ioaddr + EL3_CMD);
+	} else
+		vp->stats.tx_dropped++;
+	
+	/* Issue Tx Enable */
+	outw(TxEnable, ioaddr + EL3_CMD);
+	dev->trans_start = jiffies;
+	
+	/* Switch to register set 7 for normal use. */
+	EL3WINDOW(7);
+}
+
+/*
+ * Handle uncommon interrupt sources.  This is a separate routine to minimize
+ * the cache impact.
+ */
+static void
+vortex_error(struct net_device *dev, int status)
+{
+	struct vortex_private *vp = (struct vortex_private *)dev->priv;
+	long ioaddr = dev->base_addr;
+	int do_tx_reset = 0;
+
+	if (status & TxComplete) {			/* Really "TxError" for us. */
+		unsigned char tx_status = inb(ioaddr + TxStatus);
+		/* Presumably a tx-timeout. We must merely re-enable. */
+		if (vortex_debug > 2
+			|| (tx_status != 0x88 && vortex_debug > 0))
+			printk(KERN_DEBUG"%s: Transmit error, Tx status register %2.2x.\n",
+				   dev->name, tx_status);
+		if (tx_status & 0x14)  vp->stats.tx_fifo_errors++;
+		if (tx_status & 0x38)  vp->stats.tx_aborted_errors++;
+		outb(0, ioaddr + TxStatus);
+		if (tx_status & 0x30)
+			do_tx_reset = 1;
+		else					/* Merely re-enable the transmitter. */
+			outw(TxEnable, ioaddr + EL3_CMD);
+	}
+	if (status & RxEarly) {				/* Rx early is unused. */
+		vortex_rx(dev);
+		outw(AckIntr | RxEarly, ioaddr + EL3_CMD);
+	}
+	if (status & StatsFull) {			/* Empty statistics. */
+		static int DoneDidThat = 0;
+		if (vortex_debug > 4)
+			printk(KERN_DEBUG "%s: Updating stats.\n", dev->name);
+		update_stats(ioaddr, dev);
+		/* HACK: Disable statistics as an interrupt source. */
+		/* This occurs when we have the wrong media type! */
+		if (DoneDidThat == 0  &&
+			inw(ioaddr + EL3_STATUS) & StatsFull) {
+			printk(KERN_WARNING "%s: Updating statistics failed, disabling "
+				   "stats as an interrupt source.\n", dev->name);
+			EL3WINDOW(5);
+			outw(SetIntrEnb | (inw(ioaddr + 10) & ~StatsFull), ioaddr + EL3_CMD);
+			EL3WINDOW(7);
+			DoneDidThat++;
+		}
+	}
+	if (status & IntReq) {		/* Restore all interrupt sources.  */
+		outw(vp->status_enable, ioaddr + EL3_CMD);
+		outw(vp->intr_enable, ioaddr + EL3_CMD);
+	}
+	if (status & HostError) {
+		u16 fifo_diag;
+		EL3WINDOW(4);
+		fifo_diag = inw(ioaddr + Wn4_FIFODiag);
+		printk(KERN_ERR "%s: Host error, FIFO diagnostic register %4.4x.\n",
+			   dev->name, fifo_diag);
+		/* Adapter failure requires Tx/Rx reset and reinit. */
+		if (vp->full_bus_master_tx) {
+			/* In this case, blow the card away */
+			vortex_down(dev);
+			wait_for_completion(dev, TotalReset | 0xff);
+			vortex_up(dev);
+		} else if (fifo_diag & 0x0400)
+			do_tx_reset = 1;
+		if (fifo_diag & 0x3000) {
+			wait_for_completion(dev, RxReset);
+			/* Set the Rx filter to the current state. */
+			set_rx_mode(dev);
+			outw(RxEnable, ioaddr + EL3_CMD); /* Re-enable the receiver. */
+			outw(AckIntr | HostError, ioaddr + EL3_CMD);
+		}
+	}
+	if (do_tx_reset) {
+		wait_for_completion(dev, TxReset);
+		outw(TxEnable, ioaddr + EL3_CMD);
+	}
+
+}
+
+
+static int
+vortex_start_xmit(struct sk_buff *skb, struct net_device *dev)
+{
+	struct vortex_private *vp = (struct vortex_private *)dev->priv;
+	long ioaddr = dev->base_addr;
+
+	tx_timeout_check(dev, vortex_tx_timeout);
+
+	/* Put out the doubleword header... */
+	outl(skb->len, ioaddr + TX_FIFO);
+	if (vp->bus_master) {
+		/* Set the bus-master controller to transfer the packet. */
+		outl(virt_to_bus(skb->data), ioaddr + Wn7_MasterAddr);
+		outw((skb->len + 3) & ~3, ioaddr + Wn7_MasterLen);
+		vp->tx_skb = skb;
+		outw(StartDMADown, ioaddr + EL3_CMD);
+		/* queue will be restarted at the DMADone interrupt. */
+	} else {
+		/* ... and the packet rounded to a doubleword. */
+		outsl(ioaddr + TX_FIFO, skb->data, (skb->len + 3) >> 2);
+		DEV_FREE_SKB(skb);
+		if (inw(ioaddr + TxFree) > 1536) {
+			netif_start_queue(dev);
+		} else
+			/* Interrupt us when the FIFO has room for max-sized packet. */
+			outw(SetTxThreshold + (1536>>2), ioaddr + EL3_CMD);
+	}
+
+	dev->trans_start = jiffies;
+
+	/* Clear the Tx status stack. */
+	{
+		int tx_status;
+		int i = 32;
+
+		while (--i > 0	&&	(tx_status = inb(ioaddr + TxStatus)) > 0) {
+			if (tx_status & 0x3C) {		/* A Tx-disabling error occurred.  */
+				if (vortex_debug > 2)
+				  printk(KERN_DEBUG "%s: Tx error, status %2.2x.\n",
+						 dev->name, tx_status);
+				if (tx_status & 0x04) vp->stats.tx_fifo_errors++;
+				if (tx_status & 0x38) vp->stats.tx_aborted_errors++;
+				if (tx_status & 0x30) {
+					wait_for_completion(dev, TxReset);
+				}
+				outw(TxEnable, ioaddr + EL3_CMD);
+			}
+			outb(0x00, ioaddr + TxStatus); /* Pop the status stack. */
+		}
+	}
+	return 0;
+}
+
+static int
+boomerang_start_xmit(struct sk_buff *skb, struct net_device *dev)
+{
+	struct vortex_private *vp = (struct vortex_private *)dev->priv;
+	long ioaddr = dev->base_addr;
+
+	tx_timeout_check(dev, vortex_tx_timeout);
+
+	{
+		/* Calculate the next Tx descriptor entry. */
+		int entry = vp->cur_tx % TX_RING_SIZE;
+		struct boom_tx_desc *prev_entry =
+			&vp->tx_ring[(vp->cur_tx-1) % TX_RING_SIZE];
+		unsigned long flags;
+
+		if (vortex_debug > 3)
+			printk(KERN_DEBUG "%s: Trying to send a packet, Tx index %d.\n",
+				   dev->name, vp->cur_tx);
+		if (vp->tx_full) {
+			if (vortex_debug >0)
+				printk(KERN_WARNING "%s: Tx Ring full, refusing to send buffer.\n",
+					   dev->name);
+			return 1;
+		}
+		vp->tx_skbuff[entry] = skb;
+		vp->tx_ring[entry].next = 0;
+		vp->tx_ring[entry].addr = cpu_to_le32(virt_to_bus(skb->data));
+		vp->tx_ring[entry].length = cpu_to_le32(skb->len | LAST_FRAG);
+		vp->tx_ring[entry].status = cpu_to_le32(skb->len | TxIntrUploaded);
+
+		save_flags(flags);
+		cli();
+		/* Wait for the stall to complete. */
+		wait_for_completion(dev, DownStall);
+		prev_entry->next = cpu_to_le32(virt_to_bus(&vp->tx_ring[entry]));
+		if (inl(ioaddr + DownListPtr) == 0) {
+			outl(virt_to_bus(&vp->tx_ring[entry]), ioaddr + DownListPtr);
+			queued_packet++;
+		}
+		outw(DownUnstall, ioaddr + EL3_CMD);
+		restore_flags(flags);
+
+		vp->cur_tx++;
+		if (vp->cur_tx - vp->dirty_tx > TX_RING_SIZE - 1)
+			vp->tx_full = 1;
+		else {					/* Clear previous interrupt enable. */
+#if defined(tx_interrupt_mitigation)
+			prev_entry->status &= cpu_to_le32(~TxIntrUploaded);
+#endif
+			netif_start_queue(dev);
+		}
+		dev->trans_start = jiffies;
+		return 0;
+	}
+}
+
+/* The interrupt handler does all of the Rx thread work and cleans up
+   after the Tx thread. */
+static void vortex_interrupt(int irq, void *dev_id, struct pt_regs *regs)
+{
+	struct net_device *dev = dev_id;
+	struct vortex_private *vp = (struct vortex_private *)dev->priv;
+	long ioaddr;
+	int latency, status;
+	int work_done = max_interrupt_work;
+
+	ioaddr = dev->base_addr;
+	latency = inb(ioaddr + Timer);
+	status = inw(ioaddr + EL3_STATUS);
+	if (status & IntReq) {
+		status |= vp->deferred;
+		vp->deferred = 0;
+	}
+
+	if (status == 0xffff)
+		goto handler_exit;
+	if (vortex_debug > 4)
+		printk(KERN_DEBUG "%s: interrupt, status %4.4x, latency %d ticks.\n",
+			   dev->name, status, latency);
+	do {
+		if (vortex_debug > 5)
+				printk(KERN_DEBUG "%s: In interrupt loop, status %4.4x.\n",
+					   dev->name, status);
+		if (status & RxComplete)
+			vortex_rx(dev);
+		if (status & UpComplete) {
+			outw(AckIntr | UpComplete, ioaddr + EL3_CMD);
+			boomerang_rx(dev);
+		}
+
+		if (status & TxAvailable) {
+			if (vortex_debug > 5)
+				printk(KERN_DEBUG "	TX room bit was handled.\n");
+			/* There's room in the FIFO for a full-sized packet. */
+			outw(AckIntr | TxAvailable, ioaddr + EL3_CMD);
+			netif_wake_queue(dev);
+		}
+
+		if (status & DownComplete) {
+			unsigned int dirty_tx = vp->dirty_tx;
+
+			outw(AckIntr | DownComplete, ioaddr + EL3_CMD);
+			while (vp->cur_tx - dirty_tx > 0) {
+				int entry = dirty_tx % TX_RING_SIZE;
+				if (inl(ioaddr + DownListPtr) ==
+					virt_to_bus(&vp->tx_ring[entry]))
+					break;			/* It still hasn't been processed. */
+				if (vp->tx_skbuff[entry]) {
+					dev_kfree_skb_irq(vp->tx_skbuff[entry]);
+					vp->tx_skbuff[entry] = 0;
+				}
+				/* vp->stats.tx_packets++;  Counted below. */
+				dirty_tx++;
+			}
+			vp->dirty_tx = dirty_tx;
+			if (vp->tx_full && (vp->cur_tx - dirty_tx <= TX_RING_SIZE - 1)) {
+				vp->tx_full = 0;
+				netif_wake_queue(dev);
+			}
+		}
+		if (status & DMADone) {
+			if (inw(ioaddr + Wn7_MasterStatus) & 0x1000) {
+				outw(0x1000, ioaddr + Wn7_MasterStatus); /* Ack the event. */
+				dev_kfree_skb_irq(vp->tx_skb); /* Release the tx buffer */
+				if (inw(ioaddr + TxFree) > 1536) {
+					netif_wake_queue(dev);
+				} else /* Interrupt when FIFO has room for max-sized packet. */
+					outw(SetTxThreshold + (1536>>2), ioaddr + EL3_CMD);
+			}
+		}
+		/* Check for all uncommon interrupts at once. */
+		if (status & (HostError | RxEarly | StatsFull | TxComplete | IntReq)) {
+			if (status == 0xffff)
+				break;
+			vortex_error(dev, status);
+		}
+
+		if (--work_done < 0) {
+			printk(KERN_WARNING "%s: Too much work in interrupt, status "
+				   "%4.4x.\n", dev->name, status);
+			/* Disable all pending interrupts. */
+			do {
+				vp->deferred |= status;
+				outw(SetStatusEnb | (~vp->deferred & vp->status_enable),
+					 ioaddr + EL3_CMD);
+				outw(AckIntr | (vp->deferred & 0x7ff), ioaddr + EL3_CMD);
+			} while ((status = inw(ioaddr + EL3_CMD)) & IntLatch);
+			/* The timer will reenable interrupts. */
+			del_timer(&vp->timer);
+			vp->timer.expires = jiffies + 1;
+			add_timer(&vp->timer);
+			break;
+		}
+		/* Acknowledge the IRQ. */
+		outw(AckIntr | IntReq | IntLatch, ioaddr + EL3_CMD);
+		if (vp->cb_fn_base)			/* The PCMCIA people are idiots.  */
+			writel(0x8000, vp->cb_fn_base + 4);
+
+	} while ((status = inw(ioaddr + EL3_STATUS)) & (IntLatch | RxComplete));
+
+	if (vortex_debug > 4)
+		printk(KERN_DEBUG "%s: exiting interrupt, status %4.4x.\n",
+			   dev->name, status);
+handler_exit:
+	return;
+}
+
+static int vortex_rx(struct net_device *dev)
+{
+	struct vortex_private *vp = (struct vortex_private *)dev->priv;
+	long ioaddr = dev->base_addr;
+	int i;
+	short rx_status;
+
+	if (vortex_debug > 5)
+		printk(KERN_DEBUG"   In rx_packet(), status %4.4x, rx_status %4.4x.\n",
+			   inw(ioaddr+EL3_STATUS), inw(ioaddr+RxStatus));
+	while ((rx_status = inw(ioaddr + RxStatus)) > 0) {
+		if (rx_status & 0x4000) { /* Error, update stats. */
+			unsigned char rx_error = inb(ioaddr + RxErrors);
+			if (vortex_debug > 2)
+				printk(KERN_DEBUG " Rx error: status %2.2x.\n", rx_error);
+			vp->stats.rx_errors++;
+			if (rx_error & 0x01)  vp->stats.rx_over_errors++;
+			if (rx_error & 0x02)  vp->stats.rx_length_errors++;
+			if (rx_error & 0x04)  vp->stats.rx_frame_errors++;
+			if (rx_error & 0x08)  vp->stats.rx_crc_errors++;
+			if (rx_error & 0x10)  vp->stats.rx_length_errors++;
+		} else {
+			/* The packet length: up to 4.5K!. */
+			int pkt_len = rx_status & 0x1fff;
+			struct sk_buff *skb;
+
+			skb = dev_alloc_skb(pkt_len + 5);
+			if (vortex_debug > 4)
+				printk(KERN_DEBUG "Receiving packet size %d status %4.4x.\n",
+					   pkt_len, rx_status);
+			if (skb != NULL) {
+				skb->dev = dev;
+				skb_reserve(skb, 2);	/* Align IP on 16 byte boundaries */
+				/* 'skb_put()' points to the start of sk_buff data area. */
+				if (vp->bus_master &&
+					! (inw(ioaddr + Wn7_MasterStatus) & 0x8000)) {
+					outl(virt_to_bus(skb_put(skb, pkt_len)),
+						 ioaddr + Wn7_MasterAddr);
+					outw((skb->len + 3) & ~3, ioaddr + Wn7_MasterLen);
+					outw(StartDMAUp, ioaddr + EL3_CMD);
+					while (inw(ioaddr + Wn7_MasterStatus) & 0x8000)
+						;
+				} else {
+					insl(ioaddr + RX_FIFO, skb_put(skb, pkt_len),
+						 (pkt_len + 3) >> 2);
+				}
+				outw(RxDiscard, ioaddr + EL3_CMD); /* Pop top Rx packet. */
+				skb->protocol = eth_type_trans(skb, dev);
+				netif_rx(skb);
+				dev->last_rx = jiffies;
+				vp->stats.rx_packets++;
+				/* Wait a limited time to go to next packet. */
+				for (i = 200; i >= 0; i--)
+					if ( ! (inw(ioaddr + EL3_STATUS) & CmdInProgress))
+						break;
+				continue;
+			} else if (vortex_debug)
+				printk(KERN_NOTICE "%s: No memory to allocate a sk_buff of "
+					   "size %d.\n", dev->name, pkt_len);
+		}
+		vp->stats.rx_dropped++;
+		wait_for_completion(dev, RxDiscard);
+	}
+
+	return 0;
+}
+
+static int
+boomerang_rx(struct net_device *dev)
+{
+	struct vortex_private *vp = (struct vortex_private *)dev->priv;
+	int entry = vp->cur_rx % RX_RING_SIZE;
+	long ioaddr = dev->base_addr;
+	int rx_status;
+	int rx_work_limit = vp->dirty_rx + RX_RING_SIZE - vp->cur_rx;
+
+	if (vortex_debug > 5)
+		printk(KERN_DEBUG "  In boomerang_rx(), status %4.4x, rx_status "
+			   "%4.4x.\n",
+			   inw(ioaddr+EL3_STATUS), inw(ioaddr+RxStatus));
+	while ((rx_status = le32_to_cpu(vp->rx_ring[entry].status)) & RxDComplete){
+		if (--rx_work_limit < 0)
+			break;
+		if (rx_status & RxDError) { /* Error, update stats. */
+			unsigned char rx_error = rx_status >> 16;
+			if (vortex_debug > 2)
+				printk(KERN_DEBUG " Rx error: status %2.2x.\n", rx_error);
+			vp->stats.rx_errors++;
+			if (rx_error & 0x01)  vp->stats.rx_over_errors++;
+			if (rx_error & 0x02)  vp->stats.rx_length_errors++;
+			if (rx_error & 0x04)  vp->stats.rx_frame_errors++;
+			if (rx_error & 0x08)  vp->stats.rx_crc_errors++;
+			if (rx_error & 0x10)  vp->stats.rx_length_errors++;
+		} else {
+			/* The packet length: up to 4.5K!. */
+			int pkt_len = rx_status & 0x1fff;
+			struct sk_buff *skb;
+
+			if (vortex_debug > 4)
+				printk(KERN_DEBUG "Receiving packet size %d status %4.4x.\n",
+					   pkt_len, rx_status);
+
+			/* Check if the packet is long enough to just accept without
+			   copying to a properly sized skbuff. */
+			if (pkt_len < rx_copybreak
+				&& (skb = dev_alloc_skb(pkt_len + 2)) != 0) {
+				skb->dev = dev;
+				skb_reserve(skb, 2);	/* Align IP on 16 byte boundaries */
+				/* 'skb_put()' points to the start of sk_buff data area. */
+				memcpy(skb_put(skb, pkt_len),
+					   bus_to_virt(le32_to_cpu(vp->rx_ring[entry].addr)),
+					   pkt_len);
+				rx_copy++;
+			} else {
+				void *temp;
+				/* Pass up the skbuff already on the Rx ring. */
+				skb = vp->rx_skbuff[entry];
+				vp->rx_skbuff[entry] = NULL;
+				temp = skb_put(skb, pkt_len);
+				/* Remove this checking code for final release. */
+				if (bus_to_virt(le32_to_cpu(vp->rx_ring[entry].addr)) != temp)
+					printk(KERN_ERR "%s: Warning -- the skbuff addresses do not match"
+						   " in boomerang_rx: %p vs. %p.\n", dev->name,
+						   bus_to_virt(le32_to_cpu(vp->rx_ring[entry].addr)),
+						   temp);
+				rx_nocopy++;
+			}
+			skb->protocol = eth_type_trans(skb, dev);
+			{					/* Use hardware checksum info. */
+				int csum_bits = rx_status & 0xee000000;
+				if (csum_bits &&
+					(csum_bits == (IPChksumValid | TCPChksumValid) ||
+					 csum_bits == (IPChksumValid | UDPChksumValid))) {
+					skb->ip_summed = CHECKSUM_UNNECESSARY;
+					rx_csumhits++;
+				}
+			}
+			netif_rx(skb);
+			dev->last_rx = jiffies;
+			vp->stats.rx_packets++;
+		}
+		entry = (++vp->cur_rx) % RX_RING_SIZE;
+	}
+	/* Refill the Rx ring buffers. */
+	for (; vp->dirty_rx < vp->cur_rx; vp->dirty_rx++) {
+		struct sk_buff *skb;
+		entry = vp->dirty_rx % RX_RING_SIZE;
+		if (vp->rx_skbuff[entry] == NULL) {
+			skb = dev_alloc_skb(PKT_BUF_SZ);
+			if (skb == NULL)
+				break;			/* Bad news!  */
+			skb->dev = dev;			/* Mark as being used by this device. */
+			skb_reserve(skb, 2);	/* Align IP on 16 byte boundaries */
+			vp->rx_ring[entry].addr = cpu_to_le32(virt_to_bus(skb->tail));
+			vp->rx_skbuff[entry] = skb;
+		}
+		vp->rx_ring[entry].status = 0;	/* Clear complete bit. */
+		outw(UpUnstall, ioaddr + EL3_CMD);
+	}
+	return 0;
+}
+
+static void
+vortex_down(struct net_device *dev)
+{
+	struct vortex_private *vp = (struct vortex_private *)dev->priv;
+	long ioaddr = dev->base_addr;
+
+	del_timer(&vp->timer);
+
+	/* Turn off statistics ASAP.  We update vp->stats below. */
+	outw(StatsDisable, ioaddr + EL3_CMD);
+
+	/* Disable the receiver and transmitter. */
+	outw(RxDisable, ioaddr + EL3_CMD);
+	outw(TxDisable, ioaddr + EL3_CMD);
+
+	if (dev->if_port == XCVR_10base2)
+		/* Turn off thinnet power.  Green! */
+		outw(StopCoax, ioaddr + EL3_CMD);
+
+	outw(SetIntrEnb | 0x0000, ioaddr + EL3_CMD);
+
+	update_stats(ioaddr, dev);
+	if (vp->full_bus_master_rx)
+		outl(0, ioaddr + UpListPtr);
+	if (vp->full_bus_master_tx)
+		outl(0, ioaddr + DownListPtr);
+
+	if (vp->capabilities & CapPwrMgmt)
+		acpi_set_WOL(dev);
+}
+
+static int
+vortex_close(struct net_device *dev)
+{
+	struct vortex_private *vp = (struct vortex_private *)dev->priv;
+	long ioaddr = dev->base_addr;
+	int i;
+
+	if (netif_device_present(dev)) {
+		netif_stop_queue(dev);
+		netif_mark_down(dev);
+		vortex_down(dev);
+	}
+
+	if (vortex_debug > 1) {
+		printk(KERN_DEBUG"%s: vortex_close() status %4.4x, Tx status %2.2x.\n",
+			   dev->name, inw(ioaddr + EL3_STATUS), inb(ioaddr + TxStatus));
+		printk(KERN_DEBUG "%s: vortex close stats: rx_nocopy %d rx_copy %d"
+			   " tx_queued %d Rx pre-checksummed %d.\n",
+			   dev->name, rx_nocopy, rx_copy, queued_packet, rx_csumhits);
+	}
+
+	free_irq(dev->irq, dev);
+
+	if (vp->full_bus_master_rx) { /* Free Boomerang bus master Rx buffers. */
+		for (i = 0; i < RX_RING_SIZE; i++)
+			if (vp->rx_skbuff[i]) {
+#if LINUX_VERSION_CODE < 0x20100
+				vp->rx_skbuff[i]->free = 1;
+#endif
+				DEV_FREE_SKB(vp->rx_skbuff[i]);
+				vp->rx_skbuff[i] = 0;
+			}
+	}
+	if (vp->full_bus_master_tx) { /* Free Boomerang bus master Tx buffers. */
+		for (i = 0; i < TX_RING_SIZE; i++)
+			if (vp->tx_skbuff[i]) {
+				DEV_FREE_SKB(vp->tx_skbuff[i]);
+				vp->tx_skbuff[i] = 0;
+			}
+	}
+
+	MOD_DEC_USE_COUNT;
+	vp->open = 0;
+	return 0;
+}
+
+static struct net_device_stats *vortex_get_stats(struct net_device *dev)
+{
+	struct vortex_private *vp = (struct vortex_private *)dev->priv;
+	unsigned long flags;
+
+	if (netif_device_present(dev)) {
+		save_flags(flags);
+		cli();
+		update_stats(dev->base_addr, dev);
+		restore_flags(flags);
+	}
+	return &vp->stats;
+}
+
+/*  Update statistics.
+	Unlike with the EL3 we need not worry about interrupts changing
+	the window setting from underneath us, but we must still guard
+	against a race condition with a StatsUpdate interrupt updating the
+	table.  This is done by checking that the ASM (!) code generated uses
+	atomic updates with '+='.
+	*/
+static void update_stats(long ioaddr, struct net_device *dev)
+{
+	struct vortex_private *vp = (struct vortex_private *)dev->priv;
+	int old_window = inw(ioaddr + EL3_CMD);
+
+	if (old_window == 0xffff)	/* Chip suspended or ejected. */
+		return;
+	/* Unlike the 3c5x9 we need not turn off stats updates while reading. */
+	/* Switch to the stats window, and read everything. */
+	EL3WINDOW(6);
+	vp->stats.tx_carrier_errors		+= inb(ioaddr + 0);
+	vp->stats.tx_heartbeat_errors	+= inb(ioaddr + 1);
+	/* Multiple collisions. */		inb(ioaddr + 2);
+	vp->stats.collisions			+= inb(ioaddr + 3);
+	vp->stats.tx_window_errors		+= inb(ioaddr + 4);
+	vp->stats.rx_fifo_errors		+= inb(ioaddr + 5);
+	vp->stats.tx_packets			+= inb(ioaddr + 6);
+	vp->stats.tx_packets			+= (inb(ioaddr + 9)&0x30) << 4;
+	/* Rx packets	*/				inb(ioaddr + 7);   /* Must read to clear */
+	/* Tx deferrals */				inb(ioaddr + 8);
+	/* Don't bother with register 9, an extension of registers 6&7.
+	   If we do use the 6&7 values the atomic update assumption above
+	   is invalid. */
+#if LINUX_VERSION_CODE > 0x020119
+	vp->stats.rx_bytes += inw(ioaddr + 10);
+	vp->stats.tx_bytes += inw(ioaddr + 12);
+#else
+	inw(ioaddr + 10);
+	inw(ioaddr + 12);
+#endif
+	/* New: On the Vortex we must also clear the BadSSD counter. */
+	EL3WINDOW(4);
+	inb(ioaddr + 12);
+
+#if LINUX_VERSION_CODE > 0x020119
+	{
+		u8 up = inb(ioaddr + 13);
+		vp->stats.rx_bytes += (up & 0x0f) << 16;
+		vp->stats.tx_bytes += (up & 0xf0) << 12;
+	}
+#endif
+
+	/* We change back to window 7 (not 1) with the Vortex. */
+	EL3WINDOW(old_window >> 13);
+	return;
+}
+
+static int vortex_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
+{
+	struct vortex_private *vp = (struct vortex_private *)dev->priv;
+	long ioaddr = dev->base_addr;
+	u16 *data = (u16 *)&rq->ifr_data;
+	int phy = vp->phys[0] & 0x1f;
+
+	switch(cmd) {
+	case SIOCDEVPRIVATE:		/* Get the address of the PHY in use. */
+		data[0] = phy;
+	case SIOCDEVPRIVATE+1:		/* Read the specified MII register. */
+		EL3WINDOW(4);
+		data[3] = mdio_read(ioaddr, data[0] & 0x1f, data[1] & 0x1f);
+		return 0;
+	case SIOCDEVPRIVATE+2:		/* Write the specified MII register */
+		if (!capable(CAP_NET_ADMIN))
+			return -EPERM;
+		EL3WINDOW(4);
+		mdio_write(ioaddr, data[0] & 0x1f, data[1] & 0x1f, data[2]);
+		return 0;
+	default:
+		return -EOPNOTSUPP;
+	}
+}
+
+/* Pre-Cyclone chips have no documented multicast filter, so the only
+   multicast setting is to receive all multicast frames.  At least
+   the chip has a very clean way to set the mode, unlike many others. */
+static void set_rx_mode(struct net_device *dev)
+{
+	long ioaddr = dev->base_addr;
+	int new_mode;
+
+	if (dev->flags & IFF_PROMISC) {
+		if (vortex_debug > 0)
+			printk(KERN_NOTICE "%s: Setting promiscuous mode.\n", dev->name);
+		new_mode = SetRxFilter|RxStation|RxMulticast|RxBroadcast|RxProm;
+	} else	if ((dev->mc_list)  ||  (dev->flags & IFF_ALLMULTI)) {
+		new_mode = SetRxFilter|RxStation|RxMulticast|RxBroadcast;
+	} else
+		new_mode = SetRxFilter | RxStation | RxBroadcast;
+
+	outw(new_mode, ioaddr + EL3_CMD);
+}
+
+
+/* MII transceiver control section.
+   Read and write the MII registers using software-generated serial
+   MDIO protocol.  See the MII specifications or DP83840A data sheet
+   for details. */
+
+/* The maximum data clock rate is 2.5 Mhz.  The minimum timing is usually
+   met by back-to-back PCI I/O cycles, but we insert a delay to avoid
+   "overclocking" issues. */
+#define mdio_delay() inl(mdio_addr)
+
+#define MDIO_SHIFT_CLK	0x01
+#define MDIO_DIR_WRITE	0x04
+#define MDIO_DATA_WRITE0 (0x00 | MDIO_DIR_WRITE)
+#define MDIO_DATA_WRITE1 (0x02 | MDIO_DIR_WRITE)
+#define MDIO_DATA_READ	0x02
+#define MDIO_ENB_IN		0x00
+
+/* Generate the preamble required for initial synchronization and
+   a few older transceivers. */
+static void mdio_sync(long ioaddr, int bits)
+{
+	long mdio_addr = ioaddr + Wn4_PhysicalMgmt;
+
+	/* Establish sync by sending at least 32 logic ones. */
+	while (-- bits >= 0) {
+		outw(MDIO_DATA_WRITE1, mdio_addr);
+		mdio_delay();
+		outw(MDIO_DATA_WRITE1 | MDIO_SHIFT_CLK, mdio_addr);
+		mdio_delay();
+	}
+}
+
+static int mdio_read(long ioaddr, int phy_id, int location)
+{
+	int i;
+	int read_cmd = (0xf6 << 10) | (phy_id << 5) | location;
+	unsigned int retval = 0;
+	long mdio_addr = ioaddr + Wn4_PhysicalMgmt;
+
+	if (mii_preamble_required)
+		mdio_sync(ioaddr, 32);
+
+	/* Shift the read command bits out. */
+	for (i = 14; i >= 0; i--) {
+		int dataval = (read_cmd&(1<<i)) ? MDIO_DATA_WRITE1 : MDIO_DATA_WRITE0;
+		outw(dataval, mdio_addr);
+		mdio_delay();
+		outw(dataval | MDIO_SHIFT_CLK, mdio_addr);
+		mdio_delay();
+	}
+	/* Read the two transition, 16 data, and wire-idle bits. */
+	for (i = 19; i > 0; i--) {
+		outw(MDIO_ENB_IN, mdio_addr);
+		mdio_delay();
+		retval = (retval << 1) | ((inw(mdio_addr) & MDIO_DATA_READ) ? 1 : 0);
+		outw(MDIO_ENB_IN | MDIO_SHIFT_CLK, mdio_addr);
+		mdio_delay();
+	}
+	return retval & 0x20000 ? 0xffff : retval>>1 & 0xffff;
+}
+
+static void mdio_write(long ioaddr, int phy_id, int location, int value)
+{
+	int write_cmd = 0x50020000 | (phy_id << 23) | (location << 18) | value;
+	long mdio_addr = ioaddr + Wn4_PhysicalMgmt;
+	int i;
+
+	if (mii_preamble_required)
+		mdio_sync(ioaddr, 32);
+
+	/* Shift the command bits out. */
+	for (i = 31; i >= 0; i--) {
+		int dataval = (write_cmd&(1<<i)) ? MDIO_DATA_WRITE1 : MDIO_DATA_WRITE0;
+		outw(dataval, mdio_addr);
+		mdio_delay();
+		outw(dataval | MDIO_SHIFT_CLK, mdio_addr);
+		mdio_delay();
+	}
+	/* Leave the interface idle. */
+	for (i = 1; i >= 0; i--) {
+		outw(MDIO_ENB_IN, mdio_addr);
+		mdio_delay();
+		outw(MDIO_ENB_IN | MDIO_SHIFT_CLK, mdio_addr);
+		mdio_delay();
+	}
+
+	return;
+}
+
+/* ACPI: Advanced Configuration and Power Interface. */
+/* Set Wake-On-LAN mode and put the board into D3 (power-down) state. */
+static void acpi_set_WOL(struct net_device *dev)
+{
+	struct vortex_private *vp = (struct vortex_private *)dev->priv;
+	long ioaddr = dev->base_addr;
+
+	/* Power up on: 1==Downloaded Filter, 2==Magic Packets, 4==Link Status. */
+	EL3WINDOW(7);
+	outw(2, ioaddr + 0x0c);
+	/* The RxFilter must accept the WOL frames. */
+	outw(SetRxFilter|RxStation|RxMulticast|RxBroadcast, ioaddr + EL3_CMD);
+	outw(RxEnable, ioaddr + EL3_CMD);
+	/* Change the power state to D3; RxEnable doesn't take effect. */
+	pcibios_write_config_word(vp->pci_bus, vp->pci_devfn, 0xe0, 0x8103);
+}
+/* Change from D3 (sleep) to D0 (active).
+   Problem: The Cyclone forgets all PCI config info during the transition! */
+static void acpi_wake(int bus, int devfn)
+{
+	u32 base0, base1, romaddr;
+	u16 pci_command, pwr_command;
+	u8  pci_latency, pci_cacheline, irq;
+
+	pcibios_read_config_word(bus, devfn, 0xe0, &pwr_command);
+	if ((pwr_command & 3) == 0)
+		return;
+	pcibios_read_config_word( bus, devfn, PCI_COMMAND, &pci_command);
+	pcibios_read_config_dword(bus, devfn, PCI_BASE_ADDRESS_0, &base0);
+	pcibios_read_config_dword(bus, devfn, PCI_BASE_ADDRESS_1, &base1);
+	pcibios_read_config_dword(bus, devfn, PCI_ROM_ADDRESS, &romaddr);
+	pcibios_read_config_byte( bus, devfn, PCI_LATENCY_TIMER, &pci_latency);
+	pcibios_read_config_byte( bus, devfn, PCI_CACHE_LINE_SIZE, &pci_cacheline);
+	pcibios_read_config_byte( bus, devfn, PCI_INTERRUPT_LINE, &irq);
+
+	pcibios_write_config_word( bus, devfn, 0xe0, 0x0000);
+	pcibios_write_config_dword(bus, devfn, PCI_BASE_ADDRESS_0, base0);
+	pcibios_write_config_dword(bus, devfn, PCI_BASE_ADDRESS_1, base1);
+	pcibios_write_config_dword(bus, devfn, PCI_ROM_ADDRESS, romaddr);
+	pcibios_write_config_byte( bus, devfn, PCI_INTERRUPT_LINE, irq);
+	pcibios_write_config_byte( bus, devfn, PCI_LATENCY_TIMER, pci_latency);
+	pcibios_write_config_byte( bus, devfn, PCI_CACHE_LINE_SIZE, pci_cacheline);
+	pcibios_write_config_word( bus, devfn, PCI_COMMAND, pci_command | 5);
+}
+
+
+#ifdef MODULE
+void cleanup_module(void)
+{
+	struct net_device *next_dev;
+
+#ifdef CARDBUS
+	unregister_driver(&vortex_ops);
+	vortex_reap();
+#endif
+
+	/* No need to check MOD_IN_USE, as sys_delete_module() checks. */
+	while (root_vortex_dev) {
+		struct vortex_private *vp=(void *)(root_vortex_dev->priv);
+		next_dev = vp->next_module;
+		unregister_netdev(root_vortex_dev);
+		outw(TotalReset, root_vortex_dev->base_addr + EL3_CMD);
+		release_region(root_vortex_dev->base_addr,
+					   pci_tbl[vp->chip_id].io_size);
+		kfree(root_vortex_dev);
+		kfree(vp->priv_addr);
+		root_vortex_dev = next_dev;
+	}
+}
+
+#endif  /* MODULE */
+
+/*
+ * Local variables:
+ *  compile-command: "gcc -DMODULE -D__KERNEL__ -Wall -Wstrict-prototypes -O6 -c 3c59x.c `[ -f /usr/include/linux/modversions.h ] && echo -DMODVERSIONS`"
+ *  SMP-compile-command: "gcc -D__SMP__ -DMODULE -D__KERNEL__ -Wall -Wstrict-prototypes -O6 -c 3c59x.c"
+ *  cardbus-compile-command: "gcc -DCARDBUS -DMODULE -D__KERNEL__ -Wall -Wstrict-prototypes -O6 -c 3c59x.c -o 3c575_cb.o -I/usr/src/linux/pcmcia-cs-3.0.9/include/"
+ *  c-indent-level: 4
+ *  c-basic-offset: 4
+ *  tab-width: 4
+ * End:
+ */
Index: oldkernel/linux/pcmcia-cs-3.1.15/clients/3c589_cs.c
diff -u /dev/null linux/pcmcia-cs-3.1.15/clients/3c589_cs.c:1.1
--- /dev/null	Mon Jul 31 21:15:10 2000
+++ linux/pcmcia-cs-3.1.15/clients/3c589_cs.c	Fri Jul  7 16:34:58 2000
@@ -0,0 +1,1123 @@
+/*======================================================================
+
+    A PCMCIA ethernet driver for the 3com 3c589 card.
+    
+    Copyright (C) 1999 David A. Hinds -- dhinds@pcmcia.sourceforge.org
+
+    3c589_cs.c 1.151 2000/05/08 22:03:18
+
+    The network driver code is based on Donald Becker's 3c589 code:
+    
+    Written 1994 by Donald Becker.
+    Copyright 1993 United States Government as represented by the
+    Director, National Security Agency.  This software may be used and
+    distributed according to the terms of the GNU Public License,
+    incorporated herein by reference.
+    Donald Becker may be reached at becker@cesdis1.gsfc.nasa.gov
+
+======================================================================*/
+
+#include <pcmcia/config.h>
+#include <pcmcia/k_compat.h>
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/ptrace.h>
+#include <linux/malloc.h>
+#include <linux/string.h>
+#include <linux/timer.h>
+#include <linux/interrupt.h>
+#include <linux/in.h>
+#include <linux/delay.h>
+#include <asm/io.h>
+#include <asm/system.h>
+#include <asm/bitops.h>
+
+#include <linux/netdevice.h>
+#include <linux/etherdevice.h>
+#include <linux/skbuff.h>
+#include <linux/if_arp.h>
+#include <linux/ioport.h>
+
+#include <pcmcia/version.h>
+#include <pcmcia/cs_types.h>
+#include <pcmcia/cs.h>
+#include <pcmcia/cistpl.h>
+#include <pcmcia/cisreg.h>
+#include <pcmcia/ciscode.h>
+#include <pcmcia/ds.h>
+
+/* To minimize the size of the driver source I only define operating
+   constants if they are used several times.  You'll need the manual
+   if you want to understand driver details. */
+/* Offsets from base I/O address. */
+#define EL3_DATA	0x00
+#define EL3_TIMER	0x0a
+#define EL3_CMD		0x0e
+#define EL3_STATUS	0x0e
+
+#define EEPROM_READ	0x0080
+#define EEPROM_BUSY	0x8000
+
+#define EL3WINDOW(win_num) outw(SelectWindow + (win_num), ioaddr + EL3_CMD)
+
+/* The top five bits written to EL3_CMD are a command, the lower
+   11 bits are the parameter, if applicable. */
+enum c509cmd {
+    TotalReset = 0<<11, SelectWindow = 1<<11, StartCoax = 2<<11,
+    RxDisable = 3<<11, RxEnable = 4<<11, RxReset = 5<<11, RxDiscard = 8<<11,
+    TxEnable = 9<<11, TxDisable = 10<<11, TxReset = 11<<11,
+    FakeIntr = 12<<11, AckIntr = 13<<11, SetIntrEnb = 14<<11,
+    SetStatusEnb = 15<<11, SetRxFilter = 16<<11, SetRxThreshold = 17<<11,
+    SetTxThreshold = 18<<11, SetTxStart = 19<<11, StatsEnable = 21<<11,
+    StatsDisable = 22<<11, StopCoax = 23<<11,
+};
+
+enum c509status {
+    IntLatch = 0x0001, AdapterFailure = 0x0002, TxComplete = 0x0004,
+    TxAvailable = 0x0008, RxComplete = 0x0010, RxEarly = 0x0020,
+    IntReq = 0x0040, StatsFull = 0x0080, CmdBusy = 0x1000
+};
+
+/* The SetRxFilter command accepts the following classes: */
+enum RxFilter {
+    RxStation = 1, RxMulticast = 2, RxBroadcast = 4, RxProm = 8
+};
+
+/* Register window 1 offsets, the window used in normal operation. */
+#define TX_FIFO		0x00
+#define RX_FIFO		0x00
+#define RX_STATUS 	0x08
+#define TX_STATUS 	0x0B
+#define TX_FREE		0x0C	/* Remaining free bytes in Tx buffer. */
+
+#define WN0_IRQ		0x08	/* Window 0: Set IRQ line in bits 12-15. */
+#define WN4_MEDIA	0x0A	/* Window 4: Various transcvr/media bits. */
+#define MEDIA_TP	0x00C0	/* Enable link beat and jabber for 10baseT. */
+#define MEDIA_LED	0x0001	/* Enable link light on 3C589E cards. */
+
+/* Time in jiffies before concluding Tx hung */
+#define TX_TIMEOUT	((400*HZ)/1000)
+
+struct el3_private {
+    dev_link_t		link;
+    struct net_device	dev;
+    dev_node_t 		node;
+    struct net_device_stats stats;
+    /* For transceiver monitoring */
+    struct timer_list	media;
+    u_short		media_status;
+    u_short		fast_poll;
+    u_long		last_irq;
+};
+
+static char *if_names[] = { "auto", "10baseT", "10base2", "AUI" };
+
+#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 =
+"3c589_cs.c 1.151 2000/05/08 22:03:18 (David Hinds)";
+#else
+#define DEBUG(n, args...)
+#endif
+
+/*====================================================================*/
+
+/* Parameters that can be set with 'insmod' */
+
+/* Special hook for setting if_port when module is loaded */
+static int if_port = 0;
+
+/* Bit map of interrupts to choose from */
+static u_int irq_mask = 0xdeb8;
+static int irq_list[4] = { -1 };
+
+MODULE_PARM(if_port, "i");
+MODULE_PARM(irq_mask, "i");
+MODULE_PARM(irq_list, "1-4i");
+
+/*====================================================================*/
+
+static void tc589_config(dev_link_t *link);
+static void tc589_release(u_long arg);
+static int tc589_event(event_t event, int priority,
+		       event_callback_args_t *args);
+
+static u_short read_eeprom(ioaddr_t ioaddr, int index);
+static void tc589_reset(struct net_device *dev);
+static void media_check(u_long arg);
+static int el3_config(struct net_device *dev, struct ifmap *map);
+static int el3_open(struct net_device *dev);
+static int el3_start_xmit(struct sk_buff *skb, struct net_device *dev);
+static void el3_interrupt(int irq, void *dev_id, struct pt_regs *regs);
+static void update_stats(struct net_device *dev);
+static struct net_device_stats *el3_get_stats(struct net_device *dev);
+static int el3_rx(struct net_device *dev);
+static int el3_close(struct net_device *dev);
+static void el3_tx_timeout(struct net_device *dev);
+static void set_multicast_list(struct net_device *dev);
+
+static dev_info_t dev_info = "3c589_cs";
+
+static dev_link_t *tc589_attach(void);
+static void tc589_detach(dev_link_t *);
+
+static dev_link_t *dev_list = NULL;
+
+/*======================================================================
+
+    This bit of code is used to avoid unregistering network devices
+    at inappropriate times.  2.2 and later kernels are fairly picky
+    about when this can happen.
+    
+======================================================================*/
+
+static void flush_stale_links(void)
+{
+    dev_link_t *link, *next;
+    for (link = dev_list; link; link = next) {
+	next = link->next;
+	if (link->state & DEV_STALE_LINK)
+	    tc589_detach(link);
+    }
+}
+
+/*====================================================================*/
+
+static void cs_error(client_handle_t handle, int func, int ret)
+{
+    error_info_t err = { func, ret };
+    CardServices(ReportError, handle, &err);
+}
+
+/*======================================================================
+
+    tc589_attach() creates an "instance" of the driver, allocating
+    local data structures for one device.  The device is registered
+    with Card Services.
+
+======================================================================*/
+
+static dev_link_t *tc589_attach(void)
+{
+    struct el3_private *lp;
+    client_reg_t client_reg;
+    dev_link_t *link;
+    struct net_device *dev;
+    int i, ret;
+
+    DEBUG(0, "3c589_attach()\n");
+    flush_stale_links();
+    
+    /* Create new ethernet device */
+    lp = kmalloc(sizeof(*lp), GFP_KERNEL);
+    if (!lp) return NULL;
+    memset(lp, 0, sizeof(*lp));
+    link = &lp->link; dev = &lp->dev;
+    link->priv = dev->priv = link->irq.Instance = lp;
+    
+    link->release.function = &tc589_release;
+    link->release.data = (u_long)link;
+    link->io.NumPorts1 = 16;
+    link->io.Attributes1 = IO_DATA_PATH_WIDTH_16;
+    link->irq.Attributes = IRQ_TYPE_EXCLUSIVE | IRQ_HANDLE_PRESENT;
+    link->irq.IRQInfo1 = IRQ_INFO2_VALID|IRQ_LEVEL_ID;
+    if (irq_list[0] == -1)
+	link->irq.IRQInfo2 = irq_mask;
+    else
+	for (i = 0; i < 4; i++)
+	    link->irq.IRQInfo2 |= 1 << irq_list[i];
+    link->irq.Handler = &el3_interrupt;
+    link->conf.Attributes = CONF_ENABLE_IRQ;
+    link->conf.Vcc = 50;
+    link->conf.IntType = INT_MEMORY_AND_IO;
+    link->conf.ConfigIndex = 1;
+    link->conf.Present = PRESENT_OPTION;
+    
+    /* The EL3-specific entries in the device structure. */
+    dev->hard_start_xmit = &el3_start_xmit;
+    dev->set_config = &el3_config;
+    dev->get_stats = &el3_get_stats;
+    dev->set_multicast_list = &set_multicast_list;
+    ether_setup(dev);
+    dev->name = lp->node.dev_name;
+    dev->open = &el3_open;
+    dev->stop = &el3_close;
+#ifdef HAVE_NETIF_QUEUE
+    dev->tx_timeout = el3_tx_timeout;
+    dev->watchdog_timeo = TX_TIMEOUT;
+#endif
+    
+    /* Register with Card Services */
+    link->next = dev_list;
+    dev_list = link;
+    client_reg.dev_info = &dev_info;
+    client_reg.Attributes = INFO_IO_CLIENT | INFO_CARD_SHARE;
+    client_reg.EventMask =
+	CS_EVENT_CARD_INSERTION | CS_EVENT_CARD_REMOVAL |
+	CS_EVENT_RESET_PHYSICAL | CS_EVENT_CARD_RESET |
+	CS_EVENT_PM_SUSPEND | CS_EVENT_PM_RESUME;
+    client_reg.event_handler = &tc589_event;
+    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);
+	tc589_detach(link);
+	return NULL;
+    }
+    
+    return link;
+} /* tc589_attach */
+
+/*======================================================================
+
+    This deletes a driver "instance".  The device is de-registered
+    with Card Services.  If it has been released, all local data
+    structures are freed.  Otherwise, the structures will be freed
+    when the device is released.
+
+======================================================================*/
+
+static void tc589_detach(dev_link_t *link)
+{
+    struct el3_private *lp = link->priv;
+    dev_link_t **linkp;
+    
+    DEBUG(0, "3c589_detach(0x%p)\n", link);
+    
+    /* Locate device structure */
+    for (linkp = &dev_list; *linkp; linkp = &(*linkp)->next)
+	if (*linkp == link) break;
+    if (*linkp == NULL)
+	return;
+
+    del_timer(&link->release);
+    if (link->state & DEV_CONFIG) {
+	tc589_release((u_long)link);
+	if (link->state & DEV_STALE_CONFIG) {
+	    link->state |= DEV_STALE_LINK;
+	    return;
+	}
+    }
+    
+    if (link->handle)
+	CardServices(DeregisterClient, link->handle);
+    
+    /* Unlink device structure, free bits */
+    *linkp = link->next;
+    if (link->dev)
+	unregister_netdev(&lp->dev);
+    kfree(lp);
+    
+} /* tc589_detach */
+
+/*======================================================================
+
+    tc589_config() is scheduled to run after a CARD_INSERTION event
+    is received, to configure the PCMCIA socket, and to make the
+    ethernet device available to the system.
+    
+======================================================================*/
+
+#define CS_CHECK(fn, args...) \
+while ((last_ret=CardServices(last_fn=(fn), args))!=0) goto cs_failed
+
+static void tc589_config(dev_link_t *link)
+{
+    client_handle_t handle = link->handle;
+    struct el3_private *lp = link->priv;
+    struct net_device *dev = &lp->dev;
+    tuple_t tuple;
+    cisparse_t parse;
+    u_short buf[32], *phys_addr;
+    int last_fn, last_ret, i, j, multi = 0;
+    ioaddr_t ioaddr;
+    char *ram_split[] = {"5:3", "3:1", "1:1", "3:5"};
+    
+    DEBUG(0, "3c589_config(0x%p)\n", link);
+
+    phys_addr = (u_short *)dev->dev_addr;
+    tuple.Attributes = 0;
+    tuple.DesiredTuple = CISTPL_CONFIG;
+    CS_CHECK(GetFirstTuple, handle, &tuple);
+    tuple.TupleData = (cisdata_t *)buf;
+    tuple.TupleDataMax = sizeof(buf);
+    tuple.TupleOffset = 0;
+    CS_CHECK(GetTupleData, handle, &tuple);
+    CS_CHECK(ParseTuple, handle, &tuple, &parse);
+    link->conf.ConfigBase = parse.config.base;
+    link->conf.Present = parse.config.rmask[0];
+    
+    /* Is this a 3c562? */
+    tuple.DesiredTuple = CISTPL_MANFID;
+    tuple.Attributes = TUPLE_RETURN_COMMON;
+    if ((CardServices(GetFirstTuple, handle, &tuple) == CS_SUCCESS) &&
+	(CardServices(GetTupleData, handle, &tuple) == CS_SUCCESS)) {
+	if (le16_to_cpu(buf[0]) != MANFID_3COM)
+	    printk(KERN_INFO "3c589_cs: hmmm, is this really a "
+		   "3Com card??\n");
+	multi = (le16_to_cpu(buf[1]) == PRODID_3COM_3C562);
+    }
+    
+    /* Configure card */
+    link->state |= DEV_CONFIG;
+
+    /* For the 3c562, the base address must be xx00-xx7f */
+    link->io.IOAddrLines = 16;
+    for (i = j = 0; j < 0x400; j += 0x10) {
+	if (multi && (j & 0x80)) continue;
+	link->io.BasePort1 = j ^ 0x300;
+	i = CardServices(RequestIO, link->handle, &link->io);
+	if (i == CS_SUCCESS) break;
+    }
+    if (i != CS_SUCCESS) {
+	cs_error(link->handle, RequestIO, i);
+	goto failed;
+    }
+    CS_CHECK(RequestIRQ, link->handle, &link->irq);
+    CS_CHECK(RequestConfiguration, link->handle, &link->conf);
+	
+    dev->irq = link->irq.AssignedIRQ;
+    dev->base_addr = link->io.BasePort1;
+    if (register_netdev(dev) != 0) {
+	printk(KERN_NOTICE "3c589_cs: register_netdev() failed\n");
+	goto failed;
+    }
+    
+    ioaddr = dev->base_addr;
+    EL3WINDOW(0);
+
+    /* The 3c589 has an extra EEPROM for configuration info, including
+       the hardware address.  The 3c562 puts the address in the CIS. */
+    tuple.DesiredTuple = 0x88;
+    if (CardServices(GetFirstTuple, handle, &tuple) == CS_SUCCESS) {
+	CardServices(GetTupleData, handle, &tuple);
+	for (i = 0; i < 3; i++)
+	    phys_addr[i] = htons(buf[i]);
+    } else {
+	for (i = 0; i < 3; i++)
+	    phys_addr[i] = htons(read_eeprom(ioaddr, i));
+	if (phys_addr[0] == 0x6060) {
+	    printk(KERN_NOTICE "3c589_cs: IO port conflict at 0x%03lx"
+		   "-0x%03lx\n", dev->base_addr, dev->base_addr+15);
+	    goto failed;
+	}
+    }
+    
+    link->dev = &lp->node;
+    link->state &= ~DEV_CONFIG_PENDING;
+    
+    /* The address and resource configuration register aren't loaded from
+       the EEPROM and *must* be set to 0 and IRQ3 for the PCMCIA version. */
+    outw(0x3f00, ioaddr + 8);
+
+    /* The if_port symbol can be set when the module is loaded */
+    if ((if_port >= 0) && (if_port <= 3))
+	dev->if_port = if_port;
+    else
+	printk(KERN_NOTICE "3c589_cs: invalid if_port requested\n");
+    
+    printk(KERN_INFO "%s: 3Com 3c%s, io %#3lx, irq %d, hw_addr ",
+	   dev->name, (multi ? "562" : "589"), dev->base_addr,
+	   dev->irq);
+    for (i = 0; i < 6; i++)
+	printk("%02X%s", dev->dev_addr[i], ((i<5) ? ":" : "\n"));
+    i = inl(ioaddr);
+    printk(KERN_INFO "  %dK FIFO split %s Rx:Tx, %s xcvr\n",
+	   (i & 7) ? 32 : 8, ram_split[(i >> 16) & 3],
+	   if_names[dev->if_port]);
+    return;
+
+cs_failed:
+    cs_error(link->handle, last_fn, last_ret);
+failed:
+    tc589_release((u_long)link);
+    return;
+    
+} /* tc589_config */
+
+/*======================================================================
+
+    After a card is removed, tc589_release() will unregister the net
+    device, and release the PCMCIA configuration.  If the device is
+    still open, this will be postponed until it is closed.
+    
+======================================================================*/
+
+static void tc589_release(u_long arg)
+{
+    dev_link_t *link = (dev_link_t *)arg;
+
+    DEBUG(0, "3c589_release(0x%p)\n", link);
+    
+    if (link->open) {
+	DEBUG(1, "3c589_cs: release postponed, '%s' still open\n",
+	      link->dev->dev_name);
+	link->state |= DEV_STALE_CONFIG;
+	return;
+    }
+    
+    CardServices(ReleaseConfiguration, link->handle);
+    CardServices(ReleaseIO, link->handle, &link->io);
+    CardServices(ReleaseIRQ, link->handle, &link->irq);
+    
+    link->state &= ~DEV_CONFIG;
+    
+} /* tc589_release */
+
+/*======================================================================
+
+    The card status event handler.  Mostly, this schedules other
+    stuff to run after an event is received.  A CARD_REMOVAL event
+    also sets some flags to discourage the net drivers from trying
+    to talk to the card any more.
+    
+======================================================================*/
+
+static int tc589_event(event_t event, int priority,
+		       event_callback_args_t *args)
+{
+    dev_link_t *link = args->client_data;
+    struct el3_private *lp = link->priv;
+    struct net_device *dev = &lp->dev;
+    
+    DEBUG(1, "3c589_event(0x%06x)\n", event);
+    
+    switch (event) {
+    case CS_EVENT_CARD_REMOVAL:
+	link->state &= ~DEV_PRESENT;
+	if (link->state & DEV_CONFIG) {
+	    netif_device_detach(dev);
+	    mod_timer(&link->release, jiffies + HZ/20);
+	}
+	break;
+    case CS_EVENT_CARD_INSERTION:
+	link->state |= DEV_PRESENT | DEV_CONFIG_PENDING;
+	tc589_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 (link->open)
+		netif_device_detach(dev);
+	    CardServices(ReleaseConfiguration, link->handle);
+	}
+	break;
+    case CS_EVENT_PM_RESUME:
+	link->state &= ~DEV_SUSPEND;
+	/* Fall through... */
+    case CS_EVENT_CARD_RESET:
+	if (link->state & DEV_CONFIG) {
+	    CardServices(RequestConfiguration, link->handle, &link->conf);
+	    if (link->open) {
+		tc589_reset(dev);
+		netif_device_attach(dev);
+	    }
+	}
+	break;
+    }
+    return 0;
+} /* tc589_event */
+
+/*====================================================================*/
+
+/*
+  Use this for commands that may take time to finish
+*/
+static void wait_for_completion(struct net_device *dev, int cmd)
+{
+    int i = 100;
+    outw(cmd, dev->base_addr + EL3_CMD);
+    while (--i > 0)
+	if (!(inw(dev->base_addr + EL3_STATUS) & 0x1000)) break;
+    if (i == 0)
+	printk(KERN_NOTICE "%s: command 0x%04x did not complete!\n",
+	       dev->name, cmd);
+}
+
+/*
+  Read a word from the EEPROM using the regular EEPROM access register.
+  Assume that we are in register window zero.
+*/
+static u_short read_eeprom(ioaddr_t ioaddr, int index)
+{
+    int i;
+    outw(EEPROM_READ + index, ioaddr + 10);
+    /* Reading the eeprom takes 162 us */
+    for (i = 1620; i >= 0; i--)
+	if ((inw(ioaddr + 10) & EEPROM_BUSY) == 0)
+	    break;
+    return inw(ioaddr + 12);
+}
+
+/*
+  Set transceiver type, perhaps to something other than what the user
+  specified in dev->if_port.
+*/
+static void tc589_set_xcvr(struct net_device *dev, int if_port)
+{
+    struct el3_private *lp = (struct el3_private *)dev->priv;
+    ioaddr_t ioaddr = dev->base_addr;
+    
+    EL3WINDOW(0);
+    switch (if_port) {
+    case 0: case 1: outw(0, ioaddr + 6); break;
+    case 2: outw(3<<14, ioaddr + 6); break;
+    case 3: outw(1<<14, ioaddr + 6); break;
+    }
+    /* On PCMCIA, this just turns on the LED */
+    outw((if_port == 2) ? StartCoax : StopCoax, ioaddr + EL3_CMD);
+    /* 10baseT interface, enable link beat and jabber check. */
+    EL3WINDOW(4);
+    outw(MEDIA_LED | ((if_port < 2) ? MEDIA_TP : 0), ioaddr + WN4_MEDIA);
+    EL3WINDOW(1);
+    if (if_port == 2)
+	lp->media_status = ((dev->if_port == 0) ? 0x8000 : 0x4000);
+    else
+	lp->media_status = ((dev->if_port == 0) ? 0x4010 : 0x8800);
+}
+
+static void dump_status(struct net_device *dev)
+{
+    ioaddr_t ioaddr = dev->base_addr;
+    EL3WINDOW(1);
+    printk(KERN_INFO "  irq status %04x, rx status %04x, tx status "
+	   "%02x  tx free %04x\n", inw(ioaddr+EL3_STATUS),
+	   inw(ioaddr+RX_STATUS), inb(ioaddr+TX_STATUS),
+	   inw(ioaddr+TX_FREE));
+    EL3WINDOW(4);
+    printk(KERN_INFO "  diagnostics: fifo %04x net %04x ethernet %04x"
+	   " media %04x\n", inw(ioaddr+0x04), inw(ioaddr+0x06),
+	   inw(ioaddr+0x08), inw(ioaddr+0x0a));
+    EL3WINDOW(1);
+}
+
+/* Reset and restore all of the 3c589 registers. */
+static void tc589_reset(struct net_device *dev)
+{
+    ioaddr_t ioaddr = dev->base_addr;
+    int i;
+    
+    EL3WINDOW(0);
+    outw(0x0001, ioaddr + 4);			/* Activate board. */ 
+    outw(0x3f00, ioaddr + 8);			/* Set the IRQ line. */
+    
+    /* Set the station address in window 2. */
+    EL3WINDOW(2);
+    for (i = 0; i < 6; i++)
+	outb(dev->dev_addr[i], ioaddr + i);
+
+    tc589_set_xcvr(dev, dev->if_port);
+    
+    /* Switch to the stats window, and clear all stats by reading. */
+    outw(StatsDisable, ioaddr + EL3_CMD);
+    EL3WINDOW(6);
+    for (i = 0; i < 9; i++)
+	inb(ioaddr+i);
+    inw(ioaddr + 10);
+    inw(ioaddr + 12);
+    
+    /* Switch to register set 1 for normal use. */
+    EL3WINDOW(1);
+
+    /* Accept b-cast and phys addr only. */
+    outw(SetRxFilter | RxStation | RxBroadcast, ioaddr + EL3_CMD);
+    outw(StatsEnable, ioaddr + EL3_CMD); /* Turn on statistics. */
+    outw(RxEnable, ioaddr + EL3_CMD); /* Enable the receiver. */
+    outw(TxEnable, ioaddr + EL3_CMD); /* Enable transmitter. */
+    /* Allow status bits to be seen. */
+    outw(SetStatusEnb | 0xff, ioaddr + EL3_CMD);
+    /* Ack all pending events, and set active indicator mask. */
+    outw(AckIntr | IntLatch | TxAvailable | RxEarly | IntReq,
+	 ioaddr + EL3_CMD);
+    outw(SetIntrEnb | IntLatch | TxAvailable | RxComplete | StatsFull
+	 | AdapterFailure, ioaddr + EL3_CMD);
+}
+
+static int el3_config(struct net_device *dev, struct ifmap *map)
+{
+    if ((map->port != (u_char)(-1)) && (map->port != dev->if_port)) {
+	if (map->port <= 3) {
+	    dev->if_port = map->port;
+	    printk(KERN_INFO "%s: switched to %s port\n",
+		   dev->name, if_names[dev->if_port]);
+	    tc589_set_xcvr(dev, dev->if_port);
+	} else
+	    return -EINVAL;
+    }
+    return 0;
+}
+
+static int el3_open(struct net_device *dev)
+{
+    struct el3_private *lp = (struct el3_private *)dev->priv;
+    dev_link_t *link = &lp->link;
+    
+    if (!DEV_OK(link))
+	return -ENODEV;
+
+    link->open++;
+    MOD_INC_USE_COUNT;
+    netif_start_queue(dev);
+    netif_mark_up(dev);
+    
+    tc589_reset(dev);
+    lp->media.function = &media_check;
+    lp->media.data = (u_long)lp;
+    lp->media.expires = jiffies + HZ;
+    add_timer(&lp->media);
+
+    DEBUG(1, "%s: opened, status %4.4x.\n",
+	  dev->name, inw(dev->base_addr + EL3_STATUS));
+    
+    return 0;
+}
+
+static void el3_tx_timeout(struct net_device *dev)
+{
+    struct el3_private *lp = (struct el3_private *)dev->priv;
+    ioaddr_t ioaddr = dev->base_addr;
+    
+    printk(KERN_NOTICE "%s: Transmit timed out!\n", dev->name);
+    dump_status(dev);
+    lp->stats.tx_errors++;
+    dev->trans_start = jiffies;
+    /* Issue TX_RESET and TX_START commands. */
+    wait_for_completion(dev, TxReset);
+    outw(TxEnable, ioaddr + EL3_CMD);
+    netif_start_queue(dev);
+}
+
+static void pop_tx_status(struct net_device *dev)
+{
+    struct el3_private *lp = (struct el3_private *)dev->priv;
+    ioaddr_t ioaddr = dev->base_addr;
+    int i;
+    
+    /* Clear the Tx status stack. */
+    for (i = 32; i > 0; i--) {
+	u_char tx_status = inb(ioaddr + TX_STATUS);
+	if (!(tx_status & 0x84)) break;
+	/* reset transmitter on jabber error or underrun */
+	if (tx_status & 0x30)
+	    wait_for_completion(dev, TxReset);
+	if (tx_status & 0x38) {
+	    DEBUG(1, "%s: transmit error: status 0x%02x\n",
+		  dev->name, tx_status);
+	    outw(TxEnable, ioaddr + EL3_CMD);
+	    lp->stats.tx_aborted_errors++;
+	}
+	outb(0x00, ioaddr + TX_STATUS); /* Pop the status stack. */
+    }
+}
+
+static int el3_start_xmit(struct sk_buff *skb, struct net_device *dev)
+{
+    ioaddr_t ioaddr = dev->base_addr;
+
+    tx_timeout_check(dev, el3_tx_timeout);
+    skb_tx_check(dev, skb);
+
+    DEBUG(3, "%s: el3_start_xmit(length = %ld) called, "
+	  "status %4.4x.\n", dev->name, (long)skb->len,
+	  inw(ioaddr + EL3_STATUS));
+
+    add_tx_bytes(&((struct el3_private *)dev->priv)->stats, skb->len);
+
+    /* Put out the doubleword header... */
+    outw(skb->len, ioaddr + TX_FIFO);
+    outw(0x00, ioaddr + TX_FIFO);
+    /* ... and the packet rounded to a doubleword. */
+    outsl_ns(ioaddr + TX_FIFO, skb->data, (skb->len + 3) >> 2);
+
+    dev->trans_start = jiffies;
+    if (inw(ioaddr + TX_FREE) > 1536) {
+	netif_start_queue(dev);
+    } else
+	/* Interrupt us when the FIFO has room for max-sized packet. */
+	outw(SetTxThreshold + 1536, ioaddr + EL3_CMD);
+
+    DEV_KFREE_SKB(skb);
+    pop_tx_status(dev);
+    
+    return 0;
+}
+
+/* The EL3 interrupt handler. */
+static void el3_interrupt(int irq, void *dev_id, struct pt_regs *regs)
+{
+    struct el3_private *lp = dev_id;
+    struct net_device *dev = &lp->dev;
+    ioaddr_t ioaddr, status;
+    int i = 0;
+    
+    if (!netif_device_present(dev))
+	return;
+    ioaddr = dev->base_addr;
+
+    DEBUG(3, "%s: interrupt, status %4.4x.\n",
+	  dev->name, inw(ioaddr + EL3_STATUS));
+    
+    while ((status = inw(ioaddr + EL3_STATUS)) &
+	(IntLatch | RxComplete | StatsFull)) {
+	if (!netif_device_present(dev) ||
+	    ((status & 0xe000) != 0x2000)) {
+	    DEBUG(1, "%s: interrupt from dead card\n", dev->name);
+	    break;
+	}
+	
+	if (status & RxComplete)
+	    el3_rx(dev);
+	
+	if (status & TxAvailable) {
+	    DEBUG(3, "    TX room bit was handled.\n");
+	    /* There's room in the FIFO for a full-sized packet. */
+	    outw(AckIntr | TxAvailable, ioaddr + EL3_CMD);
+	    netif_wake_queue(dev);
+	}
+	
+	if (status & TxComplete)
+	    pop_tx_status(dev);
+
+	if (status & (AdapterFailure | RxEarly | StatsFull)) {
+	    /* Handle all uncommon interrupts. */
+	    if (status & StatsFull)		/* Empty statistics. */
+		update_stats(dev);
+	    if (status & RxEarly) {		/* Rx early is unused. */
+		el3_rx(dev);
+		outw(AckIntr | RxEarly, ioaddr + EL3_CMD);
+	    }
+	    if (status & AdapterFailure) {
+		u16 fifo_diag;
+		EL3WINDOW(4);
+		fifo_diag = inw(ioaddr + 4);
+		EL3WINDOW(1);
+		printk(KERN_NOTICE "%s: adapter failure, FIFO diagnostic"
+		       " register %04x.\n", dev->name, fifo_diag);
+		if (fifo_diag & 0x0400) {
+		    /* Tx overrun */
+		    wait_for_completion(dev, TxReset);
+		    outw(TxEnable, ioaddr + EL3_CMD);
+		}
+		if (fifo_diag & 0x2000) {
+		    /* Rx underrun */
+		    wait_for_completion(dev, RxReset);
+		    set_multicast_list(dev);
+		    outw(RxEnable, ioaddr + EL3_CMD);
+		}
+		outw(AckIntr | AdapterFailure, ioaddr + EL3_CMD);
+	    }
+	}
+	
+	if (++i > 10) {
+	    printk(KERN_NOTICE "%s: infinite loop in interrupt, "
+		   "status %4.4x.\n", dev->name, status);
+	    /* Clear all interrupts */
+	    outw(AckIntr | 0xFF, ioaddr + EL3_CMD);
+	    break;
+	}
+	/* Acknowledge the IRQ. */
+	outw(AckIntr | IntReq | IntLatch, ioaddr + EL3_CMD);
+    }
+
+    lp->last_irq = jiffies;
+    DEBUG(3, "%s: exiting interrupt, status %4.4x.\n",
+	  dev->name, inw(ioaddr + EL3_STATUS));
+    return;
+}
+
+static void media_check(u_long arg)
+{
+    struct el3_private *lp = (struct el3_private *)(arg);
+    struct net_device *dev = &lp->dev;
+    ioaddr_t ioaddr = dev->base_addr;
+    u_short media, errs;
+    u_long flags;
+
+    if (!netif_device_present(dev)) goto reschedule;
+
+    EL3WINDOW(1);
+    /* Check for pending interrupt with expired latency timer: with
+       this, we can limp along even if the interrupt is blocked */
+    if ((inw(ioaddr + EL3_STATUS) & IntLatch) &&
+	(inb(ioaddr + EL3_TIMER) == 0xff)) {
+	if (!lp->fast_poll)
+	    printk(KERN_INFO "%s: interrupt(s) dropped!\n", dev->name);
+	el3_interrupt(dev->irq, lp, NULL);
+	lp->fast_poll = HZ;
+    }
+    if (lp->fast_poll) {
+	lp->fast_poll--;
+	lp->media.expires = jiffies + 1;
+	add_timer(&lp->media);
+	return;
+    }
+    
+    save_flags(flags);
+    cli();
+    EL3WINDOW(4);
+    media = inw(ioaddr+WN4_MEDIA) & 0xc810;
+
+    /* Ignore collisions unless we've had no irq's recently */
+    if (jiffies - lp->last_irq < HZ) {
+	media &= ~0x0010;
+    } else {
+	/* Try harder to detect carrier errors */
+	EL3WINDOW(6);
+	outw(StatsDisable, ioaddr + EL3_CMD);
+	errs = inb(ioaddr + 0);
+	outw(StatsEnable, ioaddr + EL3_CMD);
+	lp->stats.tx_carrier_errors += errs;
+	if (errs || (lp->media_status & 0x0010)) media |= 0x0010;
+    }
+
+    if (media != lp->media_status) {
+	if ((media & lp->media_status & 0x8000) &&
+	    ((lp->media_status ^ media) & 0x0800))
+	    printk(KERN_INFO "%s: %s link beat\n", dev->name,
+		   (lp->media_status & 0x0800 ? "lost" : "found"));
+	else if ((media & lp->media_status & 0x4000) &&
+		 ((lp->media_status ^ media) & 0x0010))
+	    printk(KERN_INFO "%s: coax cable %s\n", dev->name,
+		   (lp->media_status & 0x0010 ? "ok" : "problem"));
+	if (dev->if_port == 0) {
+	    if (media & 0x8000) {
+		if (media & 0x0800)
+		    printk(KERN_INFO "%s: flipped to 10baseT\n",
+			   dev->name);
+		else
+		    tc589_set_xcvr(dev, 2);
+	    } else if (media & 0x4000) {
+		if (media & 0x0010)
+		    tc589_set_xcvr(dev, 1);
+		else
+		    printk(KERN_INFO "%s: flipped to 10base2\n",
+			   dev->name);
+	    }
+	}
+	lp->media_status = media;
+    }
+    
+    EL3WINDOW(1);
+    restore_flags(flags);
+
+reschedule:
+    lp->media.expires = jiffies + HZ;
+    add_timer(&lp->media);
+}
+
+static struct net_device_stats *el3_get_stats(struct net_device *dev)
+{
+    struct el3_private *lp = (struct el3_private *)dev->priv;
+    unsigned long flags;
+    dev_link_t *link = &lp->link;
+
+    if (DEV_OK(link)) {
+	save_flags(flags);
+	cli();
+	update_stats(dev);
+	restore_flags(flags);
+    }
+    return &lp->stats;
+}
+
+/*
+  Update statistics.  We change to register window 6, so this should be run
+  single-threaded if the device is active. This is expected to be a rare
+  operation, and it's simpler for the rest of the driver to assume that
+  window 1 is always valid rather than use a special window-state variable.
+*/
+static void update_stats(struct net_device *dev)
+{
+    struct el3_private *lp = (struct el3_private *)dev->priv;
+    ioaddr_t ioaddr = dev->base_addr;
+
+    DEBUG(2, "%s: updating the statistics.\n", dev->name);
+    /* Turn off statistics updates while reading. */
+    outw(StatsDisable, ioaddr + EL3_CMD);
+    /* Switch to the stats window, and read everything. */
+    EL3WINDOW(6);
+    lp->stats.tx_carrier_errors 	+= inb(ioaddr + 0);
+    lp->stats.tx_heartbeat_errors	+= inb(ioaddr + 1);
+    /* Multiple collisions. */	   	inb(ioaddr + 2);
+    lp->stats.collisions		+= inb(ioaddr + 3);
+    lp->stats.tx_window_errors		+= inb(ioaddr + 4);
+    lp->stats.rx_fifo_errors		+= inb(ioaddr + 5);
+    lp->stats.tx_packets		+= inb(ioaddr + 6);
+    /* Rx packets   */			inb(ioaddr + 7);
+    /* Tx deferrals */			inb(ioaddr + 8);
+    /* Rx octets */			inw(ioaddr + 10);
+    /* Tx octets */			inw(ioaddr + 12);
+    
+    /* Back to window 1, and turn statistics back on. */
+    EL3WINDOW(1);
+    outw(StatsEnable, ioaddr + EL3_CMD);
+}
+
+static int el3_rx(struct net_device *dev)
+{
+    struct el3_private *lp = (struct el3_private *)dev->priv;
+    ioaddr_t ioaddr = dev->base_addr;
+    int worklimit = 32;
+    short rx_status;
+    
+    DEBUG(3, "%s: in rx_packet(), status %4.4x, rx_status %4.4x.\n",
+	  dev->name, inw(ioaddr+EL3_STATUS), inw(ioaddr+RX_STATUS));
+    while (!((rx_status = inw(ioaddr + RX_STATUS)) & 0x8000) &&
+	   (--worklimit >= 0)) {
+	if (rx_status & 0x4000) { /* Error, update stats. */
+	    short error = rx_status & 0x3800;
+	    lp->stats.rx_errors++;
+	    switch (error) {
+	    case 0x0000:	lp->stats.rx_over_errors++; break;
+	    case 0x0800:	lp->stats.rx_length_errors++; break;
+	    case 0x1000:	lp->stats.rx_frame_errors++; break;
+	    case 0x1800:	lp->stats.rx_length_errors++; break;
+	    case 0x2000:	lp->stats.rx_frame_errors++; break;
+	    case 0x2800:	lp->stats.rx_crc_errors++; break;
+	    }
+	} else {
+	    short pkt_len = rx_status & 0x7ff;
+	    struct sk_buff *skb;
+	    
+	    skb = dev_alloc_skb(pkt_len+5);
+	    
+	    DEBUG(3, "    Receiving packet size %d status %4.4x.\n",
+		  pkt_len, rx_status);
+	    if (skb != NULL) {
+		skb->dev = dev;
+		
+		skb_reserve(skb, 2);
+		insl_ns(ioaddr+RX_FIFO, skb_put(skb, pkt_len),
+			(pkt_len+3)>>2);
+		skb->protocol = eth_type_trans(skb, dev);
+		
+		netif_rx(skb);
+		lp->stats.rx_packets++;
+		add_rx_bytes(&lp->stats, skb->len);
+	    } else {
+		DEBUG(1, "%s: couldn't allocate a sk_buff of"
+		      " size %d.\n", dev->name, pkt_len);
+		lp->stats.rx_dropped++;
+	    }
+	}
+	/* Pop the top of the Rx FIFO */
+	wait_for_completion(dev, RxDiscard);
+    }
+    if (worklimit == 0)
+	printk(KERN_NOTICE "%s: too much work in el3_rx!\n", dev->name);
+    return 0;
+}
+
+/* Set or clear the multicast filter for this adapter.
+   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.
+ */
+static void set_multicast_list(struct net_device *dev)
+{
+    struct el3_private *lp = dev->priv;
+    dev_link_t *link = &lp->link;
+    ioaddr_t ioaddr = dev->base_addr;
+
+    if (!(DEV_OK(link))) return;
+#ifdef PCMCIA_DEBUG
+    if (pc_debug > 2) {
+	static int old = 0;
+	if (old != dev->mc_count) {
+	    old = dev->mc_count;
+	    DEBUG(0, "%s: setting Rx mode to %d addresses.\n",
+		  dev->name, old);
+	}
+    }
+#endif
+    if (dev->flags & IFF_PROMISC)
+	outw(SetRxFilter | RxStation | RxMulticast | RxBroadcast | RxProm,
+	     ioaddr + EL3_CMD);
+    else if (dev->mc_count || (dev->flags & IFF_ALLMULTI))
+	outw(SetRxFilter|RxStation|RxMulticast|RxBroadcast, ioaddr + EL3_CMD);
+    else
+	outw(SetRxFilter | RxStation | RxBroadcast, ioaddr + EL3_CMD);
+}
+
+static int el3_close(struct net_device *dev)
+{
+    struct el3_private *lp = dev->priv;
+    dev_link_t *link = &lp->link;
+    ioaddr_t ioaddr = dev->base_addr;
+    
+    DEBUG(1, "%s: shutting down ethercard.\n", dev->name);
+
+    if (DEV_OK(link)) {
+	/* Turn off statistics ASAP.  We update lp->stats below. */
+	outw(StatsDisable, ioaddr + EL3_CMD);
+	
+	/* Disable the receiver and transmitter. */
+	outw(RxDisable, ioaddr + EL3_CMD);
+	outw(TxDisable, ioaddr + EL3_CMD);
+	
+	if (dev->if_port == 2)
+	    /* Turn off thinnet power.  Green! */
+	    outw(StopCoax, ioaddr + EL3_CMD);
+	else if (dev->if_port == 1) {
+	    /* Disable link beat and jabber */
+	    EL3WINDOW(4);
+	    outw(0, ioaddr + WN4_MEDIA);
+	}
+	
+	/* Switching back to window 0 disables the IRQ. */
+	EL3WINDOW(0);
+	/* But we explicitly zero the IRQ line select anyway. */
+	outw(0x0f00, ioaddr + WN0_IRQ);
+        
+	/* Check if the card still exists */
+	if ((inw(ioaddr+EL3_STATUS) & 0xe000) == 0x2000)
+	    update_stats(dev);
+    }
+
+    link->open--;
+    netif_stop_queue(dev);
+    netif_mark_down(dev);
+    del_timer(&lp->media);
+    if (link->state & DEV_STALE_CONFIG)
+	mod_timer(&link->release, jiffies + HZ/20);
+    
+    MOD_DEC_USE_COUNT;
+    
+    return 0;
+}
+
+/*====================================================================*/
+
+static int __init init_3c589_cs(void)
+{
+    servinfo_t serv;
+    DEBUG(0, "%s\n", version);
+    CardServices(GetCardServicesInfo, &serv);
+    if (serv.Revision != CS_RELEASE_CODE) {
+	printk(KERN_NOTICE "3c589_cs: Card Services release "
+	       "does not match!\n");
+	return -1;
+    }
+    register_pccard_driver(&dev_info, &tc589_attach, &tc589_detach);
+    return 0;
+}
+
+static void __exit exit_3c589_cs(void)
+{
+    DEBUG(0, "3c589_cs: unloading\n");
+    unregister_pccard_driver(&dev_info);
+    while (dev_list != NULL)
+	tc589_detach(dev_list);
+}
+
+module_init(init_3c589_cs);
+module_exit(exit_3c589_cs);
Index: oldkernel/linux/pcmcia-cs-3.1.15/clients/Makefile
diff -u /dev/null linux/pcmcia-cs-3.1.15/clients/Makefile:1.1
--- /dev/null	Mon Jul 31 21:15:10 2000
+++ linux/pcmcia-cs-3.1.15/clients/Makefile	Fri Jul  7 16:34:58 2000
@@ -0,0 +1,144 @@
+#
+# Copyright (C) 1998 David A. Hinds -- dhinds@pcmcia.sourceforge.org
+#
+# Makefile 1.126 2000/04/29 02:00:26
+#
+
+# Include site dependent options and kernel configuration
+include ../config.mk
+
+# For files in kernel source tree, so that we can override config flags
+XFLAGS := -O2 $(CPPFLAGS) -D__KERNEL__ -DEXPORT_SYMTAB $(MFLAG)
+
+# Don't remove "-O3" or bad things will happen!
+CFLAGS = -O3 -Wall -Wstrict-prototypes -pipe
+CPPFLAGS += $(PCDEBUG) -D__KERNEL__ -DMODULE
+
+CC += $(AFLAGS) $(KFLAGS)
+
+SRCS    = serial_cs.c memory_cs.c ftl_cs.c dummy_cs.c \
+	  sram_mtd.c iflash2_mtd.c iflash2+_mtd.c
+MODULES = serial_cs.o memory_cs.o ftl_cs.o dummy_cs.o \
+	  sram_mtd.o iflash2_mtd.o iflash2+_mtd.o
+EXTRA   =
+I_EXTRA =
+
+ifdef CONFIG_CARDBUS
+SRCS    += 3c575_cb.c tulip_cb.c memory_cb.c serial_cb.c
+MODULES += 3c575_cb.o tulip_cb.o memory_cb.o serial_cb.o
+ifdef CONFIG_SCSI
+ifdef DO_APA1480
+SRCS    += apa1480_cb.c aic7xxx.c
+MODULES += apa1480_cb.o
+endif
+endif
+ifdef DO_EPIC_CB
+SRCS    += epic100.c
+MODULES += epic_cb.o
+endif
+endif
+
+ifdef CONFIG_INET
+MODULES += pcnet_cs.o 3c589_cs.o nmclan_cs.o fmvj18x_cs.o smc91c92_cs.o \
+	   xirc2ps_cs.o 3c574_cs.o
+SRCS    += pcnet_cs.c 3c589_cs.c nmclan_cs.c fmvj18x_cs.c smc91c92_cs.c \
+	   xirc2ps_cs.c 3c574_cs.c
+SRCS    += 8390.c
+EXTRA   += 8390.o
+I_EXTRA += install-8390
+ifdef CONFIG_TR
+MODULES += ibmtr_cs.o
+SRCS    += ibmtr_cs.c
+endif
+endif
+
+ifdef DO_IDE
+SRCS    += ide_cs.c
+MODULES += ide_cs.o
+endif
+
+ifdef DO_PARPORT
+SRCS    += parport_cs.c
+MODULES += parport_cs.o
+endif
+
+vpath %.c $(LINUX)/drivers/net $(LINUX)/drivers/scsi \
+	$(LINUX)/drivers/net/tokenring
+
+SCSI=$(LINUX)/drivers/scsi
+
+ifdef CONFIG_SCSI
+SRCS    += qlogicfas.c aha152x.c fdomain.c
+SRCS    += qlogic_stub.c aha152x_stub.c fdomain_stub.c
+MODULES += qlogic_cs.o aha152x_cs.o fdomain_cs.o
+endif
+
+all:	$(MODULES) $(EXTRA)
+
+8390.o: 8390.c
+	$(CC) -MD -c $(XFLAGS) -DMODULE $<
+	@mkdir -p .depfiles ; mv $*.d .depfiles
+
+ibmtr.o: ibmtr.c
+	$(CC) -MD -c $(XFLAGS) -DPCMCIA -D__NO_VERSION__ $<
+	@mkdir -p .depfiles ; mv $*.d .depfiles
+
+ibmtr_cs.o: ibmtr_cs.c ibmtr.o
+	$(CC) -c -MD $(CFLAGS) $(CPPFLAGS) $< -o .$@
+	@mkdir -p .depfiles ; mv $*.d .depfiles
+	$(LD) -r -o $@ .$@ ibmtr.o
+	rm -f .$@ ; chmod -x $@
+
+qlogicfas.o aha152x.o fdomain.o: %.o: %.c
+	$(CC) -MD -c $(XFLAGS) -DPCMCIA -D__NO_VERSION__ $<
+	@mkdir -p .depfiles ; mv $*.d .depfiles
+
+qlogic_cs.o: qlogic_stub.o qlogicfas.o
+	$(LD) -r -o $@ $+ ; chmod -x $@
+
+aha152x_cs.o: aha152x_stub.o aha152x.o
+	$(LD) -r -o $@ $+ ; chmod -x $@
+
+fdomain_cs.o: fdomain_stub.o fdomain.o
+	$(LD) -r -o $@ $+ ; chmod -x $@
+
+3c575_cb.o tulip_cb.o: %.o: %.c
+	$(CC) -MD -c $(XFLAGS) -DMODULE -DCARDBUS $<
+	@mkdir -p .depfiles ; mv $*.d .depfiles
+
+epic_cb.o: epic100.c
+	$(CC) -c -MD $(XFLAGS) -DMODULE -DCARDBUS $< -o $@
+	@mkdir -p .depfiles ; mv epic100.d .depfiles
+
+aic7xxx.o: aic7xxx.c
+ifdef FIX_AIC7XXX
+	cd $(SCSI) ; if [ -r aic7xxx_asm.c -a ! -r aic7xxx_seq.h ] ; \
+		then $(CC) -o aic7xxx_asm aic7xxx_asm.c ; \
+		./aic7xxx_asm -o aic7xxx_seq.h aic7xxx.seq ; fi
+	patch -s $< patches/aic7xxx.old -o aic7xxx.c 2>/dev/null || \
+		( rm -f aic7xxx.c aic7xxx.c.rej aic7xxx.c.orig && \
+		patch -s $< patches/aic7xxx.fix -o aic7xxx.c )
+	$(CC) -MD -c $(CFLAGS) $(CPPFLAGS) -I$(SCSI) aic7xxx.c
+	rm aic7xxx.c
+else
+	$(CC) -MD -c $(XFLAGS) -DPCMCIA -D__NO_VERSION__ $<
+endif
+	@mkdir -p .depfiles ; mv $*.d .depfiles
+
+apa1480_cb.o: apa1480_stub.o aic7xxx.o
+	$(LD) -r -o $@ $+ ; chmod -x $@
+
+clean:
+	rm -f core core.* *.o .*.o *.s *.a *~ .depend .depfiles/*.d
+
+install-modules: $(MODULES)
+	@mkdir -p $(PREFIX)$(MODDIR)/pcmcia
+	cp $(MODULES) $(PREFIX)$(MODDIR)/pcmcia
+
+install-8390: 8390.o
+	@mkdir -p $(PREFIX)$(MODDIR)/net
+	cp 8390.o $(PREFIX)$(MODDIR)/net
+
+install: install-modules $(I_EXTRA)
+
+include ../rules.mk
Index: oldkernel/linux/pcmcia-cs-3.1.15/clients/aha152x_stub.c
diff -u /dev/null linux/pcmcia-cs-3.1.15/clients/aha152x_stub.c:1.1
--- /dev/null	Mon Jul 31 21:15:10 2000
+++ linux/pcmcia-cs-3.1.15/clients/aha152x_stub.c	Fri Jul  7 16:34:58 2000
@@ -0,0 +1,460 @@
+/*======================================================================
+
+    A driver for Adaptec AHA152X-compatible PCMCIA SCSI cards.
+
+    This driver supports the Adaptec AHA-1460, the New Media Bus
+    Toaster, and the New Media Toast & Jam.
+    
+    aha152x_cs.c 1.53 2000/05/04 01:30:00
+
+    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@pcmcia.sourceforge.org>.  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 <pcmcia/config.h>
+#include <pcmcia/k_compat.h>
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/malloc.h>
+#include <linux/string.h>
+#include <linux/timer.h>
+#include <linux/ioport.h>
+#include <scsi/scsi.h>
+#include <linux/major.h>
+#include <linux/blk.h>
+
+#include <../drivers/scsi/scsi.h>
+#include <../drivers/scsi/hosts.h>
+#include <scsi/scsi_ioctl.h>
+#include <../drivers/scsi/aha152x.h>
+
+#if (LINUX_VERSION_CODE >= VERSION(2,3,36))
+#define aha152x_reset(ptr) aha152x_host_reset(ptr)
+#elif (LINUX_VERSION_CODE >= VERSION(2,0,14))
+#define aha152x_reset(ptr) aha152x_reset(ptr, 0)
+#endif
+
+#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 =
+"aha152x_cs.c 1.53 2000/05/04 01:30:00 (David Hinds)";
+#else
+#define DEBUG(n, args...)
+#endif
+
+/*====================================================================*/
+
+/* Parameters that can be set with 'insmod' */
+
+/* Bit map of interrupts to choose from */
+static u_int irq_mask = 0xdeb8;
+static int irq_list[4] = { -1 };
+
+/* SCSI bus setup options */
+static int host_id = 7;
+static int reconnect = 1;
+static int parity = 1;
+static int synchronous = 0;
+static int reset_delay = 100;
+static int ext_trans = 0;
+
+MODULE_PARM(irq_mask, "i");
+MODULE_PARM(irq_list, "1-4i");
+MODULE_PARM(host_id, "i");
+MODULE_PARM(reconnect, "i");
+MODULE_PARM(parity, "i");
+MODULE_PARM(synchronous, "i");
+MODULE_PARM(reset_delay, "i");
+MODULE_PARM(ext_trans, "i");
+
+/*====================================================================*/
+
+typedef struct scsi_info_t {
+    dev_link_t		link;
+    struct Scsi_Host	*host;
+    int			ndev;
+    dev_node_t		node[8];
+} scsi_info_t;
+
+extern void aha152x_setup(char *str, int *ints);
+
+static void aha152x_release_cs(u_long arg);
+static int aha152x_event(event_t event, int priority,
+			 event_callback_args_t *args);
+
+static dev_link_t *aha152x_attach(void);
+static void aha152x_detach(dev_link_t *);
+
+static Scsi_Host_Template driver_template = AHA152X;
+
+static dev_link_t *dev_list = NULL;
+
+static dev_info_t dev_info = "aha152x_cs";
+
+/*====================================================================*/
+
+static void cs_error(client_handle_t handle, int func, int ret)
+{
+    error_info_t err = { func, ret };
+    CardServices(ReportError, handle, &err);
+}
+
+/*====================================================================*/
+
+static dev_link_t *aha152x_attach(void)
+{
+    scsi_info_t *info;
+    client_reg_t client_reg;
+    dev_link_t *link;
+    int i, ret;
+    
+    DEBUG(0, "aha152x_attach()\n");
+
+    /* Create new SCSI device */
+    info = kmalloc(sizeof(*info), GFP_KERNEL);
+    if (!info) return NULL;
+    memset(info, 0, sizeof(*info));
+    link = &info->link; link->priv = info;
+    link->release.function = &aha152x_release_cs;
+    link->release.data = (u_long)link;
+
+    link->io.NumPorts1 = 0x20;
+    link->io.Attributes1 = IO_DATA_PATH_WIDTH_AUTO;
+    link->io.IOAddrLines = 10;
+    link->irq.Attributes = IRQ_TYPE_EXCLUSIVE;
+    link->irq.IRQInfo1 = IRQ_INFO2_VALID|IRQ_LEVEL_ID;
+    if (irq_list[0] == -1)
+	link->irq.IRQInfo2 = irq_mask;
+    else
+	for (i = 0; i < 4; i++)
+	    link->irq.IRQInfo2 |= 1 << irq_list[i];
+    link->conf.Attributes = CONF_ENABLE_IRQ;
+    link->conf.Vcc = 50;
+    link->conf.IntType = INT_MEMORY_AND_IO;
+    link->conf.Present = PRESENT_OPTION;
+
+    /* Register with Card Services */
+    link->next = dev_list;
+    dev_list = link;
+    client_reg.dev_info = &dev_info;
+    client_reg.Attributes = INFO_IO_CLIENT | INFO_CARD_SHARE;
+    client_reg.event_handler = &aha152x_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);
+	aha152x_detach(link);
+	return NULL;
+    }
+    
+    return link;
+} /* aha152x_attach */
+
+/*====================================================================*/
+
+static void aha152x_detach(dev_link_t *link)
+{
+    dev_link_t **linkp;
+
+    DEBUG(0, "aha152x_detach(0x%p)\n", link);
+    
+    /* Locate device structure */
+    for (linkp = &dev_list; *linkp; linkp = &(*linkp)->next)
+	if (*linkp == link) break;
+    if (*linkp == NULL)
+	return;
+
+    del_timer(&link->release);
+    if (link->state & DEV_CONFIG) {
+	aha152x_release_cs((u_long)link);
+	if (link->state & DEV_STALE_CONFIG) {
+	    link->state |= DEV_STALE_LINK;
+	    return;
+	}
+    }
+
+    if (link->handle)
+	CardServices(DeregisterClient, link->handle);
+    
+    /* Unlink device structure, free bits */
+    *linkp = link->next;
+    kfree(link->priv);
+    
+} /* aha152x_detach */
+
+/*====================================================================*/
+
+#define CS_CHECK(fn, args...) \
+while ((last_ret=CardServices(last_fn=(fn), args))!=0) goto cs_failed
+
+#define CFG_CHECK(fn, args...) \
+if (CardServices(fn, args) != 0) goto next_entry
+
+static void aha152x_config_cs(dev_link_t *link)
+{
+    client_handle_t handle = link->handle;
+    scsi_info_t *info = link->priv;
+    tuple_t tuple;
+    cisparse_t parse;
+    int i, last_ret, last_fn, ints[8];
+    u_char tuple_data[64];
+    Scsi_Device *dev;
+    dev_node_t *node, **tail;
+#if (LINUX_VERSION_CODE >= VERSION(2,1,75))
+    struct Scsi_Host *host;
+#endif
+    
+    DEBUG(0, "aha152x_config(0x%p)\n", link);
+
+    tuple.DesiredTuple = CISTPL_CONFIG;
+    tuple.TupleData = tuple_data;
+    tuple.TupleDataMax = 64;
+    tuple.TupleOffset = 0;
+    CS_CHECK(GetFirstTuple, handle, &tuple);
+    CS_CHECK(GetTupleData, handle, &tuple);
+    CS_CHECK(ParseTuple, handle, &tuple, &parse);
+    link->conf.ConfigBase = parse.config.base;
+
+    /* Configure card */
+#if (LINUX_VERSION_CODE >= VERSION(2,1,23))
+    driver_template.module = &__this_module;
+#else
+    driver_template.usage_count = &GET_USE_COUNT(&__this_module);
+#endif
+    link->state |= DEV_CONFIG;
+
+    tuple.DesiredTuple = CISTPL_CFTABLE_ENTRY;
+    CS_CHECK(GetFirstTuple, handle, &tuple);
+    while (1) {
+	CFG_CHECK(GetTupleData, handle, &tuple);
+	CFG_CHECK(ParseTuple, handle, &tuple, &parse);
+	/* For New Media T&J, look for a SCSI window */
+	if (parse.cftable_entry.io.win[0].len >= 0x20)
+	    link->io.BasePort1 = parse.cftable_entry.io.win[0].base;
+	else if ((parse.cftable_entry.io.nwin > 1) &&
+		 (parse.cftable_entry.io.win[1].len >= 0x20))
+	    link->io.BasePort1 = parse.cftable_entry.io.win[1].base;
+	if ((parse.cftable_entry.io.nwin > 0) &&
+	    (link->io.BasePort1 < 0xffff)) {
+	    link->conf.ConfigIndex = parse.cftable_entry.index;
+	    i = CardServices(RequestIO, handle, &link->io);
+	    if (i == CS_SUCCESS) break;
+	}
+    next_entry:
+	CS_CHECK(GetNextTuple, handle, &tuple);
+    }
+    
+    CS_CHECK(RequestIRQ, handle, &link->irq);
+    CS_CHECK(RequestConfiguration, handle, &link->conf);
+    
+    /* A bad hack... */
+    release_region(link->io.BasePort1, link->io.NumPorts1);
+    
+    /* Set configuration options for the aha152x driver */
+    ints[0] = 7;
+    ints[1] = link->io.BasePort1;
+    ints[2] = link->irq.AssignedIRQ;
+    ints[3] = host_id;
+    ints[4] = reconnect;
+    ints[5] = parity;
+    ints[6] = synchronous;
+    ints[7] = reset_delay;
+    if (ext_trans) {
+	ints[8] = ext_trans; ints[0] = 8;
+    }
+    aha152x_setup("PCMCIA setup", ints);
+    
+    scsi_register_module(MODULE_SCSI_HA, &driver_template);
+
+    tail = &link->dev;
+    info->ndev = 0;
+#if (LINUX_VERSION_CODE < VERSION(2,1,75))
+    for (dev = scsi_devices; dev; dev = dev->next)
+	if (dev->host->hostt == &driver_template) {
+#else
+    for (host = scsi_hostlist; host; host = host->next)
+	if (host->hostt == &driver_template)
+	    for (dev = host->host_queue; dev; dev = dev->next) {
+#endif
+	    u_long arg[2], id;
+	    kernel_scsi_ioctl(dev, SCSI_IOCTL_GET_IDLUN, arg);
+	    id = (arg[0]&0x0f) + ((arg[0]>>4)&0xf0) +
+		((arg[0]>>8)&0xf00) + ((arg[0]>>12)&0xf000);
+	    node = &info->node[info->ndev];
+	    node->minor = 0;
+	    switch (dev->type) {
+	    case TYPE_TAPE:
+		node->major = SCSI_TAPE_MAJOR;
+		sprintf(node->dev_name, "st#%04lx", id);
+		break;
+	    case TYPE_DISK:
+	    case TYPE_MOD:
+		node->major = SCSI_DISK0_MAJOR;
+		sprintf(node->dev_name, "sd#%04lx", id);
+		break;
+	    case TYPE_ROM:
+	    case TYPE_WORM:
+		node->major = SCSI_CDROM_MAJOR;
+		sprintf(node->dev_name, "sr#%04lx", id);
+		break;
+	    default:
+		node->major = SCSI_GENERIC_MAJOR;
+		sprintf(node->dev_name, "sg#%04lx", id);
+		break;
+	    }
+	    *tail = node; tail = &node->next;
+	    info->ndev++;
+	    info->host = dev->host;
+	}
+    *tail = NULL;
+    if (info->ndev == 0)
+	printk(KERN_INFO "aha152x_cs: no SCSI devices found\n");
+    
+    link->state &= ~DEV_CONFIG_PENDING;
+    return;
+    
+cs_failed:
+    cs_error(link->handle, last_fn, last_ret);
+    aha152x_release_cs((u_long)link);
+    return;
+    
+} /* aha152x_config_cs */
+
+/*====================================================================*/
+
+static void aha152x_release_cs(u_long arg)
+{
+    dev_link_t *link = (dev_link_t *)arg;
+
+    DEBUG(0, "aha152x_release_cs(0x%p)\n", link);
+
+#if (LINUX_VERSION_CODE < VERSION(2,1,23))
+    if (*driver_template.usage_count != 0) {
+#else
+    if (GET_USE_COUNT(driver_template.module) != 0) {
+#endif
+	DEBUG(1, "aha152x_cs: release postponed, "
+	      "device still open\n");
+	link->state |= DEV_STALE_CONFIG;
+	return;
+    }
+
+    scsi_unregister_module(MODULE_SCSI_HA, &driver_template);
+    link->dev = NULL;
+    
+    CardServices(ReleaseConfiguration, link->handle);
+    CardServices(ReleaseIO, link->handle, &link->io);
+    CardServices(ReleaseIRQ, link->handle, &link->irq);
+    
+    link->state &= ~DEV_CONFIG;
+    if (link->state & DEV_STALE_LINK)
+	aha152x_detach(link);
+    
+} /* aha152x_release_cs */
+
+/*====================================================================*/
+
+static int aha152x_event(event_t event, int priority,
+			 event_callback_args_t *args)
+{
+    dev_link_t *link = args->client_data;
+    scsi_info_t *info = link->priv;
+    
+    DEBUG(0, "aha152x_event(0x%06x)\n", event);
+    
+    switch (event) {
+    case CS_EVENT_CARD_REMOVAL:
+	link->state &= ~DEV_PRESENT;
+	if (link->state & DEV_CONFIG)
+	    mod_timer(&link->release, jiffies + HZ/20);
+	break;
+    case CS_EVENT_CARD_INSERTION:
+	link->state |= DEV_PRESENT | DEV_CONFIG_PENDING;
+	aha152x_config_cs(link);
+	break;
+    case CS_EVENT_PM_SUSPEND:
+	link->state |= DEV_SUSPEND;
+	/* Fall through... */
+    case CS_EVENT_RESET_PHYSICAL:
+	if (link->state & DEV_CONFIG)
+	    CardServices(ReleaseConfiguration, link->handle);
+	break;
+    case CS_EVENT_PM_RESUME:
+	link->state &= ~DEV_SUSPEND;
+	/* Fall through... */
+    case CS_EVENT_CARD_RESET:
+	if (link->state & DEV_CONFIG) {
+	    Scsi_Cmnd tmp;
+	    CardServices(RequestConfiguration, link->handle, &link->conf);
+	    tmp.host = info->host;
+	    aha152x_reset(&tmp);
+	}
+	break;
+    }
+    return 0;
+} /* aha152x_event */
+
+/*====================================================================*/
+
+static int __init init_aha152x_cs(void) {
+    servinfo_t serv;
+    DEBUG(0, "%s\n", version);
+    CardServices(GetCardServicesInfo, &serv);
+    if (serv.Revision != CS_RELEASE_CODE) {
+	printk(KERN_NOTICE "aha152x_cs: Card Services release "
+	       "does not match!\n");
+	return -1;
+    }
+    register_pccard_driver(&dev_info, &aha152x_attach, &aha152x_detach);
+    return 0;
+}
+
+static void __exit exit_aha152x_cs(void) {
+    DEBUG(0, "aha152x_cs: unloading\n");
+    unregister_pccard_driver(&dev_info);
+    while (dev_list != NULL)
+	aha152x_detach(dev_list);
+}
+
+module_init(init_aha152x_cs);
+module_exit(exit_aha152x_cs);
+ 
Index: oldkernel/linux/pcmcia-cs-3.1.15/clients/apa1480_stub.c
diff -u /dev/null linux/pcmcia-cs-3.1.15/clients/apa1480_stub.c:1.1
--- /dev/null	Mon Jul 31 21:15:10 2000
+++ linux/pcmcia-cs-3.1.15/clients/apa1480_stub.c	Fri Jul  7 16:34:58 2000
@@ -0,0 +1,194 @@
+/*======================================================================
+
+    A driver for the Adaptec APA1480 CardBus SCSI Host Adapter
+
+    apa1480_cb.c 1.21 2000/04/26 22:56:36
+
+    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@pcmcia.sourceforge.org>.  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 <pcmcia/config.h>
+#include <pcmcia/k_compat.h>
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/malloc.h>
+#include <linux/string.h>
+#include <linux/timer.h>
+#include <linux/ioport.h>
+#include <scsi/scsi.h>
+#include <linux/major.h>
+#include <linux/blk.h>
+#include <linux/pci.h>
+
+#include <../drivers/scsi/scsi.h>
+#include <../drivers/scsi/hosts.h>
+#include <scsi/scsi_ioctl.h>
+#include <../drivers/scsi/aic7xxx.h>
+
+#include <pcmcia/driver_ops.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 =
+"apa1480_cb.c 1.21 2000/04/26 22:56:36 (David Hinds)";
+#else
+#define DEBUG(n, args...)
+#endif
+
+/*====================================================================*/
+
+/* Parameters that can be set with 'insmod' */
+
+static int reset = 1;
+static int ultra = 0;
+
+MODULE_PARM(reset, "i");
+MODULE_PARM(ultra, "i");
+
+/*====================================================================*/
+
+static Scsi_Host_Template driver_template = AIC7XXX;
+
+extern void aic7xxx_setup(char *, int *);
+
+static dev_node_t *apa1480_attach(dev_locator_t *loc);
+static void apa1480_detach(dev_node_t *node);
+
+struct driver_operations apa1480_ops = {
+    "apa1480_cb", apa1480_attach, NULL, NULL, apa1480_detach
+};
+
+/*====================================================================*/
+
+static dev_node_t *apa1480_attach(dev_locator_t *loc)
+{
+    u_char bus, devfn;
+    Scsi_Device *dev;
+    dev_node_t *node;
+    char s[60];
+    u_int io;
+    int n = 0;
+#if (LINUX_VERSION_CODE >= VERSION(2,1,75))
+    struct Scsi_Host *host;
+#endif
+    
+    if (loc->bus != LOC_PCI) return NULL;
+    bus = loc->b.pci.bus; devfn = loc->b.pci.devfn;
+    printk(KERN_INFO "apa1480_attach(device %02x:%02x.%d)\n",
+	   bus, PCI_SLOT(devfn), PCI_FUNC(devfn));
+
+#if (LINUX_VERSION_CODE >= VERSION(2,1,23))
+    driver_template.module = &__this_module;
+#else
+    driver_template.usage_count = &GET_USE_COUNT(__this_module);
+#endif
+
+    /* A hack to work around resource allocation confusion */
+    pcibios_read_config_dword(bus, devfn, PCI_BASE_ADDRESS_0, &io);
+    release_region(io & PCI_BASE_ADDRESS_IO_MASK, 0x100);
+
+    sprintf(s, "no_probe:1,no_reset:%d,ultra:%d",
+	    (reset==0), (ultra!=0));
+    aic7xxx_setup(s, NULL);
+    scsi_register_module(MODULE_SCSI_HA, &driver_template);
+
+    node = kmalloc(7 * sizeof(dev_node_t), GFP_KERNEL);
+#if (LINUX_VERSION_CODE < VERSION(2,1,75))
+    for (dev = scsi_devices; dev; dev = dev->next)
+	if (dev->host->hostt == &driver_template) {
+#else
+    for (host = scsi_hostlist; host; host = host->next)
+	if (host->hostt == &driver_template)
+	    for (dev = host->host_queue; dev; dev = dev->next) {
+#endif
+	    u_long arg[2], id;
+	    kernel_scsi_ioctl(dev, SCSI_IOCTL_GET_IDLUN, arg);
+	    id = (arg[0]&0x0f) + ((arg[0]>>4)&0xf0) +
+		((arg[0]>>8)&0xf00) + ((arg[0]>>12)&0xf000);
+	    node[n].minor = 0;
+	    switch (dev->type) {
+	    case TYPE_TAPE:
+		node[n].major = SCSI_TAPE_MAJOR;
+		sprintf(node[n].dev_name, "st#%04lx", id);
+		break;
+	    case TYPE_DISK:
+	    case TYPE_MOD:
+		node[n].major = SCSI_DISK0_MAJOR;
+		sprintf(node[n].dev_name, "sd#%04lx", id);
+		break;
+	    case TYPE_ROM:
+	    case TYPE_WORM:
+		node[n].major = SCSI_CDROM_MAJOR;
+		sprintf(node[n].dev_name, "sr#%04lx", id);
+		break;
+	    default:
+		node[n].major = SCSI_GENERIC_MAJOR;
+		sprintf(node[n].dev_name, "sg#%04lx", id);
+		break;
+	    }
+	    if (n) node[n-1].next = &node[n];
+	    n++;
+	}
+    if (n == 0) {
+	printk(KERN_INFO "apa1480_cs: no SCSI devices found\n");
+	scsi_unregister_module(MODULE_SCSI_HA, &driver_template);
+	kfree(node);
+	return NULL;
+    } else
+	node[n-1].next = NULL;
+    
+    MOD_INC_USE_COUNT;
+    return node;
+}
+
+static void apa1480_detach(dev_node_t *node)
+{
+    MOD_DEC_USE_COUNT;
+    scsi_unregister_module(MODULE_SCSI_HA, &driver_template);
+    kfree(node);
+}
+
+/*====================================================================*/
+
+static int __init init_apa1480_cb(void) {
+    DEBUG(0, "%s\n", version);
+    register_driver(&apa1480_ops);
+    return 0;
+}
+
+static void __exit exit_apa1480_cb(void) {
+    DEBUG(0, "apa1480_cs: unloading\n");
+    unregister_driver(&apa1480_ops);
+}
+
+module_init(init_apa1480_cb);
+module_exit(exit_apa1480_cb);
Index: oldkernel/linux/pcmcia-cs-3.1.15/clients/dummy_cs.c
diff -u /dev/null linux/pcmcia-cs-3.1.15/clients/dummy_cs.c:1.1
--- /dev/null	Mon Jul 31 21:15:10 2000
+++ linux/pcmcia-cs-3.1.15/clients/dummy_cs.c	Fri Jul  7 16:34:58 2000
@@ -0,0 +1,665 @@
+/*======================================================================
+
+    A dummy PCMCIA client driver
+
+    This is provided as an example of how to write an IO card client.
+    As written, it will function as a sort of generic point enabler,
+    configuring any card as that card's CIS specifies.
+    
+    dummy_cs.c 1.26 2000/05/16 21:31:37
+
+    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@pcmcia.sourceforge.org>.  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 <pcmcia/config.h>
+#include <pcmcia/k_compat.h>
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/sched.h>
+#include <linux/ptrace.h>
+#include <linux/malloc.h>
+#include <linux/string.h>
+#include <linux/timer.h>
+#include <linux/ioport.h>
+#include <asm/io.h>
+#include <asm/system.h>
+
+#include <pcmcia/version.h>
+#include <pcmcia/cs_types.h>
+#include <pcmcia/cs.h>
+#include <pcmcia/cistpl.h>
+#include <pcmcia/cisreg.h>
+#include <pcmcia/ds.h>
+#include <pcmcia/bus_ops.h>
+
+/*
+   All the PCMCIA modules use PCMCIA_DEBUG to control debugging.  If
+   you do not define PCMCIA_DEBUG at all, all the debug code will be
+   left out.  If you compile with PCMCIA_DEBUG=0, the debug code will
+   be present but disabled -- but it can then be enabled for specific
+   modules at load time with a 'pc_debug=#' option to insmod.
+*/
+#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 =
+"dummy_cs.c 1.26 2000/05/16 21:31:37 (David Hinds)";
+#else
+#define DEBUG(n, args...)
+#endif
+
+/*====================================================================*/
+
+/* Parameters that can be set with 'insmod' */
+
+/* Release IO ports after configuration? */
+static int free_ports = 0;
+
+/* The old way: bit map of interrupts to choose from */
+/* This means pick from 15, 14, 12, 11, 10, 9, 7, 5, 4, and 3 */
+static u_int irq_mask = 0xdeb8;
+/* Newer, simpler way of listing specific interrupts */
+static int irq_list[4] = { -1 };
+
+MODULE_PARM(free_ports, "i");
+MODULE_PARM(irq_mask, "i");
+MODULE_PARM(irq_list, "1-4i");
+
+/*====================================================================*/
+
+/*
+   The event() function is this driver's Card Services event handler.
+   It will be called by Card Services when an appropriate card status
+   event is received.  The config() and release() entry points are
+   used to configure or release a socket, in response to card
+   insertion and ejection events.  They are invoked from the dummy
+   event handler. 
+*/
+
+static void dummy_config(dev_link_t *link);
+static void dummy_release(u_long arg);
+static int dummy_event(event_t event, int priority,
+		       event_callback_args_t *args);
+
+/*
+   The attach() and detach() entry points are used to create and destroy
+   "instances" of the driver, where each instance represents everything
+   needed to manage one actual PCMCIA card.
+*/
+
+static dev_link_t *dummy_attach(void);
+static void dummy_detach(dev_link_t *);
+
+/*
+   You'll also need to prototype all the functions that will actually
+   be used to talk to your device.  See 'memory_cs' for a good example
+   of a fully self-sufficient driver; the other drivers rely more or
+   less on other parts of the kernel.
+*/
+
+/*
+   The dev_info variable is the "key" that is used to match up this
+   device driver with appropriate cards, through the card configuration
+   database.
+*/
+
+static dev_info_t dev_info = "dummy_cs";
+
+/*
+   A linked list of "instances" of the dummy device.  Each actual
+   PCMCIA card corresponds to one device instance, and is described
+   by one dev_link_t structure (defined in ds.h).
+
+   You may not want to use a linked list for this -- for example, the
+   memory card driver uses an array of dev_link_t pointers, where minor
+   device numbers are used to derive the corresponding array index.
+*/
+
+static dev_link_t *dev_list = NULL;
+
+/*
+   A dev_link_t structure has fields for most things that are needed
+   to keep track of a socket, but there will usually be some device
+   specific information that also needs to be kept track of.  The
+   'priv' pointer in a dev_link_t structure can be used to point to
+   a device-specific private data structure, like this.
+
+   To simplify the data structure handling, we actually include the
+   dev_link_t structure in the device's private data structure.
+
+   A driver needs to provide a dev_node_t structure for each device
+   on a card.  In some cases, there is only one device per card (for
+   example, ethernet cards, modems).  In other cases, there may be
+   many actual or logical devices (SCSI adapters, memory cards with
+   multiple partitions).  The dev_node_t structures need to be kept
+   in a linked list starting at the 'dev' field of a dev_link_t
+   structure.  We allocate them in the card's private data structure,
+   because they generally shouldn't be allocated dynamically.
+
+   In this case, we also provide a flag to indicate if a device is
+   "stopped" due to a power management event, or card ejection.  The
+   device IO routines can use a flag like this to throttle IO to a
+   card that is not ready to accept it.
+
+   The bus_operations pointer is used on platforms for which we need
+   to use special socket-specific versions of normal IO primitives
+   (inb, outb, readb, writeb, etc) for card IO.
+*/
+   
+typedef struct local_info_t {
+    dev_link_t		link;
+    dev_node_t		node;
+    int			stop;
+    struct bus_operations *bus;
+} local_info_t;
+
+/*====================================================================*/
+
+static void cs_error(client_handle_t handle, int func, int ret)
+{
+    error_info_t err = { func, ret };
+    CardServices(ReportError, handle, &err);
+}
+
+/*======================================================================
+
+    dummy_attach() creates an "instance" of the driver, allocating
+    local data structures for one device.  The device is registered
+    with Card Services.
+
+    The dev_link structure is initialized, but we don't actually
+    configure the card at this point -- we wait until we receive a
+    card insertion event.
+    
+======================================================================*/
+
+static dev_link_t *dummy_attach(void)
+{
+    local_info_t *local;
+    dev_link_t *link;
+    client_reg_t client_reg;
+    int ret, i;
+    
+    DEBUG(0, "dummy_attach()\n");
+
+    /* Allocate space for private device-specific data */
+    local = kmalloc(sizeof(local_info_t), GFP_KERNEL);
+    if (!local) return NULL;
+    memset(local, 0, sizeof(local_info_t));
+    link = &local->link; link->priv = local;
+    
+    /* Initialize the dev_link_t structure */
+    link->release.function = &dummy_release;
+    link->release.data = (u_long)link;
+
+    /* Interrupt setup */
+    link->irq.Attributes = IRQ_TYPE_EXCLUSIVE;
+    link->irq.IRQInfo1 = IRQ_INFO2_VALID|IRQ_LEVEL_ID;
+    if (irq_list[0] == -1)
+	link->irq.IRQInfo2 = irq_mask;
+    else
+	for (i = 0; i < 4; i++)
+	    link->irq.IRQInfo2 |= 1 << irq_list[i];
+    link->irq.Handler = NULL;
+    
+    /*
+      General socket configuration defaults can go here.  In this
+      client, we assume very little, and rely on the CIS for almost
+      everything.  In most clients, many details (i.e., number, sizes,
+      and attributes of IO windows) are fixed by the nature of the
+      device, and can be hard-wired here.
+    */
+    link->conf.Attributes = 0;
+    link->conf.Vcc = 50;
+    link->conf.IntType = INT_MEMORY_AND_IO;
+
+    /* Register with Card Services */
+    link->next = dev_list;
+    dev_list = link;
+    client_reg.dev_info = &dev_info;
+    client_reg.Attributes = INFO_IO_CLIENT | INFO_CARD_SHARE;
+    client_reg.EventMask =
+	CS_EVENT_CARD_INSERTION | CS_EVENT_CARD_REMOVAL |
+	CS_EVENT_RESET_PHYSICAL | CS_EVENT_CARD_RESET |
+	CS_EVENT_PM_SUSPEND | CS_EVENT_PM_RESUME;
+    client_reg.event_handler = &dummy_event;
+    client_reg.Version = 0x0210;
+    client_reg.event_callback_args.client_data = link;
+    ret = CardServices(RegisterClient, &link->handle, &client_reg);
+    if (ret != CS_SUCCESS) {
+	cs_error(link->handle, RegisterClient, ret);
+	dummy_detach(link);
+	return NULL;
+    }
+
+    return link;
+} /* dummy_attach */
+
+/*======================================================================
+
+    This deletes a driver "instance".  The device is de-registered
+    with Card Services.  If it has been released, all local data
+    structures are freed.  Otherwise, the structures will be freed
+    when the device is released.
+
+======================================================================*/
+
+static void dummy_detach(dev_link_t *link)
+{
+    dev_link_t **linkp;
+
+    DEBUG(0, "dummy_detach(0x%p)\n", link);
+    
+    /* Locate device structure */
+    for (linkp = &dev_list; *linkp; linkp = &(*linkp)->next)
+	if (*linkp == link) break;
+    if (*linkp == NULL)
+	return;
+
+    /*
+       If the device is currently configured and active, we won't
+       actually delete it yet.  Instead, it is marked so that when
+       the release() function is called, that will trigger a proper
+       detach().
+    */
+    if (link->state & DEV_CONFIG) {
+#ifdef PCMCIA_DEBUG
+	printk(KERN_DEBUG "dummy_cs: detach postponed, '%s' "
+	       "still locked\n", link->dev->dev_name);
+#endif
+	link->state |= DEV_STALE_LINK;
+	return;
+    }
+
+    /* Break the link with Card Services */
+    if (link->handle)
+	CardServices(DeregisterClient, link->handle);
+    
+    /* Unlink device structure, and free it */
+    *linkp = link->next;
+    /* This points to the parent local_info_t struct */
+    kfree(link->priv);
+    
+} /* dummy_detach */
+
+/*======================================================================
+
+    dummy_config() is scheduled to run after a CARD_INSERTION event
+    is received, to configure the PCMCIA socket, and to make the
+    device available to the system.
+    
+======================================================================*/
+
+#define CS_CHECK(fn, args...) \
+while ((last_ret=CardServices(last_fn=(fn),args))!=0) goto cs_failed
+
+#define CFG_CHECK(fn, args...) \
+if (CardServices(fn, args) != 0) goto next_entry
+
+static void dummy_config(dev_link_t *link)
+{
+    client_handle_t handle = link->handle;
+    local_info_t *dev = link->priv;
+    tuple_t tuple;
+    cisparse_t parse;
+    int last_fn, last_ret;
+    u_char buf[64];
+    config_info_t conf;
+    win_req_t req;
+    memreq_t map;
+    
+    DEBUG(0, "dummy_config(0x%p)\n", link);
+
+    /*
+       This reads the card's CONFIG tuple to find its configuration
+       registers.
+    */
+    tuple.DesiredTuple = CISTPL_CONFIG;
+    tuple.Attributes = 0;
+    tuple.TupleData = buf;
+    tuple.TupleDataMax = sizeof(buf);
+    tuple.TupleOffset = 0;
+    CS_CHECK(GetFirstTuple, handle, &tuple);
+    CS_CHECK(GetTupleData, handle, &tuple);
+    CS_CHECK(ParseTuple, handle, &tuple, &parse);
+    link->conf.ConfigBase = parse.config.base;
+    link->conf.Present = parse.config.rmask[0];
+    
+    /* Configure card */
+    link->state |= DEV_CONFIG;
+
+    /* Look up the current Vcc */
+    CS_CHECK(GetConfigurationInfo, handle, &conf);
+    link->conf.Vcc = conf.Vcc;
+
+    /*
+      In this loop, we scan the CIS for configuration table entries,
+      each of which describes a valid card configuration, including
+      voltage, IO window, memory window, and interrupt settings.
+
+      We make no assumptions about the card to be configured: we use
+      just the information available in the CIS.  In an ideal world,
+      this would work for any PCMCIA card, but it requires a complete
+      and accurate CIS.  In practice, a driver usually "knows" most of
+      these things without consulting the CIS, and most client drivers
+      will only use the CIS to fill in implementation-defined details.
+    */
+    tuple.DesiredTuple = CISTPL_CFTABLE_ENTRY;
+    CS_CHECK(GetFirstTuple, handle, &tuple);
+    while (1) {
+	cistpl_cftable_entry_t dflt = { 0 };
+	cistpl_cftable_entry_t *cfg = &(parse.cftable_entry);
+	CFG_CHECK(GetTupleData, handle, &tuple);
+	CFG_CHECK(ParseTuple, handle, &tuple, &parse);
+
+	if (cfg->flags & CISTPL_CFTABLE_DEFAULT) dflt = *cfg;
+	if (cfg->index == 0) goto next_entry;
+	link->conf.ConfigIndex = cfg->index;
+	
+	/* Does this card need audio output? */
+	if (cfg->flags & CISTPL_CFTABLE_AUDIO) {
+	    link->conf.Attributes |= CONF_ENABLE_SPKR;
+	    link->conf.Status = CCSR_AUDIO_ENA;
+	}
+	
+	/* Use power settings for Vcc and Vpp if present */
+	/*  Note that the CIS values need to be rescaled */
+	if (cfg->vcc.present & (1<<CISTPL_POWER_VNOM)) {
+	    if (conf.Vcc != cfg->vcc.param[CISTPL_POWER_VNOM]/10000)
+		goto next_entry;
+	} else if (dflt.vcc.present & (1<<CISTPL_POWER_VNOM)) {
+	    if (conf.Vcc != dflt.vcc.param[CISTPL_POWER_VNOM]/10000)
+		goto next_entry;
+	}
+	    
+	if (cfg->vpp1.present & (1<<CISTPL_POWER_VNOM))
+	    link->conf.Vpp1 = link->conf.Vpp2 =
+		cfg->vpp1.param[CISTPL_POWER_VNOM]/10000;
+	else if (dflt.vpp1.present & (1<<CISTPL_POWER_VNOM))
+	    link->conf.Vpp1 = link->conf.Vpp2 =
+		dflt.vpp1.param[CISTPL_POWER_VNOM]/10000;
+	
+	/* Do we need to allocate an interrupt? */
+	if (cfg->irq.IRQInfo1 || dflt.irq.IRQInfo1)
+	    link->conf.Attributes |= CONF_ENABLE_IRQ;
+	
+	/* IO window settings */
+	link->io.NumPorts1 = link->io.NumPorts2 = 0;
+	if ((cfg->io.nwin > 0) || (dflt.io.nwin > 0)) {
+	    cistpl_io_t *io = (cfg->io.nwin) ? &cfg->io : &dflt.io;
+	    link->io.Attributes1 = IO_DATA_PATH_WIDTH_AUTO;
+	    if (!(io->flags & CISTPL_IO_8BIT))
+		link->io.Attributes1 = IO_DATA_PATH_WIDTH_16;
+	    if (!(io->flags & CISTPL_IO_16BIT))
+		link->io.Attributes1 = IO_DATA_PATH_WIDTH_8;
+	    link->io.IOAddrLines = io->flags & CISTPL_IO_LINES_MASK;
+	    link->io.BasePort1 = io->win[0].base;
+	    link->io.NumPorts1 = io->win[0].len;
+	    if (io->nwin > 1) {
+		link->io.Attributes2 = link->io.Attributes1;
+		link->io.BasePort2 = io->win[1].base;
+		link->io.NumPorts2 = io->win[1].len;
+	    }
+	}
+
+	/* This reserves IO space but doesn't actually enable it */
+	CFG_CHECK(RequestIO, link->handle, &link->io);
+
+	/*
+	  Now set up a common memory window, if needed.  There is room
+	  in the dev_link_t structure for one memory window handle,
+	  but if the base addresses need to be saved, or if multiple
+	  windows are needed, the info should go in the private data
+	  structure for this device.
+
+	  Note that the memory window base is a physical address, and
+	  needs to be mapped to virtual space with ioremap() before it
+	  is used.
+	*/
+	if ((cfg->mem.nwin > 0) || (dflt.mem.nwin > 0)) {
+	    cistpl_mem_t *mem =
+		(cfg->mem.nwin) ? &cfg->mem : &dflt.mem;
+	    req.Attributes = WIN_DATA_WIDTH_16|WIN_MEMORY_TYPE_CM;
+	    req.Attributes |= WIN_ENABLE;
+	    req.Base = mem->win[0].host_addr;
+	    req.Size = mem->win[0].len;
+	    req.AccessSpeed = 0;
+	    link->win = (window_handle_t)link->handle;
+	    CFG_CHECK(RequestWindow, &link->win, &req);
+	    map.Page = 0; map.CardOffset = mem->win[0].card_addr;
+	    CFG_CHECK(MapMemPage, link->win, &map);
+	}
+	/* If we got this far, we're cool! */
+	break;
+	
+    next_entry:
+	CS_CHECK(GetNextTuple, handle, &tuple);
+    }
+    
+    /*
+       Allocate an interrupt line.  Note that this does not assign a
+       handler to the interrupt, unless the 'Handler' member of the
+       irq structure is initialized.
+    */
+    if (link->conf.Attributes & CONF_ENABLE_IRQ)
+	CS_CHECK(RequestIRQ, link->handle, &link->irq);
+	
+    /*
+       This actually configures the PCMCIA socket -- setting up
+       the I/O windows and the interrupt mapping, and putting the
+       card and host interface into "Memory and IO" mode.
+    */
+    CS_CHECK(RequestConfiguration, link->handle, &link->conf);
+
+    /*
+      We can release the IO port allocations here, if some other
+      driver for the card is going to loaded, and will expect the
+      ports to be available.
+    */
+    if (free_ports) {
+	if (link->io.BasePort1)
+	    release_region(link->io.BasePort1, link->io.NumPorts1);
+	if (link->io.BasePort2)
+	    release_region(link->io.BasePort2, link->io.NumPorts2);
+    }
+
+    /*
+      At this point, the dev_node_t structure(s) need to be
+      initialized and arranged in a linked list at link->dev.
+    */
+    sprintf(dev->node.dev_name, "skel0");
+    dev->node.major = dev->node.minor = 0;
+    link->dev = &dev->node;
+
+    /* Finally, report what we've done */
+    printk(KERN_INFO "%s: index 0x%02x: Vcc %d.%d",
+	   dev->node.dev_name, link->conf.ConfigIndex,
+	   link->conf.Vcc/10, link->conf.Vcc%10);
+    if (link->conf.Vpp1)
+	printk(", Vpp %d.%d", link->conf.Vpp1/10, link->conf.Vpp1%10);
+    if (link->conf.Attributes & CONF_ENABLE_IRQ)
+	printk(", irq %d", link->irq.AssignedIRQ);
+    if (link->io.NumPorts1)
+	printk(", io 0x%04x-0x%04x", link->io.BasePort1,
+	       link->io.BasePort1+link->io.NumPorts1-1);
+    if (link->io.NumPorts2)
+	printk(" & 0x%04x-0x%04x", link->io.BasePort2,
+	       link->io.BasePort2+link->io.NumPorts2-1);
+    if (link->win)
+	printk(", mem 0x%06lx-0x%06lx", req.Base,
+	       req.Base+req.Size-1);
+    printk("\n");
+    
+    link->state &= ~DEV_CONFIG_PENDING;
+    return;
+
+cs_failed:
+    cs_error(link->handle, last_fn, last_ret);
+    dummy_release((u_long)link);
+
+} /* dummy_config */
+
+/*======================================================================
+
+    After a card is removed, dummy_release() will unregister the
+    device, and release the PCMCIA configuration.  If the device is
+    still open, this will be postponed until it is closed.
+    
+======================================================================*/
+
+static void dummy_release(u_long arg)
+{
+    dev_link_t *link = (dev_link_t *)arg;
+
+    DEBUG(0, "dummy_release(0x%p)\n", link);
+
+    /*
+       If the device is currently in use, we won't release until it
+       is actually closed, because until then, we can't be sure that
+       no one will try to access the device or its data structures.
+    */
+    if (link->open) {
+	DEBUG(1, "dummy_cs: release postponed, '%s' still open\n",
+	      link->dev->dev_name);
+	link->state |= DEV_STALE_CONFIG;
+	return;
+    }
+
+    /* Unlink the device chain */
+    link->dev = NULL;
+
+    /*
+      In a normal driver, additional code may be needed to release
+      other kernel data structures associated with this device. 
+    */
+    
+    /* Don't bother checking to see if these succeed or not */
+    if (link->win)
+	CardServices(ReleaseWindow, link->win);
+    CardServices(ReleaseConfiguration, link->handle);
+    if (link->io.NumPorts1)
+	CardServices(ReleaseIO, link->handle, &link->io);
+    if (link->irq.AssignedIRQ)
+	CardServices(ReleaseIRQ, link->handle, &link->irq);
+    link->state &= ~DEV_CONFIG;
+    
+    if (link->state & DEV_STALE_LINK)
+	dummy_detach(link);
+    
+} /* dummy_release */
+
+/*======================================================================
+
+    The card status event handler.  Mostly, this schedules other
+    stuff to run after an event is received.
+
+    When a CARD_REMOVAL event is received, we immediately set a
+    private flag to block future accesses to this device.  All the
+    functions that actually access the device should check this flag
+    to make sure the card is still present.
+    
+======================================================================*/
+
+static int dummy_event(event_t event, int priority,
+		       event_callback_args_t *args)
+{
+    dev_link_t *link = args->client_data;
+    local_info_t *dev = link->priv;
+    
+    DEBUG(1, "dummy_event(0x%06x)\n", event);
+    
+    switch (event) {
+    case CS_EVENT_CARD_REMOVAL:
+	link->state &= ~DEV_PRESENT;
+	if (link->state & DEV_CONFIG) {
+	    ((local_info_t *)link->priv)->stop = 1;
+	    mod_timer(&link->release, jiffies + HZ/20);
+	}
+	break;
+    case CS_EVENT_CARD_INSERTION:
+	link->state |= DEV_PRESENT | DEV_CONFIG_PENDING;
+	dev->bus = args->bus;
+	dummy_config(link);
+	break;
+    case CS_EVENT_PM_SUSPEND:
+	link->state |= DEV_SUSPEND;
+	/* Fall through... */
+    case CS_EVENT_RESET_PHYSICAL:
+	/* Mark the device as stopped, to block IO until later */
+	dev->stop = 1;
+	if (link->state & DEV_CONFIG)
+	    CardServices(ReleaseConfiguration, link->handle);
+	break;
+    case CS_EVENT_PM_RESUME:
+	link->state &= ~DEV_SUSPEND;
+	/* Fall through... */
+    case CS_EVENT_CARD_RESET:
+	if (link->state & DEV_CONFIG)
+	    CardServices(RequestConfiguration, link->handle, &link->conf);
+	dev->stop = 0;
+	/*
+	  In a normal driver, additional code may go here to restore
+	  the device state and restart IO. 
+	*/
+	break;
+    }
+    return 0;
+} /* dummy_event */
+
+/*====================================================================*/
+
+static int __init init_dummy_cs(void)
+{
+    servinfo_t serv;
+    DEBUG(0, "%s\n", version);
+    CardServices(GetCardServicesInfo, &serv);
+    if (serv.Revision != CS_RELEASE_CODE) {
+	printk(KERN_NOTICE "dummy_cs: Card Services release "
+	       "does not match!\n");
+	return -1;
+    }
+    register_pccard_driver(&dev_info, &dummy_attach, &dummy_detach);
+    return 0;
+}
+
+static void __exit exit_dummy_cs(void)
+{
+    DEBUG(0, "dummy_cs: unloading\n");
+    unregister_pccard_driver(&dev_info);
+    while (dev_list != NULL) {
+	del_timer(&dev_list->release);
+	if (dev_list->state & DEV_CONFIG)
+	    dummy_release((u_long)dev_list);
+	dummy_detach(dev_list);
+    }
+}
+
+module_init(init_dummy_cs);
+module_exit(exit_dummy_cs);
Index: oldkernel/linux/pcmcia-cs-3.1.15/clients/fdomain_stub.c
diff -u /dev/null linux/pcmcia-cs-3.1.15/clients/fdomain_stub.c:1.1
--- /dev/null	Mon Jul 31 21:15:10 2000
+++ linux/pcmcia-cs-3.1.15/clients/fdomain_stub.c	Fri Jul  7 16:34:58 2000
@@ -0,0 +1,419 @@
+/*======================================================================
+
+    A driver for Future Domain-compatible PCMCIA SCSI cards
+
+    fdomain_cs.c 1.42 2000/05/04 01:30:00
+
+    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@pcmcia.sourceforge.org>.  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 <pcmcia/config.h>
+#include <pcmcia/k_compat.h>
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/malloc.h>
+#include <linux/string.h>
+#include <linux/timer.h>
+#include <linux/ioport.h>
+#include <scsi/scsi.h>
+#include <linux/major.h>
+#include <linux/blk.h>
+
+#include <../drivers/scsi/scsi.h>
+#include <../drivers/scsi/hosts.h>
+#include <scsi/scsi_ioctl.h>
+#include <../drivers/scsi/fdomain.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 =
+"fdomain_cs.c 1.42 2000/05/04 01:30:00 (David Hinds)";
+#else
+#define DEBUG(n, args...)
+#endif
+
+/*====================================================================*/
+
+/* Parameters that can be set with 'insmod' */
+
+/* Bit map of interrupts to choose from */
+static u_int irq_mask = 0xdeb8;
+static int irq_list[4] = { -1 };
+
+MODULE_PARM(irq_mask, "i");
+MODULE_PARM(irq_list, "1-4i");
+
+/*====================================================================*/
+
+typedef struct scsi_info_t {
+    dev_link_t		link;
+    int			ndev;
+    dev_node_t		node[8];
+} scsi_info_t;
+
+extern void fdomain_setup(char *str, int *ints);
+
+static void fdomain_release(u_long arg);
+static int fdomain_event(event_t event, int priority,
+			event_callback_args_t *args);
+
+static dev_link_t *fdomain_attach(void);
+static void fdomain_detach(dev_link_t *);
+
+static Scsi_Host_Template driver_template = FDOMAIN_16X0;
+
+static dev_link_t *dev_list = NULL;
+
+static dev_info_t dev_info = "fdomain_cs";
+
+/*====================================================================*/
+
+static void cs_error(client_handle_t handle, int func, int ret)
+{
+    error_info_t err = { func, ret };
+    CardServices(ReportError, handle, &err);
+}
+
+/*====================================================================*/
+
+static dev_link_t *fdomain_attach(void)
+{
+    scsi_info_t *info;
+    client_reg_t client_reg;
+    dev_link_t *link;
+    int i, ret;
+    
+    DEBUG(0, "fdomain_attach()\n");
+
+    /* Create new SCSI device */
+    info = kmalloc(sizeof(*info), GFP_KERNEL);
+    if (!info) return NULL;
+    memset(info, 0, sizeof(*info));
+    link = &info->link; link->priv = info;
+    link->release.function = &fdomain_release;
+    link->release.data = (u_long)link;
+
+    link->io.NumPorts1 = 0x10;
+    link->io.Attributes1 = IO_DATA_PATH_WIDTH_AUTO;
+    link->io.IOAddrLines = 10;
+    link->irq.Attributes = IRQ_TYPE_EXCLUSIVE;
+    link->irq.IRQInfo1 = IRQ_INFO2_VALID|IRQ_LEVEL_ID;
+    if (irq_list[0] == -1)
+	link->irq.IRQInfo2 = irq_mask;
+    else
+	for (i = 0; i < 4; i++)
+	    link->irq.IRQInfo2 |= 1 << irq_list[i];
+    link->conf.Attributes = CONF_ENABLE_IRQ;
+    link->conf.Vcc = 50;
+    link->conf.IntType = INT_MEMORY_AND_IO;
+    link->conf.Present = PRESENT_OPTION;
+
+    /* Register with Card Services */
+    link->next = dev_list;
+    dev_list = link;
+    client_reg.dev_info = &dev_info;
+    client_reg.Attributes = INFO_IO_CLIENT | INFO_CARD_SHARE;
+    client_reg.event_handler = &fdomain_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);
+	fdomain_detach(link);
+	return NULL;
+    }
+    
+    return link;
+} /* fdomain_attach */
+
+/*====================================================================*/
+
+static void fdomain_detach(dev_link_t *link)
+{
+    dev_link_t **linkp;
+
+    DEBUG(0, "fdomain_detach(0x%p)\n", link);
+    
+    /* Locate device structure */
+    for (linkp = &dev_list; *linkp; linkp = &(*linkp)->next)
+	if (*linkp == link) break;
+    if (*linkp == NULL)
+	return;
+
+    del_timer(&link->release);
+    if (link->state & DEV_CONFIG) {
+	fdomain_release((u_long)link);
+	if (link->state & DEV_STALE_CONFIG) {
+	    link->state |= DEV_STALE_LINK;
+	    return;
+	}
+    }
+
+    if (link->handle)
+	CardServices(DeregisterClient, link->handle);
+    
+    /* Unlink device structure, free bits */
+    *linkp = link->next;
+    kfree(link->priv);
+    
+} /* fdomain_detach */
+
+/*====================================================================*/
+
+#define CS_CHECK(fn, args...) \
+while ((last_ret=CardServices(last_fn=(fn), args))!=0) goto cs_failed
+
+#define CFG_CHECK(fn, args...) \
+if (CardServices(fn, args) != 0) goto next_entry
+
+static void fdomain_config(dev_link_t *link)
+{
+    client_handle_t handle = link->handle;
+    scsi_info_t *info = link->priv;
+    tuple_t tuple;
+    cisparse_t parse;
+    int i, last_ret, last_fn, ints[3];
+    u_char tuple_data[64];
+    Scsi_Device *dev;
+    dev_node_t *node, **tail;
+#if (LINUX_VERSION_CODE >= VERSION(2,1,75))
+    struct Scsi_Host *host;
+#endif
+
+    DEBUG(0, "fdomain_config(0x%p)\n", link);
+
+    tuple.DesiredTuple = CISTPL_CONFIG;
+    tuple.TupleData = tuple_data;
+    tuple.TupleDataMax = 64;
+    tuple.TupleOffset = 0;
+    CS_CHECK(GetFirstTuple, handle, &tuple);
+    CS_CHECK(GetTupleData, handle, &tuple);
+    CS_CHECK(ParseTuple, handle, &tuple, &parse);
+    link->conf.ConfigBase = parse.config.base;
+
+    /* Configure card */
+#if (LINUX_VERSION_CODE >= VERSION(2,1,23))
+    driver_template.module = &__this_module;
+#else
+    driver_template.usage_count = &GET_USE_COUNT(&__this_module);
+#endif
+    link->state |= DEV_CONFIG;
+    
+    tuple.DesiredTuple = CISTPL_CFTABLE_ENTRY;
+    CS_CHECK(GetFirstTuple, handle, &tuple);
+    while (1) {
+	CFG_CHECK(GetTupleData, handle, &tuple);
+	CFG_CHECK(ParseTuple, handle, &tuple, &parse);
+	link->conf.ConfigIndex = parse.cftable_entry.index;
+	link->io.BasePort1 = parse.cftable_entry.io.win[0].base;
+	i = CardServices(RequestIO, handle, &link->io);
+	if (i == CS_SUCCESS) break;
+    next_entry:
+	CS_CHECK(GetNextTuple, handle, &tuple);
+    }
+
+    CS_CHECK(RequestIRQ, handle, &link->irq);
+    CS_CHECK(RequestConfiguration, handle, &link->conf);
+    
+    /* A bad hack... */
+    release_region(link->io.BasePort1, link->io.NumPorts1);
+
+    /* Set configuration options for the fdomain driver */
+    ints[0] = 2;
+    ints[1] = link->io.BasePort1;
+    ints[2] = link->irq.AssignedIRQ;
+    fdomain_setup("PCMCIA setup", ints);
+    
+    scsi_register_module(MODULE_SCSI_HA, &driver_template);
+
+    tail = &link->dev;
+    info->ndev = 0;
+#if (LINUX_VERSION_CODE < VERSION(2,1,75))
+    for (dev = scsi_devices; dev != NULL; dev = dev->next)
+	if (dev->host->hostt == &driver_template) {
+#else
+    for (host = scsi_hostlist; host; host = host->next)
+	if (host->hostt == &driver_template)
+	    for (dev = host->host_queue; dev; dev = dev->next) {
+#endif
+	    u_long arg[2], id;
+	    kernel_scsi_ioctl(dev, SCSI_IOCTL_GET_IDLUN, arg);
+	    id = (arg[0]&0x0f) + ((arg[0]>>4)&0xf0) +
+		((arg[0]>>8)&0xf00) + ((arg[0]>>12)&0xf000);
+	    node = &info->node[info->ndev];
+	    node->minor = 0;
+	    switch (dev->type) {
+	    case TYPE_TAPE:
+		node->major = SCSI_TAPE_MAJOR;
+		sprintf(node->dev_name, "st#%04lx", id);
+		break;
+	    case TYPE_DISK:
+	    case TYPE_MOD:
+		node->major = SCSI_DISK0_MAJOR;
+		sprintf(node->dev_name, "sd#%04lx", id);
+		break;
+	    case TYPE_ROM:
+	    case TYPE_WORM:
+		node->major = SCSI_CDROM_MAJOR;
+		sprintf(node->dev_name, "sr#%04lx", id);
+		break;
+	    default:
+		node->major = SCSI_GENERIC_MAJOR;
+		sprintf(node->dev_name, "sg#%04lx", id);
+		break;
+	    }
+	    *tail = node; tail = &node->next;
+	    info->ndev++;
+	}
+    *tail = NULL;
+    if (info->ndev == 0)
+	printk(KERN_INFO "fdomain_cs: no SCSI devices found\n");
+    
+    link->state &= ~DEV_CONFIG_PENDING;
+    return;
+    
+cs_failed:
+    cs_error(link->handle, last_fn, last_ret);
+    fdomain_release((u_long)link);
+    return;
+    
+} /* fdomain_config */
+
+/*====================================================================*/
+
+static void fdomain_release(u_long arg)
+{
+    dev_link_t *link = (dev_link_t *)arg;
+
+    DEBUG(0, "fdomain_release(0x%p)\n", link);
+
+    if (GET_USE_COUNT(&__this_module) != 0) {
+	DEBUG(1, "fdomain_cs: release postponed, "
+	      "device still open\n");
+	link->state |= DEV_STALE_CONFIG;
+	return;
+    }
+
+    scsi_unregister_module(MODULE_SCSI_HA, &driver_template);
+    link->dev = NULL;
+    
+    CardServices(ReleaseConfiguration, link->handle);
+    CardServices(ReleaseIO, link->handle, &link->io);
+    CardServices(ReleaseIRQ, link->handle, &link->irq);
+    
+    link->state &= ~DEV_CONFIG;
+    if (link->state & DEV_STALE_LINK)
+	fdomain_detach(link);
+    
+} /* fdomain_release */
+
+/*====================================================================*/
+
+static int fdomain_event(event_t event, int priority,
+			event_callback_args_t *args)
+{
+    dev_link_t *link = args->client_data;
+
+    DEBUG(1, "fdomain_event(0x%06x)\n", event);
+    
+    switch (event) {
+    case CS_EVENT_CARD_REMOVAL:
+	link->state &= ~DEV_PRESENT;
+	if (link->state & DEV_CONFIG)
+	    mod_timer(&link->release, jiffies + HZ/20);
+	break;
+    case CS_EVENT_CARD_INSERTION:
+	link->state |= DEV_PRESENT | DEV_CONFIG_PENDING;
+	fdomain_config(link);
+	break;
+    case CS_EVENT_PM_SUSPEND:
+	link->state |= DEV_SUSPEND;
+	/* Fall through... */
+    case CS_EVENT_RESET_PHYSICAL:
+	if (link->state & DEV_CONFIG)
+	    CardServices(ReleaseConfiguration, link->handle);
+	break;
+    case CS_EVENT_PM_RESUME:
+	link->state &= ~DEV_SUSPEND;
+	/* Fall through... */
+    case CS_EVENT_CARD_RESET:
+	if (link->state & DEV_CONFIG) {
+	    CardServices(RequestConfiguration, link->handle, &link->conf);
+#if (LINUX_VERSION_CODE >= VERSION(2,1,18))
+	    fdomain_16x0_reset(NULL, 0);
+#else
+#if (LINUX_VERSION_CODE < VERSION(2,1,0)) && (LINUX_VERSION_CODE > VERSION(2,0,34))
+	    fdomain_16x0_reset(NULL, 0);
+#else
+	    fdomain_16x0_reset(NULL);
+#endif
+#endif
+	}
+	break;
+    }
+    return 0;
+} /* fdomain_event */
+
+/*====================================================================*/
+
+static int __init init_fdomain_cs(void) {
+    servinfo_t serv;
+    DEBUG(0, "%s\n", version);
+    CardServices(GetCardServicesInfo, &serv);
+    if (serv.Revision != CS_RELEASE_CODE) {
+	printk(KERN_NOTICE "fdomain_cs: Card Services release "
+	       "does not match!\n");
+	return -1;
+    }
+    register_pccard_driver(&dev_info, &fdomain_attach, &fdomain_detach);
+    return 0;
+}
+
+static void __exit exit_fdomain_cs(void) {
+    DEBUG(0, "fdomain_cs: unloading\n");
+    unregister_pccard_driver(&dev_info);
+    while (dev_list != NULL)
+	fdomain_detach(dev_list);
+}
+
+module_init(init_fdomain_cs);
+module_exit(exit_fdomain_cs);
Index: oldkernel/linux/pcmcia-cs-3.1.15/clients/fmvj18x_cs.c
diff -u /dev/null linux/pcmcia-cs-3.1.15/clients/fmvj18x_cs.c:1.1
--- /dev/null	Mon Jul 31 21:15:10 2000
+++ linux/pcmcia-cs-3.1.15/clients/fmvj18x_cs.c	Fri Jul  7 16:34:58 2000
@@ -0,0 +1,1124 @@
+/*======================================================================
+    fmvj18x_cs.c,v 1.9 1996/08/06 03:13:53 root Exp
+
+    A fmvj18x (and its compatibles) PCMCIA client driver
+
+    Contributed by Shingo Fujimoto, shingo@flab.fujitsu.co.jp
+
+    TDK LAK-CD021 and CONTEC C-NET(PC)C support added by 
+    Nobuhiro Katayama, kata-n@po.iijnet.or.jp
+
+    The PCMCIA client code is based on code written by David Hinds.
+    Network code is based on the "FMV-18x driver" by Yutaka TAMIYA
+    but is actually largely Donald Becker's AT1700 driver, which
+    carries the following attribution:
+
+    Written 1993-94 by Donald Becker.
+
+    Copyright 1993 United States Government as represented by the
+    Director, National Security Agency.
+    
+    This software may be used and distributed according to the terms
+    of the GNU Public License, incorporated herein by reference.
+    
+    The author may be reached as becker@CESDIS.gsfc.nasa.gov, or C/O
+    Center of Excellence in Space Data and Information Sciences
+    Code 930.5, Goddard Space Flight Center, Greenbelt MD 20771
+    
+======================================================================*/
+
+#include <pcmcia/config.h>
+#include <pcmcia/k_compat.h>
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/sched.h>
+#include <linux/ptrace.h>
+#include <linux/malloc.h>
+#include <linux/string.h>
+#include <linux/timer.h>
+#include <linux/interrupt.h>
+#include <linux/in.h>
+#include <linux/delay.h>
+#include <asm/io.h>
+#include <asm/system.h>
+
+#include <linux/netdevice.h>
+#include <linux/etherdevice.h>
+#include <linux/skbuff.h>
+#include <linux/if_arp.h>
+#include <linux/ioport.h>
+
+#include <pcmcia/version.h>
+#include <pcmcia/cs_types.h>
+#include <pcmcia/cs.h>
+#include <pcmcia/cistpl.h>
+#include <pcmcia/ciscode.h>
+#include <pcmcia/ds.h>
+
+/*
+   All the PCMCIA modules use PCMCIA_DEBUG to control debugging.  If
+   you do not define PCMCIA_DEBUG at all, all the debug code will be
+   left out.  If you compile with PCMCIA_DEBUG=0, the debug code will
+   be present but disabled -- but it can then be enabled for specific
+   modules at load time with a 'pc_debug=#' option to insmod.
+*/
+#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)
+#else
+#define DEBUG(n, args...)
+#endif
+
+/* Bit map of interrupts to choose from */
+/* This means pick from 15, 14, 12, 11, 10, 9, 7, 5, 4, and 3 */
+static u_int irq_mask = 0xdeb8;
+static int irq_list[4] = { -1 };
+
+/* SRAM configuration */
+/* 0:4KB*2 TX buffer   else:8KB*2 TX buffer */
+static int sram_config = 0;
+
+MODULE_PARM(irq_mask, "i");
+MODULE_PARM(irq_list, "1-4i");
+MODULE_PARM(sram_config, "i");
+
+/*====================================================================*/
+/* 
+   driver version infomation 
+ */
+#ifdef PCMCIA_DEBUG
+static char *version =
+ "fmvj18x_cs.c,v 1.9 1996/08/06 03:13:53 root Exp";
+#endif
+
+/*====================================================================*/
+/*
+    PCMCIA event handlers
+ */
+static void fmvj18x_config(dev_link_t *link);
+static void fmvj18x_release(u_long arg);
+static int fmvj18x_event(event_t event, int priority,
+			  event_callback_args_t *args);
+static dev_link_t *fmvj18x_attach(void);
+static void fmvj18x_detach(dev_link_t *);
+
+/*
+    LAN controler(MBH86960A) specific routines
+ */
+static int fjn_config(struct net_device *dev, struct ifmap *map);
+static int fjn_open(struct net_device *dev);
+static int fjn_close(struct net_device *dev);
+static int fjn_start_xmit(struct sk_buff *skb, struct net_device *dev);
+static void fjn_interrupt(int irq, void *dev_id, struct pt_regs *regs);
+static void fjn_rx(struct net_device *dev);
+static void fjn_reset(struct net_device *dev);
+static struct net_device_stats *fjn_get_stats(struct net_device *dev);
+static void set_rx_mode(struct net_device *dev);
+static void fjn_tx_timeout(struct net_device *dev);
+
+static dev_info_t dev_info = "fmvj18x_cs";
+static dev_link_t *dev_list = NULL;
+
+/*
+    card type
+ */
+typedef enum { MBH10302, MBH10304, TDK, CONTEC, LA501 } cardtype_t;
+
+/*
+    driver specific data structure
+*/
+typedef struct local_info_t {
+    dev_link_t link;
+    struct net_device dev;
+    dev_node_t node;
+    struct net_device_stats stats;
+    long open_time;
+    uint tx_started:1;
+    uint tx_queue;
+    u_short tx_queue_len;
+    cardtype_t cardtype;
+    u_short sent;
+    u_char mc_filter[8];
+} local_info_t;
+
+#define MC_FILTERBREAK 64
+
+/*====================================================================*/
+/* 
+    ioport offset from the base address 
+ */
+#define TX_STATUS               0 /* transmit status register */
+#define RX_STATUS               1 /* receive status register */
+#define TX_INTR                 2 /* transmit interrupt mask register */
+#define RX_INTR                 3 /* receive interrupt mask register */
+#define TX_MODE                 4 /* transmit mode register */
+#define RX_MODE                 5 /* receive mode register */
+#define CONFIG_0                6 /* configuration register 0 */
+#define CONFIG_1                7 /* configuration register 1 */
+
+#define NODE_ID                 8 /* node ID register            (bank 0) */
+#define MAR_ADR                 8 /* multicast address registers (bank 1) */
+
+#define DATAPORT                8 /* buffer mem port registers   (bank 2) */
+#define TX_START               10 /* transmit start register */
+#define COL_CTRL               11 /* 16 collision control register */
+#define BMPR12                 12 /* reserved */
+#define BMPR13                 13 /* reserved */
+#define RX_SKIP                14 /* skip received packet register */
+
+#define LAN_CTRL               16 /* LAN card control register */
+
+#define MAC_ID               0x1a /* hardware address */
+
+/* 
+    control bits 
+ */
+#define ENA_TMT_OK           0x80
+#define ENA_TMT_REC          0x20
+#define ENA_COL              0x04
+#define ENA_16_COL           0x02
+#define ENA_TBUS_ERR         0x01
+
+#define ENA_PKT_RDY          0x80
+#define ENA_BUS_ERR          0x40
+#define ENA_LEN_ERR          0x08
+#define ENA_ALG_ERR          0x04
+#define ENA_CRC_ERR          0x02
+#define ENA_OVR_FLO          0x01
+
+/* flags */
+#define F_TMT_RDY            0x80 /* can accept new packet */
+#define F_NET_BSY            0x40 /* carrier is detected */
+#define F_TMT_OK             0x20 /* send packet successfully */
+#define F_SRT_PKT            0x10 /* short packet error */
+#define F_COL_ERR            0x04 /* collision error */
+#define F_16_COL             0x02 /* 16 collision error */
+#define F_TBUS_ERR           0x01 /* bus read error */
+
+#define F_PKT_RDY            0x80 /* packet(s) in buffer */
+#define F_BUS_ERR            0x40 /* bus read error */
+#define F_LEN_ERR            0x08 /* short packet */
+#define F_ALG_ERR            0x04 /* frame error */
+#define F_CRC_ERR            0x02 /* CRC error */
+#define F_OVR_FLO            0x01 /* overflow error */
+
+#define F_BUF_EMP            0x40 /* receive buffer is empty */
+
+#define F_SKP_PKT            0x05 /* drop packet in buffer */
+
+/* default bitmaps */
+#define D_TX_INTR  ( ENA_TMT_OK )
+#define D_RX_INTR  ( ENA_PKT_RDY | ENA_LEN_ERR \
+		   | ENA_ALG_ERR | ENA_CRC_ERR | ENA_OVR_FLO )
+#define TX_STAT_M  ( F_TMT_RDY )
+#define RX_STAT_M  ( F_PKT_RDY | F_LEN_ERR \
+                   | F_ALG_ERR | F_CRC_ERR | F_OVR_FLO )
+
+/* commands */
+#define D_TX_MODE            0x06 /* no tests, detect carrier */
+#define ID_MATCHED           0x02 /* (RX_MODE) */
+#define RECV_ALL             0x03 /* (RX_MODE) */
+#define CONFIG0_DFL          0x5a /* 16bit bus, 4K x 2 Tx queues */
+#define CONFIG0_DFL_1        0x5e /* 16bit bus, 8K x 2 Tx queues */
+#define CONFIG0_RST          0xda /* Data Link Controler off (CONFIG_0) */
+#define CONFIG0_RST_1        0xde /* Data Link Controler off (CONFIG_0) */
+#define BANK_0               0xa0 /* bank 0 (CONFIG_1) */
+#define BANK_1               0xa4 /* bank 1 (CONFIG_1) */
+#define BANK_2               0xa8 /* bank 2 (CONFIG_1) */
+#define CHIP_OFF             0x80 /* contrl chip power off (CONFIG_1) */
+#define DO_TX                0x80 /* do transmit packet */
+#define SEND_PKT             0x81 /* send a packet */
+#define AUTO_MODE            0x07 /* Auto skip packet on 16 col detected */
+#define MANU_MODE            0x03 /* Stop and skip packet on 16 col */
+#define TDK_AUTO_MODE        0x47 /* Auto skip packet on 16 col detected */
+#define TDK_MANU_MODE        0x43 /* Stop and skip packet on 16 col */
+#define INTR_OFF             0x0d /* LAN controler ignores interrupts */
+#define INTR_ON              0x1d /* LAN controler will catch interrupts */
+
+#define TX_TIMEOUT		((400*HZ)/1000)
+
+/*======================================================================
+
+    This bit of code is used to avoid unregistering network devices
+    at inappropriate times.  2.2 and later kernels are fairly picky
+    about when this can happen.
+    
+======================================================================*/
+
+static void flush_stale_links(void)
+{
+    dev_link_t *link, *next;
+    for (link = dev_list; link; link = next) {
+	next = link->next;
+	if (link->state & DEV_STALE_LINK)
+	    fmvj18x_detach(link);
+    }
+}
+
+/*====================================================================*/
+
+static void cs_error(client_handle_t handle, int func, int ret)
+{
+    error_info_t err = { func, ret };
+    CardServices(ReportError, handle, &err);
+}
+
+/*====================================================================*/
+
+static dev_link_t *fmvj18x_attach(void)
+{
+    local_info_t *lp;
+    dev_link_t *link;
+    struct net_device *dev;
+    client_reg_t client_reg;
+    int i, ret;
+    
+    DEBUG(0, "fmvj18x_attach()\n");
+    flush_stale_links();
+
+    /* Make up a FMVJ18x specific data structure */
+    lp = kmalloc(sizeof(*lp), GFP_KERNEL);
+    if (!lp) return NULL;
+    memset(lp, 0, sizeof(*lp));
+    link = &lp->link; dev = &lp->dev;
+    link->priv = dev->priv = link->irq.Instance = lp;
+
+    link->release.function = &fmvj18x_release;
+    link->release.data = (u_long)link;
+
+    /* The io structure describes IO port mapping */
+    link->io.NumPorts1 = 32;
+    link->io.Attributes1 = IO_DATA_PATH_WIDTH_AUTO;
+    link->io.IOAddrLines = 5;
+
+    /* Interrupt setup */
+    link->irq.Attributes = IRQ_TYPE_EXCLUSIVE | IRQ_HANDLE_PRESENT;
+    link->irq.IRQInfo1 = IRQ_INFO2_VALID|IRQ_LEVEL_ID;
+    if (irq_list[0] == -1)
+	link->irq.IRQInfo2 = irq_mask;
+    else
+	for (i = 0; i < 4; i++)
+	    link->irq.IRQInfo2 |= 1 << irq_list[i];
+    link->irq.Handler = &fjn_interrupt;
+    
+    /* General socket configuration */
+    link->conf.Attributes = CONF_ENABLE_IRQ;
+    link->conf.Vcc = 50;
+    link->conf.IntType = INT_MEMORY_AND_IO;
+
+    /* The FMVJ18x specific entries in the device structure. */
+    dev->hard_start_xmit = &fjn_start_xmit;
+    dev->set_config = &fjn_config;
+    dev->get_stats = &fjn_get_stats;
+    dev->set_multicast_list = &set_rx_mode;
+    ether_setup(dev);
+    dev->name = lp->node.dev_name;
+    dev->open = &fjn_open;
+    dev->stop = &fjn_close;
+#ifdef HAVE_NETIF_QUEUE
+    dev->tx_timeout = fjn_tx_timeout;
+    dev->watchdog_timeo = TX_TIMEOUT;
+#endif
+    
+    /* Register with Card Services */
+    link->next = dev_list;
+    dev_list = link;
+    client_reg.dev_info = &dev_info;
+    client_reg.Attributes = INFO_IO_CLIENT | INFO_CARD_SHARE;
+    client_reg.EventMask =
+	CS_EVENT_CARD_INSERTION | CS_EVENT_CARD_REMOVAL |
+	CS_EVENT_RESET_PHYSICAL | CS_EVENT_CARD_RESET |
+	CS_EVENT_PM_SUSPEND | CS_EVENT_PM_RESUME;
+    client_reg.event_handler = &fmvj18x_event;
+    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);
+	fmvj18x_detach(link);
+	return NULL;
+    }
+
+    return link;
+} /* fmvj18x_attach */
+
+/*====================================================================*/
+
+static void fmvj18x_detach(dev_link_t *link)
+{
+    local_info_t *lp = link->priv;
+    dev_link_t **linkp;
+    
+    DEBUG(0, "fmvj18x_detach(0x%p)\n", link);
+    
+    /* Locate device structure */
+    for (linkp = &dev_list; *linkp; linkp = &(*linkp)->next)
+	if (*linkp == link) break;
+    if (*linkp == NULL)
+	return;
+
+    del_timer(&link->release);
+    if (link->state & DEV_CONFIG) {
+	fmvj18x_release((u_long)link);
+	if (link->state & DEV_STALE_CONFIG) {
+	    link->state |= DEV_STALE_LINK;
+	    return;
+	}
+    }
+
+    /* Break the link with Card Services */
+    if (link->handle)
+	CardServices(DeregisterClient, link->handle);
+    
+    /* Unlink device structure, free pieces */
+    *linkp = link->next;
+    if (link->dev)
+	unregister_netdev(&lp->dev);
+    kfree(lp);
+    
+} /* fmvj18x_detach */
+
+/*====================================================================*/
+
+#define CS_CHECK(fn, args...) \
+while ((last_ret=CardServices(last_fn=(fn), args))!=0) goto cs_failed
+
+static void fmvj18x_config(dev_link_t *link)
+{
+    client_handle_t handle = link->handle;
+    local_info_t *lp = link->priv;
+    struct net_device *dev = &lp->dev;
+    tuple_t tuple;
+    cisparse_t parse;
+    u_short buf[32];
+    int i, last_fn, last_ret;
+    ioaddr_t ioaddr;
+    cardtype_t cardtype;
+    char *card_name = "unknown";
+    u_char *node_id;
+    
+    DEBUG(0, "fmvj18x_config(0x%p)\n", link);
+
+    /*
+       This reads the card's CONFIG tuple to find its configuration
+       registers.
+    */
+    tuple.DesiredTuple = CISTPL_CONFIG;
+    CS_CHECK(GetFirstTuple, handle, &tuple);
+    tuple.TupleData = (u_char *)buf;
+    tuple.TupleDataMax = 64;
+    tuple.TupleOffset = 0;
+    CS_CHECK(GetTupleData, handle, &tuple);
+    CS_CHECK(ParseTuple, handle, &tuple, &parse);
+    
+    /* Configure card */
+    link->state |= DEV_CONFIG;
+
+    link->conf.ConfigBase = parse.config.base; 
+    link->conf.Present = parse.config.rmask[0];
+
+    tuple.DesiredTuple = CISTPL_FUNCE;
+    tuple.TupleOffset = 0;
+    if (CardServices(GetFirstTuple, handle, &tuple) == CS_SUCCESS) {
+	/* Yes, I have CISTPL_FUNCE. Let's check CISTPL_MANFID */
+	tuple.DesiredTuple = CISTPL_CFTABLE_ENTRY;
+	CS_CHECK(GetFirstTuple, handle, &tuple);
+	CS_CHECK(GetTupleData, handle, &tuple);
+	CS_CHECK(ParseTuple, handle, &tuple, &parse);
+	link->conf.ConfigIndex = parse.cftable_entry.index;
+	tuple.DesiredTuple = CISTPL_MANFID;
+	CS_CHECK(GetFirstTuple, handle, &tuple);
+	CS_CHECK(GetTupleData, handle, &tuple);
+
+	switch (le16_to_cpu(buf[0])) {
+	case MANFID_TDK:
+	    cardtype = TDK;
+	    break;
+	case MANFID_CONTEC:
+	    cardtype = CONTEC;
+	    break;
+	case MANFID_FUJITSU:
+	    if (le16_to_cpu(buf[1]) == PRODID_FUJITSU_MBH10302)
+		cardtype = MBH10302;
+	    else if (le16_to_cpu(buf[1]) == PRODID_FUJITSU_MBH10304)
+		cardtype = MBH10304;
+	    else
+		cardtype = LA501;
+	    break;
+	default:
+	    cardtype = MBH10304;
+	}
+    } else {
+	/* old type card */
+	cardtype = MBH10302;
+	link->conf.ConfigIndex = 1;
+    }
+    CS_CHECK(RequestIO, link->handle, &link->io);
+    CS_CHECK(RequestIRQ, link->handle, &link->irq);
+    CS_CHECK(RequestConfiguration, link->handle, &link->conf);
+    dev->irq = link->irq.AssignedIRQ;
+    dev->base_addr = link->io.BasePort1;
+    if (register_netdev(dev) != 0) {
+	printk(KERN_NOTICE "fmvj18x_cs: register_netdev() failed\n");
+	goto failed;
+    }
+
+    ioaddr = dev->base_addr;
+
+    /* Power On chip and select bank 0 */
+    outb(BANK_0, ioaddr + CONFIG_1);
+    /* Reset controler */
+    if( sram_config == 0 ) 
+	outb(CONFIG0_RST, ioaddr + CONFIG_0);
+    else
+	outb(CONFIG0_RST_1, ioaddr + CONFIG_0);
+    
+    /* Set hardware address */
+    switch (cardtype) {
+    case MBH10304:
+    case TDK:
+    case LA501:
+    case CONTEC:
+	tuple.DesiredTuple = CISTPL_FUNCE;
+	tuple.TupleOffset = 0;
+	CS_CHECK(GetFirstTuple, handle, &tuple);
+	tuple.TupleOffset = 0;
+	CS_CHECK(GetTupleData, handle, &tuple);
+	if (cardtype == MBH10304) {
+	    /* MBH10304's CIS_FUNCE is corrupted */
+	    node_id = &(tuple.TupleData[5]);
+	    card_name = "FMV-J182";
+	} else {
+	    while (tuple.TupleData[0] != CISTPL_FUNCE_LAN_NODE_ID ) {
+		CS_CHECK(GetNextTuple, handle, &tuple) ;
+		CS_CHECK(GetTupleData, handle, &tuple) ;
+	    }
+	    node_id = &(tuple.TupleData[2]);
+	    if( cardtype == TDK ) {
+		card_name = "TDK LAK-CD021";
+	    } else if( cardtype == LA501 ) {
+		card_name = "LA501";
+	    } else {
+		card_name = "C-NET(PC)C";
+	    }
+	}
+	/* Read MACID from CIS */
+	for (i = 0; i < 6; i++)
+	    dev->dev_addr[i] = node_id[i];
+	break;
+    case MBH10302:
+    default:
+	/* Read MACID from register */
+	for (i = 0; i < 6; i++) 
+	    dev->dev_addr[i] = inb(ioaddr + MAC_ID + i);
+	card_name = "FMV-J181";
+	break;
+    }
+
+    link->dev = &lp->node;
+    link->state &= ~DEV_CONFIG_PENDING;
+
+    lp->cardtype = cardtype;
+    /* print current configuration */
+    printk(KERN_INFO "%s: %s, sram %s, port %#3lx, irq %d, hw_addr ", 
+	   dev->name, card_name, sram_config == 0 ? "4K TX*2" : "8K TX*2", 
+	   dev->base_addr, dev->irq);
+    for (i = 0; i < 6; i++)
+	printk("%02X%s", dev->dev_addr[i], ((i<5) ? ":" : "\n"));
+
+    return;
+    
+cs_failed:
+    /* All Card Services errors end up here */
+    cs_error(link->handle, last_fn, last_ret);
+failed:
+    fmvj18x_release((u_long)link);
+
+} /* fmvj18x_config */
+ 
+/*====================================================================*/
+
+static void fmvj18x_release(u_long arg)
+{
+    dev_link_t *link = (dev_link_t *)arg;
+
+    DEBUG(0, "fmvj18x_release(0x%p)\n", link);
+
+    /*
+       If the device is currently in use, we won't release until it
+       is actually closed.
+    */
+    if (link->open) {
+	DEBUG(1, "fmvj18x_cs: release postponed, '%s' "
+	      "still open\n", link->dev->dev_name);
+	link->state |= DEV_STALE_CONFIG;
+	return;
+    }
+
+    /* Don't bother checking to see if these succeed or not */
+    CardServices(ReleaseWindow, link->win);
+    CardServices(ReleaseConfiguration, link->handle);
+    CardServices(ReleaseIO, link->handle, &link->io);
+    CardServices(ReleaseIRQ, link->handle, &link->irq);
+    
+    link->state &= ~DEV_CONFIG;
+    
+} /* fmvj18x_release */
+
+/*====================================================================*/
+
+static int fmvj18x_event(event_t event, int priority,
+			  event_callback_args_t *args)
+{
+    dev_link_t *link = args->client_data;
+    local_info_t *lp = link->priv;
+    struct net_device *dev = &lp->dev;
+
+    DEBUG(1, "fmvj18x_event(0x%06x)\n", event);
+    
+    switch (event) {
+    case CS_EVENT_CARD_REMOVAL:
+	link->state &= ~DEV_PRESENT;
+	if (link->state & DEV_CONFIG) {
+	    netif_device_detach(dev);
+	    mod_timer(&link->release, jiffies + HZ/20);
+	}
+	break;
+    case CS_EVENT_CARD_INSERTION:
+	link->state |= DEV_PRESENT | DEV_CONFIG_PENDING;
+	fmvj18x_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 (link->open)
+		netif_device_detach(dev);
+	    CardServices(ReleaseConfiguration, link->handle);
+	}
+	break;
+    case CS_EVENT_PM_RESUME:
+	link->state &= ~DEV_SUSPEND;
+	/* Fall through... */
+    case CS_EVENT_CARD_RESET:
+	if (link->state & DEV_CONFIG) {
+	    CardServices(RequestConfiguration, link->handle, &link->conf);
+	    if (link->open) {
+		fjn_reset(dev);
+		netif_device_attach(dev);
+	    }
+	}
+	break;
+    }
+    return 0;
+} /* fmvj18x_event */
+
+/*====================================================================*/
+
+static int __init init_fmvj18x_cs(void)
+{
+    servinfo_t serv;
+    DEBUG(0, "%s\n", version);
+    CardServices(GetCardServicesInfo, &serv);
+    if (serv.Revision != CS_RELEASE_CODE) {
+	printk(KERN_NOTICE "fmvj18x: Card Services release "
+	       "does not match!\n");
+	return -1;
+    }
+    register_pccard_driver(&dev_info, &fmvj18x_attach, &fmvj18x_detach);
+    return 0;
+}
+
+static void __exit exit_fmvj18x_cs(void)
+{
+    DEBUG(0, "fmvj18x_cs: unloading\n");
+    unregister_pccard_driver(&dev_info);
+    while (dev_list != NULL)
+	fmvj18x_detach(dev_list);
+}
+
+module_init(init_fmvj18x_cs);
+module_exit(exit_fmvj18x_cs);
+
+/*====================================================================*/
+
+static void fjn_interrupt(int irq, void *dev_id, struct pt_regs *regs)
+{
+    local_info_t *lp = dev_id;
+    struct net_device *dev = &lp->dev;
+    ioaddr_t ioaddr;
+    unsigned short tx_stat, rx_stat;
+
+    if (lp == NULL) {
+        printk(KERN_NOTICE "fjn_interrupt(): irq %d for "
+	       "unknown device.\n", irq);
+        return;
+    }
+    ioaddr = dev->base_addr;
+
+    /* avoid multiple interrupts */
+    outw(0x0000, ioaddr + TX_INTR);
+
+    /* wait for a while */
+    udelay(1);
+
+    /* get status */
+    tx_stat = inb(ioaddr + TX_STATUS);
+    rx_stat = inb(ioaddr + RX_STATUS);
+
+    /* clear status */
+    outb(tx_stat, ioaddr + TX_STATUS);
+    outb(rx_stat, ioaddr + RX_STATUS);
+    
+    DEBUG(4, "%s: interrupt, rx_status %02x.\n", dev->name, rx_stat);
+    DEBUG(4, "               tx_status %02x.\n", tx_stat);
+    
+    if (rx_stat || (inb(ioaddr + RX_MODE) & F_BUF_EMP) == 0) {
+	/* there is packet(s) in rx buffer */
+	fjn_rx(dev);
+    }
+    if (tx_stat & F_TMT_RDY) {
+	lp->stats.tx_packets += lp->sent ;
+        lp->sent = 0 ;
+	if (lp->tx_queue) {
+	    outb(DO_TX | lp->tx_queue, ioaddr + TX_START);
+	    lp->sent = lp->tx_queue ;
+	    lp->tx_queue = 0;
+	    lp->tx_queue_len = 0;
+	    dev->trans_start = jiffies;
+	} else {
+	    lp->tx_started = 0;
+	}
+	netif_wake_queue(dev);
+    }
+    DEBUG(4, "%s: exiting interrupt,\n", dev->name);
+    DEBUG(4, "    tx_status %02x, rx_status %02x.\n", tx_stat, rx_stat);
+
+    outb(D_TX_INTR, ioaddr + TX_INTR);
+    outb(D_RX_INTR, ioaddr + RX_INTR);
+
+} /* fjn_interrupt */
+
+/*====================================================================*/
+
+static void fjn_tx_timeout(struct net_device *dev)
+{
+    struct local_info_t *lp = (struct local_info_t *)dev->priv;
+    ioaddr_t ioaddr = dev->base_addr;
+
+    printk(KERN_NOTICE "%s: transmit timed out with status %04x, %s?\n",
+	   dev->name, htons(inw(ioaddr + TX_STATUS)),
+	   inb(ioaddr + TX_STATUS) & F_TMT_RDY
+	   ? "IRQ conflict" : "network cable problem");
+    printk(KERN_NOTICE "%s: timeout registers: %04x %04x %04x "
+	   "%04x %04x %04x %04x %04x.\n",
+	   dev->name, htons(inw(ioaddr + 0)),
+	   htons(inw(ioaddr + 2)), htons(inw(ioaddr + 4)),
+	   htons(inw(ioaddr + 6)), htons(inw(ioaddr + 8)),
+	   htons(inw(ioaddr +10)), htons(inw(ioaddr +12)),
+	   htons(inw(ioaddr +14)));
+    lp->stats.tx_errors++;
+    /* ToDo: We should try to restart the adaptor... */
+    cli();
+
+    fjn_reset(dev);
+
+    lp->tx_started = 0;
+    lp->tx_queue = 0;
+    lp->tx_queue_len = 0;
+    lp->sent = 0;
+    lp->open_time = jiffies;
+    sti();
+    netif_start_queue(dev);
+}
+
+static int fjn_start_xmit(struct sk_buff *skb, struct net_device *dev)
+{
+    struct local_info_t *lp = (struct local_info_t *)dev->priv;
+    ioaddr_t ioaddr = dev->base_addr;
+
+    tx_timeout_check(dev, fjn_tx_timeout);
+    skb_tx_check(dev, skb);
+
+    {
+	short length = ETH_ZLEN < skb->len ? skb->len : ETH_ZLEN;
+	unsigned char *buf = skb->data;
+
+	if (length > ETH_FRAME_LEN) {
+	    printk(KERN_NOTICE "%s: Attempting to send a large packet"
+		   " (%d bytes).\n", dev->name, length);
+	    return 1;
+	}
+
+	DEBUG(4, "%s: Transmitting a packet of length %lu.\n",
+	      dev->name, (unsigned long)skb->len);
+	add_tx_bytes(&lp->stats, skb->len);
+
+	/* Disable both interrupts. */
+	outw(0x0000, ioaddr + TX_INTR);
+
+	/* wait for a while */
+	udelay(1);
+
+	outw(length, ioaddr + DATAPORT);
+	outsw_ns(ioaddr + DATAPORT, buf, (length + 1) >> 1);
+
+	lp->tx_queue++;
+	lp->tx_queue_len += ((length+3) & ~1);
+
+	if (lp->tx_started == 0) {
+	    /* If the Tx is idle, always trigger a transmit. */
+	    outb(DO_TX | lp->tx_queue, ioaddr + TX_START);
+	    lp->sent = lp->tx_queue ;
+	    lp->tx_queue = 0;
+	    lp->tx_queue_len = 0;
+	    dev->trans_start = jiffies;
+	    lp->tx_started = 1;
+	    netif_start_queue(dev);
+	} else {
+	    if( sram_config == 0 ) {
+		if (lp->tx_queue_len < (4096 - (ETH_FRAME_LEN +2)) )
+		    /* Yes, there is room for one more packet. */
+		    netif_start_queue(dev);
+	    } else {
+		if (lp->tx_queue_len < (8192 - (ETH_FRAME_LEN +2)) && 
+						lp->tx_queue < 127 )
+		    /* Yes, there is room for one more packet. */
+		    netif_start_queue(dev);
+	    }
+	}
+
+	/* Re-enable interrupts */
+	outb(D_TX_INTR, ioaddr + TX_INTR);
+	outb(D_RX_INTR, ioaddr + RX_INTR);
+    }
+    DEV_KFREE_SKB (skb);
+
+    return 0;
+} /* fjn_start_xmit */
+
+/*====================================================================*/
+
+static void fjn_reset(struct net_device *dev)
+{
+    struct local_info_t *lp = (struct local_info_t *)dev->priv;
+    ioaddr_t ioaddr = dev->base_addr;
+    int i;
+
+    DEBUG(4, "fjn_reset(%s) called.\n",dev->name);
+
+    /* Power On chip and select bank 0 */
+    outb(BANK_0, ioaddr + CONFIG_1);
+    /* Reset buffers */
+    if( sram_config == 0 ) 
+	outb(CONFIG0_RST, ioaddr + CONFIG_0);
+    else
+	outb(CONFIG0_RST_1, ioaddr + CONFIG_0);
+
+    /* Set Tx modes */
+    outb(D_TX_MODE, ioaddr + TX_MODE);
+    /* set Rx modes */
+    outb(ID_MATCHED, ioaddr + RX_MODE);
+
+    /* Set hardware address */
+    for (i = 0; i < 6; i++) 
+        outb(dev->dev_addr[i], ioaddr + NODE_ID + i);
+
+    /* Switch to bank 1 */
+    outb(BANK_1, ioaddr + CONFIG_1);
+
+    /* set the multicast table to accept none. */
+    for (i = 0; i < 6; i++) 
+        outb(0x00, ioaddr + MAR_ADR + i);
+
+    /* Switch to bank 2 (runtime mode) */
+    outb(BANK_2, ioaddr + CONFIG_1);
+
+    /* set 16col ctrl bits */
+    if( lp->cardtype == TDK ) 
+        outb(TDK_AUTO_MODE, ioaddr + COL_CTRL);
+    else
+        outb(AUTO_MODE, ioaddr + COL_CTRL);
+
+    /* clear Reserved Regs */
+    outb(0x00, ioaddr + BMPR12);
+    outb(0x00, ioaddr + BMPR13);
+
+    /* reset Skip packet reg. */
+    outb(0x01, ioaddr + RX_SKIP);
+
+    /* Enable Tx and Rx */
+    if( sram_config == 0 )
+	outb(CONFIG0_DFL, ioaddr + CONFIG_0);
+    else
+	outb(CONFIG0_DFL_1, ioaddr + CONFIG_0);
+
+    /* Init receive pointer ? */
+    inw(ioaddr + DATAPORT);
+    inw(ioaddr + DATAPORT);
+
+    /* Clear all status */
+    outb(0xff, ioaddr + TX_STATUS);
+    outb(0xff, ioaddr + RX_STATUS);
+
+    if( lp->cardtype != TDK ) 
+    		outb(INTR_OFF, ioaddr + LAN_CTRL);
+
+    /* Turn on Rx interrupts */
+    outb(D_TX_INTR, ioaddr + TX_INTR);
+    outb(D_RX_INTR, ioaddr + RX_INTR);
+
+    /* Turn on interrupts from LAN card controler */
+    if( lp->cardtype != TDK ) 
+		outb(INTR_ON, ioaddr + LAN_CTRL);
+} /* fjn_reset */
+
+/*====================================================================*/
+
+static void fjn_rx(struct net_device *dev)
+{
+    struct local_info_t *lp = (struct local_info_t *)dev->priv;
+    ioaddr_t ioaddr = dev->base_addr;
+    int boguscount = 10;	/* 5 -> 10: by agy 19940922 */
+
+    DEBUG(4, "%s: in rx_packet(), rx_status %02x.\n",
+	  dev->name, inb(ioaddr + RX_STATUS));
+
+    while ((inb(ioaddr + RX_MODE) & F_BUF_EMP) == 0) {
+	u_short status = inw(ioaddr + DATAPORT);
+
+	DEBUG(4, "%s: Rxing packet mode %02x status %04x.\n",
+	      dev->name, inb(ioaddr + RX_MODE), status);
+#ifndef final_version
+	if (status == 0) {
+	    outb(F_SKP_PKT, ioaddr + RX_SKIP);
+	    break;
+	}
+#endif
+	if ((status & 0xF0) != 0x20) {	/* There was an error. */
+	    lp->stats.rx_errors++;
+	    if (status & F_LEN_ERR) lp->stats.rx_length_errors++;
+	    if (status & F_ALG_ERR) lp->stats.rx_frame_errors++;
+	    if (status & F_CRC_ERR) lp->stats.rx_crc_errors++;
+	    if (status & F_OVR_FLO) lp->stats.rx_over_errors++;
+	} else {
+	    u_short pkt_len = inw(ioaddr + DATAPORT);
+	    /* Malloc up new buffer. */
+	    struct sk_buff *skb;
+
+	    if (pkt_len > 1550) {
+		printk(KERN_NOTICE "%s: The FMV-18x claimed a very "
+		       "large packet, size %d.\n", dev->name, pkt_len);
+		outb(F_SKP_PKT, ioaddr + RX_SKIP);
+		lp->stats.rx_errors++;
+		break;
+	    }
+	    skb = dev_alloc_skb(pkt_len+2);
+	    if (skb == NULL) {
+		printk(KERN_NOTICE "%s: Memory squeeze, dropping "
+		       "packet (len %d).\n", dev->name, pkt_len);
+		outb(F_SKP_PKT, ioaddr + RX_SKIP);
+		lp->stats.rx_dropped++;
+		break;
+	    }
+	    skb->dev = dev;
+
+	    skb_reserve(skb, 2);
+	    insw_ns(ioaddr + DATAPORT, skb_put(skb, pkt_len),
+		    (pkt_len + 1) >> 1);
+	    skb->protocol = eth_type_trans(skb, dev);
+
+#ifdef PCMCIA_DEBUG
+	    if (pc_debug > 5) {
+		int i;
+		printk(KERN_DEBUG "%s: Rxed packet of length %d: ",
+		       dev->name, pkt_len);
+		for (i = 0; i < 14; i++)
+		    printk(" %02x", skb->data[i]);
+		printk(".\n");
+	    }
+#endif
+
+	    netif_rx(skb);
+	    lp->stats.rx_packets++;
+	    add_rx_bytes(&lp->stats, skb->len);
+	}
+	if (--boguscount <= 0)
+	    break;
+    }
+
+    /* If any worth-while packets have been received, dev_rint()
+	   has done a netif_wake_queue() for us and will work on them
+	   when we get to the bottom-half routine. */
+/*
+    if( lp->cardtype != TDK ) {
+	int i;
+	for (i = 0; i < 20; i++) {
+	    if ((inb(ioaddr + RX_MODE) & F_BUF_EMP) == F_BUF_EMP)
+		break;
+	    (void)inw(ioaddr + DATAPORT);  /+ dummy status read +/
+	    outb(F_SKP_PKT, ioaddr + RX_SKIP);
+	}
+
+	if (i > 0)
+	    DEBUG(5, "%s: Exint Rx packet with mode %02x after "
+		  "%d ticks.\n", dev->name, inb(ioaddr + RX_MODE), i);
+    }
+*/
+
+    return;
+} /* fjn_rx */
+
+/*====================================================================*/
+
+static int fjn_config(struct net_device *dev, struct ifmap *map){
+    return 0;
+}
+
+static int fjn_open(struct net_device *dev)
+{
+    struct local_info_t *lp = (struct local_info_t *)dev->priv;
+    dev_link_t *link = &lp->link;
+
+    DEBUG(4, "fjn_open('%s').\n", dev->name);
+
+    if (!DEV_OK(link))
+	return -ENODEV;
+    
+    link->open++;
+    
+    fjn_reset(dev);
+    
+    lp->tx_started = 0;
+    lp->tx_queue = 0;
+    lp->tx_queue_len = 0;
+    lp->open_time = jiffies;
+    netif_mark_up(dev);
+    netif_start_queue(dev);
+    
+    MOD_INC_USE_COUNT;
+
+    return 0;
+} /* fjn_open */
+
+/*====================================================================*/
+
+static int fjn_close(struct net_device *dev)
+{
+    struct local_info_t *lp = (struct local_info_t *)dev->priv;
+    dev_link_t *link = &lp->link;
+    ioaddr_t ioaddr = dev->base_addr;
+
+    DEBUG(4, "fjn_close('%s').\n", dev->name);
+
+    lp->open_time = 0;
+    netif_stop_queue(dev);
+    netif_mark_down(dev);
+
+    /* Set configuration register 0 to disable Tx and Rx. */
+    if( sram_config == 0 ) 
+	outb(CONFIG0_RST ,ioaddr + CONFIG_0);
+    else
+	outb(CONFIG0_RST_1 ,ioaddr + CONFIG_0);
+
+    /* Update the statistics -- ToDo. */
+
+    /* Power-down the chip.  Green, green, green! */
+    outb(CHIP_OFF ,ioaddr + CONFIG_1);
+
+    /* Set the ethernet adaptor disable IRQ */
+    if( lp->cardtype != TDK ) 
+	outb(INTR_OFF, ioaddr + LAN_CTRL);
+
+    link->open--;
+    if (link->state & DEV_STALE_CONFIG)
+	mod_timer(&link->release, jiffies + HZ/20);
+    MOD_DEC_USE_COUNT;
+
+    return 0;
+} /* fjn_close */
+
+/*====================================================================*/
+
+static struct net_device_stats *fjn_get_stats(struct net_device *dev)
+{
+    local_info_t *lp = (local_info_t *)dev->priv;
+    return &lp->stats;
+} /* fjn_get_stats */
+
+/*====================================================================*/
+
+/*
+  Set the multicast/promiscuous mode for this adaptor.
+*/
+
+/* The little-endian AUTODIN II ethernet CRC calculation.
+   N.B. Do not use for bulk data, use a table-based routine instead.
+   This is common code and should be moved to net/core/crc.c */
+static unsigned const ethernet_polynomial_le = 0xedb88320U;
+static inline unsigned ether_crc_le(int length, unsigned char *data)
+{
+    unsigned int crc = 0xffffffff;	/* Initial value. */
+    while(--length >= 0) {
+	unsigned char current_octet = *data++;
+	int bit;
+	for (bit = 8; --bit >= 0; current_octet >>= 1) {
+	    if ((crc ^ current_octet) & 1) {
+		crc >>= 1;
+		crc ^= ethernet_polynomial_le;
+	    } else
+		crc >>= 1;
+	}
+    }
+    return crc;
+}
+
+static void set_rx_mode(struct net_device *dev)
+{
+    ioaddr_t ioaddr = dev->base_addr;
+    struct local_info_t *lp = (struct local_info_t *)dev->priv;
+    unsigned char mc_filter[8];		 /* Multicast hash filter */
+    long flags;
+    int i;
+    
+    if (dev->flags & IFF_PROMISC) {
+	/* Unconditionally log net taps. */
+	printk("%s: Promiscuous mode enabled.\n", dev->name);
+	memset(mc_filter, 0xff, sizeof(mc_filter));
+	outb(3, ioaddr + RX_MODE);	/* Enable promiscuous mode */
+    } else if (dev->mc_count > MC_FILTERBREAK
+	       ||  (dev->flags & IFF_ALLMULTI)) {
+	/* Too many to filter perfectly -- accept all multicasts. */
+	memset(mc_filter, 0xff, sizeof(mc_filter));
+	outb(2, ioaddr + RX_MODE);	/* Use normal mode. */
+    } else if (dev->mc_count == 0) {
+	memset(mc_filter, 0x00, sizeof(mc_filter));
+	outb(1, ioaddr + RX_MODE);	/* Ignore almost all multicasts. */
+    } else {
+	struct dev_mc_list *mclist;
+	int i;
+	
+	memset(mc_filter, 0, sizeof(mc_filter));
+	for (i = 0, mclist = dev->mc_list; mclist && i < dev->mc_count;
+	     i++, mclist = mclist->next)
+	    set_bit(ether_crc_le(ETH_ALEN, mclist->dmi_addr) & 0x3f,
+		    mc_filter);
+    }
+    
+    save_flags(flags);
+    cli();
+    if (memcmp(mc_filter, lp->mc_filter, sizeof(mc_filter))) {
+	int saved_bank = inb(ioaddr + CONFIG_1);
+	/* Switch to bank 1 and set the multicast table. */
+	outb(0xe4, ioaddr + CONFIG_1);
+	for (i = 0; i < 8; i++)
+	    outb(mc_filter[i], ioaddr + 8 + i);
+	memcpy(lp->mc_filter, mc_filter, sizeof(mc_filter));
+	outb(saved_bank, ioaddr + CONFIG_1);
+    }
+    restore_flags(flags);
+}
Index: oldkernel/linux/pcmcia-cs-3.1.15/clients/ftl_cs.c
diff -u /dev/null linux/pcmcia-cs-3.1.15/clients/ftl_cs.c:1.1
--- /dev/null	Mon Jul 31 21:15:10 2000
+++ linux/pcmcia-cs-3.1.15/clients/ftl_cs.c	Fri Jul  7 16:34:58 2000
@@ -0,0 +1,1587 @@
+/*======================================================================
+
+    A Flash Translation Layer memory card driver
+
+    This driver implements a disk-like block device driver with an
+    apparent block size of 512 bytes for flash memory cards.
+
+    ftl_cs.c 1.65 2000/05/16 21:31:37
+
+    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@pcmcia.sourceforge.org>.  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.
+
+    LEGAL NOTE: The FTL format is patented by M-Systems.  They have
+    granted a license for its use with PCMCIA devices:
+
+     "M-Systems grants a royalty-free, non-exclusive license under
+      any presently existing M-Systems intellectual property rights
+      necessary for the design and development of FTL-compatible
+      drivers, file systems and utilities using the data formats with
+      PCMCIA PC Cards as described in the PCMCIA Flash Translation
+      Layer (FTL) Specification."
+
+    Use of the FTL format for non-PCMCIA applications may be an
+    infringement of these patents.  For additional information,
+    contact M-Systems (http://www.m-sys.com) directly.
+      
+======================================================================*/
+
+#include <pcmcia/config.h>
+#include <pcmcia/k_compat.h>
+
+/* #define PSYCHO_DEBUG */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/sched.h>
+#include <linux/ptrace.h>
+#include <linux/malloc.h>
+#include <linux/string.h>
+#include <linux/timer.h>
+#include <linux/major.h>
+#include <linux/fs.h>
+#include <linux/ioctl.h>
+#include <linux/hdreg.h>
+#include <asm/io.h>
+#include <asm/system.h>
+#include <asm/segment.h>
+#include <asm/uaccess.h>
+#include <stdarg.h>
+
+#if (LINUX_VERSION_CODE >= VERSION(2,1,0))
+#include <linux/vmalloc.h>
+#endif
+#if (LINUX_VERSION_CODE >= VERSION(2,3,3))
+#include <linux/blkpg.h>
+#endif
+
+#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>
+#include <pcmcia/ftl.h>
+
+/*====================================================================*/
+
+/* Parameters that can be set with 'insmod' */
+
+/* Major device # for FTL device */
+static int major_dev = 0;
+
+static int shuffle_freq = 50;
+
+MODULE_PARM(major_dev, "i");
+MODULE_PARM(shuffle_freq, "i");
+
+/*====================================================================*/
+
+/* Funky stuff for setting up a block device */
+#define MAJOR_NR		major_dev
+#define DEVICE_NAME		"ftl"
+#define DEVICE_REQUEST		do_ftl_request
+#define DEVICE_ON(device)
+#define DEVICE_OFF(device)
+
+#define DEVICE_NR(minor)	((minor)>>5)
+#define REGION_NR(minor)	(((minor)>>3)&3)
+#define PART_NR(minor)		((minor)&7)
+#define MINOR_NR(dev,reg,part)	(((dev)<<5)+((reg)<<3)+(part))
+
+#include <linux/blk.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 =
+"ftl_cs.c 1.65 2000/05/16 21:31:37 (David Hinds)";
+#else
+#define DEBUG(n, args...)
+#endif
+
+/*====================================================================*/
+
+/* Maximum number of separate memory devices we'll allow */
+#define MAX_DEV		4
+
+/* Maximum number of regions per device */
+#define MAX_REGION	4
+
+/* Maximum number of partitions in an FTL region */
+#define PART_BITS	3
+#define MAX_PART	8
+
+/* Maximum number of outstanding erase requests per socket */
+#define MAX_ERASE	8
+
+/* Sector size -- shouldn't need to change */
+#define SECTOR_SIZE	512
+
+static void ftl_config(dev_link_t *link);
+static void ftl_release(u_long arg);
+static int ftl_event(event_t event, int priority,
+		     event_callback_args_t *args);
+
+static dev_link_t *ftl_attach(void);
+static void ftl_detach(dev_link_t *);
+
+/* Each memory region corresponds to a minor device */
+typedef struct partition_t {
+    dev_node_t		dev;
+    u_int		state;
+    u_int		*VirtualBlockMap;
+    u_int		*VirtualPageMap;
+    u_int		FreeTotal;
+    struct eun_info_t {
+	u_int			Offset;
+	u_int			EraseCount;
+	u_int			Free;
+	u_int			Deleted;
+    } *EUNInfo;
+    struct xfer_info_t {
+	u_int			Offset;
+	u_int			EraseCount;
+	u_short			state;
+    } *XferInfo;
+    u_short		bam_index;
+    u_int		*bam_cache;
+    u_short		DataUnits;
+    u_int		BlocksPerUnit;
+    erase_unit_header_t	header;
+    region_info_t	region;
+    memory_handle_t	handle;
+    int			open;
+    int			locked;
+} partition_t;
+
+/* Partition state flags */
+#define FTL_FORMATTED	0x01
+
+/* Transfer unit states */
+#define XFER_UNKNOWN	0x00
+#define XFER_ERASING	0x01
+#define XFER_ERASED	0x02
+#define XFER_PREPARED	0x03
+#define XFER_FAILED	0x04
+
+typedef struct ftl_dev_t {
+    dev_link_t		link;
+    eraseq_handle_t	eraseq_handle;
+    eraseq_entry_t	eraseq[MAX_ERASE];
+    wait_queue_head_t	erase_pending;
+    partition_t		minor[CISTPL_MAX_DEVICES];
+} ftl_dev_t;
+
+static dev_info_t dev_info = "ftl_cs";
+static dev_link_t *dev_table[MAX_DEV] = { NULL, /* ... */ };
+
+static struct hd_struct ftl_hd[MINOR_NR(MAX_DEV, 0, 0)];
+static int ftl_sizes[MINOR_NR(MAX_DEV, 0, 0)];
+static int ftl_blocksizes[MINOR_NR(MAX_DEV, 0, 0)];
+
+static wait_queue_head_t ftl_wait_open;
+
+static struct gendisk ftl_gendisk = {
+    major:		0,
+    major_name:		"ftl",
+    minor_shift:	PART_BITS,
+    max_p:		MAX_PART,
+#if (LINUX_VERSION_CODE < VERSION(2,3,40))
+    max_nr:		MAX_DEV*MAX_PART,
+#endif
+    part:		ftl_hd,
+    sizes:		ftl_sizes,
+    nr_real:		MAX_DEV*MAX_PART
+};
+
+/*====================================================================*/
+
+static int ftl_ioctl(struct inode *inode, struct file *file,
+		     u_int cmd, u_long arg);
+static int ftl_open(struct inode *inode, struct file *file);
+static FS_RELEASE_T ftl_close(struct inode *inode, struct file *file);
+static int ftl_reread_partitions(int minor);
+
+static struct block_device_operations ftl_blk_fops = {
+    open:	ftl_open,
+    release:	ftl_close,
+    ioctl:	ftl_ioctl,
+#ifdef block_device_operations
+    read:	block_read,
+    write:	block_write,
+    fsync:	block_fsync
+#endif
+};
+
+/*====================================================================*/
+
+static void cs_error(int func, int ret)
+{
+    int i;
+    error_info_t err = { func, ret };
+    
+    for (i = 0; i < MAX_DEV; i++)
+	if (dev_table[i] != NULL) break;
+    CardServices(ReportError, dev_table[i]->handle, &err);
+}
+
+/*======================================================================
+
+    ftl_attach() creates an "instance" of the driver, allocating
+    local data structures for one device.  The device is registered
+    with Card Services.
+
+======================================================================*/
+
+static dev_link_t *ftl_attach(void)
+{
+    client_reg_t client_reg;
+    dev_link_t *link;
+    ftl_dev_t *dev;
+    eraseq_hdr_t eraseq_hdr;
+    int i, ret;
+    
+    DEBUG(0, "ftl_cs: ftl_attach()\n");
+
+    for (i = 0; i < MAX_DEV; i++)
+	if (dev_table[i] == NULL) break;
+    if (i == MAX_DEV) {
+	printk(KERN_NOTICE "ftl_cs: no devices available\n");
+	return NULL;
+    }
+    
+    /* Create new memory card device */
+    dev = kmalloc(sizeof(*dev), GFP_KERNEL);
+    if (!dev) return NULL;
+    memset(dev, 0, sizeof(*dev));
+    link = &dev->link; link->priv = dev;
+
+    link->release.function = &ftl_release;
+    link->release.data = (u_long)link;
+    dev_table[i] = link;
+    init_waitqueue_head(&dev->erase_pending);
+
+    /* Register with Card Services */
+    client_reg.dev_info = &dev_info;
+    client_reg.Attributes = INFO_IO_CLIENT | INFO_CARD_SHARE;
+    client_reg.EventMask =
+	CS_EVENT_RESET_PHYSICAL | CS_EVENT_CARD_RESET |
+	CS_EVENT_CARD_INSERTION | CS_EVENT_CARD_REMOVAL |
+	CS_EVENT_PM_SUSPEND | CS_EVENT_PM_RESUME;
+    client_reg.event_handler = &ftl_event;
+    client_reg.Version = 0x0210;
+    client_reg.event_callback_args.client_data = link;
+    ret = CardServices(RegisterClient, &link->handle, &client_reg);
+    if (ret != CS_SUCCESS) {
+	cs_error(RegisterClient, ret);
+	ftl_detach(link);
+	return NULL;
+    }
+
+    for (i = 0; i < MAX_ERASE; i++)
+	dev->eraseq[i].State = ERASE_IDLE;
+    eraseq_hdr.QueueEntryCnt = MAX_ERASE;
+    eraseq_hdr.QueueEntryArray = dev->eraseq;
+    dev->eraseq_handle = (void *)link->handle;
+    ret = CardServices(RegisterEraseQueue, &dev->eraseq_handle, &eraseq_hdr);
+    if (ret != CS_SUCCESS) {
+	cs_error(RegisterEraseQueue, ret);
+	dev->eraseq_handle = NULL;
+	ftl_detach(link);
+	return NULL;
+    }
+    
+    return link;
+} /* ftl_attach */
+
+/*======================================================================
+
+    This deletes a driver "instance".  The device is de-registered
+    with Card Services.  If it has been released, all local data
+    structures are freed.  Otherwise, the structures will be freed
+    when the device is released.
+
+======================================================================*/
+
+static void ftl_detach(dev_link_t *link)
+{
+    ftl_dev_t *dev = link->priv;
+    int i;
+
+    DEBUG(0, "ftl_cs: ftl_detach(0x%p)\n", link);
+    
+    /* Locate device structure */
+    for (i = 0; i < MAX_DEV; i++)
+	if (dev_table[i] == link) break;
+    if (i == MAX_DEV)
+	return;
+
+    del_timer(&link->release);
+    if (link->state & DEV_CONFIG) {
+	ftl_release((u_long)link);
+	if (link->state & DEV_STALE_CONFIG) {
+	    link->state |= DEV_STALE_LINK;
+	    return;
+	}
+    }
+
+    if (dev->eraseq_handle)
+	CardServices(DeregisterEraseQueue, dev->eraseq_handle);
+    if (link->handle)
+	CardServices(DeregisterClient, link->handle);
+    
+    /* Unlink device structure, free bits */
+    dev_table[i] = NULL;
+    kfree(dev);
+    
+} /* ftl_detach */
+
+/*======================================================================
+
+    ftl_config() is scheduled to run after a CARD_INSERTION event
+    is received, to configure the PCMCIA socket, and to make the
+    ethernet device available to the system.
+    
+======================================================================*/
+
+static void ftl_config(dev_link_t *link)
+{
+    ftl_dev_t *dev = link->priv;
+    partition_t *minor;
+    region_info_t region;
+    dev_node_t **tail;
+    int i, ret, nr;
+
+    DEBUG(0, "ftl_cs: ftl_config(0x%p)\n", link);
+
+    /* Configure card */
+    link->state |= DEV_CONFIG;
+
+    for (i = 0; i < MAX_DEV; i++)
+	if (dev_table[i] == link) break;
+    tail = &link->dev;
+    minor = dev->minor;
+    nr = 0;
+    region.Attributes = REGION_TYPE_CM;
+    ret = CardServices(GetFirstRegion, link->handle, &region);
+    while (ret == CS_SUCCESS) {
+	minor->region = region;
+	sprintf(minor->dev.dev_name, "ftl%dc%d", i, nr);
+	minor->dev.major = major_dev;
+	minor->dev.minor = MINOR_NR(i, nr, 0);
+	*tail = &minor->dev; tail = &minor->dev.next;
+	minor++; nr++;
+	ret = CardServices(GetNextRegion, link->handle, &region);
+    }
+    *tail = NULL;
+    
+    link->state &= ~DEV_CONFIG_PENDING;
+    
+    if (nr == 0)
+	printk(KERN_NOTICE "ftl_cs: no regions found!\n");
+    else {
+	printk(KERN_INFO "ftl_cs: ftl%d:", i);
+	minor = dev->minor;
+	for (i = 0; i < nr; i++) {
+	    if (minor[i].region.RegionSize & 0xfffff)
+		printk(" %u kb", minor[i].region.RegionSize >> 10);
+	    else
+		printk(" %u mb", minor[i].region.RegionSize >> 20);
+	}
+	printk("\n");
+    }
+    
+} /* ftl_config */
+
+/*======================================================================
+
+    After a card is removed, ftl_release() will unregister the 
+    device, and release the PCMCIA configuration.  If the device is
+    still open, this will be postponed until it is closed.
+    
+======================================================================*/
+
+static void ftl_release(u_long arg)
+{
+    dev_link_t *link = (dev_link_t *)arg;
+    int i;
+    
+    DEBUG(0, "ftl_cs: ftl_release(0x%p)\n", link);
+
+    for (i = 0; i < MAX_DEV; i++)
+	if (dev_table[i] == link) break;
+    if (link->open) {
+	DEBUG(1, "ftl_cs: release postponed, ftl%d still open\n", i);
+	link->state |= DEV_STALE_CONFIG;
+	return;
+    }
+
+    link->dev = NULL;
+    if (link->win)
+	CardServices(ReleaseWindow, link->win);
+    link->state &= ~DEV_CONFIG;
+    
+    if (link->state & DEV_STALE_LINK)
+	ftl_detach(link);
+    
+} /* ftl_release */
+
+/*======================================================================
+
+    The card status event handler.  Mostly, this schedules other
+    stuff to run after an event is received.
+    
+======================================================================*/
+
+static void save_status(eraseq_entry_t *erase);
+
+static int ftl_event(event_t event, int priority,
+		     event_callback_args_t *args)
+{
+    dev_link_t *link = args->client_data;
+    ftl_dev_t *dev = link->priv;
+
+    DEBUG(1, "ftl_cs: ftl_event()\n");
+    
+    switch (event) {
+    case CS_EVENT_CARD_REMOVAL:
+	link->state &= ~DEV_PRESENT;
+	if (link->state & DEV_CONFIG)
+	    mod_timer(&link->release, jiffies + HZ/20);
+	break;
+    case CS_EVENT_CARD_INSERTION:
+	link->state |= DEV_PRESENT | DEV_CONFIG_PENDING;
+	ftl_config(link);
+	break;
+    case CS_EVENT_ERASE_COMPLETE:
+	save_status((eraseq_entry_t *)(args->info));
+	wake_up(&dev->erase_pending);
+	break;
+    case CS_EVENT_PM_SUSPEND:
+	link->state |= DEV_SUSPEND;
+	/* Fall through... */
+    case CS_EVENT_RESET_PHYSICAL:
+	/* get_lock(link); */
+	break;
+    case CS_EVENT_PM_RESUME:
+	link->state &= ~DEV_SUSPEND;
+	/* Fall through... */
+    case CS_EVENT_CARD_RESET:
+	/* free_lock(link); */
+	break;
+    }
+    return 0;
+} /* ftl_event */
+
+/*======================================================================
+
+    Scan_header() checks to see if a memory region contains an FTL
+    partition.  build_maps() reads all the erase unit headers, builds
+    the erase unit map, and then builds the virtual page map.
+    
+======================================================================*/
+
+static int scan_header(partition_t *part)
+{
+    erase_unit_header_t header;
+    mem_op_t req;
+    int ret;
+
+    part->header.FormattedSize = 0;
+    /* Search first megabyte for a valid FTL header */
+    req.Attributes = MEM_OP_BUFFER_KERNEL;
+    req.Count = sizeof(header);
+    for (req.Offset = 0;
+	 req.Offset < 0x100000;
+	 req.Offset += part->region.BlockSize) {
+	ret = CardServices(ReadMemory, part->handle, &req, &header);
+	if (ret != CS_SUCCESS) {
+	    cs_error(ReadMemory, ret);
+	    return -1;
+	}
+	if (strcmp(header.DataOrgTuple+3, "FTL100") == 0) break;
+    }
+    if (req.Offset == 0x100000) {
+	printk(KERN_NOTICE "ftl_cs: FTL header not found.\n");
+	return -1;
+    }
+    if ((header.NumEraseUnits > 65536) || (header.BlockSize != 9) ||
+	(header.EraseUnitSize < 10) || (header.EraseUnitSize > 31) ||
+	(header.NumTransferUnits >= header.NumEraseUnits)) {
+	printk(KERN_NOTICE "ftl_cs: FTL header corrupt!\n");
+	return -1;
+    }
+    part->header = header;
+    return 0;
+}
+
+static int build_maps(partition_t *part)
+{
+    erase_unit_header_t header;
+    mem_op_t req;
+    u_short xvalid, xtrans, i;
+    u_int blocks, j;
+    int hdr_ok, ret;
+
+    /* Set up erase unit maps */
+    part->DataUnits = part->header.NumEraseUnits -
+	part->header.NumTransferUnits;
+    part->EUNInfo = kmalloc(part->DataUnits * sizeof(struct eun_info_t),
+			    GFP_KERNEL);
+    if (!part->EUNInfo) return -1;
+    for (i = 0; i < part->DataUnits; i++)
+	part->EUNInfo[i].Offset = 0xffffffff;
+    part->XferInfo =
+	kmalloc(part->header.NumTransferUnits * sizeof(struct xfer_info_t),
+		GFP_KERNEL);
+    if (!part->XferInfo) return -1;
+
+    req.Attributes = MEM_OP_BUFFER_KERNEL;
+    req.Count = sizeof(header);
+    xvalid = xtrans = 0;
+    for (i = 0; i < part->header.NumEraseUnits; i++) {
+	req.Offset = ((i + part->header.FirstPhysicalEUN)
+		      << part->header.EraseUnitSize);
+	ret = CardServices(ReadMemory, part->handle, &req, &header);
+	if (ret != CS_SUCCESS) {
+	    cs_error(ReadMemory, ret);
+	    return -1;
+	}
+	/* Is this a transfer partition? */
+	hdr_ok = (strcmp(header.DataOrgTuple+3, "FTL100") == 0);
+	if (hdr_ok && (header.LogicalEUN < part->DataUnits) &&
+	    (part->EUNInfo[header.LogicalEUN].Offset == 0xffffffff)) {
+	    part->EUNInfo[header.LogicalEUN].Offset = req.Offset;
+	    part->EUNInfo[header.LogicalEUN].EraseCount =
+		header.EraseCount;
+	    xvalid++;
+	} else {
+	    if (xtrans == part->header.NumTransferUnits) {
+		printk(KERN_NOTICE "ftl_cs: format error: too many "
+		       "transfer units!\n");
+		return -1;
+	    }
+	    if (hdr_ok && (header.LogicalEUN == 0xffff)) {
+		part->XferInfo[xtrans].state = XFER_PREPARED;
+		part->XferInfo[xtrans].EraseCount = header.EraseCount;
+	    } else {
+		part->XferInfo[xtrans].state = XFER_UNKNOWN;
+		/* Pick anything reasonable for the erase count */
+		part->XferInfo[xtrans].EraseCount =
+		    part->header.EraseCount;
+	    }
+	    part->XferInfo[xtrans].Offset = req.Offset;
+	    xtrans++;
+	}
+    }
+    /* Check for format trouble */
+    header = part->header;
+    if ((xtrans != header.NumTransferUnits) ||
+	(xvalid+xtrans != header.NumEraseUnits)) {
+	printk(KERN_NOTICE "ftl_cs: format error: erase units "
+	       "don't add up!\n");
+	return -1;
+    }
+    
+    /* Set up virtual page map */
+    blocks = header.FormattedSize >> header.BlockSize;
+    part->VirtualBlockMap = vmalloc(blocks * sizeof(u_int));
+    memset(part->VirtualBlockMap, 0xff, blocks * sizeof(u_int));
+    part->BlocksPerUnit = (1 << header.EraseUnitSize) >> header.BlockSize;
+    req.Count = part->BlocksPerUnit * sizeof(u_int);
+
+    part->bam_cache = kmalloc(part->BlocksPerUnit * sizeof(u_int),
+			      GFP_KERNEL);
+    if (!part->bam_cache) return -1;
+    part->bam_index = 0xffff;
+    part->FreeTotal = 0;
+    for (i = 0; i < part->DataUnits; i++) {
+	part->EUNInfo[i].Free = 0;
+	part->EUNInfo[i].Deleted = 0;
+	req.Offset = part->EUNInfo[i].Offset + header.BAMOffset;
+	ret = CardServices(ReadMemory, part->handle, &req,
+			   part->bam_cache);
+	if (ret != CS_SUCCESS) {
+	    cs_error(ReadMemory, ret);
+	    return -1;
+	}
+	for (j = 0; j < part->BlocksPerUnit; j++) {
+	    if (BLOCK_FREE(part->bam_cache[j])) {
+		part->EUNInfo[i].Free++;
+		part->FreeTotal++;
+	    } else if ((BLOCK_TYPE(part->bam_cache[j]) == BLOCK_DATA) &&
+		     (BLOCK_NUMBER(part->bam_cache[j]) < blocks))
+		part->VirtualBlockMap[BLOCK_NUMBER(part->bam_cache[j])] =
+		    (i << header.EraseUnitSize) + (j << header.BlockSize);
+	    else if (BLOCK_DELETED(part->bam_cache[j]))
+		part->EUNInfo[i].Deleted++;
+	}
+    }
+    
+    return 0;
+    
+} /* build_maps */
+
+/*======================================================================
+
+    Erase_xfer() schedules an asynchronous erase operation for a
+    transfer unit.
+    
+======================================================================*/
+
+static int erase_xfer(ftl_dev_t *dev, partition_t *part,
+		      u_short xfernum)
+{
+    int i, ret;
+    struct xfer_info_t *xfer;
+
+    xfer = &part->XferInfo[xfernum];
+    DEBUG(1, "ftl_cs: erasing xfer unit at 0x%x\n", xfer->Offset);
+    xfer->state = XFER_ERASING;
+    /* Is there a free erase slot? */
+    for (;;) {
+	for (i = 0; i < MAX_ERASE; i++)
+	    if (!ERASE_IN_PROGRESS(dev->eraseq[i].State)) break;
+	if (i < MAX_ERASE) break;
+	DEBUG(0, "ftl_cs: erase queue is full\n");
+	sleep_on(&dev->erase_pending);
+    }
+
+    /* Queue the request */
+    dev->eraseq[i].State = ERASE_QUEUED;
+    dev->eraseq[i].Handle = part->handle;
+    dev->eraseq[i].Offset = xfer->Offset;
+    dev->eraseq[i].Size = part->region.BlockSize;
+    dev->eraseq[i].Optional = part;
+    ret = CardServices(CheckEraseQueue, dev->eraseq_handle);
+    if (ret != CS_SUCCESS) {
+	cs_error(CheckEraseQueue, ret);
+	return -EIO;
+    }
+    xfer->EraseCount++;
+    return ret;
+} /* erase_xfer */
+
+/*======================================================================
+
+    Prepare_xfer() takes a freshly erased transfer unit and gives
+    it an appropriate header.
+    
+======================================================================*/
+
+static void save_status(eraseq_entry_t *erase)
+{
+    partition_t *part;
+    struct xfer_info_t *xfer;
+    int i;
+    
+    /* Look up the transfer unit */
+    part = (partition_t *)(erase->Optional);
+    for (i = 0; i < part->header.NumTransferUnits; i++)
+	if (part->XferInfo[i].Offset == erase->Offset) break;
+    if (i == part->header.NumTransferUnits) {
+	printk(KERN_NOTICE "ftl_cs: internal error: "
+	       "erase lookup failed!\n");
+	return;
+    }
+    xfer = &part->XferInfo[i];
+    if (erase->State == ERASE_PASSED)
+	xfer->state = XFER_ERASED;
+    else {
+	xfer->state = XFER_FAILED;
+	printk(KERN_NOTICE "ftl_cs: erase failed: state = %d\n",
+	       erase->State);
+    }
+}
+
+static void prepare_xfer(partition_t *part, int i)
+{
+    erase_unit_header_t header;
+    mem_op_t req;
+    struct xfer_info_t *xfer;
+    int nbam, ret;
+    u_int ctl;
+
+    xfer = &part->XferInfo[i];
+    xfer->state = XFER_FAILED;
+    
+    DEBUG(1, "ftl_cs: preparing xfer unit at 0x%x\n", xfer->Offset);
+
+    /* Write the transfer unit header */
+    header = part->header;
+    header.LogicalEUN = 0xffff;
+    header.EraseCount = xfer->EraseCount;
+    req.Attributes = MEM_OP_BUFFER_KERNEL;
+    req.Count = sizeof(header);
+    req.Offset = xfer->Offset;
+    ret = CardServices(WriteMemory, part->handle, &req, &header);
+    if (ret != CS_SUCCESS) {
+	cs_error(WriteMemory, ret);
+	return;
+    }
+
+    /* Write the BAM stub */
+    nbam = (part->BlocksPerUnit * sizeof(u_int) +
+	    part->header.BAMOffset + SECTOR_SIZE - 1) / SECTOR_SIZE;
+    req.Offset = xfer->Offset + part->header.BAMOffset;
+    req.Count = sizeof(u_int);
+    ctl = BLOCK_CONTROL;
+    for (i = 0; i < nbam; i++, req.Offset += sizeof(u_int)) {
+	ret = CardServices(WriteMemory, part->handle, &req, &ctl);
+	if (ret != CS_SUCCESS) {
+	    cs_error(WriteMemory, ret);
+	    return;
+	}
+    }
+    xfer->state = XFER_PREPARED;
+    
+} /* prepare_xfer */
+
+/*======================================================================
+
+    Copy_erase_unit() takes a full erase block and a transfer unit,
+    copies everything to the transfer unit, then swaps the block
+    pointers.
+
+    All data blocks are copied to the corresponding blocks in the
+    target unit, so the virtual block map does not need to be
+    updated.
+    
+======================================================================*/
+
+static int copy_erase_unit(partition_t *part, u_short srcunit,
+			   u_short xferunit)
+{
+    u_char buf[SECTOR_SIZE];
+    struct eun_info_t *eun;
+    struct xfer_info_t *xfer;
+    mem_op_t req;
+    u_int src, dest, free, i;
+    u_short unit;
+    int ret;
+
+    eun = &part->EUNInfo[srcunit];
+    xfer = &part->XferInfo[xferunit];
+    DEBUG(2, "ftl_cs: copying block 0x%x to 0x%x\n",
+	  eun->Offset, xfer->Offset);
+	
+    req.Attributes = MEM_OP_BUFFER_KERNEL;
+    
+    /* Read current BAM */
+    if (part->bam_index != srcunit) {
+	req.Offset = eun->Offset + part->header.BAMOffset;
+	req.Count = part->BlocksPerUnit * sizeof(u_int);
+	ret = CardServices(ReadMemory, part->handle, &req, part->bam_cache);
+	/* mark the cache bad, in case we get an error later */
+	part->bam_index = 0xffff;
+	if (ret != CS_SUCCESS) goto read_error;
+    }
+    
+    /* Write the LogicalEUN for the transfer unit */
+    xfer->state = XFER_UNKNOWN;
+    req.Count = sizeof(u_short);
+    req.Offset = xfer->Offset + 20; /* Bad! */
+    unit = 0x7fff;
+    ret = CardServices(WriteMemory, part->handle, &req, &unit);
+    if (ret != CS_SUCCESS) goto write_error;
+    
+    /* Copy all data blocks from source unit to transfer unit */
+    src = eun->Offset; dest = xfer->Offset;
+    req.Count = SECTOR_SIZE;
+    free = 0;
+    ret = 0;
+    for (i = 0; i < part->BlocksPerUnit; i++) {
+	switch (BLOCK_TYPE(part->bam_cache[i])) {
+	case BLOCK_CONTROL:
+	    /* This gets updated later */
+	    break;
+	case BLOCK_DATA:
+	case BLOCK_REPLACEMENT:
+	    req.Offset = src;
+	    ret = CardServices(ReadMemory, part->handle, &req, buf);
+	    if (ret != CS_SUCCESS) goto read_error;
+	    req.Offset = dest;
+	    ret = CardServices(WriteMemory, part->handle, &req, buf);
+	    if (ret != CS_SUCCESS) goto write_error;
+	    break;
+	default:
+	    /* All other blocks must be free */
+	    part->bam_cache[i] = 0xffffffff;
+	    free++;
+	    break;
+	}
+	src += SECTOR_SIZE;
+	dest += SECTOR_SIZE;
+    }
+
+    /* Write the BAM to the transfer unit */
+    req.Offset = xfer->Offset + part->header.BAMOffset;
+    req.Count = part->BlocksPerUnit * sizeof(int);
+    ret = CardServices(WriteMemory, part->handle, &req, part->bam_cache);
+    if (ret != CS_SUCCESS) goto write_error;
+    
+    /* All clear? Then update the LogicalEUN again */
+    req.Offset = xfer->Offset + 20; /* Bad! */
+    req.Count = sizeof(u_short);
+    ret = CardServices(WriteMemory, part->handle, &req, &srcunit);
+    if (ret != CS_SUCCESS) goto write_error;
+
+    /* Update the maps and usage stats*/
+    i = xfer->EraseCount;
+    xfer->EraseCount = eun->EraseCount;
+    eun->EraseCount = i;
+    i = xfer->Offset;
+    xfer->Offset = eun->Offset;
+    eun->Offset = i;
+    part->FreeTotal -= eun->Free;
+    part->FreeTotal += free;
+    eun->Free = free;
+    eun->Deleted = 0;
+    
+    /* Now, the cache should be valid for the new block */
+    part->bam_index = srcunit;
+
+    return CS_SUCCESS;
+    
+read_error:
+    cs_error(ReadMemory, ret);
+    return ret;
+    
+write_error:
+    cs_error(WriteMemory, ret);
+    return ret;
+} /* copy_erase_unit */
+
+/*======================================================================
+
+    reclaim_block() picks a full erase unit and a transfer unit and
+    then calls copy_erase_unit() to copy one to the other.  Then, it
+    schedules an erase on the expired block.
+
+    What's a good way to decide which transfer unit and which erase
+    unit to use?  Beats me.  My way is to always pick the transfer
+    unit with the fewest erases, and usually pick the data unit with
+    the most deleted blocks.  But with a small probability, pick the
+    oldest data unit instead.  This means that we generally postpone
+    the next reclaimation as long as possible, but shuffle static
+    stuff around a bit for wear leveling.
+    
+======================================================================*/
+
+static int reclaim_block(ftl_dev_t *dev, partition_t *part)
+{
+    u_short i, eun, xfer;
+    u_int best;
+    int queued, ret;
+
+    DEBUG(0, "ftl_cs: reclaiming space...\n");
+	
+    /* Pick the least erased transfer unit */
+    best = 0xffffffff; xfer = 0xffff;
+    do {
+	queued = 0;
+	for (i = 0; i < part->header.NumTransferUnits; i++) {
+	    if (part->XferInfo[i].state == XFER_UNKNOWN)
+		erase_xfer(dev, part, i);
+	    if (part->XferInfo[i].state == XFER_ERASING)
+		queued = 1;
+	    else if (part->XferInfo[i].state == XFER_ERASED)
+		prepare_xfer(part, i);
+	    if ((part->XferInfo[i].state == XFER_PREPARED) &&
+		(part->XferInfo[i].EraseCount <= best)) {
+		    best = part->XferInfo[i].EraseCount;
+		    xfer = i;
+		}
+	}
+	if (xfer == 0xffff) {
+	    if (queued) {
+		DEBUG(1, "ftl_cs: waiting for transfer "
+		      "unit to be prepared...\n");
+		sleep_on(&dev->erase_pending);
+	    } else {
+		static int ne = 0;
+		if (++ne < 5)
+		    printk(KERN_NOTICE "ftl_cs: reclaim failed: no "
+			   "suitable transfer units!\n");
+		return CS_GENERAL_FAILURE;
+	    }
+	}
+    } while (xfer == 0xffff);
+
+    eun = 0;
+    if ((jiffies % shuffle_freq) == 0) {
+	DEBUG(1, "ftl_cs: recycling freshest block...\n");
+	best = 0xffffffff;
+	for (i = 0; i < part->DataUnits; i++)
+	    if (part->EUNInfo[i].EraseCount <= best) {
+		best = part->EUNInfo[i].EraseCount;
+		eun = i;
+	    }
+    } else {
+	best = 0;
+	for (i = 0; i < part->DataUnits; i++)
+	    if (part->EUNInfo[i].Deleted >= best) {
+		best = part->EUNInfo[i].Deleted;
+		eun = i;
+	    }
+	if (best == 0) {
+	    static int ne = 0;
+	    if (++ne < 5)
+		printk(KERN_NOTICE "ftl_cs: reclaim failed: "
+		       "no free blocks!\n");
+	    return CS_GENERAL_FAILURE;
+	}
+    }
+    ret = copy_erase_unit(part, eun, xfer);
+    if (ret == CS_SUCCESS)
+	erase_xfer(dev, part, xfer);
+    else
+	printk(KERN_NOTICE "ftl_cs: copy_erase_unit failed!\n");
+    return ret;
+} /* reclaim_block */
+
+/*======================================================================
+
+    Find_free() searches for a free block.  If necessary, it updates
+    the BAM cache for the erase unit containing the free block.  It
+    returns the block index -- the erase unit is just the currently
+    cached unit.  If there are no free blocks, it returns 0 -- this
+    is never a valid data block because it contains the header.
+    
+======================================================================*/
+
+#ifdef PSYCHO_DEBUG
+static void dump_lists(partition_t *part)
+{
+    int i;
+    printk(KERN_DEBUG "ftl_cs: Free total = %d\n", part->FreeTotal);
+    for (i = 0; i < part->DataUnits; i++)
+	printk(KERN_DEBUG "ftl_cs:   unit %d: %d phys, %d free, "
+	       "%d deleted\n", i,
+	       part->EUNInfo[i].Offset >> part->header.EraseUnitSize,
+	       part->EUNInfo[i].Free, part->EUNInfo[i].Deleted);
+}
+#endif
+
+static u_int find_free(partition_t *part)
+{
+    u_short stop, eun;
+    u_int blk;
+    mem_op_t req;
+    int ret;
+    
+    /* Find an erase unit with some free space */
+    stop = (part->bam_index == 0xffff) ? 0 : part->bam_index;
+    eun = stop;
+    do {
+	if (part->EUNInfo[eun].Free != 0) break;
+	/* Wrap around at end of table */
+	if (++eun == part->DataUnits) eun = 0;
+    } while (eun != stop);
+
+    if (part->EUNInfo[eun].Free == 0)
+	return 0;
+    
+    /* Is this unit's BAM cached? */
+    if (eun != part->bam_index) {
+	/* Invalidate cache */
+	part->bam_index = 0xffff;
+	req.Attributes = MEM_OP_BUFFER_KERNEL;
+	req.Count = part->BlocksPerUnit * sizeof(u_int);
+	req.Offset = part->EUNInfo[eun].Offset + part->header.BAMOffset;
+	ret = CardServices(ReadMemory, part->handle, &req,
+			   part->bam_cache);
+	if (ret != CS_SUCCESS) {
+	    cs_error(ReadMemory, ret);
+	    return 0;
+	}
+	part->bam_index = eun;
+    }
+
+    /* Find a free block */
+    for (blk = 0; blk < part->BlocksPerUnit; blk++)
+	if (BLOCK_FREE(part->bam_cache[blk])) break;
+    if (blk == part->BlocksPerUnit) {
+#ifdef PSYCHO_DEBUG
+	static int ne = 0;
+	if (++ne == 1)
+	    dump_lists(part);
+#endif
+	printk(KERN_NOTICE "ftl_cs: bad free list!\n");
+	return 0;
+    }
+    DEBUG(2, "ftl_cs: found free block at %d in %d\n", blk, eun);
+    return blk;
+    
+} /* find_free */
+
+/*======================================================================
+
+    This gets a memory handle for the region corresponding to the
+    minor device number.
+    
+======================================================================*/
+
+static int ftl_open(struct inode *inode, struct file *file)
+{
+    int minor = MINOR(inode->i_rdev);
+    dev_link_t *link;
+    ftl_dev_t *dev;
+    partition_t *partition;
+    open_mem_t open;
+    int ret;
+
+    MOD_INC_USE_COUNT;
+    DEBUG(0, "ftl_cs: ftl_open(%d)\n", minor);
+
+    link = dev_table[DEVICE_NR(minor)];
+    if (!DEV_OK(link))
+	goto failed;
+
+    dev = (ftl_dev_t *)link->priv;
+    partition = &dev->minor[REGION_NR(minor)];
+    if (partition->region.RegionSize == 0)
+	goto failed;
+    while (partition->locked)
+	sleep_on(&ftl_wait_open);
+
+    if (partition->handle == NULL) {
+	partition->handle = (memory_handle_t)link->handle;
+	open.Attributes = partition->region.Attributes;
+	open.Offset = partition->region.CardOffset;
+	ret = CardServices(OpenMemory, &partition->handle, &open);
+	if (ret != CS_SUCCESS) {
+	    cs_error(OpenMemory, ret);
+	    goto failed;
+	}
+	if ((scan_header(partition) == 0) &&
+	    (build_maps(partition) == 0)) {
+	    partition->state = FTL_FORMATTED;
+	    ftl_reread_partitions(minor);
+#ifdef PCMCIA_DEBUG
+	    printk(KERN_INFO "ftl_cs: opening %d kb FTL partition\n",
+		   partition->header.FormattedSize >> 10);
+#endif
+	} else {
+	    CardServices(CloseMemory, partition->handle);
+	    partition->handle = NULL;
+	    printk(KERN_NOTICE "ftl_cs: FTL partition is invalid.\n");
+	    goto failed;
+	}
+    }
+
+    partition->open++;
+    link->open++;
+    return 0;
+failed:
+    MOD_DEC_USE_COUNT;
+    return -ENODEV;
+} /* ftl_open */
+
+/*====================================================================*/
+
+static FS_RELEASE_T ftl_close(struct inode *inode, struct file *file)
+{
+    dev_link_t *link;
+    int minor = MINOR(inode->i_rdev);
+    ftl_dev_t *dev;
+    partition_t *part;
+    int i;
+    
+    DEBUG(0, "ftl_cs: ftl_close(%d)\n", minor);
+
+    /* Flush all writes */
+    fsync_dev(inode->i_rdev);
+    INVALIDATE_INODES(inode->i_rdev);
+    invalidate_buffers(inode->i_rdev);
+    
+    link = dev_table[DEVICE_NR(minor)];
+    dev = (ftl_dev_t *)link->priv;
+    part = &dev->minor[REGION_NR(minor)];
+    
+    /* Wait for any pending erase operations to complete */
+    for (i = 0; i < part->header.NumTransferUnits; i++) {
+	if (part->XferInfo[i].state == XFER_ERASING)
+	    sleep_on(&dev->erase_pending);
+	if (part->XferInfo[i].state == XFER_ERASED)
+	    prepare_xfer(part, i);
+    }
+    
+    link->open--;
+    part->open--;
+    if (part->open == 0) {
+	CardServices(CloseMemory, part->handle);
+	part->handle = NULL;
+	if (part->VirtualBlockMap) {
+	    vfree(part->VirtualBlockMap);
+	    part->VirtualBlockMap = NULL;
+	}
+	if (part->VirtualPageMap) {
+	    kfree(part->VirtualPageMap);
+	    part->VirtualPageMap = NULL;
+	}
+	if (part->EUNInfo) {
+	    kfree(part->EUNInfo);
+	    part->EUNInfo = NULL;
+	}
+	if (part->XferInfo) {
+	    kfree(part->XferInfo);
+	    part->XferInfo = NULL;
+	}
+	if (part->bam_cache) {
+	    kfree(part->bam_cache);
+	    part->bam_cache = NULL;
+	}
+    }
+    
+    MOD_DEC_USE_COUNT;
+    return (FS_RELEASE_T)0;
+} /* ftl_close */
+
+/*======================================================================
+
+    Read a series of sectors from an FTL partition.
+    
+======================================================================*/
+
+static int ftl_read(partition_t *part, caddr_t buffer,
+		    u_long sector, u_long nblocks)
+{
+    mem_op_t req;
+    u_int log_addr, bsize;
+    u_long i;
+    int ret;
+    
+    DEBUG(2, "ftl_cs: ftl_read(0x%p, 0x%lx, %ld)\n",
+	  part->handle, sector, nblocks);
+    if (!(part->state & FTL_FORMATTED)) {
+	printk(KERN_NOTICE "ftl_cs: bad partition\n");
+	return -EIO;
+    }
+    bsize = part->region.BlockSize;
+    req.Attributes = MEM_OP_BUFFER_KERNEL;
+    req.Count = SECTOR_SIZE;
+    for (i = 0; i < nblocks; i++) {
+	if (((sector+i) * SECTOR_SIZE) >= part->header.FormattedSize) {
+	    printk(KERN_NOTICE "ftl_cs: bad read offset\n");
+	    return -EIO;
+	}
+	log_addr = part->VirtualBlockMap[sector+i];
+	if (log_addr == 0xffffffff)
+	    memset(buffer, 0, SECTOR_SIZE);
+	else {
+	    req.Offset = (part->EUNInfo[log_addr / bsize].Offset
+			  + (log_addr % bsize));
+	    ret = CardServices(ReadMemory, part->handle, &req, buffer);
+	    if (ret != CS_SUCCESS) {
+		cs_error(ReadMemory, ret);
+		return -EIO;
+	    }
+	}
+	buffer += SECTOR_SIZE;
+    }
+    return 0;
+} /* ftl_read */
+
+/*======================================================================
+
+    Write a series of sectors to an FTL partition
+    
+======================================================================*/
+
+static int set_bam_entry(partition_t *part, u_int log_addr,
+			 u_int virt_addr)
+{
+    mem_op_t req;
+    u_int bsize, blk;
+#ifdef PSYCHO_DEBUG
+    u_int old_addr;
+#endif
+    u_short eun;
+    int ret;
+    
+    DEBUG(2, "ftl_cs: set_bam_entry(0x%p, 0x%x, 0x%x)\n",
+	  part->handle, log_addr, virt_addr);
+    bsize = part->region.BlockSize;
+    eun = log_addr / bsize;
+    blk = (log_addr % bsize) / SECTOR_SIZE;
+    req.Attributes = MEM_OP_BUFFER_KERNEL;
+    req.Count = sizeof(u_int);
+    req.Offset = (part->EUNInfo[eun].Offset + blk * sizeof(u_int) +
+		  part->header.BAMOffset);
+    
+#ifdef PSYCHO_DEBUG
+    CardServices(ReadMemory, part->handle, &req, &old_addr);
+    if (((virt_addr == 0xfffffffe) && !BLOCK_FREE(old_addr)) ||
+	((virt_addr == 0) && (BLOCK_TYPE(old_addr) != BLOCK_DATA)) ||
+	(!BLOCK_DELETED(virt_addr) && (old_addr != 0xfffffffe))) {
+	static int ne = 0;
+	if (++ne < 5) {
+	    printk(KERN_NOTICE "ftl_cs: set_bam_entry() inconsistency!\n");
+	    printk(KERN_NOTICE "ftl_cs:   log_addr = 0x%x, old = 0x%x"
+		   ", new = 0x%x\n", log_addr, old_addr, virt_addr);
+	}
+	return CS_GENERAL_FAILURE;
+    }
+#endif
+    if (part->bam_index == eun) {
+#ifdef PSYCHO_DEBUG
+	if (part->bam_cache[blk] != old_addr) {
+	    static int ne = 0;
+	    if (++ne < 5) {
+		printk(KERN_NOTICE "ftl_cs: set_bam_entry() "
+		       "inconsistency!\n");
+		printk(KERN_NOTICE "ftl_cs:   log_addr = 0x%x, cache"
+		       " = 0x%x, card = 0x%x\n",
+		       part->bam_cache[blk], old_addr);
+	    }
+	    return CS_GENERAL_FAILURE;
+	}
+#endif
+	part->bam_cache[blk] = virt_addr;
+    }
+
+    ret = CardServices(WriteMemory, part->handle, &req, &virt_addr);
+    if (ret != CS_SUCCESS) {
+	printk(KERN_NOTICE "ftl_cs: set_bam_entry() failed!\n");
+	printk(KERN_NOTICE "ftl_cs:   log_addr = 0x%x, new = 0x%x\n",
+	       log_addr, virt_addr);
+	cs_error(WriteMemory, ret);
+    }
+    return ret;
+} /* set_bam_entry */
+
+static int ftl_write(ftl_dev_t *dev, partition_t *part, caddr_t buffer,
+		     u_long sector, u_long nblocks)
+{
+    mem_op_t req;
+    u_int bsize, log_addr, virt_addr, old_addr, blk;
+    u_long i;
+    int ret;
+
+    DEBUG(2, "ftl_cs: ftl_write(0x%p, %ld, %ld)\n",
+	  part->handle, sector, nblocks);
+    if (!(part->state & FTL_FORMATTED)) {
+	printk(KERN_NOTICE "ftl_cs: bad partition\n");
+	return -EIO;
+    }
+    /* See if we need to reclaim space, before we start */
+    while (part->FreeTotal < nblocks) {
+	ret = reclaim_block(dev, part);
+	if (ret != CS_SUCCESS)
+	    return ret;
+    }
+    
+    bsize = part->region.BlockSize;
+    req.Attributes = MEM_OP_BUFFER_KERNEL;
+    req.Count = SECTOR_SIZE;
+    virt_addr = sector * SECTOR_SIZE | BLOCK_DATA;
+    for (i = 0; i < nblocks; i++) {
+	if (virt_addr >= part->header.FormattedSize) {
+	    printk(KERN_NOTICE "ftl_cs: bad write offset\n");
+	    return -EIO;
+	}
+
+	/* Grab a free block */
+	blk = find_free(part);
+	if (blk == 0) {
+	    static int ne = 0;
+	    if (++ne < 5)
+		printk(KERN_NOTICE "ftl_cs: internal error: "
+		       "no free blocks!\n");
+	    return -ENOSPC;
+	}
+
+	/* Tag the BAM entry, and write the new block */
+	log_addr = part->bam_index * bsize + blk * SECTOR_SIZE;
+	part->EUNInfo[part->bam_index].Free--;
+	part->FreeTotal--;
+	if (set_bam_entry(part, log_addr, 0xfffffffe))
+	    return -EIO;
+	part->EUNInfo[part->bam_index].Deleted++;
+	req.Offset = (part->EUNInfo[part->bam_index].Offset +
+		      blk * SECTOR_SIZE);
+	ret = CardServices(WriteMemory, part->handle, &req, buffer);
+	if (ret != CS_SUCCESS) {
+	    printk(KERN_NOTICE "ftl_cs: block write failed!\n");
+	    printk(KERN_NOTICE "ftl_cs:   log_addr = 0x%x, virt_addr"
+		   " = 0x%x, Offset = 0x%x\n", log_addr, virt_addr,
+		   req.Offset);
+	    cs_error(WriteMemory, ret);
+	    return -EIO;
+	}
+	
+	/* Only delete the old entry when the new entry is ready */
+	old_addr = part->VirtualBlockMap[sector+i];
+	if (old_addr != 0xffffffff) {
+	    part->VirtualBlockMap[sector+i] = 0xffffffff;
+	    part->EUNInfo[old_addr/bsize].Deleted++;
+	    if (set_bam_entry(part, old_addr, 0) != CS_SUCCESS)
+		return -EIO;
+	}
+
+	/* Finally, set up the new pointers */
+	if (set_bam_entry(part, log_addr, virt_addr))
+	    return -EIO;
+	part->VirtualBlockMap[sector+i] = log_addr;
+	part->EUNInfo[part->bam_index].Deleted--;
+	
+	buffer += SECTOR_SIZE;
+	virt_addr += SECTOR_SIZE;
+    }
+    return 0;
+} /* ftl_write */
+
+/*======================================================================
+
+    IOCTL calls for getting device parameters.
+
+======================================================================*/
+
+static int ftl_ioctl(struct inode *inode, struct file *file,
+		     u_int cmd, u_long arg)
+{
+    struct hd_geometry *geo = (struct hd_geometry *)arg;
+    int ret = 0, minor = MINOR(inode->i_rdev);
+    dev_link_t *link;
+    ftl_dev_t *dev;
+    partition_t *part;
+    u_long sect;
+
+    link = dev_table[DEVICE_NR(minor)];
+    if (!DEV_OK(link)) return -ENODEV;
+    dev = (ftl_dev_t *)link->priv;
+    part = &dev->minor[REGION_NR(minor)];
+
+    switch (cmd) {
+    case HDIO_GETGEO:
+	ret = verify_area(VERIFY_WRITE, (long *)arg, sizeof(*geo));
+	if (ret) return ret;
+	/* Sort of arbitrary: round size down to 4K boundary */
+	sect = part->header.FormattedSize/SECTOR_SIZE;
+	put_user(1, (char *)&geo->heads);
+	put_user(8, (char *)&geo->sectors);
+	put_user((sect>>3), (short *)&geo->cylinders);
+	put_user(ftl_hd[minor].start_sect, (u_long *)&geo->start);
+	break;
+    case BLKGETSIZE:
+	ret = verify_area(VERIFY_WRITE, (long *)arg, sizeof(long));
+	if (ret) return ret;
+	put_user(ftl_hd[minor].nr_sects, (long *)arg);
+	break;
+    case BLKRRPART:
+	ret = ftl_reread_partitions(minor);
+	break;
+#if (LINUX_VERSION_CODE < VERSION(2,3,3))
+    case BLKFLSBUF:
+	if (!capable(CAP_SYS_ADMIN)) return -EACCES;
+	fsync_dev(inode->i_rdev);
+	invalidate_buffers(inode->i_rdev);
+	break;
+    RO_IOCTLS(inode->i_rdev, arg);
+#else
+    case BLKROSET:
+    case BLKROGET:
+    case BLKFLSBUF:
+	ret = blk_ioctl(inode->i_rdev, cmd, arg);
+	break;
+#endif
+    default:
+	ret = -EINVAL;
+    }
+
+    return ret;
+} /* ftl_ioctl */
+
+/*======================================================================
+
+    Handler for block device requests
+
+======================================================================*/
+
+static int ftl_reread_partitions(int minor)
+{
+    int d = DEVICE_NR(minor), r = REGION_NR(minor);
+    ftl_dev_t *dev = dev_table[d]->priv;
+    partition_t *part = &(dev->minor[r]);
+    int i, whole;
+
+    DEBUG(0, "ftl_cs: ftl_reread_partition(%d)\n", minor);
+    if (part->locked || (part->open > 1))
+	return -EBUSY;
+    part->locked = 1;
+    
+    whole = minor & ~(MAX_PART-1);
+    for (i = 0; i < MAX_PART; i++) {
+	if (ftl_hd[whole+i].nr_sects > 0) {
+	    kdev_t rdev = MKDEV(major_dev, whole+i);
+	    sync_dev(rdev);
+	    INVALIDATE_INODES(rdev);
+	    invalidate_buffers(rdev);
+	}
+	ftl_hd[whole+i].start_sect = 0;
+	ftl_hd[whole+i].nr_sects = 0;
+    }
+
+    scan_header(part);
+    register_disk(&ftl_gendisk, whole >> PART_BITS, MAX_PART,
+		  &ftl_blk_fops, part->header.FormattedSize/SECTOR_SIZE);
+
+#ifdef PCMCIA_DEBUG
+    for (i = 0; i < MAX_PART; i++) {
+	if (ftl_hd[whole+i].nr_sects > 0)
+	    printk(KERN_INFO "  %d: start %ld size %ld\n", i,
+		   ftl_hd[whole+i].start_sect,
+		   ftl_hd[whole+i].nr_sects);
+    }
+#endif
+    
+    part->locked = 0;
+    wake_up(&ftl_wait_open);
+    return 0;
+}
+
+/*======================================================================
+
+    Handler for block device requests
+
+======================================================================*/
+
+static void do_ftl_request(request_arg_t)
+{
+    int ret, minor;
+    dev_link_t *link;
+    ftl_dev_t *dev;
+    partition_t *part;
+
+    DEBUG(2, "ftl_cs: starting do_ftl_request()\n");
+    
+    do {
+	sti();
+	INIT_REQUEST;
+
+	minor = MINOR(CURRENT->rq_dev);
+	
+	link = dev_table[DEVICE_NR(minor)];
+	dev = (ftl_dev_t *)link->priv;
+	part = &dev->minor[REGION_NR(minor)];
+	ret = 0;
+	
+	switch (CURRENT->cmd) {
+	    
+	case READ:
+	    ret = ftl_read(part, CURRENT->buffer,
+			   CURRENT->sector+ftl_hd[minor].start_sect,
+			   CURRENT->current_nr_sectors);
+	    break;
+	    
+	case WRITE:
+	    ret = ftl_write(dev, part, CURRENT->buffer,
+			    CURRENT->sector+ftl_hd[minor].start_sect,
+			    CURRENT->current_nr_sectors);
+	    break;
+	    
+	default:
+	    panic("ftl_cs: unknown block command!\n");
+	    
+	}
+	end_request((ret == 0) ? 1 : 0);
+    } while (1);
+} /* do_ftl_request */
+
+/*====================================================================*/
+
+static int __init init_ftl_cs(void)
+{
+    servinfo_t serv;
+    int i;
+    
+    DEBUG(0, "%s\n", version);
+    
+    CardServices(GetCardServicesInfo, &serv);
+    if (serv.Revision != CS_RELEASE_CODE) {
+	printk(KERN_NOTICE "ftl_cs: Card Services release "
+	       "does not match!\n");
+	return -1;
+    }
+    
+    register_pccard_driver(&dev_info, &ftl_attach, &ftl_detach);
+
+    major_dev = register_blkdev(major_dev, "ftl", &ftl_blk_fops);
+    if (major_dev == 0) {
+	printk(KERN_NOTICE "ftl_cs: unable to grab major "
+	       "device number!\n");
+	return -ENODEV;
+    }
+
+    for (i = 0; i < MINOR_NR(MAX_DEV, 0, 0); i++)
+	ftl_blocksizes[i] = 1024;
+    for (i = 0; i < MAX_DEV*MAX_PART; i++) {
+	ftl_hd[i].nr_sects = 0;
+	ftl_hd[i].start_sect = 0;
+    }
+    blksize_size[major_dev] = ftl_blocksizes;
+    ftl_gendisk.major = major_dev;
+    blk_init_queue(BLK_DEFAULT_QUEUE(major_dev), &do_ftl_request);
+    ftl_gendisk.next = gendisk_head;
+    gendisk_head = &ftl_gendisk;
+    init_waitqueue_head(&ftl_wait_open);
+    
+    return 0;
+}
+
+static void __exit exit_ftl_cs(void)
+{
+    int i;
+    dev_link_t *link;
+    struct gendisk *gd, **gdp;
+
+    DEBUG(0, "ftl_cs: unloading\n");
+    unregister_pccard_driver(&dev_info);
+    if (major_dev != 0) {
+	unregister_blkdev(major_dev, "ftl");
+	blk_cleanup_queue(BLK_DEFAULT_QUEUE(major_dev));
+	blksize_size[major_dev] = NULL;
+    }
+    for (i = 0; i < MAX_DEV; i++) {
+	link = dev_table[i];
+	if (link) {
+	    if (link->state & DEV_CONFIG)
+		ftl_release((u_long)link);
+	    ftl_detach(link);
+	}
+    }
+    for (gdp = &gendisk_head; *gdp; gdp = &((*gdp)->next))
+	if (*gdp == &ftl_gendisk) {
+	    gd = *gdp; *gdp = gd->next;
+	    break;
+	}
+}
+
+module_init(init_ftl_cs);
+module_exit(exit_ftl_cs);
Index: oldkernel/linux/pcmcia-cs-3.1.15/clients/ibmtr_cs.c
diff -u /dev/null linux/pcmcia-cs-3.1.15/clients/ibmtr_cs.c:1.1
--- /dev/null	Mon Jul 31 21:15:10 2000
+++ linux/pcmcia-cs-3.1.15/clients/ibmtr_cs.c	Fri Jul  7 16:34:58 2000
@@ -0,0 +1,701 @@
+/*======================================================================
+
+    A PCMCIA token-ring driver for IBM-based cards
+
+    This driver supports the IBM PCMCIA Token-Ring Card.
+    Written by Steve Kipisz, kipisz@vnet.ibm.com or
+                             bungy@ibm.net
+
+    Written 1995,1996.
+
+    This code is based on pcnet_cs.c from David Hinds.
+    
+    V2.2.0 February 1999 - Mike Phillips phillim@amtrak.com
+
+    Linux V2.2.x presented significant changes to the underlying
+    ibmtr.c code.  Mainly the code became a lot more organized and
+    modular.
+
+    This caused the old PCMCIA Token Ring driver to give up and go 
+    home early. Instead of just patching the old code to make it 
+    work, the PCMCIA code has been streamlined, updated and possibly
+    improved.
+
+    This code now only contains code required for the Card Services.
+    All we do here is set the card up enough so that the real ibmtr.c
+    driver can find it and work with it properly.
+
+    i.e. We set up the io port, irq, mmio memory and shared ram memory.
+    This enables ibmtr_probe in ibmtr.c to find the card and configure it
+    as though it was a normal ISA and/or PnP card.
+
+    There is some confusion with the difference between available shared
+    ram and the amount actually reserved from memory.  ibmtr.c sets up
+    several offsets depending upon the actual on-board memory, not the
+    reserved memory.  We need to get around this to allow the cards to 
+    work with other cards in restricted memory space.  Therefore the 
+    pcmcia_reality_check function.
+
+    TODO
+	- Write the suspend / resume functions. 
+	- Fix Kernel Oops when removing card before ifconfig down
+
+    CHANGES
+
+    v2.2.5 April 1999 Mike Phillips (phillim@amtrak.com)
+    Obscure bug fix, required changed to ibmtr.c not ibmtr_cs.c
+    
+    v2.2.7 May 1999 Mike Phillips (phillim@amtrak.com)
+    Updated to version 2.2.7 to match the first version of the kernel
+    that the modification to ibmtr.c were incorporated into.
+    
+	
+======================================================================*/
+
+#include <pcmcia/config.h>
+#include <pcmcia/k_compat.h>
+
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/sched.h>
+#include <linux/ptrace.h>
+#include <linux/malloc.h>
+#include <linux/string.h>
+#include <linux/timer.h>
+#include <linux/delay.h>
+#include <asm/io.h>
+#include <asm/system.h>
+
+#include <linux/netdevice.h>
+#include <linux/trdevice.h>
+#include <linux/ibmtr.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 =
+"ibmtr_cs.c 1.10 1996/01/06 05:19:00 (Steve Kipisz)\n"
+"           2.2.7 1999/05/03 12:00:00 (Mike Phillips)\n" ;
+#else
+#define DEBUG(n, args...)
+#endif
+
+/*====================================================================*/
+
+/* Parameters that can be set with 'insmod' */
+
+/* Bit map of interrupts to choose from */
+static u_int irq_mask = 0xdeb8;
+static int irq_list[4] = { -1 };
+
+/* MMIO base address */
+static u_long mmiobase = 0;
+
+/* SRAM base address */
+static u_long srambase = 0;
+
+/* SRAM size 8,16,32,64 */
+static u_long sramsize = 16;
+
+/* Ringspeed 4,16 */
+static int ringspeed = 16;
+
+MODULE_PARM(irq_mask, "i");
+MODULE_PARM(irq_list, "1-4i");
+MODULE_PARM(mmiobase, "i");
+MODULE_PARM(srambase, "i");
+MODULE_PARM(sramsize, "i");
+MODULE_PARM(ringspeed, "i");
+
+/*====================================================================*/
+
+static void ibmtr_config(dev_link_t *link);
+static void ibmtr_hw_setup(struct net_device *dev);
+static void ibmtr_release(u_long arg);
+static int ibmtr_event(event_t event, int priority,
+                       event_callback_args_t *args);
+
+static dev_info_t dev_info = "ibmtr_cs";
+
+static dev_link_t *ibmtr_attach(void);
+static void ibmtr_detach(dev_link_t *);
+
+static dev_link_t *dev_list = NULL;
+
+#if (LINUX_VERSION_CODE >= VERSION(2,2,0))
+extern int ibmtr_probe(struct net_device *dev);
+unsigned char pcmcia_reality_check(unsigned char gss);
+#endif
+
+extern int trdev_init(struct net_device *dev);
+extern void tok_interrupt(int irq, struct pt_regs *regs);
+extern int tok_init_card(struct net_device *dev);
+extern unsigned char get_sram_size(struct tok_info *ti);
+#if (LINUX_VERSION_CODE < VERSION(2,1,100))
+extern struct timer_list tr_timer;
+#endif
+
+/*====================================================================*/
+
+typedef struct ibmtr_dev_t {
+    dev_link_t		link;
+    struct net_device	*dev; /* Changed for 2.2.0 */
+    dev_node_t          node;
+    window_handle_t     sram_win_handle;
+    struct tok_info	ti;
+} ibmtr_dev_t;
+
+/*======================================================================
+
+    This bit of code is used to avoid unregistering network devices
+    at inappropriate times.  2.2 and later kernels are fairly picky
+    about when this can happen.
+    
+======================================================================*/
+
+static void flush_stale_links(void)
+{
+    dev_link_t *link, *next;
+    for (link = dev_list; link; link = next) {
+	next = link->next;
+	if (link->state & DEV_STALE_LINK)
+	    ibmtr_detach(link);
+    }
+}
+
+/*====================================================================*/
+
+static void cs_error(client_handle_t handle, int func, int ret)
+{
+    error_info_t err = { func, ret };
+    CardServices(ReportError, handle, &err);
+}
+
+/*======================================================================
+
+    ibmtr_attach() creates an "instance" of the driver, allocating
+    local data structures for one device.  The device is registered
+    with Card Services.
+
+======================================================================*/
+
+static dev_link_t *ibmtr_attach(void)
+{
+    ibmtr_dev_t *info;
+    dev_link_t *link;
+    struct net_device *dev;
+    client_reg_t client_reg;
+    int i, ret;
+    
+    DEBUG(0, "ibmtr_attach()\n");
+    flush_stale_links();
+
+    /* Create new token-ring device */
+    info = kmalloc(sizeof(*info), GFP_KERNEL);
+    if (!info) return NULL;
+    memset(info, 0, sizeof(*info));
+    link = &info->link; link->priv = info;
+
+    link->release.function = &ibmtr_release;
+    link->release.data = (u_long)link;
+    link->io.Attributes1 = IO_DATA_PATH_WIDTH_8;
+    link->io.NumPorts1 = 4;
+    link->io.IOAddrLines = 16;
+    link->irq.Attributes = IRQ_TYPE_EXCLUSIVE | IRQ_HANDLE_PRESENT;
+    link->irq.IRQInfo1 = IRQ_INFO2_VALID|IRQ_LEVEL_ID;
+    if (irq_list[0] == -1)
+	link->irq.IRQInfo2 = irq_mask;
+    else
+	for (i = 0; i < 4; i++)
+	    link->irq.IRQInfo2 |= 1 << irq_list[i];
+    link->irq.Handler = &tok_interrupt;
+    link->conf.Attributes = CONF_ENABLE_IRQ;
+    link->conf.Vcc = 50;
+    link->conf.IntType = INT_MEMORY_AND_IO;
+    link->conf.Present = PRESENT_OPTION;
+
+#if (LINUX_VERSION_CODE < VERSION(2,2,0))
+    dev = kmalloc(sizeof(struct net_device), GFP_KERNEL);
+    memset(dev,0,sizeof(struct net_device));
+#else
+    dev = init_trdev(NULL,0);
+#endif
+    dev->priv = &info->ti;
+    link->irq.Instance = info->dev = dev;
+    
+    if (dev == NULL) {
+	ibmtr_detach(link);
+        return NULL;
+    }
+
+#if (LINUX_VERSION_CODE >= VERSION(2,2,0))
+    dev->init = &ibmtr_probe;
+#else
+    trdev_init(dev);
+    dev->name = info->node.dev_name;
+#endif
+
+    /* Register with Card Services */
+    link->next = dev_list;
+    dev_list = link;
+    client_reg.dev_info = &dev_info;
+    client_reg.Attributes = INFO_IO_CLIENT | INFO_CARD_SHARE;
+    client_reg.EventMask =
+        CS_EVENT_CARD_INSERTION | CS_EVENT_CARD_REMOVAL |
+        CS_EVENT_RESET_PHYSICAL | CS_EVENT_CARD_RESET |
+        CS_EVENT_PM_SUSPEND | CS_EVENT_PM_RESUME;
+    client_reg.event_handler = &ibmtr_event;
+    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);
+        ibmtr_detach(link);
+        return NULL;
+    }
+
+    return link;
+} /* ibmtr_attach */
+
+/*======================================================================
+
+    This deletes a driver "instance".  The device is de-registered
+    with Card Services.  If it has been released, all local data
+    structures are freed.  Otherwise, the structures will be freed
+    when the device is released.
+
+======================================================================*/
+
+static void ibmtr_detach(dev_link_t *link)
+{
+    struct ibmtr_dev_t *info = link->priv;
+    dev_link_t **linkp;
+    struct net_device *dev; 
+
+    DEBUG(0, "ibmtr_detach(0x%p)\n", link);
+
+    /* Locate device structure */
+    for (linkp = &dev_list; *linkp; linkp = &(*linkp)->next)
+        if (*linkp == link) break;
+    if (*linkp == NULL)
+        return;
+
+    dev = info->dev;
+#if (LINUX_VERSION_CODE < VERSION(2,1,100))
+    del_timer(&tr_timer);
+#else
+    {
+	struct tok_info *ti = (struct tok_info *)dev->priv;
+	del_timer(&(ti->tr_timer));
+    }
+#endif
+    del_timer(&link->release);
+    if (link->state & DEV_CONFIG) {
+        ibmtr_release((u_long)link);
+        if (link->state & DEV_STALE_CONFIG) {
+            link->state |= DEV_STALE_LINK;
+            return;
+        }
+    }
+
+    if (link->handle)
+        CardServices(DeregisterClient, link->handle);
+
+    /* Unlink device structure, free bits */
+    *linkp = link->next;
+    if (link->dev)
+#if (LINUX_VERSION_CODE <= VERSION(2,1,16))
+	unregister_netdev(info->dev);
+#else
+	unregister_trdev(info->dev);
+#endif
+    kfree(info);
+
+} /* ibmtr_detach */
+
+/*======================================================================
+
+    ibmtr_config() is scheduled to run after a CARD_INSERTION event
+    is received, to configure the PCMCIA socket, and to make the
+    token-ring device available to the system.
+
+======================================================================*/
+
+#define CS_CHECK(fn, args...) \
+while ((last_ret=CardServices(last_fn=(fn), args))!=0) goto cs_failed
+
+static void ibmtr_config(dev_link_t *link)
+{
+    client_handle_t handle = link->handle;
+    ibmtr_dev_t *info = link->priv;
+    struct net_device *dev = info->dev;
+    struct tok_info *ti = dev->priv;
+    tuple_t tuple;
+    cisparse_t parse;
+    win_req_t req;
+    memreq_t mem;
+    int i, last_ret, last_fn;
+    u_char buf[64];
+    unsigned char Shared_Ram_Base;
+
+    DEBUG(0, "ibmtr_config(0x%p)\n", link);
+
+    tuple.Attributes = 0;
+    tuple.TupleData = buf;
+    tuple.TupleDataMax = 64;
+    tuple.TupleOffset = 0;
+    tuple.DesiredTuple = CISTPL_CONFIG;
+    CS_CHECK(GetFirstTuple, handle, &tuple);
+    CS_CHECK(GetTupleData, handle, &tuple);
+    CS_CHECK(ParseTuple, handle, &tuple, &parse);
+    link->conf.ConfigBase = parse.config.base;
+
+    /* Configure card */
+    link->state |= DEV_CONFIG;
+
+    link->conf.ConfigIndex = 0x61;
+
+    /* Determine if this is PRIMARY or ALTERNATE. */
+
+    /* Try PRIMARY card at 0xA20-0xA23 */
+    link->io.BasePort1 = 0xA20;
+    i = CardServices(RequestIO, link->handle, &link->io);
+    if (i == CS_SUCCESS) {
+	memcpy(info->node.dev_name, "tr0\0", 4);
+    } else {
+	/* Couldn't get 0xA20-0xA23.  Try ALTERNATE at 0xA24-0xA27. */
+	link->io.BasePort1 = 0xA24;
+	CS_CHECK(RequestIO, link->handle, &link->io);
+	memcpy(info->node.dev_name, "tr1\0", 4);
+    }
+    dev->base_addr = link->io.BasePort1;
+
+    CS_CHECK(RequestIRQ, link->handle, &link->irq);
+    dev->irq = link->irq.AssignedIRQ;
+    ti->irq = link->irq.AssignedIRQ;
+    ti->global_int_enable=GLOBAL_INT_ENABLE+((dev->irq==9) ? 2 : dev->irq);
+
+    /* Allocate the MMIO memory window */
+    req.Attributes = WIN_DATA_WIDTH_16|WIN_MEMORY_TYPE_CM|WIN_ENABLE;
+    req.Attributes |= WIN_USE_WAIT|WIN_STRICT_ALIGN;
+    req.Base = mmiobase;
+    req.Size = 0x2000;
+    req.AccessSpeed = 250;
+    link->win = (window_handle_t)link->handle;
+    CS_CHECK(RequestWindow, &link->win, &req);
+
+    mem.CardOffset = req.Base;
+    mem.Page = 0;
+    CS_CHECK(MapMemPage, link->win, &mem);
+    ti->mmio = (u_long)ioremap(req.Base, req.Size);
+
+    /* Allocate the SRAM memory window */
+    req.Attributes = WIN_DATA_WIDTH_16|WIN_MEMORY_TYPE_CM|WIN_ENABLE;
+    req.Attributes |= WIN_USE_WAIT|WIN_MAP_BELOW_1MB;
+    req.Base = srambase;
+    req.Size = sramsize * 1024;
+    req.AccessSpeed = 250;
+    info->sram_win_handle = (window_handle_t)link->handle;
+    CS_CHECK(RequestWindow, &info->sram_win_handle, &req);
+
+    mem.CardOffset = req.Base;
+    mem.Page = 0;
+    CS_CHECK(MapMemPage, info->sram_win_handle, &mem);
+    Shared_Ram_Base = req.Base >> 12;
+   
+    ti->sram = 0;
+    ti->sram_base = Shared_Ram_Base;
+    
+    CS_CHECK(RequestConfiguration, link->handle, &link->conf);
+
+    /*  Set up the Token-Ring Controller Configuration Register and
+        turn on the card.  Check the "Local Area Network Credit Card
+        Adapters Technical Reference"  SC30-3585 for this info.  */
+    ibmtr_hw_setup(dev);
+
+#if (LINUX_VERSION_CODE <= VERSION(2,1,16))
+    i = register_netdev(dev);
+#else
+    i = register_trdev(dev);
+#endif
+    
+    if (i != 0) {
+#if (LINUX_VERSION_CODE <= VERSION(2,1,16))
+	printk(KERN_NOTICE "ibmtr_cs: register_netdev() failed\n");
+#else
+	printk(KERN_NOTICE "ibmtr_cs: register_trdev() failed\n");
+#endif
+	goto failed;
+    }
+
+    link->dev = &info->node;
+    link->state &= ~DEV_CONFIG_PENDING;
+
+    printk(KERN_INFO "%s: port %#3lx, irq %d,",
+           dev->name, dev->base_addr, dev->irq);
+    printk (" mmio %#5lx,", (u_long)ti->mmio);
+    printk (" sram %#5lx,", (u_long)ti->sram_base << 12);
+    printk ("\n" KERN_INFO "  hwaddr=");
+    for (i = 0; i < TR_ALEN; i++)
+        printk("%02X", dev->dev_addr[i]);
+    printk("\n");
+    return;
+
+cs_failed:
+    cs_error(link->handle, last_fn, last_ret);
+failed:
+    ibmtr_release((u_long)link);
+} /* ibmtr_config */
+
+/*======================================================================
+
+    After a card is removed, ibmtr_release() will unregister the net
+    device, and release the PCMCIA configuration.  If the device is
+    still open, this will be postponed until it is closed.
+
+======================================================================*/
+
+static void ibmtr_release(u_long arg)
+{
+    dev_link_t *link = (dev_link_t *)arg;
+    ibmtr_dev_t *info = link->priv;
+    struct net_device *dev = info->dev;
+
+    DEBUG(0, "ibmtr_release(0x%p)\n", link);
+
+    if (link->open) {
+	DEBUG(1, "ibmtr_cs: release postponed, '%s' "
+	      "still open\n", info->node.dev_name);
+        link->state |= DEV_STALE_CONFIG;
+        return;
+    }
+
+    CardServices(ReleaseConfiguration, link->handle);
+    CardServices(ReleaseIO, link->handle, &link->io);
+    CardServices(ReleaseIRQ, link->handle, &link->irq);
+    if (link->win) {
+	struct tok_info *ti = dev->priv;
+	iounmap((void *)ti->mmio);
+	CardServices(ReleaseWindow, link->win);
+	CardServices(ReleaseWindow, info->sram_win_handle);
+    }
+
+    link->state &= ~DEV_CONFIG;
+
+} /* ibmtr_release */
+
+/*======================================================================
+
+    The card status event handler.  Mostly, this schedules other
+    stuff to run after an event is received.  A CARD_REMOVAL event
+    also sets some flags to discourage the net drivers from trying
+    to talk to the card any more.
+
+======================================================================*/
+
+static int ibmtr_event(event_t event, int priority,
+                       event_callback_args_t *args)
+{
+    dev_link_t *link = args->client_data;
+    ibmtr_dev_t *info = link->priv;
+    struct net_device *dev = info->dev;
+
+    DEBUG(1, "ibmtr_event(0x%06x)\n", event);
+    
+    switch (event) {
+    case CS_EVENT_CARD_REMOVAL:
+        link->state &= ~DEV_PRESENT;
+        if (link->state & DEV_CONFIG) {
+	    netif_device_detach(dev);
+	    mod_timer(&link->release, jiffies + HZ/20);
+        }
+        break;
+    case CS_EVENT_CARD_INSERTION:
+        link->state |= DEV_PRESENT;
+	ibmtr_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 (link->open)
+		netif_device_detach(dev);
+            CardServices(ReleaseConfiguration, link->handle);
+        }
+        break;
+    case CS_EVENT_PM_RESUME:
+        link->state &= ~DEV_SUSPEND;
+        /* Fall through... */
+    case CS_EVENT_CARD_RESET:
+        if (link->state & DEV_CONFIG) {
+            CardServices(RequestConfiguration, link->handle, &link->conf);
+            if (link->open) {
+		(dev->init)(dev);
+		netif_device_attach(dev);
+            }
+        }
+        break;
+    }
+    return 0;
+} /* ibmtr_event */
+
+/*====================================================================*/
+
+static void ibmtr_hw_setup(struct net_device *dev)
+{
+    struct tok_info *ti = dev->priv;
+    int i; 
+#if (LINUX_VERSION_CODE < VERSION(2,2,0))
+    int j;
+    unsigned char temp;
+#endif
+
+#if (LINUX_VERSION_CODE >= VERSION(2,2,0)) 
+
+    /* Bizarre IBM behavior, there are 16 bits of information we
+       need to set, but the card only allows us to send 4 bits at a 
+       time.  For each byte sent to base_addr, bits 7-4 tell the
+       card which part of the 16 bits we are setting, bits 3-0 contain 
+       the actual information */
+
+    /* First nibble provides 4 bits of mmio */
+    i = ((int)ti->mmio >> 16) & 0x0F;
+    outb(i, dev->base_addr);
+
+    /* Second nibble provides 3 bits of mmio */
+    i = 0x10 | (((int)ti->mmio >> 12) & 0x0E);
+    outb(i, dev->base_addr);
+
+    /* Third nibble, hard-coded values */
+    i = 0x26;
+    outb(i, dev->base_addr);
+
+    /* Fourth nibble sets shared ram page size */
+
+    /* 8 = 00, 16 = 01, 32 = 10, 64 = 11 */          
+        
+    i = (sramsize >> 4) & 0x07; 
+    i = ((i == 4) ? 3 : i) << 2;
+    i |= 0x30;
+
+    if (ringspeed == 16)
+	i |= 2;
+    if (dev->base_addr == 0xA24)
+	i |= 1;
+    outb(i, dev->base_addr);
+
+    /* X40 will release the card for use */
+
+    outb(0x40, dev->base_addr);
+    
+    return;
+#else
+
+    i = ((int)ti->mmio >> 16) & 0x0F;
+    outb(i, dev->base_addr);
+    i = 0x10 | (((int)ti->mmio >> 12) & 0x0E);
+    outb(i, dev->base_addr);
+    i = 0x26;
+    outb(i, dev->base_addr);
+    i = 0x34;             /*  Assume 16k for now  */
+    if (ringspeed == 16)
+	i |= 2;
+    if (dev->base_addr == 0xA24)     /* Alternate */
+	i |= 1;
+    outb(i, dev->base_addr);
+    outb(0x40, dev->base_addr);
+
+    /* Get hw address of token ring card */
+    j=0;
+    for (i=0; i<0x18; i=i+2) {
+	temp = readb((ulong)AIP + (ulong)i + ti->mmio) & 0x0f;
+	/* Tech ref states must do this */
+	ti->hw_address[j]=temp;
+	if(j&1)
+	    dev->dev_addr[(j/2)]=ti->hw_address[j]+(ti->hw_address[j-1]<<4);
+	++j;
+    }
+
+    /* get Adapter type:  'F' = Adapter/A, 'E' = 16/4 Adapter II,...*/
+    ti->adapter_type = readb(ti->mmio + AIPADAPTYPE);
+    
+    /* get Data Rate:  F=4Mb, E=16Mb, D=4Mb & 16Mb ?? */
+    ti->data_rate = readb(ti->mmio + AIPDATARATE);
+
+    /* Get Early Token Release support?: F=no, E=4Mb, D=16Mb, C=4&16Mb */
+    ti->token_release = readb(ti->mmio + AIPEARLYTOKEN);
+    
+    /* How much shared RAM is on adapter ? */
+    ti->avail_shared_ram = 64;    /* for now */
+    
+    /* We need to set or do a bunch of work here based on previous results.. */
+    /* Support paging?  What sizes?:  F=no, E=16k, D=32k, C=16 & 32k */
+    ti->shared_ram_paging = readb(ti->mmio + AIPSHRAMPAGE);
+    
+    /* Available DHB  4Mb size:   F=2048, E=4096, D=4464 */
+    ti->dhb_size4mb = readb(ti->mmio + AIP4MBDHB);
+    
+    /* Available DHB 16Mb size:  F=2048, E=4096, D=8192, C=16384, B=17960 */
+    ti->dhb_size16mb = readb(ti->mmio + AIP16MBDHB);
+    
+    /* For now, no shared ram paging */
+    /* determine how much of total RAM is mapped into PC space */
+    ti->mapped_ram_size =
+	1<<(((readb(ti->mmio+ ACA_OFFSET + ACA_RW + RRR_ODD))>>2)+4);
+    ti->page_mask=0;
+
+    return;
+#endif
+}
+
+/*======================================================================
+  
+    A sweet little function that circumvents the problem with
+    ibmtr.c trying to use more memory than we can allocate for
+    the PCMCIA card.  ibmtr.c just assumes that if a card has 
+    64K of shared ram, the entire 64K must be mapped into memory,
+    whereas resources are sometimes a little tight in card services
+    so we fool ibmtr.c into thinking the card has less memory on
+    it than it has.
+    
+======================================================================*/
+
+unsigned char pcmcia_reality_check(unsigned char gss)
+{
+    return (gss < sramsize) ? sramsize : gss;
+}
+
+/*====================================================================*/
+
+static int __init init_ibmtr_cs(void)
+{
+    servinfo_t serv;
+    DEBUG(0, "%s\n", version);
+    CardServices(GetCardServicesInfo, &serv);
+    if (serv.Revision != CS_RELEASE_CODE) {
+        printk(KERN_NOTICE "ibmtr_cs: Card Services release "
+	       "does not match!\n");
+        return -1;
+    }
+    register_pccard_driver(&dev_info, &ibmtr_attach, &ibmtr_detach);
+    return 0;
+}
+
+static void __exit exit_ibmtr_cs(void)
+{
+    DEBUG(0, "ibmtr_cs: unloading\n");
+    unregister_pccard_driver(&dev_info);
+    while (dev_list != NULL)
+        ibmtr_detach(dev_list);
+}
+
+module_init(init_ibmtr_cs);
+module_exit(exit_ibmtr_cs);
Index: oldkernel/linux/pcmcia-cs-3.1.15/clients/ide_cs.c
diff -u /dev/null linux/pcmcia-cs-3.1.15/clients/ide_cs.c:1.1
--- /dev/null	Mon Jul 31 21:15:10 2000
+++ linux/pcmcia-cs-3.1.15/clients/ide_cs.c	Fri Jul  7 16:34:58 2000
@@ -0,0 +1,474 @@
+/*======================================================================
+
+    A driver for PCMCIA IDE/ATA disk cards
+
+    ide_cs.c 1.29 2000/05/16 21:31:36
+
+    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@pcmcia.sourceforge.org>.  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 <pcmcia/config.h>
+#include <pcmcia/k_compat.h>
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/sched.h>
+#include <linux/ptrace.h>
+#include <linux/malloc.h>
+#include <linux/string.h>
+#include <linux/timer.h>
+#include <linux/ioport.h>
+#ifndef CONFIG_BLK_DEV_IDE
+#define CONFIG_BLK_DEV_IDE
+#endif
+#include <linux/hdreg.h>
+#include <linux/major.h>
+#include <asm/io.h>
+#include <asm/system.h>
+
+#include <pcmcia/version.h>
+#include <pcmcia/cs_types.h>
+#include <pcmcia/cs.h>
+#include <pcmcia/cistpl.h>
+#include <pcmcia/ds.h>
+#include <pcmcia/cisreg.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 =
+"ide_cs.c 1.29 2000/05/16 21:31:36 (David Hinds)";
+#else
+#define DEBUG(n, args...)
+#endif
+
+/*====================================================================*/
+
+/* Parameters that can be set with 'insmod' */
+
+/* Bit map of interrupts to choose from */
+static u_int irq_mask = 0xdeb8;
+static int irq_list[4] = { -1 };
+
+MODULE_PARM(irq_mask, "i");
+MODULE_PARM(irq_list, "1-4i");
+
+/*====================================================================*/
+
+static const char ide_major[] = {
+    IDE0_MAJOR, IDE1_MAJOR, IDE2_MAJOR, IDE3_MAJOR,
+#ifdef IDE4_MAJOR
+    IDE4_MAJOR, IDE5_MAJOR
+#endif
+};
+
+typedef struct ide_info_t {
+    dev_link_t	link;
+    int		ndev;
+    dev_node_t	node;
+    int		hd;
+} ide_info_t;
+
+static void ide_release(u_long arg);
+static int ide_event(event_t event, int priority,
+		     event_callback_args_t *args);
+
+static dev_info_t dev_info = "ide_cs";
+
+static dev_link_t *ide_attach(void);
+static void ide_detach(dev_link_t *);
+
+static dev_link_t *dev_list = NULL;
+
+/*====================================================================*/
+
+static void cs_error(client_handle_t handle, int func, int ret)
+{
+    error_info_t err = { func, ret };
+    CardServices(ReportError, handle, &err);
+}
+
+/*======================================================================
+
+    ide_attach() creates an "instance" of the driver, allocating
+    local data structures for one device.  The device is registered
+    with Card Services.
+
+======================================================================*/
+
+static dev_link_t *ide_attach(void)
+{
+    ide_info_t *info;
+    dev_link_t *link;
+    client_reg_t client_reg;
+    int i, ret;
+    
+    DEBUG(0, "ide_attach()\n");
+
+    /* Create new ide device */
+    info = kmalloc(sizeof(*info), GFP_KERNEL);
+    if (!info) return NULL;
+    memset(info, 0, sizeof(*info));
+    link = &info->link; link->priv = info;
+
+    link->release.function = &ide_release;
+    link->release.data = (u_long)link;
+    link->io.Attributes1 = IO_DATA_PATH_WIDTH_AUTO;
+    link->io.Attributes2 = IO_DATA_PATH_WIDTH_8;
+    link->io.IOAddrLines = 3;
+    link->irq.Attributes = IRQ_TYPE_EXCLUSIVE;
+    link->irq.IRQInfo1 = IRQ_INFO2_VALID|IRQ_LEVEL_ID;
+    if (irq_list[0] == -1)
+	link->irq.IRQInfo2 = irq_mask;
+    else
+	for (i = 0; i < 4; i++)
+	    link->irq.IRQInfo2 |= 1 << irq_list[i];
+    link->conf.Attributes = CONF_ENABLE_IRQ;
+    link->conf.Vcc = 50;
+    link->conf.IntType = INT_MEMORY_AND_IO;
+    
+    /* Register with Card Services */
+    link->next = dev_list;
+    dev_list = link;
+    client_reg.dev_info = &dev_info;
+    client_reg.Attributes = INFO_IO_CLIENT | INFO_CARD_SHARE;
+    client_reg.EventMask =
+	CS_EVENT_CARD_INSERTION | CS_EVENT_CARD_REMOVAL |
+	CS_EVENT_RESET_PHYSICAL | CS_EVENT_CARD_RESET |
+	CS_EVENT_PM_SUSPEND | CS_EVENT_PM_RESUME;
+    client_reg.event_handler = &ide_event;
+    client_reg.Version = 0x0210;
+    client_reg.event_callback_args.client_data = link;
+    ret = CardServices(RegisterClient, &link->handle, &client_reg);
+    if (ret != CS_SUCCESS) {
+	cs_error(link->handle, RegisterClient, ret);
+	ide_detach(link);
+	return NULL;
+    }
+    
+    return link;
+} /* ide_attach */
+
+/*======================================================================
+
+    This deletes a driver "instance".  The device is de-registered
+    with Card Services.  If it has been released, all local data
+    structures are freed.  Otherwise, the structures will be freed
+    when the device is released.
+
+======================================================================*/
+
+static void ide_detach(dev_link_t *link)
+{
+    dev_link_t **linkp;
+    int ret;
+
+    DEBUG(0, "ide_detach(0x%p)\n", link);
+    
+    /* Locate device structure */
+    for (linkp = &dev_list; *linkp; linkp = &(*linkp)->next)
+	if (*linkp == link) break;
+    if (*linkp == NULL)
+	return;
+
+    del_timer(&link->release);
+    if (link->state & DEV_CONFIG)
+	ide_release((u_long)link);
+    
+    if (link->handle) {
+	ret = CardServices(DeregisterClient, link->handle);
+	if (ret != CS_SUCCESS)
+	    cs_error(link->handle, DeregisterClient, ret);
+    }
+    
+    /* Unlink, free device structure */
+    *linkp = link->next;
+    kfree(link->priv);
+    
+} /* ide_detach */
+
+/*======================================================================
+
+    ide_config() is scheduled to run after a CARD_INSERTION event
+    is received, to configure the PCMCIA socket, and to make the
+    ide device available to the system.
+
+======================================================================*/
+
+#define CS_CHECK(fn, args...) \
+while ((last_ret=CardServices(last_fn=(fn), args))!=0) goto cs_failed
+
+#define CFG_CHECK(fn, args...) \
+if (CardServices(fn, args) != 0) goto next_entry
+
+void ide_config(dev_link_t *link)
+{
+    client_handle_t handle = link->handle;
+    ide_info_t *info = link->priv;
+    tuple_t tuple;
+    u_short buf[128];
+    cisparse_t parse;
+    config_info_t conf;
+    cistpl_cftable_entry_t *cfg = &parse.cftable_entry;
+    cistpl_cftable_entry_t dflt = { 0 };
+    int i, pass, last_ret, last_fn, hd, io_base, ctl_base;
+
+    DEBUG(0, "ide_config(0x%p)\n", link);
+    
+    tuple.TupleData = (cisdata_t *)buf;
+    tuple.TupleOffset = 0; tuple.TupleDataMax = 255;
+    tuple.Attributes = 0;
+    tuple.DesiredTuple = CISTPL_CONFIG;
+    CS_CHECK(GetFirstTuple, handle, &tuple);
+    CS_CHECK(GetTupleData, handle, &tuple);
+    CS_CHECK(ParseTuple, handle, &tuple, &parse);
+    link->conf.ConfigBase = parse.config.base;
+    link->conf.Present = parse.config.rmask[0];
+    
+    /* Configure card */
+    link->state |= DEV_CONFIG;
+
+    /* Not sure if this is right... look up the current Vcc */
+    CS_CHECK(GetConfigurationInfo, handle, &conf);
+    link->conf.Vcc = conf.Vcc;
+    
+    pass = io_base = ctl_base = 0;
+    tuple.DesiredTuple = CISTPL_CFTABLE_ENTRY;
+    tuple.Attributes = 0;
+    CS_CHECK(GetFirstTuple, handle, &tuple);
+    while (1) {
+	CFG_CHECK(GetTupleData, handle, &tuple);
+	CFG_CHECK(ParseTuple, handle, &tuple, &parse);
+
+	/* Check for matching Vcc, unless we're desperate */
+	if (!pass) {
+	    if (cfg->vcc.present & (1<<CISTPL_POWER_VNOM)) {
+		if (conf.Vcc != cfg->vcc.param[CISTPL_POWER_VNOM]/10000)
+		    goto next_entry;
+	    } else if (dflt.vcc.present & (1<<CISTPL_POWER_VNOM)) {
+		if (conf.Vcc != dflt.vcc.param[CISTPL_POWER_VNOM]/10000)
+		    goto next_entry;
+	    }
+	}
+	
+	if (cfg->vpp1.present & (1<<CISTPL_POWER_VNOM))
+	    link->conf.Vpp1 = link->conf.Vpp2 =
+		cfg->vpp1.param[CISTPL_POWER_VNOM]/10000;
+	else if (dflt.vpp1.present & (1<<CISTPL_POWER_VNOM))
+	    link->conf.Vpp1 = link->conf.Vpp2 =
+		dflt.vpp1.param[CISTPL_POWER_VNOM]/10000;
+	
+	if ((cfg->io.nwin > 0) || (dflt.io.nwin > 0)) {
+	    cistpl_io_t *io = (cfg->io.nwin) ? &cfg->io : &dflt.io;
+	    link->conf.ConfigIndex = cfg->index;
+	    link->io.BasePort1 = io->win[0].base;
+	    link->io.IOAddrLines = io->flags & CISTPL_IO_LINES_MASK;
+	    if (!(io->flags & CISTPL_IO_16BIT))
+		link->io.Attributes1 = IO_DATA_PATH_WIDTH_8;
+	    if (io->nwin == 2) {
+		link->io.NumPorts1 = 8;
+		link->io.BasePort2 = io->win[1].base;
+		link->io.NumPorts2 = 1;
+		CFG_CHECK(RequestIO, link->handle, &link->io);
+		io_base = link->io.BasePort1;
+		ctl_base = link->io.BasePort2;
+	    } else if ((io->nwin == 1) && (io->win[0].len >= 16)) {
+		link->io.NumPorts1 = io->win[0].len;
+		link->io.NumPorts2 = 0;
+		CFG_CHECK(RequestIO, link->handle, &link->io);
+		io_base = link->io.BasePort1;
+		ctl_base = link->io.BasePort1+0x0e;
+	    } else goto next_entry;
+	    /* If we've got this far, we're done */
+	    break;
+	}
+	
+    next_entry:
+	if (cfg->flags & CISTPL_CFTABLE_DEFAULT) dflt = *cfg;
+	if (pass) {
+	    CS_CHECK(GetNextTuple, handle, &tuple);
+	} else if (CardServices(GetNextTuple, handle, &tuple) != 0) {
+	    CS_CHECK(GetFirstTuple, handle, &tuple);
+	    memset(&dflt, 0, sizeof(dflt));
+	    pass++;
+	}
+    }
+    
+    CS_CHECK(RequestIRQ, handle, &link->irq);
+    CS_CHECK(RequestConfiguration, handle, &link->conf);
+
+    /* deal with brain dead IDE resource management */
+    release_region(link->io.BasePort1, link->io.NumPorts1);
+    if (link->io.NumPorts2)
+	release_region(link->io.BasePort2, link->io.NumPorts2);
+
+    /* retry registration in case device is still spinning up */
+    for (hd = -1, i = 0; i < 10; i++) {
+	hd = ide_register(io_base, ctl_base, link->irq.AssignedIRQ);
+	if (hd >= 0) break;
+	if (link->io.NumPorts1 == 0x20) {
+	    hd = ide_register(io_base+0x10, ctl_base+0x10,
+			      link->irq.AssignedIRQ);
+	    if (hd >= 0) {
+		io_base += 0x10; ctl_base += 0x10;
+		break;
+	    }
+	}
+	__set_current_state(TASK_UNINTERRUPTIBLE);
+	schedule_timeout(HZ/10);
+    }
+    
+    if (hd < 0) {
+	printk(KERN_NOTICE "ide_cs: ide_register() at 0x%3x & 0x%3x"
+	       ", irq %u failed\n", io_base, ctl_base,
+	       link->irq.AssignedIRQ);
+	goto failed;
+    }
+
+    MOD_INC_USE_COUNT;
+    info->ndev = 1;
+    sprintf(info->node.dev_name, "hd%c", 'a'+(hd*2));
+    info->node.major = ide_major[hd];
+    info->node.minor = 0;
+    info->hd = hd;
+    link->dev = &info->node;
+    printk(KERN_INFO "ide_cs: %s: Vcc = %d.%d, Vpp = %d.%d\n",
+	   info->node.dev_name, link->conf.Vcc/10, link->conf.Vcc%10,
+	   link->conf.Vpp1/10, link->conf.Vpp1%10);
+
+    link->state &= ~DEV_CONFIG_PENDING;
+    return;
+    
+cs_failed:
+    cs_error(link->handle, last_fn, last_ret);
+failed:
+    ide_release((u_long)link);
+
+} /* ide_config */
+
+/*======================================================================
+
+    After a card is removed, ide_release() will unregister the net
+    device, and release the PCMCIA configuration.  If the device is
+    still open, this will be postponed until it is closed.
+    
+======================================================================*/
+
+void ide_release(u_long arg)
+{
+    dev_link_t *link = (dev_link_t *)arg;
+    ide_info_t *info = link->priv;
+    
+    DEBUG(0, "ide_release(0x%p)\n", link);
+
+    if (info->ndev) {
+	ide_unregister(info->hd);
+	MOD_DEC_USE_COUNT;
+    }
+    info->ndev = 0;
+    link->dev = NULL;
+    
+    CardServices(ReleaseConfiguration, link->handle);
+    CardServices(ReleaseIO, link->handle, &link->io);
+    CardServices(ReleaseIRQ, link->handle, &link->irq);
+    
+    link->state &= ~DEV_CONFIG;
+
+} /* ide_release */
+
+/*======================================================================
+
+    The card status event handler.  Mostly, this schedules other
+    stuff to run after an event is received.  A CARD_REMOVAL event
+    also sets some flags to discourage the ide drivers from
+    talking to the ports.
+    
+======================================================================*/
+
+int ide_event(event_t event, int priority,
+	      event_callback_args_t *args)
+{
+    dev_link_t *link = args->client_data;
+
+    DEBUG(1, "ide_event(0x%06x)\n", event);
+    
+    switch (event) {
+    case CS_EVENT_CARD_REMOVAL:
+	link->state &= ~DEV_PRESENT;
+	if (link->state & DEV_CONFIG)
+	    mod_timer(&link->release, jiffies + HZ/20);
+	break;
+    case CS_EVENT_CARD_INSERTION:
+	link->state |= DEV_PRESENT | DEV_CONFIG_PENDING;
+	ide_config(link);
+	break;
+    case CS_EVENT_PM_SUSPEND:
+	link->state |= DEV_SUSPEND;
+	/* Fall through... */
+    case CS_EVENT_RESET_PHYSICAL:
+	if (link->state & DEV_CONFIG)
+	    CardServices(ReleaseConfiguration, link->handle);
+	break;
+    case CS_EVENT_PM_RESUME:
+	link->state &= ~DEV_SUSPEND;
+	/* Fall through... */
+    case CS_EVENT_CARD_RESET:
+	if (DEV_OK(link))
+	    CardServices(RequestConfiguration, link->handle, &link->conf);
+	break;
+    }
+    return 0;
+} /* ide_event */
+
+/*====================================================================*/
+
+static int __init init_ide_cs(void)
+{
+    servinfo_t serv;
+    DEBUG(0, "%s\n", version);
+    CardServices(GetCardServicesInfo, &serv);
+    if (serv.Revision != CS_RELEASE_CODE) {
+	printk(KERN_NOTICE "ide_cs: Card Services release "
+	       "does not match!\n");
+	return -1;
+    }
+    register_pccard_driver(&dev_info, &ide_attach, &ide_detach);
+    return 0;
+}
+
+static void __exit exit_ide_cs(void)
+{
+    DEBUG(0, "ide_cs: unloading\n");
+    unregister_pccard_driver(&dev_info);
+    while (dev_list != NULL)
+	ide_detach(dev_list);
+}
+
+module_init(init_ide_cs);
+module_exit(exit_ide_cs);
Index: oldkernel/linux/pcmcia-cs-3.1.15/clients/iflash.h
diff -u /dev/null linux/pcmcia-cs-3.1.15/clients/iflash.h:1.1
--- /dev/null	Mon Jul 31 21:15:10 2000
+++ linux/pcmcia-cs-3.1.15/clients/iflash.h	Fri Jul  7 16:34:58 2000
@@ -0,0 +1,125 @@
+/*
+ * iflash.h 1.7 1999/10/25 20:03:18
+ *
+ * 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@pcmcia.sourceforge.org>.  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_IFLASH_H
+#define _LINUX_IFLASH_H
+
+/* Extended CIS registers for Series 2 and 2+ cards */
+/* The registers are all offsets from 0x4000 */
+#define CISREG_CSR		0x0100
+#define CISREG_WP		0x0104
+#define CISREG_RDYBSY		0x0140
+
+/* Extended CIS registers for Series 2 cards */
+#define CISREG_SLEEP		0x0118
+#define CISREG_RDY_MASK		0x0120
+#define CISREG_RDY_STATUS	0x0130
+
+/* Extended CIS registers for Series 2+ cards */
+#define CISREG_VCR		0x010c
+
+/* Card Status Register */
+#define CSR_SRESET		0x20	/* Soft reset */
+#define CSR_CMWP		0x10	/* Common memory write protect */
+#define CSR_PWRDOWN		0x08	/* Power down status */
+#define CSR_CISWP		0x04	/* Common memory CIS WP */
+#define CSR_WP			0x02	/* Mechanical write protect */
+#define CSR_READY		0x01	/* Ready/busy status */
+
+/* Write Protection Register */
+#define WP_BLKEN		0x04	/* Enable block locking */
+#define WP_CMWP			0x02	/* Common memory write protect */
+#define WP_CISWP		0x01	/* Common memory CIS WP */
+
+/* Voltage Control Register */
+#define VCR_VCC_LEVEL		0x80	/* 0 = 5V, 1 = 3.3V */
+#define VCR_VPP_VALID		0x02	/* Vpp Valid */
+#define VCR_VPP_GEN		0x01	/* Integrated Vpp generator */
+
+/* Ready/Busy Mode Register */
+#define RDYBSY_RACK		0x02	/* Ready acknowledge */
+#define RDYBSY_MODE		0x01	/* 1 = high performance */
+
+#define LOW(x) ((x) & 0xff)
+
+/* 28F008SA-Compatible Command Set */
+#define IF_READ_ARRAY		0xffff
+#define IF_INTEL_ID		0x9090
+#define IF_READ_CSR		0x7070
+#define IF_CLEAR_CSR		0x5050
+#define IF_WRITE		0x4040
+#define IF_BLOCK_ERASE		0x2020
+#define IF_ERASE_SUSPEND	0xb0b0
+#define IF_CONFIRM		0xd0d0
+
+/* 28F016SA Performance Enhancement Commands */
+#define IF_READ_PAGE		0x7575
+#define IF_PAGE_SWAP		0x7272
+#define IF_SINGLE_LOAD		0x7474
+#define IF_SEQ_LOAD		0xe0e0
+#define IF_PAGE_WRITE		0x0c0c
+#define IF_RDY_MODE		0x9696
+#define IF_RDY_LEVEL		0x0101
+#define IF_RDY_PULSE_WRITE	0x0202
+#define IF_RDY_PULSE_ERASE	0x0303
+#define IF_RDY_DISABLE		0x0404
+#define IF_LOCK_BLOCK		0x7777
+#define IF_UPLOAD_STATUS	0x9797
+#define IF_READ_ESR		0x7171
+#define IF_ERASE_UNLOCKED	0xa7a7
+#define IF_SLEEP		0xf0f0
+#define IF_ABORT		0x8080
+#define IF_UPLOAD_DEVINFO	0x9999
+
+/* Definitions for Compatible Status Register */
+#define CSR_WR_READY		0x8080	/* Write state machine status */
+#define CSR_ERA_SUSPEND		0x4040	/* Erase suspend status */
+#define CSR_ERA_ERR		0x2020	/* Erase status */
+#define CSR_WR_ERR		0x1010	/* Data write status */
+#define CSR_VPP_LOW		0x0808	/* Vpp status */
+
+/* Definitions for Global Status Register */
+#define GSR_WR_READY		0x8080	/* Write state machine status */
+#define GSR_OP_SUSPEND		0x4040	/* Operation suspend status */
+#define GSR_OP_ERR		0x2020	/* Device operation status */
+#define GSR_SLEEP		0x1010	/* Device sleep status */
+#define GSR_QUEUE_FULL		0x0808	/* Queue status */
+#define GSR_PAGE_AVAIL		0x0404	/* Page buffer available status */
+#define GSR_PAGE_READY		0x0202	/* Page buffer status */
+#define GSR_PAGE_SELECT		0x0101	/* Page buffer select status */
+
+/* Definitions for Block Status Register */
+#define BSR_READY		0x8080	/* Block status */
+#define BSR_UNLOCK		0x4040	/* Block lock status */
+#define BSR_FAILED		0x2020	/* Block operation status */
+#define BSR_ABORTED		0x1010	/* Operation abort status */
+#define BSR_QUEUE_FULL		0x0808	/* Queue status */
+#define BSR_VPP_LOW		0x0404	/* Vpp status */
+
+#endif /* _LINUX_IFLASH_H */
Index: oldkernel/linux/pcmcia-cs-3.1.15/clients/iflash2+_mtd.c
diff -u /dev/null linux/pcmcia-cs-3.1.15/clients/iflash2+_mtd.c:1.1
--- /dev/null	Mon Jul 31 21:15:10 2000
+++ linux/pcmcia-cs-3.1.15/clients/iflash2+_mtd.c	Fri Jul  7 16:34:58 2000
@@ -0,0 +1,1193 @@
+/*======================================================================
+
+    A simple MTD for Intel Series 2+ Flash devices
+
+    iflash2+_mtd.c 1.64 2000/05/16 21:31:36
+
+    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@pcmcia.sourceforge.org>.  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.
+    
+    For efficiency and simplicity, this driver is very block oriented.
+    Reads and writes must not span erase block boundaries.  Erases
+    are limited to one erase block per request.  This makes it much
+    easier to manage multiple asynchronous erases efficiently.
+    
+======================================================================*/
+
+#include <pcmcia/config.h>
+#include <pcmcia/k_compat.h>
+
+#ifdef __LINUX__
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/sched.h>
+#include <linux/ptrace.h>
+#include <linux/malloc.h>
+#include <linux/string.h>
+#include <linux/timer.h>
+#include <linux/timex.h>
+#include <linux/major.h>
+#include <linux/fs.h>
+#include <linux/delay.h>
+#include <asm/io.h>
+#include <asm/system.h>
+#include <asm/segment.h>
+#endif
+
+#include <stdarg.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>
+#include <pcmcia/mem_op.h>
+#include "iflash.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_INFO args); } while (0)
+static char *version =
+"iflash2+_mtd.c 1.64 2000/05/16 21:31:36 (David Hinds)";
+#else
+#define DEBUG(n, args...) do { } while (0)
+#endif
+
+/*====================================================================*/
+
+/* Parameters that can be set with 'insmod' */
+
+#define INT_MODULE_PARM(n, v) static int n = v; MODULE_PARM(n, "i")
+
+INT_MODULE_PARM(word_width, 1);			/* 1 = 16-bit */
+INT_MODULE_PARM(mem_speed, 0);			/* in ns */
+INT_MODULE_PARM(vpp_timeout_period, 1000);	/* in ms */
+INT_MODULE_PARM(vpp_settle, 100);		/* in ms */
+INT_MODULE_PARM(write_timeout, 100);		/* in ms */
+INT_MODULE_PARM(erase_timeout, 100);		/* in ms */
+INT_MODULE_PARM(erase_limit, 10000);		/* in ms */
+INT_MODULE_PARM(retry_limit, 8);		/* write retries */
+INT_MODULE_PARM(max_tries, 4096);		/* status polling */
+INT_MODULE_PARM(do_sleep, 1);			/* spin vs sleep? */
+
+/*====================================================================*/
+
+static void flash_config(dev_link_t *link);
+static void flash_release(u_long arg);
+static int flash_event(event_t event, int priority,
+		       event_callback_args_t *args);
+
+static dev_link_t *flash_attach(void);
+static void flash_detach(dev_link_t *);
+
+#define MAX_CELLS		32
+
+/* A flash region is composed of one or more "cells", where we allow
+   simultaneous erases if they are in different cells */
+typedef struct flash_region_t {
+    region_info_t	region;
+    u_int		cell_size;
+    struct flash_cell_t {
+	u_int		state;
+	k_time_t	erase_time;
+	u_int		erase_addr;
+	u_int		erase_retries;
+    } cell[MAX_CELLS];
+} flash_region_t;
+
+typedef struct flash_dev_t {
+    dev_link_t		link;
+    caddr_t		Base;
+    u_int		Size;
+    window_handle_t	ESRwin;
+    caddr_t		ESRbase;
+    int			vpp_usage;
+    k_time_t		vpp_start;
+    struct timer_list	vpp_timeout;
+    flash_region_t	*flash[2*CISTPL_MAX_DEVICES];
+} flash_dev_t;
+
+#define FLASH_PENDING		0x01
+#define FLASH_ERASING		0x02
+#define FLASH_ERASE_SUSPEND	0x04
+
+static dev_info_t dev_info = "iflash2+_mtd";
+
+static dev_link_t *dev_list = NULL;
+
+/*====================================================================*/
+
+static void cs_error(client_handle_t handle, int func, int ret)
+{
+    error_info_t err = { func, ret };
+    CardServices(ReportError, handle, &err);
+}
+
+#ifdef BENCHMARK
+static inline k_time_t uticks(void)
+{
+    k_time_t count;
+    outb_p(0x00, 0x43);
+    count = inb_p(0x40);
+    count |= inb(0x40) << 8;
+    count = ((LATCH-1) - count) * 10000;
+    count = (count + LATCH/2) / LATCH;
+    count += jiffies * 10000;
+    return count;
+}
+#endif
+
+/*======================================================================
+
+    Low level routines for programming the flash card.
+    
+======================================================================*/
+
+static void sleep_or_spin(wait_queue_head_t *queue)
+{
+    if (do_sleep)
+	wsleeptimeout(queue, 1);
+    else
+	udelay(50);
+}
+
+static void log_esr(char *s, volatile u_short *esr)
+{
+    u_short CSR, GSR, BSR;
+
+    writew(IF_READ_CSR, esr);
+    CSR = readw(esr);
+    writew(IF_READ_ESR, esr);
+    BSR = readw(esr+2);
+    GSR = readw(esr+4);
+    printk("%sCSR = 0x%04x, BSR = 0x%04x, GSR = 0x%04x\n",
+	   (s ? s : KERN_NOTICE), CSR, BSR, GSR);
+}
+
+static void abort_cmd(volatile u_short *esr)
+{
+    u_short i;
+
+    writew(IF_ABORT, esr);
+    writew(IF_READ_ESR, esr);
+    for (i = 0; i < max_tries; i++)
+	if ((readw(esr+4) & GSR_SLEEP) == GSR_SLEEP) break;
+    if (i == max_tries)
+	printk(KERN_NOTICE "iflash2+_mtd: abort cmd failed!\n");
+    writew(IF_READ_ARRAY, esr);
+    writew(IF_CLEAR_CSR, esr);
+}
+
+static int set_rdy_mode(volatile u_short *esr, u_short mode)
+{
+    u_short i, j;
+
+    DEBUG(3, "iflash2+_mtd: set_rdy_mode(%04x)\n", mode);
+    for (j = 0; j < retry_limit; j++) {
+	writew(IF_READ_ESR, esr);
+	for (i = 0; i < max_tries; i++)
+	    if (!(readw(esr+4) & GSR_QUEUE_FULL)) break;
+	if (i == max_tries)
+	    goto failed;
+	writew(IF_RDY_MODE, esr);
+	writew(mode, esr);
+	writew(IF_READ_ESR, esr);
+	for (i = 0; i < max_tries; i++)
+	    if ((readw(esr+4) & GSR_WR_READY) == GSR_WR_READY) break;
+	if (i == max_tries)
+	    goto failed;
+	if (!(readw(esr+4) & GSR_OP_ERR))
+	    return CS_SUCCESS;
+	writew(IF_READ_ARRAY, esr);
+	writew(IF_CLEAR_CSR, esr);
+    }
+failed:
+    printk(KERN_NOTICE "iflash2+_mtd: set_rdy_mode failed!\n");
+    log_esr(NULL, esr);
+    return CS_GENERAL_FAILURE;
+}
+
+static int check_write(wait_queue_head_t *queue, volatile u_short *esr)
+{
+    u_long end = jiffies + write_timeout;
+    writew(IF_READ_ESR, esr);
+    while (((readw(esr+2) & BSR_READY) != BSR_READY) && 
+	   (jiffies < end))
+	sleep_or_spin(queue);
+    if ((readw(esr+2) & BSR_READY) != BSR_READY) {
+	printk(KERN_NOTICE "iflash2+_mtd: check_write: timed out!\n");
+	log_esr(NULL, esr);
+	return CS_GENERAL_FAILURE;
+    }
+    if (readw(esr+2) & BSR_FAILED) {
+	log_esr(KERN_DEBUG "write error: ", esr);
+	return CS_WRITE_FAILURE;
+    } else
+	return CS_SUCCESS;
+}
+
+static int page_setup(wait_queue_head_t *queue, volatile u_short *esr,
+		      volatile u_short *address, u_short count)
+{
+    u_long end = jiffies + write_timeout;
+    u_short nw;
+    writew(IF_READ_ESR, esr);
+    while (((readw(esr+4) & GSR_PAGE_AVAIL) != GSR_PAGE_AVAIL) &&
+	   (jiffies < end))
+	sleep_or_spin(queue);
+    if ((readw(esr+4) & GSR_PAGE_AVAIL) != GSR_PAGE_AVAIL) {
+	printk(KERN_NOTICE "iflash2+_mtd: page_setup timed out\n");
+	log_esr(NULL, esr);
+	return CS_GENERAL_FAILURE;
+    }
+
+    nw = count >> 1;
+    if (nw == 0) {
+	/* Special case of single byte write */
+	writeb(LOW(IF_SINGLE_LOAD), address);
+    } else {
+	writew(IF_SEQ_LOAD, address);
+	/* Tricky: split count into low bytes and high bytes */
+	nw = (count-nw-1) | ((nw-1) << 8);
+	if ((u_long)address & 2) {
+	    writew(0, address);
+	    writew(nw, address);
+	} else {
+	    writew(nw, address);
+	    writew(0, address);
+	}
+    }
+    return CS_SUCCESS;
+}
+
+static int page_write(volatile u_short *esr, volatile u_short *address,
+		      u_short count)
+{
+    u_short nw;
+    u_short i;
+
+    writew(IF_READ_ESR, esr);
+    for (i = 0; i < max_tries; i++)
+	if (!(readw(esr+2) & BSR_QUEUE_FULL)) break;
+    if (i == max_tries) {
+	printk(KERN_NOTICE "iflash2+_mtd: page_write timed out\n");
+	log_esr(NULL, esr);
+	return CS_GENERAL_FAILURE;
+    }
+    nw = count >> 1;
+    if (nw == 0) {
+	writeb(LOW(IF_PAGE_WRITE), address);
+	writeb(0, address);
+	writeb(0, address);
+    } else {
+	writew(IF_PAGE_WRITE, address);
+	/* Tricky: split count into low bytes and high bytes */
+	nw = (count-nw-1) | ((nw-1) << 8);
+	if ((u_long)address & 2) {
+	    writew(0, address);
+	    writew(nw, address);
+	} else {
+	    writew(nw, address);
+	    writew(0, address);
+	}
+    }
+    return CS_SUCCESS;
+}
+
+static void block_erase(volatile u_short *address)
+{
+    writew(IF_BLOCK_ERASE, address);
+    writew(IF_CONFIRM, address);
+}
+
+static int check_erase(volatile u_short *address)
+{
+    u_short CSR;
+    writew(IF_READ_CSR, address);
+    CSR = readw(address);
+    if ((CSR & CSR_WR_READY) != CSR_WR_READY) {
+	return CS_BUSY;
+    } else if (CSR & (CSR_ERA_ERR | CSR_VPP_LOW | CSR_WR_ERR)) {
+	log_esr(KERN_NOTICE "erase error: ", address);
+	return CS_WRITE_FAILURE;
+    } else
+	return CS_SUCCESS;
+}
+
+static int suspend_erase(volatile u_short *esr)
+{
+    u_short i;
+
+    DEBUG(1, "iflash2+_mtd: suspending erase...\n");
+    writew(IF_ERASE_SUSPEND, esr);
+    writew(IF_READ_ESR, esr);
+    for (i = 0; i < max_tries; i++)
+	if ((readw(esr+4) & GSR_WR_READY) == GSR_WR_READY) break;
+    if (i == max_tries) {
+	printk(KERN_NOTICE "iflash2+_mtd: suspend_erase timed out\n");
+	log_esr(NULL, esr);
+	return CS_GENERAL_FAILURE;
+    }
+    writew(IF_READ_ARRAY, esr);
+    return CS_SUCCESS;
+}
+
+static void resume_erase(volatile u_short *esr)
+{
+    DEBUG(1, "iflash2+_mtd: resuming erase...\n");
+    writew(IF_READ_ESR, esr);
+    /* Only give resume signal if the erase is really suspended */
+    if (readw(esr+4) & GSR_OP_SUSPEND)
+	writew(IF_CONFIRM, esr);
+}
+
+static void reset_block(volatile u_short *esr)
+{
+    writew(IF_READ_ARRAY, esr);
+    writew(IF_CLEAR_CSR, esr);
+}
+
+/*====================================================================*/
+
+static void set_global_lock(window_handle_t win,
+			    volatile caddr_t base, int set)
+{
+    mtd_mod_win_t mod;
+    mod.Attributes = WIN_MEMORY_TYPE_AM;
+    mod.AccessSpeed = 250;
+    mod.CardOffset = 0x4000;
+    MTDHelperEntry(MTDModifyWindow, win, &mod);
+    writeb((set) ? WP_BLKEN : 0, base+CISREG_WP);
+}
+
+/*======================================================================
+
+    Vpp management functions.  The vpp_setup() function checks to
+    see if Vpp is available for the specified device.  If not, it
+    turns on Vpp.  The vpp_shutdown() function is scheduled to turn
+    Vpp off after an interval of inactivity.
+
+    vpp_setup() assumes that it will be called at the top of a
+    request handler, and that it can use the MTD_REQ_TIMEOUT flag
+    to tell if it has already been called for this particular
+    request, so that it can count Vpp users.
+
+    A handler should call vpp_shutdown() once for each request that
+    does a vpp_setup().
+    
+======================================================================*/
+
+static int vpp_setup(dev_link_t *link, mtd_request_t *req)
+{
+    flash_dev_t *dev = (flash_dev_t *)link->priv;
+    mtd_vpp_req_t vpp_req;
+
+    /* First time for this request? */
+    if (!(req->Function & MTD_REQ_TIMEOUT)) {
+	/* If no other users, kill shutdown timer and apply power */
+	if (++dev->vpp_usage == 1) {
+	    if (!del_timer(&dev->vpp_timeout)) {
+		DEBUG(1, "iflash2+_mtd: raising Vpp...\n");
+		dev->vpp_start = jiffies;
+		vpp_req.Vpp1 = vpp_req.Vpp2 = 120;
+		MTDHelperEntry(MTDSetVpp, link->handle, &vpp_req);
+	    }
+	}
+    }
+    /* Wait for Vpp to settle if it was just applied */
+    if (jiffies < dev->vpp_start + vpp_settle) {
+	req->Status = MTD_WAITTIMER;
+	req->Timeout = vpp_settle * 1000 / HZ;
+	return 1;
+    }
+    return 0;
+}
+
+static void vpp_off(u_long arg)
+{
+    dev_link_t *link = (dev_link_t *)arg;
+    flash_dev_t *dev;
+    mtd_vpp_req_t req;
+
+    DEBUG(1, "iflash2+_mtd: lowering Vpp...\n");
+    dev = (flash_dev_t *)link->priv;
+    dev->vpp_timeout.expires = 0;
+    req.Vpp1 = req.Vpp2 = 0;
+    MTDHelperEntry(MTDSetVpp, link->handle, &req);
+}
+
+static void vpp_shutdown(dev_link_t *link)
+{
+    flash_dev_t *dev;
+    dev = (flash_dev_t *)link->priv;
+    dev->vpp_usage--;
+    if (dev->vpp_usage == 0) {
+	dev->vpp_timeout.expires = jiffies + vpp_timeout_period;
+	add_timer(&dev->vpp_timeout);
+    }
+}
+
+/*======================================================================
+
+    flash_attach() creates an "instance" of the driver, allocating
+    local data structures for one device.  The device is registered
+    with Card Services.
+
+======================================================================*/
+
+static dev_link_t *flash_attach(void)
+{
+    client_reg_t client_reg;
+    dev_link_t *link;
+    flash_dev_t *dev;
+    int ret;
+    
+    DEBUG(0, "iflash2+_mtd: flash_attach()\n");
+
+    /* Create new memory card device */
+    dev = kmalloc(sizeof(*dev), GFP_KERNEL);
+    if (!dev) return NULL;
+    memset(dev, 0, sizeof(*dev));
+    link = &dev->link; link->priv = dev;
+    
+    link->release.function = &flash_release;
+    link->release.data = (u_long)link;
+    init_waitqueue_head(&link->pending);
+    
+    dev->vpp_timeout.function = vpp_off;
+    dev->vpp_timeout.data = (u_long)link;
+
+    /* Register with Card Services */
+    link->next = dev_list;
+    dev_list = link;
+    client_reg.dev_info = &dev_info;
+    client_reg.Attributes = INFO_MTD_CLIENT | INFO_CARD_SHARE;
+    client_reg.EventMask =
+	CS_EVENT_RESET_PHYSICAL | CS_EVENT_CARD_RESET |
+	CS_EVENT_CARD_INSERTION | CS_EVENT_CARD_REMOVAL |
+	CS_EVENT_PM_SUSPEND | CS_EVENT_PM_RESUME |
+	CS_EVENT_READY_CHANGE;
+    client_reg.event_handler = &flash_event;
+    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);
+	flash_detach(link);
+	return NULL;
+    }
+    
+    return link;
+} /* flash_attach */
+
+/*======================================================================
+
+    This deletes a driver "instance".  The device is de-registered
+    with Card Services.  If it has been released, all local data
+    structures are freed.  Otherwise, the structures will be freed
+    when the device is released.
+
+======================================================================*/
+
+static void flash_detach(dev_link_t *link)
+{
+    dev_link_t **linkp;
+    int ret;
+
+    DEBUG(0, "iflash2+_mtd: flash_detach(0x%p)\n", link);
+    
+    /* Locate device structure */
+    for (linkp = &dev_list; *linkp; linkp = &(*linkp)->next)
+	if (*linkp == link) break;
+    if (*linkp == NULL)
+	return;
+
+    del_timer(&link->release);
+    if (link->state & DEV_CONFIG)
+	flash_release((u_long)link);
+
+    if (link->handle) {
+	ret = CardServices(DeregisterClient, link->handle);
+	if (ret != CS_SUCCESS)
+	    cs_error(link->handle, DeregisterClient, ret);
+    }
+    
+    /* Unlink device structure, free bits */
+    *linkp = link->next;
+    kfree(link->priv);
+    
+} /* flash_detach */
+
+/*======================================================================
+
+    flash_config() is scheduled to run after a CARD_INSERTION event
+    is received, to bind the MTD to appropriate memory regions.
+    
+======================================================================*/
+
+static void printk_size(u_int sz)
+{
+    if (sz & 0x3ff)
+	printk("%u bytes", sz);
+    else if (sz & 0x0fffff)
+	printk("%u kb", sz >> 10);
+    else
+	printk("%u mb", sz >> 20);
+}
+
+static void flash_config(dev_link_t *link)
+{
+    client_handle_t handle = link->handle;
+    flash_dev_t *dev = link->priv;
+    win_req_t req;
+    mtd_reg_t reg;
+    region_info_t region;
+    int i, attr, ret;
+
+    DEBUG(0, "iflash2+_mtd: flash_config(0x%p)\n", link);
+
+    /* Allocate a small memory window */
+    if (word_width)
+	req.Attributes = WIN_DATA_WIDTH_16;
+    else
+	req.Attributes = WIN_DATA_WIDTH_8;
+    req.Base = req.Size = 0;
+    req.AccessSpeed = mem_speed;
+    link->win = (window_handle_t)handle;
+    ret = MTDHelperEntry(MTDRequestWindow, &link->win, &req);
+    if (ret != 0) {
+	cs_error(handle, RequestWindow, ret);
+	link->state &= ~DEV_CONFIG_PENDING;
+	flash_release((u_long)link);
+	return;
+    }
+    dev->Base = ioremap(req.Base, req.Size);
+    dev->Size = req.Size;
+
+    /* Allocate a memory window for ESR accesses*/
+    req.Base = 0;
+    dev->ESRwin = (window_handle_t)handle;
+    ret = MTDHelperEntry(MTDRequestWindow, &dev->ESRwin, &req);
+    if (ret != 0) {
+	cs_error(handle, RequestWindow, ret);
+	link->state &= ~DEV_CONFIG_PENDING;
+	flash_release((u_long)link);
+	return;
+    }
+    dev->ESRbase = ioremap(req.Base, req.Size);
+    
+    link->state |= DEV_CONFIG;
+
+    /* Grab info for all the memory regions we can access */
+    i = 0;
+    for (attr = 0; attr < 2; attr++) {
+	region.Attributes = attr ? REGION_TYPE_AM : REGION_TYPE_CM;
+	ret = CardServices(GetFirstRegion, handle, &region);
+	while (ret == CS_SUCCESS) {
+	    reg.Attributes = region.Attributes;
+	    reg.Offset = region.CardOffset;
+	    dev->flash[i] = kmalloc(sizeof(struct flash_region_t),
+				    GFP_KERNEL);
+	    if (!dev->flash[i]) break;
+	    reg.MediaID = (u_long)dev->flash[i];
+	    ret = CardServices(RegisterMTD, handle, &reg);
+	    if (ret != 0) {
+		kfree(dev->flash[i]);
+		break;
+	    }
+	    printk(KERN_INFO "iflash2+_mtd: %s at 0x%x, ",
+		   attr ? "attr" : "common", region.CardOffset);
+	    printk_size(region.RegionSize);
+	    printk(", ");
+	    printk_size(region.BlockSize);
+	    printk(" blocks, %u ns\n", region.AccessSpeed);
+	    memset(dev->flash[i], 0, sizeof(struct flash_region_t));
+	    dev->flash[i]->region = region;
+	    /* Distinguish between 4MB..20MB cards and 40MB cards */
+	    if (region.RegionSize > 0x1400000)
+		dev->flash[i]->cell_size = 0x800000; /* 8MB components */
+	    else
+		dev->flash[i]->cell_size = 0x400000; /* 4MB components */
+	    i++;
+	    ret = CardServices(GetNextRegion, handle, &region);
+	}
+    }
+    dev->flash[i] = NULL;
+    
+} /* flash_config */
+
+/*======================================================================
+
+    After a card is removed, flash_release() will release the memory
+    window allocated for this socket.
+    
+======================================================================*/
+
+static void flash_release(u_long arg)
+{
+    dev_link_t *link = (dev_link_t *)arg;
+    flash_dev_t *dev = link->priv;
+    int i;
+
+    DEBUG(0, "iflash2+_mtd: flash_release(0x%p)\n", link);
+
+    link->state &= ~DEV_CONFIG;
+    if (link->win) {
+	iounmap(dev->Base);
+	i = MTDHelperEntry(MTDReleaseWindow, link->win);
+	if (i != CS_SUCCESS)
+	    cs_error(link->handle, ReleaseWindow, i);
+    }
+    if (dev->ESRwin) {
+	iounmap(dev->ESRbase);
+	i = MTDHelperEntry(MTDReleaseWindow, dev->ESRwin);
+	if (i != CS_SUCCESS)
+	    cs_error(link->handle, ReleaseWindow, i);
+    }
+    if (dev->vpp_usage == 0)
+	del_timer(&dev->vpp_timeout);
+    vpp_off((u_long)link);
+    for (i = 0; (i < 2*CISTPL_MAX_DEVICES) && dev->flash[i]; i++)
+	kfree(dev->flash[i]);
+    
+    if (link->state & DEV_STALE_LINK)
+	flash_detach(link);
+    
+} /* flash_release */
+
+/*======================================================================
+
+    The read request handler.  This handler supports suspending
+    current erase requests.  Reading from a block that is currently
+    erasing is undefined.
+    
+======================================================================*/
+
+static int flash_read(dev_link_t *link, char *buf, mtd_request_t *req)
+{
+    flash_dev_t *dev = (flash_dev_t *)link->priv;
+    flash_region_t *flash;
+    region_info_t *region;
+    mtd_mod_win_t mod;
+    u_int from, length, nb, cell;
+    int ret;
+#ifdef BENCHMARK
+    k_time_t time;
+#endif
+    
+    DEBUG(2, "iflash2+_mtd: flash_read(0x%p, 0x%lx, 0x%p, 0x%x, "
+	  "0x%x)\n", link, req->MediaID, buf, req->SrcCardOffset,
+	  req->TransferLength);
+
+    flash = (flash_region_t *)(req->MediaID);
+    region = &flash->region;
+    if ((req->SrcCardOffset / region->BlockSize) !=
+	((req->SrcCardOffset+req->TransferLength-1) / region->BlockSize))
+	return CS_BAD_SIZE;
+    if (region->Attributes & REGION_TYPE_AM)
+	mod.Attributes = WIN_MEMORY_TYPE_AM;
+    else
+	mod.Attributes = WIN_MEMORY_TYPE_CM;
+    mod.AccessSpeed = region->AccessSpeed;
+
+    /* Suspend an in-progress block erase */
+    cell = (req->SrcCardOffset - region->CardOffset) / flash->cell_size;
+    if (flash->cell[cell].state & FLASH_ERASING) {
+	if ((flash->cell[cell].erase_addr / region->BlockSize) ==
+	    (req->SrcCardOffset / region->BlockSize)) {
+	    DEBUG(1, "iflash2+_mtd: delaying read...\n");
+	    req->Status = MTD_WAITREQ;
+	    return CS_BUSY;
+	}
+	link->state |= DEV_BUSY;
+	mod.CardOffset = flash->cell[cell].erase_addr;
+	ret = MTDHelperEntry(MTDModifyWindow, dev->ESRwin, &mod);
+	if (ret != CS_SUCCESS) goto done;
+	ret = suspend_erase((u_short *)dev->ESRbase);
+	if (ret != CS_SUCCESS) goto done;
+	flash->cell[cell].state |= FLASH_ERASE_SUSPEND;
+    } else
+	link->state |= DEV_BUSY;
+
+    mod.CardOffset = req->SrcCardOffset & ~(dev->Size-1);
+    from = req->SrcCardOffset & (dev->Size-1);
+    
+    ret = CS_SUCCESS;
+#ifdef BENCHMARK
+    time = uticks();
+#endif
+    for (length = req->TransferLength; length > 0; length -= nb) {
+	
+	ret = MTDHelperEntry(MTDModifyWindow, link->win, &mod);
+	if (ret != CS_SUCCESS) goto done;
+	nb = (from+length > dev->Size) ? dev->Size-from : length;
+
+	if (req->Function & MTD_REQ_KERNEL)
+	    copy_from_pc(buf, &dev->Base[from], nb);
+	else
+	    copy_pc_to_user(buf, &dev->Base[from], nb);
+	
+	buf += nb;
+	from = 0;
+	mod.CardOffset += dev->Size;
+    }
+    
+#ifdef BENCHMARK
+    time = uticks() - time;
+    if (time < 10000000)
+	DEBUG(3, "iflash2+_mtd: read complete, time = %ld,"
+	      " avg = %ld ns/word, rate = %ld kb/sec\n", time,
+	      time*2000/req->TransferLength,
+	      req->TransferLength*977/time);
+#endif
+    
+done:
+    if (flash->cell[cell].state & FLASH_ERASE_SUSPEND) {
+	resume_erase((u_short *)dev->ESRbase);
+	flash->cell[cell].state &= ~FLASH_ERASE_SUSPEND;
+    }
+    link->state &= ~DEV_BUSY;
+    return ret;
+} /* flash_read */
+
+/*======================================================================
+
+    basic_write() handles a write that fits completely within a
+    memory window that has already been set up.  It does a series
+    of pipelined page buffer writes.
+    
+======================================================================*/
+
+static int basic_write(wait_queue_head_t *queue, char *esr, char *dest,
+		       char *buf, u_int nb, u_int is_krnl)
+{
+    u_short npb;
+    int ret;
+
+    /* Enable interrupts on write complete */
+    ret = set_rdy_mode((u_short *)esr, IF_RDY_LEVEL);
+    if (ret != CS_SUCCESS) return ret;
+    
+    /* Fix for mis-aligned writes */
+    if ((u_long)dest & 1) {
+	DEBUG(2, "iflash2+_mtd: odd address fixup at 0x%p\n", dest);
+	ret = page_setup(queue, (u_short *)esr, (u_short *)dest, 1);
+	if (ret != CS_SUCCESS) return ret;
+	if (is_krnl)
+	    writeb(*buf, dest);
+	else {
+	    char c;
+	    get_user(c, buf);
+	    writeb(c, dest);
+	}
+	ret = page_write((u_short *)esr, (u_short *)dest, 1);
+	if (ret != CS_SUCCESS) return ret;
+	dest++; buf++; nb--;
+    }
+    
+    for (; nb > 0; nb -= npb) {
+	/* npb = # of bytes to write to page buffer */
+	npb = (nb > 512) ? 512 : nb;
+	/* sleep until page buffer is free */
+	ret = page_setup(queue, (u_short *)esr, (u_short *)dest, npb);
+	if (ret != CS_SUCCESS) return ret;
+	
+	if (is_krnl)
+	    copy_to_pc(dest, buf, npb);
+	else
+	    copy_user_to_pc(dest, buf, npb);
+	
+	ret = page_write((u_short *)esr, (u_short *)dest, npb);
+	if (ret != CS_SUCCESS) return ret;
+	check_write(queue, (u_short *)esr);
+	
+	dest += npb;
+	buf += npb;
+    }
+    
+    /* sleep until block is ready */
+    return check_write(queue, (u_short *)esr);
+}
+    
+/*======================================================================
+
+    The write request handler.  The Series 2+ cards support automatic
+    erase suspend for writes.
+    
+======================================================================*/
+
+static int flash_write(dev_link_t *link, char *buf, mtd_request_t *req)
+{
+    flash_dev_t *dev = (flash_dev_t *)link->priv;
+    mtd_mod_win_t mod;
+    mtd_rdy_req_t rdy;
+    flash_region_t *flash;
+    region_info_t *region;
+    u_int from, length, nb, retry, cell;
+    cs_status_t status;
+    int ret;
+#ifdef BENCHMARK
+    k_time_t time;
+#endif
+
+    DEBUG(2, "iflash2+_mtd: flash_write(0x%p, 0x%lx, "
+	  "0x%p, 0x%x, 0x%x)\n", link, req->MediaID, buf,
+	  req->DestCardOffset, req->TransferLength);
+
+    /* Check card write protect status */
+    ret = CardServices(GetStatus, link->handle, &status);
+    if (ret != CS_SUCCESS) {
+	cs_error(link->handle, GetStatus, ret);
+	return CS_GENERAL_FAILURE;
+    }
+    if (status.CardState & CS_EVENT_WRITE_PROTECT)
+	return CS_WRITE_PROTECTED;
+
+    flash = (flash_region_t *)(req->MediaID);
+    region = &flash->region;
+    if ((req->DestCardOffset / region->BlockSize) !=
+	((req->DestCardOffset+req->TransferLength-1) / region->BlockSize))
+	return CS_BAD_SIZE;
+    
+    if (vpp_setup(link, req) != 0)
+	return CS_BUSY;
+
+    /* Is this cell being erased or written? */
+    cell = (req->DestCardOffset - region->CardOffset) / flash->cell_size;
+    if (flash->cell[cell].state & FLASH_ERASING) {
+	DEBUG(1, "iflash2+_mtd: delaying write...\n");
+	req->Status = MTD_WAITREQ;
+	return CS_BUSY;
+    }
+    link->state |= DEV_BUSY;
+    
+    if (region->Attributes & REGION_TYPE_AM)
+	mod.Attributes = WIN_MEMORY_TYPE_AM;
+    else
+	mod.Attributes = WIN_MEMORY_TYPE_CM;
+    mod.AccessSpeed = region->AccessSpeed;
+
+    /* Set up window for ESR accesses */
+    mod.CardOffset = req->DestCardOffset & ~(region->BlockSize-1);
+    ret = MTDHelperEntry(MTDModifyWindow, dev->ESRwin, &mod);
+    if (ret != CS_SUCCESS) goto done;
+
+    rdy.Mask = CS_EVENT_READY_CHANGE;
+    MTDHelperEntry(MTDRDYMask, link->handle, &rdy);
+
+#ifdef BENCHMARK
+    time = uticks();
+#endif
+    mod.CardOffset = req->DestCardOffset & ~(dev->Size-1);
+    from = req->DestCardOffset & (dev->Size-1);
+    
+    for (length = req->TransferLength ; length > 0; length -= nb) {
+	ret = MTDHelperEntry(MTDModifyWindow, link->win, &mod);
+	if (ret != CS_SUCCESS) goto done;
+
+	nb = (from+length > dev->Size) ? dev->Size-from : length;
+
+	for (retry = 0; retry < retry_limit; retry++) {
+	    ret = basic_write(&link->pending, dev->ESRbase,
+			      dev->Base+from, buf, nb,
+			      (req->Function & MTD_REQ_KERNEL));
+	    if (ret == CS_SUCCESS)
+		break;
+	    abort_cmd((u_short *)dev->ESRbase);
+	}
+	if (retry == retry_limit) {
+	    printk(KERN_NOTICE "iflash2+_mtd: write at 0x%06x failed:"
+		   " too many retries!\n", mod.CardOffset);
+	    goto done;
+	}
+	
+	buf += nb;
+	from = 0;
+	mod.CardOffset += dev->Size;
+    }
+
+#ifdef BENCHMARK
+    time = uticks() - time;
+    if (time < 10000000)
+	DEBUG(3, "iflash2+_mtd: write complete, time = %ld,"
+	      " avg = %ld us/word, rate = %ld kb/sec\n", time,
+	      time*2/req->TransferLength,
+	      req->TransferLength*977/time);
+#endif
+    
+done:
+    reset_block((u_short *)dev->ESRbase);
+    rdy.Mask = 0;
+    MTDHelperEntry(MTDRDYMask, link->handle, &rdy);
+    link->state &= ~DEV_BUSY;
+    /* Fire up the Vpp timer */
+    vpp_shutdown(link);
+    return ret;
+} /* flash_write */
+
+/*======================================================================
+
+    The erase request handler.  This handler supports simultaneous
+    erases in different device components.
+    
+======================================================================*/
+
+static int flash_erase(dev_link_t *link, char *buf, mtd_request_t *req)
+{
+    flash_dev_t *dev = (flash_dev_t *)link->priv;
+    cs_status_t status;
+    flash_region_t *flash;
+    region_info_t *region;
+    mtd_mod_win_t mod;
+    int i, ret;
+
+    DEBUG(2, "iflash2+_mtd: flash_erase(0x%p, 0x%lx, 0x%x, 0x%x)\n",
+	  link, req->MediaID, req->DestCardOffset,
+	  req->TransferLength);
+
+    flash = (flash_region_t *)(req->MediaID);
+    region = &flash->region;
+    if (region->BlockSize != req->TransferLength)
+	return CS_BAD_SIZE;
+    
+    i = (req->DestCardOffset-region->CardOffset)/flash->cell_size;
+    
+    if (!(req->Function & MTD_REQ_TIMEOUT)) {
+	if (flash->cell[i].state & (FLASH_ERASING|FLASH_PENDING)) {
+	    DEBUG(1, "iflash2+_mtd: delaying erase...\n");
+	    req->Status = MTD_WAITREQ;
+	    return CS_BUSY;
+	}
+	/* Check card write protect status */
+	ret = CardServices(GetStatus, link->handle, &status);
+	if (ret != CS_SUCCESS) {
+	    cs_error(link->handle, GetStatus, ret);
+	    return CS_GENERAL_FAILURE;
+	}
+	if (status.CardState & CS_EVENT_WRITE_PROTECT)
+	    return CS_WRITE_PROTECTED;
+	flash->cell[i].state |= FLASH_PENDING;
+	/* Activate Vpp if necessary */
+	if (vpp_setup(link, req) != 0)
+	    return CS_BUSY;
+    }
+
+    if (region->Attributes & REGION_TYPE_AM)
+	mod.Attributes = WIN_MEMORY_TYPE_AM;
+    else
+	mod.Attributes = WIN_MEMORY_TYPE_CM;
+    mod.AccessSpeed = region->AccessSpeed;
+    mod.CardOffset = req->DestCardOffset;
+    ret = MTDHelperEntry(MTDModifyWindow, link->win, &mod);
+    if (ret != CS_SUCCESS)
+	goto done;
+    
+    if (flash->cell[i].state & FLASH_PENDING) {
+	/* Start a new block erase */
+	flash->cell[i].state &= ~FLASH_PENDING;
+	flash->cell[i].state |= FLASH_ERASING;
+	flash->cell[i].erase_addr = mod.CardOffset;
+	flash->cell[i].erase_time = jiffies;
+	flash->cell[i].erase_retries = 0;
+	set_global_lock(dev->ESRwin, dev->ESRbase, 0);
+	/* Disable busy signal during the erase */
+	set_rdy_mode((u_short *)dev->Base, IF_RDY_DISABLE);
+	block_erase((u_short *)dev->Base);
+    } else {
+	/* Check on an already started erase */
+	ret = check_erase((u_short *)dev->Base);
+	if (ret == CS_SUCCESS)
+	    goto done;
+	else if (ret != CS_BUSY) {
+	    if (++flash->cell[i].erase_retries > retry_limit) {
+		printk(KERN_NOTICE "iflash2+_mtd: erase failed: "
+		       "too many retries!\n");
+		goto done;
+	    } else {
+		flash->cell[i].erase_time = jiffies;
+		abort_cmd((u_short *)dev->Base);
+		block_erase((u_short *)dev->Base);
+	    }
+	}
+    }
+
+    /* If the request is not complete, has it taken too long? */
+    if (jiffies > flash->cell[i].erase_time + erase_limit) {
+	printk(KERN_NOTICE "iflash2+_mtd: erase timed out!\n");
+	log_esr(NULL, (u_short *)dev->Base);
+	abort_cmd((u_short *)dev->Base);
+	ret = CS_GENERAL_FAILURE;
+	goto done;
+    }
+    req->Status = MTD_WAITTIMER;
+    req->Timeout = erase_timeout;
+    return CS_BUSY;
+    
+done:
+    DEBUG(2, "iflash2+_mtd: erase complete, time = %ld\n",
+	  jiffies - flash->cell[i].erase_time);
+    flash->cell[i].state &= ~(FLASH_ERASING|FLASH_PENDING);
+    reset_block((u_short *)dev->ESRbase);
+    set_global_lock(dev->ESRwin, dev->ESRbase, 1);
+    vpp_shutdown(link);
+    return ret;
+} /* flash_erase */
+    
+/*====================================================================*/
+
+static int flash_request(dev_link_t *link, void *buf, mtd_request_t *req)
+{
+    int ret = 0;
+    
+    if (!(link->state & DEV_PRESENT))
+	return CS_NO_CARD;
+
+    if (link->state & DEV_BUSY) {
+	/* We do this because the erase routine uses the TIMEOUT flag
+	   to decide if this is a new request or a status check, so
+	   we need to propagate it */
+	if (req->Function & MTD_REQ_TIMEOUT) {
+	    req->Timeout = erase_timeout;
+	    req->Status = MTD_WAITTIMER;
+	} else
+	    req->Status = MTD_WAITREQ;
+	return CS_BUSY;
+    }
+    
+    switch (req->Function & MTD_REQ_ACTION) {
+    case MTD_REQ_READ:
+	ret = flash_read(link, buf, req);
+	break;
+    case MTD_REQ_WRITE:
+	ret = flash_write(link, buf, req);
+	break;
+    case MTD_REQ_ERASE:
+	ret = flash_erase(link, buf, req);
+	break;
+    case MTD_REQ_COPY:
+	ret = CS_UNSUPPORTED_FUNCTION;
+	break;
+    }
+    if (!(link->state & DEV_PRESENT))
+	return CS_GENERAL_FAILURE;
+    return ret;
+} /* flash_request */
+
+/*======================================================================
+
+    The card status event handler.  Mostly, this schedules other
+    stuff to run after an event is received.  A CARD_REMOVAL event
+    also sets some flags to discourage the driver from trying to
+    talk to the card any more.
+    
+======================================================================*/
+
+static int flash_event(event_t event, int priority,
+		       event_callback_args_t *args)
+{
+    dev_link_t *link = args->client_data;
+
+    DEBUG(3, "iflash2+_mtd: flash_event(0x%06x)\n", event);
+    
+    switch (event) {
+	
+    case CS_EVENT_CARD_REMOVAL:
+	link->state &= ~DEV_PRESENT;
+	if (link->state & DEV_CONFIG)
+	    mod_timer(&link->release, jiffies + HZ/20);
+	break;
+	
+    case CS_EVENT_CARD_INSERTION:
+	link->state |= DEV_PRESENT | DEV_CONFIG_PENDING;
+	flash_config(link);
+	break;
+
+    case CS_EVENT_READY_CHANGE:
+	wake_up_interruptible(&link->pending);
+	break;
+	
+    case CS_EVENT_PM_SUSPEND:
+	link->state |= DEV_SUSPEND;
+	/* Fall through... */
+    case CS_EVENT_RESET_PHYSICAL:
+	break;
+	
+    case CS_EVENT_PM_RESUME:
+	link->state &= ~DEV_SUSPEND;
+	/* Fall through... */
+    case CS_EVENT_CARD_RESET:
+	break;
+	
+    case CS_EVENT_MTD_REQUEST:
+	return flash_request(link, args->buffer, args->mtdrequest);
+	break;
+	
+    }
+    return CS_SUCCESS;
+} /* flash_event */
+
+/*====================================================================*/
+
+#ifdef __LINUX__
+
+static int __init init_iflash2x_mtd(void)
+{
+    servinfo_t serv;
+    
+    DEBUG(0, "%s\n", version);
+    
+    /* Rescale parameters */
+    vpp_timeout_period = (vpp_timeout_period * HZ) / 1000;
+    vpp_settle = (vpp_settle * HZ) / 1000;
+    write_timeout = (write_timeout * HZ) / 1000;
+    erase_limit = (erase_limit * HZ) / 1000;
+    
+    CardServices(GetCardServicesInfo, &serv);
+    if (serv.Revision != CS_RELEASE_CODE) {
+	printk(KERN_NOTICE "iflash2+_mtd: Card Services release "
+	       "does not match!\n");
+	return -1;
+    }
+    
+    register_pccard_driver(&dev_info, &flash_attach, &flash_detach);
+
+    return 0;
+}
+
+static void __exit exit_iflash2x_mtd(void)
+{
+    DEBUG(0, "iflash2+_mtd: unloading\n");
+    unregister_pccard_driver(&dev_info);
+    while (dev_list != NULL)
+	flash_detach(dev_list);
+}
+
+module_init(init_iflash2x_mtd);
+module_exit(exit_iflash2x_mtd);
+
+#endif /* __LINUX__ */
Index: oldkernel/linux/pcmcia-cs-3.1.15/clients/iflash2_mtd.c
diff -u /dev/null linux/pcmcia-cs-3.1.15/clients/iflash2_mtd.c:1.1
--- /dev/null	Mon Jul 31 21:15:10 2000
+++ linux/pcmcia-cs-3.1.15/clients/iflash2_mtd.c	Fri Jul  7 16:34:58 2000
@@ -0,0 +1,1106 @@
+/*======================================================================
+
+    A simple MTD for Intel Series 2 and Series 100 Flash devices
+
+    iflash2_mtd.c 1.55 2000/05/16 21:31:36
+
+    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@pcmcia.sourceforge.org>.  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.
+    
+    For efficiency and simplicity, this driver is very block oriented.
+    Reads and writes must not span erase block boundaries.  Erases
+    are limited to one erase block per request.  This makes it much
+    easier to manage multiple asynchronous erases efficiently.
+    
+======================================================================*/
+
+#include <pcmcia/config.h>
+#include <pcmcia/k_compat.h>
+
+#ifdef __LINUX__
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/sched.h>
+#include <linux/ptrace.h>
+#include <linux/malloc.h>
+#include <linux/string.h>
+#include <linux/timer.h>
+#include <linux/major.h>
+#include <linux/fs.h>
+#include <linux/delay.h>
+#include <asm/io.h>
+#include <asm/system.h>
+#include <asm/segment.h>
+#endif
+
+#include <stdarg.h>
+
+#include <pcmcia/version.h>
+#include <pcmcia/cs_types.h>
+#include <pcmcia/cs.h>
+#include <pcmcia/bulkmem.h>
+#include <pcmcia/cisreg.h>
+#include <pcmcia/cistpl.h>
+#include <pcmcia/ds.h>
+#include <pcmcia/mem_op.h>
+#include "iflash.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_INFO args); } while (0)
+static char *version =
+"iflash2_mtd.c 1.55 2000/05/16 21:31:36 (David Hinds)";
+#else
+#define DEBUG(n, args...) do { } while (0)
+#endif
+
+/*====================================================================*/
+
+/* Parameters that can be set with 'insmod' */
+
+/*====================================================================*/
+
+/* Parameters that can be set with 'insmod' */
+
+static int word_width = 1;			/* 1 = 16-bit */
+static int mem_speed = 0;			/* in ns */
+static int vpp_timeout_period	= 1000;		/* in ms */
+static int vpp_settle		= 100;		/* in ms */
+static int erase_timeout	= 100;		/* in ms */
+static int erase_limit		= 10000;	/* in ms */
+static int retry_limit		= 4;		/* write retries */
+static u_int max_tries       	= 4096;		/* status polling */
+
+MODULE_PARM(word_width, "i");
+MODULE_PARM(mem_speed, "i");
+MODULE_PARM(vpp_timeout_period, "i");
+MODULE_PARM(vpp_settle, "i");
+MODULE_PARM(erase_timeout, "i");
+MODULE_PARM(erase_limit, "i");
+MODULE_PARM(retry_limit, "i");
+MODULE_PARM(max_tries, "i");
+
+/*====================================================================*/
+
+static void flash_config(dev_link_t *link);
+static void flash_release(u_long arg);
+static int flash_event(event_t event, int priority,
+		       event_callback_args_t *args);
+
+static dev_link_t *flash_attach(void);
+static void flash_detach(dev_link_t *);
+
+#define MAX_CELLS		32
+
+/* A flash region is composed of one or more "cells", where we allow
+   simultaneous erases if they are in different cells */
+typedef struct flash_region_t {
+    region_info_t	region;
+    u_int		cell_size;
+    struct flash_cell_t {
+	u_int		state;
+	k_time_t	erase_time;
+	u_int		erase_addr;
+	u_int		erase_retries;
+    } cell[MAX_CELLS];
+} flash_region_t;
+
+typedef struct flash_dev_t {
+    dev_link_t		link;
+    caddr_t		Base;
+    u_int		Size;
+    u_int		vpp;
+    int			vpp_usage;
+    k_time_t		vpp_start;
+    struct timer_list	vpp_timeout;
+    flash_region_t	*flash[2*CISTPL_MAX_DEVICES];
+} flash_dev_t;
+
+#define FLASH_PENDING		0x01
+#define FLASH_ERASING		0x02
+#define FLASH_ERASE_SUSPEND	0x04
+
+static dev_info_t dev_info = "iflash2_mtd";
+
+static dev_link_t *dev_list = NULL;
+
+#ifdef __BEOS__
+static cs_client_module_info *cs;
+static ds_module_info *ds;
+static isa_module_info *isa;
+#define CardServices		cs->_CardServices
+#define MTDHelperEntry		cs->_MTDHelperEntry
+#define add_timer		cs->_add_timer
+#define del_timer		cs->_del_timer
+#define register_pccard_driver	ds->_register_pccard_driver
+#define unregister_pccard_driver ds->_unregister_pccard_driver
+#endif
+
+/*====================================================================*/
+
+static void cs_error(client_handle_t handle, int func, int ret)
+{
+    error_info_t err = { func, ret };
+    CardServices(ReportError, handle, &err);
+}
+
+/*======================================================================
+
+    Low level routines for programming the flash card.
+    
+======================================================================*/
+
+static void abort_cmd(dev_link_t *link, volatile caddr_t base,
+		      int cell, mtd_mod_win_t *old)
+{
+    u_char *addr = base + CISREG_SLEEP + ((cell>>3)<<1);
+    /* Map the CIS register page into memory */
+    mtd_mod_win_t mod = { WIN_MEMORY_TYPE_AM, 250, 0x4000 };
+    DEBUG(1, "iflash2_mtd: abort\n");
+    MTDHelperEntry(MTDModifyWindow, link->win, &mod);
+    /* Put the cell to sleep, then wake it up again */
+    writeb(readb(addr) | (1 << (cell & 7)), addr);
+    udelay(10L);
+    writeb(readb(addr) & ~(1 << (cell & 7)), addr);
+    udelay(10L);
+    /* Restore the original memory window mapping */
+    MTDHelperEntry(MTDModifyWindow, link->win, old);
+}
+
+static inline int byte_write(volatile u_char *address, u_char data)
+{
+    register u_char CSR = 0;
+    register u_short i;
+    for (i = 0; i < max_tries; i++) {
+	CSR = readb(address);
+	if (CSR & LOW(CSR_WR_READY)) {
+	    writeb(LOW(IF_WRITE), address);
+	    writeb(data, address);
+	    return CS_SUCCESS;
+	}
+    }
+    printk(KERN_NOTICE "iflash2_mtd: byte_write timed out at 0x%p, "
+	   "CSR = 0x%x\n", address, CSR);
+    return CS_WRITE_FAILURE;
+}
+
+static inline int word_write(volatile u_short *address, u_short data)
+{
+    register u_short CSR = 0, i;
+
+    for (i = 0; i < max_tries; i++) {
+	CSR = readw(address);
+	if ((CSR & CSR_WR_READY) == CSR_WR_READY) {
+	    writew(IF_WRITE, address);
+	    writew(data, address);
+	    return CS_SUCCESS;
+	}
+    }
+    printk(KERN_NOTICE "iflash2_mtd: word_write timed out at 0x%p, "
+	   "CSR = 0x%x\n", address, CSR);
+    return CS_WRITE_FAILURE;
+}
+
+static int check_write(volatile u_short *address)
+{
+    u_short CSR = 0, i;
+    writew(IF_READ_CSR, address);
+    for (i = 0; i < max_tries; i++) {
+	CSR = readw(address);
+	if ((CSR & CSR_WR_READY) == CSR_WR_READY) break;
+    }
+    if (i == max_tries) {
+	printk(KERN_NOTICE "iflash2_mtd: check_write timed out!"
+	       "  CSR = 0x%x\n", CSR);
+	return CS_GENERAL_FAILURE;
+    }
+    if (CSR & (CSR_WR_ERR | CSR_VPP_LOW)) {
+	printk(KERN_NOTICE "iflash2_mtd: write error: CSR = 0x%x\n",
+	       CSR);
+	return CS_WRITE_FAILURE;
+    } else
+	return CS_SUCCESS;
+}
+
+static void block_erase(volatile u_short *address)
+{
+    writew(IF_BLOCK_ERASE, address);
+    writew(IF_CONFIRM, address);
+}
+
+static int check_erase(volatile u_short *address)
+{
+    u_short CSR;
+    writew(IF_READ_CSR, address);
+    CSR = readw(address);
+    if ((CSR & CSR_WR_READY) != CSR_WR_READY)
+	return CS_BUSY;
+    else if (CSR & (CSR_ERA_ERR | CSR_VPP_LOW | CSR_WR_ERR)) {
+	printk(KERN_NOTICE "iflash2_mtd: erase failed: CSR = 0x%x\n",
+	       CSR);
+	return CS_WRITE_FAILURE;
+    } else
+	return CS_SUCCESS;
+}
+
+static int suspend_erase(volatile u_short *address)
+{
+    u_short CSR = 0;
+    u_int i;
+
+    writew(IF_ERASE_SUSPEND, address);
+    writew(IF_READ_CSR, address);
+    for (i = 0; i < max_tries; i++) {
+	CSR = readw(address);
+	if ((CSR & CSR_WR_READY) == CSR_WR_READY) break;
+    }
+    if (i == max_tries) {
+	printk(KERN_NOTICE "iflash2_mtd: suspend_erase timed out: "
+	       "CSR = 0x%x\n", CSR);
+	return CS_GENERAL_FAILURE;
+    }
+    writew(IF_READ_ARRAY, address);
+    return CS_SUCCESS;
+}
+
+static void resume_erase(volatile u_short *address)
+{
+    u_short CSR;
+    writew(IF_READ_CSR, address);
+    CSR = readw(address);
+    /* Only give resume signal if the erase is really suspended */
+    if (CSR & CSR_ERA_SUSPEND)
+	writew(IF_CONFIRM, address);
+}
+
+static void reset_block(volatile u_short *address)
+{
+    u_short CSR, i;
+    writew(IF_CLEAR_CSR, address);
+    for (i = 0; i < 100; i++) {
+	writew(IF_READ_CSR, address);
+	CSR = readw(address);
+	if (CSR != 0xffff) break;
+	udelay(1000);
+    }
+#ifdef PCMCIA_DEBUG
+    if (i)
+	printk(KERN_DEBUG "iflash2_mtd: reset after %d iterations\n", i);
+#endif
+    writew(IF_READ_ARRAY, address);
+}
+
+/*======================================================================
+
+    Vpp management functions.  The vpp_setup() function checks to
+    see if Vpp is available for the specified device.  If not, it
+    turns on Vpp.  The vpp_shutdown() function is scheduled to turn
+    Vpp off after an interval of inactivity.
+
+    vpp_setup() assumes that it will be called at the top of a
+    request handler, and that it can use the MTD_REQ_TIMEOUT flag
+    to tell if it has already been called for this particular
+    request, so that it can count Vpp users.
+
+    A handler should call vpp_shutdown() once for each request that
+    does a vpp_setup().
+    
+======================================================================*/
+
+static int vpp_setup(dev_link_t *link, mtd_request_t *req)
+{
+    flash_dev_t *dev = (flash_dev_t *)link->priv;
+    mtd_vpp_req_t vpp_req;
+
+    /* First, do we need to do this? */
+    if (!dev->vpp) return 0;
+    
+    /* First time for this request? */
+    if (!(req->Function & MTD_REQ_TIMEOUT)) {
+	/* If no other users, kill shutdown timer and apply power */
+	if (++dev->vpp_usage == 1) {
+	    if (!del_timer(&dev->vpp_timeout)) {
+		DEBUG(1, "iflash2_mtd: raising Vpp...\n");
+		dev->vpp_start = jiffies;
+		vpp_req.Vpp1 = vpp_req.Vpp2 = dev->vpp;
+		MTDHelperEntry(MTDSetVpp, link->handle, &vpp_req);
+	    }
+	}
+    }
+    /* Wait for Vpp to settle if it was just applied */
+    if (jiffies < dev->vpp_start + vpp_settle) {
+	req->Status = MTD_WAITTIMER;
+	req->Timeout = vpp_settle * 1000 / HZ;
+	return 1;
+    }
+    return 0;
+}
+
+static void vpp_off(u_long arg)
+{
+    dev_link_t *link = (dev_link_t *)arg;
+    flash_dev_t *dev = (flash_dev_t *)link->priv;
+    mtd_vpp_req_t req;
+
+    if (!dev->vpp) return;
+    DEBUG(1, "iflash2_mtd: lowering Vpp...\n");
+    dev->vpp_timeout.expires = 0;
+    req.Vpp1 = req.Vpp2 = 0;
+    MTDHelperEntry(MTDSetVpp, link->handle, &req);
+}
+
+static void vpp_shutdown(dev_link_t *link)
+{
+    flash_dev_t *dev = (flash_dev_t *)link->priv;
+    if (!dev->vpp) return;
+    dev->vpp_usage--;
+    if (dev->vpp_usage == 0) {
+	dev->vpp_timeout.expires = jiffies + vpp_timeout_period;
+	add_timer(&dev->vpp_timeout);
+    }
+}
+
+/*======================================================================
+
+    flash_attach() creates an "instance" of the driver, allocating
+    local data structures for one device.  The device is registered
+    with Card Services.
+
+======================================================================*/
+
+static dev_link_t *flash_attach(void)
+{
+    client_reg_t client_reg;
+    dev_link_t *link;
+    flash_dev_t *dev;
+    int ret;
+    
+    DEBUG(0, "iflash2_mtd: flash_attach()\n");
+
+    /* Create new memory card device */
+    dev = kmalloc(sizeof(*dev), GFP_KERNEL);
+    if (!dev) return NULL;
+    memset(dev, 0, sizeof(*dev));
+    link = &dev->link; link->priv = dev;
+
+    link->release.function = &flash_release;
+    link->release.data = (u_long)link;
+
+    dev->vpp_timeout.function = vpp_off;
+    dev->vpp_timeout.data = (u_long)link;
+
+    /* Register with Card Services */
+    link->next = dev_list;
+    dev_list = link;
+    client_reg.dev_info = &dev_info;
+    client_reg.Attributes = INFO_MTD_CLIENT | INFO_CARD_SHARE;
+    client_reg.EventMask =
+	CS_EVENT_RESET_PHYSICAL | CS_EVENT_CARD_RESET |
+	CS_EVENT_CARD_INSERTION | CS_EVENT_CARD_REMOVAL |
+	CS_EVENT_PM_SUSPEND | CS_EVENT_PM_RESUME;
+    client_reg.event_handler = &flash_event;
+    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);
+	flash_detach(link);
+	return NULL;
+    }
+    
+    return link;
+} /* flash_attach */
+
+/*======================================================================
+
+    This deletes a driver "instance".  The device is de-registered
+    with Card Services.  If it has been released, all local data
+    structures are freed.  Otherwise, the structures will be freed
+    when the device is released.
+
+======================================================================*/
+
+static void flash_detach(dev_link_t *link)
+{
+    dev_link_t **linkp;
+    int ret;
+
+    DEBUG(0, "iflash2_mtd: flash_detach(0x%p)\n", link);
+    
+    /* Locate device structure */
+    for (linkp = &dev_list; *linkp; linkp = &(*linkp)->next)
+	if (*linkp == link) break;
+    if (*linkp == NULL)
+	return;
+
+    del_timer(&link->release);
+    if (link->state & DEV_CONFIG)
+	flash_release((u_long)link);
+
+    if (link->handle) {
+	ret = CardServices(DeregisterClient, link->handle);
+	if (ret != CS_SUCCESS)
+	    cs_error(link->handle, DeregisterClient, ret);
+    }
+    
+    /* Unlink device structure, free bits */
+    *linkp = link->next;
+    kfree(link->priv);
+    
+} /* flash_detach */
+
+/*======================================================================
+
+    flash_config() is scheduled to run after a CARD_INSERTION event
+    is received, to bind the MTD to appropriate memory regions.
+    
+======================================================================*/
+
+static void printk_size(u_int sz)
+{
+    if (sz & 0x3ff)
+	printk("%u bytes", sz);
+    else if (sz & 0x0fffff)
+	printk("%u kb", sz >> 10);
+    else
+	printk("%u mb", sz >> 20);
+}
+
+static void flash_config(dev_link_t *link)
+{
+    client_handle_t handle = link->handle;
+    flash_dev_t *dev = link->priv;
+    win_req_t req;
+    mtd_reg_t reg;
+    region_info_t region;
+    int i, attr, ret;
+
+    DEBUG(0, "iflash2_mtd: flash_config(0x%p)\n", link);
+
+    /* Allocate a small memory window */
+    if (word_width)
+	req.Attributes = WIN_DATA_WIDTH_16;
+    else
+	req.Attributes = WIN_DATA_WIDTH_8;
+    req.Base = req.Size = 0;
+    req.AccessSpeed = mem_speed;
+    link->win = (window_handle_t)handle;
+    ret = MTDHelperEntry(MTDRequestWindow, &link->win, &req);
+    if (ret != 0) {
+	cs_error(handle, RequestWindow, ret);
+	link->state &= ~DEV_CONFIG_PENDING;
+	flash_release((u_long)link);
+	return;
+    }
+    dev->Base = ioremap(req.Base, req.Size);
+    dev->Size = req.Size;
+
+    link->state |= DEV_CONFIG;
+
+    /* Grab info for all the memory regions we can access */
+    i = 0;
+    for (attr = 0; attr < 2; attr++) {
+	region.Attributes = attr ? REGION_TYPE_AM : REGION_TYPE_CM;
+	ret = CardServices(GetFirstRegion, handle, &region);
+	while (ret == CS_SUCCESS) {
+	    reg.Attributes = region.Attributes;
+	    reg.Offset = region.CardOffset;
+	    dev->flash[i] = kmalloc(sizeof(struct flash_region_t),
+				    GFP_KERNEL);
+	    if (!dev->flash[i]) break;
+	    reg.MediaID = (u_long)dev->flash[i];
+	    ret = CardServices(RegisterMTD, handle, &reg);
+	    if (ret != 0) {
+		kfree(dev->flash[i]);
+		break;
+	    }
+	    printk(KERN_INFO "iflash2_mtd: %s at 0x%x, ",
+		   attr ? "attr" : "common", region.CardOffset);
+	    printk_size(region.RegionSize);
+	    printk(", ");
+	    printk_size(region.BlockSize);
+	    printk(" blocks, %u ns\n", region.AccessSpeed);
+	    memset(dev->flash[i], 0, sizeof(struct flash_region_t));
+	    /* Assume 128K blocks, if no geometry info present */
+	    if (region.BlockSize == 1)
+		region.BlockSize = 0x20000;
+	    dev->flash[i]->region = region;
+	    /* If not Series 100, then we'll use Vpp=12V */
+	    if (region.JedecInfo != 0xaa) dev->vpp = 120;
+	    /* All Series 2 cards have 2MB component pairs */
+	    dev->flash[i]->cell_size = 0x200000;
+	    i++;
+	    ret = CardServices(GetNextRegion, handle, &region);
+	}
+    }
+    dev->flash[i] = NULL;
+    
+} /* flash_config */
+
+/*======================================================================
+
+    After a card is removed, flash_release() will release the memory
+    window allocated for this socket.
+    
+======================================================================*/
+
+static void flash_release(u_long arg)
+{
+    dev_link_t *link = (dev_link_t *)arg;
+    flash_dev_t *dev = link->priv;
+    int i;
+
+    DEBUG(0, "iflash2_mtd: flash_release(0x%p)\n", link);
+
+    link->state &= ~DEV_CONFIG;
+    if (link->win) {
+	iounmap(dev->Base);
+	i = MTDHelperEntry(MTDReleaseWindow, link->win);
+	if (i != CS_SUCCESS)
+	    cs_error(link->handle, ReleaseWindow, i);
+    }
+    if (dev->vpp_usage == 0)
+	del_timer(&dev->vpp_timeout);
+    vpp_off((u_long)link);
+    for (i = 0; (i < 2*CISTPL_MAX_DEVICES) && dev->flash[i]; i++)
+	kfree(dev->flash[i]);
+    
+    if (link->state & DEV_STALE_LINK)
+	flash_detach(link);
+    
+} /* flash_release */
+
+/*======================================================================
+
+    The read request handler.  This handler supports suspending
+    current erase requests.  Reading from a block that is currently
+    erasing is undefined.
+    
+======================================================================*/
+
+static int flash_read(dev_link_t *link, char *buf, mtd_request_t *req)
+{
+    flash_dev_t *dev = (flash_dev_t *)link->priv;
+    flash_region_t *flash;
+    region_info_t *region;
+    mtd_mod_win_t mod;
+    u_int from, length, nb, cell;
+    u_long time;
+    int ret;
+    
+    DEBUG(2, "iflash2_mtd: flash_read(0x%p, 0x%lx, 0x%p, 0x%x, "
+	  "0x%x)\n", link, req->MediaID, buf, req->SrcCardOffset,
+	  req->TransferLength);
+
+    flash = (flash_region_t *)(req->MediaID);
+    region = &flash->region;
+    if ((req->SrcCardOffset / region->BlockSize) !=
+	((req->SrcCardOffset+req->TransferLength-1) / region->BlockSize))
+	return CS_BAD_SIZE;
+    if (region->Attributes & REGION_TYPE_AM)
+	mod.Attributes = WIN_MEMORY_TYPE_AM;
+    else
+	mod.Attributes = WIN_MEMORY_TYPE_CM;
+    mod.AccessSpeed = region->AccessSpeed;
+
+    /* Suspend an in-progress block erase */
+    cell = (req->SrcCardOffset - region->CardOffset) / flash->cell_size;
+    if (flash->cell[cell].state & FLASH_ERASING) {
+	if ((flash->cell[cell].erase_addr / region->BlockSize) ==
+	    (req->SrcCardOffset / region->BlockSize)) {
+	    req->Status = MTD_WAITREQ;
+	    return CS_BUSY;
+	}
+	link->state |= DEV_BUSY;
+	mod.CardOffset = flash->cell[cell].erase_addr;
+	ret = MTDHelperEntry(MTDModifyWindow, link->win, &mod);
+	if (ret != CS_SUCCESS) goto done;
+	ret = suspend_erase((u_short *)dev->Base);
+	if (ret != CS_SUCCESS) goto done;
+	flash->cell[cell].state |= FLASH_ERASE_SUSPEND;
+    } else
+	link->state |= DEV_BUSY;
+
+    mod.CardOffset = req->SrcCardOffset & ~(dev->Size-1);
+    from = req->SrcCardOffset & (dev->Size-1);
+    
+    ret = CS_SUCCESS;
+    time = jiffies;
+    for (length = req->TransferLength; length > 0; length -= nb) {
+	
+	ret = MTDHelperEntry(MTDModifyWindow, link->win, &mod);
+	if (ret != CS_SUCCESS) goto done;
+	nb = (from+length > dev->Size) ? dev->Size-from : length;
+
+	if (req->Function & MTD_REQ_KERNEL)
+	    copy_from_pc(buf, &dev->Base[from], nb);
+	else
+	    copy_pc_to_user(buf, &dev->Base[from], nb);
+	
+	buf += nb;
+	from = 0;
+	mod.CardOffset += dev->Size;
+    }
+    
+#ifdef PCMCIA_DEBUG
+    time = jiffies - time;
+    if (time > 1)
+	DEBUG(3, "iflash2_mtd: read complete, time = %ld, "
+	      "avg = %ld ns/word, rate = %ld kb/sec\n", time,
+	      time*20000000/req->TransferLength,
+	      req->TransferLength*100/(time*1024));
+#endif
+    
+done:
+    if (flash->cell[cell].state & FLASH_ERASE_SUSPEND) {
+	mod.CardOffset = flash->cell[cell].erase_addr;
+	ret = MTDHelperEntry(MTDModifyWindow, link->win, &mod);
+	if (ret == CS_SUCCESS)
+	    resume_erase((u_short *)dev->Base);
+	flash->cell[cell].state &= ~FLASH_ERASE_SUSPEND;
+    }
+    link->state &= ~DEV_BUSY;
+    return ret;
+} /* flash_read */
+
+/*======================================================================
+
+    basic_write() handles a write that fits completely within a
+    memory window that has already been set up.
+    
+======================================================================*/
+
+static int basic_write(char *dest, char *buf,
+		       u_int nb, u_int is_krnl)
+{
+    char *start = dest;
+    int ret;
+    
+    *(u_short *)dest = IF_READ_CSR;
+    if (is_krnl) {
+	if (nb & 1) {
+	    ret = byte_write(dest, *buf);
+	    if (ret != CS_SUCCESS) return ret;
+		dest++; buf++; nb--;
+	}
+	for (; nb != 0; dest += 2, buf += 2, nb -= 2) {
+	    ret = word_write((u_short *)dest, *(u_short *)buf);
+	    if (ret != CS_SUCCESS) return ret;
+	}
+    } else {
+	if (nb & 1) {
+	    char c;
+	    get_user(c, buf);
+	    ret = byte_write(dest, c);
+	    if (ret != CS_SUCCESS) return ret;
+	    dest++; buf++; nb--;
+	}
+	for (; nb != 0; dest += 2, buf += 2, nb -= 2) {
+	    u_short s;
+	    get_user(s, (u_short *)buf);
+	    ret = word_write((u_short *)dest, s);
+	    if (ret != CS_SUCCESS) return ret;
+	}
+    }
+    return check_write((u_short *)start);
+	
+} /* basic_write */
+
+/*======================================================================
+
+    The write request handler.  The Series 2+ cards support automatic
+    erase suspend for writes.
+    
+======================================================================*/
+
+static int flash_write(dev_link_t *link, char *buf, mtd_request_t *req)
+{
+    flash_dev_t *dev = (flash_dev_t *)link->priv;
+    mtd_mod_win_t mod;
+    flash_region_t *flash;
+    region_info_t *region;
+    u_int from, length, nb, retry, cell;
+    u_long time;
+    cs_status_t status;
+    int ret;
+
+    DEBUG(2, "iflash2_mtd: flash_write(0x%p, 0x%lx, 0x%p, 0x%x, "
+	  "0x%x)\n", link, req->MediaID, buf, req->DestCardOffset,
+	  req->TransferLength);
+
+    /* Check card write protect status */
+    ret = CardServices(GetStatus, link->handle, &status);
+    if (ret != CS_SUCCESS) {
+	cs_error(link->handle, GetStatus, ret);
+	return CS_GENERAL_FAILURE;
+    }
+    if (status.CardState & CS_EVENT_WRITE_PROTECT)
+	return CS_WRITE_PROTECTED;
+
+    flash = (flash_region_t *)(req->MediaID);
+    region = &flash->region;
+    if ((req->DestCardOffset / region->BlockSize) !=
+	((req->DestCardOffset+req->TransferLength-1) / region->BlockSize))
+	return CS_BAD_SIZE;
+    
+    if (vpp_setup(link, req) != 0)
+	return CS_BUSY;
+
+    /* Is this cell being erased? */
+    cell = (req->DestCardOffset - region->CardOffset) / flash->cell_size;
+    if (flash->cell[cell].state & FLASH_ERASING) {
+	req->Status = MTD_WAITREQ;
+	return CS_BUSY;
+    }
+    link->state |= DEV_BUSY;
+    
+    if (region->Attributes & REGION_TYPE_AM)
+	mod.Attributes = WIN_MEMORY_TYPE_AM;
+    else
+	mod.Attributes = WIN_MEMORY_TYPE_CM;
+    mod.AccessSpeed = region->AccessSpeed;
+
+    time = jiffies;
+    mod.CardOffset = req->DestCardOffset & ~(dev->Size-1);
+    from = req->DestCardOffset & (dev->Size-1);
+    
+    for (length = req->TransferLength ; length > 0; length -= nb) {
+
+	nb = (from+length > dev->Size) ? dev->Size-from : length;
+	ret = MTDHelperEntry(MTDModifyWindow, link->win, &mod);
+	if (ret != CS_SUCCESS) goto done;
+
+	for (retry = 0; retry < retry_limit; retry++) {
+	    ret = basic_write(dev->Base+from, buf, nb,
+			      (req->Function & MTD_REQ_KERNEL));
+	    if (ret == CS_SUCCESS)
+		break;
+	    abort_cmd(link, dev->Base, cell, &mod);
+	}
+	if (retry == retry_limit) {
+	    printk(KERN_NOTICE "iflash2_mtd: write failed: "
+		   "too many retries!\n");
+	    goto done;
+	}
+	
+	buf += nb;
+	from = 0;
+	mod.CardOffset += dev->Size;
+    }
+
+#ifdef PCMCIA_DEBUG
+    time = jiffies - time;
+    if (time > 1)
+	DEBUG(3, "iflash2_mtd: write complete, time = %ld, "
+	      "avg = %ld us/word, rate = %ld kb/sec\n", time,
+	      time*20000/req->TransferLength,
+	      req->TransferLength*100/(time*1024));
+#endif
+    
+done:
+    reset_block((u_short *)dev->Base);
+    link->state &= ~DEV_BUSY;
+    /* Fire up the Vpp timer */
+    vpp_shutdown(link);
+    return ret;
+} /* flash_write */
+
+/*======================================================================
+
+    The erase request handler.  This handler supports simultaneous
+    erases in different device components.
+    
+======================================================================*/
+
+static int flash_erase(dev_link_t *link, char *buf, mtd_request_t *req)
+{
+    flash_dev_t *dev = (flash_dev_t *)link->priv;
+    cs_status_t status;
+    flash_region_t *flash;
+    region_info_t *region;
+    mtd_mod_win_t mod;
+    int i, ret;
+
+    DEBUG(2, "iflash2_mtd: flash_erase(0x%p, 0x%lx, 0x%x, 0x%x)\n",
+	  link, req->MediaID, req->DestCardOffset,
+	  req->TransferLength);
+
+    flash = (flash_region_t *)(req->MediaID);
+    region = &flash->region;
+    if (region->BlockSize != req->TransferLength)
+	return CS_BAD_SIZE;
+    
+    i = (req->DestCardOffset-region->CardOffset)/flash->cell_size;
+    
+    if (!(req->Function & MTD_REQ_TIMEOUT)) {
+	if (flash->cell[i].state & (FLASH_ERASING|FLASH_PENDING)) {
+	    req->Status = MTD_WAITREQ;
+	    return CS_BUSY;
+	}
+	/* Check card write protect status */
+	ret = CardServices(GetStatus, link->handle, &status);
+	if (ret != CS_SUCCESS) {
+	    cs_error(link->handle, GetStatus, ret);
+	    return CS_GENERAL_FAILURE;
+	}
+	if (status.CardState & CS_EVENT_WRITE_PROTECT)
+	    return CS_WRITE_PROTECTED;
+	flash->cell[i].state |= FLASH_PENDING;
+	/* Activate Vpp if necessary */
+	if (vpp_setup(link, req) != 0)
+	    return CS_BUSY;
+    }
+
+    if (region->Attributes & REGION_TYPE_AM)
+	mod.Attributes = WIN_MEMORY_TYPE_AM;
+    else
+	mod.Attributes = WIN_MEMORY_TYPE_CM;
+    mod.AccessSpeed = region->AccessSpeed;
+    mod.CardOffset = req->DestCardOffset;
+    ret = MTDHelperEntry(MTDModifyWindow, link->win, &mod);
+    if (ret != CS_SUCCESS)
+	goto done;
+    
+    if (flash->cell[i].state & FLASH_PENDING) {
+	/* Start a new block erase */
+	flash->cell[i].state &= ~FLASH_PENDING;
+	flash->cell[i].state |= FLASH_ERASING;
+	flash->cell[i].erase_addr = mod.CardOffset;
+	flash->cell[i].erase_time = jiffies;
+	flash->cell[i].erase_retries = 0;
+	block_erase((u_short *)dev->Base);
+    } else {
+	/* Check on an already started erase */
+	ret = check_erase((u_short *)dev->Base);
+	if (ret == CS_SUCCESS)
+	    goto done;
+	else if (ret != CS_BUSY) {
+	    if (++flash->cell[i].erase_retries > retry_limit) {
+		printk(KERN_NOTICE "iflash2_mtd: erase failed: "
+		       "too many retries!\n");
+		goto done;
+	    } else {
+		flash->cell[i].erase_time = jiffies;
+		abort_cmd(link, dev->Base, i, &mod);
+		reset_block((u_short *)dev->Base);
+		block_erase((u_short *)dev->Base);
+	    }
+	}
+    }
+
+    /* If the request is not complete, has it taken too long? */
+    if (jiffies > flash->cell[i].erase_time + erase_limit) {
+	printk(KERN_NOTICE "iflash2_mtd: erase timed out!\n");
+	reset_block((u_short *)dev->Base);
+	ret = CS_GENERAL_FAILURE;
+	goto done;
+    }
+    req->Status = MTD_WAITTIMER;
+    req->Timeout = erase_timeout;
+    return CS_BUSY;
+    
+done:
+    DEBUG(2, "iflash2_mtd: erase complete, time = %ld\n",
+	  jiffies - flash->cell[i].erase_time);
+    flash->cell[i].state &= ~(FLASH_ERASING|FLASH_PENDING);
+    reset_block((u_short *)dev->Base);
+    vpp_shutdown(link);
+    return ret;
+} /* flash_erase */
+    
+/*====================================================================*/
+
+static int flash_request(dev_link_t *link, void *buf, mtd_request_t *req)
+{
+    int ret = 0;
+    
+    if (!(link->state & DEV_PRESENT))
+	return CS_NO_CARD;
+    
+    if (link->state & DEV_BUSY) {
+	/* We do this because the erase routine uses the TIMEOUT flag
+	   to decide if this is a new request or a status check, so
+	   we need to propagate it */
+	if (req->Function & MTD_REQ_TIMEOUT) {
+	    req->Timeout = erase_timeout;
+	    req->Status = MTD_WAITTIMER;
+	} else
+	    req->Status = MTD_WAITREQ;
+	return CS_BUSY;
+    }
+    
+    switch (req->Function & MTD_REQ_ACTION) {
+    case MTD_REQ_READ:
+	ret = flash_read(link, buf, req);
+	break;
+    case MTD_REQ_WRITE:
+	ret = flash_write(link, buf, req);
+	break;
+    case MTD_REQ_ERASE:
+	ret = flash_erase(link, buf, req);
+	break;
+    case MTD_REQ_COPY:
+	ret = CS_UNSUPPORTED_FUNCTION;
+	break;
+    }
+    if (!(link->state & DEV_PRESENT))
+	return CS_GENERAL_FAILURE;
+    return ret;
+} /* flash_request */
+
+/*======================================================================
+
+    The card status event handler.  Mostly, this schedules other
+    stuff to run after an event is received.  A CARD_REMOVAL event
+    also sets some flags to discourage the driver from trying to
+    talk to the card any more.
+    
+======================================================================*/
+
+static int flash_event(event_t event, int priority,
+		      event_callback_args_t *args)
+{
+    dev_link_t *link = args->client_data;
+
+    DEBUG(1, "iflash2_mtd: flash_event(0x%06x)\n", event);
+    
+    switch (event) {
+	
+    case CS_EVENT_CARD_REMOVAL:
+	link->state &= ~DEV_PRESENT;
+	if (link->state & DEV_CONFIG)
+	    mod_timer(&link->release, jiffies + HZ/20);
+	break;
+	
+    case CS_EVENT_CARD_INSERTION:
+	link->state |= DEV_PRESENT | DEV_CONFIG_PENDING;
+	flash_config(link);
+	break;
+
+    case CS_EVENT_PM_SUSPEND:
+	link->state |= DEV_SUSPEND;
+	/* Fall through... */
+    case CS_EVENT_RESET_PHYSICAL:
+	break;
+	
+    case CS_EVENT_PM_RESUME:
+	link->state &= ~DEV_SUSPEND;
+	/* Fall through... */
+    case CS_EVENT_CARD_RESET:
+	break;
+	
+    case CS_EVENT_MTD_REQUEST:
+	return flash_request(link, args->buffer, args->mtdrequest);
+	break;
+	
+    }
+    return CS_SUCCESS;
+} /* flash_event */
+
+/*====================================================================*/
+
+#ifdef __LINUX__
+
+static int __init init_iflash2_mtd(void)
+{
+    servinfo_t serv;
+    
+    DEBUG(0, "%s\n", version);
+
+    /* Rescale parameters */
+    vpp_timeout_period = (vpp_timeout_period * HZ) / 1000;
+    vpp_settle = (vpp_settle * HZ) / 1000;
+    erase_limit = (erase_limit * HZ) / 1000;
+    
+    CardServices(GetCardServicesInfo, &serv);
+    if (serv.Revision != CS_RELEASE_CODE) {
+	printk(KERN_NOTICE "iflash2_mtd: Card Services release "
+	       "does not match!\n");
+	return -1;
+    }
+    
+    register_pccard_driver(&dev_info, &flash_attach, &flash_detach);
+
+    return 0;
+}
+
+static void __exit exit_iflash2_mtd(void)
+{
+    DEBUG(0, "iflash2_mtd: unloading\n");
+    unregister_pccard_driver(&dev_info);
+    while (dev_list != NULL)
+	flash_detach(dev_list);
+}
+
+module_init(init_iflash2_mtd);
+module_exit(exit_iflash2_mtd);
+
+#endif /* __LINUX__ */
+
+/*====================================================================*/
+
+#ifdef __BEOS__
+
+static status_t std_ops(int32 op)
+{
+    int ret;
+    DEBUG(0, "iflash2_mtd: std_ops(%d)\n", op);
+    switch (op) {
+    case B_MODULE_INIT:
+	vpp_timeout_period = (vpp_timeout_period * HZ) / 1000;
+	vpp_settle = (vpp_settle * HZ) / 1000;
+	erase_limit = (erase_limit * HZ) / 1000;
+	ret = get_module(CS_CLIENT_MODULE_NAME, (struct module_info **)&cs);
+	if (ret != B_OK) return ret;
+	ret = get_module(DS_MODULE_NAME, (struct module_info **)&ds);
+	if (ret != B_OK) return ret;
+	ret = get_module(B_ISA_MODULE_NAME, (struct module_info **)&isa);
+	if (ret != B_OK) return ret;
+	register_pccard_driver(&dev_info, &flash_attach, &flash_detach);
+	break;
+    case B_MODULE_UNINIT:
+	unregister_pccard_driver(&dev_info);
+	while (dev_list != NULL)
+	    flash_detach(dev_list);
+	if (isa) put_module(B_ISA_MODULE_NAME);
+	if (ds) put_module(DS_MODULE_NAME);
+	if (cs) put_module(CS_CLIENT_MODULE_NAME);
+	break;
+    }
+    return B_OK;
+}
+
+static module_info flash_mtd_mod_info = {
+    MTD_MODULE_NAME("iflash2_mtd"), 0, &std_ops
+};
+
+_EXPORT module_info *modules[] = {
+    &flash_mtd_mod_info,
+    NULL
+};
+
+#endif /* __BEOS__ */
Index: oldkernel/linux/pcmcia-cs-3.1.15/clients/memory_cb.c
diff -u /dev/null linux/pcmcia-cs-3.1.15/clients/memory_cb.c:1.1
--- /dev/null	Mon Jul 31 21:15:10 2000
+++ linux/pcmcia-cs-3.1.15/clients/memory_cb.c	Fri Jul  7 16:34:58 2000
@@ -0,0 +1,341 @@
+/*======================================================================
+
+    A direct memory interface driver for CardBus cards
+
+    memory_cb.c 1.15 2000/05/16 21:31:36
+
+    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@pcmcia.sourceforge.org>.  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 <pcmcia/config.h>
+#include <pcmcia/k_compat.h>
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/sched.h>
+#include <linux/malloc.h>
+#include <linux/string.h>
+#include <linux/ioport.h>
+#include <linux/major.h>
+#include <linux/pci.h>
+#include <asm/io.h>
+
+#include <pcmcia/driver_ops.h>
+#include <pcmcia/mem_op.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 =
+"memory_cb.c 1.15 2000/05/16 21:31:36 (David Hinds)";
+#else
+#define DEBUG(n, args...)
+#endif
+
+/*====================================================================*/
+
+/* Parameters that can be set with 'insmod' */
+
+/*====================================================================*/
+
+typedef struct memory_dev_t {
+    dev_node_t		node;
+    struct pci_dev	*pdev;
+    u_int		open, stopped;
+    u_int		base[8];
+    u_int		size[8];
+    u_char		*virt[8];
+} memory_dev_t;
+
+#define MAX_DEV 8
+static memory_dev_t *dev_table[MAX_DEV] = { 0 };
+
+static int major_dev = 0;
+
+/*====================================================================*/
+
+#define FIND_FIRST_BIT(n)	((n) - ((n) & ((n)-1)))
+#define CB_BAR(n)		(PCI_BASE_ADDRESS_0+(4*(n)))
+#define CB_ROM_BASE		0x0030
+
+static dev_node_t *memory_attach(dev_locator_t *loc)
+{
+    u_char bus, devfn, cmd;
+    memory_dev_t *dev;
+    int i, br;
+    
+    if (loc->bus != LOC_PCI) return NULL;
+    bus = loc->b.pci.bus; devfn = loc->b.pci.devfn;
+    printk(KERN_INFO "memory_attach(device %02x:%02x.%d)\n",
+	   bus, PCI_SLOT(devfn), PCI_FUNC(devfn));
+
+    for (i = 0; i < MAX_DEV; i++)
+	if (dev_table[i] == NULL) break;
+    if (i == MAX_DEV) return NULL;
+    dev_table[i] = dev = kmalloc(sizeof(memory_dev_t), GFP_KERNEL);
+    memset(dev, 0, sizeof(memory_dev_t));
+    dev->pdev = pci_find_slot(bus, devfn);
+    sprintf(dev->node.dev_name, "cbmem%d", i);
+    dev->node.major = major_dev;
+    dev->node.minor = i<<3;
+    
+    dev->size[0] = 0x100;
+    printk(KERN_INFO "memory_cb: cbmem%d: 0 [256 b]", i);
+    pci_read_config_byte(dev->pdev, PCI_COMMAND, &cmd);
+    pci_write_config_byte(dev->pdev, PCI_COMMAND, 0);
+    for (i = 1; i < 8; i++) {
+	br = (i == 7) ? CB_ROM_BASE : CB_BAR(i-1);
+	pci_read_config_dword(dev->pdev, br, &dev->base[i]);
+	pci_write_config_dword(dev->pdev, br, 0xffffffff);
+	pci_read_config_dword(dev->pdev, br, &dev->size[i]);
+	pci_write_config_dword(dev->pdev, br, dev->base[i]);
+	dev->size[i] &= PCI_BASE_ADDRESS_MEM_MASK;
+	dev->size[i] = FIND_FIRST_BIT(dev->size[i]);
+	if (dev->size[i] == 0) continue;
+	if ((i == 7) || ((dev->base[i] & PCI_BASE_ADDRESS_SPACE) == 0)) {
+	    dev->base[i] &= PCI_BASE_ADDRESS_MEM_MASK;
+	    dev->virt[i] = ioremap(dev->base[i], dev->size[i]);
+	} else {
+	    dev->base[i] &= PCI_BASE_ADDRESS_IO_MASK;
+	}
+	if (dev->size[i] & 0x3ff)
+	    printk(", %d [%d b]", i, dev->size[i]);
+	else
+	    printk(", %d [%d kb]", i, dev->size[i]>>10);
+    }
+    printk("\n");
+    pci_write_config_byte(dev->pdev, PCI_COMMAND, cmd);
+    MOD_INC_USE_COUNT;
+    return &dev->node;
+}
+
+static void memory_detach(dev_node_t *node)
+{
+    memory_dev_t *dev = (memory_dev_t *)node;
+    int i;
+
+    dev->stopped = 1;
+    if (dev->open) return;
+    dev_table[node->minor >> 3] = NULL;
+    for (i = 0; i < 8; i++)
+	if (dev->virt[i] != NULL) iounmap(dev->virt[i]);
+    kfree(dev);
+    MOD_DEC_USE_COUNT;
+}
+
+/*====================================================================*/
+
+static int memory_open(struct inode *inode, struct file *file)
+{
+    int minor = MINOR(F_INODE(file)->i_rdev);
+    memory_dev_t *dev = dev_table[minor>>3];
+
+    DEBUG(0, "memory_open(%d)\n", minor);
+    if ((dev == NULL) || (dev->stopped) || (dev->size[minor&7] == 0))
+	return -ENODEV;
+    dev->open++;
+    MOD_INC_USE_COUNT;
+    return 0;
+}
+
+static FS_RELEASE_T memory_close(struct inode *inode, struct file *file)
+{
+    int minor = MINOR(F_INODE(file)->i_rdev);
+    memory_dev_t *dev = dev_table[minor>>3];
+    
+    DEBUG(0, "memory_close(%d)\n", minor);
+    dev->open--;
+    MOD_DEC_USE_COUNT;
+    if (dev->stopped && (dev->open == 0))
+	memory_detach((dev_node_t *)dev);
+    return (FS_RELEASE_T)0;
+}
+
+static ssize_t memory_read FOPS(struct inode *inode,
+				struct file *file, char *buf,
+				size_t count, loff_t *ppos)
+{
+    int minor = MINOR(F_INODE(file)->i_rdev);
+    memory_dev_t *dev = dev_table[minor>>3];
+    int space = minor & 7;
+    size_t i, odd, pos = FPOS;
+    
+    DEBUG(2, "memory_read(%d, 0x%lx, 0x%lx)\n", minor,
+	  (u_long)pos, (u_long)count);
+
+    if (dev->stopped)
+	return -ENODEV;
+    if (pos >= dev->size[space])
+	return 0;
+    if (count > dev->size[space] - pos)
+	count = dev->size[space] - pos;
+
+    odd = count & 3; count &= ~3;
+
+    if (space == 0) {
+
+	for (i = 0; i < count; i += 4, pos += 4, buf += 4)
+	    pci_read_config_dword(dev->pdev, pos, (u32 *)buf);
+	if (odd & 2) {
+	    pci_read_config_word(dev->pdev, pos, (u16 *)buf);
+	    pos += 2; buf += 2;
+	}
+	if (odd & 1) {
+	    pci_read_config_byte(dev->pdev, pos, buf);
+	}
+
+    } else if (dev->virt[space] != NULL) {
+
+	for (i = 0; i < count; i += 4, pos += 4, buf += 4)
+	    *(u32 *)buf = readl_ns(dev->virt[space]+pos);
+	if (odd & 2) {
+	    *(u16 *)buf = readw_ns(dev->virt[space]+pos);
+	    pos += 2; buf += 2;
+	}
+	if (odd & 1) {
+	    *buf = readb(dev->virt[space]+pos);
+	}
+
+    } else {
+
+	for (i = 0; i < count; i += 4, pos += 4, buf += 4)
+	    *(u32 *)buf = inl(dev->base[space]+pos);
+	if (odd & 2) {
+	    *(u16 *)buf = inw(dev->base[space]+pos);
+	    pos += 2; buf += 2;
+	}
+	if (odd & 1) {
+	    *buf = inb(dev->base[space]+pos);
+	}
+
+    }
+
+    FPOS += count+odd;
+    return count+odd;
+}
+
+static ssize_t memory_write FOPS(struct inode *inode,
+				 struct file *file, const char *buf,
+				 size_t count, loff_t *ppos)
+{
+    int minor = MINOR(F_INODE(file)->i_rdev);
+    memory_dev_t *dev = dev_table[minor>>3];
+    int space = minor & 7;
+    size_t i, odd, pos = FPOS;
+    
+    DEBUG(2, "memory_read(%d, 0x%lx, 0x%lx)\n", minor,
+	  (u_long)pos, (u_long)count);
+    
+    if (dev->stopped)
+	return -ENODEV;
+    if (pos >= dev->size[space])
+	return 0;
+    if (count > dev->size[space] - pos)
+	count = dev->size[space] - pos;
+
+    odd = count & 3; count &= ~3;
+
+    if (space == 0) {
+
+	for (i = 0; i < count; i += 4, pos += 4, buf += 4)
+	    pci_write_config_dword(dev->pdev, pos, *(u32 *)buf);
+	if (odd & 2) {
+	    pci_write_config_word(dev->pdev, pos, *(u16 *)buf);
+	    pos += 2; buf += 2;
+	}
+	if (odd & 1) {
+	    pci_write_config_byte(dev->pdev, pos, *buf);
+	}
+
+    } else if (dev->virt[space] != NULL) {
+
+	for (i = 0; i < count; i += 4, pos += 4, buf += 4)
+	    writel_ns(*(u32 *)buf, dev->virt[space]+pos);
+	if (odd & 2) {
+	    writew_ns(*(u16 *)buf, dev->virt[space]+pos);
+	    pos += 2; buf += 2;
+	}
+	if (odd & 1) {
+	    writeb(*buf, dev->virt[space]+pos);
+	}
+
+    } else {
+
+	for (i = 0; i < count; i += 4, pos += 4, buf += 4)
+	    outl(*(u32 *)buf, dev->base[space]+pos);
+	if (odd & 2) {
+	    outw(*(u16 *)buf, dev->base[space]+pos);
+	    pos += 2; buf += 2;
+	}
+	if (odd & 1) {
+	    outb(*buf, dev->base[space]+pos);
+	}
+
+    }
+
+    FPOS += count+odd;
+    return count+odd;
+}
+
+/*====================================================================*/
+
+static struct file_operations memory_fops = {
+    open:	memory_open,
+    release:	memory_close,
+    read:	memory_read,
+    write:	memory_write,
+};
+
+struct driver_operations memory_ops = {
+    "memory_cb", memory_attach, NULL, NULL, memory_detach
+};
+
+static int __init init_memory_cb(void)
+{
+    DEBUG(0, "%s\n", version);
+    major_dev = register_chrdev(major_dev, "memory_cb", &memory_fops);
+    if (major_dev == 0) {
+	printk(KERN_NOTICE "memory_cb: unable to grab major "
+	       "device number!\n");
+	return -1;
+    }
+    register_driver(&memory_ops);
+    return 0;
+}
+
+static void exit_memory_cb(void)
+{
+    DEBUG(0, "memory_cb: unloading\n");
+    unregister_driver(&memory_ops);
+    if (major_dev != 0)
+	unregister_chrdev(major_dev, "memory_cb");
+}
+
+module_init(init_memory_cb);
+module_exit(exit_memory_cb);
Index: oldkernel/linux/pcmcia-cs-3.1.15/clients/memory_cs.c
diff -u /dev/null linux/pcmcia-cs-3.1.15/clients/memory_cs.c:1.1
--- /dev/null	Mon Jul 31 21:15:10 2000
+++ linux/pcmcia-cs-3.1.15/clients/memory_cs.c	Fri Jul  7 16:34:58 2000
@@ -0,0 +1,1163 @@
+/*======================================================================
+
+    A general driver for accessing PCMCIA card memory via Bulk
+    Memory Services.
+
+    This driver provides the equivalent of /dev/mem for a PCMCIA
+    card's attribute and common memory.  It includes character
+    and block device support.
+
+    memory_cs.c 1.70 2000/05/04 01:29: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@pcmcia.sourceforge.org>.  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 <pcmcia/config.h>
+#include <pcmcia/k_compat.h>
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/malloc.h>
+#include <linux/string.h>
+#include <linux/timer.h>
+#include <linux/major.h>
+#include <linux/fs.h>
+#include <linux/ioctl.h>
+#include <asm/io.h>
+#include <asm/system.h>
+#include <asm/segment.h>
+#include <stdarg.h>
+
+#if (LINUX_VERSION_CODE >= VERSION(2,3,3))
+#include <linux/blkpg.h>
+#endif
+
+#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>
+#include <pcmcia/memory.h>
+#include <pcmcia/mem_op.h>
+
+/* Major device #'s for memory device */
+static int major_dev = 0;
+
+/* Funky stuff for setting up a block device */
+#define MAJOR_NR		major_dev
+#define DEVICE_NAME		"memory"
+#define DEVICE_REQUEST		do_memory_request
+#define DEVICE_ON(device)
+#define DEVICE_OFF(device)
+
+#define DEVICE_NR(minor)	((minor)>>4)
+#define IS_DIRECT(minor)	(((minor)&8)>>3)
+#define REGION_AM(minor)	(((minor)&4)>>2)
+#define REGION_NR(minor)	((minor)&7)
+#define MINOR_NR(dev,dir,attr,rgn) \
+(((dev)<<4)+((dir)<<3)+((attr)<<2)+(rgn))
+
+#include <linux/blk.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 =
+"memory_cs.c 1.70 2000/05/04 01:29:47 (David Hinds)";
+#else
+#define DEBUG(n, args...)
+#endif
+
+/*====================================================================*/
+
+/* Parameters that can be set with 'insmod' */
+
+/* 1 = do 16-bit transfers, 0 = do 8-bit transfers */
+static int word_width = 1;
+
+/* Speed of memory accesses, in ns */
+static int mem_speed = 0;
+
+MODULE_PARM(word_width, "i");
+MODULE_PARM(mem_speed, "i");
+
+/*====================================================================*/
+
+/* Maximum number of separate memory devices we'll allow */
+#define MAX_DEV		4
+
+/* Maximum number of partitions per memory space */
+#define MAX_PART	4
+
+/* Maximum number of outstanding erase requests per socket */
+#define MAX_ERASE	8
+
+/* Sector size -- shouldn't need to change */
+#define SECTOR_SIZE	512
+
+/* Size of the PCMCIA address space: 26 bits = 64 MB */
+#define HIGH_ADDR	0x4000000
+
+static void memory_config(dev_link_t *link);
+static void memory_release(u_long arg);
+static int memory_event(event_t event, int priority,
+			event_callback_args_t *args);
+
+static dev_link_t *memory_attach(void);
+static void memory_detach(dev_link_t *);
+
+/* Each memory region corresponds to a minor device */
+typedef struct minor_dev_t {		/* For normal regions */
+    region_info_t	region;
+    memory_handle_t	handle;
+    int			open;
+} minor_dev_t;
+
+typedef struct direct_dev_t {		/* For direct access */
+    int			flags;
+    int			open;
+    caddr_t		Base;
+    u_int		Size;
+    u_long		cardsize;
+} direct_dev_t;
+
+typedef struct memory_dev_t {
+    dev_link_t		link;
+    dev_node_t		node;
+    eraseq_handle_t	eraseq_handle;
+    eraseq_entry_t	eraseq[MAX_ERASE];
+    wait_queue_head_t	erase_pending;
+    direct_dev_t	direct;
+    minor_dev_t		minor[2*MAX_PART];
+} memory_dev_t;
+
+#define MEM_WRPROT	1
+
+static dev_info_t dev_info = "memory_cs";
+static dev_link_t *dev_table[MAX_DEV] = { NULL, /* ... */ };
+
+static int memory_blocksizes[MINOR_NR(MAX_DEV, 0, 0, 0)] =
+{ 0, /* ... */ };
+    
+/*====================================================================*/
+
+static int memory_ioctl(struct inode *inode, struct file *file,
+			u_int cmd, u_long arg);
+static ssize_t memory_read FOPS(struct inode *inode,
+				struct file *file, char *buf,
+				size_t count, loff_t *ppos);
+static ssize_t memory_write FOPS(struct inode *inode,
+				 struct file *file, const char *buf,
+				 size_t count, loff_t *ppos);
+static int memory_open(struct inode *inode, struct file *file);
+static FS_RELEASE_T memory_close(struct inode *inode,
+				 struct file *file);
+static FS_RELEASE_T memory_blk_close(struct inode *inode,
+				     struct file *file);
+
+static struct file_operations memory_chr_fops = {
+    open:	memory_open,
+    release:	memory_close,
+    read:	memory_read,
+    write:	memory_write,
+    ioctl:	memory_ioctl,
+};
+
+static struct block_device_operations memory_blk_fops = {
+    open:	memory_open,
+    release:	memory_blk_close,
+    ioctl:	memory_ioctl,
+#ifdef block_device_operations
+    read:	block_read,
+    write:	block_write,
+    fsync:	block_fsync
+#endif
+};
+
+/*====================================================================*/
+
+static void cs_error(client_handle_t handle, int func, int ret)
+{
+    error_info_t err = { func, ret };
+    CardServices(ReportError, handle, &err);
+}
+
+/*======================================================================
+
+    memory_attach() creates an "instance" of the driver, allocating
+    local data structures for one device.  The device is registered
+    with Card Services.
+
+======================================================================*/
+
+static dev_link_t *memory_attach(void)
+{
+    memory_dev_t *dev;
+    dev_link_t *link;
+    client_reg_t client_reg;
+    eraseq_hdr_t eraseq_hdr;
+    int i, ret;
+    
+    DEBUG(0, "memory_attach()\n");
+
+    for (i = 0; i < MAX_DEV; i++)
+	if (dev_table[i] == NULL) break;
+    if (i == MAX_DEV) {
+	printk(KERN_NOTICE "memory_cs: no devices available\n");
+	return NULL;
+    }
+    
+    /* Create new memory card device */
+    dev = kmalloc(sizeof(*dev), GFP_KERNEL);
+    if (!dev) return NULL;
+    memset(dev, 0, sizeof(*dev));
+    link = &dev->link; link->priv = dev;
+
+    link->release.function = &memory_release;
+    link->release.data = (u_long)link;
+    dev_table[i] = link;
+    init_waitqueue_head(&dev->erase_pending);
+
+    /* Register with Card Services */
+    client_reg.dev_info = &dev_info;
+    client_reg.Attributes = INFO_IO_CLIENT | INFO_CARD_SHARE;
+    client_reg.EventMask =
+	CS_EVENT_RESET_PHYSICAL | CS_EVENT_CARD_RESET |
+	CS_EVENT_CARD_INSERTION | CS_EVENT_CARD_REMOVAL |
+	CS_EVENT_PM_SUSPEND | CS_EVENT_PM_RESUME;
+    client_reg.event_handler = &memory_event;
+    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);
+	memory_detach(link);
+	return NULL;
+    }
+
+    for (i = 0; i < MAX_ERASE; i++)
+	dev->eraseq[i].State = ERASE_IDLE;
+    eraseq_hdr.QueueEntryCnt = MAX_ERASE;
+    eraseq_hdr.QueueEntryArray = dev->eraseq;
+    dev->eraseq_handle = (void *)link->handle;
+    ret = CardServices(RegisterEraseQueue, &dev->eraseq_handle, &eraseq_hdr);
+    if (ret != 0) {
+	cs_error(link->handle, RegisterEraseQueue, ret);
+	dev->eraseq_handle = NULL;
+	memory_detach(link);
+	return NULL;
+    }
+    
+    return link;
+} /* memory_attach */
+
+/*======================================================================
+
+    This deletes a driver "instance".  The device is de-registered
+    with Card Services.  If it has been released, all local data
+    structures are freed.  Otherwise, the structures will be freed
+    when the device is released.
+
+======================================================================*/
+
+static void memory_detach(dev_link_t *link)
+{
+    memory_dev_t *dev = link->priv;
+    int nd;
+
+    DEBUG(0, "memory_detach(0x%p)\n", link);
+    
+    /* Verify device address */
+    for (nd = 0; nd < MAX_DEV; nd++)
+	if (dev_table[nd] == link) break;
+    if (nd == MAX_DEV)
+	return;
+
+    del_timer(&link->release);
+    if (link->state & DEV_CONFIG) {
+	memory_release((u_long)link);
+	if (link->state & DEV_STALE_CONFIG) {
+	    link->state |= DEV_STALE_LINK;
+	    return;
+	}
+    }
+
+    if (dev->eraseq_handle)
+	CardServices(DeregisterEraseQueue, dev->eraseq_handle);
+    if (link->handle)
+	CardServices(DeregisterClient, link->handle);
+    
+    /* Unlink device structure, free bits */
+    dev_table[nd] = NULL;
+    kfree(dev);
+    
+} /* memory_detach */
+
+/*======================================================================
+
+    Figure out the size of a simple SRAM card
+    
+======================================================================*/
+
+static void get_size(dev_link_t *link, direct_dev_t *direct)
+{
+    modwin_t mod;
+    memreq_t mem;
+    u_char buf[26];
+    int s, t, ret;
+
+    mod.Attributes = WIN_ENABLE | WIN_MEMORY_TYPE_CM;
+    mod.AccessSpeed = 0;
+    ret = CardServices(ModifyWindow, link->win, &mod);
+    if (ret != CS_SUCCESS)
+	cs_error(link->handle, ModifyWindow, ret);
+
+    /* Look for wrap-around or dead end */
+    mem.Page = 0;
+    for (s = 12; s < 26; s++) {
+	mem.CardOffset = 1<<s;
+	CardServices(MapMemPage, link->win, &mem);
+	buf[s] = readb(direct->Base);
+	writeb(~buf[s], direct->Base);
+	for (t = 12; t < s; t++) {
+	    mem.CardOffset = 1<<t;
+	    CardServices(MapMemPage, link->win, &mem);
+	    if (readb(direct->Base) != buf[t]) {
+		writeb(buf[t], direct->Base);
+		break;
+	    }
+	}
+	if (t < s) break;
+	mem.CardOffset = 1<<s;
+	CardServices(MapMemPage, link->win, &mem);
+	if (readb(direct->Base) != (0xff & ~buf[s])) break;
+	writeb(buf[s], direct->Base);
+    }
+
+    /* Restore that last byte on wrap-around */
+    if (t < s) {
+	mem.CardOffset = 1<<t;
+	CardServices(MapMemPage, link->win, &mem);
+	writeb(buf[t], direct->Base);
+    }
+
+    direct->cardsize = (t > 15) ? (1<<t) : 0;
+} /* get_size */
+
+static void print_size(u_long sz)
+{
+    if (sz & 0x03ff)
+	printk("%ld bytes", sz);
+    else if (sz & 0x0fffff)
+	printk("%ld kb", sz >> 10);
+    else
+	printk("%ld mb", sz >> 20);
+}
+
+/*======================================================================
+
+    memory_config() is scheduled to run after a CARD_INSERTION event
+    is received, to configure the PCMCIA socket, and to make the
+    ethernet device available to the system.
+    
+======================================================================*/
+
+#define CS_CHECK(fn, args...) \
+while ((last_ret=CardServices(last_fn=(fn), args))!=0) goto cs_failed
+
+static void memory_config(dev_link_t *link)
+{
+    memory_dev_t *dev = link->priv;
+    minor_dev_t *minor;
+    region_info_t region;
+    cs_status_t status;
+    win_req_t req;
+    int nd, i, last_ret, last_fn, attr, ret, nr[2];
+
+    DEBUG(0, "memory_config(0x%p)\n", link);
+
+    /* Configure card */
+    link->state |= DEV_CONFIG;
+
+    for (nd = 0; nd < MAX_DEV; nd++)
+	if (dev_table[nd] == link) break;
+    
+    /* Allocate a small memory window for direct access */
+    if (word_width)
+	req.Attributes = WIN_DATA_WIDTH_16;
+    else
+	req.Attributes = WIN_DATA_WIDTH_8;
+    req.Base = req.Size = 0;
+    req.AccessSpeed = mem_speed;
+    link->win = (window_handle_t)link->handle;
+    CS_CHECK(RequestWindow, &link->win, &req);
+    /* Get write protect status */
+    CS_CHECK(GetStatus, link->handle, &status);
+    
+    dev->direct.Base = ioremap(req.Base, req.Size);
+    dev->direct.Size = req.Size;
+    dev->direct.cardsize = 0;
+
+    for (attr = 0; attr < 2; attr++) {
+	nr[attr] = 0;
+	minor = dev->minor + attr*MAX_PART;
+	region.Attributes =
+	    (attr) ? REGION_TYPE_AM : REGION_TYPE_CM;
+	ret = CardServices(GetFirstRegion, link->handle, &region);
+	while (ret == CS_SUCCESS) {
+	    minor->region = region;
+	    minor++; nr[attr]++;
+	    ret = CardServices(GetNextRegion, link->handle, &region);
+	}
+    }
+    
+    sprintf(dev->node.dev_name, "mem%d", nd);
+    dev->node.major = major_dev;
+    dev->node.minor = MINOR_NR(nd, 0, 0, 0);
+    link->dev = &dev->node;
+    link->state &= ~DEV_CONFIG_PENDING;
+    
+    printk(KERN_INFO "memory_cs: mem%d:", nd);
+    if ((nr[0] == 0) && (nr[1] == 0)) {
+	cisinfo_t cisinfo;
+	if ((CardServices(ValidateCIS, link->handle, &cisinfo)
+	     == CS_SUCCESS) && (cisinfo.Chains == 0)) {
+	    get_size(link, &dev->direct);
+	    printk(" anonymous: ");
+	    if (dev->direct.cardsize == 0) {
+		dev->direct.cardsize = HIGH_ADDR;
+		printk("unknown size");
+	    } else {
+		print_size(dev->direct.cardsize);
+	    }
+	} else {
+	    printk(" no regions found.");
+	}
+    } else {
+	for (attr = 0; attr < 2; attr++) {
+	    minor = dev->minor + attr*MAX_PART;
+	    if (attr && nr[0] && nr[1])
+		printk(",");
+	    if (nr[attr])
+		printk(" %s", attr ? "attribute" : "common");
+	    for (i = 0; i < nr[attr]; i++) {
+		printk(" ");
+		print_size(minor[i].region.RegionSize);
+	    }
+	}
+    }
+    printk("\n");
+    return;
+
+cs_failed:
+    cs_error(link->handle, last_fn, last_ret);
+    memory_release((u_long)link);
+    return;
+} /* memory_config */
+
+/*======================================================================
+
+    After a card is removed, memory_release() will unregister the 
+    device, and release the PCMCIA configuration.  If the device is
+    still open, this will be postponed until it is closed.
+    
+======================================================================*/
+
+static void memory_release(u_long arg)
+{
+    dev_link_t *link = (dev_link_t *)arg;
+    int nd;
+
+    DEBUG(0, "memory_release(0x%p)\n", link);
+
+    for (nd = 0; nd < MAX_DEV; nd++)
+	if (dev_table[nd] == link) break;
+    if (link->open) {
+	DEBUG(0, "memory_cs: release postponed, 'mem%d'"
+	      " still open\n", nd);
+	link->state |= DEV_STALE_CONFIG;
+	return;
+    }
+
+    link->dev = NULL;
+    if (link->win) {
+	memory_dev_t *dev = link->priv;
+	iounmap(dev->direct.Base);
+	CardServices(ReleaseWindow, link->win);
+    }
+    link->state &= ~DEV_CONFIG;
+    
+    if (link->state & DEV_STALE_LINK)
+	memory_detach(link);
+    
+} /* memory_release */
+
+/*======================================================================
+
+    The card status event handler.  Mostly, this schedules other
+    stuff to run after an event is received.  A CARD_REMOVAL event
+    also sets some flags to discourage the driver from trying
+    to talk to the card any more.
+    
+======================================================================*/
+
+static int memory_event(event_t event, int priority,
+		       event_callback_args_t *args)
+{
+    dev_link_t *link = args->client_data;
+    memory_dev_t *dev = link->priv;
+    eraseq_entry_t *erase;
+
+    DEBUG(1, "memory_event(0x%06x)\n", event);
+    
+    switch (event) {
+    case CS_EVENT_CARD_REMOVAL:
+	link->state &= ~DEV_PRESENT;
+	if (link->state & DEV_CONFIG)
+	    mod_timer(&link->release, jiffies + HZ/20);
+	break;
+    case CS_EVENT_CARD_INSERTION:
+	link->state |= DEV_PRESENT | DEV_CONFIG_PENDING;
+	memory_config(link);
+	break;
+    case CS_EVENT_ERASE_COMPLETE:
+	erase = (eraseq_entry_t *)(args->info);
+	wake_up((wait_queue_head_t *)&erase->Optional);
+	wake_up_interruptible(&dev->erase_pending);
+	break;
+    case CS_EVENT_PM_SUSPEND:
+	link->state |= DEV_SUSPEND;
+	/* Fall through... */
+    case CS_EVENT_RESET_PHYSICAL:
+	/* get_lock(link); */
+	break;
+    case CS_EVENT_PM_RESUME:
+	link->state &= ~DEV_SUSPEND;
+	/* Fall through... */
+    case CS_EVENT_CARD_RESET:
+	/* free_lock(link); */
+	break;
+    }
+    return 0;
+} /* memory_event */
+
+/*======================================================================
+
+    This gets a memory handle for the region corresponding to the
+    minor device number.
+    
+======================================================================*/
+
+static int memory_open(struct inode *inode, struct file *file)
+{
+    int minor = MINOR(inode->i_rdev);
+    dev_link_t *link;
+    memory_dev_t *dev;
+    minor_dev_t *minor_dev;
+    open_mem_t open;
+    int ret;
+    
+    DEBUG(0, "memory_open(%d)\n", minor);
+
+    link = dev_table[DEVICE_NR(minor)];
+    if (!DEV_OK(link))
+	return -ENODEV;
+    
+    dev = (memory_dev_t *)link->priv;
+
+    if (IS_DIRECT(minor) || (dev->direct.cardsize > 0)) {
+	if ((file->f_mode & 2) && (dev->direct.flags & MEM_WRPROT))
+	    return -EROFS;
+	dev->direct.open++;
+	file->private_data = NULL;
+    } else {
+	minor_dev = &dev->minor[REGION_NR(minor)];
+	if (minor_dev->region.RegionSize == 0)
+	    return -ENODEV;
+	if (minor_dev->handle == NULL) {
+	    minor_dev->handle = (memory_handle_t)link->handle;
+	    open.Attributes = minor_dev->region.Attributes;
+	    open.Offset = minor_dev->region.CardOffset;
+	    ret = CardServices(OpenMemory, &minor_dev->handle, &open);
+	    if (ret != CS_SUCCESS)
+		return -ENOMEM;
+	}
+	minor_dev->open++;
+	file->private_data = minor_dev;
+    }
+    
+    link->open++;
+    MOD_INC_USE_COUNT;
+    return 0;
+} /* memory_open */
+
+/*====================================================================*/
+
+static FS_RELEASE_T memory_close(struct inode *inode,
+				 struct file *file)
+{
+    dev_link_t *link;
+    int minor = MINOR(inode->i_rdev);
+    memory_dev_t *dev;
+    minor_dev_t *minor_dev;
+    
+    DEBUG(0, "memory_close(%d)\n", minor);
+
+    link = dev_table[DEVICE_NR(minor)];
+    dev = (memory_dev_t *)link->priv;
+    if (IS_DIRECT(minor) || (dev->direct.cardsize > 0)) {
+	dev->direct.open--;
+    } else {
+	minor_dev = &dev->minor[REGION_NR(minor)];
+	minor_dev->open--;
+	if (minor_dev->open == 0) {
+	    CardServices(CloseMemory, minor_dev->handle);
+	    minor_dev->handle = NULL;
+	}
+    }
+
+    link->open--;
+    MOD_DEC_USE_COUNT;
+    return (FS_RELEASE_T)0;
+} /* memory_close */
+
+static FS_RELEASE_T memory_blk_close(struct inode *inode,
+				     struct file *file)
+{
+    fsync_dev(inode->i_rdev);
+    INVALIDATE_INODES(inode->i_rdev);
+    invalidate_buffers(inode->i_rdev);
+    return memory_close(inode, file);
+}
+
+/*======================================================================
+
+    Read for character-mode device
+    
+======================================================================*/
+
+static ssize_t direct_read FOPS(struct inode *inode,
+				struct file *file, char *buf,
+				size_t count, loff_t *ppos)
+{
+    int minor = MINOR(F_INODE(file)->i_rdev);
+    dev_link_t *link;
+    memory_dev_t *dev;
+    direct_dev_t *direct;
+    size_t size, pos, read, from, nb;
+    int ret;
+    modwin_t mod;
+    memreq_t mem;
+
+    DEBUG(2, "direct_read(%d, 0x%lx, %ld)\n", minor,
+	  (u_long)FPOS, (u_long)count);
+
+    link = dev_table[DEVICE_NR(minor)];
+    
+    if (!DEV_OK(link))
+	return -ENODEV;
+    dev = (memory_dev_t *)link->priv;
+    direct = &dev->direct;
+    
+    /* Boundary checks */
+    if (count < 0)
+	return -EINVAL;
+    pos = FPOS;
+    size = (IS_DIRECT(minor)) ? HIGH_ADDR : direct->cardsize;
+    if (pos >= size)
+	return 0;
+    if (count > size - pos)
+	count = size - pos;
+
+    mod.Attributes = WIN_ENABLE;
+    mod.Attributes |= (REGION_AM(minor)) ? WIN_MEMORY_TYPE_AM : 0;
+    mod.AccessSpeed = 0;
+    ret = CardServices(ModifyWindow, link->win, &mod);
+    if (ret != CS_SUCCESS) {
+	cs_error(link->handle, ModifyWindow, ret);
+	return -EIO;
+    }
+    
+    mem.CardOffset = pos & ~(direct->Size-1);
+    mem.Page = 0;
+    from = pos & (direct->Size-1);
+    for (read = 0; count > 0; count -= nb, read += nb) {
+	ret = CardServices(MapMemPage, link->win, &mem);
+	if (ret != CS_SUCCESS) {
+	    cs_error(link->handle, MapMemPage, ret);
+	    return -EIO;
+	}
+	nb = (from+count > direct->Size) ? direct->Size-from : count;
+	copy_pc_to_user(buf, direct->Base+from, nb);
+	buf += nb;
+        from = 0;
+	mem.CardOffset += direct->Size;
+    }
+
+    FPOS += read;
+    return read;
+} /* direct_read */
+
+static ssize_t memory_read FOPS(struct inode *inode,
+				struct file *file, char *buf,
+				size_t count, loff_t *ppos)
+{
+    minor_dev_t *minor;
+    mem_op_t req;
+    int ret;
+
+    minor = file->private_data;
+    if (minor == NULL)
+	return direct_read FOPS(inode, file, buf, count, ppos);
+    
+    DEBUG(2, "memory_read(0x%p, 0x%lx, %ld)\n", minor->handle,
+	  (u_long)FPOS, (u_long)count);
+    
+    req.Attributes = MEM_OP_BUFFER_USER;
+    req.Offset = FPOS;
+    req.Count = count;
+    ret = CardServices(ReadMemory, minor->handle, &req, buf);
+    if (ret == CS_SUCCESS) {
+	FPOS += count;
+	return count;
+    } else if (ret == CS_BAD_OFFSET)
+	return 0;
+    else
+	return -EIO;
+} /* memory_read */
+
+/*======================================================================
+
+    Erase a memory region.  This is used by the write routine for
+    suitably aligned and sized blocks.  It is also used for the
+    MEMERASE ioctl().
+    
+======================================================================*/
+
+static int memory_erase(int minor, u_long f_pos, size_t count)
+{
+    dev_link_t *link = dev_table[DEVICE_NR(minor)];
+    memory_dev_t *dev = link->priv;
+    minor_dev_t *minor_dev = &dev->minor[REGION_NR(minor)];
+    int i, ret;
+
+    DEBUG(2, "memory_erase(%d, 0x%lx, %ld)\n", minor,
+	  f_pos, (u_long)count);
+    
+    /* Find a free erase slot, or wait for one to become available */
+    for (;;) {
+	for (i = 0; i < MAX_ERASE; i++)
+	    if (!ERASE_IN_PROGRESS(dev->eraseq[i].State)) break;
+	if (i < MAX_ERASE) break;
+	DEBUG(2, "waiting for erase slot...\n");
+	interruptible_sleep_on(&dev->erase_pending);
+	if (signal_pending(current))
+	    return -ERESTARTSYS;
+    }
+
+    /* Queue a new request */
+    dev->eraseq[i].State = ERASE_QUEUED;
+    dev->eraseq[i].Handle = minor_dev->handle;
+    dev->eraseq[i].Offset = f_pos;
+    dev->eraseq[i].Size = count;
+    ret = CardServices(CheckEraseQueue, dev->eraseq_handle);
+    if (ret != CS_SUCCESS) {
+	cs_error(link->handle, CheckEraseQueue, ret);
+	return -EIO;
+    }
+
+    /* Wait for request to complete */
+    init_waitqueue_head((wait_queue_head_t *)&dev->eraseq[i].Optional);
+    if (ERASE_IN_PROGRESS(dev->eraseq[i].State))
+	sleep_on((wait_queue_head_t *)&dev->eraseq[i].Optional);
+    if (dev->eraseq[i].State != ERASE_PASSED)
+	return -EIO;
+    return 0;
+}
+
+/*======================================================================
+
+    Write for character-mode device
+    
+======================================================================*/
+
+static ssize_t direct_write FOPS(struct inode *inode,
+				 struct file *file, const char *buf,
+				 size_t count, loff_t *ppos)
+{
+    int minor = MINOR(F_INODE(file)->i_rdev);
+    dev_link_t *link;
+    memory_dev_t *dev;
+    direct_dev_t *direct;
+    size_t size, pos, wrote, to, nb;
+    int ret;
+    modwin_t mod;
+    memreq_t mem;
+    
+    DEBUG(2, "direct_write(%d, 0x%lx, %ld)\n", minor,
+	  (u_long)FPOS, (u_long)count);
+    
+    link = dev_table[DEVICE_NR(minor)];
+    
+    if (!DEV_OK(link))
+	return -ENODEV;
+    
+    dev = (memory_dev_t *)link->priv;
+    direct = &dev->direct;
+    
+    /* Check for write protect */
+    if (direct->flags & MEM_WRPROT)
+	return -EROFS;
+
+    /* Boundary checks */
+    if (count < 0)
+	return -EINVAL;
+    size = (IS_DIRECT(minor)) ? HIGH_ADDR : direct->cardsize;
+    pos = FPOS;
+    if (pos >= size)
+        return -ENOSPC;
+    if (count > size - pos)
+	count = size - pos;
+
+    mod.Attributes = WIN_ENABLE;
+    mod.Attributes |= (REGION_AM(minor)) ? WIN_MEMORY_TYPE_AM : 0;
+    mod.AccessSpeed = 0;
+    ret = CardServices(ModifyWindow, link->win, &mod);
+    if (ret != CS_SUCCESS) {
+	cs_error(link->handle, ModifyWindow, ret);
+	return -EIO;
+    }
+    
+    mem.CardOffset = pos & ~(direct->Size-1);
+    mem.Page = 0;
+    to = pos & (direct->Size-1);
+    for (wrote = 0; count > 0; count -= nb, wrote += nb) {
+	ret = CardServices(MapMemPage, link->win, &mem);
+	if (ret != CS_SUCCESS) {
+	    cs_error(link->handle, MapMemPage, ret);
+	    return -EIO;
+	}
+	nb = (to+count > direct->Size) ? direct->Size-to : count;
+	copy_user_to_pc(direct->Base+to, buf, nb);
+	buf += nb;
+        to = 0;
+	mem.CardOffset += direct->Size;
+    }
+
+    FPOS += wrote;
+    return wrote;
+} /* direct_write */
+
+static ssize_t memory_write FOPS(struct inode *inode,
+				 struct file *file, const char *buf,
+				 size_t count, loff_t *ppos)
+{
+    minor_dev_t *minor;
+    mem_op_t req;
+    int ret;
+
+    minor = file->private_data;
+    if (minor == NULL)
+	return direct_write FOPS(inode, file, buf, count, ppos);
+    
+    DEBUG(2, "memory_write(0x%p, 0x%lx, %ld)\n", minor->handle,
+	  (u_long)FPOS, (u_long)count);
+    if ((minor->region.BlockSize > 1) &&
+	((FPOS & (minor->region.BlockSize-1)) == 0) &&
+	((count & (minor->region.BlockSize-1)) == 0)) {
+	ret = memory_erase(MINOR(F_INODE(file)->i_rdev), FPOS, count);
+	if (ret != 0)
+	    return ret;
+    }
+    
+    req.Attributes = 0;
+    req.Offset = FPOS;
+    req.Count = count;
+    ret = CardServices(WriteMemory, minor->handle, &req, buf);
+    if (ret == CS_SUCCESS) {
+	FPOS += count;
+	return count;
+    } else
+	return -EIO;
+} /* memory_write */
+
+/*======================================================================
+
+    IOCTL calls for getting device parameters.
+
+======================================================================*/
+
+static int memory_ioctl(struct inode *inode, struct file *file,
+			u_int cmd, u_long arg)
+{
+    int minor = MINOR(inode->i_rdev);
+    dev_link_t *link;
+    memory_dev_t *dev;
+    minor_dev_t *minor_dev;
+    erase_info_t erase;
+    u_int size;
+    int ret = 0;
+
+    link = dev_table[DEVICE_NR(minor)];
+    
+    if (!DEV_OK(link))
+	return -ENODEV;
+    dev = (memory_dev_t *)link->priv;
+    minor_dev = &dev->minor[REGION_NR(minor)];
+
+    size = (cmd & IOCSIZE_MASK) >> IOCSIZE_SHIFT;
+    if (cmd & IOC_IN) {
+	ret = verify_area(VERIFY_READ, (char *)arg, size);
+	if (ret) return ret;
+    }
+    if (cmd & IOC_OUT) {
+	ret = verify_area(VERIFY_WRITE, (char *)arg, size);
+	if (ret) return ret;
+    }
+
+    switch (cmd) {
+    case BLKGETSIZE:
+	if (!IS_DIRECT(minor))
+	    put_user(dev->direct.cardsize/SECTOR_SIZE, (long *)arg);
+	else
+	    put_user(minor_dev->region.RegionSize/SECTOR_SIZE,
+		     (long *)arg);
+	break;
+    case MEMGETINFO:
+	if (!IS_DIRECT(minor)) {
+	    copy_to_user((region_info_t *)arg, &minor_dev->region,
+			 sizeof(struct region_info_t));
+	} else ret = -EINVAL;
+	break;
+    case MEMERASE:
+	if (!IS_DIRECT(minor)) {
+	    copy_from_user(&erase, (erase_info_t *)arg,
+			   sizeof(struct erase_info_t));
+	    ret = memory_erase(minor, erase.Offset, erase.Size);
+	} else ret = -EINVAL;
+	break;
+#if (LINUX_VERSION_CODE < VERSION(2,3,3))
+    case BLKFLSBUF:
+	if (!capable(CAP_SYS_ADMIN)) return -EACCES;
+	if (!(inode->i_rdev)) return -EINVAL;
+	fsync_dev(inode->i_rdev);
+	invalidate_buffers(inode->i_rdev);
+	break;
+#else
+    case BLKROSET:
+    case BLKROGET:
+    case BLKFLSBUF:
+	ret = blk_ioctl(inode->i_rdev, cmd, arg);
+	break;
+#endif
+    default:
+	ret = -EINVAL;
+    }
+    
+    return ret;
+} /* memory_ioctl */
+
+/*======================================================================
+
+    Handler for block device requests
+    
+======================================================================*/
+
+
+static void do_direct_request(dev_link_t *link)
+{
+    memory_dev_t *dev = link->priv;
+    int addr, len, from, nb, ret;
+    char *buf;
+    direct_dev_t *direct;
+    modwin_t mod;
+    memreq_t mem;
+
+    direct = &dev->direct;
+    
+    addr = CURRENT->sector * SECTOR_SIZE;
+    len = CURRENT->current_nr_sectors * SECTOR_SIZE;
+    if ((addr + len) > direct->cardsize) {
+	end_request(0);
+	return;
+    }
+    
+    mod.Attributes = WIN_ENABLE;
+    mod.AccessSpeed = 0;
+    ret = CardServices(ModifyWindow, link->win, &mod);
+    if (ret != CS_SUCCESS) {
+	cs_error(link->handle, ModifyWindow, ret);
+	end_request(0);
+	return;
+    }
+
+    buf = CURRENT->buffer;
+    mem.Page = 0;
+    mem.CardOffset = addr & ~(direct->Size-1);
+    from = addr & (direct->Size-1);
+    ret = 0;
+    
+    if ((CURRENT->cmd == READ) || (CURRENT->cmd == WRITE))
+	for ( ; len > 0; len -= nb, buf += nb, from = 0) {
+	    ret = CardServices(MapMemPage, link->win, &mem);
+	    if (ret != CS_SUCCESS) break;
+	    nb = (from+len > direct->Size) ? direct->Size-from : len;
+	    if (CURRENT->cmd == READ)
+		copy_from_pc(buf, &direct->Base[from], nb);
+	    else
+		copy_to_pc(&direct->Base[from], buf, nb);
+	    mem.CardOffset += direct->Size;
+	}
+    else panic("pcmem_cs: unknown block command!\n");
+    
+    if (ret == CS_SUCCESS)
+	end_request(1);
+    else {
+	cs_error(link->handle, MapMemPage, ret);
+	end_request(0);
+    }
+} /* do_direct_request */
+
+static void do_memory_request(request_arg_t)
+{
+    int ret, minor;
+    char *buf;
+    mem_op_t req;
+    dev_link_t *link;
+    memory_dev_t *dev;
+    minor_dev_t *minor_dev;
+    
+    sti();
+    do {
+	INIT_REQUEST;
+
+	minor = MINOR(CURRENT->rq_dev);
+	link = dev_table[DEVICE_NR(minor)];
+	dev = (memory_dev_t *)link->priv;
+
+	if (IS_DIRECT(minor) || (dev->direct.cardsize > 0)) {
+	    do_direct_request(link);
+	    continue;
+	}
+	
+	minor_dev = &dev->minor[REGION_NR(minor)];
+
+	req.Attributes = MEM_OP_BUFFER_KERNEL;
+	req.Offset = CURRENT->sector * SECTOR_SIZE;
+	req.Count = CURRENT->current_nr_sectors * SECTOR_SIZE;
+	buf = CURRENT->buffer;
+	ret = CS_SUCCESS;
+	
+	if (CURRENT->cmd == READ) {
+	    ret = CardServices(ReadMemory, minor_dev->handle,
+			       &req, buf);
+	    if (ret != CS_SUCCESS)
+		cs_error(link->handle, ReadMemory, ret);
+	} else if (CURRENT->cmd == WRITE) {
+	    ret = CardServices(WriteMemory, minor_dev->handle,
+			       &req, buf);
+	    if (ret != CS_SUCCESS)
+		cs_error(link->handle, WriteMemory, ret);
+	} else
+	    panic("memory_cs: unknown block command!\n");
+	
+	if (ret == CS_SUCCESS)
+	    end_request(1);
+	else
+	    end_request(0);
+    } while (1);
+} /* do_memory_request */
+
+/*====================================================================*/
+
+static int __init init_memory_cs(void)
+{
+    servinfo_t serv;
+    int i;
+    
+    DEBUG(0, "%s\n", version);
+    
+    CardServices(GetCardServicesInfo, &serv);
+    if (serv.Revision != CS_RELEASE_CODE) {
+	printk(KERN_NOTICE "memory_cs: Card Services release "
+	       "does not match!\n");
+	return -1;
+    }
+    
+    register_pccard_driver(&dev_info, &memory_attach, &memory_detach);
+
+    for (i = MAX_CHRDEV-1; i > 0; i--) {
+	if (register_chrdev(i, "memory", &memory_chr_fops) == 0) {
+	    if (register_blkdev(i, "memory", &memory_blk_fops) == 0)
+		break;
+	    else
+		unregister_chrdev(i, "memory");
+	}
+    }
+    if (i == 0) {
+	printk(KERN_NOTICE "memory_cs: unable to grab a device #\n");
+	return -ENODEV;
+    }
+
+    major_dev = i;
+    blk_init_queue(BLK_DEFAULT_QUEUE(MAJOR_NR), &do_memory_request);
+    for (i = 0; i < MINOR_NR(MAX_DEV, 0, 0, 0); i++)
+	memory_blocksizes[i] = 1024;
+    blksize_size[major_dev] = memory_blocksizes;
+    
+    return 0;
+}
+
+static void __exit exit_memory_cs(void)
+{
+    int i;
+    dev_link_t *link;
+
+    DEBUG(0, "memory_cs: unloading\n");
+    unregister_pccard_driver(&dev_info);
+    if (major_dev != 0) {
+	unregister_chrdev(major_dev, "memory");
+	unregister_blkdev(major_dev, "memory");
+	blk_cleanup_queue(BLK_DEFAULT_QUEUE(MAJOR_NR));
+	blksize_size[major_dev] = NULL;
+    }
+    for (i = 0; i < MAX_DEV; i++) {
+	link = dev_table[i];
+	if (link) {
+	    if (link->state & DEV_CONFIG)
+		memory_release((u_long)link);
+	    memory_detach(link);
+	}
+    }
+}
+
+module_init(init_memory_cs);
+module_exit(exit_memory_cs);
Index: oldkernel/linux/pcmcia-cs-3.1.15/clients/nmclan_cs.c
diff -u /dev/null linux/pcmcia-cs-3.1.15/clients/nmclan_cs.c:1.1
--- /dev/null	Mon Jul 31 21:15:10 2000
+++ linux/pcmcia-cs-3.1.15/clients/nmclan_cs.c	Fri Jul  7 16:34:58 2000
@@ -0,0 +1,1742 @@
+/* ----------------------------------------------------------------------------
+Linux PCMCIA ethernet adapter driver for the New Media Ethernet LAN.
+  nmclan_cs.c,v 0.16 1995/07/01 06:42:17 rpao Exp rpao
+
+  The Ethernet LAN uses the Advanced Micro Devices (AMD) Am79C940 Media
+  Access Controller for Ethernet (MACE).  It is essentially the Am2150
+  PCMCIA Ethernet card contained in the the Am2150 Demo Kit.
+
+Written by Roger C. Pao <rpao@paonet.org>
+  Copyright 1995 Roger C. Pao
+
+  This software may be used and distributed according to the terms of
+  the GNU Public License.
+
+Ported to Linux 1.3.* network driver environment by
+  Matti Aarnio <mea@utu.fi>
+
+References
+
+  Am2150 Technical Reference Manual, Revision 1.0, August 17, 1993
+  Am79C940 (MACE) Data Sheet, 1994
+  Am79C90 (C-LANCE) Data Sheet, 1994
+  Linux PCMCIA Programmer's Guide v1.17
+  /usr/src/linux/net/inet/dev.c, Linux kernel 1.2.8
+
+  Eric Mears, New Media Corporation
+  Tom Pollard, New Media Corporation
+  Dean Siasoyco, New Media Corporation
+  Ken Lesniak, Silicon Graphics, Inc. <lesniak@boston.sgi.com>
+  Donald Becker <becker@cesdis1.gsfc.nasa.gov>
+  David Hinds <dhinds@pcmcia.sourceforge.org>
+
+  The Linux client driver is based on the 3c589_cs.c client driver by
+  David Hinds.
+
+  The Linux network driver outline is based on the 3c589_cs.c driver,
+  the 8390.c driver, and the example skeleton.c kernel code, which are
+  by Donald Becker.
+
+  The Am2150 network driver hardware interface code is based on the
+  OS/9000 driver for the New Media Ethernet LAN by Eric Mears.
+
+  Special thanks for testing and help in debugging this driver goes
+  to Ken Lesniak.
+
+-------------------------------------------------------------------------------
+Driver Notes and Issues
+-------------------------------------------------------------------------------
+
+1. Developed on a Dell 320SLi
+   PCMCIA Card Services 2.6.2
+   Linux dell 1.2.10 #1 Thu Jun 29 20:23:41 PDT 1995 i386
+
+2. rc.pcmcia may require loading pcmcia_core with io_speed=300:
+   'insmod pcmcia_core.o io_speed=300'.
+   This will avoid problems with fast systems which causes rx_framecnt
+   to return random values.
+
+3. If hot extraction does not work for you, use 'ifconfig eth0 down'
+   before extraction.
+
+4. There is a bad slow-down problem in this driver.
+
+5. Future: Multicast processing.  In the meantime, do _not_ compile your
+   kernel with multicast ip enabled.
+
+-------------------------------------------------------------------------------
+History
+-------------------------------------------------------------------------------
+Log: nmclan_cs.c,v
+ * Revision 0.16  1995/07/01  06:42:17  rpao
+ * Bug fix: nmclan_reset() called CardServices incorrectly.
+ *
+ * Revision 0.15  1995/05/24  08:09:47  rpao
+ * Re-implement MULTI_TX dev->tbusy handling.
+ *
+ * Revision 0.14  1995/05/23  03:19:30  rpao
+ * Added, in nmclan_config(), "tuple.Attributes = 0;".
+ * Modified MACE ID check to ignore chip revision level.
+ * Avoid tx_free_frames race condition between _start_xmit and _interrupt.
+ *
+ * Revision 0.13  1995/05/18  05:56:34  rpao
+ * Statistics changes.
+ * Bug fix: nmclan_reset did not enable TX and RX: call restore_multicast_list.
+ * Bug fix: mace_interrupt checks ~MACE_IMR_DEFAULT.  Fixes driver lockup.
+ *
+ * Revision 0.12  1995/05/14  00:12:23  rpao
+ * Statistics overhaul.
+ *
+
+95/05/13 rpao	V0.10a
+		Bug fix: MACE statistics counters used wrong I/O ports.
+		Bug fix: mace_interrupt() needed to allow statistics to be
+		processed without RX or TX interrupts pending.
+95/05/11 rpao	V0.10
+		Multiple transmit request processing.
+		Modified statistics to use MACE counters where possible.
+95/05/10 rpao	V0.09 Bug fix: Must use IO_DATA_PATH_WIDTH_AUTO.
+		*Released
+95/05/10 rpao	V0.08
+		Bug fix: Make all non-exported functions private by using
+		static keyword.
+		Bug fix: Test IntrCnt _before_ reading MACE_IR.
+95/05/10 rpao	V0.07 Statistics.
+95/05/09 rpao	V0.06 Fix rx_framecnt problem by addition of PCIC wait states.
+
+---------------------------------------------------------------------------- */
+
+/* ----------------------------------------------------------------------------
+Conditional Compilation Options
+---------------------------------------------------------------------------- */
+
+#define MULTI_TX			0
+#define RESET_ON_TIMEOUT		1
+#define TX_INTERRUPTABLE		1
+#define RESET_XILINX			0
+
+/* ----------------------------------------------------------------------------
+Include Files
+---------------------------------------------------------------------------- */
+
+#include <pcmcia/config.h>
+#include <pcmcia/k_compat.h>
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/sched.h>
+#include <linux/ptrace.h>
+#include <linux/malloc.h>
+#include <linux/string.h>
+#include <linux/timer.h>
+#include <linux/interrupt.h>
+#include <linux/in.h>
+#include <linux/delay.h>
+#include <asm/io.h>
+#include <asm/system.h>
+#include <asm/bitops.h>
+
+#include <linux/netdevice.h>
+#include <linux/etherdevice.h>
+#include <linux/skbuff.h>
+#include <linux/if_arp.h>
+#include <linux/ioport.h>
+
+#include <pcmcia/version.h>
+#include <pcmcia/cs_types.h>
+#include <pcmcia/cs.h>
+#include <pcmcia/cisreg.h>
+#include <pcmcia/cistpl.h>
+#include <pcmcia/ds.h>
+
+/* ----------------------------------------------------------------------------
+Defines
+---------------------------------------------------------------------------- */
+
+#define ETHER_ADDR_LEN			ETH_ALEN
+					/* 6 bytes in an Ethernet Address */
+#define MACE_LADRF_LEN			8
+					/* 8 bytes in Logical Address Filter */
+
+/* Loop Control Defines */
+#define MACE_MAX_IR_ITERATIONS		10
+#define MACE_MAX_RX_ITERATIONS		12
+	/*
+	TBD: Dean brought this up, and I assumed the hardware would
+	handle it:
+
+	If MACE_MAX_RX_ITERATIONS is > 1, rx_framecnt may still be
+	non-zero when the isr exits.  We may not get another interrupt
+	to process the remaining packets for some time.
+	*/
+
+/*
+The Am2150 has a Xilinx XC3042 field programmable gate array (FPGA)
+which manages the interface between the MACE and the PCMCIA bus.  It
+also includes buffer management for the 32K x 8 SRAM to control up to
+four transmit and 12 receive frames at a time.
+*/
+#define AM2150_MAX_TX_FRAMES		4
+#define AM2150_MAX_RX_FRAMES		12
+
+/* Am2150 Ethernet Card I/O Mapping */
+#define AM2150_RCV			0x00
+#define AM2150_XMT			0x04
+#define AM2150_XMT_SKIP			0x09
+#define AM2150_RCV_NEXT			0x0A
+#define AM2150_RCV_FRAME_COUNT		0x0B
+#define AM2150_MACE_BANK		0x0C
+#define AM2150_MACE_BASE		0x10
+
+/* MACE Registers */
+#define MACE_RCVFIFO			0
+#define MACE_XMTFIFO			1
+#define MACE_XMTFC			2
+#define MACE_XMTFS			3
+#define MACE_XMTRC			4
+#define MACE_RCVFC			5
+#define MACE_RCVFS			6
+#define MACE_FIFOFC			7
+#define MACE_IR				8
+#define MACE_IMR			9
+#define MACE_PR				10
+#define MACE_BIUCC			11
+#define MACE_FIFOCC			12
+#define MACE_MACCC			13
+#define MACE_PLSCC			14
+#define MACE_PHYCC			15
+#define MACE_CHIPIDL			16
+#define MACE_CHIPIDH			17
+#define MACE_IAC			18
+/* Reserved */
+#define MACE_LADRF			20
+#define MACE_PADR			21
+/* Reserved */
+/* Reserved */
+#define MACE_MPC			24
+/* Reserved */
+#define MACE_RNTPC			26
+#define MACE_RCVCC			27
+/* Reserved */
+#define MACE_UTR			29
+#define MACE_RTR1			30
+#define MACE_RTR2			31
+
+/* MACE Bit Masks */
+#define MACE_XMTRC_EXDEF		0x80
+#define MACE_XMTRC_XMTRC		0x0F
+
+#define MACE_XMTFS_XMTSV		0x80
+#define MACE_XMTFS_UFLO			0x40
+#define MACE_XMTFS_LCOL			0x20
+#define MACE_XMTFS_MORE			0x10
+#define MACE_XMTFS_ONE			0x08
+#define MACE_XMTFS_DEFER		0x04
+#define MACE_XMTFS_LCAR			0x02
+#define MACE_XMTFS_RTRY			0x01
+
+#define MACE_RCVFS_RCVSTS		0xF000
+#define MACE_RCVFS_OFLO			0x8000
+#define MACE_RCVFS_CLSN			0x4000
+#define MACE_RCVFS_FRAM			0x2000
+#define MACE_RCVFS_FCS			0x1000
+
+#define MACE_FIFOFC_RCVFC		0xF0
+#define MACE_FIFOFC_XMTFC		0x0F
+
+#define MACE_IR_JAB			0x80
+#define MACE_IR_BABL			0x40
+#define MACE_IR_CERR			0x20
+#define MACE_IR_RCVCCO			0x10
+#define MACE_IR_RNTPCO			0x08
+#define MACE_IR_MPCO			0x04
+#define MACE_IR_RCVINT			0x02
+#define MACE_IR_XMTINT			0x01
+
+#define MACE_MACCC_PROM			0x80
+#define MACE_MACCC_DXMT2PD		0x40
+#define MACE_MACCC_EMBA			0x20
+#define MACE_MACCC_RESERVED		0x10
+#define MACE_MACCC_DRCVPA		0x08
+#define MACE_MACCC_DRCVBC		0x04
+#define MACE_MACCC_ENXMT		0x02
+#define MACE_MACCC_ENRCV		0x01
+
+#define MACE_PHYCC_LNKFL		0x80
+#define MACE_PHYCC_DLNKTST		0x40
+#define MACE_PHYCC_REVPOL		0x20
+#define MACE_PHYCC_DAPC			0x10
+#define MACE_PHYCC_LRT			0x08
+#define MACE_PHYCC_ASEL			0x04
+#define MACE_PHYCC_RWAKE		0x02
+#define MACE_PHYCC_AWAKE		0x01
+
+#define MACE_IAC_ADDRCHG		0x80
+#define MACE_IAC_PHYADDR		0x04
+#define MACE_IAC_LOGADDR		0x02
+
+#define MACE_UTR_RTRE			0x80
+#define MACE_UTR_RTRD			0x40
+#define MACE_UTR_RPA			0x20
+#define MACE_UTR_FCOLL			0x10
+#define MACE_UTR_RCVFCSE		0x08
+#define MACE_UTR_LOOP_INCL_MENDEC	0x06
+#define MACE_UTR_LOOP_NO_MENDEC		0x04
+#define MACE_UTR_LOOP_EXTERNAL		0x02
+#define MACE_UTR_LOOP_NONE		0x00
+#define MACE_UTR_RESERVED		0x01
+
+/* Switch MACE register bank (only 0 and 1 are valid) */
+#define MACEBANK(win_num) outb((win_num), ioaddr + AM2150_MACE_BANK)
+
+#define MACE_IMR_DEFAULT \
+  (0xFF - \
+    ( \
+      MACE_IR_CERR | \
+      MACE_IR_RCVCCO | \
+      MACE_IR_RNTPCO | \
+      MACE_IR_MPCO | \
+      MACE_IR_RCVINT | \
+      MACE_IR_XMTINT \
+    ) \
+  )
+#undef MACE_IMR_DEFAULT
+#define MACE_IMR_DEFAULT 0x00 /* New statistics handling: grab everything */
+
+#define TX_TIMEOUT		((400*HZ)/1000)
+
+/* ----------------------------------------------------------------------------
+Type Definitions
+---------------------------------------------------------------------------- */
+
+typedef struct _mace_statistics {
+    /* MACE_XMTFS */
+    int xmtsv;
+    int uflo;
+    int lcol;
+    int more;
+    int one;
+    int defer;
+    int lcar;
+    int rtry;
+
+    /* MACE_XMTRC */
+    int exdef;
+    int xmtrc;
+
+    /* RFS1--Receive Status (RCVSTS) */
+    int oflo;
+    int clsn;
+    int fram;
+    int fcs;
+
+    /* RFS2--Runt Packet Count (RNTPC) */
+    int rfs_rntpc;
+
+    /* RFS3--Receive Collision Count (RCVCC) */
+    int rfs_rcvcc;
+
+    /* MACE_IR */
+    int jab;
+    int babl;
+    int cerr;
+    int rcvcco;
+    int rntpco;
+    int mpco;
+
+    /* MACE_MPC */
+    int mpc;
+
+    /* MACE_RNTPC */
+    int rntpc;
+
+    /* MACE_RCVCC */
+    int rcvcc;
+} mace_statistics;
+
+typedef struct _mace_private {
+    dev_link_t link;
+    struct net_device dev;
+    dev_node_t node;
+    struct net_device_stats linux_stats; /* Linux statistics counters */
+    mace_statistics mace_stats; /* MACE chip statistics counters */
+
+    /* restore_multicast_list() state variables */
+    int multicast_ladrf[MACE_LADRF_LEN]; /* Logical address filter */
+    int multicast_num_addrs;
+
+    char tx_free_frames; /* Number of free transmit frame buffers */
+    char tx_irq_disabled; /* MACE TX interrupt disabled */
+} mace_private;
+
+/* ----------------------------------------------------------------------------
+Private Global Variables
+---------------------------------------------------------------------------- */
+
+#ifdef PCMCIA_DEBUG
+static char rcsid[] =
+"nmclan_cs.c,v 0.16 1995/07/01 06:42:17 rpao Exp rpao";
+static char *version =
+"nmclan_cs 0.16 (Roger C. Pao)";
+#endif
+
+static dev_info_t dev_info="nmclan_cs";
+static dev_link_t *dev_list=NULL;
+
+static char *if_names[]={
+    "Auto", "10baseT", "BNC",
+};
+
+#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)
+#else
+#define DEBUG(n, args...)
+#endif
+
+/* ----------------------------------------------------------------------------
+Parameters
+	These are the parameters that can be set during loading with
+	'insmod'.
+---------------------------------------------------------------------------- */
+
+/* 0=auto, 1=10baseT, 2 = 10base2, default=auto */
+static int if_port=0;
+
+/* Bit map of interrupts to choose from */
+static u_int irq_mask = 0xdeb8;
+static int irq_list[4] = { -1 };
+
+MODULE_PARM(if_port, "i");
+MODULE_PARM(irq_mask, "i");
+MODULE_PARM(irq_list, "1-4i");
+
+/* ----------------------------------------------------------------------------
+Function Prototypes
+---------------------------------------------------------------------------- */
+
+static void nmclan_config(dev_link_t *link);
+static void nmclan_release(u_long arg);
+static int nmclan_event(event_t event, int priority,
+			event_callback_args_t *args);
+
+static void nmclan_reset(struct net_device *dev);
+static int mace_config(struct net_device *dev, struct ifmap *map);
+static int mace_open(struct net_device *dev);
+static int mace_close(struct net_device *dev);
+static int mace_start_xmit(struct sk_buff *skb, struct net_device *dev);
+static void mace_tx_timeout(struct net_device *dev);
+static void mace_interrupt(int irq, void *dev_id, struct pt_regs *regs);
+static struct net_device_stats *mace_get_stats(struct net_device *dev);
+static int mace_rx(struct net_device *dev, unsigned char RxCnt);
+static void restore_multicast_list(struct net_device *dev);
+
+static void set_multicast_list(struct net_device *dev);
+
+static dev_link_t *nmclan_attach(void);
+static void nmclan_detach(dev_link_t *);
+
+/* ----------------------------------------------------------------------------
+flush_stale_links
+	Clean up stale device structures
+---------------------------------------------------------------------------- */
+
+static void flush_stale_links(void)
+{
+    dev_link_t *link, *next;
+    for (link = dev_list; link; link = next) {
+	next = link->next;
+	if (link->state & DEV_STALE_LINK)
+	    nmclan_detach(link);
+    }
+}
+
+/* ----------------------------------------------------------------------------
+cs_error
+	Report a Card Services related error.
+---------------------------------------------------------------------------- */
+
+static void cs_error(client_handle_t handle, int func, int ret)
+{
+    error_info_t err = { func, ret };
+    CardServices(ReportError, handle, &err);
+}
+
+/* ----------------------------------------------------------------------------
+nmclan_attach
+	Creates an "instance" of the driver, allocating local data
+	structures for one device.  The device is registered with Card
+	Services.
+---------------------------------------------------------------------------- */
+
+static dev_link_t *nmclan_attach(void)
+{
+    mace_private *lp;
+    dev_link_t *link;
+    struct net_device *dev;
+    client_reg_t client_reg;
+    int i, ret;
+
+    DEBUG(0, "nmclan_attach()\n");
+    DEBUG(1, "%s\n", rcsid);
+    flush_stale_links();
+
+    /* Create new ethernet device */
+    lp = kmalloc(sizeof(*lp), GFP_KERNEL);
+    if (!lp) return NULL;
+    memset(lp, 0, sizeof(*lp));
+    link = &lp->link; dev = &lp->dev;
+    link->priv = dev->priv = link->irq.Instance = lp;
+
+    link->release.function = &nmclan_release;
+    link->release.data = (u_long)link;
+    link->io.NumPorts1 = 32;
+    link->io.Attributes1 = IO_DATA_PATH_WIDTH_AUTO;
+    link->io.IOAddrLines = 5;
+    link->irq.Attributes = IRQ_TYPE_EXCLUSIVE | IRQ_HANDLE_PRESENT;
+    link->irq.IRQInfo1 = IRQ_INFO2_VALID|IRQ_LEVEL_ID;
+    if (irq_list[0] == -1)
+	link->irq.IRQInfo2 = irq_mask;
+    else
+	for (i = 0; i < 4; i++)
+	    link->irq.IRQInfo2 |= 1 << irq_list[i];
+    link->irq.Handler = &mace_interrupt;
+    link->conf.Attributes = CONF_ENABLE_IRQ;
+    link->conf.Vcc = 50;
+    link->conf.IntType = INT_MEMORY_AND_IO;
+    link->conf.ConfigIndex = 1;
+    link->conf.Present = PRESENT_OPTION;
+
+    lp->tx_free_frames=AM2150_MAX_TX_FRAMES;
+
+    dev->hard_start_xmit = &mace_start_xmit;
+    dev->set_config = &mace_config;
+    dev->get_stats = &mace_get_stats;
+    dev->set_multicast_list = &set_multicast_list;
+    ether_setup(dev);
+    dev->name = lp->node.dev_name;
+    dev->open = &mace_open;
+    dev->stop = &mace_close;
+#ifdef HAVE_NETIF_QUEUE
+    dev->tx_timeout = mace_tx_timeout;
+    dev->watchdog_timeo = TX_TIMEOUT;
+#endif
+
+    /* Register with Card Services */
+    link->next = dev_list;
+    dev_list = link;
+    client_reg.dev_info = &dev_info;
+    client_reg.Attributes = INFO_IO_CLIENT | INFO_CARD_SHARE;
+    client_reg.EventMask =
+	CS_EVENT_CARD_INSERTION | CS_EVENT_CARD_REMOVAL |
+	CS_EVENT_RESET_PHYSICAL | CS_EVENT_CARD_RESET |
+	CS_EVENT_PM_SUSPEND | CS_EVENT_PM_RESUME;
+    client_reg.event_handler = &nmclan_event;
+    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);
+	nmclan_detach(link);
+	return NULL;
+    }
+
+    return link;
+} /* nmclan_attach */
+
+/* ----------------------------------------------------------------------------
+nmclan_detach
+	This deletes a driver "instance".  The device is de-registered
+	with Card Services.  If it has been released, all local data
+	structures are freed.  Otherwise, the structures will be freed
+	when the device is released.
+---------------------------------------------------------------------------- */
+
+static void nmclan_detach(dev_link_t *link)
+{
+    mace_private *lp = link->priv;
+    dev_link_t **linkp;
+
+    DEBUG(0, "nmclan_detach(0x%p)\n", link);
+
+    /* Locate device structure */
+    for (linkp = &dev_list; *linkp; linkp = &(*linkp)->next)
+	if (*linkp == link) break;
+    if (*linkp == NULL)
+	return;
+
+    del_timer(&link->release);
+    if (link->state & DEV_CONFIG) {
+	nmclan_release((u_long)link);
+	if (link->state & DEV_STALE_CONFIG) {
+	    link->state |= DEV_STALE_LINK;
+	    return;
+	}
+    }
+
+    if (link->handle)
+	CardServices(DeregisterClient, link->handle);
+
+    /* Unlink device structure, free bits */
+    *linkp = link->next;
+    if (link->dev)
+	unregister_netdev(&lp->dev);
+    kfree(lp);
+
+} /* nmclan_detach */
+
+/* ----------------------------------------------------------------------------
+mace_read
+	Reads a MACE register.  This is bank independent; however, the
+	caller must ensure that this call is not interruptable.  We are
+	assuming that during normal operation, the MACE is always in
+	bank 0.
+---------------------------------------------------------------------------- */
+static int mace_read(ioaddr_t ioaddr, int reg)
+{
+  int data = 0xFF;
+  unsigned long flags;
+
+  switch (reg >> 4) {
+    case 0: /* register 0-15 */
+      data = inb(ioaddr + AM2150_MACE_BASE + reg);
+      break;
+    case 1: /* register 16-31 */
+      save_flags(flags);
+      cli();
+      MACEBANK(1);
+      data = inb(ioaddr + AM2150_MACE_BASE + (reg & 0x0F));
+      MACEBANK(0);
+      restore_flags(flags);
+      break;
+  }
+  return (data & 0xFF);
+} /* mace_read */
+
+/* ----------------------------------------------------------------------------
+mace_write
+	Writes to a MACE register.  This is bank independent; however,
+	the caller must ensure that this call is not interruptable.  We
+	are assuming that during normal operation, the MACE is always in
+	bank 0.
+---------------------------------------------------------------------------- */
+static void mace_write(ioaddr_t ioaddr, int reg, int data)
+{
+  unsigned long flags;
+
+  switch (reg >> 4) {
+    case 0: /* register 0-15 */
+      outb(data & 0xFF, ioaddr + AM2150_MACE_BASE + reg);
+      break;
+    case 1: /* register 16-31 */
+      save_flags(flags);
+      cli();
+      MACEBANK(1);
+      outb(data & 0xFF, ioaddr + AM2150_MACE_BASE + (reg & 0x0F));
+      MACEBANK(0);
+      restore_flags(flags);
+      break;
+  }
+} /* mace_write */
+
+/* ----------------------------------------------------------------------------
+mace_init
+	Resets the MACE chip.
+---------------------------------------------------------------------------- */
+static void mace_init(ioaddr_t ioaddr, char *enet_addr)
+{
+  int i;
+
+  /* MACE Software reset */
+  mace_write(ioaddr, MACE_BIUCC, 1);
+  while (mace_read(ioaddr, MACE_BIUCC) & 0x01) {
+    /* Wait for reset bit to be cleared automatically after <= 200ns */;
+  }
+  mace_write(ioaddr, MACE_BIUCC, 0);
+
+  /* The Am2150 requires that the MACE FIFOs operate in burst mode. */
+  mace_write(ioaddr, MACE_FIFOCC, 0x0F);
+
+  mace_write(ioaddr, MACE_RCVFC, 0); /* Disable Auto Strip Receive */
+  mace_write(ioaddr, MACE_IMR, 0xFF); /* Disable all interrupts until _open */
+
+  /*
+   * Bit 2-1 PORTSEL[1-0] Port Select.
+   * 00 AUI/10Base-2
+   * 01 10Base-T
+   * 10 DAI Port (reserved in Am2150)
+   * 11 GPSI
+   * For this card, only the first two are valid.
+   * So, PLSCC should be set to
+   * 0x00 for 10Base-2
+   * 0x02 for 10Base-T
+   * Or just set ASEL in PHYCC below!
+   */
+  switch (if_port) {
+    case 1:
+      mace_write(ioaddr, MACE_PLSCC, 0x02);
+      break;
+    case 2:
+      mace_write(ioaddr, MACE_PLSCC, 0x00);
+      break;
+    default:
+      mace_write(ioaddr, MACE_PHYCC, /* ASEL */ 4);
+      /* ASEL Auto Select.  When set, the PORTSEL[1-0] bits are overridden,
+	 and the MACE device will automatically select the operating media
+	 interface port. */
+      break;
+  }
+
+  mace_write(ioaddr, MACE_IAC, MACE_IAC_ADDRCHG | MACE_IAC_PHYADDR);
+  /* Poll ADDRCHG bit */
+  while (mace_read(ioaddr, MACE_IAC) & MACE_IAC_ADDRCHG)
+    ;
+  /* Set PADR register */
+  for (i = 0; i < ETHER_ADDR_LEN; i++)
+    mace_write(ioaddr, MACE_PADR, enet_addr[i]);
+
+  /* MAC Configuration Control Register should be written last */
+  /* Let set_multicast_list set this. */
+  /* mace_write(ioaddr, MACE_MACCC, MACE_MACCC_ENXMT | MACE_MACCC_ENRCV); */
+  mace_write(ioaddr, MACE_MACCC, 0x00);
+} /* mace_init */
+
+/* ----------------------------------------------------------------------------
+nmclan_config
+	This routine is scheduled to run after a CARD_INSERTION event
+	is received, to configure the PCMCIA socket, and to make the
+	ethernet device available to the system.
+---------------------------------------------------------------------------- */
+
+#define CS_CHECK(fn, args...) \
+while ((last_ret=CardServices(last_fn=(fn), args))!=0) goto cs_failed
+
+static void nmclan_config(dev_link_t *link)
+{
+  client_handle_t handle = link->handle;
+  mace_private *lp = link->priv;
+  struct net_device *dev = &lp->dev;
+  tuple_t tuple;
+  cisparse_t parse;
+  u_char buf[64];
+  int i, last_ret, last_fn;
+  ioaddr_t ioaddr;
+
+  DEBUG(0, "nmclan_config(0x%p)\n", link);
+
+  tuple.Attributes = 0;
+  tuple.TupleData = buf;
+  tuple.TupleDataMax = 64;
+  tuple.TupleOffset = 0;
+  tuple.DesiredTuple = CISTPL_CONFIG;
+  CS_CHECK(GetFirstTuple, handle, &tuple);
+  CS_CHECK(GetTupleData, handle, &tuple);
+  CS_CHECK(ParseTuple, handle, &tuple, &parse);
+  link->conf.ConfigBase = parse.config.base;
+
+  /* Configure card */
+  link->state |= DEV_CONFIG;
+
+  CS_CHECK(RequestIO, handle, &link->io);
+  CS_CHECK(RequestIRQ, handle, &link->irq);
+  CS_CHECK(RequestConfiguration, handle, &link->conf);
+  dev->irq = link->irq.AssignedIRQ;
+  dev->base_addr = link->io.BasePort1;
+  i = register_netdev(dev);
+  if (i != 0) {
+    printk(KERN_NOTICE "nmclan_cs: register_netdev() failed\n");
+    goto failed;
+  }
+
+  ioaddr = dev->base_addr;
+
+  /* Read the ethernet address from the CIS. */
+  tuple.DesiredTuple = 0x80 /* CISTPL_CFTABLE_ENTRY_MISC */;
+  tuple.TupleData = buf;
+  tuple.TupleDataMax = 64;
+  tuple.TupleOffset = 0;
+  CS_CHECK(GetFirstTuple, handle, &tuple);
+  CS_CHECK(GetTupleData, handle, &tuple);
+  memcpy(dev->dev_addr, tuple.TupleData, ETHER_ADDR_LEN);
+
+  /* Verify configuration by reading the MACE ID. */
+  {
+    char sig[2];
+
+    sig[0] = mace_read(ioaddr, MACE_CHIPIDL);
+    sig[1] = mace_read(ioaddr, MACE_CHIPIDH);
+    if ((sig[0] == 0x40) && ((sig[1] & 0x0F) == 0x09)) {
+      DEBUG(0, "nmclan_cs configured: mace id=%x %x\n",
+	    sig[0], sig[1]);
+    } else {
+      printk(KERN_NOTICE "nmclan_cs: mace id not found: %x %x should"
+	     " be 0x40 0x?9\n", sig[0], sig[1]);
+      link->state &= ~DEV_CONFIG_PENDING;
+      return;
+    }
+  }
+
+  mace_init(ioaddr, dev->dev_addr);
+
+  /* The if_port symbol can be set when the module is loaded */
+  if (if_port <= 2)
+    dev->if_port = if_port;
+  else
+    printk(KERN_NOTICE "nmclan_cs: invalid if_port requested\n");
+
+#if 0
+  /* Determine which port we are using if auto is selected */
+  if (if_port==0) {
+    mace_write(ioaddr, MACE_MACCC, MACE_MACCC_ENXMT | MACE_MACCC_ENRCV);
+    DEBUG(2, "%s: mace_phycc 0x%X.\n", dev->name,
+	  mace_read(ioaddr, MACE_PHYCC));
+    if (mace_read(ioaddr, MACE_PHYCC) & MACE_PHYCC_LNKFL)
+      /* 10base-T receiver is in link fail, MACE is using AUI port. */
+      dev->if_port = 2;
+    else
+      dev->if_port = 1;
+    mace_write(ioaddr, MACE_MACCC, 0x00);
+  }
+  /* Unfortunately, this doesn't seem to work.  LNKFL is always set.
+     LNKFL is supposed to be opposite the green LED on the edge of the card.
+     It doesn't work if it is checked and printed in _open() either.
+     It does work if check in _start_xmit(), but that's not a good place
+     to printk. */
+#endif
+
+  link->dev = &lp->node;
+  link->state &= ~DEV_CONFIG_PENDING;
+
+  printk(KERN_INFO "%s: nmclan: port %#3lx, irq %d, %s port, hw_addr ",
+	 dev->name, dev->base_addr, dev->irq, if_names[dev->if_port]);
+  for (i = 0; i < 6; i++)
+      printk("%02X%s", dev->dev_addr[i], ((i<5) ? ":" : "\n"));
+  return;
+
+cs_failed:
+    cs_error(link->handle, last_fn, last_ret);
+failed:
+    nmclan_release((u_long)link);
+    return;
+
+} /* nmclan_config */
+
+/* ----------------------------------------------------------------------------
+nmclan_release
+	After a card is removed, nmclan_release() will unregister the
+	net device, and release the PCMCIA configuration.  If the device
+	is still open, this will be postponed until it is closed.
+---------------------------------------------------------------------------- */
+static void nmclan_release(u_long arg)
+{
+  dev_link_t *link = (dev_link_t *)arg;
+
+  DEBUG(0, "nmclan_release(0x%p)\n", link);
+
+  if (link->open) {
+    DEBUG(1, "nmclan_cs: release postponed, '%s' "
+	  "still open\n", link->dev->dev_name);
+    link->state |= DEV_STALE_CONFIG;
+    return;
+  }
+
+  CardServices(ReleaseConfiguration, link->handle);
+  CardServices(ReleaseIO, link->handle, &link->io);
+  CardServices(ReleaseIRQ, link->handle, &link->irq);
+
+  link->state &= ~DEV_CONFIG;
+
+} /* nmclan_release */
+
+/* ----------------------------------------------------------------------------
+nmclan_event
+	The card status event handler.  Mostly, this schedules other
+	stuff to run after an event is received.  A CARD_REMOVAL event
+	also sets some flags to discourage the net drivers from trying
+	to talk to the card any more.
+---------------------------------------------------------------------------- */
+static int nmclan_event(event_t event, int priority,
+		       event_callback_args_t *args)
+{
+  dev_link_t *link = args->client_data;
+  mace_private *lp = link->priv;
+  struct net_device *dev = &lp->dev;
+
+  DEBUG(1, "nmclan_event(0x%06x)\n", event);
+
+  switch (event) {
+    case CS_EVENT_CARD_REMOVAL:
+      link->state &= ~DEV_PRESENT;
+      if (link->state & DEV_CONFIG) {
+	netif_device_detach(dev);
+	mod_timer(&link->release, jiffies + HZ/20);
+      }
+      break;
+    case CS_EVENT_CARD_INSERTION:
+      link->state |= DEV_PRESENT | DEV_CONFIG_PENDING;
+      nmclan_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 (link->open)
+	  netif_device_detach(dev);
+	CardServices(ReleaseConfiguration, link->handle);
+      }
+      break;
+    case CS_EVENT_PM_RESUME:
+      link->state &= ~DEV_SUSPEND;
+      /* Fall through... */
+    case CS_EVENT_CARD_RESET:
+      if (link->state & DEV_CONFIG) {
+	CardServices(RequestConfiguration, link->handle, &link->conf);
+	if (link->open) {
+	  nmclan_reset(dev);
+	  netif_device_attach(dev);
+	}
+      }
+      break;
+    case CS_EVENT_RESET_REQUEST:
+      return 1;
+      break;
+  }
+  return 0;
+} /* nmclan_event */
+
+/* ----------------------------------------------------------------------------
+nmclan_reset
+	Reset and restore all of the Xilinx and MACE registers.
+---------------------------------------------------------------------------- */
+static void nmclan_reset(struct net_device *dev)
+{
+  mace_private *lp = dev->priv;
+
+#if RESET_XILINX
+  dev_link_t *link = &lp->link;
+  conf_reg_t reg;
+  u_long OrigCorValue; 
+
+  /* Save original COR value */
+  reg.Function = 0;
+  reg.Action = CS_READ;
+  reg.Offset = CISREG_COR;
+  reg.Value = 0;
+  CardServices(AccessConfigurationRegister, link->handle, &reg);
+  OrigCorValue = reg.Value;
+
+  /* Reset Xilinx */
+  reg.Action = CS_WRITE;
+  reg.Offset = CISREG_COR;
+  DEBUG(1, "nmclan_reset: OrigCorValue=0x%lX, resetting...\n",
+	OrigCorValue);
+  reg.Value = COR_SOFT_RESET;
+  CardServices(AccessConfigurationRegister, link->handle, &reg);
+  /* Need to wait for 20 ms for PCMCIA to finish reset. */
+
+  /* Restore original COR configuration index */
+  reg.Value = COR_LEVEL_REQ | (OrigCorValue & COR_CONFIG_MASK);
+  CardServices(AccessConfigurationRegister, link->handle, &reg);
+  /* Xilinx is now completely reset along with the MACE chip. */
+  lp->tx_free_frames=AM2150_MAX_TX_FRAMES;
+
+#endif /* #if RESET_XILINX */
+
+  /* Xilinx is now completely reset along with the MACE chip. */
+  lp->tx_free_frames=AM2150_MAX_TX_FRAMES;
+
+  /* Reinitialize the MACE chip for operation. */
+  mace_init(dev->base_addr, dev->dev_addr);
+  mace_write(dev->base_addr, MACE_IMR, MACE_IMR_DEFAULT);
+
+  /* Restore the multicast list and enable TX and RX. */
+  restore_multicast_list(dev);
+} /* nmclan_reset */
+
+/* ----------------------------------------------------------------------------
+mace_config
+	[Someone tell me what this is supposed to do?  Is if_port a defined
+	standard?  If so, there should be defines to indicate 1=10Base-T,
+	2=10Base-2, etc. including limited automatic detection.]
+---------------------------------------------------------------------------- */
+static int mace_config(struct net_device *dev, struct ifmap *map)
+{
+  if ((map->port != (u_char)(-1)) && (map->port != dev->if_port)) {
+    if (map->port <= 2) {
+      dev->if_port = map->port;
+      printk(KERN_INFO "%s: switched to %s port\n", dev->name,
+	     if_names[dev->if_port]);
+    } else
+      return -EINVAL;
+  }
+  return 0;
+} /* mace_config */
+
+/* ----------------------------------------------------------------------------
+mace_open
+	Open device driver.
+---------------------------------------------------------------------------- */
+static int mace_open(struct net_device *dev)
+{
+  ioaddr_t ioaddr = dev->base_addr;
+  mace_private *lp = dev->priv;
+  dev_link_t *link = &lp->link;
+
+  if (!DEV_OK(link))
+    return -ENODEV;
+
+  link->open++;
+  MOD_INC_USE_COUNT;
+
+  MACEBANK(0);
+
+  netif_start_queue(dev);
+  netif_mark_up(dev);
+  nmclan_reset(dev);
+
+  return 0; /* Always succeed */
+} /* mace_open */
+
+/* ----------------------------------------------------------------------------
+mace_close
+	Closes device driver.
+---------------------------------------------------------------------------- */
+static int mace_close(struct net_device *dev)
+{
+  ioaddr_t ioaddr = dev->base_addr;
+  mace_private *lp = dev->priv;
+  dev_link_t *link = &lp->link;
+
+  DEBUG(2, "%s: shutting down ethercard.\n", dev->name);
+
+  /* Mask off all interrupts from the MACE chip. */
+  outb(0xFF, ioaddr + AM2150_MACE_BASE + MACE_IMR);
+
+  link->open--;
+  netif_stop_queue(dev);
+  netif_mark_down(dev);
+  if (link->state & DEV_STALE_CONFIG)
+    mod_timer(&link->release, jiffies + HZ/20);
+
+  MOD_DEC_USE_COUNT;
+
+  return 0;
+} /* mace_close */
+
+/* ----------------------------------------------------------------------------
+mace_start_xmit
+	This routine begins the packet transmit function.  When completed,
+	it will generate a transmit interrupt.
+
+	According to /usr/src/linux/net/inet/dev.c, if _start_xmit
+	returns 0, the "packet is now solely the responsibility of the
+	driver."  If _start_xmit returns non-zero, the "transmission
+	failed, put skb back into a list."
+---------------------------------------------------------------------------- */
+
+static void mace_tx_timeout(struct net_device *dev)
+{
+  mace_private *lp = (mace_private *)dev->priv;
+  dev_link_t *link = &lp->link;
+
+  printk(KERN_NOTICE "%s: transmit timed out -- ", dev->name);
+#if RESET_ON_TIMEOUT
+  printk("resetting card\n");
+  CardServices(ResetCard, link->handle);
+#else /* #if RESET_ON_TIMEOUT */
+  printk("NOT resetting card\n");
+#endif /* #if RESET_ON_TIMEOUT */
+  dev->trans_start = jiffies;
+  netif_start_queue(dev);
+}
+
+static int mace_start_xmit(struct sk_buff *skb, struct net_device *dev)
+{
+  mace_private *lp = (mace_private *)dev->priv;
+  ioaddr_t ioaddr = dev->base_addr;
+
+  tx_timeout_check(dev, mace_tx_timeout);
+  skb_tx_check(dev, skb);
+
+  DEBUG(3, "%s: mace_start_xmit(length = %ld) called.\n",
+	dev->name, (long)skb->len);
+
+#if (!TX_INTERRUPTABLE)
+  /* Disable MACE TX interrupts. */
+  outb(MACE_IMR_DEFAULT | MACE_IR_XMTINT,
+    ioaddr + AM2150_MACE_BASE + MACE_IMR);
+  lp->tx_irq_disabled=1;
+#endif /* #if (!TX_INTERRUPTABLE) */
+
+  {
+    /* This block must not be interrupted by another transmit request!
+       mace_tx_timeout will take care of timer-based retransmissions from
+       the upper layers.  The interrupt handler is guaranteed never to
+       service a transmit interrupt while we are in here.
+    */
+
+    add_tx_bytes(&lp->linux_stats, skb->len);
+    lp->tx_free_frames--;
+
+    /* WARNING: Write the _exact_ number of bytes written in the header! */
+    /* Put out the word header [must be an outw()] . . . */
+    outw(skb->len, ioaddr + AM2150_XMT);
+    /* . . . and the packet [may be any combination of outw() and outb()] */
+    outsw_ns(ioaddr + AM2150_XMT, skb->data, skb->len >> 1);
+    if (skb->len & 1) {
+      /* Odd byte transfer */
+      outb(skb->data[skb->len-1], ioaddr + AM2150_XMT);
+    }
+
+    dev->trans_start = jiffies;
+
+#if MULTI_TX
+    if (lp->tx_free_frames > 0)
+      netif_start_queue(dev);
+#endif /* #if MULTI_TX */
+  }
+
+#if (!TX_INTERRUPTABLE)
+  /* Re-enable MACE TX interrupts. */
+  lp->tx_irq_disabled=0;
+  outb(MACE_IMR_DEFAULT, ioaddr + AM2150_MACE_BASE + MACE_IMR);
+#endif /* #if (!TX_INTERRUPTABLE) */
+
+  DEV_KFREE_SKB(skb);
+
+  return 0;
+} /* mace_start_xmit */
+
+/* ----------------------------------------------------------------------------
+mace_interrupt
+	The interrupt handler.
+---------------------------------------------------------------------------- */
+static void mace_interrupt(int irq, void *dev_id, struct pt_regs *regs)
+{
+  mace_private *lp = (mace_private *)dev_id;
+  struct net_device *dev = &lp->dev;
+  ioaddr_t ioaddr = dev->base_addr;
+  int status;
+  int IntrCnt = MACE_MAX_IR_ITERATIONS;
+
+  if (dev == NULL) {
+    DEBUG(2, "mace_interrupt(): irq 0x%X for unknown device.\n",
+	  irq);
+    return;
+  }
+
+  if (lp->tx_irq_disabled) {
+    printk(
+      (lp->tx_irq_disabled?
+       KERN_NOTICE "%s: Interrupt with tx_irq_disabled "
+       "[isr=%02X, imr=%02X]\n": 
+       KERN_NOTICE "%s: Re-entering the interrupt handler "
+       "[isr=%02X, imr=%02X]\n"),
+      dev->name,
+      inb(ioaddr + AM2150_MACE_BASE + MACE_IR),
+      inb(ioaddr + AM2150_MACE_BASE + MACE_IMR)
+    );
+    /* WARNING: MACE_IR has been read! */
+    return;
+  }
+
+  if (!netif_device_present(dev)) {
+    DEBUG(2, "%s: interrupt from dead card\n", dev->name);
+    goto exception;
+  }
+
+  do {
+    /* WARNING: MACE_IR is a READ/CLEAR port! */
+    status = inb(ioaddr + AM2150_MACE_BASE + MACE_IR);
+
+    DEBUG(3, "mace_interrupt: irq 0x%X status 0x%X.\n", irq, status);
+
+    if (status & MACE_IR_RCVINT) {
+      mace_rx(dev, MACE_MAX_RX_ITERATIONS);
+    }
+
+    if (status & MACE_IR_XMTINT) {
+      unsigned char fifofc;
+      unsigned char xmtrc;
+      unsigned char xmtfs;
+
+      fifofc = inb(ioaddr + AM2150_MACE_BASE + MACE_FIFOFC);
+      if ((fifofc & MACE_FIFOFC_XMTFC)==0) {
+	lp->linux_stats.tx_errors++;
+	outb(0xFF, ioaddr + AM2150_XMT_SKIP);
+      }
+
+      /* Transmit Retry Count (XMTRC, reg 4) */
+      xmtrc = inb(ioaddr + AM2150_MACE_BASE + MACE_XMTRC);
+      if (xmtrc & MACE_XMTRC_EXDEF) lp->mace_stats.exdef++;
+      lp->mace_stats.xmtrc += (xmtrc & MACE_XMTRC_XMTRC);
+
+      if (
+        (xmtfs = inb(ioaddr + AM2150_MACE_BASE + MACE_XMTFS)) &
+        MACE_XMTFS_XMTSV /* Transmit Status Valid */
+      ) {
+	lp->mace_stats.xmtsv++;
+
+	if (xmtfs & ~MACE_XMTFS_XMTSV) {
+	  if (xmtfs & MACE_XMTFS_UFLO) {
+	    /* Underflow.  Indicates that the Transmit FIFO emptied before
+	       the end of frame was reached. */
+	    lp->mace_stats.uflo++;
+	  }
+	  if (xmtfs & MACE_XMTFS_LCOL) {
+	    /* Late Collision */
+	    lp->mace_stats.lcol++;
+	  }
+	  if (xmtfs & MACE_XMTFS_MORE) {
+	    /* MORE than one retry was needed */
+	    lp->mace_stats.more++;
+	  }
+	  if (xmtfs & MACE_XMTFS_ONE) {
+	    /* Exactly ONE retry occurred */
+	    lp->mace_stats.one++;
+	  }
+	  if (xmtfs & MACE_XMTFS_DEFER) {
+	    /* Transmission was defered */
+	    lp->mace_stats.defer++;
+	  }
+	  if (xmtfs & MACE_XMTFS_LCAR) {
+	    /* Loss of carrier */
+	    lp->mace_stats.lcar++;
+	  }
+	  if (xmtfs & MACE_XMTFS_RTRY) {
+	    /* Retry error: transmit aborted after 16 attempts */
+	    lp->mace_stats.rtry++;
+	  }
+        } /* if (xmtfs & ~MACE_XMTFS_XMTSV) */
+
+      } /* if (xmtfs & MACE_XMTFS_XMTSV) */
+
+      lp->linux_stats.tx_packets++;
+      lp->tx_free_frames++;
+      netif_wake_queue(dev);
+    } /* if (status & MACE_IR_XMTINT) */
+
+    if (status & ~MACE_IMR_DEFAULT & ~MACE_IR_RCVINT & ~MACE_IR_XMTINT) {
+      if (status & MACE_IR_JAB) {
+        /* Jabber Error.  Excessive transmit duration (20-150ms). */
+        lp->mace_stats.jab++;
+      }
+      if (status & MACE_IR_BABL) {
+        /* Babble Error.  >1518 bytes transmitted. */
+        lp->mace_stats.babl++;
+      }
+      if (status & MACE_IR_CERR) {
+	/* Collision Error.  CERR indicates the absence of the
+	   Signal Quality Error Test message after a packet
+	   transmission. */
+        lp->mace_stats.cerr++;
+      }
+      if (status & MACE_IR_RCVCCO) {
+        /* Receive Collision Count Overflow; */
+        lp->mace_stats.rcvcco++;
+      }
+      if (status & MACE_IR_RNTPCO) {
+        /* Runt Packet Count Overflow */
+        lp->mace_stats.rntpco++;
+      }
+      if (status & MACE_IR_MPCO) {
+        /* Missed Packet Count Overflow */
+        lp->mace_stats.mpco++;
+      }
+    } /* if (status & ~MACE_IMR_DEFAULT & ~MACE_IR_RCVINT & ~MACE_IR_XMTINT) */
+
+  } while ((status & ~MACE_IMR_DEFAULT) && (--IntrCnt));
+
+exception:
+  return;
+} /* mace_interrupt */
+
+/* ----------------------------------------------------------------------------
+mace_rx
+	Receives packets.
+---------------------------------------------------------------------------- */
+static int mace_rx(struct net_device *dev, unsigned char RxCnt)
+{
+  mace_private *lp = (mace_private *)dev->priv;
+  ioaddr_t ioaddr = dev->base_addr;
+  unsigned char rx_framecnt;
+  unsigned short rx_status;
+
+  while (
+    ((rx_framecnt = inb(ioaddr + AM2150_RCV_FRAME_COUNT)) > 0) &&
+    (rx_framecnt <= 12) && /* rx_framecnt==0xFF if card is extracted. */
+    (RxCnt--)
+  ) {
+    rx_status = inw(ioaddr + AM2150_RCV);
+
+    DEBUG(3, "%s: in mace_rx(), framecnt 0x%X, rx_status"
+	  " 0x%X.\n", dev->name, rx_framecnt, rx_status);
+
+    if (rx_status & MACE_RCVFS_RCVSTS) { /* Error, update stats. */
+      lp->linux_stats.rx_errors++;
+      if (rx_status & MACE_RCVFS_OFLO) {
+        lp->mace_stats.oflo++;
+      }
+      if (rx_status & MACE_RCVFS_CLSN) {
+        lp->mace_stats.clsn++;
+      }
+      if (rx_status & MACE_RCVFS_FRAM) {
+	lp->mace_stats.fram++;
+      }
+      if (rx_status & MACE_RCVFS_FCS) {
+        lp->mace_stats.fcs++;
+      }
+    } else {
+      short pkt_len = (rx_status & ~MACE_RCVFS_RCVSTS) - 4;
+        /* Auto Strip is off, always subtract 4 */
+      struct sk_buff *skb;
+
+      lp->mace_stats.rfs_rntpc += inb(ioaddr + AM2150_RCV);
+        /* runt packet count */
+      lp->mace_stats.rfs_rcvcc += inb(ioaddr + AM2150_RCV);
+        /* rcv collision count */
+
+      DEBUG(3, "    receiving packet size 0x%X rx_status"
+	    " 0x%X.\n", pkt_len, rx_status);
+
+      skb = dev_alloc_skb(pkt_len+2);
+
+      if (skb != NULL) {
+	skb->dev = dev;
+
+	skb_reserve(skb, 2);
+	insw_ns(ioaddr + AM2150_RCV, skb_put(skb, pkt_len), pkt_len>>1);
+	if (pkt_len & 1)
+	    *(skb->tail-1) = inb(ioaddr + AM2150_RCV);
+	skb->protocol = eth_type_trans(skb, dev);
+	
+	netif_rx(skb); /* Send the packet to the upper (protocol) layers. */
+
+	lp->linux_stats.rx_packets++;
+	add_rx_bytes(&lp->linux_stats, skb->len);
+	outb(0xFF, ioaddr + AM2150_RCV_NEXT); /* skip to next frame */
+	continue;
+      } else {
+	DEBUG(1, "%s: couldn't allocate a sk_buff of size"
+	      " %d.\n", dev->name, pkt_len);
+	lp->linux_stats.rx_dropped++;
+      }
+    }
+    outb(0xFF, ioaddr + AM2150_RCV_NEXT); /* skip to next frame */
+  } /* while */
+
+  return 0;
+} /* mace_rx */
+
+/* ----------------------------------------------------------------------------
+pr_linux_stats
+---------------------------------------------------------------------------- */
+static void pr_linux_stats(struct net_device_stats *pstats)
+{
+  DEBUG(2, "pr_linux_stats\n");
+  DEBUG(2, " rx_packets=%-7ld        tx_packets=%ld\n",
+	(long)pstats->rx_packets, (long)pstats->tx_packets);
+  DEBUG(2, " rx_errors=%-7ld         tx_errors=%ld\n",
+	(long)pstats->rx_errors, (long)pstats->tx_errors);
+  DEBUG(2, " rx_dropped=%-7ld        tx_dropped=%ld\n",
+	(long)pstats->rx_dropped, (long)pstats->tx_dropped);
+  DEBUG(2, " multicast=%-7ld         collisions=%ld\n",
+	(long)pstats->multicast, (long)pstats->collisions);
+
+  DEBUG(2, " rx_length_errors=%-7ld  rx_over_errors=%ld\n",
+	(long)pstats->rx_length_errors, (long)pstats->rx_over_errors);
+  DEBUG(2, " rx_crc_errors=%-7ld     rx_frame_errors=%ld\n",
+	(long)pstats->rx_crc_errors, (long)pstats->rx_frame_errors);
+  DEBUG(2, " rx_fifo_errors=%-7ld    rx_missed_errors=%ld\n",
+	(long)pstats->rx_fifo_errors, (long)pstats->rx_missed_errors);
+
+  DEBUG(2, " tx_aborted_errors=%-7ld tx_carrier_errors=%ld\n",
+	(long)pstats->tx_aborted_errors, (long)pstats->tx_carrier_errors);
+  DEBUG(2, " tx_fifo_errors=%-7ld    tx_heartbeat_errors=%ld\n",
+	(long)pstats->tx_fifo_errors, (long)pstats->tx_heartbeat_errors);
+  DEBUG(2, " tx_window_errors=%ld\n",
+	(long)pstats->tx_window_errors);
+} /* pr_linux_stats */
+
+/* ----------------------------------------------------------------------------
+pr_mace_stats
+---------------------------------------------------------------------------- */
+static void pr_mace_stats(mace_statistics *pstats)
+{
+  DEBUG(2, "pr_mace_stats\n");
+
+  DEBUG(2, " xmtsv=%-7d             uflo=%d\n",
+	pstats->xmtsv, pstats->uflo);
+  DEBUG(2, " lcol=%-7d              more=%d\n",
+	pstats->lcol, pstats->more);
+  DEBUG(2, " one=%-7d               defer=%d\n",
+	pstats->one, pstats->defer);
+  DEBUG(2, " lcar=%-7d              rtry=%d\n",
+	pstats->lcar, pstats->rtry);
+
+  /* MACE_XMTRC */
+  DEBUG(2, " exdef=%-7d             xmtrc=%d\n",
+	pstats->exdef, pstats->xmtrc);
+
+  /* RFS1--Receive Status (RCVSTS) */
+  DEBUG(2, " oflo=%-7d              clsn=%d\n",
+	pstats->oflo, pstats->clsn);
+  DEBUG(2, " fram=%-7d              fcs=%d\n",
+	pstats->fram, pstats->fcs);
+
+  /* RFS2--Runt Packet Count (RNTPC) */
+  /* RFS3--Receive Collision Count (RCVCC) */
+  DEBUG(2, " rfs_rntpc=%-7d         rfs_rcvcc=%d\n",
+	pstats->rfs_rntpc, pstats->rfs_rcvcc);
+
+  /* MACE_IR */
+  DEBUG(2, " jab=%-7d               babl=%d\n",
+	pstats->jab, pstats->babl);
+  DEBUG(2, " cerr=%-7d              rcvcco=%d\n",
+	pstats->cerr, pstats->rcvcco);
+  DEBUG(2, " rntpco=%-7d            mpco=%d\n",
+	pstats->rntpco, pstats->mpco);
+
+  /* MACE_MPC */
+  DEBUG(2, " mpc=%d\n", pstats->mpc);
+
+  /* MACE_RNTPC */
+  DEBUG(2, " rntpc=%d\n", pstats->rntpc);
+
+  /* MACE_RCVCC */
+  DEBUG(2, " rcvcc=%d\n", pstats->rcvcc);
+
+} /* pr_mace_stats */
+
+/* ----------------------------------------------------------------------------
+update_stats
+	Update statistics.  We change to register window 1, so this
+	should be run single-threaded if the device is active. This is
+	expected to be a rare operation, and it's simpler for the rest
+	of the driver to assume that window 0 is always valid rather
+	than use a special window-state variable.
+
+	oflo & uflo should _never_ occur since it would mean the Xilinx
+	was not able to transfer data between the MACE FIFO and the
+	card's SRAM fast enough.  If this happens, something is
+	seriously wrong with the hardware.
+---------------------------------------------------------------------------- */
+static void update_stats(ioaddr_t ioaddr, struct net_device *dev)
+{
+  mace_private *lp = (mace_private *)dev->priv;
+
+  lp->mace_stats.rcvcc += mace_read(ioaddr, MACE_RCVCC);
+  lp->mace_stats.rntpc += mace_read(ioaddr, MACE_RNTPC);
+  lp->mace_stats.mpc += mace_read(ioaddr, MACE_MPC);
+  /* At this point, mace_stats is fully updated for this call.
+     We may now update the linux_stats. */
+
+  /* The MACE has no equivalent for linux_stats field which are commented
+     out. */
+
+#if 0
+  /* These must be tracked in the main body of the driver. */
+  lp->linux_stats.rx_packets;
+  lp->linux_stats.tx_packets;
+  lp->linux_stats.rx_errors;
+  lp->linux_stats.tx_errors;
+  lp->linux_stats.rx_dropped;
+  lp->linux_stats.tx_dropped;
+#endif
+  /* lp->linux_stats.multicast; */
+  lp->linux_stats.collisions = 
+    lp->mace_stats.rcvcco * 256 + lp->mace_stats.rcvcc;
+    /* Collision: The MACE may retry sending a packet 15 times
+       before giving up.  The retry count is in XMTRC.
+       Does each retry constitute a collision?
+       If so, why doesn't the RCVCC record these collisions? */
+
+  /* detailed rx_errors: */
+  lp->linux_stats.rx_length_errors = 
+    lp->mace_stats.rntpco * 256 + lp->mace_stats.rntpc;
+  /* lp->linux_stats.rx_over_errors */
+  lp->linux_stats.rx_crc_errors = lp->mace_stats.fcs;
+  lp->linux_stats.rx_frame_errors = lp->mace_stats.fram;
+  lp->linux_stats.rx_fifo_errors = lp->mace_stats.oflo;
+  lp->linux_stats.rx_missed_errors = 
+    lp->mace_stats.mpco * 256 + lp->mace_stats.mpc;
+
+  /* detailed tx_errors */
+  lp->linux_stats.tx_aborted_errors = lp->mace_stats.rtry;
+  lp->linux_stats.tx_carrier_errors = lp->mace_stats.lcar;
+    /* LCAR usually results from bad cabling. */
+  lp->linux_stats.tx_fifo_errors = lp->mace_stats.uflo;
+  lp->linux_stats.tx_heartbeat_errors = lp->mace_stats.cerr;
+  /* lp->linux_stats.tx_window_errors; */
+
+  return;
+} /* update_stats */
+
+/* ----------------------------------------------------------------------------
+mace_get_stats
+	Gathers ethernet statistics from the MACE chip.
+---------------------------------------------------------------------------- */
+static struct net_device_stats *mace_get_stats(struct net_device *dev)
+{
+  mace_private *lp = (mace_private *)dev->priv;
+
+  update_stats(dev->base_addr, dev);
+
+  DEBUG(1, "%s: updating the statistics.\n", dev->name);
+  pr_linux_stats(&lp->linux_stats);
+  pr_mace_stats(&lp->mace_stats);
+
+  return &lp->linux_stats;
+} /* net_device_stats */
+
+/* ----------------------------------------------------------------------------
+updateCRC
+	Modified from Am79C90 data sheet.
+---------------------------------------------------------------------------- */
+
+#if BROKEN_MULTICAST
+
+static void updateCRC(int *CRC, int bit)
+{
+  int poly[]={
+    1,1,1,0, 1,1,0,1,
+    1,0,1,1, 1,0,0,0,
+    1,0,0,0, 0,0,1,1,
+    0,0,1,0, 0,0,0,0
+  }; /* CRC polynomial.  poly[n] = coefficient of the x**n term of the
+	CRC generator polynomial. */
+
+  int j;
+
+  /* shift CRC and control bit (CRC[32]) */
+  for (j = 32; j > 0; j--)
+    CRC[j] = CRC[j-1];
+  CRC[0] = 0;
+
+  /* If bit XOR(control bit) = 1, set CRC = CRC XOR polynomial. */
+  if (bit ^ CRC[32])
+    for (j = 0; j < 32; j++)
+      CRC[j] ^= poly[j];
+} /* updateCRC */
+
+/* ----------------------------------------------------------------------------
+BuildLAF
+	Build logical address filter.
+	Modified from Am79C90 data sheet.
+
+Input
+	ladrf: logical address filter (contents initialized to 0)
+	adr: ethernet address
+---------------------------------------------------------------------------- */
+static void BuildLAF(int *ladrf, int *adr)
+{
+  int CRC[33]={1}; /* CRC register, 1 word/bit + extra control bit */
+
+  int i, byte; /* temporary array indices */
+  int hashcode; /* the output object */
+
+  CRC[32]=0;
+
+  for (byte = 0; byte < 6; byte++)
+    for (i = 0; i < 8; i++)
+      updateCRC(CRC, (adr[byte] >> i) & 1);
+
+  hashcode = 0;
+  for (i = 0; i < 6; i++)
+    hashcode = (hashcode << 1) + CRC[i];
+
+  byte = hashcode >> 3;
+  ladrf[byte] |= (1 << (hashcode & 7));
+
+#ifdef PCMCIA_DEBUG
+  if (pc_debug > 2) {
+    printk(KERN_DEBUG "    adr =");
+    for (i = 0; i < 6; i++)
+      printk(" %02X", adr[i]);
+    printk("\n" KERN_DEBUG "    hashcode = %d(decimal), ladrf[0:63]"
+	   " =", hashcode);
+    for (i = 0; i < 8; i++)
+      printk(" %02X", ladrf[i]);
+    printk("\n");
+  }
+#endif
+} /* BuildLAF */
+
+/* ----------------------------------------------------------------------------
+restore_multicast_list
+	Restores the multicast filter for MACE chip to the last
+	set_multicast_list() call.
+
+Input
+	multicast_num_addrs
+	multicast_ladrf[]
+---------------------------------------------------------------------------- */
+static void restore_multicast_list(struct net_device *dev)
+{
+  mace_private *lp = (mace_private *)dev->priv;
+  int num_addrs = lp->multicast_num_addrs;
+  int *ladrf = lp->multicast_ladrf;
+  ioaddr_t ioaddr = dev->base_addr;
+  int i;
+
+  DEBUG(2, "%s: restoring Rx mode to %d addresses.\n",
+	dev->name, num_addrs);
+
+  if (num_addrs > 0) {
+
+    DEBUG(1, "Attempt to restore multicast list detected.\n");
+
+    mace_write(ioaddr, MACE_IAC, MACE_IAC_ADDRCHG | MACE_IAC_LOGADDR);
+    /* Poll ADDRCHG bit */
+    while (mace_read(ioaddr, MACE_IAC) & MACE_IAC_ADDRCHG)
+      ;
+    /* Set LADRF register */
+    for (i = 0; i < MACE_LADRF_LEN; i++)
+      mace_write(ioaddr, MACE_LADRF, ladrf[i]);
+
+    mace_write(ioaddr, MACE_UTR, MACE_UTR_RCVFCSE | MACE_UTR_LOOP_EXTERNAL);
+    mace_write(ioaddr, MACE_MACCC, MACE_MACCC_ENXMT | MACE_MACCC_ENRCV);
+
+  } else if (num_addrs < 0) {
+
+    /* Promiscuous mode: receive all packets */
+    mace_write(ioaddr, MACE_UTR, MACE_UTR_LOOP_EXTERNAL);
+    mace_write(ioaddr, MACE_MACCC,
+      MACE_MACCC_PROM | MACE_MACCC_ENXMT | MACE_MACCC_ENRCV
+    );
+
+  } else {
+
+    /* Normal mode */
+    mace_write(ioaddr, MACE_UTR, MACE_UTR_LOOP_EXTERNAL);
+    mace_write(ioaddr, MACE_MACCC, MACE_MACCC_ENXMT | MACE_MACCC_ENRCV);
+
+  }
+} /* restore_multicast_list */
+
+/* ----------------------------------------------------------------------------
+set_multicast_list
+	Set or clear the multicast filter for this adaptor.
+
+Input
+	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.
+Output
+	multicast_num_addrs
+	multicast_ladrf[]
+---------------------------------------------------------------------------- */
+
+static void set_multicast_list(struct net_device *dev)
+{
+  mace_private *lp = (mace_private *)dev->priv;
+  int adr[ETHER_ADDR_LEN] = {0}; /* Ethernet address */
+  int i;
+  struct dev_mc_list *dmi = dev->mc_list;
+
+#ifdef PCMCIA_DEBUG
+  if (pc_debug > 1) {
+    static int old = 0;
+    if (dev->mc_count != old) {
+      old = dev->mc_count;
+      DEBUG(0, "%s: setting Rx mode to %d addresses.\n",
+	    dev->name, old);
+    }
+  }
+#endif
+
+  /* Set multicast_num_addrs. */
+  lp->multicast_num_addrs = dev->mc_count;
+
+  /* Set multicast_ladrf. */
+  if (num_addrs > 0) {
+    /* Calculate multicast logical address filter */
+    memset(lp->multicast_ladrf, 0, MACE_LADRF_LEN);
+    for (i = 0; i < dev->mc_count; i++) {
+      memcpy(adr, dmi->dmi_addr, ETHER_ADDR_LEN);
+      dmi = dmi->next;
+      BuildLAF(lp->multicast_ladrf, adr);
+    }
+  }
+
+  restore_multicast_list(dev);
+
+} /* set_multicast_list */
+
+#endif /* BROKEN_MULTICAST */
+
+static void restore_multicast_list(struct net_device *dev)
+{
+  ioaddr_t ioaddr = dev->base_addr;
+
+  DEBUG(2, "%s: restoring Rx mode to %d addresses.\n", dev->name,
+	((mace_private *)(dev->priv))->multicast_num_addrs);
+
+  if (dev->flags & IFF_PROMISC) {
+    /* Promiscuous mode: receive all packets */
+    mace_write(ioaddr, MACE_UTR, MACE_UTR_LOOP_EXTERNAL);
+    mace_write(ioaddr, MACE_MACCC,
+      MACE_MACCC_PROM | MACE_MACCC_ENXMT | MACE_MACCC_ENRCV
+    );
+  } else {
+    /* Normal mode */
+    mace_write(ioaddr, MACE_UTR, MACE_UTR_LOOP_EXTERNAL);
+    mace_write(ioaddr, MACE_MACCC, MACE_MACCC_ENXMT | MACE_MACCC_ENRCV);
+  }
+} /* restore_multicast_list */
+
+static void set_multicast_list(struct net_device *dev)
+{
+  mace_private *lp = (mace_private *)dev->priv;
+
+#ifdef PCMCIA_DEBUG
+  if (pc_debug > 1) {
+    static int old = 0;
+    if (dev->mc_count != old) {
+      old = dev->mc_count;
+      DEBUG(0, "%s: setting Rx mode to %d addresses.\n",
+	    dev->name, old);
+    }
+  }
+#endif
+
+  lp->multicast_num_addrs = dev->mc_count;
+  restore_multicast_list(dev);
+
+} /* set_multicast_list */
+
+/* ----------------------------------------------------------------------------
+init_nmclan_cs
+---------------------------------------------------------------------------- */
+
+static int __init init_nmclan_cs(void)
+{
+  servinfo_t serv;
+  DEBUG(0, "%s\n", version);
+  CardServices(GetCardServicesInfo, &serv);
+  if (serv.Revision != CS_RELEASE_CODE) {
+    printk(KERN_NOTICE "nmclan_cs: Card Services release does not match!\n");
+    return -1;
+  }
+  register_pccard_driver(&dev_info, &nmclan_attach, &nmclan_detach);
+  return 0;
+}
+
+/* ----------------------------------------------------------------------------
+exit_nmclan_cs
+---------------------------------------------------------------------------- */
+
+static void __exit exit_nmclan_cs(void)
+{
+    DEBUG(0, "nmclan_cs: unloading\n");
+    unregister_pccard_driver(&dev_info);
+    while (dev_list != NULL)
+	nmclan_detach(dev_list);
+}
+
+module_init(init_nmclan_cs);
+module_exit(exit_nmclan_cs);
Index: oldkernel/linux/pcmcia-cs-3.1.15/clients/ositech.h
diff -u /dev/null linux/pcmcia-cs-3.1.15/clients/ositech.h:1.1
--- /dev/null	Mon Jul 31 21:15:10 2000
+++ linux/pcmcia-cs-3.1.15/clients/ositech.h	Fri Jul  7 16:34:58 2000
@@ -0,0 +1,358 @@
+/*
+    This file contains the firmware of Seven of Diamonds from OSITECH.
+    (Special thanks to Kevin MacPherson of OSITECH)
+
+    This software may be used and distributed according to the terms of
+    the GNU Public License, incorporated herein by reference.
+*/
+
+    static const u_char __Xilinx7OD[] = {
+    0xFF, 0x04, 0xA0, 0x36, 0xF3, 0xEC, 0xFF, 0xFF, 0xFF, 0xDF, 0xFB, 0xFF,
+    0xF3, 0xFF, 0xFF, 0xFF, 
+    0xEF, 0x3F, 0xFF, 0xF7, 0xFF, 0xFF, 0xFF, 0xFF, 0xEF, 0x7F, 0xFE, 0xFF,
+    0xCE, 0xFE, 0xFE, 0xFE, 
+    0xFE, 0xDE, 0xBD, 0xDD, 0xFD, 0xFF, 0xFD, 0xCF, 0xF7, 0xBF, 0x7F, 0xFF,
+    0x7F, 0x3F, 0xFE, 0xBF, 
+    0xFF, 0xFF, 0xFF, 0xBC, 0xFF, 0xFF, 0xBD, 0xB5, 0x7F, 0x7F, 0xBF, 0xBF,
+    0x7F, 0xFF, 0xEF, 0xFF, 
+    0xFF, 0xFF, 0xFB, 0xFF, 0xF7, 0xF7, 0xFF, 0xFF, 0xFF, 0xFF, 0xFE, 0xDE,
+    0xFE, 0xFE, 0xFA, 0xDE, 
+    0xBD, 0xFD, 0xED, 0xFD, 0xFD, 0xCF, 0xEF, 0xEF, 0xEF, 0xEF, 0xC7, 0xDF,
+    0xDF, 0xDF, 0xDF, 0xDF, 
+    0xFF, 0x7E, 0xFE, 0xFD, 0x7D, 0x6D, 0xEE, 0xFE, 0x7C, 0xFB, 0xF4, 0xFB,
+    0xCF, 0xDB, 0xDF, 0xFF, 
+    0xFF, 0xBB, 0x7F, 0xFF, 0x7F, 0xFF, 0xF7, 0xFF, 0x9E, 0xBF, 0x3B, 0xBF,
+    0xBF, 0x7F, 0x7F, 0x7F, 
+    0x7E, 0x6F, 0xDF, 0xEF, 0xF5, 0xF6, 0xFD, 0xF6, 0xF5, 0xED, 0xEB, 0xFF,
+    0xEF, 0xEF, 0xEF, 0x7E, 
+    0x7F, 0x7F, 0x6F, 0x7F, 0xFF, 0xFE, 0xFE, 0xFE, 0xFE, 0xFE, 0xEF, 0xBF,
+    0xFF, 0xFF, 0xFF, 0xFF, 
+    0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xBC, 0x1F, 0x1F, 0xEE, 0xFF, 0xBC,
+    0xB7, 0xFF, 0xDF, 0xFF, 
+    0xDF, 0xEF, 0x3B, 0xE3, 0xD3, 0xFF, 0xFB, 0xFF, 0xFF, 0xDF, 0xFF, 0xFF,
+    0xFF, 0xBA, 0xBF, 0x2D, 
+    0xDB, 0xBD, 0xFD, 0xDB, 0xDF, 0xFA, 0xFB, 0xFF, 0xEF, 0xFB, 0xDB, 0xF3,
+    0xFF, 0xDF, 0xFD, 0x7F, 
+    0xEF, 0xFB, 0xFF, 0xFF, 0xBE, 0xBF, 0x27, 0xBA, 0xFE, 0xFB, 0xDF, 0xFF,
+    0xF6, 0xFF, 0xFF, 0xEF, 
+    0xFB, 0xDB, 0xF3, 0xD9, 0x9A, 0x3F, 0xFF, 0xAF, 0xBF, 0xFF, 0xFF, 0xBE,
+    0x3F, 0x37, 0xBD, 0x96, 
+    0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xAE, 0xFB, 0xF3, 0xF3, 0xEB, 0xFF,
+    0xFF, 0xFF, 0xFF, 0xFF, 
+    0xFF, 0xF7, 0xFA, 0xBC, 0xAE, 0xFE, 0xBE, 0xFE, 0xBB, 0x7F, 0xFD, 0xFF,
+    0x7F, 0xEF, 0xF7, 0xFB, 
+    0xBB, 0xD7, 0xF7, 0x7F, 0xFF, 0xF7, 0xFF, 0xFF, 0xF7, 0xBC, 0xED, 0xFD,
+    0xBD, 0x9D, 0x7D, 0x7B, 
+    0xFB, 0x7B, 0x7B, 0xFB, 0xAF, 0xFF, 0xFE, 0xFD, 0xFD, 0xFE, 0xFE, 0xFF,
+    0xFF, 0xFF, 0xFF, 0xF7, 
+    0xAA, 0xB9, 0xBF, 0x8F, 0xBF, 0xDF, 0xFF, 0x7F, 0xFF, 0xFF, 0x7F, 0xCF,
+    0xFB, 0xEB, 0xCB, 0xEB, 
+    0xEE, 0xFF, 0xFF, 0xD7, 0xFF, 0xFF, 0xFF, 0x3E, 0x33, 0x3F, 0x1C, 0x7C,
+    0xFC, 0xFF, 0xFF, 0xFF, 
+    0xFF, 0xFF, 0xCF, 0xD3, 0xF3, 0xE3, 0xF3, 0xFB, 0xFF, 0xFF, 0xFF, 0xFF,
+    0xFF, 0xEB, 0xFE, 0x35, 
+    0x3F, 0x3D, 0xFD, 0xFD, 0xFF, 0xFF, 0xFF, 0xBF, 0xFF, 0xEF, 0x6F, 0xE3,
+    0xE3, 0xE3, 0xEF, 0xFF, 
+    0xFF, 0xDF, 0xFF, 0xFF, 0xF7, 0xFE, 0x3E, 0x5E, 0xFE, 0xFF, 0xFF, 0xFF,
+    0xFF, 0xFD, 0xFF, 0xFF, 
+    0xAF, 0xCF, 0xF2, 0xCB, 0xCF, 0x8E, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFD,
+    0xFC, 0x3E, 0x1F, 0x9E, 
+    0xAD, 0xFD, 0xFF, 0xFF, 0xBF, 0xFF, 0xFF, 0xEF, 0xFF, 0xB3, 0xF7, 0xE7,
+    0xF7, 0xFA, 0xFF, 0xFF, 
+    0xFF, 0xFF, 0xFF, 0xEE, 0xEB, 0xAB, 0xAF, 0x9F, 0xE3, 0x7F, 0xFF, 0xDE,
+    0xFF, 0x7F, 0xEE, 0xFF, 
+    0xFF, 0xFB, 0x3A, 0xFA, 0xFF, 0xF2, 0x77, 0xFF, 0xFF, 0xF7, 0xFE, 0xFF,
+    0xFE, 0xBD, 0xAE, 0xDE, 
+    0x7D, 0x7D, 0xFD, 0xFF, 0xBF, 0xEE, 0xFF, 0xFD, 0xFF, 0xDB, 0xFB, 0xFF,
+    0xF7, 0xEF, 0xFB, 0xFF, 
+    0xFF, 0xFE, 0xFF, 0x2D, 0xAF, 0xB9, 0xFD, 0x79, 0xFB, 0xFA, 0xFF, 0xBF,
+    0xEF, 0xFF, 0xFF, 0x91, 
+    0xFA, 0xFB, 0xDF, 0xF7, 0xF7, 0xFF, 0xFF, 0xFF, 0xFC, 0xCF, 0x37, 0xBF,
+    0xBF, 0xFF, 0x7F, 0x7F, 
+    0xFF, 0xFF, 0xFF, 0xAF, 0xFF, 0xFF, 0xF3, 0xFB, 0xFB, 0xFF, 0xF5, 0xEF,
+    0xFF, 0xFF, 0xF7, 0xFA, 
+    0xFF, 0xFF, 0xEE, 0xFA, 0xFE, 0xFB, 0x55, 0xDD, 0xFF, 0x7F, 0xAF, 0xFE,
+    0xFF, 0xFB, 0xFB, 0xF5, 
+    0xFF, 0xF7, 0xEF, 0xFF, 0xFF, 0xFF, 0xBE, 0xBD, 0xBD, 0xBD, 0xBD, 0x7D,
+    0x7B, 0x7B, 0x7B, 0x7B, 
+    0xFB, 0xAE, 0xFF, 0xFD, 0xFE, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+    0xF7, 0xDA, 0xB7, 0x61, 
+    0xFF, 0xB9, 0x59, 0xF3, 0x73, 0xF3, 0xDF, 0x7F, 0x6F, 0xDF, 0xEF, 0xF7,
+    0xEB, 0xEB, 0xD7, 0xFF, 
+    0xD7, 0xFF, 0xFF, 0xF7, 0xFE, 0x7F, 0xFB, 0x3E, 0x38, 0x73, 0xF6, 0x7F,
+    0xFC, 0xFF, 0xFF, 0xCF, 
+    0xFF, 0xB7, 0xFB, 0xB3, 0xB3, 0x67, 0xFF, 0xE7, 0xFD, 0xFF, 0xEF, 0xF6,
+    0x7F, 0xB7, 0xBC, 0xF5, 
+    0x7B, 0xF6, 0xF7, 0xF5, 0xFF, 0xFF, 0xEF, 0xFF, 0xF7, 0xFF, 0xF7, 0xCE,
+    0xE7, 0xFF, 0x9F, 0xFF, 
+    0xFF, 0xF5, 0xFE, 0x7D, 0xFF, 0x5F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+    0xFF, 0xEF, 0xFF, 0xF6, 
+    0xCB, 0xDB, 0xEE, 0xFE, 0xFF, 0xDF, 0xFF, 0xFF, 0xFF, 0xFE, 0x7F, 0xBE,
+    0x1E, 0x3E, 0xFE, 0xFF, 
+    0x7D, 0xFE, 0xFF, 0xFF, 0xEF, 0xBF, 0xE7, 0xFF, 0xE3, 0xE3, 0xFF, 0xDF,
+    0xE7, 0xFF, 0xFF, 0xFF, 
+    0xB8, 0xEF, 0xB7, 0x2F, 0xEE, 0xFF, 0xDF, 0xFF, 0xBF, 0xFF, 0x7F, 0xEF,
+    0xEB, 0xBF, 0xA3, 0xD3, 
+    0xFF, 0x7F, 0xFF, 0xFF, 0xFF, 0xFF, 0xF7, 0xBE, 0xFD, 0x3F, 0xCF, 0xFD,
+    0xFB, 0xFF, 0xFF, 0xFF, 
+    0xFF, 0xFF, 0xAF, 0xFB, 0xBF, 0xBB, 0xBF, 0xDB, 0xFD, 0xFB, 0xFF, 0xFF,
+    0xFF, 0xFF, 0x3E, 0xFE, 
+    0x3F, 0xBA, 0xBA, 0xFE, 0xFF, 0xFF, 0xFF, 0xEF, 0xFF, 0xEF, 0xC3, 0x7F,
+    0xB2, 0x9B, 0xFF, 0xFF, 
+    0xFF, 0xFF, 0xFE, 0xFF, 0xFF, 0x3C, 0xFF, 0x3F, 0x3C, 0xFF, 0xFE, 0xFF,
+    0xFF, 0xFF, 0xFF, 0xFF, 
+    0xAF, 0xF3, 0xFE, 0xF3, 0xE3, 0xEB, 0xFF, 0xFF, 0xFF, 0xFB, 0xFF, 0xF7,
+    0x9A, 0xFE, 0xAF, 0x9E, 
+    0xBE, 0xFE, 0xFF, 0xDF, 0xFF, 0xFF, 0x7B, 0xEF, 0xF7, 0xBF, 0xFB, 0xFB,
+    0xFB, 0xFF, 0xFF, 0x7F, 
+    0xFF, 0xFF, 0xFF, 0xBC, 0xBD, 0xFD, 0xBD, 0xDD, 0x7D, 0x7B, 0x7B, 0x7B,
+    0x7B, 0xFB, 0xAE, 0xFF, 
+    0xFF, 0xFF, 0xFE, 0xFE, 0xFF, 0xFD, 0xFF, 0xFF, 0xFF, 0xF7, 0x9A, 0xFF,
+    0x9F, 0xFF, 0xAF, 0xEF, 
+    0xFF, 0xFF, 0xFF, 0xFF, 0x7F, 0xCF, 0xF3, 0xFF, 0xEB, 0xFF, 0xEB, 0xFF,
+    0xFF, 0xBF, 0xFF, 0xFF, 
+    0xEF, 0xFE, 0xFF, 0x37, 0xFC, 0xBF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+    0xCF, 0xEF, 0xFD, 0xF3, 
+    0xFF, 0xEE, 0xFE, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x6E, 0xFD, 0x2F, 0xFD,
+    0xFF, 0xFD, 0xFF, 0xFF, 
+    0xFF, 0xFF, 0xFF, 0xEF, 0xCF, 0xFF, 0xF3, 0xBF, 0x69, 0xFF, 0xFF, 0xFF,
+    0xFF, 0xFF, 0xFF, 0xFE, 
+    0xFB, 0x9F, 0xFF, 0xBF, 0xFD, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xEF, 0x87,
+    0xFE, 0xDA, 0xEF, 0xCF, 
+    0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFE, 0xEF, 0xBF, 0xEF, 0xEF, 0xFD,
+    0xFF, 0xFF, 0xFF, 0xFF, 
+    0xFF, 0xEF, 0xFD, 0xFF, 0x7B, 0xFF, 0xEB, 0xFE, 0xFF, 0xFF, 0xFF, 0xFF,
+    0xEB, 0xF8, 0xFF, 0xEF, 
+    0xAF, 0xFF, 0xFF, 0xBD, 0xFF, 0xFF, 0xFF, 0x7F, 0xEE, 0x7F, 0xEF, 0xFF,
+    0xBB, 0xFF, 0xBF, 0xFB, 
+    0xFF, 0xFF, 0xFF, 0xF7, 0xF6, 0xFB, 0xBD, 0xFD, 0xDD, 0xF5, 0xFF, 0xFF,
+    0xFF, 0xFF, 0xFF, 0xAF, 
+    0xFF, 0x5F, 0xF5, 0xDF, 0xFF, 0x7F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xF6,
+    0xF3, 0xFF, 0xDE, 0xFE, 
+    0xEF, 0xFD, 0xFF, 0xFF, 0xFF, 0xFF, 0xEF, 0xFF, 0xDE, 0xDF, 0x5F, 0xDF,
+    0xFD, 0xFF, 0xFF, 0xFF, 
+    0xFF, 0xFF, 0xFE, 0xFF, 0xFF, 0xFE, 0xFE, 0xFF, 0xFD, 0xFF, 0xFF, 0xFF,
+    0xFF, 0xAF, 0xFF, 0xFF, 
+    0xEF, 0xED, 0xFF, 0xDF, 0xFF, 0xFF, 0xFB, 0xFF, 0xFF, 0xDA, 0xBD, 0xBE,
+    0xAE, 0xFE, 0x7F, 0xFD, 
+    0xDF, 0xFF, 0xFF, 0x7F, 0xEF, 0xFF, 0xFB, 0xFB, 0xFB, 0x7F, 0xF7, 0xFF,
+    0xFF, 0xFF, 0xFF, 0xF7, 
+    0xBC, 0xFD, 0xBD, 0xBD, 0xBD, 0xFD, 0x7B, 0x7B, 0x7B, 0x7B, 0xFB, 0xAE,
+    0xFF, 0xFF, 0xFD, 0xFF, 
+    0xFF, 0xFF, 0xFD, 0xFF, 0xFF, 0xFF, 0xFF, 0xFA, 0x9F, 0xBF, 0xBF, 0xCF,
+    0x7F, 0xFF, 0xFF, 0xFF, 
+    0xFF, 0xFF, 0xAF, 0xFF, 0xEB, 0xEB, 0xEB, 0xFF, 0xD7, 0xFE, 0xFF, 0xFF,
+    0xBF, 0xE7, 0xFE, 0xBF, 
+    0x7F, 0xFC, 0xFF, 0xFF, 0xED, 0xFF, 0xFF, 0xFF, 0xFF, 0x4F, 0xFF, 0xFB,
+    0xFB, 0xFF, 0xFF, 0xDD, 
+    0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFE, 0xBD, 0xDF, 0x9D, 0xFD, 0xDF, 0xB9,
+    0xFF, 0xFF, 0xFF, 0xFF, 
+    0xEF, 0xFF, 0xFB, 0xEF, 0xEB, 0xFF, 0xDE, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+    0xF6, 0x9F, 0xFF, 0xFC, 
+    0xFE, 0xFB, 0xFD, 0xFF, 0xFF, 0xFF, 0xFF, 0xEF, 0xDF, 0xFA, 0xCD, 0xCF,
+    0xBF, 0x9F, 0xFF, 0xFF, 
+    0xFF, 0xFF, 0xF7, 0xFE, 0xBF, 0xFF, 0xDF, 0xEF, 0x5F, 0xFF, 0xFF, 0xFF,
+    0xFF, 0x7F, 0x6F, 0xFF, 
+    0xBB, 0xFD, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x7E, 0xFF,
+    0x5F, 0xFF, 0xBF, 0xBF, 
+    0xF9, 0xFF, 0xFF, 0xFF, 0x7F, 0x6E, 0x7B, 0xFF, 0xEF, 0xFD, 0xEB, 0xDF,
+    0xFF, 0xFF, 0xFF, 0xFF, 
+    0xF7, 0xB6, 0x3E, 0xFC, 0xFD, 0xBF, 0x7E, 0xFB, 0xFF, 0xFF, 0xFF, 0xF7,
+    0xEF, 0xF7, 0xF3, 0xF7, 
+    0xFF, 0xFB, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x6E, 0x35, 0x79, 0xFF,
+    0xBF, 0xFC, 0xFF, 0xFF, 
+    0xFF, 0xFF, 0xFF, 0xEF, 0xFB, 0x53, 0xDF, 0xFF, 0xEB, 0xBF, 0xFF, 0xFF,
+    0xFF, 0xFF, 0xFF, 0xBC, 
+    0xFF, 0xFF, 0xFF, 0xBF, 0xFF, 0xFD, 0xFF, 0xFF, 0xFF, 0xFF, 0xAF, 0xF5,
+    0xFF, 0xF7, 0xFF, 0xFB, 
+    0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xBA, 0xAA, 0xEE, 0xFE, 0x3F, 0x7D,
+    0xFD, 0xFF, 0xFF, 0xFF, 
+    0x7F, 0xAF, 0x77, 0xFB, 0xFB, 0xFF, 0xFB, 0xF7, 0xFF, 0xFF, 0xFF, 0xFF,
+    0xF7, 0xBE, 0xBD, 0xBD, 
+    0xBD, 0xBD, 0xFD, 0x7B, 0x7B, 0x7B, 0x7B, 0xFB, 0xAE, 0xFF, 0xEF, 0xFF,
+    0xFF, 0xFF, 0xFF, 0xFC, 
+    0xFF, 0xFF, 0xFF, 0xFF, 0x9A, 0xD9, 0xB8, 0xFF, 0xFF, 0x79, 0xFF, 0xFF,
+    0xFF, 0xFF, 0xFF, 0xCF, 
+    0xFB, 0xFF, 0xEB, 0xFF, 0xEB, 0xD7, 0xFF, 0xFF, 0xFF, 0xFF, 0xE7, 0xDE,
+    0xF8, 0xFB, 0xFE, 0x3F, 
+    0xFB, 0xFD, 0xFF, 0xFF, 0xFF, 0xFF, 0xCF, 0xAD, 0xBF, 0xFA, 0xFF, 0x73,
+    0xDF, 0xFF, 0xFF, 0xFF, 
+    0xFF, 0xFF, 0x3A, 0xF5, 0xB7, 0xFC, 0x3F, 0xF9, 0xFD, 0xFF, 0xFF, 0xFF,
+    0x7F, 0xEF, 0xF3, 0xFF, 
+    0xBF, 0xFE, 0xF3, 0x9F, 0xFE, 0xFF, 0xFF, 0xFF, 0xF7, 0x3E, 0xFF, 0xFF,
+    0xFF, 0xBF, 0xFF, 0xFF, 
+    0xFF, 0xFF, 0xFF, 0xFF, 0xAF, 0xD3, 0xFE, 0xDB, 0xFF, 0xDB, 0xDF, 0xFF,
+    0xFF, 0xFF, 0xFF, 0xFF, 
+    0x3E, 0xFF, 0xBF, 0xFF, 0x7F, 0xFF, 0xFD, 0xFF, 0xFF, 0xFF, 0xFF, 0x8F,
+    0xF3, 0xFF, 0xED, 0xFF, 
+    0xF7, 0xFB, 0xFF, 0xFF, 0xFF, 0xFF, 0xEF, 0xF6, 0x3C, 0xFE, 0xFF, 0xFF,
+    0xFF, 0xFF, 0xFF, 0xFF, 
+    0xFF, 0x9F, 0xEF, 0xEF, 0xD1, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+    0xFF, 0xFF, 0x7E, 0xBF, 
+    0xFD, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xBB, 0xEF, 0xDF, 0xF1,
+    0xFF, 0xFF, 0xFF, 0xFF, 
+    0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xEE, 0x3E, 0xFE, 0xFF, 0xFF, 0xFF, 0xFF,
+    0xFF, 0xFF, 0xFF, 0xBF, 
+    0xEF, 0xFD, 0xC3, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xBF, 0xFF,
+    0xFC, 0x3E, 0xFE, 0xFF, 
+    0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x2E, 0xEF, 0xF3, 0xFF, 0xFF,
+    0xFF, 0xFF, 0xFF, 0xFF, 
+    0xFF, 0xFF, 0xF7, 0xBA, 0xBE, 0xFE, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+    0xFF, 0x7F, 0xAF, 0xFB, 
+    0xFB, 0xFD, 0xFF, 0xFF, 0xFF, 0xFE, 0xFF, 0xFF, 0xFF, 0xF2, 0xD6, 0xED,
+    0xBD, 0xBD, 0xBD, 0x7D, 
+    0x7B, 0x7B, 0x7B, 0x7B, 0xFB, 0xAF, 0xDF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+    0xFF, 0xFF, 0xFF, 0xFF, 
+    0xFF, 0x92, 0xBF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x7F,
+    0xAF, 0xEB, 0xEB, 0xFF, 
+    0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xE7, 0xFE, 0x2E, 0xFE, 0xFF,
+    0xFF, 0xFF, 0xFF, 0xFF, 
+    0xFF, 0xFF, 0xFF, 0x4F, 0xEF, 0xF3, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+    0xFF, 0xFF, 0xFF, 0xFE, 
+    0x3C, 0xFE, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xEF, 0xCE,
+    0xC3, 0xFD, 0xFF, 0xFF, 
+    0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFE, 0x5D, 0xFF, 0xFF, 0xFF, 0xFF,
+    0xFF, 0xFF, 0xFF, 0xFF, 
+    0xFF, 0xEF, 0xCF, 0xEB, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+    0xF7, 0xEE, 0x3E, 0xFF, 
+    0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x7F, 0xEF, 0xDF, 0xE2, 0xFF,
+    0xFF, 0xFF, 0xFB, 0xFF, 
+    0xFF, 0xFF, 0xFF, 0xFF, 0xF6, 0xBE, 0xFC, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+    0xFF, 0xFF, 0x7F, 0xEE, 
+    0x5F, 0xE6, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x3E,
+    0x7D, 0xFF, 0xFF, 0xFF, 
+    0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xEF, 0xF3, 0xFB, 0xFF, 0xFF, 0xFF,
+    0xFF, 0xFF, 0xFF, 0xFF, 
+    0xBF, 0xF7, 0x36, 0xBE, 0xFE, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+    0xFF, 0xEF, 0xD3, 0xF6, 
+    0xFE, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFC, 0x7F, 0xEE,
+    0xFF, 0xFF, 0xFF, 0xFF, 
+    0xFF, 0xFF, 0xFF, 0xFF, 0xAF, 0xEF, 0xEB, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+    0xFF, 0xFF, 0xFF, 0xFF, 
+    0xBA, 0xBE, 0xFE, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xEE,
+    0xFB, 0xFA, 0xFF, 0xFF, 
+    0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xF7, 0xD6, 0xFD, 0xBD, 0xBD, 0xBD,
+    0x7D, 0x7B, 0x7B, 0x7B, 
+    0x7B, 0xFB, 0xAE, 0xFF, 0x7E, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+    0xFF, 0xF7, 0xBA, 0xBF, 
+    0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x7F, 0xEF, 0xEB, 0x6B,
+    0xFF, 0xFF, 0xFF, 0xFF, 
+    0xFF, 0xFF, 0xFF, 0xFF, 0xF7, 0xFE, 0xBE, 0xFE, 0xFF, 0xFF, 0xFF, 0xFF,
+    0xFF, 0xFF, 0xFF, 0xFF, 
+    0x4F, 0xEF, 0xF7, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xEF,
+    0x3E, 0x6E, 0xFC, 0xFF, 
+    0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xEF, 0xC3, 0xC9, 0xFF, 0xFF,
+    0xFF, 0xFF, 0xFF, 0xFF, 
+    0xFF, 0xFF, 0xFF, 0x3E, 0xBF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+    0xFF, 0xFF, 0xEF, 0xFB, 
+    0xD5, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFE, 0xFE,
+    0xFE, 0xFF, 0xFF, 0xFF, 
+    0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x6F, 0xEF, 0xFB, 0xFF, 0xFF, 0xFF, 0xFB,
+    0xFF, 0xFF, 0xFF, 0xFF, 
+    0xFF, 0xF6, 0xDF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x7F, 0xFE,
+    0xEF, 0xFF, 0xFF, 0xFF, 
+    0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xE7, 0xFF, 0xFE, 0xFF, 0xF7, 0xFF,
+    0xFF, 0xFF, 0xFF, 0xFF, 
+    0xFF, 0x7F, 0xFA, 0xEF, 0xBF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+    0xFF, 0xE7, 0xFF, 0xFE, 
+    0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x7F, 0xFE, 0xEF, 0xBF,
+    0xFF, 0xFF, 0xFF, 0xFF, 
+    0xFF, 0xFF, 0xFF, 0xFF, 0xA7, 0xFF, 0xFC, 0xF7, 0xFF, 0xFF, 0xFF, 0xFF,
+    0xFF, 0xFF, 0xFF, 0x7F, 
+    0xFE, 0xAE, 0xFF, 0xFF, 0xFD, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xE7,
+    0xF7, 0xFA, 0xFF, 0xFD, 
+    0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x7F, 0xAF, 0xFF, 0xFF, 0xFF,
+    0xFF, 0xFF, 0xFF, 0xFF, 
+    0xFF, 0xFF, 0xFF, 0xF7, 0xBE, 0xBD, 0xBD, 0xBD, 0xBD, 0x7D, 0x7B, 0x7B,
+    0x7B, 0x7B, 0xFB, 0xAF, 
+    0x7F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xCA,
+    0xFF, 0xFF, 0xFF, 0xFF, 
+    0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x7F, 0x6F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+    0xFF, 0xFF, 0xFF, 0xFF, 
+    0xFF, 0xE7, 0xFE, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+    0xFF, 0xCF, 0xFE, 0xFF, 
+    0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFE, 0xDF, 0xFF,
+    0xFF, 0xFF, 0xFF, 0xFF, 
+    0xFF, 0xFF, 0xFF, 0xFF, 0xEF, 0xFF, 0xFE, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+    0xFF, 0xFF, 0xFF, 0xFF, 
+    0xFE, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xEF,
+    0xFF, 0xFF, 0xFF, 0xFF, 
+    0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xF7, 0xFE, 0xFF, 0xFF, 0xFF, 0xFF,
+    0xFF, 0xFF, 0xFF, 0xFF, 
+    0xFF, 0xFF, 0xEF, 0xFF, 0xFE, 0xFF, 0xFF, 0xFF, 0xFB, 0xFF, 0xFF, 0xFF,
+    0xFF, 0xE7, 0xF2, 0xFC, 
+    0xEF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x7F, 0xAE, 0xEF, 0xFF,
+    0xFF, 0xFF, 0xFF, 0xFF, 
+    0xFF, 0xFF, 0xFF, 0xFF, 0xF7, 0x7E, 0xFD, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+    0xFF, 0xFF, 0xFF, 0xFF, 
+    0xEF, 0xFF, 0xFE, 0xFF, 0xFF, 0xFF, 0xBF, 0xFF, 0xFF, 0xFF, 0xBF, 0xFF,
+    0xFE, 0xFE, 0xFF, 0xFF, 
+    0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xDF, 0xEF, 0xDD, 0xFE, 0xFF, 0xFF,
+    0xFF, 0xFF, 0xFF, 0xFF, 
+    0xFF, 0xFF, 0xFF, 0xFE, 0xFE, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+    0xFF, 0xFF, 0xAF, 0xEF, 
+    0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xBA, 0xFE,
+    0xFF, 0xFF, 0xFF, 0xFF, 
+    0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xEF, 0xFA, 0xFE, 0xFF, 0xFF, 0xFF, 0xFF,
+    0xFF, 0xFF, 0xFF, 0xFF, 
+    0xF6, 0x9C, 0xBD, 0xBD, 0xBD, 0xBD, 0x7D, 0x7B, 0x7B, 0x7B, 0x7B, 0xFB,
+    0xAE, 0xFF, 0xFF, 0xFF, 
+    0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xF7, 0x7A, 0xFF, 0xFF, 0xFF,
+    0xFF, 0xDF, 0xFF, 0xFF, 
+    0xFF, 0xFF, 0x6F, 0xEF, 0xF7, 0xFF, 0xFF, 0xFF, 0xDF, 0xFF, 0xFF, 0xFF,
+    0xFF, 0xFF, 0xF7, 0xFE, 
+    0xFE, 0xFF, 0xFF, 0xFF, 0xDF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xCF, 0xEB,
+    0xFF, 0xFF, 0xFF, 0xFF, 
+    0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xEF, 0x9E, 0xFC, 0xFF, 0xFF, 0xFF, 0xFF,
+    0xFF, 0xFF, 0xFF, 0xFF, 
+    0xFF, 0xEF, 0xEF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+    0xFF, 0xFE, 0xFF, 0xFF, 
+    0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x7F, 0xEF, 0xCB, 0xFF, 0xFF,
+    0xFF, 0xFF, 0xFF, 0xFD, 
+    0xFF, 0xFF, 0xFF, 0xFF, 0xBE, 0xFD, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+    0xFF, 0xFF, 0xFF, 0xEF, 
+    0xEF, 0xFF, 0xFF, 0xFF, 0xDF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xF8,
+    0xFF, 0xFF, 0xFF, 0xFF, 
+    0xBF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xEF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+    0xFF, 0xFF, 0xFF, 0xFF, 
+    0xFF, 0xFF, 0xFE, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+    0xFB, 0xAF, 0x7F, 0xFF, 
+    0xFF, 0xFF, 0xDF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFE, 0xEF, 0xFF,
+    0xFF, 0xFF, 0xFF, 0xFF, 
+    0xFF, 0xFF, 0xFF, 0xFF, 0xEF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+    0xFF, 0xFF, 0xBF, 0xFF, 
+    0xFE, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xAE,
+    0xFF, 0xFF, 0xFF, 0xFF, 
+    0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xF7, 0xFA, 0xFF, 0xFF, 0xFF, 0xFF,
+    0xFF, 0xFF, 0xFF, 0xFF, 
+    0xFF, 0x7F, 0xEF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+    0xFF, 0xF7, 0xBC, 0xBD, 
+    0xBD, 0xBD, 0xBD, 0x7D, 0x7B, 0x7B, 0x7B, 0x7B, 0xFB, 0xAF, 0xFF, 0xFF,
+    0xFF, 0xFF, 0xFF, 0xFF, 
+    0xFF, 0xFF, 0xFF, 0xFF, 0xF7, 0xFA, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+    0xFF, 0xFF, 0xFF, 0x7F, 
+    0xAF, 0x7F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xEF,
+    0xFE, 0xFF, 0xFF, 0xFF, 
+    0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xCF, 0xFF, 0xFF, 0xFF, 0xFF,
+    0xFF, 0xFF, 0xFF, 0xFF, 
+    0xFF, 0xFF, 0xFF, 0xFE, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFB, 0xFF,
+    0xFF, 0xFF, 0xEF, 0xFF, 
+    0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFE, 0xFF,
+    0xFF, 0xFF, 0xFF, 0xFF, 
+    0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xEF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+    0xBF, 0xFF, 0xFF, 0xFF, 
+    0xFF, 0xFC, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+    0xEF, 0xFF, 0xFF, 0xFF, 
+    0xFF, 0xFF, 0xFB, 0xFF, 0xFF, 0xFF, 0xFF, 0xEF, 0xFE, 0xFF, 0x9F, 0x9F,
+    0x9F, 0x3F, 0x3F, 0x3F, 
+    0x3F, 0x3F, 0xFF, 0xEF, 0xDF, 0xDF, 0xDF, 0xDF, 0xCF, 0xB7, 0xBF, 0xBF,
+    0xBF, 0xBF, 0xFF, 0xBC, 
+    0xB9, 0x9D, 0xBD, 0xBD, 0x7D, 0x7B, 0x7B, 0x7B, 0x7B, 0xFB, 0xEF, 0xD7,
+    0xF5, 0xF3, 0xF1, 0xD1, 
+    0x65, 0xE3, 0xE3, 0xE3, 0xA3, 0xFF, 0xFE, 0x7F, 0xFE, 0xDE, 0xDE, 0xFF,
+    0xBD, 0xBD, 0xBD, 0xBD, 
+    0xDF, 0xEF, 0xFB, 0xF7, 0xF3, 0xF3, 0xF3, 0xE7, 0xE7, 0xE7, 0xE7, 0xE7,
+    0xFB, 0xFE, 0xFF, 0xFF, 
+    0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF
+    
+    };
Index: oldkernel/linux/pcmcia-cs-3.1.15/clients/parport_cs.c
diff -u /dev/null linux/pcmcia-cs-3.1.15/clients/parport_cs.c:1.1
--- /dev/null	Mon Jul 31 21:15:10 2000
+++ linux/pcmcia-cs-3.1.15/clients/parport_cs.c	Fri Jul  7 16:34:58 2000
@@ -0,0 +1,473 @@
+/*======================================================================
+
+    A driver for PCMCIA parallel port adapters
+
+    (specifically, for the Quatech SPP-100 EPP card: other cards will
+    probably require driver tweaks)
+    
+    parport_cs.c 1.17 2000/05/16 21:31:36
+
+    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@pcmcia.sourceforge.org>.  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 <pcmcia/config.h>
+#include <pcmcia/k_compat.h>
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/sched.h>
+#include <linux/ptrace.h>
+#include <linux/malloc.h>
+#include <linux/string.h>
+#include <linux/timer.h>
+#include <linux/ioport.h>
+
+#include <linux/parport.h>
+#include <linux/parport_pc.h>
+
+#include <pcmcia/version.h>
+#include <pcmcia/cs_types.h>
+#include <pcmcia/cs.h>
+#include <pcmcia/cistpl.h>
+#include <pcmcia/ds.h>
+#include <pcmcia/cisreg.h>
+#include <pcmcia/ciscode.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 =
+"parport_cs.c 1.17 2000/05/16 21:31:36 (David Hinds)";
+#else
+#define DEBUG(n, args...)
+#endif
+
+/*====================================================================*/
+
+/* Parameters that can be set with 'insmod' */
+
+/* Bit map of interrupts to choose from */
+static u_int irq_mask = 0xdeb8;
+static int irq_list[4] = { -1 };
+static int epp_mode = 1;
+
+MODULE_PARM(irq_mask, "i");
+MODULE_PARM(irq_list, "1-4i");
+MODULE_PARM(epp_mode, "i");
+
+/*====================================================================*/
+
+#define FORCE_EPP_MODE	0x08
+
+typedef struct parport_info_t {
+    dev_link_t		link;
+    int			ndev;
+    dev_node_t		node;
+    struct parport	*port;
+} parport_info_t;
+
+static dev_link_t *parport_attach(void);
+static void parport_detach(dev_link_t *);
+static void parport_config(dev_link_t *link);
+static void parport_cs_release(u_long arg);
+static int parport_event(event_t event, int priority,
+			 event_callback_args_t *args);
+
+static dev_info_t dev_info = "parport_cs";
+static dev_link_t *dev_list = NULL;
+
+extern struct parport_operations parport_pc_ops;
+static struct parport_operations parport_cs_ops;
+
+/*====================================================================*/
+
+static void cs_error(client_handle_t handle, int func, int ret)
+{
+    error_info_t err = { func, ret };
+    CardServices(ReportError, handle, &err);
+}
+
+/*======================================================================
+
+    parport_attach() creates an "instance" of the driver, allocating
+    local data structures for one device.  The device is registered
+    with Card Services.
+
+======================================================================*/
+
+static dev_link_t *parport_attach(void)
+{
+    parport_info_t *info;
+    dev_link_t *link;
+    client_reg_t client_reg;
+    int i, ret;
+    
+    DEBUG(0, "parport_attach()\n");
+
+    /* Create new parport device */
+    info = kmalloc(sizeof(*info), GFP_KERNEL);
+    if (!info) return NULL;
+    memset(info, 0, sizeof(*info));
+    link = &info->link; link->priv = info;
+
+    link->release.function = &parport_cs_release;
+    link->release.data = (u_long)link;
+    link->io.Attributes1 = IO_DATA_PATH_WIDTH_8;
+    link->io.Attributes2 = IO_DATA_PATH_WIDTH_8;
+    link->irq.Attributes = IRQ_TYPE_EXCLUSIVE;
+    link->irq.IRQInfo1 = IRQ_INFO2_VALID|IRQ_LEVEL_ID;
+    if (irq_list[0] == -1)
+	link->irq.IRQInfo2 = irq_mask;
+    else
+	for (i = 0; i < 4; i++)
+	    link->irq.IRQInfo2 |= 1 << irq_list[i];
+    link->conf.Attributes = CONF_ENABLE_IRQ;
+    link->conf.Vcc = 50;
+    link->conf.IntType = INT_MEMORY_AND_IO;
+    
+    /* Register with Card Services */
+    link->next = dev_list;
+    dev_list = link;
+    client_reg.dev_info = &dev_info;
+    client_reg.Attributes = INFO_IO_CLIENT | INFO_CARD_SHARE;
+    client_reg.EventMask =
+	CS_EVENT_CARD_INSERTION | CS_EVENT_CARD_REMOVAL |
+	CS_EVENT_RESET_PHYSICAL | CS_EVENT_CARD_RESET |
+	CS_EVENT_PM_SUSPEND | CS_EVENT_PM_RESUME;
+    client_reg.event_handler = &parport_event;
+    client_reg.Version = 0x0210;
+    client_reg.event_callback_args.client_data = link;
+    ret = CardServices(RegisterClient, &link->handle, &client_reg);
+    if (ret != CS_SUCCESS) {
+	cs_error(link->handle, RegisterClient, ret);
+	parport_detach(link);
+	return NULL;
+    }
+    
+    return link;
+} /* parport_attach */
+
+/*======================================================================
+
+    This deletes a driver "instance".  The device is de-registered
+    with Card Services.  If it has been released, all local data
+    structures are freed.  Otherwise, the structures will be freed
+    when the device is released.
+
+======================================================================*/
+
+static void parport_detach(dev_link_t *link)
+{
+    dev_link_t **linkp;
+    int ret;
+
+    DEBUG(0, "parport_detach(0x%p)\n", link);
+    
+    /* Locate device structure */
+    for (linkp = &dev_list; *linkp; linkp = &(*linkp)->next)
+	if (*linkp == link) break;
+    if (*linkp == NULL)
+	return;
+
+    del_timer(&link->release);
+    if (link->state & DEV_CONFIG)
+	parport_cs_release((u_long)link);
+    
+    if (link->handle) {
+	ret = CardServices(DeregisterClient, link->handle);
+	if (ret != CS_SUCCESS)
+	    cs_error(link->handle, DeregisterClient, ret);
+    }
+    
+    /* Unlink, free device structure */
+    *linkp = link->next;
+    kfree(link->priv);
+    
+} /* parport_detach */
+
+/*======================================================================
+
+    parport_config() is scheduled to run after a CARD_INSERTION event
+    is received, to configure the PCMCIA socket, and to make the
+    parport device available to the system.
+
+======================================================================*/
+
+#define CS_CHECK(fn, args...) \
+while ((last_ret=CardServices(last_fn=(fn), args))!=0) goto cs_failed
+
+#define CFG_CHECK(fn, args...) \
+if (CardServices(fn, args) != 0) goto next_entry
+
+static struct { u_int flag; char *name; } mode[] = {
+    { PARPORT_MODE_PCPS2, "PS2" },
+    { PARPORT_MODE_PCEPP, "EPP" },
+    { PARPORT_MODE_PCECP, "ECP" },
+    { PARPORT_MODE_PCECPEPP, "ECPEPP" },
+    { PARPORT_MODE_PCECPPS2, "ECPPS2" }
+};
+
+void parport_config(dev_link_t *link)
+{
+    client_handle_t handle = link->handle;
+    parport_info_t *info = link->priv;
+    tuple_t tuple;
+    u_short buf[128];
+    cisparse_t parse;
+    config_info_t conf;
+    cistpl_cftable_entry_t *cfg = &parse.cftable_entry;
+    cistpl_cftable_entry_t dflt = { 0 };
+    struct parport *p;
+    int i, last_ret, last_fn;
+    
+    DEBUG(0, "parport_config(0x%p)\n", link);
+    
+    tuple.TupleData = (cisdata_t *)buf;
+    tuple.TupleOffset = 0; tuple.TupleDataMax = 255;
+    tuple.Attributes = 0;
+    tuple.DesiredTuple = CISTPL_CONFIG;
+    CS_CHECK(GetFirstTuple, handle, &tuple);
+    CS_CHECK(GetTupleData, handle, &tuple);
+    CS_CHECK(ParseTuple, handle, &tuple, &parse);
+    link->conf.ConfigBase = parse.config.base;
+    link->conf.Present = parse.config.rmask[0];
+    
+    /* Configure card */
+    link->state |= DEV_CONFIG;
+
+    /* Not sure if this is right... look up the current Vcc */
+    CS_CHECK(GetConfigurationInfo, handle, &conf);
+    
+    tuple.DesiredTuple = CISTPL_CFTABLE_ENTRY;
+    tuple.Attributes = 0;
+    CS_CHECK(GetFirstTuple, handle, &tuple);
+    while (1) {
+	CFG_CHECK(GetTupleData, handle, &tuple);
+	CFG_CHECK(ParseTuple, handle, &tuple, &parse);
+
+	if ((cfg->io.nwin > 0) || (dflt.io.nwin > 0)) {
+	    cistpl_io_t *io = (cfg->io.nwin) ? &cfg->io : &dflt.io;
+	    link->conf.ConfigIndex = cfg->index;
+	    if (epp_mode)
+		link->conf.ConfigIndex |= FORCE_EPP_MODE;
+	    link->io.BasePort1 = io->win[0].base;
+	    link->io.NumPorts1 = io->win[0].len;
+	    link->io.IOAddrLines = io->flags & CISTPL_IO_LINES_MASK;
+	    if (io->nwin == 2) {
+		link->io.BasePort2 = io->win[1].base;
+		link->io.NumPorts2 = io->win[1].len;
+	    }
+	    CFG_CHECK(RequestIO, link->handle, &link->io);
+	    /* If we've got this far, we're done */
+	    break;
+	}
+	
+    next_entry:
+	if (cfg->flags & CISTPL_CFTABLE_DEFAULT) dflt = *cfg;
+	CS_CHECK(GetNextTuple, handle, &tuple);
+    }
+    
+    CS_CHECK(RequestIRQ, handle, &link->irq);
+    CS_CHECK(RequestConfiguration, handle, &link->conf);
+
+    p = parport_register_port(link->io.BasePort1,
+			      link->irq.AssignedIRQ, PARPORT_DMA_NONE,
+			      &parport_cs_ops);
+    if (p == NULL) {
+	printk(KERN_NOTICE "parport_cs: parport_register_port() at "
+	       "0x%3x, irq %u failed\n", link->io.BasePort1,
+	       link->irq.AssignedIRQ);
+	goto failed;
+    }
+
+#if (LINUX_VERSION_CODE >= VERSION(2,2,8))
+    p->private_data = kmalloc(sizeof(struct parport_pc_private),
+			      GFP_KERNEL);
+    ((struct parport_pc_private *)(p->private_data))->ctr = 0x0c;
+#endif
+    parport_proc_register(p);
+    p->flags |= PARPORT_FLAG_COMA;
+    parport_pc_write_econtrol(p, 0x00);
+    parport_pc_write_control(p, 0x0c);
+    parport_pc_write_data(p, 0x00);
+    
+    p->modes |= PARPORT_MODE_PCSPP;
+    if (epp_mode)
+	p->modes |= PARPORT_MODE_PCPS2 | PARPORT_MODE_PCEPP;
+    if (link->io.NumPorts2)
+	p->modes |= PARPORT_MODE_PCECR;
+    info->ndev = 1;
+    info->node.major = LP_MAJOR;
+    info->node.minor = p->number;
+    info->port = p;
+    strcpy(info->node.dev_name, p->name);
+    link->dev = &info->node;
+    printk(KERN_INFO "%s: PC-style PCMCIA at %#x", p->name,
+	   link->io.BasePort1);
+    if (link->io.NumPorts2)
+	printk(" & %#x", link->io.BasePort2);
+    printk(", irq %u [SPP", link->irq.AssignedIRQ);
+    for (i = 0; i < 5; i++)
+	if (p->modes & mode[i].flag) printk(",%s", mode[i].name);
+    printk("]\n");
+    
+    link->state &= ~DEV_CONFIG_PENDING;
+    return;
+    
+cs_failed:
+    cs_error(link->handle, last_fn, last_ret);
+failed:
+    parport_cs_release((u_long)link);
+
+} /* parport_config */
+
+/*======================================================================
+
+    After a card is removed, parport_cs_release() will unregister the
+    device, and release the PCMCIA configuration.  If the device is
+    still open, this will be postponed until it is closed.
+    
+======================================================================*/
+
+void parport_cs_release(u_long arg)
+{
+    dev_link_t *link = (dev_link_t *)arg;
+    parport_info_t *info = link->priv;
+    
+    DEBUG(0, "parport_release(0x%p)\n", link);
+
+    if (info->ndev) {
+	struct parport *p = info->port;
+	if (!(p->flags & PARPORT_FLAG_COMA))
+	    parport_quiesce(p);
+	parport_proc_unregister(p);
+#if (LINUX_VERSION_CODE >= VERSION(2,2,8))
+	kfree(p->private_data);
+#endif
+	parport_unregister_port(p);
+    }
+    info->ndev = 0;
+    link->dev = NULL;
+    
+    CardServices(ReleaseConfiguration, link->handle);
+    CardServices(ReleaseIO, link->handle, &link->io);
+    CardServices(ReleaseIRQ, link->handle, &link->irq);
+    
+    link->state &= ~DEV_CONFIG;
+
+} /* parport_cs_release */
+
+/*======================================================================
+
+    The card status event handler.  Mostly, this schedules other
+    stuff to run after an event is received.
+    
+======================================================================*/
+
+int parport_event(event_t event, int priority,
+		  event_callback_args_t *args)
+{
+    dev_link_t *link = args->client_data;
+
+    DEBUG(1, "parport_event(0x%06x)\n", event);
+    
+    switch (event) {
+    case CS_EVENT_CARD_REMOVAL:
+	link->state &= ~DEV_PRESENT;
+	if (link->state & DEV_CONFIG)
+	    mod_timer(&link->release, jiffies + HZ/20);
+	break;
+    case CS_EVENT_CARD_INSERTION:
+	link->state |= DEV_PRESENT | DEV_CONFIG_PENDING;
+	parport_config(link);
+	break;
+    case CS_EVENT_PM_SUSPEND:
+	link->state |= DEV_SUSPEND;
+	/* Fall through... */
+    case CS_EVENT_RESET_PHYSICAL:
+	if (link->state & DEV_CONFIG)
+	    CardServices(ReleaseConfiguration, link->handle);
+	break;
+    case CS_EVENT_PM_RESUME:
+	link->state &= ~DEV_SUSPEND;
+	/* Fall through... */
+    case CS_EVENT_CARD_RESET:
+	if (DEV_OK(link))
+	    CardServices(RequestConfiguration, link->handle, &link->conf);
+	break;
+    }
+    return 0;
+} /* parport_event */
+
+/*====================================================================*/
+
+static void inc_use_count(void)
+{
+    MOD_INC_USE_COUNT;
+    parport_pc_ops.inc_use_count();
+}
+
+static void dec_use_count(void)
+{
+    MOD_DEC_USE_COUNT;
+    parport_pc_ops.dec_use_count();
+}
+
+/*====================================================================*/
+
+static int __init init_parport_cs(void)
+{
+    servinfo_t serv;
+    DEBUG(0, "%s\n", version);
+    CardServices(GetCardServicesInfo, &serv);
+    if (serv.Revision != CS_RELEASE_CODE) {
+	printk(KERN_NOTICE "parport_cs: Card Services release "
+	       "does not match!\n");
+	return -1;
+    }
+
+    /* This is to protect against unloading modules out of order */
+    parport_cs_ops = parport_pc_ops;
+    parport_cs_ops.inc_use_count = &inc_use_count;
+    parport_cs_ops.dec_use_count = &dec_use_count;
+    
+    register_pccard_driver(&dev_info, &parport_attach, &parport_detach);
+    return 0;
+}
+
+static void __exit exit_parport_cs(void)
+{
+    DEBUG(0, "parport_cs: unloading\n");
+    unregister_pccard_driver(&dev_info);
+    while (dev_list != NULL)
+	parport_detach(dev_list);
+}
+
+module_init(init_parport_cs);
+module_exit(exit_parport_cs);
Index: oldkernel/linux/pcmcia-cs-3.1.15/clients/pcnet_cs.c
diff -u /dev/null linux/pcmcia-cs-3.1.15/clients/pcnet_cs.c:1.1
--- /dev/null	Mon Jul 31 21:15:10 2000
+++ linux/pcmcia-cs-3.1.15/clients/pcnet_cs.c	Fri Jul  7 16:34:58 2000
@@ -0,0 +1,1532 @@
+/*======================================================================
+
+    A PCMCIA ethernet driver for NS8390-based cards
+
+    This driver supports the D-Link DE-650 and Linksys EthernetCard
+    cards, the newer D-Link and Linksys combo cards, Accton EN2212
+    cards, the RPTI EP400, and the PreMax PE-200 in non-shared-memory
+    mode, and the IBM Credit Card Adapter, the NE4100, the Thomas
+    Conrad ethernet card, and the Kingston KNE-PCM/x in shared-memory
+    mode.  It will also handle the Socket EA card in either mode.
+
+    Copyright (C) 1999 David A. Hinds -- dhinds@pcmcia.sourceforge.org
+
+    pcnet_cs.c 1.120 2000/05/13 02:35:35
+    
+    The network driver code is based on Donald Becker's NE2000 code:
+
+    Written 1992,1993 by Donald Becker.
+    Copyright 1993 United States Government as represented by the
+    Director, National Security Agency.  This software may be used and
+    distributed according to the terms of the GNU Public License,
+    incorporated herein by reference.
+    Donald Becker may be reached at becker@cesdis1.gsfc.nasa.gov
+
+    Based also on Keith Moore's changes to Don Becker's code, for IBM
+    CCAE support.  Drivers merged back together, and shared-memory
+    Socket EA support added, by Ken Raeburn, September 1995.
+
+======================================================================*/
+
+#include <pcmcia/config.h>
+#include <pcmcia/k_compat.h>
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/sched.h>
+#include <linux/ptrace.h>
+#include <linux/malloc.h>
+#include <linux/string.h>
+#include <linux/timer.h>
+#include <linux/delay.h>
+#include <asm/io.h>
+#include <asm/system.h>
+
+#include <linux/netdevice.h>
+#include <../drivers/net/8390.h>
+
+#include <pcmcia/version.h>
+#include <pcmcia/cs_types.h>
+#include <pcmcia/cs.h>
+#include <pcmcia/cistpl.h>
+#include <pcmcia/ciscode.h>
+#include <pcmcia/ds.h>
+#include <pcmcia/cisreg.h>
+
+#define PCNET_CMD	0x00
+#define PCNET_DATAPORT	0x10	/* NatSemi-defined port window offset. */
+#define PCNET_RESET	0x1f	/* Issue a read to reset, a write to clear. */
+#define PCNET_MISC	0x18	/* For IBM CCAE and Socket EA cards */
+
+#define PCNET_START_PG	0x40	/* First page of TX buffer */
+#define PCNET_STOP_PG	0x80	/* Last page +1 of RX ring */
+
+/* Socket EA cards have a larger packet buffer */
+#define SOCKET_START_PG	0x01
+#define SOCKET_STOP_PG	0xff
+
+#define PCNET_RDC_TIMEOUT 0x02	/* Max wait in jiffies for Tx RDC */
+
+static char *if_names[] = { "auto", "10baseT", "10base2"};
+
+#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 =
+"pcnet_cs.c 1.120 2000/05/13 02:35:35 (David Hinds)";
+#else
+#define DEBUG(n, args...)
+#endif
+
+/*====================================================================*/
+
+/* Parameters that can be set with 'insmod' */
+
+/* Bit map of interrupts to choose from */
+static u_int irq_mask = 0xdeb8;
+static int irq_list[4] = { -1 };
+
+/* Transceiver type, for Socket EA and IBM CC cards. */
+static int if_port = 1;
+
+/* Use 64K packet buffer, for Socket EA cards. */
+static int use_big_buf = 1;
+
+/* Shared memory speed, in ns */
+static int mem_speed = 0;
+
+/* Insert a pause in block_output after sending a packet */
+static int delay_output = 0;
+
+/* Length of delay, in microseconds */
+static int delay_time = 4;
+
+/* Use shared memory, if available? */
+static int use_shmem = -1;
+
+/* Ugh!  Let the user hardwire the hardware address for queer cards */
+static int hw_addr[6] = { 0, /* ... */ };
+
+MODULE_PARM(irq_mask, "i");
+MODULE_PARM(irq_list, "1-4i");
+MODULE_PARM(if_port, "i");
+MODULE_PARM(use_big_buf, "i");
+MODULE_PARM(mem_speed, "i");
+MODULE_PARM(delay_output, "i");
+MODULE_PARM(delay_time, "i");
+MODULE_PARM(use_shmem, "i");
+MODULE_PARM(hw_addr, "6i");
+
+/*====================================================================*/
+
+static void pcnet_config(dev_link_t *link);
+static void pcnet_release(u_long arg);
+static int pcnet_event(event_t event, int priority,
+		       event_callback_args_t *args);
+static int pcnet_open(struct net_device *dev);
+static int pcnet_close(struct net_device *dev);
+static int do_ioctl(struct net_device *dev, struct ifreq *rq, int cmd);
+static void ei_irq_wrapper(int irq, void *dev_id, struct pt_regs *regs);
+static void ei_watchdog(u_long arg);
+static void pcnet_reset_8390(struct net_device *dev);
+static int set_config(struct net_device *dev, struct ifmap *map);
+static int setup_shmem_window(dev_link_t *link, int start_pg,
+			      int stop_pg, int cm_offset);
+static int setup_dma_config(dev_link_t *link, int start_pg,
+			    int stop_pg);
+
+static dev_link_t *pcnet_attach(void);
+static void pcnet_detach(dev_link_t *);
+
+static dev_info_t dev_info = "pcnet_cs";
+static dev_link_t *dev_list;
+
+/*====================================================================*/
+
+typedef struct hw_info_t {
+    u_int	offset;
+    u_char	a0, a1, a2;
+    u_int	flags;
+} hw_info_t;
+
+#define DELAY_OUTPUT	0x01
+#define HAS_MISC_REG	0x02
+#define USE_BIG_BUF	0x04
+#define HAS_IBM_MISC	0x08
+#define IS_DL10019	0x10
+#define IS_DL10022	0x20
+#define IS_AX88190	0x40
+#define USE_SHMEM	0x80	/* autodetected */
+
+static hw_info_t hw_info[] = {
+    { /* Accton EN2212 */ 0x0ff0, 0x00, 0x00, 0xe8, DELAY_OUTPUT }, 
+    { /* Allied Telesis LA-PCM */ 0x0ff0, 0x00, 0x00, 0xf4, 0 },
+    { /* APEX MultiCard */ 0x03f4, 0x00, 0x20, 0xe5, 0 },
+    { /* ASANTE FriendlyNet */ 0x4910, 0x00, 0x00, 0x94,
+      DELAY_OUTPUT | HAS_IBM_MISC },
+    { /* Danpex EN-6200P2 */ 0x0110, 0x00, 0x40, 0xc7, 0 },
+    { /* DataTrek NetCard */ 0x0ff0, 0x00, 0x20, 0xe8, 0 },
+    { /* Dayna CommuniCard E */ 0x0110, 0x00, 0x80, 0x19, 0 },
+    { /* D-Link DE-650 */ 0x0040, 0x00, 0x80, 0xc8, 0 },
+    { /* EP-210 Ethernet */ 0x0110, 0x00, 0x40, 0x33, 0 },
+    { /* EP4000 Ethernet */ 0x01c0, 0x00, 0x00, 0xb4, 0 },
+    { /* Epson EEN10B */ 0x0ff0, 0x00, 0x00, 0x48,
+      HAS_MISC_REG | HAS_IBM_MISC },
+    { /* ELECOM Laneed LD-CDWA */ 0xb8, 0x08, 0x00, 0x42, 0 },
+    { /* Hypertec Ethernet */ 0x01c0, 0x00, 0x40, 0x4c, 0 },
+    { /* IBM CCAE */ 0x0ff0, 0x08, 0x00, 0x5a,
+      HAS_MISC_REG | HAS_IBM_MISC },
+    { /* IBM CCAE */ 0x0ff0, 0x00, 0x04, 0xac,
+      HAS_MISC_REG | HAS_IBM_MISC },
+    { /* IBM CCAE */ 0x0ff0, 0x00, 0x06, 0x29,
+      HAS_MISC_REG | HAS_IBM_MISC },
+    { /* IBM FME */ 0x0374, 0x08, 0x00, 0x5a,
+      HAS_MISC_REG | HAS_IBM_MISC },
+    { /* IBM FME */ 0x0374, 0x00, 0x04, 0xac,
+      HAS_MISC_REG | HAS_IBM_MISC },
+    { /* Kansai KLA-PCM/T */ 0x0ff0, 0x00, 0x60, 0x87,
+      HAS_MISC_REG | HAS_IBM_MISC },
+    { /* NSC DP83903 */ 0x0374, 0x08, 0x00, 0x17,
+      HAS_MISC_REG | HAS_IBM_MISC },
+    { /* NSC DP83903 */ 0x0374, 0x00, 0xc0, 0xa8,
+      HAS_MISC_REG | HAS_IBM_MISC },
+    { /* NSC DP83903 */ 0x0374, 0x00, 0xa0, 0xb0,
+      HAS_MISC_REG | HAS_IBM_MISC },
+    { /* NSC DP83903 */ 0x0198, 0x00, 0x20, 0xe0,
+      HAS_MISC_REG | HAS_IBM_MISC },
+    { /* I-O DATA PCLA/T */ 0x0ff0, 0x00, 0xa0, 0xb0, 0 },
+    { /* Katron PE-520 */ 0x0110, 0x00, 0x40, 0xf6, 0 },
+    { /* Kingston KNE-PCM/x */ 0x0ff0, 0x00, 0xc0, 0xf0,
+      HAS_MISC_REG | HAS_IBM_MISC },
+    { /* Kingston KNE-PCM/x */ 0x0ff0, 0xe2, 0x0c, 0x0f,
+      HAS_MISC_REG | HAS_IBM_MISC },
+    { /* Kingston KNE-PC2 */ 0x0180, 0x00, 0xc0, 0xf0, 0 },
+    { /* Maxtech PCN2000 */ 0x5000, 0x00, 0x00, 0xe8, 0 },
+    { /* NDC Instant-Link */ 0x003a, 0x00, 0x80, 0xc6, 0 },
+    { /* NE2000 Compatible */ 0x0ff0, 0x00, 0xa0, 0x0c, 0 },
+    { /* Network General Sniffer */ 0x0ff0, 0x00, 0x00, 0x65,
+      HAS_MISC_REG | HAS_IBM_MISC },
+    { /* Panasonic VEL211 */ 0x0ff0, 0x00, 0x80, 0x45, 
+      HAS_MISC_REG | HAS_IBM_MISC },
+    { /* PreMax PE-200 */ 0x07f0, 0x00, 0x20, 0xe0, 0 },
+    { /* RPTI EP400 */ 0x0110, 0x00, 0x40, 0x95, 0 },
+    { /* SCM Ethernet */ 0x0ff0, 0x00, 0x20, 0xcb, 0 },
+    { /* Socket EA */ 0x4000, 0x00, 0xc0, 0x1b,
+      DELAY_OUTPUT | HAS_MISC_REG | USE_BIG_BUF },
+    { /* SuperSocket RE450T */ 0x0110, 0x00, 0xe0, 0x98, 0 },
+    { /* Volktek NPL-402CT */ 0x0060, 0x00, 0x40, 0x05, 0 },
+    { /* NEC PC-9801N-J12 */ 0x0ff0, 0x00, 0x00, 0x4c, 0 },
+    { /* PCMCIA Technology OEM */ 0x01c8, 0x00, 0xa0, 0x0c, 0 }
+};
+
+#define NR_INFO		(sizeof(hw_info)/sizeof(hw_info_t))
+
+static hw_info_t default_info = { 0, 0, 0, 0, 0 };
+static hw_info_t dl10019_info = { 0, 0, 0, 0, IS_DL10019 };
+static hw_info_t dl10022_info = { 0, 0, 0, 0, IS_DL10019|IS_DL10022 };
+#if 0
+static hw_info_t ax88190_info = { 0, 0, 0, 0, IS_AX88190 };
+#endif
+
+typedef struct pcnet_dev_t {
+    struct net_device	dev;	/* so &dev == &pcnet_dev_t */
+    dev_link_t		link;
+    dev_node_t		node;
+    u_int		flags;
+    caddr_t		base;
+    struct timer_list	watchdog;
+    int			stale, fast_poll;
+    u_short		link_status;
+} pcnet_dev_t;
+
+/*======================================================================
+
+    This bit of code is used to avoid unregistering network devices
+    at inappropriate times.  2.2 and later kernels are fairly picky
+    about when this can happen.
+    
+======================================================================*/
+
+static void flush_stale_links(void)
+{
+    dev_link_t *link, *next;
+    for (link = dev_list; link; link = next) {
+	next = link->next;
+	if (link->state & DEV_STALE_LINK)
+	    pcnet_detach(link);
+    }
+}
+
+/*====================================================================*/
+
+static void cs_error(client_handle_t handle, int func, int ret)
+{
+    error_info_t err = { func, ret };
+    CardServices(ReportError, handle, &err);
+}
+
+/*======================================================================
+
+    We never need to do anything when a pcnet device is "initialized"
+    by the net software, because we only register already-found cards.
+
+======================================================================*/
+
+static int pcnet_init(struct net_device *dev)
+{
+    return 0;
+}
+
+/*======================================================================
+
+    pcnet_attach() creates an "instance" of the driver, allocating
+    local data structures for one device.  The device is registered
+    with Card Services.
+
+======================================================================*/
+
+static dev_link_t *pcnet_attach(void)
+{
+    pcnet_dev_t *info;
+    dev_link_t *link;
+    struct net_device *dev;
+    client_reg_t client_reg;
+    int i, ret;
+
+    DEBUG(0, "pcnet_attach()\n");
+    flush_stale_links();
+
+    /* Create new ethernet device */
+    info = kmalloc(sizeof(*info), GFP_KERNEL);
+    if (!info) return NULL;
+    memset(info, 0, sizeof(*info));
+    link = &info->link; dev = &info->dev;
+    link->priv = info;
+    
+    link->release.function = &pcnet_release;
+    link->release.data = (u_long)link;
+    link->irq.Attributes = IRQ_TYPE_EXCLUSIVE;
+    link->irq.IRQInfo1 = IRQ_INFO2_VALID|IRQ_LEVEL_ID;
+    if (irq_list[0] == -1)
+	link->irq.IRQInfo2 = irq_mask;
+    else
+	for (i = 0; i < 4; i++)
+	    link->irq.IRQInfo2 |= 1 << irq_list[i];
+    link->conf.Attributes = CONF_ENABLE_IRQ;
+    link->conf.IntType = INT_MEMORY_AND_IO;
+
+    ethdev_init(dev);
+    dev->name = info->node.dev_name;
+    dev->init = &pcnet_init;
+    dev->open = &pcnet_open;
+    dev->stop = &pcnet_close;
+    dev->set_config = &set_config;
+
+    /* Register with Card Services */
+    link->next = dev_list;
+    dev_list = link;
+    client_reg.dev_info = &dev_info;
+    client_reg.Attributes = INFO_IO_CLIENT | INFO_CARD_SHARE;
+    client_reg.EventMask =
+	CS_EVENT_CARD_INSERTION | CS_EVENT_CARD_REMOVAL |
+	CS_EVENT_RESET_PHYSICAL | CS_EVENT_CARD_RESET |
+	CS_EVENT_PM_SUSPEND | CS_EVENT_PM_RESUME;
+    client_reg.event_handler = &pcnet_event;
+    client_reg.Version = 0x0210;
+    client_reg.event_callback_args.client_data = link;
+    ret = CardServices(RegisterClient, &link->handle, &client_reg);
+    if (ret != CS_SUCCESS) {
+	cs_error(link->handle, RegisterClient, ret);
+	pcnet_detach(link);
+	return NULL;
+    }
+
+    return link;
+} /* pcnet_attach */
+
+/*======================================================================
+
+    This deletes a driver "instance".  The device is de-registered
+    with Card Services.  If it has been released, all local data
+    structures are freed.  Otherwise, the structures will be freed
+    when the device is released.
+
+======================================================================*/
+
+static void pcnet_detach(dev_link_t *link)
+{
+    pcnet_dev_t *info = link->priv;
+    dev_link_t **linkp;
+
+    DEBUG(0, "pcnet_detach(0x%p)\n", link);
+
+    /* Locate device structure */
+    for (linkp = &dev_list; *linkp; linkp = &(*linkp)->next)
+	if (*linkp == link) break;
+    if (*linkp == NULL)
+	return;
+
+    del_timer(&link->release);
+    if (link->state & DEV_CONFIG) {
+	pcnet_release((u_long)link);
+	if (link->state & DEV_STALE_CONFIG) {
+	    link->state |= DEV_STALE_LINK;
+	    return;
+	}
+    }
+
+    if (link->handle)
+	CardServices(DeregisterClient, link->handle);
+
+    /* Unlink device structure, free bits */
+    *linkp = link->next;
+    if (link->dev)
+	unregister_netdev(&info->dev);
+    kfree(info);
+
+} /* pcnet_detach */
+
+/*======================================================================
+
+    This probes for a card's hardware address, for card types that
+    encode this information in their CIS.
+
+======================================================================*/
+
+static hw_info_t *get_hwinfo(dev_link_t *link)
+{
+    struct net_device *dev = link->priv;
+    win_req_t req;
+    memreq_t mem;
+    u_char *base, *virt;
+    int i, j;
+
+    /* Allocate a small memory window */
+    req.Attributes = WIN_DATA_WIDTH_8|WIN_MEMORY_TYPE_AM|WIN_ENABLE;
+    req.Base = 0; req.Size = 0;
+    req.AccessSpeed = 0;
+    link->win = (window_handle_t)link->handle;
+    i = CardServices(RequestWindow, &link->win, &req);
+    if (i != CS_SUCCESS) {
+	cs_error(link->handle, RequestWindow, i);
+	return NULL;
+    }
+
+    virt = ioremap(req.Base, req.Size);
+    mem.Page = 0;
+    for (i = 0; i < NR_INFO; i++) {
+	mem.CardOffset = hw_info[i].offset & ~(req.Size-1);
+	CardServices(MapMemPage, link->win, &mem);
+	base = &virt[hw_info[i].offset & (req.Size-1)];
+	if ((readb(base+0) == hw_info[i].a0) &&
+	    (readb(base+2) == hw_info[i].a1) &&
+	    (readb(base+4) == hw_info[i].a2))
+	    break;
+    }
+    if (i < NR_INFO) {
+	for (j = 0; j < 6; j++)
+	    dev->dev_addr[j] = readb(base + (j<<1));
+    }
+    
+    iounmap(virt);
+    j = CardServices(ReleaseWindow, link->win);
+    if (j != CS_SUCCESS)
+	cs_error(link->handle, ReleaseWindow, j);
+    return (i < NR_INFO) ? hw_info+i : NULL;
+} /* get_hwinfo */
+
+/*======================================================================
+
+    This probes for a card's hardware address by reading the PROM.
+    It checks the address against a list of known types, then falls
+    back to a simple NE2000 clone signature check.
+
+======================================================================*/
+
+static hw_info_t *get_prom(dev_link_t *link)
+{
+    struct net_device *dev = link->priv;
+    ioaddr_t ioaddr = dev->base_addr;
+    u_char prom[32];
+    int i, j;
+
+    /* This is lifted straight from drivers/net/ne.c */
+    struct {
+	u_char value, offset;
+    } program_seq[] = {
+	{E8390_NODMA+E8390_PAGE0+E8390_STOP, E8390_CMD}, /* Select page 0*/
+	{0x48,	EN0_DCFG},	/* Set byte-wide (0x48) access. */
+	{0x00,	EN0_RCNTLO},	/* Clear the count regs. */
+	{0x00,	EN0_RCNTHI},
+	{0x00,	EN0_IMR},	/* Mask completion irq. */
+	{0xFF,	EN0_ISR},
+	{E8390_RXOFF, EN0_RXCR},	/* 0x20  Set to monitor */
+	{E8390_TXOFF, EN0_TXCR},	/* 0x02  and loopback mode. */
+	{32,	EN0_RCNTLO},
+	{0x00,	EN0_RCNTHI},
+	{0x00,	EN0_RSARLO},	/* DMA starting at 0x0000. */
+	{0x00,	EN0_RSARHI},
+	{E8390_RREAD+E8390_START, E8390_CMD},
+    };
+
+    pcnet_reset_8390(dev);
+    udelay(10000);
+
+    for (i = 0; i < sizeof(program_seq)/sizeof(program_seq[0]); i++)
+	outb_p(program_seq[i].value, ioaddr + program_seq[i].offset);
+
+    for (i = 0; i < 32; i++)
+	prom[i] = inb(ioaddr + PCNET_DATAPORT);
+    for (i = 0; i < NR_INFO; i++) {
+	if ((prom[0] == hw_info[i].a0) &&
+	    (prom[2] == hw_info[i].a1) &&
+	    (prom[4] == hw_info[i].a2))
+	    break;
+    }
+    if ((i < NR_INFO) || ((prom[28] == 0x57) && (prom[30] == 0x57))) {
+	for (j = 0; j < 6; j++)
+	    dev->dev_addr[j] = prom[j<<1];
+	return (i < NR_INFO) ? hw_info+i : &default_info;
+    }
+    return NULL;
+} /* get_prom */
+
+/*======================================================================
+
+    For DL10019 based cards, like the Linksys EtherFast
+
+======================================================================*/
+
+static hw_info_t *get_dl10019(dev_link_t *link)
+{
+    struct net_device *dev = link->priv;
+    int i;
+    u_char sum;
+
+    for (sum = 0, i = 0x14; i < 0x1c; i++)
+	sum += inb_p(dev->base_addr + i);
+    if (sum != 0xff)
+	return NULL;
+    for (i = 0; i < 6; i++)
+	dev->dev_addr[i] = inb_p(dev->base_addr + 0x14 + i);
+    i = inb(dev->base_addr + 0x1f);
+    return ((i == 0x91)||(i == 0x99)) ? &dl10022_info : &dl10019_info;
+}
+
+/*======================================================================
+
+    For Asix AX88190 based cards
+
+======================================================================*/
+
+static hw_info_t *get_ax88190(dev_link_t *link)
+{
+    struct net_device *dev = link->priv;
+    ioaddr_t ioaddr = dev->base_addr;
+    int i, j;
+
+    /* Not much of a test, but the alternatives are messy */
+    if (link->conf.ConfigBase != 0x03c0)
+	return NULL;
+
+    outb_p(0x01, EN0_DCFG);	/* Set word-wide access. */
+    outb_p(0x00, EN0_RSARLO);	/* DMA starting at 0x0400. */
+    outb_p(0x04, EN0_RSARHI);
+    outb_p(E8390_RREAD+E8390_START, E8390_CMD);
+
+    for (i = 0; i < 6; i += 2) {
+	j = inw(ioaddr + PCNET_DATAPORT);
+	dev->dev_addr[i] = j & 0xff;
+	dev->dev_addr[i+1] = j >> 8;
+    }
+#if 0
+    return &ax88190_info;
+#else
+    printk(KERN_INFO "pcnet_cs: sorry, the AX88190 chipset is not "
+	   "supported.\n");
+    return NULL;
+#endif
+}
+
+/*======================================================================
+
+    This should be totally unnecessary... but when we can't figure
+    out the hardware address any other way, we'll let the user hard
+    wire it when the module is initialized.
+
+======================================================================*/
+
+static hw_info_t *get_hwired(dev_link_t *link)
+{
+    struct net_device *dev = link->priv;
+    int i;
+
+    for (i = 0; i < 6; i++)
+	if (hw_addr[i] != 0) break;
+    if (i == 6)
+	return NULL;
+
+    for (i = 0; i < 6; i++)
+	dev->dev_addr[i] = hw_addr[i];
+
+    return &default_info;
+} /* get_hwired */
+
+/*======================================================================
+
+    pcnet_config() is scheduled to run after a CARD_INSERTION event
+    is received, to configure the PCMCIA socket, and to make the
+    ethernet device available to the system.
+
+======================================================================*/
+
+#define CS_CHECK(fn, args...) \
+while ((last_ret=CardServices(last_fn=(fn), args))!=0) goto cs_failed
+
+#define CFG_CHECK(fn, args...) \
+if (CardServices(fn, args) != 0) goto next_entry
+
+static int try_io_port(dev_link_t *link)
+{
+    int j, ret;
+    if (link->io.NumPorts1 == 32) {
+	link->io.Attributes1 = IO_DATA_PATH_WIDTH_AUTO;
+	if (link->io.NumPorts2 > 0) {
+	    /* for master/slave multifunction cards */
+	    link->io.Attributes2 = IO_DATA_PATH_WIDTH_8;
+	    link->irq.Attributes = 
+		IRQ_TYPE_DYNAMIC_SHARING|IRQ_FIRST_SHARED;
+	}
+    } else {
+	/* This should be two 16-port windows */
+	link->io.Attributes1 = IO_DATA_PATH_WIDTH_8;
+	link->io.Attributes2 = IO_DATA_PATH_WIDTH_16;
+    }
+    if (link->io.BasePort1 == 0) {
+	link->io.IOAddrLines = 16;
+	for (j = 0; j < 0x400; j += 0x20) {
+	    link->io.BasePort1 = j ^ 0x300;
+	    link->io.BasePort2 = (j ^ 0x300) + 0x10;
+	    ret = CardServices(RequestIO, link->handle, &link->io);
+	    if (ret == CS_SUCCESS) return ret;
+	}
+	return ret;
+    } else {
+	return CardServices(RequestIO, link->handle, &link->io);
+    }
+}
+
+static void pcnet_config(dev_link_t *link)
+{
+    client_handle_t handle = link->handle;
+    pcnet_dev_t *info = link->priv;
+    struct net_device *dev = &info->dev;
+    tuple_t tuple;
+    cisparse_t parse;
+    int i, last_ret, last_fn, start_pg, stop_pg, cm_offset;
+    int manfid = 0, prodid = 0, has_shmem = 0;
+    u_short buf[64];
+    config_info_t conf;
+    hw_info_t *hw_info;
+
+    DEBUG(0, "pcnet_config(0x%p)\n", link);
+
+    tuple.Attributes = 0;
+    tuple.TupleData = (cisdata_t *)buf;
+    tuple.TupleDataMax = sizeof(buf);
+    tuple.TupleOffset = 0;
+    tuple.DesiredTuple = CISTPL_CONFIG;
+    CS_CHECK(GetFirstTuple, handle, &tuple);
+    CS_CHECK(GetTupleData, handle, &tuple);
+    CS_CHECK(ParseTuple, handle, &tuple, &parse);
+    link->conf.ConfigBase = parse.config.base;
+    link->conf.Present = parse.config.rmask[0];
+
+    /* Configure card */
+    link->state |= DEV_CONFIG;
+
+    /* Look up current Vcc */
+    CS_CHECK(GetConfigurationInfo, handle, &conf);
+    link->conf.Vcc = conf.Vcc;
+
+    tuple.DesiredTuple = CISTPL_MANFID;
+    tuple.Attributes = TUPLE_RETURN_COMMON;
+    if ((CardServices(GetFirstTuple, handle, &tuple) == CS_SUCCESS) &&
+ 	(CardServices(GetTupleData, handle, &tuple) == CS_SUCCESS)) {
+	manfid = le16_to_cpu(buf[0]);
+	prodid = le16_to_cpu(buf[1]);
+    }
+    
+    tuple.DesiredTuple = CISTPL_CFTABLE_ENTRY;
+    tuple.Attributes = 0;
+    CS_CHECK(GetFirstTuple, handle, &tuple);
+    while (last_ret == CS_SUCCESS) {
+	cistpl_cftable_entry_t *cfg = &(parse.cftable_entry);
+	cistpl_io_t *io = &(parse.cftable_entry.io);
+	
+	CFG_CHECK(GetTupleData, handle, &tuple);
+	CFG_CHECK(ParseTuple, handle, &tuple, &parse);
+	if ((cfg->index == 0) || (cfg->io.nwin == 0))
+	    goto next_entry;
+	
+	link->conf.ConfigIndex = cfg->index;
+	/* For multifunction cards, by convention, we configure the
+	   network function with window 0, and serial with window 1 */
+	if (io->nwin > 1) {
+	    i = (io->win[1].len > io->win[0].len);
+	    link->io.BasePort2 = io->win[1-i].base;
+	    link->io.NumPorts2 = io->win[1-i].len;
+	} else {
+	    i = link->io.NumPorts2 = 0;
+	}
+	has_shmem = ((cfg->mem.nwin == 1) &&
+		     (cfg->mem.win[0].len >= 0x4000));
+	link->io.BasePort1 = io->win[i].base;
+	link->io.NumPorts1 = io->win[i].len;
+	link->io.IOAddrLines = io->flags & CISTPL_IO_LINES_MASK;
+	if (link->io.NumPorts1 + link->io.NumPorts2 >= 32) {
+	    last_ret = try_io_port(link);
+	    if (last_ret == CS_SUCCESS) break;
+	}
+    next_entry:
+	last_ret = CardServices(GetNextTuple, handle, &tuple);
+    }
+    if (last_ret != CS_SUCCESS) {
+	cs_error(handle, RequestIO, last_ret);
+	goto failed;
+    }
+
+    CS_CHECK(RequestIRQ, handle, &link->irq);
+    
+    if (link->io.NumPorts2 == 8) {
+	link->conf.Attributes |= CONF_ENABLE_SPKR;
+	link->conf.Status = CCSR_AUDIO_ENA;
+    }
+    if ((manfid == MANFID_IBM) &&
+	(prodid == PRODID_IBM_HOME_AND_AWAY))
+	link->conf.ConfigIndex |= 0x10;
+    
+    CS_CHECK(RequestConfiguration, handle, &link->conf);
+    dev->irq = link->irq.AssignedIRQ;
+    dev->base_addr = link->io.BasePort1;
+    if (info->flags & HAS_MISC_REG) {
+	if ((if_port == 1) || (if_port == 2))
+	    dev->if_port = if_port;
+	else
+	    printk(KERN_NOTICE "pcnet_cs: invalid if_port requested\n");
+    } else {
+	dev->if_port = 0;
+    }
+    if (register_netdev(dev) != 0) {
+	printk(KERN_NOTICE "pcnet_cs: register_netdev() failed\n");
+	goto failed;
+    }
+
+    hw_info = get_hwinfo(link);
+    if (hw_info == NULL)
+	hw_info = get_prom(link);
+    if (hw_info == NULL)
+	hw_info = get_dl10019(link);
+    if (hw_info == NULL)
+	hw_info = get_ax88190(link);
+    if (hw_info == NULL)
+	hw_info = get_hwired(link);
+    
+    if (hw_info == NULL) {
+	printk(KERN_NOTICE "pcnet_cs: unable to read hardware net"
+	       " address for io base %#3lx\n", dev->base_addr);
+	unregister_netdev(dev);
+	goto failed;
+    }
+
+    info->flags = hw_info->flags;
+    /* Check for user overrides */
+    info->flags |= (delay_output) ? DELAY_OUTPUT : 0;
+    if ((manfid == MANFID_SOCKET) && (prodid == PRODID_SOCKET_LPE))
+	info->flags &= ~USE_BIG_BUF;
+    if (!use_big_buf)
+	info->flags &= ~USE_BIG_BUF;
+    
+    if (info->flags & USE_BIG_BUF) {
+	start_pg = SOCKET_START_PG;
+	stop_pg = SOCKET_STOP_PG;
+	cm_offset = 0x10000;
+    } else {
+	start_pg = PCNET_START_PG;
+	stop_pg = PCNET_STOP_PG;
+	cm_offset = 0;
+    }
+
+    /* has_shmem is ignored if use_shmem != -1 */
+    if ((use_shmem == 0) || (!has_shmem && (use_shmem == -1)) ||
+	(setup_shmem_window(link, start_pg, stop_pg, cm_offset) != 0))
+	setup_dma_config(link, start_pg, stop_pg);
+
+    ei_status.name = "NE2000";
+    ei_status.word16 = 1;
+    ei_status.reset_8390 = &pcnet_reset_8390;
+
+    link->dev = &info->node;
+    link->state &= ~DEV_CONFIG_PENDING;
+
+    if (info->flags & IS_DL10019) {
+	dev->do_ioctl = &do_ioctl;
+	printk(KERN_INFO "%s: NE2000 (DL100%d rev %02x): ",
+	       dev->name, ((info->flags & IS_DL10022) ? 22 : 19),
+	       inb(dev->base_addr + 0x1a));
+    } else if (info->flags & IS_AX88190) {
+	printk(KERN_INFO "%s: NE2000 (AX88190): ", dev->name);
+    } else
+	printk(KERN_INFO "%s: NE2000 Compatible: ", dev->name);
+    printk("io %#3lx, irq %d,", dev->base_addr, dev->irq);
+    if (info->flags & USE_SHMEM)
+	printk (" mem %#5lx,", dev->mem_start);
+    if (info->flags & HAS_MISC_REG)
+	printk(" %s xcvr,", if_names[dev->if_port]);
+    printk(" hw_addr ");
+    for (i = 0; i < 6; i++)
+	printk("%02X%s", dev->dev_addr[i], ((i<5) ? ":" : "\n"));
+    return;
+
+cs_failed:
+    cs_error(link->handle, last_fn, last_ret);
+failed:
+    pcnet_release((u_long)link);
+    return;
+} /* pcnet_config */
+
+/*======================================================================
+
+    After a card is removed, pcnet_release() will unregister the net
+    device, and release the PCMCIA configuration.  If the device is
+    still open, this will be postponed until it is closed.
+
+======================================================================*/
+
+static void pcnet_release(u_long arg)
+{
+    dev_link_t *link = (dev_link_t *)arg;
+    pcnet_dev_t *info = link->priv;
+
+    DEBUG(0, "pcnet_release(0x%p)\n", link);
+
+    if (link->open) {
+	DEBUG(1, "pcnet_cs: release postponed, '%s' still open\n",
+	      info->node.dev_name);
+	link->state |= DEV_STALE_CONFIG;
+	return;
+    }
+
+    if (info->flags & USE_SHMEM) {
+	iounmap(info->base);
+	CardServices(ReleaseWindow, link->win);
+    }
+    CardServices(ReleaseConfiguration, link->handle);
+    CardServices(ReleaseIO, link->handle, &link->io);
+    CardServices(ReleaseIRQ, link->handle, &link->irq);
+
+    link->state &= ~DEV_CONFIG;
+
+} /* pcnet_release */
+
+/*======================================================================
+
+    The card status event handler.  Mostly, this schedules other
+    stuff to run after an event is received.  A CARD_REMOVAL event
+    also sets some flags to discourage the net drivers from trying
+    to talk to the card any more.
+
+======================================================================*/
+
+static int pcnet_event(event_t event, int priority,
+		       event_callback_args_t *args)
+{
+    dev_link_t *link = args->client_data;
+    pcnet_dev_t *info = link->priv;
+
+    DEBUG(2, "pcnet_event(0x%06x)\n", event);
+
+    switch (event) {
+    case CS_EVENT_CARD_REMOVAL:
+	link->state &= ~DEV_PRESENT;
+	if (link->state & DEV_CONFIG) {
+	    netif_device_detach(&info->dev);
+	    mod_timer(&link->release, jiffies + HZ/20);
+	}
+	break;
+    case CS_EVENT_CARD_INSERTION:
+	link->state |= DEV_PRESENT;
+	pcnet_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 (link->open)
+		netif_device_detach(&info->dev);
+	    CardServices(ReleaseConfiguration, link->handle);
+	}
+	break;
+    case CS_EVENT_PM_RESUME:
+	link->state &= ~DEV_SUSPEND;
+	/* Fall through... */
+    case CS_EVENT_CARD_RESET:
+	if (link->state & DEV_CONFIG) {
+	    CardServices(RequestConfiguration, link->handle, &link->conf);
+	    if (link->open) {
+		pcnet_reset_8390(&info->dev);
+		NS8390_init(&info->dev, 1);
+		netif_device_attach(&info->dev);
+	    }
+	}
+	break;
+    }
+    return 0;
+} /* pcnet_event */
+
+/*======================================================================
+
+    MII interface support for DL10019 and DL10022 based cards
+
+    On the DL10019, the MII IO direction bit is 0x10; on  the DL10022
+    it is 0x20.  Setting both bits seems to work on both card types.
+
+======================================================================*/
+
+#define DLINK_GPIO		0x1c
+#define DLINK_DIAG		0x1d
+#define MDIO_SHIFT_CLK		0x80
+#define MDIO_DATA_OUT		0x40
+#define MDIO_DIR_WRITE		0x30
+#define MDIO_DATA_WRITE0	(MDIO_DIR_WRITE)
+#define MDIO_DATA_WRITE1	(MDIO_DIR_WRITE | MDIO_DATA_OUT)
+#define MDIO_DATA_READ		0x10
+#define MDIO_MASK		0x0f
+
+static void mdio_sync(ioaddr_t addr)
+{
+    int bits, mask = inb(addr) & MDIO_MASK;
+    for (bits = 0; bits < 32; bits++) {
+	outb(mask | MDIO_DATA_WRITE1, addr);
+	outb(mask | MDIO_DATA_WRITE1 | MDIO_SHIFT_CLK, addr);
+    }
+}
+
+static int mdio_read(ioaddr_t addr, int phy_id, int loc)
+{
+    u_int cmd = (0x06<<10)|(phy_id<<5)|loc;
+    int i, retval = 0, mask = inb(addr) & MDIO_MASK;
+
+    mdio_sync(addr);
+    for (i = 13; i >= 0; i--) {
+	int dat = (cmd&(1<<i)) ? MDIO_DATA_WRITE1 : MDIO_DATA_WRITE0;
+	outb(mask | dat, addr);
+	outb(mask | dat | MDIO_SHIFT_CLK, addr);
+    }
+    for (i = 19; i > 0; i--) {
+	outb(mask, addr);
+	retval = (retval << 1) | ((inb(addr) & MDIO_DATA_READ) != 0);
+	outb(mask | MDIO_SHIFT_CLK, addr);
+    }
+    return (retval>>1) & 0xffff;
+}
+
+static void mdio_write(ioaddr_t addr, int phy_id, int loc, int value)
+{
+    u_int cmd = (0x05<<28)|(phy_id<<23)|(loc<<18)|(1<<17)|value;
+    int i, mask = inb(addr) & MDIO_MASK;
+
+    mdio_sync(addr);
+    for (i = 31; i >= 0; i--) {
+	int dat = (cmd&(1<<i)) ? MDIO_DATA_WRITE1 : MDIO_DATA_WRITE0;
+	outb(mask | dat, addr);
+	outb(mask | dat | MDIO_SHIFT_CLK, addr);
+    }
+    for (i = 1; i >= 0; i--) {
+	outb(mask, addr);
+	outb(mask | MDIO_SHIFT_CLK, addr);
+    }
+}
+
+static void mdio_reset(ioaddr_t addr, int phy_id)
+{
+    outb_p(0x08, addr);
+    outb_p(0x0c, addr);
+    outb_p(0x08, addr);
+    outb_p(0x0c, addr);
+    outb_p(0x00, addr);
+}
+
+/*====================================================================*/
+
+static void set_misc_reg(struct net_device *dev)
+{
+    ioaddr_t nic_base = dev->base_addr;
+    pcnet_dev_t *info = (pcnet_dev_t *)dev;
+    u_char tmp;
+    
+    if (info->flags & HAS_MISC_REG) {
+	tmp = inb_p(nic_base + PCNET_MISC) & ~3;
+	if (dev->if_port == 2)
+	    tmp |= 1;
+	if (info->flags & USE_BIG_BUF)
+	    tmp |= 2;
+	if (info->flags & HAS_IBM_MISC)
+	    tmp |= 8;
+	outb_p(tmp, nic_base + PCNET_MISC);
+    }
+    if (info->flags & IS_DL10022) {
+	mdio_reset(nic_base + DLINK_GPIO, 0);
+	/* Restart MII autonegotiation */
+	mdio_write(nic_base + DLINK_GPIO, 0, 0, 0x0000);
+	mdio_write(nic_base + DLINK_GPIO, 0, 0, 0x1200);
+    }
+}
+
+/*====================================================================*/
+
+static int pcnet_open(struct net_device *dev)
+{
+    pcnet_dev_t *info = (pcnet_dev_t *)dev;
+    dev_link_t *link = &info->link;
+    
+    DEBUG(2, "pcnet_open('%s')\n", dev->name);
+
+    if (!DEV_OK(link))
+	return -ENODEV;
+
+    link->open++;
+    MOD_INC_USE_COUNT;
+
+    set_misc_reg(dev);
+    request_irq(dev->irq, ei_irq_wrapper, SA_SHIRQ, dev_info, dev);
+
+    info->link_status = 0x00;
+    info->watchdog.function = &ei_watchdog;
+    info->watchdog.data = (u_long)info;
+    info->watchdog.expires = jiffies + HZ;
+    add_timer(&info->watchdog);
+
+    return ei_open(dev);
+} /* pcnet_open */
+
+/*====================================================================*/
+
+static int pcnet_close(struct net_device *dev)
+{
+    pcnet_dev_t *info = (pcnet_dev_t *)dev;
+    dev_link_t *link = &info->link;
+
+    DEBUG(2, "pcnet_close('%s')\n", dev->name);
+
+    free_irq(dev->irq, dev);
+    
+    link->open--;
+    netif_stop_queue(dev);
+    netif_mark_down(dev);
+    del_timer(&info->watchdog);
+    if (link->state & DEV_STALE_CONFIG)
+	mod_timer(&link->release, jiffies + HZ/20);
+
+    MOD_DEC_USE_COUNT;
+
+    return 0;
+} /* pcnet_close */
+
+/*======================================================================
+
+    Hard reset the card.  This used to pause for the same period that
+    a 8390 reset command required, but that shouldn't be necessary.
+
+======================================================================*/
+
+static void pcnet_reset_8390(struct net_device *dev)
+{
+    ioaddr_t nic_base = dev->base_addr;
+    int i;
+
+    ei_status.txing = ei_status.dmaing = 0;
+
+    outb(inb(nic_base + PCNET_RESET), nic_base + PCNET_RESET);
+
+    for (i = 0; i < 100; i++) {
+	if ((inb_p(nic_base+EN0_ISR) & ENISR_RESET) != 0)
+	    break;
+	udelay(100L);
+    }
+    outb_p(ENISR_RESET, nic_base + EN0_ISR); /* Ack intr. */
+    
+    if (i == 100)
+	printk(KERN_ERR "%s: pcnet_reset_8390() did not complete.\n",
+	       dev->name);
+    set_misc_reg(dev);
+    
+} /* pcnet_reset_8390 */
+
+/*====================================================================*/
+
+static int set_config(struct net_device *dev, struct ifmap *map)
+{
+    pcnet_dev_t *info = (pcnet_dev_t *)dev;
+    if ((map->port != (u_char)(-1)) && (map->port != dev->if_port)) {
+	if (!(info->flags & HAS_MISC_REG))
+	    return -EOPNOTSUPP;
+	else if ((map->port < 1) || (map->port > 2))
+	    return -EINVAL;
+	dev->if_port = map->port;
+	printk(KERN_INFO "%s: switched to %s port\n",
+	       dev->name, if_names[dev->if_port]);
+	NS8390_init(dev, 1);
+    }
+    return 0;
+}
+
+/*====================================================================*/
+
+static void ei_irq_wrapper(int irq, void *dev_id, struct pt_regs *regs)
+{
+    pcnet_dev_t *info = dev_id;
+    info->stale = 0;
+    ei_interrupt(irq, dev_id, regs);
+}
+
+static void ei_watchdog(u_long arg)
+{
+    pcnet_dev_t *info = (pcnet_dev_t *)(arg);
+    struct net_device *dev = &info->dev;
+    ioaddr_t nic_base = dev->base_addr;
+    u_short link;
+
+    if (!netif_device_present(dev)) goto reschedule;
+
+    /* Check for pending interrupt with expired latency timer: with
+       this, we can limp along even if the interrupt is blocked */
+    outb_p(E8390_NODMA+E8390_PAGE0, nic_base + E8390_CMD);
+    if (info->stale++ && (inb_p(nic_base + EN0_ISR) & ENISR_ALL)) {
+	if (!info->fast_poll)
+	    printk(KERN_INFO "%s: interrupt(s) dropped!\n", dev->name);
+	ei_irq_wrapper(dev->irq, dev, NULL);
+	info->fast_poll = HZ;
+    }
+    if (info->fast_poll) {
+	info->fast_poll--;
+	info->watchdog.expires = jiffies + 1;
+	add_timer(&info->watchdog);
+	return;
+    }
+
+    if (!(info->flags & IS_DL10019))
+	goto reschedule;
+
+    link = mdio_read(dev->base_addr + DLINK_GPIO, 0, 1) & 0x0004;
+    if (link != info->link_status) {
+	printk(KERN_INFO "%s: %s link beat\n", dev->name,
+	       (link) ? "found" : "lost");
+	if (link && info->flags & IS_DL10022) {
+	    /* Disable collision detection on full duplex links */
+	    u_short p = mdio_read(dev->base_addr + DLINK_GPIO, 0, 5);
+	    outb((p & 0x0140) ? 4 : 0, dev->base_addr + DLINK_DIAG);
+	}
+	if (link)
+	    NS8390_init(dev, 1);
+	info->link_status = link;
+    }
+
+reschedule:
+    info->watchdog.expires = jiffies + HZ;
+    add_timer(&info->watchdog);
+}
+
+/*====================================================================*/
+
+static int do_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
+{
+    u16 *data = (u16 *)&rq->ifr_data;
+    ioaddr_t addr = dev->base_addr + DLINK_GPIO;
+    switch (cmd) {
+    case SIOCDEVPRIVATE:
+	data[0] = 0;
+    case SIOCDEVPRIVATE+1:
+	data[3] = mdio_read(addr, data[0], data[1] & 0x1f);
+	return 0;
+    case SIOCDEVPRIVATE+2:
+	if (!capable(CAP_NET_ADMIN))
+	    return -EPERM;
+	mdio_write(addr, data[0], data[1] & 0x1f, data[2]);
+	return 0;
+    }
+    return -EOPNOTSUPP;
+}
+
+/*====================================================================*/
+
+static void dma_get_8390_hdr(struct net_device *dev,
+			     struct e8390_pkt_hdr *hdr,
+			     int ring_page)
+{
+    ioaddr_t nic_base = dev->base_addr;
+
+    if (ei_status.dmaing) {
+	printk(KERN_NOTICE "%s: DMAing conflict in dma_block_input."
+	       "[DMAstat:%1x][irqlock:%1x]\n",
+	       dev->name, ei_status.dmaing, ei_status.irqlock);
+	return;
+    }
+    
+    ei_status.dmaing |= 0x01;
+    outb_p(E8390_NODMA+E8390_PAGE0+E8390_START, nic_base + PCNET_CMD);
+    outb_p(sizeof(struct e8390_pkt_hdr), nic_base + EN0_RCNTLO);
+    outb_p(0, nic_base + EN0_RCNTHI);
+    outb_p(0, nic_base + EN0_RSARLO);		/* On page boundary */
+    outb_p(ring_page, nic_base + EN0_RSARHI);
+    outb_p(E8390_RREAD+E8390_START, nic_base + PCNET_CMD);
+
+    insw_ns(nic_base + PCNET_DATAPORT, hdr,
+	    sizeof(struct e8390_pkt_hdr)>>1);
+    /* Fix for big endian systems */
+    hdr->count = le16_to_cpu(hdr->count);
+
+    outb_p(ENISR_RDC, nic_base + EN0_ISR);	/* Ack intr. */
+    ei_status.dmaing &= ~0x01;
+}
+
+/*====================================================================*/
+
+static void dma_block_input(struct net_device *dev, int count,
+			    struct sk_buff *skb, int ring_offset)
+{
+    ioaddr_t nic_base = dev->base_addr;
+    int xfer_count = count;
+    char *buf = skb->data;
+
+#ifdef PCMCIA_DEBUG
+    if ((ei_debug > 4) && (count != 4))
+	printk(KERN_DEBUG "%s: [bi=%d]\n", dev->name, count+4);
+#endif
+    if (ei_status.dmaing) {
+	printk(KERN_NOTICE "%s: DMAing conflict in dma_block_input."
+	       "[DMAstat:%1x][irqlock:%1x]\n",
+	       dev->name, ei_status.dmaing, ei_status.irqlock);
+	return;
+    }
+    ei_status.dmaing |= 0x01;
+    outb_p(E8390_NODMA+E8390_PAGE0+E8390_START, nic_base + PCNET_CMD);
+    outb_p(count & 0xff, nic_base + EN0_RCNTLO);
+    outb_p(count >> 8, nic_base + EN0_RCNTHI);
+    outb_p(ring_offset & 0xff, nic_base + EN0_RSARLO);
+    outb_p(ring_offset >> 8, nic_base + EN0_RSARHI);
+    outb_p(E8390_RREAD+E8390_START, nic_base + PCNET_CMD);
+
+    insw_ns(nic_base + PCNET_DATAPORT,buf,count>>1);
+    if (count & 0x01)
+	buf[count-1] = inb(nic_base + PCNET_DATAPORT), xfer_count++;
+
+    /* This was for the ALPHA version only, but enough people have
+       encountering problems that it is still here. */
+#ifdef PCMCIA_DEBUG
+    if (ei_debug > 4) {		/* DMA termination address check... */
+	int addr, tries = 20;
+	do {
+	    /* DON'T check for 'inb_p(EN0_ISR) & ENISR_RDC' here
+	       -- it's broken for Rx on some cards! */
+	    int high = inb_p(nic_base + EN0_RSARHI);
+	    int low = inb_p(nic_base + EN0_RSARLO);
+	    addr = (high << 8) + low;
+	    if (((ring_offset + xfer_count) & 0xff) == (addr & 0xff))
+		break;
+	} while (--tries > 0);
+	if (tries <= 0)
+	    printk(KERN_NOTICE "%s: RX transfer address mismatch,"
+		   "%#4.4x (expected) vs. %#4.4x (actual).\n",
+		   dev->name, ring_offset + xfer_count, addr);
+    }
+#endif
+    outb_p(ENISR_RDC, nic_base + EN0_ISR);	/* Ack intr. */
+    ei_status.dmaing &= ~0x01;
+} /* dma_block_input */
+
+/*====================================================================*/
+
+static void dma_block_output(struct net_device *dev, int count,
+			     const u_char *buf, const int start_page)
+{
+    ioaddr_t nic_base = dev->base_addr;
+    pcnet_dev_t *info = (pcnet_dev_t *)dev;
+#ifdef PCMCIA_DEBUG
+    int retries = 0;
+#endif
+    u_long dma_start;
+
+#ifdef PCMCIA_DEBUG
+    if (ei_debug > 4)
+	printk(KERN_DEBUG "%s: [bo=%d]\n", dev->name, count);
+#endif
+
+    /* Round the count up for word writes.  Do we need to do this?
+       What effect will an odd byte count have on the 8390?
+       I should check someday. */
+    if (count & 0x01)
+	count++;
+    if (ei_status.dmaing) {
+	printk(KERN_NOTICE "%s: DMAing conflict in dma_block_output."
+	       "[DMAstat:%1x][irqlock:%1x]\n",
+	       dev->name, ei_status.dmaing, ei_status.irqlock);
+	return;
+    }
+    ei_status.dmaing |= 0x01;
+    /* We should already be in page 0, but to be safe... */
+    outb_p(E8390_PAGE0+E8390_START+E8390_NODMA, nic_base+PCNET_CMD);
+
+#ifdef PCMCIA_DEBUG
+  retry:
+#endif
+
+    outb_p(ENISR_RDC, nic_base + EN0_ISR);
+
+    /* Now the normal output. */
+    outb_p(count & 0xff, nic_base + EN0_RCNTLO);
+    outb_p(count >> 8,   nic_base + EN0_RCNTHI);
+    outb_p(0x00, nic_base + EN0_RSARLO);
+    outb_p(start_page, nic_base + EN0_RSARHI);
+
+    outb_p(E8390_RWRITE+E8390_START, nic_base + PCNET_CMD);
+    outsw_ns(nic_base + PCNET_DATAPORT, buf, count>>1);
+
+    dma_start = jiffies;
+
+#ifdef PCMCIA_DEBUG
+    /* This was for the ALPHA version only, but enough people have
+       encountering problems that it is still here. */
+    if (ei_debug > 4) {	/* DMA termination address check... */
+	int addr, tries = 20;
+	do {
+	    int high = inb_p(nic_base + EN0_RSARHI);
+	    int low = inb_p(nic_base + EN0_RSARLO);
+	    addr = (high << 8) + low;
+	    if ((start_page << 8) + count == addr)
+		break;
+	} while (--tries > 0);
+	if (tries <= 0) {
+	    printk(KERN_NOTICE "%s: Tx packet transfer address mismatch,"
+		   "%#4.4x (expected) vs. %#4.4x (actual).\n",
+		   dev->name, (start_page << 8) + count, addr);
+	    if (retries++ == 0)
+		goto retry;
+	}
+    }
+#endif
+
+    while ((inb_p(nic_base + EN0_ISR) & ENISR_RDC) == 0)
+	if (jiffies - dma_start > PCNET_RDC_TIMEOUT) {
+	    printk(KERN_NOTICE "%s: timeout waiting for Tx RDC.\n",
+		   dev->name);
+	    pcnet_reset_8390(dev);
+	    NS8390_init(dev, 1);
+	    break;
+	}
+
+    outb_p(ENISR_RDC, nic_base + EN0_ISR);	/* Ack intr. */
+    if (info->flags & DELAY_OUTPUT)
+	udelay((long)delay_time);
+    ei_status.dmaing &= ~0x01;
+}
+
+/*====================================================================*/
+
+static int setup_dma_config(dev_link_t *link, int start_pg,
+			    int stop_pg)
+{
+    struct net_device *dev = link->priv;
+
+    ei_status.tx_start_page = start_pg;
+    ei_status.rx_start_page = start_pg + TX_PAGES;
+    ei_status.stop_page = stop_pg;
+
+    /* set up block i/o functions */
+    ei_status.get_8390_hdr = &dma_get_8390_hdr;
+    ei_status.block_input = &dma_block_input;
+    ei_status.block_output = &dma_block_output;
+
+    return 0;
+}
+
+/*====================================================================*/
+
+static void copyin(u_char *dest, u_char *src, int c)
+{
+    u_short *d = (u_short *)dest, *s = (u_short *)src;
+    int odd;
+
+    if (c <= 0)
+	return;
+    odd = (c & 1); c >>= 1;
+
+    if (c) {
+	do { *d++ = readw_ns(s++); } while (--c);
+    }
+    /* get last byte by fetching a word and masking */
+    if (odd)
+	*((u_char *)d) = readw(s) & 0xff;
+}
+
+static void copyout(u_char *dest, const u_char *src, int c)
+{
+    u_short *d = (u_short *)dest, *s = (u_short *)src;
+    int odd;
+
+    if (c <= 0)
+	return;
+    odd = (c & 1); c >>= 1;
+
+    if (c) {
+	do { writew_ns(*s++, d++); } while (--c);
+    }
+    /* copy last byte doing a read-modify-write */
+    if (odd)
+	writew((readw(d) & 0xff00) | *(u_char *)s, d);
+}
+
+/*====================================================================*/
+
+static void shmem_get_8390_hdr(struct net_device *dev,
+			       struct e8390_pkt_hdr *hdr,
+			       int ring_page)
+{
+    void *xfer_start = (void *)(dev->rmem_start + (ring_page << 8)
+				- (ei_status.rx_start_page << 8));
+    
+    copyin((void *)hdr, xfer_start, sizeof(struct e8390_pkt_hdr));
+    /* Fix for big endian systems */
+    hdr->count = le16_to_cpu(hdr->count);
+}
+
+/*====================================================================*/
+
+static void shmem_block_input(struct net_device *dev, int count,
+			      struct sk_buff *skb, int ring_offset)
+{
+    void *xfer_start = (void *)(dev->rmem_start + ring_offset
+				- (ei_status.rx_start_page << 8));
+    char *buf = skb->data;
+    
+    if (xfer_start + count > (void *)dev->rmem_end) {
+	/* We must wrap the input move. */
+	int semi_count = (void*)dev->rmem_end - xfer_start;
+	copyin(buf, xfer_start, semi_count);
+	buf += semi_count;
+	ring_offset = ei_status.rx_start_page << 8;
+	xfer_start = (void *)dev->rmem_start;
+	count -= semi_count;
+    }
+    copyin(buf, xfer_start, count);
+}
+
+/*====================================================================*/
+
+static void shmem_block_output(struct net_device *dev, int count,
+			       const u_char *buf, const int start_page)
+{
+    void *shmem = (void *)dev->mem_start + (start_page << 8);
+    shmem -= ei_status.tx_start_page << 8;
+    copyout(shmem, buf, count);
+}
+
+/*====================================================================*/
+
+static int setup_shmem_window(dev_link_t *link, int start_pg,
+			      int stop_pg, int cm_offset)
+{
+    struct net_device *dev = link->priv;
+    pcnet_dev_t *info = link->priv;
+    win_req_t req;
+    memreq_t mem;
+    int i, window_size, offset, last_ret, last_fn;
+
+    window_size = (stop_pg - start_pg) << 8;
+    if (window_size > 32 * 1024)
+	window_size = 32 * 1024;
+
+    /* Make sure it's a power of two.  */
+    while ((window_size & (window_size - 1)) != 0)
+	window_size += window_size & ~(window_size - 1);
+
+    /* Allocate a memory window */
+    req.Attributes = WIN_DATA_WIDTH_16|WIN_MEMORY_TYPE_CM|WIN_ENABLE;
+    req.Attributes |= WIN_USE_WAIT;
+    req.Base = 0; req.Size = window_size;
+    req.AccessSpeed = mem_speed;
+    link->win = (window_handle_t)link->handle;
+    CS_CHECK(RequestWindow, &link->win, &req);
+
+    mem.CardOffset = (start_pg << 8) + cm_offset;
+    offset = mem.CardOffset % window_size;
+    mem.CardOffset -= offset;
+    mem.Page = 0;
+    CS_CHECK(MapMemPage, link->win, &mem);
+
+    /* Try scribbling on the buffer */
+    info->base = ioremap(req.Base, window_size);
+    for (i = 0; i < (TX_PAGES<<8); i += 2)
+	writew_ns((i>>1), info->base+offset+i);
+    udelay(100);
+    for (i = 0; i < (TX_PAGES<<8); i += 2)
+	if (readw_ns(info->base+offset+i) != (i>>1)) break;
+    pcnet_reset_8390(dev);
+    if (i != (TX_PAGES<<8)) {
+	iounmap(info->base);
+	CardServices(ReleaseWindow, link->win);
+	info->base = NULL; link->win = NULL;
+	goto failed;
+    }
+    
+    dev->mem_start = (u_long)info->base + offset;
+    dev->rmem_start = dev->mem_start + (TX_PAGES<<8);
+    dev->mem_end = dev->rmem_end = (u_long)info->base + req.Size;
+
+    ei_status.tx_start_page = start_pg;
+    ei_status.rx_start_page = start_pg + TX_PAGES;
+    ei_status.stop_page = start_pg + ((req.Size - offset) >> 8);
+
+    /* set up block i/o functions */
+    ei_status.get_8390_hdr = &shmem_get_8390_hdr;
+    ei_status.block_input = &shmem_block_input;
+    ei_status.block_output = &shmem_block_output;
+
+    info->flags |= USE_SHMEM;
+    return 0;
+
+cs_failed:
+    cs_error(link->handle, last_fn, last_ret);
+failed:
+    return 1;
+}
+
+/*====================================================================*/
+
+static int __init init_pcnet_cs(void)
+{
+    servinfo_t serv;
+    DEBUG(0, "%s\n", version);
+    CardServices(GetCardServicesInfo, &serv);
+    if (serv.Revision != CS_RELEASE_CODE) {
+	printk(KERN_NOTICE "pcnet_cs: Card Services release "
+	       "does not match!\n");
+	return -1;
+    }
+    register_pccard_driver(&dev_info, &pcnet_attach, &pcnet_detach);
+    return 0;
+}
+
+static void __exit exit_pcnet_cs(void)
+{
+    DEBUG(0, "pcnet_cs: unloading\n");
+    unregister_pccard_driver(&dev_info);
+    while (dev_list != NULL)
+	pcnet_detach(dev_list);
+}
+
+module_init(init_pcnet_cs);
+module_exit(exit_pcnet_cs);
Index: oldkernel/linux/pcmcia-cs-3.1.15/clients/qlogic_stub.c
diff -u /dev/null linux/pcmcia-cs-3.1.15/clients/qlogic_stub.c:1.1
--- /dev/null	Mon Jul 31 21:15:10 2000
+++ linux/pcmcia-cs-3.1.15/clients/qlogic_stub.c	Fri Jul  7 16:34:58 2000
@@ -0,0 +1,449 @@
+/*======================================================================
+
+    A driver for the Qlogic SCSI card
+
+    qlogic_cs.c 1.78 2000/05/04 01:30:00
+
+    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@pcmcia.sourceforge.org>.  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 <pcmcia/config.h>
+#include <pcmcia/k_compat.h>
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/malloc.h>
+#include <linux/string.h>
+#include <linux/timer.h>
+#include <linux/ioport.h>
+#include <asm/io.h>
+#include <scsi/scsi.h>
+#include <linux/major.h>
+#include <linux/blk.h>
+
+#include <../drivers/scsi/scsi.h>
+#include <../drivers/scsi/hosts.h>
+#include <scsi/scsi_ioctl.h>
+
+#include <../drivers/scsi/qlogicfas.h>
+
+#if (LINUX_VERSION_CODE >= VERSION(2,1,18))
+#define qlogic_reset(h) qlogicfas_reset(h, 0)
+#else
+#if (LINUX_VERSION_CODE < VERSION(2,1,0)) && (LINUX_VERSION_CODE > VERSION(2,0,34))
+#define qlogic_reset(h) qlogicfas_reset(h, 0)
+#else
+#define qlogic_reset qlogicfas_reset
+#endif
+#endif
+
+#include <pcmcia/version.h>
+#include <pcmcia/cs_types.h>
+#include <pcmcia/cs.h>
+#include <pcmcia/cistpl.h>
+#include <pcmcia/ds.h>
+#include <pcmcia/ciscode.h>
+
+extern void qlogicfas_preset(int port, int irq);
+
+#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 =
+"qlogic_cs.c 1.78 2000/05/04 01:30:00 (David Hinds)";
+#else
+#define DEBUG(n, args...)
+#endif
+
+/*====================================================================*/
+
+/* Parameters that can be set with 'insmod' */
+
+/* Bit map of interrupts to choose from */
+static u_int irq_mask = 0xdeb8;
+static int irq_list[4] = { -1 };
+
+MODULE_PARM(irq_mask, "i");
+MODULE_PARM(irq_list, "1-4i");
+
+/*====================================================================*/
+
+typedef struct scsi_info_t {
+    dev_link_t		link;
+    u_short		manf_id;
+    int			ndev;
+    dev_node_t		node[8];
+} scsi_info_t;
+
+static void qlogic_release(u_long arg);
+static int qlogic_event(event_t event, int priority,
+			event_callback_args_t *args);
+
+static dev_link_t *qlogic_attach(void);
+static void qlogic_detach(dev_link_t *);
+
+static Scsi_Host_Template driver_template = QLOGICFAS;
+
+static dev_link_t *dev_list = NULL;
+
+static dev_info_t dev_info = "qlogic_cs";
+
+/*====================================================================*/
+
+static void cs_error(client_handle_t handle, int func, int ret)
+{
+    error_info_t err = { func, ret };
+    CardServices(ReportError, handle, &err);
+}
+
+/*====================================================================*/
+
+static dev_link_t *qlogic_attach(void)
+{
+    scsi_info_t *info;
+    client_reg_t client_reg;
+    dev_link_t *link;
+    int i, ret;
+    
+    DEBUG(0, "qlogic_attach()\n");
+
+    /* Create new SCSI device */
+    info = kmalloc(sizeof(*info), GFP_KERNEL);
+    if (!info) return NULL;
+    memset(info, 0, sizeof(*info));
+    link = &info->link; link->priv = info;
+    link->release.function = &qlogic_release;
+    link->release.data = (u_long)link;
+
+    link->io.NumPorts1 = 16;
+    link->io.Attributes1 = IO_DATA_PATH_WIDTH_AUTO;
+    link->io.IOAddrLines = 10;
+    link->irq.Attributes = IRQ_TYPE_EXCLUSIVE;
+    link->irq.IRQInfo1 = IRQ_INFO2_VALID|IRQ_LEVEL_ID;
+    if (irq_list[0] == -1)
+	link->irq.IRQInfo2 = irq_mask;
+    else
+	for (i = 0; i < 4; i++)
+	    link->irq.IRQInfo2 |= 1 << irq_list[i];
+    link->conf.Attributes = CONF_ENABLE_IRQ;
+    link->conf.Vcc = 50;
+    link->conf.IntType = INT_MEMORY_AND_IO;
+    link->conf.Present = PRESENT_OPTION;
+
+    /* Register with Card Services */
+    link->next = dev_list;
+    dev_list = link;
+    client_reg.dev_info = &dev_info;
+    client_reg.Attributes = INFO_IO_CLIENT | INFO_CARD_SHARE;
+    client_reg.event_handler = &qlogic_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);
+	qlogic_detach(link);
+	return NULL;
+    }
+    
+    return link;
+} /* qlogic_attach */
+
+/*====================================================================*/
+
+static void qlogic_detach(dev_link_t *link)
+{
+    dev_link_t **linkp;
+
+    DEBUG(0, "qlogic_detach(0x%p)\n", link);
+    
+    /* Locate device structure */
+    for (linkp = &dev_list; *linkp; linkp = &(*linkp)->next)
+	if (*linkp == link) break;
+    if (*linkp == NULL)
+	return;
+
+    del_timer(&link->release);
+    if (link->state & DEV_CONFIG) {
+	qlogic_release((u_long)link);
+	if (link->state & DEV_STALE_CONFIG) {
+	    link->state |= DEV_STALE_LINK;
+	    return;
+	}
+    }
+
+    if (link->handle)
+	CardServices(DeregisterClient, link->handle);
+    
+    /* Unlink device structure, free bits */
+    *linkp = link->next;
+    kfree(link->priv);
+    
+} /* qlogic_detach */
+
+/*====================================================================*/
+
+#define CS_CHECK(fn, args...) \
+while ((last_ret=CardServices(last_fn=(fn), args))!=0) goto cs_failed
+
+#define CFG_CHECK(fn, args...) \
+if (CardServices(fn, args) != 0) goto next_entry
+
+static void qlogic_config(dev_link_t *link)
+{
+    client_handle_t handle = link->handle;
+    scsi_info_t *info = link->priv;
+    tuple_t tuple;
+    cisparse_t parse;
+    int i, last_ret, last_fn;
+    u_short tuple_data[32];
+    Scsi_Device *dev;
+    dev_node_t **tail, *node;
+#if (LINUX_VERSION_CODE >= VERSION(2,1,75))
+    struct Scsi_Host *host;
+#endif
+
+    DEBUG(0, "qlogic_config(0x%p)\n", link);
+
+    tuple.TupleData = (cisdata_t *)tuple_data;
+    tuple.TupleDataMax = 64;
+    tuple.TupleOffset = 0;
+    tuple.DesiredTuple = CISTPL_CONFIG;
+    CS_CHECK(GetFirstTuple, handle, &tuple);
+    CS_CHECK(GetTupleData, handle, &tuple);
+    CS_CHECK(ParseTuple, handle, &tuple, &parse);
+    link->conf.ConfigBase = parse.config.base;
+    
+    tuple.DesiredTuple = CISTPL_MANFID;
+    if ((CardServices(GetFirstTuple, handle, &tuple) == CS_SUCCESS) &&
+	(CardServices(GetTupleData, handle, &tuple) == CS_SUCCESS))
+	info->manf_id = le16_to_cpu(tuple.TupleData[0]);
+
+    /* Configure card */
+#if (LINUX_VERSION_CODE >= VERSION(2,1,23))
+    driver_template.module = &__this_module;
+#else
+    driver_template.usage_count = &GET_USE_COUNT(__this_module);
+#endif
+    link->state |= DEV_CONFIG;
+
+    tuple.DesiredTuple = CISTPL_CFTABLE_ENTRY;
+    CS_CHECK(GetFirstTuple, handle, &tuple);
+    while (1) {
+	CFG_CHECK(GetTupleData, handle, &tuple);
+	CFG_CHECK(ParseTuple, handle, &tuple, &parse);
+	link->conf.ConfigIndex = parse.cftable_entry.index;
+	link->io.BasePort1 = parse.cftable_entry.io.win[0].base;
+	link->io.NumPorts1 = parse.cftable_entry.io.win[0].len;
+	if (link->io.BasePort1 != 0) {
+	    i = CardServices(RequestIO, handle, &link->io);
+	    if (i == CS_SUCCESS) break;
+	}
+    next_entry:
+	CS_CHECK(GetNextTuple, handle, &tuple);
+    }
+    
+    CS_CHECK(RequestIRQ, handle, &link->irq);
+    CS_CHECK(RequestConfiguration, handle, &link->conf);
+
+    if ((info->manf_id == MANFID_MACNICA) ||
+	(info->manf_id == MANFID_PIONEER) ||
+	(info->manf_id == 0x0098)) {
+	/* set ATAcmd */
+	outb(0xb4, link->io.BasePort1+0xd);
+	outb(0x24, link->io.BasePort1+0x9);
+	outb(0x04, link->io.BasePort1+0xd);
+    }
+
+    /* A bad hack... */
+    release_region(link->io.BasePort1, link->io.NumPorts1);
+
+    /* The KXL-810AN has a bigger IO port window */
+    if (link->io.NumPorts1 == 32)
+	qlogicfas_preset(link->io.BasePort1+16, link->irq.AssignedIRQ);
+    else
+	qlogicfas_preset(link->io.BasePort1, link->irq.AssignedIRQ);
+    
+    scsi_register_module(MODULE_SCSI_HA, &driver_template);
+
+    tail = &link->dev;
+    info->ndev = 0;
+#if (LINUX_VERSION_CODE < VERSION(2,1,75))
+    for (dev = scsi_devices; dev != NULL; dev = dev->next)
+	if (dev->host->hostt == &driver_template) {
+#else
+    for (host = scsi_hostlist; host; host = host->next)
+	if (host->hostt == &driver_template)
+	    for (dev = host->host_queue; dev; dev = dev->next) {
+#endif
+	    u_long arg[2], id;
+	    kernel_scsi_ioctl(dev, SCSI_IOCTL_GET_IDLUN, arg);
+	    id = (arg[0]&0x0f) + ((arg[0]>>4)&0xf0) +
+		((arg[0]>>8)&0xf00) + ((arg[0]>>12)&0xf000);
+	    node = &info->node[info->ndev];
+	    node->minor = 0;
+	    switch (dev->type) {
+	    case TYPE_TAPE:
+		node->major = SCSI_TAPE_MAJOR;
+		sprintf(node->dev_name, "st#%04lx", id);
+		break;
+	    case TYPE_DISK:
+	    case TYPE_MOD:
+		node->major = SCSI_DISK0_MAJOR;
+		sprintf(node->dev_name, "sd#%04lx", id);
+		break;
+	    case TYPE_ROM:
+	    case TYPE_WORM:
+		node->major = SCSI_CDROM_MAJOR;
+		sprintf(node->dev_name, "sr#%04lx", id);
+		break;
+	    default:
+		node->major = SCSI_GENERIC_MAJOR;
+		sprintf(node->dev_name, "sg#%04lx", id);
+		break;
+	    }
+	    *tail = node; tail = &node->next;
+	    info->ndev++;
+	}
+    *tail = NULL;
+    if (info->ndev == 0)
+	printk(KERN_INFO "qlogic_cs: no SCSI devices found\n");
+    
+    link->state &= ~DEV_CONFIG_PENDING;
+    return;
+
+cs_failed:
+    cs_error(link->handle, last_fn, last_ret);
+    qlogic_release((u_long)link);
+    return;
+
+} /* qlogic_config */
+
+/*====================================================================*/
+
+static void qlogic_release(u_long arg)
+{
+    dev_link_t *link = (dev_link_t *)arg;
+
+    DEBUG(0, "qlogic_release(0x%p)\n", link);
+
+    if (GET_USE_COUNT(&__this_module) != 0) {
+	DEBUG(0, "qlogic_cs: release postponed, device still open\n");
+	link->state |= DEV_STALE_CONFIG;
+	return;
+    }
+
+    scsi_unregister_module(MODULE_SCSI_HA, &driver_template);
+    link->dev = NULL;
+    
+    CardServices(ReleaseConfiguration, link->handle);
+    CardServices(ReleaseIO, link->handle, &link->io);
+    CardServices(ReleaseIRQ, link->handle, &link->irq);
+    
+    link->state &= ~DEV_CONFIG;
+    if (link->state & DEV_STALE_LINK)
+	qlogic_detach(link);
+    
+} /* qlogic_release */
+
+/*====================================================================*/
+
+static int qlogic_event(event_t event, int priority,
+			event_callback_args_t *args)
+{
+    dev_link_t *link = args->client_data;
+
+    DEBUG(1, "qlogic_event(0x%06x)\n", event);
+    
+    switch (event) {
+    case CS_EVENT_CARD_REMOVAL:
+	link->state &= ~DEV_PRESENT;
+	if (link->state & DEV_CONFIG)
+	    mod_timer(&link->release, jiffies + HZ/20);
+	break;
+    case CS_EVENT_CARD_INSERTION:
+	link->state |= DEV_PRESENT | DEV_CONFIG_PENDING;
+	qlogic_config(link);
+	break;
+    case CS_EVENT_PM_SUSPEND:
+	link->state |= DEV_SUSPEND;
+	/* Fall through... */
+    case CS_EVENT_RESET_PHYSICAL:
+	if (link->state & DEV_CONFIG)
+	    CardServices(ReleaseConfiguration, link->handle);
+	break;
+    case CS_EVENT_PM_RESUME:
+	link->state &= ~DEV_SUSPEND;
+	/* Fall through... */
+    case CS_EVENT_CARD_RESET:
+	if (link->state & DEV_CONFIG) {
+	    scsi_info_t *info = link->priv;
+	    CardServices(RequestConfiguration, link->handle, &link->conf);
+	    if ((info->manf_id == MANFID_MACNICA) ||
+		(info->manf_id == MANFID_PIONEER) ||
+		(info->manf_id == 0x0098)) {
+		outb( 0x80, link->io.BasePort1+0xd);
+		outb( 0x24, link->io.BasePort1+0x9);
+		outb( 0x04, link->io.BasePort1+0xd);
+	    }
+	    qlogic_reset(NULL);
+	}
+	break;
+    }
+    return 0;
+} /* qlogic_event */
+
+/*====================================================================*/
+
+static int __init init_qlogic_cs(void) {
+    servinfo_t serv;
+    DEBUG(0, "%s\n", version);
+    CardServices(GetCardServicesInfo, &serv);
+    if (serv.Revision != CS_RELEASE_CODE) {
+	printk(KERN_NOTICE "qlogic_cs: Card Services release "
+	       "does not match!\n");
+	return -1;
+    }
+    register_pccard_driver(&dev_info, &qlogic_attach, &qlogic_detach);
+    return 0;
+}
+
+static void __exit exit_qlogic_cs(void) {
+    DEBUG(0, "qlogic_cs: unloading\n");
+    unregister_pccard_driver(&dev_info);
+    while (dev_list != NULL)
+	qlogic_detach(dev_list);
+}
+
+module_init(init_qlogic_cs);
+module_exit(exit_qlogic_cs);
Index: oldkernel/linux/pcmcia-cs-3.1.15/clients/serial_cb.c
diff -u /dev/null linux/pcmcia-cs-3.1.15/clients/serial_cb.c:1.1
--- /dev/null	Mon Jul 31 21:15:10 2000
+++ linux/pcmcia-cs-3.1.15/clients/serial_cb.c	Fri Jul  7 16:34:58 2000
@@ -0,0 +1,164 @@
+/*======================================================================
+
+    A driver for CardBus serial devices
+
+    serial_cb.c 1.17 2000/05/04 00:24:56
+
+    Copyright 1998, 1999 by Donald Becker and David Hinds
+    
+    This software may be used and distributed according to the terms
+    of the GNU Public License, incorporated herein by reference.
+    All other rights reserved.
+    
+    This driver is an activator for CardBus serial cards, as
+    found on multifunction (e.g. Ethernet and Modem) CardBus cards.
+    
+    Donald Becker may be reached as becker@CESDIS.edu, or C/O
+    USRA Center of Excellence in Space Data and Information Sciences
+    Code 930.5, NASA Goddard Space Flight Center, Greenbelt MD 20771
+    David Hinds may be reached at dhinds@pcmcia.sourceforge.org
+    
+======================================================================*/
+
+#include <pcmcia/config.h>
+#include <pcmcia/k_compat.h>
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/sched.h>
+#include <linux/malloc.h>
+#include <linux/string.h>
+#include <linux/tty.h>
+#include <linux/serial.h>
+#include <linux/major.h>
+#include <linux/pci.h>
+#include <asm/io.h>
+
+#include <pcmcia/driver_ops.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 =
+"serial_cb.c 1.17 2000/05/04 00:24:56 (David Hinds)";
+#else
+#define DEBUG(n, args...)
+#endif
+
+/*======================================================================
+
+    Card-specific configuration hacks
+
+======================================================================*/
+
+static void device_setup(struct pci_dev *pdev, u_int ioaddr)
+{
+    u_short a, b;
+
+    pci_read_config_word(pdev, PCI_SUBSYSTEM_VENDOR_ID, &a);
+    pci_read_config_word(pdev, PCI_SUBSYSTEM_ID, &b);
+    if (((a == 0x13a2) && (b == 0x8007)) ||
+	((a == 0x1420) && (b == 0x8003))) {
+	/* Ositech, Psion 83c175-based cards */
+	DEBUG(0, "  83c175 NVCTL_m = 0x%4.4x.\n", inl(ioaddr+0x80));
+	outl(0x4C00, ioaddr + 0x80);
+	outl(0x4C80, ioaddr + 0x80);
+    }
+    DEBUG(0, "  modem registers are %2.2x %2.2x %2.2x "
+	  "%2.2x %2.2x %2.2x %2.2x %2.2x  %2.2x.\n",
+	  inb(ioaddr + 0), inb(ioaddr + 1), inb(ioaddr + 2),
+	  inb(ioaddr + 3), inb(ioaddr + 4), inb(ioaddr + 5),
+	  inb(ioaddr + 6), inb(ioaddr + 7), inb(ioaddr + 8));
+}
+
+/*======================================================================
+
+    serial_attach() creates a serial device "instance" and registers
+    it with the kernel serial driver, and serial_detach() unregisters
+    an instance.
+
+======================================================================*/
+
+static dev_node_t *serial_attach(dev_locator_t *loc)
+{
+    u_int io;
+    u_char bus, devfn, irq;
+    int line;
+    struct serial_struct serial;
+    struct pci_dev *pdev;
+    dev_node_t *node = kmalloc(sizeof(dev_node_t), GFP_KERNEL);
+
+    MOD_INC_USE_COUNT;
+    if (loc->bus != LOC_PCI)
+	goto fail;
+    bus = loc->b.pci.bus; devfn = loc->b.pci.devfn;
+    pdev = pci_find_slot(bus, devfn);
+    printk(KERN_INFO "serial_attach(device %02x:%02x.%d)\n",
+	   bus, PCI_SLOT(devfn), PCI_FUNC(devfn));
+    pci_read_config_dword(pdev, PCI_BASE_ADDRESS_0, &io);
+    pci_read_config_byte(pdev, PCI_INTERRUPT_LINE, &irq);
+    if (!(io & PCI_BASE_ADDRESS_SPACE_IO)) {
+	printk(KERN_NOTICE "serial_cb: PCI base address 0 is not IO\n");
+	goto fail;
+    }
+    io &= PCI_BASE_ADDRESS_IO_MASK;
+    device_setup(pdev, io);
+    memset(&serial, 0, sizeof(serial));
+    serial.port = io; serial.irq = irq;
+    serial.flags = ASYNC_SKIP_TEST | ASYNC_SHARE_IRQ;
+
+    /* Some devices seem to need extra time */
+    __set_current_state(TASK_UNINTERRUPTIBLE);
+    schedule_timeout(HZ/50);
+
+    line = register_serial(&serial);
+    if (line < 0) {
+	printk(KERN_NOTICE "serial_cb: register_serial() at 0x%04x, "
+	       "irq %d failed\n", serial.port, serial.irq);
+	goto fail;
+    }
+    node = kmalloc(sizeof(dev_node_t), GFP_KERNEL);
+    if (!node) goto fail_alloc;
+    sprintf(node->dev_name, "ttyS%d", line);
+    node->major = TTY_MAJOR; node->minor = 0x40 + line;
+    node->next = NULL;
+    return node;
+
+fail_alloc:
+    unregister_serial(line);
+fail:
+    MOD_DEC_USE_COUNT;
+    return NULL;
+}
+
+static void serial_detach(dev_node_t *node)
+{
+    DEBUG(0, "serial_detach(ttyS%02d)\n", node->minor - 0x40);
+    unregister_serial(node->minor - 0x40);
+    kfree(node);
+    MOD_DEC_USE_COUNT;
+}
+
+/*====================================================================*/
+
+struct driver_operations serial_ops = {
+    "serial_cb", serial_attach, NULL, NULL, serial_detach
+};
+
+static int __init init_serial_cb(void)
+{
+    DEBUG(0, "%s\n", version);
+    register_driver(&serial_ops);
+    return 0;
+}
+
+static void __exit exit_serial_cb(void)
+{
+    DEBUG(0, "serial_cb: unloading\n");
+    unregister_driver(&serial_ops);
+}
+
+module_init(init_serial_cb);
+module_exit(exit_serial_cb);
Index: oldkernel/linux/pcmcia-cs-3.1.15/clients/serial_cs.c
diff -u /dev/null linux/pcmcia-cs-3.1.15/clients/serial_cs.c:1.1
--- /dev/null	Mon Jul 31 21:15:10 2000
+++ linux/pcmcia-cs-3.1.15/clients/serial_cs.c	Fri Jul  7 16:34:58 2000
@@ -0,0 +1,658 @@
+/*======================================================================
+
+    A driver for PCMCIA serial devices
+
+    serial_cs.c 1.118 2000/05/04 01:29: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@pcmcia.sourceforge.org>.  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 <pcmcia/config.h>
+#include <pcmcia/k_compat.h>
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/sched.h>
+#include <linux/ptrace.h>
+#include <linux/malloc.h>
+#include <linux/string.h>
+#include <linux/timer.h>
+#include <linux/tty.h>
+#include <linux/serial.h>
+#include <linux/major.h>
+#include <asm/io.h>
+#include <asm/system.h>
+
+#include <pcmcia/version.h>
+#include <pcmcia/cs_types.h>
+#include <pcmcia/cs.h>
+#include <pcmcia/cistpl.h>
+#include <pcmcia/ciscode.h>
+#include <pcmcia/ds.h>
+#include <pcmcia/cisreg.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 =
+"serial_cs.c 1.118 2000/05/04 01:29:47 (David Hinds)";
+#else
+#define DEBUG(n, args...)
+#endif
+
+/*====================================================================*/
+
+/* Parameters that can be set with 'insmod' */
+
+/* Bit map of interrupts to choose from */
+static u_int irq_mask = 0xdeb8;
+static int irq_list[4] = { -1 };
+
+/* Enable the speaker? */
+static int do_sound = 1;
+
+MODULE_PARM(irq_mask, "i");
+MODULE_PARM(irq_list, "1-4i");
+MODULE_PARM(do_sound, "i");
+
+/*====================================================================*/
+
+/* Table of multi-port card ID's */
+
+typedef struct {
+    u_short	manfid;
+    u_short	prodid;
+    int		multi;		/* 1 = multifunction, > 1 = # ports */
+} multi_id_t;
+
+static multi_id_t multi_id[] = {
+    { MANFID_OMEGA, PRODID_OMEGA_QSP_100, 4 },
+    { MANFID_QUATECH, PRODID_QUATECH_DUAL_RS232, 2 },
+    { MANFID_QUATECH, PRODID_QUATECH_DUAL_RS232_D1, 2 },
+    { MANFID_QUATECH, PRODID_QUATECH_QUAD_RS232, 4 },
+    { MANFID_SOCKET, PRODID_SOCKET_DUAL_RS232, 2 },
+    { MANFID_INTEL, PRODID_INTEL_DUAL_RS232, 2 },
+    { MANFID_NATINST, PRODID_NATINST_QUAD_RS232, 4 }
+};
+#define MULTI_COUNT (sizeof(multi_id)/sizeof(multi_id_t))
+
+typedef struct serial_info_t {
+    dev_link_t	link;
+    int		ndev;
+    int		multi;
+    int		slave;
+    int		manfid;
+    dev_node_t	node[4];
+    int		line[4];
+} serial_info_t;
+
+static void serial_config(dev_link_t *link);
+static void serial_release(u_long arg);
+static int serial_event(event_t event, int priority,
+			event_callback_args_t *args);
+
+static dev_info_t dev_info = "serial_cs";
+
+static dev_link_t *serial_attach(void);
+static void serial_detach(dev_link_t *);
+
+static dev_link_t *dev_list = NULL;
+
+/*====================================================================*/
+
+static void cs_error(client_handle_t handle, int func, int ret)
+{
+    error_info_t err = { func, ret };
+    CardServices(ReportError, handle, &err);
+}
+
+/*======================================================================
+
+    serial_attach() creates an "instance" of the driver, allocating
+    local data structures for one device.  The device is registered
+    with Card Services.
+
+======================================================================*/
+
+static dev_link_t *serial_attach(void)
+{
+    serial_info_t *info;
+    client_reg_t client_reg;
+    dev_link_t *link;
+    int i, ret;
+    
+    DEBUG(0, "serial_attach()\n");
+
+    /* Create new serial device */
+    info = kmalloc(sizeof(*info), GFP_KERNEL);
+    if (!info) return NULL;
+    memset(info, 0, sizeof(*info));
+    link = &info->link; link->priv = info;
+
+    link->release.function = &serial_release;
+    link->release.data = (u_long)link;
+    link->io.Attributes1 = IO_DATA_PATH_WIDTH_8;
+    link->io.NumPorts1 = 8;
+    link->irq.Attributes = IRQ_TYPE_EXCLUSIVE;
+    link->irq.IRQInfo1 = IRQ_INFO2_VALID|IRQ_LEVEL_ID;
+    if (irq_list[0] == -1)
+	link->irq.IRQInfo2 = irq_mask;
+    else
+	for (i = 0; i < 4; i++)
+	    link->irq.IRQInfo2 |= 1 << irq_list[i];
+    link->conf.Attributes = CONF_ENABLE_IRQ;
+    link->conf.Vcc = 50;
+    if (do_sound) {
+	link->conf.Attributes |= CONF_ENABLE_SPKR;
+	link->conf.Status = CCSR_AUDIO_ENA;
+    }
+    link->conf.IntType = INT_MEMORY_AND_IO;
+    
+    /* Register with Card Services */
+    link->next = dev_list;
+    dev_list = link;
+    client_reg.dev_info = &dev_info;
+    client_reg.Attributes = INFO_IO_CLIENT | INFO_CARD_SHARE;
+    client_reg.EventMask =
+	CS_EVENT_CARD_INSERTION | CS_EVENT_CARD_REMOVAL |
+	CS_EVENT_RESET_PHYSICAL | CS_EVENT_CARD_RESET |
+	CS_EVENT_PM_SUSPEND | CS_EVENT_PM_RESUME;
+    client_reg.event_handler = &serial_event;
+    client_reg.Version = 0x0210;
+    client_reg.event_callback_args.client_data = link;
+    ret = CardServices(RegisterClient, &link->handle, &client_reg);
+    if (ret != CS_SUCCESS) {
+	cs_error(link->handle, RegisterClient, ret);
+	serial_detach(link);
+	return NULL;
+    }
+    
+    return link;
+} /* serial_attach */
+
+/*======================================================================
+
+    This deletes a driver "instance".  The device is de-registered
+    with Card Services.  If it has been released, all local data
+    structures are freed.  Otherwise, the structures will be freed
+    when the device is released.
+
+======================================================================*/
+
+static void serial_detach(dev_link_t *link)
+{
+    serial_info_t *info = link->priv;
+    dev_link_t **linkp;
+    int ret;
+
+    DEBUG(0, "serial_detach(0x%p)\n", link);
+    
+    /* Locate device structure */
+    for (linkp = &dev_list; *linkp; linkp = &(*linkp)->next)
+	if (*linkp == link) break;
+    if (*linkp == NULL)
+	return;
+
+    del_timer(&link->release);
+    if (link->state & DEV_CONFIG)
+	serial_release((u_long)link);
+    
+    if (link->handle) {
+	ret = CardServices(DeregisterClient, link->handle);
+	if (ret != CS_SUCCESS)
+	    cs_error(link->handle, DeregisterClient, ret);
+    }
+    
+    /* Unlink device structure, free bits */
+    *linkp = link->next;
+    kfree(info);
+    
+} /* serial_detach */
+
+/*====================================================================*/
+
+static int setup_serial(serial_info_t *info, ioaddr_t port, int irq)
+{
+    struct serial_struct serial;
+    int line;
+    
+    memset(&serial, 0, sizeof(serial));
+    serial.port = port;
+    serial.irq = irq;
+    serial.flags = ASYNC_SKIP_TEST;
+    serial.flags |= (info->multi || info->slave) ? ASYNC_SHARE_IRQ : 0;
+    line = register_serial(&serial);
+    if (line < 0) {
+	printk(KERN_NOTICE "serial_cs: register_serial() at 0x%04x, "
+	       "irq %d failed\n", serial.port, serial.irq);
+	return -1;
+    }
+    
+    info->line[info->ndev] = line;
+    sprintf(info->node[info->ndev].dev_name, "ttyS%d", line);
+    info->node[info->ndev].major = TTY_MAJOR;
+    info->node[info->ndev].minor = 0x40+line;
+    if (info->ndev > 0)
+	info->node[info->ndev-1].next = &info->node[info->ndev];
+    info->ndev++;
+    
+    return 0;
+}
+
+/*====================================================================*/
+
+static int get_tuple(int fn, client_handle_t handle, tuple_t *tuple,
+		     cisparse_t *parse)
+{
+    int i;
+    i = CardServices(fn, handle, tuple);
+    if (i != CS_SUCCESS) return CS_NO_MORE_ITEMS;
+    i = CardServices(GetTupleData, handle, tuple);
+    if (i != CS_SUCCESS) return i;
+    return CardServices(ParseTuple, handle, tuple, parse);
+}
+
+#define first_tuple(a, b, c) get_tuple(GetFirstTuple, a, b, c)
+#define next_tuple(a, b, c) get_tuple(GetNextTuple, a, b, c)
+
+/*====================================================================*/
+
+static int simple_config(dev_link_t *link)
+{
+    static ioaddr_t base[5] = { 0x3f8, 0x2f8, 0x3e8, 0x2e8, 0x0 };
+    client_handle_t handle = link->handle;
+    serial_info_t *info = link->priv;
+    tuple_t tuple;
+    u_char buf[256];
+    cisparse_t parse;
+    cistpl_cftable_entry_t *cf = &parse.cftable_entry;
+    config_info_t config;
+    int i, j;
+
+    /* If the card is already configured, look up the port and irq */
+    i = CardServices(GetConfigurationInfo, handle, &config);
+    if ((i == CS_SUCCESS) &&
+	(config.Attributes & CONF_VALID_CLIENT)) {
+	ioaddr_t port = 0;
+	if ((config.BasePort2 != 0) && (config.NumPorts2 == 8)) {
+	    port = config.BasePort2;
+	    info->slave = 1;
+	} else if ((info->manfid == MANFID_OSITECH) &&
+		   (config.NumPorts1 == 0x40)) {
+	    port = config.BasePort1 + 0x28;
+	    info->slave = 1;
+	}
+	if (info->slave)
+	    return setup_serial(info, port, config.AssignedIRQ);
+    }
+    link->conf.Vcc = config.Vcc;
+    
+    /* First pass: look for a config entry that looks normal. */
+    tuple.TupleData = (cisdata_t *)buf;
+    tuple.TupleOffset = 0; tuple.TupleDataMax = 255;
+    tuple.Attributes = 0;
+    tuple.DesiredTuple = CISTPL_CFTABLE_ENTRY;
+    i = first_tuple(handle, &tuple, &parse);
+    while (i != CS_NO_MORE_ITEMS) {
+	if (i != CS_SUCCESS) goto next_entry;
+	if (cf->vpp1.present & (1<<CISTPL_POWER_VNOM))
+	    link->conf.Vpp1 = link->conf.Vpp2 =
+		cf->vpp1.param[CISTPL_POWER_VNOM]/10000;
+	if ((cf->io.nwin > 0) && (cf->io.win[0].len == 8) &&
+	    (cf->io.win[0].base != 0)) {
+	    link->conf.ConfigIndex = cf->index;
+	    link->io.BasePort1 = cf->io.win[0].base;
+	    link->io.IOAddrLines = cf->io.flags & CISTPL_IO_LINES_MASK;
+	    i = CardServices(RequestIO, link->handle, &link->io);
+	    if (i == CS_SUCCESS) goto found_port;
+	}
+    next_entry:
+	i = next_tuple(handle, &tuple, &parse);
+    }
+    
+    /* Second pass: try to find an entry that isn't picky about
+       its base address, then try to grab any standard serial port
+       address, and finally try to get any free port. */
+    i = first_tuple(handle, &tuple, &parse);
+    while (i != CS_NO_MORE_ITEMS) {
+	if ((i == CS_SUCCESS) && (cf->io.nwin > 0) &&
+	    ((cf->io.flags & CISTPL_IO_LINES_MASK) <= 3)) {
+	    link->conf.ConfigIndex = cf->index;
+	    for (j = 0; j < 5; j++) {
+		link->io.BasePort1 = base[j];
+		link->io.IOAddrLines = base[j] ? 16 : 3;
+		i = CardServices(RequestIO, link->handle,
+				 &link->io);
+		if (i == CS_SUCCESS) goto found_port;
+	    }
+	}
+	i = next_tuple(handle, &tuple, &parse);
+    }
+
+found_port:
+    if (i != CS_SUCCESS) {
+	cs_error(link->handle, RequestIO, i);
+	return -1;
+    }
+    
+    i = CardServices(RequestIRQ, link->handle, &link->irq);
+    if (i != CS_SUCCESS) {
+	cs_error(link->handle, RequestIRQ, i);
+	link->irq.AssignedIRQ = 0;
+    }
+    if (info->multi && (info->manfid == MANFID_3COM))
+	link->conf.ConfigIndex &= ~(0x08);
+    i = CardServices(RequestConfiguration, link->handle, &link->conf);
+    if (i != CS_SUCCESS) {
+	cs_error(link->handle, RequestConfiguration, i);
+	return -1;
+    }
+
+    return setup_serial(info, link->io.BasePort1, link->irq.AssignedIRQ);
+}
+
+static int multi_config(dev_link_t *link)
+{
+    client_handle_t handle = link->handle;
+    serial_info_t *info = link->priv;
+    tuple_t tuple;
+    u_char buf[256];
+    cisparse_t parse;
+    cistpl_cftable_entry_t *cf = &parse.cftable_entry;
+    int i, base2 = 0;
+
+    tuple.TupleData = (cisdata_t *)buf;
+    tuple.TupleOffset = 0; tuple.TupleDataMax = 255;
+    tuple.Attributes = 0;
+    tuple.DesiredTuple = CISTPL_CFTABLE_ENTRY;
+
+    /* First, look for a generic full-sized window */
+    link->io.NumPorts1 = info->multi * 8;
+    i = first_tuple(handle, &tuple, &parse);
+    while (i != CS_NO_MORE_ITEMS) {
+	/* The quad port cards have bad CIS's, so just look for a
+	   window larger than 8 ports and assume it will be right */
+	if ((i == CS_SUCCESS) && (cf->io.nwin == 1) &&
+	    (cf->io.win[0].len > 8)) {
+	    link->conf.ConfigIndex = cf->index;
+	    link->io.BasePort1 = cf->io.win[0].base;
+	    link->io.IOAddrLines = cf->io.flags & CISTPL_IO_LINES_MASK;
+	    i = CardServices(RequestIO, link->handle, &link->io);
+	    base2 = link->io.BasePort1 + 8;
+	    if (i == CS_SUCCESS) break;
+	}
+	i = next_tuple(handle, &tuple, &parse);
+    }
+
+    /* If that didn't work, look for two windows */
+    if (i != CS_SUCCESS) {
+	link->io.NumPorts1 = link->io.NumPorts2 = 8;
+	info->multi = 2;
+	i = first_tuple(handle, &tuple, &parse);
+	while (i != CS_NO_MORE_ITEMS) {
+	    if ((i == CS_SUCCESS) && (cf->io.nwin == 2)) {
+		link->conf.ConfigIndex = cf->index;
+		link->io.BasePort1 = cf->io.win[0].base;
+		link->io.BasePort2 = cf->io.win[1].base;
+		link->io.IOAddrLines = cf->io.flags & CISTPL_IO_LINES_MASK;
+		i = CardServices(RequestIO, link->handle, &link->io);
+		base2 = link->io.BasePort2;
+		if (i == CS_SUCCESS) break;
+	    }
+	    i = next_tuple(handle, &tuple, &parse);
+	}
+    }
+    
+    if (i != CS_SUCCESS) {
+	cs_error(link->handle, RequestIO, i);
+	return -1;
+    }
+    
+    i = CardServices(RequestIRQ, link->handle, &link->irq);
+    if (i != CS_SUCCESS) {
+	cs_error(link->handle, RequestIRQ, i);
+	link->irq.AssignedIRQ = 0;
+    }
+    /* Socket Dual IO: this enables irq's for second port */
+    if (info->multi && (info->manfid == MANFID_SOCKET)) {
+	link->conf.Present |= PRESENT_EXT_STATUS;
+	link->conf.ExtStatus = ESR_REQ_ATTN_ENA;
+    }
+    i = CardServices(RequestConfiguration, link->handle, &link->conf);
+    if (i != CS_SUCCESS) {
+	cs_error(link->handle, RequestConfiguration, i);
+	return -1;
+    }
+    
+    setup_serial(info, link->io.BasePort1, link->irq.AssignedIRQ);
+    for (i = 0; i < info->multi-1; i++)
+	setup_serial(info, base2+(8*i), link->irq.AssignedIRQ);
+    
+    return 0;
+}
+
+/*======================================================================
+
+    serial_config() is scheduled to run after a CARD_INSERTION event
+    is received, to configure the PCMCIA socket, and to make the
+    serial device available to the system.
+
+======================================================================*/
+
+#define CS_CHECK(fn, args...) \
+while ((last_ret=CardServices(last_fn=(fn), args))!=0) goto cs_failed
+
+void serial_config(dev_link_t *link)
+{
+    client_handle_t handle = link->handle;
+    serial_info_t *info = link->priv;
+    tuple_t tuple;
+    u_short buf[128];
+    cisparse_t parse;
+    cistpl_cftable_entry_t *cf = &parse.cftable_entry;
+    int i, last_ret, last_fn;
+
+    DEBUG(0, "serial_config(0x%p)\n", link);
+    
+    tuple.TupleData = (cisdata_t *)buf;
+    tuple.TupleOffset = 0; tuple.TupleDataMax = 255;
+    tuple.Attributes = 0;
+    /* Get configuration register information */
+    tuple.DesiredTuple = CISTPL_CONFIG;
+    last_ret = first_tuple(handle, &tuple, &parse);
+    if (last_ret != CS_SUCCESS) {
+	last_fn = ParseTuple;
+	goto cs_failed;
+    }
+    link->conf.ConfigBase = parse.config.base;
+    link->conf.Present = parse.config.rmask[0];
+    
+    /* Configure card */
+    link->state |= DEV_CONFIG;
+
+    /* Is this a compliant multifunction card? */
+    tuple.DesiredTuple = CISTPL_LONGLINK_MFC;
+    tuple.Attributes = TUPLE_RETURN_COMMON | TUPLE_RETURN_LINK;
+    info->multi = (first_tuple(handle, &tuple, &parse) == CS_SUCCESS);
+    
+    /* Is this a multiport card? */
+    tuple.DesiredTuple = CISTPL_MANFID;
+    if (first_tuple(handle, &tuple, &parse) == CS_SUCCESS) {
+	info->manfid = le16_to_cpu(buf[0]);
+	for (i = 0; i < MULTI_COUNT; i++)
+	    if ((info->manfid == multi_id[i].manfid) &&
+		(le16_to_cpu(buf[1]) == multi_id[i].prodid))
+		break;
+	if (i < MULTI_COUNT)
+	    info->multi = multi_id[i].multi;
+    }
+
+    /* Another check for dual-serial cards: look for either serial or
+       multifunction cards that ask for appropriate IO port ranges */
+    tuple.DesiredTuple = CISTPL_FUNCID;
+    if ((info->multi == 0) &&
+	((first_tuple(handle, &tuple, &parse) != CS_SUCCESS) ||
+	 (parse.funcid.func == CISTPL_FUNCID_MULTI) ||
+	 (parse.funcid.func == CISTPL_FUNCID_SERIAL))) {
+	tuple.DesiredTuple = CISTPL_CFTABLE_ENTRY;
+	if ((first_tuple(handle, &tuple, &parse) == CS_SUCCESS) &&
+	    (((cf->io.nwin == 1) && (cf->io.win[0].len == 16)) ||
+	     ((cf->io.nwin == 2) && (cf->io.win[0].len == 8) &&
+	      (cf->io.win[1].len == 8))))
+	    info->multi = 2;
+    }
+    
+    if (info->multi > 1)
+	multi_config(link);
+    else
+	simple_config(link);
+    
+    if (info->ndev == 0)
+	goto failed;
+    
+    if (info->manfid == MANFID_IBM) {
+	conf_reg_t reg = { 0, CS_READ, 0x800, 0 };
+	CS_CHECK(AccessConfigurationRegister, link->handle, &reg);
+	reg.Action = CS_WRITE;
+	reg.Value = reg.Value | 1;
+	CS_CHECK(AccessConfigurationRegister, link->handle, &reg);
+    }
+
+    link->dev = &info->node[0];
+    link->state &= ~DEV_CONFIG_PENDING;
+    return;
+
+cs_failed:
+    cs_error(link->handle, last_fn, last_ret);
+failed:
+    serial_release((u_long)link);
+
+} /* serial_config */
+
+/*======================================================================
+
+    After a card is removed, serial_release() will unregister the net
+    device, and release the PCMCIA configuration.
+    
+======================================================================*/
+
+void serial_release(u_long arg)
+{
+    dev_link_t *link = (dev_link_t *)arg;
+    serial_info_t *info = link->priv;
+    int i;
+    
+    DEBUG(0, "serial_release(0x%p)\n", link);
+
+    for (i = 0; i < info->ndev; i++) {
+	unregister_serial(info->line[i]);
+    }
+    link->dev = NULL;
+
+    if (!info->slave) {
+	CardServices(ReleaseConfiguration, link->handle);
+	CardServices(ReleaseIO, link->handle, &link->io);
+	CardServices(ReleaseIRQ, link->handle, &link->irq);
+    }
+    
+    link->state &= ~DEV_CONFIG;
+
+} /* serial_release */
+
+/*======================================================================
+
+    The card status event handler.  Mostly, this schedules other
+    stuff to run after an event is received.  A CARD_REMOVAL event
+    also sets some flags to discourage the serial drivers from
+    talking to the ports.
+    
+======================================================================*/
+
+static int serial_event(event_t event, int priority,
+			event_callback_args_t *args)
+{
+    dev_link_t *link = args->client_data;
+    serial_info_t *info = link->priv;
+    
+    DEBUG(1, "serial_event(0x%06x)\n", event);
+    
+    switch (event) {
+    case CS_EVENT_CARD_REMOVAL:
+	link->state &= ~DEV_PRESENT;
+	if (link->state & DEV_CONFIG)
+	    mod_timer(&link->release, jiffies + HZ/20);
+	break;
+    case CS_EVENT_CARD_INSERTION:
+	link->state |= DEV_PRESENT | DEV_CONFIG_PENDING;
+	serial_config(link);
+	break;
+    case CS_EVENT_PM_SUSPEND:
+	link->state |= DEV_SUSPEND;
+	/* Fall through... */
+    case CS_EVENT_RESET_PHYSICAL:
+	if ((link->state & DEV_CONFIG) && !info->slave)
+	    CardServices(ReleaseConfiguration, link->handle);
+	break;
+    case CS_EVENT_PM_RESUME:
+	link->state &= ~DEV_SUSPEND;
+	/* Fall through... */
+    case CS_EVENT_CARD_RESET:
+	if (DEV_OK(link) && !info->slave)
+	    CardServices(RequestConfiguration, link->handle, &link->conf);
+	break;
+    }
+    return 0;
+} /* serial_event */
+
+/*====================================================================*/
+
+static int __init init_serial_cs(void)
+{
+    servinfo_t serv;
+    DEBUG(0, "%s\n", version);
+    CardServices(GetCardServicesInfo, &serv);
+    if (serv.Revision != CS_RELEASE_CODE) {
+	printk(KERN_NOTICE "serial_cs: Card Services release "
+	       "does not match!\n");
+	return -1;
+    }
+    register_pccard_driver(&dev_info, &serial_attach, &serial_detach);
+    return 0;
+}
+
+static void __exit exit_serial_cs(void)
+{
+    DEBUG(0, "serial_cs: unloading\n");
+    unregister_pccard_driver(&dev_info);
+    while (dev_list != NULL)
+	serial_detach(dev_list);
+}
+
+module_init(init_serial_cs);
+module_exit(exit_serial_cs);
Index: oldkernel/linux/pcmcia-cs-3.1.15/clients/smc91c92_cs.c
diff -u /dev/null linux/pcmcia-cs-3.1.15/clients/smc91c92_cs.c:1.1
--- /dev/null	Mon Jul 31 21:15:10 2000
+++ linux/pcmcia-cs-3.1.15/clients/smc91c92_cs.c	Fri Jul  7 16:34:58 2000
@@ -0,0 +1,1958 @@
+/*======================================================================
+
+    A PCMCIA ethernet driver for SMC91c92-based cards.
+
+    This driver supports Megahertz PCMCIA ethernet cards; and
+    Megahertz, Motorola, Ositech, and Psion Dacom ethernet/modem
+    multifunction cards.
+
+    Copyright (C) 1999 David A. Hinds -- dhinds@pcmcia.sourceforge.org
+
+    smc91c92_cs.c 1.96 2000/05/09 02:35:58
+    
+    This driver contains code written by Donald Becker
+    (becker@cesdis.gsfc.nasa.gov), Rowan Hughes (x-csrdh@jcu.edu.au),
+    David Hinds (dhinds@pcmcia.sourceforge.org), and Erik Stahlman
+    (erik@vt.edu).  Donald wrote the SMC 91c92 code using parts of
+    Erik's SMC 91c94 driver.  Rowan wrote a similar driver, and I've
+    incorporated some parts of his driver here.  I (Dave) wrote most
+    of the PCMCIA glue code, and the Ositech support code.  Kelly
+    Stephens (kstephen@holli.com) added support for the Motorola
+    Mariner, with help from Allen Brost. 
+
+    This software may be used and distributed according to the terms of
+    the GNU Public License, incorporated herein by reference.
+
+======================================================================*/
+
+#include <pcmcia/config.h>
+#include <pcmcia/k_compat.h>
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/sched.h>
+#include <linux/malloc.h>
+#include <linux/string.h>
+#include <linux/timer.h>
+#include <linux/interrupt.h>
+#include <linux/delay.h>
+#include <asm/io.h>
+#include <asm/system.h>
+
+#include <linux/netdevice.h>
+#include <linux/etherdevice.h>
+#include <linux/skbuff.h>
+#include <linux/if_arp.h>
+#include <linux/ioport.h>
+
+#include <pcmcia/version.h>
+#include <pcmcia/cs_types.h>
+#include <pcmcia/cs.h>
+#include <pcmcia/cistpl.h>
+#include <pcmcia/cisreg.h>
+#include <pcmcia/ciscode.h>
+#include <pcmcia/ds.h>
+
+/* Ositech Seven of Diamonds firmware */
+#include "ositech.h"
+
+/*====================================================================*/
+
+#ifdef PCMCIA_DEBUG
+static int pc_debug = PCMCIA_DEBUG;
+MODULE_PARM(pc_debug, "i");
+static const char *version =
+"smc91c92_cs.c 0.09 1996/8/4 Donald Becker, becker@cesdis.gsfc.nasa.gov.\n";
+#define DEBUG(n, args...) if (pc_debug>(n)) printk(KERN_DEBUG args)
+#else
+#define DEBUG(n, args...)
+#endif
+
+static char *if_names[] = { "auto", "10baseT", "10base2"};
+
+/* Parameters that can be set with 'insmod' */
+
+/*
+  Transceiver/media type.
+   0 = auto
+   1 = 10baseT (and autoselect if #define AUTOSELECT),
+   2 = AUI/10base2,
+*/
+static int if_port = 0;
+
+/* Bit map of interrupts to choose from. */
+static u_int irq_mask = 0xdeb8;
+static int irq_list[4] = { -1 };
+
+MODULE_PARM(if_port, "i");
+MODULE_PARM(irq_mask, "i");
+MODULE_PARM(irq_list, "1-4i");
+
+/* Operational parameter that usually are not changed. */
+
+/* Time in jiffies before concluding Tx hung */
+#define TX_TIMEOUT		((400*HZ)/1000)
+
+/* Maximum events (Rx packets, etc.) to handle at each interrupt. */
+#define INTR_WORK		4
+
+/* Times to check the check the chip before concluding that it doesn't
+   currently have room for another Tx packet. */
+#define MEMORY_WAIT_TIME       	8
+
+static dev_info_t dev_info = "smc91c92_cs";
+
+static dev_link_t *dev_list = NULL;
+
+struct smc_private {
+    dev_link_t			link;
+    struct net_device		dev;
+    u_short			manfid;
+    u_short			cardid;
+    struct net_device_stats	stats;
+    dev_node_t			node;
+    struct sk_buff		*saved_skb;
+    int				packets_waiting;
+    caddr_t			base;
+    u_short			cfg;
+    struct timer_list		media;
+    int				watchdog, tx_err;
+    u_short			media_status;
+    u_short			fast_poll;
+    u_long			last_rx;
+};
+
+/* Special definitions for Megahertz multifunction cards */
+#define MEGAHERTZ_ISR		0x0380
+
+/* Special function registers for Motorola Mariner */
+#define MOT_LAN			0x0000
+#define MOT_UART		0x0020
+#define MOT_EEPROM		0x20
+
+#define MOT_NORMAL \
+(COR_LEVEL_REQ | COR_FUNC_ENA | COR_ADDR_DECODE | COR_IREQ_ENA)
+
+/* Special function registers for Ositech cards */
+#define OSITECH_AUI_CTL		0x0c
+#define OSITECH_PWRDOWN		0x0d
+#define OSITECH_RESET		0x0e
+#define OSITECH_ISR		0x0f
+#define OSITECH_AUI_PWR		0x0c
+#define OSITECH_RESET_ISR	0x0e
+
+#define OSI_AUI_PWR		0x40
+#define OSI_LAN_PWRDOWN		0x02
+#define OSI_MODEM_PWRDOWN	0x01
+#define OSI_LAN_RESET		0x02
+#define OSI_MODEM_RESET		0x01
+
+/* Symbolic constants for the SMC91c9* series chips, from Erik Stahlman. */
+#define	BANK_SELECT		14		/* Window select register. */
+#define SMC_SELECT_BANK(x)  { outw(x, ioaddr + BANK_SELECT); }
+
+/* Bank 0 registers. */
+#define	TCR 		0	/* transmit control register */
+#define	 TCR_CLEAR	0	/* do NOTHING */
+#define  TCR_ENABLE	0x0001	/* if this is 1, we can transmit */
+#define	 TCR_PAD_EN	0x0080	/* pads short packets to 64 bytes */
+#define  TCR_MONCSN	0x0400  /* Monitor Carrier. */
+#define  TCR_FDUPLX	0x0800  /* Full duplex mode. */
+#define	 TCR_NORMAL TCR_ENABLE | TCR_PAD_EN
+
+#define EPH		2	/* Ethernet Protocol Handler report. */
+#define  EPH_TX_SUC	0x0001
+#define  EPH_SNGLCOL	0x0002
+#define  EPH_MULCOL	0x0004
+#define  EPH_LTX_MULT	0x0008
+#define  EPH_16COL	0x0010
+#define  EPH_SQET	0x0020
+#define  EPH_LTX_BRD	0x0040
+#define  EPH_TX_DEFR	0x0080
+#define  EPH_LAT_COL	0x0200
+#define  EPH_LOST_CAR	0x0400
+#define  EPH_EXC_DEF	0x0800
+#define  EPH_CTR_ROL	0x1000
+#define  EPH_RX_OVRN	0x2000
+#define  EPH_LINK_OK	0x4000
+#define  EPH_TX_UNRN	0x8000
+#define MEMINFO		8	/* Memory Information Register */
+#define MEMCFG		10	/* Memory Configuration Register */
+
+/* Bank 1 registers. */
+#define CONFIG			0
+#define  CFG_MII_SELECT		0x8000	/* 91C100 only */
+#define  CFG_NO_WAIT		0x1000
+#define  CFG_FULL_STEP		0x0400
+#define  CFG_SET_SQLCH		0x0200
+#define  CFG_AUI_SELECT	 	0x0100
+#define  CFG_16BIT		0x0080
+#define  CFG_DIS_LINK		0x0040
+#define  CFG_STATIC		0x0030
+#define  CFG_IRQ_SEL_1		0x0004
+#define  CFG_IRQ_SEL_0		0x0002
+#define BASE_ADDR		2
+#define	ADDR0			4
+#define	GENERAL			10
+#define	CONTROL			12
+#define  CTL_STORE		0x0001
+#define  CTL_RELOAD		0x0002
+#define  CTL_EE_SELECT		0x0004
+#define  CTL_TE_ENABLE		0x0020
+#define  CTL_CR_ENABLE		0x0040
+#define  CTL_LE_ENABLE		0x0080
+#define  CTL_AUTO_RELEASE	0x0800
+#define	 CTL_POWERDOWN		0x2000
+
+/* Bank 2 registers. */
+#define MMU_CMD		0
+#define	 MC_ALLOC	0x20  	/* or with number of 256 byte packets */
+#define	 MC_RESET	0x40
+#define  MC_RELEASE  	0x80  	/* remove and release the current rx packet */
+#define  MC_FREEPKT  	0xA0  	/* Release packet in PNR register */
+#define  MC_ENQUEUE	0xC0 	/* Enqueue the packet for transmit */
+#define	PNR_ARR		2
+#define FIFO_PORTS	4
+#define  FP_RXEMPTY	0x8000
+#define	POINTER		6
+#define  PTR_AUTO_INC	0x0040
+#define  PTR_READ	0x2000
+#define	 PTR_AUTOINC 	0x4000
+#define	 PTR_RCV	0x8000
+#define	DATA_1		8
+#define	INTERRUPT	12
+#define  IM_RCV_INT		0x1
+#define	 IM_TX_INT		0x2
+#define	 IM_TX_EMPTY_INT	0x4
+#define	 IM_ALLOC_INT		0x8
+#define	 IM_RX_OVRN_INT		0x10
+#define	 IM_EPH_INT		0x20
+
+#define	RCR		4
+enum RxCfg { RxAllMulti = 0x0004, RxPromisc = 0x0002,
+	     RxEnable = 0x0100, RxStripCRC = 0x0200};
+#define  RCR_SOFTRESET	0x8000 	/* resets the chip */
+#define	 RCR_STRIP_CRC	0x200	/* strips CRC */
+#define  RCR_ENABLE	0x100	/* IFF this is set, we can recieve packets */
+#define  RCR_ALMUL	0x4 	/* receive all multicast packets */
+#define	 RCR_PROMISC	0x2	/* enable promiscuous mode */
+
+/* the normal settings for the RCR register : */
+#define	 RCR_NORMAL	(RCR_STRIP_CRC | RCR_ENABLE)
+#define  RCR_CLEAR	0x0		/* set it to a base state */
+#define	COUNTER		6
+
+/* BANK 3 -- not the same values as in smc9194! */
+#define	MULTICAST0	0
+#define	MULTICAST2	2
+#define	MULTICAST4	4
+#define	MULTICAST6	6
+#define REVISION	0x0a
+
+/* Transmit status bits. */
+#define TS_SUCCESS 0x0001
+#define TS_16COL   0x0010
+#define TS_LATCOL  0x0200
+#define TS_LOSTCAR 0x0400
+
+/* Receive status bits. */
+#define RS_ALGNERR	0x8000
+#define RS_BADCRC	0x2000
+#define RS_ODDFRAME	0x1000
+#define RS_TOOLONG	0x0800
+#define RS_TOOSHORT	0x0400
+#define RS_MULTICAST	0x0001
+#define RS_ERRORS	(RS_ALGNERR | RS_BADCRC | RS_TOOLONG | RS_TOOSHORT)
+
+#define set_bits(v, p) outw(inw(p)|(v), (p))
+#define mask_bits(v, p) outw(inw(p)&(v), (p))
+
+/*====================================================================*/
+
+static dev_link_t *smc91c92_attach(void);
+static void smc91c92_detach(dev_link_t *);
+static void smc91c92_config(dev_link_t *link);
+static void smc91c92_release(u_long arg);
+static int smc91c92_event(event_t event, int priority,
+			  event_callback_args_t *args);
+
+static int smc91c92_open(struct net_device *dev);
+static int smc91c92_close(struct net_device *dev);
+static void smc_tx_timeout(struct net_device *dev);
+static int smc_start_xmit(struct sk_buff *skb, struct net_device *dev);
+static void smc_interrupt(int irq, void *dev_id, struct pt_regs *regs);
+static void smc_rx(struct net_device *dev);
+static struct net_device_stats *smc91c92_get_stats(struct net_device *dev);
+static void set_rx_mode(struct net_device *dev);
+static int s9k_config(struct net_device *dev, struct ifmap *map);
+static void smc_set_xcvr(struct net_device *dev, int if_port);
+static void smc_reset(struct net_device *dev);
+static void media_check(u_long arg);
+
+/*======================================================================
+
+    This bit of code is used to avoid unregistering network devices
+    at inappropriate times.  2.2 and later kernels are fairly picky
+    about when this can happen.
+    
+======================================================================*/
+
+static void flush_stale_links(void)
+{
+    dev_link_t *link, *next;
+    for (link = dev_list; link; link = next) {
+	next = link->next;
+	if (link->state & DEV_STALE_LINK)
+	    smc91c92_detach(link);
+    }
+}
+
+/*====================================================================*/
+
+static void cs_error(client_handle_t handle, int func, int ret)
+{
+    error_info_t err = { func, ret };
+    CardServices(ReportError, handle, &err);
+}
+
+/*======================================================================
+
+  smc91c92_attach() creates an "instance" of the driver, allocating
+  local data structures for one device.  The device is registered
+  with Card Services.
+
+======================================================================*/
+
+static dev_link_t *smc91c92_attach(void)
+{
+    client_reg_t client_reg;
+    struct smc_private *smc;
+    dev_link_t *link;
+    struct net_device *dev;
+    int i, ret;
+
+    DEBUG(0, "smc91c92_attach()\n");
+    flush_stale_links();
+    
+    /* Create new ethernet device */
+    smc = kmalloc(sizeof(struct smc_private), GFP_KERNEL);
+    if (!smc) return NULL;
+    memset(smc, 0, sizeof(struct smc_private));
+    link = &smc->link; dev = &smc->dev;
+
+    link->release.function = &smc91c92_release;
+    link->release.data = (u_long)link;
+    link->io.NumPorts1 = 16;
+    link->io.Attributes1 = IO_DATA_PATH_WIDTH_AUTO;
+    link->io.IOAddrLines = 4;
+    link->irq.Attributes = IRQ_TYPE_EXCLUSIVE | IRQ_HANDLE_PRESENT;
+    link->irq.IRQInfo1 = IRQ_INFO2_VALID|IRQ_LEVEL_ID;
+    if (irq_list[0] == -1)
+	link->irq.IRQInfo2 = irq_mask;
+    else
+	for (i = 0; i < 4; i++)
+	    link->irq.IRQInfo2 |= 1 << irq_list[i];
+    link->irq.Handler = &smc_interrupt;
+    link->conf.Attributes = CONF_ENABLE_IRQ;
+    link->conf.Vcc = 50;
+    link->conf.IntType = INT_MEMORY_AND_IO;
+
+    /* The SMC91c92-specific entries in the device structure. */
+    dev->hard_start_xmit = &smc_start_xmit;
+    dev->get_stats = &smc91c92_get_stats;
+    dev->set_config = &s9k_config;
+    dev->set_multicast_list = &set_rx_mode;
+    ether_setup(dev);
+    dev->name = smc->node.dev_name;
+    dev->open = &smc91c92_open;
+    dev->stop = &smc91c92_close;
+#ifdef HAVE_NETIF_QUEUE
+    dev->tx_timeout = smc_tx_timeout;
+    dev->watchdog_timeo = TX_TIMEOUT;
+#endif
+    dev->priv = link->priv = link->irq.Instance = smc;
+    
+    /* Register with Card Services */
+    link->next = dev_list;
+    dev_list = link;
+    client_reg.dev_info = &dev_info;
+    client_reg.Attributes = INFO_IO_CLIENT | INFO_CARD_SHARE;
+    client_reg.EventMask = CS_EVENT_CARD_INSERTION | CS_EVENT_CARD_REMOVAL |
+	CS_EVENT_RESET_PHYSICAL | CS_EVENT_CARD_RESET |
+	CS_EVENT_PM_SUSPEND | CS_EVENT_PM_RESUME;
+    client_reg.event_handler = &smc91c92_event;
+    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);
+	smc91c92_detach(link);
+	return NULL;
+    }
+    
+    return link;
+} /* smc91c92_attach */
+
+/*======================================================================
+
+    This deletes a driver "instance".  The device is de-registered
+    with Card Services.  If it has been released, all local data
+    structures are freed.  Otherwise, the structures will be freed
+    when the device is released.
+
+======================================================================*/
+
+static void smc91c92_detach(dev_link_t *link)
+{
+    struct smc_private *smc = link->priv;
+    dev_link_t **linkp;
+
+    DEBUG(0, "smc91c92_detach(0x%p)\n", link);
+    
+    /* Locate device structure */
+    for (linkp = &dev_list; *linkp; linkp = &(*linkp)->next)
+	if (*linkp == link) break;
+    if (*linkp == NULL)
+	return;
+    
+    del_timer(&link->release);
+    if (link->state & DEV_CONFIG) {
+	smc91c92_release((u_long)link);
+	if (link->state & DEV_STALE_CONFIG) {
+	    link->state |= DEV_STALE_LINK;
+	    return;
+	}
+    }
+    
+    if (link->handle)
+	CardServices(DeregisterClient, link->handle);
+    
+    /* Unlink device structure, free bits */
+    *linkp = link->next;
+    if (link->dev)
+	unregister_netdev(&smc->dev);
+    kfree(smc);
+    
+} /* smc91c92_detach */
+
+/*====================================================================*/
+
+static int cvt_ascii_address(struct net_device *dev, char *s)
+{
+    int i, j, da, c;
+
+    if (strlen(s) != 12)
+	return -1;
+    for (i = 0; i < 6; i++) {
+	da = 0;
+	for (j = 0; j < 2; j++) {
+	    c = *s++;
+	    da <<= 4;
+	    da += ((c >= '0') && (c <= '9')) ?
+		(c - '0') : ((c & 0x0f) + 9);
+	}
+	dev->dev_addr[i] = da;
+    }
+    return 0;
+}
+
+/*====================================================================*/
+
+static int get_tuple(int fn, client_handle_t handle, tuple_t *tuple,
+		     cisparse_t *parse)
+{
+    int i;
+    i = CardServices(fn, handle, tuple);
+    if (i != CS_SUCCESS) return i;
+    i = CardServices(GetTupleData, handle, tuple);
+    if (i != CS_SUCCESS) return i;
+    return CardServices(ParseTuple, handle, tuple, parse);
+}
+
+#define first_tuple(a, b, c) get_tuple(GetFirstTuple, a, b, c)
+#define next_tuple(a, b, c) get_tuple(GetNextTuple, a, b, c)
+
+/*======================================================================
+
+    Configuration stuff for Megahertz cards
+
+    mhz_3288_power() is used to power up a 3288's ethernet chip.
+    mhz_mfc_config() handles socket setup for multifunction (1144
+    and 3288) cards.  mhz_setup() gets a card's hardware ethernet
+    address.
+    
+======================================================================*/
+
+static int mhz_3288_power(dev_link_t *link)
+{
+    struct smc_private *smc = link->priv;
+    u_char tmp;
+    
+    /* Read the ISR twice... */
+    readb(smc->base+MEGAHERTZ_ISR);
+    udelay(5);
+    readb(smc->base+MEGAHERTZ_ISR);
+
+    /* Pause 200ms... */
+    mdelay(200);
+    
+    /* Now read and write the COR... */
+    tmp = readb(smc->base + link->conf.ConfigBase + CISREG_COR);
+    udelay(5);
+    writeb(tmp, smc->base + link->conf.ConfigBase + CISREG_COR);
+
+    return 0;
+}
+
+static int mhz_mfc_config(dev_link_t *link)
+{
+    struct smc_private *smc = link->priv;
+    struct net_device *dev = &smc->dev;
+    tuple_t tuple;
+    cisparse_t parse;
+    u_char buf[255];
+    cistpl_cftable_entry_t *cf = &parse.cftable_entry;
+    win_req_t req;
+    memreq_t mem;
+    int i, k;
+
+    link->conf.Attributes |= CONF_ENABLE_SPKR;
+    link->conf.Status = CCSR_AUDIO_ENA;
+    link->irq.Attributes =
+	IRQ_TYPE_DYNAMIC_SHARING|IRQ_FIRST_SHARED|IRQ_HANDLE_PRESENT;
+    link->io.IOAddrLines = 16;
+    link->io.Attributes2 = IO_DATA_PATH_WIDTH_8;
+    link->io.NumPorts2 = 8;
+
+    tuple.Attributes = tuple.TupleOffset = 0;
+    tuple.TupleData = (cisdata_t *)buf;
+    tuple.TupleDataMax = sizeof(buf);
+    tuple.DesiredTuple = CISTPL_CFTABLE_ENTRY;
+
+    i = first_tuple(link->handle, &tuple, &parse);
+    /* The Megahertz combo cards have modem-like CIS entries, so
+       we have to explicitly try a bunch of port combinations. */
+    while (i == CS_SUCCESS) {
+	link->conf.ConfigIndex = cf->index;
+	link->io.BasePort2 = cf->io.win[0].base;
+	for (k = 0; k < 0x400; k += 0x10) {
+	    if (k & 0x80) continue;
+	    link->io.BasePort1 = k ^ 0x300;
+	    i = CardServices(RequestIO, link->handle, &link->io);
+	    if (i == CS_SUCCESS) break;
+	}
+	if (i == CS_SUCCESS) break;
+	i = next_tuple(link->handle, &tuple, &parse);
+    }
+    if (i != CS_SUCCESS)
+	return i;
+    dev->base_addr = link->io.BasePort1;
+    
+    /* Allocate a memory window, for accessing the ISR */
+    req.Attributes = WIN_DATA_WIDTH_8|WIN_MEMORY_TYPE_AM|WIN_ENABLE;
+    req.Base = req.Size = 0;
+    req.AccessSpeed = 0;
+    link->win = (window_handle_t)link->handle;
+    i = CardServices(RequestWindow, &link->win, &req);
+    if (i != CS_SUCCESS)
+	return i;
+    smc->base = ioremap(req.Base, req.Size);
+    mem.CardOffset = mem.Page = 0;
+    if (smc->manfid == MANFID_MOTOROLA)
+	mem.CardOffset = link->conf.ConfigBase;
+    i = CardServices(MapMemPage, link->win, &mem);
+    
+    if ((i == CS_SUCCESS)
+	&& (smc->manfid == MANFID_MEGAHERTZ)
+	&& (smc->cardid == PRODID_MEGAHERTZ_EM3288))
+	mhz_3288_power(link);
+    
+    return i;
+}
+
+static int mhz_setup(dev_link_t *link)
+{
+    client_handle_t handle = link->handle;
+    struct smc_private *smc = link->priv;
+    struct net_device *dev = &smc->dev;
+    tuple_t tuple;
+    cisparse_t parse;
+    u_char buf[255], *station_addr;
+
+    tuple.Attributes = tuple.TupleOffset = 0;
+    tuple.TupleData = buf;
+    tuple.TupleDataMax = sizeof(buf);
+
+    /* Read the station address from the CIS.  It is stored as the last
+       (fourth) string in the Version 1 Version/ID tuple. */
+    tuple.DesiredTuple = CISTPL_VERS_1;
+    if (first_tuple(handle, &tuple, &parse) != CS_SUCCESS)
+	return -1;
+    /* Ugh -- the EM1144 card has two VERS_1 tuples!?! */
+    if (next_tuple(handle, &tuple, &parse) != CS_SUCCESS)
+	first_tuple(handle, &tuple, &parse);
+    if (parse.version_1.ns > 3) {
+	station_addr = parse.version_1.str + parse.version_1.ofs[3];
+	if (cvt_ascii_address(dev, station_addr) == 0)
+	    return 0;
+    }
+
+    /* Another possibility: for the EM3288, in a special tuple */
+    tuple.DesiredTuple = 0x81;
+    if (CardServices(GetFirstTuple, handle, &tuple) != CS_SUCCESS)
+	return -1;
+    if (CardServices(GetTupleData, handle, &tuple) != CS_SUCCESS)
+	return -1;
+    buf[12] = '\0';
+    if (cvt_ascii_address(dev, buf) == 0)
+	return 0;
+    
+    return -1;
+}
+
+/*======================================================================
+
+    Configuration stuff for the Motorola Mariner
+
+    mot_config() writes directly to the Mariner configuration
+    registers because the CIS is just bogus.
+    
+======================================================================*/
+
+static void mot_config(dev_link_t *link)
+{
+    struct smc_private *smc = link->priv;
+    struct net_device *dev = &smc->dev;
+    ioaddr_t ioaddr = dev->base_addr;
+    ioaddr_t iouart = link->io.BasePort2;
+    
+    /* Set UART base address and force map with COR bit 1 */
+    writeb(iouart & 0xff,        smc->base + MOT_UART + CISREG_IOBASE_0);
+    writeb((iouart >> 8) & 0xff, smc->base + MOT_UART + CISREG_IOBASE_1);
+    writeb(MOT_NORMAL,           smc->base + MOT_UART + CISREG_COR);
+    
+    /* Set SMC base address and force map with COR bit 1 */
+    writeb(ioaddr & 0xff,        smc->base + MOT_LAN + CISREG_IOBASE_0);
+    writeb((ioaddr >> 8) & 0xff, smc->base + MOT_LAN + CISREG_IOBASE_1);
+    writeb(MOT_NORMAL,           smc->base + MOT_LAN + CISREG_COR);
+
+    /* Wait for things to settle down */
+    mdelay(100);
+}
+
+static int mot_setup(dev_link_t *link) {
+    struct smc_private *smc = link->priv;
+    struct net_device *dev = &smc->dev;
+    ioaddr_t ioaddr = dev->base_addr;
+    int i, wait, loop;
+    u_int addr;
+
+    /* Read Ethernet address from Serial EEPROM */
+    
+    for (i = 0; i < 3; i++) {
+	SMC_SELECT_BANK(2);
+	outw(MOT_EEPROM + i, ioaddr + POINTER);
+	SMC_SELECT_BANK(1);
+	outw((CTL_RELOAD | CTL_EE_SELECT), ioaddr + CONTROL);
+
+	for (loop = 0; loop < 200; loop++) {
+	    udelay(10);
+	    wait = ((CTL_RELOAD | CTL_STORE) & inw(ioaddr + CONTROL));
+	    if (wait == 0) break;
+	}
+	
+	if (wait)
+	    return -1;
+	
+	addr = inw(ioaddr + GENERAL);
+	dev->dev_addr[2*i]   = addr & 0xff;
+	dev->dev_addr[2*i+1] = (addr >> 8) & 0xff;
+    }
+    
+    return 0;
+}
+
+/*====================================================================*/
+
+static int smc_config(dev_link_t *link)
+{
+    struct smc_private *smc = link->priv;
+    struct net_device *dev = &smc->dev;
+    tuple_t tuple;
+    cisparse_t parse;
+    u_char buf[255];
+    cistpl_cftable_entry_t *cf = &parse.cftable_entry;
+    int i;
+
+    tuple.Attributes = tuple.TupleOffset = 0;
+    tuple.TupleData = (cisdata_t *)buf;
+    tuple.TupleDataMax = sizeof(buf);
+    tuple.DesiredTuple = CISTPL_CFTABLE_ENTRY;
+
+    link->io.NumPorts1 = 16;
+    i = first_tuple(link->handle, &tuple, &parse);
+    while (i != CS_NO_MORE_ITEMS) {
+	if (i == CS_SUCCESS) {
+	    link->conf.ConfigIndex = cf->index;
+	    link->io.BasePort1 = cf->io.win[0].base;
+	    link->io.IOAddrLines = cf->io.flags & CISTPL_IO_LINES_MASK;
+	    i = CardServices(RequestIO, link->handle, &link->io);
+	    if (i == CS_SUCCESS) break;
+	}
+	i = next_tuple(link->handle, &tuple, &parse);
+    }
+    if (i == CS_SUCCESS)
+	dev->base_addr = link->io.BasePort1;
+    return i;
+}
+
+static int smc_setup(dev_link_t *link)
+{
+    client_handle_t handle = link->handle;
+    struct smc_private *smc = link->priv;
+    struct net_device *dev = &smc->dev;
+    tuple_t tuple;
+    cisparse_t parse;
+    cistpl_lan_node_id_t *node_id;
+    u_char buf[255], *station_addr;
+    int i;
+
+    tuple.Attributes = tuple.TupleOffset = 0;
+    tuple.TupleData = buf;
+    tuple.TupleDataMax = sizeof(buf);
+    
+    /* Check for a LAN function extension tuple */
+    tuple.DesiredTuple = CISTPL_FUNCE;
+    i = first_tuple(handle, &tuple, &parse);
+    while (i == CS_SUCCESS) {
+	if (parse.funce.type == CISTPL_FUNCE_LAN_NODE_ID)
+	    break;
+	i = next_tuple(handle, &tuple, &parse);
+    }
+    if (i == CS_SUCCESS) {
+	node_id = (cistpl_lan_node_id_t *)parse.funce.data;
+	if (node_id->nb == 6) {
+	    for (i = 0; i < 6; i++)
+		dev->dev_addr[i] = node_id->id[i];
+	    return 0;
+	}
+    }
+    
+    /* Try the third string in the Version 1 Version/ID tuple. */
+    tuple.DesiredTuple = CISTPL_VERS_1;
+    if (first_tuple(handle, &tuple, &parse) != CS_SUCCESS)
+	return -1;
+    station_addr = parse.version_1.str + parse.version_1.ofs[2];
+    if (cvt_ascii_address(dev, station_addr) == 0)
+	return 0;
+
+    return -1;
+}
+
+/*====================================================================*/
+
+static int osi_config(dev_link_t *link)
+{
+    struct smc_private *smc = link->priv;
+    struct net_device *dev = &smc->dev;
+    static ioaddr_t com[4] = { 0x3f8, 0x2f8, 0x3e8, 0x2e8 };
+    int i, j;
+    
+    link->conf.Attributes |= CONF_ENABLE_SPKR;
+    link->conf.Status = CCSR_AUDIO_ENA;
+    link->irq.Attributes =
+	IRQ_TYPE_DYNAMIC_SHARING|IRQ_FIRST_SHARED|IRQ_HANDLE_PRESENT;
+    link->io.NumPorts1 = 64;
+    link->io.Attributes2 = IO_DATA_PATH_WIDTH_8;
+    link->io.NumPorts2 = 8;
+    link->io.IOAddrLines = 16;
+    
+    /* Enable Hard Decode, LAN, Modem */
+    link->conf.ConfigIndex = 0x23;
+    
+    for (j = 0; j < 4; j++) {
+	link->io.BasePort2 = com[j];
+	i = CardServices(RequestIO, link->handle, &link->io);
+	if (i == CS_SUCCESS) break;
+    }
+    if (i != CS_SUCCESS) {
+	/* Fallback: turn off hard decode */
+	link->conf.ConfigIndex = 0x03;
+	link->io.NumPorts2 = 0;
+	i = CardServices(RequestIO, link->handle, &link->io);
+    }
+    dev->base_addr = link->io.BasePort1 + 0x10;
+    return i;
+}
+
+static int osi_setup(dev_link_t *link, u_short manfid, u_short cardid)
+{
+    client_handle_t handle = link->handle;
+    struct smc_private *smc = link->priv;
+    struct net_device *dev = &smc->dev;
+    tuple_t tuple;
+    u_char buf[255];
+    int i;
+    
+    tuple.Attributes = TUPLE_RETURN_COMMON;
+    tuple.TupleData = buf;
+    tuple.TupleDataMax = sizeof(buf);
+    tuple.TupleOffset = 0;
+    
+    /* Read the station address from tuple 0x90, subtuple 0x04 */
+    tuple.DesiredTuple = 0x90;
+    i = CardServices(GetFirstTuple, handle, &tuple);
+    while (i == CS_SUCCESS) {
+	i = CardServices(GetTupleData, handle, &tuple);
+	if ((i != CS_SUCCESS) || (buf[0] == 0x04))
+	    break;
+	i = CardServices(GetNextTuple, handle, &tuple);
+    }
+    if (i != CS_SUCCESS)
+	return -1;
+    for (i = 0; i < 6; i++)
+	dev->dev_addr[i] = buf[i+2];
+
+    if (manfid != MANFID_OSITECH) return 0;
+
+    if (cardid == PRODID_OSITECH_SEVEN) {
+	/* Download the Seven of Diamonds firmware */
+	for (i = 0; i < sizeof(__Xilinx7OD); i++) {
+	    outb(__Xilinx7OD[i], link->io.BasePort1+2);
+	    udelay(50);
+	}
+    } else {
+	/* Make sure both functions are powered up */
+	set_bits(0x300, link->io.BasePort1 + OSITECH_AUI_PWR);
+	/* Now, turn on the interrupt for both card functions */
+	set_bits(0x300, link->io.BasePort1 + OSITECH_RESET_ISR);
+	DEBUG(2, "AUI/PWR: %4.4x RESET/ISR: %4.4x\n",
+	      inw(link->io.BasePort1 + OSITECH_AUI_PWR),
+	      inw(link->io.BasePort1 + OSITECH_RESET_ISR));
+    }
+
+    return 0;
+}
+
+/*======================================================================
+
+    This verifies that the chip is some SMC91cXX variant, and returns
+    the revision code if successful.  Otherwise, it returns -ENODEV.
+    
+======================================================================*/
+
+static int check_sig(dev_link_t *link)
+{
+    struct smc_private *smc = link->priv;
+    struct net_device *dev = &smc->dev;
+    ioaddr_t ioaddr = dev->base_addr;
+    int width;
+    u_short s;
+
+    SMC_SELECT_BANK(1);
+    if (inw(ioaddr + BANK_SELECT) >> 8 != 0x33) {
+	/* Try powering up the chip */
+	outw(0, ioaddr + CONTROL);
+	mdelay(55);
+    }
+
+    /* Try setting bus width */
+    width = (link->io.Attributes1 == IO_DATA_PATH_WIDTH_AUTO);
+    s = inb(ioaddr + CONFIG);
+    if (width)
+	s |= CFG_16BIT;
+    else
+	s &= ~CFG_16BIT;
+    outb(s, ioaddr + CONFIG);
+    
+    /* Check Base Address Register to make sure bus width is OK */
+    s = inw(ioaddr + BASE_ADDR);
+    if ((inw(ioaddr + BANK_SELECT) >> 8 == 0x33) &&
+	((s >> 8) != (s & 0xff))) {
+	SMC_SELECT_BANK(3);
+	s = inw(ioaddr + REVISION);
+	return (s & 0xff);
+    }
+
+    if (width) {
+	event_callback_args_t args;
+	printk(KERN_INFO "smc91c92_cs: using 8-bit IO window.\n");
+	args.client_data = link;
+	smc91c92_event(CS_EVENT_RESET_PHYSICAL, 0, &args);
+	CardServices(ReleaseIO, link->handle, &link->io);
+	link->io.Attributes1 = IO_DATA_PATH_WIDTH_8;
+	CardServices(RequestIO, link->handle, &link->io);
+	smc91c92_event(CS_EVENT_CARD_RESET, 0, &args);
+	return check_sig(link);
+    }
+    return -ENODEV;
+}
+
+/*======================================================================
+
+    smc91c92_config() is scheduled to run after a CARD_INSERTION event
+    is received, to configure the PCMCIA socket, and to make the
+    ethernet device available to the system.
+
+======================================================================*/
+
+#define CS_EXIT_TEST(ret, svc, label) \
+if (ret != CS_SUCCESS) { cs_error(link->handle, svc, ret); goto label; }
+
+static void smc91c92_config(dev_link_t *link)
+{
+    client_handle_t handle = link->handle;
+    struct smc_private *smc = link->priv;
+    struct net_device *dev = &smc->dev;
+    tuple_t tuple;
+    cisparse_t parse;
+    u_short buf[32];
+    char *name;
+    int i, rev;
+
+    DEBUG(0, "smc91c92_config(0x%p)\n", link);
+    
+    tuple.Attributes = tuple.TupleOffset = 0;
+    tuple.TupleData = (cisdata_t *)buf;
+    tuple.TupleDataMax = sizeof(buf);
+
+    tuple.DesiredTuple = CISTPL_CONFIG;
+    i = first_tuple(handle, &tuple, &parse);
+    CS_EXIT_TEST(i, ParseTuple, config_failed);
+    link->conf.ConfigBase = parse.config.base;
+    link->conf.Present = parse.config.rmask[0];
+    
+    tuple.DesiredTuple = CISTPL_MANFID;
+    tuple.Attributes = TUPLE_RETURN_COMMON;
+    if (first_tuple(handle, &tuple, &parse) == CS_SUCCESS) {
+	smc->manfid = parse.manfid.manf;
+	smc->cardid = parse.manfid.card;
+    }
+    
+    /* Configure card */
+    link->state |= DEV_CONFIG;
+
+    if (smc->manfid == MANFID_OSITECH) {
+	i = osi_config(link);
+    } else if ((smc->manfid == MANFID_MOTOROLA) ||
+	       ((smc->manfid == MANFID_MEGAHERTZ) &&
+		((smc->cardid == PRODID_MEGAHERTZ_VARIOUS) ||
+		 (smc->cardid == PRODID_MEGAHERTZ_EM3288)))) {
+	i = mhz_mfc_config(link);
+    } else {
+	i = smc_config(link);
+    }
+    CS_EXIT_TEST(i, RequestIO, config_failed);
+    
+    i = CardServices(RequestIRQ, link->handle, &link->irq);
+    CS_EXIT_TEST(i, RequestIRQ, config_failed);
+    i = CardServices(RequestConfiguration, link->handle, &link->conf);
+    CS_EXIT_TEST(i, RequestConfiguration, config_failed);
+    
+    if (smc->manfid == MANFID_MOTOROLA)
+	mot_config(link);
+
+    dev->irq = link->irq.AssignedIRQ;
+
+    if ((if_port >= 0) && (if_port <= 2))
+	dev->if_port = if_port;
+    else
+	printk(KERN_NOTICE "smc91c92_cs: invalid if_port requested\n");
+    
+    if (register_netdev(dev) != 0) {
+	printk(KERN_ERR "smc91c92_cs: register_netdev() failed\n");
+	goto config_undo;
+    }
+
+    switch (smc->manfid) {
+    case MANFID_OSITECH:
+    case MANFID_PSION:
+	i = osi_setup(link, smc->manfid, smc->cardid); break;
+    case MANFID_SMC:
+    case MANFID_NEW_MEDIA:
+	i = smc_setup(link); break;
+    case 0x128: /* For broken Megahertz cards */
+    case MANFID_MEGAHERTZ:
+	i = mhz_setup(link); break;
+    case MANFID_MOTOROLA:
+    default: /* get the hw address from EEPROM */
+	i = mot_setup(link); break;
+    }
+    
+    if (i != 0) {
+	printk(KERN_NOTICE "smc91c92_cs: Unable to find hardware address.\n");
+	link->state &= ~DEV_CONFIG_PENDING;
+	goto config_undo;
+    }
+
+    link->dev = &smc->node;
+    link->state &= ~DEV_CONFIG_PENDING;
+
+    rev = check_sig(link);
+    name = "???";
+    if (rev > 0)
+	switch (rev >> 4) {
+	case 3: name = "92"; break;
+	case 4: name = ((rev & 15) >= 6) ? "96" : "94"; break;
+	case 5: name = "95"; break;
+	case 7: name = "100"; break;
+	case 8: name = "100-FD"; break;
+	case 9: name = "110"; break;
+	}
+    printk(KERN_INFO "%s: smc91c%s rev %d: io %#3lx, irq %d, "
+	   "hw_addr ", dev->name, name, (rev & 0x0f), dev->base_addr,
+	   dev->irq);
+    for (i = 0; i < 6; i++)
+	printk("%02X%s", dev->dev_addr[i], ((i<5) ? ":" : "\n"));
+    if (rev > 0) {
+	u_long mir, mcr, mii;
+	ioaddr_t ioaddr = dev->base_addr;
+	SMC_SELECT_BANK(0);
+	mir = inw(ioaddr + MEMINFO) & 0xff;
+	if (mir == 0xff) mir++;
+	/* Get scale factor for memory size */
+	mcr = ((rev >> 4) > 3) ? inw(ioaddr + MEMCFG) : 0x0200;
+	mir *= 128 * (1<<((mcr >> 9) & 7));
+	if (mir & 0x3ff)
+	    printk(KERN_INFO "  %lu byte", mir);
+	else
+	    printk(KERN_INFO "  %lu kb", mir>>10);
+	SMC_SELECT_BANK(1);
+	mii = inw(ioaddr + CONFIG) & CFG_MII_SELECT;
+	printk(" buffer, %s xcvr\n", mii ? "MII" : if_names[dev->if_port]);
+    }
+    
+    return;
+    
+config_undo:
+    unregister_netdev(dev);
+config_failed:			/* CS_EXIT_TEST() calls jump to here... */
+    smc91c92_release((u_long)link);
+    
+} /* smc91c92_config */
+
+/*======================================================================
+
+    After a card is removed, smc91c92_release() will unregister the net
+    device, and release the PCMCIA configuration.  If the device is
+    still open, this will be postponed until it is closed.
+
+======================================================================*/
+
+static void smc91c92_release(u_long arg)
+{
+    dev_link_t *link = (dev_link_t *)arg;
+    struct smc_private *smc = link->priv;
+
+    DEBUG(0, "smc91c92_release(0x%p)\n", link);
+    
+    if (link->open) {
+	DEBUG(1, "smc91c92_cs: release postponed, '%s' still open\n",
+	      link->dev->dev_name);
+	link->state |= DEV_STALE_CONFIG;
+	return;
+    }
+    
+    CardServices(ReleaseConfiguration, link->handle);
+    CardServices(ReleaseIO, link->handle, &link->io);
+    CardServices(ReleaseIRQ, link->handle, &link->irq);
+    if (link->win) {
+	iounmap(smc->base);
+	CardServices(ReleaseWindow, link->win);
+    }
+    
+    link->state &= ~DEV_CONFIG;
+
+} /* smc91c92_release */
+
+/*======================================================================
+
+    The card status event handler.  Mostly, this schedules other
+    stuff to run after an event is received.  A CARD_REMOVAL event
+    also sets some flags to discourage the net drivers from trying
+    to talk to the card any more.
+
+======================================================================*/
+
+static int smc91c92_event(event_t event, int priority,
+			  event_callback_args_t *args)
+{
+    dev_link_t *link = args->client_data;
+    struct smc_private *smc = link->priv;
+    struct net_device *dev = &smc->dev;
+    
+    DEBUG(1, "smc91c92_event(0x%06x)\n", event);
+
+    switch (event) {
+    case CS_EVENT_CARD_REMOVAL:
+	link->state &= ~DEV_PRESENT;
+	if (link->state & DEV_CONFIG) {
+	    netif_device_detach(dev);
+	    mod_timer(&link->release, jiffies + HZ/20);
+	}
+	break;
+    case CS_EVENT_CARD_INSERTION:
+	link->state |= DEV_PRESENT;
+	smc91c92_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 (link->open)
+		netif_device_detach(dev);
+	    CardServices(ReleaseConfiguration, link->handle);
+	}
+	break;
+    case CS_EVENT_PM_RESUME:
+	link->state &= ~DEV_SUSPEND;
+	/* Fall through... */
+    case CS_EVENT_CARD_RESET:
+	if (link->state & DEV_CONFIG) {
+	    if ((smc->manfid == MANFID_MEGAHERTZ) &&
+		(smc->cardid == PRODID_MEGAHERTZ_EM3288))
+		mhz_3288_power(link);
+	    CardServices(RequestConfiguration, link->handle, &link->conf);
+	    if (smc->manfid == MANFID_MOTOROLA)
+		mot_config(link);
+	    if ((smc->manfid == MANFID_OSITECH) &&
+		(smc->cardid != PRODID_OSITECH_SEVEN)) {
+		/* Power up the card and enable interrupts */
+		set_bits(0x0300, dev->base_addr-0x10+OSITECH_AUI_PWR);
+		set_bits(0x0300, dev->base_addr-0x10+OSITECH_RESET_ISR);
+	    }
+	    if (link->open) {
+		smc_reset(dev);
+		netif_device_attach(dev);
+	    }
+	}
+	break;
+    }
+    return 0;
+} /* smc91c92_event */
+
+/*======================================================================
+  
+    The driver core code, most of which should be common with a
+    non-PCMCIA implementation.
+    
+======================================================================*/
+
+#ifdef PCMCIA_DEBUG
+static void smc_dump(struct net_device *dev)
+{
+    ioaddr_t ioaddr = dev->base_addr;
+    u_short i, w, save;
+    save = inw(ioaddr + BANK_SELECT);
+    for (w = 0; w < 4; w++) {
+	SMC_SELECT_BANK(w);
+	printk(KERN_DEBUG "bank %d: ", w);
+	for (i = 0; i < 14; i += 2)
+	    printk(" %04x", inw(ioaddr + i));
+	printk("\n");
+    }
+    outw(save, ioaddr + BANK_SELECT);
+}
+#endif
+
+static int smc91c92_open(struct net_device *dev)
+{
+    struct smc_private *smc = dev->priv;
+    dev_link_t *link = &smc->link;
+
+#ifdef PCMCIA_DEBUG
+    DEBUG(0, "%s: smc91c92_open(%p), ID/Window %4.4x.\n",
+	  dev->name, dev, inw(dev->base_addr + BANK_SELECT));
+    if (pc_debug > 1) smc_dump(dev);
+#endif
+    
+    /* Check that the PCMCIA card is still here. */
+    if (!DEV_OK(link))
+	return -ENODEV;
+    /* Physical device present signature. */
+    if (check_sig(link) < 0) {
+	printk("smc91c92_cs: Yikes!  Bad chip signature!\n");
+	return -ENODEV;
+    }
+    link->open++;
+    MOD_INC_USE_COUNT;
+
+    netif_start_queue(dev);
+    netif_mark_up(dev);
+    smc->saved_skb = 0;
+    smc->packets_waiting = 0;
+    
+    smc_reset(dev);
+    smc->media.function = &media_check;
+    smc->media.data = (u_long)smc;
+    smc->media.expires = jiffies + HZ;
+    add_timer(&smc->media);
+    
+    return 0;
+} /* smc91c92_open */
+
+/*====================================================================*/
+
+static int smc91c92_close(struct net_device *dev)
+{
+    struct smc_private *smc = dev->priv;
+    dev_link_t *link = &smc->link;
+    ioaddr_t ioaddr = dev->base_addr;
+
+    DEBUG(0, "%s: smc91c92_close(), status %4.4x.\n",
+	  dev->name, inw(ioaddr + BANK_SELECT));
+
+    netif_stop_queue(dev);
+    netif_mark_down(dev);
+
+    /* Shut off all interrupts, and turn off the Tx and Rx sections.
+       Don't bother to check for chip present. */
+    SMC_SELECT_BANK(2);	/* Nominally paranoia, but do no assume... */
+    outw(0, ioaddr + INTERRUPT);
+    SMC_SELECT_BANK(0);
+    mask_bits(0xff00, ioaddr + RCR);
+    mask_bits(0xff00, ioaddr + TCR);
+    
+    /* Put the chip into power-down mode. */
+    SMC_SELECT_BANK(1);
+    outw(CTL_POWERDOWN, ioaddr + CONTROL );
+    
+    link->open--;
+    del_timer(&smc->media);
+    if (link->state & DEV_STALE_CONFIG)
+	mod_timer(&link->release, jiffies + HZ/20);
+    
+    MOD_DEC_USE_COUNT;
+    
+    return 0;
+} /* smc91c92_close */
+
+/*======================================================================
+
+   Transfer a packet to the hardware and trigger the packet send.
+   This may be called at either from either the Tx queue code
+   or the interrupt handler.
+   
+======================================================================*/
+
+static void smc_hardware_send_packet(struct net_device * dev)
+{
+    struct smc_private *smc = dev->priv;
+    struct sk_buff *skb = smc->saved_skb;
+    ioaddr_t ioaddr = dev->base_addr;
+    u_char packet_no;
+    
+    if (!skb) {
+	printk(KERN_ERR "%s: In XMIT with no packet to send.\n", dev->name);
+	return;
+    }
+    
+    /* There should be a packet slot waiting. */
+    packet_no = inw(ioaddr + PNR_ARR) >> 8;
+    if (packet_no & 0x80) {
+	/* If not, there is a hardware problem!  Likely an ejected card. */
+	printk(KERN_WARNING "%s: 91c92 hardware Tx buffer allocation"
+	       " failed, status %#2.2x.\n", dev->name, packet_no);
+	dev_kfree_skb_irq(skb);
+	smc->saved_skb = NULL;
+	netif_start_queue(dev);
+	return;
+    }
+
+    add_tx_bytes(&smc->stats, skb->len);
+    /* The card should use the just-allocated buffer. */
+    outw(packet_no, ioaddr + PNR_ARR);
+    /* point to the beginning of the packet */
+    outw(PTR_AUTOINC , ioaddr + POINTER);
+    
+    /* Send the packet length (+6 for status, length and ctl byte)
+       and the status word (set to zeros). */
+    {
+	u_char *buf = skb->data;
+	u_int length = skb->len; /* The chip will pad to ethernet min. */
+
+	DEBUG(2, "%s: Trying to xmit packet of length %d.\n",
+	      dev->name, length);
+	
+	/* send the packet length: +6 for status word, length, and ctl */
+	outw(0, ioaddr + DATA_1);
+	outw(length + 6, ioaddr + DATA_1);
+	outsw_ns(ioaddr + DATA_1, buf, length >> 1);
+	
+	/* The odd last byte, if there is one, goes in the control word. */
+	outw((length & 1) ? 0x2000 | buf[length-1] : 0, ioaddr + DATA_1);
+    }
+    
+    /* Enable the Tx interrupts, both Tx (TxErr) and TxEmpty. */
+    outw(((IM_TX_INT|IM_TX_EMPTY_INT)<<8) |
+	 (inw(ioaddr + INTERRUPT) & 0xff00),
+	 ioaddr + INTERRUPT);
+    
+    /* The chip does the rest of the work. */
+    outw(MC_ENQUEUE , ioaddr + MMU_CMD);
+    
+    smc->saved_skb = NULL;
+    dev_kfree_skb_irq(skb);
+    dev->trans_start = jiffies;
+    netif_start_queue(dev);
+    return;
+}
+
+/*====================================================================*/
+
+static void smc_tx_timeout(struct net_device *dev)
+{
+    struct smc_private *smc = dev->priv;
+    ioaddr_t ioaddr = dev->base_addr;
+
+    printk(KERN_NOTICE "%s: SMC91c92 transmit timed out, "
+	   "Tx_status %2.2x status %4.4x.\n",
+	   dev->name, inw(ioaddr)&0xff, inw(ioaddr + 2));
+    smc->stats.tx_errors++;
+    smc_reset(dev);
+    dev->trans_start = jiffies;
+    smc->saved_skb = NULL;
+    netif_start_queue(dev);
+}
+
+static int smc_start_xmit(struct sk_buff *skb, struct net_device *dev)
+{
+    struct smc_private *smc = dev->priv;
+    ioaddr_t ioaddr = dev->base_addr;
+    u_short num_pages;
+    short time_out, ir;
+
+    tx_timeout_check(dev, smc_tx_timeout);
+    skb_tx_check(dev, skb);
+
+    DEBUG(2, "%s: smc91c92_start_xmit(length = %d) called,"
+	  " status %4.4x.\n", dev->name, skb->len, inw(ioaddr + 2));
+    
+    if (smc->saved_skb) {
+	/* THIS SHOULD NEVER HAPPEN. */
+	smc->stats.tx_aborted_errors++;
+	printk(KERN_DEBUG "%s: Internal error -- sent packet while busy.\n",
+	       dev->name);
+	return 1;
+    }
+    smc->saved_skb = skb;
+    
+    num_pages = skb->len >> 8;
+    
+    if (num_pages > 7) {
+	printk(KERN_ERR "%s: Far too big packet error.\n", dev->name);
+	DEV_KFREE_SKB (skb);
+	smc->saved_skb = NULL;
+	smc->stats.tx_dropped++;
+	return 0;		/* Do not re-queue this packet. */
+    }
+    /* A packet is now waiting. */
+    smc->packets_waiting++;
+    
+    SMC_SELECT_BANK(2);	/* Paranoia, we should always be in window 2 */
+    
+    /* Allocate the memory; send the packet now if we win. */
+    outw(MC_ALLOC | num_pages, ioaddr + MMU_CMD);
+    for (time_out = MEMORY_WAIT_TIME; time_out >= 0; time_out--) {
+	ir = inw(ioaddr+INTERRUPT);
+	if (ir & IM_ALLOC_INT) {
+	    /* Acknowledge the interrupt, send the packet. */
+	    outw((ir&0xff00) | IM_ALLOC_INT, ioaddr + INTERRUPT);
+	    smc_hardware_send_packet(dev);	/* Send the packet now.. */
+	    return 0;
+	}
+    }
+    
+    /* Otherwise defer until the Tx-space-allocated interrupt. */
+    DEBUG(2, "%s: memory allocation deferred.\n", dev->name);
+    outw((IM_ALLOC_INT << 8) | (ir & 0xff00), ioaddr + INTERRUPT);
+    
+    return 0;
+}
+
+/*======================================================================
+
+    Handle a Tx anomolous event.  Entered while in Window 2.
+    
+======================================================================*/
+
+static void smc_tx_err(struct net_device * dev)
+{
+    struct smc_private *smc = (struct smc_private *)dev->priv;
+    ioaddr_t ioaddr = dev->base_addr;
+    int saved_packet = inw(ioaddr + PNR_ARR) & 0xff;
+    int packet_no = inw(ioaddr + FIFO_PORTS) & 0x7f;
+    int tx_status;
+    
+    /* select this as the packet to read from */
+    outw(packet_no, ioaddr + PNR_ARR);
+    
+    /* read the first word from this packet */
+    outw(PTR_AUTOINC | PTR_READ | 0, ioaddr + POINTER);
+    
+    tx_status = inw(ioaddr + DATA_1);
+
+    smc->stats.tx_errors++;
+    if (tx_status & TS_LOSTCAR) smc->stats.tx_carrier_errors++;
+    if (tx_status & TS_LATCOL)  smc->stats.tx_window_errors++;
+    if (tx_status & TS_16COL) {
+	smc->stats.tx_aborted_errors++;
+	smc->tx_err++;
+    }
+    
+    if (tx_status & TS_SUCCESS) {
+	printk(KERN_NOTICE "%s: Successful packet caused error "
+	       "interrupt?\n", dev->name);
+    }
+    /* re-enable transmit */
+    SMC_SELECT_BANK(0);
+    outw(inw(ioaddr + TCR) | TCR_ENABLE, ioaddr + TCR);
+    SMC_SELECT_BANK(2);
+    
+    outw(MC_FREEPKT, ioaddr + MMU_CMD); 	/* Free the packet memory. */
+    
+    /* one less packet waiting for me */
+    smc->packets_waiting--;
+    
+    outw(saved_packet, ioaddr + PNR_ARR);
+    return;
+}
+
+/*====================================================================*/
+
+static void smc_eph_irq(struct net_device *dev)
+{
+    struct smc_private *smc = dev->priv;
+    ioaddr_t ioaddr = dev->base_addr;
+    u_short card_stats, ephs;
+    
+    SMC_SELECT_BANK(0);
+    ephs = inw(ioaddr + EPH);
+    DEBUG(2, "%s: Ethernet protocol handler interrupt, status"
+	  " %4.4x.\n", dev->name, ephs);
+    /* Could be a counter roll-over warning: update stats. */
+    card_stats = inw(ioaddr + COUNTER);
+    /* single collisions */
+    smc->stats.collisions += card_stats & 0xF;
+    card_stats >>= 4;
+    /* multiple collisions */
+    smc->stats.collisions += card_stats & 0xF;
+#if 0 		/* These are for when linux supports these statistics */
+    card_stats >>= 4;			/* deferred */
+    card_stats >>= 4;			/* excess deferred */
+#endif
+    /* If we had a transmit error we must re-enable the transmitter. */
+    outw(inw(ioaddr + TCR) | TCR_ENABLE, ioaddr + TCR);
+
+    /* Clear a link error interrupt. */
+    SMC_SELECT_BANK(1);
+    outw(CTL_AUTO_RELEASE | 0x0000, ioaddr + CONTROL);
+    outw(CTL_AUTO_RELEASE | CTL_TE_ENABLE | CTL_CR_ENABLE,
+	 ioaddr + CONTROL);
+    SMC_SELECT_BANK(2);
+}
+
+/*====================================================================*/
+    
+static void smc_interrupt(int irq, void *dev_id, struct pt_regs *regs)
+{
+    struct smc_private *smc = dev_id;
+    struct net_device *dev = &smc->dev;
+    ioaddr_t ioaddr;
+    u_short saved_bank, saved_pointer, mask, status;
+    char bogus_cnt = INTR_WORK;		/* Work we are willing to do. */
+
+    if (!netif_device_present(dev))
+	return;
+    ioaddr = dev->base_addr;
+    
+    DEBUG(3, "%s: SMC91c92 interrupt %d at %#x.\n", dev->name,
+	  irq, ioaddr);
+    
+    smc->watchdog = 0;
+    saved_bank = inw(ioaddr + BANK_SELECT);
+    if ((saved_bank & 0xff00) != 0x3300) {
+	/* The device does not exist -- the card could be off-line, or
+	   maybe it has been ejected. */
+	DEBUG(1, "%s: SMC91c92 interrupt %d for non-existent"
+	      "/ejected device.\n", dev->name, irq);
+	goto irq_done;
+    }
+    
+    SMC_SELECT_BANK(2);
+    saved_pointer = inw(ioaddr + POINTER);
+    mask = inw(ioaddr + INTERRUPT) >> 8;
+    /* clear all interrupts */
+    outw(0, ioaddr + INTERRUPT);
+    
+    do { /* read the status flag, and mask it */
+	status = inw(ioaddr + INTERRUPT) & 0xff;
+	DEBUG(3, "%s: Status is %#2.2x (mask %#2.2x).\n", dev->name,
+	      status, mask);
+	if ((status & mask) == 0)
+	    break;
+	
+	if (status & IM_RCV_INT) {
+	    /* Got a packet(s). */
+	    smc_rx(dev);
+	    smc->last_rx = jiffies;
+	}
+	if (status & IM_TX_INT) {
+	    smc_tx_err(dev);
+	    outw(IM_TX_INT, ioaddr + INTERRUPT);
+	}
+	status &= mask;
+	if (status & IM_TX_EMPTY_INT) {
+	    outw(IM_TX_EMPTY_INT, ioaddr + INTERRUPT);
+	    mask &= ~IM_TX_EMPTY_INT;
+	    smc->stats.tx_packets += smc->packets_waiting;
+	    smc->packets_waiting = 0;
+	}
+	if (status & IM_ALLOC_INT) {
+	    /* Clear this interrupt so it doesn't happen again */
+	    mask &= ~IM_ALLOC_INT;
+	    
+	    smc_hardware_send_packet(dev);
+	    
+	    /* enable xmit interrupts based on this */
+	    mask |= (IM_TX_EMPTY_INT | IM_TX_INT);
+	    
+	    /* and let the card send more packets to me */
+	    netif_wake_queue(dev);
+	}
+	if (status & IM_RX_OVRN_INT) {
+	    smc->stats.rx_errors++;
+	    smc->stats.rx_fifo_errors++;		
+	    outw(IM_RX_OVRN_INT, ioaddr + INTERRUPT);
+	}
+	if (status & IM_EPH_INT)
+	    smc_eph_irq(dev);
+    } while (--bogus_cnt);
+
+    DEBUG(3, "  Restoring saved registers mask %2.2x bank %4.4x"
+	  " pointer %4.4x.\n", mask, saved_bank, saved_pointer);
+    
+    /* restore state register */
+    outw((mask<<8), ioaddr + INTERRUPT);
+    outw(saved_pointer, ioaddr + POINTER);
+    SMC_SELECT_BANK(saved_bank);
+
+    DEBUG(3, "%s: Exiting interrupt IRQ%d.\n", dev->name, irq);
+
+irq_done:
+    
+    if ((smc->manfid == MANFID_OSITECH) &&
+	(smc->cardid != PRODID_OSITECH_SEVEN)) {
+	/* Retrigger interrupt if needed */
+	mask_bits(0x00ff, ioaddr-0x10+OSITECH_RESET_ISR);
+	set_bits(0x0300, ioaddr-0x10+OSITECH_RESET_ISR);
+    }
+    if (smc->manfid == MANFID_MOTOROLA) {
+	u_char cor;
+	cor = readb(smc->base + MOT_UART + CISREG_COR);
+	writeb(cor & ~COR_IREQ_ENA, smc->base + MOT_UART + CISREG_COR);
+	writeb(cor, smc->base + MOT_UART + CISREG_COR);
+	cor = readb(smc->base + MOT_LAN + CISREG_COR);
+	writeb(cor & ~COR_IREQ_ENA, smc->base + MOT_LAN + CISREG_COR);
+	writeb(cor, smc->base + MOT_LAN + CISREG_COR);
+    }
+#ifdef DOES_NOT_WORK
+    if (smc->base != NULL) { /* Megahertz MFC's */
+	readb(smc->base+MEGAHERTZ_ISR);
+	readb(smc->base+MEGAHERTZ_ISR);
+    }
+#endif
+}
+
+/*====================================================================*/
+
+static void smc_rx(struct net_device *dev)
+{
+    struct smc_private *smc = (struct smc_private *)dev->priv;
+    ioaddr_t ioaddr = dev->base_addr;
+    int rx_status;
+    int packet_length;	/* Caution: not frame length, rather words
+			   to transfer from the chip. */
+    
+    /* Assertion: we are in Window 2. */
+    
+    if (inw(ioaddr + FIFO_PORTS) & FP_RXEMPTY) {
+	printk(KERN_ERR "%s: smc_rx() with nothing on Rx FIFO.\n",
+	       dev->name);
+	return;
+    }
+    
+    /*  Reset the read pointer, and read the status and packet length. */
+    outw(PTR_READ | PTR_RCV | PTR_AUTOINC, ioaddr + POINTER);
+    rx_status = inw(ioaddr + DATA_1);
+    packet_length = inw(ioaddr + DATA_1) & 0x07ff;
+
+    DEBUG(2, "%s: Receive status %4.4x length %d.\n",
+	  dev->name, rx_status, packet_length);
+    
+    if (!(rx_status & RS_ERRORS)) {		
+	/* do stuff to make a new packet */
+	struct sk_buff *skb;
+	
+	/* Note: packet_length adds 5 or 6 extra bytes here! */
+	skb = dev_alloc_skb(packet_length+2);
+	
+	if (skb == NULL) {
+	    DEBUG(1, "%s: Low memory, packet dropped.\n", dev->name);
+	    smc->stats.rx_dropped++;
+	    outw(MC_RELEASE, ioaddr + MMU_CMD);
+	    return;
+	}
+	
+	packet_length -= (rx_status & RS_ODDFRAME ? 5 : 6);
+	skb_reserve(skb, 2);
+	insw_ns(ioaddr+DATA_1, skb_put(skb, packet_length),
+		(packet_length+1)>>1);
+	skb->protocol = eth_type_trans(skb, dev);
+	
+	skb->dev = dev;
+	netif_rx(skb);
+	smc->stats.rx_packets++;
+	add_rx_bytes(&smc->stats, skb->len);
+	if (rx_status & RS_MULTICAST)
+	    smc->stats.multicast++;
+    } else {
+	/* error ... */
+	smc->stats.rx_errors++;
+	
+	if (rx_status & RS_ALGNERR)  smc->stats.rx_frame_errors++;
+	if (rx_status & (RS_TOOSHORT | RS_TOOLONG))
+	    smc->stats.rx_length_errors++;
+	if (rx_status & RS_BADCRC)	smc->stats.rx_crc_errors++;
+    }
+    /* Let the MMU free the memory of this packet. */
+    outw(MC_RELEASE, ioaddr + MMU_CMD);
+    
+    return;
+}
+
+/*====================================================================*/
+
+static struct net_device_stats *smc91c92_get_stats(struct net_device *dev)
+{
+    struct smc_private *smc = (struct smc_private *)dev->priv;
+    /* Nothing to update - the 91c92 is a pretty primative chip. */
+    return &smc->stats;
+}
+
+/*======================================================================
+
+    Compute the AUTODIN polynomial "CRC32" for ethernet packets.
+
+======================================================================*/
+
+static const u_int ethernet_polynomial = 0x04c11db7U;
+
+static u_int ether_crc(int length, u_char *data)
+{
+    int crc = 0xffffffff;	/* Initial value. */
+    
+    while (--length >= 0) {
+	u_char current_octet = *data++;
+	int bit;
+	for (bit = 0; bit < 8; bit++, current_octet >>= 1) {
+	    crc = (crc << 1) ^
+		((crc < 0) ^ (current_octet & 1) ? ethernet_polynomial : 0);
+	}
+    }
+    /* The hash index is the either the upper or lower bits of the CRC, so
+     * we return the entire CRC.
+     */
+    return crc;
+}
+
+/*======================================================================
+  
+    Calculate values for the hardware multicast filter hash table.
+    
+======================================================================*/
+
+static void fill_multicast_tbl(int count, struct dev_mc_list *addrs,
+			       u_char *multicast_table)
+{
+    struct dev_mc_list	*mc_addr;
+    
+    for (mc_addr = addrs;  mc_addr && --count > 0;  mc_addr = mc_addr->next) {
+	u_int position = ether_crc(6, mc_addr->dmi_addr);
+#ifndef final_version		/* Verify multicast address. */
+	if ((mc_addr->dmi_addr[0] & 1) == 0)
+	    continue;
+#endif
+	multicast_table[position >> 29] |= 1 << ((position >> 26) & 7);
+    }
+}
+
+/*======================================================================
+  
+    Set the receive mode.
+    
+    This routine is used by both the protocol level to notify us of
+    promiscuous/multicast mode changes, and by the open/reset code to
+    initialize the Rx registers.  We always set the multicast list and
+    leave the receiver running.
+    
+======================================================================*/
+
+static void set_rx_mode(struct net_device *dev)
+{
+    ioaddr_t ioaddr = dev->base_addr;
+    u_int multicast_table[ 2 ] = { 0, };
+    long flags;
+    u_short rx_cfg_setting;
+    
+    if (dev->flags & IFF_PROMISC) {
+	printk(KERN_NOTICE "%s: setting Rx mode to promiscuous.\n", dev->name);
+	rx_cfg_setting = RxStripCRC | RxEnable | RxPromisc | RxAllMulti;
+    } else if (dev->flags & IFF_ALLMULTI)
+	rx_cfg_setting = RxStripCRC | RxEnable | RxAllMulti;
+    else {
+	if (dev->mc_count)  {
+	    fill_multicast_tbl(dev->mc_count, dev->mc_list,
+			       (u_char *)multicast_table);
+	}
+	rx_cfg_setting = RxStripCRC | RxEnable;
+    }
+    
+    /* Load MC table and Rx setting into the chip without interrupts. */
+    save_flags(flags);
+    cli();
+    SMC_SELECT_BANK(3);
+    outl(multicast_table[0], ioaddr + MULTICAST0);
+    outl(multicast_table[1], ioaddr + MULTICAST4);
+    SMC_SELECT_BANK(0);
+    outw(rx_cfg_setting, ioaddr + RCR);
+    SMC_SELECT_BANK(2);
+    restore_flags(flags);
+    
+    return;
+}
+
+/*======================================================================
+
+    Senses when a card's config changes. Here, it's coax or TP.
+ 
+======================================================================*/
+
+static int s9k_config(struct net_device *dev, struct ifmap *map)
+{
+    struct smc_private *smc = dev->priv;
+    if ((map->port != (u_char)(-1)) && (map->port != dev->if_port)) {
+	if (smc->cfg & CFG_MII_SELECT)
+	    return -EOPNOTSUPP;
+	else if (map->port > 2)
+	    return -EINVAL;
+	dev->if_port = map->port;
+	printk(KERN_INFO "%s: switched to %s port\n",
+	       dev->name, if_names[dev->if_port]);
+	smc_reset(dev);
+    }
+    return 0;
+}
+
+/*======================================================================
+
+    Reset the chip, reloading every register that might be corrupted.
+
+======================================================================*/
+
+/*
+  Set transceiver type, perhaps to something other than what the user
+  specified in dev->if_port.
+*/
+static void smc_set_xcvr(struct net_device *dev, int if_port)
+{
+    struct smc_private *smc = (struct smc_private *)dev->priv;
+    ioaddr_t ioaddr = dev->base_addr;
+    u_short saved_bank;
+
+    saved_bank = inw(ioaddr + BANK_SELECT);
+    SMC_SELECT_BANK(1);
+    if (if_port == 2) {
+	outw(smc->cfg | CFG_AUI_SELECT, ioaddr + CONFIG);
+	if ((smc->manfid == MANFID_OSITECH) &&
+	    (smc->cardid != PRODID_OSITECH_SEVEN))
+	    set_bits(OSI_AUI_PWR, ioaddr - 0x10 + OSITECH_AUI_PWR);
+	smc->media_status = ((dev->if_port == 0) ? 0x0001 : 0x0002);
+    } else {
+	outw(smc->cfg, ioaddr + CONFIG);
+	if ((smc->manfid == MANFID_OSITECH) &&
+	    (smc->cardid != PRODID_OSITECH_SEVEN))
+	    mask_bits(~OSI_AUI_PWR, ioaddr - 0x10 + OSITECH_AUI_PWR);
+	smc->media_status = ((dev->if_port == 0) ? 0x0012 : 0x4001);
+    }
+    SMC_SELECT_BANK(saved_bank);
+}
+
+static void smc_reset(struct net_device *dev)
+{
+    ioaddr_t ioaddr = dev->base_addr;
+    struct smc_private *smc = dev->priv;
+    int i;
+
+    DEBUG(0, "%s: smc91c92 reset called.\n", dev->name);
+    
+    /* The first interaction must be a write to bring the chip out
+       of sleep mode. */
+    SMC_SELECT_BANK(0);
+    /* Reset the chip. */
+    outw(RCR_SOFTRESET, ioaddr + RCR);
+    udelay(10);
+    
+    /* Clear the transmit and receive configuration registers. */
+    outw(RCR_CLEAR, ioaddr + RCR);
+    outw(TCR_CLEAR, ioaddr + TCR);
+    
+    /* Set the Window 1 control, configuration and station addr registers.
+       No point in writing the I/O base register ;-> */
+    SMC_SELECT_BANK(1);
+    /* Automatically release succesfully transmitted packets,
+       Accept link errors, counter and Tx error interrupts. */
+    outw(CTL_AUTO_RELEASE | CTL_TE_ENABLE | CTL_CR_ENABLE,
+	 ioaddr + CONTROL);
+    smc->cfg = inw(ioaddr + CONFIG) & ~CFG_AUI_SELECT;
+    smc->cfg |= CFG_NO_WAIT | CFG_16BIT | CFG_STATIC |
+	(smc->manfid == MANFID_OSITECH ? (CFG_IRQ_SEL_1 | CFG_IRQ_SEL_0) : 0);
+    smc_set_xcvr(dev, dev->if_port);
+    if ((smc->manfid == MANFID_OSITECH) &&
+	(smc->cardid != PRODID_OSITECH_SEVEN))
+	outw((dev->if_port == 2 ? OSI_AUI_PWR : 0) |
+	     (inw(ioaddr-0x10+OSITECH_AUI_PWR) & 0xff00),
+	     ioaddr - 0x10 + OSITECH_AUI_PWR);
+    
+    /* Fill in the physical address.  The databook is wrong about the order! */
+    for (i = 0; i < 6; i += 2)
+	outw((dev->dev_addr[i+1]<<8)+dev->dev_addr[i],
+	     ioaddr + ADDR0 + i);
+    
+    /* Reset the MMU */
+    SMC_SELECT_BANK(2);
+    outw(MC_RESET, ioaddr + MMU_CMD);
+    outw(0, ioaddr + INTERRUPT);
+    
+    /* Re-enable the chip. */
+    SMC_SELECT_BANK(0);
+    outw(((smc->cfg & CFG_MII_SELECT) ? 0 : TCR_MONCSN) |
+	 TCR_ENABLE | TCR_PAD_EN, ioaddr + TCR);
+    set_rx_mode(dev);
+
+    /* Enable interrupts. */
+    SMC_SELECT_BANK(2);
+    outw((IM_EPH_INT | IM_RX_OVRN_INT | IM_RCV_INT) << 8,
+	 ioaddr + INTERRUPT);
+}
+
+/*======================================================================
+
+    Media selection timer routine
+    
+======================================================================*/
+
+static void media_check(u_long arg)
+{
+    struct smc_private *smc = (struct smc_private *)(arg);
+    struct net_device *dev = &smc->dev;
+    ioaddr_t ioaddr = dev->base_addr;
+    u_short i, media, saved_bank;
+
+    if (!netif_device_present(dev))
+	goto reschedule;
+
+    saved_bank = inw(ioaddr + BANK_SELECT);
+    SMC_SELECT_BANK(2);
+    i = inw(ioaddr + INTERRUPT);
+    SMC_SELECT_BANK(0);
+    media = inw(ioaddr + EPH) & EPH_LINK_OK;
+    SMC_SELECT_BANK(1);
+    media |= (inw(ioaddr + CONFIG) & CFG_AUI_SELECT) ? 2 : 1;
+    SMC_SELECT_BANK(saved_bank);
+    
+    /* Check for pending interrupt with watchdog flag set: with
+       this, we can limp along even if the interrupt is blocked */
+    if (smc->watchdog++ && ((i>>8) & i)) {
+	if (!smc->fast_poll)
+	    printk(KERN_INFO "%s: interrupt(s) dropped!\n", dev->name);
+	smc_interrupt(dev->irq, smc, NULL);
+	smc->fast_poll = HZ;
+    }
+    if (smc->fast_poll) {
+	smc->fast_poll--;
+	smc->media.expires = jiffies + 1;
+	add_timer(&smc->media);
+	return;
+    }
+
+    if (smc->cfg & CFG_MII_SELECT)
+	goto reschedule;
+
+    /* Ignore collisions unless we've had no rx's recently */
+    if (jiffies - smc->last_rx > HZ) {
+	if (smc->tx_err || (smc->media_status & EPH_16COL))
+	    media |= EPH_16COL;
+    }
+    smc->tx_err = 0;
+
+    if (media != smc->media_status) {
+	if ((media & smc->media_status & 1) &&
+	    ((smc->media_status ^ media) & EPH_LINK_OK))
+	    printk(KERN_INFO "%s: %s link beat\n", dev->name,
+		   (smc->media_status & EPH_LINK_OK ? "lost" : "found"));
+	else if ((media & smc->media_status & 2) &&
+		 ((smc->media_status ^ media) & EPH_16COL))
+	    printk(KERN_INFO "%s: coax cable %s\n", dev->name,
+		   (media & EPH_16COL ? "problem" : "ok"));
+	if (dev->if_port == 0) {
+	    if (media & 1) {
+		if (media & EPH_LINK_OK)
+		    printk(KERN_INFO "%s: flipped to 10baseT\n",
+			   dev->name);
+		else
+		    smc_set_xcvr(dev, 2);
+	    } else {
+		if (media & EPH_16COL)
+		    smc_set_xcvr(dev, 1);
+		else
+		    printk(KERN_INFO "%s: flipped to 10base2\n",
+			   dev->name);
+	    }
+	}
+	smc->media_status = media;
+    }
+    
+reschedule:
+    smc->media.expires = jiffies + HZ;
+    add_timer(&smc->media);
+}
+
+/*====================================================================*/
+
+static int __init init_smc91c92_cs(void)
+{
+    servinfo_t serv;
+    DEBUG(0, "%s\n", version);
+    CardServices(GetCardServicesInfo, &serv);
+    if (serv.Revision != CS_RELEASE_CODE) {
+	printk(KERN_ERR
+	       "smc91c92_cs: Card Services release does not match!\n");
+	return -1;
+    }
+    register_pccard_driver(&dev_info, &smc91c92_attach, &smc91c92_detach);
+    return 0;
+}
+
+static void __exit exit_smc91c92_cs(void)
+{
+    DEBUG(0, "smc91c92_cs: unloading\n");
+    unregister_pccard_driver(&dev_info);
+    while (dev_list != NULL)
+	smc91c92_detach(dev_list);
+}
+
+module_init(init_smc91c92_cs);
+module_exit(exit_smc91c92_cs);
Index: oldkernel/linux/pcmcia-cs-3.1.15/clients/sram_mtd.c
diff -u /dev/null linux/pcmcia-cs-3.1.15/clients/sram_mtd.c:1.1
--- /dev/null	Mon Jul 31 21:15:10 2000
+++ linux/pcmcia-cs-3.1.15/clients/sram_mtd.c	Fri Jul  7 16:34:58 2000
@@ -0,0 +1,573 @@
+/*======================================================================
+
+    A simple MTD for accessing static RAM
+
+    sram_mtd.c 1.48 2000/05/16 21:31:37
+
+    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@pcmcia.sourceforge.org>.  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 <pcmcia/config.h>
+#include <pcmcia/k_compat.h>
+
+#ifdef __LINUX__
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/sched.h>
+#include <linux/ptrace.h>
+#include <linux/malloc.h>
+#include <linux/string.h>
+#include <linux/timer.h>
+#include <linux/major.h>
+#include <linux/fs.h>
+#include <asm/io.h>
+#include <asm/system.h>
+#include <asm/segment.h>
+#endif
+
+#include <stdarg.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>
+#include <pcmcia/mem_op.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_INFO args); } while (0)
+static char *version =
+"sram_mtd.c 1.48 2000/05/16 21:31:37 (David Hinds)";
+#else
+#define DEBUG(n, args...) do { } while (0)
+#endif
+
+/*====================================================================*/
+
+/* Parameters that can be set with 'insmod' */
+
+static int word_width = 1;			/* 1 = 16-bit */
+static int mem_speed = 0;			/* in ns */
+
+MODULE_PARM(word_width, "i");
+MODULE_PARM(mem_speed, "i");
+
+/*====================================================================*/
+
+static void sram_config(dev_link_t *link);
+static void sram_release(u_long arg);
+static int sram_event(event_t event, int priority,
+		       event_callback_args_t *args);
+
+static dev_link_t *sram_attach(void);
+static void sram_detach(dev_link_t *);
+
+typedef struct sram_dev_t {
+    dev_link_t		link;
+    caddr_t		Base;
+    u_int		Size;
+    int			nregion;
+    region_info_t	region[2*CISTPL_MAX_DEVICES];
+} sram_dev_t;
+
+static dev_info_t dev_info = "sram_mtd";
+
+static dev_link_t *dev_list = NULL;
+
+#ifdef __BEOS__
+static cs_client_module_info *cs;
+static ds_module_info *ds;
+static isa_module_info *isa;
+#define CardServices		cs->_CardServices
+#define MTDHelperEntry		cs->_MTDHelperEntry
+#define add_timer		cs->_add_timer
+#define del_timer		cs->_del_timer
+#define register_pccard
+#define unregister_pccard_driver ds->_unregister_pccard_driver
+#endif
+
+/*====================================================================*/
+
+static void cs_error(client_handle_t handle, int func, int ret)
+{
+    error_info_t err = { func, ret };
+    CardServices(ReportError, handle, &err);
+}
+
+/*======================================================================
+
+    sram_attach() creates an "instance" of the driver, allocating
+    local data structures for one device.  The device is registered
+    with Card Services.
+
+======================================================================*/
+
+static dev_link_t *sram_attach(void)
+{
+    client_reg_t client_reg;
+    dev_link_t *link;
+    sram_dev_t *dev;
+    int ret;
+    
+    DEBUG(0, "sram_attach()\n");
+
+    /* Create new memory card device */
+    dev = kmalloc(sizeof(*dev), GFP_KERNEL);
+    if (!dev) return NULL;
+    memset(dev, 0, sizeof(*dev));
+    link = &dev->link; link->priv = dev;
+    
+    link->release.function = &sram_release;
+    link->release.data = (u_long)link;
+
+    /* Register with Card Services */
+    link->next = dev_list;
+    dev_list = link;
+    client_reg.dev_info = &dev_info;
+    client_reg.Attributes = INFO_MTD_CLIENT | INFO_CARD_SHARE;
+    client_reg.EventMask =
+	CS_EVENT_RESET_PHYSICAL | CS_EVENT_CARD_RESET |
+	CS_EVENT_CARD_INSERTION | CS_EVENT_CARD_REMOVAL |
+	CS_EVENT_PM_SUSPEND | CS_EVENT_PM_RESUME;
+    client_reg.event_handler = &sram_event;
+    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);
+	sram_detach(link);
+	return NULL;
+    }
+
+    return link;
+} /* sram_attach */
+
+/*======================================================================
+
+    This deletes a driver "instance".  The device is de-registered
+    with Card Services.  If it has been released, all local data
+    structures are freed.  Otherwise, the structures will be freed
+    when the device is released.
+
+======================================================================*/
+
+static void sram_detach(dev_link_t *link)
+{
+    dev_link_t **linkp;
+    int ret;
+
+    DEBUG(0, "sram_detach(0x%p)\n", link);
+    
+    /* Locate device structure */
+    for (linkp = &dev_list; *linkp; linkp = &(*linkp)->next)
+	if (*linkp == link) break;
+    if (*linkp == NULL)
+	return;
+
+    del_timer(&link->release);
+    if (link->state & DEV_CONFIG)
+	sram_release((u_long)link);
+
+    if (link->handle) {
+	ret = CardServices(DeregisterClient, link->handle);
+	if (ret != CS_SUCCESS)
+	    cs_error(link->handle, DeregisterClient, ret);
+    }
+    
+    /* Unlink device structure, free bits */
+    *linkp = link->next;
+    kfree(link->priv);
+    
+} /* sram_detach */
+
+/*======================================================================
+
+    sram_config() is scheduled to run after a CARD_INSERTION event
+    is received, to bind the MTD to appropriate memory regions.
+    
+======================================================================*/
+
+static void printk_size(u_int sz)
+{
+    if (sz & 0x3ff)
+	printk("%u bytes", sz);
+    else if (sz & 0xfffff)
+	printk("%u kb", sz >> 10);
+    else
+	printk("%u mb", sz >> 20);
+}
+
+static void sram_config(dev_link_t *link)
+{
+    client_handle_t handle = link->handle;
+    sram_dev_t *dev = link->priv;
+    win_req_t req;
+    mtd_reg_t reg;
+    region_info_t region;
+    int i, attr, ret;
+
+    DEBUG(0, "sram_config(0x%p)\n", link);
+
+    /* Allocate a small memory window */
+    if (word_width)
+	req.Attributes = WIN_DATA_WIDTH_16;
+    else
+	req.Attributes = WIN_DATA_WIDTH_8;
+    req.Base = req.Size = 0;
+    req.AccessSpeed = mem_speed;
+    link->win = (window_handle_t)handle;
+    ret = MTDHelperEntry(MTDRequestWindow, &link->win, &req);
+    if (ret != 0) {
+	cs_error(handle, RequestWindow, ret);
+	link->state &= ~DEV_CONFIG_PENDING;
+	sram_release((u_long)link);
+	return;
+    }
+
+    link->state |= DEV_CONFIG;
+
+    /* Grab info for all the memory regions we can access */
+    dev->Base = ioremap(req.Base, req.Size);
+    dev->Size = req.Size;
+    i = 0;
+    for (attr = 0; attr < 2; attr++) {
+	region.Attributes = attr ? REGION_TYPE_AM : REGION_TYPE_CM;
+	ret = CardServices(GetFirstRegion, handle, &region);
+	while (ret == CS_SUCCESS) {
+	    reg.Attributes = region.Attributes;
+	    reg.Offset = region.CardOffset;
+	    reg.MediaID = (u_long)&dev->region[i];
+	    ret = CardServices(RegisterMTD, handle, &reg);
+	    if (ret != 0) break;		
+	    printk(KERN_INFO "sram_mtd: %s at 0x%x, ",
+		   attr ? "attr" : "common", region.CardOffset);
+	    printk_size(region.RegionSize);
+	    printk(", %d ns\n", region.AccessSpeed);
+	    dev->region[i] = region; i++;
+	    ret = CardServices(GetNextRegion, &region);
+	}
+    }
+    dev->nregion = i;
+    
+} /* sram_config */
+
+/*======================================================================
+
+    After a card is removed, sram_release() will release the memory
+    window allocated for this socket.
+    
+======================================================================*/
+
+static void sram_release(u_long arg)
+{
+    dev_link_t *link = (dev_link_t *)arg;
+    sram_dev_t *dev = link->priv;
+    int ret;
+    
+    DEBUG(0, "sram_release(0x%p)\n", link);
+
+    if (link->win) {
+	iounmap(dev->Base);
+	ret = MTDHelperEntry(MTDReleaseWindow, link->win);
+	if (ret != CS_SUCCESS)
+	    cs_error(link->handle, ReleaseWindow, ret);
+    }
+    link->state &= ~DEV_CONFIG;
+    
+    if (link->state & DEV_STALE_LINK)
+	sram_detach(link);
+    
+} /* sram_release */
+
+/*====================================================================*/
+
+static int sram_read(dev_link_t *link, char *buf, mtd_request_t *req)
+{
+    sram_dev_t *dev = (sram_dev_t *)link->priv;
+    region_info_t *region;
+    mtd_mod_win_t mod;
+    u_int from, length, nb;
+    int ret;
+    
+    DEBUG(1, "sram_read(0x%p, 0x%lx, 0x%p, 0x%x, 0x%x)\n", link,
+	  req->MediaID, buf, req->SrcCardOffset, req->TransferLength);
+
+    region = (region_info_t *)(req->MediaID);
+    if (region->Attributes & REGION_TYPE_AM)
+	mod.Attributes = WIN_MEMORY_TYPE_AM;
+    else
+	mod.Attributes = WIN_MEMORY_TYPE_CM;
+    mod.AccessSpeed = region->AccessSpeed;
+
+    mod.CardOffset = req->SrcCardOffset & ~(dev->Size-1);
+    from = req->SrcCardOffset & (dev->Size-1);
+    for (length = req->TransferLength; length > 0; length -= nb) {
+	ret = MTDHelperEntry(MTDModifyWindow, link->win, &mod);
+	if (ret != CS_SUCCESS) {
+	    cs_error(link->handle, MapMemPage, ret);
+	    return ret;
+	}
+	nb = (from+length > dev->Size) ? dev->Size-from : length;
+	
+	if (req->Function & MTD_REQ_KERNEL)
+	    copy_from_pc(buf, &dev->Base[from], nb);
+	else
+	    copy_pc_to_user(buf, dev->Base+from, nb);
+	buf += nb;
+	
+	from = 0;
+	mod.CardOffset += dev->Size;
+    }
+    return CS_SUCCESS;
+} /* sram_read */
+
+/*====================================================================*/
+
+static int sram_write(dev_link_t *link, char *buf, mtd_request_t *req)
+{
+    sram_dev_t *dev = (sram_dev_t *)link->priv;
+    mtd_mod_win_t mod;
+    region_info_t *region;
+    u_int from, length, nb;
+    cs_status_t status;
+    int ret;
+
+    DEBUG(1, "sram_write(0x%p, 0x%lx, 0x%p, 0x%x, 0x%x)\n", link,
+	  req->MediaID, buf, req->DestCardOffset, req->TransferLength);
+
+    /* Check card write protect status */
+    ret = CardServices(GetStatus, link->handle, &status);
+    if (ret != 0) {
+	cs_error(link->handle, GetStatus, ret);
+	return CS_GENERAL_FAILURE;
+    }
+    if (status.CardState & CS_EVENT_WRITE_PROTECT)
+	return CS_WRITE_PROTECTED;
+    
+    region = (region_info_t *)(req->MediaID);
+    if (region->Attributes & REGION_TYPE_AM)
+	mod.Attributes = WIN_MEMORY_TYPE_AM;
+    else
+	mod.Attributes = WIN_MEMORY_TYPE_CM;
+    mod.AccessSpeed = region->AccessSpeed;
+    
+    mod.CardOffset = req->DestCardOffset & ~(dev->Size-1);
+    from = req->DestCardOffset & (dev->Size-1);
+    for (length = req->TransferLength ; length > 0; length -= nb) {
+	ret = MTDHelperEntry(MTDModifyWindow, link->win, &mod);
+	if (ret != CS_SUCCESS) {
+	    cs_error(link->handle, MapMemPage, ret);
+	    return ret;
+	}
+	nb = (from+length > dev->Size) ? dev->Size-from : length;
+
+	if (req->Function & MTD_REQ_KERNEL)
+	    copy_to_pc(dev->Base+from, buf, nb);
+	else
+	    copy_user_to_pc(dev->Base+from, buf, nb);
+	buf += nb;
+	
+	from = 0;
+	mod.CardOffset += dev->Size;
+    }
+    return CS_SUCCESS;
+} /* sram_write */
+
+/*====================================================================*/
+
+#if 0
+static int sram_erase(dev_link_t *link, char *buf, mtd_request_t *req)
+{
+    DEBUG(1, "sram_erase(0x%p, 0x%lx, 0x%p, 0x%x, 0x%x)\n", link,
+	  req->MediaID, buf, req->DestCardOffset, req->TransferLength);
+
+    if (req->Function & MTD_REQ_TIMEOUT) {
+	DEBUG(2, "sram_erase: complete\n");
+	return CS_SUCCESS;
+    } else {
+	DEBUG(2, "sram_erase: starting\n");
+	req->Status = MTD_WAITTIMER;
+	req->Timeout = 10;
+	return CS_BUSY;
+    }
+    
+} /* sram_erase */
+#endif
+
+/*====================================================================*/
+
+static int sram_request(dev_link_t *link, void *buf, mtd_request_t *req)
+{
+    int ret = 0;
+    if (!(link->state & DEV_PRESENT))
+	return CS_NO_CARD;
+    switch (req->Function & MTD_REQ_ACTION) {
+    case MTD_REQ_READ:
+	ret = sram_read(link, buf, req);
+	break;
+    case MTD_REQ_WRITE:
+	ret = sram_write(link, buf, req);
+	break;
+    case MTD_REQ_ERASE:
+#if 0
+	ret = sram_erase(link, buf, req);
+#endif
+	ret = CS_UNSUPPORTED_FUNCTION;
+	break;
+    case MTD_REQ_COPY:
+	ret = CS_UNSUPPORTED_FUNCTION;
+	break;
+    }
+    if (!(link->state & DEV_PRESENT))
+	return CS_GENERAL_FAILURE;
+    return ret;
+} /* sram_request */
+
+/*======================================================================
+
+    The card status event handler.  Mostly, this schedules other
+    stuff to run after an event is received.  A CARD_REMOVAL event
+    also sets some flags to discourage the driver from trying to
+    talk to the card any more.
+    
+======================================================================*/
+
+static int sram_event(event_t event, int priority,
+		      event_callback_args_t *args)
+{
+    dev_link_t *link = args->client_data;
+
+    DEBUG(1, "sram_event(0x%06x)\n", event);
+    
+    switch (event) {
+	
+    case CS_EVENT_CARD_REMOVAL:
+	link->state &= ~DEV_PRESENT;
+	if (link->state & DEV_CONFIG)
+	    mod_timer(&link->release, jiffies + HZ/20);
+	break;
+	
+    case CS_EVENT_CARD_INSERTION:
+	link->state |= DEV_PRESENT | DEV_CONFIG_PENDING;
+	sram_config(link);
+	break;
+	
+    case CS_EVENT_PM_SUSPEND:
+	link->state |= DEV_SUSPEND;
+	/* Fall through... */
+    case CS_EVENT_RESET_PHYSICAL:
+	break;
+	
+    case CS_EVENT_PM_RESUME:
+	link->state &= ~DEV_SUSPEND;
+	/* Fall through... */
+    case CS_EVENT_CARD_RESET:
+	break;
+	
+    case CS_EVENT_MTD_REQUEST:
+	return sram_request(link, args->buffer, args->mtdrequest);
+	break;
+	
+    }
+    return CS_SUCCESS;
+} /* sram_event */
+
+/*====================================================================*/
+
+#ifdef __LINUX__
+
+static int __init init_sram_mtd(void)
+{
+    servinfo_t serv;
+    DEBUG(0, "%s\n", version);
+    CardServices(GetCardServicesInfo, &serv);
+    if (serv.Revision != CS_RELEASE_CODE) {
+	printk(KERN_NOTICE "sram_mtd: Card Services release "
+	       "does not match!\n");
+	return -1;
+    }
+    register_pccard_driver(&dev_info, &sram_attach, &sram_detach);
+    return 0;
+}
+
+static void __exit exit_sram_mtd(void)
+{
+    DEBUG(0, "sram_mtd: unloading\n");
+    unregister_pccard_driver(&dev_info);
+    while (dev_list != NULL)
+	sram_detach(dev_list);
+}
+
+module_init(init_sram_mtd);
+module_exit(exit_sram_mtd);
+
+#endif /* __LINUX__ */
+
+/*====================================================================*/
+
+#ifdef __BEOS__
+
+static status_t std_ops(int32 op)
+{
+    int ret;
+    DEBUG(0, "sram_mtd: std_ops(%d)\n", op);
+    switch (op) {
+    case B_MODULE_INIT:
+	ret = get_module(CS_CLIENT_MODULE_NAME, (struct module_info **)&cs);
+	if (ret != B_OK) return ret;
+	ret = get_module(DS_MODULE_NAME, (struct module_info **)&ds);
+	if (ret != B_OK) return ret;
+	ret = get_module(B_ISA_MODULE_NAME, (struct module_info **)&isa);
+	if (ret != B_OK) return ret;
+	register_pccard_driver(&dev_info, &sram_attach, &sram_detach);
+	break;
+    case B_MODULE_UNINIT:
+	unregister_pccard_driver(&dev_info);
+	while (dev_list != NULL)
+	    sram_detach(dev_list);
+	if (isa) put_module(B_ISA_MODULE_NAME);
+	if (ds) put_module(DS_MODULE_NAME);
+	if (cs) put_module(CS_CLIENT_MODULE_NAME);
+	break;
+    }
+    return B_OK;
+}
+
+static module_info sram_mtd_mod_info = {
+    MTD_MODULE_NAME("sram_mtd"), 0, &std_ops
+};
+
+_EXPORT module_info *modules[] = {
+    &sram_mtd_mod_info,
+    NULL
+};
+
+#endif /* __BEOS__ */
Index: oldkernel/linux/pcmcia-cs-3.1.15/clients/tulip_cb.c
diff -u /dev/null linux/pcmcia-cs-3.1.15/clients/tulip_cb.c:1.1
--- /dev/null	Mon Jul 31 21:15:10 2000
+++ linux/pcmcia-cs-3.1.15/clients/tulip_cb.c	Fri Jul  7 16:34:58 2000
@@ -0,0 +1,3599 @@
+/* tulip.c: A DEC 21040-family ethernet driver for Linux. */
+/*
+	Written/copyright 1994-1999 by Donald Becker.
+
+	This software may be used and distributed according to the terms
+	of the GNU Public License, incorporated herein by reference.
+
+	This driver is for the Digital "Tulip" Ethernet adapter interface.
+	It should work with most DEC 21*4*-based chips/ethercards, as well as
+	with work-alike chips from Lite-On (PNIC) and Macronix (MXIC) and ASIX.
+
+	The author may be reached as becker@CESDIS.gsfc.nasa.gov, or C/O
+	Center of Excellence in Space Data and Information Sciences
+	   Code 930.5, Goddard Space Flight Center, Greenbelt MD 20771
+
+	Support and updates available at
+	http://cesdis.gsfc.nasa.gov/linux/drivers/tulip.html
+*/
+
+#define SMP_CHECK
+static const char version[] = "tulip.c:v0.91g-ppc 7/16/99 becker@cesdis.gsfc.nasa.gov (modified by danilo@cs.uni-magdeburg.de for XIRCOM CBE, fixed by Doug Ledford)\n";
+
+/* A few user-configurable values. */
+
+/* Maximum events (Rx packets, etc.) to handle at each interrupt. */
+static int max_interrupt_work = 25;
+
+#define MAX_UNITS 8
+/* Used to pass the full-duplex flag, etc. */
+static int full_duplex[MAX_UNITS] = {0, };
+static int options[MAX_UNITS] = {0, };
+static int mtu[MAX_UNITS] = {0, };			/* Jumbo MTU for interfaces. */
+
+/*  The possible media types that can be set in options[] are: */
+static const char * const medianame[] = {
+	"10baseT", "10base2", "AUI", "100baseTx",
+	"10baseT-FD", "100baseTx-FD", "100baseT4", "100baseFx",
+	"100baseFx-FD", "MII 10baseT", "MII 10baseT-FD", "MII",
+	"10baseT(forced)", "MII 100baseTx", "MII 100baseTx-FD", "MII 100baseT4",
+};
+
+/* Set if the PCI BIOS detects the chips on a multiport board backwards. */
+#ifdef REVERSE_PROBE_ORDER
+static int reverse_probe = 1;
+#else
+static int reverse_probe = 0;
+#endif
+
+/* Keep the ring sizes a power of two for efficiency.
+   Making the Tx ring too large decreases the effectiveness of channel
+   bonding and packet priority.
+   There are no ill effects from too-large receive rings. */
+#define TX_RING_SIZE	16
+#define RX_RING_SIZE	32
+
+/* Set the copy breakpoint for the copy-only-tiny-buffer Rx structure. */
+#ifdef __alpha__
+static int rx_copybreak = 1518;
+#else
+static int rx_copybreak = 100;
+#endif
+
+/*
+  Set the bus performance register.
+	Typical: Set 16 longword cache alignment, no burst limit.
+	Cache alignment bits 15:14	     Burst length 13:8
+		0000	No alignment  0x00000000 unlimited		0800 8 longwords
+		4000	8  longwords		0100 1 longword		1000 16 longwords
+		8000	16 longwords		0200 2 longwords	2000 32 longwords
+		C000	32  longwords		0400 4 longwords
+	Warning: many older 486 systems are broken and require setting 0x00A04800
+	   8 longword cache alignment, 8 longword burst.
+	ToDo: Non-Intel setting could be better.
+*/
+
+#if defined(__alpha__)
+static int csr0 = 0x01A00000 | 0xE000;
+#elif defined(__i386__) || defined(__powerpc__) || defined(__sparc__)
+static int csr0 = 0x01A00000 | 0x8000;
+#else
+#warning Processor architecture undefined!
+static int csr0 = 0x00A00000 | 0x4800;
+#endif
+
+/* Operational parameters that usually are not changed. */
+/* Time in jiffies before concluding the transmitter is hung. */
+#define TX_TIMEOUT  (4*HZ)
+#define PKT_BUF_SZ		1536			/* Size of each temporary Rx buffer.*/
+/* This is a mysterious value that can be written to CSR11 in the 21040 (only)
+   to support a pre-NWay full-duplex signaling mechanism using short frames.
+   No one knows what it should be, but if left at its default value some
+   10base2(!) packets trigger a full-duplex-request interrupt. */
+#define FULL_DUPLEX_MAGIC	0x6969
+
+#if !defined(__OPTIMIZE__)  ||  !defined(__KERNEL__)
+#warning  You must compile this file with the correct options!
+#warning  See the last lines of the source file.
+#error You must compile this driver with "-O".
+#endif
+
+#include <linux/version.h>
+#ifdef MODULE
+#ifdef MODVERSIONS
+#include <linux/modversions.h>
+#endif
+#include <linux/module.h>
+#else
+#define MOD_INC_USE_COUNT
+#define MOD_DEC_USE_COUNT
+#endif
+
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/string.h>
+#include <linux/timer.h>
+#include <linux/errno.h>
+#include <linux/ioport.h>
+#include <linux/malloc.h>
+#include <linux/interrupt.h>
+#include <linux/pci.h>
+#include <linux/netdevice.h>
+#include <linux/etherdevice.h>
+#include <linux/skbuff.h>
+#include <linux/delay.h>
+#include <asm/processor.h>		/* Processor type for cache alignment. */
+#include <asm/bitops.h>
+#include <asm/io.h>
+#include <asm/unaligned.h>
+
+/* Kernel compatibility defines, some common to David Hinds' PCMCIA package.
+   This is only in the support-all-kernels source code. */
+
+#if defined(MODULE) && LINUX_VERSION_CODE > 0x20115
+MODULE_AUTHOR("Donald Becker <becker@cesdis.gsfc.nasa.gov>");
+MODULE_DESCRIPTION("Digital 21*4* Tulip ethernet driver");
+MODULE_PARM(debug, "i");
+MODULE_PARM(max_interrupt_work, "i");
+MODULE_PARM(reverse_probe, "i");
+MODULE_PARM(rx_copybreak, "i");
+MODULE_PARM(csr0, "i");
+MODULE_PARM(options, "1-" __MODULE_STRING(MAX_UNITS) "i");
+MODULE_PARM(full_duplex, "1-" __MODULE_STRING(MAX_UNITS) "i");
+#endif
+
+#define RUN_AT(x) (jiffies + (x))
+
+#if LINUX_VERSION_CODE < 0x20123
+#define hard_smp_processor_id() smp_processor_id()
+#define test_and_set_bit(val, addr) set_bit(val, addr)
+#define le16_to_cpu(val) (val)
+#define le32_to_cpu(val) (val)
+#define cpu_to_le32(val) (val)
+#endif
+#if LINUX_VERSION_CODE <= 0x20139
+#define	net_device_stats enet_statistics
+#else
+#define NETSTATS_VER2
+#endif
+#if LINUX_VERSION_CODE < 0x20155
+/* Grrrr, the PCI code changed, but did not consider CardBus... */
+#include <linux/bios32.h>
+#define PCI_SUPPORT_VER1
+#else
+#if LINUX_VERSION_CODE < 0x2030d
+#define PCI_SUPPORT_VER2
+#else
+#define PCI_SUPPORT_VER3
+#endif
+#endif
+#if LINUX_VERSION_CODE < 0x20159
+#define dev_free_skb(skb) dev_kfree_skb(skb, FREE_WRITE);
+#else
+#define dev_free_skb(skb) dev_kfree_skb(skb);
+#endif
+#if LINUX_VERSION_CODE < 0x2030e
+#define net_device device
+#endif
+#if ! defined(CAP_NET_ADMIN)
+#define capable(CAP_XXX) (suser())
+#endif
+#ifndef HAVE_NETIF_QUEUE
+#define netif_stop_queue(dev) set_bit(0, (void *)&(dev)->tbusy)
+#define netif_start_queue(dev) clear_bit(0, (void *)&(dev)->tbusy)
+#define netif_wake_queue(dev) \
+    do { netif_start_queue(dev); mark_bh(NET_BH); } while (0)
+#define netif_device_attach(dev) \
+    do { (dev)->start = 1; netif_start_queue(dev); } while (0)
+#define netif_device_detach(dev) \
+    do { (dev)->start = 0; netif_stop_queue(dev); } while (0)
+#define netif_device_present(dev) ((dev)->start)
+#define netif_running(dev) ((dev)->start)
+#define netif_mark_up(dev) do { (dev)->start = 1; } while (0)
+#define netif_mark_down(dev) do { (dev)->start = 0; } while (0)
+#define netif_queue_stopped(dev) ((dev)->tbusy)
+#define tx_timeout_check(dev, tx_timeout) \
+    do { if (test_and_set_bit(0, (void *)&(dev)->tbusy) != 0) { \
+	if (jiffies - (dev)->trans_start < TX_TIMEOUT) return 1; \
+	tx_timeout(dev); \
+    } } while (0)
+#define dev_kfree_skb_irq(skb) dev_free_skb(skb)
+#else
+#define tx_timeout_check(dev, handler) netif_stop_queue(dev)
+#define netif_mark_up(dev) do { } while (0)
+#define netif_mark_down(dev) do { } while (0)
+#endif
+
+/* Condensed operations for readability. */
+#define virt_to_le32desc(addr)  cpu_to_le32(virt_to_bus(addr))
+#define le32desc_to_virt(addr)  bus_to_virt(le32_to_cpu(addr))
+
+#define tulip_debug debug
+#ifdef TULIP_DEBUG
+static int tulip_debug = TULIP_DEBUG;
+#else
+static int tulip_debug = 1;
+#endif
+
+/*
+				Theory of Operation
+
+I. Board Compatibility
+
+This device driver is designed for the DECchip "Tulip", Digital's
+single-chip ethernet controllers for PCI.  Supported members of the family
+are the 21040, 21041, 21140, 21140A, 21142, and 21143.  Similar work-alike
+chips from Lite-On, Macronics, ASIX, Compex and other listed below are also
+supported. 
+
+These chips are used on at least 140 unique PCI board designs.  The great
+number of chips and board designs supported is the reason for the
+driver size and complexity.  Almost of the increasing complexity is in the
+board configuration and media selection code.  There is very little
+increasing in the operational critical path length.
+
+II. Board-specific settings
+
+PCI bus devices are configured by the system at boot time, so no jumpers
+need to be set on the board.  The system BIOS preferably should assign the
+PCI INTA signal to an otherwise unused system IRQ line.
+
+Some boards have EEPROMs tables with default media entry.  The factory default
+is usually "autoselect".  This should only be overridden when using
+transceiver connections without link beat e.g. 10base2 or AUI, or (rarely!)
+for forcing full-duplex when used with old link partners that do not do
+autonegotiation. 
+
+III. Driver operation
+
+IIIa. Ring buffers
+
+The Tulip can use either ring buffers or lists of Tx and Rx descriptors.
+This driver uses statically allocated rings of Rx and Tx descriptors, set at
+compile time by RX/TX_RING_SIZE.  This version of the driver allocates skbuffs
+for the Rx ring buffers at open() time and passes the skb->data field to the
+Tulip as receive data buffers.  When an incoming frame is less than
+RX_COPYBREAK bytes long, a fresh skbuff is allocated and the frame is
+copied to the new skbuff.  When the incoming frame is larger, the skbuff is
+passed directly up the protocol stack and replaced by a newly allocated
+skbuff.
+
+The RX_COPYBREAK value is chosen to trade-off the memory wasted by
+using a full-sized skbuff for small frames vs. the copying costs of larger
+frames.  For small frames the copying cost is negligible (esp. considering
+that we are pre-loading the cache with immediately useful header
+information).  For large frames the copying cost is non-trivial, and the
+larger copy might flush the cache of useful data.  A subtle aspect of this
+choice is that the Tulip only receives into longword aligned buffers, thus
+the IP header at offset 14 isn't longword aligned for further processing.
+Copied frames are put into the new skbuff at an offset of "+2", thus copying
+has the beneficial effect of aligning the IP header and preloading the
+cache.
+
+IIIC. Synchronization
+The driver runs as two independent, single-threaded flows of control.
+One is the send-packet routine, which is single threaded by the tx
+queue layer.  The other thread is the interrupt handler, which is
+single threaded by the hardware and other software.
+
+The send packet thread has partial control over the Tx ring and tx
+queue status.  It stops the tx queue whenever it's queuing a Tx
+packet. If the next queue slot is empty, it starts the tx queue when
+finished otherwise it sets the 'tp->tx_full' flag.
+
+The interrupt handler has exclusive control over the Rx ring and records stats
+from the Tx ring.  (The Tx-done interrupt can't be selectively turned off, so
+we can't avoid the interrupt overhead by having the Tx routine reap the Tx
+stats.)	 After reaping the stats, it marks the queue entry as empty by setting
+the 'base' to zero.	 Iff the 'tp->tx_full' flag is set, it clears the
+flag and restarts the tx queue.
+
+IV. Notes
+
+Thanks to Duke Kamstra of SMC for long ago providing an EtherPower board.
+Greg LaPolla at Linksys provided PNIC and other Linksys boards.
+Znyx provided a four-port card for testing.
+
+IVb. References
+
+http://cesdis.gsfc.nasa.gov/linux/misc/NWay.html
+http://www.digital.com  (search for current 21*4* datasheets and "21X4 SROM")
+http://www.national.com/pf/DP/DP83840A.html
+http://www.asix.com.tw/pmac.htm
+http://www.admtek.com.tw/
+
+IVc. Errata
+
+The old DEC databooks were light on details.
+The 21040 databook claims that CSR13, CSR14, and CSR15 should each be the last
+register of the set CSR12-15 written.  Hmmm, now how is that possible?
+
+The DEC SROM format is very badly designed not precisely defined, leading to
+part of the media selection junkheap below.  Some boards do not have EEPROM
+media tables and need to be patched up.  Worse, other boards use the DEC
+design kit media table when it isn't correct for their board.
+
+We cannot use MII interrupts because there is no defined GPIO pin to attach
+them.  The MII transceiver status is polled using an kernel timer.
+
+*/
+
+static struct net_device *
+tulip_probe1(int pci_bus, int pci_devfn, struct net_device *dev, long ioaddr,
+			 int irq, int chip_idx, int board_idx);
+
+/* This table drives the PCI probe routines.  It's mostly boilerplate in all
+   of the drivers, and will likely be provided by some future kernel.
+   Note the matching code -- the first table entry matchs all 56** cards but
+   second only the 1234 card.
+*/
+enum pci_flags_bit {
+	PCI_USES_IO=1, PCI_USES_MEM=2, PCI_USES_MASTER=4,
+	PCI_ADDR0=0x10<<0, PCI_ADDR1=0x10<<1, PCI_ADDR2=0x10<<2, PCI_ADDR3=0x10<<3,
+};
+#define PCI_ADDR0_IO (PCI_USES_IO|PCI_ADDR0)
+
+struct pci_id_info {
+	const char *name;
+	u16	vendor_id, device_id, device_id_mask, flags;
+	int io_size, min_latency;
+	struct net_device *(*probe1)(int pci_bus, int pci_devfn, struct net_device *dev,
+							 long ioaddr, int irq, int chip_idx, int fnd_cnt);
+};
+#ifndef CARDBUS
+static struct pci_id_info pci_tbl[] = {
+  { "Digital DC21040 Tulip",
+	0x1011, 0x0002, 0xffff, PCI_ADDR0_IO, 128, 32, tulip_probe1 },
+  { "Digital DC21041 Tulip",
+	0x1011, 0x0014, 0xffff, PCI_ADDR0_IO, 128, 32, tulip_probe1 },
+  { "Digital DS21140 Tulip",
+	0x1011, 0x0009, 0xffff, PCI_ADDR0_IO, 128, 32, tulip_probe1 },
+  { "Digital DS21143 Tulip",
+	0x1011, 0x0019, 0xffff, PCI_ADDR0_IO, 128, 32, tulip_probe1 },
+  { "Lite-On 82c168 PNIC",
+	0x11AD, 0x0002, 0xffff, PCI_ADDR0_IO, 256, 32, tulip_probe1 },
+  { "Macronix 98713 PMAC",
+	0x10d9, 0x0512, 0xffff, PCI_ADDR0_IO, 256, 32, tulip_probe1 },
+  { "Macronix 98715 PMAC",
+	0x10d9, 0x0531, 0xffff, PCI_ADDR0_IO, 256, 32, tulip_probe1 },
+  { "Macronix 98725 PMAC",
+	0x10d9, 0x0531, 0xffff, PCI_ADDR0_IO, 256, 32, tulip_probe1 },
+  { "ASIX AX88140",
+	0x125B, 0x1400, 0xffff, PCI_ADDR0_IO, 128, 32, tulip_probe1 },
+  { "Lite-On LC82C115 PNIC-II",
+	0x11AD, 0xc115, 0xffff, PCI_ADDR0_IO, 256, 32, tulip_probe1 },
+  { "ADMtek AN981 Comet",
+	0x1317, 0x0981, 0xffff, PCI_ADDR0_IO, 256, 32, tulip_probe1 },
+  { "Compex RL100-TX",
+	0x11F6, 0x9881, 0xffff, PCI_ADDR0_IO, 128, 32, tulip_probe1 },
+  { "Intel 21145 Tulip",
+	0x8086, 0x0039, 0xffff, PCI_ADDR0_IO, 128, 32, tulip_probe1 },
+  { "Xircom Tulip clone",
+	0x115d, 0x0003, 0xffff, PCI_ADDR0_IO, 128, 32, tulip_probe1 },
+  {0},
+};
+#endif /* !CARD_BUS */
+
+/* This table use during operation for capabilities and media timer. */
+
+static void tulip_timer(unsigned long data);
+static void t21142_timer(unsigned long data);
+static void mxic_timer(unsigned long data);
+static void pnic_timer(unsigned long data);
+static void comet_timer(unsigned long data);
+
+enum tbl_flag {
+	HAS_MII=1, HAS_MEDIA_TABLE=2, CSR12_IN_SROM=4, ALWAYS_CHECK_MII=8,
+	HAS_PWRDWN=0x10, MC_HASH_ONLY=0x20, /* Hash-only multicast filter. */
+	HAS_PNICNWAY=0x80, HAS_NWAY143=0x40,	/* Uses internal NWay xcvr. */
+	HAS_8023X=0x100,
+};
+static struct tulip_chip_table {
+	char *chip_name;
+	int io_size;
+	int valid_intrs;			/* CSR7 interrupt enable settings */
+	int flags;
+	void (*media_timer)(unsigned long data);
+} tulip_tbl[] = {
+  { "Digital DC21040 Tulip", 128, 0x0001ebef, 0, tulip_timer },
+  { "Digital DC21041 Tulip", 128, 0x0001ebff, HAS_MEDIA_TABLE, tulip_timer },
+  { "Digital DS21140 Tulip", 128, 0x0001ebef,
+	HAS_MII | HAS_MEDIA_TABLE | CSR12_IN_SROM, tulip_timer },
+  { "Digital DS21143 Tulip", 128, 0x0801fbff,
+	HAS_MII | HAS_MEDIA_TABLE | ALWAYS_CHECK_MII | HAS_PWRDWN | HAS_NWAY143,
+	t21142_timer },
+  { "Lite-On 82c168 PNIC", 256, 0x0001ebef,
+	HAS_MII | HAS_PNICNWAY, pnic_timer },
+  { "Macronix 98713 PMAC", 128, 0x0001ebef,
+	HAS_MII | HAS_MEDIA_TABLE | CSR12_IN_SROM, mxic_timer },
+  { "Macronix 98715 PMAC", 256, 0x0001ebef,
+	HAS_MEDIA_TABLE, mxic_timer },
+  { "Macronix 98725 PMAC", 256, 0x0001ebef,
+	HAS_MEDIA_TABLE, mxic_timer },
+  { "ASIX AX88140", 128, 0x0001fbff,
+	HAS_MII | HAS_MEDIA_TABLE | CSR12_IN_SROM | MC_HASH_ONLY, tulip_timer },
+  { "Lite-On PNIC-II", 256, 0x0801fbff,
+	HAS_MII | HAS_NWAY143 | HAS_8023X, t21142_timer },
+  { "ADMtek Comet", 256, 0x0001abef,
+	MC_HASH_ONLY, comet_timer },
+  { "Compex 9881 PMAC", 128, 0x0001ebef,
+	HAS_MII | HAS_MEDIA_TABLE | CSR12_IN_SROM, mxic_timer },
+  { "Intel DS21145 Tulip", 128, 0x0801fbff,
+	HAS_MII | HAS_MEDIA_TABLE | ALWAYS_CHECK_MII | HAS_PWRDWN | HAS_NWAY143,
+	t21142_timer },
+  { "Xircom tulip work-alike", 128, 0x0801fbff,
+	HAS_MII | HAS_MEDIA_TABLE | ALWAYS_CHECK_MII | HAS_PWRDWN | HAS_NWAY143,
+	t21142_timer },
+  { "Xircom Cardbus Adapter (DEC 21143 compatible mode)", 128, 0x0801fbff,
+       HAS_MII | HAS_PWRDWN, tulip_timer }, 
+  {0},
+};
+/* This matches the table above.  Note 21142 == 21143. */
+enum chips {
+	DC21040=0, DC21041=1, DC21140=2, DC21142=3, DC21143=3,
+	LC82C168, MX98713, MX98715, MX98725, AX88140, PNIC2, COMET, COMPEX9881,
+	I21145, X21142, X3201_3,
+};
+
+/* A full-duplex map for media types. */
+enum MediaIs {
+	MediaIsFD = 1, MediaAlwaysFD=2, MediaIsMII=4, MediaIsFx=8,
+	MediaIs100=16};
+static const char media_cap[] =
+{0,0,0,16,  3,19,16,24,  27,4,7,5, 0,20,23,20 };
+static u8 t21040_csr13[] = {2,0x0C,8,4,  4,0,0,0, 0,0,0,0, 4,0,0,0};
+/* 21041 transceiver register settings: 10-T, 10-2, AUI, 10-T, 10T-FD*/
+static u16 t21041_csr13[] = { 0xEF01, 0xEF09, 0xEF09, 0xEF01, 0xEF09, };
+static u16 t21041_csr14[] = { 0xFFFF, 0xF7FD, 0xF7FD, 0x7F3F, 0x7F3D, };
+static u16 t21041_csr15[] = { 0x0008, 0x0006, 0x000E, 0x0008, 0x0008, };
+
+static u16 t21142_csr13[] = { 0x0001, 0x0009, 0x0009, 0x0000, 0x0001, };
+static u16 t21142_csr14[] = { 0xFFFF, 0x0705, 0x0705, 0x0000, 0x7F3D, };
+static u16 t21142_csr15[] = { 0x0008, 0x0006, 0x000E, 0x0008, 0x0008, };
+
+/* Offsets to the Command and Status Registers, "CSRs".  All accesses
+   must be longword instructions and quadword aligned. */
+enum tulip_offsets {
+	CSR0=0,    CSR1=0x08, CSR2=0x10, CSR3=0x18, CSR4=0x20, CSR5=0x28,
+	CSR6=0x30, CSR7=0x38, CSR8=0x40, CSR9=0x48, CSR10=0x50, CSR11=0x58,
+	CSR12=0x60, CSR13=0x68, CSR14=0x70, CSR15=0x78 };
+
+/* The bits in the CSR5 status registers, mostly interrupt sources. */
+enum status_bits {
+	TimerInt=0x800, SytemError=0x2000, TPLnkFail=0x1000, TPLnkPass=0x10,
+	NormalIntr=0x10000, AbnormalIntr=0x8000,
+	RxJabber=0x200, RxDied=0x100, RxNoBuf=0x80, RxIntr=0x40,
+	TxFIFOUnderflow=0x20, TxJabber=0x08, TxNoBuf=0x04, TxDied=0x02, TxIntr=0x01,
+};
+
+/* The Tulip Rx and Tx buffer descriptors. */
+struct tulip_rx_desc {
+	s32 status;
+	s32 length;
+	u32 buffer1, buffer2;
+};
+
+struct tulip_tx_desc {
+	s32 status;
+	s32 length;
+	u32 buffer1, buffer2;				/* We use only buffer 1.  */
+};
+
+enum desc_status_bits {
+	DescOwned=0x80000000, RxDescFatalErr=0x8000, RxWholePkt=0x0300,
+};
+
+/* Ring-wrap flag in length field, use for last ring entry.
+	0x01000000 means chain on buffer2 address,
+	0x02000000 means use the ring start address in CSR2/3.
+   Note: Some work-alike chips do not function correctly in chained mode.
+   The ASIX chip works only in chained mode.
+   Thus we indicates ring mode, but always write the 'next' field for
+   chained mode as well.
+*/
+#define DESC_RING_WRAP 0x02000000
+
+#define EEPROM_SIZE 128 	/* 2 << EEPROM_ADDRLEN */
+
+struct medialeaf {
+	u8 type;
+	u8 media;
+	unsigned char *leafdata;
+};
+
+struct mediatable {
+	u16 defaultmedia;
+	u8 leafcount, csr12dir;				/* General purpose pin directions. */
+	unsigned has_mii:1, has_nonmii:1, has_reset:6;
+	u32 csr15dir, csr15val;				/* 21143 NWay setting. */
+	struct medialeaf mleaf[0];
+};
+
+struct mediainfo {
+	struct mediainfo *next;
+	int info_type;
+	int index;
+	unsigned char *info;
+};
+
+struct tulip_private {
+	char devname[8];			/* Used only for kernel debugging. */
+	const char *product_name;
+	struct net_device *next_module;
+	struct tulip_rx_desc rx_ring[RX_RING_SIZE];
+	struct tulip_tx_desc tx_ring[TX_RING_SIZE];
+	/* The saved address of a sent-in-place packet/buffer, for skfree(). */
+	struct sk_buff* tx_skbuff[TX_RING_SIZE];
+#ifdef CARDBUS
+	/* The X3201-3 requires double word aligned tx bufs */
+	struct sk_buff* tx_aligned_skbuff[TX_RING_SIZE];
+#endif
+	/* The addresses of receive-in-place skbuffs. */
+	struct sk_buff* rx_skbuff[RX_RING_SIZE];
+	void *priv_addr;
+	char *rx_buffs;				/* Address of temporary Rx buffers. */
+	u8 setup_buf[96*sizeof(u16) + 7];
+	u16 *setup_frame;		/* Pseudo-Tx frame to init address table. */
+	int chip_id;
+	int revision;
+	int flags;
+	struct net_device_stats stats;
+	struct timer_list timer;	/* Media selection timer. */
+	unsigned int cur_rx, cur_tx;		/* The next free ring entry */
+	unsigned int dirty_rx, dirty_tx;	/* The ring entries to be free()ed. */
+	unsigned int tx_full:1;				/* The Tx queue is full. */
+	unsigned int full_duplex:1;			/* Full-duplex operation requested. */
+	unsigned int full_duplex_lock:1;
+	unsigned int fake_addr:1;			/* Multiport board faked address. */
+	unsigned int default_port:4;		/* Last dev->if_port value. */
+	unsigned int media2:4;				/* Secondary monitored media port. */
+	unsigned int medialock:1;			/* Don't sense media type. */
+	unsigned int mediasense:1;			/* Media sensing in progress. */
+	unsigned int nway:1, nwayset:1;		/* 21143 internal NWay. */
+	unsigned int open:1;
+	unsigned int reap:1;
+	unsigned int csr0;					/* CSR0 setting. */
+	unsigned int csr6;					/* Current CSR6 control settings. */
+	unsigned char eeprom[EEPROM_SIZE];	/* Serial EEPROM contents. */
+	void (*link_change)(struct net_device *dev, int csr5);
+	u16 to_advertise;					/* NWay capabilities advertised.  */
+	u16 lpar;							/* 21143 Link partner ability. */
+	u16 advertising[4];
+	signed char phys[4], mii_cnt;		/* MII device addresses. */
+	struct mediatable *mtable;
+	int cur_index;						/* Current media index. */
+	int saved_if_port;
+	unsigned char pci_bus, pci_devfn;
+	int ttimer;
+	int susp_rx;
+	unsigned long nir;
+	int pad0, pad1;						/* Used for 8-byte alignment */
+};
+
+static void parse_eeprom(struct net_device *dev);
+static int read_eeprom(long ioaddr, int location, int addr_len);
+static int mdio_read(struct net_device *dev, int phy_id, int location);
+static void mdio_write(struct net_device *dev, int phy_id, int location, int value);
+static void select_media(struct net_device *dev, int startup);
+static void tulip_up(struct net_device *dev);
+static void tulip_down(struct net_device *dev);
+static int tulip_open(struct net_device *dev);
+/* Chip-specific media selection (timer functions prototyped above). */
+static void t21142_lnk_change(struct net_device *dev, int csr5);
+static void t21142_start_nway(struct net_device *dev);
+static void pnic_lnk_change(struct net_device *dev, int csr5);
+static void pnic_do_nway(struct net_device *dev);
+
+static void tulip_tx_timeout(struct net_device *dev);
+static void tulip_init_ring(struct net_device *dev);
+static int tulip_start_xmit(struct sk_buff *skb, struct net_device *dev);
+static int tulip_refill_rx(struct net_device *dev);
+static int tulip_rx(struct net_device *dev);
+static void tulip_interrupt(int irq, void *dev_instance, struct pt_regs *regs);
+static int tulip_close(struct net_device *dev);
+static struct net_device_stats *tulip_get_stats(struct net_device *dev);
+#ifdef HAVE_PRIVATE_IOCTL
+static int private_ioctl(struct net_device *dev, struct ifreq *rq, int cmd);
+#endif
+static void set_rx_mode(struct net_device *dev);
+
+
+
+/* The Xircom cards are picky about when certain bits in CSR6 can be
+   manipulated.  Keith Owens <kaos@ocs.com.au>. */
+
+static void outl_CSR6 (u32 newcsr6, long ioaddr, int chip_idx)
+{
+	const int strict_bits = 0x0060e202;
+    int csr5, csr5_22_20, csr5_19_17, currcsr6, attempts = 200;
+    long flags;
+    save_flags(flags);
+    cli();
+    if (chip_idx != X3201_3) {
+		outl(newcsr6, ioaddr + CSR6);
+		restore_flags(flags);
+		return;
+    }
+    newcsr6 &= 0x726cfeca; /* mask out the reserved CSR6 bits that always */
+			   /* read 0 on the Xircom cards */
+    newcsr6 |= 0x320c0000; /* or in the reserved bits that always read 1 */
+    currcsr6 = inl(ioaddr + CSR6);
+    if (((newcsr6 & strict_bits) == (currcsr6 & strict_bits)) ||
+	((currcsr6 & ~0x2002) == 0)) {
+		outl(newcsr6, ioaddr + CSR6);	/* safe */
+		restore_flags(flags);
+		return;
+    }
+    /* make sure the transmitter and receiver are stopped first */
+    currcsr6 &= ~0x2002;
+    while (1) {
+		csr5 = inl(ioaddr + CSR5);
+		if (csr5 == 0xffffffff)
+			break;  /* cannot read csr5, card removed? */
+		csr5_22_20 = csr5 & 0x700000;
+		csr5_19_17 = csr5 & 0x0e0000;
+		if ((csr5_22_20 == 0 || csr5_22_20 == 0x600000) &&
+			(csr5_19_17 == 0 || csr5_19_17 == 0x80000 || csr5_19_17 == 0xc0000))
+			break;  /* both are stopped or suspended */
+		if (!--attempts) {
+			printk(KERN_INFO "tulip.c: outl_CSR6 too many attempts,"
+				   "csr5=0x%08x\n", csr5);
+			outl(newcsr6, ioaddr + CSR6);  /* unsafe but do it anyway */
+			restore_flags(flags);
+			return;
+		}
+		outl(currcsr6, ioaddr + CSR6);
+		udelay(1);
+    }
+    /* now it is safe to change csr6 */
+    outl(newcsr6, ioaddr + CSR6);
+    restore_flags(flags);
+}
+
+
+/* A list of all installed Tulip devices. */
+static struct net_device *root_tulip_dev = NULL;
+
+#ifndef CARDBUS
+int tulip_probe(struct net_device *dev)
+{
+	int cards_found = 0;
+	int pci_index = 0;
+	unsigned char pci_bus, pci_device_fn;
+
+	if ( ! pcibios_present())
+		return -ENODEV;
+
+	for (;pci_index < 0xff; pci_index++) {
+		u16 vendor, device, pci_command, new_command;
+		int chip_idx;
+		int irq;
+		long ioaddr;
+
+		if (pcibios_find_class
+			(PCI_CLASS_NETWORK_ETHERNET << 8,
+			 reverse_probe ? 0xfe - pci_index : pci_index,
+			 &pci_bus, &pci_device_fn) != PCIBIOS_SUCCESSFUL) {
+			if (reverse_probe)
+				continue;
+			else
+				break;
+		}
+		pcibios_read_config_word(pci_bus, pci_device_fn,
+								 PCI_VENDOR_ID, &vendor);
+		pcibios_read_config_word(pci_bus, pci_device_fn,
+								 PCI_DEVICE_ID, &device);
+
+		for (chip_idx = 0; pci_tbl[chip_idx].vendor_id; chip_idx++)
+			if (vendor == pci_tbl[chip_idx].vendor_id
+				&& (device & pci_tbl[chip_idx].device_id_mask) ==
+				pci_tbl[chip_idx].device_id)
+				break;
+		if (pci_tbl[chip_idx].vendor_id == 0)
+			continue;
+
+		{
+#if defined(PCI_SUPPORT_VER2)
+			struct pci_dev *pdev = pci_find_slot(pci_bus, pci_device_fn);
+			ioaddr = pdev->base_address[0] & ~3;
+			irq = pdev->irq;
+#elif defined(PCI_SUPPORT_VER3)
+			struct pci_dev *pdev = pci_find_slot(pci_bus, pci_device_fn);
+			ioaddr = pdev->resource[0].start;
+			irq = pdev->irq;
+#else
+			u32 pci_ioaddr;
+			u8 pci_irq_line;
+			pcibios_read_config_dword(pci_bus, pci_device_fn,
+									  PCI_BASE_ADDRESS_0, &pci_ioaddr);
+			pcibios_read_config_byte(pci_bus, pci_device_fn,
+									 PCI_INTERRUPT_LINE, &pci_irq_line);
+			ioaddr = pci_ioaddr & ~3;
+			irq = pci_irq_line;
+#endif
+		}
+
+		if (debug > 2)
+			printk(KERN_INFO "Found %s at PCI I/O address %#lx.\n",
+				   pci_tbl[chip_idx].name, ioaddr);
+
+		if (check_region(ioaddr, pci_tbl[chip_idx].io_size))
+			continue;
+
+		pcibios_read_config_word(pci_bus, pci_device_fn,
+								 PCI_COMMAND, &pci_command);
+		new_command = pci_command | PCI_COMMAND_MASTER|PCI_COMMAND_IO;
+		if (pci_command != new_command) {
+			printk(KERN_INFO "  The PCI BIOS has not enabled the"
+				   " device at %d/%d!  Updating PCI command %4.4x->%4.4x.\n",
+				   pci_bus, pci_device_fn, pci_command, new_command);
+			pcibios_write_config_word(pci_bus, pci_device_fn,
+									  PCI_COMMAND, new_command);
+		}
+
+		dev = pci_tbl[chip_idx].probe1(pci_bus, pci_device_fn, dev, ioaddr,
+									   irq, chip_idx, cards_found);
+
+		/* Get and check the bus-master and latency values. */
+		if (dev) {
+			u8 pci_latency;
+			pcibios_read_config_byte(pci_bus, pci_device_fn,
+									 PCI_LATENCY_TIMER, &pci_latency);
+			if (pci_latency < 10) {
+				printk(KERN_INFO "  PCI latency timer (CFLT) is "
+					   "unreasonably low at %d.  Setting to 64 clocks.\n",
+					   pci_latency);
+				pcibios_write_config_byte(pci_bus, pci_device_fn,
+										  PCI_LATENCY_TIMER, 64);
+			}
+		}
+		dev = 0;
+		cards_found++;
+	}
+
+	return cards_found ? 0 : -ENODEV;
+}
+#endif  /* not CARDBUS */
+
+static struct net_device *tulip_probe1(int pci_bus, int pci_devfn,
+								   struct net_device *dev, long ioaddr, int irq,
+								   int chip_idx, int board_idx)
+{
+	static int did_version = 0;			/* Already printed version info. */
+	struct tulip_private *tp;
+	/* See note below on the multiport cards. */
+	static unsigned char last_phys_addr[6] = {0x00, 'L', 'i', 'n', 'u', 'x'};
+	static int last_irq = 0;
+	static int multiport_cnt = 0;		/* For four-port boards w/one EEPROM */
+	u8 chip_rev;
+	int i;
+	unsigned short sum;
+	u8 ee_data[EEPROM_SIZE];
+
+	if (tulip_debug > 0  &&  did_version++ == 0)
+		printk(KERN_INFO "%s", version);
+
+	dev = init_etherdev(dev, 0);
+
+	/* Make certain the data structures are quadword aligned. */
+	{
+		void *mem = kmalloc(sizeof(*tp) + 7, GFP_KERNEL | GFP_DMA);
+		tp = (void *)(((long)mem + 7) & ~7);
+		memset(tp, 0, sizeof(*tp));
+		tp->priv_addr = mem;
+	}
+	dev->priv = tp;
+
+	tp->next_module = root_tulip_dev;
+	root_tulip_dev = dev;
+
+	pcibios_read_config_byte(pci_bus, pci_devfn, PCI_REVISION_ID, &chip_rev);
+
+	/* Bring the 21041/21143 out of sleep mode.
+	   Caution: Snooze mode does not work with some boards! */
+	if (tulip_tbl[chip_idx].flags & HAS_PWRDWN)
+		pcibios_write_config_dword(pci_bus, pci_devfn, 0x40, 0x00000000);
+
+	printk(KERN_INFO "%s: %s rev %d at %#3lx,",
+		   dev->name, tulip_tbl[chip_idx].chip_name, chip_rev, ioaddr);
+
+	/* Stop the chip's Tx and Rx processes. */
+	outl_CSR6(inl(ioaddr + CSR6) & ~0x2002, ioaddr, chip_idx);
+	/* Clear the missed-packet counter. */
+	(volatile int)inl(ioaddr + CSR8);
+
+	if (chip_idx == DC21041  &&  inl(ioaddr + CSR9) & 0x8000) {
+		printk(" 21040 compatible mode,");
+		chip_idx = DC21040;
+	}
+
+	/* The station address ROM is read byte serially.  The register must
+	   be polled, waiting for the value to be read bit serially from the
+	   EEPROM.
+	   */
+	sum = 0;
+	if (chip_idx == DC21040) {
+		outl(0, ioaddr + CSR9);		/* Reset the pointer with a dummy write. */
+		for (i = 0; i < 6; i++) {
+			int value, boguscnt = 100000;
+			do
+				value = inl(ioaddr + CSR9);
+			while (value < 0  && --boguscnt > 0);
+			dev->dev_addr[i] = value;
+			sum += value & 0xff;
+		}
+	} else if (chip_idx == LC82C168) {
+		for (i = 0; i < 3; i++) {
+			int value, boguscnt = 100000;
+			outl(0x600 | i, ioaddr + 0x98);
+			do
+				value = inl(ioaddr + CSR9);
+			while (value < 0  && --boguscnt > 0);
+			put_unaligned(le16_to_cpu(value), ((u16*)dev->dev_addr) + i);
+			sum += value & 0xffff;
+		}
+	} else if (chip_idx == COMET) {
+		/* No need to read the EEPROM. */
+		put_unaligned(inl(ioaddr + 0xA4), (u32 *)dev->dev_addr);
+		put_unaligned(inl(ioaddr + 0xA8), (u16 *)(dev->dev_addr + 4));
+		for (i = 0; i < 6; i ++)
+			sum += dev->dev_addr[i];
+	} else if (chip_idx == X3201_3) {
+		/* Xircom has its address stored in the CIS
+		 * we access it through the boot rom interface for now
+		 * this might not work, as the CIS is not parsed but I
+		 * (danilo) use the offset I found on my card's CIS !!!
+		 * 
+		 * Doug Ledford: I changed this routine around so that it
+		 * walks the CIS memory space, parsing the config items, and
+		 * finds the proper lan_node_id tuple and uses the data
+		 * stored there.
+		 */
+		unsigned char j, tuple, link, data_id, data_count;
+		outl(1<<12, ioaddr + CSR9); /* enable boot rom access */
+		for (i = 0x100; i < 0x1f7; i += link+2) {
+			outl(i, ioaddr + CSR10);
+			tuple = inl(ioaddr + CSR9) & 0xff;
+			outl(i + 1, ioaddr + CSR10);
+			link = inl(ioaddr + CSR9) & 0xff;
+			outl(i + 2, ioaddr + CSR10);
+			data_id = inl(ioaddr + CSR9) & 0xff;
+			outl(i + 3, ioaddr + CSR10);
+			data_count = inl(ioaddr + CSR9) & 0xff;
+			if ( (tuple == 0x22) &&
+				 (data_id == 0x04) && (data_count == 0x06) ) {
+				/*
+				 * This is it.  We have the data we want.
+				 */
+				for (j = 0; j < 6; j++) {
+					outl(i + j + 4, ioaddr + CSR10);
+					dev->dev_addr[j] = inl(ioaddr + CSR9) & 0xff;
+				}
+				break;
+			} else if (link == 0) {
+				break;
+			}
+		}
+		sum = 1; // to make check below fail!
+	} else {
+		/* A serial EEPROM interface, we read now and sort it out later. */
+		int sa_offset = 0;
+		int ee_addr_size = read_eeprom(ioaddr, 0xff, 8) & 0x40000 ? 8 : 6;
+
+		for (i = 0; i < sizeof(ee_data)/2; i++)
+			((u16 *)ee_data)[i] =
+				le16_to_cpu(read_eeprom(ioaddr, i, ee_addr_size));
+
+		/* DEC now has a specificiation (see Notes) but early board makers
+		   just put the address in the first EEPROM locations. */
+		/* This does  memcmp(eedata, eedata+16, 8) */
+		for (i = 0; i < 8; i ++)
+			if (ee_data[i] != ee_data[16+i])
+				sa_offset = 20;
+		if (ee_data[0] == 0xff  &&  ee_data[1] == 0xff &&  ee_data[2] == 0) {
+			sa_offset = 2;		/* Grrr, damn Matrox boards. */
+			multiport_cnt = 4;
+		}
+		for (i = 0; i < 6; i ++) {
+			dev->dev_addr[i] = ee_data[i + sa_offset];
+			sum += ee_data[i + sa_offset];
+		}
+	}
+	/* Lite-On boards have the address byte-swapped. */
+	if ((dev->dev_addr[0] == 0xA0  ||  dev->dev_addr[0] == 0xC0)
+		&&  dev->dev_addr[1] == 0x00)
+		for (i = 0; i < 6; i+=2) {
+			char tmp = dev->dev_addr[i];
+			dev->dev_addr[i] = dev->dev_addr[i+1];
+			dev->dev_addr[i+1] = tmp;
+		}
+	/* On the Zynx 315 Etherarray and other multiport boards only the
+	   first Tulip has an EEPROM.
+	   The addresses of the subsequent ports are derived from the first.
+	   Many PCI BIOSes also incorrectly report the IRQ line, so we correct
+	   that here as well. */
+	if (sum == 0  || sum == 6*0xff) {
+		printk(" EEPROM not present,");
+		for (i = 0; i < 5; i++)
+			dev->dev_addr[i] = last_phys_addr[i];
+		dev->dev_addr[i] = last_phys_addr[i] + 1;
+#if defined(__i386__)		/* Patch up x86 BIOS bug. */
+		if (last_irq)
+			irq = last_irq;
+#endif
+	}
+
+	for (i = 0; i < 6; i++)
+		printk("%c%2.2X", i ? ':' : ' ', last_phys_addr[i] = dev->dev_addr[i]);
+	printk(", IRQ %d.\n", irq);
+	last_irq = irq;
+
+	/* We do a request_region() only to register /proc/ioports info. */
+	/* Note that proper size is tulip_tbl[chip_idx].chip_name, but... */
+	request_region(ioaddr, tulip_tbl[chip_idx].io_size, dev->name);
+
+	dev->base_addr = ioaddr;
+	dev->irq = irq;
+
+	tp->pci_bus = pci_bus;
+	tp->pci_devfn = pci_devfn;
+	tp->chip_id = chip_idx;
+	tp->revision = chip_rev;
+	tp->flags = tulip_tbl[chip_idx].flags;
+	tp->csr0 = csr0;
+	tp->setup_frame = (u16 *)(((unsigned long)tp->setup_buf + 7) & ~7);
+
+	/* BugFixes: The 21143-TD hangs with PCI Write-and-Invalidate cycles.
+	   And the ASIX must have a burst limit or horrible things happen. */
+	if ((chip_idx == DC21143 && chip_rev == 65) || (chip_idx == X3201_3))
+		tp->csr0 &= ~0x01000000;
+	else if (chip_idx == AX88140)
+		tp->csr0 |= 0x2000;
+
+#ifdef TULIP_FULL_DUPLEX
+	tp->full_duplex = 1;
+	tp->full_duplex_lock = 1;
+#endif
+#ifdef TULIP_DEFAULT_MEDIA
+	tp->default_port = TULIP_DEFAULT_MEDIA;
+#endif
+#ifdef TULIP_NO_MEDIA_SWITCH
+	tp->medialock = 1;
+#endif
+
+	/* The lower four bits are the media type. */
+	if (board_idx >= 0  &&  board_idx < MAX_UNITS) {
+		tp->default_port = options[board_idx] & 15;
+		if ((options[board_idx] & 0x90) || full_duplex[board_idx] > 0)
+			tp->full_duplex = 1;
+		if (mtu[board_idx] > 0)
+			dev->mtu = mtu[board_idx];
+	}
+	if (dev->mem_start)
+		tp->default_port = dev->mem_start;
+	if (tp->default_port) {
+		tp->medialock = 1;
+		if (media_cap[tp->default_port] & MediaAlwaysFD)
+			tp->full_duplex = 1;
+	}
+	if (tp->full_duplex)
+		tp->full_duplex_lock = 1;
+
+	if (media_cap[tp->default_port] & MediaIsMII) {
+		u16 media2advert[] = { 0x20, 0x40, 0x03e0, 0x60, 0x80, 0x100, 0x200 };
+		tp->to_advertise = media2advert[tp->default_port - 9];
+	} else if (tp->flags & HAS_8023X)
+		tp->to_advertise = 0x05e1;
+	else
+		tp->to_advertise = 0x01e1;
+
+	/* This is logically part of probe1(), but too complex to write inline. */
+	if (tp->flags & HAS_MEDIA_TABLE) {
+		memcpy(tp->eeprom, ee_data, sizeof(tp->eeprom));
+		parse_eeprom(dev);
+	}
+
+	if ((tp->flags & ALWAYS_CHECK_MII) ||
+		(tp->mtable  &&  tp->mtable->has_mii) ||
+		( ! tp->mtable  &&  (tp->flags & HAS_MII))) {
+		int phy, phy_idx;
+		if (tp->mtable  &&  tp->mtable->has_mii) {
+			for (i = 0; i < tp->mtable->leafcount; i++)
+				if (tp->mtable->mleaf[i].media == 11) {
+					tp->cur_index = i;
+					tp->saved_if_port = dev->if_port;
+					select_media(dev, 1);
+					dev->if_port = tp->saved_if_port;
+					break;
+				}
+		}
+		/* Find the connected MII xcvrs.
+		   Doing this in open() would allow detecting external xcvrs later,
+		   but takes much time. */
+		for (phy = 0, phy_idx = 0; phy < 32 && phy_idx < sizeof(tp->phys);
+			 phy++) {
+			int mii_status = mdio_read(dev, phy, 1);
+			if ((mii_status & 0x8301) == 0x8001 ||
+				((mii_status & 0x8000) == 0  && (mii_status & 0x7800) != 0)) {
+				int mii_reg0 = mdio_read(dev, phy, 0);
+				int mii_advert = mdio_read(dev, phy, 4);
+				int reg4 = ((mii_status>>6) & tp->to_advertise) | 1;
+				tp->phys[phy_idx] = phy;
+				tp->advertising[phy_idx++] = reg4;
+				printk(KERN_INFO "%s:  MII transceiver #%d "
+					   "config %4.4x status %4.4x advertising %4.4x.\n",
+					   dev->name, phy, mii_reg0, mii_status, mii_advert);
+				/* Fixup for DLink with miswired PHY. */
+				if (mii_advert != reg4) {
+					printk(KERN_DEBUG "%s:  Advertising %4.4x on PHY %d,"
+						   " previously advertising %4.4x.\n",
+						   dev->name, reg4, phy, mii_advert);
+					printk(KERN_DEBUG "%s:  Advertising %4.4x (to advertise"
+						   " is %4.4x).\n",
+						   dev->name, reg4, tp->to_advertise);
+					mdio_write(dev, phy, 4, reg4);
+				}
+				/* Enable autonegotiation: some boards default to off. */
+				mdio_write(dev, phy, 0, mii_reg0 |
+						   (tp->full_duplex ? 0x1100 : 0x1000) |
+						   (media_cap[tp->default_port]&MediaIs100 ? 0x2000:0));
+			}
+		}
+		tp->mii_cnt = phy_idx;
+		if (tp->mtable  &&  tp->mtable->has_mii  &&  phy_idx == 0) {
+			printk(KERN_INFO "%s: ***WARNING***: No MII transceiver found!\n",
+				   dev->name);
+			tp->phys[0] = 1;
+		}
+	}
+
+	/* The Tulip-specific entries in the device structure. */
+	dev->open = &tulip_open;
+	dev->hard_start_xmit = &tulip_start_xmit;
+	dev->stop = &tulip_close;
+	dev->get_stats = &tulip_get_stats;
+#ifdef HAVE_PRIVATE_IOCTL
+	dev->do_ioctl = &private_ioctl;
+#endif
+#ifdef HAVE_MULTICAST
+	dev->set_multicast_list = &set_rx_mode;
+#endif
+
+	if ((tp->flags & HAS_NWAY143)  || tp->chip_id == DC21041)
+		tp->link_change = t21142_lnk_change;
+	else if (tp->flags & HAS_PNICNWAY)
+		tp->link_change = pnic_lnk_change;
+
+	/* Reset the xcvr interface and turn on heartbeat. */
+	switch (chip_idx) {
+	case DC21041:
+		tp->to_advertise = 0x0061;
+		outl(0x00000000, ioaddr + CSR13);
+		outl(0xFFFFFFFF, ioaddr + CSR14);
+		outl(0x00000008, ioaddr + CSR15); /* Listen on AUI also. */
+		outl(inl(ioaddr + CSR6) | 0x0200, ioaddr + CSR6);
+		outl(0x0000EF05, ioaddr + CSR13);
+		break;
+	case DC21040:
+		outl(0x00000000, ioaddr + CSR13);
+		outl(0x00000004, ioaddr + CSR13);
+		break;
+	case DC21140: default:
+		if (tp->mtable)
+			outl(tp->mtable->csr12dir | 0x100, ioaddr + CSR12);
+		break;
+	case DC21142:
+	case PNIC2:
+		if (tp->mii_cnt  ||  media_cap[dev->if_port] & MediaIsMII) {
+			outl(0x82020000, ioaddr + CSR6);
+			outl(0x0000, ioaddr + CSR13);
+			outl(0x0000, ioaddr + CSR14);
+			outl(0x820E0000, ioaddr + CSR6);
+		} else
+			t21142_start_nway(dev);
+		break;
+	case X3201_3:
+		outl(0x0008, ioaddr + CSR15);
+		udelay(5);  /* The delays are Xircom recommended to give the
+					 * chipset time to reset the actual hardware
+					 * on the PCMCIA card
+					 */
+		outl(0xa8050000, ioaddr + CSR15);
+		udelay(5);
+		outl(0xa00f0000, ioaddr + CSR15);
+		udelay(5);
+		outl_CSR6(0x32000200, ioaddr, chip_idx);
+		break;
+	case LC82C168:
+		if ( ! tp->mii_cnt) {
+			tp->nway = 1;
+			tp->nwayset = 0;
+			outl(0x00420000, ioaddr + CSR6);
+			outl(0x30, ioaddr + CSR12);
+			outl(0x0001F078, ioaddr + 0xB8);
+			outl(0x0201F078, ioaddr + 0xB8); /* Turn on autonegotiation. */
+		}
+		break;
+	case MX98713: case COMPEX9881:
+		outl(0x00000000, ioaddr + CSR6);
+		outl(0x000711C0, ioaddr + CSR14); /* Turn on NWay. */
+		outl(0x00000001, ioaddr + CSR13);
+		break;
+	case MX98715: case MX98725:
+		outl(0x01a80000, ioaddr + CSR6);
+		outl(0xFFFFFFFF, ioaddr + CSR14);
+		outl(0x00001000, ioaddr + CSR12);
+		break;
+	case COMET:
+		/* No initialization necessary. */
+		break;
+	}
+
+	if (tulip_tbl[chip_idx].flags & HAS_PWRDWN)
+		pcibios_write_config_dword(pci_bus, pci_devfn, 0x40, 0x40000000);
+
+	return dev;
+}
+
+/* Serial EEPROM section. */
+/* The main routine to parse the very complicated SROM structure.
+   Search www.digital.com for "21X4 SROM" to get details.
+   This code is very complex, and will require changes to support
+   additional cards, so I'll be verbose about what is going on.
+   */
+
+/* Known cards that have old-style EEPROMs. */
+static struct fixups {
+  char *name;
+  unsigned char addr0, addr1, addr2;
+  u16 newtable[32];				/* Max length below. */
+} eeprom_fixups[] = {
+  {"Asante", 0, 0, 0x94, {0x1e00, 0x0000, 0x0800, 0x0100, 0x018c,
+						  0x0000, 0x0000, 0xe078, 0x0001, 0x0050, 0x0018 }},
+  {"SMC9332DST", 0, 0, 0xC0, { 0x1e00, 0x0000, 0x0800, 0x041f,
+							   0x0000, 0x009E, /* 10baseT */
+							   0x0004, 0x009E, /* 10baseT-FD */
+							   0x0903, 0x006D, /* 100baseTx */
+							   0x0905, 0x006D, /* 100baseTx-FD */ }},
+  {"Cogent EM100", 0, 0, 0x92, { 0x1e00, 0x0000, 0x0800, 0x063f,
+								 0x0107, 0x8021, /* 100baseFx */
+								 0x0108, 0x8021, /* 100baseFx-FD */
+								 0x0100, 0x009E, /* 10baseT */
+								 0x0104, 0x009E, /* 10baseT-FD */
+								 0x0103, 0x006D, /* 100baseTx */
+								 0x0105, 0x006D, /* 100baseTx-FD */ }},
+  {"Maxtech NX-110", 0, 0, 0xE8, { 0x1e00, 0x0000, 0x0800, 0x0513,
+							   0x1001, 0x009E, /* 10base2, CSR12 0x10*/
+							   0x0000, 0x009E, /* 10baseT */
+							   0x0004, 0x009E, /* 10baseT-FD */
+							   0x0303, 0x006D, /* 100baseTx, CSR12 0x03 */
+							   0x0305, 0x006D, /* 100baseTx-FD CSR12 0x03 */}},
+  {"Accton EN1207", 0, 0, 0xE8, { 0x1e00, 0x0000, 0x0800, 0x051F,
+								  0x1B01, 0x0000, /* 10base2,   CSR12 0x1B */
+								  0x0B00, 0x009E, /* 10baseT,   CSR12 0x0B */
+								  0x0B04, 0x009E, /* 10baseT-FD,CSR12 0x0B */
+								  0x1B03, 0x006D, /* 100baseTx, CSR12 0x1B */
+								  0x1B05, 0x006D, /* 100baseTx-FD CSR12 0x1B */
+   }},
+  {0, 0, 0, 0, {}}};
+
+static const char * block_name[] = {"21140 non-MII", "21140 MII PHY",
+ "21142 Serial PHY", "21142 MII PHY", "21143 SYM PHY", "21143 reset method"};
+
+#if defined(__i386__)			/* AKA get_unaligned() */
+#define get_u16(ptr) (*(u16 *)(ptr))
+#else
+#define get_u16(ptr) (((u8*)(ptr))[0] + (((u8*)(ptr))[1]<<8))
+#endif
+
+static void parse_eeprom(struct net_device *dev)
+{
+	/* The last media info list parsed, for multiport boards.  */
+	static struct mediatable *last_mediatable = NULL;
+	static unsigned char *last_ee_data = NULL;
+	static int controller_index = 0;
+	struct tulip_private *tp = (struct tulip_private *)dev->priv;
+	unsigned char *ee_data = tp->eeprom;
+	int i;
+
+	tp->mtable = 0;
+	/* Detect an old-style (SA only) EEPROM layout:
+	   memcmp(eedata, eedata+16, 8). */
+	for (i = 0; i < 8; i ++)
+		if (ee_data[i] != ee_data[16+i])
+			break;
+	if (i >= 8) {
+		if (ee_data[0] == 0xff) {
+			if (last_mediatable) {
+				controller_index++;
+				printk(KERN_INFO "%s:  Controller %d of multiport board.\n",
+					   dev->name, controller_index);
+				tp->mtable = last_mediatable;
+				ee_data = last_ee_data;
+				goto subsequent_board;
+			} else
+				printk(KERN_INFO "%s:  Missing EEPROM, this interface may "
+					   "not work correctly!\n",
+			   dev->name);
+			return;
+		}
+	  /* Do a fix-up based on the vendor half of the station address prefix. */
+	  for (i = 0; eeprom_fixups[i].name; i++) {
+		if (dev->dev_addr[0] == eeprom_fixups[i].addr0
+			&&  dev->dev_addr[1] == eeprom_fixups[i].addr1
+			&&  dev->dev_addr[2] == eeprom_fixups[i].addr2) {
+		  if (dev->dev_addr[2] == 0xE8  &&  ee_data[0x1a] == 0x55)
+			  i++;			/* An Accton EN1207, not an outlaw Maxtech. */
+		  memcpy(ee_data + 26, eeprom_fixups[i].newtable,
+				 sizeof(eeprom_fixups[i].newtable));
+		  printk(KERN_INFO "%s: Old format EEPROM on '%s' board.  Using"
+				 " substitute media control info.\n",
+				 dev->name, eeprom_fixups[i].name);
+		  break;
+		}
+	  }
+	  if (eeprom_fixups[i].name == NULL) { /* No fixup found. */
+		  printk(KERN_INFO "%s: Old style EEPROM with no media selection "
+				 "information.\n",
+			   dev->name);
+		return;
+	  }
+	}
+
+	controller_index = 0;
+	if (ee_data[19] > 1) {		/* Multiport board. */
+		last_ee_data = ee_data;
+	}
+subsequent_board:
+
+	if (ee_data[27] == 0) {		/* No valid media table. */
+	} else if (tp->chip_id == DC21041) {
+		unsigned char *p = (void *)ee_data + ee_data[27 + controller_index*3];
+		int media = get_u16(p);
+		int count = p[2];
+		p += 3;
+
+		printk(KERN_INFO "%s: 21041 Media table, default media %4.4x (%s).\n",
+			   dev->name, media,
+			   media & 0x0800 ? "Autosense" : medianame[media & 15]);
+		for (i = 0; i < count; i++) {
+			unsigned char media_code = *p++;
+			if (media_code & 0x40)
+				p += 6;
+			printk(KERN_INFO "%s:  21041 media #%d, %s.\n",
+				   dev->name, media_code & 15, medianame[media_code & 15]);
+		}
+	} else {
+		unsigned char *p = (void *)ee_data + ee_data[27];
+		unsigned char csr12dir = 0;
+		int count, new_advertise = 0;
+		struct mediatable *mtable;
+		u16 media = get_u16(p);
+
+		p += 2;
+		if (tp->flags & CSR12_IN_SROM)
+			csr12dir = *p++;
+		count = *p++;
+		mtable = (struct mediatable *)
+			kmalloc(sizeof(struct mediatable) + count*sizeof(struct medialeaf),
+					GFP_KERNEL);
+		if (mtable == NULL)
+			return;				/* Horrible, impossible failure. */
+		last_mediatable = tp->mtable = mtable;
+		mtable->defaultmedia = media;
+		mtable->leafcount = count;
+		mtable->csr12dir = csr12dir;
+		mtable->has_nonmii = mtable->has_mii = mtable->has_reset = 0;
+		mtable->csr15dir = mtable->csr15val = 0;
+
+		printk(KERN_INFO "%s:  EEPROM default media type %s.\n", dev->name,
+			   media & 0x0800 ? "Autosense" : medianame[media & 15]);
+		for (i = 0; i < count; i++) {
+			struct medialeaf *leaf = &mtable->mleaf[i];
+
+			if ((p[0] & 0x80) == 0) { /* 21140 Compact block. */
+				leaf->type = 0;
+				leaf->media = p[0] & 0x3f;
+				leaf->leafdata = p;
+				if ((p[2] & 0x61) == 0x01)	/* Bogus, but Znyx boards do it. */
+					mtable->has_mii = 1;
+				p += 4;
+			} else {
+				leaf->type = p[1];
+				if (p[1] == 0x05) {
+					mtable->has_reset = i;
+					leaf->media = p[2] & 0x0f;
+				} else if (p[1] & 1) {
+					mtable->has_mii = 1;
+					leaf->media = 11;
+				} else {
+					mtable->has_nonmii = 1;
+					leaf->media = p[2] & 0x0f;
+					switch (leaf->media) {
+					case 0: new_advertise |= 0x0020; break;
+					case 4: new_advertise |= 0x0040; break;
+					case 3: new_advertise |= 0x0080; break;
+					case 5: new_advertise |= 0x0100; break;
+					case 6: new_advertise |= 0x0200; break;
+					}
+					if (p[1] == 2  &&  leaf->media == 0) {
+						if (p[2] & 0x40) {
+							u32 base15 = get_unaligned((u16*)&p[7]);
+							mtable->csr15dir =
+								(get_unaligned((u16*)&p[9])<<16) + base15;
+							mtable->csr15val =
+								(get_unaligned((u16*)&p[11])<<16) + base15;
+						} else {
+							mtable->csr15dir = get_unaligned((u16*)&p[3])<<16;
+							mtable->csr15val = get_unaligned((u16*)&p[5])<<16;
+						}
+					}
+				}
+				leaf->leafdata = p + 2;
+				p += (p[0] & 0x3f) + 1;
+			}
+			if (tulip_debug > 1  &&  leaf->media == 11) {
+				unsigned char *bp = leaf->leafdata;
+				printk(KERN_INFO "%s:  MII interface PHY %d, setup/reset "
+					   "sequences %d/%d long, capabilities %2.2x %2.2x.\n",
+					   dev->name, bp[0], bp[1], bp[2 + bp[1]*2],
+					   bp[5 + bp[2 + bp[1]*2]*2], bp[4 + bp[2 + bp[1]*2]*2]);
+			}
+			printk(KERN_INFO "%s:  Index #%d - Media %s (#%d) described "
+				   "by a %s (%d) block.\n",
+				   dev->name, i, medianame[leaf->media], leaf->media,
+				   block_name[leaf->type], leaf->type);
+		}
+		if (new_advertise)
+			tp->to_advertise = new_advertise;
+	}
+}
+/* Reading a serial EEPROM is a "bit" grungy, but we work our way through:->.*/
+
+/*  EEPROM_Ctrl bits. */
+#define EE_SHIFT_CLK	0x02	/* EEPROM shift clock. */
+#define EE_CS			0x01	/* EEPROM chip select. */
+#define EE_DATA_WRITE	0x04	/* Data from the Tulip to EEPROM. */
+#define EE_WRITE_0		0x01
+#define EE_WRITE_1		0x05
+#define EE_DATA_READ	0x08	/* Data from the EEPROM chip. */
+#define EE_ENB			(0x4800 | EE_CS)
+
+/* Delay between EEPROM clock transitions.
+   Even at 33Mhz current PCI implementations don't overrun the EEPROM clock.
+   We add a bus turn-around to insure that this remains true. */
+#define eeprom_delay()	inl(ee_addr)
+
+/* The EEPROM commands include the alway-set leading bit. */
+#define EE_READ_CMD		(6)
+
+/* Note: this routine returns extra data bits for size detection. */
+static int read_eeprom(long ioaddr, int location, int addr_len)
+{
+	int i;
+	unsigned retval = 0;
+	long ee_addr = ioaddr + CSR9;
+	int read_cmd = location | (EE_READ_CMD << addr_len);
+
+	outl(EE_ENB & ~EE_CS, ee_addr);
+	outl(EE_ENB, ee_addr);
+
+	/* Shift the read command bits out. */
+	for (i = 4 + addr_len; i >= 0; i--) {
+		short dataval = (read_cmd & (1 << i)) ? EE_DATA_WRITE : 0;
+		outl(EE_ENB | dataval, ee_addr);
+		eeprom_delay();
+		outl(EE_ENB | dataval | EE_SHIFT_CLK, ee_addr);
+		eeprom_delay();
+		retval = (retval << 1) | ((inl(ee_addr) & EE_DATA_READ) ? 1 : 0);
+	}
+	outl(EE_ENB, ee_addr);
+
+	for (i = 16; i > 0; i--) {
+		outl(EE_ENB | EE_SHIFT_CLK, ee_addr);
+		eeprom_delay();
+		retval = (retval << 1) | ((inl(ee_addr) & EE_DATA_READ) ? 1 : 0);
+		outl(EE_ENB, ee_addr);
+		eeprom_delay();
+	}
+
+	/* Terminate the EEPROM access. */
+	outl(EE_ENB & ~EE_CS, ee_addr);
+	return retval;
+}
+
+/* MII transceiver control section.
+   Read and write the MII registers using software-generated serial
+   MDIO protocol.  See the MII specifications or DP83840A data sheet
+   for details. */
+
+/* The maximum data clock rate is 2.5 Mhz.  The minimum timing is usually
+   met by back-to-back PCI I/O cycles, but we insert a delay to avoid
+   "overclocking" issues or future 66Mhz PCI. */
+#define mdio_delay() inl(mdio_addr)
+
+/* Read and write the MII registers using software-generated serial
+   MDIO protocol.  It is just different enough from the EEPROM protocol
+   to not share code.  The maxium data clock rate is 2.5 Mhz. */
+#define MDIO_SHIFT_CLK	0x10000
+#define MDIO_DATA_WRITE0 0x00000
+#define MDIO_DATA_WRITE1 0x20000
+#define MDIO_ENB		0x00000		/* Ignore the 0x02000 databook setting. */
+#define MDIO_ENB_IN		0x40000
+#define MDIO_DATA_READ	0x80000
+
+static int mdio_read(struct net_device *dev, int phy_id, int location)
+{
+	struct tulip_private *tp = (struct tulip_private *)dev->priv;
+	int i;
+	int read_cmd = (0xf6 << 10) | (phy_id << 5) | location;
+	int retval = 0;
+	long ioaddr = dev->base_addr;
+	long mdio_addr = ioaddr + CSR9;
+
+	if (tp->chip_id == LC82C168) {
+		int i = 1000;
+		outl(0x60020000 + (phy_id<<23) + (location<<18), ioaddr + 0xA0);
+		inl(ioaddr + 0xA0);
+		inl(ioaddr + 0xA0);
+		while (--i > 0)
+			if ( ! ((retval = inl(ioaddr + 0xA0)) & 0x80000000))
+				return retval & 0xffff;
+		return 0xffff;
+	}
+
+	if (tp->chip_id == COMET) {
+		if (phy_id == 1) {
+			if (location < 7)
+				return inl(ioaddr + 0xB4 + (location<<2));
+			else if (location == 17)
+				return inl(ioaddr + 0xD0);
+			else if (location >= 29 && location <= 31)
+				return inl(ioaddr + 0xD4 + ((location-29)<<2));
+		}
+		return 0xffff;
+	}
+
+	/* Establish sync by sending at least 32 logic ones. */
+	for (i = 32; i >= 0; i--) {
+		outl(MDIO_ENB | MDIO_DATA_WRITE1, mdio_addr);
+		mdio_delay();
+		outl(MDIO_ENB | MDIO_DATA_WRITE1 | MDIO_SHIFT_CLK, mdio_addr);
+		mdio_delay();
+	}
+	/* Shift the read command bits out. */
+	for (i = 15; i >= 0; i--) {
+		int dataval = (read_cmd & (1 << i)) ? MDIO_DATA_WRITE1 : 0;
+
+		outl(MDIO_ENB | dataval, mdio_addr);
+		mdio_delay();
+		outl(MDIO_ENB | dataval | MDIO_SHIFT_CLK, mdio_addr);
+		mdio_delay();
+	}
+	/* Read the two transition, 16 data, and wire-idle bits. */
+	for (i = 19; i > 0; i--) {
+		outl(MDIO_ENB_IN, mdio_addr);
+		mdio_delay();
+		retval = (retval << 1) | ((inl(mdio_addr) & MDIO_DATA_READ) ? 1 : 0);
+		outl(MDIO_ENB_IN | MDIO_SHIFT_CLK, mdio_addr);
+		mdio_delay();
+	}
+	return (retval>>1) & 0xffff;
+}
+
+static void mdio_write(struct net_device *dev, int phy_id, int location, int value)
+{
+	struct tulip_private *tp = (struct tulip_private *)dev->priv;
+	int i;
+	int cmd = (0x5002 << 16) | (phy_id << 23) | (location<<18) | value;
+	long ioaddr = dev->base_addr;
+	long mdio_addr = ioaddr + CSR9;
+
+	if (tp->chip_id == LC82C168) {
+		int i = 1000;
+		outl(cmd, ioaddr + 0xA0);
+		do
+			if ( ! (inl(ioaddr + 0xA0) & 0x80000000))
+				break;
+		while (--i > 0);
+		return;
+	}
+
+	if (tp->chip_id == COMET) {
+		if (phy_id != 1)
+			return;
+		if (location < 7)
+			outl(value, ioaddr + 0xB4 + (location<<2));
+		else if (location == 17)
+			outl(value, ioaddr + 0xD0);
+		else if (location >= 29 && location <= 31)
+			outl(value, ioaddr + 0xD4 + ((location-29)<<2));
+		return;
+	}
+
+	/* Establish sync by sending 32 logic ones. */
+	for (i = 32; i >= 0; i--) {
+		outl(MDIO_ENB | MDIO_DATA_WRITE1, mdio_addr);
+		mdio_delay();
+		outl(MDIO_ENB | MDIO_DATA_WRITE1 | MDIO_SHIFT_CLK, mdio_addr);
+		mdio_delay();
+	}
+	/* Shift the command bits out. */
+	for (i = 31; i >= 0; i--) {
+		int dataval = (cmd & (1 << i)) ? MDIO_DATA_WRITE1 : 0;
+		outl(MDIO_ENB | dataval, mdio_addr);
+		mdio_delay();
+		outl(MDIO_ENB | dataval | MDIO_SHIFT_CLK, mdio_addr);
+		mdio_delay();
+	}
+	/* Clear out extra bits. */
+	for (i = 2; i > 0; i--) {
+		outl(MDIO_ENB_IN, mdio_addr);
+		mdio_delay();
+		outl(MDIO_ENB_IN | MDIO_SHIFT_CLK, mdio_addr);
+		mdio_delay();
+	}
+	return;
+}
+
+
+static void
+tulip_up(struct net_device *dev)
+{
+	struct tulip_private *tp = (struct tulip_private *)dev->priv;
+	long ioaddr = dev->base_addr;
+	int next_tick = 3*HZ;
+	int i;
+
+	/* Wake the chip from sleep/snooze mode. */
+	if (tp->flags & HAS_PWRDWN)
+		pcibios_write_config_dword(tp->pci_bus, tp->pci_devfn, 0x40, 0);
+
+	/* On some chip revs we must set the MII/SYM port before the reset!? */
+	if (tp->mii_cnt  ||  (tp->mtable  &&  tp->mtable->has_mii))
+		outl_CSR6(0x00040000, ioaddr, tp->chip_id);
+
+	/* Reset the chip, holding bit 0 set at least 50 PCI cycles. */
+	outl(0x00000001, ioaddr + CSR0);
+
+	/* Deassert reset.
+	   Wait the specified 50 PCI cycles after a reset by initializing
+	   Tx and Rx queues and the address filter list. */
+	outl(tp->csr0, ioaddr + CSR0);
+
+	if (tulip_debug > 1)
+		printk(KERN_DEBUG "%s: tulip_open() irq %d.\n", dev->name, dev->irq);
+
+	/* Clear the rx, tx rings */
+	tp->tx_full = 0;
+	tp->cur_rx = tp->cur_tx = 0;
+	tp->dirty_rx = tp->dirty_tx = 0;
+	for (i = 0; i < RX_RING_SIZE; i++)
+		tp->rx_ring[i].status = cpu_to_le32(DescOwned);
+	for (i = 0; i < TX_RING_SIZE; i++) {
+		tp->tx_skbuff[i] = 0;
+		tp->tx_ring[i].status = 0x00000000;
+	}
+
+#if 0
+	if (tp->chip_id == PNIC2) {
+		u32 addr_low = cpu_to_le32(get_unaligned((u32 *)dev->dev_addr));
+		u32 addr_high = cpu_to_le16(get_unaligned((u16 *)(dev->dev_addr+4)));
+		addr_high = (dev->dev_addr[4]<<8) + (dev->dev_addr[5]<<0);
+		outl((dev->dev_addr[0]<<8) + dev->dev_addr[1] +
+			 (dev->dev_addr[2]<<24) + (dev->dev_addr[3]<<16),
+			 ioaddr + 0xB0);
+		outl(addr_high + (addr_high<<16), ioaddr + 0xB8);
+	}
+#endif
+	if (tp->flags & MC_HASH_ONLY) {
+		u32 addr_low = cpu_to_le32(get_unaligned((u32 *)dev->dev_addr));
+		u32 addr_high = cpu_to_le32(get_unaligned((u16 *)(dev->dev_addr+4)));
+		if (tp->chip_id == AX88140) {
+			outl(0, ioaddr + CSR13);
+			outl(addr_low,  ioaddr + CSR14);
+			outl(1, ioaddr + CSR13);
+			outl(addr_high, ioaddr + CSR14);
+		} else if (tp->chip_id == COMET) {
+			outl(addr_low,  ioaddr + 0xA4);
+			outl(addr_high, ioaddr + 0xA8);
+			outl(0, ioaddr + 0xAC);
+			outl(0, ioaddr + 0xB0);
+		}
+	} else if (tp->chip_id != X3201_3) {
+		/* This is set_rx_mode(), but without starting the transmitter. */
+		u16 *eaddrs = (u16 *)dev->dev_addr;
+		u16 *setup_frm = &tp->setup_frame[15*6];
+
+		/* 21140 bug: you must add the broadcast address. */
+		memset(tp->setup_frame, 0xff, 96*sizeof(u16));
+		/* Fill the final entry of the table with our physical address. */
+		*setup_frm++ = eaddrs[0]; *setup_frm++ = eaddrs[0];
+		*setup_frm++ = eaddrs[1]; *setup_frm++ = eaddrs[1];
+		*setup_frm++ = eaddrs[2]; *setup_frm++ = eaddrs[2];
+		/* Put the setup frame on the Tx list. */
+		tp->tx_ring[0].length = cpu_to_le32(0x08000000 | 192);
+		tp->tx_ring[0].buffer1 = virt_to_le32desc(tp->setup_frame);
+		tp->tx_ring[0].status = cpu_to_le32(DescOwned);
+
+		tp->cur_tx++;
+	} else { /* X3201_3 */
+		u16 *eaddrs = (u16 *)dev->dev_addr;
+		u16 *setup_frm = &tp->setup_frame[0*6];
+		
+		/* fill the table with the broadcast address */
+		memset(tp->setup_frame, 0xff, 96*sizeof(u16));
+		/* re-fill the first 14 table entries with our address */
+		for(i=0; i<14; i++) {
+			*setup_frm++ = eaddrs[0]; *setup_frm++ = eaddrs[0];
+			*setup_frm++ = eaddrs[1]; *setup_frm++ = eaddrs[1];
+			*setup_frm++ = eaddrs[2]; *setup_frm++ = eaddrs[2];
+		}
+
+		/* Put the setup frame on the Tx list. */
+		tp->tx_ring[0].length = cpu_to_le32(0x08000000 | 192);
+		/* Lie about the address of our setup frame to make the */
+		/* chip happy */
+		tp->tx_ring[0].buffer1 = (virt_to_le32desc(tp->setup_frame) + 4);
+		tp->tx_ring[0].status = cpu_to_le32(DescOwned);
+
+		tp->cur_tx++;
+	}
+
+	outl(virt_to_bus(tp->rx_ring), ioaddr + CSR3);
+	outl(virt_to_bus(tp->tx_ring), ioaddr + CSR4);
+
+	tp->saved_if_port = dev->if_port;
+	if (dev->if_port == 0)
+		dev->if_port = tp->default_port;
+
+	/* Allow selecting a default media. */
+	i = 0;
+	if (tp->mtable == NULL)
+		goto media_picked;
+	if (dev->if_port) {
+		int looking_for = media_cap[dev->if_port] & MediaIsMII ? 11 :
+			(dev->if_port == 12 ? 0 : dev->if_port);
+		for (i = 0; i < tp->mtable->leafcount; i++)
+			if (tp->mtable->mleaf[i].media == looking_for) {
+				printk(KERN_INFO "%s: Using user-specified media %s.\n",
+					   dev->name, medianame[dev->if_port]);
+				goto media_picked;
+			}
+	}
+	if ((tp->mtable->defaultmedia & 0x0800) == 0) {
+		int looking_for = tp->mtable->defaultmedia & 15;
+		for (i = 0; i < tp->mtable->leafcount; i++)
+			if (tp->mtable->mleaf[i].media == looking_for) {
+				printk(KERN_INFO "%s: Using EEPROM-set media %s.\n",
+					   dev->name, medianame[looking_for]);
+				goto media_picked;
+			}
+	}
+	/* Start sensing first non-full-duplex media. */
+	for (i = tp->mtable->leafcount - 1;
+		 (media_cap[tp->mtable->mleaf[i].media] & MediaAlwaysFD) && i > 0; i--)
+		;
+media_picked:
+
+	tp->csr6 = 0;
+	tp->cur_index = i;
+	tp->nwayset = 0;
+	if (dev->if_port == 0  && tp->chip_id == DC21041) {
+		tp->nway = 1;
+	}
+	if (dev->if_port == 0  &&  tp->chip_id == DC21142) {
+		if (tp->mii_cnt) {
+			select_media(dev, 1);
+			if (tulip_debug > 1)
+				printk(KERN_INFO "%s: Using MII transceiver %d, status "
+					   "%4.4x.\n",
+					   dev->name, tp->phys[0], mdio_read(dev, tp->phys[0], 1));
+			outl(0x82020000, ioaddr + CSR6);
+			tp->csr6 = 0x820E0000;
+			dev->if_port = 11;
+			outl(0x0000, ioaddr + CSR13);
+			outl(0x0000, ioaddr + CSR14);
+		} else
+			t21142_start_nway(dev);
+	} else if (tp->chip_id == PNIC2) {
+		t21142_start_nway(dev);
+	} else if (tp->chip_id == LC82C168  &&  ! tp->medialock) {
+		if (tp->mii_cnt) {
+			dev->if_port = 11;
+			tp->csr6 = 0x814C0000 | (tp->full_duplex ? 0x0200 : 0);
+			outl(0x0001, ioaddr + CSR15);
+		} else if (inl(ioaddr + CSR5) & TPLnkPass)
+			pnic_do_nway(dev);
+		else {
+			/* Start with 10mbps to do autonegotiation. */
+			outl(0x32, ioaddr + CSR12);
+			tp->csr6 = 0x00420000;
+			outl(0x0001B078, ioaddr + 0xB8);
+			outl(0x0201B078, ioaddr + 0xB8);
+			next_tick = 1*HZ;
+		}
+	} else if ((tp->chip_id == MX98713 || tp->chip_id == COMPEX9881)
+			   && ! tp->medialock) {
+		dev->if_port = 0;
+		tp->csr6 = 0x01880000 | (tp->full_duplex ? 0x0200 : 0);
+		outl(0x0f370000 | inw(ioaddr + 0x80), ioaddr + 0x80);
+	} else if (tp->chip_id == MX98715 || tp->chip_id == MX98725) {
+		/* Provided by BOLO, Macronix - 12/10/1998. */
+		dev->if_port = 0;
+		tp->csr6 = 0x01a80200;
+		outl(0x0f370000 | inw(ioaddr + 0x80), ioaddr + 0x80);
+		outl(0x11000 | inw(ioaddr + 0xa0), ioaddr + 0xa0);
+	} else if (tp->chip_id == DC21143  &&
+			   media_cap[dev->if_port] & MediaIsMII) {
+		/* We must reset the media CSRs when we force-select MII mode. */
+		outl(0x0000, ioaddr + CSR13);
+		outl(0x0000, ioaddr + CSR14);
+		outl(0x0008, ioaddr + CSR15);
+	} else if (tp->chip_id == X3201_3) {
+		outl(0x0008, ioaddr + CSR15);
+		udelay(5);
+		outl(0xa8050000, ioaddr + CSR15);
+		udelay(5);
+		outl(0xa00f0000, ioaddr + CSR15); 
+		udelay(5);
+		tp->csr6  = 0x32400000;
+	} else if (tp->chip_id == COMET) {
+		dev->if_port = 0;
+		tp->csr6 = 0x00040000;
+	} else if (tp->chip_id == AX88140) {
+		tp->csr6 = tp->mii_cnt ? 0x00040100 : 0x00000100;
+	} else
+		select_media(dev, 1);
+
+	/* Start the chip's Tx to process setup frame. */
+	outl_CSR6(tp->csr6, ioaddr, tp->chip_id);
+	outl_CSR6(tp->csr6 | 0x2000, ioaddr, tp->chip_id);
+
+	/* Enable interrupts by setting the interrupt mask. */
+	outl(tulip_tbl[tp->chip_id].valid_intrs, ioaddr + CSR5);
+	outl(tulip_tbl[tp->chip_id].valid_intrs, ioaddr + CSR7);
+	outl_CSR6(tp->csr6 | 0x2002, ioaddr, tp->chip_id);
+	outl(0, ioaddr + CSR2);		/* Rx poll demand */
+
+	if (tulip_debug > 2) {
+		printk(KERN_DEBUG "%s: Done tulip_open(), CSR0 %8.8x, CSR5 %8.8x CSR6 %8.8x.\n",
+			   dev->name, inl(ioaddr + CSR0), inl(ioaddr + CSR5),
+			   inl(ioaddr + CSR6));
+	}
+	/* Set the timer to switch to check for link beat and perhaps switch
+	   to an alternate media type. */
+	init_timer(&tp->timer);
+	tp->timer.expires = RUN_AT(next_tick);
+	tp->timer.data = (unsigned long)dev;
+	tp->timer.function = tulip_tbl[tp->chip_id].media_timer;
+	add_timer(&tp->timer);
+}
+
+static int
+tulip_open(struct net_device *dev)
+{
+	struct tulip_private *tp = (struct tulip_private *)dev->priv;
+
+#ifdef CARDBUS
+	if (tp->reap)
+		return -ENODEV;
+#endif
+
+	if (request_irq(dev->irq, &tulip_interrupt, SA_SHIRQ, dev->name, dev))
+		return -EAGAIN;
+
+	tulip_init_ring(dev);
+
+	tulip_up(dev);
+	tp->open = 1;
+	netif_start_queue(dev);
+	netif_mark_up(dev);
+	MOD_INC_USE_COUNT;
+
+	return 0;
+}
+
+/* Set up the transceiver control registers for the selected media type. */
+static void select_media(struct net_device *dev, int startup)
+{
+	long ioaddr = dev->base_addr;
+	struct tulip_private *tp = (struct tulip_private *)dev->priv;
+	struct mediatable *mtable = tp->mtable;
+	u32 new_csr6;
+	int i;
+
+	if (mtable) {
+		struct medialeaf *mleaf = &mtable->mleaf[tp->cur_index];
+		unsigned char *p = mleaf->leafdata;
+		switch (mleaf->type) {
+		case 0:					/* 21140 non-MII xcvr. */
+			if (tulip_debug > 1)
+				printk(KERN_DEBUG "%s: Using a 21140 non-MII transceiver"
+					   " with control setting %2.2x.\n",
+					   dev->name, p[1]);
+			dev->if_port = p[0];
+			if (startup)
+				outl(mtable->csr12dir | 0x100, ioaddr + CSR12);
+			outl(p[1], ioaddr + CSR12);
+			new_csr6 = 0x02000000 | ((p[2] & 0x71) << 18);
+			break;
+		case 2: case 4: {
+			u16 setup[5];
+			u32 csr13val, csr14val, csr15dir, csr15val;
+			for (i = 0; i < 5; i++)
+				setup[i] = get_u16(&p[i*2 + 1]);
+
+			dev->if_port = p[0] & 15;
+			if (media_cap[dev->if_port] & MediaAlwaysFD)
+				tp->full_duplex = 1;
+
+			if (startup && mtable->has_reset) {
+				struct medialeaf *rleaf = &mtable->mleaf[mtable->has_reset];
+				unsigned char *rst = rleaf->leafdata;
+				if (tulip_debug > 1)
+					printk(KERN_DEBUG "%s: Resetting the transceiver.\n",
+						   dev->name);
+				for (i = 0; i < rst[0]; i++)
+					outl(get_u16(rst + 1 + (i<<1)) << 16, ioaddr + CSR15);
+			}
+			if (tulip_debug > 1)
+				printk(KERN_DEBUG "%s: 21143 non-MII %s transceiver control "
+					   "%4.4x/%4.4x.\n",
+					   dev->name, medianame[dev->if_port], setup[0], setup[1]);
+			if (p[0] & 0x40) {	/* SIA (CSR13-15) setup values are provided. */
+				csr13val = setup[0];
+				csr14val = setup[1];
+				csr15dir = (setup[3]<<16) | setup[2];
+				csr15val = (setup[4]<<16) | setup[2];
+				outl(0, ioaddr + CSR13);
+				outl(csr14val, ioaddr + CSR14);
+				outl(csr15dir, ioaddr + CSR15);	/* Direction */
+				outl(csr15val, ioaddr + CSR15);	/* Data */
+				outl(csr13val, ioaddr + CSR13);
+			} else {
+				csr13val = 1;
+				csr14val = 0x0003FF7F;
+				csr15dir = (setup[0]<<16) | 0x0008;
+				csr15val = (setup[1]<<16) | 0x0008;
+				if (dev->if_port <= 4)
+					csr14val = t21142_csr14[dev->if_port];
+				if (startup) {
+					outl(0, ioaddr + CSR13);
+					outl(csr14val, ioaddr + CSR14);
+				}
+				outl(csr15dir, ioaddr + CSR15);	/* Direction */
+				outl(csr15val, ioaddr + CSR15);	/* Data */
+				if (startup) outl(csr13val, ioaddr + CSR13);
+			}
+			if (tulip_debug > 1)
+				printk(KERN_DEBUG "%s:  Setting CSR15 to %8.8x/%8.8x.\n",
+					   dev->name, csr15dir, csr15val);
+			if (mleaf->type == 4)
+				new_csr6 = 0x82020000 | ((setup[2] & 0x71) << 18);
+			else
+				new_csr6 = 0x82420000;
+			break;
+		}
+		case 1: case 3: {
+			int phy_num = p[0];
+			int init_length = p[1];
+			u16 *misc_info;
+			u16 to_advertise;
+
+			dev->if_port = 11;
+			new_csr6 = 0x020E0000;
+			if (mleaf->type == 3) {	/* 21142 */
+				u16 *init_sequence = (u16*)(p+2);
+				u16 *reset_sequence = &((u16*)(p+3))[init_length];
+				int reset_length = p[2 + init_length*2];
+				misc_info = reset_sequence + reset_length;
+				if (startup)
+					for (i = 0; i < reset_length; i++)
+						outl(get_u16(&reset_sequence[i]) << 16, ioaddr + CSR15);
+				for (i = 0; i < init_length; i++)
+					outl(get_u16(&init_sequence[i]) << 16, ioaddr + CSR15);
+			} else {
+				u8 *init_sequence = p + 2;
+				u8 *reset_sequence = p + 3 + init_length;
+				int reset_length = p[2 + init_length];
+				misc_info = (u16*)(reset_sequence + reset_length);
+				if (startup) {
+					outl(mtable->csr12dir | 0x100, ioaddr + CSR12);
+					for (i = 0; i < reset_length; i++)
+						outl(reset_sequence[i], ioaddr + CSR12);
+				}
+				for (i = 0; i < init_length; i++)
+					outl(init_sequence[i], ioaddr + CSR12);
+			}
+			to_advertise = (get_u16(&misc_info[1]) & tp->to_advertise) | 1;
+			tp->advertising[phy_num] = to_advertise;
+			if (tulip_debug > 1)
+				printk(KERN_DEBUG "%s:  Advertising %4.4x on PHY %d (%d).\n",
+					   dev->name, to_advertise, phy_num, tp->phys[phy_num]);
+			/* Bogus: put in by a committee?  */
+			mdio_write(dev, tp->phys[phy_num], 4, to_advertise);
+			break;
+		}
+		default:
+			printk(KERN_DEBUG "%s:  Invalid media table selection %d.\n",
+					   dev->name, mleaf->type);
+			new_csr6 = 0x020E0000;
+		}
+		if (tulip_debug > 1)
+			printk(KERN_DEBUG "%s: Using media type %s, CSR12 is %2.2x.\n",
+				   dev->name, medianame[dev->if_port],
+				   inl(ioaddr + CSR12) & 0xff);
+	} else if (tp->chip_id == DC21041) {
+		int port = dev->if_port <= 4 ? dev->if_port : 0;
+		if (tulip_debug > 1)
+			printk(KERN_DEBUG "%s: 21041 using media %s, CSR12 is %4.4x.\n",
+				   dev->name, medianame[port == 3 ? 12: port],
+				   inl(ioaddr + CSR12));
+		outl(0x00000000, ioaddr + CSR13); /* Reset the serial interface */
+		outl(t21041_csr14[port], ioaddr + CSR14);
+		outl(t21041_csr15[port], ioaddr + CSR15);
+		outl(t21041_csr13[port], ioaddr + CSR13);
+		new_csr6 = 0x80020000;
+	} else if (tp->chip_id == LC82C168) {
+		if (startup && ! tp->medialock)
+			dev->if_port = tp->mii_cnt ? 11 : 0;
+		if (tulip_debug > 1)
+			printk(KERN_DEBUG "%s: PNIC PHY status is %3.3x, media %s.\n",
+				   dev->name, inl(ioaddr + 0xB8), medianame[dev->if_port]);
+		if (tp->mii_cnt) {
+			new_csr6 = 0x810C0000;
+			outl(0x0001, ioaddr + CSR15);
+			outl(0x0201B07A, ioaddr + 0xB8);
+		} else if (startup) {
+			/* Start with 10mbps to do autonegotiation. */
+			outl(0x32, ioaddr + CSR12);
+			new_csr6 = 0x00420000;
+			outl(0x0001B078, ioaddr + 0xB8);
+			outl(0x0201B078, ioaddr + 0xB8);
+		} else if (dev->if_port == 3  ||  dev->if_port == 5) {
+			outl(0x33, ioaddr + CSR12);
+			new_csr6 = 0x01860000;
+			/* Trigger autonegotiation. */
+			outl(startup ? 0x0201F868 : 0x0001F868, ioaddr + 0xB8);
+		} else {
+			outl(0x32, ioaddr + CSR12);
+			new_csr6 = 0x00420000;
+			outl(0x1F078, ioaddr + 0xB8);
+		}
+	} else if (tp->chip_id == DC21040) {					/* 21040 */
+		/* Turn on the xcvr interface. */
+		int csr12 = inl(ioaddr + CSR12);
+		if (tulip_debug > 1)
+			printk(KERN_DEBUG "%s: 21040 media type is %s, CSR12 is %2.2x.\n",
+				   dev->name, medianame[dev->if_port], csr12);
+		if (media_cap[dev->if_port] & MediaAlwaysFD)
+			tp->full_duplex = 1;
+		new_csr6 = 0x20000;
+		/* Set the full duplux match frame. */
+		outl(FULL_DUPLEX_MAGIC, ioaddr + CSR11);
+		outl(0x00000000, ioaddr + CSR13); /* Reset the serial interface */
+		if (t21040_csr13[dev->if_port] & 8) {
+			outl(0x0705, ioaddr + CSR14);
+			outl(0x0006, ioaddr + CSR15);
+		} else {
+			outl(0xffff, ioaddr + CSR14);
+			outl(0x0000, ioaddr + CSR15);
+		}
+		outl(0x8f01 | t21040_csr13[dev->if_port], ioaddr + CSR13);
+	} else if (tp->chip_id == X3201_3) {					/* Xircom */
+		if (tp->default_port == 0)
+			dev->if_port = tp->mii_cnt ? 11 : 3;
+/* Someone is on crack, the Xircom only does MII, no Fx */
+/*		if (media_cap[dev->if_port] & MediaIsMII) {
+			new_csr6 = 0x020E0000;
+		} else if (media_cap[dev->if_port] & MediaIsFx) {
+			new_csr6 = 0x028600000;
+		} else
+			new_csr6 = 0x038600000;*/
+		new_csr6 = 0x324c0000;
+		if (tulip_debug > 1)
+			printk(KERN_DEBUG "%s: Xircom CardBus Adapter: "
+				   "%s transceiver, CSR12 %2.2x.\n",
+				   dev->name, medianame[dev->if_port],
+				   inl(ioaddr + CSR12));
+	} else {					/* Unknown chip type with no media table. */
+		if (tp->default_port == 0)
+			dev->if_port = tp->mii_cnt ? 11 : 3;
+		if (media_cap[dev->if_port] & MediaIsMII) {
+			new_csr6 = 0x020E0000;
+		} else if (media_cap[dev->if_port] & MediaIsFx) {
+			new_csr6 = 0x028600000;
+		} else
+			new_csr6 = 0x038600000;
+		if (tulip_debug > 1)
+			printk(KERN_DEBUG "%s: No media description table, assuming "
+				   "%s transceiver, CSR12 %2.2x.\n",
+				   dev->name, medianame[dev->if_port],
+				   inl(ioaddr + CSR12));
+	}
+
+	tp->csr6 = new_csr6 | (tp->csr6 & 0xfdff) | (tp->full_duplex ? 0x0200 : 0);
+	return;
+}
+
+/*
+  Check the MII negotiated duplex, and change the CSR6 setting if
+  required.
+  Return 0 if everything is OK.
+  Return < 0 if the transceiver is missing or has no link beat.
+  */
+static int check_duplex(struct net_device *dev)
+{
+	long ioaddr = dev->base_addr;
+	struct tulip_private *tp = (struct tulip_private *)dev->priv;
+	int mii_reg1, mii_reg5, negotiated, duplex;
+
+	if (tp->full_duplex_lock)
+		return 0;
+	mii_reg1 = mdio_read(dev, tp->phys[0], 1);
+	mii_reg5 = mdio_read(dev, tp->phys[0], 5);
+	if (tulip_debug > 1)
+		printk(KERN_INFO "%s: MII status %4.4x, Link partner report "
+			   "%4.4x.\n", dev->name, mii_reg1, mii_reg5);
+	if (mii_reg1 == 0xffff)
+		return -2;
+	if ((mii_reg1 & 0x0004) == 0) {
+		int new_reg1 = mdio_read(dev, tp->phys[0], 1);
+		if ((new_reg1 & 0x0004) == 0) {
+			if (tulip_debug  > 1)
+				printk(KERN_INFO "%s: No link beat on the MII interface,"
+					   " status %4.4x.\n", dev->name, new_reg1);
+			return -1;
+		}
+	}
+	negotiated = mii_reg5 & tp->advertising[0];
+	duplex = ((negotiated & 0x0300) == 0x0100
+			  || (negotiated & 0x00C0) == 0x0040);
+	/* 100baseTx-FD  or  10T-FD, but not 100-HD */
+	if (tp->full_duplex != duplex) {
+		tp->full_duplex = duplex;
+		if (negotiated & 0x038) /* 100mbps. */
+			tp->csr6 &= ~0x00400000;
+		if (tp->full_duplex) tp->csr6 |= 0x0200;
+		else				 tp->csr6 &= ~0x0200;
+		outl_CSR6(tp->csr6 | 0x0002, ioaddr, tp->chip_id);
+		outl_CSR6(tp->csr6 | 0x2002, ioaddr, tp->chip_id);
+		if (tulip_debug > 0)
+			printk(KERN_INFO "%s: Setting %s-duplex based on MII"
+				   "#%d link partner capability of %4.4x.\n",
+				   dev->name, tp->full_duplex ? "full" : "half",
+				   tp->phys[0], mii_reg5);
+		return 1;
+	}
+	return 0;
+}
+
+static void tulip_timer(unsigned long data)
+{
+	struct net_device *dev = (struct net_device *)data;
+	struct tulip_private *tp = (struct tulip_private *)dev->priv;
+	long ioaddr = dev->base_addr;
+	u32 csr12 = inl(ioaddr + CSR12);
+	int next_tick = 2*HZ;
+
+	if (tulip_debug > 2) {
+		printk(KERN_DEBUG "%s: Media selection tick, %s, status %8.8x mode"
+			   " %8.8x SIA %8.8x %8.8x %8.8x %8.8x.\n",
+			   dev->name, medianame[dev->if_port], inl(ioaddr + CSR5),
+			   inl(ioaddr + CSR6), csr12, inl(ioaddr + CSR13),
+			   inl(ioaddr + CSR14), inl(ioaddr + CSR15));
+	}
+	switch (tp->chip_id) {
+	case DC21040:
+		if (!tp->medialock  &&  csr12 & 0x0002) { /* Network error */
+			printk(KERN_INFO "%s: No link beat found.\n",
+				   dev->name);
+			dev->if_port = (dev->if_port == 2 ? 0 : 2);
+			select_media(dev, 0);
+			dev->trans_start = jiffies;
+		}
+		break;
+	case DC21041:
+		if (tulip_debug > 2)
+			printk(KERN_DEBUG "%s: 21041 media tick  CSR12 %8.8x.\n",
+				   dev->name, csr12);
+		switch (dev->if_port) {
+		case 0: case 3: case 4:
+		  if (csr12 & 0x0004) { /*LnkFail */
+			/* 10baseT is dead.  Check for activity on alternate port. */
+			tp->mediasense = 1;
+			if (csr12 & 0x0200)
+				dev->if_port = 2;
+			else
+				dev->if_port = 1;
+			printk(KERN_INFO "%s: No 21041 10baseT link beat, Media switched to %s.\n",
+				   dev->name, medianame[dev->if_port]);
+			outl(0, ioaddr + CSR13); /* Reset */
+			outl(t21041_csr14[dev->if_port], ioaddr + CSR14);
+			outl(t21041_csr15[dev->if_port], ioaddr + CSR15);
+			outl(t21041_csr13[dev->if_port], ioaddr + CSR13);
+			next_tick = 10*HZ;			/* 2.4 sec. */
+		  } else
+			next_tick = 30*HZ;
+		  break;
+		case 1:					/* 10base2 */
+		case 2:					/* AUI */
+			if (csr12 & 0x0100) {
+				next_tick = (30*HZ);			/* 30 sec. */
+				tp->mediasense = 0;
+			} else if ((csr12 & 0x0004) == 0) {
+				printk(KERN_INFO "%s: 21041 media switched to 10baseT.\n",
+					   dev->name);
+				dev->if_port = 0;
+				select_media(dev, 0);
+				next_tick = (24*HZ)/10;				/* 2.4 sec. */
+			} else if (tp->mediasense || (csr12 & 0x0002)) {
+				dev->if_port = 3 - dev->if_port; /* Swap ports. */
+				select_media(dev, 0);
+				next_tick = 20*HZ;
+			} else {
+				next_tick = 20*HZ;
+			}
+			break;
+		}
+		break;
+	case DC21140:  case DC21142: case MX98713: case COMPEX9881: default: {
+		struct medialeaf *mleaf;
+		unsigned char *p;
+		if (tp->mtable == NULL) {	/* No EEPROM info, use generic code. */
+			/* Not much that can be done.
+			   Assume this a generic MII or SYM transceiver. */
+			next_tick = 60*HZ;
+			if (tulip_debug > 2)
+				printk(KERN_DEBUG "%s: network media monitor CSR6 %8.8x "
+					   "CSR12 0x%2.2x.\n",
+					   dev->name, inl(ioaddr + CSR6), csr12 & 0xff);
+			break;
+		}
+		mleaf = &tp->mtable->mleaf[tp->cur_index];
+		p = mleaf->leafdata;
+		switch (mleaf->type) {
+		case 0: case 4: {
+			/* Type 0 serial or 4 SYM transceiver.  Check the link beat bit. */
+			int offset = mleaf->type == 4 ? 5 : 2;
+			s8 bitnum = p[offset];
+			if (p[offset+1] & 0x80) {
+				if (tulip_debug > 1)
+					printk(KERN_DEBUG"%s: Transceiver monitor tick "
+						   "CSR12=%#2.2x, no media sense.\n",
+						   dev->name, csr12);
+				if (mleaf->type == 4) {
+					if (mleaf->media == 3 && (csr12 & 0x02))
+						goto select_next_media;
+				}
+				break;
+			}
+			if (tulip_debug > 2)
+				printk(KERN_DEBUG "%s: Transceiver monitor tick: CSR12=%#2.2x"
+					   " bit %d is %d, expecting %d.\n",
+					   dev->name, csr12, (bitnum >> 1) & 7,
+					   (csr12 & (1 << ((bitnum >> 1) & 7))) != 0,
+					   (bitnum >= 0));
+			/* Check that the specified bit has the proper value. */
+			if ((bitnum < 0) !=
+				((csr12 & (1 << ((bitnum >> 1) & 7))) != 0)) {
+				if (tulip_debug > 1)
+					printk(KERN_DEBUG "%s: Link beat detected for %s.\n", dev->name,
+						   medianame[mleaf->media]);
+				if ((p[2] & 0x61) == 0x01)	/* Bogus Znyx board. */
+					goto actually_mii;
+				break;
+			}
+			if (tp->medialock)
+				break;
+	  select_next_media:
+			if (--tp->cur_index < 0) {
+				/* We start again, but should instead look for default. */
+				tp->cur_index = tp->mtable->leafcount - 1;
+			}
+			dev->if_port = tp->mtable->mleaf[tp->cur_index].media;
+			if (media_cap[dev->if_port] & MediaIsFD)
+				goto select_next_media; /* Skip FD entries. */
+			if (tulip_debug > 1)
+				printk(KERN_DEBUG "%s: No link beat on media %s,"
+					   " trying transceiver type %s.\n",
+					   dev->name, medianame[mleaf->media & 15],
+					   medianame[tp->mtable->mleaf[tp->cur_index].media]);
+			select_media(dev, 0);
+			/* Restart the transmit process. */
+			outl_CSR6(tp->csr6 | 0x0002, ioaddr, tp->chip_id);
+			outl_CSR6(tp->csr6 | 0x2002, ioaddr, tp->chip_id);
+			next_tick = (24*HZ)/10;
+			break;
+		}
+		case 1:  case 3:		/* 21140, 21142 MII */
+		actually_mii:
+			check_duplex(dev);
+			next_tick = 60*HZ;
+			break;
+		case 2:					/* 21142 serial block has no link beat. */
+		default:
+			break;
+		}
+	}
+	break;
+	}
+	tp->timer.expires = RUN_AT(next_tick);
+	add_timer(&tp->timer);
+}
+
+/* Handle the 21143 uniquely: do autoselect with NWay, not the EEPROM list
+   of available transceivers.  */
+static void t21142_timer(unsigned long data)
+{
+	struct net_device *dev = (struct net_device *)data;
+	struct tulip_private *tp = (struct tulip_private *)dev->priv;
+	long ioaddr = dev->base_addr;
+	int csr12 = inl(ioaddr + CSR12);
+	int next_tick = 60*HZ;
+	int new_csr6 = 0;
+
+	if (tulip_debug > 2)
+		printk(KERN_INFO"%s: 21143 negotiation status %8.8x, %s.\n",
+			   dev->name, csr12, medianame[dev->if_port]);
+	if (media_cap[dev->if_port] & MediaIsMII) {
+		check_duplex(dev);
+		next_tick = 60*HZ;
+	} else if (tp->nwayset) {
+		/* Don't screw up a negotiated session! */
+		if (tulip_debug > 1)
+			printk(KERN_INFO"%s: Using NWay-set %s media, csr12 %8.8x.\n",
+				   dev->name, medianame[dev->if_port], csr12);
+	} else if (tp->medialock) {
+			;
+	} else if (dev->if_port == 3) {
+		if (csr12 & 2) {	/* No 100mbps link beat, revert to 10mbps. */
+			if (tulip_debug > 1)
+				printk(KERN_INFO"%s: No 21143 100baseTx link beat, %8.8x, "
+					   "trying NWay.\n", dev->name, csr12);
+			t21142_start_nway(dev);
+			next_tick = 3*HZ;
+		}
+	} else if (((csr12 & 0x7000) != 0x5000) && tp->chip_id != X3201_3) {
+		/* Negotiation failed.  Search media types. */
+		if (tulip_debug > 1)
+			printk(KERN_INFO"%s: 21143 negotiation failed, status %8.8x.\n",
+				   dev->name, csr12);
+		if (!(csr12 & 4)) {		/* 10mbps link beat good. */
+			new_csr6 = 0x82420000;
+			dev->if_port = 0;
+			outl(0, ioaddr + CSR13);
+			outl(0x0003FFFF, ioaddr + CSR14);
+			outw(t21142_csr15[dev->if_port], ioaddr + CSR15);
+			outl(t21142_csr13[dev->if_port], ioaddr + CSR13);
+		} else {
+			/* Select 100mbps port to check for link beat. */
+			new_csr6 = 0x83860000;
+			dev->if_port = 3;
+			outl(0, ioaddr + CSR13);
+			outl(0x0003FF7F, ioaddr + CSR14);
+			outw(8, ioaddr + CSR15);
+			outl(1, ioaddr + CSR13);
+		}
+		if (tulip_debug > 1)
+			printk(KERN_INFO"%s: Testing new 21143 media %s.\n",
+				   dev->name, medianame[dev->if_port]);
+		if (new_csr6 != (tp->csr6 & ~0x00D5)) {
+			tp->csr6 &= 0x00D5;
+			tp->csr6 |= new_csr6;
+			outl(0x0301, ioaddr + CSR12);
+			outl(tp->csr6 | 0x0002, ioaddr + CSR6);
+			outl(tp->csr6 | 0x2002, ioaddr + CSR6);
+		}
+		next_tick = 3*HZ;
+	}
+	if (tp->cur_tx - tp->dirty_tx > 0  &&
+		jiffies - dev->trans_start > TX_TIMEOUT) {
+		printk(KERN_WARNING "%s: Tx hung, %d vs. %d.\n",
+			   dev->name, tp->cur_tx, tp->dirty_tx);
+		tulip_tx_timeout(dev);
+	}
+
+	tp->timer.expires = RUN_AT(next_tick);
+	add_timer(&tp->timer);
+}
+
+static void t21142_start_nway(struct net_device *dev)
+{
+	struct tulip_private *tp = (struct tulip_private *)dev->priv;
+	long ioaddr = dev->base_addr;
+	int csr14 = ((tp->to_advertise & 0x0780) << 9)  |
+		((tp->to_advertise&0x0020)<<1) | 0xffbf;
+
+	dev->if_port = 0;
+	tp->nway = tp->mediasense = 1;
+	tp->nwayset = tp->lpar = 0;
+	if (debug > 1)
+		printk(KERN_DEBUG "%s: Restarting 21143 autonegotiation, %8.8x.\n",
+			   dev->name, csr14);
+	outl(0x0001, ioaddr + CSR13);
+	outl(csr14, ioaddr + CSR14);
+	tp->csr6 = 0x82420000 | (tp->to_advertise & 0x0040 ? 0x0200 : 0);
+	outl(tp->csr6, ioaddr + CSR6);
+	if (tp->mtable  &&  tp->mtable->csr15dir) {
+		outl(tp->mtable->csr15dir, ioaddr + CSR15);
+		outl(tp->mtable->csr15val, ioaddr + CSR15);
+	} else
+		outw(0x0008, ioaddr + CSR15);
+	outl(0x1301, ioaddr + CSR12); 		/* Trigger NWAY. */
+}
+
+static void t21142_lnk_change(struct net_device *dev, int csr5)
+{
+	struct tulip_private *tp = (struct tulip_private *)dev->priv;
+	long ioaddr = dev->base_addr;
+	int csr12 = inl(ioaddr + CSR12);
+
+	if (tulip_debug > 1)
+		printk(KERN_INFO"%s: 21143 link status interrupt %8.8x, CSR5 %x, "
+			   "%8.8x.\n", dev->name, csr12, csr5, inl(ioaddr + CSR14));
+
+	/* If NWay finished and we have a negotiated partner capability. */
+	if (tp->nway  &&  !tp->nwayset  &&  (csr12 & 0x7000) == 0x5000) {
+		int setup_done = 0;
+		int negotiated = tp->to_advertise & (csr12 >> 16);
+		tp->lpar = csr12 >> 16;
+		tp->nwayset = 1;
+		if (negotiated & 0x0100)		dev->if_port = 5;
+		else if (negotiated & 0x0080)	dev->if_port = 3;
+		else if (negotiated & 0x0040)	dev->if_port = 4;
+		else if (negotiated & 0x0020)	dev->if_port = 0;
+		else {
+			tp->nwayset = 0;
+			if ((csr12 & 2) == 0  &&  (tp->to_advertise & 0x0180))
+				dev->if_port = 3;
+		}
+		tp->full_duplex = (media_cap[dev->if_port] & MediaAlwaysFD) ? 1:0;
+
+		if (tulip_debug > 1) {
+			if (tp->nwayset)
+				printk(KERN_INFO "%s: Switching to %s based on link "
+					   "negotiation %4.4x & %4.4x = %4.4x.\n",
+					   dev->name, medianame[dev->if_port], tp->to_advertise,
+					   tp->lpar, negotiated);
+			else
+				printk(KERN_INFO "%s: Autonegotiation failed, using %s,"
+					   " link beat status %4.4x.\n",
+					   dev->name, medianame[dev->if_port], csr12);
+		}
+
+		if (tp->mtable) {
+			int i;
+			for (i = 0; i < tp->mtable->leafcount; i++)
+				if (tp->mtable->mleaf[i].media == dev->if_port) {
+					tp->cur_index = i;
+					select_media(dev, 0);
+					setup_done = 1;
+					break;
+				}
+		}
+		if ( ! setup_done) {
+			tp->csr6 = dev->if_port & 1 ? 0x83860000 : 0x82420000;
+			if (tp->full_duplex)
+				tp->csr6 |= 0x0200;
+			outl(1, ioaddr + CSR13);
+		}
+#if 0							/* Restart shouldn't be needed. */
+		outl(tp->csr6 | 0x0000, ioaddr + CSR6);
+		if (debug > 2)
+			printk(KERN_DEBUG "%s:  Restarting Tx and Rx, CSR5 is %8.8x.\n",
+				   dev->name, inl(ioaddr + CSR5));
+#endif
+		outl(tp->csr6 | 0x2002, ioaddr + CSR6);
+		if (debug > 2)
+			printk(KERN_DEBUG "%s:  Setting CSR6 %8.8x/%x CSR12 %8.8x.\n",
+				   dev->name, tp->csr6, inl(ioaddr + CSR6),
+				   inl(ioaddr + CSR12));
+	} else if ((tp->nwayset  &&  (csr5 & 0x08000000)
+				&& (dev->if_port == 3  ||  dev->if_port == 5)
+				&& (csr12 & 2) == 2) ||
+			   (tp->nway && (csr5 & (TPLnkFail)))) {
+		/* Link blew? Maybe restart NWay. */
+		del_timer(&tp->timer);
+		t21142_start_nway(dev);
+		tp->timer.expires = RUN_AT(3*HZ);
+		add_timer(&tp->timer);
+	} else if (dev->if_port == 3  ||  dev->if_port == 5) {
+		if (tulip_debug > 1)
+			printk(KERN_INFO"%s: 21143 %s link beat %s.\n",
+				   dev->name, medianame[dev->if_port],
+				   (csr12 & 2) ? "failed" : "good");
+		if ((csr12 & 2)  &&  ! tp->medialock) {
+			del_timer(&tp->timer);
+			t21142_start_nway(dev);
+			tp->timer.expires = RUN_AT(3*HZ);
+			add_timer(&tp->timer);
+		}
+	} else if (dev->if_port == 0  ||  dev->if_port == 4) {
+		if ((csr12 & 4) == 0)
+			printk(KERN_INFO"%s: 21143 10baseT link beat good.\n",
+				   dev->name);
+	} else if (!(csr12 & 4)) {		/* 10mbps link beat good. */
+		if (tulip_debug)
+			printk(KERN_INFO"%s: 21143 10mbps sensed media.\n",
+				   dev->name);
+		dev->if_port = 0;
+	} else if (tp->nwayset) {
+		if (tulip_debug)
+			printk(KERN_INFO"%s: 21143 using NWay-set %s, csr6 %8.8x.\n",
+				   dev->name, medianame[dev->if_port], tp->csr6);
+	} else {		/* 100mbps link beat good. */
+		if (tulip_debug)
+			printk(KERN_INFO"%s: 21143 100baseTx sensed media.\n",
+				   dev->name);
+		dev->if_port = 3;
+		tp->csr6 = 0x83860000;
+		outl(0x0003FF7F, ioaddr + CSR14);
+		outl(0x0301, ioaddr + CSR12);
+		outl(tp->csr6 | 0x0002, ioaddr + CSR6);
+		outl(tp->csr6 | 0x2002, ioaddr + CSR6);
+	}
+}
+
+static void mxic_timer(unsigned long data)
+{
+	struct net_device *dev = (struct net_device *)data;
+	struct tulip_private *tp = (struct tulip_private *)dev->priv;
+	long ioaddr = dev->base_addr;
+	int next_tick = 60*HZ;
+
+	if (tulip_debug > 3) {
+		printk(KERN_INFO"%s: MXIC negotiation status %8.8x.\n", dev->name,
+			   inl(ioaddr + CSR12));
+	}
+	if (next_tick) {
+		tp->timer.expires = RUN_AT(next_tick);
+		add_timer(&tp->timer);
+	}
+}
+
+static void pnic_do_nway(struct net_device *dev)
+{
+	struct tulip_private *tp = (struct tulip_private *)dev->priv;
+	long ioaddr = dev->base_addr;
+	u32 phy_reg = inl(ioaddr + 0xB8);
+	u32 new_csr6 = tp->csr6 & ~0x40C40200;
+
+	if (phy_reg & 0x78000000) { /* Ignore baseT4 */
+		if (phy_reg & 0x20000000)		dev->if_port = 5;
+		else if (phy_reg & 0x40000000)	dev->if_port = 3;
+		else if (phy_reg & 0x10000000)	dev->if_port = 4;
+		else if (phy_reg & 0x08000000)	dev->if_port = 0;
+		tp->nwayset = 1;
+		new_csr6 = (dev->if_port & 1) ? 0x01860000 : 0x00420000;
+		outl(0x32 | (dev->if_port & 1), ioaddr + CSR12);
+		if (dev->if_port & 1)
+			outl(0x1F868, ioaddr + 0xB8);
+		if (phy_reg & 0x30000000) {
+			tp->full_duplex = 1;
+			new_csr6 |= 0x00000200;
+		}
+		if (tulip_debug > 1)
+			printk(KERN_DEBUG "%s: PNIC autonegotiated status %8.8x, %s.\n",
+				   dev->name, phy_reg, medianame[dev->if_port]);
+		if (tp->csr6 != new_csr6) {
+			tp->csr6 = new_csr6;
+			outl(tp->csr6 | 0x0002, ioaddr + CSR6); /* Restart Tx */
+			outl(tp->csr6 | 0x2002, ioaddr + CSR6);
+			dev->trans_start = jiffies;
+		}
+	}
+}
+static void pnic_lnk_change(struct net_device *dev, int csr5)
+{
+	struct tulip_private *tp = (struct tulip_private *)dev->priv;
+	long ioaddr = dev->base_addr;
+	int phy_reg = inl(ioaddr + 0xB8);
+
+	if (tulip_debug > 1)
+		printk(KERN_DEBUG "%s: PNIC link changed state %8.8x, CSR5 %8.8x.\n",
+			   dev->name, phy_reg, csr5);
+	if (inl(ioaddr + CSR5) & TPLnkFail) {
+		outl((inl(ioaddr + CSR7) & ~TPLnkFail) | TPLnkPass, ioaddr + CSR7);
+		if (! tp->nwayset  ||  jiffies - dev->trans_start > 1*HZ) {
+			tp->csr6 = 0x00420000 | (tp->csr6 & 0x0000fdff);
+			outl(tp->csr6, ioaddr + CSR6);
+			outl(0x30, ioaddr + CSR12);
+			outl(0x0201F078, ioaddr + 0xB8); /* Turn on autonegotiation. */
+			dev->trans_start = jiffies;
+		}
+	} else if (inl(ioaddr + CSR5) & TPLnkPass) {
+		pnic_do_nway(dev);
+		outl((inl(ioaddr + CSR7) & ~TPLnkPass) | TPLnkFail, ioaddr + CSR7);
+	}
+}
+static void pnic_timer(unsigned long data)
+{
+	struct net_device *dev = (struct net_device *)data;
+	struct tulip_private *tp = (struct tulip_private *)dev->priv;
+	long ioaddr = dev->base_addr;
+	int next_tick = 60*HZ;
+
+	if (media_cap[dev->if_port] & MediaIsMII) {
+		if (check_duplex(dev) > 0)
+			next_tick = 3*HZ;
+	} else {
+		int csr12 = inl(ioaddr + CSR12);
+		int new_csr6 = tp->csr6 & ~0x40C40200;
+		int phy_reg = inl(ioaddr + 0xB8);
+		int csr5 = inl(ioaddr + CSR5);
+
+		if (tulip_debug > 1)
+			printk(KERN_DEBUG "%s: PNIC timer PHY status %8.8x, %s "
+				   "CSR5 %8.8x.\n",
+				   dev->name, phy_reg, medianame[dev->if_port], csr5);
+		if (phy_reg & 0x04000000) {	/* Remote link fault */
+			outl(0x0201F078, ioaddr + 0xB8);
+			next_tick = 1*HZ;
+			tp->nwayset = 0;
+		} else if (phy_reg & 0x78000000) { /* Ignore baseT4 */
+			pnic_do_nway(dev);
+			next_tick = 60*HZ;
+		} else if (csr5 & TPLnkFail) { /* 100baseTx link beat */
+			if (tulip_debug > 1)
+				printk(KERN_DEBUG "%s: %s link beat failed, CSR12 %4.4x, "
+					   "CSR5 %8.8x, PHY %3.3x.\n",
+					   dev->name, medianame[dev->if_port], csr12,
+					   inl(ioaddr + CSR5), inl(ioaddr + 0xB8));
+			next_tick = 3*HZ;
+			if (tp->medialock) {
+			} else if (tp->nwayset  &&  (dev->if_port & 1)) {
+				next_tick = 1*HZ;
+			} else if (dev->if_port == 0) {
+				dev->if_port = 3;
+				outl(0x33, ioaddr + CSR12);
+				new_csr6 = 0x01860000;
+				outl(0x1F868, ioaddr + 0xB8);
+			} else {
+				dev->if_port = 0;
+				outl(0x32, ioaddr + CSR12);
+				new_csr6 = 0x00420000;
+				outl(0x1F078, ioaddr + 0xB8);
+			}
+			if (tp->csr6 != new_csr6) {
+				tp->csr6 = new_csr6;
+				outl(tp->csr6 | 0x0002, ioaddr + CSR6); /* Restart Tx */
+				outl(tp->csr6 | 0x2002, ioaddr + CSR6);
+				dev->trans_start = jiffies;
+				if (tulip_debug > 1)
+					printk(KERN_INFO "%s: Changing PNIC configuration to %s "
+						   "%s-duplex, CSR6 %8.8x.\n",
+						   dev->name, medianame[dev->if_port],
+						   tp->full_duplex ? "full" : "half", new_csr6);
+			}
+		}
+	}
+	tp->timer.expires = RUN_AT(next_tick);
+	add_timer(&tp->timer);
+}
+
+static void comet_timer(unsigned long data)
+{
+	struct net_device *dev = (struct net_device *)data;
+	struct tulip_private *tp = (struct tulip_private *)dev->priv;
+	long ioaddr = dev->base_addr;
+	int next_tick = 60*HZ;
+
+	if (tulip_debug > 1)
+		printk(KERN_DEBUG "%s: Comet link status %4.4x partner capability "
+			   "%4.4x.\n",
+			   dev->name, inl(ioaddr + 0xB8), inl(ioaddr + 0xC8));
+	tp->timer.expires = RUN_AT(next_tick);
+	add_timer(&tp->timer);
+}
+
+static void tulip_tx_timeout(struct net_device *dev)
+{
+	struct tulip_private *tp = (struct tulip_private *)dev->priv;
+	long ioaddr = dev->base_addr;
+
+	if (media_cap[dev->if_port] & MediaIsMII) {
+		/* Do nothing -- the media monitor should handle this. */
+		if (tulip_debug > 1)
+			printk(KERN_WARNING "%s: Transmit timeout using MII device.\n",
+				   dev->name);
+	} else if (tp->chip_id == DC21040) {
+		if ( !tp->medialock  &&  inl(ioaddr + CSR12) & 0x0002) {
+			dev->if_port = (dev->if_port == 2 ? 0 : 2);
+			printk(KERN_INFO "%s: transmit timed out, switching to "
+				   "%s.\n",
+				   dev->name, medianame[dev->if_port]);
+			select_media(dev, 0);
+		}
+		dev->trans_start = jiffies;
+		return;
+	} else if (tp->chip_id == DC21041) {
+		int csr12 = inl(ioaddr + CSR12);
+
+		printk(KERN_WARNING "%s: 21041 transmit timed out, status %8.8x, "
+			   "CSR12 %8.8x, CSR13 %8.8x, CSR14 %8.8x, resetting...\n",
+			   dev->name, inl(ioaddr + CSR5), csr12,
+			   inl(ioaddr + CSR13), inl(ioaddr + CSR14));
+		tp->mediasense = 1;
+		if ( ! tp->medialock) {
+			if (dev->if_port == 1 || dev->if_port == 2)
+				if (csr12 & 0x0004) {
+					dev->if_port = 2 - dev->if_port;
+				} else
+					dev->if_port = 0;
+			else
+				dev->if_port = 1;
+			select_media(dev, 0);
+		}
+	} else if (tp->chip_id == DC21140 || tp->chip_id == DC21142
+			   || tp->chip_id == MX98713 || tp->chip_id == COMPEX9881) {
+		printk(KERN_WARNING "%s: 21140 transmit timed out, status %8.8x, "
+			   "SIA %8.8x %8.8x %8.8x %8.8x, resetting...\n",
+			   dev->name, inl(ioaddr + CSR5), inl(ioaddr + CSR12),
+			   inl(ioaddr + CSR13), inl(ioaddr + CSR14), inl(ioaddr + CSR15));
+		if ( ! tp->medialock  &&  tp->mtable) {
+			do
+				--tp->cur_index;
+			while (tp->cur_index >= 0
+				   && (media_cap[tp->mtable->mleaf[tp->cur_index].media]
+					   & MediaIsFD));
+			if (--tp->cur_index < 0) {
+				/* We start again, but should instead look for default. */
+				tp->cur_index = tp->mtable->leafcount - 1;
+			}
+			select_media(dev, 0);
+			printk(KERN_WARNING "%s: transmit timed out, switching to %s "
+				   "media.\n", dev->name, medianame[dev->if_port]);
+		}
+	} else {
+		printk(KERN_WARNING "%s: Transmit timed out, status %8.8x, CSR12 "
+			   "%8.8x, resetting...\n",
+			   dev->name, inl(ioaddr + CSR5), inl(ioaddr + CSR12));
+		dev->if_port = 0;
+	}
+
+#if defined(way_too_many_messages)
+	if (tulip_debug > 3) {
+		int i;
+		for (i = 0; i < RX_RING_SIZE; i++) {
+			u8 *buf = (u8 *)(tp->rx_ring[i].buffer1);
+			int j;
+			printk(KERN_DEBUG "%2d: %8.8x %8.8x %8.8x %8.8x  "
+				   "%2.2x %2.2x %2.2x.\n",
+				   i, (unsigned int)tp->rx_ring[i].status,
+				   (unsigned int)tp->rx_ring[i].length,
+				   (unsigned int)tp->rx_ring[i].buffer1,
+				   (unsigned int)tp->rx_ring[i].buffer2,
+				   buf[0], buf[1], buf[2]);
+			for (j = 0; buf[j] != 0xee && j < 1600; j++)
+				if (j < 100) printk(" %2.2x", buf[j]);
+			printk(" j=%d.\n", j);
+		}
+		printk(KERN_DEBUG "  Rx ring %8.8x: ", (int)tp->rx_ring);
+		for (i = 0; i < RX_RING_SIZE; i++)
+			printk(" %8.8x", (unsigned int)tp->rx_ring[i].status);
+		printk("\n" KERN_DEBUG "  Tx ring %8.8x: ", (int)tp->tx_ring);
+		for (i = 0; i < TX_RING_SIZE; i++)
+			printk(" %8.8x", (unsigned int)tp->tx_ring[i].status);
+		printk("\n");
+	}
+#endif
+
+	/* Stop and restart the chip's Tx processes . */
+	outl_CSR6(tp->csr6 | 0x0002, ioaddr, tp->chip_id);
+	outl_CSR6(tp->csr6 | 0x2002, ioaddr, tp->chip_id);
+	/* Trigger an immediate transmit demand. */
+	outl(0, ioaddr + CSR1);
+
+	dev->trans_start = jiffies;
+	tp->stats.tx_errors++;
+	return;
+}
+
+
+/* Initialize the Rx and Tx rings, along with various 'dev' bits. */
+static void tulip_init_ring(struct net_device *dev)
+{
+	struct tulip_private *tp = (struct tulip_private *)dev->priv;
+	int i;
+
+	for (i = 0; i < RX_RING_SIZE; i++) {
+		tp->rx_ring[i].status = 0x00000000;
+		tp->rx_ring[i].length = cpu_to_le32(PKT_BUF_SZ);
+		tp->rx_ring[i].buffer2 = virt_to_le32desc(&tp->rx_ring[i+1]);
+		tp->rx_skbuff[i] = NULL;
+	}
+	/* Mark the last entry as wrapping the ring. */
+	tp->rx_ring[i-1].length = cpu_to_le32(PKT_BUF_SZ | DESC_RING_WRAP);
+	tp->rx_ring[i-1].buffer2 = virt_to_le32desc(&tp->rx_ring[0]);
+
+	for (i = 0; i < RX_RING_SIZE; i++) {
+		/* Note the receive buffer must be longword aligned.
+		   dev_alloc_skb() provides 16 byte alignment.  But do *not*
+		   use skb_reserve() to align the IP header! */
+		struct sk_buff *skb = dev_alloc_skb(PKT_BUF_SZ);
+		tp->rx_skbuff[i] = skb;
+		if (skb == NULL)
+			break;
+		skb->dev = dev;			/* Mark as being used by this device. */
+		tp->rx_ring[i].status = cpu_to_le32(DescOwned);	/* Owned by Tulip chip */
+		tp->rx_ring[i].buffer1 = virt_to_le32desc(skb->tail);
+	}
+	tp->dirty_rx = (unsigned int)(i - RX_RING_SIZE);
+
+	/* The Tx buffer descriptor is filled in as needed, but we
+	   do need to clear the ownership bit. */
+	for (i = 0; i < TX_RING_SIZE; i++) {
+		tp->tx_skbuff[i] = 0;
+		tp->tx_ring[i].status = 0x00000000;
+		tp->tx_ring[i].buffer2 = virt_to_le32desc(&tp->tx_ring[i+1]);
+#ifdef CARDBUS
+		if (tp->chip_id == X3201_3)
+			tp->tx_aligned_skbuff[i] = dev_alloc_skb(PKT_BUF_SZ);
+#endif
+	}
+	tp->tx_ring[i-1].buffer2 = virt_to_le32desc(&tp->tx_ring[0]);
+}
+
+static int
+tulip_start_xmit(struct sk_buff *skb, struct net_device *dev)
+{
+	struct tulip_private *tp = (struct tulip_private *)dev->priv;
+	int entry;
+	u32 flag;
+
+	tx_timeout_check(dev, tulip_tx_timeout);
+
+	/* Caution: the write order is important here, set the field
+	   with the ownership bits last. */
+
+	/* Calculate the next Tx descriptor entry. */
+	entry = tp->cur_tx % TX_RING_SIZE;
+
+	tp->tx_skbuff[entry] = skb;
+#ifdef CARDBUS
+	if (tp->chip_id == X3201_3) {
+		memcpy(tp->tx_aligned_skbuff[entry]->data,skb->data,skb->len);
+		tp->tx_ring[entry].buffer1 = virt_to_le32desc(tp->tx_aligned_skbuff[entry]->data);
+	} else
+#endif
+	tp->tx_ring[entry].buffer1 = virt_to_le32desc(skb->data);
+
+	if (tp->cur_tx - tp->dirty_tx < TX_RING_SIZE/2) {/* Typical path */
+		flag = 0x60000000; /* No interrupt */
+	} else if (tp->cur_tx - tp->dirty_tx == TX_RING_SIZE/2) {
+		flag = 0xe0000000; /* Tx-done intr. */
+	} else if (tp->cur_tx - tp->dirty_tx < TX_RING_SIZE - 2) {
+		flag = 0x60000000; /* No Tx-done intr. */
+	} else {		/* Leave room for set_rx_mode() to fill entries. */
+		tp->tx_full = 1;
+		flag = 0xe0000000; /* Tx-done intr. */
+	}
+	if (entry == TX_RING_SIZE-1)
+		flag = 0xe0000000 | DESC_RING_WRAP;
+
+	tp->tx_ring[entry].length = cpu_to_le32(skb->len | flag);
+	tp->tx_ring[entry].status = cpu_to_le32(DescOwned);
+	tp->cur_tx++;
+	if ( ! tp->tx_full)
+		netif_start_queue(dev);
+
+	dev->trans_start = jiffies;
+	/* Trigger an immediate transmit demand. */
+	outl(0, dev->base_addr + CSR1);
+
+	return 0;
+}
+
+/* The interrupt handler does all of the Rx thread work and cleans up
+   after the Tx thread. */
+static void tulip_interrupt(int irq, void *dev_instance, struct pt_regs *regs)
+{
+	struct net_device *dev = (struct net_device *)dev_instance;
+	struct tulip_private *tp = (struct tulip_private *)dev->priv;
+	long ioaddr = dev->base_addr;
+	int csr5;
+	int entry;
+	int missed;
+	int rx = 0;
+	int tx = 0;
+	int oi = 0;
+	int maxrx = RX_RING_SIZE;
+	int maxtx = TX_RING_SIZE;
+	int maxoi = TX_RING_SIZE;
+
+	tp->nir++;
+
+	do {
+		csr5 = inl(ioaddr + CSR5);
+		/* Acknowledge all of the current interrupt sources ASAP. */
+		outl(csr5 & 0x0001ffff, ioaddr + CSR5);
+
+		if (tulip_debug > 4)
+			printk(KERN_DEBUG "%s: interrupt  csr5=%#8.8x new csr5=%#8.8x.\n",
+				   dev->name, csr5, inl(dev->base_addr + CSR5));
+
+		if (csr5 == 0xffffffff)
+			break;	/* all bits set, assume PCMCIA card removed */
+
+		if ((csr5 & (NormalIntr|AbnormalIntr)) == 0)
+			break;
+
+		if (csr5 & (RxIntr | RxNoBuf)) {
+			rx += tulip_rx(dev);
+			tulip_refill_rx(dev);
+		}
+
+		if (csr5 & (TxNoBuf | TxDied | TxIntr | TimerInt)) {
+			unsigned int dirty_tx;
+
+			for (dirty_tx = tp->dirty_tx; tp->cur_tx - dirty_tx > 0;
+				 dirty_tx++) {
+				int entry = dirty_tx % TX_RING_SIZE;
+				int status = le32_to_cpu(tp->tx_ring[entry].status);
+
+				if (status < 0)
+					break;			/* It still has not been Txed */
+				/* Check for Rx filter setup frames. */
+				if (tp->tx_skbuff[entry] == NULL)
+				  continue;
+
+				if (status & 0x8000) {
+					/* There was an major error, log it. */
+#ifndef final_version
+					if (tulip_debug > 1)
+						printk(KERN_DEBUG "%s: Transmit error, Tx status %8.8x.\n",
+							   dev->name, status);
+#endif
+					tp->stats.tx_errors++;
+					if (status & 0x4104) tp->stats.tx_aborted_errors++;
+					if (status & 0x0C00) tp->stats.tx_carrier_errors++;
+					if (status & 0x0200) tp->stats.tx_window_errors++;
+					if (status & 0x0002) tp->stats.tx_fifo_errors++;
+					if ((status & 0x0080) && tp->full_duplex == 0)
+						tp->stats.tx_heartbeat_errors++;
+#ifdef ETHER_STATS
+					if (status & 0x0100) tp->stats.collisions16++;
+#endif
+				} else {
+#ifdef ETHER_STATS
+					if (status & 0x0001) tp->stats.tx_deferred++;
+#endif
+#if LINUX_VERSION_CODE > 0x20127
+					tp->stats.tx_bytes += tp->tx_skbuff[entry]->len;
+#endif
+					tp->stats.collisions += (status >> 3) & 15;
+					tp->stats.tx_packets++;
+				}
+
+				/* Free the original skb. */
+				dev_kfree_skb_irq(tp->tx_skbuff[entry]);
+				tp->tx_skbuff[entry] = 0;
+				tx++;
+			}
+
+#ifndef final_version
+			if (tp->cur_tx - dirty_tx > TX_RING_SIZE) {
+				printk(KERN_ERR "%s: Out-of-sync dirty pointer, %d vs. %d, full=%d.\n",
+					   dev->name, dirty_tx, tp->cur_tx, tp->tx_full);
+				dirty_tx += TX_RING_SIZE;
+			}
+#endif
+
+			if (tp->tx_full && tp->cur_tx - dirty_tx  < TX_RING_SIZE - 2) {
+				/* The ring is no longer full, restart queue. */
+				tp->tx_full = 0;
+				netif_wake_queue(dev);
+			}
+
+			tp->dirty_tx = dirty_tx;
+			if (csr5 & TxDied) {
+				if (tulip_debug > 2)
+					printk(KERN_WARNING "%s: The transmitter stopped."
+						   "  CSR5 is %x, CSR6 %x, new CSR6 %x.\n",
+						   dev->name, csr5, inl(ioaddr + CSR6), tp->csr6);
+				outl_CSR6(tp->csr6 | 0x0002, ioaddr, tp->chip_id);
+				outl_CSR6(tp->csr6 | 0x2002, ioaddr, tp->chip_id);
+			}
+		}
+
+		/* Log errors. */
+		if (csr5 & AbnormalIntr) {	/* Abnormal error summary bit. */
+			if (csr5 == 0xffffffff)
+				break;
+			if (csr5 & TxJabber) tp->stats.tx_errors++;
+			if (csr5 & TxFIFOUnderflow) {
+				if ((tp->csr6 & 0xC000) != 0xC000)
+					tp->csr6 += 0x4000;	/* Bump up the Tx threshold */
+				else
+					tp->csr6 |= 0x00200000;  /* Store-n-forward. */
+				/* Restart the transmit process. */
+				outl_CSR6(tp->csr6 | 0x0002, ioaddr, tp->chip_id);
+				outl_CSR6(tp->csr6 | 0x2002, ioaddr, tp->chip_id);
+				outl(0, ioaddr + CSR1);
+			}
+			if (csr5 & RxDied) {		/* Missed a Rx frame. */
+				tp->stats.rx_errors++;
+				tp->stats.rx_missed_errors += inl(ioaddr + CSR8) & 0xffff;
+				outl_CSR6(tp->csr6 | 0x2002, ioaddr, tp->chip_id);
+			}
+			if (csr5 & (TPLnkPass | TPLnkFail | 0x08000000)) {
+				if (tp->link_change)
+					(tp->link_change)(dev, csr5);
+			}
+			if (csr5 & SytemError) {
+				printk(KERN_ERR "%s: (%lu) System Error occured\n", dev->name, tp->nir);
+			}
+			/* Clear all error sources, included undocumented ones! */
+			outl(0x0800f7ba, ioaddr + CSR5);
+			oi++;
+		}
+		if (csr5 & TimerInt) {
+#if 0
+			if (tulip_debug > 2)
+				printk(KERN_ERR "%s: Re-enabling interrupts, %8.8x.\n",
+					   dev->name, csr5);
+			outl(tulip_tbl[tp->chip_id].valid_intrs, ioaddr + CSR7);
+#endif
+			tp->ttimer = 0;
+			oi++;
+		}
+		if (tx > maxtx || rx > maxrx || oi > maxoi) {
+			if (tulip_debug > 1)
+				printk(KERN_WARNING "%s: Too much work during an interrupt, "
+					   "csr5=0x%8.8x. (%lu) (%d,%d,%d)\n", dev->name, csr5, tp->nir, tx, rx, oi);
+			/* Acknowledge all interrupt sources. */
+#if 0
+			/* Clear all interrupting sources, set timer to re-enable. */
+			outl(((~csr5) & 0x0001ebef) | NormalIntr | AbnormalIntr | TimerInt,
+				 ioaddr + CSR7);
+			outl(12, ioaddr + CSR11);
+			tp->ttimer = 1;
+#endif
+			break;
+		}
+	} while (1);
+
+	tulip_refill_rx(dev);
+
+	/* check if we card is in suspend mode */
+	entry = tp->dirty_rx % RX_RING_SIZE;
+	if (tp->rx_skbuff[entry] == NULL) {
+		if (tulip_debug > 1)
+			printk(KERN_WARNING "%s: in rx suspend mode: (%lu) (tp->cur_rx = %u, ttimer = %d, rx = %d) go/stay in suspend mode\n", dev->name, tp->nir, tp->cur_rx, tp->ttimer, rx);
+		if (tp->ttimer == 0 || (inl(ioaddr + CSR11) & 0xffff) == 0) {
+			if (tulip_debug > 1)
+				printk(KERN_WARNING "%s: in rx suspend mode: (%lu) set timer\n", dev->name, tp->nir);
+			outl(tulip_tbl[tp->chip_id].valid_intrs | TimerInt,
+				 ioaddr + CSR7);
+			outl(TimerInt, ioaddr + CSR5);
+			outl(12, ioaddr + CSR11);
+			tp->ttimer = 1;
+		}
+	}
+
+	if ((missed = inl(ioaddr + CSR8) & 0x1ffff)) {
+		tp->stats.rx_dropped += missed & 0x10000 ? 0x10000 : missed;
+	}
+
+	if (tulip_debug > 4)
+		printk(KERN_DEBUG "%s: exiting interrupt, csr5=%#4.4x.\n",
+			   dev->name, inl(ioaddr + CSR5));
+
+	return;
+}
+
+static int tulip_refill_rx(struct net_device *dev)
+{
+	struct tulip_private *tp = (struct tulip_private *)dev->priv;
+	int entry;
+	int refilled = 0;
+
+	/* Refill the Rx ring buffers. */
+	for (; tp->cur_rx - tp->dirty_rx > 0; tp->dirty_rx++) {
+		entry = tp->dirty_rx % RX_RING_SIZE;
+		if (tp->rx_skbuff[entry] == NULL) {
+			struct sk_buff *skb;
+			skb = tp->rx_skbuff[entry] = dev_alloc_skb(PKT_BUF_SZ);
+			if (skb == NULL)
+				break;
+			skb->dev = dev;			/* Mark as being used by this device. */
+			tp->rx_ring[entry].buffer1 = virt_to_le32desc(skb->tail);
+			refilled++;
+		}
+		tp->rx_ring[entry].status = cpu_to_le32(DescOwned);
+	}
+	return refilled;
+}
+
+static int tulip_rx(struct net_device *dev)
+{
+	struct tulip_private *tp = (struct tulip_private *)dev->priv;
+	int entry = tp->cur_rx % RX_RING_SIZE;
+	int rx_work_limit = tp->dirty_rx + RX_RING_SIZE - tp->cur_rx;
+	int received = 0;
+
+	if (tulip_debug > 4)
+		printk(KERN_DEBUG " In tulip_rx(), entry %d %8.8x.\n", entry,
+			   tp->rx_ring[entry].status);
+	/* If we own the next entry, it is a new packet. Send it up. */
+	while ( ! (tp->rx_ring[entry].status & cpu_to_le32(DescOwned))) {
+		s32 status = le32_to_cpu(tp->rx_ring[entry].status);
+
+		if (tulip_debug > 5)
+			printk(KERN_DEBUG "%s: In tulip_rx(), entry %d %8.8x.\n",
+				   dev->name, entry, status);
+		if (--rx_work_limit < 0)
+			break;
+		if ((status & 0x38008300) != 0x0300) {
+			if ((status & 0x38000300) != 0x0300) {
+				/* Ingore earlier buffers. */
+				if ((status & 0xffff) != 0x7fff) {
+					if (tulip_debug > 1)
+						printk(KERN_WARNING "%s: Oversized Ethernet frame "
+							   "spanned multiple buffers, status %8.8x!\n",
+							   dev->name, status);
+					tp->stats.rx_length_errors++;
+				}
+			} else if (status & RxDescFatalErr) {
+				/* There was a fatal error. */
+				if (tulip_debug > 2)
+					printk(KERN_DEBUG "%s: Receive error, Rx status %8.8x.\n",
+						   dev->name, status);
+				tp->stats.rx_errors++; /* end of a packet.*/
+				if (status & 0x0890) tp->stats.rx_length_errors++;
+				if (status & 0x0004) tp->stats.rx_frame_errors++;
+				if (status & 0x0002) tp->stats.rx_crc_errors++;
+				if (status & 0x0001) tp->stats.rx_fifo_errors++;
+			}
+		} else {
+			/* Omit the four octet CRC from the length. */
+			short pkt_len = ((status >> 16) & 0x7ff) - 4;
+			struct sk_buff *skb;
+
+#ifndef final_version
+			if (pkt_len > 1518) {
+				printk(KERN_WARNING "%s: Bogus packet size of %d (%#x).\n",
+					   dev->name, pkt_len, pkt_len);
+				pkt_len = 1518;
+				tp->stats.rx_length_errors++;
+			}
+#endif
+			/* Check if the packet is long enough to accept without copying
+			   to a minimally-sized skbuff. */
+			if (pkt_len < rx_copybreak
+				&& (skb = dev_alloc_skb(pkt_len + 2)) != NULL) {
+				skb->dev = dev;
+				skb_reserve(skb, 2);	/* 16 byte align the IP header */
+#if ! defined(__alpha__)
+				eth_copy_and_sum(skb, tp->rx_skbuff[entry]->tail, pkt_len, 0);
+				skb_put(skb, pkt_len);
+#else
+				memcpy(skb_put(skb, pkt_len), tp->rx_skbuff[entry]->tail,
+					   pkt_len);
+#endif
+			} else { 	/* Pass up the skb already on the Rx ring. */
+				char *temp = skb_put(skb = tp->rx_skbuff[entry], pkt_len);
+				tp->rx_skbuff[entry] = NULL;
+#ifndef final_version
+				if (le32desc_to_virt(tp->rx_ring[entry].buffer1) != temp)
+					printk(KERN_ERR "%s: Internal fault: The skbuff addresses "
+						   "do not match in tulip_rx: %p vs. %p / %p.\n",
+						   dev->name,
+						   le32desc_to_virt(tp->rx_ring[entry].buffer1),
+						   skb->head, temp);
+#endif
+			}
+			skb->protocol = eth_type_trans(skb, dev);
+			netif_rx(skb);
+			dev->last_rx = jiffies;
+			tp->stats.rx_packets++;
+#if LINUX_VERSION_CODE > 0x20127
+			tp->stats.rx_bytes += pkt_len;
+#endif
+		}
+		received++;
+		entry = (++tp->cur_rx) % RX_RING_SIZE;
+	}
+
+	return received;
+}
+
+static void
+tulip_down(struct net_device *dev)
+{
+	long ioaddr = dev->base_addr;
+	struct tulip_private *tp = (struct tulip_private *)dev->priv;
+
+	/* Disable interrupts by clearing the interrupt mask. */
+	outl(0x00000000, ioaddr + CSR7);
+	/* Stop the chip's Tx and Rx processes. */
+	outl_CSR6(inl(ioaddr + CSR6) & ~0x2002, ioaddr, tp->chip_id);
+	/* 21040 -- Leave the card in 10baseT state. */
+	if (tp->chip_id == DC21040)
+		outl(0x00000004, ioaddr + CSR13);
+
+	if (inl(ioaddr + CSR6) != 0xffffffff)
+		tp->stats.rx_missed_errors += inl(ioaddr + CSR8) & 0xffff;
+
+	del_timer(&tp->timer);
+
+	dev->if_port = tp->saved_if_port;
+
+	/* Leave the driver in snooze, not sleep, mode. */
+	if (tp->flags & HAS_PWRDWN)
+		pcibios_write_config_dword(tp->pci_bus, tp->pci_devfn, 0x40,
+								   0x40000000);
+}
+
+static int
+tulip_close(struct net_device *dev)
+{
+	long ioaddr = dev->base_addr;
+	struct tulip_private *tp = (struct tulip_private *)dev->priv;
+	int i;
+
+	if (tulip_debug > 1)
+		printk(KERN_DEBUG "%s: Shutting down ethercard, status was %2.2x.\n",
+			   dev->name, inl(ioaddr + CSR5));
+
+	if (netif_device_present(dev)) {
+		netif_stop_queue(dev);
+		netif_mark_down(dev);
+		tulip_down(dev);
+	}
+
+	free_irq(dev->irq, dev);
+
+	/* Free all the skbuffs in the Rx queue. */
+	for (i = 0; i < RX_RING_SIZE; i++) {
+		struct sk_buff *skb = tp->rx_skbuff[i];
+		tp->rx_skbuff[i] = 0;
+		tp->rx_ring[i].status = 0;		/* Not owned by Tulip chip. */
+		tp->rx_ring[i].length = 0;
+		tp->rx_ring[i].buffer1 = 0xBADF00D0; /* An invalid address. */
+		if (skb) {
+#if LINUX_VERSION_CODE < 0x20100
+			skb->free = 1;
+#endif
+			dev_free_skb(skb);
+		}
+	}
+	for (i = 0; i < TX_RING_SIZE; i++) {
+		if (tp->tx_skbuff[i])
+			dev_free_skb(tp->tx_skbuff[i]);
+		tp->tx_skbuff[i] = 0;
+#ifdef CARDBUS
+		if (tp->tx_aligned_skbuff[i])
+			dev_free_skb(tp->tx_aligned_skbuff[i]);
+		tp->tx_aligned_skbuff[i] = 0;
+#endif
+	}
+
+	MOD_DEC_USE_COUNT;
+	tp->open = 0;
+	return 0;
+}
+
+static struct net_device_stats *tulip_get_stats(struct net_device *dev)
+{
+	struct tulip_private *tp = (struct tulip_private *)dev->priv;
+	long ioaddr = dev->base_addr;
+
+	if (netif_device_present(dev))
+		tp->stats.rx_missed_errors += inl(ioaddr + CSR8) & 0xffff;
+
+	return &tp->stats;
+}
+
+#ifdef HAVE_PRIVATE_IOCTL
+/* Provide ioctl() calls to examine the MII xcvr state. */
+static int private_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
+{
+	struct tulip_private *tp = (struct tulip_private *)dev->priv;
+	long ioaddr = dev->base_addr;
+	u16 *data = (u16 *)&rq->ifr_data;
+	int phy = tp->phys[0] & 0x1f;
+	long flags;
+
+	switch(cmd) {
+	case SIOCDEVPRIVATE:		/* Get the address of the PHY in use. */
+		if (tp->mii_cnt)
+			data[0] = phy;
+		else if (tp->chip_id & HAS_NWAY143)
+			data[0] = 32;
+		else if (tp->chip_id == COMET)
+			data[0] = 1;
+		else
+			return -ENODEV;
+	case SIOCDEVPRIVATE+1:		/* Read the specified MII register. */
+		if (data[0] == 32  &&  (tp->flags & HAS_NWAY143)) {
+			int csr12 = inl(ioaddr + CSR12);
+			int csr14 = inl(ioaddr + CSR14);
+			switch (data[1]) {
+			case 0: {
+				data[3] = (csr14<<5) & 0x1000;
+				break; }
+			case 1:
+				data[3] = 0x7848 + ((csr12&0x7000) == 0x5000 ? 0x20 : 0)
+					+ (csr12&0x06 ? 0x04 : 0);
+				break;
+			case 4: {
+				data[3] = ((csr14>>9)&0x07C0) +
+					((inl(ioaddr + CSR6)>>3)&0x0040) + ((csr14>>1)&0x20) + 1;
+				break;
+			}
+			case 5: data[3] = csr12 >> 16; break;
+			default: data[3] = 0; break;
+			}
+		} else {
+			save_flags(flags);
+			cli();
+			data[3] = mdio_read(dev, data[0] & 0x1f, data[1] & 0x1f);
+			restore_flags(flags);
+		}
+		return 0;
+	case SIOCDEVPRIVATE+2:		/* Write the specified MII register */
+		if (!capable(CAP_NET_ADMIN))
+			return -EPERM;
+		if (data[0] == 32  &&  (tp->flags & HAS_NWAY143)) {
+			if (data[1] == 5)
+				tp->to_advertise = data[2];
+		} else {
+			save_flags(flags);
+			cli();
+			mdio_write(dev, data[0] & 0x1f, data[1] & 0x1f, data[2]);
+			restore_flags(flags);
+		}
+		return 0;
+	default:
+		return -EOPNOTSUPP;
+	}
+
+	return -EOPNOTSUPP;
+}
+#endif  /* HAVE_PRIVATE_IOCTL */
+
+/* Set or clear the multicast filter for this adaptor.
+   Note that we only use exclusion around actually queueing the
+   new frame, not around filling tp->setup_frame.  This is non-deterministic
+   when re-entered but still correct. */
+
+/* The little-endian AUTODIN32 ethernet CRC calculation.
+   N.B. Do not use for bulk data, use a table-based routine instead.
+   This is common code and should be moved to net/core/crc.c */
+static unsigned const ethernet_polynomial_le = 0xedb88320U;
+static inline u32 ether_crc_le(int length, unsigned char *data)
+{
+	u32 crc = 0xffffffff;	/* Initial value. */
+	while(--length >= 0) {
+		unsigned char current_octet = *data++;
+		int bit;
+		for (bit = 8; --bit >= 0; current_octet >>= 1) {
+			if ((crc ^ current_octet) & 1) {
+				crc >>= 1;
+				crc ^= ethernet_polynomial_le;
+			} else
+				crc >>= 1;
+		}
+	}
+	return crc;
+}
+static unsigned const ethernet_polynomial = 0x04c11db7U;
+static inline u32 ether_crc(int length, unsigned char *data)
+{
+    int crc = -1;
+
+    while(--length >= 0) {
+		unsigned char current_octet = *data++;
+		int bit;
+		for (bit = 0; bit < 8; bit++, current_octet >>= 1)
+			crc = (crc << 1) ^
+				((crc < 0) ^ (current_octet & 1) ? ethernet_polynomial : 0);
+    }
+    return crc;
+}
+
+static void set_rx_mode(struct net_device *dev)
+{
+	struct tulip_private *tp = (struct tulip_private *)dev->priv;
+	long ioaddr = dev->base_addr;
+	int csr6 = inl(ioaddr + CSR6) & ~0x00D5;
+
+	tp->csr6 &= ~0x00D5;
+	if (dev->flags & IFF_PROMISC) {			/* Set promiscuous. */
+		tp->csr6 |= 0x00C0;
+		csr6 |= 0x00C0;
+		/* Unconditionally log net taps. */
+		printk(KERN_INFO "%s: Promiscuous mode enabled.\n", dev->name);
+	} else if ((dev->mc_count > 1000)  ||  (dev->flags & IFF_ALLMULTI)) {
+		/* Too many to filter well -- accept all multicasts. */
+		tp->csr6 |= 0x0080;
+		csr6 |= 0x0080;
+	} else	if (tp->flags & MC_HASH_ONLY) {
+		/* Some work-alikes have only a 64-entry hash filter table. */
+		/* Should verify correctness on big-endian/__powerpc__ */
+		struct dev_mc_list *mclist;
+		int i;
+		u32 mc_filter[2];		 /* Multicast hash filter */
+		if (dev->mc_count > 64) {		/* Arbitrary non-effective limit. */
+			tp->csr6 |= 0x0080;
+			csr6 |= 0x0080;
+		} else {
+			mc_filter[1] = mc_filter[0] = 0;
+			for (i = 0, mclist = dev->mc_list; mclist && i < dev->mc_count;
+				 i++, mclist = mclist->next)
+				set_bit(ether_crc(ETH_ALEN, mclist->dmi_addr)>>26, mc_filter);
+			if (tp->chip_id == AX88140) {
+				outl(2, ioaddr + CSR13);
+				outl(mc_filter[0], ioaddr + CSR14);
+				outl(3, ioaddr + CSR13);
+				outl(mc_filter[1], ioaddr + CSR14);
+			} else if (tp->chip_id == COMET) { /* Has a simple hash filter. */
+				outl(mc_filter[0], ioaddr + 0xAC);
+				outl(mc_filter[1], ioaddr + 0xB0);
+			}
+		}
+	} else {
+		u16 *eaddrs, *setup_frm = tp->setup_frame;
+		struct dev_mc_list *mclist;
+		u32 tx_flags = 0x08000000 | 192;
+		int i;
+
+		/* Note that only the low-address shortword of setup_frame is valid!
+		   The values are doubled for big-endian architectures. */
+		if ((dev->mc_count > 14) || ((dev->mc_count > 6) && (tp->chip_id == X3201_3))) { /* Must use a multicast hash table. */
+			u16 hash_table[32];
+			tx_flags = 0x08400000 | 192;		/* Use hash filter. */
+			memset(hash_table, 0, sizeof(hash_table));
+			set_bit(255, hash_table); 			/* Broadcast entry */
+			/* This should work on big-endian machines as well. */
+			for (i = 0, mclist = dev->mc_list; mclist && i < dev->mc_count;
+				 i++, mclist = mclist->next)
+				set_bit(ether_crc_le(ETH_ALEN, mclist->dmi_addr) & 0x1ff,
+						hash_table);
+			for (i = 0; i < 32; i++) {
+				*setup_frm++ = hash_table[i];
+				*setup_frm++ = hash_table[i];
+			}
+			setup_frm = &tp->setup_frame[13*6];
+		} else if(tp->chip_id != X3201_3) {
+			/* We have <= 14 addresses so we can use the wonderful
+			   16 address perfect filtering of the Tulip. */
+			for (i = 0, mclist = dev->mc_list; i < dev->mc_count;
+				 i++, mclist = mclist->next) {
+				eaddrs = (u16 *)mclist->dmi_addr;
+				*setup_frm++ = eaddrs[0]; *setup_frm++ = eaddrs[0];
+				*setup_frm++ = eaddrs[1]; *setup_frm++ = eaddrs[1];
+				*setup_frm++ = eaddrs[2]; *setup_frm++ = eaddrs[2];
+			}
+			/* Fill the unused entries with the broadcast address. */
+			memset(setup_frm, 0xff, (15-i)*12);
+			setup_frm = &tp->setup_frame[15*6];
+		} else {
+			/* fill the first two table entries with our address */
+			eaddrs = (u16 *)dev->dev_addr;
+			for(i=0; i<2; i++) {
+				*setup_frm++ = eaddrs[0]; *setup_frm++ = eaddrs[0];
+				*setup_frm++ = eaddrs[1]; *setup_frm++ = eaddrs[1];
+				*setup_frm++ = eaddrs[2]; *setup_frm++ = eaddrs[2];
+			}
+			/* Double fill each entry to accomodate chips that */
+			/* don't like to parse these correctly */
+			for (i=0, mclist=dev->mc_list; i<dev->mc_count;
+				 i++, mclist=mclist->next) {
+				eaddrs = (u16 *)mclist->dmi_addr;
+				*setup_frm++ = eaddrs[0]; *setup_frm++ = eaddrs[0];
+				*setup_frm++ = eaddrs[1]; *setup_frm++ = eaddrs[1];
+				*setup_frm++ = eaddrs[2]; *setup_frm++ = eaddrs[2];
+				*setup_frm++ = eaddrs[0]; *setup_frm++ = eaddrs[0];
+				*setup_frm++ = eaddrs[1]; *setup_frm++ = eaddrs[1];
+				*setup_frm++ = eaddrs[2]; *setup_frm++ = eaddrs[2];
+			}
+			i=((i+1)*2);
+			/* Fill the unused entries with the broadcast address. */
+			memset(setup_frm, 0xff, (15-i)*12);
+			setup_frm = &tp->setup_frame[15*6];
+		}
+		/* Fill the final entry with our physical address. */
+		eaddrs = (u16 *)dev->dev_addr;
+		*setup_frm++ = eaddrs[0]; *setup_frm++ = eaddrs[0];
+		*setup_frm++ = eaddrs[1]; *setup_frm++ = eaddrs[1];
+		*setup_frm++ = eaddrs[2]; *setup_frm++ = eaddrs[2];
+		/* Now add this frame to the Tx list. */
+		if (tp->cur_tx - tp->dirty_tx > TX_RING_SIZE - 2) {
+			/* Same setup recently queued, we need not add it. */
+		} else {
+			unsigned long flags;
+			unsigned int entry, dummy = -1;
+
+			save_flags(flags); cli();
+			entry = tp->cur_tx++ % TX_RING_SIZE;
+
+			if (entry != 0) {
+				/* Avoid a chip errata by prefixing a dummy entry. */
+				tp->tx_skbuff[entry] = 0;
+				tp->tx_ring[entry].length =
+					(entry == TX_RING_SIZE-1) ? cpu_to_le32(DESC_RING_WRAP) : 0;
+				tp->tx_ring[entry].buffer1 = 0;
+				/* race with chip, set DescOwned later */
+				dummy = entry;
+				entry = tp->cur_tx++ % TX_RING_SIZE;
+			}
+
+			tp->tx_skbuff[entry] = 0;
+			/* Put the setup frame on the Tx list. */
+			if (entry == TX_RING_SIZE-1)
+				tx_flags |= DESC_RING_WRAP;		/* Wrap ring. */
+			tp->tx_ring[entry].length = cpu_to_le32(tx_flags);
+			if(tp->chip_id == X3201_3)
+				tp->tx_ring[entry].buffer1 = (virt_to_le32desc(tp->setup_frame) + 4);
+			else
+				tp->tx_ring[entry].buffer1 = virt_to_le32desc(tp->setup_frame);
+			tp->tx_ring[entry].status = cpu_to_le32(DescOwned);
+			if (tp->cur_tx - tp->dirty_tx >= TX_RING_SIZE - 2) {
+				netif_stop_queue(dev);
+				tp->tx_full = 1;
+			}
+			if (dummy >= 0)
+				tp->tx_ring[dummy].status = cpu_to_le32(DescOwned);
+			restore_flags(flags);
+			/* Trigger an immediate transmit demand. */
+			outl(0, ioaddr + CSR1);
+		}
+	}
+	outl_CSR6(csr6 | 0x0000, ioaddr, tp->chip_id);
+}
+
+#ifdef CARDBUS
+
+#include <pcmcia/driver_ops.h>
+
+static void tulip_reap(void)
+{
+	struct net_device **devp, **next;
+	for (devp = &root_tulip_dev; *devp; devp = next) {
+		struct tulip_private *tp = (*devp)->priv;
+		next = &tp->next_module;
+		if (tp->open || !tp->reap) continue;
+		unregister_netdev(*devp);
+		kfree(*devp);
+		*devp = *next; next = devp;
+		kfree(tp->priv_addr);
+	}
+}
+
+static dev_node_t *tulip_attach(dev_locator_t *loc)
+{
+	struct net_device *dev;
+	u16 dev_id;
+	u16 vendor_id;
+	u32 io;
+	u8 bus, devfn, irq;
+
+	tulip_reap();
+	if (loc->bus != LOC_PCI) return NULL;
+	bus = loc->b.pci.bus; devfn = loc->b.pci.devfn;
+	printk(KERN_INFO "tulip_attach(device %02x:%02x.%d)\n",
+		   bus, PCI_SLOT(devfn), PCI_FUNC(devfn));
+	pcibios_read_config_dword(bus, devfn, PCI_BASE_ADDRESS_0, &io);
+	pcibios_read_config_word(bus, devfn, PCI_DEVICE_ID, &dev_id);
+	pcibios_read_config_byte(bus, devfn, PCI_INTERRUPT_LINE, &irq);
+	pcibios_read_config_word(bus, devfn, PCI_VENDOR_ID, &vendor_id);
+	if (dev_id == 0x0003 && vendor_id == 0x115d) 
+		dev = tulip_probe1(bus, devfn, NULL, io & ~3, irq, X3201_3, 0);
+	else
+		dev = tulip_probe1(bus, devfn, NULL, io & ~3, irq, DC21142, 0);
+	if (dev) {
+		dev_node_t *node = kmalloc(sizeof(dev_node_t), GFP_KERNEL);
+		strcpy(node->dev_name, dev->name);
+		node->major = node->minor = 0;
+		node->next = NULL;
+		MOD_INC_USE_COUNT;
+		return node;
+	}
+	return NULL;
+}
+
+static void tulip_suspend(dev_node_t *node)
+{
+	struct net_device *dev, *next;
+	printk(KERN_DEBUG "tulip_suspend(%s)\n", node->dev_name);
+	for (dev = root_tulip_dev; dev; dev = next) {
+		next = ((struct tulip_private *)dev->priv)->next_module;
+		if (strcmp(dev->name, node->dev_name) == 0) break;
+	}
+	if (dev) {
+		struct tulip_private *tp = (struct tulip_private *)dev->priv;
+		netif_device_detach(dev);
+		if (tp->open) tulip_down(dev);
+	}
+}
+
+static void tulip_resume(dev_node_t *node)
+{
+	struct net_device *dev, *next;
+	printk(KERN_DEBUG "tulip_resume(%s)\n", node->dev_name);
+	for (dev = root_tulip_dev; dev; dev = next) {
+		next = ((struct tulip_private *)dev->priv)->next_module;
+		if (strcmp(dev->name, node->dev_name) == 0) break;
+	}
+	if (dev) {
+		struct tulip_private *tp = (struct tulip_private *)dev->priv;
+		if (tp->open) tulip_up(dev);
+		netif_device_attach(dev);
+	}
+}
+
+static void tulip_detach(dev_node_t *node)
+{
+	struct net_device *dev, *next;
+	printk(KERN_DEBUG "tulip_detach(%s)\n", node->dev_name);
+	for (dev = root_tulip_dev; dev; dev = next) {
+		next = ((struct tulip_private *)dev->priv)->next_module;
+		if (strcmp(dev->name, node->dev_name) == 0) break;
+	}
+	if (dev && dev->priv) {
+		struct tulip_private *tp = dev->priv;
+		netif_device_detach(dev);
+		if (tp->open) tulip_down(dev);
+		tp->reap = 1;
+		kfree(node);
+		MOD_DEC_USE_COUNT;
+	}
+}
+
+struct driver_operations tulip_ops = {
+	"tulip_cb", tulip_attach, tulip_suspend, tulip_resume, tulip_detach
+};
+
+#endif  /* Cardbus support */
+
+
+#ifdef MODULE
+int init_module(void)
+{
+#ifdef CARDBUS
+	reverse_probe = 0;			/* Not used. */
+	register_driver(&tulip_ops);
+	return 0;
+#else
+	return tulip_probe(NULL);
+#endif
+}
+
+void cleanup_module(void)
+{
+	struct net_device *next_dev;
+
+#ifdef CARDBUS
+	unregister_driver(&tulip_ops);
+	tulip_reap();
+#endif
+
+	/* No need to check MOD_IN_USE, as sys_delete_module() checks. */
+	while (root_tulip_dev) {
+		struct tulip_private *tp = (struct tulip_private *)root_tulip_dev->priv;
+		next_dev = tp->next_module;
+		unregister_netdev(root_tulip_dev);
+		release_region(root_tulip_dev->base_addr,
+					   tulip_tbl[tp->chip_id].io_size);
+		kfree(root_tulip_dev);
+		kfree(tp->priv_addr);
+		root_tulip_dev = next_dev;
+	}
+}
+
+#endif  /* MODULE */
+
+/*
+ * Local variables:
+ *  SMP-compile-command: "gcc -D__SMP__ -DMODULE -D__KERNEL__ -Wall -Wstrict-prototypes -O6 -c tulip.c `[ -f /usr/include/linux/modversions.h ] && echo -DMODVERSIONS`"
+ *  compile-command: "gcc -DMODULE -D__KERNEL__ -Wall -Wstrict-prototypes -O6 -c tulip.c `[ -f /usr/include/linux/modversions.h ] && echo -DMODVERSIONS`"
+ *  cardbus-compile-command: "gcc -DCARDBUS -DMODULE -D__KERNEL__ -Wall -Wstrict-prototypes -O6 -c tulip.c -o tulip_cb.o -I/usr/src/pcmcia-cs-3.0.9/include/"
+ *  c-indent-level: 4
+ *  c-basic-offset: 4
+ *  tab-width: 4
+ * End:
+ */
Index: oldkernel/linux/pcmcia-cs-3.1.15/clients/xirc2ps_cs.c
diff -u /dev/null linux/pcmcia-cs-3.1.15/clients/xirc2ps_cs.c:1.1
--- /dev/null	Mon Jul 31 21:15:10 2000
+++ linux/pcmcia-cs-3.1.15/clients/xirc2ps_cs.c	Fri Jul  7 16:34:58 2000
@@ -0,0 +1,2161 @@
+/* [xirc2ps_cs.c wk 03.11.99] (1.40 1999/11/18 00:06:03)
+ * Xircom CreditCard Ethernet Adapter IIps driver
+ * Xircom Realport 10/100 (RE-100) driver 
+ *
+ * This driver originally was made by Werner Koch. Since the driver was left
+ * unmaintained for some time, there have been some improvements and changes
+ * since. These include supporting some of the "Realport" cards and develop-
+ * ing enhancements to support the new ones.
+ * It is made for CE2, CEM28, CEM33, CE33 and 
+ * CEM56 cards. The CEM56 cards work both with their modem and ethernet
+ * interface. The RealPort 10/100 Modem and similar cards are supported but
+ * with some bugs which are being corrected as they are detected. 
+ * 
+ * Code revised and maintained by Allan Baker Ortegon
+ * al527261@prodigy.net.mx
+ * Written originally by Werner Koch based on David Hinds' skeleton of the
+ * PCMCIA driver. The code has been modified as to make the newer cards
+ * available.
+ *
+ * The latest code for the driver, information on the development project
+ * for the Xircom RealPort and CE cards for the PCMCIA driver, and other
+ * related material, can be found at the following URL, which is underway:
+ * 
+ * "http://xirc2ps.linuxbox.com/index.html"
+ *
+ * Any bugs regarding this driver, please send them to:
+ * alanyuu@linuxbox.com
+ *
+ * The driver is still evolving and there are many cards which will benefit
+ * from having alpha testers. If you have a particular card and would like
+ * to be involved in this ongoing effort, please send mail to the maintainer.
+ * 
+ * Special thanks to David Hinds, to Xircom for the specifications and their
+ * software development kit, and all others who may have colaborated in the
+ * development of the driver: Koen Van Herck (Koen.Van.Herck@xircom.com),
+ * 4PC GmbH Duesseldorf, David Luger, et al.
+ * 
+ *
+ ************************************************************************
+ * Copyright (c) 1997,1998 Werner Koch (dd9jn)
+ * Copyright (c) 1999 Allan Baker Ortegon 
+ *
+ * This driver 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.
+ *
+ * It 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
+ *
+ *
+ * ALTERNATIVELY, this driver may be distributed under the terms of
+ * the following license, in which case the provisions of this license
+ * are required INSTEAD OF the GNU General Public License.  (This clause
+ * is necessary due to a potential bad interaction between the GPL and
+ * the restrictions contained in a BSD-style copyright.)
+ *
+ * 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 the entire permission notice in its entirety,
+ *    including the disclaimer of warranties.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote
+ *    products derived from this software without specific prior
+ *    written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ * OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/* Enable the bug fix for CEM56 to use modem and ethernet simultaneously */
+#define CEM56_FIX
+
+#include <pcmcia/config.h>
+#include <pcmcia/k_compat.h>
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/sched.h>
+#include <linux/ptrace.h>
+#include <linux/malloc.h>
+#include <linux/string.h>
+#include <linux/timer.h>
+#include <linux/interrupt.h>
+#include <linux/in.h>
+#include <linux/delay.h>
+#include <asm/io.h>
+#include <asm/system.h>
+#include <asm/bitops.h>
+
+#include <linux/netdevice.h>
+#include <linux/etherdevice.h>
+#include <linux/skbuff.h>
+#include <linux/if_arp.h>
+#include <linux/ioport.h>
+
+#include <pcmcia/version.h>
+#include <pcmcia/cs_types.h>
+#include <pcmcia/cs.h>
+#include <pcmcia/cistpl.h>
+#include <pcmcia/cisreg.h>
+#include <pcmcia/ciscode.h>
+
+#ifndef MANFID_XIRCOM
+  #define MANFID_XIRCOM 	   0x0105
+#endif
+#ifndef MANFID_COMPAQ
+  #define MANFID_COMPAQ 	   0x0138
+  #define MANFID_COMPAQ2	   0x0183  /* is this correct? */
+#endif
+#ifndef MANFID_INTEL
+  #define MANFID_INTEL		   0x0089
+#endif
+
+#include <pcmcia/ds.h>
+
+/* Time in jiffies before concluding Tx hung */
+#define TX_TIMEOUT	((400*HZ)/1000)
+
+/****************
+ * Some constants used to access the hardware
+ */
+
+/* Register offsets and value constans */
+#define XIRCREG_CR  0	/* Command register (wr) */
+enum xirc_cr {
+    TransmitPacket = 0x01,
+    SoftReset = 0x02,
+    EnableIntr = 0x04,
+    ForceIntr  = 0x08,
+    ClearTxFIFO = 0x10,
+    ClearRxOvrun = 0x20,
+    RestartTx	 = 0x40
+};
+#define XIRCREG_ESR 0	/* Ethernet status register (rd) */
+enum xirc_esr {
+    FullPktRcvd = 0x01, /* full packet in receive buffer */
+    PktRejected = 0x04, /* a packet has been rejected */
+    TxPktPend = 0x08,	/* TX Packet Pending */
+    IncorPolarity = 0x10,
+    MediaSelect = 0x20	/* set if TP, clear if AUI */
+};
+#define XIRCREG_PR  1	/* Page Register select */
+#define XIRCREG_EDP 4	/* Ethernet Data Port Register */
+#define XIRCREG_ISR 6	/* Ethernet Interrupt Status Register */
+enum xirc_isr {
+    TxBufOvr = 0x01,	/* TX Buffer Overflow */
+    PktTxed  = 0x02,	/* Packet Transmitted */
+    MACIntr  = 0x04,	/* MAC Interrupt occured */
+    TxResGrant = 0x08,	/* Tx Reservation Granted */
+    RxFullPkt = 0x20,	/* Rx Full Packet */
+    RxPktRej  = 0x40,	/* Rx Packet Rejected */
+    ForcedIntr= 0x80	/* Forced Interrupt */
+};
+#define XIRCREG1_IMR0 12 /* Ethernet Interrupt Mask Register (on page 1)*/
+#define XIRCREG1_IMR1 13
+#define XIRCREG0_TSO  8  /* Transmit Space Open Register (on page 0)*/
+#define XIRCREG0_TRS  10 /* Transmit reservation Size Register (page 0)*/
+#define XIRCREG0_DO   12 /* Data Offset Register (page 0) (wr) */
+#define XIRCREG0_RSR  12 /* Receive Status Register (page 0) (rd) */
+enum xirc_rsr {
+    PhyPkt = 0x01,	/* set:physical packet, clear: multicast packet */
+    BrdcstPkt = 0x02,	/* set if it is a broadcast packet */
+    PktTooLong = 0x04,	/* set if packet length > 1518 */
+    AlignErr = 0x10,	/* incorrect CRC and last octet not complete */
+    CRCErr = 0x20,	/* incorrect CRC and last octet is complete */
+    PktRxOk = 0x80	/* received ok */
+};
+#define XIRCREG0_PTR 13 /* packets transmitted register (rd) */
+#define XIRCREG0_RBC 14 /* receive byte count regsister (rd) */
+#define XIRCREG1_ECR 14 /* ethernet configurationn register */
+enum xirc_ecr {
+    FullDuplex = 0x04,	/* enable full duplex mode */
+    LongTPMode = 0x08,	/* adjust for longer lengths of TP cable */
+    DisablePolCor = 0x10,/* disable auto polarity correction */
+    DisableLinkPulse = 0x20, /* disable link pulse generation */
+    DisableAutoTx = 0x40, /* disable auto-transmit */
+};
+#define XIRCREG2_RBS 8	/* receive buffer start register */
+#define XIRCREG2_LED 10 /* LED Configuration register */
+/* values for the leds:    Bits 2-0 for led 1
+ *  0 disabled		   Bits 5-3 for led 2
+ *  1 collision
+ *  2 noncollision
+ *  3 link_detected
+ *  4 incor_polarity
+ *  5 jabber
+ *  6 auto_assertion
+ *  7 rx_tx_activity
+ */
+#define XIRCREG2_MSR 12 /* Mohawk specific register */
+
+#define XIRCREG4_GPR0 8 /* General Purpose Register 0 */
+#define XIRCREG4_GPR1 9 /* General Purpose Register 1 */
+#define XIRCREG2_GPR2 13 /* General Purpose Register 2 (page2!)*/
+#define XIRCREG4_BOV 10 /* Bonding Version Register */
+#define XIRCREG4_LMA 12 /* Local Memory Address Register */
+#define XIRCREG4_LMD 14 /* Local Memory Data Port */
+/* MAC register can only by accessed with 8 bit operations */
+#define XIRCREG40_CMD0 8    /* Command Register (wr) */
+enum xirc_cmd { 	    /* Commands */
+    Transmit = 0x01,
+    EnableRecv = 0x04,
+    DisableRecv = 0x08,
+    Abort = 0x10,
+    Online = 0x20,
+    IntrAck = 0x40,
+    Offline = 0x80
+};
+#define XIRCREG5_RHSA0	10  /* Rx Host Start Address */
+#define XIRCREG40_RXST0 9   /* Receive Status Register */
+#define XIRCREG40_TXST0 11  /* Transmit Status Register 0 */
+#define XIRCREG40_TXST1 12  /* Transmit Status Register 10 */
+#define XIRCREG40_RMASK0 13  /* Receive Mask Register */
+#define XIRCREG40_TMASK0 14  /* Transmit Mask Register 0 */
+#define XIRCREG40_TMASK1 15  /* Transmit Mask Register 0 */
+#define XIRCREG42_SWC0	8   /* Software Configuration 0 */
+#define XIRCREG42_SWC1	9   /* Software Configuration 1 */
+#define XIRCREG42_BOC	10  /* Back-Off Configuration */
+#define XIRCREG44_TDR0	8   /* Time Domain Reflectometry 0 */
+#define XIRCREG44_TDR1	9   /* Time Domain Reflectometry 1 */
+#define XIRCREG44_RXBC_LO 10 /* Rx Byte Count 0 (rd) */
+#define XIRCREG44_RXBC_HI 11 /* Rx Byte Count 1 (rd) */
+#define XIRCREG45_REV	 15 /* Revision Register (rd) */
+#define XIRCREG50_IA	8   /* Individual Address (8-13) */
+
+static char *if_names[] = { "Auto", "10BaseT", "10Base2", "AUI", "100BaseT" };
+
+/****************
+ * All the PCMCIA modules use PCMCIA_DEBUG to control debugging.  If
+ * you do not define PCMCIA_DEBUG at all, all the debug code will be
+ * left out.  If you compile with PCMCIA_DEBUG=0, the debug code will
+ * be present but disabled -- but it can then be enabled for specific
+ * modules at load time with a 'pc_debug=#' option to insmod.
+ */
+#ifdef PCMCIA_DEBUG
+static int pc_debug = PCMCIA_DEBUG;
+MODULE_PARM(pc_debug, "i");
+#define DEBUG(n, args...) if (pc_debug>(n)) printk(KDBG_XIRC args)
+#else
+#define DEBUG(n, args...)
+#endif
+static char *version =
+"xirc2ps_cs.c 1.31 1998/12/09 19:32:55 (dd9jn+kvh)";
+	    /* !--- CVS revision */
+#define KDBG_XIRC KERN_DEBUG   "xirc2ps_cs: "
+#define KERR_XIRC KERN_ERR     "xirc2ps_cs: "
+#define KWRN_XIRC KERN_WARNING "xirc2ps_cs: "
+#define KNOT_XIRC KERN_NOTICE  "xirc2ps_cs: "
+#define KINF_XIRC KERN_INFO    "xirc2ps_cs: "
+
+/* card types */
+#define XIR_UNKNOWN  0	/* unknown: not supported */
+#define XIR_CE	     1	/* (prodid 1) different hardware: not supported */
+#define XIR_CE2      2	/* (prodid 2) */
+#define XIR_CE3      3	/* (prodid 3) */
+#define XIR_CEM      4	/* (prodid 1) different hardware: not supported */
+#define XIR_CEM2     5	/* (prodid 2) */
+#define XIR_CEM3     6	/* (prodid 3) */
+#define XIR_CEM33    7	/* (prodid 4) */
+#define XIR_CEM56M   8	/* (prodid 5) */
+#define XIR_CEM56    9	/* (prodid 6) */
+#define XIR_CM28    10	/* (prodid 3) modem only: not supported here */
+#define XIR_CM33    11	/* (prodid 4) modem only: not supported here */
+#define XIR_CM56    12	/* (prodid 5) modem only: not supported here */
+#define XIR_CG	    13	/* (prodid 1) GSM modem only: not supported */
+#define XIR_CBE     14	/* (prodid 1) cardbus ethernet: not supported */
+/*====================================================================*/
+
+/* Parameters that can be set with 'insmod' */
+static int if_port = 0;
+MODULE_PARM(if_port, "i");
+
+/* Bit map of interrupts to choose from */
+/* This means pick from 15, 14, 12, 11, 10, 9, 7, 5, 4, and 3 */
+static u_long irq_mask = 0xdeb8;
+MODULE_PARM(irq_mask, "i");
+
+static int irq_list[4] = { -1 };
+MODULE_PARM(irq_list, "1-4i");
+
+static int do_sound = 1;
+MODULE_PARM(do_sound, "i");
+
+static int card_type = 0;
+MODULE_PARM(card_type, "i");  /* dummy, not used anymore */
+
+static int lockup_hack = 0;
+MODULE_PARM(lockup_hack, "i");  /* anti lockup hack */
+
+/*====================================================================*/
+
+/* We do not process more than these number of bytes during one
+ * interrupt. (Of course we receive complete packets, so this is not
+ * an exact value).
+ * Something between 2000..22000; first value gives best interrupt latency,
+ * the second enables the usage of the complete on-chip buffer. We use the
+ * high value as the initial value.
+ */
+static unsigned maxrx_bytes = 22000;
+
+/* MII management prototypes */
+static void mii_idle(ioaddr_t ioaddr);
+static void mii_putbit(ioaddr_t ioaddr, unsigned data);
+static int  mii_getbit(ioaddr_t ioaddr);
+static void mii_wbits(ioaddr_t ioaddr, unsigned data, int len);
+static unsigned mii_rd(ioaddr_t ioaddr,	u_char phyaddr, u_char phyreg);
+static void mii_wr(ioaddr_t ioaddr, u_char phyaddr, u_char phyreg,
+		   unsigned data, int len);
+
+/*
+ * The event() function is this driver's Card Services event handler.
+ * It will be called by Card Services when an appropriate card status
+ * event is received.  The config() and release() entry points are
+ * used to configure or release a socket, in response to card insertion
+ * and ejection events.  They are invoked from the event handler.
+ */
+
+static int has_ce2_string(dev_link_t * link);
+static void xirc2ps_config(dev_link_t * link);
+static void xirc2ps_release(u_long arg);
+static int xirc2ps_event(event_t event, int priority,
+			 event_callback_args_t * args);
+
+/****************
+ * The attach() and detach() entry points are used to create and destroy
+ * "instances" of the driver, where each instance represents everything
+ * needed to manage one actual PCMCIA card.
+ */
+
+static dev_link_t *xirc2ps_attach(void);
+static void xirc2ps_detach(dev_link_t *);
+
+/****************
+ * You'll also need to prototype all the functions that will actually
+ * be used to talk to your device.  See 'pcmem_cs' for a good example
+ * of a fully self-sufficient driver; the other drivers rely more or
+ * less on other parts of the kernel.
+ */
+
+static void xirc2ps_interrupt(int irq, void *dev_id, struct pt_regs *regs);
+
+/*
+ * The dev_info variable is the "key" that is used to match up this
+ * device driver with appropriate cards, through the card configuration
+ * database.
+ */
+
+static dev_info_t dev_info = "xirc2ps_cs";
+
+/****************
+ * A linked list of "instances" of the device.  Each actual
+ * PCMCIA card corresponds to one device instance, and is described
+ * by one dev_link_t structure (defined in ds.h).
+ *
+ * You may not want to use a linked list for this -- for example, the
+ * memory card driver uses an array of dev_link_t pointers, where minor
+ * device numbers are used to derive the corresponding array index.
+ */
+
+static dev_link_t *dev_list = NULL;
+
+/****************
+ * A dev_link_t structure has fields for most things that are needed
+ * to keep track of a socket, but there will usually be some device
+ * specific information that also needs to be kept track of.  The
+ * 'priv' pointer in a dev_link_t structure can be used to point to
+ * a device-specific private data structure, like this.
+ *
+ * A driver needs to provide a dev_node_t structure for each device
+ * on a card.  In some cases, there is only one device per card (for
+ * example, ethernet cards, modems).  In other cases, there may be
+ * many actual or logical devices (SCSI adapters, memory cards with
+ * multiple partitions).  The dev_node_t structures need to be kept
+ * in a linked list starting at the 'dev' field of a dev_link_t
+ * structure.  We allocate them in the card's private data structure,
+ * because they generally can't be allocated dynamically.
+ */
+
+typedef struct local_info_t {
+    dev_link_t link;
+    struct net_device dev;
+    dev_node_t node;
+    struct enet_statistics stats;
+    int card_type;
+    int probe_port;
+    int silicon; /* silicon revision. 0=old CE2, 1=Scipper, 4=Mohawk */
+    int mohawk;  /* a CE3 type card */
+    int dingo;	 /* a CEM56 type card */
+    int new_mii; /* has full 10baseT/100baseT MII */
+    int modem;	 /* is a multi function card (i.e with a modem) */
+    caddr_t dingo_ccr; /* only used for CEM56 cards */
+    unsigned last_ptr_value; /* last packets transmitted value */
+    const char *manf_str;
+} local_info_t;
+
+/****************
+ * Some more prototypes
+ */
+static int do_start_xmit(struct sk_buff *skb, struct net_device *dev);
+static void do_tx_timeout(struct net_device *dev);
+static struct enet_statistics *do_get_stats(struct net_device *dev);
+static void set_addresses(struct net_device *dev);
+static void set_multicast_list(struct net_device *dev);
+static int set_card_type(dev_link_t *link, const void *s);
+static int do_config(struct net_device *dev, struct ifmap *map);
+static int do_open(struct net_device *dev);
+static int do_ioctl(struct net_device *dev, struct ifreq *rq, int cmd);
+static void hardreset(struct net_device *dev);
+static void do_reset(struct net_device *dev, int full);
+static int init_mii(struct net_device *dev);
+static void do_powerdown(struct net_device *dev);
+static int do_stop(struct net_device *dev);
+
+
+/*=============== Helper functions =========================*/
+static void
+flush_stale_links(void)
+{
+    dev_link_t *link, *next;
+    for (link = dev_list; link; link = next) {
+	next = link->next;
+	if (link->state & DEV_STALE_LINK)
+	    xirc2ps_detach(link);
+    }
+}
+
+static void
+cs_error(client_handle_t handle, int func, int ret)
+{
+    error_info_t err = { func, ret };
+    CardServices(ReportError, handle, &err);
+}
+
+static int
+get_tuple_data(int fn, client_handle_t handle, tuple_t *tuple)
+{
+    int err;
+
+    if ((err=CardServices(fn, handle, tuple)))
+	return err;
+    return CardServices(GetTupleData, handle, tuple);
+}
+
+static int
+get_tuple(int fn, client_handle_t handle, tuple_t *tuple, cisparse_t *parse)
+{
+    int err;
+
+    if ((err=get_tuple_data(fn, handle, tuple)))
+	return err;
+    return CardServices(ParseTuple, handle, tuple, parse);
+}
+
+#define first_tuple(a, b, c) get_tuple(GetFirstTuple, a, b, c)
+#define next_tuple(a, b, c)  get_tuple(GetNextTuple, a, b, c)
+
+#define SelectPage(pgnr)   outb((pgnr), ioaddr + XIRCREG_PR)
+#define GetByte(reg)	   ((unsigned)inb(ioaddr + (reg)))
+#define GetWord(reg)	   ((unsigned)inw(ioaddr + (reg)))
+#define PutByte(reg,value) outb((value), ioaddr+(reg))
+#define PutWord(reg,value) outw((value), ioaddr+(reg))
+
+static void
+busy_loop(u_long len)
+{
+    if (in_interrupt()) {
+	u_long timeout = jiffies + len;
+	u_long flags;
+	save_flags(flags);
+	sti();
+	while (timeout >= jiffies)
+	    ;
+	restore_flags(flags);
+    } else {
+	__set_current_state(TASK_UNINTERRUPTIBLE);
+	schedule_timeout(len);
+    }
+}
+
+
+/*====== Functions used for debugging =================================*/
+#if defined(PCMCIA_DEBUG) && 0 /* reading regs may change system status */
+static void
+PrintRegisters(struct net_device *dev)
+{
+    ioaddr_t ioaddr = dev->base_addr;
+
+    if (pc_debug > 1) {
+	int i, page;
+
+	printk(KDBG_XIRC "Register  common: ");
+	for (i = 0; i < 8; i++)
+	    printk(" %2.2x", GetByte(i));
+	printk("\n");
+	for (page = 0; page <= 8; page++) {
+	    printk(KDBG_XIRC "Register page %2x: ", page);
+	    SelectPage(page);
+	    for (i = 8; i < 16; i++)
+		printk(" %2.2x", GetByte(i));
+	    printk("\n");
+	}
+	for (page=0x40 ; page <= 0x5f; page++) {
+	    if (page == 0x43 || (page >= 0x46 && page <= 0x4f)
+		|| (page >= 0x51 && page <=0x5e))
+		continue;
+	    printk(KDBG_XIRC "Register page %2x: ", page);
+	    SelectPage(page);
+	    for (i = 8; i < 16; i++)
+		printk(" %2.2x", GetByte(i));
+	    printk("\n");
+	}
+    }
+}
+#endif /* PCMCIA_DEBUG */
+
+/*============== MII Management functions ===============*/
+
+/****************
+ * Turn around for read
+ */
+static void
+mii_idle(ioaddr_t ioaddr)
+{
+    PutByte(XIRCREG2_GPR2, 0x04|0); /* drive MDCK low */
+    udelay(1);
+    PutByte(XIRCREG2_GPR2, 0x04|1); /* and drive MDCK high */
+    udelay(1);
+}
+
+/****************
+ * Write a bit to MDI/O
+ */
+static void
+mii_putbit(ioaddr_t ioaddr, unsigned data)
+{
+  #if 1
+    if (data) {
+	PutByte(XIRCREG2_GPR2, 0x0c|2|0); /* set MDIO */
+	udelay(1);
+	PutByte(XIRCREG2_GPR2, 0x0c|2|1); /* and drive MDCK high */
+	udelay(1);
+    } else {
+	PutByte(XIRCREG2_GPR2, 0x0c|0|0); /* clear MDIO */
+	udelay(1);
+	PutByte(XIRCREG2_GPR2, 0x0c|0|1); /* and drive MDCK high */
+	udelay(1);
+    }
+  #else
+    if (data) {
+	PutWord(XIRCREG2_GPR2-1, 0x0e0e);
+	udelay(1);
+	PutWord(XIRCREG2_GPR2-1, 0x0f0f);
+	udelay(1);
+    } else {
+	PutWord(XIRCREG2_GPR2-1, 0x0c0c);
+	udelay(1);
+	PutWord(XIRCREG2_GPR2-1, 0x0d0d);
+	udelay(1);
+    }
+  #endif
+}
+
+/****************
+ * Get a bit from MDI/O
+ */
+static int
+mii_getbit(ioaddr_t ioaddr)
+{
+    unsigned d;
+
+    PutByte(XIRCREG2_GPR2, 4|0); /* drive MDCK low */
+    udelay(1);
+    d = GetByte(XIRCREG2_GPR2); /* read MDIO */
+    PutByte(XIRCREG2_GPR2, 4|1); /* drive MDCK high again */
+    udelay(1);
+    return d & 0x20; /* read MDIO */
+}
+
+static void
+mii_wbits(ioaddr_t ioaddr, unsigned data, int len)
+{
+    unsigned m = 1 << (len-1);
+    for (; m; m >>= 1)
+	mii_putbit(ioaddr, data & m);
+}
+
+static unsigned
+mii_rd(ioaddr_t ioaddr,	u_char phyaddr, u_char phyreg)
+{
+    int i;
+    unsigned data=0, m;
+
+    SelectPage(2);
+    for (i=0; i < 32; i++)		/* 32 bit preamble */
+	mii_putbit(ioaddr, 1);
+    mii_wbits(ioaddr, 0x06, 4); 	/* Start and opcode for read */
+    mii_wbits(ioaddr, phyaddr, 5);	/* PHY address to be accessed */
+    mii_wbits(ioaddr, phyreg, 5);	/* PHY register to read */
+    mii_idle(ioaddr);			/* turn around */
+    mii_getbit(ioaddr);
+
+    for (m = 1<<15; m; m >>= 1)
+	if (mii_getbit(ioaddr))
+	    data |= m;
+    mii_idle(ioaddr);
+    return data;
+}
+
+static void
+mii_wr(ioaddr_t ioaddr, u_char phyaddr, u_char phyreg, unsigned data, int len)
+{
+    int i;
+
+    SelectPage(2);
+    for (i=0; i < 32; i++)		/* 32 bit preamble */
+	mii_putbit(ioaddr, 1);
+    mii_wbits(ioaddr, 0x05, 4); 	/* Start and opcode for write */
+    mii_wbits(ioaddr, phyaddr, 5);	/* PHY address to be accessed */
+    mii_wbits(ioaddr, phyreg, 5);	/* PHY Register to write */
+    mii_putbit(ioaddr, 1);		/* turn around */
+    mii_putbit(ioaddr, 0);
+    mii_wbits(ioaddr, data, len);	/* And write the data */
+    mii_idle(ioaddr);
+}
+
+#ifdef PCMCIA_DEBUG
+static void
+mii_dump(struct net_device *dev)
+{
+    ioaddr_t ioaddr = dev->base_addr;
+    int i;
+
+    /* Note that registers 14, 1d,1e and 1f are reserved and should
+     * not be read according to the DP83840A specs.
+     */
+    printk(KERN_DEBUG "%s: MII register dump:\n", dev->name);
+    for (i=0; i < 32; i++) {
+	if (!(i % 8)) {
+	    if (i)
+		printk("\n");
+	    printk(KERN_DEBUG "%s:", dev->name);
+	}
+	printk(" %04x", mii_rd(ioaddr, 0, i));
+    }
+    printk("\n");
+}
+#endif
+
+/*============= Main bulk of functions	=========================*/
+
+/****************
+ * xirc2ps_attach() creates an "instance" of the driver, allocating
+ * local data structures for one device.  The device is registered
+ * with Card Services.
+ *
+ * The dev_link structure is initialized, but we don't actually
+ * configure the card at this point -- we wait until we receive a
+ * card insertion event.
+ */
+
+static dev_link_t *
+xirc2ps_attach(void)
+{
+    client_reg_t client_reg;
+    dev_link_t *link;
+    struct net_device *dev;
+    local_info_t *local;
+    int err;
+
+    DEBUG(0, "attach()\n");
+    flush_stale_links();
+
+    /* Allocate the device structure */
+    local = kmalloc(sizeof(*local), GFP_KERNEL);
+    if (!local) return NULL;
+    memset(local, 0, sizeof(*local));
+    link = &local->link; dev = &local->dev;
+    link->priv = dev->priv = local;
+
+    link->release.function = &xirc2ps_release;
+    link->release.data = (u_long) link;
+
+    /* General socket configuration */
+    link->conf.Attributes = CONF_ENABLE_IRQ;
+    link->conf.Vcc = 50;
+    link->conf.IntType = INT_MEMORY_AND_IO;
+    link->conf.ConfigIndex = 1;
+    link->conf.Present = PRESENT_OPTION;
+    link->irq.Handler = xirc2ps_interrupt;
+    link->irq.Instance = dev;
+
+    /* Fill in card specific entries */
+    dev->hard_start_xmit = &do_start_xmit;
+    dev->set_config = &do_config;
+    dev->get_stats = &do_get_stats;
+    dev->do_ioctl = &do_ioctl;
+    dev->set_multicast_list = &set_multicast_list;
+    ether_setup(dev);
+    dev->name = local->node.dev_name;
+    dev->open = &do_open;
+    dev->stop = &do_stop;
+#ifdef HAVE_NETIF_QUEUE
+    dev->tx_timeout = do_tx_timeout;
+    dev->watchdog_timeo = TX_TIMEOUT;
+#endif
+
+    /* Register with Card Services */
+    link->next = dev_list;
+    dev_list = link;
+    client_reg.dev_info = &dev_info;
+    client_reg.Attributes = INFO_IO_CLIENT | INFO_CARD_SHARE;
+    client_reg.EventMask =
+	CS_EVENT_CARD_INSERTION | CS_EVENT_CARD_REMOVAL |
+	CS_EVENT_RESET_PHYSICAL | CS_EVENT_CARD_RESET |
+	CS_EVENT_PM_SUSPEND | CS_EVENT_PM_RESUME;
+    client_reg.event_handler = &xirc2ps_event;
+    client_reg.Version = 0x0210;
+    client_reg.event_callback_args.client_data = link;
+    if ((err = CardServices(RegisterClient, &link->handle, &client_reg))) {
+	cs_error(link->handle, RegisterClient, err);
+	xirc2ps_detach(link);
+	return NULL;
+    }
+
+    return link;
+} /* xirc2ps_attach */
+
+/****************
+ *  This deletes a driver "instance".  The device is de-registered
+ *  with Card Services.  If it has been released, all local data
+ *  structures are freed.  Otherwise, the structures will be freed
+ *  when the device is released.
+ */
+
+static void
+xirc2ps_detach(dev_link_t * link)
+{
+    local_info_t *local = link->priv;
+    dev_link_t **linkp;
+
+    DEBUG(0, "detach(0x%p)\n", link);
+
+    /* Locate device structure */
+    for (linkp = &dev_list; *linkp; linkp = &(*linkp)->next)
+	if (*linkp == link)
+	    break;
+    if (!*linkp) {
+	DEBUG(0, "detach(0x%p): dev_link lost\n", link);
+	return;
+    }
+
+    /*
+     * If the device is currently configured and active, we won't
+     * actually delete it yet.	Instead, it is marked so that when
+     * the release() function is called, that will trigger a proper
+     * detach().
+     */
+    del_timer(&link->release);
+    if (link->state & DEV_CONFIG) {
+	DEBUG(0, "detach postponed, '%s' still locked\n",
+	      link->dev->dev_name);
+	link->state |= DEV_STALE_LINK;
+	return;
+    }
+
+    /* Break the link with Card Services */
+    if (link->handle)
+	CardServices(DeregisterClient, link->handle);
+
+    /* Unlink device structure, free it */
+    *linkp = link->next;
+    if (link->dev)
+	unregister_netdev(&local->dev);
+    kfree(local);
+
+} /* xirc2ps_detach */
+
+/****************
+ * Detect the type of the card. s is the buffer with the data of tuple 0x20
+ * Returns: 0 := not supported
+ *		       mediaid=11 and prodid=47
+ * Media-Id bits:
+ *  Ethernet	    0x01
+ *  Tokenring	    0x02
+ *  Arcnet	    0x04
+ *  Wireless	    0x08
+ *  Modem	    0x10
+ *  GSM only	    0x20
+ * Prod-Id bits:
+ *  Pocket	    0x10
+ *  External	    0x20
+ *  Creditcard	    0x40
+ *  Cardbus	    0x80
+ *
+ */
+static int
+set_card_type(dev_link_t *link, const void *s)
+{
+    local_info_t *local = link->priv;
+  #ifdef PCMCIA_DEBUG
+    unsigned cisrev = ((const unsigned char *)s)[2];
+  #endif
+    unsigned mediaid= ((const unsigned char *)s)[3];
+    unsigned prodid = ((const unsigned char *)s)[4];
+
+    DEBUG(0, "cisrev=%02x mediaid=%02x prodid=%02x\n",
+	  cisrev, mediaid, prodid);
+
+    local->mohawk = 0;
+    local->dingo = 0;
+    local->modem = 0;
+    local->card_type = XIR_UNKNOWN;
+    if (!(prodid & 0x40)) {
+	printk(KNOT_XIRC "Ooops: Not a creditcard\n");
+	return 0;
+    }
+    if (!(mediaid & 0x01)) {
+	printk(KNOT_XIRC "Not an Ethernet card\n");
+	return 0;
+    }
+    if (mediaid & 0x10) {
+	local->modem = 1;
+	switch(prodid & 15) {
+	  case 1: local->card_type = XIR_CEM   ; break;
+	  case 2: local->card_type = XIR_CEM2  ; break;
+	  case 3: local->card_type = XIR_CEM3  ; break;
+	  case 4: local->card_type = XIR_CEM33 ; break;
+	  case 5: local->card_type = XIR_CEM56M;
+		  local->mohawk = 1;
+		  break;
+	  case 6:
+	  case 7: /* 7 is the RealPort 10/56 */
+		  local->card_type = XIR_CEM56 ;
+		  local->mohawk = 1;
+		  local->dingo = 1;
+		  break;
+	}
+    } else {
+	switch(prodid & 15) {
+	  case 1: local->card_type = has_ce2_string(link)? XIR_CE2 : XIR_CE ;
+		  break;
+	  case 2: local->card_type = XIR_CE2; break;
+	  case 3: local->card_type = XIR_CE3;
+		  local->mohawk = 1;
+		  break;
+	}
+    }
+    if (local->card_type == XIR_CE || local->card_type == XIR_CEM) {
+	printk(KNOT_XIRC "Sorry, this is an old CE card\n");
+	return 0;
+    }
+    if (local->card_type == XIR_UNKNOWN)
+	printk(KNOT_XIRC "unknown card (mediaid=%02x prodid=%02x)\n",
+	       mediaid, prodid);
+
+    return 1;
+}
+
+/****************
+ * There are some CE2 cards out which claim to be a CE card.
+ * This function looks for a "CE2" in the 3rd version field.
+ * Returns: true if this is a CE2
+ */
+static int
+has_ce2_string(dev_link_t * link)
+{
+    client_handle_t handle = link->handle;
+    tuple_t tuple;
+    cisparse_t parse;
+    u_char buf[256];
+
+    tuple.Attributes = 0;
+    tuple.TupleData = buf;
+    tuple.TupleDataMax = 254;
+    tuple.TupleOffset = 0;
+    tuple.DesiredTuple = CISTPL_VERS_1;
+    if (!first_tuple(handle, &tuple, &parse) && parse.version_1.ns > 2) {
+	if (strstr(parse.version_1.str + parse.version_1.ofs[2], "CE2"))
+	    return 1;
+    }
+    return 0;
+}
+
+/****************
+ * xirc2ps_config() is scheduled to run after a CARD_INSERTION event
+ * is received, to configure the PCMCIA socket, and to make the
+ * ethernet device available to the system.
+ */
+static void
+xirc2ps_config(dev_link_t * link)
+{
+    client_handle_t handle = link->handle;
+    local_info_t *local = link->priv;
+    struct net_device *dev = &local->dev;
+    tuple_t tuple;
+    cisparse_t parse;
+    ioaddr_t ioaddr;
+    int err, i;
+    u_char buf[64];
+    cistpl_lan_node_id_t *node_id = (cistpl_lan_node_id_t*)parse.funce.data;
+    cistpl_cftable_entry_t *cf = &parse.cftable_entry;
+
+    local->dingo_ccr = 0;
+
+    DEBUG(0, "config(0x%p)\n", link);
+
+    /*
+     * This reads the card's CONFIG tuple to find its configuration
+     * registers.
+     */
+    tuple.Attributes = 0;
+    tuple.TupleData = buf;
+    tuple.TupleDataMax = 64;
+    tuple.TupleOffset = 0;
+
+    /* Is this a valid	card */
+    tuple.DesiredTuple = CISTPL_MANFID;
+    if ((err=first_tuple(handle, &tuple, &parse))) {
+	printk(KNOT_XIRC "manfid not found in CIS\n");
+	goto failure;
+    }
+
+    switch(parse.manfid.manf) {
+      case MANFID_XIRCOM:
+	local->manf_str = "Xircom";
+	DEBUG(0, "found xircom card\n");
+	break;
+      case MANFID_ACCTON:
+	local->manf_str = "Accton";
+	DEBUG(0, "found Accton card\n");
+	break;
+      case MANFID_COMPAQ:
+      case MANFID_COMPAQ2:
+	local->manf_str = "Compaq";
+	DEBUG(0, "found Compaq card\n");
+	break;
+      case MANFID_INTEL:
+	local->manf_str = "Intel";
+	DEBUG(0, "found Intel card\n");
+	break;
+      default:
+	printk(KNOT_XIRC "Unknown Card Manufacturer ID: 0x%04x\n",
+	       (unsigned)parse.manfid.manf);
+	goto failure;
+    }
+
+    if (!set_card_type(link, buf)) {
+	printk(KNOT_XIRC "this card is not supported\n");
+	goto failure;
+    }
+
+    /* get configuration stuff */
+    tuple.DesiredTuple = CISTPL_CONFIG;
+    if ((err=first_tuple(handle, &tuple, &parse)))
+	goto cis_error;
+    link->conf.ConfigBase = parse.config.base;
+    link->conf.Present =    parse.config.rmask[0];
+
+    /* get the ethernet address from the CIS */
+    tuple.DesiredTuple = CISTPL_FUNCE;
+    for (err = first_tuple(handle, &tuple, &parse); !err;
+			     err = next_tuple(handle, &tuple, &parse)) {
+	/* Once I saw two CISTPL_FUNCE_LAN_NODE_ID entries:
+	 * the first one with a length of zero the second correct -
+	 * so I skip all entries with length 0 */
+	if (parse.funce.type == CISTPL_FUNCE_LAN_NODE_ID
+	    && ((cistpl_lan_node_id_t *)parse.funce.data)->nb)
+	    break;
+    }
+    if (err) { /* not found: try to get the node-id from tuple 0x89 */
+	tuple.DesiredTuple = 0x89;  /* data layout looks like tuple 0x22 */
+	if (!(err = get_tuple_data(GetFirstTuple, handle, &tuple))) {
+	    if (tuple.TupleDataLen == 8 && *buf == CISTPL_FUNCE_LAN_NODE_ID)
+		memcpy(&parse, buf, 8);
+	    else
+		err = -1;
+	}
+    }
+    if (err) { /* another try	(James Lehmer's CE2 version 4.1)*/
+	tuple.DesiredTuple = CISTPL_FUNCE;
+	for (err = first_tuple(handle, &tuple, &parse); !err;
+				 err = next_tuple(handle, &tuple, &parse)) {
+	    if (parse.funce.type == 0x02 && parse.funce.data[0] == 1
+		&& parse.funce.data[1] == 6 && tuple.TupleDataLen == 13) {
+		buf[1] = 4;
+		memcpy(&parse, buf+1, 8);
+		break;
+	    }
+	}
+    }
+    if (err) {
+	printk(KNOT_XIRC "node-id not found in CIS\n");
+	goto failure;
+    }
+    node_id = (cistpl_lan_node_id_t *)parse.funce.data;
+    if (node_id->nb != 6) {
+	printk(KNOT_XIRC "malformed node-id in CIS\n");
+	goto failure;
+    }
+    for (i=0; i < 6; i++)
+	dev->dev_addr[i] = node_id->id[i];
+
+    /* Configure card */
+    link->state |= DEV_CONFIG;
+
+    link->io.IOAddrLines =10;
+    link->io.Attributes1 = IO_DATA_PATH_WIDTH_16;
+    link->irq.Attributes = IRQ_HANDLE_PRESENT;
+    link->irq.IRQInfo1 = IRQ_INFO2_VALID | IRQ_LEVEL_ID;
+    if (irq_list[0] == -1)
+	link->irq.IRQInfo2 = irq_mask;
+    else {
+	for (i = 0; i < 4; i++)
+	    link->irq.IRQInfo2 |= 1 << irq_list[i];
+    }
+    if (local->modem) {
+	int pass;
+
+	if (do_sound) {
+	    link->conf.Attributes |= CONF_ENABLE_SPKR;
+	    link->conf.Status |= CCSR_AUDIO_ENA;
+	}
+	link->irq.Attributes |= IRQ_TYPE_DYNAMIC_SHARING|IRQ_FIRST_SHARED ;
+	link->io.NumPorts2 = 8;
+	link->io.Attributes2 = IO_DATA_PATH_WIDTH_8;
+	if (local->dingo) {
+	    /* Take the Modem IO port from the CIS and scan for a free
+	     * Ethernet port */
+	    link->io.NumPorts1 = 16; /* no Mako stuff anymore */
+	    tuple.DesiredTuple = CISTPL_CFTABLE_ENTRY;
+	    for (err = first_tuple(handle, &tuple, &parse); !err;
+				 err = next_tuple(handle, &tuple, &parse)) {
+		if (cf->io.nwin > 0  &&  (cf->io.win[0].base & 0xf) == 8) {
+		    for (ioaddr = 0x300; ioaddr < 0x400; ioaddr += 0x10) {
+			link->conf.ConfigIndex = cf->index ;
+			link->io.BasePort2 = cf->io.win[0].base;
+			link->io.BasePort1 = ioaddr;
+			if (!(err=CardServices(RequestIO, link->handle,
+								&link->io)))
+			    goto port_found;
+		    }
+		}
+	    }
+	} else {
+	    link->io.NumPorts1 = 18;
+	    /* We do 2 passes here: The first one uses the regular mapping and
+	     * the second tries again, thereby considering that the 32 ports are
+	     * mirrored every 32 bytes. Actually we use a mirrored port for
+	     * the Mako if (on the first pass) the COR bit 5 is set.
+	     */
+	    for (pass=0; pass < 2; pass++) {
+		tuple.DesiredTuple = CISTPL_CFTABLE_ENTRY;
+		for (err = first_tuple(handle, &tuple, &parse); !err;
+				     err = next_tuple(handle, &tuple, &parse)){
+		    if (cf->io.nwin > 0  &&  (cf->io.win[0].base & 0xf) == 8){
+			link->conf.ConfigIndex = cf->index ;
+			link->io.BasePort2 = cf->io.win[0].base;
+			link->io.BasePort1 = link->io.BasePort2
+				    + (pass ? (cf->index & 0x20 ? -24:8)
+					    : (cf->index & 0x20 ?   8:-24));
+			if (!(err=CardServices(RequestIO, link->handle,
+								&link->io)))
+			    goto port_found;
+		    }
+		}
+	    }
+	    /* if special option:
+	     * try to configure as Ethernet only.
+	     * .... */
+	}
+	printk(KNOT_XIRC "no ports available\n");
+    } else {
+	link->irq.Attributes |= IRQ_TYPE_EXCLUSIVE;
+	link->io.NumPorts1 = 16;
+	for (ioaddr = 0x300; ioaddr < 0x400; ioaddr += 0x10) {
+	    link->io.BasePort1 = ioaddr;
+	    if (!(err=CardServices(RequestIO, link->handle, &link->io)))
+		goto port_found;
+	}
+	link->io.BasePort1 = 0; /* let CS decide */
+	if ((err=CardServices(RequestIO, link->handle, &link->io))) {
+	    cs_error(link->handle, RequestIO, err);
+	    goto config_error;
+	}
+    }
+  port_found:
+    if (err)
+	 goto config_error;
+
+    /****************
+     * Now allocate an interrupt line.	Note that this does not
+     * actually assign a handler to the interrupt.
+     */
+    if ((err=CardServices(RequestIRQ, link->handle, &link->irq))) {
+	cs_error(link->handle, RequestIRQ, err);
+	goto config_error;
+    }
+
+    /****************
+     * This actually configures the PCMCIA socket -- setting up
+     * the I/O windows and the interrupt mapping.
+     */
+    if ((err=CardServices(RequestConfiguration,
+			  link->handle, &link->conf))) {
+	cs_error(link->handle, RequestConfiguration, err);
+	goto config_error;
+    }
+
+    if (local->dingo) {
+      #ifdef CEM56_FIX
+	conf_reg_t reg;
+      #endif
+	win_req_t req;
+	memreq_t mem;
+
+      #ifdef CEM56_FIX
+	/* Reset the modem's BAR to the correct value
+	 * This is necessary because in the RequestConfiguration call,
+	 * the base address of the ethernet port (BasePort1) is written
+	 * to the BAR registers of the modem.
+	 */
+	reg.Action = CS_WRITE;
+	reg.Offset = CISREG_IOBASE_0;
+	reg.Value = link->io.BasePort2 & 0xff;
+	if ((err = CardServices(AccessConfigurationRegister, link->handle,
+				&reg))) {
+	    cs_error(link->handle, AccessConfigurationRegister, err);
+	    goto config_error;
+	}
+	reg.Action = CS_WRITE;
+	reg.Offset = CISREG_IOBASE_1;
+	reg.Value = (link->io.BasePort2 >> 8) & 0xff;
+	if ((err = CardServices(AccessConfigurationRegister, link->handle,
+				&reg))) {
+	    cs_error(link->handle, AccessConfigurationRegister, err);
+	    goto config_error;
+	}
+     #endif
+
+	/* There is no config entry for the Ethernet part which
+	 * is at 0x0800. So we allocate a window into the attribute
+	 * memory and write direct to the CIS registers
+	 */
+	req.Attributes = WIN_DATA_WIDTH_8|WIN_MEMORY_TYPE_AM|WIN_ENABLE;
+	req.Base = req.Size = 0;
+	req.AccessSpeed = 0;
+	link->win = (window_handle_t)link->handle;
+	if ((err = CardServices(RequestWindow, &link->win, &req))) {
+	    cs_error(link->handle, RequestWindow, err);
+	    goto config_error;
+	}
+	local->dingo_ccr = ioremap(req.Base,0x1000) + 0x0800;
+	mem.CardOffset = 0x0;
+	mem.Page = 0;
+	if ((err = CardServices(MapMemPage, link->win, &mem))) {
+	    cs_error(link->handle, MapMemPage, err);
+	    goto config_error;
+	}
+
+	/* Setup the CCRs; there are no infos in the CIS about the Ethernet
+	 * part.
+	 */
+	writeb(0x47, local->dingo_ccr + CISREG_COR);
+	ioaddr = link->io.BasePort1;
+	writeb(ioaddr & 0xff	  , local->dingo_ccr + CISREG_IOBASE_0);
+	writeb((ioaddr >> 8)&0xff , local->dingo_ccr + CISREG_IOBASE_1);
+
+      #if 0
+	{
+	    u_char tmp;
+	    printk(KERN_INFO "ECOR:");
+	    for (i=0; i < 7; i++) {
+		tmp = readb(local->dingo_ccr + i*2);
+		printk(" %02x", tmp);
+	    }
+	    printk("\n");
+	    printk(KERN_INFO "DCOR:");
+	    for (i=0; i < 4; i++) {
+		tmp = readb(local->dingo_ccr + 0x20 + i*2);
+		printk(" %02x", tmp);
+	    }
+	    printk("\n");
+	    printk(KERN_INFO "SCOR:");
+	    for (i=0; i < 10; i++) {
+		tmp = readb(local->dingo_ccr + 0x40 + i*2);
+		printk(" %02x", tmp);
+	    }
+	    printk("\n");
+	}
+      #endif
+
+	writeb(0x01, local->dingo_ccr + 0x20);
+	writeb(0x0c, local->dingo_ccr + 0x22);
+	writeb(0x00, local->dingo_ccr + 0x24);
+	writeb(0x00, local->dingo_ccr + 0x26);
+	writeb(0x00, local->dingo_ccr + 0x28);
+    }
+
+    /* The if_port symbol can be set when the module is loaded */
+    local->probe_port=0;
+    if (!if_port) {
+	local->probe_port = dev->if_port = 1;
+    } else if ((if_port >= 1 && if_port <= 2) ||
+	       (local->mohawk && if_port==4))
+	dev->if_port = if_port;
+    else
+	printk(KNOT_XIRC "invalid if_port requested\n");
+
+    /* we can now register the device with the net subsystem */
+    dev->irq = link->irq.AssignedIRQ;
+    dev->base_addr = link->io.BasePort1;
+    if ((err=register_netdev(dev))) {
+	printk(KNOT_XIRC "register_netdev() failed\n");
+	goto config_error;
+    }
+
+    link->state &= ~DEV_CONFIG_PENDING;
+    link->dev = &local->node;
+
+    if (local->dingo)
+	do_reset(dev, 1); /* a kludge to make the cem56 work */
+
+    /* give some infos about the hardware */
+    printk(KERN_INFO "%s: %s: port %#3lx, irq %d, hwaddr",
+	 dev->name, local->manf_str,(u_long)dev->base_addr, (int)dev->irq);
+    for (i = 0; i < 6; i++)
+	printk("%c%02X", i?':':' ', dev->dev_addr[i]);
+    printk("\n");
+
+    return;
+
+  config_error:
+    link->state &= ~DEV_CONFIG_PENDING;
+    xirc2ps_release((u_long)link);
+    return;
+
+  cis_error:
+    printk(KNOT_XIRC "unable to parse CIS\n");
+  failure:
+    link->state &= ~DEV_CONFIG_PENDING;
+} /* xirc2ps_config */
+
+/****************
+ * After a card is removed, xirc2ps_release() will unregister the net
+ * device, and release the PCMCIA configuration.  If the device is
+ * still open, this will be postponed until it is closed.
+ */
+static void
+xirc2ps_release(u_long arg)
+{
+    dev_link_t *link = (dev_link_t *) arg;
+    local_info_t *local = link->priv;
+    struct net_device *dev = &local->dev;
+
+    DEBUG(0, "release(0x%p)\n", link);
+
+    /*
+     * If the device is currently in use, we won't release until it
+     * is actually closed.
+     */
+    if (link->open) {
+	DEBUG(0, "release postponed, '%s' "
+	      "still open\n", link->dev->dev_name);
+	link->state |= DEV_STALE_CONFIG;
+	return;
+    }
+
+    if (link->win) {
+	local_info_t *local = dev->priv;
+	if (local->dingo)
+	    iounmap(local->dingo_ccr - 0x0800);
+	CardServices(ReleaseWindow, link->win);
+    }
+    CardServices(ReleaseConfiguration, link->handle);
+    CardServices(ReleaseIO, link->handle, &link->io);
+    CardServices(ReleaseIRQ, link->handle, &link->irq);
+    link->state &= ~DEV_CONFIG;
+
+} /* xirc2ps_release */
+
+/*====================================================================*/
+
+/****************
+ * The card status event handler.  Mostly, this schedules other
+ * stuff to run after an event is received.  A CARD_REMOVAL event
+ * also sets some flags to discourage the net drivers from trying
+ * to talk to the card any more.
+ *
+ * When a CARD_REMOVAL event is received, we immediately set a flag
+ * to block future accesses to this device.  All the functions that
+ * actually access the device should check this flag to make sure
+ * the card is still present.
+ */
+
+static int
+xirc2ps_event(event_t event, int priority,
+	      event_callback_args_t * args)
+{
+    dev_link_t *link = args->client_data;
+    local_info_t *lp = link->priv;
+    struct net_device *dev = &lp->dev;
+
+    DEBUG(0, "event(%d)\n", (int)event);
+
+    switch (event) {
+    case CS_EVENT_REGISTRATION_COMPLETE:
+	DEBUG(0, "registration complete\n");
+	break;
+    case CS_EVENT_CARD_REMOVAL:
+	link->state &= ~DEV_PRESENT;
+	if (link->state & DEV_CONFIG) {
+	    netif_device_detach(dev);
+	    mod_timer(&link->release, jiffies + HZ/20);
+	}
+	break;
+    case CS_EVENT_CARD_INSERTION:
+	link->state |= DEV_PRESENT | DEV_CONFIG_PENDING;
+	xirc2ps_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 (link->open) {
+		netif_device_detach(dev);
+		do_powerdown(dev);
+	    }
+	    CardServices(ReleaseConfiguration, link->handle);
+	}
+	break;
+    case CS_EVENT_PM_RESUME:
+	link->state &= ~DEV_SUSPEND;
+	/* Fall through... */
+    case CS_EVENT_CARD_RESET:
+	if (link->state & DEV_CONFIG) {
+	    CardServices(RequestConfiguration, link->handle, &link->conf);
+	    if (link->open) {
+		do_reset(dev,1);
+		netif_device_attach(dev);
+	    }
+	}
+	break;
+    }
+    return 0;
+} /* xirc2ps_event */
+
+/*====================================================================*/
+
+/****************
+ * This is the Interrupt service route.
+ */
+static void
+xirc2ps_interrupt(int irq, void *dev_id, struct pt_regs *regs)
+{
+    struct net_device *dev = (struct net_device *)dev_id;
+    local_info_t *lp = dev->priv;
+    ioaddr_t ioaddr;
+    u_char saved_page;
+    unsigned bytes_rcvd;
+    unsigned int_status, eth_status, rx_status, tx_status;
+    unsigned rsr, pktlen;
+    ulong start_ticks = jiffies; /* fixme: jiffies rollover every 497 days
+				  * is this something to worry about?
+				  * -- on a laptop?
+				  */
+
+    if (!netif_device_present(dev))
+	return;
+
+    ioaddr = dev->base_addr;
+    if (lp->mohawk) { /* must disable the interrupt */
+	PutByte(XIRCREG_CR, 0);
+    }
+
+    DEBUG(6, "%s: interrupt %d at %#x.\n", dev->name, irq, ioaddr);
+
+    saved_page = GetByte(XIRCREG_PR);
+    /* Read the ISR to see whats the cause for the interrupt.
+     * This also clears the interrupt flags on CE2 cards
+     */
+    int_status = GetByte(XIRCREG_ISR);
+    bytes_rcvd = 0;
+  loop_entry:
+    if (int_status == 0xff) { /* card may be ejected */
+	DEBUG(3, "%s: interrupt %d for dead card\n", dev->name, irq);
+	goto leave;
+    }
+    eth_status = GetByte(XIRCREG_ESR);
+
+    SelectPage(0x40);
+    rx_status  = GetByte(XIRCREG40_RXST0);
+    PutByte(XIRCREG40_RXST0, (~rx_status & 0xff));
+    tx_status = GetByte(XIRCREG40_TXST0);
+    tx_status |= GetByte(XIRCREG40_TXST1) << 8;
+    PutByte(XIRCREG40_TXST0, 0);
+    PutByte(XIRCREG40_TXST1, 0);
+
+    DEBUG(3, "%s: ISR=%#2.2x ESR=%#2.2x RSR=%#2.2x TSR=%#4.4x\n",
+	  dev->name, int_status, eth_status, rx_status, tx_status);
+
+    /***** receive section ******/
+    SelectPage(0);
+    while (eth_status & FullPktRcvd) {
+	rsr = GetByte(XIRCREG0_RSR);
+	if (bytes_rcvd > maxrx_bytes && (rsr & PktRxOk)) {
+	    /* too many bytes received during this int, drop the rest of the
+	     * packets */
+	    lp->stats.rx_dropped++;
+	    DEBUG(2, "%s: RX drop, too much done\n", dev->name);
+	    PutWord(XIRCREG0_DO, 0x8000); /* issue cmd: skip_rx_packet */
+	} else if (rsr & PktRxOk) {
+	    struct sk_buff *skb;
+
+	    pktlen = GetWord(XIRCREG0_RBC);
+	    bytes_rcvd += pktlen;
+
+	    DEBUG(5, "rsr=%#02x packet_length=%u\n", rsr, pktlen);
+
+	    skb = dev_alloc_skb(pktlen+3); /* 1 extra so we can use insw */
+	    if (!skb) {
+		printk(KNOT_XIRC "low memory, packet dropped (size=%u)\n",
+		       pktlen);
+		lp->stats.rx_dropped++;
+	    } else { /* okay get the packet */
+		skb_reserve(skb, 2);
+		if (lp->silicon == 0 ) { /* work around a hardware bug */
+		    unsigned rhsa; /* receive start address */
+
+		    SelectPage(5);
+		    rhsa = GetWord(XIRCREG5_RHSA0);
+		    SelectPage(0);
+		    rhsa += 3; /* skip control infos */
+		    if (rhsa >= 0x8000)
+			rhsa = 0;
+		    if (rhsa + pktlen > 0x8000) {
+			unsigned i;
+			u_char *buf = skb_put(skb, pktlen);
+			for (i=0; i < pktlen ; i++, rhsa++) {
+			    buf[i] = GetByte(XIRCREG_EDP);
+			    if (rhsa == 0x8000) {
+				rhsa = 0;
+				i--;
+			    }
+			}
+		    } else {
+			insw_ns(ioaddr+XIRCREG_EDP,
+				skb_put(skb, pktlen), (pktlen+1)>>1);
+		    }
+		}
+	      #if 0
+		else if (lp->mohawk) {
+		    /* To use this 32 bit access we should use
+		     * a manual optimized loop
+		     * Also the words are swapped, we can get more
+		     * performance by using 32 bit access and swapping
+		     * the words in a register. Will need this for cardbus
+		     *
+		     * Note: don't forget to change the ALLOC_SKB to .. +3
+		     */
+		    unsigned i;
+		    u_long *p = skb_put(skb, pktlen);
+		    register u_long a;
+		    ioaddr_t edpreg = ioaddr+XIRCREG_EDP-2;
+		    for (i=0; i < len ; i += 4, p++) {
+			a = inl(edpreg);
+			__asm__("rorl $16,%0\n\t"
+				:"=q" (a)
+				: "0" (a));
+			*p = a;
+		    }
+		}
+	      #endif
+		else {
+		    insw_ns(ioaddr+XIRCREG_EDP, skb_put(skb, pktlen),
+			    (pktlen+1)>>1);
+		}
+		skb->protocol = eth_type_trans(skb, dev);
+		skb->dev = dev;
+		netif_rx(skb);
+		lp->stats.rx_packets++;
+		add_rx_bytes(&lp->stats, pktlen);
+		if (!(rsr & PhyPkt))
+		    lp->stats.multicast++;
+	    }
+	    PutWord(XIRCREG0_DO, 0x8000); /* issue cmd: skip_rx_packet */
+	} else {
+	    DEBUG(5, "rsr=%#02x\n", rsr);
+	}
+	if (rsr & PktTooLong) {
+	    lp->stats.rx_frame_errors++;
+	    DEBUG(3, "%s: Packet too long\n", dev->name);
+	}
+	if (rsr & CRCErr) {
+	    lp->stats.rx_crc_errors++;
+	    DEBUG(3, "%s: CRC error\n", dev->name);
+	}
+	if (rsr & AlignErr) {
+	    lp->stats.rx_fifo_errors++; /* okay ? */
+	    DEBUG(3, "%s: Alignment error\n", dev->name);
+	}
+
+	/* get the new ethernet status */
+	eth_status = GetByte(XIRCREG_ESR);
+    }
+    if (rx_status & 0x10) { /* Receive overrun */
+	lp->stats.rx_over_errors++;
+	PutByte(XIRCREG_CR, ClearRxOvrun);
+	DEBUG(3, "receive overrun cleared\n");
+    }
+
+    /***** transmit section ******/
+    if (int_status & PktTxed) {
+	unsigned n, nn;
+
+	n = lp->last_ptr_value;
+	nn = GetByte(XIRCREG0_PTR);
+	lp->last_ptr_value = nn;
+	if (nn < n) /* rollover */
+	    lp->stats.tx_packets += 256 - n;
+	else if (n == nn) { /* happens sometimes - don't know why */
+	    DEBUG(0, "PTR not changed?\n");
+	} else
+	    lp->stats.tx_packets += lp->last_ptr_value - n;
+	netif_wake_queue(dev);
+    }
+    if (tx_status & 0x0002) {	/* Execessive collissions */
+	DEBUG(0, "tx restarted due to execssive collissions\n");
+	PutByte(XIRCREG_CR, RestartTx);  /* restart transmitter process */
+    }
+    if (tx_status & 0x0040)
+	lp->stats.tx_aborted_errors++;
+
+    /* recalculate our work chunk so that we limit the duration of this
+     * ISR to about 1/10 of a second.
+     * Calculate only if we received a reasonable amount of bytes.
+     */
+    if (bytes_rcvd > 1000) {
+	u_long duration = jiffies - start_ticks;
+
+	if (duration >= HZ/10) { /* if more than about 1/10 second */
+	    maxrx_bytes = (bytes_rcvd * (HZ/10)) / duration;
+	    if (maxrx_bytes < 2000)
+		maxrx_bytes = 2000;
+	    else if (maxrx_bytes > 22000)
+		maxrx_bytes = 22000;
+	    DEBUG(1, "set maxrx=%u (rcvd=%u ticks=%lu)\n",
+		  maxrx_bytes, bytes_rcvd, duration);
+	} else if (!duration && maxrx_bytes < 22000) {
+	    /* now much faster */
+	    maxrx_bytes += 2000;
+	    if (maxrx_bytes > 22000)
+		maxrx_bytes = 22000;
+	    DEBUG(1, "set maxrx=%u\n", maxrx_bytes);
+	}
+    }
+
+  leave:
+    if (lockup_hack) {
+	if (int_status != 0xff && (int_status = GetByte(XIRCREG_ISR)) != 0)
+	    goto loop_entry;
+    }
+    SelectPage(saved_page);
+    PutByte(XIRCREG_CR, EnableIntr);  /* re-enable interrupts */
+    /* Instead of dropping packets during a receive, we could
+     * force an interrupt with this command:
+     *	  PutByte(XIRCREG_CR, EnableIntr|ForceIntr);
+     */
+} /* xirc2ps_interrupt */
+
+/*====================================================================*/
+
+static void
+do_tx_timeout(struct net_device *dev)
+{
+    local_info_t *lp = dev->priv;
+    printk(KERN_NOTICE "%s: transmit timed out\n", dev->name);
+    lp->stats.tx_errors++;
+    /* reset the card */
+    do_reset(dev,1);
+    dev->trans_start = jiffies;
+    netif_start_queue(dev);
+}
+
+static int
+do_start_xmit(struct sk_buff *skb, struct net_device *dev)
+{
+    local_info_t *lp = dev->priv;
+    ioaddr_t ioaddr = dev->base_addr;
+    int okay;
+    unsigned freespace;
+    unsigned pktlen = skb? skb->len : 0;
+
+    DEBUG(1, "do_start_xmit(skb=%p, dev=%p) len=%u\n",
+	  skb, dev, pktlen);
+
+    tx_timeout_check(dev, do_tx_timeout);
+    skb_tx_check(dev, skb);
+
+    /* adjust the packet length to min. required
+     * and hope that the buffer is large enough
+     * to provide some random data.
+     * fixme: For Mohawk we can change this by sending
+     * a larger packetlen than we actually have; the chip will
+     * pad this in his buffer with random bytes
+     */
+    if (pktlen < ETH_ZLEN)
+	pktlen = ETH_ZLEN;
+
+    SelectPage(0);
+    PutWord(XIRCREG0_TRS, (u_short)pktlen+2);
+    freespace = GetWord(XIRCREG0_TSO);
+    okay = freespace & 0x8000;
+    freespace &= 0x7fff;
+    /* TRS doesn't work - (indeed it is eliminated with sil-rev 1) */
+    okay = pktlen +2 < freespace;
+    DEBUG(2 + (okay ? 2 : 0), "%s: avail. tx space=%u%s\n",
+	  dev->name, freespace, okay ? " (okay)":" (not enough)");
+    if (!okay) { /* not enough space */
+	return 1;  /* upper layer may decide to requeue this packet */
+    }
+    /* send the packet */
+    PutWord(XIRCREG_EDP, (u_short)pktlen);
+    outsw_ns(ioaddr+XIRCREG_EDP, skb->data, pktlen>>1);
+    if (pktlen & 1)
+	PutByte(XIRCREG_EDP, skb->data[pktlen-1]);
+
+    if (lp->mohawk)
+	PutByte(XIRCREG_CR, TransmitPacket|EnableIntr);
+
+    DEV_KFREE_SKB (skb);
+    dev->trans_start = jiffies;
+    add_tx_bytes(&lp->stats, pktlen);
+    netif_start_queue(dev);
+    return 0;
+}
+
+static struct enet_statistics *
+do_get_stats(struct net_device *dev)
+{
+    local_info_t *lp = dev->priv;
+
+    /*	lp->stats.rx_missed_errors = GetByte(?) */
+    return &lp->stats;
+}
+
+/****************
+ * Set all addresses: This first one is the individual address,
+ * the next 9 addresses are taken from the multicast list and
+ * the rest is filled with the individual address.
+ */
+static void
+set_addresses(struct net_device *dev)
+{
+    ioaddr_t ioaddr = dev->base_addr;
+    local_info_t *lp = dev->priv;
+    struct dev_mc_list *dmi = dev->mc_list;
+    char *addr;
+    int i,j,k,n;
+
+    SelectPage(k=0x50);
+    for (i=0,j=8,n=0; ; i++, j++) {
+	if (i > 5) {
+	    if (++n > 9)
+		break;
+	    i = 0;
+	}
+	if (j > 15) {
+	    j = 8;
+	    k++;
+	    SelectPage(k);
+	}
+
+	if (n && n <= dev->mc_count && dmi) {
+	    addr = dmi->dmi_addr;
+	    dmi = dmi->next;
+	} else
+	    addr = dev->dev_addr;
+
+	if (lp->mohawk)
+	    PutByte(j, addr[5-i]);
+	else
+	    PutByte(j, addr[i]);
+    }
+    SelectPage(0);
+}
+
+/****************
+ * Set or clear the multicast filter for this adaptor.
+ * We can filter up to 9 addresses, if more are requested we set
+ * multicast promiscuous mode.
+ */
+
+static void
+set_multicast_list(struct net_device *dev)
+{
+    ioaddr_t ioaddr = dev->base_addr;
+
+    SelectPage(0x42);
+    if (dev->flags & IFF_PROMISC) { /* snoop */
+	PutByte(XIRCREG42_SWC1, 0x06); /* set MPE and PME */
+    } else if (dev->mc_count > 9 || (dev->flags & IFF_ALLMULTI)) {
+	PutByte(XIRCREG42_SWC1, 0x06); /* set MPE */
+    } else if (dev->mc_count) {
+	/* the chip can filter 9 addresses perfectly */
+	PutByte(XIRCREG42_SWC1, 0x00);
+	SelectPage(0x40);
+	PutByte(XIRCREG40_CMD0, Offline);
+	set_addresses(dev);
+	SelectPage(0x40);
+	PutByte(XIRCREG40_CMD0, EnableRecv | Online);
+    } else { /* standard usage */
+	PutByte(XIRCREG42_SWC1, 0x00);
+    }
+    SelectPage(0);
+}
+
+static int
+do_config(struct net_device *dev, struct ifmap *map)
+{
+    local_info_t *local = dev->priv;
+
+    DEBUG(0, "do_config(%p)\n", dev);
+    if (map->port != 255 && map->port != dev->if_port) {
+	if (map->port > 4)
+	    return -EINVAL;
+	if (!map->port) {
+	    local->probe_port = 1;
+	    dev->if_port = 1;
+	} else {
+	    local->probe_port = 0;
+	    dev->if_port = map->port;
+	}
+	printk(KERN_INFO "%s: switching to %s port\n",
+	       dev->name, if_names[dev->if_port]);
+	do_reset(dev,1);  /* not the fine way :-) */
+    }
+  #ifdef PCMCIA_DEBUG
+    else if (local->mohawk) {
+	/* kludge to print the mii regsiters */
+	mii_dump(dev);
+    }
+  #endif
+    return 0;
+}
+
+/****************
+ * Open the driver
+ */
+static int
+do_open(struct net_device *dev)
+{
+    local_info_t *lp = dev->priv;
+    dev_link_t *link = &lp->link;
+
+    DEBUG(0, "do_open(%p)\n", dev);
+
+    /* Check that the PCMCIA card is still here. */
+    /* Physical device present signature. */
+    if (!DEV_OK(link))
+	return -ENODEV;
+
+    /* okay */
+    link->open++;
+    MOD_INC_USE_COUNT;
+
+    netif_start_queue(dev);
+    netif_mark_up(dev);
+    do_reset(dev,1);
+
+    return 0;
+}
+
+static int
+do_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
+{
+    local_info_t *local = dev->priv;
+    ioaddr_t ioaddr = dev->base_addr;
+    u16 *data = (u16 *)&rq->ifr_data;
+
+    DEBUG(1, "%s: ioctl(%-.6s, %#04x) %04x %04x %04x %04x\n",
+	  dev->name, rq->ifr_ifrn.ifrn_name, cmd,
+	  data[0], data[1], data[2], data[3]);
+
+    if (!local->mohawk)
+	return -EOPNOTSUPP;
+
+    switch(cmd) {
+      case SIOCDEVPRIVATE:	/* Get the address of the PHY in use. */
+	data[0] = 0;		/* we have only this address */
+	/* fall trough */
+      case SIOCDEVPRIVATE+1:	/* Read the specified MII register. */
+	data[3] = mii_rd(ioaddr, data[0] & 0x1f, data[1] & 0x1f);
+	break;
+      case SIOCDEVPRIVATE+2:	/* Write the specified MII register */
+	if (!capable(CAP_NET_ADMIN))
+	    return -EPERM;
+	mii_wr(ioaddr, data[0] & 0x1f, data[1] & 0x1f, data[2], 16);
+	break;
+      default:
+	return -EOPNOTSUPP;
+    }
+    return 0;
+}
+
+static void
+hardreset(struct net_device *dev)
+{
+    local_info_t *local = dev->priv;
+    ioaddr_t ioaddr = dev->base_addr;
+
+    SelectPage(4);
+    udelay(1);
+    PutByte(XIRCREG4_GPR1, 0);	     /* clear bit 0: power down */
+    busy_loop(HZ/25);		     /* wait 40 msec */
+    if (local->mohawk)
+	PutByte(XIRCREG4_GPR1, 1);	 /* set bit 0: power up */
+    else
+	PutByte(XIRCREG4_GPR1, 1 | 4);	 /* set bit 0: power up, bit 2: AIC */
+    busy_loop(HZ/50);		     /* wait 20 msec */
+}
+
+static void
+do_reset(struct net_device *dev, int full)
+{
+    local_info_t *local = dev->priv;
+    ioaddr_t ioaddr = dev->base_addr;
+    unsigned value;
+
+    DEBUG(0, "%s: do_reset(%p,%d)\n", dev? dev->name:"eth?", dev, full);
+
+    hardreset(dev);
+    PutByte(XIRCREG_CR, SoftReset); /* set */
+    busy_loop(HZ/50);		     /* wait 20 msec */
+    PutByte(XIRCREG_CR, 0);	     /* clear */
+    busy_loop(HZ/25);		     /* wait 40 msec */
+    if (local->mohawk) {
+	SelectPage(4);
+	/* set pin GP1 and GP2 to output  (0x0c)
+	 * set GP1 to low to power up the ML6692 (0x00)
+	 * set GP2 to high to power up the 10Mhz chip  (0x02)
+	 */
+	PutByte(XIRCREG4_GPR0, 0x0e);
+    }
+
+    /* give the circuits some time to power up */
+    busy_loop(HZ/2);		/* about 500ms */
+
+    local->last_ptr_value = 0;
+    local->silicon = local->mohawk ? (GetByte(XIRCREG4_BOV) & 0x70) >> 4
+				   : (GetByte(XIRCREG4_BOV) & 0x30) >> 4;
+
+    if (local->probe_port) {
+	if (!local->mohawk) {
+	    SelectPage(4);
+	    PutByte(XIRCREG4_GPR0, 4);
+	    local->probe_port = 0;
+	}
+    } else if (dev->if_port == 2) { /* enable 10Base2 */
+	SelectPage(0x42);
+	PutByte(XIRCREG42_SWC1, 0xC0);
+    } else { /* enable 10BaseT */
+	SelectPage(0x42);
+	PutByte(XIRCREG42_SWC1, 0x80);
+    }
+    busy_loop(HZ/25);		     /* wait 40 msec to let it complete */
+
+  #ifdef PCMCIA_DEBUG
+    if (pc_debug) {
+	SelectPage(0);
+	value = GetByte(XIRCREG_ESR);	 /* read the ESR */
+	printk(KERN_DEBUG "%s: ESR is: %#02x\n", dev->name, value);
+    }
+  #endif
+
+    /* setup the ECR */
+    SelectPage(1);
+    PutByte(XIRCREG1_IMR0, 0xff); /* allow all ints */
+    PutByte(XIRCREG1_IMR1, 1	); /* and Set TxUnderrunDetect */
+    value = GetByte(XIRCREG1_ECR);
+  #if 0
+    if (local->mohawk)
+	value |= DisableLinkPulse;
+    PutByte(XIRCREG1_ECR, value);
+  #endif
+    DEBUG(0, "%s: ECR is: %#02x\n", dev->name, value);
+
+    SelectPage(0x42);
+    PutByte(XIRCREG42_SWC0, 0x20); /* disable source insertion */
+
+    if (local->silicon != 1) {
+	/* set the local memory dividing line.
+	 * The comments in the sample code say that this is only
+	 * settable with the scipper version 2 which is revision 0.
+	 * Always for CE3 cards
+	 */
+	SelectPage(2);
+	PutWord(XIRCREG2_RBS, 0x2000);
+    }
+
+    if (full)
+	set_addresses(dev);
+
+    /* Hardware workaround:
+     * The receive byte pointer after reset is off by 1 so we need
+     * to move the offset pointer back to 0.
+     */
+    SelectPage(0);
+    PutWord(XIRCREG0_DO, 0x2000); /* change offset command, off=0 */
+
+    /* setup MAC IMRs and clear status registers */
+    SelectPage(0x40);		     /* Bit 7 ... bit 0 */
+    PutByte(XIRCREG40_RMASK0, 0xff); /* ROK, RAB, rsv, RO, CRC, AE, PTL, MP */
+    PutByte(XIRCREG40_TMASK0, 0xff); /* TOK, TAB, SQE, LL, TU, JAB, EXC, CRS */
+    PutByte(XIRCREG40_TMASK1, 0xb0); /* rsv, rsv, PTD, EXT, rsv,rsv,rsv, rsv*/
+    PutByte(XIRCREG40_RXST0,  0x00); /* ROK, RAB, REN, RO, CRC, AE, PTL, MP */
+    PutByte(XIRCREG40_TXST0,  0x00); /* TOK, TAB, SQE, LL, TU, JAB, EXC, CRS */
+    PutByte(XIRCREG40_TXST1,  0x00); /* TEN, rsv, PTD, EXT, retry_counter:4  */
+
+    if (full && local->mohawk && init_mii(dev)) {
+	if (dev->if_port == 4 || local->dingo || local->new_mii) {
+	    printk(KERN_INFO "%s: MII selected\n", dev->name);
+	    SelectPage(2);
+	    PutByte(XIRCREG2_MSR, GetByte(XIRCREG2_MSR) | 0x08);
+	    busy_loop(HZ/50);
+	} else {
+	    printk(KERN_INFO "%s: MII detected; using 10mbs\n",
+		   dev->name);
+	    SelectPage(0x42);
+	    if (dev->if_port == 2) /* enable 10Base2 */
+		PutByte(XIRCREG42_SWC1, 0xC0);
+	    else  /* enable 10BaseT */
+		PutByte(XIRCREG42_SWC1, 0x80);
+	    busy_loop(HZ/25);	/* wait 40 msec to let it complete */
+	}
+    } else {  /* No MII */
+	SelectPage(0);
+	value = GetByte(XIRCREG_ESR);	 /* read the ESR */
+	dev->if_port = (value & MediaSelect) ? 1 : 2;
+    }
+
+    /* configure the LEDs */
+    SelectPage(2);
+    if (dev->if_port == 1 || dev->if_port == 4) /* TP: Link and Activity */
+	PutByte(XIRCREG2_LED, 0x3b);
+    else			      /* Coax: Not-Collision and Activity */
+	PutByte(XIRCREG2_LED, 0x3a);
+
+    if (local->dingo)
+	PutByte(0x0b, 0x04); /* 100 Mbit LED */
+
+    /* enable receiver and put the mac online */
+    if (full) {
+	SelectPage(0x40);
+	PutByte(XIRCREG40_CMD0, EnableRecv | Online);
+    }
+
+    /* setup Ethernet IMR and enable interrupts */
+    SelectPage(1);
+    PutByte(XIRCREG1_IMR0, 0xff);
+    udelay(1);
+    SelectPage(0);
+    PutByte(XIRCREG_CR, EnableIntr);
+    if (local->modem && !local->dingo) { /* do some magic */
+	if (!(GetByte(0x10) & 0x01))
+	    PutByte(0x10, 0x11); /* unmask master-int bit */
+    }
+
+    if (full)
+	printk(KERN_INFO "%s: media %s, silicon revision %d\n",
+	       dev->name, if_names[dev->if_port], local->silicon);
+    /* We should switch back to page 0 to avoid a bug in revision 0
+     * where regs with offset below 8 can't be read after an access
+     * to the MAC registers */
+    SelectPage(0);
+}
+
+/****************
+ * Initialize the Media-Independent-Interface
+ * Returns: True if we have a good MII
+ */
+static int
+init_mii(struct net_device *dev)
+{
+    local_info_t *local = dev->priv;
+    ioaddr_t ioaddr = dev->base_addr;
+    unsigned control, status, linkpartner;
+    int i;
+
+  #ifdef PCMCIA_DEBUG
+    if (pc_debug>1) {
+	mii_dump(dev);
+    }
+  #endif
+
+    status = mii_rd(ioaddr,  0, 1);
+    if ((status & 0xff00) != 0x7800)
+	return 0; /* No MII */
+
+    local->new_mii = (mii_rd(ioaddr, 0, 2) != 0xffff);
+    
+    if (local->probe_port)
+	control = 0x1000; /* auto neg */
+    else if (dev->if_port == 4)
+	control = 0x2000; /* no auto neg, 100mbs mode */
+    else
+	control = 0x0000; /* no auto neg, 10mbs mode */
+    mii_wr(ioaddr,  0, 0, control, 16);
+    udelay(100);
+    control = mii_rd(ioaddr, 0, 0);
+
+    if (control & 0x0400) {
+	printk(KERN_NOTICE "%s can't take PHY out of isolation mode\n",
+	       dev->name);
+	local->probe_port = 0;
+	return 0;
+    }
+
+    if (local->probe_port) {
+	/* according to the DP83840A specs the auto negotiation process
+	 * may take up to 3.5 sec, so we use this also for our ML6692
+	 * Fixme: Better to use a timer here!
+	 */
+	for (i=0; i < 35; i++) {
+	    busy_loop(HZ/10);	 /* wait 100 msec */
+	    status = mii_rd(ioaddr,  0, 1);
+	    if ((status & 0x0020) && (status & 0x0004))
+		break;
+	}
+
+	if (!(status & 0x0020)) {
+	    printk(KERN_INFO "%s: autonegotiation failed;"
+		   " using 10mbs\n", dev->name);
+	    if (!local->new_mii) {
+		control = 0x0000;
+		mii_wr(ioaddr,  0, 0, control, 16);
+		udelay(100);
+		SelectPage(0);
+		dev->if_port = (GetByte(XIRCREG_ESR) & MediaSelect) ? 1 : 2;
+	    }
+	} else {
+	    linkpartner = mii_rd(ioaddr, 0, 5);
+	    printk(KERN_INFO "%s: MII link partner: %04x\n",
+		   dev->name, linkpartner);
+	    if (linkpartner & 0x0080) {
+		dev->if_port = 4;
+	    } else
+		dev->if_port = 1;
+	}
+    }
+
+  #ifdef PCMCIA_DEBUG
+    if (pc_debug)
+	mii_dump(dev);
+  #endif
+
+    return 1;
+}
+
+static void
+do_powerdown(struct net_device *dev)
+{
+
+    ioaddr_t ioaddr = dev->base_addr;
+
+    DEBUG(0, "do_powerdown(%p)\n", dev);
+
+    SelectPage(4);
+    PutByte(XIRCREG4_GPR1, 0);	     /* clear bit 0: power down */
+    SelectPage(0);
+}
+
+static int
+do_stop(struct net_device *dev)
+{
+    ioaddr_t ioaddr = dev->base_addr;
+    local_info_t *lp = dev->priv;
+    dev_link_t *link = &lp->link;
+
+    DEBUG(0, "do_stop(%p)\n", dev);
+
+    if (!link)
+	return -ENODEV;
+
+    netif_stop_queue(dev);
+    netif_mark_down(dev);
+
+    SelectPage(0);
+    PutByte(XIRCREG_CR, 0);  /* disable interrupts */
+    SelectPage(0x01);
+    PutByte(XIRCREG1_IMR0, 0x00); /* forbid all ints */
+    SelectPage(4);
+    PutByte(XIRCREG4_GPR1, 0);	/* clear bit 0: power down */
+    SelectPage(0);
+
+    link->open--;
+    if (link->state & DEV_STALE_CONFIG)
+	mod_timer(&link->release, jiffies + HZ/20);
+
+    MOD_DEC_USE_COUNT;
+
+    return 0;
+}
+
+static int __init
+init_xirc2ps_cs(void)
+{
+    servinfo_t serv;
+
+    printk(KERN_INFO "%s\n", version);
+    if (card_type)
+	printk(KINF_XIRC "option card_type is obsolete\n");
+    if (lockup_hack)
+	printk(KINF_XIRC "lockup hack is enabled\n");
+    CardServices(GetCardServicesInfo, &serv);
+    if (serv.Revision != CS_RELEASE_CODE) {
+	printk(KNOT_XIRC "Card Services release does not match!\n");
+	return -1;
+    }
+    DEBUG(0, "pc_debug=%d\n", pc_debug);
+    register_pccard_driver(&dev_info, &xirc2ps_attach, &xirc2ps_detach);
+    return 0;
+}
+
+static void __exit
+exit_xirc2ps_cs(void)
+{
+    DEBUG(0, "unloading\n");
+    unregister_pccard_driver(&dev_info);
+    while (dev_list) {
+	if (dev_list->state & DEV_CONFIG)
+	    xirc2ps_release((u_long)dev_list);
+	if (dev_list)	/* xirc2ps_release() might already have detached... */
+	    xirc2ps_detach(dev_list);
+    }
+}
+
+module_init(init_xirc2ps_cs);
+module_exit(exit_xirc2ps_cs);
+
Index: oldkernel/linux/pcmcia-cs-3.1.15/clients/patches/aic7xxx.fix
diff -u /dev/null linux/pcmcia-cs-3.1.15/clients/patches/aic7xxx.fix:1.1
--- /dev/null	Mon Jul 31 21:15:10 2000
+++ linux/pcmcia-cs-3.1.15/clients/patches/aic7xxx.fix	Fri Jul  7 16:34:58 2000
@@ -0,0 +1,30 @@
+--- aic7xxx.c.orig	Thu May 21 23:18:42 1998
++++ aic7xxx.c	Fri May 22 10:27:53 1998
+@@ -163,10 +163,18 @@
+  *
+  *_M*************************************************************************/
+ 
++#ifdef PCMCIA
++#define MODULE
++#endif
++
+ #ifdef MODULE
+ #include <linux/module.h>
+ #endif
+ 
++#ifdef PCMCIA
++#undef MODULE
++#endif
++
+ #include <stdarg.h>
+ #include <asm/io.h>
+ #include <asm/irq.h>
+@@ -7238,6 +7246,8 @@
+       {PCI_VENDOR_ID_ADAPTEC, PCI_DEVICE_ID_ADAPTEC_7855, AHC_AIC7850,
+        AHC_PAGESCBS | AHC_USEDEFAULTS,                       6 },
+       {PCI_VENDOR_ID_ADAPTEC, PCI_DEVICE_ID_ADAPTEC_7860, AHC_AIC7860,
++       AHC_PAGESCBS | AHC_NEWEEPROM_FMT | AHC_BIOS_ENABLED,  7 },
++      {PCI_VENDOR_ID_ADAPTEC, 0x6075, AHC_AIC7860,
+        AHC_PAGESCBS | AHC_NEWEEPROM_FMT | AHC_BIOS_ENABLED,  7 },
+       {PCI_VENDOR_ID_ADAPTEC, PCI_DEVICE_ID_ADAPTEC_7861, AHC_294AU,
+        AHC_PAGESCBS | AHC_NEWEEPROM_FMT | AHC_BIOS_ENABLED,  8 },
Index: oldkernel/linux/pcmcia-cs-3.1.15/debug-tools/Makefile
diff -u /dev/null linux/pcmcia-cs-3.1.15/debug-tools/Makefile:1.1
--- /dev/null	Mon Jul 31 21:15:10 2000
+++ linux/pcmcia-cs-3.1.15/debug-tools/Makefile	Fri Jul  7 16:34:58 2000
@@ -0,0 +1,73 @@
+#
+# debug-tools/Makefile 1.40 2000/05/11 17:47:44 (David Hinds)
+#
+
+# Include site dependent options
+include ../config.mk
+
+CFLAGS = -O -Wall -Wstrict-prototypes -pipe
+XFLAGS = -O -pipe
+CPPFLAGS += -I../modules
+CC += $(UFLAGS)
+
+SRCS  = dump_cis.c dump_cisreg.c pack_cis.c
+HDRS  = pack_cis.h
+TOOLS = dump_cis dump_cisreg pack_cis
+
+ifdef CONFIG_PNP_BIOS
+SRCS  += lspnp.c setpnp.c
+TOOLS += lspnp setpnp
+endif
+
+ifdef CONFIG_ISA
+SRCS  += dump_tcic.c dump_exca.c 
+TOOLS += dump_tcic dump_exca
+endif
+
+ifdef CONFIG_PCI
+SRCS  += dump_cardbus.c
+TOOLS += dump_cardbus
+endif
+
+all:	$(SRCS) $(HDRS) $(TOOLS)
+
+dump_cis: dump_cis.o
+
+dump_i365: dump_i365.o
+
+dump_tcic: dump_tcic.o
+
+dump_cisreg: dump_cisreg.o
+
+lspnp: lspnp.o
+
+setpnp: setpnp.o
+
+yacc_cis.o: yacc_cis.c
+	$(CC) -MD $(XFLAGS) $(CPPFLAGS) -c $<
+	@mkdir -p .depfiles ; mv $*.d .depfiles
+
+lex_cis.o: lex_cis.c yacc_cis.h
+	$(CC) -MD $(XFLAGS) $(CPPFLAGS) -c $<
+	@mkdir -p .depfiles ; mv $*.d .depfiles
+
+pack_cis: pack_cis.o lex_cis.o yacc_cis.o
+	$(CC) $+ -o $@ -lm
+
+parser: lex_cis.o yacc_cis.c
+	$(CC) $(XFLAGS) $(CPPFLAGS) -DDEBUG -o $@ $+
+
+clean:
+	rm -f core core.* *.o *.s *.a *~ .depend .depfiles/*.d
+	rm -f dump_i365 dump_tcic $(TOOLS)
+
+install: $(TOOLS)
+	@mkdir -p $(PREFIX)/sbin
+	cp -f dump_cis pack_cis $(PREFIX)/sbin
+ifdef CONFIG_PNP_BIOS
+	cp -f lspnp setpnp $(PREFIX)/sbin
+	@mkdir -p $(PREFIX)/usr/share
+	cp -f pnp.ids $(PREFIX)/usr/share
+endif
+
+include ../rules.mk
Index: oldkernel/linux/pcmcia-cs-3.1.15/debug-tools/dump_cardbus.c
diff -u /dev/null linux/pcmcia-cs-3.1.15/debug-tools/dump_cardbus.c:1.1
--- /dev/null	Mon Jul 31 21:15:10 2000
+++ linux/pcmcia-cs-3.1.15/debug-tools/dump_cardbus.c	Fri Jul  7 16:34:58 2000
@@ -0,0 +1,184 @@
+/*======================================================================
+
+    Dump CardBus socket registers
+
+    dump_cardbus.c 1.1 2000/05/11 02:35:13
+
+    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@pcmcia.sourceforge.org>.  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 <sys/types.h>
+#include <string.h>
+#include <errno.h>
+#include <stdio.h>
+#include <unistd.h>
+#include <stdlib.h>
+
+#include "yenta.h"
+
+/*====================================================================*/
+
+typedef struct proc_cardbus {
+    u_int	reg[16];
+} proc_cardbus;
+
+typedef struct proc_info {
+    char	type[32];
+    u_int	flags;
+    int		psock;
+    u_char	bus;
+    u_char	devfn;
+    u_char	cardbus;
+} proc_info;
+
+static proc_cardbus *load_cardbus(char *fn)
+{
+    FILE *f = fopen(fn, "r");
+    static proc_cardbus cb;
+    char s[50];
+    int i, j;
+    
+    if (!f) return NULL;
+    memset(&cb, 0, sizeof cb);
+    for (i = 0; (i < 16) && !feof(f); i += 4) {
+	fgets(s, 49, f);
+	if (strlen(s) < 35) break;
+	for (j = 0; j < 4; j++)
+	    cb.reg[i+j] = strtoul(s + 9*j, NULL, 16);
+    }
+    fclose(f);
+    return &cb;
+}
+
+#define NTAG 5
+char *tag[] = { "type:", "psock:", "bus:", "devfn:", "cardbus:" };
+
+static proc_info *load_info(char *fn)
+{
+    FILE *f = fopen(fn, "r");
+    static proc_info in;
+    char s[50];
+    u_int i, a, b;
+    
+    if (!f) return NULL;
+    memset(&in, 0, sizeof in);
+    while (!feof(f)) {
+	fgets(s, 49, f);
+	for (i = 0; i < NTAG; i++)
+	    if (strncmp(s, tag[i], strlen(tag[i])) == 0) break;
+	switch (i) {
+	case 0: strcpy(in.type, s+10); break;
+	case 1: in.psock = strtoul(s+10, NULL, 10); break;
+	case 2: in.bus = strtoul(s+10, NULL, 16); break;
+	case 3:
+	    sscanf(s+10, "%02x.%d", &a, &b);
+	    in.devfn = (a<<3) | b;
+	    break;
+	case 4: in.cardbus = strtoul(s+10, NULL, 16);
+	}
+    }
+    fclose(f);
+    return &in;
+}
+
+/*====================================================================*/
+
+static char *event[] = {
+    "cstschg", "ccd1", "ccd2", "pwrcycle",
+    "16bit", "32bit", "cint", "badcard",
+    "datalost", "badvcc", "5Vcard", "3Vcard",
+    "XVcard", "YVcard", "rsvd", "rsvd",
+    "rsvd", "rsvd", "rsvd", "rsvd",
+    "rsvd", "rsvd", "rsvd", "rsvd",
+    "rsvd", "rsvd", "rsvd", "rsvd",
+    "5Vsock", "3Vsock", "XVsock", "YVsock"
+};
+
+static void print_events(char *tag, u_int val)
+{
+    int i;
+    printf("  %s:%*s 0x%08x", tag, 15-strlen(tag), "", val);
+    if (val)
+	printf("\n   ");
+    for (i = 0; i < 32; i++)
+	if (val & (1<<i)) printf(" [%s]", event[i]);
+    printf("\n");
+}
+
+/*====================================================================*/
+
+static void dump_sock(proc_cardbus *cb, proc_info *in)
+{
+    u_int val;
+    print_events("Socket Event", cb->reg[CB_SOCKET_EVENT>>2]);
+    print_events("Socket Mask", cb->reg[CB_SOCKET_MASK>>2]);
+    print_events("Socket State", cb->reg[CB_SOCKET_STATE>>2]);
+    val = cb->reg[CB_SOCKET_CONTROL>>2];
+    printf("  Socket Control:  0x%08x\n    [Vcc", val);
+    switch (val & CB_SC_VCC_MASK) {
+    case CB_SC_VCC_OFF:	printf(" off]"); break;
+    case CB_SC_VCC_5V:	printf("=5v]"); break;
+    case CB_SC_VCC_3V:	printf("=3.3v]"); break;
+    case CB_SC_VCC_XV:	printf("=Xv]"); break;
+    case CB_SC_VCC_YV:	printf("=Yv]"); break;
+    }
+    printf(" [Vpp");
+    switch (val & CB_SC_VPP_MASK) {
+    case CB_SC_VPP_OFF:	printf(" off]"); break;
+    case CB_SC_VPP_5V:	printf("=5v]"); break;
+    case CB_SC_VPP_3V:	printf("=3.3v]"); break;
+    case CB_SC_VPP_XV:	printf("=Xv]"); break;
+    case CB_SC_VPP_YV:	printf("=Yv]"); break;
+    }
+    if (val & CB_SC_CCLK_STOP)
+	printf(" [stopclk]");
+    printf("\n\n");
+}
+
+/*====================================================================*/
+
+int main(int argc, char *argv[])
+{
+    char fn[100];
+    int i;
+    proc_info *in;
+    proc_cardbus *cb;
+
+    if (access("/proc/bus/pccard", R_OK) != 0)
+	fprintf(stderr, "/proc/bus/pccard does not exist!\n");
+    for (i = 0; ; i++) {
+	sprintf(fn, "/proc/bus/pccard/%02d/cardbus", i);
+	if (access(fn, R_OK) != 0)
+	    break;
+	cb = load_cardbus(fn);
+	sprintf(fn, "/proc/bus/pccard/%02d/info", i);
+	in = load_info(fn);
+	printf("Socket %d:\n", i);
+	dump_sock(cb, in);
+    }
+    return 0;
+}
Index: oldkernel/linux/pcmcia-cs-3.1.15/debug-tools/dump_cis.c
diff -u /dev/null linux/pcmcia-cs-3.1.15/debug-tools/dump_cis.c:1.1
--- /dev/null	Mon Jul 31 21:15:10 2000
+++ linux/pcmcia-cs-3.1.15/debug-tools/dump_cis.c	Fri Jul  7 16:34:58 2000
@@ -0,0 +1,1072 @@
+/*======================================================================
+
+    PC Card CIS dump utility
+
+    dump_cis.c 1.48 2000/01/12 18:40: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@pcmcia.sourceforge.org>.  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__
+#include <pcmcia/u_compat.h>
+#endif
+
+#include <sys/types.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <sys/time.h>
+#include <sys/ioctl.h>
+#include <sys/stat.h>
+
+#include <pcmcia/cs_types.h>
+#include <pcmcia/cs.h>
+#include <pcmcia/cistpl.h>
+#include <pcmcia/ds.h>
+
+static int verbose = 0;
+static char indent[10] = "  ";
+
+/*====================================================================*/
+
+#ifdef __linux__
+
+static int major = 0;
+
+static int lookup_dev(char *name)
+{
+    FILE *f;
+    int n;
+    char s[32], t[32];
+    
+    f = fopen("/proc/devices", "r");
+    if (f == NULL)
+	return -1;
+    while (fgets(s, 32, f) != NULL) {
+	if (sscanf(s, "%d %s", &n, t) == 2)
+	    if (strcmp(name, t) == 0)
+		break;
+    }
+    fclose(f);
+    if (strcmp(name, t) == 0)
+	return n;
+    else
+	return -1;
+}
+
+#endif /* __linux__ */
+
+/*====================================================================*/
+
+static int open_sock(int sock)
+{
+#ifdef __linux__
+    int fd;
+    char *fn;
+    dev_t dev = (major<<8) + sock;
+    if ((fn = tmpnam(NULL)) == NULL)
+	return -1;
+    if (mknod(fn, (S_IFCHR|S_IREAD|S_IWRITE), dev) != 0)
+	return -1;
+    fd = open(fn, O_RDONLY);
+    unlink(fn);
+    return fd;
+#endif
+#ifdef __BEOS__
+    char fn[B_OS_NAME_LENGTH];
+    sprintf(fn, "/dev/pcmcia/sock%d", sock);
+    return open(fn, O_RDONLY);
+#endif
+} /* open_sock */
+
+/*====================================================================*/
+
+static void print_tuple(tuple_parse_t *tup)
+{
+    int i;
+    printf("%soffset 0x%2.2x, tuple 0x%2.2x, link 0x%2.2x\n",
+	   indent, tup->tuple.CISOffset, tup->tuple.TupleCode,
+	   tup->tuple.TupleLink);
+    for (i = 0; i < tup->tuple.TupleDataLen; i++) {
+	if ((i % 16) == 0) printf("%s  ", indent);
+	printf("%2.2x ", (u_char)tup->data[i]);
+	if ((i % 16) == 15) putchar('\n');
+    }
+    if ((i % 16) != 0) putchar('\n');
+}
+
+/*====================================================================*/
+
+static void print_funcid(cistpl_funcid_t *fn)
+{
+    printf("%sfuncid ", indent);
+    switch (fn->func) {
+    case CISTPL_FUNCID_MULTI:
+	printf("multi_function"); break;
+    case CISTPL_FUNCID_MEMORY:
+	printf("memory_card"); break;
+    case CISTPL_FUNCID_SERIAL:
+	printf("serial_port"); break;
+    case CISTPL_FUNCID_PARALLEL:
+	printf("parallel_port"); break;
+    case CISTPL_FUNCID_FIXED:
+	printf("fixed_disk"); break;
+    case CISTPL_FUNCID_VIDEO:
+	printf("video_adapter"); break;
+    case CISTPL_FUNCID_NETWORK:
+	printf("network_adapter"); break;
+    case CISTPL_FUNCID_AIMS:
+	printf("aims_card"); break;
+    case CISTPL_FUNCID_SCSI:
+	printf("scsi_adapter"); break;
+    default:
+	printf("unknown"); break;
+    }
+    if (fn->sysinit & CISTPL_SYSINIT_POST)
+	printf(" [post]");
+    if (fn->sysinit & CISTPL_SYSINIT_ROM)
+	printf(" [rom]");
+    putchar('\n');
+}
+
+/*====================================================================*/
+
+static void print_size(u_int size)
+{
+    if (size < 1024)
+	printf("%ub", size);
+    else if (size < 1024*1024)
+	printf("%ukb", size/1024);
+    else
+	printf("%umb", size/(1024*1024));
+}
+
+static void print_unit(u_int v, char *unit, char tag)
+{
+    int n;
+    for (n = 0; (v % 1000) == 0; n++) v /= 1000;
+    printf("%u", v);
+    if (n < strlen(unit)) putchar(unit[n]);
+    putchar(tag);
+}
+
+static void print_time(u_int tm, u_long scale)
+{
+    print_unit(tm * scale, "num", 's');
+}
+
+static void print_volt(u_int vi)
+{
+    print_unit(vi * 10, "um", 'V');
+}
+    
+static void print_current(u_int ii)
+{
+    print_unit(ii / 10, "um", 'A');
+}
+
+static void print_speed(u_int b)
+{
+    if (b < 1000)
+	printf("%u bits/sec", b);
+    else if (b < 1000000)
+	printf("%u kb/sec", b/1000);
+    else
+	printf("%u mb/sec", b/1000000);
+}
+
+/*====================================================================*/
+
+static const char *dtype[] = {
+    "NULL", "ROM", "OTPROM", "EPROM", "EEPROM", "FLASH", "SRAM",
+    "DRAM", "rsvd", "rsvd", "rsvd", "rsvd", "rsvd", "fn_specific",
+    "extended", "rsvd"
+};
+
+static void print_device(cistpl_device_t *dev)
+{
+    int i;
+    for (i = 0; i < dev->ndev; i++) {
+	printf("%s  %s ", indent, dtype[dev->dev[i].type]);
+	printf("%uns, ", dev->dev[i].speed);
+	print_size(dev->dev[i].size);
+	putchar('\n');
+    }
+    if (dev->ndev == 0)
+	printf("%s  no_info\n", indent);
+}
+
+/*====================================================================*/
+
+static void print_power(char *tag, cistpl_power_t *power)
+{
+    int i, n;
+    for (i = n = 0; i < 8; i++)
+	if (power->present & (1<<i)) n++;
+    i = 0;
+    printf("%s  %s", indent, tag);
+    if (power->present & (1<<CISTPL_POWER_VNOM)) {
+	printf(" Vnom "); i++;
+	print_volt(power->param[CISTPL_POWER_VNOM]);
+    }
+    if (power->present & (1<<CISTPL_POWER_VMIN)) {
+	printf(" Vmin "); i++;
+	print_volt(power->param[CISTPL_POWER_VMIN]);
+    }
+    if (power->present & (1<<CISTPL_POWER_VMAX)) {
+ 	printf(" Vmax "); i++;
+	print_volt(power->param[CISTPL_POWER_VMAX]);
+    }
+    if (power->present & (1<<CISTPL_POWER_ISTATIC)) {
+	printf(" Istatic "); i++;
+	print_current(power->param[CISTPL_POWER_ISTATIC]);
+    }
+    if (power->present & (1<<CISTPL_POWER_IAVG)) {
+	if (++i == 5) printf("\n%s   ", indent);
+	printf(" Iavg ");
+	print_current(power->param[CISTPL_POWER_IAVG]);
+    }
+    if (power->present & (1<<CISTPL_POWER_IPEAK)) {
+	if (++i == 5) printf("\n%s ", indent);
+	printf(" Ipeak ");
+	print_current(power->param[CISTPL_POWER_IPEAK]);
+    }
+    if (power->present & (1<<CISTPL_POWER_IDOWN)) {
+	if (++i == 5) printf("\n%s ", indent);
+	printf(" Idown ");
+	print_current(power->param[CISTPL_POWER_IDOWN]);
+    }
+    if (power->flags & CISTPL_POWER_HIGHZ_OK) {
+	if (++i == 5) printf("\n%s ", indent);
+	printf(" [highz OK]");
+    }
+    if (power->flags & CISTPL_POWER_HIGHZ_REQ) {
+	printf(" [highz]");
+    }
+    putchar('\n');
+}
+
+/*====================================================================*/
+
+static void print_cftable_entry(cistpl_cftable_entry_t *entry)
+{
+    int i;
+    
+    printf("%scftable_entry 0x%2.2x%s\n", indent, entry->index,
+	   (entry->flags & CISTPL_CFTABLE_DEFAULT) ? " [default]" : "");
+
+    if (entry->flags & ~CISTPL_CFTABLE_DEFAULT) {
+	printf("%s ", indent);
+	if (entry->flags & CISTPL_CFTABLE_BVDS)
+	    printf(" [bvd]");
+	if (entry->flags & CISTPL_CFTABLE_WP)
+	    printf(" [wp]");
+	if (entry->flags & CISTPL_CFTABLE_RDYBSY)
+	    printf(" [rdybsy]");
+	if (entry->flags & CISTPL_CFTABLE_MWAIT)
+	    printf(" [mwait]");
+	if (entry->flags & CISTPL_CFTABLE_AUDIO)
+	    printf(" [audio]");
+	if (entry->flags & CISTPL_CFTABLE_READONLY)
+	    printf(" [readonly]");
+	if (entry->flags & CISTPL_CFTABLE_PWRDOWN)
+	    printf(" [pwrdown]");
+	putchar('\n');
+    }
+    
+    if (entry->vcc.present)
+	print_power("Vcc", &entry->vcc);
+    if (entry->vpp1.present)
+	print_power("Vpp1", &entry->vpp1);
+    if (entry->vpp2.present)
+	print_power("Vpp2", &entry->vpp2);
+
+    if ((entry->timing.wait != 0) || (entry->timing.ready != 0) ||
+	(entry->timing.reserved != 0)) {
+	printf("%s  timing", indent);
+	if (entry->timing.wait != 0) {
+	    printf(" wait ");
+	    print_time(entry->timing.wait, entry->timing.waitscale);
+	}
+	if (entry->timing.ready != 0) {
+	    printf(" ready ");
+	    print_time(entry->timing.ready, entry->timing.rdyscale);
+	}
+	if (entry->timing.reserved != 0) {
+	    printf(" reserved ");
+	    print_time(entry->timing.reserved, entry->timing.rsvscale);
+	}
+	putchar('\n');
+    }
+    
+    if (entry->io.nwin) {
+	cistpl_io_t *io = &entry->io;
+	printf("%s  io", indent);
+	for (i = 0; i < io->nwin; i++) {
+	    if (i) putchar(',');
+	    printf(" 0x%4.4x-0x%4.4x", io->win[i].base,
+		   io->win[i].base+io->win[i].len-1);
+	}
+	printf(" [lines=%d]", io->flags & CISTPL_IO_LINES_MASK);
+	if (io->flags & CISTPL_IO_8BIT) printf(" [8bit]");
+	if (io->flags & CISTPL_IO_16BIT) printf(" [16bit]");
+	if (io->flags & CISTPL_IO_RANGE) printf(" [range]");
+	putchar('\n');
+    }
+
+    if (entry->irq.IRQInfo1) {
+	printf("%s  irq ", indent);
+	if (entry->irq.IRQInfo1 & IRQ_INFO2_VALID)
+	    printf("mask 0x%04x", entry->irq.IRQInfo2);
+	else
+	    printf("%u", entry->irq.IRQInfo1 & IRQ_MASK);
+	if (entry->irq.IRQInfo1 & IRQ_LEVEL_ID) printf(" [level]");
+	if (entry->irq.IRQInfo1 & IRQ_PULSE_ID) printf(" [pulse]");
+	if (entry->irq.IRQInfo1 & IRQ_SHARE_ID) printf(" [shared]");
+	putchar('\n');
+    }
+
+    if (entry->mem.nwin) {
+	cistpl_mem_t *mem = &entry->mem;
+	printf("%s  memory", indent);
+	for (i = 0; i < mem->nwin; i++) {
+	    if (i) putchar(',');
+	    printf(" 0x%4.4x-0x%4.4x @ 0x%4.4x", mem->win[i].card_addr,
+		   mem->win[i].card_addr + mem->win[i].len-1,
+		   mem->win[i].host_addr);
+	}
+	putchar('\n');
+    }
+
+    if (verbose && entry->subtuples)
+	printf("%s  %d bytes in subtuples\n", indent, entry->subtuples);
+    
+}
+
+/*====================================================================*/
+
+static void print_cftable_entry_cb(cistpl_cftable_entry_cb_t *entry)
+{
+    int i;
+    
+    printf("%scftable_entry_cb 0x%2.2x%s\n", indent, entry->index,
+	   (entry->flags & CISTPL_CFTABLE_DEFAULT) ? " [default]" : "");
+
+    if (entry->flags & ~CISTPL_CFTABLE_DEFAULT) {
+	printf("%s ", indent);
+	if (entry->flags & CISTPL_CFTABLE_MASTER)
+	    printf(" [master]");
+	if (entry->flags & CISTPL_CFTABLE_INVALIDATE)
+	    printf(" [invalidate]");
+	if (entry->flags & CISTPL_CFTABLE_VGA_PALETTE)
+	    printf(" [vga palette]");
+	if (entry->flags & CISTPL_CFTABLE_PARITY)
+	    printf(" [parity]");
+	if (entry->flags & CISTPL_CFTABLE_WAIT)
+	    printf(" [wait]");
+	if (entry->flags & CISTPL_CFTABLE_SERR)
+	    printf(" [serr]");
+	if (entry->flags & CISTPL_CFTABLE_FAST_BACK)
+	    printf(" [fast back]");
+	if (entry->flags & CISTPL_CFTABLE_BINARY_AUDIO)
+	    printf(" [binary audio]");
+	if (entry->flags & CISTPL_CFTABLE_PWM_AUDIO)
+	    printf(" [pwm audio]");
+	putchar('\n');
+    }
+    
+    if (entry->vcc.present)
+	print_power("Vcc", &entry->vcc);
+    if (entry->vpp1.present)
+	print_power("Vpp1", &entry->vpp1);
+    if (entry->vpp2.present)
+	print_power("Vpp2", &entry->vpp2);
+
+    if (entry->io) {
+	printf("%s  io_base", indent);
+	for (i = 0; i < 8; i++)
+	    if (entry->io & (1<<i)) printf(" %d", i);
+	putchar('\n');
+    }
+
+    if (entry->irq.IRQInfo1) {
+	printf("%s  irq ", indent);
+	if (entry->irq.IRQInfo1 & IRQ_INFO2_VALID)
+	    printf("mask 0x%4.4x", entry->irq.IRQInfo2);
+	else
+	    printf("%u", entry->irq.IRQInfo1 & IRQ_MASK);
+	if (entry->irq.IRQInfo1 & IRQ_LEVEL_ID) printf(" [level]");
+	if (entry->irq.IRQInfo1 & IRQ_PULSE_ID) printf(" [pulse]");
+	if (entry->irq.IRQInfo1 & IRQ_SHARE_ID) printf(" [shared]");
+	putchar('\n');
+    }
+
+    if (entry->mem) {
+	printf("%s  mem_base", indent);
+	for (i = 0; i < 8; i++)
+	    if (entry->mem & (1<<i)) printf(" %d", i);
+	putchar('\n');
+    }
+
+    if (verbose && entry->subtuples)
+	printf("%s  %d bytes in subtuples\n", indent,  entry->subtuples);
+    
+}
+
+/*====================================================================*/
+
+static void print_jedec(cistpl_jedec_t *j)
+{
+    int i;
+    for (i = 0; i < j->nid; i++) {
+	if (i != 0) putchar(',');
+	printf(" 0x%02x 0x%02x", j->id[i].mfr, j->id[i].info);
+    }
+    putchar('\n');
+}
+
+/*====================================================================*/
+
+static void print_device_geo(cistpl_device_geo_t *geo)
+{
+    int i;
+    for (i = 0; i < geo->ngeo; i++) {
+	printf("%s  width %d erase 0x%x read 0x%x write 0x%x "
+	       "partition 0x%x interleave 0x%x\n", indent,
+	       geo->geo[i].buswidth, geo->geo[i].erase_block,
+	       geo->geo[i].read_block, geo->geo[i].write_block,
+	       geo->geo[i].partition, geo->geo[i].interleave);
+    }
+}
+
+/*====================================================================*/
+
+static void print_org(cistpl_org_t *org)
+{
+    printf("%sdata_org ", indent);
+    switch (org->data_org) {
+    case CISTPL_ORG_FS:
+	printf("[filesystem]"); break;
+    case CISTPL_ORG_APPSPEC:
+	printf("[app_specific]"); break;
+    case CISTPL_ORG_XIP:
+	printf("[code]"); break;
+    default:
+	if (org->data_org < 0x80)
+	    printf("[reserved]");
+	else
+	    printf("[vendor_specific]");
+    }
+    printf(", \"%s\"\n", org->desc);
+}
+
+/*====================================================================*/
+
+static char *data_mod[] = {
+    "Bell103", "V.21", "V.23", "V.22", "Bell212A", "V.22bis",
+    "V.26", "V.26bis", "V.27bis", "V.29", "V.32", "V.32bis",
+    "V.34", "rfu", "rfu", "rfu"
+};
+static char *fax_mod[] = {
+    "V.21-C2", "V.27ter", "V.29", "V.17", "V.33", "rfu", "rfu", "rfu"
+};
+static char *fax_features[] = {
+    "T.3", "T.4", "T.6", "error", "voice", "poll", "file", "passwd"
+};
+static char *cmd_protocol[] = {
+    "AT1", "AT2", "AT3", "MNP_AT", "V.25bis", "V.25A", "DMCL"
+};
+static char *uart[] = {
+    "8250", "16450", "16550", "8251", "8530", "85230"
+};
+static char *parity[] = { "space", "mark", "odd", "even" };
+static char *stop[] = { "1", "1.5", "2" };
+static char *flow[] = {
+    "XON/XOFF xmit", "XON/XOFF rcv", "hw xmit", "hw rcv", "transparent"
+};
+static void print_serial(cistpl_funce_t *funce)
+{
+    cistpl_serial_t *s;
+    cistpl_data_serv_t *ds;
+    cistpl_fax_serv_t *fs;
+    cistpl_modem_cap_t *cp;
+    int i, j;
+    
+    switch (funce->type & 0x0f) {
+    case CISTPL_FUNCE_SERIAL_IF:
+    case CISTPL_FUNCE_SERIAL_IF_DATA:
+    case CISTPL_FUNCE_SERIAL_IF_FAX:
+    case CISTPL_FUNCE_SERIAL_IF_VOICE:
+	s = (cistpl_serial_t *)(funce->data);
+	printf("%sserial_interface", indent);
+	if ((funce->type & 0x0f) == CISTPL_FUNCE_SERIAL_IF_DATA)
+	    printf("_data");
+	else if ((funce->type & 0x0f) == CISTPL_FUNCE_SERIAL_IF_FAX)
+	    printf("_fax");
+	else if ((funce->type & 0x0f) == CISTPL_FUNCE_SERIAL_IF_VOICE)
+	    printf("_voice");
+	printf("\n%s  uart %s", indent,
+	       (s->uart_type < 6) ? uart[s->uart_type] : "reserved");
+	if (s->uart_cap_0) {
+	    printf(" [");
+	    for (i = 0; i < 4; i++)
+	        if (s->uart_cap_0 & (1<<i))
+		    printf("%s%s", parity[i],
+			   (s->uart_cap_0 >= (2<<i)) ? "/" : "]");
+	}
+	if (s->uart_cap_1) {
+	    int m = s->uart_cap_1 & 0x0f;
+	    int n = s->uart_cap_1 >> 4;
+	    printf(" [");
+	    for (i = 0; i < 4; i++)
+		if (m & (1<<i))
+		    printf("%d%s", i+5, (m >= (2<<i)) ? "/" : "");
+	    printf("] [");
+	    for (i = 0; i < 3; i++)
+	        if (n & (1<<i))
+		    printf("%s%s", stop[i], (n >= (2<<i)) ? "/" : "]");
+	}
+	printf("\n");
+	break;
+    case CISTPL_FUNCE_SERIAL_CAP:
+    case CISTPL_FUNCE_SERIAL_CAP_DATA:
+    case CISTPL_FUNCE_SERIAL_CAP_FAX:
+    case CISTPL_FUNCE_SERIAL_CAP_VOICE:
+	cp = (cistpl_modem_cap_t *)(funce->data);
+	printf("%sserial_modem_cap", indent);
+	if ((funce->type & 0x0f) == CISTPL_FUNCE_SERIAL_CAP_DATA)
+	    printf("_data");
+	else if ((funce->type & 0x0f) == CISTPL_FUNCE_SERIAL_CAP_FAX)
+	    printf("_fax");
+	else if ((funce->type & 0x0f) == CISTPL_FUNCE_SERIAL_CAP_VOICE)
+	    printf("_voice");
+	if (cp->flow) {
+	    printf("\n%s  flow", indent);
+	    for (i = 0; i < 5; i++)
+		if (cp->flow & (1<<i))
+		    printf(" [%s]", flow[i]);
+	}
+	printf("\n%s  cmd_buf %d rcv_buf %d xmit_buf %d\n",
+	       indent, 4*(cp->cmd_buf+1),
+	       cp->rcv_buf_0+(cp->rcv_buf_1<<8)+(cp->rcv_buf_2<<16),
+	       cp->xmit_buf_0+(cp->xmit_buf_1<<8)+(cp->xmit_buf_2<<16));
+	break;
+    case CISTPL_FUNCE_SERIAL_SERV_DATA:
+	ds = (cistpl_data_serv_t *)(funce->data);
+	printf("%sserial_data_services\n", indent);
+	printf("%s  data_rate %d\n", indent,
+	       75*((ds->max_data_0<<8) + ds->max_data_1));
+	printf("%s  modulation", indent);
+	for (i = j = 0; i < 16; i++)
+	    if (((ds->modulation_1<<8) + ds->modulation_0) & (1<<i)) {
+		if (++j % 6 == 0)
+		    printf("\n%s   ", indent);
+		printf(" [%s]", data_mod[i]);
+	    }
+	printf("\n");
+	if (ds->error_control) {
+	    printf("%s  error_control", indent);
+	    if (ds->error_control & CISTPL_SERIAL_ERR_MNP2_4)
+		printf(" [MNP2-4]");
+	    if (ds->error_control & CISTPL_SERIAL_ERR_V42_LAPM)
+		printf(" [V.42/LAPM]");
+	    printf("\n");
+	}
+	if (ds->compression) {
+	    printf("%s  compression", indent);
+	    if (ds->compression & CISTPL_SERIAL_CMPR_V42BIS)
+		printf(" [V.42bis]");
+	    if (ds->compression & CISTPL_SERIAL_CMPR_MNP5)
+		printf(" [MNP5]");
+	    printf("\n");
+	}
+	if (ds->cmd_protocol) {
+	    printf("%s  cmd_protocol", indent);
+	    for (i = 0; i < 7; i++)
+		if (ds->cmd_protocol & (1<<i))
+		    printf(" [%s]", cmd_protocol[i]);
+	    printf("\n");
+	}
+	break;
+	
+    case CISTPL_FUNCE_SERIAL_SERV_FAX:
+	fs = (cistpl_fax_serv_t *)(funce->data);
+	printf("%sserial_fax_services [class=%d]\n",
+	       indent, funce->type>>4);
+	printf("%s  data_rate %d\n", indent,
+	       75*((fs->max_data_0<<8) + fs->max_data_1));
+	printf("%s  modulation", indent);
+	for (i = 0; i < 8; i++)
+	    if (fs->modulation & (1<<i))
+		printf(" [%s]", fax_mod[i]);
+	printf("\n");
+	if (fs->features_0) {
+	    printf("%s  features", indent);
+	    for (i = 0; i < 8; i++)
+		if (fs->features_0 & (1<<i))
+		    printf(" [%s]", fax_features[i]);
+	    printf("\n");
+	}
+	break;
+    }
+}
+
+/*====================================================================*/
+
+static void print_fixed(cistpl_funce_t *funce)
+{
+    cistpl_ide_interface_t *i;
+    cistpl_ide_feature_t *f;
+    
+    switch (funce->type) {
+    case CISTPL_FUNCE_IDE_IFACE:
+	i = (cistpl_ide_interface_t *)(funce->data);
+	printf("%sdisk_interface ", indent);
+	if (i->interface == CISTPL_IDE_INTERFACE)
+	    printf("[ide]\n");
+	else
+	    printf("[undefined]\n");
+	break;
+    case CISTPL_FUNCE_IDE_MASTER:
+    case CISTPL_FUNCE_IDE_SLAVE:
+	f = (cistpl_ide_feature_t *)(funce->data);
+	printf("%sdisk_features", indent);
+	if (f->feature1 & CISTPL_IDE_SILICON)
+	    printf(" [silicon]");
+	else
+	    printf(" [rotating]");
+	if (f->feature1 & CISTPL_IDE_UNIQUE)
+	    printf(" [unique]");
+	if (f->feature1 & CISTPL_IDE_DUAL)
+	    printf(" [dual]");
+	else
+	    printf(" [single]");
+	if (f->feature1 && f->feature2)
+	    printf("\n%s ", indent);
+	if (f->feature2 & CISTPL_IDE_HAS_SLEEP)
+	    printf(" [sleep]");
+	if (f->feature2 & CISTPL_IDE_HAS_STANDBY)
+	    printf(" [standby]");
+	if (f->feature2 & CISTPL_IDE_HAS_IDLE)
+	    printf(" [idle]");
+	if (f->feature2 & CISTPL_IDE_LOW_POWER)
+	    printf(" [low power]");
+	if (f->feature2 & CISTPL_IDE_REG_INHIBIT)
+	    printf(" [reg inhibit]");
+	if (f->feature2 & CISTPL_IDE_HAS_INDEX)
+	    printf(" [index]");
+	if (f->feature2 & CISTPL_IDE_IOIS16)
+	    printf(" [iois16]");
+	putchar('\n');
+	break;
+    }
+}
+
+/*====================================================================*/
+
+static const char *tech[] = {
+    "undefined", "ARCnet", "ethernet", "token_ring", "localtalk",
+    "FDDI/CDDI", "ATM", "wireless"
+};
+
+static const char *media[] = {
+    "undefined", "unshielded_twisted_pair", "shielded_twisted_pair",
+    "thin_coax", "thick_coax", "fiber", "900_MHz", "2.4_GHz",
+    "5.4_GHz", "diffuse_infrared", "point_to_point_infrared"
+};
+
+static void print_network(cistpl_funce_t *funce)
+{
+    cistpl_lan_tech_t *t;
+    cistpl_lan_speed_t *s;
+    cistpl_lan_media_t *m;
+    cistpl_lan_node_id_t *n;
+    cistpl_lan_connector_t *c;
+    int i;
+    
+    switch (funce->type) {
+    case CISTPL_FUNCE_LAN_TECH:
+	t = (cistpl_lan_tech_t *)(funce->data);
+	printf("%slan_technology %s\n", indent, tech[t->tech]);
+	break;
+    case CISTPL_FUNCE_LAN_SPEED:
+	s = (cistpl_lan_speed_t *)(funce->data);
+	printf("%slan_speed ", indent);
+	print_speed(s->speed);
+	putchar('\n');
+	break;
+    case CISTPL_FUNCE_LAN_MEDIA:
+	m = (cistpl_lan_media_t *)(funce->data);
+	printf("%slan_media %s\n", indent, media[m->media]);
+	break;
+    case CISTPL_FUNCE_LAN_NODE_ID:
+	n = (cistpl_lan_node_id_t *)(funce->data);
+	printf("%slan_node_id", indent);
+	for (i = 0; i < n->nb; i++)
+	    printf(" %02x", n->id[i]);
+	putchar('\n');
+	break;
+    case CISTPL_FUNCE_LAN_CONNECTOR:
+	c = (cistpl_lan_connector_t *)(funce->data);
+	printf("%slan_connector ", indent);
+	if (c->code == 0)
+	    printf("Open connector standard\n");
+	else
+	    printf("Closed connector standard\n");
+	break;
+    }
+}
+
+/*====================================================================*/
+
+static void print_vers_1(cistpl_vers_1_t *v1)
+{
+    int i, n;
+    char s[32];
+    sprintf(s, "%svers_1 %d.%d", indent, v1->major, v1->minor);
+    printf("%s", s);
+    n = strlen(s);
+    for (i = 0; i < v1->ns; i++) {
+	if (n + strlen(v1->str + v1->ofs[i]) + 4 > 72) {
+	    n = strlen(indent) + 2;
+	    printf(",\n%s  ", indent);
+	} else {
+	    printf(", ");
+	    n += 2;
+	}
+	printf("\"%s\"", v1->str + v1->ofs[i]);
+	n += strlen(v1->str + v1->ofs[i]) + 2;
+    }
+    putchar('\n');
+}
+
+/*====================================================================*/
+
+static void print_vers_2(cistpl_vers_2_t *v2)
+{
+    printf("%sversion 0x%2.2x, compliance 0x%2.2x, dindex 0x%4.4x\n",
+	   indent, v2->vers, v2->comply, v2->dindex);
+    printf("%s  vspec8 0x%2.2x, vspec9 0x%2.2x, nhdr %d\n",
+	   indent, v2->vspec8, v2->vspec9, v2->nhdr);
+    printf("%s  vendor \"%s\"\n", indent, v2->str+v2->vendor);
+    printf("%s  info \"%s\"\n", indent, v2->str+v2->info);
+}
+
+/*====================================================================*/
+
+static void print_config(int code, cistpl_config_t *cfg)
+{
+    printf("%sconfig%s base 0x%4.4x", indent,
+	   (code == CISTPL_CONFIG_CB) ? "_cb" : "",
+	   cfg->base);
+    if (code == CISTPL_CONFIG)
+	printf(" mask 0x%4.4x", cfg->rmask[0]);
+    printf(" last_index 0x%2.2x\n", cfg->last_idx);
+    if (verbose && cfg->subtuples)
+	printf("%s  %d bytes in subtuples\n", indent, cfg->subtuples);
+}
+
+/*====================================================================*/
+
+static int nfn = 0, cur = 0;
+
+static void print_parse(tuple_parse_t *tup)
+{
+    static int func = 0;
+    int i;
+    
+    switch (tup->tuple.TupleCode) {
+    case CISTPL_DEVICE:
+    case CISTPL_DEVICE_A:
+	if (tup->tuple.TupleCode == CISTPL_DEVICE)
+	    printf("%sdev_info\n", indent);
+	else
+	    printf("%sattr_dev_info\n", indent);
+	print_device(&tup->parse.device);
+	break;
+    case CISTPL_CHECKSUM:
+	printf("%schecksum 0x%04x-0x%04x = 0x%02x\n",
+	       indent, tup->parse.checksum.addr,
+	       tup->parse.checksum.addr+tup->parse.checksum.len-1,
+	       tup->parse.checksum.sum);
+	break;
+    case CISTPL_LONGLINK_A:
+	if (verbose)
+	    printf("%slong_link_attr 0x%04x\n", indent,
+		   tup->parse.longlink.addr);
+	break;
+    case CISTPL_LONGLINK_C:
+	if (verbose)
+	    printf("%slong_link 0x%04x\n", indent,
+		   tup->parse.longlink.addr);
+	break;
+    case CISTPL_LONGLINK_MFC:
+	if (verbose) {
+	    printf("%smfc_long_link\n", indent);
+	    for (i = 0; i < tup->parse.longlink_mfc.nfn; i++)
+		printf("%s function %d: %s 0x%04x\n", indent, i,
+		       tup->parse.longlink_mfc.fn[i].space ? "common" : "attr",
+		       tup->parse.longlink_mfc.fn[i].addr);
+	} else {
+	    printf("%smfc {\n", indent);
+	    nfn = tup->parse.longlink_mfc.nfn;
+	    cur = 0;
+	    strcat(indent, "  ");
+	}
+	break;
+    case CISTPL_NO_LINK:
+	if (verbose)
+	    printf("%sno_long_link\n", indent);
+	break;
+#ifdef CISTPL_INDIRECT
+    case CISTPL_INDIRECT:
+	if (verbose)
+	    printf("%sindirect_access\n", indent);
+	break;
+#endif
+    case CISTPL_LINKTARGET:
+	if (verbose)
+	    printf("%slink_target\n", indent);
+	else {
+	    if (cur++) printf("%s}, {\n", indent+2);
+	}
+	break;
+    case CISTPL_VERS_1:
+	print_vers_1(&tup->parse.version_1);
+	break;
+    case CISTPL_ALTSTR:
+	break;
+    case CISTPL_JEDEC_A:
+    case CISTPL_JEDEC_C:
+	if (tup->tuple.TupleCode == CISTPL_JEDEC_C)
+	    printf("%scommon_jedec", indent);
+	else
+	    printf("%sattr_jedec", indent);
+	print_jedec(&tup->parse.jedec);
+	break;
+    case CISTPL_DEVICE_GEO:
+    case CISTPL_DEVICE_GEO_A:
+	if (tup->tuple.TupleCode == CISTPL_DEVICE_GEO)
+	    printf("%scommon_geometry\n", indent);
+	else
+	    printf("%sattr_geometry\n", indent);
+	print_device_geo(&tup->parse.device_geo);
+	break;
+    case CISTPL_MANFID:
+	printf("%smanfid 0x%4.4x, 0x%4.4x\n", indent,
+	       tup->parse.manfid.manf, tup->parse.manfid.card);
+	break;
+    case CISTPL_FUNCID:
+	print_funcid(&tup->parse.funcid);
+	func = tup->parse.funcid.func;
+	break;
+    case CISTPL_FUNCE:
+	switch (func) {
+	case CISTPL_FUNCID_SERIAL:
+	    print_serial(&tup->parse.funce);
+	    break;
+	case CISTPL_FUNCID_FIXED:
+	    print_fixed(&tup->parse.funce);
+	    break;
+	case CISTPL_FUNCID_NETWORK:
+	    print_network(&tup->parse.funce);
+	    break;
+	}
+	break;
+    case CISTPL_BAR:
+	printf("%sBAR %d size ", indent,
+	       tup->parse.bar.attr & CISTPL_BAR_SPACE);
+	print_size(tup->parse.bar.size);
+	if (tup->parse.bar.attr & CISTPL_BAR_SPACE_IO)
+	    printf(" [io]");
+	else
+	    printf(" [mem]");
+	if (tup->parse.bar.attr & CISTPL_BAR_PREFETCH)
+	    printf(" [prefetch]");
+	if (tup->parse.bar.attr & CISTPL_BAR_CACHEABLE)
+	    printf(" [cacheable]");
+	if (tup->parse.bar.attr & CISTPL_BAR_1MEG_MAP)
+	    printf(" [<1mb]");
+	putchar('\n');
+	break;
+    case CISTPL_CONFIG:
+    case CISTPL_CONFIG_CB:
+	print_config(tup->tuple.TupleCode, &tup->parse.config);
+	break;
+    case CISTPL_CFTABLE_ENTRY:
+	print_cftable_entry(&tup->parse.cftable_entry);
+	break;
+    case CISTPL_CFTABLE_ENTRY_CB:
+	print_cftable_entry_cb(&tup->parse.cftable_entry_cb);
+	break;
+    case CISTPL_VERS_2:
+	print_vers_2(&tup->parse.vers_2);
+	break;
+    case CISTPL_ORG:
+	print_org(&tup->parse.org);
+	break;
+    }
+}
+
+/*====================================================================*/
+
+static int get_tuple_buf(int fd, ds_ioctl_arg_t *arg, int first)
+{
+    u_int ofs;
+    static int nb = 0;
+    static u_char buf[1024];
+    
+    if (first) {
+	nb = read(fd, buf, sizeof(buf));
+	arg->tuple.TupleLink = arg->tuple.CISOffset = 0;
+    }
+    ofs = arg->tuple.CISOffset + arg->tuple.TupleLink;
+    if (ofs >= nb) return -1;
+    arg->tuple.TupleCode = buf[ofs++];
+    arg->tuple.TupleDataLen = arg->tuple.TupleLink = buf[ofs++];
+    arg->tuple.CISOffset = ofs;
+    memcpy(arg->tuple_parse.data, buf+ofs, arg->tuple.TupleLink);
+    return 0;
+}
+
+static int get_tuple(int fd, ds_ioctl_arg_t *arg, int first)
+{
+    int cmd = (first) ? DS_GET_FIRST_TUPLE : DS_GET_NEXT_TUPLE;
+    if (ioctl(fd, cmd, arg) != 0) {
+	if (errno == ENODEV)
+	    printf("%sno card\n", indent);
+	else if (errno != ENODATA)
+	    printf("%sget tuple: %s\n", indent, strerror(errno));
+	return -1;
+    }
+    if (ioctl(fd, DS_GET_TUPLE_DATA, arg) != 0) {
+	printf("%sget tuple data: %s\n", indent, strerror(errno));
+	return -1;
+    }
+    return 0;
+}
+
+/*====================================================================*/
+
+#define MAX_SOCKS 8
+
+int main(int argc, char *argv[])
+{
+    int i, fd, pfd;
+    ds_ioctl_arg_t arg;
+    int optch, errflg, first;
+    int force = 0;
+    char *infile = NULL;
+
+    errflg = 0;
+    while ((optch = getopt(argc, argv, "fvi:")) != -1) {
+	switch (optch) {
+	case 'f':
+	    force = 1; break;
+	case 'v':
+	    verbose = 1; break;
+	case 'i':
+	    infile = strdup(optarg); break;
+	default:
+	    errflg = 1; break;
+	}
+    }
+    if (errflg || (optind < argc)) {
+	fprintf(stderr, "usage: %s [-v] [-f] [-i infile]\n", argv[0]);
+	exit(EXIT_FAILURE);
+    }
+    
+#ifdef __linux__
+    major = lookup_dev("pcmcia");
+    if (major < 0) {
+	fprintf(stderr, "no pcmcia driver in /proc/devices\n");
+	exit(EXIT_FAILURE);
+    }
+#endif
+    
+    for (i = 0; (i < MAX_SOCKS) && !(i && infile); i++) {
+	nfn = cur = 0;
+	if (infile) {
+	    indent[0] = '\0';
+	    fd = open(infile, O_RDONLY);
+	    if (fd < 0) {
+		perror("open()");
+		return -1;
+	    }
+	    pfd = open_sock(0);
+	} else {
+	    strcpy(indent, "  ");
+	    fd = pfd = open_sock(i);
+	    if (fd < 0) break;
+	}
+	if (pfd < 0) {
+	    perror("open()");
+	    return -1;
+	}
+	if (!verbose && (i > 0)) putchar('\n');
+	if (!infile) printf("Socket %d:\n", i);
+	
+	if (!force && !infile) {
+	    if (ioctl(fd, DS_VALIDATE_CIS, &arg) != 0) {
+		printf("%svalidate CIS: %s\n", indent, strerror(errno));
+		continue;
+	    }
+	    if (arg.cisinfo.Chains == 0) {
+		printf("%sno CIS present\n", indent);
+		continue;
+	    }
+	}
+	
+	arg.tuple.TupleDataMax = sizeof(arg.tuple_parse.data);
+	arg.tuple.Attributes = TUPLE_RETURN_LINK | TUPLE_RETURN_COMMON;
+	arg.tuple.DesiredTuple = RETURN_FIRST_TUPLE;
+	arg.tuple.TupleOffset = 0;
+
+	for (first = 1; ; first = 0) {
+	    if (infile) {
+		if (get_tuple_buf(fd, &arg, first) != 0) break;
+	    } else {
+		if (get_tuple(fd, &arg, first) != 0) break;
+	    }
+	    if (verbose) print_tuple(&arg.tuple_parse);
+	    if (ioctl(pfd, DS_PARSE_TUPLE, &arg) == 0)
+		print_parse(&arg.tuple_parse);
+	    else if (errno != ENOSYS)
+		printf("%sparse error: %s\n", indent,
+		       strerror(errno));
+	    if (verbose) putchar('\n');
+	}
+	
+	if (!verbose && (nfn > 0))
+	    printf("%s}\n", indent+2);
+    }
+    
+    return 0;
+}
Index: oldkernel/linux/pcmcia-cs-3.1.15/debug-tools/dump_cisreg.c
diff -u /dev/null linux/pcmcia-cs-3.1.15/debug-tools/dump_cisreg.c:1.1
--- /dev/null	Mon Jul 31 21:15:10 2000
+++ linux/pcmcia-cs-3.1.15/debug-tools/dump_cisreg.c	Fri Jul  7 16:34:58 2000
@@ -0,0 +1,286 @@
+/*======================================================================
+
+    PCMCIA card configuration register dump
+
+    dump_cisreg.c 1.21 1999/10/25 20:23:27
+
+    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@pcmcia.sourceforge.org>.  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__
+#include <pcmcia/u_compat.h>
+#endif
+
+#include <sys/types.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <sys/time.h>
+#include <sys/ioctl.h>
+#include <sys/stat.h>
+
+#include <pcmcia/cs_types.h>
+#include <pcmcia/cs.h>
+#include <pcmcia/cistpl.h>
+#include <pcmcia/cisreg.h>
+#include <pcmcia/ds.h>
+
+/*====================================================================*/
+
+#ifdef __linux__
+
+static int major = 0;
+
+static int lookup_dev(char *name)
+{
+    FILE *f;
+    int n;
+    char s[32], t[32];
+    
+    f = fopen("/proc/devices", "r");
+    if (f == NULL)
+	return -1;
+    while (fgets(s, 32, f) != NULL) {
+	if (sscanf(s, "%d %s", &n, t) == 2)
+	    if (strcmp(name, t) == 0)
+		break;
+    }
+    fclose(f);
+    if (strcmp(name, t) == 0)
+	return n;
+    else
+	return -1;
+}
+
+#endif /* __linux__ */
+
+/*====================================================================*/
+
+static int open_sock(int sock)
+{
+#ifdef __linux__
+    int fd;
+    char *fn;
+    dev_t dev = (major<<8) + sock;
+    if ((fn = tmpnam(NULL)) == NULL)
+	return -1;
+    if (mknod(fn, (S_IFCHR|S_IREAD|S_IWRITE), dev) != 0)
+	return -1;
+    fd = open(fn, O_RDONLY);
+    unlink(fn);
+    return fd;
+#endif
+#ifdef __BEOS__
+    char fn[B_OS_NAME_LENGTH];
+    sprintf(fn, "/dev/pcmcia/sock%d", sock);
+    return open(fn, O_RDONLY);
+#endif
+} /* open_sock */
+
+/*====================================================================*/
+
+static int get_reg(int fd, int fn, off_t off)
+{
+    ds_ioctl_arg_t arg;
+    int ret;
+
+    arg.conf_reg.Function = fn;
+    arg.conf_reg.Action = CS_READ;
+    arg.conf_reg.Offset = off;
+    ret = ioctl(fd, DS_ACCESS_CONFIGURATION_REGISTER, &arg);
+    if (ret != 0) {
+	printf("  read config register: %s\n\n", strerror(errno));
+	return -1;
+    }
+    return arg.conf_reg.Value;
+}
+
+static int dump_option(int fd, int fn, int mfc)
+{
+    int v = get_reg(fd, fn, CISREG_COR);
+
+    if (v == -1) return -1;
+    printf("  Configuration option register = %#2.2x\n", v);
+    printf("   ");
+    if (v & COR_LEVEL_REQ) printf(" [level_req]");
+    if (v & COR_SOFT_RESET) printf(" [soft_reset]");
+    if (mfc) {
+	if (v & COR_FUNC_ENA) printf(" [func_ena]");
+	if (v & COR_ADDR_DECODE) printf(" [addr_decode]");
+	if (v & COR_IREQ_ENA) printf(" [ireq_ena]");
+	printf(" [index = %#2.2x]\n", v & COR_MFC_CONFIG_MASK);
+    } else
+	printf(" [index = %#2.2x]\n", v & COR_CONFIG_MASK);
+    return 0;
+}
+
+static void dump_status(int fd, int fn)
+{
+    int v = get_reg(fd, fn, CISREG_CCSR);
+    
+    printf("  Card configuration and status register = %#2.2x\n", v);
+    printf("   ");
+    if (v & CCSR_INTR_ACK) printf(" [intr_ack]");
+    if (v & CCSR_INTR_PENDING) printf(" [intr_pending]");
+    if (v & CCSR_POWER_DOWN) printf(" [power_down]");
+    if (v & CCSR_AUDIO_ENA) printf(" [audio]");
+    if (v & CCSR_IOIS8) printf(" [IOis8]");
+    if (v & CCSR_SIGCHG_ENA) printf(" [sigchg]");
+    if (v & CCSR_CHANGED) printf(" [changed]");
+    printf("\n");
+}
+
+static void dump_pin(int fd, int fn)
+{
+    int v = get_reg(fd, fn, CISREG_PRR);
+    
+    printf("  Pin replacement register = %#2.2x\n", v);
+    printf("   ");
+    if (v & PRR_WP_STATUS) printf(" [wp]");
+    if (v & PRR_READY_STATUS) printf(" [ready]");
+    if (v & PRR_BVD2_STATUS) printf(" [bvd2]");
+    if (v & PRR_BVD1_STATUS) printf(" [bvd1]");
+    if (v & PRR_WP_EVENT) printf(" [wp_event]");
+    if (v & PRR_READY_EVENT) printf(" [ready_event]");
+    if (v & PRR_BVD2_EVENT) printf(" [bvd2_event]");
+    if (v & PRR_BVD1_EVENT) printf(" [bvd1_event]");
+    printf("\n");
+}
+
+static void dump_copy(int fd, int fn)
+{
+    int v = get_reg(fd, fn, CISREG_SCR);
+    
+    printf("  Socket and copy register = %#2.2x\n", v);
+    printf("    [socket = %d] [copy = %d]\n",
+	   v & SCR_SOCKET_NUM,
+	   (v & SCR_COPY_NUM) >> 4);
+}
+
+static void dump_ext_status(int fd, int fn)
+{
+    int v = get_reg(fd, fn, CISREG_ESR);
+    printf("  Extended status register = %#2.2x\n", v);
+    printf("   ");
+    if (v & ESR_REQ_ATTN_ENA) printf(" [req_attn_ena]");
+    if (v & ESR_REQ_ATTN) printf(" [req_attn]");
+    printf("\n");
+}
+
+/*====================================================================*/
+
+static void dump_all(int fd, int fn, int mfc, u_int mask)
+{
+    int addr;
+    if (mask & PRESENT_OPTION) {
+	if (dump_option(fd, fn, mfc) != 0)
+	    return;
+    }
+    if (mask & PRESENT_STATUS)
+	dump_status(fd, fn);
+    if (mask & PRESENT_PIN_REPLACE)
+	dump_pin(fd, fn);
+    if (mask & PRESENT_COPY)
+	dump_copy(fd, fn);
+    if (mask & PRESENT_EXT_STATUS)
+	dump_ext_status(fd, fn);
+    if (mask & PRESENT_IOBASE_0) {
+	addr = get_reg(fd, fn, CISREG_IOBASE_0);
+	addr += get_reg(fd, fn, CISREG_IOBASE_1) << 8;
+	printf("  IO base = 0x%04x\n", addr);
+    }
+    if (mask & PRESENT_IOSIZE)
+	printf("  IO size = %d\n", get_reg(fd, fn, CISREG_IOSIZE));
+    if (mask == 0)
+	printf("  no config registers\n\n");
+    else
+	printf("\n");
+}
+
+/*====================================================================*/
+
+#define MAX_SOCKS 8
+
+int main(int argc, char *argv[])
+{
+    int i, j, nfn, fd, ret;
+    u_int mask;
+    ds_ioctl_arg_t arg;
+
+#ifdef __linux__
+    major = lookup_dev("pcmcia");
+    if (major < 0) {
+	fprintf(stderr, "no pcmcia driver in /proc/devices\n");
+	exit(EXIT_FAILURE);
+    }
+#endif
+    
+    for (i = 0; i < MAX_SOCKS; i++) {
+	fd = open_sock(i);
+	if (fd < 0) break;
+	
+	arg.tuple.TupleDataMax = sizeof(arg.tuple_parse.data);
+	arg.tuple.Attributes = TUPLE_RETURN_COMMON;
+	arg.tuple.DesiredTuple = CISTPL_LONGLINK_MFC;
+	arg.tuple.TupleOffset = 0;
+	if (ioctl(fd, DS_GET_FIRST_TUPLE, &arg) == 0) {
+	    ioctl(fd, DS_GET_TUPLE_DATA, &arg);
+	    ioctl(fd, DS_PARSE_TUPLE, &arg);
+	    nfn = arg.tuple_parse.parse.longlink_mfc.nfn;
+	} else {
+	    nfn = 1;
+	    arg.tuple.DesiredTuple = CISTPL_DEVICE;
+	    ret = ioctl(fd, DS_GET_FIRST_TUPLE, &arg);
+	    if (ret != 0) {
+		if (errno != ENODEV) perror("ioctl()");
+		continue;
+	    }
+	}
+
+	arg.tuple.DesiredTuple = CISTPL_CONFIG;
+	
+	for (j = 0; j < nfn; j++) {
+	    printf("Socket %d function %d:\n", i, j);
+	    if (ioctl(fd, DS_GET_NEXT_TUPLE, &arg) != 0) {
+		printf("  no config tuple: %s\n\n", strerror(errno));
+		continue;
+	    }
+	    ioctl(fd, DS_GET_TUPLE_DATA, &arg);
+	    ioctl(fd, DS_PARSE_TUPLE, &arg);
+	    printf("  Config register base = %#4.4x, mask = %#4.4x\n",
+		   arg.tuple_parse.parse.config.base,
+		   arg.tuple_parse.parse.config.rmask[0]);
+	    mask = arg.tuple_parse.parse.config.rmask[0];
+	    dump_all(fd, j, (nfn > 1), mask);
+	}
+    
+    }
+    return 0;
+}
Index: oldkernel/linux/pcmcia-cs-3.1.15/debug-tools/dump_exca.c
diff -u /dev/null linux/pcmcia-cs-3.1.15/debug-tools/dump_exca.c:1.1
--- /dev/null	Mon Jul 31 21:15:10 2000
+++ linux/pcmcia-cs-3.1.15/debug-tools/dump_exca.c	Fri Jul  7 16:34:58 2000
@@ -0,0 +1,550 @@
+/*======================================================================
+
+    Dump ExCA compatible PCMCIA bridge registers
+
+    dump_exca.c 1.2 2000/05/11 03:05: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@pcmcia.sourceforge.org>.  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 <sys/types.h>
+#include <string.h>
+#include <errno.h>
+#include <stdio.h>
+#include <unistd.h>
+#include <stdlib.h>
+
+#include "i82365.h"
+#include "cirrus.h"
+#include "vg468.h"
+#include "yenta.h"
+
+/*====================================================================*/
+
+typedef struct proc_exca {
+    union {
+	u_char	b[80];
+	u_short	w[40];
+    } reg;
+    u_char	ext[64];
+} proc_exca;
+
+#define IS_CIRRUS	0x01
+#define IS_VG468	0x02
+#define IS_VG469	0x04
+
+typedef struct proc_info {
+    char	type[32];
+    u_int	flags;
+    int		psock;
+    u_char	bus;
+    u_char	devfn;
+    u_char	cardbus;
+} proc_info;
+
+static proc_exca *load_exca(char *fn)
+{
+    FILE *f = fopen(fn, "r");
+    static proc_exca ex;
+    char s[50];
+    int i, j;
+    
+    if (!f) return NULL;
+    memset(&ex, 0, sizeof ex); 
+    for (i = 0; (i < 80) && !feof(f); i += 16) {
+	fgets(s, 49, f);
+	if (strlen(s) < 48) break;
+	for (j = 0; j < 16; j++)
+	    ex.reg.b[i+j] = strtoul(s + 3*j, NULL, 16);
+    }
+    for (i = 0; (i < 64) && !feof(f); i += 16) {
+	fgets(s, 49, f);
+	if (strlen(s) < 48) break;
+	for (j = 0; j < 16; j++)
+	    ex.ext[i+j] = strtoul(s + 3*j, NULL, 16);
+    }
+    fclose(f);
+    return &ex;
+}
+
+#define NTAG 5
+char *tag[] = { "type:", "psock:", "bus:", "devfn:", "cardbus:" };
+
+static proc_info *load_info(char *fn)
+{
+    FILE *f = fopen(fn, "r");
+    static proc_info in;
+    char s[50];
+    u_int i, a, b;
+    
+    if (!f) return NULL;
+    memset(&in, 0, sizeof in);
+    while (!feof(f)) {
+	fgets(s, 49, f);
+	for (i = 0; i < NTAG; i++)
+	    if (strncmp(s, tag[i], strlen(tag[i])) == 0) break;
+	switch (i) {
+	case 0: strcpy(in.type, s+10); break;
+	case 1: in.psock = strtoul(s+10, NULL, 10); break;
+	case 2: in.bus = strtoul(s+10, NULL, 16); break;
+	case 3:
+	    sscanf(s+10, "%02x.%d", &a, &b);
+	    in.devfn = (a<<3) | b;
+	    break;
+	case 4: in.cardbus = strtoul(s+10, NULL, 16);
+	}
+    }
+    if (strstr(in.type, "Cirrus"))
+	in.flags |= IS_CIRRUS;
+    if (strstr(in.type, "VG-468"))
+	in.flags |= IS_VG468;
+    if (strstr(in.type, "VG-469"))
+	in.flags |= IS_VG469;
+    fclose(f);
+    return &in;
+}
+
+/*====================================================================*/
+
+static void dump_status(proc_exca *ex)
+{
+    int v = ex->reg.b[I365_STATUS];
+    printf("  Interface status = 0x%02x\n   ", v);
+    if (v & I365_CS_BVD1) printf(" [bvd1/stschg]");
+    if (v & I365_CS_BVD2) printf(" [bvd2/spkr]");
+    if (v & I365_CS_DETECT) printf(" [detect]");
+    if (v & I365_CS_WRPROT) printf(" [wrprot]");
+    if (v & I365_CS_READY) printf(" [ready]");
+    if (v & I365_CS_POWERON) printf(" [poweron]");
+    if (v & I365_CS_GPI) printf(" [gpi]");
+    printf("\n");
+}
+
+static void dump_power(proc_exca *ex)
+{
+    int v = ex->reg.b[I365_POWER];
+    printf("  Power control = 0x%02x\n   ", v);
+    if (v & I365_PWR_OUT) printf(" [output]");
+    if (!(v & I365_PWR_NORESET)) printf(" [resetdrv]");
+    if (v & I365_PWR_AUTO) printf(" [auto]");
+    switch (v & I365_VCC_MASK) {
+    case I365_VCC_5V:
+	printf(" [Vcc=5v]"); break;
+    case I365_VCC_3V:
+	printf(" [Vcc=3.3v]"); break;
+    case 0:
+	printf(" [Vcc off]"); break;
+    }
+    switch (v & I365_VPP1_MASK) {
+    case I365_VPP1_5V:
+	printf(" [Vpp=5v]"); break;
+    case I365_VPP1_12V:
+	printf(" [Vpp=12v]"); break;
+    case 0:
+	printf(" [Vpp off]"); break;
+    }
+    printf("\n");
+}
+
+static void dump_intctl(proc_exca *ex)
+{
+    int v = ex->reg.b[I365_INTCTL];
+    printf("  Interrupt and general control = 0x%2x\n   ", v);
+    if (v & I365_RING_ENA) printf(" [ring ena]");
+    if (!(v & I365_PC_RESET)) printf(" [reset]");
+    if (v & I365_PC_IOCARD) printf(" [iocard]");
+    if (v & I365_INTR_ENA) printf(" [intr ena]");
+    printf(" [irq=%d]\n", v & I365_IRQ_MASK);
+}
+
+static void dump_csc(proc_exca *ex)
+{
+    int v = ex->reg.b[I365_CSC];
+    if (!v) return;
+    printf("  Card status change = 0x%02x\n   ", v);
+    if (v & I365_CSC_BVD1) printf(" [bvd1/stschg]");
+    if (v & I365_CSC_BVD2) printf(" [bvd2]");
+    if (v & I365_CSC_DETECT) printf(" [detect]");
+    if (v & I365_CSC_READY) printf(" [ready]");
+    if (v & I365_CSC_GPI) printf(" [gpi]");
+    printf("\n");
+}
+
+static void dump_cscint(proc_exca *ex)
+{
+    int v = ex->reg.b[I365_CSCINT];
+    printf("  Card status change interrupt control = 0x%02x\n", v);
+    printf("   ");
+    if (v & I365_CSC_BVD1) printf(" [bvd1/stschg]");
+    if (v & I365_CSC_BVD2) printf(" [bvd2]");
+    if (v & I365_CSC_DETECT) printf(" [detect]");
+    if (v & I365_CSC_READY) printf(" [ready]");
+    printf(" [irq=%d]\n", v >> 4);
+}
+
+static void dump_genctl(proc_exca *ex)
+{
+    int v = ex->reg.b[I365_GENCTL];
+    printf("  Card detect and general control = 0x%02x\n   ", v);
+    if (v & I365_CTL_16DELAY) printf(" [16delay]");
+    if (v & I365_CTL_RESET) printf(" [reset]");
+    if (v & I365_CTL_GPI_ENA) printf(" [gpi ena]");
+    if (v & I365_CTL_GPI_CTL) printf(" [gpi ctl]");
+    if (v & I365_CTL_RESUME) printf(" [resume]");
+    printf("\n");
+}
+
+static void dump_gblctl(proc_exca *ex)
+{
+    int v = ex->reg.b[I365_GBLCTL];
+    if (!v) return;
+    printf("  Global control = 0x%02x\n   ", v);
+    if (v & I365_GBL_PWRDOWN) printf(" [pwrdown]");
+    if (v & I365_GBL_CSC_LEV) printf(" [csc level]");
+    if (v & I365_GBL_WRBACK) printf(" [wrback]");
+    if (v & I365_GBL_IRQ_0_LEV) printf(" [irq A level]");
+    if (v & I365_GBL_IRQ_1_LEV) printf(" [irq B level]");
+    printf("\n");
+}
+
+/*====================================================================*/
+
+/* Cirrus-specific registers */
+
+static void dump_misc1(proc_exca *ex)
+{
+    int v = ex->reg.b[PD67_MISC_CTL_1];
+    printf("  Misc control 1 = 0x%02x\n   ", v);
+    if (v & PD67_MC1_5V_DET) printf(" [5v detect]");
+    if (v & PD67_MC1_VCC_3V) printf(" [Vcc 3.3v]");
+    if (v & PD67_MC1_PULSE_MGMT) printf(" [pulse mgmt]");
+    if (v & PD67_MC1_PULSE_IRQ) printf(" [pulse irq]");
+    if (v & PD67_MC1_SPKR_ENA) printf(" [spkr]");
+    if (v & PD67_MC1_INPACK_ENA) printf(" [inpack]");
+    printf("\n");
+}
+
+static void dump_misc2(proc_exca *ex)
+{
+    int v = ex->reg.b[PD67_MISC_CTL_2];
+    printf("  Misc control 2 = 0x%02x\n   ", v);
+    if (v & PD67_MC2_FREQ_BYPASS) printf(" [freq bypass]");
+    if (v & PD67_MC2_DYNAMIC_MODE) printf(" [dynamic mode]");
+    if (v & PD67_MC2_SUSPEND) printf(" [suspend]");
+    if (v & PD67_MC2_5V_CORE) printf(" [5v core]");
+    if (v & PD67_MC2_LED_ENA) printf(" [LED ena]");
+    if (v & PD67_MC2_3STATE_BIT7) printf(" [3state bit 7]");
+    if (v & PD67_MC2_DMA_MODE) printf(" [DMA mode]");
+    if (v & PD67_MC2_IRQ15_RI) printf(" [irq 15 is RI]");
+    printf("\n");
+}
+
+static void print_time(char *s, int v)
+{
+    printf("%s = %d", s, v & PD67_TIME_MULT);
+    switch (v & PD67_TIME_SCALE) {
+    case PD67_TIME_SCALE_16:
+	printf(" [*16]"); break;
+    case PD67_TIME_SCALE_256:
+	printf(" [*256]"); break;
+    case PD67_TIME_SCALE_4096:
+	printf(" [*4096]"); break;
+    }
+}
+
+static void dump_timing(proc_exca *ex, int i)
+{
+    printf("  Timing set %d: ", i);
+    print_time("setup", ex->reg.b[PD67_TIME_SETUP(i)]);
+    print_time(", command", ex->reg.b[PD67_TIME_CMD(i)]);
+    print_time(", recovery", ex->reg.b[PD67_TIME_RECOV(i)]);
+    printf("\n");
+}
+
+void dump_ext(proc_exca *ex)
+{
+    u_char v;
+    printf("  Extension registers:");
+    printf("    ");
+    v = ex->ext[PD67_DATA_MASK0];
+    printf("mask 0 = 0x%02x", v);
+    v = ex->reg.b[PD67_DATA_MASK1];
+    printf(", mask 1 = 0x%02x", v);
+    v = ex->reg.b[PD67_DMA_CTL];
+    printf(", DMA ctl = 0x%02x", v);
+    switch (v & PD67_DMA_MODE) {
+    case PD67_DMA_OFF:
+	printf(" [off]"); break;
+    case PD67_DMA_DREQ_INPACK:
+	printf(" [dreq is inpack]"); break;
+    case PD67_DMA_DREQ_WP:
+	printf(" [dreq is wp]"); break;
+    case PD67_DMA_DREQ_BVD2:
+	printf(" [dreq is bvd2]"); break;
+    }
+    if (v & PD67_DMA_PULLUP)
+	printf(" [pullup]");
+    printf("\n");
+}
+
+/*====================================================================*/
+
+/* Vadem-specific registers */
+
+static void dump_vsense(proc_exca *ex)
+{
+    int v = ex->reg.b[VG469_VSENSE];
+    printf("  Card voltage sense = 0x%02x\n   ", v);
+    if (v & VG469_VSENSE_A_VS1) printf(" [a_vs1]");
+    if (v & VG469_VSENSE_A_VS2) printf(" [a_vs2]");
+    if (v & VG469_VSENSE_B_VS1) printf(" [b_vs1]");
+    if (v & VG469_VSENSE_B_VS2) printf(" [b_vs2]");
+    printf("\n");
+}
+
+static void dump_vselect(proc_exca *ex)
+{
+    int v = ex->reg.b[VG469_VSELECT];
+    printf("  Card voltage select = 0x%02x\n   ", v);
+    switch (v & VG469_VSEL_VCC) {
+    case 0: printf(" [Vcc=5v]"); break;
+    case 1: printf(" [Vcc=3.3v]"); break;
+    case 2: printf(" [Vcc=X.Xv]"); break;
+    case 3: printf(" [Vcc=3.3v]"); break;
+    }
+    switch (v & VG469_VSEL_MAX) {
+    case 0: printf(" [Vmax=5v]"); break;
+    case 1: printf(" [Vmax=3.3v]"); break;
+    case 2: printf(" [Vmax=X.Xv]"); break;
+    case 3: printf(" [Vcc=3.3v]"); break;
+    }
+    if (v & VG469_VSEL_EXT_STAT) printf(" [extended]");
+    if (v & VG469_VSEL_EXT_BUS) printf(" [buffer]");
+    if (v & VG469_VSEL_MIXED)
+	printf(" [mixed]");
+    else
+	printf(" [5v only]");
+    if (v & VG469_VSEL_ISA)
+	printf(" [3v bus]");
+    else
+	printf(" [5v bus]");
+    printf("\n");
+}
+
+static void dump_control(proc_exca *ex)
+{
+    int v = ex->reg.b[VG468_CTL];
+    printf("  Control register = 0x%02x\n   ", v);
+    if (v & VG468_CTL_SLOW) printf(" [slow]");
+    if (v & VG468_CTL_ASYNC) printf(" [async]");
+    if (v & VG468_CTL_TSSI) printf(" [tri-state]");
+    if (v & VG468_CTL_DELAY) printf(" [debounce]");
+    if (v & VG469_CTL_STRETCH) printf(" [stretch]");
+    if (v & VG468_CTL_INPACK) printf(" [inpack]");
+    if (v & VG468_CTL_POLARITY)
+	printf(" [active high]");
+    else
+	printf(" [active low]");
+    if (v & VG468_CTL_COMPAT) printf(" [compat]");
+    printf("\n");
+}
+
+static void dump_misc(proc_exca *ex)
+{
+    int v = ex->reg.b[VG468_MISC];
+    printf("  Misc register = 0x%02x\n   ", v);
+    if (v & VG468_MISC_GPIO) printf(" [gpio]");
+    if (v & VG468_MISC_DMAWSB) printf(" [DMA ws]");
+    if (v & VG469_MISC_LEDENA) printf(" [LED ena]");
+    if (v & VG468_MISC_VADEMREV) printf(" [Vadem rev]");
+    if (v & VG468_MISC_UNLOCK) printf(" [unlock]");
+    printf("\n");
+}
+
+static void dump_ext_mode(proc_exca *ex, proc_info *in)
+{
+    int v = ex->reg.b[VG469_EXT_MODE];
+    printf("  Extended mode %c = 0x%02x\n   ",
+	   (in->psock ? 'B' : 'A'), v);
+    if (in->psock) {
+	if (v & VG469_MODE_B_3V) printf(" [3.3v sock B]");
+    } else {
+	if (v & VG469_MODE_INT_SENSE) printf(" [int sense]");
+	if (v & VG469_MODE_CABLE) printf(" [cable mode]");
+	if (v & VG469_MODE_COMPAT) printf(" [DF compat]");
+	if (v & VG469_MODE_TEST) printf(" [test]");
+	if (v & VG469_MODE_RIO) printf(" [RIO to INTR]");
+    }
+    printf("\n");
+}
+
+/*====================================================================*/
+
+static void dump_memwin(proc_exca *ex, proc_info *in, int w)
+{
+    u_int start, stop, off;
+    char flags[50];
+
+    start = ex->reg.w[(I365_MEM(w)+I365_W_START)>>1];
+    stop = ex->reg.w[(I365_MEM(w)+I365_W_STOP)>>1];
+    off = ex->reg.w[(I365_MEM(w)+I365_W_OFF)>>1];
+
+    if (ex->reg.b[I365_ADDRWIN] & I365_ENA_MEM(w))
+	strcpy(flags, " [on]");
+    else
+	strcpy(flags, " [off]");
+    if (start & I365_MEM_16BIT)
+	strcat(flags, " [16bit]");
+    else
+	strcat(flags, " [8bit]");
+    if (in->flags & IS_CIRRUS) {
+	if (stop & I365_MEM_WS1)
+	    strcat(flags, " [time1]");
+	else
+	    strcat(flags, " [time0]");
+    } else {
+	if (start & I365_MEM_0WS) strcat(flags, " [0ws]");
+	if (stop & I365_MEM_WS1) strcat(flags, " [ws1]");
+	if (stop & I365_MEM_WS0) strcat(flags, " [ws0]");
+    }
+    if (off & I365_MEM_WRPROT) strcat(flags, " [wrprot]");
+    if (off & I365_MEM_REG) strcat(flags, " [reg]");
+
+    start = (start & 0x0fff) << 12;
+    stop = ((stop & 0x0fff) << 12) + 0x0fff;
+    off = (off & 0x3fff) << 12;
+    start += ex->reg.b[CB_MEM_PAGE(w)]<<24;
+    stop += ex->reg.b[CB_MEM_PAGE(w)]<<24;
+    off = (off+start) & 0x3ffffff;
+    printf("  memory %d: 0x%04x-0x%04x @ 0x%08x%s\n",
+	   w, off, off+stop-start, start, flags);
+}
+
+static void dump_iowin(proc_exca *ex, proc_info *in, int w)
+{
+    u_short ctl, off = 0;
+    if (in->flags & IS_CIRRUS)
+	off = ex->reg.w[PD67_IO_OFF(w)>>1];
+    printf("  io %d: 0x%04x-0x%04x", w,
+	   off + ex->reg.w[(I365_IO(w)+I365_W_START)>>1],
+	   off + ex->reg.w[(I365_IO(w)+I365_W_STOP)>>1]);
+    if (off)
+	printf(" @ 0x%04x", ex->reg.w[(I365_IO(w)+I365_W_START)>>1]);
+
+    if (ex->reg.b[I365_ADDRWIN] & I365_ENA_IO(w))
+	printf(" [on]");
+    else
+	printf(" [off]");
+    
+    ctl = ex->reg.b[I365_IOCTL];
+    if (in->flags & IS_CIRRUS) {
+	if (ctl & I365_IOCTL_WAIT(w))
+	    printf(" [time1]");
+	else
+	    printf(" [time0]");
+    } else {
+	if (ctl & I365_IOCTL_WAIT(w)) printf(" [wait]");
+	if (ctl & I365_IOCTL_0WS(w)) printf(" [0ws]");
+    }
+    if (ctl & I365_IOCTL_IOCS16(w)) printf(" [iocs16]");
+    if (ctl & I365_IOCTL_16BIT(w))
+	printf(" [16bit]\n");
+    else
+	printf(" [8bit]\n");
+}
+
+/*====================================================================*/
+
+void dump_sock(proc_exca *ex, proc_info *in)
+{
+    int i;
+    printf("  Identification and revision = 0x%02x\n",
+	   ex->reg.b[I365_IDENT]);
+    if (in->flags & IS_CIRRUS)
+	printf("  Chip information = 0x%02x\n",
+	       ex->reg.b[PD67_CHIP_INFO]);
+    dump_status(ex);
+    dump_power(ex);
+    if (in->flags & IS_VG469)
+	dump_vselect(ex);
+    dump_intctl(ex);
+    dump_csc(ex);
+    dump_cscint(ex);
+
+    if (in->flags & IS_CIRRUS) {
+	dump_misc1(ex);
+	dump_misc2(ex);
+    } else {
+	dump_genctl(ex);
+	dump_gblctl(ex);
+    }
+
+    if (in->flags & IS_VG469) {
+	dump_vsense(ex);
+	dump_ext_mode(ex, in);
+    }
+    if ((in->flags & IS_VG468) || (in->flags & IS_VG469)) {
+	dump_control(ex);
+	dump_misc(ex);
+    }
+    
+    for (i = 0; i < 5; i++)
+	dump_memwin(ex, in, i);
+    for (i = 0; i < 2; i++)
+	dump_iowin(ex, in, i);
+    
+    if (in->flags & IS_CIRRUS) {
+	for (i = 0; i < 2; i++)
+	    dump_timing(ex, i);
+	dump_ext(ex);
+    }
+    printf("\n");
+} /* dump_sock */
+
+/*====================================================================*/
+
+int main(int argc, char *argv[])
+{
+    char fn[100];
+    int i;
+    proc_exca *ex;
+    proc_info *in;
+
+    if (access("/proc/bus/pccard", R_OK) != 0)
+	fprintf(stderr, "/proc/bus/pccard does not exist!\n");
+    for (i = 0; ; i++) {
+	sprintf(fn, "/proc/bus/pccard/%02d/exca", i);
+	if (access(fn, R_OK) != 0)
+	    break;
+	ex = load_exca(fn);
+	sprintf(fn, "/proc/bus/pccard/%02d/info", i);
+	in = load_info(fn);
+	printf("Socket %d:\n", i);
+	dump_sock(ex, in);
+    }
+    return 0;
+}
Index: oldkernel/linux/pcmcia-cs-3.1.15/debug-tools/dump_pirq
diff -u /dev/null linux/pcmcia-cs-3.1.15/debug-tools/dump_pirq:1.1
--- /dev/null	Mon Jul 31 21:15:10 2000
+++ linux/pcmcia-cs-3.1.15/debug-tools/dump_pirq	Fri Jul  7 16:34:58 2000
@@ -0,0 +1,238 @@
+#!/usr/bin/perl
+#
+# dump_pirq 1.11 2000/05/14 04:32:43
+#
+# A utility to parse the BIOS PCI IRQ Routing Table
+#
+# Copyright (C) 2000 David A. Hinds -- dhinds@pcmcia.sourceforge.org
+#
+
+#-----------------------------------------------------------------------
+
+sub dev {
+    my($devfn) = @_;
+    sprintf "%02x.%d", ($devfn>>3), ($devfn&7);
+}
+
+sub row {
+    my($tag, $link, $mask) = @_;
+    if ($link != 0) {
+	printf "  INT$tag: link 0x%02x, irq mask 0x%04x\n", $link, $mask;
+    }
+}
+
+sub parse_pirq
+{
+    my($buf) = @_;
+
+    my($p) = index($buf, "\$PIR");
+    my($minor,$major,$size,$rbus,$rdev,$mask,$cvd,$mini) =
+	unpack "CCSCCSLL", substr($buf, $p+4, 16);
+
+    printf "Interrupt routing table found at address 0xf%04x:\n", $p;
+    printf "  Version $major.$minor, size 0x%04x\n", $size;
+    printf "  Interrupt router is device %02x:%s\n", $rbus, dev($rdev);
+    printf "  PCI exclusive interrupt mask: 0x%04x\n", $mask;
+    if ($cvd) {
+	printf("  Compatible router: vendor 0x%04x device 0x%04x\n",
+	       ($cvd & 0xffff), ($cvd >> 16));
+    }
+
+    $ofs = 32;
+    while ($ofs < $size) {
+	# Parse a table entry describing a single PCI device
+	($bus, $devfn, $la, $ma, $lb, $mb, $lc, $mc, $ld, $md, $slot) =
+	    unpack "CCCSCSCSCSC", substr($buf, $p+$ofs, 15);
+	printf "\nDevice %02x:%s (slot $slot):\n", $bus, dev($devfn);
+	row("A", $la, $ma); row("B", $lb, $mb);
+	row("C", $lc, $mc); row("D", $ld, $md);
+	$ofs += 16;
+    }
+    return ($rbus, $rdev, $cvd);
+}
+
+#-----------------------------------------------------------------------
+
+# The link values in the interrupt routing table are implementation
+# dependent.  Here, we'll try to interpret the link values for some
+# known PCI bridge types.
+
+%pIIx = (0x122e8086, "82371FB PIIX",
+	 0x70008086, "82371SB PIIX3",
+	 0x71108086, "82371AB PIIX4/PIIX4E",
+	 0x71988086, "82440MX");
+
+%via = (0x05861106, "82C586",
+	0x05961106, "82C596",
+	0x06861106, "82C686");
+
+%opti = (0xc7001045, "82C700");
+
+%pico = (0x00021066, "PT86C523");
+
+%ali = (0x153310b9, "Aladdin M1533");
+
+%sis = (0x04961039, "85C496/497",
+	0x00081039, "85C503");
+
+%all_routers = (%pIIx, %via, %opti, %pico, %ali, %sis);
+
+sub outb
+{
+    my($data,$port) = @_;
+    open(IO, ">/dev/port") || die;
+    sysseek(IO, $port, 0) || die;
+    my $x = pack "C", $data;
+    syswrite(IO, $x, 1);
+    close(IO);
+}
+
+sub inb
+{
+    my($port) = @_;
+    my($data);
+    open(IO, "/dev/port") || die;
+    sysseek(IO, $port, 0) || die;
+    sysread(IO, $data, 1);
+    close(IO);
+    return unpack "C", $data;
+}
+
+sub dump_router
+{
+    my($rbus, $rdev, $cvd) = @_;
+    my($buf, @p, $i, $irq);
+
+    printf "\nInterrupt router at %02x:%s: ", $rbus, dev($rdev);
+    $rf = sprintf "/proc/bus/pci/%02x/%s", $rbus, dev($rdev);
+    open(IN, $rf);
+    if (sysread(IN, $buf, 0x100) != 0x100) {
+	print "\nCould not read router info from $rf.\n";
+	exit;
+    }
+    close(IN);
+    my $vd = unpack "L", substr($buf, 0, 4);
+
+    if ((defined $pIIx{$vd}) || (defined $pIIx{$cvd})) {
+
+	$name = (defined $pIIx{$vd}) ? $pIIx{$vd} : $pIIx{$cvd};
+	printf "Intel $name PCI-to-ISA bridge\n";
+	@p = unpack "CCCCC", substr($buf, 0x60, 5);
+	for ($i = 0; $i < 4; $i++) {
+	    printf "  PIRQ%d (link 0x%02x): ", $i+1, 0x60+$i;
+	    print (($p[$i] < 16) ? "irq $p[$i]\n" : "unrouted\n");
+	}
+	print "  Serial IRQ:";
+	print (($p[4] & 0x80) ? " [enabled]" : " [disabled]");
+	print (($p[4] & 0x40) ? " [continuous]" : " [quiet]");
+	print " [frame=", (($p[4] >> 2) & 15) + 17, "]";
+	print " [pulse=", (($p[4] & 3) * 4 + 4), "]\n";
+
+    } elsif ((defined $via{$vd}) || (defined $via{$cvd})) {
+
+	$name = (defined $via{$vd}) ? $via{$vd} : $via{$cvd};
+	printf "VIA $name PCI-to-ISA bridge\n";
+	$p = unpack "L", substr($buf, 0x55, 4);
+	%tag = (1, "A", 2, "B", 3, "C", 5, "D");
+	foreach $link (1,2,3,5) {
+	    $irq = ($p >> ($link * 4)) & 15;
+	    print "  PIRQ$tag{$link} (link 0x0$link): ";
+	    print ($irq ? "irq $irq\n" : "unrouted\n");
+	}
+
+    } elsif ((defined $opti{$vd}) || (defined $opti{$cvd})) {
+
+	$name = (defined $opti{$vd}) ? $opti{$vd} : $opti{$cvd};
+	printf "OPTi $name PCI-to-ISA bridge\n";
+	$p = unpack "S", substr($buf, 0xb8, 2);
+	for ($i = 0; $i < 4; $i++) {
+	    $irq = ($p >> ($i * 4)) & 15;
+	    printf "  PCIRQ$i (link 0x%02x): ", ($i<<4)+0x02;
+	    print ($irq ? "irq $irq\n" : "unrouted\n");
+	}
+
+    } elsif ((defined $pico{$vd} || defined $pico{$cvd})) {
+
+	$name = (defined $pico{$vd}) ? $pico{$vd} : $pico{$cvd};
+	printf "PicoPower $name PCI-to-ISA bridge\n";
+	outb(0x10, 0x24); $p = inb(0x26);
+	outb(0x11, 0x24); $p += inb(0x26)<<8;
+	@tag = ("A", "B", "C", "D");
+	for ($i = 0; $i < 4; $i++) {
+	    $irq = ($p >> ($i * 4)) & 15;
+	    print "  INT$tag[$i] (link 0x0", $i+1, "): ";
+	    print ($irq ? "irq $irq\n" : "unrouted\n");
+	}
+
+    } elsif ((defined $ali{$vd} || defined $ali{$cvd})) {
+
+	$name = (defined $ali{$vd}) ? $ali{$vd} : $ali{$cvd};
+	printf "AcerLabs $name PCI-to-ISA bridge\n";
+	$p = unpack "L", substr($buf, 0x48, 4);
+	# This mapping is insane!
+	@map = (0, 9, 3, 10, 4, 5, 7, 6, 1, 11, 0, 12, 0, 14, 0, 15);
+	for ($i = 0; $i < 8; $i++) {
+	    $irq = ($p >> ($i*4)) & 15;
+	    print "  INT", $i+1, " (link ", $i+1, "): ";
+	    print ($map[$irq] ? "irq $map[$irq]\n" : "unrouted\n");
+	}
+	$s = unpack "C", substr($buf, 0x70, 1);
+	print "  Serial IRQ:";
+	print (($s & 0x80) ? " [enabled]" : " [disabled]");
+	print (($s & 0x40) ? " [continuous]" : " [quiet]");
+	print " [frame=", (($s >> 2) & 15) + 17, "]";
+	print " [pulse=", (($s & 3) * 4 + 4), "]\n";
+
+    } elsif ((defined $sis{$vd}) || (defined $sis{$cvd})) {
+
+	$name = (defined $sis{$vd}) ? $sis{$vd} : $sis{$cvd};
+	printf "SiS $name PCI-to-ISA bridge\n";
+	$base = ($name eq "85C496/497") ? 0xc0 : 0x41;
+	@p = unpack "CCCC", substr($buf, $base, 4);
+	@tag = ("A", "B", "C", "D");
+	for ($i = 0; $i < 4; $i++) {
+	    $irq = ($p[$i] & 0x80) ? 0 : ($p[$i] & 0x0f);
+	    print "  INT$tag[$i] (link ???): ";
+	    print ($irq ? "irq $irq\n" : "unrouted\n");
+	}
+
+    } else {
+
+	printf("unknown vendor 0x%04x device 0x%04x\n",
+	       ($vd & 0xffff), ($vd >> 16));
+
+    }
+
+}
+
+#-----------------------------------------------------------------------
+
+# Grab the BIOS from 0xf0000-0xfffff
+open(IN, "/dev/mem") || die "cannot open /dev/mem\n";
+sysseek(IN, 0xf0000, 0) || die;
+die if (sysread(IN, $buf, 0x10000) != 0x10000);
+close(IN);
+
+if (index($buf, "\$PIR") >= 0) {
+
+    # Dump the PIRQ table, and the router information
+    ($rbus, $rdev, $cvd) = parse_pirq($buf);
+    dump_router($rbus, $rdev, $cvd);
+
+} else {
+
+    # Scan for any interrupt router device we recognize
+    print "No PCI interrupt routing table was found.\n";
+    open(DEV, "/proc/bus/pci/devices");
+    while (<DEV>) {
+	($rbus,$rdev,$vd) = /^(..)(..)\s+(........)/;
+	$rbus = hex($rbus); $rdev = hex($rdev); $vd = hex($vd);
+	$vd = (($vd & 0xffff0000) >> 16) | (($vd & 0xffff) << 16);
+	if (defined $all_routers{$vd}) {
+	    dump_router($rbus, $rdev, $vd);
+	    $nr++;
+	}
+    }
+    print "\nNo known PCI interrupt routers were found.\n" if (!$nr);
+
+}
Index: oldkernel/linux/pcmcia-cs-3.1.15/debug-tools/dump_tcic.c
diff -u /dev/null linux/pcmcia-cs-3.1.15/debug-tools/dump_tcic.c:1.1
--- /dev/null	Mon Jul 31 21:15:10 2000
+++ linux/pcmcia-cs-3.1.15/debug-tools/dump_tcic.c	Fri Jul  7 16:34:58 2000
@@ -0,0 +1,480 @@
+/*======================================================================
+
+    Register dump for the Databook TCIC-2 controller family
+
+    dump_tcic.c 1.20 1999/10/25 19:57: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@pcmcia.sourceforge.org>.  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 <string.h>
+#include <errno.h>
+#include <stdio.h>
+
+#ifdef __MSDOS__
+
+#include <dos.h>
+typedef unsigned char u_char;
+typedef unsigned short u_short;
+#define INB(a) inportb(a)
+#define OUTB(d, a) outportb(a, d)
+#define INW(a) inport(a)
+#define OUTW(d, a) outport(a, d)
+
+#else /* __MSDOS__ */
+
+#include <sys/types.h>
+#ifdef __GLIBC__
+#include <sys/io.h>
+#else
+#include <asm/io.h>
+#endif
+#include <unistd.h>
+#define INB(a) inb(a)
+#define OUTB(d, a) outb(d, a)
+#define INW(a) inw(a)
+#define OUTW(d, a) outw(d, a)
+
+#endif /* __MSDOS__ */
+
+#include "tcic.h"
+
+/*====================================================================*/
+
+static int tcic_base = TCIC_BASE;
+
+#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)
+
+static void tcic_setl(u_char reg, u_long data)
+{
+    OUTW(data & 0xffff, tcic_base+reg);
+    OUTW(data >> 16, tcic_base+reg+2);
+}
+
+#if 0
+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);
+}
+#endif
+
+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);
+}
+
+/*====================================================================*/
+
+int tcic_probe(void)
+{
+    int sock;
+
+    printf("Databook TCIC-2 probe: ");
+    sock = 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)
+	printf("not found.\n");
+    else
+	printf("%d sockets\n", sock);
+    
+    return sock;
+} /* tcic_probe */
+
+/*====================================================================*/
+
+void dump_sctrl(int ns)
+{
+    u_char v;
+    tcic_setl(TCIC_ADDR, (0 << TCIC_ADDR_SS_SHFT));
+    v = tcic_getb(TCIC_SCTRL);
+    printf("  Socket control = %#2.2x\n", v);
+    printf("   ");
+    if (v & TCIC_SCTRL_RESET) printf(" [RESET]");
+    if (v & TCIC_SCTRL_EDCSUM) printf(" [EDCSUM]");
+    switch (v & TCIC_SCTRL_INCMODE) {
+    case TCIC_SCTRL_INCMODE_HOLD:
+	printf(" [BYTE HOLD]"); break;
+    case TCIC_SCTRL_INCMODE_WORD:
+	printf(" [WORD HOLD]"); break;
+    case TCIC_SCTRL_INCMODE_REG:
+	printf(" [WORD INC]"); break;
+    case TCIC_SCTRL_INCMODE_AUTO:
+	printf(" [AUTO INC]"); break;
+    }
+    if (v & TCIC_SCTRL_ENA) printf(" [ENA]");
+    printf("\n");
+}
+
+void dump_sstat(int s)
+{
+    u_char v;
+    tcic_setl(TCIC_ADDR, (s << TCIC_ADDR_SS_SHFT));
+    v = tcic_getb(TCIC_SSTAT);
+    printf("  Socket status = %#2.2x\n", v);
+    printf("   ");
+    if (v & TCIC_SSTAT_CD) printf(" [CD]");
+    if (v & TCIC_SSTAT_WP) printf(" [WP]");
+    if (v & TCIC_SSTAT_RDY) printf(" [RDY]");
+    if (v & TCIC_SSTAT_LBAT1) printf(" [LBAT1]");
+    if (v & TCIC_SSTAT_LBAT2) printf(" [LBAT2]");
+    if (v & TCIC_SSTAT_PROGTIME) printf(" [PROGTIME]");
+    if (v & TCIC_SSTAT_10US) printf(" [10us]");
+    if (v & TCIC_SSTAT_6US) printf(" [6us]");
+    printf("\n");
+}
+
+void dump_mode(int s)
+{
+    u_char v;
+    tcic_setl(TCIC_ADDR, (s << TCIC_ADDR_SS_SHFT));
+    v = tcic_getb(TCIC_MODE);
+    printf("  Mode register = %#2.2x\n", v);
+    printf("   ");
+    if ((v & TCIC_MODE_PGMMASK) == 0)
+	printf(" [NORMAL]");
+    else {
+	if (v & TCIC_MODE_PGMWORD) printf(" [WORD]");
+	if (v & TCIC_MODE_PGMDBW) printf(" [DBW]");
+	if (v & TCIC_MODE_PGMCE) printf(" [CE]");
+	if (v & TCIC_MODE_PGMRD) printf(" [RD]");
+	if (v & TCIC_MODE_PGMWR) printf(" [WR]");
+    }
+    printf("\n");
+}
+
+void dump_pwr(int s)
+{
+    u_char v = tcic_getb(TCIC_PWR);
+    printf("  Power control = %#2.2x\n", v);
+    printf("   ");
+    
+    if (v & TCIC_PWR_CLIMSTAT) printf(" [CLIMSTAT]");
+    if (v & TCIC_PWR_CLIMENA) printf(" [CLIMENA]");
+    if (v & TCIC_PWR_VCC(s)) {
+	if (v & TCIC_PWR_VPP(s))
+	    printf(" [Vcc=5V] [Vpp OFF]");
+	else
+	    printf(" [Vcc=5V] [Vpp=5V]");
+    }
+    else {
+	if (v & TCIC_PWR_VPP(s))
+	    printf(" [Vcc=5V] [Vpp=12V]");
+	else
+	    printf(" [Vcc OFF] [Vpp OFF]");
+    }
+    printf("\n");
+}
+
+void dump_icsr(int s)
+{
+    u_char v;
+    tcic_setl(TCIC_ADDR, (s << TCIC_ADDR_SS_SHFT));
+    v = tcic_getb(TCIC_ICSR);
+    printf("  Interrupt control/status = %#2.2x\n", v);
+    printf("   ");
+    if (v & TCIC_ICSR_IOCHK) printf(" [IOCHK]");
+    if (v & TCIC_ICSR_CDCHG) printf(" [CDCHG]");
+    if (v & TCIC_ICSR_ERR) printf(" [ERR]");
+    if (v & TCIC_ICSR_PROGTIME) printf(" [PROGTIME]");
+    if (v & TCIC_ICSR_ILOCK) printf(" [ILOCK]");
+    if (v & TCIC_ICSR_STOPCPU) printf(" [STOPCPU]");
+    printf("\n");
+}
+
+void dump_iena(int s)
+{
+    u_char v;
+    tcic_setl(TCIC_ADDR, (s << TCIC_ADDR_SS_SHFT));
+    v = tcic_getb(TCIC_IENA);
+    printf("  Interrupt enable = %#2.2x\n", v);
+    printf("   ");
+    switch (v & TCIC_IENA_CFG_MASK) {
+    case TCIC_IENA_CFG_OFF:
+	printf(" [OFF]"); break;
+    case TCIC_IENA_CFG_OD:
+	printf(" [OD]"); break;
+    case TCIC_IENA_CFG_LOW:
+	printf(" [LOW]"); break;
+    case TCIC_IENA_CFG_HIGH:
+	printf(" [HIGH]"); break;
+    }
+    if (v & TCIC_IENA_ILOCK) printf(" [ILOCK]");
+    if (v & TCIC_IENA_PROGTIME) printf(" [PROGTIME]");
+    if (v & TCIC_IENA_ERR) printf(" [ERR]");
+    if (v & TCIC_IENA_CDCHG) printf(" [CDCHG]");
+    printf("\n");
+}
+
+void dump_wctl(int s)
+{
+    u_short v;
+    tcic_setl(TCIC_ADDR, (s << TCIC_ADDR_SS_SHFT));
+    v = tcic_aux_getw(TCIC_AUX_WCTL);
+    printf("  Wait control = %#4.4x\n", v);
+    printf("   ");
+    if (v & TCIC_WCTL_LCD) printf(" [LCD]");
+    if (v & TCIC_WCTL_LWP) printf(" [LWP]");
+    if (v & TCIC_WCTL_LRDY) printf(" [LRDY]");
+    if (v & TCIC_WCTL_LLBAT1) printf(" [LLBAT1]");
+    if (v & TCIC_WCTL_CE) printf(" [CE]");
+    if (v & TCIC_WCTL_RD) printf(" [RD]");
+    if (v & TCIC_WCTL_WR) printf(" [WR]");
+    if (v & TCIC_WAIT_SRC) printf(" [SRC]");
+    if (v & TCIC_WAIT_SENSE) printf(" [SENSE]");
+    if (v & TCIC_WAIT_ASYNC) printf(" [ASYNC]");
+    printf(" [COUNT=%d]\n", v & TCIC_WAIT_COUNT_MASK);
+}
+
+void dump_syscfg(void)
+{
+    u_short v = tcic_aux_getw(TCIC_AUX_SYSCFG);
+    printf("  System configuration = %#4.4x\n", v);
+    printf("   ");
+    if (v & TCIC_SYSCFG_ACC) printf(" [ACC]");
+    if (v & TCIC_SYSCFG_AUTOBUSY) printf(" [AUTOBUSY]");
+    if (v & TCIC_SYSCFG_MPSENSE) printf(" [MPSENSE]");
+    switch ((v & TCIC_SYSCFG_MPSEL_MASK) >> TCIC_SYSCFG_MPSEL_SHFT) {
+    case 0:
+	printf(" [/MULTI OFF]"); break;
+    case 1:
+	printf(" [/MULTI CLOCK]"); break;
+    case 2:
+	printf(" [/MULTI INPUT]"); break;
+    case 3:
+	printf(" [/MULTI OUTPUT]"); break;
+    case 5:
+	printf(" [/MULTI RI]"); break;
+    }
+    if (v & TCIC_SYSCFG_NOPDN) printf(" [NOPDN]");
+    if (v & TCIC_SYSCFG_ICSXB) printf(" [ICSXB]");
+    if (v & TCIC_SYSCFG_MCSXB) printf(" [MCSXB]");
+    if (v & TCIC_SYSCFG_IO1723) printf(" [IO1723]");
+    if (v & TCIC_SYSCFG_MCSFULL) printf(" [MCSFULL]");
+    switch (v & TCIC_SYSCFG_IRQ_MASK) {
+    case 0:
+    case 1:
+	printf(" [SKTIRQ]\n");
+	break;
+    case 3: case 4: case 5: case 6:
+    case 7: case 10: case 14:
+	printf(" [irq = %d]\n", v & TCIC_SYSCFG_IRQ_MASK);
+	break;
+    default:
+	printf(" [bad irq]\n");
+	break;
+    }
+}
+
+void dump_scf1(int s)
+{
+    u_short v;
+    tcic_setl(TCIC_ADDR, (s << TCIC_ADDR_SS_SHFT)
+	      | TCIC_ADDR_INDREG | TCIC_SCF1(s));
+    v = tcic_getw(TCIC_DATA);
+    printf("  Socket config register 1: %#4.4x\n", v);
+    printf("   ");
+    if (v & TCIC_SCF1_HD7IDE) printf(" [HD7IDE]");
+    if (v & TCIC_SCF1_DELWR) printf(" [DELWR]");
+    if (v & TCIC_SCF1_FINPACK) printf(" [FINPACK]");
+    if (v & TCIC_SCF1_SPKR) printf(" [SPKR]");
+    if (v & TCIC_SCF1_IOSTS) printf(" [IOSTS]");
+    switch ((v & TCIC_SCF1_DMA_MASK) >> TCIC_SCF1_DMA_SHIFT) {
+    case TCIC_SCF1_DMA_OFF:
+	printf(" [DMA OFF]"); break;
+    case TCIC_SCF1_DREQ2:
+	printf(" [DMA REQ2]"); break;
+    }
+    if (v & TCIC_SCF1_ATA) printf(" [ATA]");
+    if (v & TCIC_SCF1_IRDY) printf(" [IRDY]");
+    if (v & TCIC_SCF1_PCVT) printf(" [PCVT]");
+    if (v & TCIC_SCF1_IRQOC) printf(" [IRQOC]");
+    switch (v & TCIC_SCF1_IRQ_MASK) {
+    case 0:
+	printf(" [irq off]\n");
+    case 1:
+	printf(" [SKTIRQ]\n");
+	break;
+    case 3: case 4: case 5: case 6:
+    case 7: case 10: case 14:
+	printf(" [irq = %d]\n", v & TCIC_SCF1_IRQ_MASK);
+	break;
+    default:
+	printf(" [bad irq]\n");
+	break;
+    }
+}
+
+void dump_scf2(int s)
+{
+    u_short v;
+    tcic_setl(TCIC_ADDR, (s << TCIC_ADDR_SS_SHFT)
+	      | TCIC_ADDR_INDREG | TCIC_SCF2(s));
+    v = tcic_getw(TCIC_DATA);
+    printf("  Socket config register 2: %#4.4x\n", v);
+    printf("   ");
+    if (v & TCIC_SCF2_RI) printf(" [RI]");
+    if (v & TCIC_SCF2_IDBR) printf(" [IDBR]");
+    if (v & TCIC_SCF2_MDBR) printf(" [MDBR]");
+    if (v & TCIC_SCF2_MLBAT1) printf(" [MLBAT1]");
+    if (v & TCIC_SCF2_MLBAT2) printf(" [MLBAT2]");
+    if (v & TCIC_SCF2_MRDY) printf(" [MRDY]");
+    if (v & TCIC_SCF2_MWP) printf(" [MWP]");
+    if (v & TCIC_SCF2_MCD) printf(" [MCD]");
+    printf("\n");
+}
+
+/*====================================================================*/
+
+void dump_memwin(int w)
+{
+    u_short base, mmap, ctl;
+
+    tcic_setw(TCIC_ADDR+2, TCIC_ADR2_INDREG);
+    tcic_setw(TCIC_ADDR, TCIC_MWIN(0, w) + TCIC_MCTL_X);
+    ctl = tcic_getw(TCIC_DATA);
+    tcic_setw(TCIC_ADDR, TCIC_MWIN(0, w) + TCIC_MBASE_X);
+    base = tcic_getw(TCIC_DATA);
+    tcic_setw(TCIC_ADDR, TCIC_MWIN(0, w) + TCIC_MMAP_X);
+    mmap = tcic_getw(TCIC_DATA);
+    
+    printf("  Memory window %d: base = %#4.4x, mmap = %#4.4x, "
+	   "ctl = %#4.4x\n", w, base, mmap, ctl);
+    printf("    [SOCK=%d]",
+	   (ctl & TCIC_MCTL_SS_MASK) >> TCIC_MCTL_SS_SHFT);
+    printf(ctl & TCIC_MCTL_ENA ? " [ON]" : " [OFF]");
+    printf(ctl & TCIC_MCTL_B8 ? " [8 Bit]" : " [16 Bit]");
+    if (ctl & TCIC_MCTL_QUIET) printf(" [QUIET]");
+    if (ctl & TCIC_MCTL_WP) printf(" [WP]");
+    if (ctl & TCIC_MCTL_ACC) printf(" [ACC]");
+    if (ctl & TCIC_MCTL_KE) printf(" [KE]");
+    if (ctl & TCIC_MCTL_EDC) printf(" [EDC]");
+    printf(ctl & TCIC_MCTL_WCLK ? " [BCLK]" : " [CCLK]");
+    printf(" [ws = %d]", ctl & TCIC_MCTL_WSCNT_MASK);
+    if (base & TCIC_MBASE_4K_BIT) printf(" [4K]");
+    if (mmap & TCIC_MMAP_REG) printf(" [REG]");
+    printf("\n");
+}
+
+void dump_iowin(int w)
+{
+    u_short base, ctl;
+
+    tcic_setw(TCIC_ADDR+2, TCIC_ADR2_INDREG);
+    tcic_setw(TCIC_ADDR, TCIC_IWIN(0, w) + TCIC_IBASE_X);
+    base = tcic_getw(TCIC_DATA);
+    tcic_setw(TCIC_ADDR, TCIC_IWIN(0, w) + TCIC_ICTL_X);
+    ctl = tcic_getw(TCIC_DATA);
+    
+    printf("  IO window %d: base = %#4.4x, ctl = %#4.4x\n",
+	   w, base, ctl);
+    printf("    [SOCK=%d]",
+	   (ctl & TCIC_ICTL_SS_MASK) >> TCIC_ICTL_SS_SHFT);
+    printf(ctl & TCIC_ICTL_ENA ? " [ON]" : " [OFF]");
+    if (ctl & TCIC_ICTL_1K) printf(" [1K]");
+    if (ctl & TCIC_ICTL_QUIET) printf(" [QUIET]");
+    if (ctl & TCIC_ICTL_PASS16) printf(" [PASS16]");
+    if (ctl & TCIC_ICTL_ACC) printf(" [ACC]");
+    if (ctl & TCIC_ICTL_TINY) printf(" [TINY]");
+    switch (ctl & TCIC_ICTL_BW_MASK) {
+    case TCIC_ICTL_BW_DYN:
+	printf(" [BW_DYN]"); break;
+    case TCIC_ICTL_BW_8:
+	printf(" [BW_8]"); break;
+    case TCIC_ICTL_BW_16:
+	printf(" [BW_16]"); break;
+    case TCIC_ICTL_BW_ATA:
+	printf(" [BW_ATA]"); break;
+    }
+    printf(" [ws = %d]\n", ctl & TCIC_ICTL_WSCNT_MASK);
+}
+
+/*====================================================================*/
+
+void dump_global(void)
+{
+    dump_syscfg();
+    printf("\n");
+}
+
+void dump_sock(int s)
+{
+    dump_sctrl(s);
+    dump_sstat(s);
+    dump_mode(s);
+    dump_pwr(s);
+    dump_icsr(s);
+    dump_iena(s);
+    dump_scf1(s);
+    dump_scf2(s);
+    dump_wctl(s);
+    printf("\n");
+}
+
+void dump_windows(void)
+{
+    int i;
+    for (i = 0; i < 8; i++)
+	dump_memwin(i);
+    for (i = 0; i < 4; i++)
+	dump_iowin(i);
+}
+
+/*====================================================================*/
+
+int main(int argc, char *argv[])
+{
+    int sock, i;
+    
+#ifndef __MSDOS__
+    ioperm(tcic_base, 16, 1);
+    ioperm(0x80, 1, 1);
+#endif
+    
+    sock = tcic_probe();
+    if (sock == 0)
+	exit(1);
+    dump_global();
+    for (i = 0; i < sock; i++) {
+	printf("Socket %d:\n", i);
+	dump_sock(i);
+    }
+    dump_windows();
+    return 0;
+}
Index: oldkernel/linux/pcmcia-cs-3.1.15/debug-tools/lex_cis.c
diff -u /dev/null linux/pcmcia-cs-3.1.15/debug-tools/lex_cis.c:1.1
--- /dev/null	Mon Jul 31 21:15:10 2000
+++ linux/pcmcia-cs-3.1.15/debug-tools/lex_cis.c	Fri Jul  7 16:34:58 2000
@@ -0,0 +1,2341 @@
+/* A lexical scanner generated by flex */
+
+/* Scanner skeleton version:
+ * $Header: /src/cvs/valinux/oldkernel/linux/pcmcia-cs-3.1.15/debug-tools/lex_cis.c,v 1.1 2000/07/07 23:34:58 sflory Exp $
+ */
+
+#define FLEX_SCANNER
+#define YY_FLEX_MAJOR_VERSION 2
+#define YY_FLEX_MINOR_VERSION 5
+
+#include <stdio.h>
+
+
+/* cfront 1.2 defines "c_plusplus" instead of "__cplusplus" */
+#ifdef c_plusplus
+#ifndef __cplusplus
+#define __cplusplus
+#endif
+#endif
+
+
+#ifdef __cplusplus
+
+#include <stdlib.h>
+#include <unistd.h>
+
+/* Use prototypes in function declarations. */
+#define YY_USE_PROTOS
+
+/* The "const" storage-class-modifier is valid. */
+#define YY_USE_CONST
+
+#else	/* ! __cplusplus */
+
+#if __STDC__
+
+#define YY_USE_PROTOS
+#define YY_USE_CONST
+
+#endif	/* __STDC__ */
+#endif	/* ! __cplusplus */
+
+#ifdef __TURBOC__
+ #pragma warn -rch
+ #pragma warn -use
+#include <io.h>
+#include <stdlib.h>
+#define YY_USE_CONST
+#define YY_USE_PROTOS
+#endif
+
+#ifdef YY_USE_CONST
+#define yyconst const
+#else
+#define yyconst
+#endif
+
+
+#ifdef YY_USE_PROTOS
+#define YY_PROTO(proto) proto
+#else
+#define YY_PROTO(proto) ()
+#endif
+
+/* Returned upon end-of-file. */
+#define YY_NULL 0
+
+/* Promotes a possibly negative, possibly signed char to an unsigned
+ * integer for use as an array index.  If the signed char is negative,
+ * we want to instead treat it as an 8-bit unsigned char, hence the
+ * double cast.
+ */
+#define YY_SC_TO_UI(c) ((unsigned int) (unsigned char) c)
+
+/* Enter a start condition.  This macro really ought to take a parameter,
+ * but we do it the disgusting crufty way forced on us by the ()-less
+ * definition of BEGIN.
+ */
+#define BEGIN yy_start = 1 + 2 *
+
+/* Translate the current start state into a value that can be later handed
+ * to BEGIN to return to the state.  The YYSTATE alias is for lex
+ * compatibility.
+ */
+#define YY_START ((yy_start - 1) / 2)
+#define YYSTATE YY_START
+
+/* Action number for EOF rule of a given start state. */
+#define YY_STATE_EOF(state) (YY_END_OF_BUFFER + state + 1)
+
+/* Special action meaning "start processing a new file". */
+#define YY_NEW_FILE yyrestart( yyin )
+
+#define YY_END_OF_BUFFER_CHAR 0
+
+/* Size of default input buffer. */
+#define YY_BUF_SIZE 16384
+
+typedef struct yy_buffer_state *YY_BUFFER_STATE;
+
+extern int yyleng;
+extern FILE *yyin, *yyout;
+
+#define EOB_ACT_CONTINUE_SCAN 0
+#define EOB_ACT_END_OF_FILE 1
+#define EOB_ACT_LAST_MATCH 2
+
+/* The funky do-while in the following #define is used to turn the definition
+ * int a single C statement (which needs a semi-colon terminator).  This
+ * avoids problems with code like:
+ *
+ * 	if ( condition_holds )
+ *		yyless( 5 );
+ *	else
+ *		do_something_else();
+ *
+ * Prior to using the do-while the compiler would get upset at the
+ * "else" because it interpreted the "if" statement as being all
+ * done when it reached the ';' after the yyless() call.
+ */
+
+/* Return all but the first 'n' matched characters back to the input stream. */
+
+#define yyless(n) \
+	do \
+		{ \
+		/* Undo effects of setting up yytext. */ \
+		*yy_cp = yy_hold_char; \
+		YY_RESTORE_YY_MORE_OFFSET \
+		yy_c_buf_p = yy_cp = yy_bp + n - YY_MORE_ADJ; \
+		YY_DO_BEFORE_ACTION; /* set up yytext again */ \
+		} \
+	while ( 0 )
+
+#define unput(c) yyunput( c, yytext_ptr )
+
+/* The following is because we cannot portably get our hands on size_t
+ * (without autoconf's help, which isn't available because we want
+ * flex-generated scanners to compile on their own).
+ */
+typedef unsigned int yy_size_t;
+
+
+struct yy_buffer_state
+	{
+	FILE *yy_input_file;
+
+	char *yy_ch_buf;		/* input buffer */
+	char *yy_buf_pos;		/* current position in input buffer */
+
+	/* Size of input buffer in bytes, not including room for EOB
+	 * characters.
+	 */
+	yy_size_t yy_buf_size;
+
+	/* Number of characters read into yy_ch_buf, not including EOB
+	 * characters.
+	 */
+	int yy_n_chars;
+
+	/* Whether we "own" the buffer - i.e., we know we created it,
+	 * and can realloc() it to grow it, and should free() it to
+	 * delete it.
+	 */
+	int yy_is_our_buffer;
+
+	/* Whether this is an "interactive" input source; if so, and
+	 * if we're using stdio for input, then we want to use getc()
+	 * instead of fread(), to make sure we stop fetching input after
+	 * each newline.
+	 */
+	int yy_is_interactive;
+
+	/* Whether we're considered to be at the beginning of a line.
+	 * If so, '^' rules will be active on the next match, otherwise
+	 * not.
+	 */
+	int yy_at_bol;
+
+	/* Whether to try to fill the input buffer when we reach the
+	 * end of it.
+	 */
+	int yy_fill_buffer;
+
+	int yy_buffer_status;
+#define YY_BUFFER_NEW 0
+#define YY_BUFFER_NORMAL 1
+	/* When an EOF's been seen but there's still some text to process
+	 * then we mark the buffer as YY_EOF_PENDING, to indicate that we
+	 * shouldn't try reading from the input source any more.  We might
+	 * still have a bunch of tokens to match, though, because of
+	 * possible backing-up.
+	 *
+	 * When we actually see the EOF, we change the status to "new"
+	 * (via yyrestart()), so that the user can continue scanning by
+	 * just pointing yyin at a new input file.
+	 */
+#define YY_BUFFER_EOF_PENDING 2
+	};
+
+static YY_BUFFER_STATE yy_current_buffer = 0;
+
+/* We provide macros for accessing buffer states in case in the
+ * future we want to put the buffer states in a more general
+ * "scanner state".
+ */
+#define YY_CURRENT_BUFFER yy_current_buffer
+
+
+/* yy_hold_char holds the character lost when yytext is formed. */
+static char yy_hold_char;
+
+static int yy_n_chars;		/* number of characters read into yy_ch_buf */
+
+
+int yyleng;
+
+/* Points to current character in buffer. */
+static char *yy_c_buf_p = (char *) 0;
+static int yy_init = 1;		/* whether we need to initialize */
+static int yy_start = 0;	/* start state number */
+
+/* Flag which is used to allow yywrap()'s to do buffer switches
+ * instead of setting up a fresh yyin.  A bit of a hack ...
+ */
+static int yy_did_buffer_switch_on_eof;
+
+void yyrestart YY_PROTO(( FILE *input_file ));
+
+void yy_switch_to_buffer YY_PROTO(( YY_BUFFER_STATE new_buffer ));
+void yy_load_buffer_state YY_PROTO(( void ));
+YY_BUFFER_STATE yy_create_buffer YY_PROTO(( FILE *file, int size ));
+void yy_delete_buffer YY_PROTO(( YY_BUFFER_STATE b ));
+void yy_init_buffer YY_PROTO(( YY_BUFFER_STATE b, FILE *file ));
+void yy_flush_buffer YY_PROTO(( YY_BUFFER_STATE b ));
+#define YY_FLUSH_BUFFER yy_flush_buffer( yy_current_buffer )
+
+YY_BUFFER_STATE yy_scan_buffer YY_PROTO(( char *base, yy_size_t size ));
+YY_BUFFER_STATE yy_scan_string YY_PROTO(( yyconst char *yy_str ));
+YY_BUFFER_STATE yy_scan_bytes YY_PROTO(( yyconst char *bytes, int len ));
+
+static void *yy_flex_alloc YY_PROTO(( yy_size_t ));
+static void *yy_flex_realloc YY_PROTO(( void *, yy_size_t ));
+static void yy_flex_free YY_PROTO(( void * ));
+
+#define yy_new_buffer yy_create_buffer
+
+#define yy_set_interactive(is_interactive) \
+	{ \
+	if ( ! yy_current_buffer ) \
+		yy_current_buffer = yy_create_buffer( yyin, YY_BUF_SIZE ); \
+	yy_current_buffer->yy_is_interactive = is_interactive; \
+	}
+
+#define yy_set_bol(at_bol) \
+	{ \
+	if ( ! yy_current_buffer ) \
+		yy_current_buffer = yy_create_buffer( yyin, YY_BUF_SIZE ); \
+	yy_current_buffer->yy_at_bol = at_bol; \
+	}
+
+#define YY_AT_BOL() (yy_current_buffer->yy_at_bol)
+
+typedef unsigned char YY_CHAR;
+FILE *yyin = (FILE *) 0, *yyout = (FILE *) 0;
+typedef int yy_state_type;
+extern char *yytext;
+#define yytext_ptr yytext
+
+static yy_state_type yy_get_previous_state YY_PROTO(( void ));
+static yy_state_type yy_try_NUL_trans YY_PROTO(( yy_state_type current_state ));
+static int yy_get_next_buffer YY_PROTO(( void ));
+static void yy_fatal_error YY_PROTO(( yyconst char msg[] ));
+
+/* Done after the current pattern has been matched and before the
+ * corresponding action - sets up yytext.
+ */
+#define YY_DO_BEFORE_ACTION \
+	yytext_ptr = yy_bp; \
+	yyleng = (int) (yy_cp - yy_bp); \
+	yy_hold_char = *yy_cp; \
+	*yy_cp = '\0'; \
+	yy_c_buf_p = yy_cp;
+
+#define YY_NUM_RULES 96
+#define YY_END_OF_BUFFER 97
+static yyconst short int yy_accept[445] =
+    {   0,
+        2,    2,    0,    0,   97,   95,    2,    1,    2,   95,
+        3,   68,   68,   95,   95,   95,   95,   95,   95,   95,
+       95,   95,   95,   95,   95,   95,   95,   95,   95,   95,
+       95,   95,   95,   95,   95,   95,   95,   96,    2,    2,
+        3,    0,   94,    0,    3,   93,   68,   90,   84,   70,
+        0,    0,    0,   77,    0,    0,    0,    0,    0,    0,
+        0,    0,    0,    0,    0,    0,    0,    0,    0,    0,
+        0,    0,    0,    0,    0,    0,    0,    0,    0,    0,
+        0,    0,    0,    0,    0,    0,    0,    0,    0,    0,
+        0,    0,   45,    0,    0,    0,    0,    0,    0,    0,
+
+        0,    0,    0,    0,    0,    0,    0,    0,    0,    0,
+       94,    0,   93,   87,   81,    0,    0,   73,    0,   71,
+       91,   85,   72,   78,   80,   92,   86,   79,   69,    0,
+        0,    0,    0,    0,    0,    0,    0,    0,   13,    0,
+       35,    0,    0,    0,    0,    0,    0,    0,    0,    0,
+        0,    0,    0,    0,    0,    0,    0,    0,    0,    0,
+        0,    0,    0,    0,    0,    0,    0,    0,    0,    0,
+        0,    0,   51,    0,    0,    0,    0,    5,    0,    0,
+        0,    0,    0,    0,    0,    0,    0,    0,    0,    0,
+       88,   82,   74,   76,   89,   83,   75,   18,    0,    0,
+
+        0,   42,    0,    0,    0,   12,   17,   40,   39,   38,
+       36,   37,    0,    0,    0,    0,    0,    0,    0,    0,
+        0,    0,    0,    0,    0,    0,    0,    0,   29,    0,
+        0,   21,    0,    0,    0,    0,    0,    0,    0,    0,
+        0,   22,    0,    0,    0,    0,    0,    0,    0,    0,
+        0,    0,    0,    0,   56,    0,   14,   16,   44,   43,
+        0,    0,    0,    0,   28,    0,    0,    0,    0,    0,
+        0,    0,    0,    0,    0,   25,    0,    0,    0,    0,
+        0,    0,    0,    0,    0,    0,    0,    0,    0,    0,
+        0,    0,    0,   57,    0,    0,    0,    0,    0,    0,
+
+       15,    0,    0,   47,    0,    0,    0,   49,    0,   24,
+        0,    0,    0,    0,    0,    0,    0,    0,    0,    0,
+       20,    0,    0,    0,    4,    0,    6,   46,    0,    0,
+        0,    0,    0,    0,    0,   55,    7,    0,   41,   48,
+       32,    0,   52,   31,   53,    0,   50,    0,    0,    0,
+        0,    0,    0,    0,    0,    0,    0,    0,    0,    0,
+        0,   11,    0,    0,    0,    0,    0,    0,    0,   30,
+        0,   54,    0,    0,    0,    8,    9,    0,    0,    0,
+        0,    0,    0,    0,   58,    0,    0,    0,   27,   34,
+        0,   66,    0,    0,    0,    0,    0,    0,    0,    0,
+
+        0,    0,    0,    0,   33,    0,    0,   63,    0,   23,
+        0,    0,    0,    0,    0,    0,    0,    0,    0,   19,
+       60,    0,    0,    0,    0,   61,    0,    0,    0,    0,
+        0,    0,   67,    0,   10,   26,    0,    0,   62,   64,
+       59,    0,   65,    0
+    } ;
+
+static yyconst int yy_ec[256] =
+    {   0,
+        1,    1,    1,    1,    1,    1,    1,    1,    2,    3,
+        1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
+        1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
+        1,    4,    1,    5,    6,    1,    1,    1,    1,    1,
+        1,    1,    1,    1,    1,    7,    1,    8,    9,   10,
+       11,   11,   11,   12,   11,   13,   11,    1,    6,    1,
+        1,    1,    1,    1,   14,   15,   15,   16,   17,   18,
+        1,   19,   20,    1,    1,   21,   22,   23,   24,   25,
+        1,   26,   27,    1,   28,   29,    1,    1,    1,    1,
+       30,   31,   32,    1,   33,    1,   34,   35,   36,   37,
+
+       38,   39,   40,   41,   42,    1,   43,   44,   45,   46,
+       47,   48,   49,   50,   51,   52,   53,   54,   55,   56,
+       57,    1,    1,    1,    1,    1,    1,    1,    1,    1,
+        1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
+        1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
+        1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
+        1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
+        1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
+        1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
+        1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
+
+        1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
+        1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
+        1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
+        1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
+        1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
+        1,    1,    1,    1,    1
+    } ;
+
+static yyconst int yy_meta[58] =
+    {   0,
+        1,    1,    2,    1,    1,    1,    1,    3,    3,    3,
+        3,    3,    3,    3,    3,    3,    3,    3,    1,    1,
+        1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
+        1,    1,    1,    3,    3,    3,    3,    3,    3,    1,
+        1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
+        1,    1,    1,    1,    1,    1,    1
+    } ;
+
+static yyconst short int yy_base[450] =
+    {   0,
+        0,    0,    0,    0,  500,  501,   56,  501,   57,   57,
+        0,   82,  443,  472,   47,  476,   31,  468,  471,  468,
+       30,  130,   25,  459,   58,  454,   27,   24,  457,   47,
+       60,  456,  451,   65,  446,   45,  453,  501,  100,  104,
+        0,  109,  501,  110,    0,  178,  430,  501,  501,  501,
+      450,   95,  433,  501,  102,    0,  469,  457,  455,  466,
+      425,  431,  439,  424,  454,  452,  459,  436,   78,  424,
+      422,  457,  433,  414,  412,  427,   80,  409,   79,  110,
+      422,  414,  416,  408,  408,  406,  419,  410,  401,  398,
+      420,  406,  501,  402,  399,   91,  404,  412,  403,  394,
+
+      412,  394,   85,  392,  392,  396,  390,  402,  396,  118,
+      124,  151,    0,  501,  501,  144,  386,  501,  147,  501,
+      501,  501,  501,  501,  501,  501,  501,  501,    0,  414,
+      409,  410,  406,  392,  376,  396,  395,  407,  501,  405,
+      501,  370,  379,  379,  141,  388,  380,  384,  383,  380,
+      364,  371,  382,  364,  370,  363,  366,  354,  376,  364,
+      374,  375,  355,  355,  366,  369,  366,  362,  367,  361,
+      347,  361,  501,  344,  356,  351,  346,  501,  340,  336,
+      348,  355,  351,  349,  344,  343,  342,  332,  344,  329,
+      501,  501,  501,  501,  501,  501,  501,  501,  356,  357,
+
+      359,  501,  331,  333,  323,  501,  501,  501,  501,  501,
+      501,  501,  332,  321,  330,  339,  336,  331,  330,  325,
+      314,  314,  327,  323,  327,  324,  328,  309,  501,  325,
+      324,  501,  321,  312,  312,  311,  315,  303,  308,  316,
+      306,  501,  297,  304,  298,  298,  299,  285,  291,  307,
+      305,  292,  304,  289,  501,  313,  501,  501,  501,  501,
+      292,  281,  300,  284,  501,  277,  285,  277,  275,  294,
+      287,  277,  285,  271,  274,  501,  282,  283,  281,  273,
+      265,  275,  268,  280,  274,  274,  268,  272,  251,  274,
+      256,  266,  260,  501,  249,  268,  257,  260,  290,  265,
+
+      501,  261,  264,  501,  263,  250,  261,  501,  260,  501,
+      259,  235,  257,  231,  241,  249,  251,  246,  245,  229,
+      501,  242,  243,  243,  501,  232,  501,  244,  237,  232,
+      227,  235,  234,  234,  237,  501,  501,  235,  501,  501,
+      501,  216,  501,  501,  501,  221,  501,  234,  221,  232,
+      213,  208,  228,  215,  212,  216,  215,  219,  219,  201,
+      220,  501,  208,  214,  216,  201,  211,  215,  214,  501,
+      188,  501,  207,  206,  192,  501,  501,  177,  188,  188,
+      191,  176,  187,  187,  501,  171,  171,  183,  501,  501,
+      184,  501,  173,  168,  170,  170,  155,  160,  173,  171,
+
+      158,  153,  154,  155,  501,  156,  149,  501,  164,  501,
+      162,  145,  162,  147,  155,  132,  131,  140,  127,  501,
+      501,  130,  123,  120,  119,  501,  130,  119,  106,  115,
+      108,  107,  501,  102,  501,  501,   99,   83,  501,  501,
+      501,   34,  501,  501,  231,  234,  237,  240,   67
+    } ;
+
+static yyconst short int yy_def[450] =
+    {   0,
+      444,    1,  445,  445,  444,  444,  444,  444,  444,  446,
+      447,  444,   12,  444,  444,  444,  444,  444,  444,  444,
+      444,  444,  444,  444,  444,  444,  444,  444,  444,  444,
+      444,  444,  444,  444,  444,  444,  444,  444,  444,  444,
+      447,  446,  444,  448,  447,  444,   12,  444,  444,  444,
+      444,  444,  444,  444,  444,  449,  444,  444,  444,  444,
+      444,  444,  444,  444,  444,  444,  444,  444,  444,  444,
+      444,  444,  444,  444,  444,  444,  444,  444,  444,  444,
+      444,  444,  444,  444,  444,  444,  444,  444,  444,  444,
+      444,  444,  444,  444,  444,  444,  444,  444,  444,  444,
+
+      444,  444,  444,  444,  444,  444,  444,  444,  444,  446,
+      446,  448,   46,  444,  444,  444,  444,  444,  444,  444,
+      444,  444,  444,  444,  444,  444,  444,  444,  449,  444,
+      444,  444,  444,  444,  444,  444,  444,  444,  444,  444,
+      444,  444,  444,  444,  444,  444,  444,  444,  444,  444,
+      444,  444,  444,  444,  444,  444,  444,  444,  444,  444,
+      444,  444,  444,  444,  444,  444,  444,  444,  444,  444,
+      444,  444,  444,  444,  444,  444,  444,  444,  444,  444,
+      444,  444,  444,  444,  444,  444,  444,  444,  444,  444,
+      444,  444,  444,  444,  444,  444,  444,  444,  444,  444,
+
+      444,  444,  444,  444,  444,  444,  444,  444,  444,  444,
+      444,  444,  444,  444,  444,  444,  444,  444,  444,  444,
+      444,  444,  444,  444,  444,  444,  444,  444,  444,  444,
+      444,  444,  444,  444,  444,  444,  444,  444,  444,  444,
+      444,  444,  444,  444,  444,  444,  444,  444,  444,  444,
+      444,  444,  444,  444,  444,  444,  444,  444,  444,  444,
+      444,  444,  444,  444,  444,  444,  444,  444,  444,  444,
+      444,  444,  444,  444,  444,  444,  444,  444,  444,  444,
+      444,  444,  444,  444,  444,  444,  444,  444,  444,  444,
+      444,  444,  444,  444,  444,  444,  444,  444,  444,  444,
+
+      444,  444,  444,  444,  444,  444,  444,  444,  444,  444,
+      444,  444,  444,  444,  444,  444,  444,  444,  444,  444,
+      444,  444,  444,  444,  444,  444,  444,  444,  444,  444,
+      444,  444,  444,  444,  444,  444,  444,  444,  444,  444,
+      444,  444,  444,  444,  444,  444,  444,  444,  444,  444,
+      444,  444,  444,  444,  444,  444,  444,  444,  444,  444,
+      444,  444,  444,  444,  444,  444,  444,  444,  444,  444,
+      444,  444,  444,  444,  444,  444,  444,  444,  444,  444,
+      444,  444,  444,  444,  444,  444,  444,  444,  444,  444,
+      444,  444,  444,  444,  444,  444,  444,  444,  444,  444,
+
+      444,  444,  444,  444,  444,  444,  444,  444,  444,  444,
+      444,  444,  444,  444,  444,  444,  444,  444,  444,  444,
+      444,  444,  444,  444,  444,  444,  444,  444,  444,  444,
+      444,  444,  444,  444,  444,  444,  444,  444,  444,  444,
+      444,  444,  444,    0,  444,  444,  444,  444,  444
+    } ;
+
+static yyconst short int yy_nxt[559] =
+    {   0,
+        6,    7,    8,    9,   10,   11,    6,   12,   13,   13,
+       13,   13,   13,    6,    6,   14,   15,   16,    6,   17,
+        6,    6,   18,    6,    6,   19,   20,    6,   21,   22,
+        6,    6,    6,   23,   24,   25,   26,    6,   27,    6,
+        6,   28,    6,   29,   30,   31,    6,   32,    6,   33,
+       34,   35,    6,   36,   37,    6,    6,   39,   39,   39,
+       40,   43,   41,   58,   61,   68,   83,   62,   90,  129,
+       93,   59,   91,   94,   69,   70,   84,   71,   63,   92,
+       96,   64,  107,  443,   97,   98,  108,   44,   46,   47,
+       47,   47,   47,   47,   47,   48,   86,  100,   87,   99,
+
+      104,   39,  105,   39,   88,   39,  101,   40,  121,   41,
+       49,  142,   42,   43,  111,  126,   50,  151,  183,  143,
+      442,  152,   43,  122,   51,  154,   52,   53,   43,  123,
+      127,  155,   54,  156,   55,  184,  175,   56,   72,   44,
+      112,  176,   73,  157,  441,  124,  158,  159,   44,  211,
+      212,  440,  128,   42,   44,  111,  160,  191,  439,  438,
+      195,  437,  436,   74,   75,  435,   76,  434,  433,  432,
+      431,  430,  192,   77,   78,  196,  429,   79,  428,   80,
+       81,  112,  427,  426,   82,  113,  113,  113,  113,  113,
+      113,  114,  425,  424,  193,  423,  422,  197,  421,  420,
+
+      419,  418,  417,  416,  415,  414,  115,  413,  412,  411,
+      410,  409,  408,  407,  406,  405,  404,  403,  402,  401,
+      400,  399,  116,  117,  398,  397,  396,  395,  118,  394,
+      119,   38,   38,   38,   42,   42,   42,   45,  393,   45,
+      110,  110,  110,  392,  391,  390,  389,  388,  387,  386,
+      385,  384,  383,  382,  381,  380,  379,  378,  377,  376,
+      375,  374,  373,  372,  371,  370,  369,  368,  367,  366,
+      365,  364,  363,  362,  361,  360,  359,  358,  357,  356,
+      355,  354,  353,  352,  351,  350,  349,  348,  347,  346,
+      345,  344,  343,  342,  341,  340,  339,  338,  337,  336,
+
+      335,  334,  333,  332,  331,  330,  329,  328,  327,  326,
+      325,  324,  323,  322,  321,  320,  319,  318,  317,  316,
+      315,  314,  313,  312,  311,  310,  309,  308,  307,  306,
+      305,  304,  303,  302,  301,  300,  299,  298,  297,  296,
+      295,  294,  293,  292,  291,  290,  289,  288,  287,  286,
+      285,  284,  283,  282,  281,  280,  279,  278,  277,  276,
+      275,  274,  273,  272,  271,  270,  269,  268,  267,  266,
+      265,  264,  263,  262,  261,  260,  259,  258,  257,  256,
+      255,  254,  253,  252,  251,  250,  249,  248,  247,  246,
+      245,  244,  243,  242,  241,  240,  239,  238,  237,  236,
+
+      235,  234,  233,  232,  231,  230,  229,  228,  227,  226,
+      225,  224,  223,  222,  221,  220,  219,  218,  217,  216,
+      215,  214,  213,  210,  209,  208,  207,  206,  205,  204,
+      203,  202,  201,  200,  199,  198,  194,  190,  189,  188,
+      187,  186,  185,  182,  181,  180,  179,  178,  177,  174,
+      173,  172,  171,  170,  169,  168,  167,  166,  165,  164,
+      163,  162,  161,  153,  150,  149,  148,  147,  146,  145,
+      144,  141,  140,  139,  138,  137,  136,  135,  134,  133,
+      132,  131,  130,  125,  120,  444,  109,  106,  103,  102,
+       95,   89,   85,   67,   66,   65,   60,   57,  444,  444,
+
+        5,  444,  444,  444,  444,  444,  444,  444,  444,  444,
+      444,  444,  444,  444,  444,  444,  444,  444,  444,  444,
+      444,  444,  444,  444,  444,  444,  444,  444,  444,  444,
+      444,  444,  444,  444,  444,  444,  444,  444,  444,  444,
+      444,  444,  444,  444,  444,  444,  444,  444,  444,  444,
+      444,  444,  444,  444,  444,  444,  444,  444
+    } ;
+
+static yyconst short int yy_chk[559] =
+    {   0,
+        1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
+        1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
+        1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
+        1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
+        1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
+        1,    1,    1,    1,    1,    1,    1,    7,    9,    7,
+        9,   10,    9,   15,   17,   21,   23,   17,   27,  449,
+       28,   15,   27,   28,   21,   21,   23,   21,   17,   27,
+       30,   17,   36,  442,   30,   30,   36,   10,   12,   12,
+       12,   12,   12,   12,   12,   12,   25,   31,   25,   30,
+
+       34,   39,   34,   39,   25,   40,   31,   40,   52,   40,
+       12,   69,   44,   42,   44,   55,   12,   77,  103,   69,
+      438,   77,  110,   52,   12,   79,   12,   12,  111,   52,
+       55,   79,   12,   79,   12,  103,   96,   12,   22,   42,
+       44,   96,   22,   80,  437,   52,   80,   80,  110,  145,
+      145,  434,   55,  112,  111,  112,   80,  116,  432,  431,
+      119,  430,  429,   22,   22,  428,   22,  427,  425,  424,
+      423,  422,  116,   22,   22,  119,  419,   22,  418,   22,
+       22,  112,  417,  416,   22,   46,   46,   46,   46,   46,
+       46,   46,  415,  414,  116,  413,  412,  119,  411,  409,
+
+      407,  406,  404,  403,  402,  401,   46,  400,  399,  398,
+      397,  396,  395,  394,  393,  391,  388,  387,  386,  384,
+      383,  382,   46,   46,  381,  380,  379,  378,   46,  375,
+       46,  445,  445,  445,  446,  446,  446,  447,  374,  447,
+      448,  448,  448,  373,  371,  369,  368,  367,  366,  365,
+      364,  363,  361,  360,  359,  358,  357,  356,  355,  354,
+      353,  352,  351,  350,  349,  348,  346,  342,  338,  335,
+      334,  333,  332,  331,  330,  329,  328,  326,  324,  323,
+      322,  320,  319,  318,  317,  316,  315,  314,  313,  312,
+      311,  309,  307,  306,  305,  303,  302,  300,  299,  298,
+
+      297,  296,  295,  293,  292,  291,  290,  289,  288,  287,
+      286,  285,  284,  283,  282,  281,  280,  279,  278,  277,
+      275,  274,  273,  272,  271,  270,  269,  268,  267,  266,
+      264,  263,  262,  261,  256,  254,  253,  252,  251,  250,
+      249,  248,  247,  246,  245,  244,  243,  241,  240,  239,
+      238,  237,  236,  235,  234,  233,  231,  230,  228,  227,
+      226,  225,  224,  223,  222,  221,  220,  219,  218,  217,
+      216,  215,  214,  213,  205,  204,  203,  201,  200,  199,
+      190,  189,  188,  187,  186,  185,  184,  183,  182,  181,
+      180,  179,  177,  176,  175,  174,  172,  171,  170,  169,
+
+      168,  167,  166,  165,  164,  163,  162,  161,  160,  159,
+      158,  157,  156,  155,  154,  153,  152,  151,  150,  149,
+      148,  147,  146,  144,  143,  142,  140,  138,  137,  136,
+      135,  134,  133,  132,  131,  130,  117,  109,  108,  107,
+      106,  105,  104,  102,  101,  100,   99,   98,   97,   95,
+       94,   92,   91,   90,   89,   88,   87,   86,   85,   84,
+       83,   82,   81,   78,   76,   75,   74,   73,   72,   71,
+       70,   68,   67,   66,   65,   64,   63,   62,   61,   60,
+       59,   58,   57,   53,   51,   47,   37,   35,   33,   32,
+       29,   26,   24,   20,   19,   18,   16,   14,   13,    5,
+
+      444,  444,  444,  444,  444,  444,  444,  444,  444,  444,
+      444,  444,  444,  444,  444,  444,  444,  444,  444,  444,
+      444,  444,  444,  444,  444,  444,  444,  444,  444,  444,
+      444,  444,  444,  444,  444,  444,  444,  444,  444,  444,
+      444,  444,  444,  444,  444,  444,  444,  444,  444,  444,
+      444,  444,  444,  444,  444,  444,  444,  444
+    } ;
+
+static yy_state_type yy_last_accepting_state;
+static char *yy_last_accepting_cpos;
+
+/* The intent behind this definition is that it'll catch
+ * any uses of REJECT which flex missed.
+ */
+#define REJECT reject_used_but_not_detected
+#define yymore() yymore_used_but_not_detected
+#define YY_MORE_ADJ 0
+#define YY_RESTORE_YY_MORE_OFFSET
+char *yytext;
+#line 1 "lex_cis.l"
+#define INITIAL 0
+/* Special state for handling include files */
+#define src 1
+
+#line 5 "lex_cis.l"
+/*
+ * lex_cis.l 1.12 1999/10/25 19:57: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@pcmcia.sourceforge.org>.  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.
+ */
+
+#undef src
+#include <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+#include <syslog.h>
+#define src 1
+
+#include <pcmcia/cs_types.h>
+#include <pcmcia/cistpl.h>
+
+#include "pack_cis.h"
+#include "yacc_cis.h"
+
+/* For assembling nice error messages */
+int current_lineno;
+
+static int lex_number(char *);
+static int lex_units(char *, int, int);
+static int lex_float(char *);
+static int lex_string(char *);
+
+
+/* Macros after this point can all be overridden by user definitions in
+ * section 1.
+ */
+
+#ifndef YY_SKIP_YYWRAP
+#ifdef __cplusplus
+extern "C" int yywrap YY_PROTO(( void ));
+#else
+extern int yywrap YY_PROTO(( void ));
+#endif
+#endif
+
+#ifndef YY_NO_UNPUT
+static void yyunput YY_PROTO(( int c, char *buf_ptr ));
+#endif
+
+#ifndef yytext_ptr
+static void yy_flex_strncpy YY_PROTO(( char *, yyconst char *, int ));
+#endif
+
+#ifdef YY_NEED_STRLEN
+static int yy_flex_strlen YY_PROTO(( yyconst char * ));
+#endif
+
+#ifndef YY_NO_INPUT
+#ifdef __cplusplus
+static int yyinput YY_PROTO(( void ));
+#else
+static int input YY_PROTO(( void ));
+#endif
+#endif
+
+#if YY_STACK_USED
+static int yy_start_stack_ptr = 0;
+static int yy_start_stack_depth = 0;
+static int *yy_start_stack = 0;
+#ifndef YY_NO_PUSH_STATE
+static void yy_push_state YY_PROTO(( int new_state ));
+#endif
+#ifndef YY_NO_POP_STATE
+static void yy_pop_state YY_PROTO(( void ));
+#endif
+#ifndef YY_NO_TOP_STATE
+static int yy_top_state YY_PROTO(( void ));
+#endif
+
+#else
+#define YY_NO_PUSH_STATE 1
+#define YY_NO_POP_STATE 1
+#define YY_NO_TOP_STATE 1
+#endif
+
+#ifdef YY_MALLOC_DECL
+YY_MALLOC_DECL
+#else
+#if __STDC__
+#ifndef __cplusplus
+#include <stdlib.h>
+#endif
+#else
+/* Just try to get by without declaring the routines.  This will fail
+ * miserably on non-ANSI systems for which sizeof(size_t) != sizeof(int)
+ * or sizeof(void*) != sizeof(int).
+ */
+#endif
+#endif
+
+/* Amount of stuff to slurp up with each read. */
+#ifndef YY_READ_BUF_SIZE
+#define YY_READ_BUF_SIZE 8192
+#endif
+
+/* Copy whatever the last rule matched to the standard output. */
+
+#ifndef ECHO
+/* This used to be an fputs(), but since the string might contain NUL's,
+ * we now use fwrite().
+ */
+#define ECHO (void) fwrite( yytext, yyleng, 1, yyout )
+#endif
+
+/* Gets input and stuffs it into "buf".  number of characters read, or YY_NULL,
+ * is returned in "result".
+ */
+#ifndef YY_INPUT
+#define YY_INPUT(buf,result,max_size) \
+	if ( yy_current_buffer->yy_is_interactive ) \
+		{ \
+		int c = '*', n; \
+		for ( n = 0; n < max_size && \
+			     (c = getc( yyin )) != EOF && c != '\n'; ++n ) \
+			buf[n] = (char) c; \
+		if ( c == '\n' ) \
+			buf[n++] = (char) c; \
+		if ( c == EOF && ferror( yyin ) ) \
+			YY_FATAL_ERROR( "input in flex scanner failed" ); \
+		result = n; \
+		} \
+	else if ( ((result = fread( buf, 1, max_size, yyin )) == 0) \
+		  && ferror( yyin ) ) \
+		YY_FATAL_ERROR( "input in flex scanner failed" );
+#endif
+
+/* No semi-colon after return; correct usage is to write "yyterminate();" -
+ * we don't want an extra ';' after the "return" because that will cause
+ * some compilers to complain about unreachable statements.
+ */
+#ifndef yyterminate
+#define yyterminate() return YY_NULL
+#endif
+
+/* Number of entries by which start-condition stack grows. */
+#ifndef YY_START_STACK_INCR
+#define YY_START_STACK_INCR 25
+#endif
+
+/* Report a fatal error. */
+#ifndef YY_FATAL_ERROR
+#define YY_FATAL_ERROR(msg) yy_fatal_error( msg )
+#endif
+
+/* Default declaration of generated scanner - a define so the user can
+ * easily add parameters.
+ */
+#ifndef YY_DECL
+#define YY_DECL int yylex YY_PROTO(( void ))
+#endif
+
+/* Code executed at the beginning of each rule, after yytext and yyleng
+ * have been set up.
+ */
+#ifndef YY_USER_ACTION
+#define YY_USER_ACTION
+#endif
+
+/* Code executed at the end of each rule. */
+#ifndef YY_BREAK
+#define YY_BREAK break;
+#endif
+
+#define YY_RULE_SETUP \
+	YY_USER_ACTION
+
+YY_DECL
+	{
+	register yy_state_type yy_current_state;
+	register char *yy_cp, *yy_bp;
+	register int yy_act;
+
+#line 62 "lex_cis.l"
+
+
+
+	if ( yy_init )
+		{
+		yy_init = 0;
+
+#ifdef YY_USER_INIT
+		YY_USER_INIT;
+#endif
+
+		if ( ! yy_start )
+			yy_start = 1;	/* first start state */
+
+		if ( ! yyin )
+			yyin = stdin;
+
+		if ( ! yyout )
+			yyout = stdout;
+
+		if ( ! yy_current_buffer )
+			yy_current_buffer =
+				yy_create_buffer( yyin, YY_BUF_SIZE );
+
+		yy_load_buffer_state();
+		}
+
+	while ( 1 )		/* loops until end-of-file is reached */
+		{
+		yy_cp = yy_c_buf_p;
+
+		/* Support of yytext. */
+		*yy_cp = yy_hold_char;
+
+		/* yy_bp points to the position in yy_ch_buf of the start of
+		 * the current run.
+		 */
+		yy_bp = yy_cp;
+
+		yy_current_state = yy_start;
+yy_match:
+		do
+			{
+			register YY_CHAR yy_c = yy_ec[YY_SC_TO_UI(*yy_cp)];
+			if ( yy_accept[yy_current_state] )
+				{
+				yy_last_accepting_state = yy_current_state;
+				yy_last_accepting_cpos = yy_cp;
+				}
+			while ( yy_chk[yy_base[yy_current_state] + yy_c] != yy_current_state )
+				{
+				yy_current_state = (int) yy_def[yy_current_state];
+				if ( yy_current_state >= 445 )
+					yy_c = yy_meta[(unsigned int) yy_c];
+				}
+			yy_current_state = yy_nxt[yy_base[yy_current_state] + (unsigned int) yy_c];
+			++yy_cp;
+			}
+		while ( yy_base[yy_current_state] != 501 );
+
+yy_find_action:
+		yy_act = yy_accept[yy_current_state];
+		if ( yy_act == 0 )
+			{ /* have to back up */
+			yy_cp = yy_last_accepting_cpos;
+			yy_current_state = yy_last_accepting_state;
+			yy_act = yy_accept[yy_current_state];
+			}
+
+		YY_DO_BEFORE_ACTION;
+
+
+do_action:	/* This label is used only to access EOF actions. */
+
+
+		switch ( yy_act )
+	{ /* beginning of action switch */
+			case 0: /* must back up */
+			/* undo the effects of YY_DO_BEFORE_ACTION */
+			*yy_cp = yy_hold_char;
+			yy_cp = yy_last_accepting_cpos;
+			yy_current_state = yy_last_accepting_state;
+			goto yy_find_action;
+
+case 1:
+YY_RULE_SETUP
+#line 64 "lex_cis.l"
+current_lineno++;
+	YY_BREAK
+case 2:
+YY_RULE_SETUP
+#line 65 "lex_cis.l"
+/* skip */ ;
+	YY_BREAK
+case 3:
+YY_RULE_SETUP
+#line 66 "lex_cis.l"
+/* skip */ ;
+	YY_BREAK
+case 4:
+YY_RULE_SETUP
+#line 68 "lex_cis.l"
+return FUNCID;
+	YY_BREAK
+case 5:
+YY_RULE_SETUP
+#line 69 "lex_cis.l"
+return MFC;
+	YY_BREAK
+case 6:
+YY_RULE_SETUP
+#line 70 "lex_cis.l"
+return MANFID;
+	YY_BREAK
+case 7:
+YY_RULE_SETUP
+#line 71 "lex_cis.l"
+return VERS_1;
+	YY_BREAK
+case 8:
+YY_RULE_SETUP
+#line 72 "lex_cis.l"
+return CHECKSUM;
+	YY_BREAK
+case 9:
+YY_RULE_SETUP
+#line 74 "lex_cis.l"
+return DEV_INFO;
+	YY_BREAK
+case 10:
+YY_RULE_SETUP
+#line 75 "lex_cis.l"
+return ATTR_DEV_INFO;
+	YY_BREAK
+case 11:
+YY_RULE_SETUP
+#line 76 "lex_cis.l"
+return NO_INFO;
+	YY_BREAK
+case 12:
+YY_RULE_SETUP
+#line 77 "lex_cis.l"
+return lex_number("0");
+	YY_BREAK
+case 13:
+YY_RULE_SETUP
+#line 78 "lex_cis.l"
+return lex_number("1");
+	YY_BREAK
+case 14:
+YY_RULE_SETUP
+#line 79 "lex_cis.l"
+return lex_number("3");
+	YY_BREAK
+case 15:
+YY_RULE_SETUP
+#line 80 "lex_cis.l"
+return lex_number("4");
+	YY_BREAK
+case 16:
+YY_RULE_SETUP
+#line 81 "lex_cis.l"
+return lex_number("5");
+	YY_BREAK
+case 17:
+YY_RULE_SETUP
+#line 82 "lex_cis.l"
+return lex_number("6");
+	YY_BREAK
+case 18:
+YY_RULE_SETUP
+#line 83 "lex_cis.l"
+return lex_number("7");
+	YY_BREAK
+case 19:
+YY_RULE_SETUP
+#line 84 "lex_cis.l"
+return lex_number("13");
+	YY_BREAK
+case 20:
+YY_RULE_SETUP
+#line 86 "lex_cis.l"
+return CONFIG;
+	YY_BREAK
+case 21:
+YY_RULE_SETUP
+#line 87 "lex_cis.l"
+return BASE;
+	YY_BREAK
+case 22:
+YY_RULE_SETUP
+#line 88 "lex_cis.l"
+return MASK;
+	YY_BREAK
+case 23:
+YY_RULE_SETUP
+#line 89 "lex_cis.l"
+return LAST_INDEX;
+	YY_BREAK
+case 24:
+YY_RULE_SETUP
+#line 90 "lex_cis.l"
+return POST;
+	YY_BREAK
+case 25:
+YY_RULE_SETUP
+#line 91 "lex_cis.l"
+return ROM;
+	YY_BREAK
+case 26:
+YY_RULE_SETUP
+#line 93 "lex_cis.l"
+return CFTABLE;
+	YY_BREAK
+case 27:
+YY_RULE_SETUP
+#line 94 "lex_cis.l"
+return DEFAULT;
+	YY_BREAK
+case 28:
+YY_RULE_SETUP
+#line 95 "lex_cis.l"
+return BVD;
+	YY_BREAK
+case 29:
+YY_RULE_SETUP
+#line 96 "lex_cis.l"
+return WP;
+	YY_BREAK
+case 30:
+YY_RULE_SETUP
+#line 97 "lex_cis.l"
+return RDYBSY;
+	YY_BREAK
+case 31:
+YY_RULE_SETUP
+#line 98 "lex_cis.l"
+return MWAIT;
+	YY_BREAK
+case 32:
+YY_RULE_SETUP
+#line 99 "lex_cis.l"
+return AUDIO;
+	YY_BREAK
+case 33:
+YY_RULE_SETUP
+#line 100 "lex_cis.l"
+return READONLY;
+	YY_BREAK
+case 34:
+YY_RULE_SETUP
+#line 101 "lex_cis.l"
+return PWRDOWN;
+	YY_BREAK
+case 35:
+YY_RULE_SETUP
+#line 103 "lex_cis.l"
+return VCC;
+	YY_BREAK
+case 36:
+YY_RULE_SETUP
+#line 104 "lex_cis.l"
+return VPP1;
+	YY_BREAK
+case 37:
+YY_RULE_SETUP
+#line 105 "lex_cis.l"
+return VPP2;
+	YY_BREAK
+case 38:
+YY_RULE_SETUP
+#line 106 "lex_cis.l"
+return VNOM;
+	YY_BREAK
+case 39:
+YY_RULE_SETUP
+#line 107 "lex_cis.l"
+return VMIN;
+	YY_BREAK
+case 40:
+YY_RULE_SETUP
+#line 108 "lex_cis.l"
+return VMAX;
+	YY_BREAK
+case 41:
+YY_RULE_SETUP
+#line 109 "lex_cis.l"
+return ISTATIC;
+	YY_BREAK
+case 42:
+YY_RULE_SETUP
+#line 110 "lex_cis.l"
+return IAVG;
+	YY_BREAK
+case 43:
+YY_RULE_SETUP
+#line 111 "lex_cis.l"
+return IPEAK;
+	YY_BREAK
+case 44:
+YY_RULE_SETUP
+#line 112 "lex_cis.l"
+return IDOWN;
+	YY_BREAK
+case 45:
+YY_RULE_SETUP
+#line 114 "lex_cis.l"
+return IO;
+	YY_BREAK
+case 46:
+YY_RULE_SETUP
+#line 115 "lex_cis.l"
+return MEM;
+	YY_BREAK
+case 47:
+YY_RULE_SETUP
+#line 116 "lex_cis.l"
+return BIT8;
+	YY_BREAK
+case 48:
+YY_RULE_SETUP
+#line 117 "lex_cis.l"
+return BIT16;
+	YY_BREAK
+case 49:
+YY_RULE_SETUP
+#line 118 "lex_cis.l"
+return LINES;
+	YY_BREAK
+case 50:
+YY_RULE_SETUP
+#line 119 "lex_cis.l"
+return RANGE;
+	YY_BREAK
+case 51:
+YY_RULE_SETUP
+#line 121 "lex_cis.l"
+return IRQ_NO;
+	YY_BREAK
+case 52:
+YY_RULE_SETUP
+#line 122 "lex_cis.l"
+return LEVEL;
+	YY_BREAK
+case 53:
+YY_RULE_SETUP
+#line 123 "lex_cis.l"
+return PULSE;
+	YY_BREAK
+case 54:
+YY_RULE_SETUP
+#line 124 "lex_cis.l"
+return SHARED;
+	YY_BREAK
+case 55:
+YY_RULE_SETUP
+#line 126 "lex_cis.l"
+return TIMING;
+	YY_BREAK
+case 56:
+YY_RULE_SETUP
+#line 127 "lex_cis.l"
+return WAIT;
+	YY_BREAK
+case 57:
+YY_RULE_SETUP
+#line 128 "lex_cis.l"
+return READY;
+	YY_BREAK
+case 58:
+YY_RULE_SETUP
+#line 129 "lex_cis.l"
+return RESERVED;
+	YY_BREAK
+case 59:
+YY_RULE_SETUP
+#line 131 "lex_cis.l"
+return lex_number("0");
+	YY_BREAK
+case 60:
+YY_RULE_SETUP
+#line 132 "lex_cis.l"
+return lex_number("1");
+	YY_BREAK
+case 61:
+YY_RULE_SETUP
+#line 133 "lex_cis.l"
+return lex_number("2");
+	YY_BREAK
+case 62:
+YY_RULE_SETUP
+#line 134 "lex_cis.l"
+return lex_number("3");
+	YY_BREAK
+case 63:
+YY_RULE_SETUP
+#line 135 "lex_cis.l"
+return lex_number("4");
+	YY_BREAK
+case 64:
+YY_RULE_SETUP
+#line 136 "lex_cis.l"
+return lex_number("5");
+	YY_BREAK
+case 65:
+YY_RULE_SETUP
+#line 137 "lex_cis.l"
+return lex_number("6");
+	YY_BREAK
+case 66:
+YY_RULE_SETUP
+#line 138 "lex_cis.l"
+return lex_number("7");
+	YY_BREAK
+case 67:
+YY_RULE_SETUP
+#line 139 "lex_cis.l"
+return lex_number("8");
+	YY_BREAK
+case 68:
+YY_RULE_SETUP
+#line 141 "lex_cis.l"
+return lex_number(yytext);
+	YY_BREAK
+case 69:
+YY_RULE_SETUP
+#line 142 "lex_cis.l"
+return lex_number(yytext);
+	YY_BREAK
+case 70:
+YY_RULE_SETUP
+#line 144 "lex_cis.l"
+return lex_units(yytext, 1, SIZE);
+	YY_BREAK
+case 71:
+YY_RULE_SETUP
+#line 145 "lex_cis.l"
+return lex_units(yytext, 1024, SIZE);
+	YY_BREAK
+case 72:
+YY_RULE_SETUP
+#line 146 "lex_cis.l"
+return lex_units(yytext, 1024*1024, SIZE);
+	YY_BREAK
+case 73:
+YY_RULE_SETUP
+#line 148 "lex_cis.l"
+return lex_units(yytext, 1000000000, TIME);
+	YY_BREAK
+case 74:
+YY_RULE_SETUP
+#line 149 "lex_cis.l"
+return lex_units(yytext, 1000000, TIME);
+	YY_BREAK
+case 75:
+YY_RULE_SETUP
+#line 150 "lex_cis.l"
+return lex_units(yytext, 1000, TIME);
+	YY_BREAK
+case 76:
+YY_RULE_SETUP
+#line 151 "lex_cis.l"
+return lex_units(yytext, 1, TIME);
+	YY_BREAK
+case 77:
+YY_RULE_SETUP
+#line 152 "lex_cis.l"
+return lex_units(yytext, 1000000000, TIME);
+	YY_BREAK
+case 78:
+YY_RULE_SETUP
+#line 153 "lex_cis.l"
+return lex_units(yytext, 1000000, TIME);
+	YY_BREAK
+case 79:
+YY_RULE_SETUP
+#line 154 "lex_cis.l"
+return lex_units(yytext, 1000, TIME);
+	YY_BREAK
+case 80:
+YY_RULE_SETUP
+#line 155 "lex_cis.l"
+return lex_units(yytext, 1, TIME);
+	YY_BREAK
+case 81:
+YY_RULE_SETUP
+#line 157 "lex_cis.l"
+return lex_units(yytext, 100000, VOLTAGE);
+	YY_BREAK
+case 82:
+YY_RULE_SETUP
+#line 158 "lex_cis.l"
+return lex_units(yytext, 100, VOLTAGE);
+	YY_BREAK
+case 83:
+YY_RULE_SETUP
+#line 159 "lex_cis.l"
+return lex_units(yytext, 0.1, VOLTAGE);
+	YY_BREAK
+case 84:
+YY_RULE_SETUP
+#line 160 "lex_cis.l"
+return lex_units(yytext, 100000, VOLTAGE);
+	YY_BREAK
+case 85:
+YY_RULE_SETUP
+#line 161 "lex_cis.l"
+return lex_units(yytext, 100, VOLTAGE);
+	YY_BREAK
+case 86:
+YY_RULE_SETUP
+#line 162 "lex_cis.l"
+return lex_units(yytext, 0.1, VOLTAGE);
+	YY_BREAK
+case 87:
+YY_RULE_SETUP
+#line 164 "lex_cis.l"
+return lex_units(yytext, 10000000, CURRENT);
+	YY_BREAK
+case 88:
+YY_RULE_SETUP
+#line 165 "lex_cis.l"
+return lex_units(yytext, 10000, CURRENT);
+	YY_BREAK
+case 89:
+YY_RULE_SETUP
+#line 166 "lex_cis.l"
+return lex_units(yytext, 10, CURRENT);
+	YY_BREAK
+case 90:
+YY_RULE_SETUP
+#line 167 "lex_cis.l"
+return lex_units(yytext, 10000000, CURRENT);
+	YY_BREAK
+case 91:
+YY_RULE_SETUP
+#line 168 "lex_cis.l"
+return lex_units(yytext, 10000, CURRENT);
+	YY_BREAK
+case 92:
+YY_RULE_SETUP
+#line 169 "lex_cis.l"
+return lex_units(yytext, 10, CURRENT);
+	YY_BREAK
+case 93:
+YY_RULE_SETUP
+#line 171 "lex_cis.l"
+return lex_float(yytext);
+	YY_BREAK
+case 94:
+YY_RULE_SETUP
+#line 173 "lex_cis.l"
+return lex_string(yytext);
+	YY_BREAK
+case 95:
+YY_RULE_SETUP
+#line 175 "lex_cis.l"
+return yytext[0];
+	YY_BREAK
+case 96:
+YY_RULE_SETUP
+#line 177 "lex_cis.l"
+ECHO;
+	YY_BREAK
+case YY_STATE_EOF(INITIAL):
+case YY_STATE_EOF(src):
+	yyterminate();
+
+	case YY_END_OF_BUFFER:
+		{
+		/* Amount of text matched not including the EOB char. */
+		int yy_amount_of_matched_text = (int) (yy_cp - yytext_ptr) - 1;
+
+		/* Undo the effects of YY_DO_BEFORE_ACTION. */
+		*yy_cp = yy_hold_char;
+		YY_RESTORE_YY_MORE_OFFSET
+
+		if ( yy_current_buffer->yy_buffer_status == YY_BUFFER_NEW )
+			{
+			/* We're scanning a new file or input source.  It's
+			 * possible that this happened because the user
+			 * just pointed yyin at a new source and called
+			 * yylex().  If so, then we have to assure
+			 * consistency between yy_current_buffer and our
+			 * globals.  Here is the right place to do so, because
+			 * this is the first action (other than possibly a
+			 * back-up) that will match for the new input source.
+			 */
+			yy_n_chars = yy_current_buffer->yy_n_chars;
+			yy_current_buffer->yy_input_file = yyin;
+			yy_current_buffer->yy_buffer_status = YY_BUFFER_NORMAL;
+			}
+
+		/* Note that here we test for yy_c_buf_p "<=" to the position
+		 * of the first EOB in the buffer, since yy_c_buf_p will
+		 * already have been incremented past the NUL character
+		 * (since all states make transitions on EOB to the
+		 * end-of-buffer state).  Contrast this with the test
+		 * in input().
+		 */
+		if ( yy_c_buf_p <= &yy_current_buffer->yy_ch_buf[yy_n_chars] )
+			{ /* This was really a NUL. */
+			yy_state_type yy_next_state;
+
+			yy_c_buf_p = yytext_ptr + yy_amount_of_matched_text;
+
+			yy_current_state = yy_get_previous_state();
+
+			/* Okay, we're now positioned to make the NUL
+			 * transition.  We couldn't have
+			 * yy_get_previous_state() go ahead and do it
+			 * for us because it doesn't know how to deal
+			 * with the possibility of jamming (and we don't
+			 * want to build jamming into it because then it
+			 * will run more slowly).
+			 */
+
+			yy_next_state = yy_try_NUL_trans( yy_current_state );
+
+			yy_bp = yytext_ptr + YY_MORE_ADJ;
+
+			if ( yy_next_state )
+				{
+				/* Consume the NUL. */
+				yy_cp = ++yy_c_buf_p;
+				yy_current_state = yy_next_state;
+				goto yy_match;
+				}
+
+			else
+				{
+				yy_cp = yy_c_buf_p;
+				goto yy_find_action;
+				}
+			}
+
+		else switch ( yy_get_next_buffer() )
+			{
+			case EOB_ACT_END_OF_FILE:
+				{
+				yy_did_buffer_switch_on_eof = 0;
+
+				if ( yywrap() )
+					{
+					/* Note: because we've taken care in
+					 * yy_get_next_buffer() to have set up
+					 * yytext, we can now set up
+					 * yy_c_buf_p so that if some total
+					 * hoser (like flex itself) wants to
+					 * call the scanner after we return the
+					 * YY_NULL, it'll still work - another
+					 * YY_NULL will get returned.
+					 */
+					yy_c_buf_p = yytext_ptr + YY_MORE_ADJ;
+
+					yy_act = YY_STATE_EOF(YY_START);
+					goto do_action;
+					}
+
+				else
+					{
+					if ( ! yy_did_buffer_switch_on_eof )
+						YY_NEW_FILE;
+					}
+				break;
+				}
+
+			case EOB_ACT_CONTINUE_SCAN:
+				yy_c_buf_p =
+					yytext_ptr + yy_amount_of_matched_text;
+
+				yy_current_state = yy_get_previous_state();
+
+				yy_cp = yy_c_buf_p;
+				yy_bp = yytext_ptr + YY_MORE_ADJ;
+				goto yy_match;
+
+			case EOB_ACT_LAST_MATCH:
+				yy_c_buf_p =
+				&yy_current_buffer->yy_ch_buf[yy_n_chars];
+
+				yy_current_state = yy_get_previous_state();
+
+				yy_cp = yy_c_buf_p;
+				yy_bp = yytext_ptr + YY_MORE_ADJ;
+				goto yy_find_action;
+			}
+		break;
+		}
+
+	default:
+		YY_FATAL_ERROR(
+			"fatal flex scanner internal error--no action found" );
+	} /* end of action switch */
+		} /* end of scanning one token */
+	} /* end of yylex */
+
+
+/* yy_get_next_buffer - try to read in a new buffer
+ *
+ * Returns a code representing an action:
+ *	EOB_ACT_LAST_MATCH -
+ *	EOB_ACT_CONTINUE_SCAN - continue scanning from current position
+ *	EOB_ACT_END_OF_FILE - end of file
+ */
+
+static int yy_get_next_buffer()
+	{
+	register char *dest = yy_current_buffer->yy_ch_buf;
+	register char *source = yytext_ptr;
+	register int number_to_move, i;
+	int ret_val;
+
+	if ( yy_c_buf_p > &yy_current_buffer->yy_ch_buf[yy_n_chars + 1] )
+		YY_FATAL_ERROR(
+		"fatal flex scanner internal error--end of buffer missed" );
+
+	if ( yy_current_buffer->yy_fill_buffer == 0 )
+		{ /* Don't try to fill the buffer, so this is an EOF. */
+		if ( yy_c_buf_p - yytext_ptr - YY_MORE_ADJ == 1 )
+			{
+			/* We matched a single character, the EOB, so
+			 * treat this as a final EOF.
+			 */
+			return EOB_ACT_END_OF_FILE;
+			}
+
+		else
+			{
+			/* We matched some text prior to the EOB, first
+			 * process it.
+			 */
+			return EOB_ACT_LAST_MATCH;
+			}
+		}
+
+	/* Try to read more data. */
+
+	/* First move last chars to start of buffer. */
+	number_to_move = (int) (yy_c_buf_p - yytext_ptr) - 1;
+
+	for ( i = 0; i < number_to_move; ++i )
+		*(dest++) = *(source++);
+
+	if ( yy_current_buffer->yy_buffer_status == YY_BUFFER_EOF_PENDING )
+		/* don't do the read, it's not guaranteed to return an EOF,
+		 * just force an EOF
+		 */
+		yy_current_buffer->yy_n_chars = yy_n_chars = 0;
+
+	else
+		{
+		int num_to_read =
+			yy_current_buffer->yy_buf_size - number_to_move - 1;
+
+		while ( num_to_read <= 0 )
+			{ /* Not enough room in the buffer - grow it. */
+#ifdef YY_USES_REJECT
+			YY_FATAL_ERROR(
+"input buffer overflow, can't enlarge buffer because scanner uses REJECT" );
+#else
+
+			/* just a shorter name for the current buffer */
+			YY_BUFFER_STATE b = yy_current_buffer;
+
+			int yy_c_buf_p_offset =
+				(int) (yy_c_buf_p - b->yy_ch_buf);
+
+			if ( b->yy_is_our_buffer )
+				{
+				int new_size = b->yy_buf_size * 2;
+
+				if ( new_size <= 0 )
+					b->yy_buf_size += b->yy_buf_size / 8;
+				else
+					b->yy_buf_size *= 2;
+
+				b->yy_ch_buf = (char *)
+					/* Include room in for 2 EOB chars. */
+					yy_flex_realloc( (void *) b->yy_ch_buf,
+							 b->yy_buf_size + 2 );
+				}
+			else
+				/* Can't grow it, we don't own it. */
+				b->yy_ch_buf = 0;
+
+			if ( ! b->yy_ch_buf )
+				YY_FATAL_ERROR(
+				"fatal error - scanner input buffer overflow" );
+
+			yy_c_buf_p = &b->yy_ch_buf[yy_c_buf_p_offset];
+
+			num_to_read = yy_current_buffer->yy_buf_size -
+						number_to_move - 1;
+#endif
+			}
+
+		if ( num_to_read > YY_READ_BUF_SIZE )
+			num_to_read = YY_READ_BUF_SIZE;
+
+		/* Read in more data. */
+		YY_INPUT( (&yy_current_buffer->yy_ch_buf[number_to_move]),
+			yy_n_chars, num_to_read );
+
+		yy_current_buffer->yy_n_chars = yy_n_chars;
+		}
+
+	if ( yy_n_chars == 0 )
+		{
+		if ( number_to_move == YY_MORE_ADJ )
+			{
+			ret_val = EOB_ACT_END_OF_FILE;
+			yyrestart( yyin );
+			}
+
+		else
+			{
+			ret_val = EOB_ACT_LAST_MATCH;
+			yy_current_buffer->yy_buffer_status =
+				YY_BUFFER_EOF_PENDING;
+			}
+		}
+
+	else
+		ret_val = EOB_ACT_CONTINUE_SCAN;
+
+	yy_n_chars += number_to_move;
+	yy_current_buffer->yy_ch_buf[yy_n_chars] = YY_END_OF_BUFFER_CHAR;
+	yy_current_buffer->yy_ch_buf[yy_n_chars + 1] = YY_END_OF_BUFFER_CHAR;
+
+	yytext_ptr = &yy_current_buffer->yy_ch_buf[0];
+
+	return ret_val;
+	}
+
+
+/* yy_get_previous_state - get the state just before the EOB char was reached */
+
+static yy_state_type yy_get_previous_state()
+	{
+	register yy_state_type yy_current_state;
+	register char *yy_cp;
+
+	yy_current_state = yy_start;
+
+	for ( yy_cp = yytext_ptr + YY_MORE_ADJ; yy_cp < yy_c_buf_p; ++yy_cp )
+		{
+		register YY_CHAR yy_c = (*yy_cp ? yy_ec[YY_SC_TO_UI(*yy_cp)] : 1);
+		if ( yy_accept[yy_current_state] )
+			{
+			yy_last_accepting_state = yy_current_state;
+			yy_last_accepting_cpos = yy_cp;
+			}
+		while ( yy_chk[yy_base[yy_current_state] + yy_c] != yy_current_state )
+			{
+			yy_current_state = (int) yy_def[yy_current_state];
+			if ( yy_current_state >= 445 )
+				yy_c = yy_meta[(unsigned int) yy_c];
+			}
+		yy_current_state = yy_nxt[yy_base[yy_current_state] + (unsigned int) yy_c];
+		}
+
+	return yy_current_state;
+	}
+
+
+/* yy_try_NUL_trans - try to make a transition on the NUL character
+ *
+ * synopsis
+ *	next_state = yy_try_NUL_trans( current_state );
+ */
+
+#ifdef YY_USE_PROTOS
+static yy_state_type yy_try_NUL_trans( yy_state_type yy_current_state )
+#else
+static yy_state_type yy_try_NUL_trans( yy_current_state )
+yy_state_type yy_current_state;
+#endif
+	{
+	register int yy_is_jam;
+	register char *yy_cp = yy_c_buf_p;
+
+	register YY_CHAR yy_c = 1;
+	if ( yy_accept[yy_current_state] )
+		{
+		yy_last_accepting_state = yy_current_state;
+		yy_last_accepting_cpos = yy_cp;
+		}
+	while ( yy_chk[yy_base[yy_current_state] + yy_c] != yy_current_state )
+		{
+		yy_current_state = (int) yy_def[yy_current_state];
+		if ( yy_current_state >= 445 )
+			yy_c = yy_meta[(unsigned int) yy_c];
+		}
+	yy_current_state = yy_nxt[yy_base[yy_current_state] + (unsigned int) yy_c];
+	yy_is_jam = (yy_current_state == 444);
+
+	return yy_is_jam ? 0 : yy_current_state;
+	}
+
+
+#ifndef YY_NO_UNPUT
+#ifdef YY_USE_PROTOS
+static void yyunput( int c, register char *yy_bp )
+#else
+static void yyunput( c, yy_bp )
+int c;
+register char *yy_bp;
+#endif
+	{
+	register char *yy_cp = yy_c_buf_p;
+
+	/* undo effects of setting up yytext */
+	*yy_cp = yy_hold_char;
+
+	if ( yy_cp < yy_current_buffer->yy_ch_buf + 2 )
+		{ /* need to shift things up to make room */
+		/* +2 for EOB chars. */
+		register int number_to_move = yy_n_chars + 2;
+		register char *dest = &yy_current_buffer->yy_ch_buf[
+					yy_current_buffer->yy_buf_size + 2];
+		register char *source =
+				&yy_current_buffer->yy_ch_buf[number_to_move];
+
+		while ( source > yy_current_buffer->yy_ch_buf )
+			*--dest = *--source;
+
+		yy_cp += (int) (dest - source);
+		yy_bp += (int) (dest - source);
+		yy_current_buffer->yy_n_chars =
+			yy_n_chars = yy_current_buffer->yy_buf_size;
+
+		if ( yy_cp < yy_current_buffer->yy_ch_buf + 2 )
+			YY_FATAL_ERROR( "flex scanner push-back overflow" );
+		}
+
+	*--yy_cp = (char) c;
+
+
+	yytext_ptr = yy_bp;
+	yy_hold_char = *yy_cp;
+	yy_c_buf_p = yy_cp;
+	}
+#endif	/* ifndef YY_NO_UNPUT */
+
+
+#ifdef __cplusplus
+static int yyinput()
+#else
+static int input()
+#endif
+	{
+	int c;
+
+	*yy_c_buf_p = yy_hold_char;
+
+	if ( *yy_c_buf_p == YY_END_OF_BUFFER_CHAR )
+		{
+		/* yy_c_buf_p now points to the character we want to return.
+		 * If this occurs *before* the EOB characters, then it's a
+		 * valid NUL; if not, then we've hit the end of the buffer.
+		 */
+		if ( yy_c_buf_p < &yy_current_buffer->yy_ch_buf[yy_n_chars] )
+			/* This was really a NUL. */
+			*yy_c_buf_p = '\0';
+
+		else
+			{ /* need more input */
+			int offset = yy_c_buf_p - yytext_ptr;
+			++yy_c_buf_p;
+
+			switch ( yy_get_next_buffer() )
+				{
+				case EOB_ACT_LAST_MATCH:
+					/* This happens because yy_g_n_b()
+					 * sees that we've accumulated a
+					 * token and flags that we need to
+					 * try matching the token before
+					 * proceeding.  But for input(),
+					 * there's no matching to consider.
+					 * So convert the EOB_ACT_LAST_MATCH
+					 * to EOB_ACT_END_OF_FILE.
+					 */
+
+					/* Reset buffer status. */
+					yyrestart( yyin );
+
+					/* fall through */
+
+				case EOB_ACT_END_OF_FILE:
+					{
+					if ( yywrap() )
+						return EOF;
+
+					if ( ! yy_did_buffer_switch_on_eof )
+						YY_NEW_FILE;
+#ifdef __cplusplus
+					return yyinput();
+#else
+					return input();
+#endif
+					}
+
+				case EOB_ACT_CONTINUE_SCAN:
+					yy_c_buf_p = yytext_ptr + offset;
+					break;
+				}
+			}
+		}
+
+	c = *(unsigned char *) yy_c_buf_p;	/* cast for 8-bit char's */
+	*yy_c_buf_p = '\0';	/* preserve yytext */
+	yy_hold_char = *++yy_c_buf_p;
+
+
+	return c;
+	}
+
+
+#ifdef YY_USE_PROTOS
+void yyrestart( FILE *input_file )
+#else
+void yyrestart( input_file )
+FILE *input_file;
+#endif
+	{
+	if ( ! yy_current_buffer )
+		yy_current_buffer = yy_create_buffer( yyin, YY_BUF_SIZE );
+
+	yy_init_buffer( yy_current_buffer, input_file );
+	yy_load_buffer_state();
+	}
+
+
+#ifdef YY_USE_PROTOS
+void yy_switch_to_buffer( YY_BUFFER_STATE new_buffer )
+#else
+void yy_switch_to_buffer( new_buffer )
+YY_BUFFER_STATE new_buffer;
+#endif
+	{
+	if ( yy_current_buffer == new_buffer )
+		return;
+
+	if ( yy_current_buffer )
+		{
+		/* Flush out information for old buffer. */
+		*yy_c_buf_p = yy_hold_char;
+		yy_current_buffer->yy_buf_pos = yy_c_buf_p;
+		yy_current_buffer->yy_n_chars = yy_n_chars;
+		}
+
+	yy_current_buffer = new_buffer;
+	yy_load_buffer_state();
+
+	/* We don't actually know whether we did this switch during
+	 * EOF (yywrap()) processing, but the only time this flag
+	 * is looked at is after yywrap() is called, so it's safe
+	 * to go ahead and always set it.
+	 */
+	yy_did_buffer_switch_on_eof = 1;
+	}
+
+
+#ifdef YY_USE_PROTOS
+void yy_load_buffer_state( void )
+#else
+void yy_load_buffer_state()
+#endif
+	{
+	yy_n_chars = yy_current_buffer->yy_n_chars;
+	yytext_ptr = yy_c_buf_p = yy_current_buffer->yy_buf_pos;
+	yyin = yy_current_buffer->yy_input_file;
+	yy_hold_char = *yy_c_buf_p;
+	}
+
+
+#ifdef YY_USE_PROTOS
+YY_BUFFER_STATE yy_create_buffer( FILE *file, int size )
+#else
+YY_BUFFER_STATE yy_create_buffer( file, size )
+FILE *file;
+int size;
+#endif
+	{
+	YY_BUFFER_STATE b;
+
+	b = (YY_BUFFER_STATE) yy_flex_alloc( sizeof( struct yy_buffer_state ) );
+	if ( ! b )
+		YY_FATAL_ERROR( "out of dynamic memory in yy_create_buffer()" );
+
+	b->yy_buf_size = size;
+
+	/* yy_ch_buf has to be 2 characters longer than the size given because
+	 * we need to put in 2 end-of-buffer characters.
+	 */
+	b->yy_ch_buf = (char *) yy_flex_alloc( b->yy_buf_size + 2 );
+	if ( ! b->yy_ch_buf )
+		YY_FATAL_ERROR( "out of dynamic memory in yy_create_buffer()" );
+
+	b->yy_is_our_buffer = 1;
+
+	yy_init_buffer( b, file );
+
+	return b;
+	}
+
+
+#ifdef YY_USE_PROTOS
+void yy_delete_buffer( YY_BUFFER_STATE b )
+#else
+void yy_delete_buffer( b )
+YY_BUFFER_STATE b;
+#endif
+	{
+	if ( ! b )
+		return;
+
+	if ( b == yy_current_buffer )
+		yy_current_buffer = (YY_BUFFER_STATE) 0;
+
+	if ( b->yy_is_our_buffer )
+		yy_flex_free( (void *) b->yy_ch_buf );
+
+	yy_flex_free( (void *) b );
+	}
+
+
+#ifndef YY_ALWAYS_INTERACTIVE
+#ifndef YY_NEVER_INTERACTIVE
+extern int isatty YY_PROTO(( int ));
+#endif
+#endif
+
+#ifdef YY_USE_PROTOS
+void yy_init_buffer( YY_BUFFER_STATE b, FILE *file )
+#else
+void yy_init_buffer( b, file )
+YY_BUFFER_STATE b;
+FILE *file;
+#endif
+
+
+	{
+	yy_flush_buffer( b );
+
+	b->yy_input_file = file;
+	b->yy_fill_buffer = 1;
+
+#if YY_ALWAYS_INTERACTIVE
+	b->yy_is_interactive = 1;
+#else
+#if YY_NEVER_INTERACTIVE
+	b->yy_is_interactive = 0;
+#else
+	b->yy_is_interactive = file ? (isatty( fileno(file) ) > 0) : 0;
+#endif
+#endif
+	}
+
+
+#ifdef YY_USE_PROTOS
+void yy_flush_buffer( YY_BUFFER_STATE b )
+#else
+void yy_flush_buffer( b )
+YY_BUFFER_STATE b;
+#endif
+
+	{
+	if ( ! b )
+		return;
+
+	b->yy_n_chars = 0;
+
+	/* We always need two end-of-buffer characters.  The first causes
+	 * a transition to the end-of-buffer state.  The second causes
+	 * a jam in that state.
+	 */
+	b->yy_ch_buf[0] = YY_END_OF_BUFFER_CHAR;
+	b->yy_ch_buf[1] = YY_END_OF_BUFFER_CHAR;
+
+	b->yy_buf_pos = &b->yy_ch_buf[0];
+
+	b->yy_at_bol = 1;
+	b->yy_buffer_status = YY_BUFFER_NEW;
+
+	if ( b == yy_current_buffer )
+		yy_load_buffer_state();
+	}
+
+
+#ifndef YY_NO_SCAN_BUFFER
+#ifdef YY_USE_PROTOS
+YY_BUFFER_STATE yy_scan_buffer( char *base, yy_size_t size )
+#else
+YY_BUFFER_STATE yy_scan_buffer( base, size )
+char *base;
+yy_size_t size;
+#endif
+	{
+	YY_BUFFER_STATE b;
+
+	if ( size < 2 ||
+	     base[size-2] != YY_END_OF_BUFFER_CHAR ||
+	     base[size-1] != YY_END_OF_BUFFER_CHAR )
+		/* They forgot to leave room for the EOB's. */
+		return 0;
+
+	b = (YY_BUFFER_STATE) yy_flex_alloc( sizeof( struct yy_buffer_state ) );
+	if ( ! b )
+		YY_FATAL_ERROR( "out of dynamic memory in yy_scan_buffer()" );
+
+	b->yy_buf_size = size - 2;	/* "- 2" to take care of EOB's */
+	b->yy_buf_pos = b->yy_ch_buf = base;
+	b->yy_is_our_buffer = 0;
+	b->yy_input_file = 0;
+	b->yy_n_chars = b->yy_buf_size;
+	b->yy_is_interactive = 0;
+	b->yy_at_bol = 1;
+	b->yy_fill_buffer = 0;
+	b->yy_buffer_status = YY_BUFFER_NEW;
+
+	yy_switch_to_buffer( b );
+
+	return b;
+	}
+#endif
+
+
+#ifndef YY_NO_SCAN_STRING
+#ifdef YY_USE_PROTOS
+YY_BUFFER_STATE yy_scan_string( yyconst char *yy_str )
+#else
+YY_BUFFER_STATE yy_scan_string( yy_str )
+yyconst char *yy_str;
+#endif
+	{
+	int len;
+	for ( len = 0; yy_str[len]; ++len )
+		;
+
+	return yy_scan_bytes( yy_str, len );
+	}
+#endif
+
+
+#ifndef YY_NO_SCAN_BYTES
+#ifdef YY_USE_PROTOS
+YY_BUFFER_STATE yy_scan_bytes( yyconst char *bytes, int len )
+#else
+YY_BUFFER_STATE yy_scan_bytes( bytes, len )
+yyconst char *bytes;
+int len;
+#endif
+	{
+	YY_BUFFER_STATE b;
+	char *buf;
+	yy_size_t n;
+	int i;
+
+	/* Get memory for full buffer, including space for trailing EOB's. */
+	n = len + 2;
+	buf = (char *) yy_flex_alloc( n );
+	if ( ! buf )
+		YY_FATAL_ERROR( "out of dynamic memory in yy_scan_bytes()" );
+
+	for ( i = 0; i < len; ++i )
+		buf[i] = bytes[i];
+
+	buf[len] = buf[len+1] = YY_END_OF_BUFFER_CHAR;
+
+	b = yy_scan_buffer( buf, n );
+	if ( ! b )
+		YY_FATAL_ERROR( "bad buffer in yy_scan_bytes()" );
+
+	/* It's okay to grow etc. this buffer, and we should throw it
+	 * away when we're done.
+	 */
+	b->yy_is_our_buffer = 1;
+
+	return b;
+	}
+#endif
+
+
+#ifndef YY_NO_PUSH_STATE
+#ifdef YY_USE_PROTOS
+static void yy_push_state( int new_state )
+#else
+static void yy_push_state( new_state )
+int new_state;
+#endif
+	{
+	if ( yy_start_stack_ptr >= yy_start_stack_depth )
+		{
+		yy_size_t new_size;
+
+		yy_start_stack_depth += YY_START_STACK_INCR;
+		new_size = yy_start_stack_depth * sizeof( int );
+
+		if ( ! yy_start_stack )
+			yy_start_stack = (int *) yy_flex_alloc( new_size );
+
+		else
+			yy_start_stack = (int *) yy_flex_realloc(
+					(void *) yy_start_stack, new_size );
+
+		if ( ! yy_start_stack )
+			YY_FATAL_ERROR(
+			"out of memory expanding start-condition stack" );
+		}
+
+	yy_start_stack[yy_start_stack_ptr++] = YY_START;
+
+	BEGIN(new_state);
+	}
+#endif
+
+
+#ifndef YY_NO_POP_STATE
+static void yy_pop_state()
+	{
+	if ( --yy_start_stack_ptr < 0 )
+		YY_FATAL_ERROR( "start-condition stack underflow" );
+
+	BEGIN(yy_start_stack[yy_start_stack_ptr]);
+	}
+#endif
+
+
+#ifndef YY_NO_TOP_STATE
+static int yy_top_state()
+	{
+	return yy_start_stack[yy_start_stack_ptr - 1];
+	}
+#endif
+
+#ifndef YY_EXIT_FAILURE
+#define YY_EXIT_FAILURE 2
+#endif
+
+#ifdef YY_USE_PROTOS
+static void yy_fatal_error( yyconst char msg[] )
+#else
+static void yy_fatal_error( msg )
+char msg[];
+#endif
+	{
+	(void) fprintf( stderr, "%s\n", msg );
+	exit( YY_EXIT_FAILURE );
+	}
+
+
+
+/* Redefine yyless() so it works in section 3 code. */
+
+#undef yyless
+#define yyless(n) \
+	do \
+		{ \
+		/* Undo effects of setting up yytext. */ \
+		yytext[yyleng] = yy_hold_char; \
+		yy_c_buf_p = yytext + n; \
+		yy_hold_char = *yy_c_buf_p; \
+		*yy_c_buf_p = '\0'; \
+		yyleng = n; \
+		} \
+	while ( 0 )
+
+
+/* Internal utility routines. */
+
+#ifndef yytext_ptr
+#ifdef YY_USE_PROTOS
+static void yy_flex_strncpy( char *s1, yyconst char *s2, int n )
+#else
+static void yy_flex_strncpy( s1, s2, n )
+char *s1;
+yyconst char *s2;
+int n;
+#endif
+	{
+	register int i;
+	for ( i = 0; i < n; ++i )
+		s1[i] = s2[i];
+	}
+#endif
+
+#ifdef YY_NEED_STRLEN
+#ifdef YY_USE_PROTOS
+static int yy_flex_strlen( yyconst char *s )
+#else
+static int yy_flex_strlen( s )
+yyconst char *s;
+#endif
+	{
+	register int n;
+	for ( n = 0; s[n]; ++n )
+		;
+
+	return n;
+	}
+#endif
+
+
+#ifdef YY_USE_PROTOS
+static void *yy_flex_alloc( yy_size_t size )
+#else
+static void *yy_flex_alloc( size )
+yy_size_t size;
+#endif
+	{
+	return (void *) malloc( size );
+	}
+
+#ifdef YY_USE_PROTOS
+static void *yy_flex_realloc( void *ptr, yy_size_t size )
+#else
+static void *yy_flex_realloc( ptr, size )
+void *ptr;
+yy_size_t size;
+#endif
+	{
+	/* The cast to (char *) in the following accommodates both
+	 * implementations that use char* generic pointers, and those
+	 * that use void* generic pointers.  It works with the latter
+	 * because both ANSI C and C++ allow castless assignment from
+	 * any pointer type to void*, and deal with argument conversions
+	 * as though doing an assignment.
+	 */
+	return (void *) realloc( (char *) ptr, size );
+	}
+
+#ifdef YY_USE_PROTOS
+static void yy_flex_free( void *ptr )
+#else
+static void yy_flex_free( ptr )
+void *ptr;
+#endif
+	{
+	free( ptr );
+	}
+
+#if YY_MAIN
+int main()
+	{
+	yylex();
+	return 0;
+	}
+#endif
+#line 177 "lex_cis.l"
+
+
+#ifndef yywrap
+int yywrap() { return 1; }
+#endif
+
+/*======================================================================
+
+    Stuff to parse basic data types
+
+======================================================================*/
+
+static int lex_number(char *s)
+{
+    yylval.num = strtoul(s, NULL, 0);
+    return NUMBER;
+}
+
+static int lex_float(char *s)
+{
+    yylval.flt = strtod(s, NULL);
+    return FLOAT;
+}
+
+static int lex_units(char *s, int scale, int token)
+{
+    float f;
+    sscanf(s, "%f", &f);
+    yylval.num = scale*f + 0.5;
+    return token;
+}
+
+static int lex_string(char *s)
+{
+    int n = strlen(s);
+    yylval.str = malloc(n-1);
+    strncpy(yylval.str, s+1, n-2);
+    yylval.str[n-2] = '\0';
+    return STRING;
+}
+
+/*======================================================================
+
+    The main parser entry point
+
+======================================================================*/
+
+void parse_cis(FILE *f)
+{
+    current_lineno = 1;
+    yyrestart(f);
+    yyparse();
+    fclose(f);
+}
+
Index: oldkernel/linux/pcmcia-cs-3.1.15/debug-tools/lex_cis.l
diff -u /dev/null linux/pcmcia-cs-3.1.15/debug-tools/lex_cis.l:1.1
--- /dev/null	Mon Jul 31 21:15:10 2000
+++ linux/pcmcia-cs-3.1.15/debug-tools/lex_cis.l	Fri Jul  7 16:34:58 2000
@@ -0,0 +1,231 @@
+/* Special state for handling include files */
+%x src
+
+%{
+/*
+ * lex_cis.l 1.12 1999/10/25 19:57: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@pcmcia.sourceforge.org>.  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.
+ */
+
+#undef src
+#include <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+#include <syslog.h>
+#define src 1
+
+#include <pcmcia/cs_types.h>
+#include <pcmcia/cistpl.h>
+
+#include "pack_cis.h"
+#include "yacc_cis.h"
+
+/* For assembling nice error messages */
+int current_lineno;
+
+static int lex_number(char *);
+static int lex_units(char *, int, int);
+static int lex_float(char *);
+static int lex_string(char *);
+
+%}
+
+int	[0-9]+
+hex	0x[0-9a-fA-F]+
+flt	[0-9]+\.[0-9]*
+str	\"([^"]|\\.)*\"
+
+%%
+
+\n		current_lineno++;
+[ \t]*		/* skip */ ;
+[ ]*[#;].*	/* skip */ ;
+
+funcid		return FUNCID;
+mfc		return MFC;
+manfid		return MANFID;
+vers_1		return VERS_1;
+checksum	return CHECKSUM;
+
+dev_info	return DEV_INFO;
+attr_dev_info	return ATTR_DEV_INFO;
+no_info		return NO_INFO;
+NULL		return lex_number("0");
+ROM		return lex_number("1");
+EPROM		return lex_number("3");
+EEPROM		return lex_number("4");
+FLASH		return lex_number("5");
+SRAM		return lex_number("6");
+DRAM		return lex_number("7");
+fn_specific	return lex_number("13");
+
+config		return CONFIG;
+base		return BASE;
+mask		return MASK;
+last_index	return LAST_INDEX;
+\[post\]	return POST;
+\[rom\]		return ROM;
+
+cftable_entry	return CFTABLE;
+\[default\]	return DEFAULT;
+\[bvd\]		return BVD;
+\[wp\]		return WP;
+\[rdybsy\]	return RDYBSY;
+\[mwait\]	return MWAIT;
+\[audio\]	return AUDIO;
+\[readonly\]	return READONLY;
+\[pwrdown\]	return PWRDOWN;
+
+Vcc		return VCC;
+Vpp1		return VPP1;
+Vpp2		return VPP2;
+Vnom		return VNOM;
+Vmin		return VMIN;
+Vmax		return VMAX;
+Istatic		return ISTATIC;
+Iavg		return IAVG;
+Ipeak		return IPEAK;
+Idown		return IDOWN;
+
+io		return IO;
+memory		return MEM;
+\[8bit\]	return BIT8;
+\[16bit\]	return BIT16;
+\[lines		return LINES;
+\[range\]	return RANGE;
+
+irq		return IRQ_NO;
+\[level\]	return LEVEL;
+\[pulse\]	return PULSE;
+\[shared\]	return SHARED;
+
+timing		return TIMING;
+wait		return WAIT;
+ready		return READY;
+reserved	return RESERVED;
+
+multi_function	return lex_number("0");
+memory_card	return lex_number("1");
+serial_port	return lex_number("2");
+parallel_port	return lex_number("3");
+fixed_disk	return lex_number("4");
+video_adapter	return lex_number("5");
+network_adapter	return lex_number("6");
+aims_card	return lex_number("7");
+scsi_adapter	return lex_number("8");
+
+{int}		return lex_number(yytext);
+{hex}		return lex_number(yytext);
+
+{int}b		return lex_units(yytext, 1, SIZE);
+{int}kb		return lex_units(yytext, 1024, SIZE);
+{int}mb		return lex_units(yytext, 1024*1024, SIZE);
+
+{flt}s		return lex_units(yytext, 1000000000, TIME);
+{flt}ms		return lex_units(yytext, 1000000, TIME);
+{flt}us		return lex_units(yytext, 1000, TIME);
+{flt}ns		return lex_units(yytext, 1, TIME);
+{int}s		return lex_units(yytext, 1000000000, TIME);
+{int}ms		return lex_units(yytext, 1000000, TIME);
+{int}us		return lex_units(yytext, 1000, TIME);
+{int}ns		return lex_units(yytext, 1, TIME);
+
+{flt}V		return lex_units(yytext, 100000, VOLTAGE);
+{flt}mV		return lex_units(yytext, 100, VOLTAGE);
+{flt}uV		return lex_units(yytext, 0.1, VOLTAGE);
+{int}V		return lex_units(yytext, 100000, VOLTAGE);
+{int}mV		return lex_units(yytext, 100, VOLTAGE);
+{int}uV		return lex_units(yytext, 0.1, VOLTAGE);
+
+{flt}A		return lex_units(yytext, 10000000, CURRENT);
+{flt}mA		return lex_units(yytext, 10000, CURRENT);
+{flt}uA		return lex_units(yytext, 10, CURRENT);
+{int}A		return lex_units(yytext, 10000000, CURRENT);
+{int}mA		return lex_units(yytext, 10000, CURRENT);
+{int}uA		return lex_units(yytext, 10, CURRENT);
+
+{flt}		return lex_float(yytext);
+
+{str}		return lex_string(yytext);
+
+.		return yytext[0];
+
+%%
+
+#ifndef yywrap
+int yywrap() { return 1; }
+#endif
+
+/*======================================================================
+
+    Stuff to parse basic data types
+
+======================================================================*/
+
+static int lex_number(char *s)
+{
+    yylval.num = strtoul(s, NULL, 0);
+    return NUMBER;
+}
+
+static int lex_float(char *s)
+{
+    yylval.flt = strtod(s, NULL);
+    return FLOAT;
+}
+
+static int lex_units(char *s, int scale, int token)
+{
+    float f;
+    sscanf(s, "%f", &f);
+    yylval.num = scale*f + 0.5;
+    return token;
+}
+
+static int lex_string(char *s)
+{
+    int n = strlen(s);
+    yylval.str = malloc(n-1);
+    strncpy(yylval.str, s+1, n-2);
+    yylval.str[n-2] = '\0';
+    return STRING;
+}
+
+/*======================================================================
+
+    The main parser entry point
+
+======================================================================*/
+
+void parse_cis(FILE *f)
+{
+    current_lineno = 1;
+    yyrestart(f);
+    yyparse();
+    fclose(f);
+}
+
Index: oldkernel/linux/pcmcia-cs-3.1.15/debug-tools/lspnp.c
diff -u /dev/null linux/pcmcia-cs-3.1.15/debug-tools/lspnp.c:1.1
--- /dev/null	Mon Jul 31 21:15:10 2000
+++ linux/pcmcia-cs-3.1.15/debug-tools/lspnp.c	Fri Jul  7 16:34:58 2000
@@ -0,0 +1,605 @@
+/*======================================================================
+
+    A utility for dumping resource information for PnP devices
+
+    lspnp.c 1.5 1999/10/25 19:58:00
+
+    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@pcmcia.sourceforge.org>.  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.
+
+    Usage:
+
+    lspnp [-b] [-v[v]] [device #]
+
+======================================================================*/
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <string.h>
+#include <endian.h>
+#include <ctype.h>
+#include <asm/types.h>
+
+#include <linux/pnp_resource.h>
+
+static int verbose = 0, boot = 0;
+
+static struct {
+    __u8	base;
+    char *	name;
+} base_type[] = {
+    { 1, "mass storage device" },
+    { 2, "network interface controller" },
+    { 3, "display controller" },
+    { 4, "multimedia controller" },
+    { 5, "memory controller" },
+    { 6, "bridge controller" },
+    { 7, "communications device" },
+    { 8, "system peripheral" },
+    { 9, "input device" },
+    { 10, "service processor" }
+};
+#define NBASE	(sizeof(base_type)/sizeof(base_type[0]))
+
+static struct {
+    __u8	base, sub;
+    char *	name;
+} sub_type[] = {
+    { 1, 0, "SCSI" },
+    { 1, 1, "IDE" },
+    { 1, 2, "floppy" },
+    { 1, 3, "IPI" },
+    { 2, 0, "ethernet" },
+    { 2, 1, "token ring" },
+    { 2, 2, "FDDI" },
+    { 3, 0, "VGA" },
+    { 3, 1, "SVGA" },
+    { 3, 2, "XGA" },
+    { 4, 0, "video" },
+    { 4, 1, "audio" },
+    { 5, 0, "RAM" },
+    { 5, 1, "flash" },
+    { 6, 0, "host processor" },
+    { 6, 1, "ISA" },
+    { 6, 2, "EISA" },
+    { 6, 3, "MicroChannel" },
+    { 6, 4, "PCI" },
+    { 6, 5, "PCMCIA" },
+    { 6, 6, "VME" },
+    { 7, 0, "RS-232" },
+    { 7, 1, "AT parallel port" },
+    { 8, 0, "programmable interrupt controller" },
+    { 8, 1, "DMA controller" },
+    { 8, 2, "system timer" },
+    { 8, 3, "real time clock" },
+    { 8, 4, "L2 cache" },
+    { 8, 5, "NVRAM" },
+    { 8, 6, "power management" },
+    { 8, 7, "CMOS" },
+    { 8, 8, "operator panel" },
+    { 9, 0, "keyboard" },
+    { 9, 1, "digitizer" },
+    { 9, 2, "mouse" },
+    { 9, 3, "tablet" },
+    { 10, 0, "general memory" }
+};
+#define NSUB	(sizeof(sub_type)/sizeof(sub_type[0]))
+
+static struct eisa_id {
+    char	id[8];
+    char *	name;
+    struct eisa_id * next;
+} *eisa_id = NULL;
+
+#define swap16(n) ((((n)&0x00ff)<<8) | (((n)&0xff00)>>8))
+#define swap32(n) \
+    ((((n)&0xff000000)>>24) | (((n)&0x00ff0000)>>8) | \
+     (((n)&0x0000ff00)<<8)  | (((n)&0x000000ff)<<24))
+
+#if (__BYTE_ORDER == _BIG_ENDIAN)
+#define flip16(n)	swap16(n)
+#define flip32(n)	swap32(n)
+#else
+#define flip16(n)	(n)
+#define flip32(n)	(n)
+#endif
+
+/*====================================================================*/
+
+#define HEX(id,a) hex[((id)>>a) & 15]
+#define CHAR(id,a) (0x40 + (((id)>>a) & 31))
+
+static char *eisa_str(__u32 id)
+{
+    const char *hex = "0123456789abcdef";
+    static char str[8];
+    id = swap32(id);
+    str[0] = CHAR(id, 26);
+    str[1] = CHAR(id, 21);
+    str[2] = CHAR(id,16);
+    str[3] = HEX(id, 12);
+    str[4] = HEX(id, 8);
+    str[5] = HEX(id, 4);
+    str[6] = HEX(id, 0);
+    str[7] = '\0';
+    return str;
+}
+
+static void load_ids(void)
+{
+    char s[133], *t;
+    int n;
+    struct eisa_id *id;
+    FILE *f = fopen("/usr/share/pnp.ids", "r");
+    
+    if (f == NULL)
+	return;
+    while (fgets(s, sizeof(s), f)) {
+	if ((strlen(s) < 9) ||
+	    !(isupper(s[0]) && isupper(s[1]) && isupper(s[2]) &&
+	      isxdigit(s[3]) && isxdigit(s[4]) && isxdigit(s[5]) &&
+	      isxdigit(s[6]))) continue;
+	id = malloc(sizeof(struct eisa_id));
+	strncpy(id->id, s, 7);
+	for (n = 3; n < 7; n++)
+	    id->id[n] = tolower(id->id[n]);
+	id->id[7] = '\0';
+	s[strlen(s)-1] = '\0';
+	for (t = s+7; isspace(*t); t++) ;
+	id->name = strdup(t);
+	id->next = eisa_id; eisa_id = id;
+    }
+    fclose(f);
+}
+
+static void dump_flags(int flags)
+{
+    printf("    flags:");
+    if (!flags)
+	printf(" none");
+    if (flags & 0x0001)
+	printf(" [no disable]");
+    if (flags & 0x0002)
+	printf(" [no config]");
+    if (flags & 0x0004)
+	printf(" [output]");
+    if (flags & 0x0008)
+	printf(" [input]");
+    if (flags & 0x0010)
+	printf(" [bootable]");
+    if (flags & 0x0020)
+	printf(" [dock]");
+    if (flags & 0x0040)
+	printf(" [removable]");
+    if ((flags & 0x0180) == 0x0000)
+	printf(" [static]");
+    if ((flags & 0x0180) == 0x0080)
+	printf(" [dynamic]");
+    if ((flags & 0x0180) == 0x0180)
+	printf(" [dynamic only]");
+    printf("\n");
+}
+
+static void dump_class(int t1, int t2)
+{
+    int i;
+    for (i = 0; i < NBASE; i++)
+	if (t1 == base_type[i].base) break;
+    printf("%s: ", (i < NBASE) ? base_type[i].name : "reserved");
+    for (i = 0; i < NSUB; i++)
+	if ((t1 == sub_type[i].base) && (t2 == sub_type[i].sub))
+	    break;
+    printf("%s", (i < NSUB) ? sub_type[i].name : "other");
+}
+
+/*
+  Small resource tags
+*/
+
+static void dump_version(union pnp_small_resource *r)
+{
+    printf("\tPnP version %d.%d, vendor version %d.%d\n",
+	   r->version.pnp>>4, r->version.pnp & 0x0f,
+	   r->version.vendor>>4, r->version.vendor & 0x0f);
+}
+
+static void dump_ldid(union pnp_small_resource *r, int sz)
+{
+    printf("\tlogical ID %s", eisa_str(r->ldid.id));
+    if (verbose > 1) {
+	if (r->ldid.flag0 & PNP_RES_LDID_BOOT)
+	    printf(" [boot]");
+    }
+    printf("\n");
+}
+
+static void dump_gdid(union pnp_small_resource *r)
+{
+    struct eisa_id *eid;
+    char *eis = eisa_str(r->gdid.id);
+    
+    printf("\t%s", eis);
+    for (eid = eisa_id; eid; eid = eid->next)
+	if (strcmp(eis, eid->id) == 0) break;
+    if (eid)
+	printf(" %s\n", eid->name);
+    else
+	printf("\n");
+}
+
+static void dump_irq(union pnp_small_resource *r, int sz)
+{
+    int mask = flip16(r->irq.mask);
+    printf("\tirq ");
+    if (!mask) {
+        printf("disabled");
+    } else if (mask & (mask-1)) {
+	printf("mask 0x%04x", mask);
+    } else {
+	printf("%d", ffs(mask)-1);
+    }
+    if (verbose > 1) {
+	if (sz == 3) {
+	    if (r->irq.info & PNP_RES_IRQ_HIGH_EDGE)
+		printf(" [high edge]");
+	    if (r->irq.info & PNP_RES_IRQ_LOW_EDGE)
+		printf(" [low edge]");
+	    if (r->irq.info & PNP_RES_IRQ_HIGH_LEVEL)
+		printf(" [high level]");
+	    if (r->irq.info & PNP_RES_IRQ_LOW_LEVEL)
+		printf(" [low level]");
+	} else {
+	    printf(" [high edge]");
+	}
+    }
+    printf("\n");
+}
+
+static void dump_dma(union pnp_small_resource *r)
+{
+    int mask = r->dma.mask;
+    printf("\tdma ");
+    if (!mask) {
+        printf("disabled");
+    } else if (mask & (mask-1)) {
+	printf("mask 0x%04x", mask);
+    } else {
+	printf("%d", ffs(mask)-1);
+    }
+    if (verbose > 1) {
+	switch (r->dma.info & PNP_RES_DMA_WIDTH_MASK) {
+	case PNP_RES_DMA_WIDTH_8:
+	    printf(" [8 bit]"); break;
+	case PNP_RES_DMA_WIDTH_8_16:
+	    printf(" [8/16 bit]"); break;
+	case PNP_RES_DMA_WIDTH_16:
+	    printf(" [16 bit]"); break;
+	}
+	if (r->dma.info & PNP_RES_DMA_BUSMASTER)
+	    printf(" [master]");
+	if (r->dma.info & PNP_RES_DMA_COUNT_BYTE)
+	    printf(" [count byte]");
+	if (r->dma.info & PNP_RES_DMA_COUNT_WORD)
+	    printf(" [count word]");
+	switch (r->dma.info & PNP_RES_DMA_SPEED_MASK) {
+	case PNP_RES_DMA_SPEED_COMPAT: printf(" [compat]"); break;
+	case PNP_RES_DMA_SPEED_TYPEA: printf(" [type A]"); break;
+	case PNP_RES_DMA_SPEED_TYPEB: printf(" [type B]"); break;
+	case PNP_RES_DMA_SPEED_TYPEF: printf(" [type F]"); break;
+	}
+    }
+    printf("\n");
+}
+
+static void dump_dep_start(union pnp_small_resource *r, int sz)
+{
+    printf("\t[start dep fn");
+    if (sz) {
+	printf(": priority: ");
+	switch (r->dep_start.priority) {
+	case PNP_RES_CONFIG_GOOD:
+	    printf("good"); break;
+	case PNP_RES_CONFIG_ACCEPTABLE:
+	    printf("acceptable"); break;
+	case PNP_RES_CONFIG_SUBOPTIMAL:
+	    printf("suboptimal"); break;
+	default:
+	    printf("reserved"); break;
+	}
+    }
+    printf("]\n");
+}
+
+static void dump_dep_end(union pnp_small_resource *r)
+{
+    printf("\t[end dep fn]\n");
+}
+
+static void dump_io(union pnp_small_resource *r)
+{
+    int min = flip16(r->io.min), max = flip16(r->io.max);
+    printf("\tio ");
+    if (r->io.len == 0)
+	printf("disabled");
+    else if (min == max)
+	printf("0x%04x-0x%04x", min, min+r->io.len-1);
+    else
+	printf("base 0x%04x-0x%04x align 0x%02x len 0x%02x",
+	       min, max, r->io.align, r->io.len);
+    if (verbose > 1) {
+	if (r->io.info & PNP_RES_IO_DECODE_16)
+	    printf(" [16-bit decode]");
+    }
+    printf("\n");
+}
+
+static void dump_io_fixed(union pnp_small_resource *r)
+{
+    int base = flip16(r->io_fixed.base);
+    printf("\tio ");
+    if (r->io_fixed.len == 0)
+	printf("disabled\n");
+    else
+	printf("0x%04x-0x%04x\n", base, base+r->io_fixed.len-1);
+}
+
+/*
+  Large resource tags
+*/
+
+static void dump_mem_info(__u8 info)
+{
+    switch (info & PNP_RES_MEM_WIDTH_MASK) {
+    case PNP_RES_MEM_WIDTH_8:
+	printf(" [8 bit]"); break;
+    case PNP_RES_MEM_WIDTH_16:
+	printf(" [16 bit]"); break;
+    case PNP_RES_MEM_WIDTH_8_16:
+	printf(" [8/16 bit]"); break;
+    case PNP_RES_MEM_WIDTH_32:
+	printf(" [32 bit]"); break;
+    }
+    printf((info & PNP_RES_MEM_WRITEABLE) ? " [r/w]" : " [r/o]");
+    if (info & PNP_RES_MEM_CACHEABLE)
+	printf(" [cacheable]");
+    if (info & PNP_RES_MEM_HIGH_ADDRESS)
+	printf(" [high]");
+    if (info & PNP_RES_MEM_SHADOWABLE)
+	printf(" [shadow]");
+    if (info & PNP_RES_MEM_EXPANSION_ROM)
+	printf(" [rom]");
+}
+
+static void dump_ansi(union pnp_large_resource *r, int sz)
+{
+    printf("\tidentifier '%*s'\n", sz, r->ansi.str);
+}
+
+static void dump_mem(union pnp_large_resource *r)
+{
+    int min = flip16(r->mem.min) << 8;
+    int max = flip16(r->mem.max) << 8;
+    int align = flip16(r->mem.align), len = flip16(r->mem.len);
+    printf("\tmem ");
+    if (len == 0)
+	printf("disabled");
+    else if (min == max)
+	printf("0x%06x-0x%06x", min, min+len-1);
+    else
+	printf("base 0x%06x-%06x, align 0x%04x, len 0x%06x",
+	       min, max, align ? align : 0x10000, len<<8);
+    if (verbose > 1)
+	dump_mem_info(r->mem.info);
+    printf("\n");
+}
+
+static void dump_mem32(union pnp_large_resource *r)
+{
+    u_int min = flip32(r->mem32.min), max = flip32(r->mem32.max);
+    u_int align = flip32(r->mem32.align), len = flip32(r->mem32.len);
+    printf("\tmem ");
+    if (len == 0)
+	printf("disabled");
+    else if (min == max)
+	printf("0x%08x-0x%08x", min, min+len-1);
+    else
+	printf("\tmem base 0x%08x-0x%08x align 0x%06x len 0x%06x",
+	   min, max, align, len);
+    if (verbose > 1)
+	dump_mem_info(r->mem32.info);
+    printf("\n");
+}
+
+static void dump_mem32_fixed(union pnp_large_resource *r)
+{
+    u_int base = flip32(r->mem32_fixed.base);
+    u_int len = flip32(r->mem32_fixed.len);
+    printf("\tmem ");
+    if (len == 0)
+	printf("disabled");
+    else
+	printf("0x%08x-0x%08x", base, base+len-1);
+    if (verbose > 1)
+	dump_mem_info(r->mem32_fixed.info);
+    printf("\n");
+}
+
+/*====================================================================*/
+
+static char *dump_chain(u_char *buf, int nr)
+{
+    union pnp_resource *p = (union pnp_resource *)buf;
+    int tag = 0, sz;
+    
+    while (((u_char *)p < buf+nr) && (tag != PNP_RES_SMTAG_END)) {
+	if (p->lg.tag & PNP_RES_LARGE_ITEM) {
+	    union pnp_large_resource *r = &p->lg.d;
+	    tag = p->lg.tag & ~PNP_RES_LARGE_ITEM;
+	    sz = flip16(p->lg.sz) + 2;
+	    switch (tag) {
+	    case PNP_RES_LGTAG_MEM:
+		dump_mem(r); break;
+	    case PNP_RES_LGTAG_ID_ANSI:
+		dump_ansi(r, sz); break;
+	    case PNP_RES_LGTAG_ID_UNICODE:
+		/* dump_unicode(r); */ break;
+	    case PNP_RES_LGTAG_MEM32:
+		dump_mem32(r); break;
+	    case PNP_RES_LGTAG_MEM32_FIXED:
+		dump_mem32_fixed(r); break;
+	    }
+	} else {
+	    union pnp_small_resource *r = &p->sm.d;
+	    tag = (p->sm.tag >> 3); sz = (p->sm.tag & 7);
+	    switch (tag) {
+	    case PNP_RES_SMTAG_VERSION:
+		dump_version(r); break;
+	    case PNP_RES_SMTAG_LDID:
+		dump_ldid(r, sz); break;
+	    case PNP_RES_SMTAG_CDID:
+		dump_gdid(r); break;
+	    case PNP_RES_SMTAG_IRQ:
+		dump_irq(r, sz); break;
+	    case PNP_RES_SMTAG_DMA:
+		dump_dma(r); break;
+	    case PNP_RES_SMTAG_DEP_START:
+		dump_dep_start(r, sz); break;
+	    case PNP_RES_SMTAG_DEP_END:
+		dump_dep_end(r); break;
+	    case PNP_RES_SMTAG_IO:
+		dump_io(r); break;
+	    case PNP_RES_SMTAG_IO_FIXED:
+		dump_io_fixed(r); break;
+	    }
+	}
+	(u_char *)p += sz + 1;
+    }
+    return (u_char *)p;
+}
+
+static void dump_resources(int num)
+{
+    char fn[40];
+    u_char buf[4096], *p;
+    int fd, nr;
+    
+    sprintf(fn, "/proc/bus/pnp/%s%02x", (boot ? "boot/" : ""), num);
+    fd = open(fn, O_RDONLY);
+    nr = read(fd, buf, sizeof(buf));
+    close(fd);
+    if (nr > 0) {
+	if (verbose > 1)
+	    printf("    allocated resources:\n");
+	p = dump_chain(buf, nr);
+	if (verbose > 1) {
+	    if (p+4 < buf+nr) {
+		printf("    possible resources:\n");
+	    }
+	    p = dump_chain(p, nr);
+	    if (p+2 < buf+nr) {
+		printf("    compatible devices:\n");
+		p = dump_chain(p, nr);
+	    }
+	}
+    }
+}
+
+static int dump_basic(int match)
+{
+    int id, num, t1, t2, t3, flags;
+    struct eisa_id *eid;
+    char *eis, buf[64];
+    FILE *f;
+
+    f = fopen("/proc/bus/pnp/devices", "r");
+    if (f == NULL) {
+	fprintf(stderr, "lspnp: /proc/bus/pnp not available\n");
+	return -1;
+    }
+    while (fgets(buf, 63, f) != NULL) {
+	sscanf(buf, "%x %x %x:%x:%x %x", &num, &id, &t1, &t2, &t3, &flags);
+	if ((match >= 0) && (match != num))
+	    continue;
+	eis = eisa_str(id);
+	printf("%02x %7s ", num, eis);
+	for (eid = eisa_id; eid; eid = eid->next)
+	    if (strcmp(eis, eid->id) == 0) break;
+	if (eid)
+	    printf("%s", eid->name);
+	else
+	    dump_class(t1, t2);
+	printf("\n");
+	if (verbose > 1)
+	    dump_flags(flags);
+	if (verbose) {
+	    dump_resources(num);
+	    if (match < 0) printf("\n");
+	}
+    }
+    fclose(f);
+    return 0;
+}
+
+/*====================================================================*/
+
+void usage(char *name)
+{
+    fprintf(stderr, "usage: %s [-b] [-v[v]] [device #]\n", name);
+    exit(EXIT_FAILURE);
+}
+    
+int main(int argc, char *argv[])
+{
+    int optch, errflg = 0;
+    char *s;
+    
+    while ((optch = getopt(argc, argv, "bv")) != -1) {
+	switch (optch) {
+	case 'b':
+	    boot++; break;
+	case 'v':
+	    verbose++; break;
+	default:
+	    errflg = 1; break;
+	}
+    }
+    if (errflg)
+	usage(argv[0]);
+    load_ids();
+    if (optind < argc) {
+	while (optind < argc) {
+	    int i = strtoul(argv[optind], &s, 16);
+	    if ((argv[optind] == '\0') || (*s != '\0'))
+		usage(argv[0]);
+	    if (dump_basic(i) != 0)
+		return EXIT_FAILURE;
+	    optind++;
+	}
+	return EXIT_SUCCESS;
+    }
+    return dump_basic(-1);
+}
Index: oldkernel/linux/pcmcia-cs-3.1.15/debug-tools/pack_cis.c
diff -u /dev/null linux/pcmcia-cs-3.1.15/debug-tools/pack_cis.c:1.1
--- /dev/null	Mon Jul 31 21:15:10 2000
+++ linux/pcmcia-cs-3.1.15/debug-tools/pack_cis.c	Fri Jul  7 16:34:58 2000
@@ -0,0 +1,439 @@
+/*======================================================================
+
+    A utility to convert a plain text description of a Card
+    Information Structure into its packed binary representation.
+
+    pack_cis.c 1.15 2000/01/25 02:29:52
+
+    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@pcmcia.sourceforge.org>.  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.
+
+    Usage:
+
+    pack_cis [-o outfile] [infile]
+
+    [infile] defaults to stdin, and [outfile] defaults to stdout.
+    
+======================================================================*/
+
+#include <sys/types.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <getopt.h>
+#include <errno.h>
+
+#include <pcmcia/cs_types.h>
+#include <pcmcia/cs.h>
+#include <pcmcia/cistpl.h>
+
+#include "pack_cis.h"
+
+tuple_info_t *cis_root = NULL, *mfc[8] = { NULL };
+int nf = 0;
+
+/*======================================================================
+
+    Support routines for packing parts of configuration table entries
+    
+======================================================================*/
+
+static u_int mantissa[] = {
+    10, 12, 13, 15, 20, 25, 30, 35,
+    40, 45, 50, 55, 60, 70, 80, 90
+};
+static int pack_power(cistpl_power_t *pwr, u_char *b)
+{
+    u_int tmp, i;
+    u_char m, e, x, *c = b;
+    *c = pwr->present; c++;
+    for (i = 0; i < 7; i++) {
+	if (!(pwr->present & (1<<i)))
+	    continue;
+	tmp = pwr->param[i];
+	for (e = 1; ((tmp % 10) == 0) || (tmp > 999); e++)
+	    tmp /= 10;
+	if (tmp < 100) {
+	    if (tmp < 10) { tmp *= 10; e--; }
+	    for (m = 0; m < 16; m++)
+		if (mantissa[m] == tmp) break;
+	    if (m == 16) { tmp *= 10; e--; }
+	    x = 0;
+	}
+	if (tmp >= 100) {
+	    e++;
+	    x = (tmp/10) - ((tmp/10) % 10);
+	    for (m = 0; m < 16; m++)
+		if (mantissa[m] == x) break;
+	    x = (u_char)(tmp - 10*(u_int)x);
+	}
+	*c = (m<<3) | e | (x ? 0x80 : 0); c++;
+	if (x) { *c = x; c++; }
+    }
+    return c-b;
+}
+
+static int pack_io(cistpl_io_t *p, u_char *b)
+{
+    u_char *c = b;
+    u_int i, j, ml, ma;
+    *c = p->flags & (CISTPL_IO_8BIT|CISTPL_IO_16BIT);
+    if ((p->nwin == 1) && (p->win[0].base == 0)) {
+	for (i = 1, j = 0; i < p->win[0].len; i *= 2, j++) ;
+	*c |= j; c++;
+    } else {
+	for (i = ma = ml = 0; i < p->nwin; i++) {
+	    ma |= p->win[i].base;
+	    ml |= p->win[i].len-1;
+	}
+	ma = (ma > 0xffff) ? 3 : ((ma > 0xff) ? 2 : 1);
+	ml = (ml > 0xffff) ? 3 : ((ml > 0xff) ? 2 : 1);
+	*c |= 0x80 | (p->flags & CISTPL_IO_LINES_MASK); c++;
+	*c = (p->nwin-1) | (ma<<4) | (ml<<6); c++;
+	if (ma == 3) ma++; if (ml == 3) ml++;
+	for (i = 0; i < p->nwin; i++) {
+	    for (j = 0; j < ma; j++) {
+		*c = (p->win[i].base >> (8*j)) & 0xff; c++;
+	    }
+	    for (j = 0; j < ml; j++) {
+		*c = ((p->win[i].len-1) >> (8*j)) & 0xff; c++;
+	    }
+	}
+    }
+    return c-b;
+}
+
+static int pack_mem(cistpl_mem_t *p, u_char *b)
+{
+    u_char *c = b;
+    u_int i, j, ml, ma, ha;
+    for (i = ma = ml = ha = 0; i < p->nwin; i++) {
+	ma |= p->win[i].card_addr;
+	ml |= p->win[i].len;
+	ha |= p->win[i].host_addr;
+    }
+    ma = (ma|ha) >> 8; ml >>= 8;
+    ma = (ma > 0xffff) ? 3 : ((ma > 0xff) ? 2 : 1);
+    ml = (ml > 0xffff) ? 3 : ((ml > 0xff) ? 2 : 1);
+    *c = (p->nwin-1) | (ma<<5) | (ml<<3) | (ha ? 0x80 : 0); c++;
+    for (i = 0; i < p->nwin; i++) {
+	for (j = 1; j <= ml; j++) {
+	    *c = (p->win[i].len >> (8*j)) & 0xff; c++;
+	}
+	for (j = 1; j <= ma; j++) {
+	    *c = (p->win[i].card_addr >> (8*j)) & 0xff; c++;
+	}
+	if (ha)
+	    for (j = 1; j <= ma; j++) {
+		*c = (p->win[i].host_addr >> (8*j)) & 0xff; c++;
+	    }
+    }
+    return c-b;
+}
+
+static int pack_irq(cistpl_irq_t *p, u_char *b)
+{
+    b[0] = p->IRQInfo1;
+    if (p->IRQInfo1 & IRQ_INFO2_VALID) {
+	b[1] = p->IRQInfo2 & 0xff;
+	b[2] = (p->IRQInfo2 >> 8) & 0xff;
+	return 3;
+    }
+    return 1;
+}
+
+static void pack_cftable(cistpl_cftable_entry_t *p, u_char *b)
+{
+    u_char *c;
+    b[2] = p->index | 0x80;
+    if (p->flags & CISTPL_CFTABLE_DEFAULT)
+	b[2] |= 0x40;
+    b[3] = 0x01;
+    b[3] |= (p->flags & CISTPL_CFTABLE_BVDS) ? 0x10 : 0;
+    b[3] |= (p->flags & CISTPL_CFTABLE_WP) ? 0x20 : 0;
+    b[3] |= (p->flags & CISTPL_CFTABLE_RDYBSY) ? 0x40 : 0;
+    b[3] |= (p->flags & CISTPL_CFTABLE_MWAIT) ? 0x80 : 0;
+    b[4] = 0;
+    c = b+5;
+    if (p->vcc.present) {
+	b[4]++; c += pack_power(&p->vcc, c);
+	if (p->vpp1.present) {
+	    b[4]++; c += pack_power(&p->vpp1, c);
+	    if (p->vpp2.present) {
+		b[4]++; c += pack_power(&p->vpp2, c);
+	    }
+	}
+    }
+    if (p->io.nwin > 0) {
+	b[4] |= 0x08;
+	c += pack_io(&p->io, c);
+    }
+    if (p->irq.IRQInfo1 > 0) {
+	b[4] |= 0x10;
+	c += pack_irq(&p->irq, c);
+    }
+    if (p->mem.nwin > 0) {
+	b[4] |= 0x60;
+	c += pack_mem(&p->mem, c);
+    }
+    if (p->flags >> 8) {
+	b[4] |= 0x80;
+	*c++ = p->flags >> 8;
+    }
+    b[1] = c-b-2;
+}
+
+/*======================================================================
+
+    Routines for packing device info tuples
+    
+======================================================================*/
+
+static int pack_speed(u_int speed, u_char *b)
+{
+    u_char e, m, *c = b;
+    switch (speed) {
+    case 0:	*c |= 0; c++; break;
+    case 250:	*c |= 1; c++; break;
+    case 200:	*c |= 2; c++; break;
+    case 150:	*c |= 3; c++; break;
+    case 100:	*c |= 4; c++; break;
+    default:
+	*c |= 7; c++;
+	for (e = 1; speed > 80; e++)
+	    speed /= 10;
+	for (m = 0; m < 15; m++)
+	    if (mantissa[m] >= speed) break;
+	*c = ((m+1)<<3) | e; c++;
+    }
+    return c-b;
+}
+
+static void pack_device(cistpl_device_t *d, u_char *b)
+{
+    u_int i, sz;
+    u_char e, *c = b+2;
+    for (i = 0; i < d->ndev; i++) {
+	*c = (d->dev[i].type<<4);
+	c += pack_speed(d->dev[i].speed, c);
+	sz = d->dev[i].size/512;
+	for (e = 0; sz > 32; e++)
+	    sz /= 4;
+	*c = (e & 7) | ((sz-1) << 3); c++;
+    }
+    *c = 0xff; c++;
+    b[1] = c-b-2;
+}
+
+/*======================================================================
+
+    For now, I only implement a subset of tuples types, intended to be
+    enough to handle most IO-oriented cards.
+    
+======================================================================*/
+
+static int pack_tuple(tuple_info_t *t, u_char *b)
+{
+    cisparse_t *p = t->parse;
+    u_int i, m;
+    u_char *c;
+
+    *b = t->type;
+    switch (t->type) {
+    case CISTPL_DEVICE:
+    case CISTPL_DEVICE_A:
+	if (p) {
+	    pack_device(&p->device, b);
+	} else {
+	    /* Fake null device tuple */
+	    b[1] = 3; b[2] = 0; b[3] = 0; b[4] = 0xff;
+	}
+	break;
+    case CISTPL_MANFID:
+	b[1] = 4;
+	b[2] = p->manfid.manf & 0xff;
+	b[3] = p->manfid.manf >> 8;
+	b[4] = p->manfid.card & 0xff;
+	b[5] = p->manfid.card >> 8;
+	break;
+    case CISTPL_FUNCID:
+	b[1] = 2;
+	b[2] = p->funcid.func;
+	b[3] = p->funcid.sysinit;
+	break;
+    case CISTPL_CONFIG:
+	b[3] = p->config.last_idx;
+	i = p->config.base;
+	for (c = b+4, m = 0; (i > 0) || !m; i >>= 8, m++) {
+	    c[m] = i & 0xff;
+	}
+	b[2] = m-1;
+	i = p->config.rmask[0];
+	for (c = c+m, m = 0; (i > 0) || !m; i >>= 8, m++) {
+	    c[m] = i & 0xff;
+	}
+	b[2] |= ((m-1) << 2);
+	b[1] = c+m-b-2;
+	break;
+    case CISTPL_VERS_1:
+	b[2] = p->version_1.major;
+	b[3] = p->version_1.minor;
+	c = b+4;
+	for (i = 0; i < p->version_1.ns; i++) {
+	    strcpy((char *)c, p->version_1.str+p->version_1.ofs[i]);
+	    c += strlen((char *)c) + 1;
+	}
+	for (; i < 4; i++) { *c = 0; c++; }
+	*c = 0xff; c++;
+	b[1] = c-b-2;
+	break;
+    case CISTPL_CFTABLE_ENTRY:
+	pack_cftable(&p->cftable_entry, b);
+	break;
+    case CISTPL_LINKTARGET:
+	b[1] = 3; b[2] = 'C'; b[3] = 'I'; b[4] = 'S';
+	break;
+    case CISTPL_NO_LINK:
+    case CISTPL_END:
+	b[1] = 0;
+	break;
+    }
+    return b[1]+2;
+}
+
+/*======================================================================
+
+    The following routines handle parsing of aggregates of tuples.
+    pack_chain() is the simplest: just return a string of tuples and
+    terminate with an END tuple.  pack_mfc() is used to tie the
+    function-specific tuple chains for a multifunction card together
+    using a LONGLINK_MFC tuple.  And pack_cis() handles a complete
+    CIS, whether it is multifunction or not.
+    
+======================================================================*/
+
+static int pack_chain(tuple_info_t *t, u_char *b)
+{
+    int n = 0;
+    tuple_info_t end = { CISTPL_END, NULL, NULL };
+    while (t) {
+	n += pack_tuple(t, b+n);
+	t = t->next;
+    }
+    n += pack_tuple(&end, b+n);
+    return n;
+}
+
+static int pack_mfc(u_int ofs, u_char *b)
+{
+    u_int i, j, pos;
+    tuple_info_t target = { CISTPL_LINKTARGET, NULL, NULL };
+    
+    b[0] = CISTPL_LONGLINK_MFC;
+    b[1] = 5*nf + 1;
+    b[2] = nf;
+    b[5*nf+3] = CISTPL_END;
+    b[5*nf+4] = 0;
+    /* Leave space for this tuple and the CISTPL_END tuple */
+    pos = 5*nf+5;
+    for (i = 0; i < nf; i++) {
+	b[3+i*5] = 0;
+	for (j = 0; j < 4; j++)
+	    b[4+i*5+j] = ((ofs+pos) >> (8*j)) & 0xff;
+	pos += pack_tuple(&target, b+pos);
+	pos += pack_chain(mfc[i], b+pos);
+    }
+    return ofs+pos;
+}
+
+static int pack_cis(tuple_info_t *t, u_char *b)
+{
+    int n = 0;
+    tuple_info_t device = { CISTPL_DEVICE, NULL, NULL };
+    tuple_info_t nolink = { CISTPL_NO_LINK, NULL, NULL };
+    tuple_info_t end = { CISTPL_END, NULL, NULL };
+    if (t->type != CISTPL_DEVICE)
+	n = pack_tuple(&device, b);
+    while (t) {
+	n += pack_tuple(t, b+n);
+	t = t->next;
+    }
+    if (nf > 0) {
+	n = pack_mfc(n, b+n);
+    } else {
+	n += pack_tuple(&nolink, b+n);
+	n += pack_tuple(&end, b+n);
+    }
+     return n;
+}
+
+/*====================================================================*/
+
+int main(int argc, char *argv[])
+{
+    int optch, errflg = 0;
+    char *out = NULL;
+    u_char buf[1024];
+    int n;
+    FILE *f;
+
+    while ((optch = getopt(argc, argv, "o:")) != -1) {
+	switch (optch) {
+	case 'o':
+	    out = strdup(optarg); break;
+	default:
+	    errflg = 1; break;
+	}
+    }
+    if (errflg || (optind < argc-1)) {
+	fprintf(stderr, "usage: %s [-o outfile] [infile]\n",
+		argv[0]);
+	exit(EXIT_FAILURE);
+    }
+    if (optind < argc) {
+	f = fopen(argv[optind], "r");
+	if (!f) {
+	    fprintf(stderr, "could not open '%s': %s\n", argv[optind],
+		    strerror(errno));
+	    return -1;
+	}
+    } else
+	f = stdin;
+    parse_cis(f);
+    fclose(f);
+    n = pack_cis(cis_root, buf);
+    if (out) {
+	f = fopen(out, "w");
+	if (!f) {
+	    fprintf(stderr, "could not open '%s': %s\n", out,
+		    strerror(errno));
+	    return -1;
+	}
+    } else f = stdout;
+    fwrite(buf, n, 1, f);
+    fclose(f);
+    
+    return 0;
+}
Index: oldkernel/linux/pcmcia-cs-3.1.15/debug-tools/pack_cis.h
diff -u /dev/null linux/pcmcia-cs-3.1.15/debug-tools/pack_cis.h:1.1
--- /dev/null	Mon Jul 31 21:15:10 2000
+++ linux/pcmcia-cs-3.1.15/debug-tools/pack_cis.h	Fri Jul  7 16:34:58 2000
@@ -0,0 +1,38 @@
+/*
+ * pack_cis.h 1.5 1999/10/25 19:57: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@pcmcia.sourceforge.org>.  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.
+ */
+typedef struct tuple_info_t {
+    u_char		type;
+    cisparse_t		*parse;
+    struct tuple_info_t	*next;
+} tuple_info_t;
+
+extern tuple_info_t *cis_root, *mfc[8];
+extern int nf;
+
+void parse_cis(FILE *f);
Index: oldkernel/linux/pcmcia-cs-3.1.15/debug-tools/pnp.ids
diff -u /dev/null linux/pcmcia-cs-3.1.15/debug-tools/pnp.ids:1.1
--- /dev/null	Mon Jul 31 21:15:10 2000
+++ linux/pcmcia-cs-3.1.15/debug-tools/pnp.ids	Fri Jul  7 16:34:58 2000
@@ -0,0 +1,567 @@
+#--Interrupt Controllers--
+PNP0000  AT programmable interrupt controller
+PNP0001  EISA programmable interrupt controller
+PNP0002  MCA programmable interrupt controller
+PNP0003  Advanced programmable interrupt controller
+PNP0004  Cyrix SLiC MP interrupt controller
+
+#--Timers--
+PNP0100  AT system timer
+PNP0101  EISA system timer
+PNP0102  MCA system timer
+
+#--DMA--
+PNP0200  AT DMA controller
+PNP0201  EISA DMA controller
+PNP0202  MCA DMA controller
+
+#--Keyboards--
+PNP0300  IBM PC/XT keyboard controller (83-key)
+PNP0301  IBM PC/AT keyboard controller (86-key)
+PNP0302  IBM PC/XT keyboard controller (84-key)
+PNP0303  IBM enhanced keyboard (101/102-key, PS/2 mouse support)
+PNP0304  Olivetti keyboard (83-key)
+PNP0305  Olivetti keyboard (102-key)
+PNP0306  Olivetti keyboard (86-key)
+PNP0307  Microsoft Windows(R) keyboard
+PNP0308  General Input Device Emulation Interface (GIDEI) legacy
+PNP0309  Olivetti keyboard (A101/102 key)
+PNP030A  AT&T 302 keyboard
+PNP030B  Reserved by Microsoft
+PNP0320  Japanese 106-key keyboard A01
+PNP0321  Japanese 101-key keyboard
+PNP0322  Japanese AX keyboard
+PNP0323  Japanese 106-key keyboard 002/003
+PNP0324  Japanese 106-key keyboard 001
+PNP0325  Japanese Toshiba desktop keyboard
+PNP0326  Japanese Toshiba laptop keyboard
+PNP0327  Japanese Toshiba notebook keyboard
+PNP0340  Korean 84-key keyboard
+PNP0341  Korean 86-key keyboard
+PNP0342  Korean enhanced keyboard
+PNP0343  Korean enhanced keyboard 101b
+PNP0343  Korean enhanced keyboard 101c
+PNP0344  Korean enhanced keyboard 103
+
+#--Parallel Devices--
+PNP0400  Standard LPT printer port
+PNP0401  ECP printer port
+
+#--Serial Devices--
+PNP0500  Standard PC COM port
+PNP0501  16550A-compatible COM port
+PNP0502  Multiport serial device (non-intelligent 16550)
+PNP0510  Generic IRDA-compatible device
+PNP0511  Generic IRDA-compatible device
+
+#--Disk Controllers--
+PNP0600  Generic ESDI/IDE/ATA compatible hard disk controller
+PNP0601  Plus Hardcard II
+PNP0602  Plus Hardcard IIXL/EZ
+PNP0603  Generic IDE supporting Microsoft Device Bay Specification
+PNP0680  Standard bus mastering IDE hard disk controller
+PNP0683  Standard bus mastering IDE controller (no serialization)
+PNP0700  PC standard floppy disk controller
+PNP0701  Standard floppy controller supporting MS Device Bay Spec
+
+#--Compatibility with early device ID list--
+PNP0802  Microsoft Sound System compatible device
+
+#--Display Adapters--
+PNP0900  VGA-compatible display adapter
+PNP0901  Video Seven VRAM/VRAM II/1024i 
+PNP0902  8514/A Compatible
+PNP0903  Trident VGA
+PNP0904  Cirrus Logic Laptop VGA
+PNP0905  Cirrus Logic VGA
+PNP0906  Tseng ET4000
+PNP0907  Western Digital VGA
+PNP0908  Western Digital Laptop VGA
+PNP0909  S3 Inc. 911/924
+PNP090A  ATI Ultra Pro/Plus (Mach 32)
+PNP090B  ATI Ultra (Mach 8)
+PNP090C  XGA Compatible
+PNP090D  ATI VGA Wonder
+PNP090E  Weitek P9000 Graphics Adapter
+PNP090F  Oak Technology VGA
+PNP0910  Compaq QVision
+PNP0911  XGA/2
+PNP0912  Tseng Labs W32/W32i/W32p
+PNP0913  S3 Inc. 801/928/964
+PNP0914  Cirrus Logic 5429/5434 (memory mapped)
+PNP0915  Compaq Advanced VGA (AVGA)
+PNP0916  ATI Ultra Pro Turbo (Mach64)
+PNP0917  Reserved by Microsoft
+PNP0918  Matrox MGA
+PNP0919  Compaq QVision 2000
+PNP091A  Tseng W128
+PNP0930  Chips & Technologies Super VGA
+PNP0931  Chips & Technologies Accelerator
+PNP0940  NCR 77c22e Super VGA
+PNP0941  NCR 77c32blt
+PNP09FF  Plug and Play Monitors (VESA DDC)
+
+#--Peripheral Buses--
+PNP0A00  ISA bus
+PNP0A01  EISA bus
+PNP0A02  MCA bus
+PNP0A03  PCI bus
+PNP0A04  VESA/VL bus
+PNP0A05  Generic ACPI bus
+PNP0A06  Generic ACPI extended-IO bus (EIO bus)
+
+#-- Real Time Clock, BIOS, System board devices--
+PNP0800  AT-style speaker sound
+PNP0B00  AT real-time clock
+PNP0C00  Plug and Play BIOS
+PNP0C01  System board
+PNP0C02  Motherboard resources
+PNP0C03  Plug and Play BIOS event notification interrupt
+PNP0C04  Math coprocessor
+PNP0C05  APM BIOS (version independent)
+PNP0C06  Reserved for early Plug and Play BIOS
+PNP0C07  Reserved for early Plug and Play BIOS
+PNP0C08  ACPI system board hardware
+PNP0C09  ACPI embedded controller
+PNP0C0A  ACPI control method battery
+PNP0C0B  ACPI fan
+PNP0C0C  ACPI power button device
+PNP0C0D  ACPI lid device
+PNP0C0E  ACPI sleep button device
+PNP0C0F  PCI interrupt link device
+PNP0C10  ACPI system indicator device
+PNP0C11  ACPI thermal zone
+PNP0C12  Device bay controller
+PNP0C13  Plug and Play BIOS (used when ACPI mode cannot be used)
+
+#--PCMCIA Controller Chipsets--
+PNP0E00  Intel 82365-Compatible PCMCIA Controller
+PNP0E01  Cirrus Logic CL-PD6720 PCMCIA Controller
+PNP0E02  VLSI VL82C146 PCMCIA Controller
+PNP0E03  Intel 82365-compatible CardBus controller
+
+#--Mice--
+PNP0F00  Microsoft Bus Mouse
+PNP0F01  Microsoft Serial Mouse
+PNP0F02  Microsoft InPort Mouse
+PNP0F03  Microsoft PS/2-style Mouse
+PNP0F04  Mouse Systems Mouse
+PNP0F05  Mouse Systems 3-Button Mouse (COM2)
+PNP0F06  Genius Mouse (COM1)
+PNP0F07  Genius Mouse (COM2)
+PNP0F08  Logitech Serial Mouse
+PNP0F09  Microsoft BallPoint Serial Mouse
+PNP0F0A  Microsoft Plug and Play Mouse
+PNP0F0B  Microsoft Plug and Play BallPoint Mouse
+PNP0F0C  Microsoft-compatible Serial Mouse
+PNP0F0D  Microsoft-compatible InPort-compatible Mouse
+PNP0F0E  Microsoft-compatible PS/2-style Mouse
+PNP0F0F  Microsoft-compatible Serial BallPoint-compatible Mouse
+PNP0F10  Texas Instruments QuickPort Mouse
+PNP0F11  Microsoft-compatible bus mouse
+PNP0F12  Logitech PS/2-style Mouse
+PNP0F13  PS/2 port for PS/2-style mice
+PNP0F14  Microsoft Kids Mouse
+PNP0F15  Logitech bus mouse
+PNP0F16  Logitech SWIFT device
+PNP0F17  Logitech-compatible serial mouse
+PNP0F18  Logitech-compatible bus mouse
+PNP0F19  Logitech-compatible PS/2-style mouse
+PNP0F1A  Logitech-compatible SWIFT device
+PNP0F1B  HP Omnibook Mouse
+PNP0F1C  Compaq LTE Trackball PS/2-style Mouse
+PNP0F1D  Compaq LTE Trackball Serial Mouse
+PNP0F1E  Microsoft Kids Trackball Mouse
+PNP0F1F  Reserved by Microsoft Input Device Group
+PNP0F20  Reserved by Microsoft Input Device Group
+PNP0F21  Reserved by Microsoft Input Device Group
+PNP0F22  Reserved by Microsoft Input Device Group
+PNP0F23  Reserved by Microsoft Input Device Group
+PNP0FFF  Reserved by Microsoft Systems
+
+#--Network Adapters--
+PNP8001  Novell/Anthem NE3200
+PNP8004  Compaq NE3200
+PNP8006  Intel EtherExpress/32
+PNP8008  HP EtherTwist EISA LAN Adapter/32 (HP27248A)
+PNP8065  Ungermann-Bass NIUps or NIUps/EOTP
+PNP8072  DEC (DE211) EtherWorks MC/TP
+PNP8073  DEC (DE212) EtherWorks MC/TP_BNC
+PNP8078  DCA 10 Mb MCA
+PNP8074  HP MC LAN Adapter/16 TP (PC27246)
+PNP80c9  IBM Token Ring
+PNP80ca  IBM Token Ring II
+PNP80cb  IBM Token Ring II/Short
+PNP80cc  IBM Token Ring 4/16Mbs
+PNP80d3  Novell/Anthem NE1000
+PNP80d4  Novell/Anthem NE2000
+PNP80d5  NE1000 Compatible
+PNP80d6  NE2000 Compatible
+PNP80d7  Novell/Anthem NE1500T
+PNP80d8  Novell/Anthem NE2100
+PNP80dd  SMC ARCNETPC
+PNP80de  SMC ARCNET PC100, PC200
+PNP80df  SMC ARCNET PC110, PC210, PC250
+PNP80e0  SMC ARCNET PC130/E
+PNP80e1  SMC ARCNET PC120, PC220, PC260
+PNP80e2  SMC ARCNET PC270/E
+PNP80e5  SMC ARCNET PC600W, PC650W
+PNP80e7  DEC DEPCA
+PNP80e8  DEC (DE100) EtherWorks LC
+PNP80e9  DEC (DE200) EtherWorks Turbo
+PNP80ea  DEC (DE101) EtherWorks LC/TP
+PNP80eb  DEC (DE201) EtherWorks Turbo/TP
+PNP80ec  DEC (DE202) EtherWorks Turbo/TP_BNC
+PNP80ed  DEC (DE102) EtherWorks LC/TP_BNC
+PNP80ee  DEC EE101 (Built-In)
+PNP80ef  DECpc 433 WS (Built-In)
+PNP80f1  3Com EtherLink Plus
+PNP80f3  3Com EtherLink II or IITP (8 or 16-bit)
+PNP80f4  3Com TokenLink
+PNP80f6  3Com EtherLink 16
+PNP80f7  3Com EtherLink III
+PNP80f8  3Com Generic Etherlink Plug and Play Device
+PNP80fb  Thomas Conrad TC6045
+PNP80fc  Thomas Conrad TC6042
+PNP80fd  Thomas Conrad TC6142
+PNP80fe  Thomas Conrad TC6145
+PNP80ff  Thomas Conrad TC6242
+PNP8100  Thomas Conrad TC6245
+PNP8105  DCA 10 MB
+PNP8106  DCA 10 MB Fiber Optic
+PNP8107  DCA 10 MB Twisted Pair
+PNP8113  Racal NI6510
+PNP811C  Ungermann-Bass NIUpc
+PNP8120  Ungermann-Bass NIUpc/EOTP
+PNP8123  SMC StarCard PLUS (WD/8003S)
+PNP8124  SMC StarCard PLUS With On Board Hub (WD/8003SH)
+PNP8125  SMC EtherCard PLUS (WD/8003E)
+PNP8126  SMC EtherCard PLUS With Boot ROM Socket (WD/8003EBT)
+PNP8127  SMC EtherCard PLUS With Boot ROM Socket (WD/8003EB)
+PNP8128  SMC EtherCard PLUS TP (WD/8003WT)
+PNP812a  SMC EtherCard PLUS 16 With Boot ROM Socket (WD/8013EBT)
+PNP812d  Intel EtherExpress 16 or 16TP
+PNP812f  Intel TokenExpress 16/4
+PNP8130  Intel TokenExpress MCA 16/4
+PNP8132  Intel EtherExpress 16 (MCA)
+PNP8137  Artisoft AE-1
+PNP8138  Artisoft AE-2 or AE-3
+PNP8141  Amplicard AC 210/XT
+PNP8142  Amplicard AC 210/AT
+PNP814b  Everex SpeedLink /PC16 (EV2027)
+PNP8155  HP PC LAN Adapter/8 TP (HP27245)
+PNP8156  HP PC LAN Adapter/16 TP (HP27247A)
+PNP8157  HP PC LAN Adapter/8 TL (HP27250)
+PNP8158  HP PC LAN Adapter/16 TP Plus (HP27247B)
+PNP8159  HP PC LAN Adapter/16 TL Plus (HP27252)
+PNP815f  National Semiconductor Ethernode *16AT
+PNP8160  National Semiconductor AT/LANTIC EtherNODE 16-AT3
+PNP816a  NCR Token-Ring 4 Mbs ISA
+PNP816d  NCR Token-Ring 16/4 Mbs ISA
+PNP8191  Olicom 16/4 Token-Ring Adapter
+PNP81c3  SMC EtherCard PLUS Elite (WD/8003EP)
+PNP81c4  SMC EtherCard PLUS 10T (WD/8003W)
+PNP81c5  SMC EtherCard PLUS Elite 16 (WD/8013EP)
+PNP81c6  SMC EtherCard PLUS Elite 16T (WD/8013W)
+PNP81c7  SMC EtherCard PLUS Elite 16 Combo (WD/8013EW or 8013EWC)
+PNP81c8  SMC EtherElite Ultra 16
+PNP81e4  Pure Data PDI9025-32 (Token Ring)
+PNP81e6  Pure Data PDI508+ (ArcNet)
+PNP81e7  Pure Data PDI516+ (ArcNet)
+PNP81eb  Proteon Token Ring (P1390)
+PNP81ec  Proteon Token Ring (P1392)
+PNP81ed  Proteon ISA Token Ring (1340)
+PNP81ee  Proteon ISA Token Ring (1342)
+PNP81ef  Proteon ISA Token Ring (1346)
+PNP81f0  Proteon ISA Token Ring (1347)
+PNP81ff  Cabletron E2000 Series DNI
+PNP8200  Cabletron E2100 Series DNI
+PNP8209  Zenith Data Systems Z-Note
+PNP820a  Zenith Data Systems NE2000-Compatible
+PNP8213  Xircom Pocket Ethernet II
+PNP8214  Xircom Pocket Ethernet I
+PNP821d  RadiSys EXM-10
+PNP8227  SMC 3000 Series
+PNP8228  SMC 91C2 controller
+PNP8231  Advanced Micro Devices AM2100/AM1500T
+PNP8263  Tulip NCC-16
+PNP8277  Exos 105
+PNP828A  Intel '595 based Ethernet
+PNP828B  TI2000-style Token Ring
+PNP828C  AMD PCNet Family cards
+PNP828D  AMD PCNet32 (VL version)
+PNP8294  IrDA Infrared NDIS driver (Microsoft-supplied)
+PNP82bd  IBM PCMCIA-NIC
+PNP82C2  Xircom CE10
+PNP82C3  Xircom CEM2
+PNP8321  DEC Ethernet (All Types)
+PNP8323  SMC EtherCard (All Types except 8013/A)
+PNP8324  ARCNET Compatible
+PNP8326  Thomas Conrad (All Arcnet Types)
+PNP8327  IBM Token Ring (All Types)
+PNP8385  Remote Network Access Driver
+PNP8387  RNA Point-to-point Protocol Driver
+PNP8388  Reserved for Microsoft Networking components
+PNP8389  Peer IrLAN infrared driver (Microsoft-supplied)
+PNP8390  Generic network adapter
+
+#--SCSI, Proprietary CD Adapters--
+PNPA002  Future Domain 16-700 compatible controller
+PNPA003  Panasonic proprietary CD-ROM adapter (SBPro/SB16)
+PNPA01B  Trantor 128 SCSI Controller
+PNPA01D  Trantor T160 SCSI Controller
+PNPA01E  Trantor T338 Parallel SCSI controller
+PNPA01F  Trantor T348 Parallel SCSI controller
+PNPA020  Trantor Media Vision SCSI controller
+PNPA022  Always IN-2000 SCSI controller
+PNPA02B  Sony proprietary CD-ROM controller
+PNPA02D  Trantor T13b 8-bit SCSI controller
+PNPA02F  Trantor T358 Parallel SCSI controller
+PNPA030  Mitsumi LU-005 Single Speed CD-ROM controller + drive
+PNPA031  Mitsumi FX-001 Single Speed CD-ROM controller + drive
+PNPA032  Mitsumi FX-001 Double Speed CD-ROM controller + drive
+
+#--Sound/Video-capture, multimedia--
+PNPB000  Sound Blaster 1.5 sound device
+PNPB001  Sound Blaster 2.0 sound device
+PNPB002  Sound Blaster Pro sound device
+PNPB003  Sound Blaster 16 sound device
+PNPB004  Thunderboard-compatible sound device
+PNPB005  Adlib-compatible FM synthesizer device
+PNPB006  MPU401 compatible 
+PNPB007  Microsoft Windows Sound System-compatible sound device
+PNPB008  Compaq Business Audio
+PNPB009  Plug and Play Microsoft Windows Sound System Device
+PNPB00A  MediaVision Pro Audio Spectrum 
+PNPB00B  MediaVision Pro Audio 3D
+PNPB00C  MusicQuest MQX-32M
+PNPB00D  MediaVision Pro Audio Spectrum Basic
+PNPB00E  MediaVision Pro Audio Spectrum
+PNPB00F  MediaVision Jazz-16 chipset (OEM Versions)
+PNPB010  Auravision VxP500 chipset - Orchid Videola
+PNPB018  MediaVision Pro Audio Spectrum 8-bit
+PNPB019  MediaVision Pro Audio Spectrum Basic
+PNPB020  Yamaha OPL3-compatible FM synthesizer device
+PNPB02F  Joystick/Game port
+
+#--Modems--
+PNPC000  Compaq 14400 Modem (TBD)
+PNPC001  Compaq 2400/9600 Modem (TBD)
+
+#--Vendor specific--
+
+ABC1234  Intel Virtual Audio Device
+
+ACC1660  Accton EN1660 PnP LAN Card
+
+ACU0101  NCR SDMS (TM) Miniport Driver
+
+ADP1502  Adaptec AVA-1502 SCSI Host Adapter
+ADP1505  Adaptec AVA-1505 SCSI Host Adapter
+ADP1510  Adaptec AHA-1510 SCSI Host Adapter
+ADP1515  Adaptec AVA-1515 SCSI Host Adapter
+ADP1520  Adaptec AHA-152X/AHA-1510 SCSI Host Adapter
+ADP1522  Adaptec AHA-152X Plug and Play SCSI Host Adapter
+ADP1532  Adaptec AHA-152X Plug and Play SCSI Host Adapter
+ADP1540  Adaptec AHA-154X/AHA-164X/AHA-1535 SCSI Host Adapter
+ADP1542  Adaptec AHA-154X/AHA-1535 Plug and Play SCSI Host Adapter
+ADP154F  Adaptec SCSI Adapter Floppy Controller
+ADP1740  Adaptec AHA-174X EISA Host Adapter
+ADP2015  Adaptec AHA-152X/AHA-1510 SCSI Host Adapter
+ADP2215  Adaptec AHA-152X Plug and Play SCSI Host Adapter
+ADP2840  Adaptec AHA-284X VESA SCSI Host Adapter
+ADP3015  Adaptec AHA-153X/AIC-6370 Plug and Play SCSI Host Adapter
+ADP3215  Adaptec AHA-153X/AIC-6370 Plug and Play SCSI Host Adapter
+ADP4215  Adaptec AHA-154X/AHA-1535 Plug and Play SCSI Host Adapter
+ADP6360  Adaptec AHA-150X/1510/152X/AIC-6X60 SCSI Host Adapter
+ADP7770  Adaptec AIC-777X EISA SCSI Host Adapter
+ADP7771  Adaptec AIC-777X EISA SCSI Host Adapter
+
+ADV55AA  AMD PCNET Family Ethernet Adapter/ISA+
+ADV55AA  Mitron LX-2100+ Ethernet Adapter
+
+ATI4402  ATI Graphics Ultra Pro EISA (mach32)
+
+ATK1500  Allied Telesyn AT-1510 Plug and Play Ethernet Adapter
+
+AZT1605  Aztech Sound Galaxy Nova 16
+AZT2316  Aztech Sound Galaxy Washington 16
+
+BRI0200  Boca Complete Office Communicator (Voice)
+BRI1001  Boca Research BOCALANcard
+
+BUS0042  BusLogic MultiMaster SCSI Host Adapters
+BUS4201  BusLogic 32-Bit Bus Master EISA-to-SCSI Host Adapter w/Floppy
+
+CPQ3001  Compaq EISA Advanced VGA (AVGA)
+CPQ3011  Compaq QVision 1024/E
+CPQ3111  Compaq QVision 1024/E
+CPQ3112  Compaq QVision 1280/E
+CPQ3122  Compaq QVision 1280/I
+CPQ4300  Compaq Advanced ESDI Controller
+CPQ4410  Compaq Integrated 32-Bit Fast-SCSI-2 Controller
+CPQ4411  Compaq EISA 32-Bit Fast-SCSI-2 Controller
+CPQ6001  Compaq 32-Bit DualSpeed Token Ring Controller
+CPQ6002  Compaq NetFlex-2 TR Controller
+CPQ6100  Compaq NetFlex ENET/TR Controller
+CPQ6101  Compaq NetFlex-2 ENET/TR Controller
+CPQ9A83  Compaq Deskpro XL Processor Board
+CPQA050  Compaq SCSI Controller
+CPQA060  Compaq Elite Ethernet Controller
+CPQA090  Compaq SmartStation
+CPQA0A0  Compaq MiniStation/EN
+CPQA0B0  Compaq MiniStation/TR
+CPQA0D2  Compaq Modem Audio
+CPQA0D4  Compaq Modem Audio
+CPQA0D5  ESS ES688 AudioDrive
+CPQA0D6  Compaq Presario Bezel Volume Control
+CPQA0D7  Compaq Enhanced Keyboard
+CPQA0D8  Compaq PS/2 Port Mouse
+CPQA0D9  Communications Port
+CPQA0DA  Compaq IDE Controller
+CPQA0DB  Compaq Floppy Disk Controller
+CPQA0DE  Compaq PCMCIA Controller
+CPQA0DF  Compaq Notebook Display (WD)
+CPQA0E0  ECP Printer Port
+CPQA0E1  Compaq TV Tuner
+CPQA0E2  Compaq TV Tuner
+CPQA0E3  Compaq Contura Integrated Ethernet Controller
+CPQA0E4  Compaq Modem Audio
+CPQA0EF  Compaq Deskpro Thermal Sensor
+CPQAE08  Compaq Deskpro Thermal Sensor
+CPQAE26  ESS ES1688 AudioDrive
+CPQFA1B  Compaq Deskpro 486/50 system memory board
+CPQFD17  Compaq SCSI Tape Adapter
+
+CSC0000  Crystal PnP audio system CODEC
+CSC0001  Crystal PnP audio system joystick
+CSC0002  Crystal PnP audio system control registers
+CSC0003  Crystal PnP audio system MPU-401 compatible
+CSC0004  Crystal PnP IDE controller
+CSC0010  Crystal PnP audio system control registers
+CSC0011  Crystal PnP audio system CODEC/joystick
+
+CSI2201  Cabletron E2200 Series DNI / Primary
+CSI2202  Cabletron E2200 Series DNI / Secondary
+CSI2203  Cabletron E2200 Series DNI 
+
+CTL0001  Creative Labs Sound Blaster 16 or AWE-32 Plug and Play
+CTL0021  Creative Advanced Wave Effects Synthesis for AWE 32
+CTL0031  Creative Labs Sound Blaster 16 or AWE-32 Plug and Play
+CTL2001  MKEPanasonic CD-ROM Drive
+CTL2011  Creative Labs IDE controller
+CTL3011  Creative Labs Modem Blaster 28.8 DSVD PnP Voice
+CTL7001  Gameport Joystick
+CTL8001  Creative Advanced Wave Effects Synthesis for AWE 32
+
+DBK0000  Databook ISA PCMCIA Controller
+DBK0000  MobileMax Deskrunner ISA PCMCIA Controller
+DBK0204  Databook Plug and Play PCMCIA Controller based on DB86084
+DBK0214  Databook Plug and Play PCMCIA Controller based on DB86184
+DBK0402  Databook Plug and Play PCMCIA Controller based on DB86084
+DBK1402  Databook Plug and Play PCMCIA Controller based on DB86184
+
+ESS0100  ESS ES688 PnP AudioDrive
+ESS0102  ESS ES1688 PnP AudioDrive
+ESS1481  ESS ES1488 AudioDrive
+ESS1681  ESS ES1688 AudioDrive
+ESS4881  ESS ES488 AudioDrive
+ESS6880  ESS ES688 AudioDrive and Game Controller
+ESS6881  ESS ES688 AudioDrive
+
+FAR0002  Farallon EtherWave Plug and Play PC-ISA Card
+
+FDC0000  Future Domain MCS-600/700 SCSI Host Adapter
+FDC0000  Future Domain TMC-1650/1660/1670/1680 SCSI Host Adapter
+FDC0000  Future Domain TMC-1790/1795 SCSI Host Adapter
+FDC0950  Future Domain TMC-850/M/MER/MEX SCSI Host Adapter
+FDC0950  Future Domain TMC-860/860M/885/885M SCSI Host Adapter
+FDC1600  Future Domain PNP-1630/1640 Plug and Play SCSI controller
+FDC1695  Future Domain TMC-1695 Plug and Play SCSI Host Adapter
+FDC9516  Future Domain TMC-1695 Plug and Play SCSI Host Adapter
+
+HWP1940  HP J2577A 10/100VG EISA LAN Adapter
+HWP1950  HP J2573A 10/100VG ISA LAN Adapter
+HWP1C10  HP COM and LPT Ports Combo Card
+
+IBM0001  IBM Auto 16/4 ISA Token-Ring Adapter
+IBM0002  IBM Thinkpad pnfrared port
+IBM0020  InfraRed connector on the King ISA PnP PCMCIA Controller
+IBM0034  IBM Thinkpad infrared port
+IBM0070  IBM Thinkpad infrared port
+IBM0071  IBM Thinkpad infrared port
+IBM36E0  IBM Mwave DSP
+IBM36F1  IBM Mwave Midi Synthesizer
+IBM36F2  IBM Mwave SoundBlaster Compatibility
+IBM3730  IBM 3780i PnP Communications Adapter
+IBM3731  IBM 3780i PnP Communications Extender
+IBM3760  IBM Thinkpad Mwave DSP
+IBM3780  PS/2 TrackPoint
+
+INT0902  Intel TokenExpress EISA 16/4
+INT1030  Intel EtherExpress PRO/10 (PnP Enabled)
+INT1060  Intel EtherExpress PRO/100 (EISA)
+INT1201  Intel TokenExpress 32bit EISA 16/4
+
+ISAB701  All Iomega 8-bit PC2x SCSI Host Adapters except PC2F
+ISAB702  Iomega PC2F 8-bit SCSI Host Adapters
+
+MDG0002  Madge Smart 16/4 EISA Ringnode
+MDG0101  Madge Smart 16/4 ISA Client PnP Ringnode
+
+MDY1900  Microdyne NE2500 Ethernet Adapter
+MDY1901  Microdyne NE2500T Ethernet Adapter
+
+NEC8201  NEC EISA SCSI Host Adapter
+
+NVL0701  Intel EtherExpress 32
+NVL0701  Novell/Anthem NE3200 or compatible
+NVL0702  Novell/Anthem NE3200T
+
+OLC0902  Olicom EISA 16/4 Token-Ring Adapter
+OLC1201  Olicom 32bit Token-Ring Server Adapter
+OLC9430  Olicom Plug and Play Token-Ring ISA 16/4 (OC-3118)
+
+PRO6000  Proteon ProNET-4/16 EISA Token Ring (P1990) Rev A1-A7
+PRO6001  Proteon ProNET-4/16 EISA Token Ring (P1990) Rev A8 & above
+PRO6002  Proteon ProNET-4/16 EISA Token Ring (P1990) Plus
+
+RII0101  Racal ES3210 EISA
+
+RTL8019  Realtek RTL8019 PnP LAN adapter or compatible
+
+SCM0469  SCM SwapBox Family Plug and Play PCMCIA controller
+
+SKD8000  SysKonnect SK-NET Flash Ethernet Adapter
+
+SMC8010  SMC EtherCard Elite Ultra 32
+SMC8416  SMC EtherEZ (8416)
+SMC9000  SMC 9000 Ethernet Adapter
+
+SUP1380  SupraExpress 288i PnP Voice
+
+SVE0001  SVEC FD0421 EtherPlug-ISA
+
+TCI00D0  Tulip NCC-16 ISA+
+
+TCM5092  3Com EtherLink III EISA (3C579-TP)
+TCM5093  3Com EtherLink III EISA (3C579)
+TCM619B  3Com TokenLink III ISA in EISA mode (3C619B)
+
+TCO4145  Thomas-Conrad Token Ring TC4145
+
+TOS7400  Toshiba AcuPoint
+
+USC0140  UltraStor 14F/14FB/34F/34FA/34FB Driver
+USC0141  UltraStor 14F/14FB/34F/34FA/34FB Driver
+USC0142  UltraStor 14F/14FB/34F/34FA/34FB Driver
+USC0143  UltraStor 14F/14FB/34F/34FA/34FB Driver
+USC0240  UltraStor 24F/24FA Driver
+USC1240  UltraStor 124F Driver
+
+VDM0469  Vadem PCIC compatible Plug and Play PCMCIA controller
+
+WDC2001  Future Domain TMC-7000EX EISA SCSI Host Adapter
+
+ZDS2000  ZDS SCSI/IDE/Floppy EISA Controller Board
+ZDS2010  Zeos EISA IDE Controller
Index: oldkernel/linux/pcmcia-cs-3.1.15/debug-tools/setpnp.c
diff -u /dev/null linux/pcmcia-cs-3.1.15/debug-tools/setpnp.c:1.1
--- /dev/null	Mon Jul 31 21:15:10 2000
+++ linux/pcmcia-cs-3.1.15/debug-tools/setpnp.c	Fri Jul  7 16:34:58 2000
@@ -0,0 +1,310 @@
+/*======================================================================
+
+    A utility for reconfiguring PnP BIOS devices
+
+    setpnp.c 1.6 1999/10/25 19:58:00
+
+    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@pcmcia.sourceforge.org>.  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.
+
+    Usage:
+
+    setpnp [-b] [device #] [resource list]
+    setpnp [-b] [device #] {on|off}
+
+    The device number is a two-digit hex string.  The resource list
+    consists of a series of resource names and values.  Four resource
+    names are available: "io", "mem", "irq", and "dma".  Values can
+    either be single numbers or dash-delimited ranges.  More than one
+    value can be listed in a single argument, separated by commas.
+    
+    For example:
+
+    setpnp 0d irq 3 io 0x02f8-0x02ff
+
+======================================================================*/
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <string.h>
+#include <endian.h>
+#include <ctype.h>
+#include <asm/types.h>
+
+#include <linux/pnp_resource.h>
+
+static int verbose = 0, boot = 0;
+
+#define swap16(n) ((((n)&0x00ff)<<8) | (((n)&0xff00)>>8))
+#define swap32(n) \
+    ((((n)&0xff000000)>>24) | (((n)&0x00ff0000)>>8) | \
+     (((n)&0x0000ff00)<<8)  | (((n)&0x000000ff)<<24))
+
+#if (__BYTE_ORDER == _BIG_ENDIAN)
+#define flip16(n)	swap16(n)
+#define flip32(n)	swap32(n)
+#else
+#define flip16(n)	(n)
+#define flip32(n)	(n)
+#endif
+
+#define NRSRC	4
+#define NBASE	8
+#define R_IO	0
+#define R_MEM	1
+#define R_IRQ	2
+#define R_DMA	3
+
+struct rsrc_list {
+    int		nr[NRSRC];
+    u_long	base[NRSRC][NBASE];
+    u_long	len[NRSRC][NBASE];
+};
+
+static const char *rsrc_type[] = { "io", "mem", "irq", "dma" };
+
+/*====================================================================*/
+
+static char *update_chain(u_char *buf, int nr, struct rsrc_list *res)
+{
+    union pnp_resource *p = (union pnp_resource *)buf;
+    int tag = 0, sz, nu[4];
+    u_long base, len;
+    
+    nu[0] = nu[1] = nu[2] = nu[3] = 0;
+    while (((u_char *)p < buf+nr) && (tag != PNP_RES_SMTAG_END)) {
+	if (p->lg.tag & PNP_RES_LARGE_ITEM) {
+	    union pnp_large_resource *r = &p->lg.d;
+	    tag = p->lg.tag & ~PNP_RES_LARGE_ITEM;
+	    sz = flip16(p->lg.sz) + 2;
+	    switch (tag) {
+	    case PNP_RES_LGTAG_MEM:
+		if (res->nr[R_MEM] > nu[R_MEM]) {
+		    base = res->base[R_MEM][nu[R_MEM]++];
+		    len = res->len[R_MEM][nu[R_MEM]++];
+		    r->mem.min = r->mem.max = flip16(base >> 8);
+		    r->mem.len = flip16(len);
+		}
+		break;
+	    case PNP_RES_LGTAG_MEM32:
+		if (res->nr[R_MEM] > nu[R_MEM]) {
+		    base = res->base[R_MEM][nu[R_MEM]++];
+		    len = res->len[R_MEM][nu[R_MEM]++];
+		    r->mem32.min = r->mem32.max = flip32(base);
+		    r->mem32.len = flip32(len);
+		}
+		break;
+	    case PNP_RES_LGTAG_MEM32_FIXED:
+		if (res->nr[R_MEM] > nu[R_MEM]) {
+		    base = res->base[R_MEM][nu[R_MEM]];
+		    len = res->len[R_MEM][nu[R_MEM]++];
+		    r->mem32_fixed.base = flip32(base);
+		    r->mem32_fixed.len = flip32(len);
+		}
+		break;
+	    }
+	} else {
+	    union pnp_small_resource *r = &p->sm.d;
+	    tag = (p->sm.tag >> 3); sz = (p->sm.tag & 7);
+	    switch (tag) {
+	    case PNP_RES_SMTAG_IRQ:
+		if (res->nr[R_IRQ] > nu[R_IRQ]) {
+		    base = res->base[R_IRQ][nu[R_IRQ]++];
+		    r->irq.mask = base ? flip16(1<<base) : 0;
+		}
+		break;
+	    case PNP_RES_SMTAG_DMA:
+		if (res->nr[R_DMA] > nu[R_DMA]) {
+		    base = res->base[R_DMA][nu[R_DMA]++];
+		    r->dma.mask = base ? flip16(1<<base) : 0;
+		}
+		break;
+	    case PNP_RES_SMTAG_IO:
+		if (res->nr[R_IO] > nu[R_IO]) {
+		    base = res->base[R_IO][nu[R_IO]];
+		    len = res->len[R_IO][nu[R_IO]++];
+		    r->io.min = r->io.max = flip16(base);
+		    r->io.len = len;
+		}
+		break;
+	    case PNP_RES_SMTAG_IO_FIXED:
+		if (res->nr[R_IO] > nu[R_IO]) {
+		    base = res->base[R_IO][nu[R_IO]++];
+		    len = res->len[R_IO][nu[R_IO]++];
+		    r->io_fixed.base = flip16(base);
+		    r->io_fixed.len = len;
+		}
+		break;
+	    }
+	}
+	(u_char *)p += sz + 1;
+    }
+    return (u_char *)p;
+}
+
+static int update_resources(int num, struct rsrc_list *res)
+{
+    char fn[40];
+    u_char buf[4096];
+    int fd, nr, nw;
+    
+    if (access("/proc/bus/pnp", F_OK) != 0) {
+	fprintf(stderr, "lspnp: /proc/bus/pnp not available\n");
+	return EXIT_FAILURE;
+    }
+    
+    sprintf(fn, "/proc/bus/pnp/%s%02x", (boot ? "boot/" : ""), num);
+    fd = open(fn, O_RDWR);
+    nr = read(fd, buf, sizeof(buf));
+    if (nr <= 0) {
+	perror("read failed");
+	return EXIT_FAILURE;
+    }
+    
+    update_chain(buf, nr, res);
+    nw = write(fd, buf, nr);
+    close(fd);
+    if (nr != nw) {
+	perror("write failed");
+	return EXIT_FAILURE;
+    }
+    return EXIT_SUCCESS;
+}
+
+static int reset_resources(int num)
+{
+    char fn[40];
+    u_char buf[4096];
+    int fd, nr, nw;
+    
+    if (access("/proc/bus/pnp", F_OK) != 0) {
+	fprintf(stderr, "lspnp: /proc/bus/pnp not available\n");
+	return EXIT_FAILURE;
+    }
+    sprintf(fn, "/proc/bus/pnp/boot/%02x", num);
+    fd = open(fn, O_RDONLY);
+    nr = read(fd, buf, sizeof(buf));
+    close(fd);
+    if (nr <= 0) {
+	perror("read failed");
+	return EXIT_FAILURE;
+    }
+    sprintf(fn, "/proc/bus/pnp/%02x", num);
+    fd = open(fn, O_WRONLY);
+    nw = write(fd, buf, nr);
+    close(fd);
+    if (nr != nw) {
+	perror("write failed");
+	return EXIT_FAILURE;
+    }
+    return EXIT_SUCCESS;
+}
+
+/*====================================================================*/
+
+static int parse_resources(char *argv[], int argc,
+			   struct rsrc_list *res)
+{
+    int i, j;
+    u_long base, len;
+    char *s, *t;
+    
+    for (i = 0; i < argc; i += 2) {
+	for (j = 0; j < NRSRC; j++)
+	    if (strcmp(rsrc_type[j], argv[i]) == 0) break;
+	if (j == NRSRC) {
+	    fprintf(stderr, "bad resource type: '%s'\n", argv[i]);
+	    return EXIT_FAILURE;
+	}
+	s = strtok(argv[i+1], ", \t");
+	while (s) {
+	    base = strtoul(s, &t, 0);
+	    len = ((*t == '-') ? strtoul(t+1, &t, 0)-base+1 : 1);
+	    if ((*s == '\0') || (*t != '\0')) {
+		fprintf(stderr, "bad resource argument: '%s'\n", t);
+		return EXIT_FAILURE;
+	    }
+	    res->base[j][res->nr[j]] = base;
+	    res->len[j][res->nr[j]++] = len;
+	    s = strtok(NULL, ", \t");
+	}
+    }
+    return EXIT_SUCCESS;
+}
+
+/*====================================================================*/
+
+void usage(char *name)
+{
+    fprintf(stderr, "usage: %s [-b] [device #] [resources ...]\n"
+	    "    or %s [-b] [device #] {on|off}\n", name, name);
+    exit(EXIT_FAILURE);
+}
+    
+int main(int argc, char *argv[])
+{
+    int i, optch, errflg = 0;
+    static struct rsrc_list res;
+    char *s;
+    
+    while ((optch = getopt(argc, argv, "bv")) != -1) {
+	switch (optch) {
+	case 'b':
+	    boot++; break;
+	case 'v':
+	    verbose++; break;
+	default:
+	    errflg = 1; break;
+	}
+    }
+    if (errflg || (optind == argc))
+	usage(argv[0]);
+    
+    i = strtoul(argv[optind], &s, 16);
+    if ((argv[optind] == '\0') || (*s != '\0'))
+	usage(argv[0]);
+    optind++;
+
+    /* Special commands */
+    if (argc == optind+1) {
+	if (strcmp(argv[optind], "off") == 0) {
+	    res.nr[0] = res.nr[1] = res.nr[2] = res.nr[3] = 7;
+	    optind++;
+	} else if (strcmp(argv[optind], "on") == 0) {
+	    return reset_resources(i);
+	} else {
+	    usage(argv[0]);
+	}
+    } else if (argc == optind)
+	usage(argv[0]);
+    
+    if ((argc - optind) % 2)
+	usage(argv[0]);
+    if (parse_resources(argv+optind, argc-optind, &res) == 0)
+	return update_resources(i, &res);
+    return EXIT_FAILURE;
+}
Index: oldkernel/linux/pcmcia-cs-3.1.15/debug-tools/test_modem
diff -u /dev/null linux/pcmcia-cs-3.1.15/debug-tools/test_modem:1.1
--- /dev/null	Mon Jul 31 21:15:10 2000
+++ linux/pcmcia-cs-3.1.15/debug-tools/test_modem	Fri Jul  7 16:34:58 2000
@@ -0,0 +1,124 @@
+#!/usr/bin/perl
+
+use Fcntl;
+use POSIX qw(:termios_h);
+
+sub indent
+{
+    my($str) = @_;
+    $str =~ s/\n\s*(.)/\n  \1/g;
+    $str =~ s/^\s*//;
+    return "  $str";
+}
+
+sub init_tty
+{
+    # Initialize the tty device to a sane mode
+    my $fd = fileno(MODEM);
+    $term = POSIX::Termios->new();
+    $term->getattr($fd);
+    $term->setcc(VTIME, 0);
+    $term->setcc(VMIN, 0);
+    $term->setoflag(0);
+    $term->setlflag(0);
+    my $cflag = $term->getcflag | CLOCAL | CREAD | CS8;
+    $cflag &= ~(CSIZE | CSTOPB | PARENB);
+    $term->setcflag($cflag);
+    $term->setiflag(IGNBRK | IGNPAR);
+    $term->setattr($fd, TCSANOW);
+}
+
+sub at_cmd
+{
+    my($cmd) = @_;
+    my($rin, $n, $nf, $char, $buf);
+    syswrite(MODEM, "$cmd\r") || die "syswrite(): $!\n";
+    $rin = $buf = '';
+    $nr = 0;
+    while ($nr < 1024) {
+	vec($rin,fileno(MODEM),1) = 1;
+	last if (!select $rin, undef, undef, 1);
+	$nr += sysread(MODEM, $buf, 1024-$nr, $nr);
+    }
+    $buf =~ s/^\s*$cmd\s+//;
+    $buf =~ s/\s+OK\s+$//;
+    $buf =~ s/\s+/ /g;
+    return $buf;
+}
+
+sub checkout
+{
+    my($dev) = @_;
+    print "Checking modem at /dev/$dev:\n";
+    $set = `setserial /dev/$dev`;
+    print "  Settings: $set";
+    $irq = $1 if $set =~ /IRQ: (\d+)/;
+    sysopen(MODEM, "/dev/$dev", O_RDWR|O_NONBLOCK) ||
+	die "sysopen(): $!\n";
+    init_tty();
+    
+    $buf = at_cmd("ATI3");
+    if ($buf ne "") {
+	print "  ATI3 = '$buf'\n";
+	print "  The modem is operating normally.\n";
+	close(MODEM);
+    } else {
+	close(MODEM);
+	print "  Modem query timed out: trying polled mode.\n";
+	system("setserial /dev/$dev irq 0");
+	sysopen(MODEM, "/dev/$dev", O_RDWR|O_NONBLOCK) ||
+	    die "sysopen(): $!\n";
+	$buf = at_cmd("ATI3");
+	if ($buf ne "") {
+	    print "  ATI3 = '$buf'\n";
+	    print "  The modem interrupt (irq $irq) has a delivery problem.\n";
+	} else {
+	    print "  The modem is not working in polled mode.\n";
+	}
+	close(MODEM);
+	system("setserial /dev/$dev irq $irq");
+    }
+}
+
+foreach $f ("/var/run/stab", "/var/lib/pcmcia/stab",
+	    "/var/state/pcmcia/stab") {
+    if (-f $f) {
+	$stab = $f; last;
+    }
+}
+if (!$stab) {
+    print "Socket status file (stab) not found!  Is PCMCIA running??\n";
+    exit 1;
+}
+
+$ns = 0;
+open(IN, $stab);
+while ($_ = <IN>) {
+    chop;
+    if (/^Socket (\d+): (.*)/) {
+	($sock,$card) = ($1,$2);
+    } else {
+	@f = split;
+	next if ($f[1] ne "serial");
+	$ns++;
+	checkout($f[4]);
+    }
+}
+close(IN);
+
+exit 0 if ($ns);
+
+print "No PCMCIA modem devices are configured.\n";
+
+open(IN, "/sbin/cardctl ident |");
+while (<IN>) {
+    $sock = $1 if (/^Socket (\d+)/);
+    if (/function: 2/) {
+	$ns++;
+	print "\nThere is a serial device in socket $sock.\n";
+    }
+}
+close(IN);
+
+$log = `dmesg | grep register_serial | tail -2`;
+print "\nKernel messages:\n", indent($log) if ($log);
Index: oldkernel/linux/pcmcia-cs-3.1.15/debug-tools/test_network
diff -u /dev/null linux/pcmcia-cs-3.1.15/debug-tools/test_network:1.1
--- /dev/null	Mon Jul 31 21:15:10 2000
+++ linux/pcmcia-cs-3.1.15/debug-tools/test_network	Fri Jul  7 16:34:58 2000
@@ -0,0 +1,178 @@
+#!/usr/bin/perl
+
+$| = 1; # Don't buffer output
+
+sub indent
+{
+    my($str) = @_;
+    $str =~ s/\n(.)/\n  \1/g;
+    return "  $str";
+}
+
+sub irq_count
+{
+    my($irq) = @_;
+    my($s) = `grep " $irq:" /proc/interrupts`;
+    return $1 if ($s =~ /^ +\d+:\s+(\d+)/);
+}
+
+sub checkout
+{
+    my($dev,$driver,$card) = @_;
+    
+    print "\nChecking network interface $dev ($driver driver):\n\n";
+    
+    $log = `dmesg | grep $dev | tail`;
+    if ($log) {
+	print "  Kernel messages for $dev:\n", indent($log), "\n";
+    }
+    
+    $conf = `/sbin/ifconfig $dev`;
+    $conf =~ s/\n$//;
+    print "  Current ifconfig settings:\n", indent($conf), "\n";
+
+    if ($conf !~ /Mask/) {
+	print "  The interface is not configured!\n";
+    } elsif ($conf !~ /RUNNING/) {
+	print "  The interface is not running!\n";
+    } else {
+	print "  The interface is configured and running.\n";
+    }
+
+    $irq = $1 if ($conf =~ /Interrupt:(\d+)/);
+    @line = split(/\n/, $conf);
+    @addr = split(/ [a-zA-Z ]+:/, $line[1]);
+    @rx = split(/ [a-zA-Z ]+:/, $1) if ($conf =~ /RX(.*)\n/);
+    @tx = split(/ [a-zA-Z ]+:/, $1) if ($conf =~ /TX(.*)\n/);
+    shift(@rx); shift(@tx);
+    $rx_ok = ($rx[0] > 5*($rx[1]+$rx[2]+$rx[3]+$rx[4])+1);
+    $tx_ok = ($tx[0] > 5*($tx[1]+$tx[2]+$tx[3]+$tx[4])+1);
+    $rx_any = $rx[0]+$rx[1]+$rx[2]+$rx[3]+$rx[4];
+    $tx_any = $tx[0]+$rx[1]+$rx[2]+$rx[3]+$rx[4];
+    
+    if ($conf =~ /RUNNING/) {
+	if ($rx_ok && $tx_ok) {
+	    print "  RX and TX traffic both look ok.\n";
+	} elsif ($rx_ok) {
+	    print "  RX looks ok, but there seems to be a TX problem.\n";
+	} elsif ($tx_ok) {
+	    print "  TX looks ok, but there seems to be an RX problem.\n";
+	} elsif ($rx_err+$tx_err > 1) {
+	    print "  RX and TX traffic both look bad.\n";
+	} else {
+	    print "  There hasn't been any traffic on this interface!\n";
+	}
+    }
+
+    $addr = ""; $gw = 0; $dflt = "";
+    open(RT, "route -n |");
+    while (<RT>) {
+	chop; @s = split;
+	$dflt = $s[7] if ($s[0] eq "0.0.0.0");
+	next if (!/$dev/);
+	if ($s[1] ne "0.0.0.0") {
+	    print "\n  There is a route to a gateway at $s[1].\n";
+	    $addr = $s[1];
+	    $gw = 1;
+	    last;
+	}
+    }
+    close(RT);
+    if (($dflt ne "") && !$gw) {
+	print "\n  Your default route is pointed to interface $dflt.\n";
+    }
+
+    if ($addr eq "") {
+	while (1) {
+	    print "\n  Enter a numeric IP address to ping: ";
+	    $addr = <STDIN>; chop($addr);
+	    if ($addr !~ /^\d+\.\d+\.\d+\.\d+$/) {
+		print "  That is not a valid address!\n";
+	    } elsif (system("/sbin/ifuser $dev $addr")) {
+		print "  There is no route to $addr through $dev!\n";
+	    } else {
+		last;
+	    }
+	}
+    }
+
+    print "\n  Pinging $addr ...";
+    $start = irq_count($irq);
+    open(PING, "ping -c 1 $addr|");
+    $rx = 0;
+    while (<PING>) {
+	if (/(\d) packets received/) {
+	    $rx = $1;
+	    last;
+	}
+    }
+    close(PING);
+    $stop = irq_count($irq);
+    print (($rx) ? " response received!\n" : " timed out!\n");
+    print "  The device interrupt ";
+    print (($stop - $start) ? "seems" : "does not seem");
+    print " to be incrementing.\n";
+}
+
+foreach $f ("/var/run/stab", "/var/lib/pcmcia/stab",
+	    "/var/state/pcmcia/stab") {
+    if (-f $f) {
+	$stab = $f; last;
+    }
+}
+if (!$stab) {
+    print "Socket status file (stab) not found!  Is PCMCIA running??\n";
+    exit 1;
+}
+
+$net = `cat /etc/pcmcia/network`;
+$opts = `cat /etc/pcmcia/network.opts`;
+$rh = "/etc/sysconfig/network-scripts/ifcfg-eth0";
+print "PCMCIA network settings are coming from ";
+if ($net =~ /ifup / || $opts =~ /ifup /) {
+    print "linuxconf.\n";
+    print "  $rh does not exist!\n" if (!-e $rh);
+} else {
+    print "/etc/pcmcia/network.opts.\n";
+    if (!$opts) {
+	print "    /etc/pcmcia/network.opts is empty??\n";
+    } elsif (($opts !~ /\w+=[^\n]y/) && ($opts !~ /IPADDR[^\n]\d/)) {
+	print "    /etc/pcmcia/network.opts is not configured??\n";
+    }
+    print "  $rh also exists??\n" if (-e $rh);
+}
+
+
+$ns = 0;
+open(IN, $stab);
+while ($_ = <IN>) {
+    chop;
+    if (/^Socket (\d+): (.*)/) {
+	($sock,$card) = ($1,$2);
+    } else {
+	@f = split;
+	next if ($f[1] ne "network");
+	$ns++;
+	checkout($f[4], $f[2], $card);
+    }
+}
+close(IN);
+
+exit 0 if ($ns);
+
+print "No PCMCIA network interfaces are configured.\n";
+
+$s = `cat $stab`;
+open(IN, "/sbin/cardctl ident |");
+while (<IN>) {
+    $sock = $1 if (/^Socket (\d+)/);
+    if (/function: 6/) {
+	print "\nThere is a network device in socket $sock:\n";
+	$tag = $1 if ($s =~ /Socket $sock: ([^\n]+)/);
+	print "  $tag\n";
+    }
+}
+close(IN);
+
+$log = `dmesg | grep '_c[bs]:' | tail`;
+print "\nKernel messages from client drivers:\n", indent($log) if ($log);
Index: oldkernel/linux/pcmcia-cs-3.1.15/debug-tools/test_setup
diff -u /dev/null linux/pcmcia-cs-3.1.15/debug-tools/test_setup:1.1
--- /dev/null	Mon Jul 31 21:15:10 2000
+++ linux/pcmcia-cs-3.1.15/debug-tools/test_setup	Fri Jul  7 16:34:58 2000
@@ -0,0 +1,111 @@
+#!/usr/bin/perl
+
+sub indent
+{
+    my($str) = @_;
+    $str =~ s/\n\s*(.)/\n  \1/g;
+    $str =~ s/^\s*//;
+    return "  $str";
+}
+
+print "Current kernel: ", `uname -rv`;
+$rel = `uname -r`;
+$rel =~ s/\s//g;
+$core = "/lib/modules/$rel/pcmcia/pcmcia_core.o";
+if (-f $core) {
+    $info = `strings -n 10 $core | head -3`;
+    print "Module info from $core:\n", indent($info);
+} else {
+    print "$core not found.\n  The PCMCIA modules are not installed.\n"
+}
+
+foreach $f ("/etc/sysconfig/pcmcia", "/etc/pcmcia.conf",
+	    "/etc/rc.config", "/etc/rc.pcmcia") {
+    $conf = $f if (-f $f);
+}
+if ($conf) {
+    print "\nStartup options from $conf:\n";
+    if ($conf eq "/etc/rc.config") {
+	$opts = `grep PCMCIA $conf`;
+    } elsif ($conf eq "/etc/rc.pcmcia") {
+	$opts = `grep '^    [A-Z_]*=' $conf`;
+    } else {
+	$opts = `cat $conf`;
+    }
+    print indent($opts);
+}
+
+print "\nChecking current syslog files in /var/log:\n";
+foreach $f (split(/\s+/, `/bin/ls -t /var/log/*`)) {
+    next if ((!-f $f) || ($f =~ /\.\d+$/));
+    next if (system("head $f | grep -q syslogd") != 0);
+    $kernel = $f if (system("grep -q 'Card Services' $f") == 0);
+    $daemon = $f if (system("grep -q cardmgr $f") == 0);
+    last if ($kernel && $daemon);
+}
+if ($kernel || $daemon) {
+    if ($kernel eq $daemon) {
+	print "  All PCMCIA messages are in $kernel.\n";
+    } else {
+	if ($kernel) {
+	    print "  PCMCIA kernel messages are in $kernel.\n";
+	} else {
+	    print "  No PCMCIA kernel messages were found!\n";
+	}
+	if ($kernel) {
+	    print "  cardmgr messages are in $daemon.\n";
+	} else {
+	    print "  No cardmgr messages were found!\n";
+	}
+    }
+} else {
+    print "  No PCMCIA messages were found!\n";
+}
+
+print "\nModule status:\n";
+$devices = `cat /proc/devices`;
+$lsmod = `/sbin/lsmod`;
+if ($lsmod !~ /\bpcmcia_core\b/) {
+    print "  No PCMCIA modules are loaded.\n";
+} elsif (($lsmod !~ /\bi82365\b/) && ($lsmod !~ /\btcic\b/)) {
+    print "  No socket drivers are loaded.\n";
+} elsif ($lsmod !~ /\bds\b/) {
+    print "  The 'ds' module is not loaded.\n";
+} elsif ($devices !~ /pcmcia/) {
+    print "  The PCMCIA socket device is not available.\n";
+} else {
+    print "  The PCMCIA kernel modules are loaded correctly.\n";
+}
+
+$ok = 0;
+print "\nDaemon status:\n";
+if (!-f "/sbin/cardmgr") {
+    print "  /sbin/cardmgr does not exist!\n";
+}
+if (!-f "/var/run/cardmgr.pid") {
+    print "  /var/run/cardmgr.pid does not exist.\n";
+} else {
+    $pid = `cat /var/run/cardmgr.pid`;
+    $pid =~ s/\s+//g;
+    if (`cat /proc/$pid/cmdline` =~ cardmgr) {
+	print "  cardmgr is running (process $pid)\n";
+	$ok = 1;
+    } else {
+	print "  /var/run/cardmgr.pid is stale.\n";
+    }
+}
+exit if (!$ok);
+
+foreach $f ("/var/run/stab", "/var/lib/pcmcia/stab",
+	    "/var/state/pcmcia/stab") {
+    if (-f $f) {
+	$stab = $f; last;
+    }
+}
+if ($stab) {
+    print "\nCurrent socket status from $stab:\n";
+    $stat = `cat $stab`;
+    print indent($stat);
+} else {
+    print "\nSocket status file (stab) not found!\n";
+}
Index: oldkernel/linux/pcmcia-cs-3.1.15/debug-tools/yacc_cis.c
diff -u /dev/null linux/pcmcia-cs-3.1.15/debug-tools/yacc_cis.c:1.1
--- /dev/null	Mon Jul 31 21:15:10 2000
+++ linux/pcmcia-cs-3.1.15/debug-tools/yacc_cis.c	Fri Jul  7 16:34:58 2000
@@ -0,0 +1,1049 @@
+#ifndef lint
+static char yysccsid[] = "@(#)yaccpar	1.9 (Berkeley) 02/21/93";
+#endif
+#define YYBYACC 1
+#define YYMAJOR 1
+#define YYMINOR 9
+#define yyclearin (yychar=(-1))
+#define yyerrok (yyerrflag=0)
+#define YYRECOVERING (yyerrflag!=0)
+#define YYPREFIX "yy"
+#line 2 "yacc_cis.y"
+/*
+ * yacc_cis.y 1.10 1999/10/25 19:57: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@pcmcia.sourceforge.org>.  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 <sys/types.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <stdarg.h>
+#include <math.h>
+
+#include <pcmcia/cs_types.h>
+#include <pcmcia/cs.h>
+#include <pcmcia/cistpl.h>
+
+#include "pack_cis.h"
+
+/* If bison: generate nicer error messages */ 
+#define YYERROR_VERBOSE 1
+ 
+extern int current_lineno;
+
+void yyerror(char *msg, ...);
+static tuple_info_t *new_tuple(u_char type, cisparse_t *parse);
+
+#line 65 "yacc_cis.y"
+typedef union {
+    char *str;
+    u_long num;
+    float flt;
+    cistpl_power_t pwr;
+    cisparse_t *parse;
+    tuple_info_t *tuple;
+} YYSTYPE;
+#line 72 "y.tab.c"
+#define STRING 257
+#define NUMBER 258
+#define FLOAT 259
+#define VOLTAGE 260
+#define CURRENT 261
+#define SIZE 262
+#define VERS_1 263
+#define MANFID 264
+#define FUNCID 265
+#define CONFIG 266
+#define CFTABLE 267
+#define MFC 268
+#define CHECKSUM 269
+#define POST 270
+#define ROM 271
+#define BASE 272
+#define LAST_INDEX 273
+#define DEV_INFO 274
+#define ATTR_DEV_INFO 275
+#define NO_INFO 276
+#define TIME 277
+#define TIMING 278
+#define WAIT 279
+#define READY 280
+#define RESERVED 281
+#define VNOM 282
+#define VMIN 283
+#define VMAX 284
+#define ISTATIC 285
+#define IAVG 286
+#define IPEAK 287
+#define IDOWN 288
+#define VCC 289
+#define VPP1 290
+#define VPP2 291
+#define IO 292
+#define MEM 293
+#define DEFAULT 294
+#define BVD 295
+#define WP 296
+#define RDYBSY 297
+#define MWAIT 298
+#define AUDIO 299
+#define READONLY 300
+#define PWRDOWN 301
+#define BIT8 302
+#define BIT16 303
+#define LINES 304
+#define RANGE 305
+#define IRQ_NO 306
+#define MASK 307
+#define LEVEL 308
+#define PULSE 309
+#define SHARED 310
+#define YYERRCODE 256
+short yylhs[] = {                                        -1,
+    0,    0,   16,   16,   17,   17,   15,   15,   15,   15,
+   15,   15,   15,   15,   15,   12,   12,   12,   13,   13,
+   13,    3,    3,    4,    5,    5,    5,    6,    1,    1,
+    1,    1,    1,    1,    1,    2,    2,   11,   11,   11,
+   11,    8,    8,    8,    8,    8,    8,    9,    9,    9,
+    9,   10,   10,   10,   10,   10,    7,    7,    7,    7,
+    7,    7,    7,    7,    7,    7,    7,    7,    7,    7,
+    7,    7,   14,
+};
+short yylen[] = {                                         2,
+    1,    2,    0,    2,    4,    5,    1,    1,    1,    1,
+    1,    1,    1,    1,    1,    1,    5,    2,    1,    5,
+    2,    2,    3,    4,    2,    2,    2,    7,    2,    2,
+    2,    2,    2,    2,    2,    0,    2,    2,    3,    3,
+    3,    5,    5,    2,    2,    5,    2,    7,    7,    2,
+    2,    3,    4,    2,    2,    2,    2,    2,    2,    2,
+    2,    2,    2,    2,    2,    3,    3,    3,    1,    1,
+    1,    1,    6,
+};
+short yydefred[] = {                                      3,
+    0,    0,   15,    0,    0,    0,    0,    0,    0,    0,
+   16,   19,    0,   10,    0,   12,    0,    0,    0,    0,
+    0,    0,    0,   14,    4,    0,   22,    0,   25,    0,
+   57,    3,    0,    0,   26,   27,   38,   36,   36,   36,
+    0,    0,   58,   59,   60,   61,   62,   63,   64,   65,
+    0,   44,   45,    0,   47,    0,   50,   51,    0,   55,
+   54,   56,    0,    0,    0,    0,   18,    0,   21,    0,
+    0,    0,    0,    0,   23,    0,    0,    0,    0,    0,
+   52,    0,    0,    0,    0,   39,   40,   41,    0,    0,
+    3,   24,    0,    5,    0,    0,    0,    0,    0,    0,
+    0,    0,   37,    0,    0,   53,    0,    0,    0,    0,
+    0,    0,    0,    0,   29,   30,   31,   32,   33,   34,
+   35,   42,    0,   46,   43,    0,   17,   20,    6,    0,
+   73,    0,    0,   28,   48,   49,
+};
+short yydgoto[] = {                                       1,
+  103,   76,   13,   14,   15,   16,   17,   18,   19,   20,
+   21,   22,   23,   24,   25,    2,   26,
+};
+short yysindex[] = {                                      0,
+    0, -225,    0, -211, -252, -242, -238, -207,  -71, -205,
+    0,    0,   11,    0, -234,    0, -271,  -44,  -40, -300,
+ -268, -244, -243,    0,    0,   12,    0,   13,    0, -200,
+    0,    0,   14, -197,    0,    0,    0,    0,    0,    0,
+ -189, -188,    0,    0,    0,    0,    0,    0,    0,    0,
+ -253,    0,    0,   10,    0, -186,    0,    0, -185,    0,
+    0,    0, -203, -202, -201, -199,    0, -198,    0,  -46,
+ -178, -226, -122, -176,    0, -220, -220, -220,   38,   39,
+    0, -173, -172,   42,   43,    0,    0,    0,   45,   46,
+    0,    0, -167,    0,   31, -166, -165, -164, -163, -162,
+ -161, -160,    0, -156, -155,    0,    4, -154, -153, -152,
+ -151, -108, -159, -150,    0,    0,    0,    0,    0,    0,
+    0,    0,   48,    0,    0,   49,    0,    0,    0, -149,
+    0, -143, -142,    0,    0,    0,
+};
+short yyrindex[] = {                                      0,
+    0,  106,    0,    0,    0,    0,    0,    0,    0,    0,
+    0,    0,  350,    0,  370,    0,  395,    1,   47,   93,
+  146,  416,  430,    0,    0,  107,    0,    0,    0,    0,
+    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,
+    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,
+    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,
+    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,
+    0,    0,    0,    0,    0,  192,  238,  304,    0,    0,
+    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,
+    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,
+    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,
+    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,
+    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,
+    0,    0,    0,    0,    0,    0,
+};
+short yygindex[] = {                                      0,
+    0,    6,    0,    0,    0,    0,    0,    0,    0,    0,
+    0,    0,    0,    0,    0,  -30,    0,
+};
+#define YYTABLESIZE 705
+short yytable[] = {                                      56,
+   69,   73,   94,   59,   81,   28,   37,   60,   61,   62,
+   63,   64,   65,   66,   68,   29,  129,   38,   39,   40,
+   41,   42,   43,   44,   45,   46,   47,   48,   49,   50,
+    3,   67,   69,   30,   51,   35,   36,    4,    5,    6,
+    7,    8,    9,   10,   77,   78,   70,   27,   11,   12,
+   31,   32,   33,   82,   34,   70,   71,   72,   74,   75,
+  112,   96,   97,   98,   99,  100,  101,  102,   79,   80,
+   83,   84,   85,   86,   87,   88,   91,   89,   90,   92,
+   93,   95,  104,  105,  106,  107,  108,  109,  110,  111,
+  113,  114,   71,  115,  116,  117,  124,  118,  119,  120,
+  121,  122,  123,  125,  126,    1,    2,  131,  134,  127,
+  128,  132,  133,  130,  135,  136,    0,    0,    0,    0,
+    0,    0,    0,    0,    0,   69,    0,    0,    0,    0,
+    0,    0,    0,    3,    0,    0,    0,    0,    0,    0,
+    4,    5,    6,    7,    8,   72,   10,    3,    0,    0,
+    0,   11,   12,    0,    4,    5,    6,    7,    8,    0,
+   10,    0,    0,    0,    0,   11,   12,    0,    0,    0,
+    0,   70,    0,    0,    0,    0,    0,    0,    0,    0,
+    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,
+    0,   66,    0,    0,    0,    0,    0,    0,    0,    0,
+    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,
+    0,    0,    0,    0,    0,    0,    0,   71,    0,    0,
+    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,
+    0,    0,    0,    0,    0,    0,    0,   67,    0,    0,
+    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,
+    0,    0,    0,    0,    0,    0,   69,   52,   53,   54,
+   55,   57,   58,   69,   69,   69,   69,   69,   69,   69,
+   72,    0,    0,    0,   69,   69,    0,    0,   69,    0,
+    0,    0,    0,    0,    0,    0,    0,    0,    0,   69,
+   69,   69,   69,   69,   69,   69,   69,   69,   69,   69,
+   69,   69,   70,   68,    0,    0,   69,    0,    0,   70,
+   70,   70,   70,   70,   70,   70,   66,    0,    0,    0,
+   70,   70,    0,    0,   70,    0,    0,    0,    0,    0,
+    0,    0,    0,    0,    0,   70,   70,   70,   70,   70,
+   70,   70,   70,   70,   70,   70,   70,   70,   71,    9,
+    0,    0,   70,    0,    0,   71,   71,   71,   71,   71,
+   71,   71,   67,    0,    0,    0,   71,   71,    0,   11,
+   71,    0,    0,    0,    0,    0,    0,    0,    0,    0,
+    0,   71,   71,   71,   71,   71,   71,   71,   71,   71,
+   71,   71,   71,   71,   13,    0,    0,    0,   71,    0,
+    0,   72,    0,    0,    0,    0,    0,    0,   72,   72,
+   72,   72,   72,   72,   72,    7,    0,    0,    0,   72,
+   72,    0,    0,   72,    0,    0,    0,    0,   68,    8,
+    0,    0,    0,    0,   72,   72,   72,   72,   72,   72,
+   72,   72,   72,   72,   72,   72,   72,   66,    0,    0,
+    0,   72,    0,    0,   66,   66,   66,   66,   66,   66,
+   66,    0,    0,    0,    0,   66,   66,    0,    0,   66,
+    0,    0,    0,    0,    9,    0,    0,    0,    0,    0,
+   66,   66,   66,   66,   66,   66,   66,   66,   66,   66,
+   66,   66,   66,   67,   11,    0,    0,   66,    0,    0,
+   67,   67,   67,   67,   67,   67,   67,    0,    0,    0,
+    0,   67,   67,    0,    0,   67,    0,    0,    0,   13,
+    0,    0,    0,    0,    0,    0,   67,   67,   67,   67,
+   67,   67,   67,   67,   67,   67,   67,   67,   67,    0,
+    7,    0,    0,   67,    0,    0,    0,    0,    0,    0,
+    0,    0,    0,    0,    8,    0,    0,    0,    0,   68,
+    0,    0,    0,    0,    0,    0,   68,   68,   68,   68,
+   68,   68,   68,    0,    0,    0,    0,   68,   68,    0,
+    0,   68,    0,    0,    0,    0,    0,    0,    0,    0,
+    0,    0,   68,   68,   68,   68,   68,   68,   68,   68,
+   68,   68,   68,   68,   68,    9,    0,    0,    0,   68,
+    0,    0,    9,    9,    9,    9,    9,    9,    9,    0,
+    0,    0,    0,    9,    9,   11,    0,    0,    0,    0,
+    0,    0,   11,   11,   11,   11,   11,   11,   11,    0,
+    0,    0,    0,   11,   11,    0,    0,    0,    0,    0,
+   13,    0,    0,    0,    0,    0,    0,   13,   13,   13,
+   13,   13,   13,   13,    0,    0,    0,    0,   13,   13,
+    0,    7,    0,    0,    0,    0,    0,    0,    7,    7,
+    7,    7,    7,    7,    7,    8,    0,    0,    0,    7,
+    7,    0,    8,    8,    8,    8,    8,    8,    8,    0,
+    0,    0,    0,    8,    8,
+};
+short yycheck[] = {                                      44,
+    0,   32,  125,   44,  258,  258,  278,  308,  309,  310,
+  279,  280,  281,  258,  258,  258,  125,  289,  290,  291,
+  292,  293,  294,  295,  296,  297,  298,  299,  300,  301,
+  256,  276,  276,  272,  306,  270,  271,  263,  264,  265,
+  266,  267,  268,  269,   39,   40,    0,  259,  274,  275,
+  258,  123,  258,  307,   44,   44,   44,  258,   45,  257,
+   91,  282,  283,  284,  285,  286,  287,  288,  258,  258,
+   61,  258,  258,  277,  277,  277,  123,  277,  277,  258,
+  307,  258,   45,   45,  258,  258,   45,   45,   44,   44,
+  258,   61,    0,  260,  260,  260,   93,  261,  261,  261,
+  261,  258,  258,  258,  258,    0,    0,  258,  258,  262,
+  262,   64,   64,  273,  258,  258,   -1,   -1,   -1,   -1,
+   -1,   -1,   -1,   -1,   -1,  125,   -1,   -1,   -1,   -1,
+   -1,   -1,   -1,  256,   -1,   -1,   -1,   -1,   -1,   -1,
+  263,  264,  265,  266,  267,    0,  269,  256,   -1,   -1,
+   -1,  274,  275,   -1,  263,  264,  265,  266,  267,   -1,
+  269,   -1,   -1,   -1,   -1,  274,  275,   -1,   -1,   -1,
+   -1,  125,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,
+   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,
+   -1,    0,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,
+   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,
+   -1,   -1,   -1,   -1,   -1,   -1,   -1,  125,   -1,   -1,
+   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,
+   -1,   -1,   -1,   -1,   -1,   -1,   -1,    0,   -1,   -1,
+   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,
+   -1,   -1,   -1,   -1,   -1,   -1,  256,  302,  303,  304,
+  305,  302,  303,  263,  264,  265,  266,  267,  268,  269,
+  125,   -1,   -1,   -1,  274,  275,   -1,   -1,  278,   -1,
+   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,  289,
+  290,  291,  292,  293,  294,  295,  296,  297,  298,  299,
+  300,  301,  256,    0,   -1,   -1,  306,   -1,   -1,  263,
+  264,  265,  266,  267,  268,  269,  125,   -1,   -1,   -1,
+  274,  275,   -1,   -1,  278,   -1,   -1,   -1,   -1,   -1,
+   -1,   -1,   -1,   -1,   -1,  289,  290,  291,  292,  293,
+  294,  295,  296,  297,  298,  299,  300,  301,  256,    0,
+   -1,   -1,  306,   -1,   -1,  263,  264,  265,  266,  267,
+  268,  269,  125,   -1,   -1,   -1,  274,  275,   -1,    0,
+  278,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,
+   -1,  289,  290,  291,  292,  293,  294,  295,  296,  297,
+  298,  299,  300,  301,    0,   -1,   -1,   -1,  306,   -1,
+   -1,  256,   -1,   -1,   -1,   -1,   -1,   -1,  263,  264,
+  265,  266,  267,  268,  269,    0,   -1,   -1,   -1,  274,
+  275,   -1,   -1,  278,   -1,   -1,   -1,   -1,  125,    0,
+   -1,   -1,   -1,   -1,  289,  290,  291,  292,  293,  294,
+  295,  296,  297,  298,  299,  300,  301,  256,   -1,   -1,
+   -1,  306,   -1,   -1,  263,  264,  265,  266,  267,  268,
+  269,   -1,   -1,   -1,   -1,  274,  275,   -1,   -1,  278,
+   -1,   -1,   -1,   -1,  125,   -1,   -1,   -1,   -1,   -1,
+  289,  290,  291,  292,  293,  294,  295,  296,  297,  298,
+  299,  300,  301,  256,  125,   -1,   -1,  306,   -1,   -1,
+  263,  264,  265,  266,  267,  268,  269,   -1,   -1,   -1,
+   -1,  274,  275,   -1,   -1,  278,   -1,   -1,   -1,  125,
+   -1,   -1,   -1,   -1,   -1,   -1,  289,  290,  291,  292,
+  293,  294,  295,  296,  297,  298,  299,  300,  301,   -1,
+  125,   -1,   -1,  306,   -1,   -1,   -1,   -1,   -1,   -1,
+   -1,   -1,   -1,   -1,  125,   -1,   -1,   -1,   -1,  256,
+   -1,   -1,   -1,   -1,   -1,   -1,  263,  264,  265,  266,
+  267,  268,  269,   -1,   -1,   -1,   -1,  274,  275,   -1,
+   -1,  278,   -1,   -1,   -1,   -1,   -1,   -1,   -1,   -1,
+   -1,   -1,  289,  290,  291,  292,  293,  294,  295,  296,
+  297,  298,  299,  300,  301,  256,   -1,   -1,   -1,  306,
+   -1,   -1,  263,  264,  265,  266,  267,  268,  269,   -1,
+   -1,   -1,   -1,  274,  275,  256,   -1,   -1,   -1,   -1,
+   -1,   -1,  263,  264,  265,  266,  267,  268,  269,   -1,
+   -1,   -1,   -1,  274,  275,   -1,   -1,   -1,   -1,   -1,
+  256,   -1,   -1,   -1,   -1,   -1,   -1,  263,  264,  265,
+  266,  267,  268,  269,   -1,   -1,   -1,   -1,  274,  275,
+   -1,  256,   -1,   -1,   -1,   -1,   -1,   -1,  263,  264,
+  265,  266,  267,  268,  269,  256,   -1,   -1,   -1,  274,
+  275,   -1,  263,  264,  265,  266,  267,  268,  269,   -1,
+   -1,   -1,   -1,  274,  275,
+};
+#define YYFINAL 1
+#ifndef YYDEBUG
+#define YYDEBUG 0
+#endif
+#define YYMAXTOKEN 310
+#if YYDEBUG
+char *yyname[] = {
+"end-of-file",0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,"','","'-'",0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,"'='",0,0,"'@'",0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,"']'",0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,"'{'",0,"'}'",0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+"STRING","NUMBER","FLOAT","VOLTAGE","CURRENT","SIZE","VERS_1","MANFID","FUNCID",
+"CONFIG","CFTABLE","MFC","CHECKSUM","POST","ROM","BASE","LAST_INDEX","DEV_INFO",
+"ATTR_DEV_INFO","NO_INFO","TIME","TIMING","WAIT","READY","RESERVED","VNOM",
+"VMIN","VMAX","ISTATIC","IAVG","IPEAK","IDOWN","VCC","VPP1","VPP2","IO","MEM",
+"DEFAULT","BVD","WP","RDYBSY","MWAIT","AUDIO","READONLY","PWRDOWN","BIT8",
+"BIT16","LINES","RANGE","IRQ_NO","MASK","LEVEL","PULSE","SHARED",
+};
+char *yyrule[] = {
+"$accept : cis",
+"cis : chain",
+"cis : chain mfc",
+"chain :",
+"chain : chain tuple",
+"mfc : MFC '{' chain '}'",
+"mfc : mfc ',' '{' chain '}'",
+"tuple : dev_info",
+"tuple : attr_dev_info",
+"tuple : vers_1",
+"tuple : manfid",
+"tuple : funcid",
+"tuple : config",
+"tuple : cftab",
+"tuple : checksum",
+"tuple : error",
+"dev_info : DEV_INFO",
+"dev_info : dev_info NUMBER TIME ',' SIZE",
+"dev_info : dev_info NO_INFO",
+"attr_dev_info : ATTR_DEV_INFO",
+"attr_dev_info : attr_dev_info NUMBER TIME ',' SIZE",
+"attr_dev_info : attr_dev_info NO_INFO",
+"vers_1 : VERS_1 FLOAT",
+"vers_1 : vers_1 ',' STRING",
+"manfid : MANFID NUMBER ',' NUMBER",
+"funcid : FUNCID NUMBER",
+"funcid : funcid POST",
+"funcid : funcid ROM",
+"config : CONFIG BASE NUMBER MASK NUMBER LAST_INDEX NUMBER",
+"pwr : VNOM VOLTAGE",
+"pwr : VMIN VOLTAGE",
+"pwr : VMAX VOLTAGE",
+"pwr : ISTATIC CURRENT",
+"pwr : IAVG CURRENT",
+"pwr : IPEAK CURRENT",
+"pwr : IDOWN CURRENT",
+"pwrlist :",
+"pwrlist : pwrlist pwr",
+"timing : cftab TIMING",
+"timing : timing WAIT TIME",
+"timing : timing READY TIME",
+"timing : timing RESERVED TIME",
+"io : cftab IO NUMBER '-' NUMBER",
+"io : io ',' NUMBER '-' NUMBER",
+"io : io BIT8",
+"io : io BIT16",
+"io : io LINES '=' NUMBER ']'",
+"io : io RANGE",
+"mem : cftab MEM NUMBER '-' NUMBER '@' NUMBER",
+"mem : mem ',' NUMBER '-' NUMBER '@' NUMBER",
+"mem : mem BIT8",
+"mem : mem BIT16",
+"irq : cftab IRQ_NO NUMBER",
+"irq : cftab IRQ_NO MASK NUMBER",
+"irq : irq PULSE",
+"irq : irq LEVEL",
+"irq : irq SHARED",
+"cftab : CFTABLE NUMBER",
+"cftab : cftab DEFAULT",
+"cftab : cftab BVD",
+"cftab : cftab WP",
+"cftab : cftab RDYBSY",
+"cftab : cftab MWAIT",
+"cftab : cftab AUDIO",
+"cftab : cftab READONLY",
+"cftab : cftab PWRDOWN",
+"cftab : cftab VCC pwrlist",
+"cftab : cftab VPP1 pwrlist",
+"cftab : cftab VPP2 pwrlist",
+"cftab : io",
+"cftab : mem",
+"cftab : irq",
+"cftab : timing",
+"checksum : CHECKSUM NUMBER '-' NUMBER '=' NUMBER",
+};
+#endif
+#ifdef YYSTACKSIZE
+#undef YYMAXDEPTH
+#define YYMAXDEPTH YYSTACKSIZE
+#else
+#ifdef YYMAXDEPTH
+#define YYSTACKSIZE YYMAXDEPTH
+#else
+#define YYSTACKSIZE 500
+#define YYMAXDEPTH 500
+#endif
+#endif
+int yydebug;
+int yynerrs;
+int yyerrflag;
+int yychar;
+short *yyssp;
+YYSTYPE *yyvsp;
+YYSTYPE yyval;
+YYSTYPE yylval;
+short yyss[YYSTACKSIZE];
+YYSTYPE yyvs[YYSTACKSIZE];
+#define yystacksize YYSTACKSIZE
+#line 359 "yacc_cis.y"
+
+static tuple_info_t *new_tuple(u_char type, cisparse_t *parse)
+{
+    tuple_info_t *t = calloc(1, sizeof(tuple_info_t));
+    t->type = type;
+    t->parse = parse;
+    t->next = NULL;
+}
+
+void yyerror(char *msg, ...)
+{
+    va_list ap;
+    char str[256];
+
+    va_start(ap, msg);
+    sprintf(str, "error at line %d: ", current_lineno);
+    vsprintf(str+strlen(str), msg, ap);
+    fprintf(stderr, "%s\n", str);
+    va_end(ap);
+}
+
+#ifdef DEBUG
+void main(int argc, char *argv[])
+{
+    if (argc > 1)
+	parse_cis(argv[1]);
+}
+#endif
+#line 500 "y.tab.c"
+#define YYABORT goto yyabort
+#define YYREJECT goto yyabort
+#define YYACCEPT goto yyaccept
+#define YYERROR goto yyerrlab
+int
+yyparse()
+{
+    register int yym, yyn, yystate;
+#if YYDEBUG
+    register char *yys;
+    extern char *getenv();
+
+    if (yys = getenv("YYDEBUG"))
+    {
+        yyn = *yys;
+        if (yyn >= '0' && yyn <= '9')
+            yydebug = yyn - '0';
+    }
+#endif
+
+    yynerrs = 0;
+    yyerrflag = 0;
+    yychar = (-1);
+
+    yyssp = yyss;
+    yyvsp = yyvs;
+    *yyssp = yystate = 0;
+
+yyloop:
+    if (yyn = yydefred[yystate]) goto yyreduce;
+    if (yychar < 0)
+    {
+        if ((yychar = yylex()) < 0) yychar = 0;
+#if YYDEBUG
+        if (yydebug)
+        {
+            yys = 0;
+            if (yychar <= YYMAXTOKEN) yys = yyname[yychar];
+            if (!yys) yys = "illegal-symbol";
+            printf("%sdebug: state %d, reading %d (%s)\n",
+                    YYPREFIX, yystate, yychar, yys);
+        }
+#endif
+    }
+    if ((yyn = yysindex[yystate]) && (yyn += yychar) >= 0 &&
+            yyn <= YYTABLESIZE && yycheck[yyn] == yychar)
+    {
+#if YYDEBUG
+        if (yydebug)
+            printf("%sdebug: state %d, shifting to state %d\n",
+                    YYPREFIX, yystate, yytable[yyn]);
+#endif
+        if (yyssp >= yyss + yystacksize - 1)
+        {
+            goto yyoverflow;
+        }
+        *++yyssp = yystate = yytable[yyn];
+        *++yyvsp = yylval;
+        yychar = (-1);
+        if (yyerrflag > 0)  --yyerrflag;
+        goto yyloop;
+    }
+    if ((yyn = yyrindex[yystate]) && (yyn += yychar) >= 0 &&
+            yyn <= YYTABLESIZE && yycheck[yyn] == yychar)
+    {
+        yyn = yytable[yyn];
+        goto yyreduce;
+    }
+    if (yyerrflag) goto yyinrecovery;
+#ifdef lint
+    goto yynewerror;
+#endif
+yynewerror:
+    yyerror("syntax error");
+#ifdef lint
+    goto yyerrlab;
+#endif
+yyerrlab:
+    ++yynerrs;
+yyinrecovery:
+    if (yyerrflag < 3)
+    {
+        yyerrflag = 3;
+        for (;;)
+        {
+            if ((yyn = yysindex[*yyssp]) && (yyn += YYERRCODE) >= 0 &&
+                    yyn <= YYTABLESIZE && yycheck[yyn] == YYERRCODE)
+            {
+#if YYDEBUG
+                if (yydebug)
+                    printf("%sdebug: state %d, error recovery shifting\
+ to state %d\n", YYPREFIX, *yyssp, yytable[yyn]);
+#endif
+                if (yyssp >= yyss + yystacksize - 1)
+                {
+                    goto yyoverflow;
+                }
+                *++yyssp = yystate = yytable[yyn];
+                *++yyvsp = yylval;
+                goto yyloop;
+            }
+            else
+            {
+#if YYDEBUG
+                if (yydebug)
+                    printf("%sdebug: error recovery discarding state %d\n",
+                            YYPREFIX, *yyssp);
+#endif
+                if (yyssp <= yyss) goto yyabort;
+                --yyssp;
+                --yyvsp;
+            }
+        }
+    }
+    else
+    {
+        if (yychar == 0) goto yyabort;
+#if YYDEBUG
+        if (yydebug)
+        {
+            yys = 0;
+            if (yychar <= YYMAXTOKEN) yys = yyname[yychar];
+            if (!yys) yys = "illegal-symbol";
+            printf("%sdebug: state %d, error recovery discards token %d (%s)\n",
+                    YYPREFIX, yystate, yychar, yys);
+        }
+#endif
+        yychar = (-1);
+        goto yyloop;
+    }
+yyreduce:
+#if YYDEBUG
+    if (yydebug)
+        printf("%sdebug: state %d, reducing by rule %d (%s)\n",
+                YYPREFIX, yystate, yyn, yyrule[yyn]);
+#endif
+    yym = yylen[yyn];
+    yyval = yyvsp[1-yym];
+    switch (yyn)
+    {
+case 1:
+#line 84 "yacc_cis.y"
+{ cis_root = yyvsp[0].tuple; }
+break;
+case 2:
+#line 86 "yacc_cis.y"
+{ cis_root = yyvsp[-1].tuple; }
+break;
+case 3:
+#line 90 "yacc_cis.y"
+{ yyval.tuple = NULL; }
+break;
+case 4:
+#line 92 "yacc_cis.y"
+{
+		    if (yyvsp[-1].tuple == NULL) {
+			yyval.tuple = yyvsp[0].tuple;
+		    } else if (yyvsp[0].tuple == NULL) {
+			yyval.tuple = yyvsp[-1].tuple;
+		    } else {
+			tuple_info_t *tail = yyvsp[-1].tuple;
+			while (tail->next != NULL) tail = tail->next;
+			tail->next = yyvsp[0].tuple;
+			yyval.tuple = yyvsp[-1].tuple;
+		    }
+		}
+break;
+case 5:
+#line 107 "yacc_cis.y"
+{ mfc[nf++] = yyvsp[-1].tuple; }
+break;
+case 6:
+#line 109 "yacc_cis.y"
+{ mfc[nf++] = yyvsp[-1].tuple; }
+break;
+case 7:
+#line 113 "yacc_cis.y"
+{ yyval.tuple = new_tuple(CISTPL_DEVICE, yyvsp[0].parse); }
+break;
+case 8:
+#line 115 "yacc_cis.y"
+{ yyval.tuple = new_tuple(CISTPL_DEVICE_A, yyvsp[0].parse); }
+break;
+case 9:
+#line 117 "yacc_cis.y"
+{ yyval.tuple = new_tuple(CISTPL_VERS_1, yyvsp[0].parse); }
+break;
+case 10:
+#line 119 "yacc_cis.y"
+{ yyval.tuple = new_tuple(CISTPL_MANFID, yyvsp[0].parse); }
+break;
+case 11:
+#line 121 "yacc_cis.y"
+{ yyval.tuple = new_tuple(CISTPL_FUNCID, yyvsp[0].parse); }
+break;
+case 12:
+#line 123 "yacc_cis.y"
+{ yyval.tuple = new_tuple(CISTPL_CONFIG, yyvsp[0].parse); }
+break;
+case 13:
+#line 125 "yacc_cis.y"
+{ yyval.tuple = new_tuple(CISTPL_CFTABLE_ENTRY, yyvsp[0].parse); }
+break;
+case 14:
+#line 127 "yacc_cis.y"
+{ yyval.tuple = NULL; }
+break;
+case 15:
+#line 129 "yacc_cis.y"
+{ yyval.tuple = NULL; }
+break;
+case 16:
+#line 133 "yacc_cis.y"
+{ yyval.parse = calloc(1, sizeof(cisparse_t)); }
+break;
+case 17:
+#line 135 "yacc_cis.y"
+{
+		    yyval.parse->device.dev[yyval.parse->device.ndev].type = yyvsp[-3].num;
+		    yyval.parse->device.dev[yyval.parse->device.ndev].speed = yyvsp[-2].num;
+		    yyval.parse->device.dev[yyval.parse->device.ndev].size = yyvsp[0].num;
+		    yyval.parse->device.ndev++;
+		}
+break;
+case 19:
+#line 145 "yacc_cis.y"
+{ yyval.parse = calloc(1, sizeof(cisparse_t)); }
+break;
+case 20:
+#line 147 "yacc_cis.y"
+{
+		    yyval.parse->device.dev[yyval.parse->device.ndev].type = yyvsp[-3].num;
+		    yyval.parse->device.dev[yyval.parse->device.ndev].speed = yyvsp[-2].num;
+		    yyval.parse->device.dev[yyval.parse->device.ndev].size = yyvsp[0].num;
+		    yyval.parse->device.ndev++;
+		}
+break;
+case 22:
+#line 157 "yacc_cis.y"
+{
+		    yyval.parse = calloc(1, sizeof(cisparse_t));
+		    yyval.parse->version_1.major = yyvsp[0].flt;
+		    yyvsp[0].flt -= floor(yyvsp[0].flt+0.01);
+		    while (fabs(yyvsp[0].flt - floor(yyvsp[0].flt+0.5)) > 0.01) {
+			yyvsp[0].flt *= 10;
+		    }
+		    yyval.parse->version_1.minor = yyvsp[0].flt+0.01;
+		}
+break;
+case 23:
+#line 167 "yacc_cis.y"
+{
+		    cistpl_vers_1_t *v = &yyval.parse->version_1;
+		    u_int pos = 0;
+		    if (v->ns) {
+			pos = v->ofs[v->ns-1];
+			pos += strlen(v->str+pos)+1;
+		    }
+		    v->ofs[v->ns] = pos;
+		    strcpy(v->str+pos, yyvsp[0].str);
+		    v->ns++;
+		}
+break;
+case 24:
+#line 181 "yacc_cis.y"
+{
+		    yyval.parse = calloc(1, sizeof(cisparse_t));
+		    yyval.parse->manfid.manf = yyvsp[-2].num;
+		    yyval.parse->manfid.card = yyvsp[0].num;
+		}
+break;
+case 25:
+#line 189 "yacc_cis.y"
+{
+		    yyval.parse = calloc(1, sizeof(cisparse_t));
+		    yyval.parse->funcid.func = yyvsp[0].num;
+		}
+break;
+case 26:
+#line 194 "yacc_cis.y"
+{ yyval.parse->funcid.sysinit |= CISTPL_SYSINIT_POST; }
+break;
+case 27:
+#line 196 "yacc_cis.y"
+{ yyval.parse->funcid.sysinit |= CISTPL_SYSINIT_ROM; }
+break;
+case 28:
+#line 200 "yacc_cis.y"
+{
+		    yyval.parse = calloc(1, sizeof(cisparse_t));
+		    yyval.parse->config.base = yyvsp[-4].num;
+		    yyval.parse->config.rmask[0] = yyvsp[-2].num;
+		    yyval.parse->config.last_idx = yyvsp[0].num;
+		}
+break;
+case 29:
+#line 209 "yacc_cis.y"
+{
+		    yyval.pwr.present = CISTPL_POWER_VNOM;
+		    yyval.pwr.param[0] = yyvsp[0].num;
+		}
+break;
+case 30:
+#line 214 "yacc_cis.y"
+{
+		    yyval.pwr.present = CISTPL_POWER_VMIN;
+		    yyval.pwr.param[0] = yyvsp[0].num;
+		}
+break;
+case 31:
+#line 219 "yacc_cis.y"
+{
+		    yyval.pwr.present = CISTPL_POWER_VMAX;
+		    yyval.pwr.param[0] = yyvsp[0].num;
+		}
+break;
+case 32:
+#line 224 "yacc_cis.y"
+{
+		    yyval.pwr.present = CISTPL_POWER_ISTATIC;
+		    yyval.pwr.param[0] = yyvsp[0].num;
+		}
+break;
+case 33:
+#line 229 "yacc_cis.y"
+{
+		    yyval.pwr.present = CISTPL_POWER_IAVG;
+		    yyval.pwr.param[0] = yyvsp[0].num;
+		}
+break;
+case 34:
+#line 234 "yacc_cis.y"
+{
+		    yyval.pwr.present = CISTPL_POWER_IPEAK;
+		    yyval.pwr.param[0] = yyvsp[0].num;
+		}
+break;
+case 35:
+#line 239 "yacc_cis.y"
+{
+		    yyval.pwr.present = CISTPL_POWER_IDOWN;
+		    yyval.pwr.param[0] = yyvsp[0].num;
+		}
+break;
+case 36:
+#line 246 "yacc_cis.y"
+{
+		    yyval.pwr.present = 0;
+		}
+break;
+case 37:
+#line 250 "yacc_cis.y"
+{
+		    yyval.pwr.present |= 1<<(yyvsp[0].pwr.present);
+		    yyval.pwr.param[yyvsp[0].pwr.present] = yyvsp[0].pwr.param[0];
+		}
+break;
+case 42:
+#line 263 "yacc_cis.y"
+{
+		    int n = yyval.parse->cftable_entry.io.nwin;
+		    yyval.parse->cftable_entry.io.win[n].base = yyvsp[-2].num;
+		    yyval.parse->cftable_entry.io.win[n].len = yyvsp[0].num-yyvsp[-2].num+1;
+		    yyval.parse->cftable_entry.io.nwin++;
+		}
+break;
+case 43:
+#line 270 "yacc_cis.y"
+{
+		    int n = yyval.parse->cftable_entry.io.nwin;
+		    yyval.parse->cftable_entry.io.win[n].base = yyvsp[-2].num;
+		    yyval.parse->cftable_entry.io.win[n].len = yyvsp[0].num-yyvsp[-2].num+1;
+		    yyval.parse->cftable_entry.io.nwin++;
+		}
+break;
+case 44:
+#line 277 "yacc_cis.y"
+{ yyval.parse->cftable_entry.io.flags |= CISTPL_IO_8BIT; }
+break;
+case 45:
+#line 279 "yacc_cis.y"
+{ yyval.parse->cftable_entry.io.flags |= CISTPL_IO_16BIT; }
+break;
+case 46:
+#line 281 "yacc_cis.y"
+{ yyval.parse->cftable_entry.io.flags |= yyvsp[-1].num; }
+break;
+case 48:
+#line 286 "yacc_cis.y"
+{
+		    int n = yyval.parse->cftable_entry.mem.nwin;
+		    yyval.parse->cftable_entry.mem.win[n].card_addr = yyvsp[-4].num;
+		    yyval.parse->cftable_entry.mem.win[n].host_addr = yyvsp[0].num;
+		    yyval.parse->cftable_entry.mem.win[n].len = yyvsp[-2].num-yyvsp[-4].num+1;
+		    yyval.parse->cftable_entry.mem.nwin++;
+		}
+break;
+case 49:
+#line 294 "yacc_cis.y"
+{
+		    int n = yyval.parse->cftable_entry.mem.nwin;
+		    yyval.parse->cftable_entry.mem.win[n].card_addr = yyvsp[-4].num;
+		    yyval.parse->cftable_entry.mem.win[n].host_addr = yyvsp[0].num;
+		    yyval.parse->cftable_entry.mem.win[n].len = yyvsp[-2].num-yyvsp[-4].num+1;
+		    yyval.parse->cftable_entry.mem.nwin++;
+		}
+break;
+case 50:
+#line 302 "yacc_cis.y"
+{ yyval.parse->cftable_entry.io.flags |= CISTPL_IO_8BIT; }
+break;
+case 51:
+#line 304 "yacc_cis.y"
+{ yyval.parse->cftable_entry.io.flags |= CISTPL_IO_16BIT; }
+break;
+case 52:
+#line 308 "yacc_cis.y"
+{ yyval.parse->cftable_entry.irq.IRQInfo1 = (yyvsp[0].num & 0x0f); }
+break;
+case 53:
+#line 310 "yacc_cis.y"
+{
+		    yyval.parse->cftable_entry.irq.IRQInfo1 = IRQ_INFO2_VALID;
+		    yyval.parse->cftable_entry.irq.IRQInfo2 = yyvsp[0].num;
+		}
+break;
+case 54:
+#line 315 "yacc_cis.y"
+{ yyval.parse->cftable_entry.irq.IRQInfo1 |= IRQ_PULSE_ID; }
+break;
+case 55:
+#line 317 "yacc_cis.y"
+{ yyval.parse->cftable_entry.irq.IRQInfo1 |= IRQ_LEVEL_ID; }
+break;
+case 56:
+#line 319 "yacc_cis.y"
+{ yyval.parse->cftable_entry.irq.IRQInfo1 |= IRQ_SHARE_ID; }
+break;
+case 57:
+#line 323 "yacc_cis.y"
+{
+		    yyval.parse = calloc(1, sizeof(cisparse_t));
+		    yyval.parse->cftable_entry.index = yyvsp[0].num;
+		}
+break;
+case 58:
+#line 328 "yacc_cis.y"
+{ yyval.parse->cftable_entry.flags |= CISTPL_CFTABLE_DEFAULT; }
+break;
+case 59:
+#line 330 "yacc_cis.y"
+{ yyval.parse->cftable_entry.flags |= CISTPL_CFTABLE_BVDS; }
+break;
+case 60:
+#line 332 "yacc_cis.y"
+{ yyval.parse->cftable_entry.flags |= CISTPL_CFTABLE_WP; }
+break;
+case 61:
+#line 334 "yacc_cis.y"
+{ yyval.parse->cftable_entry.flags |= CISTPL_CFTABLE_RDYBSY; }
+break;
+case 62:
+#line 336 "yacc_cis.y"
+{ yyval.parse->cftable_entry.flags |= CISTPL_CFTABLE_MWAIT; }
+break;
+case 63:
+#line 338 "yacc_cis.y"
+{ yyval.parse->cftable_entry.flags |= CISTPL_CFTABLE_AUDIO; }
+break;
+case 64:
+#line 340 "yacc_cis.y"
+{ yyval.parse->cftable_entry.flags |= CISTPL_CFTABLE_READONLY; }
+break;
+case 65:
+#line 342 "yacc_cis.y"
+{ yyval.parse->cftable_entry.flags |= CISTPL_CFTABLE_PWRDOWN; }
+break;
+case 66:
+#line 344 "yacc_cis.y"
+{ yyval.parse->cftable_entry.vcc = yyvsp[0].pwr; }
+break;
+case 67:
+#line 346 "yacc_cis.y"
+{ yyval.parse->cftable_entry.vpp1 = yyvsp[0].pwr; }
+break;
+case 68:
+#line 348 "yacc_cis.y"
+{ yyval.parse->cftable_entry.vpp2 = yyvsp[0].pwr; }
+break;
+case 73:
+#line 356 "yacc_cis.y"
+{ yyval.parse = NULL; }
+break;
+#line 994 "y.tab.c"
+    }
+    yyssp -= yym;
+    yystate = *yyssp;
+    yyvsp -= yym;
+    yym = yylhs[yyn];
+    if (yystate == 0 && yym == 0)
+    {
+#if YYDEBUG
+        if (yydebug)
+            printf("%sdebug: after reduction, shifting from state 0 to\
+ state %d\n", YYPREFIX, YYFINAL);
+#endif
+        yystate = YYFINAL;
+        *++yyssp = YYFINAL;
+        *++yyvsp = yyval;
+        if (yychar < 0)
+        {
+            if ((yychar = yylex()) < 0) yychar = 0;
+#if YYDEBUG
+            if (yydebug)
+            {
+                yys = 0;
+                if (yychar <= YYMAXTOKEN) yys = yyname[yychar];
+                if (!yys) yys = "illegal-symbol";
+                printf("%sdebug: state %d, reading %d (%s)\n",
+                        YYPREFIX, YYFINAL, yychar, yys);
+            }
+#endif
+        }
+        if (yychar == 0) goto yyaccept;
+        goto yyloop;
+    }
+    if ((yyn = yygindex[yym]) && (yyn += yystate) >= 0 &&
+            yyn <= YYTABLESIZE && yycheck[yyn] == yystate)
+        yystate = yytable[yyn];
+    else
+        yystate = yydgoto[yym];
+#if YYDEBUG
+    if (yydebug)
+        printf("%sdebug: after reduction, shifting from state %d \
+to state %d\n", YYPREFIX, *yyssp, yystate);
+#endif
+    if (yyssp >= yyss + yystacksize - 1)
+    {
+        goto yyoverflow;
+    }
+    *++yyssp = yystate;
+    *++yyvsp = yyval;
+    goto yyloop;
+yyoverflow:
+    yyerror("yacc stack overflow");
+yyabort:
+    return (1);
+yyaccept:
+    return (0);
+}
Index: oldkernel/linux/pcmcia-cs-3.1.15/debug-tools/yacc_cis.h
diff -u /dev/null linux/pcmcia-cs-3.1.15/debug-tools/yacc_cis.h:1.1
--- /dev/null	Mon Jul 31 21:15:10 2000
+++ linux/pcmcia-cs-3.1.15/debug-tools/yacc_cis.h	Fri Jul  7 16:34:58 2000
@@ -0,0 +1,63 @@
+#define STRING 257
+#define NUMBER 258
+#define FLOAT 259
+#define VOLTAGE 260
+#define CURRENT 261
+#define SIZE 262
+#define VERS_1 263
+#define MANFID 264
+#define FUNCID 265
+#define CONFIG 266
+#define CFTABLE 267
+#define MFC 268
+#define CHECKSUM 269
+#define POST 270
+#define ROM 271
+#define BASE 272
+#define LAST_INDEX 273
+#define DEV_INFO 274
+#define ATTR_DEV_INFO 275
+#define NO_INFO 276
+#define TIME 277
+#define TIMING 278
+#define WAIT 279
+#define READY 280
+#define RESERVED 281
+#define VNOM 282
+#define VMIN 283
+#define VMAX 284
+#define ISTATIC 285
+#define IAVG 286
+#define IPEAK 287
+#define IDOWN 288
+#define VCC 289
+#define VPP1 290
+#define VPP2 291
+#define IO 292
+#define MEM 293
+#define DEFAULT 294
+#define BVD 295
+#define WP 296
+#define RDYBSY 297
+#define MWAIT 298
+#define AUDIO 299
+#define READONLY 300
+#define PWRDOWN 301
+#define BIT8 302
+#define BIT16 303
+#define LINES 304
+#define RANGE 305
+#define IRQ_NO 306
+#define MASK 307
+#define LEVEL 308
+#define PULSE 309
+#define SHARED 310
+typedef union {
+    char *str;
+    u_long num;
+    float flt;
+    cistpl_power_t pwr;
+    cisparse_t *parse;
+    tuple_info_t *tuple;
+} YYSTYPE;
+extern YYSTYPE yylval;
Index: oldkernel/linux/pcmcia-cs-3.1.15/debug-tools/yacc_cis.y
diff -u /dev/null linux/pcmcia-cs-3.1.15/debug-tools/yacc_cis.y:1.1
--- /dev/null	Mon Jul 31 21:15:10 2000
+++ linux/pcmcia-cs-3.1.15/debug-tools/yacc_cis.y	Fri Jul  7 16:34:58 2000
@@ -0,0 +1,386 @@
+%{
+/*
+ * yacc_cis.y 1.10 1999/10/25 19:57: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@pcmcia.sourceforge.org>.  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 <sys/types.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <stdarg.h>
+#include <math.h>
+
+#include <pcmcia/cs_types.h>
+#include <pcmcia/cs.h>
+#include <pcmcia/cistpl.h>
+
+#include "pack_cis.h"
+
+/* If bison: generate nicer error messages */ 
+#define YYERROR_VERBOSE 1
+ 
+extern int current_lineno;
+
+void yyerror(char *msg, ...);
+static tuple_info_t *new_tuple(u_char type, cisparse_t *parse);
+
+%}
+
+%token STRING NUMBER FLOAT VOLTAGE CURRENT SIZE
+%token VERS_1 MANFID FUNCID CONFIG CFTABLE MFC CHECKSUM
+%token POST ROM BASE LAST_INDEX
+%token DEV_INFO ATTR_DEV_INFO NO_INFO
+%token TIME TIMING WAIT READY RESERVED
+%token VNOM VMIN VMAX ISTATIC IAVG IPEAK IDOWN
+%token VCC VPP1 VPP2 IO MEM
+%token DEFAULT BVD WP RDYBSY MWAIT AUDIO READONLY PWRDOWN
+%token BIT8 BIT16 LINES RANGE
+%token IRQ_NO MASK LEVEL PULSE SHARED
+
+%union {
+    char *str;
+    u_long num;
+    float flt;
+    cistpl_power_t pwr;
+    cisparse_t *parse;
+    tuple_info_t *tuple;
+}
+
+%type <str> STRING
+%type <num> NUMBER SIZE VOLTAGE CURRENT TIME
+%type <flt> FLOAT
+%type <pwr> pwr pwrlist
+%type <parse> vers_1 manfid funcid config cftab io mem irq timing
+%type <parse> dev_info attr_dev_info checksum
+%type <tuple> tuple chain cis;
+%%
+
+cis:	  chain
+		{ cis_root = $1; }
+	| chain mfc
+		{ cis_root = $1; }
+	;
+
+chain:	  /* nothing */
+		{ $$ = NULL; }
+	| chain tuple
+		{
+		    if ($1 == NULL) {
+			$$ = $2;
+		    } else if ($2 == NULL) {
+			$$ = $1;
+		    } else {
+			tuple_info_t *tail = $1;
+			while (tail->next != NULL) tail = tail->next;
+			tail->next = $2;
+			$$ = $1;
+		    }
+		} 
+	;
+
+mfc:	  MFC '{' chain '}'
+		{ mfc[nf++] = $3; }
+	| mfc ',' '{' chain '}'
+		{ mfc[nf++] = $4; }
+	;
+	
+tuple:	  dev_info
+		{ $$ = new_tuple(CISTPL_DEVICE, $1); }
+	| attr_dev_info
+		{ $$ = new_tuple(CISTPL_DEVICE_A, $1); }
+	| vers_1
+		{ $$ = new_tuple(CISTPL_VERS_1, $1); }
+	| manfid
+		{ $$ = new_tuple(CISTPL_MANFID, $1); }
+	| funcid
+		{ $$ = new_tuple(CISTPL_FUNCID, $1); }
+	| config
+		{ $$ = new_tuple(CISTPL_CONFIG, $1); }
+	| cftab
+		{ $$ = new_tuple(CISTPL_CFTABLE_ENTRY, $1); }
+	| checksum
+		{ $$ = NULL; }
+	| error
+		{ $$ = NULL; }
+	;
+
+dev_info: DEV_INFO
+		{ $$ = calloc(1, sizeof(cisparse_t)); }
+	| dev_info NUMBER TIME ',' SIZE
+		{
+		    $$->device.dev[$$->device.ndev].type = $2;
+		    $$->device.dev[$$->device.ndev].speed = $3;
+		    $$->device.dev[$$->device.ndev].size = $5;
+		    $$->device.ndev++;
+		}
+	| dev_info NO_INFO
+	;
+
+attr_dev_info: ATTR_DEV_INFO
+		{ $$ = calloc(1, sizeof(cisparse_t)); }
+	| attr_dev_info NUMBER TIME ',' SIZE
+		{
+		    $$->device.dev[$$->device.ndev].type = $2;
+		    $$->device.dev[$$->device.ndev].speed = $3;
+		    $$->device.dev[$$->device.ndev].size = $5;
+		    $$->device.ndev++;
+		}
+	| attr_dev_info NO_INFO
+	;
+
+vers_1:	  VERS_1 FLOAT
+		{
+		    $$ = calloc(1, sizeof(cisparse_t));
+		    $$->version_1.major = $2;
+		    $2 -= floor($2+0.01);
+		    while (fabs($2 - floor($2+0.5)) > 0.01) {
+			$2 *= 10;
+		    }
+		    $$->version_1.minor = $2+0.01;
+		}
+	| vers_1 ',' STRING
+		{
+		    cistpl_vers_1_t *v = &$$->version_1;
+		    u_int pos = 0;
+		    if (v->ns) {
+			pos = v->ofs[v->ns-1];
+			pos += strlen(v->str+pos)+1;
+		    }
+		    v->ofs[v->ns] = pos;
+		    strcpy(v->str+pos, $3);
+		    v->ns++;
+		}
+	;
+
+manfid:	  MANFID NUMBER ',' NUMBER
+		{
+		    $$ = calloc(1, sizeof(cisparse_t));
+		    $$->manfid.manf = $2;
+		    $$->manfid.card = $4;
+		}
+	;
+
+funcid:	  FUNCID NUMBER 
+		{
+		    $$ = calloc(1, sizeof(cisparse_t));
+		    $$->funcid.func = $2;
+		}
+	| funcid POST
+		{ $$->funcid.sysinit |= CISTPL_SYSINIT_POST; }
+	| funcid ROM
+		{ $$->funcid.sysinit |= CISTPL_SYSINIT_ROM; }
+	;
+
+config:	  CONFIG BASE NUMBER MASK NUMBER  LAST_INDEX NUMBER
+		{
+		    $$ = calloc(1, sizeof(cisparse_t));
+		    $$->config.base = $3;
+		    $$->config.rmask[0] = $5;
+		    $$->config.last_idx = $7;
+		}
+	;
+
+pwr:	  VNOM VOLTAGE
+		{
+		    $$.present = CISTPL_POWER_VNOM;
+		    $$.param[0] = $2;
+		}
+	| VMIN VOLTAGE
+		{
+		    $$.present = CISTPL_POWER_VMIN;
+		    $$.param[0] = $2;
+		}
+	| VMAX VOLTAGE
+		{
+		    $$.present = CISTPL_POWER_VMAX;
+		    $$.param[0] = $2;
+		}
+	| ISTATIC CURRENT
+		{
+		    $$.present = CISTPL_POWER_ISTATIC;
+		    $$.param[0] = $2;
+		}
+	| IAVG CURRENT
+		{
+		    $$.present = CISTPL_POWER_IAVG;
+		    $$.param[0] = $2;
+		}
+	| IPEAK CURRENT
+		{
+		    $$.present = CISTPL_POWER_IPEAK;
+		    $$.param[0] = $2;
+		}
+	| IDOWN CURRENT
+		{
+		    $$.present = CISTPL_POWER_IDOWN;
+		    $$.param[0] = $2;
+		}
+	;
+
+pwrlist:  /* nothing */
+		{
+		    $$.present = 0;
+		}
+	| pwrlist pwr
+		{
+		    $$.present |= 1<<($2.present);
+		    $$.param[$2.present] = $2.param[0];
+		}
+	;
+
+timing:	  cftab TIMING
+	| timing WAIT TIME
+	| timing READY TIME
+	| timing RESERVED TIME
+	;
+
+io:	  cftab IO NUMBER '-' NUMBER
+		{
+		    int n = $$->cftable_entry.io.nwin;
+		    $$->cftable_entry.io.win[n].base = $3;
+		    $$->cftable_entry.io.win[n].len = $5-$3+1;
+		    $$->cftable_entry.io.nwin++;
+		}
+	| io ',' NUMBER '-' NUMBER
+		{
+		    int n = $$->cftable_entry.io.nwin;
+		    $$->cftable_entry.io.win[n].base = $3;
+		    $$->cftable_entry.io.win[n].len = $5-$3+1;
+		    $$->cftable_entry.io.nwin++;
+		}
+	| io BIT8
+		{ $$->cftable_entry.io.flags |= CISTPL_IO_8BIT; }
+	| io BIT16
+		{ $$->cftable_entry.io.flags |= CISTPL_IO_16BIT; }
+	| io LINES '=' NUMBER ']'
+		{ $$->cftable_entry.io.flags |= $4; }
+	| io RANGE
+	;	
+
+mem:	  cftab MEM NUMBER '-' NUMBER '@' NUMBER
+		{
+		    int n = $$->cftable_entry.mem.nwin;
+		    $$->cftable_entry.mem.win[n].card_addr = $3;
+		    $$->cftable_entry.mem.win[n].host_addr = $7;
+		    $$->cftable_entry.mem.win[n].len = $5-$3+1;
+		    $$->cftable_entry.mem.nwin++;
+		}
+	| mem ',' NUMBER '-' NUMBER '@' NUMBER
+		{
+		    int n = $$->cftable_entry.mem.nwin;
+		    $$->cftable_entry.mem.win[n].card_addr = $3;
+		    $$->cftable_entry.mem.win[n].host_addr = $7;
+		    $$->cftable_entry.mem.win[n].len = $5-$3+1;
+		    $$->cftable_entry.mem.nwin++;
+		}
+	| mem BIT8
+		{ $$->cftable_entry.io.flags |= CISTPL_IO_8BIT; }
+	| mem BIT16
+		{ $$->cftable_entry.io.flags |= CISTPL_IO_16BIT; }
+	;	
+
+irq:	  cftab IRQ_NO NUMBER
+		{ $$->cftable_entry.irq.IRQInfo1 = ($3 & 0x0f); }
+	| cftab IRQ_NO MASK NUMBER
+		{
+		    $$->cftable_entry.irq.IRQInfo1 = IRQ_INFO2_VALID;
+		    $$->cftable_entry.irq.IRQInfo2 = $4;
+		}
+	| irq PULSE
+		{ $$->cftable_entry.irq.IRQInfo1 |= IRQ_PULSE_ID; }
+	| irq LEVEL
+		{ $$->cftable_entry.irq.IRQInfo1 |= IRQ_LEVEL_ID; }
+	| irq SHARED
+		{ $$->cftable_entry.irq.IRQInfo1 |= IRQ_SHARE_ID; }
+	;
+
+cftab:	  CFTABLE NUMBER
+		{
+		    $$ = calloc(1, sizeof(cisparse_t));
+		    $$->cftable_entry.index = $2;
+		}
+	| cftab DEFAULT
+		{ $$->cftable_entry.flags |= CISTPL_CFTABLE_DEFAULT; }
+	| cftab BVD
+		{ $$->cftable_entry.flags |= CISTPL_CFTABLE_BVDS; }
+	| cftab WP
+		{ $$->cftable_entry.flags |= CISTPL_CFTABLE_WP; }
+	| cftab RDYBSY
+		{ $$->cftable_entry.flags |= CISTPL_CFTABLE_RDYBSY; }
+	| cftab MWAIT
+		{ $$->cftable_entry.flags |= CISTPL_CFTABLE_MWAIT; }
+	| cftab AUDIO
+		{ $$->cftable_entry.flags |= CISTPL_CFTABLE_AUDIO; }
+	| cftab READONLY
+		{ $$->cftable_entry.flags |= CISTPL_CFTABLE_READONLY; }
+	| cftab PWRDOWN
+		{ $$->cftable_entry.flags |= CISTPL_CFTABLE_PWRDOWN; }
+	| cftab VCC pwrlist
+		{ $$->cftable_entry.vcc = $3; }
+	| cftab VPP1 pwrlist
+		{ $$->cftable_entry.vpp1 = $3; }
+	| cftab VPP2 pwrlist
+		{ $$->cftable_entry.vpp2 = $3; }
+	| io
+	| mem
+	| irq
+	| timing
+	;
+
+checksum: CHECKSUM NUMBER '-' NUMBER '=' NUMBER
+	{ $$ = NULL; }
+
+%%
+
+static tuple_info_t *new_tuple(u_char type, cisparse_t *parse)
+{
+    tuple_info_t *t = calloc(1, sizeof(tuple_info_t));
+    t->type = type;
+    t->parse = parse;
+    t->next = NULL;
+}
+
+void yyerror(char *msg, ...)
+{
+    va_list ap;
+    char str[256];
+
+    va_start(ap, msg);
+    sprintf(str, "error at line %d: ", current_lineno);
+    vsprintf(str+strlen(str), msg, ap);
+    fprintf(stderr, "%s\n", str);
+    va_end(ap);
+}
+
+#ifdef DEBUG
+void main(int argc, char *argv[])
+{
+    if (argc > 1)
+	parse_cis(argv[1]);
+}
+#endif
Index: oldkernel/linux/pcmcia-cs-3.1.15/doc/PCMCIA-HOWTO
diff -u /dev/null linux/pcmcia-cs-3.1.15/doc/PCMCIA-HOWTO:1.1
--- /dev/null	Mon Jul 31 21:15:10 2000
+++ linux/pcmcia-cs-3.1.15/doc/PCMCIA-HOWTO	Fri Jul  7 16:34:58 2000
@@ -0,0 +1,3049 @@
+  Linux PCMCIA HOWTO
+  David Hinds, dhinds@pcmcia.sourceforge.org.
+  v2.60, 14 May 2000
+
+  This document describes how to install and use PCMCIA Card Services
+  for Linux, and answers some frequently asked questions.  The latest
+  version of this document can always be found at <ftp://source-
+  forge.org/pcmcia/doc>.  An HTML version is at  <http://pcmcia.source-
+  forge.org>.
+  ______________________________________________________________________
+
+  Table of Contents
+
+  1. General information and hardware requirements
+
+     1.1 Introduction
+     1.2 Copyright notice and disclaimer
+     1.3 What is the latest version, and where can I get it?
+     1.4 What systems are supported?
+     1.5 What cards are supported?
+     1.6 When will my favorite (unsupported) card become supported?
+     1.7 Mailing lists and other information sources
+     1.8 Why don't you distribute binaries?
+     1.9 Why is the package so darned big?
+
+  2. Compilation and installation
+
+     2.1 Prerequisites and kernel setup
+     2.2 Installation
+     2.3 Startup options
+     2.4 System resource settings
+     2.5 Notes about specific Linux distributions
+        2.5.1 Debian
+        2.5.2 Red Hat, Caldera, Mandrake
+        2.5.3 Slackware
+        2.5.4 SuSE
+
+  3. Resolving installation and configuration problems
+
+     3.1 Base PCMCIA kernel modules do not load
+     3.2 Some client driver modules do not load
+     3.3 Interrupt scan failures
+     3.4 IO port scan failures
+     3.5 Memory probe failures
+     3.6 Failure to detect card insertions and removals
+     3.7 Interrupt delivery problems
+     3.8 System resource starvation
+     3.9 Resource conflict only with two cards inserted
+     3.10 Device configuration does not complete
+
+  4. Usage and features
+
+     4.1 Tools for configuring and monitoring PCMCIA devices
+        4.1.1 The cardmgr configuration daemon
+        4.1.2 The socket status file, stab
+        4.1.3 The cardctl and cardinfo utilities
+        4.1.4 Inserting and ejecting cards
+        4.1.5 Card Services and Advanced Power Management
+        4.1.6 Shutting down the PCMCIA system
+     4.2 Overview of the PCMCIA configuration scripts
+     4.3 PCMCIA network adapters
+        4.3.1 Network device parameters
+        4.3.2 Comments about specific cards
+        4.3.3 Diagnosing problems with network adapters
+     4.4 PCMCIA serial and modem devices
+        4.4.1 Serial device parameters
+        4.4.2 Comments about specific cards
+        4.4.3 Diagnosing problems with serial devices
+     4.5 PCMCIA parallel port devices
+        4.5.1 Parallel device parameters
+        4.5.2 Diagnosing problems with parallel port devices
+     4.6 PCMCIA SCSI adapters
+        4.6.1 SCSI device parameters
+        4.6.2 Comments about specific cards
+        4.6.3 Diagnosing problems with SCSI adapters
+     4.7 PCMCIA memory cards
+        4.7.1 Memory device parameters
+        4.7.2 Using linear flash memory cards
+     4.8 PCMCIA ATA/IDE card drives
+        4.8.1 ATA/IDE fixed-disk device parameters
+        4.8.2 Diagnosing problems with ATA/IDE adapters
+     4.9 Multifunction cards
+
+  5. Advanced topics
+
+     5.1 Resource allocation for PCMCIA devices
+     5.2 How can I have separate device setups for home and work?
+     5.3 Booting from a PCMCIA device
+        5.3.1 The pcinitrd helper script
+        5.3.2 Creating an initrd boot floppy
+        5.3.3 Installing an initrd image on a non-Linux drive
+
+  6. Dealing with unsupported cards
+
+     6.1 Configuring unrecognized cards
+     6.2 Adding support for an NE2000-compatible ethernet card
+     6.3 PCMCIA floppy interface cards
+
+  7. Debugging tips and programming information
+
+     7.1 Submitting useful bug reports
+     7.2 Interpreting kernel trap reports
+     7.3 Low level PCMCIA debugging aids
+     7.4 /proc/bus/pccard
+     7.5 Writing Card Services drivers for new cards
+     7.6 Guidelines for PCMCIA client driver authors
+     7.7 Guidelines for Linux distribution maintainers
+
+  ______________________________________________________________________
+
+  11..  GGeenneerraall iinnffoorrmmaattiioonn aanndd hhaarrddwwaarree rreeqquuiirreemmeennttss
+
+  11..11..  IInnttrroodduuccttiioonn
+
+  Card Services for Linux is a complete PCMCIA or ``PC Card'' support
+  package.  It includes a set of loadable kernel modules that implement
+  a version of the Card Services applications program interface, a set
+  of client drivers for specific cards, and a card manager daemon that
+  can respond to card insertion and removal events, loading and
+  unloading drivers on demand.  It supports ``hot swapping'' of most
+  card types, so cards can be safely inserted and ejected at any time.
+
+  This software is continually under development.  It probably contains
+  bugs, and should be used with caution.  I'll do my best to fix
+  problems that are reported to me, but if you don't tell me, I may
+  never know.  If you use this code, I hope you will send me your
+  experiences, good or bad!
+
+  If you have any suggestions for how this document could be improved,
+  please let me know (dhinds@pcmcia.sourceforge.org).
+
+  11..22..  CCooppyyrriigghhtt nnoottiiccee aanndd ddiissccllaaiimmeerr
+
+  Copyright (c) 1998 David A. Hinds
+
+  This document may be reproduced or distributed in any form without my
+  prior permission.  Modified versions of this document, including
+  translations into other languages, may be freely distributed, provided
+  that they are clearly identified as such, and this copyright is
+  included intact.
+
+  This document may be included in commercial distributions without my
+  prior consent.  While it is not required, I would like to be informed
+  of such usage.  If you intend to incorporate this document in a
+  published work, please contact me to make sure you have the latest
+  available version.
+
+  This document is provided ``AS IS'', with no express or implied
+  warranties.  Use the information in this document at your own risk.
+
+  11..33..  WWhhaatt iiss tthhee llaatteesstt vveerrssiioonn,, aanndd wwhheerree ccaann II ggeett iitt??
+
+  The current major release of Card Services is version 3.1, and minor
+  updates or bug fixes are numbered 3.1.1, 3.1.2, and so on.
+
+  Source code for the latest version is available from sourceforge.org
+  in the /pcmcia directory, as pcmcia-cs-3.1.?.tar.gz.  There will
+  usually be several versions here.  I generally only keep the latest
+  minor release for a given major release.  New major releases may
+  contain relatively untested code, so I also keep the latest version of
+  the previous major release as a relatively stable fallback; the
+  current fallback is 3.0.14.  It is up to you to decide which version
+  is more appropriate, but the CHANGES file will summarize the most
+  important differences.
+
+  sourceforge.org is mirrored at sunsite.unc.edu (and all sunsite mirror
+  sites) in /pub/Linux/kernel/pcmcia.
+
+  If you do not feel up to compiling the drivers from scratch, pre-
+  compiled drivers are included with current releases of most of the
+  major Linux distributions, including Slackware, Debian, Red Hat,
+  Caldera, SuSE, and Yggdrasil, among others.
+
+  11..44..  WWhhaatt ssyysstteemmss aarree ssuuppppoorrtteedd??
+
+  This package should run on almost Intel-based Linux-capable laptop.
+  It also runs on Alpha-based platforms (i.e., the DEC Multia).  Work is
+  being done to make the package fully dual-endian, so that it will also
+  support PowerPC-based platforms (i.e., Apple Powerbooks).  Most common
+  socket controllers are supported.  Card docks for desktop systems
+  should work as long as they use a supported controller, and are
+  plugged directly into the ISA or PCI bus, as opposed to SCSI-to-PCMCIA
+  or IDE-to-PCMCIA adapters.  The following controllers are recognized
+  by the supplied socket drivers:
+
+  +o  Cirrus Logic PD6710, PD6720, PD6722, PD6729, PD6730, PD6732, PD6832
+
+  +o  Intel i82365sl B, C, and DF steps, 82092AA
+
+  +o  O2Micro OZ6729, OZ6730, OZ6812, OZ6832, OZ6833, OZ6836, OZ6860
+
+  +o  Omega Micro 82C365G, 82C092G
+
+  +o  Ricoh RF5C296, RF5C396, RL5C465, RL5C466, RL5C475, RL5C476, RL5C478
+
+  +o  SMC 34C90
+
+  +o  Texas Instruments PCI1031, PCI1130, PCI1131, PCI1210, PCI1211,
+     PCI1220, PCI1221, PCI1225, PCI1250A, PCI1251A, PCI1251B, PCI1420,
+     PCI1450
+
+  +o  Toshiba ToPIC95, ToPIC97, ToPIC100 (experimental, incomplete)
+
+  +o  Vadem VG465, VG468, VG469
+
+  +o  VLSI Technologies 82C146, VCF94365
+
+  +o  VIA VT83C469
+
+  +o  Databook DB86082, DB86082A, DB86084, DB86084A, DB86072, DB86082B
+
+  Other controllers that are register compatible with the Intel i82365sl
+  will generally work, as well.
+
+  Support for 32-bit CardBus cards is still somewhat experimental.
+  Drivers prior to version 3.0 only support 16-bit cards in CardBus
+  sockets.  Due to the rapid pace of technological change for laptop
+  hardware, new controllers appear frequently, and there may be delays
+  between when a new model appears on the market, and when driver
+  support becomes available.
+
+  Toshiba has made available some documentation for their ToPIC95 and
+  ToPIC97 chipsets, however the information they have provided has not
+  really been adequate.  Despite conflicting reports to the contrary,
+  Toshiba has not made any effective effort to remedy this situation.
+  There are serious bugs in Linux support for the ToPIC chipsets, that
+  cannot be resolved until better documentation or help from Toshiba
+  becomes available.  I do not recommend use of Toshiba laptops at this
+  time.  For use of 16-bit cards, I recommend setting the bridge mode to
+  ``PCIC'' in the BIOS setup; for CardBus cards, you are on your own.
+
+  The Motorola 6AHC05GA controller used in some Hyundai laptops is not
+  supported.  The custom host controller in the HP Omnibook 600 is also
+  unsupported.
+
+  11..55..  WWhhaatt ccaarrddss aarree ssuuppppoorrtteedd??
+
+  The current release includes drivers for a variety of ethernet cards,
+  a driver for modem and serial port cards, several SCSI adapter
+  drivers, a driver for ATA/IDE drive cards, and memory card drivers
+  that should support most SRAM cards and some flash cards.  The
+  SUPPORTED.CARDS file included with each release of Card Services lists
+  all cards that are known to work in at least one actual system.
+
+  The likelihood that a card not on the supported list will work depends
+  on the type of card.  Essentially all modems should work with the
+  supplied driver.  Some network cards may work if they are OEM versions
+  of supported cards.  Other types of IO cards (frame buffers, sound
+  cards, etc) will not work until someone writes the appropriate
+  drivers.
+
+  11..66..  WWhheenn wwiillll mmyy ffaavvoorriittee ((uunnssuuppppoorrtteedd)) ccaarrdd bbeeccoommee ssuuppppoorrtteedd??
+
+  Unfortunately, they usually don't pay me to write device drivers, so
+  if you would like to have a driver for your favorite card, you are
+  probably going to have to do at least some of the work.  Ideally, I'd
+  like to work towards a model like the Linux kernel, where I would be
+  responsible mainly for the ``core'' driver code and other authors
+  would contribute and maintain client drivers for specific cards.  The
+  SUPPORTED.CARDS file mentions some cards for which driver work is
+  currently in progress.  I will try to help where I can, but be warned
+  that debugging kernel device drivers by email is not particularly
+  effective.
+
+  Manufacturers interested in helping provide Linux support for their
+  products can contact me about consulting arrangements.
+
+  11..77..  MMaaiilliinngg lliissttss aanndd ootthheerr iinnffoorrmmaattiioonn ssoouurrcceess
+
+  I used to maintain a database and mailing list of Linux PCMCIA users.
+  More recently, I've turned my web page for Linux PCMCIA information
+  into a ``HyperNews'' site, with a set of message lists for Linux
+  PCMCIA issues.  There are lists for installation and configuration
+  issues, for different types of cards, and for programming and
+  debugging issues.  The Linux PCMCIA information page is at
+  <http://pcmcia.sourceforge.org>.  Users can request email notification
+  of new responses to particular questions, or notification for all new
+  messages in a given category.  I hope that this will become a useful
+  repository of information, for questions that go beyond the scope of
+  the HOWTO.
+
+  There is a Linux mailing list devoted to laptop issues, the ``linux-
+  laptop'' list.  For more information, send a message containing the
+  word ``help'' to majordomo@vger.rutgers.edu.  To subscribe, send a
+  message containing ``subscribe linux-laptop'' to the same address.
+  This mailing list might be a good forum for discussion of Linux PCMCIA
+  issues.
+
+  The Linux Laptop Home Page at
+  <http://www.cs.utexas.edu/users/kharker/linux-laptop> has links to
+  many sites that have information about configuring specific types of
+  laptops for Linux.  There is also a searchable database of system
+  configuration information.
+
+  11..88..  WWhhyy ddoonn''tt yyoouu ddiissttrriibbuuttee bbiinnaarriieess??
+
+  For me, distributing binaries would be a significant hassle.  It is
+  complicated because some features can only be selected at compile
+  time, and because the modules are somewhat dependent on having the
+  ``right'' kernel configuration.  So, I would probably need to
+  distribute precompiled modules along with matching kernels.  Beyond
+  this, the greatest need for precompiled modules is when installing
+  Linux on a clean system.  This typically requires setting up drivers
+  so they can be used in the installation process for a particular Linux
+  distribution.  Each Linux distribution has its own ideosyncracies, and
+  it is not feasible for me to provide boot and root disks for even just
+  the common combinations of drivers and distributions.
+
+  PCMCIA is now a part of many of the major Linux distributions,
+  including Red Hat, Caldera, Slackware, Yggdrasil, Craftworks, and
+  Nascent Technology.
+
+  11..99..  WWhhyy iiss tthhee ppaacckkaaggee ssoo ddaarrnneedd bbiigg??
+
+  Well, first of all, it isn't actually that large.  All the driver
+  modules together take up about 500K of disk space.  The utility
+  programs add up to about 70K, and the scripts in /etc/pcmcia are about
+  50K.  The core driver modules take up about 55K of system memory.  The
+  cardmgr daemon will generally be swapped out except when cards are
+  inserted or removed.  The total package size is comparable to
+  DOS/Windows Card Services implementations.
+
+  Compared to DOS ``point enablers'', this may still seem like a lot of
+  overhead, especially for people that don't plan on using many of the
+  features of PCMCIA, such as power management or hot swapping.  Point
+  enablers can be tiny because they generally support only one or a
+  small set of cards, and also generally support a restricted set of
+  host controllers.  If someone were to write a genuinely ``generic''
+  modem enabler, it would end up incorporating much of the functionality
+  of Card Services, to handle cards from different vendors and the full
+  range of host controller variants.
+  22..  CCoommppiillaattiioonn aanndd iinnssttaallllaattiioonn
+
+  22..11..  PPrreerreeqquuiissiitteess aanndd kkeerrnneell sseettuupp
+
+  Before starting, you should think about whether you really need to
+  compile the PCMCIA package yourself.  All common Linux distributions
+  come with pre-compiled driver packages.  Generally, you only need to
+  install the drivers from scratch if you need a new feature of the
+  current drivers, or if you've updated and/or reconfigured your kernel
+  in a way that is incompatible with the drivers included with your
+  Linux distribution.  While compiling the package is not technically
+  difficult, it does require some general Linux familiarity.
+
+  The following things should be installed on your system before you
+  begin:
+
+  +o  A 2.0.*, 2.2.*, or 2.3.* series kernel source tree.
+
+  +o  An appropriate set of module utilities.
+
+  +o  (Optional) the ``XForms'' X11 user interface toolkit.
+
+  You need to have a complete linux source tree for your kernel, not
+  just an up-to-date kernel image.  The driver modules contain some
+  references to kernel source files.  While you may want to build a new
+  kernel to remove unnecessary drivers, installing PCMCIA does not
+  require you to do so.
+
+  Current ``stable'' kernel sources and patches are available from
+  <ftp://sunsite.unc.edu/pub/Linux/kernel/v2.2>, or from
+  <ftp://tsx-11.mit.edu/pub/linux/sources/system/v2.2>.  Development
+  kernels can be found in the corresponding v2.3 subdirectories.
+  Current module utilities can be found in the same locations.
+
+  In the Linux kernel source tree, the Documentation/Changes file
+  describes the versions of all sorts of other system components that
+  are required for that kernel release.  You may want to check through
+  this and verify that your system is up to date, especially if you have
+  updated your kernel.  If you are using a development kernel, be sure
+  that you are using the right combination of shared libraries and
+  module tools.
+
+  When configuring your kernel, if you plan on using a PCMCIA ethernet
+  card, you should turn on networking support but turn off the normal
+  Linux network card drivers, including the ``pocket and portable
+  adapters''.  The PCMCIA network card drivers are all implemented as
+  loadable modules.  Any drivers compiled into your kernel will only
+  waste space.
+
+  If you want to use SLIP, PPP, or PLIP, you do need to either configure
+  your kernel with these enabled, or use the loadable module versions of
+  these drivers.  There is an unfortunate deficiency in the kernel
+  config process in 1.2.X kernels, in that it is not possible to set
+  configuration options (like SLIP compression) for a loadable module,
+  so it is probably better to just link SLIP into the kernel if you need
+  it.
+
+  In order to use a PCMCIA token ring adapter, your kernel should be
+  configured with ``Token Ring driver support'' (CONFIG_TR) enabled,
+  though you should leave CONFIG_IBMTR off.
+
+  If you want to use a PCMCIA IDE adapter, your kernel should be
+  configured with CONFIG_BLK_DEV_IDE_PCMCIA enabled, for 2.0.*  through
+  2.1.7 kernels.  Older kernels do not support removeable IDE devices;
+  newer kernels do not require a special configuration setting.
+
+  If you will be using a PCMCIA SCSI adapter, then enable CONFIG_SCSI
+  when configuring your kernel.  Also, enable any top level drivers
+  (SCSI disk, tape, cdrom, generic) that you expect to use.  All low-
+  level drivers for particular host adapters should be disabled, as they
+  will just take up space.
+
+  If you want to modularize a driver that is needed for a PCMCIA device,
+  you must modify /etc/pcmcia/config to specify what modules need to be
+  loaded for what card types.  For example, if the serial driver is
+  modularized, then the serial device definition should be:
+
+       device "serial_cs"
+         class "serial" module "misc/serial", "serial_cs"
+
+  This package includes an X-based card status utility called cardinfo.
+  This utility is based on a freely distributed user interface toolkit
+  called the XForms Library.  This library is available as a separate
+  package with most Linux distributions.  If you would like to build
+  cardinfo, you should install XForms and all the normal X header files
+  and libraries before configuring the PCMCIA package.
+
+  22..22..  IInnssttaallllaattiioonn
+
+  Here is a synopsis of the installation process:
+
+  +o  Unpack pcmcia-cs-3.1.?.tar.gz in /usr/src.
+
+  +o  Run ``make config'' in the new pcmcia-cs-3.1.? directory.
+
+  +o  Run ``make all'', then ``make install''.
+
+  +o  Customize the startup script and the option files in /etc/pcmcia
+     for your site, if needed.
+
+  If you plan to install any contributed client drivers not included in
+  the core PCMCIA distribution, unpack each of them in the top-level
+  directory of the PCMCIA source tree.  Then follow the normal build
+  instructions.  The extra drivers will be compiled and installed
+  automatically.
+
+  Running ``make config'' prompts for a few configuration options, and
+  checks out your system to verify that it satisfies all prerequisites
+  for installing PCMCIA support.  In most cases, you'll be able to just
+  accept all the default configuration options.  Be sure to carefully
+  check the output of this command in case there are problems.  The
+  following options are available:
+
+     AAlltteerrnnaattee ttaarrggeett iinnssttaallll ddiirreeccttoorryy??
+        If you are compiling the package for installation on another
+        machine, specify an alternate target directory when prompted.
+        This should be an absolute path.  All files will be installed
+        relative to this directory.  You will then be able to tar this
+        directory tree and copy to your target machine, and unpack
+        relative to its root directory to install everything in the
+        proper places.
+
+     BBuuiilldd ''ttrruussttiinngg'' vveerrssiioonnss ooff ccaarrdd uuttiilliittiieess??
+        Some of the support utilities (cardctl and cardinfo) can be
+        compiled either in ``safe'' or ``trusting'' forms.  The ``safe''
+        forms prevent non-root users from modifying card configurations.
+        The ``trusting'' forms permit ordinary users to issue commands
+        to suspend and resume cards, reset cards, and change the current
+        configuration scheme.  The default is to build the safe forms.
+
+     IInncclluuddee 3322--bbiitt ((CCaarrddBBuuss)) ccaarrdd ssuuppppoorrtt??
+        This option must be selected if you wish to use 32-bit CardBus
+        cards.  It is not required for CardBus bridge support, if you
+        only plan to use 16-bit PC Cards.
+
+     IInncclluuddee PPnnPP BBIIOOSS rreessoouurrccee cchheecckkiinngg??
+        This builds additional code into the PCMCIA core module to
+        communicate with a system's PnP BIOS to obtain resource
+        information for built-in ``motherboard'' devices (serial and
+        parallel ports, sound, etc), to help avoid resource conflicts.
+        If enabled, some extra resource files will be created under
+        /proc/bus/pccard, and the lspnp and setpnp tools can be used to
+        view and manipulate PnP BIOS devices.  However, this setting
+        causes problems on some laptops and is not turned on by default.
+
+     HHooww ttoo sseett kkeerrnneell--ssppeecciiffiicc ooppttiioonnss??
+        There are a few kernel configuration options that affect the
+        PCMCIA tools.  The configuration script can deduce these from
+        the running kernel (the default and most common case).
+        Alternatively, if you are compiling for installation on another
+        machine, it can read the configuration from a kernel source
+        tree, or each option can be set interactively.
+
+  The Configure script can also be executed non-interactively, for
+  automatic builds or to quickly reconfigure after a kernel update.
+  Some additional less-frequently-used options can be only be set from
+  the command line.  Running ``Configure --help'' lists all available
+  options.
+
+  Running ``make all'' followed by ``make install'' will build and then
+  install the kernel modules and utility programs.  Kernel modules are
+  installed under /lib/modules/<version>/pcmcia.  The cardmgr and
+  cardctl programs are installed in /sbin.  If cardinfo is built, it is
+  installed in /usr/bin/X11.
+
+  Configuration files will be installed in the /etc/pcmcia directory.
+  If you are installing over an older version, your old config scripts
+  will be backed up before being replaced.  The saved scripts will be
+  given an *.O extension.
+
+  If you don't know what kind of host controller your system uses, you
+  can use the probe utility in the cardmgr/ subdirectory to determine
+  this.  There are two major types: the Databook TCIC-2 type and the
+  Intel i82365SL-compatible type.
+
+  In a few cases, the probe command will be unable to determine your
+  controller type automatically.  If you have a Halikan NBD 486 system,
+  it has a TCIC-2 controller at an unusual location: you'll need to edit
+  rc.pcmcia to load the tcic module, and also set the PCIC_OPTS
+  parameter to ``tcic_base=0x02c0''.
+
+  On some systems using Cirrus controllers, including the NEC Versa M,
+  the BIOS puts the controller in a special suspended state at system
+  startup time.  On these systems, the probe command will fail to find
+  any known host controller.  If this happens, edit rc.pcmcia and set
+  PCIC to i82365, and PCIC_OPTS to ``wakeup=1''.
+
+  22..33..  SSttaarrttuupp ooppttiioonnss
+
+  The PCMCIA startup script recognizes several groups of startup
+  options, set via environment variables.  Multiple options should be
+  separated by spaces and enclosed in quotes.  Placement of startup
+  options depends on the Linux distribution used.  They may be placed
+  directly in the startup script, or they may be kept in a separate
+  option file.  See the ``Notes about specific Linux distributions'' for
+  specifics.  The following variables can be set:
+
+     PCMCIA
+        This variable specifies whether PCMCIA support should be started
+        up, or not.  If it is set to anything other than ``yes'', then
+        the startup script will be disabled.
+
+     PCIC
+        This identifies the PC Card Interface Controller driver module.
+        There are two options: ``tcic'' or ``i82365''.  Virtually all
+        current controllers are in the ``i82365'' group.  This is the
+        only mandatory option setting.
+
+     PCIC_OPTS
+        This specifies options for the PCIC module.  Some host
+        controllers have optional features that may or may not be
+        implemented in a particular system.  In some cases, it is
+        impossible for the socket driver to detect if these features are
+        implemented.  See the corresponding man page for a complete
+        description of the available options.
+
+     CORE_OPTS
+        This specifies options for the pcmcia_core module, which
+        implements the core PC Card driver services.  See ``man
+        pcmcia_core'' for more information.
+
+     CARDMGR_OPTS
+        This specifies options to be passed to the cardmgr daemon.  See
+        ``man cardmgr'' for more information.
+
+     SCHEME
+        If set, then the PC Card configuration scheme will be
+        initialized to this at driver startup time.  See the ``Overview
+        of the PCMCIA configuration scripts'' for a discussion of
+        schemes.
+
+  The low level socket drivers, tcic and i82365, have various bus timing
+  parameters that may need to be adjusted for certain systems with
+  unusual bus clocking.  Symptoms of timing problems can include card
+  recognition problems, lock-ups under heavy loads, high error rates, or
+  poor device performance.  Only certain host bridges have adjustable
+  timing parameters: check the corresponding man page to see what
+  options are available for your controller.  Here is a brief summary:
+
+  +o  Cirrus controllers have numerous configurable timing parameters.
+     The most important seems to be the cmd_time flag, which determines
+     the length of PCMCIA bus cycles.  Fast 486 systems (i.e., DX4-100)
+     seem to often benefit from increasing this from 6 (the default) to
+     12 or 16.
+
+  +o  The Cirrus PD6729 PCI controller has the fast_pci flag, which
+     should be set if the PCI bus speed is greater than 25 MHz.
+  +o  For Vadem VG-468 controllers, the async_clock flag changes the
+     relative clocking of PCMCIA bus and host bus cycles.  Setting this
+     flag adds extra wait states to some operations.  However, I have
+     yet to hear of a laptop that needs this.
+
+  +o  The pcmcia_core module has the cis_speed parameter for changing the
+     memory speed used for accessing a card's Card Information Structure
+     (CIS).  On some systems with fast bus clocks, increasing this
+     parameter (i.e., slowing down card accesses) may be beneficial for
+     card recognition problems.
+
+  +o  This is not a timing issue, but if you have more than one ISA-to-
+     PCMCIA controller in your system or extra sockets in a laptop
+     docking station, the i82365 module should be loaded with the
+     extra_sockets parameter set to 1.  This should not be necessary for
+     detection of PCI-to-PCMCIA or PCI-to-CardBus bridges.
+
+  +o  With SCM Microsystems SBP series PCI card readers (which are also
+     being distributed with Lucent WaveLan cards), it is necessary to
+     specify irq_mode=0 for the i82365 module, to force use of PCI
+     interrupts.
+
+  Here are some timing settings for specific systems:
+
+  +o  On the ARM Pentium-90 or Midwest Micro Soundbook Plus, use
+     ``freq_bypass=1 cmd_time=8''.
+
+  +o  On a Midwest Micro Soundbook Elite, use ``cmd_time=12''.
+
+  +o  On a Gateway Liberty, try ``cmd_time=16''.
+
+  +o  On a Samsung SENS 810, use ``fast_pci=1''.
+
+  22..44..  SSyysstteemm rreessoouurrccee sseettttiinnggss
+
+  Card Services should automatically avoid allocating IO ports and
+  interrupts already in use by other standard devices.  It will also
+  attempt to detect conflicts with unknown devices, but this is not
+  completely reliable.  In some cases, you may need to explicitly
+  exclude resources for a device in /etc/pcmcia/config.opts.
+
+  Here are some resource settings for specific laptop types.  View this
+  list with suspicion: it may give useful hints for solving problems,
+  but it is inevitably out of date and certainly contains mistakes.
+  Corrections and additions are welcome.
+
+  +o  On the AMS SoundPro, exclude irq 10.
+
+  +o  On some AMS TravelPro 5300 models, use memory 0xc8000-0xcffff.
+
+  +o  On the BMX 486DX2-66, exclude irq 5, irq 9.
+
+  +o  On the Chicony NB5, use memory 0xda000-0xdffff.
+
+  +o  On the Compaq Presario 1020, exclude port 0x2f8-0x2ff, irq 3, irq
+     5.
+
+  +o  On the Dell Inspiron 7000, exclude irq 3, irq 5.
+
+  +o  On the Fujitsu C series, exclude port 0x200-0x27f.
+
+  +o  On the HP Omnibook 4000C, exclude port 0x300-0x30f.
+
+  +o  On the IBM ThinkPad 380, and maybe the 385 and 600 series, exclude
+     port 0x230-0x233, and irq 5.
+
+  +o  On IBM ThinkPad 600 and 770 models with internal modems, exclude
+     port 0x2f8-0x2ff.
+
+  +o  On the IBM ThinkPad 600E and 770Z, change the high memory window to
+     0x60000000-0x60ffffff.
+
+  +o  On the Micron Millenia Transport, exclude irq 5, irq 9.
+
+  +o  On the NEC Versa M, exclude irq 9, port 0x2e0-2ff.
+
+  +o  On the NEC Versa P/75, exclude irq 5, irq 9.
+
+  +o  On the NEC Versa S, exclude irq 9, irq 12.
+
+  +o  On the NEC Versa 6000 series, exclude port 0x2f8-0x33f, irq 9, irq
+     10.
+
+  +o  On the NEC Versa SX, exclude port 0x300-0x31f.
+
+  +o  On the ProStar 9200, Altima Virage, and Acquiline Hurricane
+     DX4-100, exclude irq 5, port 0x330-0x35f.  Maybe use memory
+     0xd8000-0xdffff.
+
+  +o  On the Siemens Nixdorf SIMATIC PG 720C, use memory 0xc0000-0xcffff,
+     port 0x300-0x3bf.
+
+  +o  On the TI TravelMate 5000, use memory 0xd4000-0xdffff.
+
+  +o  On the Toshiba Satellite 4030CDS, exclude irq 9.
+
+  +o  On the Toshiba T4900 CT, exclude irq 5, port 0x2e0-0x2e8, port
+     0x330-0x338.
+
+  +o  On the Toshiba Tecra 8000, exclude irq 3, irq 5, irq 9.
+
+  +o  On the Twinhead 5100, HP 4000, Sharp PC-8700 and PC-8900, exclude
+     irq 9 (sound), irq 12.
+
+  +o  On an MPC 800 Series, exclude irq 5, port 0x300-0x30f for the CD-
+     ROM.
+
+  22..55..  NNootteess aabboouutt ssppeecciiffiicc LLiinnuuxx ddiissttrriibbuuttiioonnss
+
+  This section is incomplete.  Corrections and additions are welcome.
+
+  22..55..11..  DDeebbiiaann
+
+  Debian uses a System V boot script arrangement.  The PCMCIA startup
+  script is installed as /etc/init.d/pcmcia, and startup options are
+  specified in /etc/pcmcia.conf.  Debian's syslog configuration will
+  place kernel messages in /var/log/messages and cardmgr messages in
+  /var/log/daemon.log.
+
+  Debian distributes the PCMCIA system in two packages: the ``pcmcia-
+  cs'' package contains cardmgr and other tools, man pages, and
+  configuration scripts; and the ``pcmcia-modules'' package contains the
+  kernel driver modules.
+
+  22..55..22..  RReedd HHaatt,, CCaallddeerraa,, MMaannddrraakkee
+
+  These distributions use a System V boot script organization.  The
+  PCMCIA startup script is installed as /etc/rc.d/init.d/pcmcia, and
+  boot options are kept in /etc/sysconfig/pcmcia.  Beware that
+  installing the Red Hat package may install a default boot option file
+  that has PCMCIA disabled.  To enable PCMCIA, the ``PCMCIA'' variable
+  should be set to ``yes''.  Red Hat's default syslogd configuration
+  will record all interesting messages in /var/log/messages.
+
+  Red Hat's PCMCIA package contains a replacement for the network setup
+  script, /etc/pcmcia/network, which meshes with the Red Hat linuxconf
+  configuration system.  This is convenient for the case where just one
+  network adapter is used, with one set of network parameters, but does
+  not have the full flexibility of the regular PCMCIA network script.
+  Compiling and installing a clean PCMCIA source distribution will
+  overwrite the network script, breaking the link to the Red Hat tools.
+  If you prefer using the Red Hat tools, either use only Red Hat RPM's,
+  or replace /etc/pcmcia/network.opts with the following:
+
+       if [ -f /etc/sysconfig/network-scripts/ifcfg-eth0 ] ; then
+           start_fn () {
+               /sbin/ifup $1
+           }
+           stop_fn () {
+               /sbin/ifdown $1
+           }
+       fi
+
+  If you do use linuxconf (or netconf) to configure your network
+  interface, leave the ``kernel module'', ``I/O port'', and ``irq''
+  parameters blank.  Setting these parameters may interfere with proper
+  operation of the PCMCIA subsystem.
+
+  At boot time, when the Red Hat network subsystem starts up, it may say
+  ``Delaying eth0 initialization'' and ``[FAILED]''.  This is actually
+  not a failure: it means that this network interface will not be
+  initialized until after the PCMCIA network device is configured.
+
+  Red Hat bundles their slightly modified PCMCIA source distribution in
+  their kernel SRPM, rather than as a separate source package.
+
+  22..55..33..  SSllaacckkwwaarree
+
+  Slackware uses a BSD boot script arrangement.  The PCMCIA startup
+  script is installed as /etc/rc.d/rc.pcmcia, and boot options are
+  specified in rc.pcmcia itself.  The PCMCIA startup script is invoked
+  from /etc/rc.d/rc.S.
+
+  22..55..44..  SSuuSSEE
+
+  SuSE uses a System V init script arrangement, with init scripts stored
+  under /sbin/init.d.  The PCMCIA startup script is installed as
+  /sbin/init.d/pcmcia, and startup options are kept in /etc/rc.config.
+  The SuSE startup script is somewhat limited and does not allow PCMCIA
+  startup variables to be overridden from the lilo boot prompt.
+
+  33..  RReessoollvviinngg iinnssttaallllaattiioonn aanndd ccoonnffiigguurraattiioonn pprroobblleemmss
+
+  This section describes some of the most common failure modes for the
+  PCMCIA subsystem.  Try to match your symptoms against the examples.
+  This section only describes general failures that are not specific to
+  a particular client driver or type of card.
+
+  Before trying to diagnose a problem, you have to know where your
+  system log is kept (see ``Notes about specific Linux distributions'').
+  You should also be familiar with basic diagnostic tools like dmesg and
+  lsmod.  Also, be aware that most driver components (including all the
+  kernel modules) have their own individual man pages.
+
+  In 3.1.15 and later releases, the debug-tools subdirectory of the
+  PCMCIA source tree has a few scripts to help diagnose some of the most
+  common configuration problems.  The test_setup script checks your
+  PCMCIA installation for completeness.  The test_network and test_modem
+  scripts will try to diagnose problems with PCMCIA network and modem
+  cards.  These scripts can be particularly helpful if you are
+  unfamiliar with Linux and are not sure how to approach a problem.
+
+  Try to define your problem as narrowly as possible.  If you have
+  several cards, try each card in isolation, and in different
+  combinations.  Try cold Linux boots, versus warm boots from Windows.
+  Compare booting with cards inserted, versus inserting cards after
+  boot.  If you normally use your laptop docked, try it undocked.  And
+  sometimes, two sockets will behave differently.
+
+  It is nearly impossible to debug driver problems encountered when
+  attempting to install Linux via a PCMCIA device.  Even if you can
+  identify the problem based on its symptoms, installation disks are
+  difficult to modify, especially without access to a running Linux
+  system.  Customization of installation disks is completely dependent
+  on the choice of Linux distribution, and is beyond the scope of this
+  document.  In general, the best course of action is to install Linux
+  using some other means, obtain the latest drivers, and then debug the
+  problem if it persists.
+
+  33..11..  BBaassee PPCCMMCCIIAA kkeerrnneell mmoodduulleess ddoo nnoott llooaadd
+
+  Symptoms:
+
+  +o  Kernel version mismatch errors are reported when the PCMCIA startup
+     script runs.
+
+  +o  After startup, lsmod does not show any PCMCIA modules.
+
+  +o  cardmgr reports ``no pcmcia driver in /proc/devices'' in the system
+     log.
+
+  Kernel modules contain version information that is checked against the
+  current kernel when a module is loaded.  The type of checking depends
+  on the setting of the CONFIG_MODVERSIONS kernel option.  If this is
+  false, then the kernel version number is compiled into each module,
+  and insmod checks this for a match with the running kernel.  If
+  CONFIG_MODVERSIONS is true, then each symbol exported by the kernel is
+  given a sort of checksum.  These codes are all compared against the
+  corresponding codes compiled into a module.  The intent was for this
+  to make modules less version-dependent, because the checksums would
+  only change if a kernel interface changed, and would generally stay
+  the same across minor kernel updates.  In practice, the checksums have
+  turned out to be even more restrictive, because many kernel interfaces
+  depend on compile-time kernel option settings.  Also, the checksums
+  turned out to be an excessively pessimistic judge of compatibility.
+
+  The practical upshot of this is that kernel modules are closely tied
+  to both the kernel version, and the setting of many kernel
+  configuration options.  Generally, a set of modules compiled for one
+  2.0.31 kernel will not load against some other 2.0.31 kernel unless
+  special care is taken to ensure that the two were built with similar
+  configurations.  This makes distribution of precompiled kernel modules
+  a tricky business.
+
+  You have several options:
+
+  +o  If you obtained precompiled drivers as part of a Linux
+     distribution, verify that you are using an unmodified kernel as
+     supplied with that distribution.  If you intend to use precompiled
+     modules, you generally must stick with the corresponding kernel.
+
+  +o  If you have reconfigured or upgraded your kernel, you will probably
+     need to compile and install the PCMCIA package from scratch.  This
+     is easily done if you already have the kernel source tree
+     installed.  See ``Compilation and installation'' for detailed
+     instructions.
+
+  +o  In some cases, incompatibilities in other system components can
+     prevent correct loading of kernel modules.  If you have upgraded
+     your own kernel, pay attention to the ``minimal requirements'' for
+     module utilities and binutils listed in the Documentation/Changes
+     file in the kernel source code tree.
+
+  33..22..  SSoommee cclliieenntt ddrriivveerr mmoodduulleess ddoo nnoott llooaadd
+
+  Symptoms:
+
+  +o  The base modules (pcmcia_core, ds, i82365) load correctly.
+
+  +o  Inserting a card gives a high beep + low beep pattern.
+
+  +o  cardmgr reports version mismatch errors in the system log.
+
+  Some of the driver modules require kernel services that may or may not
+  be present, depending on kernel configuration.  For instance, the SCSI
+  card drivers require that the kernel be configured with SCSI support,
+  and the network drivers require a networking kernel.  If a kernel
+  lacks a necessary feature, insmod may report undefined symbols and
+  refuse to load a particular module. Note that insmod error messages do
+  not distinguish between version mismatch errors and missing symbol
+  errors.
+
+  Specifically:
+
+  +o  The serial client driver serial_cs requires the kernel serial
+     driver to be enabled with CONFIG_SERIAL.  This driver may be built
+     as a module.
+
+  +o  Support for multiport serial cards or multifunction cards that
+     include serial or modem devices requires CONFIG_SERIAL_SHARE_IRQ to
+     be enabled.
+
+  +o  The SCSI client drivers require that CONFIG_SCSI be enabled, along
+     with the appropriate top level driver options (CONFIG_BLK_DEV_SD,
+     CONFIG_BLK_DEV_SR, etc for 2.1 kernels).  These may be built as
+     modules.
+
+  +o  The network client drivers require that CONFIG_INET is enabled.
+     Kernel networking support cannot be compiled as a module.
+  +o  The token-ring client requires that the kernel be compiled with
+     CONFIG_TR enabled.
+
+  There are two ways to proceed:
+
+  +o  Rebuild your kernel with the necessary features enabled.
+
+  +o  If the features have been compiled as modules, then modify
+     /etc/pcmcia/config to preload these modules.
+
+  The /etc/pcmcia/config file can specify that additional modules need
+  to be loaded for a particular client.  For example, for the serial
+  driver, one would use:
+
+       device "serial_cs"
+         class "serial" module "misc/serial", "serial_cs"
+
+  Module paths are specified relative to the top-level module directory
+  for the current kernel version; if no relative path is given, then the
+  path defaults to the pcmcia subdirectory.
+
+  33..33..  IInntteerrrruupptt ssccaann ffaaiilluurreess
+
+  Symptoms:
+
+  +o  The system locks up when the PCMCIA drivers are loaded, even with
+     no cards present.
+
+  +o  The system log shows a successful host controller probe just before
+     the lock-up, but does not show interrupt probe results.
+
+  After identifying the host controller type, the socket driver probes
+  for free interrupts.  The probe involves programming the controller
+  for each apparently free interrupt, then generating a ``soft''
+  interrupt, to see if the interrupt can be detected correctly.  In some
+  cases, probing a particular interrupt can interfere with another
+  system device.
+
+  The reason for the probe is to identify interrupts which appear to be
+  free (i.e., are not reserved by any other Linux device driver), yet
+  are either not physically wired to the host controller, or are
+  connected to another device that does not have a driver.
+
+  In the system log, a successful probe might look like:
+
+       Intel PCIC probe:
+         TI 1130 CardBus at mem 0x10211000, 2 sockets
+         ...
+         ISA irqs (scanned) = 5,7,9,10 status change on irq 10
+
+  There are two ways to proceed:
+
+  +o  The interrupt probe can be restricted to a list of interrupts using
+     the irq_list parameter for the socket drivers.  For example,
+     ``irq_list=5,9,10'' would limit the scan to three interrupts.  All
+     PCMCIA devices will be restricted to using these interrupts
+     (assuming they pass the probe).  You may need to use trial and
+     error to find out which interrupts can be safely probed.
+
+  +o  The interrupt probe can be disabled entirely by loading the socket
+     driver with the ``do_scan=0'' option.  In this case, a default
+     interrupt list will be used, which avoids interrupts already
+     allocated for other devices.
+
+  In either case, the probe options can be specified using the PCIC_OPTS
+  definition in the PCMCIA startup script, for example:
+
+       PCIC_OPTS="irq_list=5,9,10"
+
+  It should be noted that /proc/interrupts is completely useless when it
+  comes to diagnosing interrupt probe problems.  The probe is sensible
+  enough to never attempt to use an interrupt that is already in use by
+  another Linux driver.  So, the PCMCIA drivers are already using all
+  the information in /proc/interrupts.  Depending on system design, an
+  inactive device can still occupy an interrupt and cause trouble if it
+  is probed for PCMCIA.
+
+  33..44..  IIOO ppoorrtt ssccaann ffaaiilluurreess
+
+  Symptoms:
+
+  +o  The system locks up when cardmgr is first started, even with no
+     cards present.
+
+  +o  The system log shows a successful host controller probe, including
+     interrupt probe results, but does not show IO probe results.
+
+  +o  In some cases, the IO probe will succeed, but report large numbers
+     of random exclusions.
+
+  When cardmgr processes IO port ranges listed in
+  /etc/pcmcia/config.opts, the kernel probes these ranges to detect
+  latent devices that occupy IO space but are not associated with a
+  Linux driver.  The probe is read-only, but in rare cases, reading from
+  a device may interfere with an important system function, resulting in
+  a lock-up.
+
+  Your system user's guide may include a map of system devices, showing
+  their IO and memory ranges.  These can be explicitly excluded in
+  config.opts.
+
+  Alternatively, if the probe is unreliable on your system, it can be
+  disabled by setting CORE_OPTS to ``probe_io=0''.  In this case, you
+  should be very careful to specify only genuinely available ranges of
+  ports in config.opts, instead of using the default settings.
+
+  33..55..  MMeemmoorryy pprroobbee ffaaiilluurreess
+
+  Symptoms:
+
+  +o  The core drivers load correctly when no cards are present, with no
+     errors in the system log.
+
+  +o  The system freezes and/or reboots as soon as any card is inserted,
+     before any beeps are heard.
+
+  Or alternately:
+
+  +o  All card insertions generate a high beep followed by a low beep.
+
+  +o  All cards are identified as ``anonymous memory cards''.
+
+  +o  The system log reports that various memory ranges have been
+     excluded.
+
+  The core modules perform a memory scan at the time of first 16-bit
+  card insertion.  This scan can potentially interfere with other memory
+  mapped devices.  Also, pre-3.0.0 driver packages perform a more
+  aggressive scan than more recent drivers.  The memory window is
+  defined in /etc/pcmcia/config.opts.  The default window is large, so
+  it may help to restrict the scan to a narrower range.  Reasonable
+  ranges to try include 0xd0000-0xdffff, 0xc0000-0xcffff,
+  0xc8000-0xcffff, or 0xd8000-0xdffff.
+
+  If you have DOS or Windows PCMCIA drivers, you may be able to deduce
+  what memory region those drivers use.  Note that DOS memory addresses
+  are often specified in ``segment'' form, which leaves off the final
+  hex digit (so an absolute address of 0xd0000 might be given as
+  0xd000).  Be sure to add the extra digit back when making changes to
+  config.opts.
+
+  In unusual cases, a memory probe failure can indicate a timing
+  register setup problem with the host controller.  See the ``Startup
+  options'' section for information about dealing with common timing
+  problems.
+
+  +o  cs: warning: no high memory space available!
+
+  CardBus bridges can allocate memory windows outside of the 640KB-1MB
+  ``memory hole'' in the ISA bus architecture.  It is generally a good
+  idea to configure CardBus bridges to use high memory windows, because
+  these are unlikely to conflict with other devices.  Also, CardBus
+  cards may require large memory windows, which may be difficult or
+  impossible to fit into low memory.  Card Services will preferentially
+  allocate windows in high memory for CardBus bridges, if both low and
+  high memory windows are defined in config.opts.  The default
+  config.opts now includes a high memory window of
+  0xa0000000-0xa0ffffff.  If you have a CardBus bridge and have upgraded
+  from an older PCMCIA driver release, add this memory window if it is
+  not already defined.
+
+  In some cases, the default high memory window is not usable.  On some
+  IBM Thinkpad models, a window of 0x60000000-0x60ffffff will work in
+  place of the default window.
+
+  33..66..  FFaaiilluurree ttoo ddeetteecctt ccaarrdd iinnsseerrttiioonnss aanndd rreemmoovvaallss
+
+  Symptoms:
+
+  +o  Cards are detected and configured properly if present at boot time.
+
+  +o  The drivers do not respond to insertion and removal events, either
+     by recording events in the system log, or by beeping.
+  In most cases, the socket driver (i82365 or tcic) will automatically
+  probe and select an appropriate interrupt to signal card status
+  changes.  The automatic interrupt probe doesn't work on some Intel-
+  compatible controllers, including Cirrus chips and the chips used in
+  some IBM ThinkPads.  If a device is inactive at probe time, its
+  interrupt may also appear to be available.  In these cases, the socket
+  driver may pick an interrupt that is used by another device.
+
+  With the i82365 and tcic drivers, the irq_list option can be used to
+  limit the interrupts that will be tested.  This list limits the set of
+  interrupts that can be used by PCMCIA cards as well as for monitoring
+  card status changes.  The cs_irq option can also be used to explicitly
+  set the interrupt to be used for monitoring card status changes.
+
+  If you can't find an interrupt number that works, there is also a
+  polled status mode: both i82365 and tcic will accept a
+  poll_interval=100 option, to poll for card status changes once per
+  second.  This option should also be used if your system has a shortage
+  of interrupts available for use by PCMCIA cards.  Especially for
+  systems with more than one host controller, there is little point in
+  dedicating interrupts for monitoring card status changes.
+
+  All these options should be set in the PCIC_OPTS= line in either
+  /etc/rc.d/rc.pcmcia or /etc/sysconfig/pcmcia, depending on your site
+  setup.
+
+  33..77..  IInntteerrrruupptt ddeelliivveerryy pprroobblleemmss
+
+  Symptoms:
+
+  +o  Cards appear to be configured successfully, but don't work.
+
+  +o  Serial and modem cards may respond very sluggishly.
+
+  +o  Network cards may report ``interrupt(s) dropped'', and/or transmit
+     timeouts.
+
+  The most simple interrupt delivery problems are due to conflicts with
+  other system devices.  These can generally be resolved by excluding
+  problem interrupts in /etc/pcmcia/config.opts.  To test, just exclude
+  interrupts one by one until either the problem is fixed or you run out
+  of interrupts.  If no interrupts work, then device conflicts are
+  probably not the problem.
+
+  CardBus bridges usually support two types of interrupts, PCI and ISA.
+  Partly for historical reasons, it has become conventional to use PCI
+  interrupts for signaling card insertion and removal events, and for
+  CardBus card interrupts; and ISA interrupts for 16-bit cards.  Since
+  version 3.1.9, this is the scheme that the Linux PCMCIA system will
+  use by default.  Most CardBus bridges support multiple methods for
+  delivering interrupts to the host CPU.  Methods include ``parallel''
+  interrupts, where each supported irq has a dedicated pin on the
+  bridge; various serial interrupt protocols, where one or two pins are
+  used to communicate with an interrupt controller; and hybrids, where,
+  for instance, PCI interrupts may be signalled using dedicated pins,
+  while ISA interrupts are delivered via a serial controller.
+
+  In general, it is the responsibility of the BIOS to program a bridge
+  for the appropriate interrupt delivery method.  However, there are
+  systems that do this incorrectly, and in some cases, there is no way
+  for software to safely detect the correct delivery method.  The i82365
+  module reports the bridge mode at startup time, and has a parameter,
+  irq_mode, that can be used to reconfigure it.  Not all bridges support
+  this parameter, and the meaning of irq_mode depends on the bridge
+  type.  See the i82365 man page for a description of what values are
+  supported by your bridge.  In some cases, a bridge may function
+  correctly in more than one interrupt mode.
+
+  Most PCMCIA card readers that fit in a PCI bus slot only provide PCI
+  interrupt routing.  The Linux drivers assume that all bridges have ISA
+  interrupt capability, since that is usually correct.  In this case, it
+  will be necessary to use the irq_mode parameter to specify a ``PCI
+  only'' interrupt delivery mode; the value of the parameter depends on
+  the bridge type, so check the i82365 man page.
+
+  33..88..  SSyysstteemm rreessoouurrccee ssttaarrvvaattiioonn
+
+  Symptoms:
+
+  +o  When a card is inserted, it is identified correctly but cannot be
+     configured (high/low beep pattern).
+
+  +o  One of the following messages will appear in the system log:
+
+       RequestIO: Resource in use
+       RequestIRQ: Resource in use
+       RequestWindow: Resource in use
+       GetNextTuple: No more items
+       could not allocate nn IO ports for CardBus socket n
+       could not allocate nnK memory for CardBus socket n
+       could not allocate interrupt for CardBus socket n
+
+  Interrupt starvation often indicates a problem with the interrupt
+  probe (see ``Interrupt scan failures'').  In some cases, the probe
+  will seem to work, but only report one or two available interrupts.
+  Check your system log to see if the scan results look sensible.
+  Disabling the probe and selecting interrupts manually should help.
+
+  If the interrupt probe is not working properly, the socket driver may
+  allocate an interrupt for monitoring card insertions, even when
+  interrupts are too scarce for this to be a good idea.  In that case,
+  you can switch the controller to polled mode by setting PCIC_OPTS to
+  ``poll_interval=100'.  Or, if you have a CardBus controller, try
+  ``pci_csc=1'', which selects a PCI interrupt (if available) for card
+  status changes.
+
+  IO port starvation is fairly uncommon, but sometimes happens with
+  cards that require large, contiguous, aligned regions of IO port
+  space, or that only recognize a few specific IO port positions.  The
+  default IO port ranges in /etc/pcmcia/config.opts are normally
+  sufficient, but may be extended.  In rare cases, starvation may
+  indicate that the IO port probe failed (see ``IO port scan
+  failures'').
+
+  Memory starvation is also uncommon with the default memory window
+  settings in config.opts.  CardBus cards may require larger memory
+  regions than typical 16-bit cards.  Since CardBus memory windows can
+  be mapped anywhere in the host's PCI address space (rather than just
+  in the 640K-1MB ``hole'' in PC systems), it is helpful to specify
+  large memory windows in high memory, such as 0xa0000000-0xa0ffffff.
+
+  33..99..  RReessoouurrccee ccoonnfflliicctt oonnllyy wwiitthh ttwwoo ccaarrddss iinnsseerrtteedd
+
+  Symptoms:
+
+  +o  Two cards each work fine when used separately.
+
+  +o  When both cards are inserted, only one works.
+
+  This usually indicates a resource conflict with a system device that
+  Linux does not know about.  PCMCIA devices are dynamically configured,
+  so, for example, interrupts are allocated as needed, rather than
+  specifically assigned to particular cards or sockets.  Given a list of
+  resources that appear to be available, cards are assigned resources in
+  the order they are configured.  In this case, the card configured last
+  is being assigned a resource that in fact is not free.
+
+  Check the system log to see what resources are used by the non-working
+  card.  Exclude these in /etc/pcmcia/config.opts, and restart the
+  cardmgr daemon to reload the resource database.
+
+  33..1100..  DDeevviiccee ccoonnffiigguurraattiioonn ddooeess nnoott ccoommpplleettee
+
+  Symptoms:
+
+  +o  When a card is inserted, exactly one high beep is heard.
+
+  +o  Subsequent card insertions and removals may be ignored.
+
+  This indicates that the card was identified successfully, however,
+  cardmgr has been unable to complete the configuration process for some
+  reason.  The most likely reason is that a step in the card setup
+  script has blocked.  A good example would be the network script
+  blocking if a network card is inserted with no actual network hookup
+  present.
+
+  To pinpoint the problem, you can manually run a setup script to see
+  where it is blocking.  The scripts are in the /etc/pcmcia directory.
+  They take two parameters: a device name, and an action.  The cardmgr
+  daemon records the configuration commands in the system log.  For
+  example, if the system log shows that the command ``./network start
+  eth0'' was the last command executed by cardmgr, the following command
+  would trace the script:
+
+       sh -x /etc/pcmcia/network start eth0
+
+  44..  UUssaaggee aanndd ffeeaattuurreess
+
+  44..11..  TToooollss ffoorr ccoonnffiigguurriinngg aanndd mmoonniittoorriinngg PPCCMMCCIIAA ddeevviicceess
+
+  If the modules are all loaded correctly, the output of the lsmod
+  command should look like the following, when no cards are inserted:
+
+  Module                  Size  Used by
+  ds                      5640   2
+  i82365                 15452   2
+  pcmcia_core            30012   3  [ds i82365]
+
+  The system log should also include output from the socket driver
+  describing the host controller(s) found and the number of sockets
+  detected.
+
+  44..11..11..  TThhee ccaarrddmmggrr ccoonnffiigguurraattiioonn ddaaeemmoonn
+
+  The cardmgr daemon is responsible for monitoring PCMCIA sockets,
+  loading client drivers when needed, and running user-level scripts in
+  response to card insertions and removals.  It records its actions in
+  the system log, but also uses beeps to signal card status changes.
+  The tones of the beeps indicate success or failure of particular
+  configuration steps.  Two high beeps indicate that a card was
+  identified and configured successfully.  A high beep followed by a low
+  beep indicates that a card was identified, but could not be configured
+  for some reason.  One low beep indicates that a card could not be
+  identified.
+
+  The cardmgr daemon configures cards based on a database of known card
+  types kept in /etc/pcmcia/config.  This file describes the various
+  client drivers, then describes how to identify various cards, and
+  which driver(s) belong with which cards.  The format of this file is
+  described in the pcmcia(5) man page.
+
+  44..11..22..  TThhee ssoocckkeett ssttaattuuss ffiillee,, ssttaabb
+
+  Cardmgr records device information for each socket in
+  /var/state/pcmcia/stab or /var/lib/pcmcia/stab, depending on
+  filesystem layout.  Here is a sample stab listing:
+
+       Socket 0: Adaptec APA-1460 SlimSCSI
+       0       scsi    aha152x_cs      0       sda     8       0
+       0       scsi    aha152x_cs      1       scd0    11      0
+       Socket 1: Serial or Modem Card
+       1       serial  serial_cs       0       ttyS1   5       65
+
+  For the lines describing devices, the first field is the socket, the
+  second is the device class, the third is the driver name, the fourth
+  is used to number multiple devices associated with the same driver,
+  the fifth is the device name, and the final two fields are the major
+  and minor device numbers for this device (if applicable).  See the
+  stab man page for more info.
+
+  44..11..33..  TThhee ccaarrddccttll aanndd ccaarrddiinnffoo uuttiilliittiieess
+
+  The cardctl command can be used to check the status of a socket, or to
+  see how it is configured.  It can also be used to alter the
+  configuration status of a card.  Here is an example of the output of
+  the ``cardctl config'' command:
+       Socket 0:
+         not configured
+       Socket 1:
+         Vcc = 5.0, Vpp1 = 0.0, Vpp2 = 0.0
+         Card type is memory and I/O
+         IRQ 3 is dynamic shared, level mode, enabled
+         Speaker output is enabled
+         Function 0:
+           Config register base = 0x0800
+             Option = 0x63, status = 0x08
+           I/O window 1: 0x0280 to 0x02bf, auto sized
+           I/O window 2: 0x02f8 to 0x02ff, 8 bit
+
+  Or ``cardctl ident'', to get card identification information:
+
+       Socket 0:
+         no product info available
+       Socket 1:
+         product info: "LINKSYS", "PCMLM336", "A", "0040052D6400"
+         manfid: 0x0143, 0xc0ab
+         function: 0 (multifunction)
+
+  The ``cardctl suspend'' and ``cardctl resume'' commands can be used to
+  shut down a card without unloading its associated drivers.  The
+  ``cardctl reset'' command attempts to reset and reconfigure a card.
+  ``cardctl insert'' and ``cardctl eject'' mimic the actions performed
+  when a card is physically inserted or ejected, including loading or
+  unloading drivers, and configuring or shutting down devices.
+
+  If you are running X, the cardinfo utility produces a graphical
+  display showing the current status of all PCMCIA sockets, similar in
+  content to ``cardctl config''.  It also provides a graphical interface
+  to most other cardctl functions.
+
+  44..11..44..  IInnsseerrttiinngg aanndd eejjeeccttiinngg ccaarrddss
+
+  In theory, you can insert and remove PCMCIA cards at any time.
+  However, it is a good idea not to eject a card that is currently being
+  used by an application program.  Kernels older than 1.1.77 would often
+  lock up when serial/modem cards were ejected, but this should be fixed
+  now.
+
+  Some card types cannot be safely hot ejected.  Specifically, ATA/IDE
+  and SCSI interface cards are not hot-swap-safe.  This is unlikely to
+  be fixed, because a complete solution would require significant
+  changes to the Linux block device model.  Also, it is generally not
+  safe to hot eject CardBus cards of any type.  This is likely to
+  improve gradually as hot swap bugs in the CardBus drivers are found
+  and fixed.  For these card types (IDE, SCSI, CardBus), it is
+  recommended that you always use ``cardctl eject'' before ejecting.
+
+  44..11..55..  CCaarrdd SSeerrvviicceess aanndd AAddvvaanncceedd PPoowweerr MMaannaaggeemmeenntt
+
+  Card Services can be compiled with support for APM (Advanced Power
+  Management) if you've configured your kernel with APM support.  The
+  APM kernel driver is maintained by Stephen Rothwell
+  (Stephen.Rothwell@canb.auug.org.au).  The apmd daemon is maintained by
+  Avery Pennarun (apenwarr@worldvisions.ca), with more information
+  available at <http://www.worldvisions.ca/~apenwarr/apmd/>.  The PCMCIA
+  modules will automatically be configured for APM if a compatible
+  version is detected on your system.
+
+  Whether or not APM is configured, you can use ``cardctl suspend''
+  before suspending your laptop, and ``cardctl resume'' after resuming,
+  to cleanly shut down and restart your PCMCIA cards.  This will not
+  work with a modem that is in use, because the serial driver isn't able
+  to save and restore the modem operating parameters.
+
+  APM seems to be unstable on some systems.  If you experience trouble
+  with APM and PCMCIA on your system, try to narrow down the problem to
+  one package or the other before reporting a bug.
+
+  Some drivers, notably the PCMCIA SCSI drivers, cannot recover from a
+  suspend/resume cycle.  When using a PCMCIA SCSI card, always use
+  ``cardctl eject'' prior to suspending the system.
+
+  44..11..66..  SShhuuttttiinngg ddoowwnn tthhee PPCCMMCCIIAA ssyysstteemm
+
+  To unload the entire PCMCIA package, invoke rc.pcmcia with:
+
+       /etc/rc.d/rc.pcmcia stop
+
+  This script will take several seconds to run, to give all client
+  drivers time to shut down gracefully.  If a device is currently in
+  use, the shutdown will be incomplete, and some kernel modules may not
+  be unloaded.  To avoid this, use ``cardctl eject'' to shut down all
+  sockets before invoking rc.pcmcia.  The exit status of the cardctl
+  command will indicate if any sockets could not be shut down.
+
+  44..22..  OOvveerrvviieeww ooff tthhee PPCCMMCCIIAA ccoonnffiigguurraattiioonn ssccrriippttss
+
+  Each PCMCIA device has an associated ``class'' that describes how it
+  should be configured and managed.  Classes are associated with device
+  drivers in /etc/pcmcia/config.  There are currently five IO device
+  classes (network, SCSI, cdrom, fixed disk, and serial) and two memory
+  device classes (memory and FTL).  For each class, there are two
+  scripts in /etc/pcmcia: a main configuration script (i.e.,
+  /etc/pcmcia/scsi for SCSI devices), and an options script (i.e.,
+  /etc/pcmcia/scsi.opts).  The main script for a device will be invoked
+  to configure that device when a card is inserted, and to shut down the
+  device when the card is removed.  For cards with several associated
+  devices, the script will be invoked for each device.
+
+  The config scripts start by extracting some information about a device
+  from the stab file.  Each script constructs a ``device address'', that
+  uniquely describes the device it has been asked to configure, in the
+  ADDRESS shell variable.  This is passed to the *.opts script, which
+  should return information about how a device at this address should be
+  configured.  For some devices, the device address is just the socket
+  number.  For others, it includes extra information that may be useful
+  in deciding how to configure the device.  For example, network devices
+  pass their hardware ethernet address as part of the device address, so
+  the network.opts script could use this to select from several
+  different configurations.
+
+  The first part of all device addresses is the current PCMCIA
+  ``scheme''.  This parameter is used to support multiple sets of device
+  configurations based on a single external user-specified variable.
+  One use of schemes would be to have a ``home'' scheme, and a ``work''
+  scheme, which would include different sets of network configuration
+  parameters.  The current scheme is selected using the ``cardctl
+  scheme'' command.  The default if no scheme is set is ``default''.
+
+  As a general rule, when configuring Linux for a laptop, PCMCIA devices
+  should only be configured from the PCMCIA device scripts.  Do not try
+  to configure a PCMCIA device the same way you would configure a
+  permanently attached device.  However, some Linux distributions
+  provide PCMCIA packages that are hooked into those distributions' own
+  device configuration tools.  In that case, some of the following
+  sections may not apply; ideally, this will be documented by the
+  distribution maintainers.
+
+  44..33..  PPCCMMCCIIAA nneettwwoorrkk aaddaapptteerrss
+
+  Linux ethernet-type network interfaces normally have names like eth0,
+  eth1, and so on.  Token-ring adapters are handled similarly, however
+  they are named tr0, tr1, and so on.  The ifconfig command is used to
+  view or modify the state of a network interface.  A peculiarity of
+  Linux is that network interfaces do not have corresponding device
+  files under /dev, so do not be surprised when you do not find them.
+
+  When an ethernet card is detected, it will be assigned the first free
+  interface name, which will normally be eth0.  Cardmgr will run the
+  /etc/pcmcia/network script to configure the interface, which normally
+  reads network settings from /etc/pcmcia/network.opts.  The network and
+  network.opts scripts will be executed only when your ethernet card is
+  actually present.  If your system has an automatic network
+  configuration facility, it may or may not be PCMCIA-aware.  Consult
+  the documentation of your Linux distribution and the ``Notes about
+  specific Linux distributions''  to determine if PCMCIA network devices
+  should be configured with the automatic tools, or by editing
+  network.opts.
+
+  The device address passed to network.opts consists of four comma-
+  separated fields: the scheme, the socket number, the device instance,
+  and the card's hardware ethernet address.  The device instance is used
+  to number devices for cards that have several network interfaces, so
+  it will usually be 0.  If you have several network cards used for
+  different purposes, one option would be to configure the cards based
+  on socket position, as in:
+
+       case "$ADDRESS" in
+       *,0,*,*)
+           # definitions for network card in socket 0
+           ;;
+       *,1,*,*)
+           # definitions for network card in socket 1
+           ;;
+       esac
+
+  Alternatively, they could be configured using their hardware
+  addresses, as in:
+
+  case "$ADDRESS" in
+  *,*,*,00:80:C8:76:00:B1)
+      # definitions for a D-Link card
+      ;;
+  *,*,*,08:00:5A:44:80:01)
+      # definitions for an IBM card
+  esac
+
+  44..33..11..  NNeettwwoorrkk ddeevviiccee ppaarraammeetteerrss
+
+  The following parameters can be defined in network.opts:
+
+     IF_PORT
+        Specifies the ethernet transceiver type, for certain 16-bit
+        cards that do not autodetect.  See ``man ifport'' for more
+        information.
+
+     BOOTP
+        A boolean (y/n) value: indicates if the host's IP address and
+        routing information should be obtained using the BOOTP protocol,
+        with bootpc or pump.
+
+     DHCP
+        A boolean (y/n) value: indicates if the host's IP address and
+        routing information should be obtained from a DHCP server.  The
+        network script first looks for dhcpcd, then dhclient, then pump.
+
+     DHCP_HOSTNAME
+        Specifies a hostname to be passed to dhcpcd or pump, for
+        inclusion in DHCP messages.
+
+     IPADDR
+        The IP address for this interface.
+
+     NETMASK, BROADCAST, NETWORK
+        Basic network parameters: see the networking HOWTO for more
+        information.
+
+     GATEWAY
+        The IP address of a gateway for this host's subnet.  Packets
+        with destinations outside this subnet will be routed to this
+        gateway.
+
+     DOMAIN
+        The local network domain name for this host, to be used in
+        creating /etc/resolv.conf.
+
+     SEARCH
+        A search list for host name lookup, to be added to
+        /etc/resolv.conf.  DOMAIN and SEARCH are mutually exclusive: see
+        ``man resolver'' for more information.
+
+     DNS_1, DNS_2, DNS_3
+        Host names or IP addresses for nameservers for this interface,
+        to be added to /etc/resolv.conf
+
+     MOUNTS
+        A space-separated list of NFS mount points to be mounted for
+        this interface.
+
+     IPX_FRAME, IPX_NETNUM
+        For IPX networks: the frame type and network number, passed to
+        the ipx_interface command.
+
+  For example:
+
+       case "$ADDRESS" in
+       *,*,*,*)
+           IF_PORT="10base2"
+           BOOTP="n"
+           IPADDR="10.0.0.1"
+           NETMASK="255.255.255.0"
+           NETWORK="10.0.0.0"
+           BROADCAST="10.0.0.255"
+           GATEWAY="10.0.0.1"
+           DOMAIN="domain.org"
+           DNS_1="dns1.domain.org"
+           ;;
+       esac
+
+  To automatically mount and unmount NFS filesystems, first add all
+  these filesystems to /etc/fstab, but include noauto in the mount
+  options.  In network.opts, list the filesystem mount points in the
+  MOUNTS variable.  It is especially important to use either cardctl or
+  cardinfo to shut down a network card when NFS mounts are active.  It
+  is not possible to cleanly unmount NFS filesystems if a network card
+  is simply ejected without warning.
+
+  In addition to the usual network configuration parameters, the
+  network.opts script can specify extra actions to be taken after an
+  interface is configured, or before an interface is shut down.  If
+  network.opts defines a shell function called start_fn, it will be
+  invoked by the network script after the interface is configured, and
+  the interface name will be passed to the function as its first (and
+  only) argument.  Similarly, if it is defined, stop_fn will be invoked
+  before shutting down an interface.
+
+  The transceiver type for some cards can be selected using the IF_PORT
+  setting.  This can either be a numeric value, or a keyword identifying
+  the transceiver type.  All the network drivers default to either
+  autodetect the interface if possible, or 10baseT otherwise.  The
+  ifport command can be used to check or set the current transceiver
+  type.  For example:
+
+       # ifport eth0 10base2
+       #
+       # ifport eth0
+       eth0    2 (10base2)
+
+  The current (3.0.10 or later) 3c589 driver should quickly autodetect
+  transceiver changes at any time.  Earlier releases of the 3c589 driver
+  had a somewhat slow and flaky transceiver autodetection algorithm.
+  For these releases, the appropriate network cable should be connected
+  to the card when the card is configured, or you can force
+  autodetection with:
+
+       ifconfig eth0 down up
+
+  44..33..22..  CCoommmmeennttss aabboouutt ssppeecciiffiicc ccaarrddss
+
+  +o  With IBM CCAE and Socket EA cards, the transceiver type (10base2,
+     10baseT, AUI) needs to be set when the network device is
+     configured.  Make sure that the transceiver type reported in the
+     system log matches your connection.
+
+  +o  The Farallon EtherWave is actually based on the 3Com 3c589, with a
+     special transceiver.  Though the EtherWave uses 10baseT-style
+     connections, its transceiver requires that the 3c589 be configured
+     in 10base2 mode.
+
+  +o  If you have trouble with an IBM CCAE, NE4100, Thomas Conrad, or
+     Kingston adapter, try increasing the memory access time with the
+     mem_speed=# option to the pcnet_cs module.  An example of how to do
+     this is given in the standard config.opts file.  Try speeds of up
+     to 1000 (in nanoseconds).
+
+  +o  For the New Media Ethernet adapter, on some systems, it may be
+     necessary to increase the IO port access time with the io_speed=#
+     option when the pcmcia_core module is loaded.  Edit CORE_OPTS in
+     the startup script  to set this option.
+
+  +o  The multicast support in the New Media Ethernet driver is
+     incomplete.  The latest driver will function with multicast
+     kernels, but will ignore multicast packets.  Promiscuous mode
+     should work properly.
+
+  +o  The driver used by the IBM and 3Com token ring adapters seems to
+     behave very badly if the cards are not connected to a ring when
+     they get initialized.  Always connect these cards to the net before
+     they are powered up.  If ifconfig reports the hardware address as
+     all 0's, this is likely to be due to a memory window configuration
+     problem.
+
+  +o  Some Linksys, D-Link, and IC-Card 10baseT/10base2 cards have a
+     unique way of selecting the transceiver type that isn't handled by
+     the Linux drivers.  One workaround is to boot DOS and use the
+     vendor-supplied utility to select the transceiver, then warm boot
+     Linux.  Alternatively, a Linux utility to perform this function is
+     available at  <ftp://sourceforge.org/pcmcia/extras/dlport.c>.
+
+  +o  16-bit PCMCIA cards have a maximum performance of 1.5-2 MB/sec.
+     That means that any 16-bit 100baseT card (i.e., any card that uses
+     the pcnet_cs, 3c574_cs, smc91c92_cs, or xirc2ps_cs driver) will
+     never achieve full 100baseT throughput.  Only CardBus network
+     adapters can fully exploit 100baseT data rates.
+
+  +o  For WaveLAN wireless network adapters, Jean Tourrilhes
+     (jt@hpl.hp.com) has put together a wireless HOWTO at
+     <http://www.hpl.hp.com/personal/Jean_Tourrilhes/Linux/>.
+
+  44..33..33..  DDiiaaggnnoossiinngg pprroobblleemmss wwiitthh nneettwwoorrkk aaddaapptteerrss
+
+  +o  In 3.1.15 and later PCMCIA releases, the test_network script in the
+     debug-tools subdirectory of the PCMCIA source tree will spot some
+     common problems.
+
+  +o  Is your card recognized as an ethernet card?  Check the system log
+     and make sure that cardmgr identifies the card correctly and starts
+     up one of the network drivers.  If it doesn't, your card might
+     still be usable if it is compatible with a supported card.  This
+     will be most easily done if the card claims to be ``NE2000
+     compatible''.
+
+  +o  Is the card configured properly?  If you are using a supported
+     card, and it was recognized by cardmgr, but still doesn't work,
+     there might be an interrupt or port conflict with another device.
+     Find out what resources the card is using (from the system log),
+     and try excluding these in /etc/pcmcia/config.opts to force the
+     card to use something different.
+
+  +o  If your card seems to be configured properly, but sometimes locks
+     up, particularly under high load, you may need to try changing your
+     socket driver timing parameters.  See the ``Startup options''
+     section for more information.
+
+  +o  If you get ``Network is unreachable'' messages when you try to
+     access the network, then the routing information specified in
+     /etc/pcmcia/network.opts is incorrect.  This exact message is an
+     absolutely foolproof indication of a routing error.  On the other
+     hand, mis-configured cards will usually fail silently.
+
+  +o  If you are trying to use DHCP to configure your network interface,
+     try testing things with a static IP address instead, to rule out a
+     DHCP configuration problem.
+
+  +o  To diagnose problems in /etc/pcmcia/network.opts, start by trying
+     to ping other systems on the same subnet using their IP addresses.
+     Then try to ping your gateway, and then machines on other subnets.
+     Ping machines by name only after trying these simpler tests.
+
+  +o  Make sure your problem is really a PCMCIA one.  It may help to see
+     see if the card works under DOS with the vendor's drivers.  Double
+     check your modifications to the /etc/pcmcia/network.opts script.
+     Make sure your drop cable, ``T'' jack, terminator, etc are working.
+
+  +o  Use real network cables.  Don't even think about using that old
+     phone cord you found in your basement.  And this means Category 5
+     cable for 100baseT.  It really matters.
+
+  44..44..  PPCCMMCCIIAA sseerriiaall aanndd mmooddeemm ddeevviicceess
+
+  Linux serial devices are accessed via the /dev/ttyS* and /dev/cua*
+  special device files.  In pre-2.2 kernels, the ttyS* devices were for
+  incoming connections, such as directly connected terminals, and the
+  cua* devices were for outgoing connections, such as modems.  Use of
+  cua* devices is deprecated in current kernels, and ttyS* can be used
+  for all applications.  The configuration of a serial device can be
+  examined and modified with the setserial command.
+
+  When a serial or modem card is detected, it will be assigned to the
+  first available serial device slot.  This will usually be /dev/ttyS1
+  (cua1) or /dev/ttyS2 (cua2), depending on the number of built-in
+  serial ports.  The ttyS* device is the one reported in stab.  The
+  default serial device option script, /etc/pcmcia/serial.opts, will
+  link the device file to /dev/modem as a convenience.  For pre-2.2
+  kernels, the link is made to the cua* device.
+
+  Do not try to use /etc/rc.d/rc.serial to configure a PCMCIA modem.
+  This script should only be used to configure non-removable devices.
+  Modify /etc/pcmcia/serial.opts if you want to do anything special to
+  set up your modem.  Also, do not try to change the IO port and
+  interrupt settings of a serial device using setserial.  This would
+  tell the serial driver to look for the device in a different place,
+  but would not change how the card's hardware is actually configured.
+  The serial configuration script allows you to specify other setserial
+  options, as well as whether a line should be added to /etc/inittab for
+  this port.
+
+  The device address passed to serial.opts has three comma-separated
+  fields: the first is the scheme, the second is the socket number, and
+  the third is the device instance.  The device instance may take
+  several values for cards that support multiple serial ports, but for
+  single-port cards, it will always be 0.  If you commonly use more than
+  one modem, you may want to specify different settings based on socket
+  position, as in:
+
+       case "$ADDRESS" in
+       *,0,*)
+           # Options for modem in socket 0
+           LINK=/dev/modem0
+           ;;
+       *,1,*)
+           # Options for modem in socket 1
+           LINK=/dev/modem1
+           ;;
+       esac
+
+  If a PCMCIA modem is already configured when Linux boots, it may be
+  incorrectly identified as an ordinary built-in serial port.  This is
+  harmless, however, when the PCMCIA drivers take control of the modem,
+  it will be assigned a different device slot.  It is best to either
+  parse stab or use /dev/modem, rather than expecting a PCMCIA modem to
+  always have the same device assignment.
+
+  If you configure your kernel to load the basic Linux serial port
+  driver as a module, you must edit /etc/pcmcia/config to indicate that
+  this module must be loaded.  Edit the serial device entry to read:
+
+       device "serial_cs"
+         class "serial" module "misc/serial", "serial_cs"
+
+  44..44..11..  SSeerriiaall ddeevviiccee ppaarraammeetteerrss
+
+  The following parameters can be defined in serial.opts:
+
+     LINK
+        Specifies a path for a symbolic link to be created to the
+        ``callout'' device (e.g., /dev/cua* for pre-2.2, or /dev/ttyS*
+        for 2.2 kernels).
+
+     SERIAL_OPTS
+        Specifies options to be passed to the setserial command.
+     INITTAB
+        If specified, this will be used to construct an inittab entry
+        for the device.
+
+  For example:
+
+       case "$ADDRESS" in
+       *,*,*,*)
+           LINK="/dev/modem"
+           SERIAL_OPTS=""
+           INITTAB="/sbin/getty"
+
+  44..44..22..  CCoommmmeennttss aabboouutt ssppeecciiffiicc ccaarrddss
+
+  +o  The Uniden Data 2000 Wireless CDPD card has some special dialing
+     strings for initiating SLIP and PPP mode.  For SLIP, use ``ATDT2'';
+     for PPP, "ATDT0".
+
+  44..44..33..  DDiiaaggnnoossiinngg pprroobblleemmss wwiitthh sseerriiaall ddeevviicceess
+
+  +o  In 3.1.15 and later PCMCIA releases, the test_modem script in the
+     debug-tools subdirectory of the PCMCIA source tree will spot some
+     common problems.
+
+  +o  Is your card recognized as a modem?  Check the system log and make
+     sure that cardmgr identifies the card correctly and starts up the
+     serial_cs driver.  If it doesn't, you may need to add a new entry
+     to your /etc/pcmcia/config file so that it will be identified
+     properly.  See the ``Configuring unrecognized cards'' section for
+     details.
+
+  +o  Is the modem configured successfully by serial_cs?  Again, check
+     the system log and look for messages from the serial_cs driver.  If
+     you see ``register_serial() failed'', you may have an I/O port
+     conflict with another device.  Another tip-off of a conflict is if
+     the device is reported to be an 8250; most modern modems should be
+     identified as 16550A UART's.  If you think you're seeing a port
+     conflict, edit /etc/pcmcia/config.opts and exclude the port range
+     that was allocated for the modem.
+
+  +o  Is there an interrupt conflict?  If the system log looks good, but
+     the modem just doesn't seem to work, try using setserial to change
+     the irq to 0, and see if the modem works.  This causes the serial
+     driver to use a slower polled mode instead of using interrupts.  If
+     this seems to fix the problem, it is likely that some other device
+     in your system is using the interrupt selected by serial_cs.  You
+     should add a line to /etc/pcmcia/config.opts to exclude this
+     interrupt.
+
+  +o  If the modem seems to work only very, very slowly, this is an
+     almost certain indicator of an interrupt conflict.
+
+  +o  Make sure your problem is really a PCMCIA one.  It may help to see
+     if the card works under DOS with the vendor's drivers.  Also, don't
+     test the card with something complex like SLIP or PPP until you are
+     sure you can make simple connections.  If simple things work but
+     SLIP does not, your problem is most likely with SLIP, not with
+     PCMCIA.
+
+  +o  If you get kernel messages indicating that the serial_cs module
+     cannot be loaded, it means that your kernel does not have serial
+     device support.  If you have compiled the serial driver as a
+     module, you must modify /etc/pcmcia/config to indicate that the
+     serial module should be loaded before serial_cs.
+
+  44..55..  PPCCMMCCIIAA ppaarraalllleell ppoorrtt ddeevviicceess
+
+  The Linux parallel port driver is layered so that several high-level
+  device types can share use of the same low level port driver.  Printer
+  devices are accessed via the /dev/lp* special device files.  The
+  configuration of a printer device can be examined and modified with
+  the tunelp command.
+
+  The parport_cs module depends on the parport and parport_pc drivers,
+  which may be either compiled into the kernel or compiled as modules.
+  The layered driver structure means that any top-level parallel drivers
+  (such as the plip driver, the printer driver, etc) must be compiled as
+  modules.  These drivers only recognize parallel port devices at module
+  startup time, so they need to be loaded after any PC Card parallel
+  devices are configured.
+
+  The device address passed to parport.opts has three comma-separated
+  fields: the first is the scheme, the second is the socket number, and
+  the third is the device instance.  The device instance may take
+  several values for cards that support multiple parallel ports, but for
+  single-port cards, it will always be 0.  If you commonly use more than
+  one such card, you may want to specify different settings based on
+  socket position, as in:
+
+       case "$ADDRESS" in
+       *,0,*)
+           # Options for card in socket 0
+           LINK=/dev/printer0
+           ;;
+       *,1,*)
+           # Options for card in socket 1
+           LINK=/dev/printer1
+           ;;
+       esac
+
+  If you configure your kernel to load the basic Linux parallel port
+  driver as a module, you must edit /etc/pcmcia/config to indicate that
+  the appropriate modules must be loaded.  Edit the parallel device
+  entry to read:
+
+       device "parport_cs"
+         class "parport" module "misc/parport", "misc/parport_pc", "parport_cs"
+
+  44..55..11..  PPaarraalllleell ddeevviiccee ppaarraammeetteerrss
+
+  The following parameters can be defined in parport.opts:
+
+     LINK
+        Specifies a path for a symbolic link to be created to the
+        printer port.
+
+     LP_OPTS
+        Specifies options to be passed to the tunelp command.
+
+  For example:
+
+       case "$ADDRESS" in
+       *,*,*,*)
+           LINK="/dev/printer"
+           LP_OPTS=""
+
+  44..55..22..  DDiiaaggnnoossiinngg pprroobblleemmss wwiitthh ppaarraalllleell ppoorrtt ddeevviicceess
+
+  +o  Is there an interrupt conflict?  If the system log looks good, but
+     the port just doesn't seem to work, try using tunelp to change the
+     irq to 0, and see if things improve.  This switches the driver to
+     polling mode.  If this seems to fix the problem, it is likely that
+     some other device in your system is using the interrupt selected by
+     parport_cs.  You should add a line to /etc/pcmcia/config.opts to
+     exclude this interrupt.
+
+  +o  If you get kernel messages indicating that the parport_cs module
+     cannot be loaded, it means that your kernel does not have parallel
+     device support.  If you have compiled the parallel driver as a
+     module, you may need to modify /etc/pcmcia/config to indicate that
+     the parport and parport_pc modules should be loaded before
+     parport_cs.
+
+  44..66..  PPCCMMCCIIAA SSCCSSII aaddaapptteerrss
+
+  All the currently supported PCMCIA SCSI cards are work-alikes of one
+  of the following ISA bus cards: the Qlogic, the Adaptec AHA-152X, or
+  the Future Domain TMC-16x0.  The PCMCIA drivers are built by linking
+  some PCMCIA-specific code (in qlogic_cs.c, aha152x_cs.c, or
+  fdomain_cs.c) with the normal Linux SCSI driver, pulled from the Linux
+  kernel source tree.  The Adaptec APA1480 CardBus driver is based on
+  the kernel aic7xxx PCI driver.  Due to limitations in the Linux SCSI
+  driver model, only one removable card per driver is supported.
+
+  When a new SCSI host adapter is detected, the SCSI drivers will probe
+  for devices.  Check the system log to make sure your devices are
+  detected properly.  New SCSI devices will be assigned to the first
+  available SCSI device files.  The first SCSI disk will be /dev/sda,
+  the first SCSI tape will be /dev/st0, and the first CD-ROM will be
+  /dev/scd0.
+
+  A list of SCSI devices connected to this host adapter will be shown in
+  stab, and the SCSI configuration script, /etc/pcmcia/scsi, will be
+  called once for each attached device, to either configure or shut down
+  that device.  The default script does not take any actions to
+  configure SCSI devices, but will properly unmount filesystems on SCSI
+  devices when a card is removed.
+
+  The device addresses passed to scsi.opts are complicated, because of
+  the variety of things that can be attached to a SCSI adapter.
+  Addresses consist of either six or seven comma-separated fields: the
+  current scheme, the device type, the socket number, the SCSI channel,
+  ID, and logical unit number, and optionally, the partition number.
+  The device type will be ``sd'' for disks, ``st'' for tapes, ``sr'' for
+  CD-ROM devices, and ``sg'' for generic SCSI devices.  For most setups,
+  the SCSI channel and logical unit number will be 0.  For disk devices
+  with several partitions, scsi.opts will first be called for the whole
+  device, with a five-field address.  The script should set the PARTS
+  variable to a list of partitions.  Then, scsi.opts will be called for
+  each partition, with the longer seven-field addresses.
+
+  If your kernel does not have a top-level driver (disk, tape, etc) for
+  a particular SCSI device, then the device will not be configured by
+  the PCMCIA drivers.  As a side effect, the device's name in stab will
+  be something like ``sd#nnnn'' where ``nnnn'' is a four-digit hex
+  number.  This happens when cardmgr is unable to translate a SCSI
+  device ID into a corresponding Linux device name.
+
+  It is possible to modularize the top-level SCSI drivers so that they
+  are loaded on demand.  To do so, you need to edit /etc/pcmcia/config
+  to tell cardmgr which extra modules need to be loaded when your
+  adapter is configured.  For example:
+
+       device "aha152x_cs"
+         class "scsi" module "scsi/scsi_mod", "scsi/sd_mod", "aha152x_cs"
+
+  would say to load the core SCSI module and the top-level disk driver
+  module before loading the regular PCMCIA driver module.  The PCMCIA
+  Configure script will not automatically detect modularized SCSI
+  modules, so you will need use the manual configure option to enable
+  SCSI support.
+
+  Always turn on SCSI devices before powering up your laptop, or before
+  inserting the adapter card, so that the SCSI bus is properly
+  terminated when the adapter is configured.  Also be very careful about
+  ejecting a SCSI adapter.  Be sure that all associated SCSI devices are
+  unmounted and closed before ejecting the card.  The best way to ensure
+  this is to use either cardctl or cardinfo to request card removal
+  before physically ejecting the card.  For now, all SCSI devices should
+  be powered up before plugging in a SCSI adapter, and should stay
+  connected until after you unplug the adapter and/or power down your
+  laptop.
+
+  There is a potential complication when using these cards that does not
+  arise with ordinary ISA bus adapters.  The SCSI bus carries a
+  ``termination power'' signal that is necessary for proper operation of
+  ordinary passive SCSI terminators.  PCMCIA SCSI adapters do not supply
+  termination power, so if it is required, an external device must
+  supply it.  Some external SCSI devices may be configured to supply
+  termination power.  Others, such as the Zip Drive and the Syquest EZ-
+  Drive, use active terminators that do not depend on it.  In some
+  cases, it may be necessary to use a special terminator block such as
+  the APS SCSI Sentry 2, which has an external power supply.  When
+  configuring your SCSI device chain, be aware of whether or not any of
+  your devices require or can provide termination power.
+
+  44..66..11..  SSCCSSII ddeevviiccee ppaarraammeetteerrss
+
+  The following parameters can be defined in scsi.opts:
+
+     DO_FSTAB
+        A boolean (y/n) setting: specifies if an entry should be added
+        to /etc/fstab for this device.
+
+     DO_FSCK
+        A boolean (y/n) setting: specifies if the filesystem should be
+        checked before being mounted, with ``fsck -Ta''.
+
+     DO_MOUNT
+        A boolean (y/n) setting: specifies if this device should be
+        automatically mounted at card insertion time.
+
+     FSTYPE, OPTS, MOUNTPT
+        The filesystem type, mount options, and mount point to be used
+        for the fstab entry and/or mounting the device.
+
+  For example, here is a script for configuring a disk device at SCSI ID
+  3, with two partitions, and a CD-ROM at SCSI ID 6:
+
+       case "$ADDRESS" in
+       *,sd,*,0,3,0)
+           # This device has two partitions...
+           PARTS="1 2"
+           ;;
+       *,sd,*,0,3,0,1)
+           # Options for partition 1:
+           #  update /etc/fstab, and mount an ext2 fs on /usr1
+           DO_FSTAB="y" ; DO_FSCK="y" ; DO_MOUNT="y"
+           FSTYPE="ext2"
+           OPTS=""
+           MOUNTPT="/usr1"
+           ;;
+       *,sd,*,0,3,0,2)
+           # Options for partition 2:
+           #  update /etc/fstab, and mount an MS-DOS fs on /usr2
+           DO_FSTAB="y" ; DO_FSCK="y" ; DO_MOUNT="y"
+           FSTYPE="msdos"
+           OPTS=""
+           MOUNTPT="/usr2"
+           ;;
+       *,sr,*,0,6,0)
+           # Options for CD-ROM at SCSI ID 6
+           PARTS=""
+           DO_FSTAB="y" ; DO_FSCK="n" ; DO_MOUNT="y"
+           FSTYPE="iso9660"
+           OPTS="ro"
+           MOUNTPT="/cdrom"
+           ;;
+       esac
+
+  44..66..22..  CCoommmmeennttss aabboouutt ssppeecciiffiicc ccaarrddss
+
+  +o  The Adaptec APA-1480 CardBus card needs a large IO port window (256
+     contiguous ports aligned on a 256-port boundary).  It may be
+     necessary to expand the IO port regions in /etc/pcmcia/config.opts
+     to guarantee that such a large window can be found.
+
+  +o  The Adaptec APA-460 SlimSCSI adapter is not supported.  This card
+     was originally sold under the Trantor name, and when Adaptec merged
+     with Trantor, they continued to sell the Trantor card with an
+     Adaptec label.  The APA-460 is not compatible with any existing
+     Linux driver.
+
+  +o  I have had one report of a bad interaction between the New Media
+     Bus Toaster and a UMAX Astra 1200s scanner.  Due to the complexity
+     of the SCSI protocol, when diagnosing problems with SCSI devices,
+     it is worth considering that incompatible combinations like this
+     may exist and may not be documented.
+
+  44..66..33..  DDiiaaggnnoossiinngg pprroobblleemmss wwiitthh SSCCSSII aaddaapptteerrss
+
+  +o  With the aha152x_cs driver (used by Adaptec, New Media, and a few
+     others), it seems that SCSI disconnect/reconnect support is a
+     frequent source of trouble with tape drives.  To disable this
+     ``feature,'' add the following to /etc/pcmcia/config.opts:
+
+       module "aha152x_cs" opts "reconnect=0"
+
+  +o  Also with the aha152x_cs driver, certain devices seem to require a
+     longer startup delay, controlled via the reset_delay module
+     parameter.  The Yamaha 4416S CDR drive is one such device.  The
+     result is the device is identified successfully, then hangs the
+     system.  In such cases, try:
+
+       module "aha152x_cs" opts "reset_delay=500"
+
+  +o  Another potential source of SCSI device probe problems is probing
+     of multiple LUN's.  If you see successful detection of a device,
+     followed by SCSI bus timeouts when LUN 1 for that device is probed,
+     then disable the kernel's CONFIG_SCSI_MULTI_LUN option.
+
+  +o  If you have compiled SCSI support as modules (CONFIG_SCSI is
+     ``m''), you must modify /etc/pcmcia/config to load the SCSI modules
+     before the appropriate *_cs driver is loaded.
+
+  +o  If you get ``aborting command due to timeout'' messages when the
+     SCSI bus is probed, you almost certainly have an interrupt
+     conflict.
+
+  +o  If the host driver reports ``no SCSI devices found'', verify that
+     your kernel was compiled with the appropriate top-level SCSI
+     drivers for your devices (i.e., disk, tape, CD-ROM, and/or
+     generic).  If a top-level driver is missing, devices of that type
+     will be ignored.
+
+  44..77..  PPCCMMCCIIAA mmeemmoorryy ccaarrddss
+
+  The memory_cs driver handles all types of memory cards, as well as
+  providing direct access to the PCMCIA memory address space for cards
+  that have other functions.  When loaded, it creates a combination of
+  character and block devices.  See the man page for the module for a
+  complete description of the device naming scheme.  Block devices are
+  used for disk-like access (creating and mounting filesystems, etc).
+  The character devices are for "raw" unbuffered reads and writes at
+  arbitrary locations.
+
+  The device address passed to memory.opts consists of two fields: the
+  scheme, and the socket number.  The options are applied to the first
+  common memory partition on the corresponding memory card.
+
+  Some older memory cards, and most simple static RAM cards, lack a
+  ``Card Information Structure'' (CIS), which is the scheme PCMCIA cards
+  use to identify themselves.  Normally, cardmgr will assume that any
+  card that lacks a CIS is a simple memory card, and load the memory_cs
+  driver.  Thus, a common side effect of a general card identification
+  problem is that other types of cards may be misdetected as memory
+  cards.
+
+  The memory_cs driver uses a heuristic to guess the capacity of these
+  cards.  The heuristic does not work for write protected cards, and may
+  make mistakes in some other cases as well.  If a card is misdetected,
+  its size should then be explicitly specified when using commands such
+  as dd or mkfs.
+
+  44..77..11..  MMeemmoorryy ddeevviiccee ppaarraammeetteerrss
+
+  The following parameters can be specified in memory.opts:
+
+     DO_FSTAB
+        A boolean (y/n) setting: specifies if an entry should be added
+        to /etc/fstab for this device.
+
+     DO_FSCK
+        A boolean (y/n) setting: specifies if the filesystem should be
+        checked before being mounted, with ``fsck -Ta''.
+
+     DO_MOUNT
+        A boolean (y/n) setting: specifies if this device should be
+        automatically mounted at card insertion time.
+
+     FSTYPE, OPTS, MOUNTPT
+        The filesystem type, mount options, and mount point to be used
+        for the fstab entry and/or mounting the device.
+
+  Here is an example of a script that will automatically mount memory
+  cards based on which socket they are inserted into:
+
+  case "$ADDRESS" in
+  *,0,0)
+      # Mount filesystem, but don't update /etc/fstab
+      DO_FSTAB="n" ; DO_FSCK="y" ; DO_MOUNT="y"
+      FSTYPE="ext2" ; OPTS=""
+      MOUNTPT="/mem0"
+      ;;
+  *,1,0)
+      # Mount filesystem, but don't update /etc/fstab
+      DO_FSTAB="n" ; DO_FSCK="y" ; DO_MOUNT="y"
+      FSTYPE="ext2" ; OPTS=""
+      MOUNTPT="/mem1"
+      ;;
+  esac
+
+  44..77..22..  UUssiinngg lliinneeaarr ffllaasshh mmeemmoorryy ccaarrddss
+
+  The following information applies only to so-called ``linear flash''
+  memory cards.  Many flash cards, including all SmartMedia and
+  CompactFlash cards, actually include circuitry to emulate an IDE disk
+  device.  Those cards are thus handled as IDE devices, not memory
+  cards.
+
+  There are two major formats for flash memory cards: the FTL or ``flash
+  translation layer'' style, and the Microsoft Flash File System.  The
+  FTL format is generally more flexible because it allows any ordinary
+  high-level filesystem (ext2, ms-dos, etc) to be used on a flash card
+  as if it were an ordinary disk device.  The FFS is a completely
+  different filesystem type.  Linux cannot currently handle cards
+  formated with FFS.
+
+  To use a flash memory card as an ordinary disk-like block device,
+  first create an FTL partition on the device with the ftl_format
+  command.  This layer hides the device-specific details of flash memory
+  programming and make the card look like a simple block device.  For
+  example:
+
+       ftl_format -i /dev/mem0c0c
+
+  Note that this command accesses the card through the ``raw'' memory
+  card interface.  Once formatted, the card can be accessed as an
+  ordinary block device via the ftl_cs driver.  For example:
+
+       mke2fs /dev/ftl0c0
+       mount -t ext2 /dev/ftl0c0 /mnt
+
+  Device naming for FTL devices is tricky.  Minor device numbers have
+  three parts: the card number, the region number on that card, and
+  optionally, the partition within that region.  A region can either be
+  treated as a single block device with no partition table (like a
+  floppy), or it can be partitioned like a hard disk device.  The
+  ``ftl0c0'' device is card 0, common memory region 0, the entire
+  region.  The ``ftl0c0p1'' through ``ftl0c0p4'' devices are primary
+  partitions 1 through 4 if the region has been partitioned.
+
+  Configuration options for FTL partitions can be given in ftl.opts,
+  which is similar in structure to memory.opts.  The device address
+  passed to ftl.opts consists of three or four fields: the scheme, the
+  socket number, the region number, and optionally, the partition
+  number.  Most flash cards have just one flash memory region, so the
+  region number will generally always be zero.
+
+  Intel Series 100 flash cards use the first 128K flash block to store
+  the cards' configuration information.  To prevent accidental erasure
+  of this information, ftl_format will automatically detect this and
+  skip the first block when creating an FTL partition.
+
+  44..88..  PPCCMMCCIIAA AATTAA//IIDDEE ccaarrdd ddrriivveess
+
+  ATA/IDE drive support is based on the regular kernel IDE driver.  This
+  includes SmartMedia and CompactFlash devices: these flash memory cards
+  are set up so that they emulate an IDE interface.  The PCMCIA-specific
+  part of the driver is ide_cs.  Be sure to use cardctl or cardinfo to
+  shut down an ATA/IDE card before ejecting it, as the driver has not
+  been made ``hot-swap-proof''.
+
+  The device addresses passed to ide.opts consist of either three or
+  four fields: the current scheme, the socket number, the drive's serial
+  number, and an optional partition number.  The ide_info command can be
+  used to obtain an IDE device's serial number.  As with SCSI devices,
+  ide.opts is first called for the entire device.  If ide.opts returns a
+  list of partitions in the PARTS variable, the script will then be
+  called for each partition.
+
+  44..88..11..  AATTAA//IIDDEE ffiixxeedd--ddiisskk ddeevviiccee ppaarraammeetteerrss
+
+  The following parameters can be specified in ide.opts:
+
+     DO_FSTAB
+        A boolean (y/n) setting: specifies if an entry should be added
+        to /etc/fstab for this device.
+
+     DO_FSCK
+        A boolean (y/n) setting: specifies if the filesystem should be
+        checked before being mounted, with ``fsck -Ta''.
+
+     DO_MOUNT
+        A boolean (y/n) setting: specifies if this device should be
+        automatically mounted at card insertion time.
+
+     FSTYPE, OPTS, MOUNTPT
+        The filesystem type, mount options, and mount point to be used
+        for the fstab entry and/or mounting the device.
+
+  Here is an example ide.opts file to mount the first partition of any
+  ATA/IDE card on /mnt.
+
+  case "$ADDRESS" in
+  *,*,*,1)
+      DO_FSTAB="y" ; DO_FSCK="y" ; DO_MOUNT="y"
+      FSTYPE="msdos"
+      OPTS=""
+      MOUNTPT="/mnt"
+      ;;
+  *,*,*)
+      PARTS="1"
+      ;;
+  esac
+
+  44..88..22..  DDiiaaggnnoossiinngg pprroobblleemmss wwiitthh AATTAA//IIDDEE aaddaapptteerrss
+
+  +o  An IO port conflict may cause the IDE driver to misdetect the drive
+     geometry and report ``INVALID GEOMETRY: 0 PHYSICAL HEADS?''.  To
+     fix, try excluding the selected IO port range in
+     /etc/pcmcia/config.opts.
+
+  +o  Some IDE drives violate the PCMCIA specification by requiring a
+     longer time to spin up than the maximum allowed card setup time.
+     Starting with release 3.0.6, the ide_cs driver will automatically
+     retry the device probe to give these drives time to spin up.  With
+     older drivers, you may need to load the pcmcia_core module with:
+
+       CORE_OPTS="unreset_delay=400"
+
+  +o  To use an ATA/IDE CD-ROM device, your kernel must be compiled with
+     CONFIG_BLK_DEV_IDECD enabled.  This will normally be the case for
+     standard kernels, however it is something to be aware of if you
+     compile a custom kernel.
+
+  +o  A common error when using IDE drives is try to mount the wrong
+     device file.  Generally, you want to mount a partition of the
+     device, not the entire device (i.e., /dev/hde1, not /dev/hde).
+
+  +o  The Linux IDE driver may have trouble configuring certain
+     removable-media drives if no media is present at insertion time.
+     The IBM Portable DriveBay has this problem.
+
+  +o  Some kernels will report a pair of ``drive_cmd'' errors at
+     insertion time.  These errors can be ignored: they pop up when a
+     removable IDE device does not accept the IDE ``door lock'' command.
+
+  44..99..  MMuullttiiffuunnccttiioonn ccaarrddss
+
+  A single interrupt can be shared by several drivers, such as the
+  serial driver and an ethernet driver: in fact, the PCMCIA
+  specification requires all card functions to share the same interrupt.
+  Normally, all card functions are available without having to swap
+  drivers.  Any remotely recent Linux kernel (i.e., 1.3.72 or later)
+  supports this kind of interrupt sharing.
+
+  Simultaneous use of two card functions is ``tricky'' and various
+  hardware vendors have implemented interrupt sharing in their own
+  incompatible (and sometimes proprietary) ways.  The drivers for some
+  cards (Ositech Jack of Diamonds, 3Com 3c562 and related cards, Linksys
+  cards) properly support simultaneous access, but others (older
+  Megahertz cards in particular) do not.  If you have trouble using a
+  card with both functions active, try using each function in isolation.
+  That may require explicitly doing an ``ifconfig down'' to shut down a
+  network interface and use a modem on the same card.
+
+  55..  AAddvvaanncceedd ttooppiiccss
+
+  55..11..  RReessoouurrccee aallllooccaattiioonn ffoorr PPCCMMCCIIAA ddeevviicceess
+
+  In theory, it should not really matter which interrupt is allocated to
+  which device, as long as two devices are not configured to use the
+  same interrupt.  In /etc/pcmcia/config.opts you'll find a place for
+  excluding interrupts that are used by non-PCMCIA devices.
+
+  Similarly, there is no way to directly specify the I/O addresses for a
+  card to use.  The /etc/pcmcia/config.opts file allows you to specify
+  ranges of ports available for use by any card, or to exclude ranges
+  that conflict with other devices.
+
+  After modifying /etc/pcmcia/config.opts, you can reinitialize cardmgr
+  with ``kill -HUP''.
+
+  The interrupt used to monitor card status changes is chosen by the
+  low-level socket driver module (i82365 or tcic) before cardmgr parses
+  /etc/pcmcia/config, so it is not affected by changes to this file.  To
+  set this interrupt, use the cs_irq= option when the socket driver is
+  loaded, by setting the PCIC_OPTS variable in /etc/rc.d/rc.pcmcia.
+
+  All the client card drivers have a parameter called irq_list for
+  specifying which interrupts they may try to allocate.  These driver
+  options should be set in your /etc/pcmcia/config file.  For example:
+
+       device "serial_cs"
+         module "serial_cs" opts "irq_list=8,12"
+         ...
+
+  would specify that the serial driver should only use irq 8 or irq 12.
+  Regardless of irq_list settings, Card Services will never allocate an
+  interrupt that is already in use by another device, or an interrupt
+  that is excluded in the config file.
+
+  55..22..  HHooww ccaann II hhaavvee sseeppaarraattee ddeevviiccee sseettuuppss ffoorr hhoommee aanndd wwoorrkk??
+
+  This is fairly easy using ``scheme'' support.  Use two configuration
+  schemes, called ``home'' and ``work''.  Here is an example of a
+  network.opts script with scheme-specific settings:
+
+  case "$ADDRESS" in
+  work,*,*,*)
+      # definitions for network card in work scheme
+      ...
+      ;;
+  home,*,*,*|default,*,*,*)
+      # definitions for network card in home scheme
+      ...
+      ;;
+  esac
+
+  The first part of a device address is always the configuration scheme.
+  In this example, the second ``case'' clause will select for both the
+  ``home'' and ``default'' schemes.  So, if the scheme is unset for any
+  reason, it will default to the ``home'' setup.
+
+  Now, to select between the two sets of settings, run either:
+
+       cardctl scheme home
+
+  or
+
+       cardctl scheme work
+
+  The cardctl command does the equivalent of shutting down all your
+  cards and restarting them.  The command can be safely executed whether
+  or not the PCMCIA system is loaded, but the command may fail if you
+  are using other PCMCIA devices at the time (even if their
+  configurations are not explicitly dependant on the scheme setting).
+
+  To find out the current scheme setting, run:
+
+       cardctl scheme
+
+  By default, the scheme setting is persistent across boots.  This can
+  have undesirable effects if networking is initialized for the wrong
+  environment.  Optionally, you can set the initial scheme value with
+  the SCHEME startup option (see ``Startup options'' for details).  It
+  is also possible to set the scheme from the lilo boot prompt.  Since
+  lilo passes unrecognized options to init as environment variables, a
+  value for SCHEME (or any other PCMCIA startup option) at the boot
+  prompt will be propagated into the PCMCIA startup script.
+
+  To save even more keystrokes, schemes can be specified in lilo's
+  configuration file.  For instance, you could have:
+
+  root = /dev/hda1
+  read-only
+  image = /boot/vmlinuz
+    label  = home
+    append = "SCHEME=home"
+  image = /boot/vmlinuz
+    label  = work
+    append = "SCHEME=work"
+
+  Typing ``home'' or ``work'' at the boot prompt would then boot into
+  the appropriate scheme.
+
+  55..33..  BBoooottiinngg ffrroomm aa PPCCMMCCIIAA ddeevviiccee
+
+  Having the root filesystem on a PCMCIA device is tricky because the
+  Linux PCMCIA system is not designed to be linked into the kernel.  Its
+  core components, the loadable kernel modules and the user mode cardmgr
+  daemon, depend on an already running system.  The kernel's ``initrd''
+  facility works around this requirement by allowing Linux to boot using
+  a temporary ram disk as a minimal root image, load drivers, and then
+  re-mount a different root filesystem.  The temporary root can
+  configure PCMCIA devices and then re-mount a PCMCIA device as root.
+
+  The initrd image absolutely must reside on a bootable device: this
+  generally cannot be put on a PCMCIA device.  This is a BIOS
+  limitation, not a kernel limitation.  It is useful here to distinguish
+  between ``boot-able'' devices (i.e., devices that can be booted), and
+  ``root-able'' devices (i.e., devices that can be mounted as root).
+  ``Boot-able'' devices are determined by the BIOS, and are generally
+  limited to internal floppy and hard disk drives.  ``Root-able''
+  devices are any block devices that the kernel supports once it has
+  been loaded.  The initrd facility makes more devices ``root-able'',
+  not ``boot-able''.
+
+  Some Linux distributions will allow installation to a device connected
+  to a PCMCIA SCSI adapter, as an unintended side-effect of their
+  support for installs from PCMCIA SCSI CD-ROM devices.  However, at
+  present, no Linux installation tools support configuring an
+  appropriate ``initrd'' to boot Linux with a PCMCIA root filesystem.
+  Setting up a system with a PCMCIA root thus requires that you use
+  another Linux system to create the ``initrd'' image.  If another Linux
+  system is not available, another option would be to temporarily
+  install a minimal Linux setup on a non-PCMCIA drive, create an initrd
+  image, and then reinstall to the PCMCIA target.
+
+  The Linux Bootdisk-HOWTO has some general information about setting up
+  boot disks but nothing specific to initrd.  The main initrd document
+  is included with recent kernel source code distributions, in
+  linux/Documentation/initrd.txt.  Before beginning, you should read
+  this document.  A familiarity with lilo is also helpful.  Using initrd
+  also requires that you have a kernel compiled with CONFIG_BLK_DEV_RAM
+  and CONFIG_BLK_DEV_INITRD enabled.
+
+  This is an advanced configuration technique, and requires a high level
+  of familiarity with Linux and the PCMCIA system.  Be sure to read all
+  the relevant documentation before starting.  The following cookbook
+  instructions should work, but deviations from the examples will
+  quickly put you in uncharted and ``unsupported'' territory, and you
+  will be on your own.
+
+  This method absolutely requires that you use a PCMCIA driver release
+  of 2.9.5 or later.  Older PCMCIA packages or individual components
+  will not work in the initrd context.  Do not mix components from
+  different releases.
+
+  55..33..11..  TThhee ppcciinniittrrdd hheellppeerr ssccrriipptt
+
+  The pcinitrd script creates a basic initrd image for booting with a
+  PCMCIA root partition.  The image includes a minimal directory
+  heirarchy, a handful of device files, a few binaries, shared
+  libraries, and a set of PCMCIA driver modules.  When invoking
+  pcinitrd, you specify the driver modules that you want to be included
+  in the image.  The core PCMCIA components, pcmcia_core and ds, are
+  automatically included.
+
+  As an example, say that your laptop uses an i82365-compatible host
+  controller, and you want to boot Linux with the root filesystem on a
+  hard drive attached to an Adaptec SlimSCSI adapter.  You could create
+  an appropriate initrd image with:
+
+       pcinitrd -v initrd pcmcia/i82365.o pcmcia/aha152x_cs.o
+
+  To customize the initrd startup sequence, you could mount the image
+  using the ``loopback'' device with a command like:
+
+       mount -o loop -t ext2 initrd /mnt
+
+  and then edit the linuxrc script.  The configuration files will be
+  installed under /etc in the image, and can also be customized.  See
+  the man page for pcinitrd for more information.
+
+  55..33..22..  CCrreeaattiinngg aann iinniittrrdd bboooott ffllooppppyy
+
+  After creating an image with pcinitrd, you can create a boot floppy by
+  copying the kernel, the compressed initrd image, and a few support
+  files for lilo to a clean floppy.  In the following example, we assume
+  that the desired PCMCIA root device is /dev/sda1:
+
+       mke2fs /dev/fd0
+       mount /dev/fd0 /mnt
+       mkdir /mnt/etc /mnt/boot /mnt/dev
+       cp -a /dev/fd0 /dev/sda1 /mnt/dev
+       cp [kernel-image] /mnt/vmlinuz
+       cp /boot/boot.b /mnt/boot/boot.b
+       gzip < [initrd-image] > /mnt/initrd
+
+  Create /mnt/etc/lilo.conf with the contents:
+
+       boot=/dev/fd0
+       compact
+       image=/vmlinuz
+           label=linux
+           initrd=/initrd
+           read-only
+           root=/dev/sda1
+
+  Finally, invoke lilo with:
+
+       lilo -r /mnt
+
+  When lilo is invoked with -r, it performs all actions relative to the
+  specified alternate root directory.  The reason for creating the
+  device files under /mnt/dev was that lilo will not be able to use the
+  files in /dev when it is running in this alternate-root mode.
+
+  55..33..33..  IInnssttaalllliinngg aann iinniittrrdd iimmaaggee oonn aa nnoonn--LLiinnuuxx ddrriivvee
+
+  One common use of the initrd facility would be on systems where the
+  internal hard drive is dedicated to another operating system.  The
+  Linux kernel and initrd image can be placed in a non-Linux partition,
+  and lilo or LOADLIN can be set up to boot Linux from these images.
+
+  Assuming that you have a kernel has been configured for the
+  appropriate root device, and an initrd image created on another
+  system, the easiest way to get started is to boot Linux using LOADLIN,
+  as:
+
+       LOADLIN <kernel> initrd=<initrd-image>
+
+  Once you can boot Linux on your target machine, you could then install
+  lilo to allow booting Linux directly.  For example, say that /dev/hda1
+  is the non-Linux target partition and /mnt can be used as a mount
+  point.  First, create a subdirectory on the target for the Linux
+  files:
+
+       mount /dev/hda1 /mnt
+       mkdir /mnt/linux
+       cp [kernel-image] /mnt/linux/vmlinuz
+       cp [initrd-image] /mnt/linux/initrd
+
+  In this example, say that /dev/sda1 is the desired Linux root
+  partition, a SCSI hard drive mounted via a PCMCIA SCSI adapter.  To
+  install lilo, create a lilo.conf file with the contents:
+
+       boot=/dev/hda
+       map=/mnt/linux/map
+       compact
+       image=/mnt/linux/vmlinuz
+               label=linux
+               root=/dev/sda1
+               initrd=/mnt/linux/initrd
+               read-only
+       other=/dev/hda1
+               table=/dev/hda
+               label=windows
+
+  The boot= line says to install the boot loader in the master boot
+  record of the specified device.  The root= line identifies the desired
+  root filesystem to be used after loading the initrd image, and may be
+  unnecessary if the kernel image is already configured this way.  The
+  other= section is used to describe the other operating system
+  installed on /dev/hda1.
+
+  To install lilo in this case, use:
+
+       lilo -C lilo.conf
+
+  Note that in this case, the lilo.conf file uses absolute paths that
+  include /mnt.  I did this in the example because the target filesystem
+  may not support the creation of Linux device files for the boot= and
+  root= options.
+
+  66..  DDeeaalliinngg wwiitthh uunnssuuppppoorrtteedd ccaarrddss
+
+  66..11..  CCoonnffiigguurriinngg uunnrreeccooggnniizzeedd ccaarrddss
+
+  Assuming that your card is supported by an existing driver, all that
+  needs to be done is to add an entry to /etc/pcmcia/config to tell
+  cardmgr how to identify the card, and which driver(s) need to be
+  linked up to this card.  Check the man page for pcmcia for more
+  information about the config file format.  If you insert an unknown
+  card, cardmgr will normally record some identification information in
+  the system log that can be used to construct the config entry.  This
+  information can also be displayed with the ``cardctl ident'' command.
+
+  Here is an example of how cardmgr will report an unsupported card in
+  /usr/adm/messages.
+
+       cardmgr[460]: unsupported card in socket 1
+       cardmgr[460]: product info: "MEGAHERTZ", "XJ2288", "V.34 PCMCIA MODEM"
+       cardmgr[460]: manfid: 0x0101, 0x1234  function: 2 (serial)
+
+  The corresponding entry in /etc/pcmcia/config would be:
+
+       card "Megahertz XJ2288 V.34 Fax Modem"
+         version "MEGAHERTZ", "XJ2288", "V.34 PCMCIA MODEM"
+         bind "serial_cs"
+
+  or using the more compact product ID codes:
+
+       card "Megahertz XJ2288 V.34 Fax Modem"
+         manfid 0x0101, 0x1234
+         bind "serial_cs"
+
+  You can use ``*'' to match strings that don't need to match exactly,
+  like version numbers.  When making new config entries, be careful to
+  copy the strings exactly, preserving case and blank spaces.  Also be
+  sure that the config entry has the same number of strings as are
+  reported in the log file.
+
+  Beware that you can specify just about any driver for a card, but if
+  you're just shooting in the dark, there is not much reason to expect
+  this to be productive.  You may get lucky and find that your card is
+  supported by an existing driver.  However, the most likely outcome is
+  that the driver won't work, and may have unfortunate side effects like
+  locking up your system.  Unlike most ordinary device drivers, which
+  probe for an appropriate card, the probe for a PCMCIA device is done
+  by cardmgr, and the driver itself may not do much validation before
+  attempting to communicate with the device.
+
+  After editing /etc/pcmcia/config, you can signal cardmgr to reload the
+  file with:
+
+       kill -HUP `cat /var/run/cardmgr.pid`
+
+  If you do set up an entry for a new card, please send me a copy so
+  that I can include it in the standard config file.
+
+  66..22..  AAddddiinngg ssuuppppoorrtt ffoorr aann NNEE22000000--ccoommppaattiibbllee eetthheerrnneett ccaarrdd
+
+  Before you begin: this procedure will only work for simple ethernet
+  cards.  Multifunction cards (i.e., ethernet/modem combo cards) have an
+  extra layer of complexity regarding how the two functions are
+  integrated, and generally cannot be supported without obtaining some
+  configuration information from the card vendor.  Using the following
+  procedure for a multifunction card will not be productive.
+
+  First, see if the card is already recognized by cardmgr.  Some cards
+  not listed in SUPPORTED.CARDS are actually OEM versions of cards that
+  are supported.  If you find a card like this, let me know so I can add
+  it to the list.
+
+  If your card is not recognized, follow the instructions in the
+  ``Configuring unrecognized cards'' section to create a config entry
+  for your card, and bind the card to the pcnet_cs driver.  Restart
+  cardmgr to use the updated config file.
+
+  If the pcnet_cs driver says that it is unable to determine your card's
+  hardware ethernet address, then edit your new config entry to bind the
+  card to the memory card driver, memory_cs.  Restart cardmgr to use the
+  new updated config file.  You will need to know your card's hardware
+  ethernet address.  This address is a series of six two-digit hex
+  numbers, often printed on the card itself.  If it is not printed on
+  the card, you may be able to use a DOS driver to display the address.
+  In any case, once you know it, run:
+
+       dd if=/dev/mem0a count=20 | od -Ax -t x1
+
+  and search the output for your address.  Only the even bytes are
+  defined, so ignore the odd bytes in the dump.  Record the hex offset
+  of the first byte of the address.  Now, edit clients/pcnet_cs.c and
+  find the hw_info structure.  You'll need to create a new entry for
+  your card.  The first field is the memory offset.  The next three
+  fields are the first three bytes of the hardware address.  The final
+  field contains some flags for specific card features; to start, try
+  setting it to 0.
+
+  After editing pcnet_cs.c, compile and install the new module.  Edit
+  /etc/pcmcia/config again, and change the card binding from memory_cs
+  to pcnet_cs.  Follow the instructions for reloading the config file,
+  and you should be all set.  Please send me copies of your new hw_info
+  and config entries.
+
+  If you can't find your card's hardware address in the hex dump, as a
+  method of last resort, it is possible to ``hard-wire'' the address
+  when the pcnet_cs module is initialized.  Edit /etc/pcmcia/config.opts
+  and add a hw_addr= option, like so:
+
+       module "pcnet_cs" opts "hw_addr=0x00,0x80,0xc8,0x01,0x02,0x03"
+
+  Substitute your own card's hardware address in the appropriate spot,
+  of course.  Beware that if you've gotten this far, it is very unlikely
+  that your card is genuinely NE2000 compatible.  In fact, I'm not sure
+  if there are _a_n_y cards that are not handled by one of the first two
+  methods.
+
+  66..33..  PPCCMMCCIIAA ffllooppppyy iinntteerrffaaccee ccaarrddss
+
+  The PCMCIA floppy interface used in the Compaq Aero and a few other
+  laptops is not yet supported by this package.  The snag in supporting
+  the Aero floppy is that the Aero seems to use a customized PCMCIA
+  controller to support DMA to the floppy.  Without knowing exactly how
+  this is done, there isn't any way to implement support under Linux.
+
+  If the floppy adapter card is present when an Aero is booted, the Aero
+  BIOS will configure the card, and Linux will identify it as a normal
+  floppy drive.  When the Linux PCMCIA drivers are loaded, they will
+  notice that the card is already configured and attached to a Linux
+  driver, and this socket will be left alone.  So, the drive can be used
+  if it is present at boot time, but the card is not hot swappable.
+
+  77..  DDeebbuuggggiinngg ttiippss aanndd pprrooggrraammmmiinngg iinnffoorrmmaattiioonn
+
+  77..11..  SSuubbmmiittttiinngg uusseeffuull bbuugg rreeppoorrttss
+
+  The best way to submit bug reports is to use the HyperNews message
+  lists on the Linux PCMCIA information site.  That way, other people
+  can see current problems (and fixes or workarounds, if available).
+  Here are some things that should be included in all bug reports:
+
+  +o  Your system brand and model.
+
+  +o  What PCMCIA card(s) you are using.
+
+  +o  Your Linux kernel version (i.e., ``uname -rv''), and PCMCIA driver
+     version (i.e., ``cardctl -V'').
+
+  +o  Any changes you have made to the startup files in /etc/pcmcia, or
+     to the PCMCIA startup script.
+
+  +o  All PCMCIA-related messages in your system log file.  That includes
+     startup messages, and messages generated when your cards are
+     configured.
+
+  All the PCMCIA modules and the cardmgr daemon send status messages to
+  the system log.  This will usually be something like /var/log/messages
+  or /usr/adm/messages.  This file should be the first place to look
+  when tracking down a problem.  When submitting a bug report, always
+  include the relevant contents of this file.  If you are having trouble
+  finding your system messages, check /etc/syslog.conf to see how
+  different classes of messages are handled.
+
+  Before submitting a bug report, please check to make sure that you are
+  using an up-to-date copy of the driver package.  While it is somewhat
+  gratifying to read bug reports for things I've already fixed, it isn't
+  a particularly constructive use of my time.
+
+  If you do not have web access, bug reports can be sent to me at
+  dhinds@pcmcia.sourceforge.org.  However, I prefer that bug reports be
+  posted to my web site, so that they can be seen by others.
+
+  77..22..  IInntteerrpprreettiinngg kkeerrnneell ttrraapp rreeppoorrttss
+
+  If your problem involves a kernel fault, the register dump from the
+  fault is only useful if you can translate the fault address, EIP, to
+  something meaningful.  Recent versions of klogd attempt to translate
+  fault addresses based on the current kernel symbol map, but this may
+  not work if the fault is in a module, or if the problem is severe
+  enough that klogd cannot finish writing the fault information to the
+  system log.
+
+  If a fault is in the main kernel, the fault address can be looked up
+  in the System.map file.  This may be installed in /System.map or
+  /boot/System.map.  If a fault is in a module, the nm command gives the
+  same information, however, the fault address has to be adjusted based
+  on the module's load address.  Let's say that you have the following
+  kernel fault:
+
+  Unable to handle kernel NULL pointer dereference
+  current->tss.cr3 = 014c9000, %cr3 = 014c9000
+  *pde = 00000000
+  Oops: 0002
+  CPU:    0
+  EIP:    0010:[<c2026081>]
+  EFLAGS: 00010282
+
+  The fault address is 0xc2026081.  Looking at System.map, we see that
+  this is past the end of the kernel, i.e., is in a kernel module.  To
+  determine which module, check the output of ``ksyms -m | sort'':
+
+       Address   Symbol                            Defined by
+       c200d000  (35k)                             [pcmcia_core]
+       c200d10c  register_ss_entry                 [pcmcia_core]
+       c200d230  unregister_ss_entry               [pcmcia_core]
+                 ...
+       c2026000  (9k)                              [3c574_cs]
+       c202a000  (4k)                              [serial_cs]
+
+  So, 0xc2026081 is in the 3c574_cs module, and is at an offset of
+  0x0081 from the start of the module.  We cannot look up this offset in
+  3c574_cs.o yet: when the kernel loads a module, it inserts a header at
+  the module load address, so the real start of the module is offset
+  from the address shown in ksyms.  The size of the header varies with
+  kernel version: to find out the size for your kernel, check a module
+  that exports symbols (like pcmcia_core above), and compare a symbol
+  address with nm output for that symbol.  In this example,
+  register_ss_entry is loaded at an offset of 0xc200d10c - 0xc200d000 =
+  0x010c, while ``nm pcmcia_core.o'' shows the offset as 0x00c0, so the
+  header size is 0x010c - 0x00c0 = 0x004c bytes.
+
+  Back to 3c574_cs, our fault offset is 0x0081, and subtracting the
+  0x004c header, the real module offset is 0x0035.  Now looking at ``nm
+  3c574_cs.o | sort'', we see:
+
+       0000002c d if_names
+       0000002c t tc574_attach
+       00000040 d mii_preamble_required
+       00000041 d dev_info
+
+  So, the fault is located in tc574_attach().
+
+  In this example, the fault did not cause a total system lockup, so
+  ksyms could be executed after the fault happened.  In other cases, you
+  may have to infer the module load addresses indirectly.  The same
+  sequence of events will normally load modules in the same order and at
+  the same addresses.  If a fault happens when a certain card is
+  inserted, get the ksyms output before inserting the card, or with a
+  different card inserted.  You can also manually load the card's driver
+  modules with insmod and run ksyms before inserting the card.
+
+  For more background, see ``man insmod'', ``man ksyms'', and ``man
+  klogd''.  In the kernel source tree, Documentation/oops-tracing.txt is
+  also relevant.  Here are a few more kernel debugging hints:
+
+  +o  Depending on the fault, it may also be useful to translate
+     addresses in the ``Call Trace'', using the same procedure as for
+     the main fault address.
+
+  +o  To diagnose a silent lock-up, try to provoke the problem with X
+     disabled, since kernel messages sent to the text console will not
+     be visible under X.
+
+  +o  If you kill klogd, most kernel messages will be echoed directly on
+     the text console, which may be helpful if the problem prevents
+     klogd from writing to the system log.
+
+  +o  To cause all kernel messages to be sent to the console, for 2.1
+     kernels, if /proc/sys/kernel/printk exists, do:
+
+       echo 8 > /proc/sys/kernel/printk
+
+  +o  The key combination <RightAlt><ScrLk> prints a register dump on the
+     text console.  This may work even if the system is otherwise
+     completely unresponsive, and the EIP address can be interpreted as
+     for a kernel fault.
+
+  +o  For 2.1 kernels configured with CONFIG_MAGIC_SYSRQ enabled, various
+     emergency functions are available via special <Alt><SysRq> key
+     combinations, documented in Documentation/sysrq.txt in the kernel
+     source tree.
+
+  77..33..  LLooww lleevveell PPCCMMCCIIAA ddeebbuuggggiinngg aaiiddss
+
+  The PCMCIA modules contain a lot of conditionally-compiled debugging
+  code.  Most of this code is under control of the PCMCIA_DEBUG
+  preprocessor define.  If this is undefined, debugging code will not be
+  compiled.  If set to 0, the code is compiled but inactive.  Larger
+  numbers specify increasing levels of verbosity.  Each module built
+  with PCMCIA_DEBUG defined will have an integer parameter, pc_debug,
+  that controls the verbosity of its output.  This can be adjusted when
+  the module is loaded, so output can be controlled on a per-module
+  basis without recompiling.
+
+  Your default configuration for syslogd may discard kernel debugging
+  messages.  To ensure that they are recorded, edit /etc/syslog.conf to
+  ensure that ``kern.debug'' messages are recorded somewhere.  See ``man
+  syslog.conf'' for details.
+
+  There are a few register-level debugging tools in the debug_tools/
+  subdirectory of the PCMCIA distribution.  The dump_tcic and dump_i365
+  utilities generate register dumps for ISA-to-PCMCIA controllers.  In
+  3.1.15 and later releases, dump_i365 is replaced by dump_exca, which
+  is similar but also works for PCI-to-CardBus bridges.  Also new in
+  3.1.15 for CardBus bridges is the dump_cardbus tool, which interprets
+  the CardBus-specific registers.  These are all most useful if you have
+  access to a datasheet for the corresponding controller chip.  The
+  dump_cis utility (dump_tuples in pre-3.0.2 distributions) lists the
+  contents of a card's CIS (Card Information Structure), and decodes
+  most of the important bits.  And the dump_cisreg utility displays a
+  card's local configuration registers.
+  The memory_cs memory card driver is also sometimes useful for
+  debugging problems with 16-bit PC Cards.  It can be bound to any card,
+  and does not interfere with other drivers.  It can be used to directly
+  access any card's attribute memory or common memory.  Similarly for
+  CardBus cards, the memory_cb driver can be bound to any 32-bit card,
+  to give direct access to that card's address spaces.  See the man
+  pages for more information.
+
+  77..44..  //pprroocc//bbuuss//ppccccaarrdd
+
+  Starting with 2.1.103 kernels, the PCMCIA package will create a tree
+  of status information under /proc/bus/pccard.  Much of the information
+  can only be interpreted using the data sheets for the PCMCIA host
+  controller.  Its contents may depend on how the drivers were
+  configured, but may include all or some of the following:
+
+     /proc/bus/pccard/{irq,ioport,memory}
+        If present, these files contain resource allocation information
+        to supplement the normal kernel resource tables.  Recent
+        versions of the PCMCIA system may obtain additional resource
+        information from the Plug and Play BIOS if configured to do so.
+
+     /proc/bus/pccard/drivers
+        In recent releases, this lists all currently loaded PCMCIA
+        client drivers.  Unlike /proc/modules, it also lists drivers
+        that may be statically linked into the kernel.
+
+     /proc/bus/pccard/*/info
+        For each socket, describes that socket's host controller and its
+        capabilities.
+
+     /proc/bus/pccard/*/exca
+        This contains a dump of a controller's ``ExCA'' Intel i82365sl-
+        compatible register set.
+
+     /proc/bus/pccard/*/{pci,cardbus}
+        For CardBus bridges, a dump of the bridge's PCI configuration
+        space, and a dump of the bridge's CardBus configuration
+        registers.
+
+  77..55..  WWrriittiinngg CCaarrdd SSeerrvviicceess ddrriivveerrss ffoorr nneeww ccaarrddss
+
+  The Linux PCMCIA Programmer's Guide is the best documentation for the
+  client driver interface.  The latest version is always available from
+  sourceforge.org in /pcmcia/doc, or on the web at
+  <http://pcmcia.sourceforge.org>.
+
+  For devices that are close relatives of normal ISA devices, you will
+  probably be able to use parts of existing Linux drivers.  In some
+  cases, the biggest stumbling block will be modifying an existing
+  driver so that it can handle adding and removing devices after boot
+  time.  Of the current drivers, the memory card driver is the only
+  ``self-contained'' driver that does not depend on other parts of the
+  Linux kernel to do most of the dirty work.
+
+  In many cases, the largest barrier to supporting a new card type is
+  obtaining technical information from the manufacturer.  It may be
+  difficult to figure out who to ask, or to explain exactly what
+  information is needed.  However, with a few exceptions, it is very
+  difficult if not impossible to implement a driver for a card without
+  technical information from the manufacturer.
+
+  I have written a dummy driver with lots of comments that explains a
+  lot of how a driver communicates with Card Services; you will find
+  this in the PCMCIA source distribution in clients/dummy_cs.c.
+
+  77..66..  GGuuiiddeelliinneess ffoorr PPCCMMCCIIAA cclliieenntt ddrriivveerr aauutthhoorrss
+
+  I have decided that it is not really feasible for me to distribute all
+  PCMCIA client drivers as part of the PCMCIA package.  Each new driver
+  makes the main package incrementally harder to maintain, and including
+  a driver inevitably transfers some of the maintenance work from the
+  driver author to me.  Instead, I will decide on a case by case basis
+  whether or not to include contributed drivers, based on user demand as
+  well as maintainability.  For drivers not included in the core
+  package, I suggest that driver authors adopt the following scheme for
+  packaging their drivers for distribution.
+
+  Driver files should be arranged in the same directory scheme used in
+  the PCMCIA source distribution, so that the driver can be unpacked on
+  top of a complete PCMCIA source tree.  A driver should include source
+  files (in ./modules/), a man page (in ./man/), and configuration files
+  (in ./etc/).  The top level directory should also include a README
+  file.
+
+  The top-level directory should include a makefile, set up so that
+  ``make -f ... all'' and ``make -f ... install'' compile the driver and
+  install all appropriate files.  If this makefile is given an extension
+  of .mk, then it will automatically be invoked by the top-level
+  Makefile for the all and install targets.  Here is an example of how
+  such a makefile could be constructed:
+
+       # Sample Makefile for contributed client driver
+       FILES = sample_cs.mk README.sample_cs \
+               modules/sample_cs.c modules/sample_cs.h \
+               etc/sample.conf etc/sample etc/sample.opts \
+               man/sample_cs.4
+       all:
+               $(MAKE) -C modules MODULES=sample_cs.o
+       install:
+               $(MAKE) -C modules install-modules MODULES=sample_cs.o
+               $(MAKE) -C etc install-clients CLIENTS=sample
+               $(MAKE) -C man install-man4 MAN4=sample_cs.4
+       dist:
+               tar czvf sample_cs.tar.gz $(FILES)
+
+  This makefile uses install targets defined in 2.9.10 and later
+  versions of the PCMCIA package.  This makefile also includes a
+  ``dist'' target for the convenience of the driver author.  You would
+  probably want to add a version number to the final package filename
+  (for example, sample_cs-1.5.tar.gz).  A complete distribution could
+  look like:
+
+  sample_cs.mk
+  README.sample_cs
+  modules/sample_cs.c
+  modules/sample_cs.h
+  etc/sample.conf
+  etc/sample
+  etc/sample.opts
+  man/sample_cs.4
+
+  With this arrangement, when the contributed driver is unpacked, it
+  becomes essentially part of the PCMCIA source tree.  It can make use
+  of the PCMCIA header files, as well as the machinery for checking the
+  user's system configuration, and automatic dependency checking, just
+  like a ``normal'' client driver.
+
+  In this example, etc/sample and etc/sample.opts would be the new
+  driver's configuration scripts (if needed), and etc/sample.conf would
+  contain any additions to the PCMCIA card configuration file.  Starting
+  with the 3.1.6 release, cardmgr will automatically process any *.conf
+  files installed in /etc/pcmcia, so installation of contributed drivers
+  should no longer require hand editing configuration files.
+
+  I will accept client drivers prepared according to this specification
+  and place them in the /pcmcia/contrib directory on sourceforge.org.
+  The README in this directory will describe how to unpack a contributed
+  driver.
+
+  The client driver interface has not changed much over time, and has
+  almost always preserved backwards compatibility.  A client driver will
+  not normally need to be updated for minor revisions in the main
+  package.  I will try to notify authors of contributed drivers of
+  changes that require updates to their drivers.
+
+  77..77..  GGuuiiddeelliinneess ffoorr LLiinnuuxx ddiissttrriibbuuttiioonn mmaaiinnttaaiinneerrss
+
+  If your distribution has system configuration tools that you would
+  like to be PCMCIA-aware, please use the *.opts files in /etc/pcmcia
+  for your ``hooks.''  These files will not be modified if a user
+  compiles and installs a new release of the PCMCIA package.  If you
+  modify the main configuration scripts, then a fresh install will
+  silently overwrite your custom scripts and break the connection with
+  your configuration tools.  Contact me if you are not sure how to write
+  an appropriate option script, or if you need additional capabilities.
+
+  It is helpful for users (and for me) if you can document how your
+  distribution deviates from the PCMCIA package as described in this
+  document.  In particular, please document changes to the startup
+  script and configuration scripts.  If you send me the appropriate
+  information, I will include it in the ``Notes about specific Linux
+  distributions''.
+
+  When building PCMCIA for distribution, consider including contributed
+  drivers that are not part of the main PCMCIA package.  For reasons of
+  maintainability, I am trying to limit the core package size, by only
+  adding new drivers if I think they are of particularly broad interest.
+  Other drivers will be distributed separately, as described in the
+  previous section.  The split between integral and separate drivers is
+  somewhat arbitrary and partly historical, and should not imply a
+  difference in quality.
+
Index: oldkernel/linux/pcmcia-cs-3.1.15/doc/PCMCIA-HOWTO.ps
diff -u /dev/null linux/pcmcia-cs-3.1.15/doc/PCMCIA-HOWTO.ps:1.1
--- /dev/null	Mon Jul 31 21:15:11 2000
+++ linux/pcmcia-cs-3.1.15/doc/PCMCIA-HOWTO.ps	Fri Jul  7 16:34:58 2000
@@ -0,0 +1,5255 @@
+%!PS-Adobe-2.0
+%%Creator: dvips(k) 5.85 Copyright 1999 Radical Eye Software
+%%Title: PCMCIA-HOWTO.dvi
+%%Pages: 50
+%%PageOrder: Ascend
+%%BoundingBox: 0 0 612 792
+%%EndComments
+%DVIPSWebPage: (www.radicaleye.com)
+%DVIPSCommandLine: dvips -t letter PCMCIA-HOWTO.dvi -o PCMCIA-HOWTO.ps
+%DVIPSParameters: dpi=600, compressed
+%DVIPSSource:  TeX output 2000.04.04:1604
+%%BeginProcSet: texc.pro
+%!
+/TeXDict 300 dict def TeXDict begin/N{def}def/B{bind def}N/S{exch}N/X{S
+N}B/A{dup}B/TR{translate}N/isls false N/vsize 11 72 mul N/hsize 8.5 72
+mul N/landplus90{false}def/@rigin{isls{[0 landplus90{1 -1}{-1 1}ifelse 0
+0 0]concat}if 72 Resolution div 72 VResolution div neg scale isls{
+landplus90{VResolution 72 div vsize mul 0 exch}{Resolution -72 div hsize
+mul 0}ifelse TR}if Resolution VResolution vsize -72 div 1 add mul TR[
+matrix currentmatrix{A A round sub abs 0.00001 lt{round}if}forall round
+exch round exch]setmatrix}N/@landscape{/isls true N}B/@manualfeed{
+statusdict/manualfeed true put}B/@copies{/#copies X}B/FMat[1 0 0 -1 0 0]
+N/FBB[0 0 0 0]N/nn 0 N/IEn 0 N/ctr 0 N/df-tail{/nn 8 dict N nn begin
+/FontType 3 N/FontMatrix fntrx N/FontBBox FBB N string/base X array
+/BitMaps X/BuildChar{CharBuilder}N/Encoding IEn N end A{/foo setfont}2
+array copy cvx N load 0 nn put/ctr 0 N[}B/sf 0 N/df{/sf 1 N/fntrx FMat N
+df-tail}B/dfs{div/sf X/fntrx[sf 0 0 sf neg 0 0]N df-tail}B/E{pop nn A
+definefont setfont}B/Cw{Cd A length 5 sub get}B/Ch{Cd A length 4 sub get
+}B/Cx{128 Cd A length 3 sub get sub}B/Cy{Cd A length 2 sub get 127 sub}
+B/Cdx{Cd A length 1 sub get}B/Ci{Cd A type/stringtype ne{ctr get/ctr ctr
+1 add N}if}B/id 0 N/rw 0 N/rc 0 N/gp 0 N/cp 0 N/G 0 N/CharBuilder{save 3
+1 roll S A/base get 2 index get S/BitMaps get S get/Cd X pop/ctr 0 N Cdx
+0 Cx Cy Ch sub Cx Cw add Cy setcachedevice Cw Ch true[1 0 0 -1 -.1 Cx
+sub Cy .1 sub]/id Ci N/rw Cw 7 add 8 idiv string N/rc 0 N/gp 0 N/cp 0 N{
+rc 0 ne{rc 1 sub/rc X rw}{G}ifelse}imagemask restore}B/G{{id gp get/gp
+gp 1 add N A 18 mod S 18 idiv pl S get exec}loop}B/adv{cp add/cp X}B
+/chg{rw cp id gp 4 index getinterval putinterval A gp add/gp X adv}B/nd{
+/cp 0 N rw exit}B/lsh{rw cp 2 copy get A 0 eq{pop 1}{A 255 eq{pop 254}{
+A A add 255 and S 1 and or}ifelse}ifelse put 1 adv}B/rsh{rw cp 2 copy
+get A 0 eq{pop 128}{A 255 eq{pop 127}{A 2 idiv S 128 and or}ifelse}
+ifelse put 1 adv}B/clr{rw cp 2 index string putinterval adv}B/set{rw cp
+fillstr 0 4 index getinterval putinterval adv}B/fillstr 18 string 0 1 17
+{2 copy 255 put pop}for N/pl[{adv 1 chg}{adv 1 chg nd}{1 add chg}{1 add
+chg nd}{adv lsh}{adv lsh nd}{adv rsh}{adv rsh nd}{1 add adv}{/rc X nd}{
+1 add set}{1 add clr}{adv 2 chg}{adv 2 chg nd}{pop nd}]A{bind pop}
+forall N/D{/cc X A type/stringtype ne{]}if nn/base get cc ctr put nn
+/BitMaps get S ctr S sf 1 ne{A A length 1 sub A 2 index S get sf div put
+}if put/ctr ctr 1 add N}B/I{cc 1 add D}B/bop{userdict/bop-hook known{
+bop-hook}if/SI save N @rigin 0 0 moveto/V matrix currentmatrix A 1 get A
+mul exch 0 get A mul add .99 lt{/QV}{/RV}ifelse load def pop pop}N/eop{
+SI restore userdict/eop-hook known{eop-hook}if showpage}N/@start{
+userdict/start-hook known{start-hook}if pop/VResolution X/Resolution X
+1000 div/DVImag X/IEn 256 array N 2 string 0 1 255{IEn S A 360 add 36 4
+index cvrs cvn put}for pop 65781.76 div/vsize X 65781.76 div/hsize X}N
+/p{show}N/RMat[1 0 0 -1 0 0]N/BDot 260 string N/Rx 0 N/Ry 0 N/V{}B/RV/v{
+/Ry X/Rx X V}B statusdict begin/product where{pop false[(Display)(NeXT)
+(LaserWriter 16/600)]{A length product length le{A length product exch 0
+exch getinterval eq{pop true exit}if}{pop}ifelse}forall}{false}ifelse
+end{{gsave TR -.1 .1 TR 1 1 scale Rx Ry false RMat{BDot}imagemask
+grestore}}{{gsave TR -.1 .1 TR Rx Ry scale 1 1 false RMat{BDot}
+imagemask grestore}}ifelse B/QV{gsave newpath transform round exch round
+exch itransform moveto Rx 0 rlineto 0 Ry neg rlineto Rx neg 0 rlineto
+fill grestore}B/a{moveto}B/delta 0 N/tail{A/delta X 0 rmoveto}B/M{S p
+delta add tail}B/b{S p tail}B/c{-4 M}B/d{-3 M}B/e{-2 M}B/f{-1 M}B/g{0 M}
+B/h{1 M}B/i{2 M}B/j{3 M}B/k{4 M}B/w{0 rmoveto}B/l{p -4 w}B/m{p -3 w}B/n{
+p -2 w}B/o{p -1 w}B/q{p 1 w}B/r{p 2 w}B/s{p 3 w}B/t{p 4 w}B/x{0 S
+rmoveto}B/y{3 2 roll p a}B/bos{/SS save N}B/eos{SS restore}B end
+
+%%EndProcSet
+TeXDict begin 40258431 52099146 1000 600 600 (PCMCIA-HOWTO.dvi)
+@start
+%DVIPSBitmapFont: Fa ecti1000 10 3
+/Fa 3 122 df<14F8EB07FE90381F871C90383E03FE137CEBF801120148486C5A485A12
+0FEBC001001F5CA2EA3F801403007F5C1300A21407485C5AA2140F5D48ECC1C0A2141F15
+831680143F1587007C017F1300ECFF076C485B9038038F8E391F0F079E3907FE03FC3901
+F000F0222677A42A>97 D<D801E013FE3A07F803FF803A0E3C0F07C03A1E3E3C03E0261C
+1F787F39383FF00114E0007813C000708114804A485AEAF07FEAE07EA20000140701FE5C
+5BA2150F00015D5B151F5E12034990383F8380160316070007027F130049137EA2160E00
+0F147C49141E161C5E001FEC3C7849EB1FE00007C7EA0780292679A42F>110
+D<13F0D803FCEB01C0D8071EEB03E0D80E1F1307121C123C0038140F4914C01270A24913
+1FD8F07E148012E013FEC648133F160012015B5D0003147E5BA215FE00075C5BA214015D
+A314035D14070003130FEBF01F3901F87FE038007FF7EB1FC7EB000F5DA2141F003F5C48
+133F92C7FC147E147C007E13FC387001F8EB03E06C485A383C1F80D80FFEC8FCEA03F023
+3679A428>121 D E
+%EndDVIPSBitmapFont
+%DVIPSBitmapFont: Fb cmmi10 10 2
+/Fb 2 63 df<EF0380EF0FC0173FEFFF80933803FE00EE0FF8EE3FE0EEFF80DB03FEC7FC
+ED0FF8ED3FE0EDFF80DA03FEC8FCEC0FF8EC3FE0ECFF80D903FEC9FCEB0FF8EB3FE0EBFF
+80D803FECAFCEA0FF8EA3FE0EA7F8000FECBFCA2EA7F80EA3FE0EA0FF8EA03FEC66C7EEB
+3FE0EB0FF8EB03FE903800FF80EC3FE0EC0FF8EC03FE913800FF80ED3FE0ED0FF8ED03FE
+923800FF80EE3FE0EE0FF8EE03FE933800FF80EF3FC0170FEF0380323279AD41>60
+D<126012FCB4FCEA7FC0EA1FF0EA07FCEA01FF38007FC0EB1FF0EB07FCEB01FF9038007F
+C0EC1FF0EC07FCEC01FF9138007FC0ED1FF0ED07FCED01FF9238007FC0EE1FF0EE07FCEE
+01FF9338007F80EF1FC0A2EF7F80933801FF00EE07FCEE1FF0EE7FC04B48C7FCED07FCED
+1FF0ED7FC04A48C8FCEC07FCEC1FF0EC7FC04948C9FCEB07FCEB1FF0EB7FC04848CAFCEA
+07FCEA3FF0EA7FC048CBFC12FC1270323279AD41>62 D E
+%EndDVIPSBitmapFont
+%DVIPSBitmapFont: Fc ectt0900 9 86
+/Fc 86 126 df<00101320007C13F838FE01FCAAEAFC00007C13F8A900381370161778AE
+27>34 D<90381C01C090383E03E0A7EB7E07017C13C0A3007FB512FEB7FCA36C14FE3900
+F80F80A50001131F01F01300A6007FB512FEB7FCA36C14FE3903E03E00A30007137EEBC0
+7CA738038038202E7DAD27>I<EB0380497EA5EB1FF0EBFFFE0003EBFF804814C0001F14
+E09038E7DFF0393F87C7F8387E07C3007C13C100FCEBC0FC12F814C1A300FCEBC0F800FE
+1470007F14001387EA3FFF7E6C13F86C13FE6CEBFF80C614C0010F13E06D13F014CFECC3
+F814C10038EBC0FC127C00FE147CA412FC00FE14F8007E13C1007FEBC3F0383F87C79038
+F7FFE06CB512C06C1480000314006C13FC38003FE0EB07C0A56D5A1E3A7CB327>I<000F
+1470486C13F8383FC001EA7FE0140315F038FFF00700F914E0A2140F15C0A2141F00FF14
+80387FE03F1500A26C485A381F807E380F00FEC75AA213015CA213035C13075CA2130F5C
+131F5CA2133F91C7FCA24913F090387E01F89038FE03FC9038FC07FEA212019038F80FFF
+0003149F13F0A2120713E0A2000F14FF9038C007FE121F1380EC03FC000FEB01F86CC712
+F0203A7DB327>I<120FEA3FC013E0EA7FF0A213F8A2123FA2120F1200A2120113F0A212
+0313E01207EA0FC0123FEA7F80EAFF005A12F812700D1973AD27>39
+D<EB01C0EB03E0130F131FEB3FC0EB7F80EBFE00485A5B1203485A5B485AA2485AA248C7
+FCA3127EA45AAC127EA47EA36C7EA26C7EA26C7E7F6C7E12017F6C7EEB7F80EB3FC0EB1F
+E0130F1303EB01C0133A73B327>I<127012F812FE7E6C7E6C7EEA0FE06C7E12037F6C7E
+1200137EA27FA2EB1F80A3EB0FC0A4EB07E0ACEB0FC0A4EB1F80A3EB3F00A2137EA25B12
+01485A5B1207485AEA3FC0485A48C7FC5A12F81270133A7AB327>I<130F497EA60078EB
+81E000FEEB87F000FF138FEBDFBF6CB512E06C14C0000F1400000313FCC613F0A2000313
+FC000F13FF003F14C04814E039FFDFBFF0EB1F8F00FE13870078EB81E00000EB8000A66D
+C7FC1C207BA627>I<120FEA3FC013E0EA7FF0A213F8A2123FA2120F120113F01203EA07
+E0121FEA7FC0EAFF8013005A12700D14738927>44 D<007FB51280B612C0A36C14801A05
+7A9227>I<121EEA7F80A2EAFFC0A4EA7F80A2EA1E000A0A728927>I<1538157CA215FC15
+F8140115F0140315E0140715C0A2140F1580141F15005C143E147E147C14FC5C13015C13
+035C13075C130F5CA2131F91C7FC5B133E137E137C13FC5B12015B12035B12075B120F5B
+A2121F90C8FC5A123E127E127C12FC5AA212701E3A7CB327>I<EB07E0EB3FFC497E90B5
+FC4814803903FC3FC03907F00FE0390FE007F0EBC003391F8001F8A248C712FCA2003E14
+7C007E147EA3007C143E00FC143FAC007E147EA46C14FCA2EB8001001F14F8EBC003000F
+14F0EBE0073907F00FE03903FC3FC06CB512806C14006D5A6D5AEB07E020307DAE27>I<
+130E131FA25B5BA25B5A5A127FB5FCA213BFEA7E3F1200B3AA003FB512805A15C01580A2
+1A2F79AE27>I<EB3FE03801FFF84813FE000FEBFF804814C0393FE07FE0EB800F397F00
+07F0007EEB03F800FE13015A6C14FC1400A3127CC8FCA2140115F8A2140315F01407EC0F
+E0EC1FC0143FEC7F80ECFF00495A495A495A495A495A495A495A01FEC7FC485AD807F813
+78484813FC485A485A48B5FCB6FCA36C14F81E2F7CAE27>I<EB1FF8EBFFFE0003EBFF80
+000F14C015E0391FF01FF0393FC007F8EB800115FC1400A26CC7FC1204C8FC140115F814
+03EC07F0140FEC3FE090381FFFC0491380A215E06D13F09038001FF8EC03FC1401EC00FE
+157E157F153FA21238127C12FEA2157F48147E6C14FE007FEB01FCEB8003393FF01FF86C
+B512F06C14E000031480C6EBFE00EB1FF820307DAE27>I<EC3F804A7EA214FF5BA2EB03
+F7EB07E7A2EB0FC71487131FEB3F07A2137E13FCA2EA01F813F01203EA07E0A2EA0FC0EA
+1F80A2EA3F00123E127E5AB7128016C0A36C1580C73807C000A849B5FC491480A36D1400
+222F7EAE27>I<001FB512E04814F0A315E090C8FCACEB1FF0EBFFFC14FF158015C09038
+F03FE09038C00FF0EB0007003EEB03F8001C1301C7FC15FC1400A3127C12FEA2140115F8
+4813036C14F0007F130F9038801FE0393FE07FC06CB512806C14006C5B000113F838007F
+C01E2F7CAD27>I<14FF010713C0011F13F04913F890B5FC48EB81FC3803FE0113F8EA07
+F0EA0FE09038C000F8001F1400485A90C8FCA25A127EEB0FF838FE3FFE48B51280B612C0
+15E09038F80FF09038E007F890388001FC90C7FC15FE48147E157F153FA3127EA3127F6C
+147F157E6C6C13FE9038C001FC120F9038F007F83907F81FF06CB512E06C14C06C148090
+383FFE00EB0FF820307DAE27>I<1278B612FE15FFA315FE39FC0001FCEC03F8EC07F000
+7814E0C7120FEC1FC01580143FEC7F00147E14FE5C13015C13035C13075CA2495AA3495A
+A3133F91C7FCA55B137EA9133C20307DAE27>I<EB0FF0EB7FFE48B512804814C0000F14
+F0EBF81F391FE007F8393F8001FC90C7FC4814FE007E147EA56C14FCEB8001391FC003F8
+390FE007F03907FC3FE00001B5128039007FFE006D5A90B5FC000314C0390FF00FF0391F
+C003F8393F8001FC90C7FC007E147EA248143FA6007E147EA2007F14FE393F8001FC391F
+E007F8EBF81F6CB512F06C14E00001148039007FFE00EB0FF020307DAE27>I<EB0FF0EB
+7FFC48B5FC4814804814C0390FF81FE0391FE007F0393FC003F8EB8001D87F0013FC007E
+130012FE48147EA4157FA37E127E007F14FF7E6D5A381FE007380FF01F6CB6FC7E6C143F
+39007FFC7F90381FF07E90C7FCA215FCA2140115F8001F1303393F8007F0EC0FE0141FEC
+3FC09038C0FF806CB512005C6C13F8000313E0C6138020307DAE27>I<121EEA7F80A2EA
+FFC0A4EA7F80A2EA1E00C7FCAC121EEA7F80A2EAFFC0A4EA7F80A2EA1E000A20729F27>
+I<120FEA3FC0A2EA7FE0A4EA3FC0A2EA0F00C7FCAC120FEA3FC013E0EA7FF0A213F8A212
+3FA2120F120113F01203EA07E0121FEA7FC0EAFF8013005A12700D2A739F27>I<153815
+FC14011407EC0FF8EC3FE0EC7FC0903801FF00495AEB0FF8495AEB7FC0495AD803FEC7FC
+485AEA1FF0485AEAFF8090C8FCA27FEA3FE06C7EEA07FC6C7EC66C7E6D7EEB1FF06D7EEB
+03FE6D7E9038007FC0EC3FE0EC0FF8EC07FC1401140015381E267CA927>I<003FB512FC
+B7FCA4C9FCA8B7FCA4003F14FC20127D9F27>I<127012FC7E6C7E6C7EEA1FF06C7EEA03
+FE6C7E38007FC06D7EEB0FF86D7EEB01FF6D1380EC3FE0EC1FF0EC07FC1403A21407EC1F
+F0EC3FE0ECFF80491300EB07FC495AEB3FE0495A4848C7FC485AEA0FF8485AEA7FC0485A
+48C8FC5A12701E267CA927>I<EB03F0497EA2497EA4143CEB1F3EA5EB3F3FA3EB3E1FA2
+017E7FA4496C7EA548486C7EA390B5FCA24880A3EBF003A248486C7EA4000F803A7FFC0F
+FF8000FF15C06D5A497E007F1580222F7EAE27>65 D<007FB5FCB612C08115F87E3907E0
+03FCEC00FE157E157F81A6157EA25D1403EC0FF890B55A15C015F081819038E000FE157F
+ED3F80151FA2ED0FC0A6151F1680153FED7F004A5A007FB55AB65A5D15E06C1480222E7F
+AD27>I<903803F80E90381FFE1F90383FFFBF90B6FC5A3803FE0F3807F803497E48487E
+485A49137FA248C7123FA25A127E151E150012FE5AAA7E127EA2151E007F143F7EA26C7E
+157F6D137E6C6C13FE3907F001FCEBF8033903FE0FF86CB512F06C14E0013F13C06D1300
+EB03F820307DAE27>I<387FFFFC14FFB612C06C80813907E00FF81407EC01FC6E7EA215
+7E157F811680151FA316C0150FABED1F80A3153F1600A25D15FEA24A5A4A5A140F007FB5
+5A5DB65A6C91C7FC14FC222E7FAD27>I<007FB61280B712C0A37E3907E0000FA6ED0780
+92C7FCA4EC07804A7EA390B5FCA5EBE00FA36E5A91C8FCA4ED03C0ED07E0A7007FB6FCB7
+FCA36C15C0232E7FAD27>I<007FB61280B712C0A37E3907E0000FA6ED078092C7FCA4EC
+07804A7EA390B5FCA5EBE00FA36E5A91C8FCAC387FFF80B57EA36C5B222E7EAD27>I<90
+3807F03890381FFC7C90387FFFFC90B5FC5A3803FC1F3807F00F380FE007EBC003001F13
+011380123F90C7FCA2127EA2157892C7FC5AA8EC1FFF4A1380A3007E6D1300EC00FCA36C
+1301A21380121FEBC003120FEBE0073807F00F3803FC1F6CB5FC7EEB7FFE90381FFC78D9
+07F0C7FC21307DAE27>I<3A7FFE07FFE0B54813F0A36C486C13E03A07E0007E00AF90B5
+12FEA59038E0007EB03A7FFE07FFE0B54813F0A36C486C13E0242E7FAD27>I<007FB512
+E0B612F0A36C14E039001F8000B3B2007FB512E0B612F0A36C14E01C2E7BAD27>I<9038
+1FFFF84913FCA36D13F89038001F80B3AC127CA212FEA2EC3F005C387F81FE13FF6C5B6C
+5B000713E0C690C7FC1E2F7BAD27>I<3A7FFC07FF8016C0486C5A6C487E16803A07C001
+F80014035D4A5A4A5A141F5D4AC7FC147E14FE5CEBC1F8EBC3F013C75CEBCFF0EBDFF813
+FF8013FEEBFC7E143EEBF83F497E01E07F140F01C07F1407811403816E7EA26E7E157C15
+7E3A7FFC01FFC016E0486C5A6C487E16C0232E7FAD27>I<387FFFC080B5FC7E5CD803F0
+C8FCB3AAED0780ED0FC0A7007FB6FCA2B7FC7E1680222E7FAD27>I<D87FE0EB7FE0486C
+EBFFF0A26D5A007F15E0000F150001B813DFEBBC03A3EBBE07019E139FA3EB9F0FA2018F
+131FA2149FA2EB879EA4EB839C14FCA3EB81F8A2EB80F01400AAD87FF0EBFFE0486C4813
+F0A36C486C13E0242E7FAD27>I<3A7FF003FFE0486C4813F0A213FC007F6D13E0000790
+38003E0013DEA313CFA3148013C714C0A213C314E0A213C114F0A3EBC0F8A31478147CA2
+143C143EA2141E141F140FA3EC07BEA3EC03FEEA7FFCEAFFFE1401A26C486C5A242E7FAD
+27>I<EBFFFC0007EBFF80001F14E0A24814F0EBC00F397F8007F8EB0003007E1301A348
+EB00FCB3A76C1301007E14F8A3007F1303EB8007393FE01FF090B5FC6C14E0A200071480
+C6EBFC001E307CAE27>I<007FB5FCB612E081816C803907E003FEEC00FF81ED3F80151F
+16C0150FA6151F1680153FED7F005DEC03FE90B55A5D5D5D92C7FC01E0C8FCADEA7FFEB5
+FCA36C5A222E7FAD27>I<EBFFFC0007EBFF80001F14E0A24814F0EBE01F397F8007F8EB
+0003007E1301A300FE14FC481300B3A4EB07E0A200FE13F1007E14F8EB03F9A2387F01FF
+1381D83FE013F090B5FC6C14E0A200071480C6FC9038001FC0A2EC0FE0A2EC07F0A2EC03
+F8A2EC01F01E397CAE27>I<387FFFF0B512FE6E7E816C803907E01FF014076E7E140181
+1400A514015D14034A5A141F90B55A5D5DA281EBE01F6E7E14076E7EA816F0EDF1F8A439
+7FFE01FBB5EBFFF08016E06C48EB7FC0C8EA1F00252F7FAD27>I<90387FC0E03901FFF1
+F0000713FF5A5AEA3FE0EB801F387F000F007E130712FE5A1403A3EC01E06C90C7FC127E
+127FEA3FC013F86CB47E6C13F86C13FE6CEBFF80C614C0010F13E0010013F0140FEC07F8
+1403140115FC1400127812FCA46CEB01F8A26C130390388007F09038F01FE090B5FC15C0
+150000F85B38701FF81E307CAE27>I<007FB61280B712C0A439FC03F00FA60078EC0780
+000091C7FCB3AB90B512C04880A36C5C222E7EAD27>I<3A7FFE01FFF8B54813FCA36C48
+6C13F83A07E0001F80B3AB6D133F00031500A26D5B0001147E6D13FE6C6C485A90387F87
+F814FF6D5B010F13C06D5BD901FEC7FC262F80AD27>I<3A7FFC03FFE06D5A00FF15F000
+7F15E0497E3A07E0007E00A46C6C5BA4EBF80100015CA46C6C485AA490387E07E0A56D48
+5AA4011F5B149FA3010F90C7FCA5EB07FEA46D5AA26D5A242F7FAD27>I<D87FE0EB7FE0
+486CEBFFF0A36C48EB7FE0001FC7EA0F80A76C6CEB1F00A614F0EB81F83907C3FC3EA414
+9CEBC79EA30003143CA301E7137CEBEF9FA2140FA200011478A49038FE07F8A300005CA2
+EBFC0390387801E0242F7FAD27>I<393FFC1FFE387FFE3F815D383FFC1F3903F00FE001
+F85B1201EBFC1F00005CEBFE3F017E90C7FCEB7F7FEB3F7E14FE6D5AA26D5AA26D5AA213
+03130780130F80131F80EB3F7E147F497E017E7F141F01FC7F140FD801F87F1407120349
+6C7E120701E07F3A7FFC0FFF8000FF15C06D5A497E007F1580222E7EAD27>I<3A7FFC03
+FFE06D5A00FF15F0007F15E0497E3A07F000FE0000035CEBF80100015CA2EBFC0300005C
+EBFE07017E5BA26D485AA290381F9F80A3010F90C7FCA2EB07FEA26D5AA26D5AAF90381F
+FF80497FA36D5B242E7FAD27>I<003FB512FE4814FFA4007EC712FEEC01FCA2EC03F8EC
+07F0A2003CEB0FE0C7EA1FC0A2EC3F80EC7F00A214FE5C1301495A5C1307495A5C131F49
+5A91C7FC5B13FEA2485A4848131E153F485A485AA2485A485AA248C7FCB7FCA46C14FE20
+2E7DAD27>I<387FFFF0B512F8A314F000FCC7FCB3B3ACB512F014F8A36C13F0153A71B3
+27>I<127012F8A27E127C127E123E123F7E7F120FA27F12077F12037F12017F12007F13
+7C137E133E133F7F80130FA280130780130380130180130080147C147E143E143F801580
+140F15C01407A215E0140315F0140115F8140015FC157CA215381E3A7CB327>I<387FFF
+F0B512F8A37EEA0001B3B3ACEA7FFFB5FCA36C13F0153A7EB327>I<007FB512F8B612FC
+A46C14F81E067C7E27>95 D<137013F812031207EA0FF0EA1FE01380EA3F00123E127E12
+7CA212FC5AA2EAFF8013E0A213F0A2127FA2EA3FE0121FEA07800D1974B227>I<3801FF
+E0000713F84813FE486D7E81EBC07FEC0FE0380F8007D802007FC71203A2EB07FF137F00
+03B5FC120F5A383FFC03EA7FE0130012FE5AA46C1307007F130FEBC07F6CB612C06C15E0
+7E000313F83A007FC03FC023207D9F27>I<EA7FE0487EA3127F1203A9EC7F809038F1FF
+E001F713F890B57E81ECC0FF9138007F8001FCEB1FC049130F16E0491307A216F01503A6
+15076D14E0A2150F6DEB1FC06D133F6DEB7F809138C1FF00ECFFFE5D01F75B01F313E026
+01E07FC7FC242E80AD27>I<EB0FFF017F13C048B512E04814F05A380FF807EA1FE0393F
+C003E0903880008048C8FC127EA212FE5AA67E127EA2007F14F0393F8001F813C0381FE0
+03390FF80FF06CB5FC6C14E06C14C06C6C1300EB0FF81D207B9F27>I<EC1FF84A7EA314
+1F1400A9EB0FF0EB7FFC48B5FC5A5A380FF81F381FE007383FC003EB8001EA7F00007E13
+00A212FE5AA67E007E1301A2007F13037EEB8007381FE00F380FF03F6CB612E06C15F06C
+5B38007FF890391FE07FE0242E7EAD27>I<EB0FF8EB3FFE90B51280000314C04814E039
+0FFC0FF0391FE003F8EBC001D83F8013FC48C7FC127E157E12FEB612FEA415FC00FCC8FC
+7E127E127F6C143C6D137E6C7E01F013FE390FFC07FC6CB5FC000114F86C14F0013F13C0
+903807FE001F207D9F27>I<EC1FF0ECFFF84913FC4913FE5BEB0FF014C0011F137CEC80
+00A6007FB512F0B612F8A36C14F039001F8000B3A4003FB512C04814E0A36C14C01F2E7E
+AD27>I<153F90391FC0FF80D97FF313C048B612E05A4814EF390FF07F873A1FC01FC3C0
+EDC000EB800F48486C7EA66C6C485AEBC01FA2390FF07F8090B5C7FC5C485BEB7FF0EB1F
+C090C9FCA27F6CB5FC15E015F84814FE4880EB8001007EC7EA3F80007C140F00FC15C048
+1407A46C140F007C1580007F143F6C6CEB7F009038F807FF6CB55A000714F86C5CC614C0
+D90FFCC7FC23337EA027>I<EA7FE0487EA3127F1203A9EC3FC09038F1FFF001F77F90B5
+7E8114E0EC007F497F5B5BA25BB03A7FFF83FFF8B500C713FCA36C018313F8262E80AD27
+>I<130F497E497EA46D5A6DC7FC90C8FCA7383FFF80487FA37EEA000FB3A4007FB512F0
+B6FC15F815F07E1D2F7BAE27>I<EA7FE07F12FF127FA21201A991383FFFC04A13E0A36E
+13C0913803F8004A5A4A5A4A5A4A5A02FFC7FCEBF1FEEBF3FCEBF7F8EBFFFC8080143F49
+6C7E496C7E01F87FEBF0076E7E6E7E816E7E157E3A7FFFC1FFF002C313F8B512E36C13C3
+16F0252E80AD27>107 D<387FFF80B57EA37EEA000FB3B2007FB512F8B612FCA36C14F8
+1E2E7CAD27>I<397F07C01F3AFF9FF07FC09039FFF9FFE091B57E7E3A0FFC7FF1F89038
+F03FC001E0138001C01300A3EB803EB03A7FF0FFC3FF486C01E3138001F913E701F813E3
+6C4801C313002920819F27>I<397FE03FC039FFF1FFF001F77F90B57E6C80000313E0EC
+007F497F5B5BA25BB03A7FFF83FFF8B500C713FCA36C018313F82620809F27>I<EB1FE0
+EB7FF83801FFFE487F481480390FF03FC0391FC00FE0393F8007F0EB00034814F8007E13
+01A248EB00FCA76C1301007E14F8A2007F1303393F8007F0A2391FE01FE0390FF03FC06C
+B512806C14006C5B38007FF8EB1FE01E207C9F27>I<397FE07F8039FFF1FFE001F713F8
+90B57E6C800003EBC0FF9138007F8001FCEB1FC049130F16E0491307A216F01503A61507
+6D14E0A2150F6DEB1FC06D133F6DEB7F809138C1FF00ECFFFE5D01F75B01F313E0D9F07F
+C7FC91C8FCAC387FFF80B57EA36C5B2431809F27>I<90380FF03C90383FFE7E90B5FC00
+0314FE5A380FFC1F381FE007EBC003383F800148C7FC127EA200FE147E5AA67E007E14FE
+A2007F1301EA3F80EBC003381FE007380FF81F6CB5FC7E6C147E38007FFCEB0FF090C7FC
+AC91381FFFF8A24A13FC6E13F8A226317E9F27>I<397FFC03FC39FFFE0FFF023F13804A
+13C0007F90B5FC39007FFE1F14F89138F00F809138E002004AC7FC5CA291C8FCA2137EAD
+007FB57EB67EA36C5C22207E9F27>I<9038FFF3800007EBFFC0121F5A5AEB803F38FC00
+0F5AA2EC07806C90C7FCEA7F8013FC383FFFF06C13FC000713FF00011480D8000F13C090
+38003FE014070078EB03F000FC1301A27E14036CEB07E0EBE01F90B512C01580150000FB
+13FC38707FF01C207B9F27>I<133C137EA8007FB512F0B612F8A36C14F0D8007EC7FCAE
+1518157EA415FE6D13FC1483ECFFF86D13F06D13E0010313C0010013001F297EA827>I<
+397FE007FE486C487EA3007F7F0003EB003FB25DA24A5AEBFC076CB612F86C15FCA2013F
+13BF90390FFC1FF82620809F27>I<3A7FFC0FFF80486C4813C0A36C486C13803A07C000
+F800EBE00100035CA2EBF00300015CA2EBF80700005CA390387C0F80A36D48C7FCA3EB3F
+3FEB1F3EA214FE6D5AA36D5AA26D5A22207E9F27>I<3A7FFE07FFE000FF15F06D5A497E
+007F15E03A0F80001F00A36D5B0007143EA414F0EBC1F83903E3FC7CA4EBE79EA2000114
+78A301F713F8A2EBFF0F6C5CA3EBFE0790387C03E024207F9F27>I<393FFC1FFF486C5A
+168016006C487E3901F807E06C6C485A4A5A017E90C7FC6D5AEB1F7E5C6D5A13076D5A5C
+80497E130F497E143EEB3E3FEB7E1F90387C0F8001F87F00016D7E3803F0033A7FFE1FFF
+80A2B54813C06C486C1380A222207E9F27>I<3A7FFC0FFF80486C4813C0A36C486C1380
+3A07E000F800000313015D13F00001130301F85B1200A26D485A137CA290387E0F80133E
+A2011F90C7FC5CA2130F149E14BE130714FC1303A25C1301A25CA213035CA213075C1208
+EA3E0F007F5B131FD87E7FC8FCEA7FFE6C5A5B6C5AEA07C022317E9F27>I<001FB512FE
+4814FFA490380001FEEC03FCEC07F8EC0FF0001EEB1FE0C7EA3FC0EC7F80ECFF00495A49
+5A495AEB1FE0495A495A49C7FC485A4848131E4848133F485A485A485A485AB7FCA46C14
+FE20207E9F27>I<EC07F8EC3FFC14FF130315F8903807FE00EB0FF05C5CB0131FEB7F80
+EA3FFFB5C7FC5BA27F003F7FEA007FEB1FC0130FB08080EB07FE903803FFF815FC130014
+3FEC07F81E3A7CB327>I<127812FCB3B3B3A21278063A70B327>I<EA7F80EAFFF013FC13
+FF7E00017F38003FC0131F130FB080EB07F8ECFFF06D13FC7FA25B4913F0ECF800EB0FE0
+5CB0131F133F48B45A007F90C7FCB5FC13FC13F0EA7F801E3A7CB327>I
+E
+%EndDVIPSBitmapFont
+%DVIPSBitmapFont: Fd cmsy10 10 4
+/Fd 4 107 df<EB1FF0EBFFFE487F000714C04814E04814F04814F8A24814FCA3B612FE
+A96C14FCA36C14F8A26C14F06C14E06C14C0000114006C5BEB1FF01F1F7BA42A>15
+D<EC01F8140FEC3F80ECFC00495A495A495AA2130F5CB3A7131F5C133F49C7FC13FEEA03
+F8EA7FE048C8FCEA7FE0EA03F8EA00FE137F6D7E131F80130FB3A7801307A26D7E6D7E6D
+7EEC3F80EC0FF814011D537ABD2A>102 D<12FCEAFFC0EA07F0EA01FCEA007E7F80131F
+80130FB3A7801307806D7E6D7EEB007EEC1FF0EC07F8EC1FF0EC7E00495A495A495A5C13
+0F5CB3A7131F5C133F91C7FC137E485AEA07F0EAFFC000FCC8FC1D537ABD2A>I<126012
+F0B3B3B3B3A91260045377BD17>106 D E
+%EndDVIPSBitmapFont
+%DVIPSBitmapFont: Fe ecbx1200 12 63
+/Fe 63 123 df<ED0FFF4AB512C0020F14F0027F80903A01FFF803FC499038C000FE010F
+EB00034948497E49485B5C495A4C138001FF6E13005CA3705AEE01F893C8FCA74BB51280
+B9FCA5C69038E00003B3B0007FD9FFC1B6FCA538467EC53E>28 D<ED0FFF4AB5EAEF8002
+0F14FF147F903901FFF807491380010F495A495A495A5C495A8213FF4A7FADB9FCA5C690
+38E00003B3B0007FD9FFC1B6FCA538467EC53E>I<EA07C0EA1FF0487E487E487E7FA314
+80A37E7EEA1FF7EA07C7EA0007130FA21400A25B131E133EA25B13FC5B485A485A120748
+5A485A90C7FC120C112278C41F>39 D<EC01E01403EC0FC0EC1F80EC3F00147E5C130149
+5A495A5C130F495A133F5C137F49C7FCA2485AA2485AA212075BA2120F5BA2121FA25B12
+3FA4485AA612FFA25BAE7FA2127FA66C7EA4121F7FA2120FA27F1207A27F1203A26C7EA2
+6C7EA26D7E133F80131F6D7E1307806D7E6D7E1300147E80EC1F80EC0FC0EC03E014011B
+6476CA2C>I<12F07E127E7E6C7E6C7E6C7E7F6C7E6C7E12007F137F80133F806D7EA26D
+7EA26D7EA2801303A2801301A280A27F1580A4EC7FC0A615E0A2143FAE147FA215C0A6EC
+FF80A415005BA25CA213035CA213075CA2495AA2495AA2495A5C137F91C7FC13FE5B1201
+485A485A5B485A485A48C8FC127E12F85A1B647ACA2C>I<EA07C0EA1FF0EA3FF8EA7FFC
+12FF13FEA213FFA47E7E7EEA07CFEA000FA2131F131EA2133EA2133C137C13F8A2EA01F0
+120313E0EA07C0EA1F801300121E120C1022788E1F>44 D<B612F8A91D097F9A25>I<EA
+07C0EA1FF0EA3FF8EA7FFCEAFFFEA7EA7FFCEA3FF8EA1FF0EA07C00F0F788E1F>I<17C0
+EE01E01603A217C01607A2EE0F80A217005EA2163EA2163C167CA25EA24B5AA25E1503A2
+4B5AA25E150FA24BC7FCA2151E153EA25DA2157815F8A24A5AA25D1403A24A5AA25D140F
+A24AC8FCA2143EA2143C147CA25CA25C1301A2495AA25C1307A2495AA291C9FC5BA2133E
+A2133C137CA25BA25B1201A2485AA2485AA25B120FA248CAFCA2121E123EA25AA2127812
+F8A25A12602B647ACA38>I<EC3FF849B5FC010F14E0013F14F890397FF01FFC9039FFC0
+07FE4890380001FF48486D1380000716C049147F000F16E049143F001F16F0A2003F16F8
+A249141F007F16FCA600FF16FEB3A3007F16FCA56C6CEC3FF8A3001F16F0A2000F16E06D
+147F000716C06D14FF6C6C4913806C6D4813006C6D485A90397FF01FFC6DB55A010F14E0
+010314809026003FF8C7FC2F427CC038>I<EC03C01407141F147FEB03FF133FB6FCA413
+C3EA0003B3B3ADB712FCA5264177C038>I<ECFFE0010F13FE013F6D7E90B612E0000315
+F82607FC0313FE3A0FE0007FFFD81F806D138048C7000F13C0488001C015E001F07F00FF
+6E13F07F17F881A46C5A6C5A6C5AC9FC17F05DA217E05D17C04B13804B1300A2ED1FFC4B
+5A5E4B5A4B5A4A90C7FC4A5A4A5AEC0FF04A5AEC3F804AC7127814FE495A494814F8D907
+E014F0495A495A49C8FC017C140149140348B7FC4816E05A5A5A5A5AB8FC17C0A42D417B
+C038>I<ECFFF0010713FF011F14C0017F14F049C66C7ED803F8EB3FFED807E06D7E81D8
+0FF86D138013FE001F16C07FA66C5A6C4815806C485BC814005D5E4B5A4B5A4B5A4A5B02
+0F1380902607FFFEC7FC15F815FF16C090C713F0ED3FFCED0FFEEEFF80816F13C017E0A2
+6F13F0A217F8A3EA0FC0EA3FF0487EA2487EA217F0A25D17E06C5A494913C05BD83F8049
+1380D81FF0491300D80FFEEBFFFE6CB612F800015D6C6C14C0011F49C7FC010113E02D42
+7BC038>I<163FA25E5E5D5DA25D5D5D5DA25D92B5FCEC01F7EC03E7140715C7EC0F87EC
+1F07143E147E147C14F8EB01F0EB03E0130714C0EB0F80EB1F00133E5BA25B485A485A48
+5A120F5B48C7FC123E5A12FCB91280A5C8000F90C7FCAC027FB61280A531417DC038>I<
+0007150301E0143F01FFEB07FF91B6FC5E5E5E5E5E16804BC7FC5D15E092C8FC01C0C9FC
+AAEC3FF001C1B5FC01C714C001DF14F09039FFE03FFC9138000FFE01FC6D7E01F06D1380
+4915C0497F6C4815E0C8FC6F13F0A317F8A4EA0F80EA3FE0487E12FF7FA317F05B5D6C48
+15E05B007EC74813C0123E003F4A1380D81FC0491300D80FF0495AD807FEEBFFFC6CB612
+F0C65D013F1480010F01FCC7FC010113C02D427BC038>I<4AB47E021F13F0027F13FC49
+B6FC01079038807F8090390FFC001FD93FF014C04948137F4948EBFFE048495A5A140048
+5A120FA248486D13C0EE7F80EE1E00003F92C7FCA25B127FA2EC07FC91381FFF8000FF01
+7F13E091B512F89039F9F01FFC9039FBC007FE9039FF8003FF17804A6C13C05B6F13E0A2
+4915F0A317F85BA4127FA5123FA217F07F121FA2000F4A13E0A26C6C15C06D4913806C01
+8014006C6D485A6C9038E01FFC6DB55A011F5C010714C0010191C7FC9038003FF02D427B
+C038>I<121E121F13FC90B712FEA45A17FC17F817F017E017C0A2481680007EC8EA3F00
+007C157E5E00785D15014B5A00F84A5A484A5A5E151FC848C7FC157E5DA24A5A14035D14
+074A5AA2141F5D143FA2147F5D14FFA25BA35B92C8FCA35BA55BAA6D5A6D5A6D5A2F447A
+C238>I<EC7FF00103B5FC010F14C0013F14F090397F801FFC3A01FC0003FE48486D7E49
+7F4848EC7F80163F484815C0A2001F151FA27FA27F7F01FE143F6D158002C0137F02F014
+006C01FC5B6E485A6C9038FF83FCEDE7F86CECFFE06C5D6C92C7FC6D14C06D80010F14F8
+82013F8090B7FC48013F14802607FC0F14C0260FF80314E04848C6FC496D13F0003F141F
+48481307496D13F8150000FF157F90C8123F161F160FA21607A36D15F0127F160F6D15E0
+6C6C141F6DEC3FC06C6CEC7F80D80FFE903801FF003A07FFC00FFE6C90B55AC615F0013F
+14C0010F91C7FC010013F02D427BC038>I<EC7FF0903807FFFE011F6D7E017F14E09039
+FFE03FF0489038800FF848496C7E48488048486D7E001F80003F1680A2484815C08117E0
+A212FF17F0A617F8A45D127FA3003F5CA26C7E5D6C6C5B12076C6C131E6CEBC07C6CEBFF
+F8013F5B010F01C013F00101130090C8FCA217E05DA2EA03C0D80FF015C0487E486C4913
+80A217004B5A150F5E49495A6C48495A01C0EBFFE0260FF0035B6CB65A6C4AC7FC6C14F8
+6C6C13E0D907FEC8FC2D427BC038>I<903807FFC0013F13FC48B612804815E0260FF800
+13F0D81FC0EB3FF848C7EA1FFC4815FE01C0130F486C14FF7FA66C485B6C4814FE000FC7
+FCC8EA3FFCED7FF8EDFFF04A13E04A13801600EC07FC4A5A5D4A5A5D4A5A92C7FCA2147E
+147CA31478AA91C8FCA814F8EB03FE497E497FA2497FA56D5BA26D90C7FC6D5AEB00F828
+467AC535>63 D<EE1F80A24C7EA24C7EA34C7EA24B7FA34B7FA24B7FA34B7F169F031F80
+161F82033F80ED3E07037E80157C8203FC804B7E02018115F0820203814B137F0207815D
+173F020F814B7F021F8292C77EA24A82023E80027E82027FB7FCA291B87EA2498302F0C8
+FCA20103834A157F0107834A153FA249488284011F8491C97E4984133E017E82B6020FB6
+12F0A54C457CC455>65 D<B9FC18F018FE727E19E026003FFCC700077F05017F716C7E72
+7E727EA2721380A37213C0A74E1380A24E1300A24E5A4E5A4E5A4D5B05075B94B5128091
+B700FCC7FC18F018FF19E002FCC7000113F8716C7EF01FFE727E7213801AC07213E0A272
+13F0A31AF8A71AF0A2601AE0604E13C0604E138095B5120005075BBA12F86119C04EC7FC
+18E045447CC350>I<DCFFF01470031F01FF14F04AB6EAE0010207EDF803023FEDFE0791
+B539E001FF0F4949C7EA3F9F010701F0EC0FFF4901C0804990C87E494881494881494816
+7F4849163F4849161F5A4A160F485B19074890CAFC19035A5BA2007F1801A34994C7FC12
+FFAE127F7F1AF0A2123FA27F6C18011AE06C7F19036C6D17C06E16077E6C6DEE0F806C6D
+EE1F006D6C5E6D6C167E6D6C6C5D6D6D4A5A6D01F0EC07F0010101FEEC1FE06D903AFFF0
+01FF80023F90B6C7FC020715FC020115F0DA001F1480030001F8C8FC44467AC451>I<B9
+FC18F018FE727E19E026003FFEC7001F13F805017F9438003FFF060F7F727F727F727F84
+737E737EA2737EA2737EA21B80A2851BC0A51BE0AD1BC0A51B8061A21B006162193F624F
+5A19FF624E5B06075B4E5B063F90C7FC4DB45A050F13F8BA5A19C04EC8FC18F095C9FC4B
+447CC356>I<BA12F8A485D8001F90C71201EF003F180F180318011800A2197E193EA319
+1EA21778A285A405F890C7FCA316011603161F92B5FCA5ED001F160316011600A2F101E0
+1778A2F103C0A494C7FC1907A21A80A2190FA2191FA2193FF17F0061601807181F4DB5FC
+BBFC61A443447DC34A>I<BA1280A419C026003FFEC7121F1701EF007F183F181F180F18
+0719E01803A31801A3EE01E0F000F0A419001603A31607160F167F91B6FCA59138FE007F
+160F16071603A31601A693C9FCAFB712F0A53C447CC346>I<DCFFF01470031F01FF14F0
+4AB6EAE0010207EDF803023FEDFE0791B539E001FF0F4949C7EA3F9F010701F0EC0FFF49
+01C0804990C87E4948814948814948167F4849163F4849161F5A4A160F485B19074890CA
+FC19035A5BA2007F1801A34994C8FC12FFAD057FB612F0127F7FA3003FDC0001EBF000A2
+7F7EA26C7FA26C7F807E6C7F6C7F6D7E6D6C5D6D6C7E6D6D5C6D01F05C010101FE143F6D
+903AFFF001FF9F023F90B6120F0207EDFC030201EDF000DA001F02C01330030001FCC9FC
+4C467AC458>I<B7D88003B612FEA526003FFEC9EBF800B3A791B9FCA54AC9FCB3AAB7D8
+8003B612FEA54F447CC358>I<B712E0A5D8001F90C7FCB3B3B3A4B712E0A523447DC32A>
+I<B712F0A526003FFECAFCB3B1F00780A4180F1900A460A360A2187EA218FE1701170317
+07171F177FEE03FFB95AA539447CC343>76 D<B500FE067FB512806E95B6FCA26F5EA2D8
+003F50C7FC013D6DEE03DFA2013C6DEE079FA26E6CEE0F1FA26E6C161EA26E6C163CA36E
+6C1678A26E6C16F0A26E6DEC01E0A26E6DEC03C0A36E6DEC0780A26F6CEC0F00A26F6C14
+1EA26F6C5CA36F6C5CA26F6C5CA26F6D485AA26F6D485AA26F6D485AA3706C48C7FCA293
+383FF81EA2706C5AA2706C5AA3706C5AA2705BA2705BA2705BA2B6057FB6128071C7FCA2
+173E171C61447CC36A>I<B64BB512FE8181A281D8003F6D91C7EA780081013D7F81133C
+6E7E6E7F6E7F6E7F6E7F82806E7F6E7F6F7E6F7F83816F7F6F7F6F7F6F7F6F7F8382707F
+707F707F707F8482707F707F717E7113807113C019E0837113F07113F87113FC7113FE19
+FF847213F884848484A28484197F193F191FA2190F1907B61603190119001A78A24F447C
+C358>I<923807FFC092B512FE0207ECFFC0021F15F091267FFE0013FC902601FFF0EB1F
+FF01070180010313C04990C76C7FD91FFC6E6C7E49486F7E49486F7E01FF8348496F7E48
+496F1380A248496F13C0A24890C96C13E0A24819F04982003F19F8A3007F19FC49177FA4
+00FF19FEAD007F19FC6D17FFA3003F19F8A26D5E6C19F0A26E5D6C19E0A26C6D4B13C06C
+19806E5D6C6D4B13006C6D4B5A6D6C4B5A6D6C4B5A6D6C4A5B6D01C001075B6D01F0011F
+5B010101FE90B5C7FC6D90B65A023F15F8020715C002004AC8FC030713C047467AC454>
+I<B9FC18F018FE727E19E0D8001F90C7000F7F05017F716C7E727E727E721380A21AC084
+A21AE0A91AC0A24E1380A21A00604E5A4E5A4D485A050F5B92B712C096C7FC18FC18C092
+CBFCB3A7B712E0A543447DC34D>I<B812F8EFFFC018F818FE727ED8001F90C7003F13E0
+05037F05007F727E727E727EA28684A286A762A24E90C7FCA24E5A61187F943801FFF005
+075B053F138092B7C8FC18F818E018F892C77FEF3FFF050F7F717F717FA2717FA2717FA7
+85A61B0F85A2187F73131F72141EB700E06DEB803E72EBE0FC72EBFFF8060114F0726C13
+E0CC0007138050457DC354>82 D<DAFFE0131C010701FE133C013F9038FF807C90B6EAE0
+FC4815F9489038801FFF3907FC00014848EB007F4848143F4848140F491407007F15035B
+1601160012FF177CA27FA26D153C7F7F6D92C7FC6C7EEBFFE014FE6CEBFFF015FF6C15E0
+16FC6C816C6F7E6C826C826C6C81011F810107811300020F80140003077FED007F82040F
+1380828212F082A282A27EA218007EA26C5D6C5E6D14036D5D6D140701F84A5A01FFEC3F
+F002F8EBFFE0486CB65AD8FC1F92C7FCD8F80714FC48C614F0480107138031467AC43E>
+I<003FBA12E0A59026FE000FEB8003D87FE09338003FF049171F90C71607A2007E180300
+7C1801A300781800A400F819F8481978A5C81700B3B3A20107B8FCA545437CC24E>I<B6
+00FE017FB691B512FEA526007FFCC8D83FFEC9EA7C006E82013F701778807415F86D705F
+6F7014016D705FA26F7014036D64814E6D14076D646F70140F6D041E94C7FCA26F023E6D
+5C6DDC3C7F151E81027F037C6D5CF0783F6F70147C023F4B6C1578A26F01016F13F86E4B
+6C5D16806E02036F485A4E7E04C0EEE0036E4A486C5DA2DCE00FEDF0076E4B6C5D16F06E
+4A6F48C8FC051E7F04F8705A6E4A027F131EA2DCFC7CEDFE3E037F0178023F133C04FE16
+FF033F01F85E4D8004FF17F86F496E5BA36F496E5BA26F604D80A26F90C86C5BA36F486F
+90C9FCA26F48167EA30478163C6F457EC374>87 D<903801FFE0011F13FE017F6D7E48B6
+12E03A03FE007FF84848EB1FFC6D6D7E486C6D7EA26F7FA36F7F6C5A6C5AEA00F090C7FC
+A40203B5FC91B6FC1307013F13F19038FFFC01000313E0481380381FFE00485A5B127F5B
+12FF5BA35DA26D5B6C6C5B4B13F0D83FFE013EEBFFC03A1FFF80FC7F0007EBFFF86CECE0
+1FC66CEB8007D90FFCC9FC322F7DAD36>97 D<EB7FC0B5FCA512037EB1ED0FF892B57E02
+C314E002CF14F89139DFC03FFC9139FF000FFE02FCEB03FF4A6D13804A15C04A6D13E05C
+EF7FF0A218F8173FA318FCAC18F8A2177F18F0A3EFFFE06E15C06E5B6E491380027C4913
+00496C495A903AFC1FC07FFC496CB512F0D9F00314C049C691C7FCC8EA1FF036467DC43E
+>I<EC3FFC49B512C0010F14F0013F14FC90397FF003FE9039FFC001FF0003495A484948
+13805B120F485AA2485A6F1300007F6E5AED00784991C7FCA212FFAC6C7EA3123F6DEC03
+C0A26C6C1407000F16806D140F6C6DEB1F006C6D133E6C01F05B3A007FFC03F86DB55A01
+0F14C0010391C7FC9038003FF82A2F7CAD32>I<EE03FEED07FFA5ED001F160FB1EC3FE0
+903803FFFC010FEBFF8F013F14CF9039FFF807FF48EBC00148903880007F4890C7123F48
+48141F49140F121F485AA3127F5BA212FFAC127FA37F123FA26C6C141FA26C6C143F0007
+157F6C6C91B5FC6CD9C00314FC6C9038F01FEF6DB5128F011FEBFE0F010713F89026007F
+C0EBF80036467CC43E>I<EC3FF80103B57E010F14E0013F8090397FF83FF89039FFC007
+FC48496C7E48496C7E48486D1380485A001FED7FC05B003FED3FE0A2127F5B17F0161F12
+FFA290B7FCA401F0C9FCA5127FA27FA2123F17F06C7E16016C6C15E06C6C14036C6DEB07
+C06C6DEB0F806C01F0EB3F0090397FFE01FE011FB55A010714F0010114C09026001FFEC7
+FC2C2F7DAD33>I<EDFF80020F13E0027F13F049B512F849EB8FFC90390FFE0FFE90381F
+FC1F14F8133FEB7FF0A2ED0FFCEBFFE0ED03F0ED00C01600ABB612F8A5C601E0C7FCB3B0
+007FEBFFE0A527467DC522>I<DAFFE0137E010F9039FE03FF80013FEBFF8F90B812C048
+D9C07F133F489038001FF84848EB0FFC4848903907FE1F80001F9238FF0F00496D90C7FC
+A2003F82A8001F93C7FCA26D5B000F5D6C6C495A6C6C495A6C9038C07FF04890B55A1680
+D8078F49C8FC018013E0000F90CAFCA47F7F7F90B612C016FC6CEDFF8017E06C826C16FC
+7E000382000F82D81FF0C77ED83FC014074848020113808248C9FC177FA46D15FF007F17
+006D5C6C6C4A5A6C6C4A5AD80FFEEC3FF83B07FFC001FFF0000190B612C06C6C92C7FC01
+0F14F8D9007F90C8FC32427DAC38>I<EB7FC0B5FCA512037EB1ED07FE92383FFF8092B5
+12E002C114F89139C7F03FFC9138CF801F9139DF000FFE14DE14FC4A6D7E5CA25CA35CB3
+A7B60083B512FEA537457CC43E>I<137C48B4FC4813804813C0A24813E0A56C13C0A26C
+13806C1300EA007C90C7FCAAEB7FC0EA7FFFA512037EB3AFB6FCA518467CC520>I<EB7F
+C0B5FCA512037EB293387FFFE0A593380FE0004C5A4CC7FC167E5EED03F8ED07E04B5A4B
+5A037FC8FC15FEECC1FCECC3FE14C7ECDFFF91B57E82A202F97F02E17F02C07FEC807F6F
+7E826F7E816F7F836F7F816F7F83707E163FB60003B512F8A535457DC43B>107
+D<EB7FC0B5FCA512037EB3B3B3A3B61280A519457CC420>I<90277F8007FEEC0FFCB590
+263FFFC090387FFF8092B5D8F001B512E002816E4880913D87F01FFC0FE03FF8913D8FC0
+0FFE1F801FFC0003D99F009026FF3E007F6C019E6D013C130F02BC5D02F86D496D7EA24A
+5D4A5DA34A5DB3A7B60081B60003B512FEA5572D7CAC5E>I<90397F8007FEB590383FFF
+8092B512E0028114F8913987F03FFC91388F801F000390399F000FFE6C139E14BC02F86D
+7E5CA25CA35CB3A7B60083B512FEA5372D7CAC3E>I<EC1FFC49B512C0010714F0011F14
+FC90397FF80FFF9026FFC0017F48496C7F4848C7EA3FE000078248486E7E49140F001F82
+A2003F82491407007F82A400FF1780AA007F1700A46C6C4A5AA2001F5E6D141F000F5E6C
+6C4A5AA26C6C6CEBFFE06C6D485B27007FF80F90C7FC6DB55A010F14F8010114C0902600
+1FFCC8FC312F7DAD38>I<90397FC00FF8B590B57E02C314E002CF14F89139DFC03FFC91
+39FF001FFE000301FCEB07FF6C496D13804A15C04A6D13E05C7013F0A2EF7FF8A4EF3FFC
+ACEF7FF8A318F017FFA24C13E06E15C06E5B6E4913806E4913006E495A9139DFC07FFC02
+CFB512F002C314C002C091C7FCED1FF092C9FCADB67EA536407DAC3E>I<DA3FE0131E90
+2603FFFC133E010F01FF137E013F1480903AFFF80FE0FE489038E003F148EBC001489038
+8000FB4890C7127F49143F001F151F485A160F5B127FA3485AAC6C7EA46C7EA26C6C141F
+163F6C6C147F6C15FF6C6D5A6C9038E003EF6C9038F01FCF6DB5128F011FEBFE0F010313
+F89038007FC091C7FCAD0307B512FCA536407CAC3B>I<90387F807FB53881FFE0028313
+F0028F13F8ED8FFC91389F1FFE000313BE6C13BC14F8A214F0ED0FFC9138E007F8ED01E0
+92C7FCA35CB3A5B612E0A5272D7DAC2E>I<90391FFC038090B51287000314FF120F381F
+F003383FC00049133F48C7121F127E00FE140FA215077EA27F01E090C7FC13FE387FFFF0
+14FF6C14C015F06C14FC6C800003806C15806C7E010F14C0EB003F020313E0140000F014
+3FA26C141F150FA27EA26C15C06C141FA26DEB3F8001E0EB7F009038F803FE90B55A00FC
+5CD8F03F13E026E007FEC7FC232F7CAD2C>I<EB01E0A51303A41307A2130FA2131FA213
+3F137F13FF1203000F90B51280B7FCA4C601E0C7FCB3A3ED01E0A9150302F013C0137F15
+0790393FF80F8090391FFC1F006DB5FC6D13FC01015B9038003FE023407EBE2C>I<D97F
+C049B4FCB50103B5FCA50003EC000F6C81B3A85EA25EA25E7E6E491380017FD901F713FE
+9138F807E76DB512C7010F1407010313FE9026007FF0EBFC00372E7CAC3E>I<B6903803
+FFFCA5000101E09038003E006C163C80017F5D8017F8013F5D6E1301011F5D6E1303010F
+5D6E13076D5DED800F6D92C7FC15C05E6DEBE01E163E6D143CEDF07C027F1378EDF8F802
+3F5B15FD021F5B15FF6E5BA36E5BA26E90C8FCA26E5AA26E5AA21578362C7EAB3B>I<B5
+D8FE1FB539801FFFF0A500019027C0003FE0C7EA7C007114786E17F86C6F6C5C6E160101
+7F6E6C5CA26E011F1403013F6F5C6E013F1407011F6F5CA26E0179140F010F048090C7FC
+6E01F95C6D02F0EBC01E15806D902681E07F5B18E003C3157C6D9139C03FF07815E76DDA
+801F5B18F803FF14F96E9039000FFDE018FF6E486D5BA36E486D5BA26E486D90C8FCA24B
+7F02075DA26E48147C4B143C4C2C7EAB51>I<B500FE90383FFFF0A5C601F0903803E000
+6D6C495A6D6C495A011F4AC7FC6E5B6D6C137E6DEB807C6D6D5A6DEBC1F0EDE3E06DEBF7
+C06EB45A806E90C8FC5D6E7E6E7F6E7FA24A7F4A7F8291381F3FFCEC3E1F027C7F4A6C7E
+49486C7F01036D7F49487E02C08049486C7F49C76C7E013E6E7E017E141FB500E090B512
+FCA5362C7EAB3B>I<B6903803FFFCA5000101E09038003E006C163C80017F5D8017F801
+3F5D6E1301011F5D6E1303010F5D6E13076D5DED800F6D92C7FC15C05E6DEBE01E163E6D
+143CEDF07C027F1378EDF8F8023F5B15FD021F5B15FF6E5BA36E5BA26E90C8FCA26E5AA2
+6E5AA21578A215F85D14015D001F1303D83F805B387FC007D8FFE05B140F92C9FC5C143E
+495A387FC1F8EB07F06CB45A6C5B000790CAFCEA01FC36407EAB3B>I<001FB71280A490
+26FC001F130001E0495A5B49495A90C7485A48495B123E4A5B4A5B003C495BA24A90C7FC
+4A5A4A5AC7FC4A5A495B495BA2495B499038800780491300A2495A4948130F49481400A2
+485B48495B485BA248495B4890C75A48485C15034848EB1FFEB7FCA4292C7DAB32>I
+E
+%EndDVIPSBitmapFont
+%DVIPSBitmapFont: Ff ecbx1000 10 61
+/Ff 61 122 df<913803FFC0027F13F00103B512FC010FEB00FED93FF8133FD97FE0EBFF
+8049485A5A1480484A13C04A6C1380A36F1300167E93C7FCA592383FFFC0B8FCA4000390
+C7FCB3ABB5D8FC3F13FFA4303A7EB935>28 D<913903FFC7C0027F13FF0103B6FC010F13
+0090383FF80190387FE003EBFFC05A14805A4A7EA281A9B8FCA4000390C7FCB3ABB5D8FC
+3F13FFA4303A7EB935>I<EA0F80EA3FE0EA7FF0A2EAFFF8A213FCA3127FA2123FEA0F9C
+EA001C133C1338A31378137013F0EA01E0A2EA03C0EA0780EA0F005A121C12180E1D79B9
+1B>39 D<141C143C14F8EB01F0EB03E01307EB0FC0EB1F8014005B137E13FE5B12015B12
+03A2485AA2120F5B121FA25B123FA4485AA512FFB1127FA56C7EA4121F7FA2120F7F1207
+A26C7EA212017F12007F137E7F7F1480EB0FC0EB07E01303EB01F0EB00F8143C141C1653
+77BD25>I<12E07E127C7E7E7F6C7E6C7E12037F6C7E7F12007F137E137FA2EB3F80A214
+C0131F14E0A2130F14F0A4EB07F8A514FCB114F8A5EB0FF0A414E0131FA214C0133F1480
+A2EB7F00A2137E13FE5B12015B485A5B1207485A485A90C7FC123E5A12F05A16537BBD25
+>I<EA0F80EA3FE0EA7FF0A2EAFFF8A213FCA3127FA2123FEA0F9CEA001C133C1338A313
+78137013F0EA01E0A2EA03C0EA0780EA0F005A121C12180E1D798C1B>44
+D<B61280A819087F9620>I<EA0F80EA3FE0EA7FF0A2EAFFF8A5EA7FF0A2EA3FE0EA0F80
+0D0D798C1B>I<1618163816781670A216F016E0150116C015031680A2150716005D150E
+151E151CA2153C15381578157015F05DA214015D14035D140792C7FCA25C140E141E141C
+143C1438A21478147014F05CA213015C13035C130791C8FCA25B130E131E131C133C1338
+A21378137013F05B12015BA212035B120790C9FC5A120EA2121E121C123C123812781270
+A212F05AA225537BBD30>I<49B4FC011F13F0017F13FC9038FF83FE4848C67E4848EB7F
+804848EB3FC04848EB1FE0A2001F15F0A24848EB0FF8A3007F15FCA400FF15FEB3007F15
+FCA5003F15F86D131FA2001F15F0A26C6CEB3FE0000715C06C6CEB7F806C6CEBFF003900
+FF83FE6DB45A011F13F0010190C7FC27377CB530>I<141E143E14FE1307137FB5FCA313
+8FEA000FB3B3A5007FB61280A4213679B530>I<EB0FFE90387FFFC048B512F0000714FC
+390FE03FFF261F800F1380263F000313C0D87F8014E0EBE00100FF6D13F07FA2ED7FF8A4
+6C5A6C5A0006C7FCC8FCEDFFF0A216E05C16C04A138016004A5A4A5AEC1FF05D4A5A4AC7
+FC14FE495AD903F01378495A495A495A49C712F8017C14F05B49130148B6FC5A5A5A5A5A
+4815E0B7FCA425367BB530>I<EB03FF011F13F0017F13FC3901FC07FF2603F003138048
+486C13C0496C13E0EA0FF86D14F0487EA66C4814E06C5A6C485AC714C04A138016004A5A
+4A5AEC3FF090380FFFC05D15F090380007FE913801FF806E13C016E0ED7FF016F8ED3FFC
+A216FEEA1FC0487E487E487EA416FCA249137F007F15F801C0EBFFF06C5A6C6C4813E026
+0FFC0713806CB61200000114FC6C6C13F0010790C7FC27377CB530>I<ED07C0150FA215
+1F153F157F15FF5CA25C5C5C5C143E143C5C5C1301495A5C495A495A5B133E5B13785B48
+5A1203485A5B48C7FC121E5A127C5AB81280A4C70001EBC000AA0103B61280A429367DB5
+30>I<001C15C0D81F80130701F8137F90B61280A216005D5D15F05D15804AC7FC14F090
+C9FCA7EB03FE90381FFFE0017F13F89038FE07FC9038F003FFD9C0011380496C13C090C7
+FC000E15E0C8127F16F0A216F8A3121FEA3FC0487E12FF7FA316F05B15FFD87F8014E000
+7EC713C0003E5B003F4913806C6C481300390FF01FFE6CB512F8000114E06C6C1380D90F
+F8C7FC25377BB530>I<EC0FF8ECFFFE0103EBFF8090390FF80FC090393FE003E090397F
+8001F09038FF000F48EC1FF84848133F485A120F5B121FA2003FEC1FF0ED0FE0484890C7
+FCA31408EC7FF039FFF1FFFC01F313FFD9F78013809039FF007FC049EB3FE04914F0ED1F
+F85B16FCA34914FEA4127FA5123F16FCA26C7E16F8000F143F6D14F0000715E06C6CEB7F
+C03A01FF81FF806C90B51200013F13FC010F13F00101138027377CB530>I<123C123EEA
+3FE090B71280A41700485D5E5E5E5EA2007CC7EA0FC000784A5A4BC7FC00F8147E485C5D
+14014A5AC7485A4A5AA24A5A143F4AC8FCA214FEA213015C1303A21307A2130F5CA2131F
+A5133FA96D5A6D5A6D5A29397BB730>I<49B47E010F13F0013F13FC9038FE01FF3A01F8
+007F804848EB3FC04848EB1FE0150F484814F01507121FA27F7F7F6D130F01FF14E014C0
+9138E01FC06CEBF83F9138FE7F806C9038FFFE005D6C14F06C14FC6C14FF6D14806D14C0
+90B612E0D803FD14F02607F07F13F848487E261FC00F13FC383F8003007F010013FE90C7
+127F151F00FE140715031501A21500A216FC7E6C14016D14F86C6C13036DEB07F06C6CEB
+0FE0D80FFEEB7FC00003B61200C614FC013F13F00103138027377CB530>I<EB1FFE48B5
+12E0000714F8390FE00FFE393F0003FF4815806D7ED8FFC014C013E0A5EA7FC06C484813
+80EA1F00C7481300EC0FFC4A5AEC3FE04A5A92C7FC14FE5C495AA25C495AA25CA990C9FC
+A7EB07C0EB1FF0497EA2497EA56D5AA26D5AEB07C0223A7BB92D>63
+D<ED03E04B7EA24B7EA34B7EA24B7EA34B7EA292B57EA34A8015F302038015E1A2020780
+15C0020F80ED807FA2021F80ED003F4A80023E131FA2027E80027C7F02FC814A7FA20101
+824A7F49B77EA3498202C0C7FC010F824A147FA2011F8291C8123F4982013E151FA2017E
+82017C8101FE83B500F80107B61280A4413A7DB948>65 D<B812C017FC17FF18C028007F
+F000037F04007F717E717E171F84A2717EA74D5AA260173F4D5A4D5A4C13C0040F5B91B6
+00FCC7FCA2EFFF8002F0C713F0EF3FF8717E717E717E19807113C0A319E0A719C0A25F4D
+138019005FEF7FFE4C485AB912F018C095C7FC17F03B397DB844>I<DB3FFCEB01C00203
+B5EAC003021FECF00791B6EAFC0F01039039FC00FF3F4901C0EB1FFFD91FFEC77E494814
+03D97FF080494880485B48177F4849153F4890C9FC181F485A180F123F5B1807127FA249
+93C7FC12FFAD127F7FF003C0123FA27F001F1707A26C6C1780180F6C6D16006C6D5D6C17
+3E6C6D157ED97FF85D6D6C4A5A6DB44A5A010701C0EB0FE06D01FCEBFF80010090B548C7
+FC021F14F8020314E09126003FFEC8FC3A3B7BB945>I<B87E17F817FF18C028007FF800
+0713F09338007FF8EF1FFE717E050313807113C0A27113E0F07FF0A2F03FF8A219FC181F
+A219FEA419FFAC19FEA419FC183FA219F8187F19F0F0FFE0A24D13C04D13804D1300EF1F
+FEEF7FFC933807FFF0B912C095C7FC17FC178040397DB849>I<B912F0A426007FF8C7FC
+EF1FF8170717031701A21700A21878A3043C137C183CA41800167CA216FC150391B5FCA4
+ECF8031500167CA2163C180FA3181EA293C7FCA2183EA2183C187CA218FCA2EF01F81703
+170F173FEE01FFB9FC18F0A338397DB83F>I<DB3FFCEB01C00203B5EAC003021FECF007
+91B6EAFC0F01039039FC00FF3F4901C0EB1FFFD91FFEC77E49481403D97FF08049488048
+5B48177F4849153F4890C9FC181F485A180F123F5B1807127FA24993C8FC12FFAB043FB6
+1280A2127F7FDC0003EBC000123FA27F121FA26C7EA26C7F6C7F6C7F7ED97FF85C6D7E6D
+B45C010701C05B6D01FCEBFF3F010090B5EAFE0F021FECF8030203ECE0009126003FFEC9
+FC413B7BB94B>71 D<B6D8FC03B612F0A426007FF8C70001EBE000B3A391B8FCA402F8C7
+1201B3A6B6D8FC03B612F0A444397DB84B>I<B612FCA439007FF800B3B3ADB612FCA41E
+397DB824>I<B7FCA426007FF8C9FCB3ACEF0780A5170F1800A35FA25FA25F5F5E5EEE0F
+FE167FB8FCA431397DB839>76 D<B500F80403B512F06E5EA26E5ED8007FF1E000A2D97B
+FF161EA201796D5DA201786D5DA26E6C5DA36E6C4A5AA26E6C4A5AA26E6C4A5AA26E6C4A
+5AA26E6C141EA36E6D5BA26E6D5BA26F6C5BA26F6C485AA36F6C485AA26F6C485AA26F6C
+48C7FCA2923803FF1EA36F13BCA26F13F8A2705AA2705AA213FCB500FC6D4848B612F0A2
+EE0F80EE070054397DB85B>I<B500FC0203B512F0A28080C66C6D90390003F0006F6E5A
+81017B7F13798101787F6E7E6E7E6E7F6E7FA26E7F6E7F6E7F6E7F6F7E153F826F13806F
+13C06F13E06F13F06F13F88117FCEE7FFEEE3FFF7013817013C17013E18218F17013F970
+13FDEF7FFF8383A28383838383187FA2183F181F01FC160FB500FC150718031801A24439
+7DB84B>I<EDFFF8020FEBFF80027F14F0903A01FFC01FFC010790380007FFD91FFC0101
+13C0D93FF06D6C7E49486E7E49486E7E48496E7E48834890C86C7EA248486F1380A24848
+6F13C0A2003F18E0A348486F13F0A400FF18F8AC007F18F06D5DA3003F18E0A26D5D001F
+18C0A26C6C4B13806C18006E5C6C6D4A5A6C5F6C6D4A5A6D6C4A5AD93FFC49485A6DB401
+075B0107D9C01F90C7FC010190B512FC6D6C14F0020F1480020001F8C8FC3D3B7BB948>
+I<B8FC17F017FEEFFF8028007FF8000F13C0040113E07013F0EF7FF8EF3FFCA2EF1FFEA2
+18FFA818FEA2EF3FFCA2EF7FF8EFFFF04C13E0040F13C091B7120017FC17E002F8C9FCB3
+A4B612FCA438397DB841>I<B712FCEEFFE017FC17FF28007FF8000F13C004017F707F71
+7E717EA2717EA284A760A24D5A604D5A4D5A04035B041F90C8FC91B612FC17E0839139F8
+003FFCEE0FFF707F707F8284A2707FA584A51A601AF084177F1901DD3FFE13E0B600FC01
+1F130394390FFF87C071EBFF8005011400CBEA1FFC443A7DB848>82
+D<D907FF130E013FEBE01E90B5EAF83E0003ECFE7E3A07FC01FFFE390FF0001F4848130F
+48481303491301007F140090C8FC167E5A163EA27F161E7F7F6D91C7FC13FC387FFFE014
+FEECFFF06C14FE6F7E6C816C15F06C816C81C681133F010F801301D9000F1480EC007F03
+0F13C01503818100F0157FA3163FA27E17807E167F6C16007E6D14FE01E0495A01F81303
+9039FF801FF800FC90B512E0D8F83F5CD8F00749C7FC39E0007FF02A3B7BB935>I<003F
+B91280A4D9F800EBF003D87FC09238007FC049161F007EC7150FA2007C1707A200781703
+A400F818E0481701A4C892C7FCB3AE010FB7FCA43B387DB742>I<B600FC011FB512C0A4
+26007FF8C8381FC000725AB3B3181F013F94C7FC8060011F163E6D6C157E187C6D6C15FC
+6D6D495A6D6DEB07F06D01F0EB1FE0DA7FFEEBFFC0021FB6C8FC02075C020014F0030F13
+80423A7DB849>I<EB3FFE0003B512E0000F14F8391FF00FFE003FEB03FF6D6C7F6E7FA2
+6F7EA26C5A6C5AEA0380C8FCA2EC3FFF010FB5FC137F3901FFF87F00071380380FFE00EA
+3FF85B485A12FF5BA415FF6D5A127F263FF00713F83B1FFC1FBFFFC0390FFFFE1F0003EB
+F80F39003FE0032A257DA42E>97 D<13FFB5FCA412077EAF4AB47E020F13F0023F13FC91
+38FE03FFDAF00013804AEB7FC00280EB3FE091C713F0EE1FF8A217FC160FA217FEAA17FC
+A3EE1FF8A217F06E133F6EEB7FE06E14C0903AFDF001FF80903AF8FC07FE009039F03FFF
+F8D9E00F13E0D9C00390C7FC2F3A7EB935>I<903801FFC0010F13FC017F13FFD9FF8013
+802603FE0013C048485AEA0FF8121F13F0123F6E13804848EB7F00151C92C7FC12FFA912
+7FA27F123FED01E06C7E15036C6CEB07C06C6C14806C6C131FC69038C07E006DB45A010F
+13F00101138023257DA42A>I<EE7F80ED7FFFA4150381AF903801FF81010F13F1013F13
+FD9038FFC07F0003EB001FD807FC1307000F8048487F5B123FA2485AA312FFAA127FA27F
+123FA26C6C5B000F5C6C6C5B6C6C4913C02701FF80FD13FE39007FFFF9011F13E1010113
+012F3A7DB935>I<903803FF80011F13F0017F13FC3901FF83FE3A03FE007F804848133F
+484814C0001FEC1FE05B003FEC0FF0A2485A16F8150712FFA290B6FCA301E0C8FCA4127F
+A36C7E1678121F6C6C14F86D14F000071403D801FFEB0FE06C9038C07FC06DB51200010F
+13FC010113E025257DA42C>I<EC1FF0903801FFFC010713FF90391FF87F8090383FE0FF
+D9FFC113C0A2481381A24813016E1380A2ED3E0092C7FCA8B6FCA4000390C8FCB3ABB512
+FEA4223A7DB91D>I<161FD907FEEBFFC090387FFFE348B6EAEFE02607FE07138F260FF8
+01131F48486C138F003F15CF4990387FC7C0EEC000007F81A6003F5DA26D13FF001F5D6C
+6C4890C7FC3907FE07FE48B512F86D13E0261E07FEC8FC90CAFCA2123E123F7F6C7E90B5
+12F8EDFF8016E06C15F86C816C815A001F81393FC0000F48C8138048157F5A163FA36C15
+7F6C16006D5C6C6C495AD81FF0EB07FCD807FEEB3FF00001B612C06C6C91C7FC010713F0
+2B377DA530>I<13FFB5FCA412077EAFED7FC0913803FFF8020F13FE91381F03FFDA3C01
+138014784A7E4A14C05CA25CA291C7FCB3A3B5D8FC3F13FFA4303A7DB935>I<EA01F0EA
+07FC487EA2487EA56C5AA26C5AEA01F0C8FCA913FF127FA412077EB3A9B512F8A4153B7D
+BA1B>I<141FEC7FC0ECFFE0A24913F0A56D13E0A2EC7FC0EC1F0091C7FCA9EC0FF0EB0F
+FFA4EB007F143FB3B0121FEA3F80EA7FC0EAFFE0EC7FE0A215C014FF6C481380903883FE
+006CB45A000F13F0000113801C4B86BA1D>I<13FFB5FCA412077EAF92380FFFE0A49238
+03FC0016F0ED0FE0ED1F804BC7FC157E5DEC03F8EC07E04A5A141FEC7FE04A7E8181A2EC
+CFFEEC0FFF496C7F806E7F6E7F82157F6F7E6F7E82150F82B5D8F83F13F8A42D3A7EB932
+>I<13FFB5FCA412077EB3B3ACB512FCA4163A7DB91B>I<01FED97FE0EB0FFC00FF902601
+FFFC90383FFF80020701FF90B512E0DA1F81903983F03FF0DA3C00903887801F000749DA
+CF007F00034914DE6D48D97FFC6D7E4A5CA24A5CA291C75BB3A3B5D8FC1FB50083B512F0
+A44C257DA451>I<01FEEB7FC000FF903803FFF8020F13FE91381F03FFDA3C0113800007
+13780003497E6D4814C05CA25CA291C7FCB3A3B5D8FC3F13FFA430257DA435>I<903801
+FFC0010F13F8017F13FFD9FF807F3A03FE003FE048486D7E48486D7E48486D7EA2003F81
+491303007F81A300FF1680A9007F1600A3003F5D6D1307001F5DA26C6C495A6C6C495A6C
+6C495A6C6C6CB45A6C6CB5C7FC011F13FC010113C029257DA430>I<9039FF01FF80B500
+0F13F0023F13FC9138FE07FFDAF00113800003496C13C00280EB7FE091C713F0EE3FF8A2
+EE1FFCA3EE0FFEAA17FC161FA217F8163F17F06E137F6E14E06EEBFFC0DAF00313809139
+FC07FE0091383FFFF8020F13E0020390C7FC91C9FCACB512FCA42F357EA435>I<49B4EB
+0780010FEBE00F013FEBF81F9039FFC07C3F0003EB803E3A07FE000F7F4848EB07FF121F
+497F123F497F127FA25B12FFAA6C7EA36C7E5D6C7E000F5C6C6C5B6C6C133F6CEBC0FD39
+007FFFF1011F13C10101130190C7FCAC037F13FEA42F357DA432>I<9038FE03F000FFEB
+0FFEEC3FFF91387C7F809138F8FFC000075B6C6C5A5CA29138807F80ED3F00150C92C7FC
+91C8FCB3A2B512FEA422257EA427>I<90383FF0383903FFFEF8000F13FF381FC00F383F
+0003007E1301007C130012FC15787E7E6D130013FCEBFFE06C13FCECFF806C14C06C14F0
+6C14F81203C614FC131F9038007FFE140700F0130114007E157E7E157C6C14FC6C14F8EB
+80019038F007F090B512C000F8140038E01FF81F257DA426>I<130FA55BA45BA25B5BA2
+5A1207001FEBFFE0B6FCA3000390C7FCB21578A815F86CEB80F014816CEBC3E090383FFF
+C06D1380903803FE001D357EB425>I<01FFEC3FC0B5EB3FFFA4000714016C80B3A35DA2
+5DA26C5C6E4813E06CD9C03E13FF90387FFFFC011F13F00103138030257DA435>I<B539
+F001FFF8A4000390C7EA1F00161E6E133E6C153C6E137C6C15786E13F8017F5CECF00101
+3F5C14F8011F495AA2ECFC07010F5CECFE0F010791C7FC6E5A6D131E15BE6D13BC15FC6D
+5BA36E5AA26E5AA26E5AA26E5AA22D257EA432>I<B500F1B538803FFFA43D07FE000FF8
+0003E06C6C010715C082028015076C6E6C148015076C01C0ED0F00826E485C017FED801E
+5D90273FF01E7F5B17C0DAF83E147C011F90393C3FE078037C14F8903B0FFC781FF0F0A2
+9139FEF00FF10107EDF9E002FF14FB6D496CB45AA24B7E6D5EA26D496C90C7FCA292C7FC
+6E5CA2023E147C023C143C40257EA445>I<B539F01FFFF0A4000390398003F8006C01C0
+13E06C1407D97FE05B6D6C485A6E48C7FC90381FFC3E010F5B903807FEFC6D6C5A5D6D5B
+6D5B6E7E6E7E814A7EA24A7E903801F3FFD903E37FD907C17FEB0FC049486C7E4A6C7E01
+3E80496D7E49130F00016E7EB590383FFFF8A42D257EA432>I<B539F001FFF8A4000390
+C7EA1F00161E6E133E6C153C6E137C6C15786E13F8017F5CECF001013F5C14F8011F495A
+A2ECFC07010F5CECFE0F010791C7FC6E5A6D131E15BE6D13BC15FC6D5BA36E5AA26E5AA2
+6E5AA26E5AA292C8FCA25C141E003F133E387F803C38FFC07C147814F8EBC1F0EBC3E06C
+485A387D1F80D83FFFC9FCEA1FFCEA07F02D357EA432>I E
+%EndDVIPSBitmapFont
+%DVIPSBitmapFont: Fg ecbx1440 14.4 35
+/Fg 35 120 df<EE7FFC031FB57E4AB612E0020715F8023F9038C00FFC913AFFFC0001FE
+4901F0EB007F010701C0EB03FF4949497F4990C75A5B5C495A4D7F01FF6F5B5CA27190C7
+FC715AEF00F895C8FCAA0407B512C0BAFCA5C601F8C7120F83B3B3A6B6D8F807B612C0A5
+42547DD349>28 D<151E153E15FE1403140F147FEB07FF0003B5FCB6FCA3EBF87FEAFC00
+C7FCB3B3B3A6007FB712FCA52E4E76CD42>49 D<EC1FFE49B512F0010F14FC013FECFF80
+4915E02701FF803F7F2703FC000713FCD807F001017F48486D7FD81F806E138048C87E70
+13C0D87FE016E001F8806D16F000FF817F7013F8A56C5AA26C5A6C5AEA0380C914F05EA2
+18E05E18C05E18804C13005F4C5A4C5A5F4B5B4B5B4B5B94C7FCED0FFC4B5A4B5AED7FC0
+4B5A4A90C8FCEC03FC4A5A4A4814F84A5A4A5A4AC8FC02FEEC01F0495A495A495A5CD90F
+80140349C8FC013E1507017FB7FC90B812E05A5A5A5A5A5A5AB9FC18C0A4354E7ACD42>
+I<913807FFC0027F13FC0103B67E010F15E090261FF80313F890267FC0007F01FEC7EA3F
+FE48488148486E138013FE486C6C6D13C0804817E080A66C5B18C06C5B6C90C75AD80038
+168090C8FC4C1300A24C5A5F4C5A4B5B4B13C0030F5BDB7FFEC7FC91387FFFF816C016FC
+EEFF80DA000313E09238007FF8EE3FFE707E70138018C07013E018F07013F8A218FC82A2
+18FEA3EA03C0EA0FF0EA3FFC487EA2B5FCA218FCA25E18F8A26C4816F0495C4916E0D83F
+E04A13C06C485CD80FF04A1380D807FE91387FFE003B03FFE003FFFC6C90B65A6C6C15E0
+010F92C7FC010114FCD9001F1380374F7BCD42>I<17FC1601A216031607160FA2161F16
+3F167FA216FF5D5DA25D5D5D167F153E157E15FC15F8EC01F01403EC07E015C0EC0F8014
+1FEC3F00143E5C14FC495A5C495A1307495A5C49C7FC5B137E137C5B1201485A5B485A12
+0F485A90C8FC123E127E5ABA1280A5C901FCC7FCAF021FB71280A5394F7CCE42>I<486C
+150601F0153E01FEEC01FED9FFF0133F91B65A5F5F5F5F5F94C7FC16FC5E16E093C8FC15
+FC01F0138091CAFCAC913807FF80023F13F891B512FE01F36E7E9026FFFC0113E09139E0
+007FF891C76C7E496E7E01F86E7E5B7013804916C0C9FC18E08218F0A418F8A31203EA0F
+E0EA3FF8487EA212FF7FA218F0A25B5E6C4816E05B01C016C06CC85A18806C6C4A13007F
+D80FF04A5A6C6CECFFFCD803FE4913F02701FFE00F5B6C6CB612806D92C7FC010F14F801
+0114C09026003FFCC8FC354F7ACD42>I<ED07FE92B512C0020314F0021F14FC91397FFC
+01FE9139FFE0007F01030180EB3F804990C7121F4948EC7FC0494814FF4948010313E049
+5A49485B5A485BA2485BA2486F13C091C7FC4803001300177E94C7FC5AA25B127FA2ED3F
+F04AB5FC020714C000FF4914F091391F807FF891393E001FFE02786D7E4A6D13807013C0
+6D5A4A6D13E018F05C7013F8A291C813FCA44916FEA3127FA6123FA37F6C17FCA36C17F8
+5E7E6E15F06C17E06C6D5B6E15C06C4B13806D6C491300D93FFC495A6DB4EBFFFC010790
+B512F06D5D01001580021F01FCC7FC020313C0374F7BCD42>I<121F7F7FEBFF8091B8FC
+A45A18FE18FC18F818F0A218E018C018804817000180C8123E007EC9127E5F007C4B5A4C
+5A5F16074C5A484B5A4CC7FC167E167CC912FC4B5A4B5AA24B5A150F4B5AA24B5AA24BC8
+FC5DA25C5D1403A214075D140FA3141FA2143FA34A5AA414FFA65BAB6D5B6E5A6E5A6E5A
+385279D042>I<173FA24D7EA34D7EA24C7FA34C7FA24C7FA34C7FA24C7FA34C7F163E83
+047E80EE7C3F04FC8016F8830301814C7E03038116E0830307814C7E030F81168083031F
+811600834B81033E80037E82157C8403FC824B800201835D840203834B800207835D92B8
+FC4A83A34A8392C9FC4A83143E85027E84027C8202FC845C850101854A820103855C8501
+07854A82A2494884D93FF082B600F0020FB712C0A55A547CD363>65
+D<932603FFF01407047F01FF140F0307B600E0131F033F03F8133F92B700FE137F020391
+26C003FF13FF020F01F8C7EA3FC1023F01C0EC0FE391B5C80003B5FC4901FC8149498149
+01E082011F498249498292CA7E4948834948835A4A83485B4885A24849187FA2485B1B3F
+A2485B1B1FA25AA21B0091CDFCA2B5FCAE7EA280A36C1A1FA36C7FA21B3F6C7F1B3E6C7F
+1B7E6C6D187C6C1AFC6E18F86C19016D6CEF03F06D7E6FEE07E06D6DEE0FC001076DEE1F
+806D01F8EE3F006D6D16FE6D01FF4B5A023F01C0EC07F8020F01FCEC3FF00203903AFFC0
+01FFC0020091B6C7FC033F15FC030715F0DB007F1480040301F0C8FC505479D25F>67
+D<BAFC19F819FF1AE01AF8D8000701F0C7001F13FE06017FDE003F13C0070F7F07037F73
+7F737F747E747E747F86747F8886888688A2747FA3881B7FA288A51D80AF1D00A564A21B
+FF64A3505BA2505BA2505BA2505B505B99C7FC505A1A7F4F485A4F13F0070F5B073F5B4E
+B55A061F49C8FCBB12F81AE097C9FC19F896CAFC59527CD165>I<932603FFF01407047F
+01FF5C0307B600E05B033F03F85B92B700FE5B02039126C003FF5B020F01F8C7EA3FC102
+3F01C0EC0FE391B5C80003B5FC4901FC814949814901E082011F498249498292CA7E4948
+834948835A4A83485B4885A2484984A2485B87A2485B87A25AA298C8FC91CFFCA2B5FCAE
+7E067FB7128080A37E95C76C90C7FC807EA36C7FA26C7FA26C7F7E806C7F137F6D7E816D
+6D93B5FC01077F6D01F85D6D7F6D01FF5D023F01E0EC0FEF020F01FCEC3FE30203903AFF
+E001FF81020091B6C6FC033F03FC133F030703F0130FDB007F02801303040301F8CAFC59
+5479D267>71 D<B912E018FF19F019FE737ED8000701F0C714E0060F7F060313FC06007F
+737E737F8587737FA28785A287A863A261636361634F90C8FC4F5A4F5A06035B060F13E0
+95B5128092B748C9FC19F019C019F09226F0000713FC050013FF063F7F727F727F727F72
+7FA2727FA28486A886A71D707513F8A2851C017301C013F0A273EBE003B86C6D9038F007
+E0739038FC1FC0070190B51280736C1400080F5BCE13F85D537CD162>82
+D<B700FE4AB612F0A5D8000F01E0CA387FC000091FC7FCB3B3B26D611B3E811B7E6D197C
+A26D6D17FC636D6D1601027F4D5A6F4C5A023F170F6E6C4C5A6E6D4B5A6E01E003FFC8FC
+6E01F8EC03FE020001FEEC1FFC923B7FFFE001FFF8031F90B612E00307168003004BC9FC
+041F14F0040091CAFC5C537CD165>85 D<EC3FFE0107B512E0011F14FC017F14FF2701FF
+C00F13C02703FE00037F486C01007F6E6D7E486D80707EA2707EA3707F6C5B6C90C7FC6C
+5AC9FCA60307B5FC0203B6FC147F0103B7FC011FEBF00F017F1300EBFFFC000313F04813
+C0485B4890C7FC5A5B485AF081F012FF5BA35EA26D5C127F6D5C003F03F713C36DD901E3
+14E06CD9C00714FF00079026F01F8114C06C90B5C61480C602FC6D1300011F01F0EB3FFC
+01010180EB07F03C387CB642>97 D<EB3FF8B5FCA51203C6FCB3A4EE7FF00307B5FC031F
+14C0037F14F0913AF9FF007FFCDAFFF8EB1FFF03E001077F03806D7F92C76C7F4A6E7F5C
+4A6F7E85183F85A38584A31A80AD1A00A36061A261187F616E15FF616E4A5B6E4A5B6F49
+5BDACFE04990C7FCDA87F0EB3FFE913A01FE01FFF8496CB65A49013F14C049010749C8FC
+90C813E041547DD249>I<913803FFE0023F13FE91B67E010315E0010F9038003FF8D93F
+FCEB07FC4948497E4948131F4849497E485B485BA24890C7FC5A5B003F6F5A705A705A00
+7F92C8FC5BA312FFAD127F7FA3123F7F6CEE0F80A26C6D141F18006C6D5C6C6D143E6C6D
+147E6C6D5C6D6C495A6DB4EB07F0010F9038C01FE06D90B5128001014AC7FCD9003F13F8
+0203138031387CB63A>I<943803FF80040FB5FCA5EE003F170FB3A4913803FF80023F13
+F849B512FE0107ECFF8F011F9038C03FEF90273FFE0007B5FCD97FF8130149487F484980
+484980484980488291C8FC5A5B123FA2127F5BA312FFAD127FA37F123FA3121F7F6C5E6C
+6D5C5F6C6D91B5FC6C6D5B6C6D4914E0D97FFCD90FEFEBFF80D91FFFEB7F8F010790B512
+0F010114FC6D6C13E00207010049C7FC41547CD249>I<913807FF80027F13F849B512FE
+01076E7E011F010313E0903A3FFC007FF0D97FF06D7E49486D7E4849130F48496D7E4882
+4890C77E1880485A82003F17C0A3485A18E082A212FFA290B8FCA401FCCAFCA6127FA37F
+123FA2EF03E06C7E17076C17C06C6D140F18806C6D141F6C6DEC3F006C6D147ED97FFC49
+5AD91FFFEB07F86D9038E03FF0010390B512C001005D023F01FCC7FC020113E033387CB6
+3C>I<ED1FF8913803FFFE020FEBFF80023F14C09139FFF83FE001039038E0FFF0491380
+49010113F85BEB3FFEA2EB7FFCA26F13F0495AEE7FE0EE1F8093C7FCAEB712C0A5C601F8
+C8FCB3B3A7B612FEA52D547CD328>I<DA1FFE14FE49B539E007FF80010FDAFC1F13C001
+3FDAFF7F13E090267FF807EBFF072701FFE001EBF07F48497E484990387FF83F91C7003F
+14C048EEFC1F489338FE070049021F90C7FCA2003F82A9001F5EA26D143F6C5E6C5E6E13
+7F6C6D495A6C6D485B6CD9F80713804890B6C8FCD803EF14FC01C114E02707C01FFEC9FC
+49CBFCA2487EA37FA27F13FC90B612FE6CEDFFF017FCEFFF806C8318F06C836C837F48B8
+7E1207D80FFCC700037F4848EC003F4848150F48486F138083485A83A56D5D007F18006D
+5D003F5F6C6C4B5A01FE153FD807FFED7FF06C01C049485AC601FC011F1380013FB648C7
+FC010F15F8010115C0D9000F01F8C8FC3B4F7CB542>I<EB3FF8B5FCA51203C6FCB3A4EE
+1FFC93B57E030314E0030F14F892391FC07FFC92397E003FFE03F86D7EECF9F04B6D7FEC
+FBC0ECFF8092C76C7FA25CA25CA45CB3ACB6D8F807B612C0A542537CD249>I<133FEBFF
+C0487F487FA2487FA66C5BA26C5B6C5B013FC7FC90C8FCAEEB1FF8B5FCA512017EB3B3A6
+B612F0A51C547CD324>I<EB3FF8B5FCA51203C6FCB3B3B3B1B612F8A51D537CD224>108
+D<D93FF0D91FF84AB47EB591B56C010F13F8030302E0013F13FE030F6E90B6FCDB3F8090
+27F803F80F7F922A7E007FFC07E0077F000302F890283FFE0F80037FC6D9F1F0011F4948
+7EDAF3E0DAFF3E814B153CDAF7805D92C76C496D7F14FF4A5EA24A5EA34A5EB3ADB6D8F8
+0FB66CB612F8A565367BB56E>I<D93FF0EB1FFCB591B57E030314E0030F14F892391FC0
+7FFC92397E003FFE000302F86D7EC6EBF1F04B6D7FECF3C0ECF78092C76C7F14FF5CA25C
+A45CB3ACB6D8F807B612C0A542367CB549>I<913801FFC0023F13FE91B67E010315E001
+0F018013F8903A3FFC001FFED97FF0EB07FF49486D7F48496D7F48496D7F91C8127F4883
+488349153F001F83A2003F8349151FA2007F83A400FF1880AC007F1800A3003F5F6D153F
+A2001F5FA26C6C4B5AA26C6D4A5A6C5F6C6D495B6C6D495B6D6C4990C7FCD93FFCEB1FFE
+6DB46CB45A010790B512F0010115C0D9003F49C8FC020313E039387CB642>I<D93FF8EB
+7FF0B50107B5FC031F14C0037F14F09126F9FF0013FCDAFFF8EB3FFF000302E0010F7FC6
+02806D7F92C76C7F4A824A804A6E7F85187F85A2183F85A4721380AD4E1300A44E5AA261
+18FF616E5C616E4A5B6E4A5B6F495B03E04990C7FC6FEB7FFE913AF9FE01FFF802F8B65A
+033F14C0030749C8FC030013E093CAFCB1B612F8A5414D7DB549>I<912603FF80EB0F80
+023F01F0131F91B500FC133F010714FF499039C03F807F013F9038000FC0D97FFC903803
+E0FF4948EB01F14849EB00F94849147F485B48824A805A91C87E5AA2485AA4485AAD6C7E
+A4123F7FA27E6E5C6C5E6C7F6E5C6C93B5FC6C6D5B6C6DEB07EFD93FFEEB0FCF903A1FFF
+807F8F01079038FFFE0F010114F86D6C13E00207130091C8FCB1040FB61280A5414D7CB5
+45>I<90393FF001FCB590380FFF804B13E0037F13F09238FE1FF89138F1F83F00019138
+F07FFC6CEBF3E015C0ECF780A2ECFF00EE3FF84AEB1FF0EE0FE093C7FC5CA45CB3ABB612
+FEA52E367DB535>I<903903FFC00E011FEBFC1E90B6127E000315FE3907FE003FD80FF0
+130F4848130348481301491300127F90C8127EA248153EA27FA27F01F091C7FC13FCEBFF
+806C13FEECFFF06C14FE6F7E6C15E06C816C15FC6C81C681133F010F15801301D9000F14
+C0EC003F030713E0150100F880167F6C153FA2161F7EA217C07E6D143F17807F6DEC7F00
+01F85C6DEB03FE9039FF801FFC486CB512F0D8F81F14C0D8F00791C7FC39E0007FF02B38
+7CB634>I<147CA614FCA41301A31303A21307A2130F131F133F137F13FF1203000F90B5
+12FEB7FCA426007FFCC8FCB3A9EE0F80ABEE1F006D7EA2011F143E806D6D5A6DEBC1F86D
+EBFFF001005C023F1380DA03FEC7FC294D7ECB33>I<D93FF8913801FFC0B50207B5FCA5
+0003ED001FC61607B3AE5FA35FA25F137F5F6D6C14F7DC01E713F06D6CD907C7EBFFC090
+3A0FFF801F876D90B51207010114FC6D6C13F0020701C091C7FC42377CB549>I<B600E0
+90381FFFFCA5000101F8C7000113006CEE007C6E15FC017F5E8017016D6C5D17036D5E6F
+13076D5E6F130FA26D6D5C171F6D93C7FC6F5B6D153E6F137E6D157C8117FC027F5CEDFE
+01023F5CEDFF036E5C168316876E5C16CF6E5C16FF6E91C8FCA36E5BA26E5BA26F5AA36F
+5AA26F5AA26F5AA23E367DB445>I<B600E1B6D8800FB5FCA500019026F0000301C0C7EA
+3FE06E6D6DEC0F806CF21F00A26E6D6D5C017F193E6E147F72147E013F197C6E6F14FC6D
+6117FF6F6E13016D4A5E03C06E13036D615E03E001E7EB80076D02075E03F001C313C06D
+4E5A160F03F80181EBE01F6D96C7FC6F48C6FC735A027F49153EDBFE3E90387FF87E023F
+177C167EDBFF7C90383FFCFC6E01FC5D4CEB1FFF6E5FA24C7F6E5F4C7F6E5FA24C7F6E5F
+4C7FA26E94C8FC93C8FC6F5DA2033E157C58367DB45F>I E
+%EndDVIPSBitmapFont
+%DVIPSBitmapFont: Fh ectt1000 10 79
+/Fh 79 127 df<007FB512F0B612F8A36C14F01D0579942C>21 D<121FEA3F80EA7FC0EA
+FFE0B0EA7FC0AEEA1F00C7FCA7121FEA3F80EA7FC0EAFFE0A5EA7FC0EA3F80EA1F000B34
+70B32C>33 D<0107131C90380F803EA8011F137EEC007CA4003FB612E0B712F8A43A003E
+00F800A2EB7E01017C5BA8EBFC0301F85BA2B712F8A4003F15E03A01F007C000A3000313
+0F01E05BA86C486CC7FC25337DB22C>35 D<143814FC13011303EB07F8EB0FF0EB1FC0EB
+3F80EB7F0013FE485A485A5B12075B120F5B485AA2123F90C7FCA25A127EA312FE5AAC7E
+127EA3127F7EA27F121FA26C7E7F12077F12037F6C7E6C7E137FEB3F80EB1FC0EB0FF0EB
+07F8EB03FC130113001438164272B92C>40 D<127012FC7E7E6C7E6C7EEA0FE06C7E6C7E
+6C7E6C7E137F7F1480131F14C0130FEB07E0A214F01303A214F81301A314FC1300AC1301
+14F8A3130314F0A2130714E0A2EB0FC0131F1480133F14005B13FE485A485A485A485AEA
+3FC0485A48C7FC5A5A1270164279B92C>I<EB0380497EA60020140800F8143E00FE14FE
+00FF13C1EBC7C7EBE7CF003FB512F8000F14E0000314806C140038007FFCA248B5FC4814
+80000F14E0003F14F839FFE7CFFEEBC7C7EB07C100FE13C000F8143E0020140800001400
+A66D5A1F247AAA2C>I<EA0F80EA1FE0EA3FF0EA7FF8A213FCA3123F121F120F120013F8
+A21201EA03F01207EA1FE0EA7FC0EAFF80130012FC12700E17718A2C>44
+D<007FB512F0B612F8A36C14F01D0579942C>I<121FEA3F80EA7FC0EAFFE0A5EA7FC0EA
+3F80EA1F000B0B708A2C>I<1507ED0F80A2151F16005D153E157E157CA215FC5D14015D
+14035D14075D140F5D141F92C7FC5C143EA2147E147C14FC5C13015C13035C13075C130F
+5C131F91C8FC5B133EA2137E137C13FC5B12015B12035B12075B120F5B121F90C9FCA25A
+123E127E127C12FC5AA2127021417BB92C>I<EB03F8EB0FFE90383FFF80497F90B57E39
+01FE0FF03903F803F848486C7EEBE0004848137EA248487FA248C7EA1F80A2003E140F00
+7E15C0A3007C140700FC15E0AC6C140F007E15C0A46CEC1F80A36C6CEB3F00A26C6C137E
+6D13FE00075CEBF0016C6C485A3901FE0FF06CB55A6D5B6D5BD90FFEC7FCEB03F823357C
+B32C>I<1307497EA2131FA2133F137F13FF5A1207127FB5FC13DF139FEA7C1F1200B3AE
+007FB512E0B612F0A36C14E01C3477B32C>I<EB0FF890387FFF8048B512E00007804814
+FC391FF80FFE393FE001FF903880007F48C7EA3F80007E141F00FE15C0150F6C15E01507
+A3127E123CC8FCA2150F16C0151F1680153F16005D15FE4A5A14034A5A4A5A4A5A4A5AEC
+FF804948C7FC495A495A495AEB3FE0EB7F8049C8FC485A4848EB03C04848EB07E0EA1FE0
+485A48B6FCB7FCA36C15C023347CB32C>I<EB0FFC90387FFF8048B512E0000714F84880
+391FF807FEEBC0004848137F6D7F1680151FA26C5A6CC7FCC8FC153F16005D15FE14014A
+5AEC1FF890381FFFF0495BA215F86D7F90380007FEEC00FF81ED3F80ED1FC0150FA216E0
+1507A2123C127EB4FC150F16C0A248141F007FEC3F806DEB7F006C6C5B391FF807FE6CB5
+5A6C5C6C14E0C66C1380D90FFCC7FC23357CB32C>I<EC07F04A7E141F143FA2147EA214
+FCEB01F8A2EB03F0EB07E0A2EB0FC0EB1F80A2EB3F00137EA25B485AA2485A5B1207485A
+A2485A48C7FCA2127E5AB712FC16FEA36C15FCC8EAF800AA91387FFFF091B512F8A36E13
+F027347EB32C>I<000FB512FE4880A35D0180C8FCADEB83FE90389FFF8090B512E015F8
+819038FE03FE9038F000FF01C07F49EB3F8090C7121F6C15C0C8120FA2ED07E0A4123C12
+7EB4FC150F16C0A248141F007EEC3F80007FEC7F006C6C5B6D485A391FF80FFC6CB55A6C
+5C000114C06C6C90C7FCEB0FF823347CB22C>I<EC3FC0903801FFF801077F011F7F497F
+90387FE07F9039FF003F804848137FEA03F8485A5B000FEC3F004848131E4990C7FC123F
+90C9FCA25A127EEB03FE90381FFF80D8FC7F13E000FDB57EB67E9038FE07FC9038F001FE
+9038C0007F49EB3F8090C7121F16C048140F16E01507A3127EA47E150F6D14C0001F141F
+6D1480000F143F6DEB7F003907F801FE3903FE07FC6CB55A6C5C6D5B011F1380D907FCC7
+FC23357CB32C>I<1278B712C016E0A316C000FCC7EA3F80ED7F0015FE00785CC712014A
+5A4A5A5D140F5D4A5A143F92C7FC5C147E14FE5C13015CA2495AA213075CA3495AA4495A
+A5133F91C8FCAA131E23357CB32C>I<EB07FC90383FFF8090B512E0000314F84880390F
+FC07FE391FF001FF9038C0007F4848EB3F8090C7121F4815C0007E140FA56CEC1F80A26C
+6CEB3F006D5B390FF001FE3903FC07F86CB55A6C6C13C0D907FCC7FC90387FFFC048B512
+F03903FC07F8390FF001FE391FC0007F497F48C7EA1F80007EEC0FC0A248EC07E0A7007E
+EC0FC0A2007F141F6C6CEB3F806C6CEB7F009038F001FF390FFC07FE6CB55A6C5CC614E0
+013F1380D907FCC7FC23357CB32C>I<EB07FCEB3FFF90B512C0488048803907FC07F839
+0FF001FC48486C7ED83F80137E157F48C77E007EEC1F8012FE5AED0FC0A416E0A37E127E
+007F141F7E6D133F6C6C137F390FF001FF3807FC0F6CB6FC6C14F76C14C7013F130FD90F
+F813C090C7FCA2151F1680153F1600000F5C486C137E486C13FE4A5A4A5A14079038801F
+F0391FE07FE090B55A6C91C7FC6C5B000113F838007FC023357CB32C>I<121FEA3F80EA
+7FC0EAFFE0A5EA7FC0EA3F80EA1F00C7FCAE121FEA3F80EA7FC0EAFFE0A5EA7FC0EA3F80
+EA1F000B2470A32C>I<1502ED0F80151F157F15FF913803FE00EC0FFCEC1FF0EC7FE0EC
+FF80D903FEC7FC495AEB1FF0495AEBFF80000390C8FCEA07FCEA1FF8EA3FE0EAFF8090C9
+FCA27FEA3FE0EA1FF8EA07FC6CB4FCC67FEB3FE06D7EEB07FC6D7E903800FF80EC7FE0EC
+1FF0EC0FFCEC03FE913800FF80157F151F150FED0200212A7BAD2C>60
+D<007FB612F0B712F8A36C15F0CAFCA8007FB612F0B712F8A36C15F025127DA12C>I<12
+2012F87EB4FC7FEA3FE0EA1FF8EA07FC6CB4FCC67FEB3FE06D7EEB07FC6D7E903800FF80
+EC7FE0EC1FF0EC0FFCEC03FE913800FF80157FA215FF913803FE00EC0FFCEC1FF0EC7FE0
+ECFF80D903FEC7FC495AEB1FF0495AEBFF80000390C8FCEA07FCEA1FF8EA3FE0EAFF8090
+C9FC12FC5A1220212A7BAD2C>I<EB3FFE0003B512C0000F14F04814FC4880397FE007FF
+90C7FC00FEEC3F806C141FA3153F007EEC7F00003C5CC7EA03FEEC0FFC4A5AEC3FE04A5A
+4AC7FC495A495A5C13075C130F5CA76D5A90C9FCA8EB0380EB0FE0A2497EA36D5AA2EB03
+8021337BB22C>I<EC7F80903803FFE0010F7F013F7F497F9038FFC0FE3901FE007FD803
+F87F4848EB1F809038E00FCF390FC03FFF48484813C091B5FCEA3F01393E03F87F903907
+F03FE0007EEBE01F397C0FC00FEC8007A2EAFC1F00F8EB0003A900FCEB8007D87C0F14C0
+A2ECC00F3A7E07E01F80003EEBF03F903903F87F00393F01FFFED81F805B6E5A6C6C6C5A
+3907E00FC09039F00007C06C6CEB0FE0D801FE131F3900FFC0FF6DB512C06D1480010FEB
+FE00010313F89038007FC023337CB22C>I<14FE497EA4497FA214EFA2130781A214C7A2
+010F7FA314C390381F83F0A590383F01F8A490387E00FCA549137E90B512FEA34880A290
+38F8003FA34848EB1F80A4000715C049130FD87FFEEBFFFC6D5AB514FE6C15FC497E2734
+7EB32C>I<007FB512E015F8B612FE6C8016C03903F0003FED0FE0ED07F01503A2ED01F8
+A6ED03F0A21507ED0FE0ED1FC0EDFF8090B612005D5D15FF16C09039F0001FE0ED07F0ED
+03F81501ED00FCA216FE167EA616FE16FC1501ED03F8150FED3FF0007FB612E016C0B712
+806CECFE0015F027337FB22C>I<02FF13700107EBE0F84913F9013F13FD4913FFEBFF81
+3901FE007F4848131FD807F0130F1507485A491303485A150148C7FCA25A007EEC00F016
+00A212FE5AAB7E127EA3007F15F06CEC01F8A26C7EA26C6C13036D14F06C6C130716E0D8
+03FC131F6C6CEB3FC03A00FF81FF806DB512006D5B010F5B6D13F00100138025357DB32C
+>I<007FB5FCB612C015F0816C803907E003FEEC00FFED7F80153FED1FC0ED0FE0A21507
+16F0150316F81501A4ED00FCACED01F8A3150316F0A2150716E0150FED1FC0153FED7F80
+EDFF00EC03FE007FB55AB65A5D15C06C91C7FC26337EB22C>I<007FB612F0B712F8A37E
+3903F00001A7ED00F01600A4EC01E04A7EA490B5FCA5EBF003A46E5A91C8FCA5163C167E
+A8007FB612FEB7FCA36C15FC27337EB22C>I<007FB612F8B712FCA37ED803F0C7FCA716
+781600A515F04A7EA490B5FCA5EBF001A46E5A92C7FCAD387FFFE0B5FC805C7E26337EB2
+2C>I<903901FC038090390FFF87C04913EF017F13FF90B6FC4813073803FC01497E4848
+137F4848133F49131F121F5B003F140F90C7FCA2127EED078092C7FCA212FE5AA8913803
+FFF84A13FCA27E007E6D13F89138000FC0A36C141FA27F121F6D133F120F6D137F6C7E6C
+6C13FF6D5A3801FF076C90B5FC6D13EF011F13CF6DEB0780D901FCC7FC26357DB32C>I<
+D87FFEEBFFFCB54813FEA36C486C13FCD807E0EB0FC0B190B6FCA59038E0000FB3D87FFE
+EBFFFCB54813FEA36C486C13FC27337EB22C>I<007FB512F8B612FCA36C14F839000FC0
+00B3B3A5007FB512F8B612FCA36C14F81E3379B22C>I<0107B512804914C0A36D148090
+390003F000B3AF1218127EA2B4FCA24A5A48130F007F131F9038C07FC06CB55A6C91C7FC
+6C5B000313F838007FC022347BB22C>I<D87FFCEB7FF8486CEBFFFCA36C48EB7FF8D807
+C0EB1F80153FED7F00157E5D4A5A14034A5A5D4A5A4A5A143F4AC7FC147E5CEBC1F813C3
+EBC7FCA2EBCFFEEBDFBEEBFFBF141F01FE7F496C7E13F86E7EEBF00301E07FEBC001816E
+7EA2157E153E153F811680ED0FC0A2ED07E0D87FFCEB1FFC486CEB3FFEA36C48EB1FFC27
+337EB22C>I<387FFFE0B57EA36C5BD803F0C8FCB3AE16F0ED01F8A8007FB6FCB7FCA36C
+15F025337DB22C>I<D87FE0EB0FFC486CEB1FFEA26D133F007F15FC000F15E001BC137B
+A4019E13F3A3EB9F01A2018F13E3A21483A2018713C314C7A201831383A214EFA2018113
+03A214FFEB80FEA3147C14381400ACD87FF0EB1FFC486CEB3FFEA36C48EB1FFC27337EB2
+2C>I<D87FF0EB7FFC486CEBFFFEA27F007FEC7FFCD807FEEB07C013DEA213DF13CFA214
+8013C714C0A213C314E0A213C114F0A213C014F8A2147CA3143EA2141E141FA2140F1587
+A2140715C7A2140315E71401A215F71400A215FFD87FFC137F487E153FA26C48EB1F8027
+337EB22C>I<EB7FFF0003B512E0000F14F848804880EBE003EB800048C7127FA2007E80
+A300FE158048141FB3A86C143FA2007E1500A3007F5CA26C6C13FEEBF00790B5FC6C5C6C
+5C000314E0C66C90C7FC21357BB32C>I<007FB512C0B612F88115FF6C15802603F00013
+C0153FED0FE0ED07F0A2150316F81501A6150316F01507A2ED0FE0ED3FC015FF90B61280
+160015FC5D15C001F0C8FCB0387FFF80B57EA36C5B25337EB22C>I<EB7FFF0003B512E0
+000F14F848804880EBF007EB800048C7127FA2007E80A300FE158048141FB3A7EB01F0EB
+03F800FE143F267E01FC1300A2EB00FE007F5C147FD83F8013FEEBF03F90B5FC6C5C6C5C
+000314E0C67E90380007F0A26E7EA26E7EA26E7EA2157FA2153E21407BB32C>I<387FFF
+FCB67E15E015F86C803907E007FE1401EC007F6F7E151FA26F7EA64B5AA2153F4BC7FCEC
+01FE140790B55A5D15E081819038E007FCEC01FE1400157F81A8160FEE1F80A5D87FFEEB
+1FBFB5ECFF00815E6C486D5AC8EA01F029347EB22C>I<90381FF80790B5EA0F804814CF
+000714FF5A381FF01F383FC003497E48C7FC007E147F00FE143F5A151FA46CEC0F00007E
+91C7FC127F7FEA3FE0EA1FFCEBFFC06C13FC0003EBFFC06C14F06C6C7F01077F9038007F
+FEEC07FF02001380153FED1FC0A2ED0FE0A20078140712FCA56CEC0FC0A26CEC1F806D13
+3F01E0EB7F009038FE01FF90B55A5D00F914F0D8F83F13C0D8700790C7FC23357CB32C>
+I<007FB612FCB712FEA43AFC007E007EA70078153CC71400B3AF90383FFFFCA2497F6D5B
+A227337EB22C>I<3B7FFF803FFFC0B56C4813E0A36C496C13C03B03F00001F800B3AF6D
+130300015DA26D130700005D6D130F017F495A6D6C485AECE0FF6DB5C7FC6D5B010313F8
+6D5B9038003F802B3480B22C>I<D87FFCEB7FFC486CEBFFFEA36C48EB7FFCD80FC0EB07
+E06D130F000715C0A36D131F00031580A36D133F00011500A36D5B0000147EA4017E5BA4
+6D485AA490381F83F0A4010F5B14C7A301075BA214EFA201035BA214FFA26D90C7FCA46D
+5A27347EB22C>I<D87FF0EB07FF486C491380A36C486D1300001FC8127CA46C6C5CA76C
+6C495AA4143E147FA33A03E0FF83E0A214F7A201E113C3A3000101E35BA201F113C701F3
+13E7A314C1A200005DA201F713F71480A301FF13FF017F91C7FC4A7EA4013E133E29347F
+B22C>I<3A3FFF03FFE0484913F0148714076C6D13E03A01F800FE007F0000495A13FE01
+7E5BEB7F03013F5B1487011F5B14CF010F5B14FF6D5BA26D90C7FCA26D5AA26D5AA2497E
+A2497EA2497F81EB0FCF81EB1FC7EC87F0EB3F83EC03F8EB7F01017E7FEBFE00497F0001
+147E49137F000380491480151FD87FFEEBFFFC6D5AB514FE6C15FC497E27337EB22C>I<
+D87FFCEB7FFC486CEBFFFEA36C48EB7FFCD807F0EB0FC0151F000315806D133F12016DEB
+7F0012006D137E017E13FE017F5BEB3F01EC81F8131FEC83F0EB0FC314C7903807E7E0A2
+01035B14EF6DB45AA292C7FC7F5C147EB0903807FFE0497FA36D5B27337EB22C>I<007F
+B6FCB71280A46C150021067B7D2C>95 D<3801FFF0000713FE001F6D7E15E048809038C0
+1FF81407EC01FC381F80000006C77EC8127EA3ECFFFE131F90B5FC1203120F48EB807E38
+3FF800EA7FC090C7FC12FE5AA47E007F14FEEB8003383FE01F6CB612FC6C15FE6C14BF00
+01EBFE1F3A003FF007FC27247CA32C>97 D<EA7FF0487EA3127F1201AAEC1FE0ECFFF801
+FB13FE90B6FC16809138F07FC09138801FE091380007F049EB03F85BED01FC491300A216
+FE167EA816FE6D14FCA2ED01F86D13036DEB07F0150F9138801FE09138E07FC091B51280
+160001FB5B01F813F83900F03FC027337FB22C>I<903803FFE0011F13F8017F13FE48B5
+FC48804848C6FCEA0FF0485A49137E4848131890C9FC5A127EA25AA8127EA2127F6C140F
+6DEB1F806C7E6D133F6C6CEB7F003907FE03FF6CB55A6C5C6C6C5B011F13E0010390C7FC
+21247AA32C>I<EC0FFE4A7EA380EC003FAAEB07F8EB3FFE90B512BF4814FF5A3807FC0F
+380FF00348487E497E48487F90C7FC007E80A212FE5AA87E007E5CA2007F5C6C7E5C6C6C
+5A380FF0073807FC1F6CB612FC6CECBFFE6C143FEB3FFC90390FF01FFC27337DB22C>I<
+EB03FE90381FFFC0017F13F048B57E48803907FE03FE390FF800FFD81FE0EB3F805B4848
+EB1FC090C7120F5A007E15E015075AB7FCA416C000FCC9FC7E127EA2127F6CEC03C06DEB
+07E06C7ED80FF0130F6C6CEB3FC001FF13FF000190B512806C1500013F13FC010F13F001
+01138023247CA32C>I<EC0FF8EC3FFE91B5FC4914805B903807FC7F14F090390FE03F00
+14C092C7FCA6007FB512FEB7FCA36C5C26000FC0C7FCB3A8003FB512F04880A36C5C2133
+7DB22C>I<ED03F8903907F80FFC90391FFE3FFE017FB6FC48B7FC48ECFE7F9038FC0FF8
+2607F003133E3A0FE001FC1CD9C0001300001F8049137EA66D13FE000F5CEBE0016C6C48
+5A3903FC0FF048B5FC5D481480D99FFEC7FCEB87F80180C8FCA37F6C7E90B512F06C14FE
+48ECFF804815E04815F03A3FC0001FF848C7EA03FC007E1400007C157C00FC157E48153E
+A46C157E007E15FCD87F801303D83FE0EB0FF8D81FFCEB7FF06CB612E0000315806C1500
+D8003F13F8010713C028387EA42C>I<EA7FF0487EA3127F1201AAEC1FE0EC7FFC9038F9
+FFFE01FB7F90B6FC9138F03F80ECC01F02807FEC000F5B5BA25BB3267FFFE0B5FCB500F1
+1480A36C01E0140029337FB22C>I<1307EB1FC0A2497EA36D5AA20107C7FC90C8FCA738
+7FFFC080B5FC7EA2EA0007B3A8007FB512FCB612FEA36C14FC1F3479B32C>I<140EEC3F
+80A2EC7FC0A3EC3F80A2EC0E0091C7FCA748B512804814C0A37EC7120FB3B3A2141F003C
+1480007E133FB414005CEB01FEEBFFFC6C5B5C001F5B000790C7FC1A467CB32C>I<EA7F
+E0487EA3127F1201AA91381FFFF04A13F8A36E13F0913800FE004A5A4A5A4A5A4A5A4A5A
+4A5A4AC7FC14FEEBF1FC13F3EBF7FE90B5FCA2EC9F80EC0FC001FE7FEBFC07496C7E496C
+7E811400157E811680151F3A7FFFC0FFFCB500E113FEA36C01C013FC27337EB22C>I<38
+7FFFE0B57EA37EEA0003B3B3A5007FB61280B712C0A36C158022337BB22C>I<3A7F83F0
+07E09039CFFC1FF83AFFDFFE3FFCD87FFF13FF91B57E3A07FE1FFC3E01FCEBF83F496C48
+7E01F013E001E013C0A301C01380B33B7FFC3FF87FF0027F13FFD8FFFE6D13F8D87FFC49
+13F0023F137F2D2481A32C>I<397FF01FE039FFF87FFC9038F9FFFE01FB7F6CB6FC0001
+9038F03F80ECC01F02807FEC000F5B5BA25BB3267FFFE0B5FCB500F11480A36C01E01400
+29247FA32C>I<EB07FCEB1FFF017F13C048B512F048803907FC07FC390FF001FE48486C
+7E0180133F003F158090C7121F007EEC0FC0A348EC07E0A76C140F007E15C0A2007F141F
+6C15806D133F6C6CEB7F006D5B6C6C485A3907FC07FC6CB55A6C5C6C6C13C0011F90C7FC
+EB07FC23247CA32C>I<397FF01FE039FFF8FFF801FB13FE90B6FC6C158000019038F07F
+C09138801FE091380007F049EB03F85BED01FC491300A216FE167EA816FE6D14FCA2ED01
+F86D13036DEB07F0150F9138801FE09138E07FC091B51280160001FB5B01F813F8EC3FC0
+91C8FCAD387FFFE0B57EA36C5B27367FA32C>I<903903FC078090391FFF0FC0017F13CF
+48B512EF4814FF3807FE07380FF00148487E49137F4848133F90C7FC48141F127E150F5A
+A87E007E141FA26C143F7F6C6C137F6D13FF380FF0033807FC0F6CB6FC6C14EF6C6C138F
+6D130FEB07F890C7FCAD0203B5FC4A1480A36E140029367DA32C>I<D87FFEEB3FC0B538
+01FFF0020713F8021F13FC6C5B39003F7FE1ECFF019138FC00F84A13704A13005CA25C5C
+A391C8FCAF007FB512E0B67EA36C5C26247EA32C>I<90387FF8700003B512F8120F5A5A
+387FC00F387E00034813015AA36CEB00F0007F140013F0383FFFC06C13FE6CEBFF800003
+14E0C66C13F8010113FCEB0007EC00FE0078147F00FC143F151F7EA26C143F6D133E6D13
+FE9038F007FC90B5FC15F815E000F8148039701FFC0020247AA32C>I<131E133FA9007F
+B6FCB71280A36C1500D8003FC8FCB1ED03C0ED07E0A5EC800F011FEB1FC0ECE07F6DB512
+80160001035B6D13F89038003FE0232E7EAD2C>I<3A7FF003FF80486C487FA3007F7F00
+01EB000FB3A3151FA2153F6D137F3900FE03FF90B7FC6D15807F6D13CF902603FE071300
+29247FA32C>I<3A7FFF01FFFCB514FE148314016C15FC3A03E0000F80A26D131F000115
+00A26D5B0000143EA26D137E017C137CA2017E13FC013E5BA2EB3F01011F5BA21483010F
+5BA214C701075BA214EF01035BA214FF6D90C7FCA26D5A147C27247EA32C>I<D87FFFEB
+7FFF6EB5FCB515806C16004A7ED807C0EB01F0A66C6C495AA3143E147FA2D801F0495AEC
+FF87A214F7A201F113C700005D9038F9E3CFA201FB13EFA3D97BC190C7FC017F13FFA214
+80A2013F5B90381F007C29247FA32C>I<3A3FFF03FFF048018713F8A36C010313F03A00
+FC007E005D90387E01F8013F5BEB1F83EC87E090380FCFC0903807EF80EB03FF6D90C7FC
+5C6D5A147C14FE130180903803EF80903807CFC0EB0FC7EC83E090381F01F0013F7FEB7E
+00017C137C49137E0001803A7FFF01FFFC1483B514FE6C15FC140127247EA32C>I<3A7F
+FF01FFFCB5008113FE148314816C010113FC3A03E0000F806C7E151F6D140012005D6D13
+3E137C017E137E013E137CA2013F13FC6D5BA2EB0F815DA2EB07C1ECC3E0A2EB03E3ECE7
+C0130114F75DEB00FFA292C7FC80A2143EA2147E147CA214FC5CA2EA0C01003F5BEA7F83
+EB87E0EA7E0F495A387FFF806C90C8FC6C5A6C5AEA07E027367EA32C>I<003FB612E048
+15F0A4007EC7EA1FE0ED3FC0ED7F80EDFF004A5A003C495AC7485A4A5A4A5A4A5A4A5A4A
+C7FCEB01FC495AEB0FF0495A495A495A49C8FC4848EB01E04848EB03F0485A485A485A48
+5A485AB7FCA46C15E024247DA32C>I<D801F8131CD807FE133E390FFF807E48EBC0FE48
+EBF3FC397F9FFFF8D8FE0713F0486C13E048C613C00070EB3F001F0A7AB22C>126
+D E
+%EndDVIPSBitmapFont
+%DVIPSBitmapFont: Fi ecss1000 10 33
+/Fi 33 122 df<12FEA7121E123CA312381278A21270A212F00711788617>44
+D<12FEA70707788617>46 D<EC07F8A24A7EA24A7EA2157EEC3F7F143EA291387E3F80A2
+147C02FC7F151FA2D901F87F150F01038014F0A201076D7E14E0A2010F6D7E14C0A2011F
+6D7E1480013F808191C7FC4981167F137E01FE6E7E90B7FCA24882A3D803F8C7EA0FF05B
+00078216075B000F8216035B001F8216015B003F6F7EA248C91380177F127E00FE17C032
+3A7EB937>65 D<913803FF80021F13F891B6FC4915C013075B4948C61380D97FF0130FD9
+FFC013034A13014890C9FC485A485A5B120F5B485AA2485AA3485AA448CAFCAC6C7EA46C
+7EA36C7EA26C7E7F12077F6C7E6C6C15206C6D14E06E1301D97FF0130FD91FFE137F6DB6
+FC6D15C0010115006D5C021F13F0020313802B3E7BBB35>67 D<B4ED3FC0B3A790B7FCA5
+90C8123FB3AA2A3A78B93B>72 D<12FFB3B3B3A4083A79B917>I<B4FCB3B3B090B612C0
+A6223A79B92D>76 D<D8FFC0ED07FFA36D5DA26D5D00FE177FA26D153F0178153EA2017C
+157EA26D15FCA3013F14016D15F8A26E1303010F15F06E1307A2010715E06E130FA20103
+15C06E131FA2010115806E133FA2010015006E5B027C137E027E13FEA2023E5BEC3F01A2
+021F5B1583A2020F5B15C702075BA3913803EFC0A215FF6E5BA26E90C7FCA392C8FCA238
+3A78B949>I<B612C015F815FF8216E090C77FED1FF8ED07FC15036F7E150082821780A2
+163FA4167FA217005E5E15014B5A1507ED1FF8EDFFF090B65A168093C7FC15F815C090CA
+FCB3A6293A79B935>80 D<EB03FF011F13F0017F13FE48B612804815C05A4848C6FCD81F
+F0EB1F804848130701801303007F140090C9FCA212FEA67E7E7F7FEA3FF013FC381FFFC0
+6C13FC6CEBFF806C14E06C14F86C80013F7F01077FD9007F1380020713C0020013E0157F
+ED1FF0150FA2ED07F8A21503A6ED07F0124012600078EC0FE0007C141FB4EC3FC001C0EB
+FF80EBFC036CB61200001F5C6C14F800015C6C6C13C0D907FEC7FC253E7CBB2E>83
+D<B91280A6C7D807F8C8FCB3B3B0313A7DB938>I<EB1FF0EBFFFC000313FF000F148048
+14C09038E01FE09038000FF0001C13070018EB03F81210C7FCEC01FCA7143FEB0FFF90B5
+FC1203120F381FFE01EA3FE0EA7F80130012FEA414037E387F800FEBE03F6CB5FC7E6C13
+F96C13E1D801FEC7FC1E287DA628>97 D<12FEB3A4EB01FCEB0FFF013F13C090B57EB67E
+9038F03FF8EBC007496C7EEB0001486D7EA2157FA3ED3F80AAED7F00A35D5D14016C5CEB
+80039038C00FF89038F03FF090B55A485C6D5BD91FFEC7FC380007F8213D7ABB2B>I<EB
+03FE90381FFFC0017F13E090B512F84814FC3803FC033907F8007CD80FE0133848481308
+1500485AA248C8FCA3127E12FEA9127FA36C7EA26D1302001F14066C6C131E6C6C137E90
+38FC03FE6CB5FCC614FC6D13F0011F13C0903807FC001F287DA625>I<ED3F80B3A4EB0F
+E0EB3FFC90B5FC4814BF4814FF3807FE07380FF801381FE00049137F003F143F5B127F90
+C7FCA312FEAA127FA36C7E157F6C7E6D13FF380FF0033807FE076CB512BF6C143F6C13FE
+EB7FF8D90FE0C7FC213D7DBB2B>I<EB07F8EB1FFE90387FFF8048B512C04814E03907FC
+0FF0390FF003F8EBE001391FC000FC49137C003F147E90C7123E5A127E151F12FEB7FCA5
+00FCC8FCA27EA2127EA2127F7E7F6C7E6D13026C6C130E6C6C133E3903FE01FE6CB5FC6C
+14FC6D13F0011F13C0903803FE0020287EA625>I<14FF010313C0130F5B5BEB7F819038
+FE004049130012015BA21203ADB512FCA5D803F8C7FCB3AE1A3D7FBC19>I<12FEB3A4EB
+01FC90380FFF804913C0017F13E090B512F039FFF81FF8EBE007EBC003018013FC140113
+00A35AB3A71E3C7ABB2B>104 D<12FFA81200AC127FB3B308397BB814>I<12FEB3A5EC03
+FE4A5A4A5A4A5A4A5A4A5A4A5A4990C7FC495A5C495A495A495A495A495A497EB57EA280
+EBF7F813E3EBC1FCEB80FE497E487F6E7E81141F6E7E8114076E7E6E7E811400157F1680
+213C7ABB29>107 D<12FEB3B3B3A6073C7ABB14>I<D901FCEB03F83BFE0FFF801FFF496D
+481380017F6DB512C090B500F114E03CFFF81FFBF03FF0D9E007EBC00F903AC003FF8007
+0180020013F86E140301005BA3485CB3A735267AA542>I<EB01FC39FE0FFF804913C001
+7F13E090B512F039FFF81FF8EBE007EBC003018013FC14011300A35AB3A71E267AA52B>
+I<EB03FE90380FFF80013F13E090B512F848803903FE03FE3907F800FF4848EB7F804913
+3F4848EB1FC04848EB0FE0A290C712074815F0A2007E140300FE15F8A9007FEC07F0A36C
+6CEB0FE0A26C6CEB1FC06D133F6C6CEB7F806C6CEBFF003903FE03FE6CB55A6C5C6D5B01
+1F13C0D903FEC7FC25287EA62A>I<903907F03F80EB3FFCEBFFFE48EBFFBF4814FF3807
+FE07380FF80148487E5B4848137F5B007F143F90C7FCA312FEA97E7EA27F123F6D137F6C
+7E15FF380FF8013807FE0790B6FC6C143FC613FEEB7FF8EB1FE090C7FCAF21367DA52B>
+113 D<14F0EAFC07130F133F137F13FF00FD130013FCEAFFF05B5BA25B90C7FCA35AB3A4
+14267AA51C>I<EB7FE03801FFFC0007EBFF804814C05A383FC03F90380007801401007E
+90C7FCA4127FA26C7E13F0EBFF806C13F06C13FC6C7F6C7FC61480131F010013C0143FEC
+0FE0A21407A3124012600078EB0FC000FE131F39FFC07F8090B5FC6C1400001F5B000313
+F838007FC01B287EA620>I<EA01FCAAB6FCA5D801FCC7FCB3A76D138014013900FF07C0
+14FFA26D1300EB3FFCEB1FE01A307FAE1E>I<00FEEB01FCB3AA1403A214076C131F387F
+807F90B5FC6C13F914F1000F13C1D803FCC7FC1E267AA42B>I<B4EC0FE06CEC1FC0A27F
+003FEC3F80A27F001FEC7F00A26C6C137E15FEA26C6C485AA36C6C485AA3D801FC5B1407
+00005C13FE140F017E5B137F141F013F5BA2149FD91FBFC7FCA3EB0FBE14FE6D5AA32325
+7FA426>I<00FED901FEEB01FC007F17F802031403A2018013DF003FEE07F01407ED9F80
+D81FC016E0020F140F158FD80FE002C013C0030F131F141FED07E0D807F01680021E143F
+143E0003DA03F0130013F8023C5C0001017C147EED01F813FC027814FE0000D9F8005BA2
+4A13FC017C5D167D137E5C013EEC3DF0013F143F5C011F5D161F36257FA439>I<D87F80
+EB0FE0003FEC1FC06C6C133F6DEB7F806C6C1400000714FE6C6C485A3801FC0301FE5B6C
+6C485A6D485A90383F9FC0EB1FDF6DB45A92C7FC6D5A6D5A1301A2497E1307497EECDF80
+90381F9FC090383F0FE0496C7EEBFE0301FC7F00016D7E48486C7E4848137F120F49EB3F
+804848EB1FC0484814E0007FEC0FF048C7EA07F8252580A426>I<B4EC0FE06CEC1FC0A2
+6C7EED3F807F001FEC7F00A26C7E15FE7F00075C1401EA03F85DEBFC0312015D3800FE07
+5D137E140F017F5B133FA290381F9F80A292C7FC130FA2EB079E14DEA2EB03FCA26D5AA3
+5C13035CA213075C130FA2495A1220D8383FC8FCEA3FFEA25B5BEA0FE023367FA426>I
+E
+%EndDVIPSBitmapFont
+%DVIPSBitmapFont: Fj ecit1000 10 17
+/Fj 17 118 df<EA0F80EA1FC0EA3FE0127FA212FFA3EA7FC0EA3F80EA1E000B0B6F8A2C
+>46 D<EC07F0EC1FFCEC7FFE49B5FC5B903907FC1F8090380FF00FEB1FC0D93F8013C090
+387F03E79038FE0FFF48485A495A48485A9038E0FE3F000713FC9039C1F81F80380FC3F0
+1383381F87E0EB07C0D83F0F1400003E1380A25DD87E1F133E007C1300A2157E157C00FC
+14FC00F85C14015D14034A5A00FC139F397C0FFFC05D6D90C7FC387E03FC383E01F8393F
+0007C0140F6C6C487E390FE0FFC090B5FC6C91C7FC6C5BC613F8EB3FC0223375B22C>64
+D<EB03F090380FFC7890383FFFFC5B90B5FC3801FE1F48486C5AEA07F8380FF00713E0D8
+1FC05B1380123F1300485C127EA2140F12FE485CA291381FC180ED87E0143FA2EC7F8F91
+38FF0FC05B6C5AD87E07EB1F80D87F0F133F6CB612006C13DFEC8FFE3907FE07FC3901F8
+01F0232476A32C>97 D<EC7F80903803FFE0010F13F8013F13FC5B9038FFC1FE3801FE00
+3803FC01EA07F8EA0FF001E013FCEA1FC0393F80007090C8FCA2127EA312FE5AA77E007E
+141C007F143E6C6C13FEEBC00F6CB5FC6C14FC6C14F0000114C039007FFE001F2475A32C
+>99 D<913803FF804A13C0A380EC001F1680A2153FA21600A25DA2157EEB03F090380FFC
+FEEB3FFF495B90B5FC3801FE1F3803FC0FD807F85B380FF00713E0EA1FC001805B123F13
+005A007E5CA2140F12FE485CA291381FC180EDC7E0EC3F87A2EC7F8F02FF13C049130F6C
+5AD87E07EB1F80D87F0F133F6CB612006C13DFEC8FFE3907FE07FC3901F801F0233376B2
+2C>I<147F903803FFC0010F13F0013F13F84913FCEBFFC13801FE004848137E485AD80F
+E013FE15FC485A383F800190380007F848133F90B512F015E01580B5EAFE0014F000FCC8
+FCA6127E151C007F143E6C6C13FEEBC00F6CB5FC6C14FC6C14F0000114C039007FFE001F
+2475A32C>I<ED03FCED1FFF4B13C05D17E0EDFE1F15FCA30201EB0FC09238F8078093C7
+FCA40103B512F8825B7F5E90260007F0C7FC5DA5140F5DA5141F5DA5143F92C8FCA45C14
+7EA514FE5CA313015CA31303001C5B127F130700FF5B130F495AEBFF807E6C90C9FCEA1F
+FCEA07F02B457DB22C>I<EC07F091381FFC7891387FFEFC49B5FC5B903807FC3F90380F
+F01F90391FE00FF8ECC007EB3F80EB7F00017E14F013FE5B12014914E0A2150F12034914
+C0A2151FA2ED3F80A2157F15FF4A13006C6C5A6D5A3800FE1F90B55A7F7FEB1FFC903807
+F0FC90C7FC1401A25DA21403A25D003C1307007E495AB4131F4A5A49B45A90B5C7FC5C6C
+13F86C13E0000F90C8FC26367BA32C>I<EA07FF487FA37EEA003F91C8FCA25BA2137EA2
+13FEA25BEC3FC00001EBFFF090B57E81A248EBF0FEECC07E14005B12075B5BA2484813FE
+5D5BA2381FC0015DA2EB8003003FECF03016FCEB000715E04814E1020F13F8007E14C1ED
+C3F000FE14C7EDCFE04814FF6E13C0168048903803FE000070EB00FC263379B22C>I<14
+0FEC1F80EC3FC0A4EC1F80EC0F0091C7FCA8133FEBFFC0000313F05A487FEA1FE1EA3FC1
+1381EA7F01127EEAFE0300FC5B13075C1200130F5C131FA25C133FEC0060EC01F8137F13
+7EEBFE0301FC13F01407EC0FE0141FEC3FC090B512806D13005CEB1FF8EB07E01D3475B3
+2C>I<D9707E137E903A79FF81FF8090B500C713C015CF92B512E002C313C34801831383
+0203EB03F001FE13FE01FC01FC13E0120301F813F8A29039F007F007000716C0A201E013
+E0000F010F130F01C001C01380A2001F011F131F018001801300A25E003F013F133E0100
+1300167E167C485B007E137EA2167F00FE13FE4849EB3F80170000780178130F2C247DA3
+2C>109 D<3901F007F03907F81FFC390FFC7FFE486CB5FC48B6128090383FFE1F14F800
+7E13F014E0EB7FC012FE00FC1380140049133FC6481400A348485B157EA24913FE0003EC
+FC18167EEBF00115F8000715FE020313FC01E013F015F1000F15F8EDF3F001C013FF6E13
+E016C0496C13806CC7EA3E0027247AA32C>I<14FE903807FF80011F13E04913F090B5FC
+48EB83F83903FE01FCEBF800485A4848137E485AA2485A90C7FC5A127EA215FE12FE4814
+FCA2140115F81403EC07F0A2EC0FE0007EEB1FC0EC3F80007F13FFD83F8313006CB45A14
+F86C5B000313C0C648C7FC1F2476A32C>I<903907C00FC090391FF03FF090393FF8FFFC
+EB7FFD91B57E9039FE7FF87F01FC497ED801F801E01380EDC01FECFF8000031400495AA2
+EBF1FCEA00015CA20103143FA24A1400A201075C167E16FE5E010F13014B5A15076E485A
+011F495A6E485A91B55A93C7FC495BEC9FF8EC07E091C9FC5BA2137EA213FEA25BA21201
+A25BA2387FFFE0A2B57E6C5BA2293680A32C>I<D801F8EBFF802607FE0313E0260FFF0F
+13F848019F13FC91B512FED83F9F138190390FFE007E007E49137F4A13FF49485A12FC91
+38E000FE16FC49481378000015005CA249C8FCA3137E13FEA25BA21201A25BA21203A25B
+A35B6C5A282479A32C>114 D<ECFFE0010713FC011F7F497F4914809038FF807FEBFC00
+485A5BA20003EC3F00151C6C6C90C7FC13FEEBFFF86C13FF6D13C0011F13F001077F9038
+003FFC1401EC007EA2001C143E127F157E48147C15FC140148495A39FF803FF06CB55A6C
+5C6C5C000749C7FCC613E0212478A32C>I<01F8EB01C0D803FEEB03E0486C13075A4813
+80D83F9F130F131F007F15C0127E013F131F00FE130000FC15805B017E133F120001FE14
+005B5D120149137EA2EDFE180003157E9038F001FCA2140316FE913807F8FC140F9038F8
+1FF92601FC3F13F890B6FC6C15F090397FFE7FE090393FF83FC090390FE00F8027247AA3
+2C>117 D E
+%EndDVIPSBitmapFont
+%DVIPSBitmapFont: Fk ecss2074 20.74 14
+/Fk 14 121 df<EF7FFCA34D7EA34C7FA34C805F5F040780187FDC0FF87FA2183FDC1FF0
+7FA2181F043F8017E0180F047F8017C004FF6D7E1780A24B6E7E1700A24B6E7F5EA20307
+6E7F5E030F82197F5E031F82193F5E033F6F7EA25E037F6F7EA25E03FF6F7EA24A498185
+93C8FC4A84855D020784855D020F717EA24A48831A3FA24A48831A1F5D027F841A0F5D02
+FF841A074990BAFCA34986A34986A202FCCBFC010F861B7F5C011F861B3F4948851B1FA2
+4948851B0FA24948851B075C4887874890CC148087A248481BC087A248481BE01C7F5B00
+1F1CF01C3F48481BF8A21C1F48481BFC1C0FA248481BFE1C075B5F757BF46A>65
+D<94381FFFE04CB67E040F15F8047F15FF4BB812E0030717F8031F17FE5D92B538F0007F
+4A91C700035B4A01FCEC007F4A01F0150F4A01C015034A90CAFC4A48173C4A481718DAFF
+F094C7FC495B495B495B4990CDFCA2495A495A5C137F5C495AA2485BA2485BA24890CEFC
+A25A5BA2485AA3123F5BA4485AA6485AB16C7EA66C7EA47F121FA36C7EA27F7EA26C7FA2
+6C7FA26C7FA26D7E80133F806D7E6D7EA26D7F6D7F6D6D5F6D6D1707DA7FFC5F6E6C5F6E
+6C177F6E01C0923801FF806E01F015076E01FC151F6E01FF92B5FC6E02F0011F1400033F
+90B712FC6F17F003075F030117806F6C4BC7FC040F15F004011580DC001F01F0C8FC5179
+74F666>67 D<D8FFC0F007FEB3B3B090BBFCA801C0CB1207B3B3B3A34F7570F470>72
+D<EAFFC0B3B3B3B3B3B3A90A756FF42C>I<EAFFC0B3B3B3B3B3B390B912FCA83E7570F4
+56>76 D<D8FFFCF33FFFA36D63A26D98B5FCA36E61A201BF1BFD6E1903019F1BF96E1907
+A3D98FF0F10FF1A3D987F8F11FE1A26E193F01831BC1A26E197F01811B81A26E19FF0180
+1B016F5FA2027F19FE6F1703023F19FCA26F1707021F19F8A26F170F020F19F06F171FA2
+020719E06F173FA2020319C06F177F020119806F17FFA26E1900705DA2037F5F701503A2
+6F6C4B5AA2031F5F70150FA2030F5F70151FA203075F70153FA26F6C4B5AA203015F7015
+FFA26F94C7FC715BA2047F5D711303043F5D711307A2041F5D71130FA2040F5D71131FA2
+04075D71133F04035DA271137F04015DA27113FF7092C8FC1881057F5BA218C3053F5BA3
+94381FE7F8A2050F5B18FFA2715BA3715BA2715BA394CBFCA268756FF48B>I<EF1FFE04
+03B512F0041F14FE047F6E7E4BB712E0030716F8031F16FE037F707E92B5D8F003804A91
+C7003F7F020701F8020713F84A01E002017F4A01806E6C7E4A48C9EA1FFF4A48707F4A48
+707F4949707F03C016004949717E4990CB6C7E49864A181F4948727E4948727EA2494872
+7F4948727FA24849727FA24849737EA291CD123F4888491A1F000F88A2491A0F001F88A2
+491A07003F88A34986A2007F1D80A44986A200FF1DC0B06D62007F1D80A56D62A2003F1D
+00A26D62A2001F64A26D1A1F000F64A26D1A3F6C646E197FA26C6D4F5AA26C6D4E5BA26C
+6D4E5BA26D6C4E5B6D6C4E90C7FCA26D6C4E5A6E183F6D6D4D5A6D626D6D4D5A6F5E6D6D
+4C5B6D01FC040F5B6E6C4C5B6E6C4C90C8FC6E01C0EDFFFE6E6D4A5B6E01FC020F5B0201
+01FF023F13E06EDAF003B55A6F90B75A031F4CC9FC030716F86F5EDB007F1580041F4ACA
+FC040314F09326001FFECBFC627977F675>79 D<B812F0EFFF8018F018FCF0FF808519F0
+8501C0C86C13FE05037FDD007F7F061F7F06077F727F06007F197F737E737E190F868573
+1380A2851BC0A285A21BE0A21A7FA61AFFA21BC0A261A21B8061A24F13006162191F4F5A
+4F5A19FF06035B4E5B061F5B067F5B0503B5C7FC057F5B90B912F86119C06106FCC8FC18
+F0188005F0C9FC01C0CDFCB3B3AF4B756FF466>I<BFFCA8CAD81FF8CAFCB3B3B3B3B3B3
+60757AF46D>84 D<D8FFC0DE1FFEF1FF806C6C22006A507E7F003F575A62886C6C692207
+506C7E6D18FE000F575A1901757E6C6C6908FC191F19036D737E6C575A1AF80707806E18
+0F6C575AF10FF0886C6D06076122FFDF1FE07F6E1803017F5590C7FCF13FC0886D6C7260
+2103F17F80896D6C726021074FC77F80010F087F4C5A604F816D6C073F5F211F4E5A896D
+6C071F5F213F4E48816D6D660A0F167F180F4F816D6D06075F21FF4E5A027F7493C8FC6F
+1803684E48816E6C65761503187F4F826E6C725E20074EC9FC020F755C6F197F200F4D5A
+0207755C6F193F201F02034A48715C6F191F203F606E0207725C0480180F207F606E020F
+725C04C018074E19FF037F9AC9FC051F717E16E04E60033F64053FEF01FF16F0031F4A4E
+5A89057F198395CBFCDB0FF8F287F81E7F4D19C75FDB07FC63F63FCF5FDB03FDF2EFE01E
+1F04FF1AFF5F6F648AA26F49628AA25F047F98CAFC91757EF496>87
+D<EAFFE0ABC7FCB3A9EA7FE0B3B3B3B30B6F74EE25>105 D<ED1FF826FFC001B57E0207
+14E0021F14F8027F8091B67E01C18101C316809038C7FE00D9CFF0011F13C0D9DFE00107
+13E0D9FF80130191C8FC18F049157F5B173F4916F8A249151FA35BA45BB3B3AC354A72C9
+52>110 D<D8FFC0ED1FF8B3B3B0173FA3177FA217FFA26D5C5E007F5D6D5C6D143F01FE
+ECFFDF273FFF8007139F91B6121F6C15FC6C15F86C15E06C15806CECFE006C6C13F0D90F
+FEC9FC354A72C852>117 D<D87FF0EF1FF86C6CEF3FF0001FF07FE06C6CEFFFC06C6C5E
+6C6C18806E4B13006C6D4B5A6C4D5A6D6C4B5A6D7E6D6C4B5A6D6C4B5A6E4B5A01074B5B
+6D6C4A90C7FC6D7F6D6D495A6E6C495A6E6C495A021F4A5A6F5C6E6C137F6E6C495A6E6C
+485B6E018390C8FC6E5C92387FC7FC16EF6FB45A6F5B6F5B6F5B6F5B6F90C9FCA2835D4B
+7F4B7F4B7F92383FEFF892387FC7FCEE83FEEDFF814AEB01FF4A486C7F4A486D7E4A486D
+7E717E4A48804A486D7E4A48130702FF6E7E49496D7E92C78049486E7F49486F7E010F70
+7E4948151F4948824A6F7E017F707E49486F7E48496F13804890C914C0484882F17FE048
+48EF3FF04848EF1FF8484818FC007FF00FFE4848EF07FF484980C849>120
+D E
+%EndDVIPSBitmapFont
+%DVIPSBitmapFont: Fl ecrm0700 7 1
+/Fl 1 66 df<140EA2141FA34A7EA3EC6FC0A2ECEFE014C7A290380183F0A390380301F8
+A201067F1400A249137EA2011C137F01187FA24980013FB5FCA2903960000FC0A201E080
+491307A248486D7EA200038115011207D81FC0497ED8FFF890383FFFE0A22B2A7EA931>
+65 D E
+%EndDVIPSBitmapFont
+%DVIPSBitmapFont: Fm ecrm1000 10 88
+/Fm 88 123 df<486C1360000314E039070001C0000EEB038048EB070000181306003813
+0E0030130C0070131C00601318A200E01338481330A400CEEB338039FF803FE001C013F0
+A3007F131FA2393F800FE0390E0003801C1981B91C>16 D<001C1307007FEB1FC039FF80
+3FE0A201C013F0A3007F131F001CEB073000001300A400011470491360A2000314E090C7
+12C048130100061480000E130348EB070048130E485B006013181C1980B91C>I<DA0FF8
+13FC91397FFF07FF903B01F807DF83C0903A07E001FF0F903B1F8007FE1FE090393F000F
+FC137E16F85B9338F007804848010790C7FC1503ACB812F8A32801F80003F0C7FCB3AB48
+6C497E267FFFE0B512F0A3333B7FBA30>27 D<EC0FF8EC7FFE903901F80780903907E001
+C090391F8000E090383F0007017E497EA25BA2485A6F5AED018092C8FCA9ED03F0B7FCA3
+3901F8000F1503B3AA486C497E267FFFE0B512C0A32A3B7FBA2E>I<EC0FFC91387FFF70
+903901F803F0903807E00790381F800FEB3F00137EA25B150748481303ADB7FCA33901F8
+0003B3AB486C497E267FFFE0B512C0A32A3B7FBA2E>I<DA0FF0EB1FF0DA7FFEEBFFFC90
+3B01F80F83F00F903C07E001CFC00380903C1F8000FF0001C090273F0007FE130F017E49
+48497EA2495CA248485C03076E5A03030203C7FC95C8FCA9F007E0BAFCA33C01F80003F0
+001F1807B3AA486C496C497E267FFFE0B500C1B51280A3413B7FBA45>I<121C127FEAFF
+80A8EA7F00AB123EAB121CABC7FCA8121C127FEAFF80A5EA7F00121C093C79BB17>33
+D<007C137C00FE13FEEAFF01A3EAFE00A7007E13FC007C137CA8003C137800381338A700
+181330171E77BA2A>I<030C497EA2031C1303031891C7FCA303385B03301306A3037013
+0E0360130CA303E0131C4B1318A3020114384B1330A30203147092C71260A34A14E0007F
+B91280BA12C0C7270C000180C7FCA2021C1303021891C8FCA402385B02301306A5027013
+0E0260130CA2BA12C06C1880280001C00038C8FC4A1330A30103147091C71260A34914E0
+01065CA3010E1301010C5CA3011C1303011891C9FCA301385B01301306A30170130E0160
+130CA23A4A7BB945>I<121C127FEAFF80A213C0A3127F121C1200A412011380A2120313
+005A1206120E5A5A5A12600A1979B917>39 D<146014E0EB01C0EB0380EB0700130E131E
+5B5BA25B485AA2485AA212075B120F90C7FCA25A121EA2123EA35AA65AB2127CA67EA312
+1EA2121F7EA27F12077F1203A26C7EA26C7E1378A27F7F130E7FEB0380EB01C0EB00E014
+60135278BD20>I<12C07E12707E7E7E120F6C7E6C7EA26C7E6C7EA21378A2137C133C13
+3E131EA2131F7FA21480A3EB07C0A6EB03E0B2EB07C0A6EB0F80A31400A25B131EA2133E
+133C137C1378A25BA2485A485AA2485A48C7FC120E5A5A5A5A5A13527CBD20>I<EB0380
+497EA7397803803C00FC147E00FE14FE397F8383FC393FC387F8390FE38FE03903FBBF80
+3900FFFE00EB3FF8EB0FE0A2EB3FF8EBFFFE3903FBBF80390FE38FE0393FC387F8397F83
+83FC39FE0380FE00FC147E0078143C390007C000A76D5A1F247BBD2A>I<1530B3A8B912
+FCA2C80030C8FCB3A836367BAF41>I<121C127FEAFF80A213C0A3127F121C1200A41201
+1380A2120313005A1206120E5A5A5A12600A19798817>I<B512FCA516057F941C>I<121C
+127FEAFF80A5EA7F00121C0909798817>I<1506A2150E150CA2151C151815381530A215
+701560A215E015C0A214011580A2140315005C1406A2140E140CA2141C1418A214381430
+A21470146014E05CA213015CA2130391C7FCA25B1306A2130E130C131C1318A213381330
+A213701360A213E05BA212015B120390C8FCA25A1206A2120E120CA2121C1218A2123812
+3012701260A212E05AA21F537BBD2A>I<EB03F8EB1FFF90387E0FC09038F803E03901E0
+00F0484813780007147C48487FA248C77EA2481580A3007EEC0FC0A500FE15E0B3007E15
+C0A4007F141F6C1580A36C1500A26C6C133EA26C6C5B6C6C5BEBF0013900F803E090387E
+0FC0D91FFFC7FCEB03F823397DB62A>I<EB01C013031307131F13FFB5FCA2131F1200B3
+B3A7497E007FB512F0A31C3779B62A>I<EB0FF0EB7FFE48B57E3903E03FE0390F000FF0
+001E6D7E001C6D7E486D7E5A6E7E126012FE6CEC7F807FA56CC7FC121CC8FCEDFF00A25D
+14015D14035D4A5A4A5A5D4A5A4AC7FC147E5C495A14E0495A495A49C8FC011EEB01805B
+5B49130348481400485A485A90C75A48B6FC5A5A485CB6FCA321377CB62A>I<EB07F8EB
+3FFF90B512C03901F80FF03903C007F848486C7E390E0001FEEA0F80391FE000FF7FA56C
+5A6C5AC7485AA25D14035D4A5A5DEC0F80027FC7FCEB1FFCECFF809038000FE06E7EEC01
+FC816E7EED7F80A216C0A2153F16E0A2121EEA7F80A2487EA316C0157F491480007EC7FC
+0070ECFF006C495A121E390F8003F83907F00FF00001B512C06C6C90C7FCEB0FF823397D
+B62A>I<1538A2157815F8A2140114031407A2140F141F141B14331473146314C3130114
+83EB030313071306130C131C131813301370136013C01201EA038013005A120E120C5A12
+3812305A12E0B712F8A3C73803F800AA4A7E0103B512F8A325387EB72A>I<0006140CD8
+0780133C9038F003F890B5FC5D5D158092C7FC14FC38067FE090C9FCAAEB07F8EB1FFE90
+38780F809038E007E03907C003F0496C7E130000066D7E81C8FC8181A21680A4121C127F
+5A7FA390C713005D12FC00605C12704A5A6C5C6C1303001E495A6C6C485A3907E03F8000
+01B5C7FC38007FFCEB1FE021397CB62A>I<EC3FC0903801FFF0010713FC90380FE03E90
+383F800790387E001F49EB3F804848137F485A12075B000FEC3F0049131E001F91C7FC5B
+123FA3127F90C9FCEB01FC903807FF8039FF1E07E090383801F0496C7E01607F01E0137E
+497F16805BED1FC0A390C713E0A57EA47F123F16C0A2001FEC3F807F000F15006D5B0007
+14FE6C6C5B6C6C485A3900FE07F090387FFFC0011F90C7FCEB03FC23397DB62A>I<1230
+1238123E003FB612E0A316C05A168016000070C712060060140E5D5D00E014304814705D
+5DC712014A5A4AC7FC1406140E5CA25C1478147014F05C1301A213035C1307A2130FA313
+1F5CA2133FA5137FA96DC8FC131E233A7BB72A>I<EB03F8EB1FFF017F13C09038FC07F0
+3901E001F83903C0007C4848133C90C7123E48141E000E141F001E80A3121FA26D5B6D13
+1E7FD80FF85B6D137C01FF13786C6D5A6CEBE3E0ECF780C601FFC7FC6D5A6D6C7E010F13
+E0013F7F01F97F3901E07FFE48486C7E380F800F48486C1380001E010113C0487F007C14
+3F0078EC1FE0150F00F81407481403A21501A36C15C0A200781403007C15806C14076CEC
+0F006C6C131ED807E0137C3903F803F0C6B55A013F1380D907FCC7FC23397DB62A>I<EB
+03F8EB1FFF017F13C03901FC07E048486C7E3907E001F8000F6D7E4848137E5B003F80A2
+48C71380A25AED1FC0A516E0A56C143FA36C7E157F121F6C6C13FF6C6C13DF0003130139
+01F0039F3900FC0F1FD93FFC13C0EB07F090C7FCA2153F1680A216005D120F486C137E48
+6C5BA24A5A4A5A49485A381F000F001CEB1F80260F807FC7FC3807FFFE000113F838003F
+C023397DB62A>I<121C127FEAFF80A5EA7F00121CC7FCB2121C127FEAFF80A5EA7F0012
+1C092479A317>I<121C127FEAFF80A5EA7F00121CC7FCB2121C127FEAFF80A213C0A312
+7F121C1200A412011380A2120313005A1206120E5A5A5A12600A3479A317>I<007FB812
+F8B912FCCCFCB0B912FC6C17F836147B9E41>61 D<EB3FE03801FFFE3907C03F80390E00
+0FC0003CEB07F000301303007014F8007C130100FE14FC7EA4127E003CEB03F8C7FCEC07
+F0A2EC0FE0EC1F80EC3F00147E147C5C495A5C495A5CA249C7FCA31306AA90C8FCA8130E
+EB3F80497EA56D5A010EC7FC1E3B7CBA27>63 D<EC03FF021F13E09138FC00FCD901E013
+1ED90780EB0780011EC7EA01E00138EC00704981498148488148488190C97E48D901FC14
+80000ED907FFEB01C0000C90391F03C000001C90267E00E013E000184901701360263801
+F86D13700030496D13300103EC0FE0267007E00107133800601718495AA200E0171C4848
+48150CAA6C6C7E1260A26D6C151C00701718263003F0130F0101141F00386D013F133826
+1800FC01771330001C017E9038E3F070000C90261F03C113E0000E903A07FF00FFC06CD9
+01FCEB3F006C90CAFC7F6C7E6C7E13706D167C011EED03FCD90780EC1FF0D901E0ECFF80
+D900FC90383FFC00021FB51280020301E0C7FC363C7BBA41>I<1538A3157CA315FEA34A
+7EA34A6C7EA202077FEC063FA2020E7FEC0C1FA2021C7FEC180FA202387FEC3007A20270
+7FEC6003A202C07F1501A2D901807F81A249C77F167FA20106810107B6FCA24981010CC7
+121FA2496E7EA3496E7EA3496E7EA213E0707E1201486C81D80FFC02071380B56C90B512
+FEA3373C7DBB3E>I<B712E016FC16FF0001903980007FC06C90C7EA1FE0707E707E707E
+A2707EA283A75F16035F4C5A4C5A4C5A4C5AEEFF8091B500FCC7FCA291C7EA7F80EE1FE0
+EE07F0707E707E83707EA21880177F18C0A7188017FFA24C13005F16034C5AEE1FF8486D
+EB7FF0B812C094C7FC16F832397DB83B>I<913A01FF800180020FEBE003027F13F8903A
+01FF807E07903A03FC000F0FD90FF0EB039F4948EB01DFD93F80EB00FF49C8127F01FE15
+3F12014848151F4848150FA248481507A2485A1703123F5B007F1601A35B00FF93C7FCAD
+127F6DED0180A3123F7F001F160318006C7E5F6C7E17066C6C150E6C6C5D00001618017F
+15386D6C5CD91FE05C6D6CEB03C0D903FCEB0F80902701FF803FC7FC9039007FFFFC020F
+13F002011380313D7BBA3C>I<B712C016F816FE000190398001FF806C90C7EA3FE0EE0F
+F0EE03F8707E707E177FA2EF3F8018C0171F18E0170F18F0A3EF07F8A418FCAC18F8A4EF
+0FF0A218E0A2171F18C0EF3F80A2EF7F0017FE4C5A4C5AEE0FF0EE3FE0486DEBFF80B8C7
+FC16F816C036397DB83F>I<B812FEA3000190388000076C90C8FC173F838383A383A318
+80170116C0A394C7FCA31501A21503150F91B5FCA3EC000F15031501A21500A21860A318
+E093C712C0A41701A3EF0380A21707A2170F173F177F486D903807FF00B9FCA333397EB8
+38>I<B812F8A30001903880001F6C90C71201EE00FC177C173C171CA2170CA4170E1706
+A2ED0180A21700A41503A21507151F91B5FCA3EC001F15071503A21501A692C8FCAD4813
+C0B612C0A32F397DB836>I<DBFF8013C0020FEBF001023F13FC9139FF803F03903A03FC
+000787D90FF0EB03CF4948EB00EF4948147F4948143F49C8121F485A4848150F48481507
+A248481503A2485A1701123F5B007F1600A448481600AB93B6FCA26C7E9338007FE0EF3F
+C0A2123F7F121FA26C7EA26C7EA26C7E6C7E6C6C157F6D7E6D6C14FF6D6C14EFD90FF8EB
+03C7D903FEEB0783903A00FFC03F0191393FFFFC00020F01F0130002001380383D7CBA41
+>I<B648B512FEA30001902680000313006C90C76C5AB3A491B6FCA391C71201B3A6486D
+497EB648B512FEA337397DB83E>I<B612C0A3C6EBC0006D5AB3B3AD497EB612C0A31A39
+7EB81E>I<013FB512E0A39039001FFC00EC07F8B3B3A3123FEA7F80EAFFC0A44A5A1380
+D87F005B0070131F6C5C6C495A6C49C7FC380781FC3801FFF038007F80233B7DB82B>I<
+B649B5FCA3000101809038007FF06C90C8EA3F80053EC7FC173C17385F5F4C5A4C5A4CC8
+FC160E5E5E5E5E4B5AED0780030EC9FC5D153E157E15FF5C4A7F4A6C7E140E4A6C7E4A6C
+7E14704A6C7E4A6C7E14804A6C7E6F7EA26F7F707EA2707E707EA2707EA2707E707EA270
+7E707F8484486D497FB6011FEBFF80A339397DB841>I<B612E0A3000101C0C8FC6C90C9
+FCB3AD1718A517381730A31770A317F0A216011603160FEE1FE0486D13FFB8FCA32D397D
+B834>I<B5933807FFF86E5DA20001F0FC002600DFC0ED1BF8A2D9CFE01533A3D9C7F015
+63A3D9C3F815C3A2D9C1FCEC0183A3D9C0FEEC0303A2027F1406A36E6C130CA36E6C1318
+A26E6C1330A36E6C1360A26E6C13C0A3913901FC0180A3913900FE0300A2ED7F06A3ED3F
+8CA2ED1FD8A3ED0FF0A3486C6D5A487ED80FFC6D48497EB500C00203B512F8A2ED018045
+397DB84C>I<B5913807FFFE8080C69238007FE06EEC1F80D9DFF0EC0F001706EBCFF8EB
+C7FCA2EBC3FEEBC1FFA201C07F6E7EA26E7E6E7E81140F6E7E8114036E7E168080ED7FC0
+16E0153FED1FF0ED0FF8A2ED07FCED03FEA2ED01FF6F1386A2EE7FC6EE3FE6A2EE1FF6EE
+0FFEA216071603A216011600A2177E486C153E487ED80FFC151EB500C0140EA217063739
+7DB83E>I<EC03FF021F13E09138FE01FC903901F8007ED907E0EB1F8049486D7ED93F80
+EB07F049C76C7E01FE6E7E48486E7E49157E0003167F4848ED3F80A24848ED1FC0A2001F
+17E049150F003F17F0A3007F17F8491507A300FF17FCAC007F17F86D150FA3003F17F0A2
+6C6CED1FE0A36C6CED3FC0000717806D157F000317006C6C15FEA26C6C4A5A017F4A5A6D
+6C495A6D6C495AD907E0EB1F80D903F8017FC7FC903900FE01FC91381FFFE0020390C8FC
+363D7BBA41>I<B712C016FC16FF0001D9800013C06C90C7EA1FE0707EEE03F883707EA2
+707EA21880A71800A24C5AA24C5A5FEE0FF04C5AEEFF8091B548C7FC16F091CAFCB3A548
+7FB6FCA331397EB838>I<EC03FF021F13E09138FE01FC903901F8007ED907E0EB1F8049
+486D7ED93F80EB07F049C76C7E01FE6E7E48486E7EA24848157F0007178049153F000F17
+C049151F001F17E0A24848ED0FF0A3007F17F8A2491507A200FF17FCAC007F17F8A26D15
+0FA2003F17F0A26C6CED1FE0A36C6CED3FC00007027C14804AB4FC3C03F80383807F003B
+01FC0701C0FEEC0E002600FE0CEBE1FC017FEC63F8D93F8CEB77F0D91FCCEB3FE0D907EE
+14806DB449C7FC0100D981FC130CEC1FFF0203131C91C7001E131C161F183CEF807CEFC0
+F8EE0FFFA318F08218E07013C07013809338007E00364B7BBA41>I<B612FEEDFFE016F8
+000190388007FE6C90C76C7EEE3FC0707E707E707EA2707EA283A65FA24C5AA24C5A4C5A
+EE3F8004FFC8FCED07FC91B512E05E9138000FF0ED03F8ED00FE82707E707EA2161F83A5
+83A6F00180A217F8160F1803486D01071400B66D6C5A04011306933800FE0ECAEA3FFCEF
+07F0393B7DB83D>I<D90FF813C090383FFE0190B512813903F807E33907E000F7484813
+7F4848133F48C7121F003E140F007E1407A2007C140312FC1501A36C1400A37E6D14006C
+7E7F13F86CB47E6C13F8ECFF806C14E06C14F86C14FEC680013F1480010714C0EB007F02
+0713E0EC007FED3FF0151F150FED07F8A200C01403A21501A37EA216F07E15036C15E06C
+14076C15C06C140F6DEB1F80D8FBF0EB3F00D8F0FE13FE39E03FFFF8010F13E0D8C00190
+C7FC253D7CBA2E>I<003FB812E0A3D9C003EB001F273E0001FE130348EE01F000781600
+00701770A300601730A400E01738481718A4C71600B3B0913807FF80011FB612E0A33539
+7DB83C>I<B6903807FFFEA3000101809038007FE06C90C8EA1F80EF0F001706B3B2170E
+6D150C80171C133F17186D6C14385F6D6C14F06D6C5C6D6C495A6D6CEB07806D6C49C7FC
+91387F807E91381FFFF8020713E09138007F80373B7DB83E>I<B500FC91387FFF80A300
+03018091380FFC006C90C8EA07E0715A6C705A6E1403017F93C7FCA280013F1506A26E14
+0E011F150C80010F5DA28001075DA26E147001031560A26D6C5CA2806D4A5AA2ED800302
+7F91C8FCA291383FC006A215E0021F5BA2EDF01C020F1318A26E6C5AA215FC02035BA2ED
+FEE002015BA26E6C5AA36FC9FCA3153EA2151CA3393B7EB83E>I<B5D8FC07B5D8F001B5
+FCA30007902780001FFEC7EA1FF86C48C7D80FF8EC07E000010307ED03C01B807F6C6F6C
+1500A26E5F017F6E6C1406A280013F4A6C5CA280011F4A6D5BEE067FA26D6C010E6D5BEE
+0C3FA26D6C011C6D5BEE181FA26D6C6F5BEE300FA26D6C6F485AEE6007A26D6C4CC7FC93
+38C003FCA203805D913B7F818001FE06A203C1150EDA3FC3C7EAFF0CA203E3151CDA1FE6
+EC7F98A215F6DA0FFCEC3FF0A302075E4B141FA202035E4B140FA202015E4B1407A20200
+93C8FC4B80503B7EB855>I<007FB590383FFFFCA3C601F801071380D97FE0D903FCC7FC
+013FEC01F06D6C5C5F6D6C5C6D6C13034CC8FC6D6C1306160E6D6C5B6DEB801816389138
+7FC0306E6C5A16E06E6C5A91380FF18015FB6EB4C9FC5D14036E7EA26E7F6F7EA24B7E15
+DF9138019FF09138038FF8150F91380607FC91380E03FE140C4A6C7EEC38000230804A6D
+7E14E04A6D7E49486D7E130391C76C7E01066E7E130E010C6E7E011C1401013C8101FE82
+2607FF80010713E0B500E0013FEBFF80A339397EB83E>I<B500FE91383FFFE0A3000301
+E0913807FE00C649EC03F0017F6F5A606D6C5D6D6C140395C7FC6D6C1406A26D6C5C6D6C
+141C17186D6C143817306D6D5B6E6C13E05F91383FE0015F91381FF003DA0FF890C8FC16
+06913807FC0E160C913803FE1C913801FF185E6E13B016E0157F6F5AB3A24B7E023FB512
+C0A33B397FB83E>I<003FB7FCA39039FC0001FE01C0130349495A003EC7FC003C4A5A5E
+0038141F00784A5A12704B5A5E006014FF4A90C7FCA24A5A5DC712074A5AA24A5A5D143F
+4A5AA24A5A92C8FC5B495AA2495A5C130F4948EB0180A2495A5C137F495A16034890C7FC
+5B1203485AEE0700485A495C001F5D48485C5E4848495A49130FB8FCA329397BB833>I<
+EAFFFCA2EAFC00B3B3B3B3A7EAFFFCA20E5379BD17>I<EAFFFCA21200B3B3B3B3A712FF
+A20E537FBD17>93 D<007FB81280B912C0A26C17803204797041>95
+D<EB1FE0EBFFFC3803E03F3907000F80390F8007E0486C6C7E13E06E7EA26E7E6C5A6C5A
+C8FCA4147FEB07FFEB3FE0EBFE00EA03F8EA0FF0EA1FC0123F485A90C7FC160C12FEA314
+01A26C13036CEB077C903980063E18383FC01E3A0FE0781FF03A03FFF00FE03A007F8007
+C026277DA52A>97 D<EA03F012FFA3120F1203B0EC1FE0EC7FF89038F1E03E9039F3801F
+809039F7000FC001FEEB07E049EB03F049EB01F85BED00FCA216FEA2167E167FAA167E16
+FEA216FC15016D14F8ED03F07F01EEEB07E001C6EB0FC09039C7801F00903881E07E9038
+00FFF8C7EA1FC0283B7EB92E>I<EB03FC90381FFF8090387E03E03901F80070484813F8
+3907E001FC380FC003A2EA1F80123F90380001F848EB00F01500A2127E12FEAA127E127F
+A26C14067F001F140E6D130C000F141C6C6C13386C6C13706C6C13E039007C07C090381F
+FF00EB07F81F277DA525>I<ED0FC0EC03FFA3EC003F150FB0EB03F8EB1FFF90387E078F
+9038F801EF3903F0007F4848133F4848131FA24848130F123F90C7FC5AA2127E12FEAA12
+7E127FA27EA26C6C131FA26C6C133F6C6C137F6C6CEBEFF03A01F801CFFF39007C078F90
+381FFE0FD907F813C0283B7DB92E>I<EB07F8EB1FFF90387C0FC03901F803E03903F001
+F0D807E013F8380FC0004848137CA248C7127E153E5A153F127E12FEA3B7FCA248C8FCA5
+127EA2127FA26C14037F001F14076C6C13060007140E6D131CD801F013386C6C13709038
+7E03E090381FFF80903803FC0020277EA525>I<147E903803FF8090380FC1E0EB1F8790
+383F0FF0137EA213FCA23901F803C091C7FCADB512FCA3D801F8C7FCB3AB487E387FFFF8
+A31C3B7FBA19>I<ED03F090390FF00FF890393FFC3C3C9039F81F707C3901F00FE03903
+E007C03A07C003E010000FECF000A248486C7EA86C6C485AA200075C6C6C485A6D485A6D
+48C7FC38073FFC38060FF0000EC9FCA4120FA213C06CB512C015F86C14FE6CECFF804815
+C03A0F80007FE048C7EA0FF0003E140348140116F8481400A56C1401007C15F06CEC03E0
+003F1407D80F80EB0F80D807E0EB3F003901FC01FC39007FFFF0010790C7FC26387EA52A
+>I<EA03F012FFA3120F1203B0EC0FF0EC3FFCECF03F9039F1C01F809039F3800FC0EBF7
+0013FE496D7EA25BA35BB3A3486C497EB500C1B51280A3293A7EB92E>I<EA0380EA0FE0
+487EA56C5AEA0380C8FCAAEA03F012FFA312071203B3AA487EB512C0A312387EB717>I<
+EB01C0EB07F0EB0FF8A5EB07F0EB01C090C7FCAAEB01F813FFA313071301B3B3A2123C12
+7E00FF13F01303A214E038FE07C0127C383C0F00EA0FFEEA03F8154984B719>I<EA03F0
+12FFA3120F1203B1913801FFFCA39138007FC01600157C15705D4A5A4A5A4AC7FC141E14
+38147814FC13F1EBF3FEEBF73F01FE7FEBF81F496C7E8114076E7E6E7E811400157E157F
+811680ED1FC0486CEB3FF0B500C0B5FCA3283A7EB92C>I<EA03F012FFA3120F1203B3B3
+AD487EB512C0A3123A7EB917>I<2703F00FF0EB1FE000FFD93FFCEB7FF8913AF03F01E0
+7E903BF1C01F83803F3D0FF3800FC7001F802603F70013CE01FE14DC49D907F8EB0FC0A2
+495CA3495CB3A3486C496CEB1FE0B500C1B50083B5FCA340257EA445>I<3903F00FF000
+FFEB3FFCECF03F9039F1C01F803A0FF3800FC03803F70013FE496D7EA25BA35BB3A3486C
+497EB500C1B51280A329257EA42E>I<EB03FE90380FFF8090383E03E09038F800F84848
+137C48487F48487F4848EB0F80001F15C090C712074815E0A2007EEC03F0A400FE15F8A9
+007E15F0A2007F14076C15E0A26C6CEB0FC0000F15806D131F6C6CEB3F006C6C137EC66C
+13F890387E03F090381FFFC0D903FEC7FC25277EA52A>I<3903F01FE000FFEB7FF89038
+F1E07E9039F3801F803A07F7000FC0D803FEEB07E049EB03F04914F849130116FC150016
+FEA3167FAA16FEA3ED01FCA26DEB03F816F06D13076DEB0FE001F614C09039F7803F0090
+38F1E07E9038F0FFF8EC1FC091C8FCAB487EB512C0A328357EA42E>I<D903F813C09038
+1FFE0190387E07819038FC01C33903F000E3000714774848133749133F001F141F485A15
+0F48C7FCA312FEAA127FA37E6D131F121F6D133F120F6C6C137F6C6C13EF3901F801CF39
+007E078F90381FFE0FEB07F890C7FCABED1FE00203B5FCA328357DA42C>I<3807E01F00
+FFEB7FC09038E1E3E09038E387F0380FE707EA03E613EE9038EC03E09038FC0080491300
+A45BB3A2487EB512F0A31C257EA421>I<EBFF03000313E7380F80FF381E003F487F487F
+00707F12F0A2807EA27EB490C7FCEA7FE013FF6C13E06C13F86C7F00037FC67F01071380
+EB007F141F00C0EB0FC01407A26C1303A37E15806C13077EEC0F00B4131E38F3C07C38E1
+FFF038C03F801A277DA521>I<1318A51338A31378A313F8120112031207001FB5FCB6FC
+A2D801F8C7FCB215C0A93800FC011580EB7C03017E13006D5AEB0FFEEB01F81A347FB220
+>I<D803F0EB07E000FFEB01FFA3000FEB001F00031407B3A4150FA3151F12016D133F00
+00EC77F86D9038E7FF8090383F03C790381FFF87903A03FC07E00029267EA42E>I<B538
+803FFEA33A0FF8000FF06C48EB07E00003EC03C06D148000011500A26C6C1306A26D130E
+017E130CA26D5BA2EC8038011F1330A26D6C5AA214E001075BA2903803F180A3D901FBC7
+FCA214FF6D5AA2147CA31438A227257EA32C>I<B53A1FFFE03FFEA3260FF8009038000F
+F86C48017EEB03E018C00003023EEB0180A26C6C013FEB0300A36C6CEC8006156FA2017E
+9038EFC00C15C7171CD93F01EBE01815830281EBF038D91F831430150102C3EBF8709026
+0FC6001360A2D907E66D5A02EC137CA2D903FCEB7F804A133FA2010192C7FC4A7FA20100
+141E4A130E0260130C37257EA33C>I<B538807FFFA33A03FE003FF00001EC1F80000092
+C7FC017E131C6D13186D6C5AECC070010F5B6D6C5AECF180EB03FB6DB4C8FC6D5AA2147F
+804A7E8114CF903801C7E090380383F090380703F8EB0601496C7E011C137E49137F0178
+7F496D7E486C80000FEC3FF0D8FFFE90B51280A329247FA32C>I<B538803FFEA33A0FF8
+000FF06C48EB07C00003EC03806C7E16007F00001406A2017E5BA2137F6D5BA26D6C5AA2
+ECC070010F1360A26D6C5AA214F101035BA2D901FBC7FCA214FF6D5AA2147CA31438A214
+30A214701460A25CA2EA7C0100FE5B130391C8FC1306EAFC0EEA701C6C5AEA1FF0EA0FC0
+27357EA32C>I<003FB512FCA2EB8003D83E0013F8003CEB07F00038EB0FE012300070EB
+1FC0EC3F800060137F150014FE495AA2C6485A495AA2495A495A495AA290387F000613FE
+A2485A485A0007140E5B4848130C4848131CA24848133C48C7127C48EB03FC90B5FCA21F
+247EA325>I E
+%EndDVIPSBitmapFont
+end
+%%EndProlog
+%%BeginSetup
+%%Feature: *Resolution 600dpi
+TeXDict begin
+%%BeginPaperSize: Letter
+letter
+%%EndPaperSize
+
+%%EndSetup
+%%Page: 1 1
+1 0 bop 0 162 a Fm(11)17 b(11)h(T)249 180 y(E)295 162
+y(X)h(L)398 145 y Fl(A)435 162 y Fm(T)481 180 y(E)527
+162 y(X)0 348 y Fk(Linux)54 b(PCMCIA)f(HO)l(WTO)p 0 461
+3900 24 v 0 575 a Fm(Da)n(vid)27 b(Hinds,)h Fj(dhinds@pcmcia.so)o(urc)o
+(ef)o(or)o(ge.)o(or)o(g)p Fm(.)1370 b(v2.57,)26 b(04)g(April)i(2000)0
+881 y Fi(This)i(do)r(cument)f(describ)r(es)h(ho)n(w)f(to)g(install)g
+(and)h(use)f(PCMCIA)i(Ca)n(rd)e(Services)h(fo)n(r)g(Linux,)h(and)f
+(answ)n(ers)f(some)g(frequently)0 994 y(ask)n(ed)38 b(questions.)69
+b(The)39 b(latest)g(version)f(of)h(this)g(do)r(cument)f(can)h(alw)n(a)n
+(ys)e(b)r(e)i(found)g(at)78 b Fh(<ftp://sourcefo)o(rge)o(.o)o(rg)o(/)0
+1108 y(pcmcia/doc>)p Fi(.)32 b(An)c(HTML)g(version)f(is)g(at)55
+b Fh(<http://pcmcia.so)o(ur)o(cef)o(or)o(ge)o(.or)o(g>)o
+Fi(.)0 1439 y Fg(Con)l(ten)l(ts)0 1679 y Ff(1)77 b(General)31
+b(information)f(and)i(hardw)m(are)i(requiremen)m(ts)1700
+b(1)125 1835 y Fm(1.1)83 b(In)n(tro)r(duction)26 b(.)41
+b(.)h(.)f(.)h(.)f(.)h(.)g(.)f(.)h(.)f(.)h(.)f(.)h(.)f(.)h(.)g(.)f(.)h
+(.)f(.)h(.)f(.)h(.)g(.)f(.)h(.)f(.)h(.)f(.)h(.)g(.)f(.)h(.)f(.)h(.)f(.)
+h(.)f(.)h(.)g(.)f(.)h(.)f(.)h(.)f(.)h(.)134 b(1)125 1991
+y(1.2)83 b(Cop)n(yrigh)n(t)26 b(notice)i(and)f(disclaimer)i(.)41
+b(.)h(.)f(.)h(.)g(.)f(.)h(.)f(.)h(.)f(.)h(.)g(.)f(.)h(.)f(.)h(.)f(.)h
+(.)g(.)f(.)h(.)f(.)h(.)f(.)h(.)f(.)h(.)g(.)f(.)h(.)f(.)h(.)f(.)h(.)134
+b(1)125 2148 y(1.3)83 b(What)28 b(is)g(the)g(latest)f(v)n(ersion,)f
+(and)i(where)f(can)g(I)g(get)h(it?)66 b(.)42 b(.)f(.)h(.)f(.)h(.)f(.)h
+(.)g(.)f(.)h(.)f(.)h(.)f(.)h(.)f(.)h(.)g(.)f(.)h(.)f(.)h(.)f(.)h(.)134
+b(1)125 2304 y(1.4)83 b(What)28 b(systems)f(are)g(supp)r(orted?)44
+b(.)e(.)f(.)h(.)f(.)h(.)g(.)f(.)h(.)f(.)h(.)f(.)h(.)g(.)f(.)h(.)f(.)h
+(.)f(.)h(.)g(.)f(.)h(.)f(.)h(.)f(.)h(.)f(.)h(.)g(.)f(.)h(.)f(.)h(.)f(.)
+h(.)134 b(1)125 2461 y(1.5)83 b(What)28 b(cards)f(are)f(supp)r(orted?)
+71 b(.)41 b(.)h(.)f(.)h(.)f(.)h(.)g(.)f(.)h(.)f(.)h(.)f(.)h(.)g(.)f(.)h
+(.)f(.)h(.)f(.)h(.)g(.)f(.)h(.)f(.)h(.)f(.)h(.)f(.)h(.)g(.)f(.)h(.)f(.)
+h(.)f(.)h(.)134 b(2)125 2617 y(1.6)83 b(When)28 b(will)g(m)n(y)g(fa)n
+(v)n(orite)e(\(unsupp)r(orted\))i(card)e(b)r(ecome)i(supp)r(orted?)84
+b(.)42 b(.)f(.)h(.)f(.)h(.)f(.)h(.)f(.)h(.)g(.)f(.)h(.)f(.)h(.)f(.)h(.)
+134 b(3)125 2774 y(1.7)83 b(Mailing)27 b(lists)h(and)f(other)g
+(information)g(sources)80 b(.)41 b(.)h(.)f(.)h(.)g(.)f(.)h(.)f(.)h(.)f
+(.)h(.)g(.)f(.)h(.)f(.)h(.)f(.)h(.)f(.)h(.)g(.)f(.)h(.)f(.)h(.)f(.)h(.)
+134 b(3)125 2930 y(1.8)83 b(Wh)n(y)28 b(don't)g(y)n(ou)f(distribute)g
+(binaries?)45 b(.)c(.)h(.)g(.)f(.)h(.)f(.)h(.)f(.)h(.)g(.)f(.)h(.)f(.)h
+(.)f(.)h(.)g(.)f(.)h(.)f(.)h(.)f(.)h(.)f(.)h(.)g(.)f(.)h(.)f(.)h(.)f(.)
+h(.)134 b(3)125 3087 y(1.9)83 b(Wh)n(y)28 b(is)f(the)h(pac)n(k)-5
+b(age)26 b(so)h(darned)g(big?)55 b(.)41 b(.)h(.)g(.)f(.)h(.)f(.)h(.)f
+(.)h(.)g(.)f(.)h(.)f(.)h(.)f(.)h(.)g(.)f(.)h(.)f(.)h(.)f(.)h(.)f(.)h(.)
+g(.)f(.)h(.)f(.)h(.)f(.)h(.)134 b(3)0 3326 y Ff(2)77
+b(Compilation)28 b(and)33 b(installation)2532 b(4)125
+3483 y Fm(2.1)83 b(Prerequisites)27 b(and)g(k)n(ernel)g(setup)32
+b(.)42 b(.)f(.)h(.)f(.)h(.)g(.)f(.)h(.)f(.)h(.)f(.)h(.)g(.)f(.)h(.)f(.)
+h(.)f(.)h(.)g(.)f(.)h(.)f(.)h(.)f(.)h(.)f(.)h(.)g(.)f(.)h(.)f(.)h(.)f
+(.)h(.)134 b(4)125 3639 y(2.2)83 b(Installation)67 b(.)41
+b(.)h(.)f(.)h(.)f(.)h(.)g(.)f(.)h(.)f(.)h(.)f(.)h(.)f(.)h(.)g(.)f(.)h
+(.)f(.)h(.)f(.)h(.)g(.)f(.)h(.)f(.)h(.)f(.)h(.)g(.)f(.)h(.)f(.)h(.)f(.)
+h(.)f(.)h(.)g(.)f(.)h(.)f(.)h(.)f(.)h(.)134 b(5)125 3796
+y(2.3)83 b(Startup)28 b(options)41 b(.)g(.)h(.)f(.)h(.)g(.)f(.)h(.)f(.)
+h(.)f(.)h(.)f(.)h(.)g(.)f(.)h(.)f(.)h(.)f(.)h(.)g(.)f(.)h(.)f(.)h(.)f
+(.)h(.)g(.)f(.)h(.)f(.)h(.)f(.)h(.)f(.)h(.)g(.)f(.)h(.)f(.)h(.)f(.)h(.)
+134 b(7)125 3952 y(2.4)83 b(System)28 b(resource)e(settings)42
+b(.)f(.)h(.)f(.)h(.)f(.)h(.)f(.)h(.)g(.)f(.)h(.)f(.)h(.)f(.)h(.)g(.)f
+(.)h(.)f(.)h(.)f(.)h(.)g(.)f(.)h(.)f(.)h(.)f(.)h(.)f(.)h(.)g(.)f(.)h(.)
+f(.)h(.)f(.)h(.)134 b(8)125 4109 y(2.5)83 b(Notes)28
+b(ab)r(out)f(sp)r(eci\034c)h(Lin)n(ux)f(distributions)60
+b(.)41 b(.)h(.)f(.)h(.)f(.)h(.)g(.)f(.)h(.)f(.)h(.)f(.)h(.)g(.)f(.)h(.)
+f(.)h(.)f(.)h(.)f(.)h(.)g(.)f(.)h(.)f(.)h(.)f(.)h(.)134
+b(9)315 4265 y(2.5.1)94 b(Debian)22 b(.)42 b(.)f(.)h(.)f(.)h(.)g(.)f(.)
+h(.)f(.)h(.)f(.)h(.)f(.)h(.)g(.)f(.)h(.)f(.)h(.)f(.)h(.)g(.)f(.)h(.)f
+(.)h(.)f(.)h(.)g(.)f(.)h(.)f(.)h(.)f(.)h(.)f(.)h(.)g(.)f(.)h(.)f(.)h(.)
+f(.)h(.)134 b(9)315 4421 y(2.5.2)94 b(Red)28 b(Hat,)g(Caldera,)e
+(Mandrak)n(e)63 b(.)42 b(.)g(.)f(.)h(.)f(.)h(.)f(.)h(.)g(.)f(.)h(.)f(.)
+h(.)f(.)h(.)g(.)f(.)h(.)f(.)h(.)f(.)h(.)f(.)h(.)g(.)f(.)h(.)f(.)h(.)f
+(.)h(.)93 b(10)315 4578 y(2.5.3)h(Slac)n(kw)n(are)48
+b(.)42 b(.)f(.)h(.)g(.)f(.)h(.)f(.)h(.)f(.)h(.)f(.)h(.)g(.)f(.)h(.)f(.)
+h(.)f(.)h(.)g(.)f(.)h(.)f(.)h(.)f(.)h(.)g(.)f(.)h(.)f(.)h(.)f(.)h(.)f
+(.)h(.)g(.)f(.)h(.)f(.)h(.)f(.)h(.)93 b(10)315 4734 y(2.5.4)h(SuSE)85
+b(.)42 b(.)f(.)h(.)f(.)h(.)g(.)f(.)h(.)f(.)h(.)f(.)h(.)f(.)h(.)g(.)f(.)
+h(.)f(.)h(.)f(.)h(.)g(.)f(.)h(.)f(.)h(.)f(.)h(.)g(.)f(.)h(.)f(.)h(.)f
+(.)h(.)f(.)h(.)g(.)f(.)h(.)f(.)h(.)f(.)h(.)93 b(10)0
+4974 y Ff(3)77 b(Resolving)29 b(installation)i(and)h(con\034guration)g
+(problems)1601 b(11)125 5130 y Fm(3.1)83 b(Base)27 b(PCMCIA)h(k)n
+(ernel)f(mo)r(dules)h(do)f(not)g(load)22 b(.)42 b(.)f(.)h(.)f(.)h(.)g
+(.)f(.)h(.)f(.)h(.)f(.)h(.)g(.)f(.)h(.)f(.)h(.)f(.)h(.)f(.)h(.)g(.)f(.)
+h(.)f(.)h(.)f(.)h(.)93 b(11)125 5287 y(3.2)83 b(Some)28
+b(clien)n(t)f(driv)n(er)g(mo)r(dules)g(do)g(not)h(load)22
+b(.)42 b(.)f(.)h(.)f(.)h(.)f(.)h(.)g(.)f(.)h(.)f(.)h(.)f(.)h(.)g(.)f(.)
+h(.)f(.)h(.)f(.)h(.)f(.)h(.)g(.)f(.)h(.)f(.)h(.)f(.)h(.)93
+b(12)125 5443 y(3.3)83 b(In)n(terrupt)28 b(scan)e(failures)61
+b(.)42 b(.)f(.)h(.)f(.)h(.)f(.)h(.)f(.)h(.)g(.)f(.)h(.)f(.)h(.)f(.)h(.)
+g(.)f(.)h(.)f(.)h(.)f(.)h(.)g(.)f(.)h(.)f(.)h(.)f(.)h(.)f(.)h(.)g(.)f
+(.)h(.)f(.)h(.)f(.)h(.)93 b(13)125 5600 y(3.4)83 b(IO)28
+b(p)r(ort)f(scan)g(failures)51 b(.)42 b(.)g(.)f(.)h(.)f(.)h(.)f(.)h(.)f
+(.)h(.)g(.)f(.)h(.)f(.)h(.)f(.)h(.)g(.)f(.)h(.)f(.)h(.)f(.)h(.)g(.)f(.)
+h(.)f(.)h(.)f(.)h(.)f(.)h(.)g(.)f(.)h(.)f(.)h(.)f(.)h(.)93
+b(14)125 5756 y(3.5)83 b(Memory)27 b(prob)r(e)g(failures)45
+b(.)d(.)f(.)h(.)f(.)h(.)f(.)h(.)f(.)h(.)g(.)f(.)h(.)f(.)h(.)f(.)h(.)g
+(.)f(.)h(.)f(.)h(.)f(.)h(.)g(.)f(.)h(.)f(.)h(.)f(.)h(.)f(.)h(.)g(.)f(.)
+h(.)f(.)h(.)f(.)h(.)93 b(14)125 5913 y(3.6)83 b(F)-7
+b(ailure)27 b(to)h(detect)g(card)f(insertions)f(and)i(remo)n(v)-5
+b(als)41 b(.)h(.)f(.)h(.)g(.)f(.)h(.)f(.)h(.)f(.)h(.)g(.)f(.)h(.)f(.)h
+(.)f(.)h(.)f(.)h(.)g(.)f(.)h(.)f(.)h(.)f(.)h(.)93 b(15)125
+6069 y(3.7)83 b(In)n(terrupt)28 b(deliv)n(ery)e(problems)61
+b(.)41 b(.)h(.)f(.)h(.)f(.)h(.)g(.)f(.)h(.)f(.)h(.)f(.)h(.)g(.)f(.)h(.)
+f(.)h(.)f(.)h(.)g(.)f(.)h(.)f(.)h(.)f(.)h(.)f(.)h(.)g(.)f(.)h(.)f(.)h
+(.)f(.)h(.)93 b(16)125 6226 y(3.8)83 b(System)28 b(resource)e(starv)-5
+b(ation)20 b(.)42 b(.)f(.)h(.)f(.)h(.)f(.)h(.)g(.)f(.)h(.)f(.)h(.)f(.)h
+(.)g(.)f(.)h(.)f(.)h(.)f(.)h(.)g(.)f(.)h(.)f(.)h(.)f(.)h(.)f(.)h(.)g(.)
+f(.)h(.)f(.)h(.)f(.)h(.)93 b(16)125 6382 y(3.9)83 b(Resource)27
+b(con\035ict)g(only)g(with)h(t)n(w)n(o)f(cards)g(inserted)k(.)42
+b(.)f(.)h(.)g(.)f(.)h(.)f(.)h(.)f(.)h(.)g(.)f(.)h(.)f(.)h(.)f(.)h(.)f
+(.)h(.)g(.)f(.)h(.)f(.)h(.)f(.)h(.)93 b(17)125 6539 y(3.10)41
+b(Device)28 b(con\034guration)e(do)r(es)h(not)h(complete)84
+b(.)41 b(.)h(.)f(.)h(.)f(.)h(.)g(.)f(.)h(.)f(.)h(.)f(.)h(.)g(.)f(.)h(.)
+f(.)h(.)f(.)h(.)f(.)h(.)g(.)f(.)h(.)f(.)h(.)f(.)h(.)93
+b(17)0 6778 y Ff(4)77 b(Usage)31 b(and)i(features)2885
+b(18)125 6935 y Fm(4.1)83 b(T)-7 b(o)r(ols)27 b(for)g(con\034guring)f
+(and)i(monitoring)e(PCMCIA)j(devices)36 b(.)42 b(.)f(.)h(.)f(.)h(.)g(.)
+f(.)h(.)f(.)h(.)f(.)h(.)f(.)h(.)g(.)f(.)h(.)f(.)h(.)f(.)h(.)93
+b(18)315 7091 y(4.1.1)h(The)28 b(cardmgr)d(con\034guration)h(daemon)j
+(.)42 b(.)f(.)h(.)f(.)h(.)g(.)f(.)h(.)f(.)h(.)f(.)h(.)g(.)f(.)h(.)f(.)h
+(.)f(.)h(.)f(.)h(.)g(.)f(.)h(.)f(.)h(.)f(.)h(.)93 b(18)315
+7247 y(4.1.2)h(The)28 b(so)r(c)n(k)n(et)e(status)h(\034le,)h(stab)79
+b(.)41 b(.)h(.)g(.)f(.)h(.)f(.)h(.)f(.)h(.)g(.)f(.)h(.)f(.)h(.)f(.)h(.)
+g(.)f(.)h(.)f(.)h(.)f(.)h(.)f(.)h(.)g(.)f(.)h(.)f(.)h(.)f(.)h(.)93
+b(18)315 7404 y(4.1.3)h(The)28 b(cardctl)f(and)g(cardinfo)g(utilities)
+46 b(.)41 b(.)h(.)f(.)h(.)f(.)h(.)g(.)f(.)h(.)f(.)h(.)f(.)h(.)g(.)f(.)h
+(.)f(.)h(.)f(.)h(.)f(.)h(.)g(.)f(.)h(.)f(.)h(.)f(.)h(.)93
+b(19)315 7560 y(4.1.4)h(Inserting)27 b(and)g(ejecting)h(cards)46
+b(.)41 b(.)h(.)g(.)f(.)h(.)f(.)h(.)f(.)h(.)g(.)f(.)h(.)f(.)h(.)f(.)h(.)
+g(.)f(.)h(.)f(.)h(.)f(.)h(.)f(.)h(.)g(.)f(.)h(.)f(.)h(.)f(.)h(.)93
+b(19)315 7717 y(4.1.5)h(Card)27 b(Services)f(and)i(A)n(dv)-5
+b(anced)27 b(P)n(o)n(w)n(er)f(Managemen)n(t)48 b(.)41
+b(.)h(.)f(.)h(.)g(.)f(.)h(.)f(.)h(.)f(.)h(.)f(.)h(.)g(.)f(.)h(.)f(.)h
+(.)f(.)h(.)93 b(20)315 7873 y(4.1.6)h(Sh)n(utting)28
+b(do)n(wn)f(the)h(PCMCIA)g(system)56 b(.)41 b(.)h(.)f(.)h(.)g(.)f(.)h
+(.)f(.)h(.)f(.)h(.)g(.)f(.)h(.)f(.)h(.)f(.)h(.)f(.)h(.)g(.)f(.)h(.)f(.)
+h(.)f(.)h(.)93 b(20)125 8030 y(4.2)83 b(Ov)n(erview)26
+b(of)i(the)g(PCMCIA)g(con\034guration)e(scripts)55 b(.)41
+b(.)h(.)g(.)f(.)h(.)f(.)h(.)f(.)h(.)g(.)f(.)h(.)f(.)h(.)f(.)h(.)f(.)h
+(.)g(.)f(.)h(.)f(.)h(.)f(.)h(.)93 b(20)125 8186 y(4.3)83
+b(PCMCIA)29 b(net)n(w)n(ork)d(adapters)62 b(.)41 b(.)h(.)f(.)h(.)f(.)h
+(.)g(.)f(.)h(.)f(.)h(.)f(.)h(.)g(.)f(.)h(.)f(.)h(.)f(.)h(.)g(.)f(.)h(.)
+f(.)h(.)f(.)h(.)f(.)h(.)g(.)f(.)h(.)f(.)h(.)f(.)h(.)93
+b(21)315 8343 y(4.3.1)h(Net)n(w)n(ork)26 b(device)i(parameters)66
+b(.)41 b(.)h(.)g(.)f(.)h(.)f(.)h(.)f(.)h(.)g(.)f(.)h(.)f(.)h(.)f(.)h(.)
+g(.)f(.)h(.)f(.)h(.)f(.)h(.)f(.)h(.)g(.)f(.)h(.)f(.)h(.)f(.)h(.)93
+b(22)p eop
+%%Page: 2 2
+2 1 bop 0 -167 3900 5 v 0 -200 a Ff(CONTENTS)3319 b Fm(2)315
+162 y(4.3.2)94 b(Commen)n(ts)27 b(ab)r(out)h(sp)r(eci\034c)f(cards)53
+b(.)42 b(.)f(.)h(.)f(.)h(.)f(.)h(.)g(.)f(.)h(.)f(.)h(.)f(.)h(.)g(.)f(.)
+h(.)f(.)h(.)f(.)h(.)f(.)h(.)g(.)f(.)h(.)f(.)h(.)f(.)h(.)93
+b(24)315 318 y(4.3.3)h(Diagnosing)26 b(problems)h(with)h(net)n(w)n(ork)
+e(adapters)35 b(.)42 b(.)f(.)h(.)f(.)h(.)f(.)h(.)g(.)f(.)h(.)f(.)h(.)f
+(.)h(.)f(.)h(.)g(.)f(.)h(.)f(.)h(.)f(.)h(.)93 b(24)125
+475 y(4.4)83 b(PCMCIA)29 b(serial)d(and)i(mo)r(dem)f(devices)83
+b(.)42 b(.)g(.)f(.)h(.)f(.)h(.)f(.)h(.)g(.)f(.)h(.)f(.)h(.)f(.)h(.)g(.)
+f(.)h(.)f(.)h(.)f(.)h(.)f(.)h(.)g(.)f(.)h(.)f(.)h(.)f(.)h(.)93
+b(25)315 631 y(4.4.1)h(Serial)27 b(device)g(parameters)39
+b(.)i(.)h(.)f(.)h(.)g(.)f(.)h(.)f(.)h(.)f(.)h(.)g(.)f(.)h(.)f(.)h(.)f
+(.)h(.)g(.)f(.)h(.)f(.)h(.)f(.)h(.)f(.)h(.)g(.)f(.)h(.)f(.)h(.)f(.)h(.)
+93 b(26)315 788 y(4.4.2)h(Commen)n(ts)27 b(ab)r(out)h(sp)r(eci\034c)f
+(cards)53 b(.)42 b(.)f(.)h(.)f(.)h(.)f(.)h(.)g(.)f(.)h(.)f(.)h(.)f(.)h
+(.)g(.)f(.)h(.)f(.)h(.)f(.)h(.)f(.)h(.)g(.)f(.)h(.)f(.)h(.)f(.)h(.)93
+b(26)315 944 y(4.4.3)h(Diagnosing)26 b(problems)h(with)h(serial)e
+(devices)59 b(.)41 b(.)h(.)g(.)f(.)h(.)f(.)h(.)f(.)h(.)g(.)f(.)h(.)f(.)
+h(.)f(.)h(.)f(.)h(.)g(.)f(.)h(.)f(.)h(.)f(.)h(.)93 b(27)125
+1101 y(4.5)83 b(PCMCIA)29 b(parallel)d(p)r(ort)h(devices)84
+b(.)41 b(.)h(.)f(.)h(.)g(.)f(.)h(.)f(.)h(.)f(.)h(.)g(.)f(.)h(.)f(.)h(.)
+f(.)h(.)g(.)f(.)h(.)f(.)h(.)f(.)h(.)f(.)h(.)g(.)f(.)h(.)f(.)h(.)f(.)h
+(.)93 b(27)315 1257 y(4.5.1)h(P)n(arallel)26 b(device)i(parameters)i(.)
+42 b(.)f(.)h(.)g(.)f(.)h(.)f(.)h(.)f(.)h(.)g(.)f(.)h(.)f(.)h(.)f(.)h(.)
+g(.)f(.)h(.)f(.)h(.)f(.)h(.)f(.)h(.)g(.)f(.)h(.)f(.)h(.)f(.)h(.)93
+b(28)315 1413 y(4.5.2)h(Diagnosing)26 b(problems)h(with)h(parallel)e(p)
+r(ort)i(devices)56 b(.)42 b(.)f(.)h(.)f(.)h(.)g(.)f(.)h(.)f(.)h(.)f(.)h
+(.)f(.)h(.)g(.)f(.)h(.)f(.)h(.)f(.)h(.)93 b(28)125 1570
+y(4.6)83 b(PCMCIA)29 b(SCSI)f(adapters)39 b(.)i(.)h(.)f(.)h(.)f(.)h(.)f
+(.)h(.)g(.)f(.)h(.)f(.)h(.)f(.)h(.)g(.)f(.)h(.)f(.)h(.)f(.)h(.)g(.)f(.)
+h(.)f(.)h(.)f(.)h(.)f(.)h(.)g(.)f(.)h(.)f(.)h(.)f(.)h(.)93
+b(29)315 1726 y(4.6.1)h(SCSI)28 b(device)f(parameters)60
+b(.)41 b(.)h(.)f(.)h(.)g(.)f(.)h(.)f(.)h(.)f(.)h(.)g(.)f(.)h(.)f(.)h(.)
+f(.)h(.)g(.)f(.)h(.)f(.)h(.)f(.)h(.)f(.)h(.)g(.)f(.)h(.)f(.)h(.)f(.)h
+(.)93 b(30)315 1883 y(4.6.2)h(Commen)n(ts)27 b(ab)r(out)h(sp)r
+(eci\034c)f(cards)53 b(.)42 b(.)f(.)h(.)f(.)h(.)f(.)h(.)g(.)f(.)h(.)f
+(.)h(.)f(.)h(.)g(.)f(.)h(.)f(.)h(.)f(.)h(.)f(.)h(.)g(.)f(.)h(.)f(.)h(.)
+f(.)h(.)93 b(31)315 2039 y(4.6.3)h(Diagnosing)26 b(problems)h(with)h
+(SCSI)g(adapters)76 b(.)42 b(.)g(.)f(.)h(.)f(.)h(.)f(.)h(.)g(.)f(.)h(.)
+f(.)h(.)f(.)h(.)f(.)h(.)g(.)f(.)h(.)f(.)h(.)f(.)h(.)93
+b(31)125 2196 y(4.7)83 b(PCMCIA)29 b(memory)d(cards)49
+b(.)41 b(.)h(.)f(.)h(.)f(.)h(.)f(.)h(.)g(.)f(.)h(.)f(.)h(.)f(.)h(.)g(.)
+f(.)h(.)f(.)h(.)f(.)h(.)g(.)f(.)h(.)f(.)h(.)f(.)h(.)f(.)h(.)g(.)f(.)h
+(.)f(.)h(.)f(.)h(.)93 b(32)315 2352 y(4.7.1)h(Memory)27
+b(device)g(parameters)71 b(.)41 b(.)h(.)g(.)f(.)h(.)f(.)h(.)f(.)h(.)g
+(.)f(.)h(.)f(.)h(.)f(.)h(.)g(.)f(.)h(.)f(.)h(.)f(.)h(.)f(.)h(.)g(.)f(.)
+h(.)f(.)h(.)f(.)h(.)93 b(32)315 2509 y(4.7.2)h(Using)27
+b(linear)g(\035ash)g(memory)g(cards)78 b(.)41 b(.)h(.)f(.)h(.)f(.)h(.)g
+(.)f(.)h(.)f(.)h(.)f(.)h(.)g(.)f(.)h(.)f(.)h(.)f(.)h(.)f(.)h(.)g(.)f(.)
+h(.)f(.)h(.)f(.)h(.)93 b(33)125 2665 y(4.8)83 b(PCMCIA)29
+b(A)-7 b(T)g(A/IDE)28 b(card)f(driv)n(es)j(.)41 b(.)h(.)f(.)h(.)g(.)f
+(.)h(.)f(.)h(.)f(.)h(.)g(.)f(.)h(.)f(.)h(.)f(.)h(.)g(.)f(.)h(.)f(.)h(.)
+f(.)h(.)f(.)h(.)g(.)f(.)h(.)f(.)h(.)f(.)h(.)93 b(34)315
+2822 y(4.8.1)h(A)-7 b(T)g(A/IDE)29 b(\034xed-disk)e(device)g
+(parameters)22 b(.)42 b(.)f(.)h(.)g(.)f(.)h(.)f(.)h(.)f(.)h(.)g(.)f(.)h
+(.)f(.)h(.)f(.)h(.)f(.)h(.)g(.)f(.)h(.)f(.)h(.)f(.)h(.)93
+b(34)315 2978 y(4.8.2)h(Diagnosing)26 b(problems)h(with)h(A)-7
+b(T)g(A/IDE)29 b(adapters)d(.)41 b(.)h(.)f(.)h(.)f(.)h(.)g(.)f(.)h(.)f
+(.)h(.)f(.)h(.)f(.)h(.)g(.)f(.)h(.)f(.)h(.)f(.)h(.)93
+b(35)125 3135 y(4.9)83 b(Multifunction)29 b(cards)22
+b(.)41 b(.)h(.)g(.)f(.)h(.)f(.)h(.)f(.)h(.)f(.)h(.)g(.)f(.)h(.)f(.)h(.)
+f(.)h(.)g(.)f(.)h(.)f(.)h(.)f(.)h(.)g(.)f(.)h(.)f(.)h(.)f(.)h(.)f(.)h
+(.)g(.)f(.)h(.)f(.)h(.)f(.)h(.)93 b(35)0 3374 y Ff(5)77
+b(A)m(dv)-5 b(anced)33 b(topics)2997 b(35)125 3531 y
+Fm(5.1)83 b(Resource)27 b(allo)r(cation)f(for)h(PCMCIA)i(devices)24
+b(.)41 b(.)h(.)f(.)h(.)f(.)h(.)g(.)f(.)h(.)f(.)h(.)f(.)h(.)g(.)f(.)h(.)
+f(.)h(.)f(.)h(.)f(.)h(.)g(.)f(.)h(.)f(.)h(.)f(.)h(.)93
+b(35)125 3687 y(5.2)83 b(Ho)n(w)27 b(can)h(I)f(ha)n(v)n(e)g(separate)f
+(device)h(setups)h(for)f(home)g(and)g(w)n(ork?)74 b(.)41
+b(.)h(.)g(.)f(.)h(.)f(.)h(.)f(.)h(.)f(.)h(.)g(.)f(.)h(.)f(.)h(.)f(.)h
+(.)93 b(36)125 3843 y(5.3)83 b(Bo)r(oting)27 b(from)g(a)g(PCMCIA)i
+(device)78 b(.)42 b(.)f(.)h(.)g(.)f(.)h(.)f(.)h(.)f(.)h(.)g(.)f(.)h(.)f
+(.)h(.)f(.)h(.)g(.)f(.)h(.)f(.)h(.)f(.)h(.)f(.)h(.)g(.)f(.)h(.)f(.)h(.)
+f(.)h(.)93 b(37)315 4000 y(5.3.1)h(The)28 b(p)r(cinitrd)g(help)r(er)f
+(script)47 b(.)42 b(.)f(.)h(.)g(.)f(.)h(.)f(.)h(.)f(.)h(.)g(.)f(.)h(.)f
+(.)h(.)f(.)h(.)g(.)f(.)h(.)f(.)h(.)f(.)h(.)f(.)h(.)g(.)f(.)h(.)f(.)h(.)
+f(.)h(.)93 b(38)315 4156 y(5.3.2)h(Creating)26 b(an)i(initrd)g(b)r(o)r
+(ot)f(\035opp)n(y)80 b(.)42 b(.)f(.)h(.)f(.)h(.)f(.)h(.)g(.)f(.)h(.)f
+(.)h(.)f(.)h(.)g(.)f(.)h(.)f(.)h(.)f(.)h(.)f(.)h(.)g(.)f(.)h(.)f(.)h(.)
+f(.)h(.)93 b(38)315 4313 y(5.3.3)h(Installing)27 b(an)g(initrd)h(image)
+f(on)g(a)g(non-Lin)n(ux)g(driv)n(e)48 b(.)42 b(.)f(.)h(.)f(.)h(.)g(.)f
+(.)h(.)f(.)h(.)f(.)h(.)f(.)h(.)g(.)f(.)h(.)f(.)h(.)f(.)h(.)93
+b(39)0 4552 y Ff(6)77 b(Dealing)30 b(with)i(unsupp)s(orted)f(cards)2338
+b(40)125 4709 y Fm(6.1)83 b(Con\034guring)27 b(unrecognized)f(cards)49
+b(.)41 b(.)h(.)f(.)h(.)g(.)f(.)h(.)f(.)h(.)f(.)h(.)g(.)f(.)h(.)f(.)h(.)
+f(.)h(.)g(.)f(.)h(.)f(.)h(.)f(.)h(.)f(.)h(.)g(.)f(.)h(.)f(.)h(.)f(.)h
+(.)93 b(40)125 4865 y(6.2)83 b(A)n(dding)28 b(supp)r(ort)f(for)g(an)h
+(NE2000-compatible)d(ethernet)j(card)k(.)41 b(.)h(.)f(.)h(.)g(.)f(.)h
+(.)f(.)h(.)f(.)h(.)f(.)h(.)g(.)f(.)h(.)f(.)h(.)f(.)h(.)93
+b(41)125 5022 y(6.3)83 b(PCMCIA)29 b(\035opp)n(y)e(in)n(terface)g
+(cards)41 b(.)g(.)h(.)f(.)h(.)g(.)f(.)h(.)f(.)h(.)f(.)h(.)g(.)f(.)h(.)f
+(.)h(.)f(.)h(.)g(.)f(.)h(.)f(.)h(.)f(.)h(.)f(.)h(.)g(.)f(.)h(.)f(.)h(.)
+f(.)h(.)93 b(42)p eop
+%%Page: 3 3
+3 2 bop 0 -167 3900 5 v 0 -200 a Ff(1.)73 b(General)32
+b(information)e(and)i(hardw)m(are)i(requiremen)m(ts)1682
+b Fm(3)0 162 y Ff(7)77 b(Debugging)30 b(tips)h(and)h(programming)d
+(information)1753 b(42)125 318 y Fm(7.1)83 b(Submitting)29
+b(useful)f(bug)f(rep)r(orts)35 b(.)42 b(.)f(.)h(.)f(.)h(.)g(.)f(.)h(.)f
+(.)h(.)f(.)h(.)g(.)f(.)h(.)f(.)h(.)f(.)h(.)g(.)f(.)h(.)f(.)h(.)f(.)h(.)
+f(.)h(.)g(.)f(.)h(.)f(.)h(.)f(.)h(.)93 b(42)125 475 y(7.2)83
+b(In)n(terpreting)27 b(k)n(ernel)g(trap)g(rep)r(orts)46
+b(.)41 b(.)h(.)f(.)h(.)g(.)f(.)h(.)f(.)h(.)f(.)h(.)g(.)f(.)h(.)f(.)h(.)
+f(.)h(.)g(.)f(.)h(.)f(.)h(.)f(.)h(.)f(.)h(.)g(.)f(.)h(.)f(.)h(.)f(.)h
+(.)93 b(43)125 631 y(7.3)83 b(Lo)n(w)27 b(lev)n(el)g(PCMCIA)i
+(debugging)d(aids)39 b(.)i(.)h(.)g(.)f(.)h(.)f(.)h(.)f(.)h(.)g(.)f(.)h
+(.)f(.)h(.)f(.)h(.)g(.)f(.)h(.)f(.)h(.)f(.)h(.)f(.)h(.)g(.)f(.)h(.)f(.)
+h(.)f(.)h(.)93 b(44)125 788 y(7.4)83 b(/pro)r(c/bus/p)r(ccard)20
+b(.)42 b(.)f(.)h(.)g(.)f(.)h(.)f(.)h(.)f(.)h(.)f(.)h(.)g(.)f(.)h(.)f(.)
+h(.)f(.)h(.)g(.)f(.)h(.)f(.)h(.)f(.)h(.)g(.)f(.)h(.)f(.)h(.)f(.)h(.)f
+(.)h(.)g(.)f(.)h(.)f(.)h(.)f(.)h(.)93 b(45)125 944 y(7.5)83
+b(W)-7 b(riting)28 b(Card)f(Services)f(driv)n(ers)g(for)h(new)h(cards)
+52 b(.)41 b(.)h(.)f(.)h(.)g(.)f(.)h(.)f(.)h(.)f(.)h(.)g(.)f(.)h(.)f(.)h
+(.)f(.)h(.)f(.)h(.)g(.)f(.)h(.)f(.)h(.)f(.)h(.)93 b(45)125
+1101 y(7.6)83 b(Guidelines)28 b(for)f(PCMCIA)i(clien)n(t)e(driv)n(er)g
+(authors)62 b(.)42 b(.)f(.)h(.)g(.)f(.)h(.)f(.)h(.)f(.)h(.)g(.)f(.)h(.)
+f(.)h(.)f(.)h(.)f(.)h(.)g(.)f(.)h(.)f(.)h(.)f(.)h(.)93
+b(46)125 1257 y(7.7)83 b(Guidelines)28 b(for)f(Lin)n(ux)h(distribution)
+f(main)n(tainers)60 b(.)42 b(.)f(.)h(.)g(.)f(.)h(.)f(.)h(.)f(.)h(.)g(.)
+f(.)h(.)f(.)h(.)f(.)h(.)f(.)h(.)g(.)f(.)h(.)f(.)h(.)f(.)h(.)93
+b(47)0 1595 y Fg(1)131 b(General)45 b(information)f(and)g(hardw)l(are)g
+(requiremen)l(ts)0 1853 y Fe(1.1)112 b(In)m(tro)s(duction)0
+2063 y Fm(Card)25 b(Services)g(for)g(Lin)n(ux)h(is)g(a)f(complete)h
+(PCMCIA)h(or)e(\020PC)h(Card\021)31 b(supp)r(ort)26 b(pac)n(k)-5
+b(age.)35 b(It)26 b(includes)g(a)g(set)f(of)h(loadable)0
+2177 y(k)n(ernel)g(mo)r(dules)g(that)h(implemen)n(t)h(a)e(v)n(ersion)f
+(of)h(the)i(Card)d(Services)h(applications)g(program)e(in)n(terface,)i
+(a)h(set)f(of)h(clien)n(t)0 2290 y(driv)n(ers)21 b(for)i(sp)r(eci\034c)
+f(cards,)h(and)g(a)f(card)g(manager)f(daemon)h(that)h(can)g(resp)r(ond)
+f(to)h(card)f(insertion)g(and)g(remo)n(v)-5 b(al)22 b(ev)n(en)n(ts,)0
+2404 y(loading)29 b(and)h(unloading)f(driv)n(ers)f(on)i(demand.)44
+b(It)31 b(supp)r(orts)e(\020hot)h(sw)n(apping\021)35
+b(of)30 b(most)g(card)f(t)n(yp)r(es,)i(so)e(cards)g(can)h(b)r(e)0
+2517 y(safely)d(inserted)g(and)h(ejected)g(at)f(an)n(y)g(time.)0
+2674 y(This)c(soft)n(w)n(are)e(is)i(con)n(tin)n(ually)g(under)g(dev)n
+(elopmen)n(t.)34 b(It)24 b(probably)e(con)n(tains)g(bugs,)h(and)g
+(should)g(b)r(e)h(used)f(with)g(caution.)0 2787 y(I'll)29
+b(do)g(m)n(y)f(b)r(est)i(to)e(\034x)h(problems)f(that)i(are)e(rep)r
+(orted)g(to)g(me,)i(but)f(if)h(y)n(ou)e(don't)h(tell)g(me,)h(I)f(ma)n
+(y)f(nev)n(er)g(kno)n(w.)40 b(If)29 b(y)n(ou)0 2901 y(use)e(this)h(co)r
+(de,)g(I)f(hop)r(e)h(y)n(ou)f(will)g(send)h(me)g(y)n(our)e(exp)r
+(eriences,)h(go)r(o)r(d)g(or)f(bad!)0 3057 y(If)69 b(y)n(ou)f(ha)n(v)n
+(e)f(an)n(y)h(suggestions)f(for)h(ho)n(w)g(this)h(do)r(cumen)n(t)g
+(could)f(b)r(e)h(impro)n(v)n(ed,)77 b(please)68 b(let)h(me)g(kno)n(w)0
+3171 y(\()p Fj(dhinds@pcmcia.so)o(urc)o(ef)o(org)o(e.)o(or)o(g)p
+Fm(\).)0 3462 y Fe(1.2)112 b(Cop)m(yrigh)m(t)36 b(notice)h(and)h
+(disclaimer)0 3673 y Fm(Cop)n(yrigh)n(t)26 b(\(c\))i(1998)e(Da)n(vid)h
+(A.)h(Hinds)0 3829 y(This)20 b(do)r(cumen)n(t)h(ma)n(y)f(b)r(e)g(repro)
+r(duced)g(or)f(distributed)i(in)g(an)n(y)e(form)h(without)h(m)n(y)f
+(prior)g(p)r(ermission.)33 b(Mo)r(di\034ed)21 b(v)n(ersions)0
+3943 y(of)27 b(this)g(do)r(cumen)n(t,)g(including)g(translations)f(in)n
+(to)g(other)h(languages,)e(ma)n(y)h(b)r(e)h(freely)g(distributed,)g
+(pro)n(vided)f(that)h(they)0 4056 y(are)g(clearly)f(iden)n(ti\034ed)i
+(as)f(suc)n(h,)g(and)g(this)h(cop)n(yrigh)n(t)e(is)i(included)g(in)n
+(tact.)0 4213 y(This)38 b(do)r(cumen)n(t)g(ma)n(y)f(b)r(e)h(included)g
+(in)g(commercial)f(distributions)g(without)h(m)n(y)g(prior)e(consen)n
+(t.)67 b(While)38 b(it)g(is)g(not)0 4326 y(required,)44
+b(I)d(w)n(ould)g(lik)n(e)f(to)h(b)r(e)h(informed)f(of)g(suc)n(h)g
+(usage.)76 b(If)42 b(y)n(ou)e(in)n(tend)i(to)f(incorp)r(orate)e(this)j
+(do)r(cumen)n(t)f(in)g(a)0 4440 y(published)28 b(w)n(ork,)e(please)h
+(con)n(tact)g(me)h(to)f(mak)n(e)g(sure)g(y)n(ou)f(ha)n(v)n(e)h(the)h
+(latest)f(a)n(v)-5 b(ailable)26 b(v)n(ersion.)0 4596
+y(This)37 b(do)r(cumen)n(t)h(is)f(pro)n(vided)f(\020AS)i(IS\021,)f
+(with)h(no)f(express)f(or)h(implied)h(w)n(arran)n(ties.)63
+b(Use)38 b(the)g(information)e(in)i(this)0 4710 y(do)r(cumen)n(t)28
+b(at)f(y)n(our)f(o)n(wn)h(risk.)0 5001 y Fe(1.3)112 b(What)38
+b(is)e(the)i(latest)e(v)m(ersion,)h(and)h(where)g(can)g(I)f(get)g(it?)0
+5211 y Fm(The)e(curren)n(t)f(ma)5 b(jor)34 b(release)g(of)h(Card)f
+(Services)g(is)h(v)n(ersion)f(3.1,)i(and)f(minor)f(up)r(dates)h(or)g
+(bug)g(\034xes)f(are)g(n)n(um)n(b)r(ered)0 5325 y(3.1.1,)26
+b(3.1.2,)h(and)g(so)g(on.)p eop
+%%Page: 4 4
+4 3 bop 0 -167 3900 5 v 0 -200 a Ff(1.)73 b(General)32
+b(information)e(and)i(hardw)m(are)i(requiremen)m(ts)1682
+b Fm(4)0 162 y(Source)51 b(co)r(de)g(for)h(the)g(latest)f(v)n(ersion)f
+(is)i(a)n(v)-5 b(ailable)50 b(from)i Fh(sourceforge.org)45
+b Fm(in)52 b(the)g Fh(/pcmcia)d Fm(directory)-7 b(,)57
+b(as)0 275 y Fh(pcmcia-cs-3.1.?.)o(ta)o(r.g)o(z)p Fm(.)j(There)36
+b(will)i(usually)e(b)r(e)i(sev)n(eral)d(v)n(ersions)h(here.)65
+b(I)37 b(generally)f(only)h(k)n(eep)g(the)g(latest)0
+389 y(minor)28 b(release)g(for)g(a)g(giv)n(en)g(ma)5
+b(jor)28 b(release.)39 b(New)29 b(ma)5 b(jor)28 b(releases)f(ma)n(y)h
+(con)n(tain)g(relativ)n(ely)f(un)n(tested)i(co)r(de,)g(so)f(I)h(also)0
+502 y(k)n(eep)j(the)h(latest)f(v)n(ersion)f(of)h(the)h(previous)e(ma)5
+b(jor)31 b(release)g(as)h(a)g(relativ)n(ely)f(stable)h(fallbac)n(k;)i
+(the)e(curren)n(t)g(fallbac)n(k)f(is)0 616 y(3.0.14.)k(It)27
+b(is)g(up)h(to)f(y)n(ou)f(to)h(decide)g(whic)n(h)g(v)n(ersion)e(is)i
+(more)f(appropriate,)g(but)h(the)h Fh(CHANGES)c Fm(\034le)j(will)h
+(summarize)e(the)0 730 y(most)h(imp)r(ortan)n(t)h(di\033erences.)0
+886 y Fh(sourceforge.org)109 b Fm(is)115 b(mirrored)f(at)h
+Fh(sunsite.unc.edu)110 b Fm(\(and)115 b(all)g(sunsite)h(mirror)d
+(sites\))j(in)0 1000 y Fh(/pub/Linux/kerne)o(l/)o(pcm)o(ci)o(a)p
+Fm(.)0 1156 y(If)30 b(y)n(ou)g(do)f(not)h(feel)g(up)h(to)f(compiling)f
+(the)h(driv)n(ers)f(from)g(scratc)n(h,)h(pre-compiled)f(driv)n(ers)f
+(are)h(included)i(with)f(curren)n(t)0 1270 y(releases)i(of)i(most)f(of)
+h(the)g(ma)5 b(jor)32 b(Lin)n(ux)h(distributions,)i(including)f(Slac)n
+(kw)n(are,)f(Debian,)i(Red)f(Hat,)h(Caldera,)f(SuSE,)0
+1383 y(and)27 b(Y)-7 b(ggdrasil,)26 b(among)h(others.)0
+1675 y Fe(1.4)112 b(What)38 b(systems)f(are)g(supp)s(orted?)0
+1885 y Fm(This)25 b(pac)n(k)-5 b(age)24 b(should)i(run)f(on)g(almost)g
+(In)n(tel-based)g(Lin)n(ux-capable)f(laptop.)36 b(It)25
+b(also)g(runs)g(on)g(Alpha-based)g(platforms)0 1998 y(\(i.e.,)e(the)f
+(DEC)h(Multia\).)36 b(W)-7 b(ork)21 b(is)g(b)r(eing)h(done)f(to)h(mak)n
+(e)f(the)h(pac)n(k)-5 b(age)20 b(fully)i(dual-endian,)h(so)e(that)h(it)
+g(will)g(also)e(supp)r(ort)0 2112 y(P)n(o)n(w)n(erPC-based)28
+b(platforms)i(\(i.e.,)h(Apple)g(P)n(o)n(w)n(erb)r(o)r(oks\).)43
+b(Most)30 b(common)g(so)r(c)n(k)n(et)f(con)n(trollers)f(are)h(supp)r
+(orted.)45 b(Card)0 2226 y(do)r(c)n(ks)27 b(for)h(desktop)g(systems)f
+(should)h(w)n(ork)f(as)h(long)f(as)h(they)g(use)g(a)g(supp)r(orted)g
+(con)n(troller,)f(and)h(are)f(plugged)g(directly)0 2339
+y(in)n(to)36 b(the)h(ISA)g(or)f(PCI)h(bus,)i(as)d(opp)r(osed)g(to)h
+(SCSI-to-PCMCIA)g(or)e(IDE-to-PCMCIA)j(adapters.)63 b(The)36
+b(follo)n(wing)0 2453 y(con)n(trollers)25 b(are)i(recognized)f(b)n(y)h
+(the)h(supplied)g(so)r(c)n(k)n(et)f(driv)n(ers:)125 2692
+y Fd(\017)41 b Fm(Cirrus)26 b(Logic)h(PD6710,)f(PD6720,)h(PD6722,)f
+(PD6729,)h(PD6730,)g(PD6732,)f(PD6832)125 2872 y Fd(\017)41
+b Fm(In)n(tel)27 b(i82365sl)e(B,)j(C,)f(and)h(DF)g(steps,)g(82092AA)125
+3052 y Fd(\017)41 b Fm(O2Micro)25 b(OZ6729,)g(OZ6730,)g(OZ6812,)g
+(OZ6832,)g(OZ6833,)g(OZ6836,)g(OZ6860)125 3232 y Fd(\017)41
+b Fm(Omega)26 b(Micro)h(82C365G,)e(82C092G)125 3412 y
+Fd(\017)41 b Fm(Ricoh)27 b(RF5C296,)f(RF5C396,)g(RL5C465,)f(RL5C466,)h
+(RL5C475,)g(RL5C476,)f(RL5C478)125 3592 y Fd(\017)41
+b Fm(SMC)27 b(34C90)125 3772 y Fd(\017)41 b Fm(T)-7 b(exas)37
+b(Instrumen)n(ts)h(PCI1031,)i(PCI1130,)g(PCI1131,)g(PCI1210,)f
+(PCI1211,)h(PCI1220,)g(PCI1221,)g(PCI1225,)208 3886 y(PCI1250A,)26
+b(PCI1251A,)g(PCI1251B,)g(PCI1420,)g(PCI1450)125 4066
+y Fd(\017)41 b Fm(T)-7 b(oshiba)26 b(T)-7 b(oPIC95,)27
+b(T)-7 b(oPIC97,)27 b(T)-7 b(oPIC100)26 b(\(exp)r(erimen)n(tal,)h
+(incomplete\))125 4246 y Fd(\017)41 b Fm(V)-7 b(adem)27
+b(V)n(G465,)g(V)n(G468,)f(V)n(G469)125 4426 y Fd(\017)41
+b Fm(VLSI)27 b(T)-7 b(ec)n(hnologies)26 b(82C146,)f(V)n(CF94365)125
+4606 y Fd(\017)41 b Fm(VIA)28 b(VT83C469)125 4786 y Fd(\017)41
+b Fm(Datab)r(o)r(ok)26 b(DB86082,)g(DB86082A,)g(DB86084,)f(DB86084A,)h
+(DB86072,)f(DB86082B)0 5025 y(Other)i(con)n(trollers)e(that)j(are)f
+(register)f(compatible)h(with)h(the)g(In)n(tel)g(i82365sl)d(will)j
+(generally)e(w)n(ork,)g(as)h(w)n(ell.)0 5182 y(Supp)r(ort)i(for)f
+(32-bit)f(CardBus)h(cards)f(is)h(still)h(somewhat)f(exp)r(erimen)n
+(tal.)39 b(Driv)n(ers)27 b(prior)g(to)i(v)n(ersion)e(3.0)g(only)h(supp)
+r(ort)0 5295 y(16-bit)j(cards)g(in)i(CardBus)e(so)r(c)n(k)n(ets.)49
+b(Due)32 b(to)h(the)f(rapid)g(pace)f(of)h(tec)n(hnological)f(c)n(hange)
+f(for)i(laptop)g(hardw)n(are,)f(new)p eop
+%%Page: 5 5
+5 4 bop 0 -167 3900 5 v 0 -200 a Ff(1.)73 b(General)32
+b(information)e(and)i(hardw)m(are)i(requiremen)m(ts)1682
+b Fm(5)0 162 y(con)n(trollers)27 b(app)r(ear)i(frequen)n(tly)-7
+b(,)29 b(and)h(there)f(ma)n(y)g(b)r(e)g(dela)n(ys)g(b)r(et)n(w)n(een)g
+(when)h(a)f(new)g(mo)r(del)h(app)r(ears)e(on)h(the)h(mark)n(et,)0
+275 y(and)d(when)h(driv)n(er)e(supp)r(ort)i(b)r(ecomes)f(a)n(v)-5
+b(ailable.)0 432 y(T)e(oshiba)38 b(has)f(made)i(a)n(v)-5
+b(ailable)37 b(some)g(do)r(cumen)n(tation)h(for)g(their)h(T)-7
+b(oPIC95)37 b(and)h(T)-7 b(oPIC97)38 b(c)n(hipsets,)i(ho)n(w)n(ev)n(er)
+d(the)0 545 y(information)32 b(they)g(ha)n(v)n(e)f(pro)n(vided)g(has)h
+(not)g(really)f(b)r(een)i(adequate.)50 b(Despite)33 b(con\035icting)f
+(rep)r(orts)f(to)h(the)h(con)n(trary)-7 b(,)0 659 y(T)g(oshiba)26
+b(has)f(not)i(made)f(an)n(y)g(e\033ectiv)n(e)g(e\033ort)g(to)g(remedy)g
+(this)h(situation.)36 b(There)26 b(are)f(serious)g(bugs)h(in)h(Lin)n
+(ux)f(supp)r(ort)0 772 y(for)k(the)g(T)-7 b(oPIC)31 b(c)n(hipsets,)f
+(that)h(cannot)e(b)r(e)i(resolv)n(ed)d(un)n(til)j(b)r(etter)g(do)r
+(cumen)n(tation)e(or)h(help)g(from)g(T)-7 b(oshiba)30
+b(b)r(ecomes)0 886 y(a)n(v)-5 b(ailable.)49 b(I)32 b(do)f(not)h
+(recommend)g(use)f(of)h(T)-7 b(oshiba)32 b(laptops)f(at)h(this)g(time.)
+51 b(F)-7 b(or)31 b(use)h(of)g(16-bit)f(cards,)h(I)g(recommend)0
+1000 y(setting)c(the)f(bridge)g(mo)r(de)h(to)f(\020PCIC\021)35
+b(in)28 b(the)f(BIOS)h(setup;)f(for)g(CardBus)g(cards,)f(y)n(ou)h(are)g
+(on)g(y)n(our)f(o)n(wn.)0 1156 y(The)37 b(Motorola)e(6AHC05GA)i(con)n
+(troller)e(used)i(in)g(some)f(Hyundai)h(laptops)g(is)g(not)g(supp)r
+(orted.)65 b(The)37 b(custom)f(host)0 1270 y(con)n(troller)26
+b(in)h(the)h(HP)h(Omnib)r(o)r(ok)e(600)f(is)i(also)e(unsupp)r(orted.)0
+1561 y Fe(1.5)112 b(What)38 b(cards)f(are)h(supp)s(orted?)0
+1771 y Fm(The)g(curren)n(t)g(release)f(includes)h(driv)n(ers)f(for)g(a)
+h(v)-5 b(ariet)n(y)38 b(of)g(ethernet)g(cards,)i(a)e(driv)n(er)f(for)h
+(mo)r(dem)g(and)g(serial)f(p)r(ort)0 1885 y(cards,)24
+b(sev)n(eral)e(SCSI)i(adapter)f(driv)n(ers,)h(a)f(driv)n(er)g(for)h(A)
+-7 b(T)g(A/IDE)25 b(driv)n(e)e(cards,)h(and)g(memory)f(card)g(driv)n
+(ers)g(that)h(should)0 1998 y(supp)r(ort)31 b(most)f(SRAM)i(cards)e
+(and)g(some)h(\035ash)f(cards.)46 b(The)31 b Fh(SUPPORTED.CARDS)25
+b Fm(\034le)31 b(included)g(with)h(eac)n(h)e(release)f(of)0
+2112 y(Card)e(Services)f(lists)i(all)f(cards)g(that)g(are)g(kno)n(wn)g
+(to)g(w)n(ork)f(in)i(at)g(least)f(one)g(actual)g(system.)0
+2268 y(The)j(lik)n(eliho)r(o)r(d)f(that)g(a)g(card)g(not)h(on)f(the)h
+(supp)r(orted)f(list)h(will)f(w)n(ork)f(dep)r(ends)i(on)g(the)f(t)n(yp)
+r(e)h(of)g(card.)41 b(Essen)n(tially)29 b(all)0 2382
+y(mo)r(dems)34 b(should)h(w)n(ork)e(with)i(the)g(supplied)f(driv)n(er.)
+57 b(Some)34 b(net)n(w)n(ork)f(cards)g(ma)n(y)h(w)n(ork)f(if)i(they)g
+(are)e(OEM)i(v)n(ersions)0 2496 y(of)c(supp)r(orted)f(cards.)44
+b(Other)30 b(t)n(yp)r(es)h(of)f(IO)h(cards)e(\(frame)h(bu\033ers,)h
+(sound)g(cards,)f(etc\))h(will)g(not)f(w)n(ork)f(un)n(til)i(someone)0
+2609 y(writes)c(the)h(appropriate)e(driv)n(ers.)0 2901
+y Fe(1.6)112 b(When)38 b(will)d(m)m(y)h(fa)m(v)m(orite)h(\(unsupp)s
+(orted\))h(card)f(b)s(ecome)h(supp)s(orted?)0 3111 y
+Fm(Unfortunately)-7 b(,)32 b(they)g(usually)f(don't)h(pa)n(y)f(me)g(to)
+h(write)f(device)g(driv)n(ers,)g(so)g(if)h(y)n(ou)f(w)n(ould)g(lik)n(e)
+g(to)g(ha)n(v)n(e)f(a)h(driv)n(er)g(for)0 3224 y(y)n(our)c(fa)n(v)n
+(orite)f(card,)h(y)n(ou)g(are)g(probably)g(going)f(to)i(ha)n(v)n(e)f
+(to)h(do)f(at)h(least)g(some)f(of)h(the)g(w)n(ork.)36
+b(Ideally)-7 b(,)28 b(I'd)g(lik)n(e)g(to)g(w)n(ork)0
+3338 y(to)n(w)n(ards)g(a)i(mo)r(del)g(lik)n(e)g(the)h(Lin)n(ux)f(k)n
+(ernel,)g(where)f(I)h(w)n(ould)g(b)r(e)h(resp)r(onsible)e(mainly)h(for)
+g(the)g(\020core\021)35 b(driv)n(er)29 b(co)r(de)h(and)0
+3452 y(other)k(authors)g(w)n(ould)h(con)n(tribute)f(and)h(main)n(tain)g
+(clien)n(t)g(driv)n(ers)e(for)i(sp)r(eci\034c)g(cards.)58
+b(The)35 b Fh(SUPPORTED.CARDS)29 b Fm(\034le)0 3565 y(men)n(tions)i
+(some)f(cards)g(for)h(whic)n(h)g(driv)n(er)f(w)n(ork)f(is)i(curren)n
+(tly)f(in)i(progress.)45 b(I)31 b(will)g(try)g(to)g(help)h(where)e(I)h
+(can,)h(but)g(b)r(e)0 3679 y(w)n(arned)26 b(that)i(debugging)f(k)n
+(ernel)f(device)i(driv)n(ers)e(b)n(y)h(email)g(is)h(not)f(particularly)
+f(e\033ectiv)n(e.)0 3835 y(Man)n(ufacturers)18 b(in)n(terested)h(in)g
+(helping)h(pro)n(vide)e(Lin)n(ux)h(supp)r(ort)g(for)g(their)g(pro)r
+(ducts)g(can)g(con)n(tact)g(me)g(ab)r(out)h(consulting)0
+3949 y(arrangemen)n(ts.)0 4240 y Fe(1.7)112 b(Mailing)36
+b(lists)g(and)i(other)f(information)f(sources)0 4450
+y Fm(I)44 b(used)h(to)f(main)n(tain)g(a)f(database)g(and)h(mailing)g
+(list)h(of)f(Lin)n(ux)g(PCMCIA)h(users.)86 b(More)43
+b(recen)n(tly)-7 b(,)48 b(I'v)n(e)c(turned)0 4564 y(m)n(y)49
+b(w)n(eb)g(page)f(for)h(Lin)n(ux)f(PCMCIA)i(information)f(in)n(to)f(a)h
+(\020Hyp)r(erNews\021)55 b(site,)g(with)50 b(a)e(set)h(of)g(message)f
+(lists)0 4677 y(for)41 b(Lin)n(ux)g(PCMCIA)i(issues.)78
+b(There)41 b(are)g(lists)h(for)f(installation)g(and)g(con\034guration)f
+(issues,)k(for)e(di\033eren)n(t)f(t)n(yp)r(e-)0 4791
+y(s)k(of)g(cards,)j(and)d(for)g(programming)d(and)j(debugging)f
+(issues.)89 b(The)45 b(Lin)n(ux)g(PCMCIA)h(information)e(page)g(is)h
+(at)0 4905 y Fh(<http://pcmcia.s)o(ou)o(rce)o(fo)o(rg)o(e.o)o(rg)o(>)p
+Fm(.)67 b(Users)38 b(can)h(request)g(email)g(noti\034cation)g(of)h(new)
+f(resp)r(onses)g(to)g(particu-)0 5018 y(lar)27 b(questions,)h(or)f
+(noti\034cation)g(for)h(all)f(new)h(messages)f(in)h(a)f(giv)n(en)g
+(category)-7 b(.)37 b(I)28 b(hop)r(e)g(that)g(this)g(will)g(b)r(ecome)g
+(a)g(useful)0 5132 y(rep)r(ository)e(of)h(information,)g(for)g
+(questions)g(that)h(go)f(b)r(ey)n(ond)g(the)h(scop)r(e)f(of)h(the)f(HO)
+n(WTO.)0 5288 y(There)h(is)g(a)f(Lin)n(ux)h(mailing)g(list)g(dev)n
+(oted)g(to)g(laptop)g(issues,)f(the)i(\020lin)n(ux-laptop\021)k(list.)
+39 b(F)-7 b(or)28 b(more)f(information,)g(send)h(a)0
+5402 y(message)i(con)n(taining)g(the)i(w)n(ord)e(\020help\021)38
+b(to)31 b Fh(majordomo@vger.ru)o(tg)o(er)o(s.e)o(du)o
+Fm(.)43 b(T)-7 b(o)31 b(subscrib)r(e,)h(send)f(a)g(message)f(con-)p
+eop
+%%Page: 6 6
+6 5 bop 0 -167 3900 5 v 0 -200 a Ff(2.)73 b(Compilation)29
+b(and)k(installation)2514 b Fm(6)0 162 y(taining)25 b(\020subscrib)r(e)
+g(lin)n(ux-laptop\021)32 b(to)25 b(the)h(same)f(address.)35
+b(This)26 b(mailing)f(list)h(migh)n(t)f(b)r(e)h(a)f(go)r(o)r(d)g(forum)
+h(for)f(discussion)0 275 y(of)j(Lin)n(ux)f(PCMCIA)h(issues.)0
+432 y(The)d(Lin)n(ux)g(Laptop)g(Home)g(P)n(age)g(at)50
+b Fh(<http://www.cs.ut)o(ex)o(as.)o(ed)o(u/)o(use)o(rs)o(/k)o(har)o(ke)
+o(r/)o(lin)o(ux)o(-)t(la)o(pt)o(op>)18 b Fm(has)25 b(links)0
+545 y(to)32 b(man)n(y)f(sites)g(that)h(ha)n(v)n(e)f(information)g(ab)r
+(out)g(con\034guring)g(sp)r(eci\034c)g(t)n(yp)r(es)h(of)g(laptops)f
+(for)g(Lin)n(ux.)49 b(There)31 b(is)h(also)e(a)0 659
+y(searc)n(hable)c(database)g(of)h(system)h(con\034guration)e
+(information.)0 947 y Fe(1.8)112 b(Wh)m(y)38 b(don't)f(y)m(ou)h
+(distribute)d(binaries?)0 1157 y Fm(F)-7 b(or)25 b(me,)h(distributing)g
+(binaries)f(w)n(ould)g(b)r(e)h(a)g(signi\034can)n(t)e(hassle.)36
+b(It)26 b(is)f(complicated)h(b)r(ecause)f(some)g(features)g(can)h(only)
+0 1271 y(b)r(e)h(selected)g(at)g(compile)g(time,)g(and)g(b)r(ecause)f
+(the)i(mo)r(dules)e(are)g(somewhat)g(dep)r(enden)n(t)i(on)f(ha)n(ving)e
+(the)j(\020righ)n(t\021)k(k)n(ernel)0 1384 y(con\034guration.)48
+b(So,)33 b(I)f(w)n(ould)g(probably)f(need)h(to)g(distribute)g
+(precompiled)g(mo)r(dules)g(along)e(with)j(matc)n(hing)e(k)n(ernels.)0
+1498 y(Bey)n(ond)g(this,)j(the)e(greatest)f(need)i(for)e(precompiled)h
+(mo)r(dules)g(is)g(when)h(installing)e(Lin)n(ux)h(on)g(a)g(clean)g
+(system.)50 b(This)0 1612 y(t)n(ypically)32 b(requires)g(setting)g(up)h
+(driv)n(ers)f(so)g(they)h(can)f(b)r(e)h(used)g(in)g(the)g(installation)
+g(pro)r(cess)e(for)i(a)f(particular)f(Lin)n(ux)0 1725
+y(distribution.)k(Eac)n(h)23 b(Lin)n(ux)g(distribution)h(has)e(its)i(o)
+n(wn)e(ideosyncracies,)g(and)h(it)h(is)f(not)g(feasible)g(for)g(me)g
+(to)g(pro)n(vide)f(b)r(o)r(ot)0 1839 y(and)27 b(ro)r(ot)g(disks)g(for)g
+(ev)n(en)g(just)i(the)e(common)g(com)n(binations)g(of)g(driv)n(ers)f
+(and)i(distributions.)0 1995 y(PCMCIA)j(is)f(no)n(w)g(a)g(part)g(of)g
+(man)n(y)g(of)g(the)h(ma)5 b(jor)29 b(Lin)n(ux)h(distributions,)h
+(including)f(Red)g(Hat,)i(Caldera,)d(Slac)n(kw)n(are,)0
+2109 y(Y)-7 b(ggdrasil,)26 b(Craft)n(w)n(orks,)f(and)j(Nascen)n(t)f(T)
+-7 b(ec)n(hnology)g(.)0 2397 y Fe(1.9)112 b(Wh)m(y)38
+b(is)e(the)i(pac)m(k)-6 b(age)38 b(so)f(darned)i(big?)0
+2607 y Fm(W)-7 b(ell,)35 b(\034rst)e(of)g(all,)h(it)g(isn't)f(actually)
+f(that)i(large.)51 b(All)34 b(the)f(driv)n(er)f(mo)r(dules)h(together)f
+(tak)n(e)h(up)g(ab)r(out)g(500K)e(of)i(disk)0 2721 y(space.)j(The)26
+b(utilit)n(y)h(programs)d(add)i(up)g(to)g(ab)r(out)h(70K,)e(and)h(the)g
+(scripts)g(in)h Fh(/etc/pcmcia)21 b Fm(are)26 b(ab)r(out)g(50K.)f(The)h
+(core)0 2834 y(driv)n(er)h(mo)r(dules)h(tak)n(e)g(up)h(ab)r(out)f(55K)f
+(of)h(system)g(memory)-7 b(.)39 b(The)28 b Fh(cardmgr)d
+Fm(daemon)j(will)h(generally)e(b)r(e)h(sw)n(app)r(ed)g(out)0
+2948 y(except)k(when)f(cards)g(are)g(inserted)g(or)g(remo)n(v)n(ed.)47
+b(The)32 b(total)g(pac)n(k)-5 b(age)30 b(size)h(is)h(comparable)e(to)h
+(DOS/Windo)n(ws)g(Card)0 3061 y(Services)c(implemen)n(tations.)0
+3218 y(Compared)22 b(to)i(DOS)f(\020p)r(oin)n(t)h(enablers\021,)e(this)
+i(ma)n(y)f(still)h(seem)f(lik)n(e)g(a)g(lot)g(of)h(o)n(v)n(erhead,)e
+(esp)r(ecially)h(for)g(p)r(eople)g(that)h(don't)0 3331
+y(plan)g(on)f(using)g(man)n(y)h(of)f(the)h(features)g(of)f(PCMCIA,)i
+(suc)n(h)e(as)g(p)r(o)n(w)n(er)g(managemen)n(t)f(or)h(hot)h(sw)n
+(apping.)35 b(P)n(oin)n(t)23 b(enablers)0 3445 y(can)32
+b(b)r(e)h(tin)n(y)f(b)r(ecause)g(they)h(generally)e(supp)r(ort)h(only)g
+(one)g(or)f(a)i(small)f(set)g(of)g(cards,)h(and)f(also)f(generally)g
+(supp)r(ort)h(a)0 3559 y(restricted)f(set)h(of)g(host)g(con)n
+(trollers.)49 b(If)32 b(someone)f(w)n(ere)g(to)h(write)g(a)g(gen)n
+(uinely)f(\020generic\021)37 b(mo)r(dem)c(enabler,)f(it)h(w)n(ould)0
+3672 y(end)26 b(up)g(incorp)r(orating)e(m)n(uc)n(h)i(of)f(the)i
+(functionalit)n(y)e(of)h(Card)f(Services,)g(to)h(handle)g(cards)f(from)
+g(di\033eren)n(t)h(v)n(endors)e(and)0 3786 y(the)k(full)g(range)e(of)i
+(host)f(con)n(troller)f(v)-5 b(arian)n(ts.)0 4121 y Fg(2)131
+b(Compilation)45 b(and)e(installation)0 4378 y Fe(2.1)112
+b(Prerequisites)36 b(and)i(k)m(ernel)f(setup)0 4589 y
+Fm(Before)27 b(starting,)f(y)n(ou)h(should)h(think)g(ab)r(out)f
+(whether)h(y)n(ou)f(really)f(need)i(to)f(compile)h(the)g(PCMCIA)g(pac)n
+(k)-5 b(age)26 b(y)n(ourself.)0 4702 y(All)41 b(common)g(Lin)n(ux)f
+(distributions)h(come)f(with)h(pre-compiled)f(driv)n(er)g(pac)n(k)-5
+b(ages.)75 b(Generally)-7 b(,)43 b(y)n(ou)d(only)g(need)h(to)0
+4816 y(install)26 b(the)h(driv)n(ers)e(from)h(scratc)n(h)f(if)h(y)n(ou)
+g(need)g(a)g(new)g(feature)g(of)h(the)f(curren)n(t)g(driv)n(ers,)f(or)g
+(if)i(y)n(ou'v)n(e)e(up)r(dated)i(and/or)0 4929 y(recon\034gured)20
+b(y)n(our)g(k)n(ernel)h(in)h(a)f(w)n(a)n(y)f(that)i(is)g(incompatible)f
+(with)h(the)g(driv)n(ers)e(included)i(with)g(y)n(our)f(Lin)n(ux)g
+(distribution.)0 5043 y(While)28 b(compiling)f(the)h(pac)n(k)-5
+b(age)26 b(is)i(not)f(tec)n(hnically)g(di\036cult,)i(it)f(do)r(es)f
+(require)f(some)h(general)f(Lin)n(ux)i(familiarit)n(y)-7
+b(.)0 5199 y(The)28 b(follo)n(wing)e(things)i(should)f(b)r(e)h
+(installed)f(on)h(y)n(our)e(system)h(b)r(efore)g(y)n(ou)g(b)r(egin:)125
+5407 y Fd(\017)41 b Fm(A)27 b(2.0.*,)g(2.2.*,)f(or)h(2.3.*)f(series)h
+(k)n(ernel)f(source)h(tree.)p eop
+%%Page: 7 7
+7 6 bop 0 -167 3900 5 v 0 -200 a Ff(2.)73 b(Compilation)29
+b(and)k(installation)2514 b Fm(7)125 162 y Fd(\017)41
+b Fm(An)28 b(appropriate)d(set)j(of)f(mo)r(dule)h(utilities.)125
+342 y Fd(\017)41 b Fm(\(Optional\))27 b(the)h(\020XF)-7
+b(orms\021)33 b(X11)27 b(user)g(in)n(terface)g(to)r(olkit.)0
+565 y(Y)-7 b(ou)33 b(need)h(to)f(ha)n(v)n(e)g(a)g(complete)g(lin)n(ux)g
+(source)f(tree)i(for)e(y)n(our)h(k)n(ernel,)h(not)f(just)h(an)f
+(up-to-date)g(k)n(ernel)f(image.)54 b(The)0 678 y(driv)n(er)26
+b(mo)r(dules)i(con)n(tain)f(some)f(references)h(to)g(k)n(ernel)g
+(source)f(\034les.)37 b(While)28 b(y)n(ou)f(ma)n(y)f(w)n(an)n(t)h(to)h
+(build)g(a)f(new)h(k)n(ernel)e(to)0 792 y(remo)n(v)n(e)g(unnecessary)g
+(driv)n(ers,)g(installing)h(PCMCIA)h(do)r(es)g(not)f(require)g(y)n(ou)f
+(to)i(do)f(so.)0 948 y(Curren)n(t)42 b(\020stable\021)49
+b(k)n(ernel)42 b(sources)f(and)i(patc)n(hes)f(are)g(a)n(v)-5
+b(ailable)41 b(from)86 b Fh(<ftp://sunsite.u)o(nc)o(.ed)o(u/)o(pu)o
+(b/L)o(in)o(ux)o(/)0 1062 y(kernel/v2.2>)p Fm(,)38 b(or)h(from)79
+b Fh(<ftp://tsx-)t(11.mi)o(t.)o(ed)o(u/p)o(ub)o(/l)o(inu)o(x/)o(sou)o
+(rc)o(es)o(/sy)o(st)o(em)o(/v2)o(.2)o(>)p Fm(.)67 b(Dev)n(elopmen)n(t)
+40 b(k-)0 1175 y(ernels)28 b(can)g(b)r(e)g(found)h(in)g(the)f(corresp)r
+(onding)f Fh(v2.3)g Fm(sub)r(directories.)38 b(Curren)n(t)27
+b(mo)r(dule)i(utilities)g(can)f(b)r(e)g(found)h(in)g(the)0
+1289 y(same)e(lo)r(cations.)0 1445 y(In)h(the)g(Lin)n(ux)g(k)n(ernel)f
+(source)f(tree,)i(the)g Fh(Documentation/Ch)o(ang)o(es)21
+b Fm(\034le)28 b(describ)r(es)g(the)g(v)n(ersions)e(of)i(all)f(sorts)g
+(of)h(other)0 1559 y(system)c(comp)r(onen)n(ts)h(that)g(are)e(required)
+h(for)g(that)h(k)n(ernel)f(release.)34 b(Y)-7 b(ou)25
+b(ma)n(y)f(w)n(an)n(t)g(to)h(c)n(hec)n(k)e(through)h(this)h(and)g(v)n
+(erify)0 1673 y(that)k(y)n(our)f(system)h(is)g(up)h(to)f(date,)h(esp)r
+(ecially)e(if)i(y)n(ou)e(ha)n(v)n(e)g(up)r(dated)i(y)n(our)e(k)n
+(ernel.)41 b(If)30 b(y)n(ou)e(are)g(using)h(a)g(dev)n(elopmen)n(t)0
+1786 y(k)n(ernel,)e(b)r(e)h(sure)f(that)g(y)n(ou)g(are)g(using)g(the)h
+(righ)n(t)f(com)n(bination)f(of)i(shared)e(libraries)h(and)g(mo)r(dule)
+h(to)r(ols.)0 1943 y(When)c(con\034guring)d(y)n(our)h(k)n(ernel,)h(if)h
+(y)n(ou)e(plan)h(on)g(using)g(a)f(PCMCIA)i(ethernet)g(card,)f(y)n(ou)f
+(should)h(turn)g(on)g(net)n(w)n(orking)0 2056 y(supp)r(ort)30
+b(but)g(turn)g(o\033)g(the)g(normal)e(Lin)n(ux)i(net)n(w)n(ork)e(card)h
+(driv)n(ers,)g(including)h(the)g(\020p)r(o)r(c)n(k)n(et)f(and)h(p)r
+(ortable)f(adapters\021.)0 2170 y(The)34 b(PCMCIA)i(net)n(w)n(ork)d
+(card)g(driv)n(ers)g(are)g(all)i(implemen)n(ted)f(as)g(loadable)f(mo)r
+(dules.)58 b(An)n(y)34 b(driv)n(ers)f(compiled)h(in)n(to)0
+2283 y(y)n(our)26 b(k)n(ernel)h(will)h(only)f(w)n(aste)g(space.)0
+2440 y(If)j(y)n(ou)e(w)n(an)n(t)h(to)g(use)g(SLIP)-7
+b(,)30 b(PPP)-7 b(,)31 b(or)e(PLIP)-7 b(,)30 b(y)n(ou)f(do)g(need)g(to)
+h(either)f(con\034gure)f(y)n(our)g(k)n(ernel)g(with)i(these)f(enabled,)
+h(or)0 2553 y(use)j(the)g(loadable)f(mo)r(dule)h(v)n(ersions)e(of)i
+(these)g(driv)n(ers.)51 b(There)32 b(is)h(an)g(unfortunate)g
+(de\034ciency)f(in)i(the)f(k)n(ernel)f(con\034g)0 2667
+y(pro)r(cess)26 b(in)i(1.2.X)g(k)n(ernels,)e(in)i(that)g(it)g(is)g(not)
+g(p)r(ossible)f(to)g(set)h(con\034guration)e(options)h(\(lik)n(e)h
+(SLIP)g(compression\))e(for)h(a)0 2780 y(loadable)f(mo)r(dule,)i(so)f
+(it)h(is)g(probably)e(b)r(etter)i(to)f(just)i(link)e(SLIP)h(in)n(to)g
+(the)g(k)n(ernel)e(if)i(y)n(ou)f(need)h(it.)0 2937 y(In)k(order)f(to)i
+(use)f(a)g(PCMCIA)h(tok)n(en)e(ring)h(adapter,)g(y)n(our)f(k)n(ernel)h
+(should)g(b)r(e)g(con\034gured)f(with)i(\020T)-7 b(ok)n(en)31
+b(Ring)h(driv)n(er)0 3051 y(supp)r(ort\021)i(\()p Fh(CONFIG_TR)p
+Fm(\))24 b(enabled,)k(though)f(y)n(ou)g(should)g(lea)n(v)n(e)f
+Fh(CONFIG_IBMTR)d Fm(o\033.)0 3207 y(If)91 b(y)n(ou)e(w)n(an)n(t)h(to)g
+(use)g(a)g(PCMCIA)h(IDE)g(adapter,)105 b(y)n(our)89 b(k)n(ernel)g
+(should)h(b)r(e)h(con\034gured)e(with)0 3321 y Fh(CONFIG_BLK_DEV_I)o
+(DE)o(_PC)o(MC)o(IA)41 b Fm(enabled,)51 b(for)c(2.0.*)e(through)i
+(2.1.7)e(k)n(ernels.)94 b(Older)47 b(k)n(ernels)f(do)g(not)h(supp)r
+(ort)0 3434 y(remo)n(v)n(eable)25 b(IDE)k(devices;)e(new)n(er)g(k)n
+(ernels)f(do)h(not)h(require)e(a)i(sp)r(ecial)f(con\034guration)f
+(setting.)0 3591 y(If)e(y)n(ou)g(will)g(b)r(e)g(using)g(a)f(PCMCIA)i
+(SCSI)f(adapter,)g(then)g(enable)g Fh(CONFIG_SCSI)19
+b Fm(when)25 b(con\034guring)d(y)n(our)h(k)n(ernel.)34
+b(Also,)0 3704 y(enable)29 b(an)n(y)g(top)h(lev)n(el)f(driv)n(ers)f
+(\(SCSI)i(disk,)g(tap)r(e,)g(cdrom,)f(generic\))g(that)h(y)n(ou)f(exp)r
+(ect)h(to)f(use.)43 b(All)30 b(lo)n(w-lev)n(el)e(driv)n(ers)0
+3818 y(for)f(particular)f(host)i(adapters)e(should)h(b)r(e)h(disabled,)
+f(as)g(they)h(will)g(just)g(tak)n(e)f(up)h(space.)0 3974
+y(If)66 b(y)n(ou)f(w)n(an)n(t)h(to)f(mo)r(dularize)h(a)f(driv)n(er)g
+(that)h(is)g(needed)g(for)f(a)h(PCMCIA)g(device,)76 b(y)n(ou)65
+b(m)n(ust)h(mo)r(dify)0 4088 y Fh(/etc/pcmcia/conf)o(ig)32
+b Fm(to)39 b(sp)r(ecify)g(what)f(mo)r(dules)h(need)g(to)f(b)r(e)h
+(loaded)f(for)g(what)h(card)f(t)n(yp)r(es.)70 b(F)-7
+b(or)38 b(example,)j(if)0 4201 y(the)28 b(serial)e(driv)n(er)h(is)g(mo)
+r(dularized,)g(then)h(the)g(serial)e(device)i(de\034nition)g(should)f
+(b)r(e:)208 4431 y Fc(device)40 b("serial_cs")286 4536
+y(class)g("serial")h(module)g("misc/serial",)h("serial_cs")0
+4775 y Fm(This)c(pac)n(k)-5 b(age)36 b(includes)i(an)g(X-based)g(card)f
+(status)g(utilit)n(y)i(called)e Fh(cardinfo)p Fm(.)65
+b(This)38 b(utilit)n(y)h(is)f(based)f(on)h(a)f(freely)0
+4889 y(distributed)29 b(user)f(in)n(terface)f(to)r(olkit)i(called)f
+(the)g(XF)-7 b(orms)28 b(Library)-7 b(.)38 b(This)29
+b(library)e(is)h(a)n(v)-5 b(ailable)27 b(as)h(a)g(separate)f(pac)n(k)-5
+b(age)0 5002 y(with)30 b(most)f(Lin)n(ux)g(distributions.)41
+b(If)30 b(y)n(ou)e(w)n(ould)h(lik)n(e)g(to)g(build)h
+Fh(cardinfo)p Fm(,)c(y)n(ou)j(should)g(install)g(XF)-7
+b(orms)29 b(and)g(all)g(the)0 5116 y(normal)e(X)g(header)g(\034les)h
+(and)f(libraries)f(b)r(efore)h(con\034guring)f(the)i(PCMCIA)h(pac)n(k)
+-5 b(age.)p eop
+%%Page: 8 8
+8 7 bop 0 -167 3900 5 v 0 -200 a Ff(2.)73 b(Compilation)29
+b(and)k(installation)2514 b Fm(8)0 162 y Fe(2.2)112 b(Installation)0
+372 y Fm(Here)27 b(is)h(a)f(synopsis)f(of)i(the)g(installation)f(pro)r
+(cess:)125 611 y Fd(\017)41 b Fm(Unpac)n(k)27 b(p)r
+(cmcia-cs-3.1.?.tar.gz)d(in)k(/usr/src.)125 791 y Fd(\017)41
+b Fm(Run)28 b(\020)7 b Fh(make)41 b(config)p Fm(\021)32
+b(in)c(the)f(new)h Fh(pcmcia-cs-3.1.?)j Fm(directory)-7
+b(.)125 971 y Fd(\017)41 b Fm(Run)28 b(\020)7 b Fh(make)41
+b(all)p Fm(\021,)26 b(then)i(\020)7 b Fh(make)42 b(install)p
+Fm(\021.)125 1151 y Fd(\017)f Fm(Customize)27 b(the)h(startup)f(script)
+g(and)h(the)g(option)f(\034les)g(in)h Fh(/etc/pcmcia)23
+b Fm(for)k(y)n(our)f(site,)i(if)g(needed.)0 1391 y(If)i(y)n(ou)e(plan)h
+(to)g(install)g(an)n(y)f(con)n(tributed)h(clien)n(t)g(driv)n(ers)f(not)
+h(included)g(in)h(the)f(core)f(PCMCIA)i(distribution,)g(unpac)n(k)0
+1504 y(eac)n(h)19 b(of)h(them)g(in)g(the)g(top-lev)n(el)f(directory)g
+(of)g(the)h(PCMCIA)h(source)d(tree.)34 b(Then)20 b(follo)n(w)f(the)i
+(normal)d(build)j(instructions.)0 1618 y(The)28 b(extra)e(driv)n(ers)g
+(will)i(b)r(e)g(compiled)f(and)h(installed)f(automatically)-7
+b(.)0 1774 y(Running)26 b(\020)7 b Fh(make)42 b(config)p
+Fm(\021)30 b(prompts)c(for)g(a)g(few)g(con\034guration)f(options,)h
+(and)g(c)n(hec)n(ks)f(out)h(y)n(our)f(system)h(to)g(v)n(erify)g(that)0
+1888 y(it)31 b(satis\034es)e(all)h(prerequisites)f(for)g(installing)h
+(PCMCIA)h(supp)r(ort.)44 b(In)30 b(most)g(cases,)g(y)n(ou'll)g(b)r(e)g
+(able)g(to)g(just)h(accept)e(all)0 2001 y(the)h(default)h
+(con\034guration)d(options.)43 b(Be)30 b(sure)f(to)h(carefully)g(c)n
+(hec)n(k)f(the)h(output)g(of)g(this)h(command)e(in)h(case)f(there)h
+(are)0 2115 y(problems.)36 b(The)28 b(follo)n(wing)e(options)h(are)g(a)
+n(v)-5 b(ailable:)0 2355 y Ff(Alternate)32 b(target)g(install)f
+(directory?)208 2501 y Fm(If)41 b(y)n(ou)g(are)f(compiling)h(the)h(pac)
+n(k)-5 b(age)40 b(for)h(installation)g(on)g(another)f(mac)n(hine,)45
+b(sp)r(ecify)c(an)h(alternate)e(target)208 2615 y(directory)c(when)j
+(prompted.)69 b(This)38 b(should)g(b)r(e)g(an)g(absolute)g(path.)69
+b(All)39 b(\034les)f(will)g(b)r(e)h(installed)f(relativ)n(e)f(to)208
+2728 y(this)29 b(directory)-7 b(.)41 b(Y)-7 b(ou)29 b(will)g(then)h(b)r
+(e)g(able)f(to)g Fh(tar)f Fm(this)h(directory)f(tree)h(and)g(cop)n(y)g
+(to)g(y)n(our)f(target)g(mac)n(hine,)h(and)208 2842 y(unpac)n(k)d
+(relativ)n(e)h(to)g(its)h(ro)r(ot)f(directory)f(to)h(install)h(ev)n
+(erything)e(in)i(the)g(prop)r(er)f(places.)0 3022 y Ff(Build)k
+('trusting')f(v)m(ersions)h(of)h(card)h(utilities?)208
+3169 y Fm(Some)e(of)h(the)h(supp)r(ort)e(utilities)i(\()p
+Fh(cardctl)c Fm(and)j Fh(cardinfo)p Fm(\))d(can)j(b)r(e)g(compiled)g
+(either)g(in)g(\020safe\021)38 b(or)31 b(\020trusting\021)208
+3282 y(forms.)55 b(The)34 b(\020safe\021)40 b(forms)33
+b(prev)n(en)n(t)g(non-ro)r(ot)g(users)g(from)g(mo)r(difying)h(card)f
+(con\034gurations.)54 b(The)34 b(\020trusting\021)208
+3396 y(forms)26 b(p)r(ermit)h(ordinary)e(users)h(to)h(issue)f(commands)
+g(to)h(susp)r(end)g(and)f(resume)h(cards,)f(reset)g(cards,)g(and)g(c)n
+(hange)208 3510 y(the)i(curren)n(t)e(con\034guration)g(sc)n(heme.)36
+b(The)28 b(default)g(is)f(to)h(build)g(the)g(safe)f(forms.)0
+3690 y Ff(Include)32 b(32-bit)f(\(CardBus\))h(card)h(supp)s(ort?)208
+3836 y Fm(This)28 b(option)h(m)n(ust)f(b)r(e)i(selected)e(if)h(y)n(ou)f
+(wish)h(to)g(use)f(32-bit)g(CardBus)g(cards.)39 b(It)29
+b(is)g(not)f(required)g(for)g(CardBus)208 3950 y(bridge)e(supp)r(ort,)i
+(if)g(y)n(ou)f(only)g(plan)g(to)h(use)f(16-bit)g(PC)h(Cards.)0
+4130 y Ff(Include)k(PnP)g(BIOS)g(resource)g(c)m(hec)m(king?)208
+4277 y Fm(This)23 b(builds)h(additional)f(co)r(de)h(in)n(to)f(the)h
+(PCMCIA)g(core)f(mo)r(dule)h(to)f(comm)n(unicate)g(with)h(a)g(system's)
+f(PnP)i(BIOS)208 4390 y(to)36 b(obtain)h(resource)e(information)h(for)g
+(built-in)i(\020motherb)r(oard\021)k(devices)36 b(\(serial)g(and)h
+(parallel)f(p)r(orts,)i(sound,)208 4504 y(etc\),)44 b(to)d(help)g(a)n
+(v)n(oid)e(resource)g(con\035icts.)77 b(If)41 b(enabled,)j(some)c
+(extra)g(resource)f(\034les)i(will)g(b)r(e)g(created)f(under)208
+4617 y Fh(/proc/bus/pccar)o(d)p Fm(,)23 b(and)28 b(the)h
+Fh(lspnp)d Fm(and)j Fh(setpnp)d Fm(to)r(ols)i(can)g(b)r(e)h(used)f(to)h
+(view)f(and)g(manipulate)h(PnP)h(BIOS)208 4731 y(devices.)36
+b(Ho)n(w)n(ev)n(er,)25 b(this)j(setting)g(causes)e(problems)h(on)g
+(some)g(laptops)g(and)h(is)f(not)h(turned)f(on)h(b)n(y)f(default.)0
+4911 y Ff(Ho)m(w)32 b(to)f(set)h(k)m(ernel-sp)s(eci\034c)f(options?)208
+5058 y Fm(There)d(are)h(a)f(few)i(k)n(ernel)e(con\034guration)g
+(options)h(that)g(a\033ect)g(the)h(PCMCIA)g(to)r(ols.)42
+b(The)29 b(con\034guration)e(script)208 5171 y(can)i(deduce)h(these)g
+(from)g(the)g(running)g(k)n(ernel)f(\(the)i(default)f(and)g(most)g
+(common)g(case\).)43 b(Alternativ)n(ely)-7 b(,)30 b(if)h(y)n(ou)208
+5285 y(are)e(compiling)h(for)g(installation)g(on)g(another)g(mac)n
+(hine,)g(it)h(can)f(read)g(the)h(con\034guration)e(from)h(a)g(k)n
+(ernel)f(source)208 5398 y(tree,)e(or)g(eac)n(h)f(option)i(can)f(b)r(e)
+h(set)f(in)n(teractiv)n(ely)-7 b(.)p eop
+%%Page: 9 9
+9 8 bop 0 -167 3900 5 v 0 -200 a Ff(2.)73 b(Compilation)29
+b(and)k(installation)2514 b Fm(9)0 162 y(The)28 b Fh(Configure)c
+Fm(script)j(can)g(also)g(b)r(e)h(executed)f(non-in)n(teractiv)n(ely)-7
+b(,)26 b(for)h(automatic)g(builds)h(or)f(to)g(quic)n(kly)g
+(recon\034gure)0 275 y(after)k(a)f(k)n(ernel)h(up)r(date.)48
+b(Some)30 b(additional)h(less-frequen)n(tly-used)e(options)i(can)f(b)r
+(e)i(only)f(b)r(e)g(set)g(from)g(the)h(command)0 389
+y(line.)37 b(Running)28 b(\020)7 b Fh(Configure)39 b(\025help)p
+Fm(\021)32 b(lists)c(all)f(a)n(v)-5 b(ailable)26 b(options.)0
+545 y(Running)32 b(\020)7 b Fh(make)42 b(all)p Fm(\021)c(follo)n(w)n
+(ed)31 b(b)n(y)h(\020)7 b Fh(make)41 b(install)p Fm(\021)36
+b(will)d(build)g(and)f(then)g(install)h(the)f(k)n(ernel)f(mo)r(dules)i
+(and)f(util-)0 659 y(it)n(y)h(programs.)51 b(Kernel)32
+b(mo)r(dules)h(are)f(installed)g(under)h Fh(/lib/modules/)p
+Fb(<)p Fh(ver)o(si)o(on)o Fb(>)p Fh(/p)o(cm)o(ci)o(a)p
+Fm(.)47 b(The)33 b Fh(cardmgr)d Fm(and)0 772 y Fh(cardctl)25
+b Fm(programs)g(are)h(installed)i(in)g Fh(/sbin)p Fm(.)35
+b(If)28 b Fh(cardinfo)c Fm(is)j(built,)i(it)f(is)f(installed)h(in)f
+Fh(/usr/bin/X11)p Fm(.)0 929 y(Con\034guration)d(\034les)h(will)g(b)r
+(e)h(installed)f(in)g(the)h Fh(/etc/pcmcia)20 b Fm(directory)-7
+b(.)35 b(If)26 b(y)n(ou)e(are)g(installing)h(o)n(v)n(er)e(an)i(older)g
+(v)n(ersion,)0 1043 y(y)n(our)35 b(old)i(con\034g)e(scripts)i(will)f(b)
+r(e)h(bac)n(k)n(ed)f(up)h(b)r(efore)f(b)r(eing)h(replaced.)63
+b(The)36 b(sa)n(v)n(ed)f(scripts)h(will)h(b)r(e)g(giv)n(en)f(an)g
+Fh(*.O)0 1156 y Fm(extension.)0 1313 y(If)j(y)n(ou)g(don't)g(kno)n(w)f
+(what)h(kind)g(of)g(host)g(con)n(troller)e(y)n(our)h(system)g(uses,)k
+(y)n(ou)c(can)h(use)g(the)g Fh(probe)e Fm(utilit)n(y)i(in)h(the)0
+1426 y Fh(cardmgr/)26 b Fm(sub)r(directory)j(to)g(determine)g(this.)43
+b(There)29 b(are)f(t)n(w)n(o)h(ma)5 b(jor)28 b(t)n(yp)r(es:)41
+b(the)30 b(Datab)r(o)r(ok)e(TCIC-2)h(t)n(yp)r(e)g(and)h(the)0
+1540 y(In)n(tel)e(i82365SL-compatible)c(t)n(yp)r(e.)0
+1696 y(In)30 b(a)g(few)g(cases,)f(the)h Fh(probe)e Fm(command)i(will)g
+(b)r(e)g(unable)g(to)f(determine)h(y)n(our)f(con)n(troller)f(t)n(yp)r
+(e)i(automatically)-7 b(.)43 b(If)30 b(y)n(ou)0 1810
+y(ha)n(v)n(e)35 b(a)g(Halik)-5 b(an)36 b(NBD)h(486)d(system,)k(it)f
+(has)e(a)h(TCIC-2)f(con)n(troller)f(at)i(an)g(un)n(usual)f(lo)r
+(cation:)53 b(y)n(ou'll)36 b(need)g(to)g(edit)0 1923
+y Fh(rc.pcmcia)24 b Fm(to)j(load)g(the)h Fh(tcic)e Fm(mo)r(dule,)i(and)
+f(also)g(set)g(the)h Fh(PCIC_OPTS)c Fm(parameter)i(to)i(\020)7
+b Fh(tcic_base=0x02)o(c0)o Fm(\021.)0 2080 y(On)32 b(some)f(systems)h
+(using)f(Cirrus)g(con)n(trollers,)g(including)h(the)h(NEC)f(V)-7
+b(ersa)31 b(M,)i(the)f(BIOS)f(puts)i(the)f(con)n(troller)e(in)i(a)0
+2193 y(sp)r(ecial)k(susp)r(ended)g(state)f(at)h(system)g(startup)f
+(time.)62 b(On)36 b(these)g(systems,)h(the)g Fh(probe)c
+Fm(command)j(will)g(fail)g(to)g(\034nd)0 2307 y(an)n(y)f(kno)n(wn)g
+(host)h(con)n(troller.)60 b(If)37 b(this)f(happ)r(ens,)i(edit)e
+Fh(rc.pcmcia)d Fm(and)i(set)h Fh(PCIC)f Fm(to)h Fh(i82365)p
+Fm(,)f(and)h Fh(PCIC_OPTS)c Fm(to)0 2420 y(\020)7 b Fh(wakeup=1)p
+Fm(\021.)0 2712 y Fe(2.3)112 b(Startup)38 b(options)0
+2922 y Fm(The)f(PCMCIA)g(startup)f(script)g(recognizes)f(sev)n(eral)g
+(groups)g(of)h(startup)g(options,)i(set)f(via)f(en)n(vironmen)n(t)f(v)
+-5 b(ariables.)0 3036 y(Multiple)21 b(options)f(should)h(b)r(e)g
+(separated)e(b)n(y)h(spaces)g(and)g(enclosed)g(in)h(quotes.)34
+b(Placemen)n(t)21 b(of)f(startup)h(options)f(dep)r(ends)0
+3149 y(on)34 b(the)h(Lin)n(ux)f(distribution)h(used.)57
+b(They)35 b(ma)n(y)e(b)r(e)i(placed)f(directly)h(in)f(the)h(startup)f
+(script,)i(or)e(they)h(ma)n(y)e(b)r(e)i(k)n(ept)0 3263
+y(in)30 b(a)f(separate)f(option)h(\034le.)43 b(See)29
+b(the)h(2.5)e(\(Notes)i(ab)r(out)f(sp)r(eci\034c)h(Lin)n(ux)f
+(distributions\))g(for)g(sp)r(eci\034cs.)43 b(The)29
+b(follo)n(wing)0 3376 y(v)-5 b(ariables)26 b(can)h(b)r(e)h(set:)0
+3616 y Fh(PCMCIA)208 3763 y Fm(This)e(v)-5 b(ariable)26
+b(sp)r(eci\034es)h(whether)g(PCMCIA)h(supp)r(ort)f(should)f(b)r(e)i
+(started)e(up,)i(or)e(not.)36 b(If)28 b(it)f(is)g(set)g(to)g(an)n
+(ything)208 3876 y(other)g(than)g(\020y)n(es\021,)f(then)i(the)g
+(startup)g(script)f(will)h(b)r(e)g(disabled.)0 4056 y
+Fh(PCIC)208 4203 y Fm(This)39 b(iden)n(ti\034es)h(the)g(PC)g(Card)e(In)
+n(terface)h(Con)n(troller)f(driv)n(er)g(mo)r(dule.)73
+b(There)39 b(are)g(t)n(w)n(o)g(options:)60 b(\020tcic\021)46
+b(or)208 4317 y(\020i82365\021.)33 b(Virtually)24 b(all)h(curren)n(t)f
+(con)n(trollers)f(are)h(in)i(the)f(\020i82365\021)k(group.)35
+b(This)25 b(is)g(the)g(only)g(mandatory)e(option)208
+4430 y(setting.)0 4610 y Fh(PCIC_OPTS)208 4757 y Fm(This)k(sp)r
+(eci\034es)g(options)g(for)f(the)i(PCIC)g(mo)r(dule.)37
+b(Some)27 b(host)g(con)n(trollers)e(ha)n(v)n(e)h(optional)g(features)h
+(that)g(ma)n(y)g(or)208 4871 y(ma)n(y)d(not)h(b)r(e)g(implemen)n(ted)h
+(in)f(a)g(particular)f(system.)35 b(In)25 b(some)g(cases,)f(it)i(is)f
+(imp)r(ossible)g(for)f(the)i(so)r(c)n(k)n(et)e(driv)n(er)f(to)208
+4984 y(detect)30 b(if)g(these)g(features)f(are)g(implemen)n(ted.)44
+b(See)29 b(the)h(corresp)r(onding)e(man)i(page)f(for)g(a)g(complete)h
+(description)208 5098 y(of)d(the)h(a)n(v)-5 b(ailable)26
+b(options.)0 5278 y Fh(CORE_OPTS)p eop
+%%Page: 10 10
+10 9 bop 0 -167 3900 5 v 0 -200 a Ff(2.)73 b(Compilation)29
+b(and)k(installation)2473 b Fm(10)208 162 y(This)21 b(sp)r(eci\034es)f
+(options)h(for)f(the)i Fh(pcmcia_core)16 b Fm(mo)r(dule,)23
+b(whic)n(h)e(implemen)n(ts)g(the)h(core)e(PC)h(Card)g(driv)n(er)e
+(services.)208 275 y(See)27 b(\020)7 b Fh(man)42 b(pcmcia_core)p
+Fm(\021)30 b(for)d(more)f(information.)0 455 y Fh(CARDMGR_OPTS)208
+602 y Fm(This)g(sp)r(eci\034es)h(options)f(to)h(b)r(e)g(passed)f(to)h
+(the)g Fh(cardmgr)d Fm(daemon.)36 b(See)27 b(\020)7 b
+Fh(man)42 b(cardmgr)p Fm(\021)30 b(for)d(more)f(information.)0
+782 y Fh(SCHEME)208 929 y Fm(If)f(set,)g(then)h(the)f(PC)g(Card)f
+(con\034guration)f(sc)n(heme)i(will)g(b)r(e)g(initialized)g(to)g(this)g
+(at)f(driv)n(er)g(startup)g(time.)37 b(See)25 b(the)208
+1042 y(4.2)h(\(Ov)n(erview)g(of)i(the)g(PCMCIA)g(con\034guration)e
+(scripts\))h(for)g(a)h(discussion)e(of)i(sc)n(hemes.)0
+1282 y(The)41 b(lo)n(w)f(lev)n(el)h(so)r(c)n(k)n(et)f(driv)n(ers,)i
+Fh(tcic)e Fm(and)h Fh(i82365)p Fm(,)h(ha)n(v)n(e)d(v)-5
+b(arious)40 b(bus)h(timing)g(parameters)f(that)h(ma)n(y)f(need)h(to)0
+1395 y(b)r(e)29 b(adjusted)g(for)g(certain)f(systems)g(with)i(un)n
+(usual)e(bus)h(clo)r(c)n(king.)39 b(Symptoms)29 b(of)g(timing)g
+(problems)f(can)h(include)g(card)0 1509 y(recognition)21
+b(problems,)i(lo)r(c)n(k-ups)e(under)h(hea)n(vy)g(loads,)g(high)g
+(error)f(rates,)h(or)g(p)r(o)r(or)g(device)g(p)r(erformance.)34
+b(Only)22 b(certain)0 1623 y(host)27 b(bridges)f(ha)n(v)n(e)g
+(adjustable)h(timing)g(parameters:)35 b(c)n(hec)n(k)27
+b(the)g(corresp)r(onding)e(man)i(page)g(to)g(see)f(what)i(options)e
+(are)0 1736 y(a)n(v)-5 b(ailable)26 b(for)h(y)n(our)g(con)n(troller.)34
+b(Here)28 b(is)f(a)g(brief)h(summary:)125 1976 y Fd(\017)41
+b Fm(Cirrus)21 b(con)n(trollers)g(ha)n(v)n(e)h(n)n(umerous)g
+(con\034gurable)f(timing)i(parameters.)34 b(The)23 b(most)g(imp)r
+(ortan)n(t)f(seems)h(to)f(b)r(e)i(the)208 2089 y Fh(cmd_time)h
+Fm(\035ag,)i(whic)n(h)i(determines)f(the)g(length)h(of)f(PCMCIA)h(bus)f
+(cycles.)39 b(F)-7 b(ast)28 b(486)f(systems)h(\(i.e.,)h(D)n(X4-100\))
+208 2203 y(seem)e(to)g(often)h(b)r(ene\034t)h(from)e(increasing)f(this)
+i(from)f(6)g(\(the)h(default\))g(to)g(12)f(or)f(16.)125
+2383 y Fd(\017)41 b Fm(The)26 b(Cirrus)g(PD6729)g(PCI)h(con)n(troller)e
+(has)i(the)g Fh(fast_pci)d Fm(\035ag,)i(whic)n(h)h(should)f(b)r(e)h
+(set)g(if)h(the)f(PCI)g(bus)g(sp)r(eed)g(is)208 2496
+y(greater)e(than)j(25)f(MHz.)125 2676 y Fd(\017)41 b
+Fm(F)-7 b(or)32 b(V)-7 b(adem)33 b(V)n(G-468)e(con)n(trollers,)h(the)h
+Fh(async_clock)c Fm(\035ag)j(c)n(hanges)f(the)i(relativ)n(e)f(clo)r(c)n
+(king)g(of)g(PCMCIA)i(bus)208 2790 y(and)29 b(host)f(bus)i(cycles.)40
+b(Setting)30 b(this)f(\035ag)g(adds)f(extra)h(w)n(ait)f(states)h(to)g
+(some)g(op)r(erations.)40 b(Ho)n(w)n(ev)n(er,)27 b(I)i(ha)n(v)n(e)f(y)n
+(et)208 2904 y(to)f(hear)g(of)g(a)g(laptop)h(that)f(needs)h(this.)125
+3084 y Fd(\017)41 b Fm(The)e Fh(pcmcia_core)c Fm(mo)r(dule)40
+b(has)g(the)g Fh(cis_speed)c Fm(parameter)i(for)h(c)n(hanging)f(the)i
+(memory)f(sp)r(eed)h(used)g(for)208 3197 y(accessing)23
+b(a)h(card's)g(Card)f(Information)h(Structure)h(\(CIS\).)g(On)g(some)f
+(systems)g(with)h(fast)g(bus)f(clo)r(c)n(ks,)h(increasing)208
+3311 y(this)i(parameter)f(\(i.e.,)i(slo)n(wing)f(do)n(wn)g(card)f
+(accesses\))h(ma)n(y)g(b)r(e)h(b)r(ene\034cial)f(for)g(card)g
+(recognition)f(problems.)125 3491 y Fd(\017)41 b Fm(This)24
+b(is)g(not)g(a)g(timing)g(issue,)h(but)g(if)g(y)n(ou)e(ha)n(v)n(e)g
+(more)h(than)g(one)g(ISA-to-PCMCIA)g(con)n(troller)f(in)h(y)n(our)f
+(system)h(or)208 3604 y(extra)c(so)r(c)n(k)n(ets)f(in)i(a)g(laptop)g
+(do)r(c)n(king)f(station,)h(the)h Fh(i82365)c Fm(mo)r(dule)j(should)g
+(b)r(e)h(loaded)e(with)h(the)h Fh(extra_sockets)208 3718
+y Fm(parameter)g(set)j(to)f(1.)36 b(This)24 b(should)g(not)g(b)r(e)h
+(necessary)e(for)h(detection)g(of)h(PCI-to-PCMCIA)f(or)g
+(PCI-to-CardBus)208 3831 y(bridges.)125 4011 y Fd(\017)41
+b Fm(With)30 b(SCM)g(Microsystems)f(SBP)h(series)f(PCI)i(card)e
+(readers)f(\(whic)n(h)i(are)f(also)f(b)r(eing)i(distributed)h(with)f
+(Lucen)n(t)208 4125 y(W)-7 b(a)n(v)n(eLan)33 b(cards\),)j(it)f(is)g
+(necessary)e(to)i(sp)r(ecify)g Fh(irq_mode=0)c Fm(for)j(the)i
+Fh(i82365)c Fm(mo)r(dule,)37 b(to)e(force)f(use)h(of)g(PCI)208
+4239 y(in)n(terrupts.)0 4478 y(Here)27 b(are)g(some)g(timing)h
+(settings)f(for)g(sp)r(eci\034c)h(systems:)125 4717 y
+Fd(\017)41 b Fm(On)27 b(the)h(ARM)g(P)n(en)n(tium-90)f(or)f(Midw)n(est)
+i(Micro)f(Soundb)r(o)r(ok)g(Plus,)h(use)f(\020)7 b Fh(freq_bypass=1)38
+b(cmd_time=8)p Fm(\021.)125 4897 y Fd(\017)j Fm(On)27
+b(a)g(Midw)n(est)h(Micro)e(Soundb)r(o)r(ok)h(Elite,)i(use)e(\020)7
+b Fh(cmd_time=12)p Fm(\021.)125 5077 y Fd(\017)41 b Fm(On)27
+b(a)g(Gatew)n(a)n(y)f(Lib)r(ert)n(y)-7 b(,)28 b(try)f(\020)7
+b Fh(cmd_time=16)p Fm(\021.)125 5257 y Fd(\017)41 b Fm(On)27
+b(a)g(Samsung)g(SENS)i(810,)d(use)h(\020)7 b Fh(fast_pci=1)p
+Fm(\021.)p eop
+%%Page: 11 11
+11 10 bop 0 -167 3900 5 v 0 -200 a Ff(2.)73 b(Compilation)29
+b(and)k(installation)2473 b Fm(11)0 162 y Fe(2.4)112
+b(System)37 b(resource)h(settings)0 372 y Fm(Card)21
+b(Services)h(should)g(automatically)f(a)n(v)n(oid)g(allo)r(cating)g(IO)
+h(p)r(orts)f(and)h(in)n(terrupts)g(already)f(in)h(use)g(b)n(y)g(other)g
+(standard)0 485 y(devices.)36 b(It)25 b(will)h(also)e(attempt)i(to)f
+(detect)h(con\035icts)f(with)h(unkno)n(wn)f(devices,)g(but)h(this)g(is)
+f(not)h(completely)f(reliable.)35 b(In)0 599 y(some)27
+b(cases,)f(y)n(ou)h(ma)n(y)g(need)h(to)f(explicitly)h(exclude)f
+(resources)f(for)h(a)g(device)g(in)h Fh(/etc/pcmcia/conf)o(ig)o(.op)o
+(ts)o Fm(.)0 755 y(Here)j(are)f(some)g(resource)g(settings)g(for)h(sp)r
+(eci\034c)g(laptop)g(t)n(yp)r(es.)48 b(View)31 b(this)g(list)h(with)f
+(suspicion:)44 b(it)31 b(ma)n(y)g(giv)n(e)f(useful)0
+869 y(hin)n(ts)e(for)f(solving)f(problems,)h(but)h(it)g(is)f
+(inevitably)g(out)h(of)f(date)h(and)f(certainly)g(con)n(tains)f(mistak)
+n(es.)36 b(Corrections)25 b(and)0 983 y(additions)i(are)g(w)n(elcome.)
+125 1214 y Fd(\017)41 b Fm(On)27 b(the)h(AMS)g(SoundPro,)f(exclude)h
+(irq)f(10.)125 1390 y Fd(\017)41 b Fm(On)27 b(some)g(AMS)h(T)-7
+b(ra)n(v)n(elPro)25 b(5300)h(mo)r(dels,)h(use)h(memory)f
+(0xc8000-0xc\033\033.)125 1567 y Fd(\017)41 b Fm(On)27
+b(the)h(BMX)g(486D)n(X2-66,)c(exclude)k(irq)f(5,)g(irq)g(9.)125
+1744 y Fd(\017)41 b Fm(On)27 b(the)h(Chicon)n(y)f(NB5,)g(use)g(memory)g
+(0xda000-0xd\033\033.)125 1920 y Fd(\017)41 b Fm(On)27
+b(the)h(Compaq)f(Presario)e(1020,)h(exclude)i(p)r(ort)f(0x2f8-0x2\033,)
+e(irq)i(3,)g(irq)h(5.)125 2097 y Fd(\017)41 b Fm(On)27
+b(the)h(Dell)g(Inspiron)f(7000,)e(exclude)j(irq)f(3,)g(irq)g(5.)125
+2274 y Fd(\017)41 b Fm(On)27 b(the)h(F)-7 b(ujitsu)28
+b(C)g(series,)f(exclude)g(p)r(ort)g(0x200-0x27f.)125
+2451 y Fd(\017)41 b Fm(On)27 b(the)h(HP)g(Omnib)r(o)r(ok)f(4000C,)f
+(exclude)h(p)r(ort)h(0x300-0x30f.)125 2627 y Fd(\017)41
+b Fm(On)27 b(the)h(IBM)f(ThinkP)n(ad)h(380,)e(and)h(ma)n(yb)r(e)h(the)g
+(385)e(and)h(600)f(series,)h(exclude)g(p)r(ort)h(0x230-0x233,)23
+b(and)k(irq)g(5.)125 2804 y Fd(\017)41 b Fm(On)27 b(IBM)g(ThinkP)n(ad)h
+(600)e(and)h(770)g(mo)r(dels)g(with)h(in)n(ternal)f(mo)r(dems,)h
+(exclude)f(p)r(ort)g(0x2f8-0x2\033.)125 2981 y Fd(\017)41
+b Fm(On)27 b(the)h(IBM)f(ThinkP)n(ad)h(600E)f(and)g(770Z,)f(c)n(hange)g
+(the)i(high)g(memory)e(windo)n(w)h(to)h(0x60000000-0x60)o
+(\033\033\033.)125 3157 y Fd(\017)41 b Fm(On)27 b(the)h(Micron)f
+(Millenia)g(T)-7 b(ransp)r(ort,)26 b(exclude)i(irq)f(5,)g(irq)g(9.)125
+3334 y Fd(\017)41 b Fm(On)27 b(the)h(NEC)g(V)-7 b(ersa)27
+b(M,)h(exclude)f(irq)g(9,)g(p)r(ort)h(0x2e0-2\033.)125
+3511 y Fd(\017)41 b Fm(On)27 b(the)h(NEC)g(V)-7 b(ersa)27
+b(P/75,)g(exclude)g(irq)g(5,)g(irq)g(9.)125 3687 y Fd(\017)41
+b Fm(On)27 b(the)h(NEC)g(V)-7 b(ersa)27 b(S,)h(exclude)f(irq)g(9,)g
+(irq)g(12.)125 3864 y Fd(\017)41 b Fm(On)27 b(the)h(NEC)g(V)-7
+b(ersa)27 b(6000)f(series,)g(exclude)h(p)r(ort)h(0x2f8-0x33f,)d(irq)i
+(9,)g(irq)g(10.)125 4041 y Fd(\017)41 b Fm(On)27 b(the)h(NEC)g(V)-7
+b(ersa)27 b(SX,)h(exclude)f(p)r(ort)h(0x300-0x31f.)125
+4217 y Fd(\017)41 b Fm(On)33 b(the)i(ProStar)e(9200,)h(Altima)h
+(Virage,)f(and)g(A)n(cquiline)g(Hurricane)g(D)n(X4-100,)f(exclude)i
+(irq)e(5,)j(p)r(ort)e(0x330-)208 4331 y(0x35f.)h(Ma)n(yb)r(e)27
+b(use)h(memory)e(0xd8000-0xd\033\033.)125 4508 y Fd(\017)41
+b Fm(On)27 b(the)h(Siemens)f(Nixdorf)h(SIMA)-7 b(TIC)28
+b(PG)g(720C,)e(use)i(memory)e(0xc0000-0xc\033\033,)f(p)r(ort)i
+(0x300-0x3bf.)125 4684 y Fd(\017)41 b Fm(On)27 b(the)h(TI)f(T)-7
+b(ra)n(v)n(elMate)26 b(5000,)g(use)h(memory)g(0xd4000-0xd\033\033.)125
+4861 y Fd(\017)41 b Fm(On)27 b(the)h(T)-7 b(oshiba)27
+b(T4900)e(CT,)j(exclude)f(irq)g(5,)g(p)r(ort)h(0x2e0-0x2e8,)c(p)r(ort)j
+(0x330-0x338.)125 5038 y Fd(\017)41 b Fm(On)27 b(the)h(T)-7
+b(oshiba)27 b(T)-7 b(ecra)26 b(8000,)g(exclude)h(irq)g(3,)g(irq)g(5,)h
+(irq)f(9.)125 5214 y Fd(\017)41 b Fm(On)27 b(the)h(T)-7
+b(winhead)27 b(5100,)f(HP)i(4000,)e(Sharp)h(PC-8700)f(and)h(PC-8900,)f
+(exclude)i(irq)f(9)g(\(sound\),)h(irq)f(12.)125 5391
+y Fd(\017)41 b Fm(On)27 b(an)g(MPC)h(800)f(Series,)f(exclude)i(irq)f
+(5,)g(p)r(ort)h(0x300-0x30f)23 b(for)k(the)h(CD-R)n(OM.)p
+eop
+%%Page: 12 12
+12 11 bop 0 -167 3900 5 v 0 -200 a Ff(2.)73 b(Compilation)29
+b(and)k(installation)2473 b Fm(12)0 162 y Fe(2.5)112
+b(Notes)37 b(ab)s(out)h(sp)s(eci\034c)f(Lin)m(ux)h(distributions)0
+372 y Fm(This)28 b(section)f(is)g(incomplete.)37 b(Corrections)26
+b(and)h(additions)g(are)g(w)n(elcome.)0 644 y Ff(2.5.1)94
+b(Debian)0 854 y Fm(Debian)59 b(uses)f(a)g(System)h(V)g(b)r(o)r(ot)f
+(script)h(arrangemen)n(t.)127 b(The)59 b(PCMCIA)g(startup)g(script)f
+(is)g(installed)h(as)0 968 y Fh(/etc/init.d/pcmc)o(ia)o
+Fm(,)35 b(and)i(startup)h(options)f(are)g(sp)r(eci\034ed)h(in)g
+Fh(/etc/pcmcia.con)o(f)p Fm(.)61 b(Debian's)38 b(syslog)e(con\034gu-)0
+1082 y(ration)27 b(will)g(place)h(k)n(ernel)e(messages)g(in)i
+Fh(/var/log/messag)o(es)21 b Fm(and)28 b Fh(cardmgr)c
+Fm(messages)i(in)i Fh(/var/log/daemon.)o(lo)o(g)p Fm(.)0
+1238 y(Debian)k(distributes)f(the)h(PCMCIA)g(system)f(in)g(t)n(w)n(o)g
+(pac)n(k)-5 b(ages:)42 b(the)32 b(\020)7 b Fh(pcmcia-cs)p
+Fm(\021)34 b(pac)n(k)-5 b(age)30 b(con)n(tains)g Fh(cardmgr)e
+Fm(and)0 1352 y(other)k(to)r(ols,)h(man)f(pages,)h(and)f
+(con\034guration)f(scripts;)j(and)e(the)h(\020)7 b Fh(pcmcia-modules)p
+Fm(\021)33 b(pac)n(k)-5 b(age)31 b(con)n(tains)g(the)i(k)n(ernel)0
+1465 y(driv)n(er)26 b(mo)r(dules.)0 1738 y Ff(2.5.2)94
+b(Red)31 b(Hat,)g(Caldera,)h(Mandrak)m(e)0 1948 y Fm(These)h
+(distributions)g(use)g(a)g(System)g(V)g(b)r(o)r(ot)h(script)e
+(organization.)52 b(The)33 b(PCMCIA)h(startup)f(script)g(is)g
+(installed)g(as)0 2061 y Fh(/etc/rc.d/init.d)o(/p)o(cmc)o(ia)o
+Fm(,)22 b(and)28 b(b)r(o)r(ot)g(options)f(are)f(k)n(ept)i(in)g
+Fh(/etc/sysconfig/p)o(cm)o(cia)o Fm(.)j(Bew)n(are)c(that)h(installing)0
+2175 y(the)d(Red)f(Hat)g(pac)n(k)-5 b(age)23 b(ma)n(y)h(install)g(a)g
+(default)g(b)r(o)r(ot)h(option)e(\034le)i(that)f(has)g(PCMCIA)h
+(disabled.)35 b(T)-7 b(o)24 b(enable)g(PCMCIA,)0 2289
+y(the)41 b(\020)7 b Fh(PCMCIA)p Fm(\021)44 b(v)-5 b(ariable)40
+b(should)g(b)r(e)i(set)e(to)h(\020)7 b Fh(yes)p Fm(\021.)74
+b(Red)41 b(Hat's)f(default)i Fh(syslogd)37 b Fm(con\034guration)i(will)
+i(record)e(all)0 2402 y(in)n(teresting)27 b(messages)f(in)h
+Fh(/var/log/messages)o Fm(.)0 2559 y(Red)32 b(Hat's)g(PCMCIA)h(pac)n(k)
+-5 b(age)31 b(con)n(tains)g(a)h(replacemen)n(t)f(for)g(the)i(net)n(w)n
+(ork)e(setup)h(script,)h Fh(/etc/pcmcia/netw)o(or)o(k)p
+Fm(,)0 2672 y(whic)n(h)26 b(meshes)g(with)g(the)h(Red)f(Hat)g
+Fh(linuxconf)d Fm(con\034guration)h(system.)36 b(This)26
+b(is)g(con)n(v)n(enien)n(t)f(for)g(the)i(case)e(where)h(just)0
+2786 y(one)32 b(net)n(w)n(ork)g(adapter)g(is)g(used,)i(with)g(one)e
+(set)h(of)g(net)n(w)n(ork)e(parameters,)h(but)i(do)r(es)e(not)h(ha)n(v)
+n(e)f(the)h(full)g(\035exibilit)n(y)g(of)0 2899 y(the)i(regular)e
+(PCMCIA)j(net)n(w)n(ork)e(script.)58 b(Compiling)35 b(and)g(installing)
+f(a)h(clean)f(PCMCIA)i(source)e(distribution)h(will)0
+3013 y(o)n(v)n(erwrite)25 b(the)j(net)n(w)n(ork)e(script,)h(breaking)f
+(the)h(link)h(to)f(the)h(Red)f(Hat)h(to)r(ols.)36 b(If)28
+b(y)n(ou)e(prefer)h(using)g(the)h(Red)f(Hat)h(to)r(ols,)0
+3127 y(either)f(use)h(only)f(Red)h(Hat)f(RPM's,)i(or)d(replace)h
+Fh(/etc/pcmcia/net)o(wor)o(k.)o(op)o(ts)21 b Fm(with)28
+b(the)g(follo)n(wing:)208 3357 y Fc(if)39 b([)h(-f)f
+(/etc/sysconfig/network-script)q(s/if)q(cfg-e)q(th0)45
+b(])40 b(;)f(then)364 3461 y(start_fn)i(\(\))f({)521
+3565 y(/sbin/ifup)i($1)364 3669 y(})364 3773 y(stop_fn)f(\(\))f({)521
+3877 y(/sbin/ifdown)i($1)364 3981 y(})208 4085 y(fi)0
+4325 y Fm(If)30 b(y)n(ou)f(do)g(use)g Fh(linuxconf)d
+Fm(\(or)j Fh(netconf)p Fm(\))e(to)j(con\034gure)e(y)n(our)g(net)n(w)n
+(ork)g(in)n(terface,)i(lea)n(v)n(e)e(the)i(\020k)n(ernel)e(mo)r
+(dule\021,)i(\020I/O)0 4438 y(p)r(ort\021,)39 b(and)e(\020irq\021)43
+b(parameters)35 b(blank.)65 b(Setting)37 b(these)g(parameters)f(ma)n(y)
+g(in)n(terfere)g(with)i(prop)r(er)e(op)r(eration)g(of)h(the)0
+4552 y(PCMCIA)28 b(subsystem.)0 4708 y(A)n(t)e(b)r(o)r(ot)g(time,)h
+(when)f(the)g(Red)h(Hat)f(net)n(w)n(ork)e(subsystem)i(starts)f(up,)h
+(it)h(ma)n(y)e(sa)n(y)g(\020Dela)n(ying)f(eth0)i(initialization\021)32
+b(and)0 4822 y(\020)7 b([F)-9 b(AILED]\021.)30 b(This)g(is)f(actually)g
+(not)h(a)f(failure:)41 b(it)30 b(means)f(that)h(this)g(net)n(w)n(ork)e
+(in)n(terface)h(will)h(not)g(b)r(e)g(initialized)g(un)n(til)0
+4936 y(after)d(the)h(PCMCIA)h(net)n(w)n(ork)d(device)h(is)g
+(con\034gured.)0 5092 y(Red)h(Hat)g(bundles)g(their)g(sligh)n(tly)f(mo)
+r(di\034ed)h(PCMCIA)h(source)e(distribution)g(in)i(their)e(k)n(ernel)g
+(SRPM,)i(rather)e(than)h(as)0 5206 y(a)f(separate)f(source)h(pac)n(k)-5
+b(age.)p eop
+%%Page: 13 13
+13 12 bop 0 -167 3900 5 v 0 -200 a Ff(3.)73 b(Resolving)30
+b(installation)h(and)h(con\034guration)g(problems)1589
+b Fm(13)0 162 y Ff(2.5.3)94 b(Slac)m(kw)m(are)0 372 y
+Fm(Slac)n(kw)n(are)64 b(uses)i(a)f(BSD)i(b)r(o)r(ot)f(script)g
+(arrangemen)n(t.)150 b(The)66 b(PCMCIA)h(startup)f(script)g(is)g
+(installed)g(as)0 485 y Fh(/etc/rc.d/rc.pcm)o(ci)o(a)p
+Fm(,)32 b(and)j(b)r(o)r(ot)h(options)f(are)f(sp)r(eci\034ed)i(in)g
+Fh(rc.pcmcia)c Fm(itself.)61 b(The)36 b(PCMCIA)g(startup)f(script)0
+599 y(is)27 b(in)n(v)n(ok)n(ed)f(from)i Fh(/etc/rc.d/rc.S)p
+Fm(.)0 872 y Ff(2.5.4)94 b(SuSE)0 1082 y Fm(SuSE)27 b(uses)e(a)h
+(System)g(V)g(init)h(script)e(arrangemen)n(t,)f(with)j(init)f(scripts)f
+(stored)g(under)h Fh(/sbin/init.d)p Fm(.)31 b(The)26
+b(PCMCIA)0 1195 y(startup)i(script)f(is)h(installed)g(as)f
+Fh(/sbin/init.d/pc)o(mci)o(a)p Fm(,)22 b(and)28 b(startup)f(options)g
+(are)g(k)n(ept)h(in)g Fh(/etc/rc.config)p Fm(.)k(The)0
+1309 y(SuSE)i(startup)g(script)f(is)g(somewhat)g(limited)h(and)f(do)r
+(es)g(not)h(allo)n(w)e(PCMCIA)j(startup)e(v)-5 b(ariables)32
+b(to)h(b)r(e)h(o)n(v)n(erridden)0 1422 y(from)27 b(the)h
+Fh(lilo)e Fm(b)r(o)r(ot)i(prompt.)0 1761 y Fg(3)131 b(Resolving)44
+b(installation)i(and)d(con\034guration)i(problems)0 1999
+y Fm(This)29 b(section)g(describ)r(es)f(some)h(of)g(the)h(most)f
+(common)f(failure)h(mo)r(des)g(for)g(the)g(PCMCIA)h(subsystem.)42
+b(T)-7 b(ry)28 b(to)h(matc)n(h)0 2113 y(y)n(our)e(symptoms)i(against)e
+(the)i(examples.)40 b(This)29 b(section)f(only)g(describ)r(es)g
+(general)g(failures)g(that)h(are)e(not)i(sp)r(eci\034c)g(to)f(a)0
+2226 y(particular)e(clien)n(t)i(driv)n(er)e(or)h(t)n(yp)r(e)h(of)f
+(card.)0 2383 y(Before)f(trying)h(to)g(diagnose)e(a)i(problem,)g(y)n
+(ou)f(ha)n(v)n(e)g(to)h(kno)n(w)f(where)h(y)n(our)f(system)g(log)h(is)g
+(k)n(ept)g(\(see)g(2.5)f(\(Notes)h(ab)r(out)0 2497 y(sp)r(eci\034c)f
+(Lin)n(ux)g(distributions\)\).)37 b(Y)-7 b(ou)27 b(should)f(also)f(b)r
+(e)i(familiar)e(with)i(basic)f(diagnostic)f(to)r(ols)h(lik)n(e)g
+Fh(dmesg)e Fm(and)i Fh(lsmod)p Fm(.)0 2610 y(Also,)34
+b(b)r(e)g(a)n(w)n(are)c(that)k(most)f(driv)n(er)e(comp)r(onen)n(ts)i
+(\(including)g(all)g(the)g(k)n(ernel)f(mo)r(dules\))i(ha)n(v)n(e)e
+(their)h(o)n(wn)f(individual)0 2724 y(man)27 b(pages.)0
+2880 y(T)-7 b(ry)25 b(to)g(de\034ne)g(y)n(our)f(problem)g(as)h(narro)n
+(wly)e(as)h(p)r(ossible.)36 b(If)26 b(y)n(ou)e(ha)n(v)n(e)g(sev)n(eral)
+f(cards,)i(try)g(eac)n(h)f(card)g(in)i(isolation,)e(and)0
+2994 y(in)k(di\033eren)n(t)g(com)n(binations.)37 b(T)-7
+b(ry)27 b(cold)g(Lin)n(ux)h(b)r(o)r(ots,)g(v)n(ersus)e(w)n(arm)h(b)r(o)
+r(ots)h(from)f(Windo)n(ws.)37 b(Compare)27 b(b)r(o)r(oting)h(with)0
+3107 y(cards)h(inserted,)i(v)n(ersus)e(inserting)h(cards)f(after)h(b)r
+(o)r(ot.)45 b(If)31 b(y)n(ou)e(normally)g(use)i(y)n(our)e(laptop)h(do)r
+(c)n(k)n(ed,)g(try)g(it)h(undo)r(c)n(k)n(ed.)0 3221 y(And)d(sometimes,)
+f(t)n(w)n(o)g(so)r(c)n(k)n(ets)f(will)i(b)r(eha)n(v)n(e)f(di\033eren)n
+(tly)-7 b(.)0 3377 y(It)21 b(is)f(nearly)f(imp)r(ossible)h(to)g(debug)g
+(driv)n(er)f(problems)g(encoun)n(tered)h(when)g(attempting)h(to)f
+(install)g(Lin)n(ux)g(via)f(a)h(PCMCIA)0 3491 y(device.)35
+b(Ev)n(en)23 b(if)g(y)n(ou)f(can)g(iden)n(tify)i(the)f(problem)f(based)
+g(on)h(its)g(symptoms,)g(installation)f(disks)h(are)e(di\036cult)j(to)f
+(mo)r(dify)-7 b(,)0 3604 y(esp)r(ecially)39 b(without)i(access)e(to)g
+(a)h(running)g(Lin)n(ux)f(system.)74 b(Customization)40
+b(of)g(installation)f(disks)g(is)h(completely)0 3718
+y(dep)r(enden)n(t)33 b(on)e(the)i(c)n(hoice)e(of)h(Lin)n(ux)g
+(distribution,)h(and)f(is)g(b)r(ey)n(ond)g(the)g(scop)r(e)g(of)g(this)g
+(do)r(cumen)n(t.)51 b(In)32 b(general,)g(the)0 3832 y(b)r(est)e(course)
+f(of)h(action)f(is)h(to)g(install)g(Lin)n(ux)f(using)h(some)f(other)g
+(means,)i(obtain)e(the)h(latest)g(driv)n(ers,)f(and)h(then)g(debug)0
+3945 y(the)e(problem)f(if)h(it)g(p)r(ersists.)0 4237
+y Fe(3.1)112 b(Base)38 b(PCMCIA)e(k)m(ernel)h(mo)s(dules)g(do)h(not)f
+(load)0 4447 y Fm(Symptoms:)125 4670 y Fd(\017)k Fm(Kernel)26
+b(v)n(ersion)g(mismatc)n(h)h(errors)f(are)g(rep)r(orted)h(when)h(the)g
+(PCMCIA)g(startup)f(script)h(runs.)125 4850 y Fd(\017)41
+b Fm(After)28 b(startup,)f Fh(lsmod)e Fm(do)r(es)j(not)f(sho)n(w)g(an)n
+(y)g(PCMCIA)h(mo)r(dules.)125 5030 y Fd(\017)41 b Fh(cardmgr)24
+b Fm(rep)r(orts)j(\020)7 b Fh(no)42 b(pcmcia)f(driver)g(in)i
+(/proc/devices)p Fm(\021)29 b(in)e(the)h(system)g(log.)0
+5253 y(Kernel)35 b(mo)r(dules)g(con)n(tain)g(v)n(ersion)e(information)i
+(that)h(is)f(c)n(hec)n(k)n(ed)f(against)g(the)i(curren)n(t)f(k)n(ernel)
+f(when)i(a)f(mo)r(dule)g(is)0 5366 y(loaded.)48 b(The)32
+b(t)n(yp)r(e)g(of)g(c)n(hec)n(king)e(dep)r(ends)i(on)f(the)h(setting)g
+(of)g(the)g Fh(CONFIG_MODVERSI)o(ON)o(S)26 b Fm(k)n(ernel)k(option.)49
+b(If)32 b(this)g(is)p eop
+%%Page: 14 14
+14 13 bop 0 -167 3900 5 v 0 -200 a Ff(3.)73 b(Resolving)30
+b(installation)h(and)h(con\034guration)g(problems)1589
+b Fm(14)0 162 y(false,)25 b(then)g(the)g(k)n(ernel)e(v)n(ersion)g(n)n
+(um)n(b)r(er)h(is)h(compiled)f(in)n(to)h(eac)n(h)e(mo)r(dule,)j(and)e
+Fh(insmod)e Fm(c)n(hec)n(ks)h(this)i(for)f(a)g(matc)n(h)h(with)0
+275 y(the)c(running)f(k)n(ernel.)34 b(If)21 b Fh(CONFIG_MODVERSIO)o(NS)
+14 b Fm(is)21 b(true,)h(then)f(eac)n(h)f(sym)n(b)r(ol)g(exp)r(orted)g
+(b)n(y)h(the)g(k)n(ernel)f(is)g(giv)n(en)g(a)g(sort)g(of)0
+389 y(c)n(hec)n(ksum.)34 b(These)21 b(co)r(des)g(are)g(all)g(compared)f
+(against)g(the)i(corresp)r(onding)e(co)r(des)h(compiled)g(in)n(to)g(a)g
+(mo)r(dule.)35 b(The)22 b(in)n(ten)n(t)0 502 y(w)n(as)29
+b(for)g(this)h(to)f(mak)n(e)g(mo)r(dules)g(less)h(v)n(ersion-dep)r
+(enden)n(t,)e(b)r(ecause)i(the)g(c)n(hec)n(ksums)e(w)n(ould)h(only)g(c)
+n(hange)g(if)h(a)f(k)n(ernel)0 616 y(in)n(terface)20
+b(c)n(hanged,)h(and)f(w)n(ould)g(generally)f(sta)n(y)h(the)h(same)f
+(across)e(minor)i(k)n(ernel)g(up)r(dates.)34 b(In)21
+b(practice,)g(the)g(c)n(hec)n(ksums)0 730 y(ha)n(v)n(e)27
+b(turned)h(out)h(to)f(b)r(e)g(ev)n(en)g(more)f(restrictiv)n(e,)g(b)r
+(ecause)h(man)n(y)g(k)n(ernel)f(in)n(terfaces)g(dep)r(end)i(on)f
+(compile-time)g(k)n(ernel)0 843 y(option)f(settings.)37
+b(Also,)27 b(the)h(c)n(hec)n(ksums)e(turned)i(out)g(to)f(b)r(e)h(an)f
+(excessiv)n(ely)f(p)r(essimistic)i(judge)g(of)f(compatibilit)n(y)-7
+b(.)0 1000 y(The)23 b(practical)f(upshot)h(of)g(this)h(is)f(that)g(k)n
+(ernel)f(mo)r(dules)h(are)f(closely)h(tied)g(to)g(b)r(oth)h(the)f(k)n
+(ernel)f(v)n(ersion,)h(and)g(the)g(setting)0 1113 y(of)g(man)n(y)f(k)n
+(ernel)g(con\034guration)g(options.)34 b(Generally)-7
+b(,)24 b(a)e(set)h(of)g(mo)r(dules)g(compiled)g(for)g(one)f(2.0.31)g(k)
+n(ernel)g(will)h(not)g(load)0 1227 y(against)29 b(some)g(other)g
+(2.0.31)f(k)n(ernel)h(unless)g(sp)r(ecial)h(care)e(is)i(tak)n(en)f(to)h
+(ensure)f(that)h(the)g(t)n(w)n(o)f(w)n(ere)g(built)i(with)f(similar)0
+1340 y(con\034gurations.)35 b(This)27 b(mak)n(es)g(distribution)g(of)h
+(precompiled)f(k)n(ernel)g(mo)r(dules)g(a)g(tric)n(ky)g(business.)0
+1497 y(Y)-7 b(ou)28 b(ha)n(v)n(e)e(sev)n(eral)g(options:)125
+1736 y Fd(\017)41 b Fm(If)f(y)n(ou)f(obtained)h(precompiled)g(driv)n
+(ers)e(as)i(part)f(of)h(a)g(Lin)n(ux)g(distribution,)j(v)n(erify)d
+(that)g(y)n(ou)g(are)f(using)g(an)208 1850 y(unmo)r(di\034ed)31
+b(k)n(ernel)e(as)h(supplied)h(with)g(that)g(distribution.)46
+b(If)31 b(y)n(ou)f(in)n(tend)h(to)f(use)h(precompiled)f(mo)r(dules,)h
+(y)n(ou)208 1963 y(generally)26 b(m)n(ust)h(stic)n(k)g(with)h(the)g
+(corresp)r(onding)e(k)n(ernel.)125 2143 y Fd(\017)41
+b Fm(If)32 b(y)n(ou)g(ha)n(v)n(e)f(recon\034gured)g(or)h(upgraded)f(y)n
+(our)g(k)n(ernel,)i(y)n(ou)f(will)h(probably)e(need)h(to)h(compile)f
+(and)g(install)h(the)208 2257 y(PCMCIA)24 b(pac)n(k)-5
+b(age)23 b(from)g(scratc)n(h.)35 b(This)24 b(is)g(easily)f(done)g(if)i
+(y)n(ou)e(already)g(ha)n(v)n(e)f(the)j(k)n(ernel)e(source)f(tree)i
+(installed.)208 2371 y(See)j(2)g(\(Compilation)h(and)f(installation\))g
+(for)g(detailed)h(instructions.)125 2551 y Fd(\017)41
+b Fm(In)d(some)g(cases,)j(incompatibilities)d(in)h(other)f(system)h
+(comp)r(onen)n(ts)f(can)g(prev)n(en)n(t)g(correct)f(loading)g(of)i(k)n
+(ernel)208 2664 y(mo)r(dules.)68 b(If)39 b(y)n(ou)e(ha)n(v)n(e)g
+(upgraded)g(y)n(our)g(o)n(wn)g(k)n(ernel,)j(pa)n(y)e(atten)n(tion)g(to)
+g(the)g(\020minimal)g(requiremen)n(ts\021)44 b(for)208
+2778 y(mo)r(dule)27 b(utilities)i(and)e(bin)n(utils)h(listed)g(in)f
+(the)h Fh(Documentation/Cha)o(ng)o(es)21 b Fm(\034le)28
+b(in)g(the)g(k)n(ernel)e(source)h(co)r(de)g(tree.)0 3069
+y Fe(3.2)112 b(Some)37 b(clien)m(t)f(driv)m(er)g(mo)s(dules)h(do)g(not)
+h(load)0 3279 y Fm(Symptoms:)125 3502 y Fd(\017)j Fm(The)27
+b(base)g(mo)r(dules)h(\()p Fh(pcmcia_core)p Fm(,)23 b
+Fh(ds)p Fm(,)k Fh(i82365)p Fm(\))e(load)i(correctly)-7
+b(.)125 3682 y Fd(\017)41 b Fm(Inserting)26 b(a)i(card)e(giv)n(es)h(a)g
+(high)g(b)r(eep)h(+)f(lo)n(w)g(b)r(eep)h(pattern.)125
+3862 y Fd(\017)41 b Fh(cardmgr)24 b Fm(rep)r(orts)j(v)n(ersion)f
+(mismatc)n(h)h(errors)e(in)j(the)g(system)f(log.)0 4085
+y(Some)33 b(of)h(the)g(driv)n(er)e(mo)r(dules)i(require)e(k)n(ernel)h
+(services)f(that)i(ma)n(y)e(or)h(ma)n(y)g(not)h(b)r(e)f(presen)n(t,)i
+(dep)r(ending)f(on)f(k)n(ernel)0 4199 y(con\034guration.)i(F)-7
+b(or)27 b(instance,)g(the)h(SCSI)f(card)f(driv)n(ers)g(require)g(that)i
+(the)g(k)n(ernel)e(b)r(e)i(con\034gured)e(with)i(SCSI)f(supp)r(ort,)0
+4312 y(and)37 b(the)g(net)n(w)n(ork)f(driv)n(ers)f(require)h(a)h(net)n
+(w)n(orking)e(k)n(ernel.)65 b(If)37 b(a)g(k)n(ernel)f(lac)n(ks)g(a)h
+(necessary)e(feature,)k Fh(insmod)c Fm(ma)n(y)0 4426
+y(rep)r(ort)29 b(unde\034ned)h(sym)n(b)r(ols)e(and)i(refuse)f(to)g
+(load)g(a)g(particular)f(mo)r(dule.)43 b(Note)30 b(that)g
+Fh(insmod)d Fm(error)g(messages)h(do)h(not)0 4539 y(distinguish)f(b)r
+(et)n(w)n(een)f(v)n(ersion)f(mismatc)n(h)h(errors)f(and)h(missing)g
+(sym)n(b)r(ol)g(errors.)0 4696 y(Sp)r(eci\034cally:)125
+4919 y Fd(\017)41 b Fm(The)25 b(serial)f(clien)n(t)h(driv)n(er)f
+Fh(serial_cs)d Fm(requires)j(the)h(k)n(ernel)g(serial)f(driv)n(er)f(to)
+i(b)r(e)h(enabled)f(with)g Fh(CONFIG_SERIAL)p Fm(.)208
+5032 y(This)i(driv)n(er)f(ma)n(y)h(b)r(e)h(built)g(as)f(a)g(mo)r(dule.)
+125 5212 y Fd(\017)41 b Fm(Supp)r(ort)24 b(for)g(m)n(ultip)r(ort)g
+(serial)f(cards)h(or)f(m)n(ultifunction)i(cards)e(that)i(include)g
+(serial)e(or)g(mo)r(dem)i(devices)e(requires)208 5326
+y Fh(CONFIG_SERIAL_S)o(HA)o(RE)o(_IR)o(Q)e Fm(to)28 b(b)r(e)g(enabled.)
+p eop
+%%Page: 15 15
+15 14 bop 0 -167 3900 5 v 0 -200 a Ff(3.)73 b(Resolving)30
+b(installation)h(and)h(con\034guration)g(problems)1589
+b Fm(15)125 162 y Fd(\017)41 b Fm(The)34 b(SCSI)h(clien)n(t)f(driv)n
+(ers)f(require)h(that)g Fh(CONFIG_SCSI)c Fm(b)r(e)35
+b(enabled,)h(along)e(with)h(the)f(appropriate)f(top)i(lev)n(el)208
+275 y(driv)n(er)26 b(options)h(\()p Fh(CONFIG_BLK_DEV_SD)o
+Fm(,)22 b Fh(CONFIG_BLK_DEV_SR)o Fm(,)g(etc)28 b(for)g(2.1)f(k)n
+(ernels\).)36 b(These)28 b(ma)n(y)f(b)r(e)h(built)h(as)208
+389 y(mo)r(dules.)125 569 y Fd(\017)41 b Fm(The)24 b(net)n(w)n(ork)f
+(clien)n(t)i(driv)n(ers)e(require)h(that)g Fh(CONFIG_INET)d
+Fm(is)j(enabled.)36 b(Kernel)23 b(net)n(w)n(orking)g(supp)r(ort)i
+(cannot)f(b)r(e)208 682 y(compiled)j(as)g(a)g(mo)r(dule.)125
+862 y Fd(\017)41 b Fm(The)27 b(tok)n(en-ring)f(clien)n(t)i(requires)e
+(that)i(the)g(k)n(ernel)e(b)r(e)i(compiled)g(with)g Fh(CONFIG_TR)c
+Fm(enabled.)0 1085 y(There)j(are)g(t)n(w)n(o)f(w)n(a)n(ys)g(to)i(pro)r
+(ceed:)125 1308 y Fd(\017)41 b Fm(Rebuild)28 b(y)n(our)e(k)n(ernel)h
+(with)h(the)g(necessary)d(features)i(enabled.)125 1488
+y Fd(\017)41 b Fm(If)35 b(the)h(features)f(ha)n(v)n(e)f(b)r(een)i
+(compiled)g(as)e(mo)r(dules,)k(then)e(mo)r(dify)g Fh(/etc/pcmcia/con)o
+(fi)o(g)30 b Fm(to)35 b(preload)f(these)208 1602 y(mo)r(dules.)0
+1825 y(The)27 b Fh(/etc/pcmcia/conf)o(ig)20 b Fm(\034le)27
+b(can)g(sp)r(ecify)g(that)g(additional)f(mo)r(dules)h(need)g(to)g(b)r
+(e)g(loaded)g(for)f(a)g(particular)g(clien)n(t.)0 1938
+y(F)-7 b(or)27 b(example,)g(for)g(the)h(serial)e(driv)n(er,)h(one)g(w)n
+(ould)g(use:)208 2168 y Fc(device)40 b("serial_cs")286
+2272 y(class)g("serial")h(module)g("misc/serial",)h("serial_cs")0
+2512 y Fm(Mo)r(dule)34 b(paths)g(are)f(sp)r(eci\034ed)h(relativ)n(e)f
+(to)h(the)g(top-lev)n(el)f(mo)r(dule)i(directory)d(for)i(the)g(curren)n
+(t)f(k)n(ernel)g(v)n(ersion;)j(if)e(no)0 2625 y(relativ)n(e)26
+b(path)i(is)f(giv)n(en,)g(then)h(the)g(path)g(defaults)g(to)f(the)h
+Fh(pcmcia)d Fm(sub)r(directory)-7 b(.)0 2917 y Fe(3.3)112
+b(In)m(terrupt)37 b(scan)h(failures)0 3127 y Fm(Symptoms:)125
+3350 y Fd(\017)j Fm(The)27 b(system)g(lo)r(c)n(ks)g(up)h(when)g(the)g
+(PCMCIA)g(driv)n(ers)e(are)h(loaded,)f(ev)n(en)i(with)g(no)f(cards)f
+(presen)n(t.)125 3530 y Fd(\017)41 b Fm(The)34 b(system)f(log)h(sho)n
+(ws)f(a)g(successful)h(host)g(con)n(troller)e(prob)r(e)i(just)g(b)r
+(efore)g(the)h(lo)r(c)n(k-up,)g(but)f(do)r(es)g(not)g(sho)n(w)208
+3643 y(in)n(terrupt)27 b(prob)r(e)g(results.)0 3866 y(After)32
+b(iden)n(tifying)g(the)h(host)e(con)n(troller)f(t)n(yp)r(e,)j(the)g(so)
+r(c)n(k)n(et)e(driv)n(er)f(prob)r(es)h(for)h(free)f(in)n(terrupts.)50
+b(The)32 b(prob)r(e)f(in)n(v)n(olv)n(es)0 3980 y(programming)20
+b(the)j(con)n(troller)d(for)i(eac)n(h)g(apparen)n(tly)f(free)h(in)n
+(terrupt,)h(then)g(generating)e(a)h(\020soft\021)28 b(in)n(terrupt,)c
+(to)e(see)g(if)h(the)0 4093 y(in)n(terrupt)j(can)g(b)r(e)g(detected)h
+(correctly)-7 b(.)35 b(In)26 b(some)g(cases,)f(probing)h(a)f
+(particular)g(in)n(terrupt)h(can)g(in)n(terfere)f(with)i(another)0
+4207 y(system)g(device.)0 4364 y(The)e(reason)e(for)i(the)g(prob)r(e)g
+(is)f(to)h(iden)n(tify)h(in)n(terrupts)e(whic)n(h)h(app)r(ear)f(to)h(b)
+r(e)g(free)g(\(i.e.,)h(are)e(not)h(reserv)n(ed)e(b)n(y)i(an)n(y)f
+(other)0 4477 y(Lin)n(ux)k(device)h(driv)n(er\),)f(y)n(et)g(are)g
+(either)h(not)f(ph)n(ysically)g(wired)g(to)h(the)g(host)f(con)n
+(troller,)g(or)f(are)h(connected)h(to)f(another)0 4591
+y(device)f(that)h(do)r(es)f(not)h(ha)n(v)n(e)e(a)h(driv)n(er.)0
+4747 y(In)h(the)g(system)f(log,)g(a)g(successful)g(prob)r(e)g(migh)n(t)
+h(lo)r(ok)f(lik)n(e:)208 4977 y Fc(Intel)40 b(PCIC)g(probe:)286
+5081 y(TI)g(1130)g(CardBus)g(at)g(mem)g(0x10211000,)i(2)d(sockets)286
+5185 y(...)286 5290 y(ISA)h(irqs)g(\(scanned\))h(=)f(5,7,9,10)h(status)
+f(change)h(on)e(irq)h(10)p eop
+%%Page: 16 16
+16 15 bop 0 -167 3900 5 v 0 -200 a Ff(3.)73 b(Resolving)30
+b(installation)h(and)h(con\034guration)g(problems)1589
+b Fm(16)0 162 y(There)27 b(are)g(t)n(w)n(o)f(w)n(a)n(ys)g(to)i(pro)r
+(ceed:)125 385 y Fd(\017)41 b Fm(The)20 b(in)n(terrupt)h(prob)r(e)f
+(can)h(b)r(e)g(restricted)f(to)h(a)f(list)h(of)g(in)n(terrupts)f(using)
+h(the)g Fh(irq_list)c Fm(parameter)j(for)g(the)h(so)r(c)n(k)n(et)208
+498 y(driv)n(ers.)64 b(F)-7 b(or)37 b(example,)i(\020)7
+b Fh(irq_list=5,9,10)o Fm(\021)38 b(w)n(ould)f(limit)h(the)g(scan)f(to)
+g(three)g(in)n(terrupts.)66 b(All)37 b(PCMCIA)208 612
+y(devices)28 b(will)i(b)r(e)g(restricted)e(to)i(using)f(these)g(in)n
+(terrupts)g(\(assuming)g(they)g(pass)g(the)h(prob)r(e\).)42
+b(Y)-7 b(ou)29 b(ma)n(y)g(need)g(to)208 725 y(use)e(trial)g(and)g
+(error)f(to)h(\034nd)h(out)g(whic)n(h)f(in)n(terrupts)g(can)h(b)r(e)g
+(safely)f(prob)r(ed.)125 905 y Fd(\017)41 b Fm(The)22
+b(in)n(terrupt)f(prob)r(e)h(can)g(b)r(e)g(disabled)g(en)n(tirely)f(b)n
+(y)h(loading)f(the)i(so)r(c)n(k)n(et)e(driv)n(er)f(with)j(the)f
+(\020do_scan=0\021)k(option.)208 1019 y(In)31 b(this)h(case,)g(a)g
+(default)g(in)n(terrupt)f(list)h(will)g(b)r(e)g(used,)h(whic)n(h)e(a)n
+(v)n(oids)f(in)n(terrupts)h(already)g(allo)r(cated)g(for)g(other)208
+1132 y(devices.)0 1355 y(In)h(either)g(case,)g(the)g(prob)r(e)g
+(options)f(can)h(b)r(e)g(sp)r(eci\034ed)g(using)g(the)g
+Fh(PCIC_OPTS)c Fm(de\034nition)k(in)g(the)h(PCMCIA)f(startup)0
+1469 y(script,)27 b(for)g(example:)208 1699 y Fc
+(PCIC_OPTS="irq_list=5,9,10")0 1938 y Fm(It)38 b(should)g(b)r(e)h
+(noted)f(that)g Fh(/proc/interrupts)31 b Fm(is)38 b(completely)g
+(useless)f(when)h(it)h(comes)e(to)h(diagnosing)e(in)n(terrupt)0
+2052 y(prob)r(e)25 b(problems.)35 b(The)26 b(prob)r(e)f(is)g(sensible)g
+(enough)g(to)h(nev)n(er)e(attempt)i(to)g(use)f(an)g(in)n(terrupt)g
+(that)h(is)f(already)f(in)i(use)f(b)n(y)0 2166 y(another)h(Lin)n(ux)g
+(driv)n(er.)35 b(So,)26 b(the)h(PCMCIA)h(driv)n(ers)d(are)g(already)g
+(using)h(all)g(the)h(information)f(in)h Fh(/proc/interrupt)o(s)p
+Fm(.)0 2279 y(Dep)r(ending)c(on)g(system)g(design,)g(an)f(inactiv)n(e)h
+(device)f(can)h(still)g(o)r(ccup)n(y)f(an)h(in)n(terrupt)f(and)h(cause)
+f(trouble)g(if)h(it)h(is)e(prob)r(ed)0 2393 y(for)27
+b(PCMCIA.)0 2684 y Fe(3.4)112 b(IO)37 b(p)s(ort)h(scan)g(failures)0
+2894 y Fm(Symptoms:)125 3117 y Fd(\017)j Fm(The)27 b(system)g(lo)r(c)n
+(ks)g(up)h(when)g Fh(cardmgr)c Fm(is)k(\034rst)f(started,)g(ev)n(en)g
+(with)h(no)g(cards)e(presen)n(t.)125 3297 y Fd(\017)41
+b Fm(The)32 b(system)h(log)f(sho)n(ws)f(a)i(successful)f(host)h(con)n
+(troller)d(prob)r(e,)k(including)f(in)n(terrupt)f(prob)r(e)h(results,)g
+(but)g(do)r(es)208 3411 y(not)27 b(sho)n(w)g(IO)g(prob)r(e)g(results.)
+125 3591 y Fd(\017)41 b Fm(In)27 b(some)g(cases,)g(the)h(IO)f(prob)r(e)
+g(will)h(succeed,)f(but)h(rep)r(ort)f(large)f(n)n(um)n(b)r(ers)h(of)h
+(random)e(exclusions.)0 3814 y(When)d Fh(cardmgr)c Fm(pro)r(cesses)i
+(IO)h(p)r(ort)h(ranges)d(listed)j(in)g Fh(/etc/pcmcia/con)o(fi)o(g.o)o
+(pt)o(s)p Fm(,)17 b(the)23 b(k)n(ernel)f(prob)r(es)f(these)i(ranges)0
+3927 y(to)i(detect)g(laten)n(t)g(devices)g(that)g(o)r(ccup)n(y)f(IO)h
+(space)f(but)i(are)e(not)h(asso)r(ciated)e(with)j(a)e(Lin)n(ux)h(driv)n
+(er.)35 b(The)25 b(prob)r(e)f(is)h(read-)0 4041 y(only)-7
+b(,)27 b(but)h(in)g(rare)e(cases,)h(reading)f(from)h(a)g(device)h(ma)n
+(y)e(in)n(terfere)h(with)h(an)f(imp)r(ortan)n(t)h(system)f(function,)h
+(resulting)f(in)0 4154 y(a)g(lo)r(c)n(k-up.)0 4311 y(Y)-7
+b(our)24 b(system)g(user's)g(guide)g(ma)n(y)g(include)g(a)g(map)h(of)f
+(system)g(devices,)h(sho)n(wing)e(their)h(IO)g(and)h(memory)e(ranges.)
+34 b(These)0 4424 y(can)27 b(b)r(e)h(explicitly)g(excluded)f(in)h
+Fh(config.opts)p Fm(.)0 4581 y(Alternativ)n(ely)-7 b(,)50
+b(if)d(the)f(prob)r(e)g(is)g(unreliable)g(on)g(y)n(our)e(system,)51
+b(it)c(can)e(b)r(e)i(disabled)f(b)n(y)g(setting)g Fh(CORE_OPTS)c
+Fm(to)0 4694 y(\020)7 b Fh(probe_io=0)p Fm(\021.)32 b(In)27
+b(this)g(case,)f(y)n(ou)g(should)g(b)r(e)h(v)n(ery)f(careful)g(to)g(sp)
+r(ecify)h(only)f(gen)n(uinely)h(a)n(v)-5 b(ailable)25
+b(ranges)g(of)i(p)r(orts)f(in)0 4808 y Fh(config.opts)p
+Fm(,)d(instead)k(of)h(using)f(the)h(default)g(settings.)0
+5100 y Fe(3.5)112 b(Memory)37 b(prob)s(e)h(failures)0
+5310 y Fm(Symptoms:)p eop
+%%Page: 17 17
+17 16 bop 0 -167 3900 5 v 0 -200 a Ff(3.)73 b(Resolving)30
+b(installation)h(and)h(con\034guration)g(problems)1589
+b Fm(17)125 162 y Fd(\017)41 b Fm(The)27 b(core)g(driv)n(ers)f(load)g
+(correctly)g(when)i(no)f(cards)g(are)f(presen)n(t,)h(with)h(no)g
+(errors)d(in)j(the)g(system)f(log.)125 342 y Fd(\017)41
+b Fm(The)27 b(system)g(freezes)g(and/or)f(reb)r(o)r(ots)h(as)g(so)r(on)
+g(as)g(an)n(y)f(card)h(is)h(inserted,)f(b)r(efore)g(an)n(y)g(b)r(eeps)h
+(are)e(heard.)0 565 y(Or)h(alternately:)125 787 y Fd(\017)41
+b Fm(All)28 b(card)e(insertions)h(generate)f(a)h(high)h(b)r(eep)g
+(follo)n(w)n(ed)e(b)n(y)i(a)f(lo)n(w)g(b)r(eep.)125 967
+y Fd(\017)41 b Fm(All)28 b(cards)e(are)h(iden)n(ti\034ed)h(as)e
+(\020anon)n(ymous)g(memory)h(cards\021.)125 1147 y Fd(\017)41
+b Fm(The)27 b(system)g(log)g(rep)r(orts)g(that)h(v)-5
+b(arious)26 b(memory)h(ranges)e(ha)n(v)n(e)i(b)r(een)h(excluded.)0
+1370 y(The)23 b(core)f(mo)r(dules)i(p)r(erform)e(a)h(memory)g(scan)f
+(at)h(the)h(time)g(of)f(\034rst)g(16-bit)g(card)f(insertion.)35
+b(This)23 b(scan)f(can)h(p)r(oten)n(tially)0 1484 y(in)n(terfere)35
+b(with)i(other)e(memory)g(mapp)r(ed)h(devices.)62 b(Also,)38
+b(pre-3.0.0)33 b(driv)n(er)i(pac)n(k)-5 b(ages)34 b(p)r(erform)i(a)f
+(more)g(aggressiv)n(e)0 1597 y(scan)28 b(than)h(more)e(recen)n(t)h
+(driv)n(ers.)39 b(The)29 b(memory)e(windo)n(w)h(is)h(de\034ned)g(in)g
+Fh(/etc/pcmcia/con)o(fi)o(g.o)o(pt)o(s)p Fm(.)34 b(The)29
+b(default)0 1711 y(windo)n(w)h(is)g(large,)g(so)g(it)h(ma)n(y)f(help)g
+(to)h(restrict)f(the)g(scan)g(to)h(a)f(narro)n(w)n(er)d(range.)44
+b(Reasonable)29 b(ranges)g(to)i(try)f(include)0 1825
+y(0xd0000-0xd\033\033,)25 b(0xc0000-0xc\033\033,)g
+(0xc8000-0xc\033\033,)f(or)j(0xd8000-0xd\033\033.)0 1981
+y(If)22 b(y)n(ou)f(ha)n(v)n(e)f(DOS)i(or)f(Windo)n(ws)g(PCMCIA)h(driv)n
+(ers,)g(y)n(ou)e(ma)n(y)h(b)r(e)h(able)g(to)f(deduce)h(what)f(memory)g
+(region)f(those)i(driv)n(ers)0 2095 y(use.)41 b(Note)29
+b(that)g(DOS)g(memory)f(addresses)f(are)h(often)h(sp)r(eci\034ed)g(in)h
+(\020segmen)n(t\021)k(form,)29 b(whic)n(h)g(lea)n(v)n(es)e(o\033)i(the)
+g(\034nal)g(hex)0 2208 y(digit)k(\(so)g(an)g(absolute)f(address)g(of)h
+(0xd0000)e(migh)n(t)i(b)r(e)g(giv)n(en)g(as)f(0xd000\).)52
+b(Be)33 b(sure)f(to)h(add)g(the)h(extra)e(digit)h(bac)n(k)0
+2322 y(when)28 b(making)f(c)n(hanges)f(to)h Fh(config.opts)p
+Fm(.)0 2478 y(In)19 b(un)n(usual)g(cases,)h(a)f(memory)f(prob)r(e)h
+(failure)g(can)g(indicate)g(a)g(timing)h(register)d(setup)j(problem)f
+(with)g(the)h(host)f(con)n(troller.)0 2592 y(See)28 b(the)g(2.3)e
+(\(Startup)i(options\))f(section)g(for)g(information)g(ab)r(out)h
+(dealing)f(with)h(common)f(timing)h(problems.)125 2831
+y Fd(\017)41 b Fh(cs:)85 b(warning:)f(no)43 b(high)f(memory)f(space)g
+(available!)0 3071 y Fm(CardBus)30 b(bridges)h(can)g(allo)r(cate)g
+(memory)g(windo)n(ws)g(outside)g(of)h(the)g(640KB-1MB)d(\020memory)h
+(hole\021)38 b(in)32 b(the)g(ISA)g(bus)0 3184 y(arc)n(hitecture.)j(It)
+25 b(is)g(generally)e(a)h(go)r(o)r(d)g(idea)h(to)g(con\034gure)e
+(CardBus)h(bridges)g(to)h(use)f(high)h(memory)f(windo)n(ws,)h(b)r
+(ecause)0 3298 y(these)30 b(are)e(unlik)n(ely)i(to)f(con\035ict)h(with)
+g(other)f(devices.)43 b(Also,)30 b(CardBus)f(cards)f(ma)n(y)h(require)g
+(large)f(memory)h(windo)n(ws,)0 3412 y(whic)n(h)20 b(ma)n(y)g(b)r(e)g
+(di\036cult)h(or)f(imp)r(ossible)g(to)g(\034t)g(in)n(to)g(lo)n(w)g
+(memory)-7 b(.)34 b(Card)19 b(Services)g(will)i(preferen)n(tially)e
+(allo)r(cate)g(windo)n(ws)0 3525 y(in)i(high)g(memory)e(for)i(CardBus)e
+(bridges,)i(if)g(b)r(oth)h(lo)n(w)e(and)g(high)h(memory)e(windo)n(ws)h
+(are)g(de\034ned)h(in)g Fh(config.opts)p Fm(.)30 b(The)0
+3639 y(default)f Fh(config.opts)24 b Fm(no)n(w)k(includes)g(a)g(high)h
+(memory)e(windo)n(w)h(of)h(0xa0000000-0xa0)o(\033\033\033.)35
+b(If)29 b(y)n(ou)f(ha)n(v)n(e)f(a)h(CardBus)0 3752 y(bridge)21
+b(and)h(ha)n(v)n(e)f(upgraded)h(from)f(an)h(older)g(PCMCIA)h(driv)n(er)
+e(release,)g(add)i(this)f(memory)f(windo)n(w)h(if)h(it)f(is)g(not)h
+(already)0 3866 y(de\034ned.)0 4022 y(In)30 b(some)f(cases,)h(the)g
+(default)g(high)g(memory)f(windo)n(w)g(is)h(not)g(usable.)43
+b(On)30 b(some)f(IBM)h(Thinkpad)g(mo)r(dels,)g(a)g(windo)n(w)0
+4136 y(of)e(0x60000000-0x6)o(0\033\033\033)23 b(will)28
+b(w)n(ork)e(in)h(place)h(of)f(the)h(default)g(windo)n(w.)0
+4427 y Fe(3.6)112 b(F)-9 b(ailure)37 b(to)f(detect)h(card)h(insertions)
+e(and)i(remo)m(v)-6 b(als)0 4638 y Fm(Symptoms:)125 4860
+y Fd(\017)41 b Fm(Cards)26 b(are)h(detected)h(and)f(con\034gured)f
+(prop)r(erly)h(if)h(presen)n(t)f(at)g(b)r(o)r(ot)h(time.)125
+5040 y Fd(\017)41 b Fm(The)29 b(driv)n(ers)f(do)h(not)h(resp)r(ond)e
+(to)i(insertion)f(and)g(remo)n(v)-5 b(al)28 b(ev)n(en)n(ts,)h(either)g
+(b)n(y)h(recording)d(ev)n(en)n(ts)i(in)h(the)f(system)208
+5154 y(log,)d(or)h(b)n(y)g(b)r(eeping.)p eop
+%%Page: 18 18
+18 17 bop 0 -167 3900 5 v 0 -200 a Ff(3.)73 b(Resolving)30
+b(installation)h(and)h(con\034guration)g(problems)1589
+b Fm(18)0 162 y(In)28 b(most)g(cases,)g(the)g(so)r(c)n(k)n(et)g(driv)n
+(er)f(\()p Fh(i82365)f Fm(or)h Fh(tcic)p Fm(\))g(will)h(automatically)f
+(prob)r(e)h(and)g(select)g(an)g(appropriate)f(in)n(ter-)0
+275 y(rupt)k(to)g(signal)f(card)g(status)h(c)n(hanges.)45
+b(The)32 b(automatic)e(in)n(terrupt)h(prob)r(e)f(do)r(esn't)h(w)n(ork)f
+(on)g(some)h(In)n(tel-compatible)0 389 y(con)n(trollers,)i(including)i
+(Cirrus)e(c)n(hips)g(and)h(the)g(c)n(hips)g(used)g(in)g(some)g(IBM)g
+(ThinkP)n(ads.)55 b(If)35 b(a)e(device)h(is)g(inactiv)n(e)f(at)0
+502 y(prob)r(e)i(time,)i(its)e(in)n(terrupt)g(ma)n(y)f(also)g(app)r
+(ear)g(to)h(b)r(e)h(a)n(v)-5 b(ailable.)58 b(In)35 b(these)g(cases,)h
+(the)g(so)r(c)n(k)n(et)e(driv)n(er)f(ma)n(y)i(pic)n(k)f(an)0
+616 y(in)n(terrupt)27 b(that)h(is)g(used)f(b)n(y)g(another)g(device.)0
+772 y(With)35 b(the)f Fh(i82365)d Fm(and)i Fh(tcic)f
+Fm(driv)n(ers,)i(the)g Fh(irq_list)c Fm(option)k(can)f(b)r(e)h(used)g
+(to)f(limit)i(the)f(in)n(terrupts)f(that)h(will)g(b)r(e)0
+886 y(tested.)h(This)22 b(list)g(limits)h(the)f(set)g(of)g(in)n
+(terrupts)f(that)h(can)g(b)r(e)g(used)g(b)n(y)f(PCMCIA)i(cards)e(as)g
+(w)n(ell)h(as)f(for)g(monitoring)g(card)0 1000 y(status)k(c)n(hanges.)
+35 b(The)25 b Fh(cs_irq)e Fm(option)i(can)g(also)f(b)r(e)i(used)f(to)h
+(explicitly)f(set)g(the)h(in)n(terrupt)f(to)g(b)r(e)h(used)f(for)g
+(monitoring)0 1113 y(card)i(status)g(c)n(hanges.)0 1270
+y(If)g(y)n(ou)e(can't)i(\034nd)f(an)g(in)n(terrupt)g(n)n(um)n(b)r(er)g
+(that)h(w)n(orks,)e(there)h(is)g(also)f(a)h(p)r(olled)h(status)f(mo)r
+(de:)36 b(b)r(oth)27 b Fh(i82365)d Fm(and)i Fh(tcic)0
+1383 y Fm(will)c(accept)g(a)g Fh(poll_interval=10)o(0)16
+b Fm(option,)23 b(to)f(p)r(oll)h(for)e(card)g(status)h(c)n(hanges)f
+(once)h(p)r(er)g(second.)34 b(This)23 b(option)e(should)0
+1497 y(also)27 b(b)r(e)i(used)g(if)g(y)n(our)e(system)h(has)g(a)g
+(shortage)f(of)h(in)n(terrupts)g(a)n(v)-5 b(ailable)27
+b(for)h(use)g(b)n(y)g(PCMCIA)i(cards.)38 b(Esp)r(ecially)29
+b(for)0 1610 y(systems)c(with)h(more)f(than)h(one)f(host)h(con)n
+(troller,)e(there)i(is)f(little)i(p)r(oin)n(t)f(in)g(dedicating)f(in)n
+(terrupts)g(for)g(monitoring)g(card)0 1724 y(status)i(c)n(hanges.)0
+1880 y(All)77 b(these)f(options)g(should)g(b)r(e)g(set)g(in)h(the)g
+Fh(PCIC_OPTS=)72 b Fm(line)k(in)h(either)f Fh(/etc/rc.d/rc.pc)o(mc)o
+(ia)70 b Fm(or)0 1994 y Fh(/etc/sysconfig/p)o(cm)o(cia)o
+Fm(,)22 b(dep)r(ending)28 b(on)f(y)n(our)f(site)i(setup.)0
+2284 y Fe(3.7)112 b(In)m(terrupt)37 b(deliv)m(ery)f(problems)0
+2494 y Fm(Symptoms:)125 2709 y Fd(\017)41 b Fm(Cards)26
+b(app)r(ear)h(to)g(b)r(e)h(con\034gured)e(successfully)-7
+b(,)28 b(but)g(don't)g(w)n(ork.)125 2886 y Fd(\017)41
+b Fm(Serial)26 b(and)i(mo)r(dem)g(cards)e(ma)n(y)h(resp)r(ond)g(v)n
+(ery)f(sluggishly)-7 b(.)125 3062 y Fd(\017)41 b Fm(Net)n(w)n(ork)26
+b(cards)g(ma)n(y)h(rep)r(ort)g(\020in)n(terrupt\(s\))g(dropp)r(ed\021,)
+g(and/or)f(transmit)h(timeouts.)0 3277 y(The)37 b(most)g(simple)h(in)n
+(terrupt)f(deliv)n(ery)f(problems)g(are)g(due)i(to)f(con\035icts)g
+(with)h(other)e(system)h(devices.)66 b(These)36 b(can)0
+3391 y(generally)27 b(b)r(e)j(resolv)n(ed)d(b)n(y)i(excluding)f
+(problem)h(in)n(terrupts)f(in)h Fh(/etc/pcmcia/conf)o(ig.)o(op)o(ts)o
+Fm(.)35 b(T)-7 b(o)29 b(test,)h(just)f(exclude)0 3504
+y(in)n(terrupts)h(one)g(b)n(y)g(one)g(un)n(til)h(either)f(the)h
+(problem)e(is)i(\034xed)f(or)g(y)n(ou)f(run)h(out)h(of)f(in)n
+(terrupts.)45 b(If)31 b(no)f(in)n(terrupts)f(w)n(ork,)0
+3618 y(then)f(device)f(con\035icts)h(are)e(probably)h(not)g(the)h
+(problem.)0 3774 y(CardBus)37 b(bridges)g(usually)g(supp)r(ort)h(t)n(w)
+n(o)f(t)n(yp)r(es)h(of)f(in)n(terrupts,)j(PCI)f(and)e(ISA.)i(P)n(artly)
+e(for)g(historical)g(reasons,)i(it)0 3888 y(has)f(b)r(ecome)g(con)n(v)n
+(en)n(tional)e(to)i(use)h(PCI)f(in)n(terrupts)g(for)g(signaling)f(card)
+g(insertion)h(and)g(remo)n(v)-5 b(al)37 b(ev)n(en)n(ts,)j(and)f(for)0
+4001 y(CardBus)23 b(card)g(in)n(terrupts;)i(and)e(ISA)i(in)n(terrupts)e
+(for)h(16-bit)f(cards.)34 b(Since)25 b(v)n(ersion)d(3.1.9,)h(this)i(is)
+f(the)g(sc)n(heme)f(that)i(the)0 4115 y(Lin)n(ux)i(PCMCIA)i(system)e
+(will)h(use)g(b)n(y)f(default.)38 b(Most)27 b(CardBus)g(bridges)g(supp)
+r(ort)g(m)n(ultiple)h(metho)r(ds)g(for)f(deliv)n(ering)0
+4229 y(in)n(terrupts)d(to)h(the)g(host)f(CPU.)i(Metho)r(ds)f(include)g
+(\020parallel\021)30 b(in)n(terrupts,)25 b(where)f(eac)n(h)g(supp)r
+(orted)g(irq)h(has)f(a)g(dedicated)0 4342 y(pin)h(on)f(the)h(bridge;)g
+(v)-5 b(arious)24 b(serial)f(in)n(terrupt)h(proto)r(cols,)g(where)g
+(one)g(or)g(t)n(w)n(o)g(pins)h(are)e(used)i(to)f(comm)n(unicate)g(with)
+h(an)0 4456 y(in)n(terrupt)h(con)n(troller;)e(and)i(h)n(ybrids,)g
+(where,)f(for)h(instance,)g(PCI)g(in)n(terrupts)g(ma)n(y)f(b)r(e)h
+(signalled)f(using)h(dedicated)g(pins,)0 4569 y(while)i(ISA)g(in)n
+(terrupts)f(are)f(deliv)n(ered)h(via)g(a)g(serial)g(con)n(troller.)0
+4726 y(In)33 b(general,)g(it)g(is)g(the)g(resp)r(onsibilit)n(y)f(of)h
+(the)g(BIOS)f(to)h(program)e(a)h(bridge)g(for)g(the)i(appropriate)d(in)
+n(terrupt)h(deliv)n(ery)0 4839 y(metho)r(d.)37 b(Ho)n(w)n(ev)n(er,)23
+b(there)i(are)f(systems)h(that)h(do)f(this)g(incorrectly)-7
+b(,)24 b(and)i(in)f(some)g(cases,)f(there)h(is)g(no)g(w)n(a)n(y)f(for)h
+(soft)n(w)n(are)0 4953 y(to)j(safely)g(detect)h(the)g(correct)f(deliv)n
+(ery)f(metho)r(d.)40 b(The)29 b Fh(i82365)d Fm(mo)r(dule)j(rep)r(orts)e
+(the)i(bridge)f(mo)r(de)h(at)f(startup)h(time,)0 5066
+y(and)e(has)g(a)g(parameter,)f Fh(irq_mode)p Fm(,)f(that)i(can)h(b)r(e)
+f(used)h(to)f(recon\034gure)f(it.)37 b(Not)28 b(all)f(bridges)g(supp)r
+(ort)g(this)h(parameter,)0 5180 y(and)k(the)h(meaning)f(of)g
+Fh(irq_mode)d Fm(dep)r(ends)k(on)f(the)g(bridge)g(t)n(yp)r(e.)51
+b(See)33 b(the)f Fh(i82365)e Fm(man)i(page)g(for)g(a)f(description)h
+(of)0 5294 y(what)27 b(v)-5 b(alues)26 b(are)g(supp)r(orted)h(b)n(y)f
+(y)n(our)g(bridge.)36 b(In)27 b(some)f(cases,)g(a)g(bridge)h(ma)n(y)f
+(function)h(correctly)e(in)j(more)e(than)g(one)0 5407
+y(in)n(terrupt)h(mo)r(de.)p eop
+%%Page: 19 19
+19 18 bop 0 -167 3900 5 v 0 -200 a Ff(3.)73 b(Resolving)30
+b(installation)h(and)h(con\034guration)g(problems)1589
+b Fm(19)0 162 y(Most)23 b(PCMCIA)i(card)d(readers)g(that)i(\034t)g(in)g
+(a)f(PCI)h(bus)f(slot)h(only)f(pro)n(vide)f(PCI)i(in)n(terrupt)f
+(routing.)35 b(The)23 b(Lin)n(ux)h(driv)n(ers)0 275 y(assume)30
+b(that)i(all)f(bridges)f(ha)n(v)n(e)g(ISA)h(in)n(terrupt)g(capabilit)n
+(y)-7 b(,)31 b(since)g(that)g(is)g(usually)g(correct.)46
+b(In)31 b(this)h(case,)f(it)g(will)h(b)r(e)0 389 y(necessary)27
+b(to)i(use)h(the)f Fh(irq_mode)d Fm(parameter)i(to)h(sp)r(ecify)g(a)g
+(\020PCI)g(only\021)36 b(in)n(terrupt)29 b(deliv)n(ery)f(mo)r(de;)i
+(the)f(v)-5 b(alue)30 b(of)f(the)0 502 y(parameter)d(dep)r(ends)i(on)f
+(the)h(bridge)f(t)n(yp)r(e,)h(so)f(c)n(hec)n(k)f(the)i
+Fh(i82365)d Fm(man)j(page.)0 794 y Fe(3.8)112 b(System)37
+b(resource)h(starv)-6 b(ation)0 1004 y Fm(Symptoms:)125
+1227 y Fd(\017)41 b Fm(When)28 b(a)f(card)f(is)i(inserted,)f(it)h(is)g
+(iden)n(ti\034ed)g(correctly)e(but)i(cannot)f(b)r(e)h(con\034gured)e
+(\(high/lo)n(w)h(b)r(eep)h(pattern\).)125 1407 y Fd(\017)41
+b Fm(One)27 b(of)g(the)h(follo)n(wing)f(messages)f(will)h(app)r(ear)g
+(in)h(the)g(system)f(log:)390 1577 y Fc(RequestIO:)42
+b(Resource)f(in)e(use)390 1682 y(RequestIRQ:)j(Resource)f(in)e(use)390
+1786 y(RequestWindow:)j(Resource)f(in)f(use)390 1890
+y(GetNextTuple:)i(No)e(more)g(items)390 1994 y(could)h(not)e(allocate)i
+(nn)f(IO)g(ports)g(for)g(CardBus)h(socket)f(n)390 2098
+y(could)h(not)e(allocate)i(nnK)f(memory)h(for)f(CardBus)g(socket)h(n)
+390 2202 y(could)g(not)e(allocate)i(interrupt)h(for)d(CardBus)i(socket)
+g(n)0 2425 y Fm(In)n(terrupt)31 b(starv)-5 b(ation)31
+b(often)g(indicates)h(a)f(problem)g(with)h(the)g(in)n(terrupt)f(prob)r
+(e)g(\(see)h(3.3)f(\(In)n(terrupt)g(scan)g(failures\)\).)0
+2539 y(In)j(some)f(cases,)h(the)g(prob)r(e)g(will)f(seem)h(to)g(w)n
+(ork,)f(but)i(only)e(rep)r(ort)g(one)g(or)g(t)n(w)n(o)g(a)n(v)-5
+b(ailable)33 b(in)n(terrupts.)54 b(Chec)n(k)33 b(y)n(our)0
+2652 y(system)g(log)g(to)h(see)f(if)h(the)g(scan)f(results)g(lo)r(ok)g
+(sensible.)55 b(Disabling)33 b(the)h(prob)r(e)f(and)h(selecting)f(in)n
+(terrupts)g(man)n(ually)0 2766 y(should)27 b(help.)0
+2922 y(If)33 b(the)g(in)n(terrupt)f(prob)r(e)h(is)f(not)h(w)n(orking)e
+(prop)r(erly)-7 b(,)33 b(the)g(so)r(c)n(k)n(et)e(driv)n(er)h(ma)n(y)g
+(allo)r(cate)f(an)i(in)n(terrupt)f(for)g(monitoring)0
+3036 y(card)26 b(insertions,)h(ev)n(en)g(when)g(in)n(terrupts)g(are)f
+(to)r(o)h(scarce)f(for)g(this)i(to)f(b)r(e)h(a)f(go)r(o)r(d)f(idea.)37
+b(In)27 b(that)g(case,)g(y)n(ou)f(can)h(switc)n(h)0 3149
+y(the)33 b(con)n(troller)e(to)h(p)r(olled)h(mo)r(de)g(b)n(y)f(setting)h
+Fh(PCIC_OPTS)c Fm(to)j(\020)7 b Fh(poll_interval=1)o(00)o
+Fm('.)47 b(Or,)33 b(if)g(y)n(ou)f(ha)n(v)n(e)f(a)h(CardBus)0
+3263 y(con)n(troller,)26 b(try)h(\020)7 b Fh(pci_csc=1)p
+Fm(\021,)23 b(whic)n(h)28 b(selects)f(a)g(PCI)h(in)n(terrupt)f(\(if)i
+(a)n(v)-5 b(ailable\))26 b(for)h(card)g(status)g(c)n(hanges.)0
+3419 y(IO)33 b(p)r(ort)f(starv)-5 b(ation)32 b(is)h(fairly)f(uncommon,)
+i(but)f(sometimes)g(happ)r(ens)g(with)g(cards)f(that)h(require)f
+(large,)g(con)n(tiguous,)0 3533 y(aligned)24 b(regions)f(of)h(IO)g(p)r
+(ort)h(space,)f(or)g(that)g(only)h(recognize)d(a)j(few)f(sp)r(eci\034c)
+h(IO)f(p)r(ort)g(p)r(ositions.)36 b(The)24 b(default)h(IO)f(p)r(ort)0
+3647 y(ranges)e(in)j Fh(/etc/pcmcia/con)o(fi)o(g.)o(opt)o(s)18
+b Fm(are)23 b(normally)f(su\036cien)n(t,)j(but)g(ma)n(y)e(b)r(e)h
+(extended.)36 b(In)24 b(rare)f(cases,)g(starv)-5 b(ation)0
+3760 y(ma)n(y)27 b(indicate)g(that)h(the)g(IO)f(p)r(ort)h(prob)r(e)f
+(failed)g(\(see)h(3.4)f(\(IO)g(p)r(ort)h(scan)e(failures\)\).)0
+3917 y(Memory)i(starv)-5 b(ation)27 b(is)h(also)g(uncommon)g(with)h
+(the)g(default)g(memory)f(windo)n(w)g(settings)g(in)h
+Fh(config.opts)p Fm(.)35 b(CardBus)0 4030 y(cards)25
+b(ma)n(y)g(require)f(larger)g(memory)h(regions)f(than)i(t)n(ypical)g
+(16-bit)f(cards.)35 b(Since)26 b(CardBus)e(memory)h(windo)n(ws)g(can)h
+(b)r(e)0 4144 y(mapp)r(ed)e(an)n(ywhere)e(in)i(the)g(host's)f(PCI)h
+(address)f(space)f(\(rather)h(than)h(just)g(in)g(the)g(640K-1MB)d
+(\020hole\021)29 b(in)24 b(PC)g(systems\),)0 4257 y(it)k(is)f(helpful)i
+(to)e(sp)r(ecify)h(large)e(memory)h(windo)n(ws)g(in)h(high)f(memory)-7
+b(,)27 b(suc)n(h)g(as)g(0xa0000000-0xa0)o(\033\033\033.)0
+4549 y Fe(3.9)112 b(Resource)37 b(con\035ict)g(only)g(with)f(t)m(w)m(o)
+g(cards)i(inserted)0 4759 y Fm(Symptoms:)125 4982 y Fd(\017)j
+Fm(T)-7 b(w)n(o)26 b(cards)h(eac)n(h)g(w)n(ork)f(\034ne)h(when)h(used)g
+(separately)-7 b(.)125 5162 y Fd(\017)41 b Fm(When)28
+b(b)r(oth)g(cards)e(are)h(inserted,)g(only)g(one)g(w)n(orks.)p
+eop
+%%Page: 20 20
+20 19 bop 0 -167 3900 5 v 0 -200 a Ff(4.)73 b(Usage)32
+b(and)h(features)2873 b Fm(20)0 162 y(This)29 b(usually)g(indicates)g
+(a)g(resource)e(con\035ict)i(with)h(a)f(system)g(device)g(that)g(Lin)n
+(ux)g(do)r(es)g(not)g(kno)n(w)g(ab)r(out.)41 b(PCMCIA)0
+275 y(devices)28 b(are)f(dynamically)h(con\034gured,)g(so,)g(for)g
+(example,)g(in)n(terrupts)g(are)f(allo)r(cated)h(as)g(needed,)g(rather)
+g(than)g(sp)r(eci\034-)0 389 y(cally)f(assigned)f(to)h(particular)f
+(cards)g(or)h(so)r(c)n(k)n(ets.)35 b(Giv)n(en)27 b(a)g(list)h(of)f
+(resources)f(that)h(app)r(ear)g(to)g(b)r(e)h(a)n(v)-5
+b(ailable,)26 b(cards)g(are)0 502 y(assigned)i(resources)g(in)i(the)g
+(order)e(they)i(are)f(con\034gured.)42 b(In)30 b(this)g(case,)f(the)h
+(card)f(con\034gured)g(last)g(is)h(b)r(eing)f(assigned)0
+616 y(a)e(resource)f(that)i(in)g(fact)f(is)h(not)f(free.)0
+772 y(Chec)n(k)50 b(the)i(system)f(log)f(to)h(see)f(what)h(resources)e
+(are)h(used)h(b)n(y)g(the)g(non-w)n(orking)e(card.)106
+b(Exclude)52 b(these)f(in)0 886 y Fh(/etc/pcmcia/conf)o(ig)o(.op)o(ts)o
+Fm(,)22 b(and)27 b(restart)g(the)h Fh(cardmgr)c Fm(daemon)j(to)h
+(reload)e(the)i(resource)e(database.)0 1178 y Fe(3.10)112
+b(Device)37 b(con\034guration)g(do)s(es)h(not)f(complete)0
+1388 y Fm(Symptoms:)125 1611 y Fd(\017)k Fm(When)28 b(a)f(card)f(is)i
+(inserted,)f(exactly)g(one)g(high)h(b)r(eep)g(is)f(heard.)125
+1791 y Fd(\017)41 b Fm(Subsequen)n(t)27 b(card)g(insertions)f(and)i
+(remo)n(v)-5 b(als)26 b(ma)n(y)h(b)r(e)h(ignored.)0 2013
+y(This)h(indicates)g(that)g(the)g(card)f(w)n(as)g(iden)n(ti\034ed)i
+(successfully)-7 b(,)29 b(ho)n(w)n(ev)n(er,)e Fh(cardmgr)f
+Fm(has)j(b)r(een)g(unable)g(to)g(complete)g(the)0 2127
+y(con\034guration)j(pro)r(cess)h(for)g(some)g(reason.)54
+b(The)33 b(most)h(lik)n(ely)f(reason)f(is)i(that)g(a)f(step)h(in)g(the)
+g(card)f(setup)h(script)g(has)0 2241 y(blo)r(c)n(k)n(ed.)j(A)28
+b(go)r(o)r(d)f(example)h(w)n(ould)f(b)r(e)h(the)g(net)n(w)n(ork)f
+(script)g(blo)r(c)n(king)g(if)i(a)e(net)n(w)n(ork)g(card)f(is)i
+(inserted)g(with)g(no)g(actual)0 2354 y(net)n(w)n(ork)e(ho)r(okup)h
+(presen)n(t.)0 2511 y(T)-7 b(o)30 b(pinp)r(oin)n(t)h(the)g(problem,)g
+(y)n(ou)f(can)g(man)n(ually)g(run)g(a)g(setup)h(script)f(to)h(see)f
+(where)g(it)h(is)f(blo)r(c)n(king.)45 b(The)31 b(scripts)f(are)0
+2624 y(in)36 b(the)g Fh(/etc/pcmcia)31 b Fm(directory)-7
+b(.)60 b(They)35 b(tak)n(e)g(t)n(w)n(o)g(parameters:)51
+b(a)35 b(device)h(name,)h(and)f(an)f(action.)60 b(The)36
+b Fh(cardmgr)0 2738 y Fm(daemon)30 b(records)e(the)j(con\034guration)e
+(commands)g(in)i(the)g(system)f(log.)44 b(F)-7 b(or)30
+b(example,)g(if)h(the)g(system)f(log)g(sho)n(ws)f(that)0
+2851 y(the)j(command)f(\020./net)n(w)n(ork)e(start)i(eth0\021)38
+b(w)n(as)31 b(the)h(last)f(command)g(executed)g(b)n(y)h
+Fh(cardmgr)p Fm(,)d(the)j(follo)n(wing)f(command)0 2965
+y(w)n(ould)c(trace)g(the)h(script:)208 3195 y Fc(sh)39
+b(-x)h(/etc/pcmcia/network)j(start)e(eth0)0 3533 y Fg(4)131
+b(Usage)43 b(and)h(features)0 3791 y Fe(4.1)112 b(T)-9
+b(o)s(ols)37 b(for)g(con\034guring)g(and)h(monitoring)d(PCMCIA)i
+(devices)0 4001 y Fm(If)d(the)h(mo)r(dules)f(are)f(all)h(loaded)f
+(correctly)-7 b(,)34 b(the)h(output)f(of)g(the)g Fh(lsmod)e
+Fm(command)i(should)g(lo)r(ok)f(lik)n(e)h(the)g(follo)n(wing,)0
+4114 y(when)28 b(no)f(cards)f(are)h(inserted:)208 4345
+y Fc(Module)707 b(Size)79 b(Used)40 b(by)208 4449 y(ds)863
+b(5640)118 b(2)208 4553 y(i82365)668 b(15452)118 b(2)208
+4657 y(pcmcia_core)473 b(30012)118 b(3)79 b([ds)40 b(i82365])0
+4896 y Fm(The)25 b(system)f(log)g(should)g(also)g(include)g(output)i
+(from)e(the)h(so)r(c)n(k)n(et)e(driv)n(er)g(describing)h(the)h(host)f
+(con)n(troller\(s\))f(found)i(and)0 5010 y(the)j(n)n(um)n(b)r(er)f(of)h
+(so)r(c)n(k)n(ets)e(detected.)p eop
+%%Page: 21 21
+21 20 bop 0 -167 3900 5 v 0 -200 a Ff(4.)73 b(Usage)32
+b(and)h(features)2873 b Fm(21)0 162 y Ff(4.1.1)94 b(The)32
+b(cardmgr)f(con\034guration)h(daemon)0 372 y Fm(The)h
+Fh(cardmgr)d Fm(daemon)i(is)h(resp)r(onsible)f(for)h(monitoring)f
+(PCMCIA)h(so)r(c)n(k)n(ets,)g(loading)f(clien)n(t)h(driv)n(ers)f(when)h
+(needed,)0 485 y(and)22 b(running)g(user-lev)n(el)e(scripts)i(in)g
+(resp)r(onse)f(to)h(card)f(insertions)g(and)h(remo)n(v)-5
+b(als.)33 b(It)23 b(records)d(its)i(actions)g(in)g(the)g(system)0
+599 y(log,)29 b(but)h(also)e(uses)h(b)r(eeps)h(to)f(signal)f(card)h
+(status)g(c)n(hanges.)41 b(The)29 b(tones)g(of)h(the)f(b)r(eeps)h
+(indicate)f(success)g(or)f(failure)h(of)0 712 y(particular)20
+b(con\034guration)f(steps.)35 b(T)-7 b(w)n(o)21 b(high)g(b)r(eeps)g
+(indicate)g(that)h(a)f(card)f(w)n(as)h(iden)n(ti\034ed)g(and)g
+(con\034gured)f(successfully)-7 b(.)0 826 y(A)34 b(high)g(b)r(eep)g
+(follo)n(w)n(ed)f(b)n(y)g(a)h(lo)n(w)f(b)r(eep)h(indicates)f(that)h(a)g
+(card)f(w)n(as)f(iden)n(ti\034ed,)k(but)f(could)e(not)h(b)r(e)g
+(con\034gured)f(for)0 940 y(some)27 b(reason.)35 b(One)27
+b(lo)n(w)g(b)r(eep)h(indicates)g(that)f(a)h(card)e(could)i(not)f(b)r(e)
+h(iden)n(ti\034ed.)0 1096 y(The)19 b Fh(cardmgr)d Fm(daemon)i
+(con\034gures)g(cards)f(based)i(on)f(a)h(database)f(of)h(kno)n(wn)f
+(card)g(t)n(yp)r(es)h(k)n(ept)f(in)i Fh(/etc/pcmcia/con)o(fi)o(g)p
+Fm(.)0 1210 y(This)j(\034le)f(describ)r(es)g(the)h(v)-5
+b(arious)22 b(clien)n(t)g(driv)n(ers,)h(then)g(describ)r(es)f(ho)n(w)g
+(to)g(iden)n(tify)h(v)-5 b(arious)22 b(cards,)g(and)h(whic)n(h)f(driv)n
+(er\(s\))0 1323 y(b)r(elong)27 b(with)h(whic)n(h)g(cards.)35
+b(The)28 b(format)f(of)h(this)f(\034le)h(is)g(describ)r(ed)f(in)h(the)g
+Fh(pcmcia\(5\))23 b Fm(man)28 b(page.)0 1593 y Ff(4.1.2)94
+b(The)32 b(so)s(c)m(k)m(et)g(status)g(\034le,)e(stab)0
+1803 y Fh(Cardmgr)18 b Fm(records)i(device)h(information)f(for)h(eac)n
+(h)f(so)r(c)n(k)n(et)h(in)g Fh(/var/state/pcmci)o(a/)o(sta)o(b)15
+b Fm(or)20 b Fh(/var/lib/pcmcia/s)o(ta)o(b)p Fm(,)0 1917
+y(dep)r(ending)28 b(on)f(\034lesystem)g(la)n(y)n(out.)36
+b(Here)27 b(is)h(a)f(sample)g Fh(stab)f Fm(listing:)208
+2132 y Fc(Socket)40 b(0:)g(Adaptec)g(APA-1460)h(SlimSCSI)208
+2236 y(0)274 b(scsi)158 b(aha152x_cs)238 b(0)274 b(sda)197
+b(8)275 b(0)208 2341 y(0)f(scsi)158 b(aha152x_cs)238
+b(1)274 b(scd0)158 b(11)236 b(0)208 2445 y(Socket)40
+b(1:)g(Serial)g(or)g(Modem)g(Card)208 2549 y(1)274 b(serial)80
+b(serial_cs)277 b(0)d(ttyS1)119 b(5)275 b(65)0 2774 y
+Fm(F)-7 b(or)30 b(the)i(lines)f(describing)f(devices,)h(the)g(\034rst)g
+(\034eld)g(is)g(the)g(so)r(c)n(k)n(et,)g(the)g(second)g(is)g(the)g
+(device)g(class,)f(the)i(third)f(is)g(the)0 2887 y(driv)n(er)c(name,)i
+(the)g(fourth)f(is)h(used)f(to)g(n)n(um)n(b)r(er)h(m)n(ultiple)g
+(devices)f(asso)r(ciated)f(with)i(the)g(same)e(driv)n(er,)h(the)h
+(\034fth)g(is)g(the)0 3001 y(device)c(name,)h(and)g(the)g(\034nal)f(t)n
+(w)n(o)g(\034elds)h(are)f(the)h(ma)5 b(jor)24 b(and)i(minor)f(device)g
+(n)n(um)n(b)r(ers)g(for)h(this)f(device)h(\(if)g(applicable\).)0
+3114 y(See)i(the)g Fh(stab)d Fm(man)j(page)f(for)g(more)f(info.)0
+3385 y Ff(4.1.3)94 b(The)32 b(cardctl)h(and)f(cardinfo)g(utilities)0
+3595 y Fm(The)f Fh(cardctl)e Fm(command)i(can)g(b)r(e)h(used)f(to)g(c)n
+(hec)n(k)g(the)h(status)f(of)g(a)g(so)r(c)n(k)n(et,)h(or)e(to)i(see)f
+(ho)n(w)f(it)i(is)f(con\034gured.)48 b(It)31 b(can)0
+3708 y(also)e(b)r(e)i(used)f(to)g(alter)f(the)i(con\034guration)d
+(status)i(of)g(a)g(card.)44 b(Here)30 b(is)g(an)g(example)f(of)h(the)h
+(output)g(of)f(the)g(\020)7 b Fh(cardctl)0 3822 y(config)p
+Fm(\021)32 b(command:)208 4037 y Fc(Socket)40 b(0:)286
+4141 y(not)g(configured)208 4245 y(Socket)g(1:)286 4349
+y(Vcc)g(=)f(5.0,)h(Vpp1)g(=)g(0.0,)g(Vpp2)g(=)g(0.0)286
+4454 y(Card)g(type)g(is)g(memory)g(and)g(I/O)286 4558
+y(IRQ)g(3)f(is)h(dynamic)h(shared,)f(level)h(mode,)f(enabled)286
+4662 y(Speaker)h(output)f(is)g(enabled)286 4766 y(Function)h(0:)364
+4870 y(Config)g(register)g(base)f(=)f(0x0800)443 4974
+y(Option)h(=)g(0x63,)g(status)h(=)e(0x08)364 5078 y(I/O)h(window)h(1:)e
+(0x0280)i(to)f(0x02bf,)g(auto)h(sized)364 5182 y(I/O)f(window)h(2:)e
+(0x02f8)i(to)f(0x02ff,)g(8)g(bit)0 5407 y Fm(Or)27 b(\020)7
+b Fh(cardctl)40 b(ident)p Fm(\021,)25 b(to)j(get)f(card)g(iden)n
+(ti\034cation)g(information:)p eop
+%%Page: 22 22
+22 21 bop 0 -167 3900 5 v 0 -200 a Ff(4.)73 b(Usage)32
+b(and)h(features)2873 b Fm(22)208 162 y Fc(Socket)40
+b(0:)286 266 y(no)g(product)g(info)g(available)208 370
+y(Socket)g(1:)286 474 y(product)h(info:)f("LINKSYS",)h("PCMLM336",)h
+("A",)e("0040052D6400")286 578 y(manfid:)h(0x0143,)f(0xc0ab)286
+682 y(function:)h(0)f(\(multifunction\))0 922 y Fm(The)32
+b(\020)7 b Fh(cardctl)40 b(suspend)p Fm(\021)c(and)31
+b(\020)7 b Fh(cardctl)40 b(resume)p Fm(\021)c(commands)31
+b(can)h(b)r(e)g(used)g(to)f(sh)n(ut)h(do)n(wn)g(a)f(card)g(without)h
+(un-)0 1035 y(loading)h(its)h(asso)r(ciated)e(driv)n(ers.)55
+b(The)33 b(\020)7 b Fh(cardctl)41 b(reset)p Fm(\021)d(command)c
+(attempts)g(to)f(reset)h(and)f(recon\034gure)f(a)i(card.)0
+1149 y(\020)7 b Fh(cardctl)40 b(insert)p Fm(\021)30 b(and)25
+b(\020)7 b Fh(cardctl)40 b(eject)p Fm(\021)30 b(mimic)25
+b(the)h(actions)e(p)r(erformed)h(when)h(a)e(card)h(is)g(ph)n(ysically)f
+(inserted)h(or)0 1262 y(ejected,)j(including)g(loading)e(or)h
+(unloading)g(driv)n(ers,)f(and)h(con\034guring)f(or)h(sh)n(utting)g(do)
+n(wn)g(devices.)0 1419 y(If)34 b(y)n(ou)e(are)g(running)h(X,)h(the)f
+Fh(cardinfo)d Fm(utilit)n(y)k(pro)r(duces)f(a)f(graphical)g(displa)n(y)
+g(sho)n(wing)g(the)i(curren)n(t)e(status)h(of)g(all)0
+1532 y(PCMCIA)h(so)r(c)n(k)n(ets,)g(similar)f(in)g(con)n(ten)n(t)g(to)h
+(\020)7 b Fh(cardctl)40 b(config)p Fm(\021.)52 b(It)34
+b(also)e(pro)n(vides)g(a)h(graphical)f(in)n(terface)h(to)g(most)0
+1646 y(other)27 b Fh(cardctl)e Fm(functions.)0 1919 y
+Ff(4.1.4)94 b(Inserting)31 b(and)h(ejecting)f(cards)0
+2129 y Fm(In)d(theory)-7 b(,)27 b(y)n(ou)g(can)h(insert)f(and)h(remo)n
+(v)n(e)e(PCMCIA)j(cards)e(at)g(an)n(y)g(time.)39 b(Ho)n(w)n(ev)n(er,)25
+b(it)k(is)f(a)f(go)r(o)r(d)g(idea)h(not)g(to)f(eject)h(a)0
+2242 y(card)f(that)h(is)f(curren)n(tly)g(b)r(eing)g(used)h(b)n(y)f(an)g
+(application)g(program.)35 b(Kernels)27 b(older)f(than)i(1.1.77)e(w)n
+(ould)h(often)h(lo)r(c)n(k)f(up)0 2356 y(when)h(serial/mo)r(dem)e
+(cards)g(w)n(ere)h(ejected,)h(but)g(this)g(should)f(b)r(e)h(\034xed)g
+(no)n(w.)0 2512 y(Some)38 b(card)e(t)n(yp)r(es)i(cannot)f(b)r(e)i
+(safely)e(hot)h(ejected.)68 b(Sp)r(eci\034cally)-7 b(,)40
+b(A)-7 b(T)g(A/IDE)39 b(and)f(SCSI)g(in)n(terface)f(cards)f(are)h(not)0
+2626 y(hot-sw)n(ap-safe.)d(This)27 b(is)g(unlik)n(ely)g(to)f(b)r(e)i
+(\034xed,)f(b)r(ecause)f(a)h(complete)f(solution)h(w)n(ould)f(require)g
+(signi\034can)n(t)g(c)n(hanges)f(to)0 2740 y(the)32 b(Lin)n(ux)f(blo)r
+(c)n(k)g(device)g(mo)r(del.)49 b(Also,)32 b(it)g(is)f(generally)f(not)h
+(safe)g(to)h(hot)f(eject)h(CardBus)e(cards)g(of)i(an)n(y)f(t)n(yp)r(e.)
+48 b(This)0 2853 y(is)28 b(lik)n(ely)h(to)f(impro)n(v)n(e)f(gradually)g
+(as)h(hot)g(sw)n(ap)g(bugs)g(in)h(the)g(CardBus)f(driv)n(ers)f(are)g
+(found)i(and)f(\034xed.)40 b(F)-7 b(or)28 b(these)h(card)0
+2967 y(t)n(yp)r(es)e(\(IDE,)i(SCSI,)f(CardBus\),)f(it)h(is)f
+(recommended)g(that)h(y)n(ou)f(alw)n(a)n(ys)f(use)h(\020)7
+b Fh(cardctl)40 b(eject)p Fm(\021)32 b(b)r(efore)c(ejecting.)0
+3239 y Ff(4.1.5)94 b(Card)32 b(Services)g(and)g(A)m(dv)-5
+b(anced)33 b(P)m(o)m(w)m(er)g(Managemen)m(t)0 3449 y
+Fm(Card)44 b(Services)g(can)g(b)r(e)h(compiled)g(with)g(supp)r(ort)g
+(for)f(APM)i(\(A)n(dv)-5 b(anced)45 b(P)n(o)n(w)n(er)e(Managemen)n(t\))
+h(if)h(y)n(ou'v)n(e)f(con-)0 3563 y(\034gured)52 b(y)n(our)g(k)n(ernel)
+f(with)j(APM)f(supp)r(ort.)113 b(The)52 b(APM)i(k)n(ernel)e(driv)n(er)f
+(is)i(main)n(tained)f(b)n(y)h(Stephen)g(Roth-)0 3677
+y(w)n(ell)39 b(\(Stephen.Roth)n(w)n(ell@can)n(b.auug.org.au\).)68
+b(The)39 b Fh(apmd)e Fm(daemon)i(is)f(main)n(tained)h(b)n(y)g(A)-9
+b(v)n(ery)38 b(P)n(ennarun)g(\(ap)r(en-)0 3790 y(w)n(arr@w)n
+(orldvisions.ca\),)d(with)j(more)e(information)h(a)n(v)-5
+b(ailable)36 b(at)74 b Fh(<http://www.worl)o(dv)o(isi)o(on)o(s.c)o(a/)o
+(~a)o(pen)o(wa)o(rr)o(/)0 3904 y(apmd/>)p Fm(.)34 b(The)26
+b(PCMCIA)h(mo)r(dules)g(will)f(automatically)f(b)r(e)i(con\034gured)e
+(for)h(APM)h(if)g(a)f(compatible)g(v)n(ersion)f(is)h(detect-)0
+4017 y(ed)i(on)f(y)n(our)f(system.)0 4174 y(Whether)34
+b(or)f(not)h(APM)h(is)f(con\034gured,)g(y)n(ou)g(can)f(use)h(\020)7
+b Fh(cardctl)40 b(suspend)p Fm(\021)e(b)r(efore)33 b(susp)r(ending)h(y)
+n(our)f(laptop,)i(and)0 4287 y(\020)7 b Fh(cardctl)40
+b(resume)p Fm(\021)27 b(after)22 b(resuming,)g(to)g(cleanly)g(sh)n(ut)g
+(do)n(wn)g(and)g(restart)f(y)n(our)g(PCMCIA)j(cards.)33
+b(This)23 b(will)f(not)h(w)n(ork)0 4401 y(with)31 b(a)g(mo)r(dem)g
+(that)g(is)f(in)h(use,)h(b)r(ecause)e(the)h(serial)f(driv)n(er)f(isn't)
+i(able)g(to)f(sa)n(v)n(e)f(and)i(restore)e(the)i(mo)r(dem)g(op)r
+(erating)0 4514 y(parameters.)0 4671 y(APM)i(seems)e(to)g(b)r(e)h
+(unstable)g(on)f(some)g(systems.)48 b(If)33 b(y)n(ou)d(exp)r(erience)h
+(trouble)h(with)g(APM)g(and)g(PCMCIA)g(on)f(y)n(our)0
+4784 y(system,)c(try)h(to)f(narro)n(w)e(do)n(wn)j(the)f(problem)g(to)h
+(one)f(pac)n(k)-5 b(age)26 b(or)h(the)h(other)f(b)r(efore)g(rep)r
+(orting)f(a)h(bug.)0 4941 y(Some)d(driv)n(ers,)f(notably)h(the)h
+(PCMCIA)f(SCSI)h(driv)n(ers,)e(cannot)h(reco)n(v)n(er)e(from)h(a)h
+(susp)r(end/resume)f(cycle.)36 b(When)24 b(using)0 5055
+y(a)j(PCMCIA)i(SCSI)e(card,)g(alw)n(a)n(ys)f(use)h(\020)7
+b Fh(cardctl)40 b(eject)p Fm(\021)32 b(prior)27 b(to)g(susp)r(ending)h
+(the)g(system.)p eop
+%%Page: 23 23
+23 22 bop 0 -167 3900 5 v 0 -200 a Ff(4.)73 b(Usage)32
+b(and)h(features)2873 b Fm(23)0 162 y Ff(4.1.6)94 b(Sh)m(utting)31
+b(do)m(wn)h(the)g(PCMCIA)g(system)0 372 y Fm(T)-7 b(o)27
+b(unload)g(the)h(en)n(tire)f(PCMCIA)i(pac)n(k)-5 b(age,)26
+b(in)n(v)n(ok)n(e)g Fh(rc.pcmcia)d Fm(with:)208 602 y
+Fc(/etc/rc.d/rc.pcmcia)43 b(stop)0 841 y Fm(This)24 b(script)g(will)h
+(tak)n(e)e(sev)n(eral)g(seconds)g(to)h(run,)h(to)f(giv)n(e)f(all)h
+(clien)n(t)h(driv)n(ers)d(time)j(to)f(sh)n(ut)g(do)n(wn)g(gracefully)-7
+b(.)35 b(If)24 b(a)g(device)0 955 y(is)33 b(curren)n(tly)f(in)h(use,)i
+(the)e(sh)n(utdo)n(wn)f(will)i(b)r(e)f(incomplete,)i(and)d(some)h(k)n
+(ernel)f(mo)r(dules)h(ma)n(y)f(not)h(b)r(e)h(unloaded.)52
+b(T)-7 b(o)0 1068 y(a)n(v)n(oid)24 b(this,)i(use)f(\020)7
+b Fh(cardctl)40 b(eject)p Fm(\021)30 b(to)25 b(sh)n(ut)h(do)n(wn)e(all)
+h(so)r(c)n(k)n(ets)f(b)r(efore)h(in)n(v)n(oking)f Fh(rc.pcmcia)p
+Fm(.)33 b(The)25 b(exit)g(status)g(of)h(the)0 1182 y
+Fh(cardctl)f Fm(command)i(will)h(indicate)f(if)h(an)n(y)f(so)r(c)n(k)n
+(ets)f(could)i(not)f(b)r(e)h(sh)n(ut)g(do)n(wn.)0 1474
+y Fe(4.2)112 b(Ov)m(erview)37 b(of)h(the)f(PCMCIA)f(con\034guration)h
+(scripts)0 1684 y Fm(Eac)n(h)c(PCMCIA)g(device)g(has)f(an)h(asso)r
+(ciated)f(\020class\021)38 b(that)33 b(describ)r(es)f(ho)n(w)g(it)i
+(should)e(b)r(e)i(con\034gured)d(and)i(managed.)0 1797
+y(Classes)21 b(are)g(asso)r(ciated)g(with)i(device)e(driv)n(ers)g(in)h
+Fh(/etc/pcmcia/confi)o(g)p Fm(.)29 b(There)22 b(are)f(curren)n(tly)g
+(\034v)n(e)h(IO)g(device)f(classes)0 1911 y(\(net)n(w)n(ork,)26
+b(SCSI,)h(cdrom,)f(\034xed)g(disk,)h(and)f(serial\))g(and)g(t)n(w)n(o)g
+(memory)g(device)g(classes)g(\(memory)g(and)g(FTL\).)h(F)-7
+b(or)26 b(eac)n(h)0 2024 y(class,)k(there)g(are)f(t)n(w)n(o)g(scripts)h
+(in)h Fh(/etc/pcmcia)p Fm(:)37 b(a)30 b(main)g(con\034guration)e
+(script)i(\(i.e.,)i Fh(/etc/pcmcia/scs)o(i)24 b Fm(for)30
+b(SCSI)0 2138 y(devices\),)25 b(and)g(an)g(options)f(script)h(\(i.e.,)h
+Fh(/etc/pcmcia/scsi)o(.o)o(pts)o Fm(\).)k(The)c(main)e(script)h(for)g
+(a)f(device)h(will)g(b)r(e)h(in)n(v)n(ok)n(ed)0 2251
+y(to)f(con\034gure)f(that)h(device)g(when)g(a)f(card)g(is)h(inserted,)h
+(and)e(to)h(sh)n(ut)g(do)n(wn)g(the)g(device)g(when)g(the)g(card)f(is)h
+(remo)n(v)n(ed.)35 b(F)-7 b(or)0 2365 y(cards)26 b(with)i(sev)n(eral)e
+(asso)r(ciated)g(devices,)i(the)f(script)h(will)f(b)r(e)h(in)n(v)n(ok)n
+(ed)f(for)g(eac)n(h)f(device.)0 2522 y(The)38 b(con\034g)f(scripts)g
+(start)g(b)n(y)h(extracting)e(some)i(information)f(ab)r(out)g(a)h
+(device)f(from)h(the)g Fh(stab)e Fm(\034le.)68 b(Eac)n(h)37
+b(script)0 2635 y(constructs)i(a)g(\020device)g(address\021,)i(that)e
+(uniquely)h(describ)r(es)f(the)h(device)f(it)h(has)f(b)r(een)h(ask)n
+(ed)e(to)i(con\034gure,)h(in)f(the)0 2749 y Fh(ADDRESS)32
+b Fm(shell)i(v)-5 b(ariable.)57 b(This)35 b(is)f(passed)g(to)h(the)g
+Fh(*.opts)d Fm(script,)k(whic)n(h)f(should)f(return)g(information)g(ab)
+r(out)h(ho)n(w)0 2862 y(a)40 b(device)g(at)g(this)g(address)f(should)h
+(b)r(e)h(con\034gured.)73 b(F)-7 b(or)40 b(some)f(devices,)k(the)e
+(device)f(address)f(is)h(just)h(the)f(so)r(c)n(k)n(et)0
+2976 y(n)n(um)n(b)r(er.)69 b(F)-7 b(or)38 b(others,)i(it)f(includes)f
+(extra)g(information)g(that)g(ma)n(y)g(b)r(e)h(useful)g(in)f(deciding)h
+(ho)n(w)e(to)i(con\034gure)e(the)0 3089 y(device.)f(F)-7
+b(or)27 b(example,)f(net)n(w)n(ork)g(devices)g(pass)g(their)h(hardw)n
+(are)d(ethernet)j(address)f(as)g(part)g(of)h(the)g(device)g(address,)f
+(so)0 3203 y(the)i Fh(network.opts)23 b Fm(script)k(could)g(use)h(this)
+f(to)h(select)f(from)g(sev)n(eral)f(di\033eren)n(t)i(con\034gurations.)
+0 3359 y(The)i(\034rst)g(part)g(of)g(all)g(device)g(addresses)f(is)h
+(the)h(curren)n(t)e(PCMCIA)i(\020sc)n(heme\021.)44 b(This)30
+b(parameter)f(is)h(used)g(to)g(supp)r(ort)0 3473 y(m)n(ultiple)f(sets)e
+(of)h(device)g(con\034gurations)e(based)h(on)h(a)g(single)f(external)g
+(user-sp)r(eci\034ed)g(v)-5 b(ariable.)37 b(One)28 b(use)g(of)g(sc)n
+(hemes)0 3587 y(w)n(ould)36 b(b)r(e)g(to)g(ha)n(v)n(e)f(a)h
+(\020home\021)42 b(sc)n(heme,)c(and)e(a)g(\020w)n(ork\021)41
+b(sc)n(heme,)d(whic)n(h)e(w)n(ould)g(include)g(di\033eren)n(t)g(sets)g
+(of)h(net)n(w)n(ork)0 3700 y(con\034guration)h(parameters.)71
+b(The)39 b(curren)n(t)g(sc)n(heme)g(is)g(selected)g(using)g(the)h(\020)
+7 b Fh(cardctl)40 b(scheme)p Fm(\021)k(command.)72 b(The)0
+3814 y(default)28 b(if)g(no)f(sc)n(heme)g(is)h(set)f(is)h
+(\020default\021.)0 3970 y(As)33 b(a)g(general)e(rule,)j(when)f
+(con\034guring)f(Lin)n(ux)g(for)h(a)f(laptop,)i(PCMCIA)g(devices)e
+(should)h(only)f(b)r(e)i(con\034gured)d(from)0 4084 y(the)e(PCMCIA)h
+(device)f(scripts.)40 b(Do)29 b(not)g(try)f(to)h(con\034gure)f(a)g
+(PCMCIA)i(device)f(the)g(same)f(w)n(a)n(y)g(y)n(ou)g(w)n(ould)g
+(con\034gure)0 4197 y(a)37 b(p)r(ermanen)n(tly)g(attac)n(hed)f(device.)
+66 b(Ho)n(w)n(ev)n(er,)38 b(some)f(Lin)n(ux)g(distributions)g(pro)n
+(vide)f(PCMCIA)i(pac)n(k)-5 b(ages)36 b(that)h(are)0
+4311 y(ho)r(ok)n(ed)27 b(in)n(to)g(those)g(distributions')h(o)n(wn)f
+(device)g(con\034guration)f(to)r(ols.)37 b(In)28 b(that)g(case,)f(some)
+g(of)g(the)h(follo)n(wing)f(sections)0 4425 y(ma)n(y)g(not)g(apply;)h
+(ideally)-7 b(,)27 b(this)h(will)g(b)r(e)g(do)r(cumen)n(ted)f(b)n(y)h
+(the)g(distribution)f(main)n(tainers.)0 4716 y Fe(4.3)112
+b(PCMCIA)37 b(net)m(w)m(ork)g(adapters)0 4926 y Fm(Lin)n(ux)22
+b(ethernet-t)n(yp)r(e)g(net)n(w)n(ork)e(in)n(terfaces)i(normally)f(ha)n
+(v)n(e)f(names)i(lik)n(e)g Fh(eth0)p Fm(,)f Fh(eth1)p
+Fm(,)h(and)g(so)g(on.)34 b(T)-7 b(ok)n(en-ring)20 b(adapters)0
+5040 y(are)j(handled)h(similarly)-7 b(,)25 b(ho)n(w)n(ev)n(er)d(they)i
+(are)f(named)h Fh(tr0)p Fm(,)g Fh(tr1)p Fm(,)g(and)g(so)f(on.)36
+b(The)24 b Fh(ifconfig)d Fm(command)j(is)g(used)g(to)g(view)0
+5153 y(or)32 b(mo)r(dify)i(the)g(state)f(of)g(a)g(net)n(w)n(ork)f(in)n
+(terface.)53 b(A)34 b(p)r(eculiarit)n(y)f(of)g(Lin)n(ux)g(is)g(that)h
+(net)n(w)n(ork)e(in)n(terfaces)g(do)h(not)g(ha)n(v)n(e)0
+5267 y(corresp)r(onding)26 b(device)h(\034les)g(under)h
+Fh(/dev)p Fm(,)e(so)h(do)g(not)g(b)r(e)h(surprised)f(when)h(y)n(ou)e
+(do)i(not)f(\034nd)h(them.)p eop
+%%Page: 24 24
+24 23 bop 0 -167 3900 5 v 0 -200 a Ff(4.)73 b(Usage)32
+b(and)h(features)2873 b Fm(24)0 162 y(When)30 b(an)e(ethernet)i(card)e
+(is)h(detected,)h(it)f(will)g(b)r(e)h(assigned)e(the)h(\034rst)g(free)g
+(in)n(terface)f(name,)i(whic)n(h)f(will)g(normally)f(b)r(e)0
+275 y Fh(eth0)p Fm(.)47 b Fh(Cardmgr)28 b Fm(will)k(run)f(the)h
+Fh(/etc/pcmcia/netw)o(or)o(k)26 b Fm(script)31 b(to)g(con\034gure)f
+(the)i(in)n(terface,)g(whic)n(h)f(normally)f(reads)0
+389 y(net)n(w)n(ork)18 b(settings)g(from)h Fh(/etc/pcmcia/netw)o(or)o
+(k.)o(opt)o(s)p Fm(.)28 b(The)19 b Fh(network)d Fm(and)j
+Fh(network.opts)14 b Fm(scripts)k(will)i(b)r(e)f(executed)0
+502 y(only)32 b(when)h(y)n(our)e(ethernet)i(card)e(is)i(actually)f
+(presen)n(t.)51 b(If)33 b(y)n(our)e(system)h(has)g(an)h(automatic)f
+(net)n(w)n(ork)f(con\034guration)0 616 y(facilit)n(y)-7
+b(,)22 b(it)f(ma)n(y)f(or)g(ma)n(y)g(not)g(b)r(e)h(PCMCIA-a)n(w)n(are.)
+33 b(Consult)21 b(the)g(do)r(cumen)n(tation)f(of)h(y)n(our)e(Lin)n(ux)i
+(distribution)f(and)h(the)0 730 y(2.5)h(\(Notes)h(ab)r(out)f(sp)r
+(eci\034c)h(Lin)n(ux)g(distributions\))g(to)f(determine)h(if)g(PCMCIA)h
+(net)n(w)n(ork)d(devices)i(should)f(b)r(e)h(con\034gured)0
+843 y(with)28 b(the)g(automatic)f(to)r(ols,)g(or)g(b)n(y)g(editing)h
+Fh(network.opts)p Fm(.)0 1000 y(The)e(device)f(address)f(passed)h(to)g
+Fh(network.opts)c Fm(consists)j(of)i(four)f(comma-separated)e
+(\034elds:)36 b(the)26 b(sc)n(heme,)f(the)h(so)r(c)n(k)n(et)0
+1113 y(n)n(um)n(b)r(er,)21 b(the)e(device)g(instance,)i(and)e(the)h
+(card's)e(hardw)n(are)f(ethernet)j(address.)32 b(The)20
+b(device)f(instance)g(is)g(used)g(to)g(n)n(um)n(b)r(er)0
+1227 y(devices)31 b(for)h(cards)e(that)i(ha)n(v)n(e)f(sev)n(eral)f(net)
+n(w)n(ork)g(in)n(terfaces,)i(so)g(it)g(will)g(usually)f(b)r(e)h(0.)50
+b(If)32 b(y)n(ou)f(ha)n(v)n(e)g(sev)n(eral)f(net)n(w)n(ork)0
+1340 y(cards)24 b(used)h(for)g(di\033eren)n(t)g(purp)r(oses,)g(one)g
+(option)g(w)n(ould)g(b)r(e)g(to)g(con\034gure)f(the)i(cards)e(based)h
+(on)g(so)r(c)n(k)n(et)f(p)r(osition,)h(as)g(in:)208 1570
+y Fc(case)40 b("$ADDRESS")h(in)208 1674 y(*,0,*,*\))364
+1779 y(#)f(definitions)h(for)f(network)h(card)f(in)g(socket)g(0)364
+1883 y(;;)208 1987 y(*,1,*,*\))364 2091 y(#)g(definitions)h(for)f
+(network)h(card)f(in)g(socket)g(1)364 2195 y(;;)208 2299
+y(esac)0 2539 y Fm(Alternativ)n(ely)-7 b(,)27 b(they)h(could)f(b)r(e)h
+(con\034gured)e(using)i(their)f(hardw)n(are)f(addresses,)g(as)g(in:)208
+2769 y Fc(case)40 b("$ADDRESS")h(in)208 2873 y
+(*,*,*,00:80:C8:76:00:B1\))364 2977 y(#)f(definitions)h(for)f(a)g
+(D-Link)g(card)364 3081 y(;;)208 3185 y(*,*,*,08:00:5A:44:80:01\))364
+3289 y(#)g(definitions)h(for)f(an)g(IBM)g(card)208 3393
+y(esac)0 3666 y Ff(4.3.1)94 b(Net)m(w)m(ork)32 b(device)g(parameters)0
+3876 y Fm(The)c(follo)n(wing)e(parameters)g(can)h(b)r(e)h(de\034ned)g
+(in)g Fh(network.opts)p Fm(:)0 4115 y Fh(IF_PORT)208
+4262 y Fm(Sp)r(eci\034es)39 b(the)h(ethernet)g(transceiv)n(er)d(t)n(yp)
+r(e,)43 b(for)c(certain)g(16-bit)g(cards)f(that)i(do)g(not)f(auto)r
+(detect.)73 b(See)40 b(\020)7 b Fh(man)208 4376 y(ifport)p
+Fm(\021)31 b(for)c(more)g(information.)0 4556 y Fh(BOOTP)208
+4703 y Fm(A)i(b)r(o)r(olean)f(\(y/n\))h(v)-5 b(alue:)39
+b(indicates)28 b(if)i(the)f(host's)f(IP)i(address)d(and)i(routing)f
+(information)g(should)g(b)r(e)h(obtained)208 4816 y(using)e(the)h
+(BOOTP)f(proto)r(col,)f(with)i Fh(bootpc)d Fm(or)i Fh(pump)p
+Fm(.)0 4996 y Fh(DHCP)208 5143 y Fm(A)i(b)r(o)r(olean)f(\(y/n\))h(v)-5
+b(alue:)39 b(indicates)28 b(if)i(the)f(host's)f(IP)i(address)d(and)i
+(routing)f(information)g(should)g(b)r(e)h(obtained)208
+5257 y(from)e(a)g(DHCP)i(serv)n(er.)35 b(The)27 b(net)n(w)n(ork)f
+(script)i(\034rst)f(lo)r(oks)g(for)g Fh(dhcpcd)p Fm(,)e(then)j
+Fh(dhclient)p Fm(,)c(then)k Fh(pump)p Fm(.)p eop
+%%Page: 25 25
+25 24 bop 0 -167 3900 5 v 0 -200 a Ff(4.)73 b(Usage)32
+b(and)h(features)2873 b Fm(25)0 162 y Fh(HOSTNAME)208
+307 y Fm(Generally)24 b(not)i(needed,)g(this)g(can)f(b)r(e)i(used)e(to)
+h(up)r(date)g(the)g(lo)r(cal)f(hostname.)36 b(The)25
+b(v)-5 b(alue)26 b(will)g(also)e(b)r(e)i(passed)f(to)208
+421 y Fh(dhcpcd)g Fm(if)j(applicable.)0 599 y Fh(IPADDR)208
+745 y Fm(The)f(IP)h(address)f(for)g(this)g(in)n(terface.)0
+923 y Fh(NETMASK)p Ff(,)h Fh(BROADCAST)p Ff(,)g Fh(NETWORK)208
+1068 y Fm(Basic)e(net)n(w)n(ork)g(parameters:)35 b(see)28
+b(the)f(net)n(w)n(orking)f(HO)n(WTO)h(for)g(more)g(information.)0
+1246 y Fh(GATEWAY)208 1392 y Fm(The)g(IP)i(address)d(of)i(a)f(gatew)n
+(a)n(y)f(for)h(this)i(host's)e(subnet.)38 b(P)n(ac)n(k)n(ets)26
+b(with)j(destinations)e(outside)h(this)g(subnet)g(will)208
+1506 y(b)r(e)g(routed)f(to)g(this)h(gatew)n(a)n(y)-7
+b(.)0 1683 y Fh(DOMAIN)208 1829 y Fm(The)27 b(lo)r(cal)g(net)n(w)n(ork)
+f(domain)h(name)h(for)f(this)h(host,)f(to)g(b)r(e)h(used)g(in)g
+(creating)e Fh(/etc/resolv.conf)o Fm(.)0 2007 y Fh(SEARCH)208
+2153 y Fm(A)40 b(searc)n(h)f(list)i(for)e(host)h(name)g(lo)r(okup,)k
+(to)c(b)r(e)g(added)h(to)f Fh(/etc/resolv.con)o(f)p Fm(.)69
+b Fh(DOMAIN)38 b Fm(and)i Fh(SEARCH)e Fm(are)208 2266
+y(m)n(utually)27 b(exclusiv)n(e:)36 b(see)27 b(\020)7
+b Fh(man)42 b(resolver)p Fm(\021)31 b(for)c(more)g(information.)0
+2444 y Fh(DNS_1)p Ff(,)i Fh(DNS_2)p Ff(,)g Fh(DNS_3)208
+2590 y Fm(Host)e(names)g(or)g(IP)h(addresses)e(for)h(nameserv)n(ers)e
+(for)i(this)h(in)n(terface,)f(to)g(b)r(e)h(added)g(to)f
+Fh(/etc/resolv.conf)0 2768 y(MOUNTS)208 2914 y Fm(A)g(space-separated)e
+(list)j(of)g(NFS)g(moun)n(t)g(p)r(oin)n(ts)f(to)g(b)r(e)h(moun)n(ted)g
+(for)f(this)h(in)n(terface.)0 3092 y Fh(IPX_FRAME)p Ff(,)g
+Fh(IPX_NETNUM)208 3237 y Fm(F)-7 b(or)26 b(IPX)j(net)n(w)n(orks:)35
+b(the)28 b(frame)f(t)n(yp)r(e)h(and)f(net)n(w)n(ork)f(n)n(um)n(b)r(er,)
+i(passed)e(to)i(the)g Fh(ipx_interface)22 b Fm(command.)0
+3472 y(F)-7 b(or)27 b(example:)208 3696 y Fc(case)40
+b("$ADDRESS")h(in)208 3801 y(*,*,*,*\))364 3905 y(IF_PORT="10base2")364
+4009 y(BOOTP="n")364 4113 y(IPADDR="10.0.0.1")364 4217
+y(NETMASK="255.255.255.0")364 4321 y(NETWORK="10.0.0.0")364
+4425 y(BROADCAST="10.0.0.255")364 4529 y(GATEWAY="10.0.0.1")364
+4633 y(DOMAIN="domain.org")364 4738 y(DNS_1="dns1.domain.org")364
+4842 y(;;)208 4946 y(esac)0 5180 y Fm(T)-7 b(o)32 b(automatically)f
+(moun)n(t)h(and)g(unmoun)n(t)g(NFS)g(\034lesystems,)h(\034rst)f(add)g
+(all)g(these)g(\034lesystems)f(to)h Fh(/etc/fstab)p Fm(,)d(but)0
+5294 y(include)37 b Fh(noauto)c Fm(in)k(the)g(moun)n(t)f(options.)62
+b(In)36 b Fh(network.opts)p Fm(,)e(list)i(the)h(\034lesystem)f(moun)n
+(t)g(p)r(oin)n(ts)g(in)h(the)g Fh(MOUNTS)0 5407 y Fm(v)-5
+b(ariable.)46 b(It)31 b(is)g(esp)r(ecially)f(imp)r(ortan)n(t)h(to)g
+(use)f(either)h Fh(cardctl)d Fm(or)i Fh(cardinfo)e Fm(to)j(sh)n(ut)g
+(do)n(wn)f(a)g(net)n(w)n(ork)g(card)g(when)p eop
+%%Page: 26 26
+26 25 bop 0 -167 3900 5 v 0 -200 a Ff(4.)73 b(Usage)32
+b(and)h(features)2873 b Fm(26)0 162 y(NFS)32 b(moun)n(ts)e(are)g(activ)
+n(e.)46 b(It)32 b(is)f(not)g(p)r(ossible)f(to)h(cleanly)f(unmoun)n(t)i
+(NFS)f(\034lesystems)g(if)g(a)g(net)n(w)n(ork)e(card)h(is)h(simply)0
+275 y(ejected)d(without)g(w)n(arning.)0 432 y(In)22 b(addition)f(to)g
+(the)h(usual)f(net)n(w)n(ork)f(con\034guration)g(parameters,)g(the)i
+Fh(network.opts)17 b Fm(script)k(can)g(sp)r(ecify)g(extra)g(actions)0
+545 y(to)29 b(b)r(e)h(tak)n(en)f(after)g(an)g(in)n(terface)f(is)h
+(con\034gured,)g(or)f(b)r(efore)h(an)g(in)n(terface)g(is)g(sh)n(ut)h
+(do)n(wn.)41 b(If)30 b Fh(network.opts)24 b Fm(de\034nes)29
+b(a)0 659 y(shell)d(function)g(called)g Fh(start_fn)p
+Fm(,)d(it)j(will)g(b)r(e)h(in)n(v)n(ok)n(ed)d(b)n(y)i(the)g(net)n(w)n
+(ork)f(script)g(after)h(the)g(in)n(terface)f(is)h(con\034gured,)f(and)0
+772 y(the)j(in)n(terface)f(name)g(will)h(b)r(e)g(passed)f(to)h(the)g
+(function)g(as)f(its)h(\034rst)f(\(and)h(only\))g(argumen)n(t.)36
+b(Similarly)-7 b(,)27 b(if)h(it)g(is)g(de\034ned,)0 886
+y Fh(stop_fn)d Fm(will)i(b)r(e)h(in)n(v)n(ok)n(ed)e(b)r(efore)i(sh)n
+(utting)f(do)n(wn)g(an)h(in)n(terface.)0 1043 y(The)d(transceiv)n(er)d
+(t)n(yp)r(e)j(for)f(some)g(cards)g(can)g(b)r(e)h(selected)g(using)f
+(the)h Fh(IF_PORT)d Fm(setting.)36 b(This)24 b(can)h(either)f(b)r(e)h
+(a)g(n)n(umeric)0 1156 y(v)-5 b(alue,)25 b(or)f(a)g(k)n(eyw)n(ord)f
+(iden)n(tifying)i(the)g(transceiv)n(er)e(t)n(yp)r(e.)36
+b(All)25 b(the)g(net)n(w)n(ork)e(driv)n(ers)h(default)h(to)f(either)h
+(auto)r(detect)g(the)0 1270 y(in)n(terface)30 b(if)i(p)r(ossible,)g(or)
+e(10baseT)f(otherwise.)47 b(The)31 b Fh(ifport)d Fm(command)j(can)g(b)r
+(e)g(used)g(to)g(c)n(hec)n(k)f(or)g(set)i(the)f(curren)n(t)0
+1383 y(transceiv)n(er)26 b(t)n(yp)r(e.)37 b(F)-7 b(or)27
+b(example:)208 1601 y Fc(#)39 b(ifport)i(eth0)f(10base2)208
+1705 y(#)208 1809 y(#)f(ifport)i(eth0)208 1914 y(eth0)157
+b(2)40 b(\(10base2\))0 2141 y Fm(The)24 b(curren)n(t)g(\(3.0.10)f(or)g
+(later\))h(3c589)f(driv)n(er)g(should)h(quic)n(kly)g(auto)r(detect)g
+(transceiv)n(er)f(c)n(hanges)g(at)h(an)n(y)g(time.)36
+b(Earlier)0 2255 y(releases)28 b(of)i(the)g(3c589)e(driv)n(er)g(had)i
+(a)f(somewhat)g(slo)n(w)g(and)g(\035aky)g(transceiv)n(er)f(auto)r
+(detection)i(algorithm.)42 b(F)-7 b(or)29 b(these)0 2368
+y(releases,)c(the)i(appropriate)d(net)n(w)n(ork)h(cable)h(should)h(b)r
+(e)g(connected)f(to)g(the)h(card)e(when)i(the)g(card)e(is)i
+(con\034gured,)e(or)h(y)n(ou)0 2482 y(can)h(force)g(auto)r(detection)g
+(with:)208 2700 y Fc(ifconfig)41 b(eth0)f(down)g(up)0
+2970 y Ff(4.3.2)94 b(Commen)m(ts)28 b(ab)s(out)k(sp)s(eci\034c)f(cards)
+125 3168 y Fd(\017)41 b Fm(With)27 b(IBM)g(CCAE)g(and)g(So)r(c)n(k)n
+(et)f(EA)i(cards,)d(the)j(transceiv)n(er)c(t)n(yp)r(e)j(\(10base2,)e
+(10baseT,)g(A)n(UI\))j(needs)e(to)h(b)r(e)g(set)208 3282
+y(when)e(the)g(net)n(w)n(ork)f(device)h(is)g(con\034gured.)35
+b(Mak)n(e)24 b(sure)g(that)i(the)f(transceiv)n(er)f(t)n(yp)r(e)h(rep)r
+(orted)f(in)i(the)f(system)g(log)208 3395 y(matc)n(hes)h(y)n(our)h
+(connection.)125 3571 y Fd(\017)41 b Fm(The)35 b(F)-7
+b(arallon)34 b(EtherW)-7 b(a)n(v)n(e)34 b(is)i(actually)e(based)h(on)g
+(the)g(3Com)g(3c589,)g(with)h(a)f(sp)r(ecial)g(transceiv)n(er.)58
+b(Though)208 3684 y(the)25 b(EtherW)-7 b(a)n(v)n(e)24
+b(uses)h(10baseT-st)n(yle)d(connections,)j(its)g(transceiv)n(er)e
+(requires)h(that)h(the)h(3c589)d(b)r(e)i(con\034gured)f(in)208
+3798 y(10base2)h(mo)r(de.)125 3973 y Fd(\017)41 b Fm(If)23
+b(y)n(ou)f(ha)n(v)n(e)g(trouble)h(with)g(an)g(IBM)g(CCAE,)h(NE4100,)f
+(Thomas)f(Conrad,)h(or)f(Kingston)g(adapter,)h(try)g(increasing)208
+4087 y(the)30 b(memory)g(access)f(time)i(with)h(the)e
+Fh(mem_speed=#)c Fm(option)31 b(to)f(the)h Fh(pcnet_cs)c
+Fm(mo)r(dule.)46 b(An)31 b(example)f(of)h(ho)n(w)208
+4200 y(to)c(do)g(this)h(is)g(giv)n(en)e(in)i(the)g(standard)f
+Fh(config.opts)c Fm(\034le.)37 b(T)-7 b(ry)27 b(sp)r(eeds)g(of)h(up)g
+(to)f(1000)f(\(in)i(nanoseconds\).)125 4375 y Fd(\017)41
+b Fm(F)-7 b(or)30 b(the)h(New)f(Media)h(Ethernet)g(adapter,)g(on)f
+(some)g(systems,)h(it)g(ma)n(y)f(b)r(e)h(necessary)e(to)i(increase)e
+(the)i(IO)f(p)r(ort)208 4489 y(access)25 b(time)j(with)f(the)g
+Fh(io_speed=#)c Fm(option)k(when)g(the)g Fh(pcmcia_core)c
+Fm(mo)r(dule)k(is)g(loaded.)36 b(Edit)28 b Fh(CORE_OPTS)23
+b Fm(in)208 4603 y(the)28 b(startup)f(script)g(to)g(set)h(this)g
+(option.)125 4778 y Fd(\017)41 b Fm(The)24 b(m)n(ulticast)h(supp)r(ort)
+g(in)g(the)g(New)g(Media)f(Ethernet)i(driv)n(er)d(is)i(incomplete.)36
+b(The)25 b(latest)f(driv)n(er)g(will)h(function)208 4891
+y(with)j(m)n(ulticast)f(k)n(ernels,)f(but)j(will)e(ignore)g(m)n
+(ulticast)g(pac)n(k)n(ets.)36 b(Promiscuous)26 b(mo)r(de)i(should)f(w)n
+(ork)f(prop)r(erly)-7 b(.)125 5066 y Fd(\017)41 b Fm(The)31
+b(driv)n(er)f(used)i(b)n(y)f(the)h(IBM)g(and)f(3Com)g(tok)n(en)g(ring)g
+(adapters)f(seems)h(to)h(b)r(eha)n(v)n(e)e(v)n(ery)h(badly)g(if)h(the)g
+(cards)208 5180 y(are)f(not)h(connected)g(to)h(a)f(ring)f(when)i(they)f
+(get)g(initialized.)52 b(Alw)n(a)n(ys)31 b(connect)h(these)g(cards)g
+(to)g(the)h(net)f(b)r(efore)208 5294 y(they)27 b(are)g(p)r(o)n(w)n
+(ered)f(up.)37 b(If)29 b Fh(ifconfig)24 b Fm(rep)r(orts)i(the)i(hardw)n
+(are)e(address)g(as)h(all)g(0's,)g(this)h(is)g(lik)n(ely)f(to)g(b)r(e)h
+(due)g(to)f(a)208 5407 y(memory)f(windo)n(w)h(con\034guration)f
+(problem.)p eop
+%%Page: 27 27
+27 26 bop 0 -167 3900 5 v 0 -200 a Ff(4.)73 b(Usage)32
+b(and)h(features)2873 b Fm(27)125 162 y Fd(\017)41 b
+Fm(Some)k(Linksys,)k(D-Link,)g(and)c(IC-Card)f(10baseT/10base2)d(cards)
+j(ha)n(v)n(e)g(a)h(unique)h(w)n(a)n(y)e(of)h(selecting)g(the)208
+275 y(transceiv)n(er)24 b(t)n(yp)r(e)i(that)h(isn't)f(handled)h(b)n(y)f
+(the)g(Lin)n(ux)g(driv)n(ers.)35 b(One)26 b(w)n(ork)-5
+b(around)24 b(is)i(to)h(b)r(o)r(ot)f(DOS)g(and)h(use)f(the)208
+389 y(v)n(endor-supplied)g(utilit)n(y)i(to)g(select)f(the)i(transceiv)n
+(er,)c(then)k(w)n(arm)d(b)r(o)r(ot)i(Lin)n(ux.)37 b(Alternativ)n(ely)-7
+b(,)28 b(a)f(Lin)n(ux)h(utilit)n(y)208 502 y(to)f(p)r(erform)g(this)h
+(function)g(is)f(a)n(v)-5 b(ailable)27 b(at)55 b Fh(<ftp://sourcefo)o
+(rge)o(.o)o(rg)o(/pc)o(mc)o(ia)o(/ex)o(tr)o(as/)o(dl)o(po)o(rt.)o(c>)o
+Fm(.)125 682 y Fd(\017)41 b Fm(16-bit)d(PCMCIA)i(cards)f(ha)n(v)n(e)f
+(a)h(maxim)n(um)g(p)r(erformance)g(of)g(1.5-2)f(MB/sec.)72
+b(That)39 b(means)g(that)h(an)n(y)e(16-)208 796 y(bit)e(100baseT)d
+(card)i(\(i.e.,)j(an)n(y)d(card)g(that)h(uses)f(the)h
+Fh(pcnet_cs)p Fm(,)f Fh(3c574_cs)p Fm(,)f Fh(smc91c92_cs)p
+Fm(,)f(or)i Fh(xirc2ps_cs)208 910 y Fm(driv)n(er\))24
+b(will)i(nev)n(er)f(ac)n(hiev)n(e)f(full)i(100baseT)e(throughput.)36
+b(Only)25 b(CardBus)f(net)n(w)n(ork)h(adapters)f(can)h(fully)h(exploit)
+208 1023 y(100baseT)f(data)i(rates.)125 1203 y Fd(\017)41
+b Fm(F)-7 b(or)21 b(W)-7 b(a)n(v)n(eLAN)22 b(wireless)f(net)n(w)n(ork)g
+(adapters,)h(Jean)g(T)-7 b(ourrilhes)21 b(\()p Fh(jt@hpl.hp.com)p
+Fm(\))c(has)22 b(put)h(together)e(a)h(wireless)208 1317
+y(HO)n(WTO)27 b(at)55 b Fh(<http://www.hpl)o(.h)o(p.c)o(om)o(/p)o(ers)o
+(on)o(al/)o(Je)o(an)o(_To)o(ur)o(ri)o(lhe)o(s/)o(Li)o(nux)o(/>)o
+Fm(.)0 1589 y Ff(4.3.3)94 b(Diagnosing)30 b(problems)f(with)j(net)m(w)m
+(ork)h(adapters)125 1790 y Fd(\017)41 b Fm(Is)d(y)n(our)g(card)g
+(recognized)f(as)i(an)f(ethernet)h(card?)70 b(Chec)n(k)39
+b(the)g(system)g(log)f(and)g(mak)n(e)h(sure)f(that)h
+Fh(cardmgr)208 1903 y Fm(iden)n(ti\034es)23 b(the)g(card)g(correctly)e
+(and)i(starts)g(up)g(one)g(of)g(the)h(net)n(w)n(ork)d(driv)n(ers.)34
+b(If)24 b(it)f(do)r(esn't,)i(y)n(our)c(card)i(migh)n(t)g(still)208
+2017 y(b)r(e)j(usable)g(if)g(it)h(is)f(compatible)g(with)g(a)g(supp)r
+(orted)g(card.)35 b(This)26 b(will)h(b)r(e)f(most)g(easily)f(done)h(if)
+h(the)f(card)g(claims)f(to)208 2130 y(b)r(e)j(\020NE2000)e
+(compatible\021.)125 2310 y Fd(\017)41 b Fm(Is)25 b(the)i(card)e
+(con\034gured)g(prop)r(erly?)35 b(If)27 b(y)n(ou)e(are)g(using)h(a)g
+(supp)r(orted)g(card,)f(and)h(it)h(w)n(as)e(recognized)f(b)n(y)i
+Fh(cardmgr)p Fm(,)208 2424 y(but)f(still)g(do)r(esn't)g(w)n(ork,)f
+(there)h(migh)n(t)f(b)r(e)i(an)e(in)n(terrupt)h(or)f(p)r(ort)g
+(con\035ict)h(with)g(another)f(device.)36 b(Find)25 b(out)g(what)208
+2538 y(resources)17 b(the)j(card)f(is)h(using)f(\(from)h(the)g(system)f
+(log\),)i(and)e(try)h(excluding)f(these)h(in)g Fh(/etc/pcmcia/con)o
+(fig)o(.o)o(pt)o(s)208 2651 y Fm(to)27 b(force)g(the)h(card)e(to)i(use)
+f(something)g(di\033eren)n(t.)125 2831 y Fd(\017)41 b
+Fm(If)23 b(y)n(our)f(card)g(seems)g(to)h(b)r(e)h(con\034gured)e(prop)r
+(erly)-7 b(,)23 b(but)g(sometimes)g(lo)r(c)n(ks)f(up,)i(particularly)e
+(under)h(high)g(load,)g(y)n(ou)208 2945 y(ma)n(y)j(need)h(to)h(try)e(c)
+n(hanging)g(y)n(our)g(so)r(c)n(k)n(et)g(driv)n(er)g(timing)i
+(parameters.)35 b(See)27 b(the)h(2.3)e(\(Startup)i(options\))f(section)
+208 3058 y(for)g(more)f(information.)125 3238 y Fd(\017)41
+b Fm(If)33 b(y)n(ou)g(get)g(\020Net)n(w)n(ork)e(is)i(unreac)n
+(hable\021)39 b(messages)31 b(when)i(y)n(ou)g(try)g(to)g(access)f(the)h
+(net)n(w)n(ork,)h(then)f(the)h(routing)208 3352 y(information)25
+b(sp)r(eci\034ed)h(in)g Fh(/etc/pcmcia/net)o(wor)o(k.)o(op)o(ts)20
+b Fm(is)25 b(incorrect.)35 b(This)26 b(exact)f(message)g(is)g(an)h
+(absolutely)208 3465 y(fo)r(olpro)r(of)20 b(indication)g(of)h(a)g
+(routing)f(error.)33 b(On)21 b(the)g(other)g(hand,)h(mis-con\034gured)d
+(cards)h(will)i(usually)e(fail)h(silen)n(tly)-7 b(.)125
+3645 y Fd(\017)41 b Fm(If)28 b(y)n(ou)e(are)h(trying)g(to)h(use)f(DHCP)
+i(to)e(con\034gure)g(y)n(our)f(net)n(w)n(ork)g(in)n(terface,)h(try)h
+(testing)f(things)h(with)g(a)f(static)h(IP)208 3759 y(address)e
+(instead,)h(to)h(rule)f(out)g(a)h(DHCP)g(con\034guration)e(problem.)125
+3939 y Fd(\017)41 b Fm(T)-7 b(o)33 b(diagnose)f(problems)h(in)h
+Fh(/etc/pcmcia/netw)o(or)o(k.o)o(pt)o(s)p Fm(,)29 b(start)k(b)n(y)h
+(trying)f(to)g(ping)h(other)f(systems)g(on)h(the)208
+4053 y(same)f(subnet)h(using)f(their)g(IP)i(addresses.)53
+b(Then)34 b(try)f(to)h(ping)f(y)n(our)g(gatew)n(a)n(y)-7
+b(,)33 b(and)g(then)h(mac)n(hines)f(on)h(other)208 4166
+y(subnets.)i(Ping)28 b(mac)n(hines)f(b)n(y)g(name)h(only)f(after)g
+(trying)g(these)h(simpler)f(tests.)125 4346 y Fd(\017)41
+b Fm(Mak)n(e)25 b(sure)g(y)n(our)g(problem)h(is)g(really)f(a)h(PCMCIA)h
+(one.)36 b(It)27 b(ma)n(y)e(help)i(to)f(see)g(see)g(if)g(the)h(card)e
+(w)n(orks)g(under)h(DOS)208 4460 y(with)f(the)h(v)n(endor's)d(driv)n
+(ers.)35 b(Double)25 b(c)n(hec)n(k)f(y)n(our)g(mo)r(di\034cations)h(to)
+g(the)g Fh(/etc/pcmcia/netwo)o(rk)o(.o)o(pts)18 b Fm(script.)208
+4573 y(Mak)n(e)26 b(sure)h(y)n(our)f(drop)h(cable,)g(\020T\021)34
+b(jac)n(k,)27 b(terminator,)g(etc)h(are)e(w)n(orking.)125
+4753 y Fd(\017)41 b Fm(Use)21 b(real)f(net)n(w)n(ork)g(cables.)34
+b(Don't)21 b(ev)n(en)g(think)h(ab)r(out)f(using)g(that)g(old)g(phone)g
+(cord)f(y)n(ou)h(found)g(in)h(y)n(our)e(basemen)n(t.)208
+4867 y(And)28 b(this)g(means)f(Category)e(5)i(cable)h(for)f(100baseT.)e
+(It)j(really)e(matters.)p eop
+%%Page: 28 28
+28 27 bop 0 -167 3900 5 v 0 -200 a Ff(4.)73 b(Usage)32
+b(and)h(features)2873 b Fm(28)0 162 y Fe(4.4)112 b(PCMCIA)37
+b(serial)f(and)i(mo)s(dem)f(devices)0 372 y Fm(Lin)n(ux)27
+b(serial)f(devices)h(are)g(accessed)f(via)h(the)h Fh(/dev/ttyS*)23
+b Fm(and)k Fh(/dev/cua*)d Fm(sp)r(ecial)j(device)g(\034les.)37
+b(In)27 b(pre-2.2)f(k)n(ernels,)0 485 y(the)f Fh(ttyS*)d
+Fm(devices)i(w)n(ere)f(for)h(incoming)g(connections,)g(suc)n(h)g(as)g
+(directly)g(connected)g(terminals,)h(and)f(the)h Fh(cua*)e
+Fm(devices)0 599 y(w)n(ere)30 b(for)g(outgoing)f(connections,)i(suc)n
+(h)g(as)f(mo)r(dems.)46 b(Use)31 b(of)g Fh(cua*)e Fm(devices)h(is)h
+(deprecated)f(in)h(curren)n(t)f(k)n(ernels,)g(and)0 712
+y Fh(ttyS*)e Fm(can)i(b)r(e)g(used)g(for)g(all)g(applications.)43
+b(The)31 b(con\034guration)d(of)i(a)g(serial)f(device)h(can)f(b)r(e)i
+(examined)f(and)g(mo)r(di\034ed)0 826 y(with)e(the)g
+Fh(setserial)c Fm(command.)0 983 y(When)h(a)f(serial)f(or)h(mo)r(dem)g
+(card)g(is)g(detected,)h(it)g(will)g(b)r(e)g(assigned)e(to)h(the)h
+(\034rst)f(a)n(v)-5 b(ailable)23 b(serial)g(device)h(slot.)36
+b(This)24 b(will)0 1096 y(usually)g(b)r(e)i Fh(/dev/ttyS1)20
+b Fm(\()p Fh(cua1)p Fm(\))k(or)g Fh(/dev/ttyS2)d Fm(\()p
+Fh(cua2)p Fm(\),)j(dep)r(ending)h(on)g(the)g(n)n(um)n(b)r(er)g(of)f
+(built-in)i(serial)e(p)r(orts.)35 b(The)0 1210 y Fh(ttyS*)18
+b Fm(device)i(is)g(the)h(one)e(rep)r(orted)h(in)g Fh(stab)p
+Fm(.)33 b(The)20 b(default)h(serial)e(device)h(option)f(script,)j
+Fh(/etc/pcmcia/ser)o(ia)o(l.o)o(pt)o(s)p Fm(,)0 1323
+y(will)31 b(link)g(the)h(device)e(\034le)i(to)e Fh(/dev/modem)d
+Fm(as)k(a)f(con)n(v)n(enience.)46 b(F)-7 b(or)30 b(pre-2.2)g(k)n
+(ernels,)g(the)i(link)f(is)g(made)f(to)h(the)h Fh(cua*)0
+1437 y Fm(device.)0 1593 y(Do)d(not)f(try)h(to)f(use)g
+Fh(/etc/rc.d/rc.seri)o(al)22 b Fm(to)29 b(con\034gure)e(a)h(PCMCIA)i
+(mo)r(dem.)40 b(This)28 b(script)h(should)f(only)g(b)r(e)h(used)0
+1707 y(to)g(con\034gure)e(non-remo)n(v)-5 b(able)27 b(devices.)40
+b(Mo)r(dify)29 b Fh(/etc/pcmcia/seri)o(al)o(.o)o(pts)22
+b Fm(if)29 b(y)n(ou)f(w)n(an)n(t)g(to)h(do)f(an)n(ything)g(sp)r(ecial)0
+1820 y(to)d(set)h(up)g(y)n(our)e(mo)r(dem.)37 b(Also,)25
+b(do)h(not)f(try)h(to)f(c)n(hange)f(the)i(IO)g(p)r(ort)f(and)g(in)n
+(terrupt)h(settings)f(of)h(a)f(serial)f(device)h(using)0
+1934 y Fh(setserial)p Fm(.)32 b(This)25 b(w)n(ould)g(tell)g(the)g
+(serial)f(driv)n(er)g(to)h(lo)r(ok)f(for)g(the)i(device)e(in)i(a)e
+(di\033eren)n(t)h(place,)g(but)h(w)n(ould)e(not)h(c)n(hange)0
+2048 y(ho)n(w)30 b(the)i(card's)d(hardw)n(are)g(is)i(actually)f
+(con\034gured.)46 b(The)31 b(serial)e(con\034guration)h(script)g(allo)n
+(ws)g(y)n(ou)g(to)h(sp)r(ecify)g(other)0 2161 y Fh(setserial)24
+b Fm(options,)j(as)g(w)n(ell)g(as)g(whether)g(a)h(line)f(should)h(b)r
+(e)g(added)f(to)g Fh(/etc/inittab)c Fm(for)k(this)h(p)r(ort.)0
+2318 y(The)33 b(device)f(address)f(passed)h(to)g Fh(serial.opts)c
+Fm(has)k(three)h(comma-separated)d(\034elds:)47 b(the)33
+b(\034rst)f(is)g(the)h(sc)n(heme,)h(the)0 2431 y(second)g(is)g(the)h
+(so)r(c)n(k)n(et)f(n)n(um)n(b)r(er,)i(and)f(the)g(third)f(is)h(the)g
+(device)f(instance.)58 b(The)34 b(device)h(instance)f(ma)n(y)g(tak)n(e)
+g(sev)n(eral)0 2545 y(v)-5 b(alues)36 b(for)f(cards)g(that)i(supp)r
+(ort)f(m)n(ultiple)g(serial)f(p)r(orts,)j(but)f(for)e(single-p)r(ort)g
+(cards,)j(it)e(will)g(alw)n(a)n(ys)f(b)r(e)h(0.)62 b(If)37
+b(y)n(ou)0 2658 y(commonly)29 b(use)g(more)g(than)h(one)f(mo)r(dem,)h
+(y)n(ou)f(ma)n(y)g(w)n(an)n(t)g(to)g(sp)r(ecify)h(di\033eren)n(t)f
+(settings)h(based)f(on)g(so)r(c)n(k)n(et)f(p)r(osition,)0
+2772 y(as)f(in:)208 3002 y Fc(case)40 b("$ADDRESS")h(in)208
+3106 y(*,0,*\))364 3210 y(#)f(Options)h(for)e(modem)i(in)e(socket)i(0)
+364 3314 y(LINK=/dev/modem0)364 3418 y(;;)208 3523 y(*,1,*\))364
+3627 y(#)f(Options)h(for)e(modem)i(in)e(socket)i(1)364
+3731 y(LINK=/dev/modem1)364 3835 y(;;)208 3939 y(esac)0
+4178 y Fm(If)24 b(a)e(PCMCIA)i(mo)r(dem)g(is)f(already)f(con\034gured)g
+(when)h(Lin)n(ux)g(b)r(o)r(ots,)h(it)g(ma)n(y)e(b)r(e)i(incorrectly)e
+(iden)n(ti\034ed)h(as)g(an)g(ordinary)0 4292 y(built-in)j(serial)e(p)r
+(ort.)36 b(This)25 b(is)g(harmless,)g(ho)n(w)n(ev)n(er,)e(when)j(the)f
+(PCMCIA)h(driv)n(ers)e(tak)n(e)g(con)n(trol)g(of)i(the)f(mo)r(dem,)h
+(it)g(will)0 4406 y(b)r(e)i(assigned)d(a)i(di\033eren)n(t)g(device)g
+(slot.)37 b(It)27 b(is)g(b)r(est)h(to)f(either)g(parse)f
+Fh(stab)f Fm(or)i(use)g Fh(/dev/modem)p Fm(,)c(rather)j(than)h(exp)r
+(ecting)0 4519 y(a)g(PCMCIA)i(mo)r(dem)e(to)h(alw)n(a)n(ys)d(ha)n(v)n
+(e)i(the)h(same)f(device)g(assignmen)n(t.)0 4676 y(If)49
+b(y)n(ou)e(con\034gure)g(y)n(our)f(k)n(ernel)i(to)g(load)f(the)h(basic)
+g(Lin)n(ux)g(serial)f(p)r(ort)h(driv)n(er)e(as)i(a)g(mo)r(dule,)53
+b(y)n(ou)47 b(m)n(ust)i(edit)0 4789 y Fh(/etc/pcmcia/conf)o(ig)21
+b Fm(to)27 b(indicate)h(that)g(this)g(mo)r(dule)g(m)n(ust)f(b)r(e)h
+(loaded.)36 b(Edit)29 b(the)f(serial)e(device)i(en)n(try)f(to)g(read:)
+208 5019 y Fc(device)40 b("serial_cs")286 5123 y(class)g("serial")h
+(module)g("misc/serial",)h("serial_cs")p eop
+%%Page: 29 29
+29 28 bop 0 -167 3900 5 v 0 -200 a Ff(4.)73 b(Usage)32
+b(and)h(features)2873 b Fm(29)0 162 y Ff(4.4.1)94 b(Serial)31
+b(device)h(parameters)0 372 y Fm(The)c(follo)n(wing)e(parameters)g(can)
+h(b)r(e)h(de\034ned)g(in)g Fh(serial.opts)p Fm(:)0 595
+y Fh(LINK)208 741 y Fm(Sp)r(eci\034es)h(a)g(path)g(for)g(a)g(sym)n(b)r
+(olic)f(link)i(to)f(b)r(e)h(created)e(to)h(the)h(\020callout\021)35
+b(device)29 b(\(e.g.,)g Fh(/dev/cua*)d Fm(for)j(pre-2.2,)208
+855 y(or)d Fh(/dev/ttyS*)e Fm(for)j(2.2)f(k)n(ernels\).)0
+1035 y Fh(SERIAL_OPTS)208 1182 y Fm(Sp)r(eci\034es)h(options)g(to)h(b)r
+(e)g(passed)e(to)i(the)g Fh(setserial)c Fm(command.)0
+1362 y Fh(INITTAB)208 1509 y Fm(If)k(sp)r(eci\034ed,)f(this)h(will)g(b)
+r(e)g(used)g(to)f(construct)g(an)g Fh(inittab)e Fm(en)n(try)i(for)g
+(the)h(device.)0 1731 y(F)-7 b(or)27 b(example:)208 1961
+y Fc(case)40 b("$ADDRESS")h(in)208 2066 y(*,*,*,*\))364
+2170 y(LINK="/dev/modem")364 2274 y(SERIAL_OPTS="")364
+2378 y(INITTAB="/sbin/getty")0 2651 y Ff(4.4.2)94 b(Commen)m(ts)28
+b(ab)s(out)k(sp)s(eci\034c)f(cards)125 2851 y Fd(\017)41
+b Fm(The)30 b(Uniden)i(Data)e(2000)f(Wireless)h(CDPD)i(card)e(has)g
+(some)g(sp)r(ecial)h(dialing)f(strings)g(for)g(initiating)h(SLIP)g(and)
+208 2964 y(PPP)e(mo)r(de.)37 b(F)-7 b(or)27 b(SLIP)-7
+b(,)28 b(use)f(\020A)-7 b(TDT2\021;)27 b(for)g(PPP)-7
+b(,)30 b("A)-7 b(TDT0".)0 3237 y Ff(4.4.3)94 b(Diagnosing)30
+b(problems)f(with)j(serial)f(devices)125 3437 y Fd(\017)41
+b Fm(Is)34 b(y)n(our)f(card)g(recognized)g(as)h(a)f(mo)r(dem?)58
+b(Chec)n(k)34 b(the)g(system)g(log)g(and)g(mak)n(e)f(sure)h(that)h
+Fh(cardmgr)c Fm(iden)n(ti\034es)208 3551 y(the)37 b(card)f(correctly)f
+(and)i(starts)f(up)h(the)h Fh(serial_cs)33 b Fm(driv)n(er.)63
+b(If)38 b(it)f(do)r(esn't,)j(y)n(ou)c(ma)n(y)g(need)h(to)g(add)g(a)f
+(new)208 3665 y(en)n(try)27 b(to)g(y)n(our)g Fh(/etc/pcmcia/conf)o(ig)
+21 b Fm(\034le)28 b(so)f(that)h(it)g(will)g(b)r(e)h(iden)n(ti\034ed)f
+(prop)r(erly)-7 b(.)36 b(See)28 b(the)g(6.1)f(\(Con\034guring)208
+3778 y(unrecognized)f(cards\))g(section)i(for)f(details.)125
+3958 y Fd(\017)41 b Fm(Is)25 b(the)h(mo)r(dem)g(con\034gured)e
+(successfully)h(b)n(y)h(serial_cs?)34 b(Again,)26 b(c)n(hec)n(k)e(the)i
+(system)g(log)e(and)i(lo)r(ok)f(for)g(messages)208 4072
+y(from)38 b(the)g(serial_cs)f(driv)n(er.)68 b(If)38 b(y)n(ou)g(see)g
+(\020register_serial\(\))d(failed\021,)41 b(y)n(ou)d(ma)n(y)f(ha)n(v)n
+(e)g(an)i(I/O)e(p)r(ort)h(con\035ict)208 4185 y(with)f(another)f
+(device.)65 b(Another)37 b(tip-o\033)g(of)g(a)g(con\035ict)g(is)g(if)h
+(the)f(device)g(is)g(rep)r(orted)f(to)h(b)r(e)h(an)e(8250;)k(most)208
+4299 y(mo)r(dern)32 b(mo)r(dems)g(should)g(b)r(e)h(iden)n(ti\034ed)g
+(as)f(16550A)e(UAR)-7 b(T's.)52 b(If)33 b(y)n(ou)e(think)i(y)n(ou're)e
+(seeing)h(a)g(p)r(ort)g(con\035ict,)208 4412 y(edit)c
+Fh(/etc/pcmcia/con)o(fi)o(g.o)o(pt)o(s)21 b Fm(and)28
+b(exclude)f(the)h(p)r(ort)g(range)e(that)i(w)n(as)e(allo)r(cated)h(for)
+g(the)h(mo)r(dem.)125 4592 y Fd(\017)41 b Fm(Is)25 b(there)g(an)g(in)n
+(terrupt)h(con\035ict?)36 b(If)26 b(the)g(system)f(log)g(lo)r(oks)f(go)
+r(o)r(d,)h(but)h(the)g(mo)r(dem)g(just)g(do)r(esn't)g(seem)f(to)g(w)n
+(ork,)208 4706 y(try)h(using)h Fh(setserial)c Fm(to)j(c)n(hange)g(the)h
+(irq)g(to)f(0,)h(and)g(see)f(if)i(the)f(mo)r(dem)g(w)n(orks.)35
+b(This)27 b(causes)e(the)j(serial)d(driv)n(er)208 4820
+y(to)31 b(use)h(a)g(slo)n(w)n(er)e(p)r(olled)i(mo)r(de)h(instead)e(of)h
+(using)g(in)n(terrupts.)50 b(If)32 b(this)h(seems)e(to)h(\034x)g(the)h
+(problem,)f(it)h(is)f(lik)n(ely)208 4933 y(that)d(some)g(other)f
+(device)i(in)f(y)n(our)f(system)h(is)g(using)g(the)h(in)n(terrupt)f
+(selected)g(b)n(y)g(serial_cs.)40 b(Y)-7 b(ou)29 b(should)g(add)g(a)208
+5047 y(line)e(to)h Fh(/etc/pcmcia/con)o(fig)o(.o)o(pt)o(s)22
+b Fm(to)27 b(exclude)h(this)f(in)n(terrupt.)125 5227
+y Fd(\017)41 b Fm(If)28 b(the)h(mo)r(dem)f(seems)g(to)g(w)n(ork)f(only)
+h(v)n(ery)-7 b(,)27 b(v)n(ery)g(slo)n(wly)-7 b(,)28 b(this)h(is)f(an)g
+(almost)f(certain)h(indicator)f(of)h(an)g(in)n(terrupt)208
+5340 y(con\035ict.)p eop
+%%Page: 30 30
+30 29 bop 0 -167 3900 5 v 0 -200 a Ff(4.)73 b(Usage)32
+b(and)h(features)2873 b Fm(30)125 162 y Fd(\017)41 b
+Fm(Mak)n(e)31 b(sure)h(y)n(our)g(problem)g(is)h(really)e(a)i(PCMCIA)g
+(one.)52 b(It)33 b(ma)n(y)f(help)h(to)g(see)f(if)h(the)g(card)f(w)n
+(orks)f(under)i(DOS)208 275 y(with)e(the)h(v)n(endor's)e(driv)n(ers.)46
+b(Also,)32 b(don't)g(test)f(the)h(card)e(with)i(something)f(complex)g
+(lik)n(e)g(SLIP)g(or)g(PPP)i(un)n(til)208 389 y(y)n(ou)24
+b(are)f(sure)i(y)n(ou)f(can)g(mak)n(e)g(simple)h(connections.)35
+b(If)25 b(simple)g(things)g(w)n(ork)e(but)j(SLIP)f(do)r(es)g(not,)g(y)n
+(our)f(problem)208 502 y(is)j(most)g(lik)n(ely)g(with)h(SLIP)-7
+b(,)29 b(not)e(with)h(PCMCIA.)125 682 y Fd(\017)41 b
+Fm(If)28 b(y)n(ou)g(get)g(k)n(ernel)g(messages)e(indicating)j(that)f
+(the)h(serial_cs)e(mo)r(dule)h(cannot)g(b)r(e)h(loaded,)f(it)h(means)f
+(that)g(y)n(our)208 796 y(k)n(ernel)21 b(do)r(es)h(not)g(ha)n(v)n(e)f
+(serial)g(device)h(supp)r(ort.)35 b(If)23 b(y)n(ou)e(ha)n(v)n(e)g
+(compiled)i(the)f(serial)f(driv)n(er)g(as)h(a)g(mo)r(dule,)i(y)n(ou)d
+(m)n(ust)208 910 y(mo)r(dify)26 b Fh(/etc/pcmcia/con)o(fig)19
+b Fm(to)26 b(indicate)f(that)h(the)g Fh(serial)e Fm(mo)r(dule)i(should)
+f(b)r(e)h(loaded)f(b)r(efore)h Fh(serial_cs)p Fm(.)0
+1201 y Fe(4.5)112 b(PCMCIA)37 b(parallel)e(p)s(ort)j(devices)0
+1411 y Fm(The)32 b(Lin)n(ux)g(parallel)e(p)r(ort)i(driv)n(er)f(is)g(la)
+n(y)n(ered)g(so)g(that)h(sev)n(eral)e(high-lev)n(el)h(device)h(t)n(yp)r
+(es)f(can)h(share)f(use)h(of)f(the)i(same)0 1525 y(lo)n(w)c(lev)n(el)h
+(p)r(ort)g(driv)n(er.)43 b(Prin)n(ter)30 b(devices)g(are)f(accessed)g
+(via)g(the)i Fh(/dev/lp*)c Fm(sp)r(ecial)i(device)h(\034les.)45
+b(The)30 b(con\034guration)0 1638 y(of)e(a)f(prin)n(ter)g(device)g(can)
+g(b)r(e)h(examined)f(and)h(mo)r(di\034ed)f(with)i(the)f
+Fh(tunelp)d Fm(command.)0 1795 y(The)31 b Fh(parport_cs)c
+Fm(mo)r(dule)32 b(dep)r(ends)f(on)g(the)h Fh(parport)c
+Fm(and)j Fh(parport_pc)c Fm(driv)n(ers,)k(whic)n(h)g(ma)n(y)g(b)r(e)g
+(either)g(compiled)0 1908 y(in)n(to)22 b(the)g(k)n(ernel)f(or)g
+(compiled)h(as)f(mo)r(dules.)35 b(The)22 b(la)n(y)n(ered)e(driv)n(er)h
+(structure)g(means)h(that)g(an)n(y)f(top-lev)n(el)g(parallel)g(driv)n
+(ers)0 2022 y(\(suc)n(h)28 b(as)f(the)h(plip)g(driv)n(er,)e(the)j(prin)
+n(ter)d(driv)n(er,)h(etc\))h(m)n(ust)g(b)r(e)g(compiled)g(as)f(mo)r
+(dules.)37 b(These)27 b(driv)n(ers)f(only)i(recognize)0
+2136 y(parallel)g(p)r(ort)g(devices)h(at)g(mo)r(dule)g(startup)f(time,)
+i(so)e(they)h(need)g(to)g(b)r(e)h(loaded)e(after)g(an)n(y)g(PC)i(Card)e
+(parallel)g(devices)0 2249 y(are)f(con\034gured.)0 2406
+y(The)j(device)g(address)e(passed)h(to)h Fh(parport.opts)25
+b Fm(has)k(three)h(comma-separated)d(\034elds:)42 b(the)30
+b(\034rst)g(is)f(the)i(sc)n(heme,)f(the)0 2519 y(second)k(is)g(the)h
+(so)r(c)n(k)n(et)f(n)n(um)n(b)r(er,)i(and)f(the)g(third)f(is)h(the)g
+(device)f(instance.)58 b(The)34 b(device)h(instance)f(ma)n(y)g(tak)n(e)
+g(sev)n(eral)0 2633 y(v)-5 b(alues)32 b(for)g(cards)f(that)h(supp)r
+(ort)h(m)n(ultiple)f(parallel)g(p)r(orts,)h(but)g(for)e(single-p)r(ort)
+h(cards,)g(it)h(will)f(alw)n(a)n(ys)f(b)r(e)h(0.)51 b(If)33
+b(y)n(ou)0 2746 y(commonly)24 b(use)h(more)f(than)h(one)f(suc)n(h)g
+(card,)h(y)n(ou)f(ma)n(y)g(w)n(an)n(t)g(to)h(sp)r(ecify)g(di\033eren)n
+(t)f(settings)h(based)f(on)h(so)r(c)n(k)n(et)e(p)r(osition,)0
+2860 y(as)k(in:)208 3090 y Fc(case)40 b("$ADDRESS")h(in)208
+3194 y(*,0,*\))364 3298 y(#)f(Options)h(for)e(card)i(in)e(socket)i(0)
+364 3402 y(LINK=/dev/printer0)364 3506 y(;;)208 3610
+y(*,1,*\))364 3715 y(#)f(Options)h(for)e(card)i(in)e(socket)i(1)364
+3819 y(LINK=/dev/printer1)364 3923 y(;;)208 4027 y(esac)0
+4266 y Fm(If)j(y)n(ou)f(con\034gure)g(y)n(our)f(k)n(ernel)h(to)h(load)f
+(the)h(basic)g(Lin)n(ux)f(parallel)g(p)r(ort)g(driv)n(er)g(as)g(a)g(mo)
+r(dule,)49 b(y)n(ou)43 b(m)n(ust)h(edit)0 4380 y Fh(/etc/pcmcia/conf)o
+(ig)29 b Fm(to)35 b(indicate)g(that)h(the)f(appropriate)f(mo)r(dules)h
+(m)n(ust)g(b)r(e)h(loaded.)59 b(Edit)37 b(the)e(parallel)f(device)0
+4493 y(en)n(try)27 b(to)g(read:)208 4724 y Fc(device)40
+b("parport_cs")286 4828 y(class)g("parport")h(module)g("misc/parport",)
+i("misc/parport_pc",)g("parport_cs")0 5100 y Ff(4.5.1)94
+b(P)m(arallel)31 b(device)h(parameters)0 5310 y Fm(The)c(follo)n(wing)e
+(parameters)g(can)h(b)r(e)h(de\034ned)g(in)g Fh(parport.opts)p
+Fm(:)p eop
+%%Page: 31 31
+31 30 bop 0 -167 3900 5 v 0 -200 a Ff(4.)73 b(Usage)32
+b(and)h(features)2873 b Fm(31)0 162 y Fh(LINK)208 308
+y Fm(Sp)r(eci\034es)27 b(a)g(path)h(for)f(a)g(sym)n(b)r(olic)g(link)h
+(to)g(b)r(e)f(created)g(to)h(the)g(prin)n(ter)e(p)r(ort.)0
+488 y Fh(LP_OPTS)208 635 y Fm(Sp)r(eci\034es)h(options)g(to)h(b)r(e)g
+(passed)e(to)i(the)g Fh(tunelp)d Fm(command.)0 857 y(F)-7
+b(or)27 b(example:)208 1086 y Fc(case)40 b("$ADDRESS")h(in)208
+1191 y(*,*,*,*\))364 1295 y(LINK="/dev/printer")364 1399
+y(LP_OPTS="")0 1671 y Ff(4.5.2)94 b(Diagnosing)30 b(problems)f(with)j
+(parallel)f(p)s(ort)h(devices)125 1871 y Fd(\017)41 b
+Fm(Is)31 b(there)g(an)g(in)n(terrupt)g(con\035ict?)48
+b(If)31 b(the)h(system)f(log)g(lo)r(oks)f(go)r(o)r(d,)h(but)h(the)g(p)r
+(ort)f(just)h(do)r(esn't)f(seem)g(to)g(w)n(ork,)208 1985
+y(try)26 b(using)h Fh(tunelp)e Fm(to)i(c)n(hange)f(the)i(irq)f(to)g(0,)
+g(and)g(see)g(if)g(things)h(impro)n(v)n(e.)35 b(This)27
+b(switc)n(hes)g(the)g(driv)n(er)f(to)h(p)r(olling)208
+2099 y(mo)r(de.)40 b(If)30 b(this)f(seems)f(to)h(\034x)g(the)g
+(problem,)g(it)g(is)g(lik)n(ely)f(that)h(some)f(other)h(device)f(in)h
+(y)n(our)f(system)g(is)h(using)g(the)208 2212 y(in)n(terrupt)24
+b(selected)g(b)n(y)g(parp)r(ort_cs.)34 b(Y)-7 b(ou)24
+b(should)g(add)g(a)g(line)h(to)f Fh(/etc/pcmcia/con)o(fig)o(.o)o(pt)o
+(s)18 b Fm(to)25 b(exclude)f(this)208 2326 y(in)n(terrupt.)125
+2506 y Fd(\017)41 b Fm(If)34 b(y)n(ou)e(get)i(k)n(ernel)e(messages)g
+(indicating)h(that)h(the)g Fh(parport_cs)c Fm(mo)r(dule)j(cannot)g(b)r
+(e)h(loaded,)h(it)f(means)f(that)208 2619 y(y)n(our)21
+b(k)n(ernel)h(do)r(es)h(not)g(ha)n(v)n(e)f(parallel)g(device)h(supp)r
+(ort.)35 b(If)23 b(y)n(ou)g(ha)n(v)n(e)f(compiled)h(the)g(parallel)f
+(driv)n(er)g(as)g(a)h(mo)r(dule,)208 2733 y(y)n(ou)i(ma)n(y)g(need)g
+(to)h(mo)r(dify)g Fh(/etc/pcmcia/conf)o(ig)19 b Fm(to)26
+b(indicate)g(that)g(the)g Fh(parport)d Fm(and)i Fh(parport_pc)d
+Fm(mo)r(dules)208 2846 y(should)27 b(b)r(e)h(loaded)f(b)r(efore)g
+Fh(parport_cs)p Fm(.)0 3138 y Fe(4.6)112 b(PCMCIA)37
+b(SCSI)g(adapters)0 3348 y Fm(All)g(the)g(curren)n(tly)e(supp)r(orted)h
+(PCMCIA)h(SCSI)g(cards)e(are)h(w)n(ork-alik)n(es)d(of)j(one)g(of)h(the)
+g(follo)n(wing)e(ISA)i(bus)f(cards:)0 3461 y(the)30 b(Qlogic,)f(the)h
+(A)n(daptec)f(AHA-152X,)g(or)g(the)h(F)-7 b(uture)30
+b(Domain)f(TMC-16x0.)41 b(The)30 b(PCMCIA)g(driv)n(ers)e(are)h(built)h
+(b)n(y)0 3575 y(linking)j(some)f(PCMCIA-sp)r(eci\034c)i(co)r(de)e(\(in)
+i Fh(qlogic_cs.c)p Fm(,)c Fh(aha152x_cs.c)p Fm(,)f(or)j
+Fh(fdomain_cs.c)p Fm(\))c(with)34 b(the)f(normal)0 3688
+y(Lin)n(ux)23 b(SCSI)g(driv)n(er,)g(pulled)g(from)g(the)g(Lin)n(ux)g(k)
+n(ernel)f(source)f(tree.)35 b(The)23 b(A)n(daptec)g(AP)-7
+b(A1480)22 b(CardBus)g(driv)n(er)g(is)h(based)0 3802
+y(on)31 b(the)g(k)n(ernel)f(aic7xxx)f(PCI)i(driv)n(er.)46
+b(Due)31 b(to)g(limitations)f(in)h(the)h(Lin)n(ux)e(SCSI)h(driv)n(er)f
+(mo)r(del,)i(only)e(one)g(remo)n(v)-5 b(able)0 3916 y(card)27
+b(p)r(er)g(driv)n(er)f(is)i(supp)r(orted.)0 4072 y(When)j(a)e(new)i
+(SCSI)f(host)g(adapter)f(is)h(detected,)i(the)e(SCSI)g(driv)n(ers)f
+(will)h(prob)r(e)g(for)g(devices.)44 b(Chec)n(k)30 b(the)g(system)g
+(log)0 4186 y(to)j(mak)n(e)e(sure)h(y)n(our)g(devices)g(are)f(detected)
+i(prop)r(erly)-7 b(.)51 b(New)33 b(SCSI)g(devices)f(will)h(b)r(e)g
+(assigned)f(to)g(the)h(\034rst)f(a)n(v)-5 b(ailable)0
+4299 y(SCSI)29 b(device)f(\034les.)39 b(The)29 b(\034rst)f(SCSI)g(disk)
+h(will)f(b)r(e)h Fh(/dev/sda)p Fm(,)c(the)k(\034rst)f(SCSI)h(tap)r(e)g
+(will)f(b)r(e)h Fh(/dev/st0)p Fm(,)c(and)k(the)f(\034rst)0
+4413 y(CD-R)n(OM)f(will)h(b)r(e)g Fh(/dev/scd0)p Fm(.)0
+4569 y(A)34 b(list)g(of)g(SCSI)g(devices)g(connected)f(to)h(this)g
+(host)g(adapter)e(will)j(b)r(e)f(sho)n(wn)f(in)h Fh(stab)p
+Fm(,)g(and)f(the)i(SCSI)f(con\034guration)0 4683 y(script,)24
+b Fh(/etc/pcmcia/scs)o(i)p Fm(,)18 b(will)23 b(b)r(e)g(called)g(once)f
+(for)h(eac)n(h)f(attac)n(hed)g(device,)i(to)f(either)g(con\034gure)e
+(or)h(sh)n(ut)h(do)n(wn)g(that)0 4796 y(device.)44 b(The)29
+b(default)i(script)e(do)r(es)h(not)g(tak)n(e)f(an)n(y)g(actions)g(to)h
+(con\034gure)e(SCSI)j(devices,)f(but)g(will)g(prop)r(erly)f(unmoun)n(t)
+0 4910 y(\034lesystems)e(on)g(SCSI)h(devices)f(when)h(a)f(card)g(is)g
+(remo)n(v)n(ed.)0 5066 y(The)35 b(device)g(addresses)f(passed)g(to)h
+Fh(scsi.opts)d Fm(are)i(complicated,)j(b)r(ecause)d(of)h(the)h(v)-5
+b(ariet)n(y)34 b(of)h(things)g(that)h(can)f(b)r(e)0 5180
+y(attac)n(hed)d(to)h(a)g(SCSI)g(adapter.)52 b(A)n(ddresses)32
+b(consist)g(of)h(either)g(six)f(or)g(sev)n(en)h(comma-separated)d
+(\034elds:)48 b(the)33 b(curren)n(t)0 5294 y(sc)n(heme,)27
+b(the)g(device)f(t)n(yp)r(e,)i(the)f(so)r(c)n(k)n(et)f(n)n(um)n(b)r
+(er,)g(the)i(SCSI)f(c)n(hannel,)f(ID,)i(and)e(logical)g(unit)h(n)n(um)n
+(b)r(er,)g(and)g(optionally)-7 b(,)0 5407 y(the)30 b(partition)g(n)n
+(um)n(b)r(er.)43 b(The)30 b(device)f(t)n(yp)r(e)h(will)h(b)r(e)f
+(\020sd\021)36 b(for)29 b(disks,)h(\020st\021)36 b(for)30
+b(tap)r(es,)g(\020sr\021)36 b(for)29 b(CD-R)n(OM)g(devices,)h(and)p
+eop
+%%Page: 32 32
+32 31 bop 0 -167 3900 5 v 0 -200 a Ff(4.)73 b(Usage)32
+b(and)h(features)2873 b Fm(32)0 162 y(\020sg\021)30 b(for)25
+b(generic)f(SCSI)h(devices.)35 b(F)-7 b(or)25 b(most)f(setups,)i(the)f
+(SCSI)g(c)n(hannel)g(and)f(logical)g(unit)h(n)n(um)n(b)r(er)g(will)g(b)
+r(e)g(0.)36 b(F)-7 b(or)24 b(disk)0 275 y(devices)j(with)g(sev)n(eral)f
+(partitions,)g Fh(scsi.opts)e Fm(will)j(\034rst)g(b)r(e)h(called)f(for)
+g(the)g(whole)g(device,)g(with)h(a)f(\034v)n(e-\034eld)f(address.)0
+389 y(The)35 b(script)f(should)g(set)g(the)h Fh(PARTS)e
+Fm(v)-5 b(ariable)33 b(to)h(a)g(list)h(of)f(partitions.)57
+b(Then,)37 b Fh(scsi.opts)30 b Fm(will)35 b(b)r(e)g(called)f(for)g(eac)
+n(h)0 502 y(partition,)27 b(with)h(the)g(longer)e(sev)n(en-\034eld)h
+(addresses.)0 659 y(If)g(y)n(our)f(k)n(ernel)g(do)r(es)g(not)h(ha)n(v)n
+(e)f(a)g(top-lev)n(el)g(driv)n(er)g(\(disk,)h(tap)r(e,)g(etc\))h(for)e
+(a)g(particular)g(SCSI)h(device,)g(then)g(the)g(device)0
+772 y(will)d(not)g(b)r(e)h(con\034gured)e(b)n(y)g(the)i(PCMCIA)f(driv)n
+(ers.)35 b(As)24 b(a)f(side)h(e\033ect,)h(the)g(device's)e(name)h(in)h
+Fh(stab)d Fm(will)i(b)r(e)h(something)0 886 y(lik)n(e)g
+(\020sd#nnnn\021)32 b(where)25 b(\020nnnn\021)32 b(is)26
+b(a)f(four-digit)f(hex)i(n)n(um)n(b)r(er.)35 b(This)26
+b(happ)r(ens)f(when)h Fh(cardmgr)c Fm(is)k(unable)f(to)g(translate)0
+1000 y(a)i(SCSI)h(device)f(ID)h(in)n(to)g(a)f(corresp)r(onding)e(Lin)n
+(ux)j(device)f(name.)0 1156 y(It)c(is)g(p)r(ossible)f(to)h(mo)r
+(dularize)f(the)h(top-lev)n(el)f(SCSI)h(driv)n(ers)e(so)h(that)h(they)g
+(are)e(loaded)h(on)h(demand.)35 b(T)-7 b(o)22 b(do)h(so,)g(y)n(ou)f
+(need)0 1270 y(to)29 b(edit)h Fh(/etc/pcmcia/conf)o(ig)23
+b Fm(to)29 b(tell)h Fh(cardmgr)c Fm(whic)n(h)j(extra)g(mo)r(dules)g
+(need)h(to)f(b)r(e)h(loaded)e(when)i(y)n(our)e(adapter)g(is)0
+1383 y(con\034gured.)36 b(F)-7 b(or)27 b(example:)208
+1613 y Fc(device)40 b("aha152x_cs")286 1717 y(class)g("scsi")h(module)f
+("scsi/scsi_mod",)j("scsi/sd_mod",)f("aha152x_cs")0 1957
+y Fm(w)n(ould)35 b(sa)n(y)f(to)h(load)f(the)h(core)f(SCSI)i(mo)r(dule)f
+(and)g(the)g(top-lev)n(el)g(disk)g(driv)n(er)e(mo)r(dule)j(b)r(efore)e
+(loading)g(the)i(regular)0 2070 y(PCMCIA)e(driv)n(er)e(mo)r(dule.)54
+b(The)33 b(PCMCIA)h(Con\034gure)e(script)g(will)i(not)f(automatically)f
+(detect)h(mo)r(dularized)g(SCSI)0 2184 y(mo)r(dules,)28
+b(so)f(y)n(ou)f(will)i(need)g(use)f(the)h(man)n(ual)f(con\034gure)f
+(option)h(to)h(enable)f(SCSI)h(supp)r(ort.)0 2340 y(Alw)n(a)n(ys)g
+(turn)h(on)g(SCSI)g(devices)f(b)r(efore)h(p)r(o)n(w)n(ering)e(up)j(y)n
+(our)d(laptop,)i(or)g(b)r(efore)f(inserting)h(the)g(adapter)f(card,)g
+(so)h(that)0 2454 y(the)h(SCSI)f(bus)h(is)f(prop)r(erly)f(terminated)i
+(when)f(the)h(adapter)e(is)i(con\034gured.)41 b(Also)29
+b(b)r(e)h(v)n(ery)e(careful)h(ab)r(out)g(ejecting)g(a)0
+2568 y(SCSI)f(adapter.)38 b(Be)28 b(sure)f(that)i(all)f(asso)r(ciated)e
+(SCSI)j(devices)e(are)h(unmoun)n(ted)g(and)g(closed)f(b)r(efore)h
+(ejecting)g(the)h(card.)0 2681 y(The)e(b)r(est)h(w)n(a)n(y)e(to)h
+(ensure)g(this)h(is)f(to)g(use)g(either)g Fh(cardctl)e
+Fm(or)h Fh(cardinfo)e Fm(to)j(request)g(card)f(remo)n(v)-5
+b(al)26 b(b)r(efore)h(ph)n(ysically)0 2795 y(ejecting)i(the)h(card.)41
+b(F)-7 b(or)29 b(no)n(w,)g(all)g(SCSI)g(devices)g(should)g(b)r(e)h(p)r
+(o)n(w)n(ered)e(up)h(b)r(efore)g(plugging)g(in)g(a)g(SCSI)h(adapter,)e
+(and)0 2908 y(should)f(sta)n(y)g(connected)g(un)n(til)h(after)g(y)n(ou)
+e(unplug)i(the)g(adapter)e(and/or)g(p)r(o)n(w)n(er)h(do)n(wn)g(y)n(our)
+f(laptop.)0 3065 y(There)c(is)h(a)g(p)r(oten)n(tial)f(complication)g
+(when)h(using)g(these)g(cards)e(that)j(do)r(es)e(not)h(arise)f(with)h
+(ordinary)e(ISA)i(bus)g(adapters.)0 3178 y(The)i(SCSI)h(bus)f(carries)e
+(a)i(\020termination)g(p)r(o)n(w)n(er\021)30 b(signal)25
+b(that)g(is)g(necessary)f(for)g(prop)r(er)h(op)r(eration)f(of)h
+(ordinary)e(passiv)n(e)0 3292 y(SCSI)h(terminators.)34
+b(PCMCIA)25 b(SCSI)f(adapters)e(do)i(not)f(supply)h(termination)f(p)r
+(o)n(w)n(er,)h(so)f(if)h(it)g(is)g(required,)g(an)f(external)0
+3406 y(device)i(m)n(ust)h(supply)f(it.)37 b(Some)25 b(external)f(SCSI)i
+(devices)f(ma)n(y)f(b)r(e)i(con\034gured)e(to)i(supply)f(termination)g
+(p)r(o)n(w)n(er.)35 b(Others,)0 3519 y(suc)n(h)28 b(as)g(the)h(Zip)g
+(Driv)n(e)f(and)g(the)h(Syquest)g(EZ-Driv)n(e,)f(use)g(activ)n(e)g
+(terminators)f(that)i(do)f(not)h(dep)r(end)g(on)g(it.)40
+b(In)29 b(some)0 3633 y(cases,)g(it)h(ma)n(y)f(b)r(e)h(necessary)e(to)i
+(use)f(a)h(sp)r(ecial)f(terminator)f(blo)r(c)n(k)i(suc)n(h)f(as)g(the)h
+(APS)h(SCSI)f(Sen)n(try)f(2,)h(whic)n(h)f(has)g(an)0
+3746 y(external)h(p)r(o)n(w)n(er)f(supply)-7 b(.)46 b(When)31
+b(con\034guring)f(y)n(our)f(SCSI)i(device)f(c)n(hain,)h(b)r(e)g(a)n(w)n
+(are)e(of)h(whether)h(or)e(not)i(an)n(y)f(of)g(y)n(our)0
+3860 y(devices)d(require)f(or)h(can)g(pro)n(vide)g(termination)g(p)r(o)
+n(w)n(er.)0 4132 y Ff(4.6.1)94 b(SCSI)32 b(device)f(parameters)0
+4343 y Fm(The)d(follo)n(wing)e(parameters)g(can)h(b)r(e)h(de\034ned)g
+(in)g Fh(scsi.opts)p Fm(:)0 4565 y Fh(DO_FSTAB)208 4712
+y Fm(A)f(b)r(o)r(olean)g(\(y/n\))h(setting:)37 b(sp)r(eci\034es)27
+b(if)h(an)g(en)n(try)f(should)g(b)r(e)h(added)f(to)h
+Fh(/etc/fstab)23 b Fm(for)k(this)h(device.)0 4892 y Fh(DO_FSCK)208
+5039 y Fm(A)22 b(b)r(o)r(olean)g(\(y/n\))g(setting:)35
+b(sp)r(eci\034es)22 b(if)h(the)f(\034lesystem)g(should)h(b)r(e)f(c)n
+(hec)n(k)n(ed)f(b)r(efore)h(b)r(eing)h(moun)n(ted,)g(with)g(\020)7
+b Fh(fsck)208 5153 y(-Ta)p Fm(\021.)0 5333 y Fh(DO_MOUNT)p
+eop
+%%Page: 33 33
+33 32 bop 0 -167 3900 5 v 0 -200 a Ff(4.)73 b(Usage)32
+b(and)h(features)2873 b Fm(33)208 162 y(A)35 b(b)r(o)r(olean)f(\(y/n\))
+h(setting:)52 b(sp)r(eci\034es)35 b(if)g(this)g(device)g(should)g(b)r
+(e)g(automatically)f(moun)n(ted)h(at)g(card)f(insertion)208
+275 y(time.)0 455 y Fh(FSTYPE)p Ff(,)29 b Fh(OPTS)p Ff(,)g
+Fh(MOUNTPT)208 602 y Fm(The)e(\034lesystem)h(t)n(yp)r(e,)f(moun)n(t)h
+(options,)f(and)g(moun)n(t)h(p)r(oin)n(t)g(to)f(b)r(e)h(used)g(for)f
+(the)h(fstab)g(en)n(try)f(and/or)e(moun)n(ting)208 715
+y(the)j(device.)0 938 y(F)-7 b(or)24 b(example,)g(here)g(is)g(a)g
+(script)g(for)g(con\034guring)e(a)i(disk)g(device)g(at)g(SCSI)h(ID)g
+(3,)f(with)h(t)n(w)n(o)e(partitions,)i(and)f(a)g(CD-R)n(OM)0
+1051 y(at)j(SCSI)h(ID)g(6:)208 1281 y Fc(case)40 b("$ADDRESS")h(in)208
+1385 y(*,sd,*,0,3,0\))364 1489 y(#)f(This)g(device)g(has)g(two)g
+(partitions...)364 1593 y(PARTS="1)h(2")364 1697 y(;;)208
+1802 y(*,sd,*,0,3,0,1\))364 1906 y(#)f(Options)h(for)e(partition)j(1:)
+364 2010 y(#)79 b(update)41 b(/etc/fstab,)g(and)f(mount)g(an)g(ext2)g
+(fs)g(on)f(/usr1)364 2114 y(DO_FSTAB="y")j(;)e(DO_FSCK="y")h(;)f
+(DO_MOUNT="y")364 2218 y(FSTYPE="ext2")364 2322 y(OPTS="")364
+2426 y(MOUNTPT="/usr1")364 2530 y(;;)208 2634 y(*,sd,*,0,3,0,2\))364
+2739 y(#)g(Options)h(for)e(partition)j(2:)364 2843 y(#)79
+b(update)41 b(/etc/fstab,)g(and)f(mount)g(an)g(MS-DOS)h(fs)e(on)h
+(/usr2)364 2947 y(DO_FSTAB="y")i(;)e(DO_FSCK="y")h(;)f(DO_MOUNT="y")364
+3051 y(FSTYPE="msdos")364 3155 y(OPTS="")364 3259 y(MOUNTPT="/usr2")364
+3363 y(;;)208 3467 y(*,sr,*,0,6,0\))364 3571 y(#)g(Options)h(for)e
+(CD-ROM)i(at)f(SCSI)g(ID)f(6)364 3676 y(PARTS="")364
+3780 y(DO_FSTAB="y")j(;)e(DO_FSCK="n")h(;)f(DO_MOUNT="y")364
+3884 y(FSTYPE="iso9660")364 3988 y(OPTS="ro")364 4092
+y(MOUNTPT="/cdrom")364 4196 y(;;)208 4300 y(esac)0 4573
+y Ff(4.6.2)94 b(Commen)m(ts)28 b(ab)s(out)k(sp)s(eci\034c)f(cards)125
+4773 y Fd(\017)41 b Fm(The)21 b(A)n(daptec)h(AP)-7 b(A-1480)21
+b(CardBus)f(card)h(needs)h(a)f(large)g(IO)g(p)r(ort)h(windo)n(w)f
+(\(256)g(con)n(tiguous)f(p)r(orts)i(aligned)f(on)g(a)208
+4887 y(256-p)r(ort)g(b)r(oundary\).)35 b(It)24 b(ma)n(y)f(b)r(e)h
+(necessary)e(to)h(expand)g(the)h(IO)g(p)r(ort)f(regions)f(in)i
+Fh(/etc/pcmcia/con)o(fig)o(.o)o(pt)o(s)208 5000 y Fm(to)j(guaran)n(tee)
+f(that)h(suc)n(h)h(a)f(large)f(windo)n(w)h(can)g(b)r(e)h(found.)125
+5180 y Fd(\017)41 b Fm(The)33 b(A)n(daptec)g(AP)-7 b(A-460)32
+b(SlimSCSI)i(adapter)e(is)h(not)g(supp)r(orted.)53 b(This)33
+b(card)g(w)n(as)f(originally)f(sold)i(under)g(the)208
+5294 y(T)-7 b(ran)n(tor)27 b(name,)j(and)f(when)g(A)n(daptec)g(merged)g
+(with)g(T)-7 b(ran)n(tor,)28 b(they)i(con)n(tin)n(ued)f(to)g(sell)g
+(the)h(T)-7 b(ran)n(tor)27 b(card)i(with)208 5407 y(an)e(A)n(daptec)g
+(lab)r(el.)37 b(The)28 b(AP)-7 b(A-460)27 b(is)g(not)h(compatible)f
+(with)h(an)n(y)f(existing)g(Lin)n(ux)g(driv)n(er.)p eop
+%%Page: 34 34
+34 33 bop 0 -167 3900 5 v 0 -200 a Ff(4.)73 b(Usage)32
+b(and)h(features)2873 b Fm(34)125 162 y Fd(\017)41 b
+Fm(I)30 b(ha)n(v)n(e)f(had)h(one)g(rep)r(ort)f(of)h(a)g(bad)g(in)n
+(teraction)g(b)r(et)n(w)n(een)g(the)g(New)h(Media)f(Bus)g(T)-7
+b(oaster)29 b(and)h(a)g(UMAX)h(Astra)208 275 y(1200s)j(scanner.)62
+b(Due)37 b(to)f(the)h(complexit)n(y)e(of)i(the)f(SCSI)h(proto)r(col,)g
+(when)g(diagnosing)d(problems)i(with)h(SCSI)208 389 y(devices,)e(it)g
+(is)f(w)n(orth)g(considering)f(that)h(incompatible)h(com)n(binations)e
+(lik)n(e)h(this)h(ma)n(y)e(exist)h(and)h(ma)n(y)e(not)i(b)r(e)208
+502 y(do)r(cumen)n(ted.)0 772 y Ff(4.6.3)94 b(Diagnosing)30
+b(problems)f(with)j(SCSI)g(adapters)125 970 y Fd(\017)41
+b Fm(With)35 b(the)g Fh(aha152x_cs)30 b Fm(driv)n(er)j(\(used)i(b)n(y)f
+(A)n(daptec,)i(New)f(Media,)h(and)e(a)h(few)f(others\),)i(it)f(seems)f
+(that)h(SCSI)208 1083 y(disconnect/reconnect)20 b(supp)r(ort)i(is)h(a)f
+(frequen)n(t)g(source)f(of)i(trouble)f(with)h(tap)r(e)f(driv)n(es.)34
+b(T)-7 b(o)22 b(disable)g(this)h(\020feature,\021)208
+1197 y(add)k(the)h(follo)n(wing)e(to)i Fh(/etc/pcmcia/con)o(fig)o(.o)o
+(pt)o(s)p Fm(:)390 1361 y Fc(module)41 b("aha152x_cs")h(opts)e
+("reconnect=0")125 1535 y Fd(\017)h Fm(Also)24 b(with)i(the)g
+Fh(aha152x_cs)21 b Fm(driv)n(er,)j(certain)h(devices)f(seem)h(to)g
+(require)f(a)h(longer)f(startup)h(dela)n(y)-7 b(,)25
+b(con)n(trolled)f(via)208 1649 y(the)k Fh(reset_delay)23
+b Fm(mo)r(dule)28 b(parameter.)36 b(The)27 b(Y)-7 b(amaha)27
+b(4416S)f(CDR)j(driv)n(e)e(is)g(one)h(suc)n(h)f(device.)37
+b(The)28 b(result)f(is)208 1762 y(the)h(device)f(is)g(iden)n(ti\034ed)h
+(successfully)-7 b(,)27 b(then)i(hangs)d(the)i(system.)37
+b(In)27 b(suc)n(h)h(cases,)e(try:)390 1926 y Fc(module)41
+b("aha152x_cs")h(opts)e("reset_delay=500")125 2100 y
+Fd(\017)h Fm(Another)c(p)r(oten)n(tial)h(source)e(of)i(SCSI)f(device)h
+(prob)r(e)f(problems)g(is)h(probing)e(of)i(m)n(ultiple)g(LUN's.)67
+b(If)39 b(y)n(ou)d(see)208 2214 y(successful)25 b(detection)h(of)g(a)f
+(device,)h(follo)n(w)n(ed)f(b)n(y)h(SCSI)g(bus)g(timeouts)g(when)g(LUN)
+g(1)g(for)f(that)h(device)g(is)f(prob)r(ed,)208 2327
+y(then)j(disable)f(the)h(k)n(ernel's)e Fh(CONFIG_SCSI_MULT)o(I_)o(LUN)
+21 b Fm(option.)125 2501 y Fd(\017)41 b Fm(If)67 b(y)n(ou)f(ha)n(v)n(e)
+g(compiled)h(SCSI)g(supp)r(ort)g(as)f(mo)r(dules)h(\()p
+Fh(CONFIG_SCSI)c Fm(is)k(\020m\021\),)76 b(y)n(ou)67
+b(m)n(ust)g(mo)r(dify)208 2615 y Fh(/etc/pcmcia/con)o(fi)o(g)22
+b Fm(to)27 b(load)g(the)h(SCSI)g(mo)r(dules)f(b)r(efore)g(the)h
+(appropriate)e Fh(*_cs)g Fm(driv)n(er)g(is)i(loaded.)125
+2789 y Fd(\017)41 b Fm(If)35 b(y)n(ou)f(get)g(\020ab)r(orting)f
+(command)i(due)f(to)h(timeout\021)42 b(messages)33 b(when)h(the)h(SCSI)
+g(bus)g(is)g(prob)r(ed,)h(y)n(ou)e(almost)208 2902 y(certainly)26
+b(ha)n(v)n(e)h(an)g(in)n(terrupt)g(con\035ict.)125 3076
+y Fd(\017)41 b Fm(If)e(the)g(host)f(driv)n(er)g(rep)r(orts)g(\020no)g
+(SCSI)h(devices)f(found\021,)k(v)n(erify)c(that)h(y)n(our)e(k)n(ernel)h
+(w)n(as)g(compiled)g(with)i(the)208 3190 y(appropriate)30
+b(top-lev)n(el)i(SCSI)g(driv)n(ers)f(for)h(y)n(our)f(devices)h(\(i.e.,)
+i(disk,)f(tap)r(e,)h(CD-R)n(OM,)e(and/or)f(generic\).)51
+b(If)32 b(a)208 3303 y(top-lev)n(el)26 b(driv)n(er)g(is)i(missing,)f
+(devices)g(of)h(that)f(t)n(yp)r(e)h(will)g(b)r(e)g(ignored.)0
+3592 y Fe(4.7)112 b(PCMCIA)37 b(memory)f(cards)0 3802
+y Fm(The)26 b Fh(memory_cs)c Fm(driv)n(er)i(handles)h(all)h(t)n(yp)r
+(es)f(of)h(memory)e(cards,)h(as)g(w)n(ell)h(as)f(pro)n(viding)f(direct)
+h(access)g(to)g(the)h(PCMCIA)0 3916 y(memory)19 b(address)f(space)h
+(for)g(cards)f(that)i(ha)n(v)n(e)e(other)h(functions.)35
+b(When)20 b(loaded,)g(it)g(creates)f(a)g(com)n(bination)g(of)g(c)n
+(haracter)0 4029 y(and)24 b(blo)r(c)n(k)f(devices.)35
+b(See)24 b(the)g(man)g(page)f(for)h(the)g(mo)r(dule)g(for)g(a)f
+(complete)h(description)f(of)h(the)g(device)g(naming)g(sc)n(heme.)0
+4143 y(Blo)r(c)n(k)30 b(devices)g(are)g(used)g(for)g(disk-lik)n(e)g
+(access)f(\(creating)h(and)h(moun)n(ting)f(\034lesystems,)h(etc\).)46
+b(The)31 b(c)n(haracter)e(devices)0 4256 y(are)e(for)g("ra)n(w")e(un)n
+(bu\033ered)j(reads)e(and)h(writes)g(at)h(arbitrary)d(lo)r(cations.)0
+4413 y(The)k(device)g(address)e(passed)h(to)h Fh(memory.opts)c
+Fm(consists)j(of)h(t)n(w)n(o)f(\034elds:)39 b(the)30
+b(sc)n(heme,)e(and)h(the)h(so)r(c)n(k)n(et)d(n)n(um)n(b)r(er.)41
+b(The)0 4526 y(options)27 b(are)g(applied)g(to)g(the)h(\034rst)g
+(common)f(memory)f(partition)i(on)f(the)h(corresp)r(onding)d(memory)i
+(card.)0 4683 y(Some)i(older)g(memory)g(cards,)g(and)h(most)f(simple)h
+(static)g(RAM)g(cards,)f(lac)n(k)g(a)g(\020Card)f(Information)h
+(Structure\021)36 b(\(CIS\),)0 4796 y(whic)n(h)d(is)h(the)g(sc)n(heme)e
+(PCMCIA)j(cards)d(use)h(to)h(iden)n(tify)f(themselv)n(es.)54
+b(Normally)-7 b(,)34 b Fh(cardmgr)d Fm(will)i(assume)g(that)h(an)n(y)0
+4910 y(card)26 b(that)h(lac)n(ks)f(a)h(CIS)g(is)g(a)g(simple)g(memory)f
+(card,)g(and)h(load)g(the)g Fh(memory_cs)c Fm(driv)n(er.)36
+b(Th)n(us,)27 b(a)f(common)h(side)g(e\033ect)0 5024 y(of)h(a)f(general)
+f(card)h(iden)n(ti\034cation)g(problem)g(is)g(that)h(other)f(t)n(yp)r
+(es)h(of)f(cards)g(ma)n(y)f(b)r(e)i(misdetected)g(as)f(memory)g(cards.)
+0 5180 y(The)g Fh(memory_cs)d Fm(driv)n(er)i(uses)h(a)g(heuristic)g(to)
+g(guess)f(the)i(capacit)n(y)e(of)h(these)h(cards.)35
+b(The)28 b(heuristic)f(do)r(es)f(not)i(w)n(ork)e(for)0
+5294 y(write)i(protected)f(cards,)g(and)g(ma)n(y)g(mak)n(e)g(mistak)n
+(es)g(in)h(some)f(other)g(cases)g(as)g(w)n(ell.)37 b(If)28
+b(a)g(card)f(is)g(misdetected,)h(its)g(size)0 5407 y(should)f(then)h(b)
+r(e)g(explicitly)g(sp)r(eci\034ed)g(when)g(using)f(commands)g(suc)n(h)g
+(as)g Fh(dd)f Fm(or)h Fh(mkfs)p Fm(.)p eop
+%%Page: 35 35
+35 34 bop 0 -167 3900 5 v 0 -200 a Ff(4.)73 b(Usage)32
+b(and)h(features)2873 b Fm(35)0 162 y Ff(4.7.1)94 b(Memory)30
+b(device)h(parameters)0 372 y Fm(The)d(follo)n(wing)e(parameters)g(can)
+h(b)r(e)h(sp)r(eci\034ed)g(in)g Fh(memory.opts)p Fm(:)0
+611 y Fh(DO_FSTAB)208 758 y Fm(A)f(b)r(o)r(olean)g(\(y/n\))h(setting:)
+37 b(sp)r(eci\034es)27 b(if)h(an)g(en)n(try)f(should)g(b)r(e)h(added)f
+(to)h Fh(/etc/fstab)23 b Fm(for)k(this)h(device.)0 938
+y Fh(DO_FSCK)208 1085 y Fm(A)22 b(b)r(o)r(olean)g(\(y/n\))g(setting:)35
+b(sp)r(eci\034es)22 b(if)h(the)f(\034lesystem)g(should)h(b)r(e)f(c)n
+(hec)n(k)n(ed)f(b)r(efore)h(b)r(eing)h(moun)n(ted,)g(with)g(\020)7
+b Fh(fsck)208 1198 y(-Ta)p Fm(\021.)0 1378 y Fh(DO_MOUNT)208
+1525 y Fm(A)35 b(b)r(o)r(olean)f(\(y/n\))h(setting:)52
+b(sp)r(eci\034es)35 b(if)g(this)g(device)g(should)g(b)r(e)g
+(automatically)f(moun)n(ted)h(at)g(card)f(insertion)208
+1639 y(time.)0 1819 y Fh(FSTYPE)p Ff(,)29 b Fh(OPTS)p
+Ff(,)g Fh(MOUNTPT)208 1966 y Fm(The)e(\034lesystem)h(t)n(yp)r(e,)f
+(moun)n(t)h(options,)f(and)g(moun)n(t)h(p)r(oin)n(t)g(to)f(b)r(e)h
+(used)g(for)f(the)h(fstab)g(en)n(try)f(and/or)e(moun)n(ting)208
+2079 y(the)j(device.)0 2319 y(Here)f(is)g(an)g(example)g(of)g(a)g
+(script)g(that)h(will)f(automatically)f(moun)n(t)i(memory)e(cards)g
+(based)h(on)g(whic)n(h)g(so)r(c)n(k)n(et)g(they)g(are)0
+2432 y(inserted)g(in)n(to:)208 2662 y Fc(case)40 b("$ADDRESS")h(in)208
+2766 y(*,0,0\))364 2870 y(#)f(Mount)g(filesystem,)i(but)e(don't)g
+(update)h(/etc/fstab)364 2975 y(DO_FSTAB="n")h(;)e(DO_FSCK="y")h(;)f
+(DO_MOUNT="y")364 3079 y(FSTYPE="ext2")i(;)e(OPTS="")364
+3183 y(MOUNTPT="/mem0")364 3287 y(;;)208 3391 y(*,1,0\))364
+3495 y(#)g(Mount)g(filesystem,)i(but)e(don't)g(update)h(/etc/fstab)364
+3599 y(DO_FSTAB="n")h(;)e(DO_FSCK="y")h(;)f(DO_MOUNT="y")364
+3703 y(FSTYPE="ext2")i(;)e(OPTS="")364 3807 y(MOUNTPT="/mem1")364
+3911 y(;;)208 4016 y(esac)0 4288 y Ff(4.7.2)94 b(Using)31
+b(linear)g(\035ash)h(memory)d(cards)0 4498 y Fm(The)d(follo)n(wing)e
+(information)h(applies)g(only)g(to)h(so-called)e(\020linear)g
+(\035ash\021)32 b(memory)25 b(cards.)35 b(Man)n(y)25
+b(\035ash)g(cards,)g(including)0 4612 y(all)30 b(SmartMedia)f(and)h
+(CompactFlash)f(cards,)h(actually)f(include)i(circuitry)e(to)h(em)n
+(ulate)g(an)g(IDE)h(disk)f(device.)44 b(Those)0 4725
+y(cards)26 b(are)h(th)n(us)h(handled)f(as)g(IDE)i(devices,)e(not)g
+(memory)g(cards.)0 4882 y(There)33 b(are)h(t)n(w)n(o)f(ma)5
+b(jor)33 b(formats)g(for)g(\035ash)h(memory)f(cards:)49
+b(the)34 b(FTL)g(or)g(\020\035ash)f(translation)g(la)n(y)n(er\021)39
+b(st)n(yle,)c(and)f(the)0 4995 y(Microsoft)i(Flash)g(File)h(System.)65
+b(The)37 b(FTL)f(format)h(is)f(generally)f(more)h(\035exible)h(b)r
+(ecause)f(it)i(allo)n(ws)d(an)n(y)h(ordinary)0 5109 y(high-lev)n(el)25
+b(\034lesystem)h(\(ext2,)g(ms-dos,)g(etc\))g(to)g(b)r(e)g(used)g(on)g
+(a)g(\035ash)f(card)h(as)f(if)i(it)f(w)n(ere)f(an)h(ordinary)e(disk)i
+(device.)36 b(The)0 5223 y(FFS)28 b(is)g(a)f(completely)g(di\033eren)n
+(t)h(\034lesystem)f(t)n(yp)r(e.)37 b(Lin)n(ux)27 b(cannot)g(curren)n
+(tly)g(handle)g(cards)g(formated)g(with)h(FFS.)p eop
+%%Page: 36 36
+36 35 bop 0 -167 3900 5 v 0 -200 a Ff(4.)73 b(Usage)32
+b(and)h(features)2873 b Fm(36)0 162 y(T)-7 b(o)24 b(use)g(a)h(\035ash)f
+(memory)f(card)h(as)g(an)g(ordinary)e(disk-lik)n(e)i(blo)r(c)n(k)g
+(device,)h(\034rst)f(create)g(an)g(FTL)g(partition)g(on)g(the)h(device)
+0 275 y(with)31 b(the)h Fh(ftl_format)27 b Fm(command.)46
+b(This)31 b(la)n(y)n(er)e(hides)i(the)h(device-sp)r(eci\034c)e(details)
+h(of)g(\035ash)f(memory)g(programming)0 389 y(and)d(mak)n(e)g(the)h
+(card)f(lo)r(ok)g(lik)n(e)g(a)g(simple)h(blo)r(c)n(k)f(device.)36
+b(F)-7 b(or)27 b(example:)208 599 y Fc(ftl_format)41
+b(-i)f(/dev/mem0c0c)0 819 y Fm(Note)30 b(that)h(this)g(command)f
+(accesses)e(the)j(card)f(through)f(the)i(\020ra)n(w\021)k(memory)30
+b(card)f(in)n(terface.)45 b(Once)30 b(formatted,)h(the)0
+932 y(card)c(can)g(b)r(e)h(accessed)e(as)h(an)g(ordinary)f(blo)r(c)n(k)
+h(device)g(via)g(the)h Fh(ftl_cs)e Fm(driv)n(er.)35 b(F)-7
+b(or)27 b(example:)208 1142 y Fc(mke2fs)40 b(/dev/ftl0c0)208
+1246 y(mount)g(-t)g(ext2)g(/dev/ftl0c0)h(/mnt)0 1466
+y Fm(Device)35 b(naming)f(for)g(FTL)g(devices)g(is)h(tric)n(ky)-7
+b(.)57 b(Minor)34 b(device)g(n)n(um)n(b)r(ers)g(ha)n(v)n(e)g(three)g
+(parts:)50 b(the)35 b(card)f(n)n(um)n(b)r(er,)i(the)0
+1580 y(region)24 b(n)n(um)n(b)r(er)i(on)f(that)i(card,)e(and)g
+(optionally)-7 b(,)26 b(the)g(partition)f(within)i(that)f(region.)35
+b(A)26 b(region)e(can)i(either)f(b)r(e)i(treated)0 1693
+y(as)22 b(a)g(single)g(blo)r(c)n(k)g(device)h(with)g(no)f(partition)g
+(table)h(\(lik)n(e)g(a)f(\035opp)n(y\),)h(or)f(it)h(can)f(b)r(e)h
+(partitioned)f(lik)n(e)h(a)f(hard)g(disk)g(device.)0
+1807 y(The)j(\020ftl0c0\021)31 b(device)25 b(is)g(card)f(0,)h(common)g
+(memory)f(region)g(0,)h(the)g(en)n(tire)g(region.)35
+b(The)25 b(\020ftl0c0p1\021)30 b(through)25 b(\020ftl0c0p4\021)0
+1920 y(devices)i(are)g(primary)f(partitions)h(1)g(through)g(4)g(if)h
+(the)g(region)e(has)h(b)r(een)h(partitioned.)0 2077 y(Con\034guration)
+45 b(options)g(for)h(FTL)g(partitions)g(can)g(b)r(e)g(giv)n(en)g(in)g
+Fh(ftl.opts)p Fm(,)i(whic)n(h)e(is)h(similar)e(in)i(structure)e(to)0
+2190 y Fh(memory.opts)p Fm(.)66 b(The)38 b(device)h(address)e(passed)h
+(to)h Fh(ftl.opts)c Fm(consists)j(of)h(three)f(or)g(four)g(\034elds:)60
+b(the)39 b(sc)n(heme,)i(the)0 2304 y(so)r(c)n(k)n(et)33
+b(n)n(um)n(b)r(er,)i(the)g(region)e(n)n(um)n(b)r(er,)i(and)f
+(optionally)-7 b(,)35 b(the)f(partition)g(n)n(um)n(b)r(er.)56
+b(Most)33 b(\035ash)h(cards)f(ha)n(v)n(e)g(just)h(one)0
+2417 y(\035ash)27 b(memory)g(region,)f(so)h(the)h(region)e(n)n(um)n(b)r
+(er)h(will)h(generally)e(alw)n(a)n(ys)g(b)r(e)i(zero.)0
+2574 y(In)n(tel)i(Series)g(100)f(\035ash)h(cards)f(use)h(the)g(\034rst)
+g(128K)f(\035ash)h(blo)r(c)n(k)f(to)i(store)e(the)i(cards')e
+(con\034guration)f(information.)44 b(T)-7 b(o)0 2687
+y(prev)n(en)n(t)28 b(acciden)n(tal)g(erasure)g(of)g(this)i
+(information,)f Fh(ftl_format)24 b Fm(will)30 b(automatically)d(detect)
+j(this)f(and)g(skip)g(the)g(\034rst)0 2801 y(blo)r(c)n(k)e(when)h
+(creating)e(an)h(FTL)h(partition.)0 3089 y Fe(4.8)112
+b(PCMCIA)37 b(A)-9 b(T)g(A/IDE)35 b(card)i(driv)m(es)0
+3299 y Fm(A)-7 b(T)g(A/IDE)25 b(driv)n(e)e(supp)r(ort)h(is)g(based)f
+(on)h(the)g(regular)f(k)n(ernel)g(IDE)i(driv)n(er.)34
+b(This)24 b(includes)g(SmartMedia)f(and)h(Compact-)0
+3413 y(Flash)29 b(devices:)41 b(these)29 b(\035ash)h(memory)e(cards)h
+(are)f(set)i(up)g(so)f(that)h(they)g(em)n(ulate)f(an)g(IDE)i(in)n
+(terface.)42 b(The)30 b(PCMCIA-)0 3526 y(sp)r(eci\034c)f(part)f(of)h
+(the)h(driv)n(er)d(is)i Fh(ide_cs)p Fm(.)39 b(Be)28 b(sure)h(to)g(use)f
+Fh(cardctl)e Fm(or)i Fh(cardinfo)e Fm(to)j(sh)n(ut)g(do)n(wn)f(an)h(A)
+-7 b(T)g(A/IDE)30 b(card)0 3640 y(b)r(efore)d(ejecting)h(it,)g(as)f
+(the)h(driv)n(er)e(has)h(not)h(b)r(een)g(made)f(\020hot-sw)n(ap-pro)r
+(of)6 b(\021.)0 3796 y(The)23 b(device)h(addresses)d(passed)i(to)g
+Fh(ide.opts)d Fm(consist)j(of)h(either)f(three)g(or)g(four)g(\034elds:)
+34 b(the)24 b(curren)n(t)f(sc)n(heme,)g(the)h(so)r(c)n(k)n(et)0
+3910 y(n)n(um)n(b)r(er,)j(the)g(driv)n(e's)f(serial)g(n)n(um)n(b)r(er,)
+h(and)g(an)g(optional)f(partition)h(n)n(um)n(b)r(er.)36
+b(The)28 b Fh(ide_info)23 b Fm(command)k(can)g(b)r(e)g(used)0
+4024 y(to)d(obtain)g(an)g(IDE)h(device's)f(serial)f(n)n(um)n(b)r(er.)36
+b(As)24 b(with)h(SCSI)f(devices,)h Fh(ide.opts)c Fm(is)j(\034rst)g
+(called)g(for)g(the)g(en)n(tire)g(device.)0 4137 y(If)g
+Fh(ide.opts)d Fm(returns)i(a)g(list)h(of)g(partitions)f(in)h(the)g
+Fh(PARTS)e Fm(v)-5 b(ariable,)24 b(the)g(script)f(will)h(then)h(b)r(e)f
+(called)f(for)h(eac)n(h)f(partition.)0 4406 y Ff(4.8.1)94
+b(A)-8 b(T)g(A/IDE)32 b(\034xed-disk)g(device)f(parameters)0
+4616 y Fm(The)d(follo)n(wing)e(parameters)g(can)h(b)r(e)h(sp)r
+(eci\034ed)g(in)g Fh(ide.opts)p Fm(:)0 4836 y Fh(DO_FSTAB)208
+4979 y Fm(A)f(b)r(o)r(olean)g(\(y/n\))h(setting:)37 b(sp)r(eci\034es)27
+b(if)h(an)g(en)n(try)f(should)g(b)r(e)h(added)f(to)h
+Fh(/etc/fstab)23 b Fm(for)k(this)h(device.)0 5151 y Fh(DO_FSCK)208
+5294 y Fm(A)22 b(b)r(o)r(olean)g(\(y/n\))g(setting:)35
+b(sp)r(eci\034es)22 b(if)h(the)f(\034lesystem)g(should)h(b)r(e)f(c)n
+(hec)n(k)n(ed)f(b)r(efore)h(b)r(eing)h(moun)n(ted,)g(with)g(\020)7
+b Fh(fsck)208 5407 y(-Ta)p Fm(\021.)p eop
+%%Page: 37 37
+37 36 bop 0 -167 3900 5 v 0 -200 a Ff(4.)73 b(Usage)32
+b(and)h(features)2873 b Fm(37)0 162 y Fh(DO_MOUNT)208
+308 y Fm(A)35 b(b)r(o)r(olean)f(\(y/n\))h(setting:)52
+b(sp)r(eci\034es)35 b(if)g(this)g(device)g(should)g(b)r(e)g
+(automatically)f(moun)n(ted)h(at)g(card)f(insertion)208
+422 y(time.)0 602 y Fh(FSTYPE)p Ff(,)29 b Fh(OPTS)p Ff(,)g
+Fh(MOUNTPT)208 749 y Fm(The)e(\034lesystem)h(t)n(yp)r(e,)f(moun)n(t)h
+(options,)f(and)g(moun)n(t)h(p)r(oin)n(t)g(to)f(b)r(e)h(used)g(for)f
+(the)h(fstab)g(en)n(try)f(and/or)e(moun)n(ting)208 862
+y(the)j(device.)0 1102 y(Here)f(is)h(an)f(example)g Fh(ide.opts)d
+Fm(\034le)k(to)f(moun)n(t)h(the)g(\034rst)f(partition)g(of)h(an)n(y)f
+(A)-7 b(T)g(A/IDE)28 b(card)f(on)g Fh(/mnt)p Fm(.)208
+1332 y Fc(case)40 b("$ADDRESS")h(in)208 1436 y(*,*,*,1\))364
+1540 y(DO_FSTAB="y")h(;)e(DO_FSCK="y")h(;)f(DO_MOUNT="y")364
+1644 y(FSTYPE="msdos")364 1748 y(OPTS="")364 1852 y(MOUNTPT="/mnt")364
+1957 y(;;)208 2061 y(*,*,*\))364 2165 y(PARTS="1")364
+2269 y(;;)208 2373 y(esac)0 2646 y Ff(4.8.2)94 b(Diagnosing)30
+b(problems)f(with)j(A)-8 b(T)g(A/IDE)32 b(adapters)125
+2846 y Fd(\017)41 b Fm(An)56 b(IO)f(p)r(ort)h(con\035ict)g(ma)n(y)f
+(cause)g(the)i(IDE)g(driv)n(er)d(to)i(misdetect)g(the)h(driv)n(e)e
+(geometry)f(and)i(rep)r(ort)208 2960 y(\020)7 b Fh(INVALID)40
+b(GEOMETRY:)g(0)j(PHYSICAL)d(HEADS?)p Fm(\021.)88 b(T)-7
+b(o)46 b(\034x,)k(try)c(excluding)f(the)h(selected)g(IO)f(p)r(ort)g
+(range)g(in)208 3073 y Fh(/etc/pcmcia/con)o(fi)o(g.)o(opt)o(s)p
+Fm(.)125 3253 y Fd(\017)c Fm(Some)34 b(IDE)i(driv)n(es)d(violate)h(the)
+h(PCMCIA)g(sp)r(eci\034cation)f(b)n(y)h(requiring)e(a)h(longer)g(time)h
+(to)f(spin)h(up)g(than)g(the)208 3367 y(maxim)n(um)d(allo)n(w)n(ed)f
+(card)h(setup)h(time.)52 b(Starting)32 b(with)h(release)f(3.0.6,)g(the)
+h(ide_cs)f(driv)n(er)f(will)i(automatically)208 3480
+y(retry)27 b(the)h(device)g(prob)r(e)g(to)g(giv)n(e)g(these)g(driv)n
+(es)f(time)i(to)f(spin)g(up.)39 b(With)29 b(older)f(driv)n(ers,)e(y)n
+(ou)i(ma)n(y)f(need)i(to)f(load)208 3594 y(the)g Fh(pcmcia_core)23
+b Fm(mo)r(dule)k(with:)390 3764 y Fc(CORE_OPTS="unreset_delay=400")125
+3944 y Fd(\017)41 b Fm(T)-7 b(o)35 b(use)h(an)g(A)-7
+b(T)g(A/IDE)38 b(CD-R)n(OM)d(device,)k(y)n(our)c(k)n(ernel)g(m)n(ust)h
+(b)r(e)h(compiled)f(with)g Fh(CONFIG_BLK_DEV_ID)o(EC)o(D)208
+4058 y Fm(enabled.)g(This)26 b(will)h(normally)e(b)r(e)i(the)g(case)e
+(for)h(standard)g(k)n(ernels,)f(ho)n(w)n(ev)n(er)g(it)h(is)h(something)
+f(to)g(b)r(e)h(a)n(w)n(are)d(of)j(if)208 4172 y(y)n(ou)f(compile)i(a)f
+(custom)g(k)n(ernel.)125 4352 y Fd(\017)41 b Fm(A)27
+b(common)g(error)f(when)h(using)g(IDE)i(driv)n(es)d(is)h(try)g(to)h
+(moun)n(t)f(the)h(wrong)e(device)h(\034le.)37 b(Generally)-7
+b(,)27 b(y)n(ou)f(w)n(an)n(t)h(to)208 4465 y(moun)n(t)g(a)g(partition)g
+(of)h(the)g(device,)f(not)h(the)g(en)n(tire)f(device)g(\(i.e.,)h
+Fh(/dev/hde1)p Fm(,)c(not)k Fh(/dev/hde)p Fm(\).)125
+4645 y Fd(\017)41 b Fm(The)c(Lin)n(ux)g(IDE)h(driv)n(er)e(ma)n(y)h(ha)n
+(v)n(e)f(trouble)h(con\034guring)e(certain)i(remo)n(v)-5
+b(able-media)35 b(driv)n(es)h(if)i(no)f(media)g(is)208
+4759 y(presen)n(t)26 b(at)i(insertion)f(time.)37 b(The)28
+b(IBM)f(P)n(ortable)g(Driv)n(eBa)n(y)f(has)h(this)h(problem.)125
+4939 y Fd(\017)41 b Fm(Some)29 b(k)n(ernels)f(will)h(rep)r(ort)g(a)f
+(pair)h(of)g(\020driv)n(e_cmd\021)35 b(errors)27 b(at)i(insertion)f
+(time.)43 b(These)29 b(errors)e(can)i(b)r(e)g(ignored:)208
+5052 y(they)e(p)r(op)h(up)g(when)g(a)f(remo)n(v)-5 b(able)26
+b(IDE)j(device)e(do)r(es)g(not)h(accept)f(the)h(IDE)g(\020do)r(or)f(lo)
+r(c)n(k\021)33 b(command.)p eop
+%%Page: 38 38
+38 37 bop 0 -167 3900 5 v 0 -200 a Ff(5.)73 b(A)m(dv)-5
+b(anced)34 b(topics)2985 b Fm(38)0 162 y Fe(4.9)112 b(Multifunction)35
+b(cards)0 372 y Fm(A)i(single)f(in)n(terrupt)h(can)f(b)r(e)h(shared)f
+(b)n(y)h(sev)n(eral)e(driv)n(ers,)i(suc)n(h)g(as)f(the)h(serial)e(driv)
+n(er)h(and)h(an)f(ethernet)h(driv)n(er:)54 b(in)0 485
+y(fact,)31 b(the)g(PCMCIA)g(sp)r(eci\034cation)e(requires)g(all)h(card)
+g(functions)g(to)g(share)f(the)i(same)f(in)n(terrupt.)44
+b(Normally)-7 b(,)30 b(all)g(card)0 599 y(functions)35
+b(are)e(a)n(v)-5 b(ailable)34 b(without)h(ha)n(ving)e(to)i(sw)n(ap)e
+(driv)n(ers.)57 b(An)n(y)34 b(remotely)g(recen)n(t)g(Lin)n(ux)h(k)n
+(ernel)e(\(i.e.,)k(1.3.72)c(or)0 712 y(later\))27 b(supp)r(orts)g(this)
+h(kind)g(of)f(in)n(terrupt)h(sharing.)0 869 y(Sim)n(ultaneous)23
+b(use)h(of)g(t)n(w)n(o)f(card)g(functions)h(is)g(\020tric)n(ky\021)29
+b(and)24 b(v)-5 b(arious)22 b(hardw)n(are)g(v)n(endors)g(ha)n(v)n(e)h
+(implemen)n(ted)h(in)n(terrupt)0 983 y(sharing)29 b(in)i(their)g(o)n
+(wn)f(incompatible)h(\(and)g(sometimes)f(proprietary\))f(w)n(a)n(ys.)45
+b(The)30 b(driv)n(ers)g(for)g(some)g(cards)g(\(Ositec)n(h)0
+1096 y(Jac)n(k)24 b(of)h(Diamonds,)h(3Com)f(3c562)e(and)i(related)g
+(cards,)g(Linksys)f(cards\))h(prop)r(erly)f(supp)r(ort)h(sim)n
+(ultaneous)g(access,)f(but)0 1210 y(others)31 b(\(older)f(Megahertz)h
+(cards)f(in)i(particular\))e(do)h(not.)49 b(If)31 b(y)n(ou)g(ha)n(v)n
+(e)f(trouble)h(using)g(a)g(card)g(with)h(b)r(oth)g(functions)0
+1323 y(activ)n(e,)c(try)h(using)g(eac)n(h)f(function)h(in)g(isolation.)
+40 b(That)29 b(ma)n(y)f(require)g(explicitly)h(doing)f(an)h(\020)7
+b Fh(ifconfig)39 b(down)p Fm(\021)34 b(to)29 b(sh)n(ut)0
+1437 y(do)n(wn)e(a)g(net)n(w)n(ork)f(in)n(terface)h(and)h(use)f(a)g(mo)
+r(dem)h(on)f(the)h(same)f(card.)0 1775 y Fg(5)131 b(A)l(dv)-7
+b(anced)45 b(topics)0 2033 y Fe(5.1)112 b(Resource)37
+b(allo)s(cation)f(for)h(PCMCIA)g(devices)0 2243 y Fm(In)32
+b(theory)-7 b(,)33 b(it)g(should)f(not)g(really)g(matter)g(whic)n(h)g
+(in)n(terrupt)g(is)g(allo)r(cated)g(to)g(whic)n(h)g(device,)h(as)f
+(long)f(as)h(t)n(w)n(o)g(devices)0 2356 y(are)23 b(not)i(con\034gured)e
+(to)h(use)g(the)h(same)f(in)n(terrupt.)35 b(In)25 b Fh(/etc/pcmcia/con)
+o(fi)o(g.o)o(pt)o(s)18 b Fm(y)n(ou'll)24 b(\034nd)h(a)f(place)g(for)f
+(excluding)0 2470 y(in)n(terrupts)k(that)h(are)e(used)i(b)n(y)f
+(non-PCMCIA)h(devices.)0 2626 y(Similarly)-7 b(,)82 b(there)71
+b(is)g(no)g(w)n(a)n(y)g(to)g(directly)g(sp)r(ecify)g(the)h(I/O)f
+(addresses)e(for)i(a)g(card)g(to)g(use.)168 b(The)0 2740
+y Fh(/etc/pcmcia/conf)o(ig)o(.op)o(ts)28 b Fm(\034le)35
+b(allo)n(ws)f(y)n(ou)g(to)h(sp)r(ecify)g(ranges)f(of)h(p)r(orts)f(a)n
+(v)-5 b(ailable)34 b(for)g(use)h(b)n(y)g(an)n(y)f(card,)i(or)e(to)0
+2854 y(exclude)27 b(ranges)f(that)i(con\035ict)g(with)g(other)f
+(devices.)0 3010 y(After)h(mo)r(difying)g Fh(/etc/pcmcia/con)o(fi)o
+(g.o)o(pt)o(s)p Fm(,)22 b(y)n(ou)k(can)i(reinitialize)f
+Fh(cardmgr)d Fm(with)k(\020)7 b Fh(kill)42 b(-HUP)p Fm(\021.)0
+3167 y(The)28 b(in)n(terrupt)g(used)h(to)f(monitor)f(card)h(status)g(c)
+n(hanges)f(is)h(c)n(hosen)f(b)n(y)h(the)h(lo)n(w-lev)n(el)e(so)r(c)n(k)
+n(et)g(driv)n(er)g(mo)r(dule)h(\()p Fh(i82365)0 3280
+y Fm(or)k Fh(tcic)p Fm(\))f(b)r(efore)i Fh(cardmgr)c
+Fm(parses)j Fh(/etc/pcmcia/con)o(fi)o(g)p Fm(,)c(so)k(it)h(is)g(not)f
+(a\033ected)h(b)n(y)g(c)n(hanges)e(to)h(this)h(\034le.)53
+b(T)-7 b(o)32 b(set)0 3394 y(this)e(in)n(terrupt,)f(use)h(the)g
+Fh(cs_irq=)c Fm(option)j(when)h(the)g(so)r(c)n(k)n(et)e(driv)n(er)g(is)
+i(loaded,)f(b)n(y)g(setting)h(the)f Fh(PCIC_OPTS)d Fm(v)-5
+b(ariable)0 3507 y(in)28 b Fh(/etc/rc.d/rc.pc)o(mci)o(a)p
+Fm(.)0 3664 y(All)e(the)f(clien)n(t)g(card)f(driv)n(ers)g(ha)n(v)n(e)g
+(a)h(parameter)e(called)i Fh(irq_list)d Fm(for)i(sp)r(ecifying)h(whic)n
+(h)g(in)n(terrupts)g(they)g(ma)n(y)f(try)h(to)0 3777
+y(allo)r(cate.)36 b(These)27 b(driv)n(er)f(options)h(should)h(b)r(e)g
+(set)f(in)h(y)n(our)e Fh(/etc/pcmcia/confi)o(g)21 b Fm(\034le.)37
+b(F)-7 b(or)27 b(example:)208 4007 y Fc(device)40 b("serial_cs")286
+4111 y(module)h("serial_cs")g(opts)f("irq_list=8,12")286
+4216 y(...)0 4455 y Fm(w)n(ould)30 b(sp)r(ecify)g(that)h(the)f(serial)f
+(driv)n(er)g(should)h(only)g(use)g(irq)g(8)g(or)f(irq)h(12.)44
+b(Regardless)28 b(of)i Fh(irq_list)d Fm(settings,)k(Card)0
+4569 y(Services)j(will)h(nev)n(er)f(allo)r(cate)g(an)g(in)n(terrupt)h
+(that)g(is)g(already)e(in)i(use)g(b)n(y)g(another)e(device,)k(or)d(an)h
+(in)n(terrupt)f(that)h(is)0 4682 y(excluded)28 b(in)f(the)h(con\034g)f
+(\034le.)0 4974 y Fe(5.2)112 b(Ho)m(w)37 b(can)h(I)f(ha)m(v)m(e)h
+(separate)g(device)f(setups)h(for)g(home)f(and)h(w)m(ork?)0
+5184 y Fm(This)29 b(is)g(fairly)f(easy)g(using)g(\020sc)n(heme\021)35
+b(supp)r(ort.)41 b(Use)29 b(t)n(w)n(o)f(con\034guration)f(sc)n(hemes,)h
+(called)h(\020home\021)35 b(and)29 b(\020w)n(ork\021.)38
+b(Here)0 5297 y(is)27 b(an)h(example)f(of)g(a)h Fh(network.opts)22
+b Fm(script)27 b(with)h(sc)n(heme-sp)r(eci\034c)f(settings:)p
+eop
+%%Page: 39 39
+39 38 bop 0 -167 3900 5 v 0 -200 a Ff(5.)73 b(A)m(dv)-5
+b(anced)34 b(topics)2985 b Fm(39)208 162 y Fc(case)40
+b("$ADDRESS")h(in)208 266 y(work,*,*,*\))364 370 y(#)f(definitions)h
+(for)f(network)h(card)f(in)g(work)g(scheme)364 474 y(...)364
+578 y(;;)208 682 y(home,*,*,*|default,*,*,*\))364 786
+y(#)g(definitions)h(for)f(network)h(card)f(in)g(home)g(scheme)364
+890 y(...)364 995 y(;;)208 1099 y(esac)0 1310 y Fm(The)34
+b(\034rst)f(part)h(of)g(a)f(device)h(address)e(is)i(alw)n(a)n(ys)e(the)
+i(con\034guration)e(sc)n(heme.)55 b(In)34 b(this)g(example,)h(the)g
+(second)e(\020case\021)0 1423 y(clause)24 b(will)h(select)g(for)f(b)r
+(oth)h(the)g(\020home\021)31 b(and)24 b(\020default\021)32
+b(sc)n(hemes.)j(So,)25 b(if)g(the)g(sc)n(heme)f(is)h(unset)g(for)f(an)n
+(y)g(reason,)g(it)h(will)0 1537 y(default)j(to)f(the)h(\020home\021)34
+b(setup.)0 1693 y(No)n(w,)27 b(to)h(select)f(b)r(et)n(w)n(een)g(the)h
+(t)n(w)n(o)f(sets)g(of)h(settings,)f(run)h(either:)208
+1895 y Fc(cardctl)40 b(scheme)h(home)0 2106 y Fm(or)208
+2307 y Fc(cardctl)f(scheme)h(work)0 2518 y Fm(The)f Fh(cardctl)c
+Fm(command)k(do)r(es)f(the)h(equiv)-5 b(alen)n(t)39 b(of)h(sh)n(utting)
+g(do)n(wn)f(all)g(y)n(our)f(cards)h(and)g(restarting)f(them.)74
+b(The)0 2632 y(command)26 b(can)h(b)r(e)g(safely)g(executed)f(whether)h
+(or)f(not)h(the)g(PCMCIA)h(system)f(is)f(loaded,)h(but)g(the)g(command)
+g(ma)n(y)f(fail)0 2745 y(if)f(y)n(ou)f(are)f(using)i(other)f(PCMCIA)h
+(devices)f(at)g(the)h(time)h(\(ev)n(en)e(if)h(their)f(con\034gurations)
+f(are)h(not)g(explicitly)h(dep)r(endan)n(t)0 2859 y(on)i(the)h(sc)n
+(heme)f(setting\).)0 3015 y(T)-7 b(o)27 b(\034nd)h(out)g(the)g(curren)n
+(t)e(sc)n(heme)h(setting,)h(run:)208 3217 y Fc(cardctl)40
+b(scheme)0 3428 y Fm(By)33 b(default,)j(the)e(sc)n(heme)f(setting)g(is)
+g(p)r(ersisten)n(t)h(across)d(b)r(o)r(ots.)55 b(This)33
+b(can)g(ha)n(v)n(e)f(undesirable)h(e\033ects)h(if)g(net)n(w)n(orking)0
+3542 y(is)d(initialized)g(for)g(the)g(wrong)f(en)n(vironmen)n(t.)46
+b(Optionally)-7 b(,)31 b(y)n(ou)f(can)h(set)g(the)g(initial)g(sc)n
+(heme)g(v)-5 b(alue)31 b(with)g(the)h Fh(SCHEME)0 3655
+y Fm(startup)h(option)g(\(see)g(2.3)f(\(Startup)h(options\))g(for)g
+(details\).)54 b(It)33 b(is)g(also)f(p)r(ossible)h(to)g(set)g(the)h(sc)
+n(heme)e(from)h(the)h Fh(lilo)0 3769 y Fm(b)r(o)r(ot)28
+b(prompt.)36 b(Since)28 b Fh(lilo)e Fm(passes)g(unrecognized)g(options)
+h(to)g Fh(init)f Fm(as)h(en)n(vironmen)n(t)f(v)-5 b(ariables,)26
+b(a)h(v)-5 b(alue)28 b(for)f Fh(SCHEME)0 3882 y Fm(\(or)j(an)n(y)h
+(other)f(PCMCIA)i(startup)e(option\))h(at)g(the)g(b)r(o)r(ot)g(prompt)g
+(will)g(b)r(e)h(propagated)d(in)n(to)h(the)i(PCMCIA)f(startup)0
+3996 y(script.)0 4152 y(T)-7 b(o)27 b(sa)n(v)n(e)e(ev)n(en)i(more)f(k)n
+(eystrok)n(es,)f(sc)n(hemes)i(can)f(b)r(e)i(sp)r(eci\034ed)f(in)h
+Fh(lilo)p Fm('s)d(con\034guration)h(\034le.)36 b(F)-7
+b(or)27 b(instance,)g(y)n(ou)f(could)0 4266 y(ha)n(v)n(e:)208
+4467 y Fc(root)40 b(=)f(/dev/hda1)208 4572 y(read-only)208
+4676 y(image)h(=)f(/boot/vmlinuz)286 4780 y(label)80
+b(=)39 b(home)286 4884 y(append)i(=)e("SCHEME=home")208
+4988 y(image)h(=)f(/boot/vmlinuz)286 5092 y(label)80
+b(=)39 b(work)286 5196 y(append)i(=)e("SCHEME=work")0
+5407 y Fm(T)n(yping)27 b(\020home\021)33 b(or)27 b(\020w)n(ork\021)33
+b(at)27 b(the)h(b)r(o)r(ot)g(prompt)f(w)n(ould)g(then)h(b)r(o)r(ot)g
+(in)n(to)f(the)h(appropriate)e(sc)n(heme.)p eop
+%%Page: 40 40
+40 39 bop 0 -167 3900 5 v 0 -200 a Ff(5.)73 b(A)m(dv)-5
+b(anced)34 b(topics)2985 b Fm(40)0 162 y Fe(5.3)112 b(Bo)s(oting)36
+b(from)h(a)h(PCMCIA)e(device)0 372 y Fm(Ha)n(ving)21
+b(the)i(ro)r(ot)f(\034lesystem)g(on)g(a)g(PCMCIA)h(device)f(is)g(tric)n
+(ky)f(b)r(ecause)h(the)h(Lin)n(ux)f(PCMCIA)h(system)f(is)g(not)h
+(designed)0 485 y(to)29 b(b)r(e)h(link)n(ed)f(in)n(to)f(the)i(k)n
+(ernel.)41 b(Its)29 b(core)f(comp)r(onen)n(ts,)h(the)g(loadable)f(k)n
+(ernel)g(mo)r(dules)i(and)f(the)g(user)g(mo)r(de)g(cardmgr)0
+599 y(daemon,)d(dep)r(end)i(on)e(an)g(already)f(running)i(system.)36
+b(The)27 b(k)n(ernel's)e(\020initrd\021)33 b(facilit)n(y)27
+b(w)n(orks)e(around)g(this)i(requiremen)n(t)0 712 y(b)n(y)36
+b(allo)n(wing)e(Lin)n(ux)i(to)g(b)r(o)r(ot)h(using)e(a)h(temp)r(orary)f
+(ram)g(disk)h(as)g(a)f(minimal)i(ro)r(ot)e(image,)j(load)d(driv)n(ers,)
+i(and)f(then)0 826 y(re-moun)n(t)23 b(a)h(di\033eren)n(t)g(ro)r(ot)g
+(\034lesystem.)35 b(The)25 b(temp)r(orary)d(ro)r(ot)i(can)g
+(con\034gure)f(PCMCIA)i(devices)e(and)h(then)h(re-moun)n(t)0
+940 y(a)i(PCMCIA)i(device)e(as)g(ro)r(ot.)0 1096 y(The)i(initrd)h
+(image)f(absolutely)f(m)n(ust)h(reside)g(on)g(a)g(b)r(o)r(otable)g
+(device:)40 b(this)30 b(generally)e(cannot)h(b)r(e)g(put)h(on)f(a)g
+(PCMCIA)0 1210 y(device.)35 b(This)23 b(is)g(a)f(BIOS)h(limitation,)h
+(not)f(a)f(k)n(ernel)g(limitation.)35 b(It)24 b(is)e(useful)i(here)e
+(to)h(distinguish)g(b)r(et)n(w)n(een)g(\020b)r(o)r(ot-able\021)0
+1323 y(devices)g(\(i.e.,)i(devices)e(that)h(can)f(b)r(e)i(b)r(o)r
+(oted\),)f(and)g(\020ro)r(ot-able\021)k(devices)23 b(\(i.e.,)i(devices)
+f(that)g(can)f(b)r(e)h(moun)n(ted)g(as)f(ro)r(ot\).)0
+1437 y(\020Bo)r(ot-able\021)33 b(devices)27 b(are)f(determined)i(b)n(y)
+f(the)i(BIOS,)e(and)g(are)g(generally)f(limited)i(to)g(in)n(ternal)f
+(\035opp)n(y)g(and)g(hard)g(disk)0 1550 y(driv)n(es.)57
+b(\020Ro)r(ot-able\021)39 b(devices)34 b(are)g(an)n(y)g(blo)r(c)n(k)g
+(devices)g(that)h(the)f(k)n(ernel)g(supp)r(orts)g(once)g(it)h(has)f(b)r
+(een)h(loaded.)57 b(The)0 1664 y(initrd)28 b(facilit)n(y)f(mak)n(es)g
+(more)f(devices)h(\020ro)r(ot-able\021,)f(not)h(\020b)r(o)r
+(ot-able\021.)0 1820 y(Some)40 b(Lin)n(ux)f(distributions)h(will)g
+(allo)n(w)f(installation)g(to)h(a)f(device)h(connected)g(to)f(a)h
+(PCMCIA)h(SCSI)f(adapter,)i(as)0 1934 y(an)c(unin)n(tended)g
+(side-e\033ect)g(of)g(their)g(supp)r(ort)g(for)f(installs)h(from)f
+(PCMCIA)i(SCSI)f(CD-R)n(OM)g(devices.)67 b(Ho)n(w)n(ev)n(er,)0
+2048 y(at)37 b(presen)n(t,)i(no)e(Lin)n(ux)g(installation)f(to)r(ols)h
+(supp)r(ort)f(con\034guring)g(an)h(appropriate)e(\020initrd\021)44
+b(to)37 b(b)r(o)r(ot)g(Lin)n(ux)g(with)g(a)0 2161 y(PCMCIA)e(ro)r(ot)f
+(\034lesystem.)58 b(Setting)35 b(up)g(a)f(system)g(with)h(a)f(PCMCIA)i
+(ro)r(ot)d(th)n(us)i(requires)e(that)i(y)n(ou)f(use)g(another)0
+2275 y(Lin)n(ux)d(system)f(to)h(create)f(the)i(\020initrd\021)37
+b(image.)47 b(If)31 b(another)f(Lin)n(ux)h(system)f(is)h(not)g(a)n(v)-5
+b(ailable,)31 b(another)f(option)h(w)n(ould)0 2388 y(b)r(e)d(to)g(temp)
+r(orarily)f(install)h(a)g(minimal)g(Lin)n(ux)g(setup)g(on)g(a)g
+(non-PCMCIA)g(driv)n(e,)f(create)g(an)h(initrd)g(image,)g(and)g(then)0
+2502 y(reinstall)f(to)g(the)h(PCMCIA)h(target.)0 2658
+y(The)j(Lin)n(ux)f(Bo)r(otdisk-HO)n(WTO)f(has)h(some)g(general)f
+(information)h(ab)r(out)h(setting)g(up)g(b)r(o)r(ot)f(disks)h(but)g
+(nothing)f(sp)r(e-)0 2772 y(ci\034c)42 b(to)h(initrd.)81
+b(The)42 b(main)g(initrd)h(do)r(cumen)n(t)f(is)g(included)h(with)g
+(recen)n(t)f(k)n(ernel)f(source)g(co)r(de)h(distributions,)k(in)0
+2886 y Fh(linux/Documentat)o(io)o(n/i)o(ni)o(tr)o(d.t)o(xt)o
+Fm(.)38 b(Before)29 b(b)r(eginning,)h(y)n(ou)g(should)f(read)g(this)h
+(do)r(cumen)n(t.)44 b(A)31 b(familiarit)n(y)e(with)0
+2999 y Fh(lilo)f Fm(is)h(also)g(helpful.)43 b(Using)29
+b(initrd)h(also)f(requires)f(that)i(y)n(ou)e(ha)n(v)n(e)h(a)g(k)n
+(ernel)f(compiled)i(with)g Fh(CONFIG_BLK_DEV_)o(RA)o(M)0
+3113 y Fm(and)d Fh(CONFIG_BLK_DEV_IN)o(IT)o(RD)21 b Fm(enabled.)0
+3269 y(This)36 b(is)f(an)h(adv)-5 b(anced)35 b(con\034guration)f(tec)n
+(hnique,)k(and)e(requires)e(a)i(high)f(lev)n(el)h(of)f(familiarit)n(y)g
+(with)i(Lin)n(ux)e(and)h(the)0 3383 y(PCMCIA)j(system.)68
+b(Be)38 b(sure)f(to)h(read)g(all)f(the)i(relev)-5 b(an)n(t)37
+b(do)r(cumen)n(tation)h(b)r(efore)g(starting.)67 b(The)38
+b(follo)n(wing)f(co)r(ok-)0 3496 y(b)r(o)r(ok)f(instructions)g(should)g
+(w)n(ork,)i(but)f(deviations)e(from)i(the)g(examples)e(will)i(quic)n
+(kly)f(put)h(y)n(ou)f(in)g(unc)n(harted)g(and)0 3610
+y(\020unsupp)r(orted\021)e(territory)-7 b(,)26 b(and)h(y)n(ou)g(will)h
+(b)r(e)g(on)f(y)n(our)f(o)n(wn.)0 3766 y(This)32 b(metho)r(d)g
+(absolutely)f(requires)f(that)i(y)n(ou)f(use)h(a)f(PCMCIA)i(driv)n(er)d
+(release)h(of)g(2.9.5)g(or)g(later.)48 b(Older)31 b(PCMCIA)0
+3880 y(pac)n(k)-5 b(ages)20 b(or)g(individual)i(comp)r(onen)n(ts)f
+(will)h(not)f(w)n(ork)f(in)i(the)g(initrd)g(con)n(text.)34
+b(Do)22 b(not)f(mix)h(comp)r(onen)n(ts)f(from)g(di\033eren)n(t)0
+3993 y(releases.)0 4263 y Ff(5.3.1)94 b(The)32 b(p)s(cinitrd)f(help)s
+(er)g(script)0 4473 y Fm(The)i Fh(pcinitrd)d Fm(script)i(creates)g(a)g
+(basic)h(initrd)g(image)f(for)g(b)r(o)r(oting)h(with)g(a)g(PCMCIA)g(ro)
+r(ot)g(partition.)52 b(The)33 b(image)0 4586 y(includes)e(a)g(minimal)g
+(directory)e(heirarc)n(h)n(y)-7 b(,)30 b(a)h(handful)g(of)g(device)g
+(\034les,)h(a)e(few)h(binaries,)g(shared)f(libraries,)h(and)g(a)f(set)0
+4700 y(of)d(PCMCIA)h(driv)n(er)e(mo)r(dules.)37 b(When)28
+b(in)n(v)n(oking)d Fh(pcinitrd)p Fm(,)f(y)n(ou)j(sp)r(ecify)g(the)h
+(driv)n(er)e(mo)r(dules)h(that)h(y)n(ou)e(w)n(an)n(t)h(to)g(b)r(e)0
+4813 y(included)h(in)g(the)g(image.)36 b(The)27 b(core)g(PCMCIA)h(comp)
+r(onen)n(ts,)f Fh(pcmcia_core)c Fm(and)28 b Fh(ds)p Fm(,)f(are)f
+(automatically)h(included.)0 4970 y(As)f(an)f(example,)h(sa)n(y)e(that)
+i(y)n(our)f(laptop)g(uses)h(an)f(i82365-compatible)e(host)i(con)n
+(troller,)f(and)i(y)n(ou)f(w)n(an)n(t)g(to)h(b)r(o)r(ot)f(Lin)n(ux)0
+5083 y(with)34 b(the)f(ro)r(ot)g(\034lesystem)g(on)g(a)g(hard)f(driv)n
+(e)g(attac)n(hed)h(to)g(an)g(A)n(daptec)g(SlimSCSI)h(adapter.)53
+b(Y)-7 b(ou)33 b(could)g(create)f(an)0 5197 y(appropriate)26
+b(initrd)i(image)e(with:)208 5407 y Fc(pcinitrd)41 b(-v)e(initrd)i
+(pcmcia/i82365.o)h(pcmcia/aha152x_cs.o)p eop
+%%Page: 41 41
+41 40 bop 0 -167 3900 5 v 0 -200 a Ff(5.)73 b(A)m(dv)-5
+b(anced)34 b(topics)2985 b Fm(41)0 162 y(T)-7 b(o)33
+b(customize)f(the)i(initrd)f(startup)g(sequence,)h(y)n(ou)e(could)h
+(moun)n(t)g(the)g(image)f(using)h(the)g(\020lo)r(opbac)n(k\021)38
+b(device)33 b(with)g(a)0 275 y(command)27 b(lik)n(e:)208
+502 y Fc(mount)40 b(-o)g(loop)g(-t)f(ext2)h(initrd)h(/mnt)0
+739 y Fm(and)26 b(then)h(edit)f(the)h Fh(linuxrc)c Fm(script.)36
+b(The)26 b(con\034guration)f(\034les)h(will)g(b)r(e)h(installed)f
+(under)g Fh(/etc)f Fm(in)h(the)h(image,)e(and)h(can)0
+852 y(also)g(b)r(e)i(customized.)37 b(See)28 b(the)g(man)f(page)g(for)g
+Fh(pcinitrd)d Fm(for)j(more)g(information.)0 1124 y Ff(5.3.2)94
+b(Creating)31 b(an)i(initrd)e(b)s(o)s(ot)g(\035opp)m(y)0
+1334 y Fm(After)26 b(creating)f(an)g(image)g(with)i Fh(pcinitrd)p
+Fm(,)c(y)n(ou)i(can)g(create)g(a)g(b)r(o)r(ot)h(\035opp)n(y)g(b)n(y)f
+(cop)n(ying)g(the)h(k)n(ernel,)f(the)h(compressed)0 1448
+y(initrd)31 b(image,)f(and)g(a)g(few)h(supp)r(ort)f(\034les)g(for)g
+Fh(lilo)e Fm(to)j(a)f(clean)g(\035opp)n(y)-7 b(.)44 b(In)31
+b(the)f(follo)n(wing)g(example,)g(w)n(e)g(assume)g(that)0
+1561 y(the)e(desired)f(PCMCIA)h(ro)r(ot)f(device)g(is)h
+Fh(/dev/sda1)p Fm(:)208 1788 y Fc(mke2fs)40 b(/dev/fd0)208
+1892 y(mount)g(/dev/fd0)h(/mnt)208 1997 y(mkdir)f(/mnt/etc)h(/mnt/boot)
+g(/mnt/dev)208 2101 y(cp)e(-a)h(/dev/fd0)h(/dev/sda1)g(/mnt/dev)208
+2205 y(cp)e([kernel-image])j(/mnt/vmlinuz)208 2309 y(cp)d(/boot/boot.b)
+j(/mnt/boot/boot.b)208 2413 y(gzip)e(<)f([initrd-image])j(>)e
+(/mnt/initrd)0 2649 y Fm(Create)27 b Fh(/mnt/etc/lilo.c)o(on)o(f)22
+b Fm(with)28 b(the)g(con)n(ten)n(ts:)208 2876 y Fc(boot=/dev/fd0)208
+2980 y(compact)208 3085 y(image=/vmlinuz)364 3189 y(label=linux)364
+3293 y(initrd=/initrd)364 3397 y(read-only)364 3501 y(root=/dev/sda1)0
+3737 y Fm(Finally)-7 b(,)28 b(in)n(v)n(ok)n(e)d(lilo)j(with:)208
+3964 y Fc(lilo)40 b(-r)f(/mnt)0 4201 y Fm(When)28 b Fh(lilo)d
+Fm(is)i(in)n(v)n(ok)n(ed)f(with)h Fh(-r)p Fm(,)g(it)g(p)r(erforms)f
+(all)h(actions)g(relativ)n(e)e(to)i(the)h(sp)r(eci\034ed)f(alternate)f
+(ro)r(ot)h(directory)-7 b(.)35 b(The)0 4314 y(reason)29
+b(for)h(creating)g(the)h(device)g(\034les)f(under)h Fh(/mnt/dev)c
+Fm(w)n(as)j(that)h Fh(lilo)e Fm(will)i(not)g(b)r(e)g(able)g(to)f(use)h
+(the)g(\034les)g(in)g Fh(/dev)0 4428 y Fm(when)d(it)g(is)f(running)g
+(in)h(this)g(alternate-ro)r(ot)e(mo)r(de.)0 4700 y Ff(5.3.3)94
+b(Installing)30 b(an)i(initrd)g(image)e(on)h(a)h(non-Lin)m(ux)g(driv)m
+(e)0 4910 y Fm(One)h(common)g(use)g(of)h(the)g(initrd)f(facilit)n(y)h
+(w)n(ould)f(b)r(e)g(on)h(systems)f(where)f(the)i(in)n(ternal)f(hard)g
+(driv)n(e)f(is)i(dedicated)f(to)0 5024 y(another)c(op)r(erating)g
+(system.)43 b(The)30 b(Lin)n(ux)g(k)n(ernel)f(and)h(initrd)g(image)f
+(can)h(b)r(e)g(placed)f(in)i(a)e(non-Lin)n(ux)g(partition,)h(and)0
+5137 y Fh(lilo)c Fm(or)h Fh(LOADLIN)d Fm(can)k(b)r(e)f(set)h(up)g(to)f
+(b)r(o)r(ot)h(Lin)n(ux)f(from)h(these)f(images.)0 5294
+y(Assuming)j(that)g(y)n(ou)f(ha)n(v)n(e)g(a)h(k)n(ernel)f(has)g(b)r
+(een)i(con\034gured)d(for)i(the)g(appropriate)e(ro)r(ot)i(device,)g
+(and)g(an)g(initrd)g(image)0 5407 y(created)d(on)g(another)g(system,)g
+(the)h(easiest)f(w)n(a)n(y)f(to)h(get)h(started)f(is)g(to)h(b)r(o)r(ot)
+f(Lin)n(ux)h(using)f Fh(LOADLIN)p Fm(,)e(as:)p eop
+%%Page: 42 42
+42 41 bop 0 -167 3900 5 v 0 -200 a Ff(6.)73 b(Dealing)31
+b(with)h(unsupp)s(orted)f(cards)2326 b Fm(42)208 162
+y Fc(LOADLIN)40 b(<kernel>)h(initrd=<initrd-image>)0
+401 y Fm(Once)21 b(y)n(ou)f(can)h(b)r(o)r(ot)g(Lin)n(ux)g(on)g(y)n(our)
+f(target)g(mac)n(hine,)i(y)n(ou)e(could)h(then)h(install)f
+Fh(lilo)e Fm(to)i(allo)n(w)f(b)r(o)r(oting)h(Lin)n(ux)g(directly)-7
+b(.)0 515 y(F)g(or)26 b(example,)g(sa)n(y)g(that)h Fh(/dev/hda1)c
+Fm(is)j(the)h(non-Lin)n(ux)f(target)g(partition)g(and)g
+Fh(/mnt)f Fm(can)h(b)r(e)i(used)e(as)g(a)g(moun)n(t)h(p)r(oin)n(t.)0
+628 y(First,)g(create)g(a)g(sub)r(directory)g(on)g(the)h(target)f(for)g
+(the)h(Lin)n(ux)f(\034les:)208 858 y Fc(mount)40 b(/dev/hda1)h(/mnt)208
+962 y(mkdir)f(/mnt/linux)208 1067 y(cp)f([kernel-image])j
+(/mnt/linux/vmlinuz)208 1171 y(cp)d([initrd-image])j(/mnt/linux/initrd)
+0 1410 y Fm(In)30 b(this)h(example,)g(sa)n(y)e(that)h
+Fh(/dev/sda1)d Fm(is)j(the)g(desired)g(Lin)n(ux)g(ro)r(ot)g(partition,)
+g(a)g(SCSI)h(hard)e(driv)n(e)h(moun)n(ted)g(via)f(a)0
+1524 y(PCMCIA)f(SCSI)g(adapter.)36 b(T)-7 b(o)27 b(install)h
+Fh(lilo)p Fm(,)e(create)g(a)h Fh(lilo.conf)d Fm(\034le)k(with)g(the)g
+(con)n(ten)n(ts:)208 1754 y Fc(boot=/dev/hda)208 1858
+y(map=/mnt/linux/map)208 1962 y(compact)208 2066 y
+(image=/mnt/linux/vmlinuz)521 2170 y(label=linux)521
+2274 y(root=/dev/sda1)521 2378 y(initrd=/mnt/linux/initrd)521
+2483 y(read-only)208 2587 y(other=/dev/hda1)521 2691
+y(table=/dev/hda)521 2795 y(label=windows)0 3034 y Fm(The)g
+Fh(boot=)e Fm(line)i(sa)n(ys)f(to)h(install)g(the)g(b)r(o)r(ot)g
+(loader)f(in)h(the)h(master)e(b)r(o)r(ot)h(record)e(of)i(the)h(sp)r
+(eci\034ed)f(device.)38 b(The)28 b Fh(root=)0 3148 y
+Fm(line)g(iden)n(ti\034es)f(the)h(desired)f(ro)r(ot)f(\034lesystem)h
+(to)h(b)r(e)f(used)h(after)f(loading)f(the)i(initrd)f(image,)g(and)g
+(ma)n(y)g(b)r(e)h(unnecessary)0 3262 y(if)c(the)g(k)n(ernel)e(image)h
+(is)g(already)f(con\034gured)g(this)i(w)n(a)n(y)-7 b(.)34
+b(The)23 b Fh(other=)e Fm(section)i(is)g(used)h(to)f(describ)r(e)g(the)
+g(other)g(op)r(erating)0 3375 y(system)k(installed)h(on)f
+Fh(/dev/hda1)p Fm(.)0 3532 y(T)-7 b(o)27 b(install)h
+Fh(lilo)e Fm(in)h(this)h(case,)f(use:)208 3762 y Fc(lilo)40
+b(-C)f(lilo.conf)0 4001 y Fm(Note)29 b(that)h(in)f(this)h(case,)f(the)g
+Fh(lilo.conf)d Fm(\034le)j(uses)g(absolute)g(paths)g(that)g(include)h
+Fh(/mnt)p Fm(.)40 b(I)29 b(did)h(this)f(in)h(the)g(example)0
+4115 y(b)r(ecause)i(the)h(target)f(\034lesystem)g(ma)n(y)g(not)g(supp)r
+(ort)h(the)f(creation)g(of)g(Lin)n(ux)h(device)f(\034les)g(for)g(the)h
+Fh(boot=)e Fm(and)h Fh(root=)0 4228 y Fm(options.)0 4567
+y Fg(6)131 b(Dealing)44 b(with)h(unsupp)t(orted)e(cards)0
+4824 y Fe(6.1)112 b(Con\034guring)37 b(unrecognized)h(cards)0
+5034 y Fm(Assuming)28 b(that)g(y)n(our)e(card)h(is)g(supp)r(orted)h(b)n
+(y)f(an)h(existing)f(driv)n(er,)g(all)g(that)h(needs)g(to)f(b)r(e)h
+(done)g(is)f(to)h(add)g(an)f(en)n(try)g(to)0 5148 y Fh
+(/etc/pcmcia/conf)o(ig)21 b Fm(to)28 b(tell)g Fh(cardmgr)c
+Fm(ho)n(w)j(to)h(iden)n(tify)g(the)g(card,)f(and)g(whic)n(h)h(driv)n
+(er\(s\))e(need)i(to)g(b)r(e)g(link)n(ed)f(up)h(to)0
+5261 y(this)i(card.)43 b(Chec)n(k)29 b(the)i(man)e(page)g(for)h
+Fh(pcmcia)d Fm(for)i(more)h(information)f(ab)r(out)g(the)i(con\034g)e
+(\034le)h(format.)43 b(If)30 b(y)n(ou)f(insert)0 5375
+y(an)g(unkno)n(wn)f(card,)g Fh(cardmgr)e Fm(will)j(normally)f(record)f
+(some)h(iden)n(ti\034cation)h(information)f(in)h(the)g(system)f(log)g
+(that)h(can)p eop
+%%Page: 43 43
+43 42 bop 0 -167 3900 5 v 0 -200 a Ff(6.)73 b(Dealing)31
+b(with)h(unsupp)s(orted)f(cards)2326 b Fm(43)0 162 y(b)r(e)34
+b(used)g(to)f(construct)h(the)g(con\034g)f(en)n(try)-7
+b(.)55 b(This)33 b(information)g(can)h(also)e(b)r(e)i(displa)n(y)n(ed)f
+(with)h(the)g(\020)7 b Fh(cardctl)41 b(ident)p Fm(\021)0
+275 y(command.)0 432 y(Here)27 b(is)h(an)f(example)g(of)h(ho)n(w)e
+(cardmgr)g(will)i(rep)r(ort)f(an)g(unsupp)r(orted)h(card)e(in)i
+Fh(/usr/adm/message)o(s)p Fm(.)208 662 y Fc(cardmgr[460]:)42
+b(unsupported)f(card)f(in)g(socket)h(1)208 766 y(cardmgr[460]:)h
+(product)e(info:)h("MEGAHERTZ",)h("XJ2288",)f("V.34)f(PCMCIA)h(MODEM")
+208 870 y(cardmgr[460]:)h(manfid:)e(0x0101,)h(0x1234)80
+b(function:)41 b(2)e(\(serial\))0 1109 y Fm(The)28 b(corresp)r(onding)d
+(en)n(try)i(in)h Fh(/etc/pcmcia/conf)o(ig)21 b Fm(w)n(ould)27
+b(b)r(e:)208 1339 y Fc(card)40 b("Megahertz)h(XJ2288)g(V.34)f(Fax)g
+(Modem")286 1444 y(version)h("MEGAHERTZ",)h("XJ2288",)f("V.34)f(PCMCIA)
+h(MODEM")286 1548 y(bind)f("serial_cs")0 1787 y Fm(or)27
+b(using)g(the)h(more)f(compact)g(pro)r(duct)g(ID)h(co)r(des:)208
+2017 y Fc(card)40 b("Megahertz)h(XJ2288)g(V.34)f(Fax)g(Modem")286
+2121 y(manfid)h(0x0101,)f(0x1234)286 2225 y(bind)g("serial_cs")0
+2465 y Fm(Y)-7 b(ou)25 b(can)g(use)g(\020*\021)31 b(to)24
+b(matc)n(h)h(strings)f(that)i(don't)f(need)g(to)g(matc)n(h)g(exactly)-7
+b(,)25 b(lik)n(e)f(v)n(ersion)g(n)n(um)n(b)r(ers.)35
+b(When)26 b(making)e(new)0 2579 y(con\034g)g(en)n(tries,)h(b)r(e)g
+(careful)g(to)g(cop)n(y)f(the)h(strings)f(exactly)-7
+b(,)25 b(preserving)e(case)i(and)f(blank)h(spaces.)35
+b(Also)25 b(b)r(e)g(sure)f(that)i(the)0 2692 y(con\034g)h(en)n(try)g
+(has)g(the)h(same)f(n)n(um)n(b)r(er)g(of)g(strings)g(as)g(are)g(rep)r
+(orted)f(in)i(the)g(log)f(\034le.)0 2849 y(Bew)n(are)c(that)i(y)n(ou)f
+(can)h(sp)r(ecify)g(just)g(ab)r(out)g(an)n(y)f(driv)n(er)f(for)h(a)h
+(card,)f(but)i(if)f(y)n(ou're)f(just)h(sho)r(oting)f(in)h(the)g(dark,)g
+(there)f(is)0 2962 y(not)g(m)n(uc)n(h)g(reason)f(to)h(exp)r(ect)h(this)
+f(to)g(b)r(e)h(pro)r(ductiv)n(e.)35 b(Y)-7 b(ou)24 b(ma)n(y)g(get)g
+(luc)n(ky)g(and)g(\034nd)g(that)h(y)n(our)e(card)g(is)h(supp)r(orted)g
+(b)n(y)0 3076 y(an)c(existing)h(driv)n(er.)33 b(Ho)n(w)n(ev)n(er,)20
+b(the)h(most)f(lik)n(ely)g(outcome)h(is)f(that)h(the)g(driv)n(er)e(w)n
+(on't)i(w)n(ork,)f(and)h(ma)n(y)f(ha)n(v)n(e)f(unfortunate)0
+3189 y(side)24 b(e\033ects)h(lik)n(e)f(lo)r(c)n(king)f(up)h(y)n(our)f
+(system.)36 b(Unlik)n(e)24 b(most)g(ordinary)f(device)h(driv)n(ers,)f
+(whic)n(h)h(prob)r(e)g(for)g(an)g(appropriate)0 3303
+y(card,)i(the)g(prob)r(e)g(for)g(a)g(PCMCIA)h(device)f(is)g(done)g(b)n
+(y)g Fh(cardmgr)p Fm(,)e(and)i(the)h(driv)n(er)e(itself)i(ma)n(y)e(not)
+i(do)f(m)n(uc)n(h)g(v)-5 b(alidation)0 3416 y(b)r(efore)27
+b(attempting)h(to)g(comm)n(unicate)e(with)j(the)e(device.)0
+3573 y(After)h(editing)g Fh(/etc/pcmcia/con)o(fi)o(g)p
+Fm(,)22 b(y)n(ou)27 b(can)g(signal)f Fh(cardmgr)f Fm(to)i(reload)g(the)
+h(\034le)f(with:)208 3803 y Fc(kill)40 b(-HUP)g(`cat)g
+(/var/run/cardmgr.pid`)0 4042 y Fm(If)34 b(y)n(ou)e(do)h(set)h(up)f(an)
+g(en)n(try)g(for)g(a)f(new)i(card,)g(please)e(send)h(me)h(a)f(cop)n(y)f
+(so)h(that)g(I)h(can)f(include)g(it)h(in)f(the)h(standard)0
+4156 y(con\034g)27 b(\034le.)0 4448 y Fe(6.2)112 b(A)m(dding)37
+b(supp)s(ort)h(for)f(an)h(NE2000-compatible)d(ethernet)i(card)0
+4658 y Fm(Before)28 b(y)n(ou)h(b)r(egin:)40 b(this)30
+b(pro)r(cedure)e(will)h(only)g(w)n(ork)f(for)h(simple)g(ethernet)g
+(cards.)41 b(Multifunction)30 b(cards)e(\(i.e.,)j(ether-)0
+4771 y(net/mo)r(dem)26 b(com)n(b)r(o)f(cards\))f(ha)n(v)n(e)h(an)g
+(extra)g(la)n(y)n(er)f(of)h(complexit)n(y)g(regarding)f(ho)n(w)h(the)h
+(t)n(w)n(o)f(functions)g(are)g(in)n(tegrated,)0 4885
+y(and)h(generally)e(cannot)i(b)r(e)g(supp)r(orted)g(without)h
+(obtaining)e(some)g(con\034guration)g(information)g(from)h(the)g(card)f
+(v)n(endor.)0 4998 y(Using)i(the)h(follo)n(wing)f(pro)r(cedure)f(for)h
+(a)g(m)n(ultifunction)i(card)e(will)g(not)h(b)r(e)g(pro)r(ductiv)n(e.)0
+5155 y(First,)40 b(see)c(if)i(the)g(card)e(is)h(already)f(recognized)g
+(b)n(y)h Fh(cardmgr)p Fm(.)63 b(Some)37 b(cards)f(not)h(listed)h(in)f
+Fh(SUPPORTED.CARDS)31 b Fm(are)0 5268 y(actually)c(OEM)g(v)n(ersions)f
+(of)h(cards)f(that)i(are)e(supp)r(orted.)37 b(If)28 b(y)n(ou)e(\034nd)i
+(a)f(card)g(lik)n(e)g(this,)g(let)h(me)g(kno)n(w)e(so)h(I)g(can)g(add)h
+(it)0 5382 y(to)f(the)h(list.)p eop
+%%Page: 44 44
+44 43 bop 0 -167 3900 5 v 0 -200 a Ff(6.)73 b(Dealing)31
+b(with)h(unsupp)s(orted)f(cards)2326 b Fm(44)0 162 y(If)27
+b(y)n(our)f(card)g(is)h(not)g(recognized,)f(follo)n(w)g(the)h
+(instructions)f(in)i(the)f(6.1)f(\(Con\034guring)g(unrecognized)g
+(cards\))g(section)g(to)0 275 y(create)j(a)g(con\034g)g(en)n(try)g(for)
+g(y)n(our)f(card,)i(and)f(bind)h(the)g(card)f(to)h(the)g
+Fh(pcnet_cs)c Fm(driv)n(er.)42 b(Restart)29 b Fh(cardmgr)e
+Fm(to)i(use)h(the)0 389 y(up)r(dated)e(con\034g)f(\034le.)0
+545 y(If)i(the)f Fh(pcnet_cs)d Fm(driv)n(er)i(sa)n(ys)g(that)i(it)f(is)
+h(unable)f(to)g(determine)g(y)n(our)f(card's)g(hardw)n(are)f(ethernet)j
+(address,)e(then)i(edit)0 659 y(y)n(our)e(new)h(con\034g)f(en)n(try)h
+(to)g(bind)g(the)h(card)e(to)h(the)g(memory)f(card)h(driv)n(er,)f
+Fh(memory_cs)p Fm(.)34 b(Restart)28 b Fh(cardmgr)d Fm(to)j(use)g(the)0
+772 y(new)k(up)r(dated)h(con\034g)f(\034le.)51 b(Y)-7
+b(ou)32 b(will)h(need)f(to)h(kno)n(w)e(y)n(our)g(card's)g(hardw)n(are)g
+(ethernet)h(address.)50 b(This)32 b(address)f(is)h(a)0
+886 y(series)24 b(of)i(six)f(t)n(w)n(o-digit)f(hex)i(n)n(um)n(b)r(ers,)
+f(often)h(prin)n(ted)f(on)g(the)h(card)f(itself.)36 b(If)26
+b(it)g(is)f(not)h(prin)n(ted)f(on)g(the)h(card,)f(y)n(ou)g(ma)n(y)0
+1000 y(b)r(e)j(able)f(to)h(use)f(a)g(DOS)h(driv)n(er)e(to)i(displa)n(y)
+e(the)i(address.)36 b(In)28 b(an)n(y)e(case,)h(once)g(y)n(ou)g(kno)n(w)
+g(it,)h(run:)208 1230 y Fc(dd)39 b(if=/dev/mem0a)j(count=20)f(|)f(od)f
+(-Ax)h(-t)g(x1)0 1469 y Fm(and)34 b(searc)n(h)e(the)j(output)f(for)g(y)
+n(our)f(address.)55 b(Only)33 b(the)i(ev)n(en)e(b)n(ytes)h(are)f
+(de\034ned,)j(so)d(ignore)g(the)i(o)r(dd)f(b)n(ytes)f(in)i(the)0
+1583 y(dump.)43 b(Record)29 b(the)h(hex)f(o\033set)g(of)h(the)g
+(\034rst)f(b)n(yte)g(of)h(the)g(address.)41 b(No)n(w,)30
+b(edit)g Fh(clients/pcnet_c)o(s.)o(c)23 b Fm(and)30 b(\034nd)g(the)0
+1696 y Fh(hw_info)g Fm(structure.)54 b(Y)-7 b(ou'll)33
+b(need)h(to)f(create)f(a)h(new)g(en)n(try)g(for)g(y)n(our)f(card.)53
+b(The)33 b(\034rst)g(\034eld)h(is)f(the)h(memory)e(o\033set.)0
+1810 y(The)f(next)h(three)f(\034elds)h(are)e(the)i(\034rst)f(three)g(b)
+n(ytes)g(of)g(the)h(hardw)n(are)e(address.)47 b(The)31
+b(\034nal)g(\034eld)h(con)n(tains)e(some)h(\035ags)0
+1923 y(for)c(sp)r(eci\034c)h(card)e(features;)h(to)h(start,)f(try)g
+(setting)h(it)g(to)f(0.)0 2080 y(After)21 b(editing)g
+Fh(pcnet_cs.c)p Fm(,)c(compile)k(and)f(install)g(the)h(new)g(mo)r
+(dule.)35 b(Edit)21 b Fh(/etc/pcmcia/conf)o(ig)14 b Fm(again,)21
+b(and)f(c)n(hange)0 2193 y(the)26 b(card)f(binding)h(from)f
+Fh(memory_cs)d Fm(to)k Fh(pcnet_cs)p Fm(.)33 b(F)-7 b(ollo)n(w)25
+b(the)h(instructions)f(for)g(reloading)f(the)i(con\034g)f(\034le,)h
+(and)g(y)n(ou)0 2307 y(should)h(b)r(e)h(all)g(set.)36
+b(Please)28 b(send)f(me)h(copies)f(of)g(y)n(our)g(new)g
+Fh(hw_info)e Fm(and)i(con\034g)g(en)n(tries.)0 2464 y(If)h(y)n(ou)g
+(can't)g(\034nd)g(y)n(our)f(card's)g(hardw)n(are)f(address)g(in)i(the)h
+(hex)f(dump,)h(as)e(a)g(metho)r(d)i(of)f(last)g(resort,)e(it)j(is)f(p)r
+(ossible)f(to)0 2577 y(\020hard-wire\021)k(the)c(address)e(when)h(the)h
+Fh(pcnet_cs)c Fm(mo)r(dule)k(is)f(initialized.)37 b(Edit)27
+b Fh(/etc/pcmcia/confi)o(g.)o(op)o(ts)20 b Fm(and)26
+b(add)0 2691 y(a)h Fh(hw_addr=)d Fm(option,)k(lik)n(e)f(so:)208
+2921 y Fc(module)40 b("pcnet_cs")h(opts)g
+("hw_addr=0x00,0x80,0xc8,0x01,0x0)q(2,0x0)q(3")0 3160
+y Fm(Substitute)24 b(y)n(our)d(o)n(wn)h(card's)g(hardw)n(are)e(address)
+i(in)h(the)g(appropriate)e(sp)r(ot,)i(of)g(course.)34
+b(Bew)n(are)21 b(that)i(if)g(y)n(ou'v)n(e)e(gotten)0
+3274 y(this)27 b(far,)g(it)g(is)g(v)n(ery)f(unlik)n(ely)h(that)g(y)n
+(our)f(card)g(is)h(gen)n(uinely)f(NE2000)g(compatible.)37
+b(In)27 b(fact,)g(I'm)g(not)g(sure)g(if)g(there)g(are)0
+3387 y Fa(any)35 b Fm(cards)27 b(that)h(are)e(not)i(handled)f(b)n(y)h
+(one)f(of)g(the)h(\034rst)g(t)n(w)n(o)e(metho)r(ds.)0
+3679 y Fe(6.3)112 b(PCMCIA)37 b(\035opp)m(y)h(in)m(terface)e(cards)0
+3889 y Fm(The)c(PCMCIA)h(\035opp)n(y)e(in)n(terface)g(used)h(in)g(the)g
+(Compaq)f(A)n(ero)g(and)h(a)g(few)g(other)f(laptops)g(is)h(not)g(y)n
+(et)g(supp)r(orted)f(b)n(y)0 4003 y(this)d(pac)n(k)-5
+b(age.)36 b(The)27 b(snag)g(in)h(supp)r(orting)f(the)h(A)n(ero)f
+(\035opp)n(y)g(is)h(that)g(the)g(A)n(ero)e(seems)h(to)h(use)g(a)f
+(customized)g(PCMCIA)0 4116 y(con)n(troller)e(to)i(supp)r(ort)f(DMA)i
+(to)f(the)g(\035opp)n(y)-7 b(.)36 b(Without)28 b(kno)n(wing)e(exactly)g
+(ho)n(w)g(this)h(is)g(done,)g(there)f(isn't)i(an)n(y)e(w)n(a)n(y)f(to)0
+4230 y(implemen)n(t)j(supp)r(ort)f(under)h(Lin)n(ux.)0
+4386 y(If)k(the)h(\035opp)n(y)e(adapter)g(card)g(is)h(presen)n(t)f
+(when)h(an)g(A)n(ero)f(is)g(b)r(o)r(oted,)i(the)g(A)n(ero)e(BIOS)g
+(will)h(con\034gure)f(the)h(card,)g(and)0 4500 y(Lin)n(ux)23
+b(will)h(iden)n(tify)g(it)g(as)e(a)h(normal)g(\035opp)n(y)g(driv)n(e.)
+34 b(When)24 b(the)g(Lin)n(ux)f(PCMCIA)h(driv)n(ers)e(are)g(loaded,)i
+(they)g(will)f(notice)0 4613 y(that)i(the)h(card)e(is)h(already)f
+(con\034gured)g(and)h(attac)n(hed)f(to)h(a)g(Lin)n(ux)g(driv)n(er,)f
+(and)h(this)g(so)r(c)n(k)n(et)f(will)i(b)r(e)f(left)h(alone.)35
+b(So,)26 b(the)0 4727 y(driv)n(e)h(can)g(b)r(e)h(used)f(if)h(it)g(is)g
+(presen)n(t)f(at)g(b)r(o)r(ot)h(time,)g(but)g(the)g(card)f(is)g(not)h
+(hot)f(sw)n(appable.)p eop
+%%Page: 45 45
+45 44 bop 0 -167 3900 5 v 0 -200 a Ff(7.)73 b(Debugging)31
+b(tips)g(and)h(programming)d(information)1741 b Fm(45)0
+162 y Fg(7)131 b(Debugging)43 b(tips)i(and)e(programming)h(information)
+0 419 y Fe(7.1)112 b(Submitting)35 b(useful)j(bug)g(rep)s(orts)0
+629 y Fm(The)20 b(b)r(est)h(w)n(a)n(y)d(to)i(submit)h(bug)f(rep)r(orts)
+f(is)h(to)f(use)h(the)h(Hyp)r(erNews)f(message)e(lists)i(on)g(the)g
+(Lin)n(ux)g(PCMCIA)h(information)0 743 y(site.)57 b(That)34
+b(w)n(a)n(y)-7 b(,)34 b(other)g(p)r(eople)g(can)g(see)g(curren)n(t)f
+(problems)g(\(and)i(\034xes)e(or)h(w)n(ork)-5 b(arounds,)33
+b(if)i(a)n(v)-5 b(ailable\).)55 b(Here)34 b(are)0 857
+y(some)27 b(things)g(that)h(should)g(b)r(e)g(included)g(in)f(all)h(bug)
+f(rep)r(orts:)125 1083 y Fd(\017)41 b Fm(Y)-7 b(our)27
+b(system)g(brand)g(and)g(mo)r(del.)125 1257 y Fd(\017)41
+b Fm(What)27 b(PCMCIA)i(card\(s\))e(y)n(ou)g(are)f(using.)125
+1432 y Fd(\017)41 b Fm(Y)-7 b(our)27 b(Lin)n(ux)g(k)n(ernel)g(v)n
+(ersion)f(\(i.e.,)i(\020)7 b Fh(uname)41 b(-rv)p Fm(\021\),)26
+b(and)h(PCMCIA)i(driv)n(er)d(v)n(ersion)g(\(i.e.,)i(\020)7
+b Fh(cardctl)40 b(-V)p Fm(\021\).)125 1606 y Fd(\017)h
+Fm(An)n(y)27 b(c)n(hanges)f(y)n(ou)h(ha)n(v)n(e)f(made)i(to)f(the)h
+(startup)f(\034les)h(in)g Fh(/etc/pcmcia)p Fm(,)23 b(or)j(to)i(the)g
+(PCMCIA)g(startup)f(script.)125 1781 y Fd(\017)41 b Fm(All)29
+b(PCMCIA-related)f(messages)f(in)i(y)n(our)e(system)i(log)e(\034le.)41
+b(That)28 b(includes)h(startup)f(messages,)f(and)i(messages)208
+1895 y(generated)d(when)i(y)n(our)e(cards)g(are)h(con\034gured.)0
+2121 y(All)22 b(the)g(PCMCIA)g(mo)r(dules)g(and)f(the)h
+Fh(cardmgr)d Fm(daemon)i(send)g(status)h(messages)e(to)h(the)h(system)f
+(log.)34 b(This)22 b(will)g(usually)0 2234 y(b)r(e)33
+b(something)g(lik)n(e)g Fh(/var/log/messag)o(es)26 b
+Fm(or)33 b Fh(/usr/adm/messag)o(es)o Fm(.)48 b(This)33
+b(\034le)g(should)g(b)r(e)g(the)h(\034rst)e(place)h(to)g(lo)r(ok)0
+2348 y(when)27 b(trac)n(king)e(do)n(wn)h(a)g(problem.)36
+b(When)27 b(submitting)g(a)f(bug)g(rep)r(ort,)g(alw)n(a)n(ys)f(include)
+i(the)g(relev)-5 b(an)n(t)25 b(con)n(ten)n(ts)h(of)h(this)0
+2461 y(\034le.)42 b(If)30 b(y)n(ou)e(are)g(ha)n(ving)h(trouble)f
+(\034nding)i(y)n(our)e(system)h(messages,)f(c)n(hec)n(k)g
+Fh(/etc/syslog.conf)22 b Fm(to)30 b(see)e(ho)n(w)h(di\033eren)n(t)0
+2575 y(classes)d(of)i(messages)e(are)g(handled.)0 2732
+y(Before)34 b(submitting)i(a)e(bug)h(rep)r(ort,)h(please)e(c)n(hec)n(k)
+g(to)h(mak)n(e)f(sure)h(that)g(y)n(ou)f(are)g(using)h(an)f(up-to-date)h
+(cop)n(y)f(of)h(the)0 2845 y(driv)n(er)29 b(pac)n(k)-5
+b(age.)42 b(While)31 b(it)f(is)g(somewhat)g(gratifying)e(to)i(read)g
+(bug)f(rep)r(orts)g(for)h(things)g(I'v)n(e)f(already)g(\034xed,)i(it)f
+(isn't)g(a)0 2959 y(particularly)c(constructiv)n(e)g(use)i(of)f(m)n(y)h
+(time.)0 3115 y(If)21 b(y)n(ou)f(do)g(not)h(ha)n(v)n(e)e(w)n(eb)i
+(access,)f(bug)h(rep)r(orts)e(can)i(b)r(e)g(sen)n(t)f(to)g(me)h(at)g
+Fj(dhinds@pcmcia.s)o(our)o(ce)o(fo)o(rge)o(.o)o(rg)o
+Fm(.)29 b(Ho)n(w)n(ev)n(er,)0 3229 y(I)f(prefer)f(that)g(bug)h(rep)r
+(orts)e(b)r(e)i(p)r(osted)g(to)f(m)n(y)h(w)n(eb)f(site,)h(so)f(that)g
+(they)h(can)f(b)r(e)h(seen)g(b)n(y)f(others.)0 3518 y
+Fe(7.2)112 b(In)m(terpreting)36 b(k)m(ernel)h(trap)g(rep)s(orts)0
+3728 y Fm(If)23 b(y)n(our)e(problem)h(in)n(v)n(olv)n(es)f(a)h(k)n
+(ernel)g(fault,)i(the)f(register)e(dump)i(from)f(the)h(fault)g(is)f
+(only)g(useful)h(if)g(y)n(ou)f(can)g(translate)g(the)0
+3842 y(fault)29 b(address,)e(EIP)-7 b(,)29 b(to)f(something)g
+(meaningful.)38 b(Recen)n(t)29 b(v)n(ersions)d(of)i Fh(klogd)e
+Fm(attempt)j(to)f(translate)f(fault)i(addresses)0 3955
+y(based)24 b(on)h(the)h(curren)n(t)e(k)n(ernel)g(sym)n(b)r(ol)g(map,)i
+(but)f(this)h(ma)n(y)e(not)h(w)n(ork)f(if)h(the)h(fault)f(is)g(in)g(a)g
+(mo)r(dule,)h(or)e(if)h(the)h(problem)0 4069 y(is)h(sev)n(ere)g(enough)
+f(that)i Fh(klogd)e Fm(cannot)h(\034nish)h(writing)f(the)h(fault)g
+(information)f(to)g(the)h(system)f(log.)0 4225 y(If)34
+b(a)g(fault)g(is)g(in)g(the)h(main)f(k)n(ernel,)g(the)h(fault)f
+(address)f(can)g(b)r(e)i(lo)r(ok)n(ed)e(up)h(in)g(the)h
+Fh(System.map)29 b Fm(\034le.)57 b(This)33 b(ma)n(y)h(b)r(e)0
+4339 y(installed)29 b(in)g Fh(/System.map)c Fm(or)j Fh
+(/boot/System.map)o Fm(.)36 b(If)29 b(a)g(fault)g(is)g(in)h(a)e(mo)r
+(dule,)i(the)f Fh(nm)g Fm(command)f(giv)n(es)g(the)i(same)0
+4452 y(information,)j(ho)n(w)n(ev)n(er,)e(the)i(fault)f(address)f(has)h
+(to)g(b)r(e)h(adjusted)f(based)g(on)g(the)h(mo)r(dule's)f(load)f
+(address.)50 b(Let's)32 b(sa)n(y)0 4566 y(that)c(y)n(ou)f(ha)n(v)n(e)f
+(the)i(follo)n(wing)e(k)n(ernel)h(fault:)208 4783 y Fc(Unable)40
+b(to)g(handle)g(kernel)h(NULL)f(pointer)h(dereference)208
+4887 y(current->tss.cr3)h(=)e(014c9000,)h(\045cr3)f(=)f(014c9000)208
+4991 y(*pde)h(=)f(00000000)208 5095 y(Oops:)h(0002)208
+5199 y(CPU:)157 b(0)208 5303 y(EIP:)g(0010:[<c2026081>])208
+5407 y(EFLAGS:)40 b(00010282)p eop
+%%Page: 46 46
+46 45 bop 0 -167 3900 5 v 0 -200 a Ff(7.)73 b(Debugging)31
+b(tips)g(and)h(programming)d(information)1741 b Fm(46)0
+162 y(The)26 b(fault)h(address)e(is)h(0xc2026081.)33
+b(Lo)r(oking)25 b(at)h Fh(System.map)p Fm(,)c(w)n(e)k(see)g(that)h
+(this)g(is)f(past)g(the)h(end)f(of)g(the)h(k)n(ernel,)f(i.e.,)0
+275 y(is)h(in)h(a)f(k)n(ernel)g(mo)r(dule.)37 b(T)-7
+b(o)27 b(determine)h(whic)n(h)f(mo)r(dule,)h(c)n(hec)n(k)f(the)h
+(output)g(of)f(\020)7 b Fh(ksyms)42 b(-m)g Fd(j)i Fh(sort)p
+Fm(\021:)208 505 y Fc(Address)119 b(Symbol)1099 b(Defined)41
+b(by)208 609 y(c200d000)80 b(\(35k\))1138 b([pcmcia_core])208
+714 y(c200d10c)80 b(register_ss_entry)670 b([pcmcia_core])208
+818 y(c200d230)80 b(unregister_ss_entry)592 b([pcmcia_core])600
+922 y(...)208 1026 y(c2026000)80 b(\(9k\))1177 b([3c574_cs])208
+1130 y(c202a000)80 b(\(4k\))1177 b([serial_cs])0 1369
+y Fm(So,)29 b(0xc2026081)c(is)k(in)h(the)f Fh(3c574_cs)d
+Fm(mo)r(dule,)k(and)f(is)g(at)g(an)g(o\033set)g(of)g(0x0081)d(from)j
+(the)h(start)e(of)h(the)h(mo)r(dule.)42 b(W)-7 b(e)0
+1483 y(cannot)33 b(lo)r(ok)f(up)i(this)f(o\033set)g(in)h
+Fh(3c574_cs.o)29 b Fm(y)n(et:)47 b(when)34 b(the)f(k)n(ernel)g(loads)f
+(a)h(mo)r(dule,)h(it)g(inserts)f(a)f(header)h(at)g(the)0
+1597 y(mo)r(dule)21 b(load)g(address,)g(so)f(the)i(real)e(start)g(of)i
+(the)f(mo)r(dule)g(is)g(o\033set)g(from)g(the)h(address)d(sho)n(wn)i
+(in)g Fh(ksyms)p Fm(.)33 b(The)21 b(size)g(of)g(the)0
+1710 y(header)27 b(v)-5 b(aries)26 b(with)i(k)n(ernel)f(v)n(ersion:)36
+b(to)27 b(\034nd)h(out)g(the)g(size)f(for)g(y)n(our)g(k)n(ernel,)f(c)n
+(hec)n(k)h(a)g(mo)r(dule)h(that)g(exp)r(orts)f(sym)n(b)r(ols)0
+1824 y(\(lik)n(e)g Fh(pcmcia_core)22 b Fm(ab)r(o)n(v)n(e\),)k(and)h
+(compare)e(a)i(sym)n(b)r(ol)f(address)g(with)h Fh(nm)f
+Fm(output)i(for)e(that)h(sym)n(b)r(ol.)36 b(In)27 b(this)h(example,)0
+1937 y Fh(register_ss_entr)o(y)17 b Fm(is)23 b(loaded)f(at)h(an)f
+(o\033set)h(of)g(0xc200d10c)d(-)j(0xc200d000)c(=)k(0x010c,)e(while)j
+(\020)7 b Fh(nm)42 b(pcmcia_core.o)p Fm(\021)0 2051 y(sho)n(ws)26
+b(the)i(o\033set)g(as)f(0x00c0,)e(so)i(the)h(header)f(size)g(is)g
+(0x010c)f(-)h(0x00c0)e(=)j(0x004c)d(b)n(ytes.)0 2207
+y(Bac)n(k)30 b(to)h Fh(3c574_cs)p Fm(,)e(our)h(fault)i(o\033set)f(is)g
+(0x0081,)e(and)i(subtracting)f(the)i(0x004c)d(header,)i(the)h(real)e
+(mo)r(dule)h(o\033set)g(is)0 2321 y(0x0035.)j(No)n(w)27
+b(lo)r(oking)g(at)g(\020)7 b Fh(nm)43 b(3c574_cs.o)c
+Fd(j)44 b Fh(sort)p Fm(\021,)25 b(w)n(e)i(see:)208 2551
+y Fc(0000002c)41 b(d)e(if_names)208 2655 y(0000002c)i(t)e(tc574_attach)
+208 2759 y(00000040)i(d)e(mii_preamble_required)208 2863
+y(00000041)i(d)e(dev_info)0 3103 y Fm(So,)27 b(the)h(fault)g(is)g(lo)r
+(cated)f(in)h Fh(tc574_attach\(\))p Fm(.)0 3259 y(In)j(this)h(example,)
+g(the)f(fault)h(did)f(not)h(cause)e(a)h(total)g(system)g(lo)r(c)n(kup,)
+h(so)e Fh(ksyms)f Fm(could)i(b)r(e)h(executed)f(after)g(the)h(fault)0
+3373 y(happ)r(ened.)44 b(In)30 b(other)f(cases,)g(y)n(ou)g(ma)n(y)g(ha)
+n(v)n(e)g(to)h(infer)g(the)g(mo)r(dule)g(load)f(addresses)f(indirectly)
+-7 b(.)44 b(The)29 b(same)h(sequence)0 3486 y(of)e(ev)n(en)n(ts)f(will)
+h(normally)e(load)h(mo)r(dules)h(in)g(the)g(same)f(order)f(and)i(at)g
+(the)g(same)f(addresses.)36 b(If)28 b(a)f(fault)h(happ)r(ens)g(when)0
+3600 y(a)h(certain)f(card)g(is)h(inserted,)g(get)g(the)g
+Fh(ksyms)e Fm(output)i(b)r(efore)g(inserting)f(the)i(card,)e(or)g(with)
+i(a)e(di\033eren)n(t)h(card)f(inserted.)0 3714 y(Y)-7
+b(ou)26 b(can)f(also)g(man)n(ually)g(load)g(the)h(card's)f(driv)n(er)f
+(mo)r(dules)i(with)h Fh(insmod)c Fm(and)j(run)f Fh(ksyms)f
+Fm(b)r(efore)i(inserting)f(the)h(card.)0 3870 y(F)-7
+b(or)47 b(more)h(bac)n(kground,)j(see)c(\020)7 b Fh(man)42
+b(insmod)p Fm(\021,)51 b(\020)7 b Fh(man)42 b(ksyms)p
+Fm(\021,)50 b(and)e(\020)7 b Fh(man)42 b(klogd)p Fm(\021.)96
+b(In)48 b(the)h(k)n(ernel)e(source)f(tree,)0 3984 y Fh
+(Documentation/oo)o(ps)o(-tr)o(ac)o(in)o(g.t)o(xt)21
+b Fm(is)27 b(also)g(relev)-5 b(an)n(t.)36 b(Here)27 b(are)g(a)g(few)h
+(more)e(k)n(ernel)h(debugging)g(hin)n(ts:)125 4223 y
+Fd(\017)41 b Fm(Dep)r(ending)24 b(on)g(the)h(fault,)h(it)e(ma)n(y)g
+(also)f(b)r(e)i(useful)f(to)h(translate)e(addresses)g(in)h(the)h
+(\020Call)e(T)-7 b(race\021,)24 b(using)g(the)h(same)208
+4337 y(pro)r(cedure)h(as)h(for)g(the)h(main)f(fault)h(address.)125
+4517 y Fd(\017)41 b Fm(T)-7 b(o)30 b(diagnose)f(a)h(silen)n(t)g(lo)r(c)
+n(k-up,)g(try)h(to)f(pro)n(v)n(ok)n(e)e(the)i(problem)g(with)h(X)g
+(disabled,)g(since)f(k)n(ernel)g(messages)e(sen)n(t)208
+4630 y(to)f(the)h(text)g(console)e(will)i(not)g(b)r(e)g(visible)f
+(under)g(X.)125 4810 y Fd(\017)41 b Fm(If)36 b(y)n(ou)g(kill)h
+Fh(klogd)p Fm(,)g(most)f(k)n(ernel)f(messages)g(will)i(b)r(e)g(ec)n(ho)
+r(ed)f(directly)g(on)g(the)h(text)g(console,)h(whic)n(h)e(ma)n(y)g(b)r
+(e)208 4924 y(helpful)28 b(if)g(the)g(problem)f(prev)n(en)n(ts)f
+Fh(klogd)g Fm(from)h(writing)g(to)h(the)g(system)f(log.)125
+5104 y Fd(\017)41 b Fm(T)-7 b(o)30 b(cause)h(all)g(k)n(ernel)f
+(messages)f(to)i(b)r(e)h(sen)n(t)f(to)g(the)g(console,)g(for)g(2.1)f(k)
+n(ernels,)h(if)h Fh(/proc/sys/kerne)o(l/p)o(ri)o(nt)o(k)208
+5217 y Fm(exists,)27 b(do:)390 5388 y Fc(echo)40 b(8)g(>)f
+(/proc/sys/kernel/printk)p eop
+%%Page: 47 47
+47 46 bop 0 -167 3900 5 v 0 -200 a Ff(7.)73 b(Debugging)31
+b(tips)g(and)h(programming)d(information)1741 b Fm(47)125
+162 y Fd(\017)41 b Fm(The)23 b(k)n(ey)g(com)n(bination)g
+Fb(<)p Fm(Righ)n(tAlt)p Fb(><)p Fm(ScrLk)p Fb(>)f Fm(prin)n(ts)h(a)h
+(register)e(dump)j(on)e(the)h(text)g(console.)35 b(This)23
+b(ma)n(y)h(w)n(ork)208 275 y(ev)n(en)g(if)h(the)h(system)e(is)h
+(otherwise)f(completely)h(unresp)r(onsiv)n(e,)f(and)h(the)g(EIP)h
+(address)e(can)h(b)r(e)g(in)n(terpreted)f(as)h(for)208
+389 y(a)i(k)n(ernel)f(fault.)125 557 y Fd(\017)41 b Fm(F)-7
+b(or)28 b(2.1)h(k)n(ernels)f(con\034gured)g(with)i Fh(CONFIG_MAGIC_SYS)
+o(RQ)23 b Fm(enabled,)29 b(v)-5 b(arious)28 b(emergency)g(functions)i
+(are)e(a)n(v)-5 b(ail-)208 671 y(able)26 b(via)h(sp)r(ecial)g
+Fb(<)p Fm(Alt)p Fb(><)p Fm(SysRq)p Fb(>)f Fm(k)n(ey)g(com)n(binations,)
+h(do)r(cumen)n(ted)g(in)h Fh(Documentation/s)o(ys)o(rq.)o(tx)o(t)21
+b Fm(in)28 b(the)208 784 y(k)n(ernel)e(source)g(tree.)0
+1071 y Fe(7.3)112 b(Lo)m(w)38 b(lev)m(el)e(PCMCIA)g(debugging)i(aids)0
+1281 y Fm(The)30 b(PCMCIA)g(mo)r(dules)g(con)n(tain)f(a)g(lot)g(of)h
+(conditionally-compiled)e(debugging)h(co)r(de.)43 b(Most)29
+b(of)g(this)h(co)r(de)g(is)f(under)0 1395 y(con)n(trol)20
+b(of)h(the)h Fh(PCMCIA_DEBUG)16 b Fm(prepro)r(cessor)j(de\034ne.)35
+b(If)21 b(this)h(is)f(unde\034ned,)i(debugging)e(co)r(de)g(will)g(not)g
+(b)r(e)h(compiled.)35 b(If)0 1508 y(set)20 b(to)g(0,)h(the)f(co)r(de)g
+(is)g(compiled)f(but)i(inactiv)n(e.)34 b(Larger)17 b(n)n(um)n(b)r(ers)j
+(sp)r(ecify)g(increasing)e(lev)n(els)h(of)h(v)n(erb)r(osit)n(y)-7
+b(.)33 b(Eac)n(h)20 b(mo)r(dule)0 1622 y(built)32 b(with)g
+Fh(PCMCIA_DEBUG)27 b Fm(de\034ned)32 b(will)g(ha)n(v)n(e)e(an)i(in)n
+(teger)e(parameter,)i Fh(pc_debug)p Fm(,)d(that)j(con)n(trols)e(the)i
+(v)n(erb)r(osit)n(y)e(of)0 1735 y(its)g(output.)45 b(This)30
+b(can)f(b)r(e)i(adjusted)f(when)g(the)g(mo)r(dule)h(is)f(loaded,)g(so)f
+(output)h(can)g(b)r(e)g(con)n(trolled)f(on)h(a)f(p)r(er-mo)r(dule)0
+1849 y(basis)e(without)h(recompiling.)0 2005 y(Y)-7 b(our)34
+b(default)g(con\034guration)f(for)g Fh(syslogd)e Fm(ma)n(y)j(discard)f
+(k)n(ernel)g(debugging)g(messages.)55 b(T)-7 b(o)34 b(ensure)f(that)i
+(they)f(are)0 2119 y(recorded,)25 b(edit)h Fh(/etc/syslog.conf)20
+b Fm(to)26 b(ensure)f(that)h(\020)7 b Fh(kern.debug)p
+Fm(\021)29 b(messages)24 b(are)h(recorded)g(somewhere.)35
+b(See)26 b(\020)7 b Fh(man)0 2233 y(syslog.conf)p Fm(\021)30
+b(for)d(details.)0 2389 y(There)39 b(are)g(a)h(few)g(debugging)f(to)r
+(ols)g(in)h(the)g Fh(debug_tools/)35 b Fm(sub)r(directory)k(of)h(the)g
+(PCMCIA)g(distribution.)74 b(The)0 2503 y Fh(dump_tcic)17
+b Fm(and)j Fh(dump_i365)c Fm(utilities)21 b(generate)e(complete)h
+(register)f(dumps)i(of)f(the)h(PCMCIA)g(con)n(trollers,)e(and)h(deco)r
+(de)0 2616 y(a)i(lot)g(of)h(the)g(register)e(information.)34
+b(They)22 b(are)g(most)g(useful)h(if)g(y)n(ou)f(ha)n(v)n(e)f(access)g
+(to)h(a)h(datasheet)e(for)h(the)h(corresp)r(onding)0
+2730 y(con)n(troller)j(c)n(hip.)39 b(The)28 b Fh(dump_cis)d
+Fm(utilit)n(y)j(\()p Fh(dump_tuples)c Fm(in)k(pre-3.0.2)e
+(distributions\))i(lists)h(the)f(con)n(ten)n(ts)f(of)h(a)g(card's)0
+2843 y(CIS)j(\(Card)g(Information)g(Structure\),)h(and)f(deco)r(des)g
+(some)g(of)g(the)h(imp)r(ortan)n(t)f(bits.)48 b(And)32
+b(the)g Fh(dump_cisreg)27 b Fm(utilit)n(y)0 2957 y(displa)n(ys)f(a)i
+(card's)e(lo)r(cal)h(con\034guration)f(registers.)0 3113
+y(The)h Fh(memory_cs)c Fm(memory)i(card)h(driv)n(er)f(is)i(also)e
+(sometimes)i(useful)g(for)f(debugging)f(problems)h(with)h(16-bit)f(PC)h
+(Cards.)0 3227 y(It)33 b(can)g(b)r(e)g(b)r(ound)h(to)f(an)n(y)f(card,)i
+(and)f(do)r(es)f(not)h(in)n(terfere)g(with)g(other)g(driv)n(ers.)51
+b(It)34 b(can)e(b)r(e)i(used)f(to)g(directly)f(access)0
+3341 y(an)n(y)e(card's)g(attribute)i(memory)e(or)g(common)h(memory)-7
+b(.)47 b(Similarly)30 b(for)h(CardBus)f(cards,)h(the)g
+Fh(memory_cb)d Fm(driv)n(er)h(can)0 3454 y(b)r(e)d(b)r(ound)g(to)f(an)n
+(y)g(32-bit)f(card,)h(to)h(giv)n(e)e(direct)h(access)g(to)g(that)h
+(card's)e(address)g(spaces.)35 b(See)26 b(the)f(man)h(pages)e(for)h
+(more)0 3568 y(information.)0 3854 y Fe(7.4)112 b(/pro)s(c/bus/p)s
+(ccard)0 4064 y Fm(Starting)51 b(with)i(2.1.103)d(k)n(ernels,)57
+b(the)52 b(PCMCIA)h(pac)n(k)-5 b(age)50 b(will)i(create)f(a)h(tree)f
+(of)h(status)g(information)f(under)0 4178 y Fh(/proc/bus/pccard)o
+Fm(.)30 b(Muc)n(h)23 b(of)h(the)g(information)e(can)h(only)g(b)r(e)h
+(in)n(terpreted)f(using)g(the)h(data)f(sheets)g(for)g(the)h(PCMCIA)0
+4292 y(host)h(con)n(troller.)35 b(Its)25 b(con)n(ten)n(ts)g(ma)n(y)g
+(dep)r(end)i(on)e(ho)n(w)g(the)h(driv)n(ers)e(w)n(ere)h(con\034gured,)g
+(but)h(ma)n(y)f(include)h(all)f(or)g(some)g(of)0 4405
+y(the)j(follo)n(wing:)0 4616 y Fh(/proc/bus/pccard)o(/)p
+Fd(f)o Fh(ir)o(q,i)o(op)o(or)o(t,m)o(em)o(ory)o Fd(g)208
+4757 y Fm(If)d(presen)n(t,)f(these)h(\034les)g(con)n(tain)f(resource)f
+(allo)r(cation)h(information)g(to)g(supplemen)n(t)h(the)g(normal)f(k)n
+(ernel)g(resource)208 4871 y(tables.)42 b(Recen)n(t)29
+b(v)n(ersions)f(of)i(the)g(PCMCIA)g(system)f(ma)n(y)g(obtain)g
+(additional)g(resource)f(information)h(from)g(the)208
+4984 y(Plug)e(and)h(Pla)n(y)f(BIOS)g(if)h(con\034gured)f(to)g(do)g(so.)
+0 5153 y Fh(/proc/bus/pccard)o(/d)o(riv)o(er)o(s)208
+5294 y Fm(In)c(recen)n(t)h(releases,)e(this)i(lists)g(all)f(curren)n
+(tly)g(loaded)g(PCMCIA)i(clien)n(t)e(driv)n(ers.)34 b(Unlik)n(e)24
+b Fh(/proc/modules)p Fm(,)19 b(it)24 b(also)208 5407
+y(lists)j(driv)n(ers)f(that)i(ma)n(y)f(b)r(e)h(statically)f(link)n(ed)g
+(in)n(to)g(the)h(k)n(ernel.)p eop
+%%Page: 48 48
+48 47 bop 0 -167 3900 5 v 0 -200 a Ff(7.)73 b(Debugging)31
+b(tips)g(and)h(programming)d(information)1741 b Fm(48)0
+162 y Fh(/proc/bus/pccard)o(/*)o(/in)o(fo)208 308 y Fm(F)-7
+b(or)26 b(eac)n(h)h(so)r(c)n(k)n(et,)g(describ)r(es)g(that)h(so)r(c)n
+(k)n(et's)e(host)h(con)n(troller)f(and)h(its)h(capabilities.)0
+488 y Fh(/proc/bus/pccard)o(/*)o(/ex)o(ca)208 635 y Fm(This)f(con)n
+(tains)g(a)g(dump)h(of)f(a)h(con)n(troller's)d(\020ExCA\021)35
+b(In)n(tel)27 b(i82365sl-compatible)d(register)i(set.)0
+815 y Fh(/proc/bus/pccard)o(/*)o(/)p Fd(f)o Fh(pci)o(,c)o(ar)o(dbu)o(s)
+p Fd(g)208 962 y Fm(F)-7 b(or)34 b(CardBus)h(bridges,)h(a)f(dump)h(of)g
+(the)f(bridge's)g(PCI)h(con\034guration)e(space,)i(and)g(a)f(dump)h(of)
+f(the)h(bridge's)208 1076 y(CardBus)26 b(con\034guration)g(registers.)0
+1367 y Fe(7.5)112 b(W)-9 b(riting)35 b(Card)j(Services)f(driv)m(ers)f
+(for)h(new)h(cards)0 1577 y Fm(The)d(Lin)n(ux)g(PCMCIA)h(Programmer's)d
+(Guide)i(is)g(the)h(b)r(est)f(do)r(cumen)n(tation)g(for)g(the)g(clien)n
+(t)g(driv)n(er)f(in)n(terface.)59 b(The)0 1691 y(latest)40
+b(v)n(ersion)e(is)i(alw)n(a)n(ys)f(a)n(v)-5 b(ailable)38
+b(from)i Fh(sourceforge.org)34 b Fm(in)40 b Fh(/pcmcia/doc)p
+Fm(,)f(or)g(on)h(the)g(w)n(eb)g(at)80 b Fh(<http://)0
+1804 y(pcmcia.sourcefor)o(ge)o(.or)o(g>)o Fm(.)0 1961
+y(F)-7 b(or)26 b(devices)h(that)g(are)f(close)h(relativ)n(es)e(of)i
+(normal)f(ISA)i(devices,)f(y)n(ou)f(will)h(probably)f(b)r(e)i(able)e
+(to)h(use)g(parts)g(of)g(existing)0 2074 y(Lin)n(ux)f(driv)n(ers.)35
+b(In)26 b(some)f(cases,)h(the)g(biggest)f(stum)n(bling)h(blo)r(c)n(k)g
+(will)g(b)r(e)h(mo)r(difying)f(an)g(existing)f(driv)n(er)g(so)h(that)g
+(it)g(can)0 2188 y(handle)i(adding)g(and)g(remo)n(ving)e(devices)i
+(after)g(b)r(o)r(ot)g(time.)39 b(Of)28 b(the)h(curren)n(t)e(driv)n
+(ers,)g(the)h(memory)g(card)f(driv)n(er)g(is)h(the)0
+2302 y(only)f(\020self-con)n(tained\021)32 b(driv)n(er)26
+b(that)i(do)r(es)f(not)g(dep)r(end)h(on)f(other)g(parts)f(of)h(the)h
+(Lin)n(ux)f(k)n(ernel)f(to)i(do)f(most)g(of)g(the)h(dirt)n(y)0
+2415 y(w)n(ork.)0 2572 y(In)e(man)n(y)e(cases,)h(the)h(largest)e
+(barrier)f(to)i(supp)r(orting)g(a)g(new)g(card)g(t)n(yp)r(e)g(is)h
+(obtaining)e(tec)n(hnical)h(information)g(from)g(the)0
+2685 y(man)n(ufacturer.)35 b(It)25 b(ma)n(y)f(b)r(e)h(di\036cult)h(to)e
+(\034gure)h(out)f(who)h(to)g(ask,)f(or)g(to)h(explain)f(exactly)g(what)
+h(information)f(is)h(needed.)0 2799 y(Ho)n(w)n(ev)n(er,)e(with)i(a)g
+(few)f(exceptions,)h(it)g(is)g(v)n(ery)e(di\036cult)i(if)h(not)e(imp)r
+(ossible)h(to)f(implemen)n(t)h(a)f(driv)n(er)g(for)g(a)g(card)g
+(without)0 2912 y(tec)n(hnical)j(information)g(from)g(the)h(man)n
+(ufacturer.)0 3069 y(I)d(ha)n(v)n(e)f(written)h(a)f(dumm)n(y)h(driv)n
+(er)f(with)h(lots)g(of)g(commen)n(ts)f(that)i(explains)e(a)g(lot)h(of)g
+(ho)n(w)f(a)h(driv)n(er)f(comm)n(unicates)g(with)0 3182
+y(Card)j(Services;)f(y)n(ou)h(will)h(\034nd)g(this)g(in)g(the)g(PCMCIA)
+g(source)e(distribution)i(in)g Fh(clients/dummy_c)o(s.)o(c)p
+Fm(.)0 3474 y Fe(7.6)112 b(Guidelines)36 b(for)i(PCMCIA)e(clien)m(t)f
+(driv)m(er)i(authors)0 3684 y Fm(I)d(ha)n(v)n(e)e(decided)i(that)f(it)h
+(is)g(not)f(really)g(feasible)g(for)g(me)g(to)h(distribute)f(all)h
+(PCMCIA)g(clien)n(t)g(driv)n(ers)d(as)i(part)g(of)h(the)0
+3798 y(PCMCIA)22 b(pac)n(k)-5 b(age.)33 b(Eac)n(h)21
+b(new)g(driv)n(er)f(mak)n(es)f(the)j(main)f(pac)n(k)-5
+b(age)19 b(incremen)n(tally)h(harder)g(to)h(main)n(tain,)h(and)f
+(including)0 3911 y(a)33 b(driv)n(er)f(inevitably)i(transfers)e(some)h
+(of)g(the)h(main)n(tenance)f(w)n(ork)f(from)h(the)h(driv)n(er)f(author)
+f(to)i(me.)54 b(Instead,)35 b(I)f(will)0 4025 y(decide)28
+b(on)h(a)f(case)f(b)n(y)h(case)g(basis)g(whether)g(or)g(not)g(to)g
+(include)h(con)n(tributed)f(driv)n(ers,)f(based)h(on)g(user)g(demand)h
+(as)e(w)n(ell)0 4138 y(as)34 b(main)n(tainabilit)n(y)-7
+b(.)56 b(F)-7 b(or)34 b(driv)n(ers)f(not)i(included)f(in)h(the)g(core)e
+(pac)n(k)-5 b(age,)35 b(I)f(suggest)g(that)g(driv)n(er)f(authors)h
+(adopt)g(the)0 4252 y(follo)n(wing)26 b(sc)n(heme)i(for)f(pac)n(k)-5
+b(aging)25 b(their)j(driv)n(ers)e(for)h(distribution.)0
+4408 y(Driv)n(er)j(\034les)i(should)f(b)r(e)h(arranged)d(in)j(the)f
+(same)g(directory)f(sc)n(heme)h(used)g(in)h(the)g(PCMCIA)g(source)e
+(distribution,)j(so)0 4522 y(that)28 b(the)f(driv)n(er)g(can)g(b)r(e)g
+(unpac)n(k)n(ed)g(on)g(top)g(of)h(a)f(complete)g(PCMCIA)h(source)e
+(tree.)37 b(A)27 b(driv)n(er)g(should)g(include)g(source)0
+4635 y(\034les)h(\(in)i Fh(./modules/)p Fm(\),)25 b(a)j(man)g(page)g
+(\(in)h Fh(./man/)p Fm(\),)e(and)h(con\034guration)f(\034les)h(\(in)i
+Fh(./etc/)p Fm(\).)37 b(The)29 b(top)f(lev)n(el)g(directory)0
+4749 y(should)f(also)g(include)h(a)f(README)i(\034le.)0
+4906 y(The)38 b(top-lev)n(el)f(directory)f(should)i(include)g(a)g(mak)n
+(e\034le,)i(set)e(up)g(so)f(that)h(\020)7 b Fh(make)42
+b(-f)g(...)67 b Fm(all\021)44 b(and)38 b(\020)7 b Fh(make)42
+b(-f)g(...)0 5019 y(install)p Fm(\021)35 b(compile)c(the)h(driv)n(er)e
+(and)i(install)f(all)g(appropriate)f(\034les.)48 b(If)32
+b(this)g(mak)n(e\034le)f(is)g(giv)n(en)g(an)g(extension)g(of)g
+Fh(.mk)p Fm(,)0 5133 y(then)26 b(it)g(will)f(automatically)g(b)r(e)g
+(in)n(v)n(ok)n(ed)f(b)n(y)h(the)h(top-lev)n(el)e Fh(Makefile)f
+Fm(for)h(the)i Fh(all)e Fm(and)i Fh(install)c Fm(targets.)35
+b(Here)25 b(is)g(an)0 5246 y(example)i(of)h(ho)n(w)f(suc)n(h)g(a)g(mak)
+n(e\034le)g(could)g(b)r(e)h(constructed:)p eop
+%%Page: 49 49
+49 48 bop 0 -167 3900 5 v 0 -200 a Ff(7.)73 b(Debugging)31
+b(tips)g(and)h(programming)d(information)1741 b Fm(49)208
+162 y Fc(#)39 b(Sample)i(Makefile)f(for)g(contributed)i(client)f
+(driver)208 266 y(FILES)f(=)f(sample_cs.mk)j(README.sample_cs)h(\\)521
+370 y(modules/sample_cs.c)h(modules/sample_cs.h)f(\\)521
+474 y(etc/sample.conf)g(etc/sample)e(etc/sample.opts)i(\\)521
+578 y(man/sample_cs.4)208 682 y(all:)521 786 y($\(MAKE\))e(-C)f
+(modules)g(MODULES=sample_cs.o)208 890 y(install:)521
+995 y($\(MAKE\))h(-C)f(modules)g(install-modules)j(MODULES=sample_cs.o)
+521 1099 y($\(MAKE\))e(-C)f(etc)g(install-clients)i(CLIENTS=sample)521
+1203 y($\(MAKE\))f(-C)f(man)g(install-man4)h(MAN4=sample_cs.4)208
+1307 y(dist:)521 1411 y(tar)f(czvf)g(sample_cs.tar.gz)j($\(FILES\))0
+1650 y Fm(This)25 b(mak)n(e\034le)f(uses)g(install)h(targets)e
+(de\034ned)i(in)g(2.9.10)e(and)i(later)f(v)n(ersions)f(of)h(the)h
+(PCMCIA)h(pac)n(k)-5 b(age.)34 b(This)25 b(mak)n(e\034le)0
+1763 y(also)32 b(includes)h(a)f(\020dist\021)40 b(target)32
+b(for)g(the)h(con)n(v)n(enience)f(of)h(the)g(driv)n(er)f(author.)52
+b(Y)-7 b(ou)33 b(w)n(ould)f(probably)g(w)n(an)n(t)g(to)h(add)f(a)0
+1877 y(v)n(ersion)18 b(n)n(um)n(b)r(er)i(to)g(the)g(\034nal)f(pac)n(k)
+-5 b(age)19 b(\034lename)g(\(for)h(example,)h Fh(sample_cs-1.5.ta)o(r.)
+o(gz)o Fm(\).)29 b(A)20 b(complete)g(distribution)0 1990
+y(could)27 b(lo)r(ok)g(lik)n(e:)208 2220 y Fc(sample_cs.mk)208
+2324 y(README.sample_cs)208 2428 y(modules/sample_cs.c)208
+2532 y(modules/sample_cs.h)208 2636 y(etc/sample.conf)208
+2740 y(etc/sample)208 2844 y(etc/sample.opts)208 2948
+y(man/sample_cs.4)0 3187 y Fm(With)c(this)g(arrangemen)n(t,)f(when)g
+(the)h(con)n(tributed)g(driv)n(er)e(is)h(unpac)n(k)n(ed,)h(it)g(b)r
+(ecomes)f(essen)n(tially)g(part)g(of)g(the)h(PCMCIA)0
+3301 y(source)29 b(tree.)44 b(It)30 b(can)g(mak)n(e)f(use)h(of)g(the)h
+(PCMCIA)f(header)g(\034les,)g(as)g(w)n(ell)f(as)h(the)g(mac)n(hinery)f
+(for)h(c)n(hec)n(king)f(the)h(user's)0 3414 y(system)d
+(con\034guration,)f(and)i(automatic)f(dep)r(endency)g(c)n(hec)n(king,)g
+(just)h(lik)n(e)f(a)g(\020normal\021)33 b(clien)n(t)28
+b(driv)n(er.)0 3571 y(In)40 b(this)h(example,)i Fh(etc/sample)36
+b Fm(and)k Fh(etc/sample.opts)34 b Fm(w)n(ould)40 b(b)r(e)g(the)h(new)f
+(driv)n(er's)f(con\034guration)g(scripts)g(\(if)0 3684
+y(needed\),)22 b(and)e Fh(etc/sample.conf)13 b Fm(w)n(ould)20
+b(con)n(tain)f(an)n(y)g(additions)h(to)g(the)g(PCMCIA)h(card)e
+(con\034guration)f(\034le.)35 b(Starting)0 3798 y(with)i(the)g(3.1.6)e
+(release,)j Fh(cardmgr)33 b Fm(will)k(automatically)f(pro)r(cess)f(an)n
+(y)h Fh(*.conf)e Fm(\034les)i(installed)h(in)f Fh(/etc/pcmcia)p
+Fm(,)f(so)0 3911 y(installation)27 b(of)g(con)n(tributed)h(driv)n(ers)e
+(should)h(no)g(longer)f(require)h(hand)g(editing)h(con\034guration)e
+(\034les.)0 4068 y(I)h(will)h(accept)f(clien)n(t)g(driv)n(ers)f
+(prepared)g(according)f(to)i(this)h(sp)r(eci\034cation)f(and)g(place)f
+(them)i(in)g(the)f Fh(/pcmcia/contrib)0 4181 y Fm(directory)g(on)g
+Fh(sourceforge.org)p Fm(.)32 b(The)c(README)i(in)f(this)f(directory)e
+(will)j(describ)r(e)e(ho)n(w)h(to)g(unpac)n(k)f(a)g(con)n(tributed)0
+4295 y(driv)n(er.)0 4451 y(The)35 b(clien)n(t)g(driv)n(er)f(in)n
+(terface)g(has)g(not)h(c)n(hanged)f(m)n(uc)n(h)h(o)n(v)n(er)e(time,)k
+(and)e(has)f(almost)g(alw)n(a)n(ys)f(preserv)n(ed)g(bac)n(kw)n(ards)0
+4565 y(compatibilit)n(y)-7 b(.)36 b(A)26 b(clien)n(t)g(driv)n(er)e
+(will)i(not)g(normally)e(need)i(to)f(b)r(e)h(up)r(dated)h(for)e(minor)g
+(revisions)f(in)i(the)g(main)g(pac)n(k)-5 b(age.)0 4679
+y(I)28 b(will)f(try)h(to)f(notify)h(authors)e(of)i(con)n(tributed)f
+(driv)n(ers)f(of)i(c)n(hanges)e(that)i(require)e(up)r(dates)i(to)f
+(their)h(driv)n(ers.)0 4970 y Fe(7.7)112 b(Guidelines)36
+b(for)i(Lin)m(ux)f(distribution)e(main)m(tainers)0 5180
+y Fm(If)26 b(y)n(our)e(distribution)i(has)f(system)g(con\034guration)f
+(to)r(ols)h(that)h(y)n(ou)f(w)n(ould)g(lik)n(e)g(to)g(b)r(e)h(PCMCIA-a)
+n(w)n(are,)e(please)h(use)h(the)0 5294 y Fh(*.opts)d
+Fm(\034les)i(in)g Fh(/etc/pcmcia)20 b Fm(for)25 b(y)n(our)f(\020ho)r
+(oks.\021)41 b(These)25 b(\034les)g(will)g(not)g(b)r(e)h(mo)r(di\034ed)
+f(if)h(a)f(user)f(compiles)h(and)f(installs)0 5407 y(a)g(new)g(release)
+f(of)h(the)h(PCMCIA)g(pac)n(k)-5 b(age.)34 b(If)25 b(y)n(ou)e(mo)r
+(dify)i(the)g(main)f(con\034guration)f(scripts,)h(then)h(a)f(fresh)g
+(install)g(will)p eop
+%%Page: 50 50
+50 49 bop 0 -167 3900 5 v 0 -200 a Ff(7.)73 b(Debugging)31
+b(tips)g(and)h(programming)d(information)1741 b Fm(50)0
+162 y(silen)n(tly)29 b(o)n(v)n(erwrite)e(y)n(our)h(custom)h(scripts)g
+(and)g(break)f(the)i(connection)f(with)g(y)n(our)f(con\034guration)g
+(to)r(ols.)41 b(Con)n(tact)29 b(me)0 275 y(if)f(y)n(ou)f(are)f(not)i
+(sure)f(ho)n(w)g(to)g(write)h(an)f(appropriate)f(option)h(script,)g(or)
+g(if)h(y)n(ou)f(need)g(additional)g(capabilities.)0 432
+y(It)j(is)g(helpful)h(for)e(users)g(\(and)h(for)g(me\))g(if)g(y)n(ou)g
+(can)f(do)r(cumen)n(t)h(ho)n(w)g(y)n(our)e(distribution)i(deviates)f
+(from)h(the)g(PCMCIA)0 545 y(pac)n(k)-5 b(age)32 b(as)h(describ)r(ed)g
+(in)h(this)g(do)r(cumen)n(t.)55 b(In)33 b(particular,)h(please)f(do)r
+(cumen)n(t)g(c)n(hanges)g(to)g(the)h(startup)f(script)g(and)0
+659 y(con\034guration)28 b(scripts.)43 b(If)30 b(y)n(ou)f(send)h(me)g
+(the)g(appropriate)e(information,)h(I)h(will)g(include)g(it)g(in)g(the)
+g(2.5)f(\(Notes)h(ab)r(out)0 772 y(sp)r(eci\034c)e(Lin)n(ux)f
+(distributions\).)0 929 y(When)21 b(building)g(PCMCIA)g(for)f
+(distribution,)i(consider)d(including)i(con)n(tributed)f(driv)n(ers)f
+(that)i(are)e(not)i(part)f(of)g(the)h(main)0 1043 y(PCMCIA)26
+b(pac)n(k)-5 b(age.)35 b(F)-7 b(or)24 b(reasons)g(of)h(main)n
+(tainabilit)n(y)-7 b(,)25 b(I)g(am)h(trying)e(to)h(limit)i(the)e(core)f
+(pac)n(k)-5 b(age)24 b(size,)i(b)n(y)f(only)g(adding)0
+1156 y(new)32 b(driv)n(ers)e(if)i(I)g(think)h(they)f(are)f(of)g
+(particularly)g(broad)f(in)n(terest.)50 b(Other)31 b(driv)n(ers)f(will)
+i(b)r(e)g(distributed)h(separately)-7 b(,)0 1270 y(as)28
+b(describ)r(ed)g(in)g(the)h(previous)e(section.)39 b(The)29
+b(split)f(b)r(et)n(w)n(een)g(in)n(tegral)g(and)g(separate)f(driv)n(ers)
+f(is)j(somewhat)e(arbitrary)0 1383 y(and)g(partly)g(historical,)g(and)g
+(should)g(not)h(imply)g(a)f(di\033erence)g(in)h(qualit)n(y)-7
+b(.)p eop
+%%Trailer
+end
+userdict /end-hook known{end-hook}if
+%%EOF
Index: oldkernel/linux/pcmcia-cs-3.1.15/doc/PCMCIA-PROG
diff -u /dev/null linux/pcmcia-cs-3.1.15/doc/PCMCIA-PROG:1.1
--- /dev/null	Mon Jul 31 21:15:11 2000
+++ linux/pcmcia-cs-3.1.15/doc/PCMCIA-PROG	Fri Jul  7 16:34:58 2000
@@ -0,0 +1,3928 @@
+  Linux PCMCIA Programmer's Guide
+  David Hinds, dhinds@pcmcia.sourceforge.org.
+  v2.24, 16 March 2000
+
+  This document describes how to write kernel device drivers for the
+  Linux PCMCIA Card Services interface.  It also describes how to write
+  user-mode utilities for communicating with Card Services.  The latest
+  version of this document can always be found at <ftp://source-
+  forge.org/pcmcia>.  An HTML version is at  <http://pcmcia.source-
+  forge.org>.
+  ______________________________________________________________________
+
+  Table of Contents
+
+  1. Introduction
+
+     1.1 Copyright notice and disclaimer
+     1.2 Acknowledgements
+
+  2. Basic Concepts
+
+     2.1 The socket interface
+     2.2 The socket controller
+
+  3. Card Services Subfunction Descriptions
+
+     3.1 Client management functions
+        3.1.1 RegisterClient
+        3.1.2 DeregisterClient
+        3.1.3 SetEventMask
+        3.1.4 BindDevice
+     3.2 Socket state control
+        3.2.1 GetStatus
+        3.2.2 ResetCard
+        3.2.3 SuspendCard
+        3.2.4 ResumeCard
+        3.2.5 EjectCard
+        3.2.6 InsertCard
+     3.3 IO card configuration calls
+        3.3.1 RequestIO
+        3.3.2 ReleaseIO
+        3.3.3 RequestIRQ
+        3.3.4 ReleaseIRQ
+        3.3.5 RequestConfiguration
+        3.3.6 ModifyConfiguration
+        3.3.7 ReleaseConfiguration
+        3.3.8 GetConfigurationInfo
+     3.4 Card Information Structure (CIS) calls
+        3.4.1 GetFirstTuple, GetNextTuple
+        3.4.2 GetTupleData
+        3.4.3 ParseTuple
+        3.4.4 ValidateCIS
+        3.4.5 ReplaceCIS
+     3.5 Memory window control
+        3.5.1 RequestWindow
+        3.5.2 ModifyWindow
+        3.5.3 ReleaseWindow
+        3.5.4 GetFirstWindow, GetNextWindow
+        3.5.5 MapMemPage, GetMemPage
+     3.6 Bulk Memory Services
+        3.6.1 RegisterMTD
+        3.6.2 GetFirstRegion, GetNextRegion
+        3.6.3 OpenMemory
+        3.6.4 CloseMemory
+        3.6.5 ReadMemory, WriteMemory
+        3.6.6 RegisterEraseQueue
+        3.6.7 DeregisterEraseQueue
+        3.6.8 CheckEraseQueue
+     3.7 Miscellaneous calls
+        3.7.1 GetCardServicesInfo
+        3.7.2 AccessConfigurationRegister
+        3.7.3 AdjustResourceInfo
+        3.7.4 ReportError
+
+  4. Card Information Structure Definitions
+
+     4.1 CIS Tuple Definitions
+        4.1.1 CISTPL_CHECKSUM
+        4.1.2 CISTPL_LONGLINK_A, CISTPL_LONGLINK_C, CISTPL_LINKTARGET, CISTPL_NOLINK
+        4.1.3 CISTPL_LONGLINK_MFC
+        4.1.4 CISTPL_DEVICE, CISTPL_DEVICE_A
+        4.1.5 CISTPL_VERS_1
+        4.1.6 CISTPL_ALTSTR
+        4.1.7 CISTPL_JEDEC_C, CISTPL_JEDEC_A
+        4.1.8 CISTPL_CONFIG, CISTPL_CONFIG_CB
+        4.1.9 CISTPL_BAR
+        4.1.10 CISTPL_CFTABLE_ENTRY
+        4.1.11 CISTPL_CFTABLE_ENTRY_CB
+        4.1.12 CISTPL_MANFID
+        4.1.13 CISTPL_FUNCID
+        4.1.14 CISTPL_DEVICE_GEO
+        4.1.15 CISTPL_VERS_2
+        4.1.16 CISTPL_ORG
+     4.2 CIS configuration register definitions
+        4.2.1 Configuration Option Register
+        4.2.2 Card Configuration and Status Register
+        4.2.3 Pin Replacement Register
+        4.2.4 Socket and Copy Register
+        4.2.5 Extended Status Register
+        4.2.6 IO Base and Size Registers
+
+  5. Card Services Event Handling
+
+     5.1 Event handler operations
+     5.2 Event descriptions
+     5.3 Client driver event handling responsibilities
+
+  6. Memory Technology Drivers
+
+     6.1 MTD request handling
+     6.2 MTD helper functions
+        6.2.1 MTDRequestWindow, MTDReleaseWindow
+        6.2.2 MTDModifyWindow
+        6.2.3 MTDSetVpp
+        6.2.4 MTDRDYMask
+
+  7. Driver Services Interface
+
+     7.1 Interface to other client drivers
+        7.1.1 The dev_link_t structure
+        7.1.2 register_pccard_driver
+        7.1.3 unregister_pccard_driver
+     7.2 The CardBus client interface
+        7.2.1 register_driver
+        7.2.2 unregister_driver
+        7.2.3 The driver_operations entry points
+     7.3 Interface to user mode utilities
+        7.3.1 Card Services event notifications
+        7.3.2 Ioctl descriptions
+
+  8. Anatomy of a Card Services Client Driver
+
+     8.1 Module initialization and cleanup
+     8.2 The *_attach() and *_detach() functions
+     8.3 The *_config() and *_release() functions
+     8.4 The client event handler
+     8.5 Locking and synchronization issues
+     8.6 Using existing Linux drivers to access PC Card devices
+
+  9. The Socket Driver Layer
+
+     9.1 Card Services entry points for socket drivers
+     9.2 Services provided by the socket driver
+        9.2.1 SS_InquireSocket
+        9.2.2 SS_RegisterCallback
+        9.2.3 SS_GetStatus
+        9.2.4 SS_GetSocket, SS_SetSocket
+        9.2.5 SS_GetIOMap, SS_SetIOMap
+        9.2.6 SS_GetMemMap, SS_SetMemMap
+        9.2.7 SS_GetBridge, SS_SetBridge
+        9.2.8 SS_ProcSetup
+     9.3 Supporting unusual socket architectures
+
+  10. Where to Go for More Information
+
+  ______________________________________________________________________
+
+  11..  IInnttrroodduuccttiioonn
+
+  The Linux kernel PCMCIA system has three main components.  At the
+  lowest level are the socket drivers.  Next is the Card Services
+  module.  Drivers for specific cards are layered on top of Card
+  Services.  One special Card Services client, called Driver Services,
+  provides a link betweek user level utility programs and the kernel
+  facilities.
+
+  The socket driver layer is loosely based on the Socket Services API.
+  There are two socket driver modules.  The tcic module supports the
+  Databook TCIC-2 family of host controllers.  The i82365 module
+  supports the Intel i82365sl family and various Intel-compatible
+  controllers, including Cirrus, VLSI, Ricoh, and Vadem chips.  In
+  addition, the i82365 module implements support for CardBus controllers
+  that follow the ``Yenta'' register-level specification.
+
+  Card Services is the largest single component of the package.  It
+  provides an API somewhat similar to DOS Card Services, adapted to a
+  Unix environment.  The Linux implementation was based in part on the
+  Solaris interface specification.  It is implemented in the pcmcia_core
+  module.  Most version 2.1 features are implemented, with some PC Card
+  95 features.
+
+  The Driver Services layer implements a user mode pseudo-device for
+  accessing some Card Services functions from utility programs.  It is
+  responsible for keeping track of all client drivers, and for matching
+  up drivers with physical sockets.  It is implemented in the ds module.
+
+  This document describes the kernel interface to the Card Services and
+  Driver Services modules, and the user interface to Driver Services.
+  It is intended for use by client device driver developers.  The Linux
+  PCMCIA-HOWTO describes how to install and use Linux PCMCIA support.
+  It is available from sourceforge.org in /pcmcia.
+
+  11..11..  CCooppyyrriigghhtt nnoottiiccee aanndd ddiissccllaaiimmeerr
+
+  Copyright (c) 1996, 1997 David A. Hinds
+
+  This document may be reproduced or distributed in any form without my
+  prior permission.  Modified versions of this document, including
+  translations into other languages, may be freely distributed, provided
+  that they are clearly identified as such, and this copyright is
+  included intact.
+
+  This document may be included in commercial distributions without my
+  prior consent.  While it is not required, I would like to be informed
+  of such usage.  If you intend to incorporate this document in a
+  published work, please contact me to make sure you have the latest
+  available version.
+
+  This document is provided ``AS IS'', with no express or implied
+  warranties.  Use the information in this document at your own risk.
+
+  11..22..  AAcckknnoowwlleeddggeemmeennttss
+
+  I'd like to thank all the Linux users who have helped test and debug
+  this software, and who have helped with driver development.  I should
+  also thank Linus Torvalds, Donald Becker, Alan Cox, and Bjorn Ekwall
+  for Linux kernel development help.  I'm especially grateful to Michael
+  Bender for many helpful discussions about the Solaris implementation.
+
+  22..  BBaassiicc CCoonncceeppttss
+
+  22..11..  TThhee ssoocckkeett iinntteerrffaaccee
+
+  The PC Card bus has two basic operating modes: ``memory-only'' and
+  ``memory and IO''.  The first mode was defined by the original Version
+  1.0 specification and only supports simple memory cards.  The second
+  mode, defined in Version 2.0, redefines a few of the memory card
+  control signals to support IO port addressing and IO interrupt
+  signalling.
+
+  PC Card devices have two memory spaces: ``attribute memory'' and
+  ``common memory''.  The interface can address up to 16MB of each type
+  of memory.  Attribute memory is typically used for holding descriptive
+  information and configuration registers.  Common memory may include
+  the bulk storage of a memory card, or device buffers in the case of IO
+  cards.  All cards that are compliant with the version 2.0 PC Card
+  specification should have a Card Information Structure (or ``CIS'') in
+  attribute memory, which describes the card and how it should be
+  configured.
+
+  Separate control signals allow cards to signal their operating status
+  to the host.  These signals include card detect, ready/busy, write
+  protect, battery low, and battery dead.
+
+  The ``memory and IO'' interface mode allows cards to address up to 64K
+  of IO ports.  It also allows cards to signal IO interrupts, and routes
+  one card output to the host system's speaker.  In this mode, several
+  of the memory card control signals are unavailable because those pins
+  are used to carry the extra IO card signals.  On some cards, these
+  signals can instead be read from a special configuration register in
+  attribute memory, the ``Pin Replacement Register''.
+
+  22..22..  TThhee ssoocckkeett ccoonnttrroolllleerr
+
+  The socket controller serves as a bridge between PC Card devices and
+  the system bus.  There are several varieties of controllers, but all
+  share the same basic functionality.  The Socket Services software
+  layer takes care of all the details of how to program the host
+  controller.
+
+  The socket controller has the job of mapping windows of addresses in
+  the host memory and IO spaces to windows of addresses in card space.
+  All supported controllers support at least four independent memory
+  windows and two IO windows per socket.
+
+  Each memory window is defined by a base address in the host address
+  space, a base address in the card address space, and a window size.
+  Some controllers differ in their alignment rules for memory windows,
+  but all controllers will support windows whose size is at least 4K and
+  also a power of two, and where the base address is a multiple of the
+  window size.  Each window can be programmed to point to either
+  attribute or common memory.
+
+  IO windows differ from memory windows in that host addresses that fall
+  within an IO window are not modified before they are passed on to an
+  IO card.  Effectively, the base addresses of the window in the host
+  and card address spaces are always equal.  IO windows also have no
+  alignment or size restrictions; an IO window can start and end on any
+  byte boundary in the 64K IO address space.
+
+  The PC Card bus defines a single interrupt signal from the card to the
+  controller.  The controller then has the responsibility of steering
+  this interrupt to an appropriate interrupt request (``irq'') line.
+  All controllers support steering card IO interrupts to essentially any
+  free interrupt line.  Because steering happens in the controller, the
+  card itself is unaware of which interrupt it uses.
+
+  All PC Card controllers can generate interrupts in response to card
+  status changes.  These interrupts are distinct from the IO interrupts
+  generated by an IO card, and use a separate interrupt line.  Signals
+  that can generate interrupts include card detect, ready/busy, write
+  protect, battery low, and battery dead.
+
+  33..  CCaarrdd SSeerrvviicceess SSuubbffuunnccttiioonn DDeessccrriippttiioonnss
+
+  Card Services calls have the general form:
+
+       #include "cs_types.h"
+       #include "cs.h"
+
+       int CardServices(int subfunc, void *arg1, void *arg2, ...);
+
+  Some Card Services functions require additional #include statements.
+  The particular subfunction determines the number of expected
+  arguments.  A return code of CS_SUCCESS indicates that a call
+  succeeded.  Other return codes indicate errors.
+
+  33..11..  CClliieenntt mmaannaaggeemmeenntt ffuunnccttiioonnss
+
+  Device drivers that use Card Services functions are called
+  ``clients''.  A device driver should use the RegisterClient call to
+  get a client handle before using other services.  Most Card Services
+  functions will take this client handle as an argument.  Before
+  unloading, drivers should also unregister with DeregisterClient.
+
+  33..11..11..  RReeggiisstteerrCClliieenntt
+
+  int CardServices(RegisterClient, client_handle_t *client, client_reg_t *reg);
+
+  The client_reg_t data structure is given by:
+
+       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 *args);
+               event_callback_args_t   event_callback_args;
+               u_int           Version;
+       } client_reg_t;
+
+  RegisterClient establishes a link between a client driver and Card
+  Services, and connects the client with an appropriate socket.  The
+  dev_info parameter is used by Card Services to match the client with a
+  socket and function; this correspondence is normally established by
+  Driver Services via a call to BindDevice.  If successful, a client
+  handle will be returned in client.
+
+  The following flags can be specified in Attributes:
+
+     INFO_MASTER_CLIENT
+        For use only by the Driver Services client.  Among other things,
+        specifies that this client should not be automatically unbound
+        when a card is ejected from this socket.
+
+     INFO_IO_CLIENT
+        Specifies that this client is an IO card driver.
+
+     INFO_MTD_CLIENT
+        Specifies that this client is a Memory Technology Driver.
+
+     INFO_MEM_CLIENT
+        Specifies that this client is a memory card driver.
+
+     INFO_CARD_SHARE
+        Included for compatibility, has no effect.
+
+     INFO_CARD_EXCL
+        Included for compatibility, has no effect.
+
+  EventMask specifies what events this client should be notified of.
+  The event_handler entry point will be called by Card Services when an
+  event in EventMask is processed.  The event_handler_args structure is
+  a template for the structure that will be passed to the event handler.
+  The Version parameter identifies the Card Services version level that
+  this driver expects; it is currently ignored.
+
+  A driver should be prepared to handle Card Services events before
+  calling RegisterClient.  This call will always generate a
+  CS_REGISTRATION_COMPLETE event, and may also generate an artificial
+  CS_CARD_INSERTION event if the socket is currently occupied.
+
+  Return codes:
+
+     CS_OUT_OF_RESOURCE
+        An appropriate socket could not be found for this driver.
+  33..11..22..  DDeerreeggiisstteerrCClliieenntt
+
+       int CardServices(DeregisterClient, client_handle_t client);
+
+  DeregisterClient severs the connection between a client and Card
+  Services.  It should be called after the client has freed any
+  resources it has allocated.  Once a connection is broken, it cannot be
+  reestablished until after another call to BindDevice.
+
+  Return codes:
+
+     CS_BAD_HANDLE
+        The client handle is invalid.
+
+     CS_IN_USE
+        The client still has allocated resources, such as IO port
+        windows or an interrupt, or the socket configuration is locked.
+
+  33..11..33..  SSeettEEvveennttMMaasskk
+
+       int CardServices(SetEventMask, client_handle_t client, eventmask_t *mask);
+
+  The eventmask_t structure is given by:
+
+       typedef struct eventmask_t {
+               u_int           Attributes;
+               u_int           EventMask;
+       } eventmask_t;
+
+  SetEventMask updates the mask that determines which events this client
+  will be notified of.
+
+  Return codes:
+
+     CS_BAD_HANDLE
+        The client handle is invalid.
+
+  33..11..44..  BBiinnddDDeevviiccee
+
+       int CardServices(BindDevice, bind_req_t *req);
+
+  The bind_req structure is given by:
+
+  typedef struct bind_req_t {
+          socket_t        Socket;
+          u_char          Function;
+          dev_info_t      *dev_info;
+  } bind_req_t;
+
+  BindDevice associates a device driver with a particular socket.  It is
+  normally called by Driver Services after a newly inserted card has
+  been identified.  Once a driver has been bound to a socket, it will be
+  eligible to register as a client of that socket.  Note that this call
+  does not take a client handle as an argument.  This is the only Card
+  Services call that takes a socket number as an argument.
+
+  The Function field specifies which function(s) of a multifunction card
+  are to be bound to this driver.  Function numbers correspond to
+  entries in the card's CISTPL_LONGLINK_MFC tuple.  If Function is set
+  to BIND_FN_ALL, the driver will be bound to all card functions.  A
+  driver will only be able to access CIS tuples corresponding to
+  functions for which it is bound.
+
+  Return codes:
+
+     CS_BAD_SOCKET
+        The specified socket number is invalid.
+
+  33..22..  SSoocckkeett ssttaattee ccoonnttrrooll
+
+  These functions are more or less concerned with getting and setting
+  the current operating state of a socket.  GetStatus returns the
+  current socket state.  ResetCard is used to send a hard reset signal
+  to a socket.  SuspendCard and ResumeCard can be used to power down and
+  power up a socket without releasing the drivers currently bound to
+  that socket.  EjectCard and InsertCard essentially mimic real card
+  ejection and insertion events.
+
+  33..22..11..  GGeettSSttaattuuss
+
+       int CardServices(GetStatus, client_handle_t client, cs_status_t *status);
+
+  The cs_status_t data structure is given by:
+
+       typedef struct cs_status_t {
+               u_char          Function;
+               u_int           CardState;
+               u_int           SocketState;
+       } cs_status_t;
+
+  GetStatus returns the current status of a client's socket.  For cards
+  that are configured in IO mode, GetStatus uses the Pin Replacement
+  Register and Extended Status Register to determine the card status.
+  For normal clients, the Function field is ignored, but for clients
+  bound with BIND_FN_ALL, this field specifies the function whose
+  configuration registers should be used to determine the socket state,
+  if the socket is currently configured.  The following flags are
+  defined in CardState:
+
+     CS_EVENT_CARD_DETECT
+        Specifies that the socket is occupied.
+
+     CS_EVENT_CB_DETECT
+        Specifies that the socket is occupied by a CardBus device.
+
+     CS_EVENT_WRITE_PROTECT
+        Specifies that the card is currently write protected.
+
+     CS_EVENT_BATTERY_LOW
+        Specifies that the card battery is low.
+
+     CS_EVENT_BATTERY_DEAD
+        Specifies that the card battery is dead.
+
+     CS_EVENT_READY_CHANGE
+        Specifies that the card is ready.
+
+     CS_EVENT_PM_SUSPEND
+        Specifies that the socket is suspended.
+
+     CS_EVENT_REQUEST_ATTENTION
+        Specifies that the request attention bit in the extended status
+        register is set.
+
+     CS_EVENT_CARD_INSERTION
+        Specifies that a card insertion event is in progress.  An
+        insertion event will be sent to the client when socket setup is
+        complete.
+
+     CS_EVENT_3VCARD
+        Indicates that the card supports 3.3V operation.
+
+     CS_EVENT_XVCARD
+        Indicates that the card supports ``X.X''V operation.  The actual
+        voltage is currently undefined in the specification.
+
+  SocketState is currently unused, but in theory, it should latch
+  changes in the state of the fields in CardState.
+
+  Return codes:
+
+     CS_BAD_HANDLE
+        The client handle is invalid.
+
+  33..22..22..  RReesseettCCaarrdd
+
+       int CardServices(ResetCard, client_handle_t client);
+
+  ResetCard requests that a client's socket be reset.  When this call is
+  made, Card Services sends all clients a CS_EVENT_RESET_REQUEST event.
+  If any client rejects the request, Card Services sends the initiating
+  client a CS_EVENT_RESET_COMPLETE event with event_callback_args.info
+  set to the return code of the client that rejected the request.
+
+  If all clients agree to the request, Card Services sends a
+  CS_EVENT_RESET_PHYSICAL event, then resets the socket.  When the
+  socket signals that it is ready, a CS_EVENT_CARD_RESET event is
+  generated.  Finally, a CS_EVENT_RESET_COMPLETE event is sent to the
+  initiating client, with event_callback_args.info set to zero.
+
+  Return codes:
+
+     CS_BAD_HANDLE
+        The client handle is invalid.
+
+     CS_NO_CARD
+        The socket assigned to this client is currently vacant.
+
+     CS_IN_USE
+        This socket is currently being reset.
+
+  33..22..33..  SSuussppeennddCCaarrdd
+
+       int CardServices(SuspendCard, client_handle_t client);
+
+  Card Services sends all clients CS_EVENT_PM_SUSPEND events, then shuts
+  down and turns off power to the socket.
+
+  Return codes:
+
+     CS_BAD_HANDLE
+        The client handle is invalid.
+
+     CS_NO_CARD
+        The socket assigned to this client is currently vacant.
+
+     CS_IN_USE
+        This socket is already suspended.
+
+  33..22..44..  RReessuummeeCCaarrdd
+
+       int CardServices(ResumeCard, client_handle_t client);
+
+  After restoring power to the socket, Card Services will notify all
+  clients with CS_EVENT_PM_RESUME events.
+
+  Return codes:
+
+     CS_BAD_HANDLE
+        The client handle is invalid.
+
+     CS_NO_CARD
+        The socket assigned to this client is currently vacant.
+
+     CS_IN_USE
+        This socket is not currently suspended.
+
+  33..22..55..  EEjjeeccttCCaarrdd
+
+       int CardServices(EjectCard, client_handle_t client);
+
+  Card Services sends eject events to all clients, then shuts down and
+  turns off power to the socket.  All clients except for Driver Services
+  will be unlinked from the socket.
+
+  Return codes:
+
+     CS_BAD_HANDLE
+        The client handle is invalid.
+
+     CS_NO_CARD
+        The socket assigned to this client is currently vacant.
+
+  33..22..66..  IInnsseerrttCCaarrdd
+
+       int CardServices(InsertCard, client_handle_t client);
+
+  Card Services sends insertion events to all clients of this socket
+  (normally, only Driver Services).
+
+  Return codes:
+
+     CS_BAD_HANDLE
+        The client handle is invalid.
+
+     CS_NO_CARD
+        The socket assigned to this client is currently vacant.
+
+     CS_IN_USE
+        The socket has already been configured.
+
+  33..33..  IIOO ccaarrdd ccoonnffiigguurraattiioonn ccaallllss
+
+  The normal order of events is for a driver to reserve IO ports and an
+  interrupt line with calls to RequestIO and RequestIRQ, then to call
+  RequestConfiguration to actually configure the socket.  If any of
+  these calls fails, a driver should be sure to release any resources it
+  successfully reserved.
+
+  Multifunction cards can have separate configurations for each card
+  function.  However, the configurations do need to be consistent with
+  one another.  While each card function has its own set of
+  configuration registers, each socket has only a single interrupt line
+  and can only map two contiguous ranges of IO ports.
+
+  CardBus cards are configured somewhat differently.  The RequestIO and
+  RequestConfiguration calls have similar roles, however, Card Services
+  takes responsibility for most of the configuration details, and the
+  contents of the request structures are ignored.
+
+  33..33..11..  RReeqquueessttIIOO
+
+       int CardServices(RequestIO, client_handle_t client, io_req_t *req);
+
+  The io_req_t data structure is given by:
+
+       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;
+
+  RequestIO reserves IO port windows for a card.  BasePort1 specifies
+  the base IO port address of the window to be reserved.  If NumPorts2
+  is non-zero, a second IO port window will also be reserved.
+  IOAddrLines specifies the number of address lines that are actually
+  decoded by the card.  The IO port allocation algorithm assumes that
+  any alias of the requested address(es) that preserves the lower
+  IOAddrLines bits will be acceptable, and will update BasePort1 and
+  BasePort2 to reflect the address range(s) actually assigned.
+
+  Prior to release 3.1.4, the IOAddrLines field was ignored.  The
+  allocator always tried to assign the exact address range requested,
+  unless the base address was zero; in that case, it would assign any
+  available window aligned to the nearest power of two larger than the
+  window size.  The new allocator verifies that the IOAddrLines
+  parameter agrees with the requested window parameters, and defaults to
+  the pre-3.1.4 behavior if an inconsistency is found.
+
+  With multifunction cards, this call will allocate IO ports for each
+  card function in such a way that all a card's ports can be mapped by
+  the two low-level IO port windows associated with each physical
+  socket.  For example, if the drivers for a hypothetical four-function
+  card each attempt to allocate one IO window of 8 ports, Card Services
+  will consolidate these into a single contiguous 32-port block.
+
+  When this function is invoked by a CardBus client, the IO request
+  structure is ignored.  Instead, Card Services examines the card and
+  allocates any necessary system resources: this includes IO and memory
+  space, as well as an interrupt, if needed.  One call will reserve all
+  resources needed for all card functions, not just the function of the
+  client making the call.
+
+  This call does not actually configure a socket's IO windows: this is
+  done by a subsequent call to RequestConfiguration.
+
+  The following flags can be specified in Attributes1 and Attributes2:
+
+     IO_DATA_PATH_WIDTH
+        This field may either be IO_DATA_PATH_WIDTH_16 for 16-bit
+        access, or IO_DATA_PATH_WIDTH_8 for 8-bit access, or
+        IO_DATA_PATH_WIDTH_AUTO to dynamically size the bus based on the
+        access size.
+
+  Return codes:
+
+     CS_BAD_HANDLE
+        The client handle is invalid.
+
+     CS_NO_CARD
+        The socket assigned to this client is currently vacant.
+
+     CS_IN_USE
+        This socket's IO windows have already been reserved.
+
+     CS_CONFIGURATION_LOCKED
+        This socket's configuration has been locked by a call to
+        RequestConfiguration.
+
+     CS_BAD_ATTRIBUTE
+        An unsupported attribute flag was specified.
+
+     CS_UNSUPPORTED_FUNCTION
+        For a CardBus client, this is returned if Card Services was not
+        configured with CardBus support.
+
+  33..33..22..  RReelleeaasseeIIOO
+
+       int CardServices(ReleaseIO, client_handle_t client, io_req_t *req);
+
+  ReleaseIO un-reserves IO port windows allocated by a previous call to
+  RequestIO.  The req parameter should be the same one passed to
+  RequestIO.  If several card functions are sharing a larger IO port
+  window, ports released by one function may not become available for
+  other uses until all card functions have released their IO ports.
+
+  For a CardBus client, this call releases all system resources
+  allocated for this card.
+
+  Return codes:
+
+     CS_BAD_HANDLE
+        The client handle is invalid.
+
+     CS_CONFIGURATION_LOCKED
+        This socket's configuration has been locked by a call to
+        RequestConfiguration.  The configuration should be released
+        before calling ReleaseIO.
+
+     CS_BAD_ARGS
+        The parameters in req do not match the parameters passed to
+        RequestIO.
+
+  33..33..33..  RReeqquueessttIIRRQQ
+
+       int CardServices(RequestIRQ, client_handle_t client, irq_req_t *req);
+
+  The irq_req_t structure is given by:
+
+       typedef struct irq_req_t {
+               u_int           Attributes;
+               u_int           AssignedIRQ;
+               u_int           IRQInfo1, IRQInfo2;
+               void            *(Handler)(int, struct pt_regs *);
+               void            *Instance
+       } irq_req_t;
+
+  RequestIRQ reserves an interrupt line for use by a card.  The IRQInfo1
+  and IRQInfo2 fields correspond to the interrupt description bytes in a
+  CFTABLE_ENTRY tuple.  If IRQ_INFO2_VALID is set in IRQInfo1, then
+  IRQInfo2 is a bit-mapped mask of allowed interrupt values.  Each bit
+  corresponds to one interrupt line: bit 0 = irq 0, bit 1 = irq 1, etc.
+  So, a mask of 0x1100 would mean that interrupts 12 and 8 could be
+  used.  If IRQ_INFO2_VALID is not set, IRQInfo1 is just the desired
+  interrupt number.  If the call is successful, the reserved interrupt
+  is returned in AssignedIRQ.
+
+  If the IRQ_HANDLER_PRESENT flag is set, then this call also specifies
+  an interrupt handler to be installed when the interrupt is enabled.
+  When RequestConfiguration is called, the handler given by Handler will
+  be installed.  For 2.0 and later kernels, the interrupt handler will
+  be installed with the device ``instance'' given in Instance.  For
+  pre-2.1.60 kernels, the kernel irq2dev_map table will also be updated.
+  With multifunction cards, the interrupt will be allocated in shared
+  mode, and the handler(s) have responsibility for determining which
+  card function(s) require attention when an interrupt is received.  If
+  a client instead bypasses Card Services to install its own interrupt
+  service routine, it should allocate the interrupt in shared mode if
+  this client could be bound to a multifunction card.
+
+  The following flags can be specified in Attributes:
+
+     IRQ_FORCED_PULSE
+        Specifies that the interrupt should be configured for pulsed
+        mode, rather than the default level mode.
+
+     IRQ_TYPE_TIME
+        Specifies that this interrupt can be time-shared with other Card
+        Services drivers.  Only one driver should enable the interrupt
+        at any time.
+
+     IRQ_FIRST_SHARED
+        In conjunction with IRQ_TYPE_TIME, this should be set by the
+        first driver requesting a shared interrupt.
+     IRQ_HANDLER_PRESENT
+        Indicates that the Handler field points to an interrupt service
+        routine that should be installed.
+
+  Return codes:
+
+     CS_BAD_HANDLE
+        The client handle is invalid.
+
+     CS_NO_CARD
+        The socket assigned to this client is currently vacant.
+
+     CS_IN_USE
+        An interrupt has already been reserved for this socket, or the
+        requested interrupt is unavailable.
+
+     CS_CONFIGURATION_LOCKED
+        This card function's configuration has been locked by a call to
+        RequestConfiguration.
+
+     CS_BAD_ATTRIBUTE
+        An unsupported attribute flag was specified.
+
+  33..33..44..  RReelleeaasseeIIRRQQ
+
+       int CardServices(ReleaseIRQ, client_handle_t client, irq_req_t *req);
+
+  ReleaseIRQ un-reserves an interrupt assigned by an earlier call to
+  RequestIRQ.  The req structure should be the same structure that was
+  passed to RequestIRQ.  If a handler was specified in the RequestIRQ
+  call, it will be unregistered at this time.
+
+  Return codes:
+
+     CS_BAD_HANDLE
+        The client handle is invalid.
+
+     CS_CONFIGURATION_LOCKED
+        This socket's configuration has been locked by a call to
+        RequestConfiguration.  The configuration should be released
+        before calling ReleaseIRQ.
+
+     CS_BAD_IRQ
+        The parameters in req do not match the parameters passed to
+        RequestIRQ.
+
+  33..33..55..  RReeqquueessttCCoonnffiigguurraattiioonn
+
+       int CardServices(RequestConfiguration, client_handle_t client, config_req_t *req);
+
+  The config_req_t structure is given by:
+
+  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;
+
+  RequestConfiguration is responsible for actually configuring a socket.
+  This includes setting voltages, setting CIS configuration registers,
+  setting up IO port windows, and setting up interrupts.
+
+  IntType specifies the type of interface to use for this card.  It may
+  be INT_MEMORY, INT_MEMORY_AND_IO, or INT_CARDBUS.  Voltages are
+  specified in units of 1/10 volt.  Currently, Vpp1 must equal Vpp2.
+
+  With multifunction cards, each card function is configured separately.
+  Each function has its own set of CIS configuration registers.
+  However, all functions must be configured with the same power and
+  interface settings.
+
+  When invoked by a CardBus client, most of the request structure is
+  ignored, and all card functions will be configured based on data
+  collected in a previous RequestIO call.  This includes configuring the
+  CardBus bridge, as well as initializing the Command, Base Address, and
+  Interrupt Line registers in each card function's configuration space.
+  IntType must be set to INT_CARDBUS in this case.
+
+  The following flags can be specified in Attributes.  DMA and speaker
+  control are not supported on all systems.
+
+     CONF_ENABLE_IRQ
+        Enable the IO interrupt reserved by a previous call to
+        RequestIRQ.
+
+     CONF_ENABLE_DMA
+        Enable DMA accesses for this socket.
+
+     CONF_ENABLE_SPKR
+        Enable speaker output from this socket.
+
+  The Present parameter is a bit map specifying which CIS configuration
+  registers are implemented by this card.  ConfigBase gives the offset
+  of the configuration registers in attribute memory.  The following
+  registers can be specified:
+
+     PRESENT_OPTION
+        Specifies that the Configuration Option Register is present.
+        The COR register will be set using the ConfigIndex parameter.
+
+     PRESENT_STATUS
+        Specifies that the Card Configuration and Status Register is
+        present.  The CCSR will be initialized with the Status
+        parameter.
+
+     PRESENT_PIN_REPLACE
+        Specifies that the Pin Replacement Register is present.  The PRR
+        will be initialized with the Pin parameter.
+
+     PRESENT_COPY
+        Specifies that the Socket and Copy Register is present.  The SCR
+        will be initialized with the Copy parameter.
+
+     PRESENT_EXT_STATUS
+        Specifies that the Extended Status Register is present.  The ESR
+        will be initialized with the ExtStatus parameter.
+
+  Return codes:
+
+     CS_BAD_HANDLE
+        The client handle is invalid.
+
+     CS_NO_CARD
+        The socket assigned to this client is currently vacant.
+
+     CS_OUT_OF_RESOURCE
+        Card Services was unable to allocate a memory window to access
+        the card's configuration registers.
+
+     CS_CONFIGURATION_LOCKED
+        This card's configuration has already been locked by another
+        call to RequestConfiguration.
+
+     CS_BAD_VCC
+        The requested Vcc voltage is not supported.
+
+     CS_BAD_VPP
+        The requested Vpp1/Vpp2 voltage is not supported.
+
+     CS_UNSUPPORTED_MODE
+        A non-CardBus client attempted to configure a CardBus card, or a
+        CardBus client attempted to configure a non-CardBus card.
+
+  33..33..66..  MMooddiiffyyCCoonnffiigguurraattiioonn
+
+       int CardServices(ModifyConfiguration, client_handle_t client, modconf_t *mod);
+
+  The modconf_t structure is given by:
+
+       typedef struct modconf_t {
+               u_int           Attributes;
+               u_int           Vcc, Vpp1, Vpp2;
+       } modconf_t;
+
+  ModifyConfiguration modifies some attributes of a socket that has been
+  configured by a call to RequestConfiguration.
+
+  The following flags can be specified in Attributes:
+
+     CONF_IRQ_CHANGE_VALID
+        Indicates that the CONF_ENABLE_IRQ setting should be updated.
+
+     CONF_ENABLE_IRQ
+        Specifies that IO interrupts should be enabled for this socket.
+
+     CONF_VCC_CHANGE_VALID
+        Indicates that Vcc should be updated.
+
+     CONF_VPP1_CHANGE_VALID
+        Indicates that Vpp1 should be updated.
+
+     CONF_VPP2_CHANGE_VALID
+        Indicates that Vpp2 should be updated.
+
+  Currently, Vpp1 and Vpp2 must always have the same value.  So, the two
+  values must always be changed at the same time.
+
+  Return codes:
+
+     CS_BAD_HANDLE
+        The client handle is invalid.
+
+     CS_NO_CARD
+        The socket assigned to this client is currently vacant.
+
+     CS_CONFIGURATION_LOCKED
+        This actually means that this socket has nnoott been locked.
+
+     CS_BAD_VCC
+        The requested Vcc voltage is not supported.
+
+     CS_BAD_VPP
+        The requested Vpp1/Vpp2 voltage is not supported.
+
+  33..33..77..  RReelleeaasseeCCoonnffiigguurraattiioonn
+
+       int CardServices(ReleaseConfiguration, client_handle_t client, config_req_t *req);
+
+  ReleaseConfiguration un-configures a socket previously set up by a
+  call to RequestConfiguration.  The req parameter should be the same
+  one used to configure the socket.
+
+  Return codes:
+
+     CS_BAD_HANDLE
+        The window handle is invalid, or the socket is not configured.
+
+  33..33..88..  GGeettCCoonnffiigguurraattiioonnIInnffoo
+
+       int CardServices(GetConfigurationInfo, client_handle_t client, config_info_t *config);
+
+  The config_info_t structure is given by:
+
+  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           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;
+
+  GetConfigurationInfo returns the current socket configuration as it
+  was set up by RequestIO, RequestIRQ, and RequestConfiguration.  It can
+  only be applied to a fully configured socket.  For normal clients
+  bound to a single card function, the Function field is ignored, and
+  data for that client's assigned function is returned.  For clients
+  bound to BIND_FN_ALL, this field specifies which function's
+  configuration data should be returned.
+
+  Return codes:
+
+     CS_BAD_HANDLE
+        The window handle is invalid, or the socket is not configured.
+
+     CS_NO_CARD
+        The socket assigned to this client is currently vacant.
+
+     CS_CONFIGURATION_LOCKED
+        This actually means that the configuration has nnoott been locked.
+
+  33..44..  CCaarrdd IInnffoorrmmaattiioonn SSttrruuccttuurree ((CCIISS)) ccaallllss
+
+  The definition of the Card Information Structure (CIS) is the darkest
+  chapter of the PC Card standard.  All version 2 compliant cards should
+  have a CIS, which describes the card and how it should be configured.
+  The CIS is a linked list of ``tuples'' in the card's attribute memory
+  space.  Each tuple consists of an identification code, a length byte,
+  and a series of data bytes.  The layout of the data bytes for some
+  tuple types is absurdly complicated, in an apparent effort to use
+  every last bit.
+
+  The ValidateCIS call checks to see if a card has a reasonable CIS.
+  The GetFirstTuple and GetNextTuple calls are used to step through CIS
+  tuple lists.  GetTupleData extracts data bytes from a tuple.  And
+  ParseTuple unpacks most tuple types into more easily used forms.
+  Finally, the ReplaceCIS call allows a client to provide Card Services
+  with a substitute for the CIS found on the card.
+
+  33..44..11..  GGeettFFiirrssttTTuuppllee,, GGeettNNeexxttTTuuppllee
+
+       #include "cistpl.h"
+
+       int CardServices(GetFirstTuple, client_handle_t client, tuple_t *tuple);
+       int CardServices(GetNextTuple, client_handle_t client, tuple_t *tuple);
+
+  The tuple_t data structure is given by:
+
+       typedef struct tuple_t {
+               u_int           Attributes;
+               cis_data_t      DesiredTuple;
+               u_int           Flags;
+               cisdata_t       TupleCode;
+               u_int           TupleLink;
+               cisdata_t       TupleOffset;
+               cisdata_t       TupleDataMax;
+               cisdata_t       TupleDataLen;
+               cisdata_t       *TupleData;
+       } tuple_t;
+
+  GetFirstTuple searches a card's CIS for the first tuple code matching
+  DesiredTuple.  The special code RETURN_FIRST_TUPLE will match the
+  first tuple of any kind.  If successful, TupleCode is set to the code
+  of the first matching tuple found, and TupleLink is the address of
+  this tuple in attribute memory.
+
+  GetNextTuple is like GetFirstTuple, except that given a tuple_t
+  structure returned by a previous call to GetFirstTuple or
+  GetNextTuple, it will return the next tuple matching DesiredTuple.
+
+  These functions will automatically traverse any link tuples found in
+  the CIS.  For multifunction cards having a CISTPL_LONGLINK_MFC tuple,
+  these functions will automatically follow just the CIS chain specific
+  to a client driver's assigned function.  If a client was bound to
+  BIND_FN_ALL, then all tuples will be returned.
+
+  The following flags can be specified in Attributes:
+
+     TUPLE_RETURN_LINK
+        Indicates that link tuples (CISTPL_LONGLINK_A,
+        CISTPL_LONGLINK_C, CISTPL_LONGLINK_MFC, CISTPL_NOLINK,
+        CISTPL_LINKTARGET) should be returned.  Normally these tuples
+        are processed silently.
+
+     TUPLE_RETURN_COMMON
+        Indicates that tuples in the ``common'' CIS section of a
+        multifunction CIS should be returned.  In the absence of this
+        flag, normally, Card Services will only return tuples specific
+        to the function bound to the client.
+
+  Return codes:
+
+     CS_BAD_HANDLE
+        The client handle is invalid.
+
+     CS_OUT_OF_RESOURCE
+        Card Services was unable to set up a memory window to map the
+        card's CIS.
+
+     CS_NO_MORE_ITEMS
+        There were no tuples matching DesiredTuple.
+
+  33..44..22..  GGeettTTuupplleeDDaattaa
+
+       #include "cistpl.h"
+
+       int CardServices(GetTupleData, client_handle_t client, tuple_t *tuple);
+
+  GetTupleData extracts a series of data bytes from the specified tuple,
+  which must have been returned by a previous call to GetFirstTuple or
+  GetNextTuple.  A maximum of TupleDataMax bytes will be copied into the
+  TupleData buffer, starting at an offset of TupleOffset bytes.  The
+  number of bytes copied is returned in TupleDataLen.
+
+  Return codes:
+
+     CS_BAD_HANDLE
+        The client handle is invalid.
+
+     CS_OUT_OF_RESOURCE
+        Card Services was unable to set up a memory window to map the
+        card's CIS.
+
+     CS_NO_MORE_ITEMS
+        The tuple does not contain any more data.  TuppleOffset is
+        greater than or equal to the length of the tuple.
+
+  33..44..33..  PPaarrsseeTTuuppllee
+
+       #include "cistpl.h"
+
+       int CardServices(ParseTuple, client_handle_t client, tuple_t *tuple, cisparse_t *parse);
+
+  The cisparse_t data structure is given by:
+
+  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_config_t         config;
+          cistpl_cftable_entry_t  cftable_entry;
+          cistpl_device_geo_t     device_geo;
+          cistpl_vers_2_t         version_2;
+          cistpl_org_t            org;
+  } cisparse_t;
+
+  ParseTuple interprets tuple data returned by a previous call to
+  GetTupleData.  The structure returned depends on the type of the
+  parsed tuple.  See the cistpl.h file for these structure definitions;
+  some of them are quite complex.
+
+  Return codes:
+
+     CS_BAD_TUPLE
+        An error was encounted during parsing of this tuple.  The tuple
+        may be incomplete, or may be formatted incorrectly.
+
+     CS_UNSUPPORTED_FUNCTION
+        ParseTuple cannot parse the specified tuple type.
+
+  33..44..44..  VVaalliiddaatteeCCIISS
+
+       int CardServices(ValidateCIS, client_handle_t client, cisinfo_t *cisinfo);
+
+  The cisinfo_t structure is given by:
+
+       typedef struct cisinfo_t {
+               u_int           Chains;
+       } cisinfo_t;
+
+  ValidateCIS attempts to verify that a card has a reasonable Card
+  Information Structure.  It returns the number of tuples found in
+  Chains.  If the CIS appears to be uninterpretable, Chains will be set
+  to 0.
+
+  Return codes:
+
+     CS_BAD_HANDLE
+        The client handle is invalid.
+
+     CS_OUT_OF_RESOURCE
+        Card Services was unable to set up a memory window to map the
+        card's CIS.
+
+  33..44..55..  RReeppllaacceeCCIISS
+
+       int CardServices(ReplaceCIS, client_handle_t client, cisdump_t *cisinfo);
+
+  The cisdump_t structure is given by:
+
+       typedef struct cisdump_t {
+               u_int           Length;
+               cisdata_t       Data[CISTPL_MAX_CIS_SIZE];
+       } cisinfo_t;
+
+  ReplaceCIS allows a client to pass Card Services a replacement for the
+  CIS found on a card.  Its intended application is for cards with
+  incomplete or inaccurate CIS information.  If a correct CIS can be
+  deduced from other information available for the card, this allows
+  that information to be provided to clients in a clean fashion.  The
+  alternative is to pollute client source code with fixes targeted for
+  each card with a CIS error.  The replacement CIS remains in effect
+  until the card is ejected, and all tuple-related services will use the
+  replacement instead of the card's actual CIS.
+
+  The Length field gives the number of bytes of CIS data in the Data
+  array.  The Data array can be considered to be just the even bytes of
+  a card's attribute memory.  It should contain all required features of
+  a normal CIS, including an initial CISTPL_DEVICE tuple and a final
+  CISTPL_END tuple.  Long links (including CISTPL_LONGLINK_MFC) may be
+  used: all target addresses are interpreted in the replacement CIS
+  space.  In general, a replacement CIS should also contain the same
+  basic identification tuples (CISTPL_MANFID, CISTPL_VERS_1) as the
+  original card.
+
+  This service was added in release 3.0.1.
+
+  Return codes:
+
+     CS_BAD_HANDLE
+        The client handle is invalid.
+
+     CS_OUT_OF_RESOURCE
+        Card Services was unable to allocate memory to hold the
+        replacement CIS.
+
+  33..55..  MMeemmoorryy wwiinnddooww ccoonnttrrooll
+
+  Each socket can have up to four active memory windows, mapping
+  portions of card memory into the host system address space.  A PC Card
+  device can address at most 16MB of both common and attribute memory.
+  Windows should typically be sized to a power of two.  Depending on
+  socket capabilities, they may need to be aligned on a boundary that is
+  a multiple of the window size in both the host and card address
+  spaces.
+
+  A memory window is initialized by a call to RequestWindow.  Some
+  window attributes can be modified using ModifyWindow.  The segment of
+  card memory mapped to the window can be modified using MapMemPage.
+  And windows are released with ReleaseWindow.  Unlike almost all other
+  Card Services subfunctions, the memory window functions normally act
+  on window_handle_t handles, rather than client_handle_t handles.
+
+  33..55..11..  RReeqquueessttWWiinnddooww
+
+       int CardServices(RequestWindow, client_handle_t *handle, win_req_t *req);
+
+  The win_req_t structure is given by:
+
+       typedef struct win_req_t {
+               u_int           Attributes;
+               u_long          Base;
+               u_int           Size;
+               u_int           AccessSpeed;
+       } win_req_t;
+
+  RequestWindow maps a window of card memory into system memory.  On
+  entry, the handle parameter should point to a valid client handle.  On
+  return, this will be replaced by a window_handle_t handle that should
+  be used in subsequent calls to ModifyWindow, MapMemPage, and
+  ReleaseWindow.
+
+  The following flags can be specified in Attributes:
+
+     WIN_MEMORY_TYPE
+        This field can be either WIN_MEMORY_TYPE_CM for common memory,
+        or WIN_MEMORY_TYPE_AM for attribute memory.
+
+     WIN_DATA_WIDTH
+        Either WIN_DATA_WIDTH_16 for 16-bit accesses, or
+        WIN_DATA_WIDTH_8 for 8-bit access.
+
+     WIN_ENABLE
+        If this is set, the window is turned on.
+
+     WIN_USE_WAIT
+        Specifies that the controller should observe the card's MWAIT
+        signal.
+
+     WIN_MAP_BELOW_1MB
+        Requests that the window be mapped below the 1MB address
+        boundary.  This may not be possible on some platforms.
+
+     WIN_STRICT_ALIGN
+        Requests that the window base be aligned to a multiple of the
+        window size.  Added in release 3.1.2.
+
+  Base specifies the base physical address of the window in system
+  memory.  If zero, Card Services will set Base to the first available
+  window address.  Size specifies the window size in bytes.  If zero,
+  Card Services will set Size to the smallest window size supported by
+  the host controller.  AccessSpeed specifies the memory access speed,
+  in nanoseconds.
+
+  Return codes:
+
+     CS_BAD_HANDLE
+        The client handle is invalid.
+
+     CS_NO_CARD
+        The socket assigned to this client is currently vacant.
+
+     CS_BAD_ATTRIBUTE
+        An unsupported window attribute was requested.
+
+     CS_OUT_OF_RESOURCE
+        The maximum number of memory windows for this socket are already
+        being used.
+
+     CS_IN_USE
+        RequestWindow was unable to find a free window of system memory.
+
+     CS_BAD_SIZE
+        ,
+
+     CS_BAD_BASE
+        Either Base or Size does not satisfy the alignment rules for
+        this socket.
+
+  33..55..22..  MMooddiiffyyWWiinnddooww
+
+       int CardServices(ModifyWindow, window_handle_t handle, modwin_t *mod);
+
+  The modwin_t structure is given by:
+
+       typedef struct modwin_t {
+               u_int           Attributes;
+               u_int           AccessSpeed;
+       } modwin_t;
+
+  ModifyWindow modifies the attributes of a window handle returned by a
+  previous call to RequestWindow.  The following attributes can be
+  changed:
+
+     WIN_MEMORY_TYPE
+        This field can be either WIN_MEMORY_TYPE_CM for common memory,
+        or WIN_MEMORY_TYPE_AM for attribute memory.
+
+     WIN_DATA_WIDTH
+        Either WIN_DATA_WIDTH_16 for 16-bit accesses, or
+        WIN_DATA_WIDTH_8 for 8-bit access.
+
+     WIN_ENABLE
+        If this is set, the window is turned on.
+
+  AccessSpeed gives the new memory access speed, in nanoseconds.
+
+  Return codes:
+
+     CS_BAD_HANDLE
+        The window handle is invalid.
+
+  33..55..33..  RReelleeaasseeWWiinnddooww
+
+       int CardServices(ReleaseWindow, window_handle_t handle);
+
+  ReleaseWindow releases a memory window previously allocated with
+  RequestWindow.
+
+  Return codes:
+
+     CS_BAD_HANDLE
+        The window handle is invalid.
+
+  33..55..44..  GGeettFFiirrssttWWiinnddooww,, GGeettNNeexxttWWiinnddooww
+
+       int CardServices(GetFirstWindow, client_handle_t *client, win_req_t *req);
+       int CardServices(GetNextWindow, window_handle_t *handle, win_req_t *req);
+
+  These calls sequentially retrieve window configuration information for
+  all of a socket's memory windows.  GetFirstWindow replaces the client
+  window handle with a memory window handle, which will in turn be
+  updated by calls to GetNextWindow.
+
+  These services were added in release 3.1.0.
+
+  Return codes:
+
+     CS_BAD_HANDLE
+        The client handle is invalid.
+
+     CS_NO_MORE_ITEMS
+        No more windows ara configured for this socket.
+
+  33..55..55..  MMaappMMeemmPPaaggee,, GGeettMMeemmPPaaggee
+
+       int CardServices(MapMemPage, window_handle_t handle, memreq_t *req);
+       int CardServices(GetMemPage, window_handle_t handle, memreq_t *req);
+
+  The memreq_t structure is given by:
+
+       typedef struct memreq_t {
+               u_int           CardOffset;
+               page_t          Page;
+       } memreq_t;
+
+  MapMemPage sets the address of card memory that is mapped to the base
+  of a memory window to CardOffset.  The window should have been created
+  by a call to RequestWindow.  The Page parameter is not implemented in
+  this version and should be set to 0.  In turn GetMemPage retrieves the
+  current card address mapping for a memory window.
+
+  The GetMemPage service was added in release 3.1.0.
+
+  Return codes:
+
+     CS_BAD_HANDLE
+        The window handle is invalid.
+
+     CS_BAD_PAGE
+        The Page value was non-zero.
+
+     CS_BAD_OFFSET
+        The requested CardOffset was out of range or did not have proper
+        alignment.
+
+  33..66..  BBuullkk MMeemmoorryy SSeerrvviicceess
+
+  Bulk memory services provide a higher level interface for accessing
+  memory regions than that provided by the memory window services.  A
+  client using bulk memory calls does not need to know anything about
+  the underlying memory organization or access methods.  The device-
+  specific code is packaged into a special Card Services client called a
+  Memory Technology Driver.
+
+  33..66..11..  RReeggiisstteerrMMTTDD
+
+       int CardServices(RegisterMTD, client_handle_t handle, mtd_reg_t *reg);
+
+  The mtd_reg_t data structure is given by:
+
+       typedef union mtd_reg_t {
+               u_int           Attributes;
+               u_int           Offset;
+               u_long          MediaID;
+       } mtd_reg_t;
+
+  RegisterMTD informs Card Services that this client MTD will handle
+  requests for a specified memory region.  The Offset field specifies
+  the starting address of the memory region.  The following fields are
+  defined in Attributes:
+
+     REGION_TYPE
+        Either REGION_TYPE_CM for common memory, or REGION_TYPE_AM for
+        attribute memory.
+
+  The MediaID field is recorded by Card Services, and will be passed to
+  the MTD as part of any request that references this memory region.
+
+  Once an MTD is bound to a memory region by a call to RegisterMTD, it
+  will remain bound until the MTD calls DeregisterClient.
+
+  Return codes:
+
+     CS_BAD_HANDLE
+        The client handle is invalid.
+
+     CS_BAD_OFFSET
+        Either the offset does not match a valid memory region for this
+        card, or another MTD has already registered for this region.
+
+  33..66..22..  GGeettFFiirrssttRReeggiioonn,, GGeettNNeexxttRReeggiioonn
+
+       int CardServices(GetFirstRegion, client_handle_t handle, region_info_t *region);
+       int CardServices(GetNextRegion, client_handle_t handle, region_info_t *region);
+
+  The region_info_t data structure is given by:
+
+       typedef union 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;
+
+  GetFirstRegion and GetNextRegion summarize the information in a card's
+  CISTPL_DEVICE, CISTPL_JEDEC, and CISTPL_DEVICE_GEO tuples.  CardOffset
+  gives the starting address of a region. RegionSize gives the length of
+  the region in bytes.  AccessSpeed gives the device's cycle time in
+  nanoseconds.  BlockSize gives the erase block size in bytes, and
+  PartMultiple gives the minimum granularity of partitions on this
+  device, in units of BlockSize.  JedecMfr and JedecInfo give the JEDEC
+  identification bytes for this region.
+
+  The following fields are defined in Attributes:
+
+     REGION_TYPE
+        Either REGION_TYPE_CM for common memory, or REGION_TYPE_AM for
+        attribute memory.
+
+  When these calls are made by an MTD client, only regions that have
+  been bound to this client through calls to BindMTD will be returned.
+
+  Return codes:
+
+     CS_BAD_HANDLE
+        The client handle is invalid.
+
+     CS_NO_MORE_ITEMS
+        No more memory regions are defined.
+
+  33..66..33..  OOppeennMMeemmoorryy
+
+       int CardServices(OpenMemory, client_handle_t *handle, open_mem_t *req);
+
+  The open_mem_t structure is given by:
+
+       typedef struct open_mem_t {
+               u_int           Attributes;
+               u_int           Offset;
+       } open_mem_t;
+
+  OpenMemory is used to obtain a handle for accessing a memory region
+  via the other bulk memory services.  The Offset field specifies the
+  base address of the region to be accessed.  If successful, the client
+  handle argument is replaced by the new memory handle.
+
+  The following fields are defined in Attributes:
+
+     MEMORY_TYPE
+        Either MEMORY_TYPE_CM for common memory, or MEMORY_TYPE_AM for
+        attribute memory.
+
+     MEMORY_EXCLUSIVE
+        Specifies that this client should have exclusive access to this
+        memory region.
+
+  Return codes:
+
+     CS_BAD_HANDLE
+        The window handle is invalid.
+
+     CS_BAD_OFFSET
+        Either the offset does not specify a valid region, or the region
+        does not have an associated MTD to service bulk memory requests.
+
+  33..66..44..  CClloosseeMMeemmoorryy
+
+       int CardServices(CloseMemory, memory_handle_t handle);
+
+  CloseMemory releases a memory handle returned by a previous call to
+  OpenMemory.  A client should release all memory handles before calling
+  DeregisterClient.
+
+  Return codes:
+
+     CS_BAD_HANDLE
+        The memory handle is invalid.
+
+  33..66..55..  RReeaaddMMeemmoorryy,, WWrriitteeMMeemmoorryy
+
+       int CardServices(ReadMemory, memory_handle_t handle mem_op_t *req, caddr_t buf);
+       int CardServices(WriteMemory, memory_handle_t handle, mem_op_t *req, caddr_t buf);
+
+  The mem_io_t structure is given by:
+
+       typedef struct mem_op_t {
+               u_int           Attributes;
+               u_int           Offset;
+               u_int           Count;
+       } mem_op_t;
+
+  ReadMemory and WriteMemory read from and write to a card memory area
+  defined by the specified memory handle, returned by a previous call to
+  OpenMemory.  The Offset field gives the offset of the operation from
+  the start of the card memory region.  The Count field gives the number
+  of bytes to be transferred.  The buf field points to a host memory
+  buffer to be the destination for a ReadMemory operation, or the source
+  for a WriteMemory operation.
+
+  The following fields are defined in Attributes:
+
+     MEM_OP_BUFFER
+        Either MEM_OP_BUFFER_USER if the host buffer is in a user memory
+        segment, or MEM_OP_BUFFER_KERNEL if the host buffer is in kernel
+        memory.
+
+     MEM_OP_DISABLE_ERASE
+        Specifies that a card area should not be erased before it is
+        written.
+
+     MEM_OP_VERIFY
+        Specifies verification of write operations.
+
+  Return codes:
+
+     CS_BAD_HANDLE
+        The window handle is invalid.
+
+     CS_BAD_OFFSET
+        The specified card offset is beyond the end of the memory
+        region.
+
+     CS_BAD_SIZE
+        The specified transfer size extends past the end of the memory
+        region.
+
+  33..66..66..  RReeggiisstteerrEErraasseeQQuueeuuee
+
+       int CardServices(RegisterEraseQueue, client_handle_t *handle, eraseq_hdr_t *header);
+
+  The eraseq_hdr_t structure is given by:
+
+       typedef struct erase_queue_header_t {
+               int             QueueEntryCount;
+               eraseq_entry_t  *QueueEntryArray;
+       } eraseq_hdr_t;
+
+  This call registers a queue of erase requests with Card Services.  An
+  eraseq_handle_t handle will be returned in *handle.  When this client
+  calls CheckEraseQueue, Card Services will scan the queue and begin
+  asynchronous processing of any new requests.
+
+  The eraseq_entry_t structure is given by:
+
+       typedef struct eraseq_entry_t {
+               memory_handle_t Handle;
+               u_char          State;
+               u_int           Size;
+               u_int           Offset;
+               void            *Optional;
+       } eraseq_entry_t;
+
+  In an erase queue entry, the Header field should be a memory handle
+  returned by a previous call to OpenMemory.  The State field indicates
+  the state of the erase request.  The following values are defined:
+
+     ERASE_QUEUED
+        Set by the client to indicate that this is a new request.
+
+     ERASE_IDLE
+        Set by the client to indicate that this entry is not active.
+
+     ERASE_PASSED
+        Set by the MTD to indicate successful completion.
+
+     ERASE_FAILED
+        Set by the MTD to indicate that the erase failed.
+
+     ERASE_MEDIA_WRPROT
+        Indicates that the region is write protected.
+
+     ERASE_NOT_ERASABLE
+        Indicates that this region does not support erase operations.
+
+     ERASE_BAD_OFFSET
+        Indicates that the erase does not start on an erase block
+        boundary.
+
+     ERASE_BAD_SIZE
+        Indicates that the requested erase size is not a multiple of the
+        erase block size.
+
+     ERASE_BAD_SOCKET
+        Set by the MTD to indicate that there is no card present.
+
+  Additionally, the macro ERASE_IN_PROGRESS() will return a true
+  condition for values of State that indicate an erase is being
+  processed.
+
+  The Size field gives the size of the erase request in bytes.  The
+  Offset field gives the offset from the start of the region.  The size
+  and offset should be aligned to erase block boundaries.  The Optional
+  field is not used by Card Services and may be used by the client
+  driver.
+
+  Return codes:
+
+     CS_BAD_HANDLE
+        The client handle is invalid.
+
+  33..66..77..  DDeerreeggiisstteerrEErraasseeQQuueeuuee
+
+       int CardServices(DeregisterEraseQueue, eraseq_handle_t handle);
+
+  DeregisterEraseQueue frees a queue previously registered by a call to
+  RegisterEraseQueue.  If there are any pending requests in the
+  specified queue, the call will fail.
+
+  Return codes:
+
+     CS_BAD_HANDLE
+        The erase queue handle is invalid.
+
+     CS_BUSY
+        The erase queue has erase requests pending.
+
+  33..66..88..  CChheecckkEErraasseeQQuueeuuee
+
+       int CardServices(CheckEraseQueue, eraseq_handle_t handle);
+
+  This call notifies Card Services that there are new erase requests in
+  a queue previously registered with RegisterEraseQueue.
+
+  Typically, a client will initially assign each erase queue entry the
+  state value ERASE_IDLE.  When new requests are added to the queue, the
+  client will set their states to ERASE_QUEUED, and call
+  CheckEraseQueue.  When the client is notified of an erase completion
+  event, it will check the state field to determine whether the request
+  was successful.
+
+  Return codes:
+
+     CS_BAD_HANDLE
+        The erase queue handle is invalid.
+
+  33..77..  MMiisscceellllaanneeoouuss ccaallllss
+
+  33..77..11..  GGeettCCaarrddSSeerrvviicceessIInnffoo
+
+       int CardServices(GetCardServicesInfo, servinfo_t *info);
+
+  The servinfo_t structure is given by:
+
+       typedef struct servinfo_t {
+               char            Signature[2];
+               u_int           Count;
+               u_int           Revision;
+               u_int           CSLevel;
+               char            *VendorString;
+       } servinfo_t;
+
+  GetCardServicesInfo returns revision information about this version of
+  Card Services.  Signature is set to ``CS''.  Count is set to the
+  number of sockets currently configured.  Revision is set to the
+  revision level of the Card Services package, and CSLevel is set to the
+  level of compliance with the PC Card standard.  These are encoded as
+  BCD numbers.  VendorString is set to point to an RCS identification
+  string.
+
+  This call always succeeds.
+
+  33..77..22..  AAcccceessssCCoonnffiigguurraattiioonnRReeggiisstteerr
+
+       #include "cisreg.h"
+
+       int CardServices(AccessConfigurationRegister, client_handle_t handle, conf_reg_t *reg);
+
+  The conf_reg_t structure is given by:
+       typedef struct conf_reg_t {
+               u_char          Function;
+               u_int           Action;
+               off_t           Offset;
+               u_int           Value;
+       } conf_reg_t;
+
+  For normal clients bound to a specific card function, the Function
+  field is ignored.  For clients bound to BIND_FN_ALL, this field
+  specifies which function's configuration registers should be accessed.
+
+  The Action parameter can be one of the following:
+
+     CS_READ
+        Read the specified configuration register and return Value.
+
+     CS_WRITE
+        Write Value to the specified configuration register.
+
+  AccessConfigurationRegister either reads or writes the one-byte CIS
+  configuration register at offset Offset from the start of the config
+  register area.  It can only be used for a socket that has been
+  configured with RequestConfiguration.
+
+  The following values for Offset are defined in cistpl.h:
+
+     CISREG_COR
+        The Configuration Option Register.
+
+     CISREG_CCSR
+        The Card Configuration and Status Register.
+
+     CISREG_PRR
+        The Pin Replacement Register.
+
+     CISREG_SCR
+        The Socket and Copy Register.
+
+     CISREG_ESR
+        The Extended Status Register.
+
+     CISREG_IOBASE0..CISREG_IOBASE3
+        The I/O Base Registers.
+
+     CISREG_IOSIZE
+        The I/O Size Register.
+
+  Return codes:
+
+     CS_BAD_HANDLE
+        The client handle is invalid.
+
+     CS_BAD_ARGS
+        The specified Action is not supported.
+
+     CS_CONFIGURATION_LOCKED
+        This actually means that the configuration has nnoott been locked.
+
+     CS_OUT_OF_RESOURCE
+        Card Services was unable to allocate a memory window to access
+        the card's configuration registers.
+
+  33..77..33..  AAddjjuussttRReessoouurrcceeIInnffoo
+
+       int CardServices(AdjustResourceInfo, client_handle_t handle, adjust_t *adj);
+
+  The adjust_t structure is given by:
+
+       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;
+
+  AdjustResourceInfo is used to tell Card Services what resources may or
+  may not be allocated by PC Card devices.  The normal Linux resource
+  management systems (the *_region calls for IO ports, interrupt
+  allocation) are respected by Card Services, but this call gives the
+  user another level of control.
+
+  The Action parameter can have the following values:
+
+     ADD_MANAGED_RESOURCE
+        Place the specified resource under Card Services control, so
+        that it may be allocated by PC Card devices.
+
+     REMOVE_MANAGED_RESOURCE
+        Remove the specified resource from Card Services control.
+
+  At initialization time, Card Services assumes that it can use all
+  available interrupts, but IO ports and memory regions must be
+  explicitly enabled with ADD_MANAGED_RESOURCE.
+
+  The Resource parameter can have the following values:
+
+     RES_MEMORY_RANGE
+        Specifies a memory range resource, described by
+        adj->resource.memory.
+
+     RES_IO_RANGE
+        Specifies an IO port resource, described by adj->resource.io.
+
+     RES_IRQ
+        Specifies an interrupt resource, described by adj->resource.irq.
+
+  The following flags may be specified in Attributes:
+
+     RES_RESERVED
+        Indicates that the resource should be reserved for PC Card
+        devices that specifically request it.  The resource will not be
+        allocated for a device that asks Card Services for any available
+        location.  This is not implemented yet.
+
+  Return codes:
+
+     CS_UNSUPPORTED_FUNCTION
+        The specified Action or Resource is not supported.
+
+     CS_BAD_BASE
+        The specified IO address is out of range.
+
+     CS_BAD_SIZE
+        The specified memory or IO window size is out of range.
+
+     CS_IN_USE
+        The specified interrupt is currently allocated by a Card
+        Services client.
+
+  33..77..44..  RReeppoorrttEErrrroorr
+
+       int CardServices(ReportError, client_handle_t handle, error_info_t *err);
+
+  The error_info_t structure is given by:
+
+       typedef struct error_info_t {
+               int             func;
+               int             retcode;
+       } error_info_t;
+
+  ReportError generates a kernel error message given a Card Services
+  function code and its return code.  If the client handle is valid,
+  then the error will be prefixed with the client driver's name.  For
+  example:
+
+       error_info_t err = { RequestIO, CS_BAD_HANDLE };
+       CardServices(ReportError, handle, &err);
+
+  could generate the following message:
+
+       serial_cs: RequestIO: Bad handle
+
+  This call always succeeds.
+
+  44..  CCaarrdd IInnffoorrmmaattiioonn SSttrruuccttuurree DDeeffiinniittiioonnss
+
+  44..11..  CCIISS TTuuppllee DDeeffiinniittiioonnss
+
+  The Card Services ParseTuple function interprets raw CIS tuple data
+  from a call to GetTupleData and returns the tuple contents in a form
+  dependant on the tuple type.  This section describes the parsed tuple
+  contents.
+
+       #include "cistpl.h"
+
+  44..11..11..  CCIISSTTPPLL__CCHHEECCKKSSUUMM
+
+  The cistpl_checksum_t structure is given by:
+
+       typedef struct cistpl_checksum_t {
+               u_short         addr;
+               u_short         len;
+               u_char          sum;
+       } cistpl_checksum_t;
+
+  44..11..22..  CCIISSTTPPLL__NNOOLLIINNKK CCIISSTTPPLL__LLOONNGGLLIINNKK__AA,, CCIISSTTPPLL__LLOONNGGLLIINNKK__CC,,
+  CCIISSTTPPLL__LLIINNKKTTAARRGGEETT,,
+
+  The cistpl_longlink_t structure is given by:
+
+       typedef struct cistpl_longlink_t {
+               u_int           addr;
+       } cistpl_longlink_t;
+
+  These tuples are pointers to additional chains of CIS tuples, either
+  in attribute or common memory.  Each CIS tuple chain can have at most
+  one long link.  CISTPL_LONGLINK_A tuples point to attribute memory,
+  and CISTPL_LONGLINK_C tuples point to common memory.  The standard CIS
+  chain starting at address 0 in attribute memory has an implied long
+  link to address 0 in common memory.  A CISTPL_NOLINK tuple can be used
+  to cancel this default link.
+
+  The first tuple of a chain pointed to by a long link must be a
+  CISTPL_LINKTARGET.  The CS tuple handling code will automatically
+  follow long links and verify link targets; these tuples are normally
+  invisible unless the TUPLE_RETURN_LINK attribute is specified in
+  GetNextTuple.
+
+  44..11..33..  CCIISSTTPPLL__LLOONNGGLLIINNKK__MMFFCC
+
+  The cistpl_longlink_mfc_t structure is given by:
+
+       typedef struct cistpl_longlink_mfc_t {
+               int     nfn;
+               struct {
+                       u_char  space;
+                       u_int   addr;
+               } fn[CISTPL_MAX_FUNCTIONS;
+       } cistpl_longlink_mfc_t;
+
+  This tuple identifies a multifunction card, and specifies long link
+  pointers to CIS chains specific for each function.  The space field is
+  either CISTPL_MFC_ATTR or CISTPL_MFC_COMMON for attribute or common
+  memory space.
+
+  44..11..44..  CCIISSTTPPLL__DDEEVVIICCEE,, CCIISSTTPPLL__DDEEVVIICCEE__AA
+
+  The cistpl_device_t structure is given by:
+
+       typedef struct cistpl_device_t {
+               int             ndev;
+               struct {
+                       u_char          type;
+                       u_char          wp;
+                       u_int           speed;
+                       u_int           size;
+               } dev[CISTPL_MAX_DEVICES];
+       } cistpl_device_t;
+
+  The CISTPL_DEVICE tuple describes address regions in a card's common
+  memory.  The CISTPL_DEVICE_A tuple describes regions in attribute
+  memory.  The type flag indicates the type of memory device for this
+  region.  The wp flag indicates if this region is write protected.  The
+  speed field is in nanoseconds, and size is in bytes.  Address regions
+  are assumed to be ordered consecutively starting with address 0.  The
+  following device types are defined:
+
+     CISTPL_DTYPE_NULL
+        Specifies that there is no device, or a ``hole'' in the card
+        address space.
+
+     CISTPL_DTYPE_ROM
+        Masked ROM
+     CISTPL_DTYPE_OTPROM
+        One-type programmable ROM.
+
+     CISTPL_DTYPE_EPROM
+        UV erasable PROM.
+
+     CISTPL_DTYPE_EEPROM
+        Electrically erasable PROM.
+
+     CISTPL_DTYPE_FLASH
+        Flash EPROM.
+
+     CISTPL_DTYPE_SRAM
+        Static or non-volatile RAM.
+
+     CISTPL_DTYPE_DRAM
+        Dynamic or volatile RAM.
+
+     CISTPL_DTYPE_FUNCSPEC
+        Specifies a function-specific device, such as a memory-mapped IO
+        device or buffer, as opposed to general purpose storage.
+
+     CISTPL_DTYPE_EXTEND
+        Specifies an extended device type.  This type is reserved for
+        future use.
+
+  44..11..55..  CCIISSTTPPLL__VVEERRSS__11
+
+  The cistpl_vers_1_t structure is given by:
+
+       typedef struct cistpl_vers_1_t {
+               u_char          major;
+               u_char          minor;
+               int             ns;
+               int             ofs[CISTPL_VERS_1_MAX_PROD_STRINGS];
+               char            str[254];
+       } cistpl_vers_1_t;
+
+  The ns field specifies the number of product information strings in
+  the tuple.  The string data is contained in the str array.  Each
+  string is null terminated, and ofs gives the offset to the start of
+  each string.
+
+  44..11..66..  CCIISSTTPPLL__AALLTTSSTTRR
+
+  The cistpl_altstr_t structure is given by:
+
+       typedef struct cistpl_altstr_t {
+               int             ns;
+               int             ofs[CISTPL_ALTSTR_MAX_STRINGS];
+               char            str[254];
+       } cistpl_altstr_t;
+
+  The ns field specifies the number of alternate language strings in the
+  tuple.  The string data is contained in the str array.  Each string is
+  null terminated, and ofs gives the offset to the start of each string.
+
+  44..11..77..  CCIISSTTPPLL__JJEEDDEECC__CC,, CCIISSTTPPLL__JJEEDDEECC__AA
+
+  The cistpl_jedec_t structure is given by:
+
+       typedef struct cistpl_jedec_t {
+               int             nid;
+               struct {
+                       u_char  mfr;
+                       u_char  info;
+               } id[CISTPL_MAX_DEVICES];
+       } cistpl_jedec_t;
+
+  JEDEC identifiers describe the specific device type used to implement
+  a region of card memory.  The nid field specifies the number of JEDEC
+  identifiers in the tuple.  There should be a one-to-one correspondence
+  between JEDEC identifiers and device descriptions in the corresponding
+  CISTPL_DEVICE tuple.
+
+  44..11..88..  CCIISSTTPPLL__CCOONNFFIIGG,, CCIISSTTPPLL__CCOONNFFIIGG__CCBB
+
+  The cistpl_config_t structure is given by:
+
+       typedef struct cistpl_config_t {
+               u_char          last_idx;
+               u_int           base;
+               u_int           rmask[4];
+               u_char          subtuples;
+       } cistpl_config_t;
+
+  The last_idx field gives the index of the highest numbered
+  configuration table entry.  The base field gives the offset of a
+  card's configuration registers in attribute memory.  The rmask array
+  is a series of bit masks indicating which configuration registers are
+  present.  Bit 0 of rmask[0] is for the COR, bit 1 is for the CCSR, and
+  so on.  The subtuples field gives the number of bytes of subtuples
+  following the normal tuple contents.
+
+  For CISTPL_CONFIG_CB, rmask is undefined, and base points to the
+  CardBus status registers.
+
+  44..11..99..  CCIISSTTPPLL__BBAARR
+
+  The cistpl_bar_t structure is given by:
+
+  typedef struct cistpl_bar_t {
+          u_char          attr;
+          u_int           size;
+  } cistpl_long_t;
+
+  A CISTPL_BAR tuple describes the characteristics of an address space
+  region pointed to by a PCI base address register, for CardBus cards.
+
+  The following bit fields are defined in attr:
+
+     CISTPL_BAR_SPACE
+        Identifies the base address register, from 1 to 6.  A value of 7
+        describes the card's Extension ROM space.
+
+     CISTPL_BAR_SPACE_IO
+        If set, this address register maps IO space (as opposed to
+        memory space).
+
+     CISTPL_BAR_PREFETCH
+        If set, this region can be prefetched.  controller.
+
+     CISTPL_BAR_CACHEABLE
+        If set, this region is cacheable as well as prefetchable.
+
+     CISTPL_BAR_1MEG_MAP
+        If set, this region should only be mapped into the first 1MB of
+        the host's physical address space.
+
+  44..11..1100..  CCIISSTTPPLL__CCFFTTAABBLLEE__EENNTTRRYY
+
+  The cistpl_cftable_entry_t structure is given by:
+
+       typedef struct cistpl_cftable_entry_t {
+               u_char          index;
+               u_char          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;
+
+  A CISTPL_CFTABLE_ENTRY structure describes a complete operating mode
+  for a card.  Many sections are optional.  The index field gives the
+  configuration index for this operating mode; writing this value to the
+  card's Configuration Option Register selects this mode.  The following
+  fields are defined in flags:
+
+     CISTPL_CFTABLE_DEFAULT
+        Specifies that this is the default configuration table entry.
+
+     CISTPL_CFTABLE_BVDS
+        Specifies that this configuration implements the BVD1 and BVD2
+        signals in the Pin Replacement Register.
+
+     CISTPL_CFTABLE_WP
+        Specifies that this configuration implements the write protect
+        signal in the Pin Replacement Register.
+
+     CISTPL_CFTABLE_RDYBSY
+        Specifies that this configuration implements the Ready/Busy
+        signal in the Pin Replacement Register.
+
+     CISTPL_CFTABLE_MWAIT
+        Specifies that the WAIT signal should be observed during memory
+        access cycles.
+
+     CISTPL_CFTABLE_AUDIO
+        Specifies that this configuration generates an audio signal that
+        can be routed to the host system speaker.
+
+     CISTPL_CFTABLE_READONLY
+        Specifies that the card has a memory region that is read-only in
+        this configuration.
+
+     CISTPL_CFTABLE_PWRDOWN
+        Specifies that this configuration supports a power down mode,
+        via the Card Configuration and Status Register.
+
+  The cistpl_power_t structure is given by:
+
+       typedef struct cistpl_power_t {
+               u_char          present;
+               u_char          flags;
+               u_int           param[7];
+       } cistpl_power_t;
+
+  The present field is bit mapped and indicates which parameters are
+  present for this power signal.  The following indices are defined:
+
+     CISTPL_POWER_VNOM
+        The nominal supply voltage.
+
+     CISTPL_POWER_VMIN
+        The minimum supply voltage.
+
+     CISTPL_POWER_VMAX
+        The maximum supply voltage.
+
+     CISTPL_POWER_ISTATIC
+        The continuous supply current required.
+
+     CISTPL_POWER_IAVG
+        The maximum current averaged over one second.
+
+     CISTPL_POWER_IPEAK
+        The maximum current averaged over 10 ms.
+
+     CISTPL_POWER_IDOWN
+        The current required in power down mode.
+
+  Voltages are given in units of 10 microvolts.  Currents are given in
+  units of 100 nanoamperes.
+
+  The cistpl_timing_t structure is given by:
+
+       typedef cistpl_timing_t {
+               u_int           wait, waitscale;
+               u_int           ready, rdyscale;
+               u_int           reserved, rsvscale;
+       } cistpl_timing_t;
+
+  Each time consists of a base time in nanoseconds, and a scale
+  multiplier.  Unspecified times have values of 0.
+
+  The cistpl_io_t structure is given by:
+
+       typedef struct cistpl_io_t {
+               u_char          flags;
+               int             nwin;
+               struct {
+                       u_int           base;
+                       u_int           len;
+               } win[CISTPL_IO_MAX_WIN;
+       } cistpl_io_t;
+
+  The number of IO windows is given by nwin.  Each window is described
+  by a base address, base, and a length in bytes, len.  The following
+  bit fields are defined in flags:
+
+     CISTPL_IO_LINES_MASK
+        The number of IO lines decoded by this card.
+
+     CISTPL_IO_8BIT
+        Indicates that the card supports split 8-bit accesses to 16-bit
+        IO registers.
+
+     CISTPL_IO_16BIT
+        Indicates that the card supports full 16-bit accesses to IO
+        registers.
+
+  The cistpl_irq_t structure is given by:
+
+       typedef struct cistpl_irq_t {
+               u_int           IRQInfo1;
+               u_int           IRQInfo2;
+       } cistpl_irq_t;
+
+  The following bit fields are defined in IRQInfo1:
+
+     IRQ_MASK
+        A specific interrupt number that this card should use.
+
+     IRQ_NMI_ID, IRQ_IOCK_ID, IRQ_BERR_ID,
+        IRQ_VEND_ID" When IRQ_INFO2_VALID is set, these indicate if a
+        corresponding special interrupt signal may be assigned to this
+        card.  The four flags are for the non-maskable, IO check, bus
+        error, and vendor specific interrupts.
+
+     IRQ_INFO2_VALID
+        Indicates that IRQInfo2 contains a valid bit mask of allowed
+        interrupt request numbers.
+
+     IRQ_LEVEL_ID
+        Indicates that the card supports level mode interrupts.
+
+     IRQ_PULSE_ID
+        Indicates that the card supports pulse mode interrupts.
+
+     IRQ_SHARE_ID
+        Indicates that the card supports sharing interrupts.
+
+  If IRQInfo1 is 0, then no interrupt information is available.
+
+  The cistpl_mem_t structure is given by:
+
+       typedef struct cistpl_mem_t {
+               u_char          nwin;
+               struct {
+                       u_int           len;
+                       u_int           card_addr;
+                       u_int           host_addr;
+               } win[CISTPL_MEM_MAX_WIN;
+       } cistpl_mem_t;
+
+  The number of memory windows is given by nwin.  Each window is
+  described by an address in the card memory space, card_addr, an
+  address in the host memory space, host_addr, and a length in bytes,
+  len.  If the host address is 0, the position of the window is
+  arbitrary.
+
+  44..11..1111..  CCIISSTTPPLL__CCFFTTAABBLLEE__EENNTTRRYY__CCBB
+
+  The cistpl_cftable_entry_cb_t structure is given by:
+
+       typedef struct cistpl_cftable_entry_cb_t {
+               u_char          index;
+               u_char          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;
+
+  A CISTPL_CFTABLE_ENTRY_CB structure describes a complete operating
+  mode for a CardBus card.  Many fields are identical to corresponding
+  fields in CISTPL_CFTABLE_ENTRY.
+
+  The io and mem fields specify which base address registers need to be
+  initialized for this configuration.  Bits 1 through 6 correspond to
+  the six base address registers, and bit 7 indicates the expansion ROM
+  base register.
+
+  44..11..1122..  CCIISSTTPPLL__MMAANNFFIIDD
+
+  The cistpl_manfid_t structure is given by:
+
+       typedef struct cistpl_manfid_t {
+               u_short         manf;
+               u_short         card;
+       } cistpl_manfid_t;
+
+  The manf field identifies the card manufacturer.  The card field is
+  chosen by the vendor and should identify the card type and model.
+
+  44..11..1133..  CCIISSTTPPLL__FFUUNNCCIIDD
+
+  The cistpl_funcid_t structure is given by:
+
+       typedef struct cistpl_funcid_t {
+               u_char          func;
+               u_char          sysinit;
+       } cistpl_funcid_t;
+
+  The func field identifies the card function.  The sysinit field
+  contains several bit-mapped flags describing how the card should be
+  configured at boot time.
+
+  The following functions are defined:
+
+     CISTPL_FUNCID_MULTI
+        A multi-function card.
+
+     CISTPL_FUNCID_MEMORY
+        A simple memory device.
+
+     CISTPL_FUNCID_SERIAL
+        A serial port or modem device.
+
+     CISTPL_FUNCID_PARALLEL
+        A parallel port device.
+
+     CISTPL_FUNCID_FIXED
+        A fixed disk device.
+
+     CISTPL_FUNCID_VIDEO
+        A video interface.
+
+     CISTPL_FUNCID_NETWORK
+        A network adapter.
+
+     CISTPL_FUNCID_AIMS
+        An auto-incrementing mass storage device.
+
+  The following flags are defined in sysinit:
+
+     CISTPL_SYSINIT_POST
+        Indicates that the system should attempt to configure this card
+        during its power-on initialization.
+
+     CISTPL_SYSINIT_ROM
+        Indicates that the card contains a system expansion ROM that
+        should be configured at boot time.
+
+  44..11..1144..  CCIISSTTPPLL__DDEEVVIICCEE__GGEEOO
+
+  The cistpl_device_geo_t structure is given by:
+
+       typedef struct cistpl_device_geo_t {
+               int             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;
+
+  The erase_block, read_block, and write_block sizes are in units of
+  buswidth bytes times interleave.  The partition size is in units of
+  erase_block.
+
+  44..11..1155..  CCIISSTTPPLL__VVEERRSS__22
+
+  The cistpl_vers_2_t structure is given by:
+
+       typedef struct cistpl_vers_2_t {
+               u_char          vers;
+               u_char          comply;
+               u_short         dindex;
+               u_char          vspec8, vspec9;
+               u_char          nhdr;
+               int             vendor, info;
+               char            str[244];
+       } cistpl_vers_2_t;
+
+  The vers field should always be 0.  The comply field indicates the
+  degree of standard compliance and should also be 0.  The dindex field
+  reserves the specified number of bytes at the start of common memory.
+  The vspec8 and vspec9 fields may contain vendor-specific information.
+  The nhdr field gives the number of copies of the CIS that are present
+  on this card.  The str array contains two strings: a vendor name, and
+  an informational message describing the card.  The offset of the
+  vendor string is given by vendor, and the offset of the product info
+  string is in info.
+
+  44..11..1166..  CCIISSTTPPLL__OORRGG
+
+  The cistpl_org_t structure is given by:
+
+       typedef struct cistpl_org_t {
+               u_char          data_org;
+               char            desc[30];
+
+  This tuple describes the data organization of a memory partition.  The
+  following values are defined for data_org:
+
+     CISTPL_ORG_FS
+        The partition contains a filesystem.
+
+     CISTPL_ORG_APPSPEC
+        The partition is in an application specific format.
+
+     CISTPL_ORG_XIP
+        The partition follows the Execute-In-Place specification.
+
+  The desc field gives a text description of the data organization.
+
+  44..22..  CCIISS ccoonnffiigguurraattiioonn rreeggiisstteerr ddeeffiinniittiioonnss
+
+  The PC Card standard defines a few standard configuration registers
+  located in a card's attribute memory space.  A card's CONFIG tuple
+  specifies which of these registers are implemented.  Programs using
+  these definitions should include:
+
+       #include "cisreg.h"
+
+  44..22..11..  CCoonnffiigguurraattiioonn OOppttiioonn RReeggiisstteerr
+
+  This register should be present for virtually all IO cards.  Writing
+  to this register selects a configuration table entry and enables a
+  card's IO functions.
+
+  The following bit fields are defined:
+
+     COR_CONFIG_MASK
+        Specifies the configuration table index describing the card's
+        current operating mode.
+     COR_LEVEL_REQ
+        Specifies that the card should generate level mode (edge-
+        triggered) interrupts, the default.
+
+     COR_SOFT_RESET
+        Setting this bit performs a ``soft'' reset operation.  Drivers
+        should use the ResetCard call to reset a card, rather than
+        writing directly to this register.
+
+  44..22..22..  CCaarrdd CCoonnffiigguurraattiioonn aanndd SSttaattuuss RReeggiisstteerr
+
+  The following bit fields are defined:
+
+     CCSR_INTR_ACK
+        If this bit is set, then the CCSR_INTR_PENDING bit will remain
+        set until it is explicitly cleared.
+
+     CCSR_INTR_PENDING
+        Signals that the card is currently asserting an interrupt
+        request.  This signal may be helpful for supporting interrupt
+        sharing.
+
+     CCSR_POWER_DOWN
+        Setting this bit signals that the card should enter a power down
+        state.
+
+     CCSR_AUDIO_ENA
+        Specifies that the card's audio output should be enabled.
+
+     CCSR_IOIS8
+        This is used by the host to indicate that it can only perform
+        8-bit IO operations and that 16-bit accesses will be carried out
+        as two 8-bit accesses.
+
+     CCSR_SIGCHG_ENA
+        This indicates to the card that it should use the SIGCHG signal
+        to indicate changes in the WP, READY, BVD1, and BVD2 signals.
+
+     CCSR_CHANGED
+        This bit signals to the host that one of the signals in the Pin
+        Replacement Register has changed state.
+
+  44..22..33..  PPiinn RReeppllaacceemmeenntt RReeggiisstteerr
+
+  Signals in this register replace signals that are not available when a
+  socket is operating in memory and IO mode.  An IO card will normally
+  assert the SIGCHG signal to indicate that one of these signals has
+  changed state, then a driver can poll this register to find out
+  specifically what happened.
+
+  The following bit fields are defined:
+
+     PRR_WP_STATUS
+        The current state of the write protect signal.
+
+     PRR_READY_STATUS
+        The current state of the ready signal.
+
+     PRR_BVD2_STATUS
+        The current state of the battery warn signal.
+     PRR_BVD1_STATUS
+        The current state of the battery dead signal.
+
+     PRR_WP_EVENT
+        Indicates that the write protect signal has changed state since
+        the PRR register was last read.
+
+     PRR_READY_EVENT
+        Indicates that the ready signal has changed state since the PRR
+        register was last read.
+
+     PRR_BVD2_EVENT
+        Indicates that the battery warn signal has changed state since
+        the PRR register was last read.
+
+     PRR_BVD1_EVENT
+        Indicates that the battery dead signal has changed state since
+        the PRR register was last read.
+
+  This register can also be written.  In this case, the STATUS bits act
+  as a mask; if a STATUS bit is set, the corresponding EVENT bit is
+  updated by the write.
+
+  44..22..44..  SSoocckkeett aanndd CCooppyy RReeggiisstteerr
+
+  This register is used when several identical cards may be set up to
+  share the same range of IO ports, to emulate an ISA bus card that
+  would control several devices.  For example, an ISA hard drive
+  controller might control several drives, selectable by writing a drive
+  number to an IO port.  For several card drives to emulate this
+  controller interface, each needs to ``know'' which drive it is, so
+  that it can identify which IO operations are intended for it.
+
+  The following bit fields are defined:
+
+     SCR_SOCKET_NUM
+        This should indicate the socket number in which the card is
+        located.
+
+     SCR_COPY_NUM
+        If several identical cards are installed in a system, this field
+        should be set to a unique number identifying which of the
+        identical cards this is.
+
+  44..22..55..  EExxtteennddeedd SSttaattuuss RReeggiisstteerr
+
+  The following bit fields are defined:
+
+     ESR_REQ_ATTN_ENA
+        When set, the CCSR_CHANGED bit will be set when the ESR_REQ_ATTN
+        bit is set, possibly generating a status change interrupt.
+
+     ESR_REQ_ATTN
+        Signals a card event, such as an incoming call for a modem.
+
+  44..22..66..  IIOO BBaassee aanndd SSiizzee RReeggiisstteerrss
+
+  For multifunction cards, these registers are used to tell the card how
+  the host IO windows have been configured for each card function.
+  There are four IO Base registers, from CISREG_IOBASE_0 to
+  CISREG_IOBASE_3, for the low-order through high-order bytes of an IO
+  address up to 32 bits long.  The CISREG_IOSIZE register is supposed to
+  be written as the number of IO ports allocated, minus one.  For MFC-
+  compliant cards, Card Services will automatically set all of these
+  registers when RequestConfiguration is called.
+
+  55..  CCaarrdd SSeerrvviicceess EEvveenntt HHaannddlliinngg
+
+  Card Services events have several sources:
+
+  +o  Card status changes reported by the low-level socket drivers.
+
+  +o  Artificial events generated by Card Services itself.
+
+  +o  Advanced Power Management (APM) events.
+
+  +o  Events generated by other Card Services clients.
+
+  Socket driver events may be either interrupt-driven or polled.
+
+  55..11..  EEvveenntt hhaannddlleerr ooppeerraattiioonnss
+
+  When Card Services recognizes that an event has occurred, it checks
+  the event mask of each client to determine which clients should
+  receive an event notification.  When a client registers with Card
+  Services, it specifies  an event handler callback function.  This
+  handler should have the form:
+
+       int (*event_handler)(event_t event, int priority, event_callback_args_t *args);
+
+  The priority parameter is set to either CS_EVENT_PRI_LOW for ordinary
+  events, or CS_EVENT_PRI_HIGH for events that require an immediate
+  response.  The only high priority event is CS_EVENT_CARD_REMOVAL.  A
+  client event handler should process this event as efficiently as
+  possible so that Card Services can quickly notify other clients.
+
+  The event_callback_args_t structure is given by:
+
+       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;
+
+  The client_handle member is set to the handle of the client whose
+  socket was responsible for the event.  This is useful if a driver is
+  bound to several sockets.  The info field is currently only used to
+  return an exit status from a call to ResetCard.  The client_data field
+  may be used by a driver to point to a local data structure associated
+  with this device.  The remaining fields are currently unused.
+
+  For sockets that do not directly map cards into the host IO and memory
+  space, the bus field is a pointer to a table of entry points for IO
+  primitives for this socket.
+
+  55..22..  EEvveenntt ddeessccrriippttiioonnss
+
+     CS_EVENT_CARD_INSERTION
+        This event signals that a card has been inserted.  If a driver
+        is bound to an already occupied socket, Card Services will send
+        the driver an artificial insertion event.
+
+     CS_EVENT_CARD_REMOVAL
+        This event signals that a card has been removed.  This event
+        should be handled with minimum delay so that Card Services can
+        notify all clients as quickly as possible.
+
+     CS_EVENT_BATTERY_LOW
+        This event signals a change of state of the ``battery low''
+        signal.
+
+     CS_EVENT_BATTERY_DEAD
+        This event signals a change of state of the ``battery dead''
+        signal.
+
+     CS_EVENT_READY_CHANGE
+        This event signals a change of state of the ``ready'' signal.
+
+     CS_EVENT_WRITE_PROTECT
+        This event signals a change of state of the ``write protect''
+        signal.
+
+     CS_EVENT_REGISTRATION_COMPLETE
+        This event is sent to a driver after a successful call to
+        RegisterClient.
+
+     CS_EVENT_RESET_REQUEST
+        This event is sent when a client calls ResetCard.  An event
+        handler can veto the reset operation by returning failure.
+
+     CS_EVENT_RESET_PHYSICAL
+        This is sent to all clients just before a reset signal is sent
+        to a card.
+
+     CS_EVENT_CARD_RESET
+        This event signals that a reset operation is finished.  The
+        success or failure of the reset should be determined using
+        GetStatus.
+
+     CS_EVENT_RESET_COMPLETE
+        This event is sent to a client that has called ResetCard to
+        signal the end of reset processing.
+
+     CS_EVENT_PM_SUSPEND
+        This event signals that Card Services has received either a user
+        initiated or APM suspend request.  An event handler can veto the
+        suspend by returning failure.
+     CS_EVENT_PM_RESUME
+        This signals that the system is back on line after a
+        suspend/resume cycle.
+
+     CS_EVENT_MTD_REQUEST
+        This is used to initiate an MTD memory operation.  A description
+        of the request is passed in the mtdrequest field of the callback
+        arguments.  A host buffer address may be passed in buffer.
+
+     CS_EVENT_ERASE_COMPLETE
+        This is used to signal a client that a queued erase operation
+        has completed.  A pointer to the erase queue entry is returned
+        in the info field of the callback arguments.
+
+  55..33..  CClliieenntt ddrriivveerr eevveenntt hhaannddlliinngg rreessppoonnssiibbiilliittiieess
+
+  A client driver should respond to CS_EVENT_CARD_INSERTION and
+  CS_EVENT_CARD_REMOVAL events by configuring and un-configuring the
+  socket.  Because card removal is a high priority event, the driver
+  should immediately block IO to the socket, perhaps by setting a flag
+  in a device structure, and schedule all other shutdown processing to
+  happen later using a timer interrupt.
+
+  When a CS_EVENT_PM_RESET_REQUEST event is received, a driver should
+  block IO and release a locked socket configuration.  When a
+  CS_EVENT_CARD_RESET is received, a driver should restore the socket
+  configuration and unblock IO.
+
+  A CS_EVENT_PM_SUSPEND event should be handled somewhat like a
+  CS_EVENT_PM_RESET_REQUEST event, in that IO should be blocked and the
+  socket configuration should be released.  When a CS_EVENT_PM_RESUME
+  event is received, a driver can expect a card to be ready to be
+  reconfigured, similar to when a CS_EVENT_CARD_RESET event is received.
+
+  66..  MMeemmoorryy TTeecchhnnoollooggyy DDrriivveerrss
+
+  A Memory Technology Driver (``MTD'') is used by Card Services to
+  implement bulk memory services for a particular type of memory device.
+  An MTD should register as a normal Card Services client with a call to
+  RegisterClient.  When it receives a card insertion event, it should
+  use GetFirstRegion and GetNextRegion to identify memory regions that
+  it will administer.  Then, it should use RegisterMTD to take control
+  of these regions.  MTD read, write, copy, and erase requests are
+  packaged into CS_EVENT_MTD_REQUEST events by Card Services, and passed
+  to the MTD's event handler for processing.
+
+  66..11..  MMTTDD rreeqquueesstt hhaannddlliinngg
+
+  An MTD receives requests from Card Services in the form of
+  CS_EVENT_MTD_REQUEST events.  Card Services passes a description of
+  the request in the mtdrequest field of the event callback arguments.
+  For requests that transfer data to or from the host, the host buffer
+  address is passed in the buffer field.
+
+  The mtd_request_t structure is given by:
+
+  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;
+
+  The Function field is bit mapped and describes the action to be
+  performed by this request:
+
+     MTD_REQ_ACTION
+        Either MTD_REQ_ERASE, MTD_REQ_READ, MTD_REQ_WRITE, or
+        MTD_REQ_COPY.
+
+     MTD_REQ_NOERASE
+        For a write command that is sized and aligned on erase block
+        boundaries, this specifies that no erase should be performed.
+
+     MTD_REQ_VERIFY
+        Specifies that writes should be verified.
+
+     MTD_REQ_READY
+        Indicates that this request is a retry of a previously request
+        that was delayed until the card asserted READY.
+
+     MTD_REQ_TIMEOUT
+        Indicates that this request is a retry of a previously request
+        that was delayed by a timeout.
+
+     MTD_REQ_FIRST
+        Indicates that this request is the first in a series of
+        requests.
+
+     MTD_REQ_LAST
+        Indicates that this request is the last of a series of requests.
+
+     MTD_REQ_KERNEL
+        Indicates that the host buffer for a read or write command is
+        located in kernel memory, as opposed to user memory.
+
+  The MediaID field is the value specified in the RegisterMTD request
+  for this region.  The Status field is used by the MTD when it is
+  unable to satisfy a request because a device is busy.  MTD requests
+  normally run without blocking.  If an MTD request would block, it
+  should return an error code of CS_BUSY, and set Status to one of the
+  have the following values:
+
+     MTD_WAITREQ
+        Specifies that the request should be retried after another MTD
+        request currently in progress completes.
+
+     MTD_WAITTIMER
+        Specifies that the request should be continued after the time
+        specified in the timeout field.
+
+     MTD_WAITRDY
+        Specifies that the request should be continued when the card
+        signals READY, or when the time specified in Timeout elapses,
+        whichever happens first.
+     MTD_WAITPOWER
+        Specifies that the request should be retried after something
+        happens that affects power availability to the socket.
+
+  For MTD_WAITTIMER and MTD_WAITRDY, the Timeout field will specify the
+  timeout interval in milliseconds.
+
+  66..22..  MMTTDD hheellppeerr ffuunnccttiioonnss
+
+  Since an MTD processes requests generated by Card Services, there may
+  be some restrictions on the sorts of Card Services calls that can be
+  safely made from the MTD event handler.  The MTD helper functions
+  provide a limited set of special services that may be needed by an MTD
+  but would be tricky to implement using the normal Card Services calls.
+  In the Linux implementation, most CS calls can be safely made from an
+  MTD event handler, but the MTD helper interface is included for
+  compatibility.
+
+       #include "cs_types.h"
+       #include "cs.h"
+       #include "bulkmem.h"
+
+       int MTDHelperEntry(int subfunc, void *arg1, void *arg2);
+
+  66..22..11..  MMTTDDRReeqquueessttWWiinnddooww,, MMTTDDRReelleeaasseeWWiinnddooww
+
+       int MTDHelperEntry(MTDRequestWindow, client_handle_t *handle, win_req_t *mod);
+       int MTDHelperEntry(MTDReleaseWindow, window_handle_t handle);
+
+  These services are identical to the standard Card Services
+  RequestWindow and ReleaseWindow calls.
+
+  66..22..22..  MMTTDDMMooddiiffyyWWiinnddooww
+
+       int MTDHelperEntry(MTDModifyWindow, memory_handle_t handle, mtd_mod_req_t *mod);
+
+  The mtd_mod_req_t structure is give by:
+
+       typedef struct mtd_mod_req_t {
+               u_int           Attributes;
+               u_int           AccessSpeed;
+               u_int           CardOffset;
+       } mtd_mod_req_t;
+
+  MTDModifyWindow is essentially equivalent to using the normal
+  ModifyWindow and MapMemPage calls.
+
+  The following flags can be specified in Attributes:
+
+     WIN_MEMORY_TYPE
+        Either WIN_MEMORY_TYPE_CM for common memory, or
+        WIN_MEMORY_TYPE_AM for attribute memory.
+
+     WIN_USE_WAIT
+        Specifies that the controller should observe the card's MWAIT
+        signal.
+
+  A window configured with MTDModifyWindow will always be enabled, and
+  have a 16 bit data width.
+
+  Return codes:
+
+     CS_BAD_HANDLE
+        The memory handle is invalid.
+
+  66..22..33..  MMTTDDSSeettVVpppp
+
+       int MTDHelperEntry(MTDSetVpp, client_handle_t client, mtd_vpp_req_t *req);
+
+       typedef struct mtd_vpp_req_t {
+               u_char          Vpp1, Vpp2;
+       } mtd_vpp_req_t;
+
+  MTDSetVpp changes the programming voltage for a socket.  Vpp1 and Vpp2
+  should be given in units of 1/10 volt.  Currently, Vpp1 should always
+  equal Vpp2.
+
+  Return codes:
+
+     CS_BAD_HANDLE
+        The client handle is invalid.
+
+     CS_BAD_VPP
+        The specified Vpp is not available, or Vpp1 does not equal Vpp2.
+
+  66..22..44..  MMTTDDRRDDYYMMaasskk
+
+       int MTDHelperEntry(MTDRDYMask, client_handle_t client, mtd_rdy_req_t *req);
+
+  typedef struct mtd_rdy_req_t {
+          u_int           Mask;
+  } mtd_rdy_req_t;
+
+  MTDRDYMask selects whether or not CS_EVENT_READY_CHANGE events will be
+  enabled.  The client should already have indicated to Card Services
+  that it should receive ready change events, via a call to either
+  RegisterClient or SetEventMask.  Ready change events will be enabled
+  if the CS_EVENT_READY_CHANGE bit is set in the Mask argument.
+
+  Return codes:
+
+     CS_BAD_HANDLE
+        The client handle is invalid.
+
+  77..  DDrriivveerr SSeerrvviicceess IInntteerrffaaccee
+
+  Driver Services provides a link between Card Services client drivers
+  and user mode utilities like the cardmgr daemon.  It is a sort of Card
+  Services ``super-client''.  Driver Services uses the BindDevice
+  function to link other client drivers with their corresponding cards.
+  Unlike other clients, Driver Services remains permanently bound to all
+  sockets as cards are inserted and removed.
+
+  77..11..  IInntteerrffaaccee ttoo ootthheerr cclliieenntt ddrriivveerrss
+
+  Driver Services keeps track of all client drivers that are installed
+  and ready to attach to a socket.  Client drivers need to have entry
+  points for creating and deleting device ``instances'', where one
+  device instance is everything needed to manage one physical card.
+
+  Each client driver is identified by a unique 16-character tag that has
+  the special type dev_info_t, defined in cs_types.h.  Each device
+  instance is described by a dev_link_t structure.
+
+  77..11..11..  TThhee ddeevv__lliinnkk__tt ssttrruuccttuurree
+
+  The dev_node_t and dev_link_t data structures are given by:
+
+  #include "ds.h"
+
+  typedef struct dev_node_t {
+          char                    dev_name[DEV_NAME_LEN];
+          u_char                  major, minor;
+          struct dev_node_t       *next;
+  }
+
+  typedef struct dev_link_t {
+          dev_node_t              *dev;
+          u_int                   state, open;
+          struct wait_queue       *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;
+
+  The dev field of the dev_link_t structure points to a linked list of
+  dev_node_t structures.  In dev_node_t, the dev_name field should be
+  filled in by the driver with a device file name for accessing this
+  device, if appropriate.  For example, the serial_cs driver uses names
+  like ``ttyS1''.  The major and minor fields give major and minor
+  device numbers for accessing this device.  Driver Services relays
+  these fields to user mode programs via the DS_GET_DEVICE_INFO ioctl.
+
+  In dev_link_t, the state field should be used to keep track of the
+  current device state.  The following flags are defined:
+
+     DEV_PRESENT
+        Indicates that the card is present.  This bit should be set and
+        cleared by the driver's event handler in response to card
+        insertion and removal events.
+
+     DEV_CONFIG
+        Indicates that the card is configured for use.
+
+     DEV_CONFIG_PENDING
+        Indicates that configuration is in progress.
+
+     DEV_SUSPEND
+        Indicates that the card is suspended.
+
+     DEV_BUSY
+        Indicates that an IO operation is in progress.  This bit may be
+        used as an interlock to prevent access conflicts.
+
+     DEV_STALE_CONFIG
+        For some drivers, when a running card is ejected, the socket
+        should not be unconfigured until any devices corresponding to
+        this card are closed.  This flag indicates that the socket
+        should be unconfigured when the device is closed.
+
+     DEV_STALE_LINK
+        A driver instance should not be deleted until all its resources
+        are released.  This flag indicates that this driver instance
+        should be freed as soon as the socket is unconfigured.
+
+  The open field is a usage count for this device.  The device should
+  only be freed when the open count is zero.  The pending field can be
+  used to manage a queue of processes waiting to use the device.
+
+  The release field is used to schedule device shutdown processing when
+  a card is ejected.  A card removal event needs to be handled at high
+  priority, so a driver's event handler will typically deal with an
+  eject by resetting the DEV_PRESENT bit in the device state, then
+  scheduling the shutdown processing to run at a later time.
+
+  The handle, io, irq, conf, and win fields comprise all the normal data
+  structures needed to configure an ordinary PC Card IO device
+
+  The priv field can be used for any sort of private data structure
+  needed to manage the device.  The next field can be used to build
+  linked lists of dev_link_t structures, for drivers that can handle
+  multiple instances.
+
+  77..11..22..  rreeggiisstteerr__ppccccaarrdd__ddrriivveerr
+
+       int register_pccard_driver(dev_info_t *dev_info,
+                                  dev_link_t *(*attach)(void),
+                                  void (*detach)(dev_link_t *));
+
+  register_pccard_driver informs Driver Services that a client driver is
+  present and ready to be bound to sockets.  When Driver Services
+  receives a DS_BIND_REQUEST ioctl that matches this driver's dev_info
+  string, it will call the driver's attach() entry point.  When it gets
+  a DS_UNBIND_REQUEST ioctl, it will call detach().
+
+  77..11..33..  uunnrreeggiisstteerr__ppccccaarrdd__ddrriivveerr
+
+       int unregister_pccard_driver(dev_info_t *dev_info);
+
+  This informs Driver Services that it should no longer bind sockets to
+  the specified client driver.
+
+  77..22..  TThhee CCaarrddBBuuss cclliieenntt iinntteerrffaaccee
+
+  The CardBus card interface is designed to be essentially an extension
+  of the PCI bus.  CardBus cards are typically designed using standard
+  PCI chip sets.  For simplicity in the client drivers, and maximum code
+  sharing with regular kernel PCI drivers, we provide a sort of ``super
+  client'' for configuring CardBus cards.  This is implemented in the
+  cb_enabler module.
+
+  The cb_enabler module is somewhat similar in philosophy to the Driver
+  Services layer for 16-bit cards.  CardBus client drivers register with
+  it, and provide a few entry points for handling device setup and
+  shutdown, as well as power management handling.  The cb_enabler module
+  takes care of configuring the card and fielding Card Services events.
+  So, all CardBus-specific code is in the enabler rather than the PCI
+  driver.
+
+  It is not mandatory for CardBus clients to use the cb_enabler
+  interface.  If a particular client requires more direct control over
+  its CardBus configuration than is provided through the cb_enabler
+  module, it can register directly with Card Services and perform Card
+  Services calls directly, just like a 16-bit client.
+
+  The cb_enabler module has two entry points: register_driver and
+  unregister_driver.  At some point, these functions may migrate into
+  the kernel: hence the generic names.
+
+  77..22..11..  rreeggiisstteerr__ddrriivveerr
+
+       int register_driver(struct driver_operations *ops);
+
+  The driver_operations structure is given by:
+
+       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;
+
+  The name field is used by cb_enabler when registering this client with
+  Card Services.  The rest of the structure describes a set of event
+  handlers for this client.
+
+  The function returns 0 on success, and -1 on failure.
+
+  77..22..22..  uunnrreeggiisstteerr__ddrriivveerr
+
+       void unregister_driver(struct driver_operations *ops);
+
+  The ops parameter should be the same structure pointer passed to a
+  prior successful call to register_driver.  The client should take care
+  to only call this function when no devices are currently being managed
+  by this client.
+
+  77..22..33..  TThhee ddrriivveerr__ooppeerraattiioonnss eennttrryy ppooiinnttss
+
+  The attach() entry point is used to configure a single device, given a
+  ``device locator'' structure describing where to find it.
+
+  The dev_locator_t structure is given by:
+
+       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;
+
+  The attach() function should return either NULL or a valid dev_node_t
+  structure describing the new device.  All the other entry points will
+  use this pointer to identify the device to be manipulated.  The
+  cb_enabler module will invoke the attach() and detach() entry points
+  in response to card insertion and removal events.  The suspend() and
+  resume() entry points will be called in response to power management
+  events.
+
+  There is no way for a driver to refuse a suspend() or detach() event.
+  When a detach() event is received, the driver should block any
+  subsequent IO to the specified device, but may preserve internal data
+  structures until the kernel device is actually closed.
+
+  77..33..  IInntteerrffaaccee ttoo uusseerr mmooddee uuttiilliittiieess
+
+  Driver Services creates a pseudo-device for communicating with user
+  mode PC Card utilities.  The major number of the device is chosen
+  dynamically, and PC Card utilities should read /proc/devices to
+  determine it.  Minor device numbers correspond to socket numbers,
+  starting with 0.
+
+  Only one process is allowed to open a socket for read/write access.
+  Other processes can open the socket in read-only mode.  A read-only
+  connection to Driver Services can perform a subset of ioctl calls.  A
+  read/write connection can issue all ioctl calls, and can also receive
+  Card Services event notifications.
+
+  77..33..11..  CCaarrdd SSeerrvviicceess eevveenntt nnoottiiffiiccaattiioonnss
+
+  Driver Services implements read() and select() functions for event
+  notification.  Reading from a PC Card device returns an unsigned long
+  value containing all the events received by Driver Services since the
+  previous read().  If no events have been received, the call will block
+  until the next event.  A select() call can be used to monitor several
+  sockets for new events.
+
+  The following events are monitored by Driver Services:
+  CS_EVENT_CARD_INSERTION, CS_EVENT_CARD_REMOVAL,
+  CS_EVENT_RESET_PHYSICAL, CS_EVENT_CARD_RESET, and
+  CS_EVENT_RESET_COMPLETE.
+
+  77..33..22..  IIooccttll ddeessccrriippttiioonnss
+
+  Most Driver Services ioctl operations directly map to Card Services
+  functions.  An ioctl call has the form:
+
+       int ioctl(int fd, int cmd, ds_ioctl_arg_t *arg);
+
+  The ds_ioctl_arg_t structure is given by:
+
+       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;
+               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;
+               cisdump_t       cisdump;
+       } ds_ioctl_arg_t;
+
+  The following ioctl commands execute the corresponding Card Services
+  function:
+
+     DS_GET_CARD_SERVICES_INFO
+        Calls CardServices(GetCardServicesInfo, ..., &arg->servinfo).
+
+     DS_ADJUST_RESOURCE_INFO
+        Calls CardServices(AdjustResourceInfo, ..., &arg->adjust).
+
+     DS_GET_CONFIGURATION_INFO
+        Calls CardServices(GetConfigurationInfo, ..., &arg->config).
+
+     DS_GET_FIRST_TUPLE
+        Calls CardServices(GetFirstTuple, ..., &arg->tuple).
+
+     DS_GET_NEXT_TUPLE
+        Calls CardServices(GetNextTuple, ..., &arg->tuple).
+
+     DS_GET_TUPLE_DATA
+        Calls CardServices(GetTupleData, ..., &arg->tuple_parse.tuple).
+        The tuple data is returned in arg->tuple_parse.data.
+
+     DS_PARSE_TUPLE
+        Calls CardServices(ParseTuple, ..., &arg->tuple_parse.tuple,
+        &arg->tuple_parse.parse).
+
+     DS_RESET_CARD
+        Calls CardServices(ResetCard, ...).
+
+     DS_GET_STATUS
+        Calls CardServices(GetStatus, ..., &arg->status).
+
+     DS_ACCESS_CONFIGURATION_REGISTER
+        Calls CardServices(AccessConfigurationRegister, ...,
+        &arg->conf_reg).
+
+     DS_VALIDATE_CIS
+        Calls CardServices(ValidateCIS, ..., &arg->cisinfo).
+
+     DS_SUSPEND_CARD
+        Calls CardServices(SuspendCard, ...).
+
+     DS_RESUME_CARD
+        Calls CardServices(ResumeCard, ...).
+
+     DS_EJECT_CARD
+        Calls CardServices(EjectCard, ...).
+
+     DS_INSERT_CARD
+        Calls CardServices(InsertCard, ...).
+
+     DS_GET_FIRST_REGION
+        Calls CardServices(GetFirstRegion, ..., &arg->region).
+
+     DS_GET_NEXT_REGION
+        Calls CardServices(GetNextRegion, ..., &arg->region).
+
+     DS_REPLACE_CIS
+        Calls CardServices(ReplaceCIS, ..., &arg->cisdump).
+
+  The following ioctl commands invoke special Driver Services functions.
+  They act on bind_info_t structures:
+
+       typedef struct bind_info_t {
+               dev_info_t              dev_info;
+               u_char                  function;
+               struct dev_info_t       *instance;
+               char                    name[DEV_NAME_LEN];
+               u_char                  major, minor;
+               void                    *next;
+       } bind_info_t;
+
+     DS_BIND_REQUEST
+        This call connects a socket to a client driver.  The specified
+        device ID dev_info is looked up in the list of registered
+        drivers.  If this is a multifunction card, the function field
+        identifies which card function is being bound.  If found, the
+        driver is bound to this socket and function using the BindDevice
+        call.  Then, Driver Services calls the client driver's attach()
+        entry point to create a device instance.  The new dev_link_t
+        pointer is returned in instance.
+
+     DS_GET_DEVICE_INFO
+        This call retrieves the dev_name, major, and minor entries from
+        the dev_link_t structure pointed to by instance.
+
+     DS_UNBIND_REQUEST
+        This call calls the detach() function for the specified driver
+        and instance, shutting down this device.
+
+  Finally, the DS_BIND_MTD request takes an argument of type mtd_info_t:
+
+       typedef struct mtd_info_t {
+               dev_info_t      dev_info;
+               u_int           Attributes;
+               u_int           CardOffset;
+       } mtd_info_t;
+
+  This call associates an MTD identified by dev_info with a memory
+  region described by Attributes and CardOffset, which have the same
+  meanings as in the Card Services BindMTD call.
+
+  88..  AAnnaattoommyy ooff aa CCaarrdd SSeerrvviicceess CClliieenntt DDrriivveerr
+
+  Each release of the Linux Card Services package comes with a well-
+  commented ``dummy'' client driver that should be used as a starting
+  point for writing a new driver.  Look for it in clients/dummy_cs.c.
+  This is not just a piece of sample code: it is written to function as
+  a sort of generic card enabler.  If bound to an IO card, it will read
+  the card's CIS and configure the card appropriately, assuming that the
+  card's CIS is complete and accurate.
+
+  88..11..  MMoodduullee iinniittiiaalliizzaattiioonn aanndd cclleeaannuupp
+
+  All loadable modules must supply init_module() and cleanup_module()
+  functions, which are invoked by the module support code when the
+  module is installed and removed.  A client driver's init function
+  should register the driver with Driver Services, via the
+  register_pccard_driver() call.  The cleanup function should use
+  unregister_pccard_driver() to unregister with Driver Services.
+  Depending on the driver, the cleanup function may also need to free
+  any device structures that still exist at shutdown time.
+
+  88..22..  TThhee **__aattttaacchh(()) aanndd **__ddeettaacchh(()) ffuunnccttiioonnss
+
+  The *_attach() entry point is responsible for creating an ``instance''
+  of the driver, setting up any data structures needed to manage one
+  card.  The *_attach() function should allocate and initialize a
+  dev_link_t structure, and call RegisterClient to establish a link with
+  Card Services.  It returns a pointer to the new dev_link_t structure,
+  or NULL if the new instance could not be created.
+
+  The *_detach() entry point deletes a driver instance created by a
+  previous call to *_attach.  It also breaks the link with Card
+  Services, using DeregisterClient.
+
+  The *_attach() entry point is called by Driver Services when a card
+  has been successfully identified and mapped to a matching driver by a
+  DS_BIND_REQUEST ioctl().  The *_detach() entry point is called in
+  response to a DS_UNBIND_REQUEST ioctl() call.
+
+  88..33..  TThhee **__ccoonnffiigg(()) aanndd **__rreelleeaassee(()) ffuunnccttiioonnss
+
+  The *_config() function is called to prepare a card for IO.  Most
+  drivers read some configuration details from the card itsef, but most
+  have at least some built-in knowledge of how the device should be set
+  up.  For example, the serial card driver reads a card's CFTABLE_ENTRY
+  tuples to determine appropriate IO port base addresses and
+  corresponding configuration indices, but the driver ignores the
+  interrupt information in the CIS.  The *_config function will parse
+  relevant parts of a card's CIS, then make calls to RequestIO,
+  RequestIRQ, and/or RequestWindow, then call RequestConfiguration.
+
+  When a card is successfully configured, the *_config() routine should
+  fill in the dev_name, major, and minor fields in the dev_link_t
+  structure.  These fields will be returned to user programs by Driver
+  Services in response to a DS_GET_DEVICE_INFO ioctl().
+
+  The *_release() function should release any resource allocated by a
+  previous call to *_config(), and blank out the device's dev_name
+  field.
+
+  The *_config() and *_release functions are normally called in response
+  to card status change events or from timer interrupts.  Thus, they
+  cannot sleep, and should not call other kernel functions that might
+  block.
+
+  88..44..  TThhee cclliieenntt eevveenntt hhaannddlleerr
+
+  The *_event() entry point is called from Card Services to notify a
+  driver of card status change events.
+
+  88..55..  LLoocckkiinngg aanndd ssyynncchhrroonniizzaattiioonn iissssuueess
+
+  A configured socket should only be released when all associated
+  devices are closed.  Releasing a socket allows its system resources to
+  be allocated for use by another device.  If the released resources are
+  reallocated while IO to the original device is still in progress, the
+  original driver may interfere with use of the new device.
+
+  A driver instance should only be freed after its corresponding socket
+  configuration has been released.  Card Services requires that a client
+  explicitly release any allocated resources before a call to
+  DeregisterClient will succeed.
+
+  All loadable modules have a ``use count'' that is used by the system
+  to determine when it is safe to unload a module.  The convention in
+  client drivers is to increment the use count when a device is opened,
+  and to decrement the count when a device is closed.  So, a driver can
+  be unloaded whenever all associated devices are closed.  in
+  particular, a driver can be unloaded even if it is still bound to a
+  socket, and the module cleanup code needs to be able to appropriately
+  free any such resources that are still allocated.  This should always
+  be safe, because if the driver has a use count of zero, all devices
+  are closed, which means all active sockets can be released, and all
+  device instances can be detached.
+
+  If a driver's *_release() function is called while a device is still
+  open, it should set the DEV_STALE_CONFIG flag in the device state, to
+  signal that the device should be released when the driver's close()
+  function is called.  If *_detach() is called for a configured device,
+  the DEV_STALE_LINK flag should be set to signal that the instance
+  should be detached when the *_release() function is called.
+
+  88..66..  UUssiinngg eexxiissttiinngg LLiinnuuxx ddrriivveerrss ttoo aacccceessss PPCC CCaarrdd ddeevviicceess
+
+  Many of the current client drivers use existing Linux driver code to
+  perform device IO operations.  The Card Services client module handles
+  card configuration and responds to card status change events, but
+  delegates device IO to a compatible driver for a conventional ISA bus
+  card.  In some cases, a conventional driver can be used without
+  modification.  However, to fully support PC Card features like hot
+  swapping and power management, there needs to be some communication
+  between the PC Card client code and the device IO code.
+
+  Most Linux drivers expect to probe for devices at boot time, and are
+  not designed to handle adding and removing devices.  One side-effect
+  of the move towards driver modularization is that it is usually easier
+  to adapt a modularized driver to handle removable devices.
+
+  It is important that a device driver be able to recover from having a
+  device disappear at an inappropriate time.  At best, the driver should
+  check for device presence before attempting any IO operation or before
+  handling an IO interrupt.  Loops that check device status should have
+  timeouts so they will eventually exit if a device never responds.
+
+  The dummy_cs driver may be useful for loading legacy drivers for
+  compatible PC Card devices.  After binding dummy_cs to a card, the
+  legacy driver module may be able to detect and communicate with the
+  device as if it were not a PC Card.  This arrangement will generally
+  not support clean hot swapping or power management functions, however
+  it may be useful as a basis for later developing a more full-featured
+  client driver.
+
+  99..  TThhee SSoocckkeett DDrriivveerr LLaayyeerr
+
+  In the Linux PCMCIA model, the ``Socket Services'' layer is a private
+  API intended only for the use of Card Services.  The API is based
+  loosely on the PCMCIA Socket Services specification, but is oriented
+  towards support for the common x86 laptop host controller types.
+
+  99..11..  CCaarrdd SSeerrvviicceess eennttrryy ppooiinnttss ffoorr ssoocckkeett ddrriivveerrss
+
+  Card Services provides special entry points for registering and
+  unregistering socket 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 socket driver invokes register_ss_entry with nsock indicating how
+  many sockets are owned by this driver, and entry pointing to the
+  function that will provide socket services for these sockets.  The
+  unregister_ss_entry routine can be safely invoked whenever Card
+  Services does not have any callback functions registered for sockets
+  owned by this driver.
+
+  99..22..  SSeerrvviicceess pprroovviiddeedd bbyy tthhee ssoocckkeett ddrriivveerr
+
+  Socket Services calls have the following form:
+
+       #include "pcmcia/ss.h"
+
+       int (*ss_entry)(u_int sock, int service, void *arg);
+
+  Non-zero return codes indicate that a request failed.
+
+  99..22..11..  SSSS__IInnqquuiirreeSSoocckkeett
+
+       int (*ss_entry)(u_int sock, SS_InquireSocket, socket_cap_t *cap);
+
+  The socket_cap_t data structure is given by:
+
+       typedef struct socket_cap_t {
+               u_int           features;
+               u_int           irq_mask;
+               u_int           map_size;
+               u_char          pci_irq;
+               u_char          cardbus;
+               struct bus_operations *bus;
+       } socket_cap_t;
+
+  The SS_InquireSocket service is used to retrieve socket capabilities.
+  The irq_mask field is a bit mask indicating which interrupts can be
+  configured for IO cards.  The map_size field gives the address
+  granularity of memory windows.  The pci_irq field, if not zero, is the
+  PCI interrupt number assigned to this socket.  It should be consistent
+  with irq_mask.  For CardBus bridges, the cardbus field should be non-
+  zero, and gives the PCI bus number of the CardBus side of the bridge.
+
+  For sockets that do not directly map cards into the host IO and memory
+  space, the bus field is a pointer to a table of entry points for IO
+  primitives for this socket.
+
+  The following flags may be specified in features:
+
+     SS_CAP_PAGE_REGS
+        Indicates that this socket supports full 32-bit addressing for
+        16-bit PC Card memory windows.
+
+     SS_CAP_VIRTUAL_BUS
+        Indicates that 16-bit card memory and IO accesses must be
+        performed using the bus operations table, rather than using
+        native bus operations.
+
+     SS_CAP_MEM_ALIGN
+        Indicates that memory windows must be aligned by the window
+        size.
+
+     SS_CAP_STATIC_MAP
+        Indicates that memory windows are statically mapped at fixed
+        locations in the host address space, and cannot be repositioned.
+
+     SS_CAP_PCCARD
+        Indicates that this socket supports 16-bit PC cards.
+
+     SS_CAP_CARDBUS
+        Indicates that this socket supports 32-bit CardBus cards.
+
+  99..22..22..  SSSS__RReeggiisstteerrCCaallllbbaacckk
+
+       int (*ss_entry)(u_int sock, SS_RegisterCallback, ss_callback_t *call);
+
+  The ss_callback_t data structure is given by:
+
+       typedef struct ss_callback_t {
+               void            (*handler)(void *info, u_int events);
+               void            *info;
+       } ss_callback_t;
+
+  The SS_RegisterCallback service sets up a callback function to be
+  invoked when the socket driver receives card status change events.  To
+  unregister a callback, this function is called with a handler value of
+  NULL.  Only one callback function can be registered per socket.
+
+  The handler will be called with the value of info that was passed to
+  SS_RegisterCallback for this socket, and with a bit map of events in
+  the events parameter.  The following events are defined:
+
+     SS_DETECT
+        A card detect change (insertion or removal) has been detected.
+
+     SS_READY
+        A memory card's ready signal has changed state.
+
+     SS_BATDEAD
+        A memory card has raised the battery-dead signal.
+
+     SS_BATWARN
+        A memory card has raised the battery-low signal.
+
+     SS_STSCHG
+        An IO card has raised the status change signal.
+
+  99..22..33..  SSSS__GGeettSSttaattuuss
+
+       int (*ss_entry)(u_int sock, SS_GetStatus, u_int *status);
+
+  The SS_GetStatus service returns the current status of this socket.
+  The status parameter will be constructed out of the following flags:
+
+     SS_WRPROT
+        The card is write-protected.
+
+     SS_BATDEAD
+        A memory card has raised the battery-dead signal.
+
+     SS_BATWARN
+        A memory card has raised the battery-low signal.
+
+     SS_READY
+        A memory card has raised its ready signal.
+
+     SS_DETECT
+        A card is present.
+
+     SS_POWERON
+        Power has been applied to the socket.
+
+     SS_STSCHG
+        An IO card has raised the status change signal.
+
+     SS_CARDBUS
+        The socket contains a CardBus card (as opposed to a 16-bit PC
+        Card).
+
+     SS_3VCARD
+        The card must be operated at no more than 3.3V.
+
+     SS_XVCARD
+        The card must be operated at no more than X.XV (not yet
+        defined).
+
+  99..22..44..  SSSS__GGeettSSoocckkeett,, SSSS__SSeettSSoocckkeett
+
+       int (*ss_entry)(u_int sock, SS_GetSocket, socket_state_t *);
+       int (*ss_entry)(u_int sock, SS_SetSocket, socket_state_t *);
+
+  The socket_state_t data structure is given by:
+
+       typedef struct socket_state_t {
+               u_int           flags;
+               u_int           csc_mask;
+               u_char          Vcc, Vpp;
+               u_char          io_irq;
+       } socket_state_t;
+
+  The csc_mask field indicates which event types should generate card
+  status change interrupts.  The following event types can be monitored:
+
+     SS_DETECT
+        Card detect changes (insertion or removal).
+
+     SS_READY
+        Memory card ready/busy changes.
+
+     SS_BATDEAD
+        Memory card battery-dead changes.
+
+     SS_BATWARN
+        Memory card battery-low changes.
+     SS_STSCHG
+        IO card status changes.
+
+  The Vcc and Vpp parameters are in units of 0.1 volts.  If non-zero,
+  io_irq specifies an interrupt number to be assigned to the card, in IO
+  mode.  The following fields are defined in flags:
+
+     SS_PWR_AUTO
+        Indicates that the socket should automatically power up sockets
+        at card insertion time, if supported.
+
+     SS_IOCARD
+        Indicates that the socket should be configured for ``memory and
+        IO'' interface mode, as opposed to simple memory card mode.
+
+     SS_RESET
+        Indicates that the card's hardware reset signal should be
+        raised.
+
+     SS_SPKR_ENA
+        Indicates that speaker output should be enabled for this socket.
+
+     SS_OUTPUT_ENA
+        Indicates that data signals to the card should be activated.
+
+  99..22..55..  SSSS__GGeettIIOOMMaapp,, SSSS__SSeettIIOOMMaapp
+
+       int (*ss_entry)(u_int sock, SS_GetIOMap, pccard_io_map *);
+       int (*ss_entry)(u_int sock, SS_SetIOMap, pccard_io_map *);
+
+  The pccard_io_map data structure is given by:
+
+       typedef struct pccard_io_map {
+               u_char          map;
+               u_char          flags;
+               u_short         speed;
+               u_short         start, stop;
+       } pccard_io_map;
+
+  The SS_GetIOMap and SS_SetIOMap entries are used to configure IO space
+  windows.  IO windows are assumed to not support address translation.
+  The Linux Card Services layer assumes that each socket has at least
+  two independently configurable IO port windows.
+
+  The map field specifies which IO map should be accessed.  The speed
+  field is the map access speed in nanoseconds.  The start and stop
+  fields give the lower and upper addresses for the IO map.  The flags
+  field is composed of the following:
+
+     MAP_ACTIVE
+        Specifies that the address map should be enabled.
+
+     MAP_16BIT
+        Specifies that the map should be configured for 16-bit accesses
+        (as opposed to 8-bit).
+
+     MAP_AUTOSZ
+        Specifies that the map should be configured to auto-size bus
+        accesses in response to the card's IOCS16 signal.
+
+     MAP_0WS
+        Requests zero wait states, as opposed to standard ISA bus
+        timing.
+
+     MAP_WRPROT
+        Specifies that the map should be write protected.
+
+     MAP_USE_WAIT
+        Specifies that access timing should respect the card's WAIT
+        signal.
+
+     MAP_PREFETCH
+        Specifies that this map may be configured for prefetching.
+
+  99..22..66..  SSSS__GGeettMMeemmMMaapp,, SSSS__SSeettMMeemmMMaapp
+
+       int (*ss_entry)(u_int sock, SS_GetMemMap, pccard_mem_map *);
+       int (*ss_entry)(u_int sock, SS_SetMemMap, pccard_mem_map *);
+
+  The pccard_mem_map data structure is given by:
+
+       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;
+
+  The map field specifies the map number.  The speed field specifies an
+  access speed in nanoseconds.  The sys_start and sys_stop fields give
+  the starting and ending addresses for the window in the host's
+  physical address space.  The card_start value specifies the card
+  address to be mapped to sys_start.  The Linux Card Services layer
+  assumes that each socket has at least four independently configurable
+  memory windows.
+
+     MAP_ACTIVE
+        Specifies that the address map should be enabled.
+
+     MAP_16BIT
+        Specifies that the map should be configured for 16-bit accesses
+        (as opposed to 8-bit).
+
+     MAP_AUTOSZ
+        Specifies that the map should be configured to auto-size bus
+        accesses in response to the card's IOCS16 signal.
+
+     MAP_0WS
+        Requests zero wait states, as opposed to standard ISA bus
+        timing.
+
+     MAP_WRPROT
+        Specifies that the map should be write protected.
+
+     MAP_ATTRIB
+        Specifies that the map should be for attribute (as opposed to
+        common) memory.
+
+     MAP_USE_WAIT
+        Specifies that access timing should respect the card's WAIT
+        signal.
+
+  99..22..77..  SSSS__GGeettBBrriiddggee,, SSSS__SSeettBBrriiddggee
+
+       int (*ss_entry)(u_int sock, SS_GetBridge, cb_bridge_map *);
+       int (*ss_entry)(u_int sock, SS_SetBridge, cb_bridge_map *);
+
+  The cb_bridge_map data structure is given by:
+
+       typedef struct cb_bridge_map {
+               u_char          map;
+               u_char          flags;
+               u_int           start, stop;
+       } cb_bridge_map;
+
+  The SS_GetBridge and SS_SetBridge entry points are used for
+  configuring bridge address windows for CardBus devices.  They are
+  similar to the 16-bit IO and memory map services.  It is assumed that
+  each CardBus socket has at least two IO and two memory bridge windows.
+  The flags field is composed of:
+
+     MAP_ACTIVE
+        Specifies that the address map should be enabled.
+
+     MAP_PREFETCH
+        Specifies that this map can be configured for prefetching.
+
+     MAP_IOSPACE
+        Specifies that this map should be for IO space (as opposed to
+        memory space).
+
+  99..22..88..  SSSS__PPrrooccSSeettuupp
+
+       int (*ss_entry)(u_int sock, SS_ProcSetup, struct proc_dir_entry *base);
+
+  Card Services uses this entry point to give the socket driver a procfs
+  directory handle under which it may create status files for a specific
+  socket.  It is the socket driver's responsbility to delete any proc
+  entries before it is unloaded.
+
+  99..33..  SSuuppppoorrttiinngg uunnuussuuaall ssoocckkeett aarrcchhiitteeccttuurreess
+
+  The Socket Services interface is oriented towards socket controllers
+  that allow PCMCIA cards to be configured to mimic native system
+  devices with the same functionality.  The ExCA standard specifies that
+  socket controllers should provide two IO and five memory windows per
+  socket, which can be independently configured and positioned in the
+  host address space and mapped to arbitrary segments of card address
+  space.  Some controllers and architectures do not provide this level
+  of functionality.  In these situations, Socket Services can
+  effectively virtualize the socket interface for client drivers.
+
+  On the client side (including internal Card Services uses), to use the
+  virtualized socket interface, code must first specify:
+
+       #include "pcmcia/bus_ops.h"
+
+  All IO operations then need to be replaced with new bus-neutral forms.
+  The following functions need to be virtualized:
+
+  +o  inb, inw, inl, inw_ns, inl_ns
+
+  +o  insb, insw, insl, insw_ns, insl_ns
+
+  +o  outb, outw, outl, outw_ns, outl_ns
+
+  +o  outsb, outsw, outsl, outsw_ns, outsl_ns
+
+  +o  readb, readw, readl, readw_ns, readl_ns
+
+  +o  writeb, writew, writel, writew_ns, writel_ns
+
+  +o  ioremap, iounmap
+
+  +o  memcpy_fromio, memcpy_toio
+
+  +o  request_irq, free_irq
+
+  The bus-neutral functions have a prefix of ``bus_'', with a new first
+  argument, the bus operations table pointer returned by
+  SS_InquireSocket.  For example, inb(port) should be replaced with
+  bus_inb(bus, port).
+
+  All the IO primitives are defined as macros that call entry points in
+  the bus operations table.  There is not a one-to-one mapping from IO
+  primitives to bus operation entry points.
+
+  The bus operations table is defined as:
+
+  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;
+
+  The priv field can be used for any purpose by the socket driver, for
+  instance, to indicate which of several sockets is being addressed.
+  The b_in, b_out, b_read, and b_write entry points each support byte,
+  word, and dword operations, either byte-swapped or unswapped.  The sz
+  parameter is 0, 1, or 2 for byte, word, or dword accesses; -1 and -2
+  select word and dword unswapped accesses.
+
+  1100..  WWhheerree ttoo GGoo ffoorr MMoorree IInnffoorrmmaattiioonn
+
+  The _L_i_n_u_x _K_e_r_n_e_l _H_a_c_k_e_r_s_' _G_u_i_d_e, written by Michael Johnson, is a good
+  source of general information about writing Linux device drivers.  It
+  is available from the usual Linux FTP sites, and is included in many
+  compilations of Linux documentation.
+
+  The PC Card standard is only available from the PCMCIA association
+  itself, and is somewhat expensive for non-members.  The PCMCIA
+  association is at  <http://www.pc-card.com>, or:
+
+       Personal Computer Memory Card International Association
+       1030 East Duane Avenue, Suite G
+       Sunnyvale, CA 94086 USA
+       (408) 720-0107, (408) 720-9416 FAX, (408) 720-9388 BBS
+
+  An alternative is the _P_C_M_C_I_A _D_e_v_e_l_o_p_e_r_'_s _G_u_i_d_e, by Michael Mori, ISBN
+  0-9640342-1-2, available from Sycard Technology, at
+  <http://www.sycard.com> or:
+
+  Sycard Technology
+  1180-F Miraloma Way
+  Sunnyvale, CA 94086 USA
+  (408) 749-0130, (408) 749-1323 FAX
+
+  The _P_C_M_C_I_A _S_o_f_t_w_a_r_e _D_e_v_e_l_o_p_e_r_'_s _H_a_n_d_b_o_o_k by Steven Kipisz, Dana
+  Beatty, and Brian Moore includes an overview of the PC Card standard,
+  and descriptions of how to write client drivers.  It also includes the
+  Linux PCMCIA Programmer's Guide, as an appendix.  It is published by
+  Peer-to-Peer Communications, ISBN 1-57398-010-2.
+
+  Larry Levine has written a more general introduction to PCMCIA called
+  the _P_C_M_C_I_A _P_r_i_m_e_r.  It is published by M & T Books, ISBN
+  1-55828-437-0.
+
+  Programming information for various PC Card host controllers is
+  available from the corresponding chip vendors.  Generally, data sheets
+  are either available on line or can be ordered from each company's web
+  site.  A collection of datasheets can be found at
+  <http:/pcmcia.sourceforge.org/specs>.
+
Index: oldkernel/linux/pcmcia-cs-3.1.15/doc/PCMCIA-PROG.ps
diff -u /dev/null linux/pcmcia-cs-3.1.15/doc/PCMCIA-PROG.ps:1.1
--- /dev/null	Mon Jul 31 21:15:11 2000
+++ linux/pcmcia-cs-3.1.15/doc/PCMCIA-PROG.ps	Fri Jul  7 16:34:58 2000
@@ -0,0 +1,5504 @@
+%!PS-Adobe-2.0
+%%Creator: dvips(k) 5.85 Copyright 1999 Radical Eye Software
+%%Title: PCMCIA-PROG.dvi
+%%Pages: 72
+%%PageOrder: Ascend
+%%BoundingBox: 0 0 612 792
+%%EndComments
+%DVIPSWebPage: (www.radicaleye.com)
+%DVIPSCommandLine: dvips -t letter PCMCIA-PROG.dvi -o PCMCIA-PROG.ps
+%DVIPSParameters: dpi=600, compressed
+%DVIPSSource:  TeX output 2000.03.15:1827
+%%BeginProcSet: texc.pro
+%!
+/TeXDict 300 dict def TeXDict begin/N{def}def/B{bind def}N/S{exch}N/X{S
+N}B/A{dup}B/TR{translate}N/isls false N/vsize 11 72 mul N/hsize 8.5 72
+mul N/landplus90{false}def/@rigin{isls{[0 landplus90{1 -1}{-1 1}ifelse 0
+0 0]concat}if 72 Resolution div 72 VResolution div neg scale isls{
+landplus90{VResolution 72 div vsize mul 0 exch}{Resolution -72 div hsize
+mul 0}ifelse TR}if Resolution VResolution vsize -72 div 1 add mul TR[
+matrix currentmatrix{A A round sub abs 0.00001 lt{round}if}forall round
+exch round exch]setmatrix}N/@landscape{/isls true N}B/@manualfeed{
+statusdict/manualfeed true put}B/@copies{/#copies X}B/FMat[1 0 0 -1 0 0]
+N/FBB[0 0 0 0]N/nn 0 N/IEn 0 N/ctr 0 N/df-tail{/nn 8 dict N nn begin
+/FontType 3 N/FontMatrix fntrx N/FontBBox FBB N string/base X array
+/BitMaps X/BuildChar{CharBuilder}N/Encoding IEn N end A{/foo setfont}2
+array copy cvx N load 0 nn put/ctr 0 N[}B/sf 0 N/df{/sf 1 N/fntrx FMat N
+df-tail}B/dfs{div/sf X/fntrx[sf 0 0 sf neg 0 0]N df-tail}B/E{pop nn A
+definefont setfont}B/Cw{Cd A length 5 sub get}B/Ch{Cd A length 4 sub get
+}B/Cx{128 Cd A length 3 sub get sub}B/Cy{Cd A length 2 sub get 127 sub}
+B/Cdx{Cd A length 1 sub get}B/Ci{Cd A type/stringtype ne{ctr get/ctr ctr
+1 add N}if}B/id 0 N/rw 0 N/rc 0 N/gp 0 N/cp 0 N/G 0 N/CharBuilder{save 3
+1 roll S A/base get 2 index get S/BitMaps get S get/Cd X pop/ctr 0 N Cdx
+0 Cx Cy Ch sub Cx Cw add Cy setcachedevice Cw Ch true[1 0 0 -1 -.1 Cx
+sub Cy .1 sub]/id Ci N/rw Cw 7 add 8 idiv string N/rc 0 N/gp 0 N/cp 0 N{
+rc 0 ne{rc 1 sub/rc X rw}{G}ifelse}imagemask restore}B/G{{id gp get/gp
+gp 1 add N A 18 mod S 18 idiv pl S get exec}loop}B/adv{cp add/cp X}B
+/chg{rw cp id gp 4 index getinterval putinterval A gp add/gp X adv}B/nd{
+/cp 0 N rw exit}B/lsh{rw cp 2 copy get A 0 eq{pop 1}{A 255 eq{pop 254}{
+A A add 255 and S 1 and or}ifelse}ifelse put 1 adv}B/rsh{rw cp 2 copy
+get A 0 eq{pop 128}{A 255 eq{pop 127}{A 2 idiv S 128 and or}ifelse}
+ifelse put 1 adv}B/clr{rw cp 2 index string putinterval adv}B/set{rw cp
+fillstr 0 4 index getinterval putinterval adv}B/fillstr 18 string 0 1 17
+{2 copy 255 put pop}for N/pl[{adv 1 chg}{adv 1 chg nd}{1 add chg}{1 add
+chg nd}{adv lsh}{adv lsh nd}{adv rsh}{adv rsh nd}{1 add adv}{/rc X nd}{
+1 add set}{1 add clr}{adv 2 chg}{adv 2 chg nd}{pop nd}]A{bind pop}
+forall N/D{/cc X A type/stringtype ne{]}if nn/base get cc ctr put nn
+/BitMaps get S ctr S sf 1 ne{A A length 1 sub A 2 index S get sf div put
+}if put/ctr ctr 1 add N}B/I{cc 1 add D}B/bop{userdict/bop-hook known{
+bop-hook}if/SI save N @rigin 0 0 moveto/V matrix currentmatrix A 1 get A
+mul exch 0 get A mul add .99 lt{/QV}{/RV}ifelse load def pop pop}N/eop{
+SI restore userdict/eop-hook known{eop-hook}if showpage}N/@start{
+userdict/start-hook known{start-hook}if pop/VResolution X/Resolution X
+1000 div/DVImag X/IEn 256 array N 2 string 0 1 255{IEn S A 360 add 36 4
+index cvrs cvn put}for pop 65781.76 div/vsize X 65781.76 div/hsize X}N
+/p{show}N/RMat[1 0 0 -1 0 0]N/BDot 260 string N/Rx 0 N/Ry 0 N/V{}B/RV/v{
+/Ry X/Rx X V}B statusdict begin/product where{pop false[(Display)(NeXT)
+(LaserWriter 16/600)]{A length product length le{A length product exch 0
+exch getinterval eq{pop true exit}if}{pop}ifelse}forall}{false}ifelse
+end{{gsave TR -.1 .1 TR 1 1 scale Rx Ry false RMat{BDot}imagemask
+grestore}}{{gsave TR -.1 .1 TR Rx Ry scale 1 1 false RMat{BDot}
+imagemask grestore}}ifelse B/QV{gsave newpath transform round exch round
+exch itransform moveto Rx 0 rlineto 0 Ry neg rlineto Rx neg 0 rlineto
+fill grestore}B/a{moveto}B/delta 0 N/tail{A/delta X 0 rmoveto}B/M{S p
+delta add tail}B/b{S p tail}B/c{-4 M}B/d{-3 M}B/e{-2 M}B/f{-1 M}B/g{0 M}
+B/h{1 M}B/i{2 M}B/j{3 M}B/k{4 M}B/w{0 rmoveto}B/l{p -4 w}B/m{p -3 w}B/n{
+p -2 w}B/o{p -1 w}B/q{p 1 w}B/r{p 2 w}B/s{p 3 w}B/t{p 4 w}B/x{0 S
+rmoveto}B/y{3 2 roll p a}B/bos{/SS save N}B/eos{SS restore}B end
+
+%%EndProcSet
+TeXDict begin 40258431 52099146 1000 600 600 (PCMCIA-PROG.dvi)
+@start
+%DVIPSBitmapFont: Fa ecti1000 10 32
+/Fa 32 121 df<EA01E0EA07F0120F13F8121FA3120FEA07B0EA0030A21370136013E013
+C0120113801203EA0700120E5A5A5A5A5A0D196EB919>39 D<EE01C01603A21607160FA2
+161F83163FA2167F16FF16EF150116CFED038FA2ED070FA2150E151E151C1538A203707F
+A2EDE007A2EC01C014031580EC0700A2140EA25CA25C027FB5FCA291B6FC9139E00007F8
+49481303A2495A130791C7FC5B130E5BA25B1378137013F0487ED807FC4A7EB56C48B512
+F0A3343C7BBB3E>65 D<DB03FE130E92393FFF801E92B5EAE03C913903FE01F0913A0FF0
+00787CDA3FC0EB3CFC4AC7EA1FF802FE140FEB03FC49481407494815F049481403495A5C
+49C813E05B485A5B000317C0485AA2485A1880485A94C7FCA2485AA3127F5BA312FF90CB
+FCA41738A217784816707E17F06C5E16015F16036C6C4A5A94C7FC001F150E6D141E000F
+5D6D5C6C6C495A6C6CEB03C0D801FEEB0F8027007F807EC8FC6DB45A010F13E0010090C9
+FC373D74BA3B>67 D<0103B612FEEFFFC018F0903B0007F8000FF84BEB03FCEF00FE020F
+157FF03F804B141F19C0021F150F19E05D1807143F19F05DA2147FA292C8FCA25C180F5C
+A2130119E04A151FA2130319C04A153FA201071780187F4A1600A2010F16FEA24A4A5A60
+011F15034D5A4A5D4D5A013F4B5A173F4A4AC7FC17FC017FEC03F84C5A91C7EA1FC04949
+B45A007F90B548C8FCB712F016803C397CB83F>I<DB03FE130E92393FFF801E92B5EAE0
+3C913903FE01F0913A0FF000787CDA3FC0EB3CFC4AC7EA1FF802FE140FEB03FC49481407
+494815F049481403495A5C49C813E05B485A5B000317C0485AA2485A1880485A94C7FCA2
+485AA3127F5BA312FF90CBFC0307B512E0A392390007FC00705A16075FA36C150F5FA36C
+6C141F5F121F6D143F6C7E4C5A6C6C14FF6C6CEB03EFD801FEEB07C728007FC03F07C7FC
+90393FFFFC03010F01F0C8FC01001380373D74BA40>71 D<0103B5D8F80FB512E0A39026
+0007F8C7381FE0004B5DA2020F153F615DA2021F157F96C7FC5DA2023F5D605DA2027F14
+016092C7FCA24A1403605CA249B7FC60A202FCC712070103150F605CA20107151F605CA2
+010F153F605CA2011F157F95C8FC5CA2013F5D5F5CA2017F14015F91C7FC491403007FD9
+FE01B512F8B55BA243397CB83E>I<0103B512F8A390390007F8005DA2140FA25DA2141F
+A25DA2143FA25DA2147FA292C7FCA25CA25CA21301A25CA21303A25CA21307A25CA2130F
+A25CA2131FA25CA2133FA25CA2137FA291C8FC497EB6FCA25C25397CB820>I<0103B500
+F890387FFFE0A21AC090260007F8C7380FFC004B15E061020F4BC7FC183E4B5C18F0021F
+4A5A4D5A4BEB0F804DC8FC023F143C5F4B5B4C5A027FEB07C04CC9FCED001E5E4A5BED01
+FCECFE0315070101497E151FECFC7C4B7E903903FDE07FDAFFC07F1580ED003F49488014
+F84A131F83130F160F4A801607011F81A24A130383133F16014A80A2017F6E7EA291C8FC
+494A7F007F01FE011F13FCB55CA243397CB840>75 D<0107B512FCA25E9026000FF8C7FC
+5D5D141FA25DA2143FA25DA2147FA292C8FCA25CA25CA21301A25CA21303A25CA21307A2
+5CA2130F170C4A141CA2011F153C17384A1478A2013F157017F04A14E01601017F140317
+C091C71207160F49EC1F80163F4914FF000102071300B8FCA25E2E397BB834>I<902607
+FFF8923807FFF0614F13E0D9000FEFF0004F5AA2021F167FF1EFC0141DDA1CFCEC01CF02
+3C16DF9538039F800238ED071FA20278ED0E3F97C7FC0270151CA202F04B5AF0707E14E0
+037E14E0010117FE4D485A02C0EC0380A20103ED0701610280140EA20107ED1C0305385B
+14006F137049160705E05B010EEC01C0A2011E913803800F61011CEC0700A2013C020E13
+1F4C5C1338ED1FB80178163F04F091C8FC01705CA201F04A5B187E00015DD807F816FEB5
+00C09039007FFFFC151E150E4C397AB84A>I<0107B612F817FF1880903B000FF0003FE0
+4BEB0FF0EF03F8141FEF01FC5DA2023F15FEA25DA2147FEF03FC92C7FCA24A15F817074A
+15F0EF0FE01301EF1FC04AEC3F80EFFE0001034A5AEE0FF091B612C04CC7FCD907F8C9FC
+A25CA2130FA25CA2131FA25CA2133FA25CA2137FA291CAFCA25BA25B1201B512FCA33739
+7BB838>80 D<92383FC00E913901FFF01C020713FC91391FC07E3C91393F001F7C027CEB
+0FF84A130749481303495A4948EB01F0A2495AA2011F15E091C7FCA34915C0A36E90C7FC
+A2806D7E14FCECFF806D13F015FE6D6D7E6D14E0010080023F7F14079138007FFC150F15
+031501A21500A2167C120EA3001E15FC5EA3003E4A5AA24B5AA2007F4A5A4B5A6D49C7FC
+6D133ED8F9F013FC39F8FC03F839F07FFFE0D8E01F138026C003FCC8FC2F3D7ABA2F>83
+D<14F8EB07FE90381F871C90383E03FE137CEBF801120148486C5A485A120FEBC001001F
+5CA2EA3F801403007F5C1300A21407485C5AA2140F5D48ECC1C0A2141F15831680143F15
+87007C017F1300ECFF076C485B9038038F8E391F0F079E3907FE03FC3901F000F0222677
+A42A>97 D<133FEA1FFFA3C67E137EA313FE5BA312015BA312035BA31207EBE0F8EBE7FE
+9038EF0F80390FFC07C013F89038F003E013E0D81FC013F0A21380A2123F1300A214075A
+127EA2140F12FE4814E0A2141F15C05AEC3F80A215005C147E5C387801F8007C5B383C03
+E0383E07C0381E1F80D80FFEC7FCEA01F01C3B77B926>I<147F903803FFC090380FC1E0
+90381F0070017E13784913383901F801F83803F003120713E0120FD81FC013F091C7FC48
+5AA2127F90C8FCA35A5AA45AA3153015381578007C14F0007EEB01E0003EEB03C0EC0F80
+6CEB3E00380F81F83803FFE0C690C7FC1D2677A426>I<ED01F815FFA3150316F0A21507
+A216E0A2150FA216C0A2151FA21680A2153FA202F81300EB07FE90381F877F90383E03FF
+017C5BEBF80112013803F00048485B120FEBC001121F5DEA3F801403127F01005BA21407
+5A485CA2140FA248ECC1C0A2141F15C3ED8380143F1587007C017F1300ECFF076C485B90
+38038F8E391F0F079E3907FE03FC3901F000F0253B77B92A>I<147F903803FFC090380F
+C1E090383F00F0017E13785B485A485A485A120F4913F8001F14F0383F8001EC07E0EC1F
+80397F81FF00EBFFF8148090C8FC5A5AA55AA21530007C14381578007E14F0003EEB01E0
+EC03C06CEB0F806CEB3E00380781F83803FFE0C690C7FC1D2677A426>I<ED07C0ED1FF0
+ED3E38ED7C3CEDF8FC15F9140115F1020313F8EDF0F0160014075DA4140F5DA4141F5D01
+0FB512C05B16809039003F800092C7FCA45C147EA414FE5CA413015CA413035CA413075C
+A4130F5CA3131F5CA391C8FC5B121CEA7E3EA2EAFE3C137C1378EAF8F01278EA3FC0EA0F
+80264C82BA19>I<EB01C0EB07E014F0130F14E01307EB038090C7FCAB13F0EA03FCEA07
+1EEA0E1F121CA212385B1270A25BEAF07E12E013FEC65AA212015B1203A25B12075BA200
+0F13E013C013C1001F13C01381A2EB83801303EB0700A2130E6C5AEA07F8EA01E0143879
+B619>105 D<EB03F0EA01FFA3EA00075CA3130F5CA3131F5CA3133F91C8FCA35B017EEB
+0F80ED3FE015F09039FE01C1F09038FC0387EC0707140E0001011C13E0EBF83891383003
+800270C7FC00035BEBF1C0EBF38001FFC8FCEA07FC7FEBFFC0EBE7F8380FE1FCEBC07E14
+7F80001F809039801F81C0A21583003F013F138001001303A21507481500007E133EEC1E
+0E151E00FE6D5A48EB07F80038EB01E0243B7BB926>107 D<EB0FC0EA07FFA3EA001F14
+80A2133FA21400A25BA2137EA213FEA25BA21201A25BA21203A25BA21207A25BA2120FA2
+5BA2121FA25BA2123FA290C7FCA25AA2EA7E0EA212FE131EEAFC1CA2133C133812F81378
+EA7870EA7CE0121FEA0F80123B79B915>I<D801E001FEEB07F03C07F803FF801FFC3C0E
+3C0F07C0783E3C1E3E3C03E1E01F261C1F78D9F3C013803C383FF001F7800F02E0140000
+7801C013FE007018C002805B4A4848EB1F80EAF07FD8E07E5CA200000207143F01FE1700
+495CA2030F5C0001177E495C18FE031F5C120349DA8001131C18F8033F153C0007040313
+3849020013F0A24B1570000F17E049017E15F019E003FEECE1C0001FEE01E34949903800
+FF000007C70038143C3E2679A444>I<D801E013FE3A07F803FF803A0E3C0F07C03A1E3E
+3C03E0261C1F787F39383FF00114E0007813C000708114804A485AEAF07FEAE07EA20000
+140701FE5C5BA2150F00015D5B151F5E12034990383F8380160316070007027F13004913
+7EA2160E000F147C49141E161C5E001FEC3C7849EB1FE00007C7EA0780292679A42F>I<
+147F903803FFC090380FC1F090381F00F8017E137C5B4848137E4848133E0007143F5B12
+0F485AA2485A157F127F90C7FCA215FF5A4814FEA2140115FC5AEC03F8A2EC07F015E014
+0F007C14C0007EEB1F80003EEB3F00147E6C13F8380F83F03803FFC0C648C7FC202677A4
+2A>I<9039078007C090391FE03FF090393CF0787C903938F8E03E9038787FC00170497E
+ECFF00D9F0FE148013E05CEA01E113C15CA2D80003143FA25CA20107147FA24A1400A201
+0F5C5E5C4B5A131F5EEC80035E013F495A6E485A5E6E48C7FC017F133EEC70FC90387E3F
+F0EC0F8001FEC9FCA25BA21201A25BA21203A25B1207B512C0A3293580A42A>I<3903C0
+03F0390FF01FFC391E783C0F381C7C703A3C3EE03F8038383FC0EB7F8000781500007013
+00151CD8F07E90C7FCEAE0FE5BA2120012015BA312035BA312075BA3120F5BA3121F5BA3
+123F90C9FC120E212679A423>114 D<14FE903807FF8090380F83C090383E00E04913F0
+0178137001F813F00001130313F0A215E00003EB01C06DC7FC7FEBFFC06C13F814FE6C7F
+6D13807F010F13C01300143F141F140F123E127E00FE1480A348EB1F0012E06C133E0070
+5B6C5B381E03E06CB45AD801FEC7FC1C267AA422>I<EB0380EB07C0130FA4131F1480A3
+133F1400A35B137E007FB5FCA2B6FC3800FC00A312015BA312035BA312075BA3120F5BA3
+121FEB801CA2143C003F1338EB0078147014F014E0EB01C0EA3E03381F0780380F0F00EA
+07FCEA01F0183579B31C>I<13F8D803FEEB01C0D8078FEB03E0390E0F8007121E121C00
+38140F131F007815C01270013F131F00F0130000E015805BD8007E133FA201FE14005B5D
+120149137EA215FE120349EBFC0EA20201131E161C15F813E0163CD9F003133814070001
+ECF07091381EF8F03A00F83C78E090393FF03FC090390FC00F00272679A42D>I<01F013
+0ED803FC133FD8071EEB7F80EA0E1F121C123C0038143F49131F0070140FA25BD8F07E14
+0000E08013FEC6485B150E12015B151E0003141C5BA2153C000714385B5DA35DA24A5A14
+0300035C6D48C7FC0001130E3800F83CEB7FF8EB0FC0212679A426>I<01F01507D803FC
+903903801F80D8071E903907C03FC0D80E1F130F121C123C0038021F131F49EC800F0070
+1607A249133FD8F07E168000E0ED000313FEC64849130718000001147E5B03FE5B000316
+0E495BA2171E00070101141C01E05B173C1738A217781770020314F05F0003010713016D
+486C485A000190391E7C07802800FC3C3E0FC7FC90393FF81FFE90390FE003F0322679A4
+37>I<903907E007C090391FF81FF89039787C383C9038F03E703A01E01EE0FE3803C01F
+018013C0D8070014FC481480000E1570023F1300001E91C7FC121CA2C75AA2147EA214FE
+A25CA21301A24A1370A2010314F016E0001C5B007E1401010714C000FEEC0380010F1307
+010EEB0F0039781CF81E9038387C3C393FF03FF03907C00FC027267CA427>I
+E
+%EndDVIPSBitmapFont
+%DVIPSBitmapFont: Fb cmsy10 10 1
+/Fb 1 16 df<EB1FF0EBFFFE487F000714C04814E04814F04814F8A24814FCA3B612FEA9
+6C14FCA36C14F8A26C14F06C14E06C14C0000114006C5BEB1FF01F1F7BA42A>15
+D E
+%EndDVIPSBitmapFont
+%DVIPSBitmapFont: Fc cmmi10 10 1
+/Fc 1 63 df<126012FCB4FCEA7FC0EA1FF0EA07FCEA01FF38007FC0EB1FF0EB07FCEB01
+FF9038007FC0EC1FF0EC07FCEC01FF9138007FC0ED1FF0ED07FCED01FF9238007FC0EE1F
+F0EE07FCEE01FF9338007F80EF1FC0A2EF7F80933801FF00EE07FCEE1FF0EE7FC04B48C7
+FCED07FCED1FF0ED7FC04A48C8FCEC07FCEC1FF0EC7FC04948C9FCEB07FCEB1FF0EB7FC0
+4848CAFCEA07FCEA3FF0EA7FC048CBFC12FC1270323279AD41>62
+D E
+%EndDVIPSBitmapFont
+%DVIPSBitmapFont: Fd ectt0900 9 79
+/Fd 79 126 df<00101320007C13F838FE01FCAAEAFC00007C13F8A900381370161778AE
+27>34 D<90381C01C090383E03E0A7EB7E07017C13C0A3007FB512FEB7FCA36C14FE3900
+F80F80A50001131F01F01300A6007FB512FEB7FCA36C14FE3903E03E00A30007137EEBC0
+7CA738038038202E7DAD27>I<131FEB7FC0497E5A80EA03F1EBE1F8EA07E013C0A513C1
+5C9039C3F1FF80D9E3E113C03803E7E3EBEFC101FF1480913881F800EC01F0EA01FEEBFC
+0301F85B00031307D807FC5B120F381FFE0FD83FBE5BEB3F1FD87E1F90C7FC149F38FC0F
+BF14FE1307ECFC020103EB0F80EB01F8A238FE03FC387E07FE397F1FFF9F6CB61200149F
+6CEB0FFE390FFC03FC3903F000F822307EAE27>38 D<EB01C0EB03E0130F131FEB3FC0EB
+7F80EBFE00485A5B1203485A5B485AA2485AA248C7FCA3127EA45AAC127EA47EA36C7EA2
+6C7EA26C7E7F6C7E12017F6C7EEB7F80EB3FC0EB1FE0130F1303EB01C0133A73B327>40
+D<127012F812FE7E6C7E6C7EEA0FE06C7E12037F6C7E1200137EA27FA2EB1F80A3EB0FC0
+A4EB07E0ACEB0FC0A4EB1F80A3EB3F00A2137EA25B1201485A5B1207485AEA3FC0485A48
+C7FC5A12F81270133A7AB327>I<130F497EA60078EB81E000FEEB87F000FF138FEBDFBF
+6CB512E06C14C0000F1400000313FCC613F0A2000313FC000F13FF003F14C04814E039FF
+DFBFF0EB1F8F00FE13870078EB81E00000EB8000A66DC7FC1C207BA627>I<120FEA3FC0
+13E0EA7FF0A213F8A2123FA2120F120113F01203EA07E0121FEA7FC0EAFF8013005A1270
+0D14738927>44 D<007FB51280B612C0A36C14801A057A9227>I<121EEA7F80A2EAFFC0
+A4EA7F80A2EA1E000A0A728927>I<1538157CA215FC15F8140115F0140315E0140715C0
+A2140F1580141F15005C143E147E147C14FC5C13015C13035C13075C130F5CA2131F91C7
+FC5B133E137E137C13FC5B12015B12035B12075B120F5BA2121F90C8FC5A123E127E127C
+12FC5AA212701E3A7CB327>I<EB07E0EB3FFC497E90B5FC4814803903FC3FC03907F00F
+E0390FE007F0EBC003391F8001F8A248C712FCA2003E147C007E147EA3007C143E00FC14
+3FAC007E147EA46C14FCA2EB8001001F14F8EBC003000F14F0EBE0073907F00FE03903FC
+3FC06CB512806C14006D5A6D5AEB07E020307DAE27>I<130E131FA25B5BA25B5A5A127F
+B5FCA213BFEA7E3F1200B3AA003FB512805A15C01580A21A2F79AE27>I<EB3FE03801FF
+F84813FE000FEBFF804814C0393FE07FE0EB800F397F0007F0007EEB03F800FE13015A6C
+14FC1400A3127CC8FCA2140115F8A2140315F01407EC0FE0EC1FC0143FEC7F80ECFF0049
+5A495A495A495A495A495A495A01FEC7FC485AD807F81378484813FC485A485A48B5FCB6
+FCA36C14F81E2F7CAE27>I<EB1FF8EBFFFE0003EBFF80000F14C015E0391FF01FF0393F
+C007F8EB800115FC1400A26CC7FC1204C8FC140115F81403EC07F0140FEC3FE090381FFF
+C0491380A215E06D13F09038001FF8EC03FC1401EC00FE157E157F153FA21238127C12FE
+A2157F48147E6C14FE007FEB01FCEB8003393FF01FF86CB512F06C14E000031480C6EBFE
+00EB1FF820307DAE27>I<EC3F804A7EA214FF5BA2EB03F7EB07E7A2EB0FC71487131FEB
+3F07A2137E13FCA2EA01F813F01203EA07E0A2EA0FC0EA1F80A2EA3F00123E127E5AB712
+8016C0A36C1580C73807C000A849B5FC491480A36D1400222F7EAE27>I<001FB512E048
+14F0A315E090C8FCACEB1FF0EBFFFC14FF158015C09038F03FE09038C00FF0EB0007003E
+EB03F8001C1301C7FC15FC1400A3127C12FEA2140115F84813036C14F0007F130F903880
+1FE0393FE07FC06CB512806C14006C5B000113F838007FC01E2F7CAD27>I<14FF010713
+C0011F13F04913F890B5FC48EB81FC3803FE0113F8EA07F0EA0FE09038C000F8001F1400
+485A90C8FCA25A127EEB0FF838FE3FFE48B51280B612C015E09038F80FF09038E007F890
+388001FC90C7FC15FE48147E157F153FA3127EA3127F6C147F157E6C6C13FE9038C001FC
+120F9038F007F83907F81FF06CB512E06C14C06C148090383FFE00EB0FF820307DAE27>
+I<1278B612FE15FFA315FE39FC0001FCEC03F8EC07F0007814E0C7120FEC1FC01580143F
+EC7F00147E14FE5C13015C13035C13075CA2495AA3495AA3133F91C7FCA55B137EA9133C
+20307DAE27>I<EB0FF0EB7FFE48B512804814C0000F14F0EBF81F391FE007F8393F8001
+FC90C7FC4814FE007E147EA56C14FCEB8001391FC003F8390FE007F03907FC3FE00001B5
+128039007FFE006D5A90B5FC000314C0390FF00FF0391FC003F8393F8001FC90C7FC007E
+147EA248143FA6007E147EA2007F14FE393F8001FC391FE007F8EBF81F6CB512F06C14E0
+0001148039007FFE00EB0FF020307DAE27>I<EB0FF0EB7FFC48B5FC4814804814C0390F
+F81FE0391FE007F0393FC003F8EB8001D87F0013FC007E130012FE48147EA4157FA37E12
+7E007F14FF7E6D5A381FE007380FF01F6CB6FC7E6C143F39007FFC7F90381FF07E90C7FC
+A215FCA2140115F8001F1303393F8007F0EC0FE0141FEC3FC09038C0FF806CB512005C6C
+13F8000313E0C6138020307DAE27>I<121EEA7F80A2EAFFC0A4EA7F80A2EA1E00C7FCAC
+121EEA7F80A2EAFFC0A4EA7F80A2EA1E000A20729F27>I<120FEA3FC0A2EA7FE0A4EA3F
+C0A2EA0F00C7FCAC120FEA3FC013E0EA7FF0A213F8A2123FA2120F120113F01203EA07E0
+121FEA7FC0EAFF8013005A12700D2A739F27>I<003FB512FCB7FCA4C9FCA8B7FCA4003F
+14FC20127D9F27>61 D<EB03F0497EA2497EA4143CEB1F3EA5EB3F3FA3EB3E1FA2017E7F
+A4496C7EA548486C7EA390B5FCA24880A3EBF003A248486C7EA4000F803A7FFC0FFF8000
+FF15C06D5A497E007F1580222F7EAE27>65 D<007FB5FCB612C08115F87E3907E003FCEC
+00FE157E157F81A6157EA25D1403EC0FF890B55A15C015F081819038E000FE157FED3F80
+151FA2ED0FC0A6151F1680153FED7F004A5A007FB55AB65A5D15E06C1480222E7FAD27>
+I<903803F80E90381FFE1F90383FFFBF90B6FC5A3803FE0F3807F803497E48487E485A49
+137FA248C7123FA25A127E151E150012FE5AAA7E127EA2151E007F143F7EA26C7E157F6D
+137E6C6C13FE3907F001FCEBF8033903FE0FF86CB512F06C14E0013F13C06D1300EB03F8
+20307DAE27>I<387FFFFC14FFB612C06C80813907E00FF81407EC01FC6E7EA2157E157F
+811680151FA316C0150FABED1F80A3153F1600A25D15FEA24A5A4A5A140F007FB55A5DB6
+5A6C91C7FC14FC222E7FAD27>I<007FB61280B712C0A37E3907E0000FA6ED078092C7FC
+A4EC07804A7EA390B5FCA5EBE00FA36E5A91C8FCA4ED03C0ED07E0A7007FB6FCB7FCA36C
+15C0232E7FAD27>I<007FB61280B712C0A37E3907E0000FA6ED078092C7FCA4EC07804A
+7EA390B5FCA5EBE00FA36E5A91C8FCAC387FFF80B57EA36C5B222E7EAD27>I<903807F0
+3890381FFC7C90387FFFFC90B5FC5A3803FC1F3807F00F380FE007EBC003001F13011380
+123F90C7FCA2127EA2157892C7FC5AA8EC1FFF4A1380A3007E6D1300EC00FCA36C1301A2
+1380121FEBC003120FEBE0073807F00F3803FC1F6CB5FC7EEB7FFE90381FFC78D907F0C7
+FC21307DAE27>I<3A7FFE07FFE0B54813F0A36C486C13E03A07E0007E00AF90B512FEA5
+9038E0007EB03A7FFE07FFE0B54813F0A36C486C13E0242E7FAD27>I<007FB512E0B612
+F0A36C14E039001F8000B3B2007FB512E0B612F0A36C14E01C2E7BAD27>I<90381FFFF8
+4913FCA36D13F89038001F80B3AC127CA212FEA2EC3F005C387F81FE13FF6C5B6C5B0007
+13E0C690C7FC1E2F7BAD27>I<387FFFC080B5FC7E5CD803F0C8FCB3AAED0780ED0FC0A7
+007FB6FCA2B7FC7E1680222E7FAD27>76 D<D87FE0EB7FE0486CEBFFF0A26D5A007F15E0
+000F150001B813DFEBBC03A3EBBE07019E139FA3EB9F0FA2018F131FA2149FA2EB879EA4
+EB839C14FCA3EB81F8A2EB80F01400AAD87FF0EBFFE0486C4813F0A36C486C13E0242E7F
+AD27>I<3A7FF003FFE0486C4813F0A213FC007F6D13E000079038003E0013DEA313CFA3
+148013C714C0A213C314E0A213C114F0A3EBC0F8A31478147CA2143C143EA2141E141F14
+0FA3EC07BEA3EC03FEEA7FFCEAFFFE1401A26C486C5A242E7FAD27>I<EBFFFC0007EBFF
+80001F14E0A24814F0EBC00F397F8007F8EB0003007E1301A348EB00FCB3A76C1301007E
+14F8A3007F1303EB8007393FE01FF090B5FC6C14E0A200071480C6EBFC001E307CAE27>
+I<007FB5FCB612E081816C803907E003FEEC00FF81ED3F80151F16C0150FA6151F168015
+3FED7F005DEC03FE90B55A5D5D5D92C7FC01E0C8FCADEA7FFEB5FCA36C5A222E7FAD27>
+I<EBFFFC0007EBFF80001F14E0A24814F0EBE01F397F8007F8EB0003007E1301A300FE14
+FC481300B3A4EB07E0A200FE13F1007E14F8EB03F9A2387F01FF1381D83FE013F090B5FC
+6C14E0A200071480C6FC9038001FC0A2EC0FE0A2EC07F0A2EC03F8A2EC01F01E397CAE27
+>I<387FFFF0B512FE6E7E816C803907E01FF014076E7E1401811400A514015D14034A5A
+141F90B55A5D5DA281EBE01F6E7E14076E7EA816F0EDF1F8A4397FFE01FBB5EBFFF08016
+E06C48EB7FC0C8EA1F00252F7FAD27>I<90387FC0E03901FFF1F0000713FF5A5AEA3FE0
+EB801F387F000F007E130712FE5A1403A3EC01E06C90C7FC127E127FEA3FC013F86CB47E
+6C13F86C13FE6CEBFF80C614C0010F13E0010013F0140FEC07F81403140115FC14001278
+12FCA46CEB01F8A26C130390388007F09038F01FE090B5FC15C0150000F85B38701FF81E
+307CAE27>I<007FB61280B712C0A439FC03F00FA60078EC0780000091C7FCB3AB90B512
+C04880A36C5C222E7EAD27>I<3A7FFE01FFF8B54813FCA36C486C13F83A07E0001F80B3
+AB6D133F00031500A26D5B0001147E6D13FE6C6C485A90387F87F814FF6D5B010F13C06D
+5BD901FEC7FC262F80AD27>I<3A7FFC03FFE06D5A00FF15F0007F15E0497E3A07E0007E
+00A46C6C5BA4EBF80100015CA46C6C485AA490387E07E0A56D485AA4011F5B149FA3010F
+90C7FCA5EB07FEA46D5AA26D5A242F7FAD27>I<D87FE0EB7FE0486CEBFFF0A36C48EB7F
+E0001FC7EA0F80A76C6CEB1F00A614F0EB81F83907C3FC3EA4149CEBC79EA30003143CA3
+01E7137CEBEF9FA2140FA200011478A49038FE07F8A300005CA2EBFC0390387801E0242F
+7FAD27>I<393FFC1FFE387FFE3F815D383FFC1F3903F00FE001F85B1201EBFC1F00005C
+EBFE3F017E90C7FCEB7F7FEB3F7E14FE6D5AA26D5AA26D5AA21303130780130F80131F80
+EB3F7E147F497E017E7F141F01FC7F140FD801F87F14071203496C7E120701E07F3A7FFC
+0FFF8000FF15C06D5A497E007F1580222E7EAD27>I<3A7FFC03FFE06D5A00FF15F0007F
+15E0497E3A07F000FE0000035CEBF80100015CA2EBFC0300005CEBFE07017E5BA26D485A
+A290381F9F80A3010F90C7FCA2EB07FEA26D5AA26D5AAF90381FFF80497FA36D5B242E7F
+AD27>I<003FB512FE4814FFA4007EC712FEEC01FCA2EC03F8EC07F0A2003CEB0FE0C7EA
+1FC0A2EC3F80EC7F00A214FE5C1301495A5C1307495A5C131F495A91C7FC5B13FEA2485A
+4848131E153F485A485AA2485A485AA248C7FCB7FCA46C14FE202E7DAD27>I<387FFFF0
+B512F8A314F000FCC7FCB3B3ACB512F014F8A36C13F0153A71B327>I<387FFFF0B512F8
+A37EEA0001B3B3ACEA7FFFB5FCA36C13F0153A7EB327>93 D<007FB512F8B612FCA46C14
+F81E067C7E27>95 D<3801FFE0000713F84813FE486D7E81EBC07FEC0FE0380F8007D802
+007FC71203A2EB07FF137F0003B5FC120F5A383FFC03EA7FE0130012FE5AA46C1307007F
+130FEBC07F6CB612C06C15E07E000313F83A007FC03FC023207D9F27>97
+D<EA7FE0487EA3127F1203A9EC7F809038F1FFE001F713F890B57E81ECC0FF9138007F80
+01FCEB1FC049130F16E0491307A216F01503A615076D14E0A2150F6DEB1FC06D133F6DEB
+7F809138C1FF00ECFFFE5D01F75B01F313E02601E07FC7FC242E80AD27>I<EB0FFF017F
+13C048B512E04814F05A380FF807EA1FE0393FC003E0903880008048C8FC127EA212FE5A
+A67E127EA2007F14F0393F8001F813C0381FE003390FF80FF06CB5FC6C14E06C14C06C6C
+1300EB0FF81D207B9F27>I<EC1FF84A7EA3141F1400A9EB0FF0EB7FFC48B5FC5A5A380F
+F81F381FE007383FC003EB8001EA7F00007E1300A212FE5AA67E007E1301A2007F13037E
+EB8007381FE00F380FF03F6CB612E06C15F06C5B38007FF890391FE07FE0242E7EAD27>
+I<EB0FF8EB3FFE90B51280000314C04814E0390FFC0FF0391FE003F8EBC001D83F8013FC
+48C7FC127E157E12FEB612FEA415FC00FCC8FC7E127E127F6C143C6D137E6C7E01F013FE
+390FFC07FC6CB5FC000114F86C14F0013F13C0903807FE001F207D9F27>I<EC1FF0ECFF
+F84913FC4913FE5BEB0FF014C0011F137CEC8000A6007FB512F0B612F8A36C14F039001F
+8000B3A4003FB512C04814E0A36C14C01F2E7EAD27>I<153F90391FC0FF80D97FF313C0
+48B612E05A4814EF390FF07F873A1FC01FC3C0EDC000EB800F48486C7EA66C6C485AEBC0
+1FA2390FF07F8090B5C7FC5C485BEB7FF0EB1FC090C9FCA27F6CB5FC15E015F84814FE48
+80EB8001007EC7EA3F80007C140F00FC15C0481407A46C140F007C1580007F143F6C6CEB
+7F009038F807FF6CB55A000714F86C5CC614C0D90FFCC7FC23337EA027>I<EA7FE0487E
+A3127F1203A9EC3FC09038F1FFF001F77F90B57E8114E0EC007F497F5B5BA25BB03A7FFF
+83FFF8B500C713FCA36C018313F8262E80AD27>I<130F497E497EA46D5A6DC7FC90C8FC
+A7383FFF80487FA37EEA000FB3A4007FB512F0B6FC15F815F07E1D2F7BAE27>I<143C14
+7E14FFA4147E143C1400A73801FFFE4813FFA37EC7123FB3B0147E1238007C13FE38FE01
+FC1303B512F814F06C13E06C13803807FE0018407CAE27>I<EA7FE07F12FF127FA21201
+A991383FFFC04A13E0A36E13C0913803F8004A5A4A5A4A5A4A5A02FFC7FCEBF1FEEBF3FC
+EBF7F8EBFFFC8080143F496C7E496C7E01F87FEBF0076E7E6E7E816E7E157E3A7FFFC1FF
+F002C313F8B512E36C13C316F0252E80AD27>I<387FFF80B57EA37EEA000FB3B2007FB5
+12F8B612FCA36C14F81E2E7CAD27>I<397F07C01F3AFF9FF07FC09039FFF9FFE091B57E
+7E3A0FFC7FF1F89038F03FC001E0138001C01300A3EB803EB03A7FF0FFC3FF486C01E313
+8001F913E701F813E36C4801C313002920819F27>I<397FE03FC039FFF1FFF001F77F90
+B57E6C80000313E0EC007F497F5B5BA25BB03A7FFF83FFF8B500C713FCA36C018313F826
+20809F27>I<EB1FE0EB7FF83801FFFE487F481480390FF03FC0391FC00FE0393F8007F0
+EB00034814F8007E1301A248EB00FCA76C1301007E14F8A2007F1303393F8007F0A2391F
+E01FE0390FF03FC06CB512806C14006C5B38007FF8EB1FE01E207C9F27>I<397FE07F80
+39FFF1FFE001F713F890B57E6C800003EBC0FF9138007F8001FCEB1FC049130F16E04913
+07A216F01503A615076D14E0A2150F6DEB1FC06D133F6DEB7F809138C1FF00ECFFFE5D01
+F75B01F313E0D9F07FC7FC91C8FCAC387FFF80B57EA36C5B2431809F27>I<90380FF03C
+90383FFE7E90B5FC000314FE5A380FFC1F381FE007EBC003383F800148C7FC127EA200FE
+147E5AA67E007E14FEA2007F1301EA3F80EBC003381FE007380FF81F6CB5FC7E6C147E38
+007FFCEB0FF090C7FCAC91381FFFF8A24A13FC6E13F8A226317E9F27>I<397FFC03FC39
+FFFE0FFF023F13804A13C0007F90B5FC39007FFE1F14F89138F00F809138E002004AC7FC
+5CA291C8FCA2137EAD007FB57EB67EA36C5C22207E9F27>I<9038FFF3800007EBFFC012
+1F5A5AEB803F38FC000F5AA2EC07806C90C7FCEA7F8013FC383FFFF06C13FC000713FF00
+011480D8000F13C09038003FE014070078EB03F000FC1301A27E14036CEB07E0EBE01F90
+B512C01580150000FB13FC38707FF01C207B9F27>I<133C137EA8007FB512F0B612F8A3
+6C14F0D8007EC7FCAE1518157EA415FE6D13FC1483ECFFF86D13F06D13E0010313C00100
+13001F297EA827>I<397FE007FE486C487EA3007F7F0003EB003FB25DA24A5AEBFC076C
+B612F86C15FCA2013F13BF90390FFC1FF82620809F27>I<3A7FFC0FFF80486C4813C0A3
+6C486C13803A07C000F800EBE00100035CA2EBF00300015CA2EBF80700005CA390387C0F
+80A36D48C7FCA3EB3F3FEB1F3EA214FE6D5AA36D5AA26D5A22207E9F27>I<3A7FFE07FF
+E000FF15F06D5A497E007F15E03A0F80001F00A36D5B0007143EA414F0EBC1F83903E3FC
+7CA4EBE79EA200011478A301F713F8A2EBFF0F6C5CA3EBFE0790387C03E024207F9F27>
+I<393FFC1FFF486C5A168016006C487E3901F807E06C6C485A4A5A017E90C7FC6D5AEB1F
+7E5C6D5A13076D5A5C80497E130F497E143EEB3E3FEB7E1F90387C0F8001F87F00016D7E
+3803F0033A7FFE1FFF80A2B54813C06C486C1380A222207E9F27>I<3A7FFC0FFF80486C
+4813C0A36C486C13803A07E000F800000313015D13F00001130301F85B1200A26D485A13
+7CA290387E0F80133EA2011F90C7FC5CA2130F149E14BE130714FC1303A25C1301A25CA2
+13035CA213075C1208EA3E0F007F5B131FD87E7FC8FCEA7FFE6C5A5B6C5AEA07C022317E
+9F27>I<001FB512FE4814FFA490380001FEEC03FCEC07F8EC0FF0001EEB1FE0C7EA3FC0
+EC7F80ECFF00495A495A495AEB1FE0495A495A49C7FC485A4848131E4848133F485A485A
+485A485AB7FCA46C14FE20207E9F27>I<EC07F8EC3FFC14FF130315F8903807FE00EB0F
+F05C5CB0131FEB7F80EA3FFFB5C7FC5BA27F003F7FEA007FEB1FC0130FB08080EB07FE90
+3803FFF815FC1300143FEC07F81E3A7CB327>I<EA7F80EAFFF013FC13FF7E00017F3800
+3FC0131F130FB080EB07F8ECFFF06D13FC7FA25B4913F0ECF800EB0FE05CB0131F133F48
+B45A007F90C7FCB5FC13FC13F0EA7F801E3A7CB327>125 D E
+%EndDVIPSBitmapFont
+%DVIPSBitmapFont: Fe ecbx1200 12 53
+/Fe 53 123 df<ED0FFF4AB512C0020F14F0027F80903A01FFF803FC499038C000FE010F
+EB00034948497E49485B5C495A4C138001FF6E13005CA3705AEE01F893C8FCA74BB51280
+B9FCA5C69038E00003B3B0007FD9FFC1B6FCA538467EC53E>28 D<EC01E01403EC0FC0EC
+1F80EC3F00147E5C1301495A495A5C130F495A133F5C137F49C7FCA2485AA2485AA21207
+5BA2120F5BA2121FA25B123FA4485AA612FFA25BAE7FA2127FA66C7EA4121F7FA2120FA2
+7F1207A27F1203A26C7EA26C7EA26D7E133F80131F6D7E1307806D7E6D7E1300147E80EC
+1F80EC0FC0EC03E014011B6476CA2C>40 D<12F07E127E7E6C7E6C7E6C7E7F6C7E6C7E12
+007F137F80133F806D7EA26D7EA26D7EA2801303A2801301A280A27F1580A4EC7FC0A615
+E0A2143FAE147FA215C0A6ECFF80A415005BA25CA213035CA213075CA2495AA2495AA249
+5A5C137F91C7FC13FE5B1201485A485A5B485A485A48C8FC127E12F85A1B647ACA2C>I<
+143E147F4A7EA56EC8FC00081508003E153E007F157FD8FFC0903801FF8001E05B9038F0
+3E0701F85BD87FFE013F130001FF5B001F9038BEFFFC000390B512E0C66C91C7FC010F13
+F8010113C0A2010F13F8017F13FF0003B612E0001F01BE13FC007F90383E7FFF01FE7FD8
+FFF8010F138001F07F9038E07F0301C07FD87F009038007F00003E153E00081508C791C7
+FC4A7EA56EC8FC143E292C79CA38>I<EA07C0EA1FF0EA3FF8EA7FFCEAFFFEA7EA7FFCEA
+3FF8EA1FF0EA07C00F0F788E1F>46 D<EC03C01407141F147FEB03FF133FB6FCA413C3EA
+0003B3B3ADB712FCA5264177C038>49 D<ECFFE0010F13FE013F6D7E90B612E0000315F8
+2607FC0313FE3A0FE0007FFFD81F806D138048C7000F13C0488001C015E001F07F00FF6E
+13F07F17F881A46C5A6C5A6C5AC9FC17F05DA217E05D17C04B13804B1300A2ED1FFC4B5A
+5E4B5A4B5A4A90C7FC4A5A4A5AEC0FF04A5AEC3F804AC7127814FE495A494814F8D907E0
+14F0495A495A49C8FC017C140149140348B7FC4816E05A5A5A5A5AB8FC17C0A42D417BC0
+38>I<ECFFF0010713FF011F14C0017F14F049C66C7ED803F8EB3FFED807E06D7E81D80F
+F86D138013FE001F16C07FA66C5A6C4815806C485BC814005D5E4B5A4B5A4B5A4A5B020F
+1380902607FFFEC7FC15F815FF16C090C713F0ED3FFCED0FFEEEFF80816F13C017E0A26F
+13F0A217F8A3EA0FC0EA3FF0487EA2487EA217F0A25D17E06C5A494913C05BD83F804913
+80D81FF0491300D80FFEEBFFFE6CB612F800015D6C6C14C0011F49C7FC010113E02D427B
+C038>I<163FA25E5E5D5DA25D5D5D5DA25D92B5FCEC01F7EC03E7140715C7EC0F87EC1F
+07143E147E147C14F8EB01F0EB03E0130714C0EB0F80EB1F00133E5BA25B485A485A485A
+120F5B48C7FC123E5A12FCB91280A5C8000F90C7FCAC027FB61280A531417DC038>I<00
+07150301E0143F01FFEB07FF91B6FC5E5E5E5E5E16804BC7FC5D15E092C8FC01C0C9FCAA
+EC3FF001C1B5FC01C714C001DF14F09039FFE03FFC9138000FFE01FC6D7E01F06D138049
+15C0497F6C4815E0C8FC6F13F0A317F8A4EA0F80EA3FE0487E12FF7FA317F05B5D6C4815
+E05B007EC74813C0123E003F4A1380D81FC0491300D80FF0495AD807FEEBFFFC6CB612F0
+C65D013F1480010F01FCC7FC010113C02D427BC038>I<4AB47E021F13F0027F13FC49B6
+FC01079038807F8090390FFC001FD93FF014C04948137F4948EBFFE048495A5A1400485A
+120FA248486D13C0EE7F80EE1E00003F92C7FCA25B127FA2EC07FC91381FFF8000FF017F
+13E091B512F89039F9F01FFC9039FBC007FE9039FF8003FF17804A6C13C05B6F13E0A249
+15F0A317F85BA4127FA5123FA217F07F121FA2000F4A13E0A26C6C15C06D4913806C0180
+14006C6D485A6C9038E01FFC6DB55A011F5C010714C0010191C7FC9038003FF02D427BC0
+38>I<121E121F13FC90B712FEA45A17FC17F817F017E017C0A2481680007EC8EA3F0000
+7C157E5E00785D15014B5A00F84A5A484A5A5E151FC848C7FC157E5DA24A5A14035D1407
+4A5AA2141F5D143FA2147F5D14FFA25BA35B92C8FCA35BA55BAA6D5A6D5A6D5A2F447AC2
+38>I<EC7FF00103B5FC010F14C0013F14F090397F801FFC3A01FC0003FE48486D7E497F
+4848EC7F80163F484815C0A2001F151FA27FA27F7F01FE143F6D158002C0137F02F01400
+6C01FC5B6E485A6C9038FF83FCEDE7F86CECFFE06C5D6C92C7FC6D14C06D80010F14F882
+013F8090B7FC48013F14802607FC0F14C0260FF80314E04848C6FC496D13F0003F141F48
+481307496D13F8150000FF157F90C8123F161F160FA21607A36D15F0127F160F6D15E06C
+6C141F6DEC3FC06C6CEC7F80D80FFE903801FF003A07FFC00FFE6C90B55AC615F0013F14
+C0010F91C7FC010013F02D427BC038>I<EC7FF0903807FFFE011F6D7E017F14E09039FF
+E03FF0489038800FF848496C7E48488048486D7E001F80003F1680A2484815C08117E0A2
+12FF17F0A617F8A45D127FA3003F5CA26C7E5D6C6C5B12076C6C131E6CEBC07C6CEBFFF8
+013F5B010F01C013F00101130090C8FCA217E05DA2EA03C0D80FF015C0487E486C491380
+A217004B5A150F5E49495A6C48495A01C0EBFFE0260FF0035B6CB65A6C4AC7FC6C14F86C
+6C13E0D907FEC8FC2D427BC038>I<EE1F80A24C7EA24C7EA34C7EA24B7FA34B7FA24B7F
+A34B7F169F031F80161F82033F80ED3E07037E80157C8203FC804B7E02018115F0820203
+814B137F0207815D173F020F814B7F021F8292C77EA24A82023E80027E82027FB7FCA291
+B87EA2498302F0C8FCA20103834A157F0107834A153FA249488284011F8491C97E498413
+3E017E82B6020FB612F0A54C457CC455>65 D<B9FC18F018FE727E19E026003FFCC70007
+7F05017F716C7E727E727EA2721380A37213C0A74E1380A24E1300A24E5A4E5A4E5A4D5B
+05075B94B5128091B700FCC7FC18F018FF19E002FCC7000113F8716C7EF01FFE727E7213
+801AC07213E0A27213F0A31AF8A71AF0A2601AE0604E13C0604E138095B5120005075BBA
+12F86119C04EC7FC18E045447CC350>I<DCFFF01470031F01FF14F04AB6EAE0010207ED
+F803023FEDFE0791B539E001FF0F4949C7EA3F9F010701F0EC0FFF4901C0804990C87E49
+48814948814948167F4849163F4849161F5A4A160F485B19074890CAFC19035A5BA2007F
+1801A34994C7FC12FFAE127F7F1AF0A2123FA27F6C18011AE06C7F19036C6D17C06E1607
+7E6C6DEE0F806C6DEE1F006D6C5E6D6C167E6D6C6C5D6D6D4A5A6D01F0EC07F0010101FE
+EC1FE06D903AFFF001FF80023F90B6C7FC020715FC020115F0DA001F1480030001F8C8FC
+44467AC451>I<B9FC18F018FE727E19E026003FFEC7001F13F805017F9438003FFF060F
+7F727F727F727F84737E737EA2737EA2737EA21B80A2851BC0A51BE0AD1BC0A51B8061A2
+1B006162193F624F5A19FF624E5B06075B4E5B063F90C7FC4DB45A050F13F8BA5A19C04E
+C8FC18F095C9FC4B447CC356>I<BA12F8A485D8001F90C71201EF003F180F1803180118
+00A2197E193EA3191EA21778A285A405F890C7FCA316011603161F92B5FCA5ED001F1603
+16011600A2F101E01778A2F103C0A494C7FC1907A21A80A2190FA2191FA2193FF17F0061
+601807181F4DB5FCBBFC61A443447DC34A>I<B712E0A5D8001F90C7FCB3B3B3A4B712E0
+A523447DC32A>73 D<B712F0A526003FFECAFCB3B1F00780A4180F1900A460A360A2187E
+A218FE170117031707171F177FEE03FFB95AA539447CC343>76 D<B500FE067FB512806E
+95B6FCA26F5EA2D8003F50C7FC013D6DEE03DFA2013C6DEE079FA26E6CEE0F1FA26E6C16
+1EA26E6C163CA36E6C1678A26E6C16F0A26E6DEC01E0A26E6DEC03C0A36E6DEC0780A26F
+6CEC0F00A26F6C141EA26F6C5CA36F6C5CA26F6C5CA26F6D485AA26F6D485AA26F6D485A
+A3706C48C7FCA293383FF81EA2706C5AA2706C5AA3706C5AA2705BA2705BA2705BA2B605
+7FB6128071C7FCA2173E171C61447CC36A>I<923807FFC092B512FE0207ECFFC0021F15
+F091267FFE0013FC902601FFF0EB1FFF01070180010313C04990C76C7FD91FFC6E6C7E49
+486F7E49486F7E01FF8348496F7E48496F1380A248496F13C0A24890C96C13E0A24819F0
+4982003F19F8A3007F19FC49177FA400FF19FEAD007F19FC6D17FFA3003F19F8A26D5E6C
+19F0A26E5D6C19E0A26C6D4B13C06C19806E5D6C6D4B13006C6D4B5A6D6C4B5A6D6C4B5A
+6D6C4A5B6D01C001075B6D01F0011F5B010101FE90B5C7FC6D90B65A023F15F8020715C0
+02004AC8FC030713C047467AC454>79 D<B9FC18F018FE727E19E0D8001F90C7000F7F05
+017F716C7E727E727E721380A21AC084A21AE0A91AC0A24E1380A21A00604E5A4E5A4D48
+5A050F5B92B712C096C7FC18FC18C092CBFCB3A7B712E0A543447DC34D>I<DAFFE0131C
+010701FE133C013F9038FF807C90B6EAE0FC4815F9489038801FFF3907FC00014848EB00
+7F4848143F4848140F491407007F15035B1601160012FF177CA27FA26D153C7F7F6D92C7
+FC6C7EEBFFE014FE6CEBFFF015FF6C15E016FC6C816C6F7E6C826C826C6C81011F810107
+811300020F80140003077FED007F82040F1380828212F082A282A27EA218007EA26C5D6C
+5E6D14036D5D6D140701F84A5A01FFEC3FF002F8EBFFE0486CB65AD8FC1F92C7FCD8F807
+14FC48C614F0480107138031467AC43E>83 D<003FBA12E0A59026FE000FEB8003D87FE0
+9338003FF049171F90C71607A2007E1803007C1801A300781800A400F819F8481978A5C8
+1700B3B3A20107B8FCA545437CC24E>I<B76C010FB512F8A526003FFEC93803E000B3B3
+A9011F17076280190F6D606F151F6D95C7FC6D6D5D197E6D6D5D6D6D1403DA7FFC4A5A6E
+B4EC3FF0020F9039F003FFE06E90B61280020193C8FC6E6C14FC030F14E09226007FFEC9
+FC4D457CC356>I<007FBA12E0BB12F0A46C19E04406776757>95
+D<903801FFE0011F13FE017F6D7E48B612E03A03FE007FF84848EB1FFC6D6D7E486C6D7E
+A26F7FA36F7F6C5A6C5AEA00F090C7FCA40203B5FC91B6FC1307013F13F19038FFFC0100
+0313E0481380381FFE00485A5B127F5B12FF5BA35DA26D5B6C6C5B4B13F0D83FFE013EEB
+FFC03A1FFF80FC7F0007EBFFF86CECE01FC66CEB8007D90FFCC9FC322F7DAD36>97
+D<EB7FC0B5FCA512037EB1ED0FF892B57E02C314E002CF14F89139DFC03FFC9139FF000F
+FE02FCEB03FF4A6D13804A15C04A6D13E05CEF7FF0A218F8173FA318FCAC18F8A2177F18
+F0A3EFFFE06E15C06E5B6E491380027C491300496C495A903AFC1FC07FFC496CB512F0D9
+F00314C049C691C7FCC8EA1FF036467DC43E>I<EC3FFC49B512C0010F14F0013F14FC90
+397FF003FE9039FFC001FF0003495A48494813805B120F485AA2485A6F1300007F6E5AED
+00784991C7FCA212FFAC6C7EA3123F6DEC03C0A26C6C1407000F16806D140F6C6DEB1F00
+6C6D133E6C01F05B3A007FFC03F86DB55A010F14C0010391C7FC9038003FF82A2F7CAD32
+>I<EE03FEED07FFA5ED001F160FB1EC3FE0903803FFFC010FEBFF8F013F14CF9039FFF8
+07FF48EBC00148903880007F4890C7123F4848141F49140F121F485AA3127F5BA212FFAC
+127FA37F123FA26C6C141FA26C6C143F0007157F6C6C91B5FC6CD9C00314FC6C9038F01F
+EF6DB5128F011FEBFE0F010713F89026007FC0EBF80036467CC43E>I<EC3FF80103B57E
+010F14E0013F8090397FF83FF89039FFC007FC48496C7E48496C7E48486D1380485A001F
+ED7FC05B003FED3FE0A2127F5B17F0161F12FFA290B7FCA401F0C9FCA5127FA27FA2123F
+17F06C7E16016C6C15E06C6C14036C6DEB07C06C6DEB0F806C01F0EB3F0090397FFE01FE
+011FB55A010714F0010114C09026001FFEC7FC2C2F7DAD33>I<EDFF80020F13E0027F13
+F049B512F849EB8FFC90390FFE0FFE90381FFC1F14F8133FEB7FF0A2ED0FFCEBFFE0ED03
+F0ED00C01600ABB612F8A5C601E0C7FCB3B0007FEBFFE0A527467DC522>I<DAFFE0137E
+010F9039FE03FF80013FEBFF8F90B812C048D9C07F133F489038001FF84848EB0FFC4848
+903907FE1F80001F9238FF0F00496D90C7FCA2003F82A8001F93C7FCA26D5B000F5D6C6C
+495A6C6C495A6C9038C07FF04890B55A1680D8078F49C8FC018013E0000F90CAFCA47F7F
+7F90B612C016FC6CEDFF8017E06C826C16FC7E000382000F82D81FF0C77ED83FC0140748
+48020113808248C9FC177FA46D15FF007F17006D5C6C6C4A5A6C6C4A5AD80FFEEC3FF83B
+07FFC001FFF0000190B612C06C6C92C7FC010F14F8D9007F90C8FC32427DAC38>I<EB7F
+C0B5FCA512037EB1ED07FE92383FFF8092B512E002C114F89139C7F03FFC9138CF801F91
+39DF000FFE14DE14FC4A6D7E5CA25CA35CB3A7B60083B512FEA537457CC43E>I<137C48
+B4FC4813804813C0A24813E0A56C13C0A26C13806C1300EA007C90C7FCAAEB7FC0EA7FFF
+A512037EB3AFB6FCA518467CC520>I<EB7FC0B5FCA512037EB293387FFFE0A593380FE0
+004C5A4CC7FC167E5EED03F8ED07E04B5A4B5A037FC8FC15FEECC1FCECC3FE14C7ECDFFF
+91B57E82A202F97F02E17F02C07FEC807F6F7E826F7E816F7F836F7F816F7F83707E163F
+B60003B512F8A535457DC43B>107 D<EB7FC0B5FCA512037EB3B3B3A3B61280A519457C
+C420>I<90277F8007FEEC0FFCB590263FFFC090387FFF8092B5D8F001B512E002816E48
+80913D87F01FFC0FE03FF8913D8FC00FFE1F801FFC0003D99F009026FF3E007F6C019E6D
+013C130F02BC5D02F86D496D7EA24A5D4A5DA34A5DB3A7B60081B60003B512FEA5572D7C
+AC5E>I<90397F8007FEB590383FFF8092B512E0028114F8913987F03FFC91388F801F00
+0390399F000FFE6C139E14BC02F86D7E5CA25CA35CB3A7B60083B512FEA5372D7CAC3E>
+I<EC1FFC49B512C0010714F0011F14FC90397FF80FFF9026FFC0017F48496C7F4848C7EA
+3FE000078248486E7E49140F001F82A2003F82491407007F82A400FF1780AA007F1700A4
+6C6C4A5AA2001F5E6D141F000F5E6C6C4A5AA26C6C6CEBFFE06C6D485B27007FF80F90C7
+FC6DB55A010F14F8010114C09026001FFCC8FC312F7DAD38>I<90397FC00FF8B590B57E
+02C314E002CF14F89139DFC03FFC9139FF001FFE000301FCEB07FF6C496D13804A15C04A
+6D13E05C7013F0A2EF7FF8A4EF3FFCACEF7FF8A318F017FFA24C13E06E15C06E5B6E4913
+806E4913006E495A9139DFC07FFC02CFB512F002C314C002C091C7FCED1FF092C9FCADB6
+7EA536407DAC3E>I<DA3FE0131E902603FFFC133E010F01FF137E013F1480903AFFF80F
+E0FE489038E003F148EBC0014890388000FB4890C7127F49143F001F151F485A160F5B12
+7FA3485AAC6C7EA46C7EA26C6C141F163F6C6C147F6C15FF6C6D5A6C9038E003EF6C9038
+F01FCF6DB5128F011FEBFE0F010313F89038007FC091C7FCAD0307B512FCA536407CAC3B
+>I<90387F807FB53881FFE0028313F0028F13F8ED8FFC91389F1FFE000313BE6C13BC14
+F8A214F0ED0FFC9138E007F8ED01E092C7FCA35CB3A5B612E0A5272D7DAC2E>I<90391F
+FC038090B51287000314FF120F381FF003383FC00049133F48C7121F127E00FE140FA215
+077EA27F01E090C7FC13FE387FFFF014FF6C14C015F06C14FC6C800003806C15806C7E01
+0F14C0EB003F020313E0140000F0143FA26C141F150FA27EA26C15C06C141FA26DEB3F80
+01E0EB7F009038F803FE90B55A00FC5CD8F03F13E026E007FEC7FC232F7CAD2C>I<EB01
+E0A51303A41307A2130FA2131FA2133F137F13FF1203000F90B51280B7FCA4C601E0C7FC
+B3A3ED01E0A9150302F013C0137F150790393FF80F8090391FFC1F006DB5FC6D13FC0101
+5B9038003FE023407EBE2C>I<D97FC049B4FCB50103B5FCA50003EC000F6C81B3A85EA2
+5EA25E7E6E491380017FD901F713FE9138F807E76DB512C7010F1407010313FE9026007F
+F0EBFC00372E7CAC3E>I<B6903803FFFCA5000101E09038003E006C163C80017F5D8017
+F8013F5D6E1301011F5D6E1303010F5D6E13076D5DED800F6D92C7FC15C05E6DEBE01E16
+3E6D143CEDF07C027F1378EDF8F8023F5B15FD021F5B15FF6E5BA36E5BA26E90C8FCA26E
+5AA26E5AA21578362C7EAB3B>I<B5D8FE1FB539801FFFF0A500019027C0003FE0C7EA7C
+007114786E17F86C6F6C5C6E1601017F6E6C5CA26E011F1403013F6F5C6E013F1407011F
+6F5CA26E0179140F010F048090C7FC6E01F95C6D02F0EBC01E15806D902681E07F5B18E0
+03C3157C6D9139C03FF07815E76DDA801F5B18F803FF14F96E9039000FFDE018FF6E486D
+5BA36E486D5BA26E486D90C8FCA24B7F02075DA26E48147C4B143C4C2C7EAB51>I<B500
+FE90383FFFF0A5C601F0903803E0006D6C495A6D6C495A011F4AC7FC6E5B6D6C137E6DEB
+807C6D6D5A6DEBC1F0EDE3E06DEBF7C06EB45A806E90C8FC5D6E7E6E7F6E7FA24A7F4A7F
+8291381F3FFCEC3E1F027C7F4A6C7E49486C7F01036D7F49487E02C08049486C7F49C76C
+7E013E6E7E017E141FB500E090B512FCA5362C7EAB3B>I<B6903803FFFCA5000101E090
+38003E006C163C80017F5D8017F8013F5D6E1301011F5D6E1303010F5D6E13076D5DED80
+0F6D92C7FC15C05E6DEBE01E163E6D143CEDF07C027F1378EDF8F8023F5B15FD021F5B15
+FF6E5BA36E5BA26E90C8FCA26E5AA26E5AA21578A215F85D14015D001F1303D83F805B38
+7FC007D8FFE05B140F92C9FC5C143E495A387FC1F8EB07F06CB45A6C5B000790CAFCEA01
+FC36407EAB3B>I<001FB71280A49026FC001F130001E0495A5B49495A90C7485A48495B
+123E4A5B4A5B003C495BA24A90C7FC4A5A4A5AC7FC4A5A495B495BA2495B499038800780
+491300A2495A4948130F49481400A2485B48495B485BA248495B4890C75A48485C150348
+48EB1FFEB7FCA4292C7DAB32>I E
+%EndDVIPSBitmapFont
+%DVIPSBitmapFont: Ff ecbx1000 10 64
+/Ff 64 123 df<913803FFC0027F13F00103B512FC010FEB00FED93FF8133FD97FE0EBFF
+8049485A5A1480484A13C04A6C1380A36F1300167E93C7FCA592383FFFC0B8FCA4000390
+C7FCB3ABB5D8FC3F13FFA4303A7EB935>28 D<EA0F80EA3FE0EA7FF0A2EAFFF8A213FCA3
+127FA2123FEA0F9CEA001C133C1338A31378137013F0EA01E0A2EA03C0EA0780EA0F005A
+121C12180E1D798C1B>44 D<EA0F80EA3FE0EA7FF0A2EAFFF8A5EA7FF0A2EA3FE0EA0F80
+0D0D798C1B>46 D<49B4FC011F13F0017F13FC9038FF83FE4848C67E4848EB7F804848EB
+3FC04848EB1FE0A2001F15F0A24848EB0FF8A3007F15FCA400FF15FEB3007F15FCA5003F
+15F86D131FA2001F15F0A26C6CEB3FE0000715C06C6CEB7F806C6CEBFF003900FF83FE6D
+B45A011F13F0010190C7FC27377CB530>48 D<141E143E14FE1307137FB5FCA3138FEA00
+0FB3B3A5007FB61280A4213679B530>I<EB0FFE90387FFFC048B512F0000714FC390FE0
+3FFF261F800F1380263F000313C0D87F8014E0EBE00100FF6D13F07FA2ED7FF8A46C5A6C
+5A0006C7FCC8FCEDFFF0A216E05C16C04A138016004A5A4A5AEC1FF05D4A5A4AC7FC14FE
+495AD903F01378495A495A495A49C712F8017C14F05B49130148B6FC5A5A5A5A5A4815E0
+B7FCA425367BB530>I<EB03FF011F13F0017F13FC3901FC07FF2603F003138048486C13
+C0496C13E0EA0FF86D14F0487EA66C4814E06C5A6C485AC714C04A138016004A5A4A5AEC
+3FF090380FFFC05D15F090380007FE913801FF806E13C016E0ED7FF016F8ED3FFCA216FE
+EA1FC0487E487E487EA416FCA249137F007F15F801C0EBFFF06C5A6C6C4813E0260FFC07
+13806CB61200000114FC6C6C13F0010790C7FC27377CB530>I<ED07C0150FA2151F153F
+157F15FF5CA25C5C5C5C143E143C5C5C1301495A5C495A495A5B133E5B13785B485A1203
+485A5B48C7FC121E5A127C5AB81280A4C70001EBC000AA0103B61280A429367DB530>I<
+001C15C0D81F80130701F8137F90B61280A216005D5D15F05D15804AC7FC14F090C9FCA7
+EB03FE90381FFFE0017F13F89038FE07FC9038F003FFD9C0011380496C13C090C7FC000E
+15E0C8127F16F0A216F8A3121FEA3FC0487E12FF7FA316F05B15FFD87F8014E0007EC713
+C0003E5B003F4913806C6C481300390FF01FFE6CB512F8000114E06C6C1380D90FF8C7FC
+25377BB530>I<EC0FF8ECFFFE0103EBFF8090390FF80FC090393FE003E090397F8001F0
+9038FF000F48EC1FF84848133F485A120F5B121FA2003FEC1FF0ED0FE0484890C7FCA314
+08EC7FF039FFF1FFFC01F313FFD9F78013809039FF007FC049EB3FE04914F0ED1FF85B16
+FCA34914FEA4127FA5123F16FCA26C7E16F8000F143F6D14F0000715E06C6CEB7FC03A01
+FF81FF806C90B51200013F13FC010F13F00101138027377CB530>I<123C123EEA3FE090
+B71280A41700485D5E5E5E5EA2007CC7EA0FC000784A5A4BC7FC00F8147E485C5D14014A
+5AC7485A4A5AA24A5A143F4AC8FCA214FEA213015C1303A21307A2130F5CA2131FA5133F
+A96D5A6D5A6D5A29397BB730>I<49B47E010F13F0013F13FC9038FE01FF3A01F8007F80
+4848EB3FC04848EB1FE0150F484814F01507121FA27F7F7F6D130F01FF14E014C09138E0
+1FC06CEBF83F9138FE7F806C9038FFFE005D6C14F06C14FC6C14FF6D14806D14C090B612
+E0D803FD14F02607F07F13F848487E261FC00F13FC383F8003007F010013FE90C7127F15
+1F00FE140715031501A21500A216FC7E6C14016D14F86C6C13036DEB07F06C6CEB0FE0D8
+0FFEEB7FC00003B61200C614FC013F13F00103138027377CB530>I<EB03FF011F13E001
+7F13F83901FF01FE48486C7E4848EB7F80484814C0001FEC3FE0485AED1FF0127F16F8A2
+12FF16FCA416FEA5007F143FA3123F157F6C7E000F14FF6C6C5A3903FE03DF6CB5129F6C
+6C131FD91FFC13FCEB00201400A3D80FE0EB3FF8487E486C14F0A216E0157F16C0EDFF80
+495A6C4848130090388007FE390FE01FF86CB55A6C14C0C691C7FCEB1FF027377CB530>
+I<ED03E04B7EA24B7EA34B7EA24B7EA34B7EA292B57EA34A8015F302038015E1A2020780
+15C0020F80ED807FA2021F80ED003F4A80023E131FA2027E80027C7F02FC814A7FA20101
+824A7F49B77EA3498202C0C7FC010F824A147FA2011F8291C8123F4982013E151FA2017E
+82017C8101FE83B500F80107B61280A4413A7DB948>65 D<B812C017FC17FF18C028007F
+F000037F04007F717E717E171F84A2717EA74D5AA260173F4D5A4D5A4C13C0040F5B91B6
+00FCC7FCA2EFFF8002F0C713F0EF3FF8717E717E717E19807113C0A319E0A719C0A25F4D
+138019005FEF7FFE4C485AB912F018C095C7FC17F03B397DB844>I<DB3FFCEB01C00203
+B5EAC003021FECF00791B6EAFC0F01039039FC00FF3F4901C0EB1FFFD91FFEC77E494814
+03D97FF080494880485B48177F4849153F4890C9FC181F485A180F123F5B1807127FA249
+93C7FC12FFAD127F7FF003C0123FA27F001F1707A26C6C1780180F6C6D16006C6D5D6C17
+3E6C6D157ED97FF85D6D6C4A5A6DB44A5A010701C0EB0FE06D01FCEBFF80010090B548C7
+FC021F14F8020314E09126003FFEC8FC3A3B7BB945>I<B87E17F817FF18C028007FF800
+0713F09338007FF8EF1FFE717E050313807113C0A27113E0F07FF0A2F03FF8A219FC181F
+A219FEA419FFAC19FEA419FC183FA219F8187F19F0F0FFE0A24D13C04D13804D1300EF1F
+FEEF7FFC933807FFF0B912C095C7FC17FC178040397DB849>I<B912F0A426007FF8C7FC
+EF1FF8170717031701A21700A21878A3043C137C183CA41800167CA216FC150391B5FCA4
+ECF8031500167CA2163C180FA3181EA293C7FCA2183EA2183C187CA218FCA2EF01F81703
+170F173FEE01FFB9FC18F0A338397DB83F>I<B912C0A43A007FF800039338007FE0171F
+170F1707A21703A21701A318F0EE7800A41800A216F8A21501150791B5FCA4ECF8071501
+1500A21678A693C8FCADB7FCA434397DB83C>I<DB3FFCEB01C00203B5EAC003021FECF0
+0791B6EAFC0F01039039FC00FF3F4901C0EB1FFFD91FFEC77E49481403D97FF080494880
+485B48177F4849153F4890C9FC181F485A180F123F5B1807127FA24993C8FC12FFAB043F
+B61280A2127F7FDC0003EBC000123FA27F121FA26C7EA26C7F6C7F6C7F7ED97FF85C6D7E
+6DB45C010701C05B6D01FCEBFF3F010090B5EAFE0F021FECF8030203ECE0009126003FFE
+C9FC413B7BB94B>I<B6D8FC03B612F0A426007FF8C70001EBE000B3A391B8FCA402F8C7
+1201B3A6B6D8FC03B612F0A444397DB84B>I<B612FCA439007FF800B3B3ADB612FCA41E
+397DB824>I<010FB612C0A4D90001EBE000B3B3EA0F80EA3FE0EA7FF0A2EAFFF8A35E5C
+13F0007F495BD83FE091C7FC391F800FFE390FF03FFC6CB512F0000114C026003FFCC8FC
+2A3A7FB831>I<B600FC0103B512C0A426007FF8C8381FE00019804EC7FC18FEEF01F84D
+5A4D5A4D5AEF3F80057EC8FC5F4C5A4C5AEE0FE0EE1F804CC9FC167E5EED03F84B7E4B7E
+4B7E4B7F5D02F9B57EDAFBF77FDAFFE37F15C103807F4A487F4A6D7E4A133F707E707F84
+82707F707F8482717E717E8483717F717F858385B600FC017FEBFFE0A443397DB84B>I<
+B7FCA426007FF8C9FCB3ACEF0780A5170F1800A35FA25FA25F5F5E5EEE0FFE167FB8FCA4
+31397DB839>I<B500F80403B512F06E5EA26E5ED8007FF1E000A2D97BFF161EA201796D
+5DA201786D5DA26E6C5DA36E6C4A5AA26E6C4A5AA26E6C4A5AA26E6C4A5AA26E6C141EA3
+6E6D5BA26E6D5BA26F6C5BA26F6C485AA36F6C485AA26F6C485AA26F6C48C7FCA2923803
+FF1EA36F13BCA26F13F8A2705AA2705AA213FCB500FC6D4848B612F0A2EE0F80EE070054
+397DB85B>I<B500FC0203B512F0A28080C66C6D90390003F0006F6E5A81017B7F137981
+01787F6E7E6E7E6E7F6E7FA26E7F6E7F6E7F6E7F6F7E153F826F13806F13C06F13E06F13
+F06F13F88117FCEE7FFEEE3FFF7013817013C17013E18218F17013F97013FDEF7FFF8383
+A28383838383187FA2183F181F01FC160FB500FC150718031801A244397DB84B>I<EDFF
+F8020FEBFF80027F14F0903A01FFC01FFC010790380007FFD91FFC010113C0D93FF06D6C
+7E49486E7E49486E7E48496E7E48834890C86C7EA248486F1380A248486F13C0A2003F18
+E0A348486F13F0A400FF18F8AC007F18F06D5DA3003F18E0A26D5D001F18C0A26C6C4B13
+806C18006E5C6C6D4A5A6C5F6C6D4A5A6D6C4A5AD93FFC49485A6DB401075B0107D9C01F
+90C7FC010190B512FC6D6C14F0020F1480020001F8C8FC3D3B7BB948>I<B8FC17F017FE
+EFFF8028007FF8000F13C0040113E07013F0EF7FF8EF3FFCA2EF1FFEA218FFA818FEA2EF
+3FFCA2EF7FF8EFFFF04C13E0040F13C091B7120017FC17E002F8C9FCB3A4B612FCA43839
+7DB841>I<EDFFF8020FEBFF80027F14F0903A01FFE03FFC010790380007FFD91FFC0101
+13C049486D7FD97FE0EC3FF049486E7E488348496E7E4890C86C7EA248486F1380A2001F
+18C04981003F18E0A3007F18F04981A300FF18F8AC007F18F0A36D5D003F18E0A36C6C4B
+13C0A2000FDA1FC014806C6C90267FF0071300EDFFF86C903A81F07C0FFE6C903AC3C01E
+1FFC6CDA800F5BD97FE3ECBFF0D93FF36DB45AD91FFF5D010701C091C7FC01019038F01F
+FC6D6CB500F01308020F6E131C0200EBF9FC92260001FE133C9438FF80FC18FF8219F8A2
+8319F0A27113E0A27113C0711380711300EF01FC3E4A7BB948>I<B712FCEEFFE017FC17
+FF28007FF8000F13C004017F707F717E717EA2717EA284A760A24D5A604D5A4D5A04035B
+041F90C8FC91B612FC17E0839139F8003FFCEE0FFF707F707F8284A2707FA584A51A601A
+F084177F1901DD3FFE13E0B600FC011F130394390FFF87C071EBFF8005011400CBEA1FFC
+443A7DB848>I<D907FF130E013FEBE01E90B5EAF83E0003ECFE7E3A07FC01FFFE390FF0
+001F4848130F48481303491301007F140090C8FC167E5A163EA27F161E7F7F6D91C7FC13
+FC387FFFE014FEECFFF06C14FE6F7E6C816C15F06C816C81C681133F010F801301D9000F
+1480EC007F030F13C01503818100F0157FA3163FA27E17807E167F6C16007E6D14FE01E0
+495A01F813039039FF801FF800FC90B512E0D8F83F5CD8F00749C7FC39E0007FF02A3B7B
+B935>I<003FB91280A4D9F800EBF003D87FC09238007FC049161F007EC7150FA2007C17
+07A200781703A400F818E0481701A4C892C7FCB3AE010FB7FCA43B387DB742>I<B600FC
+011FB512C0A426007FF8C8381FC000725AB3B3181F013F94C7FC8060011F163E6D6C157E
+187C6D6C15FC6D6D495A6D6DEB07F06D01F0EB1FE0DA7FFEEBFFC0021FB6C8FC02075C02
+0014F0030F1380423A7DB849>I<B600F00103B512E0A4C601F0C83807F0006E5E017F5F
+6E150FA2013F5F6E151F011F94C7FC6E5D6D163E6F147E6D167CA26F14FC6D5E6F13016D
+5E6F13036D5E811707027F5D6F130F023F5D6F131F021F92C8FC815F6E143EEE807E6E14
+7CEEC0FC6E5C16E016E16E5C16F36E5C16FF6F5BA36F5BA26F90C9FCA26F5AA36F5AA26F
+5AA26F5A433A7EB848>I<B6D8E01FB500FC90383FFFFCA4000101F0C7D83FFCC8EA7E00
+6C71153C171F6E197C017F701578836E7014F8013F6F5E6E1801011F4B6D5CA26E18036D
+4B6D5CA26D6D496D495A173C6F170F6D037C6D91C7FCEF787F6F5F6D4B6C6C131E816D02
+016E5BEFE01F03F8177C027F01036E13784D7E03FCEE80F8023F49486C5C15FE021F010F
+EDC1E04D7E03FF16C36E49EDE3C0041E7F049E15F76E01BC6D5C04FC15FF6E95C8FC4C80
+A26E5F4C143F6E5F4C141FA2037F5E4C140FA26F486E5AA2031F5E93C812036F5E5E3A7E
+B863>I<B600F049B512E0A4C601FCC8380FF000017F705A6E4B5A6D6C4B5A6D7F4EC7FC
+6D6D147E6D7F606D6D495A6D7F4D5A6D6D495A6E7E4D5A6E6C495A6E13804DC8FC6EEBC0
+7E6E13E05F6EEBF1F86E13F9EEFBF06EEBFFE0815F6F5B816F90C9FCB3A2021FB6FCA443
+397EB848>89 D<007FB9FCBA1280A36C18003905786A4A>95 D<EB3FFE0003B512E0000F
+14F8391FF00FFE003FEB03FF6D6C7F6E7FA26F7EA26C5A6C5AEA0380C8FCA2EC3FFF010F
+B5FC137F3901FFF87F00071380380FFE00EA3FF85B485A12FF5BA415FF6D5A127F263FF0
+0713F83B1FFC1FBFFFC0390FFFFE1F0003EBF80F39003FE0032A257DA42E>97
+D<13FFB5FCA412077EAF4AB47E020F13F0023F13FC9138FE03FFDAF00013804AEB7FC002
+80EB3FE091C713F0EE1FF8A217FC160FA217FEAA17FCA3EE1FF8A217F06E133F6EEB7FE0
+6E14C0903AFDF001FF80903AF8FC07FE009039F03FFFF8D9E00F13E0D9C00390C7FC2F3A
+7EB935>I<903801FFC0010F13FC017F13FFD9FF8013802603FE0013C048485AEA0FF812
+1F13F0123F6E13804848EB7F00151C92C7FC12FFA9127FA27F123FED01E06C7E15036C6C
+EB07C06C6C14806C6C131FC69038C07E006DB45A010F13F00101138023257DA42A>I<EE
+7F80ED7FFFA4150381AF903801FF81010F13F1013F13FD9038FFC07F0003EB001FD807FC
+1307000F8048487F5B123FA2485AA312FFAA127FA27F123FA26C6C5B000F5C6C6C5B6C6C
+4913C02701FF80FD13FE39007FFFF9011F13E1010113012F3A7DB935>I<903803FF8001
+1F13F0017F13FC3901FF83FE3A03FE007F804848133F484814C0001FEC1FE05B003FEC0F
+F0A2485A16F8150712FFA290B6FCA301E0C8FCA4127FA36C7E1678121F6C6C14F86D14F0
+00071403D801FFEB0FE06C9038C07FC06DB51200010F13FC010113E025257DA42C>I<EC
+1FF0903801FFFC010713FF90391FF87F8090383FE0FFD9FFC113C0A2481381A24813016E
+1380A2ED3E0092C7FCA8B6FCA4000390C8FCB3ABB512FEA4223A7DB91D>I<161FD907FE
+EBFFC090387FFFE348B6EAEFE02607FE07138F260FF801131F48486C138F003F15CF4990
+387FC7C0EEC000007F81A6003F5DA26D13FF001F5D6C6C4890C7FC3907FE07FE48B512F8
+6D13E0261E07FEC8FC90CAFCA2123E123F7F6C7E90B512F8EDFF8016E06C15F86C816C81
+5A001F81393FC0000F48C8138048157F5A163FA36C157F6C16006D5C6C6C495AD81FF0EB
+07FCD807FEEB3FF00001B612C06C6C91C7FC010713F02B377DA530>I<13FFB5FCA41207
+7EAFED7FC0913803FFF8020F13FE91381F03FFDA3C01138014784A7E4A14C05CA25CA291
+C7FCB3A3B5D8FC3F13FFA4303A7DB935>I<EA01F0EA07FC487EA2487EA56C5AA26C5AEA
+01F0C8FCA913FF127FA412077EB3A9B512F8A4153B7DBA1B>I<141FEC7FC0ECFFE0A249
+13F0A56D13E0A2EC7FC0EC1F0091C7FCA9EC0FF0EB0FFFA4EB007F143FB3B0121FEA3F80
+EA7FC0EAFFE0EC7FE0A215C014FF6C481380903883FE006CB45A000F13F0000113801C4B
+86BA1D>I<13FFB5FCA412077EAF92380FFFE0A4923803FC0016F0ED0FE0ED1F804BC7FC
+157E5DEC03F8EC07E04A5A141FEC7FE04A7E8181A2ECCFFEEC0FFF496C7F806E7F6E7F82
+157F6F7E6F7E82150F82B5D8F83F13F8A42D3A7EB932>I<13FFB5FCA412077EB3B3ACB5
+12FCA4163A7DB91B>I<01FED97FE0EB0FFC00FF902601FFFC90383FFF80020701FF90B5
+12E0DA1F81903983F03FF0DA3C00903887801F000749DACF007F00034914DE6D48D97FFC
+6D7E4A5CA24A5CA291C75BB3A3B5D8FC1FB50083B512F0A44C257DA451>I<01FEEB7FC0
+00FF903803FFF8020F13FE91381F03FFDA3C011380000713780003497E6D4814C05CA25C
+A291C7FCB3A3B5D8FC3F13FFA430257DA435>I<903801FFC0010F13F8017F13FFD9FF80
+7F3A03FE003FE048486D7E48486D7E48486D7EA2003F81491303007F81A300FF1680A900
+7F1600A3003F5D6D1307001F5DA26C6C495A6C6C495A6C6C495A6C6C6CB45A6C6CB5C7FC
+011F13FC010113C029257DA430>I<9039FF01FF80B5000F13F0023F13FC9138FE07FFDA
+F00113800003496C13C00280EB7FE091C713F0EE3FF8A2EE1FFCA3EE0FFEAA17FC161FA2
+17F8163F17F06E137F6E14E06EEBFFC0DAF00313809139FC07FE0091383FFFF8020F13E0
+020390C7FC91C9FCACB512FCA42F357EA435>I<49B4EB0780010FEBE00F013FEBF81F90
+39FFC07C3F0003EB803E3A07FE000F7F4848EB07FF121F497F123F497F127FA25B12FFAA
+6C7EA36C7E5D6C7E000F5C6C6C5B6C6C133F6CEBC0FD39007FFFF1011F13C10101130190
+C7FCAC037F13FEA42F357DA432>I<9038FE03F000FFEB0FFEEC3FFF91387C7F809138F8
+FFC000075B6C6C5A5CA29138807F80ED3F00150C92C7FC91C8FCB3A2B512FEA422257EA4
+27>I<90383FF0383903FFFEF8000F13FF381FC00F383F0003007E1301007C130012FC15
+787E7E6D130013FCEBFFE06C13FCECFF806C14C06C14F06C14F81203C614FC131F903800
+7FFE140700F0130114007E157E7E157C6C14FC6C14F8EB80019038F007F090B512C000F8
+140038E01FF81F257DA426>I<130FA55BA45BA25B5BA25A1207001FEBFFE0B6FCA30003
+90C7FCB21578A815F86CEB80F014816CEBC3E090383FFFC06D1380903803FE001D357EB4
+25>I<01FFEC3FC0B5EB3FFFA4000714016C80B3A35DA25DA26C5C6E4813E06CD9C03E13
+FF90387FFFFC011F13F00103138030257DA435>I<B539F001FFF8A4000390C7EA1F0016
+1E6E133E6C153C6E137C6C15786E13F8017F5CECF001013F5C14F8011F495AA2ECFC0701
+0F5CECFE0F010791C7FC6E5A6D131E15BE6D13BC15FC6D5BA36E5AA26E5AA26E5AA26E5A
+A22D257EA432>I<B500F1B538803FFFA43D07FE000FF80003E06C6C010715C082028015
+076C6E6C148015076C01C0ED0F00826E485C017FED801E5D90273FF01E7F5B17C0DAF83E
+147C011F90393C3FE078037C14F8903B0FFC781FF0F0A29139FEF00FF10107EDF9E002FF
+14FB6D496CB45AA24B7E6D5EA26D496C90C7FCA292C7FC6E5CA2023E147C023C143C4025
+7EA445>I<B539F01FFFF0A4000390398003F8006C01C013E06C1407D97FE05B6D6C485A
+6E48C7FC90381FFC3E010F5B903807FEFC6D6C5A5D6D5B6D5B6E7E6E7E814A7EA24A7E90
+3801F3FFD903E37FD907C17FEB0FC049486C7E4A6C7E013E80496D7E49130F00016E7EB5
+90383FFFF8A42D257EA432>I<B539F001FFF8A4000390C7EA1F00161E6E133E6C153C6E
+137C6C15786E13F8017F5CECF001013F5C14F8011F495AA2ECFC07010F5CECFE0F010791
+C7FC6E5A6D131E15BE6D13BC15FC6D5BA36E5AA26E5AA26E5AA26E5AA292C8FCA25C141E
+003F133E387F803C38FFC07C147814F8EBC1F0EBC3E06C485A387D1F80D83FFFC9FCEA1F
+FCEA07F02D357EA432>I<003FB612C0A3D9F0031380EB800749481300003E5C003C495A
+007C133F5D0078495A14FF5D495B5BC6485B92C7FC495A131F5C495A017FEB03C0EBFFF0
+14E04813C05AEC80074813005A49EB0F80485A003F141F4848133F9038F001FFB7FCA322
+257DA42A>I E
+%EndDVIPSBitmapFont
+%DVIPSBitmapFont: Fg ecbx1440 14.4 45
+/Fg 45 122 df<EE7FFC031FB57E4AB612E0020715F8023F9038C00FFC913AFFFC0001FE
+4901F0EB007F010701C0EB03FF4949497F4990C75A5B5C495A4D7F01FF6F5B5CA27190C7
+FC715AEF00F895C8FCAA0407B512C0BAFCA5C601F8C7120F83B3B3A6B6D8F807B612C0A5
+42547DD349>28 D<913803FF80023F13F849B6FC010715C04901017F903A3FFC007FF8D9
+7FF0EB1FFC49486D7E48496D7E4A7F4817804890C76C13C0A248486E13E0A2001F17F0A3
+003F17F8A249157FA2007F17FCA600FF17FEB3A5007F17FCA6003F17F86D15FFA3001F17
+F0A3000F17E06D5C6C17C0A26C6D4913806C17006E5B6C6D495A6D6C495AD93FFCEB7FF8
+903A0FFF01FFE06D90B55A010192C7FCD9003F13F802031380374F7BCD42>48
+D<151E153E15FE1403140F147FEB07FF0003B5FCB6FCA3EBF87FEAFC00C7FCB3B3B3A600
+7FB712FCA52E4E76CD42>I<EC1FFE49B512F0010F14FC013FECFF804915E02701FF803F
+7F2703FC000713FCD807F001017F48486D7FD81F806E138048C87E7013C0D87FE016E001
+F8806D16F000FF817F7013F8A56C5AA26C5A6C5AEA0380C914F05EA218E05E18C05E1880
+4C13005F4C5A4C5A5F4B5B4B5B4B5B94C7FCED0FFC4B5A4B5AED7FC04B5A4A90C8FCEC03
+FC4A5A4A4814F84A5A4A5A4AC8FC02FEEC01F0495A495A495A5CD90F80140349C8FC013E
+1507017FB7FC90B812E05A5A5A5A5A5A5AB9FC18C0A4354E7ACD42>I<913807FFC0027F
+13FC0103B67E010F15E090261FF80313F890267FC0007F01FEC7EA3FFE48488148486E13
+8013FE486C6C6D13C0804817E080A66C5B18C06C5B6C90C75AD80038168090C8FC4C1300
+A24C5A5F4C5A4B5B4B13C0030F5BDB7FFEC7FC91387FFFF816C016FCEEFF80DA000313E0
+9238007FF8EE3FFE707E70138018C07013E018F07013F8A218FC82A218FEA3EA03C0EA0F
+F0EA3FFC487EA2B5FCA218FCA25E18F8A26C4816F0495C4916E0D83FE04A13C06C485CD8
+0FF04A1380D807FE91387FFE003B03FFE003FFFC6C90B65A6C6C15E0010F92C7FC010114
+FCD9001F1380374F7BCD42>I<17FC1601A216031607160FA2161F163F167FA216FF5D5D
+A25D5D5D167F153E157E15FC15F8EC01F01403EC07E015C0EC0F80141FEC3F00143E5C14
+FC495A5C495A1307495A5C49C7FC5B137E137C5B1201485A5B485A120F485A90C8FC123E
+127E5ABA1280A5C901FCC7FCAF021FB71280A5394F7CCE42>I<486C150601F0153E01FE
+EC01FED9FFF0133F91B65A5F5F5F5F5F94C7FC16FC5E16E093C8FC15FC01F0138091CAFC
+AC913807FF80023F13F891B512FE01F36E7E9026FFFC0113E09139E0007FF891C76C7E49
+6E7E01F86E7E5B7013804916C0C9FC18E08218F0A418F8A31203EA0FE0EA3FF8487EA212
+FF7FA218F0A25B5E6C4816E05B01C016C06CC85A18806C6C4A13007FD80FF04A5A6C6CEC
+FFFCD803FE4913F02701FFE00F5B6C6CB612806D92C7FC010F14F8010114C09026003FFC
+C8FC354F7ACD42>I<ED07FE92B512C0020314F0021F14FC91397FFC01FE9139FFE0007F
+01030180EB3F804990C7121F4948EC7FC0494814FF4948010313E0495A49485B5A485BA2
+485BA2486F13C091C7FC4803001300177E94C7FC5AA25B127FA2ED3FF04AB5FC020714C0
+00FF4914F091391F807FF891393E001FFE02786D7E4A6D13807013C06D5A4A6D13E018F0
+5C7013F8A291C813FCA44916FEA3127FA6123FA37F6C17FCA36C17F85E7E6E15F06C17E0
+6C6D5B6E15C06C4B13806D6C491300D93FFC495A6DB4EBFFFC010790B512F06D5D010015
+80021F01FCC7FC020313C0374F7BCD42>I<121F7F7FEBFF8091B8FCA45A18FE18FC18F8
+18F0A218E018C018804817000180C8123E007EC9127E5F007C4B5A4C5A5F16074C5A484B
+5A4CC7FC167E167CC912FC4B5A4B5AA24B5A150F4B5AA24B5AA24BC8FC5DA25C5D1403A2
+14075D140FA3141FA2143FA34A5AA414FFA65BAB6D5B6E5A6E5A6E5A385279D042>I<91
+3803FFC0023F13FC49B67E010715E090260FFC0013F8D93FE0EB1FFCD97F80EB07FE49C7
+6C7E496E1380484880000317C049157F120718E0173F120FA27FA27F7F6E147F02E015C0
+8002FC14FF6C01FF15806F481300EDE0036C9138F807FE6F485A6C9138FF1FF06CEDFFE0
+17806D4AC7FC7F010F6E7E6D81010115F06D81010315FE010F81D93FF71580D97FC115C0
+2701FF807F14E048EB001F48486D14F04848010314F848481300496E13FC003F151F4914
+07007F6F13FE491400177F00FF163F49151F170F1707A21703A218FCA27F127F6DED07F8
+A26C6CED0FF07F6C6CED1FE06C6CED3FC06C6CEDFF806C01C0010313006C01FCEB3FFE6C
+6CB612F8011F15E001071580010002FCC7FC020F13C0374F7BCD42>I<913807FF80027F
+13F849B512FE01076E7E90261FFE0113E0903A7FF8003FF049486D7E48496D7E48496D7E
+484980486F138091C7FC486F13C05A18E0485A18F0A27013F812FFA318FCA618FEA35E12
+7FA4003F5DA26C7E5E7E6C6D5B161E6C7F6C6D5B6C6C6C13F890393FFC03F06DB55A0107
+4A13FC01001400EC1FF891C8FCA218F85EA301FC16F0487E2607FF8015E05E486D15C0A2
+4C1380A24C13005F4A131F6C4B5A49C7485A494A5A6C48495B6D01075B2701FF803F90C7
+FC6C90B512FC013F5C6D14C0010791C8FC9038007FF0374F7BCD42>I<173FA24D7EA34D
+7EA24C7FA34C7FA24C7FA34C7FA24C7FA34C7F163E83047E80EE7C3F04FC8016F8830301
+814C7E03038116E0830307814C7E030F81168083031F811600834B81033E80037E82157C
+8403FC824B800201835D840203834B800207835D92B8FC4A83A34A8392C9FC4A83143E85
+027E84027C8202FC845C850101854A820103855C850107854A82A2494884D93FF082B600
+F0020FB712C0A55A547CD363>65 D<B912FEF0FFF019FE737E1AE0D8000F01C0C7001F7F
+06037F727F726C7E867313807313C0A27313E0A37313F0A94F13E0A34F13C01B80614F13
+00624F5A06035B4E13E0063F5B92B8C7FC19F8A2F1FF8003C0C7001F13E0060113F89538
+007FFE737E070F13C01BE07313F0851BF87313FCA27313FEA31BFFA91BFEA2611BFCA261
+4F13F81BF0614F13E0077F13C04EB51280060FEBFE00BB5A1AF01AC04FC7FC19C050527B
+D15D>I<932603FFF01407047F01FF140F0307B600E0131F033F03F8133F92B700FE137F
+02039126C003FF13FF020F01F8C7EA3FC1023F01C0EC0FE391B5C80003B5FC4901FC8149
+49814901E082011F498249498292CA7E4948834948835A4A83485B4885A24849187FA248
+5B1B3FA2485B1B1FA25AA21B0091CDFCA2B5FCAE7EA280A36C1A1FA36C7FA21B3F6C7F1B
+3E6C7F1B7E6C6D187C6C1AFC6E18F86C19016D6CEF03F06D7E6FEE07E06D6DEE0FC00107
+6DEE1F806D01F8EE3F006D6D16FE6D01FF4B5A023F01C0EC07F8020F01FCEC3FF0020390
+3AFFC001FFC0020091B6C7FC033F15FC030715F0DB007F1480040301F0C8FC505479D25F
+>I<BAFC19F819FF1AE01AF8D8000701F0C7001F13FE06017FDE003F13C0070F7F07037F
+737F737F747E747E747F86747F8886888688A2747FA3881B7FA288A51D80AF1D00A564A2
+1BFF64A3505BA2505BA2505BA2505B505B99C7FC505A1A7F4F485A4F13F0070F5B073F5B
+4EB55A061F49C8FCBB12F81AE097C9FC19F896CAFC59527CD165>I<BB12FEA5D8000F01
+E0C700077FF0007F191F190785858586A2F23F80A21A1FA31A0FA4DD01F014C01A07A497
+C7FCA21703A31707170F171F17FF92B6FCA5EDE000171F170F17071703A317011BF8A3F2
+01F0A394C8FCA21A03A21BE0A21A07A31A0F1BC01A1F1A3FA21A7F1AFF4F13801907191F
+197F060FB5FCBCFCA21B00A34D527CD156>I<932603FFF01407047F01FF5C0307B600E0
+5B033F03F85B92B700FE5B02039126C003FF5B020F01F8C7EA3FC1023F01C0EC0FE391B5
+C80003B5FC4901FC814949814901E082011F498249498292CA7E4948834948835A4A8348
+5B4885A2484984A2485B87A2485B87A25AA298C8FC91CFFCA2B5FCAE7E067FB7128080A3
+7E95C76C90C7FC807EA36C7FA26C7FA26C7F7E806C7F137F6D7E816D6D93B5FC01077F6D
+01F85D6D7F6D01FF5D023F01E0EC0FEF020F01FCEC3FE30203903AFFE001FF81020091B6
+C6FC033F03FC133F030703F0130FDB007F02801303040301F8CAFC595479D267>71
+D<B8D88007B712FCA5D8000701F0C9003FEB8000B3AE92BAFCA503F0C9123FB3B1B8D880
+07B712FCA55E527CD167>I<B81280A5D8000701F0C7FCB3B3B3B2B81280A529527DD130>
+I<B812E0A5D8000F01E0CAFCB3B3A91AF8A419011AF0A51903A31907A2190F1AE0191FA2
+193F197F19FF60180760187F0503B5FCBB12C0A545527CD14F>76
+D<B600F04EB612F06F606F60A3D800076D4E49C7FCA2DADFFFF01F7FA202CF6D173EA302
+C76D177CA202C36D17F8A202C16DEE01F0A202C06DEE03E0A36F6CEE07C0A26F6CEE0F80
+A26F6CEE1F00A36F6D153EA26F6D5DA26F6D5DA36F6D4A5AA26F6D4A5AA2706C4A5AA370
+6C4A5AA2706C4AC7FCA2706D133EA3706D5BA2706D5BA2706D485AA2706D485AA3716C48
+5AA2716C485AA2716C48C8FCA37113BEA27113FCA2715BA3715BA2715BA2D91FF06F5AB6
+00FE050FB712F0A2725AA272C7FC74527CD17D>I<DA0FFE141C91B500F0133C010702FC
+137C011F02FF13FC017F15C19026FFF00113E148903980001FFB4890C7EA07FFD807FC14
+014848804848153F171F4848150FA2007F1607491503A2170112FFA217007FA26D167CA2
+7F7F6D93C7FC6C7E14C014F8ECFF806C14F8EDFFC06C15FC6CEDFF8017F06C16FC6C826C
+707E6C836D82011F8201078213016D6C81020781EC007F030380ED003F04031480160017
+3F837113C0838312F883A3837EA319807EA26C5E19007F6D4B5A7F6D4B5A01FC4B5A6D15
+1FD9FFC04A5AD97FF8ECFFE028FE1FFF80075B010790B6C7FCD8FC0115FC486C6C14F048
+010F14C0489026007FFCC8FC3A5479D249>83 D<003FBB12FCA59126C0007FEB000301FC
+C7ED003FD87FF0F00FFE49180749180349180190C81600A2007E1A7EA3007C1A3EA500FC
+1A3F481A1FA6C91700B3B3AC49B912C0A550517BD05B>I<B700F8017FB600FC49B612E0
+A5D8001F01C0C8001F01E0C9EBC0000E1FC7FC6F6F606D73163E6F81207E6D73167C6F81
+20FC6D735E6F6F17016D735E616F1B036D735E616F1B076E4C6E5D7015BF1F0F6E041F6E
+5D70031F161F6E9AC8FC073F8070DA3E0F5E6E73143E197E70DA7C07167E6E04FC6E147C
+704A7E1FFC6E03016F5C704A7E6E515A060381704A6C15036E735C1807704A6D14076F07
+805B7148487F1E0F6F021F04C05B05C090C77E1E1F6F4A04E090C9FCDDE03E6E5C6FF1F0
+3E187EDDF07C6E147E6FF1F87C18FC71486E14FC6F01F9715ADDFDF0801DFD6F01FFEFFF
+F04E806F62A24E817061A24E81706195C97EA27096CAFC4D82040F60A24D1607040760A2
+4D16030403604D160104016083537ED188>87 D<EC3FFE0107B512E0011F14FC017F14FF
+2701FFC00F13C02703FE00037F486C01007F6E6D7E486D80707EA2707EA3707F6C5B6C90
+C7FC6C5AC9FCA60307B5FC0203B6FC147F0103B7FC011FEBF00F017F1300EBFFFC000313
+F04813C0485B4890C7FC5A5B485AF081F012FF5BA35EA26D5C127F6D5C003F03F713C36D
+D901E314E06CD9C00714FF00079026F01F8114C06C90B5C61480C602FC6D1300011F01F0
+EB3FFC01010180EB07F03C387CB642>97 D<EB3FF8B5FCA51203C6FCB3A4EE7FF00307B5
+FC031F14C0037F14F0913AF9FF007FFCDAFFF8EB1FFF03E001077F03806D7F92C76C7F4A
+6E7F5C4A6F7E85183F85A38584A31A80AD1A00A36061A261187F616E15FF616E4A5B6E4A
+5B6F495BDACFE04990C7FCDA87F0EB3FFE913A01FE01FFF8496CB65A49013F14C0490107
+49C8FC90C813E041547DD249>I<913803FFE0023F13FE91B67E010315E0010F9038003F
+F8D93FFCEB07FC4948497E4948131F4849497E485B485BA24890C7FC5A5B003F6F5A705A
+705A007F92C8FC5BA312FFAD127F7FA3123F7F6CEE0F80A26C6D141F18006C6D5C6C6D14
+3E6C6D147E6C6D5C6D6C495A6DB4EB07F0010F9038C01FE06D90B5128001014AC7FCD900
+3F13F80203138031387CB63A>I<943803FF80040FB5FCA5EE003F170FB3A4913803FF80
+023F13F849B512FE0107ECFF8F011F9038C03FEF90273FFE0007B5FCD97FF8130149487F
+484980484980484980488291C8FC5A5B123FA2127F5BA312FFAD127FA37F123FA3121F7F
+6C5E6C6D5C5F6C6D91B5FC6C6D5B6C6D4914E0D97FFCD90FEFEBFF80D91FFFEB7F8F0107
+90B5120F010114FC6D6C13E00207010049C7FC41547CD249>I<913807FF80027F13F849
+B512FE01076E7E011F010313E0903A3FFC007FF0D97FF06D7E49486D7E4849130F48496D
+7E48824890C77E1880485A82003F17C0A3485A18E082A212FFA290B8FCA401FCCAFCA612
+7FA37F123FA2EF03E06C7E17076C17C06C6D140F18806C6D141F6C6DEC3F006C6D147ED9
+7FFC495AD91FFFEB07F86D9038E03FF0010390B512C001005D023F01FCC7FC020113E033
+387CB63C>I<ED1FF8913803FFFE020FEBFF80023F14C09139FFF83FE001039038E0FFF0
+49138049010113F85BEB3FFEA2EB7FFCA26F13F0495AEE7FE0EE1F8093C7FCAEB712C0A5
+C601F8C8FCB3B3A7B612FEA52D547CD328>I<DA1FFE14FE49B539E007FF80010FDAFC1F
+13C0013FDAFF7F13E090267FF807EBFF072701FFE001EBF07F48497E484990387FF83F91
+C7003F14C048EEFC1F489338FE070049021F90C7FCA2003F82A9001F5EA26D143F6C5E6C
+5E6E137F6C6D495A6C6D485B6CD9F80713804890B6C8FCD803EF14FC01C114E02707C01F
+FEC9FC49CBFCA2487EA37FA27F13FC90B612FE6CEDFFF017FCEFFF806C8318F06C836C83
+7F48B87E1207D80FFCC700037F4848EC003F4848150F48486F138083485A83A56D5D007F
+18006D5D003F5F6C6C4B5A01FE153FD807FFED7FF06C01C049485AC601FC011F1380013F
+B648C7FC010F15F8010115C0D9000F01F8C8FC3B4F7CB542>I<EB3FF8B5FCA51203C6FC
+B3A4EE1FFC93B57E030314E0030F14F892391FC07FFC92397E003FFE03F86D7EECF9F04B
+6D7FECFBC0ECFF8092C76C7FA25CA25CA45CB3ACB6D8F807B612C0A542537CD249>I<13
+3FEBFFC0487F487FA2487FA66C5BA26C5B6C5B013FC7FC90C8FCAEEB1FF8B5FCA512017E
+B3B3A6B612F0A51C547CD324>I<EB3FF8B5FCA51203C6FCB3A50407B512F0A59339007F
+F000EF3FC04D5A4DC7FCEE01FC4C5AEE0FF04C5A4C5A4CC8FC16FEED03FC4B5A4B5A4B5A
+4B7E4B7EECF9FF02FB7F91B57EA28203BF7F031F7F14FE4A6C7FDAF0077F6F7FA26F7F6F
+7F167F83707F707FA2707F707F707FA2707F707F84B6D8F00F14FEA53F537DD245>107
+D<EB3FF8B5FCA51203C6FCB3B3B3B1B612F8A51D537CD224>I<D93FF0D91FF84AB47EB5
+91B56C010F13F8030302E0013F13FE030F6E90B6FCDB3F809027F803F80F7F922A7E007F
+FC07E0077F000302F890283FFE0F80037FC6D9F1F0011F49487EDAF3E0DAFF3E814B153C
+DAF7805D92C76C496D7F14FF4A5EA24A5EA34A5EB3ADB6D8F80FB66CB612F8A565367BB5
+6E>I<D93FF0EB1FFCB591B57E030314E0030F14F892391FC07FFC92397E003FFE000302
+F86D7EC6EBF1F04B6D7FECF3C0ECF78092C76C7F14FF5CA25CA45CB3ACB6D8F807B612C0
+A542367CB549>I<913801FFC0023F13FE91B67E010315E0010F018013F8903A3FFC001F
+FED97FF0EB07FF49486D7F48496D7F48496D7F91C8127F4883488349153F001F83A2003F
+8349151FA2007F83A400FF1880AC007F1800A3003F5F6D153FA2001F5FA26C6C4B5AA26C
+6D4A5A6C5F6C6D495B6C6D495B6D6C4990C7FCD93FFCEB1FFE6DB46CB45A010790B512F0
+010115C0D9003F49C8FC020313E039387CB642>I<D93FF8EB7FF0B50107B5FC031F14C0
+037F14F09126F9FF0013FCDAFFF8EB3FFF000302E0010F7FC602806D7F92C76C7F4A824A
+804A6E7F85187F85A2183F85A4721380AD4E1300A44E5AA26118FF616E5C616E4A5B6E4A
+5B6F495B03E04990C7FC6FEB7FFE913AF9FE01FFF802F8B65A033F14C0030749C8FC0300
+13E093CAFCB1B612F8A5414D7DB549>I<90393FF001FCB590380FFF804B13E0037F13F0
+9238FE1FF89138F1F83F00019138F07FFC6CEBF3E015C0ECF780A2ECFF00EE3FF84AEB1F
+F0EE0FE093C7FC5CA45CB3ABB612FEA52E367DB535>114 D<903903FFC00E011FEBFC1E
+90B6127E000315FE3907FE003FD80FF0130F4848130348481301491300127F90C8127EA2
+48153EA27FA27F01F091C7FC13FCEBFF806C13FEECFFF06C14FE6F7E6C15E06C816C15FC
+6C81C681133F010F15801301D9000F14C0EC003F030713E0150100F880167F6C153FA216
+1F7EA217C07E6D143F17807F6DEC7F0001F85C6DEB03FE9039FF801FFC486CB512F0D8F8
+1F14C0D8F00791C7FC39E0007FF02B387CB634>I<147CA614FCA41301A31303A21307A2
+130F131F133F137F13FF1203000F90B512FEB7FCA426007FFCC8FCB3A9EE0F80ABEE1F00
+6D7EA2011F143E806D6D5A6DEBC1F86DEBFFF001005C023F1380DA03FEC7FC294D7ECB33
+>I<D93FF8913801FFC0B50207B5FCA50003ED001FC61607B3AE5FA35FA25F137F5F6D6C
+14F7DC01E713F06D6CD907C7EBFFC0903A0FFF801F876D90B51207010114FC6D6C13F002
+0701C091C7FC42377CB549>I<B600E090381FFFFCA5000101F8C7000113006CEE007C6E
+15FC017F5E8017016D6C5D17036D5E6F13076D5E6F130FA26D6D5C171F6D93C7FC6F5B6D
+153E6F137E6D157C8117FC027F5CEDFE01023F5CEDFF036E5C168316876E5C16CF6E5C16
+FF6E91C8FCA36E5BA26E5BA26F5AA36F5AA26F5AA26F5AA23E367DB445>I<B600E09038
+1FFFFCA5000101F8C7000113006CEE007C6E15FC017F5E6E1401013F5E8017036D6D5C17
+076D5E6F130F6D5E6F131F6D93C7FC815F6D6D133E177E6D157C6F13FC027F5C811601DA
+3FFF5B16036E5C16876E5C16CF6E5C16EF16FF6E91C8FCA26E5BA26E5BA26F5AA36F5AA2
+6F5AA26F5AA35E151F93C9FC5D153E157ED81FC0137C487E486C13FC486C5B14015D4A5A
+14074A5A6C48485A4948CAFC495A383F81FC6CB45A6C5B000313C0C648CBFC3E4D7DB445
+>121 D E
+%EndDVIPSBitmapFont
+%DVIPSBitmapFont: Fh ectt1000 10 75
+/Fh 75 123 df<0107131C90380F803EA8011F137EEC007CA4003FB612E0B712F8A43A00
+3E00F800A2EB7E01017C5BA8EBFC0301F85BA2B712F8A4003F15E03A01F007C000A30003
+130F01E05BA86C486CC7FC25337DB22C>35 D<EB0FC0EB3FE0497E497E80EA01F8EBF07C
+147E0003133E13E0A5147E147C9138FC3FF89039F0F87FFCEA01F1EBF3F001F7EB3FF891
+38E01F009038FFC03F6CEB803EA2EC007E49137C485A486C13FC00075CEBFF01D80FDF5B
+381F9F81383F8F8390380FC3E0387E07E75D38FC03F7EB01FF5D6D1410ED007C80A26CEB
+FF80D87E0113C0D87F03EBE0FC3A3F87F7F1F89038FFE3FF6C01C113F06C13806C903800
+7FC0D801FCEB1F8026357EB32C>38 D<143814FC13011303EB07F8EB0FF0EB1FC0EB3F80
+EB7F0013FE485A485A5B12075B120F5B485AA2123F90C7FCA25A127EA312FE5AAC7E127E
+A3127F7EA27F121FA26C7E7F12077F12037F6C7E6C7E137FEB3F80EB1FC0EB0FF0EB07F8
+EB03FC130113001438164272B92C>40 D<127012FC7E7E6C7E6C7EEA0FE06C7E6C7E6C7E
+6C7E137F7F1480131F14C0130FEB07E0A214F01303A214F81301A314FC1300AC130114F8
+A3130314F0A2130714E0A2EB0FC0131F1480133F14005B13FE485A485A485A485AEA3FC0
+485A48C7FC5A5A1270164279B92C>I<EB0380497EA60020140800F8143E00FE14FE00FF
+13C1EBC7C7EBE7CF003FB512F8000F14E0000314806C140038007FFCA248B5FC48148000
+0F14E0003F14F839FFE7CFFEEBC7C7EB07C100FE13C000F8143E0020140800001400A66D
+5A1F247AAA2C>I<EA0F80EA1FE0EA3FF0EA7FF8A213FCA3123F121F120F120013F8A212
+01EA03F01207EA1FE0EA7FC0EAFF80130012FC12700E17718A2C>44
+D<007FB512F0B612F8A36C14F01D0579942C>I<121FEA3F80EA7FC0EAFFE0A5EA7FC0EA
+3F80EA1F000B0B708A2C>I<1507ED0F80A2151F16005D153E157E157CA215FC5D14015D
+14035D14075D140F5D141F92C7FC5C143EA2147E147C14FC5C13015C13035C13075C130F
+5C131F91C8FC5B133EA2137E137C13FC5B12015B12035B12075B120F5B121F90C9FCA25A
+123E127E127C12FC5AA2127021417BB92C>I<EB03F8EB0FFE90383FFF80497F90B57E39
+01FE0FF03903F803F848486C7EEBE0004848137EA248487FA248C7EA1F80A2003E140F00
+7E15C0A3007C140700FC15E0AC6C140F007E15C0A46CEC1F80A36C6CEB3F00A26C6C137E
+6D13FE00075CEBF0016C6C485A3901FE0FF06CB55A6D5B6D5BD90FFEC7FCEB03F823357C
+B32C>I<1307497EA2131FA2133F137F13FF5A1207127FB5FC13DF139FEA7C1F1200B3AE
+007FB512E0B612F0A36C14E01C3477B32C>I<EB0FF890387FFF8048B512E00007804814
+FC391FF80FFE393FE001FF903880007F48C7EA3F80007E141F00FE15C0150F6C15E01507
+A3127E123CC8FCA2150F16C0151F1680153F16005D15FE4A5A14034A5A4A5A4A5A4A5AEC
+FF804948C7FC495A495A495AEB3FE0EB7F8049C8FC485A4848EB03C04848EB07E0EA1FE0
+485A48B6FCB7FCA36C15C023347CB32C>I<EB0FFC90387FFF8048B512E0000714F84880
+391FF807FEEBC0004848137F6D7F1680151FA26C5A6CC7FCC8FC153F16005D15FE14014A
+5AEC1FF890381FFFF0495BA215F86D7F90380007FEEC00FF81ED3F80ED1FC0150FA216E0
+1507A2123C127EB4FC150F16C0A248141F007FEC3F806DEB7F006C6C5B391FF807FE6CB5
+5A6C5C6C14E0C66C1380D90FFCC7FC23357CB32C>I<000FB512FE4880A35D0180C8FCAD
+EB83FE90389FFF8090B512E015F8819038FE03FE9038F000FF01C07F49EB3F8090C7121F
+6C15C0C8120FA2ED07E0A4123C127EB4FC150F16C0A248141F007EEC3F80007FEC7F006C
+6C5B6D485A391FF80FFC6CB55A6C5C000114C06C6C90C7FCEB0FF823347CB22C>53
+D<EC3FC0903801FFF801077F011F7F497F90387FE07F9039FF003F804848137FEA03F848
+5A5B000FEC3F004848131E4990C7FC123F90C9FCA25A127EEB03FE90381FFF80D8FC7F13
+E000FDB57EB67E9038FE07FC9038F001FE9038C0007F49EB3F8090C7121F16C048140F16
+E01507A3127EA47E150F6D14C0001F141F6D1480000F143F6DEB7F003907F801FE3903FE
+07FC6CB55A6C5C6D5B011F1380D907FCC7FC23357CB32C>I<EB07FC90383FFF8090B512
+E0000314F84880390FFC07FE391FF001FF9038C0007F4848EB3F8090C7121F4815C0007E
+140FA56CEC1F80A26C6CEB3F006D5B390FF001FE3903FC07F86CB55A6C6C13C0D907FCC7
+FC90387FFFC048B512F03903FC07F8390FF001FE391FC0007F497F48C7EA1F80007EEC0F
+C0A248EC07E0A7007EEC0FC0A2007F141F6C6CEB3F806C6CEB7F009038F001FF390FFC07
+FE6CB55A6C5CC614E0013F1380D907FCC7FC23357CB32C>56 D<EB07FCEB3FFF90B512C0
+488048803907FC07F8390FF001FC48486C7ED83F80137E157F48C77E007EEC1F8012FE5A
+ED0FC0A416E0A37E127E007F141F7E6D133F6C6C137F390FF001FF3807FC0F6CB6FC6C14
+F76C14C7013F130FD90FF813C090C7FCA2151F1680153F1600000F5C486C137E486C13FE
+4A5A4A5A14079038801FF0391FE07FE090B55A6C91C7FC6C5B000113F838007FC023357C
+B32C>I<121FEA3F80EA7FC0EAFFE0A5EA7FC0EA3F80EA1F00C7FCAE121FEA3F80EA7FC0
+EAFFE0A5EA7FC0EA3F80EA1F000B2470A32C>I<1502ED0F80151F157F15FF913803FE00
+EC0FFCEC1FF0EC7FE0ECFF80D903FEC7FC495AEB1FF0495AEBFF80000390C8FCEA07FCEA
+1FF8EA3FE0EAFF8090C9FCA27FEA3FE0EA1FF8EA07FC6CB4FCC67FEB3FE06D7EEB07FC6D
+7E903800FF80EC7FE0EC1FF0EC0FFCEC03FE913800FF80157F151F150FED0200212A7BAD
+2C>60 D<122012F87EB4FC7FEA3FE0EA1FF8EA07FC6CB4FCC67FEB3FE06D7EEB07FC6D7E
+903800FF80EC7FE0EC1FF0EC0FFCEC03FE913800FF80157FA215FF913803FE00EC0FFCEC
+1FF0EC7FE0ECFF80D903FEC7FC495AEB1FF0495AEBFF80000390C8FCEA07FCEA1FF8EA3F
+E0EAFF8090C9FC12FC5A1220212A7BAD2C>62 D<14FE497EA4497FA214EFA2130781A214
+C7A2010F7FA314C390381F83F0A590383F01F8A490387E00FCA549137E90B512FEA34880
+A29038F8003FA34848EB1F80A4000715C049130FD87FFEEBFFFC6D5AB514FE6C15FC497E
+27347EB32C>65 D<007FB512E015F8B612FE6C8016C03903F0003FED0FE0ED07F01503A2
+ED01F8A6ED03F0A21507ED0FE0ED1FC0EDFF8090B612005D5D15FF16C09039F0001FE0ED
+07F0ED03F81501ED00FCA216FE167EA616FE16FC1501ED03F8150FED3FF0007FB612E016
+C0B712806CECFE0015F027337FB22C>I<02FF13700107EBE0F84913F9013F13FD4913FF
+EBFF813901FE007F4848131FD807F0130F1507485A491303485A150148C7FCA25A007EEC
+00F01600A212FE5AAB7E127EA3007F15F06CEC01F8A26C7EA26C6C13036D14F06C6C1307
+16E0D803FC131F6C6CEB3FC03A00FF81FF806DB512006D5B010F5B6D13F0010013802535
+7DB32C>I<007FB5FCB612C015F0816C803907E003FEEC00FFED7F80153FED1FC0ED0FE0
+A2150716F0150316F81501A4ED00FCACED01F8A3150316F0A2150716E0150FED1FC0153F
+ED7F80EDFF00EC03FE007FB55AB65A5D15C06C91C7FC26337EB22C>I<007FB612F0B712
+F8A37E3903F00001A7ED00F01600A4EC01E04A7EA490B5FCA5EBF003A46E5A91C8FCA516
+3C167EA8007FB612FEB7FCA36C15FC27337EB22C>I<007FB612F8B712FCA37ED803F0C7
+FCA716781600A515F04A7EA490B5FCA5EBF001A46E5A92C7FCAD387FFFE0B5FC805C7E26
+337EB22C>I<903901FC038090390FFF87C04913EF017F13FF90B6FC4813073803FC0149
+7E4848137F4848133F49131F121F5B003F140F90C7FCA2127EED078092C7FCA212FE5AA8
+913803FFF84A13FCA27E007E6D13F89138000FC0A36C141FA27F121F6D133F120F6D137F
+6C7E6C6C13FF6D5A3801FF076C90B5FC6D13EF011F13CF6DEB0780D901FCC7FC26357DB3
+2C>I<D87FFEEBFFFCB54813FEA36C486C13FCD807E0EB0FC0B190B6FCA59038E0000FB3
+D87FFEEBFFFCB54813FEA36C486C13FC27337EB22C>I<007FB512F8B612FCA36C14F839
+000FC000B3B3A5007FB512F8B612FCA36C14F81E3379B22C>I<0107B512804914C0A36D
+148090390003F000B3AF1218127EA2B4FCA24A5A48130F007F131F9038C07FC06CB55A6C
+91C7FC6C5B000313F838007FC022347BB22C>I<D87FFCEB7FF8486CEBFFFCA36C48EB7F
+F8D807C0EB1F80153FED7F00157E5D4A5A14034A5A5D4A5A4A5A143F4AC7FC147E5CEBC1
+F813C3EBC7FCA2EBCFFEEBDFBEEBFFBF141F01FE7F496C7E13F86E7EEBF00301E07FEBC0
+01816E7EA2157E153E153F811680ED0FC0A2ED07E0D87FFCEB1FFC486CEB3FFEA36C48EB
+1FFC27337EB22C>I<387FFFE0B57EA36C5BD803F0C8FCB3AE16F0ED01F8A8007FB6FCB7
+FCA36C15F025337DB22C>I<D87FE0EB0FFC486CEB1FFEA26D133F007F15FC000F15E001
+BC137BA4019E13F3A3EB9F01A2018F13E3A21483A2018713C314C7A201831383A214EFA2
+01811303A214FFEB80FEA3147C14381400ACD87FF0EB1FFC486CEB3FFEA36C48EB1FFC27
+337EB22C>I<D87FF0EB7FFC486CEBFFFEA27F007FEC7FFCD807FEEB07C013DEA213DF13
+CFA2148013C714C0A213C314E0A213C114F0A213C014F8A2147CA3143EA2141E141FA214
+0F1587A2140715C7A2140315E71401A215F71400A215FFD87FFC137F487E153FA26C48EB
+1F8027337EB22C>I<EB7FFF0003B512E0000F14F848804880EBE003EB800048C7127FA2
+007E80A300FE158048141FB3A86C143FA2007E1500A3007F5CA26C6C13FEEBF00790B5FC
+6C5C6C5C000314E0C66C90C7FC21357BB32C>I<007FB512C0B612F88115FF6C15802603
+F00013C0153FED0FE0ED07F0A2150316F81501A6150316F01507A2ED0FE0ED3FC015FF90
+B61280160015FC5D15C001F0C8FCB0387FFF80B57EA36C5B25337EB22C>I<EB7FFF0003
+B512E0000F14F848804880EBF007EB800048C7127FA2007E80A300FE158048141FB3A7EB
+01F0EB03F800FE143F267E01FC1300A2EB00FE007F5C147FD83F8013FEEBF03F90B5FC6C
+5C6C5C000314E0C67E90380007F0A26E7EA26E7EA26E7EA2157FA2153E21407BB32C>I<
+387FFFFCB67E15E015F86C803907E007FE1401EC007F6F7E151FA26F7EA64B5AA2153F4B
+C7FCEC01FE140790B55A5D15E081819038E007FCEC01FE1400157F81A8160FEE1F80A5D8
+7FFEEB1FBFB5ECFF00815E6C486D5AC8EA01F029347EB22C>I<90381FF80790B5EA0F80
+4814CF000714FF5A381FF01F383FC003497E48C7FC007E147F00FE143F5A151FA46CEC0F
+00007E91C7FC127F7FEA3FE0EA1FFCEBFFC06C13FC0003EBFFC06C14F06C6C7F01077F90
+38007FFEEC07FF02001380153FED1FC0A2ED0FE0A20078140712FCA56CEC0FC0A26CEC1F
+806D133F01E0EB7F009038FE01FF90B55A5D00F914F0D8F83F13C0D8700790C7FC23357C
+B32C>I<007FB612FCB712FEA43AFC007E007EA70078153CC71400B3AF90383FFFFCA249
+7F6D5BA227337EB22C>I<3B7FFF803FFFC0B56C4813E0A36C496C13C03B03F00001F800
+B3AF6D130300015DA26D130700005D6D130F017F495A6D6C485AECE0FF6DB5C7FC6D5B01
+0313F86D5B9038003F802B3480B22C>I<D87FFCEB7FFC486CEBFFFEA36C48EB7FFCD80F
+C0EB07E06D130F000715C0A36D131F00031580A36D133F00011500A36D5B0000147EA401
+7E5BA46D485AA490381F83F0A4010F5B14C7A301075BA214EFA201035BA214FFA26D90C7
+FCA46D5A27347EB22C>I<D87FF0EB07FF486C491380A36C486D1300001FC8127CA46C6C
+5CA76C6C495AA4143E147FA33A03E0FF83E0A214F7A201E113C3A3000101E35BA201F113
+C701F313E7A314C1A200005DA201F713F71480A301FF13FF017F91C7FC4A7EA4013E133E
+29347FB22C>I<3A3FFF03FFE0484913F0148714076C6D13E03A01F800FE007F0000495A
+13FE017E5BEB7F03013F5B1487011F5B14CF010F5B14FF6D5BA26D90C7FCA26D5AA26D5A
+A2497EA2497EA2497F81EB0FCF81EB1FC7EC87F0EB3F83EC03F8EB7F01017E7FEBFE0049
+7F0001147E49137F000380491480151FD87FFEEBFFFC6D5AB514FE6C15FC497E27337EB2
+2C>I<D87FFCEB7FFC486CEBFFFEA36C48EB7FFCD807F0EB0FC0151F000315806D133F12
+016DEB7F0012006D137E017E13FE017F5BEB3F01EC81F8131FEC83F0EB0FC314C7903807
+E7E0A201035B14EF6DB45AA292C7FC7F5C147EB0903807FFE0497FA36D5B27337EB22C>
+I<003FB612C04815E0A4007EC7EA1FC0ED3F80A2ED7F00157E15FE4A5A003C5CC712034A
+5AA24A5A4A5AA24A5A4AC7FCA214FE495AA2495A495AA2495A495AA2495A49C8FCA213FE
+485AA24848EB03C049EB07E01207485A5B121F485AA248C7FCB7FCA46C15C023337CB22C
+>I<387FFFFCB512FEA314FC00FCC7FCB3B3B3B512FC14FEA36C13FC17416FB92C>I<387F
+FFFCB512FEA37EC7127EB3B3B3387FFFFEB5FCA36C13FC17417DB92C>93
+D<007FB6FCB71280A46C150021067B7D2C>95 D<3801FFF0000713FE001F6D7E15E04880
+9038C01FF81407EC01FC381F80000006C77EC8127EA3ECFFFE131F90B5FC1203120F48EB
+807E383FF800EA7FC090C7FC12FE5AA47E007F14FEEB8003383FE01F6CB612FC6C15FE6C
+14BF0001EBFE1F3A003FF007FC27247CA32C>97 D<EA7FF0487EA3127F1201AAEC1FE0EC
+FFF801FB13FE90B6FC16809138F07FC09138801FE091380007F049EB03F85BED01FC4913
+00A216FE167EA816FE6D14FCA2ED01F86D13036DEB07F0150F9138801FE09138E07FC091
+B51280160001FB5B01F813F83900F03FC027337FB22C>I<903803FFE0011F13F8017F13
+FE48B5FC48804848C6FCEA0FF0485A49137E4848131890C9FC5A127EA25AA8127EA2127F
+6C140F6DEB1F806C7E6D133F6C6CEB7F003907FE03FF6CB55A6C5C6C6C5B011F13E00103
+90C7FC21247AA32C>I<EC0FFE4A7EA380EC003FAAEB07F8EB3FFE90B512BF4814FF5A38
+07FC0F380FF00348487E497E48487F90C7FC007E80A212FE5AA87E007E5CA2007F5C6C7E
+5C6C6C5A380FF0073807FC1F6CB612FC6CECBFFE6C143FEB3FFC90390FF01FFC27337DB2
+2C>I<EB03FE90381FFFC0017F13F048B57E48803907FE03FE390FF800FFD81FE0EB3F80
+5B4848EB1FC090C7120F5A007E15E015075AB7FCA416C000FCC9FC7E127EA2127F6CEC03
+C06DEB07E06C7ED80FF0130F6C6CEB3FC001FF13FF000190B512806C1500013F13FC010F
+13F00101138023247CA32C>I<EC0FF8EC3FFE91B5FC4914805B903807FC7F14F090390F
+E03F0014C092C7FCA6007FB512FEB7FCA36C5C26000FC0C7FCB3A8003FB512F04880A36C
+5C21337DB22C>I<ED03F8903907F80FFC90391FFE3FFE017FB6FC48B7FC48ECFE7F9038
+FC0FF82607F003133E3A0FE001FC1CD9C0001300001F8049137EA66D13FE000F5CEBE001
+6C6C485A3903FC0FF048B5FC5D481480D99FFEC7FCEB87F80180C8FCA37F6C7E90B512F0
+6C14FE48ECFF804815E04815F03A3FC0001FF848C7EA03FC007E1400007C157C00FC157E
+48153EA46C157E007E15FCD87F801303D83FE0EB0FF8D81FFCEB7FF06CB612E000031580
+6C1500D8003F13F8010713C028387EA42C>I<EA7FF0487EA3127F1201AAEC1FE0EC7FFC
+9038F9FFFE01FB7F90B6FC9138F03F80ECC01F02807FEC000F5B5BA25BB3267FFFE0B5FC
+B500F11480A36C01E0140029337FB22C>I<1307EB1FC0A2497EA36D5AA20107C7FC90C8
+FCA7387FFFC080B5FC7EA2EA0007B3A8007FB512FCB612FEA36C14FC1F3479B32C>I<14
+0EEC3F80A2EC7FC0A3EC3F80A2EC0E0091C7FCA748B512804814C0A37EC7120FB3B3A214
+1F003C1480007E133FB414005CEB01FEEBFFFC6C5B5C001F5B000790C7FC1A467CB32C>
+I<EA7FE0487EA3127F1201AA91381FFFF04A13F8A36E13F0913800FE004A5A4A5A4A5A4A
+5A4A5A4A5A4AC7FC14FEEBF1FC13F3EBF7FE90B5FCA2EC9F80EC0FC001FE7FEBFC07496C
+7E496C7E811400157E811680151F3A7FFFC0FFFCB500E113FEA36C01C013FC27337EB22C
+>I<387FFFE0B57EA37EEA0003B3B3A5007FB61280B712C0A36C158022337BB22C>I<3A7F
+83F007E09039CFFC1FF83AFFDFFE3FFCD87FFF13FF91B57E3A07FE1FFC3E01FCEBF83F49
+6C487E01F013E001E013C0A301C01380B33B7FFC3FF87FF0027F13FFD8FFFE6D13F8D87F
+FC4913F0023F137F2D2481A32C>I<397FF01FE039FFF87FFC9038F9FFFE01FB7F6CB6FC
+00019038F03F80ECC01F02807FEC000F5B5BA25BB3267FFFE0B5FCB500F11480A36C01E0
+140029247FA32C>I<EB07FCEB1FFF017F13C048B512F048803907FC07FC390FF001FE48
+486C7E0180133F003F158090C7121F007EEC0FC0A348EC07E0A76C140F007E15C0A2007F
+141F6C15806D133F6C6CEB7F006D5B6C6C485A3907FC07FC6CB55A6C5C6C6C13C0011F90
+C7FCEB07FC23247CA32C>I<397FF01FE039FFF8FFF801FB13FE90B6FC6C158000019038
+F07FC09138801FE091380007F049EB03F85BED01FC491300A216FE167EA816FE6D14FCA2
+ED01F86D13036DEB07F0150F9138801FE09138E07FC091B51280160001FB5B01F813F8EC
+3FC091C8FCAD387FFFE0B57EA36C5B27367FA32C>I<903903FC078090391FFF0FC0017F
+13CF48B512EF4814FF3807FE07380FF00148487E49137F4848133F90C7FC48141F127E15
+0F5AA87E007E141FA26C143F7F6C6C137F6D13FF380FF0033807FC0F6CB6FC6C14EF6C6C
+138F6D130FEB07F890C7FCAD0203B5FC4A1480A36E140029367DA32C>I<D87FFEEB3FC0
+B53801FFF0020713F8021F13FC6C5B39003F7FE1ECFF019138FC00F84A13704A13005CA2
+5C5CA391C8FCAF007FB512E0B67EA36C5C26247EA32C>I<90387FF8700003B512F8120F
+5A5A387FC00F387E00034813015AA36CEB00F0007F140013F0383FFFC06C13FE6CEBFF80
+000314E0C66C13F8010113FCEB0007EC00FE0078147F00FC143F151F7EA26C143F6D133E
+6D13FE9038F007FC90B5FC15F815E000F8148039701FFC0020247AA32C>I<131E133FA9
+007FB6FCB71280A36C1500D8003FC8FCB1ED03C0ED07E0A5EC800F011FEB1FC0ECE07F6D
+B51280160001035B6D13F89038003FE0232E7EAD2C>I<3A7FF003FF80486C487FA3007F
+7F0001EB000FB3A3151FA2153F6D137F3900FE03FF90B7FC6D15807F6D13CF902603FE07
+130029247FA32C>I<3A7FFF01FFFCB514FE148314016C15FC3A03E0000F80A26D131F00
+011500A26D5B0000143EA26D137E017C137CA2017E13FC013E5BA2EB3F01011F5BA21483
+010F5BA214C701075BA214EF01035BA214FF6D90C7FCA26D5A147C27247EA32C>I<D87F
+FFEB7FFF6EB5FCB515806C16004A7ED807C0EB01F0A66C6C495AA3143E147FA2D801F049
+5AECFF87A214F7A201F113C700005D9038F9E3CFA201FB13EFA3D97BC190C7FC017F13FF
+A21480A2013F5B90381F007C29247FA32C>I<3A3FFF03FFF048018713F8A36C010313F0
+3A00FC007E005D90387E01F8013F5BEB1F83EC87E090380FCFC0903807EF80EB03FF6D90
+C7FC5C6D5A147C14FE130180903803EF80903807CFC0EB0FC7EC83E090381F01F0013F7F
+EB7E00017C137C49137E0001803A7FFF01FFFC1483B514FE6C15FC140127247EA32C>I<
+3A7FFF01FFFCB5008113FE148314816C010113FC3A03E0000F806C7E151F6D140012005D
+6D133E137C017E137E013E137CA2013F13FC6D5BA2EB0F815DA2EB07C1ECC3E0A2EB03E3
+ECE7C0130114F75DEB00FFA292C7FC80A2143EA2147E147CA214FC5CA2EA0C01003F5BEA
+7F83EB87E0EA7E0F495A387FFF806C90C8FC6C5A6C5AEA07E027367EA32C>I<003FB612
+E04815F0A4007EC7EA1FE0ED3FC0ED7F80EDFF004A5A003C495AC7485A4A5A4A5A4A5A4A
+5A4AC7FCEB01FC495AEB0FF0495A495A495A49C8FC4848EB01E04848EB03F0485A485A48
+5A485A485AB7FCA46C15E024247DA32C>I E
+%EndDVIPSBitmapFont
+%DVIPSBitmapFont: Fi ecss1000 10 33
+/Fi 33 122 df<B512FCA516057F941C>45 D<12FEA70707788617>I<EC07F8A24A7EA2
+4A7EA2157EEC3F7F143EA291387E3F80A2147C02FC7F151FA2D901F87F150F01038014F0
+A201076D7E14E0A2010F6D7E14C0A2011F6D7E1480013F808191C7FC4981167F137E01FE
+6E7E90B7FCA24882A3D803F8C7EA0FF05B00078216075B000F8216035B001F8216015B00
+3F6F7EA248C91380177F127E00FE17C0323A7EB937>65 D<913803FF80021F13F891B6FC
+4915C013075B4948C61380D97FF0130FD9FFC013034A13014890C9FC485A485A5B120F5B
+485AA2485AA3485AA448CAFCAC6C7EA46C7EA36C7EA26C7E7F12077F6C7E6C6C15206C6D
+14E06E1301D97FF0130FD91FFE137F6DB6FC6D15C0010115006D5C021F13F0020313802B
+3E7BBB35>67 D<B4ED3FC0B3A790B7FCA590C8123FB3AA2A3A78B93B>72
+D<12FFB3B3B3A4083A79B917>I<B4FCB3B3B090B612C0A6223A79B92D>76
+D<D8FFC0ED07FFA36D5DA26D5D00FE177FA26D153F0178153EA2017C157EA26D15FCA301
+3F14016D15F8A26E1303010F15F06E1307A2010715E06E130FA2010315C06E131FA20101
+15806E133FA2010015006E5B027C137E027E13FEA2023E5BEC3F01A2021F5B1583A2020F
+5B15C702075BA3913803EFC0A215FF6E5BA26E90C7FCA392C8FCA2383A78B949>I<B612
+C015F815FF8216E090C77FED1FF8ED07FC15036F7E150082821780A2163FA4167FA21700
+5E5E15014B5A1507ED1FF8EDFFF090B65A168093C7FC15F815C090CAFCB3A6293A79B935
+>80 D<EB03FF011F13F0017F13FE48B612804815C05A4848C6FCD81FF0EB1F8048481307
+01801303007F140090C9FCA212FEA67E7E7F7FEA3FF013FC381FFFC06C13FC6CEBFF806C
+14E06C14F86C80013F7F01077FD9007F1380020713C0020013E0157FED1FF0150FA2ED07
+F8A21503A6ED07F0124012600078EC0FE0007C141FB4EC3FC001C0EBFF80EBFC036CB612
+00001F5C6C14F800015C6C6C13C0D907FEC7FC253E7CBB2E>83 D<B91280A6C7D807F8C8
+FCB3B3B0313A7DB938>I<EB1FF0EBFFFC000313FF000F14804814C09038E01FE0903800
+0FF0001C13070018EB03F81210C7FCEC01FCA7143FEB0FFF90B5FC1203120F381FFE01EA
+3FE0EA7F80130012FEA414037E387F800FEBE03F6CB5FC7E6C13F96C13E1D801FEC7FC1E
+287DA628>97 D<12FEB3A4EB01FCEB0FFF013F13C090B57EB67E9038F03FF8EBC007496C
+7EEB0001486D7EA2157FA3ED3F80AAED7F00A35D5D14016C5CEB80039038C00FF89038F0
+3FF090B55A485C6D5BD91FFEC7FC380007F8213D7ABB2B>I<EB03FE90381FFFC0017F13
+E090B512F84814FC3803FC033907F8007CD80FE01338484813081500485AA248C8FCA312
+7E12FEA9127FA36C7EA26D1302001F14066C6C131E6C6C137E9038FC03FE6CB5FCC614FC
+6D13F0011F13C0903807FC001F287DA625>I<ED3F80B3A4EB0FE0EB3FFC90B5FC4814BF
+4814FF3807FE07380FF801381FE00049137F003F143F5B127F90C7FCA312FEAA127FA36C
+7E157F6C7E6D13FF380FF0033807FE076CB512BF6C143F6C13FEEB7FF8D90FE0C7FC213D
+7DBB2B>I<EB07F8EB1FFE90387FFF8048B512C04814E03907FC0FF0390FF003F8EBE001
+391FC000FC49137C003F147E90C7123E5A127E151F12FEB7FCA500FCC8FCA27EA2127EA2
+127F7E7F6C7E6D13026C6C130E6C6C133E3903FE01FE6CB5FC6C14FC6D13F0011F13C090
+3803FE0020287EA625>I<14FF010313C0130F5B5BEB7F819038FE004049130012015BA2
+1203ADB512FCA5D803F8C7FCB3AE1A3D7FBC19>I<903907E001F890383FFC1F90397FFE
+FFFC48B6FC5A9039F81FF8003907F00FE048486C7EEBC003A248486C7EA76C6C485AA2EB
+E0076C6C485A6C6C485A48B5FC5D4849C7FCEB3FFC381F07E090C9FCA37F7F6CB512C015
+F815FE6CECFF8016C04815E05A3A3F80007FF048C7120F007EEC03F8481401A46C140300
+7E15F0D87F80130F6C6CEB1FE03A1FFC01FFC06CB612806C1500000114FC6C6C13F00107
+90C7FC26387EA52A>I<12FEB3A4EB01FC90380FFF804913C0017F13E090B512F039FFF8
+1FF8EBE007EBC003018013FC14011300A35AB3A71E3C7ABB2B>I<12FFA81200AC127FB3
+B308397BB814>I<12FEB3A5EC03FE4A5A4A5A4A5A4A5A4A5A4A5A4990C7FC495A5C495A
+495A495A495A495A497EB57EA280EBF7F813E3EBC1FCEB80FE497E487F6E7E81141F6E7E
+8114076E7E6E7E811400157F1680213C7ABB29>107 D<12FEB3B3B3A6073C7ABB14>I<D9
+01FCEB03F83BFE0FFF801FFF496D481380017F6DB512C090B500F114E03CFFF81FFBF03F
+F0D9E007EBC00F903AC003FF80070180020013F86E140301005BA3485CB3A735267AA542
+>I<EB01FC39FE0FFF804913C0017F13E090B512F039FFF81FF8EBE007EBC003018013FC
+14011300A35AB3A71E267AA52B>I<EB03FE90380FFF80013F13E090B512F848803903FE
+03FE3907F800FF4848EB7F8049133F4848EB1FC04848EB0FE0A290C712074815F0A2007E
+140300FE15F8A9007FEC07F0A36C6CEB0FE0A26C6CEB1FC06D133F6C6CEB7F806C6CEBFF
+003903FE03FE6CB55A6C5C6D5B011F13C0D903FEC7FC25287EA62A>I<14F0EAFC07130F
+133F137F13FF00FD130013FCEAFFF05B5BA25B90C7FCA35AB3A414267AA51C>114
+D<EB7FE03801FFFC0007EBFF804814C05A383FC03F90380007801401007E90C7FCA4127F
+A26C7E13F0EBFF806C13F06C13FC6C7F6C7FC61480131F010013C0143FEC0FE0A21407A3
+124012600078EB0FC000FE131F39FFC07F8090B5FC6C1400001F5B000313F838007FC01B
+287EA620>I<EA01FCAAB6FCA5D801FCC7FCB3A76D138014013900FF07C014FFA26D1300
+EB3FFCEB1FE01A307FAE1E>I<00FEEB01FCB3AA1403A214076C131F387F807F90B5FC6C
+13F914F1000F13C1D803FCC7FC1E267AA42B>I<B4EC0FE06CEC1FC0A27F003FEC3F80A2
+7F001FEC7F00A26C6C137E15FEA26C6C485AA36C6C485AA3D801FC5B140700005C13FE14
+0F017E5B137F141F013F5BA2149FD91FBFC7FCA3EB0FBE14FE6D5AA323257FA426>I<00
+FED901FEEB01FC007F17F802031403A2018013DF003FEE07F01407ED9F80D81FC016E002
+0F140F158FD80FE002C013C0030F131F141FED07E0D807F01680021E143F143E0003DA03
+F0130013F8023C5C0001017C147EED01F813FC027814FE0000D9F8005BA24A13FC017C5D
+167D137E5C013EEC3DF0013F143F5C011F5D161F36257FA439>I<D87F80EB0FE0003FEC
+1FC06C6C133F6DEB7F806C6C1400000714FE6C6C485A3801FC0301FE5B6C6C485A6D485A
+90383F9FC0EB1FDF6DB45A92C7FC6D5A6D5A1301A2497E1307497EECDF8090381F9FC090
+383F0FE0496C7EEBFE0301FC7F00016D7E48486C7E4848137F120F49EB3F804848EB1FC0
+484814E0007FEC0FF048C7EA07F8252580A426>I<B4EC0FE06CEC1FC0A26C7EED3F807F
+001FEC7F00A26C7E15FE7F00075C1401EA03F85DEBFC0312015D3800FE075D137E140F01
+7F5B133FA290381F9F80A292C7FC130FA2EB079E14DEA2EB03FCA26D5AA35C13035CA213
+075C130FA2495A1220D8383FC8FCEA3FFEA25B5BEA0FE023367FA426>I
+E
+%EndDVIPSBitmapFont
+%DVIPSBitmapFont: Fj ecit1000 10 17
+/Fj 17 118 df<EA0F80EA1FC0EA3FE0127FA212FFA3EA7FC0EA3F80EA1E000B0B6F8A2C
+>46 D<EC07F0EC1FFCEC7FFE49B5FC5B903907FC1F8090380FF00FEB1FC0D93F8013C090
+387F03E79038FE0FFF48485A495A48485A9038E0FE3F000713FC9039C1F81F80380FC3F0
+1383381F87E0EB07C0D83F0F1400003E1380A25DD87E1F133E007C1300A2157E157C00FC
+14FC00F85C14015D14034A5A00FC139F397C0FFFC05D6D90C7FC387E03FC383E01F8393F
+0007C0140F6C6C487E390FE0FFC090B5FC6C91C7FC6C5BC613F8EB3FC0223375B22C>64
+D<EB03F090380FFC7890383FFFFC5B90B5FC3801FE1F48486C5AEA07F8380FF00713E0D8
+1FC05B1380123F1300485C127EA2140F12FE485CA291381FC180ED87E0143FA2EC7F8F91
+38FF0FC05B6C5AD87E07EB1F80D87F0F133F6CB612006C13DFEC8FFE3907FE07FC3901F8
+01F0232476A32C>97 D<EC7F80903803FFE0010F13F8013F13FC5B9038FFC1FE3801FE00
+3803FC01EA07F8EA0FF001E013FCEA1FC0393F80007090C8FCA2127EA312FE5AA77E007E
+141C007F143E6C6C13FEEBC00F6CB5FC6C14FC6C14F0000114C039007FFE001F2475A32C
+>99 D<913803FF804A13C0A380EC001F1680A2153FA21600A25DA2157EEB03F090380FFC
+FEEB3FFF495B90B5FC3801FE1F3803FC0FD807F85B380FF00713E0EA1FC001805B123F13
+005A007E5CA2140F12FE485CA291381FC180EDC7E0EC3F87A2EC7F8F02FF13C049130F6C
+5AD87E07EB1F80D87F0F133F6CB612006C13DFEC8FFE3907FE07FC3901F801F0233376B2
+2C>I<147F903803FFC0010F13F0013F13F84913FCEBFFC13801FE004848137E485AD80F
+E013FE15FC485A383F800190380007F848133F90B512F015E01580B5EAFE0014F000FCC8
+FCA6127E151C007F143E6C6C13FEEBC00F6CB5FC6C14FC6C14F0000114C039007FFE001F
+2475A32C>I<ED03FCED1FFF4B13C05D17E0EDFE1F15FCA30201EB0FC09238F8078093C7
+FCA40103B512F8825B7F5E90260007F0C7FC5DA5140F5DA5141F5DA5143F92C8FCA45C14
+7EA514FE5CA313015CA31303001C5B127F130700FF5B130F495AEBFF807E6C90C9FCEA1F
+FCEA07F02B457DB22C>I<EC07F091381FFC7891387FFEFC49B5FC5B903807FC3F90380F
+F01F90391FE00FF8ECC007EB3F80EB7F00017E14F013FE5B12014914E0A2150F12034914
+C0A2151FA2ED3F80A2157F15FF4A13006C6C5A6D5A3800FE1F90B55A7F7FEB1FFC903807
+F0FC90C7FC1401A25DA21403A25D003C1307007E495AB4131F4A5A49B45A90B5C7FC5C6C
+13F86C13E0000F90C8FC26367BA32C>I<EA07FF487FA37EEA003F91C8FCA25BA2137EA2
+13FEA25BEC3FC00001EBFFF090B57E81A248EBF0FEECC07E14005B12075B5BA2484813FE
+5D5BA2381FC0015DA2EB8003003FECF03016FCEB000715E04814E1020F13F8007E14C1ED
+C3F000FE14C7EDCFE04814FF6E13C0168048903803FE000070EB00FC263379B22C>I<14
+0FEC1F80EC3FC0A4EC1F80EC0F0091C7FCA8133FEBFFC0000313F05A487FEA1FE1EA3FC1
+1381EA7F01127EEAFE0300FC5B13075C1200130F5C131FA25C133FEC0060EC01F8137F13
+7EEBFE0301FC13F01407EC0FE0141FEC3FC090B512806D13005CEB1FF8EB07E01D3475B3
+2C>I<D9707E137E903A79FF81FF8090B500C713C015CF92B512E002C313C34801831383
+0203EB03F001FE13FE01FC01FC13E0120301F813F8A29039F007F007000716C0A201E013
+E0000F010F130F01C001C01380A2001F011F131F018001801300A25E003F013F133E0100
+1300167E167C485B007E137EA2167F00FE13FE4849EB3F80170000780178130F2C247DA3
+2C>109 D<3901F007F03907F81FFC390FFC7FFE486CB5FC48B6128090383FFE1F14F800
+7E13F014E0EB7FC012FE00FC1380140049133FC6481400A348485B157EA24913FE0003EC
+FC18167EEBF00115F8000715FE020313FC01E013F015F1000F15F8EDF3F001C013FF6E13
+E016C0496C13806CC7EA3E0027247AA32C>I<14FE903807FF80011F13E04913F090B5FC
+48EB83F83903FE01FCEBF800485A4848137E485AA2485A90C7FC5A127EA215FE12FE4814
+FCA2140115F81403EC07F0A2EC0FE0007EEB1FC0EC3F80007F13FFD83F8313006CB45A14
+F86C5B000313C0C648C7FC1F2476A32C>I<903907C00FC090391FF03FF090393FF8FFFC
+EB7FFD91B57E9039FE7FF87F01FC497ED801F801E01380EDC01FECFF8000031400495AA2
+EBF1FCEA00015CA20103143FA24A1400A201075C167E16FE5E010F13014B5A15076E485A
+011F495A6E485A91B55A93C7FC495BEC9FF8EC07E091C9FC5BA2137EA213FEA25BA21201
+A25BA2387FFFE0A2B57E6C5BA2293680A32C>I<D801F8EBFF802607FE0313E0260FFF0F
+13F848019F13FC91B512FED83F9F138190390FFE007E007E49137F4A13FF49485A12FC91
+38E000FE16FC49481378000015005CA249C8FCA3137E13FEA25BA21201A25BA21203A25B
+A35B6C5A282479A32C>114 D<ECFFE0010713FC011F7F497F4914809038FF807FEBFC00
+485A5BA20003EC3F00151C6C6C90C7FC13FEEBFFF86C13FF6D13C0011F13F001077F9038
+003FFC1401EC007EA2001C143E127F157E48147C15FC140148495A39FF803FF06CB55A6C
+5C6C5C000749C7FCC613E0212478A32C>I<01F8EB01C0D803FEEB03E0486C13075A4813
+80D83F9F130F131F007F15C0127E013F131F00FE130000FC15805B017E133F120001FE14
+005B5D120149137EA2EDFE180003157E9038F001FCA2140316FE913807F8FC140F9038F8
+1FF92601FC3F13F890B6FC6C15F090397FFE7FE090393FF83FC090390FE00F8027247AA3
+2C>117 D E
+%EndDVIPSBitmapFont
+%DVIPSBitmapFont: Fk ecss2074 20.74 20
+/Fk 20 121 df<EA7FE0AA1207A2EA0FC0A41380121FA31300A25AA2123EA3127E127CA3
+12FC0B2070FA2C>39 D<EF7FFCA34D7EA34C7FA34C805F5F040780187FDC0FF87FA2183F
+DC1FF07FA2181F043F8017E0180F047F8017C004FF6D7E1780A24B6E7E1700A24B6E7F5E
+A203076E7F5E030F82197F5E031F82193F5E033F6F7EA25E037F6F7EA25E03FF6F7EA24A
+49818593C8FC4A84855D020784855D020F717EA24A48831A3FA24A48831A1F5D027F841A
+0F5D02FF841A074990BAFCA34986A34986A202FCCBFC010F861B7F5C011F861B3F494885
+1B1FA24948851B0FA24948851B075C4887874890CC148087A248481BC087A248481BE01C
+7F5B001F1CF01C3F48481BF8A21C1F48481BFC1C0FA248481BFE1C075B5F757BF46A>65
+D<94381FFFE04CB67E040F15F8047F15FF4BB812E0030717F8031F17FE5D92B538F0007F
+4A91C700035B4A01FCEC007F4A01F0150F4A01C015034A90CAFC4A48173C4A481718DAFF
+F094C7FC495B495B495B4990CDFCA2495A495A5C137F5C495AA2485BA2485BA24890CEFC
+A25A5BA2485AA3123F5BA4485AA6485AB16C7EA66C7EA47F121FA36C7EA27F7EA26C7FA2
+6C7FA26C7FA26D7E80133F806D7E6D7EA26D7F6D7F6D6D5F6D6D1707DA7FFC5F6E6C5F6E
+6C177F6E01C0923801FF806E01F015076E01FC151F6E01FF92B5FC6E02F0011F1400033F
+90B712FC6F17F003075F030117806F6C4BC7FC040F15F004011580DC001F01F0C8FC5179
+74F666>67 D<94381FFFC00403B6FC041F15F0047F15FE4BB87E030717F0031F17FC4B17
+FF92B526F0007F14804A91C712034A01FCEC007F4A01E0030F1300021F4915034A90CAFC
+4A488303F8171F4A488349491706494994C7FC495B4990CDFCA2495A495A5C137F5C495A
+5A5C5A5CA24890CEFCA25A5BA2485AA3123F5BA4485AA6485AB0067FB612E06C7EA66C7E
+95C8127FA37F121FA36C7EA27F7EA26C7FA2807E807E6D7E80133F806D7E6D7EA26D7F6D
+7F6D7F6D7F6E7E15FE6E7E6E13C002076DED03FF6E01FC151F6E01FF4AB5FC6E02F0137F
+033F90B812C06FEFFE00030717F8030117E06F6C93C7FC041F15F0040392C8FCDC001F13
+C0537974F66A>71 D<EAFFC0B3B3B3B3B3B3A90A756FF42C>73 D<EAFFC0B3B3B3B3B3B3
+90B912FCA83E7570F456>76 D<D8FFFCF33FFFA36D63A26D98B5FCA36E61A201BF1BFD6E
+1903019F1BF96E1907A3D98FF0F10FF1A3D987F8F11FE1A26E193F01831BC1A26E197F01
+811B81A26E19FF01801B016F5FA2027F19FE6F1703023F19FCA26F1707021F19F8A26F17
+0F020F19F06F171FA2020719E06F173FA2020319C06F177F020119806F17FFA26E190070
+5DA2037F5F701503A26F6C4B5AA2031F5F70150FA2030F5F70151FA203075F70153FA26F
+6C4B5AA203015F7015FFA26F94C7FC715BA2047F5D711303043F5D711307A2041F5D7113
+0FA2040F5D71131FA204075D71133F04035DA271137F04015DA27113FF7092C8FC188105
+7F5BA218C3053F5BA394381FE7F8A2050F5B18FFA2715BA3715BA2715BA394CBFCA26875
+6FF48B>I<B812F0EFFF8018F018FCF0FF808519F08501C0C86C13FE05037FDD007F7F06
+1F7F06077F727F06007F197F737E737E190F8685731380A2851BC0A285A21BE0A21A7FA6
+1AFFA21BC0A261A21B8061A24F13006162191F4F5A4F5A19FF06035B4E5B061F5B067F5B
+0503B5C7FC057F5B90B912F86119C06106FCC8FC18F0188005F0C9FC01C0CDFCB3B3AF4B
+756FF466>80 D<91380FFF8049B512F0010F14FC017F14FF48B712C0000782001F824882
+DAE0007F49C7EA3FFE01F8140FD81FC06E7E90C86C1380121E00186F13C0001081CAFCEF
+7FE0A318F0173FAD93B5FC157F0207B6FC143F49B7FC1307011F153F017FEBF80090B512
+804801F8C7FC4813C04890C8FCEA0FFC485A485A5B485A5BA248C9FCA5177FA26D15FFA2
+6C6C5C6D5C6D140F6C6C5C01FF91B5FC6CEBE00791B612BF6CEDFE3F16FC6C15F06C15C0
+6CECFE006C6C13F0D91FFCC9FC344C77CA4C>97 D<F07FE0B3B3AD4AB47E020F13F8023F
+13FE91B612804915E0010715F04915FC4915FE499038F007FF49D9800013FF02FCC7123F
+4948804801E0804849804A804890C87E4981485A49167F121F5BA2485AA25B127FA25BA3
+12FF90CAFCAD7F127FA47F123FA27FA26C7E18FF6C7E6D5D00075E7F6C6C5D6E5C6C6D5C
+02F05C6C6DECFF7F6DB4EB03FE6D9038E01FFC6D90B512F86D15F06D15E06D15806D1500
+6D6C13FC021F13E0020390C9FC3B7C78FA52>100 D<ED7FE0913803FFFE021F6D7E4A14
+E091B612F84981010781498149D9C01F7F90273FFE00037FD97FF8130002E06E7E4948EC
+1FF04849140F4890C86C7E5B48486F7E491501120F496F7E121F49167EA24848167F845B
+127FA290CAFCF01F80A2BAFCA748CCFCA47EA37EA27FA36C7EA36C7EA26C7E7F12077F6C
+6C17806D16016C6D15076C6D150F6EED3FC0D97FF815FF6D6C14036DB46C131F6DD9F003
+B512806D90B712006D16FC01005E6E15E0021F1580020702FCC7FC020114E09126001FFE
+C8FC3A4C79CA47>I<DB1FE04AB4FC912601FFFE143F02079026FF8003B5FC4AECC01F02
+3F02F0B6FC4A02FB158091BAFC49EBE01F49D9000302FCC7FC49486D01F8C8FC02F89038
+007F8049486E7E49486E7E4A140F013F824A1407A249C86C7EA401FE6F7EAA017F4B5AA4
+6D6C4A5AA26E140F011F5E6E141F6D6C4A5A6D6C4A5A02FEEB01FF496C4990C9FC499038
+E01FFE92B55A495D02BF5C020F14C0496C5CD97E0149CAFC9138001FE001FE90CCFCA67F
+A27F8080EB3FF091B612FE6DEDFFF818FF6D17C019F0013F17FC498390BA7E48854801E0
+C71203480180DA001F7F4848C900037F4848160049EF3FF84848171F49717E127F491707
+8648481703A76D1707007F616D170F003F616D171FD81FFCEF7FF06C6C4D5A6D5E6C01C0
+03075B6C01F8033F5BC601FF4AB448C7FC6D01F0011F5B6D90B75A010F17E00103178001
+004CC8FC021F15F002031580DA000F01E0C9FC496D7CC950>103
+D<EAFFE0ABC7FCB3A9EA7FE0B3B3B3B30B6F74EE25>105 D<DB1FFC923801FFC026FFC0
+01B500C0021F13FC020702F0027F13FF021F02FC49B612C04A6E498191B7010F8101C170
+488101C37048819027C7FE007F91387FE007D9CFF8010F9027E0FF80007FD9DFE00103D9
+F1FEC7EA3FFF4A01004A140FD9FF8091267FF3F88091C8D9FFF01680496F4980495F7182
+494D16C0A2496F90C9FCA3495EA4495EB3B3AC624A72C97F>109
+D<ED1FF826FFC001B57E020714E0021F14F8027F8091B67E01C18101C316809038C7FE00
+D9CFF0011F13C0D9DFE0010713E0D9FF80130191C8FC18F049157F5B173F4916F8A24915
+1FA35BA45BB3B3AC354A72C952>I<ED1FFC92B57E020714F0021F14FC027F14FF91B77E
+010316E0498249D9F0077F4990C76C7ED93FFCEC1FFED97FF0EC07FF4A8049486E7F4849
+6E7F4890C96C7E49163F4848707E49160F000F844916074848707EA34848707EA2491600
+007F84A490CB7E481980AC6D17FF007F1900A36D5EA2003F606D1603A2001F606D1607A2
+6C6C4C5A6D161F0007606D163F6C6C4C5A6C6D4B5A6E5C6C6D4A5BD97FF8020F90C7FC6D
+6C4A5A6DB46CEBFFFC6DD9F0075B6D90B65A6D5E010016806E92C8FC021F14FC020714F0
+020114C09126001FFCC9FC414C79CA50>I<ED01F8B46C131F157FEC01FF1407141F5C5C
+9138FFFE00018113F0018313C0018790C7FCEB8FFCEB9FF85CEBBFC0A2EBFF8091C8FC5B
+A25B5BA35BA25BA45BB3B3A7254A72C936>114 D<91380FFFC091B512FE0107ECFFC001
+1F15F8017F15FE90B812804817C05A489038F0003F4890C70003138049EC007FD81FF815
+1F491507003F16014992C7FCA2485AA77FA26C7E7F7F6CB4FC6C13C014F86CEBFF806C14
+FC6CECFFE06C15FC6D14FF6D15C0010F81010315F8010081020F80DA007F7F03071480DB
+003F13C0160F040313E01600EF7FF0173FA2EF1FF8A2170FA7EF1FF0A20070163F127C00
+7FEE7FE001C015FF01F0020313C0B5020F138002F0137F91B712006C5E001F5E000716F0
+C65E011F1580010302FCC7FCD9000F13C0354C7CCA3D>I<D8FFC0ED1FF8B3B3B0173FA3
+177FA217FFA26D5C5E007F5D6D5C6D143F01FEECFFDF273FFF8007139F91B6121F6C15FC
+6C15F86C15E06C15806CECFE006C6C13F0D90FFEC9FC354A72C852>117
+D<D87FF0EF1FF86C6CEF3FF0001FF07FE06C6CEFFFC06C6C5E6C6C18806E4B13006C6D4B
+5A6C4D5A6D6C4B5A6D7E6D6C4B5A6D6C4B5A6E4B5A01074B5B6D6C4A90C7FC6D7F6D6D49
+5A6E6C495A6E6C495A021F4A5A6F5C6E6C137F6E6C495A6E6C485B6E018390C8FC6E5C92
+387FC7FC16EF6FB45A6F5B6F5B6F5B6F5B6F90C9FCA2835D4B7F4B7F4B7F92383FEFF892
+387FC7FCEE83FEEDFF814AEB01FF4A486C7F4A486D7E4A486D7E717E4A48804A486D7E4A
+48130702FF6E7E49496D7E92C78049486E7F49486F7E010F707E4948151F4948824A6F7E
+017F707E49486F7E48496F13804890C914C0484882F17FE04848EF3FF04848EF1FF84848
+18FC007FF00FFE4848EF07FF484980C849>120 D E
+%EndDVIPSBitmapFont
+%DVIPSBitmapFont: Fl ecrm0700 7 1
+/Fl 1 66 df<140EA2141FA34A7EA3EC6FC0A2ECEFE014C7A290380183F0A390380301F8
+A201067F1400A249137EA2011C137F01187FA24980013FB5FCA2903960000FC0A201E080
+491307A248486D7EA200038115011207D81FC0497ED8FFF890383FFFE0A22B2A7EA931>
+65 D E
+%EndDVIPSBitmapFont
+%DVIPSBitmapFont: Fm ecrm1000 10 80
+/Fm 80 123 df<486C1360000314E039070001C0000EEB038048EB070000181306003813
+0E0030130C0070131C00601318A200E01338481330A400CEEB338039FF803FE001C013F0
+A3007F131FA2393F800FE0390E0003801C1981B91C>16 D<001C1307007FEB1FC039FF80
+3FE0A201C013F0A3007F131F001CEB073000001300A400011470491360A2000314E090C7
+12C048130100061480000E130348EB070048130E485B006013181C1980B91C>I<DA0FF8
+13FC91397FFF07FF903B01F807DF83C0903A07E001FF0F903B1F8007FE1FE090393F000F
+FC137E16F85B9338F007804848010790C7FC1503ACB812F8A32801F80003F0C7FCB3AB48
+6C497E267FFFE0B512F0A3333B7FBA30>27 D<EC0FF8EC7FFE903901F80780903907E001
+C090391F8000E090383F0007017E497EA25BA2485A6F5AED018092C8FCA9ED03F0B7FCA3
+3901F8000F1503B3AA486C497E267FFFE0B512C0A32A3B7FBA2E>I<EC0FFC91387FFF70
+903901F803F0903807E00790381F800FEB3F00137EA25B150748481303ADB7FCA33901F8
+0003B3AB486C497E267FFFE0B512C0A32A3B7FBA2E>I<DA0FF0EB1FF0DA7FFEEBFFFC90
+3B01F80F83F00F903C07E001CFC00380903C1F8000FF0001C090273F0007FE130F017E49
+48497EA2495CA248485C03076E5A03030203C7FC95C8FCA9F007E0BAFCA33C01F80003F0
+001F1807B3AA486C496C497E267FFFE0B500C1B51280A3413B7FBA45>I<141FEC7FC090
+3801F0E0903803C0600107137090380F803090381F00381518A25BA2133E133F15381530
+A215705D5D140190381F838092CAFC1487148E02DC49B51280EB0FF85C4A9039003FF800
+0107ED0FC06E5D71C7FC6E140E010F150CD91DFC141C01391518D970FE143801E0153026
+01C07F1470D803805D00076D6C5BD80F00EBC00148011F5C4890380FE003003E6E48C8FC
+007E903807F8060203130E00FE6E5A6E6C5A1400ED7F706C4B13036F5A6F7E6C6C6D6C5B
+7013066C6C496C130E6DD979FE5B281FF001F07F133C3C07F80FE03FC0F86CB539800FFF
+F0C69026FE000313C0D91FF0D9007FC7FC393E7DBB41>38 D<121C127FEAFF80A213C0A3
+127F121C1200A412011380A2120313005A1206120E5A5A5A12600A1979B917>I<146014
+E0EB01C0EB0380EB0700130E131E5B5BA25B485AA2485AA212075B120F90C7FCA25A121E
+A2123EA35AA65AB2127CA67EA3121EA2121F7EA27F12077F1203A26C7EA26C7E1378A27F
+7F130E7FEB0380EB01C0EB00E01460135278BD20>I<12C07E12707E7E7E120F6C7E6C7E
+A26C7E6C7EA21378A2137C133C133E131EA2131F7FA21480A3EB07C0A6EB03E0B2EB07C0
+A6EB0F80A31400A25B131EA2133E133C137C1378A25BA2485A485AA2485A48C7FC120E5A
+5A5A5A5A13527CBD20>I<EB0380497EA7397803803C00FC147E00FE14FE397F8383FC39
+3FC387F8390FE38FE03903FBBF803900FFFE00EB3FF8EB0FE0A2EB3FF8EBFFFE3903FBBF
+80390FE38FE0393FC387F8397F8383FC39FE0380FE00FC147E0078143C390007C000A76D
+5A1F247BBD2A>I<121C127FEAFF80A213C0A3127F121C1200A412011380A2120313005A
+1206120E5A5A5A12600A19798817>44 D<B512FCA516057F941C>I<121C127FEAFF80A5
+EA7F00121C0909798817>I<1506A2150E150CA2151C151815381530A215701560A215E0
+15C0A214011580A2140315005C1406A2140E140CA2141C1418A214381430A21470146014
+E05CA213015CA2130391C7FCA25B1306A2130E130C131C1318A213381330A213701360A2
+13E05BA212015B120390C8FCA25A1206A2120E120CA2121C1218A21238123012701260A2
+12E05AA21F537BBD2A>I<EB03F8EB1FFF90387E0FC09038F803E03901E000F048481378
+0007147C48487FA248C77EA2481580A3007EEC0FC0A500FE15E0B3007E15C0A4007F141F
+6C1580A36C1500A26C6C133EA26C6C5B6C6C5BEBF0013900F803E090387E0FC0D91FFFC7
+FCEB03F823397DB62A>I<EB01C013031307131F13FFB5FCA2131F1200B3B3A7497E007F
+B512F0A31C3779B62A>I<EB0FF0EB7FFE48B57E3903E03FE0390F000FF0001E6D7E001C
+6D7E486D7E5A6E7E126012FE6CEC7F807FA56CC7FC121CC8FCEDFF00A25D14015D14035D
+4A5A4A5A5D4A5A4AC7FC147E5C495A14E0495A495A49C8FC011EEB01805B5B4913034848
+1400485A485A90C75A48B6FC5A5A485CB6FCA321377CB62A>I<EB07F8EB3FFF90B512C0
+3901F80FF03903C007F848486C7E390E0001FEEA0F80391FE000FF7FA56C5A6C5AC7485A
+A25D14035D4A5A5DEC0F80027FC7FCEB1FFCECFF809038000FE06E7EEC01FC816E7EED7F
+80A216C0A2153F16E0A2121EEA7F80A2487EA316C0157F491480007EC7FC0070ECFF006C
+495A121E390F8003F83907F00FF00001B512C06C6C90C7FCEB0FF823397DB62A>I<1538
+A2157815F8A2140114031407A2140F141F141B14331473146314C313011483EB03031307
+1306130C131C131813301370136013C01201EA038013005A120E120C5A123812305A12E0
+B712F8A3C73803F800AA4A7E0103B512F8A325387EB72A>I<0006140CD80780133C9038
+F003F890B5FC5D5D158092C7FC14FC38067FE090C9FCAAEB07F8EB1FFE9038780F809038
+E007E03907C003F0496C7E130000066D7E81C8FC8181A21680A4121C127F5A7FA390C713
+005D12FC00605C12704A5A6C5C6C1303001E495A6C6C485A3907E03F800001B5C7FC3800
+7FFCEB1FE021397CB62A>I<EC3FC0903801FFF0010713FC90380FE03E90383F80079038
+7E001F49EB3F804848137F485A12075B000FEC3F0049131E001F91C7FC5B123FA3127F90
+C9FCEB01FC903807FF8039FF1E07E090383801F0496C7E01607F01E0137E497F16805BED
+1FC0A390C713E0A57EA47F123F16C0A2001FEC3F807F000F15006D5B000714FE6C6C5B6C
+6C485A3900FE07F090387FFFC0011F90C7FCEB03FC23397DB62A>I<12301238123E003F
+B612E0A316C05A168016000070C712060060140E5D5D00E014304814705D5DC712014A5A
+4AC7FC1406140E5CA25C1478147014F05C1301A213035C1307A2130FA3131F5CA2133FA5
+137FA96DC8FC131E233A7BB72A>I<EB03F8EB1FFF017F13C09038FC07F03901E001F839
+03C0007C4848133C90C7123E48141E000E141F001E80A3121FA26D5B6D131E7FD80FF85B
+6D137C01FF13786C6D5A6CEBE3E0ECF780C601FFC7FC6D5A6D6C7E010F13E0013F7F01F9
+7F3901E07FFE48486C7E380F800F48486C1380001E010113C0487F007C143F0078EC1FE0
+150F00F81407481403A21501A36C15C0A200781403007C15806C14076CEC0F006C6C131E
+D807E0137C3903F803F0C6B55A013F1380D907FCC7FC23397DB62A>I<EB03F8EB1FFF01
+7F13C03901FC07E048486C7E3907E001F8000F6D7E4848137E5B003F80A248C71380A25A
+ED1FC0A516E0A56C143FA36C7E157F121F6C6C13FF6C6C13DF000313013901F0039F3900
+FC0F1FD93FFC13C0EB07F090C7FCA2153F1680A216005D120F486C137E486C5BA24A5A4A
+5A49485A381F000F001CEB1F80260F807FC7FC3807FFFE000113F838003FC023397DB62A
+>I<121C127FEAFF80A5EA7F00121CC7FCB2121C127FEAFF80A5EA7F00121C092479A317>
+I<121C127FEAFF80A5EA7F00121CC7FCB2121C127FEAFF80A213C0A3127F121C1200A412
+011380A2120313005A1206120E5A5A5A12600A3479A317>I<007FB812F8B912FCCCFCB0
+B912FC6C17F836147B9E41>61 D<1538A3157CA315FEA34A7EA34A6C7EA202077FEC063F
+A2020E7FEC0C1FA2021C7FEC180FA202387FEC3007A202707FEC6003A202C07F1501A2D9
+01807F81A249C77F167FA20106810107B6FCA24981010CC7121FA2496E7EA3496E7EA349
+6E7EA213E0707E1201486C81D80FFC02071380B56C90B512FEA3373C7DBB3E>65
+D<B712E016FC16FF0001903980007FC06C90C7EA1FE0707E707E707EA2707EA283A75F16
+035F4C5A4C5A4C5A4C5AEEFF8091B500FCC7FCA291C7EA7F80EE1FE0EE07F0707E707E83
+707EA21880177F18C0A7188017FFA24C13005F16034C5AEE1FF8486DEB7FF0B812C094C7
+FC16F832397DB83B>I<913A01FF800180020FEBE003027F13F8903A01FF807E07903A03
+FC000F0FD90FF0EB039F4948EB01DFD93F80EB00FF49C8127F01FE153F12014848151F48
+48150FA248481507A2485A1703123F5B007F1601A35B00FF93C7FCAD127F6DED0180A312
+3F7F001F160318006C7E5F6C7E17066C6C150E6C6C5D00001618017F15386D6C5CD91FE0
+5C6D6CEB03C0D903FCEB0F80902701FF803FC7FC9039007FFFFC020F13F002011380313D
+7BBA3C>I<B712C016F816FE000190398001FF806C90C7EA3FE0EE0FF0EE03F8707E707E
+177FA2EF3F8018C0171F18E0170F18F0A3EF07F8A418FCAC18F8A4EF0FF0A218E0A2171F
+18C0EF3F80A2EF7F0017FE4C5A4C5AEE0FF0EE3FE0486DEBFF80B8C7FC16F816C036397D
+B83F>I<B812FEA3000190388000076C90C8FC173F838383A383A31880170116C0A394C7
+FCA31501A21503150F91B5FCA3EC000F15031501A21500A21860A318E093C712C0A41701
+A3EF0380A21707A2170F173F177F486D903807FF00B9FCA333397EB838>I<B812F8A300
+01903880001F6C90C71201EE00FC177C173C171CA2170CA4170E1706A2ED0180A21700A4
+1503A21507151F91B5FCA3EC001F15071503A21501A692C8FCAD4813C0B612C0A32F397D
+B836>I<DBFF8013C0020FEBF001023F13FC9139FF803F03903A03FC000787D90FF0EB03
+CF4948EB00EF4948147F4948143F49C8121F485A4848150F48481507A248481503A2485A
+1701123F5B007F1600A448481600AB93B6FCA26C7E9338007FE0EF3FC0A2123F7F121FA2
+6C7EA26C7EA26C7E6C7E6C6C157F6D7E6D6C14FF6D6C14EFD90FF8EB03C7D903FEEB0783
+903A00FFC03F0191393FFFFC00020F01F0130002001380383D7CBA41>I<B648B512FEA3
+0001902680000313006C90C76C5AB3A491B6FCA391C71201B3A6486D497EB648B512FEA3
+37397DB83E>I<B612C0A3C6EBC0006D5AB3B3AD497EB612C0A31A397EB81E>I<013FB512
+E0A39039001FFC00EC07F8B3B3A3123FEA7F80EAFFC0A44A5A1380D87F005B0070131F6C
+5C6C495A6C49C7FC380781FC3801FFF038007F80233B7DB82B>I<B649B5FCA300010180
+9038007FF06C90C8EA3F80053EC7FC173C17385F5F4C5A4C5A4CC8FC160E5E5E5E5E4B5A
+ED0780030EC9FC5D153E157E15FF5C4A7F4A6C7E140E4A6C7E4A6C7E14704A6C7E4A6C7E
+14804A6C7E6F7EA26F7F707EA2707E707EA2707EA2707E707EA2707E707F8484486D497F
+B6011FEBFF80A339397DB841>I<B612E0A3000101C0C8FC6C90C9FCB3AD1718A5173817
+30A31770A317F0A216011603160FEE1FE0486D13FFB8FCA32D397DB834>I<B5933807FF
+F86E5DA20001F0FC002600DFC0ED1BF8A2D9CFE01533A3D9C7F01563A3D9C3F815C3A2D9
+C1FCEC0183A3D9C0FEEC0303A2027F1406A36E6C130CA36E6C1318A26E6C1330A36E6C13
+60A26E6C13C0A3913901FC0180A3913900FE0300A2ED7F06A3ED3F8CA2ED1FD8A3ED0FF0
+A3486C6D5A487ED80FFC6D48497EB500C00203B512F8A2ED018045397DB84C>I<B59138
+07FFFE8080C69238007FE06EEC1F80D9DFF0EC0F001706EBCFF8EBC7FCA2EBC3FEEBC1FF
+A201C07F6E7EA26E7E6E7E81140F6E7E8114036E7E168080ED7FC016E0153FED1FF0ED0F
+F8A2ED07FCED03FEA2ED01FF6F1386A2EE7FC6EE3FE6A2EE1FF6EE0FFEA216071603A216
+011600A2177E486C153E487ED80FFC151EB500C0140EA2170637397DB83E>I<EC03FF02
+1F13E09138FE01FC903901F8007ED907E0EB1F8049486D7ED93F80EB07F049C76C7E01FE
+6E7E48486E7E49157E0003167F4848ED3F80A24848ED1FC0A2001F17E049150F003F17F0
+A3007F17F8491507A300FF17FCAC007F17F86D150FA3003F17F0A26C6CED1FE0A36C6CED
+3FC0000717806D157F000317006C6C15FEA26C6C4A5A017F4A5A6D6C495A6D6C495AD907
+E0EB1F80D903F8017FC7FC903900FE01FC91381FFFE0020390C8FC363D7BBA41>I<B712
+C016FC16FF0001D9800013C06C90C7EA1FE0707EEE03F883707EA2707EA21880A71800A2
+4C5AA24C5A5FEE0FF04C5AEEFF8091B548C7FC16F091CAFCB3A5487FB6FCA331397EB838
+>I<EC03FF021F13E09138FE01FC903901F8007ED907E0EB1F8049486D7ED93F80EB07F0
+49C76C7E01FE6E7E48486E7EA24848157F0007178049153F000F17C049151F001F17E0A2
+4848ED0FF0A3007F17F8A2491507A200FF17FCAC007F17F8A26D150FA2003F17F0A26C6C
+ED1FE0A36C6CED3FC00007027C14804AB4FC3C03F80383807F003B01FC0701C0FEEC0E00
+2600FE0CEBE1FC017FEC63F8D93F8CEB77F0D91FCCEB3FE0D907EE14806DB449C7FC0100
+D981FC130CEC1FFF0203131C91C7001E131C161F183CEF807CEFC0F8EE0FFFA318F08218
+E07013C07013809338007E00364B7BBA41>I<B612FEEDFFE016F8000190388007FE6C90
+C76C7EEE3FC0707E707E707EA2707EA283A65FA24C5AA24C5A4C5AEE3F8004FFC8FCED07
+FC91B512E05E9138000FF0ED03F8ED00FE82707E707EA2161F83A583A6F00180A217F816
+0F1803486D01071400B66D6C5A04011306933800FE0ECAEA3FFCEF07F0393B7DB83D>I<
+D90FF813C090383FFE0190B512813903F807E33907E000F74848137F4848133F48C7121F
+003E140F007E1407A2007C140312FC1501A36C1400A37E6D14006C7E7F13F86CB47E6C13
+F8ECFF806C14E06C14F86C14FEC680013F1480010714C0EB007F020713E0EC007FED3FF0
+151F150FED07F8A200C01403A21501A37EA216F07E15036C15E06C14076C15C06C140F6D
+EB1F80D8FBF0EB3F00D8F0FE13FE39E03FFFF8010F13E0D8C00190C7FC253D7CBA2E>I<
+003FB812E0A3D9C003EB001F273E0001FE130348EE01F00078160000701770A300601730
+A400E01738481718A4C71600B3B0913807FF80011FB612E0A335397DB83C>I<B6903807
+FFFEA3000101809038007FE06C90C8EA1F80EF0F001706B3B2170E6D150C80171C133F17
+186D6C14385F6D6C14F06D6C5C6D6C495A6D6CEB07806D6C49C7FC91387F807E91381FFF
+F8020713E09138007F80373B7DB83E>I<B500FC91387FFF80A30003018091380FFC006C
+90C8EA07E0715A6C705A6E1403017F93C7FCA280013F1506A26E140E011F150C80010F5D
+A28001075DA26E147001031560A26D6C5CA2806D4A5AA2ED8003027F91C8FCA291383FC0
+06A215E0021F5BA2EDF01C020F1318A26E6C5AA215FC02035BA2EDFEE002015BA26E6C5A
+A36FC9FCA3153EA2151CA3393B7EB83E>I<B5D8FC07B5D8F001B5FCA30007902780001F
+FEC7EA1FF86C48C7D80FF8EC07E000010307ED03C01B807F6C6F6C1500A26E5F017F6E6C
+1406A280013F4A6C5CA280011F4A6D5BEE067FA26D6C010E6D5BEE0C3FA26D6C011C6D5B
+EE181FA26D6C6F5BEE300FA26D6C6F485AEE6007A26D6C4CC7FC9338C003FCA203805D91
+3B7F818001FE06A203C1150EDA3FC3C7EAFF0CA203E3151CDA1FE6EC7F98A215F6DA0FFC
+EC3FF0A302075E4B141FA202035E4B140FA202015E4B1407A2020093C8FC4B80503B7EB8
+55>I<007FB590383FFFFCA3C601F801071380D97FE0D903FCC7FC013FEC01F06D6C5C5F
+6D6C5C6D6C13034CC8FC6D6C1306160E6D6C5B6DEB8018163891387FC0306E6C5A16E06E
+6C5A91380FF18015FB6EB4C9FC5D14036E7EA26E7F6F7EA24B7E15DF9138019FF0913803
+8FF8150F91380607FC91380E03FE140C4A6C7EEC38000230804A6D7E14E04A6D7E49486D
+7E130391C76C7E01066E7E130E010C6E7E011C1401013C8101FE822607FF80010713E0B5
+00E0013FEBFF80A339397EB83E>I<B500FE91383FFFE0A3000301E0913807FE00C649EC
+03F0017F6F5A606D6C5D6D6C140395C7FC6D6C1406A26D6C5C6D6C141C17186D6C143817
+306D6D5B6E6C13E05F91383FE0015F91381FF003DA0FF890C8FC1606913807FC0E160C91
+3803FE1C913801FF185E6E13B016E0157F6F5AB3A24B7E023FB512C0A33B397FB83E>I<
+007FB81280B912C0A26C17803204797041>95 D<EB1FE0EBFFFC3803E03F3907000F8039
+0F8007E0486C6C7E13E06E7EA26E7E6C5A6C5AC8FCA4147FEB07FFEB3FE0EBFE00EA03F8
+EA0FF0EA1FC0123F485A90C7FC160C12FEA31401A26C13036CEB077C903980063E18383F
+C01E3A0FE0781FF03A03FFF00FE03A007F8007C026277DA52A>97
+D<EA03F012FFA3120F1203B0EC1FE0EC7FF89038F1E03E9039F3801F809039F7000FC001
+FEEB07E049EB03F049EB01F85BED00FCA216FEA2167E167FAA167E16FEA216FC15016D14
+F8ED03F07F01EEEB07E001C6EB0FC09039C7801F00903881E07E903800FFF8C7EA1FC028
+3B7EB92E>I<EB03FC90381FFF8090387E03E03901F80070484813F83907E001FC380FC0
+03A2EA1F80123F90380001F848EB00F01500A2127E12FEAA127E127FA26C14067F001F14
+0E6D130C000F141C6C6C13386C6C13706C6C13E039007C07C090381FFF00EB07F81F277D
+A525>I<ED0FC0EC03FFA3EC003F150FB0EB03F8EB1FFF90387E078F9038F801EF3903F0
+007F4848133F4848131FA24848130F123F90C7FC5AA2127E12FEAA127E127FA27EA26C6C
+131FA26C6C133F6C6C137F6C6CEBEFF03A01F801CFFF39007C078F90381FFE0FD907F813
+C0283B7DB92E>I<EB07F8EB1FFF90387C0FC03901F803E03903F001F0D807E013F8380F
+C0004848137CA248C7127E153E5A153F127E12FEA3B7FCA248C8FCA5127EA2127FA26C14
+037F001F14076C6C13060007140E6D131CD801F013386C6C137090387E03E090381FFF80
+903803FC0020277EA525>I<147E903803FF8090380FC1E0EB1F8790383F0FF0137EA213
+FCA23901F803C091C7FCADB512FCA3D801F8C7FCB3AB487E387FFFF8A31C3B7FBA19>I<
+ED03F090390FF00FF890393FFC3C3C9039F81F707C3901F00FE03903E007C03A07C003E0
+10000FECF000A248486C7EA86C6C485AA200075C6C6C485A6D485A6D48C7FC38073FFC38
+060FF0000EC9FCA4120FA213C06CB512C015F86C14FE6CECFF804815C03A0F80007FE048
+C7EA0FF0003E140348140116F8481400A56C1401007C15F06CEC03E0003F1407D80F80EB
+0F80D807E0EB3F003901FC01FC39007FFFF0010790C7FC26387EA52A>I<EA03F012FFA3
+120F1203B0EC0FF0EC3FFCECF03F9039F1C01F809039F3800FC0EBF70013FE496D7EA25B
+A35BB3A3486C497EB500C1B51280A3293A7EB92E>I<EA0380EA0FE0487EA56C5AEA0380
+C8FCAAEA03F012FFA312071203B3AA487EB512C0A312387EB717>I<EB01C0EB07F0EB0F
+F8A5EB07F0EB01C090C7FCAAEB01F813FFA313071301B3B3A2123C127E00FF13F01303A2
+14E038FE07C0127C383C0F00EA0FFEEA03F8154984B719>I<EA03F012FFA3120F1203B1
+913801FFFCA39138007FC01600157C15705D4A5A4A5A4AC7FC141E1438147814FC13F1EB
+F3FEEBF73F01FE7FEBF81F496C7E8114076E7E6E7E811400157E157F811680ED1FC0486C
+EB3FF0B500C0B5FCA3283A7EB92C>I<EA03F012FFA3120F1203B3B3AD487EB512C0A312
+3A7EB917>I<2703F00FF0EB1FE000FFD93FFCEB7FF8913AF03F01E07E903BF1C01F8380
+3F3D0FF3800FC7001F802603F70013CE01FE14DC49D907F8EB0FC0A2495CA3495CB3A348
+6C496CEB1FE0B500C1B50083B5FCA340257EA445>I<3903F00FF000FFEB3FFCECF03F90
+39F1C01F803A0FF3800FC03803F70013FE496D7EA25BA35BB3A3486C497EB500C1B51280
+A329257EA42E>I<EB03FE90380FFF8090383E03E09038F800F84848137C48487F48487F
+4848EB0F80001F15C090C712074815E0A2007EEC03F0A400FE15F8A9007E15F0A2007F14
+076C15E0A26C6CEB0FC0000F15806D131F6C6CEB3F006C6C137EC66C13F890387E03F090
+381FFFC0D903FEC7FC25277EA52A>I<3903F01FE000FFEB7FF89038F1E07E9039F3801F
+803A07F7000FC0D803FEEB07E049EB03F04914F849130116FC150016FEA3167FAA16FEA3
+ED01FCA26DEB03F816F06D13076DEB0FE001F614C09039F7803F009038F1E07E9038F0FF
+F8EC1FC091C8FCAB487EB512C0A328357EA42E>I<D903F813C090381FFE0190387E0781
+9038FC01C33903F000E3000714774848133749133F001F141F485A150F48C7FCA312FEAA
+127FA37E6D131F121F6D133F120F6C6C137F6C6C13EF3901F801CF39007E078F90381FFE
+0FEB07F890C7FCABED1FE00203B5FCA328357DA42C>I<3807E01F00FFEB7FC09038E1E3
+E09038E387F0380FE707EA03E613EE9038EC03E09038FC0080491300A45BB3A2487EB512
+F0A31C257EA421>I<EBFF03000313E7380F80FF381E003F487F487F00707F12F0A2807E
+A27EB490C7FCEA7FE013FF6C13E06C13F86C7F00037FC67F01071380EB007F141F00C0EB
+0FC01407A26C1303A37E15806C13077EEC0F00B4131E38F3C07C38E1FFF038C03F801A27
+7DA521>I<1318A51338A31378A313F8120112031207001FB5FCB6FCA2D801F8C7FCB215
+C0A93800FC011580EB7C03017E13006D5AEB0FFEEB01F81A347FB220>I<D803F0EB07E0
+00FFEB01FFA3000FEB001F00031407B3A4150FA3151F12016D133F0000EC77F86D9038E7
+FF8090383F03C790381FFF87903A03FC07E00029267EA42E>I<B538803FFEA33A0FF800
+0FF06C48EB07E00003EC03C06D148000011500A26C6C1306A26D130E017E130CA26D5BA2
+EC8038011F1330A26D6C5AA214E001075BA2903803F180A3D901FBC7FCA214FF6D5AA214
+7CA31438A227257EA32C>I<B53A1FFFE03FFEA3260FF8009038000FF86C48017EEB03E0
+18C00003023EEB0180A26C6C013FEB0300A36C6CEC8006156FA2017E9038EFC00C15C717
+1CD93F01EBE01815830281EBF038D91F831430150102C3EBF87090260FC6001360A2D907
+E66D5A02EC137CA2D903FCEB7F804A133FA2010192C7FC4A7FA20100141E4A130E026013
+0C37257EA33C>I<B538807FFFA33A03FE003FF00001EC1F80000092C7FC017E131C6D13
+186D6C5AECC070010F5B6D6C5AECF180EB03FB6DB4C8FC6D5AA2147F804A7E8114CF9038
+01C7E090380383F090380703F8EB0601496C7E011C137E49137F01787F496D7E486C8000
+0FEC3FF0D8FFFE90B51280A329247FA32C>I<B538803FFEA33A0FF8000FF06C48EB07C0
+0003EC03806C7E16007F00001406A2017E5BA2137F6D5BA26D6C5AA2ECC070010F1360A2
+6D6C5AA214F101035BA2D901FBC7FCA214FF6D5AA2147CA31438A21430A214701460A25C
+A2EA7C0100FE5B130391C8FC1306EAFC0EEA701C6C5AEA1FF0EA0FC027357EA32C>I<00
+3FB512FCA2EB8003D83E0013F8003CEB07F00038EB0FE012300070EB1FC0EC3F80006013
+7F150014FE495AA2C6485A495AA2495A495A495AA290387F000613FEA2485A485A000714
+0E5B4848130C4848131CA24848133C48C7127C48EB03FC90B5FCA21F247EA325>I
+E
+%EndDVIPSBitmapFont
+end
+%%EndProlog
+%%BeginSetup
+%%Feature: *Resolution 600dpi
+TeXDict begin
+%%BeginPaperSize: Letter
+letter
+%%EndPaperSize
+
+%%EndSetup
+%%Page: 1 1
+1 0 bop 0 162 a Fm(11)17 b(11)h(T)249 180 y(E)295 162
+y(X)h(L)398 145 y Fl(A)435 162 y Fm(T)481 180 y(E)527
+162 y(X)0 353 y Fk(Linux)54 b(PCMCIA)f(Programmer's)g(Guide)p
+0 467 3900 24 v 0 580 a Fm(Da)n(vid)27 b(Hinds,)h Fj(dhinds@pcmcia.so)o
+(urc)o(ef)o(or)o(ge.)o(or)o(g)p Fm(.)1326 b(v2.24,)26
+b(16)h(Marc)n(h)f(2000)0 886 y Fi(This)34 b(do)r(cument)f(describ)r(es)
+g(ho)n(w)g(to)g(write)g(k)n(ernel)g(device)h(drivers)g(fo)n(r)f(the)h
+(Linux)g(PCMCIA)f(Ca)n(rd)h(Services)g(interface.)55
+b(It)0 1000 y(also)37 b(describ)r(es)h(ho)n(w)g(to)f(write)h(user-mo)r
+(de)g(utilities)f(fo)n(r)i(communicating)d(with)h(Ca)n(rd)i(Services.)
+69 b(The)38 b(latest)g(version)g(of)0 1113 y(this)29
+b(do)r(cument)g(can)h(alw)n(a)n(ys)e(b)r(e)i(found)g(at)59
+b Fh(<ftp://sourcefor)o(ge)o(.o)o(rg/)o(pc)o(mci)o(a>)o
+Fi(.)38 b(An)30 b(HTML)f(version)h(is)f(at)60 b Fh(<http:)0
+1227 y(//pcmcia.sourcef)o(or)o(ge.)o(or)o(g>)o Fi(.)0
+1558 y Fg(Con)l(ten)l(ts)0 1798 y Ff(1)77 b(In)m(tro)s(duction)3201
+b(4)125 1954 y Fm(1.1)83 b(Cop)n(yrigh)n(t)26 b(notice)i(and)f
+(disclaimer)i(.)41 b(.)h(.)f(.)h(.)g(.)f(.)h(.)f(.)h(.)f(.)h(.)g(.)f(.)
+h(.)f(.)h(.)f(.)h(.)g(.)f(.)h(.)f(.)h(.)f(.)h(.)f(.)h(.)g(.)f(.)h(.)f
+(.)h(.)f(.)h(.)134 b(5)125 2111 y(1.2)83 b(A)n(c)n(kno)n(wledgemen)n
+(ts)54 b(.)41 b(.)h(.)g(.)f(.)h(.)f(.)h(.)f(.)h(.)f(.)h(.)g(.)f(.)h(.)f
+(.)h(.)f(.)h(.)g(.)f(.)h(.)f(.)h(.)f(.)h(.)g(.)f(.)h(.)f(.)h(.)f(.)h(.)
+f(.)h(.)g(.)f(.)h(.)f(.)h(.)f(.)h(.)134 b(5)0 2350 y
+Ff(2)77 b(Basic)31 b(Concepts)3091 b(5)125 2506 y Fm(2.1)83
+b(The)28 b(so)r(c)n(k)n(et)e(in)n(terface)73 b(.)42 b(.)g(.)f(.)h(.)f
+(.)h(.)f(.)h(.)f(.)h(.)g(.)f(.)h(.)f(.)h(.)f(.)h(.)g(.)f(.)h(.)f(.)h(.)
+f(.)h(.)g(.)f(.)h(.)f(.)h(.)f(.)h(.)f(.)h(.)g(.)f(.)h(.)f(.)h(.)f(.)h
+(.)134 b(5)125 2663 y(2.2)83 b(The)28 b(so)r(c)n(k)n(et)e(con)n
+(troller)37 b(.)42 b(.)g(.)f(.)h(.)f(.)h(.)f(.)h(.)f(.)h(.)g(.)f(.)h(.)
+f(.)h(.)f(.)h(.)g(.)f(.)h(.)f(.)h(.)f(.)h(.)g(.)f(.)h(.)f(.)h(.)f(.)h
+(.)f(.)h(.)g(.)f(.)h(.)f(.)h(.)f(.)h(.)134 b(6)0 2902
+y Ff(3)77 b(Card)32 b(Services)g(Subfunction)g(Descriptions)2067
+b(6)125 3059 y Fm(3.1)83 b(Clien)n(t)28 b(managemen)n(t)f(functions)62
+b(.)42 b(.)f(.)h(.)f(.)h(.)g(.)f(.)h(.)f(.)h(.)f(.)h(.)g(.)f(.)h(.)f(.)
+h(.)f(.)h(.)g(.)f(.)h(.)f(.)h(.)f(.)h(.)f(.)h(.)g(.)f(.)h(.)f(.)h(.)f
+(.)h(.)134 b(6)315 3215 y(3.1.1)94 b(RegisterClien)n(t)20
+b(.)42 b(.)g(.)f(.)h(.)f(.)h(.)f(.)h(.)f(.)h(.)g(.)f(.)h(.)f(.)h(.)f(.)
+h(.)g(.)f(.)h(.)f(.)h(.)f(.)h(.)g(.)f(.)h(.)f(.)h(.)f(.)h(.)f(.)h(.)g
+(.)f(.)h(.)f(.)h(.)f(.)h(.)134 b(7)315 3372 y(3.1.2)94
+b(DeregisterClien)n(t)78 b(.)41 b(.)h(.)f(.)h(.)f(.)h(.)f(.)h(.)g(.)f
+(.)h(.)f(.)h(.)f(.)h(.)g(.)f(.)h(.)f(.)h(.)f(.)h(.)g(.)f(.)h(.)f(.)h(.)
+f(.)h(.)f(.)h(.)g(.)f(.)h(.)f(.)h(.)f(.)h(.)134 b(8)315
+3528 y(3.1.3)94 b(SetEv)n(en)n(tMask)81 b(.)42 b(.)f(.)h(.)f(.)h(.)f(.)
+h(.)f(.)h(.)g(.)f(.)h(.)f(.)h(.)f(.)h(.)g(.)f(.)h(.)f(.)h(.)f(.)h(.)g
+(.)f(.)h(.)f(.)h(.)f(.)h(.)f(.)h(.)g(.)f(.)h(.)f(.)h(.)f(.)h(.)134
+b(8)315 3685 y(3.1.4)94 b(BindDevice)58 b(.)41 b(.)h(.)g(.)f(.)h(.)f(.)
+h(.)f(.)h(.)f(.)h(.)g(.)f(.)h(.)f(.)h(.)f(.)h(.)g(.)f(.)h(.)f(.)h(.)f
+(.)h(.)g(.)f(.)h(.)f(.)h(.)f(.)h(.)f(.)h(.)g(.)f(.)h(.)f(.)h(.)f(.)h(.)
+134 b(8)125 3841 y(3.2)83 b(So)r(c)n(k)n(et)27 b(state)h(con)n(trol)83
+b(.)42 b(.)g(.)f(.)h(.)f(.)h(.)f(.)h(.)f(.)h(.)g(.)f(.)h(.)f(.)h(.)f(.)
+h(.)g(.)f(.)h(.)f(.)h(.)f(.)h(.)g(.)f(.)h(.)f(.)h(.)f(.)h(.)f(.)h(.)g
+(.)f(.)h(.)f(.)h(.)f(.)h(.)134 b(9)315 3998 y(3.2.1)94
+b(GetStatus)43 b(.)f(.)f(.)h(.)g(.)f(.)h(.)f(.)h(.)f(.)h(.)f(.)h(.)g(.)
+f(.)h(.)f(.)h(.)f(.)h(.)g(.)f(.)h(.)f(.)h(.)f(.)h(.)g(.)f(.)h(.)f(.)h
+(.)f(.)h(.)f(.)h(.)g(.)f(.)h(.)f(.)h(.)f(.)h(.)134 b(9)315
+4154 y(3.2.2)94 b(ResetCard)27 b(.)42 b(.)f(.)h(.)g(.)f(.)h(.)f(.)h(.)f
+(.)h(.)f(.)h(.)g(.)f(.)h(.)f(.)h(.)f(.)h(.)g(.)f(.)h(.)f(.)h(.)f(.)h(.)
+g(.)f(.)h(.)f(.)h(.)f(.)h(.)f(.)h(.)g(.)f(.)h(.)f(.)h(.)f(.)h(.)93
+b(10)315 4311 y(3.2.3)h(Susp)r(endCard)54 b(.)42 b(.)g(.)f(.)h(.)f(.)h
+(.)f(.)h(.)f(.)h(.)g(.)f(.)h(.)f(.)h(.)f(.)h(.)g(.)f(.)h(.)f(.)h(.)f(.)
+h(.)g(.)f(.)h(.)f(.)h(.)f(.)h(.)f(.)h(.)g(.)f(.)h(.)f(.)h(.)f(.)h(.)93
+b(11)315 4467 y(3.2.4)h(ResumeCard)73 b(.)42 b(.)g(.)f(.)h(.)f(.)h(.)f
+(.)h(.)f(.)h(.)g(.)f(.)h(.)f(.)h(.)f(.)h(.)g(.)f(.)h(.)f(.)h(.)f(.)h(.)
+g(.)f(.)h(.)f(.)h(.)f(.)h(.)f(.)h(.)g(.)f(.)h(.)f(.)h(.)f(.)h(.)93
+b(11)315 4624 y(3.2.5)h(EjectCard)40 b(.)i(.)f(.)h(.)g(.)f(.)h(.)f(.)h
+(.)f(.)h(.)f(.)h(.)g(.)f(.)h(.)f(.)h(.)f(.)h(.)g(.)f(.)h(.)f(.)h(.)f(.)
+h(.)g(.)f(.)h(.)f(.)h(.)f(.)h(.)f(.)h(.)g(.)f(.)h(.)f(.)h(.)f(.)h(.)93
+b(12)315 4780 y(3.2.6)h(InsertCard)81 b(.)41 b(.)h(.)g(.)f(.)h(.)f(.)h
+(.)f(.)h(.)f(.)h(.)g(.)f(.)h(.)f(.)h(.)f(.)h(.)g(.)f(.)h(.)f(.)h(.)f(.)
+h(.)g(.)f(.)h(.)f(.)h(.)f(.)h(.)f(.)h(.)g(.)f(.)h(.)f(.)h(.)f(.)h(.)93
+b(12)125 4937 y(3.3)83 b(IO)28 b(card)e(con\034guration)g(calls)j(.)42
+b(.)f(.)h(.)f(.)h(.)f(.)h(.)g(.)f(.)h(.)f(.)h(.)f(.)h(.)g(.)f(.)h(.)f
+(.)h(.)f(.)h(.)g(.)f(.)h(.)f(.)h(.)f(.)h(.)f(.)h(.)g(.)f(.)h(.)f(.)h(.)
+f(.)h(.)93 b(12)315 5093 y(3.3.1)h(RequestIO)23 b(.)42
+b(.)f(.)h(.)g(.)f(.)h(.)f(.)h(.)f(.)h(.)f(.)h(.)g(.)f(.)h(.)f(.)h(.)f
+(.)h(.)g(.)f(.)h(.)f(.)h(.)f(.)h(.)g(.)f(.)h(.)f(.)h(.)f(.)h(.)f(.)h(.)
+g(.)f(.)h(.)f(.)h(.)f(.)h(.)93 b(13)315 5249 y(3.3.2)h(ReleaseIO)43
+b(.)f(.)f(.)h(.)g(.)f(.)h(.)f(.)h(.)f(.)h(.)f(.)h(.)g(.)f(.)h(.)f(.)h
+(.)f(.)h(.)g(.)f(.)h(.)f(.)h(.)f(.)h(.)g(.)f(.)h(.)f(.)h(.)f(.)h(.)f(.)
+h(.)g(.)f(.)h(.)f(.)h(.)f(.)h(.)93 b(14)315 5406 y(3.3.3)h(RequestIR)n
+(Q)29 b(.)41 b(.)h(.)g(.)f(.)h(.)f(.)h(.)f(.)h(.)f(.)h(.)g(.)f(.)h(.)f
+(.)h(.)f(.)h(.)g(.)f(.)h(.)f(.)h(.)f(.)h(.)g(.)f(.)h(.)f(.)h(.)f(.)h(.)
+f(.)h(.)g(.)f(.)h(.)f(.)h(.)f(.)h(.)93 b(14)315 5562
+y(3.3.4)h(ReleaseIR)n(Q)49 b(.)41 b(.)h(.)g(.)f(.)h(.)f(.)h(.)f(.)h(.)f
+(.)h(.)g(.)f(.)h(.)f(.)h(.)f(.)h(.)g(.)f(.)h(.)f(.)h(.)f(.)h(.)g(.)f(.)
+h(.)f(.)h(.)f(.)h(.)f(.)h(.)g(.)f(.)h(.)f(.)h(.)f(.)h(.)93
+b(16)315 5719 y(3.3.5)h(RequestCon\034guration)70 b(.)42
+b(.)f(.)h(.)f(.)h(.)g(.)f(.)h(.)f(.)h(.)f(.)h(.)g(.)f(.)h(.)f(.)h(.)f
+(.)h(.)g(.)f(.)h(.)f(.)h(.)f(.)h(.)f(.)h(.)g(.)f(.)h(.)f(.)h(.)f(.)h(.)
+93 b(16)315 5875 y(3.3.6)h(Mo)r(difyCon\034guration)38
+b(.)j(.)h(.)f(.)h(.)f(.)h(.)g(.)f(.)h(.)f(.)h(.)f(.)h(.)g(.)f(.)h(.)f
+(.)h(.)f(.)h(.)g(.)f(.)h(.)f(.)h(.)f(.)h(.)f(.)h(.)g(.)f(.)h(.)f(.)h(.)
+f(.)h(.)93 b(18)315 6032 y(3.3.7)h(ReleaseCon\034guration)26
+b(.)41 b(.)h(.)f(.)h(.)f(.)h(.)g(.)f(.)h(.)f(.)h(.)f(.)h(.)g(.)f(.)h(.)
+f(.)h(.)f(.)h(.)g(.)f(.)h(.)f(.)h(.)f(.)h(.)f(.)h(.)g(.)f(.)h(.)f(.)h
+(.)f(.)h(.)93 b(19)315 6188 y(3.3.8)h(GetCon\034gurationInfo)83
+b(.)42 b(.)f(.)h(.)f(.)h(.)g(.)f(.)h(.)f(.)h(.)f(.)h(.)g(.)f(.)h(.)f(.)
+h(.)f(.)h(.)g(.)f(.)h(.)f(.)h(.)f(.)h(.)f(.)h(.)g(.)f(.)h(.)f(.)h(.)f
+(.)h(.)93 b(19)125 6345 y(3.4)83 b(Card)27 b(Information)g(Structure)g
+(\(CIS\))h(calls)h(.)42 b(.)f(.)h(.)f(.)h(.)f(.)h(.)g(.)f(.)h(.)f(.)h
+(.)f(.)h(.)g(.)f(.)h(.)f(.)h(.)f(.)h(.)f(.)h(.)g(.)f(.)h(.)f(.)h(.)f(.)
+h(.)93 b(20)315 6501 y(3.4.1)h(GetFirstT)-7 b(uple,)28
+b(GetNextT)-7 b(uple)39 b(.)j(.)g(.)f(.)h(.)f(.)h(.)f(.)h(.)g(.)f(.)h
+(.)f(.)h(.)f(.)h(.)g(.)f(.)h(.)f(.)h(.)f(.)h(.)f(.)h(.)g(.)f(.)h(.)f(.)
+h(.)f(.)h(.)93 b(20)315 6658 y(3.4.2)h(GetT)-7 b(upleData)84
+b(.)42 b(.)f(.)h(.)f(.)h(.)f(.)h(.)f(.)h(.)g(.)f(.)h(.)f(.)h(.)f(.)h(.)
+g(.)f(.)h(.)f(.)h(.)f(.)h(.)g(.)f(.)h(.)f(.)h(.)f(.)h(.)f(.)h(.)g(.)f
+(.)h(.)f(.)h(.)f(.)h(.)93 b(21)315 6814 y(3.4.3)h(P)n(arseT)-7
+b(uple)69 b(.)41 b(.)h(.)g(.)f(.)h(.)f(.)h(.)f(.)h(.)f(.)h(.)g(.)f(.)h
+(.)f(.)h(.)f(.)h(.)g(.)f(.)h(.)f(.)h(.)f(.)h(.)g(.)f(.)h(.)f(.)h(.)f(.)
+h(.)f(.)h(.)g(.)f(.)h(.)f(.)h(.)f(.)h(.)93 b(22)315 6971
+y(3.4.4)h(V)-7 b(alidateCIS)37 b(.)k(.)h(.)g(.)f(.)h(.)f(.)h(.)f(.)h(.)
+f(.)h(.)g(.)f(.)h(.)f(.)h(.)f(.)h(.)g(.)f(.)h(.)f(.)h(.)f(.)h(.)g(.)f
+(.)h(.)f(.)h(.)f(.)h(.)f(.)h(.)g(.)f(.)h(.)f(.)h(.)f(.)h(.)93
+b(22)315 7127 y(3.4.5)h(ReplaceCIS)54 b(.)41 b(.)h(.)g(.)f(.)h(.)f(.)h
+(.)f(.)h(.)f(.)h(.)g(.)f(.)h(.)f(.)h(.)f(.)h(.)g(.)f(.)h(.)f(.)h(.)f(.)
+h(.)g(.)f(.)h(.)f(.)h(.)f(.)h(.)f(.)h(.)g(.)f(.)h(.)f(.)h(.)f(.)h(.)93
+b(23)125 7284 y(3.5)83 b(Memory)27 b(windo)n(w)g(con)n(trol)50
+b(.)41 b(.)h(.)f(.)h(.)f(.)h(.)f(.)h(.)g(.)f(.)h(.)f(.)h(.)f(.)h(.)g(.)
+f(.)h(.)f(.)h(.)f(.)h(.)g(.)f(.)h(.)f(.)h(.)f(.)h(.)f(.)h(.)g(.)f(.)h
+(.)f(.)h(.)f(.)h(.)93 b(24)315 7440 y(3.5.1)h(RequestWindo)n(w)77
+b(.)41 b(.)h(.)f(.)h(.)f(.)h(.)f(.)h(.)g(.)f(.)h(.)f(.)h(.)f(.)h(.)g(.)
+f(.)h(.)f(.)h(.)f(.)h(.)g(.)f(.)h(.)f(.)h(.)f(.)h(.)f(.)h(.)g(.)f(.)h
+(.)f(.)h(.)f(.)h(.)93 b(24)315 7596 y(3.5.2)h(Mo)r(difyWindo)n(w)44
+b(.)e(.)f(.)h(.)f(.)h(.)f(.)h(.)f(.)h(.)g(.)f(.)h(.)f(.)h(.)f(.)h(.)g
+(.)f(.)h(.)f(.)h(.)f(.)h(.)g(.)f(.)h(.)f(.)h(.)f(.)h(.)f(.)h(.)g(.)f(.)
+h(.)f(.)h(.)f(.)h(.)93 b(25)315 7753 y(3.5.3)h(ReleaseWindo)n(w)32
+b(.)42 b(.)f(.)h(.)f(.)h(.)f(.)h(.)f(.)h(.)g(.)f(.)h(.)f(.)h(.)f(.)h(.)
+g(.)f(.)h(.)f(.)h(.)f(.)h(.)g(.)f(.)h(.)f(.)h(.)f(.)h(.)f(.)h(.)g(.)f
+(.)h(.)f(.)h(.)f(.)h(.)93 b(26)315 7909 y(3.5.4)h(GetFirstWindo)n(w,)28
+b(GetNextWindo)n(w)43 b(.)f(.)f(.)h(.)f(.)h(.)g(.)f(.)h(.)f(.)h(.)f(.)h
+(.)g(.)f(.)h(.)f(.)h(.)f(.)h(.)f(.)h(.)g(.)f(.)h(.)f(.)h(.)f(.)h(.)93
+b(26)315 8066 y(3.5.5)h(MapMemP)n(age,)27 b(GetMemP)n(age)56
+b(.)42 b(.)g(.)f(.)h(.)f(.)h(.)f(.)h(.)g(.)f(.)h(.)f(.)h(.)f(.)h(.)g(.)
+f(.)h(.)f(.)h(.)f(.)h(.)f(.)h(.)g(.)f(.)h(.)f(.)h(.)f(.)h(.)93
+b(26)125 8222 y(3.6)83 b(Bulk)28 b(Memory)e(Services)51
+b(.)42 b(.)f(.)h(.)f(.)h(.)f(.)h(.)f(.)h(.)g(.)f(.)h(.)f(.)h(.)f(.)h(.)
+g(.)f(.)h(.)f(.)h(.)f(.)h(.)g(.)f(.)h(.)f(.)h(.)f(.)h(.)f(.)h(.)g(.)f
+(.)h(.)f(.)h(.)f(.)h(.)93 b(27)p eop
+%%Page: 2 2
+2 1 bop 0 -167 3900 5 v 0 -200 a Ff(CONTENTS)3319 b Fm(2)315
+162 y(3.6.1)94 b(RegisterMTD)40 b(.)i(.)g(.)f(.)h(.)f(.)h(.)f(.)h(.)f
+(.)h(.)g(.)f(.)h(.)f(.)h(.)f(.)h(.)g(.)f(.)h(.)f(.)h(.)f(.)h(.)g(.)f(.)
+h(.)f(.)h(.)f(.)h(.)f(.)h(.)g(.)f(.)h(.)f(.)h(.)f(.)h(.)93
+b(27)315 318 y(3.6.2)h(GetFirstRegion,)27 b(GetNextRegion)78
+b(.)41 b(.)h(.)f(.)h(.)f(.)h(.)g(.)f(.)h(.)f(.)h(.)f(.)h(.)g(.)f(.)h(.)
+f(.)h(.)f(.)h(.)f(.)h(.)g(.)f(.)h(.)f(.)h(.)f(.)h(.)93
+b(28)315 475 y(3.6.3)h(Op)r(enMemory)40 b(.)i(.)g(.)f(.)h(.)f(.)h(.)f
+(.)h(.)f(.)h(.)g(.)f(.)h(.)f(.)h(.)f(.)h(.)g(.)f(.)h(.)f(.)h(.)f(.)h(.)
+g(.)f(.)h(.)f(.)h(.)f(.)h(.)f(.)h(.)g(.)f(.)h(.)f(.)h(.)f(.)h(.)93
+b(29)315 631 y(3.6.4)h(CloseMemory)41 b(.)h(.)g(.)f(.)h(.)f(.)h(.)f(.)h
+(.)f(.)h(.)g(.)f(.)h(.)f(.)h(.)f(.)h(.)g(.)f(.)h(.)f(.)h(.)f(.)h(.)g(.)
+f(.)h(.)f(.)h(.)f(.)h(.)f(.)h(.)g(.)f(.)h(.)f(.)h(.)f(.)h(.)93
+b(29)315 788 y(3.6.5)h(ReadMemory)-7 b(,)26 b(W)-7 b(riteMemory)21
+b(.)41 b(.)h(.)g(.)f(.)h(.)f(.)h(.)f(.)h(.)g(.)f(.)h(.)f(.)h(.)f(.)h(.)
+g(.)f(.)h(.)f(.)h(.)f(.)h(.)f(.)h(.)g(.)f(.)h(.)f(.)h(.)f(.)h(.)93
+b(30)315 944 y(3.6.6)h(RegisterEraseQueue)66 b(.)41 b(.)h(.)f(.)h(.)f
+(.)h(.)g(.)f(.)h(.)f(.)h(.)f(.)h(.)g(.)f(.)h(.)f(.)h(.)f(.)h(.)g(.)f(.)
+h(.)f(.)h(.)f(.)h(.)f(.)h(.)g(.)f(.)h(.)f(.)h(.)f(.)h(.)93
+b(30)315 1101 y(3.6.7)h(DeregisterEraseQueue)58 b(.)42
+b(.)f(.)h(.)f(.)h(.)g(.)f(.)h(.)f(.)h(.)f(.)h(.)g(.)f(.)h(.)f(.)h(.)f
+(.)h(.)g(.)f(.)h(.)f(.)h(.)f(.)h(.)f(.)h(.)g(.)f(.)h(.)f(.)h(.)f(.)h(.)
+93 b(32)315 1257 y(3.6.8)h(Chec)n(kEraseQueue)77 b(.)42
+b(.)f(.)h(.)f(.)h(.)f(.)h(.)g(.)f(.)h(.)f(.)h(.)f(.)h(.)g(.)f(.)h(.)f
+(.)h(.)f(.)h(.)g(.)f(.)h(.)f(.)h(.)f(.)h(.)f(.)h(.)g(.)f(.)h(.)f(.)h(.)
+f(.)h(.)93 b(32)125 1413 y(3.7)83 b(Miscellaneous)27
+b(calls)56 b(.)41 b(.)h(.)g(.)f(.)h(.)f(.)h(.)f(.)h(.)f(.)h(.)g(.)f(.)h
+(.)f(.)h(.)f(.)h(.)g(.)f(.)h(.)f(.)h(.)f(.)h(.)g(.)f(.)h(.)f(.)h(.)f(.)
+h(.)f(.)h(.)g(.)f(.)h(.)f(.)h(.)f(.)h(.)93 b(32)315 1570
+y(3.7.1)h(GetCardServicesInfo)48 b(.)41 b(.)h(.)f(.)h(.)f(.)h(.)g(.)f
+(.)h(.)f(.)h(.)f(.)h(.)g(.)f(.)h(.)f(.)h(.)f(.)h(.)g(.)f(.)h(.)f(.)h(.)
+f(.)h(.)f(.)h(.)g(.)f(.)h(.)f(.)h(.)f(.)h(.)93 b(32)315
+1726 y(3.7.2)h(A)n(ccessCon\034gurationRegister)19 b(.)41
+b(.)h(.)g(.)f(.)h(.)f(.)h(.)f(.)h(.)g(.)f(.)h(.)f(.)h(.)f(.)h(.)g(.)f
+(.)h(.)f(.)h(.)f(.)h(.)f(.)h(.)g(.)f(.)h(.)f(.)h(.)f(.)h(.)93
+b(33)315 1883 y(3.7.3)h(A)n(djustResourceInfo)20 b(.)42
+b(.)f(.)h(.)f(.)h(.)f(.)h(.)g(.)f(.)h(.)f(.)h(.)f(.)h(.)g(.)f(.)h(.)f
+(.)h(.)f(.)h(.)g(.)f(.)h(.)f(.)h(.)f(.)h(.)f(.)h(.)g(.)f(.)h(.)f(.)h(.)
+f(.)h(.)93 b(34)315 2039 y(3.7.4)h(Rep)r(ortError)23
+b(.)41 b(.)h(.)g(.)f(.)h(.)f(.)h(.)f(.)h(.)f(.)h(.)g(.)f(.)h(.)f(.)h(.)
+f(.)h(.)g(.)f(.)h(.)f(.)h(.)f(.)h(.)g(.)f(.)h(.)f(.)h(.)f(.)h(.)f(.)h
+(.)g(.)f(.)h(.)f(.)h(.)f(.)h(.)93 b(36)0 2279 y Ff(4)77
+b(Card)32 b(Information)f(Structure)i(De\034nitions)2030
+b(36)125 2435 y Fm(4.1)83 b(CIS)28 b(T)-7 b(uple)28 b(De\034nitions)80
+b(.)42 b(.)f(.)h(.)f(.)h(.)f(.)h(.)f(.)h(.)g(.)f(.)h(.)f(.)h(.)f(.)h(.)
+g(.)f(.)h(.)f(.)h(.)f(.)h(.)g(.)f(.)h(.)f(.)h(.)f(.)h(.)f(.)h(.)g(.)f
+(.)h(.)f(.)h(.)f(.)h(.)93 b(36)315 2592 y(4.1.1)h(CISTPL_CHECKSUM)69
+b(.)41 b(.)h(.)f(.)h(.)g(.)f(.)h(.)f(.)h(.)f(.)h(.)g(.)f(.)h(.)f(.)h(.)
+f(.)h(.)g(.)f(.)h(.)f(.)h(.)f(.)h(.)f(.)h(.)g(.)f(.)h(.)f(.)h(.)f(.)h
+(.)93 b(37)315 2748 y(4.1.2)h(CISTPL_LONGLINK_A,)105
+b(CISTPL_LONGLINK_C,)f(CISTPL_LINKT)-7 b(AR)n(GET,)581
+2862 y(CISTPL_NOLINK)26 b(.)42 b(.)f(.)h(.)f(.)h(.)f(.)h(.)g(.)f(.)h(.)
+f(.)h(.)f(.)h(.)g(.)f(.)h(.)f(.)h(.)f(.)h(.)g(.)f(.)h(.)f(.)h(.)f(.)h
+(.)f(.)h(.)g(.)f(.)h(.)f(.)h(.)f(.)h(.)93 b(37)315 3018
+y(4.1.3)h(CISTPL_LONGLINK_MF)n(C)43 b(.)f(.)g(.)f(.)h(.)f(.)h(.)f(.)h
+(.)g(.)f(.)h(.)f(.)h(.)f(.)h(.)g(.)f(.)h(.)f(.)h(.)f(.)h(.)f(.)h(.)g(.)
+f(.)h(.)f(.)h(.)f(.)h(.)93 b(37)315 3175 y(4.1.4)h(CISTPL_DEVICE,)29
+b(CISTPL_DEVICE_A)64 b(.)42 b(.)f(.)h(.)f(.)h(.)f(.)h(.)g(.)f(.)h(.)f
+(.)h(.)f(.)h(.)f(.)h(.)g(.)f(.)h(.)f(.)h(.)f(.)h(.)93
+b(37)315 3331 y(4.1.5)h(CISTPL_VERS_1)30 b(.)42 b(.)f(.)h(.)f(.)h(.)f
+(.)h(.)g(.)f(.)h(.)f(.)h(.)f(.)h(.)g(.)f(.)h(.)f(.)h(.)f(.)h(.)g(.)f(.)
+h(.)f(.)h(.)f(.)h(.)f(.)h(.)g(.)f(.)h(.)f(.)h(.)f(.)h(.)93
+b(39)315 3488 y(4.1.6)h(CISTPL_AL)-7 b(TSTR)28 b(.)42
+b(.)f(.)h(.)f(.)h(.)f(.)h(.)g(.)f(.)h(.)f(.)h(.)f(.)h(.)g(.)f(.)h(.)f
+(.)h(.)f(.)h(.)g(.)f(.)h(.)f(.)h(.)f(.)h(.)f(.)h(.)g(.)f(.)h(.)f(.)h(.)
+f(.)h(.)93 b(39)315 3644 y(4.1.7)h(CISTPL_JEDEC_C,)28
+b(CISTPL_JEDEC_A)38 b(.)k(.)f(.)h(.)f(.)h(.)f(.)h(.)g(.)f(.)h(.)f(.)h
+(.)f(.)h(.)f(.)h(.)g(.)f(.)h(.)f(.)h(.)f(.)h(.)93 b(39)315
+3801 y(4.1.8)h(CISTPL_CONFIG,)28 b(CISTPL_CONFIG_CB)55
+b(.)41 b(.)h(.)f(.)h(.)f(.)h(.)g(.)f(.)h(.)f(.)h(.)f(.)h(.)f(.)h(.)g(.)
+f(.)h(.)f(.)h(.)f(.)h(.)93 b(39)315 3957 y(4.1.9)h(CISTPL_BAR)51
+b(.)42 b(.)f(.)h(.)f(.)h(.)f(.)h(.)f(.)h(.)g(.)f(.)h(.)f(.)h(.)f(.)h(.)
+g(.)f(.)h(.)f(.)h(.)f(.)h(.)g(.)f(.)h(.)f(.)h(.)f(.)h(.)f(.)h(.)g(.)f
+(.)h(.)f(.)h(.)f(.)h(.)93 b(40)315 4114 y(4.1.10)52 b(CISTPL_CFT)-7
+b(ABLE_ENTR)g(Y)59 b(.)42 b(.)f(.)h(.)f(.)h(.)f(.)h(.)g(.)f(.)h(.)f(.)h
+(.)f(.)h(.)g(.)f(.)h(.)f(.)h(.)f(.)h(.)f(.)h(.)g(.)f(.)h(.)f(.)h(.)f(.)
+h(.)93 b(40)315 4270 y(4.1.11)52 b(CISTPL_CFT)-7 b(ABLE_ENTR)g(Y_CB)69
+b(.)41 b(.)h(.)f(.)h(.)g(.)f(.)h(.)f(.)h(.)f(.)h(.)g(.)f(.)h(.)f(.)h(.)
+f(.)h(.)f(.)h(.)g(.)f(.)h(.)f(.)h(.)f(.)h(.)93 b(44)315
+4426 y(4.1.12)52 b(CISTPL_MANFID)80 b(.)41 b(.)h(.)f(.)h(.)f(.)h(.)g(.)
+f(.)h(.)f(.)h(.)f(.)h(.)g(.)f(.)h(.)f(.)h(.)f(.)h(.)g(.)f(.)h(.)f(.)h
+(.)f(.)h(.)f(.)h(.)g(.)f(.)h(.)f(.)h(.)f(.)h(.)93 b(44)315
+4583 y(4.1.13)52 b(CISTPL_FUNCID)31 b(.)42 b(.)f(.)h(.)f(.)h(.)f(.)h(.)
+g(.)f(.)h(.)f(.)h(.)f(.)h(.)g(.)f(.)h(.)f(.)h(.)f(.)h(.)g(.)f(.)h(.)f
+(.)h(.)f(.)h(.)f(.)h(.)g(.)f(.)h(.)f(.)h(.)f(.)h(.)93
+b(44)315 4739 y(4.1.14)52 b(CISTPL_DEVICE_GEO)42 b(.)g(.)f(.)h(.)g(.)f
+(.)h(.)f(.)h(.)f(.)h(.)g(.)f(.)h(.)f(.)h(.)f(.)h(.)g(.)f(.)h(.)f(.)h(.)
+f(.)h(.)f(.)h(.)g(.)f(.)h(.)f(.)h(.)f(.)h(.)93 b(45)315
+4896 y(4.1.15)52 b(CISTPL_VERS_2)30 b(.)42 b(.)f(.)h(.)f(.)h(.)f(.)h(.)
+g(.)f(.)h(.)f(.)h(.)f(.)h(.)g(.)f(.)h(.)f(.)h(.)f(.)h(.)g(.)f(.)h(.)f
+(.)h(.)f(.)h(.)f(.)h(.)g(.)f(.)h(.)f(.)h(.)f(.)h(.)93
+b(46)315 5052 y(4.1.16)52 b(CISTPL_OR)n(G)44 b(.)e(.)f(.)h(.)f(.)h(.)f
+(.)h(.)f(.)h(.)g(.)f(.)h(.)f(.)h(.)f(.)h(.)g(.)f(.)h(.)f(.)h(.)f(.)h(.)
+g(.)f(.)h(.)f(.)h(.)f(.)h(.)f(.)h(.)g(.)f(.)h(.)f(.)h(.)f(.)h(.)93
+b(46)125 5209 y(4.2)83 b(CIS)28 b(con\034guration)e(register)g
+(de\034nitions)47 b(.)42 b(.)g(.)f(.)h(.)f(.)h(.)f(.)h(.)g(.)f(.)h(.)f
+(.)h(.)f(.)h(.)g(.)f(.)h(.)f(.)h(.)f(.)h(.)f(.)h(.)g(.)f(.)h(.)f(.)h(.)
+f(.)h(.)93 b(46)315 5365 y(4.2.1)h(Con\034guration)26
+b(Option)h(Register)78 b(.)42 b(.)f(.)h(.)f(.)h(.)f(.)h(.)g(.)f(.)h(.)f
+(.)h(.)f(.)h(.)g(.)f(.)h(.)f(.)h(.)f(.)h(.)f(.)h(.)g(.)f(.)h(.)f(.)h(.)
+f(.)h(.)93 b(47)p eop
+%%Page: 3 3
+3 2 bop 0 -167 3900 5 v 0 -200 a Ff(CONTENTS)3319 b Fm(3)315
+162 y(4.2.2)94 b(Card)27 b(Con\034guration)f(and)h(Status)h(Register)54
+b(.)41 b(.)h(.)g(.)f(.)h(.)f(.)h(.)f(.)h(.)g(.)f(.)h(.)f(.)h(.)f(.)h(.)
+f(.)h(.)g(.)f(.)h(.)f(.)h(.)f(.)h(.)93 b(47)315 318 y(4.2.3)h(Pin)28
+b(Replacemen)n(t)g(Register)45 b(.)d(.)f(.)h(.)g(.)f(.)h(.)f(.)h(.)f(.)
+h(.)g(.)f(.)h(.)f(.)h(.)f(.)h(.)g(.)f(.)h(.)f(.)h(.)f(.)h(.)f(.)h(.)g
+(.)f(.)h(.)f(.)h(.)f(.)h(.)93 b(48)315 475 y(4.2.4)h(So)r(c)n(k)n(et)27
+b(and)g(Cop)n(y)g(Register)50 b(.)42 b(.)f(.)h(.)g(.)f(.)h(.)f(.)h(.)f
+(.)h(.)g(.)f(.)h(.)f(.)h(.)f(.)h(.)g(.)f(.)h(.)f(.)h(.)f(.)h(.)f(.)h(.)
+g(.)f(.)h(.)f(.)h(.)f(.)h(.)93 b(48)315 631 y(4.2.5)h(Extended)28
+b(Status)g(Register)60 b(.)42 b(.)f(.)h(.)g(.)f(.)h(.)f(.)h(.)f(.)h(.)g
+(.)f(.)h(.)f(.)h(.)f(.)h(.)g(.)f(.)h(.)f(.)h(.)f(.)h(.)f(.)h(.)g(.)f(.)
+h(.)f(.)h(.)f(.)h(.)93 b(49)315 788 y(4.2.6)h(IO)27 b(Base)g(and)g
+(Size)h(Registers)71 b(.)41 b(.)h(.)g(.)f(.)h(.)f(.)h(.)f(.)h(.)g(.)f
+(.)h(.)f(.)h(.)f(.)h(.)g(.)f(.)h(.)f(.)h(.)f(.)h(.)f(.)h(.)g(.)f(.)h(.)
+f(.)h(.)f(.)h(.)93 b(49)0 1027 y Ff(5)77 b(Card)32 b(Services)g(Ev)m
+(en)m(t)g(Handling)2417 b(49)125 1184 y Fm(5.1)83 b(Ev)n(en)n(t)28
+b(handler)f(op)r(erations)80 b(.)42 b(.)f(.)h(.)f(.)h(.)f(.)h(.)g(.)f
+(.)h(.)f(.)h(.)f(.)h(.)g(.)f(.)h(.)f(.)h(.)f(.)h(.)g(.)f(.)h(.)f(.)h(.)
+f(.)h(.)f(.)h(.)g(.)f(.)h(.)f(.)h(.)f(.)h(.)93 b(49)125
+1340 y(5.2)83 b(Ev)n(en)n(t)28 b(descriptions)69 b(.)41
+b(.)h(.)g(.)f(.)h(.)f(.)h(.)f(.)h(.)f(.)h(.)g(.)f(.)h(.)f(.)h(.)f(.)h
+(.)g(.)f(.)h(.)f(.)h(.)f(.)h(.)g(.)f(.)h(.)f(.)h(.)f(.)h(.)f(.)h(.)g(.)
+f(.)h(.)f(.)h(.)f(.)h(.)93 b(50)125 1496 y(5.3)83 b(Clien)n(t)28
+b(driv)n(er)e(ev)n(en)n(t)h(handling)h(resp)r(onsibilities)60
+b(.)41 b(.)h(.)f(.)h(.)g(.)f(.)h(.)f(.)h(.)f(.)h(.)g(.)f(.)h(.)f(.)h(.)
+f(.)h(.)f(.)h(.)g(.)f(.)h(.)f(.)h(.)f(.)h(.)93 b(51)0
+1736 y Ff(6)77 b(Memory)30 b(T)-8 b(ec)m(hnology)32 b(Driv)m(ers)2490
+b(51)125 1892 y Fm(6.1)83 b(MTD)29 b(request)d(handling)38
+b(.)k(.)f(.)h(.)f(.)h(.)f(.)h(.)f(.)h(.)g(.)f(.)h(.)f(.)h(.)f(.)h(.)g
+(.)f(.)h(.)f(.)h(.)f(.)h(.)g(.)f(.)h(.)f(.)h(.)f(.)h(.)f(.)h(.)g(.)f(.)
+h(.)f(.)h(.)f(.)h(.)93 b(52)125 2049 y(6.2)83 b(MTD)29
+b(help)r(er)e(functions)59 b(.)42 b(.)f(.)h(.)f(.)h(.)f(.)h(.)f(.)h(.)g
+(.)f(.)h(.)f(.)h(.)f(.)h(.)g(.)f(.)h(.)f(.)h(.)f(.)h(.)g(.)f(.)h(.)f(.)
+h(.)f(.)h(.)f(.)h(.)g(.)f(.)h(.)f(.)h(.)f(.)h(.)93 b(53)315
+2205 y(6.2.1)h(MTDRequestWindo)n(w,)28 b(MTDReleaseWindo)n(w)e(.)42
+b(.)f(.)h(.)f(.)h(.)f(.)h(.)g(.)f(.)h(.)f(.)h(.)f(.)h(.)f(.)h(.)g(.)f
+(.)h(.)f(.)h(.)f(.)h(.)93 b(53)315 2362 y(6.2.2)h(MTDMo)r(difyWindo)n
+(w)39 b(.)i(.)h(.)f(.)h(.)f(.)h(.)g(.)f(.)h(.)f(.)h(.)f(.)h(.)g(.)f(.)h
+(.)f(.)h(.)f(.)h(.)g(.)f(.)h(.)f(.)h(.)f(.)h(.)f(.)h(.)g(.)f(.)h(.)f(.)
+h(.)f(.)h(.)93 b(53)315 2518 y(6.2.3)h(MTDSetV)-7 b(pp)76
+b(.)42 b(.)g(.)f(.)h(.)f(.)h(.)f(.)h(.)f(.)h(.)g(.)f(.)h(.)f(.)h(.)f(.)
+h(.)g(.)f(.)h(.)f(.)h(.)f(.)h(.)g(.)f(.)h(.)f(.)h(.)f(.)h(.)f(.)h(.)g
+(.)f(.)h(.)f(.)h(.)f(.)h(.)93 b(54)315 2675 y(6.2.4)h(MTDRD)n(YMask)24
+b(.)42 b(.)f(.)h(.)f(.)h(.)f(.)h(.)f(.)h(.)g(.)f(.)h(.)f(.)h(.)f(.)h(.)
+g(.)f(.)h(.)f(.)h(.)f(.)h(.)g(.)f(.)h(.)f(.)h(.)f(.)h(.)f(.)h(.)g(.)f
+(.)h(.)f(.)h(.)f(.)h(.)93 b(54)0 2914 y Ff(7)77 b(Driv)m(er)32
+b(Services)g(In)m(terface)2643 b(55)125 3071 y Fm(7.1)83
+b(In)n(terface)27 b(to)h(other)f(clien)n(t)g(driv)n(ers)58
+b(.)41 b(.)h(.)f(.)h(.)g(.)f(.)h(.)f(.)h(.)f(.)h(.)g(.)f(.)h(.)f(.)h(.)
+f(.)h(.)g(.)f(.)h(.)f(.)h(.)f(.)h(.)f(.)h(.)g(.)f(.)h(.)f(.)h(.)f(.)h
+(.)93 b(55)315 3227 y(7.1.1)h(The)28 b(dev_link_t)f(structure)37
+b(.)42 b(.)f(.)h(.)g(.)f(.)h(.)f(.)h(.)f(.)h(.)g(.)f(.)h(.)f(.)h(.)f(.)
+h(.)g(.)f(.)h(.)f(.)h(.)f(.)h(.)f(.)h(.)g(.)f(.)h(.)f(.)h(.)f(.)h(.)93
+b(55)315 3384 y(7.1.2)h(register_p)r(ccard_driv)n(er)68
+b(.)41 b(.)h(.)f(.)h(.)g(.)f(.)h(.)f(.)h(.)f(.)h(.)g(.)f(.)h(.)f(.)h(.)
+f(.)h(.)g(.)f(.)h(.)f(.)h(.)f(.)h(.)f(.)h(.)g(.)f(.)h(.)f(.)h(.)f(.)h
+(.)93 b(57)315 3540 y(7.1.3)h(unregister_p)r(ccard_driv)n(er)40
+b(.)i(.)f(.)h(.)g(.)f(.)h(.)f(.)h(.)f(.)h(.)g(.)f(.)h(.)f(.)h(.)f(.)h
+(.)g(.)f(.)h(.)f(.)h(.)f(.)h(.)f(.)h(.)g(.)f(.)h(.)f(.)h(.)f(.)h(.)93
+b(57)125 3697 y(7.2)83 b(The)28 b(CardBus)e(clien)n(t)i(in)n(terface)76
+b(.)42 b(.)f(.)h(.)f(.)h(.)g(.)f(.)h(.)f(.)h(.)f(.)h(.)g(.)f(.)h(.)f(.)
+h(.)f(.)h(.)g(.)f(.)h(.)f(.)h(.)f(.)h(.)f(.)h(.)g(.)f(.)h(.)f(.)h(.)f
+(.)h(.)93 b(57)315 3853 y(7.2.1)h(register_driv)n(er)53
+b(.)42 b(.)f(.)h(.)f(.)h(.)f(.)h(.)f(.)h(.)g(.)f(.)h(.)f(.)h(.)f(.)h(.)
+g(.)f(.)h(.)f(.)h(.)f(.)h(.)g(.)f(.)h(.)f(.)h(.)f(.)h(.)f(.)h(.)g(.)f
+(.)h(.)f(.)h(.)f(.)h(.)93 b(57)315 4009 y(7.2.2)h(unregister_driv)n(er)
+26 b(.)41 b(.)h(.)f(.)h(.)f(.)h(.)f(.)h(.)g(.)f(.)h(.)f(.)h(.)f(.)h(.)g
+(.)f(.)h(.)f(.)h(.)f(.)h(.)g(.)f(.)h(.)f(.)h(.)f(.)h(.)f(.)h(.)g(.)f(.)
+h(.)f(.)h(.)f(.)h(.)93 b(58)315 4166 y(7.2.3)h(The)28
+b(driv)n(er_op)r(erations)c(en)n(try)j(p)r(oin)n(ts)21
+b(.)42 b(.)f(.)h(.)f(.)h(.)g(.)f(.)h(.)f(.)h(.)f(.)h(.)g(.)f(.)h(.)f(.)
+h(.)f(.)h(.)f(.)h(.)g(.)f(.)h(.)f(.)h(.)f(.)h(.)93 b(58)125
+4322 y(7.3)83 b(In)n(terface)27 b(to)h(user)f(mo)r(de)g(utilities)74
+b(.)41 b(.)h(.)f(.)h(.)g(.)f(.)h(.)f(.)h(.)f(.)h(.)g(.)f(.)h(.)f(.)h(.)
+f(.)h(.)g(.)f(.)h(.)f(.)h(.)f(.)h(.)f(.)h(.)g(.)f(.)h(.)f(.)h(.)f(.)h
+(.)93 b(58)315 4479 y(7.3.1)h(Card)27 b(Services)f(ev)n(en)n(t)h
+(noti\034cations)61 b(.)41 b(.)h(.)f(.)h(.)f(.)h(.)g(.)f(.)h(.)f(.)h(.)
+f(.)h(.)g(.)f(.)h(.)f(.)h(.)f(.)h(.)f(.)h(.)g(.)f(.)h(.)f(.)h(.)f(.)h
+(.)93 b(59)315 4635 y(7.3.2)h(Io)r(ctl)28 b(descriptions)42
+b(.)f(.)h(.)f(.)h(.)f(.)h(.)f(.)h(.)g(.)f(.)h(.)f(.)h(.)f(.)h(.)g(.)f
+(.)h(.)f(.)h(.)f(.)h(.)g(.)f(.)h(.)f(.)h(.)f(.)h(.)f(.)h(.)g(.)f(.)h(.)
+f(.)h(.)f(.)h(.)93 b(59)0 4875 y Ff(8)77 b(Anatom)m(y)31
+b(of)h(a)g(Card)g(Services)g(Clien)m(t)f(Driv)m(er)1916
+b(61)125 5031 y Fm(8.1)83 b(Mo)r(dule)28 b(initialization)f(and)h
+(clean)n(up)34 b(.)42 b(.)f(.)h(.)g(.)f(.)h(.)f(.)h(.)f(.)h(.)g(.)f(.)h
+(.)f(.)h(.)f(.)h(.)g(.)f(.)h(.)f(.)h(.)f(.)h(.)f(.)h(.)g(.)f(.)h(.)f(.)
+h(.)f(.)h(.)93 b(61)125 5188 y(8.2)83 b(The)28 b(*_attac)n(h\(\))f(and)
+g(*_detac)n(h\(\))g(functions)53 b(.)42 b(.)f(.)h(.)f(.)h(.)g(.)f(.)h
+(.)f(.)h(.)f(.)h(.)g(.)f(.)h(.)f(.)h(.)f(.)h(.)f(.)h(.)g(.)f(.)h(.)f(.)
+h(.)f(.)h(.)93 b(62)125 5344 y(8.3)83 b(The)28 b(*_con\034g\(\))e(and)i
+(*_release\(\))e(functions)66 b(.)42 b(.)f(.)h(.)f(.)h(.)g(.)f(.)h(.)f
+(.)h(.)f(.)h(.)g(.)f(.)h(.)f(.)h(.)f(.)h(.)f(.)h(.)g(.)f(.)h(.)f(.)h(.)
+f(.)h(.)93 b(62)p eop
+%%Page: 4 4
+4 3 bop 0 -167 3900 5 v 0 -200 a Ff(1.)73 b(In)m(tro)s(duction)3184
+b Fm(4)125 162 y(8.4)83 b(The)28 b(clien)n(t)g(ev)n(en)n(t)f(handler)46
+b(.)41 b(.)h(.)f(.)h(.)f(.)h(.)f(.)h(.)g(.)f(.)h(.)f(.)h(.)f(.)h(.)g(.)
+f(.)h(.)f(.)h(.)f(.)h(.)g(.)f(.)h(.)f(.)h(.)f(.)h(.)f(.)h(.)g(.)f(.)h
+(.)f(.)h(.)f(.)h(.)93 b(62)125 318 y(8.5)83 b(Lo)r(c)n(king)27
+b(and)g(sync)n(hronization)f(issues)45 b(.)c(.)h(.)g(.)f(.)h(.)f(.)h(.)
+f(.)h(.)g(.)f(.)h(.)f(.)h(.)f(.)h(.)g(.)f(.)h(.)f(.)h(.)f(.)h(.)f(.)h
+(.)g(.)f(.)h(.)f(.)h(.)f(.)h(.)93 b(62)125 475 y(8.6)83
+b(Using)28 b(existing)f(Lin)n(ux)g(driv)n(ers)f(to)i(access)e(PC)i
+(Card)f(devices)d(.)42 b(.)f(.)h(.)f(.)h(.)g(.)f(.)h(.)f(.)h(.)f(.)h(.)
+f(.)h(.)g(.)f(.)h(.)f(.)h(.)f(.)h(.)93 b(63)0 714 y Ff(9)77
+b(The)31 b(So)s(c)m(k)m(et)i(Driv)m(er)g(La)m(y)m(er)2650
+b(63)125 871 y Fm(9.1)83 b(Card)27 b(Services)g(en)n(try)g(p)r(oin)n
+(ts)g(for)g(so)r(c)n(k)n(et)g(driv)n(ers)h(.)41 b(.)h(.)f(.)h(.)g(.)f
+(.)h(.)f(.)h(.)f(.)h(.)g(.)f(.)h(.)f(.)h(.)f(.)h(.)f(.)h(.)g(.)f(.)h(.)
+f(.)h(.)f(.)h(.)93 b(64)125 1027 y(9.2)83 b(Services)27
+b(pro)n(vided)f(b)n(y)i(the)g(so)r(c)n(k)n(et)e(driv)n(er)69
+b(.)42 b(.)f(.)h(.)f(.)h(.)f(.)h(.)g(.)f(.)h(.)f(.)h(.)f(.)h(.)g(.)f(.)
+h(.)f(.)h(.)f(.)h(.)f(.)h(.)g(.)f(.)h(.)f(.)h(.)f(.)h(.)93
+b(64)315 1184 y(9.2.1)h(SS_InquireSo)r(c)n(k)n(et)79
+b(.)42 b(.)f(.)h(.)f(.)h(.)f(.)h(.)g(.)f(.)h(.)f(.)h(.)f(.)h(.)g(.)f(.)
+h(.)f(.)h(.)f(.)h(.)g(.)f(.)h(.)f(.)h(.)f(.)h(.)f(.)h(.)g(.)f(.)h(.)f
+(.)h(.)f(.)h(.)93 b(64)315 1340 y(9.2.2)h(SS_RegisterCallbac)n(k)26
+b(.)41 b(.)h(.)f(.)h(.)f(.)h(.)g(.)f(.)h(.)f(.)h(.)f(.)h(.)g(.)f(.)h(.)
+f(.)h(.)f(.)h(.)g(.)f(.)h(.)f(.)h(.)f(.)h(.)f(.)h(.)g(.)f(.)h(.)f(.)h
+(.)f(.)h(.)93 b(65)315 1496 y(9.2.3)h(SS_GetStatus)80
+b(.)42 b(.)f(.)h(.)f(.)h(.)f(.)h(.)f(.)h(.)g(.)f(.)h(.)f(.)h(.)f(.)h(.)
+g(.)f(.)h(.)f(.)h(.)f(.)h(.)g(.)f(.)h(.)f(.)h(.)f(.)h(.)f(.)h(.)g(.)f
+(.)h(.)f(.)h(.)f(.)h(.)93 b(66)315 1653 y(9.2.4)h(SS_GetSo)r(c)n(k)n
+(et,)27 b(SS_SetSo)r(c)n(k)n(et)33 b(.)42 b(.)g(.)f(.)h(.)f(.)h(.)f(.)h
+(.)g(.)f(.)h(.)f(.)h(.)f(.)h(.)g(.)f(.)h(.)f(.)h(.)f(.)h(.)f(.)h(.)g(.)
+f(.)h(.)f(.)h(.)f(.)h(.)93 b(66)315 1809 y(9.2.5)h(SS_GetIOMap,)27
+b(SS_SetIOMap)52 b(.)42 b(.)f(.)h(.)f(.)h(.)f(.)h(.)g(.)f(.)h(.)f(.)h
+(.)f(.)h(.)g(.)f(.)h(.)f(.)h(.)f(.)h(.)f(.)h(.)g(.)f(.)h(.)f(.)h(.)f(.)
+h(.)93 b(68)315 1966 y(9.2.6)h(SS_GetMemMap,)28 b(SS_SetMemMap)71
+b(.)41 b(.)h(.)f(.)h(.)g(.)f(.)h(.)f(.)h(.)f(.)h(.)g(.)f(.)h(.)f(.)h(.)
+f(.)h(.)f(.)h(.)g(.)f(.)h(.)f(.)h(.)f(.)h(.)93 b(68)315
+2122 y(9.2.7)h(SS_GetBridge,)27 b(SS_SetBridge)e(.)42
+b(.)g(.)f(.)h(.)f(.)h(.)f(.)h(.)g(.)f(.)h(.)f(.)h(.)f(.)h(.)g(.)f(.)h
+(.)f(.)h(.)f(.)h(.)f(.)h(.)g(.)f(.)h(.)f(.)h(.)f(.)h(.)93
+b(69)315 2279 y(9.2.8)h(SS_Pro)r(cSetup)68 b(.)42 b(.)f(.)h(.)f(.)h(.)f
+(.)h(.)f(.)h(.)g(.)f(.)h(.)f(.)h(.)f(.)h(.)g(.)f(.)h(.)f(.)h(.)f(.)h(.)
+g(.)f(.)h(.)f(.)h(.)f(.)h(.)f(.)h(.)g(.)f(.)h(.)f(.)h(.)f(.)h(.)93
+b(70)125 2435 y(9.3)83 b(Supp)r(orting)28 b(un)n(usual)f(so)r(c)n(k)n
+(et)f(arc)n(hitectures)60 b(.)41 b(.)h(.)f(.)h(.)f(.)h(.)g(.)f(.)h(.)f
+(.)h(.)f(.)h(.)g(.)f(.)h(.)f(.)h(.)f(.)h(.)f(.)h(.)g(.)f(.)h(.)f(.)h(.)
+f(.)h(.)93 b(70)0 2675 y Ff(10)29 b(Where)i(to)h(Go)f(for)h(More)f
+(Information)2201 b(71)0 3013 y Fg(1)131 b(In)l(tro)t(duction)0
+3252 y Fm(The)30 b(Lin)n(ux)g(k)n(ernel)f(PCMCIA)h(system)g(has)g
+(three)f(main)h(comp)r(onen)n(ts.)44 b(A)n(t)30 b(the)g(lo)n(w)n(est)f
+(lev)n(el)g(are)g(the)i(so)r(c)n(k)n(et)e(driv)n(ers.)0
+3365 y(Next)c(is)f(the)g(Card)g(Services)f(mo)r(dule.)36
+b(Driv)n(ers)23 b(for)g(sp)r(eci\034c)i(cards)e(are)g(la)n(y)n(ered)f
+(on)i(top)g(of)h(Card)e(Services.)35 b(One)23 b(sp)r(ecial)0
+3479 y(Card)e(Services)h(clien)n(t,)h(called)f(Driv)n(er)f(Services,)i
+(pro)n(vides)d(a)i(link)h(b)r(et)n(w)n(eek)e(user)h(lev)n(el)g(utilit)n
+(y)g(programs)e(and)i(the)h(k)n(ernel)0 3592 y(facilities.)0
+3749 y(The)32 b(so)r(c)n(k)n(et)e(driv)n(er)g(la)n(y)n(er)g(is)i(lo)r
+(osely)e(based)h(on)h(the)g(So)r(c)n(k)n(et)f(Services)f(API.)j(There)e
+(are)f(t)n(w)n(o)h(so)r(c)n(k)n(et)g(driv)n(er)f(mo)r(dules.)0
+3862 y(The)g Fh(tcic)d Fm(mo)r(dule)j(supp)r(orts)f(the)h(Datab)r(o)r
+(ok)f(TCIC-2)f(family)i(of)g(host)f(con)n(trollers.)40
+b(The)30 b Fh(i82365)d Fm(mo)r(dule)j(supp)r(orts)0 3976
+y(the)24 b(In)n(tel)h(i82365sl)c(family)j(and)g(v)-5
+b(arious)23 b(In)n(tel-compatible)g(con)n(trollers,)g(including)h
+(Cirrus,)g(VLSI,)h(Ricoh,)f(and)g(V)-7 b(adem)0 4090
+y(c)n(hips.)40 b(In)29 b(addition,)g(the)g Fh(i82365)d
+Fm(mo)r(dule)j(implemen)n(ts)g(supp)r(ort)g(for)f(CardBus)f(con)n
+(trollers)g(that)i(follo)n(w)f(the)h(\020Y)-7 b(en)n(ta\021)0
+4203 y(register-lev)n(el)25 b(sp)r(eci\034cation.)0 4360
+y(Card)38 b(Services)g(is)h(the)g(largest)e(single)i(comp)r(onen)n(t)f
+(of)h(the)g(pac)n(k)-5 b(age.)69 b(It)39 b(pro)n(vides)f(an)g(API)i
+(somewhat)e(similar)g(to)0 4473 y(DOS)31 b(Card)e(Services,)h(adapted)g
+(to)h(a)f(Unix)g(en)n(vironmen)n(t.)45 b(The)30 b(Lin)n(ux)g(implemen)n
+(tation)h(w)n(as)e(based)h(in)h(part)f(on)g(the)0 4587
+y(Solaris)c(in)n(terface)h(sp)r(eci\034cation.)38 b(It)28
+b(is)f(implemen)n(ted)i(in)f(the)g Fh(pcmcia_core)23
+b Fm(mo)r(dule.)38 b(Most)28 b(v)n(ersion)e(2.1)h(features)g(are)0
+4700 y(implemen)n(ted,)h(with)g(some)f(PC)h(Card)f(95)g(features.)0
+4857 y(The)f(Driv)n(er)e(Services)h(la)n(y)n(er)e(implemen)n(ts)j(a)f
+(user)g(mo)r(de)h(pseudo-device)e(for)h(accessing)f(some)h(Card)f
+(Services)h(functions)0 4970 y(from)31 b(utilit)n(y)h(programs.)45
+b(It)32 b(is)f(resp)r(onsible)g(for)f(k)n(eeping)h(trac)n(k)f(of)h(all)
+g(clien)n(t)h(driv)n(ers,)e(and)i(for)e(matc)n(hing)h(up)h(driv)n(ers)0
+5084 y(with)c(ph)n(ysical)f(so)r(c)n(k)n(ets.)35 b(It)28
+b(is)g(implemen)n(ted)g(in)f(the)h Fh(ds)f Fm(mo)r(dule.)0
+5240 y(This)d(do)r(cumen)n(t)g(describ)r(es)g(the)g(k)n(ernel)f(in)n
+(terface)g(to)h(the)h(Card)e(Services)g(and)h(Driv)n(er)f(Services)g
+(mo)r(dules,)h(and)g(the)h(user)0 5354 y(in)n(terface)j(to)h(Driv)n(er)
+f(Services.)40 b(It)29 b(is)g(in)n(tended)g(for)f(use)h(b)n(y)g(clien)n
+(t)f(device)h(driv)n(er)f(dev)n(elop)r(ers.)39 b(The)29
+b(Lin)n(ux)g(PCMCIA-)p eop
+%%Page: 5 5
+5 4 bop 0 -167 3900 5 v 0 -200 a Ff(2.)73 b(Basic)32
+b(Concepts)3073 b Fm(5)0 162 y(HO)n(WTO)30 b(describ)r(es)f(ho)n(w)h
+(to)g(install)g(and)g(use)g(Lin)n(ux)g(PCMCIA)h(supp)r(ort.)45
+b(It)30 b(is)h(a)n(v)-5 b(ailable)28 b(from)i Fh(sourceforge.org)0
+275 y Fm(in)e Fh(/pcmcia)p Fm(.)0 566 y Fe(1.1)112 b(Cop)m(yrigh)m(t)36
+b(notice)h(and)h(disclaimer)0 776 y Fm(Cop)n(yrigh)n(t)26
+b(\(c\))i(1996,)e(1997)f(Da)n(vid)j(A.)g(Hinds)0 933
+y(This)20 b(do)r(cumen)n(t)h(ma)n(y)f(b)r(e)g(repro)r(duced)g(or)f
+(distributed)i(in)g(an)n(y)e(form)h(without)h(m)n(y)f(prior)g(p)r
+(ermission.)33 b(Mo)r(di\034ed)21 b(v)n(ersions)0 1047
+y(of)27 b(this)g(do)r(cumen)n(t,)g(including)g(translations)f(in)n(to)g
+(other)h(languages,)e(ma)n(y)h(b)r(e)h(freely)g(distributed,)g(pro)n
+(vided)f(that)h(they)0 1160 y(are)g(clearly)f(iden)n(ti\034ed)i(as)f
+(suc)n(h,)g(and)g(this)h(cop)n(yrigh)n(t)e(is)i(included)g(in)n(tact.)0
+1317 y(This)38 b(do)r(cumen)n(t)g(ma)n(y)f(b)r(e)h(included)g(in)g
+(commercial)f(distributions)g(without)h(m)n(y)g(prior)e(consen)n(t.)67
+b(While)38 b(it)g(is)g(not)0 1430 y(required,)44 b(I)d(w)n(ould)g(lik)n
+(e)f(to)h(b)r(e)h(informed)f(of)g(suc)n(h)g(usage.)76
+b(If)42 b(y)n(ou)e(in)n(tend)i(to)f(incorp)r(orate)e(this)j(do)r(cumen)
+n(t)f(in)g(a)0 1544 y(published)28 b(w)n(ork,)e(please)h(con)n(tact)g
+(me)h(to)f(mak)n(e)g(sure)g(y)n(ou)f(ha)n(v)n(e)h(the)h(latest)f(a)n(v)
+-5 b(ailable)26 b(v)n(ersion.)0 1700 y(This)37 b(do)r(cumen)n(t)h(is)f
+(pro)n(vided)f(\020AS)i(IS\021,)f(with)h(no)f(express)f(or)h(implied)h
+(w)n(arran)n(ties.)63 b(Use)38 b(the)g(information)e(in)i(this)0
+1814 y(do)r(cumen)n(t)28 b(at)f(y)n(our)f(o)n(wn)h(risk.)0
+2105 y Fe(1.2)112 b(A)m(c)m(kno)m(wledgemen)m(ts)0 2315
+y Fm(I'd)33 b(lik)n(e)g(to)g(thank)f(all)h(the)g(Lin)n(ux)g(users)f
+(who)h(ha)n(v)n(e)e(help)r(ed)j(test)f(and)g(debug)g(this)g(soft)n(w)n
+(are,)f(and)h(who)g(ha)n(v)n(e)f(help)r(ed)0 2429 y(with)e(driv)n(er)e
+(dev)n(elopmen)n(t.)41 b(I)30 b(should)f(also)f(thank)h(Lin)n(us)g(T)-7
+b(orv)i(alds,)29 b(Donald)g(Bec)n(k)n(er,)f(Alan)i(Co)n(x,)f(and)g
+(Bjorn)f(Ekw)n(all)0 2542 y(for)i(Lin)n(ux)h(k)n(ernel)f(dev)n(elopmen)
+n(t)g(help.)46 b(I'm)31 b(esp)r(ecially)f(grateful)g(to)h(Mic)n(hael)f
+(Bender)g(for)h(man)n(y)f(helpful)h(discussions)0 2656
+y(ab)r(out)c(the)h(Solaris)f(implemen)n(tation.)0 2994
+y Fg(2)131 b(Basic)45 b(Concepts)0 3251 y Fe(2.1)112
+b(The)38 b(so)s(c)m(k)m(et)f(in)m(terface)0 3461 y Fm(The)24
+b(PC)h(Card)f(bus)g(has)g(t)n(w)n(o)f(basic)h(op)r(erating)f(mo)r(des:)
+35 b(\020memory-only\021)29 b(and)24 b(\020memory)f(and)h(IO\021.)f
+(The)i(\034rst)f(mo)r(de)g(w)n(as)0 3575 y(de\034ned)j(b)n(y)f(the)h
+(original)d(V)-7 b(ersion)26 b(1.0)g(sp)r(eci\034cation)f(and)i(only)f
+(supp)r(orts)f(simple)i(memory)f(cards.)35 b(The)26 b(second)g(mo)r
+(de,)0 3688 y(de\034ned)g(in)f(V)-7 b(ersion)25 b(2.0,)g(rede\034nes)f
+(a)h(few)h(of)f(the)h(memory)e(card)g(con)n(trol)g(signals)g(to)i(supp)
+r(ort)f(IO)g(p)r(ort)g(addressing)e(and)0 3802 y(IO)k(in)n(terrupt)g
+(signalling.)0 3959 y(PC)k(Card)e(devices)g(ha)n(v)n(e)g(t)n(w)n(o)g
+(memory)g(spaces:)41 b(\020attribute)30 b(memory\021)35
+b(and)30 b(\020common)f(memory\021.)43 b(The)30 b(in)n(terface)f(can)0
+4072 y(address)k(up)h(to)g(16MB)f(of)h(eac)n(h)f(t)n(yp)r(e)h(of)g
+(memory)-7 b(.)56 b(A)n(ttribute)34 b(memory)g(is)g(t)n(ypically)f
+(used)h(for)f(holding)h(descriptiv)n(e)0 4186 y(information)20
+b(and)g(con\034guration)f(registers.)33 b(Common)20 b(memory)g(ma)n(y)f
+(include)i(the)g(bulk)g(storage)d(of)j(a)f(memory)g(card,)h(or)0
+4299 y(device)h(bu\033ers)f(in)h(the)h(case)d(of)i(IO)g(cards.)33
+b(All)23 b(cards)d(that)i(are)f(complian)n(t)h(with)g(the)g(v)n(ersion)
+e(2.0)h(PC)i(Card)e(sp)r(eci\034cation)0 4413 y(should)j(ha)n(v)n(e)f
+(a)h(Card)f(Information)h(Structure)g(\(or)f(\020CIS\021\))h(in)h
+(attribute)f(memory)-7 b(,)24 b(whic)n(h)g(describ)r(es)g(the)g(card)g
+(and)g(ho)n(w)0 4526 y(it)k(should)f(b)r(e)h(con\034gured.)0
+4683 y(Separate)f(con)n(trol)h(signals)f(allo)n(w)h(cards)f(to)h
+(signal)g(their)h(op)r(erating)e(status)h(to)h(the)g(host.)39
+b(These)29 b(signals)e(include)i(card)0 4796 y(detect,)f(ready/busy)-7
+b(,)26 b(write)h(protect,)g(battery)h(lo)n(w,)e(and)i(battery)f(dead.)0
+4953 y(The)g(\020memory)e(and)i(IO\021)33 b(in)n(terface)26
+b(mo)r(de)h(allo)n(ws)e(cards)h(to)h(address)e(up)i(to)g(64K)e(of)i(IO)
+f(p)r(orts.)36 b(It)28 b(also)d(allo)n(ws)h(cards)f(to)0
+5066 y(signal)j(IO)h(in)n(terrupts,)g(and)g(routes)f(one)h(card)f
+(output)i(to)f(the)g(host)g(system's)g(sp)r(eak)n(er.)40
+b(In)29 b(this)h(mo)r(de,)f(sev)n(eral)f(of)h(the)0 5180
+y(memory)e(card)g(con)n(trol)f(signals)h(are)f(una)n(v)-5
+b(ailable)27 b(b)r(ecause)g(those)g(pins)h(are)f(used)h(to)f(carry)f
+(the)i(extra)f(IO)g(card)g(signals.)0 5294 y(On)h(some)f(cards,)g
+(these)h(signals)e(can)i(instead)f(b)r(e)i(read)e(from)g(a)h(sp)r
+(ecial)f(con\034guration)f(register)h(in)h(attribute)g(memory)-7
+b(,)0 5407 y(the)28 b(\020Pin)g(Replacemen)n(t)f(Register\021.)p
+eop
+%%Page: 6 6
+6 5 bop 0 -167 3900 5 v 0 -200 a Ff(3.)73 b(Card)33 b(Services)f
+(Subfunction)g(Descriptions)2049 b Fm(6)0 162 y Fe(2.2)112
+b(The)38 b(so)s(c)m(k)m(et)f(con)m(troller)0 372 y Fm(The)c(so)r(c)n(k)
+n(et)e(con)n(troller)g(serv)n(es)g(as)h(a)h(bridge)f(b)r(et)n(w)n(een)g
+(PC)i(Card)d(devices)i(and)f(the)h(system)g(bus.)52 b(There)32
+b(are)g(sev)n(eral)0 485 y(v)-5 b(arieties)29 b(of)g(con)n(trollers,)f
+(but)j(all)e(share)f(the)i(same)f(basic)g(functionalit)n(y)-7
+b(.)43 b(The)30 b(So)r(c)n(k)n(et)f(Services)f(soft)n(w)n(are)g(la)n(y)
+n(er)g(tak)n(es)0 599 y(care)e(of)i(all)f(the)h(details)g(of)f(ho)n(w)g
+(to)g(program)f(the)i(host)f(con)n(troller.)0 755 y(The)33
+b(so)r(c)n(k)n(et)e(con)n(troller)g(has)h(the)i(job)e(of)h(mapping)f
+(windo)n(ws)g(of)h(addresses)e(in)i(the)g(host)g(memory)f(and)g(IO)h
+(spaces)e(to)0 869 y(windo)n(ws)i(of)h(addresses)e(in)i(card)f(space.)
+54 b(All)35 b(supp)r(orted)e(con)n(trollers)f(supp)r(ort)h(at)h(least)f
+(four)g(indep)r(enden)n(t)i(memory)0 983 y(windo)n(ws)27
+b(and)g(t)n(w)n(o)g(IO)g(windo)n(ws)g(p)r(er)g(so)r(c)n(k)n(et.)0
+1139 y(Eac)n(h)34 b(memory)f(windo)n(w)h(is)g(de\034ned)h(b)n(y)e(a)h
+(base)g(address)f(in)h(the)h(host)f(address)f(space,)i(a)f(base)f
+(address)g(in)h(the)h(card)0 1253 y(address)25 b(space,)i(and)f(a)g
+(windo)n(w)h(size.)36 b(Some)26 b(con)n(trollers)f(di\033er)i(in)f
+(their)h(alignmen)n(t)f(rules)g(for)h(memory)e(windo)n(ws,)h(but)0
+1366 y(all)k(con)n(trollers)e(will)i(supp)r(ort)g(windo)n(ws)f(whose)h
+(size)f(is)h(at)g(least)g(4K)f(and)h(also)f(a)h(p)r(o)n(w)n(er)f(of)h
+(t)n(w)n(o,)g(and)g(where)f(the)i(base)0 1480 y(address)e(is)i(a)f(m)n
+(ultiple)h(of)f(the)h(windo)n(w)f(size.)46 b(Eac)n(h)30
+b(windo)n(w)g(can)g(b)r(e)h(programmed)e(to)h(p)r(oin)n(t)h(to)f
+(either)g(attribute)h(or)0 1593 y(common)c(memory)-7
+b(.)0 1750 y(IO)38 b(windo)n(ws)f(di\033er)h(from)g(memory)f(windo)n
+(ws)g(in)h(that)g(host)g(addresses)e(that)j(fall)f(within)g(an)g(IO)g
+(windo)n(w)f(are)g(not)0 1863 y(mo)r(di\034ed)28 b(b)r(efore)f(they)h
+(are)f(passed)g(on)g(to)h(an)f(IO)h(card.)36 b(E\033ectiv)n(ely)-7
+b(,)28 b(the)g(base)f(addresses)f(of)i(the)g(windo)n(w)f(in)h(the)g
+(host)0 1977 y(and)33 b(card)f(address)g(spaces)h(are)f(alw)n(a)n(ys)f
+(equal.)53 b(IO)33 b(windo)n(ws)g(also)f(ha)n(v)n(e)g(no)h(alignmen)n
+(t)f(or)h(size)g(restrictions;)i(an)d(IO)0 2090 y(windo)n(w)27
+b(can)g(start)g(and)h(end)f(on)h(an)n(y)e(b)n(yte)i(b)r(oundary)f(in)g
+(the)h(64K)f(IO)g(address)f(space.)0 2247 y(The)k(PC)g(Card)e(bus)i
+(de\034nes)f(a)h(single)f(in)n(terrupt)g(signal)f(from)i(the)g(card)e
+(to)i(the)g(con)n(troller.)40 b(The)30 b(con)n(troller)e(then)i(has)0
+2361 y(the)i(resp)r(onsibilit)n(y)g(of)g(steering)f(this)h(in)n
+(terrupt)g(to)g(an)f(appropriate)g(in)n(terrupt)g(request)h
+(\(\020irq\021\))f(line.)51 b(All)32 b(con)n(trollers)0
+2474 y(supp)r(ort)f(steering)g(card)g(IO)g(in)n(terrupts)g(to)g(essen)n
+(tially)g(an)n(y)g(free)g(in)n(terrupt)g(line.)49 b(Because)31
+b(steering)f(happ)r(ens)i(in)g(the)0 2588 y(con)n(troller,)26
+b(the)i(card)e(itself)i(is)g(una)n(w)n(are)d(of)j(whic)n(h)f(in)n
+(terrupt)h(it)g(uses.)0 2744 y(All)34 b(PC)g(Card)e(con)n(trollers)f
+(can)i(generate)f(in)n(terrupts)h(in)g(resp)r(onse)f(to)i(card)e
+(status)h(c)n(hanges.)52 b(These)33 b(in)n(terrupts)g(are)0
+2858 y(distinct)27 b(from)f(the)h(IO)g(in)n(terrupts)f(generated)f(b)n
+(y)h(an)h(IO)f(card,)g(and)g(use)h(a)f(separate)f(in)n(terrupt)h(line.)
+37 b(Signals)26 b(that)g(can)0 2971 y(generate)g(in)n(terrupts)h
+(include)h(card)f(detect,)h(ready/busy)-7 b(,)26 b(write)h(protect,)g
+(battery)g(lo)n(w,)g(and)h(battery)f(dead.)0 3310 y Fg(3)131
+b(Card)44 b(Services)h(Subfunction)g(Descriptions)0 3548
+y Fm(Card)27 b(Services)f(calls)h(ha)n(v)n(e)g(the)h(general)e(form:)
+208 3778 y Fd(#include)41 b("cs_types.h")208 3882 y(#include)g("cs.h")
+208 4091 y(int)e(CardServices\(int)k(subfunc,)e(void)f(*arg1,)h(void)f
+(*arg2,)g(...\);)0 4330 y Fm(Some)34 b(Card)f(Services)g(functions)h
+(require)e(additional)i Fh(#include)c Fm(statemen)n(ts.)56
+b(The)34 b(particular)e(subfunction)j(deter-)0 4444 y(mines)g(the)g(n)n
+(um)n(b)r(er)g(of)f(exp)r(ected)h(argumen)n(ts.)58 b(A)35
+b(return)f(co)r(de)h(of)f Fh(CS_SUCCESS)d Fm(indicates)k(that)g(a)f
+(call)g(succeeded.)0 4557 y(Other)27 b(return)g(co)r(des)g(indicate)h
+(errors.)0 4849 y Fe(3.1)112 b(Clien)m(t)36 b(managemen)m(t)h
+(functions)0 5059 y Fm(Device)47 b(driv)n(ers)f(that)h(use)g(Card)f
+(Services)g(functions)i(are)e(called)g(\020clien)n(ts\021.)95
+b(A)47 b(device)g(driv)n(er)f(should)h(use)g(the)0 5172
+y Fh(RegisterClient)15 b Fm(call)20 b(to)g(get)g(a)g(clien)n(t)g
+(handle)h(b)r(efore)f(using)g(other)f(services.)34 b(Most)20
+b(Card)f(Services)h(functions)g(will)h(tak)n(e)0 5286
+y(this)k(clien)n(t)f(handle)g(as)g(an)g(argumen)n(t.)34
+b(Before)24 b(unloading,)g(driv)n(ers)f(should)h(also)f(unregister)g
+(with)i Fh(DeregisterClien)o(t)p Fm(.)p eop
+%%Page: 7 7
+7 6 bop 0 -167 3900 5 v 0 -200 a Ff(3.)73 b(Card)33 b(Services)f
+(Subfunction)g(Descriptions)2049 b Fm(7)0 162 y Ff(3.1.1)94
+b(RegisterClien)m(t)208 348 y Fd(int)39 b
+(CardServices\(RegisterClient,)46 b(client_handle_t)c(*client,)f
+(client_reg_t)h(*reg\);)0 565 y Fm(The)28 b Fh(client_reg_t)22
+b Fm(data)27 b(structure)g(is)h(giv)n(en)e(b)n(y:)208
+760 y Fd(typedef)40 b(struct)h(client_reg_t)h({)521 864
+y(dev_info_t)238 b(*dev_info;)521 968 y(u_int)433 b(Attributes;)521
+1073 y(u_int)g(EventMask;)521 1177 y(int)511 b
+(\(*event_handler\)\(event_t)44 b(event,)d(int)f(priority,)1816
+1281 y(event_callback_args_t)j(*args\);)521 1385 y
+(event_callback_args_t)123 b(event_callback_args;)521
+1489 y(u_int)433 b(Version;)208 1593 y(})39 b(client_reg_t;)0
+1798 y Fh(RegisterClient)24 b Fm(establishes)k(a)h(link)h(b)r(et)n(w)n
+(een)f(a)g(clien)n(t)h(driv)n(er)e(and)h(Card)g(Services,)g(and)g
+(connects)g(the)h(clien)n(t)g(with)0 1911 y(an)d(appropriate)f(so)r(c)n
+(k)n(et.)36 b(The)27 b Fh(dev_info)d Fm(parameter)i(is)i(used)f(b)n(y)h
+(Card)e(Services)h(to)g(matc)n(h)h(the)f(clien)n(t)h(with)g(a)f(so)r(c)
+n(k)n(et)0 2025 y(and)33 b(function;)j(this)d(corresp)r(ondence)e(is)i
+(normally)e(established)i(b)n(y)f(Driv)n(er)g(Services)g(via)g(a)h
+(call)f(to)h Fh(BindDevice)p Fm(.)49 b(If)0 2139 y(successful,)27
+b(a)g(clien)n(t)h(handle)g(will)f(b)r(e)h(returned)f(in)h
+Fh(client)p Fm(.)0 2295 y(The)g(follo)n(wing)e(\035ags)h(can)g(b)r(e)h
+(sp)r(eci\034ed)g(in)f Fh(Attributes)p Fm(:)0 2500 y
+Fh(INFO_MASTER_CLIE)o(NT)208 2642 y Fm(F)-7 b(or)25 b(use)g(only)g(b)n
+(y)h(the)g(Driv)n(er)e(Services)h(clien)n(t.)36 b(Among)26
+b(other)f(things,)h(sp)r(eci\034es)f(that)h(this)g(clien)n(t)g(should)f
+(not)h(b)r(e)208 2756 y(automatically)g(un)n(b)r(ound)i(when)f(a)h
+(card)e(is)i(ejected)g(from)f(this)h(so)r(c)n(k)n(et.)0
+2927 y Fh(INFO_IO_CLIENT)208 3069 y Fm(Sp)r(eci\034es)f(that)h(this)g
+(clien)n(t)g(is)f(an)g(IO)h(card)e(driv)n(er.)0 3240
+y Fh(INFO_MTD_CLIENT)208 3382 y Fm(Sp)r(eci\034es)h(that)h(this)g
+(clien)n(t)g(is)f(a)g(Memory)g(T)-7 b(ec)n(hnology)26
+b(Driv)n(er.)0 3553 y Fh(INFO_MEM_CLIENT)208 3695 y Fm(Sp)r(eci\034es)h
+(that)h(this)g(clien)n(t)g(is)f(a)g(memory)g(card)g(driv)n(er.)0
+3866 y Fh(INFO_CARD_SHARE)208 4008 y Fm(Included)g(for)h(compatibilit)n
+(y)-7 b(,)27 b(has)g(no)g(e\033ect.)0 4179 y Fh(INFO_CARD_EXCL)208
+4322 y Fm(Included)g(for)h(compatibilit)n(y)-7 b(,)27
+b(has)g(no)g(e\033ect.)0 4526 y Fh(EventMask)h Fm(sp)r(eci\034es)k
+(what)f(ev)n(en)n(ts)g(this)h(clien)n(t)g(should)f(b)r(e)i(noti\034ed)e
+(of.)50 b(The)31 b Fh(event_handler)c Fm(en)n(try)k(p)r(oin)n(t)h(will)
+g(b)r(e)0 4640 y(called)c(b)n(y)f(Card)g(Services)g(when)h(an)g(ev)n
+(en)n(t)f(in)h Fh(EventMask)d Fm(is)i(pro)r(cessed.)37
+b(The)28 b Fh(event_handler_ar)o(gs)21 b Fm(structure)28
+b(is)f(a)0 4754 y(template)k(for)f(the)h(structure)f(that)h(will)g(b)r
+(e)g(passed)f(to)g(the)h(ev)n(en)n(t)f(handler.)46 b(The)30
+b Fh(Version)e Fm(parameter)h(iden)n(ti\034es)i(the)0
+4867 y(Card)c(Services)f(v)n(ersion)g(lev)n(el)h(that)h(this)g(driv)n
+(er)e(exp)r(ects;)i(it)g(is)f(curren)n(tly)g(ignored.)0
+5024 y(A)c(driv)n(er)f(should)h(b)r(e)g(prepared)f(to)h(handle)f(Card)h
+(Services)f(ev)n(en)n(ts)g(b)r(efore)g(calling)h Fh(RegisterClient)p
+Fm(.)29 b(This)23 b(call)g(will)g(al-)0 5137 y(w)n(a)n(ys)f(generate)h
+(a)g Fh(CS_REGISTRATION_)o(CO)o(MP)o(LET)o(E)18 b Fm(ev)n(en)n(t,)24
+b(and)f(ma)n(y)g(also)g(generate)f(an)h(arti\034cial)g
+Fh(CS_CARD_INSERTIO)o(N)0 5251 y Fm(ev)n(en)n(t)k(if)h(the)g(so)r(c)n
+(k)n(et)f(is)g(curren)n(tly)g(o)r(ccupied.)0 5407 y(Return)h(co)r(des:)
+p eop
+%%Page: 8 8
+8 7 bop 0 -167 3900 5 v 0 -200 a Ff(3.)73 b(Card)33 b(Services)f
+(Subfunction)g(Descriptions)2049 b Fm(8)0 162 y Fh(CS_OUT_OF_RESOUR)o
+(CE)208 306 y Fm(An)28 b(appropriate)d(so)r(c)n(k)n(et)i(could)g(not)h
+(b)r(e)g(found)g(for)f(this)g(driv)n(er.)0 577 y Ff(3.1.2)94
+b(DeregisterClien)m(t)208 765 y Fd(int)39 b
+(CardServices\(DeregisterClien)q(t,)45 b(client_handle_t)e(client\);)0
+993 y Fh(DeregisterClient)23 b Fm(sev)n(ers)28 b(the)h(connection)g(b)r
+(et)n(w)n(een)h(a)f(clien)n(t)g(and)h(Card)e(Services.)42
+b(It)30 b(should)f(b)r(e)h(called)f(after)g(the)0 1107
+y(clien)n(t)e(has)f(freed)h(an)n(y)f(resources)e(it)k(has)e(allo)r
+(cated.)36 b(Once)26 b(a)g(connection)h(is)f(brok)n(en,)g(it)h(cannot)g
+(b)r(e)g(reestablished)f(un)n(til)0 1220 y(after)h(another)g(call)g(to)
+g Fh(BindDevice)p Fm(.)0 1377 y(Return)h(co)r(des:)0
+1590 y Fh(CS_BAD_HANDLE)208 1735 y Fm(The)f(clien)n(t)h(handle)f(is)h
+(in)n(v)-5 b(alid.)0 1910 y Fh(CS_IN_USE)208 2055 y Fm(The)27
+b(clien)n(t)h(still)g(has)f(allo)r(cated)g(resources,)e(suc)n(h)i(as)g
+(IO)h(p)r(ort)f(windo)n(ws)g(or)f(an)i(in)n(terrupt,)f(or)g(the)h(so)r
+(c)n(k)n(et)e(con\034g-)208 2168 y(uration)g(is)i(lo)r(c)n(k)n(ed.)0
+2439 y Ff(3.1.3)94 b(SetEv)m(en)m(tMask)208 2627 y Fd(int)39
+b(CardServices\(SetEventMask,)45 b(client_handle_t)e(client,)e
+(eventmask_t)g(*mask\);)0 2855 y Fm(The)28 b Fh(eventmask_t)23
+b Fm(structure)k(is)g(giv)n(en)g(b)n(y:)208 3059 y Fd(typedef)40
+b(struct)h(eventmask_t)g({)521 3163 y(u_int)433 b(Attributes;)521
+3267 y(u_int)g(EventMask;)208 3372 y(})39 b(eventmask_t;)0
+3585 y Fh(SetEventMask)23 b Fm(up)r(dates)k(the)h(mask)f(that)h
+(determines)f(whic)n(h)h(ev)n(en)n(ts)f(this)g(clien)n(t)h(will)g(b)r
+(e)g(noti\034ed)g(of.)0 3742 y(Return)g(co)r(des:)0 3955
+y Fh(CS_BAD_HANDLE)208 4100 y Fm(The)f(clien)n(t)h(handle)f(is)h(in)n
+(v)-5 b(alid.)0 4370 y Ff(3.1.4)94 b(BindDevice)208 4559
+y Fd(int)39 b(CardServices\(BindDevice,)45 b(bind_req_t)c(*req\);)0
+4787 y Fm(The)28 b Fh(bind_req)c Fm(structure)j(is)g(giv)n(en)g(b)n(y:)
+208 4991 y Fd(typedef)40 b(struct)h(bind_req_t)g({)521
+5095 y(socket_t)316 b(Socket;)521 5199 y(u_char)394 b(Function;)521
+5303 y(dev_info_t)238 b(*dev_info;)208 5407 y(})39 b(bind_req_t;)p
+eop
+%%Page: 9 9
+9 8 bop 0 -167 3900 5 v 0 -200 a Ff(3.)73 b(Card)33 b(Services)f
+(Subfunction)g(Descriptions)2049 b Fm(9)0 162 y Fh(BindDevice)21
+b Fm(asso)r(ciates)h(a)j(device)f(driv)n(er)g(with)h(a)f(particular)f
+(so)r(c)n(k)n(et.)35 b(It)25 b(is)g(normally)e(called)i(b)n(y)f(Driv)n
+(er)g(Services)f(after)0 275 y(a)31 b(newly)g(inserted)g(card)g(has)f
+(b)r(een)i(iden)n(ti\034ed.)49 b(Once)31 b(a)g(driv)n(er)f(has)g(b)r
+(een)i(b)r(ound)g(to)f(a)g(so)r(c)n(k)n(et,)g(it)h(will)f(b)r(e)h
+(eligible)f(to)0 389 y(register)c(as)g(a)h(clien)n(t)h(of)f(that)g(so)r
+(c)n(k)n(et.)38 b(Note)28 b(that)h(this)g(call)e(do)r(es)h(not)h(tak)n
+(e)e(a)h(clien)n(t)g(handle)h(as)e(an)h(argumen)n(t.)38
+b(This)28 b(is)0 502 y(the)g(only)f(Card)g(Services)f(call)i(that)f
+(tak)n(es)g(a)g(so)r(c)n(k)n(et)g(n)n(um)n(b)r(er)g(as)g(an)g(argumen)n
+(t.)0 659 y(The)19 b Fh(Function)d Fm(\034eld)k(sp)r(eci\034es)f(whic)n
+(h)g(function\(s\))h(of)f(a)g(m)n(ultifunction)h(card)e(are)g(to)h(b)r
+(e)h(b)r(ound)f(to)g(this)h(driv)n(er.)33 b(F)-7 b(unction)0
+772 y(n)n(um)n(b)r(ers)21 b(corresp)r(ond)f(to)h(en)n(tries)g(in)g(the)
+h(card's)f Fh(CISTPL_LONGLINK)o(_M)o(FC)15 b Fm(tuple.)35
+b(If)22 b Fh(Function)c Fm(is)k(set)f(to)h Fh(BIND_FN_ALL)p
+Fm(,)0 886 y(the)27 b(driv)n(er)e(will)i(b)r(e)g(b)r(ound)g(to)f(all)g
+(card)g(functions.)37 b(A)27 b(driv)n(er)e(will)i(only)f(b)r(e)h(able)f
+(to)g(access)g(CIS)g(tuples)h(corresp)r(onding)0 1000
+y(to)g(functions)h(for)f(whic)n(h)h(it)g(is)f(b)r(ound.)0
+1156 y(Return)h(co)r(des:)0 1364 y Fh(CS_BAD_SOCKET)208
+1507 y Fm(The)f(sp)r(eci\034ed)h(so)r(c)n(k)n(et)e(n)n(um)n(b)r(er)i
+(is)f(in)n(v)-5 b(alid.)0 1795 y Fe(3.2)112 b(So)s(c)m(k)m(et)37
+b(state)h(con)m(trol)0 2005 y Fm(These)27 b(functions)g(are)g(more)f
+(or)g(less)h(concerned)f(with)i(getting)f(and)g(setting)g(the)h(curren)
+n(t)e(op)r(erating)g(state)h(of)g(a)g(so)r(c)n(k)n(et.)0
+2119 y Fh(GetStatus)33 b Fm(returns)k(the)g(curren)n(t)f(so)r(c)n(k)n
+(et)g(state.)65 b Fh(ResetCard)33 b Fm(is)k(used)g(to)g(send)g(a)g
+(hard)f(reset)h(signal)f(to)h(a)f(so)r(c)n(k)n(et.)0
+2232 y Fh(SuspendCard)c Fm(and)k Fh(ResumeCard)d Fm(can)j(b)r(e)g(used)
+h(to)f(p)r(o)n(w)n(er)f(do)n(wn)h(and)h(p)r(o)n(w)n(er)e(up)i(a)f(so)r
+(c)n(k)n(et)f(without)i(releasing)e(the)0 2346 y(driv)n(ers)24
+b(curren)n(tly)h(b)r(ound)h(to)f(that)h(so)r(c)n(k)n(et.)35
+b Fh(EjectCard)22 b Fm(and)k Fh(InsertCard)21 b Fm(essen)n(tially)k
+(mimic)h(real)f(card)g(ejection)g(and)0 2459 y(insertion)i(ev)n(en)n
+(ts.)0 2729 y Ff(3.2.1)94 b(GetStatus)208 2916 y Fd(int)39
+b(CardServices\(GetStatus,)45 b(client_handle_t)d(client,)f
+(cs_status_t)h(*status\);)0 3136 y Fm(The)28 b Fh(cs_status_t)23
+b Fm(data)k(structure)g(is)g(giv)n(en)g(b)n(y:)208 3335
+y Fd(typedef)40 b(struct)h(cs_status_t)g({)521 3439 y(u_char)394
+b(Function;)521 3543 y(u_int)433 b(CardState;)521 3647
+y(u_int)g(SocketState;)208 3751 y(})39 b(cs_status_t;)0
+3959 y Fh(GetStatus)g Fm(returns)i(the)i(curren)n(t)f(status)g(of)g(a)g
+(clien)n(t's)h(so)r(c)n(k)n(et.)80 b(F)-7 b(or)42 b(cards)f(that)i(are)
+e(con\034gured)g(in)i(IO)f(mo)r(de,)0 4072 y Fh(GetStatus)33
+b Fm(uses)j(the)g(Pin)h(Replacemen)n(t)f(Register)g(and)g(Extended)h
+(Status)g(Register)e(to)h(determine)h(the)f(card)g(sta-)0
+4186 y(tus.)52 b(F)-7 b(or)32 b(normal)g(clien)n(ts,)i(the)f
+Fh(Function)c Fm(\034eld)k(is)f(ignored,)h(but)g(for)f(clien)n(ts)h(b)r
+(ound)g(with)g Fh(BIND_FN_ALL)p Fm(,)28 b(this)33 b(\034eld)0
+4299 y(sp)r(eci\034es)22 b(the)h(function)g(whose)f(con\034guration)f
+(registers)f(should)j(b)r(e)f(used)h(to)f(determine)h(the)g(so)r(c)n(k)
+n(et)e(state,)i(if)g(the)g(so)r(c)n(k)n(et)0 4413 y(is)k(curren)n(tly)g
+(con\034gured.)36 b(The)27 b(follo)n(wing)g(\035ags)f(are)h(de\034ned)h
+(in)g Fh(CardState)p Fm(:)0 4633 y Fh(CS_EVENT_CARD_DE)o(TE)o(CT)208
+4776 y Fm(Sp)r(eci\034es)f(that)h(the)g(so)r(c)n(k)n(et)f(is)g(o)r
+(ccupied.)0 4949 y Fh(CS_EVENT_CB_DETE)o(CT)208 5092
+y Fm(Sp)r(eci\034es)g(that)h(the)g(so)r(c)n(k)n(et)f(is)g(o)r(ccupied)h
+(b)n(y)f(a)g(CardBus)f(device.)0 5264 y Fh(CS_EVENT_WRITE_P)o(RO)o(TEC)
+o(T)208 5407 y Fm(Sp)r(eci\034es)h(that)h(the)g(card)f(is)g(curren)n
+(tly)g(write)g(protected.)p eop
+%%Page: 10 10
+10 9 bop 0 -167 3900 5 v 0 -200 a Ff(3.)73 b(Card)33
+b(Services)f(Subfunction)g(Descriptions)2008 b Fm(10)0
+162 y Fh(CS_EVENT_BATTERY)o(_L)o(OW)208 308 y Fm(Sp)r(eci\034es)27
+b(that)h(the)g(card)f(battery)g(is)g(lo)n(w.)0 488 y
+Fh(CS_EVENT_BATTERY)o(_D)o(EAD)208 635 y Fm(Sp)r(eci\034es)g(that)h
+(the)g(card)f(battery)g(is)g(dead.)0 815 y Fh(CS_EVENT_READY_C)o(HA)o
+(NGE)208 962 y Fm(Sp)r(eci\034es)g(that)h(the)g(card)f(is)g(ready)-7
+b(.)0 1142 y Fh(CS_EVENT_PM_SUSP)o(EN)o(D)208 1289 y
+Fm(Sp)r(eci\034es)27 b(that)h(the)g(so)r(c)n(k)n(et)f(is)g(susp)r
+(ended.)0 1469 y Fh(CS_EVENT_REQUEST)o(_A)o(TTE)o(NT)o(IO)o(N)208
+1616 y Fm(Sp)r(eci\034es)g(that)h(the)g(request)f(atten)n(tion)g(bit)h
+(in)g(the)g(extended)g(status)f(register)f(is)i(set.)0
+1796 y Fh(CS_EVENT_CARD_IN)o(SE)o(RTI)o(ON)208 1942 y
+Fm(Sp)r(eci\034es)h(that)g(a)g(card)f(insertion)g(ev)n(en)n(t)h(is)g
+(in)g(progress.)39 b(An)29 b(insertion)g(ev)n(en)n(t)f(will)h(b)r(e)h
+(sen)n(t)f(to)f(the)i(clien)n(t)f(when)208 2056 y(so)r(c)n(k)n(et)d
+(setup)i(is)f(complete.)0 2236 y Fh(CS_EVENT_3VCARD)208
+2383 y Fm(Indicates)g(that)h(the)g(card)e(supp)r(orts)h(3.3V)g(op)r
+(eration.)0 2563 y Fh(CS_EVENT_XVCARD)208 2709 y Fm(Indicates)k(that)g
+(the)h(card)e(supp)r(orts)h(\020X.X\021V)h(op)r(eration.)47
+b(The)31 b(actual)g(v)n(oltage)f(is)h(curren)n(tly)f(unde\034ned)i(in)g
+(the)208 2823 y(sp)r(eci\034cation.)0 3063 y Fh(SocketState)15
+b Fm(is)20 b(curren)n(tly)e(un)n(used,)k(but)e(in)g(theory)-7
+b(,)21 b(it)f(should)f(latc)n(h)g(c)n(hanges)g(in)h(the)g(state)f(of)h
+(the)g(\034elds)g(in)g Fh(CardState)p Fm(.)0 3219 y(Return)28
+b(co)r(des:)0 3442 y Fh(CS_BAD_HANDLE)208 3589 y Fm(The)f(clien)n(t)h
+(handle)f(is)h(in)n(v)-5 b(alid.)0 3861 y Ff(3.2.2)94
+b(ResetCard)208 4052 y Fd(int)39 b(CardServices\(ResetCard,)45
+b(client_handle_t)d(client\);)0 4292 y Fh(ResetCard)23
+b Fm(requests)k(that)g(a)g(clien)n(t's)g(so)r(c)n(k)n(et)f(b)r(e)h
+(reset.)36 b(When)28 b(this)g(call)e(is)h(made,)g(Card)g(Services)f
+(sends)h(all)g(clien)n(ts)f(a)0 4405 y Fh(CS_EVENT_RESET_R)o(EQ)o(UES)o
+(T)e Fm(ev)n(en)n(t.)44 b(If)30 b(an)n(y)f(clien)n(t)h(rejects)g(the)g
+(request,)h(Card)e(Services)g(sends)g(the)i(initiating)f(clien)n(t)0
+4519 y(a)j Fh(CS_EVENT_RESET_)o(CO)o(MPL)o(ET)o(E)27
+b Fm(ev)n(en)n(t)33 b(with)g Fh(event_callback_ar)o(gs)o(.i)o(nfo)26
+b Fm(set)33 b(to)g(the)h(return)f(co)r(de)f(of)i(the)f(clien)n(t)0
+4632 y(that)28 b(rejected)f(the)h(request.)0 4789 y(If)j(all)g(clien)n
+(ts)f(agree)f(to)i(the)g(request,)g(Card)e(Services)h(sends)g(a)h
+Fh(CS_EVENT_RESET_)o(PHY)o(SI)o(CA)o(L)25 b Fm(ev)n(en)n(t,)31
+b(then)g(resets)f(the)0 4902 y(so)r(c)n(k)n(et.)58 b(When)36
+b(the)f(so)r(c)n(k)n(et)f(signals)g(that)i(it)f(is)g(ready)-7
+b(,)36 b(a)f Fh(CS_EVENT_CARD_R)o(ESE)o(T)29 b Fm(ev)n(en)n(t)34
+b(is)h(generated.)59 b(Finally)-7 b(,)36 b(a)0 5016 y
+Fh(CS_EVENT_RESET_C)o(OM)o(PLE)o(TE)28 b Fm(ev)n(en)n(t)34
+b(is)g(sen)n(t)g(to)h(the)g(initiating)f(clien)n(t,)i(with)f
+Fh(event_callback_ar)o(gs)o(.i)o(nfo)28 b Fm(set)34 b(to)0
+5130 y(zero.)0 5286 y(Return)28 b(co)r(des:)p eop
+%%Page: 11 11
+11 10 bop 0 -167 3900 5 v 0 -200 a Ff(3.)73 b(Card)33
+b(Services)f(Subfunction)g(Descriptions)2008 b Fm(11)0
+162 y Fh(CS_BAD_HANDLE)208 308 y Fm(The)27 b(clien)n(t)h(handle)f(is)h
+(in)n(v)-5 b(alid.)0 488 y Fh(CS_NO_CARD)208 635 y Fm(The)27
+b(so)r(c)n(k)n(et)g(assigned)f(to)h(this)h(clien)n(t)g(is)f(curren)n
+(tly)g(v)-5 b(acan)n(t.)0 815 y Fh(CS_IN_USE)208 962
+y Fm(This)27 b(so)r(c)n(k)n(et)g(is)g(curren)n(tly)g(b)r(eing)g(reset.)
+0 1235 y Ff(3.2.3)94 b(Susp)s(endCard)208 1426 y Fd(int)39
+b(CardServices\(SuspendCard,)45 b(client_handle_t)e(client\);)0
+1665 y Fm(Card)31 b(Services)h(sends)g(all)g(clien)n(ts)g
+Fh(CS_EVENT_PM_SUSP)o(EN)o(D)26 b Fm(ev)n(en)n(ts,)33
+b(then)g(sh)n(uts)f(do)n(wn)g(and)g(turns)g(o\033)g(p)r(o)n(w)n(er)g
+(to)g(the)0 1779 y(so)r(c)n(k)n(et.)0 1935 y(Return)c(co)r(des:)0
+2158 y Fh(CS_BAD_HANDLE)208 2305 y Fm(The)f(clien)n(t)h(handle)f(is)h
+(in)n(v)-5 b(alid.)0 2485 y Fh(CS_NO_CARD)208 2632 y
+Fm(The)27 b(so)r(c)n(k)n(et)g(assigned)f(to)h(this)h(clien)n(t)g(is)f
+(curren)n(tly)g(v)-5 b(acan)n(t.)0 2812 y Fh(CS_IN_USE)208
+2958 y Fm(This)27 b(so)r(c)n(k)n(et)g(is)g(already)f(susp)r(ended.)0
+3231 y Ff(3.2.4)94 b(ResumeCard)208 3422 y Fd(int)39
+b(CardServices\(ResumeCard,)45 b(client_handle_t)d(client\);)0
+3661 y Fm(After)28 b(restoring)e(p)r(o)n(w)n(er)g(to)h(the)h(so)r(c)n
+(k)n(et,)f(Card)g(Services)f(will)i(notify)g(all)f(clien)n(ts)g(with)i
+Fh(CS_EVENT_PM_RES)o(UM)o(E)22 b Fm(ev)n(en)n(ts.)0 3818
+y(Return)28 b(co)r(des:)0 4041 y Fh(CS_BAD_HANDLE)208
+4187 y Fm(The)f(clien)n(t)h(handle)f(is)h(in)n(v)-5 b(alid.)0
+4367 y Fh(CS_NO_CARD)208 4514 y Fm(The)27 b(so)r(c)n(k)n(et)g(assigned)
+f(to)h(this)h(clien)n(t)g(is)f(curren)n(tly)g(v)-5 b(acan)n(t.)0
+4694 y Fh(CS_IN_USE)208 4841 y Fm(This)27 b(so)r(c)n(k)n(et)g(is)g(not)
+h(curren)n(tly)e(susp)r(ended.)p eop
+%%Page: 12 12
+12 11 bop 0 -167 3900 5 v 0 -200 a Ff(3.)73 b(Card)33
+b(Services)f(Subfunction)g(Descriptions)2008 b Fm(12)0
+162 y Ff(3.2.5)94 b(EjectCard)208 353 y Fd(int)39 b
+(CardServices\(EjectCard,)45 b(client_handle_t)d(client\);)0
+592 y Fm(Card)24 b(Services)g(sends)h(eject)h(ev)n(en)n(ts)e(to)h(all)g
+(clien)n(ts,)h(then)f(sh)n(uts)g(do)n(wn)g(and)g(turns)g(o\033)g(p)r(o)
+n(w)n(er)f(to)h(the)h(so)r(c)n(k)n(et.)35 b(All)25 b(clien)n(ts)0
+706 y(except)j(for)f(Driv)n(er)f(Services)h(will)g(b)r(e)h(unlink)n(ed)
+g(from)f(the)h(so)r(c)n(k)n(et.)0 862 y(Return)g(co)r(des:)0
+1085 y Fh(CS_BAD_HANDLE)208 1232 y Fm(The)f(clien)n(t)h(handle)f(is)h
+(in)n(v)-5 b(alid.)0 1412 y Fh(CS_NO_CARD)208 1559 y
+Fm(The)27 b(so)r(c)n(k)n(et)g(assigned)f(to)h(this)h(clien)n(t)g(is)f
+(curren)n(tly)g(v)-5 b(acan)n(t.)0 1831 y Ff(3.2.6)94
+b(InsertCard)208 2022 y Fd(int)39 b(CardServices\(InsertCard,)45
+b(client_handle_t)d(client\);)0 2262 y Fm(Card)27 b(Services)f(sends)i
+(insertion)e(ev)n(en)n(ts)h(to)h(all)f(clien)n(ts)g(of)h(this)g(so)r(c)
+n(k)n(et)e(\(normally)-7 b(,)27 b(only)g(Driv)n(er)g(Services\).)0
+2418 y(Return)h(co)r(des:)0 2641 y Fh(CS_BAD_HANDLE)208
+2788 y Fm(The)f(clien)n(t)h(handle)f(is)h(in)n(v)-5 b(alid.)0
+2968 y Fh(CS_NO_CARD)208 3115 y Fm(The)27 b(so)r(c)n(k)n(et)g(assigned)
+f(to)h(this)h(clien)n(t)g(is)f(curren)n(tly)g(v)-5 b(acan)n(t.)0
+3295 y Fh(CS_IN_USE)208 3441 y Fm(The)27 b(so)r(c)n(k)n(et)g(has)g
+(already)f(b)r(een)i(con\034gured.)0 3733 y Fe(3.3)112
+b(IO)37 b(card)h(con\034guration)f(calls)0 3943 y Fm(The)27
+b(normal)g(order)e(of)j(ev)n(en)n(ts)e(is)h(for)g(a)g(driv)n(er)f(to)h
+(reserv)n(e)e(IO)i(p)r(orts)g(and)g(an)g(in)n(terrupt)g(line)g(with)h
+(calls)f(to)g Fh(RequestIO)0 4056 y Fm(and)h Fh(RequestIRQ)p
+Fm(,)c(then)k(to)g(call)g Fh(RequestConfigura)o(tio)o(n)22
+b Fm(to)28 b(actually)f(con\034gure)g(the)h(so)r(c)n(k)n(et.)38
+b(If)28 b(an)n(y)g(of)g(these)g(calls)0 4170 y(fails,)f(a)h(driv)n(er)e
+(should)h(b)r(e)h(sure)f(to)g(release)g(an)n(y)f(resources)g(it)i
+(successfully)f(reserv)n(ed.)0 4327 y(Multifunction)f(cards)e(can)h(ha)
+n(v)n(e)f(separate)f(con\034gurations)h(for)g(eac)n(h)g(card)h
+(function.)36 b(Ho)n(w)n(ev)n(er,)24 b(the)h(con\034gurations)e(do)0
+4440 y(need)28 b(to)f(b)r(e)h(consisten)n(t)f(with)h(one)g(another.)36
+b(While)28 b(eac)n(h)f(card)g(function)h(has)f(its)h(o)n(wn)f(set)g(of)
+h(con\034guration)e(registers,)0 4554 y(eac)n(h)h(so)r(c)n(k)n(et)f
+(has)h(only)g(a)h(single)f(in)n(terrupt)g(line)h(and)f(can)g(only)g
+(map)h(t)n(w)n(o)f(con)n(tiguous)f(ranges)g(of)h(IO)g(p)r(orts.)0
+4710 y(CardBus)e(cards)h(are)f(con\034gured)h(somewhat)g(di\033eren)n
+(tly)-7 b(.)36 b(The)27 b Fh(RequestIO)c Fm(and)j Fh(RequestConfigura)o
+(tio)o(n)20 b Fm(calls)26 b(ha)n(v)n(e)0 4824 y(similar)39
+b(roles,)k(ho)n(w)n(ev)n(er,)e(Card)e(Services)h(tak)n(es)f(resp)r
+(onsibilit)n(y)g(for)h(most)g(of)g(the)h(con\034guration)d(details,)44
+b(and)c(the)0 4937 y(con)n(ten)n(ts)27 b(of)g(the)h(request)f
+(structures)g(are)g(ignored.)p eop
+%%Page: 13 13
+13 12 bop 0 -167 3900 5 v 0 -200 a Ff(3.)73 b(Card)33
+b(Services)f(Subfunction)g(Descriptions)2008 b Fm(13)0
+162 y Ff(3.3.1)94 b(RequestIO)208 352 y Fd(int)39 b
+(CardServices\(RequestIO,)45 b(client_handle_t)d(client,)f(io_req_t)g
+(*req\);)0 589 y Fm(The)28 b Fh(io_req_t)c Fm(data)j(structure)g(is)g
+(giv)n(en)g(b)n(y:)208 800 y Fd(typedef)40 b(struct)h(io_req_t)g({)521
+904 y(ioaddr_t)316 b(BasePort1;)521 1008 y(ioaddr_t)g(NumPorts1;)521
+1112 y(u_int)433 b(Attributes1;)521 1216 y(ioaddr_t)316
+b(BasePort2;)521 1320 y(ioaddr_t)g(NumPorts2;)521 1425
+y(u_int)433 b(Attributes2;)521 1529 y(u_int)g(IOAddrLines;)208
+1633 y(})39 b(io_req_t;)0 1853 y Fh(RequestIO)20 b Fm(reserv)n(es)h(IO)
+j(p)r(ort)f(windo)n(ws)g(for)g(a)g(card.)35 b Fh(BasePort1)20
+b Fm(sp)r(eci\034es)j(the)h(base)f(IO)g(p)r(ort)h(address)e(of)i(the)g
+(windo)n(w)0 1967 y(to)36 b(b)r(e)g(reserv)n(ed.)60 b(If)36
+b Fh(NumPorts2)c Fm(is)k(non-zero,)g(a)g(second)f(IO)h(p)r(ort)f(windo)
+n(w)h(will)g(also)e(b)r(e)j(reserv)n(ed.)60 b Fh(IOAddrLines)0
+2081 y Fm(sp)r(eci\034es)22 b(the)h(n)n(um)n(b)r(er)f(of)h(address)e
+(lines)h(that)h(are)f(actually)f(deco)r(ded)i(b)n(y)f(the)h(card.)34
+b(The)23 b(IO)f(p)r(ort)g(allo)r(cation)f(algorithm)0
+2194 y(assumes)40 b(that)i(an)n(y)f(alias)f(of)h(the)h(requested)f
+(address\(es\))f(that)i(preserv)n(es)d(the)j(lo)n(w)n(er)e
+Fh(IOAddrLines)c Fm(bits)42 b(will)g(b)r(e)0 2308 y(acceptable,)27
+b(and)g(will)h(up)r(date)g Fh(BasePort1)c Fm(and)j Fh(BasePort2)d
+Fm(to)k(re\035ect)f(the)h(address)e(range\(s\))g(actually)h(assigned.)0
+2464 y(Prior)33 b(to)h(release)f(3.1.4,)h(the)h Fh(IOAddrLines)29
+b Fm(\034eld)35 b(w)n(as)e(ignored.)55 b(The)34 b(allo)r(cator)e(alw)n
+(a)n(ys)g(tried)i(to)g(assign)f(the)i(exact)0 2578 y(address)29
+b(range)h(requested,)g(unless)h(the)g(base)e(address)h(w)n(as)f(zero;)i
+(in)g(that)g(case,)g(it)g(w)n(ould)f(assign)f(an)n(y)h(a)n(v)-5
+b(ailable)29 b(win-)0 2691 y(do)n(w)j(aligned)f(to)i(the)f(nearest)g(p)
+r(o)n(w)n(er)f(of)h(t)n(w)n(o)g(larger)e(than)i(the)h(windo)n(w)f
+(size.)51 b(The)32 b(new)g(allo)r(cator)f(v)n(eri\034es)g(that)i(the)0
+2805 y Fh(IOAddrLines)17 b Fm(parameter)i(agrees)g(with)j(the)f
+(requested)g(windo)n(w)f(parameters,)h(and)g(defaults)g(to)g(the)h
+(pre-3.1.4)d(b)r(eha)n(vior)0 2918 y(if)28 b(an)f(inconsistency)g(is)h
+(found.)0 3075 y(With)35 b(m)n(ultifunction)h(cards,)f(this)f(call)g
+(will)h(allo)r(cate)f(IO)g(p)r(orts)g(for)g(eac)n(h)f(card)h(function)h
+(in)f(suc)n(h)g(a)g(w)n(a)n(y)g(that)g(all)g(a)0 3188
+y(card's)25 b(p)r(orts)h(can)g(b)r(e)g(mapp)r(ed)h(b)n(y)f(the)g(t)n(w)
+n(o)g(lo)n(w-lev)n(el)e(IO)i(p)r(ort)g(windo)n(ws)f(asso)r(ciated)g
+(with)i(eac)n(h)e(ph)n(ysical)g(so)r(c)n(k)n(et.)36 b(F)-7
+b(or)0 3302 y(example,)33 b(if)f(the)h(driv)n(ers)d(for)i(a)g(h)n(yp)r
+(othetical)f(four-function)h(card)f(eac)n(h)h(attempt)g(to)g(allo)r
+(cate)f(one)h(IO)g(windo)n(w)f(of)h(8)0 3416 y(p)r(orts,)27
+b(Card)g(Services)f(will)i(consolidate)f(these)g(in)n(to)g(a)h(single)f
+(con)n(tiguous)f(32-p)r(ort)g(blo)r(c)n(k.)0 3572 y(When)38
+b(this)h(function)f(is)g(in)n(v)n(ok)n(ed)e(b)n(y)i(a)f(CardBus)g
+(clien)n(t,)k(the)d(IO)g(request)f(structure)g(is)h(ignored.)67
+b(Instead,)40 b(Card)0 3686 y(Services)d(examines)g(the)h(card)e(and)i
+(allo)r(cates)e(an)n(y)h(necessary)f(system)i(resources:)54
+b(this)38 b(includes)g(IO)f(and)h(memory)0 3799 y(space,)25
+b(as)h(w)n(ell)f(as)g(an)h(in)n(terrupt,)g(if)g(needed.)36
+b(One)26 b(call)f(will)h(reserv)n(e)e(all)h(resources)f(needed)i(for)f
+(all)h(card)f(functions,)h(not)0 3913 y(just)i(the)g(function)g(of)g
+(the)g(clien)n(t)f(making)g(the)h(call.)0 4069 y(This)50
+b(call)g(do)r(es)g(not)g(actually)g(con\034gure)f(a)h(so)r(c)n(k)n
+(et's)f(IO)h(windo)n(ws:)82 b(this)50 b(is)g(done)g(b)n(y)g(a)g
+(subsequen)n(t)g(call)g(to)0 4183 y Fh(RequestConfigura)o(ti)o(on)p
+Fm(.)0 4339 y(The)28 b(follo)n(wing)e(\035ags)h(can)g(b)r(e)h(sp)r
+(eci\034ed)g(in)f Fh(Attributes1)c Fm(and)28 b Fh(Attributes2)p
+Fm(:)0 4560 y Fh(IO_DATA_PATH_WID)o(TH)208 4706 y Fm(This)20
+b(\034eld)h(ma)n(y)f(either)g(b)r(e)i Fh(IO_DATA_PATH_WI)o(DT)o(H_)o
+(16)14 b Fm(for)21 b(16-bit)e(access,)i(or)f Fh(IO_DATA_PATH_WID)o(TH)o
+(_8)14 b Fm(for)20 b(8-bit)208 4820 y(access,)26 b(or)h
+Fh(IO_DATA_PATH_WI)o(DT)o(H_A)o(UT)o(O)22 b Fm(to)27
+b(dynamically)g(size)g(the)h(bus)g(based)f(on)g(the)h(access)e(size.)0
+5040 y(Return)i(co)r(des:)0 5261 y Fh(CS_BAD_HANDLE)208
+5407 y Fm(The)f(clien)n(t)h(handle)f(is)h(in)n(v)-5 b(alid.)p
+eop
+%%Page: 14 14
+14 13 bop 0 -167 3900 5 v 0 -200 a Ff(3.)73 b(Card)33
+b(Services)f(Subfunction)g(Descriptions)2008 b Fm(14)0
+162 y Fh(CS_NO_CARD)208 303 y Fm(The)27 b(so)r(c)n(k)n(et)g(assigned)f
+(to)h(this)h(clien)n(t)g(is)f(curren)n(tly)g(v)-5 b(acan)n(t.)0
+471 y Fh(CS_IN_USE)208 612 y Fm(This)27 b(so)r(c)n(k)n(et's)f(IO)i
+(windo)n(ws)e(ha)n(v)n(e)h(already)f(b)r(een)i(reserv)n(ed.)0
+780 y Fh(CS_CONFIGURATION)o(_L)o(OCK)o(ED)208 921 y Fm(This)f(so)r(c)n
+(k)n(et's)f(con\034guration)g(has)h(b)r(een)h(lo)r(c)n(k)n(ed)f(b)n(y)g
+(a)g(call)g(to)h Fh(RequestConfigura)o(ti)o(on)o Fm(.)0
+1090 y Fh(CS_BAD_ATTRIBUTE)208 1231 y Fm(An)g(unsupp)r(orted)f
+(attribute)h(\035ag)f(w)n(as)f(sp)r(eci\034ed.)0 1399
+y Fh(CS_UNSUPPORTED_F)o(UN)o(CTI)o(ON)208 1540 y Fm(F)-7
+b(or)26 b(a)i(CardBus)e(clien)n(t,)i(this)g(is)f(returned)g(if)h(Card)f
+(Services)g(w)n(as)f(not)i(con\034gured)e(with)i(CardBus)e(supp)r(ort.)
+0 1807 y Ff(3.3.2)94 b(ReleaseIO)208 1993 y Fd(int)39
+b(CardServices\(ReleaseIO,)45 b(client_handle_t)d(client,)f(io_req_t)g
+(*req\);)0 2203 y Fh(ReleaseIO)34 b Fm(un-reserv)n(es)i(IO)i(p)r(ort)g
+(windo)n(ws)f(allo)r(cated)h(b)n(y)f(a)h(previous)f(call)h(to)g
+Fh(RequestIO)p Fm(.)c(The)39 b Fh(req)e Fm(parameter)0
+2317 y(should)26 b(b)r(e)h(the)g(same)e(one)h(passed)g(to)g
+Fh(RequestIO)p Fm(.)d(If)j(sev)n(eral)f(card)g(functions)i(are)e
+(sharing)g(a)h(larger)e(IO)i(p)r(ort)h(windo)n(w,)0 2430
+y(p)r(orts)e(released)f(b)n(y)h(one)f(function)i(ma)n(y)f(not)g(b)r
+(ecome)g(a)n(v)-5 b(ailable)24 b(for)h(other)f(uses)h(un)n(til)h(all)f
+(card)f(functions)h(ha)n(v)n(e)f(released)0 2544 y(their)k(IO)f(p)r
+(orts.)0 2700 y(F)-7 b(or)27 b(a)g(CardBus)f(clien)n(t,)i(this)g(call)f
+(releases)f(all)h(system)h(resources)d(allo)r(cated)i(for)g(this)h
+(card.)0 2857 y(Return)g(co)r(des:)0 3056 y Fh(CS_BAD_HANDLE)208
+3197 y Fm(The)f(clien)n(t)h(handle)f(is)h(in)n(v)-5 b(alid.)0
+3365 y Fh(CS_CONFIGURATION)o(_L)o(OCK)o(ED)208 3506 y
+Fm(This)33 b(so)r(c)n(k)n(et's)f(con\034guration)g(has)h(b)r(een)g(lo)r
+(c)n(k)n(ed)g(b)n(y)g(a)g(call)g(to)g Fh(RequestConfigurat)o(io)o(n)p
+Fm(.)48 b(The)34 b(con\034guration)208 3620 y(should)27
+b(b)r(e)h(released)e(b)r(efore)h(calling)g(ReleaseIO.)0
+3788 y Fh(CS_BAD_ARGS)208 3929 y Fm(The)g(parameters)f(in)i
+Fh(req)e Fm(do)h(not)h(matc)n(h)f(the)h(parameters)e(passed)h(to)g
+Fh(RequestIO)p Fm(.)0 4197 y Ff(3.3.3)94 b(RequestIR)m(Q)208
+4382 y Fd(int)39 b(CardServices\(RequestIRQ,)45 b(client_handle_t)d
+(client,)f(irq_req_t)g(*req\);)0 4592 y Fm(The)28 b Fh(irq_req_t)23
+b Fm(structure)k(is)h(giv)n(en)f(b)n(y:)208 4783 y Fd(typedef)40
+b(struct)h(irq_req_t)g({)521 4887 y(u_int)433 b(Attributes;)521
+4991 y(u_int)g(AssignedIRQ;)521 5095 y(u_int)g(IRQInfo1,)41
+b(IRQInfo2;)521 5199 y(void)472 b(*\(Handler\)\(int,)42
+b(struct)f(pt_regs)g(*\);)521 5303 y(void)472 b(*Instance)208
+5407 y(})39 b(irq_req_t;)p eop
+%%Page: 15 15
+15 14 bop 0 -167 3900 5 v 0 -200 a Ff(3.)73 b(Card)33
+b(Services)f(Subfunction)g(Descriptions)2008 b Fm(15)0
+162 y Fh(RequestIRQ)25 b Fm(reserv)n(es)j(an)h(in)n(terrupt)g(line)h
+(for)f(use)g(b)n(y)g(a)h(card.)41 b(The)30 b Fh(IRQInfo1)c
+Fm(and)k Fh(IRQInfo2)c Fm(\034elds)j(corresp)r(ond)f(to)0
+275 y(the)35 b(in)n(terrupt)g(description)g(b)n(ytes)f(in)i(a)e
+Fh(CFTABLE_ENTRY)c Fm(tuple.)60 b(If)36 b Fh(IRQ_INFO2_VALID)28
+b Fm(is)35 b(set)h(in)f Fh(IRQInfo1)p Fm(,)f(then)0 389
+y Fh(IRQInfo2)24 b Fm(is)k(a)f(bit-mapp)r(ed)h(mask)f(of)g(allo)n(w)n
+(ed)g(in)n(terrupt)g(v)-5 b(alues.)36 b(Eac)n(h)28 b(bit)g(corresp)r
+(onds)e(to)h(one)g(in)n(terrupt)g(line:)38 b(bit)0 502
+y(0)33 b(=)g(irq)g(0,)i(bit)f(1)f(=)g(irq)g(1,)i(etc.)54
+b(So,)35 b(a)e(mask)g(of)g(0x1100)e(w)n(ould)i(mean)g(that)h(in)n
+(terrupts)f(12)g(and)g(8)g(could)g(b)r(e)h(used.)0 616
+y(If)c Fh(IRQ_INFO2_VALID)23 b Fm(is)30 b(not)f(set,)h
+Fh(IRQInfo1)d Fm(is)i(just)h(the)g(desired)f(in)n(terrupt)g(n)n(um)n(b)
+r(er.)43 b(If)30 b(the)f(call)h(is)f(successful,)h(the)0
+730 y(reserv)n(ed)c(in)n(terrupt)h(is)g(returned)g(in)h
+Fh(AssignedIRQ)p Fm(.)0 886 y(If)37 b(the)g Fh(IRQ_HANDLER_PRES)o(EN)o
+(T)31 b Fm(\035ag)36 b(is)g(set,)j(then)e(this)g(call)f(also)g(sp)r
+(eci\034es)g(an)g(in)n(terrupt)h(handler)f(to)g(b)r(e)h(installed)0
+1000 y(when)31 b(the)g(in)n(terrupt)f(is)g(enabled.)45
+b(When)31 b Fh(RequestConfigurat)o(io)o(n)24 b Fm(is)31
+b(called,)g(the)g(handler)e(giv)n(en)h(b)n(y)g Fh(Handler)e
+Fm(will)0 1113 y(b)r(e)23 b(installed.)36 b(F)-7 b(or)22
+b(2.0)g(and)h(later)g(k)n(ernels,)g(the)g(in)n(terrupt)g(handler)f
+(will)i(b)r(e)f(installed)g(with)h(the)f(device)g(\020instance\021)29
+b(giv)n(en)0 1227 y(in)c Fh(Instance)p Fm(.)32 b(F)-7
+b(or)24 b(pre-2.1.60)f(k)n(ernels,)h(the)h(k)n(ernel)e
+Fh(irq2dev_map)d Fm(table)25 b(will)g(also)e(b)r(e)i(up)r(dated.)37
+b(With)25 b(m)n(ultifunction)0 1340 y(cards,)g(the)h(in)n(terrupt)f
+(will)g(b)r(e)h(allo)r(cated)f(in)h(shared)e(mo)r(de,)i(and)f(the)h
+(handler\(s\))g(ha)n(v)n(e)e(resp)r(onsibilit)n(y)g(for)h(determining)0
+1454 y(whic)n(h)34 b(card)g(function\(s\))i(require)d(atten)n(tion)h
+(when)h(an)f(in)n(terrupt)h(is)f(receiv)n(ed.)57 b(If)35
+b(a)f(clien)n(t)h(instead)f(b)n(ypasses)f(Card)0 1567
+y(Services)d(to)i(install)f(its)h(o)n(wn)f(in)n(terrupt)g(service)f
+(routine,)i(it)g(should)f(allo)r(cate)g(the)h(in)n(terrupt)f(in)h
+(shared)e(mo)r(de)i(if)g(this)0 1681 y(clien)n(t)c(could)f(b)r(e)h(b)r
+(ound)g(to)f(a)g(m)n(ultifunction)i(card.)0 1838 y(The)f(follo)n(wing)e
+(\035ags)h(can)g(b)r(e)h(sp)r(eci\034ed)g(in)f Fh(Attributes)p
+Fm(:)0 2060 y Fh(IRQ_FORCED_PULSE)208 2207 y Fm(Sp)r(eci\034es)g(that)h
+(the)g(in)n(terrupt)f(should)g(b)r(e)h(con\034gured)e(for)h(pulsed)h
+(mo)r(de,)f(rather)g(than)g(the)h(default)g(lev)n(el)f(mo)r(de.)0
+2387 y Fh(IRQ_TYPE_TIME)208 2534 y Fm(Sp)r(eci\034es)36
+b(that)h(this)f(in)n(terrupt)g(can)g(b)r(e)h(time-shared)e(with)i
+(other)e(Card)h(Services)f(driv)n(ers.)62 b(Only)36 b(one)f(driv)n(er)
+208 2648 y(should)27 b(enable)g(the)h(in)n(terrupt)f(at)h(an)n(y)e
+(time.)0 2828 y Fh(IRQ_FIRST_SHARED)208 2974 y Fm(In)c(conjunction)f
+(with)i Fh(IRQ_TYPE_TIME)p Fm(,)16 b(this)23 b(should)e(b)r(e)h(set)g
+(b)n(y)g(the)g(\034rst)g(driv)n(er)e(requesting)h(a)h(shared)e(in)n
+(terrupt.)0 3154 y Fh(IRQ_HANDLER_PRES)o(EN)o(T)208 3301
+y Fm(Indicates)27 b(that)h(the)g Fh(Handler)c Fm(\034eld)k(p)r(oin)n
+(ts)g(to)f(an)g(in)n(terrupt)h(service)e(routine)h(that)h(should)f(b)r
+(e)h(installed.)0 3524 y(Return)g(co)r(des:)0 3747 y
+Fh(CS_BAD_HANDLE)208 3894 y Fm(The)f(clien)n(t)h(handle)f(is)h(in)n(v)
+-5 b(alid.)0 4074 y Fh(CS_NO_CARD)208 4220 y Fm(The)27
+b(so)r(c)n(k)n(et)g(assigned)f(to)h(this)h(clien)n(t)g(is)f(curren)n
+(tly)g(v)-5 b(acan)n(t.)0 4400 y Fh(CS_IN_USE)208 4547
+y Fm(An)28 b(in)n(terrupt)f(has)g(already)f(b)r(een)i(reserv)n(ed)e
+(for)h(this)g(so)r(c)n(k)n(et,)g(or)g(the)h(requested)e(in)n(terrupt)i
+(is)f(una)n(v)-5 b(ailable.)0 4727 y Fh(CS_CONFIGURATION)o(_L)o(OCK)o
+(ED)208 4874 y Fm(This)27 b(card)g(function's)h(con\034guration)d(has)j
+(b)r(een)f(lo)r(c)n(k)n(ed)g(b)n(y)g(a)h(call)f(to)g
+Fh(RequestConfigura)o(tio)o(n)p Fm(.)0 5054 y Fh(CS_BAD_ATTRIBUTE)208
+5201 y Fm(An)h(unsupp)r(orted)f(attribute)h(\035ag)f(w)n(as)f(sp)r
+(eci\034ed.)p eop
+%%Page: 16 16
+16 15 bop 0 -167 3900 5 v 0 -200 a Ff(3.)73 b(Card)33
+b(Services)f(Subfunction)g(Descriptions)2008 b Fm(16)0
+162 y Ff(3.3.4)94 b(ReleaseIR)m(Q)208 346 y Fd(int)39
+b(CardServices\(ReleaseIRQ,)45 b(client_handle_t)d(client,)f(irq_req_t)
+g(*req\);)0 552 y Fh(ReleaseIRQ)28 b Fm(un-reserv)n(es)i(an)i(in)n
+(terrupt)f(assigned)g(b)n(y)h(an)g(earlier)f(call)h(to)g
+Fh(RequestIRQ)p Fm(.)c(The)k Fh(req)f Fm(structure)g(should)0
+666 y(b)r(e)d(the)h(same)e(structure)h(that)g(w)n(as)f(passed)g(to)h
+Fh(RequestIRQ)p Fm(.)c(If)29 b(a)e(handler)h(w)n(as)f(sp)r(eci\034ed)h
+(in)g(the)h Fh(RequestIRQ)24 b Fm(call,)k(it)0 779 y(will)g(b)r(e)g
+(unregistered)e(at)h(this)h(time.)0 936 y(Return)g(co)r(des:)0
+1132 y Fh(CS_BAD_HANDLE)208 1272 y Fm(The)f(clien)n(t)h(handle)f(is)h
+(in)n(v)-5 b(alid.)0 1439 y Fh(CS_CONFIGURATION)o(_L)o(OCK)o(ED)208
+1579 y Fm(This)33 b(so)r(c)n(k)n(et's)f(con\034guration)g(has)h(b)r
+(een)g(lo)r(c)n(k)n(ed)g(b)n(y)g(a)g(call)g(to)g Fh(RequestConfigurat)o
+(io)o(n)p Fm(.)48 b(The)34 b(con\034guration)208 1693
+y(should)27 b(b)r(e)h(released)e(b)r(efore)h(calling)g(ReleaseIR)n(Q.)0
+1859 y Fh(CS_BAD_IRQ)208 1999 y Fm(The)g(parameters)f(in)i
+Fh(req)e Fm(do)h(not)h(matc)n(h)f(the)h(parameters)e(passed)h(to)g
+Fh(RequestIRQ)p Fm(.)0 2266 y Ff(3.3.5)94 b(RequestCon\034guration)208
+2451 y Fd(int)39 b(CardServices\(RequestConfigur)q(ation)q(,)45
+b(client_handle_t)e(client,)d(config_req_t)i(*req\);)0
+2657 y Fm(The)28 b Fh(config_req_t)22 b Fm(structure)27
+b(is)h(giv)n(en)e(b)n(y:)208 2844 y Fd(typedef)40 b(struct)h
+(config_req_t)h({)521 2948 y(u_int)433 b(Attributes;)521
+3052 y(u_int)g(Vcc,)40 b(Vpp1,)g(Vpp2;)521 3156 y(u_int)433
+b(IntType;)521 3260 y(u_int)g(ConfigBase;)521 3364 y(u_char)394
+b(Status,)41 b(Pin,)f(Copy,)g(ExtStatus;)521 3468 y(u_char)394
+b(ConfigIndex;)521 3572 y(u_int)433 b(Present;)208 3676
+y(})39 b(config_req_t;)0 3873 y Fh(RequestConfigura)o(ti)o(on)34
+b Fm(is)41 b(resp)r(onsible)f(for)g(actually)g(con\034guring)g(a)g(so)r
+(c)n(k)n(et.)76 b(This)40 b(includes)h(setting)g(v)n(oltages,)0
+3986 y(setting)28 b(CIS)f(con\034guration)f(registers,)g(setting)h(up)h
+(IO)g(p)r(ort)f(windo)n(ws,)g(and)g(setting)h(up)g(in)n(terrupts.)0
+4143 y Fh(IntType)d Fm(sp)r(eci\034es)i(the)h(t)n(yp)r(e)g(of)f(in)n
+(terface)g(to)g(use)h(for)f(this)h(card.)35 b(It)28 b(ma)n(y)f(b)r(e)h
+Fh(INT_MEMORY)p Fm(,)c Fh(INT_MEMORY_AND_)o(IO)o Fm(,)e(or)0
+4256 y Fh(INT_CARDBUS)p Fm(.)h(V)-7 b(oltages)27 b(are)f(sp)r
+(eci\034ed)i(in)g(units)g(of)f(1/10)f(v)n(olt.)36 b(Curren)n(tly)-7
+b(,)27 b Fh(Vpp1)f Fm(m)n(ust)i(equal)f Fh(Vpp2)p Fm(.)0
+4413 y(With)38 b(m)n(ultifunction)g(cards,)g(eac)n(h)e(card)g(function)
+i(is)f(con\034gured)e(separately)-7 b(.)64 b(Eac)n(h)37
+b(function)g(has)g(its)g(o)n(wn)f(set)h(of)0 4526 y(CIS)32
+b(con\034guration)e(registers.)48 b(Ho)n(w)n(ev)n(er,)31
+b(all)g(functions)h(m)n(ust)g(b)r(e)g(con\034gured)f(with)h(the)g(same)
+g(p)r(o)n(w)n(er)e(and)i(in)n(terface)0 4640 y(settings.)0
+4796 y(When)k(in)n(v)n(ok)n(ed)f(b)n(y)g(a)g(CardBus)g(clien)n(t,)j
+(most)d(of)h(the)g(request)f(structure)h(is)f(ignored,)i(and)f(all)f
+(card)g(functions)h(will)0 4910 y(b)r(e)29 b(con\034gured)e(based)g(on)
+h(data)g(collected)g(in)g(a)g(previous)f Fh(RequestIO)d
+Fm(call.)39 b(This)28 b(includes)g(con\034guring)f(the)h(CardBus)0
+5024 y(bridge,)21 b(as)e(w)n(ell)g(as)h(initializing)f(the)h(Command,)h
+(Base)e(A)n(ddress,)i(and)f(In)n(terrupt)f(Line)h(registers)e(in)i(eac)
+n(h)f(card)g(function's)0 5137 y(con\034guration)26 b(space.)36
+b Fh(IntType)25 b Fm(m)n(ust)i(b)r(e)h(set)g(to)f Fh(INT_CARDBUS)c
+Fm(in)28 b(this)g(case.)0 5294 y(The)36 b(follo)n(wing)f(\035ags)g(can)
+g(b)r(e)h(sp)r(eci\034ed)g(in)g Fh(Attributes)p Fm(.)58
+b(DMA)37 b(and)e(sp)r(eak)n(er)g(con)n(trol)f(are)h(not)h(supp)r(orted)
+g(on)f(all)0 5407 y(systems.)p eop
+%%Page: 17 17
+17 16 bop 0 -167 3900 5 v 0 -200 a Ff(3.)73 b(Card)33
+b(Services)f(Subfunction)g(Descriptions)2008 b Fm(17)0
+162 y Fh(CONF_ENABLE_IRQ)208 308 y Fm(Enable)27 b(the)h(IO)g(in)n
+(terrupt)f(reserv)n(ed)e(b)n(y)j(a)f(previous)f(call)h(to)h
+Fh(RequestIRQ)p Fm(.)0 488 y Fh(CONF_ENABLE_DMA)208 635
+y Fm(Enable)f(DMA)i(accesses)d(for)h(this)h(so)r(c)n(k)n(et.)0
+815 y Fh(CONF_ENABLE_SPKR)208 962 y Fm(Enable)f(sp)r(eak)n(er)f(output)
+j(from)e(this)h(so)r(c)n(k)n(et.)0 1185 y(The)i Fh(Present)d
+Fm(parameter)i(is)g(a)h(bit)g(map)g(sp)r(ecifying)g(whic)n(h)g(CIS)g
+(con\034guration)e(registers)h(are)g(implemen)n(ted)h(b)n(y)g(this)0
+1298 y(card.)35 b Fh(ConfigBase)21 b Fm(giv)n(es)j(the)i(o\033set)f(of)
+g(the)g(con\034guration)f(registers)f(in)i(attribute)g(memory)-7
+b(.)36 b(The)25 b(follo)n(wing)f(registers)0 1412 y(can)j(b)r(e)h(sp)r
+(eci\034ed:)0 1635 y Fh(PRESENT_OPTION)208 1782 y Fm(Sp)r(eci\034es)k
+(that)h(the)g(Con\034guration)e(Option)i(Register)f(is)g(presen)n(t.)52
+b(The)32 b(COR)h(register)e(will)i(b)r(e)g(set)f(using)h(the)208
+1895 y Fh(ConfigIndex)23 b Fm(parameter.)0 2075 y Fh(PRESENT_STATUS)208
+2222 y Fm(Sp)r(eci\034es)34 b(that)g(the)g(Card)f(Con\034guration)g
+(and)g(Status)h(Register)f(is)h(presen)n(t.)55 b(The)34
+b(CCSR)g(will)h(b)r(e)f(initialized)208 2336 y(with)28
+b(the)g Fh(Status)d Fm(parameter.)0 2516 y Fh(PRESENT_PIN_REPL)o(AC)o
+(E)208 2662 y Fm(Sp)r(eci\034es)37 b(that)h(the)g(Pin)g(Replacemen)n(t)
+f(Register)g(is)g(presen)n(t.)66 b(The)37 b(PRR)h(will)g(b)r(e)g
+(initialized)g(with)f(the)h Fh(Pin)208 2776 y Fm(parameter.)0
+2956 y Fh(PRESENT_COPY)208 3103 y Fm(Sp)r(eci\034es)d(that)h(the)g(So)r
+(c)n(k)n(et)e(and)h(Cop)n(y)g(Register)f(is)i(presen)n(t.)59
+b(The)36 b(SCR)f(will)h(b)r(e)g(initialized)f(with)h(the)g
+Fh(Copy)208 3216 y Fm(parameter.)0 3396 y Fh(PRESENT_EXT_STAT)o(US)208
+3543 y Fm(Sp)r(eci\034es)23 b(that)g(the)h(Extended)g(Status)f
+(Register)f(is)h(presen)n(t.)35 b(The)23 b(ESR)h(will)f(b)r(e)g
+(initialized)h(with)f(the)h Fh(ExtStatus)208 3657 y Fm(parameter.)0
+3880 y(Return)k(co)r(des:)0 4102 y Fh(CS_BAD_HANDLE)208
+4249 y Fm(The)f(clien)n(t)h(handle)f(is)h(in)n(v)-5 b(alid.)0
+4429 y Fh(CS_NO_CARD)208 4576 y Fm(The)27 b(so)r(c)n(k)n(et)g(assigned)
+f(to)h(this)h(clien)n(t)g(is)f(curren)n(tly)g(v)-5 b(acan)n(t.)0
+4756 y Fh(CS_OUT_OF_RESOUR)o(CE)208 4903 y Fm(Card)26
+b(Services)h(w)n(as)f(unable)i(to)f(allo)r(cate)g(a)g(memory)g(windo)n
+(w)g(to)g(access)g(the)h(card's)e(con\034guration)g(registers.)0
+5083 y Fh(CS_CONFIGURATION)o(_L)o(OCK)o(ED)208 5230 y
+Fm(This)h(card's)g(con\034guration)e(has)i(already)f(b)r(een)i(lo)r(c)n
+(k)n(ed)f(b)n(y)g(another)g(call)g(to)h Fh(RequestConfigur)o(at)o(io)o
+(n)p Fm(.)p eop
+%%Page: 18 18
+18 17 bop 0 -167 3900 5 v 0 -200 a Ff(3.)73 b(Card)33
+b(Services)f(Subfunction)g(Descriptions)2008 b Fm(18)0
+162 y Fh(CS_BAD_VCC)208 308 y Fm(The)27 b(requested)g(V)-7
+b(cc)28 b(v)n(oltage)e(is)h(not)h(supp)r(orted.)0 488
+y Fh(CS_BAD_VPP)208 635 y Fm(The)f(requested)g(V)-7 b(pp1/V)g(pp2)27
+b(v)n(oltage)f(is)i(not)f(supp)r(orted.)0 815 y Fh(CS_UNSUPPORTED_M)o
+(OD)o(E)208 962 y Fm(A)40 b(non-CardBus)e(clien)n(t)i(attempted)h(to)f
+(con\034gure)e(a)i(CardBus)f(card,)j(or)d(a)h(CardBus)f(clien)n(t)h
+(attempted)g(to)208 1076 y(con\034gure)26 b(a)h(non-CardBus)f(card.)0
+1348 y Ff(3.3.6)94 b(Mo)s(difyCon\034guration)208 1539
+y Fd(int)39 b(CardServices\(ModifyConfigura)q(tion,)46
+b(client_handle_t)c(client,)f(modconf_t)g(*mod\);)0 1779
+y Fm(The)28 b Fh(modconf_t)23 b Fm(structure)k(is)h(giv)n(en)f(b)n(y:)
+208 1992 y Fd(typedef)40 b(struct)h(modconf_t)g({)521
+2096 y(u_int)433 b(Attributes;)521 2200 y(u_int)g(Vcc,)40
+b(Vpp1,)g(Vpp2;)208 2304 y(})f(modconf_t;)0 2527 y Fh(ModifyConfigurat)
+o(io)o(n)49 b Fm(mo)r(di\034es)54 b(some)g(attributes)h(of)f(a)h(so)r
+(c)n(k)n(et)e(that)i(has)f(b)r(een)h(con\034gured)e(b)n(y)i(a)f(call)g
+(to)0 2641 y Fh(RequestConfigura)o(ti)o(on)p Fm(.)0 2797
+y(The)28 b(follo)n(wing)e(\035ags)h(can)g(b)r(e)h(sp)r(eci\034ed)g(in)f
+Fh(Attributes)p Fm(:)0 3020 y Fh(CONF_IRQ_CHANGE_)o(VA)o(LID)208
+3167 y Fm(Indicates)g(that)h(the)g(CONF_ENABLE_IR)n(Q)f(setting)g
+(should)h(b)r(e)g(up)r(dated.)0 3347 y Fh(CONF_ENABLE_IRQ)208
+3494 y Fm(Sp)r(eci\034es)f(that)h(IO)f(in)n(terrupts)g(should)h(b)r(e)g
+(enabled)f(for)g(this)h(so)r(c)n(k)n(et.)0 3674 y Fh(CONF_VCC_CHANGE_)o
+(VA)o(LID)208 3821 y Fm(Indicates)f(that)h(V)-7 b(cc)27
+b(should)h(b)r(e)g(up)r(dated.)0 4001 y Fh(CONF_VPP1_CHANGE)o(_V)o(ALI)
+o(D)208 4147 y Fm(Indicates)f(that)h(V)-7 b(pp1)27 b(should)h(b)r(e)g
+(up)r(dated.)0 4327 y Fh(CONF_VPP2_CHANGE)o(_V)o(ALI)o(D)208
+4474 y Fm(Indicates)f(that)h(V)-7 b(pp2)27 b(should)h(b)r(e)g(up)r
+(dated.)0 4697 y(Curren)n(tly)-7 b(,)26 b(V)-7 b(pp1)27
+b(and)g(V)-7 b(pp2)27 b(m)n(ust)f(alw)n(a)n(ys)f(ha)n(v)n(e)h(the)h
+(same)f(v)-5 b(alue.)37 b(So,)26 b(the)h(t)n(w)n(o)f(v)-5
+b(alues)27 b(m)n(ust)g(alw)n(a)n(ys)d(b)r(e)k(c)n(hanged)d(at)0
+4811 y(the)j(same)f(time.)0 4967 y(Return)h(co)r(des:)0
+5190 y Fh(CS_BAD_HANDLE)208 5337 y Fm(The)f(clien)n(t)h(handle)f(is)h
+(in)n(v)-5 b(alid.)p eop
+%%Page: 19 19
+19 18 bop 0 -167 3900 5 v 0 -200 a Ff(3.)73 b(Card)33
+b(Services)f(Subfunction)g(Descriptions)2008 b Fm(19)0
+162 y Fh(CS_NO_CARD)208 308 y Fm(The)27 b(so)r(c)n(k)n(et)g(assigned)f
+(to)h(this)h(clien)n(t)g(is)f(curren)n(tly)g(v)-5 b(acan)n(t.)0
+488 y Fh(CS_CONFIGURATION)o(_L)o(OCK)o(ED)208 635 y Fm(This)27
+b(actually)g(means)g(that)h(this)g(so)r(c)n(k)n(et)e(has)h
+Ff(not)h Fm(b)r(een)g(lo)r(c)n(k)n(ed.)0 815 y Fh(CS_BAD_VCC)208
+962 y Fm(The)f(requested)g(V)-7 b(cc)28 b(v)n(oltage)e(is)h(not)h(supp)
+r(orted.)0 1142 y Fh(CS_BAD_VPP)208 1289 y Fm(The)f(requested)g(V)-7
+b(pp1/V)g(pp2)27 b(v)n(oltage)f(is)i(not)f(supp)r(orted.)0
+1561 y Ff(3.3.7)94 b(ReleaseCon\034guration)208 1752
+y Fd(int)39 b(CardServices\(ReleaseConfigur)q(ation)q(,)45
+b(client_handle_t)e(client,)d(config_req_t)i(*req\);)0
+1992 y Fh(ReleaseConfigura)o(ti)o(on)22 b Fm(un-con\034gures)27
+b(a)i(so)r(c)n(k)n(et)e(previously)g(set)i(up)g(b)n(y)f(a)h(call)f(to)g
+Fh(RequestConfigurat)o(io)o(n)p Fm(.)34 b(The)0 2105
+y Fh(req)26 b Fm(parameter)g(should)i(b)r(e)g(the)g(same)f(one)g(used)g
+(to)h(con\034gure)e(the)i(so)r(c)n(k)n(et.)0 2262 y(Return)g(co)r(des:)
+0 2485 y Fh(CS_BAD_HANDLE)208 2632 y Fm(The)f(windo)n(w)g(handle)h(is)f
+(in)n(v)-5 b(alid,)28 b(or)e(the)i(so)r(c)n(k)n(et)f(is)g(not)h
+(con\034gured.)0 2904 y Ff(3.3.8)94 b(GetCon\034gurationInfo)208
+3095 y Fd(int)39 b(CardServices\(GetConfiguratio)q(nInfo)q(,)45
+b(client_handle_t)e(client,)d(config_info_t)i(*config\);)0
+3335 y Fm(The)28 b Fh(config_info_t)22 b Fm(structure)27
+b(is)g(giv)n(en)g(b)n(y:)208 3548 y Fd(typedef)40 b(struct)h
+(config_info_t)h({)521 3652 y(u_char)394 b(Function;)521
+3756 y(u_int)433 b(Attributes;)521 3860 y(u_int)g(Vcc,)40
+b(Vpp1,)g(Vpp2;)521 3964 y(u_int)433 b(IntType;)521 4069
+y(u_int)g(ConfigBase;)521 4173 y(u_char)394 b(Status,)41
+b(Pin,)f(Copy,)g(Option,)h(ExtStatus;)521 4277 y(u_int)433
+b(Present;)521 4381 y(u_int)g(AssignedIRQ;)521 4485 y(u_int)g
+(IRQAttributes;)521 4589 y(ioaddr_t)316 b(BasePort1;)521
+4693 y(ioaddr_t)g(NumPorts1;)521 4797 y(u_int)433 b(Attributes1;)521
+4901 y(ioaddr_t)316 b(BasePort2;)521 5006 y(ioaddr_t)g(NumPorts2;)521
+5110 y(u_int)433 b(Attributes2;)521 5214 y(u_int)g(IOAddrLines;)208
+5318 y(})39 b(config_info_t;)p eop
+%%Page: 20 20
+20 19 bop 0 -167 3900 5 v 0 -200 a Ff(3.)73 b(Card)33
+b(Services)f(Subfunction)g(Descriptions)2008 b Fm(20)0
+162 y Fh(GetConfiguration)o(In)o(fo)15 b Fm(returns)21
+b(the)g(curren)n(t)g(so)r(c)n(k)n(et)f(con\034guration)g(as)g(it)i(w)n
+(as)e(set)i(up)f(b)n(y)g Fh(RequestIO)p Fm(,)d Fh(RequestIRQ)p
+Fm(,)0 275 y(and)k Fh(RequestConfigura)o(ti)o(on)o Fm(.)30
+b(It)22 b(can)g(only)f(b)r(e)i(applied)f(to)g(a)g(fully)g(con\034gured)
+f(so)r(c)n(k)n(et.)34 b(F)-7 b(or)22 b(normal)f(clien)n(ts)h(b)r(ound)g
+(to)0 389 y(a)j(single)f(card)h(function,)h(the)f Fh(Function)d
+Fm(\034eld)k(is)f(ignored,)f(and)h(data)g(for)f(that)i(clien)n(t's)f
+(assigned)f(function)h(is)h(returned.)0 502 y(F)-7 b(or)22
+b(clien)n(ts)g(b)r(ound)g(to)g Fh(BIND_FN_ALL)p Fm(,)c(this)23
+b(\034eld)f(sp)r(eci\034es)g(whic)n(h)g(function's)h(con\034guration)d
+(data)i(should)g(b)r(e)h(returned.)0 659 y(Return)28
+b(co)r(des:)0 882 y Fh(CS_BAD_HANDLE)208 1029 y Fm(The)f(windo)n(w)g
+(handle)h(is)f(in)n(v)-5 b(alid,)28 b(or)e(the)i(so)r(c)n(k)n(et)f(is)g
+(not)h(con\034gured.)0 1209 y Fh(CS_NO_CARD)208 1355
+y Fm(The)f(so)r(c)n(k)n(et)g(assigned)f(to)h(this)h(clien)n(t)g(is)f
+(curren)n(tly)g(v)-5 b(acan)n(t.)0 1535 y Fh(CS_CONFIGURATION)o(_L)o
+(OCK)o(ED)208 1682 y Fm(This)27 b(actually)g(means)g(that)h(the)g
+(con\034guration)e(has)h Ff(not)g Fm(b)r(een)h(lo)r(c)n(k)n(ed.)0
+1974 y Fe(3.4)112 b(Card)38 b(Information)e(Structure)h(\(CIS\))f
+(calls)0 2184 y Fm(The)26 b(de\034nition)g(of)f(the)h(Card)f
+(Information)g(Structure)h(\(CIS\))g(is)g(the)g(dark)n(est)e(c)n
+(hapter)h(of)g(the)h(PC)h(Card)d(standard.)36 b(All)0
+2297 y(v)n(ersion)23 b(2)h(complian)n(t)g(cards)f(should)h(ha)n(v)n(e)g
+(a)g(CIS,)h(whic)n(h)f(describ)r(es)g(the)h(card)e(and)i(ho)n(w)e(it)i
+(should)g(b)r(e)f(con\034gured.)35 b(The)0 2411 y(CIS)27
+b(is)g(a)f(link)n(ed)h(list)g(of)f(\020tuples\021)34
+b(in)27 b(the)g(card's)f(attribute)h(memory)e(space.)36
+b(Eac)n(h)27 b(tuple)g(consists)f(of)h(an)f(iden)n(ti\034cation)0
+2524 y(co)r(de,)f(a)f(length)h(b)n(yte,)g(and)g(a)f(series)f(of)i(data)
+f(b)n(ytes.)36 b(The)24 b(la)n(y)n(out)g(of)g(the)h(data)f(b)n(ytes)h
+(for)f(some)g(tuple)h(t)n(yp)r(es)g(is)f(absurdly)0 2638
+y(complicated,)j(in)h(an)f(apparen)n(t)g(e\033ort)g(to)g(use)h(ev)n
+(ery)e(last)h(bit.)0 2794 y(The)g Fh(ValidateCIS)22 b
+Fm(call)27 b(c)n(hec)n(ks)e(to)i(see)g(if)g(a)f(card)g(has)h(a)f
+(reasonable)f(CIS.)i(The)g Fh(GetFirstTuple)21 b Fm(and)27
+b Fh(GetNextTuple)0 2908 y Fm(calls)41 b(are)f(used)i(to)f(step)h
+(through)f(CIS)g(tuple)h(lists.)79 b Fh(GetTupleData)36
+b Fm(extracts)41 b(data)g(b)n(ytes)g(from)g(a)g(tuple.)80
+b(And)0 3022 y Fh(ParseTuple)33 b Fm(unpac)n(ks)j(most)g(tuple)i(t)n
+(yp)r(es)e(in)n(to)h(more)f(easily)g(used)h(forms.)64
+b(Finally)-7 b(,)39 b(the)e Fh(ReplaceCIS)c Fm(call)k(allo)n(ws)0
+3135 y(a)27 b(clien)n(t)h(to)f(pro)n(vide)g(Card)f(Services)h(with)h(a)
+f(substitute)h(for)f(the)h(CIS)g(found)g(on)f(the)h(card.)0
+3408 y Ff(3.4.1)94 b(GetFirstT)-8 b(uple,)30 b(GetNextT)-8
+b(uple)208 3599 y Fd(#include)41 b("cistpl.h")208 3807
+y(int)e(CardServices\(GetFirstTuple,)46 b(client_handle_t)c(client,)f
+(tuple_t)g(*tuple\);)208 3911 y(int)e(CardServices\(GetNextTuple,)45
+b(client_handle_t)e(client,)e(tuple_t)f(*tuple\);)0 4151
+y Fm(The)28 b Fh(tuple_t)c Fm(data)j(structure)g(is)h(giv)n(en)f(b)n
+(y:)208 4364 y Fd(typedef)40 b(struct)h(tuple_t)g({)521
+4468 y(u_int)433 b(Attributes;)521 4572 y(cis_data_t)238
+b(DesiredTuple;)521 4676 y(u_int)433 b(Flags;)521 4780
+y(cisdata_t)277 b(TupleCode;)521 4885 y(u_int)433 b(TupleLink;)521
+4989 y(cisdata_t)277 b(TupleOffset;)521 5093 y(cisdata_t)g
+(TupleDataMax;)521 5197 y(cisdata_t)g(TupleDataLen;)521
+5301 y(cisdata_t)g(*TupleData;)208 5405 y(})39 b(tuple_t;)p
+eop
+%%Page: 21 21
+21 20 bop 0 -167 3900 5 v 0 -200 a Ff(3.)73 b(Card)33
+b(Services)f(Subfunction)g(Descriptions)2008 b Fm(21)0
+162 y Fh(GetFirstTuple)29 b Fm(searc)n(hes)k(a)i(card's)f(CIS)h(for)f
+(the)h(\034rst)g(tuple)g(co)r(de)g(matc)n(hing)f Fh(DesiredTuple)p
+Fm(.)54 b(The)35 b(sp)r(ecial)f(co)r(de)0 275 y Fh(RETURN_FIRST_TUP)o
+(LE)24 b Fm(will)32 b(matc)n(h)e(the)h(\034rst)g(tuple)h(of)e(an)n(y)h
+(kind.)47 b(If)31 b(successful,)g Fh(TupleCode)d Fm(is)i(set)h(to)g
+(the)g(co)r(de)g(of)0 389 y(the)d(\034rst)f(matc)n(hing)g(tuple)h
+(found,)g(and)g Fh(TupleLink)c Fm(is)j(the)h(address)e(of)i(this)g
+(tuple)g(in)g(attribute)f(memory)-7 b(.)0 545 y Fh(GetNextTuple)23
+b Fm(is)28 b(lik)n(e)f Fh(GetFirstTuple)p Fm(,)22 b(except)28
+b(that)g(giv)n(en)f(a)h Fh(tuple_t)d Fm(structure)i(returned)g(b)n(y)h
+(a)f(previous)g(call)g(to)0 659 y Fh(GetFirstTuple)22
+b Fm(or)27 b Fh(GetNextTuple)p Fm(,)22 b(it)28 b(will)g(return)f(the)h
+(next)g(tuple)g(matc)n(hing)f Fh(DesiredTuple)p Fm(.)0
+815 y(These)e(functions)g(will)g(automatically)f(tra)n(v)n(erse)f(an)n
+(y)h(link)h(tuples)h(found)f(in)g(the)h(CIS.)f(F)-7 b(or)24
+b(m)n(ultifunction)i(cards)e(ha)n(ving)0 929 y(a)36 b
+Fh(CISTPL_LONGLINK_)o(MFC)30 b Fm(tuple,)39 b(these)e(functions)g(will)
+f(automatically)g(follo)n(w)g(just)h(the)g(CIS)f(c)n(hain)g(sp)r
+(eci\034c)h(to)f(a)0 1043 y(clien)n(t)28 b(driv)n(er's)e(assigned)g
+(function.)37 b(If)28 b(a)g(clien)n(t)f(w)n(as)g(b)r(ound)h(to)f
+Fh(BIND_FN_ALL)p Fm(,)c(then)28 b(all)f(tuples)h(will)g(b)r(e)g
+(returned.)0 1199 y(The)g(follo)n(wing)e(\035ags)h(can)g(b)r(e)h(sp)r
+(eci\034ed)g(in)f Fh(Attributes)p Fm(:)0 1438 y Fh(TUPLE_RETURN_LIN)o
+(K)208 1585 y Fm(Indicates)74 b(that)h(link)h(tuples)f(\()p
+Fh(CISTPL_LONGLINK_)o(A)p Fm(,)69 b Fh(CISTPL_LONGLINK_)o(C)p
+Fm(,)g Fh(CISTPL_LONGLINK_)o(MF)o(C)p Fm(,)208 1699 y
+Fh(CISTPL_NOLINK)p Fm(,)13 b Fh(CISTPL_LINKTARGET)o Fm(\))h(should)k(b)
+r(e)i(returned.)34 b(Normally)18 b(these)h(tuples)g(are)f(pro)r(cessed)
+g(silen)n(tly)-7 b(.)0 1879 y Fh(TUPLE_RETURN_COM)o(MO)o(N)208
+2026 y Fm(Indicates)29 b(that)g(tuples)h(in)f(the)h(\020common\021)35
+b(CIS)29 b(section)g(of)g(a)g(m)n(ultifunction)i(CIS)e(should)g(b)r(e)h
+(returned.)41 b(In)30 b(the)208 2139 y(absence)f(of)g(this)h(\035ag,)g
+(normally)-7 b(,)29 b(Card)g(Services)g(will)h(only)g(return)f(tuples)h
+(sp)r(eci\034c)g(to)g(the)g(function)g(b)r(ound)g(to)208
+2253 y(the)e(clien)n(t.)0 2492 y(Return)g(co)r(des:)0
+2715 y Fh(CS_BAD_HANDLE)208 2862 y Fm(The)f(clien)n(t)h(handle)f(is)h
+(in)n(v)-5 b(alid.)0 3042 y Fh(CS_OUT_OF_RESOUR)o(CE)208
+3189 y Fm(Card)26 b(Services)h(w)n(as)f(unable)i(to)f(set)h(up)g(a)f
+(memory)g(windo)n(w)g(to)g(map)h(the)g(card's)e(CIS.)0
+3369 y Fh(CS_NO_MORE_ITEMS)208 3515 y Fm(There)h(w)n(ere)f(no)h(tuples)
+h(matc)n(hing)f Fh(DesiredTuple)p Fm(.)0 3788 y Ff(3.4.2)94
+b(GetT)-8 b(upleData)208 3979 y Fd(#include)41 b("cistpl.h")208
+4187 y(int)e(CardServices\(GetTupleData,)45 b(client_handle_t)e
+(client,)e(tuple_t)f(*tuple\);)0 4427 y Fh(GetTupleData)23
+b Fm(extracts)k(a)h(series)e(of)i(data)g(b)n(ytes)f(from)h(the)g(sp)r
+(eci\034ed)h(tuple,)f(whic)n(h)g(m)n(ust)g(ha)n(v)n(e)f(b)r(een)h
+(returned)g(b)n(y)f(a)0 4540 y(previous)h(call)h(to)g
+Fh(GetFirstTuple)24 b Fm(or)29 b Fh(GetNextTuple)p Fm(.)37
+b(A)30 b(maxim)n(um)f(of)h Fh(TupleDataMax)24 b Fm(b)n(ytes)29
+b(will)h(b)r(e)f(copied)g(in)n(to)0 4654 y(the)h Fh(TupleData)d
+Fm(bu\033er,)j(starting)f(at)h(an)g(o\033set)g(of)g Fh(TupleOffset)25
+b Fm(b)n(ytes.)44 b(The)30 b(n)n(um)n(b)r(er)g(of)f(b)n(ytes)h(copied)g
+(is)g(returned)0 4767 y(in)e Fh(TupleDataLen)p Fm(.)0
+4924 y(Return)g(co)r(des:)0 5147 y Fh(CS_BAD_HANDLE)208
+5294 y Fm(The)f(clien)n(t)h(handle)f(is)h(in)n(v)-5 b(alid.)p
+eop
+%%Page: 22 22
+22 21 bop 0 -167 3900 5 v 0 -200 a Ff(3.)73 b(Card)33
+b(Services)f(Subfunction)g(Descriptions)2008 b Fm(22)0
+162 y Fh(CS_OUT_OF_RESOUR)o(CE)208 308 y Fm(Card)26 b(Services)h(w)n
+(as)f(unable)i(to)f(set)h(up)g(a)f(memory)g(windo)n(w)g(to)g(map)h(the)
+g(card's)e(CIS.)0 488 y Fh(CS_NO_MORE_ITEMS)208 635 y
+Fm(The)f(tuple)g(do)r(es)g(not)g(con)n(tain)g(an)n(y)f(more)h(data.)35
+b Fh(TuppleOffset)20 b Fm(is)25 b(greater)f(than)h(or)f(equal)h(to)g
+(the)g(length)h(of)f(the)208 749 y(tuple.)0 1021 y Ff(3.4.3)94
+b(P)m(arseT)-8 b(uple)208 1212 y Fd(#include)41 b("cistpl.h")208
+1421 y(int)e(CardServices\(ParseTuple,)45 b(client_handle_t)d(client,)f
+(tuple_t)g(*tuple,)g(cisparse_t)g(*parse\);)0 1660 y
+Fm(The)28 b Fh(cisparse_t)23 b Fm(data)k(structure)g(is)h(giv)n(en)e(b)
+n(y:)208 1873 y Fd(typedef)40 b(union)h(cisparse_t)g({)521
+1978 y(cistpl_device_t)357 b(device;)521 2082 y(cistpl_checksum_t)279
+b(checksum;)521 2186 y(cistpl_longlink_t)g(longlink;)521
+2290 y(cistpl_longlink_mfc_t)123 b(longlink_mfc;)521
+2394 y(cistpl_vers_1_t)357 b(version_1;)521 2498 y(cistpl_altstr_t)g
+(altstr;)521 2602 y(cistpl_jedec_t)396 b(jedec;)521 2706
+y(cistpl_manfid_t)357 b(manfid;)521 2810 y(cistpl_funcid_t)g(funcid;)
+521 2915 y(cistpl_config_t)g(config;)521 3019 y(cistpl_cftable_entry_t)
+84 b(cftable_entry;)521 3123 y(cistpl_device_geo_t)201
+b(device_geo;)521 3227 y(cistpl_vers_2_t)357 b(version_2;)521
+3331 y(cistpl_org_t)474 b(org;)208 3435 y(})39 b(cisparse_t;)0
+3658 y Fh(ParseTuple)32 b Fm(in)n(terprets)k(tuple)h(data)f(returned)g
+(b)n(y)g(a)h(previous)e(call)h(to)g Fh(GetTupleData)p
+Fm(.)59 b(The)37 b(structure)f(returned)0 3772 y(dep)r(ends)27
+b(on)f(the)h(t)n(yp)r(e)f(of)h(the)g(parsed)e(tuple.)37
+b(See)27 b(the)f Fh(cistpl.h)e Fm(\034le)i(for)g(these)g(structure)g
+(de\034nitions;)h(some)f(of)h(them)0 3885 y(are)g(quite)g(complex.)0
+4042 y(Return)h(co)r(des:)0 4265 y Fh(CS_BAD_TUPLE)208
+4411 y Fm(An)20 b(error)e(w)n(as)g(encoun)n(ted)i(during)f(parsing)f
+(of)i(this)g(tuple.)35 b(The)20 b(tuple)g(ma)n(y)f(b)r(e)h(incomplete,)
+h(or)e(ma)n(y)g(b)r(e)h(formatted)208 4525 y(incorrectly)-7
+b(.)0 4705 y Fh(CS_UNSUPPORTED_F)o(UN)o(CTI)o(ON)208
+4852 y(ParseTuple)23 b Fm(cannot)k(parse)f(the)i(sp)r(eci\034ed)g
+(tuple)g(t)n(yp)r(e.)0 5124 y Ff(3.4.4)94 b(V)-8 b(alidateCIS)208
+5315 y Fd(int)39 b(CardServices\(ValidateCIS,)45 b(client_handle_t)e
+(client,)d(cisinfo_t)i(*cisinfo\);)p eop
+%%Page: 23 23
+23 22 bop 0 -167 3900 5 v 0 -200 a Ff(3.)73 b(Card)33
+b(Services)f(Subfunction)g(Descriptions)2008 b Fm(23)0
+162 y(The)28 b Fh(cisinfo_t)23 b Fm(structure)k(is)h(giv)n(en)f(b)n(y:)
+208 361 y Fd(typedef)40 b(struct)h(cisinfo_t)g({)521
+465 y(u_int)433 b(Chains;)208 569 y(})39 b(cisinfo_t;)0
+778 y Fh(ValidateCIS)29 b Fm(attempts)k(to)g(v)n(erify)f(that)i(a)e
+(card)h(has)f(a)h(reasonable)e(Card)h(Information)h(Structure.)53
+b(It)33 b(returns)g(the)0 892 y(n)n(um)n(b)r(er)27 b(of)h(tuples)g
+(found)g(in)f Fh(Chains)p Fm(.)35 b(If)28 b(the)g(CIS)f(app)r(ears)g
+(to)g(b)r(e)h(unin)n(terpretable,)f Fh(Chains)e Fm(will)j(b)r(e)g(set)f
+(to)h(0.)0 1048 y(Return)g(co)r(des:)0 1257 y Fh(CS_BAD_HANDLE)208
+1401 y Fm(The)f(clien)n(t)h(handle)f(is)h(in)n(v)-5 b(alid.)0
+1574 y Fh(CS_OUT_OF_RESOUR)o(CE)208 1717 y Fm(Card)26
+b(Services)h(w)n(as)f(unable)i(to)f(set)h(up)g(a)f(memory)g(windo)n(w)g
+(to)g(map)h(the)g(card's)e(CIS.)0 1987 y Ff(3.4.5)94
+b(ReplaceCIS)208 2174 y Fd(int)39 b(CardServices\(ReplaceCIS,)45
+b(client_handle_t)d(client,)f(cisdump_t)g(*cisinfo\);)0
+2396 y Fm(The)28 b Fh(cisdump_t)23 b Fm(structure)k(is)h(giv)n(en)f(b)n
+(y:)208 2596 y Fd(typedef)40 b(struct)h(cisdump_t)g({)521
+2700 y(u_int)433 b(Length;)521 2804 y(cisdata_t)277 b
+(Data[CISTPL_MAX_CIS_SIZE];)208 2908 y(})39 b(cisinfo_t;)0
+3117 y Fh(ReplaceCIS)26 b Fm(allo)n(ws)j(a)h(clien)n(t)g(to)h(pass)e
+(Card)h(Services)f(a)h(replacemen)n(t)f(for)h(the)h(CIS)f(found)h(on)f
+(a)g(card.)44 b(Its)31 b(in)n(tended)0 3231 y(application)23
+b(is)g(for)h(cards)e(with)i(incomplete)g(or)f(inaccurate)f(CIS)i
+(information.)35 b(If)24 b(a)f(correct)f(CIS)i(can)g(b)r(e)g(deduced)f
+(from)0 3344 y(other)33 b(information)h(a)n(v)-5 b(ailable)32
+b(for)i(the)g(card,)h(this)f(allo)n(ws)f(that)h(information)g(to)g(b)r
+(e)g(pro)n(vided)f(to)h(clien)n(ts)g(in)g(a)g(clean)0
+3458 y(fashion.)43 b(The)29 b(alternativ)n(e)g(is)g(to)h(p)r(ollute)g
+(clien)n(t)f(source)g(co)r(de)g(with)h(\034xes)g(targeted)e(for)h(eac)n
+(h)g(card)g(with)h(a)f(CIS)h(error.)0 3572 y(The)i(replacemen)n(t)g
+(CIS)g(remains)g(in)h(e\033ect)f(un)n(til)h(the)g(card)e(is)i(ejected,)
+h(and)e(all)g(tuple-related)g(services)f(will)h(use)h(the)0
+3685 y(replacemen)n(t)27 b(instead)g(of)h(the)f(card's)g(actual)g(CIS.)
+0 3842 y(The)35 b Fh(Length)d Fm(\034eld)k(giv)n(es)d(the)j(n)n(um)n(b)
+r(er)e(of)h(b)n(ytes)g(of)f(CIS)h(data)g(in)g(the)g Fh(Data)f
+Fm(arra)n(y)-7 b(.)56 b(The)35 b Fh(Data)e Fm(arra)n(y)g(can)i(b)r(e)g
+(con-)0 3955 y(sidered)30 b(to)g(b)r(e)g(just)h(the)f(ev)n(en)g(b)n
+(ytes)g(of)g(a)g(card's)f(attribute)h(memory)-7 b(.)44
+b(It)31 b(should)e(con)n(tain)h(all)g(required)f(features)g(of)h(a)0
+4069 y(normal)e(CIS,)h(including)f(an)h(initial)g Fh(CISTPL_DEVICE)23
+b Fm(tuple)29 b(and)g(a)f(\034nal)h Fh(CISTPL_END)24
+b Fm(tuple.)41 b(Long)28 b(links)h(\(including)0 4182
+y Fh(CISTPL_LONGLINK_)o(MF)o(C)p Fm(\))i(ma)n(y)k(b)r(e)i(used:)54
+b(all)36 b(target)f(addresses)g(are)g(in)n(terpreted)h(in)g(the)h
+(replacemen)n(t)e(CIS)i(space.)0 4296 y(In)h(general,)i(a)e(replacemen)
+n(t)f(CIS)i(should)f(also)f(con)n(tain)h(the)g(same)g(basic)g(iden)n
+(ti\034cation)g(tuples)g(\()p Fh(CISTPL_MANFID)p Fm(,)0
+4409 y Fh(CISTPL_VERS_1)p Fm(\))22 b(as)27 b(the)h(original)e(card.)0
+4566 y(This)i(service)e(w)n(as)h(added)g(in)h(release)e(3.0.1.)0
+4722 y(Return)i(co)r(des:)0 4931 y Fh(CS_BAD_HANDLE)208
+5075 y Fm(The)f(clien)n(t)h(handle)f(is)h(in)n(v)-5 b(alid.)0
+5248 y Fh(CS_OUT_OF_RESOUR)o(CE)208 5391 y Fm(Card)26
+b(Services)h(w)n(as)f(unable)i(to)f(allo)r(cate)g(memory)g(to)g(hold)h
+(the)f(replacemen)n(t)g(CIS.)p eop
+%%Page: 24 24
+24 23 bop 0 -167 3900 5 v 0 -200 a Ff(3.)73 b(Card)33
+b(Services)f(Subfunction)g(Descriptions)2008 b Fm(24)0
+162 y Fe(3.5)112 b(Memory)37 b(windo)m(w)g(con)m(trol)0
+372 y Fm(Eac)n(h)31 b(so)r(c)n(k)n(et)e(can)i(ha)n(v)n(e)f(up)h(to)g
+(four)f(activ)n(e)g(memory)g(windo)n(ws,)h(mapping)g(p)r(ortions)f(of)h
+(card)e(memory)i(in)n(to)f(the)h(host)0 485 y(system)24
+b(address)e(space.)35 b(A)24 b(PC)g(Card)f(device)h(can)f(address)g(at)
+h(most)f(16MB)g(of)h(b)r(oth)g(common)f(and)h(attribute)g(memory)-7
+b(.)0 599 y(Windo)n(ws)30 b(should)g(t)n(ypically)g(b)r(e)g(sized)g(to)
+h(a)f(p)r(o)n(w)n(er)f(of)h(t)n(w)n(o.)44 b(Dep)r(ending)31
+b(on)f(so)r(c)n(k)n(et)f(capabilities,)i(they)f(ma)n(y)g(need)g(to)0
+712 y(b)r(e)e(aligned)f(on)g(a)g(b)r(oundary)g(that)h(is)f(a)h(m)n
+(ultiple)g(of)f(the)h(windo)n(w)f(size)g(in)h(b)r(oth)g(the)g(host)f
+(and)h(card)e(address)h(spaces.)0 869 y(A)e(memory)f(windo)n(w)g(is)h
+(initialized)g(b)n(y)f(a)g(call)h(to)f Fh(RequestWindow)p
+Fm(.)31 b(Some)24 b(windo)n(w)g(attributes)h(can)f(b)r(e)h(mo)r
+(di\034ed)g(using)0 983 y Fh(ModifyWindow)p Fm(.)k(The)20
+b(segmen)n(t)f(of)h(card)e(memory)h(mapp)r(ed)h(to)g(the)g(windo)n(w)f
+(can)g(b)r(e)h(mo)r(di\034ed)g(using)f Fh(MapMemPage)p
+Fm(.)31 b(And)0 1096 y(windo)n(ws)24 b(are)g(released)g(with)i
+Fh(ReleaseWindow)p Fm(.)k(Unlik)n(e)25 b(almost)g(all)g(other)f(Card)h
+(Services)f(subfunctions,)h(the)h(memory)0 1210 y(windo)n(w)h
+(functions)h(normally)e(act)i(on)f Fh(window_handle_t)21
+b Fm(handles,)27 b(rather)g(than)h Fh(client_handle_t)21
+b Fm(handles.)0 1480 y Ff(3.5.1)94 b(RequestWindo)m(w)208
+1669 y Fd(int)39 b(CardServices\(RequestWindow,)46 b(client_handle_t)c
+(*handle,)f(win_req_t)g(*req\);)0 1898 y Fm(The)28 b
+Fh(win_req_t)23 b Fm(structure)k(is)h(giv)n(en)f(b)n(y:)208
+2102 y Fd(typedef)40 b(struct)h(win_req_t)g({)521 2206
+y(u_int)433 b(Attributes;)521 2310 y(u_long)394 b(Base;)521
+2415 y(u_int)433 b(Size;)521 2519 y(u_int)g(AccessSpeed;)208
+2623 y(})39 b(win_req_t;)0 2837 y Fh(RequestWindow)32
+b Fm(maps)k(a)h(windo)n(w)g(of)g(card)f(memory)g(in)n(to)h(system)g
+(memory)-7 b(.)65 b(On)36 b(en)n(try)-7 b(,)39 b(the)f
+Fh(handle)d Fm(parameter)0 2950 y(should)c(p)r(oin)n(t)g(to)g(a)f(v)-5
+b(alid)31 b(clien)n(t)g(handle.)47 b(On)31 b(return,)g(this)g(will)h(b)
+r(e)f(replaced)f(b)n(y)h(a)f Fh(window_handle_t)25 b
+Fm(handle)31 b(that)0 3064 y(should)c(b)r(e)h(used)g(in)g(subsequen)n
+(t)f(calls)g(to)g Fh(ModifyWindow)p Fm(,)c Fh(MapMemPage)p
+Fm(,)g(and)28 b Fh(ReleaseWindow)p Fm(.)0 3220 y(The)g(follo)n(wing)e
+(\035ags)h(can)g(b)r(e)h(sp)r(eci\034ed)g(in)f Fh(Attributes)p
+Fm(:)0 3435 y Fh(WIN_MEMORY_TYPE)208 3579 y Fm(This)33
+b(\034eld)h(can)f(b)r(e)h(either)f Fh(WIN_MEMORY_TYPE_)o(CM)27
+b Fm(for)33 b(common)g(memory)-7 b(,)34 b(or)f Fh(WIN_MEMORY_TYPE)o(_A)
+o(M)28 b Fm(for)33 b(at-)208 3693 y(tribute)27 b(memory)-7
+b(.)0 3868 y Fh(WIN_DATA_WIDTH)208 4013 y Fm(Either)28
+b Fh(WIN_DATA_WIDTH_)o(16)21 b Fm(for)27 b(16-bit)g(accesses,)f(or)h
+Fh(WIN_DATA_WIDTH_)o(8)21 b Fm(for)27 b(8-bit)h(access.)0
+4188 y Fh(WIN_ENABLE)208 4333 y Fm(If)g(this)f(is)h(set,)g(the)f(windo)
+n(w)g(is)h(turned)g(on.)0 4509 y Fh(WIN_USE_WAIT)208
+4653 y Fm(Sp)r(eci\034es)f(that)h(the)g(con)n(troller)e(should)h
+(observ)n(e)f(the)i(card's)e(MW)-9 b(AIT)28 b(signal.)0
+4829 y Fh(WIN_MAP_BELOW_1M)o(B)208 4973 y Fm(Requests)e(that)g(the)h
+(windo)n(w)f(b)r(e)g(mapp)r(ed)h(b)r(elo)n(w)f(the)h(1MB)f(address)f(b)
+r(oundary)-7 b(.)35 b(This)27 b(ma)n(y)e(not)i(b)r(e)f(p)r(ossible)g
+(on)208 5087 y(some)h(platforms.)0 5263 y Fh(WIN_STRICT_ALIGN)208
+5407 y Fm(Requests)g(that)h(the)g(windo)n(w)f(base)g(b)r(e)g(aligned)g
+(to)h(a)f(m)n(ultiple)h(of)g(the)g(windo)n(w)f(size.)36
+b(A)n(dded)28 b(in)g(release)e(3.1.2.)p eop
+%%Page: 25 25
+25 24 bop 0 -167 3900 5 v 0 -200 a Ff(3.)73 b(Card)33
+b(Services)f(Subfunction)g(Descriptions)2008 b Fm(25)0
+162 y Fh(Base)21 b Fm(sp)r(eci\034es)h(the)h(base)e(ph)n(ysical)h
+(address)f(of)h(the)g(windo)n(w)g(in)h(system)f(memory)-7
+b(.)34 b(If)23 b(zero,)f(Card)g(Services)f(will)h(set)h
+Fh(Base)0 275 y Fm(to)32 b(the)h(\034rst)g(a)n(v)-5 b(ailable)31
+b(windo)n(w)h(address.)50 b Fh(Size)31 b Fm(sp)r(eci\034es)i(the)g
+(windo)n(w)f(size)g(in)h(b)n(ytes.)51 b(If)33 b(zero,)g(Card)e
+(Services)h(will)0 389 y(set)e Fh(Size)f Fm(to)i(the)f(smallest)g
+(windo)n(w)g(size)g(supp)r(orted)g(b)n(y)h(the)f(host)h(con)n(troller.)
+43 b Fh(AccessSpeed)26 b Fm(sp)r(eci\034es)k(the)h(memory)0
+502 y(access)26 b(sp)r(eed,)i(in)g(nanoseconds.)0 659
+y(Return)g(co)r(des:)0 882 y Fh(CS_BAD_HANDLE)208 1029
+y Fm(The)f(clien)n(t)h(handle)f(is)h(in)n(v)-5 b(alid.)0
+1209 y Fh(CS_NO_CARD)208 1355 y Fm(The)27 b(so)r(c)n(k)n(et)g(assigned)
+f(to)h(this)h(clien)n(t)g(is)f(curren)n(tly)g(v)-5 b(acan)n(t.)0
+1535 y Fh(CS_BAD_ATTRIBUTE)208 1682 y Fm(An)28 b(unsupp)r(orted)f
+(windo)n(w)g(attribute)h(w)n(as)e(requested.)0 1862 y
+Fh(CS_OUT_OF_RESOUR)o(CE)208 2009 y Fm(The)h(maxim)n(um)h(n)n(um)n(b)r
+(er)f(of)g(memory)g(windo)n(ws)g(for)g(this)h(so)r(c)n(k)n(et)e(are)h
+(already)f(b)r(eing)h(used.)0 2189 y Fh(CS_IN_USE)208
+2336 y(RequestWindow)22 b Fm(w)n(as)k(unable)i(to)f(\034nd)h(a)f(free)h
+(windo)n(w)f(of)g(system)g(memory)-7 b(.)0 2516 y Fh(CS_BAD_SIZE)208
+2662 y Fm(,)0 2842 y Fh(CS_BAD_BASE)208 2989 y Fm(Either)28
+b Fh(Base)e Fm(or)g Fh(Size)g Fm(do)r(es)h(not)h(satisfy)f(the)h
+(alignmen)n(t)f(rules)g(for)g(this)h(so)r(c)n(k)n(et.)0
+3262 y Ff(3.5.2)94 b(Mo)s(difyWindo)m(w)208 3453 y Fd(int)39
+b(CardServices\(ModifyWindow,)45 b(window_handle_t)e(handle,)e
+(modwin_t)g(*mod\);)0 3692 y Fm(The)28 b Fh(modwin_t)c
+Fm(structure)j(is)g(giv)n(en)g(b)n(y:)208 3906 y Fd(typedef)40
+b(struct)h(modwin_t)g({)521 4010 y(u_int)433 b(Attributes;)521
+4114 y(u_int)g(AccessSpeed;)208 4218 y(})39 b(modwin_t;)0
+4441 y Fh(ModifyWindow)28 b Fm(mo)r(di\034es)k(the)h(attributes)f(of)h
+(a)f(windo)n(w)g(handle)g(returned)g(b)n(y)g(a)h(previous)e(call)h(to)g
+Fh(RequestWindow)p Fm(.)0 4554 y(The)c(follo)n(wing)e(attributes)h(can)
+h(b)r(e)g(c)n(hanged:)0 4777 y Fh(WIN_MEMORY_TYPE)208
+4924 y Fm(This)33 b(\034eld)h(can)f(b)r(e)h(either)f
+Fh(WIN_MEMORY_TYPE_)o(CM)27 b Fm(for)33 b(common)g(memory)-7
+b(,)34 b(or)f Fh(WIN_MEMORY_TYPE)o(_A)o(M)28 b Fm(for)33
+b(at-)208 5038 y(tribute)27 b(memory)-7 b(.)0 5218 y
+Fh(WIN_DATA_WIDTH)208 5364 y Fm(Either)28 b Fh(WIN_DATA_WIDTH_)o(16)21
+b Fm(for)27 b(16-bit)g(accesses,)f(or)h Fh(WIN_DATA_WIDTH_)o(8)21
+b Fm(for)27 b(8-bit)h(access.)p eop
+%%Page: 26 26
+26 25 bop 0 -167 3900 5 v 0 -200 a Ff(3.)73 b(Card)33
+b(Services)f(Subfunction)g(Descriptions)2008 b Fm(26)0
+162 y Fh(WIN_ENABLE)208 308 y Fm(If)28 b(this)f(is)h(set,)g(the)f
+(windo)n(w)g(is)h(turned)g(on.)0 531 y Fh(AccessSpeed)23
+b Fm(giv)n(es)j(the)i(new)g(memory)f(access)f(sp)r(eed,)i(in)g
+(nanoseconds.)0 688 y(Return)g(co)r(des:)0 911 y Fh(CS_BAD_HANDLE)208
+1058 y Fm(The)f(windo)n(w)g(handle)h(is)f(in)n(v)-5 b(alid.)0
+1330 y Ff(3.5.3)94 b(ReleaseWindo)m(w)208 1521 y Fd(int)39
+b(CardServices\(ReleaseWindow,)46 b(window_handle_t)c(handle\);)0
+1761 y Fh(ReleaseWindow)22 b Fm(releases)k(a)h(memory)g(windo)n(w)g
+(previously)f(allo)r(cated)h(with)h Fh(RequestWindow)p
+Fm(.)0 1917 y(Return)g(co)r(des:)0 2140 y Fh(CS_BAD_HANDLE)208
+2287 y Fm(The)f(windo)n(w)g(handle)h(is)f(in)n(v)-5 b(alid.)0
+2559 y Ff(3.5.4)94 b(GetFirstWindo)m(w,)30 b(GetNextWindo)m(w)208
+2750 y Fd(int)39 b(CardServices\(GetFirstWindow,)46 b(client_handle_t)c
+(*client,)f(win_req_t)g(*req\);)208 2854 y(int)e
+(CardServices\(GetNextWindow,)46 b(window_handle_t)c(*handle,)f
+(win_req_t)g(*req\);)0 3094 y Fm(These)35 b(calls)g(sequen)n(tially)g
+(retriev)n(e)f(windo)n(w)h(con\034guration)e(information)i(for)g(all)g
+(of)h(a)f(so)r(c)n(k)n(et's)f(memory)h(windo)n(ws.)0
+3207 y Fh(GetFirstWindow)27 b Fm(replaces)k(the)j(clien)n(t)e(windo)n
+(w)h(handle)f(with)i(a)e(memory)g(windo)n(w)g(handle,)i(whic)n(h)f
+(will)g(in)g(turn)g(b)r(e)0 3321 y(up)r(dated)28 b(b)n(y)f(calls)g(to)h
+Fh(GetNextWindow)p Fm(.)0 3477 y(These)f(services)f(w)n(ere)h(added)g
+(in)h(release)e(3.1.0.)0 3634 y(Return)i(co)r(des:)0
+3857 y Fh(CS_BAD_HANDLE)208 4004 y Fm(The)f(clien)n(t)h(handle)f(is)h
+(in)n(v)-5 b(alid.)0 4184 y Fh(CS_NO_MORE_ITEMS)208 4330
+y Fm(No)27 b(more)g(windo)n(ws)f(ara)h(con\034gured)f(for)h(this)h(so)r
+(c)n(k)n(et.)0 4603 y Ff(3.5.5)94 b(MapMemP)m(age,)29
+b(GetMemP)m(age)208 4794 y Fd(int)39 b(CardServices\(MapMemPage,)45
+b(window_handle_t)d(handle,)f(memreq_t)g(*req\);)208
+4898 y(int)e(CardServices\(GetMemPage,)45 b(window_handle_t)d(handle,)f
+(memreq_t)g(*req\);)0 5137 y Fm(The)28 b Fh(memreq_t)c
+Fm(structure)j(is)g(giv)n(en)g(b)n(y:)p eop
+%%Page: 27 27
+27 26 bop 0 -167 3900 5 v 0 -200 a Ff(3.)73 b(Card)33
+b(Services)f(Subfunction)g(Descriptions)2008 b Fm(27)208
+162 y Fd(typedef)40 b(struct)h(memreq_t)g({)521 266 y(u_int)433
+b(CardOffset;)521 370 y(page_t)394 b(Page;)208 474 y(})39
+b(memreq_t;)0 697 y Fh(MapMemPage)17 b Fm(sets)j(the)i(address)d(of)i
+(card)f(memory)g(that)h(is)g(mapp)r(ed)g(to)g(the)g(base)g(of)g(a)f
+(memory)g(windo)n(w)g(to)h Fh(CardOffset)p Fm(.)0 810
+y(The)k(windo)n(w)f(should)h(ha)n(v)n(e)e(b)r(een)i(created)f(b)n(y)h
+(a)f(call)h(to)f Fh(RequestWindow)p Fm(.)31 b(The)25
+b Fh(Page)e Fm(parameter)g(is)i(not)g(implemen)n(ted)0
+924 y(in)i(this)g(v)n(ersion)e(and)h(should)g(b)r(e)h(set)g(to)g(0.)36
+b(In)26 b(turn)h Fh(GetMemPage)c Fm(retriev)n(es)i(the)i(curren)n(t)e
+(card)h(address)f(mapping)h(for)g(a)0 1038 y(memory)h(windo)n(w.)0
+1194 y(The)h Fh(GetMemPage)23 b Fm(service)j(w)n(as)h(added)g(in)h
+(release)e(3.1.0.)0 1351 y(Return)i(co)r(des:)0 1573
+y Fh(CS_BAD_HANDLE)208 1720 y Fm(The)f(windo)n(w)g(handle)h(is)f(in)n
+(v)-5 b(alid.)0 1900 y Fh(CS_BAD_PAGE)208 2047 y Fm(The)27
+b Fh(Page)f Fm(v)-5 b(alue)28 b(w)n(as)e(non-zero.)0
+2227 y Fh(CS_BAD_OFFSET)208 2374 y Fm(The)h(requested)g
+Fh(CardOffset)c Fm(w)n(as)k(out)h(of)f(range)f(or)h(did)h(not)f(ha)n(v)
+n(e)g(prop)r(er)f(alignmen)n(t.)0 2665 y Fe(3.6)112 b(Bulk)37
+b(Memory)g(Services)0 2875 y Fm(Bulk)30 b(memory)g(services)f(pro)n
+(vide)g(a)i(higher)e(lev)n(el)h(in)n(terface)g(for)g(accessing)f
+(memory)h(regions)f(than)h(that)h(pro)n(vided)e(b)n(y)0
+2989 y(the)h(memory)e(windo)n(w)h(services.)40 b(A)29
+b(clien)n(t)h(using)e(bulk)i(memory)e(calls)h(do)r(es)f(not)i(need)f
+(to)g(kno)n(w)f(an)n(ything)h(ab)r(out)g(the)0 3103 y(underlying)23
+b(memory)g(organization)e(or)i(access)g(metho)r(ds.)35
+b(The)24 b(device-sp)r(eci\034c)f(co)r(de)h(is)g(pac)n(k)-5
+b(aged)22 b(in)n(to)h(a)h(sp)r(ecial)f(Card)0 3216 y(Services)k(clien)n
+(t)g(called)g(a)h(Memory)e(T)-7 b(ec)n(hnology)26 b(Driv)n(er.)0
+3489 y Ff(3.6.1)94 b(RegisterMTD)208 3680 y Fd(int)39
+b(CardServices\(RegisterMTD,)45 b(client_handle_t)e(handle,)d
+(mtd_reg_t)i(*reg\);)0 3919 y Fm(The)28 b Fh(mtd_reg_t)23
+b Fm(data)28 b(structure)f(is)g(giv)n(en)g(b)n(y:)208
+4133 y Fd(typedef)40 b(union)h(mtd_reg_t)g({)521 4237
+y(u_int)433 b(Attributes;)521 4341 y(u_int)g(Offset;)521
+4445 y(u_long)394 b(MediaID;)208 4549 y(})39 b(mtd_reg_t;)0
+4772 y Fh(RegisterMTD)19 b Fm(informs)k(Card)f(Services)g(that)i(this)f
+(clien)n(t)h(MTD)g(will)f(handle)g(requests)g(for)g(a)f(sp)r(eci\034ed)
+i(memory)e(region.)0 4885 y(The)34 b Fh(Offset)e Fm(\034eld)j(sp)r
+(eci\034es)f(the)h(starting)f(address)f(of)h(the)h(memory)e(region.)57
+b(The)34 b(follo)n(wing)f(\034elds)i(are)e(de\034ned)i(in)0
+4999 y Fh(Attributes)p Fm(:)0 5222 y Fh(REGION_TYPE)208
+5369 y Fm(Either)28 b Fh(REGION_TYPE_CM)21 b Fm(for)27
+b(common)g(memory)-7 b(,)27 b(or)g Fh(REGION_TYPE_AM)22
+b Fm(for)27 b(attribute)g(memory)-7 b(.)p eop
+%%Page: 28 28
+28 27 bop 0 -167 3900 5 v 0 -200 a Ff(3.)73 b(Card)33
+b(Services)f(Subfunction)g(Descriptions)2008 b Fm(28)0
+162 y(The)27 b Fh(MediaID)e Fm(\034eld)i(is)g(recorded)f(b)n(y)h(Card)f
+(Services,)h(and)g(will)g(b)r(e)h(passed)e(to)h(the)h(MTD)f(as)g(part)g
+(of)g(an)n(y)f(request)h(that)0 275 y(references)f(this)i(memory)f
+(region.)0 432 y(Once)f(an)h(MTD)g(is)g(b)r(ound)g(to)g(a)g(memory)f
+(region)f(b)n(y)i(a)f(call)h(to)g Fh(RegisterMTD)p Fm(,)22
+b(it)27 b(will)h(remain)e(b)r(ound)h(un)n(til)g(the)h(MTD)0
+545 y(calls)f Fh(DeregisterClient)o Fm(.)0 702 y(Return)h(co)r(des:)0
+908 y Fh(CS_BAD_HANDLE)208 1051 y Fm(The)f(clien)n(t)h(handle)f(is)h
+(in)n(v)-5 b(alid.)0 1222 y Fh(CS_BAD_OFFSET)208 1365
+y Fm(Either)34 b(the)g(o\033set)f(do)r(es)h(not)f(matc)n(h)h(a)f(v)-5
+b(alid)34 b(memory)f(region)f(for)h(this)h(card,)h(or)e(another)f(MTD)i
+(has)g(already)208 1479 y(registered)26 b(for)h(this)g(region.)0
+1748 y Ff(3.6.2)94 b(GetFirstRegion,)29 b(GetNextRegion)208
+1934 y Fd(int)39 b(CardServices\(GetFirstRegion,)46 b(client_handle_t)c
+(handle,)f(region_info_t)h(*region\);)208 2039 y(int)d
+(CardServices\(GetNextRegion,)46 b(client_handle_t)c(handle,)f
+(region_info_t)h(*region\);)0 2257 y Fm(The)28 b Fh(region_info_t)22
+b Fm(data)27 b(structure)g(is)g(giv)n(en)g(b)n(y:)208
+2454 y Fd(typedef)40 b(union)h(region_info_t)h({)521
+2558 y(u_int)433 b(Attributes;)521 2662 y(u_int)g(CardOffset;)521
+2766 y(u_int)g(RegionSize;)521 2871 y(u_int)g(AccessSpeed;)521
+2975 y(u_int)g(BlockSize;)521 3079 y(u_int)g(PartMultiple;)521
+3183 y(u_char)394 b(JedecMfr,)41 b(JedecInfo;)521 3287
+y(memory_handle_t)i(next;)208 3391 y(})c(region_info_t;)0
+3597 y Fh(GetFirstRegion)15 b Fm(and)20 b Fh(GetNextRegion)15
+b Fm(summarize)k(the)i(information)f(in)h(a)f(card's)f
+Fh(CISTPL_DEVICE)p Fm(,)c Fh(CISTPL_JEDEC)p Fm(,)0 3711
+y(and)30 b Fh(CISTPL_DEVICE_GEO)24 b Fm(tuples.)46 b
+Fh(CardOffset)26 b Fm(giv)n(es)j(the)i(starting)f(address)f(of)i(a)f
+(region.)44 b Fh(RegionSize)26 b Fm(giv)n(es)k(the)0
+3824 y(length)h(of)f(the)h(region)f(in)g(b)n(ytes.)46
+b Fh(AccessSpeed)26 b Fm(giv)n(es)k(the)h(device's)f(cycle)g(time)h(in)
+g(nanoseconds.)44 b Fh(BlockSize)27 b Fm(giv)n(es)0 3938
+y(the)g(erase)e(blo)r(c)n(k)h(size)g(in)h(b)n(ytes,)f(and)g
+Fh(PartMultiple)c Fm(giv)n(es)j(the)i(minim)n(um)g(gran)n(ularit)n(y)c
+(of)k(partitions)e(on)i(this)f(device,)0 4052 y(in)i(units)g(of)f
+Fh(BlockSize)p Fm(.)33 b Fh(JedecMfr)25 b Fm(and)i Fh(JedecInfo)d
+Fm(giv)n(e)j(the)h(JEDEC)g(iden)n(ti\034cation)g(b)n(ytes)f(for)g(this)
+h(region.)0 4208 y(The)g(follo)n(wing)e(\034elds)i(are)e(de\034ned)i
+(in)g Fh(Attributes)p Fm(:)0 4427 y Fh(REGION_TYPE)208
+4569 y Fm(Either)g Fh(REGION_TYPE_CM)21 b Fm(for)27 b(common)g(memory)
+-7 b(,)27 b(or)g Fh(REGION_TYPE_AM)22 b Fm(for)27 b(attribute)g(memory)
+-7 b(.)0 4788 y(When)25 b(these)g(calls)g(are)f(made)g(b)n(y)h(an)g
+(MTD)g(clien)n(t,)h(only)e(regions)g(that)h(ha)n(v)n(e)f(b)r(een)h(b)r
+(ound)g(to)g(this)h(clien)n(t)f(through)f(calls)0 4902
+y(to)j Fh(BindMTD)e Fm(will)j(b)r(e)g(returned.)0 5058
+y(Return)g(co)r(des:)0 5265 y Fh(CS_BAD_HANDLE)208 5407
+y Fm(The)f(clien)n(t)h(handle)f(is)h(in)n(v)-5 b(alid.)p
+eop
+%%Page: 29 29
+29 28 bop 0 -167 3900 5 v 0 -200 a Ff(3.)73 b(Card)33
+b(Services)f(Subfunction)g(Descriptions)2008 b Fm(29)0
+162 y Fh(CS_NO_MORE_ITEMS)208 308 y Fm(No)27 b(more)g(memory)f(regions)
+g(are)h(de\034ned.)0 581 y Ff(3.6.3)94 b(Op)s(enMemory)208
+772 y Fd(int)39 b(CardServices\(OpenMemory,)45 b(client_handle_t)d
+(*handle,)f(open_mem_t)h(*req\);)0 1012 y Fm(The)28 b
+Fh(open_mem_t)23 b Fm(structure)k(is)g(giv)n(en)g(b)n(y:)208
+1225 y Fd(typedef)40 b(struct)h(open_mem_t)g({)521 1329
+y(u_int)433 b(Attributes;)521 1433 y(u_int)g(Offset;)208
+1537 y(})39 b(open_mem_t;)0 1760 y Fh(OpenMemory)26 b
+Fm(is)k(used)g(to)g(obtain)g(a)f(handle)h(for)g(accessing)f(a)g(memory)
+h(region)e(via)i(the)g(other)g(bulk)g(memory)f(services.)0
+1874 y(The)36 b Fh(Offset)e Fm(\034eld)i(sp)r(eci\034es)g(the)g(base)g
+(address)f(of)h(the)g(region)f(to)h(b)r(e)g(accessed.)61
+b(If)37 b(successful,)h(the)e(clien)n(t)g(handle)0 1987
+y(argumen)n(t)26 b(is)i(replaced)f(b)n(y)g(the)h(new)f(memory)g
+(handle.)0 2144 y(The)h(follo)n(wing)e(\034elds)i(are)e(de\034ned)i(in)
+g Fh(Attributes)p Fm(:)0 2367 y Fh(MEMORY_TYPE)208 2513
+y Fm(Either)g Fh(MEMORY_TYPE_CM)21 b Fm(for)27 b(common)g(memory)-7
+b(,)27 b(or)g Fh(MEMORY_TYPE_AM)22 b Fm(for)27 b(attribute)g(memory)-7
+b(.)0 2693 y Fh(MEMORY_EXCLUSIVE)208 2840 y Fm(Sp)r(eci\034es)27
+b(that)h(this)g(clien)n(t)g(should)f(ha)n(v)n(e)f(exclusiv)n(e)h
+(access)f(to)i(this)g(memory)e(region.)0 3063 y(Return)i(co)r(des:)0
+3286 y Fh(CS_BAD_HANDLE)208 3433 y Fm(The)f(windo)n(w)g(handle)h(is)f
+(in)n(v)-5 b(alid.)0 3613 y Fh(CS_BAD_OFFSET)208 3760
+y Fm(Either)33 b(the)g(o\033set)f(do)r(es)g(not)h(sp)r(ecify)g(a)f(v)-5
+b(alid)33 b(region,)f(or)g(the)h(region)e(do)r(es)i(not)f(ha)n(v)n(e)g
+(an)g(asso)r(ciated)f(MTD)i(to)208 3873 y(service)26
+b(bulk)i(memory)e(requests.)0 4146 y Ff(3.6.4)94 b(CloseMemory)208
+4337 y Fd(int)39 b(CardServices\(CloseMemory,)45 b(memory_handle_t)e
+(handle\);)0 4576 y Fh(CloseMemory)24 b Fm(releases)j(a)h(memory)g
+(handle)g(returned)g(b)n(y)g(a)g(previous)g(call)g(to)g
+Fh(OpenMemory)p Fm(.)36 b(A)29 b(clien)n(t)f(should)h(release)0
+4690 y(all)e(memory)g(handles)g(b)r(efore)g(calling)g
+Fh(DeregisterClient)o Fm(.)0 4846 y(Return)h(co)r(des:)0
+5069 y Fh(CS_BAD_HANDLE)208 5216 y Fm(The)f(memory)g(handle)g(is)h(in)n
+(v)-5 b(alid.)p eop
+%%Page: 30 30
+30 29 bop 0 -167 3900 5 v 0 -200 a Ff(3.)73 b(Card)33
+b(Services)f(Subfunction)g(Descriptions)2008 b Fm(30)0
+162 y Ff(3.6.5)94 b(ReadMemory)-8 b(,)29 b(W)-8 b(riteMemory)208
+353 y Fd(int)39 b(CardServices\(ReadMemory,)45 b(memory_handle_t)d
+(handle)f(mem_op_t)g(*req,)f(caddr_t)h(buf\);)208 457
+y(int)e(CardServices\(WriteMemory,)45 b(memory_handle_t)e(handle,)d
+(mem_op_t)h(*req,)g(caddr_t)f(buf\);)0 696 y Fm(The)28
+b Fh(mem_io_t)c Fm(structure)j(is)g(giv)n(en)g(b)n(y:)208
+910 y Fd(typedef)40 b(struct)h(mem_op_t)g({)521 1014
+y(u_int)433 b(Attributes;)521 1118 y(u_int)g(Offset;)521
+1222 y(u_int)g(Count;)208 1326 y(})39 b(mem_op_t;)0 1549
+y Fh(ReadMemory)23 b Fm(and)j Fh(WriteMemory)c Fm(read)k(from)g(and)h
+(write)f(to)h(a)f(card)g(memory)g(area)f(de\034ned)i(b)n(y)f(the)h(sp)r
+(eci\034ed)g(memory)0 1663 y(handle,)i(returned)g(b)n(y)f(a)h(previous)
+e(call)i(to)g Fh(OpenMemory)p Fm(.)36 b(The)29 b Fh(Offset)e
+Fm(\034eld)i(giv)n(es)f(the)h(o\033set)g(of)f(the)i(op)r(eration)d
+(from)0 1776 y(the)h(start)f(of)h(the)g(card)f(memory)g(region.)37
+b(The)28 b Fh(Count)d Fm(\034eld)k(giv)n(es)d(the)i(n)n(um)n(b)r(er)g
+(of)g(b)n(ytes)f(to)h(b)r(e)g(transferred.)36 b(The)28
+b Fh(buf)0 1890 y Fm(\034eld)j(p)r(oin)n(ts)f(to)g(a)g(host)g(memory)f
+(bu\033er)i(to)f(b)r(e)h(the)g(destination)f(for)f(a)h
+Fh(ReadMemory)d Fm(op)r(eration,)i(or)h(the)h(source)e(for)g(a)0
+2003 y Fh(WriteMemory)23 b Fm(op)r(eration.)0 2160 y(The)28
+b(follo)n(wing)e(\034elds)i(are)e(de\034ned)i(in)g Fh(Attributes)p
+Fm(:)0 2383 y Fh(MEM_OP_BUFFER)208 2529 y Fm(Either)22
+b Fh(MEM_OP_BUFFER_U)o(SE)o(R)16 b Fm(if)22 b(the)g(host)g(bu\033er)g
+(is)f(in)h(a)f(user)g(memory)g(segmen)n(t,)i(or)d Fh(MEM_OP_BUFFER_KER)
+o(NE)o(L)208 2643 y Fm(if)28 b(the)g(host)f(bu\033er)h(is)f(in)h(k)n
+(ernel)f(memory)-7 b(.)0 2823 y Fh(MEM_OP_DISABLE_E)o(RA)o(SE)208
+2970 y Fm(Sp)r(eci\034es)27 b(that)h(a)f(card)g(area)f(should)h(not)h
+(b)r(e)g(erased)e(b)r(efore)h(it)h(is)g(written.)0 3150
+y Fh(MEM_OP_VERIFY)208 3297 y Fm(Sp)r(eci\034es)f(v)n(eri\034cation)f
+(of)i(write)f(op)r(erations.)0 3519 y(Return)h(co)r(des:)0
+3742 y Fh(CS_BAD_HANDLE)208 3889 y Fm(The)f(windo)n(w)g(handle)h(is)f
+(in)n(v)-5 b(alid.)0 4069 y Fh(CS_BAD_OFFSET)208 4216
+y Fm(The)27 b(sp)r(eci\034ed)h(card)f(o\033set)g(is)h(b)r(ey)n(ond)f
+(the)h(end)g(of)f(the)h(memory)f(region.)0 4396 y Fh(CS_BAD_SIZE)208
+4543 y Fm(The)g(sp)r(eci\034ed)h(transfer)f(size)g(extends)g(past)h
+(the)f(end)h(of)g(the)g(memory)e(region.)0 4815 y Ff(3.6.6)94
+b(RegisterEraseQueue)208 5006 y Fd(int)39 b
+(CardServices\(RegisterEraseQu)q(eue,)46 b(client_handle_t)c(*handle,)f
+(eraseq_hdr_t)h(*header\);)0 5246 y Fm(The)28 b Fh(eraseq_hdr_t)22
+b Fm(structure)27 b(is)h(giv)n(en)e(b)n(y:)p eop
+%%Page: 31 31
+31 30 bop 0 -167 3900 5 v 0 -200 a Ff(3.)73 b(Card)33
+b(Services)f(Subfunction)g(Descriptions)2008 b Fm(31)208
+162 y Fd(typedef)40 b(struct)h(erase_queue_header_t)i({)521
+266 y(int)511 b(QueueEntryCount;)521 370 y(eraseq_entry_t)82
+b(*QueueEntryArray;)208 474 y(})39 b(eraseq_hdr_t;)0
+697 y Fm(This)i(call)f(registers)f(a)i(queue)g(of)f(erase)g(requests)g
+(with)h(Card)f(Services.)76 b(An)41 b Fh(eraseq_handle_t)35
+b Fm(handle)41 b(will)g(b)r(e)0 810 y(returned)26 b(in)g
+Fh(*handle)p Fm(.)34 b(When)26 b(this)h(clien)n(t)f(calls)g
+Fh(CheckEraseQueue)o Fm(,)21 b(Card)k(Services)g(will)i(scan)e(the)i
+(queue)f(and)g(b)r(egin)0 924 y(async)n(hronous)f(pro)r(cessing)h(of)i
+(an)n(y)e(new)i(requests.)0 1081 y(The)g Fh(eraseq_entry_t)21
+b Fm(structure)27 b(is)h(giv)n(en)f(b)n(y:)208 1294 y
+Fd(typedef)40 b(struct)h(eraseq_entry_t)h({)521 1398
+y(memory_handle_t)h(Handle;)521 1502 y(u_char)394 b(State;)521
+1606 y(u_int)433 b(Size;)521 1710 y(u_int)g(Offset;)521
+1814 y(void)472 b(*Optional;)208 1919 y(})39 b(eraseq_entry_t;)0
+2141 y Fm(In)k(an)g(erase)e(queue)i(en)n(try)-7 b(,)46
+b(the)d Fh(Header)e Fm(\034eld)i(should)f(b)r(e)i(a)e(memory)g(handle)h
+(returned)f(b)n(y)h(a)f(previous)g(call)g(to)0 2255 y
+Fh(OpenMemory)p Fm(.)33 b(The)27 b Fh(State)f Fm(\034eld)i(indicates)f
+(the)h(state)f(of)h(the)g(erase)e(request.)36 b(The)28
+b(follo)n(wing)e(v)-5 b(alues)27 b(are)g(de\034ned:)0
+2495 y Fh(ERASE_QUEUED)208 2641 y Fm(Set)h(b)n(y)f(the)h(clien)n(t)f
+(to)h(indicate)f(that)h(this)g(is)g(a)f(new)g(request.)0
+2821 y Fh(ERASE_IDLE)208 2968 y Fm(Set)h(b)n(y)f(the)h(clien)n(t)f(to)h
+(indicate)f(that)h(this)g(en)n(try)f(is)g(not)h(activ)n(e.)0
+3148 y Fh(ERASE_PASSED)208 3295 y Fm(Set)g(b)n(y)f(the)h(MTD)g(to)f
+(indicate)h(successful)f(completion.)0 3475 y Fh(ERASE_FAILED)208
+3622 y Fm(Set)h(b)n(y)f(the)h(MTD)g(to)f(indicate)h(that)g(the)g(erase)
+e(failed.)0 3802 y Fh(ERASE_MEDIA_WRPR)o(OT)208 3948
+y Fm(Indicates)h(that)h(the)g(region)e(is)h(write)h(protected.)0
+4128 y Fh(ERASE_NOT_ERASAB)o(LE)208 4275 y Fm(Indicates)f(that)h(this)f
+(region)g(do)r(es)g(not)g(supp)r(ort)h(erase)e(op)r(erations.)0
+4455 y Fh(ERASE_BAD_OFFSET)208 4602 y Fm(Indicates)h(that)h(the)g
+(erase)e(do)r(es)h(not)h(start)f(on)g(an)g(erase)f(blo)r(c)n(k)h(b)r
+(oundary)-7 b(.)0 4782 y Fh(ERASE_BAD_SIZE)208 4929 y
+Fm(Indicates)27 b(that)h(the)g(requested)e(erase)h(size)g(is)g(not)h(a)
+f(m)n(ultiple)h(of)g(the)g(erase)e(blo)r(c)n(k)h(size.)0
+5109 y Fh(ERASE_BAD_SOCKET)208 5256 y Fm(Set)h(b)n(y)f(the)h(MTD)g(to)f
+(indicate)h(that)g(there)f(is)g(no)h(card)e(presen)n(t.)p
+eop
+%%Page: 32 32
+32 31 bop 0 -167 3900 5 v 0 -200 a Ff(3.)73 b(Card)33
+b(Services)f(Subfunction)g(Descriptions)2008 b Fm(32)0
+162 y(A)n(dditionally)-7 b(,)25 b(the)g(macro)e Fh(ERASE_IN_PROGRES)o
+(S\(\))18 b Fm(will)25 b(return)f(a)g(true)h(condition)f(for)g(v)-5
+b(alues)24 b(of)h Fh(State)d Fm(that)j(indicate)0 275
+y(an)i(erase)f(is)i(b)r(eing)g(pro)r(cessed.)0 432 y(The)d
+Fh(Size)f Fm(\034eld)h(giv)n(es)f(the)i(size)f(of)g(the)h(erase)e
+(request)g(in)i(b)n(ytes.)36 b(The)25 b Fh(Offset)e Fm(\034eld)i(giv)n
+(es)f(the)i(o\033set)f(from)g(the)g(start)g(of)0 545
+y(the)j(region.)36 b(The)27 b(size)h(and)f(o\033set)h(should)f(b)r(e)h
+(aligned)f(to)h(erase)e(blo)r(c)n(k)h(b)r(oundaries.)36
+b(The)28 b Fh(Optional)c Fm(\034eld)k(is)g(not)f(used)0
+659 y(b)n(y)g(Card)g(Services)g(and)g(ma)n(y)g(b)r(e)h(used)f(b)n(y)h
+(the)g(clien)n(t)f(driv)n(er.)0 815 y(Return)h(co)r(des:)0
+1038 y Fh(CS_BAD_HANDLE)208 1185 y Fm(The)f(clien)n(t)h(handle)f(is)h
+(in)n(v)-5 b(alid.)0 1458 y Ff(3.6.7)94 b(DeregisterEraseQueue)208
+1649 y Fd(int)39 b(CardServices\(DeregisterErase)q(Queue)q(,)45
+b(eraseq_handle_t)e(handle\);)0 1888 y Fh(DeregisterEraseQ)o(ue)o(ue)24
+b Fm(frees)29 b(a)h(queue)g(previously)f(registered)f(b)n(y)i(a)f(call)
+h(to)g Fh(RegisterEraseQue)o(ue)o Fm(.)39 b(If)30 b(there)g(are)0
+2002 y(an)n(y)d(p)r(ending)h(requests)e(in)i(the)g(sp)r(eci\034ed)g
+(queue,)f(the)h(call)f(will)h(fail.)0 2158 y(Return)g(co)r(des:)0
+2381 y Fh(CS_BAD_HANDLE)208 2528 y Fm(The)f(erase)f(queue)i(handle)f
+(is)h(in)n(v)-5 b(alid.)0 2708 y Fh(CS_BUSY)208 2855
+y Fm(The)27 b(erase)f(queue)i(has)f(erase)f(requests)h(p)r(ending.)0
+3127 y Ff(3.6.8)94 b(Chec)m(kEraseQueue)208 3318 y Fd(int)39
+b(CardServices\(CheckEraseQueue)q(,)45 b(eraseq_handle_t)d(handle\);)0
+3558 y Fm(This)c(call)h(noti\034es)f(Card)g(Services)f(that)i(there)f
+(are)g(new)g(erase)f(requests)h(in)h(a)f(queue)g(previously)g
+(registered)f(with)0 3671 y Fh(RegisterEraseQue)o(ue)o
+Fm(.)0 3828 y(T)n(ypically)-7 b(,)22 b(a)g(clien)n(t)g(will)g
+(initially)g(assign)f(eac)n(h)g(erase)g(queue)h(en)n(try)f(the)i(state)
+f(v)-5 b(alue)21 b Fh(ERASE_IDLE)p Fm(.)d(When)23 b(new)f(requests)0
+3941 y(are)27 b(added)h(to)g(the)g(queue,)g(the)h(clien)n(t)f(will)g
+(set)g(their)g(states)f(to)h Fh(ERASE_QUEUED)p Fm(,)23
+b(and)28 b(call)g Fh(CheckEraseQueue)o Fm(.)33 b(When)0
+4055 y(the)j(clien)n(t)g(is)g(noti\034ed)g(of)g(an)g(erase)f
+(completion)g(ev)n(en)n(t,)j(it)e(will)h(c)n(hec)n(k)e(the)h(state)g
+(\034eld)g(to)g(determine)g(whether)g(the)0 4168 y(request)27
+b(w)n(as)f(successful.)0 4325 y(Return)i(co)r(des:)0
+4548 y Fh(CS_BAD_HANDLE)208 4694 y Fm(The)f(erase)f(queue)i(handle)f
+(is)h(in)n(v)-5 b(alid.)0 4986 y Fe(3.7)112 b(Miscellaneous)37
+b(calls)0 5196 y Ff(3.7.1)94 b(GetCardServicesInfo)208
+5387 y Fd(int)39 b(CardServices\(GetCardServices)q(Info,)46
+b(servinfo_t)41 b(*info\);)p eop
+%%Page: 33 33
+33 32 bop 0 -167 3900 5 v 0 -200 a Ff(3.)73 b(Card)33
+b(Services)f(Subfunction)g(Descriptions)2008 b Fm(33)0
+162 y(The)28 b Fh(servinfo_t)23 b Fm(structure)k(is)g(giv)n(en)g(b)n
+(y:)208 361 y Fd(typedef)40 b(struct)h(servinfo_t)g({)521
+466 y(char)472 b(Signature[2];)521 570 y(u_int)433 b(Count;)521
+674 y(u_int)g(Revision;)521 778 y(u_int)g(CSLevel;)521
+882 y(char)472 b(*VendorString;)208 986 y(})39 b(servinfo_t;)0
+1195 y Fh(GetCardServicesI)o(nf)o(o)26 b Fm(returns)31
+b(revision)g(information)h(ab)r(out)f(this)i(v)n(ersion)d(of)i(Card)g
+(Services.)49 b Fh(Signature)28 b Fm(is)k(set)0 1309
+y(to)c(\020CS\021.)g Fh(Count)f Fm(is)h(set)h(to)f(the)h(n)n(um)n(b)r
+(er)f(of)g(so)r(c)n(k)n(ets)f(curren)n(tly)h(con\034gured.)38
+b Fh(Revision)25 b Fm(is)j(set)h(to)f(the)h(revision)e(lev)n(el)h(of)0
+1422 y(the)e(Card)e(Services)h(pac)n(k)-5 b(age,)24 b(and)h
+Fh(CSLevel)d Fm(is)k(set)f(to)g(the)h(lev)n(el)f(of)g(compliance)f
+(with)i(the)g(PC)g(Card)e(standard.)35 b(These)0 1536
+y(are)27 b(enco)r(ded)g(as)g(BCD)h(n)n(um)n(b)r(ers.)36
+b Fh(VendorString)23 b Fm(is)k(set)h(to)f(p)r(oin)n(t)h(to)f(an)h(R)n
+(CS)f(iden)n(ti\034cation)g(string.)0 1692 y(This)h(call)f(alw)n(a)n
+(ys)e(succeeds.)0 1962 y Ff(3.7.2)94 b(A)m
+(ccessCon\034gurationRegister)208 2150 y Fd(#include)41
+b("cisreg.h")208 2358 y(int)e(CardServices\(AccessConfigura)q(tionR)q
+(egis)q(ter,)46 b(client_handle_t)c(handle,)f(conf_reg_t)g(*reg\);)0
+2580 y Fm(The)28 b Fh(conf_reg_t)23 b Fm(structure)k(is)g(giv)n(en)g(b)
+n(y:)208 2780 y Fd(typedef)40 b(struct)h(conf_reg_t)g({)521
+2884 y(u_char)394 b(Function;)521 2988 y(u_int)433 b(Action;)521
+3092 y(off_t)g(Offset;)521 3196 y(u_int)g(Value;)208
+3300 y(})39 b(conf_reg_t;)0 3510 y Fm(F)-7 b(or)33 b(normal)g(clien)n
+(ts)h(b)r(ound)g(to)f(a)h(sp)r(eci\034c)g(card)f(function,)j(the)e
+Fh(Function)c Fm(\034eld)k(is)g(ignored.)54 b(F)-7 b(or)33
+b(clien)n(ts)h(b)r(ound)g(to)0 3623 y Fh(BIND_FN_ALL)p
+Fm(,)23 b(this)28 b(\034eld)g(sp)r(eci\034es)f(whic)n(h)h(function's)g
+(con\034guration)d(registers)h(should)h(b)r(e)h(accessed.)0
+3780 y(The)g Fh(Action)d Fm(parameter)h(can)h(b)r(e)h(one)f(of)h(the)g
+(follo)n(wing:)0 3989 y Fh(CS_READ)208 4132 y Fm(Read)f(the)h(sp)r
+(eci\034ed)g(con\034guration)d(register)h(and)i(return)f
+Fh(Value)p Fm(.)0 4305 y Fh(CS_WRITE)208 4449 y Fm(W)-7
+b(rite)27 b Fh(Value)f Fm(to)h(the)h(sp)r(eci\034ed)g(con\034guration)e
+(register.)0 4658 y Fh(AccessConfigurat)o(io)o(nRe)o(gi)o(st)o(er)36
+b Fm(either)42 b(reads)f(or)g(writes)h(the)g(one-b)n(yte)g(CIS)g
+(con\034guration)e(register)h(at)h(o\033set)0 4771 y
+Fh(Offset)26 b Fm(from)i(the)h(start)e(of)i(the)f(con\034g)g(register)f
+(area.)37 b(It)29 b(can)f(only)g(b)r(e)h(used)f(for)g(a)g(so)r(c)n(k)n
+(et)f(that)i(has)f(b)r(een)g(con\034gured)0 4885 y(with)g
+Fh(RequestConfigura)o(ti)o(on)p Fm(.)0 5041 y(The)g(follo)n(wing)e(v)-5
+b(alues)27 b(for)g Fh(Offset)e Fm(are)i(de\034ned)h(in)g
+Fh(cistpl.h)p Fm(:)0 5264 y Fh(CISREG_COR)208 5407 y
+Fm(The)f(Con\034guration)f(Option)h(Register.)p eop
+%%Page: 34 34
+34 33 bop 0 -167 3900 5 v 0 -200 a Ff(3.)73 b(Card)33
+b(Services)f(Subfunction)g(Descriptions)2008 b Fm(34)0
+162 y Fh(CISREG_CCSR)208 308 y Fm(The)27 b(Card)g(Con\034guration)f
+(and)h(Status)h(Register.)0 488 y Fh(CISREG_PRR)208 635
+y Fm(The)f(Pin)h(Replacemen)n(t)g(Register.)0 815 y Fh(CISREG_SCR)208
+962 y Fm(The)f(So)r(c)n(k)n(et)g(and)g(Cop)n(y)g(Register.)0
+1142 y Fh(CISREG_ESR)208 1289 y Fm(The)g(Extended)i(Status)e(Register.)
+0 1469 y Fh(CISREG_IOBASE0)p Ff(..)o Fh(CI)o(SR)o(EG_)o(IO)o(BA)o(SE3)
+208 1616 y Fm(The)g(I/O)g(Base)f(Registers.)0 1796 y
+Fh(CISREG_IOSIZE)208 1942 y Fm(The)h(I/O)g(Size)g(Register.)0
+2182 y(Return)h(co)r(des:)0 2405 y Fh(CS_BAD_HANDLE)208
+2552 y Fm(The)f(clien)n(t)h(handle)f(is)h(in)n(v)-5 b(alid.)0
+2732 y Fh(CS_BAD_ARGS)208 2878 y Fm(The)27 b(sp)r(eci\034ed)h
+Fh(Action)d Fm(is)j(not)f(supp)r(orted.)0 3058 y Fh(CS_CONFIGURATION)o
+(_L)o(OCK)o(ED)208 3205 y Fm(This)g(actually)g(means)g(that)h(the)g
+(con\034guration)e(has)h Ff(not)g Fm(b)r(een)h(lo)r(c)n(k)n(ed.)0
+3385 y Fh(CS_OUT_OF_RESOUR)o(CE)208 3532 y Fm(Card)e(Services)h(w)n(as)
+f(unable)i(to)f(allo)r(cate)g(a)g(memory)g(windo)n(w)g(to)g(access)g
+(the)h(card's)e(con\034guration)g(registers.)0 3804 y
+Ff(3.7.3)94 b(A)m(djustResourceInfo)208 3995 y Fd(int)39
+b(CardServices\(AdjustResourceI)q(nfo,)46 b(client_handle_t)c(handle,)f
+(adjust_t)g(*adj\);)0 4235 y Fm(The)28 b Fh(adjust_t)c
+Fm(structure)j(is)g(giv)n(en)g(b)n(y:)208 4448 y Fd(typedef)40
+b(struct)h(adjust_t)g({)521 4552 y(u_int)433 b(Action;)521
+4657 y(u_int)g(Resource;)521 4761 y(u_int)g(Attributes;)521
+4865 y(union)41 b({)835 4969 y(struct)g(memory)f({)1149
+5073 y(u_long)393 b(Base;)1149 5177 y(u_long)g(Size;)835
+5281 y(})39 b(memory;)835 5385 y(struct)i(io)e({)p eop
+%%Page: 35 35
+35 34 bop 0 -167 3900 5 v 0 -200 a Ff(3.)73 b(Card)33
+b(Services)f(Subfunction)g(Descriptions)2008 b Fm(35)1149
+162 y Fd(ioaddr_t)315 b(BasePort;)1149 266 y(ioaddr_t)g(NumPorts;)1149
+370 y(u_int)432 b(IOAddrLines;)835 474 y(})39 b(io;)835
+578 y(struct)i(irq)e({)1149 682 y(u_int)432 b(IRQ;)835
+786 y(})39 b(irq;)521 890 y(})h(resource;)208 995 y(})f(adjust_t;)0
+1217 y Fh(AdjustResourceIn)o(fo)32 b Fm(is)38 b(used)h(to)f(tell)h
+(Card)f(Services)g(what)g(resources)f(ma)n(y)g(or)h(ma)n(y)g(not)h(b)r
+(e)g(allo)r(cated)e(b)n(y)i(PC)0 1331 y(Card)29 b(devices.)44
+b(The)30 b(normal)f(Lin)n(ux)h(resource)e(managemen)n(t)h(systems)h
+(\(the)h(*_region)c(calls)j(for)f(IO)h(p)r(orts,)g(in)n(terrupt)0
+1445 y(allo)r(cation\))d(are)f(resp)r(ected)i(b)n(y)f(Card)g(Services,)
+f(but)i(this)g(call)f(giv)n(es)g(the)h(user)f(another)f(lev)n(el)h(of)h
+(con)n(trol.)0 1601 y(The)g Fh(Action)d Fm(parameter)h(can)h(ha)n(v)n
+(e)f(the)i(follo)n(wing)f(v)-5 b(alues:)0 1824 y Fh(ADD_MANAGED_RESO)o
+(UR)o(CE)208 1971 y Fm(Place)37 b(the)g(sp)r(eci\034ed)h(resource)d
+(under)i(Card)g(Services)f(con)n(trol,)i(so)f(that)g(it)h(ma)n(y)e(b)r
+(e)i(allo)r(cated)e(b)n(y)h(PC)h(Card)208 2084 y(devices.)0
+2264 y Fh(REMOVE_MANAGED_R)o(ES)o(OUR)o(CE)208 2411 y
+Fm(Remo)n(v)n(e)26 b(the)i(sp)r(eci\034ed)g(resource)d(from)j(Card)e
+(Services)h(con)n(trol.)0 2634 y(A)n(t)20 b(initialization)g(time,)i
+(Card)d(Services)g(assumes)f(that)i(it)h(can)e(use)h(all)g(a)n(v)-5
+b(ailable)18 b(in)n(terrupts,)j(but)f(IO)g(p)r(orts)f(and)h(memory)0
+2748 y(regions)26 b(m)n(ust)i(b)r(e)g(explicitly)f(enabled)h(with)g
+Fh(ADD_MANAGED_RES)o(OU)o(RCE)o Fm(.)0 2904 y(The)g Fh(Resource)c
+Fm(parameter)i(can)h(ha)n(v)n(e)f(the)i(follo)n(wing)f(v)-5
+b(alues:)0 3127 y Fh(RES_MEMORY_RANGE)208 3274 y Fm(Sp)r(eci\034es)27
+b(a)g(memory)g(range)f(resource,)g(describ)r(ed)h(b)n(y)h
+Fh(adj-)p Fc(>)p Fh(resource.m)o(em)o(ory)o Fm(.)0 3454
+y Fh(RES_IO_RANGE)208 3600 y Fm(Sp)r(eci\034es)f(an)h(IO)f(p)r(ort)g
+(resource,)f(describ)r(ed)h(b)n(y)h Fh(adj-)p Fc(>)p
+Fh(resource.i)o(o)p Fm(.)0 3780 y Fh(RES_IRQ)208 3927
+y Fm(Sp)r(eci\034es)f(an)h(in)n(terrupt)f(resource,)f(describ)r(ed)h(b)
+n(y)g Fh(adj-)p Fc(>)p Fh(resource.ir)o(q)p Fm(.)0 4150
+y(The)h(follo)n(wing)e(\035ags)h(ma)n(y)f(b)r(e)i(sp)r(eci\034ed)g(in)g
+Fh(Attributes)p Fm(:)0 4373 y Fh(RES_RESERVED)208 4520
+y Fm(Indicates)k(that)g(the)h(resource)e(should)h(b)r(e)h(reserv)n(ed)d
+(for)i(PC)h(Card)f(devices)g(that)g(sp)r(eci\034cally)g(request)g(it.)
+52 b(The)208 4633 y(resource)28 b(will)i(not)h(b)r(e)f(allo)r(cated)g
+(for)f(a)h(device)g(that)g(asks)f(Card)h(Services)f(for)h(an)n(y)f(a)n
+(v)-5 b(ailable)29 b(lo)r(cation.)44 b(This)30 b(is)208
+4747 y(not)d(implemen)n(ted)h(y)n(et.)0 4970 y(Return)g(co)r(des:)0
+5193 y Fh(CS_UNSUPPORTED_F)o(UN)o(CTI)o(ON)208 5339 y
+Fm(The)f(sp)r(eci\034ed)h Fh(Action)d Fm(or)i Fh(Resource)d
+Fm(is)j(not)h(supp)r(orted.)p eop
+%%Page: 36 36
+36 35 bop 0 -167 3900 5 v 0 -200 a Ff(4.)73 b(Card)33
+b(Information)e(Structure)h(De\034nitions)2019 b Fm(36)0
+162 y Fh(CS_BAD_BASE)208 308 y Fm(The)27 b(sp)r(eci\034ed)h(IO)f
+(address)f(is)i(out)f(of)h(range.)0 488 y Fh(CS_BAD_SIZE)208
+635 y Fm(The)f(sp)r(eci\034ed)h(memory)f(or)f(IO)i(windo)n(w)f(size)g
+(is)g(out)h(of)f(range.)0 815 y Fh(CS_IN_USE)208 962
+y Fm(The)g(sp)r(eci\034ed)h(in)n(terrupt)f(is)h(curren)n(tly)e(allo)r
+(cated)h(b)n(y)g(a)g(Card)g(Services)g(clien)n(t.)0 1235
+y Ff(3.7.4)94 b(Rep)s(ortError)208 1426 y Fd(int)39 b
+(CardServices\(ReportError,)45 b(client_handle_t)e(handle,)d
+(error_info_t)i(*err\);)0 1665 y Fm(The)28 b Fh(error_info_t)22
+b Fm(structure)27 b(is)h(giv)n(en)e(b)n(y:)208 1878 y
+Fd(typedef)40 b(struct)h(error_info_t)h({)521 1983 y(int)511
+b(func;)521 2087 y(int)g(retcode;)208 2191 y(})39 b(error_info_t;)0
+2414 y Fh(ReportError)26 b Fm(generates)j(a)h(k)n(ernel)g(error)f
+(message)g(giv)n(en)g(a)i(Card)e(Services)h(function)h(co)r(de)g(and)f
+(its)h(return)f(co)r(de.)46 b(If)0 2527 y(the)28 b(clien)n(t)g(handle)f
+(is)h(v)-5 b(alid,)27 b(then)h(the)g(error)e(will)i(b)r(e)f(pre\034xed)
+h(with)g(the)g(clien)n(t)f(driv)n(er's)f(name.)37 b(F)-7
+b(or)27 b(example:)208 2757 y Fd(error_info_t)41 b(err)f(=)g({)f
+(RequestIO,)j(CS_BAD_HANDLE)g(};)208 2861 y(CardServices\(ReportError,)
+i(handle,)d(&err\);)0 3101 y Fm(could)27 b(generate)g(the)h(follo)n
+(wing)e(message:)208 3314 y Fd(serial_cs:)41 b(RequestIO:)g(Bad)f
+(handle)0 3537 y Fm(This)28 b(call)f(alw)n(a)n(ys)e(succeeds.)0
+3876 y Fg(4)131 b(Card)44 b(Information)g(Structure)i(De\034nitions)0
+4133 y Fe(4.1)112 b(CIS)37 b(T)-9 b(uple)37 b(De\034nitions)0
+4343 y Fm(The)e(Card)f(Services)g Fh(ParseTuple)d Fm(function)36
+b(in)n(terprets)e(ra)n(w)g(CIS)h(tuple)h(data)e(from)h(a)g(call)f(to)h
+Fh(GetTupleData)30 b Fm(and)0 4457 y(returns)g(the)h(tuple)h(con)n(ten)
+n(ts)e(in)h(a)f(form)h(dep)r(endan)n(t)g(on)f(the)h(tuple)h(t)n(yp)r
+(e.)46 b(This)31 b(section)f(describ)r(es)h(the)g(parsed)f(tuple)0
+4570 y(con)n(ten)n(ts.)208 4800 y Fd(#include)41 b("cistpl.h")p
+eop
+%%Page: 37 37
+37 36 bop 0 -167 3900 5 v 0 -200 a Ff(4.)73 b(Card)33
+b(Information)e(Structure)h(De\034nitions)2019 b Fm(37)0
+162 y Ff(4.1.1)94 b(CISTPL_CHECKSUM)0 372 y Fm(The)28
+b Fh(cistpl_checksum)o(_t)21 b Fm(structure)27 b(is)h(giv)n(en)e(b)n
+(y:)208 585 y Fd(typedef)40 b(struct)h(cistpl_checksum_t)i({)521
+689 y(u_short)355 b(addr;)521 793 y(u_short)g(len;)521
+898 y(u_char)394 b(sum;)208 1002 y(})39 b(cistpl_checksum_t;)0
+1274 y Ff(4.1.2)94 b(CISTPL_LONGLINK_A,)143 b(CISTPL_LONGLINK_C,)g
+(CISTPL_LINKT)-8 b(AR)m(GET,)292 1388 y(CISTPL_NOLINK)0
+1598 y Fm(The)28 b Fh(cistpl_longlink)o(_t)21 b Fm(structure)27
+b(is)h(giv)n(en)e(b)n(y:)208 1811 y Fd(typedef)40 b(struct)h
+(cistpl_longlink_t)i({)521 1915 y(u_int)433 b(addr;)208
+2020 y(})39 b(cistpl_longlink_t;)0 2242 y Fm(These)30
+b(tuples)g(are)f(p)r(oin)n(ters)g(to)h(additional)g(c)n(hains)f(of)h
+(CIS)g(tuples,)h(either)f(in)g(attribute)g(or)f(common)h(memory)-7
+b(.)43 b(Eac)n(h)0 2356 y(CIS)36 b(tuple)g(c)n(hain)f(can)g(ha)n(v)n(e)
+g(at)g(most)h(one)f(long)g(link.)61 b Fh(CISTPL_LONGLINK_)o(A)30
+b Fm(tuples)36 b(p)r(oin)n(t)g(to)f(attribute)h(memory)-7
+b(,)0 2470 y(and)26 b Fh(CISTPL_LONGLINK_)o(C)21 b Fm(tuples)26
+b(p)r(oin)n(t)h(to)f(common)g(memory)-7 b(.)36 b(The)26
+b(standard)f(CIS)i(c)n(hain)f(starting)f(at)i(address)e(0)h(in)0
+2583 y(attribute)31 b(memory)g(has)f(an)h(implied)h(long)e(link)h(to)g
+(address)f(0)h(in)g(common)g(memory)-7 b(.)47 b(A)31
+b Fh(CISTPL_NOLINK)26 b Fm(tuple)31 b(can)0 2697 y(b)r(e)d(used)f(to)h
+(cancel)f(this)h(default)g(link.)0 2853 y(The)h(\034rst)g(tuple)g(of)g
+(a)f(c)n(hain)h(p)r(oin)n(ted)g(to)f(b)n(y)h(a)f(long)h(link)g(m)n(ust)
+g(b)r(e)g(a)f Fh(CISTPL_LINKTARGE)o(T)p Fm(.)23 b(The)29
+b(CS)g(tuple)g(handling)0 2967 y(co)r(de)j(will)g(automatically)f
+(follo)n(w)h(long)f(links)h(and)g(v)n(erify)f(link)i(targets;)g(these)f
+(tuples)g(are)g(normally)f(in)n(visible)g(unless)0 3080
+y(the)d Fh(TUPLE_RETURN_LIN)o(K)21 b Fm(attribute)28
+b(is)g(sp)r(eci\034ed)f(in)h Fh(GetNextTuple)p Fm(.)0
+3353 y Ff(4.1.3)94 b(CISTPL_LONGLINK_MF)m(C)0 3563 y
+Fm(The)28 b Fh(cistpl_longlink)o(_m)o(fc_)o(t)21 b Fm(structure)27
+b(is)h(giv)n(en)f(b)n(y:)208 3776 y Fd(typedef)40 b(struct)h
+(cistpl_longlink_mfc_t)j({)521 3881 y(int)197 b(nfn;)521
+3985 y(struct)41 b({)835 4089 y(u_char)80 b(space;)835
+4193 y(u_int)119 b(addr;)521 4297 y(})40 b(fn[CISTPL_MAX_FUNCTIONS;)208
+4401 y(})f(cistpl_longlink_mfc_t;)0 4624 y Fm(This)c(tuple)g(iden)n
+(ti\034es)g(a)g(m)n(ultifunction)h(card,)g(and)e(sp)r(eci\034es)h(long)
+f(link)h(p)r(oin)n(ters)g(to)f(CIS)h(c)n(hains)g(sp)r(eci\034c)g(for)f
+(eac)n(h)0 4738 y(function.)79 b(The)41 b Fh(space)e
+Fm(\034eld)j(is)f(either)g Fh(CISTPL_MFC_ATTR)35 b Fm(or)41
+b Fh(CISTPL_MFC_COMM)o(ON)35 b Fm(for)41 b(attribute)g(or)g(common)0
+4851 y(memory)27 b(space.)0 5124 y Ff(4.1.4)94 b(CISTPL_DEVICE,)32
+b(CISTPL_DEVICE_A)0 5334 y Fm(The)c Fh(cistpl_device_t)21
+b Fm(structure)27 b(is)g(giv)n(en)g(b)n(y:)p eop
+%%Page: 38 38
+38 37 bop 0 -167 3900 5 v 0 -200 a Ff(4.)73 b(Card)33
+b(Information)e(Structure)h(De\034nitions)2019 b Fm(38)208
+162 y Fd(typedef)40 b(struct)h(cistpl_device_t)h({)521
+266 y(int)511 b(ndev;)521 370 y(struct)41 b({)835 474
+y(u_char)394 b(type;)835 578 y(u_char)g(wp;)835 682 y(u_int)433
+b(speed;)835 786 y(u_int)g(size;)521 890 y(})40 b
+(dev[CISTPL_MAX_DEVICES];)208 995 y(})f(cistpl_device_t;)0
+1217 y Fm(The)33 b Fh(CISTPL_DEVICE)28 b Fm(tuple)34
+b(describ)r(es)f(address)f(regions)g(in)i(a)f(card's)f(common)h(memory)
+-7 b(.)54 b(The)33 b Fh(CISTPL_DEVICE_A)0 1331 y Fm(tuple)i(describ)r
+(es)f(regions)f(in)i(attribute)f(memory)-7 b(.)57 b(The)35
+b Fh(type)e Fm(\035ag)h(indicates)g(the)h(t)n(yp)r(e)f(of)h(memory)f
+(device)g(for)g(this)0 1445 y(region.)40 b(The)29 b Fh(wp)g
+Fm(\035ag)f(indicates)h(if)h(this)f(region)f(is)h(write)g(protected.)41
+b(The)29 b Fh(speed)e Fm(\034eld)i(is)g(in)h(nanoseconds,)e(and)h
+Fh(size)0 1558 y Fm(is)e(in)g(b)n(ytes.)37 b(A)n(ddress)26
+b(regions)f(are)h(assumed)h(to)g(b)r(e)g(ordered)f(consecutiv)n(ely)f
+(starting)i(with)g(address)f(0.)36 b(The)27 b(follo)n(wing)0
+1672 y(device)g(t)n(yp)r(es)h(are)e(de\034ned:)0 1911
+y Fh(CISTPL_DTYPE_NUL)o(L)208 2058 y Fm(Sp)r(eci\034es)h(that)h(there)g
+(is)f(no)g(device,)h(or)e(a)h(\020hole\021)34 b(in)28
+b(the)g(card)e(address)h(space.)0 2238 y Fh(CISTPL_DTYPE_ROM)208
+2385 y Fm(Mask)n(ed)f(R)n(OM)0 2565 y Fh(CISTPL_DTYPE_OTP)o(RO)o(M)208
+2712 y Fm(One-t)n(yp)r(e)h(programmable)e(R)n(OM.)0 2892
+y Fh(CISTPL_DTYPE_EPR)o(OM)208 3038 y Fm(UV)j(erasable)e(PR)n(OM.)0
+3218 y Fh(CISTPL_DTYPE_EEP)o(RO)o(M)208 3365 y Fm(Electrically)h
+(erasable)f(PR)n(OM.)0 3545 y Fh(CISTPL_DTYPE_FLA)o(SH)208
+3692 y Fm(Flash)h(EPR)n(OM.)0 3872 y Fh(CISTPL_DTYPE_SRA)o(M)208
+4019 y Fm(Static)g(or)g(non-v)n(olatile)f(RAM.)0 4199
+y Fh(CISTPL_DTYPE_DRA)o(M)208 4345 y Fm(Dynamic)h(or)g(v)n(olatile)f
+(RAM.)0 4525 y Fh(CISTPL_DTYPE_FUN)o(CS)o(PEC)208 4672
+y Fm(Sp)r(eci\034es)20 b(a)f(function-sp)r(eci\034c)h(device,)h(suc)n
+(h)f(as)f(a)g(memory-mapp)r(ed)g(IO)g(device)h(or)f(bu\033er,)j(as)d
+(opp)r(osed)g(to)h(general)208 4786 y(purp)r(ose)27 b(storage.)0
+4966 y Fh(CISTPL_DTYPE_EXT)o(EN)o(D)208 5113 y Fm(Sp)r(eci\034es)g(an)h
+(extended)f(device)h(t)n(yp)r(e.)37 b(This)27 b(t)n(yp)r(e)h(is)f
+(reserv)n(ed)f(for)h(future)h(use.)p eop
+%%Page: 39 39
+39 38 bop 0 -167 3900 5 v 0 -200 a Ff(4.)73 b(Card)33
+b(Information)e(Structure)h(De\034nitions)2019 b Fm(39)0
+162 y Ff(4.1.5)94 b(CISTPL_VERS_1)0 372 y Fm(The)28 b
+Fh(cistpl_vers_1_t)21 b Fm(structure)27 b(is)g(giv)n(en)g(b)n(y:)208
+585 y Fd(typedef)40 b(struct)h(cistpl_vers_1_t)h({)521
+689 y(u_char)394 b(major;)521 793 y(u_char)g(minor;)521
+898 y(int)511 b(ns;)521 1002 y(int)g(ofs[CISTPL_VERS_1_MAX_PROD_STRI)q
+(NGS];)521 1106 y(char)472 b(str[254];)208 1210 y(})39
+b(cistpl_vers_1_t;)0 1433 y Fm(The)29 b Fh(ns)g Fm(\034eld)g(sp)r
+(eci\034es)g(the)h(n)n(um)n(b)r(er)f(of)g(pro)r(duct)h(information)e
+(strings)g(in)i(the)g(tuple.)42 b(The)29 b(string)g(data)g(is)g(con)n
+(tained)0 1546 y(in)f(the)g Fh(str)e Fm(arra)n(y)-7 b(.)35
+b(Eac)n(h)27 b(string)g(is)g(n)n(ull)h(terminated,)g(and)f
+Fh(ofs)f Fm(giv)n(es)h(the)h(o\033set)f(to)h(the)g(start)f(of)g(eac)n
+(h)g(string.)0 1819 y Ff(4.1.6)94 b(CISTPL_AL)-8 b(TSTR)0
+2029 y Fm(The)28 b Fh(cistpl_altstr_t)21 b Fm(structure)27
+b(is)g(giv)n(en)g(b)n(y:)208 2242 y Fd(typedef)40 b(struct)h
+(cistpl_altstr_t)h({)521 2347 y(int)511 b(ns;)521 2451
+y(int)g(ofs[CISTPL_ALTSTR_MAX_STRINGS];)521 2555 y(char)472
+b(str[254];)208 2659 y(})39 b(cistpl_altstr_t;)0 2882
+y Fm(The)28 b Fh(ns)e Fm(\034eld)i(sp)r(eci\034es)g(the)g(n)n(um)n(b)r
+(er)f(of)h(alternate)e(language)g(strings)h(in)h(the)g(tuple.)37
+b(The)28 b(string)e(data)i(is)f(con)n(tained)g(in)0 2995
+y(the)h Fh(str)e Fm(arra)n(y)-7 b(.)35 b(Eac)n(h)27 b(string)g(is)h(n)n
+(ull)f(terminated,)h(and)f Fh(ofs)g Fm(giv)n(es)f(the)i(o\033set)f(to)h
+(the)g(start)f(of)g(eac)n(h)g(string.)0 3268 y Ff(4.1.7)94
+b(CISTPL_JEDEC_C,)33 b(CISTPL_JEDEC_A)0 3478 y Fm(The)28
+b Fh(cistpl_jedec_t)21 b Fm(structure)27 b(is)h(giv)n(en)f(b)n(y:)208
+3691 y Fd(typedef)40 b(struct)h(cistpl_jedec_t)h({)521
+3796 y(int)511 b(nid;)521 3900 y(struct)41 b({)835 4004
+y(u_char)80 b(mfr;)835 4108 y(u_char)g(info;)521 4212
+y(})40 b(id[CISTPL_MAX_DEVICES];)208 4316 y(})f(cistpl_jedec_t;)0
+4539 y Fm(JEDEC)33 b(iden)n(ti\034ers)e(describ)r(e)h(the)g(sp)r
+(eci\034c)g(device)g(t)n(yp)r(e)g(used)f(to)h(implemen)n(t)h(a)e
+(region)g(of)g(card)g(memory)-7 b(.)49 b(The)32 b Fh(nid)0
+4653 y Fm(\034eld)e(sp)r(eci\034es)g(the)h(n)n(um)n(b)r(er)f(of)g
+(JEDEC)h(iden)n(ti\034ers)f(in)g(the)h(tuple.)45 b(There)29
+b(should)h(b)r(e)h(a)f(one-to-one)e(corresp)r(ondence)0
+4766 y(b)r(et)n(w)n(een)f(JEDEC)i(iden)n(ti\034ers)e(and)h(device)f
+(descriptions)g(in)g(the)h(corresp)r(onding)e Fh(CISTPL_DEVICE)c
+Fm(tuple.)0 5039 y Ff(4.1.8)94 b(CISTPL_CONFIG,)32 b(CISTPL_CONFIG_CB)0
+5249 y Fm(The)c Fh(cistpl_config_t)21 b Fm(structure)27
+b(is)g(giv)n(en)g(b)n(y:)p eop
+%%Page: 40 40
+40 39 bop 0 -167 3900 5 v 0 -200 a Ff(4.)73 b(Card)33
+b(Information)e(Structure)h(De\034nitions)2019 b Fm(40)208
+162 y Fd(typedef)40 b(struct)h(cistpl_config_t)h({)521
+266 y(u_char)394 b(last_idx;)521 370 y(u_int)433 b(base;)521
+474 y(u_int)g(rmask[4];)521 578 y(u_char)394 b(subtuples;)208
+682 y(})39 b(cistpl_config_t;)0 905 y Fm(The)28 b Fh(last_idx)d
+Fm(\034eld)k(giv)n(es)e(the)i(index)f(of)g(the)h(highest)f(n)n(um)n(b)r
+(ered)g(con\034guration)f(table)h(en)n(try)-7 b(.)39
+b(The)28 b Fh(base)f Fm(\034eld)h(giv)n(es)0 1019 y(the)j(o\033set)f
+(of)g(a)g(card's)g(con\034guration)e(registers)h(in)i(attribute)f
+(memory)-7 b(.)44 b(The)31 b Fh(rmask)d Fm(arra)n(y)g(is)j(a)e(series)h
+(of)g(bit)h(masks)0 1132 y(indicating)22 b(whic)n(h)h(con\034guration)e
+(registers)g(are)h(presen)n(t.)34 b(Bit)23 b(0)f(of)h
+Fh(rmask[0])c Fm(is)k(for)f(the)h(COR,)g(bit)g(1)f(is)h(for)f(the)h
+(CCSR,)0 1246 y(and)j(so)g(on.)37 b(The)26 b Fh(subtuples)d
+Fm(\034eld)k(giv)n(es)e(the)i(n)n(um)n(b)r(er)g(of)f(b)n(ytes)g(of)h
+(subtuples)g(follo)n(wing)e(the)i(normal)f(tuple)h(con)n(ten)n(ts.)0
+1402 y(F)-7 b(or)27 b Fh(CISTPL_CONFIG_CB)o Fm(,)22 b
+Fh(rmask)j Fm(is)j(unde\034ned,)g(and)f Fh(base)f Fm(p)r(oin)n(ts)i(to)
+f(the)h(CardBus)f(status)g(registers.)0 1675 y Ff(4.1.9)94
+b(CISTPL_BAR)0 1885 y Fm(The)28 b Fh(cistpl_bar_t)22
+b Fm(structure)27 b(is)h(giv)n(en)e(b)n(y:)208 2098 y
+Fd(typedef)40 b(struct)h(cistpl_bar_t)h({)521 2203 y(u_char)394
+b(attr;)521 2307 y(u_int)433 b(size;)208 2411 y(})39
+b(cistpl_long_t;)0 2634 y Fm(A)22 b Fh(CISTPL_BAR)c Fm(tuple)23
+b(describ)r(es)e(the)h(c)n(haracteristics)e(of)i(an)f(address)g(space)g
+(region)g(p)r(oin)n(ted)h(to)g(b)n(y)f(a)h(PCI)g(base)f(address)0
+2747 y(register,)26 b(for)h(CardBus)g(cards.)0 2904 y(The)h(follo)n
+(wing)e(bit)i(\034elds)g(are)e(de\034ned)i(in)g Fh(attr)p
+Fm(:)0 3127 y Fh(CISTPL_BAR_SPACE)208 3273 y Fm(Iden)n(ti\034es)34
+b(the)h(base)f(address)f(register,)i(from)f(1)g(to)h(6.)57
+b(A)35 b(v)-5 b(alue)34 b(of)h(7)f(describ)r(es)g(the)h(card's)e
+(Extension)i(R)n(OM)208 3387 y(space.)0 3567 y Fh(CISTPL_BAR_SPACE)o
+(_I)o(O)208 3714 y Fm(If)28 b(set,)f(this)h(address)e(register)g(maps)i
+(IO)f(space)g(\(as)g(opp)r(osed)g(to)g(memory)g(space\).)0
+3894 y Fh(CISTPL_BAR_PREFE)o(TC)o(H)208 4040 y Fm(If)h(set,)f(this)h
+(region)e(can)h(b)r(e)h(prefetc)n(hed.)37 b(con)n(troller.)0
+4220 y Fh(CISTPL_BAR_CACHE)o(AB)o(LE)208 4367 y Fm(If)28
+b(set,)f(this)h(region)e(is)i(cac)n(heable)e(as)h(w)n(ell)g(as)g
+(prefetc)n(hable.)0 4547 y Fh(CISTPL_BAR_1MEG_)o(MA)o(P)208
+4694 y Fm(If)h(set,)f(this)h(region)e(should)i(only)f(b)r(e)h(mapp)r
+(ed)g(in)n(to)f(the)h(\034rst)f(1MB)g(of)h(the)g(host's)f(ph)n(ysical)f
+(address)h(space.)0 4967 y Ff(4.1.10)93 b(CISTPL_CFT)-8
+b(ABLE_ENTR)g(Y)0 5177 y Fm(The)28 b Fh(cistpl_cftable_)o(en)o(try)o
+(_t)21 b Fm(structure)27 b(is)g(giv)n(en)g(b)n(y:)p eop
+%%Page: 41 41
+41 40 bop 0 -167 3900 5 v 0 -200 a Ff(4.)73 b(Card)33
+b(Information)e(Structure)h(De\034nitions)2019 b Fm(41)208
+162 y Fd(typedef)40 b(struct)h(cistpl_cftable_entry_t)j({)521
+266 y(u_char)394 b(index;)521 370 y(u_char)g(flags;)521
+474 y(u_char)g(interface;)521 578 y(cistpl_power_t)82
+b(vcc,)40 b(vpp1,)g(vpp2;)521 682 y(cistpl_timing_t)j(timing;)521
+786 y(cistpl_io_t)199 b(io;)521 890 y(cistpl_irq_t)160
+b(irq;)521 995 y(cistpl_mem_t)g(mem;)521 1099 y(u_char)394
+b(subtuples;)208 1203 y(})39 b(cistpl_cftable_entry_t;)0
+1424 y Fm(A)d Fh(CISTPL_CFTABLE_E)o(NT)o(RY)29 b Fm(structure)35
+b(describ)r(es)g(a)g(complete)g(op)r(erating)g(mo)r(de)g(for)g(a)h
+(card.)59 b(Man)n(y)35 b(sections)g(are)0 1538 y(optional.)51
+b(The)32 b Fh(index)f Fm(\034eld)h(giv)n(es)f(the)i(con\034guration)e
+(index)i(for)e(this)i(op)r(erating)e(mo)r(de;)k(writing)d(this)h(v)-5
+b(alue)32 b(to)h(the)0 1651 y(card's)26 b(Con\034guration)g(Option)i
+(Register)e(selects)h(this)h(mo)r(de.)37 b(The)28 b(follo)n(wing)e
+(\034elds)i(are)e(de\034ned)i(in)g Fh(flags)p Fm(:)0
+1889 y Fh(CISTPL_CFTABLE_D)o(EF)o(AUL)o(T)208 2035 y
+Fm(Sp)r(eci\034es)f(that)h(this)g(is)f(the)h(default)g(con\034guration)
+e(table)i(en)n(try)-7 b(.)0 2214 y Fh(CISTPL_CFTABLE_B)o(VD)o(S)208
+2361 y Fm(Sp)r(eci\034es)38 b(that)g(this)g(con\034guration)e(implemen)
+n(ts)i(the)h(BVD1)f(and)g(BVD2)g(signals)e(in)i(the)h(Pin)f(Replacemen)
+n(t)208 2474 y(Register.)0 2653 y Fh(CISTPL_CFTABLE_W)o(P)208
+2800 y Fm(Sp)r(eci\034es)27 b(that)g(this)g(con\034guration)e(implemen)
+n(ts)i(the)g(write)g(protect)f(signal)g(in)h(the)g(Pin)h(Replacemen)n
+(t)e(Register.)0 2979 y Fh(CISTPL_CFTABLE_R)o(DY)o(BSY)208
+3125 y Fm(Sp)r(eci\034es)h(that)h(this)g(con\034guration)e(implemen)n
+(ts)i(the)g(Ready/Busy)e(signal)g(in)i(the)g(Pin)g(Replacemen)n(t)g
+(Register.)0 3305 y Fh(CISTPL_CFTABLE_M)o(WA)o(IT)208
+3451 y Fm(Sp)r(eci\034es)f(that)h(the)g Fh(WAIT)e Fm(signal)h(should)g
+(b)r(e)h(observ)n(ed)e(during)h(memory)g(access)f(cycles.)0
+3630 y Fh(CISTPL_CFTABLE_A)o(UD)o(IO)208 3777 y Fm(Sp)r(eci\034es)19
+b(that)h(this)g(con\034guration)d(generates)h(an)h(audio)g(signal)g
+(that)g(can)g(b)r(e)h(routed)f(to)g(the)h(host)f(system)g(sp)r(eak)n
+(er.)0 3956 y Fh(CISTPL_CFTABLE_R)o(EA)o(DON)o(LY)208
+4102 y Fm(Sp)r(eci\034es)27 b(that)h(the)g(card)f(has)g(a)g(memory)g
+(region)f(that)i(is)f(read-only)f(in)i(this)g(con\034guration.)0
+4281 y Fh(CISTPL_CFTABLE_P)o(WR)o(DOW)o(N)208 4428 y
+Fm(Sp)r(eci\034es)f(that)g(this)g(con\034guration)e(supp)r(orts)i(a)f
+(p)r(o)n(w)n(er)g(do)n(wn)g(mo)r(de,)h(via)g(the)g(Card)f
+(Con\034guration)f(and)i(Status)208 4541 y(Register.)0
+4779 y(The)h Fh(cistpl_power_t)21 b Fm(structure)27 b(is)h(giv)n(en)f
+(b)n(y:)208 4991 y Fd(typedef)40 b(struct)h(cistpl_power_t)h({)521
+5095 y(u_char)394 b(present;)521 5199 y(u_char)g(flags;)521
+5303 y(u_int)433 b(param[7];)208 5407 y(})39 b(cistpl_power_t;)p
+eop
+%%Page: 42 42
+42 41 bop 0 -167 3900 5 v 0 -200 a Ff(4.)73 b(Card)33
+b(Information)e(Structure)h(De\034nitions)2019 b Fm(42)0
+162 y(The)36 b Fh(present)c Fm(\034eld)k(is)g(bit)g(mapp)r(ed)g(and)f
+(indicates)g(whic)n(h)h(parameters)d(are)i(presen)n(t)g(for)g(this)h(p)
+r(o)n(w)n(er)e(signal.)60 b(The)0 275 y(follo)n(wing)26
+b(indices)i(are)f(de\034ned:)0 515 y Fh(CISTPL_POWER_VNO)o(M)208
+662 y Fm(The)g(nominal)g(supply)h(v)n(oltage.)0 842 y
+Fh(CISTPL_POWER_VMI)o(N)208 988 y Fm(The)f(minim)n(um)h(supply)g(v)n
+(oltage.)0 1168 y Fh(CISTPL_POWER_VMA)o(X)208 1315 y
+Fm(The)f(maxim)n(um)h(supply)f(v)n(oltage.)0 1495 y Fh
+(CISTPL_POWER_IST)o(AT)o(IC)208 1642 y Fm(The)g(con)n(tin)n(uous)g
+(supply)g(curren)n(t)g(required.)0 1822 y Fh(CISTPL_POWER_IAV)o(G)208
+1969 y Fm(The)g(maxim)n(um)h(curren)n(t)e(a)n(v)n(eraged)f(o)n(v)n(er)h
+(one)h(second.)0 2149 y Fh(CISTPL_POWER_IPE)o(AK)208
+2295 y Fm(The)g(maxim)n(um)h(curren)n(t)e(a)n(v)n(eraged)f(o)n(v)n(er)h
+(10)g(ms.)0 2475 y Fh(CISTPL_POWER_IDO)o(WN)208 2622
+y Fm(The)h(curren)n(t)g(required)f(in)i(p)r(o)n(w)n(er)f(do)n(wn)g(mo)r
+(de.)0 2862 y(V)-7 b(oltages)26 b(are)h(giv)n(en)g(in)h(units)g(of)f
+(10)g(micro)n(v)n(olts.)35 b(Curren)n(ts)26 b(are)h(giv)n(en)f(in)i
+(units)g(of)g(100)e(nanoamp)r(eres.)0 3018 y(The)i Fh(cistpl_timing_t)
+21 b Fm(structure)27 b(is)g(giv)n(en)g(b)n(y:)208 3232
+y Fd(typedef)40 b(cistpl_timing_t)j({)521 3336 y(u_int)433
+b(wait,)40 b(waitscale;)521 3440 y(u_int)433 b(ready,)40
+b(rdyscale;)521 3544 y(u_int)433 b(reserved,)41 b(rsvscale;)208
+3648 y(})e(cistpl_timing_t;)0 3871 y Fm(Eac)n(h)25 b(time)h(consists)e
+(of)h(a)g(base)g(time)h(in)f(nanoseconds,)f(and)h(a)g(scale)g(m)n
+(ultiplier.)36 b(Unsp)r(eci\034ed)26 b(times)f(ha)n(v)n(e)f(v)-5
+b(alues)25 b(of)g(0.)0 4027 y(The)j Fh(cistpl_io_t)23
+b Fm(structure)k(is)g(giv)n(en)g(b)n(y:)208 4241 y Fd(typedef)40
+b(struct)h(cistpl_io_t)g({)521 4345 y(u_char)394 b(flags;)521
+4449 y(int)511 b(nwin;)521 4553 y(struct)41 b({)835 4657
+y(u_int)433 b(base;)835 4761 y(u_int)g(len;)521 4865
+y(})40 b(win[CISTPL_IO_MAX_WIN;)208 4970 y(})f(cistpl_io_t;)0
+5192 y Fm(The)c(n)n(um)n(b)r(er)f(of)g(IO)h(windo)n(ws)e(is)i(giv)n(en)
+e(b)n(y)i Fh(nwin)p Fm(.)56 b(Eac)n(h)34 b(windo)n(w)g(is)h(describ)r
+(ed)f(b)n(y)g(a)g(base)g(address,)h Fh(base)p Fm(,)g(and)f(a)0
+5306 y(length)28 b(in)f(b)n(ytes,)h Fh(len)p Fm(.)35
+b(The)28 b(follo)n(wing)e(bit)j(\034elds)e(are)g(de\034ned)h(in)f
+Fh(flags)p Fm(:)p eop
+%%Page: 43 43
+43 42 bop 0 -167 3900 5 v 0 -200 a Ff(4.)73 b(Card)33
+b(Information)e(Structure)h(De\034nitions)2019 b Fm(43)0
+162 y Fh(CISTPL_IO_LINES_)o(MA)o(SK)208 300 y Fm(The)27
+b(n)n(um)n(b)r(er)g(of)h(IO)f(lines)h(deco)r(ded)f(b)n(y)g(this)h
+(card.)0 464 y Fh(CISTPL_IO_8BIT)208 602 y Fm(Indicates)f(that)h(the)g
+(card)e(supp)r(orts)h(split)h(8-bit)g(accesses)d(to)j(16-bit)f(IO)g
+(registers.)0 765 y Fh(CISTPL_IO_16BIT)208 904 y Fm(Indicates)g(that)h
+(the)g(card)e(supp)r(orts)h(full)i(16-bit)d(accesses)g(to)i(IO)f
+(registers.)0 1102 y(The)h Fh(cistpl_irq_t)22 b Fm(structure)27
+b(is)h(giv)n(en)e(b)n(y:)208 1282 y Fd(typedef)40 b(struct)h
+(cistpl_irq_t)h({)521 1386 y(u_int)433 b(IRQInfo1;)521
+1490 y(u_int)g(IRQInfo2;)208 1594 y(})39 b(cistpl_irq_t;)0
+1784 y Fm(The)28 b(follo)n(wing)e(bit)i(\034elds)g(are)e(de\034ned)i
+(in)g Fh(IRQInfo1)p Fm(:)0 1974 y Fh(IRQ_MASK)208 2112
+y Fm(A)f(sp)r(eci\034c)h(in)n(terrupt)f(n)n(um)n(b)r(er)h(that)f(this)h
+(card)f(should)g(use.)0 2276 y Fh(IRQ_NMI_ID)p Ff(,)g
+Fh(IRQ_IOCK_ID)p Ff(,)g Fh(IRQ_BERR_ID)p Ff(,)f Fh(IRQ_VEND_ID)208
+2414 y Fm(When)19 b Fh(IRQ_INFO2_VALID)12 b Fm(is)18
+b(set,)j(these)d(indicate)h(if)g(a)f(corresp)r(onding)f(sp)r(ecial)h
+(in)n(terrupt)g(signal)g(ma)n(y)f(b)r(e)i(assigned)208
+2528 y(to)g(this)h(card.)33 b(The)20 b(four)f(\035ags)g(are)g(for)g
+(the)h(non-mask)-5 b(able,)20 b(IO)f(c)n(hec)n(k,)i(bus)f(error,)f(and)
+g(v)n(endor)g(sp)r(eci\034c)h(in)n(terrupts.)0 2691 y
+Fh(IRQ_INFO2_VALID)208 2830 y Fm(Indicates)27 b(that)h
+Fh(IRQInfo2)c Fm(con)n(tains)i(a)i(v)-5 b(alid)27 b(bit)h(mask)f(of)h
+(allo)n(w)n(ed)e(in)n(terrupt)h(request)g(n)n(um)n(b)r(ers.)0
+2993 y Fh(IRQ_LEVEL_ID)208 3131 y Fm(Indicates)g(that)h(the)g(card)e
+(supp)r(orts)h(lev)n(el)g(mo)r(de)h(in)n(terrupts.)0
+3295 y Fh(IRQ_PULSE_ID)208 3433 y Fm(Indicates)f(that)h(the)g(card)e
+(supp)r(orts)h(pulse)h(mo)r(de)g(in)n(terrupts.)0 3597
+y Fh(IRQ_SHARE_ID)208 3735 y Fm(Indicates)f(that)h(the)g(card)e(supp)r
+(orts)h(sharing)g(in)n(terrupts.)0 3925 y(If)h Fh(IRQInfo1)c
+Fm(is)k(0,)f(then)h(no)f(in)n(terrupt)h(information)e(is)i(a)n(v)-5
+b(ailable.)0 4081 y(The)28 b Fh(cistpl_mem_t)22 b Fm(structure)27
+b(is)h(giv)n(en)e(b)n(y:)208 4262 y Fd(typedef)40 b(struct)h
+(cistpl_mem_t)h({)521 4366 y(u_char)394 b(nwin;)521 4470
+y(struct)41 b({)835 4574 y(u_int)433 b(len;)835 4678
+y(u_int)g(card_addr;)835 4782 y(u_int)g(host_addr;)521
+4886 y(})40 b(win[CISTPL_MEM_MAX_WIN;)208 4990 y(})f(cistpl_mem_t;)0
+5180 y Fm(The)c(n)n(um)n(b)r(er)f(of)h(memory)f(windo)n(ws)g(is)h(giv)n
+(en)f(b)n(y)g Fh(nwin)p Fm(.)57 b(Eac)n(h)35 b(windo)n(w)f(is)h
+(describ)r(ed)f(b)n(y)h(an)f(address)g(in)h(the)g(card)0
+5294 y(memory)26 b(space,)g Fh(card_addr)p Fm(,)d(an)j(address)f(in)i
+(the)g(host)f(memory)g(space,)g Fh(host_addr)p Fm(,)d(and)j(a)h(length)
+f(in)h(b)n(ytes,)f Fh(len)p Fm(.)36 b(If)0 5407 y(the)28
+b(host)f(address)g(is)g(0,)g(the)h(p)r(osition)f(of)h(the)g(windo)n(w)f
+(is)g(arbitrary)-7 b(.)p eop
+%%Page: 44 44
+44 43 bop 0 -167 3900 5 v 0 -200 a Ff(4.)73 b(Card)33
+b(Information)e(Structure)h(De\034nitions)2019 b Fm(44)0
+162 y Ff(4.1.11)93 b(CISTPL_CFT)-8 b(ABLE_ENTR)g(Y_CB)0
+372 y Fm(The)28 b Fh(cistpl_cftable_)o(en)o(try)o(_c)o(b_)o(t)22
+b Fm(structure)27 b(is)g(giv)n(en)g(b)n(y:)208 585 y
+Fd(typedef)40 b(struct)h(cistpl_cftable_entry_cb_t)k({)521
+689 y(u_char)394 b(index;)521 793 y(u_char)g(flags;)521
+898 y(cistpl_power_t)82 b(vcc,)40 b(vpp1,)g(vpp2;)521
+1002 y(u_char)394 b(io;)521 1106 y(cistpl_irq_t)160 b(irq;)521
+1210 y(u_char)394 b(mem;)521 1314 y(u_char)g(subtuples;)208
+1418 y(})39 b(cistpl_cftable_entry_cb_t;)0 1641 y Fm(A)34
+b Fh(CISTPL_CFTABLE_EN)o(TR)o(Y_C)o(B)28 b Fm(structure)33
+b(describ)r(es)h(a)g(complete)g(op)r(erating)f(mo)r(de)h(for)f(a)h
+(CardBus)f(card.)56 b(Man)n(y)0 1755 y(\034elds)28 b(are)e(iden)n
+(tical)h(to)h(corresp)r(onding)d(\034elds)j(in)g Fh(CISTPL_CFTABLE_)o
+(ENT)o(RY)o Fm(.)0 1911 y(The)c Fh(io)e Fm(and)i Fh(mem)e
+Fm(\034elds)h(sp)r(ecify)h(whic)n(h)f(base)g(address)f(registers)g
+(need)i(to)f(b)r(e)h(initialized)g(for)f(this)g(con\034guration.)34
+b(Bits)23 b(1)0 2025 y(through)h(6)g(corresp)r(ond)f(to)i(the)g(six)f
+(base)g(address)g(registers,)f(and)i(bit)g(7)f(indicates)h(the)g
+(expansion)e(R)n(OM)i(base)f(register.)0 2297 y Ff(4.1.12)93
+b(CISTPL_MANFID)0 2507 y Fm(The)28 b Fh(cistpl_manfid_t)21
+b Fm(structure)27 b(is)g(giv)n(en)g(b)n(y:)208 2721 y
+Fd(typedef)40 b(struct)h(cistpl_manfid_t)h({)521 2825
+y(u_short)355 b(manf;)521 2929 y(u_short)g(card;)208
+3033 y(})39 b(cistpl_manfid_t;)0 3256 y Fm(The)27 b Fh(manf)f
+Fm(\034eld)i(iden)n(ti\034es)f(the)h(card)e(man)n(ufacturer.)36
+b(The)27 b Fh(card)f Fm(\034eld)h(is)g(c)n(hosen)g(b)n(y)g(the)g(v)n
+(endor)f(and)i(should)f(iden)n(tify)0 3369 y(the)h(card)f(t)n(yp)r(e)g
+(and)h(mo)r(del.)0 3642 y Ff(4.1.13)93 b(CISTPL_FUNCID)0
+3852 y Fm(The)28 b Fh(cistpl_funcid_t)21 b Fm(structure)27
+b(is)g(giv)n(en)g(b)n(y:)208 4066 y Fd(typedef)40 b(struct)h
+(cistpl_funcid_t)h({)521 4170 y(u_char)394 b(func;)521
+4274 y(u_char)g(sysinit;)208 4378 y(})39 b(cistpl_funcid_t;)0
+4601 y Fm(The)30 b Fh(func)e Fm(\034eld)i(iden)n(ti\034es)f(the)h(card)
+f(function.)44 b(The)29 b Fh(sysinit)e Fm(\034eld)j(con)n(tains)f(sev)n
+(eral)e(bit-mapp)r(ed)j(\035ags)f(describing)0 4714 y(ho)n(w)e(the)h
+(card)f(should)g(b)r(e)h(con\034gured)e(at)i(b)r(o)r(ot)f(time.)0
+4871 y(The)h(follo)n(wing)e(functions)i(are)e(de\034ned:)0
+5110 y Fh(CISTPL_FUNCID_MU)o(LT)o(I)208 5257 y Fm(A)h(m)n
+(ulti-function)i(card.)p eop
+%%Page: 45 45
+45 44 bop 0 -167 3900 5 v 0 -200 a Ff(4.)73 b(Card)33
+b(Information)e(Structure)h(De\034nitions)2019 b Fm(45)0
+162 y Fh(CISTPL_FUNCID_ME)o(MO)o(RY)208 308 y Fm(A)27
+b(simple)h(memory)f(device.)0 488 y Fh(CISTPL_FUNCID_SE)o(RI)o(AL)208
+635 y Fm(A)g(serial)g(p)r(ort)g(or)g(mo)r(dem)h(device.)0
+815 y Fh(CISTPL_FUNCID_PA)o(RA)o(LLE)o(L)208 962 y Fm(A)f(parallel)g(p)
+r(ort)g(device.)0 1142 y Fh(CISTPL_FUNCID_FI)o(XE)o(D)208
+1289 y Fm(A)g(\034xed)h(disk)f(device.)0 1469 y Fh(CISTPL_FUNCID_VI)o
+(DE)o(O)208 1616 y Fm(A)g(video)h(in)n(terface.)0 1796
+y Fh(CISTPL_FUNCID_NE)o(TW)o(ORK)208 1942 y Fm(A)f(net)n(w)n(ork)g
+(adapter.)0 2122 y Fh(CISTPL_FUNCID_AI)o(MS)208 2269
+y Fm(An)h(auto-incremen)n(ting)e(mass)g(storage)g(device.)0
+2509 y(The)i(follo)n(wing)e(\035ags)h(are)f(de\034ned)i(in)g
+Fh(sysinit)p Fm(:)0 2732 y Fh(CISTPL_SYSINIT_P)o(OS)o(T)208
+2878 y Fm(Indicates)f(that)h(the)g(system)f(should)g(attempt)h(to)g
+(con\034gure)e(this)i(card)f(during)g(its)g(p)r(o)n(w)n(er-on)f
+(initialization.)0 3058 y Fh(CISTPL_SYSINIT_R)o(OM)208
+3205 y Fm(Indicates)h(that)h(the)g(card)e(con)n(tains)h(a)g(system)g
+(expansion)g(R)n(OM)g(that)h(should)f(b)r(e)h(con\034gured)e(at)i(b)r
+(o)r(ot)f(time.)0 3478 y Ff(4.1.14)93 b(CISTPL_DEVICE_GEO)0
+3688 y Fm(The)28 b Fh(cistpl_device_g)o(eo)o(_t)21 b
+Fm(structure)27 b(is)h(giv)n(en)e(b)n(y:)208 3901 y Fd(typedef)40
+b(struct)h(cistpl_device_geo_t)i({)521 4005 y(int)511
+b(ngeo;)521 4109 y(struct)41 b({)835 4213 y(u_char)394
+b(buswidth;)835 4318 y(u_int)433 b(erase_block;)835 4422
+y(u_int)g(read_block;)835 4526 y(u_int)g(write_block;)835
+4630 y(u_int)g(partition;)835 4734 y(u_int)g(interleave;)521
+4838 y(})40 b(geo[CISTPL_MAX_DEVICES];)208 4942 y(})f
+(cistpl_device_geo_t;)0 5165 y Fm(The)31 b Fh(erase_block)p
+Fm(,)c Fh(read_block)p Fm(,)g(and)k Fh(write_block)26
+b Fm(sizes)k(are)g(in)h(units)g(of)f Fh(buswidth)e Fm(b)n(ytes)i(times)
+h Fh(interleave)p Fm(.)0 5279 y(The)d Fh(partition)23
+b Fm(size)28 b(is)f(in)h(units)g(of)g Fh(erase_block)p
+Fm(.)p eop
+%%Page: 46 46
+46 45 bop 0 -167 3900 5 v 0 -200 a Ff(4.)73 b(Card)33
+b(Information)e(Structure)h(De\034nitions)2019 b Fm(46)0
+162 y Ff(4.1.15)93 b(CISTPL_VERS_2)0 372 y Fm(The)28
+b Fh(cistpl_vers_2_t)21 b Fm(structure)27 b(is)g(giv)n(en)g(b)n(y:)208
+555 y Fd(typedef)40 b(struct)h(cistpl_vers_2_t)h({)521
+659 y(u_char)394 b(vers;)521 763 y(u_char)g(comply;)521
+868 y(u_short)355 b(dindex;)521 972 y(u_char)394 b(vspec8,)41
+b(vspec9;)521 1076 y(u_char)394 b(nhdr;)521 1180 y(int)511
+b(vendor,)41 b(info;)521 1284 y(char)472 b(str[244];)208
+1388 y(})39 b(cistpl_vers_2_t;)0 1581 y Fm(The)25 b Fh(vers)d
+Fm(\034eld)j(should)f(alw)n(a)n(ys)f(b)r(e)i(0.)35 b(The)25
+b Fh(comply)d Fm(\034eld)j(indicates)f(the)h(degree)e(of)i(standard)e
+(compliance)h(and)g(should)0 1695 y(also)32 b(b)r(e)h(0.)53
+b(The)33 b Fh(dindex)d Fm(\034eld)k(reserv)n(es)c(the)k(sp)r(eci\034ed)
+f(n)n(um)n(b)r(er)f(of)h(b)n(ytes)g(at)g(the)g(start)f(of)h(common)g
+(memory)-7 b(.)52 b(The)0 1808 y Fh(vspec8)35 b Fm(and)j
+Fh(vspec9)d Fm(\034elds)j(ma)n(y)f(con)n(tain)g(v)n(endor-sp)r
+(eci\034c)g(information.)67 b(The)37 b Fh(nhdr)g Fm(\034eld)h(giv)n(es)
+e(the)j(n)n(um)n(b)r(er)e(of)0 1922 y(copies)26 b(of)h(the)g(CIS)h
+(that)f(are)f(presen)n(t)g(on)h(this)g(card.)36 b(The)27
+b Fh(str)e Fm(arra)n(y)g(con)n(tains)h(t)n(w)n(o)g(strings:)36
+b(a)26 b(v)n(endor)g(name,)h(and)f(an)0 2035 y(informational)e(message)
+f(describing)h(the)h(card.)35 b(The)25 b(o\033set)f(of)h(the)g(v)n
+(endor)f(string)g(is)g(giv)n(en)g(b)n(y)h Fh(vendor)p
+Fm(,)d(and)j(the)g(o\033set)0 2149 y(of)j(the)f(pro)r(duct)h(info)g
+(string)f(is)g(in)h Fh(info)p Fm(.)0 2415 y Ff(4.1.16)93
+b(CISTPL_OR)m(G)0 2625 y Fm(The)28 b Fh(cistpl_org_t)22
+b Fm(structure)27 b(is)h(giv)n(en)e(b)n(y:)208 2809 y
+Fd(typedef)40 b(struct)h(cistpl_org_t)h({)521 2913 y(u_char)394
+b(data_org;)521 3017 y(char)472 b(desc[30];)0 3210 y
+Fm(This)38 b(tuple)h(describ)r(es)f(the)g(data)g(organization)e(of)i(a)
+g(memory)g(partition.)68 b(The)39 b(follo)n(wing)e(v)-5
+b(alues)38 b(are)f(de\034ned)i(for)0 3323 y Fh(data_org)p
+Fm(:)0 3526 y Fh(CISTPL_ORG_FS)208 3665 y Fm(The)27 b(partition)g(con)n
+(tains)g(a)g(\034lesystem.)0 3830 y Fh(CISTPL_ORG_APPSP)o(EC)208
+3969 y Fm(The)g(partition)g(is)h(in)g(an)f(application)g(sp)r(eci\034c)
+g(format.)0 4134 y Fh(CISTPL_ORG_XIP)208 4274 y Fm(The)g(partition)g
+(follo)n(ws)g(the)h(Execute-In-Place)f(sp)r(eci\034cation.)0
+4476 y(The)h Fh(desc)e Fm(\034eld)h(giv)n(es)g(a)g(text)h(description)f
+(of)g(the)h(data)f(organization.)0 4761 y Fe(4.2)112
+b(CIS)37 b(con\034guration)h(register)e(de\034nitions)0
+4971 y Fm(The)29 b(PC)h(Card)e(standard)g(de\034nes)h(a)g(few)g
+(standard)f(con\034guration)g(registers)f(lo)r(cated)i(in)g(a)g(card's)
+f(attribute)h(memory)0 5084 y(space.)66 b(A)38 b(card's)e
+Fh(CONFIG)g Fm(tuple)i(sp)r(eci\034es)f(whic)n(h)h(of)f(these)h
+(registers)d(are)i(implemen)n(ted.)67 b(Programs)36 b(using)h(these)0
+5198 y(de\034nitions)28 b(should)f(include:)208 5391
+y Fd(#include)41 b("cisreg.h")p eop
+%%Page: 47 47
+47 46 bop 0 -167 3900 5 v 0 -200 a Ff(4.)73 b(Card)33
+b(Information)e(Structure)h(De\034nitions)2019 b Fm(47)0
+162 y Ff(4.2.1)94 b(Con\034guration)31 b(Option)g(Register)0
+372 y Fm(This)23 b(register)e(should)i(b)r(e)g(presen)n(t)f(for)h
+(virtually)f(all)g(IO)h(cards.)34 b(W)-7 b(riting)23
+b(to)g(this)g(register)e(selects)i(a)f(con\034guration)f(table)0
+485 y(en)n(try)27 b(and)g(enables)g(a)g(card's)g(IO)g(functions.)0
+642 y(The)h(follo)n(wing)e(bit)i(\034elds)g(are)e(de\034ned:)0
+865 y Fh(COR_CONFIG_MASK)208 1011 y Fm(Sp)r(eci\034es)h(the)h
+(con\034guration)e(table)i(index)f(describing)g(the)h(card's)e(curren)n
+(t)h(op)r(erating)f(mo)r(de.)0 1191 y Fh(COR_LEVEL_REQ)208
+1338 y Fm(Sp)r(eci\034es)h(that)h(the)g(card)f(should)g(generate)f(lev)
+n(el)h(mo)r(de)h(\(edge-triggered\))e(in)n(terrupts,)h(the)h(default.)0
+1518 y Fh(COR_SOFT_RESET)208 1665 y Fm(Setting)34 b(this)h(bit)g(p)r
+(erforms)e(a)h(\020soft\021)41 b(reset)33 b(op)r(eration.)56
+b(Driv)n(ers)33 b(should)h(use)g(the)h Fh(ResetCard)c
+Fm(call)j(to)g(reset)f(a)208 1779 y(card,)26 b(rather)h(than)g(writing)
+h(directly)f(to)g(this)h(register.)0 2051 y Ff(4.2.2)94
+b(Card)32 b(Con\034guration)g(and)g(Status)g(Register)0
+2261 y Fm(The)c(follo)n(wing)e(bit)i(\034elds)g(are)e(de\034ned:)0
+2484 y Fh(CCSR_INTR_ACK)208 2631 y Fm(If)i(this)f(bit)i(is)e(set,)h
+(then)g(the)g Fh(CCSR_INTR_PENDI)o(NG)21 b Fm(bit)28
+b(will)g(remain)f(set)g(un)n(til)h(it)g(is)g(explicitly)g(cleared.)0
+2811 y Fh(CCSR_INTR_PENDIN)o(G)208 2958 y Fm(Signals)40
+b(that)i(the)g(card)e(is)i(curren)n(tly)e(asserting)g(an)h(in)n
+(terrupt)g(request.)78 b(This)41 b(signal)g(ma)n(y)g(b)r(e)g(helpful)i
+(for)208 3071 y(supp)r(orting)27 b(in)n(terrupt)g(sharing.)0
+3251 y Fh(CCSR_POWER_DOWN)208 3398 y Fm(Setting)g(this)h(bit)g(signals)
+f(that)h(the)g(card)e(should)i(en)n(ter)f(a)g(p)r(o)n(w)n(er)f(do)n(wn)
+h(state.)0 3578 y Fh(CCSR_AUDIO_ENA)208 3725 y Fm(Sp)r(eci\034es)g
+(that)h(the)g(card's)f(audio)g(output)h(should)f(b)r(e)h(enabled.)0
+3905 y Fh(CCSR_IOIS8)208 4052 y Fm(This)20 b(is)h(used)g(b)n(y)f(the)i
+(host)e(to)h(indicate)g(that)g(it)g(can)g(only)f(p)r(erform)g(8-bit)h
+(IO)f(op)r(erations)g(and)h(that)g(16-bit)f(accesses)208
+4165 y(will)27 b(b)r(e)h(carried)e(out)i(as)f(t)n(w)n(o)g(8-bit)g
+(accesses.)0 4345 y Fh(CCSR_SIGCHG_ENA)208 4492 y Fm(This)j(indicates)g
+(to)g(the)h(card)e(that)i(it)g(should)f(use)g(the)g Fh(SIGCHG)e
+Fm(signal)i(to)g(indicate)g(c)n(hanges)f(in)i(the)f Fh(WP)p
+Fm(,)g Fh(READY)p Fm(,)208 4606 y Fh(BVD1)p Fm(,)c(and)h
+Fh(BVD2)f Fm(signals.)0 4786 y Fh(CCSR_CHANGED)208 4932
+y Fm(This)f(bit)h(signals)f(to)g(the)h(host)g(that)g(one)f(of)h(the)g
+(signals)e(in)i(the)g(Pin)h(Replacemen)n(t)e(Register)g(has)g(c)n
+(hanged)f(state.)p eop
+%%Page: 48 48
+48 47 bop 0 -167 3900 5 v 0 -200 a Ff(4.)73 b(Card)33
+b(Information)e(Structure)h(De\034nitions)2019 b Fm(48)0
+162 y Ff(4.2.3)94 b(Pin)31 b(Replacemen)m(t)f(Register)0
+372 y Fm(Signals)f(in)h(this)h(register)d(replace)h(signals)g(that)h
+(are)f(not)h(a)n(v)-5 b(ailable)28 b(when)i(a)g(so)r(c)n(k)n(et)f(is)h
+(op)r(erating)e(in)j(memory)e(and)g(IO)0 485 y(mo)r(de.)41
+b(An)30 b(IO)e(card)g(will)i(normally)d(assert)h(the)i
+Fh(SIGCHG)c Fm(signal)i(to)h(indicate)g(that)g(one)g(of)g(these)g
+(signals)f(has)g(c)n(hanged)0 599 y(state,)f(then)h(a)g(driv)n(er)e
+(can)h(p)r(oll)h(this)g(register)e(to)h(\034nd)h(out)g(sp)r
+(eci\034cally)f(what)g(happ)r(ened.)0 755 y(The)h(follo)n(wing)e(bit)i
+(\034elds)g(are)e(de\034ned:)0 953 y Fh(PRR_WP_STATUS)208
+1094 y Fm(The)h(curren)n(t)g(state)g(of)h(the)g(write)f(protect)g
+(signal.)0 1261 y Fh(PRR_READY_STATUS)208 1401 y Fm(The)g(curren)n(t)g
+(state)g(of)h(the)g(ready)e(signal.)0 1569 y Fh(PRR_BVD2_STATUS)208
+1709 y Fm(The)h(curren)n(t)g(state)g(of)h(the)g(battery)f(w)n(arn)f
+(signal.)0 1877 y Fh(PRR_BVD1_STATUS)208 2017 y Fm(The)h(curren)n(t)g
+(state)g(of)h(the)g(battery)f(dead)g(signal.)0 2184 y
+Fh(PRR_WP_EVENT)208 2325 y Fm(Indicates)g(that)h(the)g(write)f(protect)
+g(signal)g(has)g(c)n(hanged)f(state)i(since)f(the)h(PRR)g(register)e(w)
+n(as)h(last)g(read.)0 2492 y Fh(PRR_READY_EVENT)208 2633
+y Fm(Indicates)g(that)h(the)g(ready)e(signal)h(has)g(c)n(hanged)f
+(state)i(since)f(the)h(PRR)g(register)e(w)n(as)h(last)g(read.)0
+2800 y Fh(PRR_BVD2_EVENT)208 2941 y Fm(Indicates)g(that)h(the)g
+(battery)f(w)n(arn)f(signal)h(has)g(c)n(hanged)f(state)i(since)f(the)h
+(PRR)g(register)e(w)n(as)h(last)g(read.)0 3108 y Fh(PRR_BVD1_EVENT)208
+3248 y Fm(Indicates)g(that)h(the)g(battery)f(dead)g(signal)g(has)g(c)n
+(hanged)f(state)h(since)h(the)g(PRR)g(register)e(w)n(as)h(last)g(read.)
+0 3446 y(This)33 b(register)f(can)g(also)g(b)r(e)i(written.)54
+b(In)33 b(this)h(case,)f(the)h Fh(STATUS)c Fm(bits)k(act)f(as)f(a)h
+(mask;)i(if)f(a)f Fh(STATUS)d Fm(bit)k(is)f(set,)i(the)0
+3560 y(corresp)r(onding)26 b Fh(EVENT)f Fm(bit)j(is)g(up)r(dated)g(b)n
+(y)f(the)h(write.)0 3827 y Ff(4.2.4)94 b(So)s(c)m(k)m(et)32
+b(and)h(Cop)m(y)f(Register)0 4037 y Fm(This)i(register)f(is)h(used)g
+(when)g(sev)n(eral)f(iden)n(tical)g(cards)g(ma)n(y)h(b)r(e)g(set)h(up)f
+(to)g(share)f(the)i(same)e(range)g(of)h(IO)g(p)r(orts,)h(to)0
+4150 y(em)n(ulate)22 b(an)g(ISA)h(bus)g(card)f(that)g(w)n(ould)g(con)n
+(trol)g(sev)n(eral)e(devices.)35 b(F)-7 b(or)22 b(example,)h(an)f(ISA)h
+(hard)f(driv)n(e)g(con)n(troller)e(migh)n(t)0 4264 y(con)n(trol)j(sev)n
+(eral)f(driv)n(es,)i(selectable)g(b)n(y)g(writing)g(a)g(driv)n(e)g(n)n
+(um)n(b)r(er)g(to)g(an)g(IO)g(p)r(ort.)35 b(F)-7 b(or)24
+b(sev)n(eral)f(card)g(driv)n(es)g(to)h(em)n(ulate)0 4378
+y(this)29 b(con)n(troller)e(in)n(terface,)h(eac)n(h)g(needs)h(to)g
+(\020kno)n(w\021)34 b(whic)n(h)29 b(driv)n(e)f(it)h(is,)g(so)f(that)h
+(it)h(can)e(iden)n(tify)h(whic)n(h)g(IO)f(op)r(erations)0
+4491 y(are)f(in)n(tended)g(for)h(it.)0 4648 y(The)g(follo)n(wing)e(bit)
+i(\034elds)g(are)e(de\034ned:)0 4845 y Fh(SCR_SOCKET_NUM)208
+4986 y Fm(This)h(should)g(indicate)h(the)g(so)r(c)n(k)n(et)e(n)n(um)n
+(b)r(er)i(in)f(whic)n(h)h(the)g(card)f(is)g(lo)r(cated.)0
+5153 y Fh(SCR_COPY_NUM)208 5294 y Fm(If)20 b(sev)n(eral)f(iden)n(tical)
+h(cards)g(are)f(installed)i(in)g(a)f(system,)h(this)g(\034eld)g(should)
+f(b)r(e)h(set)g(to)f(a)g(unique)h(n)n(um)n(b)r(er)f(iden)n(tifying)208
+5407 y(whic)n(h)27 b(of)h(the)g(iden)n(tical)f(cards)f(this)i(is.)p
+eop
+%%Page: 49 49
+49 48 bop 0 -167 3900 5 v 0 -200 a Ff(5.)73 b(Card)33
+b(Services)f(Ev)m(en)m(t)g(Handling)2405 b Fm(49)0 162
+y Ff(4.2.5)94 b(Extended)31 b(Status)h(Register)0 372
+y Fm(The)c(follo)n(wing)e(bit)i(\034elds)g(are)e(de\034ned:)0
+594 y Fh(ESR_REQ_ATTN_ENA)208 741 y Fm(When)k(set,)g(the)g
+Fh(CCSR_CHANGED)24 b Fm(bit)31 b(will)e(b)r(e)h(set)g(when)g(the)g
+Fh(ESR_REQ_ATTN)24 b Fm(bit)31 b(is)e(set,)h(p)r(ossibly)f(generating)f
+(a)208 855 y(status)f(c)n(hange)f(in)n(terrupt.)0 1034
+y Fh(ESR_REQ_ATTN)208 1181 y Fm(Signals)g(a)h(card)g(ev)n(en)n(t,)g
+(suc)n(h)g(as)g(an)h(incoming)f(call)g(for)g(a)g(mo)r(dem.)0
+1454 y Ff(4.2.6)94 b(IO)31 b(Base)h(and)g(Size)g(Registers)0
+1664 y Fm(F)-7 b(or)18 b(m)n(ultifunction)h(cards,)g(these)g(registers)
+e(are)g(used)i(to)f(tell)h(the)g(card)e(ho)n(w)h(the)h(host)f(IO)g
+(windo)n(ws)g(ha)n(v)n(e)f(b)r(een)i(con\034gured)0 1777
+y(for)29 b(eac)n(h)g(card)g(function.)45 b(There)29 b(are)g(four)g(IO)h
+(Base)f(registers,)f(from)i Fh(CISREG_IOBASE_0)24 b Fm(to)29
+b Fh(CISREG_IOBASE_3)p Fm(,)c(for)0 1891 y(the)j(lo)n(w-order)e
+(through)h(high-order)f(b)n(ytes)h(of)h(an)g(IO)f(address)g(up)h(to)g
+(32)f(bits)h(long.)37 b(The)28 b Fh(CISREG_IOSIZE)23
+b Fm(register)j(is)0 2004 y(supp)r(osed)32 b(to)g(b)r(e)g(written)h(as)
+e(the)i(n)n(um)n(b)r(er)f(of)g(IO)f(p)r(orts)h(allo)r(cated,)h(min)n
+(us)f(one.)50 b(F)-7 b(or)32 b(MF)n(C-complian)n(t)f(cards,)h(Card)0
+2118 y(Services)27 b(will)g(automatically)g(set)g(all)h(of)f(these)h
+(registers)d(when)j Fh(RequestConfigura)o(tio)o(n)21
+b Fm(is)28 b(called.)0 2456 y Fg(5)131 b(Card)44 b(Services)h(Ev)l(en)l
+(t)g(Handling)0 2695 y Fm(Card)27 b(Services)f(ev)n(en)n(ts)h(ha)n(v)n
+(e)f(sev)n(eral)g(sources:)125 2934 y Fb(\017)41 b Fm(Card)26
+b(status)i(c)n(hanges)e(rep)r(orted)g(b)n(y)i(the)g(lo)n(w-lev)n(el)e
+(so)r(c)n(k)n(et)g(driv)n(ers.)125 3114 y Fb(\017)41
+b Fm(Arti\034cial)27 b(ev)n(en)n(ts)g(generated)f(b)n(y)h(Card)g
+(Services)g(itself.)125 3294 y Fb(\017)41 b Fm(A)n(dv)-5
+b(anced)27 b(P)n(o)n(w)n(er)f(Managemen)n(t)g(\(APM\))k(ev)n(en)n(ts.)
+125 3474 y Fb(\017)41 b Fm(Ev)n(en)n(ts)27 b(generated)f(b)n(y)i(other)
+f(Card)f(Services)h(clien)n(ts.)0 3713 y(So)r(c)n(k)n(et)g(driv)n(er)f
+(ev)n(en)n(ts)h(ma)n(y)g(b)r(e)h(either)f(in)n(terrupt-driv)n(en)f(or)h
+(p)r(olled.)0 4004 y Fe(5.1)112 b(Ev)m(en)m(t)37 b(handler)h(op)s
+(erations)0 4214 y Fm(When)j(Card)e(Services)h(recognizes)e(that)j(an)f
+(ev)n(en)n(t)g(has)g(o)r(ccurred,)i(it)f(c)n(hec)n(ks)e(the)i(ev)n(en)n
+(t)f(mask)g(of)g(eac)n(h)g(clien)n(t)g(to)0 4328 y(determine)29
+b(whic)n(h)g(clien)n(ts)f(should)h(receiv)n(e)f(an)g(ev)n(en)n(t)h
+(noti\034cation.)40 b(When)29 b(a)g(clien)n(t)g(registers)e(with)i
+(Card)f(Services,)h(it)0 4441 y(sp)r(eci\034es)e(an)h(ev)n(en)n(t)f
+(handler)g(callbac)n(k)f(function.)37 b(This)28 b(handler)f(should)g
+(ha)n(v)n(e)f(the)i(form:)208 4671 y Fd(int)39 b
+(\(*event_handler\)\(event_t)45 b(event,)40 b(int)g(priority,)h
+(event_callback_args_t)j(*args\);)0 4910 y Fm(The)36
+b Fh(priority)d Fm(parameter)h(is)i(set)g(to)f(either)h
+Fh(CS_EVENT_PRI_LOW)29 b Fm(for)36 b(ordinary)e(ev)n(en)n(ts,)j(or)e
+Fh(CS_EVENT_PRI_HIG)o(H)0 5024 y Fm(for)e(ev)n(en)n(ts)g(that)i
+(require)d(an)i(immediate)g(resp)r(onse.)55 b(The)34
+b(only)f(high)h(priorit)n(y)f(ev)n(en)n(t)g(is)h Fh(CS_EVENT_CARD_R)o
+(EMO)o(VA)o(L)p Fm(.)0 5137 y(A)c(clien)n(t)f(ev)n(en)n(t)g(handler)f
+(should)h(pro)r(cess)f(this)i(ev)n(en)n(t)e(as)h(e\036cien)n(tly)g(as)g
+(p)r(ossible)f(so)h(that)g(Card)g(Services)f(can)h(quic)n(kly)0
+5251 y(notify)f(other)f(clien)n(ts.)0 5407 y(The)h Fh(event_callback_)o
+(ar)o(gs_)o(t)21 b Fm(structure)27 b(is)h(giv)n(en)f(b)n(y:)p
+eop
+%%Page: 50 50
+50 49 bop 0 -167 3900 5 v 0 -200 a Ff(5.)73 b(Card)33
+b(Services)f(Ev)m(en)m(t)g(Handling)2405 b Fm(50)208
+162 y Fd(typedef)40 b(struct)h(event_callback_args_t)j({)521
+266 y(client_handle_t)357 b(client_handle;)521 370 y(void)786
+b(*info;)521 474 y(void)g(*mtdrequest;)521 578 y(void)g(*buffer;)521
+682 y(void)g(*misc;)521 786 y(void)g(*client_data;)521
+890 y(struct)41 b(bus_operations)121 b(*bus;)208 995
+y(})39 b(event_callback_args_t;)0 1216 y Fm(The)31 b
+Fh(client_handle)26 b Fm(mem)n(b)r(er)32 b(is)f(set)g(to)h(the)f
+(handle)h(of)f(the)h(clien)n(t)f(whose)g(so)r(c)n(k)n(et)f(w)n(as)g
+(resp)r(onsible)h(for)g(the)h(ev)n(en)n(t.)0 1329 y(This)c(is)f(useful)
+i(if)f(a)f(driv)n(er)g(is)h(b)r(ound)g(to)f(sev)n(eral)f(so)r(c)n(k)n
+(ets.)37 b(The)28 b Fh(info)e Fm(\034eld)i(is)g(curren)n(tly)e(only)i
+(used)f(to)h(return)f(an)h(exit)0 1443 y(status)j(from)f(a)h(call)f(to)
+h Fh(ResetCard)p Fm(.)43 b(The)31 b Fh(client_data)26
+b Fm(\034eld)31 b(ma)n(y)g(b)r(e)g(used)g(b)n(y)f(a)h(driv)n(er)e(to)i
+(p)r(oin)n(t)g(to)g(a)f(lo)r(cal)h(data)0 1556 y(structure)c(asso)r
+(ciated)f(with)i(this)g(device.)37 b(The)27 b(remaining)g(\034elds)g
+(are)g(curren)n(tly)g(un)n(used.)0 1713 y(F)-7 b(or)26
+b(so)r(c)n(k)n(ets)g(that)h(do)g(not)g(directly)g(map)f(cards)g(in)n
+(to)h(the)g(host)g(IO)g(and)f(memory)g(space,)h(the)g
+Fh(bus)f Fm(\034eld)h(is)g(a)g(p)r(oin)n(ter)f(to)0 1826
+y(a)h(table)h(of)f(en)n(try)g(p)r(oin)n(ts)h(for)f(IO)g(primitiv)n(es)g
+(for)g(this)h(so)r(c)n(k)n(et.)0 2117 y Fe(5.2)112 b(Ev)m(en)m(t)37
+b(descriptions)0 2317 y Fh(CS_EVENT_CARD_IN)o(SE)o(RTI)o(ON)208
+2464 y Fm(This)30 b(ev)n(en)n(t)g(signals)g(that)h(a)f(card)g(has)g(b)r
+(een)h(inserted.)45 b(If)32 b(a)e(driv)n(er)f(is)i(b)r(ound)g(to)f(an)g
+(already)g(o)r(ccupied)g(so)r(c)n(k)n(et,)208 2577 y(Card)c(Services)h
+(will)h(send)f(the)h(driv)n(er)e(an)i(arti\034cial)e(insertion)h(ev)n
+(en)n(t.)0 2756 y Fh(CS_EVENT_CARD_RE)o(MO)o(VAL)208
+2903 y Fm(This)i(ev)n(en)n(t)f(signals)g(that)i(a)e(card)g(has)h(b)r
+(een)h(remo)n(v)n(ed.)39 b(This)30 b(ev)n(en)n(t)e(should)h(b)r(e)g
+(handled)h(with)f(minim)n(um)h(dela)n(y)208 3016 y(so)c(that)i(Card)f
+(Services)g(can)g(notify)h(all)f(clien)n(ts)g(as)g(quic)n(kly)g(as)g(p)
+r(ossible.)0 3195 y Fh(CS_EVENT_BATTERY)o(_L)o(OW)208
+3342 y Fm(This)g(ev)n(en)n(t)g(signals)f(a)i(c)n(hange)e(of)i(state)f
+(of)g(the)h(\020battery)f(lo)n(w\021)34 b(signal.)0 3521
+y Fh(CS_EVENT_BATTERY)o(_D)o(EAD)208 3667 y Fm(This)27
+b(ev)n(en)n(t)g(signals)f(a)i(c)n(hange)e(of)i(state)f(of)g(the)h
+(\020battery)f(dead\021)34 b(signal.)0 3846 y Fh(CS_EVENT_READY_C)o(HA)
+o(NGE)208 3992 y Fm(This)27 b(ev)n(en)n(t)g(signals)f(a)i(c)n(hange)e
+(of)i(state)f(of)g(the)h(\020ready\021)33 b(signal.)0
+4171 y Fh(CS_EVENT_WRITE_P)o(RO)o(TEC)o(T)208 4318 y
+Fm(This)27 b(ev)n(en)n(t)g(signals)f(a)i(c)n(hange)e(of)i(state)f(of)g
+(the)h(\020write)f(protect\021)34 b(signal.)0 4497 y
+Fh(CS_EVENT_REGISTR)o(AT)o(ION)o(_C)o(OM)o(PLE)o(TE)208
+4643 y Fm(This)27 b(ev)n(en)n(t)g(is)h(sen)n(t)f(to)g(a)h(driv)n(er)e
+(after)h(a)g(successful)g(call)h(to)f Fh(RegisterClient)p
+Fm(.)0 4822 y Fh(CS_EVENT_RESET_R)o(EQ)o(UES)o(T)208
+4968 y Fm(This)32 b(ev)n(en)n(t)g(is)g(sen)n(t)g(when)h(a)f(clien)n(t)h
+(calls)e Fh(ResetCard)p Fm(.)48 b(An)33 b(ev)n(en)n(t)f(handler)g(can)g
+(v)n(eto)f(the)i(reset)f(op)r(eration)f(b)n(y)208 5082
+y(returning)26 b(failure.)0 5261 y Fh(CS_EVENT_RESET_P)o(HY)o(SIC)o(AL)
+208 5407 y Fm(This)h(is)h(sen)n(t)f(to)g(all)h(clien)n(ts)f(just)h(b)r
+(efore)f(a)h(reset)f(signal)f(is)i(sen)n(t)f(to)g(a)h(card.)p
+eop
+%%Page: 51 51
+51 50 bop 0 -167 3900 5 v 0 -200 a Ff(6.)73 b(Memory)31
+b(T)-8 b(ec)m(hnology)32 b(Driv)m(ers)2478 b Fm(51)0
+162 y Fh(CS_EVENT_CARD_RE)o(SE)o(T)208 308 y Fm(This)37
+b(ev)n(en)n(t)f(signals)g(that)h(a)g(reset)f(op)r(eration)g(is)h
+(\034nished.)65 b(The)37 b(success)f(or)h(failure)f(of)h(the)h(reset)e
+(should)h(b)r(e)208 422 y(determined)27 b(using)g Fh(GetStatus)p
+Fm(.)0 602 y Fh(CS_EVENT_RESET_C)o(OM)o(PLE)o(TE)208
+749 y Fm(This)g(ev)n(en)n(t)g(is)h(sen)n(t)f(to)g(a)h(clien)n(t)f(that)
+h(has)f(called)g Fh(ResetCard)d Fm(to)k(signal)e(the)i(end)g(of)f
+(reset)g(pro)r(cessing.)0 929 y Fh(CS_EVENT_PM_SUSP)o(EN)o(D)208
+1076 y Fm(This)e(ev)n(en)n(t)f(signals)g(that)h(Card)g(Services)f(has)g
+(receiv)n(ed)g(either)h(a)g(user)f(initiated)i(or)e(APM)i(susp)r(end)f
+(request.)36 b(An)208 1189 y(ev)n(en)n(t)27 b(handler)g(can)g(v)n(eto)g
+(the)h(susp)r(end)f(b)n(y)h(returning)e(failure.)0 1369
+y Fh(CS_EVENT_PM_RESU)o(ME)208 1516 y Fm(This)h(signals)f(that)i(the)g
+(system)g(is)f(bac)n(k)g(on)g(line)h(after)f(a)g(susp)r(end/resume)g
+(cycle.)0 1696 y Fh(CS_EVENT_MTD_REQ)o(UE)o(ST)208 1843
+y Fm(This)36 b(is)h(used)g(to)f(initiate)i(an)e(MTD)h(memory)f(op)r
+(eration.)64 b(A)37 b(description)f(of)h(the)g(request)f(is)h(passed)f
+(in)h(the)208 1956 y Fh(mtdrequest)23 b Fm(\034eld)28
+b(of)f(the)h(callbac)n(k)e(argumen)n(ts.)36 b(A)28 b(host)f(bu\033er)h
+(address)e(ma)n(y)h(b)r(e)h(passed)f(in)h Fh(buffer)p
+Fm(.)0 2136 y Fh(CS_EVENT_ERASE_C)o(OM)o(PLE)o(TE)208
+2283 y Fm(This)33 b(is)g(used)g(to)g(signal)f(a)g(clien)n(t)h(that)h(a)
+e(queued)i(erase)d(op)r(eration)h(has)h(completed.)53
+b(A)33 b(p)r(oin)n(ter)g(to)g(the)g(erase)208 2397 y(queue)27
+b(en)n(try)g(is)g(returned)h(in)f(the)h Fh(info)e Fm(\034eld)i(of)g
+(the)g(callbac)n(k)e(argumen)n(ts.)0 2688 y Fe(5.3)112
+b(Clien)m(t)36 b(driv)m(er)g(ev)m(en)m(t)h(handling)g(resp)s
+(onsibilities)0 2898 y Fm(A)29 b(clien)n(t)h(driv)n(er)d(should)i(resp)
+r(ond)f(to)h Fh(CS_EVENT_CARD_INS)o(ER)o(TI)o(ON)23 b
+Fm(and)29 b Fh(CS_EVENT_CARD_R)o(EM)o(OVA)o(L)23 b Fm(ev)n(en)n(ts)28
+b(b)n(y)h(con-)0 3012 y(\034guring)35 b(and)h(un-con\034guring)f(the)i
+(so)r(c)n(k)n(et.)62 b(Because)35 b(card)g(remo)n(v)-5
+b(al)35 b(is)i(a)f(high)g(priorit)n(y)f(ev)n(en)n(t,)j(the)e(driv)n(er)
+f(should)0 3125 y(immediately)30 b(blo)r(c)n(k)g(IO)g(to)g(the)h(so)r
+(c)n(k)n(et,)f(p)r(erhaps)g(b)n(y)g(setting)g(a)g(\035ag)g(in)g(a)g
+(device)g(structure,)h(and)f(sc)n(hedule)g(all)g(other)0
+3239 y(sh)n(utdo)n(wn)d(pro)r(cessing)f(to)h(happ)r(en)h(later)f(using)
+g(a)h(timer)f(in)n(terrupt.)0 3395 y(When)d(a)f Fh(CS_EVENT_PM_RESE)o
+(T_)o(REQ)o(UE)o(ST)17 b Fm(ev)n(en)n(t)23 b(is)g(receiv)n(ed,)h(a)f
+(driv)n(er)f(should)h(blo)r(c)n(k)g(IO)g(and)h(release)e(a)h(lo)r(c)n
+(k)n(ed)f(so)r(c)n(k)n(et)0 3509 y(con\034guration.)48
+b(When)32 b(a)f Fh(CS_EVENT_CARD_RES)o(ET)25 b Fm(is)32
+b(receiv)n(ed,)g(a)f(driv)n(er)f(should)i(restore)e(the)i(so)r(c)n(k)n
+(et)f(con\034guration)0 3623 y(and)c(un)n(blo)r(c)n(k)g(IO.)0
+3779 y(A)i Fh(CS_EVENT_PM_SUS)o(PE)o(ND)22 b Fm(ev)n(en)n(t)28
+b(should)g(b)r(e)g(handled)h(somewhat)e(lik)n(e)h(a)g
+Fh(CS_EVENT_PM_RESE)o(T_)o(REQ)o(UE)o(ST)22 b Fm(ev)n(en)n(t,)28
+b(in)0 3893 y(that)j(IO)f(should)g(b)r(e)h(blo)r(c)n(k)n(ed)f(and)g
+(the)h(so)r(c)n(k)n(et)e(con\034guration)g(should)h(b)r(e)h(released.)
+45 b(When)31 b(a)f Fh(CS_EVENT_PM_RES)o(UM)o(E)0 4006
+y Fm(ev)n(en)n(t)54 b(is)g(receiv)n(ed,)60 b(a)54 b(driv)n(er)f(can)g
+(exp)r(ect)i(a)f(card)f(to)h(b)r(e)h(ready)e(to)i(b)r(e)f
+(recon\034gured,)59 b(similar)54 b(to)g(when)g(a)0 4120
+y Fh(CS_EVENT_CARD_RE)o(SE)o(T)22 b Fm(ev)n(en)n(t)27
+b(is)g(receiv)n(ed.)0 4458 y Fg(6)131 b(Memory)44 b(T)-11
+b(ec)l(hnology)45 b(Driv)l(ers)0 4697 y Fm(A)30 b(Memory)g(T)-7
+b(ec)n(hnology)28 b(Driv)n(er)h(\(\020MTD\021\))i(is)f(used)g(b)n(y)g
+(Card)f(Services)g(to)h(implemen)n(t)h(bulk)f(memory)f(services)g(for)g
+(a)0 4810 y(particular)e(t)n(yp)r(e)i(of)g(memory)f(device.)40
+b(An)29 b(MTD)h(should)e(register)f(as)i(a)f(normal)g(Card)g(Services)f
+(clien)n(t)i(with)g(a)g(call)f(to)0 4924 y Fh(RegisterClient)p
+Fm(.)g(When)21 b(it)f(receiv)n(es)e(a)i(card)f(insertion)g(ev)n(en)n
+(t,)i(it)f(should)g(use)g Fh(GetFirstRegion)14 b Fm(and)20
+b Fh(GetNextRegion)0 5038 y Fm(to)25 b(iden)n(tify)g(memory)f(regions)f
+(that)i(it)g(will)g(administer.)35 b(Then,)26 b(it)f(should)g(use)f
+Fh(RegisterMTD)c Fm(to)25 b(tak)n(e)f(con)n(trol)f(of)i(these)0
+5151 y(regions.)57 b(MTD)35 b(read,)h(write,)h(cop)n(y)-7
+b(,)35 b(and)g(erase)e(requests)h(are)g(pac)n(k)-5 b(aged)33
+b(in)n(to)i Fh(CS_EVENT_MTD_REQ)o(UE)o(ST)28 b Fm(ev)n(en)n(ts)34
+b(b)n(y)0 5265 y(Card)27 b(Services,)f(and)i(passed)f(to)g(the)h(MTD's)
+g(ev)n(en)n(t)f(handler)g(for)g(pro)r(cessing.)p eop
+%%Page: 52 52
+52 51 bop 0 -167 3900 5 v 0 -200 a Ff(6.)73 b(Memory)31
+b(T)-8 b(ec)m(hnology)32 b(Driv)m(ers)2478 b Fm(52)0
+162 y Fe(6.1)112 b(MTD)38 b(request)f(handling)0 372
+y Fm(An)26 b(MTD)h(receiv)n(es)e(requests)g(from)g(Card)g(Services)g
+(in)i(the)f(form)g(of)g Fh(CS_EVENT_MTD_RE)o(QUE)o(ST)19
+b Fm(ev)n(en)n(ts.)36 b(Card)25 b(Services)0 485 y(passes)32
+b(a)g(description)g(of)g(the)i(request)e(in)g(the)i Fh(mtdrequest)28
+b Fm(\034eld)33 b(of)g(the)g(ev)n(en)n(t)f(callbac)n(k)f(argumen)n(ts.)
+51 b(F)-7 b(or)32 b(requests)0 599 y(that)c(transfer)e(data)h(to)h(or)f
+(from)g(the)h(host,)f(the)h(host)f(bu\033er)h(address)e(is)i(passed)f
+(in)g(the)h Fh(buffer)d Fm(\034eld.)0 755 y(The)j Fh(mtd_request_t)22
+b Fm(structure)27 b(is)g(giv)n(en)g(b)n(y:)208 950 y
+Fd(typedef)40 b(struct)h(mtd_request_t)h({)521 1054 y(u_int)433
+b(SrcCardOffset;)521 1158 y(u_int)g(DestCardOffset;)521
+1262 y(u_int)g(TransferLength;)521 1366 y(u_int)g(Function;)521
+1471 y(u_long)394 b(MediaID;)521 1575 y(u_int)433 b(Status;)521
+1679 y(u_int)g(Timeout;)208 1783 y(})39 b(mtd_request_t;)0
+1987 y Fm(The)28 b Fh(Function)c Fm(\034eld)k(is)f(bit)h(mapp)r(ed)g
+(and)g(describ)r(es)e(the)i(action)f(to)h(b)r(e)g(p)r(erformed)f(b)n(y)
+g(this)h(request:)0 2191 y Fh(MTD_REQ_ACTION)208 2333
+y Fm(Either)g Fh(MTD_REQ_ERASE)p Fm(,)22 b Fh(MTD_REQ_READ)p
+Fm(,)g Fh(MTD_REQ_WRITE)p Fm(,)h(or)j Fh(MTD_REQ_COPY)p
+Fm(.)0 2504 y Fh(MTD_REQ_NOERASE)208 2646 y Fm(F)-7 b(or)28
+b(a)g(write)h(command)f(that)i(is)e(sized)h(and)g(aligned)f(on)h(erase)
+e(blo)r(c)n(k)h(b)r(oundaries,)h(this)g(sp)r(eci\034es)g(that)g(no)f
+(erase)208 2759 y(should)f(b)r(e)h(p)r(erformed.)0 2930
+y Fh(MTD_REQ_VERIFY)208 3072 y Fm(Sp)r(eci\034es)f(that)h(writes)f
+(should)h(b)r(e)g(v)n(eri\034ed.)0 3243 y Fh(MTD_REQ_READY)208
+3385 y Fm(Indicates)i(that)g(this)h(request)f(is)g(a)g(retry)g(of)g(a)g
+(previously)f(request)h(that)h(w)n(as)e(dela)n(y)n(ed)g(un)n(til)i(the)
+g(card)e(asserted)208 3498 y Fh(READY)p Fm(.)0 3669 y
+Fh(MTD_REQ_TIMEOUT)208 3811 y Fm(Indicates)e(that)h(this)f(request)g
+(is)h(a)f(retry)g(of)g(a)g(previously)g(request)f(that)i(w)n(as)f(dela)
+n(y)n(ed)f(b)n(y)i(a)f(timeout.)0 3981 y Fh(MTD_REQ_FIRST)208
+4124 y Fm(Indicates)g(that)h(this)f(request)g(is)h(the)g(\034rst)f(in)h
+(a)f(series)g(of)g(requests.)0 4294 y Fh(MTD_REQ_LAST)208
+4436 y Fm(Indicates)g(that)h(this)f(request)g(is)h(the)g(last)f(of)h(a)
+f(series)f(of)i(requests.)0 4607 y Fh(MTD_REQ_KERNEL)208
+4749 y Fm(Indicates)e(that)g(the)h(host)f(bu\033er)h(for)e(a)h(read)g
+(or)f(write)i(command)e(is)i(lo)r(cated)f(in)g(k)n(ernel)g(memory)-7
+b(,)26 b(as)f(opp)r(osed)h(to)208 4862 y(user)g(memory)-7
+b(.)0 5066 y(The)35 b Fh(MediaID)d Fm(\034eld)j(is)g(the)g(v)-5
+b(alue)35 b(sp)r(eci\034ed)g(in)g(the)h Fh(RegisterMTD)30
+b Fm(request)k(for)h(this)g(region.)58 b(The)35 b Fh(Status)d
+Fm(\034eld)j(is)0 5180 y(used)30 b(b)n(y)g(the)g(MTD)h(when)f(it)h(is)f
+(unable)g(to)g(satisfy)g(a)f(request)h(b)r(ecause)f(a)h(device)g(is)g
+(busy)-7 b(.)44 b(MTD)31 b(requests)e(normally)0 5294
+y(run)h(without)h(blo)r(c)n(king.)44 b(If)30 b(an)g(MTD)h(request)f(w)n
+(ould)f(blo)r(c)n(k,)i(it)f(should)g(return)g(an)g(error)e(co)r(de)i
+(of)h Fh(CS_BUSY)p Fm(,)c(and)j(set)0 5407 y Fh(Status)25
+b Fm(to)j(one)f(of)g(the)h(ha)n(v)n(e)f(the)h(follo)n(wing)e(v)-5
+b(alues:)p eop
+%%Page: 53 53
+53 52 bop 0 -167 3900 5 v 0 -200 a Ff(6.)73 b(Memory)31
+b(T)-8 b(ec)m(hnology)32 b(Driv)m(ers)2478 b Fm(53)0
+162 y Fh(MTD_WAITREQ)208 306 y Fm(Sp)r(eci\034es)22 b(that)h(the)g
+(request)f(should)g(b)r(e)h(retried)f(after)g(another)g(MTD)h(request)f
+(curren)n(tly)f(in)i(progress)d(completes.)0 481 y Fh(MTD_WAITTIMER)208
+626 y Fm(Sp)r(eci\034es)27 b(that)h(the)g(request)f(should)g(b)r(e)h
+(con)n(tin)n(ued)f(after)h(the)g(time)g(sp)r(eci\034ed)f(in)h(the)g
+Fh(timeout)d Fm(\034eld.)0 801 y Fh(MTD_WAITRDY)208 946
+y Fm(Sp)r(eci\034es)f(that)h(the)g(request)f(should)h(b)r(e)g(con)n
+(tin)n(ued)f(when)h(the)f(card)g(signals)g Fh(READY)p
+Fm(,)e(or)i(when)h(the)g(time)g(sp)r(eci\034ed)208 1059
+y(in)i Fh(Timeout)e Fm(elapses,)i(whic)n(hev)n(er)f(happ)r(ens)i
+(\034rst.)0 1234 y Fh(MTD_WAITPOWER)208 1379 y Fm(Sp)r(eci\034es)g
+(that)g(the)h(request)e(should)h(b)r(e)g(retried)f(after)h(something)g
+(happ)r(ens)g(that)g(a\033ects)g(p)r(o)n(w)n(er)f(a)n(v)-5
+b(ailabilit)n(y)26 b(to)208 1492 y(the)i(so)r(c)n(k)n(et.)0
+1720 y(F)-7 b(or)27 b Fh(MTD_WAITTIMER)22 b Fm(and)27
+b Fh(MTD_WAITRDY)p Fm(,)d(the)j Fh(Timeout)e Fm(\034eld)j(will)g(sp)r
+(ecify)g(the)g(timeout)g(in)n(terv)-5 b(al)26 b(in)i(milliseconds.)0
+2010 y Fe(6.2)112 b(MTD)38 b(help)s(er)f(functions)0
+2220 y Fm(Since)31 b(an)f(MTD)h(pro)r(cesses)d(requests)i(generated)f
+(b)n(y)h(Card)g(Services,)g(there)g(ma)n(y)g(b)r(e)h(some)e
+(restrictions)g(on)h(the)h(sorts)0 2333 y(of)i(Card)f(Services)g(calls)
+g(that)h(can)g(b)r(e)g(safely)g(made)f(from)h(the)g(MTD)h(ev)n(en)n(t)e
+(handler.)52 b(The)33 b(MTD)h(help)r(er)f(functions)0
+2447 y(pro)n(vide)28 b(a)g(limited)h(set)g(of)g(sp)r(ecial)f(services)g
+(that)h(ma)n(y)f(b)r(e)h(needed)g(b)n(y)f(an)h(MTD)g(but)h(w)n(ould)e
+(b)r(e)h(tric)n(ky)f(to)h(implemen)n(t)0 2561 y(using)f(the)g(normal)f
+(Card)h(Services)f(calls.)37 b(In)29 b(the)f(Lin)n(ux)g(implemen)n
+(tation,)g(most)g(CS)g(calls)g(can)g(b)r(e)g(safely)g(made)f(from)0
+2674 y(an)g(MTD)h(ev)n(en)n(t)f(handler,)g(but)i(the)f(MTD)g(help)r(er)
+f(in)n(terface)g(is)h(included)g(for)f(compatibilit)n(y)-7
+b(.)208 2892 y Fd(#include)41 b("cs_types.h")208 2996
+y(#include)g("cs.h")208 3101 y(#include)g("bulkmem.h")208
+3309 y(int)e(MTDHelperEntry\(int)44 b(subfunc,)d(void)f(*arg1,)g(void)g
+(*arg2\);)0 3579 y Ff(6.2.1)94 b(MTDRequestWindo)m(w,)30
+b(MTDReleaseWindo)m(w)208 3768 y Fd(int)39 b
+(MTDHelperEntry\(MTDRequestWin)q(dow,)46 b(client_handle_t)c(*handle,)f
+(win_req_t)g(*mod\);)208 3872 y(int)e(MTDHelperEntry\(MTDReleaseWin)q
+(dow,)46 b(window_handle_t)c(handle\);)0 4100 y Fm(These)27
+b(services)f(are)h(iden)n(tical)g(to)h(the)g(standard)e(Card)h
+(Services)g Fh(RequestWindow)22 b Fm(and)27 b Fh(ReleaseWindow)22
+b Fm(calls.)0 4370 y Ff(6.2.2)94 b(MTDMo)s(difyWindo)m(w)208
+4559 y Fd(int)39 b(MTDHelperEntry\(MTDModifyWind)q(ow,)45
+b(memory_handle_t)e(handle,)e(mtd_mod_req_t)h(*mod\);)0
+4787 y Fm(The)28 b Fh(mtd_mod_req_t)22 b Fm(structure)27
+b(is)g(giv)n(e)g(b)n(y:)208 4991 y Fd(typedef)40 b(struct)h
+(mtd_mod_req_t)h({)521 5095 y(u_int)433 b(Attributes;)521
+5199 y(u_int)g(AccessSpeed;)521 5303 y(u_int)g(CardOffset;)208
+5407 y(})39 b(mtd_mod_req_t;)p eop
+%%Page: 54 54
+54 53 bop 0 -167 3900 5 v 0 -200 a Ff(6.)73 b(Memory)31
+b(T)-8 b(ec)m(hnology)32 b(Driv)m(ers)2478 b Fm(54)0
+162 y Fh(MTDModifyWindow)21 b Fm(is)28 b(essen)n(tially)e(equiv)-5
+b(alen)n(t)28 b(to)f(using)g(the)h(normal)f Fh(ModifyWindow)22
+b Fm(and)28 b Fh(MapMemPage)23 b Fm(calls.)0 318 y(The)28
+b(follo)n(wing)e(\035ags)h(can)g(b)r(e)h(sp)r(eci\034ed)g(in)f
+Fh(Attributes)p Fm(:)0 544 y Fh(WIN_MEMORY_TYPE)208 688
+y Fm(Either)h Fh(WIN_MEMORY_TYPE)o(_C)o(M)22 b Fm(for)27
+b(common)g(memory)-7 b(,)26 b(or)h Fh(WIN_MEMORY_TYPE_)o(AM)21
+b Fm(for)27 b(attribute)h(memory)-7 b(.)0 863 y Fh(WIN_USE_WAIT)208
+1007 y Fm(Sp)r(eci\034es)27 b(that)h(the)g(con)n(troller)e(should)h
+(observ)n(e)f(the)i(card's)e(MW)-9 b(AIT)28 b(signal.)0
+1233 y(A)g(windo)n(w)f(con\034gured)f(with)i Fh(MTDModifyWindow)22
+b Fm(will)28 b(alw)n(a)n(ys)d(b)r(e)j(enabled,)f(and)h(ha)n(v)n(e)e(a)h
+(16)g(bit)h(data)f(width.)0 1390 y(Return)h(co)r(des:)0
+1602 y Fh(CS_BAD_HANDLE)208 1746 y Fm(The)f(memory)g(handle)g(is)h(in)n
+(v)-5 b(alid.)0 2016 y Ff(6.2.3)94 b(MTDSetV)-8 b(pp)208
+2204 y Fd(int)39 b(MTDHelperEntry\(MTDSetVpp,)45 b(client_handle_t)e
+(client,)d(mtd_vpp_req_t)i(*req\);)208 2421 y(typedef)e(struct)h
+(mtd_vpp_req_t)h({)521 2525 y(u_char)394 b(Vpp1,)40 b(Vpp2;)208
+2629 y(})f(mtd_vpp_req_t;)0 2855 y Fh(MTDSetVpp)25 b
+Fm(c)n(hanges)j(the)i(programming)d(v)n(oltage)g(for)i(a)f(so)r(c)n(k)n
+(et.)41 b Fh(Vpp1)28 b Fm(and)h Fh(Vpp2)e Fm(should)i(b)r(e)h(giv)n(en)
+e(in)h(units)h(of)f(1/10)0 2969 y(v)n(olt.)36 b(Curren)n(tly)-7
+b(,)27 b Fh(Vpp1)f Fm(should)h(alw)n(a)n(ys)f(equal)h
+Fh(Vpp2)p Fm(.)0 3125 y(Return)h(co)r(des:)0 3338 y Fh(CS_BAD_HANDLE)
+208 3482 y Fm(The)f(clien)n(t)h(handle)f(is)h(in)n(v)-5
+b(alid.)0 3656 y Fh(CS_BAD_VPP)208 3800 y Fm(The)27 b(sp)r(eci\034ed)h
+(V)-7 b(pp)28 b(is)g(not)f(a)n(v)-5 b(ailable,)26 b(or)h(V)-7
+b(pp1)28 b(do)r(es)f(not)h(equal)f(V)-7 b(pp2.)0 4071
+y Ff(6.2.4)94 b(MTDRD)m(YMask)208 4259 y Fd(int)39 b
+(MTDHelperEntry\(MTDRDYMask,)45 b(client_handle_t)e(client,)e
+(mtd_rdy_req_t)h(*req\);)208 4476 y(typedef)e(struct)h(mtd_rdy_req_t)h
+({)521 4580 y(u_int)433 b(Mask;)208 4684 y(})39 b(mtd_rdy_req_t;)0
+4910 y Fh(MTDRDYMask)d Fm(selects)k(whether)g(or)g(not)g
+Fh(CS_EVENT_READY_C)o(HAN)o(GE)34 b Fm(ev)n(en)n(ts)39
+b(will)i(b)r(e)g(enabled.)75 b(The)40 b(clien)n(t)g(should)0
+5024 y(already)d(ha)n(v)n(e)g(indicated)i(to)f(Card)g(Services)f(that)i
+(it)g(should)f(receiv)n(e)f(ready)g(c)n(hange)h(ev)n(en)n(ts,)i(via)e
+(a)g(call)g(to)g(either)0 5137 y Fh(RegisterClient)18
+b Fm(or)23 b Fh(SetEventMask)p Fm(.)30 b(Ready)24 b(c)n(hange)e(ev)n
+(en)n(ts)h(will)h(b)r(e)h(enabled)e(if)h(the)h Fh(CS_EVENT_READY_)o(CH)
+o(ANG)o(E)18 b Fm(bit)0 5251 y(is)27 b(set)h(in)g(the)g
+Fh(Mask)e Fm(argumen)n(t.)0 5407 y(Return)i(co)r(des:)p
+eop
+%%Page: 55 55
+55 54 bop 0 -167 3900 5 v 0 -200 a Ff(7.)73 b(Driv)m(er)33
+b(Services)f(In)m(terface)2631 b Fm(55)0 162 y Fh(CS_BAD_HANDLE)208
+308 y Fm(The)27 b(clien)n(t)h(handle)f(is)h(in)n(v)-5
+b(alid.)0 647 y Fg(7)131 b(Driv)l(er)46 b(Services)f(In)l(terface)0
+885 y Fm(Driv)n(er)24 b(Services)g(pro)n(vides)g(a)h(link)g(b)r(et)n(w)
+n(een)g(Card)g(Services)f(clien)n(t)h(driv)n(ers)f(and)h(user)f(mo)r
+(de)i(utilities)g(lik)n(e)e(the)i Fh(cardmgr)0 999 y
+Fm(daemon.)48 b(It)31 b(is)h(a)f(sort)f(of)h(Card)g(Services)f(\020sup)
+r(er-clien)n(t\021.)47 b(Driv)n(er)31 b(Services)f(uses)h(the)h
+Fh(BindDevice)27 b Fm(function)32 b(to)f(link)0 1113
+y(other)20 b(clien)n(t)i(driv)n(ers)d(with)i(their)g(corresp)r(onding)e
+(cards.)34 b(Unlik)n(e)21 b(other)f(clien)n(ts,)i(Driv)n(er)e(Services)
+g(remains)h(p)r(ermanen)n(tly)0 1226 y(b)r(ound)28 b(to)f(all)h(so)r(c)
+n(k)n(ets)e(as)h(cards)f(are)h(inserted)g(and)g(remo)n(v)n(ed.)0
+1518 y Fe(7.1)112 b(In)m(terface)38 b(to)f(other)g(clien)m(t)e(driv)m
+(ers)0 1728 y Fm(Driv)n(er)d(Services)h(k)n(eeps)f(trac)n(k)g(of)i(all)
+f(clien)n(t)g(driv)n(ers)f(that)i(are)e(installed)h(and)g(ready)g(to)g
+(attac)n(h)g(to)g(a)g(so)r(c)n(k)n(et.)53 b(Clien)n(t)0
+1841 y(driv)n(ers)29 b(need)h(to)g(ha)n(v)n(e)g(en)n(try)f(p)r(oin)n
+(ts)i(for)f(creating)f(and)h(deleting)g(device)g(\020instances\021,)g
+(where)g(one)g(device)g(instance)g(is)0 1955 y(ev)n(erything)c(needed)i
+(to)f(manage)g(one)g(ph)n(ysical)g(card.)0 2111 y(Eac)n(h)j(clien)n(t)g
+(driv)n(er)f(is)h(iden)n(ti\034ed)g(b)n(y)g(a)g(unique)g(16-c)n
+(haracter)d(tag)j(that)g(has)f(the)i(sp)r(ecial)f(t)n(yp)r(e)g
+Fh(dev_info_t)p Fm(,)d(de\034ned)0 2225 y(in)h Fh(cs_types.h)p
+Fm(.)33 b(Eac)n(h)27 b(device)g(instance)g(is)h(describ)r(ed)f(b)n(y)g
+(a)h Fh(dev_link_t)23 b Fm(structure.)0 2498 y Ff(7.1.1)94
+b(The)32 b(dev_link_t)g(structure)0 2708 y Fm(The)c Fh(dev_node_t)23
+b Fm(and)k Fh(dev_link_t)d Fm(data)j(structures)g(are)f(giv)n(en)h(b)n
+(y:)208 2921 y Fd(#include)41 b("ds.h")208 3129 y(typedef)f(struct)h
+(dev_node_t)g({)521 3233 y(char)786 b(dev_name[DEV_NAME_LEN];)521
+3338 y(u_char)708 b(major,)40 b(minor;)521 3442 y(struct)h(dev_node_t)
+277 b(*next;)208 3546 y(})208 3754 y(typedef)40 b(struct)h(dev_link_t)g
+({)521 3858 y(dev_node_t)552 b(*dev;)521 3962 y(u_int)747
+b(state,)40 b(open;)521 4066 y(struct)h(wait_queue)277
+b(*pending)521 4170 y(struct)41 b(timer_list)277 b(release)521
+4275 y(client_handle_t)357 b(handle;)521 4379 y(io_req_t)630
+b(io;)521 4483 y(irq_req_t)591 b(irq;)521 4587 y(config_req_t)474
+b(conf;)521 4691 y(window_handle_t)357 b(win;)521 4795
+y(void)786 b(*priv;)521 4899 y(struct)41 b(dev_link_t)277
+b(*next;)208 5003 y(})39 b(dev_link_t;)0 5226 y Fm(The)27
+b Fh(dev)f Fm(\034eld)h(of)g(the)g Fh(dev_link_t)c Fm(structure)j(p)r
+(oin)n(ts)h(to)f(a)h(link)n(ed)g(list)g(of)g Fh(dev_node_t)22
+b Fm(structures.)36 b(In)27 b Fh(dev_node_t)p Fm(,)0
+5340 y(the)38 b Fh(dev_name)c Fm(\034eld)k(should)g(b)r(e)g(\034lled)g
+(in)g(b)n(y)f(the)h(driv)n(er)e(with)j(a)e(device)g(\034le)h(name)f
+(for)h(accessing)e(this)i(device,)i(if)p eop
+%%Page: 56 56
+56 55 bop 0 -167 3900 5 v 0 -200 a Ff(7.)73 b(Driv)m(er)33
+b(Services)f(In)m(terface)2631 b Fm(56)0 162 y(appropriate.)38
+b(F)-7 b(or)28 b(example,)g(the)h Fh(serial_cs)c Fm(driv)n(er)i(uses)h
+(names)g(lik)n(e)h(\020)7 b Fh(ttyS1)p Fm(\021.)37 b(The)28
+b Fh(major)f Fm(and)h Fh(minor)f Fm(\034elds)h(giv)n(e)0
+275 y(ma)5 b(jor)28 b(and)h(minor)g(device)g(n)n(um)n(b)r(ers)g(for)g
+(accessing)f(this)i(device.)42 b(Driv)n(er)28 b(Services)g(rela)n(ys)g
+(these)i(\034elds)f(to)g(user)g(mo)r(de)0 389 y(programs)c(via)i(the)h
+Fh(DS_GET_DEVICE_IN)o(FO)21 b Fm(io)r(ctl.)0 545 y(In)26
+b Fh(dev_link_t)p Fm(,)d(the)j Fh(state)f Fm(\034eld)h(should)g(b)r(e)h
+(used)f(to)g(k)n(eep)g(trac)n(k)f(of)h(the)g(curren)n(t)g(device)g
+(state.)36 b(The)26 b(follo)n(wing)f(\035ags)0 659 y(are)i(de\034ned:)0
+898 y Fh(DEV_PRESENT)208 1045 y Fm(Indicates)h(that)g(the)h(card)f(is)g
+(presen)n(t.)39 b(This)28 b(bit)h(should)f(b)r(e)h(set)g(and)f(cleared)
+f(b)n(y)h(the)h(driv)n(er's)e(ev)n(en)n(t)h(handler)g(in)208
+1159 y(resp)r(onse)e(to)h(card)g(insertion)g(and)g(remo)n(v)-5
+b(al)27 b(ev)n(en)n(ts.)0 1339 y Fh(DEV_CONFIG)208 1486
+y Fm(Indicates)g(that)h(the)g(card)e(is)i(con\034gured)e(for)h(use.)0
+1665 y Fh(DEV_CONFIG_PENDI)o(NG)208 1812 y Fm(Indicates)g(that)h
+(con\034guration)d(is)j(in)g(progress.)0 1992 y Fh(DEV_SUSPEND)208
+2139 y Fm(Indicates)f(that)h(the)g(card)e(is)i(susp)r(ended.)0
+2319 y Fh(DEV_BUSY)208 2466 y Fm(Indicates)h(that)g(an)g(IO)h(op)r
+(eration)e(is)h(in)h(progress.)40 b(This)29 b(bit)h(ma)n(y)f(b)r(e)h
+(used)f(as)g(an)g(in)n(terlo)r(c)n(k)g(to)g(prev)n(en)n(t)f(access)208
+2579 y(con\035icts.)0 2759 y Fh(DEV_STALE_CONFIG)208
+2906 y Fm(F)-7 b(or)18 b(some)g(driv)n(ers,)h(when)g(a)g(running)f
+(card)g(is)h(ejected,)i(the)e(so)r(c)n(k)n(et)f(should)g(not)h(b)r(e)g
+(uncon\034gured)f(un)n(til)i(an)n(y)e(devices)208 3020
+y(corresp)r(onding)23 b(to)j(this)f(card)g(are)g(closed.)35
+b(This)26 b(\035ag)e(indicates)i(that)g(the)g(so)r(c)n(k)n(et)e(should)
+h(b)r(e)h(uncon\034gured)f(when)208 3133 y(the)j(device)f(is)g(closed.)
+0 3313 y Fh(DEV_STALE_LINK)208 3460 y Fm(A)e(driv)n(er)e(instance)i
+(should)f(not)h(b)r(e)g(deleted)g(un)n(til)g(all)g(its)g(resources)d
+(are)i(released.)35 b(This)24 b(\035ag)g(indicates)h(that)g(this)208
+3574 y(driv)n(er)h(instance)h(should)g(b)r(e)h(freed)g(as)f(so)r(on)f
+(as)h(the)h(so)r(c)n(k)n(et)f(is)g(uncon\034gured.)0
+3813 y(The)e Fh(open)e Fm(\034eld)h(is)h(a)f(usage)g(coun)n(t)g(for)g
+(this)h(device.)35 b(The)25 b(device)f(should)h(only)f(b)r(e)h(freed)f
+(when)h(the)g(op)r(en)f(coun)n(t)h(is)f(zero.)0 3927
+y(The)k Fh(pending)c Fm(\034eld)k(can)f(b)r(e)h(used)g(to)f(manage)g(a)
+g(queue)g(of)h(pro)r(cesses)e(w)n(aiting)h(to)g(use)g(the)h(device.)0
+4083 y(The)j Fh(release)d Fm(\034eld)k(is)e(used)h(to)g(sc)n(hedule)g
+(device)g(sh)n(utdo)n(wn)f(pro)r(cessing)g(when)h(a)f(card)g(is)h
+(ejected.)48 b(A)31 b(card)f(remo)n(v)-5 b(al)0 4197
+y(ev)n(en)n(t)31 b(needs)h(to)f(b)r(e)h(handled)g(at)g(high)f(priorit)n
+(y)-7 b(,)32 b(so)f(a)g(driv)n(er's)f(ev)n(en)n(t)h(handler)g(will)h(t)
+n(ypically)f(deal)h(with)g(an)f(eject)h(b)n(y)0 4310
+y(resetting)25 b(the)g Fh(DEV_PRESENT)c Fm(bit)26 b(in)f(the)h(device)f
+(state,)g(then)h(sc)n(heduling)f(the)g(sh)n(utdo)n(wn)g(pro)r(cessing)f
+(to)h(run)g(at)g(a)g(later)0 4424 y(time.)0 4580 y(The)31
+b Fh(handle)p Fm(,)e Fh(io)p Fm(,)h Fh(irq)p Fm(,)h Fh(conf)p
+Fm(,)f(and)g Fh(win)g Fm(\034elds)g(comprise)g(all)g(the)h(normal)f
+(data)g(structures)g(needed)g(to)h(con\034gure)e(an)0
+4694 y(ordinary)d(PC)i(Card)f(IO)g(device)0 4850 y(The)22
+b Fh(priv)e Fm(\034eld)i(can)g(b)r(e)g(used)g(for)f(an)n(y)g(sort)g(of)
+h(priv)-5 b(ate)22 b(data)f(structure)g(needed)h(to)g(manage)f(the)h
+(device.)35 b(The)22 b Fh(next)e Fm(\034eld)0 4964 y(can)27
+b(b)r(e)h(used)g(to)f(build)h(link)n(ed)g(lists)f(of)h
+Fh(dev_link_t)23 b Fm(structures,)k(for)g(driv)n(ers)f(that)i(can)f
+(handle)g(m)n(ultiple)h(instances.)p eop
+%%Page: 57 57
+57 56 bop 0 -167 3900 5 v 0 -200 a Ff(7.)73 b(Driv)m(er)33
+b(Services)f(In)m(terface)2631 b Fm(57)0 162 y Ff(7.1.2)94
+b(register_p)s(ccard_driv)m(er)208 353 y Fd(int)39 b
+(register_pccard_driver\(dev_i)q(nfo_t)46 b(*dev_info,)1266
+457 y(dev_link_t)c(*\(*attach\)\(void\),)1266 561 y(void)f
+(\(*detach\)\(dev_link_t)i(*\)\);)0 800 y Fh(register_pccard_)o(dr)o
+(ive)o(r)23 b Fm(informs)28 b(Driv)n(er)g(Services)g(that)i(a)e(clien)n
+(t)i(driv)n(er)d(is)i(presen)n(t)g(and)f(ready)g(to)h(b)r(e)h(b)r(ound)
+f(to)0 914 y(so)r(c)n(k)n(ets.)34 b(When)25 b(Driv)n(er)f(Services)f
+(receiv)n(es)g(a)h Fh(DS_BIND_REQUEST)18 b Fm(io)r(ctl)25
+b(that)f(matc)n(hes)g(this)h(driv)n(er's)e Fh(dev_info)e
+Fm(string,)0 1027 y(it)i(will)g(call)f(the)h(driv)n(er's)e
+Fh(attach\(\))e Fm(en)n(try)j(p)r(oin)n(t.)36 b(When)23
+b(it)g(gets)f(a)g Fh(DS_UNBIND_REQUES)o(T)17 b Fm(io)r(ctl,)23
+b(it)g(will)g(call)f Fh(detach\(\))p Fm(.)0 1300 y Ff(7.1.3)94
+b(unregister_p)s(ccard_driv)m(er)208 1491 y Fd(int)39
+b(unregister_pccard_driver\(dev)q(_info)q(_t)45 b(*dev_info\);)0
+1731 y Fm(This)28 b(informs)f(Driv)n(er)f(Services)h(that)h(it)g
+(should)f(no)g(longer)f(bind)i(so)r(c)n(k)n(ets)f(to)g(the)h(sp)r
+(eci\034ed)g(clien)n(t)f(driv)n(er.)0 2022 y Fe(7.2)112
+b(The)38 b(CardBus)g(clien)m(t)d(in)m(terface)0 2232
+y Fm(The)d(CardBus)e(card)h(in)n(terface)g(is)g(designed)h(to)f(b)r(e)h
+(essen)n(tially)f(an)g(extension)g(of)h(the)g(PCI)g(bus.)49
+b(CardBus)31 b(cards)f(are)0 2346 y(t)n(ypically)k(designed)f(using)h
+(standard)f(PCI)i(c)n(hip)f(sets.)57 b(F)-7 b(or)33 b(simplicit)n(y)i
+(in)f(the)h(clien)n(t)f(driv)n(ers,)g(and)g(maxim)n(um)g(co)r(de)0
+2459 y(sharing)29 b(with)j(regular)c(k)n(ernel)i(PCI)h(driv)n(ers,)f(w)
+n(e)h(pro)n(vide)e(a)h(sort)g(of)h(\020sup)r(er)f(clien)n(t\021)37
+b(for)30 b(con\034guring)g(CardBus)f(cards.)0 2573 y(This)f(is)f
+(implemen)n(ted)h(in)g(the)g Fh(cb_enabler)23 b Fm(mo)r(dule.)0
+2729 y(The)35 b Fh(cb_enabler)d Fm(mo)r(dule)j(is)h(somewhat)e(similar)
+h(in)h(philosoph)n(y)e(to)h(the)h(Driv)n(er)f(Services)f(la)n(y)n(er)g
+(for)h(16-bit)f(cards.)0 2843 y(CardBus)18 b(clien)n(t)g(driv)n(ers)g
+(register)f(with)i(it,)i(and)e(pro)n(vide)e(a)i(few)g(en)n(try)f(p)r
+(oin)n(ts)h(for)f(handling)g(device)h(setup)g(and)g(sh)n(utdo)n(wn,)0
+2956 y(as)34 b(w)n(ell)h(as)f(p)r(o)n(w)n(er)g(managemen)n(t)g
+(handling.)59 b(The)35 b Fh(cb_enabler)30 b Fm(mo)r(dule)36
+b(tak)n(es)e(care)f(of)i(con\034guring)f(the)h(card)f(and)0
+3070 y(\034elding)28 b(Card)e(Services)h(ev)n(en)n(ts.)36
+b(So,)27 b(all)g(CardBus-sp)r(eci\034c)g(co)r(de)g(is)g(in)h(the)g
+(enabler)f(rather)f(than)i(the)g(PCI)g(driv)n(er.)0 3226
+y(It)37 b(is)g(not)f(mandatory)g(for)g(CardBus)f(clien)n(ts)i(to)f(use)
+h(the)g Fh(cb_enabler)32 b Fm(in)n(terface.)64 b(If)37
+b(a)f(particular)g(clien)n(t)g(requires)0 3340 y(more)25
+b(direct)h(con)n(trol)e(o)n(v)n(er)g(its)i(CardBus)f(con\034guration)f
+(than)i(is)f(pro)n(vided)g(through)g(the)h Fh(cb_enabler)c
+Fm(mo)r(dule,)k(it)g(can)0 3454 y(register)g(directly)h(with)h(Card)f
+(Services)g(and)g(p)r(erform)g(Card)g(Services)f(calls)h(directly)-7
+b(,)28 b(just)g(lik)n(e)f(a)g(16-bit)g(clien)n(t.)0 3610
+y(The)f Fh(cb_enabler)d Fm(mo)r(dule)j(has)g(t)n(w)n(o)f(en)n(try)h(p)r
+(oin)n(ts:)36 b Fh(register_driver)20 b Fm(and)26 b Fh
+(unregister_drive)o(r)p Fm(.)31 b(A)n(t)26 b(some)g(p)r(oin)n(t,)0
+3724 y(these)i(functions)f(ma)n(y)g(migrate)g(in)n(to)g(the)h(k)n
+(ernel:)36 b(hence)28 b(the)f(generic)g(names.)0 3996
+y Ff(7.2.1)94 b(register_driv)m(er)208 4187 y Fd(int)39
+b(register_driver\(struct)44 b(driver_operations)f(*ops\);)0
+4427 y Fm(The)28 b Fh(driver_operatio)o(ns)21 b Fm(structure)27
+b(is)h(giv)n(en)e(b)n(y:)208 4640 y Fd(typedef)40 b(struct)h
+(driver_operations)i({)521 4744 y(char)472 b(*name)521
+4848 y(dev_node_t)238 b(*\(*attach\))41 b(\(dev_locator_t)h(*loc\);)521
+4952 y(void)472 b(\(*suspend\))41 b(\(dev_node_t)h(*dev\);)521
+5057 y(void)472 b(\(*resume\))41 b(\(dev_node_t)h(*dev\);)521
+5161 y(void)472 b(\(*detach\))41 b(\(dev_node_t)h(*dev\);)208
+5265 y(})d(driver_operations;)p eop
+%%Page: 58 58
+58 57 bop 0 -167 3900 5 v 0 -200 a Ff(7.)73 b(Driv)m(er)33
+b(Services)f(In)m(terface)2631 b Fm(58)0 162 y(The)38
+b Fh(name)f Fm(\034eld)h(is)g(used)g(b)n(y)f Fh(cb_enabler)d
+Fm(when)39 b(registering)d(this)i(clien)n(t)g(with)h(Card)e(Services.)
+67 b(The)38 b(rest)g(of)g(the)0 275 y(structure)27 b(describ)r(es)g(a)g
+(set)h(of)f(ev)n(en)n(t)g(handlers)g(for)g(this)h(clien)n(t.)0
+432 y(The)g(function)g(returns)f(0)g(on)g(success,)g(and)g(-1)g(on)g
+(failure.)0 704 y Ff(7.2.2)94 b(unregister_driv)m(er)208
+895 y Fd(void)40 b(unregister_driver\(struct)k(driver_operations)f
+(*ops\);)0 1135 y Fm(The)19 b Fh(ops)e Fm(parameter)h(should)g(b)r(e)h
+(the)h(same)e(structure)g(p)r(oin)n(ter)g(passed)g(to)h(a)f(prior)g
+(successful)g(call)h(to)f Fh(register_driver)p Fm(.)0
+1248 y(The)29 b(clien)n(t)h(should)f(tak)n(e)f(care)g(to)i(only)e(call)
+h(this)h(function)g(when)f(no)g(devices)g(are)f(curren)n(tly)g(b)r
+(eing)i(managed)e(b)n(y)h(this)0 1362 y(clien)n(t.)0
+1635 y Ff(7.2.3)94 b(The)32 b(driv)m(er_op)s(erations)f(en)m(try)i(p)s
+(oin)m(ts)0 1845 y Fm(The)c Fh(attach\(\))c Fm(en)n(try)j(p)r(oin)n(t)g
+(is)h(used)f(to)h(con\034gure)e(a)h(single)g(device,)h(giv)n(en)e(a)h
+(\020device)g(lo)r(cator\021)34 b(structure)28 b(describing)0
+1958 y(where)f(to)g(\034nd)h(it.)0 2115 y(The)g Fh(dev_locator_t)22
+b Fm(structure)27 b(is)g(giv)n(en)g(b)n(y:)208 2328 y
+Fd(typedef)40 b(struct)h(dev_locator_t)h({)521 2432 y(enum)e({)g
+(LOC_ISA,)h(LOC_PCI)g(})e(bus;)521 2536 y(union)i({)835
+2640 y(struct)g({)1149 2745 y(u_short)354 b(io_base_1,)42
+b(io_base_2;)1149 2849 y(u_long)393 b(mem_base;)1149
+2953 y(u_char)g(irq,)40 b(dma;)835 3057 y(})f(isa;)835
+3161 y(struct)i({)1149 3265 y(u_char)393 b(bus;)1149
+3369 y(u_char)g(devfn;)835 3473 y(})39 b(pci;)521 3577
+y(})h(b;)208 3681 y(})f(dev_locator_t;)0 3904 y Fm(The)23
+b Fh(attach\(\))c Fm(function)24 b(should)e(return)h(either)g
+Fh(NULL)e Fm(or)h(a)g(v)-5 b(alid)23 b Fh(dev_node_t)c
+Fm(structure)j(describing)g(the)h(new)g(device.)0 4018
+y(All)31 b(the)g(other)f(en)n(try)g(p)r(oin)n(ts)h(will)g(use)f(this)h
+(p)r(oin)n(ter)g(to)f(iden)n(tify)h(the)g(device)g(to)f(b)r(e)h
+(manipulated.)47 b(The)30 b Fh(cb_enabler)0 4132 y Fm(mo)r(dule)21
+b(will)g(in)n(v)n(ok)n(e)e(the)j Fh(attach\(\))17 b Fm(and)k
+Fh(detach\(\))d Fm(en)n(try)i(p)r(oin)n(ts)h(in)g(resp)r(onse)f(to)g
+(card)g(insertion)h(and)f(remo)n(v)-5 b(al)20 b(ev)n(en)n(ts.)0
+4245 y(The)28 b Fh(suspend\(\))23 b Fm(and)28 b Fh(resume\(\))c
+Fm(en)n(try)j(p)r(oin)n(ts)h(will)f(b)r(e)h(called)f(in)h(resp)r(onse)f
+(to)g(p)r(o)n(w)n(er)g(managemen)n(t)f(ev)n(en)n(ts.)0
+4402 y(There)h(is)g(no)g(w)n(a)n(y)f(for)h(a)g(driv)n(er)f(to)h(refuse)
+g(a)f Fh(suspend\(\))e Fm(or)i Fh(detach\(\))e Fm(ev)n(en)n(t.)37
+b(When)27 b(a)g Fh(detach\(\))d Fm(ev)n(en)n(t)j(is)g(receiv)n(ed,)0
+4515 y(the)f(driv)n(er)e(should)h(blo)r(c)n(k)f(an)n(y)h(subsequen)n(t)
+g(IO)g(to)g(the)h(sp)r(eci\034ed)f(device,)h(but)g(ma)n(y)e(preserv)n
+(e)g(in)n(ternal)g(data)h(structures)0 4629 y(un)n(til)j(the)g(k)n
+(ernel)f(device)g(is)g(actually)g(closed.)0 4920 y Fe(7.3)112
+b(In)m(terface)38 b(to)f(user)g(mo)s(de)g(utilities)0
+5130 y Fm(Driv)n(er)32 b(Services)g(creates)g(a)g(pseudo-device)g(for)h
+(comm)n(unicating)f(with)h(user)g(mo)r(de)g(PC)g(Card)g(utilities.)53
+b(The)33 b(ma)5 b(jor)0 5244 y(n)n(um)n(b)r(er)25 b(of)g(the)g(device)g
+(is)f(c)n(hosen)g(dynamically)-7 b(,)25 b(and)g(PC)g(Card)f(utilities)i
+(should)f(read)f Fh(/proc/devices)19 b Fm(to)25 b(determine)0
+5357 y(it.)37 b(Minor)27 b(device)h(n)n(um)n(b)r(ers)f(corresp)r(ond)e
+(to)j(so)r(c)n(k)n(et)e(n)n(um)n(b)r(ers,)h(starting)g(with)h(0.)p
+eop
+%%Page: 59 59
+59 58 bop 0 -167 3900 5 v 0 -200 a Ff(7.)73 b(Driv)m(er)33
+b(Services)f(In)m(terface)2631 b Fm(59)0 162 y(Only)28
+b(one)h(pro)r(cess)f(is)g(allo)n(w)n(ed)g(to)g(op)r(en)h(a)g(so)r(c)n
+(k)n(et)e(for)i(read/write)e(access.)39 b(Other)28 b(pro)r(cesses)g
+(can)g(op)r(en)h(the)g(so)r(c)n(k)n(et)f(in)0 275 y(read-only)20
+b(mo)r(de.)35 b(A)21 b(read-only)f(connection)h(to)g(Driv)n(er)f
+(Services)h(can)g(p)r(erform)g(a)g(subset)g(of)h Fh(ioctl)d
+Fm(calls.)34 b(A)22 b(read/write)0 389 y(connection)27
+b(can)g(issue)g(all)h Fh(ioctl)d Fm(calls,)i(and)h(can)f(also)f(receiv)
+n(e)g(Card)h(Services)g(ev)n(en)n(t)g(noti\034cations.)0
+660 y Ff(7.3.1)94 b(Card)32 b(Services)g(ev)m(en)m(t)g(noti\034cations)
+0 870 y Fm(Driv)n(er)24 b(Services)h(implemen)n(ts)g
+Fh(read\(\))e Fm(and)i Fh(select\(\))d Fm(functions)k(for)f(ev)n(en)n
+(t)g(noti\034cation.)35 b(Reading)25 b(from)g(a)g(PC)h(Card)0
+983 y(device)d(returns)g(an)g(unsigned)h(long)e(v)-5
+b(alue)24 b(con)n(taining)e(all)i(the)g(ev)n(en)n(ts)e(receiv)n(ed)h(b)
+n(y)g(Driv)n(er)f(Services)h(since)g(the)h(previous)0
+1097 y Fh(read\(\))p Fm(.)47 b(If)32 b(no)f(ev)n(en)n(ts)g(ha)n(v)n(e)g
+(b)r(een)h(receiv)n(ed,)f(the)i(call)e(will)h(blo)r(c)n(k)f(un)n(til)h
+(the)g(next)g(ev)n(en)n(t.)49 b(A)32 b Fh(select\(\))c
+Fm(call)j(can)h(b)r(e)0 1211 y(used)c(to)f(monitor)g(sev)n(eral)f(so)r
+(c)n(k)n(ets)g(for)h(new)g(ev)n(en)n(ts.)0 1367 y(The)121
+b(follo)n(wing)g(ev)n(en)n(ts)f(are)h(monitored)g(b)n(y)g(Driv)n(er)f
+(Services:)224 b Fh(CS_EVENT_CARD_I)o(NS)o(ERT)o(IO)o(N)p
+Fm(,)0 1481 y Fh(CS_EVENT_CARD_RE)o(MO)o(VAL)o Fm(,)311
+b Fh(CS_EVENT_RESET_PH)o(YS)o(ICA)o(L)p Fm(,)g Fh(CS_EVENT_CARD_RE)o
+(SE)o(T)p Fm(,)g(and)0 1594 y Fh(CS_EVENT_RESET_C)o(OM)o(PLE)o(TE)o
+Fm(.)0 1865 y Ff(7.3.2)94 b(Io)s(ctl)31 b(descriptions)0
+2075 y Fm(Most)c(Driv)n(er)g(Services)f Fh(ioctl)g Fm(op)r(erations)g
+(directly)h(map)h(to)f(Card)g(Services)g(functions.)37
+b(An)28 b(io)r(ctl)f(call)h(has)f(the)h(form:)208 2296
+y Fd(int)39 b(ioctl\(int)j(fd,)d(int)h(cmd,)g(ds_ioctl_arg_t)j(*arg\);)
+0 2526 y Fm(The)28 b(ds_io)r(ctl_arg_t)d(structure)i(is)g(giv)n(en)g(b)
+n(y:)208 2732 y Fd(typedef)40 b(union)h(ds_ioctl_arg_t)h({)521
+2836 y(servinfo_t)238 b(servinfo;)521 2940 y(adjust_t)316
+b(adjust;)521 3044 y(config_info_t)121 b(config;)521
+3148 y(tuple_t)355 b(tuple;)521 3252 y(tuple_parse_t)121
+b(tuple_parse;)521 3356 y(client_req_t)160 b(client_req;)521
+3461 y(status_t)316 b(status;)521 3565 y(conf_reg_t)238
+b(conf_reg;)521 3669 y(cisinfo_t)277 b(cisinfo;)521 3773
+y(region_info_t)121 b(region;)521 3877 y(bind_info_t)199
+b(bind_info;)521 3981 y(mtd_info_t)238 b(mtd_info;)521
+4085 y(cisdump_t)277 b(cisdump;)208 4189 y(})39 b(ds_ioctl_arg_t;)0
+4405 y Fm(The)28 b(follo)n(wing)e Fh(ioctl)g Fm(commands)g(execute)i
+(the)g(corresp)r(onding)d(Card)i(Services)g(function:)0
+4620 y Fh(DS_GET_CARD_SERV)o(IC)o(ES_)o(IN)o(FO)208 4765
+y Fm(Calls)g Fh(CardServices\(Ge)o(tC)o(ar)o(dSe)o(rv)o(ic)o(esI)o(nf)o
+(o,)37 b(...,)42 b(&arg-)p Fc(>)p Fh(servinfo\))p Fm(.)0
+4941 y Fh(DS_ADJUST_RESOUR)o(CE)o(_IN)o(FO)208 5086 y
+Fm(Calls)27 b Fh(CardServices\(Ad)o(ju)o(st)o(Res)o(ou)o(rc)o(eIn)o(fo)
+o(,)38 b(...,)j(&arg-)p Fc(>)p Fh(adjust\))p Fm(.)0 5262
+y Fh(DS_GET_CONFIGURA)o(TI)o(ON_)o(IN)o(FO)208 5407 y
+Fm(Calls)27 b Fh(CardServices\(Ge)o(tC)o(on)o(fig)o(ur)o(at)o(ion)o(In)
+o(fo,)37 b(...,)42 b(&arg-)p Fc(>)p Fh(config\))p Fm(.)p
+eop
+%%Page: 60 60
+60 59 bop 0 -167 3900 5 v 0 -200 a Ff(7.)73 b(Driv)m(er)33
+b(Services)f(In)m(terface)2631 b Fm(60)0 162 y Fh(DS_GET_FIRST_TUP)o
+(LE)208 308 y Fm(Calls)27 b Fh(CardServices\(Ge)o(tF)o(ir)o(stT)o(up)o
+(le)o(,)38 b(...,)k(&arg-)p Fc(>)p Fh(tuple\))p Fm(.)0
+486 y Fh(DS_GET_NEXT_TUPL)o(E)208 632 y Fm(Calls)27 b
+Fh(CardServices\(Ge)o(tN)o(ex)o(tTu)o(pl)o(e,)37 b(...,)42
+b(&arg-)p Fc(>)p Fh(tuple\))p Fm(.)0 810 y Fh(DS_GET_TUPLE_DAT)o(A)208
+956 y Fm(Calls)26 b Fh(CardServices\(Get)o(Tup)o(le)o(Dat)o(a,)37
+b(...,)42 b(&arg-)p Fc(>)p Fh(tuple_par)o(se)o(.tu)o(pl)o(e\))p
+Fm(.)30 b(The)e(tuple)g(data)e(is)i(returned)208 1070
+y(in)f Fh(arg-)p Fc(>)p Fh(tuple_parse.)o(da)o(ta)o Fm(.)0
+1248 y Fh(DS_PARSE_TUPLE)208 1394 y Fm(Calls)1137 b Fh
+(CardServices\(Par)o(se)o(Tu)o(ple)o(,)37 b(...,)42 b(&arg-)p
+Fc(>)p Fh(tuple_pars)o(e.t)o(up)o(le)o(,)208 1507 y(&arg-)p
+Fc(>)p Fh(tuple_par)o(se)o(.p)o(ars)o(e\))o Fm(.)0 1686
+y Fh(DS_RESET_CARD)208 1832 y Fm(Calls)27 b Fh(CardServices\(Re)o(se)o
+(tC)o(ard)o(,)37 b(...\))p Fm(.)0 2010 y Fh(DS_GET_STATUS)208
+2156 y Fm(Calls)27 b Fh(CardServices\(Ge)o(tS)o(ta)o(tus)o(,)37
+b(...,)42 b(&arg-)p Fc(>)p Fh(status\))p Fm(.)0 2334
+y Fh(DS_ACCESS_CONFIG)o(UR)o(ATI)o(ON)o(_R)o(EGI)o(ST)o(ER)208
+2480 y Fm(Calls)27 b Fh(CardServices\(Ac)o(ce)o(ss)o(Con)o(fi)o(gu)o
+(rat)o(io)o(nRe)o(gi)o(st)o(er,)37 b(...,)42 b(&arg-)p
+Fc(>)p Fh(conf_reg\))o Fm(.)0 2659 y Fh(DS_VALIDATE_CIS)208
+2804 y Fm(Calls)27 b Fh(CardServices\(Va)o(li)o(da)o(teC)o(IS)o(,)37
+b(...,)42 b(&arg-)p Fc(>)p Fh(cisinfo\))p Fm(.)0 2983
+y Fh(DS_SUSPEND_CARD)208 3129 y Fm(Calls)27 b Fh(CardServices\(Su)o(sp)
+o(en)o(dCa)o(rd)o(,)37 b(...\))p Fm(.)0 3307 y Fh(DS_RESUME_CARD)208
+3453 y Fm(Calls)27 b Fh(CardServices\(Re)o(su)o(me)o(Car)o(d,)37
+b(...\))p Fm(.)0 3631 y Fh(DS_EJECT_CARD)208 3777 y Fm(Calls)27
+b Fh(CardServices\(Ej)o(ec)o(tC)o(ard)o(,)37 b(...\))p
+Fm(.)0 3955 y Fh(DS_INSERT_CARD)208 4101 y Fm(Calls)27
+b Fh(CardServices\(In)o(se)o(rt)o(Car)o(d,)37 b(...\))p
+Fm(.)0 4280 y Fh(DS_GET_FIRST_REG)o(IO)o(N)208 4426 y
+Fm(Calls)27 b Fh(CardServices\(Ge)o(tF)o(ir)o(stR)o(eg)o(io)o(n,)37
+b(...,)42 b(&arg-)p Fc(>)p Fh(region\))p Fm(.)0 4604
+y Fh(DS_GET_NEXT_REGI)o(ON)208 4750 y Fm(Calls)27 b Fh
+(CardServices\(Ge)o(tN)o(ex)o(tRe)o(gi)o(on)o(,)38 b(...,)k(&arg-)p
+Fc(>)p Fh(region\))p Fm(.)0 4928 y Fh(DS_REPLACE_CIS)208
+5074 y Fm(Calls)27 b Fh(CardServices\(Re)o(pl)o(ac)o(eCI)o(S,)37
+b(...,)42 b(&arg-)p Fc(>)p Fh(cisdump\))p Fm(.)0 5294
+y(The)31 b(follo)n(wing)f Fh(ioctl)e Fm(commands)j(in)n(v)n(ok)n(e)e
+(sp)r(ecial)h(Driv)n(er)g(Services)g(functions.)47 b(They)30
+b(act)h(on)g Fh(bind_info_t)26 b Fm(struc-)0 5407 y(tures:)p
+eop
+%%Page: 61 61
+61 60 bop 0 -167 3900 5 v 0 -200 a Ff(8.)73 b(Anatom)m(y)32
+b(of)g(a)g(Card)g(Services)g(Clien)m(t)f(Driv)m(er)1904
+b Fm(61)208 162 y Fd(typedef)40 b(struct)h(bind_info_t)g({)521
+266 y(dev_info_t)552 b(dev_info;)521 370 y(u_char)708
+b(function;)521 474 y(struct)41 b(dev_info_t)277 b(*instance;)521
+578 y(char)786 b(name[DEV_NAME_LEN];)521 682 y(u_char)708
+b(major,)40 b(minor;)521 786 y(void)786 b(*next;)208
+890 y(})39 b(bind_info_t;)0 1130 y Fh(DS_BIND_REQUEST)208
+1277 y Fm(This)25 b(call)g(connects)g(a)g(so)r(c)n(k)n(et)f(to)h(a)g
+(clien)n(t)h(driv)n(er.)34 b(The)26 b(sp)r(eci\034ed)f(device)g(ID)h
+Fh(dev_info)c Fm(is)k(lo)r(ok)n(ed)e(up)i(in)f(the)h(list)208
+1390 y(of)j(registered)e(driv)n(ers.)40 b(If)29 b(this)g(is)g(a)g(m)n
+(ultifunction)h(card,)e(the)i Fh(function)25 b Fm(\034eld)30
+b(iden)n(ti\034es)f(whic)n(h)f(card)h(function)208 1504
+y(is)h(b)r(eing)h(b)r(ound.)48 b(If)31 b(found,)h(the)g(driv)n(er)d(is)
+i(b)r(ound)h(to)e(this)i(so)r(c)n(k)n(et)d(and)i(function)h(using)e
+(the)i Fh(BindDevice)26 b Fm(call.)208 1617 y(Then,)31
+b(Driv)n(er)f(Services)g(calls)g(the)h(clien)n(t)g(driv)n(er's)f
+Fh(attach\(\))d Fm(en)n(try)j(p)r(oin)n(t)h(to)g(create)f(a)g(device)h
+(instance.)46 b(The)208 1731 y(new)27 b Fh(dev_link_t)d
+Fm(p)r(oin)n(ter)j(is)g(returned)g(in)h Fh(instance)p
+Fm(.)0 1911 y Fh(DS_GET_DEVICE_IN)o(FO)208 2058 y Fm(This)f(call)h
+(retriev)n(es)e(the)i Fh(dev_name)p Fm(,)c Fh(major)p
+Fm(,)i(and)i Fh(minor)d Fm(en)n(tries)i(from)h(the)g
+Fh(dev_link_t)23 b Fm(structure)k(p)r(oin)n(ted)h(to)208
+2171 y(b)n(y)f Fh(instance)p Fm(.)0 2351 y Fh(DS_UNBIND_REQUES)o(T)208
+2498 y Fm(This)g(call)g(calls)g(the)h Fh(detach\(\))c
+Fm(function)k(for)g(the)f(sp)r(eci\034ed)h(driv)n(er)e(and)i(instance,)
+f(sh)n(utting)h(do)n(wn)f(this)h(device.)0 2738 y(Finally)-7
+b(,)28 b(the)g Fh(DS_BIND_MTD)23 b Fm(request)j(tak)n(es)h(an)g
+(argumen)n(t)g(of)g(t)n(yp)r(e)h Fh(mtd_info_t)p Fm(:)208
+2968 y Fd(typedef)40 b(struct)h(mtd_info_t)g({)521 3072
+y(dev_info_t)238 b(dev_info;)521 3176 y(u_int)433 b(Attributes;)521
+3280 y(u_int)g(CardOffset;)208 3384 y(})39 b(mtd_info_t;)0
+3624 y Fm(This)32 b(call)g(asso)r(ciates)f(an)h(MTD)h(iden)n(ti\034ed)g
+(b)n(y)f Fh(dev_info)d Fm(with)k(a)f(memory)g(region)f(describ)r(ed)h
+(b)n(y)g Fh(Attributes)c Fm(and)0 3737 y Fh(CardOffset)p
+Fm(,)23 b(whic)n(h)28 b(ha)n(v)n(e)e(the)i(same)f(meanings)g(as)g(in)h
+(the)g(Card)e(Services)h Fh(BindMTD)e Fm(call.)0 4076
+y Fg(8)131 b(Anatom)l(y)44 b(of)g(a)g(Card)f(Services)i(Clien)l(t)h
+(Driv)l(er)0 4314 y Fm(Eac)n(h)29 b(release)f(of)i(the)g(Lin)n(ux)f
+(Card)f(Services)h(pac)n(k)-5 b(age)28 b(comes)h(with)h(a)f(w)n
+(ell-commen)n(ted)f(\020dumm)n(y\021)36 b(clien)n(t)30
+b(driv)n(er)e(that)0 4428 y(should)k(b)r(e)h(used)f(as)g(a)g(starting)f
+(p)r(oin)n(t)i(for)f(writing)g(a)g(new)g(driv)n(er.)50
+b(Lo)r(ok)32 b(for)g(it)g(in)h Fh(clients/dummy_cs)o(.c)o
+Fm(.)46 b(This)32 b(is)0 4541 y(not)f(just)g(a)g(piece)g(of)g(sample)f
+(co)r(de:)43 b(it)32 b(is)e(written)h(to)g(function)h(as)e(a)g(sort)g
+(of)h(generic)f(card)g(enabler.)46 b(If)31 b(b)r(ound)h(to)e(an)0
+4655 y(IO)i(card,)g(it)g(will)g(read)f(the)h(card's)f(CIS)h(and)g
+(con\034gure)f(the)h(card)f(appropriately)-7 b(,)31 b(assuming)g(that)h
+(the)g(card's)f(CIS)h(is)0 4768 y(complete)27 b(and)h(accurate.)0
+5060 y Fe(8.1)112 b(Mo)s(dule)38 b(initialization)32
+b(and)39 b(clean)m(up)0 5270 y Fm(All)29 b(loadable)f(mo)r(dules)g(m)n
+(ust)h(supply)f Fh(init_module\(\))c Fm(and)k Fh(cleanup_module\(\))22
+b Fm(functions,)29 b(whic)n(h)g(are)e(in)n(v)n(ok)n(ed)g(b)n(y)0
+5384 y(the)k(mo)r(dule)f(supp)r(ort)h(co)r(de)f(when)g(the)h(mo)r(dule)
+g(is)f(installed)g(and)h(remo)n(v)n(ed.)43 b(A)31 b(clien)n(t)g(driv)n
+(er's)d(init)j(function)g(should)p eop
+%%Page: 62 62
+62 61 bop 0 -167 3900 5 v 0 -200 a Ff(8.)73 b(Anatom)m(y)32
+b(of)g(a)g(Card)g(Services)g(Clien)m(t)f(Driv)m(er)1904
+b Fm(62)0 162 y(register)35 b(the)i(driv)n(er)e(with)i(Driv)n(er)f
+(Services,)h(via)f(the)h Fh(register_pccard_)o(dri)o(ve)o(r\(\))30
+b Fm(call.)63 b(The)37 b(clean)n(up)f(function)0 275
+y(should)27 b(use)g Fh(unregister_pcca)o(rd_)o(dr)o(iv)o(er\()o(\))21
+b Fm(to)27 b(unregister)f(with)h(Driv)n(er)f(Services.)36
+b(Dep)r(ending)28 b(on)e(the)i(driv)n(er,)e(the)0 389
+y(clean)n(up)h(function)h(ma)n(y)f(also)f(need)i(to)g(free)f(an)n(y)g
+(device)g(structures)g(that)h(still)f(exist)h(at)f(sh)n(utdo)n(wn)g
+(time.)0 680 y Fe(8.2)112 b(The)38 b(*_attac)m(h\(\))f(and)h(*_detac)m
+(h\(\))f(functions)0 890 y Fm(The)h Fh(*_attach\(\))33
+b Fm(en)n(try)k(p)r(oin)n(t)h(is)g(resp)r(onsible)e(for)h(creating)g
+(an)g(\020instance\021)44 b(of)37 b(the)h(driv)n(er,)h(setting)f(up)g
+(an)n(y)f(data)0 1004 y(structures)21 b(needed)i(to)f(manage)e(one)i
+(card.)34 b(The)23 b Fh(*_attach\(\))18 b Fm(function)k(should)g(allo)r
+(cate)f(and)h(initialize)g(a)g Fh(dev_link_t)0 1118 y
+Fm(structure,)29 b(and)g(call)f Fh(RegisterClient)c Fm(to)k(establish)h
+(a)g(link)g(with)g(Card)g(Services.)40 b(It)29 b(returns)g(a)f(p)r(oin)
+n(ter)h(to)g(the)g(new)0 1231 y Fh(dev_link_t)23 b Fm(structure,)k(or)g
+Fh(NULL)f Fm(if)i(the)g(new)g(instance)f(could)g(not)h(b)r(e)g
+(created.)0 1388 y(The)e Fh(*_detach\(\))21 b Fm(en)n(try)k(p)r(oin)n
+(t)h(deletes)g(a)f(driv)n(er)g(instance)g(created)g(b)n(y)g(a)g
+(previous)g(call)g(to)h Fh(*_attach)p Fm(.)33 b(It)26
+b(also)e(breaks)0 1501 y(the)k(link)g(with)g(Card)e(Services,)h(using)g
+Fh(DeregisterClient)o Fm(.)0 1658 y(The)32 b Fh(*_attach\(\))c
+Fm(en)n(try)j(p)r(oin)n(t)h(is)g(called)g(b)n(y)f(Driv)n(er)g(Services)
+g(when)h(a)g(card)f(has)g(b)r(een)h(successfully)g(iden)n(ti\034ed)g
+(and)0 1771 y(mapp)r(ed)40 b(to)g(a)f(matc)n(hing)g(driv)n(er)f(b)n(y)i
+(a)f Fh(DS_BIND_REQUEST)34 b Fm(io)r(ctl\(\).)74 b(The)39
+b Fh(*_detach\(\))d Fm(en)n(try)j(p)r(oin)n(t)h(is)g(called)f(in)0
+1885 y(resp)r(onse)26 b(to)i(a)f Fh(DS_UNBIND_REQUES)o(T)22
+b Fm(io)r(ctl\(\))28 b(call.)0 2176 y Fe(8.3)112 b(The)38
+b(*_con\034g\(\))f(and)h(*_release\(\))f(functions)0
+2386 y Fm(The)c Fh(*_config\(\))28 b Fm(function)33 b(is)g(called)f(to)
+g(prepare)f(a)i(card)e(for)h(IO.)h(Most)f(driv)n(ers)f(read)h(some)g
+(con\034guration)e(details)0 2500 y(from)35 b(the)g(card)g(itsef,)i
+(but)f(most)f(ha)n(v)n(e)f(at)h(least)f(some)h(built-in)g(kno)n(wledge)
+f(of)h(ho)n(w)g(the)g(device)g(should)g(b)r(e)h(set)f(up.)0
+2614 y(F)-7 b(or)29 b(example,)i(the)f(serial)f(card)g(driv)n(er)g
+(reads)g(a)g(card's)g Fh(CFTABLE_ENTRY)c Fm(tuples)30
+b(to)g(determine)g(appropriate)f(IO)g(p)r(ort)0 2727
+y(base)g(addresses)e(and)i(corresp)r(onding)f(con\034guration)f
+(indices,)j(but)g(the)g(driv)n(er)e(ignores)g(the)h(in)n(terrupt)g
+(information)g(in)0 2841 y(the)34 b(CIS.)f(The)h Fh(*_config)c
+Fm(function)k(will)f(parse)g(relev)-5 b(an)n(t)32 b(parts)h(of)g(a)g
+(card's)g(CIS,)g(then)h(mak)n(e)f(calls)f(to)i Fh(RequestIO)p
+Fm(,)0 2954 y Fh(RequestIRQ)p Fm(,)23 b(and/or)j Fh(RequestWindow)p
+Fm(,)d(then)28 b(call)f Fh(RequestConfigur)o(ati)o(on)o
+Fm(.)0 3111 y(When)37 b(a)e(card)h(is)g(successfully)f(con\034gured,)i
+(the)g Fh(*_config\(\))32 b Fm(routine)k(should)g(\034ll)g(in)g(the)h
+Fh(dev_name)p Fm(,)e Fh(major)p Fm(,)h(and)0 3224 y Fh(minor)25
+b Fm(\034elds)h(in)h(the)g Fh(dev_link_t)c Fm(structure.)36
+b(These)26 b(\034elds)h(will)g(b)r(e)g(returned)f(to)h(user)f(programs)
+e(b)n(y)i(Driv)n(er)g(Services)0 3338 y(in)i(resp)r(onse)e(to)i(a)f
+Fh(DS_GET_DEVICE_IN)o(FO)21 b Fm(io)r(ctl\(\).)0 3494
+y(The)h Fh(*_release\(\))17 b Fm(function)23 b(should)e(release)g(an)n
+(y)g(resource)f(allo)r(cated)h(b)n(y)g(a)h(previous)f(call)g(to)h
+Fh(*_config\(\))p Fm(,)d(and)i(blank)0 3608 y(out)28
+b(the)g(device's)f Fh(dev_name)d Fm(\034eld.)0 3764 y(The)30
+b Fh(*_config\(\))c Fm(and)31 b Fh(*_release)26 b Fm(functions)31
+b(are)e(normally)g(called)h(in)h(resp)r(onse)e(to)h(card)f(status)h(c)n
+(hange)f(ev)n(en)n(ts)h(or)0 3878 y(from)25 b(timer)h(in)n(terrupts.)35
+b(Th)n(us,)26 b(they)g(cannot)f(sleep,)h(and)f(should)g(not)h(call)f
+(other)g(k)n(ernel)f(functions)i(that)g(migh)n(t)g(blo)r(c)n(k.)0
+4170 y Fe(8.4)112 b(The)38 b(clien)m(t)d(ev)m(en)m(t)i(handler)0
+4380 y Fm(The)28 b Fh(*_event\(\))23 b Fm(en)n(try)k(p)r(oin)n(t)h(is)g
+(called)f(from)g(Card)g(Services)f(to)i(notify)g(a)f(driv)n(er)f(of)h
+(card)g(status)g(c)n(hange)g(ev)n(en)n(ts.)0 4671 y Fe(8.5)112
+b(Lo)s(c)m(king)37 b(and)i(sync)m(hronization)d(issues)0
+4881 y Fm(A)25 b(con\034gured)e(so)r(c)n(k)n(et)g(should)h(only)g(b)r
+(e)h(released)e(when)i(all)f(asso)r(ciated)f(devices)h(are)f(closed.)35
+b(Releasing)23 b(a)h(so)r(c)n(k)n(et)g(allo)n(ws)0 4995
+y(its)i(system)f(resources)e(to)i(b)r(e)h(allo)r(cated)f(for)g(use)g(b)
+n(y)g(another)g(device.)35 b(If)26 b(the)g(released)e(resources)f(are)i
+(reallo)r(cated)f(while)0 5108 y(IO)j(to)h(the)g(original)e(device)h
+(is)g(still)h(in)g(progress,)d(the)j(original)e(driv)n(er)g(ma)n(y)h
+(in)n(terfere)g(with)h(use)g(of)f(the)h(new)g(device.)p
+eop
+%%Page: 63 63
+63 62 bop 0 -167 3900 5 v 0 -200 a Ff(9.)73 b(The)32
+b(So)s(c)m(k)m(et)h(Driv)m(er)g(La)m(y)m(er)2638 b Fm(63)0
+162 y(A)29 b(driv)n(er)e(instance)h(should)g(only)g(b)r(e)h(freed)f
+(after)g(its)h(corresp)r(onding)d(so)r(c)n(k)n(et)h(con\034guration)g
+(has)h(b)r(een)h(released.)38 b(Card)0 275 y(Services)29
+b(requires)g(that)h(a)g(clien)n(t)g(explicitly)g(release)f(an)n(y)g
+(allo)r(cated)h(resources)e(b)r(efore)h(a)h(call)g(to)g
+Fh(DeregisterClien)o(t)0 389 y Fm(will)e(succeed.)0 545
+y(All)i(loadable)f(mo)r(dules)h(ha)n(v)n(e)f(a)h(\020use)f(coun)n
+(t\021)36 b(that)30 b(is)g(used)g(b)n(y)g(the)g(system)g(to)g
+(determine)g(when)g(it)g(is)g(safe)g(to)g(unload)0 659
+y(a)h(mo)r(dule.)48 b(The)32 b(con)n(v)n(en)n(tion)d(in)j(clien)n(t)f
+(driv)n(ers)f(is)h(to)g(incremen)n(t)g(the)h(use)f(coun)n(t)g(when)h(a)
+f(device)g(is)g(op)r(ened,)h(and)f(to)0 772 y(decremen)n(t)e(the)g
+(coun)n(t)g(when)h(a)f(device)g(is)g(closed.)41 b(So,)29
+b(a)g(driv)n(er)f(can)h(b)r(e)h(unloaded)f(whenev)n(er)f(all)h(asso)r
+(ciated)f(devices)0 886 y(are)35 b(closed.)61 b(in)37
+b(particular,)f(a)g(driv)n(er)f(can)g(b)r(e)i(unloaded)e(ev)n(en)h(if)g
+(it)h(is)f(still)g(b)r(ound)g(to)g(a)g(so)r(c)n(k)n(et,)h(and)e(the)i
+(mo)r(dule)0 1000 y(clean)n(up)28 b(co)r(de)h(needs)g(to)f(b)r(e)i
+(able)e(to)h(appropriately)e(free)h(an)n(y)g(suc)n(h)h(resources)e
+(that)i(are)f(still)h(allo)r(cated.)40 b(This)28 b(should)0
+1113 y(alw)n(a)n(ys)h(b)r(e)h(safe,)h(b)r(ecause)f(if)h(the)g(driv)n
+(er)f(has)g(a)g(use)g(coun)n(t)g(of)h(zero,)f(all)g(devices)g(are)g
+(closed,)g(whic)n(h)h(means)f(all)g(activ)n(e)0 1227
+y(so)r(c)n(k)n(ets)c(can)h(b)r(e)h(released,)f(and)g(all)g(device)h
+(instances)f(can)g(b)r(e)h(detac)n(hed.)0 1383 y(If)f(a)f(driv)n(er's)e
+Fh(*_release\(\))e Fm(function)27 b(is)f(called)g(while)h(a)f(device)g
+(is)g(still)g(op)r(en,)h(it)g(should)f(set)g(the)h Fh(DEV_STALE_CONFI)o
+(G)0 1497 y Fm(\035ag)j(in)h(the)g(device)f(state,)h(to)f(signal)g
+(that)h(the)g(device)f(should)g(b)r(e)h(released)f(when)g(the)h(driv)n
+(er's)e Fh(close\(\))f Fm(function)j(is)0 1610 y(called.)36
+b(If)25 b Fh(*_detach\(\))d Fm(is)j(called)g(for)f(a)h(con\034gured)f
+(device,)i(the)f Fh(DEV_STALE_LINK)20 b Fm(\035ag)k(should)h(b)r(e)h
+(set)f(to)g(signal)g(that)0 1724 y(the)j(instance)f(should)g(b)r(e)h
+(detac)n(hed)g(when)f(the)h Fh(*_release\(\))23 b Fm(function)28
+b(is)g(called.)0 2015 y Fe(8.6)112 b(Using)37 b(existing)f(Lin)m(ux)i
+(driv)m(ers)e(to)h(access)h(PC)f(Card)h(devices)0 2226
+y Fm(Man)n(y)24 b(of)g(the)h(curren)n(t)f(clien)n(t)g(driv)n(ers)f(use)
+i(existing)f(Lin)n(ux)g(driv)n(er)f(co)r(de)h(to)h(p)r(erform)f(device)
+g(IO)g(op)r(erations.)34 b(The)25 b(Card)0 2339 y(Services)i(clien)n(t)
+i(mo)r(dule)g(handles)f(card)f(con\034guration)g(and)h(resp)r(onds)g
+(to)g(card)g(status)g(c)n(hange)f(ev)n(en)n(ts,)h(but)h(delegates)0
+2453 y(device)f(IO)h(to)f(a)h(compatible)f(driv)n(er)g(for)g(a)g(con)n
+(v)n(en)n(tional)f(ISA)i(bus)g(card.)39 b(In)29 b(some)f(cases,)g(a)g
+(con)n(v)n(en)n(tional)f(driv)n(er)g(can)0 2566 y(b)r(e)35
+b(used)g(without)g(mo)r(di\034cation.)57 b(Ho)n(w)n(ev)n(er,)35
+b(to)f(fully)h(supp)r(ort)g(PC)g(Card)f(features)g(lik)n(e)g(hot)g(sw)n
+(apping)g(and)g(p)r(o)n(w)n(er)0 2680 y(managemen)n(t,)e(there)g(needs)
+f(to)h(b)r(e)g(some)g(comm)n(unication)f(b)r(et)n(w)n(een)g(the)i(PC)f
+(Card)f(clien)n(t)h(co)r(de)g(and)g(the)g(device)f(IO)0
+2793 y(co)r(de.)0 2950 y(Most)i(Lin)n(ux)g(driv)n(ers)f(exp)r(ect)i(to)
+f(prob)r(e)g(for)f(devices)h(at)g(b)r(o)r(ot)h(time,)h(and)e(are)g(not)
+g(designed)g(to)g(handle)g(adding)g(and)0 3063 y(remo)n(ving)d
+(devices.)47 b(One)31 b(side-e\033ect)h(of)f(the)h(mo)n(v)n(e)e(to)n(w)
+n(ards)f(driv)n(er)h(mo)r(dularization)g(is)i(that)f(it)h(is)f(usually)
+g(easier)f(to)0 3177 y(adapt)d(a)g(mo)r(dularized)g(driv)n(er)f(to)i
+(handle)f(remo)n(v)-5 b(able)27 b(devices.)0 3334 y(It)k(is)f(imp)r
+(ortan)n(t)g(that)h(a)f(device)h(driv)n(er)e(b)r(e)i(able)f(to)h(reco)n
+(v)n(er)d(from)i(ha)n(ving)f(a)h(device)h(disapp)r(ear)e(at)h(an)h
+(inappropriate)0 3447 y(time.)58 b(A)n(t)35 b(b)r(est,)h(the)f(driv)n
+(er)e(should)h(c)n(hec)n(k)g(for)g(device)g(presence)f(b)r(efore)h
+(attempting)h(an)n(y)f(IO)g(op)r(eration)f(or)g(b)r(efore)0
+3561 y(handling)28 b(an)g(IO)h(in)n(terrupt.)39 b(Lo)r(ops)28
+b(that)h(c)n(hec)n(k)e(device)h(status)h(should)f(ha)n(v)n(e)f
+(timeouts)i(so)f(they)h(will)f(ev)n(en)n(tually)g(exit)0
+3674 y(if)g(a)f(device)h(nev)n(er)e(resp)r(onds.)0 3831
+y(The)d Fh(dummy_cs)d Fm(driv)n(er)i(ma)n(y)g(b)r(e)i(useful)f(for)g
+(loading)f(legacy)g(driv)n(ers)f(for)i(compatible)g(PC)g(Card)g
+(devices.)34 b(After)24 b(binding)0 3944 y Fh(dummy_cs)c
+Fm(to)j(a)g(card,)h(the)f(legacy)f(driv)n(er)g(mo)r(dule)i(ma)n(y)f(b)r
+(e)g(able)g(to)h(detect)g(and)f(comm)n(unicate)f(with)i(the)g(device)f
+(as)g(if)h(it)0 4058 y(w)n(ere)f(not)h(a)g(PC)g(Card.)35
+b(This)24 b(arrangemen)n(t)e(will)i(generally)f(not)h(supp)r(ort)g
+(clean)f(hot)h(sw)n(apping)f(or)g(p)r(o)n(w)n(er)g(managemen)n(t)0
+4171 y(functions,)28 b(ho)n(w)n(ev)n(er)d(it)j(ma)n(y)f(b)r(e)h(useful)
+g(as)f(a)g(basis)g(for)g(later)g(dev)n(eloping)f(a)h(more)g
+(full-featured)h(clien)n(t)f(driv)n(er.)0 4510 y Fg(9)131
+b(The)44 b(So)t(c)l(k)l(et)h(Driv)l(er)g(La)l(y)l(er)0
+4748 y Fm(In)26 b(the)h(Lin)n(ux)f(PCMCIA)g(mo)r(del,)h(the)f(\020So)r
+(c)n(k)n(et)g(Services\021)31 b(la)n(y)n(er)25 b(is)h(a)f(priv)-5
+b(ate)26 b(API)h(in)n(tended)f(only)g(for)f(the)i(use)f(of)g(Card)0
+4862 y(Services.)48 b(The)32 b(API)h(is)f(based)f(lo)r(osely)g(on)g
+(the)h(PCMCIA)h(So)r(c)n(k)n(et)e(Services)g(sp)r(eci\034cation,)h(but)
+g(is)g(orien)n(ted)f(to)n(w)n(ards)0 4976 y(supp)r(ort)c(for)g(the)h
+(common)f(x86)g(laptop)g(host)g(con)n(troller)f(t)n(yp)r(es.)p
+eop
+%%Page: 64 64
+64 63 bop 0 -167 3900 5 v 0 -200 a Ff(9.)73 b(The)32
+b(So)s(c)m(k)m(et)h(Driv)m(er)g(La)m(y)m(er)2638 b Fm(64)0
+162 y Fe(9.1)112 b(Card)38 b(Services)f(en)m(try)g(p)s(oin)m(ts)g(for)g
+(so)s(c)m(k)m(et)g(driv)m(ers)0 372 y Fm(Card)27 b(Services)f(pro)n
+(vides)g(sp)r(ecial)i(en)n(try)f(p)r(oin)n(ts)g(for)g(registering)f
+(and)h(unregistering)f(so)r(c)n(k)n(et)h(driv)n(ers:)208
+602 y Fd(typedef)40 b(int)g(\(*ss_entry_t\)\(u_int)k(sock,)c(u_int)g
+(cmd,)g(void)g(*arg\);)208 706 y(extern)g(int)g(register_ss_entry\(int)
+k(nsock,)c(ss_entry_t)i(entry\);)208 810 y(extern)e(void)g
+(unregister_ss_entry\(ss_entry_)q(t)45 b(entry\);)0 1050
+y Fm(The)e(so)r(c)n(k)n(et)e(driv)n(er)h(in)n(v)n(ok)n(es)f
+Fh(register_ss_ent)o(ry)36 b Fm(with)44 b Fh(nsock)c
+Fm(indicating)j(ho)n(w)f(man)n(y)g(so)r(c)n(k)n(ets)g(are)f(o)n(wned)h
+(b)n(y)0 1163 y(this)c(driv)n(er,)h(and)f Fh(entry)e
+Fm(p)r(oin)n(ting)i(to)g(the)g(function)h(that)f(will)g(pro)n(vide)f
+(so)r(c)n(k)n(et)g(services)f(for)h(these)h(so)r(c)n(k)n(ets.)67
+b(The)0 1277 y Fh(unregister_ss_en)o(tr)o(y)29 b Fm(routine)35
+b(can)f(b)r(e)i(safely)f(in)n(v)n(ok)n(ed)e(whenev)n(er)h(Card)g
+(Services)g(do)r(es)h(not)g(ha)n(v)n(e)f(an)n(y)g(callbac)n(k)0
+1390 y(functions)28 b(registered)e(for)h(so)r(c)n(k)n(ets)f(o)n(wned)h
+(b)n(y)g(this)h(driv)n(er.)0 1682 y Fe(9.2)112 b(Services)37
+b(pro)m(vided)g(b)m(y)h(the)f(so)s(c)m(k)m(et)g(driv)m(er)0
+1892 y Fm(So)r(c)n(k)n(et)27 b(Services)f(calls)h(ha)n(v)n(e)g(the)h
+(follo)n(wing)e(form:)208 2122 y Fd(#include)41 b("pcmcia/ss.h")208
+2330 y(int)e(\(*ss_entry\)\(u_int)k(sock,)e(int)f(service,)h(void)f
+(*arg\);)0 2570 y Fm(Non-zero)26 b(return)h(co)r(des)g(indicate)h(that)
+g(a)f(request)g(failed.)0 2842 y Ff(9.2.1)94 b(SS_InquireSo)s(c)m(k)m
+(et)208 3033 y Fd(int)39 b(\(*ss_entry\)\(u_int)k(sock,)e
+(SS_InquireSocket,)i(socket_cap_t)e(*cap\);)0 3273 y
+Fm(The)28 b Fh(socket_cap_t)22 b Fm(data)27 b(structure)g(is)h(giv)n
+(en)e(b)n(y:)208 3486 y Fd(typedef)40 b(struct)h(socket_cap_t)h({)521
+3590 y(u_int)433 b(features;)521 3694 y(u_int)g(irq_mask;)521
+3798 y(u_int)g(map_size;)521 3902 y(u_char)394 b(pci_irq;)521
+4007 y(u_char)g(cardbus;)521 4111 y(struct)41 b(bus_operations)h(*bus;)
+208 4215 y(})d(socket_cap_t;)0 4438 y Fm(The)d Fh(SS_InquireSocket)30
+b Fm(service)35 b(is)h(used)g(to)h(retriev)n(e)e(so)r(c)n(k)n(et)g
+(capabilities.)62 b(The)36 b Fh(irq_mask)d Fm(\034eld)k(is)f(a)g(bit)h
+(mask)0 4551 y(indicating)24 b(whic)n(h)h(in)n(terrupts)e(can)h(b)r(e)h
+(con\034gured)f(for)f(IO)i(cards.)34 b(The)25 b Fh(map_size)c
+Fm(\034eld)j(giv)n(es)g(the)h(address)e(gran)n(ularit)n(y)0
+4665 y(of)k(memory)g(windo)n(ws.)36 b(The)27 b Fh(pci_irq)e
+Fm(\034eld,)j(if)g(not)f(zero,)g(is)g(the)h(PCI)g(in)n(terrupt)f(n)n
+(um)n(b)r(er)g(assigned)f(to)h(this)h(so)r(c)n(k)n(et.)36
+b(It)0 4778 y(should)28 b(b)r(e)g(consisten)n(t)g(with)g
+Fh(irq_mask)p Fm(.)35 b(F)-7 b(or)27 b(CardBus)g(bridges,)g(the)i
+Fh(cardbus)c Fm(\034eld)j(should)g(b)r(e)g(non-zero,)e(and)i(giv)n(es)0
+4892 y(the)g(PCI)g(bus)g(n)n(um)n(b)r(er)f(of)g(the)h(CardBus)f(side)g
+(of)h(the)g(bridge.)0 5048 y(F)-7 b(or)26 b(so)r(c)n(k)n(ets)g(that)h
+(do)g(not)g(directly)g(map)f(cards)g(in)n(to)h(the)g(host)g(IO)g(and)f
+(memory)g(space,)h(the)g Fh(bus)f Fm(\034eld)h(is)g(a)g(p)r(oin)n(ter)f
+(to)0 5162 y(a)h(table)h(of)f(en)n(try)g(p)r(oin)n(ts)h(for)f(IO)g
+(primitiv)n(es)g(for)g(this)h(so)r(c)n(k)n(et.)0 5318
+y(The)g(follo)n(wing)e(\035ags)h(ma)n(y)f(b)r(e)i(sp)r(eci\034ed)g(in)g
+Fh(features)p Fm(:)p eop
+%%Page: 65 65
+65 64 bop 0 -167 3900 5 v 0 -200 a Ff(9.)73 b(The)32
+b(So)s(c)m(k)m(et)h(Driv)m(er)g(La)m(y)m(er)2638 b Fm(65)0
+162 y Fh(SS_CAP_PAGE_REGS)208 307 y Fm(Indicates)27 b(that)h(this)f(so)
+r(c)n(k)n(et)g(supp)r(orts)g(full)h(32-bit)f(addressing)f(for)h(16-bit)
+g(PC)h(Card)f(memory)f(windo)n(ws.)0 483 y Fh(SS_CAP_VIRTUAL_B)o(US)208
+628 y Fm(Indicates)f(that)i(16-bit)e(card)h(memory)f(and)h(IO)g
+(accesses)f(m)n(ust)h(b)r(e)h(p)r(erformed)e(using)h(the)h(bus)f(op)r
+(erations)f(table,)208 742 y(rather)h(than)i(using)f(nativ)n(e)g(bus)h
+(op)r(erations.)0 919 y Fh(SS_CAP_MEM_ALIGN)208 1064
+y Fm(Indicates)f(that)h(memory)e(windo)n(ws)h(m)n(ust)h(b)r(e)g
+(aligned)f(b)n(y)g(the)h(windo)n(w)f(size.)0 1240 y Fh
+(SS_CAP_STATIC_MA)o(P)208 1385 y Fm(Indicates)c(that)h(memory)f(windo)n
+(ws)h(are)e(statically)i(mapp)r(ed)g(at)g(\034xed)g(lo)r(cations)f(in)h
+(the)g(host)g(address)e(space,)i(and)208 1499 y(cannot)j(b)r(e)h(rep)r
+(ositioned.)0 1676 y Fh(SS_CAP_PCCARD)208 1821 y Fm(Indicates)f(that)h
+(this)f(so)r(c)n(k)n(et)g(supp)r(orts)g(16-bit)g(PC)h(cards.)0
+1997 y Fh(SS_CAP_CARDBUS)208 2142 y Fm(Indicates)f(that)h(this)f(so)r
+(c)n(k)n(et)g(supp)r(orts)g(32-bit)g(CardBus)f(cards.)0
+2414 y Ff(9.2.2)94 b(SS_RegisterCallbac)m(k)208 2603
+y Fd(int)39 b(\(*ss_entry\)\(u_int)k(sock,)e(SS_RegisterCallback,)i
+(ss_callback_t)f(*call\);)0 2834 y Fm(The)28 b Fh(ss_callback_t)22
+b Fm(data)27 b(structure)g(is)g(giv)n(en)g(b)n(y:)208
+3040 y Fd(typedef)40 b(struct)h(ss_callback_t)h({)521
+3145 y(void)472 b(\(*handler\)\(void)42 b(*info,)f(u_int)f(events\);)
+521 3249 y(void)472 b(*info;)208 3353 y(})39 b(ss_callback_t;)0
+3569 y Fm(The)25 b Fh(SS_RegisterCallba)o(ck)19 b Fm(service)24
+b(sets)h(up)g(a)g(callbac)n(k)f(function)i(to)f(b)r(e)h(in)n(v)n(ok)n
+(ed)d(when)j(the)g(so)r(c)n(k)n(et)e(driv)n(er)g(receiv)n(es)0
+3682 y(card)33 b(status)h(c)n(hange)e(ev)n(en)n(ts.)55
+b(T)-7 b(o)33 b(unregister)g(a)g(callbac)n(k,)i(this)f(function)g(is)g
+(called)f(with)h(a)g(handler)f(v)-5 b(alue)34 b(of)g
+Fh(NULL)p Fm(.)0 3796 y(Only)27 b(one)g(callbac)n(k)g(function)h(can)f
+(b)r(e)h(registered)e(p)r(er)h(so)r(c)n(k)n(et.)0 3952
+y(The)g(handler)f(will)h(b)r(e)g(called)g(with)g(the)g(v)-5
+b(alue)27 b(of)g Fh(info)e Fm(that)i(w)n(as)f(passed)g(to)h
+Fh(SS_RegisterCall)o(bac)o(k)21 b Fm(for)26 b(this)h(so)r(c)n(k)n(et,)0
+4066 y(and)g(with)h(a)g(bit)g(map)f(of)h(ev)n(en)n(ts)e(in)i(the)g
+Fh(events)d Fm(parameter.)36 b(The)27 b(follo)n(wing)g(ev)n(en)n(ts)g
+(are)f(de\034ned:)0 4297 y Fh(SS_DETECT)208 4442 y Fm(A)h(card)g
+(detect)h(c)n(hange)f(\(insertion)g(or)f(remo)n(v)-5
+b(al\))27 b(has)g(b)r(een)h(detected.)0 4619 y Fh(SS_READY)208
+4764 y Fm(A)f(memory)g(card's)g(ready)f(signal)h(has)g(c)n(hanged)f
+(state.)0 4940 y Fh(SS_BATDEAD)208 5085 y Fm(A)h(memory)g(card)g(has)g
+(raised)f(the)i(battery-dead)f(signal.)0 5262 y Fh(SS_BATWARN)208
+5407 y Fm(A)g(memory)g(card)g(has)g(raised)f(the)i(battery-lo)n(w)e
+(signal.)p eop
+%%Page: 66 66
+66 65 bop 0 -167 3900 5 v 0 -200 a Ff(9.)73 b(The)32
+b(So)s(c)m(k)m(et)h(Driv)m(er)g(La)m(y)m(er)2638 b Fm(66)0
+162 y Fh(SS_STSCHG)208 308 y Fm(An)28 b(IO)f(card)f(has)h(raised)g(the)
+h(status)f(c)n(hange)g(signal.)0 581 y Ff(9.2.3)94 b(SS_GetStatus)208
+772 y Fd(int)39 b(\(*ss_entry\)\(u_int)k(sock,)e(SS_GetStatus,)h(u_int)
+e(*status\);)0 1012 y Fm(The)35 b Fh(SS_GetStatus)30
+b Fm(service)k(returns)h(the)g(curren)n(t)f(status)h(of)g(this)g(so)r
+(c)n(k)n(et.)59 b(The)35 b Fh(status)d Fm(parameter)i(will)h(b)r(e)h
+(con-)0 1125 y(structed)27 b(out)h(of)g(the)g(follo)n(wing)e(\035ags:)0
+1365 y Fh(SS_WRPROT)208 1511 y Fm(The)h(card)g(is)g(write-protected.)0
+1691 y Fh(SS_BATDEAD)208 1838 y Fm(A)g(memory)g(card)g(has)g(raised)f
+(the)i(battery-dead)f(signal.)0 2018 y Fh(SS_BATWARN)208
+2165 y Fm(A)g(memory)g(card)g(has)g(raised)f(the)i(battery-lo)n(w)e
+(signal.)0 2345 y Fh(SS_READY)208 2492 y Fm(A)h(memory)g(card)g(has)g
+(raised)f(its)i(ready)f(signal.)0 2672 y Fh(SS_DETECT)208
+2818 y Fm(A)g(card)g(is)h(presen)n(t.)0 2998 y Fh(SS_POWERON)208
+3145 y Fm(P)n(o)n(w)n(er)e(has)h(b)r(een)h(applied)f(to)h(the)g(so)r(c)
+n(k)n(et.)0 3325 y Fh(SS_STSCHG)208 3472 y Fm(An)g(IO)f(card)f(has)h
+(raised)g(the)h(status)f(c)n(hange)g(signal.)0 3652 y
+Fh(SS_CARDBUS)208 3799 y Fm(The)g(so)r(c)n(k)n(et)g(con)n(tains)f(a)h
+(CardBus)g(card)f(\(as)i(opp)r(osed)f(to)g(a)g(16-bit)g(PC)h(Card\).)0
+3979 y Fh(SS_3VCARD)208 4126 y Fm(The)f(card)g(m)n(ust)h(b)r(e)f(op)r
+(erated)g(at)h(no)f(more)g(than)g(3.3V.)0 4306 y Fh(SS_XVCARD)208
+4452 y Fm(The)g(card)g(m)n(ust)h(b)r(e)f(op)r(erated)g(at)h(no)f(more)g
+(than)g(X.XV)i(\(not)f(y)n(et)f(de\034ned\).)0 4725 y
+Ff(9.2.4)94 b(SS_GetSo)s(c)m(k)m(et,)32 b(SS_SetSo)s(c)m(k)m(et)208
+4916 y Fd(int)39 b(\(*ss_entry\)\(u_int)k(sock,)e(SS_GetSocket,)h
+(socket_state_t)g(*\);)208 5020 y(int)d(\(*ss_entry\)\(u_int)k(sock,)e
+(SS_SetSocket,)h(socket_state_t)g(*\);)0 5259 y Fm(The)28
+b Fh(socket_state_t)21 b Fm(data)27 b(structure)g(is)h(giv)n(en)f(b)n
+(y:)p eop
+%%Page: 67 67
+67 66 bop 0 -167 3900 5 v 0 -200 a Ff(9.)73 b(The)32
+b(So)s(c)m(k)m(et)h(Driv)m(er)g(La)m(y)m(er)2638 b Fm(67)208
+162 y Fd(typedef)40 b(struct)h(socket_state_t)h({)521
+266 y(u_int)433 b(flags;)521 370 y(u_int)g(csc_mask;)521
+474 y(u_char)394 b(Vcc,)40 b(Vpp;)521 578 y(u_char)394
+b(io_irq;)208 682 y(})39 b(socket_state_t;)0 905 y Fm(The)23
+b Fh(csc_mask)d Fm(\034eld)j(indicates)g(whic)n(h)g(ev)n(en)n(t)f(t)n
+(yp)r(es)h(should)g(generate)f(card)g(status)h(c)n(hange)e(in)n
+(terrupts.)35 b(The)23 b(follo)n(wing)0 1019 y(ev)n(en)n(t)k(t)n(yp)r
+(es)h(can)f(b)r(e)h(monitored:)0 1258 y Fh(SS_DETECT)208
+1405 y Fm(Card)e(detect)i(c)n(hanges)e(\(insertion)i(or)e(remo)n(v)-5
+b(al\).)0 1585 y Fh(SS_READY)208 1732 y Fm(Memory)26
+b(card)h(ready/busy)f(c)n(hanges.)0 1912 y Fh(SS_BATDEAD)208
+2059 y Fm(Memory)g(card)h(battery-dead)f(c)n(hanges.)0
+2239 y Fh(SS_BATWARN)208 2385 y Fm(Memory)g(card)h(battery-lo)n(w)f(c)n
+(hanges.)0 2565 y Fh(SS_STSCHG)208 2712 y Fm(IO)h(card)f(status)i(c)n
+(hanges.)0 2952 y(The)h Fh(Vcc)e Fm(and)h Fh(Vpp)g Fm(parameters)f(are)
+g(in)i(units)g(of)g(0.1)e(v)n(olts.)40 b(If)29 b(non-zero,)e
+Fh(io_irq)f Fm(sp)r(eci\034es)i(an)h(in)n(terrupt)f(n)n(um)n(b)r(er)g
+(to)0 3065 y(b)r(e)g(assigned)e(to)i(the)g(card,)e(in)i(IO)f(mo)r(de.)
+37 b(The)28 b(follo)n(wing)e(\034elds)i(are)f(de\034ned)g(in)h
+Fh(flags)p Fm(:)0 3305 y Fh(SS_PWR_AUTO)208 3451 y Fm(Indicates)f(that)
+h(the)g(so)r(c)n(k)n(et)e(should)h(automatically)g(p)r(o)n(w)n(er)f(up)
+i(so)r(c)n(k)n(ets)e(at)i(card)e(insertion)h(time,)h(if)g(supp)r
+(orted.)0 3631 y Fh(SS_IOCARD)208 3778 y Fm(Indicates)34
+b(that)i(the)f(so)r(c)n(k)n(et)f(should)h(b)r(e)h(con\034gured)e(for)g
+(\020memory)g(and)h(IO\021)42 b(in)n(terface)34 b(mo)r(de,)j(as)e(opp)r
+(osed)f(to)208 3892 y(simple)27 b(memory)g(card)g(mo)r(de.)0
+4072 y Fh(SS_RESET)208 4219 y Fm(Indicates)g(that)h(the)g(card's)e
+(hardw)n(are)f(reset)i(signal)g(should)g(b)r(e)h(raised.)0
+4399 y Fh(SS_SPKR_ENA)208 4545 y Fm(Indicates)f(that)h(sp)r(eak)n(er)e
+(output)i(should)f(b)r(e)h(enabled)f(for)g(this)h(so)r(c)n(k)n(et.)0
+4725 y Fh(SS_OUTPUT_ENA)208 4872 y Fm(Indicates)f(that)h(data)f
+(signals)f(to)h(the)h(card)f(should)g(b)r(e)h(activ)-5
+b(ated.)p eop
+%%Page: 68 68
+68 67 bop 0 -167 3900 5 v 0 -200 a Ff(9.)73 b(The)32
+b(So)s(c)m(k)m(et)h(Driv)m(er)g(La)m(y)m(er)2638 b Fm(68)0
+162 y Ff(9.2.5)94 b(SS_GetIOMap,)31 b(SS_SetIOMap)208
+353 y Fd(int)39 b(\(*ss_entry\)\(u_int)k(sock,)e(SS_GetIOMap,)h
+(pccard_io_map)g(*\);)208 457 y(int)d(\(*ss_entry\)\(u_int)k(sock,)e
+(SS_SetIOMap,)h(pccard_io_map)g(*\);)0 696 y Fm(The)28
+b Fh(pccard_io_map)22 b Fm(data)27 b(structure)g(is)g(giv)n(en)g(b)n
+(y:)208 910 y Fd(typedef)40 b(struct)h(pccard_io_map)h({)521
+1014 y(u_char)394 b(map;)521 1118 y(u_char)g(flags;)521
+1222 y(u_short)355 b(speed;)521 1326 y(u_short)g(start,)40
+b(stop;)208 1430 y(})f(pccard_io_map;)0 1653 y Fm(The)20
+b Fh(SS_GetIOMap)15 b Fm(and)20 b Fh(SS_SetIOMap)c Fm(en)n(tries)j(are)
+g(used)h(to)g(con\034gure)f(IO)g(space)g(windo)n(ws.)34
+b(IO)20 b(windo)n(ws)f(are)g(assumed)0 1767 y(to)25 b(not)f(supp)r(ort)
+h(address)e(translation.)35 b(The)25 b(Lin)n(ux)f(Card)g(Services)g(la)
+n(y)n(er)f(assumes)h(that)h(eac)n(h)f(so)r(c)n(k)n(et)g(has)g(at)h
+(least)f(t)n(w)n(o)0 1880 y(indep)r(enden)n(tly)k(con\034gurable)e(IO)h
+(p)r(ort)h(windo)n(ws.)0 2037 y(The)40 b Fh(map)e Fm(\034eld)i(sp)r
+(eci\034es)f(whic)n(h)g(IO)h(map)f(should)g(b)r(e)h(accessed.)71
+b(The)40 b Fh(speed)d Fm(\034eld)j(is)g(the)g(map)f(access)f(sp)r(eed)i
+(in)0 2150 y(nanoseconds.)50 b(The)33 b Fh(start)e Fm(and)h
+Fh(stop)f Fm(\034elds)i(giv)n(e)f(the)h(lo)n(w)n(er)e(and)h(upp)r(er)h
+(addresses)e(for)h(the)h(IO)f(map.)52 b(The)33 b Fh(flags)0
+2264 y Fm(\034eld)28 b(is)f(comp)r(osed)g(of)h(the)g(follo)n(wing:)0
+2503 y Fh(MAP_ACTIVE)208 2650 y Fm(Sp)r(eci\034es)f(that)h(the)g
+(address)e(map)i(should)f(b)r(e)h(enabled.)0 2830 y Fh(MAP_16BIT)208
+2977 y Fm(Sp)r(eci\034es)f(that)h(the)g(map)g(should)f(b)r(e)h
+(con\034gured)e(for)h(16-bit)g(accesses)f(\(as)h(opp)r(osed)g(to)h
+(8-bit\).)0 3157 y Fh(MAP_AUTOSZ)208 3304 y Fm(Sp)r(eci\034es)e(that)h
+(the)f(map)g(should)g(b)r(e)h(con\034gured)e(to)h(auto-size)f(bus)h
+(accesses)f(in)i(resp)r(onse)e(to)h(the)g(card's)g Fh(IOCS16)208
+3417 y Fm(signal.)0 3597 y Fh(MAP_0WS)208 3744 y Fm(Requests)h(zero)f
+(w)n(ait)h(states,)h(as)e(opp)r(osed)h(to)h(standard)e(ISA)i(bus)g
+(timing.)0 3924 y Fh(MAP_WRPROT)208 4071 y Fm(Sp)r(eci\034es)f(that)h
+(the)g(map)g(should)f(b)r(e)h(write)f(protected.)0 4251
+y Fh(MAP_USE_WAIT)208 4398 y Fm(Sp)r(eci\034es)g(that)h(access)e
+(timing)i(should)g(resp)r(ect)f(the)h(card's)e Fh(WAIT)g
+Fm(signal.)0 4578 y Fh(MAP_PREFETCH)208 4724 y Fm(Sp)r(eci\034es)h
+(that)h(this)g(map)f(ma)n(y)g(b)r(e)h(con\034gured)f(for)g(prefetc)n
+(hing.)0 4997 y Ff(9.2.6)94 b(SS_GetMemMap,)29 b(SS_SetMemMap)208
+5188 y Fd(int)39 b(\(*ss_entry\)\(u_int)k(sock,)e(SS_GetMemMap,)h
+(pccard_mem_map)g(*\);)208 5292 y(int)d(\(*ss_entry\)\(u_int)k(sock,)e
+(SS_SetMemMap,)h(pccard_mem_map)g(*\);)p eop
+%%Page: 69 69
+69 68 bop 0 -167 3900 5 v 0 -200 a Ff(9.)73 b(The)32
+b(So)s(c)m(k)m(et)h(Driv)m(er)g(La)m(y)m(er)2638 b Fm(69)0
+162 y(The)28 b Fh(pccard_mem_map)21 b Fm(data)27 b(structure)g(is)h
+(giv)n(en)f(b)n(y:)208 370 y Fd(typedef)40 b(struct)h(pccard_mem_map)h
+({)521 474 y(u_char)394 b(map;)521 578 y(u_char)g(flags;)521
+682 y(u_short)355 b(speed;)521 787 y(u_long)394 b(sys_start,)41
+b(sys_stop;)521 891 y(u_int)433 b(card_start;)208 995
+y(})39 b(pccard_mem_map;)0 1213 y Fm(The)c Fh(map)f Fm(\034eld)i(sp)r
+(eci\034es)f(the)g(map)h(n)n(um)n(b)r(er.)59 b(The)35
+b Fh(speed)f Fm(\034eld)h(sp)r(eci\034es)g(an)g(access)f(sp)r(eed)h(in)
+h(nanoseconds.)58 b(The)0 1326 y Fh(sys_start)22 b Fm(and)k
+Fh(sys_stop)c Fm(\034elds)k(giv)n(e)f(the)i(starting)e(and)g(ending)h
+(addresses)e(for)i(the)g(windo)n(w)f(in)h(the)h(host's)e(ph)n(ysical)0
+1440 y(address)31 b(space.)51 b(The)32 b Fh(card_start)d
+Fm(v)-5 b(alue)32 b(sp)r(eci\034es)g(the)h(card)f(address)f(to)h(b)r(e)
+h(mapp)r(ed)g(to)f Fh(sys_start)p Fm(.)48 b(The)32 b(Lin)n(ux)0
+1553 y(Card)24 b(Services)h(la)n(y)n(er)e(assumes)i(that)g(eac)n(h)g
+(so)r(c)n(k)n(et)f(has)h(at)g(least)g(four)g(indep)r(enden)n(tly)h
+(con\034gurable)d(memory)i(windo)n(ws.)0 1787 y Fh(MAP_ACTIVE)208
+1932 y Fm(Sp)r(eci\034es)i(that)h(the)g(address)e(map)i(should)f(b)r(e)
+h(enabled.)0 2110 y Fh(MAP_16BIT)208 2255 y Fm(Sp)r(eci\034es)f(that)h
+(the)g(map)g(should)f(b)r(e)h(con\034gured)e(for)h(16-bit)g(accesses)f
+(\(as)h(opp)r(osed)g(to)h(8-bit\).)0 2433 y Fh(MAP_AUTOSZ)208
+2578 y Fm(Sp)r(eci\034es)e(that)h(the)f(map)g(should)g(b)r(e)h
+(con\034gured)e(to)h(auto-size)f(bus)h(accesses)f(in)i(resp)r(onse)e
+(to)h(the)g(card's)g Fh(IOCS16)208 2692 y Fm(signal.)0
+2869 y Fh(MAP_0WS)208 3015 y Fm(Requests)h(zero)f(w)n(ait)h(states,)h
+(as)e(opp)r(osed)h(to)h(standard)e(ISA)i(bus)g(timing.)0
+3192 y Fh(MAP_WRPROT)208 3338 y Fm(Sp)r(eci\034es)f(that)h(the)g(map)g
+(should)f(b)r(e)h(write)f(protected.)0 3515 y Fh(MAP_ATTRIB)208
+3661 y Fm(Sp)r(eci\034es)g(that)h(the)g(map)g(should)f(b)r(e)h(for)f
+(attribute)h(\(as)f(opp)r(osed)g(to)g(common\))g(memory)-7
+b(.)0 3838 y Fh(MAP_USE_WAIT)208 3984 y Fm(Sp)r(eci\034es)27
+b(that)h(access)e(timing)i(should)g(resp)r(ect)f(the)h(card's)e
+Fh(WAIT)g Fm(signal.)0 4255 y Ff(9.2.7)94 b(SS_GetBridge,)30
+b(SS_SetBridge)208 4445 y Fd(int)39 b(\(*ss_entry\)\(u_int)k(sock,)e
+(SS_GetBridge,)h(cb_bridge_map)g(*\);)208 4549 y(int)d
+(\(*ss_entry\)\(u_int)k(sock,)e(SS_SetBridge,)h(cb_bridge_map)g(*\);)0
+4782 y Fm(The)28 b Fh(cb_bridge_map)22 b Fm(data)27 b(structure)g(is)g
+(giv)n(en)g(b)n(y:)208 4991 y Fd(typedef)40 b(struct)h(cb_bridge_map)h
+({)521 5095 y(u_char)394 b(map;)521 5199 y(u_char)g(flags;)521
+5303 y(u_int)433 b(start,)40 b(stop;)208 5407 y(})f(cb_bridge_map;)p
+eop
+%%Page: 70 70
+70 69 bop 0 -167 3900 5 v 0 -200 a Ff(9.)73 b(The)32
+b(So)s(c)m(k)m(et)h(Driv)m(er)g(La)m(y)m(er)2638 b Fm(70)0
+162 y(The)38 b Fh(SS_GetBridge)32 b Fm(and)38 b Fh(SS_SetBridge)33
+b Fm(en)n(try)k(p)r(oin)n(ts)g(are)g(used)h(for)f(con\034guring)f
+(bridge)h(address)g(windo)n(ws)g(for)0 275 y(CardBus)d(devices.)59
+b(They)35 b(are)f(similar)g(to)h(the)h(16-bit)e(IO)h(and)g(memory)f
+(map)h(services.)58 b(It)36 b(is)f(assumed)g(that)g(eac)n(h)0
+389 y(CardBus)26 b(so)r(c)n(k)n(et)h(has)g(at)g(least)g(t)n(w)n(o)g(IO)
+g(and)h(t)n(w)n(o)f(memory)f(bridge)h(windo)n(ws.)36
+b(The)28 b Fh(flags)d Fm(\034eld)j(is)g(comp)r(osed)f(of:)0
+627 y Fh(MAP_ACTIVE)208 773 y Fm(Sp)r(eci\034es)g(that)h(the)g(address)
+e(map)i(should)f(b)r(e)h(enabled.)0 953 y Fh(MAP_PREFETCH)208
+1099 y Fm(Sp)r(eci\034es)f(that)h(this)g(map)f(can)h(b)r(e)g
+(con\034gured)e(for)h(prefetc)n(hing.)0 1279 y Fh(MAP_IOSPACE)208
+1425 y Fm(Sp)r(eci\034es)g(that)h(this)g(map)f(should)h(b)r(e)g(for)f
+(IO)g(space)g(\(as)g(opp)r(osed)g(to)g(memory)g(space\).)0
+1697 y Ff(9.2.8)94 b(SS_Pro)s(cSetup)208 1888 y Fd(int)39
+b(\(*ss_entry\)\(u_int)k(sock,)e(SS_ProcSetup,)h(struct)e
+(proc_dir_entry)j(*base\);)0 2126 y Fm(Card)30 b(Services)g(uses)g
+(this)h(en)n(try)f(p)r(oin)n(t)h(to)f(giv)n(e)g(the)h(so)r(c)n(k)n(et)f
+(driv)n(er)f(a)h(pro)r(cfs)h(directory)e(handle)i(under)f(whic)n(h)h
+(it)g(ma)n(y)0 2239 y(create)24 b(status)h(\034les)g(for)f(a)h(sp)r
+(eci\034c)g(so)r(c)n(k)n(et.)35 b(It)25 b(is)g(the)g(so)r(c)n(k)n(et)f
+(driv)n(er's)g(resp)r(onsbilit)n(y)g(to)g(delete)i(an)n(y)e(pro)r(c)g
+(en)n(tries)g(b)r(efore)0 2353 y(it)k(is)f(unloaded.)0
+2644 y Fe(9.3)112 b(Supp)s(orting)37 b(un)m(usual)i(so)s(c)m(k)m(et)e
+(arc)m(hitectures)0 2854 y Fm(The)28 b(So)r(c)n(k)n(et)f(Services)g(in)
+n(terface)h(is)g(orien)n(ted)f(to)n(w)n(ards)f(so)r(c)n(k)n(et)h(con)n
+(trollers)f(that)i(allo)n(w)f(PCMCIA)i(cards)e(to)h(b)r(e)g(con\034g-)0
+2968 y(ured)g(to)g(mimic)g(nativ)n(e)g(system)g(devices)g(with)g(the)h
+(same)e(functionalit)n(y)-7 b(.)39 b(The)28 b(ExCA)h(standard)e(sp)r
+(eci\034es)h(that)g(so)r(c)n(k)n(et)0 3082 y(con)n(trollers)d(should)i
+(pro)n(vide)e(t)n(w)n(o)h(IO)h(and)g(\034v)n(e)f(memory)h(windo)n(ws)f
+(p)r(er)h(so)r(c)n(k)n(et,)f(whic)n(h)h(can)f(b)r(e)i(indep)r(enden)n
+(tly)f(con\034g-)0 3195 y(ured)21 b(and)h(p)r(ositioned)f(in)h(the)g
+(host)f(address)g(space)g(and)g(mapp)r(ed)h(to)f(arbitrary)f(segmen)n
+(ts)h(of)g(card)g(address)f(space.)34 b(Some)0 3309 y(con)n(trollers)29
+b(and)i(arc)n(hitectures)e(do)i(not)g(pro)n(vide)f(this)h(lev)n(el)g
+(of)g(functionalit)n(y)-7 b(.)47 b(In)31 b(these)g(situations,)h(So)r
+(c)n(k)n(et)e(Services)0 3422 y(can)d(e\033ectiv)n(ely)h(virtualize)e
+(the)i(so)r(c)n(k)n(et)f(in)n(terface)g(for)g(clien)n(t)g(driv)n(ers.)0
+3579 y(On)g(the)h(clien)n(t)f(side)g(\(including)h(in)n(ternal)e(Card)h
+(Services)f(uses\),)h(to)g(use)g(the)h(virtualized)e(so)r(c)n(k)n(et)g
+(in)n(terface,)h(co)r(de)g(m)n(ust)0 3692 y(\034rst)g(sp)r(ecify:)208
+3921 y Fd(#include)41 b("pcmcia/bus_ops.h")0 4159 y Fm(All)28
+b(IO)e(op)r(erations)g(then)i(need)f(to)g(b)r(e)h(replaced)e(with)i
+(new)f(bus-neutral)f(forms.)37 b(The)27 b(follo)n(wing)f(functions)h
+(need)h(to)f(b)r(e)0 4272 y(virtualized:)125 4510 y Fb(\017)41
+b Fh(inb)p Fm(,)26 b Fh(inw)p Fm(,)g Fh(inl)p Fm(,)h
+Fh(inw_ns)p Fm(,)e Fh(inl_ns)125 4690 y Fb(\017)41 b
+Fh(insb)p Fm(,)26 b Fh(insw)p Fm(,)g Fh(insl)p Fm(,)g
+Fh(insw_ns)p Fm(,)e Fh(insl_ns)125 4869 y Fb(\017)41
+b Fh(outb)p Fm(,)26 b Fh(outw)p Fm(,)g Fh(outl)p Fm(,)g
+Fh(outw_ns)p Fm(,)e Fh(outl_ns)125 5048 y Fb(\017)41
+b Fh(outsb)p Fm(,)25 b Fh(outsw)p Fm(,)h Fh(outsl)p Fm(,)f
+Fh(outsw_ns)p Fm(,)g Fh(outsl_ns)125 5228 y Fb(\017)41
+b Fh(readb)p Fm(,)25 b Fh(readw)p Fm(,)h Fh(readl)p Fm(,)f
+Fh(readw_ns)p Fm(,)g Fh(readl_ns)125 5407 y Fb(\017)41
+b Fh(writeb)p Fm(,)25 b Fh(writew)p Fm(,)g Fh(writel)p
+Fm(,)g Fh(writew_ns)p Fm(,)f Fh(writel_ns)p eop
+%%Page: 71 71
+71 70 bop 0 -167 3900 5 v 0 -200 a Ff(10.)73 b(Where)32
+b(to)f(Go)h(for)g(More)f(Information)2141 b Fm(71)125
+162 y Fb(\017)41 b Fh(ioremap)p Fm(,)24 b Fh(iounmap)125
+342 y Fb(\017)41 b Fh(memcpy_fromio)p Fm(,)22 b Fh(memcpy_toio)125
+522 y Fb(\017)41 b Fh(request_irq)p Fm(,)23 b Fh(free_irq)0
+761 y Fm(The)e(bus-neutral)g(functions)h(ha)n(v)n(e)e(a)h(pre\034x)g
+(of)g(\020)7 b Fh(bus_)p Fm(\021,)20 b(with)i(a)f(new)g(\034rst)h
+(argumen)n(t,)f(the)h(bus)f(op)r(erations)f(table)i(p)r(oin)n(ter)0
+875 y(returned)27 b(b)n(y)g Fh(SS_InquireSocket)p Fm(.)k(F)-7
+b(or)26 b(example,)i Fh(inb\(port\))23 b Fm(should)28
+b(b)r(e)g(replaced)e(with)i Fh(bus_inb\(bus,)39 b(port\))p
+Fm(.)0 1031 y(All)29 b(the)g(IO)g(primitiv)n(es)f(are)g(de\034ned)h(as)
+f(macros)f(that)i(call)f(en)n(try)g(p)r(oin)n(ts)h(in)g(the)g(bus)g(op)
+r(erations)e(table.)40 b(There)28 b(is)h(not)0 1145 y(a)e(one-to-one)f
+(mapping)h(from)g(IO)h(primitiv)n(es)f(to)g(bus)h(op)r(eration)e(en)n
+(try)h(p)r(oin)n(ts.)0 1301 y(The)h(bus)f(op)r(erations)f(table)i(is)f
+(de\034ned)h(as:)208 1531 y Fd(typedef)40 b(struct)h(bus_operations)h
+({)521 1635 y(void)158 b(*priv;)521 1739 y(u32)197 b(\(*b_in\)\(void)42
+b(*bus,)e(u32)g(port,)g(s32)g(sz\);)521 1844 y(void)158
+b(\(*b_ins\)\(void)42 b(*bus,)e(u32)g(port,)h(void)f(*buf,)1188
+1948 y(u32)g(count,)g(s32)g(sz\);)521 2052 y(void)158
+b(\(*b_out\)\(void)42 b(*bus,)e(u32)g(val,)g(u32)g(port,)h(s32)e(sz\);)
+521 2156 y(void)158 b(\(*b_outs\)\(void)42 b(*bus,)f(u32)f(port,)g
+(void)g(*buf,)1227 2260 y(u32)g(count,)h(s32)f(sz\);)521
+2364 y(void)158 b(*\(*b_ioremap\)\(void)43 b(*bus,)e(u_long)f(ofs,)g
+(u_long)h(sz\);)521 2468 y(void)158 b(\(*b_iounmap\)\(void)43
+b(*bus,)d(void)g(*addr\);)521 2572 y(u32)197 b(\(*b_read\)\(void)42
+b(*bus,)f(void)f(*addr,)g(s32)g(sz\);)521 2676 y(void)158
+b(\(*b_write\)\(void)43 b(*bus,)d(u32)g(val,)g(void)g(*addr,)g(s32)g
+(sz\);)521 2781 y(void)158 b(\(*b_copy_from\)\(void)43
+b(*bus,)e(void)f(*d,)g(void)g(*s,)g(u32)g(count\);)521
+2885 y(void)158 b(\(*b_copy_to\)\(void)43 b(*bus,)d(void)g(*d,)g(void)g
+(*s,)g(u32)g(count\);)521 2989 y(int)197 b(\(*b_request_irq\)\(void)44
+b(*bus,)c(u_int)g(irq,)1502 3093 y(void)g(\(*handler\)\(int,)i(void)e
+(*,)2129 3197 y(struct)h(pt_regs)g(*\),)1502 3301 y(u_long)f(flags,)h
+(const)f(char)g(*device,)1502 3405 y(void)g(*dev_id\);)521
+3509 y(void)158 b(\(*b_free_irq\)\(void)43 b(*bus,)e(u_int)f(irq,)g
+(void)g(*dev_id\);)208 3613 y(})f(bus_operations;)0 3853
+y Fm(The)31 b Fh(priv)e Fm(\034eld)i(can)f(b)r(e)h(used)g(for)f(an)n(y)
+g(purp)r(ose)g(b)n(y)g(the)h(so)r(c)n(k)n(et)f(driv)n(er,)g(for)g
+(instance,)h(to)g(indicate)g(whic)n(h)f(of)h(sev)n(eral)0
+3967 y(so)r(c)n(k)n(ets)f(is)g(b)r(eing)h(addressed.)46
+b(The)31 b Fh(b_in)p Fm(,)f Fh(b_out)p Fm(,)g Fh(b_read)p
+Fm(,)f(and)i Fh(b_write)d Fm(en)n(try)i(p)r(oin)n(ts)h(eac)n(h)f(supp)r
+(ort)h(b)n(yte,)g(w)n(ord,)0 4080 y(and)26 b(dw)n(ord)g(op)r(erations,)
+f(either)h(b)n(yte-sw)n(app)r(ed)g(or)f(unsw)n(app)r(ed.)36
+b(The)27 b Fh(sz)f Fm(parameter)e(is)j(0,)f(1,)g(or)g(2)g(for)g(b)n
+(yte,)g(w)n(ord,)g(or)0 4194 y(dw)n(ord)h(accesses;)f(-1)g(and)i(-2)f
+(select)g(w)n(ord)f(and)i(dw)n(ord)e(unsw)n(app)r(ed)i(accesses.)0
+4532 y Fg(10)131 b(Where)44 b(to)f(Go)h(for)g(More)g(Information)0
+4771 y Fm(The)36 b Fa(Linux)h(Kernel)h(Hackers')g(Guide)6
+b Fm(,)40 b(written)c(b)n(y)g(Mic)n(hael)f(Johnson,)i(is)f(a)g(go)r(o)r
+(d)f(source)g(of)h(general)f(information)0 4884 y(ab)r(out)27
+b(writing)g(Lin)n(ux)g(device)h(driv)n(ers.)35 b(It)28
+b(is)f(a)n(v)-5 b(ailable)26 b(from)h(the)h(usual)f(Lin)n(ux)g(FTP)h
+(sites,)g(and)f(is)g(included)h(in)g(man)n(y)0 4998 y(compilations)f
+(of)g(Lin)n(ux)g(do)r(cumen)n(tation.)0 5154 y(The)e(PC)h(Card)e
+(standard)g(is)h(only)f(a)n(v)-5 b(ailable)24 b(from)h(the)g(PCMCIA)h
+(asso)r(ciation)d(itself,)j(and)f(is)g(somewhat)f(exp)r(ensiv)n(e)h
+(for)0 5268 y(non-mem)n(b)r(ers.)36 b(The)27 b(PCMCIA)i(asso)r(ciation)
+d(is)h(at)55 b Fh(<http://www.pc-)t(ca)o(rd)o(.c)o(om>)o
+Fm(,)22 b(or:)p eop
+%%Page: 72 72
+72 71 bop 0 -167 3900 5 v 0 -200 a Ff(10.)73 b(Where)32
+b(to)f(Go)h(for)g(More)f(Information)2141 b Fm(72)208
+162 y Fd(Personal)41 b(Computer)f(Memory)h(Card)f(International)i
+(Association)208 266 y(1030)e(East)g(Duane)g(Avenue,)h(Suite)f(G)208
+370 y(Sunnyvale,)h(CA)f(94086)g(USA)208 474 y(\(408\))g(720-0107,)h
+(\(408\))f(720-9416)h(FAX,)f(\(408\))h(720-9388)g(BBS)0
+714 y Fm(An)36 b(alternativ)n(e)e(is)h(the)h Fa(PCMCIA)i(Develop)l
+(er's)g(Guide)6 b Fm(,)38 b(b)n(y)d(Mic)n(hael)g(Mori,)i(ISBN)e
+(0-9640342-1-2,)d(a)n(v)-5 b(ailable)33 b(from)0 827
+y(Sycard)27 b(T)-7 b(ec)n(hnology)g(,)25 b(at)56 b Fh(<http://www.syc)o
+(ar)o(d.c)o(om)o(>)22 b Fm(or:)208 1057 y Fd(Sycard)40
+b(Technology)208 1161 y(1180-F)g(Miraloma)h(Way)208 1265
+y(Sunnyvale,)g(CA)f(94086)g(USA)208 1369 y(\(408\))g(749-0130,)h
+(\(408\))f(749-1323)h(FAX)0 1609 y Fm(The)34 b Fa(PCMCIA)j(Softwar)l(e)
+f(Develop)l(er's)i(Handb)l(o)l(ok)44 b Fm(b)n(y)34 b(Stev)n(en)g
+(Kipisz,)h(Dana)f(Beatt)n(y)-7 b(,)35 b(and)f(Brian)f(Mo)r(ore)g
+(includes)0 1723 y(an)d(o)n(v)n(erview)f(of)i(the)g(PC)g(Card)f
+(standard,)h(and)f(descriptions)g(of)h(ho)n(w)f(to)h(write)f(clien)n(t)
+h(driv)n(ers.)45 b(It)31 b(also)f(includes)h(the)0 1836
+y(Lin)n(ux)k(PCMCIA)h(Programmer's)c(Guide,)38 b(as)c(an)h(app)r
+(endix.)59 b(It)36 b(is)f(published)g(b)n(y)g(P)n(eer-to-P)n(eer)e
+(Comm)n(unications,)0 1950 y(ISBN)28 b(1-57398-010-2.)0
+2106 y(Larry)39 b(Levine)i(has)g(written)g(a)g(more)f(general)g(in)n
+(tro)r(duction)h(to)g(PCMCIA)h(called)e(the)i Fa(PCMCIA)h(Primer)9
+b Fm(.)79 b(It)41 b(is)0 2220 y(published)28 b(b)n(y)f(M)h(&)f(T)h(Bo)r
+(oks,)e(ISBN)i(1-55828-437-0.)0 2376 y(Programming)36
+b(information)h(for)g(v)-5 b(arious)37 b(PC)h(Card)f(host)g(con)n
+(trollers)f(is)h(a)n(v)-5 b(ailable)37 b(from)g(the)h(corresp)r(onding)
+e(c)n(hip)0 2490 y(v)n(endors.)f(Generally)-7 b(,)25
+b(data)h(sheets)g(are)f(either)h(a)n(v)-5 b(ailable)24
+b(on)i(line)g(or)g(can)f(b)r(e)i(ordered)d(from)i(eac)n(h)f(compan)n
+(y's)g(w)n(eb)h(site.)0 2603 y(A)i(collection)f(of)g(datasheets)g(can)g
+(b)r(e)h(found)g(at)55 b Fh(<http:/pcmcia.so)o(urc)o(ef)o(or)o(ge.)o
+(or)o(g/)o(spe)o(cs)o(>)p Fm(.)p eop
+%%Trailer
+end
+userdict /end-hook known{end-hook}if
+%%EOF
Index: oldkernel/linux/pcmcia-cs-3.1.15/etc/Makefile
diff -u /dev/null linux/pcmcia-cs-3.1.15/etc/Makefile:1.1
--- /dev/null	Mon Jul 31 21:15:11 2000
+++ linux/pcmcia-cs-3.1.15/etc/Makefile	Fri Jul  7 16:34:58 2000
@@ -0,0 +1,18 @@
+#
+# etc/Makefile 1.56 2000/04/27 02:07:17 (David Hinds)
+#
+
+# Include site dependent options
+include ../config.mk
+
+all:
+ifeq ($(HOST_ARCH),$(ARCH))
+	@set -e ; $(MAKE) -C cis
+endif
+
+dep:
+clean:
+
+install:
+	@set -e ; $(MAKE) -C cis install
+	@./install-etc
Index: oldkernel/linux/pcmcia-cs-3.1.15/etc/config
diff -u /dev/null linux/pcmcia-cs-3.1.15/etc/config:1.1
--- /dev/null	Mon Jul 31 21:15:11 2000
+++ linux/pcmcia-cs-3.1.15/etc/config	Fri Jul  7 16:34:58 2000
@@ -0,0 +1,1628 @@
+#
+# PCMCIA Card Configuration Database
+#
+# config 1.119 2000/05/15 19:28:14 (David Hinds)
+#
+
+# config.opts is now included at the very end
+
+#
+# Device driver definitions
+#
+device "3c589_cs"
+  class "network" module "3c589_cs"
+
+device "ibmtr_cs"
+  class "network" module "ibmtr_cs"
+
+device "nmclan_cs"
+  class "network" module "nmclan_cs"
+
+device "oti12_cs"
+  class "cdrom" module "oti12_cs"
+
+device "pcnet_cs"
+  class "network" module "net/8390", "pcnet_cs"
+
+device "smc91c92_cs"
+  class "network" module "smc91c92_cs"
+
+device "wavelan_cs"
+  class "network" module "wavelan_cs"
+
+device "wvlan_cs"
+  class "network" module "wvlan_cs"
+
+device "memory_cs" needs_mtd
+  class "memory" module "memory_cs"
+
+device "ftl_cs" needs_mtd
+  class "ftl" module "ftl_cs"
+
+device "serial_cs"
+  class "serial" module "serial_cs"
+
+device "parport_cs"
+  class "parport" module "parport_cs"
+
+device "qlogic_cs"
+  class "scsi" module "qlogic_cs"
+
+device "aha152x_cs"
+  class "scsi" module "aha152x_cs"
+
+device "fdomain_cs"
+  class "scsi" module "fdomain_cs"
+
+device "sym53c500_cs"
+  class "scsi" module "sym53c500_cs"
+
+device "ide_cs"
+  class "ide" module "ide_cs"
+
+device "fmvj18x_cs"
+  class "network" module "fmvj18x_cs" 
+
+device "netwave_cs"
+  class "network" module "netwave_cs"
+
+device "xirc2ps_cs"
+  class "network" module "xirc2ps_cs"
+
+device "iscc_cs"
+  class "iscc" module "iscc_cs"
+
+device "3c574_cs"
+  class "network" module "3c574_cs"
+
+device "teles_cs"
+  class "teles" module "teles_cs"
+
+device "3c575_cb"
+  class "network" module "cb_enabler", "3c575_cb"
+
+device "apa1480_cb"
+  class "scsi" module "cb_enabler", "apa1480_cb"
+
+device "tulip_cb"
+  class "network" module "cb_enabler", "tulip_cb"
+
+device "memory_cb"
+  class "memory" module "cb_enabler", "memory_cb"
+
+device "epic_cb"
+  class "network" module "cb_enabler", "epic_cb"
+
+device "serial_cb"
+  class "serial" module "cb_enabler", "serial_cb"
+
+device "ray_cs"
+  class "network" module "ray_cs"
+
+device "airo_cs"
+  class "network" module "airo", "airo_cs"
+#
+# Ethernet adapter definitions
+#
+card "2412LAN Ethernet"
+  version "2412LAN"
+  bind "pcnet_cs"
+
+card "3Com 589 Ethernet"
+  manfid 0x0101, 0x0589
+  bind "3c589_cs"
+
+card "Accton EN2212 Ethernet"
+  version "ACCTON", "EN2212"
+  bind "pcnet_cs"
+
+card "Accton EN2216 Ethernet"
+  version "ACCTON", "EN2216-PCMCIA-ETHERNET"
+  bind "pcnet_cs"
+
+card "Accton UE2212 Ethernet"
+  version "PCMCIA", "UE2212"
+  bind "pcnet_cs"
+
+card "Accton UE2216 Ethernet"
+  version "PCMCIA", "PCMCIA-ETHERNET-CARD", "UE2216"
+  bind "pcnet_cs"
+
+card "Allied Telesis LA-PCM Ethernet"
+  manfid 0xc00f, 0x0002
+  cis "cis/LA-PCM.dat"
+  bind "pcnet_cs"
+
+card "AmbiCom AMB8002 Ethernet"
+  version "AmbiCom Inc", "AMB8002"
+  bind "pcnet_cs"
+
+card "AmbiCom AMB8002T Ethernet"
+  version "AmbiCom Inc", "AMB8002T"
+  bind "pcnet_cs"
+
+card "AmbiCom AMB8010 Ethernet"
+  version "AmbiCom Inc", "AMB8010"
+  bind "pcnet_cs"
+
+card "AnyCom ECO Ethernet"
+  version "AnyCom", "ECO Ethernet"
+  bind "pcnet_cs"
+
+card "Argosy EN210 Ethernet"
+  version "PCMCIA LAN", "Ethernet"
+  bind "pcnet_cs"
+
+card "Asante FriendlyNet Ethernet"
+  version "ASANTE", "FriendlyNet PC Card"
+  bind "pcnet_cs"
+
+card "Billionton LNT-10TB"
+  version "Billionton", "LNT-10TB"
+  bind "pcnet_cs"
+
+card "Billionton LNT-10TN"
+  version "PCMCIA", "LNT-10TN"
+  bind "pcnet_cs"
+
+card "California Access Ethernet"
+  version "PCMCIAs", "ComboCard"
+  bind "pcnet_cs"
+
+card "CeLAN Ethernet"
+  version "PCMCIA", "ETHERNET V1.0"
+  bind "pcnet_cs"
+
+card "CentreCOM LA-PCM V2 Ethernet"
+  version "Allied Telesis, K.K.", "CentreCOM LA-PCM_V2"
+  bind "pcnet_cs"
+
+card "CNet CN30BC Ethernet"
+  version "CNet  ", "CN30BC", "ETHERNET"
+  bind "pcnet_cs"
+
+card "CNet CN40BC Ethernet"
+  version "CNet", "CN40BC Ethernet"
+  bind "pcnet_cs"
+
+card "Compaq Ethernet"
+  version "Compaq", "Ethernet LAN Card"
+  bind "xirc2ps_cs"
+
+card "Compaq Netelligent 10/100 Ethernet"
+  version "Compaq", "Netelligent 10/100 PC Card"
+  bind "xirc2ps_cs"
+
+card "COMPU-SHACK BASEline Ethernet"
+  version "COMPU-SHACK", "BASEline PCMCIA 10 MBit Ethernetadapter"
+  bind "pcnet_cs"
+
+card "Connectware LANdingGear Ethernet"
+  manfid 0x0057, 0x1004
+  bind "pcnet_cs"
+
+card "CONTEC Ethernet"
+  version "CONTEC Co.,Ltd."
+  bind "fmvj18x_cs"
+
+card "Corega PCC-T Ethernet"
+  version "corega K.K.", "corega Ether PCC-T"
+  bind "pcnet_cs"
+
+card "Corega PCC-T Ethernet"
+  version "corega,K.K.", "Ethernet LAN Card"
+  bind "pcnet_cs"
+
+card "Corega PCM-T Ethernet"
+  version "Corega,K.K.", "Ethernet LAN Card"
+  bind "pcnet_cs"
+
+card "CyQ've 10baseT Ethernet"
+  version "CyQ've 10 Base-T LAN CARD"
+  bind "pcnet_cs"
+
+card "CyQ've ELA-010 Ethernet"
+  version "CyQ've", "ELA-010"
+  bind "pcnet_cs"
+
+card "Danpex EN-6200P2 Ethernet"
+  version "*", "EN-6200P2"
+  bind "pcnet_cs"
+
+card "DataTrek NetCard Ethernet"
+  version "DataTrek.", "NetCard "
+  bind "pcnet_cs"
+
+card "Dayna Commnunications CommuniCard E Ethernet"
+  version "Dayna Communications, Inc.", "CommuniCard E"
+  bind "pcnet_cs"
+
+card "Digital DEPCM-BA Ethernet"
+  version "DIGITAL", "DEPCM-XX"
+  bind "pcnet_cs"
+
+card "Digital PCP78-AC Ethernet"
+  version "Digital", "Ethernet", "Adapter"
+  bind "pcnet_cs"
+
+card "D-Link DE-650 Ethernet"
+  version "D-Link", "DE-650"
+  bind "pcnet_cs"
+
+card "D-Link DFE-650 Ethernet"
+  version "D-Link", "DFE-650"
+  bind "pcnet_cs"
+
+card "D-Link DE-660 Ethernet"
+  version "D-Link", "DE-660"
+  bind "pcnet_cs"
+
+card "D-Link DE-650 Ethernet"
+  tuple 0x40, 0x0009, "D-Link PC Ethernet Card"
+  bind "pcnet_cs"
+
+card "DynaLink L10C Ethernet"
+  version "DYNALINK", "L10C"
+  bind "pcnet_cs"
+
+card "E2000 NE2000-Compatible Ethernet"
+  version "Ethernet Adapter", "E2000 PCMCIA Ethernet"
+  bind "pcnet_cs"
+
+card "Eagle NE200 Ethernet"
+  manfid 0x0004, 0x0004
+  bind "fmvj18x_cs"
+
+card "Edimax Ethernet Combo"
+  version "Edimax Technology Inc.", "PCMCIA", "Ethernet Card"
+  bind "pcnet_cs"
+
+card "EFA 207 Ethernet"
+  version "EFA   ", "EFA207", "ETHERNET"
+  bind "pcnet_cs"
+
+card "Eiger Labs EPX-ET10T2 Ethernet"
+  version "EIGER Labs Inc.", "Ethernet Combo card"
+  bind "pcnet_cs"
+
+card "Eiger Labs EPX-ET10BT Ethernet"
+  version "EIGER Labs Inc.", "Ethernet 10BaseT card"
+  bind "pcnet_cs"
+
+card "Eiger Labs EPX-10BT Ethernet"
+  version "Eiger Labs,Inc", "EPX-10BT PC Card Ethernet 10BT"
+  bind "fmvj18x_cs"
+
+card "Eiger Labs EPX-ET 10BT Ethernet"
+  version "Eiger labs,Inc.", "EPX-10BT PC Card Ethernet 10BT"
+  bind "fmvj18x_cs"
+
+card "ELECOM Laneed LD-CDF"
+  version "Laneed", "LD-CDF"
+  bind "pcnet_cs"
+
+card "EZLink 4109 Ethernet"
+  version "PCMCIA", "Ethernet Card"
+  bind "pcnet_cs"
+
+card "EP-210 Ethernet"
+  version "Ethernet PCMCIA adapter", "EP-210"
+  bind "pcnet_cs"
+
+card "EP-210 Ethernet"
+  version "EP-210 PCMCIA LAN CARD."
+  bind "pcnet_cs"
+
+card "EP-220 Ethernet"
+  version "PCMCIA", "ETHERNET"
+  bind "pcnet_cs"
+
+card "Epson EEN10B Ethernet"
+  version "Seiko Epson Corp.", "Ethernet"
+  bind "pcnet_cs"
+
+card "Farallon ENet"
+  version "Farallon", "ENet"
+  bind "3c589_cs"
+
+card "Fujitsu FMV-J181 Ethernet"
+  version "PCMCIA MBH10302"
+  bind "fmvj18x_cs"
+
+card "Fujitsu FMV-1080 Ethernet"
+  version "FUJITSU", "MBH10308"
+  bind "fmvj18x_cs"
+
+card "Fujitsu FMV-J182 Ethernet"
+  version "FUJITSU", "LAN Card(FMV-J182)"
+  bind "fmvj18x_cs"
+
+card "Fujitsu Towa LA501 Ethernet"
+  version "FUJITSU TOWA", "LA501"
+  bind "fmvj18x_cs"
+
+card "Grey Cell GCS2000 Ethernet"
+  version "Grey Cell", "GCS2000"
+  bind "pcnet_cs"
+
+card "Grey Cell GCS2220 Ethernet"
+  version "Grey Cell", "GCS2220"
+  bind "pcnet_cs"
+
+card "GVC NIC-2000P Ethernet"
+  version "GVC", "NIC-2000p"
+  bind "pcnet_cs"
+
+card "GVC NIC-2000P Ethernet"
+  version "PCMCIA", "Ethernet Combo card"
+  bind "pcnet_cs"
+
+card "Hitachi HT-4840-11 Ethernet"
+  version "HITACHI", "HT-4840-11"
+  bind "fmvj18x_cs"
+
+card "Hypertec EP401 Ethernet"
+  version "Hypertec", "*", "EP401"
+  bind "pcnet_cs"
+
+card "IBM Credit Card Ethernet"
+  version "IBM Corp.", "Ethernet"
+  bind "pcnet_cs"
+
+card "IC-Card Ethernet"
+  version "IC-CARD", "IC-CARD"
+  bind "pcnet_cs"
+
+card "IC-Card Plus Ethernet"
+  version "IC-CARD+", "IC-CARD+"
+  bind "pcnet_cs"
+
+card "Kansai KLA-PCM/T Ethernet"
+  version "KANSAI ELECTRIC CO.,LTD", "KLA-PCM/T"
+  bind "pcnet_cs"
+
+card "Katron PE-520 Ethernet"
+  version "KCI", "PE520 PCMCIA Ethernet Adapter"
+  bind "pcnet_cs"
+
+card "KingMax Technology Ethernet"
+  version "KingMax Technology Inc.", "EN10-T2", "PCMCIA Ethernet Card"
+  bind "pcnet_cs"
+
+card "KingMax Technology Ethernet"
+  version "KingMax Technology Inc.", "*", "Ethernet Card"
+  bind "pcnet_cs"
+
+card "KingMax Technology Ethernet"
+  version "KINGMAX", "EN10T2T"
+  bind "pcnet_cs"
+
+card "Kingston KNE-PCM/x Ethernet"
+  version "Kingston Technology Corp.", "EtheRx PC Card Ethernet Adapter"
+  bind "pcnet_cs"
+
+card "Kingston KNE-PC2 Ethernet"
+  version "Kingston", "KNE-PC2"
+  bind "pcnet_cs"
+
+card "KTI PE-520 Plus Ethernet"
+  version "KTI", "PE520 PLUS"
+  cis "cis/PE520.dat"
+  bind "pcnet_cs"
+
+card "Linksys Ethernet"
+  tuple 0x40, 0x0009, "E-CARD PC Ethernet Card"
+  cis "cis/E-CARD.dat"
+  bind "pcnet_cs"
+
+card "Linksys Ethernet"
+  version "LINKSYS", "E-CARD"
+  bind "pcnet_cs"
+
+card "Linksys Ethernet"
+  version "E-CARD", "E-CARD"
+  bind "pcnet_cs"
+
+card "Linksys Ethernet"
+  version "Linksys", "Combo PCMCIA EthernetCard (EC2T)"
+  bind "pcnet_cs"
+
+card "Longshine ShineNet LCS-8534 Ethernet"
+  version "LONGSHINE", "PCMCIA Ethernet Card"
+  bind "pcnet_cs"
+
+card "Longshine ShineNet LCS-8534 Ethernet"
+  version "LONGSHINE", "*", "EP401"
+  bind "pcnet_cs"
+
+card "Logitec LPM-LN10BA Ethernet"
+  version "Cardwell", "PCMCIA", "ETHERNET"
+  bind "pcnet_cs"
+
+card "Logitec LPM-LN20T Ethernet"
+  version "Logitec", "LPM-LN20T"
+  bind "pcnet_cs"
+
+card "MACNICA Ethernet"
+  version "MACNICA", "ME1-JEIDA"
+  bind "pcnet_cs"
+
+card "Maxtech PCN2000 Ethernet"
+  version "MAXTECH", "PCN2000"
+  bind "pcnet_cs"
+
+card "Megahertz CC10BT/2 Ethernet"
+  version "Megahertz", "CC10BT/2"
+  bind "smc91c92_cs"
+
+card "Melco LPC2-T Ethernet"
+  manfid 0x01bf, 0x2216
+  bind "pcnet_cs"
+
+card "Microdyne NE4200 Ethernet"
+  version "Microdyne", "NE4200"
+  bind "pcnet_cs"
+
+card "Midori LT-PCMT Ethernet"
+  version "MIDORI ELEC.", "LT-PCMT"
+  bind "pcnet_cs"
+
+card "National Semiconductor InfoMover 4100 Ethernet"
+  version "National Semiconductor", "InfoMover 4100"
+  bind "pcnet_cs"
+
+card "National Semiconductor InfoMover NE4100 Ethernet"
+  version "National Semiconductor", "InfoMover NE4100"
+  bind "pcnet_cs"
+
+card "NEC PC-9801N-J12 Ethernet"
+  version "NEC", "PC-9801N-J12"
+  bind "pcnet_cs"
+
+card "New Media Ethernet"
+  version "New Media Corporation", "Ethernet"
+  bind "nmclan_cs"
+
+card "New Media BASICS Ethernet"
+  version "BASICS by New Media Corporation", "Ethernet", "SMC91C94"
+  bind "smc91c92_cs"
+
+card "New Media LanSurfer"
+  manfid 0x0057, 0x0021
+  bind "pcnet_cs"
+
+card "NextCom NC5310 Ethernet"
+  version "NextComK.K.", "NC5310 Ver1.0        "
+  bind "fmvj18x_cs"
+
+card "NE2000 Compatible Ethernet"
+  version "PCMCIA", "Ethernet"
+  bind "pcnet_cs"
+
+card "NE2000 Compatible Ethernet"
+  version "PCMCIA", "Ethernet 10BaseT Card"
+  bind "pcnet_cs"
+
+card "NE2000 Compatible Ethernet"
+  version "NE2000 Compatible"
+  bind "pcnet_cs"
+
+card "NE2000 Compatible Ethernet"
+  version "Ethernet", "Adapter"
+  bind "pcnet_cs"
+
+card "NE2000 Compatible Ethernet"
+  manfid 0x0149, 0xc1ab
+  bind "pcnet_cs"
+
+card "NDC Instant-Link Ethernet"
+  version "NDC", "Ethernet"
+  cis "cis/NE2K.dat"
+  bind "pcnet_cs"
+
+card "Novell Eagle 200T Ethernet"
+  version "EAGLE Technology", "NE200 ETHERNET LAN MBH10302 04"
+  bind "fmvj18x_cs"
+
+card "Ositech Four of Diamonds Ethernet"
+  version "Ositech", "Trumpcard:Four of Diamonds Ethernet"
+  bind "smc91c92_cs"
+
+card "IO DATA PCLA/T Ethernet"
+  version "I-O DATA", "PCLA", "ETHERNET"
+  bind "pcnet_cs"
+
+card "IO DATA PCLA/TE Ethernet"
+  version "IO DATA", "PCLATE", "ETHERNET"
+  bind "pcnet_cs"
+
+card "Panasonic CF-VEL211 Ethernet"
+  version "Matsushita Electric Industrial Co.,LTD.", "CF-VEL211"
+  bind "pcnet_cs"
+
+card "PreMax PE-200 Ethernet"
+  version "PMX   ", "PE-200"
+  cis "cis/PE-200.dat"
+  bind "pcnet_cs"
+
+card "Psion Gold Card Ethernet"
+  version "Psion Dacom", "Gold Card Ethernet"
+  bind "pcnet_cs"
+
+card "Psion Gold Card Netglobal Ethernet"
+  version "Psion", "10Mb Ethernet"
+  bind "smc91c92_cs"
+
+card "RATOC Ethernet"
+  version "PCMCIA LAN MBH10304  ES"
+  bind "fmvj18x_cs"
+
+card "RATOC REX-R280 Ethernet"
+  version "RATOC System Inc.", "10BASE_T CARD R280"
+  bind "fmvj18x_cs"
+
+card "Relia RE2408T Ethernet"
+  version "PCMCIA LAN", "Ethernet"
+  bind "pcnet_cs"
+
+card "Reliasys 2400A Ethernet"
+  version "=RELIA==", "Ethernet"
+  bind "pcnet_cs"
+
+card "RPTI EP400 Ethernet"
+  version "RPTI LTD.", "EP400"
+  bind "pcnet_cs"
+
+card "RPTI EP400 Ethernet"
+  version "RPTI", "EP400 Ethernet NE2000 Compatible"
+  bind "pcnet_cs"
+
+card "RPTI EP401 Ethernet"
+  version "RPTI", "EP401 Ethernet NE2000 Compatible"
+  bind "pcnet_cs"
+
+card "RPTI 1625B Ethernet"
+  version "RP", "1625B Ethernet NE2000 Compatible"
+  bind "pcnet_cs"
+
+card "SCM Ethernet Combo"
+  version "SCM", "Ethernet Combo card"
+  bind "pcnet_cs"
+
+card "Sky Link Express"
+  version "2408LAN", "Ethernet"
+  bind "pcnet_cs"
+
+card "SMC EtherEZ Ethernet"
+  version "SMC", "EtherEZ Ethernet 8020"
+  bind "smc91c92_cs"
+
+card "SMC EZCard-10 Ethernet"
+  version "SMC", "EZCard-10-PCMCIA"
+  bind "pcnet_cs"
+
+card "Socket EA Ethernet"
+  version "Socket Communications Inc",
+    "Socket EA PCMCIA LAN Adapter Revision D"
+  bind "pcnet_cs"
+
+card "Socket EA Ethernet"
+  version "Socket Communications Inc",
+    "Socket EA PCMCIA LAN Adapter Revision E"
+  bind "pcnet_cs"
+
+card "Socket LP-E Ethernet"
+  manfid 0x0104, 0x000d
+  bind "pcnet_cs"
+
+card "Socket LP-E CF+ Ethernet"
+  manfid 0x0104, 0x0075
+  bind "pcnet_cs"
+
+card "SuperSocket Ethernet"
+  version "Telecom Device K.K.", "SuperSocket RE450T"
+  bind "pcnet_cs"
+
+card "Surecom Ethernet"
+  version "TAMARACK", "Ethernet"
+  bind "pcnet_cs"
+
+card "TDK LAC-CD02x Ethernet"
+  version "TDK", "LAC-CD02x"
+  bind "fmvj18x_cs"
+
+card "Xircom IIps Ethernet"
+  version "Xircom", "*", "PS-CE2-10"
+  bind "xirc2ps_cs"
+
+card "Xircom RE-10 Ethernet"
+  version "Xircom", "*", "RE-10"
+  bind "xirc2ps_cs"
+
+#
+# 10/100baseT network adapters
+#
+card "3Com 572/574 Fast Ethernet"
+  manfid 0x0101, 0x0574
+  bind "3c574_cs"
+
+card "Abocom LinkMate FE1000 Fast Ethernet"
+  version "Fast Ethernet", "Adapter"
+  bind "pcnet_cs"
+
+card "Accton Fast EtherCard-16"
+  manfid 0x01bf, 0x010a
+  bind "xirc2ps_cs"
+
+card "AmbiCom AMB8110 Fast Ethernet"
+  manfid 0x021b, 0x0202
+  bind "pcnet_cs"
+
+card "AnyCom ECO 10/100 Fast Ethernet"
+  version "AnyCom", "ECO Ethernet 10/100"
+  bind "pcnet_cs"
+
+card "Argosy EN220 Fast Ethernet"
+  version "ARGOSY", "Fast Ethernet PCCard"
+  bind "smc91c92_cs"
+
+card "COMPU-SHACK FASTline 10/100 Fast Ethernet"
+  version "COMPU-SHACK", "FASTline PCMCIA 10/100 Fast-Ethernet"
+  bind "pcnet_cs"
+
+card "Corega PCC-TX Fast Ethernet"
+  version "corega K.K.", "corega FastEther PCC-TX"
+  bind "pcnet_cs"
+
+card "D-Link Fast Ethernet"
+  version "ETHER-C16"
+  bind "pcnet_cs"
+
+card "Dynalink L100C Fast Ethernet"
+  version "DYNALINK", "L100C"
+  bind "smc91c92_cs"
+
+card "EXP ThinLan-110 Fast Ethernet"
+  version "PCMCIA", "Fast Ethernet PCCard"
+  bind "smc91c92_cs"
+
+card "Farallon Enet"
+  version "Farallon", "Farallon Enet"
+  bind "smc91c92_cs"
+
+card "Intel EtherExpress PRO/100"
+  version "Intel", "EtherExpress(TM) PRO/100 PC Card Mobile Adapter16"
+  bind "xirc2ps_cs"
+
+card "IO DATA PCET/TX Fast Ethernet"
+  version "IO DATA", "PCETTX"
+  bind "pcnet_cs"
+
+card "KTI ETHER-C16 Fast ethernet"
+  manfid 0x0149, 0x0230
+  bind "pcnet_cs"
+
+card "Laneed LD-10/100CD Fast Ethernet"
+  version "Laneed", "LD-10/100CD"
+  bind "pcnet_cs"
+
+card "Level One 10/100 Fast Ethernet"
+  version "Dual Speed", "10/100 PC Card"
+  bind "pcnet_cs"
+
+card "Linksys EtherFast 10/100 Fast Ethernet"
+  version "Linksys", "EtherFast 10/100 PC Card (PCMPC100)"
+  bind "pcnet_cs"
+
+card "Logitec LPM-LN100TX Fast Ethernet"
+  version "Logitec", "LPM-LN100TX"
+  bind "pcnet_cs"
+
+card "Melco LPC2-TX Fast Ethernet"
+  version "MELCO", "LPC2-TX"
+  bind "pcnet_cs"
+
+card "Melco/SMC LPC-TX Fast Ethernet"
+  version "MELCO/SMC", "LPC-TX"
+  bind "smc91c92_cs"
+
+card "Microcom C.E. Travel Card 10/100 Fast Ethernet"
+  version "Microcom C.E.", "Travel Card LAN 10/100"
+  bind "pcnet_cs"
+
+card "NetGear FA410TXC Fast Ethernet"
+  version "NETGEAR", "FA410TX"
+  bind "pcnet_cs"
+
+card "Ositech Seven of Diamonds Fast Ethernet"
+  version "Ositech", "Trumpcard:Seven of Diamonds Ethernet"
+  bind "smc91c92_cs"
+
+card "NE2000 Compatible Fast Ethernet"
+  version "PCMCIA", "10/100 Ethernet Card"
+  bind "pcnet_cs"
+
+card "NE2000 Compatible Fast Ethernet"
+  version "PCMCIA", "FAST ETHERNET CARD"
+  bind "pcnet_cs"
+
+card "Planex FNW-3600T Fast Ethernet"
+  version "Fast Ethernet", "Adapter"
+  bind "pcnet_cs"
+
+card "Toshiba Advanced Network Fast Ethernet"
+  version "Toshiba Information Systems", "*", "TPCENET"
+  bind "xirc2ps_cs"
+
+card "Toshiba 10/100 Fast Ethernet"
+  version "Toshiba", "10/100 Ethernet PC Card"
+  bind "xirc2ps_cs"
+
+# These conflict with other cards!
+#card "WiseCom WC-PC400 Fast Ethernet"
+#  manfid 0x0186, 0x0100
+#  bind "smc91c92_cs"
+#card "WiseCom WC-PC400 Fast Ethernet"
+#  manfid 0x8a01, 0xc1ab
+#  bind "smc91c92_cs"
+
+card "Xircom CE3-10/100 Fast Ethernet"
+  version "Xircom", "*", "CE3-10/100"
+  bind "xirc2ps_cs"
+
+#
+# Wireless network adapters
+#
+card "Aironet PC4500"
+  manfid 0x015f, 0x0005
+  bind "airo_cs"
+
+card "Aironet PC4800"
+  manfid 0x015f, 0x0007
+  bind "airo_cs"
+
+card "AT&T WaveLAN Adapter"
+  version "AT&T", "WaveLAN/PCMCIA"
+  bind "wavelan_cs"
+
+card "Cabletron RoamAbout 802.11 DS"
+  version "Cabletron", "RoamAbout 802.11 DS"
+  bind "wvlan_cs"
+
+card "Digital RoamAbout/DS"
+  version "Digital", "RoamAbout/DS"
+  bind "wavelan_cs"
+
+card "Lucent Technologies WaveLAN Adapter"
+  version "Lucent Technologies", "WaveLAN/PCMCIA"
+  bind "wavelan_cs"
+
+card "Lucent Technologies WaveLAN/IEEE Adapter"
+  version "Lucent Technologies", "WaveLAN/IEEE"
+  bind "wvlan_cs"
+
+card "MELCO WLI-PCM-L11"
+  version "MELCO", "WLI-PCM-L11"
+  bind "wvlan_cs"
+
+card "NCR WaveLAN Adapter"
+  version "NCR", "WaveLAN/PCMCIA"
+  bind "wavelan_cs"
+
+card "NCR WaveLAN/IEEE Adapter"
+  version "NCR", "WaveLAN/IEEE"
+  bind "wvlan_cs"
+
+card "RayLink PC Card WLAN Adapter"
+  manfid 0x01a6, 0x0000
+  bind "ray_cs"
+
+card "Xircom CreditCard Netwave"
+  version "Xircom", "CreditCard Netwave"
+  bind "netwave_cs"
+
+#
+# Modems and other serial devices
+#
+# NOTE: most modems do not need explicit entries here, because they
+# are correctly identified using the following generic entry.
+#
+card "Serial or Modem"
+  function serial_port
+  bind "serial_cs"
+
+card "3Com 3CCM156 56K Global Modem"
+  manfid 0x0101, 0x0039
+  bind "serial_cs"
+
+card "Angia Fax/Modem"
+  version "Intelligent", "ANGIA FAX/MODEM"
+  bind "serial_cs"
+
+card "Bullet V.34 28.8K Modem"
+  version "OEM      ", "C288MX     "
+  bind "serial_cs"
+
+card "Cirrus Logic 14.4K Fax Modem"
+  version "CIRRUS LOGIC", "FAX MODEM"
+  bind "serial_cs"
+
+card "Compaq 28.8K Modem"
+  version "COMPAQ", "PCMCIA 28800 FAX/DATA MODEM"
+  bind "serial_cs"
+
+card "Compaq 33.6K Modem"
+  version "COMPAQ", "PCMCIA 33600 FAX/DATA MODEM"
+  bind "serial_cs"
+
+card "Dr. Neuhaus 14.4K FURY Card"
+  version "Dr. Neuhaus", "FURY CARD 14K4"
+  bind "serial_cs"
+
+card "E.TECH Bullet 33.6K Modem"
+  version "PCMCIA   ", "C336MX     "
+  bind "serial_cs"
+
+card "Gateway 2000 TelePath Fax Modem"
+  version "GATEWAY2000", "CC3144", "*", "PCMCIA MODEM"
+  bind "serial_cs"
+
+card "Intel-compatible Modem"
+  version "Intel", "MODEM 2400+"
+  bind "serial_cs"
+
+card "Macronix Fax/Modem"
+  version "MACRONIX", "FAX/MODEM"
+  bind "serial_cs"
+
+card "Megahertz PCMCIA Modem"
+  version "MEGAHERTZ", "*", "*", "PCMCIA MODEM"
+  bind "serial_cs"
+
+card "Megahertz V.34 Modem"
+  version "MEGAHERTZ", "*", "V.34 PCMCIA MODEM"
+  bind "serial_cs"
+
+card "MultiTech MultiModem"
+  version "Multi-Tech", "MT1432LT"
+  bind "serial_cs"
+
+card "MultiTech V.34 Modem"
+  version "Multi-Tech", "MT2834LT"
+  bind "serial_cs"
+
+card "MultiTech MT5634ZLX"
+  version "MultiTech", "PCMCIA 56K DataFax"
+  cis "cis/MT5634ZLX.dat"
+  bind "serial_cs"
+
+card "Toshiba T144PF Modem"
+  version "TOSHIBA", "T144PF", "*", "PCMCIA MODEM"
+  bind "serial_cs"
+
+card "Advantech COMpad-32/85"
+  version "ADVANTECH", "COMpad-32/85", "1.0"
+  cis "cis/COMpad.dat"
+  bind "serial_cs"
+
+card "Advantech COMpad-32/85"
+  version "ADV", "*", "TECH", "COMpad-32/85"
+  bind "serial_cs"
+
+card "Argosy Dual Serial I/O"
+  version "*", "RS-COM 2P"
+  cis "cis/RS-COM-2P.dat"
+  bind "serial_cs"
+
+card "Computerboards PCM-COM422"
+  version "Computerboards, Inc.", "PCM-COM422"
+  bind "serial_cs"
+
+card "Fujitsu FMV-JMD711"
+  version "FUJITSU", "FC14F ", "MBH10213"
+  bind "serial_cs"
+
+card "IOTech Dual RS-232"
+  version "IOTech Inc ", "PCMCIA Dual RS-232 Serial Port Card"
+  bind "serial_cs"
+
+card "National Instruments PCMCIA-232"
+  manfid 0x10b, 0x0d50
+  bind "serial_cs"
+
+card "National Instruments PCMCIA-232/2"
+  manfid 0x10b, 0x0d51
+  bind "serial_cs"
+
+card "National Instruments PCMCIA-485"
+  manfid 0x10b, 0x0d52
+  bind "serial_cs"
+
+card "National Instruments PCMCIA-485/2"
+  manfid 0x10b, 0x0d53
+  bind "serial_cs"
+
+card "National Instruments PCMCIA-232/4"
+  manfid 0x10b, 0xd180
+  bind "serial_cs"
+
+card "Omega Engineering QSP-100"
+  manfid 0x0137, 0x0025
+  bind "serial_cs"
+
+card "Quatech Dual RS-232"
+  version "Quatech Inc", "PCMCIA Dual RS-232 Serial Port Card"
+  bind "serial_cs"
+
+card "Quatech Quad RS-232"
+  manfid 0x0137, 0x001b
+  bind "serial_cs"
+
+card "Silicom 2S100 Dual Serial"
+  manfid 0x0089, 0x0301
+  bind "serial_cs"
+
+card "Socket Communications Dual RS-232"
+  manfid 0x0104, 0x0006
+  bind "serial_cs"
+
+#
+# Memory cards
+#
+card "Anonymous Memory"
+  anonymous
+  bind "memory_cs"
+
+card "Memory Card"
+  function memory_card
+  bind "memory_cs"
+
+card "IBM 2MB SRAM"
+  version "IBM", "2MB SRAM"
+  bind "memory_cs"
+
+card "IBM 4MB Series 1 Flash"
+  version "IBM", "4MB FLASH"
+  bind "memory_cs", "ftl_cs"
+
+card "IBM 8MB Series 2 Flash"
+  version "IBM", "8MB FLASH"
+  bind "memory_cs", "ftl_cs"
+
+card "Intel Series 2 2MB Flash"
+  version "intel", "SERIES2-02 "
+  bind "memory_cs", "ftl_cs"
+
+card "Intel Series 2 4MB Flash"
+  version "intel", "SERIES2-04 "
+  bind "memory_cs", "ftl_cs"
+
+card "Intel Series 2 20MB Flash"
+  version "intel", "SERIES2-20 "
+  bind "memory_cs", "ftl_cs"
+
+card "Intel Series 2+ 8MB Flash"
+  version "Intel", "S2E8 SW"
+  bind "memory_cs", "ftl_cs"
+
+card "Intel Series 2+ 20MB Flash"
+  version "Intel", "S2E20SW"
+  bind "memory_cs", "ftl_cs"
+
+card "Intel Series 100 Flash"
+  version "intel", "VALUE SERIES 100 "
+  bind "memory_cs", "ftl_cs"
+
+card "IO DATA 2MB SRAM"
+  version "IO DATA", "PCS-2M", "2MB SRAM"
+  bind "memory_cs"
+
+card "Maxtor MobileMax Flash"
+  version "Maxtor", "MAXFL MobileMax Flash Memory Card"
+  bind "memory_cs", "ftl_cs"
+
+card "Seiko/Epson WWB101EN20"
+  version "SEIKO EPSON", "WWB101EN20"
+  bind "memory_cs"
+
+card "Seiko/Epson WWB513EN20"
+  version "SEIKO EPSON", "WWB513EN20"
+  bind "memory_cs"
+
+card "Franklink/Rolodex REX-3000"
+  version "Starfish, Inc.", "REX-3000"
+  bind "memory_cs"
+
+card "Franklink/Rolodex REX-4100"
+  version "Starfish, Inc.", "REX-4100"
+  bind "memory_cs"
+
+card "RATOC SmartMedia Adapter"
+  version "RATOC Systems,Inc.", "SmartMedia ADAPTER PC Card"
+  bind "memory_cs", "ftl_cs"
+
+#
+# Memory Technology Drivers
+#
+region "Generic or SRAM"
+  default
+  mtd "sram_mtd"
+
+region "Intel Series 2 Flash"
+  jedec 0x89 0xa2
+  mtd "iflash2_mtd"
+
+region "Intel Series 100 Flash"
+  jedec 0x89 0xaa
+  mtd "iflash2_mtd"
+
+region "Intel Series 2+ Flash"
+  jedec 0x89 0xa0
+  mtd "iflash2+_mtd"
+
+#
+# Token Ring adapters
+#
+card "3Com TokenLink Velocity Adapter"
+  version "3Com", "TokenLink Velocity PC Card"
+  bind "ibmtr_cs"
+
+card "IBM Token Ring Adapter"
+  version "IBM", "TOKEN RING"
+  bind "ibmtr_cs"
+
+#
+# SCSI host adapters
+#
+card "Adaptec APA-1460 SlimSCSI"
+  version "Adaptec, Inc.", "APA-1460 SCSI Host Adapter"
+  bind "aha152x_cs"
+
+card "Eiger Labs SCSI"
+  version "EIger Labs", "PCMCIA-to-SCSI Adapter"
+  bind "qlogic_cs"
+
+card "Epson SC200 SCSI"
+  version "EPSON", "SCSI-2 PC Card SC200"
+  bind "qlogic_cs"
+  
+card "IBM SCSI"
+  version "IBM Corp.", "SCSI PCMCIA Card"
+  bind "fdomain_cs"
+
+card "IBM SCSI"
+  version "SCSI PCMCIA Adapter Card"
+  bind "fdomain_cs"
+
+#card "MACNICA mPS100 SCSI"
+#  version "MACNICA", "MIRACLE SCSI", "mPS100"
+#  bind "qlogic_cs"
+
+card "MACNICA mPS110 SCSI"
+  version "MACNICA", "MIRACLE SCSI-II mPS110"
+  bind "qlogic_cs"
+
+card "Midori CN-SC43 SCSI"
+  version "MIDORI ELECTRONICS ", "CN-SC43"
+  bind "qlogic_cs"
+
+card "NEC PC-9801N-J03R SCSI"
+  version "NEC", "PC-9801N-J03R"
+  bind "qlogic_cs"
+
+card "New Media Bus Toaster SCSI"
+  version "New Media", "SCSI", "Bus Toaster"
+  bind "aha152x_cs"
+
+card "New Media Toast & Jam Sound/SCSI"
+  version "New Media Corporation", "Multimedia Sound/SCSI"
+  bind "aha152x_cs"
+
+card "Noteworthy Bus Toaster SCSI"
+  version "NOTEWORTHY", "SCSI", "Bus Toaster"
+  bind "aha152x_cs"
+
+card "New Media BASICS SCSI"
+  version "BASICS by New Media Corporation", "SCSI Sym53C500"
+  bind "sym53c500_cs"
+
+card "New Media Bus Toaster SCSI"
+  version "New Media Corporation", "SCSI Bus Toaster Sym53C500"
+  bind "sym53c500_cs"
+
+card "Panasonic KXLC003"
+  version "KME ", "KXLC003"
+  bind "qlogic_cs"
+
+card "Panasonic KXLC004"
+  version "KME ", "KXLC004"
+  bind "qlogic_cs"
+
+card "Qlogic FastSCSI"
+  version "QLOGIC CORPORATION", "pc05"
+  bind "qlogic_cs"
+
+card "Qlogic FastSCSI"
+  version "QLOGIC CORPORATION", "pc05 rev 1.10"
+  bind "qlogic_cs"
+
+card "Raven CD-Note SCSI"
+  version "KME", "KXLC002", "00"
+  bind "qlogic_cs"
+
+card "RATOC REX-9530 SCSI-2"
+  version "RATOC System Inc.", "SCSI2 CARD 37"
+  bind "qlogic_cs"
+
+card "SIMA TECH SCSI9000"
+  version "*", "SCSI9000"
+  bind "sym53c500_cs"
+
+card "Simple Technology SCSI"
+  version " SIMPLE TECHNOLOGY Corporation",
+    "SCSI PCMCIA Credit Card Controller"
+  bind "fdomain_cs"
+
+card "Toshiba SCSC200A SCSI"
+  version "TOSHIBA", "SCSC200A PC CARD SCSI"
+  bind "qlogic_cs"
+
+card "Toshiba SCSC200B SCSI"
+  version "TOSHIBA", "SCSC200B PC CARD SCSI-10"
+  bind "qlogic_cs"
+
+#
+# Multifunction cards
+#
+card "3Com 3c562/3c563 Ethernet/Modem"
+  manfid 0x0101, 0x0562
+  bind "3c589_cs" to 0, "serial_cs" to 1
+
+card "3Com/Megahertz 3CXEM556 Ethernet/Modem"
+  manfid 0x0101, 0x0035
+  cis "cis/3CXEM556.dat"
+  bind "3c589_cs" to 0, "serial_cs" to 1
+
+card "3Com/Megahertz 3CXEM556 B-INT Ethernet/Modem"
+  manfid 0x0101, 0x003d
+  cis "cis/3CXEM556.dat"
+  bind "3c589_cs" to 0, "serial_cs" to 1
+
+card "3Com/Megahertz 3CCFEM556 Ethernet/Modem"
+  manfid 0x0101, 0x0556
+  cis "cis/3CCFEM556.dat"
+  bind "3c574_cs" to 0, "serial_cs" to 1
+
+card "Accton EN2218 LAN/Modem"
+  version "PCMCIA", "EN2218-LAN/MODEM"
+  cis "cis/PCMLM28.dat"
+  bind "pcnet_cs", "serial_cs"
+
+card "Accton UE2218 LAN/Modem"
+  version "PCMCIA", "UE2218-LAN/MODEM"
+  cis "cis/PCMLM28.dat"
+  bind "pcnet_cs", "serial_cs"
+
+card "AnyCom Fast Ethernet/Modem"
+  version "AnyCom", "Fast Ethernet + 56K COMBO"
+  bind "pcnet_cs", "serial_cs"
+
+card "Apex MultiCard Ethernet/Modem"
+  version "APEX DATA", "MULTICARD", "ETHERNET-MODEM"
+  bind "pcnet_cs" to 0, "serial_cs" to 1
+
+card "Billionton LM5LT-10B Ethernet/Modem"
+  manfid 0x021b, 0x0101
+  bind "pcnet_cs", "serial_cs"
+
+card "Compaq Microcom CPQ550 Ethernet/Modem"
+  manfid 0x0138, 0x110a
+  bind "xirc2ps_cs", "serial_cs"
+
+card "Dayna Communicard Ethernet/Modem"
+  version "DAYNA COMMUNICATIONS", "LAN AND MODEM MULTIFUNCTION"
+  cis "cis/DP83903.dat"
+  bind "pcnet_cs" to 0, "serial_cs" to 1
+
+card "D-Link DME336T Ethernet/Modem"
+  version "D-Link", "DME336T"
+  bind "pcnet_cs", "serial_cs"
+
+card "D-Link DMF560TX Ethernet/Modem"
+  manfid 0x0143, 0xc0ab
+  bind "pcnet_cs", "serial_cs"
+
+card "Gateway Telepath Ethernet/Modem"
+  version "Gateway 2000", "XJEM3336"
+  bind "smc91c92_cs", "serial_cs"
+
+card "Grey Cell GCS3400 Ethernet/Modem"
+  version "Grey Cell", "GCS3000"
+  bind "pcnet_cs", "serial_cs"
+
+card "IBM Home and Away Ethernet/Modem"
+  version "IBM", "Home and Away Credit Card Adapter"
+  bind "pcnet_cs" to 0, "serial_cs" to 1
+
+card "IBM Home and Away 28.8 Ethernet/Modem"
+  version "IBM", "Home and Away 28.8 PC Card       "
+  bind "pcnet_cs" to 0, "serial_cs" to 1
+
+card "IBM w95 Home and Away Ethernet/Modem"
+  version "IBM", "w95 Home and Away Credit Card "
+  bind "pcnet_cs" to 0, "serial_cs" to 1
+
+card "Intel EtherExpress PRO/100 LAN/Modem"
+  manfid 0x0089, 0x110a
+  bind "xirc2ps_cs", "serial_cs"
+
+card "No-Name Ethernet/Modem"
+  version "*", "FAX/Modem/Ethernet Combo Card "
+  bind "pcnet_cs" to 0, "serial_cs" to 1
+
+card "Linksys LANmodem 28.8"
+  version "LINKSYS", "PCMLM28"
+  cis "cis/PCMLM28.dat"
+  bind "pcnet_cs", "serial_cs"
+
+card "Linksys LANmodem 33.6"
+  version "LINKSYS", "PCMLM336"
+  bind "pcnet_cs", "serial_cs"
+
+card "Linksys EtherFast LANmodem 56K"
+  version "Linksys", "EtherFast 10&100 + 56K PC Card (PCMLM56)"
+  bind "pcnet_cs", "serial_cs"
+
+card "Megahertz CC/XJEM1144 Ethernet/Modem"
+  version "MEGAHERTZ", "XJEM1144/CCEM1144", "PCMCIA MODEM"
+  bind "smc91c92_cs", "serial_cs"
+
+card "Megahertz CC/XJEM1144 Ethernet/Modem"
+  version "MEGAHERTZ", "XJEM1144/CCEM1144"
+  bind "smc91c92_cs", "serial_cs"
+
+card "Megahertz EM1144T Ethernet/Modem"
+  version "MEGAHERTZ", "EM1144T", "PCMCIA MODEM"
+  bind "smc91c92_cs", "serial_cs"
+
+card "Megahertz CC/XJEM3288 Ethernet/Modem"
+  version "MEGAHERTZ", "CC/XJEM3288", "DATA/FAX/CELL ETHERNET MODEM"
+  bind "smc91c92_cs", "serial_cs"
+
+card "Megahertz CC/XJEM3336 Ethernet/Modem"
+  version "MEGAHERTZ", "CC/XJEM3336", "DATA/FAX/CELL ETHERNET MODEM"
+  bind "smc91c92_cs", "serial_cs"
+
+card "Motorola Marquis Ethernet/Modem"
+  version "Motorola MARQUIS"
+  bind "3c589_cs" to 0, "serial_cs" to 1
+
+card "Motorola Mariner Ethernet/Modem"
+  manfid 0x0109, 0x0501
+  bind "smc91c92_cs", "serial_cs"
+
+card "NSC DP83903-based Ethernet/Modem"
+  version "*", "*", "*", "NSC MF LAN/Modem"
+  cis "cis/DP83903.dat"
+  bind "pcnet_cs" to 0, "serial_cs" to 1
+
+card "Ositech Jack of Diamonds Ethernet/Modem"
+  version "Ositech", "Trumpcard:Jack of Diamonds Modem+Ethernet"
+  bind "smc91c92_cs", "serial_cs"
+
+card "Ositech Jack of Hearts Ethernet/Modem"
+  version "Ositech", "Trumpcard:Jack of Hearts Modem+Ethernet"
+  bind "smc91c92_cs", "serial_cs"
+
+card "Ositech Jack of Hearts Ethernet/Modem"
+  manfid 0x0140, 0x000a
+  bind "smc91c92_cs", "serial_cs"
+
+card "Psion Gold Card V34 Ethernet"
+  version "Psion Dacom", "Gold Card V34 Ethernet"
+  cis "cis/PCMLM28.dat"
+  bind "pcnet_cs", "serial_cs"
+
+card "Psion Gold Card V34 Ethernet"
+  version "Psion Dacom", "Gold Card V34 Ethernet GSM"
+  cis "cis/PCMLM28.dat"
+  bind "pcnet_cs", "serial_cs"
+
+card "Psion Gold Card Netglobal 56K+10Mb Ethernet"
+  manfid 0x016c, 0x0020
+  bind "smc91c92_cs" to 0, "serial_cs" to 1
+
+card "Rover ComboCard Ethernet/Modem"
+  version "PCMCIAs", "ComboCard"
+  bind "pcnet_cs", "serial_cs"
+
+card "TDK Global Networker Ethernet/Modem"
+  version "TDK", "GlobalNetworker 3410/3412"
+  bind "serial_cs"
+
+card "TDK 3000/3400/5670 Fast Ethernet/Modem"
+  manfid 0x0143, 0x3341
+  bind "pcnet_cs", "serial_cs"
+
+card "TDK DFL5610WS Ethernet/Modem"
+  manfid 0x0105, 0xea15
+  bind "pcnet_cs", "serial_cs"
+
+card "Telecom Device SuperSocket LM336 Ethernet/Modem"
+  version "PCMCIAs", "LanModem"
+  bind "pcnet_cs", "serial_cs"
+
+card "Xircom CE II Ethernet/Modem"
+  version "Xircom", "CreditCard Ethernet+Modem II"
+  bind "xirc2ps_cs", "serial_cs"
+
+card "Xircom CEM28 Ethernet/Modem"
+  version "Xircom", "*", "CEM28"
+  bind "xirc2ps_cs", "serial_cs"
+
+card "Xircom CEM33 Ethernet/Modem"
+  version "Xircom", "*", "CEM33"
+  bind "xirc2ps_cs", "serial_cs"
+
+card "Xircom CEM56 Ethernet/Modem"
+  version "Xircom", "*", "CEM56"
+  bind "xirc2ps_cs", "serial_cs"
+
+card "Xircom RealPort REM10BT Ethernet/Modem"
+  version "Xircom", "*", "REM10"
+  bind "xirc2ps_cs", "serial_cs"
+
+#
+# ATA/IDE fixed disk devices
+#
+card "ATA/IDE Fixed Disk"
+  function fixed_disk
+  bind "ide_cs"
+
+card "ACE DoubleFlash 20MB"
+  version "IBM", "IBM17JSSFP20"
+  bind "ide_cs"
+
+card "Argosy EIDE CD-ROM"
+  version "ARGOSY", "CD-ROM"
+  bind "ide_cs"
+
+card "Caravelle CD-36N/CD-36E CD-ROM"
+  version "Caravelle", "PSC-IDE ", "PSC000"
+  bind "ide_cs"
+
+card "CNF CARDport CD-ROM"
+  version "CNF CD-M", "CD-ROM"
+  bind "ide_cs"
+
+card "Creative Technology CD-ROM"
+  version "Creative Technology Ltd.", "PCMCIA CD-ROM Interface Card"
+  bind "ide_cs"
+
+card "Digital Mobile Media CD-ROM"
+  version "Digital Equipment Corporation.", "Digital Mobile Media CD-ROM"
+  bind "ide_cs"
+
+card "EXP CD940 CD-ROM"
+  version "EXP   ", "CD-ROM"
+  bind "ide_cs"
+
+card "EXP Traveler 620 CD-ROM"
+  version "EXP", "CD+GAME", "C1"
+  bind "ide_cs"
+
+card "Freecom IQ-drive"
+  version "FREECOM", "PCCARD-IDE"
+  bind "ide_cs"
+
+card "Generic ATAPI CD-ROM"
+  version "PCMCIA", "CD-ROM"
+  bind "ide_cs"
+
+card "IBM Max Portable CD-ROM"
+  manfid 0x00a4, 0x002d
+  bind "ide_cs"
+
+card "IBM Portable Drive Bay"
+  version "PCMCIA", "IDE CARD", "F1"
+  bind "ide_cs"
+
+card "IO DATA CDP-TX/PCIDE"
+  version "IO DATA", "PCIDE"
+  bind "ide_cs"
+
+card "IO DATA PCIDE II"
+  version "IO DATA", "PCIDEII"
+  bind "ide_cs"
+
+card "IO DATA CBIDE"
+  version "WIT", "IDE16"
+  bind "ide_cs"
+
+card "MCD601p CD-ROM"
+  version "CDROM", "IDE", "MCD-601p"
+  bind "ide_cs"
+
+card "Ninja ATA"
+  version " ", "NinjaATA-"
+  bind "ide_cs"
+
+card "Simple Tech Compact Flash"
+  version "STI Flash"
+  bind "ide_cs"
+
+#
+# Non-ATA/IDE CD-ROM's
+#
+card "Innovative Communications CyberRom CD"
+  version "Innovative Communications", "CyberRom CD"
+  bind "oti12_cs"
+
+#
+# Miscellaneous card definitions
+#
+#card "Canon FDCard"
+#  version "Canon Electronics INC.", "FDCard Ver. 1.00"
+#
+#card "New Media .WAVjammer"
+#version "New Media Corporation", ".WAVjammer"
+
+card "IBM Smart Capture Card"
+  version "IBM Corp.", "Video Capture"
+  bind "iscc_cs"
+
+card "Parallel Port Card"
+  function parallel_port
+  bind "parport_cs"
+
+card "Quatech SPP-100 Parallel Port Card"
+  manfid 0x0137, 0x0003
+  bind "parport_cs"
+
+card "TELES S0/PC ISDN"
+  version "TELES", "S0/PC"
+  bind "teles_cs"
+
+#
+# CardBus cards
+#
+card "3Com 3c575-TX Fast EtherLink XL"
+  manfid 0x0101, 0x5057
+  bind "3c575_cb"
+
+card "3Com 3CCFE575B/3CXFE575B Fast EtherLink XL"
+  manfid 0x0101, 0x5157
+  bind "3c575_cb"
+
+card "3Com 3CCFE575CT/3CXFE575CT Fast EtherLink XL"
+  manfid 0x0101, 0x5257
+  bind "3c575_cb"
+
+card "3Com 3CCFEM656B w/Winmodem"
+  manfid 0x0102, 0x6560
+  bind "3c575_cb"
+
+card "3Com 3CCFEM656B w/Winmodem"
+  manfid 0x0102, 0x6562
+  bind "3c575_cb"
+
+card "3Com 3CCFEM656C w/Winmodem"
+  manfid 0x0102, 0x6564
+  bind "3c575_cb"
+
+card "Accton EN2220 Fast Ethernet"
+  version "Accton", "EN2220 CardBus Fast Ethernet Card"
+  bind "tulip_cb"
+
+card "Adaptec APA-1480 SCSI Host Adapter"
+  manfid 0x012f, 0xcb01
+  bind "apa1480_cb"
+
+#Conflicts with corega PCC-T!
+#card "Allied Telesyn AT-2800 10/100 Fast Ethernet"
+#  manfid 0xc00f, 0x0000
+#  bind "tulip_cb"
+
+card "Ambicom AMB8100 Fast Ethernet"
+  manfid 0x9513, 0x0081
+  bind "tulip_cb"
+
+card "Asante FriendlyNET 10/100 CardBus"
+  version "Asante", "FriendlyNET 10/100 CardBus"
+  bind "tulip_cb"
+
+card "D-Link DFE-660 Fast Ethernet"
+  manfid 0x50c7, 0xcafe
+  bind "tulip_cb"
+
+card "Genius MF3000 Fast Ethernet"
+  version "CardBus", "10/100Mbps LanCard"
+  bind "tulip_cb"
+
+card "IBM 10/100 EtherJet CardBus"
+  manfid 0x00a4, 0x0113
+  bind "tulip_cb"
+
+card "Intel EtherExpress PRO/100 CardBus Mobile Adapter32"
+  manfid 0x0089, 0x0102
+  bind "tulip_cb"
+
+card "Kingston KNE-CB4TX Fast Ethernet"
+  manfid 0x0186, 0x0101
+  bind "tulip_cb"
+
+card "Linksys EtherFast 10/100"
+  manfid 0x0149, 0x0231
+  bind "tulip_cb"
+
+card "Linksys EtherFast 10/100"
+  manfid 0x0149, 0xc2ab
+  bind "tulip_cb"
+
+card "NetGear FA510C Fast Ethernet"
+  manfid 0x9513, 0x0081
+  bind "tulip_cb"
+
+card "PLANET ENW-3502-FC"
+  version "PLANET", "ENW-3502-FC"
+  bind "tulip_cb"
+
+card "PrimeXPress 10/100 Fast Ethernet"
+  manfid 0x021b, 0x0510
+  bind "tulip_cb"
+
+card "SMC EZ 10/100 Fast Ethernet"
+  manfid 0x01bf, 0x2220
+  bind "tulip_cb"
+
+card "SMC EZ 10/100 Fast Ethernet"
+  manfid 0x01bf, 0x2225
+  bind "tulip_cb"
+
+#card "SVEC 10/100 Fast Ethernet"
+#  manfid 0x8a01, 0x0100
+#  bind "tulip_cb"
+
+card "TDK NetworkFlyer 10/100 Fast Ethernet"
+  manfid 0x0105, 0x0500
+  bind "tulip_cb"
+
+card "Tulip-based CardBus Fast Ethernet"
+  version "CardBus", "10/100Mbps LAN Card"
+  bind "tulip_cb"
+
+card "UMAX Technologies UMAX250 Fast Ethernet"
+  manfid 0x9513, 0x0081
+  bind "tulip_cb"
+
+card "Ositech Seven of Spades Fast Ethernet"
+  manfid 0x0140, 0x0011
+  bind "epic_cb"
+
+card "Ositech Jack of Spades Fast Ethernet/Modem"
+  manfid 0x0140, 0x000f
+  bind "epic_cb" to 0, "serial_cb" to 1
+
+card "Ositech Jack of Spades Fast Ethernet/Modem"
+  manfid 0x0140, 0x0012
+  bind "epic_cb" to 0, "serial_cb" to 1
+
+card "Psion Gold Card Netglobal 56K+10/100Mb CardBus"
+  manfid 0x016c, 0x0021
+  bind "epic_cb" to 0, "serial_cb" to 1
+
+card "Xircom CardBus 10/100 Ethernet"
+  version "Xircom", "*", "CBEII-10/100"
+  bind "tulip_cb"
+
+card "Xircom CardBus 10/100 Ethernet + 56K Modem"
+  version "Xircom", "*", "CBEM56G"
+  bind "tulip_cb" to 0, "serial_cb" to 1
+
+# Include configuration files for add-on drivers
+
+source ./*.conf
+
+# Include local configuration settings
+
+source ./config.opts
Index: oldkernel/linux/pcmcia-cs-3.1.15/etc/config.opts
diff -u /dev/null linux/pcmcia-cs-3.1.15/etc/config.opts:1.1
--- /dev/null	Mon Jul 31 21:15:11 2000
+++ linux/pcmcia-cs-3.1.15/etc/config.opts	Fri Jul  7 16:34:58 2000
@@ -0,0 +1,55 @@
+#
+# Local PCMCIA Configuration File
+#
+#----------------------------------------------------------------------
+
+# System resources available for PCMCIA devices
+
+include port 0x100-0x4ff, port 0x800-0x8ff, port 0xc00-0xcff
+include memory 0xc0000-0xfffff
+include memory 0xa0000000-0xa0ffffff, memory 0x60000000-0x60ffffff
+
+# High port numbers do not always work...
+# include port 0x1000-0x17ff
+
+# Extra port range for IBM Token Ring
+include port 0xa00-0xaff
+
+# Resources we should not use, even if they appear to be available
+
+# First built-in serial port
+exclude irq 4
+# Second built-in serial port
+#exclude irq 3
+# First built-in parallel port
+exclude irq 7
+# PS/2 Mouse controller port, comment this out if you don't have a PS/2
+# based mouse
+exclude irq 12
+
+#----------------------------------------------------------------------
+
+# Examples of options for loadable modules
+
+# To fix sluggish network with IBM ethernet adapter...
+#module "pcnet_cs" opts "mem_speed=600"
+
+# Options for IBM Token Ring adapters
+#module "ibmtr_cs" opts "mmiobase=0xd0000 srambase=0xd4000"
+
+# Options for Raylink/WebGear driver: uncomment only one line...
+# Generic ad-hoc network
+module "ray_cs" opts "pc_debug=1 essid=ADHOC_ESSID hop_dwell=128 beacon_period=256 translate=1"
+# Infrastructure network for older cards
+#module "ray_cs" opts "pc_debug=1 net_type=1 essid=ESSID1"
+# Infrastructure network for WebGear
+#module "ray_cs" opts "pc_debug=1 net_type=1 essid=ESSID1 translate=1 hop_dwell=128 beacon_period=256"
+
+# Options for WaveLAN/IEEE driver (AccessPoint mode)...
+#module "wvlan_cs" opts "station_name=MY_PC"
+# Options for WaveLAN/IEEE driver (ad-hoc mode)...
+#module "wvlan_cs" opts "port_type=3 channel=1 station_name=MY_PC"
+
+# Options for Xircom Netwave driver...
+#module "netwave_cs" opts "domain=0x100 scramble_key=0x0"
+
Index: oldkernel/linux/pcmcia-cs-3.1.15/etc/ftl
diff -u /dev/null linux/pcmcia-cs-3.1.15/etc/ftl:1.1
--- /dev/null	Mon Jul 31 21:15:11 2000
+++ linux/pcmcia-cs-3.1.15/etc/ftl	Fri Jul  7 16:34:58 2000
@@ -0,0 +1,61 @@
+#!/bin/sh
+#
+# ftl 1.23 2000/04/17 20:31:01 (David Hinds)
+#
+# Initialize or shutdown an FTL memory device
+#
+# The first argument should be the action to be performed, and the
+# second, the base name for the device.
+#
+# The script passes an extended device address to 'ftl.opts' in the 
+# ADDRESS variable, to retrieve device-specific configuration options.
+# The address format is "scheme,socket,instance" where "scheme" is the
+# current PCMCIA configuration scheme, "socket" is the socket number,
+# and "instance" is used to number multiple FTL regions on a single
+# card.
+#
+
+if [ -r ./shared ] ; then . ./shared ; else . /etc/pcmcia/shared ; fi
+
+# Get device attributes
+get_info $DEVICE
+
+# Load site-specific settings
+ADDRESS="$SCHEME,$SOCKET,$INSTANCE"
+. $0.opts
+
+case "$ACTION" in
+
+'start')
+    rm -f /dev/$DEVICE
+    mknod /dev/$DEVICE b $MAJOR $MINOR
+    mknod /dev/${DEVICE}p1 b $MAJOR `expr $MINOR + 1`
+    mknod /dev/${DEVICE}p2 b $MAJOR `expr $MINOR + 2`
+    mknod /dev/${DEVICE}p3 b $MAJOR `expr $MINOR + 3`
+    mknod /dev/${DEVICE}p4 b $MAJOR `expr $MINOR + 4`
+    add_parts /dev/$DEVICE "$PARTS" || exit 1
+    ;;
+
+'check')
+    fuser -s -m /dev/${DEVICE}* && exit 1
+    ;;
+
+'stop')
+    rm_parts /dev/$DEVICE "$PARTS"
+    rm -f /dev/$DEVICE /dev/${DEVICE}p[1-4]
+    ;;
+
+'cksum')
+    chk_parts "$NEW_SCHEME,$SOCKET,$INSTANCE" || exit 1
+    ;;
+    
+'suspend'|'resume')
+    ;;
+
+*)
+    usage
+    ;;
+
+esac
+
+exit 0
Index: oldkernel/linux/pcmcia-cs-3.1.15/etc/ftl.opts
diff -u /dev/null linux/pcmcia-cs-3.1.15/etc/ftl.opts:1.1
--- /dev/null	Mon Jul 31 21:15:11 2000
+++ linux/pcmcia-cs-3.1.15/etc/ftl.opts	Fri Jul  7 16:34:58 2000
@@ -0,0 +1,13 @@
+# FTL Device Configuration
+#
+# The address format is "scheme,socket,instance".
+#
+case "$ADDRESS" in
+*,*,*)
+    #INFO="Sample FTL setup"
+    #DO_FSTAB="y" ; DO_FSCK="y" ; DO_MOUNT="y"
+    #FSTYPE="ext2"
+    #OPTS=""
+    #MOUNTPT="/mnt/mem"
+    ;;
+esac
Index: oldkernel/linux/pcmcia-cs-3.1.15/etc/ide
diff -u /dev/null linux/pcmcia-cs-3.1.15/etc/ide:1.1
--- /dev/null	Mon Jul 31 21:15:11 2000
+++ linux/pcmcia-cs-3.1.15/etc/ide	Fri Jul  7 16:34:58 2000
@@ -0,0 +1,70 @@
+#!/bin/sh
+#
+# ide 1.11 2000/04/17 20:31:02 (David Hinds)
+#
+# Initialize or shutdown a PCMCIA ATA/IDE adapter
+#
+# The first argument should be either 'start' or 'stop'.  The second
+# argument is the base name for the device.
+#
+# The script passes an extended device address to 'ide.opts' in the
+# ADDRESS variable, to retrieve device-specific configuration options.
+# The address format is "scheme,socket,serial_no[,part]" where
+# "scheme" is the PCMCIA configuration scheme, "socket" is the socket
+# number, "serial_no" is the card's serial number if available, and
+# "part" is, optionally, the partition number.
+#
+# The script first calls ide.opts for the entire device.  If ide.opts
+# returns with the PARTS variable set, then this variable contains a
+# list of partitions for which options should be read.
+#
+
+if [ -r ./shared ] ; then . ./shared ; else . /etc/pcmcia/shared ; fi
+
+# Get device attributes
+get_info $DEVICE
+
+if [ ! -b /dev/$DEVICE ] ; then
+    mknod /dev/$DEVICE b $MAJOR 0
+    for minor in 1 2 3 4 5 6 7 8 ; do
+	mknod /dev/${DEVICE}$minor b $MAJOR $minor
+    done
+fi
+eval `/sbin/ide_info /dev/$DEVICE` || usage
+
+# Load site-specific settings
+ADDRESS="$SCHEME,$SOCKET,$SERIAL_NO"
+. $0.opts
+
+case "$ACTION" in
+
+'start')
+    add_parts "$ADDRESS" "$PARTS" || exit 1
+    ;;
+
+'check')
+    if [ -b /dev/$DEVICE ] ; then
+	fuser -s -m /dev/${DEVICE}* && exit 1
+    else
+	fuser -s /dev/${DEVICE}* && exit 1
+    fi
+    ;;
+
+'stop')
+    rm_parts "$ADDRESS" "$PARTS" || exit 1
+    ;;
+
+'cksum')
+    chk_parts "$NEW_SCHEME,$SOCKET,$SERIAL_NO" || exit 1
+    ;;
+    
+'suspend'|'resume')
+    ;;
+
+*)
+    usage
+    ;;
+
+esac
+
+exit 0
Index: oldkernel/linux/pcmcia-cs-3.1.15/etc/ide.opts
diff -u /dev/null linux/pcmcia-cs-3.1.15/etc/ide.opts:1.1
--- /dev/null	Mon Jul 31 21:15:11 2000
+++ linux/pcmcia-cs-3.1.15/etc/ide.opts	Fri Jul  7 16:34:58 2000
@@ -0,0 +1,19 @@
+# ATA/IDE drive adapter configuration
+#
+# The address format is "scheme,socket,serial_no[,part]".
+#
+# For multi-partition devices, first return list of partitions in
+# $PARTS.  Then, we'll get called for each partition.
+#
+case "$ADDRESS" in
+*,*,*,1)
+    #INFO="Sample IDE setup"
+    #DO_FSTAB="y" ; DO_FSCK="y" ; DO_MOUNT="y"
+    #FSTYPE="msdos"
+    #OPTS=""
+    #MOUNTPT="/mnt/ide"
+    ;;
+*,*,*)
+    #PARTS="1"
+    ;;
+esac
Index: oldkernel/linux/pcmcia-cs-3.1.15/etc/install-etc
diff -u /dev/null linux/pcmcia-cs-3.1.15/etc/install-etc:1.1
--- /dev/null	Mon Jul 31 21:15:11 2000
+++ linux/pcmcia-cs-3.1.15/etc/install-etc	Fri Jul  7 16:34:58 2000
@@ -0,0 +1,131 @@
+#!/bin/sh
+#
+# etc/install-etc 1.3 2000/05/15 19:28:10 (David Hinds)
+#
+# This handles updating the PCMCIA startup and device configuration
+# scripts.  I used to do this in the Makefile, but it is really much
+# more of a shell scripty thing.
+
+# Get configuration settings
+. ../config.out
+
+PROBE=../cardmgr/probe
+ETC=$PREFIX/etc/pcmcia
+
+install_clients ()
+{
+    echo "-> Updating client scripts in $ETC"
+    mkdir -p $ETC
+    CONF=*.conf
+    if [ "$CONF" != "*.conf" ] ; then
+	cp *.conf $ETC
+    fi
+    for f in *.opts ; do
+	b=`basename $f .opts`
+	cmp -s $b $ETC/$b && continue
+	[ -r $ETC/$b ] && mv $ETC/$b $ETC/$b.O
+	cp $b $ETC/$b
+	[ -r $ETC/$f ] || cp $f $ETC/$f
+    done
+    for f in shared ; do
+	cmp -s $f $ETC/$f && continue
+	[ -r $ETC/$f ] && mv $ETC/$f $ETC/$f.O
+	cp $f $ETC/$f
+    done
+}
+
+install_sysv ()
+{
+    SYSV=$PREFIX$RC_DIR/init.d/pcmcia
+
+     if [ -d /etc/sysconfig ] ; then
+	mkdir -p $PREFIX/etc/sysconfig
+	CFG=$PREFIX/etc/sysconfig/pcmcia
+	if [ -f $CFG ] ; then . $CFG ; fi
+	if [ "$PCMCIA" != "yes" ] ; then
+	    echo "-> Creating PCMCIA options file $CFG"
+	    echo PCMCIA=yes > $CFG
+	    PCIC=i82365
+	    if [ -x $PROBE ] ; then PCIC=`$PROBE -m` ; fi
+	    echo "PCIC=$PCIC" >> $CFG
+	    echo "PCIC_OPTS=" >> $CFG
+	    echo "CORE_OPTS=" >> $CFG
+	    echo "CARDMGR_OPTS=" >> $CFG
+	fi
+    fi
+
+    if ! cmp -s rc.pcmcia $SYSV ; then
+	if [ -e $SYSV ] ; then SYSV=$SYSV.N ; fi
+	echo "-> Installing PCMCIA startup script as $SYSV"
+	mkdir -p $PREFIX$RC_DIR/init.d
+	cp -f rc.pcmcia $SYSV
+	chmod +x $SYSV
+    fi
+
+    for RUN in 0 6 ; do
+	RC=$PREFIX$RC_DIR/rc$RUN.d
+	mkdir -p $RC
+	if [ ! -r $RC/*pcmcia ] ; then
+	    ln -vsf ../init.d/pcmcia $RC/K52pcmcia
+	fi
+    done
+    for RUN in 2 3 5 ; do
+	RC=$PREFIX$RC_DIR/rc$RUN.d
+	mkdir -p $RC
+	if [ ! -r $RC/*pcmcia ] ; then
+	    ln -vsf ../init.d/pcmcia $RC/S45pcmcia
+	fi
+    done
+}
+
+install_bsd ()
+{
+    BSD=$PREFIX/etc/rc.d/rc.pcmcia
+    if [ -e $BSD ] ; then BSD=$BSD.N ; fi
+
+    echo "-> Installing PCMCIA startup script as $BSD"
+    mkdir -p $PREFIX/etc/rc.d
+    if [ -x $PROBE ] ; then
+	PCIC=`$PROBE -m`
+	sed -e "s/=i82365/=$PCIC/" rc.pcmcia > $BSD
+    else
+	cp -f rc.pcmcia $BSD
+    fi
+    chmod +x $BSD
+}
+
+install_depmod ()
+{
+    CONF=$PREFIX/etc/modules.conf
+    if [ ! -r $CONF -a -r $PREFIX/etc/conf.modules ] ; then
+	CONF=$PREFIX/etc/conf.modules
+    fi
+    if ! modprobe -c | grep -q 'path\[pcmcia\]' ; then
+	echo "-> Updating $CONF"
+	grep -qs ^path $CONF || grep -qs ^keep $CONF ||
+	    echo keep >> $CONF
+	modprobe -c | sed -ne '/path/s/\[net\]/\[pcmcia\]/p' >> $CONF
+    fi
+    if [ -x /sbin/depmod -a "$PREFIX" = "" ] ; then
+	echo "-> Running depmod..."
+	depmod -a
+    else
+	echo "-> *NOT* running depmod.  Run depmod by hand if necessary."
+    fi
+}
+
+if [ "$SYSV_INIT" = "y" ] ; then
+    install_sysv
+else
+    install_bsd
+fi
+
+install_clients
+install_depmod
+
+# Directory to receive cardmgr's 'stab' socket status file
+if [ -d /var/state ] ; then
+    mkdir -p $PREFIX/var/state/pcmcia
+else
+    mkdir -p $PREFIX/var/lib/pcmcia
+fi
Index: oldkernel/linux/pcmcia-cs-3.1.15/etc/memory
diff -u /dev/null linux/pcmcia-cs-3.1.15/etc/memory:1.1
--- /dev/null	Mon Jul 31 21:15:11 2000
+++ linux/pcmcia-cs-3.1.15/etc/memory	Fri Jul  7 16:34:58 2000
@@ -0,0 +1,86 @@
+#!/bin/sh
+#
+# memory 1.26 2000/04/17 20:30:22 (David Hinds)
+#
+# Initialize or shutdown a PCMCIA memory device
+#
+# The first argument should be either 'start' or 'stop'.  The second
+# argument is the base name for the device.
+#
+# This script creates character devices for direct access to the PCMCIA
+# address spaces:
+#
+#	/dev/{name}c	- common memory direct access device
+#	/dev/{name}a	- attribute memory direct access device
+#
+# It also creates character and block devices for accessing the first
+# attribute and common memory partitions:
+#
+#       /dev/{name}c0c  - common memory, character device
+#       /dev/{name}c0b  - common memory, block device
+#       /dev/{name}a0c  - attribute memory, character device
+#
+# The script passes an extended device address to 'memory.opts' in the 
+# ADDRESS variable, to retrieve device-specific configuration options
+# for the common-memory block device.
+#
+# The address format is "scheme,socket" where "scheme" is the current
+# PCMCIA device configuration scheme, and "socket" is the socket number.
+#
+
+if [ -r ./shared ] ; then . ./shared ; else . /etc/pcmcia/shared ; fi
+
+# Get device attributes
+get_info $DEVICE
+
+# Load site-specific settings
+ADDRESS="$SCHEME,$SOCKET"
+. $0.opts
+
+case "$ACTION" in
+
+'start')
+    rm -f /dev/${DEVICE}*
+    if [ "$DRIVER" = "memory_cb" ] ; then
+	for N in 0 1 2 3 4 5 6 7 ; do
+	    mknod /dev/${DEVICE}s${N} c $MAJOR `expr $MINOR + $N`
+	done
+    else
+	mknod /dev/${DEVICE}c0c c $MAJOR `expr $MINOR`
+	mknod /dev/${DEVICE}c0b b $MAJOR `expr $MINOR`
+	mknod /dev/${DEVICE}a0c c $MAJOR `expr $MINOR + 4`
+	mknod /dev/${DEVICE}c c $MAJOR `expr $MINOR + 8`
+	mknod /dev/${DEVICE}a c $MAJOR `expr $MINOR + 8 + 4`
+	add_blkdev /dev/${DEVICE}c0b || exit 1
+    fi
+    ;;
+
+'check')
+    fuser -s /dev/${DEVICE}* && exit 1
+    if [ "$DRIVER" != "memory_cb" ] ; then
+	fuser -s -m /dev/${DEVICE}c0b && exit 1
+    fi
+    ;;
+
+'stop')
+    fuser -k /dev/${DEVICE}* > /dev/null
+    if [ "$DRIVER" != "memory_cb" ] ; then
+	rm_blkdev /dev/${DEVICE}c0b || exit 1
+    fi
+    rm -f /dev/${DEVICE}*
+    ;;
+
+'cksum')
+    chk_simple "$NEW_SCHEME,$SOCKET,$INSTANCE" || exit 1
+    ;;
+    
+'suspend'|'resume')
+    ;;
+
+*)
+    usage
+    ;;
+
+esac
+
+exit 0
Index: oldkernel/linux/pcmcia-cs-3.1.15/etc/memory.opts
diff -u /dev/null linux/pcmcia-cs-3.1.15/etc/memory.opts:1.1
--- /dev/null	Mon Jul 31 21:15:11 2000
+++ linux/pcmcia-cs-3.1.15/etc/memory.opts	Fri Jul  7 16:34:58 2000
@@ -0,0 +1,13 @@
+# Device configuration for memory cards
+#
+# The address format is "scheme,socket".
+#
+case "$ADDRESS" in
+*,*)
+    #INFO="Sample memory setup"
+    #DO_FSTAB="y" ; DO_FSCK="y" ; DO_MOUNT="y"
+    #FSTYPE="ext2"
+    #OPTS=""
+    #MOUNTPT="/mnt/mem"
+    ;;
+esac
Index: oldkernel/linux/pcmcia-cs-3.1.15/etc/network
diff -u /dev/null linux/pcmcia-cs-3.1.15/etc/network:1.1
--- /dev/null	Mon Jul 31 21:15:11 2000
+++ linux/pcmcia-cs-3.1.15/etc/network	Fri Jul  7 16:34:58 2000
@@ -0,0 +1,26 @@
+#! /bin/sh
+#
+# network.sample $Revision: 1.1 $ $Date: 2000/07/07 23:34:58 $ (David Hinds)
+#
+# Initialize or shutdown a PCMCIA ethernet adapter
+#
+# This script should be invoked with two arguments.  The first is the
+# action to be taken, either "start", "stop", or "restart".  The
+# second is the network interface name.
+
+action=$1
+device=$2
+
+case "${action:?}" in
+'start')
+	/etc/sysconfig/network-scripts/ifup ifcfg-${device}
+    ;;
+'stop')
+	/etc/sysconfig/network-scripts/ifdown ifcfg-${device}
+    ;;
+'restart')
+    /sbin/ifconfig ${device:?} down up
+    ;;
+esac
+
+exit 0
Index: oldkernel/linux/pcmcia-cs-3.1.15/etc/network.opts
diff -u /dev/null linux/pcmcia-cs-3.1.15/etc/network.opts:1.1
--- /dev/null	Mon Jul 31 21:15:11 2000
+++ linux/pcmcia-cs-3.1.15/etc/network.opts	Fri Jul  7 16:34:58 2000
@@ -0,0 +1,45 @@
+# Network adapter configuration
+#
+# The address format is "scheme,socket,instance,hwaddr".
+#
+# Note: the "network address" here is NOT the same as the IP address.
+# See the Networking HOWTO.  In short, the network address is the IP
+# address masked by the netmask.
+#
+case "$ADDRESS" in
+*,*,*,*)
+    INFO="Sample private network setup"
+    # Transceiver selection, for some cards -- see 'man ifport'
+    IF_PORT=""
+    # Use BOOTP (via /sbin/bootpc, or /sbin/pump)? [y/n]
+    BOOTP="n"
+    # Use DHCP (via /sbin/dhcpcd, /sbin/dhclient, or /sbin/pump)? [y/n]
+    DHCP="n"
+    # If you need to explicitly specify a hostname for DHCP requests
+    DHCP_HOSTNAME=""
+    # Host's IP address, netmask, network address, broadcast address
+    IPADDR=""
+    NETMASK="255.255.255.0"
+    NETWORK="10.0.1.0"
+    BROADCAST="10.0.1.255"
+    # Gateway address for static routing
+    GATEWAY="10.0.1.1"
+    # Things to add to /etc/resolv.conf for this interface
+    DOMAIN=""
+    SEARCH=""
+    DNS_1=""
+    DNS_2=""
+    DNS_3=""
+    # NFS mounts, should be listed in /etc/fstab
+    MOUNTS=""
+    # If you need to override the interface's MTU...
+    MTU=""
+    # For IPX interfaces, the frame type and network number
+    IPX_FRAME=""
+    IPX_NETNUM=""
+    # Extra stuff to do after setting up the interface
+    start_fn () { return; }
+    # Extra stuff to do before shutting down the interface
+    stop_fn () { return; }
+    ;;
+esac
Index: oldkernel/linux/pcmcia-cs-3.1.15/etc/network.orignal
diff -u /dev/null linux/pcmcia-cs-3.1.15/etc/network.orignal:1.1
--- /dev/null	Mon Jul 31 21:15:11 2000
+++ linux/pcmcia-cs-3.1.15/etc/network.orignal	Fri Jul  7 16:34:58 2000
@@ -0,0 +1,242 @@
+#! /bin/sh
+#
+# network 1.73 2000/04/29 01:39:15 (David Hinds)
+#
+# Initialize or shutdown a PCMCIA ethernet adapter
+#
+# This script should be invoked with two arguments.  The first is the
+# action to be taken, either "start", "stop", or "restart".  The
+# second is the network interface name.
+#
+# The script passes an extended device address to 'network.opts' in
+# the ADDRESS variable, to retrieve device-specific configuration
+# options.  The address format is "scheme,socket,instance,hwaddr"
+# where "scheme" is the current PCMCIA device configuration scheme,
+# "socket" is the socket number, "instance" is used to number multiple
+# interfaces in a single socket, and "hwaddr" is the card's hardware
+# ethernet address.
+#
+
+if [ -r ./shared ] ; then . ./shared ; else . /etc/pcmcia/shared ; fi
+
+# Get device attributes
+get_info $DEVICE
+HWADDR=`/sbin/ifconfig $DEVICE | sed -n -e 's/.*addr \([^ ]*\) */\1/p'`
+
+# Load site-specific settings
+ADDRESS="$SCHEME,$SOCKET,$INSTANCE,$HWADDR"
+start_fn () { return; }
+stop_fn () { return; }
+. $0.opts
+
+RESOLV=/etc/resolv.conf
+
+# Now, run the specific script for Wireless LAN interfaces
+# Note : we need the wireless parameters to be set up before IP parameters,
+# so that we can perform DHCP over the Wireless link if needed. Jean II
+if [ -x ./wireless ] ; then
+    . ./wireless
+else
+    . /etc/pcmcia/wireless
+fi
+
+match () { case $1 in $2) return 0; ;; *) return 1; ;; esac ; }
+bootp_setup ()
+{
+    if match `uname -r` "2.[2-9].*" ; then
+	/sbin/ifconfig $DEVICE up
+    else
+	/sbin/ifconfig $DEVICE up 0.0.0.0
+	/sbin/route add default dev $DEVICE netmask 0.0.0.0
+    fi
+}
+
+case "$ACTION" in
+
+'start')
+
+    test "$IF_PORT" && /sbin/ifport $DEVICE $IF_PORT
+
+    if is_true $PUMP ; then
+	/sbin/pump -i $DEVICE
+    elif is_true $BOOTP ; then
+	bootp_setup
+	if [ -x /sbin/bootpc ] ; then
+	    eval `/sbin/bootpc --bootfile '' --returniffail \
+		--timeoutwait 10 --dev $DEVICE`
+	    /sbin/ifconfig $DEVICE down
+	    if [ "$GATEWAYS" ] ; then
+		set - $GATEWAYS ; GATEWAY=$1
+	    fi
+	elif [ -x /sbin/pump ] ; then
+	    /sbin/pump -i $DEVICE
+	else
+	    exit 1
+	fi
+    elif is_true $DHCP ; then
+	bootp_setup
+	HN=${DHCP_HOSTNAME:+-h $DHCP_HOSTNAME}
+	if [ -x /sbin/dhcpcd ] ; then
+	    # This is a version check: I know it looks weird
+	    if /sbin/dhcpcd -XYZZY 2>&1 | grep -q DHCP ; then
+		/sbin/dhcpcd $DEVICE $HN >/dev/null 2>&1 || exit 1
+	    else
+		# Jump through hoops for lame 0.70-era dhcpcd
+		L=/var/run/dhcp-lock-$DEVICE
+		/bin/echo "#!/bin/sh\nrm $L" > $L ; chmod +x $L
+		/sbin/dhcpcd $HN -c $L $DEVICE >/dev/null 2>&1
+		for t in 0 1 2 3 4 5 6 7 8 9 ; do
+		    sleep 2 ; if [ ! -e $L ] ; then break ; fi
+		done
+		rm -f $L
+		if [ -e /etc/dhcpc/resolv.conf ] ; then
+		    echo "# $DEVICE begin" > $RESOLV.N
+		    cat /etc/dhcpc/resolv.conf >> $RESOLV.N
+		    echo "# $DEVICE end" >> $RESOLV.N
+		    cat $RESOLV >> $RESOLV.N ; mv $RESOLV.N $RESOLV
+		fi
+	    fi
+	elif [ -x /sbin/dhclient ] ; then
+	    /sbin/dhclient $DEVICE >/dev/null 2>&1 || exit 1
+	elif [ -x /sbin/pump ] ; then
+	    /sbin/pump $HN -i $DEVICE
+	else
+	    exit 1
+	fi
+    fi
+
+    if [ "$IPADDR" ] ; then
+	# Basic network setup
+	NM=${NETMASK:+netmask $NETMASK}
+	BC=${BROADCAST:+broadcast $BROADCAST}
+	MTU=${MTU:+mtu $MTU}
+	/sbin/ifconfig $DEVICE up $IPADDR $NM $BC $MTU
+	if [ "$NETWORK" ] ; then
+	    /sbin/ifuser $DEVICE $NETWORK || \
+		/sbin/route add -net $NETWORK $NM dev $DEVICE
+	elif [ "$GATEWAY" ] ; then
+	    /sbin/ifuser $DEVICE $GATEWAY || \
+		/sbin/route add $GATEWAY $DEVICE
+	fi
+	test "$GATEWAY" && /sbin/route add default gw $GATEWAY metric 1
+    fi
+    
+    # Update DNS stuff
+    if [ "$DOMAIN$SEARCH$DNSSRVS$DNS_1$DNS_2$DNS_3" ] ; then
+	echo "# $DEVICE begin" > $RESOLV.N
+	test "$DOMAIN" && echo "domain $DOMAIN" >> $RESOLV.N
+	test "$SEARCH" && echo "search $SEARCH" >> $RESOLV.N
+	for DNS in $DNSSRVS $DNS_1 $DNS_2 $DNS_3 ; do
+	    echo "nameserver $DNS" >> $RESOLV.N
+	done
+	echo "# $DEVICE end" >> $RESOLV.N
+	sed -e "/# $DEVICE begin/,/# $DEVICE end/d" $RESOLV >> $RESOLV.N
+	mv $RESOLV.N $RESOLV
+    fi
+
+    # Handle NFS mounts
+    if [ "$MOUNTS" ] ; then
+	for MT in $MOUNTS ; do mount -v $MT ; done
+    fi
+
+    if [ "$IPX_NETNUM" ] ; then
+	ipx_interface add $DEVICE $IPX_FRAME $IPX_NETNUM
+    fi
+
+    start_fn $DEVICE
+    ;;
+
+'stop')
+
+    stop_fn $DEVICE
+
+    if is_true $PUMP || is_true $BOOTP || is_true $DHCP || [ "$IPADDR" ] ; then
+
+	# Shut down all NFS mounts on this interface
+	nfsstop ()
+	{
+	    local HOST MT
+	    if read HOST MT ; then
+		nfsstop
+		if /sbin/ifuser $DEVICE $HOST ; then
+		    fuser -k -m $MT > /dev/null
+		    umount -v $MT
+		fi
+	    fi
+	}
+	mount -t nfs | sed -e 's/:.* on \(.*\) type .*/ \1/' | nfsstop
+
+	test "$IPX_NETNUM" && ipx_interface del $DEVICE $IPX_FRAME
+
+	# Remove nameservers
+	if fgrep -q "# $DEVICE begin" $RESOLV ; then
+	    sed -e "/# $DEVICE begin/,/# $DEVICE end/d"	$RESOLV > $RESOLV.N
+	    mv $RESOLV.N $RESOLV
+	fi
+
+	if is_true $PUMP ; then
+	    pump -r -i $DEVICE
+	elif is_true $DHCP ; then
+	    if [ -x /sbin/dhcpcd ] ; then
+		kill -TERM `cat /var/run/dhcpcd-$DEVICE.pid`
+		sleep 2
+		/sbin/dhcpcd -XYZZY 2>&1 | grep -q DHCP || \
+		    rm -f /var/run/dhcpcd-$DEVICE.pid
+	    elif [ -x /sbin/dhclient ] ; then
+		kill -TERM `cat /var/run/dhclient.pid`
+	    elif [ -x /sbin/pump ] ; then
+		/sbin/pump -r -i $DEVICE
+	    fi
+	fi
+    fi
+    /sbin/ifconfig $DEVICE down
+    ;;
+
+'check')
+    /sbin/ifconfig $DEVICE | grep -q RUNNING || exit 0
+
+    # Check for any in-use NFS mounts
+    nfscheck ()
+    {
+	while read HOST MT ; do
+	    /sbin/ifuser $DEVICE $HOST && fuser -sm $MT && exit 1
+	done
+    }
+    mount -t nfs | sed -e 's/:.* on \(.*\) type .*/ \1/' | nfscheck
+
+    # Check for active TCP or UDP connections
+    getdests ()
+    {
+    	IFS=" :" ; read A ; read A
+	while read A B C D E HOST PORT STATE ; do
+	    if [ "$STATE" != "FIN_WAIT1" -a "$STATE" != "FIN_WAIT2" \
+		-a "$STATE" != "CLOSE_WAIT" -a "$STATE" != "TIME_WAIT" \
+		-a "$HOST" != "127.0.0.1" -a "$HOST" != "0.0.0.0" \
+		-a "$PORT" != "*" ] ; then
+		echo $HOST
+	    fi
+	done
+    }
+    DESTS=`netstat -ntuw | getdests`
+    /sbin/ifuser $DEVICE $DESTS && exit 1
+    ;;
+
+'cksum')
+    if [ $WIRELESS = 1 ] ; then exit 1 ; fi
+    chk_simple "$NEW_SCHEME,$SOCKET,$INSTANCE,$HWADDR" || exit 1
+    ;;
+
+'restart')
+    test "$IPADDR" && /sbin/ifconfig $DEVICE down up
+    ;;
+
+'suspend'|'resume')
+    ;;
+
+*)
+    usage
+    ;;
+
+esac
+
+exit 0
Index: oldkernel/linux/pcmcia-cs-3.1.15/etc/parport
diff -u /dev/null linux/pcmcia-cs-3.1.15/etc/parport:1.1
--- /dev/null	Mon Jul 31 21:15:11 2000
+++ linux/pcmcia-cs-3.1.15/etc/parport	Fri Jul  7 16:34:58 2000
@@ -0,0 +1,73 @@
+#!/bin/sh
+#
+# serial 1.3 2000/04/17 20:30:22 (David Hinds)
+#
+# Initialize or shutdown a PCMCIA parallel device
+#
+# The first argument should be either 'start' or 'stop'.  The second
+# argument is the base name for the device.
+#
+# The script passes an extended device address to 'parallel.opts' in the
+# ADDRESS variable, to retrieve device-specific configuration options.
+# The address format is "scheme,socket,instance" where "scheme" is the
+# PCMCIA configuration scheme, "socket" is the socket number, and
+# "instance" is used to number multiple ports on a single card.  
+#
+
+if [ -r ./shared ] ; then . ./shared ; else . /etc/pcmcia/shared ; fi
+
+# Get device attributes
+get_info $DEVICE
+
+# Load site-specific settings
+ADDRESS="$SCHEME,$SOCKET,$INSTANCE"
+. $0.opts
+
+LP="lp$MINOR"
+
+case "$ACTION" in
+
+'start')
+    if [ ! -c /dev/$LP ] ; then
+	mknod /dev/$LP c $MAJOR $MINOR
+    fi
+    if [ "$LINK" ] ; then
+	mv -f $LINK $LINK.O 2>/dev/null
+	ln -s /dev/$DIALOUT $LINK
+    fi
+    if [ "$LP_OPTS" ] ; then
+	tunelp /dev/$LP $LP_OPTS
+    fi
+    ;;
+
+'check')
+    fuser -s /dev/$LP /dev/$LP $LINK && exit 1
+    ;;
+
+'cksum')
+    chk_simple "$NEW_SCHEME,$SOCKET,$INSTANCE" || exit 1
+    ;;
+    
+'stop')
+    fuser -k /dev/$LP $LINK > /dev/null
+    rm -f $LINK ; mv -f $LINK.O $LINK 2>/dev/null
+    ;;
+
+'suspend')
+    fuser -k -STOP /dev/$LP > /dev/null
+    ;;
+
+'resume')
+    if [ "$LP_OPTS" ] ; then
+	tunelp /dev/$LP $LP_OPTS
+    fi
+    fuser -k -CONT /dev/$LP $LINK > /dev/null
+    ;;
+
+*)
+    usage
+    ;;
+
+esac
+
+exit 0
Index: oldkernel/linux/pcmcia-cs-3.1.15/etc/parport.opts
diff -u /dev/null linux/pcmcia-cs-3.1.15/etc/parport.opts:1.1
--- /dev/null	Mon Jul 31 21:15:11 2000
+++ linux/pcmcia-cs-3.1.15/etc/parport.opts	Fri Jul  7 16:34:58 2000
@@ -0,0 +1,13 @@
+# Parallel device configuration
+#
+# The address format is "scheme,socket,instance".
+#
+case "$ADDRESS" in
+*,*,*)
+    #INFO="Sample parport setup"
+    # Symbolic link?
+    #LINK="/dev/printer"
+    # Options for 'tunelp'
+    #LP_OPTS=""
+    ;;
+esac
Index: oldkernel/linux/pcmcia-cs-3.1.15/etc/rc.pcmcia
diff -u /dev/null linux/pcmcia-cs-3.1.15/etc/rc.pcmcia:1.1
--- /dev/null	Mon Jul 31 21:15:11 2000
+++ linux/pcmcia-cs-3.1.15/etc/rc.pcmcia	Fri Jul  7 16:34:58 2000
@@ -0,0 +1,175 @@
+#!/bin/sh
+
+# rc.pcmcia 1.31 1999/12/11 03:59:04 (David Hinds)
+#
+# This is designed to work in BSD as well as SysV init setups.  See
+# the HOWTO for customization instructions.
+
+# Tags for Red Hat init configuration tools
+#
+# chkconfig: 2345 08 96
+# processname: cardmgr
+# pidfile: /var/run/cardmgr.pid
+# config: /etc/pcmcia/config
+# config: /etc/pcmcia/config.opts
+# description: PCMCIA support is usually to support things like ethernet \
+#              and modems in laptops.  It won't get started unless \
+#              configured so it is safe to have it installed on machines \
+#              that don't need it.
+
+# Allow environment variables to override all options
+if [ "$PCMCIA" ] ; then readonly PCMCIA ; fi
+if [ "$PCIC" ] ; then readonly PCIC ; fi
+if [ "$PCIC_OPTS" ] ; then readonly PCIC_OPTS ; fi
+if [ "$CORE_OPTS" ] ; then readonly CORE_OPTS ; fi
+if [ "$CARDMGR_OPTS" ] ; then readonly CARDMGR_OPTS ; fi
+if [ "$SCHEME" ] ; then readonly SCHEME ; fi
+
+# Source PCMCIA configuration, if available
+if [ -f /etc/pcmcia.conf ] ; then
+    # Debian startup option file
+    . /etc/pcmcia.conf
+elif [ -f /etc/sysconfig/pcmcia ] ; then
+    # Red Hat startup option file
+    . /etc/sysconfig/pcmcia
+else
+    # Slackware startup options go right here:
+    # Should be either i82365 or tcic
+    PCIC=i82365
+    # Put socket driver timing parameters here
+    PCIC_OPTS=
+    # Put pcmcia_core options here
+    CORE_OPTS=
+    # Put cardmgr options here
+    CARDMGR_OPTS=
+    # To set the PCMCIA scheme at startup...
+    SCHEME=
+fi
+if [ "$PCMCIA" -a "$PCMCIA" != "yes" ] ; then exit 0 ; fi
+
+usage()
+{
+    echo "Usage: $0 {start|stop|status|restart|reload}"
+}
+
+cleanup()
+{
+    while read SN CLASS MOD INST DEV EXTRA ; do
+	if [ "$SN" != "Socket" ] ; then
+	    /etc/pcmcia/$CLASS stop $DEV 2> /dev/null
+	fi
+    done
+}
+
+EXITCODE=1
+for x in "1" ; do
+
+    if [ "$PCIC" = "" ] ; then
+	echo "PCIC not defined in rc.pcmcia!"
+	break
+    fi
+
+    if [ $# -lt 1 ] ; then usage ; break ; fi
+    action=$1
+
+    case "$action" in
+
+    start)
+	echo -n "Starting PCMCIA services:"
+	if [ -d /var/state/pcmcia ] ; then
+	    SC=/var/state/pcmcia/scheme
+	    RUN=/var/state/pcmcia
+	elif [ -d /var/lib/pcmcia ] ; then
+	    SC=/var/lib/pcmcia/scheme
+	    RUN=/var/lib/pcmcia
+	else
+	    SC=/var/run/pcmcia-scheme
+	    RUN=/var/run
+	fi
+	if [ -L $SC -o ! -O $SC ] ; then rm -f $SC ; fi
+	if [ ! -f $SC ] ; then umask 022 ; touch $SC ; fi
+	if [ "$SCHEME" ] ; then umask 022 ; echo $SCHEME > $SC ; fi
+	fgrep -q pcmcia /proc/devices
+	if [ $? -ne 0 ] ; then
+	    if [ -d /lib/modules/preferred ] ; then
+		PC=/lib/modules/preferred/pcmcia
+	    else
+		PC=/lib/modules/`uname -r`/pcmcia
+	    fi
+	    if [ -d $PC ] ; then
+		echo -n " modules"
+		/sbin/insmod $PC/pcmcia_core.o $CORE_OPTS
+		/sbin/insmod $PC/$PCIC.o $PCIC_OPTS
+		/sbin/insmod $PC/ds.o
+	    else
+		echo " module directory $PC not found."
+		break
+	    fi
+	fi
+	if [ -s /var/run/cardmgr.pid ] && \
+	    kill -0 `cat /var/run/cardmgr.pid` 2>/dev/null ; then
+	    echo " cardmgr is already running."
+	else
+	    if [ -r $RUN/stab ] ; then
+		cat $RUN/stab | cleanup
+	    fi
+	    echo " cardmgr."
+	    /sbin/cardmgr $CARDMGR_OPTS
+	fi
+	if [ -d /var/lock/subsys ] ; then
+	    touch /var/lock/subsys/pcmcia
+	fi
+	;;
+
+    stop)
+	echo -n "Shutting down PCMCIA services:"
+	if [ -s /var/run/cardmgr.pid ] ; then
+	    PID=`cat /var/run/cardmgr.pid`
+	    kill $PID
+	    echo -n " cardmgr"
+	    # Give cardmgr a few seconds to handle the signal
+	    kill -0 $PID 2>/dev/null && sleep 2 && \
+	    kill -0 $PID 2>/dev/null && sleep 2 && \
+	    kill -0 $PID 2>/dev/null && sleep 2 && \
+	    kill -0 $PID 2>/dev/null
+	fi
+	if fgrep -q "ds  " /proc/modules ; then
+	    echo -n " modules"
+	    /sbin/rmmod ds
+	    /sbin/rmmod $PCIC
+	    /sbin/rmmod pcmcia_core
+	fi
+	echo "."
+	rm -f /var/lock/subsys/pcmcia
+	EXITCODE=0
+	;;
+
+    status)
+	pid=`pidof cardmgr`
+	if [ "$pid" != "" ] ; then
+	    echo "cardmgr (pid $pid) is running..."
+	    EXITCODE=0
+	else
+	    echo "cardmgr is stopped"
+	    EXITCODE=3
+	fi
+	;;
+
+    restart|reload)
+	$0 stop
+	$0 start
+	EXITCODE=$?
+	;;
+
+    *)
+	usage
+	;;
+
+    esac
+
+done
+
+# Only exit if we're in our own subshell
+if [ "${0##*/}" = "rc.pcmcia" ] ; then
+    exit $EXITCODE
+fi
Index: oldkernel/linux/pcmcia-cs-3.1.15/etc/scsi
diff -u /dev/null linux/pcmcia-cs-3.1.15/etc/scsi:1.1
--- /dev/null	Mon Jul 31 21:15:11 2000
+++ linux/pcmcia-cs-3.1.15/etc/scsi	Fri Jul  7 16:34:58 2000
@@ -0,0 +1,76 @@
+#!/bin/sh
+#
+# scsi 1.30 1997/05/13 02:18:00 (David Hinds)
+#
+# Initialize or shutdown a PCMCIA SCSI adapter
+#
+# The first argument should be either 'start' or 'stop'.  The second
+# argument is the base name for the device.
+#
+# The script passes an extended device address to 'scsi.opts' in the
+# ADDRESS variable, to retrieve device-specific configuration options.
+# The address format is "scheme,device,socket,channel,id,lun[,part]"
+# where "scheme" is the PCMCIA configuration scheme; "device" is the
+# SCSI device type (sd, sr, st, sg); "socket" is the socket number;
+# "channel", "id", and "lun" are the SCSI device ID's; and "part" is,
+# optionally, the partition number.
+#
+# The script first calls scsi.opts for the entire device.  If
+# scsi.opts returns with the PARTS variable set, then this variable
+# contains a list of partitions for which options should be read.
+#
+
+if [ -r ./shared ] ; then . ./shared ; else . /etc/pcmcia/shared ; fi
+
+# Get device attributes
+get_info $DEVICE
+
+case "$DEVICE" in
+sd*)  TYPE="sd" ;;
+st*)  TYPE="st" ;;
+scd*) TYPE="sr" ;;
+sg*)  TYPE="sg" ;;
+esac
+eval `/sbin/scsi_info /dev/$DEVICE` || usage
+
+# Load site-specific settings
+ADDRESS="$SCHEME,$TYPE,$SOCKET,$SCSI_ID"
+. $0.opts
+
+case "$ACTION" in
+
+'start')
+    add_parts $ADDRESS "$PARTS" || exit 1
+    ;;
+
+'stop')
+    if [ -b /dev/$DEVICE ] ; then
+	rm_parts $ADDRESS "$PARTS"
+    else
+	fuser -k /dev/$DEVICE > /dev/null
+    fi
+    exit $?
+    ;;
+
+'check')
+    if [ -b /dev/$DEVICE ] ; then
+	fuser -s -m /dev/${DEVICE}* && exit 1
+    elif [ -c /dev/$DEVICE ] ; then
+	fuser -s /dev/${DEVICE}* && exit 1
+    fi
+    ;;
+
+'cksum')
+    chk_parts "$NEW_SCHEME,$TYPE,$SOCKET,$SCSI_ID" || exit 1
+    ;;
+    
+'suspend'|'resume')
+    ;;
+
+*)
+    usage
+    ;;
+
+esac
+
+exit 0
Index: oldkernel/linux/pcmcia-cs-3.1.15/etc/scsi.opts
diff -u /dev/null linux/pcmcia-cs-3.1.15/etc/scsi.opts:1.1
--- /dev/null	Mon Jul 31 21:15:11 2000
+++ linux/pcmcia-cs-3.1.15/etc/scsi.opts	Fri Jul  7 16:34:58 2000
@@ -0,0 +1,19 @@
+# SCSI adapter configuration
+#
+# The address format is "scheme,type,socket,channel,id,lun[,part]".
+#
+# For multi-partition devices, first return list of partitions in
+# $PARTS.  Then, we'll get called for each partition.
+#
+# This example will mount any CD-ROM on /cdrom, if possible.
+#
+case "$ADDRESS" in
+*,sr,*,*,*,*)
+    INFO="Default CD-ROM setup"
+    PARTS=""
+    DO_FSTAB="y" ; DO_FSCK="n" ; DO_MOUNT="n"
+    FSTYPE="iso9660"
+    OPTS="ro,noauto"
+    MOUNTPT="/mnt/cdrom"
+    ;;
+esac
Index: oldkernel/linux/pcmcia-cs-3.1.15/etc/serial
diff -u /dev/null linux/pcmcia-cs-3.1.15/etc/serial:1.1
--- /dev/null	Mon Jul 31 21:15:11 2000
+++ linux/pcmcia-cs-3.1.15/etc/serial	Fri Jul  7 16:34:58 2000
@@ -0,0 +1,95 @@
+#!/bin/sh
+#
+# serial 1.34 2000/04/18 01:50:17 (David Hinds)
+#
+# Initialize or shutdown a PCMCIA serial device
+#
+# The first argument should be either 'start' or 'stop'.  The second
+# argument is the base name for the device.
+#
+# The script passes an extended device address to 'serial.opts' in the 
+# ADDRESS variable, to retrieve device-specific configuration options.
+# The address format is "scheme,socket,instance" where "scheme" is the
+# PCMCIA configuration scheme, "socket" is the socket number, and
+# "instance" is used to number multiple ports on a single card.  
+#
+
+if [ -r ./shared ] ; then . ./shared ; else . /etc/pcmcia/shared ; fi
+
+# Get device attributes
+get_info $DEVICE
+
+# Load site-specific settings
+ADDRESS="$SCHEME,$SOCKET,$INSTANCE"
+. $0.opts
+
+CALLOUT=$DEVICE
+
+case "$ACTION" in
+
+'start')
+    if [ ! -c /dev/$DEVICE ] ; then
+	cd /dev ; ./MAKEDEV $DEVICE
+    fi
+    if [ "$LINK" ] ; then
+	mv -f $LINK $LINK.O 2>/dev/null
+	if uname -r | grep -q '^2\.[2345]' ; then
+	    ln -s /dev/$DEVICE $LINK
+	else
+	    ln -s /dev/$CALLOUT $LINK
+	fi
+    fi
+    # Workaround for serial driver bug
+    IRQ=`setserial /dev/$DEVICE | sed -e 's/.*IRQ: //'`
+    setserial /dev/$DEVICE irq 0 ; setserial /dev/$DEVICE irq $IRQ
+    if [ "$SERIAL_OPTS" ] ; then
+	setserial /dev/$DEVICE irq 0
+	setserial /dev/$DEVICE $SERIAL_OPTS
+    fi
+    if [ "$INITTAB" ] ; then
+	echo "S$NR:12345:respawn:$INITTAB $DEVICE" >> /etc/inittab
+	telinit q
+    fi
+    ;;
+
+'check')
+    if [ "$INITTAB" ] ; then
+	fuser -v /dev/$DEVICE /dev/$CALLOUT $LINK | grep -v getty \
+	    | grep -q /dev/$DEVICE && exit 1
+    else
+	fuser -s /dev/$DEVICE /dev/$CALLOUT $LINK && exit 1
+    fi
+    ;;
+
+'cksum')
+    chk_simple "$NEW_SCHEME,$SOCKET,$INSTANCE" || exit 1
+    ;;
+    
+'stop')
+    if [ "$INITTAB" ] ; then
+	fgrep -v $DEVICE /etc/inittab > /etc/inittab.new
+	mv /etc/inittab.new /etc/inittab
+	telinit q
+    fi
+    fuser -k /dev/$DEVICE /dev/$CALLOUT $LINK > /dev/null
+    rm -f $LINK ; mv -f $LINK.O $LINK 2>/dev/null
+    ;;
+
+'suspend')
+    fuser -k -STOP /dev/$DEVICE /dev/$CALLOUT > /dev/null
+    ;;
+
+'resume')
+    if [ "$SERIAL_OPTS" ] ; then
+	setserial /dev/$DEVICE $SERIAL_OPTS
+    fi
+    fuser -k -CONT /dev/$DEVICE /dev/$CALLOUT $LINK > /dev/null
+    ;;
+
+*)
+    usage
+    ;;
+
+esac
+
+exit 0
Index: oldkernel/linux/pcmcia-cs-3.1.15/etc/serial.opts
diff -u /dev/null linux/pcmcia-cs-3.1.15/etc/serial.opts:1.1
--- /dev/null	Mon Jul 31 21:15:11 2000
+++ linux/pcmcia-cs-3.1.15/etc/serial.opts	Fri Jul  7 16:34:58 2000
@@ -0,0 +1,16 @@
+# Serial device configuration
+#
+# The address format is "scheme,socket,instance".
+#
+case "$ADDRESS" in
+*,*,*)
+    INFO="Default modem setup"
+    # Symbolic link to dialout device
+    LINK="/dev/modem"
+    # Options for 'setserial'
+    IRQ=`setserial -g /dev/$DEVICE | cut -f 7 -d ' ' -`
+    SERIAL_OPTS="irq $IRQ"
+    # Should we create an inittab entry for this port?
+    #INITTAB="/sbin/mgetty"
+    ;;
+esac
Index: oldkernel/linux/pcmcia-cs-3.1.15/etc/shared
diff -u /dev/null linux/pcmcia-cs-3.1.15/etc/shared:1.1
--- /dev/null	Mon Jul 31 21:15:11 2000
+++ linux/pcmcia-cs-3.1.15/etc/shared	Fri Jul  7 16:34:58 2000
@@ -0,0 +1,143 @@
+#
+# shared 1.18 2000/04/17 20:27:52 (David Hinds)
+#
+
+usage ()
+{
+    echo "usage: $0 [action] [device name]"
+    echo "  actions: start check stop suspend resume"
+    exit 1
+}
+
+is_true ()
+{
+    [ "$1" = "y" -o "$1" = "Y" -o "$1" = "yes" -o "$1" = "YES" ]
+}
+
+add_blkdev ()
+{
+    # usage: add_blkdev [device]
+    if [ "$LINK" ] ; then ln -s $1 $LINK || return 1 ; fi
+    if is_true $DO_FSTAB ; then
+	echo "$1 $MOUNTPT ${FSTYPE:-auto} ${OPTS:-defaults} 0 0" >> /etc/fstab
+    fi
+    if is_true $DO_FSCK ; then
+	/sbin/fsck -Ta $1 || return 1
+    fi
+    if is_true $DO_MOUNT ; then
+	O=${OPTS:+-o $OPTS} ; FS=${FSTYPE:+-t $FSTYPE}
+	mount -v $O $FS $1 $MOUNTPT || return 1
+    fi
+    return 0
+}
+
+add_parts ()
+{
+    # usage: add_parts [address] [parts]
+    RET=0
+    for PART in ${2:-""} ; do
+	# Get mount options for particular partitions
+	if [ "$PART" ] ; then
+	    ADDRESS="$1,$PART"
+	    unset DO_FSTAB DO_FSCK DO_MOUNT LINK
+	    . $0.opts
+	fi
+	add_blkdev /dev/$DEVICE$PART || RET=1
+    done
+    return $RET
+}
+
+rm_blkdev ()
+{
+    # usage: rm_blkdev [device]
+    test -b $1 || return 1
+    fuser -k -m $1 > /dev/null
+    if mount | fgrep -q "$1 on" ; then
+	umount -v $1 || return 1
+    fi
+    if is_true $DO_FSTAB ; then
+	fgrep -v $1 /etc/fstab > /etc/fstab.N
+	mv /etc/fstab.N /etc/fstab
+    fi
+}
+
+rm_parts ()
+{
+    # usage: rm_parts [address] [parts]
+    BLK=/dev/$DEVICE
+    test -b $BLK || return 1
+    for PART in ${2:-""} ; do
+	if [ "$PART" ] ; then
+	    ADDRESS="$1,$PART"
+	    unset DO_FSTAB DO_FSCK DO_MOUNT
+	    . $0.opts
+	fi
+	if is_true $DO_FSTAB ; then
+	    fgrep -v "$BLK$PART " /etc/fstab > /etc/fstab.N
+	    mv /etc/fstab.N /etc/fstab
+	fi
+    done
+    fuser -k -m /dev/${DEVICE}* > /dev/null
+    LIST=`mount | sed -ne "s+^\($BLK[0-9]*\) .*+\1+p"`
+    if [ "$LIST" ] ; then
+	for MT in $LIST ; do
+	    umount -v $MT || return 1
+	done
+    fi
+}
+
+chk_simple ()
+{
+    # usage: chk_simple [new-address]
+    ADDRESS=""
+    OLD=`set | grep -v '^OLD=' | md5sum`
+    ADDRESS="$1"
+    . $0.opts
+    ADDRESS=""
+    NEW=`set | grep -v '^OLD=' | md5sum`
+    [ "$OLD" = "$NEW" ]
+}
+
+chk_parts ()
+{
+    # usage: chk_parts [new-address]
+    OLD_ADDR="$ADDRESS"
+    chk_simple $1 || return 1
+    if [ ! "$PARTS" ] ; then return 0 ; fi
+    for PART in $PARTS ; do
+	ADDRESS="$OLD_ADDR,$PART"
+	. $0.opts
+	chk_simple "$1,$PART" || return 1
+    done
+}
+
+grep_stab ()
+{
+    # this should be cheaper than invoking "grep"
+    local CLASS DEV
+    while read SOCKET CLASS DRIVER INSTANCE DEV MAJOR MINOR ; do
+	if [ "$1" = "$DEV" ] ; then return 0 ; fi
+    done
+    return 1
+}
+
+get_info ()
+{
+    if [ -d /var/state/pcmcia ] ; then
+	SCHEME=`cat /var/state/pcmcia/scheme`
+	STAB=/var/state/pcmcia/stab
+    elif [ -d /var/lib/pcmcia ] ; then
+	SCHEME=`cat /var/lib/pcmcia/scheme`
+	STAB=/var/lib/pcmcia/stab
+    else
+	SCHEME=`cat /var/run/pcmcia-scheme`
+	STAB=/var/run/stab
+    fi
+    if [ ! "$SCHEME" ] ; then SCHEME="default" ; fi
+    grep_stab $1 < $STAB || usage
+}
+
+# A bit of stuff to do right away...
+
+if [ $# -lt 2 ] ; then usage ; fi
+ACTION=$1 ; DEVICE=$2 ; NEW_SCHEME=$3
Index: oldkernel/linux/pcmcia-cs-3.1.15/etc/wireless
diff -u /dev/null linux/pcmcia-cs-3.1.15/etc/wireless:1.1
--- /dev/null	Mon Jul 31 21:15:11 2000
+++ linux/pcmcia-cs-3.1.15/etc/wireless	Fri Jul  7 16:34:58 2000
@@ -0,0 +1,94 @@
+#!/bin/sh
+#
+# wireless network 1.63 2000/02/09 03:12:42 (David Hinds/Jean Tourrilhes)
+#
+# Specific configuration of a PCMCIA wireless LAN adapter
+#
+# This script is invoked automatically by the network script; it should
+# not be executed by hand.
+#
+# Note : it would be real cool to have the name of the driver as part
+# of the extended device address
+#
+
+# Load site-specific settings
+if [ -x ./wireless.opts ] ; then
+    . ./wireless.opts
+else
+    . /etc/pcmcia/wireless.opts
+fi
+
+# Find the path where wireless tools are installed
+for IWPATH in /usr/{bin,sbin} /usr/local/{bin,sbin} /sbin ; do
+    if [ -x $IWPATH/iwconfig ] ; then break ; fi
+done
+
+case "$ACTION" in
+
+'start')
+    # Set all desired settings via iwconfig
+
+    # Mode need to be first : some settings apply only in a specific mode !
+    if [ "$MODE" ] ; then
+	$IWPATH/iwconfig $DEVICE mode $MODE
+    fi
+    # This is a bit hackish, but should do the job right...
+    if [ "$ESSID" ] || [ "$MODE" ] ; then
+        NICKNAME=`/bin/hostname`
+	$IWPATH/iwconfig $DEVICE nick $NICKNAME >/dev/null 2>&1
+    fi
+    # Regular stuff...
+    if [ "$NWID" ] ; then
+	$IWPATH/iwconfig $DEVICE nwid $NWID
+    fi
+    if [ "$FREQ" ] ; then
+	$IWPATH/iwconfig $DEVICE freq $FREQ
+    elif [ "$CHANNEL" ] ; then
+	$IWPATH/iwconfig $DEVICE channel $CHANNEL
+    fi
+    if [ "$SENS" ] ; then
+	$IWPATH/iwconfig $DEVICE sens $SENS
+    fi
+    if [ "$RATE" ] ; then
+	$IWPATH/iwconfig $DEVICE rate $RATE
+    fi
+    if [ "$KEY" ] ; then
+	$IWPATH/iwconfig $DEVICE key $KEY
+    fi
+    if [ "$RTS" ] ; then
+	$IWPATH/iwconfig $DEVICE rts $RTS
+    fi
+    if [ "$FRAG" ] ; then
+	$IWPATH/iwconfig $DEVICE frag $FRAG
+    fi
+    # More specific parameters
+    if [ "$IWCONFIG" ] ; then
+	$IWPATH/iwconfig $DEVICE $IWCONFIG
+    fi
+    if [ "$IWSPY" ] ; then
+	$IWPATH/iwspy $DEVICE $IWSPY
+    fi
+    if [ "$IWPRIV" ] ; then
+	$IWPATH/iwpriv $DEVICE $IWPRIV
+    fi
+    # ESSID need to be last : most device re-perform the scanning/discovery
+    # when this is set, and things like encryption keys are better be
+    # defined if we want to discover the right set of APs/nodes.
+    if [ "$ESSID" ] ; then
+	$IWPATH/iwconfig $DEVICE essid "$ESSID"
+    fi
+    ;;
+
+'cksum')
+    chk_simple "$NEW_SCHEME,$SOCKET,$INSTANCE,$HWADDR"
+    WIRELESS=$?
+    ;;
+
+'stop'|'check'|'restart'|'suspend'|'resume')
+    ;;
+
+*)
+    usage
+    ;;
+
+esac
Index: oldkernel/linux/pcmcia-cs-3.1.15/etc/wireless.opts
diff -u /dev/null linux/pcmcia-cs-3.1.15/etc/wireless.opts:1.1
--- /dev/null	Mon Jul 31 21:15:11 2000
+++ linux/pcmcia-cs-3.1.15/etc/wireless.opts	Fri Jul  7 16:34:58 2000
@@ -0,0 +1,117 @@
+# Wireless LAN adapter configuration
+#
+# The address format is "scheme,socket,instance,hwaddr".
+#
+# Theory of operation : all the Wireless specific configuration is done
+# through the Wireless Extensions, so we will just call 'iwconfig' with
+# the right parameters defined below.
+# Of course, you need to have iwconfig installled on your system.
+# To download iwconfig, or for more info on Wireless Extensions :
+#	http://www.hpl.hp.com/personal/Jean_Tourrilhes/Linux/Tools.html
+#
+# Note : you don't need to fill all parameters, leave them blank, in most
+# cases the driver will initialise itself with sane defaults values or
+# automatically figure out the value... And not all drivers do support
+# all settings...
+#
+# Finally, send comments and flames to me, Jean Tourrilhes <jt@hpl.hp.com>
+#
+
+case "$ADDRESS" in
+
+# NOTE : Remove the following four lines to activate the samples below ...
+# --------- START SECTION TO REMOVE -----------
+*,*,*,*)
+    ;;
+# ---------- END SECTION TO REMOVE ------------
+
+# Here are a few examples with a few Wireless LANs supported...
+
+# Lucent Wavelan IEEE
+# Note : wvlan_cs driver only, and version 1.0.4+ for encryption support
+*,*,*,00:60:1D:*)
+    INFO="Wavelan IEEE example (Lucent default settings)"
+    ESSID="Wavelan Network"
+    MODE="Managed"
+    RATE="auto"
+    KEY="s:secu1"
+    ;;
+
+# Raytheon Raylink/WebGear Aviator2.4 (end with 8F or F1 !)
+# Note : driver version 1.70+ only
+*,*,*,00:00:8F:*)
+    INFO="Raylink/Aviator2.4 example (Aviator default ad-hoc setting)"
+    ESSID="ADHOC_ESSID"
+    MODE="Ad-Hoc"
+    RATE="auto"
+    IWPRIV="set_framing 1"
+    ;;
+
+# Old Lucent Wavelan
+*,*,*,08:00:0E:*)
+    INFO="Wavelan example (Lucent default settings)"
+    NWID="0100"
+    MODE="Ad-Hoc"
+    FREQ="2.425G"
+    KEY="off"
+    ;;
+
+# Netwave (Xircom Netwave/Netwave Airsurfer)
+*,*,*,00:80:C7:*)
+    INFO="Netwave example (Netwave default settings)"
+    NWID="100"
+    KEY="00"
+    ;;
+
+# Proxim RangeLan2/Symphony (what is the MAC address ???)
+*,*,*,XX:XX:XX:*)
+    INFO="Proxim RangeLan2/Symphony example"
+    NWID="0"
+    MODE="Master"
+    CHANNEL="15"
+    IWPRIV="setsubchan 1"
+    ;;
+
+# No Wires Needed Swallow 550 and 1100 setting (what is the MAC address ???)
+*,*,*,XX:XX:XX:*)
+    INFO="NWN Swallow example"
+    ESSID="session"
+    KEY="0000-0000-00 open"
+    ;;
+
+# Symbol Spectrum24 setting (what is the MAC address ???)
+*,*,*,XX:XX:XX:*)
+    INFO="Symbol Spectrum24 example"
+    ESSID="Essid string"
+    ;;
+
+# Generic example (decribe all possible settings)
+*,*,*,*)
+    INFO="Fill with your own settings..."
+    # ESSID (extended network name) : My Network, any
+    ESSID=""
+    # NWID/Domain (cell identifier) : 89AB, 100, off
+    NWID=""
+    # Operation mode : Ad-Hoc, Managed, Master, Repeater, Secondary, auto
+    MODE=""
+    # Frequency or channel : 1, 2, 3 (channel) ; 2.422G, 2.46G (frequency)
+    FREQ=""
+    CHANNEL=""
+    # Sensitivity (cell size + roaming speed) : 1, 2, 3 ; -70 (dBm)
+    SENS=""
+    # Bit rate : auto, 1M, 11M
+    RATE=""
+    # Encryption key : 4567-89AB-CD, s:password
+    KEY=""
+    # RTS threshold : off, 500
+    RTS=""
+    # Fragmentation threshold : off, 1000
+    FRAG=""
+    # Other iwconfig parameters : power off, ap 01:23:45:67:89:AB
+    IWCONFIG=""
+    # iwspy parameters : + 01:23:45:67:89:AB
+    IWSPY=""
+    # iwpriv parameters : set_port 2, set_histo 50 60
+    IWPRIV=""
+    ;;
+esac
Index: oldkernel/linux/pcmcia-cs-3.1.15/etc/cis/3CCFEM556.cis
diff -u /dev/null linux/pcmcia-cs-3.1.15/etc/cis/3CCFEM556.cis:1.1
--- /dev/null	Mon Jul 31 21:15:11 2000
+++ linux/pcmcia-cs-3.1.15/etc/cis/3CCFEM556.cis	Fri Jul  7 16:34:58 2000
@@ -0,0 +1,22 @@
+#
+# This card is MFC-compliant, but identifies itself as single function
+#
+vers_1 5.0, "3Com", "Megahertz 3CCFEM556", "LAN + 56k Modem"
+manfid 0x0101, 0x0556
+funcid 0
+
+mfc {
+  funcid network_adapter
+  config base 0x1000 mask 0x267 last_index 0x07
+  cftable_entry 0x07
+    Vcc Vnom 5V
+    irq mask 0xffff [level]
+    io  0x0000-0x000f [8bit] [16bit]
+}, {
+  funcid serial_port
+  config base 0x1100 mask 0x277 last_index 0x27
+  cftable_entry 0x27
+    Vcc Vnom 5V
+    irq mask 0xffff [level]
+    io  0x0000-0x0007 [8bit]
+}
Index: oldkernel/linux/pcmcia-cs-3.1.15/etc/cis/3CXEM556.cis
diff -u /dev/null linux/pcmcia-cs-3.1.15/etc/cis/3CXEM556.cis:1.1
--- /dev/null	Mon Jul 31 21:15:11 2000
+++ linux/pcmcia-cs-3.1.15/etc/cis/3CXEM556.cis	Fri Jul  7 16:34:58 2000
@@ -0,0 +1,22 @@
+#
+# This card is MFC-compliant, but identifies itself as single function
+#
+vers_1 5.0, "3Com", "Megahertz 3CXEM556", "LAN + 56k Modem"
+manfid 0x0101, 0x0035
+funcid 0
+
+mfc {
+  funcid network_adapter
+  config base 0x0800 mask 0x63 last_index 0x07
+  cftable_entry 0x07
+    Vcc Vnom 5V
+    irq mask 0xffff [level]
+    io  0x0000-0x000f [8bit] [16bit]
+}, {
+  funcid serial_port
+  config base 0x900 mask 0x63 last_index 0x27
+  cftable_entry 0x27
+    Vcc Vnom 5V
+    irq mask 0xffff [level]
+    io  0x0000-0x0007 [8bit]
+}
Index: oldkernel/linux/pcmcia-cs-3.1.15/etc/cis/COMpad.cis
diff -u /dev/null linux/pcmcia-cs-3.1.15/etc/cis/COMpad.cis:1.1
--- /dev/null	Mon Jul 31 21:15:11 2000
+++ linux/pcmcia-cs-3.1.15/etc/cis/COMpad.cis	Fri Jul  7 16:34:58 2000
@@ -0,0 +1,20 @@
+#
+# Replacement CIS for Advantech COMpad-32/85
+#
+dev_info
+  NULL 0ns, 512b
+vers_1 4.1, "ADVANTECH", "COMpad-32/85", "1.0"
+funcid serial_port [post]
+config base 0x0100 mask 0x0003 last_index 0x05
+cftable_entry 0x01 [default]
+  [mwait]
+  io 0x02e8-0x02ef, 0x03e8-0x03ef [lines=10] [8bit] [range]
+  irq mask 0x9eb8 [level]
+cftable_entry 0x02
+  io 0x0330-0x033f [lines=10] [8bit] [range]
+cftable_entry 0x03
+  io 0x0340-0x034f [lines=10] [8bit] [range]
+cftable_entry 0x04
+  io 0x0350-0x035f [lines=10] [8bit] [range]
+cftable_entry 0x05
+  io 0x0360-0x036f [lines=10] [8bit] [range]
Index: oldkernel/linux/pcmcia-cs-3.1.15/etc/cis/DP83903.cis
diff -u /dev/null linux/pcmcia-cs-3.1.15/etc/cis/DP83903.cis:1.1
--- /dev/null	Mon Jul 31 21:15:11 2000
+++ linux/pcmcia-cs-3.1.15/etc/cis/DP83903.cis	Fri Jul  7 16:34:58 2000
@@ -0,0 +1,24 @@
+#
+# This CIS is for cards based on the National Semiconductor
+# DP83903 Multiple Function Interface Chip
+#
+vers_1 4.1, "Multifunction Card", "", "", "NSC MF LAN/Modem"
+manfid 0x0175, 0x0000
+funcid 0
+
+mfc {
+  funcid network_adapter
+  config base 0x1020 mask 0x277 last_index 0x17
+  cftable_entry 0x17
+    Vcc Vnom 5V
+    irq mask 0xffff [level]
+    io  0x0000-0x001f [8bit] [16bit]
+    memory 0x0000-0x3fff @ 0x0000
+}, {
+  funcid serial_port
+  config base 0x1040 mask 0x0277 last_index 0x07
+  cftable_entry 0x07
+    Vcc Vnom 5V
+    irq mask 0xffff [level]
+    io  0x0000-0x0007 [8bit]
+}
Index: oldkernel/linux/pcmcia-cs-3.1.15/etc/cis/E-CARD.cis
diff -u /dev/null linux/pcmcia-cs-3.1.15/etc/cis/E-CARD.cis:1.1
--- /dev/null	Mon Jul 31 21:15:11 2000
+++ linux/pcmcia-cs-3.1.15/etc/cis/E-CARD.cis	Fri Jul  7 16:34:58 2000
@@ -0,0 +1,9 @@
+#
+# Replacement CIS for old, broken Linksys cards
+#
+vers_1 4.1, "LINKSYS", "E-CARD"
+config base 0x0008 mask 0x000b last_index 0x00
+cftable_entry 0x1 [default]
+  Vcc Vnom 5V
+  irq mask 0xffff [level]
+  io 0x0000-0x000f, 0x0010-0x001f [8bit] [16bit]
Index: oldkernel/linux/pcmcia-cs-3.1.15/etc/cis/LA-PCM.cis
diff -u /dev/null linux/pcmcia-cs-3.1.15/etc/cis/LA-PCM.cis:1.1
--- /dev/null	Mon Jul 31 21:15:11 2000
+++ linux/pcmcia-cs-3.1.15/etc/cis/LA-PCM.cis	Fri Jul  7 16:34:58 2000
@@ -0,0 +1,44 @@
+#
+# Replacement CIS for Allied Telesis LA-PCM
+#
+dev_info
+  fn_specific 100ns, 64kb
+  FLASH 150ns, 60kb
+attr_dev_info
+  FLASH 150ns, 4kb
+manfid 0xc00f, 0x0002
+funcid network_adapter [post] [rom]
+vers_1 4.1, "Allied Telesis,K.K", "Ethernet LAN Card", "CentreCOM", "LA-PCM"
+config base 0x20000 mask 0x000b last_index 0x10
+cftable_entry 0x01
+  io 0x0200-0x021f [8bit] [16bit]
+cftable_entry 0x02
+  io 0x0220-0x023f [8bit] [16bit]
+cftable_entry 0x03
+  io 0x0240-0x025f [8bit] [16bit]
+cftable_entry 0x04
+  io 0x0260-0x027f [8bit] [16bit]
+cftable_entry 0x05
+  io 0x0280-0x029f [8bit] [16bit]
+cftable_entry 0x06
+  io 0x02a0-0x02bf [8bit] [16bit]
+cftable_entry 0x07
+  io 0x02c0-0x02df [8bit] [16bit]
+cftable_entry 0x08
+  io 0x02e0-0x02ff [8bit] [16bit]
+cftable_entry 0x09
+  io 0x0300-0x031f [8bit] [16bit]
+cftable_entry 0x0a
+  io 0x0320-0x033f [8bit] [16bit]
+cftable_entry 0x0b
+  io 0x0340-0x035f [8bit] [16bit]
+cftable_entry 0x0c
+  io 0x0360-0x037f [8bit] [16bit]
+cftable_entry 0x0d
+  io 0x0380-0x039f [8bit] [16bit]
+cftable_entry 0x0e
+  io 0x03a0-0x03bf [8bit] [16bit]
+cftable_entry 0x0f
+  io 0x03c0-0x03df [8bit] [16bit]
+cftable_entry 0x10
+  io 0x03e0-0x03ff [8bit] [16bit]
Index: oldkernel/linux/pcmcia-cs-3.1.15/etc/cis/MT5634ZLX.cis
diff -u /dev/null linux/pcmcia-cs-3.1.15/etc/cis/MT5634ZLX.cis:1.1
--- /dev/null	Mon Jul 31 21:15:11 2000
+++ linux/pcmcia-cs-3.1.15/etc/cis/MT5634ZLX.cis	Fri Jul  7 16:34:58 2000
@@ -0,0 +1,18 @@
+#
+# Replacement CIS for Multitech MT5634ZLX modems
+#
+dev_info no_info
+vers_1 4.1, "MultiTech", "PCMCIA 56K DataFax"
+manfid 0x0200, 0x0001
+funcid serial_port
+config base 0xff80 mask 0x0067 last_index 0x27
+cftable_entry 0x0f [default]
+  [rdybsy] [audio] [pwrdown]
+  Vcc Vnom 5V Vpp1 Vnom 5V Vpp2 Vnom 5V
+  io 0x03f8-0x03ff [lines=10] [8bit]
+cftable_entry 0x17
+  io 0x02f8-0x02ff [lines=10] [8bit]
+cftable_entry 0x1f
+  io 0x03e8-0x03ef [lines=10] [8bit]
+cftable_entry 0x27
+  io 0x02e8-0x02ef [lines=10] [8bit]
Index: oldkernel/linux/pcmcia-cs-3.1.15/etc/cis/Makefile
diff -u /dev/null linux/pcmcia-cs-3.1.15/etc/cis/Makefile:1.1
--- /dev/null	Mon Jul 31 21:15:11 2000
+++ linux/pcmcia-cs-3.1.15/etc/cis/Makefile	Fri Jul  7 16:34:58 2000
@@ -0,0 +1,26 @@
+#
+# etc/cis/Makefile $Version$ 2000/04/29 02:00:58 (David Hinds)
+#
+
+# Include site dependent options
+include ../../config.mk
+
+ETC = $(PREFIX)/etc/pcmcia
+PACK = ../../debug-tools/pack_cis
+
+CIS = $(patsubst %.cis,%.dat,$(wildcard *.cis))
+
+all: $(CIS)
+
+dep:
+
+clean:
+	rm -f *.dat
+
+install: $(CIS)
+	@mkdir -p $(ETC)/cis
+	cp *.dat $(ETC)/cis
+
+.SUFFIXES: .dat .cis
+.cis.dat:
+	$(PACK) -o $@ $<
Index: oldkernel/linux/pcmcia-cs-3.1.15/etc/cis/NE2K.cis
diff -u /dev/null linux/pcmcia-cs-3.1.15/etc/cis/NE2K.cis:1.1
--- /dev/null	Mon Jul 31 21:15:11 2000
+++ linux/pcmcia-cs-3.1.15/etc/cis/NE2K.cis	Fri Jul  7 16:34:58 2000
@@ -0,0 +1,10 @@
+#
+# Replacement CIS for various busted NE2000-compatible cards
+#
+vers_1 4.1, "PCMCIA", "Ethernet"
+funcid network_adapter
+config base 0x03f8 mask 0x03 last_index 0x20
+cftable_entry 0x20 [default]
+  Vcc Vnom 5V
+  irq mask 0xffff [level]
+  io 0x0000-0x001f [8bit] [16bit]
Index: oldkernel/linux/pcmcia-cs-3.1.15/etc/cis/PCMLM28.cis
diff -u /dev/null linux/pcmcia-cs-3.1.15/etc/cis/PCMLM28.cis:1.1
--- /dev/null	Mon Jul 31 21:15:11 2000
+++ linux/pcmcia-cs-3.1.15/etc/cis/PCMLM28.cis	Fri Jul  7 16:34:58 2000
@@ -0,0 +1,37 @@
+#
+# The on-card CIS says it is MFC-compliant, but it is not
+#
+vers_1 4.1, "LINKSYS", "PCMLM28"
+manfid 0x0143, 0xc0ab
+funcid 0
+config base 0x03f8 mask 0x03 last_index 0x2f
+
+cftable_entry 0x24 [default]
+  Vcc Vnom 5V
+  irq mask 0xffff [level]
+  io 0x0300-0x031f, 0x02f8-0x02ff [8bit] [16bit]
+
+cftable_entry 0x25
+  io 0x0320-0x033f, 0x02f8-0x02ff [8bit] [16bit]
+cftable_entry 0x26
+  io 0x0340-0x035f, 0x02f8-0x02ff [8bit] [16bit]
+cftable_entry 0x27
+  io 0x0360-0x037f, 0x02f8-0x02ff [8bit] [16bit]
+
+cftable_entry 0x28
+  io 0x0300-0x031f, 0x03e8-0x03ef [8bit] [16bit]
+cftable_entry 0x29
+  io 0x0320-0x033f, 0x03e8-0x03ef [8bit] [16bit]
+cftable_entry 0x2a
+  io 0x0340-0x035f, 0x03e8-0x03ef [8bit] [16bit]
+cftable_entry 0x2b
+  io 0x0360-0x037f, 0x03e8-0x03ef [8bit] [16bit]
+
+cftable_entry 0x2c
+  io 0x0300-0x031f, 0x02e8-0x02ef [8bit] [16bit]
+cftable_entry 0x2d
+  io 0x0320-0x033f, 0x02e8-0x02ef [8bit] [16bit]
+cftable_entry 0x2e
+  io 0x0340-0x035f, 0x02e8-0x02ef [8bit] [16bit]
+cftable_entry 0x2f
+  io 0x0360-0x037f, 0x02e8-0x02ef [8bit] [16bit]
Index: oldkernel/linux/pcmcia-cs-3.1.15/etc/cis/PE-200.cis
diff -u /dev/null linux/pcmcia-cs-3.1.15/etc/cis/PE-200.cis:1.1
--- /dev/null	Mon Jul 31 21:15:11 2000
+++ linux/pcmcia-cs-3.1.15/etc/cis/PE-200.cis	Fri Jul  7 16:34:58 2000
@@ -0,0 +1,11 @@
+#
+# Replacement CIS for PE-200 ethernet card
+#
+vers_1 4.1, "PMX   ", "PE-200", "ETHERNET", "R01"
+funcid network_adapter [post] [rom]
+config base 0x0100 mask 0x0001 last_index 0x01
+cftable_entry 0x1 [default]
+  [mwait]
+  Vcc Vnom 5V
+  irq mask 0xffff [level]
+  io 0x0000-0x000f, 0x0010-0x001f [8bit] [16bit]
Index: oldkernel/linux/pcmcia-cs-3.1.15/etc/cis/PE520.cis
diff -u /dev/null linux/pcmcia-cs-3.1.15/etc/cis/PE520.cis:1.1
--- /dev/null	Mon Jul 31 21:15:11 2000
+++ linux/pcmcia-cs-3.1.15/etc/cis/PE520.cis	Fri Jul  7 16:34:58 2000
@@ -0,0 +1,11 @@
+#
+# Replacement CIS for LanPro EP-4000A ethernet card
+#
+vers_1 4.1, "KTI", "PE520 PLUS", "PCMCIA Ethernet"
+manfid 0x0161, 0x0010
+funcid network_adapter
+config base 0x0fd0 mask 0x0b last_index 0x01
+cftable_entry 0x01 [default]
+  Vcc Vnom 5V
+  irq mask 0xffff [level]
+  io 0x0000-0x001f [8bit] [16bit]
Index: oldkernel/linux/pcmcia-cs-3.1.15/etc/cis/RS-COM-2P.cis
diff -u /dev/null linux/pcmcia-cs-3.1.15/etc/cis/RS-COM-2P.cis:1.1
--- /dev/null	Mon Jul 31 21:15:11 2000
+++ linux/pcmcia-cs-3.1.15/etc/cis/RS-COM-2P.cis	Fri Jul  7 16:34:58 2000
@@ -0,0 +1,14 @@
+#
+# Replacement CIS for dual-serial-port IO card
+#
+vers_1 4.1, "PCMCIA", "RS-COM 2P"
+funcid serial_port [post]
+config base 0x0100 mask 0x0001 last_index 0x03
+cftable_entry 0x01 [default]
+  [mwait]
+  io 0x03e8-0x03ef, 0x02e8-0x02ef [lines=10] [8bit] [range]
+  irq mask 0x9eb8 [level]
+cftable_entry 0x02
+  io 0x0250-0x0257, 0x0258-0x025f [lines=10] [8bit] [range]
+cftable_entry 0x03
+  io 0x0260-0x0267, 0x0268-0x026f [lines=10] [8bit] [range]
Index: oldkernel/linux/pcmcia-cs-3.1.15/flash/Makefile
diff -u /dev/null linux/pcmcia-cs-3.1.15/flash/Makefile:1.1
--- /dev/null	Mon Jul 31 21:15:11 2000
+++ linux/pcmcia-cs-3.1.15/flash/Makefile	Fri Jul  7 16:34:58 2000
@@ -0,0 +1,28 @@
+#
+# flash/Makefile 1.16 2000/05/11 02:34:15 (David Hinds)
+#
+
+# Include site dependent options
+include ../config.mk
+
+CFLAGS = -O -Wall -Wstrict-prototypes -pipe
+CC += $(UFLAGS)
+
+SRCS  = ftl_format.c ftl_check.c
+TOOLS = ftl_format ftl_check
+
+all:	$(TOOLS)
+
+ftl_format: ftl_format.o
+
+ftl_check: ftl_check.o
+
+clean:
+	rm -f core core.* *.o *.s *.a *~ .depend .depfiles/*.d
+	rm -f $(TOOLS)
+
+install: $(TOOLS)
+	@mkdir -p $(PREFIX)/sbin
+	cp -f $(TOOLS) $(PREFIX)/sbin
+
+include ../rules.mk
Index: oldkernel/linux/pcmcia-cs-3.1.15/flash/ftl_check.c
diff -u /dev/null linux/pcmcia-cs-3.1.15/flash/ftl_check.c:1.1
--- /dev/null	Mon Jul 31 21:15:11 2000
+++ linux/pcmcia-cs-3.1.15/flash/ftl_check.c	Fri Jul  7 16:34:58 2000
@@ -0,0 +1,209 @@
+/*======================================================================
+
+    Utility to create an FTL partition in a memory region
+
+    ftl_check.c 1.10 1999/10/25 20:01: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@pcmcia.sourceforge.org>.  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 <sys/types.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <stddef.h>
+#include <string.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <sys/time.h>
+#include <sys/ioctl.h>
+#include <sys/stat.h>
+
+#include <pcmcia/cs_types.h>
+#include <pcmcia/bulkmem.h>
+#include <pcmcia/ftl.h>
+#include <pcmcia/memory.h>
+
+/*====================================================================*/
+
+static void print_size(u_int s)
+{
+    if ((s > 0x100000) && ((s % 0x100000) == 0))
+	printf("%d mb", s / 0x100000);
+    else if ((s > 0x400) && ((s % 0x400) == 0))
+	printf("%d kb", s / 0x400);
+    else
+	printf("%d bytes", s);
+}
+
+/*====================================================================*/
+
+static void check_partition(int fd, int verbose)
+{
+    region_info_t region;
+    erase_unit_header_t hdr, hdr2;
+    u_int i, j, nbam, *bam;
+    int control, data, free, deleted;
+    
+    /* Get partition size, block size */
+    if (ioctl(fd, MEMGETINFO, &region) != 0) {
+	perror("get info failed");
+	return;
+    }
+
+    printf("Memory region info:\n");
+    printf("  Card offset = 0x%x, region size = ", region.CardOffset);
+    print_size(region.RegionSize);
+    printf(", access speed = %u ns\n", region.AccessSpeed);
+    printf("  Erase block size = ");
+    print_size(region.BlockSize);
+    printf(", partition multiple = ");
+    print_size(region.PartMultiple);
+    printf("\n\n");
+
+    for (i = 0; i < region.RegionSize/region.BlockSize; i++) {
+	if (lseek(fd, (i * region.BlockSize), SEEK_SET) == -1) {
+	    perror("seek failed");
+	    break;
+	}
+	read(fd, &hdr, sizeof(hdr));
+	if ((hdr.FormattedSize > 0) &&
+	    (hdr.FormattedSize <= region.RegionSize) &&
+	    (hdr.NumEraseUnits > 0) &&
+	    (hdr.NumEraseUnits <= region.RegionSize/region.BlockSize))
+	    break;
+    }
+    if (i == region.RegionSize/region.BlockSize) {
+	fprintf(stderr, "No valid erase unit headers!\n");
+	return;
+    }
+    
+    printf("Partition header:\n");
+    printf("  Formatted size = ");
+    print_size(hdr.FormattedSize);
+    printf(", erase units = %d, transfer units = %d\n",
+	   hdr.NumEraseUnits, hdr.NumTransferUnits);
+    printf("  Erase unit size = ");
+    print_size(1 << hdr.EraseUnitSize);
+    printf(", virtual block size = ");
+    print_size(1 << hdr.BlockSize);
+    printf("\n");
+    
+    /* Create basic block allocation table for control blocks */
+    nbam = (region.BlockSize >> hdr.BlockSize);
+    bam = malloc(nbam * sizeof(u_int));
+
+    for (i = 0; i < hdr.NumEraseUnits; i++) {
+	if (lseek(fd, (i << hdr.EraseUnitSize), SEEK_SET) == -1) {
+	    perror("seek failed");
+	    break;
+	}
+	if (read(fd, &hdr2, sizeof(hdr2)) == -1) {
+	    perror("read failed");
+	    break;
+	}
+	printf("\nErase unit %d:\n", i);
+	if ((hdr2.FormattedSize != hdr.FormattedSize) ||
+	    (hdr2.NumEraseUnits != hdr.NumEraseUnits) ||
+	    (hdr2.SerialNumber != hdr.SerialNumber))
+	    printf("  Erase unit header is corrupt.\n");
+	else if (hdr2.LogicalEUN == 0xffff)
+	    printf("  Transfer unit, erase count = %d\n", hdr2.EraseCount);
+	else {
+	    printf("  Logical unit %d, erase count = %d\n",
+		   hdr2.LogicalEUN, hdr2.EraseCount);
+	    if (lseek(fd, (i << hdr.EraseUnitSize)+hdr.BAMOffset,
+		      SEEK_SET) == -1) {
+		perror("seek failed");
+		break;
+	    }
+	    if (read(fd, bam, nbam * sizeof(u_int)) == -1) {
+		perror("read failed");
+		break;
+	    }
+	    free = deleted = control = data = 0;
+	    for (j = 0; j < nbam; j++) {
+		if (BLOCK_FREE(bam[j]))
+		    free++;
+		else if (BLOCK_DELETED(bam[j]))
+		    deleted++;
+		else switch (BLOCK_TYPE(bam[j])) {
+		case BLOCK_CONTROL: control++; break;
+		case BLOCK_DATA: data++; break;
+		default: break;
+		}
+	    }
+	    printf("  Block allocation: %d control, %d data, %d free,"
+		   " %d deleted\n", control, data, free, deleted);
+	}
+    }
+} /* format_partition */
+
+/*====================================================================*/
+
+int main(int argc, char *argv[])
+{
+    int verbose;
+    int optch, errflg, fd;
+    struct stat buf;
+    
+    errflg = 0;
+    verbose = 0;
+    while ((optch = getopt(argc, argv, "v")) != -1) {
+	switch (optch) {
+	case 'v':
+	    verbose = 1; break;
+	default:
+	    errflg = 1; break;
+	}
+    }
+    if (errflg || (optind != argc-1)) {
+	fprintf(stderr, "usage: %s [-v] device\n", argv[0]);
+	exit(EXIT_FAILURE);
+    }
+
+    if (stat(argv[optind], &buf) != 0) {
+	perror("status check failed");
+	exit(EXIT_FAILURE);
+    }
+    if (!(buf.st_mode & S_IFCHR)) {
+	fprintf(stderr, "%s is not a character special device\n",
+		argv[optind]);
+	exit(EXIT_FAILURE);
+    }
+    fd = open(argv[optind], O_RDONLY);
+    if (fd == -1) {
+	perror("open failed");
+	exit(EXIT_FAILURE);
+    }
+
+    check_partition(fd, verbose);
+    close(fd);
+    
+    exit(EXIT_SUCCESS);
+    return 0;
+}
Index: oldkernel/linux/pcmcia-cs-3.1.15/flash/ftl_format.c
diff -u /dev/null linux/pcmcia-cs-3.1.15/flash/ftl_format.c:1.1
--- /dev/null	Mon Jul 31 21:15:11 2000
+++ linux/pcmcia-cs-3.1.15/flash/ftl_format.c	Fri Jul  7 16:34:58 2000
@@ -0,0 +1,320 @@
+/*======================================================================
+
+    Utility to create an FTL partition in a memory region
+
+    ftl_format.c 1.13 1999/10/25 20:01: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@pcmcia.sourceforge.org>.  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 <sys/types.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <stddef.h>
+#include <string.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <sys/time.h>
+#include <sys/ioctl.h>
+#include <sys/stat.h>
+
+#include <pcmcia/cs_types.h>
+#include <pcmcia/bulkmem.h>
+#include <pcmcia/ftl.h>
+#include <pcmcia/memory.h>
+
+/*====================================================================*/
+
+static void print_size(u_int s)
+{
+    if ((s > 0x100000) && ((s % 0x100000) == 0))
+	printf("%d mb", s / 0x100000);
+    else if ((s > 0x400) && ((s % 0x400) == 0))
+	printf("%d kb", s / 0x400);
+    else
+	printf("%d bytes", s);
+}
+
+/*====================================================================*/
+
+static const char LinkTarget[] = {
+    0x13, 0x03, 'C', 'I', 'S'
+};
+static const char DataOrg[] = {
+    0x46, 0x39, 0x00, 'F', 'T', 'L', '1', '0', '0', 0x00
+};
+
+static void build_header(erase_unit_header_t *hdr, u_int RegionSize,
+			 u_int BlockSize, u_int Spare, int Reserve,
+			 u_int BootSize)
+{
+    u_int i, BootUnits, nbam;
+    
+    /* Default everything to the erased state */
+    memset(hdr, 0xff, sizeof(*hdr));
+    memcpy(hdr->LinkTargetTuple, LinkTarget, 5);
+    memcpy(hdr->DataOrgTuple, DataOrg, 10);
+    hdr->EndTuple[0] = hdr->EndTuple[1] = 0xff;
+    BootSize = (BootSize + (BlockSize-1)) & ~(BlockSize-1);
+    BootUnits = BootSize / BlockSize;
+    
+    /* We only support 512-byte blocks */
+    hdr->BlockSize = 9;
+    hdr->EraseUnitSize = 0;
+    for (i = BlockSize; i > 1; i >>= 1)
+	hdr->EraseUnitSize++;
+    hdr->EraseCount = 0;
+    hdr->FirstPhysicalEUN = BootUnits;
+    hdr->NumEraseUnits = (RegionSize - BootSize) >> hdr->EraseUnitSize;
+    hdr->NumTransferUnits = Spare;
+    hdr->FormattedSize =
+	RegionSize - ((Spare + BootUnits) << hdr->EraseUnitSize);
+    /* Leave a little bit of space between the CIS and BAM */
+    hdr->BAMOffset = 0x80;
+    /* Adjust size to account for BAM space */
+    nbam = ((1 << (hdr->EraseUnitSize - hdr->BlockSize)) * sizeof(u_int)
+	    + hdr->BAMOffset + (1 << hdr->BlockSize) - 1) >> hdr->BlockSize;
+    hdr->FormattedSize -=
+	(hdr->NumEraseUnits - Spare) * (nbam << hdr->BlockSize);
+    hdr->FormattedSize -= ((hdr->FormattedSize * Reserve / 100) & ~0xfff);
+    hdr->FirstVMAddress = 0xffffffff;
+    hdr->NumVMPages = 0;
+    hdr->Flags = 0;
+    /* hdr->Code defaults to erased state */
+    hdr->SerialNumber = time(NULL);
+    /* hdr->AltEUHOffset defaults to erased state */
+
+} /* build_header */
+
+/*====================================================================*/
+
+static int format_partition(int fd, int quiet, int interrogate,
+			    u_int spare, int reserve, u_int bootsize)
+{
+    region_info_t region;
+    erase_info_t erase;
+    erase_unit_header_t hdr;
+    u_int step, lun, i, nbam, *bam;
+    
+    /* Get partition size, block size */
+    if (ioctl(fd, MEMGETINFO, &region) != 0) {
+	perror("get info failed");
+	return -1;
+    }
+
+    /* Intel Series 100 Flash: skip first block */
+    if ((region.JedecMfr == 0x89) && (region.JedecInfo == 0xaa) &&
+	(bootsize == 0)) {
+	if (!quiet)
+	    printf("Skipping first block to protect CIS info...\n");
+	bootsize = 1;
+    }
+    
+    /* Create header */
+    build_header(&hdr, region.RegionSize, region.BlockSize,
+		 spare, reserve, bootsize);
+
+    if (!quiet) {
+	printf("Partition size = ");
+	print_size(region.RegionSize);
+	printf(", erase unit size = ");
+	print_size(region.BlockSize);
+	printf(", %d transfer units\n", spare);
+	if (bootsize != 0) {
+	    print_size(hdr.FirstPhysicalEUN << hdr.EraseUnitSize);
+	    printf(" allocated for boot image\n");
+	}
+	printf("Reserved %d%%, formatted size = ", reserve);
+	print_size(hdr.FormattedSize);
+	printf("\n");
+	fflush(stdout);
+    }
+
+    if (interrogate) {
+	char str[3];
+	printf("This will destroy all data on the target device.  "
+	       "Confirm (y/n): ");
+	if (fgets(str, 3, stdin) == NULL)
+	    return -1;
+	if ((strcmp(str, "y\n") != 0) && (strcmp(str, "Y\n") != 0))
+	    return -1;
+    }
+    
+    /* Create basic block allocation table for control blocks */
+    nbam = ((region.BlockSize >> hdr.BlockSize) * sizeof(u_int)
+	    + hdr.BAMOffset + (1 << hdr.BlockSize) - 1) >> hdr.BlockSize;
+    bam = malloc(nbam * sizeof(u_int));
+    for (i = 0; i < nbam; i++)
+	bam[i] = BLOCK_CONTROL;
+    
+    /* Erase partition */
+    if (!quiet) {
+	printf("Erasing all blocks...\n");
+	fflush(stdout);
+    }
+    erase.Size = region.BlockSize;
+    erase.Offset = region.BlockSize * hdr.FirstPhysicalEUN;
+    for (i = 0; i < hdr.NumEraseUnits; i++) {
+	if (ioctl(fd, MEMERASE, &erase) != 0) {
+	    if (!quiet) {
+		putchar('\n');
+		fflush(stdout);
+	    }
+	    perror("block erase failed");
+	    return -1;
+	}
+	erase.Offset += erase.Size;
+	if (!quiet) {
+	    if (region.RegionSize <= 0x800000) {
+		if (erase.Offset % 0x100000) {
+		    if (!(erase.Offset % 0x20000)) putchar('-');
+		}
+		else putchar('+');
+	    }
+	    else {
+		if (erase.Offset % 0x800000) {
+		    if (!(erase.Offset % 0x100000)) putchar('+');
+		}
+		else putchar('*');
+	    }
+	    fflush(stdout);
+	}
+    }
+    if (!quiet) putchar('\n');
+
+    /* Prepare erase units */
+    if (!quiet) {
+	printf("Writing erase unit headers...\n");
+	fflush(stdout);
+    }
+    lun = 0;
+    /* Distribute transfer units over the entire region */
+    step = (spare) ? (hdr.NumEraseUnits/spare) : (hdr.NumEraseUnits+1);
+    for (i = 0; i < hdr.NumEraseUnits; i++) {
+	u_int ofs = (i + hdr.FirstPhysicalEUN) << hdr.EraseUnitSize;
+	if (lseek(fd, ofs, SEEK_SET) == -1) {
+	    perror("seek failed");
+	    break;
+	}
+	/* Is this a transfer unit? */
+	if (((i+1) % step) == 0)
+	    hdr.LogicalEUN = 0xffff;
+	else {
+	    hdr.LogicalEUN = lun;
+	    lun++;
+	}
+	if (write(fd, &hdr, sizeof(hdr)) == -1) {
+	    perror("write failed");
+	    break;
+	}
+	if (lseek(fd, ofs + hdr.BAMOffset, SEEK_SET) == -1) {
+	    perror("seek failed");
+	    break;
+	}
+	if (write(fd, bam, nbam * sizeof(u_int)) == -1) {
+	    perror("write failed");
+	    break;
+	}
+    }
+    if (i < hdr.NumEraseUnits)
+	return -1;
+    else
+	return 0;
+} /* format_partition */
+
+/*====================================================================*/
+
+int main(int argc, char *argv[])
+{
+    int quiet, interrogate, reserve;
+    int optch, errflg, fd, ret;
+    u_int spare, bootsize;
+    char *s;
+    extern char *optarg;
+    struct stat buf;
+
+    quiet = 0;
+    interrogate = 0;
+    spare = 1;
+    reserve = 5;
+    errflg = 0;
+    bootsize = 0;
+    
+    while ((optch = getopt(argc, argv, "qir:s:b:")) != -1) {
+	switch (optch) {
+	case 'q':
+	    quiet = 1; break;
+	case 'i':
+	    interrogate = 1; break;
+	case 's':
+	    spare = strtoul(optarg, NULL, 0); break;
+	case 'r':
+	    reserve = strtoul(optarg, NULL, 0); break;
+	case 'b':
+	    bootsize = strtoul(optarg, &s, 0);
+	    if ((*s == 'k') || (*s == 'K'))
+		bootsize *= 1024;
+	    break;
+	default:
+	    errflg = 1; break;
+	}
+    }
+    if (errflg || (optind != argc-1)) {
+	fprintf(stderr, "usage: %s [-q] [-i] [-s spare-blocks]"
+		" [-r reserve-percent] [-b bootsize] device\n", argv[0]);
+	exit(EXIT_FAILURE);
+    }
+
+    if (stat(argv[optind], &buf) != 0) {
+	perror("status check failed");
+	exit(EXIT_FAILURE);
+    }
+    if (!(buf.st_mode & S_IFCHR)) {
+	fprintf(stderr, "%s is not a character special device\n",
+		argv[optind]);
+	exit(EXIT_FAILURE);
+    }
+    fd = open(argv[optind], O_RDWR);
+    if (fd == -1) {
+	perror("open failed");
+	exit(EXIT_FAILURE);
+    }
+
+    ret = format_partition(fd, quiet, interrogate, spare, reserve,
+			   bootsize);
+    if (!quiet) {
+	if (ret)
+	    printf("format failed.\n");
+	else
+	    printf("format successful.\n");
+    }
+    close(fd);
+    
+    exit((ret) ? EXIT_FAILURE : EXIT_SUCCESS);
+    return 0;
+}
Index: oldkernel/linux/pcmcia-cs-3.1.15/include/asm/uaccess.h
diff -u /dev/null linux/pcmcia-cs-3.1.15/include/asm/uaccess.h:1.1
--- /dev/null	Mon Jul 31 21:15:11 2000
+++ linux/pcmcia-cs-3.1.15/include/asm/uaccess.h	Fri Jul  7 16:34:58 2000
@@ -0,0 +1,55 @@
+#ifndef _PCMCIA_UACCESS_H
+#define _PCMCIA_UACCESS_H
+
+#include <linux/version.h>
+#ifndef VERSION
+#define VERSION(a,b,c) (((a)<<16) + ((b)<<8) + (c))
+#endif
+
+#if (LINUX_VERSION_CODE < VERSION(2,1,0))
+#include <linux/mm.h>
+static inline u_long copy_from_user(void *to, const void *from, u_long n)
+{
+    int i;
+    if ((i = verify_area(VERIFY_READ, from, n)) != 0)
+	return i;
+    memcpy_fromfs(to, from, n);
+    return 0;
+}
+static inline u_long copy_to_user(void *to, const void *from, u_long n)
+{
+    int i;
+    if ((i = verify_area(VERIFY_WRITE, to, n)) != 0)
+	return i;
+    memcpy_tofs(to, from, n);
+    return 0;
+}
+
+#if (!defined(__alpha__) || (LINUX_VERSION_CODE < VERSION(2,0,34)))
+#define ioremap(a,b) \
+    (((a) < 0x100000) ? (void *)((u_long)(a)) : vremap(a,b))
+#define iounmap(v) \
+    do { if ((u_long)(v) > 0x100000) vfree(v); } while (0)
+#endif
+/* This is evil... throw away the built-in get_user in 2.0 */
+#include <asm/segment.h>
+#undef get_user
+
+#ifdef __alpha__
+#define get_user(x, ptr) 	((x) = __get_user((ptr), sizeof(*(ptr))))
+#undef get_fs_long
+#undef put_fs_long
+#define get_fs_long(ptr)	__get_user((ptr), sizeof(int))
+#define put_fs_long(x, ptr)	__put_user((x), (ptr), sizeof(int))
+#else
+#define get_user(x, ptr) \
+		((sizeof(*ptr) == 4) ? (x = get_fs_long(ptr)) : \
+		 (sizeof(*ptr) == 2) ? (x = get_fs_word(ptr)) : \
+		 (x = get_fs_byte(ptr)))
+#endif
+
+#else /* 2.1.X */
+#include_next <asm/uaccess.h>
+#endif
+
+#endif /* _PCMCIA_UACCESS_H */
Index: oldkernel/linux/pcmcia-cs-3.1.15/include/linux/ibmtr.h
diff -u /dev/null linux/pcmcia-cs-3.1.15/include/linux/ibmtr.h:1.1
--- /dev/null	Mon Jul 31 21:15:11 2000
+++ linux/pcmcia-cs-3.1.15/include/linux/ibmtr.h	Fri Jul  7 16:34:58 2000
@@ -0,0 +1,10 @@
+#ifndef _COMPAT_IBMTR_H
+#define _COMPAT_IBMTR_H
+
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,3,21))
+#include <../drivers/net/tokenring/ibmtr.h>
+#else
+#include <../drivers/net/ibmtr.h>
+#endif
+
+#endif /* _COMPAT_IBMTR_H */
Index: oldkernel/linux/pcmcia-cs-3.1.15/include/linux/init.h
diff -u /dev/null linux/pcmcia-cs-3.1.15/include/linux/init.h:1.1
--- /dev/null	Mon Jul 31 21:15:11 2000
+++ linux/pcmcia-cs-3.1.15/include/linux/init.h	Fri Jul  7 16:34:58 2000
@@ -0,0 +1,17 @@
+#ifndef _COMPAT_INIT_H
+#define _COMPAT_INIT_H
+
+#include <linux/version.h>
+
+#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,3,0)) && defined(MODULE)
+#define __init
+#define __initdata
+#define __exit
+#define __exitdata
+#define module_init(x) int init_module(void) { return x(); }
+#define module_exit(x) void cleanup_module(void) { x(); }
+#else
+#include_next <linux/init.h>
+#endif
+
+#endif /* _COMPAT_INIT_H */
Index: oldkernel/linux/pcmcia-cs-3.1.15/include/linux/pci.h
diff -u /dev/null linux/pcmcia-cs-3.1.15/include/linux/pci.h:1.1
--- /dev/null	Mon Jul 31 21:15:11 2000
+++ linux/pcmcia-cs-3.1.15/include/linux/pci.h	Fri Jul  7 16:34:58 2000
@@ -0,0 +1,49 @@
+#ifndef _COMPAT_PCI_H
+#define _COMPAT_PCI_H
+
+#include_next <linux/pci.h>
+#include <linux/version.h>
+
+#ifndef PCI_FUNC
+#define PCI_FUNC(devfn)		((devfn)&7)
+#define PCI_SLOT(devfn)		((devfn)>>3)
+#define PCI_DEVFN(dev,fn)	(((dev)<<3)|((fn)&7))
+#endif
+
+#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,1,0))
+extern struct pci_dev *pci_devices;
+extern struct pci_bus pci_root;
+#endif
+
+#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,1,93))
+
+#include <linux/bios32.h>
+#include <linux/types.h>
+
+extern struct pci_dev *pci_find_slot(u_int bus, u_int devfn);
+extern struct pci_dev *pci_find_class(u_int class, struct pci_dev *from);
+
+#define pci_fn(x, sz, t) \
+    static inline int pci_##x##_config_##sz(struct pci_dev *d, u8 w, t v) \
+    { return pcibios_##x##_config_##sz(d->bus->number, d->devfn, w, v); }
+pci_fn(read, byte, u8 *)
+pci_fn(read, word, u16 *)
+pci_fn(read, dword, u32 *)
+pci_fn(write, byte, u8)
+pci_fn(write, word, u16)
+pci_fn(write, dword, u32)
+
+#endif
+
+#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,3,24))
+extern int pci_enable_device(struct pci_dev *dev);
+extern int pci_set_power_state(struct pci_dev *dev, int state);
+#endif
+
+#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,3,40))
+#define pci_for_each_dev(p) for (p = pci_devices; p; p = p->next)
+#endif
+
+extern u32 pci_irq_mask;
+
+#endif /* _COMPAT_PCI_H */
Index: oldkernel/linux/pcmcia-cs-3.1.15/include/linux/pm.h
diff -u /dev/null linux/pcmcia-cs-3.1.15/include/linux/pm.h:1.1
--- /dev/null	Mon Jul 31 21:15:11 2000
+++ linux/pcmcia-cs-3.1.15/include/linux/pm.h	Fri Jul  7 16:34:58 2000
@@ -0,0 +1,23 @@
+#ifndef _COMPAT_PM_H
+#define _COMPAT_PM_H
+
+#include <linux/version.h>
+
+#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,3,43))
+
+#include <linux/apm_bios.h>
+
+/* This is an ugly hack: it only works in case statements */
+#define PM_SUSPEND		APM_SYS_SUSPEND: case APM_USER_SUSPEND
+#define PM_RESUME		APM_NORMAL_RESUME: case APM_CRITICAL_RESUME
+
+#define pm_register(a, b, fn)	apm_register_callback(fn)
+#define pm_unregister_all(fn)	apm_unregister_callback(fn)
+
+#else
+
+#include_next <linux/pm.h>
+
+#endif
+
+#endif /* _COMPAT_PM_H */
Index: oldkernel/linux/pcmcia-cs-3.1.15/include/linux/pnp_bios.h
diff -u /dev/null linux/pcmcia-cs-3.1.15/include/linux/pnp_bios.h:1.1
--- /dev/null	Mon Jul 31 21:15:11 2000
+++ linux/pcmcia-cs-3.1.15/include/linux/pnp_bios.h	Fri Jul  7 16:34:58 2000
@@ -0,0 +1,127 @@
+/*
+ * Include file for the interface to a PnP BIOS
+ *
+ * Original BIOS code (C) 1998 Christian Schmidt (chr.schmidt@tu-bs.de)
+ * PnP handler parts (c) 1998 Tom Lees <tom@lpsg.demon.co.uk>
+ * Minor reorganizations by David Hinds <dhinds@zen.stanford.edu>
+ *
+ * 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, 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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ * $Original Id: pnp-bios.h,v 0.1 1998/03/19 23:00:00 cs Exp $
+ * pnp_bios.h,v 1.1 1999/08/04 15:56:03 root Exp
+ */
+
+#ifndef _LINUX_PNP_BIOS_H
+#define _LINUX_PNP_BIOS_H
+
+/*
+ * Status codes (warnings and errors)
+ */
+#define PNP_SUCCESS                     0x00
+#define PNP_NOT_SET_STATICALLY          0x7f
+#define PNP_UNKNOWN_FUNCTION            0x81
+#define PNP_FUNCTION_NOT_SUPPORTED      0x82
+#define PNP_INVALID_HANDLE              0x83
+#define PNP_BAD_PARAMETER               0x84
+#define PNP_SET_FAILED                  0x85
+#define PNP_EVENTS_NOT_PENDING          0x86
+#define PNP_SYSTEM_NOT_DOCKED           0x87
+#define PNP_NO_ISA_PNP_CARDS            0x88
+#define PNP_UNABLE_TO_DETERMINE_DOCK_CAPABILITIES 0x89
+#define PNP_CONFIG_CHANGE_FAILED_NO_BATTERY 0x8a
+#define PNP_CONFIG_CHANGE_FAILED_RESOURCE_CONFLICT 0x8b
+#define PNP_BUFFER_TOO_SMALL            0x8c
+#define PNP_USE_ESCD_SUPPORT            0x8d
+#define PNP_MESSAGE_NOT_SUPPORTED       0x8e
+#define PNP_HARDWARE_ERROR              0x8f
+
+#define ESCD_SUCCESS                    0x00
+#define ESCD_IO_ERROR_READING           0x55
+#define ESCD_INVALID                    0x56
+#define ESCD_BUFFER_TOO_SMALL           0x59
+#define ESCD_NVRAM_TOO_SMALL            0x5a
+#define ESCD_FUNCTION_NOT_SUPPORTED     0x81
+
+/*
+ * Events that can be received by "get event"
+ */
+#define PNPEV_ABOUT_TO_CHANGE_CONFIG	0x0001
+#define PNPEV_DOCK_CHANGED		0x0002
+#define PNPEV_SYSTEM_DEVICE_CHANGED	0x0003
+#define PNPEV_CONFIG_CHANGED_FAILED	0x0004
+#define PNPEV_UNKNOWN_SYSTEM_EVENT	0xffff
+/* 0x8000 through 0xfffe are OEM defined */
+
+/*
+ * Messages that should be sent through "send message"
+ */
+#define PNPMSG_OK			0x00
+#define PNPMSG_ABORT			0x01
+#define PNPMSG_UNDOCK_DEFAULT_ACTION	0x40
+#define PNPMSG_POWER_OFF		0x41
+#define PNPMSG_PNP_OS_ACTIVE		0x42
+#define PNPMSG_PNP_OS_INACTIVE		0x43
+/* 0x8000 through 0xffff are OEM defined */
+
+#pragma pack(1)
+struct pnp_dev_node_info {
+	__u16	no_nodes;
+	__u16	max_node_size;
+};
+struct pnp_docking_station_info {
+	__u32	location_id;
+	__u32	serial;
+	__u16	capabilities;
+};
+struct pnp_isa_config_struc {
+	__u8	revision;
+	__u8	no_csns;
+	__u16	isa_rd_data_port;
+	__u16	reserved;
+};
+struct escd_info_struc {
+	__u16	min_escd_write_size;
+	__u16	escd_size;
+	__u32	nv_storage_base;
+};
+struct pnp_bios_node {
+	__u16	size;
+	__u8	handle;
+	__u32	eisa_id;
+	__u8	type_code[3];
+	__u16	flags;
+	__u8	data[0];
+};
+#pragma pack()
+
+#ifdef __KERNEL__
+extern void pnp_bios_init (void);
+extern int pnp_bios_dev_node_info (struct pnp_dev_node_info *data);
+extern int pnp_bios_get_dev_node (u8 *nodenum, char config, struct pnp_bios_node *data);
+extern int pnp_bios_set_dev_node (u8 nodenum, char config, struct pnp_bios_node *data);
+extern int pnp_bios_get_event (u16 *message);
+extern int pnp_bios_send_message (u16 message);
+extern int pnp_bios_dock_station_info (struct pnp_docking_station_info *data);
+extern int pnp_bios_set_stat_res (char *info);
+extern int pnp_bios_get_stat_res (char *info);
+extern int pnp_bios_apm_id_table (char *table, u16 *size);
+extern int pnp_bios_isapnp_config (struct pnp_isa_config_struc *data);
+extern int pnp_bios_escd_info (struct escd_info_struc *data);
+extern int pnp_bios_read_escd (char *data, u32 nvram_base);
+extern int pnp_bios_write_escd (char *data, u32 nvram_base);
+extern int pnp_bios_present (void);
+#endif /* __KERNEL__ */
+
+#endif /* _LINUX_PNP_BIOS_H */
Index: oldkernel/linux/pcmcia-cs-3.1.15/include/linux/pnp_resource.h
diff -u /dev/null linux/pcmcia-cs-3.1.15/include/linux/pnp_resource.h:1.1
--- /dev/null	Mon Jul 31 21:15:11 2000
+++ linux/pcmcia-cs-3.1.15/include/linux/pnp_resource.h	Fri Jul  7 16:34:58 2000
@@ -0,0 +1,148 @@
+#ifndef LINUX_PNP_RESOURCE
+#define LINUX_PNP_RESOURCE
+
+/* ISA Plug and Play Resource Definitions */
+
+#define PNP_RES_LARGE_ITEM		0x80
+
+/* Small resource items */
+#define PNP_RES_SMTAG_VERSION		0x01
+#define PNP_RES_SMTAG_LDID		0x02
+#define PNP_RES_SMTAG_CDID		0x03
+#define PNP_RES_SMTAG_IRQ		0x04
+#define PNP_RES_SMTAG_DMA		0x05
+#define PNP_RES_SMTAG_DEP_START		0x06
+#define PNP_RES_SMTAG_DEP_END		0x07
+#define PNP_RES_SMTAG_IO		0x08
+#define PNP_RES_SMTAG_IO_FIXED		0x09
+#define PNP_RES_SMTAG_VENDOR		0x0e
+#define PNP_RES_SMTAG_END		0x0f
+
+/* Large resource items */
+#define PNP_RES_LGTAG_MEM		0x01
+#define PNP_RES_LGTAG_ID_ANSI		0x02
+#define PNP_RES_LGTAG_ID_UNICODE	0x03
+#define PNP_RES_LGTAG_VENDOR		0x04
+#define PNP_RES_LGTAG_MEM32		0x05
+#define PNP_RES_LGTAG_MEM32_FIXED	0x06
+
+/* Logical device ID flags */
+#define PNP_RES_LDID_BOOT		0x01
+
+/* IRQ information */
+#define PNP_RES_IRQ_HIGH_EDGE		0x01
+#define PNP_RES_IRQ_LOW_EDGE		0x02
+#define PNP_RES_IRQ_HIGH_LEVEL		0x04
+#define PNP_RES_IRQ_LOW_LEVEL		0x08
+
+/* DMA information */
+#define PNP_RES_DMA_WIDTH_MASK		0x03
+#define PNP_RES_DMA_WIDTH_8		0x00
+#define PNP_RES_DMA_WIDTH_8_16		0x01
+#define PNP_RES_DMA_WIDTH_16		0x02
+#define PNP_RES_DMA_BUSMASTER		0x04
+#define PNP_RES_DMA_COUNT_BYTE		0x08
+#define PNP_RES_DMA_COUNT_WORD		0x10
+#define PNP_RES_DMA_SPEED_MASK		0x60
+#define PNP_RES_DMA_SPEED_COMPAT	0x00
+#define PNP_RES_DMA_SPEED_TYPEA		0x20
+#define PNP_RES_DMA_SPEED_TYPEB		0x40
+#define PNP_RES_DMA_SPEED_TYPEF		0x60
+
+/* Resource group priority */
+#define PNP_RES_CONFIG_GOOD		0x00
+#define PNP_RES_CONFIG_ACCEPTABLE	0x01
+#define PNP_RES_CONFIG_SUBOPTIMAL	0x02
+
+/* IO information */
+#define PNP_RES_IO_DECODE_16		0x01
+
+/* Memory information */
+#define PNP_RES_MEM_WRITEABLE		0x01
+#define PNP_RES_MEM_CACHEABLE		0x02
+#define PNP_RES_MEM_HIGH_ADDRESS	0x04
+#define PNP_RES_MEM_WIDTH_MASK		0x18
+#define PNP_RES_MEM_WIDTH_8		0x00
+#define PNP_RES_MEM_WIDTH_16		0x08
+#define PNP_RES_MEM_WIDTH_8_16		0x10
+#define PNP_RES_MEM_WIDTH_32		0x18
+#define PNP_RES_MEM_SHADOWABLE		0x20
+#define PNP_RES_MEM_EXPANSION_ROM	0x40
+
+/*
+  note: multi-byte data types in these structures are little endian,
+  and have to be byte swapped before use on big endian platforms.
+*/
+
+#pragma pack(1)
+union pnp_small_resource {
+	struct {
+		__u8	pnp, vendor;
+	} version;
+	struct {
+		__u32	id;
+		__u8	flag0, flag1;
+	} ldid;
+	struct {
+		__u32	id;
+	} gdid;
+	struct {
+		__u16	mask;
+		__u8	info;
+	} irq;
+	struct {
+		__u8	mask, info;
+	} dma;
+	struct {
+		__u8	priority;
+	} dep_start;
+	struct {
+		__u8	info;
+		__u16	min, max;
+		__u8	align, len;
+	} io;
+	struct {
+		__u16	base;
+		__u8	len;
+	} io_fixed;
+	struct {
+		__u8	checksum;
+	} end;
+};
+
+union pnp_large_resource {
+	struct {
+		__u8	info;
+		__u16	min, max, align, len;
+	} mem;
+	struct {
+		__u8	str[0];
+	} ansi;
+	struct {
+		__u16	country;
+		__u8	str[0];
+	} unicode;
+	struct {
+		__u8	info;
+		__u32	min, max, align, len;
+	} mem32;
+	struct {
+		__u8	info;
+		__u32	base, len;
+	} mem32_fixed;
+};
+
+union pnp_resource {
+	struct {
+		__u8	tag;
+		union pnp_small_resource d;
+	} sm;
+	struct {
+		__u8	tag;
+		__u16	sz;
+		union pnp_large_resource d;
+	} lg;
+};
+#pragma pack()
+
+#endif /* LINUX_PNP_RESOURCE */
Index: oldkernel/linux/pcmcia-cs-3.1.15/include/linux/proc_fs.h
diff -u /dev/null linux/pcmcia-cs-3.1.15/include/linux/proc_fs.h:1.1
--- /dev/null	Mon Jul 31 21:15:11 2000
+++ linux/pcmcia-cs-3.1.15/include/linux/proc_fs.h	Fri Jul  7 16:34:58 2000
@@ -0,0 +1,23 @@
+#ifndef _COMPAT_PROC_FS_H
+#define _COMPAT_PROC_FS_H
+
+#include <linux/version.h>
+#include_next <linux/proc_fs.h>
+
+#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,1,00))
+#define proc_mkdir(name, root) create_proc_entry(name, S_IFDIR, root)
+extern inline struct proc_dir_entry *
+create_proc_read_entry(const char *name, mode_t mode,
+		       struct proc_dir_entry *base,
+		       read_proc_t *read_proc, void *data)
+{
+    struct proc_dir_entry *res = create_proc_entry(name, mode, base);
+    if (res) {
+	res->read_proc = read_proc;
+	res->data = data;
+    }
+    return res;
+}
+#endif
+
+#endif /* _COMPAT_PROC_FS_H */
Index: oldkernel/linux/pcmcia-cs-3.1.15/include/pcmcia/bulkmem.h
diff -u /dev/null linux/pcmcia-cs-3.1.15/include/pcmcia/bulkmem.h:1.1
--- /dev/null	Mon Jul 31 21:15:11 2000
+++ linux/pcmcia-cs-3.1.15/include/pcmcia/bulkmem.h	Fri Jul  7 16:34:58 2000
@@ -0,0 +1,195 @@
+/*
+ * Definitions for bulk memory services
+ *
+ * bulkmem.h 1.11 1999/10/25 20:23:16
+ *
+ * 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@pcmcia.sourceforge.org>.  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 */
Index: oldkernel/linux/pcmcia-cs-3.1.15/include/pcmcia/bus_ops.h
diff -u /dev/null linux/pcmcia-cs-3.1.15/include/pcmcia/bus_ops.h:1.1
--- /dev/null	Mon Jul 31 21:15:11 2000
+++ linux/pcmcia-cs-3.1.15/include/pcmcia/bus_ops.h	Fri Jul  7 16:34:58 2000
@@ -0,0 +1,152 @@
+/*
+ * bus_ops.h 1.9 1999/11/20 01:26: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@pcmcia.sourceforge.org>.  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
+
+#include <linux/config.h>
+
+#ifdef CONFIG_VIRTUAL_BUS
+
+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;
+
+#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 */
Index: oldkernel/linux/pcmcia-cs-3.1.15/include/pcmcia/ciscode.h
diff -u /dev/null linux/pcmcia-cs-3.1.15/include/pcmcia/ciscode.h:1.1
--- /dev/null	Mon Jul 31 21:15:11 2000
+++ linux/pcmcia-cs-3.1.15/include/pcmcia/ciscode.h	Fri Jul  7 16:34:58 2000
@@ -0,0 +1,117 @@
+/*
+ * ciscode.h 1.40 2000/02/01 19:06:40
+ *
+ * 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@pcmcia.sourceforge.org>.  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_PIONEER			0x000b
+
+#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 */
Index: oldkernel/linux/pcmcia-cs-3.1.15/include/pcmcia/cisreg.h
diff -u /dev/null linux/pcmcia-cs-3.1.15/include/pcmcia/cisreg.h:1.1
--- /dev/null	Mon Jul 31 21:15:11 2000
+++ linux/pcmcia-cs-3.1.15/include/pcmcia/cisreg.h	Fri Jul  7 16:34:58 2000
@@ -0,0 +1,135 @@
+/*
+ * cisreg.h 1.16 2000/01/16 19:19: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@pcmcia.sourceforge.org>.  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
+
+/*
+ * Indirect Addressing Registers for Zoomed Video: these are addresses
+ * in common memory space
+ */
+#define CISREG_ICTRL0		0x02	/* control registers */
+#define CISREG_ICTRL1		0x03
+#define CISREG_IADDR0		0x04	/* address registers */
+#define CISREG_IADDR1		0x05
+#define CISREG_IADDR2		0x06
+#define CISREG_IADDR3		0x07
+#define CISREG_IDATA0		0x08	/* data registers */
+#define CISREG_IDATA1		0x09
+
+#define ICTRL0_COMMON		0x01
+#define ICTRL0_AUTOINC		0x02
+#define ICTRL0_BYTEGRAN		0x04
+
+#endif /* _LINUX_CISREG_H */
Index: oldkernel/linux/pcmcia-cs-3.1.15/include/pcmcia/cistpl.h
diff -u /dev/null linux/pcmcia-cs-3.1.15/include/pcmcia/cistpl.h:1.1
--- /dev/null	Mon Jul 31 21:15:11 2000
+++ linux/pcmcia-cs-3.1.15/include/pcmcia/cistpl.h	Fri Jul  7 16:34:58 2000
@@ -0,0 +1,587 @@
+/*
+ * cistpl.h 1.32 2000/01/11 19:06:50
+ *
+ * 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@pcmcia.sourceforge.org>.  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_INDIRECT		0x03
+#define CISTPL_CONFIG_CB	0x04
+#define CISTPL_CFTABLE_ENTRY_CB	0x05
+#define CISTPL_LONGLINK_MFC	0x06
+#define CISTPL_BAR		0x07
+#define CISTPL_PWR_MGMNT	0x08
+#define CISTPL_EXTDEVICE	0x09
+#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
+#define CISTPL_SPCL		0x90
+
+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 */
Index: oldkernel/linux/pcmcia-cs-3.1.15/include/pcmcia/cs.h
diff -u /dev/null linux/pcmcia-cs-3.1.15/include/pcmcia/cs.h:1.1
--- /dev/null	Mon Jul 31 21:15:11 2000
+++ linux/pcmcia-cs-3.1.15/include/pcmcia/cs.h	Fri Jul  7 16:34:58 2000
@@ -0,0 +1,469 @@
+/*
+ * cs.h 1.69 1999/10/25 20:23:17
+ *
+ * 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@pcmcia.sourceforge.org>.  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_STRICT_ALIGN	0x0200
+#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 */
Index: oldkernel/linux/pcmcia-cs-3.1.15/include/pcmcia/cs_types.h
diff -u /dev/null linux/pcmcia-cs-3.1.15/include/pcmcia/cs_types.h:1.1
--- /dev/null	Mon Jul 31 21:15:11 2000
+++ linux/pcmcia-cs-3.1.15/include/pcmcia/cs_types.h	Fri Jul  7 16:34:58 2000
@@ -0,0 +1,65 @@
+/*
+ * cs_types.h 1.17 2000/01/18 01:14:36
+ *
+ * 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@pcmcia.sourceforge.org>.  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__
+#ifdef __KERNEL__
+#include <linux/types.h>
+#else
+#include <sys/types.h>
+#endif
+#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 */
Index: oldkernel/linux/pcmcia-cs-3.1.15/include/pcmcia/driver_ops.h
diff -u /dev/null linux/pcmcia-cs-3.1.15/include/pcmcia/driver_ops.h:1.1
--- /dev/null	Mon Jul 31 21:15:11 2000
+++ linux/pcmcia-cs-3.1.15/include/pcmcia/driver_ops.h	Fri Jul  7 16:34:58 2000
@@ -0,0 +1,82 @@
+/*
+ * driver_ops.h 1.14 1999/10/25 20:23:17
+ *
+ * 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@pcmcia.sourceforge.org>.  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 */
Index: oldkernel/linux/pcmcia-cs-3.1.15/include/pcmcia/ds.h
diff -u /dev/null linux/pcmcia-cs-3.1.15/include/pcmcia/ds.h:1.1
--- /dev/null	Mon Jul 31 21:15:11 2000
+++ linux/pcmcia-cs-3.1.15/include/pcmcia/ds.h	Fri Jul  7 16:34:58 2000
@@ -0,0 +1,163 @@
+/*
+ * ds.h 1.55 1999/10/25 20:23:17
+ *
+ * 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@pcmcia.sourceforge.org>.  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 */
Index: oldkernel/linux/pcmcia-cs-3.1.15/include/pcmcia/ftl.h
diff -u /dev/null linux/pcmcia-cs-3.1.15/include/pcmcia/ftl.h:1.1
--- /dev/null	Mon Jul 31 21:15:11 2000
+++ linux/pcmcia-cs-3.1.15/include/pcmcia/ftl.h	Fri Jul  7 16:34:58 2000
@@ -0,0 +1,73 @@
+/*
+ * ftl.h 1.7 1999/10/25 20:23:17
+ *
+ * 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@pcmcia.sourceforge.org>.  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 */
Index: oldkernel/linux/pcmcia-cs-3.1.15/include/pcmcia/k_compat.h
diff -u /dev/null linux/pcmcia-cs-3.1.15/include/pcmcia/k_compat.h:1.1
--- /dev/null	Mon Jul 31 21:15:11 2000
+++ linux/pcmcia-cs-3.1.15/include/pcmcia/k_compat.h	Fri Jul  7 16:34:58 2000
@@ -0,0 +1,335 @@
+/*
+ * k_compat.h 1.124 2000/05/16 22:07: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@pcmcia.sourceforge.org>.  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_K_COMPAT_H
+#define _LINUX_K_COMPAT_H
+
+#define __LINUX__
+#define VERSION(v,p,s)		(((v)<<16)+(p<<8)+s)
+
+/* These are deprecated: should not use any more */
+#define RUN_AT(x)		(jiffies+(x))
+#define CONST			const
+#define ALLOC_SKB(len)		dev_alloc_skb(len+2)
+#define DEVICE(req)		((req)->rq_dev)
+#define GET_PACKET(dev, skb, count)\
+		skb_reserve((skb), 2); \
+		BLOCK_INPUT(skb_put((skb), (count)), (count)); \
+		(skb)->protocol = eth_type_trans((skb), (dev))
+
+#define BLK_DEV_HDR		"linux/blk.h"
+#define NEW_MULTICAST
+
+#define FREE_IRQ(i,d)		free_irq(i, d)
+#define REQUEST_IRQ(i,h,f,n,d)	request_irq(i,h,f,n,d)
+#define IRQ(a,b,c)		(a,b,c)
+#define DEV_ID			dev_id
+#define IRQ_MAP(irq, dev)	do { } while (0)
+
+#if (LINUX_VERSION_CODE < VERSION(2,3,1))
+#if (LINUX_VERSION_CODE < VERSION(2,0,16))
+#define init_waitqueue_head(p)	(*(p) = NULL)
+#else
+#define init_waitqueue_head(p)	init_waitqueue(p)
+#endif
+typedef struct wait_queue *wait_queue_head_t;
+#endif
+
+#define FS_SIZE_T		ssize_t
+#define U_FS_SIZE_T		size_t
+
+#if (LINUX_VERSION_CODE < VERSION(2,1,31))
+#define FS_RELEASE_T		void
+#else
+#define FS_RELEASE_T		int
+#endif
+
+#if (LINUX_VERSION_CODE < VERSION(2,1,38))
+#define test_and_set_bit	set_bit
+#endif
+
+#if (LINUX_VERSION_CODE > VERSION(2,1,16))
+#define AUTOCONF_INCLUDED
+#define EXPORT_SYMTAB
+#define register_symtab(x)
+#endif
+#ifdef CONFIG_MODVERSIONS
+#define MODVERSIONS		1
+#include <linux/modversions.h>
+#endif
+#include <linux/module.h>
+
+#if (LINUX_VERSION_CODE < VERSION(2,1,18))
+#define MODULE_PARM(a,b)	extern int __bogus_decl
+#define MODULE_AUTHOR(a)	extern int __bogus_decl
+#define MODULE_DESCRIPTION(a)	extern int __bogus_decl
+#undef  GET_USE_COUNT
+#define GET_USE_COUNT(m)	mod_use_count_
+#endif
+
+#if (LINUX_VERSION_CODE < VERSION(2,1,45))
+#define F_INODE(file)		((file)->f_inode)
+#else
+#define F_INODE(file)		((file)->f_dentry->d_inode)
+#endif
+
+#if (LINUX_VERSION_CODE < VERSION(2,1,51))
+#define INVALIDATE_INODES(r)	invalidate_inodes(r)
+#else
+#define INVALIDATE_INODES(r) \
+	do { struct super_block *sb = get_super(r); \
+	if (sb) invalidate_inodes(sb); } while (0)
+#endif
+
+#if (LINUX_VERSION_CODE < VERSION(2,1,60))
+#define FOPS(i,f,b,c,p)		(i,f,b,c)
+#define FPOS			(file->f_pos)
+#else
+#define FOPS(i,f,b,c,p)		(f,b,c,p)
+#define FPOS			(*ppos)
+#endif
+
+#if (LINUX_VERSION_CODE < VERSION(2,1,68))
+#define signal_pending(cur)	((cur)->signal & ~(cur)->blocked)
+#endif
+
+#if (LINUX_VERSION_CODE < VERSION(2,1,86))
+#define DEV_KFREE_SKB(skb)	dev_kfree_skb(skb, FREE_WRITE)
+#else
+#define DEV_KFREE_SKB(skb)	dev_kfree_skb(skb)
+#endif
+
+#if (LINUX_VERSION_CODE < VERSION(2,1,89))
+#define POLL_WAIT(f, q, w)	poll_wait(q, w)
+#else
+#define POLL_WAIT(f, q, w)	poll_wait(f, q, w)
+#endif
+
+#include <asm/byteorder.h>
+#ifndef le16_to_cpu
+#define le16_to_cpu(x)		(x)
+#define le32_to_cpu(x)		(x)
+#define cpu_to_le16(x)		(x)
+#define cpu_to_le32(x)		(x)
+#endif
+
+#if (LINUX_VERSION_CODE < VERSION(2,1,90))
+#define spin_lock(l)		do { } while (0)
+#define spin_unlock(l)		do { } while (0)
+#define spin_lock_irqsave(l,f)	do { save_flags(f); cli(); } while (0)
+#define spin_unlock_irqrestore(l,f) do { restore_flags(f); } while (0)
+#define spin_lock_init(s)	do { } while (0)
+#define spin_trylock(l)		(1)
+typedef int spinlock_t;
+#else
+#if (LINUX_VERSION_CODE < VERSION(2,3,17))
+#include <asm/spinlock.h>
+#else
+#include <linux/spinlock.h>
+#endif
+#if defined(CONFIG_SMP) || (LINUX_VERSION_CODE > VERSION(2,3,6)) || \
+    (defined(__powerpc__) && (LINUX_VERSION_CODE > VERSION(2,2,12)))
+#define USE_SPIN_LOCKS
+#endif
+#endif
+
+#if (LINUX_VERSION_CODE < VERSION(2,2,12)) && \
+    !defined(CONFIG_SMP) && defined(__alpha__)
+#undef spin_trylock
+#define spin_trylock(l)		(1)
+#endif
+
+#ifndef spin_is_locked
+#define spin_is_locked(l)	(0)
+#endif
+
+#if (LINUX_VERSION_CODE < VERSION(2,1,104))
+#define mdelay(x) { int i; for (i=0;i<x;i++) udelay(1000); }
+#endif
+
+#if (LINUX_VERSION_CODE < VERSION(2,1,0))
+#define __set_current_state(n) \
+    do { current->state = TASK_INTERRUPTIBLE; } while (0)
+#elif (LINUX_VERSION_CODE < VERSION(2,3,16))
+#define __set_current_state(n)	do { current->state = (n); } while (0)
+#endif
+
+#define wacquire(w)		do { } while (0)
+#define wrelease(w)		do { } while (0)
+#define wsleep(w)		interruptible_sleep_on(w)
+#define wakeup(w)		wake_up_interruptible(w)
+#define wsleeptimeout(w,t)	interruptible_sleep_on_timeout(w,t)
+#if (LINUX_VERSION_CODE < VERSION(2,1,127))
+#define interruptible_sleep_on_timeout(w,t) \
+    ({(current->timeout=jiffies+(t));wsleep(w);current->timeout;})
+#define schedule_timeout(t) \
+    do { current->timeout = jiffies+(t); schedule(); } while (0)
+#endif
+
+#include <asm/io.h>
+#ifndef readw_ns
+#ifdef __powerpc__
+#if (LINUX_VERSION_CODE < VERSION(2,2,0))
+#define readw_ns(p)		ld_be16((volatile unsigned short *)(p))
+#define readl_ns(p)		ld_be32((volatile unsigned *)(p))
+#define writew_ns(v,p)		st_be16((volatile unsigned short *)(p),(v))
+#define writel_ns(v,p)		st_be32((volatile unsigned *)(p),(v))
+#else
+#define readw_ns(p)		in_be16((volatile unsigned short *)(p))
+#define readl_ns(p)		in_be32((volatile unsigned *)(p))
+#define writew_ns(v,p)		out_be16((volatile unsigned short *)(p),(v))
+#define writel_ns(v,p)		out_be32((volatile unsigned *)(p),(v))
+#endif
+#define inw_ns(p)		in_be16((unsigned short *)((p)+_IO_BASE))
+#define inl_ns(p)		in_be32((unsigned *)((p)+_IO_BASE))
+#define outw_ns(v,p)		out_be16((unsigned short *)((p)+_IO_BASE),(v))
+#define outl_ns(v,p)		out_be32((unsigned *)((p)+_IO_BASE),(v))
+#else
+#define readw_ns(p)		readw(p)
+#define readl_ns(p)		readl(p)
+#define writew_ns(v,p)		writew(v,p)
+#define writel_ns(v,p)		writel(v,p)
+#define inw_ns(p)		inw(p)
+#define inl_ns(p)		inl(p)
+#define outw_ns(v,p)		outw(v,p)
+#define outl_ns(v,p)		outl(v,p)
+#endif
+#endif
+#ifndef insw_ns
+#define insw_ns(p,b,l)		insw(p,b,l)
+#define insl_ns(p,b,l)		insl(p,b,l)
+#define outsw_ns(p,b,l)		outsw(p,b,l)
+#define outsl_ns(p,b,l)		outsl(p,b,l)
+#endif
+
+#if (LINUX_VERSION_CODE < VERSION(2,1,126))
+#define SCSI_DISK0_MAJOR	SCSI_DISK_MAJOR
+#endif
+
+typedef unsigned long k_time_t;
+#define ACQUIRE_RESOURCE_LOCK	do {} while (0)
+#define RELEASE_RESOURCE_LOCK	do {} while (0)
+
+/* Only for backwards compatibility */
+#include <asm/uaccess.h>
+
+#include <linux/ioport.h>
+#if defined(check_mem_region) && !defined(HAVE_MEMRESERVE)
+#define HAVE_MEMRESERVE
+#endif
+#ifndef HAVE_MEMRESERVE
+#define vacate_region		release_region
+#define vacate_mem_region	release_mem_region
+extern int check_mem_region(unsigned long base, unsigned long num);
+extern void request_mem_region(unsigned long base, unsigned long num,
+			       char *name);
+extern void release_mem_region(unsigned long base, unsigned long num);
+#endif
+
+#if (LINUX_VERSION_CODE < VERSION(2,3,14))
+#define net_device		device
+#endif
+
+#if (LINUX_VERSION_CODE < VERSION(2,2,0))
+#define in_interrupt()		(intr_count)
+#endif
+
+#if (LINUX_VERSION_CODE < VERSION(2,3,32))
+#define BLK_DEFAULT_QUEUE(n)	blk_dev[n].request_fn
+#define blk_init_queue(q, req)	q = (req)
+#define blk_cleanup_queue(q)	q = NULL
+#define request_arg_t		void
+#else
+#define request_arg_t		request_queue_t *q
+#endif
+
+#include <linux/sched.h>
+#ifndef CAP_SYS_ADMIN
+#define capable(x)		(suser())
+#endif
+
+#if (LINUX_VERSION_CODE < VERSION(2,3,38))
+#define block_device_operations file_operations
+#endif
+
+#if (LINUX_VERSION_CODE < VERSION(2,3,40))
+#define register_disk(dev, drive, minors, ops, size) \
+    do { (dev)->part[(drive)*(minors)].nr_sects = size; \
+	if (size == 0) (dev)->part[(drive)*(minors)].start_sect = -1; \
+	resetup_one_dev(dev, drive); } while (0);
+#endif
+
+#if (LINUX_VERSION_CODE < VERSION(2,1,25))
+#define net_device_stats	enet_statistics
+#define skb_tx_check(dev, skb) \
+    do { if (skb == NULL) { dev_tint(dev); return 0; } \
+    if (skb->len <= 0) return 0; } while (0)
+#define add_rx_bytes(stats, n)	do { int x; x = (n); } while (0)
+#define add_tx_bytes(stats, n)	do { int x; x = (n); } while (0)
+#else
+#define skb_tx_check(dev, skb)	do { } while (0)
+#define add_rx_bytes(stats, n)	do { (stats)->rx_bytes += n; } while (0)
+#define add_tx_bytes(stats, n)	do { (stats)->tx_bytes += n; } while (0)
+#endif
+
+#if (LINUX_VERSION_CODE < VERSION(2,3,43))
+#define netif_stop_queue(dev)	set_bit(0, (void *)&(dev)->tbusy)
+#define netif_start_queue(dev)	clear_bit(0, (void *)&(dev)->tbusy)
+#define netif_wake_queue(dev) \
+    do { netif_start_queue(dev); mark_bh(NET_BH); } while (0)
+#define netif_device_attach(dev) \
+    do { (dev)->start = 1; netif_start_queue(dev); } while (0)
+#define netif_device_detach(dev) \
+    do { (dev)->start = 0; netif_stop_queue(dev); } while (0)
+#define netif_device_present(dev) ((dev)->start)
+#define netif_running(dev)	((dev)->start)
+#define netif_mark_up(dev)	do { (dev)->start = 1; } while (0)
+#define netif_mark_down(dev)	do { (dev)->start = 0; } while (0)
+#define netif_carrier_on(dev)	do { dev->flags |= IFF_RUNNING; } while (0)
+#define netif_carrier_off(dev)	do { dev->flags &= ~IFF_RUNNING; } while (0)
+#define netif_queue_stopped(dev) ((dev)->tbusy)
+#define tx_timeout_check(dev, tx_timeout) \
+    do { if (test_and_set_bit(0, (void *)&(dev)->tbusy) != 0) { \
+	if (jiffies - (dev)->trans_start < TX_TIMEOUT) return 1; \
+	tx_timeout(dev); \
+    } } while (0)
+#define dev_kfree_skb_irq(skb)	DEV_KFREE_SKB(skb)
+#else
+#define netif_mark_up(dev)	do { } while (0)
+#define netif_mark_down(dev)	do { } while (0)
+#define tx_timeout_check(d,h)	netif_stop_queue(d)
+#endif
+
+#if (LINUX_VERSION_CODE < VERSION(2,2,0))
+#define timer_pending(a)	(((a)->prev) != NULL)
+#define mod_timer(a, b)	\
+    do { del_timer(a); (a)->expires = (b); add_timer(a); } while (0)
+#endif
+
+#endif /* _LINUX_K_COMPAT_H */
Index: oldkernel/linux/pcmcia-cs-3.1.15/include/pcmcia/mem_op.h
diff -u /dev/null linux/pcmcia-cs-3.1.15/include/pcmcia/mem_op.h:1.1
--- /dev/null	Mon Jul 31 21:15:11 2000
+++ linux/pcmcia-cs-3.1.15/include/pcmcia/mem_op.h	Fri Jul  7 16:34:58 2000
@@ -0,0 +1,133 @@
+/*
+ * mem_op.h 1.12 1999/10/25 20:23:17
+ *
+ * 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@pcmcia.sourceforge.org>.  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 = readw_ns(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) {
+	writew_ns(*(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(readw_ns(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);
+	writew_ns(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 */
Index: oldkernel/linux/pcmcia-cs-3.1.15/include/pcmcia/memory.h
diff -u /dev/null linux/pcmcia-cs-3.1.15/include/pcmcia/memory.h:1.1
--- /dev/null	Mon Jul 31 21:15:11 2000
+++ linux/pcmcia-cs-3.1.15/include/pcmcia/memory.h	Fri Jul  7 16:34:58 2000
@@ -0,0 +1,41 @@
+/*
+ * memory.h 1.6 1999/10/25 20:23:17
+ *
+ * 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@pcmcia.sourceforge.org>.  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 */
Index: oldkernel/linux/pcmcia-cs-3.1.15/include/pcmcia/ss.h
diff -u /dev/null linux/pcmcia-cs-3.1.15/include/pcmcia/ss.h:1.1
--- /dev/null	Mon Jul 31 21:15:11 2000
+++ linux/pcmcia-cs-3.1.15/include/pcmcia/ss.h	Fri Jul  7 16:34:58 2000
@@ -0,0 +1,132 @@
+/*
+ * ss.h 1.27 2000/03/16 02:26:02
+ *
+ * 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@pcmcia.sourceforge.org>.  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
+#define SS_PENDING	0x4000
+
+/* 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_STATIC_MAP	0x0008
+#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 */
Index: oldkernel/linux/pcmcia-cs-3.1.15/include/pcmcia/version.h
diff -u /dev/null linux/pcmcia-cs-3.1.15/include/pcmcia/version.h:1.1
--- /dev/null	Mon Jul 31 21:15:11 2000
+++ linux/pcmcia-cs-3.1.15/include/pcmcia/version.h	Fri Jul  7 16:34:58 2000
@@ -0,0 +1,4 @@
+/* version.h 1.87 2000/04/11 02:14:45 (David Hinds) */
+
+#define CS_RELEASE "3.1.15"
+#define CS_RELEASE_CODE 0x310f
Index: oldkernel/linux/pcmcia-cs-3.1.15/include/static/linux/ibmtr.h
diff -u /dev/null linux/pcmcia-cs-3.1.15/include/static/linux/ibmtr.h:1.1
--- /dev/null	Mon Jul 31 21:15:11 2000
+++ linux/pcmcia-cs-3.1.15/include/static/linux/ibmtr.h	Fri Jul  7 16:34:58 2000
@@ -0,0 +1,10 @@
+#ifndef _COMPAT_IBMTR_H
+#define _COMPAT_IBMTR_H
+
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,3,21))
+#include <../drivers/net/tokenring/ibmtr.h>
+#else
+#include <../drivers/net/ibmtr.h>
+#endif
+
+#endif /* _COMPAT_IBMTR_H */
Index: oldkernel/linux/pcmcia-cs-3.1.15/include/static/linux/init.h
diff -u /dev/null linux/pcmcia-cs-3.1.15/include/static/linux/init.h:1.1
--- /dev/null	Mon Jul 31 21:15:11 2000
+++ linux/pcmcia-cs-3.1.15/include/static/linux/init.h	Fri Jul  7 16:34:58 2000
@@ -0,0 +1,17 @@
+#ifndef _COMPAT_INIT_H
+#define _COMPAT_INIT_H
+
+#include <linux/version.h>
+
+#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,3,0)) && defined(MODULE)
+#define __init
+#define __initdata
+#define __exit
+#define __exitdata
+#define module_init(x) int init_module(void) { return x(); }
+#define module_exit(x) void cleanup_module(void) { x(); }
+#else
+#include_next <linux/init.h>
+#endif
+
+#endif /* _COMPAT_INIT_H */
Index: oldkernel/linux/pcmcia-cs-3.1.15/include/static/linux/pci.h
diff -u /dev/null linux/pcmcia-cs-3.1.15/include/static/linux/pci.h:1.1
--- /dev/null	Mon Jul 31 21:15:11 2000
+++ linux/pcmcia-cs-3.1.15/include/static/linux/pci.h	Fri Jul  7 16:34:58 2000
@@ -0,0 +1,49 @@
+#ifndef _COMPAT_PCI_H
+#define _COMPAT_PCI_H
+
+#include_next <linux/pci.h>
+#include <linux/version.h>
+
+#ifndef PCI_FUNC
+#define PCI_FUNC(devfn)		((devfn)&7)
+#define PCI_SLOT(devfn)		((devfn)>>3)
+#define PCI_DEVFN(dev,fn)	(((dev)<<3)|((fn)&7))
+#endif
+
+#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,1,0))
+extern struct pci_dev *pci_devices;
+extern struct pci_bus pci_root;
+#endif
+
+#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,1,93))
+
+#include <linux/bios32.h>
+#include <linux/types.h>
+
+extern struct pci_dev *pci_find_slot(u_int bus, u_int devfn);
+extern struct pci_dev *pci_find_class(u_int class, struct pci_dev *from);
+
+#define pci_fn(x, sz, t) \
+    static inline int pci_##x##_config_##sz(struct pci_dev *d, u8 w, t v) \
+    { return pcibios_##x##_config_##sz(d->bus->number, d->devfn, w, v); }
+pci_fn(read, byte, u8 *)
+pci_fn(read, word, u16 *)
+pci_fn(read, dword, u32 *)
+pci_fn(write, byte, u8)
+pci_fn(write, word, u16)
+pci_fn(write, dword, u32)
+
+#endif
+
+#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,3,24))
+extern int pci_enable_device(struct pci_dev *dev);
+extern int pci_set_power_state(struct pci_dev *dev, int state);
+#endif
+
+#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,3,40))
+#define pci_for_each_dev(p) for (p = pci_devices; p; p = p->next)
+#endif
+
+extern u32 pci_irq_mask;
+
+#endif /* _COMPAT_PCI_H */
Index: oldkernel/linux/pcmcia-cs-3.1.15/include/static/linux/pm.h
diff -u /dev/null linux/pcmcia-cs-3.1.15/include/static/linux/pm.h:1.1
--- /dev/null	Mon Jul 31 21:15:11 2000
+++ linux/pcmcia-cs-3.1.15/include/static/linux/pm.h	Fri Jul  7 16:34:58 2000
@@ -0,0 +1,23 @@
+#ifndef _COMPAT_PM_H
+#define _COMPAT_PM_H
+
+#include <linux/version.h>
+
+#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,3,43))
+
+#include <linux/apm_bios.h>
+
+/* This is an ugly hack: it only works in case statements */
+#define PM_SUSPEND		APM_SYS_SUSPEND: case APM_USER_SUSPEND
+#define PM_RESUME		APM_NORMAL_RESUME: case APM_CRITICAL_RESUME
+
+#define pm_register(a, b, fn)	apm_register_callback(fn)
+#define pm_unregister_all(fn)	apm_unregister_callback(fn)
+
+#else
+
+#include_next <linux/pm.h>
+
+#endif
+
+#endif /* _COMPAT_PM_H */
Index: oldkernel/linux/pcmcia-cs-3.1.15/include/static/linux/pnp_bios.h
diff -u /dev/null linux/pcmcia-cs-3.1.15/include/static/linux/pnp_bios.h:1.1
--- /dev/null	Mon Jul 31 21:15:11 2000
+++ linux/pcmcia-cs-3.1.15/include/static/linux/pnp_bios.h	Fri Jul  7 16:34:58 2000
@@ -0,0 +1,127 @@
+/*
+ * Include file for the interface to a PnP BIOS
+ *
+ * Original BIOS code (C) 1998 Christian Schmidt (chr.schmidt@tu-bs.de)
+ * PnP handler parts (c) 1998 Tom Lees <tom@lpsg.demon.co.uk>
+ * Minor reorganizations by David Hinds <dhinds@zen.stanford.edu>
+ *
+ * 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, 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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ * $Original Id: pnp-bios.h,v 0.1 1998/03/19 23:00:00 cs Exp $
+ * pnp_bios.h,v 1.1 1999/08/04 15:56:03 root Exp
+ */
+
+#ifndef _LINUX_PNP_BIOS_H
+#define _LINUX_PNP_BIOS_H
+
+/*
+ * Status codes (warnings and errors)
+ */
+#define PNP_SUCCESS                     0x00
+#define PNP_NOT_SET_STATICALLY          0x7f
+#define PNP_UNKNOWN_FUNCTION            0x81
+#define PNP_FUNCTION_NOT_SUPPORTED      0x82
+#define PNP_INVALID_HANDLE              0x83
+#define PNP_BAD_PARAMETER               0x84
+#define PNP_SET_FAILED                  0x85
+#define PNP_EVENTS_NOT_PENDING          0x86
+#define PNP_SYSTEM_NOT_DOCKED           0x87
+#define PNP_NO_ISA_PNP_CARDS            0x88
+#define PNP_UNABLE_TO_DETERMINE_DOCK_CAPABILITIES 0x89
+#define PNP_CONFIG_CHANGE_FAILED_NO_BATTERY 0x8a
+#define PNP_CONFIG_CHANGE_FAILED_RESOURCE_CONFLICT 0x8b
+#define PNP_BUFFER_TOO_SMALL            0x8c
+#define PNP_USE_ESCD_SUPPORT            0x8d
+#define PNP_MESSAGE_NOT_SUPPORTED       0x8e
+#define PNP_HARDWARE_ERROR              0x8f
+
+#define ESCD_SUCCESS                    0x00
+#define ESCD_IO_ERROR_READING           0x55
+#define ESCD_INVALID                    0x56
+#define ESCD_BUFFER_TOO_SMALL           0x59
+#define ESCD_NVRAM_TOO_SMALL            0x5a
+#define ESCD_FUNCTION_NOT_SUPPORTED     0x81
+
+/*
+ * Events that can be received by "get event"
+ */
+#define PNPEV_ABOUT_TO_CHANGE_CONFIG	0x0001
+#define PNPEV_DOCK_CHANGED		0x0002
+#define PNPEV_SYSTEM_DEVICE_CHANGED	0x0003
+#define PNPEV_CONFIG_CHANGED_FAILED	0x0004
+#define PNPEV_UNKNOWN_SYSTEM_EVENT	0xffff
+/* 0x8000 through 0xfffe are OEM defined */
+
+/*
+ * Messages that should be sent through "send message"
+ */
+#define PNPMSG_OK			0x00
+#define PNPMSG_ABORT			0x01
+#define PNPMSG_UNDOCK_DEFAULT_ACTION	0x40
+#define PNPMSG_POWER_OFF		0x41
+#define PNPMSG_PNP_OS_ACTIVE		0x42
+#define PNPMSG_PNP_OS_INACTIVE		0x43
+/* 0x8000 through 0xffff are OEM defined */
+
+#pragma pack(1)
+struct pnp_dev_node_info {
+	__u16	no_nodes;
+	__u16	max_node_size;
+};
+struct pnp_docking_station_info {
+	__u32	location_id;
+	__u32	serial;
+	__u16	capabilities;
+};
+struct pnp_isa_config_struc {
+	__u8	revision;
+	__u8	no_csns;
+	__u16	isa_rd_data_port;
+	__u16	reserved;
+};
+struct escd_info_struc {
+	__u16	min_escd_write_size;
+	__u16	escd_size;
+	__u32	nv_storage_base;
+};
+struct pnp_bios_node {
+	__u16	size;
+	__u8	handle;
+	__u32	eisa_id;
+	__u8	type_code[3];
+	__u16	flags;
+	__u8	data[0];
+};
+#pragma pack()
+
+#ifdef __KERNEL__
+extern void pnp_bios_init (void);
+extern int pnp_bios_dev_node_info (struct pnp_dev_node_info *data);
+extern int pnp_bios_get_dev_node (u8 *nodenum, char config, struct pnp_bios_node *data);
+extern int pnp_bios_set_dev_node (u8 nodenum, char config, struct pnp_bios_node *data);
+extern int pnp_bios_get_event (u16 *message);
+extern int pnp_bios_send_message (u16 message);
+extern int pnp_bios_dock_station_info (struct pnp_docking_station_info *data);
+extern int pnp_bios_set_stat_res (char *info);
+extern int pnp_bios_get_stat_res (char *info);
+extern int pnp_bios_apm_id_table (char *table, u16 *size);
+extern int pnp_bios_isapnp_config (struct pnp_isa_config_struc *data);
+extern int pnp_bios_escd_info (struct escd_info_struc *data);
+extern int pnp_bios_read_escd (char *data, u32 nvram_base);
+extern int pnp_bios_write_escd (char *data, u32 nvram_base);
+extern int pnp_bios_present (void);
+#endif /* __KERNEL__ */
+
+#endif /* _LINUX_PNP_BIOS_H */
Index: oldkernel/linux/pcmcia-cs-3.1.15/include/static/linux/pnp_resource.h
diff -u /dev/null linux/pcmcia-cs-3.1.15/include/static/linux/pnp_resource.h:1.1
--- /dev/null	Mon Jul 31 21:15:11 2000
+++ linux/pcmcia-cs-3.1.15/include/static/linux/pnp_resource.h	Fri Jul  7 16:34:58 2000
@@ -0,0 +1,148 @@
+#ifndef LINUX_PNP_RESOURCE
+#define LINUX_PNP_RESOURCE
+
+/* ISA Plug and Play Resource Definitions */
+
+#define PNP_RES_LARGE_ITEM		0x80
+
+/* Small resource items */
+#define PNP_RES_SMTAG_VERSION		0x01
+#define PNP_RES_SMTAG_LDID		0x02
+#define PNP_RES_SMTAG_CDID		0x03
+#define PNP_RES_SMTAG_IRQ		0x04
+#define PNP_RES_SMTAG_DMA		0x05
+#define PNP_RES_SMTAG_DEP_START		0x06
+#define PNP_RES_SMTAG_DEP_END		0x07
+#define PNP_RES_SMTAG_IO		0x08
+#define PNP_RES_SMTAG_IO_FIXED		0x09
+#define PNP_RES_SMTAG_VENDOR		0x0e
+#define PNP_RES_SMTAG_END		0x0f
+
+/* Large resource items */
+#define PNP_RES_LGTAG_MEM		0x01
+#define PNP_RES_LGTAG_ID_ANSI		0x02
+#define PNP_RES_LGTAG_ID_UNICODE	0x03
+#define PNP_RES_LGTAG_VENDOR		0x04
+#define PNP_RES_LGTAG_MEM32		0x05
+#define PNP_RES_LGTAG_MEM32_FIXED	0x06
+
+/* Logical device ID flags */
+#define PNP_RES_LDID_BOOT		0x01
+
+/* IRQ information */
+#define PNP_RES_IRQ_HIGH_EDGE		0x01
+#define PNP_RES_IRQ_LOW_EDGE		0x02
+#define PNP_RES_IRQ_HIGH_LEVEL		0x04
+#define PNP_RES_IRQ_LOW_LEVEL		0x08
+
+/* DMA information */
+#define PNP_RES_DMA_WIDTH_MASK		0x03
+#define PNP_RES_DMA_WIDTH_8		0x00
+#define PNP_RES_DMA_WIDTH_8_16		0x01
+#define PNP_RES_DMA_WIDTH_16		0x02
+#define PNP_RES_DMA_BUSMASTER		0x04
+#define PNP_RES_DMA_COUNT_BYTE		0x08
+#define PNP_RES_DMA_COUNT_WORD		0x10
+#define PNP_RES_DMA_SPEED_MASK		0x60
+#define PNP_RES_DMA_SPEED_COMPAT	0x00
+#define PNP_RES_DMA_SPEED_TYPEA		0x20
+#define PNP_RES_DMA_SPEED_TYPEB		0x40
+#define PNP_RES_DMA_SPEED_TYPEF		0x60
+
+/* Resource group priority */
+#define PNP_RES_CONFIG_GOOD		0x00
+#define PNP_RES_CONFIG_ACCEPTABLE	0x01
+#define PNP_RES_CONFIG_SUBOPTIMAL	0x02
+
+/* IO information */
+#define PNP_RES_IO_DECODE_16		0x01
+
+/* Memory information */
+#define PNP_RES_MEM_WRITEABLE		0x01
+#define PNP_RES_MEM_CACHEABLE		0x02
+#define PNP_RES_MEM_HIGH_ADDRESS	0x04
+#define PNP_RES_MEM_WIDTH_MASK		0x18
+#define PNP_RES_MEM_WIDTH_8		0x00
+#define PNP_RES_MEM_WIDTH_16		0x08
+#define PNP_RES_MEM_WIDTH_8_16		0x10
+#define PNP_RES_MEM_WIDTH_32		0x18
+#define PNP_RES_MEM_SHADOWABLE		0x20
+#define PNP_RES_MEM_EXPANSION_ROM	0x40
+
+/*
+  note: multi-byte data types in these structures are little endian,
+  and have to be byte swapped before use on big endian platforms.
+*/
+
+#pragma pack(1)
+union pnp_small_resource {
+	struct {
+		__u8	pnp, vendor;
+	} version;
+	struct {
+		__u32	id;
+		__u8	flag0, flag1;
+	} ldid;
+	struct {
+		__u32	id;
+	} gdid;
+	struct {
+		__u16	mask;
+		__u8	info;
+	} irq;
+	struct {
+		__u8	mask, info;
+	} dma;
+	struct {
+		__u8	priority;
+	} dep_start;
+	struct {
+		__u8	info;
+		__u16	min, max;
+		__u8	align, len;
+	} io;
+	struct {
+		__u16	base;
+		__u8	len;
+	} io_fixed;
+	struct {
+		__u8	checksum;
+	} end;
+};
+
+union pnp_large_resource {
+	struct {
+		__u8	info;
+		__u16	min, max, align, len;
+	} mem;
+	struct {
+		__u8	str[0];
+	} ansi;
+	struct {
+		__u16	country;
+		__u8	str[0];
+	} unicode;
+	struct {
+		__u8	info;
+		__u32	min, max, align, len;
+	} mem32;
+	struct {
+		__u8	info;
+		__u32	base, len;
+	} mem32_fixed;
+};
+
+union pnp_resource {
+	struct {
+		__u8	tag;
+		union pnp_small_resource d;
+	} sm;
+	struct {
+		__u8	tag;
+		__u16	sz;
+		union pnp_large_resource d;
+	} lg;
+};
+#pragma pack()
+
+#endif /* LINUX_PNP_RESOURCE */
Index: oldkernel/linux/pcmcia-cs-3.1.15/include/static/linux/proc_fs.h
diff -u /dev/null linux/pcmcia-cs-3.1.15/include/static/linux/proc_fs.h:1.1
--- /dev/null	Mon Jul 31 21:15:11 2000
+++ linux/pcmcia-cs-3.1.15/include/static/linux/proc_fs.h	Fri Jul  7 16:34:58 2000
@@ -0,0 +1,23 @@
+#ifndef _COMPAT_PROC_FS_H
+#define _COMPAT_PROC_FS_H
+
+#include <linux/version.h>
+#include_next <linux/proc_fs.h>
+
+#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,1,00))
+#define proc_mkdir(name, root) create_proc_entry(name, S_IFDIR, root)
+extern inline struct proc_dir_entry *
+create_proc_read_entry(const char *name, mode_t mode,
+		       struct proc_dir_entry *base,
+		       read_proc_t *read_proc, void *data)
+{
+    struct proc_dir_entry *res = create_proc_entry(name, mode, base);
+    if (res) {
+	res->read_proc = read_proc;
+	res->data = data;
+    }
+    return res;
+}
+#endif
+
+#endif /* _COMPAT_PROC_FS_H */
Index: oldkernel/linux/pcmcia-cs-3.1.15/include/static/pcmcia/ciscode.h
diff -u /dev/null linux/pcmcia-cs-3.1.15/include/static/pcmcia/ciscode.h:1.1
--- /dev/null	Mon Jul 31 21:15:11 2000
+++ linux/pcmcia-cs-3.1.15/include/static/pcmcia/ciscode.h	Fri Jul  7 16:34:58 2000
@@ -0,0 +1,117 @@
+/*
+ * ciscode.h 1.40 2000/02/01 19:06:40
+ *
+ * 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@pcmcia.sourceforge.org>.  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_PIONEER			0x000b
+
+#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 */
Index: oldkernel/linux/pcmcia-cs-3.1.15/man/Makefile
diff -u /dev/null linux/pcmcia-cs-3.1.15/man/Makefile:1.1
--- /dev/null	Mon Jul 31 21:15:11 2000
+++ linux/pcmcia-cs-3.1.15/man/Makefile	Fri Jul  7 16:34:58 2000
@@ -0,0 +1,50 @@
+#
+# man/Makefile 1.47 2000/05/15 23:26:53 (David Hinds)
+#
+
+# Include site dependent options
+include ../config.mk
+
+COFLAGS = -kv
+MANDIR = $(PREFIX)/usr/man
+
+MAN1_X11 = cardinfo.1
+MAN4 = pcmcia_core.4 tcic.4 i82365.4 tc589_cs.4 pcnet_cs.4 dummy_cs.4 \
+	serial_cs.4 ftl_cs.4 memory_cs.4 fmvj18x_cs.4 tc574_cs.4 \
+	tc575_cb.4 netwave_cs.4 wavelan_cs.4 aha152x_cs.4 xirc2ps_cs.4 \
+	memory_cb.4 ibmtr_cs.4 smc91c92_cs.4 iflash2_mtd.4 iflash2+_mtd.4 \
+	wvlan_cs.4 ray_cs.4 airo.4 airo_cs.4
+MAN5 = pcmcia.5 stab.5
+MAN8 = cardmgr.8 cardctl.8 ftl_format.8 ftl_check.8 scsi_info.8 \
+	ifport.8 ifuser.8 ide_info.8 pcinitrd.8 pack_cis.8 dump_cis.8 \
+	lspnp.8 setpnp.8
+
+all: $(MAN1_X11) $(MAN4) $(MAN5) $(MAN8)
+
+dep:
+
+clean:
+
+install-man1-x11: $(MAN1_X11)
+	@mkdir -p $(PREFIX)/usr/X11R6/man/man1
+	cp $(MAN1_X11) $(PREFIX)/usr/X11R6/man/man1
+
+install-man4: $(MAN4)
+	@mkdir -p $(MANDIR)/man4
+	cp *.4 $(MANDIR)/man4
+
+install-man5: $(MAN5)
+	@mkdir -p $(MANDIR)/man5
+	cp *.5 $(MANDIR)/man5
+
+install-man8: $(MAN8)
+	@mkdir -p $(MANDIR)/man8
+	cp *.8 $(MANDIR)/man8
+
+install: install-man1-x11 install-man4 install-man5 install-man8
+
+man2html: $(MAN1) $(MAN4) $(MAN5) $(MAN8)
+	for f in *.[1458] ; do				\
+	    man2html $$f | ./fixhtml > html/$$f.html ;	\
+	done
+	./indexhtml > html/index.html
Index: oldkernel/linux/pcmcia-cs-3.1.15/man/aha152x_cs.4
diff -u /dev/null linux/pcmcia-cs-3.1.15/man/aha152x_cs.4:1.1
--- /dev/null	Mon Jul 31 21:15:11 2000
+++ linux/pcmcia-cs-3.1.15/man/aha152x_cs.4	Fri Jul  7 16:34:58 2000
@@ -0,0 +1,65 @@
+.\" Copyright (C) 1998 David A. Hinds -- dhinds@pcmcia.sourceforge.org
+.\" aha152x_cs.4 1.7 1999/10/25 19:50:45
+.\"
+.TH AHA152X_CS 4 "1999/10/25 19:50:45" "pcmcia-cs"
+.SH NAME
+aha152x_cs \- Adaptec AHA-152X compatible PCMCIA device driver
+.SH SYNOPSIS
+.B insmod aha152x_cs.o
+.RB [ pc_debug=\c
+.IR n ]
+.RB [ irq_list=\c
+.IR i,j,... ]
+.RB [ host_id=\c
+.IR n ]
+.RB [ reconnect=\c
+.IR n ]
+.RB [ parity=\c
+.IR n ]
+.RB [ synchronous=\c
+.IR n ]
+.RB [ reset_delay=\c
+.IR n ]
+.RB [ ext_trans=\c
+.IR n ]
+.SH DESCRIPTION
+.B aha152x_cs
+is the low-level Card Services driver for various PCMCIA SCSI adapters
+that are compatible with the Adaptec AHA-152X host adapter.  These
+include the New Media Bus Toaster, the Adaptec AHA-1460, and various
+other OEM cards.
+.SH PARAMETERS
+.TP
+.BI pc_debug= n
+Selects the PCMCIA debugging level.  This parameter is only available
+if the module is compiled with debugging enabled.  A non-zero value
+enables debugging.
+.TP
+.BI irq_list= i,j,...
+Specifies the set of interrupts that may be allocated by this driver.
+.TP
+.BI host_id= n
+Specifies the SCSI ID of the host adapter.  The default host ID is 7.
+.TP
+.BI reconnect= n
+Enables support for disconnect/reconnect, if non-zero.
+The default is 1 (true).
+.TP
+.BI parity= n
+Enables SCSI parity checking.  The default is 1 (true).
+.TP
+.BI synchronous= n
+Enables negotiation of synchronous SCSI transfers.
+The default is 0 (false).
+.TP
+.BI reset_delay= n
+Specifies a delay for SCSI bus resets, in 10 millisecond intervals.
+The default is 100.
+.TP
+.BI ext_trans= n
+Enables the ``extended translation'' scheme for partition tables of
+drives larger than 1 GB.
+.SH AUTHOR
+David Hinds \- dhinds@pcmcia.sourceforge.org
+.SH "SEE ALSO"
+cardmgr(8), pcmcia(5).
Index: oldkernel/linux/pcmcia-cs-3.1.15/man/airo.4
diff -u /dev/null linux/pcmcia-cs-3.1.15/man/airo.4:1.1
--- /dev/null	Mon Jul 31 21:15:11 2000
+++ linux/pcmcia-cs-3.1.15/man/airo.4	Fri Jul  7 16:34:58 2000
@@ -0,0 +1,162 @@
+.\" Copyright (c) 2000 Benjamin C. Reed <breed@almaden.ibm.com>
+.\" airo.c.4
+.\"
+.TH AIRO 4 "1/17/00" "IBM Almaden Research Center"
+
+.SH NAME
+airo \- Driver for the Aironet 802.11 ISA/PCI/PCMCIA 4500 & 4800 cards
+
+.SH SYNOPSIS
+.B insmod airo.o
+.RB [ io=\c
+.IR i,j,... ]
+.RB [ irq=\c
+.IR i,j,... ]
+.RB [ basic_rate=\c
+.IR n ]
+.RB [ rates=\c
+.IR i,j,... ]
+.RB [ ssids=\c
+.IR i,j,... ]
+
+.SH DESCRIPTION
+This driver is for Aironet 4500 and 4800 ISA/PCI/PCMCIA cards and 2.0
+or 2.2 kernels.  Just for fun, I tested a 3500 for a total of 2
+minutes and it seemed to work more or less.  (The configuration
+information displayed in the Config file seemed a bit messed up.)
+
+The card will create an ethX device for each wireless card.  An entry
+for each device will be created under /proc/aironet/ethX with entries
+to view the status of the card and configure it.
+
+.SH /proc/aironet
+In the /proc/aironet partition there will be a subdirectory for each
+aironet interface. In that subdirectory are four files: Status,
+Config, WepKey, and SSID.
+
+.TP   
+.BI Status
+Most of the fields in the Status file are self describing.  The Mode:
+field is a bitmask.  Here is the description from the programmer's
+manual:
+   
+   Bit Meaning
+   0x0001 Configured
+   0x0002 MAC Enabled
+   0x0004 Receive Enabled
+   0x0010 In Sync
+   0x0020 Associated
+   0x8000 Error
+   
+I'm not sure what the units are in the Signal: field.
+
+.TP   
+.BI Config
+The Config file is mode up of fields separated by newlines.  When
+setting the fields, they can occur in any order.  If the values are
+in error, a sane default will be used.  Note, there must be exactly
+one space between the colon and the value.
+
+.TP
+.BI   Mode:
+can be "adhoc" or "ESS".  Defaults to ESS.
+
+.TP
+.BI   NodeName:
+Can be up to 16 characters in length
+
+.TP
+.BI   PowerMode:
+Can be CAM (Constantly Awake Mode), PSP (Power Saving
+something...), PSPCAM (you guess...).  CAM is default.
+
+.TP
+.BI   DataRates:
+Must be separated by exactly 1 space.  The units are 500 kps.  So 2 is
+1 mbs.  There can be up to 8 rates specified.  The basic rate set by
+setting the high bit (bit 7).
+
+.TP
+.BI   Channel:
+Don't know anything about this except that you can set it...
+
+.TP
+.BI   XmitPower:
+Transmit power in milliwatts.
+
+.TP
+.BI   WEP:
+Can be open, encrypt, and shared, meaning no authentication, 
+encrypted data only, shared key authentication and encryption.
+Note that when WEP is enabled the current cards (as of 9/9/99)
+do not allow data rates above 2 mbs.
+
+.TP
+.BI   Modulation:
+Can be cck or mok.  Sets the modulation type for speeds above 2mbs.
+
+.TP
+.BI WepKey
+This file allows the WepKey to be set.  I don't use Wep, so I can't
+really test it. The key is set by writing the key as a string
+to the file.  Each octet must be written in hexadecimal with
+leading zeros and separated by colons.  For security reasons the key
+cannot be read from the card.  Writing to this file sets both the
+permanent and temporary key.  (Anyone have a need for being able
+to write them separately?)  For example:
+
+     echo 12:04:78:9a:bc > /proc/aironet/eth0/WepKey
+   
+.TP
+.BI SSID
+The SSID file has the list of usable SSIDs. If the list is empty, it
+will associate with any access point that it can find. The SSIDs are
+separated by line feeds. This file may also be written to to change
+the list.
+
+.TP
+.BI Stats/StatsDelta
+Basically a dump of all the statistics of the card.  The source has
+provisions for all the statistics even though by default a lot of them
+are turned off.  Stats give the statistics from the time the card was
+powered up.  StatsDelta gives the statistics from the time the statistics
+were last reset.  The statistics are reset by opening the StatsDelta file
+for writing.
+
+.\"
+.\" PARAMETER part
+.\"
+.SH PARAMETERS
+.TP
+.BI io= i,j,...
+Specifies the set of ioports used by the driver.  This is only used
+for ISA cards.  The irq to be used will match the irq in the same
+position in the irq list.  So basically ioport at index i will be used 
+with the irq at index i.
+.TP
+.BI irq= i,j,...
+Specifies the set of interrupts are used by the driver.
+.TP
+.BI rates= i,j,...
+A comma separted list of rates.  There are up to 8 of them.  They are
+specified in 512 kps units.
+.TP
+.BI basic_rate= n
+Sets the basic rate of the card.  Same units as the rates.  (It must
+be one of the rates.)
+.TP
+.BI ssids= i,j,k
+A commat separated list of ssids.  There can be up to 3.  They are a
+maximum of 32 characters.
+
+.SH SPECIFIC NOTES
+When used with PCMCIA cards, it must be used with the airo_cs module.
+
+.SH AUTHOR
+Benjamin C. Reed \- breed@almaden.ibm.com
+
+.SH SEE ALSO
+.BR airo_cs (4),
+.BR cardmgr (8),
+.BR pcmcia (5),
+.BR insmod (1),
Index: oldkernel/linux/pcmcia-cs-3.1.15/man/airo_cs.4
diff -u /dev/null linux/pcmcia-cs-3.1.15/man/airo_cs.4:1.1
--- /dev/null	Mon Jul 31 21:15:11 2000
+++ linux/pcmcia-cs-3.1.15/man/airo_cs.4	Fri Jul  7 16:34:58 2000
@@ -0,0 +1,34 @@
+.\" Copyright (c) 2000 Benjamin C. Reed <breed@almaden.ibm.com>
+.\" airo_cs.c.4
+.\"
+.TH AIRO_CS 4 "1/17/00" "IBM Almaden Research Center"
+
+.SH NAME
+airo_cs \- PCMCIA Services wrapper for Aironet PC4500&4800 cards
+
+.SH SYNOPSIS
+.B insmod airo_cs.o
+
+.SH DESCRIPTION
+.B airo_cs
+is the adapter to the 
+.B airo
+driver for Aironet PC4500 & PC4800 802.11 wireless ethernet cards.
+This driver must be loaded after
+.BR airo (4).
+It handles the events from Card Services since
+.B airo
+is not Card Services aware.
+
+.SH PARAMETERS
+
+None.
+
+.SH AUTHOR
+Benjamin C. Reed \- breed@almaden.ibm.com
+
+.SH SEE ALSO
+.BR airo (4),
+.BR cardmgr (8),
+.BR pcmcia (5),
+.BR insmod (1),
Index: oldkernel/linux/pcmcia-cs-3.1.15/man/cardctl.8
diff -u /dev/null linux/pcmcia-cs-3.1.15/man/cardctl.8:1.1
--- /dev/null	Mon Jul 31 21:15:11 2000
+++ linux/pcmcia-cs-3.1.15/man/cardctl.8	Fri Jul  7 16:34:58 2000
@@ -0,0 +1,100 @@
+.\" Copyright (C) 1998 David A. Hinds -- dhinds@pcmcia.sourceforge.org
+.\" cardctl.8 1.14 1999/10/25 19:50:45
+.\"
+.TH CARDCTL 8 "1999/10/25 19:50:45" "pcmcia-cs"
+.SH NAME
+cardctl \- PCMCIA card control utility
+.SH SYNOPSIS
+.B cardctl
+.RB [ -V ]
+.I command
+.RI [ socket ]
+.br
+.B cardctl
+.RB [ "\-c\ "\c
+.I config\c
+]
+.RB [ "\-f\ "\c
+.I scheme\c
+]
+.RB [ "\-s\ "\c
+.I stab\c
+]
+.B scheme
+.RI [ name ]
+.SH DESCRIPTION
+.B Cardctl
+is used to monitor and control the state of PCMCIA sockets.  If a
+socket number is specified, the command will be applied to just one
+socket; otherwise, all sockets will be affected.
+.PP
+.B Cardctl
+is also used to select between multiple PCMCIA configuration schemes.
+The current scheme name is passed to the device option scripts as part
+of the ``device address'', so the scripts can use it to choose between
+different setups.
+.PP
+If
+.B cardctl
+is executed by root, all commands are available.  If it is executed by
+an unpriviledged user, only the informational commands are accessible.
+.SH COMMANDS
+.TP \w'abcd'u
+.B status
+Display the current socket status flags.
+.TP
+.B config
+Display the socket configuration, including power settings, interrupt
+and I/O window settings, and configuration registers.
+.TP
+.B ident
+Display card identification information, including product
+identification strings, manufacturer ID codes, and function ID codes.
+.TP
+.B suspend
+Shut down and then disable power for a socket.
+.TP
+.B resume
+Restore power to a socket, and re-configure for use.
+.TP
+.B reset
+Send a reset signal to a socket, subject to approval by any drivers
+already bound to the socket.
+.TP
+.B eject
+Notify all client drivers that this card will be ejected, then cut
+power to the socket.
+.TP
+.B insert
+Notify all client drivers that this card has just been inserted.
+.TP
+.B scheme
+If no scheme name is given,
+.B cardctl
+will display the current PCMCIA configuration scheme.  If a scheme
+name is given,
+.B cardctl
+will unconfigure all PCMCIA devices, and reconfigure for the new
+scheme.
+.SH OPTIONS
+.TP
+.B \-V
+Show version information and exit.
+.TP
+.BI "\-c " config
+Look for the card configuration database and card configuration
+scripts in the specified directory, instead of 
+.IR /etc/pcmcia .
+.TP
+.BI "\-f " scheme
+Use the specified file to keep track of the current configuration
+scheme, instead of
+.IR /var/{state,lib}/pcmcia/scheme .
+.TP
+.BI "\-s " stab
+Read current socket information from the specified file, instead of
+.IR /var/{state,lib}/pcmcia/stab .
+.SH AUTHOR
+David Hinds \- dhinds@pcmcia.sourceforge.org
+.SH "SEE ALSO"
+cardmgr(8).
Index: oldkernel/linux/pcmcia-cs-3.1.15/man/cardinfo.1
diff -u /dev/null linux/pcmcia-cs-3.1.15/man/cardinfo.1:1.1
--- /dev/null	Mon Jul 31 21:15:11 2000
+++ linux/pcmcia-cs-3.1.15/man/cardinfo.1	Fri Jul  7 16:34:58 2000
@@ -0,0 +1,43 @@
+.\" Copyright (C) 1998 David A. Hinds -- dhinds@pcmcia.sourceforge.org
+.\" cardinfo.1 1.8 1999/12/21 22:53:16
+.\"
+.TH CARDINFO 1 "1999/12/21 22:53:16" "pcmcia-cs"
+.SH NAME
+cardinfo \- PCMCIA card monitor and control utility for X
+.SH SYNOPSIS
+.B cardinfo
+.SH DESCRIPTION
+.B Cardinfo
+displays the current configurations of all PCMCIA sockets in the
+system.  For each card, the display includes the card name, the card
+state, IO port and interrupt settings, and the names of any devices
+associated with that card.  Each socket also has a menu of commands
+for manipulating the socket state.
+.PP
+The socket state includes a row of abbreviated state flags.  The
+.B CD
+flag indicates that a card is detected in that socket.  The
+.B Vcc
+flag indicates that the socket is powered up.  The
+.B Vpp
+flag indicates that the programming power supply is active.  The
+.B WP
+flag indicates that the card is write protected.
+.PP
+Below the socket status data is a log of card status change events.
+The following events are logged: card insertion and removal, user
+insert and eject requests, suspend and resume, and socket resets.
+.PP
+The reset button below the socket displays sends a SIGHUP signal to
+.BR cardmgr ,
+causing all sockets to be reinitialized from scratch.
+.PP
+.B Cardinfo
+is setuid root so that it can create temporary device
+files for accessing the PCMCIA sockets.  An ordinary user will not be
+able to access any of the socket control functions.
+.SH AUTHOR
+David Hinds \- dhinds@pcmcia.sourceforge.org
+.SH "SEE ALSO"
+cardmgr(8), cardctl(8).
+
Index: oldkernel/linux/pcmcia-cs-3.1.15/man/cardmgr.8
diff -u /dev/null linux/pcmcia-cs-3.1.15/man/cardmgr.8:1.1
--- /dev/null	Mon Jul 31 21:15:11 2000
+++ linux/pcmcia-cs-3.1.15/man/cardmgr.8	Fri Jul  7 16:34:58 2000
@@ -0,0 +1,146 @@
+.\" Copyright (C) 1998 David A. Hinds -- dhinds@pcmcia.sourceforge.org
+.\" cardmgr.8 1.35 2000/03/15 02:00:44
+.\"
+.TH CARDMGR 8 "2000/03/15 02:00:44" "pcmcia-cs"
+.SH NAME
+cardmgr \- PCMCIA device manager
+.SH SYNOPSIS
+.B cardmgr
+.RB [ -V ]
+.RB [ -q ]
+.RB [ -d ]
+.RB [ -o ]
+.RB [ -f ]
+.RB [ -v ]
+.RB [ "\-c\ "\c
+.I configpath\c
+]
+.RB [ "\-m\ "\c
+.I modpath\c
+]
+.RB [ "\-p\ "\c
+.I pidfile\c
+]
+.RB [ "\-s\ "\c
+.I stabfile\c
+]
+.SH DESCRIPTION
+.B Cardmgr
+monitors PCMCIA sockets for card insertion and removal events.  When a
+card is inserted,
+.B cardmgr
+looks up the card in a database of known cards.  If the card can be
+identified, appropriate device drivers will be loaded and bound to the
+card.  When a card is ejected, that card's drivers will be shut down
+and unloaded if possible.  Based on the contents of the PCMCIA card
+configuration database,
+.B cardmgr
+may also execute arbitrary commands when appropriate cards are either
+inserted or removed.
+.PP
+All insertion and removal events, device driver loads and unloads, and
+startup and shutdown commands are reported in the system log file.
+Warnings and errors will also be logged.  Current card and device
+information for each socket is recorded in
+.I /var/state/pcmcia/stab
+or
+.IR /var/lib/pcmcia/stab .
+.PP
+Normally, when a card is identified,
+.I cardmgr
+will send a beep to the console.  A beep is also generated when a card
+is successfully configured.  A beep of lower pitch is generated if
+either of these steps fails.  Ejecting a card produces a single beep.
+.PP
+When
+.B cardmgr
+receives a
+.B SIGHUP
+signal, it will reload its configuration file.  When
+.B cardmgr
+receives a
+.B SIGTERM
+signal, it will shut down all sockets that are not busy and then
+exit, but drivers for busy sockets will stay loaded.
+.PP
+If the
+.B PCMCIA_OPTS
+environment variable is set, its contents will be parsed after the
+main card configuration file is read.
+.PP
+At startup,
+.B cardmgr
+requires that
+.I /tmp
+reside on a filesystem that permits special device files (i.e., a real
+linux filesystem, that is not mounted "nodev").
+.SH OPTIONS
+.TP
+.B \-V
+Show version information and exit.
+.TP
+.B \-q
+Quiet mode: don't beep when cards are inserted.
+.TP
+.B \-v
+Verbose mode: generates more informational messages during normal
+operation.
+.TP
+.B \-d
+Follow module dependencies when loading driver modules, by defaulting
+to use
+.B modprobe
+instead of
+.BR insmod .
+Normally,
+.B cardmgr
+will try using
+.B modprobe
+only after an unsuccessful attempt with
+.BR insmod .
+.TP
+.B \-f
+Foreground: do not fork and run as a daemon until after configuring
+any cards that are already present.
+.TP
+.B \-o
+One pass: configure cards that are present, then exit.  This flag
+also forces
+.B cardmgr
+to run in the foreground.
+.TP
+.BI "\-c " configpath
+Look for the card configuration database and card configuration
+scripts in the specified directory, instead of 
+.IR /etc/pcmcia .
+.TP
+.BI "\-m " modpath
+Look for loadable kernel modules in the specified directory, instead
+of
+.IR /lib/modules/`uname -r` .
+.TP
+.BI "\-p " pidfile
+Write the PID of the cardmgr process to the specified file, instead of
+.IR /var/run/cardmgr.pid .
+.TP
+.BI "\-s " stabfile
+Write current socket information to the specified file, instead of
+.IR /var/{state,lib}/pcmcia/stab .
+.SH FILES
+.PD 0
+.TP \w'/etc/pcmcia/config.opts\ \ \ \|\|'u
+/etc/pcmcia/config
+Card configuration database
+.TP
+/etc/pcmcia/config.opts
+Local resource settings for PCMCIA devices
+.TP
+/var/run/cardmgr.pid
+PID of active cardmgr process
+.TP
+/var/{state,lib}/pcmcia/stab
+Current card and device information for each socket.
+.SH AUTHOR
+David Hinds \- dhinds@pcmcia.sourceforge.org
+.SH "SEE ALSO"
+pcmcia(5), stab(5), cardctl(8), cardinfo(1).
Index: oldkernel/linux/pcmcia-cs-3.1.15/man/dummy_cs.4
diff -u /dev/null linux/pcmcia-cs-3.1.15/man/dummy_cs.4:1.1
--- /dev/null	Mon Jul 31 21:15:11 2000
+++ linux/pcmcia-cs-3.1.15/man/dummy_cs.4	Fri Jul  7 16:34:58 2000
@@ -0,0 +1,55 @@
+.\" Copyright (C) 1998 David A. Hinds -- dhinds@pcmcia.sourceforge.org
+.\" dummy_cs.4 1.6 1999/10/25 19:50:45
+.\"
+.TH DUMMY_CS 4 "1999/10/25 19:50:45" "pcmcia-cs"
+.SH NAME
+dummy_cs \- PCMCIA dummy device driver
+.SH SYNOPSIS
+.B insmod dummy_cs.o
+.RB [ pc_debug=\c
+.IR n ]
+.RB [ free_ports=\c
+.IR n ]
+.RB [ irq_list=\c
+.IR i,j,... ]
+.SH DESCRIPTION
+The
+.B dummy_cs
+module has two purposes.  It is intended as a demonstration of how to
+write the PCMCIA interface code for a client driver, and the source
+code is heavily commented.  It is also written to function as a sort
+of generic ``point enabler'': when bound to any PCMCIA IO card, it
+will read the card's Configuration Information Structure, and
+configure the card appropriately.  The configuration includes setting
+up IO and memory windows, configuring the card for interrupts, and
+initializing the card's PCMCIA configuration registers.
+.PP
+It turns out that many cards report incomplete or inaccurate
+configuration information, due to vendor carelessness and the
+complexity of the data format.  A vendor driver can generally take
+for granted many configuration details, so there is not much incentive
+for vendors to ensure that the on-card information is complete.  Thus,
+the
+.B dummy_cs
+module is limited by its generality: since it makes no assumptions
+about card types, it is forced to rely on the card information, for
+better or worse.
+.SH PARAMETERS
+.TP
+.BI pc_debug= n
+Selects the PCMCIA debugging level.  This parameter is only available
+if the module is compiled with debugging enabled.  A non-zero value
+enables debugging.
+.TP
+.BI free_ports= n
+A flag indicating if the IO ports allocated for the card should be
+freed from the kernel resource maps.  This is useful if the dummy
+driver is being used to configure a card in preparation for loading a
+specific PCMCIA-unaware driver.  The default is 0 (false).
+.TP
+.BI irq_list= i,j,...
+Specifies the set of interrupts that may be allocated by this driver.
+.SH AUTHOR
+David Hinds \- dhinds@pcmcia.sourceforge.org
+.SH "SEE ALSO"
+cardmgr(8), pcmcia(5).
Index: oldkernel/linux/pcmcia-cs-3.1.15/man/dump_cis.8
diff -u /dev/null linux/pcmcia-cs-3.1.15/man/dump_cis.8:1.1
--- /dev/null	Mon Jul 31 21:15:11 2000
+++ linux/pcmcia-cs-3.1.15/man/dump_cis.8	Fri Jul  7 16:34:58 2000
@@ -0,0 +1,48 @@
+.\" Copyright (C) 1998 David A. Hinds -- dhinds@pcmcia.sourceforge.org
+.\" dump_cis.8 1.4 1999/12/21 22:41:19
+.\"
+.TH DUMP_CIS 8 "1999/12/21 22:41:19" "pcmcia-cs"
+.SH NAME
+dump_cis \- display PCMCIA Card Information Structures
+.SH SYNOPSIS
+.B dump_cis
+.RB [ -f ]
+.RB [ -v ]
+.RB [ "\-i\ "\c
+.I infile\c
+]
+.SH DESCRIPTION
+.B Dump_cis
+retrieves and parses the Card Information Structures for inserted
+PCMCIA devices, or optionally, parses CIS information from a file.
+.PP
+The
+.B pack_cis
+utility can parse a subset of the non-verbose output
+of
+.BR dump_cis ,
+so it is fairly easy to use
+.B dump_cis
+output as templates for
+.BR pack_cis .
+If a replacement CIS has been loaded for a card,
+.B dump_cis
+will display the replacement rather than the actual data on the card.
+.SH OPTIONS
+.TP
+.B \-f
+Force: attempt to decode any available CIS information even if the
+overall CIS organization appears to be invalid.
+.TP
+.B \-v
+Verbose output: display raw hex data for each tuple, and provide a
+more complete dump of some tuple types.
+.TP
+.BI "\-i " infile
+Read packed CIS data from a file (as created by
+.BR pack_cis )
+instead of reading from active cards.
+.SH AUTHOR
+David Hinds \- dhinds@pcmcia.sourceforge.org
+.SH "SEE ALSO"
+pack_cis(8).
Index: oldkernel/linux/pcmcia-cs-3.1.15/man/fmvj18x_cs.4
diff -u /dev/null linux/pcmcia-cs-3.1.15/man/fmvj18x_cs.4:1.1
--- /dev/null	Mon Jul 31 21:15:11 2000
+++ linux/pcmcia-cs-3.1.15/man/fmvj18x_cs.4	Fri Jul  7 16:34:58 2000
@@ -0,0 +1,46 @@
+y.\" Copyright (c) 1996 Shingo Fujimoto <shingo@flab.fujitsu.co.jp>
+.\" fmvj18x_cs.4,v 1.4 1999/02/08 08:02:01 root Exp
+.\"
+.TH FMVJ18x_CS 4 "1999/02/08 08:02:01" ""
+.SH NAME
+fmvj18x_cs \- Fujitsu FMV-J18x series device driver
+.SH SYNOPSIS
+.B insmod fmvj18x_cs.o
+.RB [ pc_debug=\c
+.IR n ]
+.RB [ fmvj18x_debug=\c
+.IR n ]
+.RB [ irq_list=\c
+.IR i,j,... ]
+.SH DESCRIPTION
+.B fmvj18x_cs
+is the low-level Card Services driver for the Fujitsu FMV-J18x
+series PCMCIA ethernet adapter.  When this driver is attached to a card, it
+allocates the next available ethernet device
+.RB ( eth0 .. eth# ).
+This
+device name will be reported in the kernel log file, and passed on to
+.BR cardmgr (8).
+.SH PARAMETERS
+.TP
+.BI pc_debug= n
+Selects the PCMCIA debugging level.  This parameter is only available
+if the module is compiled with debugging enabled.  A non-zero value
+enables debugging.
+.TP
+.BI fmvj18x_debug= n
+Selects the network debugging level.  The current default is 3; values
+of up to six increase reporting verbosity.
+.TP
+.BI irq_list= i,j,...
+Specifies the set of interrupts that may be allocated by this driver.
+.SH AUTHOR
+Shingo Fujimoto \- Fujitsu Laboratories Ltd.
+<Shingo@flab.fujitsu.co.jp>
+.SH THANKS
+.TP 
+Yutaka TAMIYA \- Fujitsu Laboratories Ltd.
+.TP 
+Hideaki Yoda \- Fujitsu Limited.
+.SH "SEE ALSO"
+cardmgr(8), pcmcia(5).
Index: oldkernel/linux/pcmcia-cs-3.1.15/man/ftl_check.8
diff -u /dev/null linux/pcmcia-cs-3.1.15/man/ftl_check.8:1.1
--- /dev/null	Mon Jul 31 21:15:11 2000
+++ linux/pcmcia-cs-3.1.15/man/ftl_check.8	Fri Jul  7 16:34:58 2000
@@ -0,0 +1,20 @@
+.\" Copyright (C) 1998 David A. Hinds -- dhinds@pcmcia.sourceforge.org
+.\" ftl_check.1 1.6 1999/10/25 19:50:46
+.\"
+.TH FTL_CHECK 1 "1999/10/25 19:50:46" "pcmcia-cs"
+.SH NAME
+ftl_check \- Flash Translation Layer format checker
+.SH SYNOPSIS
+.B ftl_check
+.I device
+.SH DESCRIPTION
+.B Ftl_check
+dumps a lot of bookkeeping information for a Flash Translation Layer
+partition.  It needs to access the flash partition's raw character-mode
+device (such as
+.IR /dev/mem0c0c ).
+It cannot actually fix formatting problems.
+.SH AUTHOR
+David Hinds \- dhinds@pcmcia.sourceforge.org
+.SH "SEE ALSO"
+ftl_format(8).
Index: oldkernel/linux/pcmcia-cs-3.1.15/man/ftl_cs.4
diff -u /dev/null linux/pcmcia-cs-3.1.15/man/ftl_cs.4:1.1
--- /dev/null	Mon Jul 31 21:15:11 2000
+++ linux/pcmcia-cs-3.1.15/man/ftl_cs.4	Fri Jul  7 16:34:58 2000
@@ -0,0 +1,54 @@
+.\" Copyright (C) 1998 David A. Hinds -- dhinds@pcmcia.sourceforge.org
+.\" ftl_cs.4 1.10 1999/10/25 19:50:46
+.\"
+.TH FTL_CS 4 "1999/10/25 19:50:46" "pcmcia-cs"
+.SH NAME
+ftl_cs \- Flash Translation Layer driver for PCMCIA memory cards
+.SH SYNOPSIS
+.B insmod ftl_cs.o
+.RB [ pc_debug=\c
+.IR n ]
+.RB [ major_dev=\c
+.IR n ]
+.SH DESCRIPTION
+Flash memory devices typically need to be erased before they are
+written, and most flash devices can only be erased on large block
+boundaries like 64K or 128K.  The Flash Translation Layer driver, 
+.BR ftl_cs ,
+implements a sort of virtual sector-addressable block device that
+hides the details of erase operations.  Using the FTL driver, a flash
+memory card can be treated as an ordinary block device.
+.PP
+The
+.B ftl_cs
+driver allocates a major device number when it is loaded.  Minor
+device numbers have a bitwise layout of 'dddrrppp'.  'ddd' is the
+device number, with one card counting as one device.  'rr' is the
+common-memory region number, generally 0.  And 'ppp' selects a logical
+partition within the FTL region.
+.PP
+The default configuration script for FTL devices will create a block
+device with the name of the form '/dev/ftl{d}c{r}', where '{d}' is the
+device number and '{r}' is the region number, that spans the
+entire FTL region.  It also creates devices '/dev/ftl{d}c{r}p[1-4]'
+pointing to partitions 1 through 4 within this FTL region. 
+.PP
+An FTL region must be formatted before use.  The formatting
+utility,
+.BR ftl_format ,
+needs to write to the corresponding raw memory device rather than the
+FTL device interface.
+.SH PARAMETERS
+.TP
+.BI pc_debug= n
+Selects the PCMCIA debugging level.  This parameter is only available
+if the module is compiled with debugging enabled.  A non-zero value
+enables debugging.
+.TP
+.BI major_dev= n
+Selects the major device number to allocate for FTL devices.  The
+default is to pick any available major number.
+.SH AUTHOR
+David Hinds \- dhinds@pcmcia.sourceforge.org
+.SH "SEE ALSO"
+ftl_format(8), cardmgr(8), memory_cs(4), pcmcia(5).
Index: oldkernel/linux/pcmcia-cs-3.1.15/man/ftl_format.8
diff -u /dev/null linux/pcmcia-cs-3.1.15/man/ftl_format.8:1.1
--- /dev/null	Mon Jul 31 21:15:11 2000
+++ linux/pcmcia-cs-3.1.15/man/ftl_format.8	Fri Jul  7 16:34:58 2000
@@ -0,0 +1,69 @@
+.\" Copyright (C) 1998 David A. Hinds -- dhinds@pcmcia.sourceforge.org
+.\" ftl_format.1 1.9 1999/10/25 19:50:46
+.\"
+.TH FTL_FORMAT 1 "1999/10/25 19:50:46" "pcmcia-cs"
+.SH NAME
+ftl_format \- Flash Translation Layer formatting utility
+.SH SYNOPSIS
+.B ftl_format
+.RB [ -q ]
+.RB [ -i ]
+.RB [ "\-s "\c
+.IR spare ]
+.RB [ "\-r "\c
+.IR reserve ]
+.RB [ "\-b "\c
+.IR bootsize ]
+.I device
+.SH DESCRIPTION
+.B Ftl_format
+creates a Flash Translation Layer partition on a flash memory device.   
+It needs to access the flash partition's raw character-mode device
+(such as
+.IR /dev/mem0c0c ).
+.PP
+This is actually a low-level format operation, required before
+accessing a memory device via the FTL block device driver.  Once a
+partition is prepared with
+.BR ftl_format ,
+a filesystem should be created in a separate step.  Filesystem
+commands should access the device via the FTL device file (such as
+.IR /dev/ftl0 ).
+.PP
+Optionally,
+.B ftl_format
+can reserve a region at the beginning of the flash card address space
+for a boot image (or any other purpose).  The boot area is not part of
+the FTL partition, and can only be accessed via the raw memory device.
+.PP
+On Intel Series 100 flash cards, the first flash block is used to
+store the card's configuration information structures.  If no boot
+area is specified on the command line,
+.B ftl_format
+will automatically create one to span the first block.
+.SH OPTIONS
+.TP
+.B \-q
+Quiet mode: don't print formatting statistics.
+.TP
+.B \-i
+Interactive: confirm before beginning the format.
+.TP
+.BI "\-s " spare
+Reserve the specified number of erase blocks as spares.  The default
+is 1.  A read-write partition requires at least one spare block.
+.TP
+.BI "\-r " reserve
+Reserve the specified percentage of the total space on the device to
+improve write efficiency.  The default is 5%.  Reserving less space
+increases the frequency of flash erase operations to reclaim free
+blocks.
+.TP
+.BI "\-b " bootsize
+Requests that a portion of the flash card be reserved for a boot
+image.  The size will be rounded up to an integral number of erase
+blocks.
+.SH AUTHOR
+David Hinds \- dhinds@pcmcia.sourceforge.org
+.SH "SEE ALSO"
+ftl_cs(4), ftl_check(8).
Index: oldkernel/linux/pcmcia-cs-3.1.15/man/i82365.4
diff -u /dev/null linux/pcmcia-cs-3.1.15/man/i82365.4:1.1
--- /dev/null	Mon Jul 31 21:15:11 2000
+++ linux/pcmcia-cs-3.1.15/man/i82365.4	Fri Jul  7 16:34:58 2000
@@ -0,0 +1,290 @@
+.\" Copyright (C) 1998 David A. Hinds -- dhinds@pcmcia.sourceforge.org
+.\" i82365.4 1.34 2000/04/03 20:04:01
+.\"
+.TH I82365 4 "2000/04/03 20:04:01" "pcmcia-cs"
+.SH NAME
+i82365 \- Intel i82365sl PCMCIA controller driver
+
+.SH SYNOPSIS
+.B insmod i82365.o
+.RB [ pc_debug=\c
+.IR n ]
+.RB [ i365_base=\c
+.IR n ]
+.RB [ ignore=\c
+.IR n ]
+.RB [ extra_sockets=\c
+.IR n ]
+.RB [ do_scan=\c
+.IR n ]
+.RB [ irq_list=\c
+.IR i,j,... ]
+.RB [ cs_irq=\c
+.IR n ]
+.RB [ poll_interval=\c
+.IR n ]
+.RB [ cycle_time=\c
+.IR n ]
+.RB [ do_pci_probe=\c
+.IR n ]
+.RB [ cb_write_post=\c
+.IR n ]
+.RB [ pci_csc=\c
+.IR n ]
+.RB [ pci_int=\c
+.IR n ]
+.RB [ pci_irq_list=\c
+.IR i,j,... ]
+.RB [ has_dma=\c
+.IR n ]
+.RB [ has_led=\c
+.IR n ]
+.RB [ has_ring=\c
+.IR n ]
+.RB [ freq_bypass=\c
+.IR n ]
+.RB [ setup_time=\c
+.IR n ]
+.RB [ cmd_time=\c
+.IR n ]
+.RB [ recov_time=\c
+.IR n ]
+.RB [ wakeup=\c
+.IR n ]
+.RB [ fast_pci=\c
+.IR n ]
+.RB [ async_clock=\c
+.IR n ]
+.RB [ cable_mode=\c
+.IR n ]
+.RB [ irq_mode=\c
+.IR n ]
+.RB [ p2cclk=\c
+.IR n ]
+
+.SH DESCRIPTION
+This is the low-level driver for the Intel i82365sl PCMCIA host
+controller, and many derivative controllers.  It also implements the
+Intel "Yenta" register specification for CardBus bridges.  Common
+clones of the i82365sl include controllers made by Cirrus Logic, IBM, 
+O2Micro, Omega Micro, Ricoh, SMC, Texas Instruments, Toshiba, Vadem,
+and VLSI.  The overwhelming majority of current PCMCIA controllers,
+and all CardBus bridges, are register compatible with the i82365sl.
+This driver is used by Card Services for configuring the host
+controller, and for monitoring card status change events.
+.PP
+An ISA i82365-compatible controller normally sits at the IO addresses
+0x3e0-0x3e1.  Two ISA controllers can cooperate to share the same IO
+ports, supporting a total of four sockets.  A second pair of
+controllers can be located at 0x3e2-0x3e3.  Probing at this position
+is controlled by the \fBextra_sockets\fR parameter.  This only affects
+ISA bridges: the PCI bridge probe handles multiple controllers
+automatically.  The driver will support a maximum of eight sockets. 
+
+.SH CardBus interrupt delivery
+CardBus bridges generally support both PCI and ISA interrupt signals,
+and multiple methods of deliving interrupt events to the host system.
+The system BIOS is partly responsible for correctly configuring the
+bridge to match the implemented interrupt hardware at boot time.  This
+module provides several parameters for overriding this default
+interrupt configuration.  The \fBpci_int\fR and \fBpci_csc\fR settings
+can be used to control use of PCI interrupts for card interrupts or
+card status changes.  The \fBirq_mode\fR setting, for bridges that
+support it, can be used to select an interrupt delivery method.
+.PP
+When the \fBi82365\fR module is loaded, it performs a scan of free
+ISA interrupts to determine which ones appear to be usable for PCMCIA
+events.  The interrupt scan results are reported in the system log.  A
+successful scan will report a list of interrupts as ``scanned''; if no
+interrupts appear to work, then a ``default'' list is reported.  Some
+bridges (Cirrus non-CardBus bridges, some Toshiba bridges) do not
+support the software interrupt test and will always report a
+``default'' list.  In other cases, this may be a sign of an incorrect
+\fBirq_mode\fR.
+
+.SH PARAMETERS
+.TP
+.BI pc_debug= n
+Selects the PCMCIA debugging level.  This parameter is only available
+if the module is compiled with debugging enabled.  A non-zero value
+enables debugging.
+.TP
+.BI i365_base= n
+Sets the base I/O port address of the i82365sl chip.  The default is
+0x3e0.  Applies only to ISA-to-PCMCIA bridges.
+.TP
+.BI ignore= n
+Causes the driver to ignore a single socket.  Sockets are numbered
+starting at 0.  The socket will be left in whatever state it was
+already in, so it can be used for cards with point enablers that do
+not cooperate with Card Services.
+.TP
+.BI extra_sockets= n
+A flag indicating if the driver should probe for as many as eight ISA
+sockets, or stop after checking for four sockets.  The default is
+0 (stop at four sockets).  Systems with two independent ISA-to-PCMCIA
+controllers (say, one internal and one in a docking station) may
+require this flag to be set, even though they have a total of only
+four sockets.  If this flag is set, then
+.BR poll_interval
+will automatically be enabled.
+.TP
+.BI do_scan= n
+This flag specifies that all free ISA interrupts should be tested to
+see if they can be triggered by the PCMCIA controller.  The default is
+1 (true).
+.TP
+.BI irq_list= i,j,...
+Specifies the set of interrupts that may be allocated by this driver,
+if they are otherwise available.
+The default list is 3, 4, 5, 7, 9, 10, 11, 12, 14, and 15.
+.TP
+.BI cs_irq= n
+Sets the interrupt line to use for monitoring card status changes.
+The default is 0, which means pick the highest-numbered legal
+interrupt not already in use.  Legal values are 15, 14, 12, 11,
+10, 9, 7, 5, 4, and 3.
+.TP
+.BI poll_interval= n
+Sets the card status polling delay, in 1/100 second increments.  If
+this parameter is set, card status interrupts will be disabled.  A
+reasonable value is 100.  Polling only affects detection of card
+insert and eject events.
+.TP
+.BI cycle_time= n
+Sets the length of a host bus cycle, in nanoseconds.  The default is
+210 ns, corresponding to a standard 4.77 MHz clock.
+
+.SH Options for CardBus controllers
+.TP
+.BI do_pci_probe= n
+This flag indicates if the PCI bus should be probed for PCI-to-PCMCIA
+and/or PCI-to-CardBus bridges.  The default is 1 (true).
+.TP
+.BI cb_write_post= n
+A flag indicating if write posting (a performance feature) should be
+enabled.  The default is 1 (true), except on certain TI 1130 bridges.
+.TP
+.BI pci_csc= n
+Specifies that card status change interrupts should be routed to PCI
+interrupts, for CardBus controllers.  The default is 1 (true).
+.TP
+.BI pci_int= n
+Specifies that functional interrupts for IO cards should be routed to
+PCI interrupts, for CardBus controllers.  The default is 1 (true),
+except on systems that require use of PCI interrupts.
+.TP
+.BI pci_irq_list = i,j,...
+The Linux kernel sometimes cannot deduce the PCI interrupt assignments
+for CardBus sockets.  If this information can be determined some other
+way, it can be entered here.  The Nth socket will get the Nth
+interrupt number from the list. 
+
+.SH Options specific for Cirrus controllers
+When the
+.B i82365
+driver is loaded, it will try to determine what interrupts can safely
+be allocated for use by PCMCIA devices.  Cirrus controllers support
+some optional features that interfere with the use of certain
+interrupt lines.  Cirrus chips also lack the functionality needed to
+detect whether or not an interrupt can be used.  The
+.BR has_dma ,
+.BR has_ring ,
+and
+.B has_led
+options are used to specify if these features are implemented.
+.TP
+.BI has_dma= n
+A flag indicating if the controller has DMA support.
+.TP
+.BI has_led= n
+A flag indicating if the controller is wired for a disk status LED.
+This is set by default.
+.TP
+.BI has_ring= n
+A flag indicating if the controller's "ring indicate" signal is
+implemented.  This is set by default.
+.TP
+.BI freq_bypass= n
+A flag indicating that the controller should be set up in "frequency
+bypass" mode.  This disables the normal 7/4 clock multiplier, and
+slows down all PCMCIA bus access, for systems with fast system clocks.
+.TP
+.BI setup_time= n
+Sets the bus setup time, in internal clock cycles. The default is 1.
+.TP
+.BI cmd_time= n
+Sets the bus command time, in internal clock cycles. The default is 6.
+.TP
+.BI recov_time= n
+Sets the bus recovery time, in internal clock cycles. The default is 0.
+.TP
+.BI wakeup= n
+A flag indicating if the probe function should attempt to wake up a
+suspended controller chip.  The default is 0.
+.TP
+.BI fast_pci= n
+A flag for the PD6729 PCI controller, indicating that the PCI bus
+speed exceeds 25 MHz.
+.TP
+.BI irq_mode= n
+For the PD6729 PCI controller, specifies the interrupt delivery mode.
+The default is to use ISA bus interrupts; a value of 1 selects PCI
+interrupts.  This must be set for correct operation of some PCI card
+readers.
+
+.SH Options specific for Ricoh CardBus controllers
+.TP
+.BI irq_mode= n
+Selects the interrupt routing method.  A value of 1 selects ISA
+interrupt routing, and 2 selects interrupt routing via an external
+serial interrupt controller.  The default is to use whatever routing
+method is already enabled.
+.TP
+.BI setup_time= n
+Sets the bus setup time, in internal clock cycles. The default is 3.
+.TP
+.BI cmd_time= n
+Sets the bus command time, in internal clock cycles. The default is 6.
+.TP
+.BI hold_time= n
+Sets the bus hold time, in internal clock cycles. The default is 1.
+
+.SH Options specific for Vadem ISA controllers
+.TP
+.BI async_clock= n
+This flag specifies that PCMCIA bus cycles should be clocked
+asynchronously from host bus cycles.  It effectively adds a wait state
+to some operations.
+.TP
+.BI cable_mode= n
+For the VG469, this flag adjusts certain socket signals for driving a
+socket connected via a cable.
+
+.SH Options specific for TI CardBus controllers
+Normally, a system's BIOS will configure these options appropriately,
+so all these options default to leaving these features configured the
+way the driver finds them.
+.TP
+.BI has_ring= n
+A flag indicating if the controller is wired for "ring indicate".
+The default is to read the current setting from the controller.
+.TP
+.BI irq_mode= n
+Selects the interrupt routing method.  A value of 0 selects only PCI
+interrupts; 1 selects ISA interrupt routing; 2 selects ISA interrupt
+routing via an external serial interrupt controller; and 3 selects
+serial routing for both PCI and ISA interrupts.  The default is to use
+whatever routing  method is already active, or ISA routing if no
+method is enabled.
+.TP
+.BI p2cclk= n
+A flag, indicating if the P2CCLK pin should be configured as an input
+(0) or an output (1).  This signal is used for communicating with a
+socket power controller; if set incorrectly, the bridge will be unable
+to power up cards.  The default is to use the BIOS setting.
+
+.SH AUTHOR
+David Hinds \- dhinds@pcmcia.sourceforge.org
+.SH "SEE ALSO"
+cardmgr(8), pcmcia(5).
Index: oldkernel/linux/pcmcia-cs-3.1.15/man/ibmtr_cs.4
diff -u /dev/null linux/pcmcia-cs-3.1.15/man/ibmtr_cs.4:1.1
--- /dev/null	Mon Jul 31 21:15:11 2000
+++ linux/pcmcia-cs-3.1.15/man/ibmtr_cs.4	Fri Jul  7 16:34:58 2000
@@ -0,0 +1,58 @@
+.\" Copyright (C) 1998 David A. Hinds -- dhinds@pcmcia.sourceforge.org
+.\" ibmtr_cs.4 1.4 1999/10/25 19:50:46
+.\"
+.TH IBMTR_CS 4 "1999/10/25 19:50:46" "pcmcia-cs"
+.SH NAME
+ibmtr_cs \- IBM Token Ring PCMCIA device driver
+.SH SYNOPSIS
+.B insmod ibmtr_cs.o
+.RB [ pc_debug=\c
+.IR n ]
+.RB [ mmiobase=\c
+.IR n ]
+.RB [ srambase=\c
+.IR n ]
+.RB [ ringspeed=\c
+.IR n ]
+.RB [ irq_list=\c
+.IR i,j,... ]
+.SH DESCRIPTION
+.B ibmtr_cs
+is the low-level Card Services driver for the IBM Token Ring network
+adapter and a few very similar cards.  When this driver is attached to
+a card, it allocates the next available token ring interface
+.RB ( tr0 .. tr# ).
+This
+device name will be reported in the kernel log file, and passed on to
+.BR cardmgr (8).
+.P
+Due to awkward design of the kernel ibmtr driver, the shared packet
+memory for these cards must be mapped to a memory address below 1MB or
+0x100000.  The PCMCIA software will attempt to do this automatically,
+but the automatic algorithm may choose values that conflict with other
+system devices, so a manual override with the
+.B srambase
+parameter may be required.  The memory-mapped IO window generally will
+not be a problem.
+.SH PARAMETERS
+.TP
+.BI pc_debug= n
+Selects the PCMCIA debugging level.  This parameter is only available
+if the module is compiled with debugging enabled.  A non-zero value
+enables debugging.
+.TP
+.BI mmiobase= n
+Specifies a fixed address for the card's memory mapped IO window.  The
+default is to select any available memory window.
+.TP
+.BI srambase= n
+Specifies a fixed address for the card's shared packet memory.  The
+default is to select any available window below 1MB.
+.TP
+.BI ringspeed= n
+Selects the network speed, in mb/sec.  Valid values are 4 or 16, and
+the default is 16.
+.SH AUTHOR
+David Hinds \- dhinds@pcmcia.sourceforge.org
+.SH "SEE ALSO"
+cardmgr(8), pcmcia(5), ifport(8).
Index: oldkernel/linux/pcmcia-cs-3.1.15/man/ide_info.8
diff -u /dev/null linux/pcmcia-cs-3.1.15/man/ide_info.8:1.1
--- /dev/null	Mon Jul 31 21:15:11 2000
+++ linux/pcmcia-cs-3.1.15/man/ide_info.8	Fri Jul  7 16:34:58 2000
@@ -0,0 +1,23 @@
+.\" Copyright (C) 1998 David A. Hinds -- dhinds@pcmcia.sourceforge.org
+.\" ide_info.8 1.5 1999/10/25 19:50:46
+.\"
+.TH IDE_INFO 8 "1999/10/25 19:50:46" "pcmcia-cs"
+.SH NAME
+ide_info \- IDE device description tool
+.SH SYNOPSIS
+.B ide_info
+.I device
+.SH DESCRIPTION
+.B Ide_info
+opens the specified IDE device file, and retrieves its device
+identification information.  Its
+output is a set of Bourne-style shell commands to define the
+.BR MODEL ,
+.BR FW_REV ,
+and
+.B SERIAL_NO
+variables based on this information.  The PCMCIA configuration script
+for IDE-type devices uses this utility so that the serial number can
+be used to specify configurations for particular cards.
+.SH AUTHOR
+David Hinds \- dhinds@pcmcia.sourceforge.org
Index: oldkernel/linux/pcmcia-cs-3.1.15/man/iflash2+_mtd.4
diff -u /dev/null linux/pcmcia-cs-3.1.15/man/iflash2+_mtd.4:1.1
--- /dev/null	Mon Jul 31 21:15:11 2000
+++ linux/pcmcia-cs-3.1.15/man/iflash2+_mtd.4	Fri Jul  7 16:34:58 2000
@@ -0,0 +1,108 @@
+.\" Copyright (C) 1998 David A. Hinds -- dhinds@pcmcia.sourceforge.org
+.\" iflash2_mtd.4 1.7 2000/04/21 19:30:55
+.\"
+.TH IFLASH2_MTD 4 "2000/04/21 19:30:55" "pcmcia-cs"
+
+.SH NAME
+iflash2+_mtd \- memory technology driver for Intel Series 2+ flash
+
+.SH SYNOPSIS
+.B insmod iflash2+_mtd.o
+.RB [ pc_debug=\c
+.IR n ]
+.RB [ mem_speed=\c
+.IR n ]
+.RB [ word_width=\c
+.IR n ]
+.RB [ vpp_timeout_period=\c
+.IR n ]
+.RB [ vpp_settle=\c
+.IR n ]
+.RB [ erase_timeout=\c
+.IR n ]
+.RB [ erase_limit=\c
+.IR n ]
+.RB [ retry_limit=\c
+.IR n ]
+.RB [ max_tries=\c
+.IR n ]
+.RB [ mem_speed=\c
+.IR n ]
+.RB [ word_width=\c
+.IR n ]
+.RB [ do_sleep=\c
+.IR n ]
+
+.SH DESCRIPTION
+.B Iflash2+_mtd
+is a memory technology driver for Intel Series 2+ flash devices.
+Memory technology drivers are used by Card Services to provide
+device-independent access for memory cards through bulk memory
+services.
+.PP
+In addition to backwards compatibility with Series 2 flash devices,
+Series 2+ devices provide fast page-mode transfers, which allow
+sequential flash writes to proceed in the background without active
+monitoring.  While faster than Series 2 cards in actual write speeds,
+this means that Series 2+ cards also do not tie up the host processor
+while writes are in progress.  By default, the driver sleeps while
+waiting for writes to complete.  For even faster write throughput, at
+the expense of higher CPU utilization, the driver can optionally poll
+for write completion.  The \fBdo_sleep\fR parameter determines which
+mode is used.
+
+.SH PARAMETERS
+.TP
+.BI pc_debug= n
+Selects the PCMCIA debugging level.  This parameter is only available
+if the module is compiled with debugging enabled.  A non-zero value
+enables debugging.
+.TP
+.BI mem_speed= n
+Sets the access speed of shared memory windows, in nanoseconds.  The
+default is 0 (i.e., no extra wait states).  Values of up to 1000 are
+legal.
+.TP
+.BI word_width= n
+A flag indicating if memory windows should be configured for
+8-bit (if 0) or 16-bit (if 1) transfers.  The default is 1 (16-bit).
+.TP
+.BI vpp_timeout_period= n
+In milliseconds, this specifies the maximum idle period after a write
+operation before programming power will be switched off.  The default
+is 1000 ms.
+.TP
+.BI vpp_settle= n
+In milliseconds, this gives a delay between when programming power is
+switched on, and when the device is assumed to be powered up and ready
+to receive erase or write commands.  The default is 100 ms.
+.TP
+.BI write_timeout= n
+In milliseconds, specifies the maximum elapsed time for a page write
+(256 words) before it times out.  The default is 100 ms.
+.TP
+.BI erase_timeout= n
+In milliseconds, specifies the poll interval for monitoring the status
+of a bulk erase operation.  The default is 100 ms.
+.TP
+.BI erase_limit= n
+In milliseconds, specifies the maximum elapsed time before an erase
+operation is assumed to have failed.  The default is 10000 ms.
+.TP
+.BI retry_limit= n
+The maximum number of retries for a write operation.  The default is
+8.
+.TP
+.BI max_tries= n
+The maximum number of status register polls before various commands
+are assumed to have timed out.  The default is 4096.
+.TP
+.BI do_sleep= n
+A flag indicating if the driver should sleep or busy loop while
+waiting for write completion.  The default is 1 (true).
+
+.SH AUTHOR
+David Hinds \- dhinds@pcmcia.sourceforge.org
+
+.SH "SEE ALSO"
+iflash2+_mtd(4), memory_cs(4).
Index: oldkernel/linux/pcmcia-cs-3.1.15/man/iflash2_mtd.4
diff -u /dev/null linux/pcmcia-cs-3.1.15/man/iflash2_mtd.4:1.1
--- /dev/null	Mon Jul 31 21:15:11 2000
+++ linux/pcmcia-cs-3.1.15/man/iflash2_mtd.4	Fri Jul  7 16:34:58 2000
@@ -0,0 +1,87 @@
+.\" Copyright (C) 1998 David A. Hinds -- dhinds@pcmcia.sourceforge.org
+.\" iflash2_mtd.4 1.6 1999/12/21 22:56:31
+.\"
+.TH IFLASH2_MTD 4 "1999/12/21 22:56:31" "pcmcia-cs"
+.SH NAME
+iflash2_mtd \- memory technology driver for Intel Series 2 flash
+.SH SYNOPSIS
+.B insmod iflash2_mtd.o
+.RB [ pc_debug=\c
+.IR n ]
+.RB [ mem_speed=\c
+.IR n ]
+.RB [ word_width=\c
+.IR n ]
+.RB [ vpp_timeout_period=\c
+.IR n ]
+.RB [ vpp_settle=\c
+.IR n ]
+.RB [ erase_timeout=\c
+.IR n ]
+.RB [ erase_limit=\c
+.IR n ]
+.RB [ retry_limit=\c
+.IR n ]
+.RB [ max_tries=\c
+.IR n ]
+.RB [ mem_speed=\c
+.IR n ]
+.RB [ word_width=\c
+.IR n ]
+.SH DESCRIPTION
+.B Iflash2_mtd
+is a memory technology driver for Intel Series 2 and Series 100 flash
+devices.  Memory technology drivers are used by Card Services to
+provide device-independent access for memory cards through bulk memory
+services.  
+.PP
+Writing to Series 2 and Series 100 flash devices is very processor
+intensive.  Individual words are written one at a time, at a speed of
+roughly 10 us per word.  This busy period is too short to schedule
+other processes to run, so the driver will not yield the processor
+until an entire block is written.
+.SH PARAMETERS
+.TP
+.BI pc_debug= n
+Selects the PCMCIA debugging level.  This parameter is only available
+if the module is compiled with debugging enabled.  A non-zero value
+enables debugging.
+.TP
+.BI mem_speed= n
+Sets the access speed of shared memory windows, in nanoseconds.  The
+default is 0 (i.e., no extra wait states).  Values of up to 1000 are
+legal.
+.TP
+.BI word_width= n
+A flag indicating if memory windows should be configured for
+8-bit (if 0) or 16-bit (if 1) transfers.  The default is 1 (16-bit).
+.TP
+.BI vpp_timeout_period= n
+In milliseconds, this specifies the maximum idle period after a write
+operation before programming power will be switched off.  The default
+is 1000 ms.
+.TP
+.BI vpp_settle= n
+In milliseconds, this gives a delay between when programming power is
+switched on, and when the device is assumed to be powered up and ready
+to receive erase or write commands.  The default is 100 ms.
+.TP
+.BI erase_timeout= n
+In milliseconds, specifies the poll interval for monitoring the status
+of a bulk erase operation.  The default is 100 ms.
+.TP
+.BI erase_limit= n
+In milliseconds, specifies the maximum elapsed time before an erase
+operation is assumed to have failed.  The default is 10000 ms.
+.TP
+.BI retry_limit= n
+The maximum number of retries for a write operation.  The default is
+4.
+.TP
+.BI max_tries= n
+The maximum number of status register polls before a single word write
+is assumed to have timed out.  The default is 4096.
+.SH AUTHOR
+David Hinds \- dhinds@pcmcia.sourceforge.org
+.SH "SEE ALSO"
+iflash2+_mtd(4), memory_cs(4).
Index: oldkernel/linux/pcmcia-cs-3.1.15/man/ifport.8
diff -u /dev/null linux/pcmcia-cs-3.1.15/man/ifport.8:1.1
--- /dev/null	Mon Jul 31 21:15:11 2000
+++ linux/pcmcia-cs-3.1.15/man/ifport.8	Fri Jul  7 16:34:58 2000
@@ -0,0 +1,59 @@
+.\" Copyright (C) 1998 David A. Hinds -- dhinds@pcmcia.sourceforge.org
+.\" ifport.8 1.8 1999/11/02 20:34:56
+.\"
+.TH IFPORT 8 "1999/11/02 20:34:56" "pcmcia-cs"
+
+.SH NAME
+ifport \- select the transceiver type for a network interface
+
+.SH SYNOPSIS
+.B ifport
+.I interface
+.RB [ auto | 10baseT | 10base2 | aui | 100baseT | ## ]
+
+.SH DESCRIPTION
+.B Ifport
+sets the transceiver type for the specified network interface, for
+drivers that support multiple transceiver types.  If a type is not
+specified on the command line, then the current type is displayed.
+The type can be specified either numerically or by keyword.  The five
+standard transceiver types
+.RB ( auto ,
+.BR 10baseT ,
+.BR 10base2 ,
+.BR aui ,
+and
+.BR 100baseT )
+correspond to codes 0 to 3, for all the Linux PCMCIA network drivers.
+The keyword match is case insensitive.
+.PP
+The network drivers may not reconfigure a card for a new transceiver
+type if the interface is already open.  It is best to invoke
+.B ifport
+prior to configuring the interface with
+.B ifconfig
+to ensure that the new setting takes effect immediately.
+.PP
+This utility only works with a limited set of 16-bit PC Card drivers:
+.BR 3c589_cs ,
+.BR nmclan_cs ,
+.BR pcnet_cs ,
+.BR smc91c92_cs ,
+and
+.BR xirc2ps_cs .
+If invoked for other drivers,
+.B ifport
+may report bogus transceiver
+settings, or report ``Operation not supported''.
+
+.SH DIAGNOSTICS
+.TP
+.B ioctl: Operation not supported
+Indicates that this network device does not support manual transceiver
+selection.  There may be only one transceiver option, or the device
+may always autodetect the appropriate transceiver.
+
+.SH AUTHOR
+David Hinds \- dhinds@pcmcia.sourceforge.org
+.SH "SEE ALSO"
+ifconfig(8).
Index: oldkernel/linux/pcmcia-cs-3.1.15/man/ifuser.8
diff -u /dev/null linux/pcmcia-cs-3.1.15/man/ifuser.8:1.1
--- /dev/null	Mon Jul 31 21:15:11 2000
+++ linux/pcmcia-cs-3.1.15/man/ifuser.8	Fri Jul  7 16:34:58 2000
@@ -0,0 +1,29 @@
+.\" Copyright (C) 1998 David A. Hinds -- dhinds@pcmcia.sourceforge.org
+.\" ifuser.8 1.5 1999/10/25 19:50:46
+.\"
+.TH IFUSER 8 "1999/10/25 19:50:46" "pcmcia-cs"
+.SH NAME
+ifuser \- identify destinations routed to a particular network interface
+.SH SYNOPSIS
+.B ifuser
+.RB [ -v ]
+.I interface
+.RI [ "target\ ..." ]
+.SH DESCRIPTION
+This utility checks to see if any of the listed hosts or network
+addresses are routed through the specified interface.  Destinations
+may be specified either by IP address or by name.
+.PP
+The exit code will be 0 if any listed host or network is routed
+through this interface, and 1 if the interface is not in use (similar
+to 
+.BR fuser ).
+.SH OPTIONS
+.TP
+.B \-v
+Verbose mode: if enabled, then the names of those destinations routed
+to this interface (if any) will be reported on standard output.
+.SH AUTHORS
+David Hinds \- dhinds@pcmcia.sourceforge.org
+.br
+Regis "HPReg" Duchesne \- regis@via.ecp.fr
Index: oldkernel/linux/pcmcia-cs-3.1.15/man/lspnp.8
diff -u /dev/null linux/pcmcia-cs-3.1.15/man/lspnp.8:1.1
--- /dev/null	Mon Jul 31 21:15:11 2000
+++ linux/pcmcia-cs-3.1.15/man/lspnp.8	Fri Jul  7 16:34:58 2000
@@ -0,0 +1,48 @@
+.\" Copyright (C) 1999 David A. Hinds -- dhinds@pcmcia.sourceforge.org
+.\" lspnp.8 1.3 1999/10/25 19:50:46
+.\"
+.TH LSPNP 8 "1999/10/25 19:50:46" "pcmcia-cs"
+.SH NAME
+lspnp \- list Plug and Play BIOS device nodes and resources
+.SH SYNOPSIS
+.B lspnp
+.RB [ -b ]
+.RB [ -v [ v ]]
+.RI [ "device ..." ]
+.SH DESCRIPTION
+This utility presents a formatted interpretation of the contents of the
+.I /proc/bus/pnp
+tree.  Its default output is a list of Plug and Play device node
+numbers, product identifiers, and descriptions.  Verbose output
+.RB ( -v )
+includes resource allocations (IO ports, memory, interrupts, and DMA 
+channels) for each device.  Very verbose output
+.RB ( -vv )
+includes lists of possible resources, various configuration flags, and
+product identifiers for compatible devices.
+.PP
+The output can be limited to one or more specific device nodes by
+specifying their two-digit hex node numbers on the command line.  By
+default, current (dynamic) device configuration information is
+displayed; with the
+.B -b
+option, the boot (static) configuration is shown.
+.SH OPTIONS
+.TP
+.B \-b
+Boot mode: read device resource information that will be used at next
+boot (as opposed to current resource info).
+.TP
+.B \-v
+Selects more verbose output.  Can be used more than once.
+.SH FILES
+.TP \w'/usr/share/pnp.ids\ \ \ \ |\|'u
+/usr/share/pnp.ids
+A database of known Plug and Play device ID's.
+.TP
+/proc/bus/pnp/...
+The kernel interface for Plug and Play BIOS device services.
+.SH AUTHORS
+David Hinds \- dhinds@pcmcia.sourceforge.org
+.SH "SEE ALSO"
+setpnp(8)
Index: oldkernel/linux/pcmcia-cs-3.1.15/man/memory_cb.4
diff -u /dev/null linux/pcmcia-cs-3.1.15/man/memory_cb.4:1.1
--- /dev/null	Mon Jul 31 21:15:11 2000
+++ linux/pcmcia-cs-3.1.15/man/memory_cb.4	Fri Jul  7 16:34:58 2000
@@ -0,0 +1,57 @@
+.\" Copyright (C) 1998 David A. Hinds -- dhinds@pcmcia.sourceforge.org
+.\" memory_cs.4 1.4 1999/10/25 19:50:46
+.\"
+.TH MEMORY_CS 4 "1999/10/25 19:50:46" "pcmcia-cs"
+.SH NAME
+memory_cb \- CardBus memory driver
+.SH SYNOPSIS
+.B insmod memory_cb.o
+.RB [ pc_debug=\c
+.IR n ]
+.SH DESCRIPTION
+.B Memory_cb
+gives direct memory access to the address spaces of CardBus cards.
+It provides character-mode devices for accessing a card's PCI
+configuration space, up to six mapped memory or IO regions, and its
+expansion ROM space.
+When loaded,
+.B memory_cb
+will allocate a free major device number.  For each card, it will
+report which address spaces are available, and their sizes.  Minor
+numbers have the form 'dddddsss', where 'ddddd' is the instance number
+and 'sss' is the memory space for that instance.
+When
+.B memory_cb
+is bound to a card, it will report its major and minor device numbers
+to
+.BR cardmgr (8).
+.PP
+The default memory card initialization script creates device special
+files for all eight card address spaces, though for a particular card,
+some of these may be unavailable.  These devices have the
+following names: 
+.TP
+.I /dev/cbmem#s0
+The card's PCI configuration space.
+.TP
+.I /dev/cbmem#s[1-6]
+The IO or memory spaces mapped by the card's six Base Address
+Registers.
+.TP
+.I /dev/cbmem#s7
+The card's expansion ROM space.
+.PP
+The character special devices can be used to read and write arbitrary
+numbers of bytes to arbitrary locations.  The
+.B memory_cb
+driver can be bound to any card regardless of function.
+.SH PARAMETERS
+.TP
+.BI pc_debug= n
+Selects the PCMCIA debugging level.  This parameter is only available
+if the module is compiled with debugging enabled.  A non-zero value
+enables debugging.
+.SH AUTHOR
+David Hinds \- dhinds@pcmcia.sourceforge.org
+.SH "SEE ALSO"
+cardmgr(8), pcmcia(5), memory_cs(4).
Index: oldkernel/linux/pcmcia-cs-3.1.15/man/memory_cs.4
diff -u /dev/null linux/pcmcia-cs-3.1.15/man/memory_cs.4:1.1
--- /dev/null	Mon Jul 31 21:15:11 2000
+++ linux/pcmcia-cs-3.1.15/man/memory_cs.4	Fri Jul  7 16:34:58 2000
@@ -0,0 +1,111 @@
+.\" Copyright (C) 1998 David A. Hinds -- dhinds@pcmcia.sourceforge.org
+.\" memory_cs.4 1.10 1999/10/25 19:50:46
+.\"
+.TH MEMORY_CS 4 "1999/10/25 19:50:46" "pcmcia-cs"
+.SH NAME
+memory_cs \- MTD-aware PCMCIA memory card driver
+.SH SYNOPSIS
+.B insmod memory_cs.o
+.RB [ pc_debug=\c
+.IR n ]
+.RB [ mem_speed=\c
+.IR n ]
+.RB [ word_width=\c
+.IR n ]
+.SH DESCRIPTION
+.B Memory_cs
+is the Card Services driver for PCMCIA memory cards, and also provides
+direct memory access for other types of cards.
+It provides character-mode and block-mode for accessing any card's
+attribute and common memory address spaces, analogous to
+.IR /dev/mem .
+.B Memory_cs
+will allocate a free major device number when it is loaded.  It
+provides two types of minor devices: "direct" character-mode devices
+for raw access a card's entire PCMCIA common and attribute memory
+spaces, and "indirect" devices for accessing specific memory
+partitions via an appropriate Memory Technology Driver.  The
+bitwise layout of minor device numbers is 'ddddxarr'.  'dddd'
+is the device number, with one card counting as one memory device.
+'x' is set if this is a direct-access device, 'a' is set for attribute
+memory, and 'rr' is the region number (for indirect devices).  When
+.B memory_cs
+is bound to a card, it will report its major and minor device numbers
+to
+.BR cardmgr (8).
+.PP
+The default memory card initialization script creates character
+special device files for the direct common memory and attribute memory
+devices.  It also creates character special devices for accessing the
+first attribute and common memory partitions, and a block device for
+accessing the first common memory partition.  These devices have the
+following names: 
+.TP
+.I /dev/mem#c
+Common memory direct access, character special device.
+.TP
+.I /dev/mem#a
+Attribute memory direct access, character special device.
+.TP
+.I /dev/mem#c0c
+Common memory region 0, character special device.
+.TP
+.I /dev/mem#c0b
+Common memory region 0, block special device.
+.TP
+.I /dev/mem#a0c
+Attribute memory region 0, character special device.
+.PP
+The block special device for a card's common memory can be used to
+create a filesystem on a card, and the device can be mounted in much
+the same way as a floppy disk.  In some cases, you may need to
+explicitly specify the card's capacity when creating a filesystem.
+.PP
+The character special devices can be used to read and write arbitrary
+numbers of bytes to arbitrary locations.  For devices that need to be
+explicitly erased before writing, if a write request is aligned and
+sized on erase block boundaries for the target memory card, the driver
+will erase the target region before writing to the card.
+.PP
+Since any PCMCIA card can be accessed as a memory card,
+.B memory_cs
+can be bound to any card regardless of function, and regardless of
+what other drivers might also be bound to that card.  For example,
+this driver can be bound to a card and then used to read out the
+contents of the card's attribute memory.
+.SH PARAMETERS
+.TP
+.BI pc_debug= n
+Selects the PCMCIA debugging level.  This parameter is only available
+if the module is compiled with debugging enabled.  A non-zero value
+enables debugging.
+.TP
+.BI mem_speed= n
+Sets the access speed of the shared memory window for direct access
+devices, in nanoseconds.  The default is 0 (i.e., no extra wait
+states).  Values of up to 1000 are legal.
+.TP
+.BI word_width= n
+A flag indicating if direct access devices should be configured for
+8-bit (if 0) or 16-bit (if 1) transfers.  The default is 1 (16-bit).
+.SH IOCTLS
+These are defined in
+.BR <pcmcia/memory.h> .
+.TP
+.B MEMGETINFO
+This takes an argument of type
+.BR (region_info_t\ *) ,
+defined in
+.BR <pcmcia/bulkmem.h> .
+The structure will be filled in with memory region information for 
+this device, such as access speed, erase block size, and JEDEC
+identifiers.  
+.TP
+.B MEMERASE
+This takes an argument of type
+.BR (erase_info_t\ *) ,
+specifying the offset and length of a memory region to be erased.  
+.SH AUTHOR
+David Hinds \- dhinds@pcmcia.sourceforge.org
+.SH "SEE ALSO"
+cardmgr(8), pcmcia(5), memory_cb(4).
Index: oldkernel/linux/pcmcia-cs-3.1.15/man/netwave_cs.4
diff -u /dev/null linux/pcmcia-cs-3.1.15/man/netwave_cs.4:1.1
--- /dev/null	Mon Jul 31 21:15:11 2000
+++ linux/pcmcia-cs-3.1.15/man/netwave_cs.4	Fri Jul  7 16:34:58 2000
@@ -0,0 +1,65 @@
+.\" Copyright (C) 1998 David A. Hinds -- dhinds@pcmcia.sourceforge.org
+.\" netwave_cs.4 1.6 1999/10/25 19:50:46
+.\"
+.TH NETWAVE_CS 4 "1999/10/25 19:50:46" "pcmcia-cs"
+.SH NAME
+netwave_cs \- Xircom Creditcard Netwave device driver
+.SH SYNOPSIS
+.B insmod netwave_cs.o
+.RB [ pc_debug=\c
+.IR n ]
+.RB [ domain=\c
+.IR n ]
+.RB [ scramble_key=\c
+.IR n ]
+.RB [ mem_speed=\c
+.IR n ]
+.RB [ irq_list=\c
+.IR i,j,... ]
+.SH DESCRIPTION
+.B Netwave_cs
+is the low-level Card Services driver for the Xircom Creditcard
+Netwave PCMCIA wireless network adapter.  When this driver is attached
+to a card, it allocates the next available ethernet device
+.RB ( eth0 .. eth# ).
+This
+device name will be reported in the kernel log file, and will be
+passed on to
+.BR cardmgr (8).
+.PP
+The wireless domain number and scrambling key can be specified using
+module parameters when the module is loaded.  These parameters should
+be specified in
+.IR /etc/pcmcia/config.opts .
+.SH PARAMETERS
+.TP
+.BI pc_debug= n
+Selects the PCMCIA debugging level.  This parameter is only available
+if the module is compiled with debugging enabled.  A non-zero value
+enables debugging.
+.TP
+.BI domain= n
+Selects what access point(s) to talk to, by their domain number.
+Values from 0 to 0x1ff are valid; 0x100 is the default.
+.TP
+.BI scramble_key= n
+Selects the scramble key for domains that are scrambled.  Values from
+0 to 0x1ff are valid.  The default is 0 (no scrambling).
+.TP
+.BI mem_speed= n
+Sets the access speed of the shared memory window, in nanoseconds.
+The default is 0 (i.e., no extra wait states).  Values of up to 1000
+are legal.
+.TP
+.BI irq_list= i,j,...
+Specifies the set of interrupts that may be allocated by this driver.
+.SH BUGS
+The statistics reported back from the driver are wrong.
+.SH AUTHORS
+Dag Brattli \- dagb@cs.uit.no
+.br
+John Markus Bjorndalen \- johnm@staff.cs.uit.no
+.br
+David Hinds \- dhinds@pcmcia.sourceforge.org
+.SH "SEE ALSO"
+cardmgr(8), pcmcia(5).
Index: oldkernel/linux/pcmcia-cs-3.1.15/man/pack_cis.8
diff -u /dev/null linux/pcmcia-cs-3.1.15/man/pack_cis.8:1.1
--- /dev/null	Mon Jul 31 21:15:11 2000
+++ linux/pcmcia-cs-3.1.15/man/pack_cis.8	Fri Jul  7 16:34:58 2000
@@ -0,0 +1,61 @@
+.\" Copyright (C) 1998 David A. Hinds -- dhinds@pcmcia.sourceforge.org
+.\" pack_cis.8 1.4 1999/12/21 22:41:19
+.\"
+.TH PACK_CIS 8 "1999/12/21 22:41:19" "pcmcia-cs"
+.SH NAME
+pack_cis \- compile PCMCIA Card Information Structures
+.SH SYNOPSIS
+.B pack_cis
+.RB [ "\-o\ "\c
+.I outfile\c
+]
+.I infile
+.SH DESCRIPTION
+.B Pack_cis
+is used to convert a text description of a PCMCIA Card
+Information Structure (CIS) to its packed binary representation.  It
+can parse a reasonably useful subset of the possible output of the
+.B dump_cis
+utility.  The primary use of
+.B pack_cis
+is to construct replacement CIS files
+for cards that have incomplete, inaccurate, or damaged CIS
+structures.  Thus, the supported tuple types are mostly limited to
+things that are important for correctly configuring typical IO cards.
+.PP
+By default, the packed data is written to standard output.
+.SH FORMAT
+The best way to get started writing CIS descriptions will be to use
+.B dump_cis
+to extract the CIS data from a card, and to examine the CIS files
+distributed with the PCMCIA source tree in
+.IR etc/cis/ .
+.PP
+The basic structure of a CIS is a list of tuple descriptions.
+Anything following a hash mark (``#'') is treated as a comment.
+A multifunction CIS can be described with the notation:
+.sp
+.RS
+.nf
+[common tuple list]
+mfc {
+  [tuple list for function 0]
+}, {
+  [tuple list for function 1]
+}
+.RE
+.fi
+.sp
+.SH OPTIONS
+.TP
+.BI "\-o " outfile
+Write the packed tuple data to the specified file.
+.SH FILES
+.PD 0
+.TP \w'/etc/pcmcia/cis\ \ \ \|\|'u
+/etc/pcmcia/cis
+Standard location for packed CIS files
+.SH AUTHOR
+David Hinds \- dhinds@pcmcia.sourceforge.org
+.SH "SEE ALSO"
+dump_cis(8), cardmgr(8), pcmcia(5).
Index: oldkernel/linux/pcmcia-cs-3.1.15/man/pcinitrd.8
diff -u /dev/null linux/pcmcia-cs-3.1.15/man/pcinitrd.8:1.1
--- /dev/null	Mon Jul 31 21:15:11 2000
+++ linux/pcmcia-cs-3.1.15/man/pcinitrd.8	Fri Jul  7 16:34:58 2000
@@ -0,0 +1,133 @@
+.\" Copyright (C) 1998 David A. Hinds -- dhinds@pcmcia.sourceforge.org
+.\" pcinitrd.8 1.11 2000/03/26 07:47:28
+.\"
+.TH PCINITRD 8 "$Date" "pcmcia-cs"
+.SH NAME
+pcinitrd \- create a PCMCIA initrd ram disk image
+.SH SYNOPSIS
+.B pcinitrd
+.RB [ -v ]
+.RB [ -a ]
+.RB [ --all ]
+.RB [ "\-d\ "\c
+.I alternate-root\c
+]
+.RB [ \-\-dir=\c
+.I alternate-root\c
+]
+.RB [ "\-r\ "\c
+.I kernel-release\c
+]
+.RB [ \-\-release=\c
+.I kernel-release\c
+]
+.RB [ "\-s\ "\c
+.I image-size\c
+]
+.RB [ \-\-size=\c
+.I image-size\c
+]
+.RB [ -u ]
+.RB [ --update ]
+.I initrd-image
+.RI [ "modules\ ..." ]
+.SH DESCRIPTION
+The
+.B pcinitrd
+script creates an initrd ram disk image for booting with the root
+filesystem on a PCMCIA device.  If the target is a block special
+device (i.e.,
+.IR /dev/fd0 ),
+then the initrd image is created on that device.  If the target does
+not already exist or if it is an ordinary file, then
+.B pcinitrd
+will create the image file using the ``loopback'' device.
+.PP
+Modules are specified with paths relative to
+.IR /lib/modules/[kernel-release] .
+The core PCMCIA modules
+.RI ( pcmcia/pcmcia_core
+and
+.IR  pcmcia/ds )
+will automatically be installed in the target image.  All other
+device-specific modules need to be listed on the command line,
+along with the appropriate socket driver
+.RI ( pcmcia/i82365.o
+or
+.IR pcmcia/tcic.o ).
+Alternatively, if
+.B -a
+is specified, then all available PCMCIA socket drivers and block
+device drivers will be included in the image.  Additional files to be
+copied to the initrd image may also be listed on the command line.
+Executable programs will be installed in
+.IR /bin ,
+shared libraries will be installed in
+.IR /lib ,
+device files will be installed in
+.IR /dev ,
+and any other files will be placed in
+.IR /etc .
+.PP
+The startup script in the resulting image,
+.IR linuxrc ,
+may need to be customized for a particular system.  It contains the
+same variable definitions as the normal PCMCIA startup scripts (i.e.,
+.BR PCIC= ,
+.BR PCIC_OPTS= ,
+and
+.B CORE_OPTS=
+variables).  The
+.I /etc/config.opts
+file may also need to be edited.  Any changes to
+.I linuxrc
+or
+.I config.opts
+will be preserved if
+.B pcinitrd
+is executed in ``update'' mode.
+.PP
+Another feature of the generated
+.I linuxrc
+is that if the
+.B DEBUG
+variable is set to a non-blank string at the boot prompt, then cardmgr
+will echo all its status messages to the console, and after
+.I linuxrc
+executes, it will fire up a shell on the console.  This can be helpful
+for debugging initrd problems.  However, few commands are available in
+the normal initrd environment.
+.SH OPTIONS
+.TP
+.B \-v
+Verbose mode.  Identify files as they are copied.
+.TP
+\fB\-a\fR, \fB\-\-all\fR
+Install all socket drivers and block-style PCMCIA device drivers,
+including memory card, SCSI card, and fixed-disk drivers.  This is
+mainly intended for use by package maintainers.
+.TP
+\fB\-d\fI alternate-root\fR, \fB\-\-dir=\fIalternate-root\fR
+Specifies an alternate directory tree to search for all the files used
+to put together the initrd image.  This may be helpful for running 
+.B pcinitrd
+after booting from an installation or rescue diskette.
+.TP
+\fB\-r\fI kernel-release\fR, \fB\-\-release=\fIkernel-release\fR
+Specifies the kernel release number (i.e., 2.0.28) to use when looking
+for modules in /lib/modules.  The default is the release of the
+running kernel.
+.TP
+\fB\-s\fI image-size\fR, \fB\-\-size=\fIimage-size\fR
+Specifies the filesystem size to create on the target file or device,
+in 1k blocks.  The default is 1440.
+.TP
+\fB\-u\fR, \fB\-\-update\fR
+Update mode: updates
+.B cardmgr
+and all the kernel modules in an existing initrd image, but does not
+modify other files.
+.SH AUTHOR
+David Hinds \- dhinds@pcmcia.sourceforge.org
+.SH "SEE ALSO"
+pcmcia(5), cardmgr(8), lilo(8).
Index: oldkernel/linux/pcmcia-cs-3.1.15/man/pcmcia.5
diff -u /dev/null linux/pcmcia-cs-3.1.15/man/pcmcia.5:1.1
--- /dev/null	Mon Jul 31 21:15:11 2000
+++ linux/pcmcia-cs-3.1.15/man/pcmcia.5	Fri Jul  7 16:34:58 2000
@@ -0,0 +1,246 @@
+.\" Copyright (C) 1998 David A. Hinds -- dhinds@pcmcia.sourceforge.org
+.\" pcmcia.5 1.24 1999/10/25 19:50:46
+.\"
+.TH PCMCIA 5 "1999/10/25 19:50:46" "pcmcia-cs"
+.SH NAME
+/etc/pcmcia/config \- PCMCIA card configuration database
+
+.SH DESCRIPTION
+The PCMCIA card configuration file is read by
+.IR cardmgr (8)
+at startup time.  It defines what resources are available for use by
+Card Services, describes how to load and initialize device drivers,
+and describes specific PCMCIA cards.
+
+.SH Resource descriptions
+There are three kinds of resource entries:
+.BR include ,
+.BR exclude ,
+and
+.BR reserve .
+Including a resource enables Card Services to allocate
+that resource for client drivers.  Part of a resource that is under
+Card Services control can be excluded if a specific device in the
+system uses that resource.  And, a resource can be reserved, so that
+it will only be assigned to a client if that client specifically asks
+for that resource, or no other suitable resources are available.
+.PP
+There are three resource types:
+.BR port ,
+.BR memory ,
+and
+.BR irq .
+By default, Card Services assumes that it can use any interrupt that
+is not bound by another device driver.  However, it makes no
+assumptions about IO port and address ranges, because some Linux
+drivers do not register their resource usage.  So, port and memory
+ranges must be explicitly made available for use by PCMCIA devices.
+.PP
+So, here is a portion of a config file:
+.sp
+.RS
+.nf
+include port 0x300-0x3ff, memory 0xd0000-0xdffff
+reserve irq 3
+exclude irq 4, port 0x3f8-0x3ff
+.RE
+.fi
+.sp
+This says that Card Services can allocate ports in the range 0x300 to
+0x3ff, and memory in the range 0xd0000 to 0xdffff.  It should not use
+irq 4 or ports 0x3f8-0x3ff (even if they seem to be available).  And
+irq 3 should only be allocated if a client specifically asks for it.
+.PP
+Card Services will never allocate resources already allocated by
+another kernel device driver.  The
+.BR include / exclude / reserve
+mechanism just
+provides a way of controlling what resources it will try to use, to
+accomodate devices that are not registered with the Linux resource
+manager.
+
+.SH Device driver descriptions
+All Card Services client drivers are identified by a 16-character tag.
+.B Device
+entries in the config file describe client drivers.  The only
+required field is the device tag.  Additional fields can specify
+kernel modules that need to be loaded to make the device available,
+and a script to be executed to enable and disable instances of
+a device.  When an instance of a driver is assigned to a socket, it
+gives cardmgr a device name by which this device will be known by the
+system (for example,
+.I eth0
+for a net device, or
+.I cua1
+for a modem).
+This name will be passed to the configuration script.  For example:
+.sp
+.RS
+.nf
+device "pcnet_cs"
+  class "network"
+  module "net/8390" opts "ei_debug=4", "pcnet_cs"
+.RE
+.fi
+.sp
+This says that the
+.B pcnet_cs
+device requires two loadable modules.
+The first one is located in the
+.I net
+module subdirectory and will be
+loaded with a specific parameter setting.  The second module should be
+in the
+.I pcmcia
+module subdirectory.  The device is in the network class, so the
+.I network
+script in the configuration directory will be used to start or stop
+the device.
+.PP
+It is also possible to specify default options for a particular kernel
+module, outside of a device driver declaration.  This is convenient
+for keeping local configuration options in a file separate from the
+main card configuration file.  For example:
+.sp
+.RS
+.nf
+module "pcnet_cs" opts "mem_speed=600"
+.RE
+.fi
+.sp
+
+.SH Card descriptions
+Card declarations map PCMCIA cards to their client drivers.  A card
+declaration consists of a descriptive name, a method for identifying
+the card when it is inserted, and driver bindings.  There are five
+identification methods: the
+.B version
+method matches a card using its
+VERSION_1 id strings, the
+.B manfid
+method matches a card using its MANFID tuple codes, the
+.B tuple
+method matches a card using any
+string embedded in any arbitrary CIS tuple, the
+.B function
+method matches a card using its function ID, and the
+.B anonymous
+method matches any card that does not have a CIS.  This last method
+is only intended to be used for old-style Type I memory cards.  For
+example:
+.sp
+.RS
+.nf
+card "Linksys Ethernet Card"
+  tuple 0x40, 0x0009, "E-CARD PC Ethernet Card"
+  bind "pcnet_cs"
+.RE
+.fi
+.sp
+This card is identified by a string at offset 0x0009 in tuple 0x40,
+and will be bound to the
+.B pcnet_cs
+driver (which must be already declared in a
+.B driver
+declaration).
+.sp
+.RS
+.nf
+card "Connectware LANdingGear Adapter"
+  manfid 0x0057, 0x1004
+  bind "pcnet_cs"
+.RE
+.fi
+.sp
+This card is identified by its MANFID tuple contents.
+.sp
+.RS
+.nf
+card "D-Link DE-650 Ethernet Card"
+  version "D-Link", "DE-650"
+  bind "pcnet_cs"
+.RE
+.fi
+.sp
+This card will be identified using its VERSION_1 tuple, and will also
+be bound to the
+.B pcnet_cs
+driver.
+.sp
+.RS
+.nf
+card "Serial port device"
+  function serial_port
+  bind "serial_cs"
+.RE
+.fi
+.sp
+This binds the
+.B serial_cs
+driver to any card with a CIS function ID of
+0x02, which corresponds to a serial port card.  The function ID can
+either be a number, or one of the following predefined functions:
+.BR memory_card ,
+.BR serial_port ,
+.BR parallel_port ,
+.BR fixed_disk ,
+.BR video_adapter ,
+.BR network_adapter ,
+and
+.BR aims_card .
+.PP
+Finally, the configuration file can specify that Card Services should
+use a replacement for the configuration information found on a card.
+This can be useful if a card's configuration information is
+particularly incomplete or inaccurate.  The new information is read
+from a file as in this example:
+.sp
+.RS
+.nf
+card "Evil broken card"
+  manfid 0x1234, 0x5678
+  cis "fixup.cis"
+  bind "serial_cs"
+.RE
+.fi
+.sp
+
+.SH Memory region definitions 
+Memory region definitions are used to associate a particular type of
+memory device with a Memory Technology Driver, or "MTD".  An MTD is
+used to service memory accesses in a device-independent fashion.  When
+a card is identified, Card Services will attempt to load MTD's for all
+its memory regions.
+.PP
+A memory region definition begins with the
+.B region
+keyword and a descriptive string.  This is followed by an
+identification method: either
+.B default
+to identify an MTD to be used for any otherwise unclassified region,
+or
+.B jedec
+to identify a region based on its JEDEC identification codes.  Thus,
+for example,
+.sp
+.RS
+.nf
+region "Intel Series 2 Flash"
+  jedec 0x89 0xa2
+  mtd "iflash2_mtd"
+.RE
+.fi
+.sp
+specifies that the
+.B iflash2_mtd
+driver will be loaded based on a JEDEC match.
+
+.SH BUGS
+The
+.B reserve
+keyword has not actually been implemented in a useful way for this
+version of Card Services.
+.SH AUTHOR
+David Hinds \- dhinds@pcmcia.sourceforge.org
+.SH "SEE ALSO"
+cardmgr(8).
Index: oldkernel/linux/pcmcia-cs-3.1.15/man/pcmcia_core.4
diff -u /dev/null linux/pcmcia-cs-3.1.15/man/pcmcia_core.4:1.1
--- /dev/null	Mon Jul 31 21:15:11 2000
+++ linux/pcmcia-cs-3.1.15/man/pcmcia_core.4	Fri Jul  7 16:34:58 2000
@@ -0,0 +1,146 @@
+.\" Copyright (C) 1998 David A. Hinds -- dhinds@pcmcia.sourceforge.org
+.\" pcmcia_core.4 1.22 2000/03/10 00:37:04
+.\"
+.TH PCMCIA_CORE 4 "2000/03/10 00:37:04" "pcmcia-cs"
+.SH NAME
+pcmcia_core \- PCMCIA Card Services core module
+.SH SYNOPSIS
+.B insmod pcmcia_core.o
+.RB [ pc_debug=\c
+.IR n ]
+.RB [ setup_delay=\c
+.IR n ]
+.RB [ resume_delay=\c
+.IR n ]
+.RB [ shutdown_delay=\c
+.IR n ]
+.RB [ vcc_settle=\c
+.IR n ]
+.RB [ reset_time=\c
+.IR n ]
+.RB [ unreset_delay=\c
+.IR n ]
+.RB [ unreset_check=\c
+.IR n ]
+.RB [ unreset_limit=\c
+.IR n ]
+.RB [ cis_speed=\c
+.IR n ]
+.RB [ io_speed=\c
+.IR n ]
+.RB [ strict_cis=\c
+.IR n ]
+.RB [ probe_io=\c
+.IR n ]
+.RB [ probe_mem=\c
+.IR n ]
+.RB [ cb_mem_base=\c
+.IR n ]
+.RB [ cb_bus_base=\c
+.IR n ]
+.RB [ cb_bus_step=\c
+.IR n ]
+.RB [ cb_pci_irq=\c
+.IR n ]
+.SH DESCRIPTION
+.B Pcmcia_core
+is the core Card Services module, required for all drivers for
+specific PCMCIA cards.  It is loaded prior to loading any socket
+device drivers.
+.PP
+In the event that kernel version mismatches prevent this module from
+being loaded, version information can be extracted from the module
+itself by doing:
+.sp
+.RS
+.nf
+strings -n 10 pcmcia_core.o | head -3
+.RE
+.fi
+.sp
+.SH PARAMETERS
+.TP
+.BI pc_debug= n
+Selects the PCMCIA debugging level.  This parameter is only available
+if the module is compiled with debugging enabled.  A non-zero value
+enables debugging.
+.TP
+.BI setup_delay= n
+Sets the delay between when a card is first detected, and when it will
+be powered up.  In 1/100 second increments, the default is 5.
+.TP
+.BI resume_delay= n
+Sets the delay between when a resume event is processed, and when a
+suspended card will be powered up.  In 1/100 second increments, the
+default is 20.
+.TP
+.BI shutdown_delay= n
+Sets the delay between when when a card removal event is detected, and
+when the socket will be disabled.  In 1/100 second increments, the
+default is 5.
+.TP
+.BI vcc_settle= n
+Sets the time to wait after first applying power to a socket before
+accessing a card.  In 1/100 second increments, the default is 40.
+.TP
+.BI reset_time= n
+Sets how long the software reset signal will be asserted, in
+microseconds.  The default is 10.
+.TP
+.BI unreset_delay= n
+Sets the delay between when a card is reset, and when the card will
+first be checked to see if it is ready.  In 1/100 second increments,
+the default is 10.  This delay should be increased for cards that
+raise the ready signal prematurely.
+.TP
+.BI unreset_check= n
+Sets how often to check to see if a card is ready after it is sent a
+software reset.  In 1/100 second increments, the default is 10.
+.TP
+.BI unreset_limit= n
+Sets the maximum number of checks to make before pronouncing a card to
+be dead.  The default is 30.
+.TP
+.BI cis_speed= n
+Sets the access delay in nanoseconds for CIS memory windows.  This
+parameter only affects card identification.  The default is 300 ns.
+.TP
+.BI io_speed= n
+Sets the access delay in nanoseconds for IO port windows.  The default
+is 0.
+.TP
+.BI probe_io= n
+A flag indicating if Card Services should probe IO port regions for
+conflicts with other devices unknown to Linux.  The default is 1
+(true).
+.TP
+.BI probe_mem= n
+A flag indicating if Card Services should probe memory windows for
+conflicts with ROM extensions or memory-mapped devices.  The default
+is 1 (true).
+.TP
+.BI cb_mem_base= n
+Sets the base address to use for memory mapping CardBus bridge
+registers.  By default, bridges that are not already initialized by
+the PCI BIOS will be mapped at 0x68000000.  If this parameter is set,
+then this value will override any existing mappings.
+.TP
+.BI cb_bus_base= n
+Specifies that PCI bus numbers for CardBus busses should be renumbered
+starting with this value.  By default, bus values that are
+uninitialized at boot time will be numbered starting with bus 0x20.
+.TP
+.BI cb_bus_step= n
+Specifies the number of bus slots to reserve for secondary PCI
+busses, for each CardBus socket, when busses are renumbered.  The
+default is 2.
+.TP
+.BI cb_pci_irq= n
+Specifies an interrupt number 1..15 to be assigned to any CardBus
+bridge whose PCI interrupt was not set by the BIOS.  The default is to
+pick an interrupt based on the BIOS PCI Interrupt Routing table only
+when the table is unambiguous.
+.SH AUTHOR
+David Hinds \- dhinds@pcmcia.sourceforge.org
+.SH "SEE ALSO"
+cardmgr(8), pcmcia(5).
Index: oldkernel/linux/pcmcia-cs-3.1.15/man/pcnet_cs.4
diff -u /dev/null linux/pcmcia-cs-3.1.15/man/pcnet_cs.4:1.1
--- /dev/null	Mon Jul 31 21:15:11 2000
+++ linux/pcmcia-cs-3.1.15/man/pcnet_cs.4	Fri Jul  7 16:34:58 2000
@@ -0,0 +1,95 @@
+.\" Copyright (C) 1998 David A. Hinds -- dhinds@pcmcia.sourceforge.org
+.\" pcnet_cs.4 1.14 1999/12/21 22:58:26
+.\"
+.TH PCNET_CS 4 "1999/12/21 22:58:26" "pcmcia-cs"
+
+.SH NAME
+pcnet_cs \- generic NS8390-based PCMCIA Ethernet Driver
+
+.SH SYNOPSIS
+.B insmod pcnet_cs.o
+.RB [ pc_debug=\c
+.IR n ]
+.RB [ irq_list=\c
+.IR i,j,... ]
+.RB [ if_port=\c
+.IR n ]
+.RB [ use_big_buf=\c
+.IR n ]
+.RB [ mem_speed=\c
+.IR n ]
+.RB [ delay_output=\c
+.IR n ]
+.RB [ delay_time=\c
+.IR n ]
+.RB [ hw_addr=\c
+.IR n,n,n,n,n,n ]
+
+.SH DESCRIPTION
+.B Pcnet_cs
+is a driver for all NS8390-based PCMCIA ethernet cards.  It can use
+either polled IO or a shared memory window to exchange data with the
+card.  The driver first tests for a shared memory buffer, falling
+back on polled IO if the memory test fails.  It replaces the
+.B de650_cs
+and
+.B ibmcc_cs
+drivers in previous releases.  When this driver is bound to a card, it
+allocates the next available ethernet device
+.RB ( eth0 .. eth# ).
+This
+device name will be reported in the kernel log file, and passed on to
+.BR cardmgr (8).
+
+.SH PARAMETERS
+.TP
+.BI pc_debug= n
+Selects the PCMCIA debugging level.  This parameter is only available
+if the module is compiled with debugging enabled.  A non-zero value
+enables debugging.
+.TP
+.BI irq_list= i,j,...
+Specifies the set of interrupts that may be allocated by this driver.
+.TP
+.BI if_port= n
+Selects the transceiver type, for Socket EA and IBM CCAE cards.  1 is
+10baseT (twisted pair), and 2 is 10base2 (BNC, or thin net).  The
+default is 1 (10baseT).
+.TP
+.BI use_big_buf= n
+For Socket EA cards, a flag indicating if the driver should use the
+large (64K) packet buffer.  The default is 1 (true).
+.TP
+.BI mem_speed= n
+Sets the access speed of the shared memory window, in nanoseconds.
+The default is 0 (i.e., no extra wait states).  Values of up to 1000
+are legal.
+.TP
+.BI delay_output= n
+Specifies that a delay should be inserted after a polled IO block
+output.  This is turned on by default for Accton and Socket EA cards.
+.TP
+.BI delay_time= n
+Specifies the length of the
+.B delay_output
+delay, in microseconds.  The default is 4.
+.TP
+.BI hw_addr= n,n,n,n,n,n
+For cards whose hardware ethernet addresses can't be identified by the
+current driver, this is a hack for hardwiring a specific address.  The
+argument should consist of exactly six byte-sized numbers, separated
+by commas, with no spaces.  Numbers may be in decimal or hex ('0xNN').
+
+.SH DIAGNOSTICS
+.TP
+.B eth#: interrupt(s) dropped!
+Indicates that the driver did not receive an interrupt notification
+for some reason.  The driver will poll the card (with a significant
+performance penalty) if the problem persists.  The most likely cause
+is an interrupt conflict and/or host bridge configuration problem.
+
+.SH AUTHOR
+David Hinds \- dhinds@pcmcia.sourceforge.org
+
+.SH "SEE ALSO"
+cardmgr(8), pcmcia(5).
Index: oldkernel/linux/pcmcia-cs-3.1.15/man/ray_cs.4
diff -u /dev/null linux/pcmcia-cs-3.1.15/man/ray_cs.4:1.1
--- /dev/null	Mon Jul 31 21:15:11 2000
+++ linux/pcmcia-cs-3.1.15/man/ray_cs.4	Fri Jul  7 16:34:58 2000
@@ -0,0 +1,153 @@
+.\"
+.\" Man page for ray_cs Raylink wireless LAN Card Services
+.\"
+.\" Copyright (c) 1999 Corey Thomas
+.\"
+.\" You may distribute under the terms of the GNU General Public
+.\" License version 2 only
+.\"
+.\" Corey Thomas
+.\" corey@world.std.com
+.\"
+.TH ray_cs "January 20, 1999"
+.LO 4
+.SH NAME
+ray_cs \- Raylink wireless LAN \- PCMCIA card device driver
+.br
+.SH SYNOPSIS
+.B insmod ray_cs 
+.RB [essid=string]
+.RB [irq_mask=n]
+.RB [net_type=[0-1]]
+.RB [ray_debug=[0-5]]
+.RB [phy_addr=xNNNNNNNNNNNN]
+.RB [hop_dwell=n]
+.RB [beacon_period=n]
+.RB [psm=[0-1]]
+.RB [translate=[0-1]]
+.RB [country=[1-8]]
+.RB [sniffer=[0-1]]
+.RB [bc=[0-1]]
+.SH DESCRIPTION
+.B ray_cs
+is the low level Card Services device driver for the Raylink wireless
+LAN PCMCIA adapter.  It is normally loaded automatically by card
+services according to the parameters specified in
+.IR /etc/pcmcia/ray_cs.opts .
+.SH PARAMETERS
+.TP
+.B essid=string
+ESS ID - network name to join string with maximum length of 32 chars
+default value = "LINUX"
+
+.TP
+.B irq_mask=n
+linux standard 16 bit value 1bit/IRQ lsb is IRQ 0, bit 1 is IRQ 1 etc.
+Used to restrict choice of IRQ's to use.
+
+.TP
+.B net_type=n
+0 = adhoc network (default)
+1 = infrastructure
+
+.TP
+.B ray_debug=n
+(0-5) larger values for more verbose logging.
+.TP
+.B phy_addr=string          
+string of 12 hex digits containing new MAC address.
+must be started with x e.g. x00008f123456
+
+.TP
+.B hop_dwell=n
+hop dwell time in Kilo-microseconds legal values = 16,32,64,128(default),256
+
+.TP
+.B beacon_period=n
+Beacon period in Kilo-microseconds.
+.br
+Legal values = 16,32,64,128,256(default) 
+must be integer multiple of hop dwell.
+
+.TP
+.B psm=n
+Power save mode
+.br
+0 = continuously active
+.br
+1 = power save mode (significantly slower)
+
+.TP
+.B bc=n
+Power save mode
+.br
+0 = 802.11 timing
+.br
+1 = 802.11 modified timing.  Interframe spacing is slowed down for
+compatibility with older Breezecom access points.
+
+.TP
+.B translate
+.br
+0 = no translation (encapsulate frames)
+.br
+1 = translation (default)
+
+.TP
+.B country=n
+.br
+Country code
+.br
+1 = USA (default)
+.br
+2 = Europe
+.br
+3 = Japan
+.br
+4 = Korea
+.br
+5 = Spain
+.br
+6 = France
+.br
+7 = Israel
+.br
+8 = Australia
+
+.TP
+.B sniffer=n
+.br
+0 = normal network interface - not sniffer (default)
+.br
+1 = sniffer which can be used to record all network traffic using
+tcpdump or similar, but no normal network use is allowed.  This is
+because linux has no knowledge of 802.11 headers and cannot parse them
+correctly.  Note that tcpdump does not understand 802.11 headers,
+either so it can't interpret the contents, but it can record to a
+file.
+
+.TP
+.SH BUGS
+ray_cs can lock the machine if the card is pulled out while active.
+I have never observed a crash if card is deactivated as follows before
+removal:
+.br
+.B	ifconfig eth0 down
+.br
+The above command assumes that the Raylink card is configured as eth0.
+
+This driver only does encapsulation of ethernet frames within 802.11
+frames.  Most vendors, including Raytheon, are moving to a frame
+translation method.  Translation support has been started, but is not
+yet functional.
+
+Support for defragmenting frames is not yet tested.
+
+The ioctl support is incomplete.  The hardware address cannot be set
+using ifconfig yet.  If a different hardware address is needed, it may
+be set using the phy_addr parameter in ray_cs.opts.
+
+.SH AUTHOR
+Corey Thomas \- corey@world.std.com
+.SH "SEE ALSO"
+cardmgr(8), pcmcia(5), ifconfig(8).
Index: oldkernel/linux/pcmcia-cs-3.1.15/man/scsi_info.8
diff -u /dev/null linux/pcmcia-cs-3.1.15/man/scsi_info.8:1.1
--- /dev/null	Mon Jul 31 21:15:11 2000
+++ linux/pcmcia-cs-3.1.15/man/scsi_info.8	Fri Jul  7 16:34:58 2000
@@ -0,0 +1,33 @@
+.\" Copyright (C) 1998 David A. Hinds -- dhinds@pcmcia.sourceforge.org
+.\" scsi_info.8 1.6 1999/10/25 19:50:46
+.\"
+.TH SCSI_INFO 8 "1999/10/25 19:50:46" "pcmcia-cs"
+.SH NAME
+scsi_info \- SCSI device description tool
+.SH SYNOPSIS
+.B scsi_info
+.I device
+.SH DESCRIPTION
+.B Scsi_info
+opens the specified SCSI device file, and retrieves its
+actual SCSI address parameters.  It also looks up the device in
+.I /proc/scsi/scsi
+and retrieves the device's vendor information, if available.  Its
+output is a pair of Bourne-style shell commands to define the
+.B SCSI_ID
+and
+.B MODEL
+variables based on this information.  The
+.B SCSI_ID
+variable has three comma-separated fields: the SCSI channel number,
+the device ID, and the logical unit number.  In most cases, the
+channel and logical unit will be 0.
+.PP
+The reason for the existence of this utility lies in the peculiar
+method for assigning minor device numbers to Linux SCSI devices.
+Devices are numbered based on the order in which they are detected,
+irrespective of their device addresses.  This tool automatically
+converts these arbitrary device assignments back to the
+user-configured addresses.
+.SH AUTHOR
+David Hinds \- dhinds@pcmcia.sourceforge.org
Index: oldkernel/linux/pcmcia-cs-3.1.15/man/serial_cs.4
diff -u /dev/null linux/pcmcia-cs-3.1.15/man/serial_cs.4:1.1
--- /dev/null	Mon Jul 31 21:15:11 2000
+++ linux/pcmcia-cs-3.1.15/man/serial_cs.4	Fri Jul  7 16:34:58 2000
@@ -0,0 +1,51 @@
+.\" Copyright (C) 1998 David A. Hinds -- dhinds@pcmcia.sourceforge.org
+.\" serial_cs.4 1.11 1999/10/25 19:50:46
+.\"
+.TH SERIAL_CS 4 "1999/10/25 19:50:46" "pcmcia-cs"
+.SH NAME
+serial_cs \- PCMCIA serial port driver
+.SH SYNOPSIS
+.B insmod serial_cs.o
+.RB [ pc_debug=\c
+.IR n ]
+.RB [ irq_list=\c
+.IR i,j,... ]
+.RB [ do_sound=\c
+.IR n ]
+.SH DESCRIPTION
+.B Serial_cs
+is the Card Services driver for all PCMCIA serial devices, including
+modem cards.  When
+.B serial_cs
+is bound to a serial or modem card, it will generally attempt to
+allocate the first unused serial device for use by the card.  The
+device chosen will be recorded in the kernel log file, and will also
+be reported to
+.BR cardmgr (8).
+The major and minor numbers and device name reported by
+.B serial_cs
+will match the corresponding "dialout" device
+.RI ( /dev/cua# ).
+The new
+device can be accessed using this device file or the corresponding
+.I /dev/ttyS#
+device.  The default serial card setup script will link
+the dialout device to
+.IR /dev/modem .
+.SH PARAMETERS
+.TP
+.BI pc_debug= n
+Selects the PCMCIA debugging level.  This parameter is only available
+if the module is compiled with debugging enabled.  A non-zero value
+enables debugging.
+.TP
+.BI irq_list= i,j,...
+Specifies the set of interrupts that may be allocated by this driver.
+.TP
+.BI do_sound= n
+A flag specifying if speaker output should be enabled.  The default is
+1 (true).  Set to 0 to disable speaker output.
+.SH AUTHOR
+David Hinds \- dhinds@pcmcia.sourceforge.org
+.SH "SEE ALSO"
+cardmgr(8), pcmcia(5).
Index: oldkernel/linux/pcmcia-cs-3.1.15/man/setpnp.8
diff -u /dev/null linux/pcmcia-cs-3.1.15/man/setpnp.8:1.1
--- /dev/null	Mon Jul 31 21:15:11 2000
+++ linux/pcmcia-cs-3.1.15/man/setpnp.8	Fri Jul  7 16:34:58 2000
@@ -0,0 +1,64 @@
+.\" Copyright (C) 1999 David A. Hinds -- dhinds@pcmcia.sourceforge.org
+.\" setpnp.8 1.2 1999/10/25 19:50:46
+.\"
+.TH SETPNP 8 "1999/10/25 19:50:46" "pcmcia-cs"
+.SH NAME
+setpnp \- modify Plug and Play BIOS device resources
+.SH SYNOPSIS
+.B setpnp
+.RB [ -b ]
+.I device resource...
+.br
+.B setpnp
+.RB [ -b ]
+.I device {on|off}
+.SH DESCRIPTION
+This utility updates the system resource information for Plug and Play
+BIOS device nodes.  A device is specified by its two-digit hex node
+number.  In its first form, a list of resources are given on the
+command line.  Alternatively, a device can either be simply switched
+``on'' (reset to its boot configuration) or ``off'' (all resources
+disabled).
+.PP
+There are four types of resources: ``io'', ``mem'', ``irq'', and
+``dma''.  A resource list consists of one or more space-separated
+pairs of a resource type with one or more values.  Multiple values for
+one resource type can be separated by commas.  Values can also either
+be unitary or dash-separated ranges.  For example:
+.sp
+.RS
+.nf
+setpnp 0d io 0x2f8-0x2ff irq 3
+setpnp 12 io 0x350-0x35f,0x2f8-0x2ff irq 3 irq 10
+.RE
+.fi
+.sp
+The order of items of different types is not important, but if more
+than one item of the same type is present, their relative order is
+significant.  The Plug and Play BIOS will reject invalid configuration
+attempts; however,
+.B setpnp
+will not attempt to determine why a configuration was rejected.
+.PP
+By default, current (dynamic) device configuration information is
+modified.  With the
+.B -b
+option, a device's boot (static) configuration can be updated.  Some
+devices may only be reconfigured for the following boot.  Be especially
+careful when modifying your system's boot configuration.  Improper use
+of this command may disable vital system devices and render your
+system unbootable. 
+.SH OPTIONS
+.TP
+.B \-b
+Boot mode: update the device resource information that will be used at
+next boot (as opposed to current resource info).
+.TP
+.SH FILES
+.TP \w'/proc/bus/pnp/...\ \ \ \ |\|'u
+/proc/bus/pnp/...
+The kernel interface for Plug and Play BIOS device services.
+.SH AUTHORS
+David Hinds \- dhinds@pcmcia.sourceforge.org
+.SH "SEE ALSO"
+lspnp(8)
Index: oldkernel/linux/pcmcia-cs-3.1.15/man/smc91c92_cs.4
diff -u /dev/null linux/pcmcia-cs-3.1.15/man/smc91c92_cs.4:1.1
--- /dev/null	Mon Jul 31 21:15:11 2000
+++ linux/pcmcia-cs-3.1.15/man/smc91c92_cs.4	Fri Jul  7 16:34:58 2000
@@ -0,0 +1,74 @@
+.\" Copyright (C) 1999 David A. Hinds -- dhinds@pcmcia.sourceforge.org
+.\" smc91c92_cs.4 1.3 1999/10/25 19:50:46
+.\"
+.TH SMC91C92_CS 4 "1999/10/25 19:50:46" "pcmcia-cs"
+
+.SH NAME
+smc91c92_cs \- SMC 91cxx device driver
+
+.SH SYNOPSIS
+.B insmod smc91c92_cs.o
+.RB [ pc_debug=\c
+.IR n ]
+.RB [ if_port=\c
+.IR n ]
+.RB [ irq_list=\c
+.IR i,j,... ]
+
+.SH DESCRIPTION
+.B Smc91c92_cs
+is the low-level Card Services driver for SMC 91c92, 91c94,
+91c96, and 91c100 based PC Card ethernet adapters.  When this
+driver is attached to a card, it
+allocates the next available ethernet device
+.RB ( eth0 .. eth# ).
+This
+device name will be reported in the kernel log file, and passed on to
+.BR cardmgr (8).
+.PP
+With the default transceiver setting, the driver will attempt to
+continuously autodetect the transceiver type (10base2 or 10baseT).
+There should normally only be a one or two second lag before the
+correct transceiver is selected.  On particularly noisy or busy
+networks, it is possible for the detection logic to incorrectly
+toggle the transceiver type.  If this becomes a problem, it may be
+necessary to explicitly select the interface type when the module is
+loaded or with the 
+.B ifport
+command.
+
+.SH PARAMETERS
+.TP
+.BI pc_debug= n
+Selects the PCMCIA debugging level.  This parameter is only available
+if the module is compiled with debugging enabled.  A non-zero value
+enables debugging.
+.TP
+.BI if_port= n
+Selects the transceiver type.  0 is autodetect (10baseT or 10base2),
+1 is 10baseT (twisted pair), and 2 is 10base2 (BNC, or thin net).  The
+default is 0 (autodetect).
+.TP
+.BI irq_list= i,j,...
+Specifies the set of interrupts that may be allocated by this driver.
+.SH DIAGNOSTICS
+.TP
+.B eth#: interrupt(s) dropped!
+Indicates that the driver did not receive an interrupt notification
+for some reason.  The driver will poll the card (with a significant
+performance penalty) if the problem persists.  The most likely cause
+is an interrupt conflict and/or host bridge configuration problem.
+
+.SH DIAGNOSTICS
+.TP
+.B eth#: interrupt(s) dropped!
+Indicates that the driver did not receive an interrupt notification
+for some reason.  The driver will poll the card (with a significant
+performance penalty) if the problem persists.  The most likely cause
+is an interrupt conflict and/or host bridge configuration problem.
+
+.SH AUTHOR
+David Hinds \- dhinds@pcmcia.sourceforge.org
+
+.SH "SEE ALSO"
+cardmgr(8), pcmcia(5), ifport(8).
Index: oldkernel/linux/pcmcia-cs-3.1.15/man/stab.5
diff -u /dev/null linux/pcmcia-cs-3.1.15/man/stab.5:1.1
--- /dev/null	Mon Jul 31 21:15:11 2000
+++ linux/pcmcia-cs-3.1.15/man/stab.5	Fri Jul  7 16:34:58 2000
@@ -0,0 +1,47 @@
+.\" Copyright (C) 1998 David A. Hinds -- dhinds@pcmcia.sourceforge.org
+.\" stab.5 1.11 1999/12/21 22:40:19
+.\"
+.TH STAB 5 "1999/12/21 22:40:19" "pcmcia-cs"
+.SH NAME
+stab \- current PCMCIA socket status
+.SH DESCRIPTION
+The
+.I stab
+file is created by
+.B cardmgr
+and contains identification and device driver information for PCMCIA
+cards.  Each socket is described by one header line, followed by one
+or more device driver lines.  The header gives the card name as given
+in
+.IR /etc/pcmcia/config .
+Device driver lines consist of a series of tab-separated fields.  The
+first field is the socket number.  The second field is the device
+class, which identifies which script in
+.I /etc/pcmcia
+is used to configure or shut down this device.
+The third field is the driver name.
+The fourth field is used to number devices when a single
+card has several devices associated with the same driver.  The fifth
+field is the device name, and the final two fields are major and minor
+device numbers for this device, if appropriate.
+.PP
+The file is updated by
+.B cardmgr
+whenever a card is inserted or ejected, and when
+.B cardmgr
+receives a
+.B SIGHUP
+signal.
+.PP
+The
+.I stab
+file will normally be created in either
+.I /var/state/pcmcia
+or
+.IR /var/lib/pcmcia ,
+but if neither directory is available, it will be found in
+.IR /var/run .
+.SH AUTHOR
+David Hinds \- dhinds@pcmcia.sourceforge.org
+.SH "SEE ALSO"
+cardmgr(8), pcmcia(5), cardinfo(1).
Index: oldkernel/linux/pcmcia-cs-3.1.15/man/tc574_cs.4
diff -u /dev/null linux/pcmcia-cs-3.1.15/man/tc574_cs.4:1.1
--- /dev/null	Mon Jul 31 21:15:11 2000
+++ linux/pcmcia-cs-3.1.15/man/tc574_cs.4	Fri Jul  7 16:34:58 2000
@@ -0,0 +1,74 @@
+.\" Copyright (c) 1998 Donald Becker and David Hinds.
+.\" tc574_cs.4 1.0 1998/01/12 19:11:01
+.\"
+.TH 3C574_CS 4 "1998/01/12 19:11:01" "CESDIS"
+
+.SH NAME
+3c574_cs \- 3Com 3c574 Etherlink XL 10/100 PC Card device driver
+
+.SH SYNOPSIS
+.B insmod 3c574_cs.o
+.RB [ pc_debug=\c
+.IR n ]
+.RB [ if_port=\c
+.IR n ]
+.RB [ irq_list=\c
+.IR i,j,... ]
+.RB [ full_duplex=\c
+.IR n ]
+.RB [ max_interrupt_work=\c
+.IR n ]
+
+.SH DESCRIPTION
+.B 3c574_cs
+is the low-level Card Services driver for the 3Com 3c574 EtherLink XL
+PCMCIA ethernet adapter.  When this driver is attached to a card, it
+allocates the next available ethernet device
+.RB ( eth0 .. eth# ).
+This device name will be reported in the kernel log file, and passed on to
+.BR cardmgr (8).
+.PP
+The driver uses the N-Way autonegotiating transceiver to negotiate the
+speed and duplex of the network link.  If the link partner does not
+support negotiation, only the link speed is detected.
+
+.SH PARAMETERS
+.TP
+.BI pc_debug= n
+Selects the PCMCIA debugging level.  This parameter is only available
+if the module is compiled with debugging enabled.  A non-zero value
+enables debugging.
+.TP
+.BI if_port= n
+Selects the transceiver type.  Only 0, 1, and 4 are acceptable values, other
+values return an error.  This actual value specificed is ignored -- the
+autonegotiating transceiver selects the media speed and duplex used.
+.TP
+.BI irq_list= i,j,...
+This option limits the set of interrupts that may be allocated by this driver.
+The default is all normally-usable IRQs.
+.TP
+.BI full_duplex= n
+This flag determines if only full-duplex modes are advertised.  It
+defaults to 0 (false).
+.TP
+.BI max_interrupt_work= work-limit
+This option selects the maximum amount of work handled during each
+interrupt.  Each received packet counts as one unit of work, as does
+updating statistics counters and handling errors.  The default is 32.
+
+.SH DIAGNOSTICS
+.TP
+.B eth#: interrupt(s) dropped!
+Indicates that the driver did not receive an interrupt notification
+for some reason.  The driver will poll the card (with a significant
+performance penalty) if the problem persists.  The most likely cause
+is an interrupt conflict and/or host bridge configuration problem.
+
+.SH AUTHOR
+Driver core: Donald Becker \- becker@cesdis.gsfc.nasa.gov.
+.PP
+PC Card interface: David Hinds \- dhinds@pcmcia.sourceforge.org
+.SH "SEE ALSO"
+cardmgr(8), pcmcia(5), ifport(8).
+
Index: oldkernel/linux/pcmcia-cs-3.1.15/man/tc575_cb.4
diff -u /dev/null linux/pcmcia-cs-3.1.15/man/tc575_cb.4:1.1
--- /dev/null	Mon Jul 31 21:15:11 2000
+++ linux/pcmcia-cs-3.1.15/man/tc575_cb.4	Fri Jul  7 16:34:58 2000
@@ -0,0 +1,48 @@
+.\" Copyright (c) 1998 Donald Becker and David Hinds.
+.\" tc575_cb.4 1.0 1998/02/5 03:35:00
+.\"
+.TH 3C575_CB 4 "1998/02/05 03:35:00" "CESDIS"
+.SH NAME
+3c575_cb \- 3Com 3c575 Etherlink XL 10/100 CardBus device driver
+.SH SYNOPSIS
+.B insmod 3c575_cb.o
+.RB [ pc_debug=\c
+.IR n ]
+.SH DESCRIPTION
+.B 3c575_cb
+is the low-level Card Services driver for the 3Com 3c575 EtherLink XL
+CardBus ethernet adapter.  When this driver is attached to a card, it
+allocates the next available ethernet device
+.RB ( eth0 .. eth# ).
+This information for this card will be reported in the kernel log file, and
+the device name passed on to
+.BR cardmgr (8).
+.PP
+The driver uses the N-Way autonegotiating transceiver to negotiate the speed
+and duplex of the network link.  If the link partner does not support
+negotiation only the link speed is detected.
+.PP
+If the on-card EEPROM is programmed for a full-duplex (FD) link, only FD media
+types are advertised and the link is assumed to be full-duplex.
+.SH PARAMETERS
+.TP
+.BI rx_copybreak= n
+Set the breakpoint for copying incoming frames into reduced-sized
+packet buffers.  The default value of 200 bytes is reasonable for most systems.
+.TP
+.BI max_interrupt_work= n
+This option selects the maximum amount of work handled during each
+interrupt.  Each received packet counts as one unit of work, as does
+updating statistics counters and handling errors.  The default value of
+20 should only need to be increased on very slow machines.
+If "too much work at interrupt" messages are logged
+the system power management configuration should be set to full speed rather
+than increasing this value.
+
+.SH AUTHOR
+This driver: Donald Becker \- becker@cesdis.gsfc.nasa.gov.
+.PP
+Linux PC Card control software: David Hinds \- dhinds@pcmcia.sourceforge.org et al.
+.SH "SEE ALSO"
+cardmgr(8), pcmcia(5), ifport(8).
+
Index: oldkernel/linux/pcmcia-cs-3.1.15/man/tc589_cs.4
diff -u /dev/null linux/pcmcia-cs-3.1.15/man/tc589_cs.4:1.1
--- /dev/null	Mon Jul 31 21:15:11 2000
+++ linux/pcmcia-cs-3.1.15/man/tc589_cs.4	Fri Jul  7 16:34:58 2000
@@ -0,0 +1,68 @@
+.\" Copyright (C) 1998 David A. Hinds -- dhinds@pcmcia.sourceforge.org
+.\" tc589_cs.4 1.15 1999/10/25 19:50:46
+.\"
+.TH 3C589_CS 4 "1999/10/25 19:50:46" "pcmcia-cs"
+
+.SH NAME
+3c589_cs \- 3Com 3c589 Etherlink III device driver
+
+.SH SYNOPSIS
+.B insmod 3c589_cs.o
+.RB [ pc_debug=\c
+.IR n ]
+.RB [ if_port=\c
+.IR n ]
+.RB [ irq_list=\c
+.IR i,j,... ]
+
+.SH DESCRIPTION
+.B 3c589_cs
+is the low-level Card Services driver for the 3Com 3c589
+PCMCIA ethernet adapter and 3Com 3c562/3c563 combo cards.  When this
+driver is attached to a card, it
+allocates the next available ethernet device
+.RB ( eth0 .. eth# ).
+This
+device name will be reported in the kernel log file, and passed on to
+.BR cardmgr (8).
+.PP
+With the default transceiver setting, the driver will attempt to
+continuously autodetect the transceiver type (10base2 or 10baseT).
+There should normally only be a one or two second lag before the
+correct transceiver is selected.  On particularly noisy or busy
+networks, it is possible for the detection logic to incorrectly
+toggle the transceiver type.  If this becomes a problem, it may be
+necessary to explicitly select the interface
+type when the module is loaded or with the
+.B ifport
+command.
+
+.SH PARAMETERS
+.TP
+.BI pc_debug= n
+Selects the PCMCIA debugging level.  This parameter is only available
+if the module is compiled with debugging enabled.  A non-zero value
+enables debugging.
+.TP
+.BI if_port= n
+Selects the transceiver type.  0 is autodetect (10baseT or 10base2),
+1 is 10baseT (twisted pair), 2 is
+10base2 (BNC, or thin net). and 3 is AUI (thick ethernet).  The
+default is 0 (autodetect).
+.TP
+.BI irq_list= i,j,...
+Specifies the set of interrupts that may be allocated by this driver.
+
+.SH DIAGNOSTICS
+.TP
+.B eth#: interrupt(s) dropped!
+Indicates that the driver did not receive an interrupt notification
+for some reason.  The driver will poll the card (with a significant
+performance penalty) if the problem persists.  The most likely cause
+is an interrupt conflict and/or host bridge configuration problem.
+
+.SH AUTHOR
+David Hinds \- dhinds@pcmcia.sourceforge.org
+
+.SH "SEE ALSO"
+cardmgr(8), pcmcia(5), ifport(8).
Index: oldkernel/linux/pcmcia-cs-3.1.15/man/tcic.4
diff -u /dev/null linux/pcmcia-cs-3.1.15/man/tcic.4:1.1
--- /dev/null	Mon Jul 31 21:15:11 2000
+++ linux/pcmcia-cs-3.1.15/man/tcic.4	Fri Jul  7 16:34:58 2000
@@ -0,0 +1,79 @@
+.\" Copyright (C) 1998 David A. Hinds -- dhinds@pcmcia.sourceforge.org
+.\" tcic.4 1.16 1999/10/25 19:50:47
+.\"
+.TH TCIC 4 "1999/10/25 19:50:47" "pcmcia-cs"
+.SH NAME
+tcic \- Databook TCIC-2 PCMCIA controller driver
+.SH SYNOPSIS
+.B insmod tcic.o
+.RB [ pc_debug=\c
+.IR n ]
+.RB [ tcic_base=\c
+.IR n ]
+.RB [ ignore=\c
+.IR n ]
+.RB [ do_scan=\c
+.IR n ]
+.RB [ irq_list=\c
+.IR i,j,... ]
+.RB [ cs_irq=\c
+.IR n ]
+.RB [ poll_interval=\c
+.IR n ]
+.RB [ poll_quick=\c
+.IR n ]
+.RB [ cycle_time=\c
+.IR n ]
+.SH DESCRIPTION
+This is the low-level driver for the Databook TCIC-2 PCMCIA host
+controller family.  It is used by Card Services for programming the
+TCIC-2 chip, and for monitoring card status change events.
+.SH PARAMETERS
+.TP
+.BI pc_debug= n
+Selects the PCMCIA debugging level.  This parameter is only available
+if the module is compiled with debugging enabled.  A non-zero value
+enables debugging.
+.TP
+.BI tcic_base= n
+Sets the base I/O port address of the TCIC-2 chip.  The default is
+0x240.
+.TP
+.BI ignore= n
+Causes the driver to ignore a single socket.  Sockets are numbered
+starting at 0.  The socket will be left in whatever state it was
+already in, so it can be used for cards with point enablers that do
+not cooperate with Card Services.
+.TP
+.BI do_scan= n
+This flag specifies that all free interrupts should be tested to see
+if they can be triggered by the PCMCIA controller.  The default is 1
+(on). 
+.TP
+.BI irq_list= i,j,...
+Specifies the set of interrupts that may be allocated by this driver,
+if they are otherwise available.
+The default list is 3, 4, 5, 6, 7, 10, 11, and 14. 
+.TP
+.BI cs_irq= n
+Sets the interrupt line to use for monitoring card status changes.
+The default is 0, which means pick any legal interrupt not already in
+use.  Legal values are 14, 10, 7, 6, 5, 4, and 3.
+.TP
+.BI poll_interval= n
+Sets the card status polling delay, in 1/100 second increments.  If
+this parameter is set, card status interrupts will be disabled.  
+.TP
+.BI poll_quick= n
+When a card status change interrupt is received, the TCIC-2 chip is
+briefly polled for additional status changes.  This parameter sets the
+polling delay, in 1/100 second increments.  The default is 5, meaning
+0.05 seconds.
+.TP
+.BI cycle_time= n
+Sets the length of a CCLK external clock cycle, in nanoseconds.  The
+default is 70 ns, corresponding to a standard ISA 14.31818 MHz clock.
+.SH AUTHOR
+David Hinds \- dhinds@pcmcia.sourceforge.org
+.SH "SEE ALSO"
+cardmgr(8), pcmcia(5).
Index: oldkernel/linux/pcmcia-cs-3.1.15/man/wavelan_cs.4
diff -u /dev/null linux/pcmcia-cs-3.1.15/man/wavelan_cs.4:1.1
--- /dev/null	Mon Jul 31 21:15:11 2000
+++ linux/pcmcia-cs-3.1.15/man/wavelan_cs.4	Fri Jul  7 16:34:58 2000
@@ -0,0 +1,183 @@
+.\" Copyright (c) 1995 Anthony D. Joseph <adj@lcs.mit.edu>
+.\" Revisited by Jean II - HPLB - 96
+.\" wavelan_cs.c.4
+.\"
+.TH WAVELAN_CS 4 "4/16/95" "MIT Lab. for Comp. Sci."
+.\"
+.\" NAME part
+.\"
+.SH NAME
+wavelan_cs \- AT&T GIS WaveLAN PCMCIA device driver
+.\"
+.\" SYNOPSIS part
+.\"
+.SH SYNOPSIS
+.B insmod wavelan_cs.o
+.RB [ irq_list=\c
+.IR i,j,... ]
+.RB [ mem_speed=\c
+.IR n ]
+.RB [ do_roaming=\c
+.IR n ]
+.\"
+.\" DESCRIPTION part
+.\"
+.SH DESCRIPTION
+.I wavelan_cs
+is the low-level Card Services driver for the NCR / AT&T / Lucent
+.B WaveLAN PCMCIA
+and Digital (DEC)
+.B RoamAbout DS
+wireless ethernet adapter.  When this driver is attached to a card, it
+allocates the next available ethernet device (eth0..eth#).  This
+device name will be passed on to
+.IR cardmgr (8)
+for the card configuration, and reported in the kernel log file with
+the MAC address, NWID and frequency used by the card.
+.\"
+.\" PARAMETER part
+.\"
+.SH PARAMETERS
+.TP
+.BI irq_list= i,j,...
+Specifies the set of interrupts that may be allocated by this driver.
+.TP
+.BI mem_speed= n
+Sets the access speed of the shared memory window, in nanoseconds.
+The default is 0 (i.e., no extra wait states).
+.TP
+.BI do_roaming= n
+Enables or disables roaming mode.  The default is 1 (roam).
+.\"
+.\" WIRELESS part
+.\"
+.SH WIRELESS EXTENSIONS
+Use
+.IR iwconfig (8)
+to manipulate wireless extensions.
+.\"	mode sub part
+.SS Mode
+Set the operating mode to  
+.I Ad-Hoc
+or
+.IR Managed .
+This in fact disable or enable roaming support. This setting is not
+saved in hardware.
+.\"	NWID sub part
+.SS Network ID
+Set the network ID 
+.RI [ 0
+to
+.IR FFFF ]
+or disable it
+.RI [ off ]
+or reenable it
+.RI [ on ].
+As the NWID is stored in the card Permanent Storage Area, it will be
+reuse at any further invocation of the driver.
+.\"	Frequency sub part
+.SS Frequency & channels
+For the 2.4GHz 2.00 Hardware, you are able to set the frequency by
+specifying one of the 10 defined channels
+.RI ( 2.412,
+.I 2.422, 2.425, 2.4305, 2.432, 2.442, 2.452, 2.460, 2.462
+or
+.IR 2.484 )
+or directly by its value. The frequency is changed immediately and
+permanentely. Frequency availability depend on the regulations...
+.\"	Sensitivity sub part
+.SS Sensitivity
+Signal level threshold for packet reception
+.RI [ 0
+to
+.IR 63 ].
+Should be set according to the ambiant noise level.
+.\"	Encryption key sub part
+.SS Encryption key
+Set the encryption key
+.RI [ 0
+to
+.IR FFFF-FFFF-FFFF-FFFF ].
+Use
+.RI [ off ]
+and
+.RI [ on ]
+to disable and reenable the hardware encryption. This feature works
+only for device with encryption option (DES or AES).
+.\"	Spy sub part
+.SS Statistics spy
+Set a list of MAC addresses in the driver (up to 8) and get the last
+quality of link for each of those (see
+.IR iwspy (8)).
+.\"	/proc/net/wireless part
+.SS /proc/net/wireless
+.I status
+is the status reported by the modem.
+.I Link quality
+reports the quality of the modulation on the air (direct sequence
+spread spectrum) [max = 16].
+.I Level
+and
+.I Noise
+refer to the signal level and noise level [max = 64].
+The
+.I crypt discarded packet
+and
+.I misc discarded packet
+counters are not implemented.
+.\"
+.\" IOCTL part
+.\"
+.SH PRIVATE IOCTL
+You may use
+.IR iwpriv (8)
+to manipulate private ioctls.
+.\"	threshold part
+.SS Quality threshold
+Enable you the define the quality threshold used by the modem (packet
+below that level are discarded).
+.\"	Histogram part
+.SS Histogram
+This functionality allow to set a number of signal level intervals and
+to count the number of packets received in each of those defined
+intervals. This distribution might be used to calculate the mean value
+and standard deviation of the signal level.
+.\"
+.\" OTHER part
+.\"
+.SH OTHER FEATURES
+Hot unplug support.
+.br
+Power saving (use 'ifconfig down').
+.\"
+.\" SPECIFIC part
+.\"
+.SH SPECIFIC NOTES
+This driver will fail to load some
+.B non NCR/ATT&T/Lucent
+Wavelan cards. If it's your case, you must look in the source code on
+how to add your card to the detection routine.
+.PP
+Some of the mentioned features are optional. You may enable to disable
+them by changing flags in the driver header and recompile.
+.\"
+.\" AUTHOR part
+.\"
+.SH AUTHOR
+Anthony D. Joseph \- adj@lcs.mit.edu
+.br
+Jean Tourrilhes \- jt@hplb.hpl.hp.com
+.br
+(+ others - see source code for details)
+.\"
+.\" SEE ALSO part
+.\"
+.SH SEE ALSO
+.BR wavelan (4),
+.BR cardmgr (8),
+.BR pcmcia (5),
+.BR ifconfig (8),
+.BR insmod (1),
+.BR iwconfig (8),
+.BR iwspy (8),
+.BR iwpriv (8).
Index: oldkernel/linux/pcmcia-cs-3.1.15/man/wvlan_cs.4
diff -u /dev/null linux/pcmcia-cs-3.1.15/man/wvlan_cs.4:1.1
--- /dev/null	Mon Jul 31 21:15:11 2000
+++ linux/pcmcia-cs-3.1.15/man/wvlan_cs.4	Fri Jul  7 16:34:58 2000
@@ -0,0 +1,305 @@
+.\" Copyright (c) 1999 Andreas Neuhaus <andy@fasta.fh-dortmund.de>
+.\" wvlan_cs.c.4
+.\"
+.TH WVLAN_CS 4 "27/12/99" ""
+.\"
+.\" NAME part
+.\"
+.SH NAME
+wvlan_cs \- Lucent WaveLAN/IEEE 802.11 device driver
+.\"
+.\" SYNOPSIS part
+.\"
+.SH SYNOPSIS
+.B insmod wvlan_cs.o
+.RB [ irq_list=\c
+.IR i,j,... ]
+.RB [ port_type=\c
+.IR n ]
+.RB [ station_name=\c
+.IR s ]
+.RB [ network_name=\c
+.IR s ]
+.RB [ channel=\c
+.IR n ]
+.RB [ ap_density=\c
+.IR n ]
+.RB [ medium_reservation=\c
+.IR n ]
+.RB [ frag_threshold=\c
+.IR n ]
+.RB [ transmit_rate=\c
+.IR n ]
+.RB [ eth=\c
+.IR n ]
+.RB [ mtu=\c
+.IR n ]
+.\"
+.\" DESCRIPTION part
+.\"
+.SH DESCRIPTION
+.I wvlan_cs
+is the low-level Card Services driver for the Lucent
+.B WaveLAN/IEEE 802.11
+and compatible (the NCR
+.B WaveLAN/IEEE 802.11
+, the Cabletron
+.B RoamAbout 802.11 DS
+, the Melco
+.B WLI-PCM-L11
+) wireless ethernet adapters.  When this driver is attached to a card, it
+allocates the next available device (wvlan0..wvlan#).  This
+device name will be passed on to
+.IR cardmgr (8)
+for the card configuration, and reported in the kernel log.
+.\"
+.\" PARAMETER part
+.\"
+.SH PARAMETERS
+.TP
+.BI irq_list = i,j,...
+Specifies the set of interrupts that may be allocated by this driver.
+.TP
+.BI port_type = n
+Select WaveLAN port type:
+.RI [ 1 ]
+BSS - Basic Service Set (default),
+.RI [ 2 ]
+WDS - Wireless Distribution System,
+.RI [ 3 ]
+Pseudo-IBSS - ad-hoc network (no AccessPoint, PtP).
+.TP
+.BI station_name = s
+Sets the station name.
+The default is card-configured.
+.TP
+.BI network_name = s
+Sets the independent network name in ad-hoc mode.
+Sets the desired network (desired ESSID) to connect to if using an access point.
+The default is card-configured.
+.TP
+.BI channel = n
+Channel (frequency) for ad-hoc networks and is useless if using an access point.
+Valid range:
+.RI [ 0 - 14 ]
+(depends on local restrictions) and defaults to
+.RI [ 3 ]
+.TP
+.BI ap_density = n
+Sets the access point density (sensitivity). This affects modem and roaming thresholds.
+.RI [ 1 ]
+low density (default),
+.RI [ 2 ]
+medium density,
+.RI [ 3 ]
+high density.
+.TP
+.BI medium_reservation = n
+Sets the medium reservation (RTS/CTS frame length), which affects the number of octets in a message or fragment above which a RTS/CTS handshake is performed.
+.RI [ 500 ]
+hidden stations,
+.RI [ 2347 ]
+no RTS/CTS (default). Valid range:
+.RI [ 0 - 2347]
+.TP
+.BI frag_threshold = n
+Defines the number of bytes used for the fragmentation boundary for directed messages (Fragmentation length unicast message transmission).
+.RI [ 2346 ]
+is the default, valid range:
+.RI [ 256 - 2346 ]
+(even numbers only!).
+.TP
+.BI transmit_rate = n
+Transmit rate control.
+.RI [ 1 ]
+fixed low,
+.RI [ 2 ]
+fixed high,
+.RI [ 3 ]
+auto select high (default),
+.RI [ 4 ]
+fixed medium,
+.RI [ 5 ]
+fixed high,
+.RI [ 6 ]
+auto select standard,
+.RI [ 7 ]
+auto select medium.
+.TP
+.BI eth = n
+Network device naming. By default
+.RI [ 0 ]
+devices are named wvlan#, set this to
+.RI [ 1 ]
+to have devices named eth#.
+.TP
+.BI mtu = n
+Maximum transfer unit.
+.RI [ 1500 ]
+is the default, valid range:
+.RI [ 256 - 2296 ]
+.\"
+.\" WIRELESS part
+.\"
+.SH WIRELESS EXTENSIONS
+Use
+.IR iwconfig (8)
+to manipulate wireless extensions. 
+You need a kernel which was compiled with CONFIG_NET_RADIO set.
+It is recommended that you run at least Linux kernel 2.2.11 and use wireless_tools 19.
+Older version do not support all of the current commands.
+.\"	ESSID sub part
+.SS ESSID (network ID)
+Set the network ID of the desired network to connect to (with access point)
+or the name of your private ad-hoc network (no access point).
+.\"	mode sub part
+.SS Mode
+Set the operating mode to
+.I Ad-Hoc
+or
+.IR Managed .
+In managed mode, the card will try to connect to an Access Point, to
+get access to the infrastructure. In Ad-Hoc mode, the card doesn't
+require an Access Point and can communicate directly with its peers.
+.\"	Frequency sub part
+.SS Frequency & channels
+Channel (frequency) for ad-hoc networks. The frequency is changed
+immediately and is only changeable in ad-hoc network mode. You may
+enter a frequency value in the 2.4 GHz band or the channel number.
+.br
+Valid values:
+.I 2.412, 2.417, 2.422, 2.427, 2.432, 2.437, 2.442, 2.447, 2.452, 2.457, 2.462,
+.I 2.467, 2.472
+or
+.I 2.484
+GHz (depends on local restrictions) and defaults to
+.I 2.422
+GHz
+.\"	Sens sub part
+.SS Sens
+Set the Access Point density (sensitivity). This affects modem and
+roaming thresholds.
+.RI [ 1 ]
+low density (default),
+.RI [ 2 ]
+medium density,
+.RI [ 3 ]
+high density.
+.\"	Rts sub part
+.SS Rts
+Sets the medium reservation threshold (RTS/CTS frame length), which
+affects the number of octets in a message or fragment above which a
+RTS/CTS handshake is performed.
+.br
+Use
+.RI [ 500 ]
+when there are hidden stations or large number of nodes and
+.RI [ 2347 ]
+for no RTS/CTS (default). Valid range:
+.RI [ 0 - 2347]
+.\"	Frag sub part
+.SS Frag
+Defines the number of bytes used for the fragmentation boundary for
+directed messages (Fragmentation length unicast message
+transmission). To be use when you have interferences on the radio,
+because it decreases significantely the performance.
+.br
+.RI [ 2346 ]
+is the default, valid range:
+.RI [ 256 - 2346 ].
+.\"	Rate sub part
+.SS Rate
+Set the rate used for transmission (but not reception). You may want
+to set it to a fixed value for high number of nodes.
+.br
+The default is
+.IR auto ,
+or you may use
+.IR 1 ", " 2  ", " 5.5 " or " 11
+Mb/s (of course, 2 Mb/s cards can get the higher speeds).
+.\"	Enc sub part
+.SS Enc
+Set the encryption key
+.RI [ 0
+to
+.IR FFFF-FFFF-FF ].
+Use
+.RI [ off ]
+and
+.RI [ on ]
+to disable and reenable the hardware encryption. This feature works
+only for device with encryption option (Silver or Gold).
+.br
+The card has 4 different keys that you may select, and you can choose
+the default key for transmission (see
+.IR iwconfig (8)).
+.\"	Nick sub part
+.SS Nick (station name)
+Set the station name (only used for debugging purpose).
+.\"	Spy sub part
+.SS Statistics spy
+Set a list of MAC addresses in the driver (up to 8) and get the last
+quality of link for each of those (see
+.IR iwspy (8)).
+.\"	/proc/net/wireless part
+.SS /proc/net/wireless
+.I status
+is the status reported by the modem.
+.I Level
+and
+.I Noise
+refer to the signal level and noise level in dBm.
+.\"
+.\" IOCTL part
+.\"
+.SH PRIVATE IOCTL
+You may use
+.IR iwpriv (8)
+to manipulate private ioctls.
+.\"	Histogram part
+.SS Histogram
+This functionality allow to set a number of signal level intervals and
+to count the number of packets received in each of those defined
+intervals. This distribution might be used to calculate the mean value
+and standard deviation of the signal level.
+.\"
+.\" SPECIFIC part
+.\"
+.SH SPECIFIC NOTES
+Some of the mentioned features are optional. You may enable to disable
+them by changing flags in the driver header and recompile.
+.PP
+It's currently not possible to use the WaveLAN/IEEE as a bridge (MAC
+level). This is not a restriction of the driver, the NIC firmware
+doesn't allow to send out packets with another source MAC address
+than its own (which is mandatory required for bridgeing to work).
+.PP
+Also the WaveLAN/IEEE can be used to connect to an Access Point, but
+cannot be an Access Point itself (because lack of bridgeing).
+.\"
+.\" AUTHOR part
+.\"
+.SH AUTHOR
+Andreas Neuhaus <andy@fasta.fh-dortmund.de>
+.\"
+.\" THANKS part
+.\"
+.SH THANKS
+I would like to thank Lucent Technology for making the necessary information
+available to public. Thanks to Nico Valster and Jan Martejin at Lucent for
+technical support. Thanks to Frank Bruegmann, who managed to get additional
+hardware for me so that I can now do tests in different environments. And
+thanks to Jean Tourrilhes for many patches and wireless kernel extensions.
+Also many thanks to everybody who tested and helped me developing this
+driver :-)
+.\"
+.\" SEE ALSO part
+.\"
+.SH SEE ALSO
+.BR cardmgr (8),
+.BR pcmcia (5),
+.BR ifconfig (8),
+.BR insmod (1),
+.BR iwconfig (8),
+.BR iwspy (8),
+.BR iwpriv (8).
Index: oldkernel/linux/pcmcia-cs-3.1.15/man/xirc2ps_cs.4
diff -u /dev/null linux/pcmcia-cs-3.1.15/man/xirc2ps_cs.4:1.1
--- /dev/null	Mon Jul 31 21:15:11 2000
+++ linux/pcmcia-cs-3.1.15/man/xirc2ps_cs.4	Fri Jul  7 16:34:58 2000
@@ -0,0 +1,41 @@
+.\" Copyright (c) 1997 Werner Koch <werner.koch@guug.de>
+.\" xirc2ps_cs.4,v 1.5 1998/09/15 12:40:59 wk Exp
+.\"
+.TH XIRC2PS_CS 4 "1.5  1998/09/15 12:40:59" ""
+.SH NAME
+xirc2ps_cs \- Xircom CE2ps (and newer) device driver
+.SH SYNOPSIS
+.B insmod xirc2ps_cs.o
+.RB [ pc_debug=\c
+.IR n ]
+.RB [ irq_mask=\c
+.IR n ]
+.RB [ lockup_hack=\c
+.IR 1 ]
+.SH DESCRIPTION
+.B xirc2ps_cs
+is the low-level Card Services driver for the Xircom
+PCMCIA ethernet adapters.  When this driver is attached to a card, it
+allocates the next available ethernet device.
+.SH PARAMETERS
+.TP
+.BI pc_debug= n
+Selects the PCMCIA debugging level.  This parameter is only available
+if the module is compiled with debugging enabled.  A non-zero value
+enables debugging.
+.TP
+.BI irq_mask= n
+Specifies the set of interrupts that may be allocated by this driver.
+Each bit of the mask word corresponds to one irq number: 0x0001 is irq
+0, 0x0002 is irq 1, etc.
+.TP
+.BI lockup_hack= 1
+Enables a hack to avoid lockups on some cards.	Use this only if you
+really have lockup problems with your card.
+.SH "SEE ALSO"
+cardmgr(8), pcmcia(5).
+.SH BUGS
+Please report to <xircom-bugs@isil.d.shuttle.de>
+.SH AUTHOR
+Werner Koch
+<werner.koch@guug.de>
Index: oldkernel/linux/pcmcia-cs-3.1.15/modules/Makefile
diff -u /dev/null linux/pcmcia-cs-3.1.15/modules/Makefile:1.1
--- /dev/null	Mon Jul 31 21:15:11 2000
+++ linux/pcmcia-cs-3.1.15/modules/Makefile	Fri Jul  7 16:34:58 2000
@@ -0,0 +1,66 @@
+#
+# Copyright (C) 1998 David A. Hinds -- dhinds@pcmcia.sourceforge.org
+#
+# Makefile 1.114 2000/04/29 02:00:30
+#
+
+# Include site dependent options and kernel configuration
+include ../config.mk
+
+# Don't remove "-O2" or bad things will happen!  We use -O2 rather
+# than -O3 because it yields smaller code; this is not performance
+# critical stuff.
+
+CFLAGS = -O2 -Wall -Wstrict-prototypes -pipe
+CPPFLAGS += $(PCDEBUG) -D__KERNEL__ -DMODULE
+
+CC += $(AFLAGS) $(KFLAGS)
+
+SRCS    = cs.c cistpl.c rsrc_mgr.c bulkmem.c ds.c
+CORE    = cs.o cistpl.o rsrc_mgr.o bulkmem.o
+MODULES = pcmcia_core.o ds.o
+
+ifdef CONFIG_CARDBUS
+SRCS    += cardbus.c cb_enabler.c
+CORE    += cardbus.o
+MODULES += cb_enabler.o
+endif
+
+# Which socket drivers do we need?
+ifeq ($(ARCH), arm)
+SRCS	+= sa1100.c
+MODULES	+= sa1100.o
+else
+ifdef CONFIG_8xx
+SRCS	+= m8xx_pcmcia.c
+MODULES	+= m8xx_pcmcia.o
+else
+SRCS	+= i82365.c tcic.c
+MODULES	+= i82365.o tcic.o
+endif
+endif
+
+ifdef CONFIG_PCI
+SRCS    += pci_fixup.c
+CORE    += pci_fixup.o
+endif
+
+ifdef CONFIG_PNP_BIOS
+SRCS    += pnp_bios.c pnp_proc.c pnp_rsrc.c
+CORE    += pnp_bios.o pnp_proc.o pnp_rsrc.o
+endif
+
+all:	$(MODULES)
+
+pcmcia_core.o: $(CORE)
+	$(LD) -r -o $@ $(CORE)
+	chmod -x $@
+
+clean:
+	rm -f core core.* *.o .*.o *.s *.a *~ .depend .depfiles/*.d
+
+install install-modules: $(MODULES)
+	@mkdir -p $(PREFIX)$(MODDIR)/pcmcia
+	cp $(MODULES) $(PREFIX)$(MODDIR)/pcmcia
+
+include ../rules.mk
Index: oldkernel/linux/pcmcia-cs-3.1.15/modules/bulkmem.c
diff -u /dev/null linux/pcmcia-cs-3.1.15/modules/bulkmem.c:1.1
--- /dev/null	Mon Jul 31 21:15:11 2000
+++ linux/pcmcia-cs-3.1.15/modules/bulkmem.c	Fri Jul  7 16:34:58 2000
@@ -0,0 +1,650 @@
+/*======================================================================
+
+    PCMCIA Bulk Memory Services
+
+    bulkmem.c 1.36 2000/05/09 20:53:56
+
+    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@pcmcia.sourceforge.org>.  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 <pcmcia/config.h>
+#define __NO_VERSION__
+#include <pcmcia/k_compat.h>
+
+#ifdef __LINUX__
+#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>
+#endif
+
+#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);
+    wacquire(&mtd->mtd_req);
+    for (ret = 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... */
+	    wsleeptimeout(&mtd->mtd_req, HZ);
+	    break;
+	case MTD_WAITTIMER:
+	case MTD_WAITRDY:
+	    wsleeptimeout(&mtd->mtd_req, req->Timeout*HZ/1000);
+	    req->Function |= MTD_REQ_TIMEOUT;
+	    break;
+	case MTD_WAITPOWER:
+	    wsleep(&mtd->mtd_req);
+	    break;
+	}
+	if (signal_pending(current))
+	    printk(KERN_NOTICE "cs: do_mtd_request interrupted!\n");
+    }
+    wrelease(&mtd->mtd_req);
+    if (tries == 20) {
+	printk(KERN_NOTICE "cs: MTD request timed out!\n");
+	ret = CS_GENERAL_FAILURE;
+    }
+    wakeup(&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;
+    wacquire(&mtd->mtd_req);
+    ret = EVENT(mtd, CS_EVENT_MTD_REQUEST, CS_EVENT_PRI_LOW);
+    wrelease(&mtd->mtd_req);
+    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(busy);
+	/* Resubmit anything waiting for a request to finish */
+	wakeup(&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;
+	    init_timer(&busy->timeout);
+	    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 */
+
+/*======================================================================
+
+    Erase queue management functions
+    
+======================================================================*/
+
+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);
+    if (!queue) return CS_OUT_OF_RESOURCE;
+    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(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;
+    }
+#ifdef __BEOS__
+    if (region->dev_info[0] != '\0') {
+	char n[80];
+	struct module_info *m;
+	sprintf(n, MTD_MODULE_NAME("%s"), region->dev_info);
+	if (get_module(n, &m) != B_OK)
+	    dprintf("cs: could not find MTD module %s\n", n);
+    }
+#endif
+    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;
+#ifdef __BEOS__
+    if (handle->dev_info[0] != '\0') {
+	char n[80];
+	sprintf(n, MTD_MODULE_NAME("%s"), handle->dev_info);
+	put_module(n);
+    }
+#endif
+    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 */
+
+/*======================================================================
+
+    This isn't needed for anything I could think of.
+    
+======================================================================*/
+
+int copy_memory(memory_handle_t handle, copy_op_t *req)
+{
+    if (CHECK_REGION(handle))
+	return CS_BAD_HANDLE;
+    return CS_UNSUPPORTED_FUNCTION;
+}
+
Index: oldkernel/linux/pcmcia-cs-3.1.15/modules/cardbus.c
diff -u /dev/null linux/pcmcia-cs-3.1.15/modules/cardbus.c:1.1
--- /dev/null	Mon Jul 31 21:15:11 2000
+++ linux/pcmcia-cs-3.1.15/modules/cardbus.c	Fri Jul  7 16:34:58 2000
@@ -0,0 +1,699 @@
+/*======================================================================
+  
+    Cardbus device configuration
+    
+    cardbus.c 1.72 2000/05/16 23:39:20
+
+    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@pcmcia.sourceforge.org>.  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.
+    
+======================================================================*/
+
+#include <pcmcia/config.h>
+#define __NO_VERSION__
+#include <pcmcia/k_compat.h>
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/config.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		pci_read_config_byte
+#define pci_writeb		pci_write_config_byte
+#define pci_readw		pci_read_config_word
+#define pci_writew		pci_write_config_word
+#define pci_readl		pci_read_config_dword
+#define pci_writel		pci_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
+
+#if (LINUX_VERSION_CODE >= VERSION(2,1,103))
+#define NEW_LINUX_PCI
+#endif
+#if (LINUX_VERSION_CODE >= VERSION(2,3,40))
+#define NEWER_LINUX_PCI
+#endif
+
+typedef struct cb_config_t {
+    u_int		size[7];
+    struct pci_dev	dev;
+#ifndef NEW_LINUX_PCI
+    struct {
+	u_long		base_address[6];
+	u_long		rom_address;
+    } extra;
+#endif
+} cb_config_t;
+
+#if (LINUX_VERSION_CODE >= VERSION(2,3,15))
+#define BASE(cb,n)	((cb).dev.resource[n].start)
+#define ROM(cb)		((cb).dev.resource[6].start)
+#else
+#ifdef NEW_LINUX_PCI
+#define BASE(cb,n)	((cb).dev.base_address[n])
+#define ROM(cb)		((cb).dev.rom_address)
+#else
+#define BASE(cb,n)	((cb).extra.base_address[n])
+#define ROM(cb)		((cb).extra.rom_address)
+#endif
+#endif
+
+/* There are three classes of bridge maps: IO ports,
+   non-prefetchable memory, and prefetchable memory */
+typedef enum { B_IO, B_M1, B_M2 } map_type;
+
+static const u_int map_flags[] = {
+    PCI_BASE_ADDRESS_SPACE_IO,
+    PCI_BASE_ADDRESS_SPACE_MEMORY,
+    PCI_BASE_ADDRESS_SPACE_MEMORY | PCI_BASE_ADDRESS_MEM_PREFETCH
+};
+
+/*=====================================================================
+
+    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;
+    cb_config_t *c = s->cb_config;
+    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], 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(&c[0].dev, br, 0xffffffff);
+    pci_readl(&c[0].dev, 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, sz, 0, "cb_enabler") != 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(&c[0].dev, br, base | 1);
+    pci_writeb(&c[0].dev, 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) {
+	cb_config_t *c = s->cb_config;
+	/* 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(&c[0].dev, PCI_COMMAND, 0);
+	pci_writel(&c[0].dev, 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)
+{
+    cb_config_t *c = s->cb_config;
+    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(&c[fn].dev, 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;
+	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)
+{
+    u_short vend, v, dev;
+    u_char hdr, fn, bus = s->cap.cardbus;
+    cb_config_t *c;
+
+    struct pci_dev tmp;
+    int i;
+    tmp.bus = s->cap.cb_bus; tmp.devfn = 0;
+#ifdef NEWER_LINUX_PCI
+    list_add(&tmp.global_list, &pci_devices);
+#else
+    tmp.next = pci_devices; pci_devices = &tmp;
+#endif
+
+    /* The APA1480 did not like reading the vendor ID first */
+    pci_readw(&tmp, PCI_DEVICE_ID, &dev);
+    pci_readw(&tmp, PCI_VENDOR_ID, &vend);
+    printk(KERN_INFO "cs: cb_alloc(bus %d): vendor 0x%04x, "
+	   "device 0x%04x\n", bus, vend, dev);
+
+    pci_readb(&tmp, PCI_HEADER_TYPE, &hdr);
+    if (hdr & 0x80) {
+	/* Count functions */
+	for (fn = 0; fn < 8; fn++) {
+	    tmp.devfn = fn;
+	    pci_readw(&tmp, 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;
+
+    for (i = 0; i < fn; i++) {
+	c[i].dev.bus = s->cap.cb_bus;
+	c[i].dev.devfn = i;
+#ifdef NEWER_LINUX_PCI
+	list_add_tail(&c[i].dev.bus_list, &s->cap.cb_bus->devices); 
+	list_add_tail(&c[i].dev.global_list, &pci_devices);
+#else
+	if (i < fn-1) {
+	    c[i].dev.sibling = c[i].dev.next = &c[i+1].dev;
+	}
+#endif
+    }
+#ifdef NEWER_LINUX_PCI
+    list_del(&tmp.global_list);
+#else
+    s->cap.cb_bus->devices = &c[0].dev;
+    /* Link into PCI device chain */
+    c[fn-1].dev.next = tmp.next;
+    pci_devices = &c[0].dev;
+#endif
+    for (i = 0; i < fn; i++) {
+	c[i].dev.vendor = vend;
+	pci_readw(&c[i].dev, PCI_DEVICE_ID, &c[i].dev.device);
+	pci_readl(&c[i].dev, PCI_CLASS_REVISION, &c[i].dev.class);
+	c[i].dev.class >>= 8;
+#ifdef NEW_LINUX_PCI
+	c[i].dev.hdr_type = hdr;
+#endif
+#if defined(HAS_PROC_BUS) && !defined(NEWER_LINUX_PCI)
+	pci_proc_attach_device(&c[i].dev);
+#endif
+    }
+    return CS_SUCCESS;
+}
+
+void cb_free(socket_info_t *s)
+{
+    cb_config_t *c = s->cb_config;
+
+    if (c) {
+#ifdef NEWER_LINUX_PCI
+	int i;
+	for (i = 0; i < s->functions; i++)
+	    list_del(&c[i].dev.global_list);
+	INIT_LIST_HEAD(&s->cap.cb_bus->devices);
+#else
+	struct pci_dev **p, *q;
+	/* 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;
+#ifdef HAS_PROC_BUS
+	    pci_proc_detach_device(q);
+#endif
+	}
+	if (*p) *p = q;
+	s->cap.cb_bus->devices = NULL;
+#endif
+	kfree(s->cb_config);
+	s->cb_config = NULL;
+	printk(KERN_INFO "cs: cb_free(bus %d)\n", s->cap.cardbus);
+    }
+}
+
+/*=====================================================================
+
+    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, *name;
+    u_int sz, align, m, mask[3], num[3], base[3];
+    int irq;
+
+    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(&c[i].dev, CB_BAR(j), 0xffffffff);
+	    pci_readl(&c[i].dev, 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(&c[i].dev, CB_ROM_BASE, 0xffffffff);
+	pci_readl(&c[i].dev, 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]) {
+	for (align = 1; align < mask[B_IO]; align <<= 1) ;
+	if (find_io_region(&s->io[0].BasePort, num[B_IO],
+			   align, 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]) {
+	for (align = 1; align < mask[B_M1]; align <<= 1) ;
+	if (find_mem_region(&s->win[0].base, num[B_M1], align,
+			    0, name) != 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]) {
+	for (align = 1; align < mask[B_M2]; align <<= 1) ;
+	if (find_mem_region(&s->win[1].base, num[B_M2], align,
+			    0, name) != 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], j) = base[m] | map_flags[m];
+		}
+	    }
+	}
+    }
+    
+    /* Allocate interrupt if needed */
+    s->irq.AssignedIRQ = irq = 0;
+    for (i = 0; i < fn; i++) {
+	pci_readb(&c[i].dev, PCI_INTERRUPT_PIN, &j);
+	if (j == 0) continue;
+	if ((irq == 0) && (s->cap.irq_mask & (1 << s->cap.pci_irq)))
+	    irq = s->cap.pci_irq;
+#ifdef CONFIG_ISA
+	if (irq == 0) {
+	    int try;
+	    for (try = 0; try < 2; try++) {
+		for (irq = 0; irq < 32; irq++)
+		    if (((s->cap.irq_mask >> irq) & 1) &&
+			(try_irq(IRQ_TYPE_EXCLUSIVE, irq, try) == 0))
+			break;
+		if (irq < 32) break;
+	    }
+	    if (irq == 32) irq = 0;
+	}
+	if (irq == 0) {
+	    printk(KERN_NOTICE "cs: could not allocate interrupt"
+		   " for CardBus socket %d\n", s->sock);
+	    goto failed;
+	}
+#endif
+    }
+    s->irq.AssignedIRQ = irq;
+    for (i = 0; i < fn; i++)
+	c[i].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], j) != 0)
+		pci_writel(&c[i].dev, CB_BAR(j), BASE(c[i], j));
+	}
+	if (ROM(c[i]) != 0)
+	    pci_writel(&c[i].dev, CB_ROM_BASE, ROM(c[i]) | 1);
+    }
+
+    /* Set up PCI interrupt and command registers */
+    for (i = 0; i < s->functions; i++) {
+	pci_writeb(&c[i].dev, PCI_COMMAND, PCI_COMMAND_MASTER |
+		   PCI_COMMAND_IO | PCI_COMMAND_MEMORY);
+	pci_writeb(&c[i].dev, PCI_CACHE_LINE_SIZE, 8);
+    }
+    
+    if (s->irq.AssignedIRQ) {
+	for (i = 0; i < s->functions; i++)
+	    pci_writeb(&c[i].dev, 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);
+    }
+}
Index: oldkernel/linux/pcmcia-cs-3.1.15/modules/cb_enabler.c
diff -u /dev/null linux/pcmcia-cs-3.1.15/modules/cb_enabler.c:1.1
--- /dev/null	Mon Jul 31 21:15:11 2000
+++ linux/pcmcia-cs-3.1.15/modules/cb_enabler.c	Fri Jul  7 16:34:58 2000
@@ -0,0 +1,469 @@
+/*======================================================================
+
+    CardBus device enabler
+
+    cb_enabler.c 1.29 2000/03/31 19:56:11
+
+    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@pcmcia.sourceforge.org>.  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 <pcmcia/config.h>
+#include <pcmcia/k_compat.h>
+
+#ifdef __LINUX__
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/malloc.h>
+#include <linux/string.h>
+#include <linux/timer.h>
+#endif
+
+#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.29 2000/03/31 19:56:11 (David Hinds)";
+#else
+#define DEBUG(n, args...) do { } while (0)
+#endif
+
+MODULE_AUTHOR("David Hinds <dhinds@pcmcia.sourceforge.org>");
+MODULE_DESCRIPTION("CardBus stub enabler module");
+
+/*====================================================================*/
+
+/* 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];
+
+#ifdef __BEOS__
+static cs_socket_module_info *cs;
+#define RSRC_MGR cs->
+#endif
+
+/*====================================================================*/
+
+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;
+
+    MOD_INC_USE_COUNT;
+    DEBUG(0, "cb_attach(%d)\n", n);
+
+    link = kmalloc(sizeof(struct dev_link_t), GFP_KERNEL);
+    if (!link) {
+	MOD_DEC_USE_COUNT;
+	return NULL;
+    }
+
+    memset(link, 0, sizeof(struct dev_link_t));
+    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_PHYSICAL |
+	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;
+    
+    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;
+
+    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(link);
+    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)
+	    cb_release((u_long)link);
+	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;
+    }
+}
+
+/*====================================================================*/
+
+#ifdef __LINUX__
+
+#if (LINUX_VERSION_CODE <= VERSION(2,1,17))
+
+#undef CONFIG_MODVERSIONS
+static struct symbol_table cb_enabler_symtab = {
+#include <linux/symtab_begin.h>
+#undef X
+#define X(sym) { (void *)&sym, SYMBOL_NAME_STR(sym) }
+    X(register_driver),
+    X(unregister_driver),
+#include <linux/symtab_end.h>
+};
+
+#else
+
+EXPORT_SYMBOL(register_driver);
+EXPORT_SYMBOL(unregister_driver);
+
+#endif
+
+static int __init init_cb_enabler(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;
+    }
+    register_symtab(&cb_enabler_symtab);
+    return 0;
+}
+
+static void __exit exit_cb_enabler(void)
+{
+    DEBUG(0, "cb_enabler: unloading\n");
+}
+
+module_init(init_cb_enabler);
+module_exit(exit_cb_enabler);
+
+#endif /* __LINUX__ */
+
+/*====================================================================*/
+
+#ifdef __BEOS__
+
+typedef struct module_info mod_t;
+
+static status_t std_ops(int32 op)
+{
+    switch (op) {
+    case B_MODULE_INIT:
+	DEBUG(0, ("%s\n", version));
+	ret = get_module(CS_SOCKET_MODULE_NAME, (struct module_info **)&cs);
+	if (ret != B_OK) return ret;
+	break;
+    case B_MODULE_UNINIT:
+	if (cs) put_module(CS_CLIENT_MODULE_NAME, cs);
+	break;
+    }
+    return B_OK;
+}
+
+static cb_enabler_module_info cb_enabler_info = {
+    { { CB_ENABLER_MODULE_NAME, 0, &std_ops }, NULL },
+    &register_driver,
+    &unregister_driver
+};
+
+_EXPORT module_info *modules[] = {
+    (module_info *)&cb_enabler_info,
+    NULL
+};
+
+#endif /* __BEOS__ */
Index: oldkernel/linux/pcmcia-cs-3.1.15/modules/cirrus.h
diff -u /dev/null linux/pcmcia-cs-3.1.15/modules/cirrus.h:1.1
--- /dev/null	Mon Jul 31 21:15:11 2000
+++ linux/pcmcia-cs-3.1.15/modules/cirrus.h	Fri Jul  7 16:34:58 2000
@@ -0,0 +1,174 @@
+/*
+ * cirrus.h 1.7 2000/04/24 21:19: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@pcmcia.sourceforge.org>.  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 */
+
+#define pd67_ext_get(s, r) \
+    (i365_set(s, PD67_EXT_INDEX, r), i365_get(s, PD67_EXT_DATA))
+#define pd67_ext_set(s, r, v) \
+    (i365_set(s, PD67_EXT_INDEX, r), i365_set(s, PD67_EXT_DATA, v))
+
+/* 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_EXTERN_DATA */
+#define PD67_EXD_VS1(s)		(0x01 << ((s)<<1))
+#define PD67_EXD_VS2(s)		(0x02 << ((s)<<1))
+
+/* 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 */
+
+/* Data structure for tracking vendor-specific state */
+typedef struct cirrus_state_t {
+    u_char		misc1;		/* PD67_MISC_CTL_1 */
+    u_char		misc2;		/* PD67_MISC_CTL_2 */
+    u_char		ectl1;		/* PD67_EXT_CTL_1 */
+    u_char		timer[6];	/* PD67_TIME_* */
+} cirrus_state_t;
+
+#endif /* _LINUX_CIRRUS_H */
Index: oldkernel/linux/pcmcia-cs-3.1.15/modules/cistpl.c
diff -u /dev/null linux/pcmcia-cs-3.1.15/modules/cistpl.c:1.1
--- /dev/null	Mon Jul 31 21:15:11 2000
+++ linux/pcmcia-cs-3.1.15/modules/cistpl.c	Fri Jul  7 16:34:58 2000
@@ -0,0 +1,1456 @@
+/*======================================================================
+
+    PCMCIA Card Information Structure parser
+
+    cistpl.c 1.80 2000/03/31 03:53: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@pcmcia.sourceforge.org>.  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 <pcmcia/config.h>
+#define __NO_VERSION__
+#include <pcmcia/k_compat.h>
+
+#ifdef __LINUX__
+#include <linux/config.h>
+#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>
+#endif
+
+#include <pcmcia/cs_types.h>
+#include <pcmcia/bus_ops.h>
+#include <pcmcia/ss.h>
+#include <pcmcia/cs.h>
+#include <pcmcia/bulkmem.h>
+#include <pcmcia/cisreg.h>
+#include <pcmcia/cistpl.h>
+#include "cs_internal.h"
+#include "rsrc_mgr.h"
+
+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.
+    
+======================================================================*/
+
+/* Bits in attr field */
+#define IS_ATTR		1
+#define IS_INDIRECT	8
+
+static void set_cis_map(socket_info_t *s, pccard_mem_map *mem)
+{
+    s->ss_entry(s->sock, SS_SetMemMap, mem);
+    if (s->cap.features & SS_CAP_STATIC_MAP) {
+	if (s->cis_virt)
+	    bus_iounmap(s->cap.bus, s->cis_virt);
+	s->cis_virt = bus_ioremap(s->cap.bus, mem->sys_start,
+				  s->cap.map_size);
+    }
+}
+
+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, *buf = ptr;
+    
+    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 & IS_INDIRECT) {
+	/* Indirect accesses use a bunch of special registers at fixed
+	   locations in common memory */
+	u_char flags = ICTRL0_COMMON|ICTRL0_AUTOINC|ICTRL0_BYTEGRAN;
+	if (attr & IS_ATTR) { addr *= 2; flags = ICTRL0_AUTOINC; }
+	mem->card_start = 0;
+	set_cis_map(s, mem);
+	sys = s->cis_virt;
+	bus_writeb(s->cap.bus, flags, sys+CISREG_ICTRL0);
+	bus_writeb(s->cap.bus, addr & 0xff, sys+CISREG_IADDR0);
+	bus_writeb(s->cap.bus, (addr>>8) & 0xff, sys+CISREG_IADDR1);
+	bus_writeb(s->cap.bus, (addr>>16) & 0xff, sys+CISREG_IADDR2);
+	bus_writeb(s->cap.bus, (addr>>24) & 0xff, sys+CISREG_IADDR3);
+	for ( ; len > 0; len--, buf++)
+	    *buf = bus_readb(s->cap.bus, sys+CISREG_IDATA0);
+    } else {
+	u_int inc = 1;
+	if (attr) { mem->flags |= MAP_ATTRIB; inc++; addr *= 2; }
+	sys += (addr & (s->cap.map_size-1));
+	mem->card_start = addr & ~(s->cap.map_size-1);
+	while (len) {
+	    set_cis_map(s, mem);
+	    sys = s->cis_virt + (addr & (s->cap.map_size-1));
+	    for ( ; len > 0; len--, buf++, sys += inc) {
+		if (sys == s->cis_virt+s->cap.map_size) break;
+		*buf = bus_readb(s->cap.bus, sys);
+	    }
+	    mem->card_start += s->cap.map_size;
+	    addr = 0;
+	}
+    }
+    DEBUG(3, "cs:  %#2.2x %#2.2x %#2.2x %#2.2x ...\n",
+	  *(u_char *)(ptr+0), *(u_char *)(ptr+1),
+	  *(u_char *)(ptr+2), *(u_char *)(ptr+3));
+}
+
+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, *buf = ptr;
+    
+    DEBUG(3, "cs: write_cis_mem(%d, %#x, %u)\n", attr, addr, len);
+    if (setup_cis_mem(s) != 0) return;
+    mem->flags |= MAP_ACTIVE; mem->flags &= ~MAP_ATTRIB;
+
+    if (attr & IS_INDIRECT) {
+	/* Indirect accesses use a bunch of special registers at fixed
+	   locations in common memory */
+	u_char flags = ICTRL0_COMMON|ICTRL0_AUTOINC|ICTRL0_BYTEGRAN;
+	if (attr & IS_ATTR) { addr *= 2; flags = ICTRL0_AUTOINC; }
+	mem->card_start = 0;
+	set_cis_map(s, mem);
+	sys = s->cis_virt;
+	bus_writeb(s->cap.bus, flags, sys+CISREG_ICTRL0);
+	bus_writeb(s->cap.bus, addr & 0xff, sys+CISREG_IADDR0);
+	bus_writeb(s->cap.bus, (addr>>8) & 0xff, sys+CISREG_IADDR1);
+	bus_writeb(s->cap.bus, (addr>>16) & 0xff, sys+CISREG_IADDR2);
+	bus_writeb(s->cap.bus, (addr>>24) & 0xff, sys+CISREG_IADDR3);
+	for ( ; len > 0; len--, buf++)
+	    bus_writeb(s->cap.bus, *buf, sys+CISREG_IDATA0);
+    } else {
+	int inc = 1;
+	if (attr & IS_ATTR) { mem->flags |= MAP_ATTRIB; inc++; addr *= 2; }
+	mem->card_start = addr & ~(s->cap.map_size-1);
+	while (len) {
+	    set_cis_map(s, mem);
+	    sys = s->cis_virt + (addr & (s->cap.map_size-1));
+	    for ( ; len > 0; len--, buf++, sys += inc) {
+		if (sys == s->cis_virt+s->cap.map_size) break;
+		bus_writeb(s->cap.bus, *buf, sys);
+	    }
+	    mem->card_start += s->cap.map_size;
+	    addr = 0;
+	}
+    }
+}
+
+/*======================================================================
+
+    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->cap.features & SS_CAP_STATIC_MAP) &&
+	(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,
+			    s->cap.map_size, low, "card services")) {
+	    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);
+	if (!(s->cap.features & SS_CAP_STATIC_MAP))
+	    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;
+	s->cis_virt = NULL;
+    }
+}
+
+/*======================================================================
+
+    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:4;
+    u_int		has_link:1;
+    u_int		mfc_fn:3;
+    u_int		space:4;
+} 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_INDIRECT) ||
+	    (link[0] == CISTPL_NO_LINK)) {
+	    switch (link[0]) {
+	    case CISTPL_LONGLINK_A:
+		HAS_LINK(tuple->Flags) = 1;
+		LINK_SPACE(tuple->Flags) = attr | IS_ATTR;
+		read_cis_cache(s, attr, ofs+2, 4, &tuple->LinkOffset);
+		break;
+	    case CISTPL_LONGLINK_C:
+		HAS_LINK(tuple->Flags) = 1;
+		LINK_SPACE(tuple->Flags) = attr & ~IS_ATTR;
+		read_cis_cache(s, attr, ofs+2, 4, &tuple->LinkOffset);
+		break;
+	    case CISTPL_INDIRECT:
+		HAS_LINK(tuple->Flags) = 1;
+		LINK_SPACE(tuple->Flags) = IS_ATTR | IS_INDIRECT;
+		tuple->LinkOffset = 0;
+		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;
+}
+
+/*====================================================================*/
+
+#define _MIN(a, b)		(((a) < (b)) ? (a) : (b))
+
+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;
+
+    if (CHECK_HANDLE(handle))
+	return CS_BAD_HANDLE;
+
+    info->Chains = reserved = 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; we should really have either that
+       or a CFTABLE_ENTRY of some sort */
+    if ((tuple.TupleCode != CISTPL_DEVICE) &&
+	(read_tuple(handle, CISTPL_CFTABLE_ENTRY, &p) != CS_SUCCESS) &&
+	(read_tuple(handle, CISTPL_CFTABLE_ENTRY_CB, &p) != CS_SUCCESS))
+	return CS_SUCCESS;
+
+    /* All cards should have a MANFID tuple, and/or a VERS_1 or VERS_2
+       tuple, for card identification */
+    if ((read_tuple(handle, CISTPL_MANFID, &p) != CS_SUCCESS) &&
+	(read_tuple(handle, CISTPL_VERS_1, &p) != CS_SUCCESS) &&
+	(read_tuple(handle, CISTPL_VERS_2, &p) != CS_SUCCESS))
+	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;
+}
+
Index: oldkernel/linux/pcmcia-cs-3.1.15/modules/cs.c
diff -u /dev/null linux/pcmcia-cs-3.1.15/modules/cs.c:1.1
--- /dev/null	Mon Jul 31 21:15:11 2000
+++ linux/pcmcia-cs-3.1.15/modules/cs.c	Fri Jul  7 16:34:58 2000
@@ -0,0 +1,2480 @@
+/*======================================================================
+
+    PCMCIA Card Services -- core services
+
+    cs.c 1.259 2000/05/10 19:26: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@pcmcia.sourceforge.org>.  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 <pcmcia/config.h>
+#include <pcmcia/k_compat.h>
+
+#ifdef __LINUX__
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/config.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 <linux/pm.h>
+#include <asm/system.h>
+#include <asm/irq.h>
+#endif
+
+#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 PCMCIA_DEBUG
+int pc_debug = PCMCIA_DEBUG;
+MODULE_PARM(pc_debug, "i");
+static const char *version =
+"cs.c 1.259 2000/05/10 19:26:32 (David Hinds)";
+#endif
+
+#ifdef CONFIG_PCI
+#define PCI_OPT " [pci]"
+#else
+#define PCI_OPT ""
+#endif
+#ifdef CONFIG_CARDBUS
+#define CB_OPT " [cardbus]"
+#else
+#define CB_OPT ""
+#endif
+#ifdef CONFIG_PM
+#define PM_OPT " [apm]"
+#else
+#define PM_OPT ""
+#endif
+#ifdef CONFIG_PNP_BIOS
+#define PNP_OPT " [pnp]"
+#else
+#define PNP_OPT ""
+#endif
+#if !defined(CONFIG_CARDBUS) && !defined(CONFIG_PCI) && \
+    !defined(CONFIG_PM) && !defined(CONFIG_PNP_BIOS)
+#define OPTIONS " none"
+#else
+#define OPTIONS PCI_OPT CB_OPT PM_OPT PNP_OPT
+#endif
+
+#ifdef __BEOS__
+static const char *release = "BeOS PCMCIA Card Services " CS_RELEASE;
+#endif
+#ifdef __LINUX__
+static const char *release = "Linux PCMCIA Card Services " CS_RELEASE;
+#ifdef UTS_RELEASE
+static const char *kernel = "kernel build: " UTS_RELEASE " " UTS_VERSION;
+#endif
+#endif
+static const char *options = "options: " OPTIONS;
+
+MODULE_AUTHOR("David Hinds <dhinds@pcmcia.sourceforge.org>");
+MODULE_DESCRIPTION("Linux PCMCIA Card Services " CS_RELEASE
+		   "\n  options:" OPTIONS);
+
+/*====================================================================*/
+
+/* Parameters that can be set with 'insmod' */
+
+#define INT_MODULE_PARM(n, v) static int n = v; MODULE_PARM(n, "i")
+
+INT_MODULE_PARM(setup_delay,	HZ/20);		/* ticks */
+INT_MODULE_PARM(resume_delay,	HZ/5);		/* ticks */
+INT_MODULE_PARM(shutdown_delay,	HZ/40);		/* ticks */
+INT_MODULE_PARM(vcc_settle,	HZ*4/10);	/* ticks */
+INT_MODULE_PARM(reset_time,	10);		/* usecs */
+INT_MODULE_PARM(unreset_delay,	HZ/10);		/* ticks */
+INT_MODULE_PARM(unreset_check,	HZ/10);		/* ticks */
+INT_MODULE_PARM(unreset_limit,	30);		/* unreset_check's */
+
+/* Access speed for attribute memory windows */
+INT_MODULE_PARM(cis_speed,	300);		/* ns */
+
+/* Access speed for IO windows */
+INT_MODULE_PARM(io_speed,	0);		/* ns */
+
+/* Optional features */
+#ifdef CONFIG_PM
+INT_MODULE_PARM(do_apm, 1);
+#endif
+#ifdef CONFIG_PNP_BIOS
+INT_MODULE_PARM(do_pnp, 1);
+#endif
+
+/*====================================================================*/
+
+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 HAS_PROC_BUS
+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(HAS_PROC_BUS) && defined(PCMCIA_DEBUG)
+static 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;
+	spin_lock_init(&s->lock);
+	
+	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 HAS_PROC_BUS
+	if (proc_pccard) {
+	    char name[3];
+	    sprintf(name, "%02d", i);
+	    s->proc = proc_mkdir(name, proc_pccard);
+	    if (s->proc)
+		ss_entry(ns, SS_ProcSetup, s->proc);
+#ifdef PCMCIA_DEBUG
+	    if (s->proc)
+		create_proc_read_entry("clients", 0, s->proc,
+				       proc_read_clients, s);
+#endif
+	}
+#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;
+
+#ifdef HAS_PROC_BUS
+    for (i = 0; i < sockets; i++) {
+	s = socket_table[i];
+	if (s->ss_entry != ss_entry) continue;
+	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
+
+    for (;;) {
+	for (i = 0; i < sockets; i++) {
+	    s = socket_table[i];
+	    if (s->ss_entry == ss_entry) break;
+	}
+	if (i == sockets)
+	    break;
+	shutdown_socket(i);
+	release_cis_mem(s);
+	while (s->clients) {
+	    client = s->clients;
+	    s->clients = s->clients->next;
+	    kfree(client);
+	}
+	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->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
+    s->functions = 0;
+    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_PENDING) {
+	/* Does the socket need more time? */
+	DEBUG(2, "cs: setup_socket(%ld): status pending\n", i);
+	if (++s->setup_timeout > 100) {
+	    printk(KERN_NOTICE "cs: socket %ld voltage interrogation"
+		   " timed out\n", i);
+	} else {
+	    s->setup.expires = jiffies + HZ/10;
+	    add_timer(&s->setup);
+	}
+    } else 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->setup_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->setup_timeout > unreset_limit) {
+	    printk(KERN_NOTICE "cs: socket %ld timed out during"
+		   " reset\n", i);
+	    s->state &= ~EVENT_MASK;
+	} else {
+	    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;
+	    s->setup_timeout = 0;
+	    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_PM
+#if (LINUX_VERSION_CODE < VERSION(2,3,43))
+static int handle_pm_event(apm_event_t rqst)
+#else
+static int handle_pm_event(struct pm_dev *dev, pm_request_t rqst,
+			   void *data)
+#endif
+{
+    int i, stat;
+    socket_info_t *s;
+    static int down = 0;
+
+    /* <linux/pm.h> hides a hack so this works with old APM support */
+    switch (rqst) {
+    case PM_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 PM_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_pm_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, u_int lines, char *name)
+{
+    int i;
+    ioaddr_t try, align;
+
+    align = (*base) ? (lines ? 1<<lines : 0) : 1;
+    if (align && (align < num)) {
+	if (*base) {
+	    DEBUG(0, "odd IO request: num %04x align %04x\n",
+		  num, align);
+	    align = 0;
+	} else
+	    while (align && (align < num)) align <<= 1;
+    }
+    if (*base & ~(align-1)) {
+	DEBUG(0, "odd IO request: base %04x align %04x\n",
+	      *base, align);
+	align = 0;
+    }
+    for (i = 0; i < MAX_IO_WIN; i++) {
+	if (s->io[i].NumPorts == 0) {
+	    if (find_io_region(base, num, align, 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, 0, 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, 0, 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);
+    if (!client) return CS_OUT_OF_RESOURCE;
+    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_16;
+    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_16)
+	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,
+				 config_req_t *req)
+{
+    socket_info_t *s;
+    pccard_io_map io = { 0, 0, 0, 0, 1 };
+    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_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) {
+#ifdef __LINUX__
+	bus_free_irq(s->cap.bus, req->AssignedIRQ, req->Instance);
+#endif
+#ifdef __BEOS__
+	remove_io_interrupt_handler(req->AssignedIRQ, req->Handler,
+				    req->Instance);
+#endif
+    }
+
+#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, req->IOAddrLines,
+		       handle->dev_info))
+	return CS_IN_USE;
+
+    if (req->NumPorts2) {
+	if (alloc_io_space(s, req->Attributes2, &req->BasePort2,
+			   req->NumPorts2, req->IOAddrLines,
+			   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) {
+#ifdef __LINUX__
+	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;
+#endif
+#ifdef __BEOS__
+	install_io_interrupt_handler(irq, req->Handler,
+				     req->Instance, 0);
+#endif
+    }
+
+    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;
+    u_long align;
+    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;
+
+    /* Window size defaults to smallest available */
+    if (req->Size == 0)
+	req->Size = s->cap.map_size;
+    align = (((s->cap.features & SS_CAP_MEM_ALIGN) ||
+	      (req->Attributes & WIN_STRICT_ALIGN)) ?
+	     req->Size : s->cap.map_size);
+    if (req->Size & (s->cap.map_size-1))
+	return CS_BAD_SIZE;
+    if ((req->Base && (s->cap.features & SS_CAP_STATIC_MAP)) ||
+	(req->Base & (align-1)))
+	return CS_BAD_BASE;
+    if (req->Base)
+	align = 0;
+
+    /* Allocate system memory window */
+    for (w = 0; w < MAX_WIN; w++)
+	if (!(s->state & SOCKET_WIN_REQ(w))) break;
+    if (w == MAX_WIN)
+	return CS_OUT_OF_RESOURCE;
+
+    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 (!(s->cap.features & SS_CAP_STATIC_MAP) &&
+	find_mem_region(&win->base, win->size, align,
+			(req->Attributes & WIN_MAP_BELOW_1MB) ||
+			!(s->cap.features & SS_CAP_PAGE_REGS),
+			(*handle)->dev_info))
+	return CS_IN_USE;
+    (*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_16)
+	win->ctl.flags |= MAP_16BIT;
+    if (req->Attributes & WIN_USE_WAIT)
+	win->ctl.flags |= MAP_USE_WAIT;
+    win->ctl.sys_start = win->base;
+    win->ctl.sys_stop = win->base + win->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 */
+    req->Base = win->ctl.sys_start;
+    *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 > 2) {
+	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
+    
+======================================================================*/
+
+#ifdef __LINUX__
+
+#include <linux/pci.h>
+
+#if (LINUX_VERSION_CODE <= VERSION(2,1,17))
+
+#undef CONFIG_MODVERSIONS
+static struct symbol_table cs_symtab = {
+#include <linux/symtab_begin.h>
+#undef X
+#define X(sym) { (void *)&sym, SYMBOL_NAME_STR(sym) }
+    X(register_ss_entry),
+    X(unregister_ss_entry),
+    X(CardServices),
+    X(MTDHelperEntry),
+#ifdef HAS_PROC_BUS
+    X(proc_pccard),
+#endif
+#ifndef HAVE_MEMRESERVE
+    X(request_mem_region),
+    X(release_mem_region),
+#endif
+#ifdef CONFIG_PNP_BIOS
+    X(check_pnp_irq),
+#endif
+#ifdef CONFIG_PCI
+    X(pci_irq_mask),
+    X(pci_devices),
+    X(pci_root),
+    X(pci_find_slot),
+    X(pci_find_class),
+    X(pci_enable_device),
+    X(pci_set_power_state),
+#endif
+#include <linux/symtab_end.h>
+};
+
+#else
+
+EXPORT_SYMBOL(register_ss_entry);
+EXPORT_SYMBOL(unregister_ss_entry);
+EXPORT_SYMBOL(CardServices);
+EXPORT_SYMBOL(MTDHelperEntry);
+#ifdef HAS_PROC_BUS
+EXPORT_SYMBOL(proc_pccard);
+#endif
+#ifndef HAVE_MEMRESERVE
+EXPORT_SYMBOL(request_mem_region);
+EXPORT_SYMBOL(release_mem_region);
+#endif
+#ifdef CONFIG_PNP_BIOS
+EXPORT_SYMBOL(check_pnp_irq);
+#endif
+#ifdef CONFIG_PCI
+EXPORT_SYMBOL(pci_irq_mask);
+#if (LINUX_VERSION_CODE < VERSION(2,3,24))
+EXPORT_SYMBOL(pci_enable_device);
+EXPORT_SYMBOL(pci_set_power_state);
+#endif
+#endif
+
+#endif
+
+static int __init init_pcmcia_cs(void)
+{
+    printk(KERN_INFO "%s\n", release);
+#ifdef UTS_RELEASE
+    printk(KERN_INFO "  %s\n", kernel);
+#endif
+    printk(KERN_INFO "  %s\n", options);
+    DEBUG(0, "%s\n", version);
+#ifdef CONFIG_PM
+    if (do_apm)
+	pm_register(PM_SYS_DEV, PM_SYS_PCMCIA, handle_pm_event);
+#endif
+#ifdef CONFIG_PCI
+    pci_fixup_init();
+#endif
+#ifdef CONFIG_PNP_BIOS
+    if (do_pnp) {
+	pnp_bios_init();
+	pnp_proc_init();
+	pnp_rsrc_init();
+    }
+#endif
+    register_symtab(&cs_symtab);
+#ifdef HAS_PROC_BUS
+    proc_pccard = proc_mkdir("pccard", proc_bus);
+#ifdef CONFIG_PNP_BIOS
+    if (proc_pccard) {
+	create_proc_read_entry("ioport", 0, proc_pccard,
+			       proc_read_io, NULL);
+	create_proc_read_entry("irq", 0, proc_pccard,
+			       proc_read_irq, NULL);
+    }
+#endif
+#ifndef HAVE_MEMRESERVE
+    if (proc_pccard)
+	create_proc_read_entry("memory", 0, proc_pccard,
+			       proc_read_mem, NULL);
+#endif
+#endif
+    return 0;
+}
+
+static void __exit exit_pcmcia_cs(void)
+{
+    printk(KERN_INFO "unloading PCMCIA Card Services\n");
+#ifdef HAS_PROC_BUS
+    if (proc_pccard) {
+#ifdef CONFIG_PNP_BIOS
+	remove_proc_entry("ioport", proc_pccard);
+	remove_proc_entry("irq", proc_pccard);
+#endif
+#ifndef HAVE_MEMRESERVE
+	remove_proc_entry("memory", proc_pccard);
+#endif
+	remove_proc_entry("pccard", proc_bus);
+    }
+#endif
+#ifdef CONFIG_PM
+    if (do_apm)
+	pm_unregister_all(handle_pm_event);
+#endif
+#ifdef CONFIG_PCI
+    pci_fixup_done();
+#endif
+#ifdef CONFIG_PNP_BIOS
+    if (do_pnp) {
+	pnp_proc_done();
+	pnp_rsrc_done();
+    }
+#endif
+    release_resource_db();
+}
+
+module_init(init_pcmcia_cs);
+module_exit(exit_pcmcia_cs);
+
+#endif /* __LINUX__ */
+
+/*====================================================================*/
+
+#ifdef __BEOS__
+
+isa_module_info *isa = NULL;
+pci_module_info *pci = NULL;
+config_manager_for_bus_module_info *cm = NULL;
+module_info *i82365 = NULL;
+typedef struct module_info mod_t;
+
+static status_t std_ops(int32 op)
+{
+    switch (op) {
+    case B_MODULE_INIT:
+	printk(KERN_INFO "%s\n", release);
+	printk(KERN_INFO "  %s\n", options);
+	DEBUG(0, "%s\n", version);
+	init_timer();
+	if (get_module(B_ISA_MODULE_NAME, (mod_t **)&isa) != B_OK)
+	    return B_ERROR;
+	if (get_module(B_PCI_MODULE_NAME, (mod_t **)&pci) != B_OK)
+	    return B_ERROR;
+	if (get_module(B_CONFIG_MANAGER_FOR_BUS_MODULE_NAME,
+		       (mod_t **)&cm) != B_OK)
+	    return B_ERROR;
+	get_module(SS_MODULE_NAME("i82365"), &i82365);
+	break;
+    case B_MODULE_UNINIT:
+	printk(KERN_INFO "unloading PCMCIA Card Services\n");
+	if (i82365 != NULL) put_module(SS_MODULE_NAME("i82365"));
+	release_resource_db();
+	if (cm != NULL)
+	    put_module(B_CONFIG_MANAGER_FOR_BUS_MODULE_NAME);
+	if (pci != NULL) put_module(B_PCI_MODULE_NAME);
+	if (isa != NULL) put_module(B_ISA_MODULE_NAME);
+	stop_timer();
+	break;
+    }
+    return B_OK;
+}
+
+static status_t no_ops(int32 op)
+{
+    return B_OK;
+}
+
+static cs_client_module_info cs_client_info = {
+    { { CS_CLIENT_MODULE_NAME, B_KEEP_LOADED, &std_ops }, NULL },
+    (int (*)(int, ...))&CardServices,
+    (int (*)(int, ...))&MTDHelperEntry,
+    &add_timer,
+    &del_timer
+};
+
+static cs_socket_module_info cs_socket_info = {
+    { { CS_SOCKET_MODULE_NAME, B_KEEP_LOADED, &no_ops }, NULL },
+    &register_ss_entry,
+    &unregister_ss_entry,
+    &add_timer,
+    &del_timer,
+    &register_resource,
+    &release_resource,
+    &check_resource
+};
+
+_EXPORT module_info *modules[] = {
+    (module_info *)&cs_client_info,
+    (module_info *)&cs_socket_info,
+    NULL
+};
+
+#endif /* __BEOS__ */
Index: oldkernel/linux/pcmcia-cs-3.1.15/modules/cs_internal.h
diff -u /dev/null linux/pcmcia-cs-3.1.15/modules/cs_internal.h:1.1
--- /dev/null	Mon Jul 31 21:15:11 2000
+++ linux/pcmcia-cs-3.1.15/modules/cs_internal.h	Fri Jul  7 16:34:58 2000
@@ -0,0 +1,309 @@
+/*
+ * cs_internal.h 1.51 2000/02/08 00:31:51
+ *
+ * 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@pcmcia.sourceforge.org>.  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
+
+#ifdef __BEOS__
+#include "wchan.h"
+#endif
+
+#ifdef __LINUX__
+#include <linux/config.h>
+#endif
+
+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;
+#ifdef __LINUX__
+    wait_queue_head_t	mtd_req;
+#endif
+#ifdef __BEOS__
+    struct wchan	mtd_req;
+#endif
+    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 {
+#ifdef USE_SPIN_LOCKS
+    spinlock_t			lock;
+#endif
+    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			setup_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 HAS_PROC_BUS
+    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, ioaddr_t align,
+		   char *name);
+int find_mem_region(u_long *base, u_long num, u_long align,
+		    int force_low, char *name);
+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);
+int check_pnp_irq(int n);
+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);
+
+/* in pci_fixup */
+void pci_fixup_init(void);
+void pci_fixup_done(void);
+
+#define MAX_SOCK 8
+extern socket_t sockets;
+extern socket_info_t *socket_table[MAX_SOCK];
+
+#ifdef HAS_PROC_BUS
+extern struct proc_dir_entry *proc_pccard;
+#endif
+
+#ifdef __BEOS__
+#include <config_manager_p.h>
+extern isa_module_info *isa;
+extern pci_module_info *pci;
+extern config_manager_for_bus_module_info *cm;
+#define RSRC_MGR
+#endif
+
+#ifdef PCMCIA_DEBUG
+extern int pc_debug;
+#define DEBUG(n, args...) do { if (pc_debug>(n)) printk(KERN_DEBUG args); } while (0)
+#else
+#define DEBUG(n, args...) do { } while (0)
+#endif
+
+#endif /* _LINUX_CS_INTERNAL_H */
Index: oldkernel/linux/pcmcia-cs-3.1.15/modules/ds.c
diff -u /dev/null linux/pcmcia-cs-3.1.15/modules/ds.c:1.1
--- /dev/null	Mon Jul 31 21:15:11 2000
+++ linux/pcmcia-cs-3.1.15/modules/ds.c	Fri Jul  7 16:34:58 2000
@@ -0,0 +1,990 @@
+/*======================================================================
+
+    PC Card Driver Services
+    
+    ds.c 1.105 2000/05/03 20:04:52
+    
+    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@pcmcia.sourceforge.org>.  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 <pcmcia/config.h>
+#include <pcmcia/k_compat.h>
+
+#include <linux/module.h>
+#include <linux/init.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/proc_fs.h>
+#if (LINUX_VERSION_CODE >= VERSION(2,1,23))
+#include <linux/poll.h>
+#endif
+
+#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.105 2000/05/03 20:04:52 (David Hinds)";
+#else
+#define DEBUG(n, args...)
+#endif
+
+MODULE_AUTHOR("David Hinds <dhinds@pcmcia.sourceforge.org>");
+MODULE_DESCRIPTION("PCMCIA Driver Services " CS_RELEASE);
+
+/*====================================================================*/
+
+typedef struct driver_info_t {
+    dev_info_t		dev_info;
+    int			use_count, status;
+    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;
+
+extern struct proc_dir_entry *proc_pccard;
+
+/* We use this to distinguish in-kernel from modular drivers */
+static int init_status = 1;
+
+/*====================================================================*/
+
+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);
+	if (!driver) return -ENOMEM;
+	strncpy(driver->dev_info, (char *)dev_info, DEV_NAME_LEN);
+	driver->use_count = 0;
+	driver->status = init_status;
+	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 -ENODEV;
+    
+    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 */
+
+/*====================================================================*/
+
+#ifdef HAS_PROC_BUS
+static int proc_read_drivers(char *buf, char **start, off_t pos,
+			     int count, int *eof, void *data)
+{
+    driver_info_t *d;
+    char *p = buf;
+    for (d = root_driver; d; d = d->next)
+	p += sprintf(p, "%-24.24s %d %d\n", d->dev_info,
+		     d->status, d->use_count);
+    return (p - buf);
+}
+#endif
+
+/*======================================================================
+
+    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);
+	if (!driver) return -ENOMEM;
+	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(c->driver);
+	}
+    }
+    *b = c->next;
+    kfree(c);
+    
+    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;
+    }
+    
+    user = kmalloc(sizeof(user_info_t), GFP_KERNEL);
+    if (!user) return -ENOMEM;
+    MOD_INC_USE_COUNT;
+    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 FS_RELEASE_T 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 (FS_RELEASE_T)0;
+    s = &socket_table[i];
+    user = file->private_data;
+    if (CHECK_USER(user))
+	return (FS_RELEASE_T)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 (FS_RELEASE_T)0;
+    *link = user->next;
+    user->user_magic = 0;
+    kfree(user);
+    
+    MOD_DEC_USE_COUNT;
+    return (FS_RELEASE_T)0;
+} /* ds_release */
+
+/*====================================================================*/
+
+static ssize_t ds_read FOPS(struct inode *inode,
+			    struct file *file, char *buf,
+			    size_t count, loff_t *ppos)
+{
+    socket_t i = MINOR(F_INODE(file)->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 FOPS(struct inode *inode,
+			     struct file *file, const char *buf,
+			     size_t count, loff_t *ppos)
+{
+    socket_t i = MINOR(F_INODE(file)->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 */
+
+/*====================================================================*/
+
+#if (LINUX_VERSION_CODE < VERSION(2,1,23))
+
+static int ds_select(struct inode *inode, struct file *file,
+		     int sel_type, select_table *wait)
+{
+    socket_t i = MINOR(inode->i_rdev);
+    socket_info_t *s;
+    user_info_t *user;
+
+    DEBUG(2, "ds_select(socket %d)\n", i);
+    
+    if ((i >= sockets) || (sockets == 0))
+	return -ENODEV;
+    s = &socket_table[i];
+    user = file->private_data;
+    if (CHECK_USER(user))
+	return -EIO;
+    if (sel_type != SEL_IN)
+	return 0;
+    if (!queue_empty(user))
+	return 1;
+    select_wait(&s->queue, wait);
+    return 0;
+} /* ds_select */
+
+#else
+
+static u_int ds_poll(struct file *file, poll_table *wait)
+{
+    socket_t i = MINOR(F_INODE(file)->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 */
+
+#endif
+
+/*====================================================================*/
+
+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) && !capable(CAP_SYS_ADMIN))
+	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) && !capable(CAP_SYS_ADMIN))
+	    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 (!capable(CAP_SYS_ADMIN)) 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 (!capable(CAP_SYS_ADMIN)) 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 = {
+    open:	ds_open,
+    release:	ds_release,
+    ioctl:	ds_ioctl,
+    read:	ds_read,
+    write:	ds_write,
+#if (LINUX_VERSION_CODE < VERSION(2,1,23))
+    select:	ds_select
+#else
+    poll:	ds_poll
+#endif
+};
+
+#if (LINUX_VERSION_CODE <= VERSION(2,1,17))
+
+#undef CONFIG_MODVERSIONS
+static struct symbol_table ds_symtab = {
+#include <linux/symtab_begin.h>
+#undef X
+#define X(sym) { (void *)&sym, SYMBOL_NAME_STR(sym) }
+    X(register_pccard_driver),
+    X(unregister_pccard_driver),
+#include <linux/symtab_end.h>
+};
+
+#else
+
+EXPORT_SYMBOL(register_pccard_driver);
+EXPORT_SYMBOL(unregister_pccard_driver);
+
+#endif
+
+/*====================================================================*/
+
+int __init init_pcmcia_ds(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);
+    if (!socket_table) return -1;
+    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;
+	init_timer(&s->removal);
+	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;
+    register_symtab(&ds_symtab);
+
+#ifdef HAS_PROC_BUS
+    if (proc_pccard)
+	create_proc_read_entry("drivers", 0, proc_pccard,
+			       proc_read_drivers, NULL);
+    init_status = 0;
+#endif
+    return 0;
+}
+
+#ifdef MODULE
+
+int __init init_module(void)
+{
+    return init_pcmcia_ds();
+}
+
+void __exit cleanup_module(void)
+{
+    int i;
+#ifdef HAS_PROC_BUS
+    if (proc_pccard)
+	remove_proc_entry("drivers", proc_pccard);
+#endif
+    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
Index: oldkernel/linux/pcmcia-cs-3.1.15/modules/i82365.c
diff -u /dev/null linux/pcmcia-cs-3.1.15/modules/i82365.c:1.1
--- /dev/null	Mon Jul 31 21:15:11 2000
+++ linux/pcmcia-cs-3.1.15/modules/i82365.c	Fri Jul  7 16:34:58 2000
@@ -0,0 +1,2748 @@
+/*======================================================================
+
+    Device driver for Intel 82365 and compatible PC Card controllers,
+    and Yenta-compatible PCI-to-CardBus controllers.
+
+    i82365.c 1.312 2000/05/10 19:30:15
+
+    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@pcmcia.sourceforge.org>.  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 <pcmcia/config.h>
+#include <pcmcia/k_compat.h>
+
+#ifdef __LINUX__
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/config.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>
+#endif
+
+#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...) if (pc_debug>(n)) printk(KERN_DEBUG args)
+static const char *version =
+"i82365.c 1.312 2000/05/10 19:30:15 (David Hinds)";
+#else
+#define DEBUG(n, args...) do { } while (0)
+#endif
+
+#ifdef __BEOS__
+typedef int32 irq_ret_t;
+#define _request_irq(i, h, f, n) \
+    install_io_interrupt_handler(i, h, irq_list+i, 0)
+#define _free_irq(i, h) remove_io_interrupt_handler(i, h, irq_list+i)
+#define _check_irq(i, f) check_irq(i)
+static cs_socket_module_info *cs;
+static isa_module_info *isa;
+static pci_module_info *pci;
+#define RSRC_MGR cs->
+#define register_ss_entry	cs->_register_ss_entry
+#define unregister_ss_entry	cs->_unregister_ss_entry
+#define add_timer		cs->_add_timer
+#define del_timer		cs->_del_timer
+#else
+typedef void irq_ret_t;
+#define _request_irq(i, h, f, n) request_irq(i, h, f, n, socket)
+#define _free_irq(i, h) free_irq(i, socket)
+#endif
+
+MODULE_AUTHOR("David Hinds <dhinds@pcmcia.sourceforge.org>");
+MODULE_DESCRIPTION("Intel ExCA/Yenta PCMCIA socket driver");
+
+/*====================================================================*/
+
+/* Parameters that can be set with 'insmod' */
+
+#define INT_MODULE_PARM(n, v) static int n = v; MODULE_PARM(n, "i")
+
+/* General options */
+INT_MODULE_PARM(poll_interval, 0);	/* in ticks, 0 means never */
+INT_MODULE_PARM(cycle_time, 120);	/* in ns, 120 ns = 8.33 MHz */
+
+/* Cirrus options */
+INT_MODULE_PARM(has_dma, -1);
+INT_MODULE_PARM(has_led, -1);
+INT_MODULE_PARM(has_ring, -1);
+INT_MODULE_PARM(dynamic_mode, 0);
+INT_MODULE_PARM(freq_bypass, -1);
+INT_MODULE_PARM(setup_time, -1);
+INT_MODULE_PARM(cmd_time, -1);
+INT_MODULE_PARM(recov_time, -1);
+
+#ifdef CONFIG_ISA
+INT_MODULE_PARM(i365_base, 0x3e0);	/* IO address for probes */
+INT_MODULE_PARM(extra_sockets, 0);	/* Probe at i365_base+2? */
+INT_MODULE_PARM(ignore, -1);		/* Ignore this socket # */
+INT_MODULE_PARM(do_scan, 1);		/* Probe free interrupts? */
+INT_MODULE_PARM(cs_irq, 0);		/* card status irq */
+INT_MODULE_PARM(irq_mask, 0xffff);	/* bit map of irq's to use */
+static int irq_list[16] = { -1 };
+MODULE_PARM(irq_list, "1-16i");
+/* Vadem options */
+INT_MODULE_PARM(async_clock, -1);
+INT_MODULE_PARM(cable_mode, -1);
+INT_MODULE_PARM(wakeup, 0);
+#endif
+
+#ifdef CONFIG_PCI
+static int pci_irq_list[8] = { 0 };	/* PCI interrupt assignments */
+MODULE_PARM(pci_irq_list, "1-8i");
+INT_MODULE_PARM(do_pci_probe, 1);	/* Scan for PCI bridges? */
+INT_MODULE_PARM(fast_pci, -1);
+INT_MODULE_PARM(cb_write_post, -1);
+INT_MODULE_PARM(irq_mode, -1);		/* Override BIOS routing? */
+INT_MODULE_PARM(hold_time, -1);		/* Ricoh specific */
+INT_MODULE_PARM(p2cclk, -1);		/* TI specific */
+#endif
+
+#if defined(CONFIG_ISA) && defined(CONFIG_PCI)
+INT_MODULE_PARM(pci_csc, 1);		/* PCI card status irqs? */
+INT_MODULE_PARM(pci_int, 1);		/* PCI IO card irqs? */
+#elif defined(CONFIG_ISA) && !defined(CONFIG_PCI)
+#define pci_csc		0
+#define pci_int		0
+#elif !defined(CONFIG_ISA) && defined(CONFIG_PCI)
+#define pci_csc		0
+#define pci_int		1		/* We must use PCI irq's */
+#else
+#error "No bus architectures defined!"
+#endif
+
+/*====================================================================*/
+
+typedef struct socket_info_t {
+    u_short		type, flags;
+    socket_cap_t	cap;
+    ioaddr_t		ioaddr;
+    u_short		psock;
+    u_char		cs_irq, intr;
+    void		(*handler)(void *info, u_int events);
+    void		*info;
+#ifdef HAS_PROC_BUS
+    struct proc_dir_entry *proc;
+#endif
+    u_char		pci_irq_code;
+#ifdef CONFIG_PCI
+    u_short		vendor, device;
+    u_char		revision, bus, devfn;
+    u_short		bcr;
+    u_char		pci_lat, cb_lat, sub_bus, cache;
+    u_int		cb_phys;
+    char		*cb_virt;
+#endif
+    union {
+	cirrus_state_t		cirrus;
+	vg46x_state_t		vg46x;
+	o2micro_state_t		o2micro;
+	ti113x_state_t		ti113x;
+	ricoh_state_t		ricoh;
+	topic_state_t		topic;
+    } state;
+} socket_info_t;
+
+/* Where we keep track of our sockets... */
+static int sockets = 0;
+static socket_info_t socket[8] = {
+    { 0, }, /* ... */
+};
+
+#ifdef CONFIG_ISA
+static int grab_irq;
+#ifdef USE_SPIN_LOCKS
+static spinlock_t isa_lock = SPIN_LOCK_UNLOCKED;
+#endif
+#define ISA_LOCK(s, f) \
+    if (!((s)->flags & IS_CARDBUS)) spin_lock_irqsave(&isa_lock, f)
+#define ISA_UNLOCK(n, f) \
+    if (!((s)->flags & IS_CARDBUS)) spin_unlock_irqrestore(&isa_lock, f)
+#else
+#define ISA_LOCK(n, f) do { } while (0)
+#define ISA_UNLOCK(n, f) do { } while (0)
+#endif
+
+static void pcic_interrupt_wrapper(u_long data);
+static struct timer_list poll_timer = {
+    function: pcic_interrupt_wrapper
+};
+
+#define flip(v,b,f) (v = ((f)<0) ? v : ((f) ? ((v)|(b)) : ((v)&(~b))))
+
+/*====================================================================*/
+
+/* Some PCI shortcuts */
+
+#ifdef CONFIG_PCI
+static int pci_readb(socket_info_t *s, int r, u_char *v)
+{ return pcibios_read_config_byte(s->bus, s->devfn, r, v); }
+static int pci_writeb(socket_info_t *s, int r, u_char v)
+{ return pcibios_write_config_byte(s->bus, s->devfn, r, v); }
+static int pci_readw(socket_info_t *s, int r, u_short *v)
+{ return pcibios_read_config_word(s->bus, s->devfn, r, v); }
+static int pci_writew(socket_info_t *s, int r, u_short v)
+{ return pcibios_write_config_word(s->bus, s->devfn, r, v); }
+static int pci_readl(socket_info_t *s, int r, u_int *v)
+{ return pcibios_read_config_dword(s->bus, s->devfn, r, v); }
+static int pci_writel(socket_info_t *s, int r, u_int v)
+{ return pcibios_write_config_dword(s->bus, s->devfn, r, v); }
+#endif
+
+#define cb_readb(s, r)		readb((s)->cb_virt + (r))
+#define cb_readl(s, r)		readl((s)->cb_virt + (r))
+#define cb_writeb(s, r, v)	writeb(v, (s)->cb_virt + (r))
+#define cb_writel(s, r, v)	writel(v, (s)->cb_virt + (r))
+
+/*====================================================================*/
+
+/* 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_I82092AA, IS_OM82C092G,
+    IS_PD6729, IS_PD6730, IS_PD6832,
+    IS_OZ6729, IS_OZ6730, IS_OZ6832, IS_OZ6836, IS_OZ6812,
+    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_TI1031, IS_TI1410,
+    IS_TOPIC95_A, IS_TOPIC95_B, IS_TOPIC97, IS_TOPIC100,
+    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;
+
+#define ID(a,b) PCI_VENDOR_ID_##a,PCI_DEVICE_ID_##a##_##b
+
+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
+    { "Intel 82092AA", IS_PCI, ID(INTEL, 82092AA_0) },
+    { "Omega Micro 82C092G", IS_PCI, ID(OMEGA, 82C092G) },
+    { "Cirrus PD6729", IS_CIRRUS|IS_PCI, ID(CIRRUS, 6729) },
+    { "Cirrus PD6730", IS_CIRRUS|IS_PCI, PCI_VENDOR_ID_CIRRUS, 0xffff },
+    { "Cirrus PD6832", IS_CIRRUS|IS_CARDBUS, ID(CIRRUS, 6832) },
+    { "O2Micro OZ6729", IS_O2MICRO|IS_PCI|IS_VG_PWR, ID(O2, 6729) },
+    { "O2Micro OZ6730", IS_O2MICRO|IS_PCI|IS_VG_PWR, ID(O2, 6730) },
+    { "O2Micro OZ6832/33", IS_O2MICRO|IS_CARDBUS, ID(O2, 6832) },
+    { "O2Micro OZ6836/60", IS_O2MICRO|IS_CARDBUS, ID(O2, 6836) },
+    { "O2Micro OZ6812", IS_O2MICRO|IS_CARDBUS, ID(O2, 6812) },
+    { "Ricoh RL5C465", IS_RICOH|IS_CARDBUS, ID(RICOH, RL5C465) },
+    { "Ricoh RL5C466", IS_RICOH|IS_CARDBUS, ID(RICOH, RL5C466) },
+    { "Ricoh RL5C475", IS_RICOH|IS_CARDBUS, ID(RICOH, RL5C475) },
+    { "Ricoh RL5C476", IS_RICOH|IS_CARDBUS, ID(RICOH, RL5C476) },
+    { "Ricoh RL5C478", IS_RICOH|IS_CARDBUS, ID(RICOH, RL5C478) },
+    { "SMC 34C90", IS_CARDBUS, ID(SMC, 34C90) },
+    { "TI 1130", IS_TI|IS_CARDBUS, ID(TI, 1130) },
+    { "TI 1131", IS_TI|IS_CARDBUS, ID(TI, 1131) },
+    { "TI 1250A", IS_TI|IS_CARDBUS, ID(TI, 1250A) },
+    { "TI 1220", IS_TI|IS_CARDBUS, ID(TI, 1220) },
+    { "TI 1221", IS_TI|IS_CARDBUS, ID(TI, 1221) },
+    { "TI 1210", IS_TI|IS_CARDBUS, ID(TI, 1210) },
+    { "TI 1251A", IS_TI|IS_CARDBUS, ID(TI, 1251A) },
+    { "TI 1251B", IS_TI|IS_CARDBUS, ID(TI, 1251B) },
+    { "TI 1450", IS_TI|IS_CARDBUS, ID(TI, 1450) },
+    { "TI 1225", IS_TI|IS_CARDBUS, ID(TI, 1225) },
+    { "TI 1211", IS_TI|IS_CARDBUS, ID(TI, 1211) },
+    { "TI 1420", IS_TI|IS_CARDBUS, ID(TI, 1420) },
+    { "TI 1031", IS_TI|IS_CARDBUS, ID(TI, 1031) },
+    { "TI 1410", IS_TI|IS_CARDBUS, ID(TI, 1410) },
+    { "Toshiba ToPIC95-A", IS_CARDBUS|IS_TOPIC, ID(TOSHIBA, TOPIC95_A) },
+    { "Toshiba ToPIC95-B", IS_CARDBUS|IS_TOPIC, ID(TOSHIBA, TOPIC95_B) },
+    { "Toshiba ToPIC97", IS_CARDBUS|IS_TOPIC, ID(TOSHIBA, TOPIC97) },
+    { "Toshiba ToPIC100", IS_CARDBUS|IS_TOPIC, ID(TOSHIBA, TOPIC100) },
+    { "Unknown", IS_PCI|IS_UNKNOWN, 0, 0 },
+    { "Unknown", IS_CARDBUS|IS_UNKNOWN, 0, 0 }
+#endif
+};
+
+#define PCIC_COUNT	(sizeof(pcic)/sizeof(pcic_t))
+
+/*====================================================================*/
+
+static u_char i365_get(socket_info_t *s, u_short reg)
+{
+#ifdef CONFIG_PCI
+    if (s->cb_virt)
+	return cb_readb(s, 0x0800 + reg);
+#endif
+    outb(I365_REG(s->psock, reg), s->ioaddr);
+    return inb(s->ioaddr+1);
+}
+
+static void i365_set(socket_info_t *s, u_short reg, u_char data)
+{
+#ifdef CONFIG_PCI
+    if (s->cb_virt) {
+	cb_writeb(s, 0x0800 + reg, data);
+	return;
+    }
+#endif
+    outb(I365_REG(s->psock, reg), s->ioaddr);
+    outb(data, s->ioaddr+1);
+}
+
+static void i365_bset(socket_info_t *s, u_short reg, u_char mask)
+{
+    u_char d = i365_get(s, reg);
+    i365_set(s, reg, d | mask);
+}
+
+static void i365_bclr(socket_info_t *s, u_short reg, u_char mask)
+{
+    u_char d = i365_get(s, reg);
+    i365_set(s, reg, d & ~mask);
+}
+
+static void i365_bflip(socket_info_t *s, u_short reg, u_char mask, int b)
+{
+    u_char d = i365_get(s, reg);
+    i365_set(s, reg, (b) ? (d | mask) : (d & ~mask));
+}
+
+static u_short i365_get_pair(socket_info_t *s, u_short reg)
+{
+    u_short a = i365_get(s, reg), b = i365_get(s, reg+1);
+    return (a + (b<<8));
+}
+
+static void i365_set_pair(socket_info_t *s, u_short reg, u_short data)
+{
+    i365_set(s, reg, data & 0xff);
+    i365_set(s, 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.
+    
+======================================================================*/
+
+#ifdef CONFIG_PCI
+
+static int __init get_pci_irq(socket_info_t *s)
+{
+    u8 irq;
+#ifdef __BEOS__
+    pci_readb(s, PCI_INTERRUPT_LINE, &irq);
+#else
+    irq = pci_find_slot(s->bus, s->devfn)->irq;
+#endif
+    if ((irq == 0) && (pci_csc || pci_int))
+	irq = pci_irq_list[s - socket];
+    if (irq >= NR_IRQS) irq = 0;
+    s->cap.pci_irq = irq;
+    return irq;
+}
+
+#endif
+
+static void __init cirrus_get_state(socket_info_t *s)
+{
+    cirrus_state_t *p = &s->state.cirrus;
+    int i;
+
+    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);
+    if (s->flags & IS_PCI)
+	p->ectl1 = pd67_ext_get(s, PD67_EXT_CTL_1);
+    for (i = 0; i < 6; i++)
+	p->timer[i] = i365_get(s, PD67_TIME_SETUP(0)+i);
+}
+
+static void cirrus_set_state(socket_info_t *s)
+{
+    cirrus_state_t *p = &s->state.cirrus;
+    u_char misc;
+    int i;
+
+    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);
+    if (s->flags & IS_PCI)
+	pd67_ext_set(s, PD67_EXT_CTL_1, p->ectl1);
+    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(socket_info_t *s, int pcsc, int pint)
+{
+    flip(s->bcr, PD6832_BCR_MGMT_IRQ_ENA, !pcsc);
+    return 0;
+}
+#endif
+
+static u_int __init cirrus_set_opts(socket_info_t *s, char *buf)
+{
+    cirrus_state_t *p = &s->state.cirrus;
+    u_int mask = 0xffff;
+
+    p->misc1 |= PD67_MC1_SPKR_ENA;
+    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 (!(s->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;
+	p->misc1 &= ~(PD67_MC1_PULSE_MGMT | PD67_MC1_PULSE_IRQ);
+	p->ectl1 &= ~(PD67_EC1_INV_MGMT_IRQ | PD67_EC1_INV_CARD_IRQ);
+	flip(p->misc2, PD67_MC2_FAST_PCI, fast_pci);
+	if (p->misc2 & PD67_MC2_IRQ15_RI)
+	    mask &= (s->type == IS_PD6730) ? ~0x0400 : ~0x8000;
+	if ((s->flags & IS_PCI) && (irq_mode == 1) && get_pci_irq(s)) {
+	    /* Configure PD6729 bridge for PCI interrupts */
+	    p->ectl1 |= PD67_EC1_INV_MGMT_IRQ | PD67_EC1_INV_CARD_IRQ;
+	    s->pci_irq_code = 3; /* PCI INTA = "irq 3" */
+	    buf += strlen(buf);
+	    sprintf(buf, " [pci irq %d]", s->cap.pci_irq);
+	    mask = 0;
+	}
+#endif
+    }
+    if (!(s->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 __init vg46x_get_state(socket_info_t *s)
+{
+    vg46x_state_t *p = &s->state.vg46x;
+    p->ctl = i365_get(s, VG468_CTL);
+    if (s->type == IS_VG469)
+	p->ema = i365_get(s, VG469_EXT_MODE);
+}
+
+static void vg46x_set_state(socket_info_t *s)
+{
+    vg46x_state_t *p = &s->state.vg46x;
+    i365_set(s, VG468_CTL, p->ctl);
+    if (s->type == IS_VG469)
+	i365_set(s, VG469_EXT_MODE, p->ema);
+}
+
+static u_int __init vg46x_set_opts(socket_info_t *s, char *buf)
+{
+    vg46x_state_t *p = &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 (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 __init ti113x_get_state(socket_info_t *s)
+{
+    ti113x_state_t *p = &s->state.ti113x;
+    pci_readl(s, TI113X_SYSTEM_CONTROL, &p->sysctl);
+    pci_readb(s, TI113X_CARD_CONTROL, &p->cardctl);
+    pci_readb(s, TI113X_DEVICE_CONTROL, &p->devctl);
+    pci_readb(s, TI1250_DIAGNOSTIC, &p->diag);
+}
+
+static void ti113x_set_state(socket_info_t *s)
+{
+    ti113x_state_t *p = &s->state.ti113x;
+    pci_writel(s, TI113X_SYSTEM_CONTROL, p->sysctl);
+    pci_writeb(s, TI113X_CARD_CONTROL, p->cardctl);
+    pci_writeb(s, TI113X_DEVICE_CONTROL, p->devctl);
+    pci_writeb(s, TI1250_MULTIMEDIA_CTL, 0);
+    pci_writeb(s, 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(socket_info_t *s, int pcsc, int pint)
+{
+    ti113x_state_t *p = &s->state.ti113x;
+    s->intr = (pcsc) ? I365_INTR_ENA : 0;
+    if (s->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 (s->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 __init ti113x_set_opts(socket_info_t *s, char *buf)
+{
+    ti113x_state_t *p = &s->state.ti113x;
+    u_int mask = 0xffff;
+    int old = (s->type <= IS_TI1131);
+    
+    flip(p->cardctl, TI113X_CCR_RIENB, has_ring);
+    p->cardctl &= ~TI113X_CCR_ZVENABLE;
+    p->cardctl |= TI113X_CCR_SPKROUTEN;
+    if (!old) flip(p->sysctl, TI122X_SCR_P2CCLK, p2cclk);
+    switch (irq_mode) {
+    case 0:
+	p->devctl &= ~TI113X_DCR_IMODE_MASK;
+	break;
+    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:
+	/* Feeble fallback: if PCI-only but no PCI irq, try ISA */
+	if (((p->devctl & TI113X_DCR_IMODE_MASK) == 0) &&
+	    (s->cap.pci_irq == 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;
+	}
+    }
+    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.
+
+    The interrupt test doesn't seem to be reliable with Ricoh
+    bridges.  It seems to depend on what type of card is in the
+    socket, and on the history of that socket, in some way that
+    doesn't show up in the current socket state.
+
+======================================================================*/
+
+#ifdef CONFIG_PCI
+
+static void __init ricoh_get_state(socket_info_t *s)
+{
+    ricoh_state_t *p = &s->state.ricoh;
+    pci_readw(s, RL5C4XX_MISC, &p->misc);
+    pci_readw(s, RL5C4XX_16BIT_CTL, &p->ctl);
+    pci_readw(s, RL5C4XX_16BIT_IO_0, &p->io);
+    pci_readw(s, RL5C4XX_16BIT_MEM_0, &p->mem);
+}
+
+static void ricoh_set_state(socket_info_t *s)
+{
+    ricoh_state_t *p = &s->state.ricoh;
+    pci_writew(s, RL5C4XX_MISC, p->misc);
+    pci_writew(s, RL5C4XX_16BIT_CTL, p->ctl);
+    pci_writew(s, RL5C4XX_16BIT_IO_0, p->io);
+    pci_writew(s, RL5C4XX_16BIT_MEM_0, p->mem);
+}
+
+static u_int __init ricoh_set_opts(socket_info_t *s, char *buf)
+{
+    ricoh_state_t *p = &s->state.ricoh;
+    u_int mask = 0xffff;
+    int old = (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 __init o2micro_get_state(socket_info_t *s)
+{
+    o2micro_state_t *p = &s->state.o2micro;
+    if ((s->revision == 0x34) || (s->revision == 0x62) ||
+	(s->type == IS_OZ6812)) {
+	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 (s->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(socket_info_t *s)
+{
+    o2micro_state_t *p = &s->state.o2micro;
+    if ((s->revision == 0x34) || (s->revision == 0x62) ||
+	(s->type == IS_OZ6812)) {
+	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 (s->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 __init o2micro_set_opts(socket_info_t *s, char *buf)
+{
+    o2micro_state_t *p = &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 (s->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;
+	if (s->revision == 0x34)
+	    p->mode_c = 0x20;
+    } else {
+	if (p->mode_b & O2_MODE_B_IRQ15_RI) mask &= ~0x8000;
+    }
+    if (p->mode_b & O2_MODE_B_IRQ15_RI)
+	strcat(buf, " [ring]");
+    if (irq_mode != -1)
+	p->mode_d = irq_mode;
+    if (p->mode_d & O2_MODE_D_ISA_IRQ) {
+	strcat(buf, " [pci+isa]");
+    } else {
+	switch (p->mode_d & O2_MODE_D_IRQ_MODE) {
+	case O2_MODE_D_IRQ_PCPCI:
+	    strcat(buf, " [pc/pci]"); break;
+	case O2_MODE_D_IRQ_PCIWAY:
+	    strcat(buf, " [pci/way]"); break;
+	case O2_MODE_D_IRQ_PCI:
+	    strcat(buf, " [pci only]"); break;
+	}
+    }
+    if (s->flags & IS_CARDBUS) {
+	if (p->mode_d & O2_MODE_D_W97_IRQ)
+	    strcat(buf, " [win97]");
+    }
+    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 __init topic_get_state(socket_info_t *s)
+{
+    topic_state_t *p = &s->state.topic;
+    pci_readb(s, TOPIC_SLOT_CONTROL, &p->slot);
+    pci_readb(s, TOPIC_CARD_CONTROL, &p->ccr);
+    pci_readb(s, TOPIC_CARD_DETECT, &p->cdr);
+    pci_readl(s, TOPIC_REGISTER_CONTROL, &p->rcr);
+}
+
+static void topic_set_state(socket_info_t *s)
+{
+    topic_state_t *p = &s->state.topic;
+    pci_writeb(s, TOPIC_SLOT_CONTROL, p->slot);
+    pci_writeb(s, TOPIC_CARD_CONTROL, p->ccr);
+    pci_writeb(s, TOPIC_CARD_DETECT, p->cdr);
+    pci_writel(s, TOPIC_REGISTER_CONTROL, p->rcr);
+}
+
+static int topic_set_irq_mode(socket_info_t *s, int pcsc, int pint)
+{
+    if (s->type >= IS_TOPIC97) {
+	topic_state_t *p = &s->state.topic;
+	flip(p->ccr, TOPIC97_ICR_IRQSEL, pcsc);
+	return 0;
+    } else {
+	/* no ISA card status change irq */
+	return !pcsc;
+    }
+}
+
+static u_int __init topic_set_opts(socket_info_t *s, char *buf)
+{
+    topic_state_t *p = &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
+    
+======================================================================*/
+
+/* Default settings for PCI command configuration register */
+#define CMD_DFLT (PCI_COMMAND_IO|PCI_COMMAND_MEMORY| \
+		  PCI_COMMAND_MASTER|PCI_COMMAND_WAIT)
+
+#ifdef CONFIG_PCI
+
+static void __init cb_get_state(socket_info_t *s)
+{
+    pci_readb(s, PCI_CACHE_LINE_SIZE, &s->cache);
+    pci_readb(s, PCI_LATENCY_TIMER, &s->pci_lat);
+    pci_readb(s, CB_LATENCY_TIMER, &s->cb_lat);
+    pci_readb(s, CB_CARDBUS_BUS, &s->cap.cardbus);
+    pci_readb(s, CB_SUBORD_BUS, &s->sub_bus);
+    pci_readw(s, CB_BRIDGE_CONTROL, &s->bcr);
+    get_pci_irq(s);
+}
+
+static void cb_set_state(socket_info_t *s)
+{
+#ifdef __LINUX__
+    pci_set_power_state(pci_find_slot(s->bus, s->devfn), 0);
+#endif
+    pci_writel(s, CB_LEGACY_MODE_BASE, 0);
+    pci_writel(s, PCI_BASE_ADDRESS_0, s->cb_phys);
+    pci_writew(s, PCI_COMMAND, CMD_DFLT);
+    pci_writeb(s, PCI_CACHE_LINE_SIZE, s->cache);
+    pci_writeb(s, PCI_LATENCY_TIMER, s->pci_lat);
+    pci_writeb(s, CB_LATENCY_TIMER, s->cb_lat);
+    pci_writeb(s, CB_CARDBUS_BUS, s->cap.cardbus);
+    pci_writeb(s, CB_SUBORD_BUS, s->sub_bus);
+    pci_writew(s, CB_BRIDGE_CONTROL, s->bcr);
+}
+
+static int cb_get_irq_mode(socket_info_t *s)
+{
+    return (!(s->bcr & CB_BCR_ISA_IRQ));
+}
+
+static int cb_set_irq_mode(socket_info_t *s, int pcsc, int pint)
+{
+    flip(s->bcr, CB_BCR_ISA_IRQ, !(pint));
+    if (s->flags & IS_CIRRUS)
+	return cirrus_set_irq_mode(s, pcsc, pint);
+    else if (s->flags & IS_TI)
+	return ti113x_set_irq_mode(s, pcsc, pint);
+    else if (s->flags & IS_TOPIC)
+	return topic_set_irq_mode(s, pcsc, pint);
+    /* By default, assume that we can't do ISA status irqs */
+    return (!pcsc);
+}
+
+static void __init cb_set_opts(socket_info_t *s, char *buf)
+{
+    s->bcr |= CB_BCR_WRITE_POST;
+    /* some TI1130's seem to exhibit problems with write posting */
+    if (((s->type == IS_TI1130) && (s->revision == 4) &&
+	 (cb_write_post < 0)) || (cb_write_post == 0))
+	s->bcr &= ~CB_BCR_WRITE_POST;
+    if (s->cache == 0) s->cache = 8;
+    if (s->pci_lat == 0) s->pci_lat = 0xa8;
+    if (s->cb_lat == 0) s->cb_lat = 0xb0;
+    if (s->cap.pci_irq == 0)
+	strcat(buf, " [no pci irq]");
+    else
+	sprintf(buf, " [pci irq %d]", s->cap.pci_irq);
+    buf += strlen(buf);
+    if (!(s->flags & IS_TOPIC))
+	s->cap.features |= SS_CAP_PAGE_REGS;
+    sprintf(buf, " [lat %d/%d] [bus %d/%d]",
+	    s->pci_lat, s->cb_lat, s->cap.cardbus, s->sub_bus);
+}
+
+#endif
+
+/*======================================================================
+
+    Power control for Cardbus controllers: used both for 16-bit and
+    Cardbus cards.
+    
+======================================================================*/
+
+#ifdef CONFIG_PCI
+
+static void cb_get_power(socket_info_t *s, socket_state_t *state)
+{
+    u_int reg = cb_readl(s, 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_VPP_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 int cb_set_power(socket_info_t *s, socket_state_t *state)
+{
+    u_int reg = 0;
+    /* restart card voltage detection if it seems appropriate */
+    if ((state->Vcc == 0) && (state->Vpp == 0) &&
+	!(cb_readl(s, CB_SOCKET_STATE) & CB_SS_VSENSE))
+	cb_writel(s, CB_SOCKET_FORCE, CB_SF_CVSTEST);
+    switch (state->Vcc) {
+    case 0:		reg = 0; break;
+    case 33:		reg = CB_SC_VCC_3V; break;
+    case 50:		reg = CB_SC_VCC_5V; break;
+    default:		return -EINVAL;
+    }
+    switch (state->Vpp) {
+    case 0:		break;
+    case 33:		reg |= CB_SC_VPP_3V; break;
+    case 50:		reg |= CB_SC_VPP_5V; break;
+    case 120:		reg |= CB_SC_VPP_12V; break;
+    default:		return -EINVAL;
+    }
+    if (reg != cb_readl(s, CB_SOCKET_CONTROL))
+	cb_writel(s, CB_SOCKET_CONTROL, reg);
+    return 0;
+}
+
+#endif
+
+/*======================================================================
+
+    Generic routines to get and set controller options
+    
+======================================================================*/
+
+static void __init get_bridge_state(socket_info_t *s)
+{
+    if (s->flags & IS_CIRRUS)
+	cirrus_get_state(s);
+#ifdef CONFIG_ISA
+    else if (s->flags & IS_VADEM)
+	vg46x_get_state(s);
+#endif
+#ifdef CONFIG_PCI
+    else if (s->flags & IS_O2MICRO)
+	o2micro_get_state(s);
+    else if (s->flags & IS_TI)
+	ti113x_get_state(s);
+    else if (s->flags & IS_RICOH)
+	ricoh_get_state(s);
+    else if (s->flags & IS_TOPIC)
+	topic_get_state(s);
+    if (s->flags & IS_CARDBUS)
+	cb_get_state(s);
+#endif
+}
+
+static void set_bridge_state(socket_info_t *s)
+{
+#ifdef CONFIG_PCI
+    if (s->flags & IS_CARDBUS)
+	cb_set_state(s);
+#endif
+    if (s->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, s->intr);
+#ifdef CONFIG_ISA
+    if (s->flags & IS_VADEM)
+	vg46x_set_state(s);
+#endif
+#ifdef CONFIG_PCI
+    if (s->flags & IS_O2MICRO)
+	o2micro_set_state(s);
+    else if (s->flags & IS_TI)
+	ti113x_set_state(s);
+    else if (s->flags & IS_RICOH)
+	ricoh_set_state(s);
+    else if (s->flags & IS_TOPIC)
+	topic_set_state(s);
+#endif
+}
+
+static u_int __init set_bridge_opts(socket_info_t *s, u_short ns)
+{
+    u_short i;
+    u_int m = 0xffff;
+    char buf[128];
+
+    for (i = 0; i < ns; i++) {
+	if (s[i].flags & IS_ALIVE) {
+	    printk(KERN_INFO "    host opts [%d]: already alive!\n", i);
+	    continue;
+	}
+	buf[0] = '\0';
+	get_bridge_state(s+i);
+	if (s[i].flags & IS_CIRRUS)
+	    m = cirrus_set_opts(s+i, buf);
+#ifdef CONFIG_ISA
+	else if (s[i].flags & IS_VADEM)
+	    m = vg46x_set_opts(s+i, buf);
+#endif
+#ifdef CONFIG_PCI
+	else if (s[i].flags & IS_O2MICRO)
+	    m = o2micro_set_opts(s+i, buf);
+	else if (s[i].flags & IS_TI)
+	    m = ti113x_set_opts(s+i, buf);
+	else if (s[i].flags & IS_RICOH)
+	    m = ricoh_set_opts(s+i, buf);
+	else if (s[i].flags & IS_TOPIC)
+	    m = topic_set_opts(s+i, buf);
+	if (s[i].flags & IS_CARDBUS)
+	    cb_set_opts(s+i, buf+strlen(buf));
+#endif
+	set_bridge_state(s+i);
+	printk(KERN_INFO "    host opts [%d]:%s\n", i,
+	       (*buf) ? buf : " none");
+    }
+#ifdef CONFIG_PCI
+    m &= ~pci_irq_mask;
+#endif
+    return m;
+}
+
+/*======================================================================
+
+    Interrupt testing code, for ISA and PCI interrupts
+    
+======================================================================*/
+
+static volatile u_int irq_hits, irq_shared;
+static volatile socket_info_t *irq_sock;
+
+static irq_ret_t irq_count IRQ(int irq, void *dev, struct pt_regs *regs)
+{
+    irq_hits++;
+#ifndef __BEOS__
+    DEBUG(2, "-> hit on irq %d\n", irq);
+#endif
+    if (!irq_shared && (irq_hits > 100)) {
+	printk(KERN_INFO "    PCI irq %d seems to be wedged!\n", irq);
+	disable_irq(irq);
+	return (irq_ret_t)0;
+    }
+#ifdef CONFIG_PCI
+    if (irq_sock->flags & IS_CARDBUS) {
+	cb_writel(irq_sock, CB_SOCKET_EVENT, -1);
+    } else
+#endif
+    i365_get((socket_info_t *)irq_sock, I365_CSC);
+    return (irq_ret_t)1;
+}
+
+#ifdef __LINUX__
+static int _check_irq(int irq, int flags)
+{
+#ifdef CONFIG_PNP_BIOS
+    extern int check_pnp_irq(int);
+    if ((flags != SA_SHIRQ) && check_pnp_irq(irq))
+	return -1;
+#endif
+    if (request_irq(irq, irq_count, flags, "x", irq_count) != 0)
+	return -1;
+    free_irq(irq, irq_count);
+    return 0;
+}
+#endif
+
+static u_int __init test_irq(socket_info_t *s, int irq, int pci)
+{
+    u_char csc = (pci) ? 0 : irq;
+
+#ifdef CONFIG_PNP_BIOS
+    extern int check_pnp_irq(int);
+    if (!pci && check_pnp_irq(irq)) return 1;
+#endif
+
+    DEBUG(2, "  testing %s irq %d\n", pci ? "PCI" : "ISA", irq);
+    irq_sock = s; irq_shared = irq_hits = 0;
+    if (_request_irq(irq, irq_count, 0, "scan")) {
+	irq_shared++;
+	if (!pci || _request_irq(irq, irq_count, SA_SHIRQ, "scan"))
+	    return 1;
+    }
+    irq_hits = 0;
+    __set_current_state(TASK_UNINTERRUPTIBLE);
+    schedule_timeout(HZ/100);
+    if (irq_hits && !irq_shared) {
+	_free_irq(irq, irq_count);
+	DEBUG(2, "    spurious hit!\n");
+	return 1;
+    }
+
+    /* Generate one interrupt */
+#ifdef CONFIG_PCI
+    if (s->flags & IS_CARDBUS) {
+	cb_writel(s, CB_SOCKET_EVENT, -1);
+	i365_set(s, I365_CSCINT, I365_CSC_STSCHG | (csc << 4));
+	cb_writel(s, CB_SOCKET_EVENT, -1);
+	cb_writel(s, CB_SOCKET_MASK, CB_SM_CSTSCHG);
+	cb_writel(s, CB_SOCKET_FORCE, CB_SE_CSTSCHG);
+	udelay(1000);
+	cb_writel(s, CB_SOCKET_EVENT, -1);
+	cb_writel(s, CB_SOCKET_MASK, 0);
+    } else
+#endif
+    {
+	i365_set(s, I365_CSCINT, I365_CSC_DETECT | (csc << 4));
+	i365_bset(s, I365_GENCTL, I365_CTL_SW_IRQ);
+	udelay(1000);
+    }
+
+    _free_irq(irq, irq_count);
+
+    /* mask all interrupts */
+    i365_set(s, I365_CSCINT, 0);
+    DEBUG(2, "    hits = %d\n", irq_hits);
+    
+    return pci ? (irq_hits == 0) : (irq_hits != 1);
+}
+
+#ifdef CONFIG_ISA
+static u_int __init isa_scan(socket_info_t *s, u_int mask0)
+{
+    u_int mask1 = 0;
+    int i;
+
+#ifdef CONFIG_PCI
+    /* Only scan if we can select ISA csc irq's */
+    if (!(s->flags & IS_CARDBUS) || (cb_set_irq_mode(s, 0, 0) == 0))
+#endif
+    if (do_scan) {
+	set_bridge_state(s);
+	i365_set(s, I365_CSCINT, 0);
+	for (i = 0; i < 16; i++)
+	    if ((mask0 & (1 << i)) && (test_irq(s, i, 0) == 0))
+		mask1 |= (1 << i);
+	for (i = 0; i < 16; i++)
+	    if ((mask1 & (1 << i)) && (test_irq(s, 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 int __init pci_scan(socket_info_t *s)
+{
+    int ret;
+    if ((s->flags & IS_RICOH) || !(s->flags & IS_CARDBUS)) {
+	/* for PCI-to-PCMCIA bridges, just check for wedged irq */
+	irq_sock = s; irq_hits = 0;
+	if (_request_irq(s->cap.pci_irq, irq_count, 0, "scan"))
+	    return 1;
+	udelay(50);
+	_free_irq(s->cap.pci_irq, irq_count);
+	return (!irq_hits);
+    }
+    cb_set_irq_mode(s, 1, 0);
+    set_bridge_state(s);
+    i365_set(s, I365_CSCINT, 0);
+    ret = ((test_irq(s, s->cap.pci_irq, 1) == 0) &&
+	   (test_irq(s, s->cap.pci_irq, 1) == 0));
+    if (!ret)
+	printk(KERN_INFO "    PCI irq %d test failed\n",
+	       s->cap.pci_irq);
+    return ret;
+}
+#endif /* CONFIG_PCI */
+
+/*====================================================================*/
+
+#ifdef CONFIG_ISA
+
+static int __init isa_identify(u_short port, u_short sock)
+{
+    socket_info_t *s = socket+sockets;
+    u_char val;
+    int type = -1;
+
+    /* Use the next free entry in the socket table */
+    s->ioaddr = port;
+    s->psock = sock;
+    
+    /* Wake up a sleepy Cirrus controller */
+    if (wakeup) {
+	i365_bclr(s, PD67_MISC_CTL_2, PD67_MC2_SUSPEND);
+	/* Pause at least 50 ms */
+	mdelay(50);
+    }
+    
+    if ((val = i365_get(s, 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(s, VG468_MISC, VG468_MISC_VADEMREV);
+    val = i365_get(s, I365_IDENT);
+    if (val & I365_IDENT_VADEM) {
+	i365_bclr(s, VG468_MISC, VG468_MISC_VADEMREV);
+	type = ((val & 7) >= 4) ? IS_VG469 : IS_VG468;
+    }
+
+    /* Check for Ricoh chips */
+    val = i365_get(s, RF5C_CHIP_ID);
+    if ((val == RF5C_CHIP_RF5C296) || (val == RF5C_CHIP_RF5C396))
+	type = IS_RF5Cx96;
+    
+    /* Check for Cirrus CL-PD67xx chips */
+    i365_set(s, PD67_CHIP_INFO, 0);
+    val = i365_get(s, PD67_CHIP_INFO);
+    if ((val & PD67_INFO_CHIP_ID) == PD67_INFO_CHIP_ID) {
+	val = i365_get(s, PD67_CHIP_INFO);
+	if ((val & PD67_INFO_CHIP_ID) == 0) {
+	    type = (val & PD67_INFO_SLOTS) ? IS_PD672X : IS_PD6710;
+	    i365_set(s, PD67_EXT_INDEX, 0xe5);
+	    if (i365_get(s, PD67_EXT_INDEX) != 0xe5)
+		type = IS_VT83C469;
+	}
+    }
+    return type;
+} /* isa_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 __init is_alive(socket_info_t *s)
+{
+    u_char stat;
+    u_short start, stop;
+    
+    stat = i365_get(s, I365_STATUS);
+    start = i365_get_pair(s, I365_IO(0)+I365_W_START);
+    stop = i365_get_pair(s, I365_IO(0)+I365_W_STOP);
+    if ((stop - start < 0x40) && (stop - start >= 0x07) &&
+	((start & 0xfeef) != 0x02e8) && (start >= 0x100) &&
+	(stat & I365_CS_DETECT) && (stat & I365_CS_POWERON) &&
+	(i365_get(s, I365_INTCTL) & I365_PC_IOCARD) &&
+	(i365_get(s, I365_ADDRWIN) & I365_ENA_IO(0)) &&
+	(check_region(start, stop-start+1) != 0))
+	return 1;
+    else
+	return 0;
+}
+
+/*====================================================================*/
+
+static void __init add_socket(u_short port, int psock, int type)
+{
+    socket_info_t *s = socket+sockets;
+    s->ioaddr = port;
+    s->psock = psock;
+    s->type = type;
+    s->flags = pcic[type].flags;
+    if (is_alive(s))
+	s->flags |= IS_ALIVE;
+    sockets++;
+}
+
+static void __init add_pcic(int ns, int type)
+{
+    u_int mask = 0, i;
+    int use_pci = 0, isa_irq = 0;
+    socket_info_t *s = &socket[sockets-ns];
+
+    if (s->ioaddr > 0) request_region(s->ioaddr, 2, "i82365");
+    
+    if (sockets == ns) printk("\n");
+    printk(KERN_INFO "  %s", pcic[type].name);
+#ifdef CONFIG_PCI
+    if (s->flags & IS_UNKNOWN)
+	printk(" [%04x %04x]", s->vendor, s->device);
+    printk(" rev %02x", s->revision);
+    if (s->flags & IS_CARDBUS)
+	printk(" PCI-to-CardBus at slot %02x:%02x, mem %#08x\n",
+	       s->bus, PCI_SLOT(s->devfn), s->cb_phys);
+    else if (s->flags & IS_PCI)
+	printk(" PCI-to-PCMCIA at slot %02x:%02x, port %#x\n",
+	       s->bus, PCI_SLOT(s->devfn), s->ioaddr);
+    else
+#endif
+	printk(" ISA-to-PCMCIA at port %#x ofs 0x%02x\n",
+	       s->ioaddr, s->psock*0x40);
+
+#ifdef CONFIG_ISA
+    if (irq_list[0] == -1)
+	mask = irq_mask;
+    else
+	for (i = mask = 0; i < 16; i++)
+	    mask |= (1<<irq_list[i]);
+#endif
+    /* Set host options, build basic interrupt mask */
+    mask &= I365_ISA_IRQ_MASK & set_bridge_opts(s, ns);
+
+#ifdef CONFIG_PCI
+    /* Can we use PCI interrupts for card status changes? */
+    if (pci_csc || pci_int) {
+	for (i = 0; i < ns; i++)
+	    if (!s[i].cap.pci_irq || !pci_scan(&s[i])) break;
+	use_pci = (i == ns);
+    }
+#endif
+#ifdef CONFIG_ISA
+    /* Scan, report ISA card interrupts */
+    if (mask)
+	mask = isa_scan(s, mask);
+#endif
+
+#ifdef CONFIG_PCI
+    if (!mask)
+	printk(KERN_INFO "    %s card interrupts,",
+	       (use_pci && pci_int) ? "PCI" : "*NO*");
+    if (use_pci && pci_csc)
+	printk(" PCI status changes\n");
+#endif
+
+#ifdef CONFIG_ISA
+    /* Poll if only two sensible interrupts available */
+    if (!(use_pci && pci_csc) && !poll_interval) {
+	u_int tmp = (mask & 0xff20);
+	tmp = tmp & (tmp-1);
+	if ((tmp & (tmp-1)) == 0)
+	    poll_interval = HZ;
+    }
+    /* Only try an ISA cs_irq if this is the first controller */
+    if (!(use_pci && pci_csc) && !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 (isa_irq = 15; isa_irq > 0; isa_irq--)
+	    if (cs_mask & (1 << isa_irq)) break;
+	if (isa_irq) {
+	    grab_irq = 1;
+	    cs_irq = isa_irq;
+	    printk(" status change on irq %d\n", isa_irq);
+	}
+    }
+#endif
+    
+    if (!(use_pci && pci_csc) && !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++) {
+	s[i].cap.features |= SS_CAP_PCCARD;
+	s[i].cap.map_size = 0x1000;
+	s[i].cap.irq_mask = mask;
+	if (!use_pci)
+	    s[i].cap.pci_irq = 0;
+	if (use_pci && pci_int)
+	    s[i].cap.irq_mask |= (1 << s[i].cap.pci_irq);
+	s[i].cs_irq = isa_irq;
+#ifdef CONFIG_PCI
+	if (s[i].flags & IS_CARDBUS) {
+	    s[i].cap.features |= SS_CAP_CARDBUS;
+	    cb_set_irq_mode(s+i, pci_csc && s[i].cap.pci_irq,
+			    pci_int && s[i].cap.pci_irq);
+	}
+#endif
+    }
+
+} /* add_pcic */
+
+/*====================================================================*/
+
+#ifdef CONFIG_PCI
+
+#ifdef __BEOS__
+typedef u_short pci_id_t;
+static int pci_lookup(u_int class, pci_id_t *id,
+		      u_char *bus, u_char *devfn)
+{
+    pci_info info;
+    while (pci->get_nth_pci_info((*id)++, &info) == 0) {
+	if (((info.class_base<<8) + info.class_sub) == class) {
+	    *bus = info.bus;
+	    *devfn = PCI_DEVFN(info.device, info.function);
+	    return 0;
+	}
+    }
+    return -1;
+}
+#else
+typedef struct pci_dev *pci_id_t;
+static int __init 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;
+}
+#endif
+
+static void __init add_pci_bridge(int type, u_short v, u_short d)
+{
+    socket_info_t *s = &socket[sockets];
+    u_int addr, ns;
+
+#ifdef __LINUX__
+    pci_enable_device(pci_find_slot(s->bus, s->devfn));
+#endif
+
+    if (type == PCIC_COUNT) type = IS_UNK_PCI;
+    pci_readl(s, PCI_BASE_ADDRESS_0, &addr);
+    addr &= ~0x1;
+    for (ns = 0; ns < ((type == IS_I82092AA) ? 4 : 2); ns++) {
+	s[ns].bus = s->bus; s[ns].devfn = s->devfn;
+	s[ns].vendor = v; s[ns].device = d;
+	add_socket(addr, ns, type);
+    }
+    add_pcic(ns, type);
+}
+
+static int check_cb_mapping(socket_info_t *s)
+{
+    /* A few sanity checks to validate the bridge mapping */
+    if ((cb_readb(s, 0x800+I365_IDENT) & 0x70) ||
+	(cb_readb(s, 0x800+I365_CSC) && cb_readb(s, 0x800+I365_CSC) &&
+	 cb_readb(s, 0x800+I365_CSC)) || cb_readl(s, CB_SOCKET_FORCE) ||
+	((cb_readl(s, CB_SOCKET_STATE) >> 16) != 0x3000))
+	return 1;
+    return 0;
+}
+
+static void __init add_cb_bridge(int type, u_short v, u_short d0)
+{
+    socket_info_t *s = &socket[sockets];
+    u_char bus = s->bus, devfn = s->devfn;
+    u_short d, ns;
+    u_char a, 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(s, PCI_HEADER_TYPE, &a);
+    pci_readb(s, PCI_CLASS_REVISION, &r);
+    max = (a & 0x80) ? 8 : 1;
+    for (ns = 0; ns < max; ns++, s++, devfn++) {
+	s->bus = bus; s->devfn = devfn;
+	if (pci_readw(s, PCI_DEVICE_ID, &d) || (d != d0))
+	    break;
+	s->vendor = v; s->device = d; s->revision = r;
+
+#ifdef __LINUX__
+	pci_enable_device(pci_find_slot(bus, devfn));
+	pci_set_power_state(pci_find_slot(bus, devfn), 0);
+#endif
+	/* Set up CardBus register mapping */
+	pci_writel(s, CB_LEGACY_MODE_BASE, 0);
+	pci_readl(s, PCI_BASE_ADDRESS_0, &s->cb_phys);
+	if (s->cb_phys == 0) {
+	    printk("\n" KERN_NOTICE "  Bridge register mapping failed:"
+		   " check cb_mem_base setting\n");
+	    break;
+	}
+	s->cb_virt = ioremap(s->cb_phys, 0x1000);
+	if (check_cb_mapping(s) != 0) {
+	    printk("\n" KERN_NOTICE "  Bad bridge mapping at "
+		   "0x%08x!\n", s->cb_phys);
+	    break;
+	}
+
+	request_mem_region(s->cb_phys, 0x1000, "i82365");
+	add_socket(0, 0, type);
+    }
+    if (ns == 0) return;
+    
+    add_pcic(ns, type);
+
+#ifdef __LINUX__
+#if (LINUX_VERSION_CODE >= VERSION(2,1,103))
+    /* Look up PCI bus bridge structures if needed */
+    s -= ns;
+    for (a = 0; a < ns; a++) {
+	struct pci_dev *self = pci_find_slot(bus, s[a].devfn);
+#if (LINUX_VERSION_CODE >= VERSION(2,3,40))
+	s[a].cap.cb_bus = self->subordinate;
+#else
+	struct pci_bus *child;
+	for (child = self->bus->children; child; child = child->next)
+	    if (child->number == s[a].cap.cardbus) break;
+	s[a].cap.cb_bus = child;
+#endif
+    }
+#endif
+#endif
+}
+
+static void __init pci_probe(u_int class)
+{
+    socket_info_t *s = &socket[sockets];
+    u_short i, v, d;
+    pci_id_t id;
+    
+    id = 0;
+    while (pci_lookup(class, &id, &s->bus, &s->devfn) == 0) {
+	if (PCI_FUNC(s->devfn) != 0) continue;
+	pci_readw(s, PCI_VENDOR_ID, &v);
+	pci_readw(s, PCI_DEVICE_ID, &d);
+	for (i = 0; i < PCIC_COUNT; i++)
+	    if ((pcic[i].vendor == v) && (pcic[i].device == d)) break;
+	if (((i < PCIC_COUNT) && (pcic[i].flags & IS_CARDBUS)) ||
+	    (class == PCI_CLASS_BRIDGE_CARDBUS))
+	    add_cb_bridge(i, v, d);
+	else
+	    add_pci_bridge(i, v, d);
+	s = &socket[sockets];
+    }
+}
+
+#endif
+
+/*====================================================================*/
+
+#ifdef CONFIG_ISA
+
+static void __init isa_probe(ioaddr_t base)
+{
+    int i, j, sock, k, ns, id;
+    ioaddr_t port;
+
+#ifndef __BEOS__
+    if (check_region(base, 2) != 0) {
+	if (sockets == 0)
+	    printk("port conflict at %#x\n", i365_base);
+	return;
+    }
+#endif
+
+    id = isa_identify(base, 0);
+    if ((id == IS_I82365DF) && (isa_identify(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 (isa_identify(port, sock) == IS_I82365DF) {
+		add_socket(port, sock, IS_VLSI);
+		add_pcic(1, IS_VLSI);
+	    }
+	}
+    } else {
+	for (i = 0; i < 4; i += 2) {
+	    port = base + 2*(i>>2);
+	    sock = (i & 3);
+	    id = isa_identify(port, sock);
+	    if (id < 0) continue;
+
+	    for (j = ns = 0; j < 2; j++) {
+		/* Does the socket exist? */
+		if ((ignore == i+j) || (isa_identify(port, sock+j) < 0))
+		    continue;
+		/* Check for bad socket decode */
+		for (k = 0; k <= sockets; k++)
+		    i365_set(socket+k, I365_MEM(0)+I365_W_OFF, k);
+		for (k = 0; k <= sockets; k++)
+		    if (i365_get(socket+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
+
+/*======================================================================
+
+    The card status event handler.  This may either be interrupt
+    driven or polled.  It monitors mainly for card insert and eject
+    events; there are various other kinds of events that can be
+    monitored (ready/busy, status change, etc), but they are almost
+    never used.
+    
+======================================================================*/
+
+static irq_ret_t pcic_interrupt IRQ(int irq, void *dev,
+				    struct pt_regs *regs)
+{
+#ifdef __BEOS__
+    int irq = (int *)dev - irq_list;
+#endif
+    int i, j, csc;
+    u_int events, active;
+#ifdef CONFIG_ISA
+    u_long flags = 0;
+#endif
+    
+    DEBUG(2, "i82365: pcic_interrupt(%d)\n", irq);
+
+    for (j = 0; j < 20; j++) {
+	active = 0;
+	for (i = 0; i < sockets; i++) {
+	    socket_info_t *s = &socket[i];
+	    if ((s->cs_irq != irq) && (s->cap.pci_irq != irq))
+		continue;
+	    ISA_LOCK(s, flags);
+	    csc = i365_get(s, I365_CSC);
+#ifdef CONFIG_PCI
+	    if ((s->flags & IS_CARDBUS) &&
+		(cb_readl(s, CB_SOCKET_EVENT) & CB_SE_CCD)) {
+		cb_writel(s, CB_SOCKET_EVENT, CB_SE_CCD);
+		csc |= I365_CSC_DETECT;
+	    }
+#endif
+	    if ((csc == 0) || (!s->handler) ||
+		(i365_get(s, I365_IDENT) & 0x70)) {
+		ISA_UNLOCK(s, flags);
+		continue;
+	    }
+	    events = (csc & I365_CSC_DETECT) ? SS_DETECT : 0;
+	    if (i365_get(s, 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;
+	    }
+	    ISA_UNLOCK(s, flags);
+	    DEBUG(1, "i82365: socket %d event 0x%04x\n", i, events);
+	    if (events)
+		s->handler(s->info, events);
+	    active |= events;
+	}
+	if (!active) break;
+    }
+    if (j == 20)
+	printk(KERN_NOTICE "i82365: infinite loop in interrupt "
+	       "handler: active = 0x%04x\n", active);
+
+    DEBUG(2, "i82365: interrupt done\n");
+    return (irq_ret_t)1;
+} /* pcic_interrupt */
+
+static void pcic_interrupt_wrapper(u_long data)
+{
+#ifdef __BEOS__
+    pcic_interrupt IRQ(0, irq_list, NULL);
+#else
+    pcic_interrupt(0, NULL, NULL);
+#endif
+    poll_timer.expires = jiffies + poll_interval;
+    add_timer(&poll_timer);
+}
+
+/*====================================================================*/
+
+static int pcic_register_callback(socket_info_t *s, ss_callback_t *call)
+{
+    if (call == NULL) {
+	s->handler = NULL;
+	MOD_DEC_USE_COUNT;
+    } else {
+	MOD_INC_USE_COUNT;
+	s->handler = call->handler;
+	s->info = call->info;
+    }
+    return 0;
+} /* pcic_register_callback */
+
+/*====================================================================*/
+
+static int pcic_inquire_socket(socket_info_t *s, socket_cap_t *cap)
+{
+    *cap = s->cap;
+    return 0;
+}
+
+/*====================================================================*/
+
+static int i365_get_status(socket_info_t *s, u_int *value)
+{
+    u_int status;
+    
+    status = i365_get(s, I365_STATUS);
+    *value = ((status & I365_CS_DETECT) == I365_CS_DETECT)
+	? SS_DETECT : 0;
+    if (i365_get(s, 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 (s->flags & IS_CARDBUS) {
+	status = cb_readl(s, CB_SOCKET_STATE);
+	*value |= (status & CB_SS_32BIT) ? SS_CARDBUS : 0;
+	*value |= (status & CB_SS_3VCARD) ? SS_3VCARD : 0;
+	*value |= (status & CB_SS_XVCARD) ? SS_XVCARD : 0;
+	*value |= (status & CB_SS_VSENSE) ? 0 : SS_PENDING;
+    } else if (s->flags & IS_O2MICRO) {
+	status = i365_get(s, O2_MODE_B);
+	*value |= (status & O2_MODE_B_VS1) ? 0 : SS_3VCARD;
+	*value |= (status & O2_MODE_B_VS2) ? 0 : SS_XVCARD;
+    } else if (s->type == IS_PD6729) {
+	socket_info_t *t = (s->psock) ? s : s+1;
+	status = pd67_ext_get(t, PD67_EXTERN_DATA);
+	*value |= (status & PD67_EXD_VS1(s->psock)) ? 0 : SS_3VCARD;
+	*value |= (status & PD67_EXD_VS2(s->psock)) ? 0 : SS_XVCARD;
+    }
+    /* For now, ignore cards with unsupported voltage keys */
+    if (*value & SS_XVCARD)
+	*value &= ~(SS_DETECT|SS_3VCARD|SS_XVCARD);
+#endif
+#ifdef CONFIG_ISA
+    if (s->type == IS_VG469) {
+	status = i365_get(s, VG469_VSENSE);
+	if (s->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", s-socket, *value);
+    return 0;
+} /* i365_get_status */
+
+/*====================================================================*/
+
+static int i365_get_socket(socket_info_t *s, socket_state_t *state)
+{
+    u_char reg, vcc, vpp;
+    
+    reg = i365_get(s, 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 (s->flags & IS_CARDBUS) {
+	cb_get_power(s, state);
+    } else
+#endif
+    if (s->flags & IS_CIRRUS) {
+	if (i365_get(s, 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 (s->flags & IS_VG_PWR) {
+	if (i365_get(s, 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 (s->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(s, I365_INTCTL);
+    state->flags |= (reg & I365_PC_RESET) ? 0 : SS_RESET;
+    state->flags |= (reg & I365_PC_IOCARD) ? SS_IOCARD : 0;
+#ifdef CONFIG_PCI
+    if (cb_get_irq_mode(s) != 0)
+	state->io_irq = s->cap.pci_irq;
+    else
+#endif
+	state->io_irq = reg & I365_IRQ_MASK;
+    
+    /* Card status change mask */
+    reg = i365_get(s, 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(2, "i82365: GetSocket(%d) = flags %#3.3x, Vcc %d, Vpp %d, "
+	  "io_irq %d, csc_mask %#2.2x\n", s-socket, state->flags,
+	  state->Vcc, state->Vpp, state->io_irq, state->csc_mask);
+    return 0;
+} /* i365_get_socket */
+
+/*====================================================================*/
+
+static int i365_set_socket(socket_info_t *s, socket_state_t *state)
+{
+    u_char reg;
+    
+    DEBUG(2, "i82365: SetSocket(%d, flags %#3.3x, Vcc %d, Vpp %d, "
+	  "io_irq %d, csc_mask %#2.2x)\n", s-socket, state->flags,
+	  state->Vcc, state->Vpp, state->io_irq, state->csc_mask);
+    
+    /* First set global controller options */
+#ifdef CONFIG_PCI
+    if (s->cap.pci_irq)
+	cb_set_irq_mode(s, pci_csc, (s->cap.pci_irq == state->io_irq));
+    s->bcr &= ~CB_BCR_CB_RESET;
+#endif
+    set_bridge_state(s);
+    
+    /* IO card, RESET flag, IO interrupt */
+    reg = s->intr | ((state->io_irq == s->cap.pci_irq) ?
+		     s->pci_irq_code : state->io_irq);
+    reg |= (state->flags & SS_RESET) ? 0 : I365_PC_RESET;
+    reg |= (state->flags & SS_IOCARD) ? I365_PC_IOCARD : 0;
+    i365_set(s, 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 (s->flags & IS_CARDBUS) {
+	cb_set_power(s, state);
+	reg |= i365_get(s, I365_POWER) & (I365_VCC_MASK|I365_VPP1_MASK);
+    } else
+#endif
+    if (s->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(s, PD67_MISC_CTL_1, PD67_MC1_VCC_3V);
+	    else if (state->Vcc == 50)
+		i365_bclr(s, PD67_MISC_CTL_1, PD67_MC1_VCC_3V);
+	    else return -EINVAL;
+	}
+    } else if (s->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(s, VG469_VSELECT, VG469_VSEL_VCC);
+	    else if (state->Vcc == 50)
+		i365_bclr(s, VG469_VSELECT, VG469_VSEL_VCC);
+	    else return -EINVAL;
+	}
+    } else if (s->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(s, I365_POWER))
+	i365_set(s, I365_POWER, reg);
+
+    /* Card status change interrupt mask */
+    reg = (s->cap.pci_irq ? s->pci_irq_code : s->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(s, I365_CSCINT, reg);
+    i365_get(s, I365_CSC);
+#ifdef CONFIG_PCI
+    if (s->flags & IS_CARDBUS) {
+	if (s->cs_irq || (pci_csc && s->cap.pci_irq))
+	    cb_writel(s, CB_SOCKET_MASK, CB_SM_CCD);
+	cb_writel(s, CB_SOCKET_EVENT, -1);
+    }
+#endif
+
+    return 0;
+} /* i365_set_socket */
+
+/*====================================================================*/
+
+static int i365_get_io_map(socket_info_t *s, struct pccard_io_map *io)
+{
+    u_char map, ioctl, addr;
+    
+    map = io->map;
+    if (map > 1) return -EINVAL;
+    io->start = i365_get_pair(s, I365_IO(map)+I365_W_START);
+    io->stop = i365_get_pair(s, I365_IO(map)+I365_W_STOP);
+    ioctl = i365_get(s, I365_IOCTL);
+    addr = i365_get(s, I365_ADDRWIN);
+    io->speed = (ioctl & I365_IOCTL_WAIT(map)) ? cycle_time : 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(3, "i82365: GetIOMap(%d, %d) = %#2.2x, %d ns, %#4.4x-%#4.4x\n",
+	  s-socket, map, io->flags, io->speed, io->start, io->stop);
+    return 0;
+} /* i365_get_io_map */
+
+/*====================================================================*/
+
+static int i365_set_io_map(socket_info_t *s, struct pccard_io_map *io)
+{
+    u_char map, ioctl;
+    
+    DEBUG(3, "i82365: SetIOMap(%d, %d, %#2.2x, %d ns, %#4.4x-%#4.4x)\n",
+	  s-socket, 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(s, I365_ADDRWIN) & I365_ENA_IO(map))
+	i365_bclr(s, I365_ADDRWIN, I365_ENA_IO(map));
+    i365_set_pair(s, I365_IO(map)+I365_W_START, io->start);
+    i365_set_pair(s, I365_IO(map)+I365_W_STOP, io->stop);
+    ioctl = i365_get(s, 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(s, I365_IOCTL, ioctl);
+    /* Turn on the window if necessary */
+    if (io->flags & MAP_ACTIVE)
+	i365_bset(s, I365_ADDRWIN, I365_ENA_IO(map));
+    return 0;
+} /* i365_set_io_map */
+
+/*====================================================================*/
+
+static int i365_get_mem_map(socket_info_t *s, struct pccard_mem_map *mem)
+{
+    u_short base, i;
+    u_char map, addr;
+    
+    map = mem->map;
+    if (map > 4) return -EINVAL;
+    addr = i365_get(s, I365_ADDRWIN);
+    mem->flags = (addr & I365_ENA_MEM(map)) ? MAP_ACTIVE : 0;
+    base = I365_MEM(map);
+    
+    i = i365_get_pair(s, 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(s, base+I365_W_STOP);
+    mem->speed  = (i & I365_MEM_WS0) ? 1 : 0;
+    mem->speed += (i & I365_MEM_WS1) ? 2 : 0;
+    mem->speed *= cycle_time;
+    mem->sys_stop = ((u_long)(i & 0x0fff) << 12) + 0x0fff;
+    
+    i = i365_get_pair(s, 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 (s->type == IS_PD6729) {
+	i365_set(s, PD67_EXT_INDEX, PD67_MEM_PAGE(map));
+	addr = i365_get(s, PD67_EXT_DATA) << 24;
+    } else if (s->flags & IS_CARDBUS) {
+	addr = i365_get(s, CB_MEM_PAGE(map)) << 24;
+	mem->sys_stop += addr; mem->sys_start += addr;
+    }
+#endif
+    
+    DEBUG(3, "i82365: GetMemMap(%d, %d) = %#2.2x, %d ns, %#5.5lx-%#5."
+	  "5lx, %#5.5x\n", s-socket, 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(socket_info_t *s, struct pccard_mem_map *mem)
+{
+    u_short base, i;
+    u_char map;
+    
+    DEBUG(3, "i82365: SetMemMap(%d, %d, %#2.2x, %d ns, %#5.5lx-%#5.5"
+	  "lx, %#5.5x)\n", s-socket, 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 (!(s->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(s, I365_ADDRWIN) & I365_ENA_MEM(map))
+	i365_bclr(s, I365_ADDRWIN, I365_ENA_MEM(map));
+
+#ifdef CONFIG_PCI
+    /* Take care of high byte, for PCI controllers */
+    if (s->type == IS_PD6729) {
+	i365_set(s, PD67_EXT_INDEX, PD67_MEM_PAGE(map));
+	i365_set(s, PD67_EXT_DATA, (mem->sys_start >> 24));
+    } else if (s->flags & IS_CARDBUS)
+	i365_set(s, 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(s, base+I365_W_START, i);
+    
+    i = (mem->sys_stop >> 12) & 0x0fff;
+    switch (mem->speed / cycle_time) {
+    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(s, 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(s, base+I365_W_OFF, i);
+    
+    /* Turn on the window if necessary */
+    if (mem->flags & MAP_ACTIVE)
+	i365_bset(s, I365_ADDRWIN, I365_ENA_MEM(map));
+    return 0;
+} /* i365_set_mem_map */
+
+/*======================================================================
+
+    The few things that are strictly for Cardbus cards goes here.
+
+======================================================================*/
+
+#ifdef CONFIG_CARDBUS
+
+static int cb_get_status(socket_info_t *s, u_int *value)
+{
+    u_int state = cb_readl(s, CB_SOCKET_STATE);
+    *value = (state & CB_SS_32BIT) ? SS_CARDBUS : 0;
+    *value |= (state & CB_SS_CCD) ? 0 : SS_DETECT;
+    *value |= (state & CB_SS_CSTSCHG) ? SS_STSCHG : 0;
+    *value |= (state & CB_SS_PWRCYCLE) ? (SS_POWERON|SS_READY) : 0;
+    *value |= (state & CB_SS_3VCARD) ? SS_3VCARD : 0;
+    *value |= (state & CB_SS_XVCARD) ? SS_XVCARD : 0;
+    *value |= (state & CB_SS_VSENSE) ? 0 : SS_PENDING;
+    DEBUG(1, "yenta: GetStatus(%d) = %#4.4x\n", s-socket, *value);
+    return 0;
+} /* cb_get_status */
+
+static int cb_get_socket(socket_info_t *s, socket_state_t *state)
+{
+    u_short bcr;
+
+    cb_get_power(s, state);
+    pci_readw(s, CB_BRIDGE_CONTROL, &bcr);
+    state->flags |= (bcr & CB_BCR_CB_RESET) ? SS_RESET : 0;
+    if (cb_get_irq_mode(s) != 0)
+	state->io_irq = s->cap.pci_irq;
+    else
+	state->io_irq = i365_get(s, I365_INTCTL) & I365_IRQ_MASK;
+    DEBUG(2, "yenta: GetSocket(%d) = flags %#3.3x, Vcc %d, Vpp %d"
+	  ", io_irq %d, csc_mask %#2.2x\n", s-socket, state->flags,
+	  state->Vcc, state->Vpp, state->io_irq, state->csc_mask);
+    return 0;
+} /* cb_get_socket */
+
+static int cb_set_socket(socket_info_t *s, socket_state_t *state)
+{
+    u_int reg;
+    
+    DEBUG(2, "yenta: SetSocket(%d, flags %#3.3x, Vcc %d, Vpp %d, "
+	  "io_irq %d, csc_mask %#2.2x)\n", s-socket, 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(s, 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_bridge_state(s);
+    
+    cb_set_power(s, state);
+    
+    /* Handle IO interrupt using ISA routing */
+    reg = s->intr;
+    if (state->io_irq != s->cap.pci_irq) reg |= state->io_irq;
+    i365_set(s, I365_INTCTL, reg);
+    
+    /* Handle CSC mask */
+    if (!s->cs_irq && (!pci_csc || !s->cap.pci_irq))
+	return 0;
+    reg = (s->cs_irq << 4);
+    if (state->csc_mask & SS_DETECT) reg |= I365_CSC_DETECT;
+    i365_set(s, I365_CSCINT, reg);
+    i365_get(s, I365_CSC);
+    cb_writel(s, CB_SOCKET_MASK, CB_SM_CCD);
+    cb_writel(s, CB_SOCKET_EVENT, -1);
+    
+    return 0;
+} /* cb_set_socket */
+
+static int cb_get_bridge(socket_info_t *s, struct cb_bridge_map *m)
+{
+    u_char map = m->map;
+
+    if (map > 1) return -EINVAL;
+    m->flags &= MAP_IOSPACE;
+    map += (m->flags & MAP_IOSPACE) ? 2 : 0;
+    pci_readl(s, CB_MEM_BASE(map), &m->start);
+    pci_readl(s, 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, CB_BRIDGE_CONTROL, &bcr);
+	m->flags |= (bcr & CB_BCR_PREFETCH(map)) ? MAP_PREFETCH : 0;
+    }
+    DEBUG(3, "yenta: GetBridge(%d, %d) = %#2.2x, %#4.4x-%#4.4x\n",
+	  s-socket, map, m->flags, m->start, m->stop);
+    return 0;
+}
+
+static int cb_set_bridge(socket_info_t *s, struct cb_bridge_map *m)
+{
+    u_char map;
+    
+    DEBUG(3, "yenta: SetBridge(%d, %d, %#2.2x, %#4.4x-%#4.4x)\n",
+	  s-socket, 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, CB_BRIDGE_CONTROL, &bcr);
+	bcr &= ~CB_BCR_PREFETCH(map);
+	bcr |= (m->flags & MAP_PREFETCH) ? CB_BCR_PREFETCH(map) : 0;
+	pci_writew(s, CB_BRIDGE_CONTROL, bcr);
+    }
+    if (m->flags & MAP_ACTIVE) {
+	pci_writel(s, CB_MEM_BASE(map), m->start);
+	pci_writel(s, CB_MEM_LIMIT(map), m->stop);
+    } else {
+	pci_writel(s, CB_MEM_BASE(map), 0);
+	pci_writel(s, CB_MEM_LIMIT(map), 0);
+    }
+    return 0;
+}
+
+#endif /* CONFIG_CARDBUS */
+
+/*======================================================================
+
+    Routines for accessing socket information and register dumps via
+    /proc/bus/pccard/...
+    
+======================================================================*/
+
+#ifdef HAS_PROC_BUS
+
+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)
+{
+    socket_info_t *s = data;
+    char *p = buf;
+    int i, top;
+    
+#ifdef CONFIG_ISA
+    u_long flags = 0;
+#endif
+    ISA_LOCK(s, flags);
+    top = 0x40;
+    if (s->flags & IS_CARDBUS)
+	top = (s->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(s,i), i365_get(s,i+1),
+		     i365_get(s,i+2), i365_get(s,i+3),
+		     ((i % 16) == 12) ? "\n" : " ");
+    }
+    ISA_UNLOCK(s, flags);
+    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;
+    char *p = buf;
+    u_int a, b, c, d;
+    int i;
+    
+    for (i = 0; i < 0xc0; i += 0x10) {
+	pci_readl(s, i, &a);
+	pci_readl(s, i+4, &b);
+	pci_readl(s, i+8, &c);
+	pci_readl(s, i+12, &d);
+	p += sprintf(p, "%08x %08x %08x %08x\n", a, b, c, d);
+    }
+    return (p - buf);
+}
+
+static int proc_read_cardbus(char *buf, char **start, off_t pos,
+			     int count, int *eof, void *data)
+{
+    socket_info_t *s = data;
+    char *p = buf;
+    int i, top;
+
+    top = (s->flags & IS_O2MICRO) ? 0x30 : 0x20;
+    for (i = 0; i < top; i += 0x10)
+	p += sprintf(p, "%08x %08x %08x %08x\n",
+		     cb_readl(s,i+0x00), cb_readl(s,i+0x04),
+		     cb_readl(s,i+0x08), cb_readl(s,i+0x0c));
+    return (p - buf);
+}
+#endif
+
+static void pcic_proc_setup(socket_info_t *s, struct proc_dir_entry *base)
+{
+    create_proc_read_entry("info", 0, base, proc_read_info, s);
+    create_proc_read_entry("exca", 0, base, proc_read_exca, s);
+#ifdef CONFIG_PCI
+    if (s->flags & (IS_PCI|IS_CARDBUS))
+	create_proc_read_entry("pci", 0, base, proc_read_pci, s);
+    if (s->flags & IS_CARDBUS)
+	create_proc_read_entry("cardbus", 0, base, proc_read_cardbus, s);
+#endif
+    s->proc = base;
+}
+
+static void pcic_proc_remove(socket_info_t *s)
+{
+    struct proc_dir_entry *base = s->proc;
+    if (base == NULL) return;
+    remove_proc_entry("info", base);
+    remove_proc_entry("exca", base);
+#ifdef CONFIG_PCI
+    if (s->flags & (IS_PCI|IS_CARDBUS))
+	remove_proc_entry("pci", base);
+    if (s->flags & IS_CARDBUS)
+	remove_proc_entry("cardbus", base);
+#endif
+}
+
+#endif /* HAS_PROC_BUS */
+
+/*====================================================================*/
+
+typedef int (*subfn_t)(socket_info_t *, 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 HAS_PROC_BUS
+    (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)
+{
+    socket_info_t *s = &socket[sock];
+    subfn_t fn;
+    int ret;
+#ifdef CONFIG_ISA
+    u_long flags = 0;
+#endif
+
+    if (cmd >= NFUNC)
+	return -EINVAL;
+
+    if (s->flags & IS_ALIVE) {
+	if (cmd == SS_GetStatus)
+	    *(u_int *)arg = 0;
+	return -EINVAL;
+    }
+    
+    fn = pcic_service_table[cmd];
+#ifdef CONFIG_CARDBUS
+    if ((s->flags & IS_CARDBUS) &&
+	(cb_readl(s, 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
+
+    ISA_LOCK(s, flags);
+    ret = (fn == NULL) ? -EINVAL : fn(s, arg);
+    ISA_UNLOCK(s, flags);
+    return ret;
+} /* pcic_service */
+
+/*====================================================================*/
+
+static int __init init_i82365(void)
+{
+#ifdef __LINUX__
+    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;
+    }
+#endif
+    DEBUG(0, "%s\n", version);
+    printk(KERN_INFO "Intel PCIC probe: ");
+    sockets = 0;
+
+    ACQUIRE_RESOURCE_LOCK;
+
+#ifdef CONFIG_PCI
+    if (do_pci_probe && pcibios_present()) {
+	pci_probe(PCI_CLASS_BRIDGE_CARDBUS);
+	pci_probe(PCI_CLASS_BRIDGE_PCMCIA);
+    }
+#endif
+
+#ifdef CONFIG_ISA
+    isa_probe(i365_base);
+    if (!sockets || extra_sockets)
+	isa_probe(i365_base+2);
+#endif
+
+    RELEASE_RESOURCE_LOCK;
+
+    if (sockets == 0) {
+	printk("not found.\n");
+	return -ENODEV;
+    }
+
+    /* Set up interrupt handler(s) */
+#ifdef CONFIG_ISA
+    if (grab_irq != 0)
+	_request_irq(cs_irq, pcic_interrupt, 0, "i82365");
+#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");
+	    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.expires = jiffies + poll_interval;
+	add_timer(&poll_timer);
+    }
+
+    return 0;
+
+} /* init_i82365 */
+
+static void __exit exit_i82365(void)
+{
+    int i;
+#ifdef HAS_PROC_BUS
+    for (i = 0; i < sockets; i++)
+	pcic_proc_remove(&socket[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, pcic_interrupt);
+#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, pcic_interrupt);
+	    mask |= (1<<irq);
+	}
+    }
+#endif
+    for (i = 0; i < sockets; i++) {
+	socket_info_t *s = &socket[i];
+	/* Turn off all interrupt sources! */
+	i365_set(s, I365_CSCINT, 0);
+#ifdef CONFIG_PCI
+	if (s->flags & IS_CARDBUS)
+	    cb_writel(s, CB_SOCKET_MASK, 0);
+	if (s->cb_virt) {
+	    iounmap(s->cb_virt);
+	    release_mem_region(s->cb_phys, 0x1000);
+	} else
+#endif
+	    release_region(s->ioaddr, 2);
+    }
+} /* exit_i82365 */
+
+#ifdef __LINUX__
+
+module_init(init_i82365);
+module_exit(exit_i82365);
+
+#endif
+
+/*====================================================================*/
+
+#ifdef __BEOS__
+
+static status_t std_ops(int32 op)
+{
+    int ret;
+    switch (op) {
+    case B_MODULE_INIT:
+	ret = get_module(CS_SOCKET_MODULE_NAME, (struct module_info **)&cs);
+	if (ret != B_OK) return ret;
+	ret = get_module(B_ISA_MODULE_NAME, (struct module_info **)&isa);
+	if (ret != B_OK) return ret;
+	ret = get_module(B_PCI_MODULE_NAME, (struct module_info **)&pci);
+	if (ret != B_OK) return ret;
+	return pcic_init();
+	break;
+    case B_MODULE_UNINIT:
+	exit_i82365();
+	if (pci) put_module(B_PCI_MODULE_NAME);
+	if (isa) put_module(B_ISA_MODULE_NAME);
+	if (cs) put_module(CS_SOCKET_MODULE_NAME);
+	break;
+    }
+    return B_OK;
+}
+
+static module_info pcic_mod_info = {
+    SS_MODULE_NAME("i82365"), 0, &std_ops
+};
+
+_EXPORT module_info *modules[] = {
+    &pcic_mod_info,
+    NULL
+};
+
+#endif
Index: oldkernel/linux/pcmcia-cs-3.1.15/modules/i82365.h
diff -u /dev/null linux/pcmcia-cs-3.1.15/modules/i82365.h:1.1
--- /dev/null	Mon Jul 31 21:15:12 2000
+++ linux/pcmcia-cs-3.1.15/modules/i82365.h	Fri Jul  7 16:34:58 2000
@@ -0,0 +1,153 @@
+/*
+ * i82365.h 1.18 2000/03/08 23:37:13
+ *
+ * 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@pcmcia.sourceforge.org>.  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))
+
+/* Default ISA interrupt mask */
+#define I365_ISA_IRQ_MASK	0xdeb8	/* irq's 3-5,7,9-12,14,15 */
+
+/* Device ID's for PCI-to-PCMCIA bridges */
+
+#ifndef PCI_VENDOR_ID_INTEL
+#define PCI_VENDOR_ID_INTEL		0x8086
+#endif
+#ifndef PCI_DEVICE_ID_INTEL_82092AA_0
+#define PCI_DEVICE_ID_INTEL_82092AA_0	0x1221
+#endif
+#ifndef PCI_VENDOR_ID_OMEGA
+#define PCI_VENDOR_ID_OMEGA		0x119b
+#endif
+#ifndef PCI_DEVICE_ID_OMEGA_82C092G
+#define PCI_DEVICE_ID_OMEGA_82C092G	0x1221
+#endif
+
+#endif /* _LINUX_I82365_H */
Index: oldkernel/linux/pcmcia-cs-3.1.15/modules/o2micro.h
diff -u /dev/null linux/pcmcia-cs-3.1.15/modules/o2micro.h:1.1
--- /dev/null	Mon Jul 31 21:15:12 2000
+++ linux/pcmcia-cs-3.1.15/modules/o2micro.h	Fri Jul  7 16:34:58 2000
@@ -0,0 +1,137 @@
+/*
+ * o2micro.h 1.15 2000/04/24 21:19: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@pcmcia.sourceforge.org>.  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
+#ifndef PCI_DEVICE_ID_O2_6812
+#define PCI_DEVICE_ID_O2_6812		0x6872
+#endif
+
+/* Additional PCI configuration registers */
+
+#define O2_MUX_CONTROL		0x90	/* 32 bit */
+#define  O2_MUX_RING_OUT	0x0000000f
+#define  O2_MUX_SKTB_ACTV	0x000000f0
+#define  O2_MUX_SCTA_ACTV_ENA	0x00000100
+#define  O2_MUX_SCTB_ACTV_ENA	0x00000200
+#define  O2_MUX_SER_IRQ_ROUTE	0x0000e000
+#define  O2_MUX_SER_PCI		0x00010000
+
+#define  O2_MUX_SKTA_TURBO	0x000c0000	/* for 6833, 6860 */
+#define  O2_MUX_SKTB_TURBO	0x00300000
+#define  O2_MUX_AUX_VCC_3V	0x00400000
+#define  O2_MUX_PCI_VCC_5V	0x00800000
+#define  O2_MUX_PME_MUX		0x0f000000
+
+/* Additional ExCA registers */
+
+#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_PWR_MASK	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_C_IREQ_SEL	0x30
+#define  O2_MODE_C_MGMT_SEL	0xc0
+
+#define O2_MODE_D		0x3b
+#define  O2_MODE_D_IRQ_MODE	0x03
+#define  O2_MODE_D_IRQ_PCPCI	0x00
+#define  O2_MODE_D_IRQ_PCIWAY	0x02
+#define  O2_MODE_D_IRQ_PCI	0x03
+#define  O2_MODE_D_PCI_CLKRUN	0x04
+#define  O2_MODE_D_CB_CLKRUN	0x08
+#define  O2_MODE_D_SKT_ACTV	0x20
+#define  O2_MODE_D_PCI_FIFO	0x40	/* for OZ6729, OZ6730 */
+#define  O2_MODE_D_W97_IRQ	0x40
+#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
+
+/* Data structure for tracking vendor-specific state */
+typedef struct o2micro_state_t {
+    u_char		mode_a;		/* O2_MODE_A */
+    u_char		mode_b;		/* O2_MODE_B */
+    u_char		mode_c;		/* O2_MODE_C */
+    u_char		mode_d;		/* O2_MODE_D */
+    u_char		mhpg;		/* O2_MHPG_DMA */
+    u_char		fifo;		/* O2_FIFO_ENA */
+    u_char		mode_e;		/* O2_MODE_E */
+} o2micro_state_t;
+
+#endif /* _LINUX_O2MICRO_H */
Index: oldkernel/linux/pcmcia-cs-3.1.15/modules/pci_fixup.c
diff -u /dev/null linux/pcmcia-cs-3.1.15/modules/pci_fixup.c:1.1
--- /dev/null	Mon Jul 31 21:15:12 2000
+++ linux/pcmcia-cs-3.1.15/modules/pci_fixup.c	Fri Jul  7 16:34:58 2000
@@ -0,0 +1,599 @@
+/*======================================================================
+
+    Kernel fixups for PCI device support
+    
+    pci_fixup.c 1.17 2000/05/16 21:31:49
+    
+    PCI bus fixups: various bits of code that don't really belong in
+    the PCMCIA subsystem, but may or may not be available from the
+    kernel, depending on kernel version.  The basic idea is to make
+    2.0.* and 2.2.* kernels look like they have the 2.3.* features.
+
+======================================================================*/
+
+#include <pcmcia/config.h>
+#define __NO_VERSION__
+#include <pcmcia/k_compat.h>
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/malloc.h>
+#include <linux/pci.h>
+#include <asm/io.h>
+
+/* We use these for setting up CardBus bridges */
+#include "yenta.h"
+#include "i82365.h"
+
+#if (LINUX_VERSION_CODE < VERSION(2,3,24))
+
+/* Default memory base addresses for CardBus controllers */
+static u_int cb_mem_base[] = { 0x0, 0x68000000, 0xf8000000 };
+MODULE_PARM(cb_mem_base, "i");
+
+/* PCI bus number overrides for CardBus controllers */
+#define INT_MODULE_PARM(n, v) static int n = v; MODULE_PARM(n, "i")
+INT_MODULE_PARM(cb_bus_base, 0);
+INT_MODULE_PARM(cb_bus_step, 2);
+INT_MODULE_PARM(cb_pci_irq, 0);
+
+#endif
+
+/* (exported) mask of interrupts reserved for PCI devices */
+u32 pci_irq_mask = 0;
+
+/*======================================================================
+
+    Basic PCI services missing from older kernels: device lookup, etc
+
+======================================================================*/
+
+#if (LINUX_VERSION_CODE < VERSION(2,1,0))
+struct pci_dev *pci_devices = NULL;
+struct pci_bus pci_root = {
+    parent:	NULL,
+    children:	NULL,
+    next:	NULL,
+    self:	NULL,
+    devices:	NULL,
+    number:	0
+};
+#endif
+
+#if (LINUX_VERSION_CODE < VERSION(2,1,93))
+
+struct pci_dev *pci_find_slot(u_int bus, u_int devfn)
+{
+    struct pci_dev *dev;
+    for (dev = pci_devices; dev; dev = dev->next)
+	if ((dev->devfn == devfn) && (bus == dev->bus->number))
+	    return dev;
+#if (LINUX_VERSION_CODE > VERSION(2,1,0))
+    return NULL;
+#else
+    {
+	struct pci_bus *b;
+	u8 hdr;
+	u32 id, class;
+
+	if (pcibios_read_config_byte(bus, devfn & ~7, PCI_HEADER_TYPE, &hdr))
+	    return NULL;
+	if (PCI_FUNC(devfn) && !(hdr & 0x80))
+	    return NULL;
+	pcibios_read_config_dword(bus, devfn, PCI_VENDOR_ID, &id);
+	if ((id == 0) || (id == 0xffffffff))
+	    return NULL;
+	dev = kmalloc(sizeof *dev, GFP_ATOMIC);
+	if (!dev)
+	    return NULL;
+	memset(dev, 0, sizeof *dev);
+	dev->devfn = devfn;
+	pcibios_read_config_byte(bus, devfn, PCI_INTERRUPT_LINE, &dev->irq);
+	dev->vendor = id & 0xffff;
+	dev->device = id >> 16;
+	pcibios_read_config_dword(bus, devfn, PCI_CLASS_REVISION, &class);
+	if (dev->irq == 255)
+	    dev->irq = 0;
+	dev->class = class >> 8;
+	for (b = &pci_root; b; b = b->next)
+	    if (b->number == bus) break;
+	if (!b) {
+	    b = kmalloc(sizeof *b, GFP_ATOMIC);
+	    if (!b) {
+		kfree(dev);
+		return NULL;
+	    }
+	    memset(b, 0, sizeof *b);
+	    b->number = bus;
+	    b->next = pci_root.next;
+	    pci_root.next = b;
+	}
+	dev->bus = b;
+	return dev;
+    }
+#endif
+}
+
+struct pci_dev *pci_find_class(u_int class, struct pci_dev *from)
+{
+    static u16 index = 0;
+    u8 bus, devfn;
+    if (from == NULL)
+	index = 0;
+    if (pcibios_find_class(class, index++, &bus, &devfn) == 0)
+	return pci_find_slot(bus, devfn);
+    else
+	return NULL;
+}
+
+#endif /* (LINUX_VERSION_CODE < VERSION(2,1,93)) */
+
+/*======================================================================
+
+    PCI Interrupt Routing Table parser
+
+    This only needs to be done once per boot: we scan the BIOS for
+    the routing table, and then look for devices that have interrupt
+    assignments that the kernel doesn't know about.  If we find any,
+    we update their pci_dev structures and write the PCI interrupt
+    line registers.
+    
+======================================================================*/
+
+#if (LINUX_VERSION_CODE < VERSION(2,3,24)) && defined(__i386__)
+
+#pragma pack(1)
+
+struct slot_entry {
+    u8		bus, devfn;
+    struct pirq_pin {
+	u8	link;
+	u16	irq_map;
+    } pin[4];
+    u8		slot;
+    u8		reserved;
+};
+
+struct routing_table {
+    u32		signature;
+    u8		minor, major;
+    u16		size;
+    u8		bus, devfn;
+    u16		pci_mask;
+    u32		compat;
+    u32		miniport;
+    u8		reserved[11];
+    u8		checksum;
+    struct slot_entry entry[0];
+};
+
+#pragma pack()
+
+/*
+  The meaning of the link bytes in the routing table is vendor
+  specific.  We need code to get and set the routing information.
+*/
+
+static u8 pIIx_link(struct pci_dev *router, u8 link)
+{
+    u8 pirq;
+    /* link should be 0x60, 0x61, 0x62, 0x63 */
+    pci_read_config_byte(router, link, &pirq);
+    return (pirq < 16) ? pirq : 0;
+}
+
+static void pIIx_init(struct pci_dev *router, u8 link, u8 irq)
+{
+    pci_write_config_byte(router, link, irq);
+}
+
+static u8 via_link(struct pci_dev *router, u8 link)
+{
+    u8 pirq = 0;
+    /* link should be 1, 2, 3, 5 */
+    if (link < 6)
+	pci_read_config_byte(router, 0x55 + (link>>1), &pirq);
+    return (link & 1) ? (pirq >> 4) : (pirq & 15);
+}
+
+static void via_init(struct pci_dev *router, u8 link, u8 irq)
+{
+    u8 pirq;
+    pci_read_config_byte(router, 0x55 + (link>>1), &pirq);
+    pirq &= (link & 1) ? 0x0f : 0xf0;
+    pirq |= (link & 1) ? (irq << 4) : (irq & 15);
+    pci_write_config_byte(router, 0x55 + (link>>1), pirq);
+}
+
+static u8 opti_link(struct pci_dev *router, u8 link)
+{
+    u8 pirq = 0;
+    /* link should be 0x02, 0x12, 0x22, 0x32 */
+    if ((link & 0xcf) == 0x02)
+	pci_read_config_byte(router, 0xb8 + (link >> 5), &pirq);
+    return (link & 0x10) ? (pirq >> 4) : (pirq & 15);
+}
+
+static void opti_init(struct pci_dev *router, u8 link, u8 irq)
+{
+    u8 pirq;
+    pci_read_config_byte(router, 0xb8 + (link >> 5), &pirq);
+    pirq &= (link & 0x10) ? 0x0f : 0xf0;
+    pirq |= (link & 0x10) ? (irq << 4) : (irq & 15);
+    pci_write_config_byte(router, 0xb8 + (link >> 5), pirq);
+}
+
+static u8 ali_link(struct pci_dev *router, u8 link)
+{
+    /* No, you're not dreaming */
+    static const u8 map[] =
+    { 0, 9, 3, 10, 4, 5, 7, 6, 1, 11, 0, 12, 0, 14, 0, 15 };
+    u8 pirq;
+    /* link should be 0x01..0x08 */
+    pci_read_config_byte(router, 0x48 + ((link-1)>>1), &pirq);
+    return (link & 1) ? map[pirq&15] : map[pirq>>4];
+}
+
+static void ali_init(struct pci_dev *router, u8 link, u8 irq)
+{
+    /* Inverse of map in ali_link */
+    static const u8 map[] =
+    { 0, 8, 0, 2, 4, 5, 7, 6, 0, 1, 3, 9, 11, 0, 13, 15 };
+    u8 pirq;
+    pci_read_config_byte(router, 0x48 + ((link-1)>>1), &pirq);
+    pirq &= (link & 1) ? 0x0f : 0xf0;
+    pirq |= (link & 1) ? (map[irq] << 4) : (map[irq] & 15);
+    pci_write_config_byte(router, 0x48 + ((link-1)>>1), pirq);
+}
+
+/*
+  A table of all the PCI interrupt routers for which we know how to
+  interpret the link bytes.
+*/
+
+#ifndef PCI_DEVICE_ID_INTEL_82371FB_0
+#define PCI_DEVICE_ID_INTEL_82371FB_0 0x122e
+#endif
+#ifndef PCI_DEVICE_ID_INTEL_82371SB_0
+#define PCI_DEVICE_ID_INTEL_82371SB_0 0x7000
+#endif
+#ifndef PCI_DEVICE_ID_INTEL_82371AB_0
+#define PCI_DEVICE_ID_INTEL_82371AB_0 0x7110
+#endif
+#ifndef PCI_DEVICE_ID_INTEL_82440MX_1
+#define PCI_DEVICE_ID_INTEL_82440MX_1 0x7198
+#endif
+#ifndef PCI_DEVICE_ID_VIA_82C586_0
+#define PCI_DEVICE_ID_VIA_82C586_0 0x0586
+#endif
+#ifndef PCI_DEVICE_ID_VIA_82C596
+#define PCI_DEVICE_ID_VIA_82C596 0x0596
+#endif
+#ifndef PCI_DEVICE_ID_VIA_82C686
+#define PCI_DEVICE_ID_VIA_82C686 0x0686
+#endif
+
+#define ID(a,b) PCI_VENDOR_ID_##a,PCI_DEVICE_ID_##a##_##b
+
+struct router {
+    u16 vendor, device;
+    u8 (*xlate)(struct pci_dev *, u8);
+    void (*init)(struct pci_dev *, u8, u8);
+} router_table[] = {
+    { ID(INTEL, 82371FB_0),	&pIIx_link,	&pIIx_init },
+    { ID(INTEL, 82371SB_0),	&pIIx_link,	&pIIx_init },
+    { ID(INTEL, 82371AB_0),	&pIIx_link,	&pIIx_init },
+    { ID(INTEL, 82440MX_1),	&pIIx_link,	&pIIx_init },
+    { ID(VIA, 82C586_0),	&via_link,	&via_init },
+    { ID(VIA, 82C596),		&via_link,	&via_init },
+    { ID(VIA, 82C686),		&via_link,	&via_init },
+    { ID(OPTI, 82C700),		&opti_link,	&opti_init },
+    { ID(AL, M1533),		&ali_link,	&ali_init }
+};
+#define ROUTER_COUNT (sizeof(router_table)/sizeof(router_table[0]))
+
+/* Global variables for current interrupt routing table */
+static struct routing_table *pirq = NULL;
+static struct pci_dev *router_dev = NULL;
+static struct router *router_info = NULL;
+
+#ifndef __va
+#define __va(x) (x)
+#endif
+
+static void scan_pirq_table(void)
+{
+    struct routing_table *r;
+    struct pci_dev *router, *dev;
+    u8 pin, fn, *p;
+    int i;
+    struct slot_entry *e;
+
+    /* Scan the BIOS for the routing table signature */
+    for (p = (u8 *)__va(0xf0000); p < (u8 *)__va(0xfffff); p += 16)
+	if ((p[0] == '$') && (p[1] == 'P') &&
+	    (p[2] == 'I') && (p[3] == 'R')) break;
+    if (p >= (u8 *)__va(0xfffff))
+	return;
+    
+    pirq = r = (struct routing_table *)p;
+    printk(KERN_INFO "PCI routing table version %d.%d at %#06x\n",
+	   r->major, r->minor, (u32)r & 0xfffff);
+    pci_irq_mask |= r->pci_mask;
+
+    router_dev = router = pci_find_slot(r->bus, r->devfn);
+    if (router) {
+	for (i = 0; i < ROUTER_COUNT; i++) {
+	    if ((router->vendor == router_table[i].vendor) &&
+		(router->device == router_table[i].device))
+		break;
+	    if (((r->compat & 0xffff) == router_table[i].vendor) &&
+		((r->compat >> 16) == router_table[i].device))
+		break;
+	}
+	if (i == ROUTER_COUNT)
+	    printk(KERN_INFO "  unknown PCI interrupt router %04x:%04x\n",
+		   router->vendor, router->device);
+	else
+	    router_info = &router_table[i];
+    }
+
+    for (e = r->entry; (u8 *)e < p+r->size; e++) {
+	for (fn = 0; fn < 8; fn++) {
+	    dev = pci_find_slot(e->bus, e->devfn | fn);
+	    if ((dev == NULL) || (dev->irq != 0)) continue;
+	    pci_read_config_byte(dev, PCI_INTERRUPT_PIN, &pin);
+	    if ((pin == 0) || (pin == 255)) continue;
+	    if (router_info) {
+		dev->irq = router_info->xlate(router, e->pin[pin-1].link);
+	    } else {
+		/* Fallback: see if only one irq possible */
+		int map = e->pin[pin-1].irq_map;
+		if (map && (!(map & (map-1))))
+		    dev->irq = ffs(map)-1;
+	    }
+	    if (dev->irq) {
+		printk(KERN_INFO "  %02x:%02x.%1x -> irq %d\n",
+		       e->bus, PCI_SLOT(dev->devfn),
+		       PCI_FUNC(dev->devfn), dev->irq);
+		pci_write_config_byte(dev, PCI_INTERRUPT_LINE,
+				      dev->irq);
+	    }
+	}
+    }
+}
+
+#endif /* (LINUX_VERSION_CODE < VERSION(2,3,24)) && defined(__i386__) */
+
+/*======================================================================
+
+    PCI device enabler
+
+    This is not at all generic... it is mostly a hack to correctly
+    configure CardBus bridges.
+    
+======================================================================*/
+
+#if (LINUX_VERSION_CODE < VERSION(2,3,24))
+
+static int check_cb_mapping(u_int phys)
+{
+    /* A few sanity checks to validate the bridge mapping */
+    char *virt = ioremap(phys, 0x1000);
+    int ret = ((readb(virt+0x800+I365_IDENT) & 0x70) ||
+	       (readb(virt+0x800+I365_CSC) &&
+		readb(virt+0x800+I365_CSC) &&
+		readb(virt+0x800+I365_CSC)));
+    ret |= readl(virt+CB_SOCKET_FORCE);
+    ret |= (readl(virt+CB_SOCKET_STATE) >> 16) != 0x3000;
+    iounmap(virt);
+    return ret;
+}
+
+static void setup_cb_bridge(struct pci_dev *dev)
+{
+    u8 bus, sub;
+    u32 phys;
+    int i;
+
+    /* This is nasty, but where else can we put it? */
+    if (PCI_FUNC(dev->devfn) == 0) {
+	struct pci_dev *sib;
+	sib = pci_find_slot(dev->bus->number, dev->devfn+1);
+	if (sib) {
+	    u8 a, b;
+	    /* Check for bad PCI bus numbering */
+	    pci_read_config_byte(dev, CB_CARDBUS_BUS, &a);
+	    pci_read_config_byte(sib, CB_CARDBUS_BUS, &b);
+	    if (a == b) {
+		pci_write_config_byte(dev, CB_CARDBUS_BUS, 0);
+		pci_write_config_byte(sib, CB_CARDBUS_BUS, 0);
+	    }
+	}
+    }
+
+    /* Assign PCI bus numbers, if needed */
+    pci_read_config_byte(dev, CB_CARDBUS_BUS, &bus);
+    pci_read_config_byte(dev, CB_SUBORD_BUS, &sub);
+    if ((cb_bus_base > 0) || (bus == 0)) {
+	if (cb_bus_base <= 0) cb_bus_base = 0x20;
+	bus = cb_bus_base;
+	sub = cb_bus_base+cb_bus_step;
+	cb_bus_base += cb_bus_step+1;
+	pci_write_config_byte(dev, CB_CARDBUS_BUS, bus);
+	pci_write_config_byte(dev, CB_SUBORD_BUS, sub);
+    }
+
+#if (LINUX_VERSION_CODE >= VERSION(2,1,103))
+    /* Create pci_bus structure for the CardBus, if needed */
+    {
+	struct pci_bus *child, *parent = dev->bus;
+	for (child = parent->children; child; child = child->next)
+	    if (child->number == bus) break;
+	if (!child) {
+	    child = kmalloc(sizeof(struct pci_bus), GFP_KERNEL);
+	    memset(child, 0, sizeof(struct pci_bus));
+	    child->self = dev;
+	    child->primary = bus;
+	    child->number = child->secondary = bus;
+	    child->subordinate = sub;
+	    child->parent = parent;
+#if (LINUX_VERSION_CODE >= VERSION(2,3,15))
+	    child->ops = parent->ops;
+#endif
+	    child->next = parent->children;
+	    parent->children = child;
+	}
+    }
+#endif
+
+    /* Map the CardBus bridge registers, if needed */
+    pci_write_config_dword(dev, CB_LEGACY_MODE_BASE, 0);
+    pci_read_config_dword(dev, PCI_BASE_ADDRESS_0, &phys);
+    if ((phys == 0) || (cb_mem_base[0] != 0)) {
+	/* Make sure the bridge is awake so we can test it */
+	pci_set_power_state(dev, 0);
+	for (i = 0; i < sizeof(cb_mem_base)/sizeof(u_int); i++) {
+	    phys = cb_mem_base[i];
+	    if (phys == 0) continue;
+	    pci_write_config_dword(dev, PCI_BASE_ADDRESS_0, phys);
+	    if (check_cb_mapping(phys) == 0) break;
+	}
+	if (i == sizeof(cb_mem_base)/sizeof(u_int)) {
+	    pci_write_config_dword(dev, PCI_BASE_ADDRESS_0, 0);
+	} else {
+	    cb_mem_base[0] = cb_mem_base[i] + 0x1000;
+	}
+    }
+}
+
+#define CMD_DFLT (PCI_COMMAND_IO | PCI_COMMAND_MEMORY | \
+		  PCI_COMMAND_MASTER | PCI_COMMAND_WAIT)
+
+#ifdef __i386__
+
+static u8 pirq_init(struct pci_dev *router, struct pirq_pin *pin)
+{
+    u16 map = pin->irq_map;
+    u8 irq = 0;
+    if (pirq->pci_mask)
+	map &= pirq->pci_mask;
+    if (cb_pci_irq)
+	map = 1<<cb_pci_irq;
+    /* Be conservative: only init irq if the mask is unambiguous */
+    if (map && (!(map & (map-1)))) {
+	irq = ffs(map)-1;
+	router_info->init(router, pin->link, irq);
+	pci_irq_mask |= (1<<irq);
+    }
+    return irq;
+}
+
+static void setup_cb_bridge_irq(struct pci_dev *dev)
+{
+    struct slot_entry *e;
+    u8 pin;
+    u32 phys;
+    char *virt;
+
+    pci_read_config_byte(dev, PCI_INTERRUPT_PIN, &pin);
+    pci_read_config_dword(dev, PCI_BASE_ADDRESS_0, &phys);
+    if (!pin || !phys)
+	return;
+    virt = ioremap(phys, 0x1000);
+    if (virt) {
+	/* Disable any pending interrupt sources */
+	writel(0, virt+CB_SOCKET_MASK);
+	writel(-1, virt+CB_SOCKET_EVENT);
+	iounmap(virt);
+    }
+    for (e = pirq->entry; (u8 *)e < (u8 *)pirq + pirq->size; e++) {
+	if ((e->bus != dev->bus->number) ||
+	    (e->devfn != (dev->devfn & ~7)))
+	    continue;
+	dev->irq = pirq_init(router_dev, &e->pin[pin-1]);
+	pci_write_config_byte(dev, PCI_INTERRUPT_LINE, dev->irq);
+	break;
+    }
+}
+
+#endif
+
+int pci_enable_device(struct pci_dev *dev)
+{
+    pci_write_config_word(dev, PCI_COMMAND, CMD_DFLT);
+    if ((dev->class >> 8) == PCI_CLASS_BRIDGE_CARDBUS) {
+	setup_cb_bridge(dev);
+    }
+#ifdef __i386__
+    /* In certain cases, if the interrupt can be deduced, but was
+       unrouted when the pirq table was scanned, we'll try to set it
+       up now. */
+    if (!dev->irq && pirq && (router_info) &&
+	((dev->class >> 8) == PCI_CLASS_BRIDGE_CARDBUS)) {
+	setup_cb_bridge_irq(dev);
+    }
+#endif
+    return 0;
+}
+
+int pci_set_power_state(struct pci_dev *dev, int state)
+{
+    u8 a, b, pmcs;
+    pci_read_config_byte(dev, PCI_STATUS, &a);
+    if (a & PCI_STATUS_CAPLIST) {
+	pci_read_config_byte(dev, PCI_CB_CAPABILITY_POINTER, &b);
+	while (b != 0) {
+	    pci_read_config_byte(dev, b+PCI_CAPABILITY_ID, &a);
+	    if (a == PCI_CAPABILITY_PM) {
+		pmcs = b + PCI_PM_CONTROL_STATUS;
+		/* Make sure we're in D0 state */
+		pci_write_config_word(dev, pmcs, PCI_PMCS_PWR_STATE_D0);
+		break;
+	    }
+	    pci_read_config_byte(dev, b+PCI_NEXT_CAPABILITY, &b);
+	}
+    }
+    return 0;
+}
+
+#endif /* (LINUX_VERSION_CODE < VERSION(2,3,24)) */
+
+/*======================================================================
+
+    General setup and cleanup entry points
+
+======================================================================*/
+
+void pci_fixup_init(void)
+{
+    struct pci_dev *p;
+
+#if (LINUX_VERSION_CODE < VERSION(2,3,24)) && defined(__i386__)
+    scan_pirq_table();
+#endif
+
+    pci_for_each_dev(p)
+	pci_irq_mask |= (1<<p->irq);
+
+#ifdef __alpha__
+#define PIC 0x4d0
+    pci_irq_mask |= inb(PIC) | (inb(PIC+1) << 8);
+#endif
+}
+
+void pci_fixup_done(void)
+{
+#if (LINUX_VERSION_CODE < VERSION(2,1,0))
+    struct pci_dev *d, *dn;
+    struct pci_bus *b, *bn;
+    for (d = pci_devices; d; d = dn) {
+	dn = d->next;
+	kfree(d);
+    }
+    for (b = pci_root.next; b; b = bn) {
+	bn = b->next;
+	kfree(b);
+    }
+#endif
+}
Index: oldkernel/linux/pcmcia-cs-3.1.15/modules/pnp_bios.c
diff -u /dev/null linux/pcmcia-cs-3.1.15/modules/pnp_bios.c:1.1
--- /dev/null	Mon Jul 31 21:15:12 2000
+++ linux/pcmcia-cs-3.1.15/modules/pnp_bios.c	Fri Jul  7 16:34:58 2000
@@ -0,0 +1,538 @@
+/*
+ * PnP bios services
+ * 
+ * Originally (C) 1998 Christian Schmidt (chr.schmidt@tu-bs.de)
+ * Modifications (c) 1998 Tom Lees <tom@lpsg.demon.co.uk>
+ * Minor reorganizations by David Hinds <dhinds@pcmcia.sourceforge.org>
+ *
+ * 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, 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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ *   Reference:
+ *   Compaq Computer Corporation, Phoenix Technologies Ltd., Intel 
+ *   Corporation. 
+ *   Plug and Play BIOS Specification, Version 1.0A, May 5, 1994
+ *   Plug and Play BIOS Clarification Paper, October 6, 1994
+ *
+ */
+
+#include <pcmcia/config.h>
+#define __NO_VERSION__
+#include <pcmcia/k_compat.h>
+
+#include <linux/types.h>
+#include <linux/module.h>
+#include <linux/linkage.h>
+#include <linux/kernel.h>
+#include <linux/pnp_bios.h>
+#include <asm/page.h>
+#include <asm/system.h>
+#include <asm/desc.h>
+
+/* PnP bios signature: "$PnP" */
+#define PNP_SIGNATURE   (('$' << 0) + ('P' << 8) + ('n' << 16) + ('P' << 24))
+
+#ifdef MODULE
+static struct desc_struct *gdt;
+#endif
+
+/*
+ * This is the standard structure used to identify the entry point
+ * to the Plug and Play bios
+ */
+#pragma pack(1)
+union pnpbios {
+	struct {
+		u32 signature;    /* "$PnP" */
+		u8 version;	  /* in BCD */
+		u8 length;	  /* length in bytes, currently 21h */
+		u16 control;	  /* system capabilities */
+		u8 checksum;	  /* all bytes must add up to 0 */
+
+		u32 eventflag;    /* phys. address of the event flag */
+		u16 rmoffset;     /* real mode entry point */
+		u16 rmcseg;
+		u16 pm16offset;   /* 16 bit protected mode entry */
+		u32 pm16cseg;
+		u32 deviceID;	  /* EISA encoded system ID or 0 */
+		u16 rmdseg;	  /* real mode data segment */
+		u32 pm16dseg;	  /* 16 bit pm data segment base */
+	} fields;
+	char chars[0x21];	  /* To calculate the checksum */
+};
+#pragma pack()
+
+/*
+ * Local Variables
+ */
+static asmlinkage struct {
+	u32	offset;
+	u16	segment;
+} pnp_bios_callpoint;
+
+static union pnpbios * pnp_bios_inst_struc = NULL;
+
+/* The PnP entries in the GDT */
+#define PNP_GDT		0x0038
+#define PNP_CS32	(PNP_GDT+0x00)	/* segment for calling fn */
+#define PNP_CS16	(PNP_GDT+0x08)	/* code segment for bios */
+#define PNP_DS		(PNP_GDT+0x10)	/* data segment for bios */
+#define PNP_TS1		(PNP_GDT+0x18)	/* transfer data segment */
+#define PNP_TS2		(PNP_GDT+0x20)	/* another data segment */
+
+static struct desc_struct saved_gdt[5];
+static struct desc_struct pnp_gdt[] = {
+	{ 0, 0x00c09a00 },	/* 32-bit code */
+	{ 0, 0x00809a00 },	/* 16-bit code */
+	{ 0, 0x00809200 },	/* 16-bit data */
+	{ 0, 0x00809200 },	/* 16-bit data */
+	{ 0, 0x00809200 }	/* 16-bit data */
+};
+
+/*
+ * GDT abuse: since we want this to work when loaded as a module on a
+ * normal kernel, we drop the PnP GDT entries on top of the APM stuff
+ * and protect it with a spin lock (
+ */
+
+static long gdt_flags;
+#ifdef USE_SPIN_LOCKS
+static spinlock_t gdt_lock = SPIN_LOCK_UNLOCKED;
+#endif
+
+static void push_pnp_gdt(void)
+{
+	spin_lock_irqsave(&gdt_lock, gdt_flags);
+	memcpy(saved_gdt, &gdt[PNP_GDT >> 3], sizeof(saved_gdt));
+	memcpy(&gdt[PNP_GDT >> 3], pnp_gdt, sizeof(pnp_gdt));
+}
+
+static void pop_pnp_gdt(void)
+{
+	memcpy(pnp_gdt, &gdt[PNP_GDT >> 3], sizeof(pnp_gdt));
+	memcpy(&gdt[PNP_GDT >> 3], saved_gdt, sizeof(saved_gdt));
+	spin_unlock_irqrestore(&gdt_lock, gdt_flags);
+}
+
+/* 
+ * These are some opcodes for a "static asmlinkage"
+ * As this code is *not* executed inside the linux kernel segment, but in a
+ * alias at offset 0, we need a far return that can not be compiled by
+ * default (please, prove me wrong! this is *really* ugly!) 
+ * This is the only way to get the bios to return into the kernel code,
+ * because the bios code runs in 16 bit protected mode and therefore can only
+ * return to the caller if the call is within the first 64kB, and the linux
+ * kernel begins at offset 1MB...
+ */
+static asmlinkage u8 pnp_bios_callfunc[] =
+{
+	0x52,			              /* push edx */
+	0x51,			              /* push ecx */
+	0x53,			              /* push ebx */
+	0x50,			              /* push eax */
+	0x66, 0x9a, 0, 0,	              /* call far pnp_cs16:0, offset */
+	(PNP_CS16) & 0xff, (PNP_CS16) >> 8,   /* becomes fixed up later */
+	0x83, 0xc4, 0x10,	              /* add esp, 16 */
+	0xcb};			              /* retf */
+
+#define Q_SET_SEL(selname, address, size) \
+set_base (gdt [(selname) >> 3], __va((u32)(address))); \
+set_limit (gdt [(selname) >> 3], size)
+
+#define Q2_SET_SEL(selname, address, size) \
+set_base (gdt [(selname) >> 3], (u32)(address)); \
+set_limit (gdt [(selname) >> 3], size)
+
+/*
+ * Callable Functions
+ */
+#define PNP_GET_NUM_SYS_DEV_NODES       0x00
+#define PNP_GET_SYS_DEV_NODE            0x01
+#define PNP_SET_SYS_DEV_NODE            0x02
+#define PNP_GET_EVENT                   0x03
+#define PNP_SEND_MESSAGE                0x04
+#define PNP_GET_DOCKING_STATION_INFORMATION 0x05
+#define PNP_SET_STATIC_ALLOCED_RES_INFO 0x09
+#define PNP_GET_STATIC_ALLOCED_RES_INFO 0x0a
+#define PNP_GET_APM_ID_TABLE            0x0b
+#define PNP_GET_PNP_ISA_CONFIG_STRUC    0x40
+#define PNP_GET_ESCD_INFO               0x41
+#define PNP_READ_ESCD                   0x42
+#define PNP_WRITE_ESCD                  0x43
+
+/*
+ * Call pnp bios with function 0x00, "get number of system device nodes"
+ */
+int pnp_bios_dev_node_info(struct pnp_dev_node_info *data)
+{
+	u16 status;
+	if (!pnp_bios_present ())
+		return PNP_FUNCTION_NOT_SUPPORTED;
+	push_pnp_gdt();
+	Q2_SET_SEL(PNP_TS1, data, sizeof(struct pnp_dev_node_info));
+	__asm__ __volatile__
+          ("lcall %%cs:" SYMBOL_NAME_STR(pnp_bios_callpoint) "\n\t"
+           :"=a"(status)
+           :"a"(PNP_GET_NUM_SYS_DEV_NODES),
+             "b"((2 << 16) | PNP_TS1),
+             "c"((PNP_DS << 16) | PNP_TS1)
+           :"memory");
+	data->no_nodes &= 0xff;
+	pop_pnp_gdt();
+	return status;
+}
+
+/* 
+ * Call pnp bios with function 0x01, "get system device node"
+ * Input:  *nodenum=desired node, 
+ *         static=1: config (dynamic) config, else boot (static) config,
+ * Output: *nodenum=next node or 0xff if no more nodes
+ */
+int pnp_bios_get_dev_node(u8 *nodenum, char config, struct pnp_bios_node *data)
+{
+	u16 status;
+	if (!pnp_bios_present ())
+		return PNP_FUNCTION_NOT_SUPPORTED;
+	push_pnp_gdt();
+	Q2_SET_SEL(PNP_TS1, nodenum, sizeof(char));
+	Q2_SET_SEL(PNP_TS2, data, 64 * 1024);
+	__asm__ __volatile__
+          ("lcall %%cs:" SYMBOL_NAME_STR(pnp_bios_callpoint) "\n\t"
+           :"=a"(status)
+           :"a"(PNP_GET_SYS_DEV_NODE),
+            "b"(PNP_TS1),
+            "c"(((config ? 1 : 2) <<16) | PNP_TS2),
+            "d"(PNP_DS)
+           :"memory");
+	pop_pnp_gdt();
+	return status;
+}
+
+/*
+ * Call pnp bios with function 0x02, "set system device node"
+ * Input: nodenum=desired node, 
+ *        static=1: config (dynamic) config, else boot (static) config,
+ */
+int pnp_bios_set_dev_node(u8 nodenum, char config, struct pnp_bios_node *data)
+{
+	u16 status;
+	if (!pnp_bios_present ())
+		return PNP_FUNCTION_NOT_SUPPORTED;
+	push_pnp_gdt();
+	Q2_SET_SEL(PNP_TS1, data, /* *((u16 *) data)*/ 65536);
+	__asm__ __volatile__
+          ("lcall %%cs:" SYMBOL_NAME_STR(pnp_bios_callpoint) "\n\t"
+           :"=a"(status)
+           :"a"(((u32) nodenum << 16) |
+                PNP_SET_SYS_DEV_NODE),
+            "b"(PNP_TS1 << 16),
+            "c"((PNP_DS << 16) | (config ? 1 : 2))
+           :"memory");
+	pop_pnp_gdt();
+	return status;
+}
+
+/*
+ * Call pnp bios with function 0x03, "get event"
+ */
+#if needed
+int pnp_bios_get_event(u16 *event)
+{
+	u16 status;
+	if (!pnp_bios_present ())
+		return PNP_FUNCTION_NOT_SUPPORTED;
+	push_pnp_gdt();
+	Q2_SET_SEL(PNP_TS1, event, sizeof(u16));
+	__asm__ __volatile__
+          ("lcall %%cs:" SYMBOL_NAME_STR(pnp_bios_callpoint) "\n\t"
+           :"=a"(status)
+           :"a"(PNP_GET_EVENT),
+            "b"((PNP_DS << 16) | PNP_TS1)
+           :"memory");
+	pop_pnp_gdt();
+	return status;
+}
+#endif
+
+/* 
+ * Call pnp bios with function 0x04, "send message"
+ */
+#if needed
+int pnp_bios_send_message(u16 message)
+{
+	u16 status;
+	if (!pnp_bios_present ())
+		return PNP_FUNCTION_NOT_SUPPORTED;
+	push_pnp_gdt();
+	__asm__ __volatile__
+          ("lcall %%cs:" SYMBOL_NAME_STR(pnp_bios_callpoint) "\n\t"
+           :"=a"(status)
+           :"a"(((u32) message << 16) |
+                PNP_SEND_MESSAGE),
+            "b"(PNP_DS)
+           :"memory");
+	pop_pnp_gdt();
+	return status;
+}
+#endif
+
+/*
+ * Call pnp bios with function 0x05, "get docking station information"
+ */
+#if needed
+int pnp_bios_dock_station_info(struct pnp_docking_station_info *data)
+{
+	u16 status;
+	if (!pnp_bios_present ())
+		return PNP_FUNCTION_NOT_SUPPORTED;
+	push_pnp_gdt();
+	Q2_SET_SEL(PNP_TS1, data, sizeof(struct pnp_docking_station_info));
+	__asm__ __volatile__
+          ("lcall %%cs:" SYMBOL_NAME_STR(pnp_bios_callpoint) "\n\t"
+           :"=a"(status)
+           :"a"(PNP_GET_DOCKING_STATION_INFORMATION),
+            "b"((PNP_TS1 << 16) | PNP_DS)
+           :"memory");
+	pop_pnp_gdt();
+	return status;
+}
+#endif
+
+/*
+ * Call pnp bios with function 0x09, "set statically allocated resource
+ * information"
+ */
+#if needed
+int pnp_bios_set_stat_res(char *info)
+{
+	u16 status;
+	if (!pnp_bios_present ())
+		return PNP_FUNCTION_NOT_SUPPORTED;
+	push_pnp_gdt();
+	Q2_SET_SEL(PNP_TS1, info, *((u16 *) info));
+	__asm__ __volatile__
+          ("lcall %%cs:" SYMBOL_NAME_STR(pnp_bios_callpoint) "\n\t"
+           :"=a"(status)
+           :"a"(PNP_SET_STATIC_ALLOCED_RES_INFO),
+            "b"((PNP_TS1 << 16) | PNP_DS)
+           :"memory");
+	pop_pnp_gdt();
+	return status;
+}
+#endif
+
+/*
+ * Call pnp bios with function 0x0a, "get statically allocated resource
+ * information"
+ */
+#if needed
+int pnp_bios_get_stat_res(char *info)
+{
+	u16 status;
+	if (!pnp_bios_present ())
+		return PNP_FUNCTION_NOT_SUPPORTED;
+	push_pnp_gdt();
+	Q2_SET_SEL(PNP_TS1, info, 64 * 1024);
+	__asm__ __volatile__
+          ("lcall %%cs:" SYMBOL_NAME_STR(pnp_bios_callpoint) "\n\t"
+           :"=a"(status)
+           :"a"(PNP_GET_STATIC_ALLOCED_RES_INFO),
+            "b"((PNP_TS1 << 16) | PNP_DS)
+           :"memory");
+	pop_pnp_gdt();
+	return status;
+}
+#endif
+
+/*
+ * Call pnp bios with function 0x0b, "get APM id table"
+ */
+#if needed
+int pnp_bios_apm_id_table(char *table, u16 *size)
+{
+	u16 status;
+	if (!pnp_bios_present ())
+		return PNP_FUNCTION_NOT_SUPPORTED;
+	push_pnp_gdt();
+	Q2_SET_SEL(PNP_TS1, table, *size);
+	Q2_SET_SEL(PNP_TS2, size, sizeof(u16));
+	__asm__ __volatile__
+          ("lcall %%cs:" SYMBOL_NAME_STR(pnp_bios_callpoint) "\n\t"
+           :"=a"(status)
+           :"a"(PNP_GET_APM_ID_TABLE),
+            "b"(PNP_TS2),
+            "c"((PNP_DS << 16) | PNP_TS1)
+           :"memory");
+	pop_pnp_gdt();
+	return status;
+}
+#endif
+
+/*
+ * Call pnp bios with function 0x40, "get isa pnp configuration structure"
+ */
+#if needed
+int pnp_bios_isapnp_config(struct pnp_isa_config_struc *data)
+{
+	u16 status;
+	if (!pnp_bios_present ())
+		return PNP_FUNCTION_NOT_SUPPORTED;
+	push_pnp_gdt();
+	Q2_SET_SEL(PNP_TS1, data, sizeof(struct pnp_isa_config_struc));
+	__asm__ __volatile__
+          ("lcall %%cs:" SYMBOL_NAME_STR(pnp_bios_callpoint) "\n\t"
+           :"=a"(status)
+           :"a"(PNP_GET_PNP_ISA_CONFIG_STRUC),
+            "b"((PNP_DS << 16) | PNP_TS1)
+           :"memory");
+	pop_pnp_gdt();
+	return status;
+}
+#endif
+
+/*
+ * Call pnp bios with function 0x41, "get ESCD info"
+ */
+#if needed
+int pnp_bios_escd_info(struct escd_info_struc *data)
+{
+	u16 status;
+	if (!pnp_bios_present ())
+		return ESCD_FUNCTION_NOT_SUPPORTED;
+	push_pnp_gdt();
+	Q2_SET_SEL(PNP_TS1, data, sizeof(struct escd_info_struc));
+	__asm__ __volatile__
+          ("lcall %%cs:" SYMBOL_NAME_STR(pnp_bios_callpoint) "\n\t"
+           :"=a"(status)
+           :"a"(PNP_GET_ESCD_INFO),
+            "b"((2 << 16) | PNP_TS1),
+            "c"((4 << 16) | PNP_TS1),
+            "d"((PNP_DS << 16) | PNP_TS1)
+           :"memory");
+	pop_pnp_gdt();
+	return status;
+}
+#endif
+
+/*
+ * Call pnp bios function 0x42, "read ESCD"
+ * nvram_base is determined by calling escd_info
+ */
+#if needed
+int pnp_bios_read_escd(char *data, u32 nvram_base)
+{
+	u16 status;
+	if (!pnp_bios_present ())
+		return ESCD_FUNCTION_NOT_SUPPORTED;
+	push_pnp_gdt();
+	Q2_SET_SEL(PNP_TS1, data, 64 * 1024);
+	set_base(gdt[PNP_TS2 >> 3], nvram_base);
+	set_limit(gdt[PNP_TS2 >> 3], 64 * 1024);
+	__asm__ __volatile__
+          ("lcall %%cs:" SYMBOL_NAME_STR(pnp_bios_callpoint) "\n\t"
+           :"=a"(status)
+           :"a"(PNP_READ_ESCD),
+            "b"((PNP_TS2 << 16) | PNP_TS1),
+            "c"(PNP_DS)
+           :"memory");
+	pop_pnp_gdt();
+	return status;
+}
+#endif
+
+/*
+ * Call pnp bios function 0x43, "write ESCD"
+ */
+#if needed
+int pnp_bios_write_escd(char *data, u32 nvram_base)
+{
+	u16 status;
+	if (!pnp_bios_present ())
+		return ESCD_FUNCTION_NOT_SUPPORTED;
+	push_pnp_gdt();
+	Q2_SET_SEL(PNP_TS1, data, 64 * 1024);
+	set_base(gdt[PNP_TS2 >> 3], nvram_base);
+	set_limit(gdt[PNP_TS2 >> 3], 64 * 1024);
+	__asm__ __volatile__
+          ("lcall %%cs:" SYMBOL_NAME_STR(pnp_bios_callpoint) "\n\t"
+           :"=a"(status)
+           :"a"(PNP_WRITE_ESCD),
+            "b"((PNP_TS2 << 16) | PNP_TS1),
+            "c"(PNP_DS)
+           :"memory");
+	pop_pnp_gdt();
+	return status;
+}
+#endif
+
+int pnp_bios_present(void)
+{
+  return (pnp_bios_inst_struc != NULL);
+}
+
+/* 
+ * Searches the defined area (0xf0000-0xffff0) for a valid PnP BIOS
+ * structure and, if found one, sets up the selectors and entry points
+ */
+
+void pnp_bios_init(void)
+{
+	union pnpbios *check;
+	u8 sum;
+	int i, length;
+
+#ifdef MODULE
+	struct Xgt_desc_struct my_gdt_descr;
+	__asm__ __volatile__ ("sgdt %0" : : "m" (my_gdt_descr));
+	gdt = (struct desc_struct *)my_gdt_descr.address;
+#endif
+
+	for (check = (union pnpbios *) __va(0xf0000);
+	     check < (union pnpbios *) __va(0xffff0);
+	     ((void *) (check)) += 16) {
+		if (check->fields.signature != PNP_SIGNATURE)
+			continue;
+		length = check->fields.length;
+		if (!length)
+			continue;
+		for (sum = 0, i = 0; i < length; i++)
+			sum += check->chars[i];
+		if (sum)
+			continue;
+		if (check->fields.version < 0x10) {
+			printk(KERN_WARNING "PnP: unsupported version %d.%d",
+			       check->fields.version >> 4,
+			       check->fields.version & 15);
+			continue;
+		}
+		printk(KERN_INFO "PnP: PNP BIOS installation structure at 0x%p\n",
+		       check);
+		printk(KERN_INFO "PnP: PNP BIOS version %d.%d, entry at %x:%x, dseg at %x\n",
+                       check->fields.version >> 4, check->fields.version & 15,
+		       check->fields.pm16cseg, check->fields.pm16offset,
+		       check->fields.pm16dseg);
+		push_pnp_gdt();
+		Q2_SET_SEL(PNP_CS32, &pnp_bios_callfunc,
+			   sizeof(pnp_bios_callfunc));
+		Q_SET_SEL(PNP_CS16, check->fields.pm16cseg, 64 * 1024);
+		Q_SET_SEL(PNP_DS, check->fields.pm16dseg, 64 * 1024);
+		pop_pnp_gdt();
+		pnp_bios_callfunc[6] = check->fields.pm16offset & 0xff;
+		pnp_bios_callfunc[7] = check->fields.pm16offset >> 8;
+		pnp_bios_callpoint.offset = 0;
+		pnp_bios_callpoint.segment = PNP_CS32;
+		pnp_bios_inst_struc = check;
+		break;
+	}
+}
Index: oldkernel/linux/pcmcia-cs-3.1.15/modules/pnp_proc.c
diff -u /dev/null linux/pcmcia-cs-3.1.15/modules/pnp_proc.c:1.1
--- /dev/null	Mon Jul 31 21:15:12 2000
+++ linux/pcmcia-cs-3.1.15/modules/pnp_proc.c	Fri Jul  7 16:34:58 2000
@@ -0,0 +1,141 @@
+/*
+ * pnp_proc.c: /proc/bus/pnp interface for Plug and Play devices
+ *
+ * Written by David Hinds, dhinds@pcmcia.sourceforge.org
+ */
+
+#include <pcmcia/config.h>
+#define __NO_VERSION__
+#include <pcmcia/k_compat.h>
+
+#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/malloc.h>
+#include <linux/types.h>
+#include <linux/proc_fs.h>
+#include <linux/pnp_bios.h>
+
+static struct proc_dir_entry *proc_pnp = NULL;
+static struct proc_dir_entry *proc_pnp_boot = NULL;
+static struct pnp_dev_node_info node_info;
+
+static int proc_read_devices(char *buf, char **start, off_t pos,
+			     int count, int *eof, void *data)
+{
+	struct pnp_bios_node *node;
+	u8 num;
+	char *p = buf;
+
+	if (pos != 0) {
+	    *eof = 1;
+	    return 0;
+	}
+	node = kmalloc(node_info.max_node_size, GFP_KERNEL);
+	if (!node) return -ENOMEM;
+	for (num = 0; num != 0xff; ) {
+		pnp_bios_get_dev_node(&num, 0, node);
+		p += sprintf(p, "%02x\t%08x\t%02x:%02x:%02x\t%04x\n",
+			     node->handle, node->eisa_id,
+			     node->type_code[0], node->type_code[1],
+			     node->type_code[2], node->flags);
+	}
+	kfree(node);
+	return (p-buf);
+}
+
+static int proc_read_node(char *buf, char **start, off_t pos,
+			  int count, int *eof, void *data)
+{
+	struct pnp_bios_node *node;
+	int boot = (long)data >> 8;
+	u8 num = (long)data;
+	int len;
+
+	if (pos != 0) {
+	    *eof = 1;
+	    return 0;
+	}
+	node = kmalloc(node_info.max_node_size, GFP_KERNEL);
+	if (!node) return -ENOMEM;
+	pnp_bios_get_dev_node(&num, boot, node);
+	len = node->size - sizeof(struct pnp_bios_node);
+	memcpy(buf, node->data, len);
+	kfree(node);
+	return len;
+}
+
+static int proc_write_node(struct file *file, const char *buf,
+			   unsigned long count, void *data)
+{
+	struct pnp_bios_node *node;
+	int boot = (long)data >> 8;
+	u8 num = (long)data;
+
+	node = kmalloc(node_info.max_node_size, GFP_KERNEL);
+	if (!node) return -ENOMEM;
+	pnp_bios_get_dev_node(&num, boot, node);
+	if (count != node->size - sizeof(struct pnp_bios_node))
+		return -EINVAL;
+	memcpy(node->data, buf, count);
+	if (pnp_bios_set_dev_node(node->handle, boot, node) != 0)
+	    return -EINVAL;
+	kfree(node);
+	return count;
+}
+
+void pnp_proc_init(void)
+{
+	struct pnp_bios_node *node;
+	struct proc_dir_entry *ent;
+	char name[3];
+	u8 num;
+
+	if (!pnp_bios_present()) return;
+	if (pnp_bios_dev_node_info(&node_info) != 0)
+		return;
+	
+	proc_pnp = proc_mkdir("pnp", proc_bus);
+	if (!proc_pnp) return;
+	proc_pnp_boot = proc_mkdir("boot", proc_pnp);
+	if (!proc_pnp_boot) return;
+	create_proc_read_entry("devices", 0, proc_pnp,
+			       proc_read_devices, NULL);
+	
+	node = kmalloc(node_info.max_node_size, GFP_KERNEL);
+	if (!node) return;
+	for (num = 0; num != 0xff; ) {
+		sprintf(name, "%02x", num);
+		if (pnp_bios_get_dev_node(&num, 0, node) != 0)
+			break;
+		ent = create_proc_entry(name, 0, proc_pnp);
+		if (ent) {
+			ent->read_proc = proc_read_node;
+			ent->write_proc = proc_write_node;
+			ent->data = (void *)(long)(node->handle);
+		}
+		ent = create_proc_entry(name, 0, proc_pnp_boot);
+		if (ent) {
+			ent->read_proc = proc_read_node;
+			ent->write_proc = proc_write_node;
+			ent->data = (void *)(long)(node->handle+0x100);
+		}
+	}
+	kfree(node);
+}
+
+void pnp_proc_done(void)
+{
+	u8 num;
+	char name[3];
+	
+	if (!proc_pnp) return;
+	for (num = 0; num != 0xff; num++) {
+		sprintf(name, "%02x", num);
+		remove_proc_entry(name, proc_pnp);
+		remove_proc_entry(name, proc_pnp_boot);
+	}
+	remove_proc_entry("boot", proc_pnp);
+	remove_proc_entry("devices", proc_pnp);
+	remove_proc_entry("pnp", proc_bus);
+}
Index: oldkernel/linux/pcmcia-cs-3.1.15/modules/pnp_rsrc.c
diff -u /dev/null linux/pcmcia-cs-3.1.15/modules/pnp_rsrc.c:1.1
--- /dev/null	Mon Jul 31 21:15:12 2000
+++ linux/pcmcia-cs-3.1.15/modules/pnp_rsrc.c	Fri Jul  7 16:34:58 2000
@@ -0,0 +1,276 @@
+#include <pcmcia/config.h>
+#define __NO_VERSION__
+#include <pcmcia/k_compat.h>
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/string.h>
+#include <linux/malloc.h>
+#include <linux/ioport.h>
+#include <linux/pci.h>
+#include <linux/pnp_bios.h>
+#include <linux/pnp_resource.h>
+#include <asm/irq.h>
+
+/* From rsrc_mgr.c */
+void request_io_region(u_long base, u_long num, char *name);
+
+/*======================================================================
+
+    PnP interrupt table manager
+
+======================================================================*/
+
+struct irq_entry {
+    char *name;
+    struct irq_entry *next;
+};
+
+static struct irq_entry *irq[NR_IRQS];
+
+int proc_read_irq(char *buf, char **start, off_t pos,
+		  int count, int *eof, void *data)
+{
+    int i;
+    struct irq_entry *e;
+    char *p = buf;
+    for (i = 0; i < NR_IRQS; i++) {
+	if (!irq[i]) continue;
+	p += sprintf(p, "%3d:  ", i);
+	for (e = irq[i]; e; e = e->next) {
+	    strcpy(p, e->name);
+	    if (e->next)
+		strcat(p, ", ");
+	    p += strlen(p);
+	}
+	strcat(p, "\n");
+	p++;
+    }
+    return (p - buf);
+}
+
+void alloc_pnp_irq(int n, char *name)
+{
+    struct irq_entry **e = &irq[n];
+    while (*e != NULL)
+	e = &((*e)->next);
+    *e = kmalloc(sizeof(*e), GFP_KERNEL);
+    if (*e) {
+	(*e)->name = name;
+	(*e)->next = NULL;
+    }
+}
+
+int check_pnp_irq(int n)
+{
+    return (irq[n] ? -EBUSY : 0);
+}
+
+void free_pnp_irqs(void)
+{
+    int n;
+    struct irq_entry *e, *f;
+    for (n = 0; n < NR_IRQS; n++)
+	for (e = irq[n]; e; e = f) {
+	    f = e->next;
+	    kfree(e);
+	}
+}
+
+/*======================================================================
+
+    PCI device resource enumeration
+
+======================================================================*/
+
+#ifdef CONFIG_PCI
+
+static char *pci_names = NULL;
+
+static int pci_claim_resources(void)
+{
+    struct pci_dev *dev;
+    int r;
+    unsigned long flags;
+#if (LINUX_VERSION_CODE < VERSION(2,3,13))
+    unsigned long a;
+    u32 b, sz, idx;
+    u16 cmd, tmp;
+#endif
+    char *name;
+
+    r = 0; pci_for_each_dev(dev) r++;
+    name = pci_names = kmalloc(r*12, GFP_KERNEL);
+    if (!name) return -ENOMEM;
+    
+    save_flags(flags);
+    cli();
+    pci_for_each_dev(dev) {
+	if (dev->hdr_type != PCI_HEADER_TYPE_NORMAL)
+	    continue;
+	sprintf(name, "pci %02x:%02x.%1x", dev->bus->number,
+		PCI_SLOT(dev->devfn), PCI_FUNC(dev->devfn));
+	if (dev->irq)
+	    alloc_pnp_irq(dev->irq, name);
+#if (LINUX_VERSION_CODE < VERSION(2,3,13))
+	/* Disable IO and memory while we fiddle */
+	pci_read_config_word(dev, PCI_COMMAND, &cmd);
+	tmp = cmd & ~(PCI_COMMAND_IO | PCI_COMMAND_MEMORY);
+	pci_write_config_word(dev, PCI_COMMAND, tmp);
+	for (idx = 0; idx < 6; idx++) {
+	    a = dev->base_address[idx];
+	    r = PCI_BASE_ADDRESS_0 + 4*idx;
+	    if (((a & PCI_BASE_ADDRESS_SPACE_IO) &&
+		 !(a & PCI_BASE_ADDRESS_IO_MASK)) ||
+		!(a & PCI_BASE_ADDRESS_MEM_MASK))
+		continue;
+	    pci_read_config_dword(dev, r, &b);
+	    pci_write_config_dword(dev, r, ~0);
+	    pci_read_config_dword(dev, r, &sz);
+	    pci_write_config_dword(dev, r, b);
+	    if (a & PCI_BASE_ADDRESS_SPACE_IO) {
+		a &= PCI_BASE_ADDRESS_IO_MASK;
+		sz = (~(sz & PCI_BASE_ADDRESS_IO_MASK))+1;
+		sz &= 0xffff;
+		if (sz <= 0x100)
+		    request_io_region(a, sz, name);
+	    } else {
+		a &= PCI_BASE_ADDRESS_MEM_MASK;
+		sz = (~(sz & PCI_BASE_ADDRESS_MEM_MASK))+1;
+		request_mem_region(a, sz, name);
+	    }
+	}
+	if (dev->rom_address & ~1) {
+	    r = PCI_ROM_ADDRESS;
+	    pci_read_config_dword(dev, r, &b);
+	    pci_write_config_dword(dev, r, ~0);
+	    pci_read_config_dword(dev, r, &sz);
+	    pci_write_config_dword(dev, r, b);
+	    sz = (~(sz & ~1))+1;
+	    request_mem_region(dev->rom_address & ~1, sz, name);
+	}
+	pci_write_config_word(dev, PCI_COMMAND, cmd);
+#endif
+	name += 12;
+    }
+    restore_flags(flags);
+    return 0;
+}
+
+#endif /* CONFIG_PCI */
+
+/*======================================================================
+
+    PnP device resource enumeration
+    
+======================================================================*/
+
+#define flip16(n)	le16_to_cpu(n)
+#define flip32(n)	le32_to_cpu(n)
+
+static struct pnp_dev_node_info node_info;
+
+static void pnp_scan_node(char *name, u8 *buf, int len)
+{
+    union pnp_resource *p = (union pnp_resource *)buf;
+    int tag = 0, sz;
+    
+    while (((u8 *)p < buf+len) && (tag != PNP_RES_SMTAG_END)) {
+	if (p->lg.tag & PNP_RES_LARGE_ITEM) {
+	    
+	    union pnp_large_resource *r = &p->lg.d;
+	    tag = p->lg.tag & ~PNP_RES_LARGE_ITEM;
+	    sz = flip16(p->lg.sz) + 3;
+	    switch (tag) {
+	    case PNP_RES_LGTAG_MEM:
+		if (r->mem.len && (r->mem.min == r->mem.max))
+		    request_mem_region(flip16(r->mem.min)<<8,
+				       flip16(r->mem.len), name);
+		break;
+	    case PNP_RES_LGTAG_MEM32:
+		if (r->mem32.len && (r->mem32.min == r->mem32.max))
+		    request_mem_region(flip32(r->mem32.min),
+				       flip32(r->mem32.len), name);
+		break;
+	    case PNP_RES_LGTAG_MEM32_FIXED:
+		if (r->mem32_fixed.len)
+		    request_mem_region(flip32(r->mem32_fixed.base),
+				       flip32(r->mem32_fixed.len), name);
+		break;
+	    }
+	    
+	} else {
+	    
+	    union pnp_small_resource *r = &p->sm.d;
+	    tag = (p->sm.tag >> 3); sz = (p->sm.tag & 7) + 1;
+	    switch (tag) {
+	    case PNP_RES_SMTAG_IRQ:
+		if (r->irq.mask && !(r->irq.mask & (r->irq.mask-1)))
+		    alloc_pnp_irq(ffs(flip16(r->irq.mask))-1, name);
+		break;
+	    case PNP_RES_SMTAG_IO:
+		if (r->io.len && (r->io.min == r->io.max))
+		    request_io_region(flip16(r->io.min),
+				      r->io.len, name);
+		break;
+	    case PNP_RES_SMTAG_IO_FIXED:
+		if (r->io_fixed.len)
+		    request_io_region(flip16(r->io_fixed.base),
+				      r->io_fixed.len, name);
+		break;
+	    }
+	    
+	}
+	(u8 *)p += sz;
+    }
+}
+
+static char *pnp_names = NULL;
+
+static int pnp_claim_resources(void)
+{
+    struct pnp_bios_node *node;
+    char *name;
+    u8 num;
+    
+    node = kmalloc(node_info.max_node_size, GFP_KERNEL);
+    if (!node) return -ENOMEM;
+    pnp_names = kmalloc(node_info.no_nodes*7, GFP_KERNEL);
+    if (!pnp_names) {
+	kfree(node);
+	return -ENOMEM;
+    }
+    for (name = pnp_names, num = 0; num != 0xff; name += 7) {
+	pnp_bios_get_dev_node(&num, 0, node);
+	sprintf(name, "pnp %02x", node->handle);
+	pnp_scan_node(name, node->data, node->size - sizeof(*node));
+    }
+    kfree(node);
+    return 0;
+}
+
+/*====================================================================*/
+
+void pnp_rsrc_init(void)
+{
+#ifdef CONFIG_PCI
+    if (pcibios_present())
+	pci_claim_resources();
+#endif
+    if (pnp_bios_present()) {
+	if ((pnp_bios_dev_node_info(&node_info) == 0) &&
+	    (node_info.no_nodes > 0))
+	    pnp_claim_resources();
+    }
+}
+
+void pnp_rsrc_done(void)
+{
+    if (pnp_names)
+	kfree(pnp_names);
+    free_pnp_irqs();
+#ifdef CONFIG_PCI
+    if (pci_names)
+	kfree(pci_names);
+#endif
+}
Index: oldkernel/linux/pcmcia-cs-3.1.15/modules/ricoh.h
diff -u /dev/null linux/pcmcia-cs-3.1.15/modules/ricoh.h:1.1
--- /dev/null	Mon Jul 31 21:15:12 2000
+++ linux/pcmcia-cs-3.1.15/modules/ricoh.h	Fri Jul  7 16:34:58 2000
@@ -0,0 +1,140 @@
+/*
+ * ricoh.h 1.10 2000/04/24 21:19: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@pcmcia.sourceforge.org>.  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
+
+/* Data structure for tracking vendor-specific state */
+typedef struct ricoh_state_t {
+    u_short		misc;		/* RL5C4XX_MISC */
+    u_short		ctl;		/* RL5C4XX_16BIT_CTL */
+    u_short		io;		/* RL5C4XX_16BIT_IO_0 */
+    u_short		mem;		/* RL5C4XX_16BIT_MEM_0 */
+} ricoh_state_t;
+
+#endif /* _LINUX_RICOH_H */
Index: oldkernel/linux/pcmcia-cs-3.1.15/modules/rsrc_mgr.c
diff -u /dev/null linux/pcmcia-cs-3.1.15/modules/rsrc_mgr.c:1.1
--- /dev/null	Mon Jul 31 21:15:12 2000
+++ linux/pcmcia-cs-3.1.15/modules/rsrc_mgr.c	Fri Jul  7 16:34:58 2000
@@ -0,0 +1,928 @@
+/*======================================================================
+
+    Resource management routines
+
+    rsrc_mgr.c 1.77 1999/11/16 03:32: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@pcmcia.sourceforge.org>.  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 <pcmcia/config.h>
+#define __NO_VERSION__
+#include <pcmcia/k_compat.h>
+
+#ifdef __LINUX__
+#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/init.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>
+#endif
+
+#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
+
+/*======================================================================
+
+    Linux resource management extensions
+    
+======================================================================*/
+
+#ifdef __LINUX__
+
+#ifndef CONFIG_PNP_BIOS
+#define check_io_region(b,n) (0)
+#endif
+
+#if defined(CONFIG_PNP_BIOS) || !defined(HAVE_MEMRESERVE)
+
+#ifdef USE_SPIN_LOCKS
+static spinlock_t rsrc_lock = SPIN_LOCK_UNLOCKED;
+#endif
+
+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 */
+#ifdef CONFIG_PNP_BIOS
+static resource_entry_t io_list = { 0, 0, NULL, NULL };
+#endif
+#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);
+    if (!entry) return -ENOMEM;
+    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;
+}
+
+#ifdef CONFIG_PNP_BIOS
+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 HAS_PROC_BUS
+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
+#endif
+
+#ifndef HAVE_MEMRESERVE
+int check_mem_region(u_long base, u_long num)
+{
+    return check_my_resource(&mem_list, base, num);
+}
+void request_mem_region(u_long base, u_long num, char *name)
+{
+    register_my_resource(&mem_list, base, num, name);
+}
+void release_mem_region(u_long base, u_long num)
+{
+    release_my_resource(&mem_list, base, num);
+}
+#ifdef HAS_PROC_BUS
+int proc_read_mem(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 = mem_list.next; r; r = r->next)
+	p += sprintf(p, "%08lx-%08lx : %s\n", r->base,
+		     r->base+r->num-1, r->name);
+    spin_unlock_irqrestore(&rsrc_lock, flags);
+    return (p - buf);
+}
+#endif
+#endif
+
+#endif /* defined(CONFIG_PNP_BIOS) || !defined(HAVE_MEMRESERVE) */
+#endif /* __LINUX__ */
+
+#ifdef __BEOS__
+
+/*======================================================================
+
+    BeOS resource management functions
+    
+======================================================================*/
+
+#include "config_manager.h"
+#include "config_manager_p.h"
+
+typedef struct possible_device_configurations pdc_t;
+typedef struct device_configuration dc_t;
+typedef resource_descriptor rd_t;
+
+int register_resource(int type, u_long base, u_long num)
+{
+    pdc_t *p = malloc(sizeof(pdc_t)+sizeof(dc_t)+sizeof(rd_t));
+    dc_t *c = &p->possible[0];
+    rd_t *r = &c->resources[0];
+    dc_t *got;
+    int ret;
+    p->num_possible = 1;
+    c->flags = 0; c->num_resources = 1;
+    r->type = type;
+    if (type == B_IRQ_RESOURCE) {
+	r->d.m.mask = 1<<base;
+	r->d.m.flags = r->d.m.cookie = 0;
+    } else {
+	r->d.r.minbase = r->d.r.maxbase = base; r->d.r.len = num;
+	r->d.r.basealign = 1; r->d.r.flags = r->d.r.cookie = 0;
+    }
+    ret = cm->assign_configuration(p, &got);
+    if (ret == 0) free(got);
+    free(p);
+    return ret;
+}
+
+int release_resource(int type, u_long base, u_long num)
+{
+    dc_t *c = malloc(sizeof(dc_t)+sizeof(rd_t));
+    rd_t *r = &c->resources[0];
+    int ret;
+    c->flags = 0; c->num_resources = 1;
+    r->type = type;
+    if (type == B_IRQ_RESOURCE) {
+	r->d.m.mask = 1<<base;
+	r->d.m.flags = r->d.m.cookie = 0;
+    } else {
+	r->d.r.minbase = r->d.r.maxbase = base; r->d.r.len = num;
+	r->d.r.basealign = 1; r->d.r.flags = r->d.r.cookie = 0;
+    }
+    ret = cm->unassign_configuration(c);
+    free(c);
+    return ret;
+}
+
+int check_resource(int type, u_long base, u_long num)
+{
+    int ret = register_resource(type, base, num);
+    if (ret == B_OK) release_resource(type, base, num);
+    return ret;
+}
+
+#endif /* __BEOS__ */
+
+/*======================================================================
+
+    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);
+    if (!q) return CS_OUT_OF_RESOURCE;
+    q->base = base; q->num = num;
+    q->next = p->next; p->next = q;
+    return CS_SUCCESS;
+}
+
+/*====================================================================*/
+
+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);
+		if (!p) return CS_OUT_OF_RESOURCE;
+		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 CS_SUCCESS;
+}
+
+/*======================================================================
+
+    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);
+    ACQUIRE_RESOURCE_LOCK;
+    
+    /* 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");
+    RELEASE_RESOURCE_LOCK;
+}
+#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);
+    ACQUIRE_RESOURCE_LOCK;
+    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");
+    RELEASE_RESOURCE_LOCK;
+    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.
+
+    The 'align' field should reflect the number of bits of address
+    that need to be preserved from the initial value of *base.  It
+    should be a power of two, greater than or equal to 'num'.  A value
+    of 0 means that all bits of *base are significant.  *base should
+    also be strictly less than 'align'.
+    
+======================================================================*/
+
+int find_io_region(ioaddr_t *base, ioaddr_t num, ioaddr_t align,
+		   char *name)
+{
+    ioaddr_t try;
+    resource_map_t *m;
+    
+    ACQUIRE_RESOURCE_LOCK;
+    for (m = io_db.next; m != &io_db; m = m->next) {
+	try = (m->base & ~(align-1)) + *base;
+	for (try = (try >= m->base) ? try : try+align;
+	     (try >= m->base) && (try+num <= m->base+m->num);
+	     try += align) {
+	    if ((check_region(try, num) == 0) &&
+		(check_io_region(try, num) == 0)) {
+		*base = try;
+		request_region(try, num, name);
+		RELEASE_RESOURCE_LOCK;
+		return 0;
+	    }
+	    if (!align) break;
+	}
+    }
+    RELEASE_RESOURCE_LOCK;
+    return -1;
+}
+
+int find_mem_region(u_long *base, u_long num, u_long align,
+		    int force_low, char *name)
+{
+    u_long try;
+    resource_map_t *m;
+
+    ACQUIRE_RESOURCE_LOCK;
+    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;
+	    try = (m->base & ~(align-1)) + *base;
+	    for (try = (try >= m->base) ? try : try+align;
+		 (try >= m->base) && (try+num <= m->base+m->num);
+		 try += align) {
+		if (check_mem_region(try, num) == 0) {
+		    request_mem_region(try, num, name);
+		    *base = try;
+		    RELEASE_RESOURCE_LOCK;
+		    return 0;
+		}
+		if (!align) break;
+	    }
+	}
+	if (force_low) break;
+	force_low++;
+    }
+    RELEASE_RESOURCE_LOCK;
+    return -1;
+}
+
+/*======================================================================
+
+    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
+
+#ifdef __LINUX__
+static void fake_irq 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;
+}
+#endif
+
+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;
+}
+
+#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, ret;
+
+    base = adj->resource.memory.Base;
+    num = adj->resource.memory.Size;
+    if ((num == 0) || (base+num-1 < base))
+	return CS_BAD_SIZE;
+
+    ret = CS_SUCCESS;
+    switch (adj->Action) {
+    case ADD_MANAGED_RESOURCE:
+	ret = add_interval(&mem_db, base, num);
+	break;
+    case REMOVE_MANAGED_RESOURCE:
+	ret = sub_interval(&mem_db, base, num);
+	if (ret == CS_SUCCESS) {
+	    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:
+	ret = CS_UNSUPPORTED_FUNCTION;
+    }
+    
+    return ret;
+}
+
+/*====================================================================*/
+
+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;
+}
+
+/*====================================================================*/
+
+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;
+}
+
+/*====================================================================*/
+
+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;
+}
+
+/*====================================================================*/
+
+void release_resource_db(void)
+{
+    resource_map_t *p, *q;
+#if defined(CONFIG_PNP_BIOS) || !defined(HAVE_MEMRESERVE)
+    resource_entry_t *u, *v;
+#endif
+    
+    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);
+    }
+#ifdef CONFIG_PNP_BIOS
+    for (u = io_list.next; u; u = v) {
+	v = u->next;
+	kfree(u);
+    }
+#endif
+#ifndef HAVE_MEMRESERVE
+    for (u = mem_list.next; u; u = v) {
+	v = u->next;
+	kfree(u);
+    }
+#endif
+}
Index: oldkernel/linux/pcmcia-cs-3.1.15/modules/rsrc_mgr.h
diff -u /dev/null linux/pcmcia-cs-3.1.15/modules/rsrc_mgr.h:1.1
--- /dev/null	Mon Jul 31 21:15:12 2000
+++ linux/pcmcia-cs-3.1.15/modules/rsrc_mgr.h	Fri Jul  7 16:34:58 2000
@@ -0,0 +1,39 @@
+/*
+ * rsrc_mgr.h 1.19 1999/10/25 20:03: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@pcmcia.sourceforge.org>.  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 */
Index: oldkernel/linux/pcmcia-cs-3.1.15/modules/smc34c90.h
diff -u /dev/null linux/pcmcia-cs-3.1.15/modules/smc34c90.h:1.1
--- /dev/null	Mon Jul 31 21:15:12 2000
+++ linux/pcmcia-cs-3.1.15/modules/smc34c90.h	Fri Jul  7 16:34:58 2000
@@ -0,0 +1,52 @@
+/*
+ * smc34c90.h 1.7 1999/10/25 20:03: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@pcmcia.sourceforge.org>.  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 */
Index: oldkernel/linux/pcmcia-cs-3.1.15/modules/tcic.c
diff -u /dev/null linux/pcmcia-cs-3.1.15/modules/tcic.c:1.1
--- /dev/null	Mon Jul 31 21:15:12 2000
+++ linux/pcmcia-cs-3.1.15/modules/tcic.c	Fri Jul  7 16:34:58 2000
@@ -0,0 +1,952 @@
+/*======================================================================
+
+    Device driver for Databook TCIC-2 PCMCIA controller
+
+    tcic.c 1.115 2000/05/10 19:30:15
+
+    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@pcmcia.sourceforge.org>.  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 <pcmcia/config.h>
+#include <pcmcia/k_compat.h>
+
+#include <linux/module.h>
+#include <linux/init.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 <linux/pci.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.115 2000/05/10 19:30:15 (David Hinds)";
+#define DEBUG(n, args...) if (pc_debug>(n)) printk(KERN_DEBUG args)
+#else
+#define DEBUG(n, args...)
+#endif
+
+MODULE_AUTHOR("David Hinds <dhinds@pcmcia.sourceforge.org>");
+MODULE_DESCRIPTION("Databook TCIC-2 PCMCIA socket driver");
+
+/*====================================================================*/
+
+/* 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 int sockets;
+static socket_info_t socket_table[2];
+static struct timer_list poll_timer = { function: tcic_timer };
+
+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 __init irq_count(int irq, void *dev, struct pt_regs *regs)
+{
+    irq_hits++;
+}
+
+static u_int __init try_irq(int irq)
+{
+    u_short cfg;
+
+    irq_hits = 0;
+    if (request_irq(irq, irq_count, 0, "irq scan", irq_count) != 0)
+	return -1;
+    mdelay(10);
+    if (irq_hits) {
+	free_irq(irq, irq_count);
+	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, irq_count);
+
+    /* 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 __init irq_scan(u_int mask0)
+{
+    u_int mask1;
+    int i;
+
+#ifdef CONFIG_PCI
+    mask0 &= ~pci_irq_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", irq_count) == 0)) {
+		mask1 |= (1 << i);
+		free_irq(i, irq_count);
+	    }
+	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 __init 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 __init 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;
+}
+
+/*====================================================================*/
+
+static int __init init_tcic(void)
+{
+    int i, sock;
+    u_int mask, scan;
+    servinfo_t serv;
+
+    DEBUG(0, "%s\n", version);
+    CardServices(GetCardServicesInfo, &serv);
+    if (serv.Revision != CS_RELEASE_CODE) {
+	printk(KERN_NOTICE "tcic: Card Services release "
+	       "does not match!\n");
+	return -1;
+    }
+    
+    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);
+    }
+    
+    /* 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",
+			     tcic_interrupt) == 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, tcic_interrupt);
+	return -ENODEV;
+    }
+
+    return 0;
+    
+} /* init_tcic */
+
+/*====================================================================*/
+
+static void __exit exit_tcic(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, tcic_interrupt);
+    }
+    del_timer(&poll_timer);
+    restore_flags(flags);
+    release_region(tcic_base, 16);
+} /* exit_tcic */
+
+/*====================================================================*/
+
+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;
+	}
+	DEBUG(1, "tcic: socket %d event 0x%04x\n", i, events);
+	if (events)
+	    socket_table[i].handler(socket_table[i].info, events);
+    }
+
+    /* Schedule next poll, if needed */
+    if (((cs_irq == 0) || quick) && !timer_pending(&poll_timer)) {
+	poll_timer.expires = jiffies + (quick ? poll_quick : poll_interval);
+	add_timer(&poll_timer);
+    }
+    active = 0;
+    
+    DEBUG(2, "tcic: interrupt done\n");
+    
+} /* tcic_interrupt */
+
+static void tcic_timer(u_long data)
+{
+    DEBUG(2, "tcic: tcic_timer()\n");
+    tcic_interrupt(0, NULL, NULL);
+}
+
+/*====================================================================*/
+
+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(3, "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(3, "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(3, "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(3, "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)
+{
+    return (cmd < NFUNC) ? service_table[cmd](lsock, arg) : -EINVAL; 
+}
+
+/*====================================================================*/
+
+module_init(init_tcic);
+module_exit(exit_tcic);
Index: oldkernel/linux/pcmcia-cs-3.1.15/modules/tcic.h
diff -u /dev/null linux/pcmcia-cs-3.1.15/modules/tcic.h:1.1
--- /dev/null	Mon Jul 31 21:15:12 2000
+++ linux/pcmcia-cs-3.1.15/modules/tcic.h	Fri Jul  7 16:34:58 2000
@@ -0,0 +1,266 @@
+/*
+ * tcic.h 1.13 1999/10/25 20:03: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@pcmcia.sourceforge.org>.  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 */
Index: oldkernel/linux/pcmcia-cs-3.1.15/modules/ti113x.h
diff -u /dev/null linux/pcmcia-cs-3.1.15/modules/ti113x.h:1.1
--- /dev/null	Mon Jul 31 21:15:12 2000
+++ linux/pcmcia-cs-3.1.15/modules/ti113x.h	Fri Jul  7 16:34:58 2000
@@ -0,0 +1,191 @@
+/*
+ * ti113x.h 1.21 2000/05/10 18:22:11
+ *
+ * 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@pcmcia.sourceforge.org>.  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_1031
+#define PCI_DEVICE_ID_TI_1031		0xac13
+#endif
+#ifndef PCI_DEVICE_ID_TI_1131
+#define PCI_DEVICE_ID_TI_1131		0xac15
+#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_1410
+#define PCI_DEVICE_ID_TI_1410		0xac50
+#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_P2CCLK		0x08000000
+#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))
+
+/* Data structure for tracking vendor-specific state */
+typedef struct ti113x_state_t {
+    u_int		sysctl;		/* TI113X_SYSTEM_CONTROL */
+    u_char		cardctl;	/* TI113X_CARD_CONTROL */
+    u_char		devctl;		/* TI113X_DEVICE_CONTROL */
+    u_char		diag;		/* TI1250_DIAGNOSTIC */
+} ti113x_state_t;
+
+#endif /* _LINUX_TI113X_H */
Index: oldkernel/linux/pcmcia-cs-3.1.15/modules/topic.h
diff -u /dev/null linux/pcmcia-cs-3.1.15/modules/topic.h:1.1
--- /dev/null	Mon Jul 31 21:15:12 2000
+++ linux/pcmcia-cs-3.1.15/modules/topic.h	Fri Jul  7 16:34:59 2000
@@ -0,0 +1,107 @@
+/*
+ * topic.h 1.11 2000/04/24 21:19: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@pcmcia.sourceforge.org>.  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$ 2000/04/24 21:19:49
+ */
+
+#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
+#ifndef PCI_DEVICE_ID_TOSHIBA_TOPIC100
+#define PCI_DEVICE_ID_TOSHIBA_TOPIC100	0x0617
+#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
+
+/* Data structure for tracking vendor-specific state */
+typedef struct topic_state_t {
+    u_char		slot;		/* TOPIC_SLOT_CONTROL */
+    u_char		ccr;		/* TOPIC_CARD_CONTROL */
+    u_char		cdr;		/* TOPIC_CARD_DETECT */
+    u_int		rcr;		/* TOPIC_REGISTER_CONTROL */
+} topic_state_t;
+
+#endif /* _LINUX_TOPIC_H */
Index: oldkernel/linux/pcmcia-cs-3.1.15/modules/vg468.h
diff -u /dev/null linux/pcmcia-cs-3.1.15/modules/vg468.h:1.1
--- /dev/null	Mon Jul 31 21:15:12 2000
+++ linux/pcmcia-cs-3.1.15/modules/vg468.h	Fri Jul  7 16:34:59 2000
@@ -0,0 +1,112 @@
+/*
+ * vg468.h 1.12 2000/04/24 21:19: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@pcmcia.sourceforge.org>.  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 */
+
+/* Data structure for tracking vendor-specific state */
+typedef struct vg46x_state_t {
+    u_char		ctl;		/* VG468_CTL */
+    u_char		ema;		/* VG468_EXT_MODE_A */
+} vg46x_state_t;
+
+#endif /* _LINUX_VG468_H */
Index: oldkernel/linux/pcmcia-cs-3.1.15/modules/yenta.h
diff -u /dev/null linux/pcmcia-cs-3.1.15/modules/yenta.h:1.1
--- /dev/null	Mon Jul 31 21:15:12 2000
+++ linux/pcmcia-cs-3.1.15/modules/yenta.h	Fri Jul  7 16:34:59 2000
@@ -0,0 +1,156 @@
+/*
+ * yenta.h 1.18 2000/02/06 06:57: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@pcmcia.sourceforge.org>.  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_CCD			0x00000006
+#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_CCD			0x00000006
+#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_VSENSE			0x00003c86
+#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 */
Index: oldkernel/linux/pcmcia-cs-3.1.15/wireless/Makefile
diff -u /dev/null linux/pcmcia-cs-3.1.15/wireless/Makefile:1.1
--- /dev/null	Mon Jul 31 21:15:12 2000
+++ linux/pcmcia-cs-3.1.15/wireless/Makefile	Fri Jul  7 16:34:59 2000
@@ -0,0 +1,41 @@
+#
+# Copyright (C) 1998 David A. Hinds -- dhinds@pcmcia.sourceforge.org
+#
+# Makefile 1.6 2000/04/29 02:00:34
+#
+
+# Include site dependent options and kernel configuration
+include ../config.mk
+
+# Don't remove "-O3" or bad things will happen!
+CFLAGS = -O3 -Wall -Wstrict-prototypes -pipe
+CPPFLAGS += $(PCDEBUG) -D__KERNEL__ -DMODULE
+
+CC += $(AFLAGS) $(KFLAGS)
+
+XFLAGS = $(CFLAGS) $(CPPFLAGS) $(MFLAG)
+
+MODULES = netwave_cs.o wavelan_cs.o ray_cs.o wvlan_cs.o airo_cs.o airo.o
+SRCS    = netwave_cs.c wavelan_cs.c ray_cs.c airo_cs.c airo.c \
+	  wvlan_cs.c wvlan_hcf.c wvlan_hcfio.c \
+
+all:	$(MODULES)
+
+wvlan_hcf.o wvlan_hcfio.o: %.o: %.c
+	$(CC) -MD -c $(XFLAGS) $<
+	@mkdir -p .depfiles ; mv $*.d .depfiles
+
+wvlan_cs.o: wvlan_cs.c wvlan_hcf.o wvlan_hcfio.o
+	$(CC) -c -MD $(CFLAGS) $(CPPFLAGS) $< -o .$@
+	@mkdir -p .depfiles ; mv $*.d .depfiles
+	$(LD) -r -o $@ .$@ wvlan_hcf.o wvlan_hcfio.o
+	rm -f .$@ ; chmod -x $@
+
+clean:
+	rm -f core core.* *.o .*.o *.s *.a *~ .depend .depfiles/*.d
+
+install: $(MODULES)
+	@mkdir -p $(PREFIX)$(MODDIR)/pcmcia
+	cp $(MODULES) $(PREFIX)$(MODDIR)/pcmcia
+
+include ../rules.mk
Index: oldkernel/linux/pcmcia-cs-3.1.15/wireless/airo.c
diff -u /dev/null linux/pcmcia-cs-3.1.15/wireless/airo.c:1.1
--- /dev/null	Mon Jul 31 21:15:12 2000
+++ linux/pcmcia-cs-3.1.15/wireless/airo.c	Fri Jul  7 16:34:59 2000
@@ -0,0 +1,2680 @@
+/*======================================================================
+
+    Aironet driver for 4500 and 4800 series cards
+
+    The contents of this file are subject to the Mozilla Public
+    License Version 1.0 (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.
+
+    This code was developed by Benjamin Reed <breed@almaden.ibm.com>
+    including portions of which come from the Aironet PC4500
+    Developer's Reference Manual and used with permission.  Copyright
+    (C) 1999 Benjamin Reed.  All Rights Reserved.  Permission to use
+    code in the Developer's manual was granted for this driver by
+    Aironet.
+    
+======================================================================*/
+
+#ifndef __KERNEL__
+#define __KERNEL__
+#endif
+
+#ifndef MODULE
+#define MODULE
+#endif
+
+#include <linux/autoconf.h>
+#ifdef CONFIG_MODVERSIONS
+#define MODVERSIONS
+#include <linux/modversions.h>
+#endif                 
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/proc_fs.h>
+
+#include <linux/sched.h>
+#include <linux/ptrace.h>
+#include <linux/malloc.h>
+#include <linux/string.h>
+#include <linux/timer.h>
+#include <linux/interrupt.h>
+#include <linux/in.h>
+#include <asm/io.h>
+#include <asm/system.h>
+#include <asm/bitops.h>
+
+#include <linux/netdevice.h>
+#include <linux/etherdevice.h>
+#include <linux/skbuff.h>
+#include <linux/if_arp.h>
+#include <linux/ioport.h>
+#include <linux/config.h>
+#ifdef CONFIG_PCI
+#  include <linux/pci.h>
+
+static struct {
+	unsigned short vendor;
+	unsigned short id;
+} card_ids[] = { { 0x14b9, 1 },
+		 { 0x14b9, 0x4500 },
+		 { 0x14b9, 0x4800 },
+		 { 0, 0 } 
+};
+#endif
+
+/* As you can see this list is HUGH!
+   I really don't know what a lot of these counts are about, but they
+   are all here for completeness.  If the IGNLABEL macro is put in
+   infront of the label, that statistic will not be included in the list
+   of statistics in the /proc filesystem */
+
+#define IGNLABEL 0&(int)
+char *statsLabels[] = {
+	"RxOverrun",
+	IGNLABEL "RxPlcpCrcErr",
+	IGNLABEL "RxPlcpFormatErr",
+	IGNLABEL "RxPlcpLengthErr",
+	"RxMacCrcErr",
+	"RxMacCrcOk",
+	"RxWepErr",
+	"RxWepOk",
+	"RetryLong",
+	"RetryShort",
+	"MaxRetries",
+	"NoAck",
+	"NoCts",
+	"RxAck",
+	"RxCts",
+	"TxAck",
+	"TxRts",
+	"TxCts",
+	"TxMc",
+	"TxBc",
+	"TxUcFrags",
+	"TxUcPackets",
+	"TxBeacon",
+	"RxBeacon",
+	"TxSinColl",
+	"TxMulColl",
+	"DefersNo",
+	"DefersProt",
+	"DefersEngy",
+	"DupFram",
+	"RxFragDisc",
+	"TxAged",
+	"RxAged",
+	"LostSync-MaxRetry",
+	"LostSync-MissedBeacons",
+	"LostSync-ArlExceeded",
+	"LostSync-Deauth",
+	"LostSync-Disassoced",
+	"LostSync-TsfTiming",
+	"HostTxMc",
+	"HostTxBc",
+	"HostTxUc",
+	"HostTxFail",
+	"HostRxMc",
+	"HostRxBc",
+	"HostRxUc",
+	"HostRxDiscard",
+	IGNLABEL "HmacTxMc",
+	IGNLABEL "HmacTxBc",
+	IGNLABEL "HmacTxUc",
+	IGNLABEL "HmacTxFail",
+	IGNLABEL "HmacRxMc",
+	IGNLABEL "HmacRxBc",
+	IGNLABEL "HmacRxUc",
+	IGNLABEL "HmacRxDiscard",
+	IGNLABEL "HmacRxAccepted",
+	"SsidMismatch",
+	"ApMismatch",
+	"RatesMismatch",
+	"AuthReject",
+	"AuthTimeout",
+	"AssocReject",
+	"AssocTimeout",
+	IGNLABEL "ReasonOutsideTable",
+	IGNLABEL "ReasonStatus1",
+	IGNLABEL "ReasonStatus2",
+	IGNLABEL "ReasonStatus3",
+	IGNLABEL "ReasonStatus4",
+	IGNLABEL "ReasonStatus5",
+	IGNLABEL "ReasonStatus6",
+	IGNLABEL "ReasonStatus7",
+	IGNLABEL "ReasonStatus8",
+	IGNLABEL "ReasonStatus9",
+	IGNLABEL "ReasonStatus10",
+	IGNLABEL "ReasonStatus11",
+	IGNLABEL "ReasonStatus12",
+	IGNLABEL "ReasonStatus13",
+	IGNLABEL "ReasonStatus14",
+	IGNLABEL "ReasonStatus15",
+	IGNLABEL "ReasonStatus16",
+	IGNLABEL "ReasonStatus17",
+	IGNLABEL "ReasonStatus18",
+	IGNLABEL "ReasonStatus19",
+	"RxMan",
+	"TxMan",
+	"RxRefresh",
+	"TxRefresh",
+	"RxPoll",
+	"TxPoll",
+	"HostRetries",
+	"LostSync-HostReq",
+	"HostTxBytes",
+	"HostRxBytes",
+	"ElapsedUsec",
+	"ElapsedSec",
+	"LostSyncBetterAP",
+	(char*)-1 };
+#ifndef RUN_AT
+#define RUN_AT(x) (jiffies+(x))
+#endif
+
+
+/* These variables are for insmod, since it seems that the rates
+   can only be set in setup_card.  Rates should be a comma separated
+   (no spaces) list of rates (up to 8). */
+
+static int rates[8] = {0,0,0,0,0,0,0,0};
+static int basic_rate = 0;
+static char *ssids[3] = {0,0,0};
+
+static int io[4]={ 0,};
+static int irq[4]={ 0,};
+
+static int auto_wep = 0; /* If set, it tries to figure out the wep mode */
+static int aux_bap = 0; /* Checks to see if the aux ports are needed to read
+                           the bap, needed on some older cards and buses. */   
+
+#if (LINUX_VERSION_CODE < 0x2032b)
+#define netif_stop_queue(dev) do { (dev)->tbusy = 1; } while (0)
+#define netif_start_queue(dev) do { (dev)->tbusy = 0; } while (0)
+#define netif_wake_queue(dev) \
+    do { (dev)->tbusy = 0; mark_bh(NET_BH); } while (0)
+#define netif_mark_up(dev) do { (dev)->start = 1; } while (0)
+#define netif_mark_down(dev) do { (dev)->start = 0; } while (0)
+#define netif_device_present(dev) ((dev)->start)
+#else
+#define netif_mark_up(dev) do { } while (0)
+#define netif_mark_down(dev) do { } while (0)
+#endif
+
+#if (LINUX_VERSION_CODE > 0x20155)
+/* new kernel */
+MODULE_PARM(io,"1-4i");
+MODULE_PARM(irq,"1-4i");
+MODULE_PARM(basic_rate,"i");
+MODULE_PARM(rates,"1-8i");
+MODULE_PARM(ssids,"1-3s");
+MODULE_PARM(auto_wep,"i");
+MODULE_PARM(aux_bap,"i");
+
+#include <asm/uaccess.h>
+
+#define KFREE_SKB(a,b)  dev_kfree_skb(a)
+#define PROC_REGISTER(a,b) proc_register(a,b)
+#else 
+/* old kernel */
+#define SPIN_LOCK_UNLOCKED 0
+#define spinlock_t int
+#define spin_lock_irqsave(x, y) save_flags(y); cli()
+#define spin_unlock_irqrestore(x, y) restore_flags(y)
+#define le32_to_cpu(x) (x)
+#define cpu_to_le32(x) (x)
+#define le16_to_cpu(x) (x)
+#define cpu_to_le16(x) (x)
+#include <linux/bios32.h>
+#define net_device_stats enet_statistics
+#define KFREE_SKB(a,b)  dev_kfree_skb(a,b)
+#define PROC_REGISTER(a,b) proc_register_dynamic(a,b)
+#endif
+#if (LINUX_VERSION_CODE < 0x020311)
+#define PROC_UNREGISTER(root, entry) proc_unregister(root, (entry)->low_ino)
+#else
+#define PROC_REGISTER(root, entry) error
+#define PROC_UNREGISTER(root, entry) error
+#endif
+#if (LINUX_VERSION_CODE < 0x02030e)
+#define net_device device
+#endif
+
+#define min(x,y) ((x<y)?x:y)
+
+#define isalnum(x) ((x>='a'&&x<='z')||(x>='A'&&x<='Z')||(x>='0'&&x<='9'))
+
+/* This is a kind of sloppy hack to get this information to OUT4500 and
+   IN4500.  I would be extremely interested in the situation where this
+   doesnt work though!!! */
+static int do8bitIO = 0;
+
+/* Return codes */
+#define SUCCESS 0
+#define ERROR -1
+#define NO_PACKET -2
+
+/* Commands */
+#define NOP 0x0010
+#define MAC_ENABLE 0x0001
+#define MAC_DISABLE 0x0002
+#define CMD_ACCESS 0x0021
+#define CMD_ALLOCATETX 0x000a
+#define CMD_TRANSMIT 0x000b
+#define HOSTSLEEP 0x85
+#define CMD_SETMODE 0x0009
+#define CMD_ENABLEAUX 0x0111
+
+/* Registers */
+#define COMMAND 0x00
+#define PARAM0 0x02
+#define PARAM1 0x04
+#define PARAM2 0x06
+#define STATUS 0x08
+#define RESP0 0x0a
+#define RESP1 0x0c
+#define RESP2 0x0e
+#define LINKSTAT 0x10
+#define SELECT0 0x18
+#define OFFSET0 0x1c
+#define RXFID 0x20
+#define TXALLOCFID 0x22
+#define TXCOMPLFID 0x24
+#define DATA0 0x36
+#define EVSTAT 0x30
+#define EVINTEN 0x32
+#define EVACK 0x34
+#define SWS0 0x28
+#define SWS1 0x2a
+#define SWS2 0x2c
+#define SWS3 0x2e
+#define AUXPAGE 0x3A
+#define AUXOFF 0x3C
+#define AUXDATA 0x3E
+
+/* BAP selectors */
+#define BAP0 0 // Used for receiving packets
+#define BAP1 2 // Used for xmiting packets and working with RIDS
+
+/* Flags */
+#define COMMAND_BUSY 0x8000
+
+#define BAP_BUSY 0x8000
+#define BAP_ERR 0x4000
+#define BAP_DONE 0x2000
+
+#define PROMISC 0xffff
+
+#define EV_CMD 0x10
+#define EV_CLEARCOMMANDBUSY 0x4000
+#define EV_RX 0x01
+#define EV_TX 0x02
+#define EV_TXEXC 0x04
+#define EV_ALLOC 0x08
+#define EV_LINK 0x80
+#define EV_AWAKE 0x100
+#define STATUS_INTS ( EV_AWAKE | EV_LINK | EV_TXEXC | EV_TX | EV_RX )
+
+/* The RIDs */
+#define RID_WEP_PERM 0xFF16
+#define RID_WEP_TEMP 0xFF15
+#define RID_SSID     0xFF11
+#define RID_CONFIG   0xFF10
+#define RID_ACTUALCONFIG 0xFF20 /*readonly*/
+#define RID_MODULATION 0xFF17
+#define RID_STATS 0xFF68
+#define RID_STATSDELTA 0xFF69
+#define RID_STATSDELTACLEAR 0xFF6A
+
+/*
+ * Rids and endian-ness:  The Rids will always be little endian, since
+ * this is what the card wants.  So any assignments to are from the
+ * rids need to be converted to the correct endian.
+ */
+
+/* This structure came from an email sent to me from an engineer at
+   aironet for inclusion into this driver */
+typedef struct {
+	u16 len;
+	u16 kindex;
+	u8 mac[6];
+	u16 klen;
+	u8 key[16];  /* 40-bit keys */
+} WepKeyRid;
+
+/* These structures are from the Aironet's PC4500 Developers Manual */
+typedef struct {
+	u16 len;
+	u8 ssid[32];
+} Ssid;
+
+typedef struct {
+	u16 len;
+	Ssid ssids[3];
+} SsidRid;
+
+typedef struct {
+        u16 len;
+        u16 modulation;
+#define MOD_DEFAULT 0
+#define MOD_CCK 1
+#define MOD_MOK 2
+} ModulationRid;
+
+typedef struct {
+	u16 cmd;
+	u16 parm0;
+	u16 parm1;
+	u16 parm2;
+} Cmd;
+
+typedef struct {
+	u16 status;
+	u16 rsp0;
+	u16 rsp1;
+	u16 rsp2;
+} Resp;
+
+typedef struct {
+	u16 len; /* sizeof(ConfigRid) */
+	u16 opmode; /* operating mode */
+#define MODE_STA_IBSS 0
+#define MODE_STA_ESS 1
+#define MODE_AP 2
+#define MODE_AP_RPTR 3
+#define MODE_ETHERNET_HOST (0<<8) /* rx payloads converted */
+#define MODE_LLC_HOST (1<<8) /* rx payloads left as is */
+#define MODE_AIRONET_EXTEND (1<<9) /* enable Aironet extenstions */
+#define MODE_AP_INTERFACE (1<<10) /* enable ap interface extensions */
+	u16 rmode; /* receive mode */
+#define RXMODE_BC_MC_ADDR 0
+#define RXMODE_BC_ADDR 1 /* ignore multicasts */
+#define RXMODE_ADDR 2 /* ignore multicast and broadcast */
+#define RXMODE_RFMON 3 /* wireless monitor mode */
+#define RXMODE_RFMON_ANYBSS 4
+#define RXMODE_LANMON 5 /* lan style monitor -- data packets only */
+#define RXMODE_DISABLE_802_3_HEADER (1<<8) /* disables 802.3 header on rx */
+	u16 fragThresh;
+	u16 rtsThres;
+	u8 macAddr[6];
+	u8 rates[8];
+	u16 shortRetryLimit;
+	u16 longRetryLimit;
+	u16 txLifetime; /* in kusec */
+	u16 rxLifetime; /* in kusec */
+	u16 stationary;
+	u16 ordering;
+	u16 u16deviceType; /* for overriding device type */
+	u16 _reserved1[5];
+	/*---------- Scanning/Associating ----------*/
+	u16 scanMode;
+#define SCANMODE_ACTIVE 0
+#define SCANMODE_PASSIVE 1
+#define SCANMODE_AIROSCAN 2
+	u16 probeDelay; /* in kusec */
+	u16 probeEnergyTimeout; /* in kusec */
+        u16 probeResponseTimeout;
+	u16 beaconListenTimeout;
+	u16 joinNetTimeout;
+	u16 authTimeout;
+	u16 authType;
+#define AUTH_OPEN 0x1
+#define AUTH_ENCRYPT 0x101
+#define AUTH_SHAREDKEY 0x102
+	u16 associationTimeout;
+	u16 specifiedApTimeout;
+	u16 offlineScanInterval;
+	u16 offlineScanDuration;
+	u16 linkLossDelay;
+	u16 maxBeaconLostTime;
+	u16 refreshInterval;
+#define DISABLE_REFRESH 0xFFFF
+	u16 _reserved1a[1];
+	/*---------- Power save operation ----------*/
+	u16 powerSaveMode;
+#define POWERSAVE_CAM 0
+#define POWERSAVE_PSP 1
+#define POWERSAVE_PSPCAM 2
+	u16 sleepForDtims;
+	u16 listenInterval;
+	u16 fastListenInterval;
+	u16 listenDecay;
+	u16 fastListenDelay;
+	u16 _reserved2[2];
+	/*---------- Ap/Ibss config items ----------*/
+	u16 beaconPeriod;
+	u16 atimDuration;
+	u16 hopPeriod;
+	u16 channelSet;
+	u16 channel;
+	u16 dtimPeriod;
+	u16 _reserved3[2];
+	/*---------- Radio configuration ----------*/
+	u16 radioType;
+#define RADIOTYPE_DEFAULT 0
+#define RADIOTYPE_802_11 1
+#define RADIOTYPE_LEGACY 2
+	u8 rxDiversity;
+	u8 txDiversity;
+	u16 txPower;
+#define TXPOWER_DEFAULT 0
+	u16 rssiThreshold;
+#define RSSI_DEFAULT 0
+        u16 modulation;
+	u16 radioSpecific[3];
+	/*---------- Aironet Extensions ----------*/
+	u8 nodeName[16];
+	u16 arlThreshold;
+	u16 arlDecay;
+	u16 arlDelay;
+	u16 _reserved4[1];
+	/*---------- Aironet Extensions ----------*/
+	u16 magicAction;
+#define MAGIC_ACTION_STSCHG 1
+#define MACIC_ACTION_RESUME 2
+#define MAGIC_IGNORE_MCAST (1<<8)
+#define MAGIC_IGNORE_BCAST (1<<9)
+#define MAGIC_SWITCH_TO_PSP (0<<10)
+#define MAGIC_STAY_IN_CAM (1<<10)
+	u16 filler;
+} ConfigRid;
+
+typedef struct {
+	u16 len;
+	u8 mac[6];
+	u16 mode;
+	u16 errorCode;
+	u16 sigQuality;
+	u16 SSIDlen;
+	char SSID[32];
+	char apName[16];
+	char bssid[4][6];
+	u16 beaconPeriod;
+	u16 dimPeriod;
+	u16 atimDuration;
+	u16 hopPeriod;
+	u16 channelSet;
+	u16 channel;
+	u16 hopsToBackbone;
+	u16 apTotalLoad;
+	u16 generatedLoad;
+	u16 accumulatedArl;
+	u16 signalQuality;
+	u16 currentXmitRate;
+	u16 apDevExtensions;
+	u16 normalizedSignalStrength;
+} StatusRid;
+
+typedef struct {
+	u16 len;
+	char oui[3];
+	u16 prodNum;
+	char manName[32];
+	char prodName[16];
+	char prodVer[8];
+	char factoryAddr[6];
+	char aironetAddr[6];
+	u16 radioType;
+	u16 country;
+	char callid[6];
+	char supportedRates[8];
+	char rxDiversity;
+	char txDiversity;
+	u16 txPowerLevels[8];
+	u16 hardVer;
+	u16 hardCap;
+	u16 tempRange;
+	u16 softVer;
+	u16 softSubVer;
+	u16 interfaceVer;
+	u16 softCap;
+	u16 bootBlockVer;
+} CapabilityRid;
+
+#define TXCTL_TXOK (1<<1) /* report if tx is ok */
+#define TXCTL_TXEX (1<<2) /* report if tx fails */
+#define TXCTL_802_3 (0<<3) /* 802.3 packet */
+#define TXCTL_802_11 (1<<3) /* 802.11 mac packet */
+#define TXCTL_ETHERNET (0<<4) /* payload has ethertype */
+#define TXCTL_LLC (1<<4) /* payload is llc */
+#define TXCTL_RELEASE (0<<5) /* release after completion */
+#define TXCTL_NORELEASE (1<<5) /* on completion returns to host */
+
+#define BUSY_FID 0x10000
+
+static char *version =
+"airo.c 0.99zf 2000/03/25 16:27:17 (Benjamin Reed)";
+
+struct airo_info;
+
+static int get_dec_u16( char *buffer, int *start, int limit );
+static void OUT4500( struct airo_info *, u16 register, u16 value );
+static unsigned short IN4500( struct airo_info *, u16 register );
+static u16 setup_card(struct airo_info*, u8 *mac, ConfigRid *);
+static void enable_interrupts(struct airo_info*);
+static void disable_interrupts(struct airo_info*);
+static u16 issuecommand(struct airo_info*, Cmd *pCmd, Resp *pRsp);
+static int bap_setup(struct airo_info*, u16 rid, u16 offset, int whichbap);
+static int aux_bap_read(struct airo_info*, u16 *pu16Dst, int bytelen, 
+			int whichbap);
+static int fast_bap_read(struct airo_info*, u16 *pu16Dst, int bytelen, 
+			 int whichbap);
+static int bap_write(struct airo_info*, const u16 *pu16Src, int bytelen,
+		     int whichbap);
+static int PC4500_accessrid(struct airo_info*, u16 rid, u16 accmd);
+static int PC4500_readrid(struct airo_info*, u16 rid, void *pBuf, int len);
+static int PC4500_writerid(struct airo_info*, u16 rid, const void
+			   *pBuf, int len);
+static int do_writerid( struct airo_info*, u16 rid, const void *rid_data, 
+			int len );
+static u16 transmit_allocate(struct airo_info*, int lenPayload);
+static int transmit_802_3_packet(struct airo_info*, u16 TxFid, char
+				 *pPacket, int len);
+
+static void airo_interrupt( int irq, void* dev_id, struct pt_regs
+			    *regs);
+struct airo_info {
+	struct net_device_stats	stats;
+	int open;
+	char name[8];
+	struct net_device             *dev;
+	/* Note, we can have MAX_FIDS outstanding.  FIDs are 16-bits, so we
+	   use the high bit to mark wether it is in use. */
+#define MAX_FIDS 6
+	int                           fids[MAX_FIDS];
+	int registered;
+	ConfigRid config;
+	u16 authtype;
+	struct timer_list timer;
+#if (LINUX_VERSION_CODE < 0x20311)
+	struct proc_dir_entry proc_entry;
+	struct proc_dir_entry proc_statsdelta_entry;
+	struct proc_dir_entry proc_stats_entry;
+	struct proc_dir_entry proc_status_entry;
+	struct proc_dir_entry proc_config_entry;
+	struct proc_dir_entry proc_SSID_entry;
+	struct proc_dir_entry proc_wepkey_entry;
+#else
+	struct proc_dir_entry *proc_entry;
+#endif
+	struct airo_info *next;
+        spinlock_t bap0_lock;
+        spinlock_t bap1_lock;
+        spinlock_t aux_lock;
+        spinlock_t cmd_lock;
+        int flags;
+#define FLAG_PROMISC 0x01
+#define FLAG_RADIO_OFF 0x02
+	int (*bap_read)(struct airo_info*, u16 *pu16Dst, int bytelen, 
+		int whichbap);
+};
+
+static inline int bap_read(struct airo_info *ai, u16 *pu16Dst, int bytelen, 
+			   int whichbap) {
+	return ai->bap_read(ai, pu16Dst, bytelen, whichbap);
+}
+
+static int setup_proc_entry( struct net_device *dev,
+			     struct airo_info *apriv );
+static int takedown_proc_entry( struct net_device *dev,
+				struct airo_info *apriv );
+
+
+static int airo_open(struct net_device *dev) {
+	struct airo_info *info = dev->priv;
+
+	MOD_INC_USE_COUNT;
+	if ( info->open == 0 ) {
+		enable_interrupts(info);
+	}
+	info->open++;
+
+	netif_start_queue(dev);
+	netif_mark_up(dev);
+	
+	return 0;
+}
+
+static int airo_start_xmit(struct sk_buff *skb, struct net_device *dev) {
+	s16 len;
+	s16 retval = 0;
+	u16 status;
+	u32 flags;
+	s8 *buffer;
+	int i;
+	struct airo_info *priv = (struct airo_info*)dev->priv;
+	u32 *fids = priv->fids;
+	
+	if ( skb == NULL ) {
+		printk( KERN_ERR "airo:  skb == NULL!!!\n" );
+		return 0;
+	}
+	
+	/* Find a vacant FID */
+	spin_lock_irqsave(&priv->bap1_lock, flags);
+	for( i = 0; i < MAX_FIDS; i++ ) {
+		if ( !( fids[i] & 0xffff0000 ) ) break;
+	}
+	if ( i == MAX_FIDS ) {
+                netif_stop_queue(dev);
+		retval = -EBUSY;
+		goto tx_done;
+	}
+	
+	len = ETH_ZLEN < skb->len ? skb->len : ETH_ZLEN; /* check min length*/
+	buffer = skb->data;
+	
+	status = transmit_802_3_packet( priv, 
+					fids[i],
+					skb->data, len );
+	
+	if ( status == SUCCESS ) {
+                /* Mark fid as used & save length for later */
+		fids[i] |= (len << 16); 
+		dev->trans_start = jiffies;
+	} else {
+		((struct airo_info*)dev->priv)->stats.tx_errors++;
+	}
+ tx_done:
+	spin_unlock_irqrestore(&priv->bap1_lock, flags);
+	KFREE_SKB( skb, FREE_WRITE );
+	return 0;
+}
+
+static struct net_device_stats *airo_get_stats(struct net_device *dev) {
+	return &(((struct airo_info*)dev->priv)->stats);
+}
+
+static void airo_set_multicast_list(struct net_device *dev) {
+        struct airo_info *ai = (struct airo_info*)dev->priv;
+
+        ai->flags &= ~FLAG_PROMISC;
+	if (dev->flags&IFF_PROMISC) {
+	        ai->flags |= FLAG_PROMISC;
+	} else if ((dev->flags&IFF_ALLMULTI)||dev->mc_count>0) {
+		/* Turn on multicast.  (Should be already setup...) */
+	}
+}
+
+static int private_ioctl(struct net_device *dev, struct ifreq *rq, 
+			 int cmd) {
+	return 0;
+}
+
+static int airo_change_mtu(struct net_device *dev, int new_mtu)
+{
+	if ((new_mtu < 68) || (new_mtu > 2400))
+		return -EINVAL;
+	dev->mtu = new_mtu;
+	return 0;
+}
+
+
+static int airo_close(struct net_device *dev) { 
+	struct airo_info *ai = (struct airo_info*)dev->priv;
+	ai->open--;
+	netif_stop_queue(dev);
+	netif_mark_down(dev);
+	if ( !ai->open ) {
+		disable_interrupts( ai );
+	}
+	MOD_DEC_USE_COUNT;
+	return 0;
+}
+
+static void del_airo_dev( struct net_device *dev );
+
+void stop_airo_card( struct net_device *dev ) 
+{
+	struct airo_info *ai = (struct airo_info*)dev->priv;
+	takedown_proc_entry( dev, ai );
+	if (ai->registered) {
+		unregister_netdev( dev );
+		ai->registered = 0;
+	}
+	disable_interrupts(ai);
+	release_region( dev->base_addr, 64 );
+	free_irq( dev->irq, dev );
+	del_airo_dev( dev );
+	if (dev->priv)
+		kfree(dev->priv);
+	kfree( dev );
+	if (auto_wep) del_timer(&(ai)->timer);
+}
+
+static void add_airo_dev( struct net_device *dev ); 
+
+struct net_device *init_airo_card( unsigned short irq, int port )
+{
+	struct net_device *dev;
+	struct airo_info *ai;
+	int i;
+	
+	/* Create the network device object. */
+	dev = kmalloc(sizeof(struct net_device), GFP_KERNEL);
+	memset(dev, 0, sizeof(struct net_device));
+	
+	/* Space for the info structure. */
+	dev->priv = kmalloc(sizeof(struct airo_info), GFP_KERNEL);
+	memset(dev->priv, 0, sizeof(struct airo_info));
+	ai = (struct airo_info *)dev->priv;
+        ai->dev = dev;
+	ai->bap0_lock = SPIN_LOCK_UNLOCKED;
+	ai->bap1_lock = SPIN_LOCK_UNLOCKED;
+	ai->aux_lock = SPIN_LOCK_UNLOCKED;
+	ai->cmd_lock = SPIN_LOCK_UNLOCKED;
+	add_airo_dev( dev ); 
+	
+	/* The Airo-specific entries in the device structure. */
+	dev->hard_start_xmit = &airo_start_xmit;
+	dev->get_stats = &airo_get_stats;
+	dev->set_multicast_list = &airo_set_multicast_list;
+	dev->do_ioctl = &private_ioctl;
+	dev->name = ((struct airo_info *)dev->priv)->name;
+	ether_setup(dev);
+	dev->change_mtu = &airo_change_mtu;
+	dev->open = &airo_open;
+	dev->stop = &airo_close;
+	netif_stop_queue(dev);
+	dev->irq = irq;
+	dev->base_addr = port;
+	
+	if ( request_irq( dev->irq, airo_interrupt, 
+			  SA_SHIRQ | SA_INTERRUPT, dev->name, dev ) ) {
+		printk(KERN_ERR "airo: register interrupt %d failed\n", irq );
+	}
+	request_region( dev->base_addr, 64, dev->name );
+	
+	memset( &((struct airo_info*)dev->priv)->config, 0,
+		sizeof(((struct airo_info*)dev->priv)->config));
+	
+	if ( setup_card( ai, dev->dev_addr, 
+			 &((struct airo_info*)dev->priv)->config) 
+	     != SUCCESS ) {
+		printk( KERN_ERR "airo: MAC could not be enabled\n" );
+		goto init_undo;
+	} else {
+		printk( KERN_INFO "airo: MAC enabled %s %x:%x:%x:%x:%x:%x\n",
+			dev->name,
+			dev->dev_addr[0],
+			dev->dev_addr[1],
+			dev->dev_addr[2],
+			dev->dev_addr[3],
+			dev->dev_addr[4],
+			dev->dev_addr[5]
+			);
+		/* Allocate the transmit buffers */
+		for( i = 0; i < MAX_FIDS; i++ ) {
+			ai->fids[i] = transmit_allocate( ai, 2000 );
+		}
+	}
+	
+	if (register_netdev(dev) != 0) {
+		printk(KERN_ERR "airo: register_netdev() failed\n");
+		goto init_undo;
+	}
+	((struct airo_info*)dev->priv)->registered = 1;
+	
+	setup_proc_entry( dev, (struct airo_info*)dev->priv );
+	
+	netif_start_queue(dev);
+	return dev;
+ init_undo:
+	stop_airo_card( dev );
+	return 0;
+}
+
+int reset_airo_card( struct net_device *dev ) {
+	int i;
+	struct airo_info *ai = (struct airo_info*)dev->priv;
+
+	if ( setup_card(ai, dev->dev_addr,
+			&(ai)->config) != SUCCESS ) {
+		printk( KERN_ERR "airo: MAC could not be enabled\n" );
+		return -1;
+	} else {
+		printk( KERN_INFO "airo: MAC enabled %s %x:%x:%x:%x:%x:%x\n",
+			dev->name,
+			dev->dev_addr[0],
+			dev->dev_addr[1],
+			dev->dev_addr[2],
+			dev->dev_addr[3],
+			dev->dev_addr[4],
+			dev->dev_addr[5]
+			);
+		/* Allocate the transmit buffers */
+		for( i = 0; i < MAX_FIDS; i++ ) {
+			((struct airo_info*)dev->priv)->fids[i] =
+				transmit_allocate( ai, 2000 );
+		}
+	}
+	enable_interrupts( ai );
+	netif_start_queue(dev);
+	return 0;
+}
+
+static void airo_interrupt ( int irq, void* dev_id, struct pt_regs *regs) {
+	struct net_device *dev = (struct net_device *)dev_id;
+	u16 len;
+	u16 status;
+	u16 fid;
+	struct airo_info *apriv = (struct airo_info *)dev->priv;
+	u16 savedInterrupts;
+	
+
+	if (!netif_device_present(dev))
+		return;
+	
+	status = IN4500( apriv, EVSTAT );
+	if ( !status ) return;
+	
+	if ( status & EV_AWAKE ) {
+		OUT4500( apriv, EVACK, EV_AWAKE );
+		OUT4500( apriv, EVACK, EV_AWAKE );
+	}
+	
+	savedInterrupts = IN4500( apriv, EVINTEN );
+	OUT4500( apriv, EVINTEN, 0 );
+	
+	if ( status & EV_LINK ) {
+		/* The link status has changed, if you want to put a
+		   monitor hook in, do it here.  (Remember that
+		   interrupts are still disabled!)
+		*/
+		/*u16 newStatus = */IN4500(apriv, LINKSTAT);
+		/* Here is what newStatus means: */
+#define NOBEACON 0x8000 /* Loss of sync - missed beacons */
+#define MAXRETRIES 0x8001 /* Loss of sync - max retries */
+#define MAXARL 0x8002 /* Loss of sync - average retry level exceeded*/
+#define FORCELOSS 0x8003 /* Loss of sync - host request */
+#define TSFSYNC 0x8004 /* Loss of sync - TSF synchronization */
+#define DEAUTH 0x8100 /* Deauthentication (low byte is reason code) */
+#define DISASS 0x8200 /* Disassociation (low byte is reason code) */
+#define ASSFAIL 0x8400 /* Association failure (low byte is reason
+			  code) */
+#define AUTHFAIL 0x0300 /* Authentication failure (low byte is reason
+			   code) */
+#define ASSOCIATED 0x0400 /* Assocatied */
+#define RC_RESERVED 0 /* Reserved return code */
+#define RC_NOREASON 1 /* Unspecified reason */
+#define RC_AUTHINV 2 /* Previous authentication invalid */
+#define RC_DEAUTH 3 /* Deauthenticated because sending station is
+		       leaving */
+#define RC_NOACT 4 /* Disassociated due to inactivity */
+#define RC_MAXLOAD 5 /* Disassociated because AP is unable to handle
+			all currently associated stations */
+#define RC_BADCLASS2 6 /* Class 2 frame received from
+			  non-Authenticated station */
+#define RC_BADCLASS3 7 /* Class 3 frame received from
+			  non-Associated station */
+#define RC_STATLEAVE 8 /* Disassociated because sending station is
+			  leaving BSS */
+#define RC_NOAUTH 9 /* Station requesting (Re)Association is not
+		       Authenticated with the responding station */
+	}
+	
+	/* Check to see if there is something to recieve */
+	if ( status & EV_RX  ) {
+		struct sk_buff *skb;
+		int flags;
+
+		fid = IN4500( apriv, RXFID );
+
+		/* Get the packet length */
+	        spin_lock_irqsave(&apriv->bap0_lock, flags);
+		bap_setup( apriv, fid, 0x36, BAP0 );
+		bap_read( apriv, &len, sizeof(len), BAP0 );
+
+		len = le16_to_cpu(len);
+                /* The length only counts the payload
+		   not the hw addresses */
+		len += 12; 
+		if ( len < 12 || len > 2048 ) {
+#if LINUX_VERSION_CODE > 0x20127
+			apriv->stats.rx_length_errors++;
+#endif
+			apriv->stats.rx_errors++;
+			printk( KERN_ERR 
+				"airo: Bad size %d\n", len );
+		} else {
+			skb = dev_alloc_skb( len + 2 );
+			if ( !skb ) {
+				apriv->stats.rx_dropped++;
+			} else {
+				char *buffer;
+				buffer = skb_put( skb, len );
+		                bap_setup( apriv, fid, 0x36+sizeof(len), BAP0 );
+				bap_read( apriv, (u16*)buffer, len, BAP0 );
+				apriv->stats.rx_packets++;
+#if LINUX_VERSION_CODE > 0x20127
+				apriv->stats.rx_bytes += len;
+#endif
+				skb->dev = dev;
+				skb->ip_summed = CHECKSUM_NONE;
+				skb->protocol = eth_type_trans( skb, dev );
+
+				netif_rx( skb );
+			}
+		}
+		spin_unlock_irqrestore(&apriv->bap0_lock, flags);
+	}
+
+	/* Check to see if a packet has been transmitted */
+	if (  status & ( EV_TX|EV_TXEXC ) ) {
+		int i;
+		int len = 0;
+		int full = 1;
+		int index = -1;
+		
+		fid = IN4500(apriv, TXCOMPLFID);
+		
+		for( i = 0; i < MAX_FIDS; i++ ) {
+			if (!(apriv->fids[i] & 0xffff0000)) full = 0;
+			if ( ( apriv->fids[i] & 0xffff ) == fid ) {
+				len = apriv->fids[i] >> 16;
+				index = i;
+				/* Set up to be used again */
+				apriv->fids[i] &= 0xffff; 
+			}
+		}
+		if (full) netif_wake_queue(dev);
+		if (index==-1) {
+			printk( KERN_ERR
+				"airo: Unallocated FID was used to xmit\n" );
+		}
+		if ( status & EV_TX ) {
+			apriv->stats.tx_packets++;
+#if LINUX_VERSION_CODE > 0x20127
+			if(index!=-1)
+				apriv->stats.tx_bytes += len;
+#endif
+		} else {
+			apriv->stats.tx_errors++;
+		}
+	}
+	if ( status & ~STATUS_INTS ) 
+		printk( KERN_WARNING 
+			"airo: Got weird status %x\n", 
+			status & ~STATUS_INTS );
+	OUT4500( apriv, EVACK, status & STATUS_INTS );
+	OUT4500( apriv, EVINTEN, savedInterrupts );
+	
+	/* done.. */
+	return;     
+}
+
+/*
+ *  Routines to talk to the card
+ */
+
+/*
+ *  This was originally written for the 4500, hence the name
+ *  NOTE:  If use with 8bit mode and SMP bad things will happen!
+ *         Why would some one do 8 bit IO in an SMP machine?!?
+ */
+static void OUT4500( struct airo_info *ai, u16 reg, u16 val ) {
+	val = cpu_to_le16(val);
+	if ( !do8bitIO )
+		outw( val, ai->dev->base_addr + reg );
+	else {
+		outb( val & 0xff, ai->dev->base_addr + reg );
+		outb( val >> 8, ai->dev->base_addr + reg + 1 );
+	}
+}
+
+static u16 IN4500( struct airo_info *ai, u16 reg ) {
+	unsigned short rc;
+	
+	if ( !do8bitIO )
+		rc = inw( ai->dev->base_addr + reg );
+	else {
+		rc = inb( ai->dev->base_addr + reg );
+		rc += ((int)inb( ai->dev->base_addr + reg + 1 )) << 8;
+	}
+	return le16_to_cpu(rc);
+}
+
+static int enable_MAC( struct airo_info *ai, Resp *rsp ) {
+        Cmd cmd;
+	int status;
+
+        if (ai->flags&FLAG_RADIO_OFF) return SUCCESS;
+	memset(&cmd, 0, sizeof(cmd));
+	cmd.cmd = MAC_ENABLE; // disable in case already enabled
+	status = issuecommand(ai, &cmd, rsp);
+	if (status == SUCCESS && ai->flags|FLAG_PROMISC) {
+	        Cmd cmd;
+		Resp rsp;
+		memset(&cmd, 0, sizeof(cmd));
+		cmd.cmd=CMD_SETMODE;
+		cmd.parm1=PROMISC;
+		issuecommand(ai, &cmd, &rsp);
+	}
+	return status;
+}
+
+static void disable_MAC( struct airo_info *ai ) {
+        Cmd cmd;
+	Resp rsp;
+
+	memset(&cmd, 0, sizeof(cmd));
+	cmd.cmd = MAC_DISABLE; // disable in case already enabled
+	issuecommand(ai, &cmd, &rsp);
+}
+
+static void enable_interrupts( struct airo_info *ai ) {
+	/* Reset the status register */
+	u16 status = IN4500( ai, EVSTAT );
+	OUT4500( ai, EVACK, status );
+	/* Enable the interrupts */
+	OUT4500( ai, EVINTEN, STATUS_INTS );
+	/* Note there is a race condition between the last two lines that
+	   I dont know how to get rid of right now... */
+}
+
+static void disable_interrupts( struct airo_info *ai ) {
+	OUT4500( ai, EVINTEN, 0 );
+}
+
+static u16 setup_card(struct airo_info *ai, u8 *mac, 
+		      ConfigRid *config)
+{
+	Cmd cmd; 
+	Resp rsp;
+	ConfigRid cfg;
+	int status;
+	int i;
+	SsidRid mySsid;
+
+	memset( &mySsid, 0, sizeof( mySsid ) );
+
+	/* The NOP is the first step in getting the card going */
+	cmd.cmd = NOP;
+	cmd.parm0 = cmd.parm1 = cmd.parm2 = 0;
+	if ( issuecommand( ai, &cmd, &rsp ) != SUCCESS ) {
+		return ERROR;
+	}
+	memset(&cmd, 0, sizeof(cmd));
+	cmd.cmd = MAC_DISABLE; // disable in case already enabled
+	if ( issuecommand( ai, &cmd, &rsp ) != SUCCESS ) {
+		return ERROR;
+	}
+	
+	// Let's figure out if we need to use the AUX port
+	cmd.cmd = CMD_ENABLEAUX;
+	if (issuecommand(ai, &cmd, &rsp) != SUCCESS) {
+		printk(KERN_ERR "airo: Error checking for AUX port\n");
+		return ERROR;
+	}
+	if (!aux_bap || rsp.status & 0xff00) {
+		ai->bap_read = fast_bap_read;
+		printk(KERN_DEBUG "airo: Doing fast bap_reads\n");
+	} else {
+		ai->bap_read = aux_bap_read;
+		printk(KERN_DEBUG "airo: Doing AUX bap_reads\n");
+	}
+	if ( config->len ) {
+		cfg = *config;
+	} else {
+		// general configuration (read/modify/write)
+		status = PC4500_readrid(ai, RID_CONFIG, &cfg, sizeof(cfg));
+		if ( status != SUCCESS ) return ERROR;
+		cfg.opmode = MODE_STA_ESS; // station in ESS mode
+    
+		/* Save off the MAC */
+		for( i = 0; i < 6; i++ ) {
+			mac[i] = cfg.macAddr[i];
+		}
+
+		/* Check to see if there are any insmod configured 
+		   rates to add */
+		if ( rates ) {
+			int i = 0;
+			if ( rates[0] ) memset(cfg.rates,0,sizeof(cfg.rates));
+			for( i = 0; i < 8 && rates[i]; i++ ) {
+				cfg.rates[i] = rates[i];
+			}    
+		}
+		if ( basic_rate > 0 ) {
+			int i;
+			for( i = 0; i < 8; i++ ) {
+				if ( cfg.rates[i] == basic_rate ||
+				     !cfg.rates ) {
+					cfg.rates[i] = basic_rate | 0x80;
+					break;
+				}
+			}
+		}
+		*config = cfg;
+	}
+	
+	/* Setup the SSIDs if present */
+	if ( ssids[0] ) {
+		int i = 0;
+		for( i = 0; i < 3 && ssids[i]; i++ ) {
+			mySsid.ssids[i].len = strlen(ssids[i]);
+			if ( mySsid.ssids[i].len > 32 ) 
+				mySsid.ssids[i].len = 32;
+			memcpy(mySsid.ssids[i].ssid, ssids[i],
+			       mySsid.ssids[i].len);
+			mySsid.ssids[i].len = cpu_to_le16(mySsid.ssids[i].len);
+		}
+	}
+	
+	status = PC4500_writerid( ai, RID_CONFIG, &cfg, sizeof(cfg));
+	if ( status != SUCCESS ) return ERROR;
+	
+	/* Set up the SSID list */
+	status = PC4500_writerid(ai, RID_SSID, &mySsid, sizeof(mySsid));
+	if ( status != SUCCESS ) return ERROR;
+	
+	status = enable_MAC(ai, &rsp);
+	if (status != SUCCESS || (rsp.status & 0xFF00) != 0) {
+		int reason = rsp.rsp0;
+		int badRidNumber = rsp.rsp1;
+		int badRidOffset = rsp.rsp2;
+		printk( KERN_ERR 
+			"airo: Bad MAC enable reason = %x, rid = %x, offset = %d\n",
+			reason,
+			badRidNumber,
+			badRidOffset );
+		return ERROR;
+	}
+	return SUCCESS;
+}
+
+static u16 issuecommand(struct airo_info *ai, Cmd *pCmd, Resp *pRsp) {
+        // Im really paranoid about letting it run forever!
+	int max_tries = 600000;  
+        int rc = SUCCESS;
+	int flags;
+
+	spin_lock_irqsave(&ai->cmd_lock, flags);
+	OUT4500(ai, PARAM0, pCmd->parm0);
+	OUT4500(ai, PARAM1, pCmd->parm1);
+	OUT4500(ai, PARAM2, pCmd->parm2);
+	OUT4500(ai, COMMAND, pCmd->cmd);
+	while ( max_tries-- &&
+		(IN4500(ai, EVSTAT) & EV_CMD) == 0) {
+		if ( IN4500(ai, COMMAND) == pCmd->cmd) { 
+			// PC4500 didn't notice command, try again
+			OUT4500(ai, COMMAND, pCmd->cmd);
+		}
+	}
+	if ( max_tries == -1 ) {
+		printk( KERN_ERR 
+			"airo: Max tries exceeded when issueing command\n" );
+                rc = ERROR;
+                goto done;
+	}
+	// command completed
+	pRsp->status = IN4500(ai, STATUS);
+	pRsp->rsp0 = IN4500(ai, RESP0);
+	pRsp->rsp1 = IN4500(ai, RESP1);
+	pRsp->rsp2 = IN4500(ai, RESP2);
+	
+	// clear stuck command busy if necessary
+	if (IN4500(ai, COMMAND) & COMMAND_BUSY) {
+		OUT4500(ai, EVACK, EV_CLEARCOMMANDBUSY);
+	}
+	// acknowledge processing the status/response
+	OUT4500(ai, EVACK, EV_CMD);
+done:
+	spin_unlock_irqrestore(&ai->cmd_lock, flags);
+	return rc;
+}
+
+/* Sets up the bap to start exchange data.  whichbap should
+ * be one of the BAP0 or BAP1 defines.  Locks should be held before
+ * calling! */
+static int bap_setup(struct airo_info *ai, u16 rid, u16 offset, int whichbap )
+{
+	int timeout = 50;
+	int max_tries = 3;
+	
+	OUT4500(ai, SELECT0+whichbap, rid);
+	OUT4500(ai, OFFSET0+whichbap, offset);
+	while (1) {
+		int status = IN4500(ai, OFFSET0+whichbap);
+		if (status & BAP_BUSY) {
+                        /* This isn't really a timeout, but its kinda
+			   close */
+			if (timeout--) { 
+				continue;
+			}
+		} else if ( status & BAP_ERR ) {
+			/* invalid rid or offset */
+			printk( KERN_ERR "airo: BAP error %x %d\n", 
+				status, whichbap );
+			return ERROR;
+		} else if (status & BAP_DONE) { // success
+			return SUCCESS;
+		}
+		if ( !(max_tries--) ) {
+			printk( KERN_ERR 
+				"airo: BAP setup error too many retries\n" );
+			return ERROR;
+		}
+		// -- PC4500 missed it, try again
+		OUT4500(ai, SELECT0+whichbap, rid);
+		OUT4500(ai, OFFSET0+whichbap, offset);
+		timeout = 50;
+	}
+}
+
+/* should only be called by aux_bap_read.  This aux function and the
+   following use concepts not documented in the developers guide.  I
+   got them from a patch given to my by Aironet */
+static u16 aux_setup(struct airo_info *ai, u16 page,
+		     u16 offset, u16 *len)
+{
+	u16 next;
+
+	OUT4500(ai, AUXPAGE, page);
+	OUT4500(ai, AUXOFF, 0);
+	next = IN4500(ai, AUXDATA);
+	*len = IN4500(ai, AUXDATA)&0xff;
+	if (offset != 4) OUT4500(ai, AUXOFF, offset);
+	return next;
+}
+
+/* requires call to bap_setup() first */
+static int aux_bap_read(struct airo_info *ai, u16 *pu16Dst,
+		     int bytelen, int whichbap) 
+{
+	u16 len;
+	u16 page;
+	u16 offset;
+	u16 next;
+	int words;
+	int i;
+	int flags;
+
+	spin_lock_irqsave(&ai->aux_lock, flags);
+	page = IN4500(ai, SWS0+whichbap);
+	offset = IN4500(ai, SWS2+whichbap);
+	next = aux_setup(ai, page, offset, &len);
+	words = (bytelen+1)>>1;
+
+	for (i=0; i<words;) {
+		int count;
+		count = (len>>1) < (words-i) ? (len>>1) : (words-i);
+		if ( !do8bitIO ) 
+			insw( ai->dev->base_addr+DATA0+whichbap, 
+			      pu16Dst+i,count );
+		else
+			insb( ai->dev->base_addr+DATA0+whichbap, 
+			      pu16Dst+i, count << 1 );
+		i += count;
+		if (i<words) {
+			next = aux_setup(ai, next, 4, &len);
+		}
+	}
+	spin_unlock_irqrestore(&ai->aux_lock, flags);
+	return SUCCESS;
+}
+
+
+/* requires call to bap_setup() first */
+static int fast_bap_read(struct airo_info *ai, u16 *pu16Dst, 
+			 int bytelen, int whichbap)
+{
+	bytelen = (bytelen + 1) & (~1); // round up to even value
+	if ( !do8bitIO ) 
+		insw( ai->dev->base_addr+DATA0+whichbap, pu16Dst, bytelen>>1 );
+	else
+		insb( ai->dev->base_addr+DATA0+whichbap, pu16Dst, bytelen );
+	return SUCCESS;
+}
+
+/* requires call to bap_setup() first */
+static int bap_write(struct airo_info *ai, const u16 *pu16Src, 
+		     int bytelen, int whichbap)
+{
+	bytelen = (bytelen + 1) & (~1); // round up to even value
+	if ( !do8bitIO ) 
+		outsw( ai->dev->base_addr+DATA0+whichbap, 
+		       pu16Src, bytelen>>1 );
+	else
+		outsb( ai->dev->base_addr+DATA0+whichbap, pu16Src, bytelen );
+	return SUCCESS;
+}
+
+static int PC4500_accessrid(struct airo_info *ai, u16 rid, u16 accmd)
+{
+	Cmd cmd; /* for issuing commands */
+	Resp rsp; /* response from commands */
+	u16 status;
+
+	memset(&cmd, 0, sizeof(cmd));
+	cmd.cmd = accmd;
+	cmd.parm0 = rid;
+	status = issuecommand(ai, &cmd, &rsp);
+	if (status != 0) return status;
+	if ( (rsp.status & 0x7F00) != 0) {
+		return (accmd << 8) + (rsp.rsp0 & 0xFF);
+	}
+	return 0;
+}
+
+/*  Note, that we are using BAP1 which is also used by transmit, so
+ *  we must get a lock. */
+static int PC4500_readrid(struct airo_info *ai, u16 rid, void *pBuf, int len)
+{
+	u16 status;
+        int flags;
+        int rc = SUCCESS;
+
+	spin_lock_irqsave(&ai->bap1_lock, flags);
+	if ( (status = PC4500_accessrid(ai, rid, CMD_ACCESS)) != SUCCESS) {
+                rc = status;
+                goto done;
+        }
+	if (bap_setup(ai, rid, 0, BAP1) != SUCCESS) {
+		rc = status;
+                goto done;
+        }
+	// read the rid length field
+	bap_read(ai, pBuf, 2, BAP1);
+	// length for remaining part of rid
+	len = min(len, le16_to_cpu(*(u16*)pBuf)) - 2;
+	
+	if ( len <= 2 ) {
+		printk( KERN_ERR 
+			"airo: Rid %x has a length of %d which is too short\n",
+			(int)rid,
+			(int)len );
+		rc = ERROR;
+                goto done;
+	}
+	// read remainder of the rid
+	if (bap_setup(ai, rid, 2, BAP1) != SUCCESS) {
+                rc = ERROR;
+                goto done;
+        }
+	rc = bap_read(ai, ((u16*)pBuf)+1, len, BAP1);
+done:
+	spin_unlock_irqrestore(&ai->bap1_lock, flags);
+	return rc;
+}
+
+/*  Note, that we are using BAP1 which is also used by transmit, so
+ *  make sure this isnt called when a transmit is happening */
+static int PC4500_writerid(struct airo_info *ai, u16 rid, 
+			   const void *pBuf, int len)
+{
+	u16 status;
+        int flags;
+	int rc = SUCCESS;
+
+	spin_lock_irqsave(&ai->bap1_lock, flags);
+	// --- first access so that we can write the rid data
+	if ( (status = PC4500_accessrid(ai, rid, CMD_ACCESS)) != 0) {
+                rc = status;
+                goto done;
+        }
+	// --- now write the rid data
+	if (bap_setup(ai, rid, 0, BAP1) != SUCCESS) {
+                rc = ERROR;
+                goto done;
+        }
+	bap_write(ai, pBuf, len, BAP1);
+	// ---now commit the rid data
+	rc = PC4500_accessrid(ai, rid, 0x100|CMD_ACCESS);
+done:
+	spin_unlock_irqrestore(&ai->bap1_lock, flags);
+        return rc;
+}
+
+/* Allocates a FID to be used for transmitting packets.  We only use
+   one for now. */
+static u16 transmit_allocate(struct airo_info *ai, int lenPayload)
+{
+	Cmd cmd;
+	Resp rsp;
+	u16 txFid;
+	u16 txControl;
+        int flags;
+
+	cmd.cmd = CMD_ALLOCATETX;
+	cmd.parm0 = lenPayload;
+	if (issuecommand(ai, &cmd, &rsp) != SUCCESS) return 0;
+	if ( (rsp.status & 0xFF00) != 0) return 0;
+	/* wait for the allocate event/indication
+	 * It makes me kind of nervous that this can just sit here and spin,
+	 * but in practice it only loops like four times. */
+	while ( (IN4500(ai, EVSTAT) & EV_ALLOC) == 0) ;
+	// get the allocated fid and acknowledge
+	txFid = IN4500(ai, TXALLOCFID);
+	OUT4500(ai, EVACK, EV_ALLOC);
+  
+	/*  The CARD is pretty cool since it converts the ethernet packet
+	 *  into 802.11.  Also note that we don't release the FID since we
+	 *  will be using the same one over and over again. */
+	/*  We only have to setup the control once since we are not
+	 *  releasing the fid. */
+	txControl = TXCTL_TXOK | TXCTL_TXEX | TXCTL_802_3
+		| TXCTL_ETHERNET | TXCTL_NORELEASE;
+	spin_lock_irqsave(&ai->bap1_lock, flags);
+	if (bap_setup(ai, txFid, 0x0008, BAP1) != SUCCESS) return ERROR;
+	bap_write(ai, &txControl, sizeof(txControl), BAP1);
+	spin_unlock_irqrestore(&ai->bap1_lock, flags);
+
+	return txFid;
+}
+
+/* In general BAP1 is dedicated to transmiting packets.  However,
+   since we need a BAP when accessing RIDs, we also use BAP1 for that.
+   Make sure the BAP1 spinlock is held when this is called. */
+static int transmit_802_3_packet(struct airo_info *ai, u16 txFid, 
+				 char *pPacket, int len)
+{
+	u16 payloadLen;
+	Cmd cmd;
+	Resp rsp;
+	
+	if (len < 12) {
+		printk( KERN_WARNING "Short packet %d\n", len );
+		return ERROR;
+	}
+	
+	// packet is destination[6], source[6], payload[len-12]
+	// write the payload length and dst/src/payload
+	if (bap_setup(ai, txFid, 0x0036, BAP1) != SUCCESS) return ERROR;
+	/* The hardware addresses aren't counted as part of the payload, so
+	 * we have to subtract the 12 bytes for the addresses off */
+	payloadLen = cpu_to_le16(len - 12);
+	bap_write(ai, &payloadLen, sizeof(payloadLen),BAP1);
+	bap_write(ai, (const u16*)pPacket, len, BAP1);
+	// issue the transmit command
+	memset( &cmd, 0, sizeof( cmd ) );
+	cmd.cmd = CMD_TRANSMIT;
+	cmd.parm0 = txFid;
+	if (issuecommand(ai, &cmd, &rsp) != SUCCESS) return ERROR;
+	if ( (rsp.status & 0xFF00) != 0) return ERROR;
+	return SUCCESS;
+}
+
+/*
+ *  This is the proc_fs routines.  It is a bit messier than I would
+ *  like!  Feel free to clean it up!
+ */
+
+/*
+ *  Unfortunately sometime between 2.0 and 2.2 the proc interface changed...
+ *  Unfortunately I dont know when it was...
+ *  Im guessing it is sometime around 0x20155...  Anybody know?
+ */
+
+#if (LINUX_VERSION_CODE > 0x20155)
+static ssize_t proc_read( struct file *file,
+			  char *buffer,
+			  size_t len,
+			  loff_t *offset);
+
+static ssize_t proc_write( struct file *file,
+			   const char *buffer,
+			   size_t len,
+			   loff_t *offset );
+static int proc_close( struct inode *inode, struct file *file );
+#else
+static int proc_read( struct inode *inode,
+		      struct file *file,
+		      char *buffer,
+		      int len );
+
+static int proc_write( struct inode *inode,
+		       struct file *file,
+		       const char *buffer,
+		       int len );
+static void proc_close( struct inode *inode, struct file *file );
+#endif
+
+static int proc_stats_open( struct inode *inode, struct file *file );
+static int proc_statsdelta_open( struct inode *inode, struct file *file );
+static int proc_status_open( struct inode *inode, struct file *file );
+static int proc_SSID_open( struct inode *inode, struct file *file );
+static int proc_config_open( struct inode *inode, struct file *file );
+static int proc_wepkey_open( struct inode *inode, struct file *file );
+
+
+static struct file_operations proc_statsdelta_ops = {
+	read:           proc_read,
+	open:           proc_statsdelta_open,
+	release:        proc_close
+};
+
+static struct inode_operations proc_inode_statsdelta_ops = {
+	&proc_statsdelta_ops};
+
+static struct file_operations proc_stats_ops = {
+	read:           proc_read,
+	open:           proc_stats_open,
+	release:        proc_close
+};
+
+static struct inode_operations proc_inode_stats_ops = {
+	&proc_stats_ops};
+
+static struct file_operations proc_status_ops = {
+	read:            proc_read,
+	open:            proc_status_open,
+	release:         proc_close
+};
+
+static struct inode_operations proc_inode_status_ops = {
+	&proc_status_ops};
+
+static struct file_operations proc_SSID_ops = {
+	read:          proc_read,
+	write:         proc_write,
+	open:          proc_SSID_open,
+	release:       proc_close
+};
+
+static struct inode_operations proc_inode_SSID_ops = {
+	&proc_SSID_ops};
+
+static struct file_operations proc_config_ops = {
+	read:          proc_read,
+	write:         proc_write,
+	open:          proc_config_open,
+	release:       proc_close
+};
+
+static struct inode_operations proc_inode_config_ops = {
+	&proc_config_ops};
+
+static struct file_operations proc_wepkey_ops = {
+	read:          proc_read,
+	write:         proc_write,
+	open:          proc_wepkey_open,
+	release:       proc_close
+};
+
+static struct inode_operations proc_inode_wepkey_ops = {
+	&proc_wepkey_ops};
+
+#if ((LINUX_VERSION_CODE > 0x20155) && (LINUX_VERSION_CODE < 0x20311))
+/*
+ * We need to do reference counting here.  When the inode is first used,
+ * this will be called with fill non-zero.  When it is released this
+ * will be called with fill set to zero.
+ */
+static void airo_fill_inode( struct inode *i, int fill ) {
+	if ( fill ) {
+		MOD_INC_USE_COUNT;
+	} else {
+		MOD_DEC_USE_COUNT;
+	}
+}
+#endif
+
+static struct file_operations airo_file_ops = {
+	NULL, // lseek
+	NULL, // read
+	NULL, // write
+	NULL, // readdir
+	NULL, // select
+	NULL, // ioctl
+	NULL, // mmap
+	NULL, // open
+	NULL, // release
+};
+
+static struct inode_operations airo_inode_ops = {
+	&airo_file_ops,
+	NULL, // create
+	NULL, // lookup
+};
+
+#if (LINUX_VERSION_CODE < 0x20311)
+static struct proc_dir_entry airo_entry = {
+	0,
+	7,
+	"aironet",
+	S_IFDIR | S_IRUGO | S_IXUGO,
+	1,
+	0, 0,
+	44,
+	&airo_inode_ops,
+	0, // get_info
+#if ((LINUX_VERSION_CODE > 0x20155) && (LINUX_VERSION_CODE < 0x20311))
+	airo_fill_inode
+#endif
+};
+#else
+static struct proc_dir_entry *airo_entry = 0;
+#endif
+
+#if (LINUX_VERSION_CODE < 0x20311)
+static struct proc_dir_entry wepkey_entry = {
+	0, 6, "WepKey",
+	S_IFREG | S_IWUSR, 2, 0, 0,
+	13,
+	&proc_inode_wepkey_ops, NULL
+};
+
+static struct proc_dir_entry statsdelta_entry = {
+	0, 10, "StatsDelta",
+	S_IFREG | S_IRUGO | S_IWUSR , 2, 0, 0,
+	13,
+	&proc_inode_statsdelta_ops, NULL
+};
+
+static struct proc_dir_entry stats_entry = {
+	0, 5, "Stats",
+	S_IFREG | S_IRUGO , 2, 0, 0,
+	13,
+	&proc_inode_stats_ops, NULL
+};
+
+static struct proc_dir_entry status_entry = {
+	0, 6, "Status",
+	S_IFREG | S_IRUGO , 2, 0, 0,
+	13,
+	&proc_inode_status_ops, NULL
+};
+
+static struct proc_dir_entry SSID_entry = {
+	0, 4, "SSID",
+	S_IFREG | S_IRUGO | S_IWUSR, 2, 0, 0,
+	13,
+	&proc_inode_SSID_ops, NULL
+};
+
+static struct proc_dir_entry config_entry = {
+	0, 6, "Config",
+	S_IFREG | S_IRUGO | S_IWUSR, 2, 0, 0,
+	13,
+	&proc_inode_config_ops, NULL
+};
+#endif
+
+struct proc_data {
+	int release_buffer;
+	int readlen;
+	char *rbuffer;
+	int writelen;
+	int maxwritelen;
+	char *wbuffer;
+	void (*on_close) (struct inode *, struct file *);
+};
+
+#if (LINUX_VERSION_CODE < 0x20311)
+static int setup_proc_entry( struct net_device *dev,
+			     struct airo_info *apriv ) {
+	/* First setup the device directory */
+	memset( &apriv->proc_entry, 0, sizeof( apriv->proc_entry ) );
+	apriv->proc_entry.namelen = strlen( dev->name );
+	apriv->proc_entry.name = dev->name;
+	apriv->proc_entry.mode = S_IFDIR | S_IRUGO | S_IXUGO;
+	apriv->proc_entry.nlink = 2;
+	apriv->proc_entry.ops = airo_entry.ops;
+	PROC_REGISTER( &airo_entry, &apriv->proc_entry );
+	
+	/* Setup the StatsDelta */
+	memcpy( &apriv->proc_statsdelta_entry, &statsdelta_entry, 
+		sizeof( statsdelta_entry ) );
+	apriv->proc_statsdelta_entry.data = dev;
+	PROC_REGISTER( &apriv->proc_entry, 
+		       &apriv->proc_statsdelta_entry );
+	
+	/* Setup the Stats */
+	memcpy( &apriv->proc_stats_entry, &stats_entry, 
+		sizeof( stats_entry ) );
+	apriv->proc_stats_entry.data = dev;
+	PROC_REGISTER( &apriv->proc_entry, 
+		       &apriv->proc_stats_entry );
+	
+	/* Setup the Status */
+	memcpy( &apriv->proc_status_entry, &status_entry, 
+		sizeof( status_entry ) );
+	apriv->proc_status_entry.data = dev;
+	PROC_REGISTER( &apriv->proc_entry, 
+		       &apriv->proc_status_entry );
+	
+	/* Setup the Config */
+	memcpy( &apriv->proc_config_entry, &config_entry, 
+		sizeof( config_entry ) );
+	apriv->proc_config_entry.data = dev;
+	PROC_REGISTER( &apriv->proc_entry, 
+		       &apriv->proc_config_entry );
+
+	/* Setup the SSID */
+	memcpy( &apriv->proc_SSID_entry, &SSID_entry, sizeof( SSID_entry ) );
+	apriv->proc_SSID_entry.data = dev;
+	PROC_REGISTER( &apriv->proc_entry, 
+		       &apriv->proc_SSID_entry );
+	
+	/* Setup the WepKey */
+	memcpy( &apriv->proc_wepkey_entry, &wepkey_entry, 
+		sizeof( wepkey_entry ) );
+	apriv->proc_wepkey_entry.data = dev;
+	PROC_REGISTER( &apriv->proc_entry, 
+		       &apriv->proc_wepkey_entry );
+	
+	return 0;
+}
+
+static int takedown_proc_entry( struct net_device *dev,
+				struct airo_info *apriv ) {
+	if ( !apriv->proc_entry.namelen ) return 0;
+	PROC_UNREGISTER( &apriv->proc_entry, &apriv->proc_statsdelta_entry );
+	PROC_UNREGISTER( &apriv->proc_entry, &apriv->proc_stats_entry );
+	PROC_UNREGISTER( &apriv->proc_entry, &apriv->proc_status_entry );
+	PROC_UNREGISTER( &apriv->proc_entry, &apriv->proc_config_entry );
+	PROC_UNREGISTER( &apriv->proc_entry, &apriv->proc_SSID_entry );
+	PROC_UNREGISTER( &apriv->proc_entry, &apriv->proc_wepkey_entry );
+	PROC_UNREGISTER( &airo_entry, &apriv->proc_entry );
+	return 0;
+}
+#else
+static int setup_proc_entry( struct net_device *dev,
+			     struct airo_info *apriv ) {
+	struct proc_dir_entry *entry;
+	/* First setup the device directory */
+	apriv->proc_entry = create_proc_entry(dev->name,
+					      S_IFDIR|S_IRUGO|S_IXUGO,
+					      airo_entry);
+	/* Setup the StatsDelta */
+	entry = create_proc_entry("StatsDelta",
+				  S_IFREG | S_IRUGO | S_IWUSR,
+				  apriv->proc_entry);
+	entry->data = dev;
+/*	This is what was needed right up to the last few versions
+        of 2.3:
+	entry->ops = &proc_inode_statsdelta_ops;
+*/
+	entry->proc_fops = &proc_statsdelta_ops;
+	
+	/* Setup the Stats */
+	entry = create_proc_entry("Stats",
+				  S_IFREG | S_IRUGO,
+				  apriv->proc_entry);
+	entry->data = dev;
+	entry->proc_fops = &proc_stats_ops;
+	
+	/* Setup the Status */
+	entry = create_proc_entry("Status",
+				  S_IFREG | S_IRUGO,
+				  apriv->proc_entry);
+	entry->data = dev;
+	entry->proc_fops = &proc_status_ops;
+	
+	/* Setup the Config */
+	entry = create_proc_entry("Config",
+				  S_IFREG | S_IRUGO | S_IWUGO,
+				  apriv->proc_entry);
+	entry->data = dev;
+	entry->proc_fops = &proc_config_ops;
+
+	/* Setup the SSID */
+	entry = create_proc_entry("SSID",
+				  S_IFREG | S_IRUGO | S_IWUGO,
+				  apriv->proc_entry);
+	entry->data = dev;
+	entry->proc_fops = &proc_SSID_ops;
+
+	/* Setup the WepKey */
+	entry = create_proc_entry("WepKey",
+				  S_IFREG | S_IWUSR,
+				  apriv->proc_entry);
+	entry->data = dev;
+	entry->proc_fops = &proc_wepkey_ops;
+
+	return 0;
+}
+
+static int takedown_proc_entry( struct net_device *dev,
+				struct airo_info *apriv ) {
+	if ( !apriv->proc_entry->namelen ) return 0;
+	remove_proc_entry("Stats",apriv->proc_entry);
+	remove_proc_entry("StatsDelta",apriv->proc_entry);
+	remove_proc_entry("Status",apriv->proc_entry);
+	remove_proc_entry("Config",apriv->proc_entry);
+	remove_proc_entry("SSID",apriv->proc_entry);
+	remove_proc_entry("WepKey",apriv->proc_entry);
+	remove_proc_entry(dev->name,airo_entry);
+	return 0;
+}
+#endif
+
+/*
+ *  What we want from the proc_fs is to be able to efficiently read
+ *  and write the configuration.  To do this, we want to read the
+ *  configuration when the file is opened and write it when the file is
+ *  closed.  So basically we allocate a read buffer at open and fill it
+ *  with data, and allocate a write buffer and read it at close.
+ */
+
+/*
+ *  The read routine is generic, it relies on the preallocated rbuffer
+ *  to supply the data.
+ */
+#if (LINUX_VERSION_CODE > 0x20155)
+static ssize_t proc_read( struct file *file,
+			  char *buffer,
+			  size_t len,
+			  loff_t *offset )
+#else
+static int proc_read( struct inode *inode,
+		      struct file *file,
+		      char *buffer,
+		      int len ) 
+#endif
+{
+	int i;
+	int pos;
+	struct proc_data *priv = (struct proc_data*)file->private_data;
+	
+	if( !priv->rbuffer ) return -EINVAL;
+	
+#if (LINUX_VERSION_CODE > 0x20155)
+	pos = *offset;
+#else
+	pos = file->f_pos;
+#endif
+	for( i = 0; i+pos < priv->readlen && i < len; i++ ) {
+		put_user( priv->rbuffer[i+pos], buffer+i );
+	}
+#if (LINUX_VERSION_CODE > 0x20155)
+	*offset += i;
+#else
+	file->f_pos += i;
+#endif
+	return i;
+}
+
+/*
+ *  The write routine is generic, it fills in a preallocated rbuffer
+ *  to supply the data.
+ */
+#if (LINUX_VERSION_CODE > 0x20155)
+static ssize_t proc_write( struct file *file,
+			   const char *buffer,
+			   size_t len,
+			   loff_t *offset ) 
+#else
+static int proc_write( struct inode *inode,
+		       struct file *file,
+		       const char *buffer,
+		       int len ) 
+#endif
+{
+	int i;
+	int pos;
+	struct proc_data *priv = (struct proc_data*)file->private_data;
+	
+	if ( !priv->wbuffer ) {
+		return -EINVAL;
+	}
+	
+#if (LINUX_VERSION_CODE > 0x20155)
+	pos = *offset;
+#else
+	pos = file->f_pos;
+#endif
+	
+	for( i = 0; i + pos <  priv->maxwritelen &&
+		     i < len; i++ ) {
+#if (LINUX_VERSION_CODE > 0x20155)
+		get_user( priv->wbuffer[i+pos], buffer + i );
+#else
+		priv->wbuffer[i+pos] = get_user( buffer + i );
+#endif
+	}
+	if ( i+pos > priv->writelen ) priv->writelen = i+file->f_pos;
+#if (LINUX_VERSION_CODE > 0x20155)
+	*offset += i;
+#else
+	file->f_pos += i;
+#endif
+	return i;
+}
+
+static int proc_status_open( struct inode *inode, struct file *file ) {
+	struct proc_data *data;
+	struct proc_dir_entry *dp = inode->u.generic_ip;
+	struct net_device *dev = dp->data;
+	struct airo_info *apriv = (struct airo_info *)dev->priv;
+	CapabilityRid cap_rid;
+	StatusRid status_rid;
+	
+	MOD_INC_USE_COUNT;
+	
+	dp = (struct proc_dir_entry *) inode->u.generic_ip;
+	
+	file->private_data = kmalloc(sizeof(struct proc_data ), GFP_KERNEL);
+	memset(file->private_data, 0, sizeof(struct proc_data));
+	data = (struct proc_data *)file->private_data;
+	data->rbuffer = kmalloc( 2048, GFP_KERNEL );
+	
+	PC4500_readrid(apriv, 0xFF50, &status_rid,
+		       sizeof(status_rid));
+	PC4500_readrid(apriv, 0xFF00, &cap_rid,
+		       sizeof(cap_rid));
+	
+	sprintf( data->rbuffer, "Mode: %x\n"
+		 "Signal Strength: %d\n"
+		 "Signal Quality: %d\n"
+		 "SSID: %-.*s\n"
+		 "AP: %-.16s\n"
+		 "Freq: %d\n"
+		 "BitRate: %dmbs\n"
+		 "Driver Version: %s\n"
+		 "Device: %s\nManufacturer: %s\nFirmware Version: %s\n"
+		 "Radio type: %x\nCountry: %x\nHardware Version: %x\n"
+		 "Software Version: %x\nSoftware Subversion: %x\n"
+		 "Boot block version: %x\n",
+		 (int)le16_to_cpu(status_rid.mode),
+		 (int)le16_to_cpu(status_rid.normalizedSignalStrength),
+		 (int)le16_to_cpu(status_rid.signalQuality),
+		 (int)status_rid.SSIDlen,
+		 status_rid.SSID,
+		 status_rid.apName,
+		 (int)le16_to_cpu(status_rid.channel),
+		 (int)le16_to_cpu(status_rid.currentXmitRate)/2,
+		 version,
+		 cap_rid.prodName,
+		 cap_rid.manName,
+		 cap_rid.prodVer,
+		 le16_to_cpu(cap_rid.radioType),
+		 le16_to_cpu(cap_rid.country),
+		 le16_to_cpu(cap_rid.hardVer),
+		 (int)le16_to_cpu(cap_rid.softVer),
+		 (int)le16_to_cpu(cap_rid.softSubVer),
+		 (int)le16_to_cpu(cap_rid.bootBlockVer) );
+	data->readlen = strlen( data->rbuffer );
+	return 0;
+}
+
+static int proc_stats_rid_open(struct inode*, struct file*, u16);
+static int proc_statsdelta_open( struct inode *inode, 
+				 struct file *file ) {
+	if (file->f_mode&FMODE_WRITE) {
+	return proc_stats_rid_open(inode, file, RID_STATSDELTACLEAR);
+	}
+	return proc_stats_rid_open(inode, file, RID_STATSDELTA);
+}
+
+static int proc_stats_open( struct inode *inode, struct file *file ) {
+	return proc_stats_rid_open(inode, file, RID_STATS);
+}
+
+static int proc_stats_rid_open( struct inode *inode, 
+				struct file *file,
+				u16 rid ) {
+	struct proc_data *data;
+	struct proc_dir_entry *dp = inode->u.generic_ip;
+	struct net_device *dev = dp->data;
+	struct airo_info *apriv = (struct airo_info *)dev->priv;
+	char buffer[1024];
+	int i, j;
+	int *vals = (int*)&buffer[4];
+	MOD_INC_USE_COUNT;
+	
+	
+	dp = (struct proc_dir_entry *) inode->u.generic_ip;
+	
+	file->private_data = kmalloc(sizeof(struct proc_data ), GFP_KERNEL);
+	memset(file->private_data, 0, sizeof(struct proc_data));
+	data = (struct proc_data *)file->private_data;
+	data->rbuffer = kmalloc( 4096, GFP_KERNEL );
+	
+	PC4500_readrid(apriv, rid, buffer,
+		       sizeof(buffer));
+
+        j = 0;
+	for(i=0; (int)statsLabels[i]!=-1 && 
+		    i*4<le16_to_cpu(*(u16*)buffer); i++){
+                if (!statsLabels[i]) continue;
+		if (j+strlen(statsLabels[i])+16>4096) {
+			printk(KERN_WARNING
+			       "airo: Potentially disasterous buffer overflow averted!\n");
+			break;
+		}
+		j+=sprintf( data->rbuffer+j, "%s: %d\n",statsLabels[i],
+			    le32_to_cpu(vals[i]));
+        }
+	if (i*4>=le16_to_cpu(*(u16*)buffer)){
+		printk(KERN_WARNING
+		       "airo: Got a short rid\n");
+	}
+	data->readlen = j;
+	return 0;
+}
+
+static int get_dec_u16( char *buffer, int *start, int limit ) {
+	u16 value;
+	int valid = 0;
+	for( value = 0; buffer[*start] >= '0' &&
+		     buffer[*start] <= '9' &&
+		     *start < limit; (*start)++ ) {
+		valid = 1;
+		value *= 10;
+		value += buffer[*start] - '0';
+	}
+	if ( !valid ) return -1;
+	return value;
+}
+
+static void proc_config_on_close( struct inode *inode, struct file *file ) {
+	struct proc_data *data = file->private_data;
+	struct proc_dir_entry *dp = inode->u.generic_ip;
+	struct net_device *dev = dp->data;
+	struct airo_info *ai = (struct airo_info*)dev->priv;
+	ConfigRid config;
+	Cmd cmd;
+	Resp rsp;
+	char *line;
+	
+	if ( !data->writelen ) return;
+	dp = (struct proc_dir_entry *) inode->u.generic_ip;
+	
+	memset(&cmd, 0, sizeof(Cmd));
+	cmd.cmd = MAC_DISABLE; // disable in case already enabled
+	issuecommand(ai, &cmd, &rsp);
+	PC4500_readrid(ai, RID_ACTUALCONFIG, &config,
+		       sizeof(config));
+
+	line = data->wbuffer;
+	while( line[0] ) {
+		/*** Mode processing */
+		if ( !strncmp( line, "Mode: ", 6 ) ) {
+			line += 6;
+			if ( line[0] == 'a' ) config.opmode = 0;
+			else config.opmode = cpu_to_le16(1);
+		}
+		
+		/*** Radio status */
+		else if (!strncmp(line,"Radio: ", 7)) {
+			line += 7;
+			if (!strncmp(line,"off",3)) {
+				ai->flags |= FLAG_RADIO_OFF;
+			} else {
+				ai->flags &= ~FLAG_RADIO_OFF;
+			}
+		}
+		/*** NodeName processing */
+		else if ( !strncmp( line, "NodeName: ", 10 ) ) {
+			int j;
+			
+			line += 10;
+			memset( config.nodeName, 0, 16 );
+			/* Do the name, assume a space between the mode and node name */
+			for( j = 0; j < 16 && line[j] != '\n'; j++ ) {
+				config.nodeName[j] = line[j];
+			}
+		} 
+		
+		/*** PowerMode processing */
+		else if ( !strncmp( line, "PowerMode: ", 11 ) ) {
+			line += 11;
+			if ( !strncmp( line, "PSPCAM", 6 ) ) {
+				config.powerSaveMode = 
+					cpu_to_le16(POWERSAVE_PSPCAM);
+			} else if ( !strncmp( line, "PSP", 3 ) ) {
+				config.powerSaveMode = 
+					cpu_to_le16(POWERSAVE_PSP);
+			} else {
+				config.powerSaveMode = 
+					cpu_to_le16(POWERSAVE_CAM);
+			}	
+		} else if ( !strncmp( line, "DataRates: ", 11 ) ) {
+			int v, i = 0, k = 0; /* i is index into line, 
+						k is index to rates */
+			
+			line += 11;
+			while((v = get_dec_u16(line, &i, 3))!=-1) {
+				config.rates[k++] = (u8)v;
+				line += i + 1;
+				i = 0;
+			}
+		} else if ( !strncmp( line, "Channel: ", 9 ) ) {
+			int v, i = 0;
+			line += 9;
+			v = get_dec_u16(line, &i, i+3);
+			if ( v != -1 ) 
+				config.channelSet = (u16)cpu_to_le16(v);
+		} else if ( !strncmp( line, "XmitPower: ", 11 ) ) {
+			int v, i = 0;
+			line += 11;
+			v = get_dec_u16(line, &i, i+3);
+			if ( v != -1 ) config.txPower = 
+					       (u16)cpu_to_le16(v);
+		} else if ( !strncmp( line, "WEP: ", 5 ) ) {
+			line += 5;
+			switch( line[0] ) {
+			case 's':
+				config.authType = cpu_to_le16(AUTH_SHAREDKEY);
+				break;
+			case 'e':
+				config.authType = cpu_to_le16(AUTH_ENCRYPT);
+				break;
+			default:
+				config.authType = cpu_to_le16(AUTH_OPEN);
+				break;
+			}
+		} else if ( !strncmp( line, "LongRetryLimit: ", 16 ) ) {
+			int v, i = 0;
+			
+			line += 16;
+			v = get_dec_u16(line, &i, 3);
+			v = (v<0) ? 0 : ((v>255) ? 255 : v);
+			config.longRetryLimit = (u16)cpu_to_le16(v);
+		} else if ( !strncmp( line, "ShortRetryLimit: ", 17 ) ) {
+			int v, i = 0;
+			
+			line += 17;
+			v = get_dec_u16(line, &i, 3);
+			v = (v<0) ? 0 : ((v>255) ? 255 : v);
+			config.shortRetryLimit = (u16)cpu_to_le16(v);
+		} else if ( !strncmp( line, "RTSThreshold: ", 14 ) ) {
+			int v, i = 0;
+			
+			line += 14;
+			v = get_dec_u16(line, &i, 4);
+			v = (v<0) ? 0 : ((v>2312) ? 2312 : v);
+			config.rtsThres = (u16)cpu_to_le16(v);
+		} else if ( !strncmp( line, "TXMSDULifetime: ", 16 ) ) {
+			int v, i = 0;
+			
+			line += 16;
+			v = get_dec_u16(line, &i, 5);
+			v = (v<0) ? 0 : v;
+			config.txLifetime = (u16)cpu_to_le16(v);
+		} else if ( !strncmp( line, "RXMSDULifetime: ", 16 ) ) {
+			int v, i = 0;
+			
+			line += 16;
+			v = get_dec_u16(line, &i, 5);
+			v = (v<0) ? 0 : v;
+			config.rxLifetime = (u16)cpu_to_le16(v);
+		} else if ( !strncmp( line, "TXDiversity: ", 13 ) ) {
+			config.txDiversity = 
+				(line[13]=='l') ? cpu_to_le16(1) :
+				((line[13]=='r')? cpu_to_le16(2):
+				 cpu_to_le16(3));
+		} else if ( !strncmp( line, "RXDiversity: ", 13 ) ) {
+			config.rxDiversity = 
+				(line[13]=='l') ? cpu_to_le16(1) :
+				((line[13]=='r')? cpu_to_le16(2):
+				 cpu_to_le16(3));
+		} else if ( !strncmp( line, "FragThreshold: ", 15 ) ) {
+			int v, i = 0;
+			
+			line += 15;
+			v = get_dec_u16(line, &i, 4);
+			v = (v<256) ? 256 : ((v>2312) ? 2312 : v);
+			v = v & 0xfffe; /* Make sure its even */
+			config.fragThresh = (u16)cpu_to_le16(v);
+		} else if (!strncmp(line, "Modulation: ", 12)) {
+		        line += 12;
+			switch(*line) {
+			case 'd':  config.modulation=MOD_DEFAULT; break;
+			case 'c':  config.modulation=MOD_CCK; break;
+			case 'm':  config.modulation=MOD_MOK; break;
+			default:
+				printk( KERN_WARNING "airo: Unknown modulation\n" );
+			}
+		} else {
+			printk( KERN_WARNING "Couldn't figure out %s\n", line );
+		}
+		while( line[0] && line[0] != '\n' ) line++;
+		if ( line[0] ) line++;
+	}
+	ai->config = config;
+	PC4500_writerid(ai, RID_CONFIG, &config,
+			sizeof(config));
+	enable_MAC(ai, &rsp);
+}
+
+static int proc_config_open( struct inode *inode, struct file *file ) {
+	struct proc_data *data;
+	struct proc_dir_entry *dp = inode->u.generic_ip;
+	struct net_device *dev = dp->data;
+	struct airo_info *ai = (struct airo_info*)dev->priv;
+	ConfigRid config;
+	int i;
+	
+	MOD_INC_USE_COUNT;
+	
+	dp = (struct proc_dir_entry *) inode->u.generic_ip;
+	
+	file->private_data = kmalloc(sizeof(struct proc_data ), GFP_KERNEL);
+	memset(file->private_data, 0, sizeof(struct proc_data));
+	data = (struct proc_data *)file->private_data;
+	data->rbuffer = kmalloc( 2048, GFP_KERNEL );
+	data->wbuffer = kmalloc( 2048, GFP_KERNEL );
+	memset( data->wbuffer, 0, 2048 );
+	data->maxwritelen = 2048;
+	data->on_close = proc_config_on_close;
+	
+	PC4500_readrid(ai, RID_ACTUALCONFIG, &config,
+		       sizeof(config));
+	
+	i = sprintf( data->rbuffer, 
+		     "Mode: %s\n"
+		     "Radio: %s\n"
+		     "NodeName: %-16s\n"
+		     "PowerMode: %s\n"
+		     "DataRates: %d %d %d %d %d %d %d %d\n"
+		     "Channel: %d\n"
+		     "XmitPower: %d\n",
+		     config.opmode == 0 ? "adhoc" : 
+		     config.opmode == 1 ? "ESS" : "Error",
+		     ai->flags&FLAG_RADIO_OFF ? "off" : "on",
+		     config.nodeName,
+		     config.powerSaveMode == 0 ? "CAM" :
+		     config.powerSaveMode == 1 ? "PSP" :
+		     config.powerSaveMode == 2 ? "PSPCAM" : "Error",
+		     (int)config.rates[0],
+		     (int)config.rates[1],
+		     (int)config.rates[2],
+		     (int)config.rates[3],
+		     (int)config.rates[4],
+		     (int)config.rates[5],
+		     (int)config.rates[6],
+		     (int)config.rates[7],
+		     (int)le16_to_cpu(config.channelSet),
+		     (int)le16_to_cpu(config.txPower)
+		);
+	sprintf( data->rbuffer + i,
+		 "LongRetryLimit: %d\n"
+		 "ShortRetryLimit: %d\n"
+		 "RTSThreshold: %d\n"
+		 "TXMSDULifetime: %d\n"
+		 "RXMSDULifetime: %d\n"
+		 "TXDiversity: %s\n"
+		 "RXDiversity: %s\n"
+		 "FragThreshold: %d\n"
+		 "WEP: %s\n"
+		 "Modulation: %s\n",
+		 (int)le16_to_cpu(config.longRetryLimit),
+		 (int)le16_to_cpu(config.shortRetryLimit),
+		 (int)le16_to_cpu(config.rtsThres),
+		 (int)le16_to_cpu(config.txLifetime),
+		 (int)le16_to_cpu(config.rxLifetime),
+		 config.txDiversity == 1 ? "left" :
+		 config.txDiversity == 2 ? "right" : "both",
+		 config.rxDiversity == 1 ? "left" :
+		 config.rxDiversity == 2 ? "right" : "both",
+		 (int)le16_to_cpu(config.fragThresh),
+		 config.authType == AUTH_ENCRYPT ? "encrypt" :
+		 config.authType == AUTH_SHAREDKEY ? "shared" : "open",
+		 config.modulation == 0 ? "default" :
+		 config.modulation == MOD_CCK ? "cck" :
+		 config.modulation == MOD_MOK ? "mok" : "error"
+		);
+	data->readlen = strlen( data->rbuffer );
+	return 0;
+}
+
+static void proc_SSID_on_close( struct inode *inode, struct file *file ) {
+	struct proc_data *data = (struct proc_data *)file->private_data;
+	struct proc_dir_entry *dp = inode->u.generic_ip;
+	struct net_device *dev = dp->data;
+	struct airo_info *ai = (struct airo_info*)dev->priv;
+	SsidRid SSID_rid;
+	int i;
+	int offset = 0;
+	
+	if ( !data->writelen ) return;
+	
+	memset( &SSID_rid, 0, sizeof( SSID_rid ) );
+	
+	for( i = 0; i < 3; i++ ) {
+		int j;
+		for( j = 0; j+offset < data->writelen && j < 32 &&
+			     data->wbuffer[offset+j] != '\n'; j++ ) {
+			SSID_rid.ssids[i].ssid[j] = data->wbuffer[offset+j];
+		}
+		if ( j == 0 ) break;
+		SSID_rid.ssids[i].len = cpu_to_le16(j);
+		offset += j;
+		while( data->wbuffer[offset] != '\n' && 
+		       offset < data->writelen ) offset++;
+		offset++;
+	}
+	do_writerid(ai, RID_SSID, &SSID_rid, sizeof( SSID_rid ));
+}
+
+/* This function wraps PC4500_writerid with a MAC disable */
+static int do_writerid( struct airo_info *ai, u16 rid, const void *rid_data,
+			int len ) {
+	int rc;
+	Cmd cmd;
+	Resp rsp;
+	
+	memset(&cmd, 0, sizeof(cmd));
+	cmd.cmd = MAC_DISABLE; // disable in case already enabled
+	issuecommand(ai, &cmd, &rsp);
+	rc = PC4500_writerid(ai, 
+			     rid, rid_data, len);
+	enable_MAC(ai, &rsp);
+	return rc;
+}
+
+static int set_wep_key(struct airo_info *ai, const char *key, u16 keylen ) {
+	static const unsigned char macaddr[6] = { 0x01, 0, 0, 0, 0, 0 };
+	WepKeyRid wkr;
+        int rc;
+
+	wkr.len = cpu_to_le16(sizeof(wkr));
+	wkr.kindex = cpu_to_le16(0);
+	wkr.klen = cpu_to_le16(keylen);
+	memcpy( wkr.key, key, keylen );
+	memcpy( wkr.mac, macaddr, 6 );
+	rc = do_writerid(ai, RID_WEP_TEMP, &wkr, sizeof(wkr));
+        if (rc!=SUCCESS) printk(KERN_ERR "airo:  WEP_TEMP set %x\n", rc); 
+	rc = do_writerid(ai, RID_WEP_PERM, &wkr, sizeof(wkr));
+        if (rc!=SUCCESS) printk(KERN_ERR "airo:  WEP_PERM set %x\n", rc);
+	return 0;
+}
+
+static u8 hexVal(char c) {
+	if (c>='0' && c<='9') return c -= '0';
+	if (c>='a' && c<='f') return c -= 'a'-10;
+	if (c>='A' && c<='F') return c -= 'A'-10;
+	return 0;
+}
+
+static void proc_wepkey_on_close( struct inode *inode, struct file *file ) {
+	struct proc_data *data;
+	struct proc_dir_entry *dp = inode->u.generic_ip;
+	struct net_device *dev = dp->data;
+	struct airo_info *ai = (struct airo_info*)dev->priv;
+	int i;
+	char key[16];
+
+	memset(key, 0, sizeof(key));
+	
+	dp = (struct proc_dir_entry *) inode->u.generic_ip;
+	data = (struct proc_data *)file->private_data;
+	if ( !data->writelen ) return;
+	
+	for( i = 0; i < 16*3 && data->wbuffer[i]; i++ ) {
+		switch(i%3) {
+		case 0:
+			key[i/3] = hexVal(data->wbuffer[i])<<4;
+			break;
+		case 1:
+			key[i/3] |= hexVal(data->wbuffer[i]);
+			break;
+		}
+	}
+	set_wep_key(ai, key, i/3);
+}
+
+static int proc_wepkey_open( struct inode *inode, struct file *file ) {
+	struct proc_data *data;
+	struct proc_dir_entry *dp = inode->u.generic_ip;
+	struct net_device *dev = dp->data;
+	struct airo_info *ai = (struct airo_info*)dev->priv;
+	char *ptr;
+	WepKeyRid wkr;
+	
+	MOD_INC_USE_COUNT;
+	
+	dp = (struct proc_dir_entry *) inode->u.generic_ip;
+	
+	file->private_data = kmalloc(sizeof(struct proc_data ), GFP_KERNEL);
+	memset(file->private_data, 0, sizeof(struct proc_data));
+	memset(&wkr, 0, sizeof(wkr));
+	data = (struct proc_data *)file->private_data;
+	data->rbuffer = kmalloc( 80, GFP_KERNEL );
+	data->writelen = 0;
+	data->maxwritelen = 80;
+	data->wbuffer = kmalloc( 80, GFP_KERNEL );
+	memset( data->wbuffer, 0, 80 );
+	data->on_close = proc_wepkey_on_close;
+	
+	PC4500_readrid(ai, RID_WEP_PERM, &wkr, sizeof(wkr));
+	ptr = data->rbuffer;
+	sprintf(ptr, "The wep key cannot be read\n");
+	data->readlen = strlen( data->rbuffer );
+	return 0;
+}
+
+static int proc_SSID_open( struct inode *inode, struct file *file ) {
+	struct proc_data *data;
+	struct proc_dir_entry *dp = inode->u.generic_ip;
+	struct net_device *dev = dp->data;
+	struct airo_info *ai = (struct airo_info*)dev->priv;
+	int i;
+	char *ptr;
+	SsidRid SSID_rid;
+
+	MOD_INC_USE_COUNT;
+	
+	dp = (struct proc_dir_entry *) inode->u.generic_ip;
+	
+	file->private_data = kmalloc(sizeof(struct proc_data ), GFP_KERNEL);
+	memset(file->private_data, 0, sizeof(struct proc_data));
+	data = (struct proc_data *)file->private_data;
+	data->rbuffer = kmalloc( 104, GFP_KERNEL );
+	data->writelen = 0;
+	data->maxwritelen = 33*3;
+	data->wbuffer = kmalloc( 33*3, GFP_KERNEL );
+	memset( data->wbuffer, 0, 33*3 );
+	data->on_close = proc_SSID_on_close;
+	
+	PC4500_readrid(ai, RID_SSID, 
+		       &SSID_rid, sizeof( SSID_rid ));
+	ptr = data->rbuffer;
+	for( i = 0; i < 3; i++ ) {
+		int j;
+		if ( !SSID_rid.ssids[i].len ) break;
+		for( j = 0; j < 32 && 
+			     j < le16_to_cpu(SSID_rid.ssids[i].len) && 
+			     SSID_rid.ssids[i].ssid[j]; j++ ) {
+			*ptr++ = SSID_rid.ssids[i].ssid[j]; 
+		}
+		*ptr++ = '\n';
+	}
+	*ptr = '\0';
+	data->readlen = strlen( data->rbuffer );
+	return 0;
+}
+
+#if (LINUX_VERSION_CODE > 0x20155)
+static int proc_close( struct inode *inode, struct file *file ) 
+#else
+static void proc_close( struct inode *inode, struct file *file ) 
+#endif
+{
+	struct proc_data *data = (struct proc_data *)file->private_data;
+	if ( data->on_close != NULL ) data->on_close( inode, file );
+	MOD_DEC_USE_COUNT;
+	if ( data->rbuffer ) kfree( data->rbuffer );
+	if ( data->wbuffer ) kfree( data->wbuffer );
+	kfree( data );
+#if (LINUX_VERSION_CODE > 0x20155)
+	return 0;
+#endif
+}
+
+static struct net_device_list {
+	struct net_device *dev;
+	struct net_device_list *next;
+} *airo_devices = 0;
+
+/* Since the card doesnt automatically switch to the right WEP mode,
+   we will make it do it.  If the card isn't associated, every secs we
+   will switch WEP modes to see if that will help.  If the card is
+   associated we will check every minute to see if anything has
+   changed. */
+static void timer_func( u_long data ) {
+	struct net_device *dev = (struct net_device*)data;
+	struct airo_info *apriv = (struct airo_info *)dev->priv;
+	u16 linkstat = IN4500(apriv, LINKSTAT);
+	
+	if (linkstat != 0x400 ) {
+		struct timer_list *timer = &apriv->timer;
+		ConfigRid config = apriv->config;
+		int i;
+		
+		switch(apriv->authtype) {
+		case AUTH_ENCRYPT:
+			/* So escalate to SHAREDKEY */
+			config.authType = AUTH_SHAREDKEY;
+			/* The current hardware can't do more than
+			   2mbs with encryption */
+			for(i=0; i<8; i++) {
+				if (config.rates[i] > 4) {
+					config.rates[i] = 0;
+				}
+			}
+			apriv->authtype = AUTH_SHAREDKEY;
+			break;
+		case AUTH_SHAREDKEY:
+			/* Drop to open */
+			config.authType = AUTH_OPEN;
+			apriv->authtype = AUTH_OPEN;
+			break;
+		default:  /* We'll default to open */
+			/* So escalate to ENCRYPT */
+			config.authType = AUTH_ENCRYPT;
+			/* The current hardware can't do more than
+			   2mbs with encryption */
+			for(i=0; i<8; i++) {
+				if (config.rates[i] > 4) {
+					config.rates[i] = 0;
+				}
+			}
+			apriv->authtype = AUTH_ENCRYPT;
+		}
+		setup_card(apriv, dev->dev_addr, &config);
+		timer->expires = RUN_AT(HZ*5);  /*Check every 5 secs
+						  until everything is OK*/
+	} else {
+		struct timer_list *timer = &apriv->timer;
+		timer->expires = RUN_AT(HZ*60);  /*Check every 60 secs
+						   until everything is OK*/
+	}
+	add_timer(&apriv->timer);
+}
+
+static void add_airo_dev( struct net_device *dev ) {
+	struct net_device_list *node =
+		(struct net_device_list*)kmalloc( sizeof( *node ), GFP_KERNEL );
+	if ( !node ) {
+		printk( KERN_ERR "airo_pci:  Out of memory\n" );
+	} else {
+		if ( auto_wep ) {
+			struct timer_list *timer = 
+				&((struct airo_info*)dev->priv)->timer;
+			
+			timer->function = timer_func;
+			timer->data = (u_long)dev;
+			timer->prev = timer->next = 0;
+			/*Start off checking 5 secs */
+			timer->expires = RUN_AT( HZ * 5 );  
+			add_timer(timer);
+		}
+		
+		node->dev = dev;
+		node->next = airo_devices;
+		airo_devices = node;
+	}
+}
+
+static void del_airo_dev( struct net_device *dev ) {
+	struct net_device_list **p = &airo_devices;
+	while( *p && ( (*p)->dev != dev ) )
+		p = &(*p)->next;
+	if ( *p && (*p)->dev == dev )
+		*p = (*p)->next; 
+}
+
+int init_module( void )
+{
+	int i;
+	
+#if (LINUX_VERSION_CODE > 0x20155)
+#if (LINUX_VERSION_CODE < 0x20311)
+	airo_entry.ops->lookup = 
+		proc_net->ops->lookup;
+	airo_entry.ops->default_file_ops->readdir = 
+		proc_net->ops->default_file_ops->readdir;
+#endif
+#else
+	airo_entry.ops = proc_net.ops;
+#endif
+#if (LINUX_VERSION_CODE > 0x20311)
+	airo_entry = create_proc_entry("aironet",
+				       S_IFDIR | S_IRUGO,
+				       proc_root_driver);
+#else
+	PROC_REGISTER( &proc_root, &airo_entry );
+#endif
+	
+	for( i = 0; i < 4 && io[i] && irq[i]; i++ ) {
+		printk( KERN_INFO 
+			"airo:  Trying to configure ISA adapter at irq=%d io=0x%x\n",
+			irq[i], io[i] );
+		init_airo_card( irq[i], io[i] );
+	}
+	
+#ifdef CONFIG_PCI
+	if ( pcibios_present() ) {
+		int i;
+		printk( KERN_INFO "airo:  Probing for PCI adapters\n" );
+		for( i = 0; card_ids[i].vendor; i++ ) {
+#if (LINUX_VERSION_CODE > 0x20155)
+			struct pci_dev *dev = 0;
+			while((dev = pci_find_device(card_ids[i].vendor, card_ids[i].id,
+						     dev))) {
+				init_airo_card( dev->irq, 
+#if (LINUX_VERSION_CODE < 0x2030d)
+						dev->base_address[2] & 
+						PCI_BASE_ADDRESS_IO_MASK
+#else
+						dev->resource[2].start
+#endif
+					);
+			}
+#else
+			int j;
+			unsigned char bus, fun;
+			
+			/* We are running fast and loose here, it would be nice to fix it... */
+			for( j = 0; j < 4; j++ ) {
+				unsigned char irq;
+				unsigned int io;
+				if ( pcibios_find_device( card_ids[i].vendor, card_ids[i].id,
+							  j, &bus, &fun ) != PCIBIOS_SUCCESSFUL ) break;
+				pcibios_read_config_byte( bus, fun, PCI_INTERRUPT_LINE, &irq );
+				pcibios_read_config_dword( bus, fun, PCI_BASE_ADDRESS_2, &io );
+				io &= PCI_BASE_ADDRESS_IO_MASK;
+				init_airo_card( irq, io );
+			}
+#endif
+		}
+		printk( KERN_INFO "airo:  Finished probing for PCI adapters\n" );
+	}
+#endif
+	return 0;
+}
+
+void cleanup_module( void )
+{
+	while( airo_devices ) {
+		printk( KERN_INFO "airo: Unregistering %s\n", airo_devices->dev->name );
+		stop_airo_card( airo_devices->dev );
+	}
+#if (LINUX_VERSION_CODE < 0x20311)
+	PROC_UNREGISTER( &proc_root, &airo_entry );
+#else
+	remove_proc_entry("aironet", proc_root_driver);
+#endif
+}
+
+  
Index: oldkernel/linux/pcmcia-cs-3.1.15/wireless/airo_cs.c
diff -u /dev/null linux/pcmcia-cs-3.1.15/wireless/airo_cs.c:1.1
--- /dev/null	Mon Jul 31 21:15:12 2000
+++ linux/pcmcia-cs-3.1.15/wireless/airo_cs.c	Fri Jul  7 16:34:59 2000
@@ -0,0 +1,661 @@
+/*======================================================================
+
+    Aironet driver for 4500 and 4800 series cards
+
+    The contents of this file are subject to the Mozilla Public
+    License Version 1.0 (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.
+
+    This code was developed by Benjamin Reed <breed@almaden.ibm.com>
+    including portions of which come from the Aironet PC4500
+    Developer's Reference Manual and used with permission.  Copyright
+    (C) 1999 Benjamin Reed.  All Rights Reserved.  Permission to use
+    code in the Developer's manual was granted for this driver by
+    Aironet.
+
+    In addition this module was derived from dummy_cs.
+    The initial developer of dummy_cs is David A. Hinds
+    <dhinds@hyper.stanford.edu>.  Portions created by David A. Hinds
+    are Copyright (C) 1999 David A. Hinds.  All Rights Reserved.    
+    
+======================================================================*/
+#define PCMCIA_DIST
+#ifdef PCMCIA_DIST
+#include <pcmcia/config.h>
+#include <pcmcia/k_compat.h>
+#else
+#ifndef __KERNEL__
+#define __KERNEL__
+#endif
+
+#ifndef MODULE
+#define MODULE
+#endif
+
+#include <linux/autoconf.h>
+#ifdef CONFIG_MODVERSIONS
+#define MODVERSIONS
+#include <linux/modversions.h>
+#endif   
+
+#include <linux/config.h>
+#endif 
+#include <linux/kernel.h>
+#include <linux/module.h>
+
+#include <linux/sched.h>
+#include <linux/ptrace.h>
+#include <linux/malloc.h>
+#include <linux/string.h>
+#include <linux/timer.h>
+#include <linux/netdevice.h>
+#include <asm/io.h>
+#include <asm/system.h>
+
+#include <pcmcia/version.h>
+#include <pcmcia/cs_types.h>
+#include <pcmcia/cs.h>
+#include <pcmcia/cistpl.h>
+#include <pcmcia/cisreg.h>
+#include <pcmcia/ds.h>
+
+/*
+   All the PCMCIA modules use PCMCIA_DEBUG to control debugging.  If
+   you do not define PCMCIA_DEBUG at all, all the debug code will be
+   left out.  If you compile with PCMCIA_DEBUG=0, the debug code will
+   be present but disabled -- but it can then be enabled for specific
+   modules at load time with a 'pc_debug=#' option to insmod.
+*/
+#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 =
+"airo_cs.c .99zb 2000/02/20 00:38:22 (Benjamin Reed)";
+#else
+#define DEBUG(n, args...)
+#endif
+
+/*====================================================================*/
+
+/* Parameters that can be set with 'insmod' */
+
+/* The old way: bit map of interrupts to choose from */
+/* This means pick from 15, 14, 12, 11, 10, 9, 7, 5, 4, and 3 */
+static u_int irq_mask = 0xdeb8;
+/* Newer, simpler way of listing specific interrupts */
+static int irq_list[4] = { -1 };
+
+MODULE_PARM(irq_mask, "i");
+MODULE_PARM(irq_list, "1-4i");
+
+/*====================================================================*/
+
+/*
+   The event() function is this driver's Card Services event handler.
+   It will be called by Card Services when an appropriate card status
+   event is received.  The config() and release() entry points are
+   used to configure or release a socket, in response to card
+   insertion and ejection events.  They are invoked from the airo_cs
+   event handler. 
+*/
+
+struct net_device *init_airo_card( int, int );
+void stop_airo_card( struct net_device * );
+int reset_airo_card( struct net_device * );
+
+static void airo_config(dev_link_t *link);
+static void airo_release(u_long arg);
+static int airo_event(event_t event, int priority,
+		       event_callback_args_t *args);
+
+/*
+   The attach() and detach() entry points are used to create and destroy
+   "instances" of the driver, where each instance represents everything
+   needed to manage one actual PCMCIA card.
+*/
+
+static dev_link_t *airo_attach(void);
+static void airo_detach(dev_link_t *);
+
+/*
+   You'll also need to prototype all the functions that will actually
+   be used to talk to your device.  See 'pcmem_cs' for a good example
+   of a fully self-sufficient driver; the other drivers rely more or
+   less on other parts of the kernel.
+*/
+
+/*
+   The dev_info variable is the "key" that is used to match up this
+   device driver with appropriate cards, through the card configuration
+   database.
+*/
+
+static dev_info_t dev_info = "airo_cs";
+
+/*
+   A linked list of "instances" of the  aironet device.  Each actual
+   PCMCIA card corresponds to one device instance, and is described
+   by one dev_link_t structure (defined in ds.h).
+
+   You may not want to use a linked list for this -- for example, the
+   memory card driver uses an array of dev_link_t pointers, where minor
+   device numbers are used to derive the corresponding array index.
+*/
+
+static dev_link_t *dev_list = NULL;
+
+/*
+   A dev_link_t structure has fields for most things that are needed
+   to keep track of a socket, but there will usually be some device
+   specific information that also needs to be kept track of.  The
+   'priv' pointer in a dev_link_t structure can be used to point to
+   a device-specific private data structure, like this.
+
+   A driver needs to provide a dev_node_t structure for each device
+   on a card.  In some cases, there is only one device per card (for
+   example, ethernet cards, modems).  In other cases, there may be
+   many actual or logical devices (SCSI adapters, memory cards with
+   multiple partitions).  The dev_node_t structures need to be kept
+   in a linked list starting at the 'dev' field of a dev_link_t
+   structure.  We allocate them in the card's private data structure,
+   because they generally shouldn't be allocated dynamically.
+
+   In this case, we also provide a flag to indicate if a device is
+   "stopped" due to a power management event, or card ejection.  The
+   device IO routines can use a flag like this to throttle IO to a
+   card that is not ready to accept it.
+*/
+   
+typedef struct local_info_t {
+	dev_node_t	node;
+	struct net_device *eth_dev;
+} local_info_t;
+
+/*====================================================================*/
+
+static void cs_error(client_handle_t handle, int func, int ret)
+{
+	error_info_t err = { func, ret };
+	CardServices(ReportError, handle, &err);
+}
+
+/*======================================================================
+  
+  This bit of code is used to avoid unregistering network devices
+  at inappropriate times.  2.2 and later kernels are fairly picky
+  about when this can happen.
+  
+  ======================================================================*/
+
+static void flush_stale_links(void)
+{
+	dev_link_t *link, *next;
+	for (link = dev_list; link; link = next) {
+		next = link->next;
+		if (link->state & DEV_STALE_LINK)
+			airo_detach(link);
+	}
+}
+ 
+/*======================================================================
+  
+  airo_attach() creates an "instance" of the driver, allocating
+  local data structures for one device.  The device is registered
+  with Card Services.
+  
+  The dev_link structure is initialized, but we don't actually
+  configure the card at this point -- we wait until we receive a
+  card insertion event.
+  
+  ======================================================================*/
+
+static dev_link_t *airo_attach(void)
+{
+	client_reg_t client_reg;
+	dev_link_t *link;
+	local_info_t *local;
+	int ret, i;
+	
+	DEBUG(0, "airo_attach()\n");
+	flush_stale_links();
+	
+	/* Initialize the dev_link_t structure */
+	link = kmalloc(sizeof(struct dev_link_t), GFP_KERNEL);
+	memset(link, 0, sizeof(struct dev_link_t));
+	link->release.function = &airo_release;
+	link->release.data = (u_long)link;
+	
+	/* Interrupt setup */
+	link->irq.Attributes = IRQ_TYPE_EXCLUSIVE;
+	link->irq.IRQInfo1 = IRQ_INFO2_VALID|IRQ_LEVEL_ID;
+	if (irq_list[0] == -1)
+		link->irq.IRQInfo2 = irq_mask;
+	else
+		for (i = 0; i < 4; i++)
+			link->irq.IRQInfo2 |= 1 << irq_list[i];
+	link->irq.Handler = NULL;
+	
+	/*
+	  General socket configuration defaults can go here.  In this
+	  client, we assume very little, and rely on the CIS for almost
+	  everything.  In most clients, many details (i.e., number, sizes,
+	  and attributes of IO windows) are fixed by the nature of the
+	  device, and can be hard-wired here.
+	*/
+	link->conf.Attributes = 0;
+	link->conf.Vcc = 50;
+	link->conf.IntType = INT_MEMORY_AND_IO;
+	
+	/* Allocate space for private device-specific data */
+	local = kmalloc(sizeof(local_info_t), GFP_KERNEL);
+	memset(local, 0, sizeof(local_info_t));
+	link->priv = local;
+	
+	/* Register with Card Services */
+	link->next = dev_list;
+	dev_list = link;
+	client_reg.dev_info = &dev_info;
+	client_reg.Attributes = INFO_IO_CLIENT | INFO_CARD_SHARE;
+	client_reg.EventMask =
+		CS_EVENT_CARD_INSERTION | CS_EVENT_CARD_REMOVAL |
+		CS_EVENT_RESET_PHYSICAL | CS_EVENT_CARD_RESET |
+		CS_EVENT_PM_SUSPEND | CS_EVENT_PM_RESUME;
+	client_reg.event_handler = &airo_event;
+	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);
+		airo_detach(link);
+		return NULL;
+	}
+	
+	return link;
+} /* airo_attach */
+
+/*======================================================================
+  
+  This deletes a driver "instance".  The device is de-registered
+  with Card Services.  If it has been released, all local data
+  structures are freed.  Otherwise, the structures will be freed
+  when the device is released.
+  
+  ======================================================================*/
+
+static void airo_detach(dev_link_t *link)
+{
+	dev_link_t **linkp;
+	
+	DEBUG(0, "airo_detach(0x%p)\n", link);
+	
+	/* Locate device structure */
+	for (linkp = &dev_list; *linkp; linkp = &(*linkp)->next)
+		if (*linkp == link) break;
+	if (*linkp == NULL)
+		return;
+	
+	del_timer(&link->release);
+	if ( link->state & DEV_CONFIG ) {
+		airo_release( (int)link );
+		if ( link->state & DEV_STALE_CONFIG ) {
+			link->state |= DEV_STALE_LINK;
+			return;
+		}
+	}
+	
+	if ( ((local_info_t*)link->priv)->eth_dev ) {
+		stop_airo_card( ((local_info_t*)link->priv)->eth_dev );
+	}
+	((local_info_t*)link->priv)->eth_dev = 0;   
+	
+	/* Break the link with Card Services */
+	if (link->handle)
+		CardServices(DeregisterClient, link->handle);
+	
+	
+	
+	/* Unlink device structure, free pieces */
+	*linkp = link->next;
+	if (link->priv) {
+		kfree_s(link->priv, sizeof(local_info_t));
+	}
+	kfree_s(link, sizeof(struct dev_link_t));
+	
+} /* airo_detach */
+
+/*======================================================================
+  
+  airo_config() is scheduled to run after a CARD_INSERTION event
+  is received, to configure the PCMCIA socket, and to make the
+  device available to the system.
+  
+  ======================================================================*/
+
+#define CS_CHECK(fn, args...) \
+while ((last_ret=CardServices(last_fn=(fn),args))!=0) goto cs_failed
+
+#define CFG_CHECK(fn, args...) \
+if (CardServices(fn, args) != 0) goto next_entry
+
+static void airo_config(dev_link_t *link)
+{
+	client_handle_t handle;
+	tuple_t tuple;
+	cisparse_t parse;
+	local_info_t *dev;
+	int last_fn, last_ret;
+	u_char buf[64];
+	win_req_t req;
+	memreq_t map;
+	
+	handle = link->handle;
+	dev = link->priv;
+
+	DEBUG(0, "airo_config(0x%p)\n", link);
+	
+	/*
+	  This reads the card's CONFIG tuple to find its configuration
+	  registers.
+	*/
+	tuple.DesiredTuple = CISTPL_CONFIG;
+	tuple.Attributes = 0;
+	tuple.TupleData = buf;
+	tuple.TupleDataMax = sizeof(buf);
+	tuple.TupleOffset = 0;
+	CS_CHECK(GetFirstTuple, handle, &tuple);
+	CS_CHECK(GetTupleData, handle, &tuple);
+	CS_CHECK(ParseTuple, handle, &tuple, &parse);
+	link->conf.ConfigBase = parse.config.base;
+	link->conf.Present = parse.config.rmask[0];
+	
+	/* Configure card */
+	link->state |= DEV_CONFIG;
+	
+	/*
+	  In this loop, we scan the CIS for configuration table entries,
+	  each of which describes a valid card configuration, including
+	  voltage, IO window, memory window, and interrupt settings.
+	  
+	  We make no assumptions about the card to be configured: we use
+	  just the information available in the CIS.  In an ideal world,
+	  this would work for any PCMCIA card, but it requires a complete
+	  and accurate CIS.  In practice, a driver usually "knows" most of
+	  these things without consulting the CIS, and most client drivers
+	  will only use the CIS to fill in implementation-defined details.
+	*/
+	tuple.DesiredTuple = CISTPL_CFTABLE_ENTRY;
+	CS_CHECK(GetFirstTuple, handle, &tuple);
+	while (1) {
+		cistpl_cftable_entry_t dflt = { 0 };
+		cistpl_cftable_entry_t *cfg = &(parse.cftable_entry);
+		CFG_CHECK(GetTupleData, handle, &tuple);
+		CFG_CHECK(ParseTuple, handle, &tuple, &parse);
+		
+		if (cfg->flags & CISTPL_CFTABLE_DEFAULT) dflt = *cfg;
+		if (cfg->index == 0) goto next_entry;
+		link->conf.ConfigIndex = cfg->index;
+		
+		/* Does this card need audio output? */
+		if (cfg->flags & CISTPL_CFTABLE_AUDIO) {
+			link->conf.Attributes |= CONF_ENABLE_SPKR;
+			link->conf.Status = CCSR_AUDIO_ENA;
+		}
+		
+		/* Use power settings for Vcc and Vpp if present */
+		/*  Note that the CIS values need to be rescaled */
+		if (cfg->vcc.present & (1<<CISTPL_POWER_VNOM))
+			link->conf.Vcc = cfg->vcc.param[CISTPL_POWER_VNOM]/10000;
+		else if (dflt.vcc.present & (1<<CISTPL_POWER_VNOM))
+			link->conf.Vcc = dflt.vcc.param[CISTPL_POWER_VNOM]/10000;
+		
+		if (cfg->vpp1.present & (1<<CISTPL_POWER_VNOM))
+			link->conf.Vpp1 = link->conf.Vpp2 =
+				cfg->vpp1.param[CISTPL_POWER_VNOM]/10000;
+		else if (dflt.vpp1.present & (1<<CISTPL_POWER_VNOM))
+			link->conf.Vpp1 = link->conf.Vpp2 =
+				dflt.vpp1.param[CISTPL_POWER_VNOM]/10000;
+		
+		/* Do we need to allocate an interrupt? */
+		if (cfg->irq.IRQInfo1 || dflt.irq.IRQInfo1)
+			link->conf.Attributes |= CONF_ENABLE_IRQ;
+		
+		/* IO window settings */
+		link->io.NumPorts1 = link->io.NumPorts2 = 0;
+		if ((cfg->io.nwin > 0) || (dflt.io.nwin > 0)) {
+			cistpl_io_t *io = (cfg->io.nwin) ? &cfg->io : &dflt.io;
+			link->io.Attributes1 = IO_DATA_PATH_WIDTH_AUTO;
+			if (!(io->flags & CISTPL_IO_8BIT))
+				link->io.Attributes1 = IO_DATA_PATH_WIDTH_16;
+			if (!(io->flags & CISTPL_IO_16BIT))
+				link->io.Attributes1 = IO_DATA_PATH_WIDTH_8;
+			link->io.BasePort1 = io->win[0].base;
+			link->io.NumPorts1 = io->win[0].len;
+			if (io->nwin > 1) {
+				link->io.Attributes2 = link->io.Attributes1;
+				link->io.BasePort2 = io->win[1].base;
+				link->io.NumPorts2 = io->win[1].len;
+			}
+		}
+		
+		/* This reserves IO space but doesn't actually enable it */
+		CFG_CHECK(RequestIO, link->handle, &link->io); 
+		
+		/*
+		  Now set up a common memory window, if needed.  There is room
+		  in the dev_link_t structure for one memory window handle,
+		  but if the base addresses need to be saved, or if multiple
+		  windows are needed, the info should go in the private data
+		  structure for this device.
+		  
+		  Note that the memory window base is a physical address, and
+		  needs to be mapped to virtual space with ioremap() before it
+		  is used.
+		*/
+		if ((cfg->mem.nwin > 0) || (dflt.mem.nwin > 0)) {
+			cistpl_mem_t *mem =
+				(cfg->mem.nwin) ? &cfg->mem : &dflt.mem;
+			req.Attributes = WIN_DATA_WIDTH_16|WIN_MEMORY_TYPE_CM;
+			req.Base = mem->win[0].host_addr;
+			req.Size = mem->win[0].len;
+			req.AccessSpeed = 0;
+			link->win = (window_handle_t)link->handle;
+			CFG_CHECK(RequestWindow, &link->win, &req);
+			map.Page = 0; map.CardOffset = mem->win[0].card_addr;
+			CFG_CHECK(MapMemPage, link->win, &map);
+		}
+		/* If we got this far, we're cool! */
+		break;
+		
+	next_entry:
+		CS_CHECK(GetNextTuple, handle, &tuple);
+	}
+	
+    /*
+      Allocate an interrupt line.  Note that this does not assign a
+      handler to the interrupt, unless the 'Handler' member of the
+      irq structure is initialized.
+    */
+	if (link->conf.Attributes & CONF_ENABLE_IRQ)
+		CS_CHECK(RequestIRQ, link->handle, &link->irq);
+	
+	/*
+	  This actually configures the PCMCIA socket -- setting up
+	  the I/O windows and the interrupt mapping, and putting the
+	  card and host interface into "Memory and IO" mode.
+	*/
+	CS_CHECK(RequestConfiguration, link->handle, &link->conf);
+	((local_info_t*)link->priv)->eth_dev = 
+		init_airo_card( link->irq.AssignedIRQ,
+				link->io.BasePort1 );
+	if (!((local_info_t*)link->priv)->eth_dev) goto cs_failed;
+	
+	/*
+	  At this point, the dev_node_t structure(s) need to be
+	  initialized and arranged in a linked list at link->dev.
+	*/
+	strcpy(dev->node.dev_name, ((local_info_t*)link->priv)->eth_dev->name );
+	dev->node.major = dev->node.minor = 0;
+	link->dev = &dev->node;
+	
+	/* Finally, report what we've done */
+	printk(KERN_INFO "%s: index 0x%02x: Vcc %d.%d",
+	       dev->node.dev_name, link->conf.ConfigIndex,
+	       link->conf.Vcc/10, link->conf.Vcc%10);
+	if (link->conf.Vpp1)
+		printk(", Vpp %d.%d", link->conf.Vpp1/10, link->conf.Vpp1%10);
+	if (link->conf.Attributes & CONF_ENABLE_IRQ)
+		printk(", irq %d", link->irq.AssignedIRQ);
+	if (link->io.NumPorts1)
+		printk(", io 0x%04x-0x%04x", link->io.BasePort1,
+		       link->io.BasePort1+link->io.NumPorts1-1);
+	if (link->io.NumPorts2)
+		printk(" & 0x%04x-0x%04x", link->io.BasePort2,
+		       link->io.BasePort2+link->io.NumPorts2-1);
+	if (link->win)
+		printk(", mem 0x%06lx-0x%06lx", req.Base,
+		       req.Base+req.Size-1);
+	printk("\n");
+	
+	link->state &= ~DEV_CONFIG_PENDING;
+	return;
+	
+ cs_failed:
+	cs_error(link->handle, last_fn, last_ret);
+	airo_release((u_long)link);
+	
+} /* airo_config */
+
+/*======================================================================
+  
+  After a card is removed, airo_release() will unregister the
+  device, and release the PCMCIA configuration.  If the device is
+  still open, this will be postponed until it is closed.
+  
+  ======================================================================*/
+
+static void airo_release(u_long arg)
+{
+	dev_link_t *link = (dev_link_t *)arg;
+	
+	DEBUG(0, "airo_release(0x%p)\n", link);
+	
+	/*
+	  If the device is currently in use, we won't release until it
+	  is actually closed, because until then, we can't be sure that
+	  no one will try to access the device or its data structures.
+	*/
+	if (link->open) {
+		DEBUG(1, "airo_cs: release postponed, '%s' still open\n",
+		      link->dev->dev_name);
+		link->state |= DEV_STALE_CONFIG;
+		return;
+	}
+	
+	/* Unlink the device chain */
+	link->dev = NULL;
+	
+	/*
+	  In a normal driver, additional code may be needed to release
+	  other kernel data structures associated with this device. 
+	*/
+	
+	/* Don't bother checking to see if these succeed or not */
+	if (link->win)
+		CardServices(ReleaseWindow, link->win);
+	CardServices(ReleaseConfiguration, link->handle);
+	if (link->io.NumPorts1)
+		CardServices(ReleaseIO, link->handle, &link->io);
+	if (link->irq.AssignedIRQ)
+		CardServices(ReleaseIRQ, link->handle, &link->irq);
+	link->state &= ~DEV_CONFIG;
+	
+} /* airo_release */
+
+/*======================================================================
+  
+  The card status event handler.  Mostly, this schedules other
+  stuff to run after an event is received.
+
+  When a CARD_REMOVAL event is received, we immediately set a
+  private flag to block future accesses to this device.  All the
+  functions that actually access the device should check this flag
+  to make sure the card is still present.
+  
+  ======================================================================*/
+
+static int airo_event(event_t event, int priority,
+		      event_callback_args_t *args)
+{
+	dev_link_t *link = args->client_data;
+	local_info_t *local = link->priv;
+	
+	DEBUG(1, "airo_event(0x%06x)\n", event);
+	
+	switch (event) {
+	case CS_EVENT_CARD_REMOVAL:
+		link->state &= ~DEV_PRESENT;
+		if (link->state & DEV_CONFIG) {
+			netif_device_detach(local->eth_dev);
+			mod_timer(&link->release, jiffies + HZ/20);
+		}
+		break;
+	case CS_EVENT_CARD_INSERTION:
+		link->state |= DEV_PRESENT | DEV_CONFIG_PENDING;
+		airo_config(link);
+		break;
+	case CS_EVENT_PM_SUSPEND:
+		link->state |= DEV_SUSPEND;
+		/* Fall through... */
+	case CS_EVENT_RESET_PHYSICAL:
+		if (link->state & DEV_CONFIG) {
+			netif_device_detach(local->eth_dev);
+			CardServices(ReleaseConfiguration, link->handle);
+		}
+		break;
+	case CS_EVENT_PM_RESUME:
+		link->state &= ~DEV_SUSPEND;
+		/* Fall through... */
+	case CS_EVENT_CARD_RESET:
+		if (link->state & DEV_CONFIG) {
+			CardServices(RequestConfiguration, link->handle, &link->conf);
+			reset_airo_card(local->eth_dev);
+			netif_device_attach(local->eth_dev);
+		}
+		break;
+	}
+	return 0;
+} /* airo_event */
+
+/*====================================================================*/
+
+int init_module(void)
+{
+	servinfo_t serv;
+	DEBUG(0, "%s\n", version);
+	CardServices(GetCardServicesInfo, &serv);
+	if (serv.Revision != CS_RELEASE_CODE) {
+		printk(KERN_NOTICE "airo_cs: Card Services release "
+		       "does not match!\n");
+		return -1;
+	}
+	register_pcmcia_driver(&dev_info, &airo_attach, &airo_detach);
+	return 0;
+}
+
+void cleanup_module(void)
+{
+	DEBUG(0, "airo_cs: unloading\n");
+	unregister_pcmcia_driver(&dev_info);
+	while (dev_list != NULL) {
+		if (dev_list->state & DEV_CONFIG)
+			airo_release((u_long)dev_list);
+		airo_detach(dev_list);
+	}
+}
Index: oldkernel/linux/pcmcia-cs-3.1.15/wireless/i82593.h
diff -u /dev/null linux/pcmcia-cs-3.1.15/wireless/i82593.h:1.1
--- /dev/null	Mon Jul 31 21:15:12 2000
+++ linux/pcmcia-cs-3.1.15/wireless/i82593.h	Fri Jul  7 16:34:59 2000
@@ -0,0 +1,225 @@
+/*
+ * Definitions for Intel 82593 CSMA/CD Core LAN Controller
+ * The definitions are taken from the 1992 users manual with Intel
+ * order number 297125-001.
+ *
+ * /usr/src/pc/RCS/i82593.h,v 1.1 1996/07/17 15:23:12 root Exp
+ *
+ * Copyright 1994, Anders Klemets <klemets@it.kth.se>
+ *
+ * This software may be freely distributed for noncommercial purposes
+ * as long as this notice is retained.
+ * 
+ * HISTORY
+ * i82593.h,v
+ * Revision 1.1  1996/07/17 15:23:12  root
+ * Initial revision
+ *
+ * Revision 1.3  1995/04/05  15:13:58  adj
+ * Initial alpha release
+ *
+ * Revision 1.2  1994/06/16  23:57:31  klemets
+ * Mirrored all the fields in the configuration block.
+ *
+ * Revision 1.1  1994/06/02  20:25:34  klemets
+ * Initial revision
+ *
+ *
+ */
+#ifndef	_I82593_H
+#define	_I82593_H
+
+/* Intel 82593 CSMA/CD Core LAN Controller */
+
+/* Port 0 Command Register definitions */
+
+/* Execution operations */
+#define OP0_NOP			0	/* CHNL = 0 */
+#define OP0_SWIT_TO_PORT_1	0	/* CHNL = 1 */
+#define OP0_IA_SETUP		1
+#define OP0_CONFIGURE		2
+#define OP0_MC_SETUP		3
+#define OP0_TRANSMIT		4
+#define OP0_TDR			5
+#define OP0_DUMP		6
+#define OP0_DIAGNOSE		7
+#define OP0_TRANSMIT_NO_CRC	9
+#define OP0_RETRANSMIT		12
+#define OP0_ABORT		13
+/* Reception operations */
+#define OP0_RCV_ENABLE		8
+#define OP0_RCV_DISABLE		10
+#define OP0_STOP_RCV		11
+/* Status pointer control operations */
+#define OP0_FIX_PTR		15	/* CHNL = 1 */
+#define OP0_RLS_PTR		15	/* CHNL = 0 */
+#define OP0_RESET		14
+
+#define CR0_CHNL		(1 << 4)	/* 0=Channel 0, 1=Channel 1 */
+#define CR0_STATUS_0		0x00
+#define CR0_STATUS_1		0x20
+#define CR0_STATUS_2		0x40
+#define CR0_STATUS_3		0x60
+#define CR0_INT_ACK		(1 << 7)	/* 0=No ack, 1=acknowledge */
+
+/* Port 0 Status Register definitions */
+
+#define SR0_NO_RESULT		0		/* dummy */
+#define SR0_EVENT_MASK		0x0f
+#define SR0_IA_SETUP_DONE	1
+#define SR0_CONFIGURE_DONE	2
+#define SR0_MC_SETUP_DONE	3
+#define SR0_TRANSMIT_DONE	4
+#define SR0_TDR_DONE		5
+#define SR0_DUMP_DONE		6
+#define SR0_DIAGNOSE_PASSED	7
+#define SR0_TRANSMIT_NO_CRC_DONE 9
+#define SR0_RETRANSMIT_DONE	12
+#define SR0_EXECUTION_ABORTED	13
+#define SR0_END_OF_FRAME	8
+#define SR0_RECEPTION_ABORTED	10
+#define SR0_DIAGNOSE_FAILED	15
+#define SR0_STOP_REG_HIT	11
+
+#define SR0_CHNL		(1 << 4)
+#define SR0_EXECUTION		(1 << 5)
+#define SR0_RECEPTION		(1 << 6)
+#define SR0_INTERRUPT		(1 << 7)
+#define SR0_BOTH_RX_TX		(SR0_EXECUTION | SR0_RECEPTION)
+
+#define SR3_EXEC_STATE_MASK	0x03
+#define SR3_EXEC_IDLE		0
+#define SR3_TX_ABORT_IN_PROGRESS 1
+#define SR3_EXEC_ACTIVE		2
+#define SR3_ABORT_IN_PROGRESS	3
+#define SR3_EXEC_CHNL		(1 << 2)
+#define SR3_STP_ON_NO_RSRC	(1 << 3)
+#define SR3_RCVING_NO_RSRC	(1 << 4)
+#define SR3_RCV_STATE_MASK	0x60
+#define SR3_RCV_IDLE		0x00
+#define SR3_RCV_READY		0x20
+#define SR3_RCV_ACTIVE		0x40
+#define SR3_RCV_STOP_IN_PROG	0x60
+#define SR3_RCV_CHNL		(1 << 7)
+
+/* Port 1 Command Register definitions */
+
+#define OP1_NOP			0
+#define OP1_SWIT_TO_PORT_0	1
+#define OP1_INT_DISABLE		2
+#define OP1_INT_ENABLE		3
+#define OP1_SET_TS		5
+#define OP1_RST_TS		7
+#define OP1_POWER_DOWN		8
+#define OP1_RESET_RING_MNGMT	11
+#define OP1_RESET		14
+#define OP1_SEL_RST		15
+
+#define CR1_STATUS_4		0x00
+#define CR1_STATUS_5		0x20
+#define CR1_STATUS_6		0x40
+#define CR1_STOP_REG_UPDATE	(1 << 7)
+
+/* Receive frame status bits */
+
+#define	RX_RCLD			(1 << 0)
+#define RX_IA_MATCH		(1 << 1)
+#define	RX_NO_AD_MATCH		(1 << 2)
+#define RX_NO_SFD		(1 << 3)
+#define RX_SRT_FRM		(1 << 7)
+#define RX_OVRRUN		(1 << 8)
+#define RX_ALG_ERR		(1 << 10)
+#define RX_CRC_ERR		(1 << 11)
+#define RX_LEN_ERR		(1 << 12)
+#define RX_RCV_OK		(1 << 13)
+#define RX_TYP_LEN		(1 << 15)
+
+/* Transmit status bits */
+
+#define TX_NCOL_MASK		0x0f
+#define TX_FRTL			(1 << 4)
+#define TX_MAX_COL		(1 << 5)
+#define TX_HRT_BEAT		(1 << 6)
+#define TX_DEFER		(1 << 7)
+#define TX_UND_RUN		(1 << 8)
+#define TX_LOST_CTS		(1 << 9)
+#define TX_LOST_CRS		(1 << 10)
+#define TX_LTCOL		(1 << 11)
+#define TX_OK			(1 << 13)
+#define TX_COLL			(1 << 15)
+
+
+struct i82593_conf_block {
+  u_char fifo_limit : 4,
+  	 forgnesi   : 1,
+  	 fifo_32    : 1,
+  	 d6mod      : 1,
+  	 throttle_enb : 1;
+  u_char throttle   : 6,
+	 cntrxint   : 1,
+	 contin	    : 1;
+  u_char addr_len   : 3,
+  	 acloc 	    : 1,
+ 	 preamb_len : 2,
+  	 loopback   : 2;
+  u_char lin_prio   : 3,
+	 tbofstop   : 1,
+	 exp_prio   : 3,
+	 bof_met    : 1;
+  u_char	    : 4,
+	 ifrm_spc   : 4;
+  u_char	    : 5,
+	 slottim_low : 3;
+  u_char slottim_hi : 3,
+		    : 1,
+	 max_retr   : 4;
+  u_char prmisc     : 1,
+	 bc_dis     : 1,
+  		    : 1,
+	 crs_1	    : 1,
+	 nocrc_ins  : 1,
+	 crc_1632   : 1,
+  	 	    : 1,
+  	 crs_cdt    : 1;
+  u_char cs_filter  : 3,
+	 crs_src    : 1,
+	 cd_filter  : 3,
+		    : 1;
+  u_char	    : 2,
+  	 min_fr_len : 6;
+  u_char lng_typ    : 1,
+	 lng_fld    : 1,
+	 rxcrc_xf   : 1,
+	 artx	    : 1,
+	 sarec	    : 1,
+	 tx_jabber  : 1,	/* why is this called max_len in the manual? */
+	 hash_1	    : 1,
+  	 lbpkpol    : 1;
+  u_char	    : 6,
+  	 fdx	    : 1,
+  	  	    : 1;
+  u_char dummy_6    : 6,	/* supposed to be ones */
+  	 mult_ia    : 1,
+  	 dis_bof    : 1;
+  u_char dummy_1    : 1,	/* supposed to be one */
+	 tx_ifs_retrig : 2,
+	 mc_all     : 1,
+	 rcv_mon    : 2,
+	 frag_acpt  : 1,
+  	 tstrttrs   : 1;
+  u_char fretx	    : 1,
+	 runt_eop   : 1,
+	 hw_sw_pin  : 1,
+	 big_endn   : 1,
+	 syncrqs    : 1,
+	 sttlen     : 1,
+	 tx_eop     : 1,
+  	 rx_eop	    : 1;
+  u_char rbuf_size  : 5,
+	 rcvstop    : 1,
+  	 	    : 2;
+};
+
+#define I82593_MAX_MULTICAST_ADDRESSES	128	/* Hardware hashed filter */
+
+#endif _I82593_H
Index: oldkernel/linux/pcmcia-cs-3.1.15/wireless/netwave_cs.c
diff -u /dev/null linux/pcmcia-cs-3.1.15/wireless/netwave_cs.c:1.1
--- /dev/null	Mon Jul 31 21:15:12 2000
+++ linux/pcmcia-cs-3.1.15/wireless/netwave_cs.c	Fri Jul  7 16:34:59 2000
@@ -0,0 +1,1638 @@
+/*********************************************************************
+ *                
+ * Filename:      netwave_cs.c
+ * Version:       0.4.1
+ * Description:   Netwave AirSurfer Wireless LAN PC Card driver
+ * Status:        Experimental.
+ * Authors:       John Markus Bjørndalen <johnm@cs.uit.no>
+ *                Dag Brattli <dagb@cs.uit.no>
+ *                David Hinds <dhinds@pcmcia.sourceforge.org>
+ * Created at:    A long time ago!
+ * Modified at:   Mon Nov 10 11:54:37 1997
+ * Modified by:   Dag Brattli <dagb@cs.uit.no>
+ * 
+ *     Copyright (c) 1997 University of Tromsø, Norway
+ *
+ * Revision History:
+ *
+ *   08-Nov-97 15:14:47   John Markus Bjørndalen <johnm@cs.uit.no>
+ *    - Fixed some bugs in netwave_rx and cleaned it up a bit. 
+ *      (One of the bugs would have destroyed packets when receiving
+ *      multiple packets per interrupt). 
+ *    - Cleaned up parts of newave_hw_xmit. 
+ *    - A few general cleanups. 
+ *   24-Oct-97 13:17:36   Dag Brattli <dagb@cs.uit.no>
+ *    - Fixed netwave_rx receive function (got updated docs)
+ *   Others:
+ *    - Changed name from xircnw to netwave, take a look at 
+ *      http://www.netwave-wireless.com
+ *    - Some reorganizing of the code
+ *    - Removed possible race condition between interrupt handler and transmit
+ *      function
+ *    - Started to add wireless extensions, but still needs some coding
+ *    - Added watchdog for better handling of transmission timeouts 
+ *      (hopefully this works better)
+ ********************************************************************/
+
+/* To have statistics (just packets sent) define this */
+#undef NETWAVE_STATS
+
+#include <pcmcia/config.h>
+#include <pcmcia/k_compat.h>
+
+#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/sched.h>
+#include <linux/types.h>
+#include <linux/fcntl.h>
+#include <linux/interrupt.h>
+#include <linux/ptrace.h>
+#include <linux/ioport.h>
+#include <linux/in.h>
+#include <linux/malloc.h>
+#include <linux/string.h>
+#include <linux/timer.h>
+#include <asm/system.h>
+#include <asm/bitops.h>
+#include <asm/io.h>
+#include <asm/dma.h>
+#include <linux/errno.h>
+
+#include <linux/netdevice.h>
+#include <linux/etherdevice.h>
+#include <linux/skbuff.h>
+
+#ifdef HAS_WIRELESS_EXTENSIONS
+#include <linux/wireless.h>
+#endif
+
+#include <pcmcia/version.h>
+#include <pcmcia/cs_types.h>
+#include <pcmcia/cs.h>
+#include <pcmcia/cistpl.h>
+#include <pcmcia/cisreg.h>
+#include <pcmcia/ds.h>
+#include <pcmcia/mem_op.h>
+
+#define NETWAVE_REGOFF         0x8000
+/* The Netwave IO registers, offsets to iobase */
+#define NETWAVE_REG_COR        0x0
+#define NETWAVE_REG_CCSR       0x2
+#define NETWAVE_REG_ASR        0x4
+#define NETWAVE_REG_IMR        0xa
+#define NETWAVE_REG_PMR        0xc
+#define NETWAVE_REG_IOLOW      0x6
+#define NETWAVE_REG_IOHI       0x7
+#define NETWAVE_REG_IOCONTROL  0x8
+#define NETWAVE_REG_DATA       0xf
+/* The Netwave Extended IO registers, offsets to RamBase */
+#define NETWAVE_EREG_ASCC      0x114
+#define NETWAVE_EREG_RSER      0x120
+#define NETWAVE_EREG_RSERW     0x124
+#define NETWAVE_EREG_TSER      0x130
+#define NETWAVE_EREG_TSERW     0x134
+#define NETWAVE_EREG_CB        0x100
+#define NETWAVE_EREG_SPCQ      0x154
+#define NETWAVE_EREG_SPU       0x155
+#define NETWAVE_EREG_LIF       0x14e
+#define NETWAVE_EREG_ISPLQ     0x156
+#define NETWAVE_EREG_HHC       0x158
+#define NETWAVE_EREG_NI        0x16e
+#define NETWAVE_EREG_MHS       0x16b
+#define NETWAVE_EREG_TDP       0x140
+#define NETWAVE_EREG_RDP       0x150
+#define NETWAVE_EREG_PA        0x160
+#define NETWAVE_EREG_EC        0x180
+#define NETWAVE_EREG_CRBP      0x17a
+#define NETWAVE_EREG_ARW       0x166
+
+/*
+ * Commands used in the extended command buffer
+ * NETWAVE_EREG_CB (0x100-0x10F) 
+ */
+#define NETWAVE_CMD_NOP        0x00
+#define NETWAVE_CMD_SRC        0x01
+#define NETWAVE_CMD_STC        0x02
+#define NETWAVE_CMD_AMA        0x03
+#define NETWAVE_CMD_DMA        0x04
+#define NETWAVE_CMD_SAMA       0x05
+#define NETWAVE_CMD_ER         0x06
+#define NETWAVE_CMD_DR         0x07
+#define NETWAVE_CMD_TL         0x08
+#define NETWAVE_CMD_SRP        0x09
+#define NETWAVE_CMD_SSK        0x0a
+#define NETWAVE_CMD_SMD        0x0b
+#define NETWAVE_CMD_SAPD       0x0c
+#define NETWAVE_CMD_SSS        0x11
+/* End of Command marker */
+#define NETWAVE_CMD_EOC        0x00
+
+/* ASR register bits */
+#define NETWAVE_ASR_RXRDY   0x80
+#define NETWAVE_ASR_TXBA    0x01
+
+#define TX_TIMEOUT		((32*HZ)/100)
+
+static const unsigned int imrConfRFU1 = 0x10; /* RFU interrupt mask, keep high */
+static const unsigned int imrConfIENA = 0x02; /* Interrupt enable */
+
+static const unsigned int corConfIENA   = 0x01; /* Interrupt enable */
+static const unsigned int corConfLVLREQ = 0x40; /* Keep high */
+
+static const unsigned int rxConfRxEna  = 0x80; /* Receive Enable */
+static const unsigned int rxConfMAC    = 0x20; /* MAC host receive mode*/ 
+static const unsigned int rxConfPro    = 0x10; /* Promiscuous */
+static const unsigned int rxConfAMP    = 0x08; /* Accept Multicast Packets */
+static const unsigned int rxConfBcast  = 0x04; /* Accept Broadcast Packets */
+
+static const unsigned int txConfTxEna  = 0x80; /* Transmit Enable */
+static const unsigned int txConfMAC    = 0x20; /* Host sends MAC mode */
+static const unsigned int txConfEUD    = 0x10; /* Enable Uni-Data packets */
+static const unsigned int txConfKey    = 0x02; /* Scramble data packets */
+static const unsigned int txConfLoop   = 0x01; /* Loopback mode */
+
+/*
+   All the PCMCIA modules use PCMCIA_DEBUG to control debugging.  If
+   you do not define PCMCIA_DEBUG at all, all the debug code will be
+   left out.  If you compile with PCMCIA_DEBUG=0, the debug code will
+   be present but disabled -- but it can then be enabled for specific
+   modules at load time with a 'pc_debug=#' option to insmod.
+*/
+
+#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 =
+"netwave_cs.c 0.3.0 Thu Jul 17 14:36:02 1997 (John Markus Bjørndalen)\n";
+#else
+#define DEBUG(n, args...)
+#endif
+
+static dev_info_t dev_info = "netwave_cs";
+
+/*====================================================================*/
+
+/* Parameters that can be set with 'insmod' */
+
+/* Choose the domain, default is 0x100 */
+static u_int  domain = 0x100;
+
+/* Scramble key, range from 0x0 to 0xffff.  
+ * 0x0 is no scrambling. 
+ */
+static u_int  scramble_key = 0x0;
+
+/* Shared memory speed, in ns. The documentation states that 
+ * the card should not be read faster than every 400ns. 
+ * This timing should be provided by the HBA. If it becomes a 
+ * problem, try setting mem_speed to 400. 
+ */
+static int mem_speed = 0;
+
+/* Bit map of interrupts to choose from */
+/* This means pick from 15, 14, 12, 11, 10, 9, 7, 5, 4, and 3 */
+static u_int irq_mask = 0xdeb8;
+static int irq_list[4] = { -1 };
+
+MODULE_PARM(domain, "i");
+MODULE_PARM(scramble_key, "i");
+MODULE_PARM(mem_speed, "i");
+MODULE_PARM(irq_mask, "i");
+MODULE_PARM(irq_list, "1-4i");
+
+/*====================================================================*/
+
+/* PCMCIA (Card Services) related functions */
+static void netwave_release(u_long arg);     /* Card removal */
+static int  netwave_event(event_t event, int priority, 
+					      event_callback_args_t *args);
+static void netwave_pcmcia_config(dev_link_t *arg); /* Runs after card 
+													   insertion */
+static dev_link_t *netwave_attach(void);     /* Create instance */
+static void netwave_detach(dev_link_t *);    /* Destroy instance */
+static void netwave_flush_stale_links(void);	     /* Destroy all staled instances */
+
+/* Hardware configuration */
+static void netwave_doreset(ioaddr_t iobase, u_char* ramBase);
+static void netwave_reset(struct net_device *dev);
+
+/* Misc device stuff */
+static int netwave_open(struct net_device *dev);  /* Open the device */
+static int netwave_close(struct net_device *dev); /* Close the device */
+static int netwave_config(struct net_device *dev, struct ifmap *map);
+
+/* Packet transmission and Packet reception */
+static int netwave_start_xmit( struct sk_buff *skb, struct net_device *dev);
+static int netwave_rx( struct net_device *dev);
+
+/* Interrupt routines */
+static void netwave_interrupt(int irq, void *dev_id, struct pt_regs *regs);
+#ifdef HAVE_NETIF_QUEUE
+static void netwave_watchdog(struct net_device *);
+#else
+static void netwave_watchdog(u_long);
+#endif
+
+/* Statistics */
+static void update_stats(struct net_device *dev);
+static struct enet_statistics *netwave_get_stats(struct net_device *dev);
+
+/* Wireless extensions */
+#ifdef WIRELESS_EXT
+static struct iw_statistics* netwave_get_wireless_stats(struct net_device *dev);
+#endif
+static int netwave_ioctl(struct net_device *, struct ifreq *, int);
+
+static void set_multicast_list(struct net_device *dev);
+
+/*
+   A linked list of "instances" of the skeleton device.  Each actual
+   PCMCIA card corresponds to one device instance, and is described
+   by one dev_link_t structure (defined in ds.h).
+
+   You may not want to use a linked list for this -- for example, the
+   memory card driver uses an array of dev_link_t pointers, where minor
+   device numbers are used to derive the corresponding array index.
+*/
+static dev_link_t *dev_list = NULL;
+
+/*
+   A dev_link_t structure has fields for most things that are needed
+   to keep track of a socket, but there will usually be some device
+   specific information that also needs to be kept track of.  The
+   'priv' pointer in a dev_link_t structure can be used to point to
+   a device-specific private data structure, like this.
+
+   A driver needs to provide a dev_node_t structure for each device
+   on a card.  In some cases, there is only one device per card (for
+   example, ethernet cards, modems).  In other cases, there may be
+   many actual or logical devices (SCSI adapters, memory cards with
+   multiple partitions).  The dev_node_t structures need to be kept
+   in a linked list starting at the 'dev' field of a dev_link_t
+   structure.  We allocate them in the card's private data structure,
+   because they generally can't be allocated dynamically.
+*/
+
+#define SIOCGIPSNAP	SIOCDEVPRIVATE		/* Site Survey Snapshot */
+/*#define SIOCGIPQTHR	SIOCDEVPRIVATE + 1*/
+
+#define MAX_ESA 10
+
+typedef struct net_addr {
+    u_char addr48[6];
+} net_addr;
+
+struct site_survey {
+    u_short length;
+    u_char  struct_revision;
+    u_char  roaming_state;
+	
+    u_char  sp_existsFlag;
+    u_char  sp_link_quality;
+    u_char  sp_max_link_quality;
+    u_char  linkQualityGoodFairBoundary;
+    u_char  linkQualityFairPoorBoundary;
+    u_char  sp_utilization;
+    u_char  sp_goodness;
+    u_char  sp_hotheadcount;
+    u_char  roaming_condition;
+	
+    net_addr sp;
+    u_char   numAPs;
+    net_addr nearByAccessPoints[MAX_ESA];
+};	
+   
+typedef struct netwave_private {
+    dev_link_t link;
+    struct net_device      dev;
+    dev_node_t node;
+    u_char     *ramBase;
+    int        timeoutCounter;
+    int        lastExec;
+    struct timer_list      watchdog;	/* To avoid blocking state */
+    struct site_survey     nss;
+    struct enet_statistics stats;
+#ifdef WIRELESS_EXT
+    struct iw_statistics   iw_stats;    /* Wireless stats */
+#endif
+} netwave_private;
+
+#ifdef NETWAVE_STATS
+static struct enet_statistics *netwave_get_stats(struct net_device *dev);
+#endif
+
+/*
+ * The Netwave card is little-endian, so won't work for big endian
+ * systems.
+ */
+static inline unsigned short get_uint16(u_char* staddr) 
+{
+    return readw(staddr); /* Return only 16 bits */
+}
+
+static inline short get_int16(u_char* staddr)
+{
+    return readw(staddr);
+}
+
+/**************************************************************************/
+
+static void cs_error(client_handle_t handle, int func, int ret)
+{
+    error_info_t err = { func, ret };
+    CardServices(ReportError, handle, &err);
+}
+
+/* 
+ * Wait until the WOC (Write Operation Complete) bit in the 
+ * ASR (Adapter Status Register) is asserted. 
+ * This should have aborted if it takes too long time. 
+ */
+static inline void wait_WOC(unsigned int iobase)
+{
+    /* Spin lock */
+    while ((inb(iobase + NETWAVE_REG_ASR) & 0x8) != 0x8) ; 
+}
+
+#ifdef WIRELESS_EXT
+static void netwave_snapshot(netwave_private *priv, u_char *ramBase, 
+			     ioaddr_t iobase) { 
+    u_short resultBuffer;
+
+    /* if time since last snapshot is > 1 sec. (100 jiffies?)  then take 
+     * new snapshot, else return cached data. This is the recommended rate.  
+     */
+    if ( jiffies - priv->lastExec > 100) { 
+	/* Take site survey  snapshot */ 
+	/*printk( KERN_DEBUG "Taking new snapshot. %ld\n", jiffies -
+	  priv->lastExec); */
+	wait_WOC(iobase); 
+	writeb(NETWAVE_CMD_SSS, ramBase + NETWAVE_EREG_CB + 0); 
+	writeb(NETWAVE_CMD_EOC, ramBase + NETWAVE_EREG_CB + 1); 
+	wait_WOC(iobase); 
+
+	/* Get result and copy to cach */ 
+	resultBuffer = readw(ramBase + NETWAVE_EREG_CRBP); 
+	copy_from_pc( &priv->nss, ramBase+resultBuffer, 
+		      sizeof(struct site_survey)); 
+    } 
+}
+#endif
+
+#ifdef WIRELESS_EXT
+/*
+ * Function netwave_get_wireless_stats (dev)
+ *
+ *    Wireless extensions statistics
+ *
+ */
+static struct iw_statistics *netwave_get_wireless_stats(struct net_device *dev)
+{	
+    unsigned long flags;
+    ioaddr_t iobase = dev->base_addr;
+    netwave_private *priv = (netwave_private *) dev->priv;
+    u_char *ramBase = priv->ramBase;
+    struct iw_statistics* wstats;
+	
+    wstats = &priv->iw_stats;
+
+    save_flags(flags);
+    cli();
+	
+    netwave_snapshot( priv, ramBase, iobase);
+
+    wstats->status = priv->nss.roaming_state;
+    wstats->qual.qual = readb( ramBase + NETWAVE_EREG_SPCQ); 
+    wstats->qual.level = readb( ramBase + NETWAVE_EREG_ISPLQ);
+    wstats->qual.noise = readb( ramBase + NETWAVE_EREG_SPU) & 0x3f;
+    wstats->discard.nwid = 0L;
+    wstats->discard.code = 0L;
+    wstats->discard.misc = 0L;
+
+    restore_flags(flags);
+    
+    return &priv->iw_stats;
+}
+#endif
+
+/*
+ * Function netwave_attach (void)
+ *
+ *     Creates an "instance" of the driver, allocating local data 
+ *     structures for one device.  The device is registered with Card 
+ *     Services.
+ *
+ *     The dev_link structure is initialized, but we don't actually
+ *     configure the card at this point -- we wait until we receive a
+ *     card insertion event.
+ */
+static dev_link_t *netwave_attach(void)
+{
+    client_reg_t client_reg;
+    dev_link_t *link;
+    struct net_device *dev;
+    netwave_private *priv;
+    int i, ret;
+    
+    DEBUG(0, "netwave_attach()\n");
+    
+    /* Perform some cleanup */
+    netwave_flush_stale_links();
+
+    /* Initialize the dev_link_t structure */
+    priv = kmalloc(sizeof(*priv), GFP_KERNEL);
+    if (!priv) return NULL;
+    memset(priv, 0, sizeof(*priv));
+    link = &priv->link; dev = &priv->dev;
+    link->priv = dev->priv = priv;
+    link->release.function = &netwave_release;
+    link->release.data = (u_long)link;
+	
+    /* The io structure describes IO port mapping */
+    link->io.NumPorts1 = 16;
+    link->io.Attributes1 = IO_DATA_PATH_WIDTH_16;
+    /* link->io.NumPorts2 = 16; 
+       link->io.Attributes2 = IO_DATA_PATH_WIDTH_16; */
+    link->io.IOAddrLines = 5;
+    
+    /* Interrupt setup */
+    link->irq.Attributes = IRQ_TYPE_EXCLUSIVE | IRQ_HANDLE_PRESENT;
+    link->irq.IRQInfo1 = IRQ_INFO2_VALID|IRQ_LEVEL_ID;
+    if (irq_list[0] == -1)
+	link->irq.IRQInfo2 = irq_mask;
+    else
+	for (i = 0; i < 4; i++)
+	    link->irq.IRQInfo2 |= 1 << irq_list[i];
+    link->irq.Handler = &netwave_interrupt;
+    
+    /* General socket configuration */
+    link->conf.Attributes = CONF_ENABLE_IRQ;
+    link->conf.Vcc = 50;
+    link->conf.IntType = INT_MEMORY_AND_IO;
+    link->conf.ConfigIndex = 1;
+    link->conf.Present = PRESENT_OPTION;
+
+    /* Netwave specific entries in the device structure */
+    dev->hard_start_xmit = &netwave_start_xmit;
+    dev->set_config = &netwave_config;
+    dev->get_stats  = &netwave_get_stats;
+    dev->set_multicast_list = &set_multicast_list;
+    /* wireless extensions */
+#ifdef WIRELESS_EXT
+    dev->get_wireless_stats = &netwave_get_wireless_stats;
+#endif
+    dev->do_ioctl = &netwave_ioctl;
+
+#ifdef HAVE_NETIF_QUEUE
+    dev->tx_timeout = &netwave_watchdog;
+    dev->watchdog_timeo = TX_TIMEOUT;
+#else
+    /* Set the watchdog timer */
+    priv->watchdog.function = &netwave_watchdog;
+    priv->watchdog.data = (unsigned long) dev;
+#endif
+
+    ether_setup(dev);
+    dev->name = priv->node.dev_name;
+    dev->open = &netwave_open;
+    dev->stop = &netwave_close;
+    link->irq.Instance = dev;
+    
+    /* Register with Card Services */
+    link->next = dev_list;
+    dev_list = link;
+    client_reg.dev_info = &dev_info;
+    client_reg.Attributes = INFO_IO_CLIENT | INFO_CARD_SHARE;
+    client_reg.EventMask =
+	CS_EVENT_CARD_INSERTION | CS_EVENT_CARD_REMOVAL |
+	CS_EVENT_RESET_PHYSICAL | CS_EVENT_CARD_RESET |
+	CS_EVENT_PM_SUSPEND | CS_EVENT_PM_RESUME;
+    client_reg.event_handler = &netwave_event;
+    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);
+	netwave_detach(link);
+	return NULL;
+    }
+
+    return link;
+} /* netwave_attach */
+
+/*
+ * Function netwave_detach (link)
+ *
+ *    This deletes a driver "instance".  The device is de-registered
+ *    with Card Services.  If it has been released, all local data
+ *    structures are freed.  Otherwise, the structures will be freed
+ *    when the device is released.
+ */
+static void netwave_detach(dev_link_t *link)
+{
+    netwave_private *priv = link->priv;
+    dev_link_t **linkp;
+
+    DEBUG(0, "netwave_detach(0x%p)\n", link);
+  
+    /*
+	  If the device is currently configured and active, we won't
+	  actually delete it yet.  Instead, it is marked so that when
+	  the release() function is called, that will trigger a proper
+	  detach().
+	*/
+    del_timer(&link->release);
+    if (link->state & DEV_CONFIG) {
+	netwave_release((u_long) link);
+	if (link->state & DEV_STALE_CONFIG) {
+	    DEBUG(1, "netwave_cs: detach postponed, '%s' still "
+		  "locked\n", link->dev->dev_name);
+	    link->state |= DEV_STALE_LINK;
+	    return;
+	}
+    }
+	
+    /* Break the link with Card Services */
+    if (link->handle)
+	CardServices(DeregisterClient, link->handle);
+    
+    /* Locate device structure */
+    for (linkp = &dev_list; *linkp; linkp = &(*linkp)->next)
+	if (*linkp == link) break;
+    if (*linkp == NULL)
+      {
+	DEBUG(1, "netwave_cs: detach fail, '%s' not in list\n",
+	      link->dev->dev_name);
+	return;
+      }
+
+    /* Unlink device structure, free pieces */
+    *linkp = link->next;
+    if (link->dev)
+	unregister_netdev(&priv->dev);
+    kfree(priv);
+    
+} /* netwave_detach */
+
+/*
+ * Function netwave_flush_stale_links (void)
+ *
+ *    This deletes all driver "instances" that need to be deleted.
+ *    Sometimes, netwave_detach can't be performed following a call from
+ *    cardmgr (device still open) and the device is put in a STALE_LINK
+ *    state.
+ *    This function is in charge of making the cleanup...
+ */
+static void netwave_flush_stale_links(void)
+{
+    dev_link_t *	link;		/* Current node in linked list */
+    dev_link_t *	next;		/* Next node in linked list */
+
+    DEBUG(1, "netwave_flush_stale_links(0x%p)\n", dev_list);
+
+    /* Go through the list */
+    for (link = dev_list; link; link = next) {
+        next = link->next;
+        /* Check if in need of being removed */
+        if(link->state & DEV_STALE_LINK)
+	    netwave_detach(link);
+    }
+} /* netwave_flush_stale_links */
+
+/*
+ * Function netwave_ioctl (dev, rq, cmd)
+ *
+ *     Perform ioctl : config & info stuff
+ *     This is the stuff that are treated the wireless extensions (iwconfig)
+ *
+ */
+static int netwave_ioctl(struct net_device *dev, /* ioctl device */
+			 struct ifreq *rq,	 /* Data passed */
+			 int	cmd)	     /* Ioctl number */
+{
+    unsigned long flags;
+    int			ret = 0;
+#ifdef WIRELESS_EXT
+    ioaddr_t iobase = dev->base_addr;
+    netwave_private *priv = (netwave_private *) dev->priv;
+    u_char *ramBase = priv->ramBase;
+    struct iwreq *wrq = (struct iwreq *) rq;
+#endif
+	
+    DEBUG(0, "%s: ->netwave_ioctl(cmd=0x%X)\n", dev->name, cmd);
+	
+    /* Disable interrupts & save flags */
+    save_flags(flags);
+    cli();
+
+    /* Look what is the request */
+    switch(cmd) {
+	/* --------------- WIRELESS EXTENSIONS --------------- */
+#ifdef WIRELESS_EXT
+    case SIOCGIWNAME:
+	/* Get name */
+	strcpy(wrq->u.name, "Netwave");
+	break;
+    case SIOCSIWNWID:
+	/* Set domain */
+#if WIRELESS_EXT > 8
+	if(!wrq->u.nwid.disabled) {
+	    domain = wrq->u.nwid.value;
+#else	/* WIRELESS_EXT > 8 */
+	if(wrq->u.nwid.on) {
+	    domain = wrq->u.nwid.nwid;
+#endif	/* WIRELESS_EXT > 8 */
+	    printk( KERN_DEBUG "Setting domain to 0x%x%02x\n", 
+		    (domain >> 8) & 0x01, domain & 0xff);
+	    wait_WOC(iobase);
+	    writeb(NETWAVE_CMD_SMD, ramBase + NETWAVE_EREG_CB + 0);
+	    writeb( domain & 0xff, ramBase + NETWAVE_EREG_CB + 1);
+	    writeb((domain >>8 ) & 0x01,ramBase + NETWAVE_EREG_CB+2);
+	    writeb(NETWAVE_CMD_EOC, ramBase + NETWAVE_EREG_CB + 3);
+	} break;
+    case SIOCGIWNWID:
+	/* Read domain*/
+#if WIRELESS_EXT > 8
+	wrq->u.nwid.value = domain;
+	wrq->u.nwid.disabled = 0;
+	wrq->u.nwid.fixed = 1;
+#else	/* WIRELESS_EXT > 8 */
+	wrq->u.nwid.nwid = domain;
+	wrq->u.nwid.on = 1;
+#endif	/* WIRELESS_EXT > 8 */
+	break;
+#if WIRELESS_EXT > 8	/* Note : The API did change... */
+    case SIOCGIWENCODE:
+	/* Get scramble key */
+	if(wrq->u.encoding.pointer != (caddr_t) 0)
+	  {
+	    char	key[2];
+	    key[1] = scramble_key & 0xff;
+	    key[0] = (scramble_key>>8) & 0xff;
+	    wrq->u.encoding.flags = IW_ENCODE_ENABLED;
+	    wrq->u.encoding.length = 2;
+	    if(copy_to_user(wrq->u.encoding.pointer, key, 2))
+	      ret = -EFAULT;
+	  }
+	break;
+    case SIOCSIWENCODE:
+	/* Set  scramble key */
+	if(wrq->u.encoding.pointer != (caddr_t) 0)
+	  {
+	    char	key[2];
+	    if(copy_from_user(key, wrq->u.encoding.pointer, 2))
+	      {
+		ret = -EFAULT;
+		break;
+	      }
+	    scramble_key = (key[0] << 8) | key[1];
+	    wait_WOC(iobase);
+	    writeb(NETWAVE_CMD_SSK, ramBase + NETWAVE_EREG_CB + 0);
+	    writeb(scramble_key & 0xff, ramBase + NETWAVE_EREG_CB + 1);
+	    writeb((scramble_key>>8) & 0xff, ramBase + NETWAVE_EREG_CB + 2);
+	    writeb(NETWAVE_CMD_EOC, ramBase + NETWAVE_EREG_CB + 3);
+	  }
+	break;
+    case SIOCGIWMODE:
+      /* Mode of operation */
+	if(domain & 0x100)
+	  wrq->u.mode = IW_MODE_INFRA;
+	else
+	  wrq->u.mode = IW_MODE_ADHOC;
+      break;
+#else /* WIRELESS_EXT > 8 */
+    case SIOCGIWENCODE:
+	/* Get scramble key */
+	wrq->u.encoding.code = scramble_key;
+	wrq->u.encoding.method = 1;
+	break;
+    case SIOCSIWENCODE:
+	/* Set  scramble key */
+	scramble_key = wrq->u.encoding.code;
+	wait_WOC(iobase);
+	writeb(NETWAVE_CMD_SSK, ramBase + NETWAVE_EREG_CB + 0);
+	writeb(scramble_key & 0xff, ramBase + NETWAVE_EREG_CB + 1);
+	writeb((scramble_key>>8) & 0xff, ramBase + NETWAVE_EREG_CB + 2);
+	writeb(NETWAVE_CMD_EOC, ramBase + NETWAVE_EREG_CB + 3);
+	break;
+#endif /* WIRELESS_EXT > 8 */
+   case SIOCGIWRANGE:
+       /* Basic checking... */
+       if(wrq->u.data.pointer != (caddr_t) 0) {
+	   struct iw_range	range;
+		   
+	   /* Set the length (useless : its constant...) */
+	   wrq->u.data.length = sizeof(struct iw_range);
+		   
+	   /* Set information in the range struct */
+	   range.throughput = 450 * 1000;	/* don't argue on this ! */
+	   range.min_nwid = 0x0000;
+	   range.max_nwid = 0x01FF;
+
+	   range.num_channels = range.num_frequency = 0;
+		   
+	   range.sensitivity = 0x3F;
+	   range.max_qual.qual = 255;
+	   range.max_qual.level = 255;
+	   range.max_qual.noise = 0;
+		   
+#if WIRELESS_EXT > 7
+	   range.num_bitrates = 1;
+	   range.bitrate[0] = 1000000;	/* 1 Mb/s */
+#endif /* WIRELESS_EXT > 7 */
+
+#if WIRELESS_EXT > 8
+	   range.encoding_size[0] = 2;		/* 16 bits scrambling */
+	   range.num_encoding_sizes = 1;
+	   range.max_encoding_tokens = 1;	/* Only one key possible */
+#endif /* WIRELESS_EXT > 8 */
+
+	   /* Copy structure to the user buffer */
+	   if(copy_to_user(wrq->u.data.pointer, &range,
+			sizeof(struct iw_range)))
+	     ret = -EFAULT;
+       }
+       break;
+    case SIOCGIWPRIV:
+	/* Basic checking... */
+	if(wrq->u.data.pointer != (caddr_t) 0) {
+	    struct iw_priv_args	priv[] =
+	    {	/* cmd,		set_args,	get_args,	name */
+		{ SIOCGIPSNAP, IW_PRIV_TYPE_BYTE | IW_PRIV_SIZE_FIXED | 0, 
+		  sizeof(struct site_survey), 
+		  "getsitesurvey" },
+	    };
+			
+	    /* Set the number of ioctl available */
+	    wrq->u.data.length = 1;
+			
+	    /* Copy structure to the user buffer */
+	    if(copy_to_user(wrq->u.data.pointer, (u_char *) priv,
+			 sizeof(priv)))
+	      ret = -EFAULT;
+	} 
+	break;
+    case SIOCGIPSNAP:
+	if(wrq->u.data.pointer != (caddr_t) 0) {
+	    /* Take snapshot of environment */
+	    netwave_snapshot( priv, ramBase, iobase);
+	    wrq->u.data.length = priv->nss.length;
+	    /* Copy structure to the user buffer */
+	    if(copy_to_user(wrq->u.data.pointer, 
+			 (u_char *) &priv->nss,
+			 sizeof( struct site_survey)))
+	      {
+		printk(KERN_DEBUG "Bad buffer!\n");
+		break;
+	      }
+
+	    priv->lastExec = jiffies;
+	}
+	break;
+#endif
+    default:
+	ret = -EOPNOTSUPP;
+    }
+	
+    /* ReEnable interrupts & restore flags */
+    restore_flags(flags);
+    
+    return ret;
+}
+
+/*
+ * Function netwave_pcmcia_config (link)
+ *
+ *     netwave_pcmcia_config() is scheduled to run after a CARD_INSERTION 
+ *     event is received, to configure the PCMCIA socket, and to make the
+ *     device available to the system. 
+ *
+ */
+
+#define CS_CHECK(fn, args...) \
+while ((last_ret=CardServices(last_fn=(fn), args))!=0) goto cs_failed
+
+static void netwave_pcmcia_config(dev_link_t *link) {
+    client_handle_t handle = link->handle;
+    netwave_private *priv = link->priv;
+    struct net_device *dev = &priv->dev;
+    tuple_t tuple;
+    cisparse_t parse;
+    int i, j, last_ret, last_fn;
+    u_char buf[64];
+    win_req_t req;
+    memreq_t mem;
+    u_char *ramBase = NULL;
+
+    DEBUG(0, "netwave_pcmcia_config(0x%p)\n", link);
+
+    /*
+      This reads the card's CONFIG tuple to find its configuration
+      registers.
+    */
+    tuple.Attributes = 0;
+    tuple.TupleData = (cisdata_t *) buf;
+    tuple.TupleDataMax = 64;
+    tuple.TupleOffset = 0;
+    tuple.DesiredTuple = CISTPL_CONFIG;
+    CS_CHECK(GetFirstTuple, handle, &tuple);
+    CS_CHECK(GetTupleData, handle, &tuple);
+    CS_CHECK(ParseTuple, handle, &tuple, &parse);
+    link->conf.ConfigBase = parse.config.base;
+    link->conf.Present = parse.config.rmask[0];
+    
+    /* Configure card */
+    link->state |= DEV_CONFIG;
+	
+    /*
+     *  Try allocating IO ports.  This tries a few fixed addresses.
+     *  If you want, you can also read the card's config table to
+     *  pick addresses -- see the serial driver for an example.
+     */
+    for (j = 0x0; j < 0x400; j += 0x20) {
+	link->io.BasePort1 = j ^ 0x300;
+	i = CardServices(RequestIO, link->handle, &link->io);
+	if (i == CS_SUCCESS) break;
+    }
+    if (i != CS_SUCCESS) {
+	cs_error(link->handle, RequestIO, i);
+	goto failed;
+    }
+		
+    /*
+     *  Now allocate an interrupt line.  Note that this does not
+     *  actually assign a handler to the interrupt.
+     */
+    CS_CHECK(RequestIRQ, handle, &link->irq);
+	
+    /*
+     *  This actually configures the PCMCIA socket -- setting up
+     *  the I/O windows and the interrupt mapping.
+     */
+    CS_CHECK(RequestConfiguration, handle, &link->conf);
+    
+    /*
+     *  Allocate a 32K memory window.  Note that the dev_link_t
+     *  structure provides space for one window handle -- if your
+     *  device needs several windows, you'll need to keep track of
+     *  the handles in your private data structure, link->priv.
+     */
+    DEBUG(1, "Setting mem speed of %d\n", mem_speed);
+    
+    req.Attributes = WIN_DATA_WIDTH_8|WIN_MEMORY_TYPE_CM|WIN_ENABLE;
+    req.Base = 0; req.Size = 0x8000;
+    req.AccessSpeed = mem_speed;
+    link->win = (window_handle_t)link->handle;
+    CS_CHECK(RequestWindow, &link->win, &req);
+    mem.CardOffset = 0x20000; mem.Page = 0; 
+    CS_CHECK(MapMemPage, link->win, &mem);
+    
+    /* Store base address of the common window frame */
+    ramBase = ioremap(req.Base, 0x8000);
+    ((netwave_private*)dev->priv)->ramBase = ramBase;
+    
+    dev->irq = link->irq.AssignedIRQ;
+    dev->base_addr = link->io.BasePort1;
+    if (register_netdev(dev) != 0) {
+	printk(KERN_DEBUG "netwave_cs: register_netdev() failed\n");
+	goto failed;
+    }
+	
+    link->dev = &priv->node;
+    link->state &= ~DEV_CONFIG_PENDING;
+
+    /* Reset card before reading physical address */
+    netwave_doreset(dev->base_addr, ramBase);
+    
+    /* Read the ethernet address and fill in the Netwave registers. */
+    for (i = 0; i < 6; i++) 
+	dev->dev_addr[i] = readb(ramBase + NETWAVE_EREG_PA + i);
+
+    printk(KERN_INFO "%s: Netwave: port %#3lx, irq %d, mem %lx id "
+	   "%c%c, hw_addr ", dev->name, dev->base_addr, dev->irq,
+	   (u_long) ramBase, (int) readb(ramBase+NETWAVE_EREG_NI),
+	   (int) readb(ramBase+NETWAVE_EREG_NI+1));
+    for (i = 0; i < 6; i++)
+	printk("%02X%s", dev->dev_addr[i], ((i<5) ? ":" : "\n"));
+
+    /* get revision words */
+    printk(KERN_DEBUG "Netwave_reset: revision %04x %04x\n", 
+	   get_uint16(ramBase + NETWAVE_EREG_ARW),
+	   get_uint16(ramBase + NETWAVE_EREG_ARW+2));
+    return;
+
+cs_failed:
+    cs_error(link->handle, last_fn, last_ret);
+failed:
+    netwave_release((u_long)link);
+} /* netwave_pcmcia_config */
+
+/*
+ * Function netwave_release (arg)
+ *
+ *    After a card is removed, netwave_release() will unregister the net
+ *    device, and release the PCMCIA configuration.  If the device is
+ *    still open, this will be postponed until it is closed.
+ */
+static void netwave_release(u_long arg) {
+    dev_link_t *link = (dev_link_t *)arg;
+    netwave_private *priv = link->priv;
+
+    DEBUG(0, "netwave_release(0x%p)\n", link);
+
+    /*
+      If the device is currently in use, we won't release until it
+      is actually closed.
+      */
+    if (link->open) {
+	printk(KERN_DEBUG "netwave_cs: release postponed, '%s' still open\n",
+	       link->dev->dev_name);
+	link->state |= DEV_STALE_CONFIG;
+	return;
+    }
+	
+    /* Don't bother checking to see if these succeed or not */
+    if (link->win) {
+	iounmap(priv->ramBase);
+	CardServices(ReleaseWindow, link->win);
+    }
+    CardServices(ReleaseConfiguration, link->handle);
+    CardServices(ReleaseIO, link->handle, &link->io);
+    CardServices(ReleaseIRQ, link->handle, &link->irq);
+ 
+    link->state &= ~(DEV_CONFIG | DEV_STALE_CONFIG);
+    
+} /* netwave_release */
+
+/*
+ * Function netwave_event (event, priority, args)
+ *
+ *    The card status event handler.  Mostly, this schedules other
+ *    stuff to run after an event is received.  A CARD_REMOVAL event
+ *    also sets some flags to discourage the net drivers from trying
+ *    to talk to the card any more.
+ *
+ *    When a CARD_REMOVAL event is received, we immediately set a flag
+ *    to block future accesses to this device.  All the functions that
+ *    actually access the device should check this flag to make sure
+ *    the card is still present.
+ *
+ */
+static int netwave_event(event_t event, int priority,
+			 event_callback_args_t *args) {
+    dev_link_t *link = args->client_data;
+    netwave_private *priv = link->priv;
+    struct net_device *dev = &priv->dev;
+	
+    DEBUG(1, "netwave_event(0x%06x)\n", event);
+  
+    switch (event) {
+    case CS_EVENT_REGISTRATION_COMPLETE:
+	DEBUG(0, "netwave_cs: registration complete\n");
+	break;
+
+    case CS_EVENT_CARD_REMOVAL:
+	link->state &= ~DEV_PRESENT;
+	if (link->state & DEV_CONFIG) {
+	    netif_device_detach(dev);
+	    mod_timer(&link->release, jiffies + HZ/20);
+	}
+	break;
+    case CS_EVENT_CARD_INSERTION:
+	link->state |= DEV_PRESENT | DEV_CONFIG_PENDING;
+	netwave_pcmcia_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 (link->open)
+		netif_device_detach(dev);
+	    CardServices(ReleaseConfiguration, link->handle);
+	}
+	break;
+    case CS_EVENT_PM_RESUME:
+	link->state &= ~DEV_SUSPEND;
+	/* Fall through... */
+    case CS_EVENT_CARD_RESET:
+	if (link->state & DEV_CONFIG) {
+	    CardServices(RequestConfiguration, link->handle, &link->conf);
+	    if (link->open) {
+		netwave_reset(dev);
+		netif_device_attach(dev);
+	    }
+	}
+	break;
+    }
+    return 0;
+} /* netwave_event */
+
+/*
+ * Function netwave_doreset (ioBase, ramBase)
+ *
+ *    Proper hardware reset of the card.
+ */
+static void netwave_doreset(ioaddr_t ioBase, u_char* ramBase) {
+    /* Reset card */
+    wait_WOC(ioBase);
+    outb(0x80, ioBase + NETWAVE_REG_PMR);
+    writeb(0x08, ramBase + NETWAVE_EREG_ASCC); /* Bit 3 is WOC */
+    outb(0x0, ioBase + NETWAVE_REG_PMR); /* release reset */
+}
+
+/*
+ * Function netwave_reset (dev)
+ *
+ *    Reset and restore all of the netwave registers 
+ */
+static void netwave_reset(struct net_device *dev) {
+    /* u_char state; */
+    netwave_private *priv = (netwave_private*) dev->priv;
+    u_char *ramBase = priv->ramBase;
+    ioaddr_t iobase = dev->base_addr;
+
+    DEBUG(0, "netwave_reset: Done with hardware reset\n");
+
+    priv->timeoutCounter = 0;
+
+#ifndef HAVE_NETIF_QUEUE
+    /* If watchdog was activated, kill it ! */
+    del_timer(&priv->watchdog);
+#endif
+
+    /* Reset card */
+    netwave_doreset(iobase, ramBase);
+    printk(KERN_DEBUG "netwave_reset: Done with hardware reset\n");
+	
+    /* Write a NOP to check the card */
+    wait_WOC(iobase);
+    writeb(NETWAVE_CMD_NOP, ramBase + NETWAVE_EREG_CB + 0);
+    writeb(NETWAVE_CMD_EOC, ramBase + NETWAVE_EREG_CB + 1);
+	
+    /* Set receive conf */
+    wait_WOC(iobase);
+    writeb(NETWAVE_CMD_SRC, ramBase + NETWAVE_EREG_CB + 0);
+    writeb(rxConfRxEna + rxConfBcast, ramBase + NETWAVE_EREG_CB + 1);
+    writeb(NETWAVE_CMD_EOC, ramBase + NETWAVE_EREG_CB + 2);
+    
+    /* Set transmit conf */
+    wait_WOC(iobase);
+    writeb(NETWAVE_CMD_STC, ramBase + NETWAVE_EREG_CB + 0);
+    writeb(txConfTxEna, ramBase + NETWAVE_EREG_CB + 1);
+    writeb(NETWAVE_CMD_EOC, ramBase + NETWAVE_EREG_CB + 2);
+    
+    /* Now set the MU Domain */
+    printk(KERN_DEBUG "Setting domain to 0x%x%02x\n", (domain >> 8) & 0x01, domain & 0xff);
+    wait_WOC(iobase);
+    writeb(NETWAVE_CMD_SMD, ramBase + NETWAVE_EREG_CB + 0);
+    writeb(domain & 0xff, ramBase + NETWAVE_EREG_CB + 1);
+    writeb((domain>>8) & 0x01, ramBase + NETWAVE_EREG_CB + 2);
+    writeb(NETWAVE_CMD_EOC, ramBase + NETWAVE_EREG_CB + 3);
+	
+    /* Set scramble key */
+    printk(KERN_DEBUG "Setting scramble key to 0x%x\n", scramble_key);
+    wait_WOC(iobase);
+    writeb(NETWAVE_CMD_SSK, ramBase + NETWAVE_EREG_CB + 0);
+    writeb(scramble_key & 0xff, ramBase + NETWAVE_EREG_CB + 1);
+    writeb((scramble_key>>8) & 0xff, ramBase + NETWAVE_EREG_CB + 2);
+    writeb(NETWAVE_CMD_EOC, ramBase + NETWAVE_EREG_CB + 3);
+
+    /* Enable interrupts, bit 4 high to keep unused
+     * source from interrupting us, bit 2 high to 
+     * set interrupt enable, 567 to enable TxDN, 
+     * RxErr and RxRdy
+     */
+    wait_WOC(iobase);
+    outb(imrConfIENA+imrConfRFU1, iobase + NETWAVE_REG_IMR);
+
+    /* Hent 4 bytes fra 0x170. Skal vaere 0a,29,88,36
+     * waitWOC
+     * skriv 80 til d000:3688
+     * sjekk om det ble 80
+     */
+    
+    /* Enable Receiver */
+    wait_WOC(iobase);
+    writeb(NETWAVE_CMD_ER, ramBase + NETWAVE_EREG_CB + 0);
+    writeb(NETWAVE_CMD_EOC, ramBase + NETWAVE_EREG_CB + 1);
+	
+    /* Set the IENA bit in COR */
+    wait_WOC(iobase);
+    outb(corConfIENA + corConfLVLREQ, iobase + NETWAVE_REG_COR);
+}
+
+/*
+ * Function netwave_config (dev, map)
+ *
+ *    Configure device, this work is done by netwave_pcmcia_config when a
+ *    card is inserted
+ */
+static int netwave_config(struct net_device *dev, struct ifmap *map) {
+    return 0; 
+}
+
+/*
+ * Function netwave_hw_xmit (data, len, dev)    
+ */
+static int netwave_hw_xmit(unsigned char* data, int len,
+			   struct net_device* dev) {
+    unsigned long flags;
+    unsigned int TxFreeList,
+	         curBuff,
+	         MaxData, 
+                 DataOffset;
+    int tmpcount; 
+	
+    netwave_private *priv = (netwave_private *) dev->priv;
+    u_char* ramBase = priv->ramBase;
+    ioaddr_t iobase = dev->base_addr;
+	
+    /* Disable interrupts & save flags */
+    save_flags(flags);
+    cli();
+
+    /* Check if there are transmit buffers available */
+    wait_WOC(iobase);
+    if ((inb(iobase+NETWAVE_REG_ASR) & NETWAVE_ASR_TXBA) == 0) {
+	/* No buffers available */
+	printk(KERN_DEBUG "netwave_hw_xmit: %s - no xmit buffers available.\n",
+	       dev->name);
+	return 1;
+    }
+
+    add_tx_bytes(&priv->stats, len);
+
+    DEBUG(3, "Transmitting with SPCQ %x SPU %x LIF %x ISPLQ %x\n",
+	  readb(ramBase + NETWAVE_EREG_SPCQ),
+	  readb(ramBase + NETWAVE_EREG_SPU),
+	  readb(ramBase + NETWAVE_EREG_LIF),
+	  readb(ramBase + NETWAVE_EREG_ISPLQ));
+
+    /* Now try to insert it into the adapters free memory */
+    wait_WOC(iobase);
+    TxFreeList = get_uint16(ramBase + NETWAVE_EREG_TDP);
+    MaxData    = get_uint16(ramBase + NETWAVE_EREG_TDP+2);
+    DataOffset = get_uint16(ramBase + NETWAVE_EREG_TDP+4);
+	
+    DEBUG(3, "TxFreeList %x, MaxData %x, DataOffset %x\n",
+	  TxFreeList, MaxData, DataOffset);
+
+    /* Copy packet to the adapter fragment buffers */
+    curBuff = TxFreeList; 
+    tmpcount = 0; 
+    while (tmpcount < len) {
+	int tmplen = len - tmpcount; 
+	copy_to_pc(ramBase + curBuff + DataOffset, data + tmpcount, 
+		   (tmplen < MaxData) ? tmplen : MaxData);
+	tmpcount += MaxData;
+			
+	/* Advance to next buffer */
+	curBuff = get_uint16(ramBase + curBuff);
+    }
+    
+    /* Now issue transmit list */
+    wait_WOC(iobase);
+    writeb(NETWAVE_CMD_TL, ramBase + NETWAVE_EREG_CB + 0);
+    writeb(len & 0xff, ramBase + NETWAVE_EREG_CB + 1);
+    writeb((len>>8) & 0xff, ramBase + NETWAVE_EREG_CB + 2);
+    writeb(NETWAVE_CMD_EOC, ramBase + NETWAVE_EREG_CB + 3);
+
+#ifndef HAVE_NETIF_QUEUE
+    /* If watchdog not already active, activate it... */
+    mod_timer(&priv->watchdog, jiffies + TX_TIMEOUT);
+#endif
+    restore_flags( flags);
+    return 0;
+}
+
+static int netwave_start_xmit(struct sk_buff *skb, struct net_device *dev) {
+	/* This flag indicate that the hardware can't perform a transmission.
+	 * Theoritically, NET3 check it before sending a packet to the driver,
+	 * but in fact it never do that and pool continuously.
+	 * As the watchdog will abort too long transmissions, we are quite safe...
+	 */
+
+#ifndef HAVE_NETIF_QUEUE
+    if (dev->tbusy) {
+	/* Handled by watchdog */
+	return 1;
+#if 0
+	/* If we get here, some higher level has decided we are broken.
+	   There should really be a 'kick me' function call instead.
+	   */
+	int tickssofar = jiffies - dev->trans_start;
+	if (tickssofar < TX_TIMEOUT) 
+	  return 1;
+	netwave_watchdog((u_long)dev);
+#endif
+    }
+#endif
+
+    skb_tx_check(dev, skb);
+    netif_stop_queue(dev);
+
+    {
+	short length = ETH_ZLEN < skb->len ? skb->len : ETH_ZLEN;
+	unsigned char* buf = skb->data;
+	
+	if (netwave_hw_xmit( buf, length, dev) == 1) {
+	    /* Some error, let's make them call us another time? */
+	    netif_start_queue(dev);
+	}
+	dev->trans_start = jiffies;
+    }
+    DEV_KFREE_SKB(skb);
+    
+    return 0;
+} /* netwave_start_xmit */
+
+/*
+ * Function netwave_interrupt (irq, dev_id, regs)
+ *
+ *    This function is the interrupt handler for the Netwave card. This
+ *    routine will be called whenever: 
+ *	  1. A packet is received.
+ *	  2. A packet has successfully been transfered and the unit is
+ *	     ready to transmit another packet.
+ *	  3. A command has completed execution.
+ */
+static void netwave_interrupt(int irq, void* dev_id, struct pt_regs *regs) {
+    ioaddr_t iobase;
+    u_char *ramBase;
+    struct net_device *dev = (struct net_device *)dev_id;
+    struct netwave_private *priv = dev->priv;
+    dev_link_t *link = &priv->link;
+    int i;
+    
+    if (!netif_device_present(dev))
+	return;
+    
+    iobase = dev->base_addr;
+    ramBase = priv->ramBase;
+	
+    /* Now find what caused the interrupt, check while interrupts ready */
+    for (i = 0; i < 10; i++) {
+	u_char status;
+		
+	wait_WOC(iobase);	
+	if (!(inb(iobase+NETWAVE_REG_CCSR) & 0x02))
+	    break; /* None of the interrupt sources asserted */
+	
+        status = inb(iobase + NETWAVE_REG_ASR);
+		
+	if (!DEV_OK(link)) {
+	    DEBUG(1, "netwave_interrupt: Interrupt with status 0x%x "
+		  "from removed or suspended card!\n", status);
+	    break;
+	}
+		
+	/* RxRdy */
+	if (status & 0x80) {
+	    netwave_rx(dev);
+	    /* wait_WOC(iobase); */
+	    /* RxRdy cannot be reset directly by the host */
+	}
+	/* RxErr */
+	if (status & 0x40) {
+	    u_char rser;
+			
+	    rser = readb(ramBase + NETWAVE_EREG_RSER);			
+	    
+	    if (rser & 0x04) {
+		++priv->stats.rx_dropped; 
+		++priv->stats.rx_crc_errors;
+	    }
+	    if (rser & 0x02)
+		++priv->stats.rx_frame_errors;
+			
+	    /* Clear the RxErr bit in RSER. RSER+4 is the
+	     * write part. Also clear the RxCRC (0x04) and 
+	     * RxBig (0x02) bits if present */
+	    wait_WOC(iobase);
+	    writeb(0x40 | (rser & 0x06), ramBase + NETWAVE_EREG_RSER + 4);
+
+	    /* Write bit 6 high to ASCC to clear RxErr in ASR,
+	     * WOC must be set first! 
+	     */
+	    wait_WOC(iobase);
+	    writeb(0x40, ramBase + NETWAVE_EREG_ASCC);
+
+	    /* Remember to count up priv->stats on error packets */
+	    ++priv->stats.rx_errors;
+	}
+	/* TxDN */
+	if (status & 0x20) {
+	    int txStatus;
+
+	    txStatus = readb(ramBase + NETWAVE_EREG_TSER);
+	    DEBUG(3, "Transmit done. TSER = %x id %x\n", 
+		  txStatus, readb(ramBase + NETWAVE_EREG_TSER + 1));
+	    
+	    if (txStatus & 0x20) {
+		/* Transmitting was okay, clear bits */
+		wait_WOC(iobase);
+		writeb(0x2f, ramBase + NETWAVE_EREG_TSER + 4);
+		++priv->stats.tx_packets;
+	    }
+			
+	    if (txStatus & 0xd0) {
+		if (txStatus & 0x80) {
+		    ++priv->stats.collisions; /* Because of /proc/net/dev*/
+		    /* ++priv->stats.tx_aborted_errors; */
+		    /* printk("Collision. %ld\n", jiffies - dev->trans_start); */
+		}
+		if (txStatus & 0x40) 
+		    ++priv->stats.tx_carrier_errors;
+		/* 0x80 TxGU Transmit giveup - nine times and no luck
+		 * 0x40 TxNOAP No access point. Discarded packet.
+		 * 0x10 TxErr Transmit error. Always set when 
+		 *      TxGU and TxNOAP is set. (Those are the only ones
+		 *      to set TxErr).
+		 */
+		DEBUG(3, "netwave_interrupt: TxDN with error status %x\n", 
+		      txStatus);
+		
+		/* Clear out TxGU, TxNOAP, TxErr and TxTrys */
+		wait_WOC(iobase);
+		writeb(0xdf & txStatus, ramBase+NETWAVE_EREG_TSER+4);
+		++priv->stats.tx_errors;
+	    }
+	    DEBUG(3, "New status is TSER %x ASR %x\n",
+		  readb(ramBase + NETWAVE_EREG_TSER),
+		  inb(iobase + NETWAVE_REG_ASR));
+
+#ifndef HAVE_NETIF_QUEUE
+	    /* If watchdog was activated, kill it ! */
+	    del_timer(&priv->watchdog);
+#endif
+
+	    netif_wake_queue(dev);
+	}
+	/* TxBA, this would trigger on all error packets received */
+	/* if (status & 0x01) {
+	   DEBUG(4, "Transmit buffers available, %x\n", status);
+	   }
+	   */
+    }
+} /* netwave_interrupt */
+
+/*
+ * Function netwave_watchdog (a)
+ *
+ *    Watchdog : when we start a transmission, we set a timer in the
+ *    kernel.  If the transmission complete, this timer is disabled. If
+ *    it expire, we reset the card.
+ *
+ */
+#ifdef HAVE_NETIF_QUEUE
+static void netwave_watchdog(struct net_device *dev) {
+#else
+static void netwave_watchdog(u_long a) {
+    struct net_device *dev = (struct net_device *)a;
+#endif
+
+    DEBUG(1, "%s: netwave_watchdog: watchdog timer expired\n", dev->name);
+    netwave_reset(dev);
+    dev->trans_start = jiffies;
+    netif_start_queue(dev);
+} /* netwave_watchdog */
+
+static struct enet_statistics *netwave_get_stats(struct net_device *dev) {
+    netwave_private *priv = (netwave_private*)dev->priv;
+
+    update_stats(dev);
+
+    DEBUG(2, "netwave: SPCQ %x SPU %x LIF %x ISPLQ %x MHS %x rxtx %x"
+	  " %x tx %x %x %x %x\n", 
+	  readb(priv->ramBase + NETWAVE_EREG_SPCQ),
+	  readb(priv->ramBase + NETWAVE_EREG_SPU),
+	  readb(priv->ramBase + NETWAVE_EREG_LIF),
+	  readb(priv->ramBase + NETWAVE_EREG_ISPLQ),
+	  readb(priv->ramBase + NETWAVE_EREG_MHS),
+	  readb(priv->ramBase + NETWAVE_EREG_EC + 0xe),
+	  readb(priv->ramBase + NETWAVE_EREG_EC + 0xf),
+	  readb(priv->ramBase + NETWAVE_EREG_EC + 0x18),
+	  readb(priv->ramBase + NETWAVE_EREG_EC + 0x19),
+	  readb(priv->ramBase + NETWAVE_EREG_EC + 0x1a),
+	  readb(priv->ramBase + NETWAVE_EREG_EC + 0x1b));
+
+    return &priv->stats;
+}
+
+static void update_stats(struct net_device *dev) {
+    unsigned long flags;
+
+    save_flags(flags);
+    cli();
+
+/*     netwave_private *priv = (netwave_private*) dev->priv;
+    priv->stats.rx_packets = readb(priv->ramBase + 0x18e); 
+    priv->stats.tx_packets = readb(priv->ramBase + 0x18f); */
+
+    restore_flags(flags);
+}
+
+static int netwave_rx(struct net_device *dev) {
+    netwave_private *priv = (netwave_private*)(dev->priv);
+    u_char *ramBase = priv->ramBase;
+    ioaddr_t iobase = dev->base_addr;
+    u_char rxStatus;
+    struct sk_buff *skb = NULL;
+    unsigned int curBuffer,
+		rcvList;
+    int rcvLen;
+    int tmpcount = 0;
+    int dataCount, dataOffset;
+    int i;
+    u_char *ptr;
+	
+    DEBUG(3, "xinw_rx: Receiving ... \n");
+
+    /* Receive max 10 packets for now. */
+    for (i = 0; i < 10; i++) {
+	/* Any packets? */
+	wait_WOC(iobase);
+	rxStatus = readb(ramBase + NETWAVE_EREG_RSER);		
+	if ( !( rxStatus & 0x80)) /* No more packets */
+	    break;
+		
+	/* Check if multicast/broadcast or other */
+	/* multicast = (rxStatus & 0x20);  */
+		
+	/* The receive list pointer and length of the packet */
+	wait_WOC(iobase);
+	rcvLen  = get_int16( ramBase + NETWAVE_EREG_RDP);
+	rcvList = get_uint16( ramBase + NETWAVE_EREG_RDP + 2);
+		
+	if (rcvLen < 0) {
+	    printk(KERN_DEBUG "netwave_rx: Receive packet with len %d\n", 
+		   rcvLen);
+	    return 0;
+	}
+		
+	skb = dev_alloc_skb(rcvLen+5);
+	if (skb == NULL) {
+	    DEBUG(1, "netwave_rx: Could not allocate an sk_buff of "
+		  "length %d\n", rcvLen);
+	    ++priv->stats.rx_dropped; 
+	    /* Tell the adapter to skip the packet */
+	    wait_WOC(iobase);
+	    writeb(NETWAVE_CMD_SRP, ramBase + NETWAVE_EREG_CB + 0);
+	    writeb(NETWAVE_CMD_EOC, ramBase + NETWAVE_EREG_CB + 1);
+	    return 0;
+	}
+
+	skb_reserve( skb, 2);  /* Align IP on 16 byte */
+	skb_put( skb, rcvLen);
+	skb->dev = dev;
+
+	/* Copy packet fragments to the skb data area */
+	ptr = (u_char*) skb->data;
+	curBuffer = rcvList;
+	tmpcount = 0; 
+	while ( tmpcount < rcvLen) {
+	    /* Get length and offset of current buffer */
+	    dataCount  = get_uint16( ramBase+curBuffer+2);
+	    dataOffset = get_uint16( ramBase+curBuffer+4);
+		
+	    copy_from_pc( ptr + tmpcount,
+			  ramBase+curBuffer+dataOffset, dataCount);
+
+	    tmpcount += dataCount;
+		
+	    /* Point to next buffer */
+	    curBuffer = get_uint16(ramBase + curBuffer);
+	}
+	
+	skb->protocol = eth_type_trans(skb,dev);
+	/* Queue packet for network layer */
+	netif_rx(skb);
+		
+	/* Got the packet, tell the adapter to skip it */
+	wait_WOC(iobase);
+	writeb(NETWAVE_CMD_SRP, ramBase + NETWAVE_EREG_CB + 0);
+	writeb(NETWAVE_CMD_EOC, ramBase + NETWAVE_EREG_CB + 1);
+	DEBUG(3, "Packet reception ok\n");
+		
+	priv->stats.rx_packets++;
+
+	add_rx_bytes(&priv->stats, skb->len);
+    }
+    return 0;
+}
+
+static int netwave_open(struct net_device *dev) {
+    netwave_private *priv = dev->priv;
+    dev_link_t *link = &priv->link;
+
+    DEBUG(1, "netwave_open: starting.\n");
+    
+    if (!DEV_OK(link))
+	return -ENODEV;
+
+    link->open++;
+    MOD_INC_USE_COUNT;
+
+    netif_start_queue(dev);
+    netif_mark_up(dev);
+    netwave_reset(dev);
+	
+    return 0;
+}
+
+static int netwave_close(struct net_device *dev) {
+    netwave_private *priv = (netwave_private *)dev->priv;
+    dev_link_t *link = &priv->link;
+
+    DEBUG(1, "netwave_close: finishing.\n");
+
+#ifndef HAVE_NETIF_QUEUE
+    /* If watchdog was activated, kill it ! */
+    del_timer(&priv->watchdog);
+#endif
+
+    link->open--;
+    netif_stop_queue(dev);
+    netif_mark_down(dev);
+    if (link->state & DEV_STALE_CONFIG)
+	mod_timer(&link->release, jiffies + HZ/20);
+	
+    MOD_DEC_USE_COUNT;
+    return 0;
+}
+
+static int __init init_netwave_cs(void) {
+    servinfo_t serv;
+
+    DEBUG(0, "%s\n", version);
+
+    CardServices(GetCardServicesInfo, &serv);
+    if (serv.Revision != CS_RELEASE_CODE) {
+	printk("netwave_cs: Card Services release does not match!\n");
+	return -1;
+    }
+ 
+    register_pccard_driver(&dev_info, &netwave_attach, &netwave_detach);
+	
+    return 0;
+}
+
+static void __exit exit_netwave_cs(void) {
+    DEBUG(1, "netwave_cs: unloading\n");
+
+    unregister_pccard_driver(&dev_info);
+
+    /* Do some cleanup of the device list */
+    netwave_flush_stale_links();
+    if(dev_list != NULL)	/* Critical situation */
+        printk("netwave_cs: devices remaining when removing module\n");
+}
+
+module_init(init_netwave_cs);
+module_exit(exit_netwave_cs);
+
+/* 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.
+ */
+static void set_multicast_list(struct net_device *dev)
+{
+    ioaddr_t iobase = dev->base_addr;
+    u_char* ramBase = ((netwave_private*) dev->priv)->ramBase;
+    u_char  rcvMode = 0;
+   
+#ifdef PCMCIA_DEBUG
+    if (pc_debug > 2) {
+	static int old = 0;
+	if (old != dev->mc_count) {
+	    old = dev->mc_count;
+	    DEBUG(0, "%s: setting Rx mode to %d addresses.\n",
+		  dev->name, dev->mc_count);
+	}
+    }
+#endif
+	
+    if (dev->mc_count || (dev->flags & IFF_ALLMULTI)) {
+	/* Multicast Mode */
+	rcvMode = rxConfRxEna + rxConfAMP + rxConfBcast;
+    } else if (dev->flags & IFF_PROMISC) {
+	/* Promiscous mode */
+	rcvMode = rxConfRxEna + rxConfPro + rxConfAMP + rxConfBcast;
+    } else {
+	/* Normal mode */
+	rcvMode = rxConfRxEna + rxConfBcast;
+    }
+	
+    /* printk("netwave set_multicast_list: rcvMode to %x\n", rcvMode);*/
+    /* Now set receive mode */
+    wait_WOC(iobase);
+    writeb(NETWAVE_CMD_SRC, ramBase + NETWAVE_EREG_CB + 0);
+    writeb(rcvMode, ramBase + NETWAVE_EREG_CB + 1);
+    writeb(NETWAVE_CMD_EOC, ramBase + NETWAVE_EREG_CB + 2);
+}
Index: oldkernel/linux/pcmcia-cs-3.1.15/wireless/ray_cs.c
diff -u /dev/null linux/pcmcia-cs-3.1.15/wireless/ray_cs.c:1.1
--- /dev/null	Mon Jul 31 21:15:12 2000
+++ linux/pcmcia-cs-3.1.15/wireless/ray_cs.c	Fri Jul  7 16:34:59 2000
@@ -0,0 +1,2935 @@
+/*=============================================================================
+ *
+ * A  PCMCIA client driver for the Raylink wireless LAN card.
+ * The starting point for this module was the skeleton.c in the
+ * PCMCIA 2.9.12 package written by David Hinds, dhinds@allegro.stanford.edu
+ *
+ *
+ * Copyright (c) 1998  Corey Thomas (corey@world.std.com)
+ *
+ * This driver is free software; you can redistribute it and/or modify
+ * it under the terms of version 2 only of the GNU General Public License as 
+ * published by the Free Software Foundation.
+ *
+ * It 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
+ * 
+=============================================================================*/
+
+#include <pcmcia/config.h>
+#include <pcmcia/k_compat.h>
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/sched.h>
+#include <linux/proc_fs.h>
+#include <linux/ptrace.h>
+#include <linux/malloc.h>
+#include <linux/string.h>
+#include <linux/timer.h>
+#include <asm/io.h>
+#include <asm/system.h>
+#include <asm/byteorder.h>
+
+#include <linux/netdevice.h>
+#include <linux/etherdevice.h>
+#include <linux/if_arp.h>
+#include <linux/ioport.h>
+#include <linux/skbuff.h>
+
+#include <pcmcia/version.h>
+#include <pcmcia/cs_types.h>
+#include <pcmcia/cs.h>
+#include <pcmcia/cistpl.h>
+#include <pcmcia/cisreg.h>
+#include <pcmcia/ds.h>
+#include <pcmcia/mem_op.h>
+
+#ifdef HAS_WIRELESS_EXTENSIONS
+#include <linux/wireless.h>
+#if WIRELESS_EXT < 9
+#warning "Wireless extension v9 or newer required"
+#endif	/* WIRELESS_EXT < 9 */
+/* Warning : these stuff will slow down the driver... */
+#define WIRELESS_SPY		/* Enable spying addresses */
+/* Definitions we need for spy */
+typedef struct iw_statistics	iw_stats;
+typedef struct iw_quality	iw_qual;
+typedef u_char	mac_addr[ETH_ALEN];	/* Hardware address */
+#endif	/* HAS_WIRELESS_EXTENSIONS */
+
+#include "rayctl.h"
+#include "ray_cs.h"
+
+/* All the PCMCIA modules use PCMCIA_DEBUG to control debugging.  If
+   you do not define PCMCIA_DEBUG at all, all the debug code will be
+   left out.  If you compile with PCMCIA_DEBUG=0, the debug code will
+   be present but disabled -- but it can then be enabled for specific
+   modules at load time with a 'pc_debug=#' option to insmod.
+*/
+
+#ifdef RAYLINK_DEBUG
+#define PCMCIA_DEBUG RAYLINK_DEBUG
+#endif
+#ifdef PCMCIA_DEBUG
+static int ray_debug = 0;
+static int pc_debug = PCMCIA_DEBUG;
+MODULE_PARM(pc_debug, "i");
+/* #define DEBUG(n, args...) if (pc_debug>(n)) printk(KERN_DEBUG args); */
+#define DEBUG(n, args...) if (pc_debug>(n)) printk(args);
+#else
+#define DEBUG(n, args...)
+#endif
+/** Prototypes based on PCMCIA skeleton driver *******************************/
+static void ray_config(dev_link_t *link);
+static void ray_release(u_long arg);
+static int ray_event(event_t event, int priority, event_callback_args_t *args);
+static dev_link_t *ray_attach(void);
+static void ray_detach(dev_link_t *);
+
+/***** Prototypes indicated by device structure ******************************/
+static int ray_dev_close(struct net_device *dev);
+static int ray_dev_config(struct net_device *dev, struct ifmap *map);
+static struct enet_statistics *ray_get_stats(struct net_device *dev);
+static int ray_dev_init(struct net_device *dev);
+static int ray_dev_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd);
+static int ray_open(struct net_device *dev);
+static int ray_dev_start_xmit(struct sk_buff *skb, struct net_device *dev);
+static void set_multicast_list(struct net_device *dev);
+static void ray_update_multi_list(struct net_device *dev, int all);
+static int translate_frame(ray_dev_t *local, struct tx_msg *ptx,
+                unsigned char *data, int len);
+static void ray_build_header(ray_dev_t *local, struct tx_msg *ptx, UCHAR msg_type,
+                unsigned char *data);
+static void untranslate(ray_dev_t *local, struct sk_buff *skb, int len);
+#if WIRELESS_EXT > 7	/* If wireless extension exist in the kernel */
+static iw_stats * ray_get_wireless_stats(struct net_device *	dev);
+#endif	/* WIRELESS_EXT > 7 */
+
+/***** Prototypes for raylink functions **************************************/
+static int asc_to_int(char a);
+static void authenticate(ray_dev_t *local);
+static int build_auth_frame(ray_dev_t *local, UCHAR *dest, int auth_type);
+static void authenticate_timeout(u_long);
+static int get_free_ccs(ray_dev_t *local);
+static int get_free_tx_ccs(ray_dev_t *local);
+static void init_startup_params(ray_dev_t *local);
+static int parse_addr(char *in_str, UCHAR *out);
+static int ray_hw_xmit(unsigned char* data, int len, struct net_device* dev, UCHAR type);
+static int ray_init(struct net_device *dev);
+static int interrupt_ecf(ray_dev_t *local, int ccs);
+static void ray_reset(struct net_device *dev);
+static void ray_update_parm(struct net_device *dev, UCHAR objid, UCHAR *value, int len);
+static void verify_dl_startup(u_long);
+
+/* Prototypes for interrpt time functions **********************************/
+static void ray_interrupt (int reg, void *dev_id, struct pt_regs *regs);
+static void clear_interrupt(ray_dev_t *local);
+static void rx_deauthenticate(ray_dev_t *local, struct rcs *prcs, 
+                       unsigned int pkt_addr, int rx_len);
+static int copy_from_rx_buff(ray_dev_t *local, UCHAR *dest, int pkt_addr, int len);
+static void ray_rx(struct net_device *dev, ray_dev_t *local, struct rcs *prcs);
+static void release_frag_chain(ray_dev_t *local, struct rcs *prcs);
+static void rx_authenticate(ray_dev_t *local, struct rcs *prcs,
+                     unsigned int pkt_addr, int rx_len);
+static void rx_data(struct net_device *dev, struct rcs *prcs, unsigned int pkt_addr, 
+             int rx_len);
+static void associate(ray_dev_t *local);
+
+/* Card command functions */
+static int dl_startup_params(struct net_device *dev);
+static void join_net(u_long local);
+static void start_net(u_long local);
+/* void start_net(ray_dev_t *local); */
+
+static int ray_cs_proc_read(char *, char **, off_t, int, int *, void *);
+/* Create symbol table for registering with kernel in init_module */
+#if (LINUX_VERSION_CODE <= VERSION(2,1,17))
+static struct symbol_table ray_cs_syms = {
+#include <linux/symtab_begin.h>
+#undef X
+#define X(sym) { (void *)&sym, SYMBOL_NAME_STR(sym) }
+    X(ray_rx),
+    X(ray_dev_ioctl),
+#include <linux/symtab_end.h>
+};
+#else /* (kernel > 2.1.17) Use new kernel method of registering symbols */
+EXPORT_SYMBOL(ray_dev_ioctl);
+EXPORT_SYMBOL(ray_rx);
+#endif
+
+/*===========================================================================*/
+/* Parameters that can be set with 'insmod' */
+/* Bit map of interrupts to choose from */
+/* This means pick from 15, 14, 12, 11, 10, 9, 7, 5, 4, and 3 */
+static u_long irq_mask = 0xdeb8;
+
+/* ADHOC=0, Infrastructure=1 */
+static int net_type = ADHOC;
+
+/* Hop dwell time in Kus (1024 us units defined by 802.11) */
+static int hop_dwell = 128;
+
+/* Beacon period in Kus */
+static int beacon_period = 256;
+
+/* power save mode (0 = off, 1 = save power) */
+static int psm = 0;
+
+/* String for network's Extended Service Set ID. 32 Characters max */
+static char *essid = NULL;
+
+/* Default to encapsulation unless translation requested */
+static int translate = 1;
+
+static int country = USA;
+
+static int sniffer = 0;
+
+static int bc = 0;
+
+/* 48 bit physical card address if overriding card's real physical
+ * address is required.  Since IEEE 802.11 addresses are 48 bits
+ * like ethernet, an int can't be used, so a string is used. To
+ * allow use of addresses starting with a decimal digit, the first
+ * character must be a letter and will be ignored. This letter is
+ * followed by up to 12 hex digits which are the address.  If less
+ * than 12 digits are used, the address will be left filled with 0's.
+ * Note that bit 0 of the first byte is the broadcast bit, and evil
+ * things will happen if it is not 0 in a card address.
+ */
+static char *phy_addr = NULL;
+
+
+/* The dev_info variable is the "key" that is used to match up this
+   device driver with appropriate cards, through the card configuration
+   database.
+*/
+static dev_info_t dev_info = "ray_cs";
+
+/* A linked list of "instances" of the ray device.  Each actual
+   PCMCIA card corresponds to one device instance, and is described
+   by one dev_link_t structure (defined in ds.h).
+*/
+static dev_link_t *dev_list = NULL;
+
+/* A dev_link_t structure has fields for most things that are needed
+   to keep track of a socket, but there will usually be some device
+   specific information that also needs to be kept track of.  The
+   'priv' pointer in a dev_link_t structure can be used to point to
+   a device-specific private data structure, like this.
+*/
+static unsigned int ray_mem_speed = 500;
+MODULE_AUTHOR("Corey Thomas <corey@world.std.com>");
+MODULE_DESCRIPTION("Raylink/WebGear wireless LAN driver");
+MODULE_PARM(irq_mask,"i");
+MODULE_PARM(net_type,"i");
+MODULE_PARM(hop_dwell,"i");
+MODULE_PARM(beacon_period,"i");
+MODULE_PARM(psm,"i");
+MODULE_PARM(essid,"s");
+MODULE_PARM(translate,"i");
+MODULE_PARM(country,"i");
+MODULE_PARM(sniffer,"i");
+MODULE_PARM(bc,"i");
+MODULE_PARM(phy_addr,"s");
+MODULE_PARM(ray_mem_speed, "i");
+
+static UCHAR b5_default_startup_parms[] = {
+    0,   0,                         /* Adhoc station */
+   'L','I','N','U','X', 0,  0,  0,  /* 32 char ESSID */
+    0,  0,  0,  0,  0,  0,  0,  0,
+    0,  0,  0,  0,  0,  0,  0,  0,
+    0,  0,  0,  0,  0,  0,  0,  0,
+    1,  0,                          /* Active scan, CA Mode */
+    0,  0,  0,  0,  0,  0,          /* No default MAC addr  */
+    0x7f, 0xff,                     /* Frag threshold */
+    0x00, 0x80,                     /* Hop time 128 Kus*/
+    0x01, 0x00,                     /* Beacon period 256 Kus */
+    0x01, 0x07, 0xa3,               /* DTIM, retries, ack timeout*/
+    0x1d, 0x82, 0x4e,               /* SIFS, DIFS, PIFS */
+    0x7f, 0xff,                     /* RTS threshold */
+    0x04, 0xe2, 0x38, 0xA4,         /* scan_dwell, max_scan_dwell */
+    0x05,                           /* assoc resp timeout thresh */
+    0x08, 0x02, 0x08,               /* adhoc, infra, super cycle max*/
+    0,                              /* Promiscuous mode */
+    0x0c, 0x0bd,                    /* Unique word */
+    0x32,                           /* Slot time */
+    0xff, 0xff,                     /* roam-low snr, low snr count */
+    0x05, 0xff,                     /* Infra, adhoc missed bcn thresh */
+    0x01, 0x0b, 0x4f,               /* USA, hop pattern, hop pat length */
+/* b4 - b5 differences start here */
+    0x00, 0x3f,                     /* CW max */
+    0x00, 0x0f,                     /* CW min */
+    0x04, 0x08,                     /* Noise gain, limit offset */
+    0x28, 0x28,                     /* det rssi, med busy offsets */
+    7,                              /* det sync thresh */
+    0, 2, 2,                        /* test mode, min, max */
+    0,                              /* allow broadcast SSID probe resp */
+    0, 0,                           /* privacy must start, can join */
+    2, 0, 0, 0, 0, 0, 0, 0          /* basic rate set */
+};
+
+static UCHAR b4_default_startup_parms[] = {
+    0,   0,                         /* Adhoc station */
+   'L','I','N','U','X', 0,  0,  0,  /* 32 char ESSID */
+    0,  0,  0,  0,  0,  0,  0,  0,
+    0,  0,  0,  0,  0,  0,  0,  0,
+    0,  0,  0,  0,  0,  0,  0,  0,
+    1,  0,                          /* Active scan, CA Mode */
+    0,  0,  0,  0,  0,  0,          /* No default MAC addr  */
+    0x7f, 0xff,                     /* Frag threshold */
+    0x02, 0x00,                     /* Hop time */
+    0x00, 0x01,                     /* Beacon period */
+    0x01, 0x07, 0xa3,               /* DTIM, retries, ack timeout*/
+    0x1d, 0x82, 0xce,               /* SIFS, DIFS, PIFS */
+    0x7f, 0xff,                     /* RTS threshold */
+    0xfb, 0x1e, 0xc7, 0x5c,         /* scan_dwell, max_scan_dwell */
+    0x05,                           /* assoc resp timeout thresh */
+    0x04, 0x02, 0x4,                /* adhoc, infra, super cycle max*/
+    0,                              /* Promiscuous mode */
+    0x0c, 0x0bd,                    /* Unique word */
+    0x4e,                           /* Slot time (TBD seems wrong)*/
+    0xff, 0xff,                     /* roam-low snr, low snr count */
+    0x05, 0xff,                     /* Infra, adhoc missed bcn thresh */
+    0x01, 0x0b, 0x4e,               /* USA, hop pattern, hop pat length */
+/* b4 - b5 differences start here */
+    0x3f, 0x0f,                     /* CW max, min */
+    0x04, 0x08,                     /* Noise gain, limit offset */
+    0x28, 0x28,                     /* det rssi, med busy offsets */
+    7,                              /* det sync thresh */
+    0, 2, 2                         /* test mode, min, max*/
+};
+/*===========================================================================*/
+static unsigned char eth2_llc[] = {0xaa, 0xaa, 3, 0, 0, 0};
+
+static char hop_pattern_length[] = { 1,
+	     USA_HOP_MOD,             EUROPE_HOP_MOD,
+	     JAPAN_HOP_MOD,           KOREA_HOP_MOD,
+	     SPAIN_HOP_MOD,           FRANCE_HOP_MOD,
+	     ISRAEL_HOP_MOD,          AUSTRALIA_HOP_MOD,
+	     JAPAN_TEST_HOP_MOD
+};
+
+static char rcsid[] = " ray_cs.c,v 1.17 2000/05/16 23:37:12 root Exp - Corey Thomas corey@world.std.com";
+
+/*===========================================================================*/
+static void cs_error(client_handle_t handle, int func, int ret)
+{
+    error_info_t err = { func, ret };
+    CardServices(ReportError, handle, &err);
+}
+/*======================================================================
+
+    This bit of code is used to avoid unregistering network devices
+    at inappropriate times.  2.2 and later kernels are fairly picky
+    about when this can happen.
+    
+======================================================================*/
+
+static void flush_stale_links(void)
+{
+    dev_link_t *link, *next;
+    for (link = dev_list; link; link = next) {
+	next = link->next;
+	if (link->state & DEV_STALE_LINK)
+	    ray_detach(link);
+    }
+}
+
+/*=============================================================================
+    ray_attach() creates an "instance" of the driver, allocating
+    local data structures for one device.  The device is registered
+    with Card Services.
+    The dev_link structure is initialized, but we don't actually
+    configure the card at this point -- we wait until we receive a
+    card insertion event.
+=============================================================================*/
+static dev_link_t *ray_attach(void)
+{
+    client_reg_t client_reg;
+    dev_link_t *link;
+    ray_dev_t *local;
+    int ret;
+    struct net_device *dev;
+    
+    DEBUG(1, "ray_attach()\n");
+    flush_stale_links();
+
+    /* Initialize the dev_link_t structure */
+    link = kmalloc(sizeof(struct dev_link_t), GFP_KERNEL);
+    if (link == NULL) return link;
+    memset(link, 0, sizeof(struct dev_link_t));
+    link->release.function = &ray_release;
+    link->release.data = (u_long)link;
+
+    /* The io structure describes IO port mapping. None used here */
+    link->io.NumPorts1 = 0;
+    link->io.Attributes1 = IO_DATA_PATH_WIDTH_8;
+    link->io.IOAddrLines = 5;
+
+    /* Interrupt setup. For PCMCIA, driver takes what's given */
+    link->irq.Attributes = IRQ_TYPE_EXCLUSIVE | IRQ_HANDLE_PRESENT;
+    link->irq.IRQInfo1 = IRQ_INFO2_VALID | IRQ_LEVEL_ID;
+    link->irq.IRQInfo2 = irq_mask;
+    link->irq.Handler = &ray_interrupt;
+
+    /* General socket configuration */
+    link->conf.Attributes = CONF_ENABLE_IRQ;
+    link->conf.Vcc = 50;
+    link->conf.IntType = INT_MEMORY_AND_IO;
+    link->conf.ConfigIndex = 1;
+    link->conf.Present = PRESENT_OPTION;
+
+    /* Allocate space for private device-specific data */
+    dev = kmalloc(sizeof(struct net_device), GFP_KERNEL);
+    if (dev == NULL) {
+	kfree_s(link, sizeof(struct dev_link_t));
+	return NULL;
+    }
+    memset(dev, 0, sizeof(struct net_device));
+    link->priv = dev;
+    link->irq.Instance = dev;
+    
+    local = kmalloc(sizeof(ray_dev_t), GFP_KERNEL);
+    if (local == NULL) {
+	kfree_s(dev, sizeof(struct dev_link_t));
+	kfree_s(link, sizeof(struct dev_link_t));
+	return NULL;
+    }
+    memset(local, 0, sizeof(ray_dev_t));
+    dev->priv = local;
+    local->finder = link;
+    local->card_status = CARD_INSERTED;
+    local->authentication_state = UNAUTHENTICATED;
+    local->num_multi = 0;
+    spin_lock_init(&local->ray_lock);
+    DEBUG(2,"ray_attach link = %p,  dev = %p,  local = %p, intr = %p\n",
+          link,dev,local,&ray_interrupt);
+
+    /* Raylink entries in the device structure */
+    dev->hard_start_xmit = &ray_dev_start_xmit;
+    dev->set_config = &ray_dev_config;
+    dev->get_stats  = &ray_get_stats;
+    dev->do_ioctl = &ray_dev_ioctl;
+#if WIRELESS_EXT > 7	/* If wireless extension exist in the kernel */
+    dev->get_wireless_stats = ray_get_wireless_stats;
+#endif
+
+    dev->set_multicast_list = &set_multicast_list;
+
+    DEBUG(2,"ray_cs ray_attach calling ether_setup.)\n");
+    ether_setup(dev);
+    dev->name = local->node.dev_name;
+    dev->init = &ray_dev_init;
+    dev->open = &ray_open;
+    dev->stop = &ray_dev_close;
+
+    /* Register with Card Services */
+    link->next = dev_list;
+    dev_list = link;
+    client_reg.dev_info = &dev_info;
+    client_reg.Attributes = INFO_IO_CLIENT | INFO_CARD_SHARE;
+    client_reg.EventMask =
+        CS_EVENT_CARD_INSERTION | CS_EVENT_CARD_REMOVAL |
+        CS_EVENT_RESET_PHYSICAL | CS_EVENT_CARD_RESET |
+        CS_EVENT_PM_SUSPEND | CS_EVENT_PM_RESUME;
+    client_reg.event_handler = &ray_event;
+    client_reg.Version = 0x0210;
+    client_reg.event_callback_args.client_data = link;
+
+    DEBUG(2,"ray_cs ray_attach calling CardServices(RegisterClient...)\n");
+
+    init_timer(&local->timer);
+
+    ret = CardServices(RegisterClient, &link->handle, &client_reg);
+    if (ret != 0) {
+        printk("ray_cs ray_attach RegisterClient unhappy - detaching\n");
+        cs_error(link->handle, RegisterClient, ret);
+        ray_detach(link);
+        return NULL;
+    }
+    DEBUG(2,"ray_cs ray_attach ending\n");
+    return link;
+} /* ray_attach */
+/*=============================================================================
+    This deletes a driver "instance".  The device is de-registered
+    with Card Services.  If it has been released, all local data
+    structures are freed.  Otherwise, the structures will be freed
+    when the device is released.
+=============================================================================*/
+static void ray_detach(dev_link_t *link)
+{
+    dev_link_t **linkp;
+
+    DEBUG(1, "ray_detach(0x%p)\n", link);
+    
+    /* Locate device structure */
+    for (linkp = &dev_list; *linkp; linkp = &(*linkp)->next)
+        if (*linkp == link) break;
+    if (*linkp == NULL)
+        return;
+
+    /* If the device is currently configured and active, we won't
+      actually delete it yet.  Instead, it is marked so that when
+      the release() function is called, that will trigger a proper
+      detach().
+    */
+    del_timer(&link->release);
+    if (link->state & DEV_CONFIG) {
+        ray_release((u_long)link);
+        if(link->state & DEV_STALE_CONFIG) {
+            link->state |= DEV_STALE_LINK;
+            return;
+        }
+    }
+
+    /* Break the link with Card Services */
+    if (link->handle)
+        CardServices(DeregisterClient, link->handle);
+    
+    /* Unlink device structure, free pieces */
+    *linkp = link->next;
+    if (link->priv) {
+	struct net_device *dev = link->priv;
+	if (link->dev) unregister_netdev(dev);
+        if (dev->priv)
+            kfree(dev->priv);
+        kfree(dev);
+    }
+    kfree(link);
+    DEBUG(2,"ray_cs ray_detach ending\n");
+} /* ray_detach */
+/*=============================================================================
+    ray_config() is run after a CARD_INSERTION event
+    is received, to configure the PCMCIA socket, and to make the
+    ethernet device available to the system.
+=============================================================================*/
+#define CS_CHECK(fn, args...) \
+while ((last_ret=CardServices(last_fn=(fn),args))!=0) goto cs_failed
+#define MAX_TUPLE_SIZE 128
+static void ray_config(dev_link_t *link)
+{
+    client_handle_t handle = link->handle;
+    tuple_t tuple;
+    cisparse_t parse;
+    int last_fn, last_ret;
+    int i;
+    u_char buf[MAX_TUPLE_SIZE];
+    win_req_t req;
+    memreq_t mem;
+    struct net_device *dev = (struct net_device *)link->priv;
+    ray_dev_t *local = (ray_dev_t *)dev->priv;
+
+    DEBUG(1, "ray_config(0x%p)\n", link);
+
+    /* This reads the card's CONFIG tuple to find its configuration regs */
+    tuple.DesiredTuple = CISTPL_CONFIG;
+    CS_CHECK(GetFirstTuple, handle, &tuple);
+    tuple.TupleData = buf;
+    tuple.TupleDataMax = MAX_TUPLE_SIZE;
+    tuple.TupleOffset = 0;
+    CS_CHECK(GetTupleData, handle, &tuple);
+    CS_CHECK(ParseTuple, handle, &tuple, &parse);
+    link->conf.ConfigBase = parse.config.base;
+    link->conf.Present = parse.config.rmask[0];
+
+    /* Determine card type and firmware version */
+    buf[0] = buf[MAX_TUPLE_SIZE - 1] = 0;
+    tuple.DesiredTuple = CISTPL_VERS_1;
+    CS_CHECK(GetFirstTuple, handle, &tuple);
+    tuple.TupleData = buf;
+    tuple.TupleDataMax = MAX_TUPLE_SIZE;
+    tuple.TupleOffset = 2;
+    CS_CHECK(GetTupleData, handle, &tuple);
+
+    for (i=0; i<tuple.TupleDataLen - 4; i++) 
+        if (buf[i] == 0) buf[i] = ' ';
+    printk(KERN_INFO "ray_cs Detected: %s\n",buf);
+
+    /* Configure card */
+    link->state |= DEV_CONFIG;
+
+    /* Now allocate an interrupt line.  Note that this does not
+       actually assign a handler to the interrupt.
+    */
+    CS_CHECK(RequestIRQ, link->handle, &link->irq);
+    dev->irq = link->irq.AssignedIRQ;
+    
+    /* This actually configures the PCMCIA socket -- setting up
+       the I/O windows and the interrupt mapping.
+    */
+    CS_CHECK(RequestConfiguration, link->handle, &link->conf);
+
+/*** Set up 32k window for shared memory (transmit and control) ************/
+    req.Attributes = WIN_DATA_WIDTH_8 | WIN_MEMORY_TYPE_CM | WIN_ENABLE | WIN_USE_WAIT;
+    req.Base = 0;
+    req.Size = 0x8000;
+    req.AccessSpeed = ray_mem_speed;
+    link->win = (window_handle_t)link->handle;
+    CS_CHECK(RequestWindow, &link->win, &req);
+    mem.CardOffset = 0x0000; mem.Page = 0;
+    CS_CHECK(MapMemPage, link->win, &mem);
+    local->sram = (UCHAR *)(ioremap(req.Base,req.Size));
+
+/*** Set up 16k window for shared memory (receive buffer) ***************/
+    req.Attributes = WIN_DATA_WIDTH_8 | WIN_MEMORY_TYPE_CM | WIN_ENABLE | WIN_USE_WAIT;
+    req.Base = 0;
+    req.Size = 0x4000;
+    req.AccessSpeed = ray_mem_speed;
+    local->rmem_handle = (window_handle_t)link->handle;
+    CS_CHECK(RequestWindow, &local->rmem_handle, &req);
+    mem.CardOffset = 0x8000; mem.Page = 0;
+    CS_CHECK(MapMemPage, local->rmem_handle, &mem);
+    local->rmem = (UCHAR *)(ioremap(req.Base,req.Size));
+
+/*** Set up window for attribute memory ***********************************/
+    req.Attributes = WIN_DATA_WIDTH_8 | WIN_MEMORY_TYPE_AM | WIN_ENABLE | WIN_USE_WAIT;
+    req.Base = 0;
+    req.Size = 0x1000;
+    req.AccessSpeed = ray_mem_speed;
+    local->amem_handle = (window_handle_t)link->handle;
+    CS_CHECK(RequestWindow, &local->amem_handle, &req);
+    mem.CardOffset = 0x0000; mem.Page = 0;
+    CS_CHECK(MapMemPage, local->amem_handle, &mem);
+    local->amem = (UCHAR *)(ioremap(req.Base,req.Size));
+
+    DEBUG(3,"ray_config sram=%p\n",local->sram);
+    DEBUG(3,"ray_config rmem=%p\n",local->rmem);
+    DEBUG(3,"ray_config amem=%p\n",local->amem);
+    if (ray_init(dev) < 0)
+	goto config_failed;
+
+    i = register_netdev(dev);
+    if (i != 0) {
+        printk(KERN_INFO "ray_config register_netdev() failed\n");
+	goto config_failed;
+    }
+
+    link->dev = &local->node;
+
+    local->card_status = CARD_AWAITING_PARAM;
+    clear_interrupt(local); /* Clear any interrupt from the card */
+
+    link->state &= ~DEV_CONFIG_PENDING;
+    printk(KERN_INFO "%s: RayLink, irq %d, hw_addr ",
+       dev->name, dev->irq);
+    for (i = 0; i < 6; i++)
+    printk("%02X%s", dev->dev_addr[i], ((i<5) ? ":" : "\n"));
+
+    return;
+
+cs_failed:
+    cs_error(link->handle, last_fn, last_ret);
+config_failed:
+    ray_release((u_long)link);
+} /* ray_config */
+/*===========================================================================*/
+static int ray_init(struct net_device *dev)
+{
+    int i;
+    UCHAR *p;
+    struct ccs *pccs;
+    ray_dev_t *local = (ray_dev_t *)dev->priv;
+    dev_link_t *link = local->finder;
+    DEBUG(1, "ray_init(0x%p)\n", dev);
+    if (!(link->state & DEV_PRESENT)) {
+        printk(KERN_INFO "ray_init - device not present\n");
+        return -1;
+    }
+
+    local->net_type = net_type;
+    local->sta_type = TYPE_STA;
+
+    spin_lock(&local->ray_lock);
+
+    /* Copy the startup results to local memory */
+    memcpy_fromio(&local->startup_res, local->sram + ECF_TO_HOST_BASE,\
+           sizeof(struct startup_res_6));
+
+    /* Check Power up test status and get mac address from card */
+    if (local->startup_res.startup_word != 0x80) {
+    printk(KERN_INFO "ray_init ERROR card status = %2x\n",
+           local->startup_res.startup_word);
+        local->card_status = CARD_INIT_ERROR;
+        spin_unlock(&local->ray_lock);
+        return -1;
+    }
+
+    local->fw_ver = local->startup_res.firmware_version[0];
+    local->fw_bld = local->startup_res.firmware_version[1];
+    local->fw_var = local->startup_res.firmware_version[2];
+    DEBUG(1,"ray_init firmware version %d.%d \n",local->fw_ver, local->fw_bld);
+
+    local->tib_length = 0x20;
+    if ((local->fw_ver == 5) && (local->fw_bld >= 30))
+        local->tib_length = local->startup_res.tib_length;
+    DEBUG(2,"ray_init tib_length = 0x%02x\n", local->tib_length);
+    /* Initialize CCS's to buffer free state */
+    pccs = (struct ccs *)(local->sram + CCS_BASE);
+    for (i=0;  i<NUMBER_OF_CCS;  i++) {
+        writeb(CCS_BUFFER_FREE, &(pccs++)->buffer_status);
+    }
+    init_startup_params(local);
+
+    /* copy mac address to startup parameters */
+    if (parse_addr(phy_addr, local->sparm.b4.a_mac_addr))
+    {
+        p = local->sparm.b4.a_mac_addr;
+    }
+    else
+    {
+        memcpy(&local->sparm.b4.a_mac_addr,
+               &local->startup_res.station_addr, ADDRLEN);
+        p = local->sparm.b4.a_mac_addr;
+    }
+
+    local->card_status = CARD_AWAITING_PARAM;
+    spin_unlock(&local->ray_lock);
+    DEBUG(2,"ray_init ending\n");
+    return 0;
+} /* ray_init */
+/*===========================================================================*/
+/* Download startup parameters to the card and command it to read them       */
+static int dl_startup_params(struct net_device *dev)
+{
+    int ccsindex;
+    ray_dev_t *local = (ray_dev_t *)dev->priv;
+    struct ccs *pccs;
+    dev_link_t *link = local->finder;
+
+    DEBUG(1,"dl_startup_params entered\n");
+    if (!(link->state & DEV_PRESENT)) {
+        DEBUG(2,"ray_cs dl_startup_params - device not present\n");
+        return -1;
+    }
+    
+    /* Copy parameters to host to ECF area */
+    if (local->fw_ver == 0x55) 
+        memcpy_toio(local->sram + HOST_TO_ECF_BASE, &local->sparm.b4,
+               sizeof(struct b4_startup_params));
+    else
+        memcpy_toio(local->sram + HOST_TO_ECF_BASE, &local->sparm.b5,
+               sizeof(struct b5_startup_params));
+
+    
+    /* Fill in the CCS fields for the ECF */
+    if ((ccsindex = get_free_ccs(local)) < 0) return -1;
+    local->dl_param_ccs = ccsindex;
+    pccs = ((struct ccs *)(local->sram + CCS_BASE)) + ccsindex;
+    writeb(CCS_DOWNLOAD_STARTUP_PARAMS, &pccs->cmd);
+    DEBUG(2,"dl_startup_params start ccsindex = %d\n", local->dl_param_ccs);
+    /* Interrupt the firmware to process the command */
+    if (interrupt_ecf(local, ccsindex)) {
+        printk(KERN_INFO "ray dl_startup_params failed - "
+           "ECF not ready for intr\n");
+        local->card_status = CARD_DL_PARAM_ERROR;
+        writeb(CCS_BUFFER_FREE, &(pccs++)->buffer_status);
+        return -2;
+    }
+    local->card_status = CARD_DL_PARAM;
+    /* Start kernel timer to wait for dl startup to complete. */
+    del_timer(&local->timer);   /* If already exist, remove */
+    local->timer.expires = jiffies + HZ/2;
+    local->timer.data = (long)local;
+    local->timer.function = &verify_dl_startup;
+    add_timer(&local->timer);
+    /* Parameters changed, so we need to re-authenticate */
+    local->authentication_state = UNAUTHENTICATED;
+    DEBUG(2,"ray_cs dl_startup_params started timer for verify_dl_startup\n");
+    return 0;
+} /* dl_startup_params */
+/*===========================================================================*/
+static void init_startup_params(ray_dev_t *local)
+{
+    int i; 
+
+    if (country > JAPAN_TEST) country = USA;
+    else
+        if (country < USA) country = USA;
+    /* structure for hop time and beacon period is defined here using 
+     * New 802.11D6.1 format.  Card firmware is still using old format
+     * until version 6.
+     *    Before                    After
+     *    a_hop_time ms byte        a_hop_time ms byte
+     *    a_hop_time 2s byte        a_hop_time ls byte
+     *    a_hop_time ls byte        a_beacon_period ms byte
+     *    a_beacon_period           a_beacon_period ls byte
+     *
+     *    a_hop_time = uS           a_hop_time = KuS
+     *    a_beacon_period = hops    a_beacon_period = KuS
+     */                             /* 64ms = 010000 */
+    if (local->fw_ver == 0x55)  {
+        memcpy((UCHAR *)&local->sparm.b4, b4_default_startup_parms, 
+               sizeof(struct b4_startup_params));
+        /* Translate sane kus input values to old build 4/5 format */
+        /* i = hop time in uS truncated to 3 bytes */
+        i = (hop_dwell * 1024) & 0xffffff;
+        local->sparm.b4.a_hop_time[0] = (i >> 16) & 0xff;
+        local->sparm.b4.a_hop_time[1] = (i >> 8) & 0xff;
+        local->sparm.b4.a_beacon_period[0] = 0;
+        local->sparm.b4.a_beacon_period[1] =
+            ((beacon_period/hop_dwell) - 1) & 0xff;
+        local->sparm.b4.a_curr_country_code = country;
+        local->sparm.b4.a_hop_pattern_length = 
+            hop_pattern_length[(int)country] - 1;
+        if (bc)
+        {
+            local->sparm.b4.a_ack_timeout = 0x50;
+            local->sparm.b4.a_sifs = 0x3f;
+        }
+    }
+    else {    /* Version 5 uses real kus values */
+        memcpy((UCHAR *)&local->sparm.b5, b5_default_startup_parms, 
+               sizeof(struct b5_startup_params));
+
+        local->sparm.b5.a_hop_time[0] = (hop_dwell >> 8) & 0xff;
+        local->sparm.b5.a_hop_time[1] = hop_dwell & 0xff;
+        local->sparm.b5.a_beacon_period[0] = (beacon_period >> 8) & 0xff;
+        local->sparm.b5.a_beacon_period[1] = beacon_period & 0xff;
+        if (psm)
+            local->sparm.b5.a_power_mgt_state = 1;
+        local->sparm.b5.a_curr_country_code = country;
+        local->sparm.b5.a_hop_pattern_length = 
+            hop_pattern_length[(int)country];
+    }
+    
+    local->sparm.b4.a_network_type = net_type & 0x01;
+    local->sparm.b4.a_acting_as_ap_status = TYPE_STA;
+
+    if (essid != NULL)
+        strncpy(local->sparm.b4.a_current_ess_id, essid, ESSID_SIZE);
+} /* init_startup_params */ 
+/*===========================================================================*/
+static void verify_dl_startup(u_long data)
+{
+    ray_dev_t *local = (ray_dev_t *)data;
+    struct ccs *pccs = ((struct ccs *)(local->sram + CCS_BASE)) + local->dl_param_ccs;
+    UCHAR status;
+    dev_link_t *link = local->finder;
+
+    if (!(link->state & DEV_PRESENT)) {
+        DEBUG(2,"ray_cs verify_dl_startup - device not present\n");
+        return;
+    }
+
+    spin_lock(&local->ray_lock);
+
+#ifdef PCMCIA_DEBUG
+    if (pc_debug > 2) {
+    int i;
+    printk(KERN_DEBUG "verify_dl_startup parameters sent via ccs %d:\n",
+           local->dl_param_ccs);
+        for (i=0; i<sizeof(struct b5_startup_params); i++) {
+            printk(" %2x", (unsigned int) readb(local->sram + HOST_TO_ECF_BASE + i));
+        }
+    printk("\n");
+    }
+#endif
+
+    status = readb(&pccs->buffer_status);
+    if (status!= CCS_BUFFER_FREE)
+    {
+        printk(KERN_INFO "Download startup params failed.  Status = %d\n",
+           status);
+        local->card_status = CARD_DL_PARAM_ERROR;
+	spin_unlock(&local->ray_lock);
+        return;
+    }
+    if (local->sparm.b4.a_network_type == ADHOC)
+        start_net((u_long)local);
+    else
+        join_net((u_long)local);
+
+    spin_unlock(&local->ray_lock);
+    return;
+} /* end verify_dl_startup */
+/*===========================================================================*/
+/* Command card to start a network */
+static void start_net(u_long data)
+{
+    ray_dev_t *local = (ray_dev_t *)data;
+    struct ccs *pccs;
+    int ccsindex;
+    dev_link_t *link = local->finder;
+    if (!(link->state & DEV_PRESENT)) {
+        DEBUG(2,"ray_cs start_net - device not present\n");
+        return;
+    }
+    /* Fill in the CCS fields for the ECF */
+    if ((ccsindex = get_free_ccs(local)) < 0) return;
+    pccs = ((struct ccs *)(local->sram + CCS_BASE)) + ccsindex;
+    writeb(CCS_START_NETWORK, &pccs->cmd);
+    writeb(0, &pccs->var.start_network.update_param);
+    /* Interrupt the firmware to process the command */
+    if (interrupt_ecf(local, ccsindex)) {
+        DEBUG(1,"ray start net failed - card not ready for intr\n");
+        writeb(CCS_BUFFER_FREE, &(pccs++)->buffer_status);
+        return;
+    }
+    local->card_status = CARD_DOING_ACQ;
+    return;
+} /* end start_net */
+/*===========================================================================*/
+/* Command card to join a network */
+static void join_net(u_long data)
+{
+    ray_dev_t *local = (ray_dev_t *)data;
+
+    struct ccs *pccs;
+    int ccsindex;
+    dev_link_t *link = local->finder;
+    
+    if (!(link->state & DEV_PRESENT)) {
+        DEBUG(2,"ray_cs join_net - device not present\n");
+        return;
+    }
+    /* Fill in the CCS fields for the ECF */
+    if ((ccsindex = get_free_ccs(local)) < 0) return;
+    pccs = ((struct ccs *)(local->sram + CCS_BASE)) + ccsindex;
+    writeb(CCS_JOIN_NETWORK, &pccs->cmd);
+    writeb(0, &pccs->var.join_network.update_param);
+    writeb(0, &pccs->var.join_network.net_initiated);
+    /* Interrupt the firmware to process the command */
+    if (interrupt_ecf(local, ccsindex)) {
+        DEBUG(1,"ray join net failed - card not ready for intr\n");
+        writeb(CCS_BUFFER_FREE, &(pccs++)->buffer_status);
+        return;
+    }
+    local->card_status = CARD_DOING_ACQ;
+    return;
+}
+/*============================================================================
+    After a card is removed, ray_release() will unregister the net
+    device, and release the PCMCIA configuration.  If the device is
+    still open, this will be postponed until it is closed.
+=============================================================================*/
+static void ray_release(u_long arg)
+{
+    dev_link_t *link = (dev_link_t *)arg;
+    struct net_device *dev = link->priv; 
+    ray_dev_t *local = dev->priv;
+    int i;
+    
+    DEBUG(1, "ray_release(0x%p)\n", link);
+    /* If the device is currently in use, we won't release until it
+      is actually closed.
+    */
+    if (link->open) {
+        DEBUG(1, "ray_cs: release postponed, '%s' still open\n",
+              link->dev->dev_name);
+        link->state |= DEV_STALE_CONFIG;
+        return;
+    }
+    del_timer(&local->timer);
+    link->state &= ~DEV_CONFIG;
+
+    iounmap(local->sram);
+    iounmap(local->rmem);
+    iounmap(local->amem);
+    /* Do bother checking to see if these succeed or not */
+    i = CardServices(ReleaseWindow, link->win);
+    if ( i != CS_SUCCESS ) DEBUG(0,"ReleaseWindow(link->win) ret = %x\n",i);
+    i = CardServices(ReleaseWindow, local->amem_handle);
+    if ( i != CS_SUCCESS ) DEBUG(0,"ReleaseWindow(local->amem) ret = %x\n",i);
+    i = CardServices(ReleaseWindow, local->rmem_handle);
+    if ( i != CS_SUCCESS ) DEBUG(0,"ReleaseWindow(local->rmem) ret = %x\n",i);
+    i = CardServices(ReleaseConfiguration, link->handle);
+    if ( i != CS_SUCCESS ) DEBUG(0,"ReleaseConfiguration ret = %x\n",i);
+    i = CardServices(ReleaseIRQ, link->handle, &link->irq);
+    if ( i != CS_SUCCESS ) DEBUG(0,"ReleaseIRQ ret = %x\n",i);
+
+    DEBUG(2,"ray_release ending\n");
+} /* ray_release */
+/*=============================================================================
+    The card status event handler.  Mostly, this schedules other
+    stuff to run after an event is received.  A CARD_REMOVAL event
+    also sets some flags to discourage the net drivers from trying
+    to talk to the card any more.
+
+    When a CARD_REMOVAL event is received, we immediately set a flag
+    to block future accesses to this device.  All the functions that
+    actually access the device should check this flag to make sure
+    the card is still present.
+=============================================================================*/
+static int ray_event(event_t event, int priority,
+                     event_callback_args_t *args)
+{
+    dev_link_t *link = args->client_data;
+    struct net_device *dev = link->priv;
+    ray_dev_t *local = (ray_dev_t *)dev->priv;
+    DEBUG(1, "ray_event(0x%06x)\n", event);
+    
+    switch (event) {
+    case CS_EVENT_CARD_REMOVAL:
+        link->state &= ~DEV_PRESENT;
+        if (link->state & DEV_CONFIG) {
+	    netif_device_detach(dev);
+            mod_timer(&link->release, jiffies + HZ/20);
+	    del_timer(&local->timer);
+        }
+        break;
+    case CS_EVENT_CARD_INSERTION:
+        link->state |= DEV_PRESENT | DEV_CONFIG_PENDING;
+        ray_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 (link->open)
+		netif_device_detach(dev);
+            CardServices(ReleaseConfiguration, link->handle);
+        }
+        break;
+    case CS_EVENT_PM_RESUME:
+        link->state &= ~DEV_SUSPEND;
+        /* Fall through... */
+    case CS_EVENT_CARD_RESET:
+        if (link->state & DEV_CONFIG) {
+            CardServices(RequestConfiguration, link->handle, &link->conf);
+            if (link->open) {
+                ray_reset(dev);
+		netif_device_attach(dev);
+            }
+        }
+        break;
+    }
+    DEBUG(2,"ray_event ending\n");
+    return 0;
+} /* ray_event */
+/*===========================================================================*/
+int init_module(void)
+{
+    int rc;
+    servinfo_t serv;
+    
+    printk(KERN_INFO "%s\n", rcsid);
+    CardServices(GetCardServicesInfo, &serv);
+    if (serv.Revision != CS_RELEASE_CODE) {
+        printk(KERN_NOTICE "ray: Card Services release does not match!\n");
+        return -1;
+    }
+    rc = register_pcmcia_driver(&dev_info, &ray_attach, &ray_detach);
+    DEBUG(1, "raylink init_module register_pcmcia_driver returns 0x%x\n",rc);
+    register_symtab(&ray_cs_syms);
+#ifdef HAS_PROC_BUS
+    create_proc_read_entry("ray_cs", 0, &proc_root, ray_cs_proc_read, NULL);
+#endif
+    if (translate != 0) translate = 1;
+#ifdef PCMCIA_DEBUG
+    if (ray_debug != 0) pc_debug = ray_debug;
+#endif
+    return 0;
+} /* init_module */
+/*===========================================================================*/
+void cleanup_module(void)
+{
+    DEBUG(0, "ray_cs: cleanup_module\n");
+
+    unregister_pcmcia_driver(&dev_info);
+    while (dev_list != NULL)
+        ray_detach(dev_list);
+#ifdef HAS_PROC_BUS
+    remove_proc_entry("ray_cs", &proc_root);
+#endif
+} /* cleanup_module */
+/*===========================================================================*/
+static int ray_dev_init(struct net_device *dev)
+{
+    int i;
+    ray_dev_t *local = dev->priv;
+    dev_link_t *link = local->finder;
+
+    DEBUG(1,"ray_dev_init(dev=%p)\n",dev);
+    if (!(link->state & DEV_PRESENT)) {
+        DEBUG(2,"ray_dev_init - device not present\n");
+        return -1;
+    }
+
+    spin_lock(&local->ray_lock);
+
+    /* Download startup parameters */
+    if ( (i = dl_startup_params(dev)) < 0)
+    {
+        printk(KERN_INFO "ray_dev_init dl_startup_params failed - "
+           "returns 0x%x\n",i);
+        spin_unlock(&local->ray_lock);
+        return -1;
+    }
+    
+    /* copy mac and broadcast addresses to linux device */
+    memcpy(&dev->dev_addr, &local->sparm.b4.a_mac_addr, ADDRLEN);
+    memset(dev->broadcast, 0xff, ETH_ALEN);
+
+    DEBUG(2,"ray_dev_init ending\n");
+    spin_unlock(&local->ray_lock);
+    return 0;
+}
+/*===========================================================================*/
+static int ray_dev_config(struct net_device *dev, struct ifmap *map)
+{
+    ray_dev_t *local = dev->priv;
+    dev_link_t *link = local->finder;
+    /* Dummy routine to satisfy device structure */
+    DEBUG(1,"ray_dev_config(dev=%p,ifmap=%p)\n",dev,map);
+    if (!DEV_OK(link)) {
+        DEBUG(2,"ray_dev_config - device not present\n");
+        return -1;
+    }
+
+    return 0;
+}
+/*===========================================================================*/
+static int ray_dev_start_xmit(struct sk_buff *skb, struct net_device *dev)
+{
+    ray_dev_t *local = dev->priv;
+    dev_link_t *link = local->finder;
+    short length;
+
+    if (!DEV_OK(link)) {
+        DEBUG(2,"ray_dev_start_xmit - device not present\n");
+        return -1;
+    }
+    DEBUG(3,"ray_dev_start_xmit(skb=%p, dev=%p)\n",skb,dev);
+#ifndef HAVE_NETIF_QUEUE
+    if (netif_queue_stopped(dev))
+    {
+        printk(KERN_NOTICE "ray_dev_start_xmit busy\n");
+        return 1;
+    }
+#endif
+    skb_tx_check(dev, skb);
+
+#ifdef __SMP__
+    disable_irq(dev->irq);
+#endif
+
+    spin_lock(&local->ray_lock);
+
+    if (local->authentication_state == NEED_TO_AUTH) {
+        DEBUG(0,"ray_cs Sending authentication request.\n");
+        if (!build_auth_frame (local, local->auth_id, OPEN_AUTH_REQUEST)) {
+            local->authentication_state = AUTHENTICATED;
+	    netif_stop_queue(dev);
+            spin_unlock(&local->ray_lock);
+#ifdef __SMP__
+            enable_irq(dev->irq);
+#endif
+            return 1;
+        }
+    }
+
+    length = ETH_ZLEN < skb->len ? skb->len : ETH_ZLEN;
+    switch (ray_hw_xmit( skb->data, length, dev, DATA_TYPE)) {
+        case XMIT_NO_CCS:
+        case XMIT_NEED_AUTH:
+	    netif_stop_queue(dev);
+            spin_unlock(&local->ray_lock);
+#ifdef __SMP__
+            enable_irq(dev->irq);
+#endif
+            return 1;
+        case XMIT_NO_INTR:
+        case XMIT_MSG_BAD:
+        case XMIT_OK:
+        default:
+            dev->trans_start = jiffies;
+            spin_unlock(&local->ray_lock);
+#ifdef __SMP__
+            enable_irq(dev->irq);
+#endif
+            DEV_KFREE_SKB(skb);
+            return 0;
+    }
+    /* Never get here.  All returns from above switch */
+    return 0;
+} /* ray_dev_start_xmit */
+/*===========================================================================*/
+static int ray_hw_xmit(unsigned char* data, int len, struct net_device* dev, 
+                UCHAR msg_type)
+{
+    ray_dev_t *local = (ray_dev_t *)dev->priv;
+    struct ccs *pccs;
+    int ccsindex;
+    int offset;
+    struct tx_msg *ptx; /* Address of xmit buffer in PC space */
+    short int addr;     /* Address of xmit buffer in card space */
+    
+    DEBUG(3,"ray_hw_xmit(data=%p, len=%d, dev=%p)\n",data,len,dev);
+    if (len + TX_HEADER_LENGTH > TX_BUF_SIZE)
+    {
+        printk(KERN_INFO "ray_hw_xmit packet too large: %d bytes\n",len);
+        return XMIT_MSG_BAD;
+    }
+    switch (ccsindex = get_free_tx_ccs(local)) {
+    case ECCSBUSY:
+	DEBUG(2,"ray_hw_xmit tx_ccs table busy\n");
+    case ECCSFULL:
+        DEBUG(2,"ray_hw_xmit No free tx ccs\n");
+    case ECARDGONE:
+	netif_stop_queue(dev);
+        return XMIT_NO_CCS;
+    default:
+	break;
+    }
+    addr = TX_BUF_BASE + (ccsindex << 11);
+
+    if (msg_type == DATA_TYPE) {
+	add_tx_bytes(&local->stats, len);
+        local->stats.tx_packets++;
+    }
+
+    ptx = (struct tx_msg *)(local->sram + addr);
+
+    ray_build_header(local, ptx, msg_type, data);
+    if (translate) {
+        offset = translate_frame(local, ptx, data, len);
+    }
+    else { /* Encapsulate frame */
+        /* TBD TIB length will move address of ptx->var */
+        memcpy_toio(&ptx->var, data, len);
+        offset = 0;
+    }
+
+    /* fill in the CCS */
+    pccs = ((struct ccs *)(local->sram + CCS_BASE)) + ccsindex;
+    len += TX_HEADER_LENGTH + offset;
+    writeb(CCS_TX_REQUEST, &pccs->cmd);
+    writeb(addr >> 8, &pccs->var.tx_request.tx_data_ptr[0]);
+    writeb(local->tib_length, &pccs->var.tx_request.tx_data_ptr[1]);
+    writeb(len >> 8, &pccs->var.tx_request.tx_data_length[0]);
+    writeb(len & 0xff, &pccs->var.tx_request.tx_data_length[1]);
+/* TBD still need psm_cam? */
+    writeb(PSM_CAM, &pccs->var.tx_request.pow_sav_mode);
+    writeb(local->net_default_tx_rate, &pccs->var.tx_request.tx_rate);
+    writeb(0, &pccs->var.tx_request.antenna);
+    DEBUG(3,"ray_hw_xmit default_tx_rate = 0x%x\n",\
+          local->net_default_tx_rate);
+
+    /* Interrupt the firmware to process the command */
+    if (interrupt_ecf(local, ccsindex)) {
+        DEBUG(2,"ray_hw_xmit failed - ECF not ready for intr\n");
+/* TBD very inefficient to copy packet to buffer, and then not
+   send it, but the alternative is to queue the messages and that
+   won't be done for a while.  Maybe stop the tx queue until a CCS is
+   free?
+*/
+        writeb(CCS_BUFFER_FREE, &pccs->buffer_status);
+        return XMIT_NO_INTR;
+    }
+    return XMIT_OK;
+} /* end ray_hw_xmit */
+/*===========================================================================*/
+static int translate_frame(ray_dev_t *local, struct tx_msg *ptx, unsigned char *data,
+                    int len)
+{
+    unsigned short int proto = ((struct ethhdr *)data)->h_proto;
+
+    if (ntohs(proto) >= 1536) { /* DIX II ethernet frame */
+        DEBUG(3,"ray_cs translate_frame DIX II\n");
+        /* Copy LLC header to card buffer */
+        memcpy_toio((UCHAR *)&ptx->var, eth2_llc, sizeof(eth2_llc));
+        memcpy_toio( ((UCHAR *)&ptx->var) + sizeof(eth2_llc), (UCHAR *)&proto, 2);
+        if ((proto == 0xf380) || (proto == 0x3781)) {
+            /* This is the selective translation table, only 2 entries */
+            writeb(0xf8, (UCHAR *) &((struct snaphdr_t *)ptx->var)->org[3]);
+        }
+        /* Copy body of ethernet packet without ethernet header */
+        memcpy_toio((UCHAR *)&ptx->var + sizeof(struct snaphdr_t), \
+                    data + ETH_HLEN,  len - ETH_HLEN);
+        return (int) sizeof(struct snaphdr_t) - ETH_HLEN;
+    }
+    else { /* already  802 type, and proto is length */
+        DEBUG(3,"ray_cs translate_frame 802\n");
+        if (proto == 0xffff) { /* evil netware IPX 802.3 without LLC */
+        DEBUG(3,"ray_cs translate_frame evil IPX\n");
+            memcpy_toio((UCHAR *)&ptx->var, data + ETH_HLEN,  len - ETH_HLEN);
+            return 0 - ETH_HLEN;
+        }
+        memcpy_toio((UCHAR *)&ptx->var, data + ETH_HLEN,  len - ETH_HLEN);
+        return 0 - ETH_HLEN;
+    }
+    /* TBD do other frame types */
+} /* end translate_frame */
+/*===========================================================================*/
+static void ray_build_header(ray_dev_t *local, struct tx_msg *ptx, UCHAR msg_type,
+                unsigned char *data)
+{
+    writeb(PROTOCOL_VER | msg_type, &ptx->mac.frame_ctl_1);
+/*** IEEE 802.11 Address field assignments *************
+                TODS FROMDS   addr_1     addr_2          addr_3   addr_4
+Adhoc           0    0        dest       src (terminal)  BSSID    N/A
+AP to Terminal  0    1        dest       AP(BSSID)       source   N/A
+Terminal to AP  1    0        AP(BSSID)  src (terminal)  dest     N/A
+AP to AP        1    1        dest AP    src AP          dest     source      
+*******************************************************/
+    if (local->net_type == ADHOC) {   
+        writeb(0, &ptx->mac.frame_ctl_2);
+        memcpy_toio(ptx->mac.addr_1, ((struct ethhdr *)data)->h_dest, 2 * ADDRLEN);
+        memcpy_toio(ptx->mac.addr_3, local->bss_id, ADDRLEN);
+    }
+    else /* infrastructure */
+    {
+        if (local->sparm.b4.a_acting_as_ap_status)
+        {
+            writeb(FC2_FROM_DS, &ptx->mac.frame_ctl_2);;
+            memcpy_toio(ptx->mac.addr_1, ((struct ethhdr *)data)->h_dest, ADDRLEN);
+            memcpy_toio(ptx->mac.addr_2, local->bss_id, 6);
+            memcpy_toio(ptx->mac.addr_3, ((struct ethhdr *)data)->h_source, ADDRLEN);
+        }
+        else /* Terminal */
+        {
+            writeb(FC2_TO_DS, &ptx->mac.frame_ctl_2);
+            memcpy_toio(ptx->mac.addr_1, local->bss_id, ADDRLEN);
+            memcpy_toio(ptx->mac.addr_2, ((struct ethhdr *)data)->h_source, ADDRLEN);
+            memcpy_toio(ptx->mac.addr_3, ((struct ethhdr *)data)->h_dest, ADDRLEN);
+        }
+    }
+} /* end encapsulate_frame */
+/*===========================================================================*/
+static int ray_dev_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
+{
+    ray_dev_t *local = (ray_dev_t *)dev->priv;
+    dev_link_t *link = local->finder;
+    int err = 0;
+#if WIRELESS_EXT > 8
+    struct iwreq *wrq = (struct iwreq *) ifr;
+#endif	/* WIRELESS_EXT > 8 */
+
+    if (!DEV_OK(link)) {
+        DEBUG(2,"ray_dev_ioctl - device not present\n");
+        return -1;
+    }
+    DEBUG(2,"ray_cs IOCTL dev=%p, ifr=%p, cmd = 0x%x\n",dev,ifr,cmd);
+
+#ifdef __SMP__
+    disable_irq(dev->irq);
+#endif
+
+    spin_lock(&local->ray_lock);
+
+    /* Validate the command */
+    switch (cmd)
+    {
+#if WIRELESS_EXT > 8
+      /* --------------- WIRELESS EXTENSIONS --------------- */
+      /* The Wireless Extension support was written by Jean Tourrilhes,
+       * so blame me for the bugs, not Corey... */
+      /* Get name */
+    case SIOCGIWNAME:
+      strcpy(wrq->u.name, "IEEE 802.11-FH");
+      break;
+
+      /* Get frequency/channel */
+    case SIOCGIWFREQ:
+      wrq->u.freq.m = local->sparm.b5.a_hop_pattern;
+      wrq->u.freq.e = 0;
+      break;
+
+      /* Set frequency/channel */
+    case SIOCSIWFREQ:
+      /* Setting by channel number */
+      if ((wrq->u.freq.m > USA_HOP_MOD) || (wrq->u.freq.e > 0))
+	err = -EOPNOTSUPP;
+      else
+	{
+	   local->sparm.b5.a_hop_pattern = wrq->u.freq.m;
+	   dl_startup_params(dev);
+	}
+      break;
+
+      /* Get current network name (ESSID) */
+    case SIOCGIWESSID:
+      if (wrq->u.data.pointer)
+	{
+	  char card_essid[IW_ESSID_MAX_SIZE + 1];
+	  /* Get the essid that was set */
+          memcpy(card_essid, local->sparm.b5.a_current_ess_id,
+		 IW_ESSID_MAX_SIZE);
+	  essid[IW_ESSID_MAX_SIZE] = '\0';
+
+	  /* Push it out ! */
+          wrq->u.data.length = strlen(card_essid) + 1;
+	  wrq->u.data.flags = 1; /* active */
+	  copy_to_user(wrq->u.data.pointer, card_essid, sizeof(card_essid));
+	}
+      break;
+
+      /* Set desired network name (ESSID) */
+    case SIOCSIWESSID:
+	if (wrq->u.data.pointer)
+	{
+	    char	card_essid[IW_ESSID_MAX_SIZE + 1];
+	    
+	    /* Check if we asked for `any' */
+	    if(wrq->u.data.flags == 0)
+	    {
+		/* Corey : can you do that ? */
+		err = -EOPNOTSUPP;
+	    }
+	    else
+	    {
+		/* Check the size of the string */
+		if(wrq->u.data.length >
+		   IW_ESSID_MAX_SIZE + 1)
+		{
+		    err = -E2BIG;
+		    break;
+		}
+		copy_from_user(card_essid,
+			       wrq->u.data.pointer,
+			       wrq->u.data.length);
+		card_essid[IW_ESSID_MAX_SIZE] = '\0';
+
+		/* Set the ESSID in the card */
+		memcpy(local->sparm.b5.a_current_ess_id, card_essid,
+		       IW_ESSID_MAX_SIZE);
+		dl_startup_params(dev);
+	    }
+	}
+	break;
+
+	/* Get current Access Point (BSSID in our case) */
+    case SIOCGIWAP:
+	memcpy(wrq->u.ap_addr.sa_data, local->bss_id, ETH_ALEN);
+	wrq->u.ap_addr.sa_family = ARPHRD_ETHER;
+	break;
+
+	/* Get the current bit-rate */
+    case SIOCGIWRATE:
+	if(local->net_default_tx_rate == 3)
+	    wrq->u.bitrate.value = 2000000;	/* Hum... */
+	else
+	    wrq->u.bitrate.value = local->net_default_tx_rate * 500000;
+	wrq->u.bitrate.fixed = 0;		/* We are in auto mode */
+	break;
+
+	/* Set the desired bit-rate */
+    case SIOCSIWRATE:
+    {
+	int card_rate = wrq->u.bitrate.value;
+	/* Auto ? */
+	if(wrq->u.bitrate.fixed == 0)
+	    card_rate = 2000000;
+	/* Check if rate is in range */
+	if((card_rate != 1000000) &&
+	   (card_rate != 2000000))
+	{
+	    err = -EINVAL;
+	    break;
+	}
+	/* Hack for 1.5 Mb/s instead of 2 Mb/s */
+	if((local->fw_ver == 0x55) &&		/* Please check */
+	   (card_rate == 2000000))
+	    local->net_default_tx_rate = 3;
+	else
+	    local->net_default_tx_rate = card_rate/500000;
+    }
+      break;
+
+      /* Get the current RTS threshold */
+    case SIOCGIWRTS:
+      wrq->u.rts.value = (local->sparm.b5.a_rts_threshold[0] << 8)
+	+ local->sparm.b5.a_rts_threshold[1];
+      wrq->u.rts.disabled = (wrq->u.rts.value == 32767);
+      wrq->u.rts.fixed = 1;
+      break;
+
+      /* Set the desired RTS threshold */
+    case SIOCSIWRTS:
+    {
+	int rthr = wrq->u.rts.value;
+	/* if(wrq->u.rts.fixed == 0) we should complain */
+	if(wrq->u.rts.disabled)
+	    rthr = 32767;
+	else
+	    if((rthr < 0) || (rthr > 2347)) /* What's the max packet size ??? */
+	    {
+		err = -EINVAL;
+		break;
+	    }
+	local->sparm.b5.a_rts_threshold[0] = (rthr >> 8) & 0xFF;
+	local->sparm.b5.a_rts_threshold[1] = rthr & 0xFF;
+	dl_startup_params(dev);
+    }
+    break;
+
+      /* Get the current fragmentation threshold */
+    case SIOCGIWFRAG:
+      wrq->u.frag.value = (local->sparm.b5.a_frag_threshold[0] << 8)
+	+ local->sparm.b5.a_frag_threshold[1];
+      wrq->u.frag.disabled = (wrq->u.frag.value == 32767);
+      wrq->u.frag.fixed = 1;
+      break;
+
+
+      /* Set the desired fragmentation threshold */
+    case SIOCSIWFRAG:
+    {
+	int fthr = wrq->u.frag.value;
+	/* if(wrq->u.frag.fixed == 0) should complain */
+	if(wrq->u.frag.disabled)
+	    fthr = 32767;
+	else
+	    if((fthr < 256) || (fthr > 2347)) /* To check out ! */
+	    {
+		err = -EINVAL;
+		break;
+	    }
+	local->sparm.b5.a_frag_threshold[0] = (fthr >> 8) & 0xFF;
+	local->sparm.b5.a_frag_threshold[1] = fthr & 0xFF;
+	dl_startup_params(dev);
+    }
+    break;
+
+      /* Get the current mode of operation */
+    case SIOCGIWMODE:
+      if(local->sparm.b5.a_network_type)
+	wrq->u.mode = IW_MODE_INFRA;
+      else
+	wrq->u.mode = IW_MODE_ADHOC;
+      break;
+
+      /* Set the current mode of operation */
+    case SIOCSIWMODE:
+    {
+	char card_mode = 1;
+	
+	switch (wrq->u.mode)
+	{
+	case IW_MODE_ADHOC:
+	    card_mode = 0;
+	    // Fall through
+	case IW_MODE_INFRA:
+	    local->sparm.b5.a_network_type = card_mode;
+	    dl_startup_params(dev);
+	    break;
+	default:
+	    err = -EINVAL;
+	}
+    }
+    break;
+
+      /* Define the range (variations) of above parameters */
+    case SIOCGIWRANGE:
+      /* Basic checking... */
+      if(wrq->u.data.pointer != (caddr_t) 0)
+	{
+	  struct iw_range	range;
+	  memset((char *) &range, 0, sizeof(struct iw_range));
+
+	  /* Set the length (useless : its constant...) */
+	  wrq->u.data.length = sizeof(struct iw_range);
+
+	  /* Set information in the range struct */
+	  range.throughput = 1.1 * 1000 * 1000;	/* Put the right number here */
+	  range.num_channels = hop_pattern_length[(int)country]; 
+	  range.num_frequency = 0;
+	  range.max_qual.qual = 0;
+	  range.max_qual.level = 255;	/* What's the correct value ? */
+	  range.max_qual.noise = 255;	/* Idem */
+	  range.num_bitrates = 2;
+	  range.bitrate[0] = 1000000;	/* 1 Mb/s */
+	  range.bitrate[1] = 2000000;	/* 2 Mb/s */
+
+	  /* Copy structure to the user buffer */
+	  if(copy_to_user(wrq->u.data.pointer, &range,
+			  sizeof(struct iw_range)))
+	    err = -EFAULT;
+	}
+      break;
+
+#ifdef WIRELESS_SPY
+      /* ------------------ IWSPY SUPPORT ------------------ */
+      /* Set addresses to spy */
+    case SIOCSIWSPY:
+      /* Check the number of addresses */
+      if(wrq->u.data.length > IW_MAX_SPY)
+	{
+	  err = -E2BIG;
+	  break;
+	}
+      local->spy_number = wrq->u.data.length;
+
+      /* If there is some addresses to copy */
+      if(local->spy_number > 0)
+	{
+	  struct sockaddr	address[IW_MAX_SPY];
+	  int			i;
+
+	  /* Copy addresses to the driver */
+	  if(copy_from_user(address, wrq->u.data.pointer,
+			    sizeof(struct sockaddr) * local->spy_number))
+	    {
+	      err = -EFAULT;
+	      break;
+	    }
+
+	  /* Copy addresses to the lp structure */
+	  for(i = 0; i < local->spy_number; i++)
+	    memcpy(local->spy_address[i], address[i].sa_data, ETH_ALEN);
+
+	  /* Reset structure... */
+	  memset(local->spy_stat, 0x00, sizeof(iw_qual) * IW_MAX_SPY);
+
+#ifdef DEBUG_IOCTL_INFO
+	  printk(KERN_DEBUG "SetSpy - Set of new addresses is :\n");
+	  for(i = 0; i < local->spy_number; i++)
+	    printk(KERN_DEBUG "%02X:%02X:%02X:%02X:%02X:%02X\n",
+		   local->spy_address[i][0],
+		   local->spy_address[i][1],
+		   local->spy_address[i][2],
+		   local->spy_address[i][3],
+		   local->spy_address[i][4],
+		   local->spy_address[i][5]);
+#endif	/* DEBUG_IOCTL_INFO */
+	}
+      break;
+
+      /* Get the spy list and spy stats */
+    case SIOCGIWSPY:
+      /* Set the number of addresses */
+      wrq->u.data.length = local->spy_number;
+
+      /* If the user want to have the addresses back... */
+      if((local->spy_number > 0) && (wrq->u.data.pointer != (caddr_t) 0))
+	{
+	  struct sockaddr	address[IW_MAX_SPY];
+	  int			i;
+
+	  /* Copy addresses from the lp structure */
+	  for(i = 0; i < local->spy_number; i++)
+	    {
+	      memcpy(address[i].sa_data, local->spy_address[i], ETH_ALEN);
+	      address[i].sa_family = ARPHRD_ETHER;
+	    }
+
+	  /* Copy addresses to the user buffer */
+	  if(copy_to_user(wrq->u.data.pointer, address,
+		       sizeof(struct sockaddr) * local->spy_number))
+	    {
+	      err = -EFAULT;
+	      break;
+	    }
+
+	  /* Copy stats to the user buffer (just after) */
+	  if(copy_to_user(wrq->u.data.pointer +
+		       (sizeof(struct sockaddr) * local->spy_number),
+		       local->spy_stat, sizeof(iw_qual) * local->spy_number))
+	    {
+	      err = -EFAULT;
+	      break;
+	    }
+
+	  /* Reset updated flags */
+	  for(i = 0; i < local->spy_number; i++)
+	    local->spy_stat[i].updated = 0x0;
+	}	/* if(pointer != NULL) */
+
+      break;
+#endif	/* WIRELESS_SPY */
+
+      /* ------------------ PRIVATE IOCTL ------------------ */
+#define SIOCSIPFRAMING	SIOCDEVPRIVATE		/* Set framing mode */
+#define SIOCGIPFRAMING	SIOCDEVPRIVATE + 1	/* Get framing mode */
+#define SIOCGIPCOUNTRY	SIOCDEVPRIVATE + 3	/* Get country code */
+    case SIOCSIPFRAMING:
+      if(!suser())	/* For private IOCTLs, we need to check permissions */
+	{
+	  err = -EPERM;
+	  break;
+	}
+      translate = *(wrq->u.name);	/* Set framing mode */
+      break;
+    case SIOCGIPFRAMING:
+      *(wrq->u.name) = translate;
+      break;
+    case SIOCGIPCOUNTRY:
+      *(wrq->u.name) = country;
+      break;
+    case SIOCGIWPRIV:
+      /* Export our "private" interface */
+      if(wrq->u.data.pointer != (caddr_t) 0)
+	{
+	  struct iw_priv_args	priv[] =
+	  {	/* cmd,		set_args,	get_args,	name */
+	    { SIOCSIPFRAMING, IW_PRIV_TYPE_BYTE | IW_PRIV_SIZE_FIXED | 1, 0, "set_framing" },
+	    { SIOCGIPFRAMING, 0, IW_PRIV_TYPE_BYTE | IW_PRIV_SIZE_FIXED | 1, "get_framing" },
+	    { SIOCGIPCOUNTRY, 0, IW_PRIV_TYPE_BYTE | IW_PRIV_SIZE_FIXED | 1, "get_country" },
+	  };
+	  /* Set the number of ioctl available */
+	  wrq->u.data.length = 3;
+	  /* Copy structure to the user buffer */
+	  if(copy_to_user(wrq->u.data.pointer, (u_char *) priv,
+		       sizeof(priv)))
+	    err = -EFAULT;
+	}
+      break;
+#endif	/* WIRELESS_EXT > 8 */
+
+        default:
+            DEBUG(0,"ray_dev_ioctl cmd = 0x%x\n", cmd);
+            err = -EOPNOTSUPP;
+    }
+#ifdef __SMP__
+    enable_irq(dev->irq);
+#endif
+    spin_unlock(&local->ray_lock);
+    return err;
+} /* end ray_dev_ioctl */
+/*===========================================================================*/
+#if WIRELESS_EXT > 7	/* If wireless extension exist in the kernel */
+static iw_stats * ray_get_wireless_stats(struct net_device *	dev)
+{
+  ray_dev_t *	local = (ray_dev_t *) dev->priv;
+  dev_link_t *link = local->finder;
+  struct status *p = (struct status *)(local->sram + STATUS_BASE);
+
+  if(local == (ray_dev_t *) NULL)
+    return (iw_stats *) NULL;
+
+#ifdef __SMP__
+    disable_irq(dev->irq);
+#endif
+
+  spin_lock(&local->ray_lock);
+
+  local->wstats.status = local->card_status;
+#ifdef WIRELESS_SPY
+  if((local->spy_number > 0) && (local->sparm.b5.a_network_type == 0))
+    {
+      /* Get it from the first node in spy list */
+      local->wstats.qual.qual = local->spy_stat[0].qual;
+      local->wstats.qual.level = local->spy_stat[0].level;
+      local->wstats.qual.noise = local->spy_stat[0].noise;
+      local->wstats.qual.updated = local->spy_stat[0].updated;
+    }
+#endif /* WIRELESS_SPY */
+
+  if((link->state & DEV_PRESENT)) {
+    local->wstats.qual.noise = readb(&p->rxnoise);
+    local->wstats.qual.updated |= 4;
+  }
+
+#ifdef __SMP__
+    enable_irq(dev->irq);
+#endif
+
+  spin_unlock(&local->ray_lock);
+  return &local->wstats;
+} /* end ray_get_wireless_stats */
+#endif	/* WIRELESS_EXT > 7 */
+/*===========================================================================*/
+static int ray_open(struct net_device *dev)
+{
+    ray_dev_t *local = dev->priv;
+    dev_link_t *link = local->finder;
+    
+    DEBUG(1, "ray_open('%s')\n", dev->name);
+
+    if (!DEV_OK(link))
+        return -ENODEV;
+
+    if (link->open == 0) local->num_multi = 0;
+    link->open++;
+    MOD_INC_USE_COUNT;
+
+    if (sniffer) netif_stop_queue(dev);
+    else         netif_start_queue(dev);
+    netif_mark_up(dev);
+
+    DEBUG(2,"ray_open ending\n");
+    return 0;
+} /* end ray_open */
+/*===========================================================================*/
+static int ray_dev_close(struct net_device *dev)
+{
+    ray_dev_t *local = dev->priv;
+    dev_link_t *link = local->finder;
+
+    DEBUG(1, "ray_dev_close('%s')\n", dev->name);
+
+    link->open--;
+    netif_stop_queue(dev);
+    netif_mark_down(dev);
+    if (link->state & DEV_STALE_CONFIG)
+        mod_timer(&link->release, jiffies + HZ/20);
+
+    MOD_DEC_USE_COUNT;
+
+    return 0;
+} /* end ray_dev_close */
+/*===========================================================================*/
+static void ray_reset(struct net_device *dev) {
+    DEBUG(1,"ray_reset entered\n");
+    return;
+}
+/*===========================================================================*/
+/* Cause a firmware interrupt if it is ready for one                         */
+/* Return nonzero if not ready                                               */
+static int interrupt_ecf(ray_dev_t *local, int ccs)
+{
+    int i = 50;
+    dev_link_t *link = local->finder;
+
+    if (!(link->state & DEV_PRESENT)) {
+        DEBUG(2,"ray_cs interrupt_ecf - device not present\n");
+        return -1;
+    }
+    DEBUG(2,"interrupt_ecf(local=%p, ccs = 0x%x)\n",local,ccs);
+
+    while ( i && 
+            (readb(local->amem + CIS_OFFSET + ECF_INTR_OFFSET) & ECF_INTR_SET))
+        i--;
+    if (i == 0) {
+        DEBUG(2,"ray_cs interrupt_ecf card not ready for interrupt\n");
+        return -1;
+    }
+    /* Fill the mailbox, then kick the card */
+    writeb(ccs, local->sram + SCB_BASE);
+    writeb(ECF_INTR_SET, local->amem + CIS_OFFSET + ECF_INTR_OFFSET);
+    return 0;
+} /* interrupt_ecf */
+/*===========================================================================*/
+/* Get next free transmit CCS                                                */
+/* Return - index of current tx ccs                                          */
+static int get_free_tx_ccs(ray_dev_t *local)
+{
+    int i;
+    struct ccs *pccs = (struct ccs *)(local->sram + CCS_BASE);
+    dev_link_t *link = local->finder;
+
+    if (!(link->state & DEV_PRESENT)) {
+        DEBUG(2,"ray_cs get_free_tx_ccs - device not present\n");
+        return ECARDGONE;
+    }
+
+    if (test_and_set_bit(0,&local->tx_ccs_lock)) {
+        DEBUG(1,"ray_cs tx_ccs_lock busy\n");
+        return ECCSBUSY;
+    } 
+
+    for (i=0; i < NUMBER_OF_TX_CCS; i++) {
+        if (readb(&(pccs+i)->buffer_status) == CCS_BUFFER_FREE) {
+            writeb(CCS_BUFFER_BUSY, &(pccs+i)->buffer_status);
+            writeb(CCS_END_LIST, &(pccs+i)->link);
+			local->tx_ccs_lock = 0;
+            return i;
+        }
+    }
+	local->tx_ccs_lock = 0;
+    DEBUG(2,"ray_cs ERROR no free tx CCS for raylink card\n");
+    return ECCSFULL;
+} /* get_free_tx_ccs */
+/*===========================================================================*/
+/* Get next free CCS                                                         */
+/* Return - index of current ccs                                             */
+static int get_free_ccs(ray_dev_t *local)
+{
+    int i;
+    struct ccs *pccs = (struct ccs *)(local->sram + CCS_BASE);
+    dev_link_t *link = local->finder;
+
+    if (!(link->state & DEV_PRESENT)) {
+        DEBUG(2,"ray_cs get_free_ccs - device not present\n");
+        return ECARDGONE;
+    }
+    if (test_and_set_bit(0,&local->ccs_lock)) {
+        DEBUG(1,"ray_cs ccs_lock busy\n");
+        return ECCSBUSY;
+    } 
+
+    for (i = NUMBER_OF_TX_CCS; i < NUMBER_OF_CCS; i++) {
+        if (readb(&(pccs+i)->buffer_status) == CCS_BUFFER_FREE) {
+            writeb(CCS_BUFFER_BUSY, &(pccs+i)->buffer_status);
+            writeb(CCS_END_LIST, &(pccs+i)->link);
+			local->ccs_lock = 0;
+            return i;
+        }
+    }
+	local->ccs_lock = 0;
+    DEBUG(1,"ray_cs ERROR no free CCS for raylink card\n");
+    return ECCSFULL;
+} /* get_free_ccs */
+/*===========================================================================*/
+static void authenticate_timeout(u_long data)
+{
+    ray_dev_t *local = (ray_dev_t *)data;
+#ifdef __SMP__
+    dev_link_t *link = local->finder;
+    struct net_device *dev = (struct net_device *) link->priv;
+    disable_irq(dev->irq);
+#endif
+
+    spin_lock(&local->ray_lock);
+    del_timer(&local->timer);
+    printk(KERN_INFO "ray_cs Authentication with access point failed"
+       " - timeout\n");
+    join_net((u_long)local);
+
+#ifdef __SMP__
+    enable_irq(dev->irq);
+#endif
+
+    spin_unlock(&local->ray_lock);
+    return;
+}
+/*===========================================================================*/
+static int asc_to_int(char a)
+{
+    if (a < '0') return -1;
+    if (a <= '9') return (a - '0');
+    if (a < 'A') return -1;
+    if (a <= 'F') return (10 + a - 'A');
+    if (a < 'a') return -1;
+    if (a <= 'f') return (10 + a - 'a');
+    return -1;
+}
+/*===========================================================================*/
+static int parse_addr(char *in_str, UCHAR *out)
+{
+    int len;
+    int i,j,k;
+    int status;
+    
+    if (in_str == NULL) return 0;
+    if ((len = strlen(in_str)) < 2) return 0;
+    memset(out, 0, ADDRLEN);
+
+    status = 1;
+    j = len - 1;
+    if (j > 12) j = 12;
+    i = 5;
+    
+    while (j > 0)
+    {
+        if ((k = asc_to_int(in_str[j--])) != -1) out[i] = k;
+        else return 0;
+
+        if (j == 0) break;
+        if ((k = asc_to_int(in_str[j--])) != -1) out[i] += k << 4;
+        else return 0;
+        if (!i--) break;
+    }
+    return status;
+}
+/*===========================================================================*/
+static struct enet_statistics *ray_get_stats(struct net_device *dev)
+{
+    ray_dev_t *local = (ray_dev_t *)dev->priv;
+    dev_link_t *link = local->finder;
+    struct status *p = (struct status *)(local->sram + STATUS_BASE);
+
+    if (!DEV_OK(link)) {
+        DEBUG(2,"ray_cs enet_statistics - device not present\n");
+        return &local->stats;
+    }
+
+    if (readb(&p->mrx_overflow_for_host))
+    {
+        local->stats.rx_over_errors += ntohs(readb(&p->mrx_overflow));
+        writeb(0,&p->mrx_overflow);
+        writeb(0,&p->mrx_overflow_for_host);
+    }
+    if (readb(&p->mrx_checksum_error_for_host))
+    {
+        local->stats.rx_crc_errors += ntohs(readb(&p->mrx_checksum_error));
+        writeb(0,&p->mrx_checksum_error);
+        writeb(0,&p->mrx_checksum_error_for_host);
+    }
+    if (readb(&p->rx_hec_error_for_host))
+    {
+        local->stats.rx_frame_errors += ntohs(readb(&p->rx_hec_error));
+        writeb(0,&p->rx_hec_error);
+        writeb(0,&p->rx_hec_error_for_host);
+    }
+    return &local->stats;
+}
+/*===========================================================================*/
+static void ray_update_parm(struct net_device *dev, UCHAR objid, UCHAR *value, int len)
+{
+    ray_dev_t *local = (ray_dev_t *)dev->priv;
+    dev_link_t *link = local->finder;
+    int ccsindex;
+    int i;
+    struct ccs *pccs;
+
+    if (!DEV_OK(link)) {
+        DEBUG(2,"ray_update_parm - device not present\n");
+        return;
+    }
+
+#ifdef __SMP__
+    disable_irq(dev->irq);
+#endif
+
+    spin_lock(&local->ray_lock);
+
+    if ((ccsindex = get_free_ccs(local)) < 0)
+    {
+        DEBUG(0,"ray_update_parm - No free ccs\n");
+#ifdef __SMP__
+        enable_irq(dev->irq);
+#endif
+        spin_unlock(&local->ray_lock);
+        return;
+    }
+    pccs = ((struct ccs *)(local->sram + CCS_BASE)) + ccsindex;
+    writeb(CCS_UPDATE_PARAMS, &pccs->cmd);
+    writeb(objid, &pccs->var.update_param.object_id);
+    writeb(1, &pccs->var.update_param.number_objects);
+    writeb(0, &pccs->var.update_param.failure_cause);
+    for (i=0; i<len; i++) {
+        writeb(value[i], local->sram + HOST_TO_ECF_BASE);
+    }
+    /* Interrupt the firmware to process the command */
+    if (interrupt_ecf(local, ccsindex)) {
+        DEBUG(0,"ray_cs associate failed - ECF not ready for intr\n");
+        writeb(CCS_BUFFER_FREE, &(pccs++)->buffer_status);
+    }
+#ifdef __SMP__
+    enable_irq(dev->irq);
+#endif
+    spin_unlock(&local->ray_lock);
+    return;
+}
+/*===========================================================================*/
+static void ray_update_multi_list(struct net_device *dev, int all)
+{
+    struct dev_mc_list *dmi, **dmip;
+    int ccsindex;
+    struct ccs *pccs;
+    int i = 0;
+    ray_dev_t *local = (ray_dev_t *)dev->priv;
+    dev_link_t *link = local->finder;
+    UCHAR *p = local->sram + HOST_TO_ECF_BASE;
+
+    if (!DEV_OK(link)) {
+        DEBUG(2,"ray_update_multi_list - device not present\n");
+        return;
+    }
+    else 
+        DEBUG(2,"ray_update_multi_list(%p)\n",dev);
+
+#ifdef __SMP__
+    disable_irq(dev->irq);
+#endif
+
+    spin_lock(&local->ray_lock);
+
+    if ((ccsindex = get_free_ccs(local)) < 0)
+    {
+        DEBUG(1,"ray_update_multi - No free ccs\n");
+#ifdef __SMP__
+        enable_irq(dev->irq);
+#endif
+        spin_unlock(&local->ray_lock);
+        return;
+    }
+    pccs = ((struct ccs *)(local->sram + CCS_BASE)) + ccsindex;
+    writeb(CCS_UPDATE_MULTICAST_LIST, &pccs->cmd);
+
+    if (all) {
+        writeb(0xff, &pccs->var);
+        local->num_multi = 0xff;
+    }
+    else {
+        /* Copy the kernel's list of MC addresses to card */
+        for (dmip=&dev->mc_list; (dmi=*dmip)!=NULL; dmip=&dmi->next) {
+            memcpy_toio(p, dmi->dmi_addr, ETH_ALEN);
+            DEBUG(1,"ray_update_multi add addr %02x%02x%02x%02x%02x%02x\n",dmi->dmi_addr[0],dmi->dmi_addr[1],dmi->dmi_addr[2],dmi->dmi_addr[3],dmi->dmi_addr[4],dmi->dmi_addr[5]);
+            p += ETH_ALEN;
+            i++;
+        }
+        if (i > 256/ADDRLEN) i = 256/ADDRLEN;
+        writeb((UCHAR)i, &pccs->var);
+        DEBUG(1,"ray_cs update_multi %d addresses in list\n", i);
+        /* Interrupt the firmware to process the command */
+        local->num_multi = i;
+    }
+    if (interrupt_ecf(local, ccsindex)) {
+        DEBUG(1,"ray_cs update_multi failed - ECF not ready for intr\n");
+        writeb(CCS_BUFFER_FREE, &(pccs++)->buffer_status);
+    }
+#ifdef __SMP__
+    enable_irq(dev->irq);
+#endif
+    spin_unlock(&local->ray_lock);
+    return;
+} /* end ray_update_multi_list */
+/*===========================================================================*/
+static void set_multicast_list(struct net_device *dev)
+{
+    ray_dev_t *local = (ray_dev_t *)dev->priv;
+    UCHAR promisc;
+
+    DEBUG(2,"ray_cs set_multicast_list(%p)\n",dev);
+
+    if (dev->flags & IFF_PROMISC)
+    {
+        if (local->sparm.b5.a_promiscuous_mode == 0) {
+            DEBUG(1,"ray_cs set_multicast_list promisc on\n");
+            local->sparm.b5.a_promiscuous_mode = 1;
+            promisc = 1;
+            ray_update_parm(dev,  OBJID_promiscuous_mode, \
+                            &promisc, sizeof(promisc));
+        }
+    }
+    else {
+        if (local->sparm.b5.a_promiscuous_mode == 1) {
+            DEBUG(1,"ray_cs set_multicast_list promisc off\n");
+            local->sparm.b5.a_promiscuous_mode = 0;
+            promisc = 0;
+            ray_update_parm(dev,  OBJID_promiscuous_mode, \
+                            &promisc, sizeof(promisc));
+        }
+    }
+
+    if (dev->flags & IFF_ALLMULTI) ray_update_multi_list(dev, 1);
+    else
+    {
+        if (local->num_multi != dev->mc_count) ray_update_multi_list(dev, 0);
+    }
+} /* end set_multicast_list */
+/*=============================================================================
+ * All routines below here are run at interrupt time.
+=============================================================================*/
+static void ray_interrupt(int irq, void *dev_id, struct pt_regs * regs)
+{
+    struct net_device *dev = (struct net_device *)dev_id;
+    ray_dev_t *local = dev->priv;
+    dev_link_t *link = local->finder;
+    struct ccs *pccs;
+    struct rcs *prcs;
+    UCHAR rcsindex;
+    UCHAR tmp;
+    UCHAR cmd;
+    UCHAR status;
+
+    if ( !DEV_OK(link) ) {
+        DEBUG(2,"ray_cs interrupt from device not present or suspended.\n");
+        return;
+    }
+
+    DEBUG(3,"ray_cs: interrupt for *dev=%p\n",dev);
+
+    if (!(spin_trylock(&local->ray_lock))) {
+	printk(KERN_DEBUG "ray_cs::ray_interrupt: spinlock locked in interrupt\n");
+    }
+
+    rcsindex = readb(&((struct scb *)(local->sram))->rcs_index);
+
+    DEBUG(3, "ray_cs: Interrupt rcsindex = %d\n", rcsindex);
+
+    if (rcsindex >= (NUMBER_OF_CCS + NUMBER_OF_RCS))
+    {
+        printk("ray_cs interrupt bad rcsindex = 0x%x\n",rcsindex);
+        spin_unlock(&local->ray_lock);
+        clear_interrupt(local);
+        return;
+    }
+    if (rcsindex < NUMBER_OF_CCS) /* If it's a returned CCS */
+    {
+        pccs = ((struct ccs *) (local->sram + CCS_BASE)) + rcsindex;
+        cmd = readb(&pccs->cmd);
+        status = readb(&pccs->buffer_status);
+        switch (cmd)
+        {
+        case CCS_DOWNLOAD_STARTUP_PARAMS: /* Happens in firmware someday */
+            del_timer(&local->timer);
+            if (status == CCS_COMMAND_COMPLETE) {
+                DEBUG(1,"ray_cs interrupt download_startup_parameters OK\n");
+            }
+            else {
+                DEBUG(1,"ray_cs interrupt download_startup_parameters fail\n");
+            }
+            break;
+        case CCS_UPDATE_PARAMS:
+            DEBUG(1,"ray_cs interrupt update params done\n");
+            if (status != CCS_COMMAND_COMPLETE) {
+                tmp = readb(&pccs->var.update_param.failure_cause);
+            DEBUG(0,"ray_cs interrupt update params failed - reason %d\n",tmp);
+            }
+            break;
+        case CCS_REPORT_PARAMS:
+            DEBUG(1,"ray_cs interrupt report params done\n");
+            break;
+        case CCS_UPDATE_MULTICAST_LIST: /* Note that this CCS isn't returned */
+            DEBUG(1,"ray_cs interrupt CCS Update Multicast List done\n");
+            break;
+        case CCS_UPDATE_POWER_SAVINGS_MODE:
+            DEBUG(1,"ray_cs interrupt update power save mode done\n");
+            break;
+        case CCS_START_NETWORK:
+        case CCS_JOIN_NETWORK:
+            if (status == CCS_COMMAND_COMPLETE) {
+                if (readb(&pccs->var.start_network.net_initiated) == 1) {
+                    printk(KERN_DEBUG "ray_cs interrupt network \"%s\" started\n",\
+                          local->sparm.b4.a_current_ess_id);
+                }
+                else {
+                    printk(KERN_DEBUG "ray_cs interrupt network \"%s\" joined\n",\
+                          local->sparm.b4.a_current_ess_id);
+                }
+                memcpy_fromio(&local->bss_id,pccs->var.start_network.bssid,ADDRLEN);
+
+                if (local->fw_ver == 0x55) local->net_default_tx_rate = 3;
+                else local->net_default_tx_rate = 
+                         readb(&pccs->var.start_network.net_default_tx_rate);
+                local->encryption = readb(&pccs->var.start_network.encryption);
+                if (!sniffer && (local->net_type == INFRA)
+                    && !(local->sparm.b4.a_acting_as_ap_status)) {
+                    authenticate(local);
+                }
+                local->card_status = CARD_ACQ_COMPLETE;
+            }
+            else {
+                local->card_status = CARD_ACQ_FAILED;
+
+                del_timer(&local->timer);
+                local->timer.expires = jiffies + HZ*5;
+                local->timer.data = (long)local;
+                if (status == CCS_START_NETWORK) {
+                    DEBUG(0,"ray_cs interrupt network \"%s\" start failed\n",\
+                          local->sparm.b4.a_current_ess_id);
+                    local->timer.function = &start_net;
+                }
+                else {
+                    DEBUG(0,"ray_cs interrupt network \"%s\" join failed\n",\
+                          local->sparm.b4.a_current_ess_id);
+                    local->timer.function = &join_net;
+                }
+                add_timer(&local->timer);
+            }
+            break;
+        case CCS_START_ASSOCIATION:
+            if (status == CCS_COMMAND_COMPLETE) {
+                local->card_status = CARD_ASSOC_COMPLETE;
+                DEBUG(0,"ray_cs association successful\n");
+            }
+            else
+            {
+                DEBUG(0,"ray_cs association failed,\n");
+                local->card_status = CARD_ASSOC_FAILED;
+                join_net((u_long)local);
+            }
+            break;
+        case CCS_TX_REQUEST:
+            if (status == CCS_COMMAND_COMPLETE) {
+                DEBUG(3,"ray_cs interrupt tx request complete\n");
+            }
+            else {
+                DEBUG(1,"ray_cs interrupt tx request failed\n");
+            }
+            if (!sniffer)
+		netif_wake_queue(dev);
+            break;
+        case CCS_TEST_MEMORY:
+            DEBUG(1,"ray_cs interrupt mem test done\n");
+            break;
+        case CCS_SHUTDOWN:
+            DEBUG(1,"ray_cs interrupt Unexpected CCS returned - Shutdown\n");
+            break;
+        case CCS_DUMP_MEMORY:
+            DEBUG(1,"ray_cs interrupt dump memory done\n");
+            break;
+        case CCS_START_TIMER:
+            DEBUG(2,"ray_cs interrupt DING - raylink timer expired\n");
+            break;
+        default:
+            DEBUG(1,"ray_cs interrupt Unexpected CCS 0x%x returned 0x%x\n",\
+                  rcsindex, cmd);
+        }
+        writeb(CCS_BUFFER_FREE, &pccs->buffer_status);
+    }
+    else /* It's an RCS */
+    {
+        prcs = ((struct rcs *)(local->sram + CCS_BASE)) + rcsindex;
+    
+        switch (readb(&prcs->interrupt_id))
+        {
+        case PROCESS_RX_PACKET:
+            ray_rx(dev, local, prcs);
+            break;
+        case REJOIN_NET_COMPLETE:
+            DEBUG(1,"ray_cs interrupt rejoin net complete\n");
+            local->card_status = CARD_ACQ_COMPLETE;
+            /* do we need to clear tx buffers CCS's? */
+            if (local->sparm.b4.a_network_type == ADHOC) {
+                if (!sniffer) netif_wake_queue(dev);
+            }
+            else {
+                memcpy_fromio(&local->bss_id, prcs->var.rejoin_net_complete.bssid, ADDRLEN);
+                DEBUG(1,"ray_cs new BSSID = %02x%02x%02x%02x%02x%02x\n",\
+                      local->bss_id[0], local->bss_id[1], local->bss_id[2],\
+                      local->bss_id[3], local->bss_id[4], local->bss_id[5]);
+                if (!sniffer) authenticate(local);
+            }
+            break;
+        case ROAMING_INITIATED:
+            DEBUG(1,"ray_cs interrupt roaming initiated\n"); 
+	    netif_stop_queue(dev);
+            local->card_status = CARD_DOING_ACQ;
+            break;
+        case JAPAN_CALL_SIGN_RXD:
+            DEBUG(1,"ray_cs interrupt japan call sign rx\n");
+            break;
+        default:
+            DEBUG(1,"ray_cs Unexpected interrupt for RCS 0x%x cmd = 0x%x\n",\
+                  rcsindex, (unsigned int) readb(&prcs->interrupt_id));
+            break;
+        }
+        writeb(CCS_BUFFER_FREE, &prcs->buffer_status);
+    }
+    spin_unlock(&local->ray_lock);
+    clear_interrupt(local);
+} /* ray_interrupt */
+/*===========================================================================*/
+static void ray_rx(struct net_device *dev, ray_dev_t *local, struct rcs *prcs)
+{
+    int rx_len;
+    unsigned int pkt_addr;
+    UCHAR *pmsg;
+    DEBUG(4,"ray_rx process rx packet\n");
+
+    /* Calculate address of packet within Rx buffer */
+    pkt_addr = ((readb(&prcs->var.rx_packet.rx_data_ptr[0]) << 8)
+                + readb(&prcs->var.rx_packet.rx_data_ptr[1])) & RX_BUFF_END;
+    /* Length of first packet fragment */
+    rx_len = (readb(&prcs->var.rx_packet.rx_data_length[0]) << 8)
+        + readb(&prcs->var.rx_packet.rx_data_length[1]);
+
+    local->last_rsl = readb(&prcs->var.rx_packet.rx_sig_lev);
+    pmsg = local->rmem + pkt_addr;
+    switch(readb(pmsg))
+    {
+    case DATA_TYPE:
+        DEBUG(4,"ray_rx data type\n");
+        rx_data(dev, prcs, pkt_addr, rx_len);
+        break;
+    case AUTHENTIC_TYPE:
+        DEBUG(4,"ray_rx authentic type\n");
+        if (sniffer) rx_data(dev, prcs, pkt_addr, rx_len);
+        else rx_authenticate(local, prcs, pkt_addr, rx_len);
+        break;
+    case DEAUTHENTIC_TYPE:
+        DEBUG(4,"ray_rx deauth type\n");
+        if (sniffer) rx_data(dev, prcs, pkt_addr, rx_len);
+        else rx_deauthenticate(local, prcs, pkt_addr, rx_len);
+        break;
+    case NULL_MSG_TYPE:
+        DEBUG(3,"ray_cs rx NULL msg\n");
+        break;
+    case BEACON_TYPE:
+        DEBUG(4,"ray_rx beacon type\n");
+        if (sniffer) rx_data(dev, prcs, pkt_addr, rx_len);
+
+        copy_from_rx_buff(local, (UCHAR *)&local->last_bcn, pkt_addr, 
+                          rx_len < sizeof(struct beacon_rx) ? 
+                          rx_len : sizeof(struct beacon_rx));
+
+	local->beacon_rxed = 1;
+        /* Get the statistics so the card counters never overflow */
+        ray_get_stats(dev);
+            break;
+    default:
+        DEBUG(0,"ray_cs unknown pkt type %2x\n", (unsigned int) readb(pmsg));
+        break;
+    }
+
+} /* end ray_rx */
+/*===========================================================================*/
+static void rx_data(struct net_device *dev, struct rcs *prcs, unsigned int pkt_addr, 
+             int rx_len)
+{
+    struct sk_buff *skb = NULL;
+    struct rcs *prcslink = prcs;
+    ray_dev_t *local = dev->priv;
+    UCHAR *rx_ptr;
+    int total_len;
+    int tmp;
+#ifdef WIRELESS_SPY
+    int siglev = local->last_rsl;
+    u_char linksrcaddr[ETH_ALEN];	/* Other end of the wireless link */
+#endif
+
+    if (!sniffer) {
+        if (translate) {
+/* TBD length needs fixing for translated header */
+            if (rx_len < (ETH_HLEN + RX_MAC_HEADER_LENGTH) ||
+                rx_len > (dev->mtu + RX_MAC_HEADER_LENGTH + ETH_HLEN + FCS_LEN)) 
+            {
+                DEBUG(0,"ray_cs invalid packet length %d received \n",rx_len);
+                return;
+            }
+        }
+        else /* encapsulated ethernet */ {
+            if (rx_len < (ETH_HLEN + RX_MAC_HEADER_LENGTH) ||
+                rx_len > (dev->mtu + RX_MAC_HEADER_LENGTH + ETH_HLEN + FCS_LEN))
+            {
+                DEBUG(0,"ray_cs invalid packet length %d received \n",rx_len);
+                return;
+            }
+        }
+    }
+    DEBUG(4,"ray_cs rx_data packet\n");
+    /* If fragmented packet, verify sizes of fragments add up */
+    if (readb(&prcs->var.rx_packet.next_frag_rcs_index) != 0xFF) {
+        DEBUG(1,"ray_cs rx'ed fragment\n");
+        tmp = (readb(&prcs->var.rx_packet.totalpacketlength[0]) << 8)
+            +  readb(&prcs->var.rx_packet.totalpacketlength[1]);
+        total_len = tmp;
+        prcslink = prcs;
+        do {
+            tmp -= (readb(&prcslink->var.rx_packet.rx_data_length[0]) << 8)
+                +   readb(&prcslink->var.rx_packet.rx_data_length[1]);
+            if (readb(&prcslink->var.rx_packet.next_frag_rcs_index) == 0xFF
+                || tmp < 0) break;
+            prcslink = ((struct rcs *)(local->sram + CCS_BASE))
+                + readb(&prcslink->link_field);
+        } while (1);
+
+        if (tmp < 0)
+        {
+            DEBUG(0,"ray_cs rx_data fragment lengths don't add up\n");
+            local->stats.rx_dropped++; 
+            release_frag_chain(local, prcs);
+            return;
+        }
+    }
+    else { /* Single unfragmented packet */
+        total_len = rx_len;
+    }
+
+    skb = dev_alloc_skb( total_len+5 );
+    if (skb == NULL)
+    {
+        DEBUG(0,"ray_cs rx_data could not allocate skb\n");
+        local->stats.rx_dropped++; 
+        if (readb(&prcs->var.rx_packet.next_frag_rcs_index) != 0xFF)
+            release_frag_chain(local, prcs);
+        return;
+    }
+    skb_reserve( skb, 2);   /* Align IP on 16 byte (TBD check this)*/
+    skb->dev = dev;
+
+    DEBUG(4,"ray_cs rx_data total_len = %x, rx_len = %x\n",total_len,rx_len);
+
+/************************/
+    /* Reserve enough room for the whole damn packet. */
+    rx_ptr = skb_put( skb, total_len);
+    /* Copy the whole packet to sk_buff */
+    rx_ptr += copy_from_rx_buff(local, rx_ptr, pkt_addr & RX_BUFF_END, rx_len);
+    /* Get source address */
+#ifdef WIRELESS_SPY
+    memcpy(linksrcaddr, ((struct mac_header *)skb->data)->addr_2, ETH_ALEN);
+#endif
+    /* Now, deal with encapsulation/translation/sniffer */
+    if (!sniffer) {
+        if (!translate) { 
+            /* Encapsulated ethernet, so just lop off 802.11 MAC header */
+/* TBD reserve            skb_reserve( skb, RX_MAC_HEADER_LENGTH); */
+            skb_pull( skb, RX_MAC_HEADER_LENGTH);
+        }
+        else {
+            /* Do translation */
+            untranslate(local, skb, total_len);
+        }
+    }
+    else 
+    {  /* sniffer mode, so just pass whole packet */  };
+
+/************************/
+    /* Now pick up the rest of the fragments if any */
+    tmp = 17; 
+    if (readb(&prcs->var.rx_packet.next_frag_rcs_index) != 0xFF) {
+        prcslink = prcs;
+        DEBUG(1,"ray_cs rx_data in fragment loop\n");
+        do {
+            prcslink = ((struct rcs *)(local->sram + CCS_BASE))
+                + readb(&prcslink->var.rx_packet.next_frag_rcs_index);
+            rx_len = (( readb(&prcslink->var.rx_packet.rx_data_length[0]) << 8)
+                      + readb(&prcslink->var.rx_packet.rx_data_length[1]))
+                & RX_BUFF_END;
+            pkt_addr = (( readb(&prcslink->var.rx_packet.rx_data_ptr[0]) << 8)
+                        + readb(&prcslink->var.rx_packet.rx_data_ptr[1]))
+                & RX_BUFF_END;
+
+            rx_ptr += copy_from_rx_buff(local, rx_ptr, pkt_addr, rx_len);
+
+        } while (tmp-- && 
+                 readb(&prcslink->var.rx_packet.next_frag_rcs_index) != 0xFF);
+        release_frag_chain(local, prcs);
+    }
+
+    skb->protocol = eth_type_trans(skb,dev);
+    netif_rx(skb);
+
+    local->stats.rx_packets++;
+    add_rx_bytes(&local->stats, skb->len);
+
+    /* Gather signal strength per address */
+#ifdef WIRELESS_SPY
+    /* For the Access Point or the node having started the ad-hoc net
+     * note : ad-hoc work only in some specific configurations, but we
+     * kludge in ray_get_wireless_stats... */
+    if(!memcmp(linksrcaddr, local->bss_id, ETH_ALEN))
+      {
+	/* Update statistics */
+	/*local->wstats.qual.qual = none ? */
+	local->wstats.qual.level = siglev;
+	/*local->wstats.qual.noise = none ? */
+	local->wstats.qual.updated = 0x2;
+      }
+    /* Now, for the addresses in the spy list */
+    {
+      int	i;
+      /* Look all addresses */
+      for(i = 0; i < local->spy_number; i++)
+	/* If match */
+	if(!memcmp(linksrcaddr, local->spy_address[i], ETH_ALEN))
+	  {
+	    /* Update statistics */
+	    /*local->spy_stat[i].qual = none ? */
+	    local->spy_stat[i].level = siglev;
+	    /*local->spy_stat[i].noise = none ? */
+	    local->spy_stat[i].updated = 0x2;
+	  }
+    }
+#endif	/* WIRELESS_SPY */
+} /* end rx_data */
+/*===========================================================================*/
+static void untranslate(ray_dev_t *local, struct sk_buff *skb, int len)
+{
+    snaphdr_t *psnap = (snaphdr_t *)(skb->data + RX_MAC_HEADER_LENGTH);
+    struct mac_header *pmac = (struct mac_header *)skb->data;
+    unsigned short type = *(unsigned short *)psnap->ethertype;
+    unsigned int xsap = *(unsigned int *)psnap & 0x00ffffff;
+    unsigned int org = (*(unsigned int *)psnap->org) & 0x00ffffff;
+    int delta;
+    struct ethhdr *peth;
+    UCHAR srcaddr[ADDRLEN];
+    UCHAR destaddr[ADDRLEN];
+
+    if (pmac->frame_ctl_2 & FC2_FROM_DS) {
+	if (pmac->frame_ctl_2 & FC2_TO_DS) { /* AP to AP */
+	    memcpy(destaddr, pmac->addr_3, ADDRLEN);
+	    memcpy(srcaddr, ((unsigned char *)pmac->addr_3) + ADDRLEN, ADDRLEN);
+	} else { /* AP to terminal */
+	    memcpy(destaddr, pmac->addr_1, ADDRLEN);
+	    memcpy(srcaddr, pmac->addr_3, ADDRLEN); 
+	}
+    } else { /* Terminal to AP */
+	if (pmac->frame_ctl_2 & FC2_TO_DS) {
+	    memcpy(destaddr, pmac->addr_3, ADDRLEN);
+	    memcpy(srcaddr, pmac->addr_2, ADDRLEN); 
+	} else { /* Adhoc */
+	    memcpy(destaddr, pmac->addr_1, ADDRLEN);
+	    memcpy(srcaddr, pmac->addr_2, ADDRLEN); 
+	}
+    }
+
+#ifdef PCMCIA_DEBUG
+    if (pc_debug > 3) {
+    int i;
+    printk(KERN_DEBUG "skb->data before untranslate");
+    for (i=0;i<64;i++) 
+        printk("%02x ",skb->data[i]);
+    printk("\n" KERN_DEBUG "type = %08x, xsap = %08x, org = %08x\n",
+           type,xsap,org);
+    printk(KERN_DEBUG "untranslate skb->data = %p\n",skb->data);
+    }
+#endif
+
+    if ( xsap != SNAP_ID) {
+        /* not a snap type so leave it alone */
+        DEBUG(3,"ray_cs untranslate NOT SNAP %x\n", *(unsigned int *)psnap & 0x00ffffff);
+
+        delta = RX_MAC_HEADER_LENGTH - ETH_HLEN;
+        peth = (struct ethhdr *)(skb->data + delta);
+        peth->h_proto = htons(len - RX_MAC_HEADER_LENGTH);
+    }
+    else { /* Its a SNAP */
+        if (org == BRIDGE_ENCAP) { /* EtherII and nuke the LLC  */
+        DEBUG(3,"ray_cs untranslate Bridge encap\n");
+            delta = RX_MAC_HEADER_LENGTH 
+                + sizeof(struct snaphdr_t) - ETH_HLEN;
+            peth = (struct ethhdr *)(skb->data + delta);
+            peth->h_proto = type;
+        }
+        else {
+            if (org == RFC1042_ENCAP) {
+                switch (type) {
+                case RAY_IPX_TYPE:
+                case APPLEARP_TYPE:
+                    DEBUG(3,"ray_cs untranslate RFC IPX/AARP\n");
+                    delta = RX_MAC_HEADER_LENGTH - ETH_HLEN;
+                    peth = (struct ethhdr *)(skb->data + delta);
+                    peth->h_proto = htons(len - RX_MAC_HEADER_LENGTH);
+                    break;
+                default:
+                    DEBUG(3,"ray_cs untranslate RFC default\n");
+                    delta = RX_MAC_HEADER_LENGTH + 
+                        sizeof(struct snaphdr_t) - ETH_HLEN;
+                    peth = (struct ethhdr *)(skb->data + delta);
+                    peth->h_proto = type;
+                    break;
+                }
+            }
+            else {
+                printk("ray_cs untranslate very confused by packet\n");
+                delta = RX_MAC_HEADER_LENGTH - ETH_HLEN;
+                peth = (struct ethhdr *)(skb->data + delta);
+                peth->h_proto = type;
+            }
+        }
+    }
+/* TBD reserve  skb_reserve(skb, delta); */
+    skb_pull(skb, delta);
+    DEBUG(3,"untranslate after skb_pull(%d), skb->data = %p\n",delta,skb->data);
+    memcpy(peth->h_dest, destaddr, ADDRLEN);
+    memcpy(peth->h_source, srcaddr, ADDRLEN);
+#ifdef PCMCIA_DEBUG
+    if (pc_debug > 3) {
+    int i;
+    printk(KERN_DEBUG "skb->data after untranslate:");
+    for (i=0;i<64;i++)
+        printk("%02x ",skb->data[i]);
+    printk("\n");
+    }
+#endif
+} /* end untranslate */
+/*===========================================================================*/
+/* Copy data from circular receive buffer to PC memory.
+ * dest     = destination address in PC memory
+ * pkt_addr = source address in receive buffer
+ * len      = length of packet to copy
+ */
+static int copy_from_rx_buff(ray_dev_t *local, UCHAR *dest, int pkt_addr, int length)
+{
+    int wrap_bytes = (pkt_addr + length) - (RX_BUFF_END + 1);
+    if (wrap_bytes <= 0)
+    {
+        memcpy_fromio(dest,local->rmem + pkt_addr,length);
+    }
+    else /* Packet wrapped in circular buffer */
+    {
+        memcpy_fromio(dest,local->rmem+pkt_addr,length - wrap_bytes);
+        memcpy_fromio(dest + length - wrap_bytes, local->rmem, wrap_bytes);
+    }
+    return length;
+}
+/*===========================================================================*/
+static void release_frag_chain(ray_dev_t *local, struct rcs* prcs)
+{
+    struct rcs *prcslink = prcs;
+    int tmp = 17;
+    unsigned rcsindex = readb(&prcs->var.rx_packet.next_frag_rcs_index);
+
+    while (tmp--) {
+        writeb(CCS_BUFFER_FREE, &prcslink->buffer_status);
+        if (rcsindex >= (NUMBER_OF_CCS + NUMBER_OF_RCS)) {
+            DEBUG(1,"ray_cs interrupt bad rcsindex = 0x%x\n",rcsindex);
+            break;      
+        }   
+        prcslink = ((struct rcs *)(local->sram + CCS_BASE)) + rcsindex;
+        rcsindex = readb(&prcslink->var.rx_packet.next_frag_rcs_index);
+    }
+    writeb(CCS_BUFFER_FREE, &prcslink->buffer_status);
+}
+/*===========================================================================*/
+static void authenticate(ray_dev_t *local)
+{
+    dev_link_t *link = local->finder;
+    DEBUG(0,"ray_cs Starting authentication.\n");
+    if (!(link->state & DEV_PRESENT)) {
+        DEBUG(2,"ray_cs authenticate - device not present\n");
+        return;
+    }
+
+    del_timer(&local->timer);
+    if (build_auth_frame(local, local->bss_id, OPEN_AUTH_REQUEST)) {
+        local->timer.function = &join_net;
+    }
+    else {
+        local->timer.function = &authenticate_timeout;
+    }
+    local->timer.expires = jiffies + HZ*2;
+    local->timer.data = (long)local;
+    add_timer(&local->timer);
+    local->authentication_state = AWAITING_RESPONSE;
+} /* end authenticate */
+/*===========================================================================*/
+static void rx_authenticate(ray_dev_t *local, struct rcs *prcs,
+                     unsigned int pkt_addr, int rx_len)
+{
+    UCHAR buff[256];
+    struct rx_msg *msg = (struct rx_msg *)buff;
+    
+    del_timer(&local->timer);
+
+    copy_from_rx_buff(local, buff, pkt_addr, rx_len & 0xff);
+    /* if we are trying to get authenticated */
+    if (local->sparm.b4.a_network_type == ADHOC) {
+        DEBUG(1,"ray_cs rx_auth var= %02x %02x %02x %02x %02x %02x\n", msg->var[0],msg->var[1],msg->var[2],msg->var[3],msg->var[4],msg->var[5]);
+        if (msg->var[2] == 1) {
+                    DEBUG(0,"ray_cs Sending authentication response.\n");
+                    if (!build_auth_frame (local, msg->mac.addr_2, OPEN_AUTH_RESPONSE)) {
+                        local->authentication_state = NEED_TO_AUTH;
+                        memcpy(local->auth_id, msg->mac.addr_2, ADDRLEN);
+                    }
+        }
+    }
+    else /* Infrastructure network */
+    {
+        if (local->authentication_state == AWAITING_RESPONSE) {
+            /* Verify authentication sequence #2 and success */
+            if (msg->var[2] == 2) {
+                if ((msg->var[3] | msg->var[4]) == 0) {
+                    DEBUG(1,"Authentication successful\n");
+                    local->card_status = CARD_AUTH_COMPLETE;
+                    associate(local);
+                    local->authentication_state = AUTHENTICATED;
+                }
+                else {
+                    DEBUG(0,"Authentication refused\n");
+                    local->card_status = CARD_AUTH_REFUSED;
+                    join_net((u_long)local);
+                    local->authentication_state = UNAUTHENTICATED;
+                }
+            }
+        }
+    }
+
+} /* end rx_authenticate */
+/*===========================================================================*/
+static void associate(ray_dev_t *local)
+{
+    struct ccs *pccs;
+    dev_link_t *link = local->finder;
+    struct net_device *dev = link->priv;
+    int ccsindex;
+    if (!(link->state & DEV_PRESENT)) {
+        DEBUG(2,"ray_cs associate - device not present\n");
+        return;
+    }
+    /* If no tx buffers available, return*/
+    if ((ccsindex = get_free_ccs(local)) < 0)
+    {
+/* TBD should never be here but... what if we are? */
+        DEBUG(1,"ray_cs associate - No free ccs\n");
+        return;
+    }
+    DEBUG(1,"ray_cs Starting association with access point\n");
+    pccs = ((struct ccs *)(local->sram + CCS_BASE)) + ccsindex;
+    /* fill in the CCS */
+    writeb(CCS_START_ASSOCIATION, &pccs->cmd);
+    /* Interrupt the firmware to process the command */
+    if (interrupt_ecf(local, ccsindex)) {
+        DEBUG(1,"ray_cs associate failed - ECF not ready for intr\n");
+        writeb(CCS_BUFFER_FREE, &(pccs++)->buffer_status);
+
+        del_timer(&local->timer);
+        local->timer.expires = jiffies + HZ*2;
+        local->timer.data = (long)local;
+        local->timer.function = &join_net;
+        add_timer(&local->timer);
+        local->card_status = CARD_ASSOC_FAILED;
+        return;
+    }
+    if (!sniffer) netif_start_queue(dev);
+
+} /* end associate */
+/*===========================================================================*/
+static void rx_deauthenticate(ray_dev_t *local, struct rcs *prcs, 
+                       unsigned int pkt_addr, int rx_len)
+{
+/*  UCHAR buff[256];
+    struct rx_msg *msg = (struct rx_msg *)buff;
+*/
+    DEBUG(0,"Deauthentication frame received\n");
+    local->authentication_state = UNAUTHENTICATED;
+    /* Need to reauthenticate or rejoin depending on reason code */
+/*  copy_from_rx_buff(local, buff, pkt_addr, rx_len & 0xff);
+ */
+}
+/*===========================================================================*/
+static void clear_interrupt(ray_dev_t *local)
+{
+    writeb(0, local->amem + CIS_OFFSET + HCS_INTR_OFFSET);
+}
+/*===========================================================================*/
+#ifdef HAS_PROC_BUS
+#define MAXDATA (PAGE_SIZE - 80)
+
+static char *card_status[] = {
+    "Card inserted - uninitialized",     /* 0 */
+    "Card not downloaded",               /* 1 */
+    "Waiting for download parameters",   /* 2 */
+    "Card doing acquisition",            /* 3 */
+    "Acquisition complete",              /* 4 */
+    "Authentication complete",           /* 5 */
+    "Association complete",              /* 6 */
+    "???", "???", "???", "???",          /* 7 8 9 10 undefined */
+    "Card init error",                   /* 11 */
+    "Download parameters error",         /* 12 */
+    "???",                               /* 13 */
+    "Acquisition failed",                /* 14 */
+    "Authentication refused",            /* 15 */
+    "Association failed"                 /* 16 */
+};
+
+static char *nettype[] = {"Adhoc", "Infra "};
+static char *framing[] = {"Encapsulation", "Translation"}
+;
+/*===========================================================================*/
+static int ray_cs_proc_read(char *buf, char **start, off_t offset, 
+                     int len, int *eof, void *data)
+{
+/* Print current values which are not available via other means
+ * eg ifconfig 
+ */
+    int i;
+    dev_link_t *link = dev_list;
+    struct net_device *dev = (struct net_device *)link->priv;
+    ray_dev_t *local = (ray_dev_t *)dev->priv;
+    UCHAR *p;
+    struct freq_hop_element *pfh;
+    UCHAR c[33];
+
+    len = 0;
+
+    len += sprintf(buf + len, "Raylink Wireless LAN driver status\n");
+    len += sprintf(buf + len, "%s\n", rcsid);
+    /* build 4 does not report version, and field is 0x55 after memtest */
+    len += sprintf(buf + len, "Firmware version     = ");
+    if (local->fw_ver == 0x55)
+        len += sprintf(buf + len, "4 - Use dump_cis for more details\n");
+    else
+        len += sprintf(buf + len, "%2d.%02d.%02d\n",
+                   local->fw_ver, local->fw_bld, local->fw_var);
+
+    for (i=0; i<32; i++) c[i] = local->sparm.b5.a_current_ess_id[i];
+    c[32] = 0;
+    len += sprintf(buf + len, "%s network ESSID = \"%s\"\n", 
+                   nettype[local->sparm.b5.a_network_type], c);
+
+    p = local->bss_id;
+    len += sprintf(buf + len, 
+                   "BSSID                = %02x:%02x:%02x:%02x:%02x:%02x\n",
+                   p[0],p[1],p[2],p[3],p[4],p[5]);
+
+    len += sprintf(buf + len, "Country code         = %d\n", 
+                   local->sparm.b5.a_curr_country_code);
+
+    i = local->card_status;
+    if (i < 0) i = 10;
+    if (i > 16) i = 10;
+    len += sprintf(buf + len, "Card status          = %s\n", card_status[i]);
+
+    len += sprintf(buf + len, "Framing mode         = %s\n",framing[translate]);
+
+    len += sprintf(buf + len, "Last pkt signal lvl  = %d\n", local->last_rsl);
+
+    if (local->beacon_rxed) {
+	/* Pull some fields out of last beacon received */
+	len += sprintf(buf + len, "Beacon Interval      = %d Kus\n", 
+		       local->last_bcn.beacon_intvl[0]
+		       + 256 * local->last_bcn.beacon_intvl[1]);
+    
+	p = local->last_bcn.elements;
+	if (p[0] == C_ESSID_ELEMENT_ID) p += p[1] + 2;
+	else {
+	    len += sprintf(buf + len, "Parse beacon failed at essid element id = %d\n",p[0]);
+	    return len;
+	}
+
+	if (p[0] == C_SUPPORTED_RATES_ELEMENT_ID) {
+	    len += sprintf(buf + len, "Supported rate codes = ");
+	    for (i=2; i<p[1] + 2; i++) 
+		len += sprintf(buf + len, "0x%02x ", p[i]);
+	    len += sprintf(buf + len, "\n");
+	    p += p[1] + 2;
+	}
+	else {
+	    len += sprintf(buf + len, "Parse beacon failed at rates element\n");
+	    return len;
+	}
+
+	if (p[0] == C_FH_PARAM_SET_ELEMENT_ID) {
+	    pfh = (struct freq_hop_element *)p;
+	    len += sprintf(buf + len, "Hop dwell            = %d Kus\n",
+			   pfh->dwell_time[0] + 256 * pfh->dwell_time[1]);
+	    len += sprintf(buf + len, "Hop set              = %d \n", pfh->hop_set);
+	    len += sprintf(buf + len, "Hop pattern          = %d \n", pfh->hop_pattern);
+	    len += sprintf(buf + len, "Hop index            = %d \n", pfh->hop_index);
+	    p += p[1] + 2;
+	}
+	else {
+	    len += sprintf(buf + len, "Parse beacon failed at FH param element\n");
+	    return len;
+	}
+    } else {
+	len += sprintf(buf + len, "No beacons received\n");
+    }
+    return len;
+}
+
+#endif
+/*===========================================================================*/
+static int build_auth_frame(ray_dev_t *local, UCHAR *dest, int auth_type)
+{
+    int addr;
+    struct ccs *pccs;
+    struct tx_msg *ptx;
+    int ccsindex;
+
+    /* If no tx buffers available, return */
+    if ((ccsindex = get_free_tx_ccs(local)) < 0)
+    {
+        DEBUG(1,"ray_cs send authenticate - No free tx ccs\n");
+        return -1;
+    }
+
+    pccs = ((struct ccs *)(local->sram + CCS_BASE)) + ccsindex;
+
+    /* Address in card space */
+    addr = TX_BUF_BASE + (ccsindex << 11);
+    /* fill in the CCS */
+    writeb(CCS_TX_REQUEST, &pccs->cmd);
+    writeb(addr >> 8, pccs->var.tx_request.tx_data_ptr);
+    writeb(0x20, pccs->var.tx_request.tx_data_ptr + 1);
+    writeb(TX_AUTHENTICATE_LENGTH_MSB, pccs->var.tx_request.tx_data_length);
+    writeb(TX_AUTHENTICATE_LENGTH_LSB,pccs->var.tx_request.tx_data_length + 1);
+    writeb(0, &pccs->var.tx_request.pow_sav_mode);
+
+    ptx = (struct tx_msg *)(local->sram + addr);
+    /* fill in the mac header */
+    writeb(PROTOCOL_VER | AUTHENTIC_TYPE, &ptx->mac.frame_ctl_1);
+    writeb(0, &ptx->mac.frame_ctl_2);
+
+    memcpy_toio(ptx->mac.addr_1, dest, ADDRLEN);
+    memcpy_toio(ptx->mac.addr_2, local->sparm.b4.a_mac_addr, ADDRLEN);
+    memcpy_toio(ptx->mac.addr_3, local->bss_id, ADDRLEN);
+
+    /* Fill in msg body with protocol 00 00, sequence 01 00 ,status 00 00 */
+    memset_io(ptx->var, 0, 6);
+    writeb(auth_type & 0xff, ptx->var + 2);
+
+    /* Interrupt the firmware to process the command */
+    if (interrupt_ecf(local, ccsindex)) {
+        DEBUG(1,"ray_cs send authentication request failed - ECF not ready for intr\n");
+        writeb(CCS_BUFFER_FREE, &(pccs++)->buffer_status);
+        return -1;
+    }
+    return 0;
+} /* End build_auth_frame */
+/*===========================================================================*/
Index: oldkernel/linux/pcmcia-cs-3.1.15/wireless/ray_cs.h
diff -u /dev/null linux/pcmcia-cs-3.1.15/wireless/ray_cs.h:1.1
--- /dev/null	Mon Jul 31 21:15:12 2000
+++ linux/pcmcia-cs-3.1.15/wireless/ray_cs.h	Fri Jul  7 16:34:59 2000
@@ -0,0 +1,79 @@
+/* Raytheon wireless LAN PCMCIA card driver for Linux 
+   A  PCMCIA client driver for the Raylink wireless network card
+   Written by Corey Thomas
+*/
+
+#ifndef RAYLINK_H
+
+struct beacon_rx {
+    struct mac_header mac;
+    UCHAR timestamp[8];
+    UCHAR beacon_intvl[2];
+    UCHAR capability[2];
+    UCHAR elements[sizeof(struct essid_element) 
+                  + sizeof(struct rates_element)
+                  + sizeof(struct freq_hop_element) 
+                  + sizeof(struct japan_call_sign_element)
+                  + sizeof(struct tim_element)];
+};
+
+/* Return values for get_free{,_tx}_ccs */
+#define ECCSFULL  (-1)
+#define ECCSBUSY  (-2)
+#define ECARDGONE (-3)
+
+typedef struct ray_dev_t {
+    int card_status;
+    int authentication_state;
+    dev_node_t  node;
+    window_handle_t amem_handle;   /* handle to window for attribute memory  */
+    window_handle_t rmem_handle;   /* handle to window for rx buffer on card */
+    UCHAR *sram;                   /* pointer to beginning of shared RAM     */
+    UCHAR *amem;                   /* pointer to attribute mem window        */
+    UCHAR *rmem;                   /* pointer to receive buffer window       */
+    dev_link_t *finder;            /* pointer back to dev_link_t for card    */
+    struct timer_list timer;
+    spinlock_t ray_lock;
+    int tx_ccs_lock;
+    int ccs_lock;
+    int   dl_param_ccs;
+    union {
+        struct b4_startup_params b4;
+        struct b5_startup_params b5;
+    } sparm;
+    int timeout_flag;
+    UCHAR supported_rates[8];
+    UCHAR japan_call_sign[12];
+    struct startup_res_6 startup_res;
+    int num_multi;
+    /* Network parameters from start/join */
+    UCHAR bss_id[6];
+    UCHAR auth_id[6];
+    UCHAR net_default_tx_rate;
+    UCHAR encryption;
+    struct enet_statistics stats;
+
+    UCHAR net_type;
+    UCHAR sta_type;
+    UCHAR fw_ver;
+    UCHAR fw_bld;
+    UCHAR fw_var;
+    UCHAR ASIC_version;
+    UCHAR assoc_id[2];
+    UCHAR tib_length;
+    UCHAR last_rsl;
+    int beacon_rxed;
+    struct beacon_rx last_bcn;
+#ifdef WIRELESS_EXT
+    iw_stats	wstats;		/* Wireless specific stats */
+#endif
+#ifdef WIRELESS_SPY
+    int		spy_number;		/* Number of addresses to spy */
+    mac_addr	spy_address[IW_MAX_SPY + 1];	/* The addresses to spy */
+    iw_qual	spy_stat[IW_MAX_SPY + 1];	/* Statistics gathered */
+#endif	/* WIRELESS_SPY */
+
+} ray_dev_t;
+/*****************************************************************************/
+
+#endif /* RAYLINK_H */
Index: oldkernel/linux/pcmcia-cs-3.1.15/wireless/rayctl.h
diff -u /dev/null linux/pcmcia-cs-3.1.15/wireless/rayctl.h:1.1
--- /dev/null	Mon Jul 31 21:15:12 2000
+++ linux/pcmcia-cs-3.1.15/wireless/rayctl.h	Fri Jul  7 16:34:59 2000
@@ -0,0 +1,732 @@
+#ifndef RAYLINK_H
+
+typedef unsigned char UCHAR;
+
+/****** IEEE 802.11 constants ************************************************/
+#define ADDRLEN           6
+/* Frame control 1 bit fields */
+#define PROTOCOL_VER      0x00
+#define DATA_TYPE         0x08
+#define ASSOC_REQ_TYPE    0x00
+#define ASSOC_RESP_TYPE   0x10
+#define REASSOC_REQ_TYPE  0x20
+#define REASSOC_RESP_TYPE 0x30
+#define NULL_MSG_TYPE     0x48
+#define BEACON_TYPE       0x80
+#define DISASSOC_TYPE     0xA0
+#define PSPOLL_TYPE       0xA4
+#define AUTHENTIC_TYPE    0xB0
+#define DEAUTHENTIC_TYPE  0xC0
+/* Frame control 2 bit fields */
+#define FC2_TO_DS         0x01
+#define FC2_FROM_DS       0x02
+#define FC2_MORE_FRAG     0x04
+#define FC2_RETRY         0x08
+#define FC2_PSM           0x10
+#define FC2_MORE_DATA     0x20
+#define FC2_WEP           0x40
+#define FC2_ORDER         0x80
+/*****************************************************************************/
+/* 802.11 element ID's and lengths */
+#define C_BP_CAPABILITY_ESS             0x01
+#define C_BP_CAPABILITY_IBSS            0x02
+#define C_BP_CAPABILITY_CF_POLLABLE     0x04
+#define C_BP_CAPABILITY_CF_POLL_REQUEST 0x08
+#define C_BP_CAPABILITY_PRIVACY         0x10
+
+#define C_ESSID_ELEMENT_ID               0
+#define C_ESSID_ELEMENT_MAX_LENGTH       32
+
+#define C_SUPPORTED_RATES_ELEMENT_ID     1
+#define C_SUPPORTED_RATES_ELEMENT_LENGTH 2
+
+#define C_FH_PARAM_SET_ELEMENT_ID        2
+#define C_FH_PARAM_SET_ELEMENT_LNGTH     5
+
+#define C_CF_PARAM_SET_ELEMENT_ID        4
+#define C_CF_PARAM_SET_ELEMENT_LNGTH     6
+
+#define C_TIM_ELEMENT_ID                 5
+#define C_TIM_BITMAP_LENGTH            251
+#define C_TIM_BMCAST_BIT              0x01
+
+#define C_IBSS_ELEMENT_ID                6
+#define C_IBSS_ELEMENT_LENGTH            2
+
+#define C_JAPAN_CALL_SIGN_ELEMENT_ID    51
+#define C_JAPAN_CALL_SIGN_ELEMENT_LNGTH 12
+
+#define C_DISASSOC_REASON_CODE_LEN       2
+#define C_DISASSOC_REASON_CODE_DEFAULT   8
+
+#define C_CRC_LEN                        4
+#define C_NUM_SUPPORTED_RATES            8 
+/****** IEEE 802.11 mac header for type data packets *************************/
+struct mac_header {
+  UCHAR frame_ctl_1;                          
+  UCHAR frame_ctl_2;
+  UCHAR duration_lsb;
+  UCHAR duration_msb;
+  UCHAR addr_1[ADDRLEN];
+  UCHAR addr_2[ADDRLEN];
+  UCHAR addr_3[ADDRLEN];
+  UCHAR seq_frag_num[2];
+/*  UCHAR addr_4[ADDRLEN]; *//* only present for AP to AP (TO DS and FROM DS */
+};
+/****** IEEE 802.11 frame element structures *********************************/
+struct essid_element
+{
+  UCHAR id;
+  UCHAR length;
+  UCHAR text[C_ESSID_ELEMENT_MAX_LENGTH];
+};
+struct rates_element
+{
+  UCHAR id;
+  UCHAR length;
+  UCHAR value[8];
+};
+struct freq_hop_element
+{
+  UCHAR id;
+  UCHAR length;
+  UCHAR dwell_time[2];
+  UCHAR hop_set;
+  UCHAR hop_pattern;
+  UCHAR hop_index;
+};
+struct tim_element
+{
+  UCHAR id;
+  UCHAR length;
+  UCHAR dtim_count;
+  UCHAR dtim_period;    
+  UCHAR bitmap_control;
+  UCHAR tim[C_TIM_BITMAP_LENGTH];
+};
+struct ibss_element
+{
+  UCHAR id;
+  UCHAR length;
+  UCHAR atim_window[2];
+};
+struct japan_call_sign_element
+{
+  UCHAR id;
+  UCHAR length;
+  UCHAR call_sign[12];
+};
+/****** Beacon message structures ********************************************/
+/* .elements is a large lump of max size because elements are variable size  */
+struct infra_beacon
+{
+    UCHAR timestamp[8];
+    UCHAR beacon_intvl[2];
+    UCHAR capability[2];
+    UCHAR elements[sizeof(struct essid_element) 
+                  + sizeof(struct rates_element)
+                  + sizeof(struct freq_hop_element) 
+                  + sizeof(struct japan_call_sign_element)
+                  + sizeof(struct tim_element)];
+};
+struct adhoc_beacon
+{
+    UCHAR timestamp[8];
+    UCHAR beacon_intvl[2];
+    UCHAR capability[2];
+    UCHAR elements[sizeof(struct essid_element) 
+                  + sizeof(struct rates_element)
+                  + sizeof(struct freq_hop_element) 
+                  + sizeof(struct japan_call_sign_element)
+                  + sizeof(struct ibss_element)];
+};
+/*****************************************************************************/
+/*****************************************************************************/
+/* #define C_MAC_HDR_2_WEP 0x40 */
+/* TX/RX CCS constants */
+#define TX_HEADER_LENGTH 0x1C
+#define RX_MAC_HEADER_LENGTH 0x18
+#define TX_AUTHENTICATE_LENGTH (TX_HEADER_LENGTH + 6)
+#define TX_AUTHENTICATE_LENGTH_MSB (TX_AUTHENTICATE_LENGTH >> 8)
+#define TX_AUTHENTICATE_LENGTH_LSB (TX_AUTHENTICATE_LENGTH & 0xff)
+#define TX_DEAUTHENTICATE_LENGTH (TX_HEADER_LENGTH + 2)
+#define TX_DEAUTHENTICATE_LENGTH_MSB (TX_AUTHENTICATE_LENGTH >> 8)
+#define TX_DEAUTHENTICATE_LENGTH_LSB (TX_AUTHENTICATE_LENGTH & 0xff)
+#define FCS_LEN           4
+
+#define ADHOC                 0
+#define INFRA                 1
+
+#define TYPE_STA              0
+#define TYPE_AP               1
+
+#define PASSIVE_SCAN          1
+#define ACTIVE_SCAN           1
+
+#define PSM_CAM               0
+
+/* Country codes */
+#define USA                   1
+#define EUROPE                2
+#define JAPAN                 3
+#define KOREA                 4
+#define SPAIN                 5
+#define FRANCE                6
+#define ISRAEL                7
+#define AUSTRALIA             8
+#define JAPAN_TEST            9
+
+/* Hop pattern lengths */
+#define USA_HOP_MOD          79 
+#define EUROPE_HOP_MOD       79 
+#define JAPAN_HOP_MOD        23
+#define KOREA_HOP_MOD        23
+#define SPAIN_HOP_MOD        27
+#define FRANCE_HOP_MOD       35
+#define ISRAEL_HOP_MOD       35
+#define AUSTRALIA_HOP_MOD    47
+#define JAPAN_TEST_HOP_MOD   23
+
+#define ESSID_SIZE           32
+/**********************************************************************/
+/* CIS Register Constants */
+#define CIS_OFFSET             0x0f00
+/* Configuration Option Register (0x0F00) */
+#define COR_OFFSET             0x00
+#define COR_SOFT_RESET         0x80
+#define COR_LEVEL_IRQ          0x40
+#define COR_CONFIG_NUM         0x01
+#define COR_DEFAULT            (COR_LEVEL_IRQ | COR_CONFIG_NUM)
+
+/* Card Configuration and Status Register (0x0F01) */
+#define CCSR_OFFSET            0x01
+#define CCSR_HOST_INTR_PENDING 0x01
+#define CCSR_POWER_DOWN        0x04
+
+/* HCS Interrupt Register (0x0F05) */
+#define HCS_INTR_OFFSET        0x05
+/* #define HCS_INTR_OFFSET        0x0A */
+#define HCS_INTR_CLEAR         0x00
+
+/* ECF Interrupt Register (0x0F06) */
+#define ECF_INTR_OFFSET        0x06
+/* #define ECF_INTR_OFFSET        0x0C */
+#define ECF_INTR_SET           0x01
+
+/* Authorization Register 0 (0x0F08) */
+#define AUTH_0_ON              0x57
+
+/* Authorization Register 1 (0x0F09) */
+#define AUTH_1_ON              0x82
+
+/* Program Mode Register (0x0F0A) */
+#define PC2PM                  0x02
+#define PC2CAL                 0x10
+#define PC2MLSE                0x20
+
+/* PC Test Mode Register (0x0F0B) */
+#define PC_TEST_MODE           0x08
+
+/* Frequency Control Word (0x0F10) */
+/* Range 0x02 - 0xA6 */
+
+/* Test Mode Control 1-4 (0x0F14 - 0x0F17) */
+
+/**********************************************************************/
+
+/* Shared RAM Area */
+#define SCB_BASE               0x0000
+#define STATUS_BASE            0x0100
+#define HOST_TO_ECF_BASE       0x0200
+#define ECF_TO_HOST_BASE       0x0300
+#define CCS_BASE               0x0400
+#define RCS_BASE               0x0800
+#define INFRA_TIM_BASE         0x0C00
+#define SSID_LIST_BASE         0x0D00
+#define TX_BUF_BASE            0x1000
+#define RX_BUF_BASE            0x8000
+
+#define NUMBER_OF_CCS    64
+#define NUMBER_OF_RCS    64
+/*#define NUMBER_OF_TX_CCS 14 */
+#define NUMBER_OF_TX_CCS 14
+
+#define TX_BUF_SIZE      (2048 - sizeof(struct tx_msg))
+#define RX_BUFF_END      0x3FFF
+/* Values for buffer_status */
+#define CCS_BUFFER_FREE       0
+#define CCS_BUFFER_BUSY       1
+#define CCS_COMMAND_COMPLETE  2
+#define CCS_COMMAND_FAILED    3
+
+/* Values for cmd */
+#define CCS_DOWNLOAD_STARTUP_PARAMS    1
+#define CCS_UPDATE_PARAMS              2
+#define CCS_REPORT_PARAMS              3
+#define CCS_UPDATE_MULTICAST_LIST      4
+#define CCS_UPDATE_POWER_SAVINGS_MODE  5
+#define CCS_START_NETWORK              6
+#define CCS_JOIN_NETWORK               7
+#define CCS_START_ASSOCIATION          8
+#define CCS_TX_REQUEST                 9
+#define CCS_TEST_MEMORY              0xa
+#define CCS_SHUTDOWN                 0xb
+#define CCS_DUMP_MEMORY              0xc
+#define CCS_START_TIMER              0xe
+#define CCS_LAST_CMD                 CCS_START_TIMER
+
+/* Values for link field */
+#define CCS_END_LIST                 0xff
+
+/* values for buffer_status field */
+#define RCS_BUFFER_FREE       0
+#define RCS_BUFFER_BUSY       1
+#define RCS_COMPLETE          2
+#define RCS_FAILED            3
+#define RCS_BUFFER_RELEASE    0xFF
+
+/* values for interrupt_id field */
+#define PROCESS_RX_PACKET           0x80 /* */
+#define REJOIN_NET_COMPLETE         0x81 /* RCS ID: Rejoin Net Complete */
+#define ROAMING_INITIATED           0x82 /* RCS ID: Roaming Initiated   */
+#define JAPAN_CALL_SIGN_RXD         0x83 /* RCS ID: New Japan Call Sign */
+
+/*****************************************************************************/
+/* Memory types for dump memory command */
+#define C_MEM_PROG  0
+#define C_MEM_XDATA 1
+#define C_MEM_SFR   2
+#define C_MEM_IDATA 3
+
+/*** Return values for hw_xmit **********/
+#define XMIT_OK        (0)
+#define XMIT_MSG_BAD   (-1)
+#define XMIT_NO_CCS    (-2)
+#define XMIT_NO_INTR   (-3)
+#define XMIT_NEED_AUTH (-4)
+
+/*** Values for card status */
+#define CARD_INSERTED       (0)
+
+#define CARD_AWAITING_PARAM (1)
+#define CARD_INIT_ERROR     (11)
+
+#define CARD_DL_PARAM       (2)
+#define CARD_DL_PARAM_ERROR (12)
+
+#define CARD_DOING_ACQ      (3)
+
+#define CARD_ACQ_COMPLETE   (4)
+#define CARD_ACQ_FAILED     (14)
+
+#define CARD_AUTH_COMPLETE  (5)
+#define CARD_AUTH_REFUSED   (15)
+
+#define CARD_ASSOC_COMPLETE (6)
+#define CARD_ASSOC_FAILED   (16)
+
+/*** Values for authentication_state ***********************************/
+#define UNAUTHENTICATED     (0)
+#define AWAITING_RESPONSE   (1)
+#define AUTHENTICATED       (2)
+#define NEED_TO_AUTH        (3)
+
+/*** Values for authentication type ************************************/
+#define OPEN_AUTH_REQUEST   (1)
+#define OPEN_AUTH_RESPONSE  (2)
+#define BROADCAST_DEAUTH    (0xc0)
+/*** Values for timer functions ****************************************/
+#define TODO_NOTHING              (0)
+#define TODO_VERIFY_DL_START      (-1)
+#define TODO_START_NET            (-2)
+#define TODO_JOIN_NET             (-3)
+#define TODO_AUTHENTICATE_TIMEOUT (-4)
+#define TODO_SEND_CCS             (-5)
+/***********************************************************************/
+/* Parameter passing structure for update/report parameter CCS's */
+struct object_id {
+    void          *object_addr;
+    unsigned char object_length;
+};
+
+#define OBJID_network_type            0
+#define OBJID_acting_as_ap_status     1
+#define OBJID_current_ess_id          2
+#define OBJID_scanning_mode           3
+#define OBJID_power_mgt_state         4
+#define OBJID_mac_address             5
+#define OBJID_frag_threshold          6
+#define OBJID_hop_time                7
+#define OBJID_beacon_period           8
+#define OBJID_dtim_period             9
+#define OBJID_retry_max              10
+#define OBJID_ack_timeout            11
+#define OBJID_sifs                   12
+#define OBJID_difs                   13
+#define OBJID_pifs                   14
+#define OBJID_rts_threshold          15
+#define OBJID_scan_dwell_time        16
+#define OBJID_max_scan_dwell_time    17
+#define OBJID_assoc_resp_timeout     18
+#define OBJID_adhoc_scan_cycle_max   19
+#define OBJID_infra_scan_cycle_max   20
+#define OBJID_infra_super_cycle_max  21
+#define OBJID_promiscuous_mode       22
+#define OBJID_unique_word            23
+#define OBJID_slot_time              24
+#define OBJID_roaming_low_snr        25
+#define OBJID_low_snr_count_thresh   26
+#define OBJID_infra_missed_bcn       27
+#define OBJID_adhoc_missed_bcn       28
+#define OBJID_curr_country_code      29
+#define OBJID_hop_pattern            30
+#define OBJID_reserved               31
+#define OBJID_cw_max_msb             32
+#define OBJID_cw_min_msb             33
+#define OBJID_noise_filter_gain      34
+#define OBJID_noise_limit_offset     35
+#define OBJID_det_rssi_thresh_offset 36
+#define OBJID_med_busy_thresh_offset 37
+#define OBJID_det_sync_thresh        38
+#define OBJID_test_mode              39
+#define OBJID_test_min_chan_num      40
+#define OBJID_test_max_chan_num      41
+#define OBJID_allow_bcast_ID_prbrsp  42
+#define OBJID_privacy_must_start     43
+#define OBJID_privacy_can_join       44
+#define OBJID_basic_rate_set         45
+
+/**** Configuration/Status/Control Area ***************************/
+/*    System Control Block (SCB) Area
+ *    Located at Shared RAM offset 0
+ */
+struct scb {
+    UCHAR ccs_index;
+    UCHAR rcs_index;
+};
+
+/****** Status area at Shared RAM offset 0x0100 ******************************/
+struct status {
+    UCHAR mrx_overflow_for_host;         /* 0=ECF may write, 1=host may write*/
+    UCHAR mrx_checksum_error_for_host;   /* 0=ECF may write, 1=host may write*/
+    UCHAR rx_hec_error_for_host;         /* 0=ECF may write, 1=host may write*/
+    UCHAR reserved1;
+    short mrx_overflow;                  /* ECF increments on rx overflow    */
+    short mrx_checksum_error;            /* ECF increments on rx CRC error   */
+    short rx_hec_error;                  /* ECF incs on mac header CRC error */
+    UCHAR rxnoise;                       /* Average RSL measurement          */
+};
+
+/****** Host-to-ECF Data Area at Shared RAM offset 0x200 *********************/
+struct host_to_ecf_area {
+    
+};
+
+/****** ECF-to-Host Data Area at Shared RAM offset 0x0300 ********************/
+struct startup_res_518 {
+    UCHAR startup_word;
+    UCHAR station_addr[ADDRLEN];
+    UCHAR calc_prog_chksum;
+    UCHAR calc_cis_chksum;
+    UCHAR ecf_spare[7];
+    UCHAR japan_call_sign[12];
+};
+
+struct startup_res_6 {
+    UCHAR startup_word;
+    UCHAR station_addr[ADDRLEN];
+    UCHAR reserved;
+    UCHAR supp_rates[8];
+    UCHAR japan_call_sign[12];
+    UCHAR calc_prog_chksum;
+    UCHAR calc_cis_chksum;
+    UCHAR firmware_version[3];
+    UCHAR asic_version;
+    UCHAR tib_length;
+};
+
+struct start_join_net_params {
+    UCHAR net_type;
+    UCHAR ssid[ESSID_SIZE];
+    UCHAR reserved;
+    UCHAR privacy_can_join;
+};
+
+/****** Command Control Structure area at Shared ram offset 0x0400 ***********/
+/* Structures for command specific parameters (ccs.var) */
+struct update_param_cmd {
+    UCHAR object_id;
+    UCHAR number_objects;
+    UCHAR failure_cause;
+};
+struct report_param_cmd {
+    UCHAR object_id;
+    UCHAR number_objects;
+    UCHAR failure_cause;
+    UCHAR length;
+};
+struct start_network_cmd {
+    UCHAR update_param;
+    UCHAR bssid[ADDRLEN];
+    UCHAR net_initiated;
+    UCHAR net_default_tx_rate;
+    UCHAR encryption;
+};
+struct join_network_cmd {
+    UCHAR update_param;
+    UCHAR bssid[ADDRLEN];
+    UCHAR net_initiated;
+    UCHAR net_default_tx_rate;
+    UCHAR encryption;
+};
+struct tx_requested_cmd {
+ 
+    UCHAR tx_data_ptr[2];
+    UCHAR tx_data_length[2];
+    UCHAR host_reserved[2];
+    UCHAR reserved[3];
+    UCHAR tx_rate;
+    UCHAR pow_sav_mode;
+    UCHAR retries;
+    UCHAR antenna;
+};
+struct tx_requested_cmd_4 {
+ 
+    UCHAR tx_data_ptr[2];
+    UCHAR tx_data_length[2];
+    UCHAR dest_addr[ADDRLEN];
+    UCHAR pow_sav_mode;
+    UCHAR retries;
+    UCHAR station_id;
+};
+struct memory_dump_cmd {
+    UCHAR memory_type;
+    UCHAR memory_ptr[2];
+    UCHAR length;
+};
+struct update_association_cmd {
+    UCHAR status;
+    UCHAR aid[2];
+};
+struct start_timer_cmd {
+    UCHAR duration[2];
+};
+
+struct ccs {
+    UCHAR buffer_status;                 /* 0 = buffer free, 1 = buffer busy */
+                                         /* 2 = command complete, 3 = failed */
+    UCHAR cmd;                           /* command to ECF                   */
+    UCHAR link;                          /* link to next CCS, FF=end of list */
+    /* command specific parameters      */
+    union {
+        char reserved[13];
+        struct update_param_cmd update_param;
+        struct report_param_cmd report_param;
+        UCHAR nummulticast;
+        UCHAR mode;
+        struct start_network_cmd start_network;
+        struct join_network_cmd join_network;
+        struct tx_requested_cmd tx_request;
+        struct memory_dump_cmd memory_dump;
+        struct update_association_cmd update_assoc;
+        struct start_timer_cmd start_timer;
+    } var;
+};
+
+/*****************************************************************************/
+/* Transmit buffer structures */
+struct tib_structure {
+    UCHAR ccs_index;
+    UCHAR psm;
+    UCHAR pass_fail;
+    UCHAR retry_count;
+    UCHAR max_retries;
+    UCHAR frags_remaining;
+    UCHAR no_rb;
+    UCHAR rts_reqd;
+    UCHAR csma_tx_cntrl_2;
+    UCHAR sifs_tx_cntrl_2;
+    UCHAR tx_dma_addr_1[2];
+    UCHAR tx_dma_addr_2[2];
+    UCHAR var_dur_2mhz[2];
+    UCHAR var_dur_1mhz[2];
+    UCHAR max_dur_2mhz[2];
+    UCHAR max_dur_1mhz[2];
+    UCHAR hdr_len;
+    UCHAR max_frag_len[2];
+    UCHAR var_len[2];
+    UCHAR phy_hdr_4;
+    UCHAR mac_hdr_1;
+    UCHAR mac_hdr_2;
+    UCHAR sid[2];
+};
+
+struct phy_header {
+    UCHAR sfd[2];
+    UCHAR hdr_3;
+    UCHAR hdr_4;
+};
+struct rx_msg {
+    struct mac_header mac;
+    UCHAR  var[1];
+};
+
+struct tx_msg {
+    struct tib_structure tib;
+    struct phy_header phy;
+    struct mac_header mac;
+    UCHAR  var[1];
+};
+
+/****** ECF Receive Control Stucture (RCS) Area at Shared RAM offset 0x0800  */
+/* Structures for command specific parameters (rcs.var) */
+struct rx_packet_cmd {
+    UCHAR rx_data_ptr[2];
+    UCHAR rx_data_length[2];
+    UCHAR rx_sig_lev;
+    UCHAR next_frag_rcs_index;
+    UCHAR totalpacketlength[2];
+};
+struct rejoin_net_cmplt_cmd {
+    UCHAR reserved;
+    UCHAR bssid[ADDRLEN];
+};
+struct japan_call_sign_rxd {
+    UCHAR rxd_call_sign[8];
+    UCHAR reserved[5];
+};
+
+struct rcs {
+    UCHAR buffer_status;
+    UCHAR interrupt_id;
+    UCHAR link_field;
+    /* command specific parameters      */
+    union {
+        UCHAR reserved[13]; 
+        struct rx_packet_cmd rx_packet;
+        struct rejoin_net_cmplt_cmd rejoin_net_complete;
+        struct japan_call_sign_rxd japan_call_sign;
+    } var;
+};
+
+/****** Startup parameter structures for both versions of firmware ***********/
+struct b4_startup_params {
+    UCHAR a_network_type;                /* C_ADHOC, C_INFRA                 */
+    UCHAR a_acting_as_ap_status;         /* C_TYPE_STA, C_TYPE_AP            */
+    UCHAR a_current_ess_id[ESSID_SIZE];  /* Null terminated unless 32 long   */
+    UCHAR a_scanning_mode;               /* passive 0, active 1              */
+    UCHAR a_power_mgt_state;             /* CAM 0,                           */
+    UCHAR a_mac_addr[ADDRLEN];           /*                                  */
+    UCHAR a_frag_threshold[2];           /* 512                              */
+    UCHAR a_hop_time[2];                 /* 16k * 2**n, n=0-4 in Kus         */
+    UCHAR a_beacon_period[2];            /* n * a_hop_time  in Kus           */
+    UCHAR a_dtim_period;                 /* in beacons                       */
+    UCHAR a_retry_max;                   /*                                  */
+    UCHAR a_ack_timeout;                 /*                                  */
+    UCHAR a_sifs;                        /*                                  */
+    UCHAR a_difs;                        /*                                  */
+    UCHAR a_pifs;                        /*                                  */
+    UCHAR a_rts_threshold[2];            /*                                  */
+    UCHAR a_scan_dwell_time[2];          /*                                  */
+    UCHAR a_max_scan_dwell_time[2];      /*                                  */
+    UCHAR a_assoc_resp_timeout_thresh;   /*                                  */
+    UCHAR a_adhoc_scan_cycle_max;        /*                                  */
+    UCHAR a_infra_scan_cycle_max;        /*                                  */
+    UCHAR a_infra_super_scan_cycle_max;  /*                                  */
+    UCHAR a_promiscuous_mode;            /*                                  */
+    UCHAR a_unique_word[2];              /*                                  */
+    UCHAR a_slot_time;                   /*                                  */
+    UCHAR a_roaming_low_snr_thresh;      /*                                  */
+    UCHAR a_low_snr_count_thresh;        /*                                  */
+    UCHAR a_infra_missed_bcn_thresh;     /*                                  */
+    UCHAR a_adhoc_missed_bcn_thresh;     /*                                  */
+    UCHAR a_curr_country_code;           /* C_USA                            */
+    UCHAR a_hop_pattern;                 /*                                  */
+    UCHAR a_hop_pattern_length;          /*                                  */
+/* b4 - b5 differences start here */
+    UCHAR a_cw_max;                      /*                                  */
+    UCHAR a_cw_min;                      /*                                  */
+    UCHAR a_noise_filter_gain;           /*                                  */
+    UCHAR a_noise_limit_offset;          /*                                  */
+    UCHAR a_det_rssi_thresh_offset;      /*                                  */
+    UCHAR a_med_busy_thresh_offset;      /*                                  */
+    UCHAR a_det_sync_thresh;             /*                                  */
+    UCHAR a_test_mode;                   /*                                  */
+    UCHAR a_test_min_chan_num;           /*                                  */
+    UCHAR a_test_max_chan_num;           /*                                  */
+    UCHAR a_rx_tx_delay;                 /*                                  */
+    UCHAR a_current_bss_id[ADDRLEN];     /*                                  */
+    UCHAR a_hop_set;                     /*                                  */
+};
+struct b5_startup_params {
+    UCHAR a_network_type;                /* C_ADHOC, C_INFRA                 */
+    UCHAR a_acting_as_ap_status;         /* C_TYPE_STA, C_TYPE_AP            */
+    UCHAR a_current_ess_id[ESSID_SIZE];  /* Null terminated unless 32 long   */
+    UCHAR a_scanning_mode;               /* passive 0, active 1              */
+    UCHAR a_power_mgt_state;             /* CAM 0,                           */
+    UCHAR a_mac_addr[ADDRLEN];           /*                                  */
+    UCHAR a_frag_threshold[2];           /* 512                              */
+    UCHAR a_hop_time[2];                 /* 16k * 2**n, n=0-4 in Kus         */
+    UCHAR a_beacon_period[2];            /* n * a_hop_time  in Kus           */
+    UCHAR a_dtim_period;                 /* in beacons                       */
+    UCHAR a_retry_max;                   /* 4                                */
+    UCHAR a_ack_timeout;                 /*                                  */
+    UCHAR a_sifs;                        /*                                  */
+    UCHAR a_difs;                        /*                                  */
+    UCHAR a_pifs;                        /*                                  */
+    UCHAR a_rts_threshold[2];            /*                                  */
+    UCHAR a_scan_dwell_time[2];          /*                                  */
+    UCHAR a_max_scan_dwell_time[2];      /*                                  */
+    UCHAR a_assoc_resp_timeout_thresh;   /*                                  */
+    UCHAR a_adhoc_scan_cycle_max;        /*                                  */
+    UCHAR a_infra_scan_cycle_max;        /*                                  */
+    UCHAR a_infra_super_scan_cycle_max;  /*                                  */
+    UCHAR a_promiscuous_mode;            /*                                  */
+    UCHAR a_unique_word[2];              /*                                  */
+    UCHAR a_slot_time;                   /*                                  */
+    UCHAR a_roaming_low_snr_thresh;      /*                                  */
+    UCHAR a_low_snr_count_thresh;        /*                                  */
+    UCHAR a_infra_missed_bcn_thresh;     /*                                  */
+    UCHAR a_adhoc_missed_bcn_thresh;     /*                                  */
+    UCHAR a_curr_country_code;           /* C_USA                            */
+    UCHAR a_hop_pattern;                 /*                                  */
+    UCHAR a_hop_pattern_length;          /*                                  */
+/* b4 - b5 differences start here */
+    UCHAR a_cw_max[2];                   /*                                  */
+    UCHAR a_cw_min[2];                   /*                                  */
+    UCHAR a_noise_filter_gain;           /*                                  */
+    UCHAR a_noise_limit_offset;          /*                                  */
+    UCHAR a_det_rssi_thresh_offset;      /*                                  */
+    UCHAR a_med_busy_thresh_offset;      /*                                  */
+    UCHAR a_det_sync_thresh;             /*                                  */
+    UCHAR a_test_mode;                   /*                                  */
+    UCHAR a_test_min_chan_num;           /*                                  */
+    UCHAR a_test_max_chan_num;           /*                                  */
+    UCHAR a_allow_bcast_SSID_probe_rsp;
+    UCHAR a_privacy_must_start;
+    UCHAR a_privacy_can_join;
+    UCHAR a_basic_rate_set[8];
+};
+
+/*****************************************************************************/
+#define RAY_IOCG_PARMS (SIOCDEVPRIVATE)
+#define RAY_IOCS_PARMS (SIOCDEVPRIVATE + 1)
+#define RAY_DO_CMD     (SIOCDEVPRIVATE + 2)
+
+/****** ethernet <-> 802.11 translation **************************************/
+typedef struct snaphdr_t
+{
+  UCHAR   dsap;
+  UCHAR   ssap;
+  UCHAR   ctrl;
+  UCHAR   org[3];
+  UCHAR   ethertype[2];
+} snaphdr_t;
+
+#define BRIDGE_ENCAP  0xf80000
+#define RFC1042_ENCAP 0
+#define SNAP_ID       0x0003aaaa
+#define RAY_IPX_TYPE  0x8137
+#define APPLEARP_TYPE 0x80f3
+/*****************************************************************************/
+#endif /* #ifndef RAYLINK_H */
Index: oldkernel/linux/pcmcia-cs-3.1.15/wireless/wavelan.h
diff -u /dev/null linux/pcmcia-cs-3.1.15/wireless/wavelan.h:1.1
--- /dev/null	Mon Jul 31 21:15:12 2000
+++ linux/pcmcia-cs-3.1.15/wireless/wavelan.h	Fri Jul  7 16:34:59 2000
@@ -0,0 +1,386 @@
+/*
+ *	Wavelan Pcmcia driver
+ *
+ *		Jean II - HPLB '96
+ *
+ * Reorganization and extension of the driver.
+ * Original copyright follow. See wavelan_cs.h for details.
+ *
+ * This file contain the declarations of the Wavelan hardware. Note that
+ * the Pcmcia Wavelan include a i82593 controler (see definitions in
+ * file i82593.h).
+ *
+ * The main difference between the pcmcia hardware and the ISA one is
+ * the Ethernet Controler (i82593 instead of i82586). The i82593 allow
+ * only one send buffer. The PSA (Parameter Storage Area : EEprom for
+ * permanent storage of various info) is memory mapped, but not the
+ * MMI (Modem Management Interface).
+ */
+
+/*
+ * Definitions for the AT&T GIS (formerly NCR) WaveLAN PCMCIA card: 
+ *   An Ethernet-like radio transceiver controlled by an Intel 82593
+ *   coprocessor.
+ *
+ *
+ ****************************************************************************
+ *   Copyright 1995
+ *   Anthony D. Joseph
+ *   Massachusetts Institute of Technology
+ *
+ *   Permission to use, copy, modify, and distribute this program
+ *   for any purpose and without fee is hereby granted, provided
+ *   that this copyright and permission notice appear on all copies
+ *   and supporting documentation, the name of M.I.T. not be used
+ *   in advertising or publicity pertaining to distribution of the
+ *   program without specific prior permission, and notice be given
+ *   in supporting documentation that copying and distribution is
+ *   by permission of M.I.T.  M.I.T. makes no representations about
+ *   the suitability of this software for any purpose.  It is pro-
+ *   vided "as is" without express or implied warranty.         
+ ****************************************************************************
+ *
+ *
+ * Credits:
+ *     Special thanks to Jan Hoogendoorn of AT&T GIS Utrecht for
+ *       providing extremely useful information about WaveLAN PCMCIA hardware
+ *
+ *     This driver is based upon several other drivers, in particular:
+ *       David Hinds' Linux driver for the PCMCIA 3c589 ethernet adapter
+ *       Bruce Janson's Linux driver for the AT-bus WaveLAN adapter
+ *	 Anders Klemets' PCMCIA WaveLAN adapter driver
+ *       Robert Morris' BSDI driver for the PCMCIA WaveLAN adapter
+ */
+
+#ifndef _WAVELAN_H
+#define	_WAVELAN_H
+
+/************************** MAGIC NUMBERS ***************************/
+
+/* The detection of the wavelan card is made by reading the MAC address
+ * from the card and checking it. If you have a non AT&T product (OEM,
+ * like DEC RoamAbout, or Digital Ocean, Epson, ...), you must modify this
+ * part to accomodate your hardware...
+ */
+const unsigned char	MAC_ADDRESSES[][3] =
+{
+  { 0x08, 0x00, 0x0E },		/* AT&T Wavelan (standard) & DEC RoamAbout */
+  { 0x08, 0x00, 0x6A },		/* AT&T Wavelan (alternate) */
+  { 0x00, 0x00, 0xE1 },		/* Hitachi Wavelan */
+  { 0x00, 0x60, 0x1D }		/* Lucent Wavelan (another one) */
+  /* Add your card here and send me the patch ! */
+};
+
+/*
+ * Constants used to convert channels to frequencies
+ */
+
+/* Frequency available in the 2.0 modem, in units of 250 kHz
+ * (as read in the offset register of the dac area).
+ * Used to map channel numbers used by `wfreqsel' to frequencies
+ */
+const short	channel_bands[] = { 0x30, 0x58, 0x64, 0x7A, 0x80, 0xA8,
+				    0xD0, 0xF0, 0xF8, 0x150 };
+
+/* Frequencies of the 1.0 modem (fixed frequencies).
+ * Use to map the PSA `subband' to a frequency
+ * Note : all frequencies apart from the first one need to be multiplied by 10
+ */
+const int	fixed_bands[] = { 915e6, 2.425e8, 2.46e8, 2.484e8, 2.4305e8 };
+
+
+/*************************** PC INTERFACE ****************************/
+
+/* WaveLAN host interface definitions */
+
+#define	LCCR(base)	(base)		/* LAN Controller Command Register */
+#define	LCSR(base)	(base)		/* LAN Controller Status Register */
+#define	HACR(base)	(base+0x1)	/* Host Adapter Command Register */
+#define	HASR(base)	(base+0x1)	/* Host Adapter Status Register */
+#define PIORL(base)	(base+0x2)	/* Program I/O Register Low */
+#define RPLL(base)	(base+0x2)	/* Receive Pointer Latched Low */
+#define PIORH(base)	(base+0x3)	/* Program I/O Register High */
+#define RPLH(base)	(base+0x3)	/* Receive Pointer Latched High */
+#define PIOP(base)	(base+0x4)	/* Program I/O Port */
+#define MMR(base)	(base+0x6)	/* MMI Address Register */
+#define MMD(base)	(base+0x7)	/* MMI Data Register */
+
+/* Host Adaptor Command Register bit definitions */
+
+#define HACR_LOF	  (1 << 3)	/* Lock Out Flag, toggle every 250ms */
+#define HACR_PWR_STAT	  (1 << 4)	/* Power State, 1=active, 0=sleep */
+#define HACR_TX_DMA_RESET (1 << 5)	/* Reset transmit DMA ptr on high */
+#define HACR_RX_DMA_RESET (1 << 6)	/* Reset receive DMA ptr on high */
+#define HACR_ROM_WEN	  (1 << 7)	/* EEPROM write enabled when true */
+
+#define HACR_RESET              (HACR_TX_DMA_RESET | HACR_RX_DMA_RESET)
+#define	HACR_DEFAULT		(HACR_PWR_STAT)
+
+/* Host Adapter Status Register bit definitions */
+
+#define HASR_MMI_BUSY	(1 << 2)	/* MMI is busy when true */
+#define HASR_LOF	(1 << 3)	/* Lock out flag status */
+#define HASR_NO_CLK	(1 << 4)	/* active when modem not connected */
+
+/* Miscellaneous bit definitions */
+
+#define PIORH_SEL_TX	(1 << 5)	/* PIOR points to 0=rx/1=tx buffer */
+#define MMR_MMI_WR	(1 << 0)	/* Next MMI cycle is 0=read, 1=write */
+#define PIORH_MASK	0x1f		/* only low 5 bits are significant */
+#define RPLH_MASK	0x1f		/* only low 5 bits are significant */
+#define MMI_ADDR_MASK	0x7e		/* Bits 1-6 of MMR are significant */
+
+/* Attribute Memory map */
+
+#define CIS_ADDR	0x0000		/* Card Information Status Register */
+#define PSA_ADDR	0x0e00		/* Parameter Storage Area address */
+#define EEPROM_ADDR	0x1000		/* EEPROM address (unused ?) */
+#define COR_ADDR	0x4000		/* Configuration Option Register */
+
+/* Configuration Option Register bit definitions */
+
+#define COR_CONFIG	(1 << 0)	/* Config Index, 0 when unconfigured */
+#define COR_SW_RESET	(1 << 7)	/* Software Reset on true */
+#define COR_LEVEL_IRQ	(1 << 6)	/* Level IRQ */
+
+/* Local Memory map */
+
+#define RX_BASE		0x0000		/* Receive memory, 8 kB */
+#define TX_BASE		0x2000		/* Transmit memory, 2 kB */
+#define UNUSED_BASE	0x2800		/* Unused, 22 kB */
+#define RX_SIZE		(TX_BASE-RX_BASE)	/* Size of receive area */
+#define RX_SIZE_SHIFT	6		/* Bits to shift in stop register */
+
+#define TRUE  1
+#define FALSE 0
+
+#define MOD_ENAL 1
+#define MOD_PROM 2
+
+/* Size of a MAC address */
+#define WAVELAN_ADDR_SIZE	6
+
+/* Maximum size of Wavelan packet */
+#define WAVELAN_MTU	1500
+
+#define	MAXDATAZ		(6 + 6 + 2 + WAVELAN_MTU)
+
+/********************** PARAMETER STORAGE AREA **********************/
+
+/*
+ * Parameter Storage Area (PSA).
+ */
+typedef struct psa_t	psa_t;
+struct psa_t
+{
+  /* For the PCMCIA Adapter, locations 0x00-0x0F are unused and fixed at 00 */
+  unsigned char	psa_io_base_addr_1;	/* [0x00] Base address 1 ??? */
+  unsigned char	psa_io_base_addr_2;	/* [0x01] Base address 2 */
+  unsigned char	psa_io_base_addr_3;	/* [0x02] Base address 3 */
+  unsigned char	psa_io_base_addr_4;	/* [0x03] Base address 4 */
+  unsigned char	psa_rem_boot_addr_1;	/* [0x04] Remote Boot Address 1 */
+  unsigned char	psa_rem_boot_addr_2;	/* [0x05] Remote Boot Address 2 */
+  unsigned char	psa_rem_boot_addr_3;	/* [0x06] Remote Boot Address 3 */
+  unsigned char	psa_holi_params;	/* [0x07] HOst Lan Interface (HOLI) Parameters */
+  unsigned char	psa_int_req_no;		/* [0x08] Interrupt Request Line */
+  unsigned char	psa_unused0[7];		/* [0x09-0x0F] unused */
+
+  unsigned char	psa_univ_mac_addr[WAVELAN_ADDR_SIZE];	/* [0x10-0x15] Universal (factory) MAC Address */
+  unsigned char	psa_local_mac_addr[WAVELAN_ADDR_SIZE];	/* [0x16-1B] Local MAC Address */
+  unsigned char	psa_univ_local_sel;	/* [0x1C] Universal Local Selection */
+#define		PSA_UNIVERSAL	0		/* Universal (factory) */
+#define		PSA_LOCAL	1		/* Local */
+  unsigned char	psa_comp_number;	/* [0x1D] Compatability Number: */
+#define		PSA_COMP_PC_AT_915	0 	/* PC-AT 915 MHz	*/
+#define		PSA_COMP_PC_MC_915	1 	/* PC-MC 915 MHz	*/
+#define		PSA_COMP_PC_AT_2400	2 	/* PC-AT 2.4 GHz	*/
+#define		PSA_COMP_PC_MC_2400	3 	/* PC-MC 2.4 GHz	*/
+#define		PSA_COMP_PCMCIA_915	4 	/* PCMCIA 915 MHz or 2.0 */
+  unsigned char	psa_thr_pre_set;	/* [0x1E] Modem Threshold Preset */
+  unsigned char	psa_feature_select;	/* [0x1F] Call code required (1=on) */
+#define		PSA_FEATURE_CALL_CODE	0x01 	/* Call code required (Japan) */
+  unsigned char	psa_subband;		/* [0x20] Subband	*/
+#define		PSA_SUBBAND_915		0	/* 915 MHz or 2.0 */
+#define		PSA_SUBBAND_2425	1	/* 2425 MHz	*/
+#define		PSA_SUBBAND_2460	2	/* 2460 MHz	*/
+#define		PSA_SUBBAND_2484	3	/* 2484 MHz	*/
+#define		PSA_SUBBAND_2430_5	4	/* 2430.5 MHz	*/
+  unsigned char	psa_quality_thr;	/* [0x21] Modem Quality Threshold */
+  unsigned char	psa_mod_delay;		/* [0x22] Modem Delay ??? (reserved) */
+  unsigned char	psa_nwid[2];		/* [0x23-0x24] Network ID */
+  unsigned char	psa_nwid_select;	/* [0x25] Network ID Select On Off */
+  unsigned char	psa_encryption_select;	/* [0x26] Encryption On Off */
+  unsigned char	psa_encryption_key[8];	/* [0x27-0x2E] Encryption Key */
+  unsigned char	psa_databus_width;	/* [0x2F] AT bus width select 8/16 */
+  unsigned char	psa_call_code[8];	/* [0x30-0x37] (Japan) Call Code */
+  unsigned char	psa_nwid_prefix[2];	/* [0x38-0x39] Roaming domain */
+  unsigned char	psa_reserved[2];	/* [0x3A-0x3B] Reserved - fixed 00 */
+  unsigned char	psa_conf_status;	/* [0x3C] Conf Status, bit 0=1:config*/
+  unsigned char	psa_crc[2];		/* [0x3D] CRC-16 over PSA */
+  unsigned char	psa_crc_status;		/* [0x3F] CRC Valid Flag */
+};
+
+/* Size for structure checking (if padding is correct) */
+#define	PSA_SIZE	64
+
+/* Calculate offset of a field in the above structure
+ * Warning : only even addresses are used */
+#define	psaoff(p,f) 	((unsigned short) ((void *)(&((psa_t *) ((void *) NULL + (p)))->f) - (void *) NULL))
+
+/******************** MODEM MANAGEMENT INTERFACE ********************/
+
+/*
+ * Modem Management Controller (MMC) write structure.
+ */
+typedef struct mmw_t	mmw_t;
+struct mmw_t
+{
+  unsigned char	mmw_encr_key[8];	/* encryption key */
+  unsigned char	mmw_encr_enable;	/* enable/disable encryption */
+#define	MMW_ENCR_ENABLE_MODE	0x02	/* Mode of security option */
+#define	MMW_ENCR_ENABLE_EN	0x01	/* Enable security option */
+  unsigned char	mmw_unused0[1];		/* unused */
+  unsigned char	mmw_des_io_invert;	/* Encryption option */
+#define	MMW_DES_IO_INVERT_RES	0x0F	/* Reserved */
+#define	MMW_DES_IO_INVERT_CTRL	0xF0	/* Control ??? (set to 0) */
+  unsigned char	mmw_unused1[5];		/* unused */
+  unsigned char	mmw_loopt_sel;		/* looptest selection */
+#define	MMW_LOOPT_SEL_DIS_NWID	0x40	/* disable NWID filtering */
+#define	MMW_LOOPT_SEL_INT	0x20	/* activate Attention Request */
+#define	MMW_LOOPT_SEL_LS	0x10	/* looptest w/o collision avoidance */
+#define MMW_LOOPT_SEL_LT3A	0x08	/* looptest 3a */
+#define	MMW_LOOPT_SEL_LT3B	0x04	/* looptest 3b */
+#define	MMW_LOOPT_SEL_LT3C	0x02	/* looptest 3c */
+#define	MMW_LOOPT_SEL_LT3D	0x01	/* looptest 3d */
+  unsigned char	mmw_jabber_enable;	/* jabber timer enable */
+  /* Abort transmissions > 200 ms */
+  unsigned char	mmw_freeze;		/* freeze / unfreeeze signal level */
+  /* 0 : signal level & qual updated for every new message, 1 : frozen */
+  unsigned char	mmw_anten_sel;		/* antenna selection */
+#define MMW_ANTEN_SEL_SEL	0x01	/* direct antenna selection */
+#define	MMW_ANTEN_SEL_ALG_EN	0x02	/* antenna selection algo. enable */
+  unsigned char	mmw_ifs;		/* inter frame spacing */
+  /* min time between transmission in bit periods (.5 us) - bit 0 ignored */
+  unsigned char	mmw_mod_delay;	 	/* modem delay (synchro) */
+  unsigned char	mmw_jam_time;		/* jamming time (after collision) */
+  unsigned char	mmw_unused2[1];		/* unused */
+  unsigned char	mmw_thr_pre_set;	/* level threshold preset */
+  /* Discard all packet with signal < this value (4) */
+  unsigned char	mmw_decay_prm;		/* decay parameters */
+  unsigned char	mmw_decay_updat_prm;	/* decay update parameterz */
+  unsigned char	mmw_quality_thr;	/* quality (z-quotient) threshold */
+  /* Discard all packet with quality < this value (3) */
+  unsigned char	mmw_netw_id_l;		/* NWID low order byte */
+  unsigned char	mmw_netw_id_h;		/* NWID high order byte */
+  /* Network ID or Domain : create virtual net on the air */
+
+  /* 2.0 Hardware extension - frequency selection support */
+  unsigned char	mmw_mode_select;	/* for analog tests (set to 0) */
+  unsigned char	mmw_unused3[1];		/* unused */
+  unsigned char	mmw_fee_ctrl;		/* frequency eeprom control */
+#define	MMW_FEE_CTRL_PRE	0x10	/* Enable protected instructions */
+#define	MMW_FEE_CTRL_DWLD	0x08	/* Download eeprom to mmc */
+#define	MMW_FEE_CTRL_CMD	0x07	/* EEprom commands : */
+#define	MMW_FEE_CTRL_READ	0x06	/* Read */
+#define	MMW_FEE_CTRL_WREN	0x04	/* Write enable */
+#define	MMW_FEE_CTRL_WRITE	0x05	/* Write data to address */
+#define	MMW_FEE_CTRL_WRALL	0x04	/* Write data to all addresses */
+#define	MMW_FEE_CTRL_WDS	0x04	/* Write disable */
+#define	MMW_FEE_CTRL_PRREAD	0x16	/* Read addr from protect register */
+#define	MMW_FEE_CTRL_PREN	0x14	/* Protect register enable */
+#define	MMW_FEE_CTRL_PRCLEAR	0x17	/* Unprotect all registers */
+#define	MMW_FEE_CTRL_PRWRITE	0x15	/* Write addr in protect register */
+#define	MMW_FEE_CTRL_PRDS	0x14	/* Protect register disable */
+  /* Never issue this command (PRDS) : it's irreversible !!! */
+
+  unsigned char	mmw_fee_addr;		/* EEprom address */
+#define	MMW_FEE_ADDR_CHANNEL	0xF0	/* Select the channel */
+#define	MMW_FEE_ADDR_OFFSET	0x0F	/* Offset in channel data */
+#define	MMW_FEE_ADDR_EN		0xC0	/* FEE_CTRL enable operations */
+#define	MMW_FEE_ADDR_DS		0x00	/* FEE_CTRL disable operations */
+#define	MMW_FEE_ADDR_ALL	0x40	/* FEE_CTRL all operations */
+#define	MMW_FEE_ADDR_CLEAR	0xFF	/* FEE_CTRL clear operations */
+
+  unsigned char	mmw_fee_data_l;		/* Write data to EEprom */
+  unsigned char	mmw_fee_data_h;		/* high octet */
+  unsigned char	mmw_ext_ant;		/* Setting for external antenna */
+#define	MMW_EXT_ANT_EXTANT	0x01	/* Select external antenna */
+#define	MMW_EXT_ANT_POL		0x02	/* Polarity of the antenna */
+#define	MMW_EXT_ANT_INTERNAL	0x00	/* Internal antenna */
+#define	MMW_EXT_ANT_EXTERNAL	0x03	/* External antenna */
+#define	MMW_EXT_ANT_IQ_TEST	0x1C	/* IQ test pattern (set to 0) */
+};
+
+/* Size for structure checking (if padding is correct) */
+#define	MMW_SIZE	37
+
+/* Calculate offset of a field in the above structure */
+#define	mmwoff(p,f) 	(unsigned short)((void *)(&((mmw_t *)((void *)0 + (p)))->f) - (void *)0)
+
+
+/*
+ * Modem Management Controller (MMC) read structure.
+ */
+typedef struct mmr_t	mmr_t;
+struct mmr_t
+{
+  unsigned char	mmr_unused0[8];		/* unused */
+  unsigned char	mmr_des_status;		/* encryption status */
+  unsigned char	mmr_des_avail;		/* encryption available (0x55 read) */
+#define	MMR_DES_AVAIL_DES	0x55		/* DES available */
+#define	MMR_DES_AVAIL_AES	0x33		/* AES (AT&T) available */
+  unsigned char	mmr_des_io_invert;	/* des I/O invert register */
+  unsigned char	mmr_unused1[5];		/* unused */
+  unsigned char	mmr_dce_status;		/* DCE status */
+#define	MMR_DCE_STATUS_RX_BUSY		0x01	/* receiver busy */
+#define	MMR_DCE_STATUS_LOOPT_IND	0x02	/* loop test indicated */
+#define	MMR_DCE_STATUS_TX_BUSY		0x04	/* transmitter on */
+#define	MMR_DCE_STATUS_JBR_EXPIRED	0x08	/* jabber timer expired */
+#define MMR_DCE_STATUS			0x0F	/* mask to get the bits */
+  unsigned char	mmr_dsp_id;		/* DSP id (AA = Daedalus rev A) */
+  unsigned char	mmr_unused2[2];		/* unused */
+  unsigned char	mmr_correct_nwid_l;	/* # of correct NWID's rxd (low) */
+  unsigned char	mmr_correct_nwid_h;	/* # of correct NWID's rxd (high) */
+  /* Warning : Read high order octet first !!! */
+  unsigned char	mmr_wrong_nwid_l;	/* # of wrong NWID's rxd (low) */
+  unsigned char	mmr_wrong_nwid_h;	/* # of wrong NWID's rxd (high) */
+  unsigned char	mmr_thr_pre_set;	/* level threshold preset */
+#define	MMR_THR_PRE_SET		0x3F		/* level threshold preset */
+#define	MMR_THR_PRE_SET_CUR	0x80		/* Current signal above it */
+  unsigned char	mmr_signal_lvl;		/* signal level */
+#define	MMR_SIGNAL_LVL		0x3F		/* signal level */
+#define	MMR_SIGNAL_LVL_VALID	0x80		/* Updated since last read */
+  unsigned char	mmr_silence_lvl;	/* silence level (noise) */
+#define	MMR_SILENCE_LVL		0x3F		/* silence level */
+#define	MMR_SILENCE_LVL_VALID	0x80		/* Updated since last read */
+  unsigned char	mmr_sgnl_qual;		/* signal quality */
+#define	MMR_SGNL_QUAL		0x0F		/* signal quality */
+#define	MMR_SGNL_QUAL_ANT	0x80		/* current antenna used */
+  unsigned char	mmr_netw_id_l;		/* NWID low order byte ??? */
+  unsigned char	mmr_unused3[3];		/* unused */
+
+  /* 2.0 Hardware extension - frequency selection support */
+  unsigned char	mmr_fee_status;		/* Status of frequency eeprom */
+#define	MMR_FEE_STATUS_ID	0xF0		/* Modem revision id */
+#define	MMR_FEE_STATUS_DWLD	0x08		/* Download in progress */
+#define	MMR_FEE_STATUS_BUSY	0x04		/* EEprom busy */
+  unsigned char	mmr_unused4[1];		/* unused */
+  unsigned char	mmr_fee_data_l;		/* Read data from eeprom (low) */
+  unsigned char	mmr_fee_data_h;		/* Read data from eeprom (high) */
+};
+
+/* Size for structure checking (if padding is correct) */
+#define	MMR_SIZE	36
+
+/* Calculate offset of a field in the above structure */
+#define	mmroff(p,f) 	(unsigned short)((void *)(&((mmr_t *)((void *)0 + (p)))->f) - (void *)0)
+
+
+/* Make the two above structures one */
+typedef union mm_t
+{
+  struct mmw_t	w;	/* Write to the mmc */
+  struct mmr_t	r;	/* Read from the mmc */
+} mm_t;
+
+#endif /* _WAVELAN_H */
Index: oldkernel/linux/pcmcia-cs-3.1.15/wireless/wavelan_cs.c
diff -u /dev/null linux/pcmcia-cs-3.1.15/wireless/wavelan_cs.c:1.1
--- /dev/null	Mon Jul 31 21:15:12 2000
+++ linux/pcmcia-cs-3.1.15/wireless/wavelan_cs.c	Fri Jul  7 16:34:59 2000
@@ -0,0 +1,4865 @@
+/*
+ *	Wavelan Pcmcia driver
+ *
+ *		Jean II - HPLB '96
+ *
+ * Reorganisation and extension of the driver.
+ * Original copyright follow. See wavelan_cs.h for details.
+ *
+ * This code is derived from Anthony D. Joseph's code and all the changes here
+ * are also under the original copyright below.
+ *
+ * This code supports version 2.00 of WaveLAN/PCMCIA cards (2.4GHz), and
+ * can work on Linux 2.0.36 with support of David Hinds' PCMCIA Card Services
+ *
+ * Joe Finney (joe@comp.lancs.ac.uk) at Lancaster University in UK added
+ * critical code in the routine to initialize the Modem Management Controller.
+ *
+ * Thanks to Alan Cox and Bruce Janson for their advice.
+ *
+ *	-- Yunzhou Li (scip4166@nus.sg)
+ *
+#ifdef WAVELAN_ROAMING	
+ * Roaming support added 07/22/98 by Justin Seger (jseger@media.mit.edu)
+ * based on patch by Joe Finney from Lancaster University.
+#endif :-)
+ *
+ * Lucent (formerly AT&T GIS, formerly NCR) WaveLAN PCMCIA card: An
+ * Ethernet-like radio transceiver controlled by an Intel 82593 coprocessor.
+ *
+ *   A non-shared memory PCMCIA ethernet driver for linux
+ *
+ * ISA version modified to support PCMCIA by Anthony Joseph (adj@lcs.mit.edu)
+ *
+ *
+ * Joseph O'Sullivan & John Langford (josullvn@cs.cmu.edu & jcl@cs.cmu.edu)
+ *
+ * Apr 2 '98  made changes to bring the i82593 control/int handling in line
+ *             with offical specs...
+ *
+ ****************************************************************************
+ *   Copyright 1995
+ *   Anthony D. Joseph
+ *   Massachusetts Institute of Technology
+ *
+ *   Permission to use, copy, modify, and distribute this program
+ *   for any purpose and without fee is hereby granted, provided
+ *   that this copyright and permission notice appear on all copies
+ *   and supporting documentation, the name of M.I.T. not be used
+ *   in advertising or publicity pertaining to distribution of the
+ *   program without specific prior permission, and notice be given
+ *   in supporting documentation that copying and distribution is
+ *   by permission of M.I.T.  M.I.T. makes no representations about
+ *   the suitability of this software for any purpose.  It is pro-
+ *   vided "as is" without express or implied warranty.         
+ ****************************************************************************
+ *
+ */
+
+#include "wavelan_cs.h"		/* Private header */
+
+/************************* MISC SUBROUTINES **************************/
+/*
+ * Subroutines which won't fit in one of the following category
+ * (wavelan modem or i82593)
+ */
+
+/*------------------------------------------------------------------*/
+/*
+ * Wrapper for disabling interrupts.
+ * (note : inline, so optimised away)
+ */
+static inline void
+wv_splhi(net_local *		lp,
+	 unsigned long *	pflags)
+{
+  spin_lock_irqsave(&lp->spinlock, *pflags);
+  /* Note : above does the cli(); itself */
+}
+
+/*------------------------------------------------------------------*/
+/*
+ * Wrapper for re-enabling interrupts.
+ */
+static inline void
+wv_splx(net_local *		lp,
+	unsigned long *		pflags)
+{
+  spin_unlock_irqrestore(&lp->spinlock, *pflags);
+
+  /* Note : enabling interrupts on the hardware is done in wv_ru_start()
+   * via : outb(OP1_INT_ENABLE, LCCR(base));
+   */
+}
+
+/*------------------------------------------------------------------*/
+/*
+ * Wrapper for reporting error to cardservices
+ */
+static void cs_error(client_handle_t handle, int func, int ret)
+{
+    error_info_t err = { func, ret };
+    CardServices(ReportError, handle, &err);
+}
+
+#ifdef STRUCT_CHECK
+/*------------------------------------------------------------------*/
+/*
+ * Sanity routine to verify the sizes of the various WaveLAN interface
+ * structures.
+ */
+static char *
+wv_structuct_check(void)
+{
+#define	SC(t,s,n)	if (sizeof(t) != s) return(n);
+
+  SC(psa_t, PSA_SIZE, "psa_t");
+  SC(mmw_t, MMW_SIZE, "mmw_t");
+  SC(mmr_t, MMR_SIZE, "mmr_t");
+
+#undef	SC
+
+  return((char *) NULL);
+} /* wv_structuct_check */
+#endif	/* STRUCT_CHECK */
+
+/******************* MODEM MANAGEMENT SUBROUTINES *******************/
+/*
+ * Usefull subroutines to manage the modem of the wavelan
+ */
+
+/*------------------------------------------------------------------*/
+/*
+ * Read from card's Host Adaptor Status Register.
+ */
+static inline u_char
+hasr_read(u_long	base)
+{
+  return(inb(HASR(base)));
+} /* hasr_read */
+
+/*------------------------------------------------------------------*/
+/*
+ * Write to card's Host Adapter Command Register.
+ */
+static inline void
+hacr_write(u_long	base,
+	   u_char	hacr)
+{
+  outb(hacr, HACR(base));
+} /* hacr_write */
+
+/*------------------------------------------------------------------*/
+/*
+ * Write to card's Host Adapter Command Register. Include a delay for
+ * those times when it is needed.
+ */
+static inline void
+hacr_write_slow(u_long	base,
+		u_char	hacr)
+{
+  hacr_write(base, hacr);
+  /* delay might only be needed sometimes */
+  udelay(1000L);
+} /* hacr_write_slow */
+
+/*------------------------------------------------------------------*/
+/*
+ * Read the Parameter Storage Area from the WaveLAN card's memory
+ */
+static void
+psa_read(device *	dev,
+	 int		o,	/* offset in PSA */
+	 u_char *	b,	/* buffer to fill */
+	 int		n)	/* size to read */
+{
+  u_char *	ptr = ((u_char *)dev->mem_start) + PSA_ADDR + (o << 1);
+
+  while(n-- > 0)
+    {
+      *b++ = readb(ptr);
+      /* Due to a lack of address decode pins, the WaveLAN PCMCIA card
+       * only supports reading even memory addresses. That means the
+       * increment here MUST be two.
+       * Because of that, we can't use memcpy_fromio()...
+       */
+      ptr += 2;
+    }
+} /* psa_read */
+
+/*------------------------------------------------------------------*/
+/*
+ * Write the Paramter Storage Area to the WaveLAN card's memory
+ */
+static void
+psa_write(device *	dev,
+	  int		o,	/* Offset in psa */
+	  u_char *	b,	/* Buffer in memory */
+	  int		n)	/* Length of buffer */
+{
+  u_char *	ptr = ((u_char *) dev->mem_start) + PSA_ADDR + (o << 1);
+  int		count = 0;
+  ioaddr_t	base = dev->base_addr;
+  /* As there seem to have no flag PSA_BUSY as in the ISA model, we are
+   * oblige to verify this address to know when the PSA is ready... */
+  volatile u_char *	verify = ((u_char *) dev->mem_start) + PSA_ADDR +
+    (psaoff(0, psa_comp_number) << 1);
+
+  /* Authorize writting to PSA */
+  hacr_write(base, HACR_PWR_STAT | HACR_ROM_WEN);
+
+  while(n-- > 0)
+    {
+      /* write to PSA */
+      writeb(*b++, ptr);
+      ptr += 2;
+
+      /* I don't have the spec, so I don't know what the correct
+       * sequence to write is. This hack seem to work for me... */
+      count = 0;
+      while((readb(verify) != PSA_COMP_PCMCIA_915) && (count++ < 100))
+	udelay(1000);
+    }
+
+  /* Put the host interface back in standard state */
+  hacr_write(base, HACR_DEFAULT);
+} /* psa_write */
+
+#ifdef SET_PSA_CRC
+/*------------------------------------------------------------------*/
+/*
+ * Calculate the PSA CRC
+ * Thanks to Valster, Nico <NVALSTER@wcnd.nl.lucent.com> for the code
+ * NOTE: By specifying a length including the CRC position the
+ * returned value should be zero. (i.e. a correct checksum in the PSA)
+ *
+ * The Windows drivers don't use the CRC, but the AP and the PtP tool
+ * depend on it.
+ */
+static u_short
+psa_crc(unsigned char *	psa,	/* The PSA */
+	int		size)	/* Number of short for CRC */
+{
+  int		byte_cnt;	/* Loop on the PSA */
+  u_short	crc_bytes = 0;	/* Data in the PSA */
+  int		bit_cnt;	/* Loop on the bits of the short */
+
+  for(byte_cnt = 0; byte_cnt < size; byte_cnt++ )
+    {
+      crc_bytes ^= psa[byte_cnt];	/* Its an xor */
+
+      for(bit_cnt = 1; bit_cnt < 9; bit_cnt++ )
+	{
+	  if(crc_bytes & 0x0001)
+	    crc_bytes = (crc_bytes >> 1) ^ 0xA001;
+	  else
+	    crc_bytes >>= 1 ;
+        }
+    }
+
+  return crc_bytes;
+} /* psa_crc */
+#endif	/* SET_PSA_CRC */
+
+/*------------------------------------------------------------------*/
+/*
+ * update the checksum field in the Wavelan's PSA
+ */
+static void
+update_psa_checksum(device *	dev)
+{
+#ifdef SET_PSA_CRC
+  psa_t		psa;
+  u_short	crc;
+
+  /* read the parameter storage area */
+  psa_read(dev, 0, (unsigned char *) &psa, sizeof(psa));
+
+  /* update the checksum */
+  crc = psa_crc((unsigned char *) &psa,
+		sizeof(psa) - sizeof(psa.psa_crc[0]) - sizeof(psa.psa_crc[1])
+		- sizeof(psa.psa_crc_status));
+
+  psa.psa_crc[0] = crc & 0xFF;
+  psa.psa_crc[1] = (crc & 0xFF00) >> 8;
+
+  /* Write it ! */
+  psa_write(dev, (char *)&psa.psa_crc - (char *)&psa,
+	    (unsigned char *)&psa.psa_crc, 2);
+
+#ifdef DEBUG_IOCTL_INFO
+  printk (KERN_DEBUG "%s: update_psa_checksum(): crc = 0x%02x%02x\n",
+          dev->name, psa.psa_crc[0], psa.psa_crc[1]);
+
+  /* Check again (luxury !) */
+  crc = psa_crc((unsigned char *) &psa,
+		 sizeof(psa) - sizeof(psa.psa_crc_status));
+
+  if(crc != 0)
+    printk(KERN_WARNING "%s: update_psa_checksum(): CRC does not agree with PSA data (even after recalculating)\n", dev->name);
+#endif /* DEBUG_IOCTL_INFO */
+#endif	/* SET_PSA_CRC */
+} /* update_psa_checksum */
+
+/*------------------------------------------------------------------*/
+/*
+ * Write 1 byte to the MMC.
+ */
+static inline void
+mmc_out(u_long		base,
+	u_short		o,
+	u_char		d)
+{
+  /* Wait for MMC to go idle */
+  while(inb(HASR(base)) & HASR_MMI_BUSY)
+    ;
+
+  outb((u_char)((o << 1) | MMR_MMI_WR), MMR(base));
+  outb(d, MMD(base));
+}
+
+/*------------------------------------------------------------------*/
+/*
+ * Routine to write bytes to the Modem Management Controller.
+ * We start by the end because it is the way it should be !
+ */
+static inline void
+mmc_write(u_long	base,
+	  u_char	o,
+	  u_char *	b,
+	  int		n)
+{
+  o += n;
+  b += n;
+
+  while(n-- > 0 )
+    mmc_out(base, --o, *(--b));
+} /* mmc_write */
+
+/*------------------------------------------------------------------*/
+/*
+ * Read 1 byte from the MMC.
+ * Optimised version for 1 byte, avoid using memory...
+ */
+static inline u_char
+mmc_in(u_long	base,
+       u_short	o)
+{
+  while(inb(HASR(base)) & HASR_MMI_BUSY)
+    ;
+  outb(o << 1, MMR(base));		/* Set the read address */
+
+  outb(0, MMD(base));			/* Required dummy write */
+
+  while(inb(HASR(base)) & HASR_MMI_BUSY)
+    ;
+  return (u_char) (inb(MMD(base)));	/* Now do the actual read */
+}
+
+/*------------------------------------------------------------------*/
+/*
+ * Routine to read bytes from the Modem Management Controller.
+ * The implementation is complicated by a lack of address lines,
+ * which prevents decoding of the low-order bit.
+ * (code has just been moved in the above function)
+ * We start by the end because it is the way it should be !
+ */
+static inline void
+mmc_read(u_long		base,
+	 u_char		o,
+	 u_char *	b,
+	 int		n)
+{
+  o += n;
+  b += n;
+
+  while(n-- > 0)
+    *(--b) = mmc_in(base, --o);
+} /* mmc_read */
+
+/*------------------------------------------------------------------*/
+/*
+ * Get the type of encryption available...
+ */
+static inline int
+mmc_encr(u_long		base)	/* i/o port of the card */
+{
+  int	temp;
+
+  temp = mmc_in(base, mmroff(0, mmr_des_avail));
+  if((temp != MMR_DES_AVAIL_DES) && (temp != MMR_DES_AVAIL_AES))
+    return 0;
+  else
+    return temp;
+}
+
+/*------------------------------------------------------------------*/
+/*
+ * Wait for the frequency EEprom to complete a command...
+ * I hope this one will be optimally inlined...
+ */
+static inline void
+fee_wait(u_long		base,	/* i/o port of the card */
+	 int		delay,	/* Base delay to wait for */
+	 int		number)	/* Number of time to wait */
+{
+  int		count = 0;	/* Wait only a limited time */
+
+  while((count++ < number) &&
+	(mmc_in(base, mmroff(0, mmr_fee_status)) & MMR_FEE_STATUS_BUSY))
+    udelay(delay);
+}
+
+/*------------------------------------------------------------------*/
+/*
+ * Read bytes from the Frequency EEprom (frequency select cards).
+ */
+static void
+fee_read(u_long		base,	/* i/o port of the card */
+	 u_short	o,	/* destination offset */
+	 u_short *	b,	/* data buffer */
+	 int		n)	/* number of registers */
+{
+  b += n;		/* Position at the end of the area */
+
+  /* Write the address */
+  mmc_out(base, mmwoff(0, mmw_fee_addr), o + n - 1);
+
+  /* Loop on all buffer */
+  while(n-- > 0)
+    {
+      /* Write the read command */
+      mmc_out(base, mmwoff(0, mmw_fee_ctrl), MMW_FEE_CTRL_READ);
+
+      /* Wait until EEprom is ready (should be quick !) */
+      fee_wait(base, 10, 100);
+
+      /* Read the value */
+      *--b = ((mmc_in(base, mmroff(0, mmr_fee_data_h)) << 8) |
+	      mmc_in(base, mmroff(0, mmr_fee_data_l)));
+    }
+}
+
+#ifdef WIRELESS_EXT	/* If wireless extension exist in the kernel */
+
+/*------------------------------------------------------------------*/
+/*
+ * Write bytes from the Frequency EEprom (frequency select cards).
+ * This is a bit complicated, because the frequency eeprom has to
+ * be unprotected and the write enabled.
+ * Jean II
+ */
+static void
+fee_write(u_long	base,	/* i/o port of the card */
+	  u_short	o,	/* destination offset */
+	  u_short *	b,	/* data buffer */
+	  int		n)	/* number of registers */
+{
+  b += n;		/* Position at the end of the area */
+
+#ifdef EEPROM_IS_PROTECTED	/* disabled */
+#ifdef DOESNT_SEEM_TO_WORK	/* disabled */
+  /* Ask to read the protected register */
+  mmc_out(base, mmwoff(0, mmw_fee_ctrl), MMW_FEE_CTRL_PRREAD);
+
+  fee_wait(base, 10, 100);
+
+  /* Read the protected register */
+  printk("Protected 2 : %02X-%02X\n",
+	 mmc_in(base, mmroff(0, mmr_fee_data_h)),
+	 mmc_in(base, mmroff(0, mmr_fee_data_l)));
+#endif	/* DOESNT_SEEM_TO_WORK */
+
+  /* Enable protected register */
+  mmc_out(base, mmwoff(0, mmw_fee_addr), MMW_FEE_ADDR_EN);
+  mmc_out(base, mmwoff(0, mmw_fee_ctrl), MMW_FEE_CTRL_PREN);
+
+  fee_wait(base, 10, 100);
+
+  /* Unprotect area */
+  mmc_out(base, mmwoff(0, mmw_fee_addr), o + n);
+  mmc_out(base, mmwoff(0, mmw_fee_ctrl), MMW_FEE_CTRL_PRWRITE);
+#ifdef DOESNT_SEEM_TO_WORK	/* disabled */
+  /* Or use : */
+  mmc_out(base, mmwoff(0, mmw_fee_ctrl), MMW_FEE_CTRL_PRCLEAR);
+#endif	/* DOESNT_SEEM_TO_WORK */
+
+  fee_wait(base, 10, 100);
+#endif	/* EEPROM_IS_PROTECTED */
+
+  /* Write enable */
+  mmc_out(base, mmwoff(0, mmw_fee_addr), MMW_FEE_ADDR_EN);
+  mmc_out(base, mmwoff(0, mmw_fee_ctrl), MMW_FEE_CTRL_WREN);
+
+  fee_wait(base, 10, 100);
+
+  /* Write the EEprom address */
+  mmc_out(base, mmwoff(0, mmw_fee_addr), o + n - 1);
+
+  /* Loop on all buffer */
+  while(n-- > 0)
+    {
+      /* Write the value */
+      mmc_out(base, mmwoff(0, mmw_fee_data_h), (*--b) >> 8);
+      mmc_out(base, mmwoff(0, mmw_fee_data_l), *b & 0xFF);
+
+      /* Write the write command */
+      mmc_out(base, mmwoff(0, mmw_fee_ctrl), MMW_FEE_CTRL_WRITE);
+
+      /* Wavelan doc says : wait at least 10 ms for EEBUSY = 0 */
+      udelay(10000);
+      fee_wait(base, 10, 100);
+    }
+
+  /* Write disable */
+  mmc_out(base, mmwoff(0, mmw_fee_addr), MMW_FEE_ADDR_DS);
+  mmc_out(base, mmwoff(0, mmw_fee_ctrl), MMW_FEE_CTRL_WDS);
+
+  fee_wait(base, 10, 100);
+
+#ifdef EEPROM_IS_PROTECTED	/* disabled */
+  /* Reprotect EEprom */
+  mmc_out(base, mmwoff(0, mmw_fee_addr), 0x00);
+  mmc_out(base, mmwoff(0, mmw_fee_ctrl), MMW_FEE_CTRL_PRWRITE);
+
+  fee_wait(base, 10, 100);
+#endif	/* EEPROM_IS_PROTECTED */
+}
+#endif	/* WIRELESS_EXT */
+
+/******************* WaveLAN Roaming routines... ********************/
+
+#ifdef WAVELAN_ROAMING	/* Conditional compile, see wavelan_cs.h */
+
+unsigned char WAVELAN_BEACON_ADDRESS[]= {0x09,0x00,0x0e,0x20,0x03,0x00};
+  
+void wv_roam_init(struct net_device *dev)
+{
+  net_local  *lp= (net_local *)dev->priv;
+
+  /* Do not remove this unless you have a good reason */
+  printk(KERN_NOTICE "%s: Warning, you have enabled roaming on"
+	 " device %s !\n", dev->name, dev->name);
+  printk(KERN_NOTICE "Roaming is currently an experimental unsuported feature"
+	 " of the Wavelan driver.\n");
+  printk(KERN_NOTICE "It may work, but may also make the driver behave in"
+	 " erratic ways or crash.\n");
+
+  lp->wavepoint_table.head=NULL;           /* Initialise WavePoint table */
+  lp->wavepoint_table.num_wavepoints=0;
+  lp->wavepoint_table.locked=0;
+  lp->curr_point=NULL;                        /* No default WavePoint */
+  lp->cell_search=0;
+  
+  lp->cell_timer.data=(long)lp;               /* Start cell expiry timer */
+  lp->cell_timer.function=wl_cell_expiry;
+  lp->cell_timer.expires=jiffies+CELL_TIMEOUT;
+  add_timer(&lp->cell_timer);
+  
+  wv_nwid_filter(NWID_PROMISC,lp) ;    /* Enter NWID promiscuous mode */
+  /* to build up a good WavePoint */
+                                           /* table... */
+  printk(KERN_DEBUG "WaveLAN: Roaming enabled on device %s\n",dev->name);
+}
+ 
+void wv_roam_cleanup(struct net_device *dev)
+{
+  wavepoint_history *ptr,*old_ptr;
+  net_local *lp= (net_local *)dev->priv;
+  
+  printk(KERN_DEBUG "WaveLAN: Roaming Disabled on device %s\n",dev->name);
+  
+  /* Fixme : maybe we should check that the timer exist before deleting it */
+  del_timer(&lp->cell_timer);          /* Remove cell expiry timer       */
+  ptr=lp->wavepoint_table.head;        /* Clear device's WavePoint table */
+  while(ptr!=NULL)
+    {
+      old_ptr=ptr;
+      ptr=ptr->next;	
+      wl_del_wavepoint(old_ptr,lp);	
+    }
+}
+
+/* Enable/Disable NWID promiscuous mode on a given device */
+void wv_nwid_filter(unsigned char mode, net_local *lp)
+{
+  mm_t                  m;
+  unsigned long         flags;
+  
+#ifdef WAVELAN_ROAMING_DEBUG
+  printk(KERN_DEBUG "WaveLAN: NWID promisc %s, device %s\n",(mode==NWID_PROMISC) ? "on" : "off", lp->dev->name);
+#endif
+  
+  /* Disable interrupts & save flags */
+  wv_splhi(lp, &flags);
+  
+  m.w.mmw_loopt_sel = (mode==NWID_PROMISC) ? MMW_LOOPT_SEL_DIS_NWID : 0x00;
+  mmc_write(lp->dev->base_addr, (char *)&m.w.mmw_loopt_sel - (char *)&m, (unsigned char *)&m.w.mmw_loopt_sel, 1);
+  
+  if(mode==NWID_PROMISC)
+    lp->cell_search=1;
+  else
+    lp->cell_search=0;
+
+  /* ReEnable interrupts & restore flags */
+  wv_splx(lp, &flags);
+}
+
+/* Find a record in the WavePoint table matching a given NWID */
+wavepoint_history *wl_roam_check(unsigned short nwid, net_local *lp)
+{
+  wavepoint_history	*ptr=lp->wavepoint_table.head;
+  
+  while(ptr!=NULL){
+    if(ptr->nwid==nwid)
+      return ptr;	
+    ptr=ptr->next;
+  }
+  return NULL;
+}
+
+/* Create a new wavepoint table entry */
+wavepoint_history *wl_new_wavepoint(unsigned short nwid, unsigned char seq, net_local* lp)
+{
+  wavepoint_history *new_wavepoint;
+
+#ifdef WAVELAN_ROAMING_DEBUG	
+  printk(KERN_DEBUG "WaveLAN: New Wavepoint, NWID:%.4X\n",nwid);
+#endif
+  
+  if(lp->wavepoint_table.num_wavepoints==MAX_WAVEPOINTS)
+    return NULL;
+  
+  new_wavepoint=(wavepoint_history *) kmalloc(sizeof(wavepoint_history),GFP_ATOMIC);
+  if(new_wavepoint==NULL)
+    return NULL;
+  
+  new_wavepoint->nwid=nwid;                       /* New WavePoints NWID */
+  new_wavepoint->average_fast=0;                    /* Running Averages..*/
+  new_wavepoint->average_slow=0;
+  new_wavepoint->qualptr=0;                       /* Start of ringbuffer */
+  new_wavepoint->last_seq=seq-1;                /* Last sequence no.seen */
+  memset(new_wavepoint->sigqual,0,WAVEPOINT_HISTORY);/* Empty ringbuffer */
+  
+  new_wavepoint->next=lp->wavepoint_table.head;/* Add to wavepoint table */
+  new_wavepoint->prev=NULL;
+  
+  if(lp->wavepoint_table.head!=NULL)
+    lp->wavepoint_table.head->prev=new_wavepoint;
+  
+  lp->wavepoint_table.head=new_wavepoint;
+  
+  lp->wavepoint_table.num_wavepoints++;     /* no. of visible wavepoints */
+  
+  return new_wavepoint;
+}
+
+/* Remove a wavepoint entry from WavePoint table */
+void wl_del_wavepoint(wavepoint_history *wavepoint, struct net_local *lp)
+{
+  if(wavepoint==NULL)
+    return;
+  
+  if(lp->curr_point==wavepoint)
+    lp->curr_point=NULL;
+  
+  if(wavepoint->prev!=NULL)
+    wavepoint->prev->next=wavepoint->next;
+  
+  if(wavepoint->next!=NULL)
+    wavepoint->next->prev=wavepoint->prev;
+  
+  if(lp->wavepoint_table.head==wavepoint)
+    lp->wavepoint_table.head=wavepoint->next;
+  
+  lp->wavepoint_table.num_wavepoints--;
+  kfree(wavepoint);
+}
+
+/* Timer callback function - checks WavePoint table for stale entries */ 
+void wl_cell_expiry(unsigned long data)
+{
+  net_local *lp=(net_local *)data;
+  wavepoint_history *wavepoint=lp->wavepoint_table.head,*old_point;
+  
+#if WAVELAN_ROAMING_DEBUG > 1
+  printk(KERN_DEBUG "WaveLAN: Wavepoint timeout, dev %s\n",lp->dev->name);
+#endif
+  
+  if(lp->wavepoint_table.locked)
+    {
+#if WAVELAN_ROAMING_DEBUG > 1
+      printk(KERN_DEBUG "WaveLAN: Wavepoint table locked...\n");
+#endif
+      
+      lp->cell_timer.expires=jiffies+1; /* If table in use, come back later */
+      add_timer(&lp->cell_timer);
+      return;
+    }
+  
+  while(wavepoint!=NULL)
+    {
+      if(wavepoint->last_seen < jiffies-CELL_TIMEOUT)
+	{
+#ifdef WAVELAN_ROAMING_DEBUG
+	  printk(KERN_DEBUG "WaveLAN: Bye bye %.4X\n",wavepoint->nwid);
+#endif
+	  
+	  old_point=wavepoint;
+	  wavepoint=wavepoint->next;
+	  wl_del_wavepoint(old_point,lp);
+	}
+      else
+	wavepoint=wavepoint->next;
+    }
+  lp->cell_timer.expires=jiffies+CELL_TIMEOUT;
+  add_timer(&lp->cell_timer);
+}
+
+/* Update SNR history of a wavepoint */
+void wl_update_history(wavepoint_history *wavepoint, unsigned char sigqual, unsigned char seq)	
+{
+  int i=0,num_missed=0,ptr=0;
+  int average_fast=0,average_slow=0;
+  
+  num_missed=(seq-wavepoint->last_seq)%WAVEPOINT_HISTORY;/* Have we missed
+							    any beacons? */
+  if(num_missed)
+    for(i=0;i<num_missed;i++)
+      {
+	wavepoint->sigqual[wavepoint->qualptr++]=0; /* If so, enter them as 0's */
+	wavepoint->qualptr %=WAVEPOINT_HISTORY;    /* in the ringbuffer. */
+      }
+  wavepoint->last_seen=jiffies;                 /* Add beacon to history */
+  wavepoint->last_seq=seq;	
+  wavepoint->sigqual[wavepoint->qualptr++]=sigqual;          
+  wavepoint->qualptr %=WAVEPOINT_HISTORY;
+  ptr=(wavepoint->qualptr-WAVEPOINT_FAST_HISTORY+WAVEPOINT_HISTORY)%WAVEPOINT_HISTORY;
+  
+  for(i=0;i<WAVEPOINT_FAST_HISTORY;i++)       /* Update running averages */
+    {
+      average_fast+=wavepoint->sigqual[ptr++];
+      ptr %=WAVEPOINT_HISTORY;
+    }
+  
+  average_slow=average_fast;
+  for(i=WAVEPOINT_FAST_HISTORY;i<WAVEPOINT_HISTORY;i++)
+    {
+      average_slow+=wavepoint->sigqual[ptr++];
+      ptr %=WAVEPOINT_HISTORY;
+    }
+  
+  wavepoint->average_fast=average_fast/WAVEPOINT_FAST_HISTORY;
+  wavepoint->average_slow=average_slow/WAVEPOINT_HISTORY;	
+}
+
+/* Perform a handover to a new WavePoint */
+void wv_roam_handover(wavepoint_history *wavepoint, net_local *lp)
+{
+  ioaddr_t              base = lp->dev->base_addr;  
+  mm_t                  m;
+  unsigned long         flags;
+
+  if(wavepoint==lp->curr_point)          /* Sanity check... */
+    {
+      wv_nwid_filter(!NWID_PROMISC,lp);
+      return;
+    }
+  
+#ifdef WAVELAN_ROAMING_DEBUG
+  printk(KERN_DEBUG "WaveLAN: Doing handover to %.4X, dev %s\n",wavepoint->nwid,lp->dev->name);
+#endif
+ 	
+  /* Disable interrupts & save flags */
+  wv_splhi(lp, &flags);
+
+  m.w.mmw_netw_id_l = wavepoint->nwid & 0xFF;
+  m.w.mmw_netw_id_h = (wavepoint->nwid & 0xFF00) >> 8;
+  
+  mmc_write(base, (char *)&m.w.mmw_netw_id_l - (char *)&m, (unsigned char *)&m.w.mmw_netw_id_l, 2);
+  
+  /* ReEnable interrupts & restore flags */
+  wv_splx(lp, &flags);
+
+  wv_nwid_filter(!NWID_PROMISC,lp);
+  lp->curr_point=wavepoint;
+}
+
+/* Called when a WavePoint beacon is received */
+static inline void wl_roam_gather(device *  dev,
+				  u_char *  hdr,   /* Beacon header */
+				  u_char *  stats) /* SNR, Signal quality 
+						      of packet */
+{
+  wavepoint_beacon *beacon= (wavepoint_beacon *)hdr; /* Rcvd. Beacon */
+  unsigned short nwid=ntohs(beacon->nwid);  
+  unsigned short sigqual=stats[2] & MMR_SGNL_QUAL;   /* SNR of beacon */
+  wavepoint_history *wavepoint=NULL;                /* WavePoint table entry */
+  net_local *lp=(net_local *)dev->priv;              /* Device info */
+
+#if 0
+  /* Some people don't need this, some other may need it */
+  nwid=nwid^ntohs(beacon->domain_id);
+#endif
+
+#if WAVELAN_ROAMING_DEBUG > 1
+  printk(KERN_DEBUG "WaveLAN: beacon, dev %s:\n",dev->name);
+  printk(KERN_DEBUG "Domain: %.4X NWID: %.4X SigQual=%d\n",ntohs(beacon->domain_id),nwid,sigqual);
+#endif
+  
+  lp->wavepoint_table.locked=1;                            /* <Mutex> */
+  
+  wavepoint=wl_roam_check(nwid,lp);            /* Find WavePoint table entry */
+  if(wavepoint==NULL)                    /* If no entry, Create a new one... */
+    {
+      wavepoint=wl_new_wavepoint(nwid,beacon->seq,lp);
+      if(wavepoint==NULL)
+	goto out;
+    }
+  if(lp->curr_point==NULL)             /* If this is the only WavePoint, */
+    wv_roam_handover(wavepoint, lp);	         /* Jump on it! */
+  
+  wl_update_history(wavepoint, sigqual, beacon->seq); /* Update SNR history
+							 stats. */
+  
+  if(lp->curr_point->average_slow < SEARCH_THRESH_LOW) /* If our current */
+    if(!lp->cell_search)                  /* WavePoint is getting faint, */
+      wv_nwid_filter(NWID_PROMISC,lp);    /* start looking for a new one */
+  
+  if(wavepoint->average_slow > 
+     lp->curr_point->average_slow + WAVELAN_ROAMING_DELTA)
+    wv_roam_handover(wavepoint, lp);   /* Handover to a better WavePoint */
+  
+  if(lp->curr_point->average_slow > SEARCH_THRESH_HIGH) /* If our SNR is */
+    if(lp->cell_search)  /* getting better, drop out of cell search mode */
+      wv_nwid_filter(!NWID_PROMISC,lp);
+  
+out:
+  lp->wavepoint_table.locked=0;                        /* </MUTEX>   :-) */
+}
+
+/* Test this MAC frame a WavePoint beacon */
+static inline int WAVELAN_BEACON(unsigned char *data)
+{
+  wavepoint_beacon *beacon= (wavepoint_beacon *)data;
+  static wavepoint_beacon beacon_template={0xaa,0xaa,0x03,0x08,0x00,0x0e,0x20,0x03,0x00};
+  
+  if(memcmp(beacon,&beacon_template,9)==0)
+    return 1;
+  else
+    return 0;
+}
+#endif	/* WAVELAN_ROAMING */
+
+/************************ I82593 SUBROUTINES *************************/
+/*
+ * Usefull subroutines to manage the Ethernet controler
+ */
+
+/*------------------------------------------------------------------*/
+/*
+ * Routine to synchronously send a command to the i82593 chip. 
+ * Should be called with interrupts disabled.
+ * (called by wv_packet_write(), wv_ru_stop(), wv_ru_start(),
+ *  wv_82593_config() & wv_diag())
+ */
+static int
+wv_82593_cmd(device *	dev,
+	     char *	str,
+	     int	cmd,
+	     int	result)
+{
+  ioaddr_t	base = dev->base_addr;
+  int		status;
+  int		wait_completed;
+  long		spin;
+
+  /* Spin until the chip finishes executing its current command (if any) */
+  do
+    {
+      outb(OP0_NOP | CR0_STATUS_3, LCCR(base));
+      status = inb(LCSR(base));
+    }
+  while((status & SR3_EXEC_STATE_MASK) != SR3_EXEC_IDLE);
+
+  /* Issue the command to the controler */
+  outb(cmd, LCCR(base));
+
+  /* If we don't have to check the result of the command
+   * Note : this mean that the irq handler will deal with that */
+  if(result == SR0_NO_RESULT)
+    return(TRUE);
+
+  /* We are waiting for command completion */
+  wait_completed = TRUE;
+
+  /* Busy wait while the LAN controller executes the command. */
+  spin = 1000;
+  do
+    {
+      /* Time calibration of the loop */
+      udelay(10);
+
+      /* Read the interrupt register */
+      outb(CR0_STATUS_0 | OP0_NOP, LCCR(base));
+      status = inb(LCSR(base));
+
+      /* Check if there was an interrupt posted */
+      if((status & SR0_INTERRUPT))
+	{
+	  /* Acknowledge the interrupt */
+	  outb(CR0_INT_ACK | OP0_NOP, LCCR(base));
+
+	  /* Check if interrupt is a command completion */
+	  if(((status & SR0_BOTH_RX_TX) != SR0_BOTH_RX_TX) &&
+	     ((status & SR0_BOTH_RX_TX) != 0x0) &&
+	     !(status & SR0_RECEPTION))
+	    {
+	      /* Signal command completion */
+	      wait_completed = FALSE;
+	    }
+	  else
+	    {
+	      /* Note : Rx interrupts will be handled later, because we can
+	       * handle multiple Rx packets at once */
+#ifdef DEBUG_INTERRUPT_INFO
+	      printk(KERN_INFO "wv_82593_cmd: not our interrupt\n");
+#endif
+	    }
+	}
+    }
+  while(wait_completed && (spin-- > 0));
+
+  /* If the interrupt hasn't be posted */
+  if(wait_completed)
+    {
+#ifdef DEBUG_INTERRUPT_ERROR
+      printk(KERN_INFO "wv_82593_cmd: %s timeout, status 0x%02x\n",
+	     str, status);
+#endif
+      return(FALSE);
+    }
+
+  /* Check the return code returned by the card (see above) against
+   * the expected return code provided by the caller */
+  if((status & SR0_EVENT_MASK) != result)
+    {
+#ifdef DEBUG_INTERRUPT_ERROR
+      printk(KERN_INFO "wv_82593_cmd: %s failed, status = 0x%x\n",
+	     str, status);
+#endif
+      return(FALSE);
+    }
+
+  return(TRUE);
+} /* wv_82593_cmd */
+
+/*------------------------------------------------------------------*/
+/*
+ * This routine does a 593 op-code number 7, and obtains the diagnose
+ * status for the WaveLAN.
+ */
+static inline int
+wv_diag(device *	dev)
+{
+  net_local *	lp = (net_local *)dev->priv;
+  unsigned long flags;
+  int		ret = FALSE;
+
+  wv_splhi(lp, &flags);
+
+  if(wv_82593_cmd(dev, "wv_diag(): diagnose",
+		  OP0_DIAGNOSE, SR0_DIAGNOSE_PASSED))
+    ret = TRUE;
+
+  wv_splx(lp, &flags);
+
+#ifdef DEBUG_CONFIG_ERROR
+  printk(KERN_INFO "wavelan_cs: i82593 Self Test failed!\n");
+#endif
+  return(ret);
+} /* wv_diag */
+
+/*------------------------------------------------------------------*/
+/*
+ * Routine to read len bytes from the i82593's ring buffer, starting at
+ * chip address addr. The results read from the chip are stored in buf.
+ * The return value is the address to use for next the call.
+ */
+static int
+read_ringbuf(device *	dev,
+	     int	addr,
+	     char *	buf,
+	     int	len)
+{
+  ioaddr_t	base = dev->base_addr;
+  int		ring_ptr = addr;
+  int		chunk_len;
+  char *	buf_ptr = buf;
+
+  /* Get all the buffer */
+  while(len > 0)
+    {
+      /* Position the Program I/O Register at the ring buffer pointer */
+      outb(ring_ptr & 0xff, PIORL(base));
+      outb(((ring_ptr >> 8) & PIORH_MASK), PIORH(base));
+
+      /* First, determine how much we can read without wrapping around the
+	 ring buffer */
+      if((addr + len) < (RX_BASE + RX_SIZE))
+	chunk_len = len;
+      else
+	chunk_len = RX_BASE + RX_SIZE - addr;
+      insb(PIOP(base), buf_ptr, chunk_len);
+      buf_ptr += chunk_len;
+      len -= chunk_len;
+      ring_ptr = (ring_ptr - RX_BASE + chunk_len) % RX_SIZE + RX_BASE;
+    }
+  return(ring_ptr);
+} /* read_ringbuf */
+
+/*------------------------------------------------------------------*/
+/*
+ * Reconfigure the i82593, or at least ask for it...
+ * Because wv_82593_config use the transmission buffer, we must do it
+ * when we are sure that there is no transmission, so we do it now
+ * or in wavelan_packet_xmit() (I can't find any better place,
+ * wavelan_interrupt is not an option...), so you may experience
+ * some delay sometime...
+ */
+static inline void
+wv_82593_reconfig(device *	dev)
+{
+  net_local *	lp = (net_local *)dev->priv;
+  dev_link_t *	link = ((net_local *) dev->priv)->link;
+
+  /* Arm the flag, will be cleard in wv_82593_config() */
+  lp->reconfig_82593 = TRUE;
+
+  /* Check if we can do it now ! */
+  if((link->open) && (netif_running(dev)) && !(netif_queue_stopped(dev)))
+    {
+      wv_82593_config(dev);
+    }
+  else
+    {
+#ifdef DEBUG_IOCTL_INFO
+      printk(KERN_DEBUG
+	     "%s: wv_82593_reconfig(): delayed (state = %lX, link = %d)\n",
+	     dev->name, devstate(dev), link->open);
+#endif
+    }
+}
+
+#ifdef OLDIES
+/*------------------------------------------------------------------*/
+/*
+ * Dumps the current i82593 receive buffer to the console.
+ */
+static void wavelan_dump(device *dev)
+{
+  ioaddr_t base = dev->base_addr;
+  int i, c;
+
+  /* disable receiver so we can use channel 1 */
+  outb(OP0_RCV_DISABLE, LCCR(base));
+
+  /* reset receive DMA pointer */
+  hacr_write_slow(base, HACR_PWR_STAT | HACR_RX_DMA_RESET);
+  hacr_write(base, HACR_DEFAULT);
+
+  /* dump into receive buffer */
+  wv_82593_cmd(dev, "wavelan_dump(): dump", CR0_CHNL|OP0_DUMP, SR0_DUMP_DONE);
+
+  /* set read pointer to start of receive buffer */
+  outb(0, PIORL(base));
+  outb(0, PIORH(base));
+
+  printk(KERN_DEBUG "wavelan_cs: dump:\n");
+  printk(KERN_DEBUG "     00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F");
+  for(i = 0; i < 73; i++){
+    if((i % 16) == 0) {
+      printk("\n0x%02x:", i);
+      if (!i) {
+	printk("   ");
+	continue;
+      }
+    }
+    c = inb(PIOP(base));
+    printk("%02x ", c);
+  }
+  printk("\n");
+
+  /* enable the receiver again */
+  wv_ru_start(dev);
+}
+#endif
+
+
+/********************* DEBUG & INFO SUBROUTINES *********************/
+/*
+ * This routines are used in the code to show debug informations.
+ * Most of the time, it dump the content of hardware structures...
+ */
+
+#ifdef DEBUG_PSA_SHOW
+/*------------------------------------------------------------------*/
+/*
+ * Print the formatted contents of the Parameter Storage Area.
+ */
+static void
+wv_psa_show(psa_t *	p)
+{
+  printk(KERN_DEBUG "##### wavelan psa contents: #####\n");
+  printk(KERN_DEBUG "psa_io_base_addr_1: 0x%02X %02X %02X %02X\n",
+	 p->psa_io_base_addr_1,
+	 p->psa_io_base_addr_2,
+	 p->psa_io_base_addr_3,
+	 p->psa_io_base_addr_4);
+  printk(KERN_DEBUG "psa_rem_boot_addr_1: 0x%02X %02X %02X\n",
+	 p->psa_rem_boot_addr_1,
+	 p->psa_rem_boot_addr_2,
+	 p->psa_rem_boot_addr_3);
+  printk(KERN_DEBUG "psa_holi_params: 0x%02x, ", p->psa_holi_params);
+  printk("psa_int_req_no: %d\n", p->psa_int_req_no);
+#ifdef DEBUG_SHOW_UNUSED
+  printk(KERN_DEBUG "psa_unused0[]: %02X:%02X:%02X:%02X:%02X:%02X:%02X\n",
+	 p->psa_unused0[0],
+	 p->psa_unused0[1],
+	 p->psa_unused0[2],
+	 p->psa_unused0[3],
+	 p->psa_unused0[4],
+	 p->psa_unused0[5],
+	 p->psa_unused0[6]);
+#endif	/* DEBUG_SHOW_UNUSED */
+  printk(KERN_DEBUG "psa_univ_mac_addr[]: %02x:%02x:%02x:%02x:%02x:%02x\n",
+	 p->psa_univ_mac_addr[0],
+	 p->psa_univ_mac_addr[1],
+	 p->psa_univ_mac_addr[2],
+	 p->psa_univ_mac_addr[3],
+	 p->psa_univ_mac_addr[4],
+	 p->psa_univ_mac_addr[5]);
+  printk(KERN_DEBUG "psa_local_mac_addr[]: %02x:%02x:%02x:%02x:%02x:%02x\n",
+	 p->psa_local_mac_addr[0],
+	 p->psa_local_mac_addr[1],
+	 p->psa_local_mac_addr[2],
+	 p->psa_local_mac_addr[3],
+	 p->psa_local_mac_addr[4],
+	 p->psa_local_mac_addr[5]);
+  printk(KERN_DEBUG "psa_univ_local_sel: %d, ", p->psa_univ_local_sel);
+  printk("psa_comp_number: %d, ", p->psa_comp_number);
+  printk("psa_thr_pre_set: 0x%02x\n", p->psa_thr_pre_set);
+  printk(KERN_DEBUG "psa_feature_select/decay_prm: 0x%02x, ",
+	 p->psa_feature_select);
+  printk("psa_subband/decay_update_prm: %d\n", p->psa_subband);
+  printk(KERN_DEBUG "psa_quality_thr: 0x%02x, ", p->psa_quality_thr);
+  printk("psa_mod_delay: 0x%02x\n", p->psa_mod_delay);
+  printk(KERN_DEBUG "psa_nwid: 0x%02x%02x, ", p->psa_nwid[0], p->psa_nwid[1]);
+  printk("psa_nwid_select: %d\n", p->psa_nwid_select);
+  printk(KERN_DEBUG "psa_encryption_select: %d, ", p->psa_encryption_select);
+  printk("psa_encryption_key[]: %02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x\n",
+	 p->psa_encryption_key[0],
+	 p->psa_encryption_key[1],
+	 p->psa_encryption_key[2],
+	 p->psa_encryption_key[3],
+	 p->psa_encryption_key[4],
+	 p->psa_encryption_key[5],
+	 p->psa_encryption_key[6],
+	 p->psa_encryption_key[7]);
+  printk(KERN_DEBUG "psa_databus_width: %d\n", p->psa_databus_width);
+  printk(KERN_DEBUG "psa_call_code/auto_squelch: 0x%02x, ",
+	 p->psa_call_code[0]);
+  printk("psa_call_code[]: %02X:%02X:%02X:%02X:%02X:%02X:%02X:%02X\n",
+	 p->psa_call_code[0],
+	 p->psa_call_code[1],
+	 p->psa_call_code[2],
+	 p->psa_call_code[3],
+	 p->psa_call_code[4],
+	 p->psa_call_code[5],
+	 p->psa_call_code[6],
+	 p->psa_call_code[7]);
+#ifdef DEBUG_SHOW_UNUSED
+  printk(KERN_DEBUG "psa_reserved[]: %02X:%02X:%02X:%02X\n",
+	 p->psa_reserved[0],
+	 p->psa_reserved[1],
+	 p->psa_reserved[2],
+	 p->psa_reserved[3]);
+#endif	/* DEBUG_SHOW_UNUSED */
+  printk(KERN_DEBUG "psa_conf_status: %d, ", p->psa_conf_status);
+  printk("psa_crc: 0x%02x%02x, ", p->psa_crc[0], p->psa_crc[1]);
+  printk("psa_crc_status: 0x%02x\n", p->psa_crc_status);
+} /* wv_psa_show */
+#endif	/* DEBUG_PSA_SHOW */
+
+#ifdef DEBUG_MMC_SHOW
+/*------------------------------------------------------------------*/
+/*
+ * Print the formatted status of the Modem Management Controller.
+ * This function need to be completed...
+ */
+static void
+wv_mmc_show(device *	dev)
+{
+  ioaddr_t	base = dev->base_addr;
+  net_local *	lp = (net_local *)dev->priv;
+  mmr_t		m;
+
+  /* Basic check */
+  if(hasr_read(base) & HASR_NO_CLK)
+    {
+      printk(KERN_WARNING "%s: wv_mmc_show: modem not connected\n",
+	     dev->name);
+      return;
+    }
+
+  wv_splhi(lp, &flags);
+
+  /* Read the mmc */
+  mmc_out(base, mmwoff(0, mmw_freeze), 1);
+  mmc_read(base, 0, (u_char *)&m, sizeof(m));
+  mmc_out(base, mmwoff(0, mmw_freeze), 0);
+
+#ifdef WIRELESS_EXT	/* If wireless extension exist in the kernel */
+  /* Don't forget to update statistics */
+  lp->wstats.discard.nwid += (m.mmr_wrong_nwid_h << 8) | m.mmr_wrong_nwid_l;
+#endif	/* WIRELESS_EXT */
+
+  wv_splx(lp, &flags);
+
+  printk(KERN_DEBUG "##### wavelan modem status registers: #####\n");
+#ifdef DEBUG_SHOW_UNUSED
+  printk(KERN_DEBUG "mmc_unused0[]: %02X:%02X:%02X:%02X:%02X:%02X:%02X:%02X\n",
+	 m.mmr_unused0[0],
+	 m.mmr_unused0[1],
+	 m.mmr_unused0[2],
+	 m.mmr_unused0[3],
+	 m.mmr_unused0[4],
+	 m.mmr_unused0[5],
+	 m.mmr_unused0[6],
+	 m.mmr_unused0[7]);
+#endif	/* DEBUG_SHOW_UNUSED */
+  printk(KERN_DEBUG "Encryption algorythm: %02X - Status: %02X\n",
+	 m.mmr_des_avail, m.mmr_des_status);
+#ifdef DEBUG_SHOW_UNUSED
+  printk(KERN_DEBUG "mmc_unused1[]: %02X:%02X:%02X:%02X:%02X\n",
+	 m.mmr_unused1[0],
+	 m.mmr_unused1[1],
+	 m.mmr_unused1[2],
+	 m.mmr_unused1[3],
+	 m.mmr_unused1[4]);
+#endif	/* DEBUG_SHOW_UNUSED */
+  printk(KERN_DEBUG "dce_status: 0x%x [%s%s%s%s]\n",
+	 m.mmr_dce_status,
+	 (m.mmr_dce_status & MMR_DCE_STATUS_RX_BUSY) ? "energy detected,":"",
+	 (m.mmr_dce_status & MMR_DCE_STATUS_LOOPT_IND) ?
+	 "loop test indicated," : "",
+	 (m.mmr_dce_status & MMR_DCE_STATUS_TX_BUSY) ? "transmitter on," : "",
+	 (m.mmr_dce_status & MMR_DCE_STATUS_JBR_EXPIRED) ?
+	 "jabber timer expired," : "");
+  printk(KERN_DEBUG "Dsp ID: %02X\n",
+	 m.mmr_dsp_id);
+#ifdef DEBUG_SHOW_UNUSED
+  printk(KERN_DEBUG "mmc_unused2[]: %02X:%02X\n",
+	 m.mmr_unused2[0],
+	 m.mmr_unused2[1]);
+#endif	/* DEBUG_SHOW_UNUSED */
+  printk(KERN_DEBUG "# correct_nwid: %d, # wrong_nwid: %d\n",
+	 (m.mmr_correct_nwid_h << 8) | m.mmr_correct_nwid_l,
+	 (m.mmr_wrong_nwid_h << 8) | m.mmr_wrong_nwid_l);
+  printk(KERN_DEBUG "thr_pre_set: 0x%x [current signal %s]\n",
+	 m.mmr_thr_pre_set & MMR_THR_PRE_SET,
+	 (m.mmr_thr_pre_set & MMR_THR_PRE_SET_CUR) ? "above" : "below");
+  printk(KERN_DEBUG "signal_lvl: %d [%s], ",
+	 m.mmr_signal_lvl & MMR_SIGNAL_LVL,
+	 (m.mmr_signal_lvl & MMR_SIGNAL_LVL_VALID) ? "new msg" : "no new msg");
+  printk("silence_lvl: %d [%s], ", m.mmr_silence_lvl & MMR_SILENCE_LVL,
+	 (m.mmr_silence_lvl & MMR_SILENCE_LVL_VALID) ? "update done" : "no new update");
+  printk("sgnl_qual: 0x%x [%s]\n", m.mmr_sgnl_qual & MMR_SGNL_QUAL,
+	 (m.mmr_sgnl_qual & MMR_SGNL_QUAL_ANT) ? "Antenna 1" : "Antenna 0");
+#ifdef DEBUG_SHOW_UNUSED
+  printk(KERN_DEBUG "netw_id_l: %x\n", m.mmr_netw_id_l);
+#endif	/* DEBUG_SHOW_UNUSED */
+} /* wv_mmc_show */
+#endif	/* DEBUG_MMC_SHOW */
+
+#ifdef DEBUG_I82593_SHOW
+/*------------------------------------------------------------------*/
+/*
+ * Print the formatted status of the i82593's receive unit.
+ */
+static void
+wv_ru_show(device *	dev)
+{
+  net_local *lp = (net_local *) dev->priv;
+
+  printk(KERN_DEBUG "##### wavelan i82593 receiver status: #####\n");
+  printk(KERN_DEBUG "ru: rfp %d stop %d", lp->rfp, lp->stop);
+  /*
+   * Not implemented yet...
+   */
+  printk("\n");
+} /* wv_ru_show */
+#endif	/* DEBUG_I82593_SHOW */
+
+#ifdef DEBUG_DEVICE_SHOW
+/*------------------------------------------------------------------*/
+/*
+ * Print the formatted status of the WaveLAN PCMCIA device driver.
+ */
+static void
+wv_dev_show(device *	dev)
+{
+  printk(KERN_DEBUG "dev:");
+  printk(" state=%lX,", devstate(dev));
+  printk(" trans_start=%ld,", dev->trans_start);
+  printk(" flags=0x%x,", dev->flags);
+  printk("\n");
+} /* wv_dev_show */
+
+/*------------------------------------------------------------------*/
+/*
+ * Print the formatted status of the WaveLAN PCMCIA device driver's
+ * private information.
+ */
+static void
+wv_local_show(device *	dev)
+{
+  net_local *lp;
+
+  lp = (net_local *)dev->priv;
+
+  printk(KERN_DEBUG "local:");
+  /*
+   * Not implemented yet...
+   */
+  printk("\n");
+} /* wv_local_show */
+#endif	/* DEBUG_DEVICE_SHOW */
+
+#if defined(DEBUG_RX_INFO) || defined(DEBUG_TX_INFO)
+/*------------------------------------------------------------------*/
+/*
+ * Dump packet header (and content if necessary) on the screen
+ */
+static inline void
+wv_packet_info(u_char *		p,		/* Packet to dump */
+	       int		length,		/* Length of the packet */
+	       char *		msg1,		/* Name of the device */
+	       char *		msg2)		/* Name of the function */
+{
+  int		i;
+  int		maxi;
+
+  printk(KERN_DEBUG "%s: %s(): dest %02X:%02X:%02X:%02X:%02X:%02X, length %d\n",
+	 msg1, msg2, p[0], p[1], p[2], p[3], p[4], p[5], length);
+  printk(KERN_DEBUG "%s: %s(): src %02X:%02X:%02X:%02X:%02X:%02X, type 0x%02X%02X\n",
+	 msg1, msg2, p[6], p[7], p[8], p[9], p[10], p[11], p[12], p[13]);
+
+#ifdef DEBUG_PACKET_DUMP
+
+  printk(KERN_DEBUG "data=\"");
+
+  if((maxi = length) > DEBUG_PACKET_DUMP)
+    maxi = DEBUG_PACKET_DUMP;
+  for(i = 14; i < maxi; i++)
+    if(p[i] >= ' ' && p[i] <= '~')
+      printk(" %c", p[i]);
+    else
+      printk("%02X", p[i]);
+  if(maxi < length)
+    printk("..");
+  printk("\"\n");
+  printk(KERN_DEBUG "\n");
+#endif	/* DEBUG_PACKET_DUMP */
+}
+#endif	/* defined(DEBUG_RX_INFO) || defined(DEBUG_TX_INFO) */
+
+/*------------------------------------------------------------------*/
+/*
+ * This is the information which is displayed by the driver at startup
+ * There  is a lot of flag to configure it at your will...
+ */
+static inline void
+wv_init_info(device *	dev)
+{
+  ioaddr_t	base = dev->base_addr;
+  psa_t		psa;
+  int		i;
+
+  /* Read the parameter storage area */
+  psa_read(dev, 0, (unsigned char *) &psa, sizeof(psa));
+
+#ifdef DEBUG_PSA_SHOW
+  wv_psa_show(&psa);
+#endif
+#ifdef DEBUG_MMC_SHOW
+  wv_mmc_show(dev);
+#endif
+#ifdef DEBUG_I82593_SHOW
+  wv_ru_show(dev);
+#endif
+
+#ifdef DEBUG_BASIC_SHOW
+  /* Now, let's go for the basic stuff */
+  printk(KERN_NOTICE "%s: WaveLAN: port %#x, irq %d, hw_addr",
+	 dev->name, base, dev->irq);
+  for(i = 0; i < WAVELAN_ADDR_SIZE; i++)
+    printk("%s%02X", (i == 0) ? " " : ":", dev->dev_addr[i]);
+
+  /* Print current network id */
+  if(psa.psa_nwid_select)
+    printk(", nwid 0x%02X-%02X", psa.psa_nwid[0], psa.psa_nwid[1]);
+  else
+    printk(", nwid off");
+
+  /* If 2.00 card */
+  if(!(mmc_in(base, mmroff(0, mmr_fee_status)) &
+       (MMR_FEE_STATUS_DWLD | MMR_FEE_STATUS_BUSY)))
+    {
+      unsigned short	freq;
+
+      /* Ask the EEprom to read the frequency from the first area */
+      fee_read(base, 0x00 /* 1st area - frequency... */,
+	       &freq, 1);
+
+      /* Print frequency */
+      printk(", 2.00, %ld", (freq >> 6) + 2400L);
+
+      /* Hack !!! */
+      if(freq & 0x20)
+	printk(".5");
+    }
+  else
+    {
+      printk(", PCMCIA, ");
+      switch (psa.psa_subband)
+	{
+	case PSA_SUBBAND_915:
+	  printk("915");
+	  break;
+	case PSA_SUBBAND_2425:
+	  printk("2425");
+	  break;
+	case PSA_SUBBAND_2460:
+	  printk("2460");
+	  break;
+	case PSA_SUBBAND_2484:
+	  printk("2484");
+	  break;
+	case PSA_SUBBAND_2430_5:
+	  printk("2430.5");
+	  break;
+	default:
+	  printk("???");
+	}
+    }
+
+  printk(" MHz\n");
+#endif	/* DEBUG_BASIC_SHOW */
+
+#ifdef DEBUG_VERSION_SHOW
+  /* Print version information */
+  printk(KERN_NOTICE "%s", version);
+#endif
+} /* wv_init_info */
+
+/********************* IOCTL, STATS & RECONFIG *********************/
+/*
+ * We found here routines that are called by Linux on differents
+ * occasions after the configuration and not for transmitting data
+ * These may be called when the user use ifconfig, /proc/net/dev
+ * or wireless extensions
+ */
+
+/*------------------------------------------------------------------*/
+/*
+ * Get the current ethernet statistics. This may be called with the
+ * card open or closed.
+ * Used when the user read /proc/net/dev
+ */
+static en_stats	*
+wavelan_get_stats(device *	dev)
+{
+#ifdef DEBUG_IOCTL_TRACE
+  printk(KERN_DEBUG "%s: <>wavelan_get_stats()\n", dev->name);
+#endif
+
+  return(&((net_local *) dev->priv)->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.
+ */
+
+static void
+wavelan_set_multicast_list(device *	dev)
+{
+  net_local *	lp = (net_local *) dev->priv;
+
+#ifdef DEBUG_IOCTL_TRACE
+  printk(KERN_DEBUG "%s: ->wavelan_set_multicast_list()\n", dev->name);
+#endif
+
+#ifdef DEBUG_IOCTL_INFO
+  printk(KERN_DEBUG "%s: wavelan_set_multicast_list(): setting Rx mode %02X to %d addresses.\n",
+	 dev->name, dev->flags, dev->mc_count);
+#endif
+
+  if(dev->flags & IFF_PROMISC)
+    {
+      /*
+       * Enable promiscuous mode: receive all packets.
+       */
+      if(!lp->promiscuous)
+	{
+	  lp->promiscuous = 1;
+	  lp->allmulticast = 0;
+	  lp->mc_count = 0;
+
+	  wv_82593_reconfig(dev);
+
+	  /* Tell the kernel that we are doing a really bad job... */
+	  dev->flags |= IFF_PROMISC;
+	}
+    }
+  else
+    /* If all multicast addresses
+     * or too much multicast addresses for the hardware filter */
+    if((dev->flags & IFF_ALLMULTI) ||
+       (dev->mc_count > I82593_MAX_MULTICAST_ADDRESSES))
+      {
+	/*
+	 * Disable promiscuous mode, but active the all multicast mode
+	 */
+	if(!lp->allmulticast)
+	  {
+	    lp->promiscuous = 0;
+	    lp->allmulticast = 1;
+	    lp->mc_count = 0;
+
+	    wv_82593_reconfig(dev);
+
+	    /* Tell the kernel that we are doing a really bad job... */
+	    dev->flags |= IFF_ALLMULTI;
+	  }
+      }
+    else
+      /* If there is some multicast addresses to send */
+      if(dev->mc_list != (struct dev_mc_list *) NULL)
+	{
+	  /*
+	   * Disable promiscuous mode, but receive all packets
+	   * in multicast list
+	   */
+#ifdef MULTICAST_AVOID
+	  if(lp->promiscuous || lp->allmulticast ||
+	     (dev->mc_count != lp->mc_count))
+#endif
+	    {
+	      lp->promiscuous = 0;
+	      lp->allmulticast = 0;
+	      lp->mc_count = dev->mc_count;
+
+	      wv_82593_reconfig(dev);
+	    }
+	}
+      else
+	{
+	  /*
+	   * Switch to normal mode: disable promiscuous mode and 
+	   * clear the multicast list.
+	   */
+	  if(lp->promiscuous || lp->mc_count == 0)
+	    {
+	      lp->promiscuous = 0;
+	      lp->allmulticast = 0;
+	      lp->mc_count = 0;
+
+	      wv_82593_reconfig(dev);
+	    }
+	}
+#ifdef DEBUG_IOCTL_TRACE
+  printk(KERN_DEBUG "%s: <-wavelan_set_multicast_list()\n", dev->name);
+#endif
+}
+
+/*------------------------------------------------------------------*/
+/*
+ * This function doesn't exist...
+ * (Note : it was a nice way to test the reconfigure stuff...)
+ */
+#ifdef SET_MAC_ADDRESS
+static int
+wavelan_set_mac_address(device *	dev,
+			void *		addr)
+{
+  struct sockaddr *	mac = addr;
+
+  /* Copy the address */
+  memcpy(dev->dev_addr, mac->sa_data, WAVELAN_ADDR_SIZE);
+
+  /* Reconfig the beast */
+  wv_82593_reconfig(dev);
+
+  return 0;
+}
+#endif	/* SET_MAC_ADDRESS */
+
+#ifdef WIRELESS_EXT	/* If wireless extension exist in the kernel */
+
+/*------------------------------------------------------------------*/
+/*
+ * Frequency setting (for hardware able of it)
+ * It's a bit complicated and you don't really want to look into it...
+ * (called in wavelan_ioctl)
+ */
+static inline int
+wv_set_frequency(u_long		base,	/* i/o port of the card */
+		 iw_freq *	frequency)
+{
+  const int	BAND_NUM = 10;	/* Number of bands */
+  long		freq = 0L;	/* offset to 2.4 GHz in .5 MHz */
+#ifdef DEBUG_IOCTL_INFO
+  int		i;
+#endif
+
+  /* Setting by frequency */
+  /* Theoritically, you may set any frequency between
+   * the two limits with a 0.5 MHz precision. In practice,
+   * I don't want you to have trouble with local
+   * regulations... */
+  if((frequency->e == 1) &&
+     (frequency->m >= (int) 2.412e8) && (frequency->m <= (int) 2.487e8))
+    {
+      freq = ((frequency->m / 10000) - 24000L) / 5;
+    }
+
+  /* Setting by channel (same as wfreqsel) */
+  /* Warning : each channel is 22MHz wide, so some of the channels
+   * will interfere... */
+  if((frequency->e == 0) &&
+     (frequency->m >= 0) && (frequency->m < BAND_NUM))
+    {
+      /* Get frequency offset. */
+      freq = channel_bands[frequency->m] >> 1;
+    }
+
+  /* Verify if the frequency is allowed */
+  if(freq != 0L)
+    {
+      u_short	table[10];	/* Authorized frequency table */
+
+      /* Read the frequency table */
+      fee_read(base, 0x71 /* frequency table */,
+	       table, 10);
+
+#ifdef DEBUG_IOCTL_INFO
+      printk(KERN_DEBUG "Frequency table :");
+      for(i = 0; i < 10; i++)
+	{
+	  printk(" %04X",
+		 table[i]);
+	}
+      printk("\n");
+#endif
+
+      /* Look in the table if the frequency is allowed */
+      if(!(table[9 - ((freq - 24) / 16)] &
+	   (1 << ((freq - 24) % 16))))
+	return -EINVAL;		/* not allowed */
+    }
+  else
+    return -EINVAL;
+
+  /* If we get a usable frequency */
+  if(freq != 0L)
+    {
+      unsigned short	area[16];
+      unsigned short	dac[2];
+      unsigned short	area_verify[16];
+      unsigned short	dac_verify[2];
+      /* Corresponding gain (in the power adjust value table)
+       * see AT&T Wavelan Data Manual, REF 407-024689/E, page 3-8
+       * & WCIN062D.DOC, page 6.2.9 */
+      unsigned short	power_limit[] = { 40, 80, 120, 160, 0 };
+      int		power_band = 0;		/* Selected band */
+      unsigned short	power_adjust;		/* Correct value */
+
+      /* Search for the gain */
+      power_band = 0;
+      while((freq > power_limit[power_band]) &&
+	    (power_limit[++power_band] != 0))
+	;
+
+      /* Read the first area */
+      fee_read(base, 0x00,
+	       area, 16);
+
+      /* Read the DAC */
+      fee_read(base, 0x60,
+	       dac, 2);
+
+      /* Read the new power adjust value */
+      fee_read(base, 0x6B - (power_band >> 1),
+	       &power_adjust, 1);
+      if(power_band & 0x1)
+	power_adjust >>= 8;
+      else
+	power_adjust &= 0xFF;
+
+#ifdef DEBUG_IOCTL_INFO
+      printk(KERN_DEBUG "Wavelan EEprom Area 1 :");
+      for(i = 0; i < 16; i++)
+	{
+	  printk(" %04X",
+		 area[i]);
+	}
+      printk("\n");
+
+      printk(KERN_DEBUG "Wavelan EEprom DAC : %04X %04X\n",
+	     dac[0], dac[1]);
+#endif
+
+      /* Frequency offset (for info only...) */
+      area[0] = ((freq << 5) & 0xFFE0) | (area[0] & 0x1F);
+
+      /* Receiver Principle main divider coefficient */
+      area[3] = (freq >> 1) + 2400L - 352L;
+      area[2] = ((freq & 0x1) << 4) | (area[2] & 0xFFEF);
+
+      /* Transmitter Main divider coefficient */
+      area[13] = (freq >> 1) + 2400L;
+      area[12] = ((freq & 0x1) << 4) | (area[2] & 0xFFEF);
+
+      /* Others part of the area are flags, bit streams or unused... */
+
+      /* Set the value in the DAC */
+      dac[1] = ((power_adjust >> 1) & 0x7F) | (dac[1] & 0xFF80);
+      dac[0] = ((power_adjust & 0x1) << 4) | (dac[0] & 0xFFEF);
+
+      /* Write the first area */
+      fee_write(base, 0x00,
+		area, 16);
+
+      /* Write the DAC */
+      fee_write(base, 0x60,
+		dac, 2);
+
+      /* We now should verify here that the EEprom writting was ok */
+
+      /* ReRead the first area */
+      fee_read(base, 0x00,
+	       area_verify, 16);
+
+      /* ReRead the DAC */
+      fee_read(base, 0x60,
+	       dac_verify, 2);
+
+      /* Compare */
+      if(memcmp(area, area_verify, 16 * 2) ||
+	 memcmp(dac, dac_verify, 2 * 2))
+	{
+#ifdef DEBUG_IOCTL_ERROR
+	  printk(KERN_INFO "Wavelan: wv_set_frequency : unable to write new frequency to EEprom (??)\n");
+#endif
+	  return -EOPNOTSUPP;
+	}
+
+      /* We must download the frequency parameters to the
+       * synthetisers (from the EEprom - area 1)
+       * Note : as the EEprom is auto decremented, we set the end
+       * if the area... */
+      mmc_out(base, mmwoff(0, mmw_fee_addr), 0x0F);
+      mmc_out(base, mmwoff(0, mmw_fee_ctrl),
+	      MMW_FEE_CTRL_READ | MMW_FEE_CTRL_DWLD);
+
+      /* Wait until the download is finished */
+      fee_wait(base, 100, 100);
+
+      /* We must now download the power adjust value (gain) to
+       * the synthetisers (from the EEprom - area 7 - DAC) */
+      mmc_out(base, mmwoff(0, mmw_fee_addr), 0x61);
+      mmc_out(base, mmwoff(0, mmw_fee_ctrl),
+	      MMW_FEE_CTRL_READ | MMW_FEE_CTRL_DWLD);
+
+      /* Wait until the download is finished */
+      fee_wait(base, 100, 100);
+
+#ifdef DEBUG_IOCTL_INFO
+      /* Verification of what we have done... */
+
+      printk(KERN_DEBUG "Wavelan EEprom Area 1 :");
+      for(i = 0; i < 16; i++)
+	{
+	  printk(" %04X",
+		 area_verify[i]);
+	}
+      printk("\n");
+
+      printk(KERN_DEBUG "Wavelan EEprom DAC : %04X %04X\n",
+	     dac_verify[0], dac_verify[1]);
+#endif
+
+      return 0;
+    }
+  else
+    return -EINVAL;		/* Bah, never get there... */
+}
+
+/*------------------------------------------------------------------*/
+/*
+ * Give the list of available frequencies
+ */
+static inline int
+wv_frequency_list(u_long	base,	/* i/o port of the card */
+		  iw_freq *	list,	/* List of frequency to fill */
+		  int		max)	/* Maximum number of frequencies */
+{
+  u_short	table[10];	/* Authorized frequency table */
+  long		freq = 0L;	/* offset to 2.4 GHz in .5 MHz + 12 MHz */
+  int		i;		/* index in the table */
+#if WIRELESS_EXT > 7
+  const int	BAND_NUM = 10;	/* Number of bands */
+  int		c = 0;		/* Channel number */
+#endif WIRELESS_EXT
+
+  /* Read the frequency table */
+  fee_read(base, 0x71 /* frequency table */,
+	   table, 10);
+
+  /* Look all frequencies */
+  i = 0;
+  for(freq = 0; freq < 150; freq++)
+    /* Look in the table if the frequency is allowed */
+    if(table[9 - (freq / 16)] & (1 << (freq % 16)))
+      {
+#if WIRELESS_EXT > 7
+	/* Compute approximate channel number */
+	while((((channel_bands[c] >> 1) - 24) < freq) &&
+	      (c < BAND_NUM))
+	  c++;
+	list[i].i = c;	/* Set the list index */
+#endif WIRELESS_EXT
+
+	/* put in the list */
+	list[i].m = (((freq + 24) * 5) + 24000L) * 10000;
+	list[i++].e = 1;
+
+	/* Check number */
+	if(i >= max)
+	  return(i);
+      }
+
+  return(i);
+}
+
+#ifdef WIRELESS_SPY
+/*------------------------------------------------------------------*/
+/*
+ * Gather wireless spy statistics : for each packet, compare the source
+ * address with out list, and if match, get the stats...
+ * Sorry, but this function really need wireless extensions...
+ */
+static inline void
+wl_spy_gather(device *	dev,
+	      u_char *	mac,		/* MAC address */
+	      u_char *	stats)		/* Statistics to gather */
+{
+  net_local *	lp = (net_local *) dev->priv;
+  int		i;
+
+  /* Look all addresses */
+  for(i = 0; i < lp->spy_number; i++)
+    /* If match */
+    if(!memcmp(mac, lp->spy_address[i], WAVELAN_ADDR_SIZE))
+      {
+	/* Update statistics */
+	lp->spy_stat[i].qual = stats[2] & MMR_SGNL_QUAL;
+	lp->spy_stat[i].level = stats[0] & MMR_SIGNAL_LVL;
+	lp->spy_stat[i].noise = stats[1] & MMR_SILENCE_LVL;
+	lp->spy_stat[i].updated = 0x7;
+      }
+}
+#endif	/* WIRELESS_SPY */
+
+#ifdef HISTOGRAM
+/*------------------------------------------------------------------*/
+/*
+ * This function calculate an histogram on the signal level.
+ * As the noise is quite constant, it's like doing it on the SNR.
+ * We have defined a set of interval (lp->his_range), and each time
+ * the level goes in that interval, we increment the count (lp->his_sum).
+ * With this histogram you may detect if one wavelan is really weak,
+ * or you may also calculate the mean and standard deviation of the level...
+ */
+static inline void
+wl_his_gather(device *	dev,
+	      u_char *	stats)		/* Statistics to gather */
+{
+  net_local *	lp = (net_local *) dev->priv;
+  u_char	level = stats[0] & MMR_SIGNAL_LVL;
+  int		i;
+
+  /* Find the correct interval */
+  i = 0;
+  while((i < (lp->his_number - 1)) && (level >= lp->his_range[i++]))
+    ;
+
+  /* Increment interval counter */
+  (lp->his_sum[i])++;
+}
+#endif	/* HISTOGRAM */
+
+/*------------------------------------------------------------------*/
+/*
+ * Perform ioctl : config & info stuff
+ * This is here that are treated the wireless extensions (iwconfig)
+ */
+static int
+wavelan_ioctl(struct net_device *	dev,	/* Device on wich the ioctl apply */
+	      struct ifreq *	rq,	/* Data passed */
+	      int		cmd)	/* Ioctl number */
+{
+  ioaddr_t		base = dev->base_addr;
+  net_local *		lp = (net_local *)dev->priv;	/* lp is not unused */
+  struct iwreq *	wrq = (struct iwreq *) rq;
+  psa_t			psa;
+  mm_t			m;
+  unsigned long		flags;
+  int			ret = 0;
+
+#ifdef DEBUG_IOCTL_TRACE
+  printk(KERN_DEBUG "%s: ->wavelan_ioctl(cmd=0x%X)\n", dev->name, cmd);
+#endif
+
+  /* Disable interrupts & save flags */
+  wv_splhi(lp, &flags);
+
+  /* Look what is the request */
+  switch(cmd)
+    {
+      /* --------------- WIRELESS EXTENSIONS --------------- */
+
+    case SIOCGIWNAME:
+      strcpy(wrq->u.name, "Wavelan");
+      break;
+
+    case SIOCSIWNWID:
+      /* Set NWID in wavelan */
+#if WIRELESS_EXT > 8
+      if(!wrq->u.nwid.disabled)
+	{
+	  /* Set NWID in psa */
+	  psa.psa_nwid[0] = (wrq->u.nwid.value & 0xFF00) >> 8;
+	  psa.psa_nwid[1] = wrq->u.nwid.value & 0xFF;
+#else	/* WIRELESS_EXT > 8 */
+      if(wrq->u.nwid.on)
+	{
+	  /* Set NWID in psa */
+	  psa.psa_nwid[0] = (wrq->u.nwid.nwid & 0xFF00) >> 8;
+	  psa.psa_nwid[1] = wrq->u.nwid.nwid & 0xFF;
+#endif	/* WIRELESS_EXT > 8 */
+	  psa.psa_nwid_select = 0x01;
+	  psa_write(dev, (char *)psa.psa_nwid - (char *)&psa,
+		    (unsigned char *)psa.psa_nwid, 3);
+
+	  /* Set NWID in mmc */
+	  m.w.mmw_netw_id_l = psa.psa_nwid[1];
+	  m.w.mmw_netw_id_h = psa.psa_nwid[0];
+	  mmc_write(base, (char *)&m.w.mmw_netw_id_l - (char *)&m,
+		    (unsigned char *)&m.w.mmw_netw_id_l, 2);
+	  mmc_out(base, mmwoff(0, mmw_loopt_sel), 0x00);
+	}
+      else
+	{
+	  /* Disable nwid in the psa */
+	  psa.psa_nwid_select = 0x00;
+	  psa_write(dev, (char *)&psa.psa_nwid_select - (char *)&psa,
+		    (unsigned char *)&psa.psa_nwid_select, 1);
+
+	  /* Disable nwid in the mmc (no filtering) */
+	  mmc_out(base, mmwoff(0, mmw_loopt_sel), MMW_LOOPT_SEL_DIS_NWID);
+	}
+      /* update the Wavelan checksum */
+      update_psa_checksum(dev);
+      break;
+
+    case SIOCGIWNWID:
+      /* Read the NWID */
+      psa_read(dev, (char *)psa.psa_nwid - (char *)&psa,
+	       (unsigned char *)psa.psa_nwid, 3);
+#if WIRELESS_EXT > 8
+      wrq->u.nwid.value = (psa.psa_nwid[0] << 8) + psa.psa_nwid[1];
+      wrq->u.nwid.disabled = !(psa.psa_nwid_select);
+      wrq->u.nwid.fixed = 1;	/* Superfluous */
+#else	/* WIRELESS_EXT > 8 */
+      wrq->u.nwid.nwid = (psa.psa_nwid[0] << 8) + psa.psa_nwid[1];
+      wrq->u.nwid.on = psa.psa_nwid_select;
+#endif	/* WIRELESS_EXT > 8 */
+      break;
+
+    case SIOCSIWFREQ:
+      /* Attempt to recognise 2.00 cards (2.4 GHz frequency selectable) */
+      if(!(mmc_in(base, mmroff(0, mmr_fee_status)) &
+	   (MMR_FEE_STATUS_DWLD | MMR_FEE_STATUS_BUSY)))
+	ret = wv_set_frequency(base, &(wrq->u.freq));
+      else
+	ret = -EOPNOTSUPP;
+      break;
+
+    case SIOCGIWFREQ:
+      /* Attempt to recognise 2.00 cards (2.4 GHz frequency selectable)
+       * (does it work for everybody ??? - especially old cards...) */
+      if(!(mmc_in(base, mmroff(0, mmr_fee_status)) &
+	   (MMR_FEE_STATUS_DWLD | MMR_FEE_STATUS_BUSY)))
+	{
+	  unsigned short	freq;
+
+	  /* Ask the EEprom to read the frequency from the first area */
+	  fee_read(base, 0x00 /* 1st area - frequency... */,
+		   &freq, 1);
+	  wrq->u.freq.m = ((freq >> 5) * 5 + 24000L) * 10000;
+	  wrq->u.freq.e = 1;
+	}
+      else
+	{
+	  psa_read(dev, (char *)&psa.psa_subband - (char *)&psa,
+		   (unsigned char *)&psa.psa_subband, 1);
+
+	  if(psa.psa_subband <= 4)
+	    {
+	      wrq->u.freq.m = fixed_bands[psa.psa_subband];
+	      wrq->u.freq.e = (psa.psa_subband != 0);
+	    }
+	  else
+	    ret = -EOPNOTSUPP;
+	}
+      break;
+
+    case SIOCSIWSENS:
+      /* Set the level threshold */
+#if WIRELESS_EXT > 7
+      /* We should complain loudly if wrq->u.sens.fixed = 0, because we
+       * can't set auto mode... */
+      psa.psa_thr_pre_set = wrq->u.sens.value & 0x3F;
+#else	/* WIRELESS_EXT > 7 */
+      psa.psa_thr_pre_set = wrq->u.sensitivity & 0x3F;
+#endif	/* WIRELESS_EXT > 7 */
+      psa_write(dev, (char *)&psa.psa_thr_pre_set - (char *)&psa,
+	       (unsigned char *)&psa.psa_thr_pre_set, 1);
+      /* update the Wavelan checksum */
+      update_psa_checksum(dev);
+      mmc_out(base, mmwoff(0, mmw_thr_pre_set), psa.psa_thr_pre_set);
+      break;
+
+    case SIOCGIWSENS:
+      /* Read the level threshold */
+      psa_read(dev, (char *)&psa.psa_thr_pre_set - (char *)&psa,
+	       (unsigned char *)&psa.psa_thr_pre_set, 1);
+#if WIRELESS_EXT > 7
+      wrq->u.sens.value = psa.psa_thr_pre_set & 0x3F;
+      wrq->u.sens.fixed = 1;
+#else	/* WIRELESS_EXT > 7 */
+      wrq->u.sensitivity = psa.psa_thr_pre_set & 0x3F;
+#endif	/* WIRELESS_EXT > 7 */
+      break;
+
+#if WIRELESS_EXT > 8
+    case SIOCSIWENCODE:
+      /* Set encryption key */
+      if(!mmc_encr(base))
+	{
+	  ret = -EOPNOTSUPP;
+	  break;
+	}
+
+      /* Basic checking... */
+      if(wrq->u.encoding.pointer != (caddr_t) 0)
+	{
+	  /* Check the size of the key */
+	  if(wrq->u.encoding.length != 8)
+	    {
+	      ret = -EINVAL;
+	      break;
+	    }
+
+	  /* Copy the key in the driver */
+	  if(copy_from_user(psa.psa_encryption_key, wrq->u.encoding.pointer,
+			    wrq->u.encoding.length))
+	    {
+	      ret = -EFAULT;
+	      break;
+	    }
+
+	  psa.psa_encryption_select = 1;
+	  psa_write(dev, (char *) &psa.psa_encryption_select - (char *) &psa,
+		    (unsigned char *) &psa.psa_encryption_select, 8+1);
+
+	  mmc_out(base, mmwoff(0, mmw_encr_enable),
+		  MMW_ENCR_ENABLE_EN | MMW_ENCR_ENABLE_MODE);
+	  mmc_write(base, mmwoff(0, mmw_encr_key),
+		    (unsigned char *) &psa.psa_encryption_key, 8);
+	}
+
+      if(wrq->u.encoding.flags & IW_ENCODE_DISABLED)
+	{	/* disable encryption */
+	  psa.psa_encryption_select = 0;
+	  psa_write(dev, (char *) &psa.psa_encryption_select - (char *) &psa,
+		    (unsigned char *) &psa.psa_encryption_select, 1);
+
+	  mmc_out(base, mmwoff(0, mmw_encr_enable), 0);
+	}
+      /* update the Wavelan checksum */
+      update_psa_checksum(dev);
+      break;
+
+    case SIOCGIWENCODE:
+      /* Read the encryption key */
+      if(!mmc_encr(base))
+	{
+	  ret = -EOPNOTSUPP;
+	  break;
+	}
+
+      /* only super-user can see encryption key */
+      if(!capable(CAP_NET_ADMIN))
+	{
+	  ret = -EPERM;
+	  break;
+	}
+
+      /* Basic checking... */
+      if(wrq->u.encoding.pointer != (caddr_t) 0)
+	{
+	  psa_read(dev, (char *) &psa.psa_encryption_select - (char *) &psa,
+		   (unsigned char *) &psa.psa_encryption_select, 1+8);
+
+	  /* encryption is enabled ? */
+	  if(psa.psa_encryption_select)
+	    wrq->u.encoding.flags = IW_ENCODE_ENABLED;
+	  else
+	    wrq->u.encoding.flags = IW_ENCODE_DISABLED;
+	  wrq->u.encoding.flags |= mmc_encr(base);
+
+	  /* Copy the key to the user buffer */
+	  wrq->u.encoding.length = 8;
+	  if(copy_to_user(wrq->u.encoding.pointer, psa.psa_encryption_key, 8))
+	    ret = -EFAULT;
+	}
+      break;
+#endif	/* WIRELESS_EXT > 8 */
+
+#ifdef WAVELAN_ROAMING_EXT
+#if WIRELESS_EXT > 5
+    case SIOCSIWESSID:
+      /* Check if disable */
+      if(wrq->u.data.flags == 0)
+	lp->filter_domains = 0;
+      else
+	/* Basic checking... */
+	if(wrq->u.data.pointer != (caddr_t) 0)
+	  {
+	    char	essid[IW_ESSID_MAX_SIZE + 1];
+	    char *	endp;
+
+	    /* Check the size of the string */
+	    if(wrq->u.data.length > IW_ESSID_MAX_SIZE + 1)
+	      {
+		ret = -E2BIG;
+		break;
+	      }
+
+	    /* Copy the string in the driver */
+	    if(copy_from_user(essid, wrq->u.data.pointer, wrq->u.data.length))
+	      {
+		ret = -EFAULT;
+		break;
+	      }
+	    essid[IW_ESSID_MAX_SIZE] = '\0';
+
+#ifdef DEBUG_IOCTL_INFO
+	    printk(KERN_DEBUG "SetEssid : ``%s''\n", essid);
+#endif	/* DEBUG_IOCTL_INFO */
+
+	    /* Convert to a number (note : Wavelan specific) */
+	    lp->domain_id = simple_strtoul(essid, &endp, 16);
+	    /* Has it worked  ? */
+	    if(endp > essid)
+	      lp->filter_domains = 1;
+	    else
+	      {
+		lp->filter_domains = 0;
+		ret = -EINVAL;
+	      }
+	  }
+      break;
+
+    case SIOCGIWESSID:
+      /* Basic checking... */
+      if(wrq->u.data.pointer != (caddr_t) 0)
+	{
+	  char		essid[IW_ESSID_MAX_SIZE + 1];
+
+	  /* Is the domain ID active ? */
+	  wrq->u.data.flags = lp->filter_domains;
+
+	  /* Copy Domain ID into a string (Wavelan specific) */
+	  /* Sound crazy, be we can't have a snprintf in the kernel !!! */
+	  sprintf(essid, "%lX", lp->domain_id);
+	  essid[IW_ESSID_MAX_SIZE] = '\0';
+
+	  /* Set the length */
+	  wrq->u.data.length = strlen(essid) + 1;
+
+	  /* Copy structure to the user buffer */
+	  if(copy_to_user(wrq->u.data.pointer, essid, wrq->u.data.length))
+	    ret = -EFAULT;
+	}
+      break;
+
+    case SIOCSIWAP:
+#ifdef DEBUG_IOCTL_INFO
+      printk(KERN_DEBUG "Set AP to : %02X:%02X:%02X:%02X:%02X:%02X\n",
+	     wrq->u.ap_addr.sa_data[0],
+	     wrq->u.ap_addr.sa_data[1],
+	     wrq->u.ap_addr.sa_data[2],
+	     wrq->u.ap_addr.sa_data[3],
+	     wrq->u.ap_addr.sa_data[4],
+	     wrq->u.ap_addr.sa_data[5]);
+#endif	/* DEBUG_IOCTL_INFO */
+
+      ret = -EOPNOTSUPP;	/* Not supported yet */
+      break;
+
+    case SIOCGIWAP:
+      /* Should get the real McCoy instead of own Ethernet address */
+      memcpy(wrq->u.ap_addr.sa_data, dev->dev_addr, WAVELAN_ADDR_SIZE);
+      wrq->u.ap_addr.sa_family = ARPHRD_ETHER;
+
+      ret = -EOPNOTSUPP;	/* Not supported yet */
+      break;
+#endif	/* WIRELESS_EXT > 5 */
+#endif	/* WAVELAN_ROAMING_EXT */
+
+#if WIRELESS_EXT > 8
+#ifdef WAVELAN_ROAMING
+    case SIOCSIWMODE:
+      switch(wrq->u.mode)
+	{
+	case IW_MODE_ADHOC:
+	  if(do_roaming)
+	    {
+	      wv_roam_cleanup(dev);
+	      do_roaming = 0;
+	    }
+	  break;
+	case IW_MODE_INFRA:
+	  if(!do_roaming)
+	    {
+	      wv_roam_init(dev);
+	      do_roaming = 1;
+	    }
+	  break;
+	default:
+	  ret = -EINVAL;
+	}
+      break;
+
+    case SIOCGIWMODE:
+      if(do_roaming)
+	wrq->u.mode = IW_MODE_INFRA;
+      else
+	wrq->u.mode = IW_MODE_ADHOC;
+      break;
+#endif	/* WAVELAN_ROAMING */
+#endif /* WIRELESS_EXT > 8 */
+
+    case SIOCGIWRANGE:
+      /* Basic checking... */
+      if(wrq->u.data.pointer != (caddr_t) 0)
+	{
+	  struct iw_range	range;
+
+	  /* Set the length (useless : its constant...) */
+	  wrq->u.data.length = sizeof(struct iw_range);
+
+	  /* Set information in the range struct */
+	  range.throughput = 1.4 * 1000 * 1000;	/* don't argue on this ! */
+	  range.min_nwid = 0x0000;
+	  range.max_nwid = 0xFFFF;
+
+	  /* Attempt to recognise 2.00 cards (2.4 GHz frequency selectable) */
+	  if(!(mmc_in(base, mmroff(0, mmr_fee_status)) &
+	       (MMR_FEE_STATUS_DWLD | MMR_FEE_STATUS_BUSY)))
+	    {
+	      range.num_channels = 10;
+	      range.num_frequency = wv_frequency_list(base, range.freq,
+						      IW_MAX_FREQUENCIES);
+	    }
+	  else
+	    range.num_channels = range.num_frequency = 0;
+
+	  range.sensitivity = 0x3F;
+	  range.max_qual.qual = MMR_SGNL_QUAL;
+	  range.max_qual.level = MMR_SIGNAL_LVL;
+	  range.max_qual.noise = MMR_SILENCE_LVL;
+
+#if WIRELESS_EXT > 7
+	  range.num_bitrates = 1;
+	  range.bitrate[0] = 2000000;	/* 2 Mb/s */
+#endif /* WIRELESS_EXT > 7 */
+
+#if WIRELESS_EXT > 8
+	  /* Encryption supported ? */
+	  if(mmc_encr(base))
+	    {
+	      range.encoding_size[0] = 8;	/* DES = 64 bits key */
+	      range.num_encoding_sizes = 1;
+	      range.max_encoding_tokens = 1;	/* Only one key possible */
+	    }
+	  else
+	    {
+	      range.num_encoding_sizes = 0;
+	      range.max_encoding_tokens = 0;
+	    }
+#endif /* WIRELESS_EXT > 8 */
+
+	  /* Copy structure to the user buffer */
+	  if(copy_to_user(wrq->u.data.pointer, &range,
+			  sizeof(struct iw_range)))
+	    ret = -EFAULT;
+	}
+      break;
+
+    case SIOCGIWPRIV:
+      /* Basic checking... */
+      if(wrq->u.data.pointer != (caddr_t) 0)
+	{
+	  struct iw_priv_args	priv[] =
+	  {	/* cmd,		set_args,	get_args,	name */
+	    { SIOCSIPQTHR, IW_PRIV_TYPE_BYTE | IW_PRIV_SIZE_FIXED | 1, 0, "setqualthr" },
+	    { SIOCGIPQTHR, 0, IW_PRIV_TYPE_BYTE | IW_PRIV_SIZE_FIXED | 1, "getqualthr" },
+	    { SIOCSIPHISTO, IW_PRIV_TYPE_BYTE | 16,	0, "sethisto" },
+	    { SIOCGIPHISTO, 0,	    IW_PRIV_TYPE_INT | 16, "gethisto" },
+	    { SIOCSIPROAM, IW_PRIV_TYPE_BYTE | IW_PRIV_SIZE_FIXED | 1 , 0, "setroam" },
+	    { SIOCGIPROAM, 0, IW_PRIV_TYPE_BYTE | IW_PRIV_SIZE_FIXED | 1, "getroam" },
+	  };
+
+	  /* Set the number of ioctl available */
+	  wrq->u.data.length = 6;
+
+	  /* Copy structure to the user buffer */
+	  if(copy_to_user(wrq->u.data.pointer, (u_char *) priv,
+		       sizeof(priv)))
+	    ret = -EFAULT;
+	}
+      break;
+
+#ifdef WIRELESS_SPY
+    case SIOCSIWSPY:
+      /* Set the spy list */
+
+      /* Check the number of addresses */
+      if(wrq->u.data.length > IW_MAX_SPY)
+	{
+	  ret = -E2BIG;
+	  break;
+	}
+      lp->spy_number = wrq->u.data.length;
+
+      /* If there is some addresses to copy */
+      if(lp->spy_number > 0)
+	{
+	  struct sockaddr	address[IW_MAX_SPY];
+	  int			i;
+
+	  /* Copy addresses to the driver */
+	  if(copy_from_user(address, wrq->u.data.pointer,
+			    sizeof(struct sockaddr) * lp->spy_number))
+	    {
+	      ret = -EFAULT;
+	      break;
+	    }
+
+	  /* Copy addresses to the lp structure */
+	  for(i = 0; i < lp->spy_number; i++)
+	    {
+	      memcpy(lp->spy_address[i], address[i].sa_data,
+		     WAVELAN_ADDR_SIZE);
+	    }
+
+	  /* Reset structure... */
+	  memset(lp->spy_stat, 0x00, sizeof(iw_qual) * IW_MAX_SPY);
+
+#ifdef DEBUG_IOCTL_INFO
+	  printk(KERN_DEBUG "SetSpy - Set of new addresses is :\n");
+	  for(i = 0; i < wrq->u.data.length; i++)
+	    printk(KERN_DEBUG "%02X:%02X:%02X:%02X:%02X:%02X\n",
+		   lp->spy_address[i][0],
+		   lp->spy_address[i][1],
+		   lp->spy_address[i][2],
+		   lp->spy_address[i][3],
+		   lp->spy_address[i][4],
+		   lp->spy_address[i][5]);
+#endif	/* DEBUG_IOCTL_INFO */
+	}
+
+      break;
+
+    case SIOCGIWSPY:
+      /* Get the spy list and spy stats */
+
+      /* Set the number of addresses */
+      wrq->u.data.length = lp->spy_number;
+
+      /* If the user want to have the addresses back... */
+      if((lp->spy_number > 0) && (wrq->u.data.pointer != (caddr_t) 0))
+	{
+	  struct sockaddr	address[IW_MAX_SPY];
+	  int			i;
+
+	  /* Copy addresses from the lp structure */
+	  for(i = 0; i < lp->spy_number; i++)
+	    {
+	      memcpy(address[i].sa_data, lp->spy_address[i],
+		     WAVELAN_ADDR_SIZE);
+	      address[i].sa_family = ARPHRD_ETHER;
+	    }
+
+	  /* Copy addresses to the user buffer */
+	  if(copy_to_user(wrq->u.data.pointer, address,
+		       sizeof(struct sockaddr) * lp->spy_number))
+	    {
+	      ret = -EFAULT;
+	      break;
+	    }
+
+	  /* Copy stats to the user buffer (just after) */
+	  if(copy_to_user(wrq->u.data.pointer +
+		       (sizeof(struct sockaddr) * lp->spy_number),
+		       lp->spy_stat, sizeof(iw_qual) * lp->spy_number))
+	    {
+	      ret = -EFAULT;
+	      break;
+	    }
+
+	  /* Reset updated flags */
+	  for(i = 0; i < lp->spy_number; i++)
+	    lp->spy_stat[i].updated = 0x0;
+	}	/* if(pointer != NULL) */
+
+      break;
+#endif	/* WIRELESS_SPY */
+
+      /* ------------------ PRIVATE IOCTL ------------------ */
+
+    case SIOCSIPQTHR:
+      if(!capable(CAP_NET_ADMIN))
+	{
+	  ret = -EPERM;
+	  break;
+	}
+      psa.psa_quality_thr = *(wrq->u.name) & 0x0F;
+      psa_write(dev, (char *)&psa.psa_quality_thr - (char *)&psa,
+	       (unsigned char *)&psa.psa_quality_thr, 1);
+      /* update the Wavelan checksum */
+      update_psa_checksum(dev);
+      mmc_out(base, mmwoff(0, mmw_quality_thr), psa.psa_quality_thr);
+      break;
+
+    case SIOCGIPQTHR:
+      psa_read(dev, (char *)&psa.psa_quality_thr - (char *)&psa,
+	       (unsigned char *)&psa.psa_quality_thr, 1);
+      *(wrq->u.name) = psa.psa_quality_thr & 0x0F;
+      break;
+
+#ifdef WAVELAN_ROAMING
+    case SIOCSIPROAM:
+      /* Note : should check if user == root */
+      if(do_roaming && (*wrq->u.name)==0)
+	wv_roam_cleanup(dev);
+      else if(do_roaming==0 && (*wrq->u.name)!=0)
+	wv_roam_init(dev);
+
+      do_roaming = (*wrq->u.name);
+	  
+      break;
+
+    case SIOCGIPROAM:
+      *(wrq->u.name) = do_roaming;
+      break;
+#endif	/* WAVELAN_ROAMING */
+
+#ifdef HISTOGRAM
+    case SIOCSIPHISTO:
+      /* Verif if the user is root */
+      if(!capable(CAP_NET_ADMIN))
+	{
+	  ret = -EPERM;
+	}
+
+      /* Check the number of intervals */
+      if(wrq->u.data.length > 16)
+	{
+	  ret = -E2BIG;
+	  break;
+	}
+      lp->his_number = wrq->u.data.length;
+
+      /* If there is some addresses to copy */
+      if(lp->his_number > 0)
+	{
+	  /* Copy interval ranges to the driver */
+	  if(copy_from_user(lp->his_range, wrq->u.data.pointer,
+			 sizeof(char) * lp->his_number))
+	    {
+	      ret = -EFAULT;
+	      break;
+	    }
+
+	  /* Reset structure... */
+	  memset(lp->his_sum, 0x00, sizeof(long) * 16);
+	}
+      break;
+
+    case SIOCGIPHISTO:
+      /* Set the number of intervals */
+      wrq->u.data.length = lp->his_number;
+
+      /* Give back the distribution statistics */
+      if((lp->his_number > 0) && (wrq->u.data.pointer != (caddr_t) 0))
+	{
+	  /* Copy data to the user buffer */
+	  if(copy_to_user(wrq->u.data.pointer, lp->his_sum,
+		       sizeof(long) * lp->his_number))
+	    ret = -EFAULT;
+
+	}	/* if(pointer != NULL) */
+      break;
+#endif	/* HISTOGRAM */
+
+      /* ------------------- OTHER IOCTL ------------------- */
+
+    default:
+      ret = -EOPNOTSUPP;
+    }
+
+  /* ReEnable interrupts & restore flags */
+  wv_splx(lp, &flags);
+
+#ifdef DEBUG_IOCTL_TRACE
+  printk(KERN_DEBUG "%s: <-wavelan_ioctl()\n", dev->name);
+#endif
+  return ret;
+}
+
+/*------------------------------------------------------------------*/
+/*
+ * Get wireless statistics
+ * Called by /proc/net/wireless...
+ */
+static iw_stats *
+wavelan_get_wireless_stats(device *	dev)
+{
+  ioaddr_t		base = dev->base_addr;
+  net_local *		lp = (net_local *) dev->priv;
+  mmr_t			m;
+  iw_stats *		wstats;
+  unsigned long		flags;
+
+#ifdef DEBUG_IOCTL_TRACE
+  printk(KERN_DEBUG "%s: ->wavelan_get_wireless_stats()\n", dev->name);
+#endif
+
+  /* Paranoia */
+  if(lp == (net_local *) NULL)
+    return (iw_stats *) NULL;
+
+  /* Disable interrupts & save flags */
+  wv_splhi(lp, &flags);
+
+  wstats = &lp->wstats;
+
+  /* Get data from the mmc */
+  mmc_out(base, mmwoff(0, mmw_freeze), 1);
+
+  mmc_read(base, mmroff(0, mmr_dce_status), &m.mmr_dce_status, 1);
+  mmc_read(base, mmroff(0, mmr_wrong_nwid_l), &m.mmr_wrong_nwid_l, 2);
+  mmc_read(base, mmroff(0, mmr_thr_pre_set), &m.mmr_thr_pre_set, 4);
+
+  mmc_out(base, mmwoff(0, mmw_freeze), 0);
+
+  /* Copy data to wireless stuff */
+  wstats->status = m.mmr_dce_status & MMR_DCE_STATUS;
+  wstats->qual.qual = m.mmr_sgnl_qual & MMR_SGNL_QUAL;
+  wstats->qual.level = m.mmr_signal_lvl & MMR_SIGNAL_LVL;
+  wstats->qual.noise = m.mmr_silence_lvl & MMR_SILENCE_LVL;
+  wstats->qual.updated = (((m.mmr_signal_lvl & MMR_SIGNAL_LVL_VALID) >> 7) |
+			  ((m.mmr_signal_lvl & MMR_SIGNAL_LVL_VALID) >> 6) |
+			  ((m.mmr_silence_lvl & MMR_SILENCE_LVL_VALID) >> 5));
+  wstats->discard.nwid += (m.mmr_wrong_nwid_h << 8) | m.mmr_wrong_nwid_l;
+  wstats->discard.code = 0L;
+  wstats->discard.misc = 0L;
+
+  /* ReEnable interrupts & restore flags */
+  wv_splx(lp, &flags);
+
+#ifdef DEBUG_IOCTL_TRACE
+  printk(KERN_DEBUG "%s: <-wavelan_get_wireless_stats()\n", dev->name);
+#endif
+  return &lp->wstats;
+}
+#endif	/* WIRELESS_EXT */
+
+/************************* PACKET RECEPTION *************************/
+/*
+ * This part deal with receiving the packets.
+ * The interrupt handler get an interrupt when a packet has been
+ * successfully received and called this part...
+ */
+
+/*------------------------------------------------------------------*/
+/*
+ * Calculate the starting address of the frame pointed to by the receive
+ * frame pointer and verify that the frame seem correct
+ * (called by wv_packet_rcv())
+ */
+static inline int
+wv_start_of_frame(device *	dev,
+		  int		rfp,	/* end of frame */
+		  int		wrap)	/* start of buffer */
+{
+  ioaddr_t	base = dev->base_addr;
+  int		rp;
+  int		len;
+
+  rp = (rfp - 5 + RX_SIZE) % RX_SIZE;
+  outb(rp & 0xff, PIORL(base));
+  outb(((rp >> 8) & PIORH_MASK), PIORH(base));
+  len = inb(PIOP(base));
+  len |= inb(PIOP(base)) << 8;
+
+  /* Sanity checks on size */
+  /* Frame too big */
+  if(len > MAXDATAZ + 100)
+    {
+#ifdef DEBUG_RX_ERROR
+      printk(KERN_INFO "%s: wv_start_of_frame: Received frame too large, rfp %d len 0x%x\n",
+	     dev->name, rfp, len);
+#endif
+      return(-1);
+    }
+  
+  /* Frame too short */
+  if(len < 7)
+    {
+#ifdef DEBUG_RX_ERROR
+      printk(KERN_INFO "%s: wv_start_of_frame: Received null frame, rfp %d len 0x%x\n",
+	     dev->name, rfp, len);
+#endif
+      return(-1);
+    }
+  
+  /* Wrap around buffer */
+  if(len > ((wrap - (rfp - len) + RX_SIZE) % RX_SIZE))	/* magic formula ! */
+    {
+#ifdef DEBUG_RX_ERROR
+      printk(KERN_INFO "%s: wv_start_of_frame: wrap around buffer, wrap %d rfp %d len 0x%x\n",
+	     dev->name, wrap, rfp, len);
+#endif
+      return(-1);
+    }
+
+  return((rp - len + RX_SIZE) % RX_SIZE);
+} /* wv_start_of_frame */
+
+/*------------------------------------------------------------------*/
+/*
+ * This routine does the actual copy of data (including the ethernet
+ * header structure) from the WaveLAN card to an sk_buff chain that
+ * will be passed up to the network interface layer. NOTE: We
+ * currently don't handle trailer protocols (neither does the rest of
+ * the network interface), so if that is needed, it will (at least in
+ * part) be added here.  The contents of the receive ring buffer are
+ * copied to a message chain that is then passed to the kernel.
+ *
+ * Note: if any errors occur, the packet is "dropped on the floor"
+ * (called by wv_packet_rcv())
+ */
+static inline void
+wv_packet_read(device *		dev,
+	       int		fd_p,
+	       int		sksize)
+{
+  net_local *		lp = (net_local *) dev->priv;
+  struct sk_buff *	skb;
+
+#ifdef DEBUG_RX_TRACE
+  printk(KERN_DEBUG "%s: ->wv_packet_read(0x%X, %d)\n",
+	 dev->name, fd_p, sksize);
+#endif
+
+  /* Allocate some buffer for the new packet */
+  if((skb = dev_alloc_skb(sksize+2)) == (struct sk_buff *) NULL)
+    {
+#ifdef DEBUG_RX_ERROR
+      printk(KERN_INFO "%s: wv_packet_read(): could not alloc_skb(%d, GFP_ATOMIC)\n",
+	     dev->name, sksize);
+#endif
+      lp->stats.rx_dropped++;
+      /*
+       * Not only do we want to return here, but we also need to drop the
+       * packet on the floor to clear the interrupt.
+       */
+      return;
+    }
+
+  skb->dev = dev;
+
+  skb_reserve(skb, 2);
+  fd_p = read_ringbuf(dev, fd_p, (char *) skb_put(skb, sksize), sksize);
+  skb->protocol = eth_type_trans(skb, dev);
+
+#ifdef DEBUG_RX_INFO
+  wv_packet_info(skb->mac.raw, sksize, dev->name, "wv_packet_read");
+#endif	/* DEBUG_RX_INFO */
+     
+  /* Statistics gathering & stuff associated.
+   * It seem a bit messy with all the define, but it's really simple... */
+  if(
+#ifdef WIRELESS_SPY
+     (lp->spy_number > 0) ||
+#endif	/* WIRELESS_SPY */
+#ifdef HISTOGRAM
+     (lp->his_number > 0) ||
+#endif	/* HISTOGRAM */
+#ifdef WAVELAN_ROAMING
+     (do_roaming) ||
+#endif	/* WAVELAN_ROAMING */
+     0)
+    {
+      u_char	stats[3];	/* Signal level, Noise level, Signal quality */
+
+      /* read signal level, silence level and signal quality bytes */
+      fd_p = read_ringbuf(dev, (fd_p + 4) % RX_SIZE + RX_BASE,
+			  stats, 3);
+#ifdef DEBUG_RX_INFO
+      printk(KERN_DEBUG "%s: wv_packet_read(): Signal level %d/63, Silence level %d/63, signal quality %d/16\n",
+	     dev->name, stats[0] & 0x3F, stats[1] & 0x3F, stats[2] & 0x0F);
+#endif
+
+#ifdef WAVELAN_ROAMING
+      if(do_roaming)
+	if(WAVELAN_BEACON(skb->data))
+	  wl_roam_gather(dev, skb->data, stats);
+#endif	/* WAVELAN_ROAMING */
+	  
+#ifdef WIRELESS_SPY
+      wl_spy_gather(dev, skb->mac.raw + WAVELAN_ADDR_SIZE, stats);
+#endif	/* WIRELESS_SPY */
+#ifdef HISTOGRAM
+      wl_his_gather(dev, stats);
+#endif	/* HISTOGRAM */
+    }
+
+  /*
+   * Hand the packet to the Network Module
+   */
+  netif_rx(skb);
+
+  /* Keep stats up to date */
+  lp->stats.rx_packets++;
+  add_rx_bytes(&lp->stats, skb->len);
+
+#ifdef DEBUG_RX_TRACE
+  printk(KERN_DEBUG "%s: <-wv_packet_read()\n", dev->name);
+#endif
+  return;
+}
+
+/*------------------------------------------------------------------*/
+/*
+ * This routine is called by the interrupt handler to initiate a
+ * packet transfer from the card to the network interface layer above
+ * this driver.  This routine checks if a buffer has been successfully
+ * received by the WaveLAN card.  If so, the routine wv_packet_read is
+ * called to do the actual transfer of the card's data including the
+ * ethernet header into a packet consisting of an sk_buff chain.
+ * (called by wavelan_interrupt())
+ * Note : the spinlock is already grabbed for us and irq are disabled.
+ */
+static inline void
+wv_packet_rcv(device *	dev)
+{
+  ioaddr_t	base = dev->base_addr;
+  net_local *	lp = (net_local *) dev->priv;
+  int		newrfp;
+  int		rp;
+  int		len;
+  int		f_start;
+  int		status;
+  int		i593_rfp;
+  int		stat_ptr;
+  u_char	c[4];
+
+#ifdef DEBUG_RX_TRACE
+  printk(KERN_DEBUG "%s: ->wv_packet_rcv()\n", dev->name);
+#endif
+
+  /* Get the new receive frame pointer from the i82593 chip */
+  outb(CR0_STATUS_2 | OP0_NOP, LCCR(base));
+  i593_rfp = inb(LCSR(base));
+  i593_rfp |= inb(LCSR(base)) << 8;
+  i593_rfp %= RX_SIZE;
+
+  /* Get the new receive frame pointer from the WaveLAN card.
+   * It is 3 bytes more than the increment of the i82593 receive
+   * frame pointer, for each packet. This is because it includes the
+   * 3 roaming bytes added by the mmc.
+   */
+  newrfp = inb(RPLL(base));
+  newrfp |= inb(RPLH(base)) << 8;
+  newrfp %= RX_SIZE;
+
+#ifdef DEBUG_RX_INFO
+  printk(KERN_DEBUG "%s: wv_packet_rcv(): i593_rfp %d stop %d newrfp %d lp->rfp %d\n",
+	 dev->name, i593_rfp, lp->stop, newrfp, lp->rfp);
+#endif
+
+#ifdef DEBUG_RX_ERROR
+  /* If no new frame pointer... */
+  if(lp->overrunning || newrfp == lp->rfp)
+    printk(KERN_INFO "%s: wv_packet_rcv(): no new frame: i593_rfp %d stop %d newrfp %d lp->rfp %d\n",
+	   dev->name, i593_rfp, lp->stop, newrfp, lp->rfp);
+#endif
+
+  /* Read all frames (packets) received */
+  while(newrfp != lp->rfp)
+    {
+      /* A frame is composed of the packet, followed by a status word,
+       * the length of the frame (word) and the mmc info (SNR & qual).
+       * It's because the length is at the end that we can only scan
+       * frames backward. */
+
+      /* Find the first frame by skipping backwards over the frames */
+      rp = newrfp;	/* End of last frame */
+      while(((f_start = wv_start_of_frame(dev, rp, newrfp)) != lp->rfp) &&
+	    (f_start != -1))
+	  rp = f_start;
+
+      /* If we had a problem */
+      if(f_start == -1)
+	{
+#ifdef DEBUG_RX_ERROR
+	  printk(KERN_INFO "wavelan_cs: cannot find start of frame ");
+	  printk(" i593_rfp %d stop %d newrfp %d lp->rfp %d\n",
+		 i593_rfp, lp->stop, newrfp, lp->rfp);
+#endif
+	  lp->rfp = rp;		/* Get to the last usable frame */
+	  continue;
+	}
+
+      /* f_start point to the beggining of the first frame received
+       * and rp to the beggining of the next one */
+
+      /* Read status & length of the frame */
+      stat_ptr = (rp - 7 + RX_SIZE) % RX_SIZE;
+      stat_ptr = read_ringbuf(dev, stat_ptr, c, 4);
+      status = c[0] | (c[1] << 8);
+      len = c[2] | (c[3] << 8);
+
+      /* Check status */
+      if((status & RX_RCV_OK) != RX_RCV_OK)
+	{
+	  lp->stats.rx_errors++;
+	  if(status & RX_NO_SFD)
+	    lp->stats.rx_frame_errors++;
+	  if(status & RX_CRC_ERR)
+	    lp->stats.rx_crc_errors++;
+	  if(status & RX_OVRRUN)
+	    lp->stats.rx_over_errors++;
+
+#ifdef DEBUG_RX_FAIL
+	  printk(KERN_DEBUG "%s: wv_packet_rcv(): packet not received ok, status = 0x%x\n",
+		 dev->name, status);
+#endif
+	}
+      else
+	/* Read the packet and transmit to Linux */
+	wv_packet_read(dev, f_start, len - 2);
+
+      /* One frame has been processed, skip it */
+      lp->rfp = rp;
+    }
+
+  /*
+   * Update the frame stop register, but set it to less than
+   * the full 8K to allow space for 3 bytes of signal strength
+   * per packet.
+   */
+  lp->stop = (i593_rfp + RX_SIZE - ((RX_SIZE / 64) * 3)) % RX_SIZE;
+  outb(OP0_SWIT_TO_PORT_1 | CR0_CHNL, LCCR(base));
+  outb(CR1_STOP_REG_UPDATE | (lp->stop >> RX_SIZE_SHIFT), LCCR(base));
+  outb(OP1_SWIT_TO_PORT_0, LCCR(base));
+
+#ifdef DEBUG_RX_TRACE
+  printk(KERN_DEBUG "%s: <-wv_packet_rcv()\n", dev->name);
+#endif
+}
+
+/*********************** PACKET TRANSMISSION ***********************/
+/*
+ * This part deal with sending packet through the wavelan
+ * We copy the packet to the send buffer and then issue the send
+ * command to the i82593. The result of this operation will be
+ * checked in wavelan_interrupt()
+ */
+
+/*------------------------------------------------------------------*/
+/*
+ * This routine fills in the appropriate registers and memory
+ * locations on the WaveLAN card and starts the card off on
+ * the transmit.
+ * (called in wavelan_packet_xmit())
+ */
+static inline void
+wv_packet_write(device *	dev,
+		void *		buf,
+		short		length)
+{
+  net_local *		lp = (net_local *) dev->priv;
+  ioaddr_t		base = dev->base_addr;
+  unsigned long		flags;
+  int			clen = length;
+  register u_short	xmtdata_base = TX_BASE;
+
+#ifdef DEBUG_TX_TRACE
+  printk(KERN_DEBUG "%s: ->wv_packet_write(%d)\n", dev->name, length);
+#endif
+
+  wv_splhi(lp, &flags);
+
+  /* Check if we need some padding */
+  if(clen < ETH_ZLEN)
+    clen = ETH_ZLEN;
+
+  /* Write the length of data buffer followed by the buffer */
+  outb(xmtdata_base & 0xff, PIORL(base));
+  outb(((xmtdata_base >> 8) & PIORH_MASK) | PIORH_SEL_TX, PIORH(base));
+  outb(clen & 0xff, PIOP(base));	/* lsb */
+  outb(clen >> 8, PIOP(base));  	/* msb */
+
+  /* Send the data */
+  outsb(PIOP(base), buf, clen);
+
+  /* Indicate end of transmit chain */
+  outb(OP0_NOP, PIOP(base));
+  /* josullvn@cs.cmu.edu: need to send a second NOP for alignment... */
+  outb(OP0_NOP, PIOP(base));
+
+  /* Reset the transmit DMA pointer */
+  hacr_write_slow(base, HACR_PWR_STAT | HACR_TX_DMA_RESET);
+  hacr_write(base, HACR_DEFAULT);
+  /* Send the transmit command */
+  wv_82593_cmd(dev, "wv_packet_write(): transmit",
+	       OP0_TRANSMIT, SR0_NO_RESULT);
+
+  /* Keep stats up to date */
+  add_tx_bytes(&lp->stats, length);
+
+#ifndef HAVE_NETIF_QUEUE
+  /* If watchdog not already active, activate it... */
+  mod_timer(&lp->watchdog, jiffies + WATCHDOG_JIFFIES);
+#endif
+
+  wv_splx(lp, &flags);
+
+#ifdef DEBUG_TX_INFO
+  wv_packet_info((u_char *) buf, length, dev->name, "wv_packet_write");
+#endif	/* DEBUG_TX_INFO */
+
+#ifdef DEBUG_TX_TRACE
+  printk(KERN_DEBUG "%s: <-wv_packet_write()\n", dev->name);
+#endif
+}
+
+/*------------------------------------------------------------------*/
+/*
+ * This routine is called when we want to send a packet (NET3 callback)
+ * In this routine, we check if the the harware is ready to accept
+ * the packet. We also prevent reentrance. Then, we call the function
+ * to send the packet...
+ */
+static int
+wavelan_packet_xmit(struct sk_buff *	skb,
+		    device *		dev)
+{
+  net_local *	lp = (net_local *)dev->priv;
+
+#ifdef DEBUG_TX_TRACE
+  printk(KERN_DEBUG "%s: ->wavelan_packet_xmit(0x%X)\n", dev->name,
+	 (unsigned) skb);
+#endif
+
+  /* Check that skb is valid */
+  skb_tx_check(dev, skb);
+  
+#if (LINUX_VERSION_CODE < VERSION(2,1,79))
+  /*
+   * For ethernet, fill in the header.
+   */
+  skb->arp = 1;
+#endif
+
+  /*
+   * Block a timer-based transmit from overlapping a previous transmit.
+   * In other words, prevent reentering this routine.
+   */
+  netif_stop_queue(dev);
+
+  /* If somebody has asked to reconfigure the controler,
+   * we can do it now */
+  if(lp->reconfig_82593)
+    {
+      wv_82593_config(dev);
+      /* Note : the configure procedure was totally synchronous,
+       * so the Tx buffer is now free */
+    }
+
+#ifdef DEBUG_TX_ERROR
+	if (skb->next)
+		printk(KERN_INFO "skb has next\n");
+#endif
+
+  wv_packet_write(dev, skb->data, skb->len);
+
+  DEV_KFREE_SKB(skb);
+
+#ifdef DEBUG_TX_TRACE
+  printk(KERN_DEBUG "%s: <-wavelan_packet_xmit()\n", dev->name);
+#endif
+  return(0);
+}
+
+/********************** HARDWARE CONFIGURATION **********************/
+/*
+ * This part do the real job of starting and configuring the hardware.
+ */
+
+/*------------------------------------------------------------------*/
+/*
+ * Routine to initialize the Modem Management Controller.
+ * (called by wv_hw_config())
+ */
+static inline int
+wv_mmc_init(device *	dev)
+{
+  ioaddr_t	base = dev->base_addr;
+  psa_t		psa;
+  mmw_t		m;
+  int		configured;
+  int		i;		/* Loop counter */
+
+#ifdef DEBUG_CONFIG_TRACE
+  printk(KERN_DEBUG "%s: ->wv_mmc_init()\n", dev->name);
+#endif
+
+  /* Read the parameter storage area */
+  psa_read(dev, 0, (unsigned char *) &psa, sizeof(psa));
+
+  /*
+   * Check the first three octets of the MAC addr for the manufacturer's code.
+   * Note: If you get the error message below, you've got a
+   * non-NCR/AT&T/Lucent PCMCIA cards, see wavelan_cs.h for detail on
+   * how to configure your card...
+   */
+  for(i = 0; i < (sizeof(MAC_ADDRESSES) / sizeof(char) / 3); i++)
+    if((psa.psa_univ_mac_addr[0] == MAC_ADDRESSES[i][0]) &&
+       (psa.psa_univ_mac_addr[1] == MAC_ADDRESSES[i][1]) &&
+       (psa.psa_univ_mac_addr[2] == MAC_ADDRESSES[i][2]))
+      break;
+
+  /* If we have not found it... */
+  if(i == (sizeof(MAC_ADDRESSES) / sizeof(char) / 3))
+    {
+#ifdef DEBUG_CONFIG_ERRORS
+      printk(KERN_WARNING "%s: wv_mmc_init(): Invalid MAC address: %02X:%02X:%02X:...\n",
+	     dev->name, psa.psa_univ_mac_addr[0],
+	     psa.psa_univ_mac_addr[1], psa.psa_univ_mac_addr[2]);
+#endif
+      return FALSE;
+    }
+
+  /* Get the MAC address */
+  memcpy(&dev->dev_addr[0], &psa.psa_univ_mac_addr[0], WAVELAN_ADDR_SIZE);
+
+#ifdef USE_PSA_CONFIG
+  configured = psa.psa_conf_status & 1;
+#else
+  configured = 0;
+#endif
+
+  /* Is the PSA is not configured */
+  if(!configured)
+    {
+      /* User will be able to configure NWID after (with iwconfig) */
+      psa.psa_nwid[0] = 0;
+      psa.psa_nwid[1] = 0;
+
+      /* As NWID is not set : no NWID checking */
+      psa.psa_nwid_select = 0;
+
+      /* Disable encryption */
+      psa.psa_encryption_select = 0;
+
+      /* Set to standard values
+       * 0x04 for AT,
+       * 0x01 for MCA,
+       * 0x04 for PCMCIA and 2.00 card (AT&T 407-024689/E document)
+       */
+      if (psa.psa_comp_number & 1)
+	psa.psa_thr_pre_set = 0x01;
+      else
+	psa.psa_thr_pre_set = 0x04;
+      psa.psa_quality_thr = 0x03;
+
+      /* It is configured */
+      psa.psa_conf_status |= 1;
+
+#ifdef USE_PSA_CONFIG
+      /* Write the psa */
+      psa_write(dev, (char *)psa.psa_nwid - (char *)&psa,
+		(unsigned char *)psa.psa_nwid, 4);
+      psa_write(dev, (char *)&psa.psa_thr_pre_set - (char *)&psa,
+		(unsigned char *)&psa.psa_thr_pre_set, 1);
+      psa_write(dev, (char *)&psa.psa_quality_thr - (char *)&psa,
+		(unsigned char *)&psa.psa_quality_thr, 1);
+      psa_write(dev, (char *)&psa.psa_conf_status - (char *)&psa,
+		(unsigned char *)&psa.psa_conf_status, 1);
+      /* update the Wavelan checksum */
+      update_psa_checksum(dev);
+#endif	/* USE_PSA_CONFIG */
+    }
+
+  /* Zero the mmc structure */
+  memset(&m, 0x00, sizeof(m));
+
+  /* Copy PSA info to the mmc */
+  m.mmw_netw_id_l = psa.psa_nwid[1];
+  m.mmw_netw_id_h = psa.psa_nwid[0];
+  
+  if(psa.psa_nwid_select & 1)
+    m.mmw_loopt_sel = 0x00;
+  else
+    m.mmw_loopt_sel = MMW_LOOPT_SEL_DIS_NWID;
+
+  memcpy(&m.mmw_encr_key, &psa.psa_encryption_key, 
+	 sizeof(m.mmw_encr_key));
+
+  if(psa.psa_encryption_select)
+    m.mmw_encr_enable = MMW_ENCR_ENABLE_EN | MMW_ENCR_ENABLE_MODE;
+  else
+    m.mmw_encr_enable = 0;
+
+  m.mmw_thr_pre_set = psa.psa_thr_pre_set & 0x3F;
+  m.mmw_quality_thr = psa.psa_quality_thr & 0x0F;
+
+  /*
+   * Set default modem control parameters.
+   * See NCR document 407-0024326 Rev. A.
+   */
+  m.mmw_jabber_enable = 0x01;
+  m.mmw_anten_sel = MMW_ANTEN_SEL_ALG_EN;
+  m.mmw_ifs = 0x20;
+  m.mmw_mod_delay = 0x04;
+  m.mmw_jam_time = 0x38;
+
+  m.mmw_des_io_invert = 0;
+  m.mmw_freeze = 0;
+  m.mmw_decay_prm = 0;
+  m.mmw_decay_updat_prm = 0;
+
+  /* Write all info to mmc */
+  mmc_write(base, 0, (u_char *)&m, sizeof(m));
+
+  /* The following code start the modem of the 2.00 frequency
+   * selectable cards at power on. It's not strictly needed for the
+   * following boots...
+   * The original patch was by Joe Finney for the PCMCIA driver, but
+   * I've cleaned it a bit and add documentation.
+   * Thanks to Loeke Brederveld from Lucent for the info.
+   */
+
+  /* Attempt to recognise 2.00 cards (2.4 GHz frequency selectable)
+   * (does it work for everybody ??? - especially old cards...) */
+  /* Note : WFREQSEL verify that it is able to read from EEprom
+   * a sensible frequency (address 0x00) + that MMR_FEE_STATUS_ID
+   * is 0xA (Xilinx version) or 0xB (Ariadne version).
+   * My test is more crude but do work... */
+  if(!(mmc_in(base, mmroff(0, mmr_fee_status)) &
+       (MMR_FEE_STATUS_DWLD | MMR_FEE_STATUS_BUSY)))
+    {
+      /* We must download the frequency parameters to the
+       * synthetisers (from the EEprom - area 1)
+       * Note : as the EEprom is auto decremented, we set the end
+       * if the area... */
+      m.mmw_fee_addr = 0x0F;
+      m.mmw_fee_ctrl = MMW_FEE_CTRL_READ | MMW_FEE_CTRL_DWLD;
+      mmc_write(base, (char *)&m.mmw_fee_ctrl - (char *)&m,
+		(unsigned char *)&m.mmw_fee_ctrl, 2);
+
+      /* Wait until the download is finished */
+      fee_wait(base, 100, 100);
+
+#ifdef DEBUG_CONFIG_INFO
+      /* The frequency was in the last word downloaded... */
+      mmc_read(base, (char *)&m.mmw_fee_data_l - (char *)&m,
+	       (unsigned char *)&m.mmw_fee_data_l, 2);
+
+      /* Print some info for the user */
+      printk(KERN_DEBUG "%s: Wavelan 2.00 recognised (frequency select) : Current frequency = %ld\n",
+	     dev->name,
+	     ((m.mmw_fee_data_h << 4) |
+	      (m.mmw_fee_data_l >> 4)) * 5 / 2 + 24000L);
+#endif
+
+      /* We must now download the power adjust value (gain) to
+       * the synthetisers (from the EEprom - area 7 - DAC) */
+      m.mmw_fee_addr = 0x61;
+      m.mmw_fee_ctrl = MMW_FEE_CTRL_READ | MMW_FEE_CTRL_DWLD;
+      mmc_write(base, (char *)&m.mmw_fee_ctrl - (char *)&m,
+		(unsigned char *)&m.mmw_fee_ctrl, 2);
+
+      /* Wait until the download is finished */
+    }	/* if 2.00 card */
+
+#ifdef DEBUG_CONFIG_TRACE
+  printk(KERN_DEBUG "%s: <-wv_mmc_init()\n", dev->name);
+#endif
+  return TRUE;
+}
+
+/*------------------------------------------------------------------*/
+/*
+ * Routine to gracefully turn off reception, and wait for any commands
+ * to complete.
+ * (called in wv_ru_start() and wavelan_close() and wavelan_event())
+ */
+static int
+wv_ru_stop(device *	dev)
+{
+  ioaddr_t	base = dev->base_addr;
+  net_local *	lp = (net_local *) dev->priv;
+  unsigned long	flags;
+  int		status;
+  int		spin;
+
+#ifdef DEBUG_CONFIG_TRACE
+  printk(KERN_DEBUG "%s: ->wv_ru_stop()\n", dev->name);
+#endif
+
+  wv_splhi(lp, &flags);
+
+  /* First, send the LAN controller a stop receive command */
+  wv_82593_cmd(dev, "wv_graceful_shutdown(): stop-rcv",
+	       OP0_STOP_RCV, SR0_NO_RESULT);
+
+  /* Then, spin until the receive unit goes idle */
+  spin = 300;
+  do
+    {
+      udelay(10);
+      outb(OP0_NOP | CR0_STATUS_3, LCCR(base));
+      status = inb(LCSR(base));
+    }
+  while(((status & SR3_RCV_STATE_MASK) != SR3_RCV_IDLE) && (spin-- > 0));
+
+  /* Now, spin until the chip finishes executing its current command */
+  do
+    {
+      udelay(10);
+      outb(OP0_NOP | CR0_STATUS_3, LCCR(base));
+      status = inb(LCSR(base));
+    }
+  while(((status & SR3_EXEC_STATE_MASK) != SR3_EXEC_IDLE) && (spin-- > 0));
+
+  wv_splx(lp, &flags);
+
+  /* If there was a problem */
+  if(spin <= 0)
+    {
+#ifdef DEBUG_CONFIG_ERROR
+      printk(KERN_INFO "%s: wv_ru_stop(): The chip doesn't want to stop...\n",
+	     dev->name);
+#endif
+      return FALSE;
+    }
+
+#ifdef DEBUG_CONFIG_TRACE
+  printk(KERN_DEBUG "%s: <-wv_ru_stop()\n", dev->name);
+#endif
+  return TRUE;
+} /* wv_ru_stop */
+
+/*------------------------------------------------------------------*/
+/*
+ * This routine starts the receive unit running.  First, it checks if
+ * the card is actually ready. Then the card is instructed to receive
+ * packets again.
+ * (called in wv_hw_reset() & wavelan_open())
+ */
+static int
+wv_ru_start(device *	dev)
+{
+  ioaddr_t	base = dev->base_addr;
+  net_local *	lp = (net_local *) dev->priv;
+  unsigned long	flags;
+
+#ifdef DEBUG_CONFIG_TRACE
+  printk(KERN_DEBUG "%s: ->wv_ru_start()\n", dev->name);
+#endif
+
+  /*
+   * We need to start from a quiescent state. To do so, we could check
+   * if the card is already running, but instead we just try to shut
+   * it down. First, we disable reception (in case it was already enabled).
+   */
+  if(!wv_ru_stop(dev))
+    return FALSE;
+
+  wv_splhi(lp, &flags);
+
+  /* Now we know that no command is being executed. */
+
+  /* Set the receive frame pointer and stop pointer */
+  lp->rfp = 0;
+  outb(OP0_SWIT_TO_PORT_1 | CR0_CHNL, LCCR(base));
+
+  /* Reset ring management.  This sets the receive frame pointer to 1 */
+  outb(OP1_RESET_RING_MNGMT, LCCR(base));
+
+#if 0
+  /* XXX the i82593 manual page 6-4 seems to indicate that the stop register
+     should be set as below */
+  /* outb(CR1_STOP_REG_UPDATE|((RX_SIZE - 0x40)>> RX_SIZE_SHIFT),LCCR(base));*/
+#elif 0
+  /* but I set it 0 instead */
+  lp->stop = 0;
+#else
+  /* but I set it to 3 bytes per packet less than 8K */
+  lp->stop = (0 + RX_SIZE - ((RX_SIZE / 64) * 3)) % RX_SIZE;
+#endif
+  outb(CR1_STOP_REG_UPDATE | (lp->stop >> RX_SIZE_SHIFT), LCCR(base));
+  outb(OP1_INT_ENABLE, LCCR(base));
+  outb(OP1_SWIT_TO_PORT_0, LCCR(base));
+
+  /* Reset receive DMA pointer */
+  hacr_write_slow(base, HACR_PWR_STAT | HACR_TX_DMA_RESET);
+  hacr_write_slow(base, HACR_DEFAULT);
+
+  /* Receive DMA on channel 1 */
+  wv_82593_cmd(dev, "wv_ru_start(): rcv-enable",
+	       CR0_CHNL | OP0_RCV_ENABLE, SR0_NO_RESULT);
+
+#ifdef DEBUG_I82593_SHOW
+  {
+    int	status;
+    int	opri;
+    int	spin = 10000;
+
+    /* spin until the chip starts receiving */
+    do
+      {
+	outb(OP0_NOP | CR0_STATUS_3, LCCR(base));
+	status = inb(LCSR(base));
+	if(spin-- <= 0)
+	  break;
+      }
+    while(((status & SR3_RCV_STATE_MASK) != SR3_RCV_ACTIVE) &&
+	  ((status & SR3_RCV_STATE_MASK) != SR3_RCV_READY));
+    printk(KERN_DEBUG "rcv status is 0x%x [i:%d]\n",
+	   (status & SR3_RCV_STATE_MASK), i);
+  }
+#endif
+
+  wv_splx(lp, &flags);
+
+#ifdef DEBUG_CONFIG_TRACE
+  printk(KERN_DEBUG "%s: <-wv_ru_start()\n", dev->name);
+#endif
+  return TRUE;
+}
+
+/*------------------------------------------------------------------*/
+/*
+ * This routine does a standard config of the WaveLAN controler (i82593).
+ * In the ISA driver, this is integrated in wavelan_hardware_reset()
+ * (called by wv_hw_config(), wv_82593_reconfig() & wavelan_packet_xmit())
+ */
+static int
+wv_82593_config(device *	dev)
+{
+  ioaddr_t			base = dev->base_addr;
+  net_local *			lp = (net_local *) dev->priv;
+  struct i82593_conf_block	cfblk;
+  unsigned long			flags;
+  int				ret = TRUE;
+
+#ifdef DEBUG_CONFIG_TRACE
+  printk(KERN_DEBUG "%s: ->wv_82593_config()\n", dev->name);
+#endif
+
+  /* Create & fill i82593 config block
+   *
+   * Now conform to Wavelan document WCIN085B
+   */
+  memset(&cfblk, 0x00, sizeof(struct i82593_conf_block));
+  cfblk.d6mod = FALSE;  	/* Run in i82593 advanced mode */
+  cfblk.fifo_limit = 5;         /* = 56 B rx and 40 B tx fifo thresholds */
+  cfblk.forgnesi = FALSE;       /* 0=82C501, 1=AMD7992B compatibility */
+  cfblk.fifo_32 = 1;
+  cfblk.throttle_enb = FALSE;
+  cfblk.contin = TRUE;          /* enable continuous mode */
+  cfblk.cntrxint = FALSE;       /* enable continuous mode receive interrupts */
+  cfblk.addr_len = WAVELAN_ADDR_SIZE;
+  cfblk.acloc = TRUE;           /* Disable source addr insertion by i82593 */
+  cfblk.preamb_len = 0;         /* 2 bytes preamble (SFD) */
+  cfblk.loopback = FALSE;
+  cfblk.lin_prio = 0;   	/* conform to 802.3 backoff algoritm */
+  cfblk.exp_prio = 5;	        /* conform to 802.3 backoff algoritm */
+  cfblk.bof_met = 1;	        /* conform to 802.3 backoff algoritm */
+  cfblk.ifrm_spc = 0x20;	/* 32 bit times interframe spacing */
+  cfblk.slottim_low = 0x20;	/* 32 bit times slot time */
+  cfblk.slottim_hi = 0x0;
+  cfblk.max_retr = 15;
+  cfblk.prmisc = ((lp->promiscuous) ? TRUE: FALSE);	/* Promiscuous mode */
+  cfblk.bc_dis = FALSE;         /* Enable broadcast reception */
+  cfblk.crs_1 = TRUE;		/* Transmit without carrier sense */
+  cfblk.nocrc_ins = FALSE;	/* i82593 generates CRC */	
+  cfblk.crc_1632 = FALSE;	/* 32-bit Autodin-II CRC */
+  cfblk.crs_cdt = FALSE;	/* CD not to be interpreted as CS */
+  cfblk.cs_filter = 0;  	/* CS is recognized immediately */
+  cfblk.crs_src = FALSE;	/* External carrier sense */
+  cfblk.cd_filter = 0;  	/* CD is recognized immediately */
+  cfblk.min_fr_len = ETH_ZLEN >> 2;     /* Minimum frame length 64 bytes */
+  cfblk.lng_typ = FALSE;	/* Length field > 1500 = type field */
+  cfblk.lng_fld = TRUE; 	/* Disable 802.3 length field check */
+  cfblk.rxcrc_xf = TRUE;	/* Don't transfer CRC to memory */
+  cfblk.artx = TRUE;		/* Disable automatic retransmission */
+  cfblk.sarec = TRUE;		/* Disable source addr trig of CD */
+  cfblk.tx_jabber = TRUE;	/* Disable jabber jam sequence */
+  cfblk.hash_1 = FALSE; 	/* Use bits 0-5 in mc address hash */
+  cfblk.lbpkpol = TRUE; 	/* Loopback pin active high */
+  cfblk.fdx = FALSE;		/* Disable full duplex operation */
+  cfblk.dummy_6 = 0x3f; 	/* all ones */
+  cfblk.mult_ia = FALSE;	/* No multiple individual addresses */
+  cfblk.dis_bof = FALSE;	/* Disable the backoff algorithm ?! */
+  cfblk.dummy_1 = TRUE; 	/* set to 1 */
+  cfblk.tx_ifs_retrig = 3;	/* Hmm... Disabled */
+#ifdef MULTICAST_ALL
+  cfblk.mc_all = (lp->allmulticast ? TRUE: FALSE);	/* Allow all multicasts */
+#else
+  cfblk.mc_all = FALSE;		/* No multicast all mode */
+#endif
+  cfblk.rcv_mon = 0;		/* Monitor mode disabled */
+  cfblk.frag_acpt = TRUE;	/* Do not accept fragments */
+  cfblk.tstrttrs = FALSE;	/* No start transmission threshold */
+  cfblk.fretx = TRUE;		/* FIFO automatic retransmission */
+  cfblk.syncrqs = FALSE; 	/* Synchronous DRQ deassertion... */
+  cfblk.sttlen = TRUE;  	/* 6 byte status registers */
+  cfblk.rx_eop = TRUE;  	/* Signal EOP on packet reception */
+  cfblk.tx_eop = TRUE;  	/* Signal EOP on packet transmission */
+  cfblk.rbuf_size = RX_SIZE>>11;	/* Set receive buffer size */
+  cfblk.rcvstop = TRUE; 	/* Enable Receive Stop Register */
+
+#ifdef DEBUG_I82593_SHOW
+  {
+    u_char *c = (u_char *) &cfblk;
+    int i;
+    printk(KERN_DEBUG "wavelan_cs: config block:");
+    for(i = 0; i < sizeof(struct i82593_conf_block); i++,c++)
+      {
+	if((i % 16) == 0) printk("\n" KERN_DEBUG);
+	printk("%02x ", *c);
+      }
+    printk("\n");
+  }
+#endif
+
+  /* Disable interrupts */
+  wv_splhi(lp, &flags);
+
+  /* Copy the config block to the i82593 */
+  outb(TX_BASE & 0xff, PIORL(base));
+  outb(((TX_BASE >> 8) & PIORH_MASK) | PIORH_SEL_TX, PIORH(base));
+  outb(sizeof(struct i82593_conf_block) & 0xff, PIOP(base));    /* lsb */
+  outb(sizeof(struct i82593_conf_block) >> 8, PIOP(base));	/* msb */
+  outsb(PIOP(base), (char *) &cfblk, sizeof(struct i82593_conf_block));
+
+  /* reset transmit DMA pointer */
+  hacr_write_slow(base, HACR_PWR_STAT | HACR_TX_DMA_RESET);
+  hacr_write(base, HACR_DEFAULT);
+  if(!wv_82593_cmd(dev, "wv_82593_config(): configure",
+		   OP0_CONFIGURE, SR0_CONFIGURE_DONE))
+    ret = FALSE;
+
+  /* Initialize adapter's ethernet MAC address */
+  outb(TX_BASE & 0xff, PIORL(base));
+  outb(((TX_BASE >> 8) & PIORH_MASK) | PIORH_SEL_TX, PIORH(base));
+  outb(WAVELAN_ADDR_SIZE, PIOP(base));	/* byte count lsb */
+  outb(0, PIOP(base));			/* byte count msb */
+  outsb(PIOP(base), &dev->dev_addr[0], WAVELAN_ADDR_SIZE);
+
+  /* reset transmit DMA pointer */
+  hacr_write_slow(base, HACR_PWR_STAT | HACR_TX_DMA_RESET);
+  hacr_write(base, HACR_DEFAULT);
+  if(!wv_82593_cmd(dev, "wv_82593_config(): ia-setup",
+		   OP0_IA_SETUP, SR0_IA_SETUP_DONE))
+    ret = FALSE;
+
+#ifdef WAVELAN_ROAMING
+    /* If roaming is enabled, join the "Beacon Request" multicast group... */
+    /* But only if it's not in there already! */
+  if(do_roaming)
+    dev_mc_add(dev,WAVELAN_BEACON_ADDRESS, WAVELAN_ADDR_SIZE, 1);
+#endif	/* WAVELAN_ROAMING */
+
+  /* If any multicast address to set */
+  if(lp->mc_count)
+    {
+      struct dev_mc_list *	dmi;
+      int			addrs_len = WAVELAN_ADDR_SIZE * lp->mc_count;
+
+#ifdef DEBUG_CONFIG_INFO
+      printk(KERN_DEBUG "%s: wv_hw_config(): set %d multicast addresses:\n",
+	     dev->name, lp->mc_count);
+      for(dmi=dev->mc_list; dmi; dmi=dmi->next)
+	printk(KERN_DEBUG " %02x:%02x:%02x:%02x:%02x:%02x\n",
+	       dmi->dmi_addr[0], dmi->dmi_addr[1], dmi->dmi_addr[2],
+	       dmi->dmi_addr[3], dmi->dmi_addr[4], dmi->dmi_addr[5] );
+#endif
+
+      /* Initialize adapter's ethernet multicast addresses */
+      outb(TX_BASE & 0xff, PIORL(base));
+      outb(((TX_BASE >> 8) & PIORH_MASK) | PIORH_SEL_TX, PIORH(base));
+      outb(addrs_len & 0xff, PIOP(base));	/* byte count lsb */
+      outb((addrs_len >> 8), PIOP(base));	/* byte count msb */
+      for(dmi=dev->mc_list; dmi; dmi=dmi->next)
+	outsb(PIOP(base), dmi->dmi_addr, dmi->dmi_addrlen);
+
+      /* reset transmit DMA pointer */
+      hacr_write_slow(base, HACR_PWR_STAT | HACR_TX_DMA_RESET);
+      hacr_write(base, HACR_DEFAULT);
+      if(!wv_82593_cmd(dev, "wv_82593_config(): mc-setup",
+		       OP0_MC_SETUP, SR0_MC_SETUP_DONE))
+	ret = FALSE;
+      lp->mc_count = dev->mc_count;	/* remember to avoid repeated reset */
+    }
+
+  /* Job done, clear the flag */
+  lp->reconfig_82593 = FALSE;
+
+  /* Re-enable interrupts */
+  wv_splx(lp, &flags);
+
+#ifdef DEBUG_CONFIG_TRACE
+  printk(KERN_DEBUG "%s: <-wv_82593_config()\n", dev->name);
+#endif
+  return(ret);
+}
+
+/*------------------------------------------------------------------*/
+/*
+ * Read the Access Configuration Register, perform a software reset,
+ * and then re-enable the card's software.
+ *
+ * If I understand correctly : reset the pcmcia interface of the
+ * wavelan.
+ * (called by wv_config())
+ */
+static inline int
+wv_pcmcia_reset(device *	dev)
+{
+  int		i;
+  conf_reg_t	reg = { 0, CS_READ, CISREG_COR, 0 };
+  dev_link_t *	link = ((net_local *) dev->priv)->link;
+
+#ifdef DEBUG_CONFIG_TRACE
+  printk(KERN_DEBUG "%s: ->wv_pcmcia_reset()\n", dev->name);
+#endif
+
+  i = CardServices(AccessConfigurationRegister, link->handle, &reg);
+  if(i != CS_SUCCESS)
+    {
+      cs_error(link->handle, AccessConfigurationRegister, i);
+      return FALSE;
+    }
+      
+#ifdef DEBUG_CONFIG_INFO
+  printk(KERN_DEBUG "%s: wavelan_pcmcia_reset(): Config reg is 0x%x\n",
+	 dev->name, (u_int) reg.Value);
+#endif
+
+  reg.Action = CS_WRITE;
+  reg.Value = reg.Value | COR_SW_RESET;
+  i = CardServices(AccessConfigurationRegister, link->handle, &reg);
+  if(i != CS_SUCCESS)
+    {
+      cs_error(link->handle, AccessConfigurationRegister, i);
+      return FALSE;
+    }
+      
+  reg.Action = CS_WRITE;
+  reg.Value = COR_LEVEL_IRQ | COR_CONFIG;
+  i = CardServices(AccessConfigurationRegister, link->handle, &reg);
+  if(i != CS_SUCCESS)
+    {
+      cs_error(link->handle, AccessConfigurationRegister, i);
+      return FALSE;
+    }
+
+#ifdef DEBUG_CONFIG_TRACE
+  printk(KERN_DEBUG "%s: <-wv_pcmcia_reset()\n", dev->name);
+#endif
+  return TRUE;
+}
+
+/*------------------------------------------------------------------*/
+/*
+ * wavelan_hw_config() is called after a CARD_INSERTION event is
+ * received, to configure the wavelan hardware.
+ * Note that the reception will be enabled in wavelan->open(), so the
+ * device is configured but idle...
+ * Performs the following actions:
+ * 	1. A pcmcia software reset (using wv_pcmcia_reset())
+ *	2. A power reset (reset DMA)
+ *	3. Reset the LAN controller
+ *	4. Initialize the radio modem (using wv_mmc_init)
+ *	5. Configure LAN controller (using wv_82593_config)
+ *	6. Perform a diagnostic on the LAN controller
+ * (called by wavelan_event() & wv_hw_reset())
+ */
+static int
+wv_hw_config(device *	dev)
+{
+  net_local *		lp = (net_local *) dev->priv;
+  ioaddr_t		base = dev->base_addr;
+
+#ifdef DEBUG_CONFIG_TRACE
+  printk(KERN_DEBUG "%s: ->wv_hw_config()\n", dev->name);
+#endif
+
+#ifdef STRUCT_CHECK
+  if(wv_structuct_check() != (char *) NULL)
+    {
+      printk(KERN_WARNING "%s: wv_hw_config: structure/compiler botch: \"%s\"\n",
+	     dev->name, wv_structuct_check());
+      return FALSE;
+    }
+#endif	/* STRUCT_CHECK == 1 */
+
+  /* Reset the pcmcia interface */
+  if(wv_pcmcia_reset(dev) == FALSE)
+    return FALSE;
+
+  /* Power UP the module + reset the modem + reset host adapter
+   * (in fact, reset DMA channels) */
+  hacr_write_slow(base, HACR_RESET);
+  hacr_write(base, HACR_DEFAULT);
+
+  /* Check if the the module has been powered up... */
+  if(hasr_read(base) & HASR_NO_CLK)
+    {
+#ifdef DEBUG_CONFIG_ERRORS
+      printk(KERN_WARNING "%s: wv_hw_config(): modem not connected or not a wavelan card\n",
+	     dev->name);
+#endif
+      return FALSE;
+    }
+
+  /* initialize the modem */
+  if(wv_mmc_init(dev) == FALSE)
+    return FALSE;
+
+  /* reset the LAN controller (i82593) */
+  outb(OP0_RESET, LCCR(base));
+  udelay(1000L);	/* A bit crude ! */
+
+  /* Initialize the LAN controler */
+  if((wv_82593_config(dev) == FALSE) ||
+     (wv_diag(dev) == FALSE))
+    {
+#ifdef DEBUG_CONFIG_ERRORS
+      printk(KERN_INFO "%s: wv_hw_config(): i82593 init failed\n", dev->name);
+#endif
+      return FALSE;
+    }
+
+  /* 
+   * insert code for loopback test here
+   */
+
+  /* The device is now configured */
+  lp->configured = 1;
+
+#ifdef DEBUG_CONFIG_TRACE
+  printk(KERN_DEBUG "%s: <-wv_hw_config()\n", dev->name);
+#endif
+  return TRUE;
+}
+
+/*------------------------------------------------------------------*/
+/*
+ * Totally reset the wavelan and restart it.
+ * Performs the following actions:
+ * 	1. Call wv_hw_config()
+ *	2. Start the LAN controller's receive unit
+ * (called by wavelan_event(), wavelan_watchdog() and wavelan_open())
+ */
+static inline void
+wv_hw_reset(device *	dev)
+{
+  net_local *	lp = (net_local *) dev->priv;
+
+#ifdef DEBUG_CONFIG_TRACE
+  printk(KERN_DEBUG "%s: ->wv_hw_reset()\n", dev->name);
+#endif
+
+#ifndef HAVE_NETIF_QUEUE
+  /* If watchdog was activated, kill it ! */
+  del_timer(&lp->watchdog);
+#endif
+
+  lp->nresets++;
+  lp->configured = 0;
+  
+  /* Call wv_hw_config() for most of the reset & init stuff */
+  if(wv_hw_config(dev) == FALSE)
+    return;
+
+  /* start receive unit */
+  wv_ru_start(dev);
+
+#ifdef DEBUG_CONFIG_TRACE
+  printk(KERN_DEBUG "%s: <-wv_hw_reset()\n", dev->name);
+#endif
+}
+
+/*------------------------------------------------------------------*/
+/*
+ * wv_pcmcia_config() is called after a CARD_INSERTION event is
+ * received, to configure the PCMCIA socket, and to make the ethernet
+ * device available to the system.
+ * (called by wavelan_event())
+ */
+static inline int
+wv_pcmcia_config(dev_link_t *	link)
+{
+  client_handle_t	handle;
+  tuple_t		tuple;
+  cisparse_t		parse;
+  struct net_device *	dev;
+  int			i;
+  u_char		buf[64];
+  win_req_t		req;
+  memreq_t		mem;
+
+  handle = link->handle;
+  dev = (device *) link->priv;
+
+#ifdef DEBUG_CONFIG_TRACE
+  printk(KERN_DEBUG "->wv_pcmcia_config(0x%p)\n", link);
+#endif
+
+  /*
+   * This reads the card's CONFIG tuple to find its configuration
+   * registers.
+   */
+  do
+    {
+      tuple.Attributes = 0;
+      tuple.DesiredTuple = CISTPL_CONFIG;
+      i = CardServices(GetFirstTuple, handle, &tuple);
+      if(i != CS_SUCCESS)
+	break;
+      tuple.TupleData = (cisdata_t *)buf;
+      tuple.TupleDataMax = 64;
+      tuple.TupleOffset = 0;
+      i = CardServices(GetTupleData, handle, &tuple);
+      if(i != CS_SUCCESS)
+	break;
+      i = CardServices(ParseTuple, handle, &tuple, &parse);
+      if(i != CS_SUCCESS)
+	break;
+      link->conf.ConfigBase = parse.config.base;
+      link->conf.Present = parse.config.rmask[0];
+    }
+  while(0);
+  if(i != CS_SUCCESS)
+    {
+      cs_error(link->handle, ParseTuple, i);
+      link->state &= ~DEV_CONFIG_PENDING;
+      return FALSE;
+    }
+    
+  /* Configure card */
+  link->state |= DEV_CONFIG;
+  do
+    {
+      i = CardServices(RequestIO, link->handle, &link->io);
+      if(i != CS_SUCCESS)
+	{
+	  cs_error(link->handle, RequestIO, i);
+	  break;
+	}
+
+      /*
+       * Now allocate an interrupt line.  Note that this does not
+       * actually assign a handler to the interrupt.
+       */
+      i = CardServices(RequestIRQ, link->handle, &link->irq);
+      if(i != CS_SUCCESS)
+	{
+	  cs_error(link->handle, RequestIRQ, i);
+	  break;
+	}
+
+      /*
+       * This actually configures the PCMCIA socket -- setting up
+       * the I/O windows and the interrupt mapping.
+       */
+      link->conf.ConfigIndex = 1;
+      i = CardServices(RequestConfiguration, link->handle, &link->conf);
+      if(i != CS_SUCCESS)
+	{
+	  cs_error(link->handle, RequestConfiguration, i);
+	  break;
+	}
+
+      /*
+       * Allocate a small memory window.  Note that the dev_link_t
+       * structure provides space for one window handle -- if your
+       * device needs several windows, you'll need to keep track of
+       * the handles in your private data structure, link->priv.
+       */
+      req.Attributes = WIN_DATA_WIDTH_8|WIN_MEMORY_TYPE_AM|WIN_ENABLE;
+      req.Base = req.Size = 0;
+      req.AccessSpeed = mem_speed;
+      link->win = (window_handle_t)link->handle;
+      i = CardServices(RequestWindow, &link->win, &req);
+      if(i != CS_SUCCESS)
+	{
+	  cs_error(link->handle, RequestWindow, i);
+	  break;
+	}
+
+      dev->rmem_start = dev->mem_start =
+	  (u_long)ioremap(req.Base, req.Size);
+      dev->rmem_end = dev->mem_end = dev->mem_start + req.Size;
+
+      mem.CardOffset = 0; mem.Page = 0;
+      i = CardServices(MapMemPage, link->win, &mem);
+      if(i != CS_SUCCESS)
+	{
+	  cs_error(link->handle, MapMemPage, i);
+	  break;
+	}
+
+      /* Feed device with this info... */
+      dev->irq = link->irq.AssignedIRQ;
+      dev->base_addr = link->io.BasePort1;
+      netif_start_queue(dev);
+
+#ifdef DEBUG_CONFIG_INFO
+      printk(KERN_DEBUG "wv_pcmcia_config: MEMSTART 0x%x IRQ %d IOPORT 0x%x\n",
+	     (u_int) dev->mem_start, dev->irq, (u_int) dev->base_addr);
+#endif
+
+      i = register_netdev(dev);
+      if(i != 0)
+	{
+#ifdef DEBUG_CONFIG_ERRORS
+	  printk(KERN_INFO "wv_pcmcia_config(): register_netdev() failed\n");
+#endif
+	  break;
+	}
+    }
+  while(0);		/* Humm... Disguised goto !!! */
+
+  link->state &= ~DEV_CONFIG_PENDING;
+  /* If any step failed, release any partially configured state */
+  if(i != 0)
+    {
+      wv_pcmcia_release((u_long) link);
+      return FALSE;
+    }
+
+  /* ???? Could you explain me this, Dave ? */
+  link->dev = &((net_local *) dev->priv)->node;
+
+#ifdef DEBUG_CONFIG_TRACE
+  printk(KERN_DEBUG "<-wv_pcmcia_config()\n");
+#endif
+  return TRUE;
+}
+
+/*------------------------------------------------------------------*/
+/*
+ * After a card is removed, wv_pcmcia_release() will unregister the net
+ * device, and release the PCMCIA configuration.  If the device is
+ * still open, this will be postponed until it is closed.
+ */
+static void
+wv_pcmcia_release(u_long	arg)	/* Address of the interface struct */
+{
+  dev_link_t *	link = (dev_link_t *) arg;
+  device *	dev = (device *) link->priv;
+
+#ifdef DEBUG_CONFIG_TRACE
+  printk(KERN_DEBUG "%s: -> wv_pcmcia_release(0x%p)\n", dev->name, link);
+#endif
+
+  /* If the device is currently in use, we won't release until it is
+   * actually closed. */
+  if(link->open)
+    {
+#ifdef DEBUG_CONFIG_INFO
+      printk(KERN_DEBUG "%s: wv_pcmcia_release: release postponed, device still open\n",
+	     dev->name);
+#endif
+      link->state |= DEV_STALE_CONFIG;
+      return;
+    }
+
+  /* Don't bother checking to see if these succeed or not */
+  iounmap((u_char *)dev->mem_start);
+  CardServices(ReleaseWindow, link->win);
+  CardServices(ReleaseConfiguration, link->handle);
+  CardServices(ReleaseIO, link->handle, &link->io);
+  CardServices(ReleaseIRQ, link->handle, &link->irq);
+
+  link->state &= ~(DEV_CONFIG | DEV_STALE_CONFIG);
+
+#ifdef DEBUG_CONFIG_TRACE
+  printk(KERN_DEBUG "%s: <- wv_pcmcia_release()\n", dev->name);
+#endif
+} /* wv_pcmcia_release */
+
+/*------------------------------------------------------------------*/
+/*
+ * Sometimes, wavelan_detach can't be performed following a call from
+ * cardmgr (device still open, pcmcia_release not done) and the device
+ * is put in a STALE_LINK state and remains in memory.
+ *
+ * This function run through our current list of device and attempt
+ * another time to remove them. We hope that since last time the
+ * device has properly been closed.
+ *
+ * (called by wavelan_attach() & cleanup_module())
+ */
+static void
+wv_flush_stale_links(void)
+{
+  dev_link_t *	link;		/* Current node in linked list */
+  dev_link_t *	next;		/* Next node in linked list */
+
+#ifdef DEBUG_CONFIG_TRACE
+  printk(KERN_DEBUG "-> wv_flush_stale_links(0x%p)\n", dev_list);
+#endif
+
+  /* Go through the list */
+  for (link = dev_list; link; link = next)
+    {
+      next = link->next;
+
+      /* Check if in need of being removed */
+      if((link->state & DEV_STALE_LINK) ||
+	 (! (link->state & DEV_PRESENT)))
+	wavelan_detach(link);
+
+    }
+
+#ifdef DEBUG_CONFIG_TRACE
+  printk(KERN_DEBUG "<- wv_flush_stale_links()\n");
+#endif
+}
+
+/************************ INTERRUPT HANDLING ************************/
+
+/*
+ * This function is the interrupt handler for the WaveLAN card. This
+ * routine will be called whenever: 
+ *	1. A packet is received.
+ *	2. A packet has successfully been transfered and the unit is
+ *	   ready to transmit another packet.
+ *	3. A command has completed execution.
+ */
+static void
+wavelan_interrupt(int		irq,
+		  void *	dev_id,
+		  struct pt_regs * regs)
+{
+  device *	dev;
+  net_local *	lp;
+  ioaddr_t	base;
+  int		status0;
+  u_int		tx_status;
+
+  if((dev = (device *)dev_id) == (device *) NULL)
+    {
+#ifdef DEBUG_INTERRUPT_ERROR
+      printk(KERN_WARNING "wavelan_interrupt(): irq %d for unknown device.\n",
+	     irq);
+#endif
+      return;
+    }
+
+#ifdef DEBUG_INTERRUPT_TRACE
+  printk(KERN_DEBUG "%s: ->wavelan_interrupt()\n", dev->name);
+#endif
+
+  lp = (net_local *) dev->priv;
+  base = dev->base_addr;
+
+#ifdef DEBUG_INTERRUPT_ERROR
+  /* Check state of our spinlock (it should be cleared) */
+  if(spin_is_locked(&lp->spinlock))
+    printk(KERN_INFO
+	   "%s: wavelan_interrupt(): spinlock is already locked !!!\n",
+	   dev->name);
+#endif
+
+  /* Prevent reentrancy. It is safe because wv_splhi disable interrupts
+   * before aquiring the spinlock */
+  spin_lock(&lp->spinlock);
+
+  /* Treat all pending interrupts */
+  while(1)
+    {
+      /* ---------------- INTERRUPT CHECKING ---------------- */
+      /*
+       * Look for the interrupt and verify the validity
+       */
+      outb(CR0_STATUS_0 | OP0_NOP, LCCR(base));
+      status0 = inb(LCSR(base));
+
+#ifdef DEBUG_INTERRUPT_INFO
+      printk(KERN_DEBUG "status0 0x%x [%s => 0x%x]", status0, 
+	     (status0&SR0_INTERRUPT)?"int":"no int",status0&~SR0_INTERRUPT);
+      if(status0&SR0_INTERRUPT)
+	{
+	  printk(" [%s => %d]\n", (status0 & SR0_CHNL) ? "chnl" :
+		 ((status0 & SR0_EXECUTION) ? "cmd" :
+		  ((status0 & SR0_RECEPTION) ? "recv" : "unknown")),
+		 (status0 & SR0_EVENT_MASK));
+	}
+      else
+	printk("\n");
+#endif
+
+      /* Return if no actual interrupt from i82593 (normal exit) */
+      if(!(status0 & SR0_INTERRUPT))
+	break;
+
+      /* If interrupt is both Rx and Tx or none...
+       * This code in fact is there to catch the spurious interrupt
+       * when you remove the wavelan pcmcia card from the socket */
+      if(((status0 & SR0_BOTH_RX_TX) == SR0_BOTH_RX_TX) ||
+	 ((status0 & SR0_BOTH_RX_TX) == 0x0))
+	{
+#ifdef DEBUG_INTERRUPT_INFO
+	  printk(KERN_INFO "%s: wv_interrupt(): bogus interrupt (or from dead card) : %X\n",
+		 dev->name, status0);
+#endif
+	  /* Acknowledge the interrupt */
+	  outb(CR0_INT_ACK | OP0_NOP, LCCR(base));
+	  break;
+	}
+
+      /* ----------------- RECEIVING PACKET ----------------- */
+      /*
+       * When the wavelan signal the reception of a new packet,
+       * we call wv_packet_rcv() to copy if from the buffer and
+       * send it to NET3
+       */
+      if(status0 & SR0_RECEPTION)
+	{
+#ifdef DEBUG_INTERRUPT_INFO
+	  printk(KERN_DEBUG "%s: wv_interrupt(): receive\n", dev->name);
+#endif
+
+	  if((status0 & SR0_EVENT_MASK) == SR0_STOP_REG_HIT)
+	    {
+#ifdef DEBUG_INTERRUPT_ERROR
+	      printk(KERN_INFO "%s: wv_interrupt(): receive buffer overflow\n",
+		     dev->name);
+#endif
+	      lp->stats.rx_over_errors++;
+	      lp->overrunning = 1;
+      	    }
+
+	  /* Get the packet */
+	  wv_packet_rcv(dev);
+	  lp->overrunning = 0;
+
+	  /* Acknowledge the interrupt */
+	  outb(CR0_INT_ACK | OP0_NOP, LCCR(base));
+	  continue;
+    	}
+
+      /* ---------------- COMMAND COMPLETION ---------------- */
+      /*
+       * Interrupts issued when the i82593 has completed a command.
+       * Most likely : transmission done
+       */
+
+      /* If a transmission has been done */
+      if((status0 & SR0_EVENT_MASK) == SR0_TRANSMIT_DONE ||
+	 (status0 & SR0_EVENT_MASK) == SR0_RETRANSMIT_DONE ||
+	 (status0 & SR0_EVENT_MASK) == SR0_TRANSMIT_NO_CRC_DONE)
+	{
+#ifdef DEBUG_TX_ERROR
+	  if((status0 & SR0_EVENT_MASK) == SR0_TRANSMIT_NO_CRC_DONE)
+	    printk(KERN_INFO "%s: wv_interrupt(): packet transmitted without CRC.\n",
+		   dev->name);
+#endif
+
+#ifndef HAVE_NETIF_QUEUE
+	  /* If watchdog was activated, kill it ! */
+	  del_timer(&lp->watchdog);
+#endif
+
+	  /* Get transmission status */
+	  tx_status = inb(LCSR(base));
+	  tx_status |= (inb(LCSR(base)) << 8);
+#ifdef DEBUG_INTERRUPT_INFO
+	  printk(KERN_DEBUG "%s: wv_interrupt(): transmission done\n",
+		 dev->name);
+	  {
+	    u_int	rcv_bytes;
+	    u_char	status3;
+	    rcv_bytes = inb(LCSR(base));
+	    rcv_bytes |= (inb(LCSR(base)) << 8);
+	    status3 = inb(LCSR(base));
+	    printk(KERN_DEBUG "tx_status 0x%02x rcv_bytes 0x%02x status3 0x%x\n",
+		   tx_status, rcv_bytes, (u_int) status3);
+	  }
+#endif
+	  /* Check for possible errors */
+	  if((tx_status & TX_OK) != TX_OK)
+	    {
+	      lp->stats.tx_errors++;
+
+	      if(tx_status & TX_FRTL)
+		{
+#ifdef DEBUG_TX_ERROR
+		  printk(KERN_INFO "%s: wv_interrupt(): frame too long\n",
+			 dev->name);
+#endif
+		}
+	      if(tx_status & TX_UND_RUN)
+		{
+#ifdef DEBUG_TX_FAIL
+		  printk(KERN_DEBUG "%s: wv_interrupt(): DMA underrun\n",
+			 dev->name);
+#endif
+		  lp->stats.tx_aborted_errors++;
+		}
+	      if(tx_status & TX_LOST_CTS)
+		{
+#ifdef DEBUG_TX_FAIL
+		  printk(KERN_DEBUG "%s: wv_interrupt(): no CTS\n", dev->name);
+#endif
+		  lp->stats.tx_carrier_errors++;
+		}
+	      if(tx_status & TX_LOST_CRS)
+		{
+#ifdef DEBUG_TX_FAIL
+		  printk(KERN_DEBUG "%s: wv_interrupt(): no carrier\n",
+			 dev->name);
+#endif
+		  lp->stats.tx_carrier_errors++;
+		}
+	      if(tx_status & TX_HRT_BEAT)
+		{
+#ifdef DEBUG_TX_FAIL
+		  printk(KERN_DEBUG "%s: wv_interrupt(): heart beat\n", dev->name);
+#endif
+		  lp->stats.tx_heartbeat_errors++;
+		}
+	      if(tx_status & TX_DEFER)
+		{
+#ifdef DEBUG_TX_FAIL
+		  printk(KERN_DEBUG "%s: wv_interrupt(): channel jammed\n",
+			 dev->name);
+#endif
+		}
+	      /* Ignore late collisions since they're more likely to happen
+	       * here (the WaveLAN design prevents the LAN controller from
+	       * receiving while it is transmitting). We take action only when
+	       * the maximum retransmit attempts is exceeded.
+	       */
+	      if(tx_status & TX_COLL)
+		{
+		  if(tx_status & TX_MAX_COL)
+		    {
+#ifdef DEBUG_TX_FAIL
+		      printk(KERN_DEBUG "%s: wv_interrupt(): channel congestion\n",
+			     dev->name);
+#endif
+		      if(!(tx_status & TX_NCOL_MASK))
+			{
+			  lp->stats.collisions += 0x10;
+			}
+		    }
+		}
+	    }	/* if(!(tx_status & TX_OK)) */
+
+	  lp->stats.collisions += (tx_status & TX_NCOL_MASK);
+	  lp->stats.tx_packets++;
+
+	  netif_wake_queue(dev);
+	  outb(CR0_INT_ACK | OP0_NOP, LCCR(base));	/* Acknowledge the interrupt */
+    	} 
+      else	/* if interrupt = transmit done or retransmit done */
+	{
+#ifdef DEBUG_INTERRUPT_ERROR
+	  printk(KERN_INFO "wavelan_cs: unknown interrupt, status0 = %02x\n",
+		 status0);
+#endif
+	  outb(CR0_INT_ACK | OP0_NOP, LCCR(base));	/* Acknowledge the interrupt */
+    	}
+    }	/* while(1) */
+
+  spin_unlock(&lp->spinlock);
+
+#ifdef DEBUG_INTERRUPT_TRACE
+  printk(KERN_DEBUG "%s: <-wavelan_interrupt()\n", dev->name);
+#endif
+} /* wv_interrupt */
+
+/*------------------------------------------------------------------*/
+/*
+ * Watchdog: when we start a transmission, a timer is set for us in the
+ * kernel.  If the transmission completes, this timer is disabled. If
+ * the timer expires, we are called and we try to unlock the hardware.
+ *
+ * Note : This watchdog is move clever than the one in the ISA driver,
+ * because it try to abort the current command before reseting
+ * everything...
+ * On the other hand, it's a bit simpler, because we don't have to
+ * deal with the multiple Tx buffers...
+ */
+static void
+#ifndef HAVE_NETIF_QUEUE
+wavelan_watchdog(u_long		a)
+{
+  device *		dev = (device *) a;
+#else
+wavelan_watchdog(device *	dev)
+{
+#endif
+  net_local *		lp = (net_local *) dev->priv;
+  ioaddr_t		base = dev->base_addr;
+  unsigned long		flags;
+  int			aborted = FALSE;
+
+#ifdef DEBUG_INTERRUPT_TRACE
+  printk(KERN_DEBUG "%s: ->wavelan_watchdog()\n", dev->name);
+#endif
+
+#ifdef DEBUG_INTERRUPT_ERROR
+  printk(KERN_INFO "%s: wavelan_watchdog: watchdog timer expired\n",
+	 dev->name);
+#endif
+
+  wv_splhi(lp, &flags);
+
+  /* Ask to abort the current command */
+  outb(OP0_ABORT, LCCR(base));
+
+  /* Wait for the end of the command (a bit hackish) */
+  if(wv_82593_cmd(dev, "wavelan_watchdog(): abort",
+		  OP0_NOP | CR0_STATUS_3, SR0_EXECUTION_ABORTED))
+    aborted = TRUE;
+
+  /* Release spinlock here so that wv_hw_reset() can grab it */
+  wv_splx(lp, &flags);
+
+  /* Check if we were successful in aborting it */
+  if(!aborted)
+    {
+      /* It seem that it wasn't enough */
+#ifdef DEBUG_INTERRUPT_ERROR
+      printk(KERN_INFO "%s: wavelan_watchdog: abort failed, trying reset\n",
+	     dev->name);
+#endif
+      wv_hw_reset(dev);
+    }
+
+#ifdef DEBUG_PSA_SHOW
+  {
+    psa_t		psa;
+    psa_read(dev, 0, (unsigned char *) &psa, sizeof(psa));
+    wv_psa_show(&psa);
+  }
+#endif
+#ifdef DEBUG_MMC_SHOW
+  wv_mmc_show(dev);
+#endif
+#ifdef DEBUG_I82593_SHOW
+  wv_ru_show(dev);
+#endif
+
+  /* We are no more waiting for something... */
+  netif_wake_queue(dev);
+
+#ifdef DEBUG_INTERRUPT_TRACE
+  printk(KERN_DEBUG "%s: <-wavelan_watchdog()\n", dev->name);
+#endif
+}
+
+/********************* CONFIGURATION CALLBACKS *********************/
+/*
+ * Here are the functions called by the pcmcia package (cardmgr) and
+ * linux networking (NET3) for initialization, configuration and
+ * deinstallations of the Wavelan Pcmcia Hardware.
+ */
+
+/*------------------------------------------------------------------*/
+/*
+ * Configure and start up the WaveLAN PCMCIA adaptor.
+ * Called by NET3 when it "open" the device.
+ */
+static int
+wavelan_open(device *	dev)
+{
+  dev_link_t *	link = ((net_local *) dev->priv)->link;
+  net_local *	lp = (net_local *)dev->priv;
+  ioaddr_t	base = dev->base_addr;
+
+#ifdef DEBUG_CALLBACK_TRACE
+  printk(KERN_DEBUG "%s: ->wavelan_open(dev=0x%x)\n", dev->name,
+	 (unsigned int) dev);
+#endif
+
+  /* Check if the modem is powered up (wavelan_close() power it down */
+  if(hasr_read(base) & HASR_NO_CLK)
+    {
+      /* Power up (power up time is 250us) */
+      hacr_write(base, HACR_DEFAULT);
+
+      /* Check if the the module has been powered up... */
+      if(hasr_read(base) & HASR_NO_CLK)
+	{
+#ifdef DEBUG_CONFIG_ERRORS
+	  printk(KERN_WARNING "%s: wavelan_open(): modem not connected\n",
+		 dev->name);
+#endif
+	  return FALSE;
+	}
+    }
+
+  /* Start reception and declare the driver ready */
+  if(!lp->configured)
+    return FALSE;
+  if(!wv_ru_start(dev))
+    wv_hw_reset(dev);		/* If problem : reset */
+  netif_start_queue(dev);
+  netif_mark_up(dev);
+
+  /* Mark the device as used */
+  link->open++;
+  MOD_INC_USE_COUNT;
+
+#ifdef WAVELAN_ROAMING
+  if(do_roaming)
+    wv_roam_init(dev);
+#endif	/* WAVELAN_ROAMING */
+
+#ifdef DEBUG_CALLBACK_TRACE
+  printk(KERN_DEBUG "%s: <-wavelan_open()\n", dev->name);
+#endif
+  return 0;
+}
+
+/*------------------------------------------------------------------*/
+/*
+ * Shutdown the WaveLAN PCMCIA adaptor.
+ * Called by NET3 when it "close" the device.
+ */
+static int
+wavelan_close(device *	dev)
+{
+  dev_link_t *	link = ((net_local *) dev->priv)->link;
+  ioaddr_t	base = dev->base_addr;
+
+#ifdef DEBUG_CALLBACK_TRACE
+  printk(KERN_DEBUG "%s: ->wavelan_close(dev=0x%x)\n", dev->name,
+	 (unsigned int) dev);
+#endif
+
+  /* If the device isn't open, then nothing to do */
+  if(!link->open)
+    {
+#ifdef DEBUG_CONFIG_INFO
+      printk(KERN_DEBUG "%s: wavelan_close(): device not open\n", dev->name);
+#endif
+      return 0;
+    }
+
+#ifdef WAVELAN_ROAMING
+  /* Cleanup of roaming stuff... */
+  if(do_roaming)
+    wv_roam_cleanup(dev);
+#endif	/* WAVELAN_ROAMING */
+
+#ifndef HAVE_NETIF_QUEUE
+  /* If watchdog was activated, kill it ! */
+    del_timer(&((net_local *)dev->priv)->watchdog);
+#endif
+
+  link->open--;
+  MOD_DEC_USE_COUNT;
+
+  /* If the card is still present */
+  if(netif_running(dev))
+    {
+      netif_stop_queue(dev);
+      netif_mark_down(dev);
+
+      /* Stop receiving new messages and wait end of transmission */
+      wv_ru_stop(dev);
+
+      /* Power down the module */
+      hacr_write(base, HACR_DEFAULT & (~HACR_PWR_STAT));
+    }
+  else
+    /* The card is no more there (flag is activated in wv_pcmcia_release) */
+    if(link->state & DEV_STALE_CONFIG)
+      wv_pcmcia_release((u_long)link);
+
+#ifdef DEBUG_CALLBACK_TRACE
+  printk(KERN_DEBUG "%s: <-wavelan_close()\n", dev->name);
+#endif
+  return 0;
+}
+
+/*------------------------------------------------------------------*/
+/*
+ * wavelan_attach() creates an "instance" of the driver, allocating
+ * local data structures for one device (one interface).  The device
+ * is registered with Card Services.
+ *
+ * The dev_link structure is initialized, but we don't actually
+ * configure the card at this point -- we wait until we receive a
+ * card insertion event.
+ */
+static dev_link_t *
+wavelan_attach(void)
+{
+  client_reg_t	client_reg;	/* Register with cardmgr */
+  dev_link_t *	link;		/* Info for cardmgr */
+  device *	dev;		/* Interface generic data */
+  net_local *	lp;		/* Interface specific data */
+  int		i, ret;
+
+#ifdef DEBUG_CALLBACK_TRACE
+  printk(KERN_DEBUG "-> wavelan_attach()\n");
+#endif
+
+  /* Perform some cleanup */
+  wv_flush_stale_links();
+
+  /* Initialize the dev_link_t structure */
+  link = kmalloc(sizeof(struct dev_link_t), GFP_KERNEL);
+  memset(link, 0, sizeof(struct dev_link_t));
+
+  /* Unused for the Wavelan */
+  link->release.function = &wv_pcmcia_release;
+  link->release.data = (u_long) link;
+
+  /* The io structure describes IO port mapping */
+  link->io.NumPorts1 = 8;
+  link->io.Attributes1 = IO_DATA_PATH_WIDTH_8;
+  link->io.IOAddrLines = 3;
+
+  /* Interrupt setup */
+  link->irq.Attributes = IRQ_TYPE_EXCLUSIVE | IRQ_HANDLE_PRESENT;
+  link->irq.IRQInfo1 = IRQ_INFO2_VALID | IRQ_LEVEL_ID;
+  if (irq_list[0] == -1)
+    link->irq.IRQInfo2 = irq_mask;
+  else
+    for (i = 0; i < 4; i++)
+      link->irq.IRQInfo2 |= 1 << irq_list[i];
+  link->irq.Handler = wavelan_interrupt;
+
+  /* General socket configuration */
+  link->conf.Attributes = CONF_ENABLE_IRQ;
+  link->conf.Vcc = 50;
+  link->conf.IntType = INT_MEMORY_AND_IO;
+
+  /* Chain drivers */
+  link->next = dev_list;
+  dev_list = link;
+
+  /* Allocate the generic data structure */
+  dev = kmalloc(sizeof(struct net_device), GFP_KERNEL);
+  memset(dev, 0x00, sizeof(struct net_device));
+  link->priv = link->irq.Instance = dev;
+
+  /* Allocate the wavelan-specific data structure. */
+  dev->priv = lp = (net_local *) kmalloc(sizeof(net_local), GFP_KERNEL);
+  memset(lp, 0x00, sizeof(net_local));
+
+  /* Init specific data */
+  lp->configured = 0;
+  lp->reconfig_82593 = FALSE;
+  lp->nresets = 0;
+  /* Multicast stuff */
+  lp->promiscuous = 0;
+  lp->allmulticast = 0;
+  lp->mc_count = 0;
+
+  /* Init spinlock */
+  spin_lock_init(&lp->spinlock);
+
+  /* back links */
+  lp->link = link;
+  lp->dev = dev;
+
+  /* Standard setup for generic data */
+  ether_setup(dev);
+
+  /* wavelan NET3 callbacks */
+  dev->open = &wavelan_open;
+  dev->stop = &wavelan_close;
+  dev->hard_start_xmit = &wavelan_packet_xmit;
+  dev->get_stats = &wavelan_get_stats;
+  dev->set_multicast_list = &wavelan_set_multicast_list;
+#ifdef SET_MAC_ADDRESS
+  dev->set_mac_address = &wavelan_set_mac_address;
+#endif	/* SET_MAC_ADDRESS */
+
+#ifdef HAVE_NETIF_QUEUE
+  /* Set the watchdog timer */
+  dev->tx_timeout	= &wavelan_watchdog;
+  dev->watchdog_timeo	= WATCHDOG_JIFFIES;
+#else
+  lp->watchdog.function = wavelan_watchdog;
+  lp->watchdog.data = (unsigned long) dev;
+#endif
+
+#ifdef WIRELESS_EXT	/* If wireless extension exist in the kernel */
+  dev->do_ioctl = wavelan_ioctl;	/* wireless extensions */
+  dev->get_wireless_stats = wavelan_get_wireless_stats;
+#endif
+
+  /* Other specific data */
+  /* Provide storage area for device name */
+  dev->name = ((net_local *)dev->priv)->node.dev_name;
+  dev->mtu = WAVELAN_MTU;
+
+  /* Register with Card Services */
+  client_reg.dev_info = &dev_info;
+  client_reg.Attributes = INFO_IO_CLIENT | INFO_CARD_SHARE;
+  client_reg.EventMask = 
+    CS_EVENT_REGISTRATION_COMPLETE |
+    CS_EVENT_CARD_INSERTION | CS_EVENT_CARD_REMOVAL |
+    CS_EVENT_RESET_PHYSICAL | CS_EVENT_CARD_RESET |
+    CS_EVENT_PM_SUSPEND | CS_EVENT_PM_RESUME;
+  client_reg.event_handler = &wavelan_event;
+  client_reg.Version = 0x0210;
+  client_reg.event_callback_args.client_data = link;
+
+#ifdef DEBUG_CONFIG_INFO
+  printk(KERN_DEBUG "wavelan_attach(): almost done, calling CardServices\n");
+#endif
+
+  ret = CardServices(RegisterClient, &link->handle, &client_reg);
+  if(ret != 0)
+    {
+      cs_error(link->handle, RegisterClient, ret);
+      wavelan_detach(link);
+      return NULL;
+    }
+
+#ifdef DEBUG_CALLBACK_TRACE
+  printk(KERN_DEBUG "<- wavelan_attach()\n");
+#endif
+
+  return link;
+}
+
+/*------------------------------------------------------------------*/
+/*
+ * This deletes a driver "instance".  The device is de-registered with
+ * Card Services.  If it has been released, all local data structures
+ * are freed.  Otherwise, the structures will be freed when the device
+ * is released.
+ */
+static void
+wavelan_detach(dev_link_t *	link)
+{
+#ifdef DEBUG_CALLBACK_TRACE
+  printk(KERN_DEBUG "-> wavelan_detach(0x%p)\n", link);
+#endif
+
+  /*
+   * If the device is currently configured and active, we won't
+   * actually delete it yet.  Instead, it is marked so that when the
+   * release() function is called, that will trigger a proper
+   * detach().
+   */
+  if(link->state & DEV_CONFIG)
+    {
+      /* Some others haven't done their job : give them another chance */
+      wv_pcmcia_release((u_long) link);
+      if(link->state & DEV_STALE_CONFIG)
+	{
+#ifdef DEBUG_CONFIG_INFO
+	  printk(KERN_DEBUG "wavelan_detach: detach postponed,"
+		 " '%s' still locked\n", link->dev->dev_name);
+#endif
+	  link->state |= DEV_STALE_LINK;
+	  return;
+	}
+    }
+
+  /* Break the link with Card Services */
+  if(link->handle)
+    CardServices(DeregisterClient, link->handle);
+    
+  /* Remove the interface data from the linked list */
+  if(dev_list == link)
+    dev_list = link->next;
+  else
+    {
+      dev_link_t *	prev = dev_list;
+
+      while((prev != (dev_link_t *) NULL) && (prev->next != link))
+	prev = prev->next;
+
+      if(prev == (dev_link_t *) NULL)
+	{
+#ifdef DEBUG_CONFIG_ERRORS
+	  printk(KERN_WARNING "wavelan_detach : Attempting to remove a nonexistent device.\n");
+#endif
+	  return;
+	}
+
+      prev->next = link->next;
+    }
+
+  /* Free pieces */
+  if(link->priv)
+    {
+      device *	dev = (device *) link->priv;
+
+      /* Remove ourselves from the kernel list of ethernet devices */
+      /* Warning : can't be called from interrupt, timer or wavelan_close() */
+      if(link->dev != NULL)
+	unregister_netdev(dev);
+      link->dev = NULL;
+
+      if(dev->priv)
+	{
+	  /* Sound strange, but safe... */
+	  ((net_local *) dev->priv)->link = (dev_link_t *) NULL;
+	  ((net_local *) dev->priv)->dev = (device *) NULL;
+	  kfree(dev->priv);
+	}
+      kfree(link->priv);
+    }
+  kfree(link);
+
+#ifdef DEBUG_CALLBACK_TRACE
+  printk(KERN_DEBUG "<- wavelan_detach()\n");
+#endif
+}
+
+/*------------------------------------------------------------------*/
+/*
+ * The card status event handler. Mostly, this schedules other stuff
+ * to run after an event is received. A CARD_REMOVAL event also sets
+ * some flags to discourage the net drivers from trying to talk to the
+ * card any more.
+ */
+static int
+wavelan_event(event_t		event,		/* The event received */
+	      int		priority,
+	      event_callback_args_t *	args)
+{
+  dev_link_t *	link = (dev_link_t *) args->client_data;
+  device *	dev = (device *) link->priv;
+
+#ifdef DEBUG_CALLBACK_TRACE
+  printk(KERN_DEBUG "->wavelan_event(): %s\n",
+	 ((event == CS_EVENT_REGISTRATION_COMPLETE)?"registration complete" :
+	  ((event == CS_EVENT_CARD_REMOVAL) ? "card removal" :
+	   ((event == CS_EVENT_CARD_INSERTION) ? "card insertion" :
+	    ((event == CS_EVENT_PM_SUSPEND) ? "pm suspend" :
+	     ((event == CS_EVENT_RESET_PHYSICAL) ? "physical reset" :
+	      ((event == CS_EVENT_PM_RESUME) ? "pm resume" :
+	       ((event == CS_EVENT_CARD_RESET) ? "card reset" :
+		"unknown"))))))));
+#endif
+
+    switch(event)
+      {
+      case CS_EVENT_REGISTRATION_COMPLETE:
+#ifdef DEBUG_CONFIG_INFO
+	printk(KERN_DEBUG "wavelan_cs: registration complete\n");
+#endif
+	break;
+
+      case CS_EVENT_CARD_REMOVAL:
+	/* Oups ! The card is no more there */
+	link->state &= ~DEV_PRESENT;
+	if(link->state & DEV_CONFIG)
+	  {
+	    /* Accept no more transmissions */
+	    netif_device_detach(dev);
+
+	    /* Release the card */
+	    wv_pcmcia_release((u_long) link);
+	  }
+	break;
+
+      case CS_EVENT_CARD_INSERTION:
+	/* Reset and configure the card */
+	link->state |= DEV_PRESENT | DEV_CONFIG_PENDING;
+	if(wv_pcmcia_config(link) &&
+	   wv_hw_config(dev))
+	  wv_init_info(dev);
+	else
+	  dev->irq = 0;
+	break;
+
+      case CS_EVENT_PM_SUSPEND:
+	/* NB: wavelan_close will be called, but too late, so we are
+	 * obliged to close nicely the wavelan here. David, could you
+	 * close the device before suspending them ? And, by the way,
+	 * could you, on resume, add a "route add -net ..." after the
+	 * ifconfig up ??? Thanks... */
+
+	/* Stop receiving new messages and wait end of transmission */
+	wv_ru_stop(dev);
+
+	/* Power down the module */
+	hacr_write(dev->base_addr, HACR_DEFAULT & (~HACR_PWR_STAT));
+
+	/* The card is now suspended */
+	link->state |= DEV_SUSPEND;
+	/* Fall through... */
+      case CS_EVENT_RESET_PHYSICAL:
+    	if(link->state & DEV_CONFIG)
+	  {
+      	    if(link->open)
+	      netif_device_detach(dev);
+      	    CardServices(ReleaseConfiguration, link->handle);
+	  }
+	break;
+
+      case CS_EVENT_PM_RESUME:
+	link->state &= ~DEV_SUSPEND;
+	/* Fall through... */
+      case CS_EVENT_CARD_RESET:
+	if(link->state & DEV_CONFIG)
+	  {
+      	    CardServices(RequestConfiguration, link->handle, &link->conf);
+      	    if(link->open)	/* If RESET -> True, If RESUME -> False ??? */
+	      {
+		wv_hw_reset(dev);
+		netif_device_attach(dev);
+	      }
+	  }
+	break;
+    }
+
+#ifdef DEBUG_CALLBACK_TRACE
+  printk(KERN_DEBUG "<-wavelan_event()\n");
+#endif
+  return 0;
+}
+
+/****************************** MODULE ******************************/
+/*
+ * Module entry points : insertion & removal
+ */
+
+/*------------------------------------------------------------------*/
+/*
+ * Module insertion : initialisation of the module.
+ * Register the card with cardmgr...
+ */
+static int __init
+init_wavelan_cs(void)
+{
+  servinfo_t	serv;
+
+#ifdef DEBUG_MODULE_TRACE
+  printk(KERN_DEBUG "-> init_wavelan_cs()\n");
+#ifdef DEBUG_VERSION_SHOW
+  printk(KERN_DEBUG "%s", version);
+#endif
+#endif
+
+  CardServices(GetCardServicesInfo, &serv);
+  if(serv.Revision != CS_RELEASE_CODE)
+    {
+#ifdef DEBUG_CONFIG_ERRORS
+      printk(KERN_WARNING "init_wavelan_cs: Card Services release does not match!\n");
+#endif
+      return -1;
+    }
+
+  register_pccard_driver(&dev_info, &wavelan_attach, &wavelan_detach);
+
+#ifdef DEBUG_MODULE_TRACE
+  printk(KERN_DEBUG "<- init_wavelan_cs()\n");
+#endif
+  return 0;
+}
+
+/*------------------------------------------------------------------*/
+/*
+ * Module removal
+ */
+static void __exit
+exit_wavelan_cs(void)
+{
+#ifdef DEBUG_MODULE_TRACE
+  printk(KERN_DEBUG "-> cleanup_module()\n");
+#endif
+#ifdef DEBUG_BASIC_SHOW
+  printk(KERN_NOTICE "wavelan_cs: unloading\n");
+#endif
+
+  /* Do some cleanup of the device list */
+  wv_flush_stale_links();
+
+  /* If there remain some devices... */
+#ifdef DEBUG_CONFIG_ERRORS
+  if(dev_list != NULL)
+    {
+      /* Honestly, if this happen we are in a deep s**t */
+      printk(KERN_INFO "wavelan_cs: devices remaining when removing module\n");
+      printk(KERN_INFO "Please flush your disks and reboot NOW !\n");
+    }
+#endif
+
+  unregister_pccard_driver(&dev_info);
+
+#ifdef DEBUG_MODULE_TRACE
+  printk(KERN_DEBUG "<- cleanup_module()\n");
+#endif
+}
+
+module_init(init_wavelan_cs);
+module_exit(exit_wavelan_cs);
Index: oldkernel/linux/pcmcia-cs-3.1.15/wireless/wavelan_cs.h
diff -u /dev/null linux/pcmcia-cs-3.1.15/wireless/wavelan_cs.h:1.1
--- /dev/null	Mon Jul 31 21:15:12 2000
+++ linux/pcmcia-cs-3.1.15/wireless/wavelan_cs.h	Fri Jul  7 16:34:59 2000
@@ -0,0 +1,835 @@
+/*
+ *	Wavelan Pcmcia driver
+ *
+ *		Jean II - HPLB '96
+ *
+ * Reorganisation and extension of the driver.
+ *
+ * This file contain all definition and declarations necessary for the
+ * wavelan pcmcia driver. This file is a private header, so it should
+ * be included only on wavelan_cs.c !!!
+ */
+
+#ifndef WAVELAN_CS_H
+#define WAVELAN_CS_H
+
+/************************** DOCUMENTATION **************************/
+/*
+ * This driver provide a Linux interface to the Wavelan Pcmcia hardware
+ * The Wavelan is a product of Lucent (http://www.wavelan.com/).
+ * This division was formerly part of NCR and then AT&T.
+ * Wavelan are also distributed by DEC (RoamAbout DS)...
+ *
+ * To know how to use this driver, read the PCMCIA HOWTO.
+ * If you want to exploit the many other fonctionalities, look comments
+ * in the code...
+ *
+ * This driver is the result of the effort of many peoples (see below).
+ */
+
+/* ------------------------ SPECIFIC NOTES ------------------------ */
+/*
+ * Web page
+ * --------
+ *	I try to maintain a web page with the Wireless LAN Howto at :
+ *	    http://www.hpl.hp.com/personal/Jean_Tourrilhes/Linux/Wavelan.html
+ *
+ * SMP
+ * ---
+ *	We now *should* be SMP compliant.
+ *	I don't have a SMP box to verify that (my Pentium 133 is not), so
+ *	someone has to certify that from me.
+ *	Anyway, I spent enough time chasing interrupt re-entrancy during
+ *	errors or reconfigure, and I designed the locked/unlocked sections
+ *	of the driver with great care, and with the recent addition of
+ *	the spinlock (thanks to the new API), we should be quite close to
+ *	the truth.
+ *	The SMP/IRQ locking is quite coarse and conservative (i.e. not fast),
+ *	but better safe than sorry (especially at 2 Mb/s ;-).
+ *
+ *	I have also looked into disabling only our interrupt on the card
+ *	(via HACR) instead of all interrupts in the processor (via cli),
+ *	so that other driver are not impacted, and it look like it's
+ *	possible, but it's very tricky to do right (full of races). As
+ *	the gain would be mostly for SMP systems, it can wait...
+ *
+ * Debugging and options
+ * ---------------------
+ *	You will find below a set of '#define" allowing a very fine control
+ *	on the driver behaviour and the debug messages printed.
+ *	The main options are :
+ *	o WAVELAN_ROAMING, for the experimental roaming support.
+ *	o SET_PSA_CRC, to have your card correctly recognised by
+ *	  an access point and the Point-to-Point diagnostic tool.
+ *	o USE_PSA_CONFIG, to read configuration from the PSA (EEprom)
+ *	  (otherwise we always start afresh with some defaults)
+ *
+ * wavelan_cs.o is darn too big
+ * -------------------------
+ *	That's true ! There is a very simple way to reduce the driver
+ *	object by 33% (yes !). Comment out the following line :
+ *		#include <linux/wireless.h>
+ *	Other compile options can also reduce the size of it...
+ *
+ * MAC address and hardware detection :
+ * ----------------------------------
+ *	The detection code of the wavelan chech that the first 3
+ *	octets of the MAC address fit the company code. This type of
+ *	detection work well for AT&T cards (because the AT&T code is
+ *	hardcoded in wavelan.h), but of course will fail for other
+ *	manufacturer.
+ *
+ *	If you are sure that your card is derived from the wavelan,
+ *	here is the way to configure it :
+ *	1) Get your MAC address
+ *		a) With your card utilities (wfreqsel, instconf, ...)
+ *		b) With the driver :
+ *			o compile the kernel with DEBUG_CONFIG_INFO enabled
+ *			o Boot and look the card messages
+ *	2) Set your MAC code (3 octets) in MAC_ADDRESSES[][3] (wavelan.h)
+ *	3) Compile & verify
+ *	4) Send me the MAC code - I will include it in the next version...
+ *
+ */
+
+/* --------------------- WIRELESS EXTENSIONS --------------------- */
+/*
+ * This driver is the first one to support "wireless extensions".
+ * This set of extensions provide you some way to control the wireless
+ * caracteristics of the hardware in a standard way and support for
+ * applications for taking advantage of it (like Mobile IP).
+ *
+ * You will need to enable the CONFIG_NET_RADIO define in the kernel
+ * configuration to enable the wireless extensions (this is the one
+ * giving access to the radio network device choice).
+ *
+ * It might also be a good idea as well to fetch the wireless tools to
+ * configure the device and play a bit.
+ */
+
+/* ---------------------------- FILES ---------------------------- */
+/*
+ * wavelan_cs.c :	The actual code for the driver - C functions
+ *
+ * wavelan_cs.h :	Private header : local types / vars for the driver
+ *
+ * wavelan.h :		Description of the hardware interface & structs
+ *
+ * i82593.h :		Description if the Ethernet controler
+ */
+
+/* --------------------------- HISTORY --------------------------- */
+/*
+ * The history of the Wavelan drivers is as complicated as history of
+ * the Wavelan itself (NCR -> AT&T -> Lucent).
+ *
+ * All started with Anders Klemets <klemets@paul.rutgers.edu>,
+ * writting a Wavelan ISA driver for the MACH microkernel. Girish
+ * Welling <welling@paul.rutgers.edu> had also worked on it.
+ * Keith Moore modify this for the Pcmcia hardware.
+ * 
+ * Robert Morris <rtm@das.harvard.edu> port these two drivers to BSDI
+ * and add specific Pcmcia support (there is currently no equivalent
+ * of the PCMCIA package under BSD...).
+ *
+ * Jim Binkley <jrb@cs.pdx.edu> port both BSDI drivers to FreeBSD.
+ *
+ * Bruce Janson <bruce@cs.usyd.edu.au> port the BSDI ISA driver to Linux.
+ *
+ * Anthony D. Joseph <adj@lcs.mit.edu> started modify Bruce driver
+ * (with help of the BSDI PCMCIA driver) for PCMCIA.
+ * Yunzhou Li <yunzhou@strat.iol.unh.edu> finished is work.
+ * Joe Finney <joe@comp.lancs.ac.uk> patched the driver to start
+ * correctly 2.00 cards (2.4 GHz with frequency selection).
+ * David Hinds <dhinds@pcmcia.sourceforge.org> integrated the whole in his
+ * Pcmcia package (+ bug corrections).
+ *
+ * I (Jean Tourrilhes - jt@hplb.hpl.hp.com) then started to make some
+ * patchs to the Pcmcia driver. After, I added code in the ISA driver
+ * for Wireless Extensions and full support of frequency selection
+ * cards. Now, I'm doing the same to the Pcmcia driver + some
+ * reorganisation.
+ * Loeke Brederveld <lbrederv@wavelan.com> from Lucent has given me
+ * much needed informations on the Wavelan hardware.
+ */
+
+/* By the way : for the copyright & legal stuff :
+ * Almost everybody wrote code under GNU or BSD license (or alike),
+ * and want that their original copyright remain somewhere in the
+ * code (for myself, I go with the GPL).
+ * Nobody want to take responsibility for anything, except the fame...
+ */
+
+/* --------------------------- CREDITS --------------------------- */
+/*
+ * Credits:
+ *    Special thanks to Jan Hoogendoorn of AT&T GIS Utrecht and
+ *	Loeke Brederveld of Lucent for providing extremely useful
+ *	information about WaveLAN PCMCIA hardware
+ *
+ *    This driver is based upon several other drivers, in particular:
+ *	David Hinds' Linux driver for the PCMCIA 3c589 ethernet adapter
+ *	Bruce Janson's Linux driver for the AT-bus WaveLAN adapter
+ *	Anders Klemets' PCMCIA WaveLAN adapter driver
+ *	Robert Morris' BSDI driver for the PCMCIA WaveLAN adapter
+ *
+ * Additional Credits:
+ *
+ *    This software was originally developed under Linux 1.2.3
+ *	(Slackware 2.0 distribution).
+ *    And then under Linux 2.0.x (Debian 1.1 -> 2.2 - pcmcia 2.8.18+)
+ *	with an HP OmniBook 4000 and then a 5500.
+ *
+ *    It is based on other device drivers and information either written
+ *    or supplied by:
+ *	James Ashton (jaa101@syseng.anu.edu.au),
+ *	Ajay Bakre (bakre@paul.rutgers.edu),
+ *	Donald Becker (becker@super.org),
+ *	Jim Binkley <jrb@cs.pdx.edu>,
+ *	Loeke Brederveld <lbrederv@wavelan.com>,
+ *	Allan Creighton (allanc@cs.su.oz.au),
+ *	Brent Elphick <belphick@uwaterloo.ca>,
+ *	Joe Finney <joe@comp.lancs.ac.uk>,
+ *	Matthew Geier (matthew@cs.su.oz.au),
+ *	Remo di Giovanni (remo@cs.su.oz.au),
+ *	Mark Hagan (mhagan@wtcpost.daytonoh.NCR.COM),
+ *	David Hinds <dhinds@pcmcia.sourceforge.org>,
+ *	Jan Hoogendoorn (c/o marteijn@lucent.com),
+ *      Bruce Janson <bruce@cs.usyd.edu.au>,
+ *	Anthony D. Joseph <adj@lcs.mit.edu>,
+ *	Anders Klemets (klemets@paul.rutgers.edu),
+ *	Yunzhou Li <yunzhou@strat.iol.unh.edu>,
+ *	Marc Meertens (mmeertens@lucent.com),
+ *	Keith Moore,
+ *	Robert Morris (rtm@das.harvard.edu),
+ *	Ian Parkin (ian@cs.su.oz.au),
+ *	John Rosenberg (johnr@cs.su.oz.au),
+ *	George Rossi (george@phm.gov.au),
+ *	Arthur Scott (arthur@cs.su.oz.au),
+ *	Stanislav Sinyagin <stas@isf.ru>
+ *	Peter Storey,
+ *	Jean Tourrilhes <jt@hpl.hp.com>,
+ *	Girish Welling (welling@paul.rutgers.edu)
+ *	Clark Woodworth <clark@hiway1.exit109.com>
+ *	Yongguang Zhang <ygz@isl.hrl.hac.com>...
+ */
+
+/* ------------------------- IMPROVEMENTS ------------------------- */
+/*
+ * I proudly present :
+ *
+ * Changes made in 2.8.22 :
+ * ----------------------
+ *	- improved wv_set_multicast_list
+ *	- catch spurious interrupt
+ *	- correct release of the device
+ *
+ * Changes mades in release :
+ * ------------------------
+ *	- Reorganisation of the code, function name change
+ *	- Creation of private header (wavelan_cs.h)
+ *	- Reorganised debug messages
+ *	- More comments, history, ...
+ *	- Configure earlier (in "insert" instead of "open")
+ *        and do things only once
+ *	- mmc_init : configure the PSA if not done
+ *	- mmc_init : 2.00 detection better code for 2.00 init
+ *	- better info at startup
+ *	- Correct a HUGE bug (volatile & uncalibrated busy loop)
+ *	  in wv_82593_cmd => config speedup
+ *	- Stop receiving & power down on close (and power up on open)
+ *	  use "ifconfig down" & "ifconfig up ; route add -net ..."
+ *	- Send packets : add watchdog instead of pooling
+ *	- Receive : check frame wrap around & try to recover some frames
+ *	- wavelan_set_multicast_list : avoid reset
+ *	- add wireless extensions (ioctl & get_wireless_stats)
+ *	  get/set nwid/frequency on fly, info for /proc/net/wireless
+ *	- Supress useless stuff from lp (net_local), but add link
+ *	- More inlines
+ *	- Lot of others minor details & cleanups
+ *
+ * Changes made in second release :
+ * ------------------------------
+ *	- Optimise wv_85893_reconfig stuff, fix potential problems
+ *	- Change error values for ioctl
+ *	- Non blocking wv_ru_stop() + call wv_reset() in case of problems
+ *	- Remove development printk from wavelan_watchdog()
+ *	- Remove of the watchdog to wavelan_close instead of wavelan_release
+ *	  fix potential problems...
+ *	- Start debugging suspend stuff (but it's still a bit weird)
+ *	- Debug & optimize dump header/packet in Rx & Tx (debug)
+ *	- Use "readb" and "writeb" to be kernel 2.1 compliant
+ *	- Better handling of bogus interrupts
+ *	- Wireless extension : SETSPY and GETSPY
+ *	- Remove old stuff (stats - for those needing it, just ask me...)
+ *	- Make wireless extensions optional
+ *
+ * Changes made in third release :
+ * -----------------------------
+ *	- cleanups & typos
+ *	- modif wireless ext (spy -> only one pointer)
+ *	- new private ioctl to set/get quality & level threshold
+ *	- Init : correct default value of level threshold for pcmcia
+ *	- kill watchdog in hw_reset
+ *	- more 2.1 support (copy_to/from_user instead of memcpy_to/fromfs)
+ *	- Add message level (debug stuff in /var/adm/debug & errors not
+ *	  displayed at console and still in /var/adm/messages)
+ *
+ * Changes made in fourth release :
+ * ------------------------------
+ *	- multicast support (yes !) thanks to Yongguang Zhang.
+ *
+ * Changes made in fifth release (2.9.0) :
+ * -------------------------------------
+ *	- Revisited multicast code (it was mostly wrong).
+ *	- protect code in wv_82593_reconfig with dev->tbusy (oups !)
+ *
+ * Changes made in sixth release (2.9.1a) :
+ * --------------------------------------
+ *	- Change the detection code for multi manufacturer code support
+ *	- Correct bug (hang kernel) in init when we were "rejecting" a card 
+ *
+ * Changes made in seventh release (2.9.1b) :
+ * ----------------------------------------
+ *	- Update to wireless extensions changes
+ *	- Silly bug in card initial configuration (psa_conf_status)
+ *
+ * Changes made in eigth release :
+ * -----------------------------
+ *	- Small bug in debug code (probably not the last one...)
+ *	- 1.2.13 support (thanks to Clark Woodworth)
+ *
+ * Changes made for release in 2.9.2b :
+ * ----------------------------------
+ *	- Level threshold is now a standard wireless extension (version 4 !)
+ *	- modules parameters types for kernel > 2.1.17
+ *	- updated man page
+ *	- Others cleanup from David Hinds
+ *
+ * Changes made for release in 2.9.5 :
+ * ---------------------------------
+ *	- byte count stats (courtesy of David Hinds)
+ *	- Remove dev_tint stuff (courtesy of David Hinds)
+ *	- Others cleanup from David Hinds
+ *	- Encryption setting from Brent Elphick (thanks a lot !)
+ *	- 'base' to 'u_long' for the Alpha (thanks to Stanislav Sinyagin)
+ *
+ * Changes made for release in 2.9.6 :
+ * ---------------------------------
+ *	- fix bug : no longuer disable watchdog in case of bogus interrupt
+ *	- increase timeout in config code for picky hardware
+ *	- mask unused bits in status (Wireless Extensions)
+ *
+ * Changes integrated by Justin Seger <jseger@MIT.EDU> & David Hinds :
+ * -----------------------------------------------------------------
+ *	- Roaming "hack" from Joe Finney <joe@comp.lancs.ac.uk>
+ *	- PSA CRC code from Bob Gray <rgray@bald.cs.dartmouth.edu>
+ *	- Better initialisation of the i82593 controller
+ *	  from Joseph K. O'Sullivan <josullvn+@cs.cmu.edu>
+ *
+ * Changes made for release in 3.0.10 :
+ * ----------------------------------
+ *	- Fix eject "hang" of the driver under 2.2.X :
+ *		o create wv_flush_stale_links()
+ *		o Rename wavelan_release to wv_pcmcia_release & move up
+ *		o move unregister_netdev to wavelan_detach()
+ *		o wavelan_release() no longer call wavelan_detach()
+ *		o Supress "release" timer
+ *		o Other cleanups & fixes
+ *	- New MAC address in the probe
+ *	- Reorg PSA_CRC code (endian neutral & cleaner)
+ *	- Correct initialisation of the i82593 from Lucent manual
+ *	- Put back the watchdog, with larger timeout
+ *	- TRANSMIT_NO_CRC is a "normal" error, so recover from it
+ *	  from Derrick J Brashear <shadow@dementia.org>
+ *	- Better handling of TX and RX normal failure conditions
+ *	- #ifdef out all the roaming code
+ *	- Add ESSID & "AP current address" ioctl stubs
+ *	- General cleanup of the code
+ *
+ * Changes made for release in 3.0.13 :
+ * ----------------------------------
+ *	- Re-enable compilation of roaming code by default, but with
+ *	  do_roaming = 0
+ *	- Nuke `nwid=nwid^ntohs(beacon->domain_id)' in wl_roam_gather
+ *	  at the demand of John Carol Langford <jcl@gs176.sp.cs.cmu.edu>
+ *	- Introduced WAVELAN_ROAMING_EXT for incomplete ESSID stuff.
+ *
+ * Changes made for release in 3.0.15 :
+ * ----------------------------------
+ *	- Change e-mail and web page addresses
+ *	- Watchdog timer is now correctly expressed in HZ, not in jiffies
+ *	- Add channel number to the list of frequencies in range
+ *	- Add the (short) list of bit-rates in range
+ *	- Developp a new sensitivity... (sens.value & sens.fixed)
+ *
+ * Changes made for release in 3.1.2 :
+ * ---------------------------------
+ *	- Fix check for root permission (break instead of exit)
+ *	- New nwid & encoding setting (Wireless Extension 9)
+ *
+ * Changes made for release in 3.1.12 :
+ * ----------------------------------
+ *	- reworked wv_82593_cmd to avoid using the IRQ handler and doing
+ *	  ugly things with interrupts.
+ *	- Add IRQ protection in 82593_config/ru_start/ru_stop/watchdog
+ *	- Update to new network API (softnet - 2.3.43) :
+ *		o replace dev->tbusy (David + me)
+ *		o replace dev->tstart (David + me)
+ *		o remove dev->interrupt (David)
+ *		o add SMP locking via spinlock in splxx (me)
+ *		o add spinlock in interrupt handler (me)
+ *		o use kernel watchdog instead of ours (me)
+ *		o verify that all the changes make sense and work (me)
+ *	- Re-sync kernel/pcmcia versions (not much actually)
+ *	- A few other cleanups (David & me)...
+ *
+ * Wishes & dreams:
+ * ----------------
+ *	- Cleanup and integrate the roaming code
+ *	  (std debug, set DomainID, decay avg and co...)
+ */
+
+/***************************** INCLUDES *****************************/
+
+#undef IN_KERNEL_SOURCE
+#ifndef IN_KERNEL_SOURCE		/* David : check this out ! */
+#include <pcmcia/config.h>
+#include <pcmcia/k_compat.h>
+#endif	/* IN_KERNEL_SOURCE */
+
+/* Linux headers that we need */
+#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/sched.h>
+#include <linux/ptrace.h>
+#include <linux/malloc.h>
+#include <linux/string.h>
+#include <linux/timer.h>
+#include <linux/interrupt.h>
+#include <linux/in.h>
+#include <linux/delay.h>
+#include <asm/uaccess.h>
+#include <asm/io.h>
+#include <asm/system.h>
+#include <asm/bitops.h>
+
+#include <linux/netdevice.h>
+#include <linux/etherdevice.h>
+#include <linux/skbuff.h>
+#include <linux/if_arp.h>
+#include <linux/ioport.h>
+#include <linux/fcntl.h>
+
+#ifdef IN_KERNEL_SOURCE		/* David : check this out ! */
+#ifdef CONFIG_NET_PCMCIA_RADIO
+#include <linux/wireless.h>		/* Wireless extensions */
+#endif	/* CONFIG_NET_PCMCIA_RADIO */
+#else	/* IN_KERNEL_SOURCE */
+#ifdef HAS_WIRELESS_EXTENSIONS
+#include <linux/wireless.h>		/* Wireless extensions */
+#endif	/* HAS_WIRELESS_EXTENSIONS */
+#endif	/* IN_KERNEL_SOURCE */
+
+/* Pcmcia headers that we need */
+#include <pcmcia/cs_types.h>
+#include <pcmcia/cs.h>
+#include <pcmcia/cistpl.h>
+#include <pcmcia/cisreg.h>
+#include <pcmcia/ds.h>
+#include <pcmcia/version.h>
+
+/* Wavelan declarations */
+#include "i82593.h"	/* Definitions for the Intel chip */
+
+#include "wavelan.h"	/* Others bits of the hardware */
+
+/*********************** KERNEL COMPATIBILITY ***********************/
+/* Hyde some uglyness... */
+
+/* These are also useful...
+ */
+#ifndef HAVE_NETIF_QUEUE
+#define devstate(dev)			((dev->tbusy) | (dev->start << 1))
+#else	/* 2.3.47 */
+#define devstate(dev)			(dev->state)
+#endif	/* 2.3.47 */
+
+/************************** DRIVER OPTIONS **************************/
+/*
+ * `#define' or `#undef' the following constant to change the behaviour
+ * of the driver...
+ */
+#define WAVELAN_ROAMING		/* Include experimental roaming code */
+#undef WAVELAN_ROAMING_EXT	/* Enable roaming wireless extensions */
+#undef SET_PSA_CRC		/* Set the CRC in PSA (slower) */
+#define USE_PSA_CONFIG		/* Use info from the PSA */
+#undef STRUCT_CHECK		/* Verify padding of structures */
+#undef EEPROM_IS_PROTECTED	/* Doesn't seem to be necessary */
+#define MULTICAST_AVOID		/* Avoid extra multicast (I'm sceptical) */
+#undef SET_MAC_ADDRESS		/* Experimental */
+
+#ifdef WIRELESS_EXT	/* If wireless extension exist in the kernel */
+/* Warning : these stuff will slow down the driver... */
+#define WIRELESS_SPY		/* Enable spying addresses */
+#undef HISTOGRAM		/* Enable histogram of sig level... */
+#endif
+
+/****************************** DEBUG ******************************/
+
+#undef DEBUG_MODULE_TRACE	/* Module insertion/removal */
+#undef DEBUG_CALLBACK_TRACE	/* Calls made by Linux */
+#undef DEBUG_INTERRUPT_TRACE	/* Calls to handler */
+#undef DEBUG_INTERRUPT_INFO	/* type of interrupt & so on */
+#define DEBUG_INTERRUPT_ERROR	/* problems */
+#undef DEBUG_CONFIG_TRACE	/* Trace the config functions */
+#undef DEBUG_CONFIG_INFO	/* What's going on... */
+#define DEBUG_CONFIG_ERRORS	/* Errors on configuration */
+#undef DEBUG_TX_TRACE		/* Transmission calls */
+#undef DEBUG_TX_INFO		/* Header of the transmited packet */
+#undef DEBUG_TX_FAIL		/* Normal failure conditions */
+#define DEBUG_TX_ERROR		/* Unexpected conditions */
+#undef DEBUG_RX_TRACE		/* Transmission calls */
+#undef DEBUG_RX_INFO		/* Header of the transmited packet */
+#undef DEBUG_RX_FAIL		/* Normal failure conditions */
+#define DEBUG_RX_ERROR		/* Unexpected conditions */
+#undef DEBUG_PACKET_DUMP	32	/* Dump packet on the screen */
+#undef DEBUG_IOCTL_TRACE	/* Misc call by Linux */
+#undef DEBUG_IOCTL_INFO		/* Various debug info */
+#define DEBUG_IOCTL_ERROR	/* What's going wrong */
+#define DEBUG_BASIC_SHOW	/* Show basic startup info */
+#undef DEBUG_VERSION_SHOW	/* Print version info */
+#undef DEBUG_PSA_SHOW		/* Dump psa to screen */
+#undef DEBUG_MMC_SHOW		/* Dump mmc to screen */
+#undef DEBUG_SHOW_UNUSED	/* Show also unused fields */
+#undef DEBUG_I82593_SHOW	/* Show i82593 status */
+#undef DEBUG_DEVICE_SHOW	/* Show device parameters */
+
+/************************ CONSTANTS & MACROS ************************/
+
+#ifdef DEBUG_VERSION_SHOW
+static const char *version = "wavelan_cs.c : v22 (wireless extensions) 23/02/00\n";
+#endif
+
+/* Watchdog temporisation */
+#define	WATCHDOG_JIFFIES	(256*HZ/100)
+
+/* Fix a bug in some old wireless extension definitions */
+#ifndef IW_ESSID_MAX_SIZE
+#define IW_ESSID_MAX_SIZE	32
+#endif
+
+/* ------------------------ PRIVATE IOCTL ------------------------ */
+
+#define SIOCSIPQTHR	SIOCDEVPRIVATE		/* Set quality threshold */
+#define SIOCGIPQTHR	SIOCDEVPRIVATE + 1	/* Get quality threshold */
+#define SIOCSIPROAM     SIOCDEVPRIVATE + 2      /* Set roaming state */
+#define SIOCGIPROAM     SIOCDEVPRIVATE + 3      /* Get roaming state */
+
+#define SIOCSIPHISTO	SIOCDEVPRIVATE + 6	/* Set histogram ranges */
+#define SIOCGIPHISTO	SIOCDEVPRIVATE + 7	/* Get histogram values */
+
+/*************************** WaveLAN Roaming  **************************/
+#ifdef WAVELAN_ROAMING		/* Conditional compile, see above in options */
+
+#define WAVELAN_ROAMING_DEBUG	 0	/* 1 = Trace of handover decisions */
+					/* 2 = Info on each beacon rcvd... */
+#define MAX_WAVEPOINTS		7	/* Max visible at one time */
+#define WAVEPOINT_HISTORY	5	/* SNR sample history slow search */
+#define WAVEPOINT_FAST_HISTORY	2	/* SNR sample history fast search */
+#define SEARCH_THRESH_LOW	10	/* SNR to enter cell search */
+#define SEARCH_THRESH_HIGH	13	/* SNR to leave cell search */
+#define WAVELAN_ROAMING_DELTA	1	/* Hysteresis value (+/- SNR) */
+#define CELL_TIMEOUT		2*HZ	/* in jiffies */
+
+#define FAST_CELL_SEARCH	1	/* Boolean values... */
+#define NWID_PROMISC		1	/* for code clarity. */
+
+typedef struct wavepoint_beacon
+{
+  unsigned char		dsap,		/* Unused */
+			ssap,		/* Unused */
+			ctrl,		/* Unused */
+			O,U,I,		/* Unused */
+			spec_id1,	/* Unused */
+			spec_id2,	/* Unused */
+			pdu_type,	/* Unused */
+			seq;		/* WavePoint beacon sequence number */
+  unsigned short	domain_id,	/* WavePoint Domain ID */
+			nwid;		/* WavePoint NWID */
+} wavepoint_beacon;
+
+typedef struct wavepoint_history
+{
+  unsigned short	nwid;		/* WavePoint's NWID */
+  int			average_slow;	/* SNR running average */
+  int			average_fast;	/* SNR running average */
+  unsigned char	  sigqual[WAVEPOINT_HISTORY]; /* Ringbuffer of recent SNR's */
+  unsigned char		qualptr;	/* Index into ringbuffer */
+  unsigned char		last_seq;	/* Last seq. no seen for WavePoint */
+  struct wavepoint_history *next;	/* Next WavePoint in table */
+  struct wavepoint_history *prev;	/* Previous WavePoint in table */
+  unsigned long		last_seen;	/* Time of last beacon recvd, jiffies */
+} wavepoint_history;
+
+struct wavepoint_table
+{
+  wavepoint_history	*head;		/* Start of ringbuffer */
+  int			num_wavepoints;	/* No. of WavePoints visible */
+  unsigned char		locked;		/* Table lock */
+};
+
+#endif	/* WAVELAN_ROAMING */
+
+/****************************** TYPES ******************************/
+
+/* Shortcuts */
+typedef struct net_device	device;
+typedef struct net_device_stats	en_stats;
+typedef struct iw_statistics	iw_stats;
+typedef struct iw_quality	iw_qual;
+typedef struct iw_freq		iw_freq;
+typedef struct net_local	net_local;
+typedef struct timer_list	timer_list;
+
+/* Basic types */
+typedef u_char		mac_addr[WAVELAN_ADDR_SIZE];	/* Hardware address */
+
+/*
+ * Static specific data for the interface.
+ *
+ * For each network interface, Linux keep data in two structure. "device"
+ * keep the generic data (same format for everybody) and "net_local" keep
+ * the additional specific data.
+ * Note that some of this specific data is in fact generic (en_stats, for
+ * example).
+ */
+struct net_local
+{
+  dev_node_t 	node;		/* ???? What is this stuff ???? */
+  device *	dev;		/* Reverse link... */
+  spinlock_t	spinlock;	/* Serialize access to the hardware (SMP) */
+  dev_link_t *	link;		/* pcmcia structure */
+  en_stats	stats;		/* Ethernet interface statistics */
+  int		nresets;	/* Number of hw resets */
+  u_char	configured;	/* If it is configured */
+  u_char	reconfig_82593;	/* Need to reconfigure the controler */
+  u_char	promiscuous;	/* Promiscuous mode */
+  u_char	allmulticast;	/* All Multicast mode */
+  int		mc_count;	/* Number of multicast addresses */
+#ifndef HAVE_NETIF_QUEUE
+  timer_list	watchdog;	/* To avoid blocking state */
+#endif	/* 2.3.47 */
+
+  int   	stop;		/* Current i82593 Stop Hit Register */
+  int   	rfp;		/* Last DMA machine receive pointer */
+  int		overrunning;	/* Receiver overrun flag */
+
+#ifdef WIRELESS_EXT
+  iw_stats	wstats;		/* Wireless specific stats */
+#endif
+
+#ifdef WIRELESS_SPY
+  int		spy_number;		/* Number of addresses to spy */
+  mac_addr	spy_address[IW_MAX_SPY];	/* The addresses to spy */
+  iw_qual	spy_stat[IW_MAX_SPY];		/* Statistics gathered */
+#endif	/* WIRELESS_SPY */
+#ifdef HISTOGRAM
+  int		his_number;		/* Number of intervals */
+  u_char	his_range[16];		/* Boundaries of interval ]n-1; n] */
+  u_long	his_sum[16];		/* Sum in interval */
+#endif	/* HISTOGRAM */
+#ifdef WAVELAN_ROAMING
+  u_long	domain_id;	/* Domain ID we lock on for roaming */
+  int		filter_domains;	/* Check Domain ID of beacon found */
+ struct wavepoint_table	wavepoint_table;	/* Table of visible WavePoints*/
+  wavepoint_history *	curr_point;		/* Current wavepoint */
+  int			cell_search;		/* Searching for new cell? */
+  struct timer_list	cell_timer;		/* Garbage collection */
+#endif	/* WAVELAN_ROAMING */
+};
+
+/**************************** PROTOTYPES ****************************/
+
+#ifdef WAVELAN_ROAMING
+/* ---------------------- ROAMING SUBROUTINES -----------------------*/
+
+wavepoint_history *wl_roam_check(unsigned short nwid, net_local *lp);
+wavepoint_history *wl_new_wavepoint(unsigned short nwid, unsigned char seq, net_local *lp);
+void wl_del_wavepoint(wavepoint_history *wavepoint, net_local *lp);
+void wl_cell_expiry(unsigned long data);
+wavepoint_history *wl_best_sigqual(int fast_search, net_local *lp);
+void wl_update_history(wavepoint_history *wavepoint, unsigned char sigqual, unsigned char seq);
+void wv_roam_handover(wavepoint_history *wavepoint, net_local *lp);
+void wv_nwid_filter(unsigned char mode, net_local *lp);
+void wv_roam_init(struct net_device *dev);
+void wv_roam_cleanup(struct net_device *dev);
+#endif	/* WAVELAN_ROAMING */
+
+/* ----------------------- MISC SUBROUTINES ------------------------ */
+static inline void
+	wv_splhi(net_local *,		/* Disable interrupts */
+		 unsigned long *);	/* flags */
+static inline void
+	wv_splx(net_local *,		/* ReEnable interrupts */
+		unsigned long *);	/* flags */
+static void
+	cs_error(client_handle_t,	/* Report error to cardmgr */
+		 int,
+		 int);
+/* ----------------- MODEM MANAGEMENT SUBROUTINES ----------------- */
+static inline u_char		/* data */
+	hasr_read(u_long);	/* Read the host interface : base address */
+static inline void
+	hacr_write(u_long,	/* Write to host interface : base address */
+		   u_char),	/* data */
+	hacr_write_slow(u_long,
+		   u_char);
+static void
+	psa_read(device *,	/* Read the Parameter Storage Area */
+		 int,		/* offset in PSA */
+		 u_char *,	/* buffer to fill */
+		 int),		/* size to read */
+	psa_write(device *,	/* Write to the PSA */
+		  int,		/* Offset in psa */
+		  u_char *,	/* Buffer in memory */
+		  int);		/* Length of buffer */
+static inline void
+	mmc_out(u_long,		/* Write 1 byte to the Modem Manag Control */
+		u_short,
+		u_char),
+	mmc_write(u_long,	/* Write n bytes to the MMC */
+		  u_char,
+		  u_char *,
+		  int);
+static inline u_char		/* Read 1 byte from the MMC */
+	mmc_in(u_long,
+	       u_short);
+static inline void
+	mmc_read(u_long,	/* Read n bytes from the MMC */
+		 u_char,
+		 u_char *,
+		 int),
+	fee_wait(u_long,	/* Wait for frequency EEprom : base address */
+		 int,		/* Base delay to wait for */
+		 int);		/* Number of time to wait */
+static void
+	fee_read(u_long,	/* Read the frequency EEprom : base address */
+		 u_short,	/* destination offset */
+		 u_short *,	/* data buffer */
+		 int);		/* number of registers */
+/* ---------------------- I82593 SUBROUTINES ----------------------- */
+static int
+	wv_82593_cmd(device *,	/* synchronously send a command to i82593 */ 
+		     char *,
+		     int,
+		     int);
+static inline int
+	wv_diag(device *);	/* Diagnostique the i82593 */
+static int
+	read_ringbuf(device *,	/* Read a receive buffer */
+		     int,
+		     char *,
+		     int);
+static inline void
+	wv_82593_reconfig(device *);	/* Reconfigure the controler */
+/* ------------------- DEBUG & INFO SUBROUTINES ------------------- */
+static inline void
+	wv_init_info(device *);	/* display startup info */
+/* ------------------- IOCTL, STATS & RECONFIG ------------------- */
+static en_stats	*
+	wavelan_get_stats(device *);	/* Give stats /proc/net/dev */
+/* ----------------------- PACKET RECEPTION ----------------------- */
+static inline int
+	wv_start_of_frame(device *,	/* Seek beggining of current frame */
+			  int,	/* end of frame */
+			  int);	/* start of buffer */
+static inline void
+	wv_packet_read(device *,	/* Read a packet from a frame */
+		       int,
+		       int),
+	wv_packet_rcv(device *);	/* Read all packets waiting */
+/* --------------------- PACKET TRANSMISSION --------------------- */
+static inline void
+	wv_packet_write(device *,	/* Write a packet to the Tx buffer */
+			void *,
+			short);
+static int
+	wavelan_packet_xmit(struct sk_buff *,	/* Send a packet */
+			    device *);
+/* -------------------- HARDWARE CONFIGURATION -------------------- */
+static inline int
+	wv_mmc_init(device *);	/* Initialize the modem */
+static int
+	wv_ru_stop(device *),	/* Stop the i82593 receiver unit */
+	wv_ru_start(device *);	/* Start the i82593 receiver unit */
+static int
+	wv_82593_config(device *);	/* Configure the i82593 */
+static inline int
+	wv_pcmcia_reset(device *);	/* Reset the pcmcia interface */
+static int
+	wv_hw_config(device *);	/* Reset & configure the whole hardware */
+static inline void
+	wv_hw_reset(device *);	/* Same, + start receiver unit */
+static inline int
+	wv_pcmcia_config(dev_link_t *);	/* Configure the pcmcia interface */
+static void
+	wv_pcmcia_release(u_long),	/* Remove a device */
+	wv_flush_stale_links(void);	/* "detach" all possible devices */
+/* ---------------------- INTERRUPT HANDLING ---------------------- */
+static void
+wavelan_interrupt(int,	/* Interrupt handler */
+		  void *,
+		  struct pt_regs *);
+static void
+#ifdef HAVE_NETIF_QUEUE
+	wavelan_watchdog(device *);	/* Transmission watchdog */
+#else
+	wavelan_watchdog(u_long);	/* Transmission watchdog */
+#endif
+/* ------------------- CONFIGURATION CALLBACKS ------------------- */
+static int
+	wavelan_open(device *),		/* Open the device */
+	wavelan_close(device *);	/* Close the device */
+static dev_link_t *
+	wavelan_attach(void);		/* Create a new device */
+static void
+	wavelan_detach(dev_link_t *);	/* Destroy a removed device */
+static int
+	wavelan_event(event_t,		/* Manage pcmcia events */
+		      int,
+		      event_callback_args_t *);
+
+/**************************** VARIABLES ****************************/
+
+static dev_info_t dev_info = "wavelan_cs";
+static dev_link_t *dev_list = NULL;	/* Linked list of devices */
+
+/*
+ * Parameters that can be set with 'insmod'
+ * The exact syntax is 'insmod wavelan_cs.o <var>=<value>'
+ */
+
+/* Bit map of interrupts to choose from */
+/* This means pick from 15, 14, 12, 11, 10, 9, 7, 5, 4 and 3 */
+static int	irq_mask = 0xdeb8;
+static int 	irq_list[4] = { -1 };
+
+/* Shared memory speed, in ns */
+static int	mem_speed = 0;
+
+/* New module interface */
+MODULE_PARM(irq_mask, "i");
+MODULE_PARM(irq_list, "1-4i");
+MODULE_PARM(mem_speed, "i");
+
+#ifdef WAVELAN_ROAMING		/* Conditional compile, see above in options */
+/* Enable roaming mode ? No ! Please keep this to 0 */
+static int	do_roaming = 0;
+MODULE_PARM(do_roaming, "i");
+#endif	/* WAVELAN_ROAMING */
+
+#endif	/* WAVELAN_CS_H */
+
Index: oldkernel/linux/pcmcia-cs-3.1.15/wireless/wvlan_cs.c
diff -u /dev/null linux/pcmcia-cs-3.1.15/wireless/wvlan_cs.c:1.1
--- /dev/null	Mon Jul 31 21:15:12 2000
+++ linux/pcmcia-cs-3.1.15/wireless/wvlan_cs.c	Fri Jul  7 16:34:59 2000
@@ -0,0 +1,2915 @@
+/********************************************************************
+ *	WaveLAN/IEEE PCMCIA Linux network device driver
+ *
+ *	by Andreas Neuhaus <andy@fasta.fh-dortmund.de>
+ *	http://www.fasta.fh-dortmund.de/users/andy/wvlan/
+ *
+ *	This driver is free software; you can redistribute and/or
+ *	modify it under the terms of the GNU General Public License;
+ *	either version 2 of the license, or (at your option) any
+ *	later version.
+ *	Please send comments/bugfixes/patches to the above address.
+ *
+ *	Based on the Linux PCMCIA Programmer's Guide
+ *	and Lucent Technologies' HCF-Light library (wvlan47).
+ *
+ *	See 'man 4 wvlan_cs' for more information.
+ *
+ * TODO
+ *		We should use multiple Tx buffers to gain performance.
+ *		Move configuration settings to private device data
+ *			(Current version has problems with multiple
+ *			cards when a card reset is necessary).
+ *		Have a closer look to the endianess (PPC problems).
+ *
+ * HISTORY
+ *	v1.0.4	2000/02/26
+ *		Some changes to fit into kernel 2.3.x.
+ *		Some changes to better fit into the new net API.
+ *		Use of spinlocks for disabling interrupts.
+ *		Conditional to allow ignoring tx timeouts.
+ *		Disable interrupts during config/shutdown/reset.
+ *		Credits go to Jean Tourrilhes for all the following:
+ *		Promiscuous mode (tcpdump now work correctly).
+ *		Set multicast Rx list (RTP now work correctly).
+ *		Hook up watchdog timer in new net API.
+ *		Update frag/rts to new W-Ext.
+ *		Operating mode support + W-Ext (Neat...).
+ *		Power Saving support + W-Ext (useless...).
+ *		WEP (Privacy - Silver+Gold) support + W-Ext (yeah !!!).
+ *		Disable interupts during reading wireless stats.
+ *		(New quality indicator not included, need more work)
+ *		Plus a few cleanups, comments and fixes...
+ *
+ *	v1.0.3	Skipped to not confuse with kernel 2.3.x driver
+ *
+ *	v1.0.2	2000/01/07
+ *		Merged driver into the PCMCIA Card Services package
+ *			(thanks to David Hinds).
+ *		Removed README, added man page (man 4 wvlan_cs).
+ *
+ *	v1.0.1	1999/09/02
+ *		Interrupts are now disabled during ioctl to prevent being
+ *			disturbed during our fiddling with the NIC (occured
+ *			when using wireless tools while heavy loaded link).
+ *		Fixed a problem with more than 6 spy addresses (thanks to
+ *			Thomas Ekstrom).
+ *		Hopefully fixed problems with bigger packet sizes than 1500.
+ *		When you changed parameters that were specified at module
+ *			load time later with wireless_tools and the card was
+ *			reset afterward (e.g. by a Tx timeout), all changes
+ *			were lost. Changes will stay now after a reset.
+ *		Rewrote some parts of this README, added card LEDs description.
+ *		Added medium_reservation, ap_density, frag_threshold and
+ *			transmit_rate to module parameters.
+ *		Applying the patch now also modifies the files SUPPORTED.CARDS
+ *			and MAINTAINERS.
+ *		Signal/noise levels are now reported in dBm (-102..-10).
+ *		Added support for the new wireless extension (get wireless_
+ *			tools 19). Credits go to Jean Tourrilhes for all
+ *			the following:
+ *		Setting channel by giving frequency value is now available.
+ *		Setting/getting ESSID/BSSID/station-name is now possible
+ *			via iwconfig.
+ *		Support to set/get the desired/current bitrate.
+ *		Support to set/get RTS threshold.
+ *		Support to set/get fragmentation threshold.
+ *		Support to set/get AP density.
+ *		Support to set/get port type.
+ *		Fixed a problem with ioctl calls when setting station/network
+ *			name, where the new name string wasn't in kernel space
+ *			(thanks to Danton Nunes).
+ *		Driver sucessful tested on AlphaLinux (thanks to Peter Olson).
+ *		Driver sucessful tested with WaveLAN Turbo cards.
+ *
+ *	v0.2.7	1999/07/20
+ *		Changed release/detach code to fix hotswapping with 2.2/2.3
+ *			kernels (thanks to Derrick J Brashear).
+ *		Fixed wrong adjustment of receive buffer length. This was only
+ *			a problem when a higher level protocol relies on correct
+ *			length information, so it never occured with IPv4
+ *			(thanks to Henrik Gulbrandsen).
+ *
+ *	v0.2.6	1999/05/04
+ *		Added wireless spy and histogram support. Signal levels
+ *			are now reported in ad-hoc mode correctly, but you
+ *			need to use iwspy for it, because we can 'hear' more
+ *			than one remote host in ad-hoc mode (thanks
+ *			to Albert K T Hui for the code and to Richard van
+ *			Leeuwen for the technical details).
+ *		Fixed a bug with wrong tx_bytes count.
+ *		Added GPL file wvlan.COPYING.
+ *
+ *	v0.2.5	1999/03/12
+ *		Hopefully fixed problems with the Makefile patch.
+ *		Changed the interrupt service routine to do never lock up
+ *			in an endless loop (if this ever would happen...).
+ *		Missed a conditional which made the driver unable to compile
+ *			on 2.0.x kernels (thanks to Glenn D. Golden).
+ *
+ *	v0.2.4	1999/03/10
+ *		Tested in ad-hoc mode and with access point (many thanks
+ *			to Frank Bruegmann, who made some hardware available
+ *			to me so that I can now test it myself).
+ *		Change the interrupt service routine to repeat on frame
+ *			reception and deallocate the NICs receiving frame
+ *			buffer correctly (thanks to Glenn D. Golden).
+ *		Fixed a problem with checksums where under some circumstances
+ *			an incorrect packet wasn't recognized. Switched
+ *			on the kernel checksum checking (thanks to Glenn D. Golden).
+ *		Setting the channel value is now checked against valid channel
+ *			values which are read from the card.
+ *		Added private ioctl (iwconfig priv) station_name, network_name
+ *			and current_network. It needs an iwconfig capable of
+ *			setting and gettings strings (thanks to Justin Seger).
+ *		Ioctl (iwconfig) should now return the real current used channel.
+ *		Setting the channel value is now only valid using ad-hoc mode.
+ *			It's useless when using an access points.
+ *		Renamed the ssid parameter to network_name and made it work
+ *			correctly for all port_types. It should work now
+ *			in ad-hoc networks as well as with access points.
+ *		Added entries for the NCR WaveLAN/IEEE and the Cabletron
+ *			RoamAbout 802.11 DS card (thanks to Richard van Leeuwen)
+ *		Support to count the received and transmitted bytes
+ *			if kernel version >2.1.25.
+ *		Changed the reset method in case of Tx-timeouts.
+ *		PM suspend/resume should work now (thanks to Dave Kristol).
+ *		Changed installation and driver package. Read INSTALL in this
+ *			file for information how it works now.
+ *
+ *	v0.2.3	1999/02/25
+ *		Added support to set the own SSID
+ *		Changed standard channel setting to 3 so that it works
+ *			with Windows without specifying a channel (the
+ *			Windows driver seem to default to channel 3).
+ *		Fixed two problems with the Ethernet-II frame de/encapsulation.
+ *
+ *	v0.2.2	1999/02/07
+ *		First public beta release.
+ *		Added support to get link quality via iwconfig.
+ *		Added support to change channel via iwconfig.
+ *		Added changeable MTU setting (thanks to Tomasz Motylewski).
+ *		Added Ethernet-II frame de/encapsulation, because
+ *			HCF-Light doesn't support it.
+ *
+ *	v0.2.1	1999/02/03
+ *		Added channel parameter.
+ *		Rewrote the driver with information made public
+ *			in Lucent's HCF-Light library. The HCF was
+ *			slightly modified to get rid of the compiler
+ *			warnings. The filenames were prefixed with
+ *			wvlan_ to better fit into the pcmcia package.
+ *
+ *	v0.1d	1998/12/21
+ *		Fixed a problem where the NIC was crashing during heavy
+ *			loaded transmissions. Interrupts are now disabled
+ *			during wvlan_tx() function. Seems to work fine now.
+ *
+ *	v0.1c	1998/12/20
+ *		Driver works fine with ad-hoc network.
+ *
+ *	v0.1b	1998/12/19
+ *		First successful send-tests.
+ *
+ *	v0.1a	1998/12/18
+ *		First tests with card functions.
+ */
+
+#include <linux/config.h>
+#include <linux/version.h>
+#ifndef KERNEL_VERSION
+#define KERNEL_VERSION(a,b,c) (((a) << 16) + ((b) << 8) + (c))
+#endif
+
+#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,3,0))
+#include <pcmcia/config.h>
+#include <pcmcia/k_compat.h>
+#endif
+
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/ptrace.h>
+#include <linux/malloc.h>
+#include <linux/string.h>
+#include <linux/timer.h>
+#include <asm/io.h>
+#include <asm/system.h>
+#include <asm/uaccess.h>
+
+#include <pcmcia/version.h>
+#include <pcmcia/cs_types.h>
+#include <pcmcia/cs.h>
+#include <pcmcia/cistpl.h>
+#include <pcmcia/cisreg.h>
+#include <pcmcia/ds.h>
+
+#include <linux/netdevice.h>
+#include <linux/etherdevice.h>
+#include <linux/skbuff.h>
+#include <linux/if_arp.h>
+#include <linux/ioport.h>
+#include <linux/fcntl.h>
+
+#ifdef MODULE
+#ifdef MODVERSIONS
+#include <linux/modversions.h>
+#endif
+#include <linux/module.h>
+#else
+#define MOD_INC_USE_COUNT
+#define MOD_DEC_USE_COUNT
+#endif
+
+#include <linux/wireless.h>
+#if WIRELESS_EXT < 5
+#error "Wireless extension v5 or newer required"
+#endif
+#define WIRELESS_SPY		// enable iwspy support
+#undef HISTOGRAM		// disable histogram of signal levels
+
+// This is needed for station_name, but we may not compile WIRELESS_EXT
+#ifndef IW_ESSID_MAX_SIZE
+#define IW_ESSID_MAX_SIZE	32
+#endif /* IW_ESSID_MAX_SIZE */
+
+#include "wvlan_hcf.h"
+
+/* #define PCMCIA_DEBUG 1	// For developer only :-) */
+
+// Undefine this if you want to ignore Tx timeouts
+// (i.e. card will not be reset on Tx timeouts)
+#define WVLAN_RESET_ON_TX_TIMEOUT
+
+
+/********************************************************************
+ * DEBUG
+ */
+#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);
+#else
+#define DEBUG(n, args...) {}
+#endif
+#define DEBUG_INFO		1
+#define DEBUG_NOISY		2
+#define DEBUG_TXRX		3
+#define DEBUG_CALLTRACE		4
+#define DEBUG_INTERRUPT		5
+
+
+/********************************************************************
+ * MISC
+ */
+static char *version = "1.0.4";
+static dev_info_t dev_info = "wvlan_cs";
+static dev_link_t *dev_list = NULL;
+
+// Module parameters
+// Note: all these module parameters should really be "per-device", as
+// opposed to global. It mean converting everything to array and
+// referencing by the dev_list index (to add).
+static u_int irq_mask = 0xdeb8;				// Interrupt mask
+static int irq_list[4] = { -1 };			// Interrupt list (alternative)
+static int port_type = 1;				// Port-type [1]
+static char station_name[IW_ESSID_MAX_SIZE+1] = "\0";	// Name of station []
+static char network_name[IW_ESSID_MAX_SIZE+1] = "\0";	// Name of network []
+static int channel = 3;					// Channel [3]
+static int ap_density = 1;				// AP density [1]
+static int medium_reservation = 2347;			// RTS threshold [2347]
+static int frag_threshold = 2346;			// Fragmentation threshold [2346]
+static int transmit_rate = 3;				// Transmit rate [3]
+static int eth = 0;
+static int mtu = 1500;
+MODULE_PARM(irq_mask, "i");
+MODULE_PARM(irq_list, "1-4i");
+MODULE_PARM(port_type, "i");
+MODULE_PARM(station_name, "c" __MODULE_STRING(IW_ESSID_MAX_SIZE));
+MODULE_PARM(network_name, "c" __MODULE_STRING(IW_ESSID_MAX_SIZE));
+MODULE_PARM(channel, "i");
+MODULE_PARM(ap_density, "i");
+MODULE_PARM(medium_reservation, "i");
+MODULE_PARM(frag_threshold, "i");
+MODULE_PARM(transmit_rate, "i");
+MODULE_PARM(eth, "i");
+MODULE_PARM(mtu, "i");
+
+// Useful macros we have in pcmcia-cs but not in the kernel
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,3,0))
+#define DEV_KFREE_SKB(skb) dev_kfree_skb(skb);
+#define skb_tx_check(dev, skb)
+#define add_rx_bytes(stats, n) (stats)->rx_bytes += n;
+#define add_tx_bytes(stats, n) (stats)->tx_bytes += n;
+#endif
+
+// Ethernet timeout is ((400*HZ)/1000), but we should use a higher
+// value, because wireless transmissions are much slower
+#define TX_TIMEOUT ((4000*HZ)/1000)
+
+// Ethernet-II snap header
+static char snap_header[] = { 0x00, 0x00, 0xaa, 0xaa, 0x03, 0x00, 0x00, 0xf8 };
+
+// Valid MTU values (HCF_MAX_MSG (2304) is the max hardware frame size)
+#define WVLAN_MIN_MTU 256
+#define WVLAN_MAX_MTU (HCF_MAX_MSG - sizeof(snap_header))
+
+// Max number of multicast addresses that the filter can accept
+#define WVLAN_MAX_MULTICAST GROUP_ADDR_SIZE/6
+
+// Frequency list (map channels to frequencies)
+const long frequency_list[] = { 2412, 2417, 2422, 2427, 2432, 2437, 2442,
+				2447, 2452, 2457, 2462, 2467, 2472, 2484 };
+
+// Bit-rate list in 1/2 Mb/s (first is dummy - not for original turbo)
+const int rate_list[] = { 0, 2, 4, -255, 11, 22, -4, -11, 0, 0, 0, 0 };
+
+// A few details needed for WEP (Wireless Equivalent Privacy)
+#define MAX_KEY_SIZE 14			// 128 (?) bits
+#define MIN_KEY_SIZE  5			// 40 bits RC4 - WEP
+#define MAX_KEYS      4			// 4 different keys
+
+// Keep track of wvlanX devices
+#define MAX_WVLAN_CARDS 16
+static struct net_device *wvlandev_index[MAX_WVLAN_CARDS];
+
+// Local data for netdevice
+struct net_local {
+	dev_node_t		node;
+	struct net_device	*dev;		// backtrack device
+	dev_link_t		*link;		// backtrack link
+	spinlock_t		slock;		// spinlock
+	int			interrupt;	// interrupt
+	IFB_STRCT		ifb;		// WaveLAN structure
+	struct net_device_stats	stats;		// device stats
+	u_char			promiscuous;	// Promiscuous mode
+	u_char			allmulticast;	// All multicast mode
+	int			mc_count;	// Number of multicast addrs
+#ifdef WIRELESS_EXT
+	struct iw_statistics	wstats;		// wireless stats
+#ifdef WIRELESS_SPY
+	int			spy_number;
+	u_char			spy_address[IW_MAX_SPY][MAC_ADDR_SIZE];
+	struct iw_quality	spy_stat[IW_MAX_SPY];
+#endif
+#ifdef HISTOGRAM
+	int			his_number;
+	u_char			his_range[16];
+	u_long			his_sum[16];
+#endif
+	int			wep_on;		// WEP enabled
+	int			transmit_key;	// Key used for transmissions
+	KEY_STRCT		key[MAX_KEYS];	// WEP keys & size
+#endif /* WIRELESS_EXT */
+};
+
+// Shortcuts
+#ifdef WIRELESS_EXT
+typedef struct iw_statistics	iw_stats;
+typedef struct iw_quality	iw_qual;
+typedef struct iw_freq		iw_freq;
+#endif /* WIRELESS_EXT */
+
+// Show CardServices error message (syslog)
+static void cs_error (client_handle_t handle, int func, int ret)
+{
+	error_info_t err = { func, ret };
+	CardServices(ReportError, handle, &err);
+}
+
+
+/********************************************************************
+ * FUNCTION PROTOTYPES
+ */
+int wvlan_hw_setmaxdatalen (IFBP ifbp, int maxlen);
+int wvlan_hw_getmacaddr (IFBP ifbp, char *mac, int len);
+int wvlan_hw_getchannellist (IFBP ifbp);
+int wvlan_hw_setporttype (IFBP ifbp, int ptype);
+int wvlan_hw_getporttype (IFBP ifbp);
+int wvlan_hw_setstationname (IFBP ifbp, char *name);
+int wvlan_hw_getstationname (IFBP ifbp, char *name, int len);
+int wvlan_hw_setssid (IFBP ifbp, char *name);
+int wvlan_hw_getssid (IFBP ifbp, char *name, int len, int cur);
+int wvlan_hw_getbssid (IFBP ifbp, char *mac, int len);
+int wvlan_hw_setchannel (IFBP ifbp, int channel);
+int wvlan_hw_getchannel (IFBP ifbp);
+int wvlan_hw_getcurrentchannel (IFBP ifbp);
+int wvlan_hw_setthreshold (IFBP ifbp, int thrh, int cmd);
+int wvlan_hw_getthreshold (IFBP ifbp, int cmd);
+int wvlan_hw_setbitrate (IFBP ifbp, int brate);
+int wvlan_hw_getbitrate (IFBP ifbp, int cur);
+int wvlan_hw_getratelist (IFBP ifbp, char *brlist);
+#ifdef WIRELESS_EXT
+int wvlan_hw_getfrequencylist (IFBP ifbp, iw_freq *list, int max);
+int wvlan_getbitratelist (IFBP ifbp, __s32 *list, int max);
+#endif /* WIRELESS_EXT */
+#if WIRELESS_EXT > 8
+int wvlan_hw_setpower (IFBP ifbp, int enabled, int cmd);
+int wvlan_hw_getpower (IFBP ifbp, int cmd);
+int wvlan_hw_setpmsleep (IFBP ifbp, int duration);
+int wvlan_hw_getpmsleep (IFBP ifbp);
+int wvlan_hw_getprivacy (IFBP ifbp);
+int wvlan_hw_setprivacy (IFBP ifbp, int mode, int transmit, KEY_STRCT *keys);
+#endif /* WIRELESS_EXT > 8 */
+static int wvlan_hw_setpromisc (IFBP ifbp, int promisc);
+
+int wvlan_hw_config (struct net_device *dev);
+int wvlan_hw_shutdown (struct net_device *dev);
+int wvlan_hw_reset (struct net_device *dev);
+
+struct net_device_stats *wvlan_get_stats (struct net_device *dev);
+#ifdef WIRELESS_EXT
+int wvlan_ioctl (struct net_device *dev, struct ifreq *rq, int cmd);
+struct iw_statistics *wvlan_get_wireless_stats (struct net_device *dev);
+#ifdef WIRELESS_SPY
+static inline void wvlan_spy_gather (struct net_device *dev, u_char *mac, u_char *stats);
+#endif
+#ifdef HISTOGRAM
+static inline void wvlan_his_gather (struct net_device *dev, u_char *stats);
+#endif
+#endif /* WIRELESS_EXT */
+int wvlan_change_mtu (struct net_device *dev, int new_mtu);
+static void wvlan_set_multicast_list (struct net_device *dev);
+
+static void wvlan_watchdog (struct net_device *dev);
+int wvlan_tx (struct sk_buff *skb, struct net_device *dev);
+void wvlan_rx (struct net_device *dev, int len);
+
+static int wvlan_open (struct net_device *dev);
+static int wvlan_close (struct net_device *dev);
+
+static void wvlan_interrupt (int irq, void *dev_id, struct pt_regs *regs);
+
+static int wvlan_config (dev_link_t *link);
+static void wvlan_release (u_long arg);
+
+static dev_link_t *wvlan_attach (void);
+static void wvlan_detach (dev_link_t *link);
+
+static int wvlan_event (event_t event, int priority, event_callback_args_t *args);
+
+extern int init_module (void);
+extern void cleanup_module (void);
+
+
+/********************************************************************
+ * HARDWARE SETTINGS
+ */
+// Stupid constants helping clarity
+#define WVLAN_CURRENT	1
+#define WVLAN_DESIRED	0
+
+int wvlan_hw_setmaxdatalen (IFBP ifbp, int maxlen)
+{
+	CFG_ID_STRCT ltv;
+	int rc;
+
+	ltv.len = 2;
+	ltv.typ = CFG_CNF_MAX_DATA_LEN;
+	ltv.id[0] = maxlen;
+	rc = hcf_put_info(ifbp, (LTVP) &ltv);
+	DEBUG(DEBUG_NOISY, "%s: hcf_put_info(CFG_CNF_MAX_DATA_LEN:0x%x) returned 0x%x\n", dev_info, maxlen, rc);
+	return rc;
+}
+
+int wvlan_hw_getmacaddr (IFBP ifbp, char *mac, int len)
+{
+	CFG_MAC_ADDR_STRCT ltv;
+	int rc, l;
+
+	ltv.len = 4;
+	ltv.typ = CFG_CNF_OWN_MAC_ADDR;
+	rc = hcf_get_info(ifbp, (LTVP) &ltv);
+	DEBUG(DEBUG_NOISY, "%s: hcf_get_info(CFG_CNF_OWN_MAC_ADDR) returned 0x%x\n", dev_info, rc);
+	if (rc)
+		return rc;
+	l = min(len, ltv.len*2);
+	memcpy(mac, (char *)ltv.mac_addr, l);
+	return 0;
+}
+
+int wvlan_hw_getchannellist (IFBP ifbp)
+{
+	CFG_ID_STRCT ltv;
+	int rc, chlist;
+
+	ltv.len = 2;
+	ltv.typ = CFG_CHANNEL_LIST;
+	rc = hcf_get_info(ifbp, (LTVP) &ltv);
+	chlist = ltv.id[0];
+	DEBUG(DEBUG_NOISY, "%s: hcf_get_info(CFG_CHANNEL_LIST):0x%x returned 0x%x\n", dev_info, chlist, rc);
+	return rc ? 0 : chlist;
+}
+
+int wvlan_hw_setporttype (IFBP ifbp, int ptype)
+{
+	CFG_ID_STRCT ltv;
+	int rc;
+
+	ltv.len = 2;
+	ltv.typ = CFG_CNF_PORT_TYPE;
+	ltv.id[0] = ptype;
+	rc = hcf_put_info(ifbp, (LTVP) &ltv);
+	DEBUG(DEBUG_NOISY, "%s: hcf_put_info(CFG_CNF_PORT_TYPE:0x%x) returned 0x%x\n", dev_info, ptype, rc);
+	return rc;
+}
+
+int wvlan_hw_getporttype (IFBP ifbp)
+{
+	CFG_ID_STRCT ltv;
+	int rc, ptype;
+
+	ltv.len = 2;
+	ltv.typ = CFG_CNF_PORT_TYPE;
+	rc = hcf_get_info(ifbp, (LTVP) &ltv);
+	ptype = ltv.id[0];
+	DEBUG(DEBUG_NOISY, "%s: hcf_get_info(CFG_CNF_PORT_TYPE):0x%x returned 0x%x\n", dev_info, ptype, rc);
+	return rc ? 0 : ptype;
+}
+
+int wvlan_hw_setstationname (IFBP ifbp, char *name)
+{
+	CFG_ID_STRCT ltv;
+	int rc, l;
+
+	ltv.len = 18;
+	ltv.typ = CFG_CNF_OWN_NAME;
+	l = min(strlen(name), ltv.len*2);
+	ltv.id[0] = l;
+	memcpy((char *) &ltv.id[1], name, l);
+	rc = hcf_put_info(ifbp, (LTVP) &ltv);
+	DEBUG(DEBUG_NOISY, "%s: hcf_put_info(CFG_CNF_OWN_NAME:'%s') returned 0x%x\n", dev_info, name, rc);
+	return rc;
+}
+
+int wvlan_hw_getstationname (IFBP ifbp, char *name, int len)
+{
+	CFG_ID_STRCT ltv;
+	int rc, l;
+
+	ltv.len = 18;
+	ltv.typ = CFG_CNF_OWN_NAME;
+	rc = hcf_get_info(ifbp, (LTVP) &ltv);
+	DEBUG(DEBUG_NOISY, "%s: hcf_get_info(CFG_CNF_OWN_NAME) returned 0x%x\n", dev_info, rc);
+	if (rc)
+		return rc;
+	if (ltv.id[0])
+		l = min(len, ltv.id[0]);
+	else
+		l = min(len, ltv.len*2);	/* It's a feature */
+	memcpy(name, (char *) &ltv.id[1], l);
+	name[l] = 0;
+	DEBUG(DEBUG_NOISY, "%s: hcf_get_info(CFG_CNF_OWN_NAME):'%s'\n", dev_info, name);
+	return 0;
+}
+
+int wvlan_hw_setssid (IFBP ifbp, char *name)
+{
+	CFG_ID_STRCT ltv;
+	int rc, l;
+
+	ltv.len = 18;
+	if (port_type == 3)
+		ltv.typ = CFG_CNF_OWN_SSID;
+	else
+		ltv.typ = CFG_CNF_DESIRED_SSID;
+	l = min(strlen(name), ltv.len*2);
+	ltv.id[0] = l;
+	memcpy((char *) &ltv.id[1], name, l);
+	rc = hcf_put_info(ifbp, (LTVP) &ltv);
+	DEBUG(DEBUG_NOISY, "%s: hcf_put_info(CFG_CNF_OWN/DESIRED_SSID:'%s') returned 0x%x\n", dev_info, name, rc);
+	return rc;
+}
+
+int wvlan_hw_getssid (IFBP ifbp, char *name, int len, int cur)
+{
+	CFG_ID_STRCT ltv;
+	int rc, l;
+
+	ltv.len = 18;
+	if (cur)
+		ltv.typ = CFG_CURRENT_SSID;
+	else
+		if (port_type == 3)
+			ltv.typ = CFG_CNF_OWN_SSID;
+		else
+			ltv.typ = CFG_CNF_DESIRED_SSID;
+	rc = hcf_get_info(ifbp, (LTVP) &ltv);
+	DEBUG(DEBUG_NOISY, "%s: hcf_get_info(CFG_CNF_OWN/DESIRED/CURRENT_SSID) returned 0x%x\n", dev_info, rc);
+	if (rc)
+		return rc;
+	if (ltv.id[0])
+	{
+		l = min(len, ltv.id[0]);
+		memcpy(name, (char *) &ltv.id[1], l);
+	}
+	else
+		l = 0;
+	name[l] = '\0';
+	DEBUG(DEBUG_NOISY, "%s: hcf_get_info(CFG_CNF_OWN/DESIRED/CURRENT_SSID):'%s'\n", dev_info, name);
+	return 0;
+}
+
+int wvlan_hw_getbssid (IFBP ifbp, char *mac, int len)
+{
+	CFG_MAC_ADDR_STRCT ltv;
+	int rc, l;
+
+	ltv.len = 4;
+	ltv.typ = CFG_CURRENT_BSSID;
+	rc = hcf_get_info(ifbp, (LTVP) &ltv);
+	DEBUG(DEBUG_NOISY, "%s: hcf_get_info(CFG_CURRENT_BSSID) returned 0x%x\n", dev_info, rc);
+	if (rc)
+		return rc;
+	l = min(len, ltv.len*2);
+	memcpy(mac, (char *)ltv.mac_addr, l);
+	return 0;
+}
+
+int wvlan_hw_setchannel (IFBP ifbp, int channel)
+{
+	CFG_ID_STRCT ltv;
+	int rc;
+
+	ltv.len = 2;
+	ltv.typ = CFG_CNF_OWN_CHANNEL;
+	ltv.id[0] = channel;
+	rc = hcf_put_info(ifbp, (LTVP) &ltv);
+	DEBUG(DEBUG_NOISY, "%s: hcf_put_info(CFG_CNF_OWN_CHANNEL:0x%x) returned 0x%x\n", dev_info, channel, rc);
+	return rc;
+}
+
+int wvlan_hw_getchannel (IFBP ifbp)
+{
+	CFG_ID_STRCT ltv;
+	int rc, channel;
+
+	ltv.len = 2;
+	ltv.typ = CFG_CNF_OWN_CHANNEL;
+	rc = hcf_get_info(ifbp, (LTVP) &ltv);
+	channel = ltv.id[0];
+	DEBUG(DEBUG_NOISY, "%s: hcf_get_info(CFG_CNF_OWN_CHANNEL):0x%x returned 0x%x\n", dev_info, channel, rc);
+	return rc ? 0 : channel;
+}
+
+int wvlan_hw_getcurrentchannel (IFBP ifbp)
+{
+	CFG_ID_STRCT ltv;
+	int rc, channel;
+
+	ltv.len = 2;
+	ltv.typ = CFG_CURRENT_CHANNEL;
+	rc = hcf_get_info(ifbp, (LTVP) &ltv);
+	channel = ltv.id[0];
+	DEBUG(DEBUG_NOISY, "%s: hcf_get_info(CFG_CURRENT_CHANNEL):0x%x returned 0x%x\n", dev_info, channel, rc);
+	return rc ? 0 : channel;
+}
+
+int wvlan_hw_setthreshold (IFBP ifbp, int thrh, int cmd)
+{
+	CFG_ID_STRCT ltv;
+	int rc;
+
+	ltv.len = 2;
+	ltv.typ = cmd;
+	ltv.id[0] = thrh;
+	rc = hcf_put_info(ifbp, (LTVP) &ltv);
+	DEBUG(DEBUG_NOISY, "%s: hcf_put_info(0x%x:0x%x) returned 0x%x\n", dev_info, cmd, thrh, rc);
+	return rc;
+}
+
+int wvlan_hw_getthreshold (IFBP ifbp, int cmd)
+{
+	CFG_ID_STRCT ltv;
+	int rc, thrh;
+
+	ltv.len = 2;
+	ltv.typ = cmd;
+	rc = hcf_get_info(ifbp, (LTVP) &ltv);
+	thrh = ltv.id[0];
+	DEBUG(DEBUG_NOISY, "%s: hcf_get_info(0x%x):0x%x returned 0x%x\n", dev_info, cmd, thrh, rc);
+	return rc ? 0 : thrh;
+}
+
+int wvlan_hw_setbitrate (IFBP ifbp, int brate)
+{
+	CFG_ID_STRCT ltv;
+	int rc;
+
+	ltv.len = 2;
+	ltv.typ = CFG_TX_RATE_CONTROL;
+	ltv.id[0] = brate;
+	rc = hcf_put_info(ifbp, (LTVP) &ltv);
+	DEBUG(DEBUG_NOISY, "%s: hcf_put_info(CFG_TX_RATE_CONTROL:0x%x) returned 0x%x\n", dev_info, brate, rc);
+	return rc;
+}
+
+int wvlan_hw_getbitrate (IFBP ifbp, int cur)
+{
+	CFG_ID_STRCT ltv;
+	int rc, brate;
+
+	ltv.len = 2;
+	ltv.typ = cur ? CFG_CURRENT_TX_RATE : CFG_TX_RATE_CONTROL;
+	rc = hcf_get_info(ifbp, (LTVP) &ltv);
+	brate = ltv.id[0];
+	DEBUG(DEBUG_NOISY, "%s: hcf_get_info(CFG_TX_RATE_CONTROL):0x%x returned 0x%x\n", dev_info, brate, rc);
+	return rc ? 0 : brate;
+}
+
+int wvlan_hw_getratelist(IFBP ifbp, char *brlist)
+{
+	CFG_ID_STRCT ltv;
+	int rc, brnum;
+
+	ltv.len = 10;
+	ltv.typ = CFG_SUPPORTED_DATA_RATES;
+	rc = hcf_get_info(ifbp, (LTVP) &ltv);
+	brnum = ltv.id[0];
+	memcpy(brlist, (char *) &ltv.id[1], brnum);
+	DEBUG(DEBUG_NOISY, "%s: hcf_get_info(CFG_CHANNEL_LIST):0x%x returned 0x%x\n", dev_info, brnum, rc);
+	return rc ? 0 : brnum;
+}
+
+#ifdef WIRELESS_EXT
+int wvlan_hw_getfrequencylist(IFBP ifbp, iw_freq *list, int max)
+{
+	int chlist = wvlan_hw_getchannellist(ifbp);
+	int i, k = 0;
+
+	/* Compute maximum number of freq to scan */
+	if(max > 15)
+		max = 15;
+
+	/* Check availability */
+	for(i = 0; i < max; i++)
+		if((1 << i) & chlist)
+		{
+#if WIRELESS_EXT > 7
+			list[k].i = i + 1;	/* Set the list index */
+#endif /* WIRELESS_EXT */
+			list[k].m = frequency_list[i] * 100000;
+			list[k++].e = 1;	/* Values in table in MHz -> * 10^5 * 10 */
+		}
+
+	return k;
+}
+
+int wvlan_getbitratelist(IFBP ifbp, __s32 *list, int max)
+{
+	char brlist[9];
+	int brnum = wvlan_hw_getratelist(ifbp, brlist);
+	int i;
+
+	/* Compute maximum number of freq to scan */
+	if(brnum > max)
+		brnum = max;
+
+	/* Convert to Mb/s */
+	for(i = 0; i < max; i++)
+		list[i] = (brlist[i] & 0x7F) * 500000;
+
+	return brnum;
+}
+#endif /* WIRELESS_EXT */
+
+#if WIRELESS_EXT > 8
+int wvlan_hw_setpower (IFBP ifbp, int enabled, int cmd)
+{
+	CFG_ID_STRCT ltv;
+	int rc;
+
+	ltv.len = 2;
+	ltv.typ = cmd;
+	ltv.id[0] = enabled;
+	rc = hcf_put_info(ifbp, (LTVP) &ltv);
+	DEBUG(DEBUG_NOISY, "%s: hcf_put_info(0x%x:0x%x) returned 0x%x\n", dev_info, cmd, enabled, rc);
+	return rc;
+}
+
+int wvlan_hw_getpower (IFBP ifbp, int cmd)
+{
+	CFG_ID_STRCT ltv;
+	int rc, enabled;
+
+	ltv.len = 2;
+	ltv.typ = cmd;
+	rc = hcf_get_info(ifbp, (LTVP) &ltv);
+	enabled = ltv.id[0];
+	DEBUG(DEBUG_NOISY, "%s: hcf_get_info(0x%x):0x%x returned 0x%x\n", dev_info, cmd, enabled, rc);
+	return rc ? 0 : enabled;
+}
+
+int wvlan_hw_setpmsleep (IFBP ifbp, int duration)
+{
+	CFG_ID_STRCT ltv;
+	int rc;
+
+	ltv.len = 2;
+	ltv.typ = CFG_CNF_MAX_SLEEP_DURATION;
+	ltv.id[0] = duration;
+	rc = hcf_put_info(ifbp, (LTVP) &ltv);
+	DEBUG(DEBUG_NOISY, "%s: hcf_put_info(CNF_MAX_SLEEP_DURATION:0x%x) returned 0x%x\n", dev_info, duration, rc);
+	return rc;
+}
+
+int wvlan_hw_getpmsleep (IFBP ifbp)
+{
+	CFG_ID_STRCT ltv;
+	int rc, duration;
+
+	ltv.len = 2;
+	ltv.typ = CFG_CNF_MAX_SLEEP_DURATION;
+	rc = hcf_get_info(ifbp, (LTVP) &ltv);
+	duration = ltv.id[0];
+	DEBUG(DEBUG_NOISY, "%s: hcf_get_info(CNF_MAX_SLEEP_DURATION):0x%x returned 0x%x\n", dev_info, duration, rc);
+	return rc ? 0 : duration;
+}
+
+int wvlan_hw_getprivacy (IFBP ifbp)
+{
+	CFG_ID_STRCT ltv;
+	int rc, privacy;
+
+	// This function allow to distiguish bronze cards from other
+	// types, to know if WEP exist...
+	// This is stupid, we have no way to distinguish the silver
+	// and gold cards, because the call below return 1 in all
+	// cases. Yuk...
+	ltv.len = 2;
+	ltv.typ = CFG_PRIVACY_OPTION_IMPLEMENTED;
+	rc = hcf_get_info(ifbp, (LTVP) &ltv);
+	privacy = ltv.id[0];
+	DEBUG(DEBUG_NOISY, "%s: hcf_get_info(CNF_MAX_SLEEP_DURATION):0x%x returned 0x%x\n", dev_info, privacy, rc);
+	return rc ? 0 : privacy;
+}
+
+int wvlan_hw_setprivacy (IFBP ifbp, int mode, int transmit, KEY_STRCT *keys)
+{
+	CFG_ID_STRCT ltv;
+	CFG_CNF_DEFAULT_KEYS_STRCT ltv_key;
+	int rc;
+
+	if (mode)
+	{
+		// Set the index of the key used for transmission
+		ltv.len = 2;
+		ltv.typ = CFG_CNF_TX_KEY_ID;
+		ltv.id[0] = transmit;
+		rc = hcf_put_info(ifbp, (LTVP) &ltv);
+		DEBUG(DEBUG_NOISY, "%s: hcf_put_info(CFG_CNF_TX_KEY_ID:0x%x) returned 0x%x\n", dev_info, mode, rc);
+		if (rc)
+			return rc;
+
+		// Set the keys themselves (all in on go !)
+		ltv_key.len = sizeof(KEY_STRCT)*MAX_KEYS/2 + 1;
+		ltv_key.typ = CFG_CNF_DEFAULT_KEYS;
+		memcpy((char *) &ltv_key.key, (char *) keys, sizeof(KEY_STRCT)*MAX_KEYS);
+		rc = hcf_put_info(ifbp, (LTVP) &ltv_key);
+		DEBUG(DEBUG_NOISY, "%s: hcf_put_info(CFG_CNF_TX_KEY_ID:0x%x) returned 0x%x\n", dev_info, mode, rc);
+		if (rc)
+			return rc;
+	}
+	// enable/disable encryption
+	ltv.len = 2;
+	ltv.typ = CFG_CNF_ENCRYPTION;
+	ltv.id[0] = mode;
+	rc = hcf_put_info(ifbp, (LTVP) &ltv);
+	DEBUG(DEBUG_NOISY, "%s: hcf_put_info(CFG_CNF_ENCRYPTION:0x%x) returned 0x%x\n", dev_info, mode, rc);
+	return rc;
+}
+#endif /* WIRELESS_EXT > 8 */
+
+static int wvlan_hw_setpromisc (IFBP ifbp, int promisc)
+{
+	CFG_ID_STRCT ltv;
+	int rc;
+
+	ltv.len = 2;
+	ltv.typ = CFG_PROMISCUOUS_MODE;
+	ltv.id[0] = promisc;
+	rc = hcf_put_info(ifbp, (LTVP) &ltv);
+	DEBUG(DEBUG_NOISY, "%s: hcf_put_info(CFG_PROMISCUOUS_MODE:0x%x) returned 0x%x\n", dev_info, promisc, rc);
+	return rc;
+}
+
+
+/********************************************************************
+ * HARDWARE CONFIG / SHUTDOWN / RESET
+ */
+int wvlan_hw_config (struct net_device *dev)
+{
+	struct net_local *local = (struct net_local *) dev->priv;
+	unsigned long flags;
+	int rc, i, chlist;
+
+	// TODO: Parameters should be stored per-device (in dev->priv).
+	// The problem is that this function erase all the per-device config
+	// done via Wireless Extensions with global variables (ouch!). This
+	// means that multi-card setup are guaranteed not to work.
+
+	DEBUG(DEBUG_CALLTRACE, "-> wvlan_hw_config(%s)\n", dev->name);
+
+	// Disable interrupts
+	spin_lock_irqsave(&local->slock, flags);
+
+	// Init the HCF library
+	hcf_connect(&local->ifb, dev->base_addr);
+
+	// Init hardware and turn on interrupts
+	rc = hcf_action(&local->ifb, HCF_ACT_CARD_IN);
+	DEBUG(DEBUG_NOISY, "%s: hcf_action(HCF_ACT_CARD_IN) returned 0x%x\n", dev_info, rc);
+#if defined(PCMCIA_DEBUG) && (PCMCIA_DEBUG>=DEBUG_INTERRUPT)
+	local->ifb.IFB_IntEnMask |= HREG_EV_TICK;
+#endif
+	rc = hcf_action(&local->ifb, HCF_ACT_INT_ON);
+	DEBUG(DEBUG_NOISY, "%s: hcf_action(HCF_ACT_INT_ON) returned 0x%x\n", dev_info, rc);
+
+	// Set hardware parameters
+	if (!rc)
+		rc = wvlan_hw_setmaxdatalen(&local->ifb, HCF_MAX_MSG);
+	if (!rc)
+		rc = wvlan_hw_setporttype(&local->ifb, port_type);
+	if (!rc && *station_name)
+		rc = wvlan_hw_setstationname(&local->ifb, station_name);
+	if (!rc && *network_name)
+		rc = wvlan_hw_setssid(&local->ifb, network_name);
+	if (!rc)
+		rc = wvlan_hw_setthreshold(&local->ifb, ap_density, CFG_CNF_SYSTEM_SCALE);
+	if (!rc)
+		rc = wvlan_hw_setthreshold(&local->ifb, medium_reservation, CFG_RTS_THRH);
+	if (!rc)
+		rc = wvlan_hw_setthreshold(&local->ifb, frag_threshold, CFG_FRAGMENTATION_THRH);
+	if (!rc)
+		rc = wvlan_hw_setthreshold(&local->ifb, transmit_rate, CFG_TX_RATE_CONTROL);
+
+	// Check valid channel settings
+	if (!rc && port_type == 3)
+	{
+		chlist = wvlan_hw_getchannellist(&local->ifb);
+		printk(KERN_INFO "%s: Valid channels: ", dev_info);
+		for (i=1; i<17; i++)
+			if (1<<(i-1) & chlist)
+				printk("%d ", i);
+		printk("\n");
+		if (channel<1 || channel>16 || !(1<<(channel-1) & chlist))
+			printk(KERN_WARNING "%s: Channel value of %d is invalid!\n", dev_info, channel);
+		else
+			rc = wvlan_hw_setchannel(&local->ifb, channel);
+	}
+
+	// Enable hardware
+	if (!rc)
+	{
+		rc = hcf_enable(&local->ifb, 0);
+		DEBUG(DEBUG_NOISY, "%s: hcf_enable(0) returned 0x%x\n", dev_info, rc);
+	}
+
+	// Get MAC address
+	if (!rc)
+	{
+		rc = wvlan_hw_getmacaddr(&local->ifb, dev->dev_addr, ETH_ALEN);
+		printk(KERN_INFO "%s: MAC address on %s is ", dev_info, dev->name);
+		for (i=0; i<ETH_ALEN; i++)
+			printk("%02x ", dev->dev_addr[i]);
+		printk("\n");
+	}
+
+	// Re-enable interrupts
+	spin_unlock_irqrestore(&local->slock, flags);
+
+	// Report error if any
+	if (rc)
+		printk(KERN_WARNING "%s: Initialization failed!\n", dev_info);
+
+	DEBUG(DEBUG_CALLTRACE, "<- wvlan_hw_config()\n");
+	return rc;
+}
+
+int wvlan_hw_shutdown (struct net_device *dev)
+{
+	struct net_local *local = (struct net_local *) dev->priv;
+	unsigned long flags;
+	int rc;
+
+	DEBUG(DEBUG_CALLTRACE, "-> wvlan_hw_shutdown(%s)\n", dev->name);
+
+	// Disable interrupts
+	spin_lock_irqsave(&local->slock, flags);
+
+	// Disable and shutdown hardware
+	rc = hcf_disable(&local->ifb, 0);
+	DEBUG(DEBUG_NOISY, "%s: hcf_disable(0) returned 0x%x\n", dev_info, rc);
+	rc = hcf_action(&local->ifb, HCF_ACT_INT_OFF);
+	DEBUG(DEBUG_NOISY, "%s: hcf_action(HCF_ACT_INT_OFF) returned 0x%x\n", dev_info, rc);
+	rc = hcf_action(&local->ifb, HCF_ACT_CARD_OUT);
+	DEBUG(DEBUG_NOISY, "%s: hcf_action(HCF_ACT_CARD_OUT) returned 0x%x\n", dev_info, rc);
+
+	// Release HCF library
+	hcf_disconnect(&local->ifb);
+
+	// Re-enable interrupts
+	spin_unlock_irqrestore(&local->slock, flags);
+
+	DEBUG(DEBUG_CALLTRACE, "<- wvlan_hw_shutdown()\n");
+	return 0;
+}
+
+int wvlan_hw_reset (struct net_device *dev)
+{
+	struct net_local *local = (struct net_local *) dev->priv;
+	unsigned long flags;
+	int rc;
+
+	DEBUG(DEBUG_CALLTRACE, "-> wvlan_hw_reset(%s)\n", dev->name);
+
+	// Disable interrupts
+	spin_lock_irqsave(&local->slock, flags);
+
+	// Disable hardware
+	rc = hcf_disable(&local->ifb, 0);
+	DEBUG(DEBUG_NOISY, "%s: hcf_disable(0) returned 0x%x\n", dev_info, rc);
+	rc = hcf_action(&local->ifb, HCF_ACT_INT_OFF);
+	DEBUG(DEBUG_NOISY, "%s: hcf_action(HCF_ACT_INT_OFF) returned 0x%x\n", dev_info, rc);
+
+	// Re-Enable hardware
+	rc = hcf_action(&local->ifb, HCF_ACT_INT_ON);
+	DEBUG(DEBUG_NOISY, "%s: hcf_action(HCF_ACT_INT_ON) returned 0x%x\n", dev_info, rc);
+	rc = hcf_enable(&local->ifb, 0);
+	DEBUG(DEBUG_NOISY, "%s: hcf_enable(0) returned 0x%x\n", dev_info, rc);
+
+	// Re-enable interrupts
+	spin_unlock_irqrestore(&local->slock, flags);
+
+	DEBUG(DEBUG_CALLTRACE, "<- wvlan_hw_reset()\n");
+	return rc;
+}
+
+
+/********************************************************************
+ * NET STATS / IOCTL
+ */
+struct net_device_stats *wvlan_get_stats (struct net_device *dev)
+{
+	DEBUG(DEBUG_CALLTRACE, "<> wvlan_get_stats(%s)\n", dev->name);
+	return(&((struct net_local *) dev->priv)->stats);
+}
+
+#ifdef WIRELESS_EXT
+int wvlan_ioctl (struct net_device *dev, struct ifreq *rq, int cmd)
+{
+	struct net_local *local = (struct net_local *) dev->priv;
+	struct iwreq *wrq = (struct iwreq *) rq;
+	unsigned long flags;
+	int rc = 0;
+
+	DEBUG(DEBUG_CALLTRACE, "-> wvlan_ioctl(%s, cmd=0x%x)\n", dev->name, cmd);
+
+	// Disable interrupts
+	spin_lock_irqsave(&local->slock, flags);
+
+	switch (cmd)
+	{
+		// Get name
+		case SIOCGIWNAME:
+			strcpy(wrq->u.name, "IEEE 802.11-DS");
+			break;
+
+		// Set frequency/channel
+		case SIOCSIWFREQ:
+			// If setting by frequency, convert to a channel
+			if((wrq->u.freq.e == 1) &&
+			   (wrq->u.freq.m >= (int) 2.412e8) &&
+			   (wrq->u.freq.m <= (int) 2.487e8))
+			{
+				int f = wrq->u.freq.m / 100000;
+				int c = 0;
+				while((c < 14) && (f != frequency_list[c]))
+					c++;
+				// Hack to fall through...
+				wrq->u.freq.e = 0;
+				wrq->u.freq.m = c + 1;
+			}
+			// Setting by channel number
+			if ((port_type != 3) || (wrq->u.freq.m > 1000) || (wrq->u.freq.e > 0))
+				rc = -EOPNOTSUPP;
+			else
+			{
+				int channel = wrq->u.freq.m;
+				int chlist = wvlan_hw_getchannellist(&local->ifb);
+				if (channel<1 || channel>16 || !(1<<(channel-1) & chlist))
+				{
+					DEBUG(DEBUG_INFO, "%s: New channel value of %d for %s is invalid!\n", dev_info, wrq->u.freq.m, dev->name);
+					rc = -EINVAL;
+				}
+				else
+				{
+					wvlan_hw_setchannel(&local->ifb, wrq->u.freq.m);
+					wvlan_hw_reset(dev);
+					channel = wrq->u.freq.m;
+				}
+			}
+			break;
+
+		// Get frequency/channel
+		case SIOCGIWFREQ:
+#ifdef WEXT_USECHANNELS
+			wrq->u.freq.m = wvlan_hw_getcurrentchannel(&local->ifb);
+			wrq->u.freq.e = 0;
+#else
+			{
+				int f = wvlan_hw_getcurrentchannel(&local->ifb);
+				wrq->u.freq.m = frequency_list[f-1] * 100000;
+				wrq->u.freq.e = 1;
+			}
+#endif
+			break;
+
+#if WIRELESS_EXT > 5
+		// Set desired network name (ESSID)
+		case SIOCSIWESSID:
+			if (wrq->u.data.pointer)
+			{
+				char	essid[IW_ESSID_MAX_SIZE + 1];
+
+				/* Check if we asked for `any' */
+				if(wrq->u.data.flags == 0)
+				{
+					essid[0] = '\0';
+				}
+				else
+				{
+					/* Check the size of the string */
+					if(wrq->u.data.length >
+					   IW_ESSID_MAX_SIZE + 1)
+					{
+						rc = -E2BIG;
+						break;
+					}
+					copy_from_user(essid,
+						       wrq->u.data.pointer,
+						       wrq->u.data.length);
+					essid[IW_ESSID_MAX_SIZE] = '\0';
+				}
+				wvlan_hw_setssid(&local->ifb, essid);
+				wvlan_hw_reset(dev);
+				strncpy(network_name, essid, sizeof(network_name)-1);
+			}
+			break;
+
+		// Get current network name (ESSID)
+		case SIOCGIWESSID:
+			if (wrq->u.data.pointer)
+			{
+				char essid[IW_ESSID_MAX_SIZE + 1];
+				/* Get the essid that was set */
+				wvlan_hw_getssid(&local->ifb, essid,
+						 IW_ESSID_MAX_SIZE,
+						 WVLAN_DESIRED);
+				/* If it was set to any, get the current one */
+				if(strlen(essid) == 0)
+					wvlan_hw_getssid(&local->ifb, essid,
+							 IW_ESSID_MAX_SIZE,
+							 WVLAN_CURRENT);
+
+				/* Push it out ! */
+				wrq->u.data.length = strlen(essid) + 1;
+				wrq->u.data.flags = 1; /* active */
+				copy_to_user(wrq->u.data.pointer, essid, sizeof(essid));
+			}
+			break;
+
+		// Get current Access Point (BSSID)
+		case SIOCGIWAP:
+			wvlan_hw_getbssid(&local->ifb, wrq->u.ap_addr.sa_data, ETH_ALEN);
+			wrq->u.ap_addr.sa_family = ARPHRD_ETHER;
+			break;
+
+#endif	/* WIRELESS_EXT > 5 */
+
+#if WIRELESS_EXT > 7
+		// Set desired station name
+		case SIOCSIWNICKN:
+			if (wrq->u.data.pointer)
+			{
+				char	name[IW_ESSID_MAX_SIZE + 1];
+
+				/* Check the size of the string */
+				if(wrq->u.data.length > IW_ESSID_MAX_SIZE + 1)
+				{
+					rc = -E2BIG;
+					break;
+				}
+				copy_from_user(name, wrq->u.data.pointer, wrq->u.data.length);
+				name[IW_ESSID_MAX_SIZE] = '\0';
+				wvlan_hw_setstationname(&local->ifb, name);
+				wvlan_hw_reset(dev);
+				strncpy(station_name, name, sizeof(station_name)-1);
+			}
+			break;
+
+		// Get current station name
+		case SIOCGIWNICKN:
+			if (wrq->u.data.pointer)
+			{
+				char name[IW_ESSID_MAX_SIZE + 1];
+				wvlan_hw_getstationname(&local->ifb, name, IW_ESSID_MAX_SIZE);
+				wrq->u.data.length = strlen(name) + 1;
+				copy_to_user(wrq->u.data.pointer, name, sizeof(name));
+			}
+			break;
+
+		// Set the desired bit-rate
+		case SIOCSIWRATE:
+			{
+				// Start the magic...
+				char	brlist[9];
+				int	brnum = wvlan_hw_getratelist(&local->ifb, brlist);
+				int	brate = wrq->u.bitrate.value/500000;
+				int	wvrate = 0;
+
+				// Auto or fixed ?
+				if(wrq->u.bitrate.fixed == 0)
+					// Let be simple for now...
+					wvrate = 3;
+					// We could read the last desired
+					// channel and set corresp. auto mode
+				else if((wrq->u.bitrate.value <= (brnum * 2 - 1)) &&
+					(wrq->u.bitrate.value > 0))
+				{
+					// Setting by channel index
+					wvrate = wrq->u.bitrate.value;
+				}
+				else
+				{
+					// Setting by frequency value
+					// Find index in magic table
+					while((rate_list[wvrate] != brate) &&
+					      (wvrate < (brnum * 2)))
+						wvrate++;
+
+					// Check if in range
+					if((wvrate < 1) ||
+					   (wvrate >= (brnum * 2)))
+					{
+						rc = -EINVAL;
+						break;
+					}
+				}
+				wvlan_hw_setbitrate(&local->ifb, wvrate);
+				wvlan_hw_reset(dev);
+				transmit_rate = wvrate;
+			}
+			break;
+
+		// Get the current bit-rate
+		case SIOCGIWRATE:
+			{
+				int	wvrate = wvlan_hw_getbitrate(&local->ifb, WVLAN_DESIRED);
+				int	brate = rate_list[wvrate];
+
+				// Auto ?
+				if (brate < 0)
+				{
+					wrq->u.bitrate.fixed = 0;
+					wvrate = wvlan_hw_getbitrate(&local->ifb, WVLAN_CURRENT);
+#if OLD_FIRMWARE
+					// Or maybe I just got it wrong?
+					brate = rate_list[wvrate];
+#else
+					brate = 2 * wvrate;
+					// Mandatory kludge!
+					if (wvrate == 6)
+						brate = 11;
+#endif
+				}
+				else
+					wrq->u.bitrate.fixed = 1;
+
+				wrq->u.bitrate.value = brate * 500000;
+			}
+			break;
+
+		// Set the desired RTS threshold
+		case SIOCSIWRTS:
+			{
+				int rthr = wrq->u.rts.value;
+				// if(wrq->u.rts.fixed == 0) we should complain
+#if WIRELESS_EXT > 8
+				if(wrq->u.rts.disabled)
+					rthr = 2347;
+#endif /* WIRELESS_EXT > 8 */
+				if((rthr < 0) || (rthr > 2347))
+				{
+					rc = -EINVAL;
+					break;
+				}
+				wvlan_hw_setthreshold(&local->ifb, rthr, CFG_RTS_THRH);
+				wvlan_hw_reset(dev);
+				medium_reservation = rthr;
+			}
+			break;
+
+		// Get the current RTS threshold
+		case SIOCGIWRTS:
+			wrq->u.rts.value = wvlan_hw_getthreshold(&local->ifb, CFG_RTS_THRH);
+#if WIRELESS_EXT > 8
+			wrq->u.rts.disabled = (wrq->u.rts.value == 2347);
+#endif /* WIRELESS_EXT > 8 */
+			wrq->u.rts.fixed = 1;
+			break;
+
+		// Set the desired fragmentation threshold
+		case SIOCSIWFRAG:
+			{
+				int fthr = wrq->u.frag.value;
+				// if(wrq->u.frag.fixed == 0) should complain
+#if WIRELESS_EXT > 8
+				if(wrq->u.frag.disabled)
+					fthr = 2346;
+#endif /* WIRELESS_EXT > 8 */
+				if((fthr < 256) || (fthr > 2346))
+				{
+					rc = -EINVAL;
+					break;
+				}
+				fthr &= ~0x1;	// Get an even value
+				wvlan_hw_setthreshold(&local->ifb, fthr, CFG_FRAGMENTATION_THRH);
+				wvlan_hw_reset(dev);
+			}
+			break;
+
+		// Get the current fragmentation threshold
+		case SIOCGIWFRAG:
+			wrq->u.frag.value = wvlan_hw_getthreshold(&local->ifb, CFG_FRAGMENTATION_THRH);
+#if WIRELESS_EXT > 8
+			wrq->u.frag.disabled = (wrq->u.frag.value == 2346);
+#endif /* WIRELESS_EXT > 8 */
+			wrq->u.frag.fixed = 1;
+			break;
+
+		// Set the desired AP density
+		case SIOCSIWSENS:
+			{
+				int dens = wrq->u.sens.value;
+				if((dens < 1) || (dens > 3))
+				{
+					rc = -EINVAL;
+					break;
+				}
+				wvlan_hw_setthreshold(&local->ifb, dens, CFG_CNF_SYSTEM_SCALE);
+				wvlan_hw_reset(dev);
+				ap_density = dens;
+			}
+			break;
+
+		// Get the current AP density
+		case SIOCGIWSENS:
+			wrq->u.sens.value = wvlan_hw_getthreshold(&local->ifb, CFG_CNF_SYSTEM_SCALE);
+			wrq->u.sens.fixed = 0;	/* auto */
+			break;
+#endif	/* WIRELESS_EXT > 7 */
+
+#if WIRELESS_EXT > 8
+		// Set port type
+		case SIOCSIWMODE:
+			{
+				char ptype = 1;
+
+				switch (wrq->u.mode)
+				{
+					case IW_MODE_ADHOC:
+						ptype = 3;
+						// Fall through
+					case IW_MODE_INFRA:
+						wvlan_hw_setporttype(&local->ifb, ptype);
+						wvlan_hw_reset(dev);
+						port_type = ptype;
+						break;
+					default:
+						rc = -EINVAL;
+				}
+			}
+			break;
+
+		// Get port type
+		case SIOCGIWMODE:
+			if (wvlan_hw_getporttype(&local->ifb) == 1)
+				wrq->u.mode = IW_MODE_INFRA;
+			else
+				wrq->u.mode = IW_MODE_ADHOC;
+			break;
+
+		// Set the desired Power Management mode
+		case SIOCSIWPOWER:
+			// Disable it ?
+			if(wrq->u.power.disabled)
+				wvlan_hw_setpower (&local->ifb, 0, CFG_CNF_PM_ENABLED);
+			else
+			{
+				// Check mode
+				switch(wrq->u.power.flags & IW_POWER_MODE)
+				{
+					case IW_POWER_UNICAST_R:
+						wvlan_hw_setpower(&local->ifb, 0, CFG_CNF_MCAST_RX);
+						break;
+					case IW_POWER_ALL_R:
+						wvlan_hw_setpower(&local->ifb, 1, CFG_CNF_MCAST_RX);
+						break;
+					case IW_POWER_ON:	// None = ok
+						break;
+					default:	// Invalid
+						rc = -EINVAL;
+				}
+				// Set period
+				if (wrq->u.power.flags & IW_POWER_PERIOD)
+				{
+					// Activate PM
+					wvlan_hw_setpower(&local->ifb, 1, CFG_CNF_PM_ENABLED);
+					// Hum: check max/min values ?
+					wvlan_hw_setpmsleep (&local->ifb, wrq->u.power.value/1000);
+				}
+				if (wrq->u.power.flags & IW_POWER_TIMEOUT)
+					rc = -EINVAL;	// Invalid
+			}
+			if (!rc)
+				wvlan_hw_reset(dev);
+			break;
+
+		// Get the power management settings
+		case SIOCGIWPOWER:
+			wrq->u.power.disabled = !wvlan_hw_getpower(&local->ifb, CFG_CNF_PM_ENABLED);
+			wrq->u.power.flags = IW_POWER_PERIOD;
+			wrq->u.power.value = wvlan_hw_getpmsleep (&local->ifb) * 1000;
+			if (wvlan_hw_getpower(&local->ifb, CFG_CNF_MCAST_RX))
+				wrq->u.power.flags |= IW_POWER_ALL_R;
+			else
+				wrq->u.power.flags |= IW_POWER_UNICAST_R;
+			break;
+
+		// Set WEP keys and mode
+		case SIOCSIWENCODE:
+			// Is it supported?
+			if (!wvlan_hw_getprivacy(&local->ifb))
+			{
+				rc = -EOPNOTSUPP;
+				break;
+			}
+			// Basic checking: do we have a key to set?
+			if (wrq->u.encoding.pointer != (caddr_t) 0)
+			{
+				int index = (wrq->u.encoding.flags & IW_ENCODE_INDEX) - 1;
+				// Check the size of the key
+				if (wrq->u.encoding.length > MAX_KEY_SIZE)
+				{
+					rc = -EINVAL;
+					break;
+				}
+				// Check the index
+				if ((index < 0) || (index >= MAX_KEYS))
+					index = local->transmit_key;
+				// Cleanup
+				memset(local->key[index].key, 0, MAX_KEY_SIZE);
+				// Copy the key in the driver
+				if (copy_from_user(local->key[index].key, wrq->u.encoding.pointer, wrq->u.encoding.length))
+				{
+					local->key[index].len = 0;
+					rc = -EFAULT;
+					break;
+				}
+				// Set the length
+				if (wrq->u.encoding.length > MIN_KEY_SIZE)
+					local->key[index].len = MAX_KEY_SIZE;
+				else
+					if (wrq->u.encoding.length > 0)
+						local->key[index].len = MIN_KEY_SIZE;
+					else
+						local->key[index].len = 0;
+				// Enable WEP (if possible)
+				if ((index == local->transmit_key) && (local->key[local->transmit_key].len > 0))
+					local->wep_on = 1;
+			}
+			else
+			{
+				int index = (wrq->u.encoding.flags & IW_ENCODE_INDEX) - 1;
+				// Do we want to just set the current transmit key?
+				if ((index >= 0) && (index < MAX_KEYS))
+				{
+					if (local->key[index].len > 0)
+					{
+						local->transmit_key = index;
+						local->wep_on = 1;
+					}
+					else
+						rc = -EINVAL;
+				}
+			}
+			// Read the flags
+			if (wrq->u.encoding.flags & IW_ENCODE_DISABLED)
+				local->wep_on = 0;	// disable encryption
+			if (wrq->u.encoding.flags & IW_ENCODE_RESTRICTED)
+				rc = -EINVAL;		// Invalid
+			// Commit the changes
+			if (rc == 0) {
+				wvlan_hw_setprivacy(&local->ifb, local->wep_on, local->transmit_key, local->key);
+				wvlan_hw_reset(dev);
+			}
+			break;
+
+		// Get the WEP keys and mode
+		case SIOCGIWENCODE:
+			// Is it supported?
+			if (!wvlan_hw_getprivacy(&local->ifb))
+			{
+				rc = -EOPNOTSUPP;
+				break;
+			}
+			// Only super-user can see WEP key
+			if (!capable(CAP_NET_ADMIN))
+			{
+				rc = -EPERM;
+				break;
+			}
+			// Basic checking...
+			if (wrq->u.encoding.pointer != (caddr_t) 0)
+			{
+				int index = (wrq->u.encoding.flags & IW_ENCODE_INDEX) - 1;
+				// Note: should read from adapter(?), and check if WEP capable
+				// Set the flags
+				wrq->u.encoding.flags = 0;
+				if (local->wep_on == 0)
+					wrq->u.encoding.flags |= IW_ENCODE_DISABLED;
+				// Which key do we want
+				if ((index < 0) || (index >= MAX_KEYS))
+					index = local->transmit_key;
+				wrq->u.encoding.flags |= index + 1;
+				// Copy the key to the user buffer
+				wrq->u.encoding.length = local->key[index].len;
+				if (copy_to_user(wrq->u.encoding.pointer, local->key[index].key, local->key[index].len))
+					rc = -EFAULT;
+			}
+			break;
+#endif /* WIRELESS_EXT > 8 */
+
+		// Get range of parameters
+		case SIOCGIWRANGE:
+			if (wrq->u.data.pointer)
+			{
+				struct iw_range range;
+				rc = verify_area(VERIFY_WRITE, wrq->u.data.pointer, sizeof(struct iw_range));
+				if (rc)
+					break;
+				wrq->u.data.length = sizeof(range);
+				// Throughput is no way near 2 Mb/s !
+				// This value should be :
+				//	1.6 Mb/s for the 2 Mb/s card
+				//	~5 Mb/s for the 11 Mb/s card
+				// Jean II
+				range.throughput = 1.6 * 1024 * 1024;
+				range.min_nwid = 0x0000;
+				range.max_nwid = 0x0000;
+				range.num_channels = 14;
+				range.num_frequency = wvlan_hw_getfrequencylist(&local->ifb,
+						      range.freq,
+						      IW_MAX_FREQUENCIES);
+				range.sensitivity = 3;
+				if (port_type == 3 && local->spy_number == 0)
+				{
+					range.max_qual.qual = 0;
+					range.max_qual.level = 0;
+					range.max_qual.noise = 0;
+				}
+				else
+				{
+					range.max_qual.qual = 0x8b - 0x2f;
+					range.max_qual.level = 0x2f - 0x95 - 1;
+					range.max_qual.noise = 0x2f - 0x95 - 1;
+				}
+#if WIRELESS_EXT > 7
+				range.num_bitrates = wvlan_getbitratelist(&local->ifb,
+							range.bitrate,
+							IW_MAX_BITRATES);
+				range.min_rts = 0;
+				range.max_rts = 2347;
+				range.min_frag = 256;
+				range.max_frag = 2346;
+#endif	/* WIRELESS_EXT > 7 */
+#if WIRELESS_EXT > 8
+				// Is WEP it supported?
+				if (wvlan_hw_getprivacy(&local->ifb))
+				{
+					// WEP: RC4 40 bits
+					range.encoding_size[0] = 5;
+					// RC4 ~128 bits
+					range.encoding_size[1] = 14;
+					range.num_encoding_sizes = 2;
+					range.max_encoding_tokens = 4;	// 4 keys
+				}
+				else
+				{
+					range.num_encoding_sizes = 0;
+					range.max_encoding_tokens = 0;
+				}
+#endif /* WIRELESS_EXT > 8 */
+				copy_to_user(wrq->u.data.pointer, &range, sizeof(struct iw_range));
+			}
+			break;
+
+#ifdef WIRELESS_SPY
+		// Set the spy list
+		case SIOCSIWSPY:
+			if (wrq->u.data.length > IW_MAX_SPY)
+			{
+				rc = -E2BIG;
+				break;
+			}
+			local->spy_number = wrq->u.data.length;
+			if (local->spy_number > 0)
+			{
+				struct sockaddr address[IW_MAX_SPY];
+				int i;
+				rc = verify_area(VERIFY_READ, wrq->u.data.pointer, sizeof(struct sockaddr) * local->spy_number);
+				if (rc)
+					break;
+				copy_from_user(address, wrq->u.data.pointer, sizeof(struct sockaddr) * local->spy_number);
+				for (i=0; i<local->spy_number; i++)
+					memcpy(local->spy_address[i], address[i].sa_data, MAC_ADDR_SIZE);
+				memset(local->spy_stat, 0, sizeof(struct iw_quality) * IW_MAX_SPY);
+				DEBUG(DEBUG_INFO, "%s: New spy list:\n", dev_info);
+				for (i=0; i<wrq->u.data.length; i++)
+					DEBUG(DEBUG_INFO, "%s: %d - %02x:%02x:%02x:%02x:%02x:%02x\n", dev_info, i+1,
+						local->spy_address[i][0], local->spy_address[i][1],
+						local->spy_address[i][2], local->spy_address[i][3],
+						local->spy_address[i][4], local->spy_address[i][5]);
+			}
+			break;
+
+		// Get the spy list
+		case SIOCGIWSPY:
+			wrq->u.data.length = local->spy_number;
+			if ((local->spy_number > 0) && (wrq->u.data.pointer))
+			{
+				struct sockaddr address[IW_MAX_SPY];
+				int i;
+				rc = verify_area(VERIFY_WRITE, wrq->u.data.pointer, (sizeof(struct iw_quality)+sizeof(struct sockaddr)) * IW_MAX_SPY);
+				if (rc)
+					break;
+				for (i=0; i<local->spy_number; i++)
+				{
+					memcpy(address[i].sa_data, local->spy_address[i], MAC_ADDR_SIZE);
+					address[i].sa_family = AF_UNIX;
+				}
+				copy_to_user(wrq->u.data.pointer, address, sizeof(struct sockaddr) * local->spy_number);
+				copy_to_user(wrq->u.data.pointer + (sizeof(struct sockaddr)*local->spy_number), local->spy_stat, sizeof(struct iw_quality) * local->spy_number);
+				for (i=0; i<local->spy_number; i++)
+					local->spy_stat[i].updated = 0;
+			}
+			break;
+#endif /* WIRELESS_SPY */
+
+#ifdef HISTOGRAM
+		// Set the histogram range
+		case SIOCDEVPRIVATE + 0xd:
+			// Only super-user can set histogram data
+			if (!capable(CAP_NET_ADMIN))
+			{
+				rc = -EPERM;
+				break;
+			}
+			if (wrq->u.data.length > 16)
+			{
+				rc = -E2BIG;
+				break;
+			}
+			local->his_number = wrq->u.data.length;
+			if (local->his_number > 0)
+			{
+				rc = verify_area(VERIFY_READ, wrq->u.data.pointer, sizeof(char) * local->his_number);
+				if (rc)
+					break;
+				copy_from_user(local->his_range, wrq->u.data.pointer, sizeof(char) * local->his_number);
+				memset(local->his_sum, 0, sizeof(long) * 16);
+			}
+			break;
+
+		// Get the histogram statistic
+		case SIOCDEVPRIVATE + 0xe:
+			wrq->u.data.length = local->his_number;
+			if ((local->his_number > 0) && (wrq->u.data.pointer))
+			{
+				rc = verify_area(VERIFY_WRITE, wrq->u.data.pointer, sizeof(long) * 16);
+				if (rc)
+					break;
+				copy_to_user(wrq->u.data.pointer, local->his_sum, sizeof(long) * local->his_number);
+			}
+			break;
+#endif /* HISTOGRAM */
+
+		// Get valid private ioctl calls
+		case SIOCGIWPRIV:
+			if (wrq->u.data.pointer)
+			{
+				struct iw_priv_args priv[] = {
+#ifdef HISTOGRAM
+					{ SIOCDEVPRIVATE + 0xd, IW_PRIV_TYPE_BYTE | 16, 0, "sethisto" },
+					{ SIOCDEVPRIVATE + 0xe, 0, IW_PRIV_TYPE_INT | 16, "gethisto" },
+#endif
+#ifdef PCMCIA_DEBUG
+					{ SIOCDEVPRIVATE + 0x0, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "force_reset" },
+					{ SIOCDEVPRIVATE + 0x1, IW_PRIV_TYPE_INT | IW_PRIV_SIZE_FIXED | 1, 0, "debug_getinfo" },
+#endif
+				};
+				rc = verify_area(VERIFY_WRITE, wrq->u.data.pointer, sizeof(priv));
+				if (rc)
+					break;
+				wrq->u.data.length = sizeof(priv) / sizeof(priv[0]);
+				copy_to_user(wrq->u.data.pointer, priv, sizeof(priv));
+			}
+			break;
+
+#ifdef PCMCIA_DEBUG
+		// Force card reset (debug purpose only)
+		case SIOCDEVPRIVATE + 0x0:
+			// Only super-user can reset the card...
+			if (!capable(CAP_NET_ADMIN))
+			{
+				rc = -EPERM;
+				break;
+			}
+			if (*((int *) wrq->u.name) > 0)
+			{
+				// 'hard' reset
+				printk(KERN_DEBUG "%s: Forcing hard reset\n", dev_info);
+				wvlan_hw_shutdown(dev);
+				wvlan_hw_config(dev);
+			}
+			else
+			{
+				// 'soft' reset
+				printk(KERN_DEBUG "%s: Forcing soft reset\n", dev_info);
+				wvlan_hw_reset(dev);
+			}
+			break;
+
+		// Get info from card and dump answer to syslog (debug purpose only)
+		case SIOCDEVPRIVATE + 0x1:
+			{
+				CFG_ID_STRCT ltv;
+				char *p;
+				int typ = *((int *) wrq->u.name);
+				ltv.len = 18;
+				ltv.typ = typ;
+				rc = hcf_get_info(&local->ifb, (LTVP) &ltv);
+				if (rc)
+					printk(KERN_DEBUG "%s: hcf_get_info(0x%x) returned error 0x%x\n", dev_info, typ, rc);
+				else
+				{
+					p = (char *) &ltv.id;
+					printk(KERN_DEBUG "%s: hcf_get_info(0x%x) returned %d words:\n", dev_info, ltv.typ, ltv.len);
+					printk(KERN_DEBUG "%s: hex-dump: ", dev_info);
+					for (rc=0; rc<(ltv.len); rc++)
+						printk("%04x ", ltv.id[rc]);
+					printk("\n");
+					printk(KERN_DEBUG "%s: ascii-dump: '", dev_info);
+					for (rc=0; rc<(ltv.len*2); rc++)
+						printk("%c", (p[rc]>31) ? p[rc] : '.');
+					printk("'\n");
+				}
+			}
+			break;
+#endif /* PCMCIA_DEBUG */
+
+		// All other calls are currently unsupported
+		default:
+			rc = -EOPNOTSUPP;
+	}
+
+	// Re-enable interrupts
+	spin_unlock_irqrestore(&local->slock, flags);
+
+	DEBUG(DEBUG_CALLTRACE, "<- wvlan_ioctl()\n");
+	return rc;
+}
+
+struct iw_statistics *wvlan_get_wireless_stats (struct net_device *dev)
+{
+	struct net_local *local = (struct net_local *) dev->priv;
+	CFG_COMMS_QUALITY_STRCT ltv;
+	unsigned long flags;
+	int rc;
+
+	DEBUG(DEBUG_CALLTRACE, "-> wvlan_get_wireless_stats(%s)\n", dev->name);
+
+	// Disable interrupts
+	spin_lock_irqsave(&local->slock, flags);
+
+	local->wstats.status = 0;
+	if (port_type != 3)
+	{
+		ltv.len = 4;
+		ltv.typ = CFG_COMMS_QUALITY;
+		rc = hcf_get_info(&local->ifb, (LTVP) &ltv);
+		DEBUG(DEBUG_NOISY, "%s: hcf_get_info(CFG_COMMS_QUALITY) returned 0x%x\n", dev_info, rc);
+		local->wstats.qual.qual = max(min(ltv.coms_qual, 0x8b-0x2f), 0);
+		local->wstats.qual.level = max(min(ltv.signal_lvl, 0x8a), 0x2f) - 0x95;
+		local->wstats.qual.noise = max(min(ltv.noise_lvl, 0x8a), 0x2f) - 0x95;
+		local->wstats.qual.updated = 7;
+	}
+	else
+	{
+		// Quality levels cannot be determined in ad-hoc mode,
+		// because we can 'hear' more that one remote station.
+		// If a spy address is defined, we report stats of the
+		// first spy address
+		local->wstats.qual.qual = 0;
+		local->wstats.qual.level = 0;
+		local->wstats.qual.noise = 0;
+		local->wstats.qual.updated = 0;
+#ifdef WIRELESS_SPY
+		if (local->spy_number > 0)
+		{
+			local->wstats.qual.qual = local->spy_stat[0].qual;
+			local->wstats.qual.level = local->spy_stat[0].level;
+			local->wstats.qual.noise = local->spy_stat[0].noise;
+			local->wstats.qual.updated = local->spy_stat[0].updated;
+		}
+#endif /* WIRELESS_SPY */
+	}
+
+	// Packets discarded in the wireless adapter due to wireless specific problems
+	local->wstats.discard.nwid = 0;
+	local->wstats.discard.code = local->ifb.IFB_NIC_Tallies.RxWEPUndecryptable;
+	local->wstats.discard.misc = local->ifb.IFB_NIC_Tallies.RxFCSErrors +
+					local->ifb.IFB_NIC_Tallies.RxDiscards_NoBuffer +
+					local->ifb.IFB_NIC_Tallies.TxDiscardsWrongSA;
+
+	// Re-enable interrupts
+	spin_unlock_irqrestore(&local->slock, flags);
+
+	DEBUG(DEBUG_CALLTRACE, "<- wvlan_get_wireless_stats()\n");
+	return (&local->wstats);
+}
+
+#ifdef WIRELESS_SPY
+static inline void wvlan_spy_gather (struct net_device *dev, u_char *mac, u_char *stats)
+{
+	struct net_local *local = (struct net_local *)dev->priv;
+	int i;
+
+	// Gather wireless spy statistics: for each packet, compare the
+	// source address with out list, and if match, get the stats...
+	for (i=0; i<local->spy_number; i++)
+		if (!memcmp(mac, local->spy_address[i], MAC_ADDR_SIZE))
+		{
+			local->spy_stat[i].qual = stats[2];
+			local->spy_stat[i].level = stats[0] - 0x95;
+			local->spy_stat[i].noise = stats[1] - 0x95;
+			local->spy_stat[i].updated = 7;
+		}
+}
+#endif /* WIRELESS_SPY */
+
+#ifdef HISTOGRAM
+static inline void wvlan_his_gather (struct net_device *dev, u_char *stats)
+{
+	struct net_local *local = (struct net_local *)dev->priv;
+	u_char level = stats[0] - 0x2f;
+	int i;
+
+	// Calculate a histogram of the signal level. Each time the
+	// level goes into our defined set of interval, we increment
+	// the count.
+	i = 0;
+	while ((i < (local->his_number-1)) && (level >= local->his_range[i++]));
+	local->his_sum[i]++;
+}
+#endif /* HISTOGRAM */
+#endif /* WIRELESS_EXT */
+
+int wvlan_change_mtu (struct net_device *dev, int new_mtu)
+{
+	if (new_mtu < WVLAN_MIN_MTU || new_mtu > WVLAN_MAX_MTU)
+	{
+		DEBUG(DEBUG_INFO, "%s: New MTU of %d for %s out of range!\n", dev_info, new_mtu, dev->name);
+		return -EINVAL;
+	}
+	dev->mtu = new_mtu;
+	DEBUG(DEBUG_INFO, "%s: MTU of %s set to %d bytes\n", dev_info, dev->name, new_mtu);
+	return 0;
+}
+
+static void wvlan_set_multicast_list (struct net_device *dev)
+{
+	struct net_local *local = (struct net_local *)dev->priv;
+	unsigned long flags;
+
+	// Note: check if hardware up & running?
+
+	// Disable interrupts
+	spin_lock_irqsave(&local->slock, flags);
+
+	DEBUG(DEBUG_INFO, "%s: setting multicast Rx mode %02X to %d addresses.\n", dev->name, dev->flags, dev->mc_count);
+
+	// Ok, what do we want?
+	if (dev->flags & IFF_PROMISC)
+	{
+		// Enable promiscuous mode: receive all packets.
+		if (!local->promiscuous)
+		{
+			local->promiscuous = 1;
+			local->mc_count = 0;
+			wvlan_hw_setpromisc(&local->ifb, local->promiscuous);
+			dev->flags |= IFF_PROMISC;
+		}
+	}
+	else
+		// If all multicast addresses
+		// or too many multicast addresses for the hardware filter
+		if ((dev->flags & IFF_ALLMULTI) || (dev->mc_count > WVLAN_MAX_MULTICAST))
+		{
+			// Disable promiscuous mode, but active the all multicast mode
+			if (!local->promiscuous) {
+				// The Wavelan IEEE doesn't seem to have a
+				// "receive all multicast" flag, which allow to
+				// grab all multicast frames. So we go for
+				// promiscuous and let TCP filter packets,
+				// which is *very* far from optimal.
+				// Note that CNF_MCAST_RX is quite different,
+				// as it specify if the Wavelan will wake up for
+				// the broadcast announcements from the AP (DTIM)
+				local->promiscuous = 1;
+				local->mc_count = 0;
+				wvlan_hw_setpromisc(&local->ifb, local->promiscuous);
+				// Tell the kernel that we are doing a really bad job...
+				dev->flags |= IFF_PROMISC;
+			}
+		}
+		else
+			// If there is some multicast addresses to send
+			if (dev->mc_list != (struct dev_mc_list *) NULL)
+			{
+				// Disable promiscuous mode, but receive all packets
+				// in multicast list
+#ifdef MULTICAST_AVOID
+				if (local->promiscuous || local->allmulticast || (dev->mc_count != local->mc_count))
+#endif
+				{
+					struct dev_mc_list *dmi;
+					int i;
+					CFG_GROUP_ADDR_STRCT ltv;
+					int rc;
+
+					local->promiscuous = 0;
+					local->mc_count = dev->mc_count;
+					// Disable promiscuous
+					wvlan_hw_setpromisc(&local->ifb, local->promiscuous);
+					dev->flags &= ~IFF_PROMISC;
+					// Write multicast addresses in the adapter
+					for (i=0, dmi=dev->mc_list; dmi; dmi=dmi->next)
+					memcpy(ltv.mac_addr[i++], dmi->dmi_addr, dmi->dmi_addrlen);
+					ltv.len = (ETH_ALEN * local->mc_count / 2) + 1;
+					ltv.typ = CFG_GROUP_ADDR;
+					rc = hcf_put_info(&local->ifb, (LTVP) &ltv);
+					DEBUG(DEBUG_NOISY, "%s: hcf_put_info(CFG_GROUP_ADDR:0x%x) returned 0x%x\n", dev_info, local->mc_count, rc);
+				}
+			}
+			else
+			{
+				// Switch to normal mode: disable promiscuous mode and
+				// clear the multicast list.
+				if (local->promiscuous || local->mc_count != 0)
+				{
+					CFG_GROUP_ADDR_STRCT ltv;
+					int rc;
+					local->promiscuous = 0;
+					local->mc_count = 0;
+					wvlan_hw_setpromisc(&local->ifb, local->promiscuous);
+					// Clear multicast list
+					ltv.len = 1;
+					ltv.typ = CFG_GROUP_ADDR;
+					rc = hcf_put_info(&local->ifb, (LTVP) &ltv);
+					DEBUG(DEBUG_NOISY, "%s: hcf_put_info(CFG_GROUP_ADDR:0x%x) returned 0x%x\n", dev_info, local->mc_count, rc);
+				}
+			}
+	// Re-enable interrupts
+	spin_unlock_irqrestore(&local->slock, flags);
+
+	return;
+}
+
+
+
+/********************************************************************
+ * NET TX / RX
+ */
+static void wvlan_watchdog (struct net_device *dev)
+{
+	DEBUG(DEBUG_CALLTRACE, "-> wvlan_wathdog(%s)\n", dev->name);
+
+	// In theory, we could try to abort the current Tx command here,
+	// this would avoid to go through a long reset process in many
+	// cases (obstruction of the channel, very high contention)...
+
+	// Reset card in case of Tx timeout
+#ifdef WVLAN_RESET_ON_TX_TIMEOUT
+	printk(KERN_WARNING "%s: %s Tx timed out! Resetting card\n", dev_info, dev->name);
+	// Note: those two will take care of locking spinlock & irq
+	wvlan_hw_shutdown(dev);
+	wvlan_hw_config(dev);
+#else
+	printk(KERN_WARNING "%s: %s Tx timed out! Ignoring...\n", dev_info, dev->name);
+#endif
+
+	DEBUG(DEBUG_CALLTRACE, "<- wvlan_watchdog()\n");
+}
+
+int wvlan_tx (struct sk_buff *skb, struct net_device *dev)
+{
+	struct net_local *local = (struct net_local *)dev->priv;
+	unsigned long flags;
+	int rc, len;
+	char *p;
+
+	DEBUG(DEBUG_CALLTRACE, "-> wvlan_tx(%s)\n", dev->name);
+
+#if (KERNEL_VERSION_CODE < KERNEL_VERSION(2,3,42))
+	// We normally shouldn't be called if queue is stopped (transmitter busy)
+	// but older kernel code does anyway. So we'll check if the last
+	// transmission has timed out and reset the device in case
+	if (netif_queue_stopped(dev))
+	{
+		DEBUG(DEBUG_TXRX, "%s: wvlan_tx(%s) called while busy!\n", dev_info, dev->name);
+		if ((jiffies - dev->trans_start) < TX_TIMEOUT)
+			return 1;
+		if (!netif_running(dev))
+		{
+			printk(KERN_WARNING "%s: %s Tx on stopped device!\n", dev_info, dev->name);
+			return 1;
+		}
+		wvlan_watchdog(dev);
+	}
+#endif
+
+	skb_tx_check(dev, skb);
+#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,1,79))
+	skb->arp = 1;
+#endif
+
+	// Disable interrupts
+	spin_lock_irqsave(&local->slock, flags);
+
+	// Tell queueing layer to stop sending
+	// TODO: We should use multiple Tx buffers and
+	// re-enable the queue (netif_wake_queue()) if
+	// there's space left in the Tx buffers.
+	netif_stop_queue(dev);
+
+	// Prepare packet
+	p = skb->data;
+	len = (ETH_ZLEN < skb->len) ? skb->len : ETH_ZLEN;
+
+	// Add Ethernet-II frame encapsulation, because
+	// HCF-light doesn't support that.
+	if (p[13] + (p[12] << 8) > 1500)
+	{
+		hcf_put_data(&local->ifb, p, 12, 0);
+		len += sizeof(snap_header);
+		snap_header[1] = (len-0x0e) & 0xff;
+		snap_header[0] = (char)((len-0x0e) >> 8);
+		hcf_put_data(&local->ifb, snap_header, sizeof(snap_header), 0);
+		hcf_put_data(&local->ifb, p+12, len-12-sizeof(snap_header), 0);
+	}
+	else
+		hcf_put_data(&local->ifb, p, len, 0);
+
+	// Send packet
+	rc = hcf_send(&local->ifb, 0);
+
+	// Remeber time transmission and count tx bytes
+	dev->trans_start = jiffies;
+	add_tx_bytes(&local->stats, len);
+
+	// Re-enable interrupts
+	spin_unlock_irqrestore(&local->slock, flags);
+
+	// It might be no good idea doing a printk() debug output during
+	// disabled interrupts (I'm not sure...). So better do it here.
+	DEBUG(DEBUG_TXRX, "%s: Sending 0x%x octets\n", dev_info, len);
+	DEBUG(DEBUG_NOISY, "%s: hcf_send() returned 0x%x\n", dev_info, rc);
+
+	DEV_KFREE_SKB(skb);
+	DEBUG(DEBUG_CALLTRACE, "<- wvlan_tx()\n");
+	return 0;
+}
+
+void wvlan_rx (struct net_device *dev, int len)
+{
+	struct net_local *local = (struct net_local *)dev->priv;
+	struct sk_buff *skb;
+	char *p;
+
+	DEBUG(DEBUG_CALLTRACE, "-> wvlan_rx(%s)\n", dev->name);
+
+	// Create skb packet
+	skb = dev_alloc_skb(len+2);
+	if (!skb)
+	{
+		printk(KERN_WARNING "%s: %s Rx cannot allocate buffer for new packet\n", dev_info, dev->name);
+		local->stats.rx_dropped++;
+		return;
+	}
+	DEBUG(DEBUG_TXRX, "%s: Receiving 0x%x octets\n", dev_info, len);
+
+	// Align IP on 16b boundary
+	skb_reserve(skb, 2);
+	p = skb_put(skb, len);
+	dev->last_rx = jiffies;
+
+	// Add Ethernet-II frame decapsulation, because
+	// HCF-light doesn't support that.
+	if (local->ifb.IFB_RxStat == 0x2000 || local->ifb.IFB_RxStat == 0x4000)
+	{
+		hcf_get_data(&local->ifb, 0, p, 12);
+		hcf_get_data(&local->ifb, 12+sizeof(snap_header), p+12, len-12-sizeof(snap_header));
+		skb_trim(skb, len-sizeof(snap_header));
+	}
+	else
+		hcf_get_data(&local->ifb, 0, p, len);
+
+	skb->dev = dev;
+	skb->protocol = eth_type_trans(skb, dev);
+	skb->ip_summed = CHECKSUM_NONE;
+
+	// Hand the packet over to the kernel
+	netif_rx(skb);
+	local->stats.rx_packets++;
+	add_rx_bytes(&local->stats, len);
+
+#ifdef WIRELESS_EXT
+#if defined(WIRELESS_SPY) || defined(HISTOGRAM)
+	if (
+#ifdef WIRELESS_SPY
+		(local->spy_number > 0) ||
+#endif
+#ifdef HISTOGRAM
+		(local->his_number > 0) ||
+#endif
+		0 )
+	{
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(1,3,0))
+		char *srcaddr = skb->mac.raw + MAC_ADDR_SIZE;
+#else
+		char *srcaddr = skb->data + MAX_ADDR_SIZE;
+#endif
+		u_char stats[3];
+		int rc, i;
+		local->wstats.status = 0;
+
+		// Using spy support with port_type==1 will really
+		// slow down everything, because the signal quality
+		// must be queried for each packet here.
+		// If the user really asks for it (set some address in the
+		// spy list), we do it, but he will pay the price.
+		// Note that to get here, you need both WIRELESS_SPY
+		// compiled in AND some addresses in the list !!!
+		// TODO: Get and cache stats here so that they
+		// are available but don't need to be retreived
+		// every time a packet is received.
+#if defined(HISTOGRAM)
+		// We can't be clever...
+		rc = hcf_get_data(&local->ifb, HFS_Q_INFO, stats, 2);
+		DEBUG(DEBUG_NOISY, "%s: hcf_get_data(HFS_Q_INFO) returned 0x%x\n", dev_info, rc);
+#else // Therefore WIRELESS_SPY only !!!
+		memset(&stats, 0, sizeof(stats));
+		// Query only for addresses in our list !
+		for (i=0; i<local->spy_number; i++)
+			if (!memcmp(srcaddr, local->spy_address[i], MAC_ADDR_SIZE))
+			{
+				rc = hcf_get_data(&local->ifb, HFS_Q_INFO, stats, 2);
+				break;
+			}
+#endif
+		stats[2] = stats[0];
+		stats[0] = max(min(stats[1], 0x8a), 0x2f);
+		stats[1] = max(min(stats[2], 0x8a), 0x2f);
+		stats[2] = stats[0] - stats[1];
+#ifdef WIRELESS_SPY
+		wvlan_spy_gather(dev, srcaddr, stats);  
+#endif
+#ifdef HISTOGRAM
+		wvlan_his_gather(dev, stats);
+#endif
+	}
+#endif /* WIRELESS_SPY || HISTOGRAM */
+#endif /* WIRELESS_EXT */
+
+	DEBUG(DEBUG_CALLTRACE, "<- wvlan_rx()\n");
+}
+
+
+/********************************************************************
+ * NET OPEN / CLOSE
+ */
+
+static int wvlan_open (struct net_device *dev)
+{
+	struct net_local *local = (struct net_local *) dev->priv;
+	struct dev_link_t *link = local->link;
+
+	DEBUG(DEBUG_CALLTRACE, "-> wvlan_open(%s)\n", dev->name);
+
+	// TODO: Power up the card here and power down on close?
+	// For now this is done on device init, not on open
+	// Might be better placed here so that some settings can
+	// be made by shutting down the device without removing
+	// the driver (iwconfig).
+	// But this is no real problem for now :-)
+
+	// Start reception and declare the driver ready
+	if (!local->ifb.IFB_CardStat)
+		return -ENODEV;
+	netif_device_attach(dev);
+	netif_start_queue(dev);
+	local->interrupt = 0;
+	link->open++;
+	MOD_INC_USE_COUNT;
+
+	DEBUG(DEBUG_CALLTRACE, "<- wvlan_open()\n");
+	return 0;
+}
+
+static int wvlan_close (struct net_device *dev)
+{
+	struct net_local *local = (struct net_local *) dev->priv;
+	struct dev_link_t *link = local->link;
+
+	// If the device isn't open, then nothing to do
+	if (!link->open)
+	{
+		DEBUG(DEBUG_CALLTRACE, "<> wvlan_close(%s)\n", dev->name);
+		return 0;
+	}
+
+	DEBUG(DEBUG_CALLTRACE, "-> wvlan_close(%s)\n", dev->name);
+
+	// Close the device
+	link->open--;
+	MOD_DEC_USE_COUNT;
+
+	// Check if card is still present
+	if (netif_running(dev))
+	{
+		netif_stop_queue(dev);
+		netif_device_detach(dev);
+		// TODO: Shutdown hardware (see wvlan_open)
+	}
+	else
+		if (link->state & DEV_STALE_CONFIG)
+			mod_timer(&link->release, jiffies + HZ/20);
+
+	DEBUG(DEBUG_CALLTRACE, "<- wvlan_close()\n");
+	return -EINVAL;
+}
+
+
+/********************************************************************
+ * INTERRUPT HANDLER
+ */
+static void wvlan_interrupt (int irq, void *dev_id, struct pt_regs *regs)
+{
+	struct net_device *dev = (struct net_device *) dev_id;
+	struct net_local *local = (struct net_local *) dev->priv;
+	int rc, cnt, ev, len;
+
+	DEBUG(DEBUG_INTERRUPT, "-> wvlan_interrupt(%d)\n", irq);
+
+	// Check device
+	if (!dev)
+	{
+		printk(KERN_WARNING "%s: IRQ %d for unknown device!\n", dev_info, irq);
+		return;
+	}
+
+	// Turn off interrupts
+	rc = hcf_action(&local->ifb, HCF_ACT_INT_OFF);
+	DEBUG(DEBUG_NOISY, "%s: hcf_action(HCF_ACT_INT_OFF) returned 0x%x\n", dev_info, rc);
+	if (test_and_set_bit(0, (void *)&local->interrupt))
+		printk(KERN_WARNING "%s: Warning: IRQ %d Reentering interrupt handler!\n", dev_info, irq);
+
+	// Process pending interrupts.
+	// We continue until hcf_service_nic tells that no received
+	// frames are pending. However we should check to not lock up
+	// here in an endless loop.
+	cnt = 7;
+	while (cnt--)
+	{
+		// Ask NIC why interrupt occured
+		ev = hcf_service_nic(&local->ifb);
+		DEBUG(DEBUG_NOISY, "%s: hcf_service_nic() returned 0x%x RscInd 0x%x\n", dev_info, ev, local->ifb.IFB_PIFRscInd);
+
+		// Transmission completion seem to be also signalled with ev==0
+		// better check that out with RscInd and complete transfer also
+		if (local->ifb.IFB_PIFRscInd && netif_queue_stopped(dev))
+			ev |= HREG_EV_TX;
+
+		// HREG_EV_TICK: WMAC controller auxiliary timer tick
+		if (ev & HREG_EV_TICK)
+		{
+			DEBUG(DEBUG_INFO,"%s: Auxiliary timer tick\n", dev_info);
+		}
+
+		// HREG_EV_RES: WMAC controller H/W error (wait timeout)
+		if (ev & HREG_EV_RES)
+		{
+			// This message seems to occur often on heavy load
+			// but it seem to don't have any effects on transmission
+			// so we simply ignore it.
+			//printk(KERN_WARNING "%s: WMAC H/W error (wait timeout, ignoring)!\n", dev_info);
+		}
+
+		// HREG_EV_INFO_DROP: WMAC did not have sufficient RAM to build unsollicited frame
+		if (ev & HREG_EV_INFO_DROP)
+			printk(KERN_WARNING "%s: WMAC did not have sufficient RAM to build unsollicited frame!\n", dev_info);
+
+		// HREG_EV_INFO: WMAC controller asynchronous information frame
+		if (ev & HREG_EV_INFO)
+		{
+			DEBUG(DEBUG_INFO, "%s: WMAC controller asynchronous information frame\n", dev_info);
+		}
+
+		// HREG_EV_CMD: WMAC controller command completed, status and response available
+		//	unnecessary to handle here, it's handled by polling in HCF
+
+		// HREG_EV_ALLOC: WMAC controller asynchronous part of allocation/reclaim completed
+		//	also unnecessary to handle here, it's handled by polling in HCF
+
+		// HREG_EV_TX_EXC: WMAC controller asynchronous transmission unsuccessful completed
+		if (ev & HREG_EV_TX_EXC)
+		{
+			printk(KERN_WARNING "%s: WMAC controller asynchronous transmission unsuccessful completed\n", dev_info);
+			local->stats.tx_errors++;
+			netif_wake_queue(dev);
+		}
+
+		// HREG_EV_TX: WMAC controller asynchronous transmission successful completed
+		if (ev & HREG_EV_TX)
+		{
+			DEBUG(DEBUG_TXRX, "%s: Transmission successful completed\n", dev_info);
+			local->stats.tx_packets++;
+			netif_wake_queue(dev);
+		}
+
+		// HREG_EV_RX: WMAC controller asynchronous receive frame
+		// Break loop if no frame was received.
+		if (!(ev & HREG_EV_RX))
+			break;
+
+		// If a frame was received, we process it and wrap back
+		// up to the top of the while() loop so that hcf_service_nic()
+		// gets called again after the frame drained from the NIC.
+		// This allows us to find out if yet another frame has
+		// arrived, and also to immediately acknowledge the just-
+		// processed frame so that the NIC's buffer gets de-
+		// allocated right away.
+		len = local->ifb.IFB_RxLen;
+		if (len)
+		{
+			DEBUG(DEBUG_INTERRUPT, "%s: Frame received. rx_len=0x%x\n", dev_info, len);
+			wvlan_rx(dev, len);
+		}
+	}
+	if (!cnt)
+		printk(KERN_WARNING "%s: Maximum interrupt loops reached!\n", dev_info);
+
+	// From now on, we don't care if we re-enter the interrupt handler
+	local->interrupt = 0;
+
+	// Turn back interrupts on (unlock)
+	rc = hcf_action(&local->ifb, HCF_ACT_INT_ON);
+	DEBUG(DEBUG_NOISY, "%s: hcf_action(HCF_ACT_INT_ON) returned 0x%x\n", dev_info, rc);
+
+	DEBUG(DEBUG_INTERRUPT, "<- wvlan_interrupt()\n");
+}
+
+
+/********************************************************************
+ * PCMCIA CONFIG / RELEASE
+ */
+#define CS_CHECK(fn, args...) while ((last_ret=CardServices(last_fn=(fn),args))!=0) goto cs_failed
+#define CFG_CHECK(fn, args...) if (CardServices(fn, args) != 0) goto next_entry
+static int wvlan_config (dev_link_t *link)
+{
+	client_handle_t handle = link->handle;
+	tuple_t tuple;
+	cisparse_t parse;
+	struct net_device *dev = (struct net_device *) link->priv;
+	struct net_local *local = (struct net_local *) dev->priv;
+	int last_fn, last_ret;
+	u_char buf[64];
+	win_req_t req;
+	memreq_t map;
+	int rc, i;
+
+	DEBUG(DEBUG_CALLTRACE, "-> wvlan_config(0x%p)\n", link);
+
+	// This reads the card's CONFIG tuple to find its configuration registers.
+	tuple.DesiredTuple = CISTPL_CONFIG;
+	tuple.Attributes = 0;
+	tuple.TupleData = buf;
+	tuple.TupleDataMax = sizeof(buf);
+	tuple.TupleOffset = 0;
+	CS_CHECK(GetFirstTuple, handle, &tuple);
+	CS_CHECK(GetTupleData, handle, &tuple);
+	CS_CHECK(ParseTuple, handle, &tuple, &parse);
+	link->conf.ConfigBase = parse.config.base;
+	link->conf.Present = parse.config.rmask[0];
+
+	// Configure card
+	link->state |= DEV_CONFIG;
+
+	// In this loop, we scan the CIS for configuration table entries,
+	// each of which describes a valid card configuration, including
+	// voltage, IO window, memory window, and interrupt settings.
+	// We make no assumptions about the card to be configured: we use
+	// just the information available in the CIS.  In an ideal world,
+	// this would work for any PCMCIA card, but it requires a complete
+	// and accurate CIS.  In practice, a driver usually "knows" most of
+	// these things without consulting the CIS, and most client drivers
+	// will only use the CIS to fill in implementation-defined details.
+	tuple.DesiredTuple = CISTPL_CFTABLE_ENTRY;
+	CS_CHECK(GetFirstTuple, handle, &tuple);
+	while (1) {
+		cistpl_cftable_entry_t dflt = { 0 };
+		cistpl_cftable_entry_t *cfg = &(parse.cftable_entry);
+		CFG_CHECK(GetTupleData, handle, &tuple);
+		CFG_CHECK(ParseTuple, handle, &tuple, &parse);
+
+		if (cfg->index == 0) goto next_entry;
+		link->conf.ConfigIndex = cfg->index;
+
+		// Does this card need audio output?
+		if (cfg->flags & CISTPL_CFTABLE_AUDIO)
+		{
+			link->conf.Attributes |= CONF_ENABLE_SPKR;
+			link->conf.Status = CCSR_AUDIO_ENA;
+		}
+	
+		// Use power settings for Vcc and Vpp if present
+		// Note that the CIS values need to be rescaled
+		if (cfg->vcc.present & (1<<CISTPL_POWER_VNOM))
+			link->conf.Vcc = cfg->vcc.param[CISTPL_POWER_VNOM]/10000;
+		else if (dflt.vcc.present & (1<<CISTPL_POWER_VNOM))
+			link->conf.Vcc = dflt.vcc.param[CISTPL_POWER_VNOM]/10000;
+
+		if (cfg->vpp1.present & (1<<CISTPL_POWER_VNOM))
+			link->conf.Vpp1 = link->conf.Vpp2 = cfg->vpp1.param[CISTPL_POWER_VNOM]/10000;
+		else if (dflt.vpp1.present & (1<<CISTPL_POWER_VNOM))
+			link->conf.Vpp1 = link->conf.Vpp2 = dflt.vpp1.param[CISTPL_POWER_VNOM]/10000;
+
+		// Do we need to allocate an interrupt?
+		if (cfg->irq.IRQInfo1 || dflt.irq.IRQInfo1)
+			link->conf.Attributes |= CONF_ENABLE_IRQ;
+
+		// IO window settings
+		link->io.NumPorts1 = link->io.NumPorts2 = 0;
+		if ((cfg->io.nwin > 0) || (dflt.io.nwin > 0)) {
+			cistpl_io_t *io = (cfg->io.nwin) ? &cfg->io : &dflt.io;
+			link->io.Attributes1 = IO_DATA_PATH_WIDTH_AUTO;
+			if (!(io->flags & CISTPL_IO_8BIT))
+				link->io.Attributes1 = IO_DATA_PATH_WIDTH_16;
+			if (!(io->flags & CISTPL_IO_16BIT))
+				link->io.Attributes1 = IO_DATA_PATH_WIDTH_8;
+			link->io.BasePort1 = io->win[0].base;
+			link->io.NumPorts1 = io->win[0].len;
+			if (io->nwin > 1) {
+				link->io.Attributes2 = link->io.Attributes1;
+				link->io.BasePort2 = io->win[1].base;
+				link->io.NumPorts2 = io->win[1].len;
+			}
+		}
+
+		// This reserves IO space but doesn't actually enable it
+		CFG_CHECK(RequestIO, link->handle, &link->io);
+
+		// Now set up a common memory window, if needed.  There is room
+		// in the dev_link_t structure for one memory window handle,
+		// but if the base addresses need to be saved, or if multiple
+		// windows are needed, the info should go in the private data
+		// structure for this device.
+		// Note that the memory window base is a physical address, and
+		// needs to be mapped to virtual space with ioremap() before it
+		// is used.
+		if ((cfg->mem.nwin > 0) || (dflt.mem.nwin > 0)) {
+			cistpl_mem_t *mem = (cfg->mem.nwin) ? &cfg->mem : &dflt.mem;
+			req.Attributes = WIN_DATA_WIDTH_16|WIN_MEMORY_TYPE_CM;
+			req.Base = mem->win[0].host_addr;
+			req.Size = mem->win[0].len;
+			req.AccessSpeed = 0;
+			link->win = (window_handle_t)link->handle;
+			CFG_CHECK(RequestWindow, &link->win, &req);
+			map.Page = 0; map.CardOffset = mem->win[0].card_addr;
+			CFG_CHECK(MapMemPage, link->win, &map);
+		}
+
+		// If we got this far, we're cool!
+		break;
+
+next_entry:
+		if (cfg->flags & CISTPL_CFTABLE_DEFAULT)
+			dflt = *cfg;
+		CS_CHECK(GetNextTuple, handle, &tuple);
+	}
+
+	// Allocate an interrupt line.  Note that this does not assign a
+	// handler to the interrupt, unless the 'Handler' member of the
+	// irq structure is initialized.
+	if (link->conf.Attributes & CONF_ENABLE_IRQ)
+	{
+		link->irq.Attributes = IRQ_TYPE_EXCLUSIVE | IRQ_HANDLE_PRESENT;
+		link->irq.IRQInfo1 = IRQ_INFO2_VALID | IRQ_LEVEL_ID;
+		if (irq_list[0] == -1)
+			link->irq.IRQInfo2 = irq_mask;
+		else
+			for (i=0; i<4; i++)
+				link->irq.IRQInfo2 |= 1 << irq_list[i];
+		link->irq.Handler = wvlan_interrupt;
+		link->irq.Instance = dev;
+		CS_CHECK(RequestIRQ, link->handle, &link->irq);
+	}
+
+	// This actually configures the PCMCIA socket -- setting up
+	// the I/O windows and the interrupt mapping, and putting the
+	// card and host interface into "Memory and IO" mode.
+	CS_CHECK(RequestConfiguration, link->handle, &link->conf);
+
+	// Feed the netdevice with this info
+	dev->irq = link->irq.AssignedIRQ;
+	dev->base_addr = link->io.BasePort1;
+	netif_start_queue(dev);
+
+	// Report what we've done
+	printk(KERN_INFO "%s: index 0x%02x: Vcc %d.%d", dev_info, link->conf.ConfigIndex, link->conf.Vcc/10, link->conf.Vcc%10);
+	if (link->conf.Vpp1)
+		printk(", Vpp %d.%d", link->conf.Vpp1/10, link->conf.Vpp1%10);
+	if (link->conf.Attributes & CONF_ENABLE_IRQ)
+		printk(", irq %d", link->irq.AssignedIRQ);
+	if (link->io.NumPorts1)
+		printk(", io 0x%04x-0x%04x", link->io.BasePort1, link->io.BasePort1+link->io.NumPorts1-1);
+	if (link->io.NumPorts2)
+		printk(" & 0x%04x-0x%04x", link->io.BasePort2, link->io.BasePort2+link->io.NumPorts2-1);
+	if (link->win)
+		printk(", mem 0x%06lx-0x%06lx", req.Base, req.Base+req.Size-1);
+	printk("\n");
+
+	link->state &= ~DEV_CONFIG_PENDING;
+
+	// Make netdevice's name (if not ethX) and remember the device
+	// Not very efficient here, this should go somewhere into dev_list,
+	// but it works for now (taken from register_netdevice in kernel)
+	if (!eth)
+	{
+		for (i=0; i<MAX_WVLAN_CARDS; ++i)
+			if (!wvlandev_index[i])
+			{
+				sprintf(local->node.dev_name, "wvlan%d", i);
+				wvlandev_index[i] = dev;
+				break;
+			}
+	}
+
+	// Register the netdevice
+	rc = register_netdev(dev);
+	if (rc)
+	{
+		printk(KERN_WARNING "%s: register_netdev() failed!\n", dev_info);
+		wvlan_release((u_long)link);
+		return 0;
+	}
+	printk(KERN_INFO "%s: Registered netdevice %s\n", dev_info, dev->name);
+
+	link->dev = &local->node;
+
+	// Success!
+	DEBUG(DEBUG_CALLTRACE, "<- wvlan_config()\n");
+	return 1;
+
+cs_failed:
+	cs_error(link->handle, last_fn, last_ret);
+	wvlan_release((u_long)link);
+	DEBUG(DEBUG_CALLTRACE, "<- wvlan_config()\n");
+	return 0;
+}
+
+static void wvlan_release (u_long arg)
+{
+	dev_link_t *link = (dev_link_t *) arg;
+	struct net_device *dev = (struct net_device *) link->priv;
+	int i;
+
+	DEBUG(DEBUG_CALLTRACE, "-> wvlan_release(0x%p)\n", link);
+
+	// If the device is currently in use, we won't release
+	// until it's actually closed.
+	if (link->open)
+	{
+		DEBUG(DEBUG_INFO, "%s: wvlan_release: release postponed, %s still locked\n", dev_info, link->dev->dev_name);
+		link->state |= DEV_STALE_CONFIG;
+		return;
+	}
+
+	// Power down
+	wvlan_hw_shutdown(dev);
+
+	// Remove our device from index (only devices named wvlanX)
+	for (i=0; i<MAX_WVLAN_CARDS; ++i)
+		if (wvlandev_index[i] == dev)
+		{
+			wvlandev_index[i] = NULL;
+			break;
+		}
+
+	if (link->win)
+		CardServices(ReleaseWindow, link->win);
+	CardServices(ReleaseConfiguration, link->handle);
+	if (link->io.NumPorts1)
+		CardServices(ReleaseIO, link->handle, &link->io);
+	if (link->irq.AssignedIRQ)
+		CardServices(ReleaseIRQ, link->handle, &link->irq);
+
+	link->state &= ~DEV_CONFIG;
+
+	DEBUG(DEBUG_CALLTRACE, "<- wvlan_release()\n");
+}
+
+
+/********************************************************************
+ * PCMCIA ATTACH / DETACH
+ */
+static dev_link_t *wvlan_attach (void)
+{
+	dev_link_t *link;
+	struct net_device *dev;
+	struct net_local *local;
+	int rc;
+	client_reg_t client_reg;
+
+	DEBUG(DEBUG_CALLTRACE, "-> wvlan_attach()\n");
+
+	// Flush stale links
+	for (link=dev_list; link; link=link->next)
+		if (link->state & DEV_STALE_LINK)
+			wvlan_detach(link);
+
+	// Initialize the dev_link_t structure
+	link = kmalloc(sizeof(struct dev_link_t), GFP_KERNEL);
+	memset(link, 0, sizeof(struct dev_link_t));
+	link->release.function = &wvlan_release;
+	link->release.data = (u_long) link;
+	link->conf.Vcc = 50;
+	link->conf.IntType = INT_MEMORY_AND_IO;
+
+	// Allocate space for netdevice (private data of link)
+	dev = kmalloc(sizeof(struct net_device), GFP_KERNEL);
+	memset(dev, 0, sizeof(struct net_device));
+	link->priv = dev;
+
+	// Allocate space for netdevice priv (private data of netdevice)
+	local = kmalloc(sizeof(struct net_local), GFP_KERNEL);
+	memset(local, 0, sizeof(struct net_local));
+	dev->priv = local;
+
+	// Initialize specific data
+	local->link = link;
+	local->dev = dev;
+	spin_lock_init(&local->slock);
+
+	// Standard setup for generic data
+	ether_setup(dev);
+
+	// kernel callbacks
+	dev->open = wvlan_open;
+	dev->stop = wvlan_close;
+	dev->hard_start_xmit = wvlan_tx;
+	dev->get_stats = wvlan_get_stats;
+#ifdef WIRELESS_EXT
+	dev->do_ioctl = wvlan_ioctl;
+	dev->get_wireless_stats = wvlan_get_wireless_stats;
+#endif
+	dev->change_mtu = wvlan_change_mtu;
+	dev->set_multicast_list = wvlan_set_multicast_list;
+//	dev->set_mac_address = wvlan_set_mac_address;
+#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,3,42))
+	dev->tx_timeout = &wvlan_watchdog;
+	dev->watchdog_timeo = TX_TIMEOUT;
+#endif
+
+	// Other netdevice data
+	dev->name = local->node.dev_name;
+	dev->mtu = mtu;
+	netif_stop_queue(dev);
+
+	// Register with CardServices
+	link->next = dev_list;
+	dev_list = link;
+	client_reg.dev_info = &dev_info;
+	client_reg.Attributes = INFO_IO_CLIENT;
+	client_reg.EventMask =	CS_EVENT_REGISTRATION_COMPLETE |
+				CS_EVENT_CARD_INSERTION | CS_EVENT_CARD_REMOVAL |
+				CS_EVENT_RESET_PHYSICAL | CS_EVENT_CARD_RESET |
+				CS_EVENT_PM_SUSPEND | CS_EVENT_PM_RESUME;
+	client_reg.event_handler = &wvlan_event;
+	client_reg.Version = 0x0210;
+	client_reg.event_callback_args.client_data = link;
+
+	rc = CardServices(RegisterClient, &link->handle, &client_reg);
+	if (rc)
+	{
+		cs_error(link->handle, RegisterClient, rc);
+		wvlan_detach(link);
+		return NULL;
+	}
+
+	DEBUG(DEBUG_CALLTRACE, "<- wvlan_attach()\n");
+	return link;
+}
+
+static void wvlan_detach (dev_link_t *link)
+{
+	dev_link_t **linkp;
+
+	DEBUG(DEBUG_CALLTRACE, "-> wvlan_detach(0x%p)\n", link);
+
+	// Locate device structure
+	for (linkp=&dev_list; *linkp; linkp=&(*linkp)->next)
+		if (*linkp == link)
+			break;
+	if (!*linkp)
+	{
+		printk(KERN_WARNING "%s: Attempt to detach non-existing PCMCIA client!\n", dev_info);
+		return;
+	}
+
+	// If the device is currently configured and active, we won't
+	// actually delete it yet. Instead, it is marked so that when the
+	// release() function is called, that will trigger a proper
+	// detach()
+	del_timer(&link->release);
+	if (link->state & DEV_CONFIG)
+	{
+		DEBUG(DEBUG_INFO, "%s: wvlan_detach: detach postponed, %s still locked\n", dev_info, link->dev->dev_name);
+		wvlan_release((u_long)link);
+		if (link->state & DEV_STALE_CONFIG)
+		{
+			link->state |= DEV_STALE_LINK;
+			return;
+		}
+	}
+
+	// Break the line with CardServices
+	if (link->handle)
+		CardServices(DeregisterClient, link->handle);
+
+	// Unlink device structure, free pieces
+	*linkp = link->next;
+	if (link->priv)
+	{
+		struct net_device *dev = (struct net_device *) link->priv;
+		if (link->dev)
+		{
+			unregister_netdev(dev);
+			DEBUG(DEBUG_INFO, "%s: Netdevice unregistered\n", dev_info);
+		}
+		if (dev->priv)
+			kfree_s(dev->priv, sizeof(struct net_local));
+		kfree_s(link->priv, sizeof(struct net_device));
+	}
+	kfree_s(link, sizeof(struct dev_link_t));
+
+	DEBUG(DEBUG_CALLTRACE, "<- wvlan_detach()\n");
+}
+
+
+/********************************************************************
+ * PCMCIA EVENT HANDLER
+ */
+static int wvlan_event (event_t event, int priority, event_callback_args_t *args)
+{
+	dev_link_t *link = (dev_link_t *) args->client_data;
+	struct net_device *dev = (struct net_device *) link->priv;
+
+	DEBUG(DEBUG_CALLTRACE, "-> wvlan_event(%s, %d, 0x%p)\n",
+		((event==CS_EVENT_REGISTRATION_COMPLETE) ? "registration complete" :
+		((event==CS_EVENT_CARD_INSERTION) ? "card insertion" :
+		((event==CS_EVENT_CARD_REMOVAL) ? "card removal" :
+		((event==CS_EVENT_RESET_PHYSICAL) ? "physical physical" :
+		((event==CS_EVENT_CARD_RESET) ? "card reset" :
+		((event==CS_EVENT_PM_SUSPEND) ? "pm suspend" :
+		((event==CS_EVENT_PM_RESUME) ? "pm resume" :
+		"unknown"))))))), priority, args);
+
+	switch (event)
+	{
+		case CS_EVENT_CARD_INSERTION:
+			link->state |= DEV_PRESENT | DEV_CONFIG_PENDING;
+			if (!wvlan_config(link) || wvlan_hw_config(dev))
+				dev->irq = 0;
+			break;
+
+		case CS_EVENT_CARD_REMOVAL:
+			link->state &= ~DEV_PRESENT;
+			if (link->state & DEV_CONFIG)
+			{
+				netif_stop_queue(dev);
+				netif_device_detach(dev);
+				mod_timer(&link->release, jiffies + HZ/20);
+			}
+			break;
+
+		case CS_EVENT_PM_SUSPEND:
+			link->state |= DEV_SUSPEND;
+		case CS_EVENT_RESET_PHYSICAL:
+			if (link->state & DEV_CONFIG)
+			{
+				if (link->open)
+				{
+					netif_stop_queue(dev);
+					netif_device_detach(dev);
+				}
+				CardServices(ReleaseConfiguration, link->handle);
+			}
+			break;
+
+		case CS_EVENT_PM_RESUME:
+			link->state &= ~DEV_SUSPEND;
+			// Fall through
+		case CS_EVENT_CARD_RESET:
+			if (link->state & DEV_CONFIG)
+			{
+				CardServices(RequestConfiguration, link->handle, &link->conf);
+				if (link->open)
+				{
+					wvlan_hw_shutdown(dev);
+					wvlan_hw_config(dev);
+					netif_device_attach(dev);
+					netif_start_queue(dev);
+				}
+			}
+			break;
+	}
+
+	DEBUG(DEBUG_CALLTRACE, "<- wvlan_event()\n");
+	return 0;
+}
+
+
+/********************************************************************
+ * MODULE INSERTION / REMOVAL
+ */
+extern int init_module (void)
+{
+	servinfo_t serv;
+
+	DEBUG(DEBUG_CALLTRACE, "-> init_module()\n");
+
+	printk(KERN_INFO "%s: WaveLAN/IEEE PCMCIA driver v%s\n", dev_info, version);
+	printk(KERN_INFO "%s: (c) Andreas Neuhaus <andy@fasta.fh-dortmund.de>\n", dev_info);
+
+	// Check CardServices release
+	CardServices(GetCardServicesInfo, &serv);
+	if (serv.Revision != CS_RELEASE_CODE)
+	{
+		printk(KERN_WARNING "%s: CardServices release does not match!\n", dev_info);
+		return -1;
+	}
+
+	// Register PCMCIA driver
+	register_pcmcia_driver(&dev_info, &wvlan_attach, &wvlan_detach);
+
+	DEBUG(DEBUG_CALLTRACE, "<- init_module()\n");
+	return 0;
+}
+
+extern void cleanup_module (void)
+{
+	DEBUG(DEBUG_CALLTRACE, "-> cleanup_module()\n");
+
+	// Unregister PCMCIA driver
+	unregister_pcmcia_driver(&dev_info);
+
+	// Remove leftover devices
+	if (dev_list)
+		DEBUG(DEBUG_INFO, "%s: Removing leftover devices!\n", dev_info);
+	while (dev_list)
+	{
+		if (dev_list->state & DEV_CONFIG)
+			wvlan_release((u_long)dev_list);
+		wvlan_detach(dev_list);
+	}
+
+	printk(KERN_INFO "%s: Driver unloaded\n", dev_info);
+	DEBUG(DEBUG_CALLTRACE, "<- cleanup_module()\n");
+}
+
+
+/********************************************************************
+ * EOF
+ */
Index: oldkernel/linux/pcmcia-cs-3.1.15/wireless/wvlan_hcf.c
diff -u /dev/null linux/pcmcia-cs-3.1.15/wireless/wvlan_hcf.c:1.1
--- /dev/null	Mon Jul 31 21:15:12 2000
+++ linux/pcmcia-cs-3.1.15/wireless/wvlan_hcf.c	Fri Jul  7 16:34:59 2000
@@ -0,0 +1,1978 @@
+/* This file is part of the Hardware Control Functions Light (HCF-light) library
+   to control the Lucent Technologies WaveLAN/IEEE Network I/F Card.
+   The HCF is the implementation of the Wireless Connection I/F (WCI).
+   
+   The HCF-light files are a subset of the HCF files. The complete set offers a
+   number of additional facilities, e.g. firmware download, Etherner-II encapsulation,
+   additional diagnostic facilities, ASSERT logic to support debugging, 802.11 support,
+   Configuration Management.
+   This complete set is explicitely not in the Public Domain but can be made 
+   available under certain restriction. (see the pointer below for support)
+   
+   The HCF-light files are 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. 
+   
+   At the time of this writing, you can request for support at:
+   betasupport@wavelan.com
+   
+   Documentation is expected to be available in the week of 8 Februari 1999
+
+*/
+
+
+/**************************************************************************************************************
+*
+* FILE   :	HCF.CPP *************** 2.0 ***********************************************************************
+*
+* DATE    :	2000/01/06 23:30:52   1.2
+*
+* AUTHOR :	Nico Valster
+*
+* DESC   :	HCF Routines hcf_action, hcf_connect, hcf_disable
+*						 hcf_disconnect, hcf_download, hcf_enable, hcf_generate_int
+*						 hcf_get_info, hcf_get_data, hcf_service_nic
+*						 hcf_put_info, hcf_put_data, hcf_register_mailbox, hcf_send,
+*						 hcf_send_diag_msg
+*			Local Support Routines for above procedures
+*
+*			Customizable via HCFCFG.H, which is included by HCF.H
+*
+***************************************************************************************************************
+* COPYRIGHT (c) 1995			 by AT&T.	 				All Rights Reserved
+* COPYRIGHT (c) 1996, 1997, 1998 by Lucent Technologies.	All Rights Reserved
+*
+* At the sole discretion of Lucent Technologies parts of this source may be extracted
+* and placed in the Public Domain under the GPL.
+* This extraction takes place by means of an AWK-script acting on embedded tags.
+* The AWK script is:
+ *	BEGIN { c = 0 }
+ *	{ if ( c == 0 ) i = 1}			#if in @HCF_L>..@HCF_L< block, skip
+ *	{ if (name != FILENAME ) name = FILENAME }
+ *	
+ *	{ if ( i && c == 0  ) { print ; hcf_l_cnt++ } }
+ *	#{ if ( i ) { print ; hcf_l_cnt++ } }
+ *	#{if ( c == 0 ) { printf("N%d", c) ; hcf_l_cnt++ } }
+ *	#{if ( c == 1 ) { printf("E%d", c) ; hcf_l_cnt++ } }
+ *	
+ *	#END { printf("%s:: HCF lines: %d, HCF_Light lines: %d", name, NR, hcf_l_cnt ) }
+*
+* and is not in any sense derived from the extracted source. 
+*
+**************************************************************************************************************/
+
+
+
+
+
+/****************************************************************************
+wvlan_hcf.c,v
+Revision 1.2  2000/01/06 23:30:52  root
+*** empty log message ***
+
+ * 
+ *    Rev 1.0   02 Feb 1999 14:32:28   NVALST
+ * Initial revision.
+Revision 1.3  1999/02/01 22:58:40  nico
+*** empty log message ***
+ * 
+ *    Rev 2.12   29 Jan 1999 10:48:40   NVALST
+ * 
+ *    Rev 1.108   28 Jan 1999 14:43:18   NVALST
+ * intermediate, once more correction of loop in hcf_service_nic + download
+ * passed to Marc
+ * 
+****************************************************************************/
+
+/**************************************************************************************************************
+*
+* CHANGE HISTORY
+*
+
+  960702 - NV
+	Original Entry - derived from WaveLAN-I HCF 2.12
+
+
+*
+* ToDo
+*
+ 1:	For all/most functions, update "MSF-accessible fields of Result Block:" entry
+ 2: Use the "numbered comments" in the NARRATIVE consistently, i.e. hcf_put_info
+ 3: hcf_put_data, hcf_send, hcf_send_diag_msg
+	once the dust is settled whether hcf_put_data or hcf_send is the appropriate place is to specify port,
+	it can be considered whether part of the hcf_send_diag_msg and hcf_send can be isolated in a common
+	routine.
+ 4:	hcf_send_diag_msg:
+  	- what are the appropriate return values
+	- once the dust is settled whether type should or shouldn't be parameter of hcf_send_diag_msg, it can
+	  be decided whether the HFX_TX_CNTL_ABS update at each call is needed
+ 5:	hcf_service_nic, hcf_send, hcf_send_diag_msg etc
+ 	check for a CONSISTENT strategy for the testing of IFB_CardStat, for presence, enabled, ports
+ 6:	Decide on the relative merits of HCF_ACT_ASSERT_OFF/_ON versus CFG_REG_MSF_ASSERT
+	
+
+*
+* Implementation Notes
+*
+ -	C++ style cast is not used to keep DA-C happy
+ -	a leading marker of //! is used. The purpose of such a sequence is to help the
+	(maintenance) programmer to understand the flow
+ 	An example in hcf_action( HCF_ACT_802_3 ) is
+	//!		ifbp->IFB_RxFence = 0;
+	which is superfluous because IFB_RxFence gets set at every hcf_service_nic but
+	it shows to the (maintenance) programmer it is an intentional omission at
+	the place where someone could consider it most appropriate at first glance
+ -	using near pointers in a model where ss!=ds is an invitation for disaster, so be aware of how you specify
+ 	your model and how you define variables which are used at interrupt time
+ -	Once the comment "the value of -1 for parameter len is meaningless but it guarantees that the next call
+ 	to bap_ini is interpreted as an initial call, causing the BAP to be really initialized." was considered
+ 	useful information. Does this trick still lingers somewhere;?
+ -	remember that sign extension on 32 bit platforms may cause problems unless code is carefully constructed,
+ 	e.g. use "(hcf_16)~foo" rather than "~foo"
+
+	
+*
+* Miscellaneous Notes
+*
+ -	AccessPoint performance could be improved by adding a hcf_send_pif_msg equivalent of hcf_send_diag_msg
+
+
+*************************************************************************************************************/
+
+#include "wvlan_hcf.h"				// HCF and MSF common include file
+#include "wvlan_hcfdef.h"			// HCF specific include file
+
+/*************************************************************************************************************/
+/***************************************  PROTOTYPES  ********************************************************/
+/*************************************************************************************************************/
+// moving these prototypes to HCFDEF.H turned out to be less attractive in the HCF-light generation
+STATIC int			aux_cntl( IFBP ifbp, hcf_16 cmd );
+STATIC int			calibrate( IFBP ifbp );
+STATIC int			cmd_wait( IFBP ifbp, int cmd_code, int par_0 );
+STATIC void			enable_int(IFBP ifbp, int event );
+       int			hcf_initialize( IFBP ifbp );
+STATIC int			ini_hermes( IFBP ifbp );
+STATIC void	 		isr_info( IFBP ifbp );
+STATIC int			put_info( IFBP ifbp, LTVP ltvp	);
+STATIC hcf_16		alloc( IFBP ifbp, int len );
+
+
+/**************************************************************************************************************
+******************************* D A T A    D E F I N I T I O N S **********************************************
+**************************************************************************************************************/
+
+STATIC hcf_8 BASED hcf_rev[] = "\nHCF1.2\n";
+
+/* Note that the "BASED" construction (supposedly) only amounts to something in the small memory model.
+ * In that case CS and DS are equal, so we can ignore the consequences of casting the BASED cfg_drv_...
+ * structure to hcf_16
+ * Note that the whole BASED riggamarole is needlessly complicated because both the Microsoft Compiler and
+ * Linker are unnecessary restrictive in what far pointer manipulation they allow
+ */
+
+
+/* 
+	The below table accessed via a computed index was the original implementation for hcf_get_info with 
+	CFG_DRV_IDENTITY, CFG_DRV_SUP_RANGE, CFG_DRV_ACT_RANGE_PRI, CFG_DRV_ACT_RANGE_STA, CFG_DRV_ACT_RANGE_HSI
+	as type. However it was reported that the 68K compiler for MAC OS is unable to initialize pointers.
+	Accepting this story at face value, the HCF is coded around this problem by implementing a direct access..
+	To save part of the invested effort, the original table is kept as comment.
+
+STATIC LTV_STRCT*   BASED xxxx[ ] = {
+	(LTV_STRCT*)&cfg_drv_identity,      //CFG_DRV_IDENTITY              0x0826
+	(LTV_STRCT*)&cfg_drv_sup_range,     //CFG_DRV_SUP_RANGE             0x0827
+	(LTV_STRCT*)&cfg_drv_act_range_pri, //CFG_DRV_ACT_RANGE_PRI         0x0828
+	(LTV_STRCT*)&cfg_drv_act_range_sta  //CFG_DRV_ACT_RANGE_STA         0x0829
+	(LTV_STRCT*)&cfg_drv_act_range_hsi	//CFG_DRV_ACT_RANGE_HSI			0x082A
+  };
+*/
+
+
+/**************************************************************************************************************
+************************** T O P   L E V E L   H C F   R O U T I N E S ****************************************
+**************************************************************************************************************/
+
+
+/*******************************************************************************************************************
+
+
+.MODULE			hcf_action
+.LIBRARY 		HCF
+.TYPE 			function
+.SYSTEM			msdos
+.SYSTEM			NW4
+.APPLICATION	Card configuration
+.DESCRIPTION	Changes the run-time Card behavior
+
+.ARGUMENTS
+  int hcf_action(IFBP ifbp, hcf_action_cmd action )
+.RETURNS
+  int
+
+  MSF-accessible fields of Result Block: -
+
+.NARRATIVE
+
+ Name:	hcf_action
+
+ Summary: Changes the run-time Card behavior
+
+ Parameters:
+  ifbp	address of the Interface Block
+
+  action	number identifying the type of change
+
+  o HCF_ACT_INT_ON		enable interrupt generation by WaveLAN NIC
+  o HCF_ACT_INT_OFF		disable interrupt generation by WaveLAN NIC
+  o HCF_ACT_CARD_IN		MSF reported Card insertion
+  o HCF_ACT_CARD_OUT	MSF reported Card removal
+
+ Returns:
+  o	HCF_ACT_INT_OFF
+		0: no interrupt pending
+		1: interrupt pending
+  o	all other
+		0 (((however, see the special treatment for HCF_ACT_INT_ON)))
+
+ Remarks:
+  o	HCF_ACT_INT_OFF/HCF_ACT_INT_ON codes may be nested but must be balanced. The INT_OFF/INT_ON housekeeping
+	is initialized by hcf_connect with a call of hcf_action with INT_OFF, causing the interrupt generation
+	mechanism to be disabled at first. This suits MSF implementation based on a polling strategy. An MSFT
+	based on a interrupt strategy must call hcf_action with INT_ON in its initialization logic.
+
+  o To prevent I/O while the I/O space is no longer owned by the HCF, due to a card swap, no I/O is allowed
+	when the CARD_STAT_PRESENT bit of IFB_CardStat is off.
+
+.DIAGRAM
+ 2: IFB_IntOffCnt is used to balance the INT_OFF and INT_ON calls.
+ 4: Disabling of the interrupts is simply achieved by writing a zero to the Hermes IntEn register
+ 5: To be able to return the information to the MSF whether an interrupt is actually pending, the Hermes
+	EvStat register is sampled and compared against the current IFB_IntEnMask value
+ 6:	Originally the construction "if ( ifbp->IFB_IntOffCnt-- <= 1 )" was used in stead of
+ 	"if ( --ifbp->IFB_IntOffCnt == 0 )". This serviced to get around the unsigned logic, but as additional
+ 	"benefit" it seemed the most optimal "fail safe" code (in the sense of shortest/quickest path in error
+ 	free flows, fail safe in the sense of too many INT_ON invocations compared to INT_OFF). However when a
+ 	real life MSF programmer ran to a MSF sequence problem, exactly causing that problem, he was annoyed
+ 	with this fail safe code. As a consequence it is taken out. As a side-effect of this unhappy MSF programmer
+ 	adventures to find his problem, the return status is defined to reflect the IFBIntOffCnt, Note that this 
+ 	is solely intended for aid debugging, no MSF logic should depend on this feature, No garuantees for the 
+ 	future are given.
+ 	Enabling of the interrupts is achieved by writing the contents of IFB_IntEnMask to the Hermes IntEn
+ 	register.
+ 7:	Since the card is present again, it must be re-initialized. Since this may be another card we may as well 
+ 	clear all bits in IFB_CardStat and set only the "present" bit. 
+ 	The first call to hcf_enable will restore the contents of HREG_INT_EN register taking the 
+ 	HCF_ACT_IN_ON/OFF history in account.
+ 9:	The MSF must call hcf_action with HCF_ACT_CARD_OUT when the MSF detects a card removal (e.g. when the MSF
+	is notified by the CAD). As a minimum, the "present" bit in IFB_CardStat must be reset, however since
+	the card insertion will clear all other bits, the simplest solution is to clear IFB_CardStat here as well.
+	As a result of the resetting of the CARD_STAT_PRESENT bit, no hcf-function except hcf_action with
+	HCF_ACT_CARD_IN results in card I/O anymore. However hcf_functions may still perform their other
+	activities, e.g. hcf_get_info_mb still supplies a MBIB if one is available.
+	As a result of the resetting of the CARD_STAT_INI bit, the call to hcf_initialize by hcf_action with
+	HCF_ACT_CARD_IN results in re-initialization of the NIC.
+.ENDOC				END DOCUMENTATION
+
+
+**************************************************************************************************************/
+int hcf_action( IFBP ifbp, 					//address of the Interface Block
+				hcf_action_cmd action		/*number identifying the type of change
+											*/
+ 				) {
+
+int		rc = HCF_SUCCESS;
+//int		i, j;
+//hcf_16	scratch[2];
+
+	
+
+	switch (action) {
+	  case HCF_ACT_INT_OFF:						// Disable Interrupt generation
+		ifbp->IFB_IntOffCnt++;																			/* 2 */
+		if ( ifbp->IFB_CardStat & CARD_STAT_PRESENT ) {
+			OUT_PORT_WORD( ifbp->IFB_IOBase + HREG_INT_EN, 0 ); 										/* 4 */
+			if ( IN_PORT_WORD( ifbp->IFB_IOBase + HREG_EV_STAT ) & ifbp->IFB_IntEnMask ) {				/* 5 */
+				rc = HCF_INT_PENDING;
+			}
+		}
+		break;
+		
+	  case HCF_ACT_INT_ON:						// Enable Interrupt generation
+		if ( --ifbp->IFB_IntOffCnt == 0 ) {																/* 6 */
+			if ( ifbp->IFB_CardStat & CARD_STAT_PRESENT ) {
+				OUT_PORT_WORD( ifbp->IFB_IOBase + HREG_INT_EN, ifbp->IFB_IntEnMask );
+			}
+		}
+		rc = ifbp->IFB_IntOffCnt;
+		break;
+		
+	  case  HCF_ACT_CARD_IN:					// MSF reported Card insertion							/* 7 */
+		ifbp->IFB_CardStat = CARD_STAT_PRESENT;
+		hcf_initialize ( ifbp );
+
+		if ( ifbp->IFB_CardStat & CARD_STAT_ENABLED ) {
+		  (void)hcf_enable( ifbp, 0 );
+		}
+		break;
+	
+	  case 	HCF_ACT_CARD_OUT:  					// MSF reported Card removal							/* 9 */
+		ifbp->IFB_CardStat = 0;
+		break;
+		
+		
+	  case 	HCF_ACT_TALLIES:					// Hermes Inquire Tallies (F100) command				/*12 */
+		action = (hcf_action_cmd)(action - HCF_ACT_TALLIES + CFG_TALLIES);
+		if ( ifbp->IFB_CardStat & CARD_STAT_ENABLED ) {
+		  rc = cmd_wait( ifbp, HCMD_INQUIRE, action );
+		}  		
+		break;
+		
+		
+		
+
+	  default:
+		break;
+	}
+	return rc;
+}/* hcf_action */
+
+
+
+/*******************************************************************************************************************
+
+.MODULE			hcf_connect
+.LIBRARY 		HCF
+.TYPE 			function
+.SYSTEM			msdos
+.SYSTEM			unix
+.SYSTEM			NW4
+.APPLICATION	Card Initialization Group for WaveLAN based drivers and utilities
+.DESCRIPTION	Initializes Card and HCF housekeeping
+
+.ARGUMENTS
+  void hcf_connect( IFBP ifbp, hcf_io io_base )
+
+.RETURNS
+	n.a.
+
+  MSF-accessible fields of Result Block:
+	IFB_IOBase				entry parameter io_base
+	IFB_IORange				HREG_IO_RANGE (0x40)
+	IFB_HCFVersionMajor		the major part of the PVCS maintained version number
+	IFB_HCFVersionMinor		the minor part of the PVCS maintained version number
+	IFB_Version				version of the IFB layout (0x01 for this release)
+	
+.NARRATIVE
+
+ Parameters:
+	ifbp		address of the Interface Block
+	io_base		I/O Base address of the NIC
+
+
+  Hcf_connect grants access right for the HCF to the IFB and initializes the HCF housekeeping part of the
+  IFB. Hcf_connect does not perform any I/O.
+
+  The HCF-Version fields are set dynamically, because I do not know of any C mechanism to have the compiler
+  and the version control system (PVCS) cooperate to achieve this at compile time.  The HCFVersions fields are
+  constructed by collecting and shifting the low order nibbles of the PVCS controlled ASCII representation.
+  Note that the low order nibble of a space (0x20) nicely coincides with the low order nibble of an ASCII '0'
+  (0x30). Also note that the code breaks when major or minor number exceeds 99.
+
+
+.DIAGRAM
+ 1:	patch_catch is called as early in the flow as the C-entry code allows to help the HCF debugger as much as
+	possible.  The philosophy behind patch_catch versus a simple direct usage of the INT_3 macro is explained
+	in the description of patch_catch
+ 2:	The IFB is zero-filled.
+ 	This presets IFB_CardStat and IFB_TickIni at appropriate values for hcf_initialize.
+10: In addition to the MSF readable fields mentioned in the description section, the following HCF specific
+	fields are given their actual value:
+	  -	a number of fields as side effect of the calls of hcf_action (see item 14)
+	  -	IFB_Magic
+	IFB_VERSION, which reflects the version of the IFB layout, is defined in HCF.H
+14:	Hcf_connect defaults to "no interrupt generation" (by calling hcf_action with the appropriate parameter),
+	"802.3 frame type" and "no card present" (implicitly achieved by the zero-filling of the IFB).
+	Depending on HCFL, the 802.3 frame type is either initialized in line or by calling hcf_action.
+	
+.NOTICE
+  If io_base ever needs to be dynamic, it may be more logical to pass
+	- io_base at hcf_enable or
+	- have a separate hcf_put_config command or
+	- demand a hcf_disconnect - hcf_connect sequence
+	
+.NOTICE
+  On platforms where the NULL-pointer is not a bit-pattern of all zeros, the zero-filling of the IFB results
+  in an seemingly incorrect initialization of IFB_MBp. The implementation of the MailBox manipulation in
+  put_mb_info protects against the absence of a MailBox based on IFB_MBSize, IFB_MBWp and ifbp->IFB_MBRp. This
+  has ramifications on the initialization of the MailBox via hcf_put_info with the CFG_REG_MB type.
+
+.ENDOC				END DOCUMENTATION
+-------------------------------------------------------------------------------------------------------------*/
+void hcf_connect( IFBP ifbp, 					//address of the Interface Block
+				  hcf_io io_base				//I/O Base address of the NIC
+				) {
+
+hcf_8 *q;
+
+#if defined _M_I86TM
+#endif // _M_I86TM
+	
+
+	for ( q = (hcf_8*)&ifbp[1]; q > (hcf_8*)ifbp; *--q = 0) /*NOP*/;									/* 2 */
+
+	ifbp->IFB_Version	= IFB_VERSION;					  												/* 10*/
+	ifbp->IFB_IOBase	= io_base;
+	ifbp->IFB_IORange	= HREG_IO_RANGE;
+	ifbp->IFB_Magic		= HCF_MAGIC;
+	ifbp->IFB_HCFVersionMajor	= (hcf_8)( (hcf_rev[REV_OFFSET] << 4 | hcf_rev[REV_OFFSET+1]) & 0x0F );
+	ifbp->IFB_HCFVersionMinor	= (hcf_8)( hcf_rev[REV_OFFSET+4] == ' ' ?
+								  		   hcf_rev[REV_OFFSET+3] & 0x0F :
+								  		   (hcf_rev[REV_OFFSET+3] << 4 | hcf_rev[REV_OFFSET+4]) & 0x0F );
+
+	(void)hcf_action(ifbp, HCF_ACT_INT_OFF );															/* 14*/
+    ifbp->IFB_FSBase = HFS_ADDR_DEST_ABS;
+	return;
+}/* hcf_connect	*/
+
+
+
+
+
+/*******************************************************************************************************************
+
+.MODULE			hcf_disable
+.LIBRARY 		HCF
+.TYPE 			function
+.SYSTEM			msdos
+.SYSTEM			unix
+.SYSTEM			NW4
+.APPLICATION	Card Initialization Group for WaveLAN based drivers and utilities
+.DESCRIPTION    Disables data transmission and reception
+.ARGUMENTS
+  int hcf_disable( IFBP ifbp, hcf_16 port )
+
+.RETURNS
+	HCF_SUCCESS
+	HCF_ERR_NO_NIC
+	HCF_ERR_TIME_OUT (via cmd_wait)
+	HCF_FAILURE (via cmd_wait)
+	
+  MSF-accessible fields of Result Block:
+   	IFB_CardStat  -	reset CARD_STAT_ENABLED bit iff at completion no port enabled anymore
+
+.NARRATIVE
+
+  Parameters:
+	ifbp		address of the Interface Block
+
+  Condition Settings:
+	Card Interrupts	  - Unchanged
+					  -	Disabled (Note that the value of IFB_IntOffCnt is unchanged)
+					    					  
+
+.NOTICE
+ o  hcf_disable may disable the card interrupts, however it does NOT influence IFB_IntOffCnt.
+	This way it is symmetrical with hcf_enable, which does NOT enable the card interrupts.	
+	
+**************************************************************************************************************/
+int hcf_disable( IFBP ifbp, hcf_16 port ) {
+
+int					rc;
+//hcf_16				p_bit;
+
+		rc = cmd_wait( ifbp, HCMD_DISABLE | (port << 8 ), 0 );
+		ifbp->IFB_CardStat &= (hcf_16)~CARD_STAT_ENABLED;
+		(void)hcf_action( ifbp, HCF_ACT_INT_OFF );														/* 40 */
+		ifbp->IFB_IntOffCnt--;
+	return rc;
+}/* hcf_disable */
+
+
+
+/*******************************************************************************************************************
+
+
+.MODULE			hcf_disconnect
+.LIBRARY 		HCF
+.TYPE 			function
+.SYSTEM			msdos
+.SYSTEM			NW4
+.APPLICATION	Card Connection for WaveLAN based drivers and utilities
+.DESCRIPTION
+  Disable transmission and reception, release the IFB
+.ARGUMENTS
+  void hcf_disconnect( IFBP ifbp )
+.RETURNS
+  void
+
+  MSF-accessible fields of Result Block:
+  	IFB_CardStat	cleared
+
+.NARRATIVE
+  Parameters:
+	ifbp		address of the Interface Block
+
+  Description:
+	Brings the NIC in quiescent state by calling hcf_initialize, thus preventing any interrupts in the future.
+
+.DIAGRAM
+ 1:	hcf_initialize gives a justification to execute the Hermes Initialize command only when really needed.
+ 	Despite this basic philosophy and although the HCF can determine whether the NIC is initialized based
+ 	on IFB_CardStat, the minimal set of actions to initialize the Hermes is always done by calling
+ 	ini_hermes.
+ 5:	clear all IFB fields
+ 	The clearing of IFB_CardStat prevents I/O on any subsequent hcf_function
+
+.ENDOC				END DOCUMENTATION
+-------------------------------------------------------------------------------------------------------------*/
+void hcf_disconnect( IFBP ifbp ) {
+
+hcf_8 *q;
+
+
+	ini_hermes( ifbp );
+
+	for ( q = (hcf_8*)&ifbp[1]; q > (hcf_8*)ifbp; *--q = 0) /*NOP*/;									/* 5 */
+
+}/* hcf_disconnect */
+
+
+
+
+
+/*******************************************************************************************************************
+
+
+.MODULE			hcf_enable
+.LIBRARY 		HCF
+.TYPE 			function
+.SYSTEM			msdos
+.SYSTEM			unix
+.SYSTEM			NW4
+.APPLICATION	Card Initialization Group for WaveLAN based drivers and utilities
+.DESCRIPTION    Enables data transmission and reception
+.ARGUMENTS
+  int hcf_enable( IFBP ifbp, hcf_16 port )
+.RETURNS
+	HCF_SUCCESS
+	HCF_ERR_TIME_OUT (via cmd_wait)
+	HCF_FAILURE (via cmd_wait)
+
+  MSF-accessible fields of Result Block
+
+  Condition Settings:
+	Card Interrupts: Off if IFB_IntOffCnt > 0; On if IFB_IntOffCnt == 0
+					 (Note that the value of IFB_IntOffCnt is unchanged)
+
+.NARRATIVE
+  Parameters:
+  	ifbp	address of the Interface Block
+
+  Description:
+
+	hcf_enable takes successively the following actions:
+ 6:	If the requested port is disabled and if the NIC is present, the Hermes Enable command is executed.
+	If CARD_STAT_PRESENT is off, the body of hcf_enable must be skipped to prevent I/O because the I/O space
+	may no longer owned by the HCF, due to a card swap.
+	The IFB_IntEnMask is set to allow Info events, Receive events and Allocate events to generate interrupts
+	and effectuated if appropriate based on IFB_IntOffCnt by calling enable_int.
+	Note that since the effect of interrupt enabling has no effect on IFB_IntOffCnt, this code may
+	be called not only at the transition from disabled to enabled but whenever a port is enabled.
+12:	When the port successfully changes from disabled to enabled - including the case when no NIC is
+	present - , the NIC status as reflected by IFB_CardStat must change to enabled
+
+.DIAGRAM
+
+.NOTICE
+  When the Hermes enable cmd is given, the static configuration of the Hermes is done.
+.ENDOC				END DOCUMENTATION
+
+-------------------------------------------------------------------------------------------------------------*/
+int hcf_enable( IFBP ifbp, hcf_16 port ) {
+
+int	rc;
+
+
+	
+	if ( (ifbp->IFB_CardStat & CARD_STAT_PRESENT) == 0 
+	   ) { rc = HCF_ERR_NO_NIC;	}	/* 6 */
+	else {
+		rc = HCF_SUCCESS;
+			rc = cmd_wait( ifbp, HCMD_ENABLE | ( port << 8 ), 0 );
+			if ( rc == HCF_SUCCESS ) enable_int( ifbp, HREG_EV_INFO | HREG_EV_RX | HREG_EV_ALLOC );		/* 8 */
+	}
+	if ( rc == HCF_SUCCESS || rc == HCF_ERR_NO_NIC ) {
+		ifbp->IFB_CardStat |= CARD_STAT_ENABLED;
+	}
+	return rc;
+
+}/* hcf_enable */
+
+
+
+/*******************************************************************************************************************
+
+
+.MODULE			hcf_get_data
+.LIBRARY 		HCF
+.TYPE 			function
+.SYSTEM			msdos
+.SYSTEM			unix
+.APPLICATION	Data Transfer Function for WaveLAN based drivers and utilities
+.DESCRIPTION
+	Obtains received message data parts from NIC RAM
+.ARGUMENTS
+	int hcf_get_data( IFBP ifbp, int offset, wci_bufp bufp, int len )
+	Card Interrupts disabled
+.RETURNS
+	hcf_16
+		zero			NIC not removed during data copying process
+		HCF_ERR_NO_NIC	NIC removed during data copying process
+		......
+
+  MSF-accessible fields of Result Block: -
+
+.NARRATIVE
+	parameters:
+		ifbp		address of the Interface Block
+		offset		offset (in bytes) in buffer in NIC RAM to start copy process
+		len			length (in bytes) of data to be copied
+		bufp		char pointer, address of buffer in PC RAM
+
+	When hcf_service_nic reports the availability of data, hcf_get_data can be
+	called to copy that data from NIC RAM to PC RAM.
+
+	Hcf_get_data copies the number of bytes requested by the parameter len from
+	NIC RAM to PC RAM. If len is larger than the (remaining) length of the
+	message, undefined data is appended to the message. This implies that if
+	hcf_get_data is called while the last hcf_service_nic reported no data
+	available, undefined data is copied.
+
+	Hcf_get_data starts the copy process at the offset requested by the
+	parameter offset, e.g. offset HFS_ADDR_DEST will start copying from the
+	Destination Address, the very begin of the 802.3 framemessage.
+	In case of a fragmented PC RAM buffer, it is the responsibility of the MSF,
+	to specify as offset the cumulative values of the len parameters of the
+	preceeding hcf_get_data calls. This I/F gives a MSF the facility to read
+	(part of) a message and then read it again.
+	
+.DIAGRAM
+.ENDOC				END DOCUMENTATION
+
+
+-------------------------------------------------------------------------------------------------------------*/
+int hcf_get_data( IFBP ifbp, int offset, wci_bufp bufp, int len ) {
+
+int rc = HCF_SUCCESS;
+//int	tlen;
+
+
+	if ( ifbp->IFB_CardStat & CARD_STAT_PRESENT ) {	
+		if ( offset < 0 ) offset -= HFS_STAT;
+		else {
+			offset += ifbp->IFB_FSBase;
+	    }
+		if ( rc == HCF_SUCCESS ) rc = hcfio_string( ifbp, BAP_1, ifbp->IFB_RxFID, offset, bufp, 0, len, IO_IN );
+	}
+	return rc;
+}/* hcf_get_data */
+
+
+
+
+/**************************************************************************************************************
+
+
+ Name:	hcf_get_info
+
+ Summary: Obtains transient and persistent configuration information from the
+	Card and from the HCF
+
+ Parameters:
+  ifbp	address of the Interface Block
+
+  ltvp	address of LengthTypeValue structure specifying the "what" and the "how much" of the information
+  		to be collected from the HCF or from the Hermes
+
+ Returns:
+	int
+		..... ????????????????	
+
+ Remarks: Transfers operation information and transient and persistent
+ 	configuration information from the Card and from the HCF to the MSF.
+	The exact layout of the provided data structure
+	depends on the action code. Copying stops if either the complete
+	Configuration Information is copied or if the number of bytes indicated
+	by len is copied.  Len acts as a safe guard against Configuration
+	Information blocks which have different sizes for different Hermes
+	versions, e.g. when later versions support more tallies than earlier
+	versions. It is a consious decision that unused parts of the PC RAM buffer are not cleared.
+
+ Remarks: The only error against which is protected is the "Read error"
+	as result of Card removal. Only the last hcf_io_string need
+	to be protected because if the first fails the second will fail
+	as well. Checking for cmd_wait errors is supposed superfluous because
+	problems in cmd_wait are already caught or will be caught by
+	hcf_enable.
+	
+	
+ 3:	tallying of "No inquire space" is done by cmd_wait
+
+ Note:
+	the codes for type are "cleverly" chosen to be identical to the RID
+	
+
+ 7:	The return status of cmd_wait and the first hcfio_in_string can be ignored, because when one fails, the
+ 	other fails via the IFB_TimStat mechanism
+		
+**************************************************************************************************************/
+int hcf_get_info(IFBP ifbp, LTVP ltvp ) {
+
+int				rc = HCF_ERR_LEN;
+//hcf_io			reg;
+hcf_16			i, len;
+hcf_16			type;						//don't change type to unsigned cause of "is it a RID" test
+hcf_16 			*q;							//source pointer (Tally-part of IFB)
+//hcf_16 FAR 		*bq;						//source pointer (Identity or Range records)	;?why bq and not e.g. wq
+wci_recordp		p = ltvp->val;				//destination word pointer (in LTV record)
+//wci_bufp		cp = (wci_bufp)ltvp->val;	//destination char pointer (in LTV record)
+
+	
+	len = ltvp->len;
+	type = ltvp->typ;
+	
+	if ( len > 1 ) {
+	
+		rc = HCF_SUCCESS;
+		switch ( type ) {
+			
+#if MSF_COMPONENT_ID != COMP_ID_AP1
+		  case CFG_TALLIES:																				/* 3 */
+			ltvp->len = len = min( len, (hcf_16)(HCF_TOT_TAL_CNT + HCF_TOT_TAL_CNT + 1) );
+			q = (hcf_16*)/*(wci_recordp)*/&ifbp->IFB_NIC_Tallies; //.TxUnicastFrames;
+			while ( --len ) *p++ = *q++;
+			(void)hcf_action( ifbp, HCF_ACT_TALLIES );
+			break;
+#endif //COMP_ID_AP1
+
+			
+
+			
+			
+		  default:
+			rc = HCF_ERR_NO_NIC;
+			if ( ifbp->IFB_CardStat & CARD_STAT_PRESENT ) {
+				rc = HCF_ERR_TIME_OUT;			
+				  	if ( type < CFG_RID_CFG_MIN ) {
+				  		ltvp->len = 0;
+				  	} else {
+						(void)cmd_wait( ifbp, HCMD_ACCESS, type );											/* 7 */
+						(void)hcfio_string( ifbp, BAP_1, type, 0, (wci_bufp)&i, 1, sizeof(hcf_16), IO_IN );
+						ltvp->len = min( i, len );
+						rc = hcfio_string( ifbp, BAP_1, type, sizeof(hcf_16), (wci_bufp)&ltvp->typ, 1, MUL_BY_2(ltvp->len), IO_IN );
+						if ( rc == HCF_SUCCESS && i > len ) rc = HCF_ERR_LEN;
+					}
+			}
+		}
+	}
+	return rc;
+
+}/* hcf_get_info */
+
+
+/*******************************************************************************************************************
+
+.MODULE			hcf_initialize  ;?in fact an hcf-support routine, given an hcf_... name just in case we want to
+								  export it over the WCI later
+.LIBRARY 		HCF
+.TYPE 			function
+.SYSTEM			msdos
+.SYSTEM			unix
+.SYSTEM			NW4
+.APPLICATION	Card Initialization Group for WaveLAN based drivers and utilities
+.DESCRIPTION    ..........., in addition, a light-weight diagnostic test of the NIC
+.ARGUMENTS
+  int hcf_initialize( IFBP ifbp )
+
+.RETURNS
+	HCF_SUCCESS
+	HCF_ERR_NO_NIC
+	HCF_ERR_TIME_OUT;
+	HCF_FAILURE (via cmd_wait)
+				(via hcf_get_info)
+	HCF_ERR_INCOMP_PRI
+	HCF_ERR_INCOMP_STA	
+	
+  MSF-accessible fields of Result Block:
+   	IFB_DUIFRscInd, IFB_NotifyRscInd, IFB_PIFRscInd cleared
+   	IFB_MBInfoLen, IFB_RxLen, IFB_RxStat cleared
+   	IFB_CardStat  -	CARD_STAT_ENA_0	through CARD_STAT_ENA_6
+				  -	CARD_STAT_INCOMP_PRI
+				  -	CARD_STAT_INCOMP_STA
+   	
+
+.NARRATIVE
+
+  Parameters:
+	ifbp		address of the Interface Block
+
+  hcf_initialize will successively:
+  -	initialize the NIC by calling ini_hermes
+  -	calibrate the S/W protection timer against the Hermes Timer by calling calibrate
+
+  Condition Settings:
+	Card Interrupts: Disabled  (Note that the value of IFB_IntOffCnt is unchanged)
+
+  Remarks: since hcf_initialize is the first step in the initialization of the card and since the strategy is to
+   detect problems as a side effect of "necessary" actions, hcf_initialize has, in deviation of the general
+   strategy, an additional "wait for busy bit drop" at all places where Hermes commands are executed. An
+   additional complication is that no calibrated value for the protection count can be assumed since it is
+   part of the first execution of hcf_disable to determine this calibrated value (a catch 22). The initial
+   value (set at INI_TICK_INI by hcf_connect) of the protection count is considered safe, because:
+   o the HCF does not use the pipeline mechanism of Hermes commands.
+   o the likelihood of failure (the only time when protection count is relevant) is small.
+   o the time will be sufficiently large on a fast machine (busy bit drops on good NIC before counter expires)
+   o the time will be sufficiently small on a slow machine (counter expires on bad NIC before the enduser
+     switches the power off in despair
+	IFB_TickIni is used in cmd_wait to protect the Initialize command. The time needed to wrap a 32 bit counter
+	around is longer than many humans want to wait, hence the more or less arbitrary value of 0x10000L is
+	chosen, assuming it does not take too long on an XT and is not too short on a scream-machine.
+	Once we passed the CARD_STAT_PRESENT test on IFB_CardStat, the other bits can be reset. This is needed
+	to have a dynamical adjustment of the Station/Primary Incompatibility flags.
+	Especially IFB_TimStat must be cleared (new round, new chances)
+
+ Remarks: First the HCF disables the generation of card interrupts. Next it waits for the Busy bit in the
+   Command register to drop (the additional safety required for hcf_initialize as described above). If the Hermes
+   passes this superficial health test, the Hermes Initialize command is executed. The Initialize command acts
+   as the "best possible" reset under HCF control. A more "severe/reliable" reset is under MSF control via the
+   COR register.
+
+ Remarks: If the Initialize of the Hermes succeeds, the S/W protection counter is calibrated if not already
+   calibrated. This calibration is "reasonably" accurate because the Hermes is in a quiet state as a result of
+   the Initialize command. The hcf_put_info function is used to program the Hermes Tick for its minimum
+   interval (1024 microseconds). Programming the Tick interval terminates the old interval timing immediately
+   and starts the new interval. Due to this ad-hoc switch the first interval has a larger inaccuracy. By
+   timing immediately a second interval the accuracy improves due to the synchronization of HCF and Hermes.
+   After this second interval, the Hermes Tick is programmed for its default value of 1 second again.
+
+.NARRATIVE
+ 2:	Clear all fields of the IFB except those which need to survive hcf_initialize. This is intended to make
+ 	the behavior and - as a consequence - the debugging of the HCF more reproduceable.
+
+ 3:	Disable the interrupt generation facility (see also #30)
+ 5: Depending on whether there is selective disabling of a single port or a collective disabling of
+	all ports a specific bit or all bits representing the enabled ports are reset. In case of "all ports"
+	none of the other bits except CARD_STAT_ENABLED is relevant, so as an easy implementation all those
+	other bits are cleared.
+	The individual bits conveyed in IFB_CardStat are historically grown. To leave the WCI unchanged, the
+	individual "port enabled" bits are scattered through IFB_CardStat. As a consequence there is some bit
+	arithmetic involved to convert a port number to a bit flag
+	The masking of port with HCF_PORT_MASK is a cheap safeguard against I/F violations by the MSF. If the MSF
+	supplies an invalid bit pattern, unwanted bits may end up in Hermes Command register via Disable command
+	with unpredictable effects.
+ 7: Check whether CARD_STAT_PRESENT bit of IFB_CardStat is on. If not the remainder of hcf_initialize must be
+	skipped to prevent I/O because the I/O space may no longer owned by the HCF, due to a card swap.
+12:	When a single port must be disabled AND it is not the only enabled port, that port is selectively
+	disabled. If all ports or the only enabled port is to be disabled, the disabling is skipped and the
+	Hermes Initiate command is supposed to take care of it all.
+16: perform a superficial Hermes health test. Note that in hcf_initialize all (or at least most) activities are
+	checked for conditions like "Busy bit should drop". If such a condition is not met in time, hcf_initialize
+	returns an error code. Hcf_functions which are only called during "normal" operations may ignore such
+	events. Their only obligation is to prevent that the code hangs.
+	Note that early models of the Hermes needed some arbitrary read before the first write activity to operate
+	stable (ref tracker 27). This code achieves that function as a side effect.
+18:	Initialize the Hermes. The results of this way of initialization depends on the capabilities of the Hermes
+  	firmware. Therefore, the Hermes H/W controlled bits, like those in the evitable register are not guaranteed
+  	to be cleared as result of the initialize command. However it is guaranteed that no more events are in the
+    pipeline. Ack-ing indiscriminately all events resolves this problem. An alternative would be to use the
+    resulting value of "IN_PORT_WORD( ifbp->IFB_IOBase + HREG_EV_STAT )" rather than 0xFFFF to specifically
+    only reset those events which are set. This strategy is considered to be only more aesthetically pleasing
+    (if that).
+20:	Perform some housekeeping tasks
+  - Write HCF_MAGIC as signature to S/W support register 0.  This signature is used to detect card removal
+	wherever the presence of the card is critical while HCF may not yet have been informed by the MSF of the
+	removal of the card.  Note that this task can not be postponed because that would cause the hcfio_in_string
+	called by hcf_get_info to fail
+22:
+
+	  -	IFB_TickIni	must be initialized (at INI_TICK_INI) to prevent that actions like hcf_put_info immediately
+	    after hcf_connect (that is without intervening hcf_disable) at an absent (or failing) NIC take too
+	    long.  Note that this is a legal hcf-sequence according to the WCI-specification.
+
+
+
+
+	IFB_TickIni is the value used to initialize the S/W protection counter in a way which makes the
+	expiration period more or less independent of the processor speed. If IFB_TickIni is not yet calibrated,
+	it is done now.
+	First off all the Hermes Tick period is programmed for a "reasonable" interval, currently 8092 or 8k
+	microseconds, by means of hcf_put_info. Note that IFB_DLTarget, which is guaranteed to get the correct
+	value later on in hcf_enable, is misused as re-entrant storage for the RID used to program the Tick period.
+	The HCF synchronizes itself with the Hermes timer by waiting for the first timer tick. This synchronizing is done by
+	ack-ing the Tick regardless of its current value. This guarantees Tick becomes low. Then Tick is sampled
+	till it is high, which guarantees a new complete interval starts in the Hermes. Tick is acked again and
+	another Tick is awaited. This period is as accurate as we can get.
+	To diminish the chance that in a pre-emptive environment IFB_TickIni is calibrated too low because the HCF
+	just happens to loose control during this calibration, the calibration is performed 10 times and the
+	largest value is used.
+	IFB_TickIni is then set at approximately 1 second by multiplying that largest value by 128. The 8k
+	microseconds interval and the multiplication by 128 are chosen as a compromise between accuracy of
+	the calibration. time consumed by the calibration and possibilities for the compiler to optimize
+	the arithmetic.
+26:	Finally the Hermes Tick period is programmed for a "reasonable" runtime interval, currently 1 second
+	(1,000,000/1,024 kilo-microseconds), by means of hcf_put_info (again the available CONCATENATED storage
+	is misused)
+	Note that in case of failure, IFB_TickIni ends up as INI_TICK_INI, which is a supposedly acceptable
+	value to handle the rare case of a broken card.
+30: The Supplier Range of the Primary Firmware function is retrieved from the Hermes and checked against
+	the Top and Bottom level supported by this HCF.
+	If the primary firmware does not supply this RID or supplies the "old" HardwareStructure Info, the
+	Primary Compatibility check is skipped. These conditions are recognized based on the length field supplied
+	by the Hermes. ;?is this wise in the post-GCA area
+32: In case of a HCF compiled for station functionality, the Supplier Range of the Station Firmware function
+	is retrieved from the Hermes and checked against the Top and Bottom level supported by this HCF.
+	Note that the Firmware can have multiple Variants, but that the HCF currently only supports a single
+	variant.
+40:	Perform some more housekeeping tasks
+  -	Decrement ifbp->IFB_IntOffCnt to compensate side effect of ACT_INT_OFF action at begin of hcf_initialize (see
+	#2). This can not be handled by calling hcf_action with HCF_ACT_ON, because this could as undesirable
+	side effect actually enable interrupts
+	
+.NOTICE
+ o  For all practical WCI purposes there is no practical difference between a Hermes disable command at all
+	individual ports and an hermes initialize command
+ o  hcf_initialize disables the card interrupts, however it does NOT influence IFB_IntOffCnt.
+	This way it is symmetrical with hcf_enable, which does NOT enable the card interrupts.	
+
+
+   	IFB_CardStat  -	CARD_STAT_INCOMP_PRI
+				  -	CARD_STAT_INCOMP_STA
+   	
+ 5:	The house keeping is done, consisting of the steps:
+	- allocate a Tx Frame Structure for the protocol stack
+	- allocate a Tx Frame Structure for the utility
+	- allocate a Information Frame Structure for the Notify command
+	Note that a subsequent allocate is only performed if the preceding one
+	succeeded
+	- if all allocates succeeded, the Resource Indicators corresponding
+	  with the Tx Frames are set
+
+
+**************************************************************************************************************/
+int hcf_initialize( IFBP ifbp ) {
+
+int		rc;
+//hcf_16	*p;
+hcf_8	*q;
+
+
+	for ( q = (hcf_8*)&ifbp->IFB_PIFRscInd; q < (hcf_8*)&ifbp[1]; *q++ = 0) /*NOP*/;					/* 2 */
+
+//	if ( (ifbp->IFB_CardStat & CARD_STAT_INI) == 0 ) {				//present but not initialized	/* 7 */
+	do { //;?CARD_STAT_PRESENT check superfluous as long as hcf_initialize is not defined on the WCI
+		rc = ini_hermes( ifbp );
+		if ( rc != HCF_SUCCESS ) break;																/* 32*/
+		OUT_PORT_WORD( ifbp->IFB_IOBase + HREG_SW_0, HCF_MAGIC );									/* 20*/
+		rc = calibrate( ifbp );   																	/* 22*/
+		if ( rc != HCF_SUCCESS ) break;
+
+#if defined MSF_COMPONENT_ID  //;?interesting question at which level HCFL interacts		
+#endif // MSF_COMPONENT_ID
+        ifbp->IFB_CardStat |= CARD_STAT_INI;	//consider this as sufficient to reach CARD_STAT_INI?	/* 24*/
+		if ( rc != HCF_SUCCESS ) break;   //;? apparently this still should follow the moved IFB_DLTarget logic but
+											//;? think this over for the different scenarios
+		if ( ( ifbp->IFB_PIF_FID    = alloc( ifbp, HFS_TX_ALLOC_SIZE )  ) == 0		||				/* 5 */
+			 ( ifbp->IFB_DUIF_FID   = alloc( ifbp, HFS_TX_ALLOC_SIZE )  ) == 0  ) {
+			rc = HCF_FAILURE;
+		} else {
+			ifbp->IFB_PIFRscInd = ifbp->IFB_DUIFRscInd = 1;
+
+		}
+	} while ( 0 ); //pseudo goto-less, accept "warning: conditional expression is constant"
+
+	return rc;
+}/* hcf_initialize */
+
+
+/*******************************************************************************************************************
+
+
+.MODULE			hcf_put_data
+.LIBRARY 		HCF
+.TYPE 			function
+.SYSTEM			msdos
+.SYSTEM			unix
+.SYSTEM			NW4
+.APPLICATION	Data Transfer Function for WaveLAN based drivers and utilities
+.ARGUMENTS
+	void hcf_put_data( IFBP ifbp, wci_bufp bufp, int len, hcf_16 port )
+	Card Interrupts disabled
+
+.RETURNS
+	void
+
+  MSF-accessible fields of Result Block: -
+
+.DESCRIPTION	Transfers (part of) transmit message to the NIC and handles
+	the Ethernet-II encapsulation if applicable
+.NARRATIVE
+	parameters:
+		ifbp		address of the Interface Block
+		bufp		char pointer, address of buffer in PC RAM
+		len			length (in bytes) of data to be copied
+		port		HCF_PORT_0 - HCF_PORT_6 .........;?
+					HCF_PUT_DATA_RESET
+
+
+	Refer to hcf_service;?non-existing reference, for a concise description about possible
+	relation/sequencing of hcf_put_data in the Interrupt Service Routine
+	
+	In essence, hcf_put_data copies the number of bytes specified by parameter len from the location in PC
+	RAM specified by bufp to the NIC RAM buffer associated with the Protocol Stack dedicated FID.
+	The first call succeeding hcf_send (or hcf_enable), writes the first byte at offset HFS_ADDR_DEST in
+	the transmit data buffer, successive hcf_put_data calls continue where the preceeding hcf_put_data stopped.
+	
+	IFB_FrameType determines whether the message in the PC RAM buffer is interpreted as an 802.3 or 802.11
+	frame.  This influences:
+ 	o the position where the first byte of the initial hcf_put_data is stored
+ 	o Only in case of the 802.3 frame type, hcf_put_data checks whether the frame is an Ethernet-II rather
+ 	  than an "official" 802.3 frame. The E-II check is based on the length/type field in the MAC header. If
+ 	  this field has a value larger than 1500, E-II is assumed. The implementation of this test fails if the
+	  length/type field is split over 2 hcf_put_data calls.
+	  If E-II is recognized, the length field HFS_LEN_ABS is skipped for the time being and a SNAP header is
+	  inserted starting at HFS_DAT_ABS. This SNAP header represents either RFC1042 or Bridge-Tunnel
+	  encapsulation, depending on whether the type is absent or present in enc_trans_tbl.
+ 	o In case of the 802.11 frame type, hcf_put_data checks whether the complete header + length field is
+ 	  written (note that part of the header may be written by previous hcf_put_data calls and part may be
+ 	  written by this call).  If so, the next byte is written at HFS_DAT_ABS (the 802.3 header area is skipped)
+
+	It is allowed to write the 802.3 header, 802.11 header and/or data in fragments, e.g. the first
+	hcf_put_data call writes 18 bytes starting at location HFS_ADDR_1_ABS and the second call writes 6 more
+	bytes starting at location HFS_ADDR_4. Although Address part #4 is not present in some 802.11 headers,
+	all 4 addressing parts and the length field must be written in case of 802.11. Once the complete header
+	is written, the data part is written starting from offset HFS_DAT_ABS.
+
+	Hcf_put_data does not check for transmit buffer overflow because the Hermes does this protection.
+	In case of a transmit buffer overflow, the surplus which does not fit in the buffer is simply dropped.
+	Note that this possibly results in the transmission of incomplete frames.
+
+.DIAGRAM
+1*: If the card is not present, prevent all I/O because "our" I/O base may have been given away to someone
+	else in a CS/SS environment.  Also no I/O should be performed if the NIC is not enabled. However
+	an MSF which calls hcf_put_data while the NIC is not enabled probably contains a logic flaw (or has a
+	strategy which was not foreseen at the time this was written)
+10* HCF_PUT_DATA_RESET discards all the data put by preceeding hcf_put_data calls and resets the HCF
+	housekeeping just the same as after an hcf_send triggered allocate event.
+	Note: To make the WCI fail-safe, invalid port numbers are silently rejected by treating them as 
+	HCF_PUT_DATA_RESET. Note that the assumption is that this should never ever occure in a debugged MSF and 
+	that during debugging the ASSERT is sufficient support to help the MSF programmer.
+2*:	This statement is only true at the first hcf_put_data call after an hcf_send result or hcf_enable
+	The housekeeping is done.
+ 	o the PIFRscInd is cleared, so the MSF can not begin another hcf_put_data/hcf_send sequence
+	before completing the current one
+ 	o the Tx Encoding flag (TxFrameType) is cleared
+ 	o the index to the first free position in the FID (IFB_PIFLoadIdx) is initialized based on IFB_FSBase.
+ 	  IFB_FSBase is initialized when hcf_action is called with HCF_ACT_802_3 or HCF_ACT_802_11
+3*:	Pay Attention: it may seem attractive to change this code, e.g. to save the superfluous call to
+	hcfio_out_string when the Destination and Source address are written by the preceeding call and the
+	current call starts at the length/type field. However this code is "reasonably carefully" crafted
+	to take in account all boundary conditions. It is very easy to make a change which does not work under
+	all feasible split ups of the message in fragments.
+	First IFB_PIFLoadIdx is checked.
+	  - If IFB_PIFLoadIdx points past HFS_LEN_ABS, the preceeding call(s) to hcf_put_data already passed the
+	  length/type field. As a consequence the fragment can be concatenated to the data already copied to
+	  NIC RAM.
+	  - If IFB_PIFLoadIdx does not point past HFS_LEN_ABS, the current fragment may or may not contain part of
+	  the Destination and/or Source Address and it may or may not contain the length/type field.
+	  If the fragment contains addressing information or -in case of 802.11- length info , this information
+	  is copied/concatenated to the NIC RAM buffer. The working variables (pointer and length of fragment) as
+	  well as the IFB_PIFLoadIdx are adjusted.
+	The semi-obscure differences in the boundary testing are caused by:
+	  o 802.11: the "below the boundary" area is Addr1, Addr2, Addr3, Ctrl, Adrr4 + DataLen and the "above"
+	  	area is the "real" data
+	  o 802.3: the "below the boundary" area is DestAddr + SrcAddr and the "above" area is the length +
+	  	"real" data
+	  o E-II: the "below the boundary" area is DestAddr + SrcAddr, then there is a "virtual" area with the
+	  	SNAP header (which will in the end include the HCF calculated length)  and the "above" area is the
+	  	"protocol stack length" (is in reality the type code) + "real" data
+4*:	If there is still data left, IFB_PIFLoadIdx may need adjustment (802.11 and E-II encapsulation).  Again
+	note that this length check is crucial to prevent mis-manipulation of IFB_PIFLoadIdx in case the header
+	is written in multiple fragments.
+	In case of 802.3, the E-II check is done. In case of E-II, the encapsulation type (RFC1042 versus
+	Bridge-Tunnel) is determined and the corresponding SNAP header is written to NIC RAM and
+	IFB_PIFLoadIdx is adjusted.
+6*:	All data which is not already copied under 3*, is copied here.
+	In case of 802.11, the HFS_DAT field is the first field written by this code.
+	In case of 802.3, the HFS_LEN field is the first field written by this code.
+	In case of E-II encapsulation, the HFS_TYPE field is the first field written by this code.
+	Note that in case of E-II encapsulation, the HFS_LEN field is not written by hcf_put_data at all, but by
+	hcf_send because the data length is not	known till all fragments have been processed.
+	
+.NOTE	
+	The possible split of a single hcf_put_data call into 2 calls to hcfio_out_string results in 2 calls
+	to bap_ini, which may be unexpected while you are debugging, but is never the less the intended behavior.
+	Along the same line a call of hcfio_out_string with a value of 0 for parameter len may be unexpected, e.g.
+	when the len parameter of hcf_put_data is either 1 or 2, the latter depending on the odd/even aspects of
+	IFB_PIFLoadIdx.	
+	
+	
+	
+.NOTE
+	The test on PIFRscInd to distinguish the initial hcf_put_data from subsequent calls is not thread safe.
+	It is assumed that threaded MSFs have their own mechanism to assure that hcf_put_data calls belonging to
+	a single frame are atomic with respect to each other. It is also assumed that the MSF takes care that
+	the hcf_put_data calls of multiple frames do not run concurrent
+	
+	
+.ENDOC				END DOCUMENTATION
+
+
+-------------------------------------------------------------------------------------------------------------*/
+void hcf_put_data( IFBP ifbp, wci_bufp bufp, int len, hcf_16 port ) {
+
+int		idx;				//working index into Tx Frame structure, presume MSF control
+//int		tlen;				//working type/length of frame, working length for partial copy of frame
+	
+
+	if ( ifbp->IFB_CardStat & CARD_STAT_PRESENT ) {															/* 1 */
+			if ( ifbp->IFB_PIFRscInd ) {																	/* 2 */
+				ifbp->IFB_PIFRscInd = 0;
+				ifbp->IFB_PIFLoadIdx = ifbp->IFB_FSBase;    //;?<HCF_L> should result in 0
+			}
+			
+			idx = ifbp->IFB_PIFLoadIdx;
+			ifbp->IFB_PIFLoadIdx += (hcf_16)len;
+			(void)hcfio_string( ifbp, BAP_0, ifbp->IFB_PIF_FID, idx, bufp, 0, len, IO_OUT);		/* 6 */
+	}
+	return;
+}/* hcf_put_data */
+
+
+/**************************************************************************************************************
+
+
+ Name:	hcf_put_info
+
+ Summary: Transfers operation information and transient and persistent
+ 	configuration information to the Card.
+
+ Parameters:
+  ifbp	address of the Interface Block
+
+  type	specifies the RID (as defined by Hermes I/F)
+
+  bufp	address in NIC RAM where record data is located
+
+   len	length of data (in bytes)
+
+.NARRATIVE
+
+ Remarks:
+	CFG_NOTIFY: only runs after hcf_enable
+
+ Remarks: Configuration information is copied from the provided data
+	structure into the Card. The exact layout of the provided data
+	structure depends on the action code. Also the mechanism used to copy
+	the data to the card depends on the action code. In order to make the
+	changes which are based on the Access command (see support routine put_info)
+	sustain over activities like hcf_diagnose and recovery from PCMCIA card
+	insertion, the data associated with these particular action codes, is
+	saved in the IF-block. The codes for this type are "cleverly" chosen to
+	be identical to the RID.
+	
+	bufp is defined as a pointer to items of type hcf_16 because of the
+	correlation with the Hermes definition
+	
+	
+.DIAGRAM
+
+.NOTICE
+	Future enhancements in the functionality offered by the WCI and/or implementation aspects of the HCF
+	may warrant filtering on the type-field of the LTV to recognize non-MSF accessible records, e.g. CFG_TICK
+	
+**************************************************************************************************************/
+
+int hcf_put_info( IFBP ifbp,
+				  LTVP ltvp		/*number identifying the type of change
+<PRE>
+									CFG_INFO_FRAME_MIN	lowest value representing an Information Frame
+									CFG_NOTIFY			Handover Address
+										
+									CFG_TALLIES			Communications Tallies
+									CFG_SCAN			Scan results
+										                        	
+									CFG_LINK_STAT 		Link Status
+									CFG_ASSOC_STAT		Association Status
+								
+</PRE>							*/
+			    ) {
+
+//int			cnt = 3;
+//hcf_16		i = ltvp->len - 1;
+int			rc = HCF_SUCCESS;
+
+	
+	if ( CFG_RID_CFG_MIN <= ltvp->typ && ltvp->typ <= CFG_RID_CFG_MAX ) {
+      	//all codes between 0xFC00 and 0xFCFF are passed to Hermes)
+//		if ( ( ifbp->IFB_CardStat & CARD_STAT_PRI_STA_PRES ) == CARD_STAT_PRESENT ) {
+//			do {
+//				rc = hcfio_string( ifbp, BAP_1,
+//								   ltvp->typ, 0, (wci_bufp)ltvp, 2, MUL_BY_2(ltvp->len + 1), IO_OUT_CHECK );
+//			} while ( cnt-- && rc != HCF_SUCCESS );
+//			if ( rc == HCF_SUCCESS ) rc = cmd_wait( ifbp, HCMD_ACCESS + HCMD_ACCESS_WRITE, ltvp->typ );
+//			if ( rc == HCF_SUCCESS ) rc = put_info( ifbp, ltvp );
+
+		rc = put_info( ifbp, ltvp );
+//		}
+	}	
+	return rc;
+}/* hcf_put_info */
+
+
+
+
+
+/******************************************************************************************************************
+
+.MODULE			hcf_send
+.LIBRARY 		HCF
+.TYPE 			function
+.SYSTEM			msdos
+.SYSTEM			unix
+.SYSTEM			NW4
+.APPLICATION	Data Transfer Function for WaveLAN based drivers and utilities
+.DESCRIPTION	Transmit a message on behalf of the protocol stack
+.ARGUMENTS
+	void hcf_send( IFBP ifbp , hcf_send_type type )
+	Card Interrupts disabled
+
+.RETURNS
+	void
+
+  MSF-accessible fields of Result Block: -
+
+.NARRATIVE
+	Hcf_send transmits the Protocol Stack message loaded in NIC RAM by the
+	preceeding hcf_put_data calls.
+
+.DIAGRAM
+1:	The actual data length (the number of bytes in the Tx Frame structure
+	following the 802.3/802.11 Header Info blocks, is determined by
+	IFB_PIFLoadIdx, the index in the Transmit Frame Structure to store the
+	"next" byte. Note that this value must be compensated for the header info
+	by subtracting HFS_DAT.
+2/3:TxFrameType - which is based on the preceding hcf_put_data calls - defines
+	whether the actual data length is written to the 802.11 or 802.3 Header Info
+	block.
+2:	In case of 802.11, the entry parameter type is augmented to reflect	802.11
+	before it is written to the Control Field block.
+3:	In case of 802.3, the actual length must be converted from the native
+	format of the Host (Little Endian in case of an 80x86) to Big Endian before
+	it is written to the 802.3 Header Info block.
+4:	The actual send+reclaim command is performed by the routine send.
+7:	The return status of hcfio_in_string can be ignored, because when it fails, cmd_wait will fail via the
+ 	IFB_TimStat mechanism
+.NOTICE
+  ;?This comment is definitely out of date
+  The choice to let hcf_send calculate the actual data length as
+  IFB_PIFLoadIdx - HFS_DAT, implies that hcf_put_data with the HFS_LUCENT
+  mechanism MUST be used to write the Data Info Block. A change in this I/F
+  will impact hcf_send as well.
+  An alternative would be to have a parameter datlen. If datlen is zero, the
+  current behavior is used. If datlen has a non-zero value, its value is used
+  as the actual data length (without validating against HCF_MAX_MSG and without
+  validating the total number of bytes put by hcf_put_data).
+
+.NOTICE
+  hcf_put_data/send leave the responsibility to only send messages on enabled ports at the MSF level.
+  This is considered the strategy which is sufficiently adequate for all "robust" MSFs, have the least
+  processor utilization and being still acceptable robust at the WCI !!!!!
+.ENDOC				END DOCUMENTATION
+
+------------------------------------------------------------------------------------------------------------*/
+int hcf_send( IFBP ifbp , hcf_16 port ) {	//;?note that port is unused due to ambivalence about what the "right" I/F is
+
+int	rc = HCF_SUCCESS;
+
+
+	if ( ifbp->IFB_CardStat & CARD_STAT_PRESENT ) {												/* 1 */	
+		/* H/W Pointer problem detection */	
+		if ( ifbp->IFB_BAP_0[0] != ifbp->IFB_FSBase ) {	//;?<HCF _L> should BE HARD CODED, also add to send diag msg	/* 30*/
+			rc = hcfio_string( ifbp, BAP_0, ifbp->IFB_PIF_FID, ifbp->IFB_PIFLoadIdx, NULL, 0, 0, IO_OUT_CHECK );
+			
+			if ( rc == HCF_FAILURE ) {
+				ifbp->IFB_PIFRscInd = 1;
+			}
+		}
+		if ( rc == HCF_SUCCESS ) {
+			if ( /*ifbp->IFB_FrameType == ENC_802_11 || */ ifbp->IFB_TxFrameType == ENC_TX_E_II ) {		/* 2 */
+				ifbp->IFB_PIFLoadIdx -= HFS_DAT_ABS;		//actual length of frame					/* 1 */
+				CNV_INT_TO_BIG_NP(&ifbp->IFB_PIFLoadIdx);  //;?is it worthwhile to have this additional macro
+				(void)hcfio_string( ifbp, BAP_0, ifbp->IFB_PIF_FID, HFS_LEN_ABS,
+										(wci_bufp)&ifbp->IFB_PIFLoadIdx, 0, 2, IO_OUT );			/* 7 */
+			}
+//			send( ifbp, ifbp->IFB_PIF_FID, port | ifbp->IFB_FrameType );								/* 4 */
+			(void)cmd_wait( ifbp, HCMD_TX + HCMD_RECL, ifbp->IFB_PIF_FID );			//justify "void"
+		}
+		/* reset the BAP pointer for the Tx Framestructure, note that we access the BAP not the NIC RAM
+		 * after we relinguished control of the Tx FID to the Hermes
+		 */
+		(void)hcfio_string( ifbp, BAP_0, ifbp->IFB_PIF_FID, ifbp->IFB_FSBase, NULL, 0, 0, IO_IN );
+	}
+	return rc;
+} /* hcf_send */
+
+
+
+/*******************************************************************************************************************
+
+.MODULE			hcf_send_diag_msg
+.LIBRARY 		HCF
+.TYPE 			function
+.SYSTEM			msdos
+.SYSTEM			unix
+.SYSTEM			NW4
+.APPLICATION	Data Transfer Function for WaveLAN based drivers and utilities
+.DESCRIPTION	Transmit a message on behalf of the Driver-Utility I/F
+.ARGUMENTS
+	void hcf_send_diag_msg( IFBP ifbp, wci_bufp bufp, hcf_16 len )
+	Card Interrupts disabled
+
+.RETURNS
+	void
+
+  MSF-accessible fields of Result Block: -
+
+.NARRATIVE
+	Hcf_send_diag_msg transmits the message
+.DIAGRAM
+
+ 2:
+
+ 4: Based on the assumption that hcf_send_diag_msg is called at a low frequency, HFS_TX_CNTL_ABS is written
+  	on each call rather than using an IFB-field to remember the previous value and update only if needed
+
+
+.ENDOC				END DOCUMENTATION
+
+-------------------------------------------------------------------------------------------------------------*/
+int hcf_send_diag_msg( IFBP ifbp, hcf_16 type, wci_bufp bufp, int len ) {
+
+int rc = HCF_SUCCESS;
+
+
+	if ( ifbp->IFB_CardStat & CARD_STAT_PRESENT ) {
+		rc = HCF_ERR_BUSY; //;?more appropriate value needed
+		if ( ifbp->IFB_DUIFRscInd ) {																	/* 2 */
+			rc = hcfio_string( ifbp, BAP_0, ifbp->IFB_DUIF_FID, HFS_ADDR_DEST_ABS, bufp, 0, len, IO_OUT_CHECK );
+			if ( rc == HCF_SUCCESS ) {
+				ifbp->IFB_DUIFRscInd = 0;
+				(void)hcfio_string( ifbp, BAP_0, ifbp->IFB_PIF_FID, HFS_TX_CNTL_ABS, 		//justify void
+								  (wci_bufp)&type, 1, 2, IO_OUT );								/* 4 */
+				(void)cmd_wait( ifbp, HCMD_TX + HCMD_RECL, ifbp->IFB_DUIF_FID );			
+			}
+		}
+	}
+	return rc;
+} /* hcf_send_diag_msg */
+
+
+
+
+
+/*******************************************************************************************************************
+
+
+.MODULE			hcf_service_nic
+.LIBRARY 		HCF
+.TYPE 			function
+.SYSTEM			msdos
+.APPLICATION	Data Transfer Function for WaveLAN based drivers and utilities
+.DESCRIPTION	Provides received message and link status information
+.ARGUMENTS
+	int	hcf_service_nic(IFBP ifbp )
+	Card Interrupts disabled
+
+.RETURNS
+	int
+		all the bits of the Hermes evitable register, which are encountered during execution of hcf_service_nic
+		the "pseudo"-events HREG_EV_NO_CARD, HREG_EV_DUIF_RX
+	MSF-accessible fields of Result Block
+		IFB_RxLen			0 or Frame size as reported by LAN Controller
+		IFB_RxStat
+		IFB_MBInfoLen
+		IFB_PIFRscInd
+		IFB_DUIFRscInd
+		IFB_NotifyRscInd
+		IFB_HCF_Tallies
+
+
+.NARRATIVE
+	hcf_service_nic is primarily intended to be part of the Interrupt Service Routine.
+	hcf_service_nic is presumed to neither interrupt other HCF-tasks nor to be interrupted by other HCF-tasks.
+	A way to achieve this is to precede hcf_service_nic as well as all other HCF-tasks with a call to
+	hcf_action to disable the card interrupts and, after all work is completed, with a call to hcf_action to
+	restore (which is not necessarily the same as enabling) the card interrupts.
+	In case of a polled environment, it is assumed that the MSF programmer is sufficiently familiar with the
+	specific requirements of that environment to translate the interrupt strategy to a polled strategy.
+	
+	hcf_service_nic services the following Hermes events:
+		HREG_EV_INFO		Asynchronous Information Frame
+		HREG_EV_INFO_DROP	WMAC did not have sufficient RAM to build Unsolicited Information Frame
+		HREG_EV_ALLOC		Asynchronous part of Allocation/Reclaim completed
+		HREG_EV_RX			the detection of the availability of received messages
+
+	If a message is available, its length is reflected by the IFB_RxLen field of the IFB. This length
+	reflects the 802.3 message length (i.e. the data itself but not the Destination Address, Source Address,
+	DataLength field nor the SAP-header in case of decapsulation by the HCF).
+	If no message is available, IFB_RxLen is zero.
+
+  **Buffer free strategy
+	When hcf_service_nic reports the availability of a message, the MSF can access that message or parts
+	thereof, by means of hcf_get_data calls till the next call of hcf_service_nic. Therefore it must be
+	prevented that the LAN Controller writes new data in the buffer associated with the last hcf_service_nic
+	report.
+	As a consequence hcf_service_nic is the only procedure which can free receive buffers for re-use by the
+	LAN Controller. Freeing a buffer is done implicitly by acknowledging the Rx event to the Hermes. The
+	strategy of hcf_service_nic is to free the buffer it has reported as containing an available message in
+	the preceeding call (assuming there was an available message).
+	A consequence of this strategy is that the Interrupt Service Routine of the MSF must repeatedly call
+	hcf_service_nic till hcf_service_nic returns "no message available". It can be reasoned that
+	hcf_action( INT_ON ) should not be given before the MSF has completely processed a reported Rx-frame. The
+	reason is that the INT_ON action is guaranteed to cause a (Rx-)interrupt (the MSF is processing a
+	Rx-frame, hence the Rx-event bit in the Hermes register must be active). This interrupt will cause
+	hcf_service_nic to be called, which will cause the ack-ing of the "last" Rx-event to the Hermes,
+	causing the Hermes to discard the associated NIC RAM buffer.
+
+
+.DIAGRAM
+ 2: IFB_RxLen and IFB_RxStat must be cleared before the NIC presence check otherwise these values may stay
+ 	non-zero if the NIC is pulled out at an inconvenient moment
+ 4: If the card is not present, prevent all I/O because "our" I/O base may have been given away to someone
+	else in a CS/SS environment.
+	The MSF may have considerable latency in informing the HCF of the card removal by means of an hcf_disable.
+	To prevent that hcf_service_nic reports bogus information to the MSF with all - possibly difficult to
+	debug - undesirable side effects, hcf_service_nic pays performance wise the prize to use the momentanuous
+	NIC presence test by checking the contents of the Hermes register HREG_SW_0 against the value HCF_MAGIC.
+ 6:	The return status of hcf_service_nic is defined as reflecting all interrupt causes this call has run into,
+ 	hence an accumulator is needed. This return status services ONLY to help the MSF programmer to debug the
+ 	total system.
+ 	When the card is removed, the pseudo event HREG_EV_NO_CARD is reported.
+ 	NOTE, the HREG_EV_NO_CARD bit is explicitly not intended for the MSF to detect NIC removal. The MSF must
+ 	use its own - environment specific - means for that.
+10:	ack the "old" Rx-event. See "Buffer free strategy" above for more explanation.
+    IFB_RxFID, IFB_RxLen and IFB_RxStat must be cleared to bring both the internal HCF house keeping as the
+    information supplied to the MSF in the state "no frame received"
+12:	The evitable register of the Hermes is sampled and all non-Rx activities are handled.
+ 	The non-Rx activities are:
+	 -	Alloc.  The corresponding FID register is sampled, and based on this FID, either the IFB_PIFRscInd,
+	 	the IFB_DUIFRscInd or the IFB_NotifyRscInd is raised.
+	 	Note that no ASSERT is performed to check whether the RscInd corresponding with the sampled 
+	 	HREG_ALLOC_FID has a zero value. It is felt that this obscures the code to the reader while adding
+	 	little practical value
+	 -	LinkEvent (including solicited and unsolicited tallies) are handled by procedure isr_info.
+	 -	Info drop events are handled by incrementing a tally
+14:	All the non-Rx/non-Cmd activities are acknowledged. Combining all these acknowledgements to a single 
+	place, is considered an optimization.
+	Note that the Rx-acknowledgement is explicitly not included, as justified in "Buffer free strategy" above.
+	Note that the Cmd-acknowledgement is explicitly not included, because all command handling is handled 
+	in line.
+16:	The handling of the non-Rx activities, may have bought the Hermes sufficient time to raise an Rx event
+	in the evitable register (assuming an other Rx event was pending and this loop through hcf_service_nic
+	acknowledged an Rx event). Therefore the evitable register is sampled again. If a frame is available,
+	the FID of that frame and the characteristics (status and length) are read from the NIC. These values are, 
+	after Endianess conversion if needed, stored in IFB_RxStat and IFB_RxLen. IFB_RxLen is also adjusted for 
+	the size of the 802.3 MAC header. Note: Whether this adjustment is the correct/most optimal for 802.11
+	is debatable, however it is paramount that IFB_RxFID and IFB_RxLEN must either be both zero or both
+	non-zero to get a coherent behavior of the MSF+HCF.
+18:	If the Hermes frame status reflects an error - which can only occure in promiscuous mode - the frame
+	is not further processed and control is passed back to the MSF
+20:	WMP messages are processed by copying them to the MailBox. Accu is updated to reflect the reception
+	of the WMP frame to the debugger and sample is modified to go once more through the loop in the hope 
+	to process the next pending Rx frame.
+22: Both in 802.11 mode and 802.3_pure mode, the frame is not further processed (no decapsulation) and 
+	control is passed back to the MSF.
+	In 802.3 mode the HCF checks whether decaposulation is needed (i.e. the Hermes reported Tunnel
+	encapsulation or the Hermes reported 1042 Encapsulation and the frame type does not match one of the 
+	values in enc_trans_tbl.
+	The actual decapsulation takes place on the fly in hcf_get_data, based on the value of IFB_RxFence.
+	Note that in case of decapsulation the SNAP header is not passed to the MSF, hence IFB_RxLen must be 
+	compensated for the SNAP header length
+	
+.NOTICES
+    To make it possible to discriminate between a message without payload (only MAC addresses and implicit
+    the length) it is a convenient I/F to add 14 ( space occupied by MAC addresses and Length) to the
+    Hermes reported payload. So the maintenance programmer should be forwarned when considering changing
+    this strategy. Also the impact on 802.11 should be considered ;?
+.ENDOC				END DOCUMENTATION
+
+-------------------------------------------------------------------------------------------------------------*/
+int	hcf_service_nic(IFBP ifbp ) {
+
+int		accu = HREG_EV_NO_CARD;
+hcf_16	sample, tmp;
+
+
+    ifbp->IFB_RxLen = ifbp->IFB_RxStat = 0;																		/* 2 */
+	if ( ifbp->IFB_CardStat & CARD_STAT_PRESENT && IN_PORT_WORD( ifbp->IFB_IOBase + HREG_SW_0) == HCF_MAGIC ) {	/* 4 */
+		accu = 0;																								/* 6 */
+        if ( ifbp->IFB_RxFID ) {								    											/*10 */
+            OUT_PORT_WORD( ifbp->IFB_IOBase + HREG_EV_ACK, HREG_EV_RX );
+            ifbp->IFB_RxFID = ifbp->IFB_RxLen = ifbp->IFB_RxStat = 0;
+        }
+        sample = IN_PORT_WORD( ifbp->IFB_IOBase + HREG_EV_STAT );												/*12*/
+        accu |= sample;
+
+        if ( sample & HREG_EV_INFO )		isr_info( ifbp );
+        if ( sample & HREG_EV_ALLOC ) {
+            tmp = IN_PORT_WORD(ifbp->IFB_IOBase + HREG_ALLOC_FID );
+            if ( tmp == ifbp->IFB_PIF_FID ) ifbp->IFB_PIFRscInd = 1;
+            else if ( tmp == ifbp->IFB_DUIF_FID ) ifbp->IFB_DUIFRscInd = 1;
+                 else {
+                    ifbp->IFB_NotifyRscInd = 1;
+                 }
+        }
+        tmp = sample & (hcf_16)~(HREG_EV_RX | HREG_EV_CMD );													/*14 */
+        if ( tmp ) OUT_PORT_WORD( ifbp->IFB_IOBase + HREG_EV_ACK, tmp );
+
+        sample = IN_PORT_WORD( ifbp->IFB_IOBase + HREG_EV_STAT );												/*16 */
+        if ( sample & HREG_EV_RX ) {
+            ifbp->IFB_RxFID = IN_PORT_WORD( ifbp->IFB_IOBase + HREG_RX_FID);
+            (void)hcfio_string(ifbp, BAP_1, ifbp->IFB_RxFID, HFS_STAT_ABS, (wci_bufp)&ifbp->IFB_RxStat, 1, 2, IO_IN );
+            (void)hcfio_string(ifbp, BAP_1, ifbp->IFB_RxFID, HFS_DAT_LEN_ABS, (wci_bufp)&ifbp->IFB_RxLen, 1,2,IO_IN );
+            ifbp->IFB_RxLen += HFS_DAT;
+        }
+    }
+	return accu;
+}/* hcf_service_nic */
+
+
+
+
+
+/**************************************************************************************************************
+************************** H C F   S U P P O R T   R O U T I N E S ********************************************
+**************************************************************************************************************/
+
+
+
+/******************************************************************************************************************
+
+
+.MODULE			alloc
+.LIBRARY 		HCF_SUP
+.TYPE 			function
+.SYSTEM			msdos
+.SYSTEM			unix
+.SYSTEM			NW4
+.APPLICATION	Support for HCFR routines
+.DESCRIPTION	allocates a (TX or Notify) FID in NIC RAM and clears it
+
+.ARGUMENTS
+
+.RETURNS
+  0:	failure
+  <>0:	PIF value
+
+.NARRATIVE
+
+
+.DIAGRAM
+ 1:	execute the allocate command by calling cmd_wait
+ 2: wait till either the alloc event or a time-out occures
+ 3: if the alloc event occures,
+ 	- read the FID to return it to the caller of alloc
+ 	- acknowledge the alloc event
+ 	- clear the storage allocated in NIC RAM (see notice below)
+ 4:	since alloc is only called after an Hermes initialize command but before the Hermes enable, a failing
+	allocation is considered a H/W failure, hence the Miscellaneous Error tally is incremented
+	
+.NOTICE
+ o  Clearing the FID is not only an aesthetical matter, it is also the cheapest (code-size) way to enforce
+ 	  -	correlation between IFB_TxCntl (which is cleared by hcf_disable) and the field HFS_TX_CNTL_ABS of a
+ 		IFB_PIF_FID
+ 	  -	zero value of the field HFS_TX_CNTL_ABS of a IFB_DUIF_FID (hcf_send_diag_msg only supports port 0)
+ 	
+  Note that Card Interrupts are disabled as a side effect of hcf_disable when alloc is called.  This is a
+  necessary condition, otherwise the ISR can get control, causing hcf_service_nic to run.  This would
+  constitute an error because hcf_service_nic needs a defined IFB_PIF_FID and IFB_DUIF_FID to manipulate
+  IFB_PIFRscInd and IFB_DUIFRscInd
+
+  The put_info functions must be called before the alloc calls because of cnfMaxDataLength ;?Really, what is the catch
+ 	
+ 	
+.DIAGRAM
+.ENDOC				END DOCUMENTATION
+*/
+/*-----------------------------------------------------------------------------------------------------------*/
+hcf_16 alloc( IFBP ifbp, int len ) {
+
+hcf_32 prot_cnt = ifbp->IFB_TickIni;
+hcf_16 pif		= 0;
+hcf_16 zero		= 0;
+
+	if ( cmd_wait( ifbp, HCMD_ALLOC, len ) == HCF_SUCCESS ) {											/* 1 */
+		while ( prot_cnt ) {
+			prot_cnt--;
+			if ( IN_PORT_WORD(ifbp->IFB_IOBase + HREG_EV_STAT ) & HREG_EV_ALLOC ) {						/* 2 */
+				pif = IN_PORT_WORD(ifbp->IFB_IOBase + HREG_ALLOC_FID );									/* 3 */
+				OUT_PORT_WORD(ifbp->IFB_IOBase + HREG_EV_ACK, HREG_EV_ALLOC );
+				(void)hcfio_string( ifbp, BAP_0, pif, 0, (wci_bufp)&zero, 0, 2, IO_OUT );	//justify void
+				len = DIV_BY_2( len );
+				while ( --len ) OUT_PORT_WORD( ifbp->IFB_IOBase + BAP_0, 0 );
+				break;
+			}
+		}
+	}
+	return pif;
+}/* alloc */
+
+
+
+
+
+
+
+
+
+/******************************************************************************************************************
+
+.MODULE			calibrate
+.LIBRARY 		HCF_SUP
+.TYPE 			function
+.SYSTEM			msdos
+.SYSTEM			unix
+.SYSTEM			NW4
+.APPLICATION	Support for HCFR routines
+.DESCRIPTION	
+
+.ARGUMENTS
+  int calibrate( IFBP ifbp )
+	
+.RETURNS
+  HCF_SUCCESS
+  HCF_ERR_TIME_OUT
+  HCF_..... (via hcf_put_info)
+
+.NARRATIVE
+  o
+  o
+
+
+.DIAGRAM
+ 1:	
+ 2:
+ 	
+.NOTICE
+ o
+ 	
+.DIAGRAM
+.ENDOC				END DOCUMENTATION
+*/
+/*-----------------------------------------------------------------------------------------------------------*/
+int calibrate( IFBP ifbp ) {
+
+LTV_STRCT	x;					// initialization with "= { 2, CFG_TICK_TIME};" causes memset 
+								// to be used under some compilers
+int			cnt = 10;
+int			rc = HCF_SUCCESS;
+hcf_32		prot_cnt;
+
+//	if ( ifbp->IFB_TickIni == 0 ) {										                        	/* 22*/
+	x.len = 2;
+	x.typ = CFG_TICK_TIME;
+	x.val[0] = CNV_LITTLE_TO_INT( 8 );	//no compile time conversion available
+	rc = hcf_put_info( ifbp, &x );
+	ifbp->IFB_TickIni = 0;												                        	/* 22*/
+	while ( rc == HCF_SUCCESS && --cnt ) {
+		prot_cnt = 0;
+		OUT_PORT_WORD( ifbp->IFB_IOBase + HREG_EV_ACK, HREG_EV_TICK );
+		while ( (IN_PORT_WORD( ifbp->IFB_IOBase + HREG_EV_STAT ) & HREG_EV_TICK) == 0 &&
+				++prot_cnt <= INI_TICK_INI ) /*NOP*/;
+		ifbp->IFB_TickIni = max( ifbp->IFB_TickIni, prot_cnt);
+	}
+	if ( ifbp->IFB_TickIni == INI_TICK_INI ) rc = HCF_ERR_TIME_OUT;
+	ifbp->IFB_TickIni *= 128;						//time out value of 8*128 = 1024 k microseconds
+//	}
+	x.val[0] = CNV_LITTLE_TO_INT( ONE_SECOND );
+	rc = hcf_put_info( ifbp, &x );
+	return rc;
+} /* calibrate */
+
+
+
+
+
+
+/**************************************************************************************************************
+
+
+.MODULE			cmd_wait
+.LIBRARY 		HCF_SUP
+.TYPE 			function
+.SYSTEM			msdos
+.SYSTEM			unix
+.SYSTEM			NW4
+.APPLICATION	Support for HCFR routines
+.DESCRIPTION
+
+.ARGUMENTS
+
+.RETURNS
+  hcf_16
+	HCF_SUCCESS
+	HCF_ERR_TIME_OUT
+	HCF_FAILURE
+	HCF_ERR_BUSY
+	
+.NARRATIVE
+.DIAGRAM
+
+ 1:	the test on rc checks whether a BAP initialization or a call to cmd_wait did ever fail. If so, the Hermes
+	is assumed inoperable/defect, and all subsequent bap_ini/cmd_wait calls are nullified till hcf_disable
+	clears the IFB_TimStat field.
+ 	
+ 2:	Based on the Hermes design, the read of the busy bit is superfluous because we wait for the Cmd bit in
+	the Event Status register.
+
+ 3:	When the Hermes reports on another command than the Host just issued, the two are apparently out of
+ 	sync and all bets are off about the consequences. Therefore this situation is treated the same as an
+ 	Hermes failure as indicated by time-out (blocking all further bap_ini/cmd_wait calls till hcf_disable.
+ 	
+ 5:	If HREG_STAT reflects an error it is either an HCF bug or a H/W problem. Since
+	no distinction can be made at forehand, the "vague" HCF_FAILURE code is used
+	
+.NOTICE
+	Due to the general HCF strategy to wait for command completion, a 2nd command can never be excuted
+	overlapping a previous command. As a consequence the Hermes requirement that no Inquiry command may be
+	executed if there is still an unacknowledged Inquiry command outstanding, is automatically met.
+	However, there are two pseudo-asynchronous commands (Diagnose and Download) which do not adhere to this
+	general HCF strategy. In that case we rely on the MSF to do not overlap these commands, but no protection
+	is offered by the HCF
+.ENDOC				END DOCUMENTATION
+*/
+/* -------------------------------------------------------------------------------------------------------------------*/
+int cmd_wait( IFBP ifbp, int cmd_code, int par_0 ) {
+
+int		rc = ifbp->IFB_TimStat;
+hcf_32	prot_cnt = ifbp->IFB_TickIni;
+
+
+	if ( rc == HCF_SUCCESS ) {																			/* 1 */
+		OUT_PORT_WORD( ifbp->IFB_IOBase + HREG_PARAM_0, par_0 );
+		OUT_PORT_WORD( ifbp->IFB_IOBase + HREG_CMD, cmd_code );
+		while (prot_cnt && (IN_PORT_WORD(ifbp->IFB_IOBase + HREG_EV_STAT) & HREG_EV_CMD) == 0 ) prot_cnt--;/*2 */
+		if ( prot_cnt == 0 ) {
+			rc = ifbp->IFB_TimStat = HCF_ERR_TIME_OUT;
+		} else {
+			rc = IN_PORT_WORD( ifbp->IFB_IOBase + HREG_STAT );
+			OUT_PORT_WORD( ifbp->IFB_IOBase + HREG_EV_ACK, HREG_EV_CMD );
+			if ( (rc ^ cmd_code) & HREG_STAT_CMD_CODE ) {												/* 3 */
+				rc = ifbp->IFB_TimStat = HCF_FAILURE;
+			} else {
+				rc &= HREG_STAT_CMD_RESULT;									//Hermes defined Result Code
+			}
+			if ( rc ) rc = HCF_FAILURE;																	/* 5 */
+		}
+	}
+	return rc;
+}/* cmd_wait */
+
+
+
+/***********************************************************************************************************************
+
+
+ Name:	enable_int
+
+ Summary: Enables a specific Hermes interrupt
+
+ Parameters:
+  ifbp	address of the Interface Block
+  event	Hermes event to be enabled as interrupt source
+
+ Remarks: To get the contents of the IntEn register changed is a two step process:
+
+ 	o change the "shadow" in IFB_IntEnMask
+
+ 	o call hcf_action to actually copy the shadow to the IntEn register.
+
+ 	To prevent a change in the "Card Interrupt En/Disabled state, a balancing
+ 	pair of HCF_ACT_INT_OFF and HCF_ACT_INT_ON must be used. To prevent
+ 	a temporary enabling as undesirable side effect, the first call must be
+ 	HCF_ACT_INT_OFF.
+ 	Note that at the very first interrupt, hcf_service_nic causes the removal of
+ 	the Tick and Cmd bit in the IntEn register.
+ 	
+ 	
+.DIAGRAM
+***********************************************************************************************************************/
+//#pragma  Reminder2( "enable_int: shouldn't this be used in more places" )
+void	enable_int(IFBP ifbp, int event ) {
+
+	ifbp->IFB_IntEnMask |= event;
+	(void)hcf_action( ifbp, HCF_ACT_INT_OFF );
+	(void)hcf_action( ifbp, HCF_ACT_INT_ON );
+	return;
+
+}/* enable_int */
+
+
+
+
+
+/****************************************************************************************************************************
+
+
+.MODULE			ini_hermes
+.LIBRARY 		HCF_SUP
+.TYPE 			function
+.SYSTEM			msdos
+.SYSTEM			unix
+.SYSTEM			NW4
+.APPLICATION	Support for HCF routines
+.DESCRIPTION
+
+.ARGUMENTS
+
+.RETURNS
+  void
+            
+            
+	As side effect of the Hermes Initialize command, the interrupts are disabled            
+.NARRATIVE
+ 1:	
+ 2:	
+.DIAGRAM
+
+.ENDOC				END DOCUMENTATION
+-------------------------------------------------------------------------------------------------------------*/
+int ini_hermes( IFBP ifbp ) {
+
+int		rc = HCF_ERR_NO_NIC;
+//hcf_32	prot_cnt  = ifbp->IFB_TickIni = INI_TICK_INI;	//initialize at best guess before calibration
+hcf_32	prot_cnt;
+
+    if ( ifbp->IFB_CardStat & CARD_STAT_PRESENT ) {//present										/* 7 */
+		if ( ifbp->IFB_TickIni == 0)  ifbp->IFB_TickIni = INI_TICK_INI;	//initialize at best guess before calibration
+		prot_cnt  = ifbp->IFB_TickIni;
+		while (prot_cnt && IN_PORT_WORD(ifbp->IFB_IOBase + HREG_CMD ) & HCMD_BUSY ) prot_cnt--;		/* 16*/
+			
+		rc = HCF_ERR_TIME_OUT;
+		if ( prot_cnt != 0 ) {
+			rc = cmd_wait( ifbp, HCMD_INI, 0 );														/* 18*/
+			OUT_PORT_WORD( ifbp->IFB_IOBase + HREG_EV_ACK, 0xFFFF );
+		}
+
+	}
+	return rc;
+}/* ini_hermes */
+
+
+/****************************************************************************************************************************
+
+
+.MODULE			isr_info
+.LIBRARY 		HCF_SUP
+.TYPE 			function
+.SYSTEM			msdos
+.SYSTEM			unix
+.SYSTEM			NW4
+.APPLICATION	Support for HCF routines
+.DESCRIPTION
+
+.ARGUMENTS
+
+.RETURNS
+  void
+
+.NARRATIVE
+ 1:	info[0] becomes the length of the T-field + the length of the Value-field in words. Note that it is
+	dangerous to determine the length of the Value field by decrementing info[0], because if -e.g. as a
+	result of a bug in the Hermes as has happened in real life- info[0] becomes 0, a decrement results in
+	a very large number. Therefore all code is crafted around an unchanged info[0], with the intention to
+	make the HCF more robust against I/F violations.
+ 2:	This is an example of the strategy described in #1 above. Info[0] is expected to be HCF_NIC_TAL_CNT + 1.
+	By using a pre-decrement, this value results in HCF_NIC_TAL_CNT movements of a single tally value into
+	the IFB_NIC_Tallies area of the IFB.
+ 3:	Although put_info_mb is robust against a len-parameter with value zero, it accepts any bogus value
+	for the type-parameter.
+.DIAGRAM
+
+.ENDOC				END DOCUMENTATION
+-------------------------------------------------------------------------------------------------------------*/
+void isr_info( IFBP ifbp ) {
+
+hcf_16	info[2], tmp;
+hcf_32	*p;
+
+	tmp = IN_PORT_WORD( ifbp->IFB_IOBase + HREG_INFO_FID );
+	(void)hcfio_string(ifbp, BAP_1, tmp, 0, (wci_bufp)info, 2, sizeof(info), IO_IN );						/* 1 */
+	
+	if ( info[1] == CFG_TALLIES ) {
+		if ( info[0] > HCF_NIC_TAL_CNT ) info[0] = HCF_NIC_TAL_CNT + 1;										/* 2 */
+		p = (hcf_32*)&ifbp->IFB_NIC_Tallies;//.TxUnicastFrames;
+		while ( --info[0] ) *p++ += IN_PORT_WORD( ifbp->IFB_IOBase + BAP_1 );
+	}
+	return;
+}/* isr_info */
+
+
+
+
+
+
+#if defined _M_I86TM
+#endif //_M_I86TM
+
+/***********************************************************************************************************************
+
+
+ Name:	put_info
+
+ Summary: stores Hermes configuration information in the ConfigTable of the IFB
+
+ Parameters:
+  ifbp	address of the Interface Block
+  ltvp	address in NIC RAM where LVT-records are located
+
+
+.NARRATIVE
+
+**************************************************************************************************************/
+int put_info( IFBP ifbp, LTVP ltvp	) {
+
+int					cnt = 3;
+//hcf_16				i = ltvp->len - 1;
+int					rc = HCF_SUCCESS;
+
+	
+	if ( ifbp->IFB_CardStat & CARD_STAT_PRESENT ) {
+	
+
+		do {
+			rc = hcfio_string( ifbp, BAP_1,
+							   ltvp->typ, 0, (wci_bufp)ltvp, 2, MUL_BY_2(ltvp->len + 1), IO_OUT_CHECK );
+		} while ( cnt-- && rc != HCF_SUCCESS );
+		if ( rc == HCF_SUCCESS ) rc = cmd_wait( ifbp, HCMD_ACCESS + HCMD_ACCESS_WRITE, ltvp->typ );
+	}	
+	
+	return rc;
+}/* put_info */
+
+
+
+
+
+
+
Index: oldkernel/linux/pcmcia-cs-3.1.15/wireless/wvlan_hcf.h
diff -u /dev/null linux/pcmcia-cs-3.1.15/wireless/wvlan_hcf.h:1.1
--- /dev/null	Mon Jul 31 21:15:12 2000
+++ linux/pcmcia-cs-3.1.15/wireless/wvlan_hcf.h	Fri Jul  7 16:34:59 2000
@@ -0,0 +1,287 @@
+/* This file is part of the Hardware Control Functions Light (HCF-light) library
+   to control the Lucent Technologies WaveLAN/IEEE Network I/F Card.
+   The HCF is the implementation of the Wireless Connection I/F (WCI).
+   
+   The HCF-light files are a subset of the HCF files. The complete set offers a
+   number of additional facilities, e.g. firmware download, Etherner-II encapsulation,
+   additional diagnostic facilities, ASSERT logic to support debugging, 802.11 support,
+   Configuration Management.
+   This complete set is explicitely not in the Public Domain but can be made 
+   available under certain restriction. (see the pointer below for support)
+   
+   The HCF-light files are 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. 
+   
+   At the time of this writing, you can request for support at:
+   betasupport@wavelan.com
+   
+   Documentation is expected to be available in the week of 8 Februari 1999
+
+*/
+
+
+#ifndef HCF_H
+#define HCF_H 1
+
+/*************************************************************************************************************
+*
+* FILE	 : hcf.h *************** 2.0 *************************************************************************
+*
+* DATE   : 2000/01/06 23:30:52   1.2
+*
+* AUTHOR : Nico Valster
+*
+* DESC   : Definitions and Prototypes for MSF as well as HCF sources
+*
+*			Customizable via HCFCFG.H
+*
+*
+**************************************************************************************************************
+Instructions to convert HCF.H to HCF.INC by means of H2INC
+
+Use a command line which defines the specific macros and command line options
+needed to build the C-part, e.g. for the DOS ODI driver
+		`h2inc /C /Ni /Zp /Zn hcf	 hcf.h`
+
+
+**************************************************************************************************************
+* COPYRIGHT (c) 1996, 1997, 1998 by Lucent Technologies.	 All Rights Reserved.
+**************************************************************************************************************/
+
+/****************************************************************************
+wvlan_hcf.h,v
+Revision 1.2  2000/01/06 23:30:52  root
+*** empty log message ***
+
+ * 
+ *    Rev 1.0   02 Feb 1999 14:32:30   NVALST
+ * Initial revision.
+Revision 1.2  1999/02/01 22:58:35  nico
+*** empty log message ***
+
+Revision 1.1  1999/01/30 19:24:39  nico
+Initial revision
+
+Revision 1.1  1999/01/30 19:07:57  nico
+Initial revision
+
+ * 
+ *    Rev 1.110   29 Jan 1999 15:52:42   NVALST
+ * intermediate, maybe working but seems to need two times to load in 
+ * light-version
+ * 
+ *    Rev 2.12   29 Jan 1999 10:48:44   NVALST
+ * 
+ *    Rev 1.108   28 Jan 1999 14:43:22   NVALST
+ * 
+****************************************************************************/
+
+/**************************************************************************************************************
+*
+* CHANGE HISTORY
+*
+  961018 - NV
+	Original Entry
+
+*************************************************************************************************************/
+
+
+                                                                                                            
+#include "wvlan_hcfcfg.h"	// System Constants to be defined by the MSF-programmer to tailor the HCF
+#include <stddef.h> //do not move to hcf.cpp to keep Chris (Borland) and Marc (MSVC 4)happy (defines NULL)
+
+#include "wvlan_mdd.h"	// Include file common for HCF, MSF, UIL, USF
+
+/************************************************************************************************************/
+/******************   H C F  F U N C T I O N   P A R A M E T E R	 ****************************************/
+/************************************************************************************************************/
+
+//offsets for hcf_put_data and hcf_get_data
+				
+
+// 802.3/E-II/802.11 offsets to access Hermes control fields
+#define HFS_STAT				-0x2E	//0x0000
+#define 	HFS_STAT_ERR		RX_STAT_ERR	//link "natural" HCF name to "natural" MSF name
+
+#define HFS_Q_INFO				-0x28	//0x0006
+#define HFS_TX_CNTL				-0x22	//0x000C
+#define HFS_FRAME_CNTL			-0x20	//0x000E
+#define HFS_ID					-0x1E	//0x0010
+
+// 802.11 relative offsets to access 802.11 header fields 
+#define HFS_ADDR_1				0x00	//0x0012
+#define HFS_ADDR_2				0x06	//0x0018
+#define HFS_ADDR_3				0x0C	//0x001E
+#define HFS_SEQ_CNTL			0x12	//0x0024
+#define HFS_ADDR_4				0x14	//0x0026
+#define HFS_DAT_LEN				0x1A	//0x002C
+
+// 802.3 / E-II relative offsets to access 802.3 header fields
+#define HFS_ADDR_DEST			0x00	//0x002E
+#define HFS_ADDR_SRC			0x06	//0x0034
+#define HFS_LEN					0x0C	//0x003A
+#define HFS_DAT					0x0E	//0x003C
+
+// E-II relative offsets to access SNAP header fields
+#define HFS_TYPE				0x14	//0x0042	//Eternet-II type in 1042/Bridge-Tunnel encapsulated frame
+
+
+//#define HCF_ACT_INT_PENDING	0x0001		//interrupt pending, return status HCF_ACT_INT_OFF
+
+
+
+/*************************************************************************************************************/
+/****************   H C F  F U N C T I O N   R E T U R N   C O D E S   ***************************************/
+/*************************************************************************************************************/
+
+//Debug Purposes only				!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
+#define HREG_EV_TICK		0x8000	//WMAC Controller Auxiliary Timer Tick
+#define HREG_EV_RES			0x4000	//WMAC Controller H/W error (Wait Time-out)
+#define HREG_EV_INFO_DROP	0x2000	//WMAC did not have sufficient RAM to build Unsollicited Frame
+#define HREG_EV_NO_CARD		0x0800	/* PSEUDO event: card removed											  */
+#define HREG_EV_DUIF_RX     0x0400  /* PSEUDO event: WMP frame received										  */
+#define HREG_EV_INFO		0x0080	//WMAC Controller Asynchronous Information Frame
+#define HREG_EV_CMD			0x0010	//WMAC Controller Command completed, Status and Response avaialble
+#define HREG_EV_ALLOC		0x0008	//WMAC Controller Asynchronous part of Allocation/Reclaim completed
+#define HREG_EV_TX_EXC		0x0004	//WMAC Controller Asynchronous Transmission unsuccessful completed
+#define HREG_EV_TX			0x0002	//WMAC Controller Asynchronous Transmission successful completed
+#define HREG_EV_RX			0x0001	//WMAC Controller Asynchronous Receive Frame
+
+
+
+//=========================================  T A L L I E S  ===================================================
+
+typedef struct CFG_HERMES_TALLIES_STRCT {  //Hermes Tallies (IFB substructure)
+  hcf_32	TxUnicastFrames;
+  hcf_32	TxMulticastFrames;
+  hcf_32	TxFragments;
+  hcf_32	TxUnicastOctets;
+  hcf_32	TxMulticastOctets;
+  hcf_32	TxDeferredTransmissions;
+  hcf_32	TxSingleRetryFrames;
+  hcf_32	TxMultipleRetryFrames;
+  hcf_32	TxRetryLimitExceeded;
+  hcf_32	TxDiscards;
+  hcf_32	RxUnicastFrames;
+  hcf_32	RxMulticastFrames;
+  hcf_32	RxFragments;
+  hcf_32	RxUnicastOctets;
+  hcf_32	RxMulticastOctets;
+  hcf_32	RxFCSErrors;
+  hcf_32	RxDiscards_NoBuffer;
+  hcf_32	TxDiscardsWrongSA;
+  hcf_32	RxWEPUndecryptable;
+  hcf_32	RxMsgInMsgFragments;
+  hcf_32	RxMsgInBadMsgFragments;
+}CFG_HERMES_TALLIES_STRCT;
+
+
+//Note this way to define CFG_TALLIES_STRCT_SIZE implies that all tallies must keep the same (hcf_32) size
+#define		HCF_NIC_TAL_CNT	(sizeof(CFG_HERMES_TALLIES_STRCT)/ sizeof(hcf_32))
+#define		HCF_TOT_TAL_CNT	(HCF_NIC_TAL_CNT)
+
+/************************************************************************************************************/
+/***********   W C I    F U N C T I O N S    P R O T O T Y P E S   ******************************************/
+/************************************************************************************************************/
+
+#define IFB_VERSION 0x82	 			/* initially 80, to be incremented by every IFB layout change		*/
+
+
+
+/* identifier IFB_STRCT on typedef line needed to get the individual fields in the MS Browser DataBase	*/
+typedef struct IFB_STRCT{               //I/F Block
+/* MSF readable part of Result block structure							*************************************/
+  hcf_io		IFB_IOBase;				/* I/O address of Hermes chip as passed by MSF at hcf_connect call	*/
+#if defined HCF_PORT_IO
+  hcf_16		IFB_IOBase_pad;			// Optional field, makes IFB-layout independent of IFB_IOBase size
+#endif //HCF_PORT_IO
+  hcf_16		IFB_IORange;			// I/O Range used by Hermes chip
+  hcf_8			IFB_Version;			/* initially 0, to be incremented by every IFB layout change		*/
+  hcf_8			IFB_Slack_2;			/* align/slack space												*/
+  hcf_8			IFB_HCFVersionMajor;	// Major version of the HCF.0x01 for this release
+  hcf_8			IFB_HCFVersionMinor;	/* Minor version of the HCF.  Incremented for each coding maintenance 
+  										 * cycle. 0x01 for the Initial release								*/
+  CFG_HERMES_TALLIES_STRCT	IFB_NIC_Tallies;	//Hermes tallies
+
+/* part I (survives hcf_disable)    ************************************************************************/
+  hcf_16		IFB_CardStat;			/* see Design spec													*/
+  hcf_16		IFB_FSBase;				// frame type dependent offset (HFS_ADDR_1_ABS or HFS_ADDR_DEST_ABS)
+  hcf_16		IFB_RxFence;			// frame type dependent gap fence (HFS_ADDR_DEST_ABS or HFS_LEN_ABS)
+  hcf_16		IFB_IntOffCnt;			/* see Design spec													*/
+  hcf_32	 	IFB_TickIni;			/* initialization of counter for 1 ms processor loop				*/
+  										/* keep this unsigned otherwise the "clever" ASSERT in hcf_disable 
+  										 * has a higher risk to get into trouble on slow machines
+  										 * keep this hcf_16 to prevent a "close to infinity" time out if
+  										 * calibration fails on 32-bits machine								*/
+  hcf_16		IFB_Magic;				/* see Design spec													*/
+  hcf_16		IFB_Slack_4[2];			/* align/slack space												*/
+
+/* part II (cleared or re-initialized at hcf_disable/hcf_enable)   *****************************************/
+  hcf_8  		IFB_PIFRscInd;			/* see Design spec   //;?Q:int better than hcf_8 A: No!				*/
+  hcf_8			IFB_DUIFRscInd;			/* Value indicating the command resource availability for the 
+  										 * Driver-Utility I/F (i.e. hcf_send_diag_msg).						*/
+  										/* Values: */                                                       
+  										/* * No command resource		0									*/
+  										/* * Command resource available	01h-FFh								*/
+  hcf_8  		IFB_NotifyRscInd;		/* see Design spec   //;?Q:int better than hcf_8 A: No!				*/
+  hcf_8			IFB_Slack_6;			/* align/slack space												*/
+  hcf_16		IFB_PIF_FID;			/* see Design spec													*/
+  hcf_16		IFB_DUIF_FID;			/* field which contains FID value identifying the Tx Frame Structure,
+  										 * to be used by hcf_send_diag_msg									*/
+  hcf_16		IFB_Notify_FID;			/* field which contains FID value identifying the Notify Frame Struct
+  										 * to be used by hcf_put_info in case of Notify type codes			*/
+  hcf_16		IFB_RxFID;				/* see Design spec													*/
+  hcf_16		IFB_MB_FID;				/* pass appropriate FID to hcf_put_mb_info							*/
+  hcf_16		IFB_TxFrameType;		/* see Design spec													*/
+  hcf_16		IFB_RxLen;				/* see Design spec													*/
+  hcf_16		IFB_RxStat;				/* see Design spec													*/
+  hcf_16		IFB_UnloadIdx;			/* see Design spec													*/
+  hcf_16		IFB_PIFLoadIdx;			/* see Design spec													*/
+  hcf_8 		IFB_TxCntl[2];			/* contents of HFS_TX_CNTL field of TFS
+  										 * 0: MACPort, 1: StrucType,TxEx,TxOK								*/
+  hcf_16		IFB_BAP_0[2];			/* offset
+  										 * RID/FID															*/
+  hcf_16		IFB_BAP_1[2];			/* offset
+  										 * RID/FID															*/
+  hcf_16		IFB_IntEnMask;			/* see Design spec													*/
+  hcf_16		IFB_TimStat;			/* BAP initialization or Cmd Completion failed once					*/
+
+}IFB_STRCT;
+
+
+
+typedef IFB_STRCT*	IFBP;
+
+
+EXTERN_C int	hcf_action			(IFBP ifbp, hcf_action_cmd cmd );
+EXTERN_C void	hcf_assert			(IFBP ifbp, wci_bufp file_name, unsigned int line_number, int q );
+EXTERN_C void	hcf_connect			(IFBP ifbp, hcf_io io_base );
+EXTERN_C int	hcf_disable			(IFBP ifbp, hcf_16 port );
+EXTERN_C void	hcf_disconnect		(IFBP ifbp );
+EXTERN_C int	hcf_enable			(IFBP ifbp, hcf_16 port );
+EXTERN_C int	hcf_get_info		(IFBP ifbp, LTVP ltvp );
+EXTERN_C int	hcf_get_data		(IFBP ifbp, int offset, wci_bufp bufp, int len );
+EXTERN_C int	hcf_service_nic		(IFBP ifbp );
+//EXTERN_C void	hcf_put_data		(IFBP ifbp, wci_bufp bufp, int len );
+EXTERN_C void	hcf_put_data		(IFBP ifbp, wci_bufp bufp, int len, hcf_16 port );
+EXTERN_C int	hcf_put_info		(IFBP ifbp, LTVP ltvp );
+EXTERN_C int	hcf_put_header		(IFBP ifbp, int offset, wci_bufp bufp, int len, hcf_8 check );
+EXTERN_C int	hcf_send			(IFBP ifbp, hcf_16 type );
+EXTERN_C int	hcf_send_diag_msg	(IFBP ifbp, hcf_16 type, wci_bufp bufp, int len );
+
+
+
+
+#endif  /* HCF_H */
+
Index: oldkernel/linux/pcmcia-cs-3.1.15/wireless/wvlan_hcfcfg.h
diff -u /dev/null linux/pcmcia-cs-3.1.15/wireless/wvlan_hcfcfg.h:1.1
--- /dev/null	Mon Jul 31 21:15:12 2000
+++ linux/pcmcia-cs-3.1.15/wireless/wvlan_hcfcfg.h	Fri Jul  7 16:34:59 2000
@@ -0,0 +1,1083 @@
+/* This file is part of the Hardware Control Functions Light (HCF-light) library
+   to control the Lucent Technologies WaveLAN/IEEE Network I/F Card.
+   The HCF is the implementation of the Wireless Connection I/F (WCI).
+   
+   The HCF-light files are a subset of the HCF files. The complete set offers a
+   number of additional facilities, e.g. firmware download, Etherner-II encapsulation,
+   additional diagnostic facilities, ASSERT logic to support debugging, 802.11 support,
+   Configuration Management.
+   This complete set is explicitely not in the Public Domain but can be made 
+   available under certain restriction. (see the pointer below for support)
+   
+   The HCF-light files are 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. 
+   
+   At the time of this writing, you can request for support at:
+   betasupport@wavelan.com
+   
+   Documentation is expected to be available in the week of 8 Februari 1999
+
+*/
+
+
+#ifndef HCFCFG_H                                                     
+#define HCFCFG_H 1
+
+/**************************************************************************************************************
+*
+* FILE	 : hcfcfg.tpl // hcfcfg.h **************************** 2.0 ********************************************
+*
+* DATE   : 2000/01/06 23:30:52   1.2
+*
+* AUTHOR : Nico Valster
+*
+* DESC   : HCF Customization Macros
+*
+***************************************************************************************************************
+* COPYRIGHT (c) 1994, 1995		 by AT&T.	 				All Rights Reserved.
+* COPYRIGHT (c) 1996, 1997, 1998 by Lucent Technologies.	All Rights Reserved.
+*
+***************************************************************************************************************
+*
+* hcfcfg.tpl list all #defines which must be specified to:
+*    I:	adjust the HCF functions defined in HCF.CPP to the characteristics of a specific environment
+* 		o maximum sizes for messages and notification frames, persistent configuration storage
+* 		o Endianess
+*
+*	II:	Compiler specific macros
+* 		o port I/O macros
+* 		o type definitions
+*
+*  III:	Environment specific ASSERT macro
+*
+*   IV: Compiler specific 
+*
+*    V: ;? specific 
+*
+*
+* By copying HCFCFG.TPL to HCFCFG.H and -if needed- modifying the #defines the WCI functionality can be 
+* tailored
+* T O   D O :  A D D   A   R E C I P E   T O   D O   T H I S
+*
+**************************************************************************************************************/
+
+/****************************************************************************
+wvlan_hcfcfg.h,v
+Revision 1.2  2000/01/06 23:30:52  root
+*** empty log message ***
+
+ * 
+ *    Rev 1.0   02 Feb 1999 14:32:32   NVALST
+ * Initial revision.
+Revision 1.2  1999/02/01 21:01:41  nico
+*** empty log message ***
+
+Revision 1.1  1999/01/30 19:24:39  nico
+Initial revision
+
+Revision 1.1  1999/01/30 19:07:57  nico
+Initial revision
+
+ * 
+ *    Rev 1.110   29 Jan 1999 15:52:44   NVALST
+ * intermediate, maybe working but seems to need two times to load in 
+ * light-version
+ * 
+ *    Rev 1.109   29 Jan 1999 12:50:26   NVALST
+ * intermediate
+ * 
+ *    Rev 1.108   28 Jan 1999 14:43:24   NVALST
+ * intermediate, once more correction of loop in hcf_service_nic + download
+ * passed to Marc
+ * 
+ *    Rev 1.107   27 Jan 1999 13:53:24   NVALST
+ * intermediate, once more correction of loop in hcf_service_nic
+ * 
+ *    Rev 1.106   26 Jan 1999 16:42:46   NVALST
+ * intermediate, corrected loop in hcf_service_nic (which was as result of a 
+ * walkthrough, changed from a bug without consequences into one with consequences
+ * 
+ *    Rev 1.105   25 Jan 1999 14:24:48   NVALST
+ * intermediate, hopefully suitable for release
+ * 
+ *    Rev 1.104   22 Jan 1999 16:59:34   NVALST
+ * intermediate, minor corrections + some HCF-L stuff
+ * 
+ *    Rev 1.103   15 Jan 1999 15:14:46   NVALST
+ * intermediate, deposited as HCF2.10
+ * 
+*************************************************************************************************/
+
+
+/****************************************************************************
+*
+* CHANGE HISTORY
+*
+
+  960702 - NV
+	Original Entry - derived from HCF 2.12
+*************************************************************************************************/
+
+
+/*  * * * * * * * * * * * * * * * * * * * * * *  I * * * * * * * * * * * * * * * * * * * * * * */
+
+/*	Endianess
+ *	Default: HCF_LITTLE_ENDIAN
+ *	Little Endian (a.k.a. Intel), least significant byte first
+ *	Big Endian (a.k.a. Motorola), most significant byte first
+ *
+ * If neither HCF_LITTLE_ENDIAN nor HCF_BIG_ENDIAN, the defintion of the following macros must be supplied
+ * by the MSF programmer:
+ *  o CNV_LITTLE_TO_INT(w)			interprets the 16-bits input value as Little Endian, returns an hcf_16
+ * 	o CNV_BIG_TO_INT(w)				interprets the 16-bits input value as Big Endian, returns an hcf_16
+ * 	o CNV_INT_TO_BIG_NP(addr)		converts in place the 16-bit value addressed by a near pointer from hcf_16
+ * 									to Big Endian
+ * 	o CNV_LITTLE_TO_INT_NP(addr)	converts in place the 16-bit value addressed by a near pointer from 
+ *									Little endian to hcf_16
+ *
+ * At a number of places in the HCF code, the CNV_INT_TO_BIG_NP macro is used. While it does have the desired 
+ * effect on all platforms, it's naming is misleading, so revisit all places where these CNV macros are used
+ * to assure the right name is used at the right place.
+ * Hint: introduce CNV_HOST_TO_NETWORK names if appropriate
+ *
+ */
+ 
+#define HCF_LITTLE_ENDIAN			// selects Little Endian (a.k.a. Intel), least significant byte first
+//#define HCF_BIG_ENDIAN				// selects Big Endian (a.k.a. Motorola), most significant byte first
+
+/*	I/O Address size
+ *	Platforms which use port mapped I/O will (in general) have a 64k I/O space, conveniently expressed in
+ *	a 16-bits quantity
+ *	Platforms which use memory mapped I/O will (in general) have an I/O space much larger than 64k,
+ *	and need a 32-bits quantity to express the I/O base
+ *	To accomodate this the macros HCF_PORT_IO and HCF_MEM_IO are available. Exactly 1 of these must be
+ *	defined. If HCF_PORT_IO is defined, the HCF will use an hcf_16 to express I/O base and store in the
+ *	IFB. If HCF_MEM_IO, an hcf_32 is used for this purpose. The default is HCF_PORT_IO
+ */
+#define HCF_PORT_IO
+//#define HCF_MEM_IO
+
+/*	Alignment
+ *	Some platforms can access words on odd boundaries (with possibly an performance impact), at other
+ *	platforms such an access may result in a memory access violation.
+ *	It is assumed that everywhere where the HCF casts a char pointer into a word pointer, the 
+ *	alignment criteria are met. This put some restrictions on the MSF, which are assumed to be 
+ *	"automatically" fullfilled at the applicable platforms
+ *	To assert this assumption, the macro HCF_ALIGN can be defined. The default vaslue is 0, meaning no
+ *	alignment, a value of 2 means word alignment, other values are invalid
+ */
+
+/*  * * * * * * * * * * * * * * * * * * * * * * II * * * * * * * * * * * * * * * * * * * * * * */
+
+
+
+/************************************************************************************************/
+/******************  C O M P I L E R   S P E C I F I C   M A C R O S  ***************************/
+/************************************************************************************************/
+/*************************************************************************************************
+*
+* The platforms supported by this version are:
+*	- Microsoft Visual C 1.5 (16 bits platform)
+*	- Microsoft Visual C 2.0 (32 bits platform)
+*	- Watcom C/C++ 9.5
+*	- SCO UNIX
+*
+* In this version of hcfiocfg.tpl all macros except the MSVC 1.5 versions are either dependent on
+* compiler/environment supplied macros (e.g. _MSC_VER or "def-ed out"
+*
+* By selecting the appropriate Macro definitions by means of modifying the
+* "#ifdef 0/1" lines, the HCF can be adjusted for the I/O chararcteristics of
+* a specific compiler
+*
+* If needed the macros can be modified or replaced with definitions appropriate
+* for your personal platform
+* If you need to make such changes it is appreciated if you inform Lucent Technologies WCND Utrecht
+* That way the changes can become part of the next release of the WCI
+*
+*
+*	The prototypes and functional description of the macros are:
+*
+*	hcf_8	IN_PORT_BYTE(  hcf_16 port)
+*			Reads a byte (8 bits) from the specified port
+*
+*	hcf_16	IN_PORT_WORD(  hcf_16 port)
+*			Reads a word (16 bits) from the specified port
+*
+*	void	OUT_PORT_BYTE( hcf_16 port, hcf_8 value)
+*			Writes a byte (8 bits) to the specified port
+*
+*	void	OUT_PORT_WORD( hcf_16 port, hcf_16 value)
+*			Writes a word (16 bits) to the specified port
+*
+*	void	IN_PORT_STRING( port, dest, len)
+*			Reads len number of words from the specified port to the (FAR) address dest in PC-RAM
+*			Note that len specifies the number of words, NOT the number of bytes
+*			!!!NOTE, although len specifies the number of words, dest MUST be a char pointer NOTE!!!
+*			See also the common notes for IN_PORT_STRING and OUT_PORT_STRING
+*
+*	void	OUT_PORT_STRING( port, src, len)
+*			Writes len number of words from the (FAR) address src in PC-RAM to the specified port
+*			Note that len specifies the number of words, NOT the number of bytes.
+*			!!!NOTE, although len specifies the number of words, src MUST be a char pointer NOTE!!!
+*
+*			The peculiar combination of word-length and char pointers for IN_PORT_STRING as well as
+*			OUT_PORT_STRING is justified by the assumption that it offers a more optimal algorithm
+*
+*			Note to the HCF-implementor:
+*			Due to the passing of the parameters to compiler specific blabla.........
+*			do not use "expressions" as parameters, e.g. don't use "ifbp->IFB_IOBase + HREG_AUX_DATA" but
+*			assign this to a temporary variable.
+*
+*
+*  NOTE!!	For convenience of the MSF-programmer, all {IN|OUT}_PORT_{BYTE|WORD|STRING} macros are allowed to 
+*			modify their parameters (although some might argue that this would constitute bad coding
+*			practice). This has its implications on the HCF, e.g. as a consequence these macros should not
+*			be called with parameters which have side effects, e.g auto-increment.
+*
+*  NOTE!!	in the Micosoft implementation of inline assembly it is O.K. to corrupt all flags except
+*			the direction flag and to corrupt all registers except the segment registers and EDI, ESI, 
+*			ESP and EBP (or their 16 bits equivalents).
+*			Other environments may have other constraints
+*
+*  NOTE!!	in the Intel environment it is O.K to have a word (as a 16 bits quantity) at a byte boundary, 
+*			hence IN_/OUT_PORT_STRING can move words between PC-memory and NIC-memory with as only
+*			constraint that the the words are on a word boundary in NIC-memory. This does not hold true
+*			for all conceivalble environments, e.g. an Motorola 68xxx does not allow this, in other
+*			words whenever there is a move from address in 2*n in one memory type to address 2*m+1 in the
+*			other type, the current templates for IN_/OUT_PORT_STRING are unsuitable. Probably the
+*			boundary conditions imposed by these type of platforms prevent this case from materializing
+*
+*************************************************************************************************/
+
+/************************************************************************************************/
+/****************************  N E T W A R E   3 8 6  *******************************************/
+/************************************************************************************************/
+
+#if defined  __NETWARE_386__	/* WATCOM */
+
+#define	MSF_COMPONENT_ID			COMP_ID_ODI_32
+#define HCF_STA						//station characteristics
+
+#include <conio.h>
+
+//#define CNV_LITTLE_TO_INT(x) (x)			// No endianess conversion needed
+
+typedef unsigned char				hcf_8;
+typedef unsigned short				hcf_16;
+typedef unsigned long				hcf_32;
+
+#define FAR							// flat 32-bits code
+#define BASED 
+
+#define IN_PORT_BYTE(port)			((hcf_8)inp( (hcf_io)(port) ))  //;?leave out cast to hcf_8;?
+#define IN_PORT_WORD(port)			(inpw( (hcf_io)(port) ))
+#define OUT_PORT_BYTE(port, value)	(outp( (hcf_io)(port), value ))
+#define OUT_PORT_WORD(port, value)	(outpw( (hcf_io)(port), value ))
+
+#define IN_PORT_STRING( prt, dst, n)	while ( n-- ) { *(hcf_16 FAR*)dst = IN_PORT_WORD( prt ); dst += 2; }
+#define OUT_PORT_STRING( prt, src, n)	while ( n-- ) { OUT_PORT_WORD( prt, *(hcf_16 FAR*)src ) ; src  += 2; }
+
+#endif	// __NETWARE_386__
+
+
+// Note:
+// Visual C++ 1.5 : _MSC_VER ==  800
+// Visual C++ 4.0 : _MSC_VER == 1000
+// Visual C++ 4.2 : _MSC_VER == 1020
+
+
+/************************************************************************************************/
+/****************************  P A C K E T   D R I V E R  ***************************************/
+/**********************************  D O S   O D I  *********************************************/
+/************************************************************************************************/
+
+#if defined WVLAN_42 || defined WVLAN_43|| defined WVLAN43L
+
+#pragma warning ( disable: 4001 )
+										
+#define HCF_STA						//station characteristics
+
+#if defined WVLAN_43
+#define	MSF_COMPONENT_ID			COMP_ID_ODI_16
+#define	MSF_COMPONENT_VAR			1
+#define	MSF_COMPONENT_MAJOR_VER		1
+#define	MSF_COMPONENT_MINOR_VER		4
+
+#elif defined WVLAN_42
+#define	MSF_COMPONENT_ID			COMP_ID_PACKET
+#define	MSF_COMPONENT_VAR			1
+#define	MSF_COMPONENT_MAJOR_VER		1
+#define	MSF_COMPONENT_MINOR_VER		24
+
+#elif defined WVLAN43L
+#define	HCF_MAX_CONFIG				0
+
+#define	MSF_COMPONENT_MAJOR_VER		0
+#define	MSF_COMPONENT_MINOR_VER		1
+
+#endif //WVLAN_xx
+										
+#define FAR  __far					// segmented 16 bits mode
+#if defined _M_I86TM
+#define BASED __based(__segname("_CODE"))
+#else
+#define BASED 
+#endif // _M_I86TM
+
+typedef unsigned char				hcf_8;
+typedef unsigned short				hcf_16;
+typedef unsigned long				hcf_32;
+
+#include <stdio.h>
+#include <conio.h>
+//#ifndef _DEBUG 
+#pragma intrinsic( _inp, _inpw, _outp, _outpw )
+//#endif // _DEBUG
+
+#define IN_PORT_BYTE(port)			((hcf_8)_inp( (hcf_io)(port) ))
+#define IN_PORT_WORD(port)			((hcf_16)_inpw( (hcf_io)(port) ))
+#define OUT_PORT_BYTE(port, value)	((void)_outp( (hcf_io)(port), value ))
+#define OUT_PORT_WORD(port, value)	((void)_outpw( (hcf_io)(port), value ))
+
+#if defined HCF_STRICT
+#define IN_PORT_STRING( prt, dst, n)	{ ips( prt, dst, n); }
+#define OUT_PORT_STRING( prt, dst, n)	{ ops( prt, dst, n); }
+#elif 0												// C implementation
+#define IN_PORT_STRING( prt, dst, n)	while ( n-- ) { *(hcf_16 FAR*)dst = IN_PORT_WORD( prt ); dst += 2; }
+#define OUT_PORT_STRING( prt, src, n)	while ( n-- ) { OUT_PORT_WORD( prt, *(hcf_16 FAR*)src ) ; src  += 2; }
+//;?  WHY hcf_16 FAR*)src and not unsigned char FAR*)src
+#else												// Assembler implementation
+#define IN_PORT_STRING( port, dest, len) __asm 		\
+{													\
+	__asm push di                               	\
+	__asm push es                                 	\
+	__asm mov cx,len                            	\
+	__asm les di,dest                           	\
+	__asm mov dx,port                           	\
+	__asm rep insw                              	\
+	__asm pop es	                            	\
+	__asm pop di	                            	\
+}
+
+#define OUT_PORT_STRING( port, src, len) __asm		\
+{                                               	\
+	__asm push si                                 	\
+	__asm push ds                                 	\
+	__asm mov cx,len                              	\
+	__asm lds si,src                             	\
+	__asm mov dx,port                             	\
+	__asm rep outsw	                            	\
+	__asm pop ds                                  	\
+	__asm pop si                                  	\
+}
+
+#endif	// Asm or C implementation
+
+#endif	/* WVLAN_43, WVLAN_42 (DOS ODI, Packet Driver) */
+
+
+/************************************************************************************************/
+/*************************************  W C I T S T *********************************************/
+/************************************************************************************************/
+
+#if defined WCITST
+
+#pragma warning ( disable: 4001 )
+										
+#define HCF_STA						//station characteristics
+#define HCF_AP						//AccesPoint characteristics
+
+#if _CONSOLE
+#define FAR							// flat 32 bits mode  (also defined in WINDEF.H)
+#define BASED 
+#else
+#define FAR  __far					// segmented 16 bits mode
+#if defined _M_I86TM
+#define BASED __based(__segname("_CODE"))
+#else
+#define BASED 
+#endif // _M_I86TM
+#endif  //_CONSOLE
+
+typedef unsigned char				hcf_8;
+typedef unsigned short				hcf_16;
+typedef unsigned long				hcf_32;
+
+#include <stdio.h>
+#include <conio.h>
+#ifndef _DEBUG
+#pragma intrinsic( _inp, _inpw, _outp, _outpw )
+#endif // _DEBUG
+
+#ifdef LOG
+extern FILE* utm_logfile;
+hcf_16	ipw( hcf_16 port );
+hcf_8	ipb( hcf_16 port );
+void	opw( hcf_16 port, hcf_16 value );
+void	opb( hcf_16 port, hcf_8 value );
+
+#define IN_PORT_BYTE(port)			ipb( (hcf_io)(port) )
+#define IN_PORT_WORD(port)			ipw( (hcf_io)(port) )
+#define OUT_PORT_BYTE(port, value)	opb( (hcf_io)(port), (hcf_8)(value) )
+#define OUT_PORT_WORD(port, value)	opw( (hcf_io)(port), (hcf_16)(value) )
+#else //LOG
+#define IN_PORT_BYTE(port)			((hcf_8)_inp( (hcf_io)(port) ))
+#define IN_PORT_WORD(port)			((hcf_16)_inpw( (hcf_io)(port) ))
+#define OUT_PORT_BYTE(port, value)	((void)_outp( (hcf_io)(port), value ))
+#define OUT_PORT_WORD(port, value)	((void)_outpw( (hcf_io)(port), value ))
+#endif //LOG
+
+#define	toch_maar_geen_asm
+#if defined(toch_maar_asm)  && !defined(__DA_C__)  //;? temporary solution to satisfy DA-C
+#define IN_PORT_STRING( port, dest, len) __asm 		\
+{													\
+	__asm push di                               	\
+	__asm push es                                 	\
+	__asm mov cx,len                            	\
+	__asm les di,dest                           	\
+	__asm mov dx,port                           	\
+	__asm rep insw                              	\
+	__asm pop es	                            	\
+	__asm pop di	                            	\
+}
+
+#define OUT_PORT_STRING( port, src, len) __asm		\
+{                                               	\
+	__asm push si                                 	\
+	__asm push ds                                 	\
+	__asm mov cx,len                              	\
+	__asm lds si,src                             	\
+	__asm mov dx,port                             	\
+	__asm rep outsw	                            	\
+	__asm pop ds                                  	\
+	__asm pop si                                  	\
+}
+
+#else	//toch_maar_asm  && !__DA_C__
+#define IN_PORT_STRING( prt, dst, n)	while ( n-- ) { *(hcf_16 FAR*)dst = IN_PORT_WORD( prt ); dst += 2; }
+#define OUT_PORT_STRING( prt, src, n)	while ( n-- ) { OUT_PORT_WORD( prt, *(hcf_16 FAR*)src ) ; src  += 2; }
+//;?  WHY hcf_16 FAR*)src and not unsigned char FAR*)src
+#endif	//toch_maar_asm  && !__DA_C__
+
+#endif	/* WCITST */
+
+/************************************************************************************************/
+/********************************************  W S U  *******************************************/
+/************************************************************************************************/
+
+#if 0 //;? conflicts with WIN_CE _MSC_VER >= 1000 	/* Microsoft Visual C ++ 4.x, 5.x */
+
+// Note:
+// Visual C++ 4.0 : _MSC_VER == 1000
+// Visual C++ 4.2 : _MSC_VER == 1020
+
+										
+#pragma warning ( disable: 4001 )
+										
+#define HCF_STA						//station characteristics
+
+//#if defined WVLAN_43
+//#define	MSF_COMPONENT_ID			COMP_ID_ODI_16
+//#else if defined WVLAN_42
+//#define	MSF_COMPONENT_ID			COMP_ID_PACKET
+//#endif //WVLAN_xx
+										
+#if !defined FAR
+//#if _CONSOLE
+//#define FAR							// flat 32 bits mode  (also defined in WINDEF.H)
+//#define BASED 
+//#else
+#define FAR							// far is an obsolete key in Visual C++ 4.x
+//#if defined _M_I86TM
+//#define BASED __based(__segname("_CODE"))
+//#else
+#define BASED 
+//#endif // _M_I86TM
+//#endif  //_CONSOLE
+#endif	//!defined FAR
+
+typedef unsigned char				hcf_8;
+typedef unsigned short				hcf_16;
+typedef unsigned long				hcf_32;
+
+#include <stdio.h>
+#include <conio.h>
+
+#define IN_PORT_BYTE(port)			((hcf_8)_inp( (hcf_io)(port) ))
+#define IN_PORT_WORD(port)			((hcf_16)_inpw( (hcf_io)(port) ))
+#define OUT_PORT_BYTE(port, value)	((void)_outp( (hcf_io)(port), value ))
+#define OUT_PORT_WORD(port, value)	((void)_outpw( (hcf_io)(port), value ))
+
+#define	toch_maar_geen_asm
+#if defined(toch_maar_asm)
+#define IN_PORT_STRING( port, dest, len) __asm 		\
+{													\
+	__asm push di                               	\
+	__asm push es                                 	\
+	__asm mov cx,len                            	\
+	__asm les di,dest                           	\
+	__asm mov dx,port                           	\
+	__asm rep insw                              	\
+	__asm pop es	                            	\
+	__asm pop di	                            	\
+}
+
+#define OUT_PORT_STRING( port, src, len) __asm		\
+{                                               	\
+	__asm push si                                 	\
+	__asm push ds                                 	\
+	__asm mov cx,len                              	\
+	__asm lds si,src                             	\
+	__asm mov dx,port                             	\
+	__asm rep outsw	                            	\
+	__asm pop ds                                  	\
+	__asm pop si                                  	\
+}
+
+#else	//toch_maar_asm
+#define IN_PORT_STRING( prt, dst, n)	while ( n-- ) { *(hcf_16 FAR*)dst = IN_PORT_WORD( prt ); dst += 2; }
+#define OUT_PORT_STRING( prt, src, n)	while ( n-- ) { OUT_PORT_WORD( prt, *(hcf_16 FAR*)src ) ; src  += 2; }
+//;?  WHY hcf_16 FAR*)src and not unsigned char FAR*)src
+#endif	//toch_maar_asm
+
+#endif	/* _MSC_VER >= 1000 (Microsoft Visual C++ 4.0 ) */
+
+
+
+
+/************************************************************************************************/
+/******************************************  L I N U X  *****************************************/
+/************************************************************************************************/
+
+#if defined __linux__
+
+#define HCF_STA						//station characteristics
+#define	MSF_COMPONENT_ID	COMP_ID_LINUX
+#define	MSF_COMPONENT_VAR			1
+#define	MSF_COMPONENT_MAJOR_VER		0
+#define	MSF_COMPONENT_MINOR_VER		4
+
+#include <asm/io.h>
+
+//#define CNV_LITTLE_TO_INT(x)			// No endianess conversion needed										
+
+#define FAR							// flat 32-bits code
+#define BASED 
+
+typedef unsigned char				hcf_8;
+typedef unsigned short				hcf_16;
+typedef unsigned long				hcf_32;
+
+#define IN_PORT_BYTE(port)			((hcf_8)inb( (hcf_io)(port) ))
+#define IN_PORT_WORD(port)			((hcf_16)inw( (hcf_io)(port) ))
+#define OUT_PORT_BYTE(port, value)	(outb( (hcf_8) (value), (hcf_io)(port) ))
+#define OUT_PORT_WORD(port, value)	(outw( (hcf_16) (value), (hcf_io)(port) ))
+
+#ifdef	toch_maar_asm
+#else
+#define IN_PORT_STRING( prt, dst, n)	while ( n-- ) { *(hcf_16 FAR*)dst = IN_PORT_WORD( prt ); dst += 2; }
+#define OUT_PORT_STRING( prt, src, n)	while ( n-- ) { OUT_PORT_WORD( prt, *(hcf_16 FAR*)src ) ; src  += 2; }
+#endif	//toch_maar_asm
+
+#endif	/* LINUX */
+
+
+
+/************************************************************************************************/
+/********************************** S C O   U N I X  ********************************************/
+/************************************************************************************************/
+
+#if 0
+
+#define HCF_STA						//station characteristics
+#define	MSF_COMPONENT_ID
+
+//#define CNV_LITTLE_TO_INT(x)			// No endianess conversion needed										
+
+#define FAR							// flat 32-bits code
+#define BASED 
+
+typedef unsigned char				hcf_8;
+typedef unsigned short				hcf_16;
+typedef unsigned long				hcf_32;
+
+#define IN_PORT_BYTE(port)			((hcf_8)inb( (hcf_io)(port) ))
+#define IN_PORT_WORD(port)			((hcf_16)inw( (hcf_io)(port) ))
+#define OUT_PORT_BYTE(port, value)	(outb( (hcf_io)(port), (hcf_8) (value) ))
+#define OUT_PORT_WORD(port, value)	(outw( (hcf_io)(port), (hcf_16) (value) ))
+
+#define FAR							// flat 32-bits code
+#define BASED 
+
+
+#endif	/* SCO UNIX */
+
+
+/************************************************************************************************/
+/*********************************  M I N I P O R T  ********************************************/
+/************************************************************************************************/
+
+#if 0
+
+#define	MSF_COMPONENT_ID			COMP_ID_MINIPORT
+#define HCF_STA						//station characteristics
+
+#include <ndis.h>
+#include <version.h>
+
+#define	MSF_COMPONENT_VAR			1
+#define	MSF_COMPONENT_MAJOR_VER		TPI_MAJOR_VERSION
+#define	MSF_COMPONENT_MINOR_VER		TPI_MINOR_VERSION
+
+
+//#define CNV_LITTLE_TO_INT(x)			// No endianess conversion needed										
+
+#if !defined FAR
+#define FAR							// flat 32-bits code
+#endif //!defined FAR
+
+#define BASED 
+
+__inline UCHAR NDIS_IN_BYTE( ULONG port )
+{
+    UCHAR value;
+    NdisRawReadPortUchar(port , &value);
+    return (value);
+}
+
+__inline USHORT NDIS_IN_WORD( ULONG port )
+{
+    USHORT value;
+    NdisRawReadPortUshort(port , &value);
+    return (value);
+}
+
+#define IN_PORT_BYTE(port)			NDIS_IN_BYTE( (ULONG) (port) )
+#define IN_PORT_WORD(port)			NDIS_IN_WORD( (ULONG) (port) )
+#define OUT_PORT_BYTE(port, value)	NdisRawWritePortUchar( (ULONG) (port) , (UCHAR) (value))
+#define OUT_PORT_WORD(port, value)	NdisRawWritePortUshort((ULONG) (port) , (USHORT) (value))
+
+#define IN_PORT_STRING(port, addr, len)		NdisRawReadPortBufferUshort(port, addr, (len));
+#define OUT_PORT_STRING(port, addr, len)	NdisRawWritePortBufferUshort(port, addr, (len));
+
+typedef UCHAR	hcf_8;
+typedef USHORT	hcf_16;
+typedef ULONG	hcf_32;
+
+#endif	/* MINIPORT */
+
+/************************************************************************************************/
+/*********************************  W A V E P O I N T  ******************************************/
+/************************************************************************************************/
+
+#if defined WVLAN_81	/* BORLANDC */
+
+#define HCF_AP						//access point characteristics
+#define	MSF_COMPONENT_ID	COMP_ID_AP1
+#define	MSF_COMPONENT_VAR			1
+#define	MSF_COMPONENT_MAJOR_VER		3
+#define	MSF_COMPONENT_MINOR_VER		34
+
+#include <dos.h>
+
+//#define CNV_LITTLE_TO_INT(x)			// No endianess conversion needed										
+
+typedef unsigned char				hcf_8;
+typedef unsigned short				hcf_16;
+typedef unsigned long				hcf_32;
+
+//#define HCF_ASSERT					0  /* debug build only */
+
+#if !defined FAR
+#define FAR  far					// segmented 16 bits mode
+#endif //!defined FAR
+#define BASED 
+
+
+#define IN_PORT_BYTE(port)					(inportb( (hcf_io)(port) ))
+#define IN_PORT_WORD(port)					(inport( (hcf_io)(port) ))
+#define OUT_PORT_BYTE(port, value)      	(outportb( (hcf_io)(port), value ))
+#define OUT_PORT_WORD(port, value)      	(outport( (hcf_io)(port), value ))
+
+#define IN_PORT_STRING(port, addr, len) 	\
+	asm { push di; push es; mov cx,len; les di,addr; mov dx,port; rep insw; pop es; pop di }
+
+#define OUT_PORT_STRING(port, addr, len)	\
+	asm { push si; push ds; mov cx,len; lds si,addr; mov dx,port; rep outsw; pop ds; pop si }
+
+#endif /* WavePoint */
+
+/************************************************************************************************/
+/**************************  MPC860 - Diab or High C 29K   **************************************/
+/************************************************************************************************/
+
+#if defined(__ppc) || defined(_AM29K) //|| (CPU == PPC860)
+
+#define HCF_AP						//AccesPoint characteristics
+#define MSF_COMPONENT_VAR       0
+#define MSF_COMPONENT_ID        0
+#define MSF_COMPONENT_MAJOR_VER 1
+#define MSF_COMPONENT_MINOR_VER 0
+
+#define FAR			// flat 32-bits code
+#define BASED
+
+typedef unsigned char				hcf_8;
+typedef unsigned short				hcf_16;
+typedef unsigned long				hcf_32;
+
+#define SwapBytes(t)    /*lint -e572*/(((t) >> 8) + (((t) & 0xff) << 8))/*lint +e572*/
+
+#if defined(__ppc) || (CPU == PPC860)
+    #ifndef __GNUC__
+        #define __asm__     asm
+    #endif
+
+    #if !defined(_lint)
+        #define EIEIO()     __asm__(" eieio")
+    #else
+        #define EIEIO()
+    #endif
+
+    hcf_8 IN_PORT_BYTE(int port) {
+        hcf_8 value = *(volatile hcf_8 *)(port); EIEIO();
+        return value;
+    }
+
+    hcf_16 IN_PORT_WORD(int port) {
+        hcf_16 value = *(volatile hcf_16 *)(port); EIEIO();
+        value = SwapBytes(value);
+        return value;
+    }
+
+    #define OUT_PORT_BYTE(port, value) { *(volatile hcf_8 *)(port) = (value); EIEIO(); }
+    #define OUT_PORT_WORD(port, value)      \
+            { *(volatile hcf_16 *)(port) = SwapBytes(value); EIEIO(); }
+#else
+    #define IN_PORT_BYTE(port) (*(volatile hcf_8 *)(port))
+    #define IN_PORT_WORD(port) (*(volatile hcf_16 *)(port))
+    #define OUT_PORT_BYTE(port, value) (*(volatile hcf_8 *)(port) = (value))
+    #define OUT_PORT_WORD(port, value) (*(volatile hcf_16 *)(port) = (value))
+#endif
+
+/***************************************************************************/
+
+#define IN_PORT_STRING( port, dest, len)        {                       \
+                        unsigned l = (len);                             \
+                        hcf_16 t, *d = (volatile hcf_16 *)(dest);       \
+                        while (l--) {                                   \
+                            t = IN_PORT_WORD(port);                     \
+                            *d++ = SwapBytes(t);                        \
+                        }                                               \
+                                                }
+
+#define OUT_PORT_STRING( port, src, len)        {                       \
+                        unsigned l = (len);                             \
+                        hcf_16 t, *s = (volatile hcf_16 *)(src);        \
+                        while (l--) {                                   \
+                            t = *s++;                                   \
+                            OUT_PORT_WORD(port, SwapBytes(t));          \
+                        }                                               \
+                                                }
+
+#if PRODUCT == 9150
+    #define HCF_AP
+    #define HCF_ASSERT
+    #undef MSF_COMPONENT_ID
+#endif
+
+#endif	/* MPC860 - Diab or High C 29K */
+
+/************************************************************************************************/
+/***********************************  M A C  O S   **********************************************/
+/************************************************************************************************/
+
+        /**********/
+#if 0   /* MAC_OS */
+        /**********/
+
+#define HCF_STA                     //station characteristics
+#define MSF_COMPONENT_ID            COMP_ID_MAC_OS
+#define MSF_COMPONENT_VAR           0
+#define MSF_COMPONENT_MAJOR_VER     3
+#define MSF_COMPONENT_MINOR_VER     0
+
+#define MAC_OS                      1
+#define FAR                         // flat 32-bits code
+#define BASED
+
+#undef  HCF_LITTLE_ENDIAN           // selects Little Endian (a.k.a. Intel), least significant byte first
+#define HCF_BIG_ENDIAN              // selects Big Endian (a.k.a. Motorola), most significant byte first
+
+#if defined(DEBUG)
+#define HCF_ASSERT                  1
+#endif // DEBUG
+
+typedef unsigned char               hcf_8;
+typedef unsigned short              hcf_16;
+typedef unsigned long               hcf_32;
+
+#ifdef  __cplusplus
+extern "C" {
+#endif
+extern volatile unsigned char *MacIOaddr;
+extern hcf_8  IN_PORT_BYTE(hcf_16 port);
+extern void   OUT_PORT_BYTE(hcf_16 port, hcf_8 value);
+extern hcf_16 IN_PORT_WORD(hcf_16 port);
+extern void   OUT_PORT_WORD(hcf_16 port, hcf_16 value);
+extern void   IN_PORT_STRING(hcf_16 port, void *dest, hcf_16 len);
+extern void   OUT_PORT_STRING(hcf_16 port, void *src, hcf_16 len);
+
+#define SwapBytes(t)    (((t) >> 8) + (((t) & 0xff) << 8))
+
+#ifdef  __cplusplus
+}
+#endif
+
+#endif  /* MAC_OS */
+
+/************************************************************************************************/
+/***********************************  W I N C E *************************************************/
+/************************************************************************************************/
+
+                  /*********/
+#ifdef _WIN32_WCE /* WINCE */
+                  /*********/
+
+#define	MSF_COMPONENT_ID			COMP_ID_WIN_CE
+#define HCF_STA						//station characteristics
+
+#include <ndis.h>
+#include <version.h>
+#include <ntcompat.h>
+
+#define	MSF_COMPONENT_VAR			1
+#define	MSF_COMPONENT_MAJOR_VER		TPI_MAJOR_VERSION
+#define	MSF_COMPONENT_MINOR_VER		TPI_MINOR_VERSION
+
+#define BASED 
+
+#undef  HCF_LITTLE_ENDIAN           // selects Little Endian (a.k.a. Intel), least significant byte first
+#undef  HCF_BIG_ENDIAN              // selects Big Endian (a.k.a. Motorola), most significant byte first
+
+#if defined(_SH3_) || defined (_SHx_) || defined(_MIPS_) || defined(_X86_)
+#define HCF_LITTLE_ENDIAN
+#endif
+
+#if defined(DEBUG) || defined(_WIN32_WCE_DEBUG)
+#define HCF_ASSERT                  1
+#endif // DEBUG
+
+typedef UCHAR   hcf_8;
+typedef USHORT  hcf_16;
+typedef ULONG   hcf_32;
+
+#ifdef  __cplusplus
+extern "C" {
+#endif
+
+#define WCE_IO_OFFSET   0x40
+extern ULONG  WceIoAddr;
+
+extern hcf_8  IN_PORT_BYTE(hcf_16 port);
+extern void   OUT_PORT_BYTE(hcf_16 port, hcf_8 value);
+extern hcf_16 IN_PORT_WORD(hcf_16 port);
+extern void   OUT_PORT_WORD(hcf_16 port, hcf_16 value);
+extern void   IN_PORT_STRING(hcf_16 port, void *dest, hcf_16 len);
+extern void   OUT_PORT_STRING(hcf_16 port, void *src, hcf_16 len);
+
+#ifdef  __cplusplus
+}
+#endif
+
+#endif	/* _WIN32_WCE */
+
+
+/*  * * * * * * * * * * * * * * * * * * * * * *  IV  * * * * * * * * * * * * * * * * * * * * * * */
+
+/***************************************Compiler specific ****************************************/
+
+#ifdef __cplusplus
+#define EXTERN_C extern "C"
+#else
+#define EXTERN_C
+#endif //__cplusplus
+                                                                                                            
+
+/************************************************************************************************/
+/********** M A C R O S derived of C O M P I L E R   S P E C I F I C   M A C R O S  *************/
+/************************************************************************************************/
+
+typedef hcf_8  FAR *wci_bufp;			 // segmented 16-bits or flat 32-bits pointer to 8 bits unit
+typedef hcf_16 FAR *wci_recordp;		 // segmented 16-bits or flat 32-bits pointer to 16 bits unit
+
+typedef hcf_8  FAR *hcf_8fp;			 // segmented 16-bits or flat 32-bits pointer to 8 bits unit
+typedef hcf_16 FAR *hcf_16fp;			 // segmented 16-bits or flat 32-bits pointer to 16 bits unit
+typedef hcf_32 FAR *hcf_32fp;			 // segmented 16-bits or flat 32-bits pointer to 8 bits unit
+
+
+#if defined HCF_STA && defined HCF_AP
+#if defined WCITST
+#pragma message( "you should also test both in isolation" )
+#else
+error; define exactly one of these terms;
+#endif
+#endif
+#if ! defined HCF_STA && ! defined HCF_AP
+error; define exactly one of these terms;
+#endif
+
+/*  * * * * * * * * * * * * * * * * * * * * * *  V  * * * * * * * * * * * * * * * * * * * * * * */
+
+#if defined HCF_PORT_IO
+#if defined HCF_MEM_IO
+error;
+#else
+typedef hcf_16 hcf_io;
+#endif //HCF_MEM_IO
+#endif //HCF_PORT_IO
+#if defined HCF_MEM_IO
+#if defined HCF_PORT_IO
+error;
+#else
+typedef hcf_32 hcf_io;
+#endif //HCF_PORT_IO
+#endif //HCF_MEM_IO
+
+
+
+/* MSF_COMPONENT_ID is used to define the CFG_IDENTITY_STRCT in HCF.C
+ * CFG_IDENTITY_STRCT is defined in HCF.C purely based on convenience arguments
+ * The HCF can not have the knowledge to determine the ComponentId field of the
+ * Identity record (aka as Version Record), therefore the MSF part of the Drivers
+ * must supply this value via the System Constant MSF_COMPONENT_ID
+ * There is a set of values predefined in MDD.H (format COMP_ID_.....)
+ */
+
+#if defined	MSF_COMPONENT_ID
+#define	DUI_COMPAT_VAR				MSF_COMPONENT_ID
+#define	DUI_COMPAT_BOT              4
+#define	DUI_COMPAT_TOP              4
+#endif // MSF_COMPONENT_ID
+
+/************************************************************************************************/
+/***************  E N V I R O N M E N T   S P E C I F I C   M A C R O S  ************************/
+/************************************************************************************************/
+
+
+#if defined HCF_ASSERT	//the next line may need modification for a specific environment
+extern int	BASED HCF_VAR_0; //Revision 2.0 gives an explanation of the need for HCF_VAR_0
+#endif
+
+#if defined HCF_PROFILING
+#endif
+
+/************************************************************************************************/
+/******  M S F    S U P P O R T    F U N C T I O N S    P R O T O T Y P E S   *******************/
+/************************************************************************************************/
+
+EXTERN_C void msf_assert ( wci_bufp file_namep, unsigned int line_number, hcf_16 trace, int qual );
+
+/* To increase portability, use unsigned char and unsigned char * when accessing parts of larger
+ * types to convert their Endianess
+ */
+
+#if defined HCF_BIG_ENDIAN
+#if defined HCF_LITTLE_ENDIAN
+	error
+#else	//************************************* B I G   E N D I A N *******************************************
+#define CNV_LITTLE_TO_INT(w)    ( ((hcf_16)(w) & 0x00ff) << 8 | ((hcf_16)(w) & 0xff00) >> 8 )
+#define CNV_BIG_TO_INT(w)		(w)		// No endianess conversion needed
+
+#define CNV_INT_TO_BIG_NP(addr)
+#define CNV_LITTLE_TO_INT_NP(addr) {							\
+	hcf_8 temp;													\
+	temp = ((hcf_8 FAR *)(addr))[0];							\
+	((hcf_8 FAR *)(addr))[0] = ((hcf_8 FAR *)(addr))[1];		\
+	((hcf_8 FAR *)(addr))[1] = temp;							\
+}
+
+#endif // HCF_LITTLE_ENDIAN
+#endif // HCF_BIG_ENDIAN
+
+#if defined HCF_LITTLE_ENDIAN
+#if defined HCF_BIG_ENDIAN
+	error; 
+#else	//************************************* L I T T L E   E N D I A N *************************************
+
+#define CNV_LITTLE_TO_INT(w) 	(w)		// No endianess conversion needed
+#define CNV_BIG_TO_INT(w)       ( ((hcf_16)(w) & 0x00ff) << 8 | ((hcf_16)(w) & 0xff00) >> 8 )
+
+#define CNV_INT_TO_BIG_NP(addr) {								\
+	hcf_8 temp;													\
+	temp = ((hcf_8 FAR *)(addr))[0];							\
+	((hcf_8 FAR *)(addr))[0] = ((hcf_8 FAR *)(addr))[1];		\
+	((hcf_8 FAR *)(addr))[1] = temp;							\
+}
+#define CNV_LITTLE_TO_INT_NP(addr)
+
+#endif // HCF_BIG_ENDIAN
+#endif // HCF_LITTLE_ENDIAN
+
+// conversion macros which can be expressed in other macros
+#define CNV_INT_TO_LITTLE(w)	CNV_LITTLE_TO_INT(w)
+#define CNV_INT_TO_BIG(w)		CNV_BIG_TO_INT(w)
+
+#endif //HCFCFG_H
+
+//******************************************* A L I G N M E N T  **********************************************
+#if defined HCF_ALIGN 
+#if HCF_ALIGN != 0 && HCF_ALIGN != 2
+	error;
+#endif // HCF_ALIGN != 0 && HCF_ALIGN != 2
+#else
+#define HCF_ALIGN 0			//default to no alignment
+#endif // HCF_ALIGN  
+
+
+
+
+/*  * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ *	
+ *	The routines ips and ops (short for InPutString and OutPutString) are created to use the 
+ *	compiler to do the type checking. It turned out that it is too easy to accidentally pass
+ *	a word pointer to the the macros IN_PORT_STRING and OUT_PORT_STRING rather than a byte pointer.
+ *	The "+2" as some macro implementations use, does not have the intended effect in those cases.
+ *	The HCF_STRICT business can be ignored by MSF programmers.
+ *	
+ *  * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+
+
+#if defined HCF_STRICT
+void ips( hcf_io prt, wci_bufp dst, int n);
+void ops( hcf_io prt, wci_bufp src, int n);
+#endif //HCF_STRICT
+
+
+
+
+
+
+
+#if !defined HCF_MAX_CONFIG
+#define HCF_MAX_CONFIG		256		// maximum accumulated size in hcf_16 of LTV records used in hcf_put_config
+#endif
+
+#if !defined HCF_MAX_MSG
+#define HCF_MAX_MSG			2304	/* WaveLAN Pakket Size										*/
+#endif
+
+#if !defined HCF_MAX_NOTIFY		
+#define HCF_MAX_NOTIFY		6		// maximum size in bytes of "real" data in Notify command
+#endif
Index: oldkernel/linux/pcmcia-cs-3.1.15/wireless/wvlan_hcfdef.h
diff -u /dev/null linux/pcmcia-cs-3.1.15/wireless/wvlan_hcfdef.h:1.1
--- /dev/null	Mon Jul 31 21:15:12 2000
+++ linux/pcmcia-cs-3.1.15/wireless/wvlan_hcfdef.h	Fri Jul  7 16:34:59 2000
@@ -0,0 +1,375 @@
+/* This file is part of the Hardware Control Functions Light (HCF-light) library
+   to control the Lucent Technologies WaveLAN/IEEE Network I/F Card.
+   The HCF is the implementation of the Wireless Connection I/F (WCI).
+   
+   The HCF-light files are a subset of the HCF files. The complete set offers a
+   number of additional facilities, e.g. firmware download, Etherner-II encapsulation,
+   additional diagnostic facilities, ASSERT logic to support debugging, 802.11 support,
+   Configuration Management.
+   This complete set is explicitely not in the Public Domain but can be made 
+   available under certain restriction. (see the pointer below for support)
+   
+   The HCF-light files are 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. 
+   
+   At the time of this writing, you can request for support at:
+   betasupport@wavelan.com
+   
+   Documentation is expected to be available in the week of 8 Februari 1999
+
+*/
+
+
+#ifndef HCFDEFC_H
+#define HCFDEFC_H 1
+
+
+/*************************************************************************************************
+*
+* FILE	 : HCFDEFC.H *************** 2.0 *********************
+*
+* DATE   : 2000/01/06 23:30:53   1.2
+*
+* AUTHOR : Nico Valster
+*
+* DESC   : Definitions and Prototypes for HCF only
+*
+**************************************************************************************************
+* COPYRIGHT (c) 1996, 1997, 1998 by Lucent Technologies.	 All Rights Reserved.
+*************************************************************************************************/
+
+
+/****************************************************************************
+wvlan_hcfdef.h,v
+Revision 1.2  2000/01/06 23:30:53  root
+*** empty log message ***
+
+ * 
+ *    Rev 1.0   02 Feb 1999 14:32:34   NVALST
+ * Initial revision.
+Revision 1.1  1999/01/30 19:24:39  nico
+Initial revision
+
+Revision 1.1  1999/01/30 19:07:57  nico
+Initial revision
+
+ * 
+ *    Rev 1.110   29 Jan 1999 15:52:44   NVALST
+ * intermediate, maybe working but seems to need two times to load in 
+ * light-version
+ * 
+ *    Rev 2.12   29 Jan 1999 10:48:44   NVALST
+ * 
+ *    Rev 1.108   28 Jan 1999 14:43:24   NVALST
+ * intermediate, once more correction of loop in hcf_service_nic + download
+ * passed to Marc
+ * 
+ *    Rev 2.11   27 Jan 1999 16:57:42   NVALST
+ * 
+ *    Rev 1.107   27 Jan 1999 13:53:24   NVALST
+ * intermediate, once more correction of loop in hcf_service_nic
+ * 
+ *    Rev 1.106   26 Jan 1999 16:42:46   NVALST
+ * intermediate, corrected loop in hcf_service_nic (which was as result of a 
+ * walkthrough, changed from a bug without consequences into one with consequences
+ * 
+ *    Rev 1.105   25 Jan 1999 14:24:46   NVALST
+ * intermediate, hopefully suitable for release
+ * 
+ *    Rev 1.104   22 Jan 1999 16:59:34   NVALST
+ * intermediate, minor corrections + some HCF-L stuff
+ * 
+ *    Rev 1.103   15 Jan 1999 15:14:46   NVALST
+ * intermediate, deposited as HCF2.10
+ * 
+ *    Rev 2.10   15 Jan 1999 14:54:34   NVALST
+ * 
+****************************************************************************/
+
+
+/****************************************************************************
+*
+* CHANGE HISTORY
+*
+  961018 - NV
+	Original Entry
+
+**************************************************************************************************/
+
+/************************************************************************************************/
+/*********************************  P R E F I X E S  ********************************************/
+/************************************************************************************************/
+//IFB_		Interface Block
+//HCMD_		Hermes Command
+//HFS_		Hermes (Transmit/Receive) Frame Structure
+//HREG_		Hermes Register
+
+/*************************************************************************************************/
+
+
+/************************************************************************************************/
+/********************************* GENERAL EQUATES **********************************************/
+/************************************************************************************************/
+//#define STATIC			//;?cheap way out to get things compiled while intransition for ObjectOutline
+//#if ! defined STATIC	//;? change to HCF_STATIC some day
+//#if defined _DEBUG || defined OOL
+#define STATIC		EXTERN_C
+//#else
+//#define STATIC		static
+//#endif //_DEBUG
+//#endif // STATIC
+
+
+#define AUX_MAGIC_0				0xFE01
+#define AUX_MAGIC_1				0xDC23
+#define AUX_MAGIC_2				0xBA45
+#define HCF_MAGIC				0x7D37	// "}7" Handle validation
+#define DIAG_MAGIC				0x5A5A
+
+#define	PLUG_DATA_OFFSET        0x3F0000L
+
+
+#define ONE_SECOND				977		// 977 times a Hermes Timer Tick of 1K microseconds ~ 1 second
+#define INI_TICK_INI			0x20000L
+
+#define IO_IN					0		//hcfio_in_string
+#define IO_OUT					1		//hcfio_out_string
+#define IO_OUT_CHECK			2		//enable Data Corruption Detect on hcfio_out_string
+
+#define CARD_STAT_ENA_PRES		(CARD_STAT_ENABLED|CARD_STAT_PRESENT)
+#define CARD_STAT_PRI_PRES		(CARD_STAT_PRESENT|CARD_STAT_INCOMP_PRI)
+#define CARD_STAT_PRI_STA_PRES	(CARD_STAT_PRI_PRES|CARD_STAT_INCOMP_STA)
+
+#define DO_ASSERT				( ifbp->IFB_Magic != HCF_MAGIC && ifbp->IFB_Magic == HCF_MAGIC )	//FALSE without the nasty compiler warning
+
+#define HCF_ASSERT_ACTION			0x0001
+//#define HCF_ASSERT_CONNECT		no use to trace this
+#define HCF_ASSERT_DISABLE			0x0002
+#define HCF_ASSERT_DISCONNECT		0x0004
+#define HCF_ASSERT_ENABLE			0x0008
+#define HCF_ASSERT_GET_DATA			0x0010
+#define HCF_ASSERT_GET_INFO			0x0020
+#define HCF_ASSERT_INITIALIZE		0x0040
+#define HCF_ASSERT_RESEND			0x0080
+#define HCF_ASSERT_SERVICE_NIC		0x0100
+#define HCF_ASSERT_PUT_DATA			0x0200
+#define HCF_ASSERT_PUT_INFO			0x0400
+#define HCF_ASSERT_PUT_HDR			0x0800
+#define HCF_ASSERT_SEND				0x1000
+#define HCF_ASSERT_SEND_DIAG_MSG	0x2000
+#define HCF_ASSERT_INT_OFF			0x4000
+#define HCF_ASSERT_MISC				0x8000	
+
+
+#define	CFG_CONFIG_RID_MASK			0xFC00		//CONFIGURATION RECORDS
+
+#define BAP_0					HREG_DATA_0		//Tx-related register set for WMAC buffer access
+#define BAP_1					HREG_DATA_1		//non Tx-related register set for WMAC buffer access
+/************************************************************************************************/
+/***************************** STRUCTURES *******************************************************/
+/************************************************************************************************/
+                            
+                            
+//************************* Hermes Receive/Transmit Frame Structures
+//HFS_STAT
+//see MMD.H for HFS_STAT_ERR
+#define 	HFS_STAT_MSG_TYPE	0xE000	//Hermes reported Message Type
+#define 	HFS_STAT_1042		0x2000	//RFC1042 Encoded
+#define 	HFS_STAT_TUNNEL		0x4000	//Bridge-Tunnel Encoded
+#define 	HFS_STAT_WMP_MSG	0x6000	//WaveLAN-II Management Protocol Frame
+
+//HFS_TX_CNTL
+//see ENC_802_3/ENC_802_11 definition
+                            
+                            
+//************************* Hermes Register Offsets and Command bits
+#define HREG_IO_RANGE			0x40		//I/O Range used by Hermes
+
+
+//************************* Command/Status
+#define HREG_CMD				0x00		//
+#define 	HCMD_CMD_CODE			0x3F
+#define HREG_PARAM_0			0x02		//
+#define HREG_PARAM_1			0x04		//
+#define HREG_PARAM_2			0x06		//
+#define HREG_STAT				0x08		//
+#define 	HREG_STAT_CMD_CODE		0x003F	//
+#define		HREG_STAT_DIAG_ERR		0x0100
+#define		HREG_STAT_INQUIRE_ERR	0x0500
+#define 	HREG_STAT_CMD_RESULT	0x7F00	//
+#define HREG_RESP_0				0x0A		//
+#define HREG_RESP_1				0x0C		//
+#define HREG_RESP_2				0x0E		//
+
+
+//************************* FID Management
+#define HREG_INFO_FID			0x10		//
+#define HREG_RX_FID				0x20		//
+#define HREG_ALLOC_FID  		0x22		//
+//rsrvd #define HREG_TX_COMPL_FID  	0x24		//
+
+
+//************************* BAP
+#define HREG_SELECT_0			0x18		//
+#define HREG_OFFSET_0			0x1C		//
+//#define 	HREG_OFFSET_BUSY		0x8000	// use HCMD_BUSY
+#define 	HREG_OFFSET_ERR			0x4000	//
+//rsrvd #define 	HREG_OFFSET_DATA_OFFSET	0x0FFF	//
+
+#define HREG_DATA_0				0x36		//
+//rsrvd #define HREG_SELECT_1	0x1A		//
+//rsrvd #define HREG_OFFSET_1	0x1E		//
+
+#define HREG_DATA_1				0x38		//
+
+
+//************************* Event
+#define HREG_EV_STAT			0x30		//
+#define HREG_INT_EN				0x32		//
+#define HREG_EV_ACK				0x34		//
+
+
+//************************* Host Software
+#define HREG_SW_0				0x28		//
+#define HREG_SW_1				0x2A		//
+#define HREG_SW_2				0x2C		//
+//rsrvd #define HREG_SW_3		0x2E		//
+//************************* Control and Auxiliary Port
+
+#define HREG_CNTL				0x14		//
+#define		HREG_CNTL_AUX_ENA		0xC000
+#define		HREG_CNTL_AUX_ENA_STAT	0xC000
+#define		HREG_CNTL_AUX_DIS_STAT	0x0000
+#define		HREG_CNTL_AUX_ENA_CNTL	0x8000
+#define		HREG_CNTL_AUX_DIS_CNTL	0x4000
+#define HREG_AUX_PAGE			0x3A		//
+#define HREG_AUX_OFFSET			0x3C		//
+#define HREG_AUX_DATA			0x3E		//
+
+
+/************************************************************************************************/
+/***************************** END OF STRUCTURES ***********************************************/
+/************************************************************************************************/
+
+
+/************************************************************************************************/
+/**********************************  EQUATES  ***************************************************/
+/************************************************************************************************/
+
+// Tx/Rx frame Structure
+//
+#define HFS_STAT_ABS		(0x2E + HFS_STAT)    		//0x0000
+#define HFS_Q_INFO_ABS		(0x2E + HFS_Q_INFO)			//0x0006
+#define HFS_TX_CNTL_ABS		(0x2E + HFS_TX_CNTL)		//0x000C
+#define HFS_FRAME_CNTL_ABS	(0x2E + HFS_FRAME_CNTL)		//0X000E
+#define HFS_ID_ABS			(0x2E + HFS_ID)				//0X0010
+
+#define HFS_ADDR_1_ABS		(0x12 + HFS_ADDR_1)  		//0x0012
+#define HFS_ADDR_2_ABS		(0x12 + HFS_ADDR_2)  		//0x0018
+#define HFS_ADDR_3_ABS		(0x12 + HFS_ADDR_3)  		//0x001E
+#define HFS_SEQ_CNTL_ABS	(0x12 + HFS_SEQ_CNTL)		//0x0024
+#define HFS_ADDR_4_ABS		(0x12 + HFS_ADDR_4) 		//0x0026
+#define HFS_DAT_LEN_ABS		(0x12 + HFS_DAT_LEN)		//0x002C
+
+#define HFS_ADDR_DEST_ABS   (0x2E + HFS_ADDR_DEST)		//0x002E
+#define HFS_ADDR_SRC_ABS    (0x2E + HFS_ADDR_SRC)		//0x0034
+#define HFS_LEN_ABS	       	(0x2E + HFS_LEN)			//0x003A
+#define HFS_DAT_ABS	       	(0x2E + HFS_DAT)			//0x003C
+#define HFS_TYPE_ABS	    (0x2E + HFS_TYPE)			//0x0042	Eternet-II type in 1042/Bridge-Tunnel encapsulated frame
+
+#define HFS_802_11_GAP		(HFS_DAT_ABS  - HFS_ADDR_DEST_ABS)
+#define HFS_E_II_GAP       	(HFS_TYPE_ABS - HFS_LEN_ABS)
+
+#define KLUDGE_MARGIN		8							//safety margin for Tx Data Corruption workaround
+
+#define HFS_TX_ALLOC_SIZE	HCF_MAX_MSG + HFS_DAT_ABS + KLUDGE_MARGIN
+
+// IFB field related
+//		IFB_TxFrameType
+//#define ENC_TX_802_3           	0x00
+//#define ENC_TX_802_11         	0x11
+#define ENC_TX_E_II				0x0E	//encapsulation flag
+
+// SNAP header for E-II Encapsulation
+#define ENC_TX_1042             0x00
+#define ENC_TX_TUNNEL           0xF8
+
+// Hermes Command Codes and Qualifier bits
+#define 	HCMD_BUSY			0x8000	// Busy bit, applicable for all commands
+#define 	HCMD_RECL			0x0100	// Reclaim bit, applicable for Tx and Inquire
+
+#define HCMD_INI				0x0000	//
+#define HCMD_ENABLE				0x0001	//
+#define HCMD_DISABLE			0x0002	//
+#define HCMD_DIAG				0x0003	//
+#define HCMD_ALLOC				0x000A	//
+#define HCMD_TX					0x000B	//
+#define HCMD_NOTIFY				0x0010	//
+#define HCMD_INQUIRE			0x0011	//
+#define HCMD_ACCESS				0x0021	//
+#define 	HCMD_ACCESS_WRITE		0x0100	//
+#define HCMD_PROGRAM			0x0022	//
+#define 	HCMD_PROGRAM_DISABLE				0x0000	//
+#define 	HCMD_PROGRAM_ENABLE_VOLATILE	 	0x0100	//
+#define 	HCMD_PROGRAM_ENABLE_NON_VOLATILE	0x0200	//
+#define 	HCMD_PROGRAM_NON_VOLATILE			0x0300	//
+
+// Miscellanuos 
+//
+#define REV_OFFSET 16					// offset of Major version within the PVCS generated Version String
+
+
+/************************************************************************************************/
+/**********************************  END OF EQUATES  ********************************************/
+/************************************************************************************************/
+
+
+/************************************************************************************************/
+/**************************************  MACROS  ************************************************/
+/************************************************************************************************/
+
+/************************************************************************************************
+	DEBUG_INT is an undocumented feature to assist the HCF debugger
+	By expanding INT_3 to either an "int 3" or a NOP, it is very easy to check
+	by means of a binary file compare whether a "debug" version really corresponds
+	with a "non-debug" version.
+	;? is is currently unknown whether there is a real reason to restrict this
+	implemenation to the MSVC environment
+*/
+#if defined (_MSC_VER)
+#ifdef DEBUG_INT
+//#pragma message( Reminder "int 3, should be removed before releasing" )
+#define INT_3 __asm int 3
+#else
+#define INT_3 __asm nop
+#endif /*DEBUG_INT*/
+#else
+#define INT_3
+#endif /*_MSC_VER*/
+
+#define MUL_BY_2( x )	( (x) << 1 )	//used to multiply by 2
+#define DIV_BY_2( x )	( (x) >> 1 )	//used to divide by 2
+
+/************************************************************************************************/
+/**************************************  END OF MACROS  *****************************************/
+/************************************************************************************************/
+
+/************************************************************************************************/
+/***************************************  PROTOTYPES  *******************************************/
+/************************************************************************************************/
+
+int 	hcfio_string( IFBP ifbp, int bap, int fid, int offset, wci_bufp pc_addr, int wlen, int blen, int type );
+
+
+#endif	//HCFDEFC_H
Index: oldkernel/linux/pcmcia-cs-3.1.15/wireless/wvlan_hcfio.c
diff -u /dev/null linux/pcmcia-cs-3.1.15/wireless/wvlan_hcfio.c:1.1
--- /dev/null	Mon Jul 31 21:15:12 2000
+++ linux/pcmcia-cs-3.1.15/wireless/wvlan_hcfio.c	Fri Jul  7 16:34:59 2000
@@ -0,0 +1,432 @@
+/* This file is part of the Hardware Control Functions Light (HCF-light) library
+   to control the Lucent Technologies WaveLAN/IEEE Network I/F Card.
+   The HCF is the implementation of the Wireless Connection I/F (WCI).
+   
+   The HCF-light files are a subset of the HCF files. The complete set offers a
+   number of additional facilities, e.g. firmware download, Etherner-II encapsulation,
+   additional diagnostic facilities, ASSERT logic to support debugging, 802.11 support,
+   Configuration Management.
+   This complete set is explicitely not in the Public Domain but can be made 
+   available under certain restriction. (see the pointer below for support)
+   
+   The HCF-light files are 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. 
+   
+   At the time of this writing, you can request for support at:
+   betasupport@wavelan.com
+   
+   Documentation is expected to be available in the week of 8 Februari 1999
+
+*/
+
+
+
+/**************************************************************************************************************
+*
+* FILE	  : hcfio.cpp
+*
+* DATE    : 2000/01/06 23:30:53   1.2
+*
+* AUTHOR  : Nico Valster
+*
+* DESC    : WCI-II HCF I/O Support Routines
+*           These routines are isolated in their own *.CPP file to facilitate porting
+*
+*           Customizable via HCFCFG.H which is included by HCF.H
+*
+***************************************************************************************************************
+* COPYRIGHT (c) 1994, 1995 by AT&T. 	   						All Rights Reserved.
+* COPYRIGHT (c) 1996, 1997, 1998 by Lucent Technologies.     	All Rights Reserved.
+**************************************************************************************************************/
+
+/****************************************************************************
+wvlan_hcfio.c,v
+Revision 1.2  2000/01/06 23:30:53  root
+*** empty log message ***
+
+ * 
+ *    Rev 1.0   02 Feb 1999 14:32:30   NVALST
+ * Initial revision.
+Revision 1.1  1999/01/30 19:34:40  nico
+Initial revision
+
+Revision 1.1  1999/01/30 19:24:39  nico
+Initial revision
+
+Revision 1.1  1999/01/30 19:07:33  nico
+Initial revision
+
+ * 
+ *    Rev 1.110   29 Jan 1999 15:52:40   NVALST
+ * intermediate, maybe working but seems to need two times to load in 
+ * light-version
+ * 
+ *    Rev 2.12   29 Jan 1999 10:48:46   NVALST
+ * 
+ *    Rev 1.108   28 Jan 1999 14:43:18   NVALST
+ * intermediate, once more correction of loop in hcf_service_nic + download
+ * passed to Marc
+ * 
+ *    Rev 2.11   27 Jan 1999 16:57:42   NVALST
+ * 
+ *    Rev 1.107   27 Jan 1999 13:53:22   NVALST
+ * intermediate, once more correction of loop in hcf_service_nic
+ * 
+ *    Rev 1.106   26 Jan 1999 16:42:44   NVALST
+ * intermediate, corrected loop in hcf_service_nic (which was as result of a 
+ * walkthrough, changed from a bug without consequences into one with consequences
+ * 
+ *    Rev 1.105   25 Jan 1999 14:24:46   NVALST
+ * intermediate, hopefully suitable for release
+ * 
+ *    Rev 1.104   22 Jan 1999 16:59:30   NVALST
+ * intermediate, minor corrections + some HCF-L stuff
+ * 
+ *    Rev 1.103   15 Jan 1999 15:14:40   NVALST
+ * intermediate, deposited as HCF2.10
+ * 
+****************************************************************************/
+
+
+/****************************************************************************
+*
+* CHANGE HISTORY
+*
+  961121 - NV
+    Original Entry
+
+**************************************************************************************************************/
+
+/* ToDo
+ * the CNV_LITTLE_TO_INT does have the desired effect on all platforms, but it's naming is
+ * misleading, so revisit all these CNV macros to assure the right name is used at the right
+ * place. Hint: introduce CNV_HOST_TO_NETWORK names if appropriate
+ */
+
+
+#include "wvlan_hcf.h"
+#include "wvlan_hcfdef.h"
+
+#ifdef HCF_ASSERT
+static char BASED HCF__FILE__[] = { "  " __FILE__};	/* 6 spaces to supply room to build an LTV record for 
+													 * runtime HCF_ASSERTs.  This record is constructed as:
+													 * - L:		 self explanatory
+													 * - T:		 CFG_MB_ASSERT
+													 * - V[0]:	 line_number
+													 * - V[1..]: (unchanged) file name						*/
+#endif
+
+/*  * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ *	
+ *	Refer to HCFCFG.H for more information on the routines ips and ops (short for InPutString 
+ *	and OutPutString)
+ *	
+ *  * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+ 
+#if defined HCF_STRICT
+void ips( hcf_io prt, wci_bufp dst, int n) {
+
+	while ( n-- ) { 
+		*(hcf_16 FAR*)dst = IN_PORT_WORD( prt );
+		dst += 2;
+	}
+} // ips
+
+void ops( hcf_io prt, wci_bufp src, int n) {
+
+	while ( n-- ) {
+		OUT_PORT_WORD( prt, *(hcf_16 FAR*)src );
+		src  += 2;
+	}
+} // ops
+#endif // HCF_STRICT
+
+/***************************************** DOCZ Header ********************************************************
+
+
+.MODULE         hcfio_string
+.LIBRARY        HCF_SUP
+.TYPE           function
+.SYSTEM         msdos
+.SYSTEM         unix
+.SYSTEM         NW4
+.APPLICATION    I/O Support for HCF routines
+.DESCRIPTION    read/write string with specified length from/to WaveLAN NIC RAM to/from PC RAM
+
+
+int hcfio_string( IFBP ifbp, int bap, int fid, 
+				  int offset, wci_bufp pc_addr, int word_len, int tot_len, int type ) {
+.ARGUMENTS
+  IFBP			ifbp			I/F Block
+  int			bap				BAP0/1
+  int			fid				FID/RID
+  int			offset			offset in FID/RID
+  wci_bufp		pc_addr			begin address in PC RAM to write to or read from
+  int			word_len		number of leading words of which the Endianess must be converted
+  int			tot_len			number of bytes to write or read
+  int			type            action code
+								  -	IO_IN			read from NIC RAM
+								  -	IO_OUT			write to NIC RAM
+								  -	IO_OUT_CHECK	Data Corruption Detect
+
+.RETURNS
+  int
+	HCF_SUCCESS     	O.K
+	HCF_ERR_TIME_OUT    BAP can not be initialized
+	HCF_ERR_NO_NIC		card is removed
+	HCF_FAILURE			Data Corruption Detection catched
+
+.NARRATIVE
+
+  hcfio_string has the following tasks:
+  -	copy data from NIC RAM to Host RAM or vice versa
+  - optionally convert the data or part of the data from/to Little Endian format (as used by the NIC) 
+  	to/from the Native Endian format (as used by the Host)
+  -	check for Data Corruption in the data written to the NIC
+	
+  Data is a string with specified length copied from/to a specified offset in a specified Receive Frame 
+  Structure (FID), Transmit Frame Structure (FID) or Record (RID) to/from a Host RAM buffer with a specified
+  begin address.
+  A length of 0 can be specified, resulting in no data transfer. This feature accomodates MSFs in certain
+  Host environments (i.e. ODI) and it is used in the Data Corruption detection.
+  Which Buffer Acces Path (BAP0 or BAP1) is used, is defined by a parameter.  
+  A non-zero return status indicates:
+  -	the selected BAP could not properly be initialized
+  -	the card is removed before completion of the data transfer
+  - the Data Corruption Detection triggered
+  - the NIC is considered inoperational due to a time-out of some Hermes activity in the past
+  In all other cases, a zero is returned.
+  If a card removal is returned, the MSF has the option to drop the message or recover in any other way it 
+  sees fit.
+  BAP Initialization failure indicates an H/W error which is very likely to signal complete H/W failure. Once
+  a BAP Initialization failure has occured all subsequent interactions with the Hermes will return a time out
+  status till the Hermes is re-initialized by means of an hcf_disable (at all ports in case of a multi-port
+  environment)
+
+.DIAGRAM
+
+ 1:	the test on rc checks whether a BAP initialization or a call to cmd_wait did ever fail. If so, the Hermes 
+	is assumed inoperable/defect, and all subsequent bap_ini/cmd_wait calls are nullified till hcf_disable 
+	clears the IFB_TimStat field.
+ 2:	The PCMCIA card can be removed in the middle of the transfer. By depositing a "magic number" in the 
+	HREG_SW_0 register of the Hermes at initialization time and by verifying this location after 
+    reading the string, it can be determined whether the card is still present and the return status is 
+    set accordingly.
+ 3:	The test on offset and fid in the IFB_BAP_<n> structure corresponding with the BAP entry parameter, 
+	assures that the BAP is only initialized if the current set of parameters specifies a location wich is 
+	not consecutive with the last read/write access. If initialization is needed, then:
+	  -	the select register is set
+	  -	the offset register is set
+	  -	the IFB_BAP_<n> structure is initialized
+	  - the offset register is monitored till a successful condition (no busy bit and no error bit) is 
+	  	detected or till the protection counter (calibrated at approx 1 second) expires
+	If the counter expires, this is reflected in IFB_TimStat, so all subsequent calls to hcfio_string
+	fail immediately ( see step 1)
+ 4:	the offset register in the IFB_BAP_<n> structure is updated to be used as described in item 3 above 
+ 	on the next call
+10:	The NIC I/F is optimized for word transfer but it can only handle word transfer at a word boundary. 
+	Therefore an additional test must be done to handle the read preparation in case the begin address in 
+	NIC RAM is odd.
+    This situation is handled by first reading a single byte and secondly reading a string of WORDS with a
+    BYTE length of the requested length minus 1.
+	NOTE: MACRO IN_PORT_STRING possibly modifies p (depending on how the MSF-programmer chooses to construct
+	this macro, so pc_addr can not be used as parameter
+11:	At completion of the word based transfer, a test is made to determine whether 1 additional byte must be 
+	read (odd length starting at even address or even length starting at odd boundary)
+12: finally the optionally conversion of the first words from Little Endian to Native Endian format is done.
+20: first the optionally conversion of the first words from Native Endian to Little Endian format is done.
+	This implies that Endian conversion can ONLY take place at word boundaries.
+	Note that the difference with the IO_IN part of the logic is based on optimization considerations (both
+	speed and size) and the boundary condition to return the output buffer unchanged to the caller
+	Note also that the check on zero-length for output can not be the simple "skip all" as used for input, 
+	because the Data Corruption Detection needs some of the side effects of this code, specifically the 
+	BAP initialization
+21: As for the IO_IN part, the logic must first cope with odd begin addresses in NIC RAM and the bulk of the
+	transfer is done via OUT_PORT_STRING. Due to a flaw in the Hermes, writing the high byte corrupts the 
+	low byte. As a work around, the HCF reads the low byte deposited in NIC RAM by the previous 
+	hcfio_string, merges that byte with the first byte of the current Host RAM buffer into a word and
+	writes that word to NIC RAM via OUT_PORT_WORD. Since OUT_PORT_WORD converts from Native Endian to
+	Little Endian, while at this point of the procedure the Host buffer must have the correct Endianess,
+	the macro CNV_LITTLE_TO_INT counteracts this unwanted adjustment of OUT_PORT_WORD.
+22: At completion of the word based transfer, a test is made to determine whether 1 additional byte must be 
+	written
+30: The case of Data Corruption Detection:
+	First the NIC RAM pointer is aligned on a word boundary to cope with the problem of an odd number of
+	bytes written before. This is done by skipping one additional byte before the Data Corruption 
+	Detection Pattern is appended to the data already written to the NIC RAM.
+	Then 8 bytes fixed pattern is written. The justification of this is given in the NOTICE section below
+31: In order to read the pattern back, the BAP must be initialized to address the begin of the pattern.
+	The select register does not change, so only the offset register needs to be written, followed by
+	a wait for successful completion.
+40: To recognize the case that the NIC is removed during execution of hcfio_string, the same check as in
+	step 2 is done again.
+99:	In the past, one of the asserts in bap_ini (which no longer exists now it is assimilated in hcfio_string) 
+	catched if "offset" was invalid. By calling bap_ini with the original (offset + length), bap_ini would 
+	catch when the MSF passes the RID/FID boundary during the read process. It turned out that this feature 
+	did obscure the tracing during debugging so much that its total effect on the debugging process was 
+	considered detrimental, however re-institution can be considered depending on the bug you are chasing
+
+
+.NOTICE
+The problem is that without known cause, the Hermes internal NIC RAM pointer misses its auto-increment causing 
+two successive writes to NIC RAM to address the same location. As a consequence word <n> is overwritten and 
+a word <n+j> is written at position <n+j-1>. Since the Hermes is unaware of this, nothing in the system is 
+going to catch this, e.g. the frame is received on the other side with correct FCS. As a workaround, the HCF 
+keeps track of where the NIC RAM pointer SHOULD be. After all hcf_put_data calls are done, in other words, 
+when hcf_send is called, the HCF writes a number of words - the kludge pattern - after the MSF-data. Then it 
+sets the NIC RAM pointer by means of a re-initialization of the BAP to where this kludge pattern SHOULD be and 
+reads the first word. This first word must match the kludge pattern, otherwise, apparently, the auto-increment 
+failed. We need to write more than 1 word otherwise if the previous use of that piece of NIC RAM would have 
+left by chance the right "kludge" value just after the newly but incorrectly put data, the test would not 
+trigger. By overwriting the next 3 words as well, we assume the likelihood of this to be sufficiently small. 
+The frequency observed of this problem varies from 1 out of 1000 frames till to low to be noticeable. Just to 
+be on the safe side we assume that the chance of an error is 10E-3. By writing 4 words we reduce the 
+likelihood of an unnoticed problem to 10E-12, but of course this becomes tricky because we don't know whether 
+the chances are independent. Note that the HCF notion of the NIC RAM pointer is a "logical" view in the 
+RID/FID address space, while the Hermes has a completely different physical address value for this pointer, 
+however that difference does not influence above reasoning.
+
+.NOTE
+  Depending on the selected optimization options, using "register int reg" causes some obscure 
+  optimization with si. As a result the code is longer. Therefore, do not invest time to optimize this code 
+  that way during a "maintenance cycle".
+ 
+.NOTE
+  The IN_/OUT_PORT_WORD_/STRING macros are MSF-programmer defined and may or may not have side effects 
+  on their parameters, therefore they can not handle expressions like "len/2". As a solution all these macros
+  must be called via "simple" variables, with no side effects like ++ and their contents is unpredictable
+  at completion of the macro
+  
+.NOTE
+  The implementation is choosen to have input, output and BAP setup all rolled into one monolithic
+  function rather than a more ameniable hcfio_in_string, hcfio_out_string and bap_ini to minimize the 
+  stack usage during Interrupt Service (especially relevant for DOS drivers)
+
+.NOTE
+  The local variable reg corresponds with a register of the appropriate BAP. This is possible by the 
+  intentional choice of the addresses of the individual registers of the two BAPs and the macro used to 
+  specify whether BAP_0 or BAP_1 should be used. The value of reg is changed in the flow of hcfio_string
+  because, depending on the context, reg is most optimal addressing the offset register or the data register.
+
+	
+
+ .ENDOC                          END DOCUMENTATION
+
+-------------------------------------------------------------------------------------------------------------*/
+
+
+int hcfio_string( IFBP ifbp, int bap, int fid, 
+				  int offset, wci_bufp pc_addr, int word_len, int tot_len, int type ) {
+
+hcf_io		reg = ifbp->IFB_IOBase + bap - HREG_DATA_0 + HREG_OFFSET_0;				//reg = offset register
+hcf_32		prot_cnt = ifbp->IFB_TickIni;
+hcf_16  	*p1 = bap == BAP_0 ? ifbp->IFB_BAP_0 : ifbp->IFB_BAP_1;
+wci_bufp	cp;
+wci_recordp	wp = (wci_recordp)pc_addr;
+int			rc;
+int			tlen;
+
+#if HCF_ALIGN != 0
+#endif // HCF_ALIGN
+			/* assumption, writing words takes place only initial, never at odd NIC RAM addresses nor odd PC 
+			 * addresses	*/
+
+	if ( ( rc = ifbp->IFB_TimStat ) == HCF_SUCCESS ) {													/* 1 */
+	    if ( IN_PORT_WORD( ifbp->IFB_IOBase + HREG_SW_0 ) != HCF_MAGIC ) rc =  HCF_ERR_NO_NIC;			/* 2 */
+	}	
+	if ( rc == HCF_SUCCESS ) {
+	
+		/* make sure all preceeding BAP manipulation is settled */
+		while ( prot_cnt && IN_PORT_WORD( reg ) & (HCMD_BUSY|HREG_OFFSET_ERR) ) prot_cnt--;
+	
+		if ( offset != (int)*p1 || fid != (int)*(p1+1) ) {												/* 3 */
+			OUT_PORT_WORD( reg - HREG_OFFSET_0 + HREG_SELECT_0, fid );
+			OUT_PORT_WORD( reg, offset & 0xFFFE );
+			*p1 = (hcf_16)offset;
+			*(p1+1) = (hcf_16)fid;
+			/* use type == IO_IN and len == 0 as a way to set the BAP for the futute, e.g. at the end of hcf_send */
+//			while ( prot_cnt-- && IN_PORT_WORD( reg ) & (HCMD_BUSY|HREG_OFFSET_ERR) ) /*NOP*/;
+			while ( tot_len && prot_cnt && IN_PORT_WORD( reg ) & (HCMD_BUSY|HREG_OFFSET_ERR) ) prot_cnt--;
+			if ( prot_cnt == 0 ) {
+				/* ;? It could be discussed whether the HREG_OFFSET_ERR bit should result in blocking NIC access 
+				 *	till next initialize */
+				rc = ifbp->IFB_TimStat = HCF_ERR_TIME_OUT;
+			}
+		}
+		*p1 += (hcf_16)tot_len;																			/* 4 */
+	}
+	reg += HREG_DATA_0 - HREG_OFFSET_0;												     // reg = data register
+	if ( rc == HCF_SUCCESS && type == IO_IN ) { 														//input
+		if ( tot_len ) {
+			if ( offset & 0x01 ) { /*odd	*/															/* 10*/
+				*pc_addr++ = IN_PORT_BYTE( reg+1 );
+				tot_len--;
+			}
+			cp = pc_addr;
+			tlen = DIV_BY_2( tot_len );
+			IN_PORT_STRING( reg, cp, tlen );
+			if ( tot_len & 1 ) *(pc_addr + tot_len - 1) = IN_PORT_BYTE( reg );							/* 11*/
+			while ( word_len-- ) {
+				CNV_LITTLE_TO_INT_NP( wp );																/* 12*/
+				wp++;
+			}
+		}
+	}
+	if ( rc == HCF_SUCCESS && type != IO_IN ) {											  //output and/or check
+		tlen = word_len;                                                                                /* 20*/
+		while ( tlen-- ) {                                                                              /* 20*/
+			OUT_PORT_WORD( reg, *(wci_recordp)pc_addr );
+			pc_addr += 2;
+		}
+//		tlen = offset + tot_len;
+		if ( tot_len && offset & 0x01 ) {																/* 21*/
+			OUT_PORT_WORD( reg, CNV_LITTLE_TO_INT( (*pc_addr <<8) + IN_PORT_BYTE( reg ) ) );
+			pc_addr++;
+			tot_len--;
+		}
+		word_len = DIV_BY_2( tot_len ) - word_len;	  //misuse no longer needed parameter as temporary variable
+		cp = pc_addr;
+		OUT_PORT_STRING( reg, cp, word_len );
+		if ( tot_len & 1 ) OUT_PORT_BYTE( reg, *(pc_addr + tot_len - 1) );								/* 22*/
+
+
+		if ( type == IO_OUT_CHECK /*&& *p1 != ifbp->IFB_FSBase */) {	//;?<HCF _L> should BE HARD CODED	/* 30*/
+			if ( *p1 & 0X01 ) (void)IN_PORT_WORD( reg );	//align on word boundary
+			OUT_PORT_WORD( reg, 0xCAFE );
+			OUT_PORT_WORD( reg, 0xABBA );
+			OUT_PORT_WORD( reg, 0xDEAD );
+			OUT_PORT_WORD( reg, 0xD00F );
+//!!		OUT_PORT_WORD( bap - HREG_OFFSET_0 + HREG_SELECT_0, fid );									/* 31*/
+			OUT_PORT_WORD( reg - HREG_DATA_0 + HREG_OFFSET_0, (*p1 + 1)&0xFFFE );
+			prot_cnt = ifbp->IFB_TickIni;
+			while ( prot_cnt && IN_PORT_WORD(reg - HREG_DATA_0 + HREG_OFFSET_0) & (HCMD_BUSY|HREG_OFFSET_ERR) ) prot_cnt--;
+			if ( prot_cnt == 0 ) {
+				rc = ifbp->IFB_TimStat = HCF_ERR_TIME_OUT;
+			}
+			if ( IN_PORT_WORD( reg ) != 0xCAFE ) {
+	 			rc = HCF_FAILURE;
+				ifbp->IFB_PIFRscInd = 1;
+//!			} else {
+//!				rc = HCF_SUCCESS;
+			}
+		}
+	}
+	if ( rc == HCF_SUCCESS ) {																			/* 40*/
+	    if ( IN_PORT_WORD( ifbp->IFB_IOBase + HREG_SW_0 ) != HCF_MAGIC ) rc =  HCF_ERR_NO_NIC;
+	}	
+
+//!	ASSERT( bap_ini( ifbp, bap, fid, (offset + len) & 0xFFFE) == HCF_SUCCESS )							/*99 */
+    return rc;
+}/* hcfio_string */
+
Index: oldkernel/linux/pcmcia-cs-3.1.15/wireless/wvlan_mdd.h
diff -u /dev/null linux/pcmcia-cs-3.1.15/wireless/wvlan_mdd.h:1.1
--- /dev/null	Mon Jul 31 21:15:12 2000
+++ linux/pcmcia-cs-3.1.15/wireless/wvlan_mdd.h	Fri Jul  7 16:34:59 2000
@@ -0,0 +1,468 @@
+/* This file is part of the Hardware Control Functions Light (HCF-light) library
+   to control the Lucent Technologies WaveLAN/IEEE Network I/F Card.
+   The HCF is the implementation of the Wireless Connection I/F (WCI).
+   
+   The HCF-light files are a subset of the HCF files. The complete set offers a
+   number of additional facilities, e.g. firmware download, Etherner-II encapsulation,
+   additional diagnostic facilities, ASSERT logic to support debugging, 802.11 support,
+   Configuration Management.
+   This complete set is explicitely not in the Public Domain but can be made 
+   available under certain restriction. (see the pointer below for support)
+   
+   The HCF-light files are 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. 
+   
+   At the time of this writing, you can request for support at:
+   betasupport@wavelan.com
+   
+   Documentation is expected to be available in the week of 8 Februari 1999
+
+*/
+
+
+#ifndef MDD_H
+#define MDD_H 1
+
+/*************************************************************************************************************
+*
+* FILE	 : mdd.h
+*
+* DATE   : 2000/02/28 23:09:38   1.3
+*
+* AUTHOR : Nico Valster
+*
+* DESC   : Definitions and Prototypes for HCF, MSF, UIL as well as USF sources
+*
+*
+*
+* Implementation Notes
+*
+ -	Typ rather than type is used as field names in structures like CFG_CIS_STRCT because type leads to
+ 	conflicts with MASM when the H-file is converted to an INC-file
+*
+**************************************************************************************************************
+Instructions to convert MDD.H to MDD.INC by means of H2INC
+
+Use a command line which defines the specific macros and command line options
+needed to build the C-part, e.g. for the DOS ODI driver
+		`h2inc /C /Ni /Zp /Zn mdd	 mdd.h`
+
+
+**************************************************************************************************************
+* COPYRIGHT (c) 1998 by Lucent Technologies.	 All Rights Reserved.
+*************************************************************************************************************/
+
+/****************************************************************************
+wvlan_mdd.h,v
+Revision 1.3  2000/02/28 23:09:38  root
+*** empty log message ***
+
+Revision 1.2  2000/01/06 23:30:53  root
+*** empty log message ***
+
+ * 
+ *    Rev 1.0   02 Feb 1999 14:32:36   NVALST
+ * Initial revision.
+Revision 1.3  1999/02/01 22:58:35  nico
+*** empty log message ***
+
+Revision 1.2  1999/02/01 21:01:41  nico
+*** empty log message ***
+
+Revision 1.1  1999/01/30 19:24:39  nico
+Initial revision
+
+Revision 1.1  1999/01/30 19:07:57  nico
+Initial revision
+
+ * 
+ *    Rev 1.110   29 Jan 1999 15:52:44   NVALST
+ * intermediate, maybe working but seems to need two times to load in 
+ * light-version
+ * 
+ *    Rev 2.12   29 Jan 1999 10:48:46   NVALST
+ * 
+ *    Rev 1.108   28 Jan 1999 14:43:24   NVALST
+ * intermediate, once more correction of loop in hcf_service_nic + download
+ * passed to Marc
+ * 
+ *    Rev 2.11   27 Jan 1999 16:57:42   NVALST
+ * 
+ *    Rev 1.107   27 Jan 1999 13:53:24   NVALST
+ * intermediate, once more correction of loop in hcf_service_nic
+ * 
+ *    Rev 1.106   26 Jan 1999 16:42:46   NVALST
+ * intermediate, corrected loop in hcf_service_nic (which was as result of a 
+ * walkthrough, changed from a bug without consequences into one with consequences
+ * 
+ *    Rev 1.105   25 Jan 1999 14:24:48   NVALST
+ * intermediate, hopefully suitable for release
+ * 
+ *    Rev 1.104   22 Jan 1999 16:59:34   NVALST
+ * intermediate, minor corrections + some HCF-L stuff
+ * 
+ *    Rev 1.103   15 Jan 1999 15:14:46   NVALST
+ * intermediate, deposited as HCF2.10
+ * 
+ *    Rev 2.10   15 Jan 1999 14:54:36   NVALST
+ * 
+ *
+****************************************************************************/
+
+
+/****************************************************************************
+*
+* CHANGE HISTORY
+*
+  961018 - NV
+	Original Entry, split of from HCF.H
+
+*************************************************************************************************************/
+
+/******************************      M A C R O S     ********************************************************/
+
+/* min and max macros */
+#if !defined(max)
+#define max(a,b)  (((a) > (b)) ? (a) : (b))
+#endif
+#if !defined(min)
+#define min(a,b)  (((a) < (b)) ? (a) : (b))
+#endif
+
+
+/*************************************************************************************************************/
+
+/****************************** General define ***************************************************************/
+
+#define MAC_ADDR_SIZE			6
+#define GROUP_ADDR_SIZE			(32 * MAC_ADDR_SIZE)
+#define STAT_NAME_SIZE			32
+
+
+
+//IFB field related
+//		IFB_CardStat
+#define CARD_STAT_PRESENT				0x8000U	/* MSF defines card as being present
+												 * controls whether hcf-function is allowed to do I/O		*/
+#define CARD_STAT_ENABLED				0x4000U	// one or more MAC Ports enabled
+#define CARD_STAT_INI					0x0800U	// Hermes Initiliazed
+
+//		IFB_RxStat
+#define RX_STAT_ERR						0x0003U	//Error mask
+#define 	RX_STAT_UNDECR				0x0002U	//Non-decryptable encrypted message
+#define 	RX_STAT_FCS_ERR				0x0001U	//FCS error
+
+/****************************** Xxxxxxxx *********************************************************************/
+
+enum /*hcf_stat*/ {
+	HCF_FAILURE			= 0xFF,		/* An (unspecified) failure, 0xFF is choosen to have a non-ubiquitous value
+	                                 *	Note that HCF_xxxx errors which can end up in the CFG_DIAG LTV should
+	                                 *	never exceed 0xFF, because the high order byte of VAL[0] is reserved
+	                                 *	for Hermes errors
+	                                 */
+	HCF_SUCCESS			= 0x00,		// 0x00: OK
+	//gap for ODI related status
+	HCF_ERR_DIAG_0		= 0x02,		// 0x02: HCF noticed an error after hcf_disable, before diagnose command
+	HCF_ERR_DIAG_1,					// 0x03: HCF noticed an error after succesful diagnose command
+	HCF_ERR_TIME_OUT,               // 0x04: Expected Hermes event did not occure in expected time
+	HCF_ERR_NO_NIC,					// 0x05: card not found (usually yanked away during hcfio_in_string
+	HCF_ERR_BUSY,					// 0x06: ;?Inquire cmd while another Inquire in progress
+	HCF_ERR_SEQ_BUG,				// 0x07: other cmd than the expected completed, probably HCF-bug
+	HCF_ERR_LEN,					// 0x08: buffer size insufficient
+									//		  -	hcf_get_info buffer has a size of 0 or 1 or less than needed
+									//			to accomodate all data
+};
+
+#define	HCF_INT_PENDING			1	// (ODI initiated) return status of hcf_act( HCF_ACT_INT_OFF )
+
+
+
+/* hard coded values (e.g. for HCF_ACT_TALLIES and HCF_ACT_INT_OFF) are needed for HCFL							*/
+typedef enum  { /*hcf_action_cmd*/
+										/*	gap left over by swapping 3 frame mode action with 4 INT_OFF/_ON
+										 *	CARD_IN/_OUT. This was done to have HCFL default automagically
+										 *	to HCF_ACT_802_3_PURE
+										 *	This gap available for future features								*/
+	HCF_ACT_SPARE_03,					//03 gap available for future features
+										/* DUI code 0x04 -> DON'T EVER MOVE 									*/
+										/* DUI code 0x05 -> DON'T EVER MOVE 									*/
+	HCF_ACT_TALLIES = 0x05,				//05 Hermes Inquire Tallies (F100) command
+#if defined HCF_ASSERT
+	HCF_ACT_ASSERT_OFF,					//09 de-activate Assert reporting
+	HCF_ACT_ASSERT_ON,					//0A activate Assert reporting	
+#else	
+#endif // HCF_ASSERT
+										/* DUI code 0x0B -> DON'T EVER MOVE 									*/
+										/* DUI code 0x0C -> DON'T EVER MOVE 									*/
+	HCF_ACT_INT_OFF = 0x0D,				//0D Disable Interrupt generation
+	HCF_ACT_INT_ON,						//0E Enable Interrupt generation
+	HCF_ACT_CARD_IN,					//0F MSF reported Card insertion
+	HCF_ACT_CARD_OUT,  					//10 MSF reported Card removal
+/*	HCF_ACT_MAX							// xxxx: start value for UIL-range, NOT to be passed to HCF
+ *										Too bad, there was originally no spare room created to use
+ *										HCF_ACT_MAX as an equivalent of HCF_ERR_MAX. Since creating
+ *										this room in retrospect would create a backward incompatibilty
+ *										we will just have to live with the haphazard sequence of
+ *										UIL- and HCF specific codes. Theoretically this could be
+ *										corrected when and if there will ever be an overall 
+ *										incompatibilty introduced for another reason
+ */										 
+} hcf_action_cmd;
+
+
+
+
+
+
+
+
+/*============================================================= HCF Defined RECORDS	=========================*/
+/*============================================================= INFORMATION FRRAMES		=====================*/
+#define CFG_INFO_FRAME_MIN				0xF000		//lowest value representing an Informatio Frame
+	
+#define CFG_TALLIES						0xF100		//Communications Tallies
+#define CFG_SCAN						0xF101		//Scan results
+	                        	
+#define CFG_LINK_STAT 					0xF200		//Link Status
+	
+/*============================================================= CONFIGURATION RECORDS	=====================*/
+/*============================================================= mask 0xFCxx				=====================*/						
+//	NETWORK PARAMETERS, STATIC CONFIGURATION ENTITIES
+//FC05, FC0A, FC0B, FC0C, FC0D: SEE W2DN149
+	
+#define CFG_RID_CFG_MIN					0xFC00		//lowest value representing a Configuration RID
+#define CFG_CNF_PORT_TYPE				0xFC00		//[STA] Connection control characteristics
+#define CFG_CNF_OWN_MAC_ADDR			0xFC01		//[STA] MAC Address of this node
+#define CFG_CNF_DESIRED_SSID			0xFC02		//[STA] Service Set identification for connection
+#define CFG_CNF_OWN_CHANNEL				0xFC03		//Communication channel for BSS creation
+#define CFG_CNF_OWN_SSID				0xFC04		//IBSS creation (STA) or ESS (AP) Service Set Ident
+#define CFG_CNF_OWN_ATIM_WINDOW			0xFC05		//[STA] ATIM Window time for IBSS creation
+#define CFG_CNF_SYSTEM_SCALE			0xFC06		//System Scale that specifies the AP density
+#define CFG_CNF_MAX_DATA_LEN			0xFC07		//Maximum length of MAC Frame Body data
+#define CFG_CNF_WDS_ADDR				0xFC08		//[STA] MAC Address of corresponding WDS Link node
+#define CFG_CNF_PM_ENABLED				0xFC09		//[STA] Switch for ESS Power Management (PM) On/Off
+#define CFG_CNF_PM_EPS					0xFC0A		//[STA] Switch for ESS PM EPS/PS Mode
+#define CFG_CNF_MCAST_RX				0xFC0B		//[STA] Switch for ESS PM Multicast reception On/Off
+#define CFG_CNF_MAX_SLEEP_DURATION		0xFC0C		//[STA] Maximum sleep time for ESS PM
+#define CFG_CNF_HOLDOVER_DURATION		0xFC0D		//[STA] Holdover time for ESS PM
+#define CFG_CNF_OWN_NAME				0xFC0E		//Identification text for diagnostic purposes
+
+#define CFG_CNF_ENCRYPTION				0xFC20		//select en/de-cryption of Tx/Rx messages
+	
+	
+//	NETWORK PARAMETERS, DYNAMIC CONFIGURATION ENTITIES
+#define CFG_GROUP_ADDR					0xFC80		//[STA] Multicast MAC Addresses for Rx-message
+#define CFG_CREATE_IBSS					0xFC81		//[STA] Switch for IBSS creation On/Off
+#define CFG_FRAGMENTATION_THRH			0xFC82		//[STA] Fragment length for unicast Tx-message
+#define CFG_RTS_THRH					0xFC83		//[STA] Frame length used for RTS/CTS handshake
+#define CFG_TX_RATE_CONTROL				0xFC84		//[STA] Data rate control for message transmission
+#define CFG_PROMISCUOUS_MODE			0xFC85		//[STA] Switch for Promiscuous mode reception On/Off
+
+#define CFG_CNF_DEFAULT_KEYS			0xFCB0		//defines set of encryption keys
+#define CFG_CNF_TX_KEY_ID			0xFCB1		//select key for encryption of Tx messages
+	
+
+//	BEHAVIOR PARAMETERS	
+#define CFG_TICK_TIME					0xFCE0		//[PRI] Auxiliary Timer tick interval
+#define CFG_RID_CFG_MAX					0xFCFF		//highest value representing an Configuration RID
+
+
+/*============================================================= INFORMATION RECORDS 	=====================*/
+/*============================================================= mask 0xFDxx				=====================*/
+//	NIC INFORMATION	
+#define CFG_RID_INF_MIN					0xFD00		//lowest value representing an Information RID
+#define CFG_PRI_IDENTITY				0xFD02
+#define CFG_PRI_SUP_RANGE				0xFD03		//Primary supplier range
+#define CFG_CFI_ACT_RANGES_PRI			0xFD04
+
+#define CFG_HSI_SUP_RANGE				0xFD09		//H/W - S/W I/F supplier range
+#define CFG_NIC_SERIAL_NUMBER			0xFD0A
+#define CFG_NIC_IDENTITY				0xFD0B
+#define CFG_MFI_SUP_RANGE				0xFD0C
+#define CFG_CFI_SUP_RANGE				0xFD0D
+
+#define CFG_CHANNEL_LIST				0xFD10		//Allowed communication channels
+#define CFG_REG_DOMAINS					0xFD11		//List of intended regulatory domains
+#define CFG_TEMP_TYPE  					0xFD12		//Hardware temperature range code
+#define CFG_CIS							0xFD13		//PC Card Standard Card Information Structure
+
+#define CFG_STA_IDENTITY				0xFD20
+#define CFG_STA_SUP_RANGE				0xFD21		//Station supplier range
+#define CFG_MFI_ACT_RANGES_STA			0xFD22
+#define CFG_CFI_ACT_RANGES_STA			0xFD23
+
+//	MAC INFORMATION
+#define CFG_PORT_STAT					0xFD40		//[STA] Actual MAC Port connection control status
+#define CFG_CURRENT_SSID				0xFD41		//[STA] Identification of the actually connected SS
+#define CFG_CURRENT_BSSID				0xFD42		//[STA] Identification of the actually connected BSS
+#define CFG_COMMS_QUALITY				0xFD43		//[STA] Quality of the Basic Service Set connection
+#define CFG_CURRENT_TX_RATE				0xFD44		//[STA] Actual transmit data rate
+#define CFG_OWN_BEACON_INTERVAL			0xFD45		//Beacon transmit interval time for BSS creation
+#define CFG_CUR_SCALE_THRH				0xFD46		//Actual System Scale thresholds settings
+#define CFG_PROTOCOL_RSP_TIME			0xFD47		//Max time to await a response to a request message
+#define CFG_SHORT_RETRY_LIMIT			0xFD48		//Max number of transmit attempts for short frames
+#define CFG_LONG_RETRY_LIMIT			0xFD49		//Max number of transmit attempts for long frames
+#define CFG_MAX_TX_LIFETIME				0xFD4A		//Max transmit frame handling duration
+#define CFG_MAX_RX_LIFETIME				0xFD4B		//Max received frame handling duration
+#define CFG_CF_POLLABLE					0xFD4C		//[STA] Contention Free pollable capability indication
+#define CFG_AUTHENTICATION_ALGORITHMS	0xFD4D		//Available Authentication Algorithms indication
+#define CFG_AUTHENTICATION_TYPE			0xFD4E		//Available Authentication Types indication
+#define CFG_PRIVACY_OPTION_IMPLEMENTED	0xFD4F		//WEP Option availability indication
+	
+
+//	MODEM INFORMATION	
+#define CFG_PHY_TYPE					0xFDC0		//		// 	Physical layer type indication
+#define CFG_CURRENT_CHANNEL				0xFDC1		//Actual frequency channel used for transmission
+#define CFG_CURRENT_POWER_STATE			0xFDC2		//Actual power consumption status
+#define CFG_CCAMODE						0xFDC3		//Clear channel assessment mode indication
+#define CFG_CCATIME						0xFDC4		//Clear channel assessment time
+#define CFG_MAC_PROCESSING_DELAY		0xFDC5		//MAC processing delay time
+#define CFG_SUPPORTED_DATA_RATES		0xFDC6		//Data rates capability information
+
+#define CFG_RID_INF_MAX					0xFDFF		//highest value representing an Information RID
+
+//} hcf_info_type;
+
+
+
+
+/*************************************************************************************************************/
+
+/****************************** S T R U C T U R E   D E F I N I T I O N S ************************************/
+
+typedef struct LTV_STRCT {	//used for all "minimal" LTV records
+	hcf_16	len;					//default length of RID
+	hcf_16	typ;					//RID identification as defined by Hermes
+	hcf_16	val[1];					//do not change this, some dynamic structures are defined based on this !!
+}LTV_STRCT;
+
+typedef LTV_STRCT FAR *	LTVP;
+
+
+
+
+
+#define COMP_ID_MINIPORT	41				//Windows 9x/NT Miniport
+#define COMP_ID_PACKET		42				//Packet
+#define COMP_ID_ODI_16		43				//DOS ODI
+#define COMP_ID_ODI_32		44				//32-bits ODI
+#define COMP_ID_MAC_OS		45				//Macintosh OS
+#define COMP_ID_WIN_CE		46				//Windows CE Miniport
+#define COMP_ID_LINUX		47				//You never guessed, Linux
+#define COMP_ID_AP1			81				//WaveLAN/IEEE AP
+
+
+
+#define COMP_ROLE_SUPL	00				//supplier
+#define COMP_ROLE_ACT	01				//actor
+
+#define COMP_ID_MFI		01				//Modem		 		- Firmware	I/F
+#define COMP_ID_CFI		02				//Controller		- Firmware	I/F
+#define COMP_ID_PRI		03				//Primary Firmware	- Driver	I/F
+#define COMP_ID_STA		04				//Station Firmware	- Driver	I/F
+#define COMP_ID_DUI		05				//Driver			- Utility	I/F
+#define COMP_ID_HSI		06				//H/W               - Driver	I/F
+
+typedef struct KEY_STRCT {
+	hcf_16	len;			//length of key
+	hcf_8	key[14];		//encryption key
+} KEY_STRCT;
+
+typedef struct CFG_CNF_DEFAULT_KEYS_STRCT {	//CFG_CNF_DEFAULT_KEYS (0xFCB0) defines set of encrypti
+	hcf_16		len;		//default length of RID
+	hcf_16		typ;		//RID identification as defined by Hermes
+	KEY_STRCT	key[4];		//encryption keys
+} CFG_CNF_DEFAULT_KEYS_STRCT;
+
+
+typedef struct CFG_REG_DOMAINS_STRCT {	//CFG_REG_DOMAINS (0xFD11) List of intended regulatory domains.
+	hcf_16	len;					//length of RID
+	hcf_16	typ;					//RID identification as defined by Hermes
+	hcf_16	domains[6];
+}CFG_REG_DOMAINS_STRCT;
+
+typedef struct CFG_CIS_STRCT {			//CFG_CIS (0xFD13) PC Card Standard Card Information Structure
+	hcf_16	len;					//length of RID
+	hcf_16	typ;					//RID identification as defined by Hermes
+	hcf_16	cis[240];				//Compact CIS Area, a linked list of tuples
+}CFG_CIS_STRCT;
+
+
+typedef struct CFG_COMMS_QUALITY_STRCT {//CFG_COMMS_QUALITY (0xFD43) Quality of the Basic Service Set connection [STA]
+	hcf_16	len;					//length of RID
+	hcf_16	typ;					//RID identification as defined by Hermes
+	hcf_16	coms_qual;              //Communication Quality of the BSS the station is connected to
+	hcf_16	signal_lvl;				//Average Signal Level of the BSS the station is connected to
+	hcf_16	noise_lvl;				//Average Noise Level of the currently used Frequency Channel
+}CFG_COMMS_QUALITY_STRCT;
+
+
+
+typedef struct CFG_CUR_SCALE_THRH_STRCT {//CFG_CUR_SCALE_THRH (0xFD46) Actual System Scale thresholds
+	hcf_16	len;					//default length of RID [STA: 6  AP: 4]
+	hcf_16	typ;					//RID identification as defined by Hermes
+	hcf_16	energy_detect_thrh;		//Receiver H/W Energy Detect Threshold
+	hcf_16	carrier_detect_thrh;	//Receiver H/W Carrier Detect Threshold
+	hcf_16	defer_thrh;				//Receiver H/W Defer Threshold
+	hcf_16	cell_search_thrh;		//Firmware Roaming Cell Search Threshold [STA]
+	hcf_16	out_of_range_thrh;		//Firmware Roaming Out of Range Threshold [STA]
+	hcf_16	delta_snr;				//Firmware Roaming Delta SNR value [STA]
+}CFG_CUR_SCALE_THRH_STRCT;
+
+
+typedef struct CFG_PCF_INFO_STRCT {		//CFG_PCF_INFO (0xFD87) Point Coordination Function capability info [AP]
+	hcf_16	len;					//default length of RID
+	hcf_16	typ;					//RID identification as defined by Hermes
+	hcf_16	energy_detect_thrh;
+	hcf_16	carrier_detect_thrh;
+	hcf_16	defer_thrh;
+	hcf_16	cell_search_thrh;
+	hcf_16	range_thrh;
+}CFG_PCF_INFO_STRCT;
+
+
+typedef struct CFG_MAC_ADDR_STRCT{			//0xFC01	[STA] MAC Address of this node.
+											//0xFC08	STA] MAC Address of corresponding WDS Link node.
+											//0xFC11	[AP] Port 1 MAC Adrs of corresponding WDS Link node
+											//0xFC12	[AP] Port 2 MAC Adrs of corresponding WDS Link node
+											//0xFC13	[AP] Port 3 MAC Adrs of corresponding WDS Link node
+											//0xFC14	[AP] Port 4 MAC Adrs of corresponding WDS Link node
+											//0xFC15	[AP] Port 5 MAC Adrs of corresponding WDS Link node
+											//0xFC16	[AP] Port 6 MAC Adrs of corresponding WDS Link node
+	hcf_16	len;					//default length of RID
+	hcf_16	typ;					//RID identification as defined by Hermes
+	hcf_16	mac_addr[3];
+}CFG_MAC_ADDR_STRCT;
+
+typedef struct CFG_GROUP_ADDR_STRCT{			//0xFC80	//[STA] Multicast MAC Addresses for
+	hcf_16	len;					//default length of RID
+	hcf_16	typ;					//RID identification as defined by Hermes
+	hcf_16	mac_addr[GROUP_ADDR_SIZE/6][3];
+}CFG_GROUP_ADDR_STRCT;
+
+
+typedef struct CFG_ID_STRCT {				//0xFC02	[STA] Service Set identification for connection.
+											//0xFC04	IBSS creation (STA) or ESS (AP) Service Set Ident
+											//0xFC0E	Identification text for diagnostic purposes.
+	hcf_16	len;					//default length of RID
+	hcf_16	typ;					//RID identification as defined by Hermes
+	hcf_16	id[17];
+}CFG_ID_STRCT;
+
+
+typedef void *	DUIP;
+
+#endif // MDD_H
+
+
